Fix pedantic warnings in mingw builds.
[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 "internal/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 = OPENSSL_malloc(sizeof(*p));
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     OPENSSL_free(filename);
187     OPENSSL_free(p);
188     if (h != NULL)
189         FreeLibrary(h);
190     return (0);
191 }
192
193 static int win32_unload(DSO *dso)
194 {
195     HINSTANCE *p;
196     if (dso == NULL) {
197         DSOerr(DSO_F_WIN32_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
198         return (0);
199     }
200     if (sk_void_num(dso->meth_data) < 1)
201         return (1);
202     p = sk_void_pop(dso->meth_data);
203     if (p == NULL) {
204         DSOerr(DSO_F_WIN32_UNLOAD, DSO_R_NULL_HANDLE);
205         return (0);
206     }
207     if (!FreeLibrary(*p)) {
208         DSOerr(DSO_F_WIN32_UNLOAD, DSO_R_UNLOAD_FAILED);
209         /*
210          * We should push the value back onto the stack in case of a retry.
211          */
212         sk_void_push(dso->meth_data, p);
213         return (0);
214     }
215     /* Cleanup */
216     OPENSSL_free(p);
217     return (1);
218 }
219
220 /*
221  * Using GetProcAddress for variables? TODO: Check this out in the Win32 API
222  * docs, there's probably a variant for variables.
223  */
224 static void *win32_bind_var(DSO *dso, const char *symname)
225 {
226     HINSTANCE *ptr;
227     union {
228         void *p;
229         FARPROC f;
230     } sym;
231
232     if ((dso == NULL) || (symname == NULL)) {
233         DSOerr(DSO_F_WIN32_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
234         return (NULL);
235     }
236     if (sk_void_num(dso->meth_data) < 1) {
237         DSOerr(DSO_F_WIN32_BIND_VAR, DSO_R_STACK_ERROR);
238         return (NULL);
239     }
240     ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
241     if (ptr == NULL) {
242         DSOerr(DSO_F_WIN32_BIND_VAR, DSO_R_NULL_HANDLE);
243         return (NULL);
244     }
245     sym.f = GetProcAddress(*ptr, symname);
246     if (sym.p == NULL) {
247         DSOerr(DSO_F_WIN32_BIND_VAR, DSO_R_SYM_FAILURE);
248         ERR_add_error_data(3, "symname(", symname, ")");
249         return (NULL);
250     }
251     return (sym.p);
252 }
253
254 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
255 {
256     HINSTANCE *ptr;
257     union {
258         void *p;
259         FARPROC f;
260     } sym;
261
262     if ((dso == NULL) || (symname == NULL)) {
263         DSOerr(DSO_F_WIN32_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
264         return (NULL);
265     }
266     if (sk_void_num(dso->meth_data) < 1) {
267         DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_STACK_ERROR);
268         return (NULL);
269     }
270     ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
271     if (ptr == NULL) {
272         DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_NULL_HANDLE);
273         return (NULL);
274     }
275     sym.f = GetProcAddress(*ptr, symname);
276     if (sym.p == NULL) {
277         DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_SYM_FAILURE);
278         ERR_add_error_data(3, "symname(", symname, ")");
279         return (NULL);
280     }
281     return ((DSO_FUNC_TYPE)sym.f);
282 }
283
284 struct file_st {
285     const char *node;
286     int nodelen;
287     const char *device;
288     int devicelen;
289     const char *predir;
290     int predirlen;
291     const char *dir;
292     int dirlen;
293     const char *file;
294     int filelen;
295 };
296
297 static struct file_st *win32_splitter(DSO *dso, const char *filename,
298                                       int assume_last_is_dir)
299 {
300     struct file_st *result = NULL;
301     enum { IN_NODE, IN_DEVICE, IN_FILE } position;
302     const char *start = filename;
303     char last;
304
305     if (!filename) {
306         DSOerr(DSO_F_WIN32_SPLITTER, DSO_R_NO_FILENAME);
307         /*
308          * goto err;
309          */
310         return (NULL);
311     }
312
313     result = OPENSSL_zalloc(sizeof(*result));
314     if (result == NULL) {
315         DSOerr(DSO_F_WIN32_SPLITTER, ERR_R_MALLOC_FAILURE);
316         return (NULL);
317     }
318
319     position = IN_DEVICE;
320
321     if ((filename[0] == '\\' && filename[1] == '\\')
322         || (filename[0] == '/' && filename[1] == '/')) {
323         position = IN_NODE;
324         filename += 2;
325         start = filename;
326         result->node = start;
327     }
328
329     do {
330         last = filename[0];
331         switch (last) {
332         case ':':
333             if (position != IN_DEVICE) {
334                 DSOerr(DSO_F_WIN32_SPLITTER, DSO_R_INCORRECT_FILE_SYNTAX);
335                 /*
336                  * goto err;
337                  */
338                 OPENSSL_free(result);
339                 return (NULL);
340             }
341             result->device = start;
342             result->devicelen = (int)(filename - start);
343             position = IN_FILE;
344             start = ++filename;
345             result->dir = start;
346             break;
347         case '\\':
348         case '/':
349             if (position == IN_NODE) {
350                 result->nodelen = (int)(filename - start);
351                 position = IN_FILE;
352                 start = ++filename;
353                 result->dir = start;
354             } else if (position == IN_DEVICE) {
355                 position = IN_FILE;
356                 filename++;
357                 result->dir = start;
358                 result->dirlen = (int)(filename - start);
359                 start = filename;
360             } else {
361                 filename++;
362                 result->dirlen += (int)(filename - start);
363                 start = filename;
364             }
365             break;
366         case '\0':
367             if (position == IN_NODE) {
368                 result->nodelen = (int)(filename - start);
369             } else {
370                 if (filename - start > 0) {
371                     if (assume_last_is_dir) {
372                         if (position == IN_DEVICE) {
373                             result->dir = start;
374                             result->dirlen = 0;
375                         }
376                         result->dirlen += (int)(filename - start);
377                     } else {
378                         result->file = start;
379                         result->filelen = (int)(filename - start);
380                     }
381                 }
382             }
383             break;
384         default:
385             filename++;
386             break;
387         }
388     }
389     while (last);
390
391     if (!result->nodelen)
392         result->node = NULL;
393     if (!result->devicelen)
394         result->device = NULL;
395     if (!result->dirlen)
396         result->dir = NULL;
397     if (!result->filelen)
398         result->file = NULL;
399
400     return (result);
401 }
402
403 static char *win32_joiner(DSO *dso, const struct file_st *file_split)
404 {
405     int len = 0, offset = 0;
406     char *result = NULL;
407     const char *start;
408
409     if (!file_split) {
410         DSOerr(DSO_F_WIN32_JOINER, ERR_R_PASSED_NULL_PARAMETER);
411         return (NULL);
412     }
413     if (file_split->node) {
414         len += 2 + file_split->nodelen; /* 2 for starting \\ */
415         if (file_split->predir || file_split->dir || file_split->file)
416             len++;              /* 1 for ending \ */
417     } else if (file_split->device) {
418         len += file_split->devicelen + 1; /* 1 for ending : */
419     }
420     len += file_split->predirlen;
421     if (file_split->predir && (file_split->dir || file_split->file)) {
422         len++;                  /* 1 for ending \ */
423     }
424     len += file_split->dirlen;
425     if (file_split->dir && file_split->file) {
426         len++;                  /* 1 for ending \ */
427     }
428     len += file_split->filelen;
429
430     if (!len) {
431         DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
432         return (NULL);
433     }
434
435     result = OPENSSL_malloc(len + 1);
436     if (!result) {
437         DSOerr(DSO_F_WIN32_JOINER, ERR_R_MALLOC_FAILURE);
438         return (NULL);
439     }
440
441     if (file_split->node) {
442         strcpy(&result[offset], "\\\\");
443         offset += 2;
444         strncpy(&result[offset], file_split->node, file_split->nodelen);
445         offset += file_split->nodelen;
446         if (file_split->predir || file_split->dir || file_split->file) {
447             result[offset] = '\\';
448             offset++;
449         }
450     } else if (file_split->device) {
451         strncpy(&result[offset], file_split->device, file_split->devicelen);
452         offset += file_split->devicelen;
453         result[offset] = ':';
454         offset++;
455     }
456     start = file_split->predir;
457     while (file_split->predirlen > (start - file_split->predir)) {
458         const char *end = openssl_strnchr(start, '/',
459                                           file_split->predirlen - (start -
460                                                                    file_split->predir));
461         if (!end)
462             end = start
463                 + file_split->predirlen - (start - file_split->predir);
464         strncpy(&result[offset], start, end - start);
465         offset += (int)(end - start);
466         result[offset] = '\\';
467         offset++;
468         start = end + 1;
469     }
470     start = file_split->dir;
471     while (file_split->dirlen > (start - file_split->dir)) {
472         const char *end = openssl_strnchr(start, '/',
473                                           file_split->dirlen - (start -
474                                                                 file_split->dir));
475         if (!end)
476             end = start + file_split->dirlen - (start - file_split->dir);
477         strncpy(&result[offset], start, end - start);
478         offset += (int)(end - start);
479         result[offset] = '\\';
480         offset++;
481         start = end + 1;
482     }
483     strncpy(&result[offset], file_split->file, file_split->filelen);
484     offset += file_split->filelen;
485     result[offset] = '\0';
486     return (result);
487 }
488
489 static char *win32_merger(DSO *dso, const char *filespec1,
490                           const char *filespec2)
491 {
492     char *merged = NULL;
493     struct file_st *filespec1_split = NULL;
494     struct file_st *filespec2_split = NULL;
495
496     if (!filespec1 && !filespec2) {
497         DSOerr(DSO_F_WIN32_MERGER, ERR_R_PASSED_NULL_PARAMETER);
498         return (NULL);
499     }
500     if (!filespec2) {
501         merged = OPENSSL_malloc(strlen(filespec1) + 1);
502         if (!merged) {
503             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
504             return (NULL);
505         }
506         strcpy(merged, filespec1);
507     } else if (!filespec1) {
508         merged = OPENSSL_malloc(strlen(filespec2) + 1);
509         if (!merged) {
510             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
511             return (NULL);
512         }
513         strcpy(merged, filespec2);
514     } else {
515         filespec1_split = win32_splitter(dso, filespec1, 0);
516         if (!filespec1_split) {
517             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
518             return (NULL);
519         }
520         filespec2_split = win32_splitter(dso, filespec2, 1);
521         if (!filespec2_split) {
522             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
523             OPENSSL_free(filespec1_split);
524             return (NULL);
525         }
526
527         /* Fill in into filespec1_split */
528         if (!filespec1_split->node && !filespec1_split->device) {
529             filespec1_split->node = filespec2_split->node;
530             filespec1_split->nodelen = filespec2_split->nodelen;
531             filespec1_split->device = filespec2_split->device;
532             filespec1_split->devicelen = filespec2_split->devicelen;
533         }
534         if (!filespec1_split->dir) {
535             filespec1_split->dir = filespec2_split->dir;
536             filespec1_split->dirlen = filespec2_split->dirlen;
537         } else if (filespec1_split->dir[0] != '\\'
538                    && filespec1_split->dir[0] != '/') {
539             filespec1_split->predir = filespec2_split->dir;
540             filespec1_split->predirlen = filespec2_split->dirlen;
541         }
542         if (!filespec1_split->file) {
543             filespec1_split->file = filespec2_split->file;
544             filespec1_split->filelen = filespec2_split->filelen;
545         }
546
547         merged = win32_joiner(dso, filespec1_split);
548     }
549     OPENSSL_free(filespec1_split);
550     OPENSSL_free(filespec2_split);
551     return (merged);
552 }
553
554 static char *win32_name_converter(DSO *dso, const char *filename)
555 {
556     char *translated;
557     int len, transform;
558
559     len = strlen(filename);
560     transform = ((strstr(filename, "/") == NULL) &&
561                  (strstr(filename, "\\") == NULL) &&
562                  (strstr(filename, ":") == NULL));
563     if (transform)
564         /* We will convert this to "%s.dll" */
565         translated = OPENSSL_malloc(len + 5);
566     else
567         /* We will simply duplicate filename */
568         translated = OPENSSL_malloc(len + 1);
569     if (translated == NULL) {
570         DSOerr(DSO_F_WIN32_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
571         return (NULL);
572     }
573     if (transform)
574         sprintf(translated, "%s.dll", filename);
575     else
576         sprintf(translated, "%s", filename);
577     return (translated);
578 }
579
580 static const char *openssl_strnchr(const char *string, int c, size_t len)
581 {
582     size_t i;
583     const char *p;
584     for (i = 0, p = string; i < len && *p; i++, p++) {
585         if (*p == c)
586             return p;
587     }
588     return NULL;
589 }
590
591 # include <tlhelp32.h>
592 # ifdef _WIN32_WCE
593 #  define DLLNAME "TOOLHELP.DLL"
594 # else
595 #  ifdef MODULEENTRY32
596 #   undef MODULEENTRY32         /* unmask the ASCII version! */
597 #  endif
598 #  define DLLNAME "KERNEL32.DLL"
599 # endif
600
601 typedef HANDLE(WINAPI *CREATETOOLHELP32SNAPSHOT) (DWORD, DWORD);
602 typedef BOOL(WINAPI *CLOSETOOLHELP32SNAPSHOT) (HANDLE);
603 typedef BOOL(WINAPI *MODULE32) (HANDLE, MODULEENTRY32 *);
604
605 static int win32_pathbyaddr(void *addr, char *path, int sz)
606 {
607     HMODULE dll;
608     HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
609     MODULEENTRY32 me32;
610     CREATETOOLHELP32SNAPSHOT create_snap;
611     CLOSETOOLHELP32SNAPSHOT close_snap;
612     MODULE32 module_first, module_next;
613
614     if (addr == NULL) {
615         union {
616             int (*f) (void *, char *, int);
617             void *p;
618         } t = {
619             win32_pathbyaddr
620         };
621         addr = t.p;
622     }
623
624     dll = LoadLibrary(TEXT(DLLNAME));
625     if (dll == NULL) {
626         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_UNSUPPORTED);
627         return -1;
628     }
629
630     create_snap = (CREATETOOLHELP32SNAPSHOT)
631         GetProcAddress(dll, "CreateToolhelp32Snapshot");
632     if (create_snap == NULL) {
633         FreeLibrary(dll);
634         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_UNSUPPORTED);
635         return -1;
636     }
637     /* We take the rest for granted... */
638 # ifdef _WIN32_WCE
639     close_snap = (CLOSETOOLHELP32SNAPSHOT)
640         GetProcAddress(dll, "CloseToolhelp32Snapshot");
641 # else
642     close_snap = (CLOSETOOLHELP32SNAPSHOT) CloseHandle;
643 # endif
644     module_first = (MODULE32) GetProcAddress(dll, "Module32First");
645     module_next = (MODULE32) GetProcAddress(dll, "Module32Next");
646
647     hModuleSnap = (*create_snap) (TH32CS_SNAPMODULE, 0);
648     if (hModuleSnap == INVALID_HANDLE_VALUE) {
649         FreeLibrary(dll);
650         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_UNSUPPORTED);
651         return -1;
652     }
653
654     me32.dwSize = sizeof(me32);
655
656     if (!(*module_first) (hModuleSnap, &me32)) {
657         (*close_snap) (hModuleSnap);
658         FreeLibrary(dll);
659         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_FAILURE);
660         return -1;
661     }
662
663     do {
664         if ((BYTE *) addr >= me32.modBaseAddr &&
665             (BYTE *) addr < me32.modBaseAddr + me32.modBaseSize) {
666             (*close_snap) (hModuleSnap);
667             FreeLibrary(dll);
668 # ifdef _WIN32_WCE
669 #  if _WIN32_WCE >= 101
670             return WideCharToMultiByte(CP_ACP, 0, me32.szExePath, -1,
671                                        path, sz, NULL, NULL);
672 #  else
673             {
674                 int i, len = (int)wcslen(me32.szExePath);
675                 if (sz <= 0)
676                     return len + 1;
677                 if (len >= sz)
678                     len = sz - 1;
679                 for (i = 0; i < len; i++)
680                     path[i] = (char)me32.szExePath[i];
681                 path[len++] = 0;
682                 return len;
683             }
684 #  endif
685 # else
686             {
687                 int len = (int)strlen(me32.szExePath);
688                 if (sz <= 0)
689                     return len + 1;
690                 if (len >= sz)
691                     len = sz - 1;
692                 memcpy(path, me32.szExePath, len);
693                 path[len++] = 0;
694                 return len;
695             }
696 # endif
697         }
698     } while ((*module_next) (hModuleSnap, &me32));
699
700     (*close_snap) (hModuleSnap);
701     FreeLibrary(dll);
702     return 0;
703 }
704
705 static void *win32_globallookup(const char *name)
706 {
707     HMODULE dll;
708     HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
709     MODULEENTRY32 me32;
710     CREATETOOLHELP32SNAPSHOT create_snap;
711     CLOSETOOLHELP32SNAPSHOT close_snap;
712     MODULE32 module_first, module_next;
713     union {
714         void *p;
715         FARPROC f;
716     } ret = { NULL };
717
718     dll = LoadLibrary(TEXT(DLLNAME));
719     if (dll == NULL) {
720         DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
721         return NULL;
722     }
723
724     create_snap = (CREATETOOLHELP32SNAPSHOT)
725         GetProcAddress(dll, "CreateToolhelp32Snapshot");
726     if (create_snap == NULL) {
727         FreeLibrary(dll);
728         DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
729         return NULL;
730     }
731     /* We take the rest for granted... */
732 # ifdef _WIN32_WCE
733     close_snap = (CLOSETOOLHELP32SNAPSHOT)
734         GetProcAddress(dll, "CloseToolhelp32Snapshot");
735 # else
736     close_snap = (CLOSETOOLHELP32SNAPSHOT) CloseHandle;
737 # endif
738     module_first = (MODULE32) GetProcAddress(dll, "Module32First");
739     module_next = (MODULE32) GetProcAddress(dll, "Module32Next");
740
741     hModuleSnap = (*create_snap) (TH32CS_SNAPMODULE, 0);
742     if (hModuleSnap == INVALID_HANDLE_VALUE) {
743         FreeLibrary(dll);
744         DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
745         return NULL;
746     }
747
748     me32.dwSize = sizeof(me32);
749
750     if (!(*module_first) (hModuleSnap, &me32)) {
751         (*close_snap) (hModuleSnap);
752         FreeLibrary(dll);
753         return NULL;
754     }
755
756     do {
757         if ((ret.f = GetProcAddress(me32.hModule, name))) {
758             (*close_snap) (hModuleSnap);
759             FreeLibrary(dll);
760             return ret.p;
761         }
762     } while ((*module_next) (hModuleSnap, &me32));
763
764     (*close_snap) (hModuleSnap);
765     FreeLibrary(dll);
766     return NULL;
767 }
768 #endif                          /* DSO_WIN32 */