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