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