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)
66DSO_METHOD *DSO_METHOD_win32(void)
67{
68    return NULL;
69}
70#else
71
72# ifdef _WIN32_WCE
73#  if _WIN32_WCE < 300
74static 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
91static 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
118static int win32_load(DSO *dso);
119static int win32_unload(DSO *dso);
120static void *win32_bind_var(DSO *dso, const char *symname);
121static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname);
122# if 0
123static int win32_unbind_var(DSO *dso, char *symname, void *symptr);
124static int win32_unbind_func(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
125static int win32_init(DSO *dso);
126static int win32_finish(DSO *dso);
127static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg);
128# endif
129static char *win32_name_converter(DSO *dso, const char *filename);
130static char *win32_merger(DSO *dso, const char *filespec1,
131                          const char *filespec2);
132static int win32_pathbyaddr(void *addr, char *path, int sz);
133static void *win32_globallookup(const char *name);
134
135static const char *openssl_strnchr(const char *string, int c, size_t len);
136
137static 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
157DSO_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
167static 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
207static 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 */
238static 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
265static 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
292struct 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
305static 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
412static 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
512static 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
577static 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
603static 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
624typedef HANDLE(WINAPI *CREATETOOLHELP32SNAPSHOT) (DWORD, DWORD);
625typedef BOOL(WINAPI *CLOSETOOLHELP32SNAPSHOT) (HANDLE);
626typedef BOOL(WINAPI *MODULE32) (HANDLE, MODULEENTRY32 *);
627
628static 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
728static 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 */
789