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