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