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

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

Rewrote findDll.

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