59ff10a15d02c97b2aed800fbe1ebae536486893
[openssl.git] / crypto / dso / dso_win32.c
1 /* dso_win32.c -*- mode:C; c-file-style: "eay" -*- */
2 /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59 #include <stdio.h>
60 #include <string.h>
61 #include "cryptlib.h"
62 #include <openssl/dso.h>
63
64 #if !defined(DSO_WIN32)
65 DSO_METHOD *DSO_METHOD_win32(void)
66         {
67         return NULL;
68         }
69 #else
70
71 #ifdef _WIN32_WCE
72 # if _WIN32_WCE < 300
73 static FARPROC GetProcAddressA(HMODULE hModule,LPCSTR lpProcName)
74         {
75         WCHAR lpProcNameW[64];
76         int i;
77
78         for (i=0;lpProcName[i] && i<64;i++)
79                 lpProcNameW[i] = (WCHAR)lpProcName[i];
80         if (i==64) return NULL;
81         lpProcNameW[i] = 0;
82
83         return GetProcAddressW(hModule,lpProcNameW);
84         }
85 # endif
86 # undef GetProcAddress
87 # define GetProcAddress GetProcAddressA
88 #endif
89
90 /* Part of the hack in "win32_load" ... */
91 #define DSO_MAX_TRANSLATED_SIZE 256
92
93 static int win32_load(DSO *dso);
94 static int win32_unload(DSO *dso);
95 static void *win32_bind_var(DSO *dso, const char *symname);
96 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname);
97 #if 0
98 static int win32_unbind_var(DSO *dso, char *symname, void *symptr);
99 static int win32_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
100 static int win32_init(DSO *dso);
101 static int win32_finish(DSO *dso);
102 static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg);
103 #endif
104 static char *win32_name_converter(DSO *dso, const char *filename);
105 static char *win32_merger(DSO *dso, const char *filespec1,
106         const char *filespec2);
107 static int win32_pathbyaddr(void *addr,char *path,int sz);
108
109 static const char *openssl_strnchr(const char *string, int c, size_t len);
110
111 static DSO_METHOD dso_meth_win32 = {
112         "OpenSSL 'win32' shared library method",
113         win32_load,
114         win32_unload,
115         win32_bind_var,
116         win32_bind_func,
117 /* For now, "unbind" doesn't exist */
118 #if 0
119         NULL, /* unbind_var */
120         NULL, /* unbind_func */
121 #endif
122         NULL, /* ctrl */
123         win32_name_converter,
124         win32_merger,
125         NULL, /* init */
126         NULL, /* finish */
127         win32_pathbyaddr
128         };
129
130 DSO_METHOD *DSO_METHOD_win32(void)
131         {
132         return(&dso_meth_win32);
133         }
134
135 /* For this DSO_METHOD, our meth_data STACK will contain;
136  * (i) a pointer to the handle (HINSTANCE) returned from
137  *     LoadLibrary(), and copied.
138  */
139
140 static int win32_load(DSO *dso)
141         {
142         HINSTANCE h = NULL, *p = NULL;
143         /* See applicable comments from dso_dl.c */
144         char *filename = DSO_convert_filename(dso, NULL);
145
146         if(filename == NULL)
147                 {
148                 DSOerr(DSO_F_WIN32_LOAD,DSO_R_NO_FILENAME);
149                 goto err;
150                 }
151         h = LoadLibraryA(filename);
152         if(h == NULL)
153                 {
154                 DSOerr(DSO_F_WIN32_LOAD,DSO_R_LOAD_FAILED);
155                 ERR_add_error_data(3, "filename(", filename, ")");
156                 goto err;
157                 }
158         p = (HINSTANCE *)OPENSSL_malloc(sizeof(HINSTANCE));
159         if(p == NULL)
160                 {
161                 DSOerr(DSO_F_WIN32_LOAD,ERR_R_MALLOC_FAILURE);
162                 goto err;
163                 }
164         *p = h;
165         if(!sk_push(dso->meth_data, (char *)p))
166                 {
167                 DSOerr(DSO_F_WIN32_LOAD,DSO_R_STACK_ERROR);
168                 goto err;
169                 }
170         /* Success */
171         dso->loaded_filename = filename;
172         return(1);
173 err:
174         /* Cleanup !*/
175         if(filename != NULL)
176                 OPENSSL_free(filename);
177         if(p != NULL)
178                 OPENSSL_free(p);
179         if(h != NULL)
180                 FreeLibrary(h);
181         return(0);
182         }
183
184 static int win32_unload(DSO *dso)
185         {
186         HINSTANCE *p;
187         if(dso == NULL)
188                 {
189                 DSOerr(DSO_F_WIN32_UNLOAD,ERR_R_PASSED_NULL_PARAMETER);
190                 return(0);
191                 }
192         if(sk_num(dso->meth_data) < 1)
193                 return(1);
194         p = (HINSTANCE *)sk_pop(dso->meth_data);
195         if(p == NULL)
196                 {
197                 DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_NULL_HANDLE);
198                 return(0);
199                 }
200         if(!FreeLibrary(*p))
201                 {
202                 DSOerr(DSO_F_WIN32_UNLOAD,DSO_R_UNLOAD_FAILED);
203                 /* We should push the value back onto the stack in
204                  * case of a retry. */
205                 sk_push(dso->meth_data, (char *)p);
206                 return(0);
207                 }
208         /* Cleanup */
209         OPENSSL_free(p);
210         return(1);
211         }
212
213 /* Using GetProcAddress for variables? TODO: Check this out in
214  * the Win32 API docs, there's probably a variant for variables. */
215 static void *win32_bind_var(DSO *dso, const char *symname)
216         {
217         HINSTANCE *ptr;
218         void *sym;
219
220         if((dso == NULL) || (symname == NULL))
221                 {
222                 DSOerr(DSO_F_WIN32_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER);
223                 return(NULL);
224                 }
225         if(sk_num(dso->meth_data) < 1)
226                 {
227                 DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_STACK_ERROR);
228                 return(NULL);
229                 }
230         ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
231         if(ptr == NULL)
232                 {
233                 DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_NULL_HANDLE);
234                 return(NULL);
235                 }
236         sym = GetProcAddress(*ptr, symname);
237         if(sym == NULL)
238                 {
239                 DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_SYM_FAILURE);
240                 ERR_add_error_data(3, "symname(", symname, ")");
241                 return(NULL);
242                 }
243         return(sym);
244         }
245
246 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
247         {
248         HINSTANCE *ptr;
249         void *sym;
250
251         if((dso == NULL) || (symname == NULL))
252                 {
253                 DSOerr(DSO_F_WIN32_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER);
254                 return(NULL);
255                 }
256         if(sk_num(dso->meth_data) < 1)
257                 {
258                 DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_STACK_ERROR);
259                 return(NULL);
260                 }
261         ptr = (HINSTANCE *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1);
262         if(ptr == NULL)
263                 {
264                 DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_NULL_HANDLE);
265                 return(NULL);
266                 }
267         sym = GetProcAddress(*ptr, symname);
268         if(sym == NULL)
269                 {
270                 DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_SYM_FAILURE);
271                 ERR_add_error_data(3, "symname(", symname, ")");
272                 return(NULL);
273                 }
274         return((DSO_FUNC_TYPE)sym);
275         }
276
277 struct file_st
278         {
279         const char *node; int nodelen;
280         const char *device; int devicelen;
281         const char *predir; int predirlen;
282         const char *dir; int dirlen;
283         const char *file; int filelen;
284         };
285
286 static struct file_st *win32_splitter(DSO *dso, const char *filename,
287         int assume_last_is_dir)
288         {
289         struct file_st *result = NULL;
290         enum { IN_NODE, IN_DEVICE, IN_FILE } position;
291         const char *start = filename;
292
293         if (!filename)
294                 {
295                 DSOerr(DSO_F_WIN32_SPLITTER,DSO_R_NO_FILENAME);
296                 /*goto err;*/
297                 return(NULL);
298                 }
299
300         result = OPENSSL_malloc(sizeof(struct file_st));
301         if(result == NULL)
302                 {
303                 DSOerr(DSO_F_WIN32_SPLITTER,
304                         ERR_R_MALLOC_FAILURE);
305                 return(NULL);
306                 }
307
308         memset(result, 0, sizeof(struct file_st));
309         position = IN_DEVICE;
310
311         if((filename[0] == '\\' && filename[1] == '\\')
312                 || (filename[0] == '/' && filename[1] == '/'))
313                 {
314                 position = IN_NODE;
315                 filename += 2;
316                 start = filename;
317                 result->node = start;
318                 }
319
320         do
321                 {
322                 switch(filename[0])
323                         {
324                 case ':':
325                         if(position != IN_DEVICE)
326                                 {
327                                 DSOerr(DSO_F_WIN32_SPLITTER,
328                                         DSO_R_INCORRECT_FILE_SYNTAX);
329                                 /*goto err;*/
330                                 return(NULL);
331                                 }
332                         result->device = start;
333                         result->devicelen = filename - start;
334                         position = IN_FILE;
335                         start = ++filename;
336                         result->dir = start;
337                         break;
338                 case '\\':
339                 case '/':
340                         if(position == IN_NODE)
341                                 {
342                                 result->nodelen = filename - start;
343                                 position = IN_FILE;
344                                 start = ++filename;
345                                 result->dir = start;
346                                 }
347                         else
348                                 {
349                                 filename++;
350                                 result->dirlen += filename - start;
351                                 }
352                         break;
353                 case '\0':
354                         if(position == IN_NODE)
355                                 {
356                                 result->nodelen = filename - start;
357                                 }
358                         else
359                                 {
360                                 if(filename - start > 0)
361                                         {
362                                         if (assume_last_is_dir)
363                                                 {
364                                                 result->devicelen += filename - start;
365                                                 }
366                                         else
367                                                 {
368                                                 result->file = start;
369                                                 result->filelen = filename - start;
370                                                 }
371                                         }
372                                 }
373                         break;
374                 default:
375                         filename++;
376                         break;
377                         }
378                 }
379         while(*filename);
380
381         if(!result->nodelen) result->node = NULL;
382         if(!result->devicelen) result->device = NULL;
383         if(!result->dirlen) result->dir = NULL;
384         if(!result->filelen) result->file = NULL;
385
386         return(result);
387         }
388
389 static char *win32_joiner(DSO *dso, const struct file_st *file_split)
390         {
391         int len = 0, offset = 0;
392         char *result = NULL;
393         const char *start;
394
395         if(!file_split)
396                 {
397                 DSOerr(DSO_F_WIN32_JOINER,
398                                 ERR_R_PASSED_NULL_PARAMETER);
399                 return(NULL);
400                 }
401         if(file_split->node)
402                 {
403                 len += 2 + file_split->nodelen; /* 2 for starting \\ */
404                 if(file_split->predir || file_split->dir || file_split->file)
405                         len++;  /* 1 for ending \ */
406                 }
407         else if(file_split->device)
408                 {
409                 len += file_split->devicelen + 1; /* 1 for ending : */
410                 }
411         len += file_split->predirlen;
412         if(file_split->predir && (file_split->dir || file_split->file))
413                 {
414                 len++;  /* 1 for ending \ */
415                 }
416         len += file_split->dirlen;
417         if(file_split->dir && file_split->file)
418                 {
419                 len++;  /* 1 for ending \ */
420                 }
421         len += file_split->filelen;
422
423         if(!len)
424                 {
425                 DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
426                 return(NULL);
427                 }
428
429         result = OPENSSL_malloc(len + 1);
430         if (!result)
431                 {
432                 DSOerr(DSO_F_WIN32_JOINER,
433                         ERR_R_MALLOC_FAILURE);
434                 return(NULL);
435                 }
436
437         if(file_split->node)
438                 {
439                 strcpy(&result[offset], "\\\\"); offset += 2;
440                 strncpy(&result[offset], file_split->node,
441                         file_split->nodelen); offset += file_split->nodelen;
442                 if(file_split->predir || file_split->dir || file_split->file)
443                         {
444                         result[offset] = '\\'; offset++;
445                         }
446                 }
447         else if(file_split->device)
448                 {
449                 strncpy(&result[offset], file_split->device,
450                         file_split->devicelen); offset += file_split->devicelen;
451                 result[offset] = ':'; offset++;
452                 }
453         start = file_split->predir;
454         while(file_split->predirlen > (start - file_split->predir))
455                 {
456                 const char *end = openssl_strnchr(start, '/',
457                         file_split->predirlen - (start - file_split->predir));
458                 if(!end)
459                         end = start
460                                 + file_split->predirlen
461                                 - (start - file_split->predir);
462                 strncpy(&result[offset], start,
463                         end - start); offset += end - start;
464                 result[offset] = '\\'; offset++;
465                 start = end + 1;
466                 }
467         if(file_split->predir && (file_split->dir || file_split->file))
468                 {
469                 result[offset] = '\\'; offset++;
470                 }
471         start = file_split->dir;
472         while(file_split->dirlen > (start - file_split->dir))
473                 {
474                 const char *end = openssl_strnchr(start, '/',
475                         file_split->dirlen - (start - file_split->dir));
476                 if(!end)
477                         end = start
478                                 + file_split->dirlen
479                                 - (start - file_split->dir);
480                 strncpy(&result[offset], start,
481                         end - start); offset += end - start;
482                 result[offset] = '\\'; offset++;
483                 start = end + 1;
484                 }
485         if(file_split->dir && file_split->file)
486                 {
487                 result[offset] = '\\'; offset++;
488                 }
489         strncpy(&result[offset], file_split->file,
490                 file_split->filelen); offset += file_split->filelen;
491         result[offset] = '\0';
492         return(result);
493         }
494
495 static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2)
496         {
497         char *merged = NULL;
498         struct file_st *filespec1_split = NULL;
499         struct file_st *filespec2_split = NULL;
500
501         if(!filespec1 && !filespec2)
502                 {
503                 DSOerr(DSO_F_WIN32_MERGER,
504                                 ERR_R_PASSED_NULL_PARAMETER);
505                 return(NULL);
506                 }
507         if (!filespec2)
508                 {
509                 merged = OPENSSL_malloc(strlen(filespec1) + 1);
510                 if(!merged)
511                         {
512                         DSOerr(DSO_F_WIN32_MERGER,
513                                 ERR_R_MALLOC_FAILURE);
514                         return(NULL);
515                         }
516                 strcpy(merged, filespec1);
517                 }
518         else if (!filespec1)
519                 {
520                 merged = OPENSSL_malloc(strlen(filespec2) + 1);
521                 if(!merged)
522                         {
523                         DSOerr(DSO_F_WIN32_MERGER,
524                                 ERR_R_MALLOC_FAILURE);
525                         return(NULL);
526                         }
527                 strcpy(merged, filespec2);
528                 }
529         else
530                 {
531                 filespec1_split = win32_splitter(dso, filespec1, 1);
532                 if (!filespec1_split)
533                         {
534                         DSOerr(DSO_F_WIN32_MERGER,
535                                 ERR_R_MALLOC_FAILURE);
536                         return(NULL);
537                         }
538                 filespec2_split = win32_splitter(dso, filespec2, 0);
539                 if (!filespec1_split)
540                         {
541                         DSOerr(DSO_F_WIN32_MERGER,
542                                 ERR_R_MALLOC_FAILURE);
543                         OPENSSL_free(filespec1_split);
544                         return(NULL);
545                         }
546
547                 /* Fill in into filespec1_split */
548                 if (!filespec1_split->node && !filespec1_split->device)
549                         {
550                         filespec1_split->node = filespec2_split->node;
551                         filespec1_split->nodelen = filespec2_split->nodelen;
552                         filespec1_split->device = filespec2_split->device;
553                         filespec1_split->devicelen = filespec2_split->devicelen;
554                         }
555                 if (!filespec1_split->dir)
556                         {
557                         filespec1_split->dir = filespec2_split->dir;
558                         filespec1_split->dirlen = filespec2_split->dirlen;
559                         }
560                 else if (filespec1_split->dir[0] != '\\'
561                         && filespec1_split->dir[0] != '/')
562                         {
563                         filespec1_split->predir = filespec2_split->dir;
564                         filespec1_split->predirlen = filespec2_split->dirlen;
565                         }
566                 if (!filespec1_split->file)
567                         {
568                         filespec1_split->file = filespec2_split->file;
569                         filespec1_split->filelen = filespec2_split->filelen;
570                         }
571
572                 merged = win32_joiner(dso, filespec1_split);
573                 }
574         return(merged);
575         }
576
577 static char *win32_name_converter(DSO *dso, const char *filename)
578         {
579         char *translated;
580         int len, transform;
581
582         len = strlen(filename);
583         transform = ((strstr(filename, "/") == NULL) &&
584                         (strstr(filename, "\\") == NULL) &&
585                         (strstr(filename, ":") == NULL));
586         if(transform)
587                 /* We will convert this to "%s.dll" */
588                 translated = OPENSSL_malloc(len + 5);
589         else
590                 /* We will simply duplicate filename */
591                 translated = OPENSSL_malloc(len + 1);
592         if(translated == NULL)
593                 {
594                 DSOerr(DSO_F_WIN32_NAME_CONVERTER,
595                                 DSO_R_NAME_TRANSLATION_FAILED); 
596                 return(NULL);   
597                 }
598         if(transform)
599                 sprintf(translated, "%s.dll", filename);
600         else
601                 sprintf(translated, "%s", filename);
602         return(translated);
603         }
604
605 static const char *openssl_strnchr(const char *string, int c, size_t len)
606         {
607         size_t i;
608         const char *p;
609         for (i = 0, p = string; i < len && *p; i++, p++)
610                 {
611                 if (*p == c)
612                         return p;
613                 }
614         return NULL;
615         }
616
617 #include <tlhelp32.h>
618 #ifdef _WIN32_WCE
619 # define DLLNAME "TOOLHELP.DLL"
620 #else
621 # ifdef MODULEENTRY32
622 # undef MODULEENTRY32   /* unmask the ASCII version! */
623 # endif
624 # define DLLNAME "KERNEL32.DLL"
625 #endif
626
627 typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
628 typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
629 typedef BOOL (WINAPI *MODULE32)(HANDLE, MODULEENTRY32 *);
630
631 static int win32_pathbyaddr(void *addr,char *path,int sz)
632         {
633         HMODULE dll;
634         HANDLE hModuleSnap = INVALID_HANDLE_VALUE; 
635         MODULEENTRY32 me32; 
636         CREATETOOLHELP32SNAPSHOT create_snap;
637         CLOSETOOLHELP32SNAPSHOT  close_snap;
638         MODULE32 module_first, module_next;
639         int len;
640  
641         if (addr == NULL)
642                 {
643                 union   { int(*f)(void*,char*,int); void *p; } t =
644                         { win32_pathbyaddr };
645                 addr = t.p;
646                 }
647
648         dll = LoadLibrary(TEXT(DLLNAME));
649         if (dll == NULL)
650                 {
651                 DSOerr(DSO_F_PATHBYADDR,DSO_R_UNSUPPORTED);
652                 return -1;
653                 }
654
655         create_snap = (CREATETOOLHELP32SNAPSHOT)
656                 GetProcAddress(dll,"CreateToolhelp32Snapshot");
657         if (create_snap == NULL)
658                 {
659                 DSOerr(DSO_F_PATHBYADDR,DSO_R_UNSUPPORTED);
660                 return -1;
661                 }
662         /* We take the rest for granted... */
663 #ifdef _WIN32_WCE
664         close_snap = (CLOSETOOLHELP32SNAPSHOT)
665                 GetProcAddress(dll,"CloseToolhelp32Snapshot");
666 #else
667         close_snap = (CLOSETOOLHELP32SNAPSHOT)CloseHandle;
668 #endif
669         module_first = (MODULE32)GetProcAddress(dll,"Module32First");
670         module_next  = (MODULE32)GetProcAddress(dll,"Module32Next");
671
672         hModuleSnap = (*create_snap)(TH32CS_SNAPMODULE,0); 
673         if( hModuleSnap == INVALID_HANDLE_VALUE ) 
674                 { 
675                 FreeLibrary(dll);
676                 DSOerr(DSO_F_PATHBYADDR,DSO_R_UNSUPPORTED);
677                 return -1;
678                 } 
679  
680         me32.dwSize = sizeof(me32); 
681  
682         if(!(*module_first)(hModuleSnap,&me32)) 
683                 { 
684                 (*close_snap)(hModuleSnap);
685                 FreeLibrary(dll);
686                 DSOerr(DSO_F_PATHBYADDR,DSO_R_FAILURE);
687                 return -1;
688                 }
689  
690         do      { 
691                 if ((BYTE *)addr >= me32.modBaseAddr &&
692                     (BYTE *)addr <  me32.modBaseAddr+me32.modBaseSize)
693                         {
694                         (*close_snap)(hModuleSnap);
695                         FreeLibrary(dll);
696 #ifdef _WIN32_WCE
697 # if _WIN32_WCE >= 101
698                         return WideCharToMultiByte(CP_ACP,0,me32.szExePath,-1,
699                                                         path,sz,NULL,NULL);
700 # else
701                         len = (int)wcslen(me32.szExePath);
702                         if (sz <= 0) return len+1;
703                         if (len >= sz) len=sz-1;
704                         for(i=0;i<len;i++)
705                                 path[i] = (char)me32.szExePath[i];
706                         path[len++] = 0;
707                         return len;
708 # endif
709 #else
710                         len = (int)strlen(me32.szExePath);
711                         if (sz <= 0) return len+1;
712                         if (len >= sz) len=sz-1;
713                         memcpy(path,me32.szExePath,len);
714                         path[len++] = 0;
715                         return len;
716 #endif
717                         } 
718                 } while((*module_next)(hModuleSnap, &me32)); 
719  
720         (*close_snap)(hModuleSnap); 
721         FreeLibrary(dll);
722         return 0;
723         }
724 #endif /* DSO_WIN32 */