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_void_push(dso->meth_data, 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_void_num(dso->meth_data) < 1)
219 		return(1);
220 	p = sk_void_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_void_push(dso->meth_data, 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_void_num(dso->meth_data) < 1)
252 		{
253 		DSOerr(DSO_F_WIN32_BIND_VAR,DSO_R_STACK_ERROR);
254 		return(NULL);
255 		}
256 	ptr = sk_void_value(dso->meth_data, sk_void_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_void_num(dso->meth_data) < 1)
283 		{
284 		DSOerr(DSO_F_WIN32_BIND_FUNC,DSO_R_STACK_ERROR);
285 		return(NULL);
286 		}
287 	ptr = sk_void_value(dso->meth_data, sk_void_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 				OPENSSL_free(result);
359 				return(NULL);
360 				}
361 			result->device = start;
362 			result->devicelen = (int)(filename - start);
363 			position = IN_FILE;
364 			start = ++filename;
365 			result->dir = start;
366 			break;
367 		case '\\':
368 		case '/':
369 			if(position == IN_NODE)
370 				{
371 				result->nodelen = (int)(filename - start);
372 				position = IN_FILE;
373 				start = ++filename;
374 				result->dir = start;
375 				}
376 			else if(position == IN_DEVICE)
377 				{
378 				position = IN_FILE;
379 				filename++;
380 				result->dir = start;
381 				result->dirlen = (int)(filename - start);
382 				start = filename;
383 				}
384 			else
385 				{
386 				filename++;
387 				result->dirlen += (int)(filename - start);
388 				start = filename;
389 				}
390 			break;
391 		case '\0':
392 			if(position == IN_NODE)
393 				{
394 				result->nodelen = (int)(filename - start);
395 				}
396 			else
397 				{
398 				if(filename - start > 0)
399 					{
400 					if (assume_last_is_dir)
401 						{
402 						if (position == IN_DEVICE)
403 							{
404 							result->dir = start;
405 							result->dirlen = 0;
406 							}
407 						result->dirlen +=
408 							(int)(filename - start);
409 						}
410 					else
411 						{
412 						result->file = start;
413 						result->filelen =
414 							(int)(filename - start);
415 						}
416 					}
417 				}
418 			break;
419 		default:
420 			filename++;
421 			break;
422 			}
423 		}
424 	while(last);
425 
426 	if(!result->nodelen) result->node = NULL;
427 	if(!result->devicelen) result->device = NULL;
428 	if(!result->dirlen) result->dir = NULL;
429 	if(!result->filelen) result->file = NULL;
430 
431 	return(result);
432 	}
433 
434 static char *win32_joiner(DSO *dso, const struct file_st *file_split)
435 	{
436 	int len = 0, offset = 0;
437 	char *result = NULL;
438 	const char *start;
439 
440 	if(!file_split)
441 		{
442 		DSOerr(DSO_F_WIN32_JOINER,
443 				ERR_R_PASSED_NULL_PARAMETER);
444 		return(NULL);
445 		}
446 	if(file_split->node)
447 		{
448 		len += 2 + file_split->nodelen;	/* 2 for starting \\ */
449 		if(file_split->predir || file_split->dir || file_split->file)
450 			len++;	/* 1 for ending \ */
451 		}
452 	else if(file_split->device)
453 		{
454 		len += file_split->devicelen + 1; /* 1 for ending : */
455 		}
456 	len += file_split->predirlen;
457 	if(file_split->predir && (file_split->dir || file_split->file))
458 		{
459 		len++;	/* 1 for ending \ */
460 		}
461 	len += file_split->dirlen;
462 	if(file_split->dir && file_split->file)
463 		{
464 		len++;	/* 1 for ending \ */
465 		}
466 	len += file_split->filelen;
467 
468 	if(!len)
469 		{
470 		DSOerr(DSO_F_WIN32_JOINER, DSO_R_EMPTY_FILE_STRUCTURE);
471 		return(NULL);
472 		}
473 
474 	result = OPENSSL_malloc(len + 1);
475 	if (!result)
476 		{
477 		DSOerr(DSO_F_WIN32_JOINER,
478 			ERR_R_MALLOC_FAILURE);
479 		return(NULL);
480 		}
481 
482 	if(file_split->node)
483 		{
484 		strcpy(&result[offset], "\\\\"); offset += 2;
485 		strncpy(&result[offset], file_split->node,
486 			file_split->nodelen); offset += file_split->nodelen;
487 		if(file_split->predir || file_split->dir || file_split->file)
488 			{
489 			result[offset] = '\\'; offset++;
490 			}
491 		}
492 	else if(file_split->device)
493 		{
494 		strncpy(&result[offset], file_split->device,
495 			file_split->devicelen); offset += file_split->devicelen;
496 		result[offset] = ':'; offset++;
497 		}
498 	start = file_split->predir;
499 	while(file_split->predirlen > (start - file_split->predir))
500 		{
501 		const char *end = openssl_strnchr(start, '/',
502 			file_split->predirlen - (start - file_split->predir));
503 		if(!end)
504 			end = start
505 				+ file_split->predirlen
506 				- (start - file_split->predir);
507 		strncpy(&result[offset], start,
508 			end - start); offset += (int)(end - start);
509 		result[offset] = '\\'; offset++;
510 		start = end + 1;
511 		}
512 #if 0 /* Not needed, since the directory converter above already appeneded
513 	 a backslash */
514 	if(file_split->predir && (file_split->dir || file_split->file))
515 		{
516 		result[offset] = '\\'; offset++;
517 		}
518 #endif
519 	start = file_split->dir;
520 	while(file_split->dirlen > (start - file_split->dir))
521 		{
522 		const char *end = openssl_strnchr(start, '/',
523 			file_split->dirlen - (start - file_split->dir));
524 		if(!end)
525 			end = start
526 				+ file_split->dirlen
527 				- (start - file_split->dir);
528 		strncpy(&result[offset], start,
529 			end - start); offset += (int)(end - start);
530 		result[offset] = '\\'; offset++;
531 		start = end + 1;
532 		}
533 #if 0 /* Not needed, since the directory converter above already appeneded
534 	 a backslash */
535 	if(file_split->dir && file_split->file)
536 		{
537 		result[offset] = '\\'; offset++;
538 		}
539 #endif
540 	strncpy(&result[offset], file_split->file,
541 		file_split->filelen); offset += file_split->filelen;
542 	result[offset] = '\0';
543 	return(result);
544 	}
545 
546 static char *win32_merger(DSO *dso, const char *filespec1, const char *filespec2)
547 	{
548 	char *merged = NULL;
549 	struct file_st *filespec1_split = NULL;
550 	struct file_st *filespec2_split = NULL;
551 
552 	if(!filespec1 && !filespec2)
553 		{
554 		DSOerr(DSO_F_WIN32_MERGER,
555 				ERR_R_PASSED_NULL_PARAMETER);
556 		return(NULL);
557 		}
558 	if (!filespec2)
559 		{
560 		merged = OPENSSL_malloc(strlen(filespec1) + 1);
561 		if(!merged)
562 			{
563 			DSOerr(DSO_F_WIN32_MERGER,
564 				ERR_R_MALLOC_FAILURE);
565 			return(NULL);
566 			}
567 		strcpy(merged, filespec1);
568 		}
569 	else if (!filespec1)
570 		{
571 		merged = OPENSSL_malloc(strlen(filespec2) + 1);
572 		if(!merged)
573 			{
574 			DSOerr(DSO_F_WIN32_MERGER,
575 				ERR_R_MALLOC_FAILURE);
576 			return(NULL);
577 			}
578 		strcpy(merged, filespec2);
579 		}
580 	else
581 		{
582 		filespec1_split = win32_splitter(dso, filespec1, 0);
583 		if (!filespec1_split)
584 			{
585 			DSOerr(DSO_F_WIN32_MERGER,
586 				ERR_R_MALLOC_FAILURE);
587 			return(NULL);
588 			}
589 		filespec2_split = win32_splitter(dso, filespec2, 1);
590 		if (!filespec2_split)
591 			{
592 			DSOerr(DSO_F_WIN32_MERGER,
593 				ERR_R_MALLOC_FAILURE);
594 			OPENSSL_free(filespec1_split);
595 			return(NULL);
596 			}
597 
598 		/* Fill in into filespec1_split */
599 		if (!filespec1_split->node && !filespec1_split->device)
600 			{
601 			filespec1_split->node = filespec2_split->node;
602 			filespec1_split->nodelen = filespec2_split->nodelen;
603 			filespec1_split->device = filespec2_split->device;
604 			filespec1_split->devicelen = filespec2_split->devicelen;
605 			}
606 		if (!filespec1_split->dir)
607 			{
608 			filespec1_split->dir = filespec2_split->dir;
609 			filespec1_split->dirlen = filespec2_split->dirlen;
610 			}
611 		else if (filespec1_split->dir[0] != '\\'
612 			&& filespec1_split->dir[0] != '/')
613 			{
614 			filespec1_split->predir = filespec2_split->dir;
615 			filespec1_split->predirlen = filespec2_split->dirlen;
616 			}
617 		if (!filespec1_split->file)
618 			{
619 			filespec1_split->file = filespec2_split->file;
620 			filespec1_split->filelen = filespec2_split->filelen;
621 			}
622 
623 		merged = win32_joiner(dso, filespec1_split);
624 		}
625 	OPENSSL_free(filespec1_split);
626 	OPENSSL_free(filespec2_split);
627 	return(merged);
628 	}
629 
630 static char *win32_name_converter(DSO *dso, const char *filename)
631 	{
632 	char *translated;
633 	int len, transform;
634 
635 	len = strlen(filename);
636 	transform = ((strstr(filename, "/") == NULL) &&
637 			(strstr(filename, "\\") == NULL) &&
638 			(strstr(filename, ":") == NULL));
639 	if(transform)
640 		/* We will convert this to "%s.dll" */
641 		translated = OPENSSL_malloc(len + 5);
642 	else
643 		/* We will simply duplicate filename */
644 		translated = OPENSSL_malloc(len + 1);
645 	if(translated == NULL)
646 		{
647 		DSOerr(DSO_F_WIN32_NAME_CONVERTER,
648 				DSO_R_NAME_TRANSLATION_FAILED);
649 		return(NULL);
650 		}
651 	if(transform)
652 		sprintf(translated, "%s.dll", filename);
653 	else
654 		sprintf(translated, "%s", filename);
655 	return(translated);
656 	}
657 
658 static const char *openssl_strnchr(const char *string, int c, size_t len)
659 	{
660 	size_t i;
661 	const char *p;
662 	for (i = 0, p = string; i < len && *p; i++, p++)
663 		{
664 		if (*p == c)
665 			return p;
666 		}
667 	return NULL;
668 	}
669 
670 #include <tlhelp32.h>
671 #ifdef _WIN32_WCE
672 # define DLLNAME "TOOLHELP.DLL"
673 #else
674 # ifdef MODULEENTRY32
675 # undef MODULEENTRY32	/* unmask the ASCII version! */
676 # endif
677 # define DLLNAME "KERNEL32.DLL"
678 #endif
679 
680 typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
681 typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
682 typedef BOOL (WINAPI *MODULE32)(HANDLE, MODULEENTRY32 *);
683 
684 static int win32_pathbyaddr(void *addr,char *path,int sz)
685 	{
686 	HMODULE dll;
687 	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
688 	MODULEENTRY32 me32;
689 	CREATETOOLHELP32SNAPSHOT create_snap;
690 	CLOSETOOLHELP32SNAPSHOT  close_snap;
691 	MODULE32 module_first, module_next;
692 	int len;
693 
694 	if (addr == NULL)
695 		{
696 		union	{ int(*f)(void*,char*,int); void *p; } t =
697 			{ win32_pathbyaddr };
698 		addr = t.p;
699 		}
700 
701 	dll = LoadLibrary(TEXT(DLLNAME));
702 	if (dll == NULL)
703 		{
704 		DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_UNSUPPORTED);
705 		return -1;
706 		}
707 
708 	create_snap = (CREATETOOLHELP32SNAPSHOT)
709 		GetProcAddress(dll,"CreateToolhelp32Snapshot");
710 	if (create_snap == NULL)
711 		{
712 		FreeLibrary(dll);
713 		DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_UNSUPPORTED);
714 		return -1;
715 		}
716 	/* We take the rest for granted... */
717 #ifdef _WIN32_WCE
718 	close_snap = (CLOSETOOLHELP32SNAPSHOT)
719 		GetProcAddress(dll,"CloseToolhelp32Snapshot");
720 #else
721 	close_snap = (CLOSETOOLHELP32SNAPSHOT)CloseHandle;
722 #endif
723 	module_first = (MODULE32)GetProcAddress(dll,"Module32First");
724 	module_next  = (MODULE32)GetProcAddress(dll,"Module32Next");
725 
726 	hModuleSnap = (*create_snap)(TH32CS_SNAPMODULE,0);
727 	if( hModuleSnap == INVALID_HANDLE_VALUE )
728 		{
729 		FreeLibrary(dll);
730 		DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_UNSUPPORTED);
731 		return -1;
732 		}
733 
734 	me32.dwSize = sizeof(me32);
735 
736 	if(!(*module_first)(hModuleSnap,&me32))
737 		{
738 		(*close_snap)(hModuleSnap);
739 		FreeLibrary(dll);
740 		DSOerr(DSO_F_WIN32_PATHBYADDR,DSO_R_FAILURE);
741 		return -1;
742 		}
743 
744 	do	{
745 		if ((BYTE *)addr >= me32.modBaseAddr &&
746 		    (BYTE *)addr <  me32.modBaseAddr+me32.modBaseSize)
747 			{
748 			(*close_snap)(hModuleSnap);
749 			FreeLibrary(dll);
750 #ifdef _WIN32_WCE
751 # if _WIN32_WCE >= 101
752 			return WideCharToMultiByte(CP_ACP,0,me32.szExePath,-1,
753 							path,sz,NULL,NULL);
754 # else
755 			len = (int)wcslen(me32.szExePath);
756 			if (sz <= 0) return len+1;
757 			if (len >= sz) len=sz-1;
758 			for(i=0;i<len;i++)
759 				path[i] = (char)me32.szExePath[i];
760 			path[len++] = 0;
761 			return len;
762 # endif
763 #else
764 			len = (int)strlen(me32.szExePath);
765 			if (sz <= 0) return len+1;
766 			if (len >= sz) len=sz-1;
767 			memcpy(path,me32.szExePath,len);
768 			path[len++] = 0;
769 			return len;
770 #endif
771 			}
772 		} while((*module_next)(hModuleSnap, &me32));
773 
774 	(*close_snap)(hModuleSnap);
775 	FreeLibrary(dll);
776 	return 0;
777 	}
778 
779 static void *win32_globallookup(const char *name)
780 	{
781 	HMODULE dll;
782 	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
783 	MODULEENTRY32 me32;
784 	CREATETOOLHELP32SNAPSHOT create_snap;
785 	CLOSETOOLHELP32SNAPSHOT  close_snap;
786 	MODULE32 module_first, module_next;
787 	FARPROC ret=NULL;
788 
789 	dll = LoadLibrary(TEXT(DLLNAME));
790 	if (dll == NULL)
791 		{
792 		DSOerr(DSO_F_WIN32_GLOBALLOOKUP,DSO_R_UNSUPPORTED);
793 		return NULL;
794 		}
795 
796 	create_snap = (CREATETOOLHELP32SNAPSHOT)
797 		GetProcAddress(dll,"CreateToolhelp32Snapshot");
798 	if (create_snap == NULL)
799 		{
800 		FreeLibrary(dll);
801 		DSOerr(DSO_F_WIN32_GLOBALLOOKUP,DSO_R_UNSUPPORTED);
802 		return NULL;
803 		}
804 	/* We take the rest for granted... */
805 #ifdef _WIN32_WCE
806 	close_snap = (CLOSETOOLHELP32SNAPSHOT)
807 		GetProcAddress(dll,"CloseToolhelp32Snapshot");
808 #else
809 	close_snap = (CLOSETOOLHELP32SNAPSHOT)CloseHandle;
810 #endif
811 	module_first = (MODULE32)GetProcAddress(dll,"Module32First");
812 	module_next  = (MODULE32)GetProcAddress(dll,"Module32Next");
813 
814 	hModuleSnap = (*create_snap)(TH32CS_SNAPMODULE,0);
815 	if( hModuleSnap == INVALID_HANDLE_VALUE )
816 		{
817 		FreeLibrary(dll);
818 		DSOerr(DSO_F_WIN32_GLOBALLOOKUP,DSO_R_UNSUPPORTED);
819 		return NULL;
820 		}
821 
822 	me32.dwSize = sizeof(me32);
823 
824 	if (!(*module_first)(hModuleSnap,&me32))
825 		{
826 		(*close_snap)(hModuleSnap);
827 		FreeLibrary(dll);
828 		return NULL;
829 		}
830 
831 	do	{
832 		if ((ret = GetProcAddress(me32.hModule,name)))
833 			{
834 			(*close_snap)(hModuleSnap);
835 			FreeLibrary(dll);
836 			return ret;
837 			}
838 		} while((*module_next)(hModuleSnap,&me32));
839 
840 	(*close_snap)(hModuleSnap);
841 	FreeLibrary(dll);
842 	return NULL;
843 	}
844 #endif /* DSO_WIN32 */
845