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