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

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

Added argument pszAltPath to method findDll. This argument may hold
an alternative executable search path. Intented for LoadLibraryEx flag
LOAD_WITH_ALTERED_SEARCH_PATH.

File size: 22.3 KB
Line 
1/* $Id: winimagebase.cpp,v 1.16 2000-04-16 04:27:37 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 executable path. This
169 * will include a filename or at least a backslash at
170 * the end.
171 * If this is NULL (which is it by default) the
172 * executable path is used. If this is specified,
173 * this path is used instead. This is intented used
174 * to implement the LoadLibraryEx flag
175 * LOAD_WITH_ALTERED_SEARCH_PATH.
176 *
177 * @status Completely implemented.
178 * @author Sander van Leeuwen (sandervl@xs4all.nl)
179 * knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
180 * @remark
181 */
182BOOL Win32ImageBase::findDll(const char *pszFileName,
183 char *pszFullName, int cchFullName,
184 const char *pszAltPath /*=NULL*/)
185{
186 BOOL fRet = FALSE; /* Return value. (Pessimistic attitude! Init it to FALSE...) */
187 char * psz; /* General string pointer. */
188 int cchFileName; /* Length of the normalized filename (after ".DLL" is added). */
189 struct localvars /* local variables which are to big to fit onto the stack. */
190 {
191 char szPath[1024]; /* Path buffer. Used to store pathlists. 1024 should be enough */
192 /* for LIBPATH (which at least had a limit of ca. 750 chars). */
193 char sz[CCHMAXPATH]; /* Filename/path buffer. (Normally used to build filenames */
194 /* which are passed in as search experessions to DosFindFirst.) */
195 FILEFINDBUF3 findbuf3; /* DosFindFirst buffer. */
196 } * plv;
197 int iPath; /* Current path or pathlist being examined. This is the loop */
198 /* variable looping on the FINDDLL_* defines. */
199
200 /* These defines sets the order the paths and pathlists are examined. */
201 #define FINDDLL_EXECUTABLEDIR 1
202 #define FINDDLL_CURRENTDIR 2
203 #define FINDDLL_SYSTEM32DIR 3
204 #define FINDDLL_SYSTEM16DIR 4
205 #define FINDDLL_WINDIR 5
206 #define FINDDLL_PATH 6
207 #define FINDDLL_BEGINLIBPATH 7
208 #define FINDDLL_LIBPATH 8
209 #define FINDDLL_ENDLIBPATH 9
210 #define FINDDLL_FIRST FINDDLL_EXECUTABLEDIR
211 #define FINDDLL_LAST FINDDLL_ENDLIBPATH
212
213
214 /** @sketch
215 * Copy the filename to be found to the outputbuffer, and add .DLL if not '.'
216 * is found in the name. This has two reasons:
217 * 1) When searching paths we simply append the buffer contents to the path
218 * being examined.
219 * 2) The buffer will at least return the passed in filename.
220 */
221 psz = strchr(pszFileName, '.');
222 cchFileName = strlen(pszFileName) + (psz ? 0 : 4);
223 if (cchFileName >= cchFullName)
224 {
225 dassert(cchFileName < cchFullName, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
226 "cchFileName (%d) >= cchFullName (%d)",
227 pszFileName, pszFullName, cchFullName, cchFileName, cchFullName));
228 *pszFullName = '\0';
229 return FALSE;
230 }
231 strcpy(pszFullName, pszFileName);
232 if (psz == NULL)
233 strcpy(pszFullName + cchFileName - 4, ".DLL");
234
235
236 /** @sketch
237 * Allocate memory for local variables.
238 */
239 plv = (struct localvars *)malloc(sizeof(*plv));
240 if (!plv)
241 {
242 dassert(plv, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
243 "malloc failed allocating %d bytes of memory for local variables.",
244 pszFileName, pszFullName, cchFullName, sizeof(*plv)));
245 return FALSE;
246 }
247
248
249 /** @sketch
250 * Loop thru the paths and pathlists searching them for the filename.
251 */
252 for (iPath = FINDDLL_FIRST; iPath <= FINDDLL_LAST; iPath++)
253 {
254 APIRET rc; /* Returncode from OS/2 APIs. */
255 const char * pszPath; /* Pointer to the path being examined. */
256
257 /** @sketch
258 * Get the path/dir to examin. (This is determined by the value if iPath.)
259 */
260 switch (iPath)
261 {
262 case FINDDLL_EXECUTABLEDIR:
263 if (pszAltPath)
264 pszPath = strcpy(plv->szPath, pszAltPath);
265 else
266 {
267 /* ASSUMES: getFullPath allways returns a fully qualified
268 * path, ie. with at least one backslash. and that all
269 * slashes are backslashes!
270 */
271 pszPath = strcpy(plv->szPath, WinExe->getFullPath());
272 }
273 psz = strrchr(plv->szPath, '\\');
274 dassert(psz, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
275 "WinExe->getFullPath returned a path not fully qualified: %s",
276 pszFileName, pszFullName, cchFullName, pszPath));
277 if (psz)
278 *psz = '\0';
279 else
280 continue;
281 break;
282
283 case FINDDLL_CURRENTDIR:
284 pszPath = ".";
285 break;
286
287 case FINDDLL_SYSTEM32DIR:
288 pszPath = InternalGetSystemDirectoryA();
289 break;
290
291 case FINDDLL_SYSTEM16DIR:
292 #if 1
293 continue; /* Skip this index */
294 #else
295 pszPath = InternalGetWindowsDirectoryA();
296 strcpy(plv->sz2, InternalGetWindowsDirectoryA());
297 strcat(plv->sz2, "\SYSTEM");
298 break;
299 #endif
300
301 case FINDDLL_WINDIR:
302 pszPath = InternalGetWindowsDirectoryA();
303 break;
304
305 case FINDDLL_PATH:
306 pszPath = getenv("PATH");
307 break;
308
309 case FINDDLL_BEGINLIBPATH:
310 rc = DosQueryExtLIBPATH(plv->szPath, BEGIN_LIBPATH);
311 if (rc != NO_ERROR)
312 {
313 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
314 "DosQueryExtLIBPATH failed with rc=%d, iPath=%d",
315 pszFileName, pszFullName, cchFullName, rc, iPath));
316 continue;
317 }
318 pszPath = plv->szPath;
319 break;
320
321 case FINDDLL_LIBPATH:
322 rc = DosQueryHeaderInfo(NULLHANDLE, 0, plv->szPath, sizeof(plv->szPath), QHINF_LIBPATH);
323 if (rc != NO_ERROR)
324 {
325 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
326 "DosQueryHeaderInfo failed with rc=%d, iPath=%d",
327 pszFileName, pszFullName, cchFullName, rc, iPath));
328 continue;
329 }
330 pszPath = plv->szPath;
331 break;
332
333 case FINDDLL_ENDLIBPATH:
334 rc = DosQueryExtLIBPATH(plv->szPath, END_LIBPATH);
335 if (rc != NO_ERROR)
336 {
337 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
338 "DosQueryExtLIBPATH failed with rc=%d, iPath=%d",
339 pszFileName, pszFullName, cchFullName, rc, iPath));
340 continue;
341 }
342 pszPath = plv->szPath;
343 break;
344
345 default: /* !internalerror! */
346 goto end;
347 }
348
349
350 /** @sketch
351 * pszPath is now set to the pathlist to be searched.
352 * So we'll loop thru all the paths in the list.
353 */
354 while (pszPath != NULL && *pszPath != '\0')
355 {
356 HDIR hDir; /* Find handle used when calling FindFirst. */
357 ULONG culFiles; /* Number of files to find / found. */
358 char * pszNext; /* Pointer to the next pathlist path */
359 int cch; /* Length of path (including the slash after the slash is added). */
360
361 /** @sketch
362 * Find the end of the path.
363 * Copy the path into the plv->sz buffer.
364 * Set pszNext.
365 */
366 pszNext = strchr(pszPath, ';');
367 if (pszNext != NULL)
368 {
369 cch = pszNext - pszPath;
370 pszNext++;
371 }
372 else
373 cch = strlen(pszPath);
374
375 if (cch + cchFileName + 1 >= sizeof(plv->sz)) /* assertion */
376 {
377 dassert(cch + cchFileName + 1 < sizeof(plv->sz), ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
378 "cch (%d) + cchFileName (%d) + 1 < sizeof(plv->sz) (%d) - paths too long!, iPath=%d",
379 pszFileName, pszFullName, cchFullName, cch, cchFileName, sizeof(plv->sz), iPath));
380 pszPath = pszNext;
381 continue;
382 }
383 memcpy(plv->sz, pszPath, cch); //arg! Someone made strncpy not work as supposed!
384
385
386 /** @sketch
387 * Add a '\\' and the filename (pszFullname) to the path;
388 * then we'll have a fullpath.
389 */
390 plv->sz[cch++] = '\\';
391 strcpy(&plv->sz[cch], pszFullName);
392
393
394 /** @sketch
395 * Use DosFindFirst to check if the file exists.
396 * IF the file exists THEN
397 * Query Fullpath using OS/2 API.
398 * IF unsuccessful THEN return relative name.
399 * Check that the fullname buffer is large enough.
400 * Copy the filename found to the fullname buffer.
401 * ENDIF
402 * IF successful THEN uppercase the fullname buffer.
403 * goto end
404 * ENDIF
405 */
406 hDir = HDIR_CREATE;
407 culFiles = 1;
408 rc = DosFindFirst(plv->sz, &hDir, FILE_NORMAL,
409 &plv->findbuf3, sizeof(plv->findbuf3),
410 &culFiles, FIL_STANDARD);
411 DosFindClose(hDir);
412 if (culFiles >= 1 && rc == NO_ERROR)
413 {
414 /* Return full path - we'll currently return a relative path. */
415 rc = DosQueryPathInfo(plv->sz, FIL_QUERYFULLNAME, pszFullName, cchFullName);
416 fRet = rc == NO_ERROR;
417 if (!fRet)
418 {
419 /* Return a relative path - probably better that failing... */
420 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
421 "rc = %d",
422 pszFileName, pszFullName, cchFullName, rc));
423
424 if (cch + cchFileName + 1 <= cchFullName)
425 {
426 strcpy(pszFullName, plv->sz);
427 strcpy(pszFullName + cch, plv->findbuf3.achName);
428 fRet = TRUE;
429 }
430 else
431 {
432 dassert(cch + cchFileName + 1 > cchFullName, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
433 "cch (%d) + cchFileName (%d) + 1 < cchFullName (%d); %s",
434 pszFileName, pszFullName, cchFullName, cch, cchFileName, cchFullName, plv->sz));
435 }
436 }
437 if (fRet) strupr(pszFullName);
438 goto end;
439 }
440
441 pszPath = pszNext;
442 }
443 } /* for iPath */
444
445
446end:
447 /*
448 * Cleanup: free local variables.
449 */
450 free(plv);
451 return fRet;
452}
453
454
455//******************************************************************************
456//******************************************************************************
457BOOL Win32ImageBase::isPEImage(char *szFileName)
458{
459 char filename[CCHMAXPATH];
460 char *syspath;
461 HFILE dllfile;
462 IMAGE_FILE_HEADER fh;
463 HFILE win32handle;
464 ULONG ulAction = 0; /* Action taken by DosOpen */
465 ULONG ulLocal = 0; /* File pointer position after DosSetFilePtr */
466 APIRET rc = NO_ERROR; /* Return code */
467 LPVOID win32file = NULL;
468 ULONG ulRead;
469 int nSections, i;
470
471 if (!findDll(szFileName, filename, sizeof(filename)))
472 {
473 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) findDll failed to find the file.\n",
474 szFileName, rc));
475 return FALSE;
476 }
477
478 rc = DosOpen(filename, /* File path name */
479 &win32handle, /* File handle */
480 &ulAction, /* Action taken */
481 0L, /* File primary allocation */
482 0L, /* File attribute */
483 OPEN_ACTION_FAIL_IF_NEW |
484 OPEN_ACTION_OPEN_IF_EXISTS, /* Open function type */
485 OPEN_FLAGS_NOINHERIT |
486 OPEN_SHARE_DENYNONE |
487 OPEN_ACCESS_READONLY, /* Open mode of the file */
488 0L); /* No extended attribute */
489
490 if (rc != NO_ERROR)
491 {
492 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) failed with %u\n",
493 szFileName, rc));
494 return(FALSE);
495 }
496
497 /* Move the file pointer back to the beginning of the file */
498 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
499
500 IMAGE_DOS_HEADER *pdoshdr = (IMAGE_DOS_HEADER *)malloc(sizeof(IMAGE_DOS_HEADER));
501 if(pdoshdr == NULL) {
502 DosClose(win32handle); /* Close the file */
503 return(FALSE);
504 }
505 rc = DosRead(win32handle, pdoshdr, sizeof(IMAGE_DOS_HEADER), &ulRead);
506 if(rc != NO_ERROR) {
507 DosClose(win32handle); /* Close the file */
508 return(FALSE);
509 }
510 ULONG hdrsize = pdoshdr->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof(IMAGE_FILE_HEADER);
511 free(pdoshdr);
512
513 /* Move the file pointer back to the beginning of the file */
514 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
515
516 win32file = malloc(hdrsize);
517 if(win32file == NULL) {
518 DosClose(win32handle); /* Close the file */
519 return(FALSE);
520 }
521 rc = DosRead(win32handle, win32file, hdrsize, &ulRead);
522 if(rc != NO_ERROR) {
523 goto failure;
524 }
525
526 if(GetPEFileHeader (win32file, &fh) == FALSE) {
527 goto failure;
528 }
529
530 if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
531 goto failure;
532 }
533 if(fh.Machine != IMAGE_FILE_MACHINE_I386) {
534 goto failure;
535 }
536 //IMAGE_FILE_SYSTEM == only drivers (device/file system/video etc)?
537 if(fh.Characteristics & IMAGE_FILE_SYSTEM) {
538 goto failure;
539 }
540 DosClose(win32handle);
541 return(TRUE);
542
543failure:
544 free(win32file);
545 DosClose(win32handle);
546 return(FALSE);
547}
548//******************************************************************************
549//******************************************************************************
550/**
551 * Static helper which finds the Win32ImageBase object corresponding to hModule.
552 * @returns Pointer to Win32ImageBase object corresponding to hModule.
553 * @param hModule Odin32 modulehandler. 0 and -1 is aliases for the executable module
554 * @status completely implemented and tested.
555 * @author knut st. osmundsen
556 */
557Win32ImageBase * Win32ImageBase::findModule(HMODULE hModule)
558{
559 Win32ImageBase *pRet;
560
561 if (hModule == -1 || hModule == 0 || /* note: WinNt 4, SP4 don't accept -1 as the EXE handle.*/
562 (WinExe != NULL && hModule == WinExe->getInstanceHandle())
563 )
564 pRet = WinExe;
565 else
566 pRet = Win32DllBase::findModule(hModule);
567
568 if (pRet == NULL)
569 {
570 if (WinExe == NULL)
571 dprintf(("Win32ImageBase::findModule: Module not found. WinExe is NULL, hModule=%#x\n", hModule));
572 else
573 dprintf(("Win32ImageBase::findModule: Module not found, hModule=%#x\n", hModule));
574 }
575
576 return pRet;
577}
578
579
Note: See TracBrowser for help on using the repository browser.