Have only one DSO_METHOD_openssl
[openssl.git] / crypto / dso / dso_win32.c
1 /*
2  * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
3  * 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 "dso_locl.h"
60
61 #if defined(DSO_WIN32)
62
63 # ifdef _WIN32_WCE
64 #  if _WIN32_WCE < 300
65 static FARPROC GetProcAddressA(HMODULE hModule, LPCSTR lpProcName)
66 {
67     WCHAR lpProcNameW[64];
68     int i;
69
70     for (i = 0; lpProcName[i] && i < 64; i++)
71         lpProcNameW[i] = (WCHAR)lpProcName[i];
72     if (i == 64)
73         return NULL;
74     lpProcNameW[i] = 0;
75
76     return GetProcAddressW(hModule, lpProcNameW);
77 }
78 #  endif
79 #  undef GetProcAddress
80 #  define GetProcAddress GetProcAddressA
81
82 static HINSTANCE LoadLibraryA(LPCSTR lpLibFileName)
83 {
84     WCHAR *fnamw;
85     size_t len_0 = strlen(lpLibFileName) + 1, i;
86
87 #  ifdef _MSC_VER
88     fnamw = (WCHAR *)_alloca(len_0 * sizeof(WCHAR));
89 #  else
90     fnamw = (WCHAR *)alloca(len_0 * sizeof(WCHAR));
91 #  endif
92     if (fnamw == NULL) {
93         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
94         return NULL;
95     }
96 #  if defined(_WIN32_WCE) && _WIN32_WCE>=101
97     if (!MultiByteToWideChar(CP_ACP, 0, lpLibFileName, len_0, fnamw, len_0))
98 #  endif
99         for (i = 0; i < len_0; i++)
100             fnamw[i] = (WCHAR)lpLibFileName[i];
101
102     return LoadLibraryW(fnamw);
103 }
104 # endif
105
106 /* Part of the hack in "win32_load" ... */
107 # define DSO_MAX_TRANSLATED_SIZE 256
108
109 static int win32_load(DSO *dso);
110 static int win32_unload(DSO *dso);
111 static void *win32_bind_var(DSO *dso, const char *symname);
112 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname);
113 static char *win32_name_converter(DSO *dso, const char *filename);
114 static char *win32_merger(DSO *dso, const char *filespec1,
115                           const char *filespec2);
116 static int win32_pathbyaddr(void *addr, char *path, int sz);
117 static void *win32_globallookup(const char *name);
118
119 static const char *openssl_strnchr(const char *string, int c, size_t len);
120
121 static DSO_METHOD dso_meth_win32 = {
122     "OpenSSL 'win32' shared library method",
123     win32_load,
124     win32_unload,
125     win32_bind_var,
126     win32_bind_func,
127     NULL,                       /* ctrl */
128     win32_name_converter,
129     win32_merger,
130     NULL,                       /* init */
131     NULL,                       /* finish */
132     win32_pathbyaddr,
133     win32_globallookup
134 };
135
136 DSO_METHOD *DSO_METHOD_openssl(void)
137 {
138     return &dso_meth_win32;
139 }
140
141 /*
142  * For this DSO_METHOD, our meth_data STACK will contain; (i) a pointer to
143  * the handle (HINSTANCE) returned from LoadLibrary(), and copied.
144  */
145
146 static int win32_load(DSO *dso)
147 {
148     HINSTANCE h = NULL, *p = NULL;
149     /* See applicable comments from dso_dl.c */
150     char *filename = DSO_convert_filename(dso, NULL);
151
152     if (filename == NULL) {
153         DSOerr(DSO_F_WIN32_LOAD, DSO_R_NO_FILENAME);
154         goto err;
155     }
156     h = LoadLibraryA(filename);
157     if (h == NULL) {
158         DSOerr(DSO_F_WIN32_LOAD, DSO_R_LOAD_FAILED);
159         ERR_add_error_data(3, "filename(", filename, ")");
160         goto err;
161     }
162     p = OPENSSL_malloc(sizeof(*p));
163     if (p == NULL) {
164         DSOerr(DSO_F_WIN32_LOAD, ERR_R_MALLOC_FAILURE);
165         goto err;
166     }
167     *p = h;
168     if (!sk_void_push(dso->meth_data, p)) {
169         DSOerr(DSO_F_WIN32_LOAD, DSO_R_STACK_ERROR);
170         goto err;
171     }
172     /* Success */
173     dso->loaded_filename = filename;
174     return (1);
175  err:
176     /* Cleanup ! */
177     OPENSSL_free(filename);
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         DSOerr(DSO_F_WIN32_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
189         return (0);
190     }
191     if (sk_void_num(dso->meth_data) < 1)
192         return (1);
193     p = sk_void_pop(dso->meth_data);
194     if (p == NULL) {
195         DSOerr(DSO_F_WIN32_UNLOAD, DSO_R_NULL_HANDLE);
196         return (0);
197     }
198     if (!FreeLibrary(*p)) {
199         DSOerr(DSO_F_WIN32_UNLOAD, DSO_R_UNLOAD_FAILED);
200         /*
201          * We should push the value back onto the stack in case of a retry.
202          */
203         sk_void_push(dso->meth_data, p);
204         return (0);
205     }
206     /* Cleanup */
207     OPENSSL_free(p);
208     return (1);
209 }
210
211 /*
212  * Using GetProcAddress for variables? TODO: Check this out in the Win32 API
213  * docs, there's probably a variant for variables.
214  */
215 static void *win32_bind_var(DSO *dso, const char *symname)
216 {
217     HINSTANCE *ptr;
218     union {
219         void *p;
220         FARPROC f;
221     } sym;
222
223     if ((dso == NULL) || (symname == NULL)) {
224         DSOerr(DSO_F_WIN32_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
225         return (NULL);
226     }
227     if (sk_void_num(dso->meth_data) < 1) {
228         DSOerr(DSO_F_WIN32_BIND_VAR, DSO_R_STACK_ERROR);
229         return (NULL);
230     }
231     ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
232     if (ptr == NULL) {
233         DSOerr(DSO_F_WIN32_BIND_VAR, DSO_R_NULL_HANDLE);
234         return (NULL);
235     }
236     sym.f = GetProcAddress(*ptr, symname);
237     if (sym.p == NULL) {
238         DSOerr(DSO_F_WIN32_BIND_VAR, DSO_R_SYM_FAILURE);
239         ERR_add_error_data(3, "symname(", symname, ")");
240         return (NULL);
241     }
242     return (sym.p);
243 }
244
245 static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname)
246 {
247     HINSTANCE *ptr;
248     union {
249         void *p;
250         FARPROC f;
251     } sym;
252
253     if ((dso == NULL) || (symname == NULL)) {
254         DSOerr(DSO_F_WIN32_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
255         return (NULL);
256     }
257     if (sk_void_num(dso->meth_data) < 1) {
258         DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_STACK_ERROR);
259         return (NULL);
260     }
261     ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
262     if (ptr == NULL) {
263         DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_NULL_HANDLE);
264         return (NULL);
265     }
266     sym.f = GetProcAddress(*ptr, symname);
267     if (sym.p == NULL) {
268         DSOerr(DSO_F_WIN32_BIND_FUNC, DSO_R_SYM_FAILURE);
269         ERR_add_error_data(3, "symname(", symname, ")");
270         return (NULL);
271     }
272     return ((DSO_FUNC_TYPE)sym.f);
273 }
274
275 struct file_st {
276     const char *node;
277     int nodelen;
278     const char *device;
279     int devicelen;
280     const char *predir;
281     int predirlen;
282     const char *dir;
283     int dirlen;
284     const char *file;
285     int filelen;
286 };
287
288 static struct file_st *win32_splitter(DSO *dso, const char *filename,
289                                       int assume_last_is_dir)
290 {
291     struct file_st *result = NULL;
292     enum { IN_NODE, IN_DEVICE, IN_FILE } position;
293     const char *start = filename;
294     char last;
295
296     if (!filename) {
297         DSOerr(DSO_F_WIN32_SPLITTER, DSO_R_NO_FILENAME);
298         /*
299          * goto err;
300          */
301         return (NULL);
302     }
303
304     result = OPENSSL_zalloc(sizeof(*result));
305     if (result == NULL) {
306         DSOerr(DSO_F_WIN32_SPLITTER, ERR_R_MALLOC_FAILURE);
307         return (NULL);
308     }
309
310     position = IN_DEVICE;
311
312     if ((filename[0] == '\\' && filename[1] == '\\')
313         || (filename[0] == '/' && filename[1] == '/')) {
314         position = IN_NODE;
315         filename += 2;
316         start = filename;
317         result->node = start;
318     }
319
320     do {
321         last = filename[0];
322         switch (last) {
323         case ':':
324             if (position != IN_DEVICE) {
325                 DSOerr(DSO_F_WIN32_SPLITTER, DSO_R_INCORRECT_FILE_SYNTAX);
326                 /*
327                  * goto err;
328                  */
329                 OPENSSL_free(result);
330                 return (NULL);
331             }
332             result->device = start;
333             result->devicelen = (int)(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                 result->nodelen = (int)(filename - start);
342                 position = IN_FILE;
343                 start = ++filename;
344                 result->dir = start;
345             } else if (position == IN_DEVICE) {
346                 position = IN_FILE;
347                 filename++;
348                 result->dir = start;
349                 result->dirlen = (int)(filename - start);
350                 start = filename;
351             } else {
352                 filename++;
353                 result->dirlen += (int)(filename - start);
354                 start = filename;
355             }
356             break;
357         case '\0':
358             if (position == IN_NODE) {
359                 result->nodelen = (int)(filename - start);
360             } else {
361                 if (filename - start > 0) {
362                     if (assume_last_is_dir) {
363                         if (position == IN_DEVICE) {
364                             result->dir = start;
365                             result->dirlen = 0;
366                         }
367                         result->dirlen += (int)(filename - start);
368                     } else {
369                         result->file = start;
370                         result->filelen = (int)(filename - start);
371                     }
372                 }
373             }
374             break;
375         default:
376             filename++;
377             break;
378         }
379     }
380     while (last);
381
382     if (!result->nodelen)
383         result->node = NULL;
384     if (!result->devicelen)
385         result->device = NULL;
386     if (!result->dirlen)
387         result->dir = NULL;
388     if (!result->filelen)
389         result->file = NULL;
390
391     return (result);
392 }
393
394 static char *win32_joiner(DSO *dso, const struct file_st *file_split)
395 {
396     int len = 0, offset = 0;
397     char *result = NULL;
398     const char *start;
399
400     if (!file_split) {
401         DSOerr(DSO_F_WIN32_JOINER, ERR_R_PASSED_NULL_PARAMETER);
402         return (NULL);
403     }
404     if (file_split->node) {
405         len += 2 + file_split->nodelen; /* 2 for starting \\ */
406         if (file_split->predir || file_split->dir || file_split->file)
407             len++;              /* 1 for ending \ */
408     } else if (file_split->device) {
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         len++;                  /* 1 for ending \ */
414     }
415     len += file_split->dirlen;
416     if (file_split->dir && file_split->file) {
417         len++;                  /* 1 for ending \ */
418     }
419     len += file_split->filelen;
420
421     if (!len) {
422         DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
423         return (NULL);
424     }
425
426     result = OPENSSL_malloc(len + 1);
427     if (result == NULL) {
428         DSOerr(DSO_F_WIN32_JOINER, ERR_R_MALLOC_FAILURE);
429         return (NULL);
430     }
431
432     if (file_split->node) {
433         strcpy(&result[offset], "\\\\");
434         offset += 2;
435         strncpy(&result[offset], file_split->node, file_split->nodelen);
436         offset += file_split->nodelen;
437         if (file_split->predir || file_split->dir || file_split->file) {
438             result[offset] = '\\';
439             offset++;
440         }
441     } else if (file_split->device) {
442         strncpy(&result[offset], file_split->device, file_split->devicelen);
443         offset += file_split->devicelen;
444         result[offset] = ':';
445         offset++;
446     }
447     start = file_split->predir;
448     while (file_split->predirlen > (start - file_split->predir)) {
449         const char *end = openssl_strnchr(start, '/',
450                                           file_split->predirlen - (start -
451                                                                    file_split->predir));
452         if (!end)
453             end = start
454                 + file_split->predirlen - (start - file_split->predir);
455         strncpy(&result[offset], start, end - start);
456         offset += (int)(end - start);
457         result[offset] = '\\';
458         offset++;
459         start = end + 1;
460     }
461     start = file_split->dir;
462     while (file_split->dirlen > (start - file_split->dir)) {
463         const char *end = openssl_strnchr(start, '/',
464                                           file_split->dirlen - (start -
465                                                                 file_split->dir));
466         if (!end)
467             end = start + file_split->dirlen - (start - file_split->dir);
468         strncpy(&result[offset], start, end - start);
469         offset += (int)(end - start);
470         result[offset] = '\\';
471         offset++;
472         start = end + 1;
473     }
474     strncpy(&result[offset], file_split->file, file_split->filelen);
475     offset += file_split->filelen;
476     result[offset] = '\0';
477     return (result);
478 }
479
480 static char *win32_merger(DSO *dso, const char *filespec1,
481                           const char *filespec2)
482 {
483     char *merged = NULL;
484     struct file_st *filespec1_split = NULL;
485     struct file_st *filespec2_split = NULL;
486
487     if (!filespec1 && !filespec2) {
488         DSOerr(DSO_F_WIN32_MERGER, ERR_R_PASSED_NULL_PARAMETER);
489         return (NULL);
490     }
491     if (!filespec2) {
492         merged = OPENSSL_malloc(strlen(filespec1) + 1);
493         if (merged == NULL) {
494             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
495             return (NULL);
496         }
497         strcpy(merged, filespec1);
498     } else if (!filespec1) {
499         merged = OPENSSL_malloc(strlen(filespec2) + 1);
500         if (merged == NULL) {
501             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
502             return (NULL);
503         }
504         strcpy(merged, filespec2);
505     } else {
506         filespec1_split = win32_splitter(dso, filespec1, 0);
507         if (!filespec1_split) {
508             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
509             return (NULL);
510         }
511         filespec2_split = win32_splitter(dso, filespec2, 1);
512         if (!filespec2_split) {
513             DSOerr(DSO_F_WIN32_MERGER, ERR_R_MALLOC_FAILURE);
514             OPENSSL_free(filespec1_split);
515             return (NULL);
516         }
517
518         /* Fill in into filespec1_split */
519         if (!filespec1_split->node && !filespec1_split->device) {
520             filespec1_split->node = filespec2_split->node;
521             filespec1_split->nodelen = filespec2_split->nodelen;
522             filespec1_split->device = filespec2_split->device;
523             filespec1_split->devicelen = filespec2_split->devicelen;
524         }
525         if (!filespec1_split->dir) {
526             filespec1_split->dir = filespec2_split->dir;
527             filespec1_split->dirlen = filespec2_split->dirlen;
528         } else if (filespec1_split->dir[0] != '\\'
529                    && filespec1_split->dir[0] != '/') {
530             filespec1_split->predir = filespec2_split->dir;
531             filespec1_split->predirlen = filespec2_split->dirlen;
532         }
533         if (!filespec1_split->file) {
534             filespec1_split->file = filespec2_split->file;
535             filespec1_split->filelen = filespec2_split->filelen;
536         }
537
538         merged = win32_joiner(dso, filespec1_split);
539     }
540     OPENSSL_free(filespec1_split);
541     OPENSSL_free(filespec2_split);
542     return (merged);
543 }
544
545 static char *win32_name_converter(DSO *dso, const char *filename)
546 {
547     char *translated;
548     int len, transform;
549
550     len = strlen(filename);
551     transform = ((strstr(filename, "/") == NULL) &&
552                  (strstr(filename, "\\") == NULL) &&
553                  (strstr(filename, ":") == NULL));
554     if (transform)
555         /* We will convert this to "%s.dll" */
556         translated = OPENSSL_malloc(len + 5);
557     else
558         /* We will simply duplicate filename */
559         translated = OPENSSL_malloc(len + 1);
560     if (translated == NULL) {
561         DSOerr(DSO_F_WIN32_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
562         return (NULL);
563     }
564     if (transform)
565         sprintf(translated, "%s.dll", filename);
566     else
567         sprintf(translated, "%s", filename);
568     return (translated);
569 }
570
571 static const char *openssl_strnchr(const char *string, int c, size_t len)
572 {
573     size_t i;
574     const char *p;
575     for (i = 0, p = string; i < len && *p; i++, p++) {
576         if (*p == c)
577             return p;
578     }
579     return NULL;
580 }
581
582 # include <tlhelp32.h>
583 # ifdef _WIN32_WCE
584 #  define DLLNAME "TOOLHELP.DLL"
585 # else
586 #  ifdef MODULEENTRY32
587 #   undef MODULEENTRY32         /* unmask the ASCII version! */
588 #  endif
589 #  define DLLNAME "KERNEL32.DLL"
590 # endif
591
592 typedef HANDLE(WINAPI *CREATETOOLHELP32SNAPSHOT) (DWORD, DWORD);
593 typedef BOOL(WINAPI *CLOSETOOLHELP32SNAPSHOT) (HANDLE);
594 typedef BOOL(WINAPI *MODULE32) (HANDLE, MODULEENTRY32 *);
595
596 static int win32_pathbyaddr(void *addr, char *path, int sz)
597 {
598     HMODULE dll;
599     HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
600     MODULEENTRY32 me32;
601     CREATETOOLHELP32SNAPSHOT create_snap;
602     CLOSETOOLHELP32SNAPSHOT close_snap;
603     MODULE32 module_first, module_next;
604
605     if (addr == NULL) {
606         union {
607             int (*f) (void *, char *, int);
608             void *p;
609         } t = {
610             win32_pathbyaddr
611         };
612         addr = t.p;
613     }
614
615     dll = LoadLibrary(TEXT(DLLNAME));
616     if (dll == NULL) {
617         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_UNSUPPORTED);
618         return -1;
619     }
620
621     create_snap = (CREATETOOLHELP32SNAPSHOT)
622         GetProcAddress(dll, "CreateToolhelp32Snapshot");
623     if (create_snap == NULL) {
624         FreeLibrary(dll);
625         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_UNSUPPORTED);
626         return -1;
627     }
628     /* We take the rest for granted... */
629 # ifdef _WIN32_WCE
630     close_snap = (CLOSETOOLHELP32SNAPSHOT)
631         GetProcAddress(dll, "CloseToolhelp32Snapshot");
632 # else
633     close_snap = (CLOSETOOLHELP32SNAPSHOT) CloseHandle;
634 # endif
635     module_first = (MODULE32) GetProcAddress(dll, "Module32First");
636     module_next = (MODULE32) GetProcAddress(dll, "Module32Next");
637
638     hModuleSnap = (*create_snap) (TH32CS_SNAPMODULE, 0);
639     if (hModuleSnap == INVALID_HANDLE_VALUE) {
640         FreeLibrary(dll);
641         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_UNSUPPORTED);
642         return -1;
643     }
644
645     me32.dwSize = sizeof(me32);
646
647     if (!(*module_first) (hModuleSnap, &me32)) {
648         (*close_snap) (hModuleSnap);
649         FreeLibrary(dll);
650         DSOerr(DSO_F_WIN32_PATHBYADDR, DSO_R_FAILURE);
651         return -1;
652     }
653
654     do {
655         if ((BYTE *) addr >= me32.modBaseAddr &&
656             (BYTE *) addr < me32.modBaseAddr + me32.modBaseSize) {
657             (*close_snap) (hModuleSnap);
658             FreeLibrary(dll);
659 # ifdef _WIN32_WCE
660 #  if _WIN32_WCE >= 101
661             return WideCharToMultiByte(CP_ACP, 0, me32.szExePath, -1,
662                                        path, sz, NULL, NULL);
663 #  else
664             {
665                 int i, len = (int)wcslen(me32.szExePath);
666                 if (sz <= 0)
667                     return len + 1;
668                 if (len >= sz)
669                     len = sz - 1;
670                 for (i = 0; i < len; i++)
671                     path[i] = (char)me32.szExePath[i];
672                 path[len++] = 0;
673                 return len;
674             }
675 #  endif
676 # else
677             {
678                 int len = (int)strlen(me32.szExePath);
679                 if (sz <= 0)
680                     return len + 1;
681                 if (len >= sz)
682                     len = sz - 1;
683                 memcpy(path, me32.szExePath, len);
684                 path[len++] = 0;
685                 return len;
686             }
687 # endif
688         }
689     } while ((*module_next) (hModuleSnap, &me32));
690
691     (*close_snap) (hModuleSnap);
692     FreeLibrary(dll);
693     return 0;
694 }
695
696 static void *win32_globallookup(const char *name)
697 {
698     HMODULE dll;
699     HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
700     MODULEENTRY32 me32;
701     CREATETOOLHELP32SNAPSHOT create_snap;
702     CLOSETOOLHELP32SNAPSHOT close_snap;
703     MODULE32 module_first, module_next;
704     union {
705         void *p;
706         FARPROC f;
707     } ret = { NULL };
708
709     dll = LoadLibrary(TEXT(DLLNAME));
710     if (dll == NULL) {
711         DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
712         return NULL;
713     }
714
715     create_snap = (CREATETOOLHELP32SNAPSHOT)
716         GetProcAddress(dll, "CreateToolhelp32Snapshot");
717     if (create_snap == NULL) {
718         FreeLibrary(dll);
719         DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
720         return NULL;
721     }
722     /* We take the rest for granted... */
723 # ifdef _WIN32_WCE
724     close_snap = (CLOSETOOLHELP32SNAPSHOT)
725         GetProcAddress(dll, "CloseToolhelp32Snapshot");
726 # else
727     close_snap = (CLOSETOOLHELP32SNAPSHOT) CloseHandle;
728 # endif
729     module_first = (MODULE32) GetProcAddress(dll, "Module32First");
730     module_next = (MODULE32) GetProcAddress(dll, "Module32Next");
731
732     hModuleSnap = (*create_snap) (TH32CS_SNAPMODULE, 0);
733     if (hModuleSnap == INVALID_HANDLE_VALUE) {
734         FreeLibrary(dll);
735         DSOerr(DSO_F_WIN32_GLOBALLOOKUP, DSO_R_UNSUPPORTED);
736         return NULL;
737     }
738
739     me32.dwSize = sizeof(me32);
740
741     if (!(*module_first) (hModuleSnap, &me32)) {
742         (*close_snap) (hModuleSnap);
743         FreeLibrary(dll);
744         return NULL;
745     }
746
747     do {
748         if ((ret.f = GetProcAddress(me32.hModule, name))) {
749             (*close_snap) (hModuleSnap);
750             FreeLibrary(dll);
751             return ret.p;
752         }
753     } while ((*module_next) (hModuleSnap, &me32));
754
755     (*close_snap) (hModuleSnap);
756     FreeLibrary(dll);
757     return NULL;
758 }
759 #endif                          /* DSO_WIN32 */