source: trunk/src/kernel32/winimagebase.cpp@ 3397

Last change on this file since 3397 was 3397, checked in by bird, 25 years ago

Added parameter pszAltPath to findDll.

File size: 22.1 KB
Line 
1/* $Id: winimagebase.cpp,v 1.15 2000-04-16 04:19:57 bird Exp $ */
2
3/*
4 * Win32 PE Image base class
5 *
6 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998-2000 Knut St. Osmundsen (knut.stange.osmundsen@pmsc.no)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13#define INCL_DOSFILEMGR /* File Manager values */
14#define INCL_DOSMODULEMGR /* DOS Module manager */
15#define INCL_DOSERRORS /* DOS Error values */
16#define INCL_DOSPROCESS /* DOS Process values */
17#define INCL_DOSMISC /* DOS Miscellanous values */
18#define INCL_WIN /* All Win API */
19#define INCL_BASE /* All Dos API */
20#include <os2wrap.h> /* Odin32 OS/2 API wrappers. */
21
22#include <stdio.h> /* C Library Standard I/O */
23#include <string.h> /* C Library string operations */
24#include <stdlib.h> /* C Library Standard stuff */
25
26#include <misc.h> /* Odin32 Miscellaneous definitions, debug stuff*/
27#include <win32type.h> /* Odin32 Common types and definition. */
28#include "winimagebase.h" /* Odin32 Executable Image Base Class */
29#include "windllbase.h" /* Odin32 Dll Base Class */
30#include "winexebase.h" /* Odin32 Exe Base Class */
31#include <pefile.h> /* Odin32 PE definitions */
32#include <unicode.h> /* Odin32 Unicode conversion */
33#include <winres.h> /* Odin32 Resource Class */
34#include "oslibmisc.h"
35#include "oslibdos.h"
36#include "initterm.h"
37#include <win\virtual.h>
38#include "directory.h" /* InternalGet<Windows/System>Directory. */
39#include <os2newapi.h> /* DosQueryHeaderInfo. */
40
41#define DBG_LOCALLOG DBG_winimagebase
42#include "dbglocal.h"
43
44//******************************************************************************
45//******************************************************************************
46Win32ImageBase::Win32ImageBase(HINSTANCE hInstance) :
47 errorState(NO_ERROR), entryPoint(0), fullpath(NULL),
48 tlsAddress(0), tlsIndexAddr(0), tlsInitSize(0), tlsTotalSize(0),
49 tlsCallBackAddr(0), tlsIndex(-1), winres(NULL), pResDir(NULL),
50 ulRVAResourceSection(0)
51{
52 magic = MAGIC_WINIMAGE;
53
54 if(hInstance != -1) {
55 this->hinstance = hInstance;
56
57 char *name = OSLibGetDllName(hinstance);
58 strcpy(szFileName, name);
59 strupr(szFileName);
60
61 //rename dll (os/2 -> win32) if necessary (i.e. OLE32OS2 -> OLE32)
62 Win32DllBase::renameDll(szFileName, FALSE);
63
64 name = strrchr(szFileName, '\\')+1;
65 strcpy(szModule, name);
66
67 char *dot = strrchr(szModule, '.');
68 if(dot)
69 *dot = 0;
70 }
71 else {
72 szModule[0] = 0;
73 this->hinstance = -1;
74 }
75}
76//******************************************************************************
77//******************************************************************************
78Win32ImageBase::~Win32ImageBase()
79{
80 Win32Resource *res;
81
82 while(winres)
83 {
84 res = winres->next;
85 delete(winres);
86 winres = res;
87 }
88 if(fullpath)
89 free(fullpath);
90}
91//******************************************************************************
92//******************************************************************************
93void Win32ImageBase::setFullPath(char *name)
94{
95 dassert(name, ("setFullPath, name == NULL"));
96 fullpath = (char *)malloc(strlen(name)+1);
97 dassert(fullpath, ("setFullPath, fullpath == NULL"));
98 strcpy(fullpath, name);
99}
100//******************************************************************************
101//Add image to dependency list of this image
102//******************************************************************************
103void Win32ImageBase::addDependency(Win32DllBase *image)
104{
105 loadedDlls.Push((ULONG)image);
106}
107//******************************************************************************
108//******************************************************************************
109BOOL Win32ImageBase::dependsOn(Win32DllBase *image)
110{
111 QueueItem *item;
112 BOOL ret = FALSE;
113
114 dlllistmutex.enter();
115 item = loadedDlls.Head();
116 while(item) {
117 if(loadedDlls.getItem(item) == (ULONG)image) {
118 ret = TRUE;
119 break;
120 }
121 item = loadedDlls.getNext(item);
122 }
123 dlllistmutex.leave();
124 return ret;
125}
126//******************************************************************************
127//Returns required OS version for this image
128//******************************************************************************
129ULONG Win32ImageBase::getVersion()
130{
131 dprintf(("Win32ImageBase::getVersion: NOT IMPLEMENTED!"));
132 return 0x40000; //NT 4
133}
134
135
136/**
137 * Finds a executable module (or really any file) using the DLL search order.
138 * The search order used is:
139 * 1. The directory from which the application loaded.
140 * 2. The current directory.
141 * 3. System directory. (GetSystemDirectory returns its path)
142 * (Windows NT/2k directory name: SYSTEM32)
143 * 4. (Windows NT/2k: The 16-bit Windows system directory. There
144 * is no function that obtains the path of this directory.
145 * (Directory name: SYSTEM)
146 * THIS IS NOT SEARCHED BY ODIN.)
147 * 5. The Windows directory. (GetWindowsDirectory returns its path)
148 * 6. The Directories listed in the PATH environment variable.
149 * 7. The Directories listed in the BEGINLIBPATH.
150 * 8. The Directories listed in the LIBPATH.
151 * 9. The Directories listed in the ENDLIBPATH.
152 *
153 * @returns Success indicator. TRUE: found FALSE: not found.
154 * Note! pszFullname will normally contain the contents of
155 * pszFilename upon return, there is one case FALSE case when
156 * pszFullname will be empty upon return. That's when the buffer
157 * isn't large enough to hold the content of pszFilename including
158 * an extention.
159 * So, please check for the return value!
160 * @param pszFilename File to find. This name should not have a path!
161 * If it don't contains an '.', ".DLL" is appended to
162 * the name.
163 * @param pszFullname Pointer to output buffer, this will hold the
164 * a fully qualified, uppercased, filename upon
165 * successful return.
166 * @param cchFullname Size of the buffer pointer to by pszFullname.
167 * (A length of at least CCHMAXPATH is recommended.)
168 * @parm pszAltPath Pointer to alternate first path. If this is NULL
169 * (which is it by default) the executable path
170 * is used. If this is specified, this path is used
171 * instead. This is intented used to implement the
172 * LoadLibraryEx flag LOAD_WITH_ALTERED_SEARCH_PATH.
173 *
174 * @status Completely implemented.
175 * @author Sander van Leeuwen (sandervl@xs4all.nl)
176 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
177 * @remark
178 */
179BOOL Win32ImageBase::findDll(const char *pszFileName,
180 char *pszFullName, int cchFullName,
181 const char *pszAltPath /*=NULL*/)
182{
183 BOOL fRet = FALSE; /* Return value. (Pessimistic attitude! Init it to FALSE...) */
184 char * psz; /* General string pointer. */
185 int cchFileName; /* Length of the normalized filename (after ".DLL" is added). */
186 struct localvars /* local variables which are to big to fit onto the stack. */
187 {
188 char szPath[1024]; /* Path buffer. Used to store pathlists. 1024 should be enough */
189 /* for LIBPATH (which at least had a limit of ca. 750 chars). */
190 char sz[CCHMAXPATH]; /* Filename/path buffer. (Normally used to build filenames */
191 /* which are passed in as search experessions to DosFindFirst.) */
192 FILEFINDBUF3 findbuf3; /* DosFindFirst buffer. */
193 } * plv;
194 int iPath; /* Current path or pathlist being examined. This is the loop */
195 /* variable looping on the FINDDLL_* defines. */
196
197 /* These defines sets the order the paths and pathlists are examined. */
198 #define FINDDLL_EXECUTABLEDIR 1
199 #define FINDDLL_CURRENTDIR 2
200 #define FINDDLL_SYSTEM32DIR 3
201 #define FINDDLL_SYSTEM16DIR 4
202 #define FINDDLL_WINDIR 5
203 #define FINDDLL_PATH 6
204 #define FINDDLL_BEGINLIBPATH 7
205 #define FINDDLL_LIBPATH 8
206 #define FINDDLL_ENDLIBPATH 9
207 #define FINDDLL_FIRST FINDDLL_EXECUTABLEDIR
208 #define FINDDLL_LAST FINDDLL_ENDLIBPATH
209
210
211 /** @sketch
212 * Copy the filename to be found to the outputbuffer, and add .DLL if not '.'
213 * is found in the name. This has two reasons:
214 * 1) When searching paths we simply append the buffer contents to the path
215 * being examined.
216 * 2) The buffer will at least return the passed in filename.
217 */
218 psz = strchr(pszFileName, '.');
219 cchFileName = strlen(pszFileName) + (psz ? 0 : 4);
220 if (cchFileName >= cchFullName)
221 {
222 dassert(cchFileName < cchFullName, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
223 "cchFileName (%d) >= cchFullName (%d)",
224 pszFileName, pszFullName, cchFullName, cchFileName, cchFullName));
225 *pszFullName = '\0';
226 return FALSE;
227 }
228 strcpy(pszFullName, pszFileName);
229 if (psz == NULL)
230 strcpy(pszFullName + cchFileName - 4, ".DLL");
231
232
233 /** @sketch
234 * Allocate memory for local variables.
235 */
236 plv = (struct localvars *)malloc(sizeof(*plv));
237 if (!plv)
238 {
239 dassert(plv, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
240 "malloc failed allocating %d bytes of memory for local variables.",
241 pszFileName, pszFullName, cchFullName, sizeof(*plv)));
242 return FALSE;
243 }
244
245
246 /** @sketch
247 * Loop thru the paths and pathlists searching them for the filename.
248 */
249 for (iPath = FINDDLL_FIRST; iPath <= FINDDLL_LAST; iPath++)
250 {
251 APIRET rc; /* Returncode from OS/2 APIs. */
252 const char * pszPath; /* Pointer to the path being examined. */
253
254 /** @sketch
255 * Get the path/dir to examin. (This is determined by the value if iPath.)
256 */
257 switch (iPath)
258 {
259 case FINDDLL_EXECUTABLEDIR:
260 if (!pszAltPath)
261 {
262 /* ASSUMES: getFullPath allways returns a fully qualified
263 * path, ie. with at least one backslash. and that all
264 * slashes are backslashes!
265 */
266 pszPath = strcpy(plv->szPath, WinExe->getFullPath());
267 psz = strrchr(plv->szPath, '\\');
268 dassert(psz, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
269 "WinExe->getFullPath returned a path not fully qualified: %s",
270 pszFileName, pszFullName, cchFullName, pszPath));
271 if (psz)
272 *psz = '\0';
273 else
274 continue;
275 }
276 else
277 pszPath = pszAltPath;
278 break;
279
280 case FINDDLL_CURRENTDIR:
281 pszPath = ".";
282 break;
283
284 case FINDDLL_SYSTEM32DIR:
285 pszPath = InternalGetSystemDirectoryA();
286 break;
287
288 case FINDDLL_SYSTEM16DIR:
289 #if 1
290 continue; /* Skip this index */
291 #else
292 pszPath = InternalGetWindowsDirectoryA();
293 strcpy(plv->sz2, InternalGetWindowsDirectoryA());
294 strcat(plv->sz2, "\SYSTEM");
295 break;
296 #endif
297
298 case FINDDLL_WINDIR:
299 pszPath = InternalGetWindowsDirectoryA();
300 break;
301
302 case FINDDLL_PATH:
303 pszPath = getenv("PATH");
304 break;
305
306 case FINDDLL_BEGINLIBPATH:
307 rc = DosQueryExtLIBPATH(plv->szPath, BEGIN_LIBPATH);
308 if (rc != NO_ERROR)
309 {
310 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
311 "DosQueryExtLIBPATH failed with rc=%d, iPath=%d",
312 pszFileName, pszFullName, cchFullName, rc, iPath));
313 continue;
314 }
315 pszPath = plv->szPath;
316 break;
317
318 case FINDDLL_LIBPATH:
319 rc = DosQueryHeaderInfo(NULLHANDLE, 0, plv->szPath, sizeof(plv->szPath), QHINF_LIBPATH);
320 if (rc != NO_ERROR)
321 {
322 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
323 "DosQueryHeaderInfo failed with rc=%d, iPath=%d",
324 pszFileName, pszFullName, cchFullName, rc, iPath));
325 continue;
326 }
327 pszPath = plv->szPath;
328 break;
329
330 case FINDDLL_ENDLIBPATH:
331 rc = DosQueryExtLIBPATH(plv->szPath, END_LIBPATH);
332 if (rc != NO_ERROR)
333 {
334 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
335 "DosQueryExtLIBPATH failed with rc=%d, iPath=%d",
336 pszFileName, pszFullName, cchFullName, rc, iPath));
337 continue;
338 }
339 pszPath = plv->szPath;
340 break;
341
342 default: /* !internalerror! */
343 goto end;
344 }
345
346
347 /** @sketch
348 * pszPath is now set to the pathlist to be searched.
349 * So we'll loop thru all the paths in the list.
350 */
351 while (pszPath != NULL && *pszPath != '\0')
352 {
353 HDIR hDir; /* Find handle used when calling FindFirst. */
354 ULONG culFiles; /* Number of files to find / found. */
355 char * pszNext; /* Pointer to the next pathlist path */
356 int cch; /* Length of path (including the slash after the slash is added). */
357
358 /** @sketch
359 * Find the end of the path.
360 * Copy the path into the plv->sz buffer.
361 * Set pszNext.
362 */
363 pszNext = strchr(pszPath, ';');
364 if (pszNext != NULL)
365 {
366 cch = pszNext - pszPath;
367 pszNext++;
368 }
369 else
370 cch = strlen(pszPath);
371
372 if (cch + cchFileName + 1 >= sizeof(plv->sz)) /* assertion */
373 {
374 dassert(cch + cchFileName + 1 < sizeof(plv->sz), ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
375 "cch (%d) + cchFileName (%d) + 1 < sizeof(plv->sz) (%d) - paths too long!, iPath=%d",
376 pszFileName, pszFullName, cchFullName, cch, cchFileName, sizeof(plv->sz), iPath));
377 pszPath = pszNext;
378 continue;
379 }
380 memcpy(plv->sz, pszPath, cch); //arg! Someone made strncpy not work as supposed!
381
382
383 /** @sketch
384 * Add a '\\' and the filename (pszFullname) to the path;
385 * then we'll have a fullpath.
386 */
387 plv->sz[cch++] = '\\';
388 strcpy(&plv->sz[cch], pszFullName);
389
390
391 /** @sketch
392 * Use DosFindFirst to check if the file exists.
393 * IF the file exists THEN
394 * Query Fullpath using OS/2 API.
395 * IF unsuccessful THEN return relative name.
396 * Check that the fullname buffer is large enough.
397 * Copy the filename found to the fullname buffer.
398 * ENDIF
399 * IF successful THEN uppercase the fullname buffer.
400 * goto end
401 * ENDIF
402 */
403 hDir = HDIR_CREATE;
404 culFiles = 1;
405 rc = DosFindFirst(plv->sz, &hDir, FILE_NORMAL,
406 &plv->findbuf3, sizeof(plv->findbuf3),
407 &culFiles, FIL_STANDARD);
408 DosFindClose(hDir);
409 if (culFiles >= 1 && rc == NO_ERROR)
410 {
411 /* Return full path - we'll currently return a relative path. */
412 rc = DosQueryPathInfo(plv->sz, FIL_QUERYFULLNAME, pszFullName, cchFullName);
413 fRet = rc == NO_ERROR;
414 if (!fRet)
415 {
416 /* Return a relative path - probably better that failing... */
417 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
418 "rc = %d",
419 pszFileName, pszFullName, cchFullName, rc));
420
421 if (cch + cchFileName + 1 <= cchFullName)
422 {
423 strcpy(pszFullName, plv->sz);
424 strcpy(pszFullName + cch, plv->findbuf3.achName);
425 fRet = TRUE;
426 }
427 else
428 {
429 dassert(cch + cchFileName + 1 > cchFullName, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
430 "cch (%d) + cchFileName (%d) + 1 < cchFullName (%d); %s",
431 pszFileName, pszFullName, cchFullName, cch, cchFileName, cchFullName, plv->sz));
432 }
433 }
434 if (fRet) strupr(pszFullName);
435 goto end;
436 }
437
438 pszPath = pszNext;
439 }
440 } /* for iPath */
441
442
443end:
444 /*
445 * Cleanup: free local variables.
446 */
447 free(plv);
448 return fRet;
449}
450
451
452//******************************************************************************
453//******************************************************************************
454BOOL Win32ImageBase::isPEImage(char *szFileName)
455{
456 char filename[CCHMAXPATH];
457 char *syspath;
458 HFILE dllfile;
459 IMAGE_FILE_HEADER fh;
460 HFILE win32handle;
461 ULONG ulAction = 0; /* Action taken by DosOpen */
462 ULONG ulLocal = 0; /* File pointer position after DosSetFilePtr */
463 APIRET rc = NO_ERROR; /* Return code */
464 LPVOID win32file = NULL;
465 ULONG ulRead;
466 int nSections, i;
467
468 if (!findDll(szFileName, filename, sizeof(filename)))
469 {
470 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) findDll failed to find the file.\n",
471 szFileName, rc));
472 return FALSE;
473 }
474
475 rc = DosOpen(filename, /* File path name */
476 &win32handle, /* File handle */
477 &ulAction, /* Action taken */
478 0L, /* File primary allocation */
479 0L, /* File attribute */
480 OPEN_ACTION_FAIL_IF_NEW |
481 OPEN_ACTION_OPEN_IF_EXISTS, /* Open function type */
482 OPEN_FLAGS_NOINHERIT |
483 OPEN_SHARE_DENYNONE |
484 OPEN_ACCESS_READONLY, /* Open mode of the file */
485 0L); /* No extended attribute */
486
487 if (rc != NO_ERROR)
488 {
489 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) failed with %u\n",
490 szFileName, rc));
491 return(FALSE);
492 }
493
494 /* Move the file pointer back to the beginning of the file */
495 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
496
497 IMAGE_DOS_HEADER *pdoshdr = (IMAGE_DOS_HEADER *)malloc(sizeof(IMAGE_DOS_HEADER));
498 if(pdoshdr == NULL) {
499 DosClose(win32handle); /* Close the file */
500 return(FALSE);
501 }
502 rc = DosRead(win32handle, pdoshdr, sizeof(IMAGE_DOS_HEADER), &ulRead);
503 if(rc != NO_ERROR) {
504 DosClose(win32handle); /* Close the file */
505 return(FALSE);
506 }
507 ULONG hdrsize = pdoshdr->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof(IMAGE_FILE_HEADER);
508 free(pdoshdr);
509
510 /* Move the file pointer back to the beginning of the file */
511 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
512
513 win32file = malloc(hdrsize);
514 if(win32file == NULL) {
515 DosClose(win32handle); /* Close the file */
516 return(FALSE);
517 }
518 rc = DosRead(win32handle, win32file, hdrsize, &ulRead);
519 if(rc != NO_ERROR) {
520 goto failure;
521 }
522
523 if(GetPEFileHeader (win32file, &fh) == FALSE) {
524 goto failure;
525 }
526
527 if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
528 goto failure;
529 }
530 if(fh.Machine != IMAGE_FILE_MACHINE_I386) {
531 goto failure;
532 }
533 //IMAGE_FILE_SYSTEM == only drivers (device/file system/video etc)?
534 if(fh.Characteristics & IMAGE_FILE_SYSTEM) {
535 goto failure;
536 }
537 DosClose(win32handle);
538 return(TRUE);
539
540failure:
541 free(win32file);
542 DosClose(win32handle);
543 return(FALSE);
544}
545//******************************************************************************
546//******************************************************************************
547/**
548 * Static helper which finds the Win32ImageBase object corresponding to hModule.
549 * @returns Pointer to Win32ImageBase object corresponding to hModule.
550 * @param hModule Odin32 modulehandler. 0 and -1 is aliases for the executable module
551 * @status completely implemented and tested.
552 * @author knut st. osmundsen
553 */
554Win32ImageBase * Win32ImageBase::findModule(HMODULE hModule)
555{
556 Win32ImageBase *pRet;
557
558 if (hModule == -1 || hModule == 0 || /* note: WinNt 4, SP4 don't accept -1 as the EXE handle.*/
559 (WinExe != NULL && hModule == WinExe->getInstanceHandle())
560 )
561 pRet = WinExe;
562 else
563 pRet = Win32DllBase::findModule(hModule);
564
565 if (pRet == NULL)
566 {
567 if (WinExe == NULL)
568 dprintf(("Win32ImageBase::findModule: Module not found. WinExe is NULL, hModule=%#x\n", hModule));
569 else
570 dprintf(("Win32ImageBase::findModule: Module not found, hModule=%#x\n", hModule));
571 }
572
573 return pRet;
574}
575
576
Note: See TracBrowser for help on using the repository browser.