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