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

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

Corrected bug - WinExe might be NULL during intiation. Currently we'll
ignore the executable path. (temprorary fix!)

File size: 22.7 KB
Line 
1/* $Id: winimagebase.cpp,v 1.17 2000-04-16 06:47:22 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 if (!WinExe) continue;
272 pszPath = strcpy(plv->szPath, WinExe->getFullPath());
273 }
274 psz = strrchr(plv->szPath, '\\');
275 dassert(psz, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
276 "WinExe->getFullPath returned a path not fully qualified: %s",
277 pszFileName, pszFullName, cchFullName, pszPath));
278 if (psz)
279 *psz = '\0';
280 else
281 continue;
282 break;
283
284 case FINDDLL_CURRENTDIR:
285 pszPath = ".";
286 break;
287
288 case FINDDLL_SYSTEM32DIR:
289 pszPath = InternalGetSystemDirectoryA();
290 break;
291
292 case FINDDLL_SYSTEM16DIR:
293 #if 1
294 continue; /* Skip this index */
295 #else
296 pszPath = InternalGetWindowsDirectoryA();
297 strcpy(plv->sz2, InternalGetWindowsDirectoryA());
298 strcat(plv->sz2, "\SYSTEM");
299 break;
300 #endif
301
302 case FINDDLL_WINDIR:
303 pszPath = InternalGetWindowsDirectoryA();
304 break;
305
306 case FINDDLL_PATH:
307 pszPath = getenv("PATH");
308 break;
309
310 case FINDDLL_BEGINLIBPATH:
311 rc = DosQueryExtLIBPATH(plv->szPath, BEGIN_LIBPATH);
312 if (rc != NO_ERROR)
313 {
314 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
315 "DosQueryExtLIBPATH failed with rc=%d, iPath=%d",
316 pszFileName, pszFullName, cchFullName, rc, iPath));
317 continue;
318 }
319 pszPath = plv->szPath;
320 break;
321
322 case FINDDLL_LIBPATH:
323 rc = DosQueryHeaderInfo(NULLHANDLE, 0, plv->szPath, sizeof(plv->szPath), QHINF_LIBPATH);
324 if (rc != NO_ERROR)
325 {
326 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
327 "DosQueryHeaderInfo failed with rc=%d, iPath=%d",
328 pszFileName, pszFullName, cchFullName, rc, iPath));
329 continue;
330 }
331 pszPath = plv->szPath;
332 break;
333
334 case FINDDLL_ENDLIBPATH:
335 rc = DosQueryExtLIBPATH(plv->szPath, END_LIBPATH);
336 if (rc != NO_ERROR)
337 {
338 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
339 "DosQueryExtLIBPATH failed with rc=%d, iPath=%d",
340 pszFileName, pszFullName, cchFullName, rc, iPath));
341 continue;
342 }
343 pszPath = plv->szPath;
344 break;
345
346 default: /* !internalerror! */
347 goto end;
348 }
349
350
351 /** @sketch
352 * pszPath is now set to the pathlist to be searched.
353 * So we'll loop thru all the paths in the list.
354 */
355 while (pszPath != NULL && *pszPath != '\0')
356 {
357 HDIR hDir; /* Find handle used when calling FindFirst. */
358 ULONG culFiles; /* Number of files to find / found. */
359 char * pszNext; /* Pointer to the next pathlist path */
360 int cch; /* Length of path (including the slash after the slash is added). */
361
362 /** @sketch
363 * Find the end of the path.
364 * Copy the path into the plv->sz buffer.
365 * Set pszNext.
366 */
367 pszNext = strchr(pszPath, ';');
368 if (pszNext != NULL)
369 {
370 cch = pszNext - pszPath;
371 pszNext++;
372 }
373 else
374 cch = strlen(pszPath);
375
376 if (cch + cchFileName + 1 >= sizeof(plv->sz)) /* assertion */
377 {
378 dassert(cch + cchFileName + 1 < sizeof(plv->sz), ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
379 "cch (%d) + cchFileName (%d) + 1 < sizeof(plv->sz) (%d) - paths too long!, iPath=%d",
380 pszFileName, pszFullName, cchFullName, cch, cchFileName, sizeof(plv->sz), iPath));
381 pszPath = pszNext;
382 continue;
383 }
384 memcpy(plv->sz, pszPath, cch); //arg! Someone made strncpy not work as supposed!
385
386
387 /** @sketch
388 * Add a '\\' and the filename (pszFullname) to the path;
389 * then we'll have a fullpath.
390 */
391 plv->sz[cch++] = '\\';
392 strcpy(&plv->sz[cch], pszFullName);
393
394
395 /** @sketch
396 * Use DosFindFirst to check if the file exists.
397 * IF the file exists THEN
398 * Query Fullpath using OS/2 API.
399 * IF unsuccessful THEN return relative name.
400 * Check that the fullname buffer is large enough.
401 * Copy the filename found to the fullname buffer.
402 * ENDIF
403 * IF successful THEN uppercase the fullname buffer.
404 * goto end
405 * ENDIF
406 */
407 hDir = HDIR_CREATE;
408 culFiles = 1;
409 rc = DosFindFirst(plv->sz, &hDir, FILE_NORMAL,
410 &plv->findbuf3, sizeof(plv->findbuf3),
411 &culFiles, FIL_STANDARD);
412 DosFindClose(hDir);
413 if (culFiles >= 1 && rc == NO_ERROR)
414 {
415 /* Return full path - we'll currently return a relative path. */
416 rc = DosQueryPathInfo(plv->sz, FIL_QUERYFULLNAME, pszFullName, cchFullName);
417 fRet = rc == NO_ERROR;
418 if (!fRet)
419 {
420 /* Return a relative path - probably better that failing... */
421 dassert(rc == NO_ERROR, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
422 "rc = %d",
423 pszFileName, pszFullName, cchFullName, rc));
424
425 if (cch + cchFileName + 1 <= cchFullName)
426 {
427 strcpy(pszFullName, plv->sz);
428 strcpy(pszFullName + cch, plv->findbuf3.achName);
429 fRet = TRUE;
430 }
431 else
432 {
433 dassert(cch + cchFileName + 1 > cchFullName, ("KERNEL32:Win32ImageBase::findDll(%s, 0x%08x, %d): "
434 "cch (%d) + cchFileName (%d) + 1 < cchFullName (%d); %s",
435 pszFileName, pszFullName, cchFullName, cch, cchFileName, cchFullName, plv->sz));
436 }
437 }
438 if (fRet) strupr(pszFullName);
439 goto end;
440 }
441
442 pszPath = pszNext;
443 }
444 } /* for iPath */
445
446
447end:
448 /*
449 * Cleanup: free local variables.
450 */
451 free(plv);
452 return fRet;
453}
454
455
456//******************************************************************************
457//******************************************************************************
458/**
459 * Checks if a file is a PE executable image valid to be executed on this machine.
460 * @returns FALSE if not PE image.
461 * > 0 if valid PE image.
462 * 1 DLL
463 * 2 EXE
464 * @param szFilename Pointer to filename
465 * @author knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
466 * @remark Should not call findDll!
467 */
468BOOL Win32ImageBase::isPEImage(char *szFileName)
469{
470 char filename[CCHMAXPATH];
471 char *syspath;
472 HFILE dllfile;
473 IMAGE_FILE_HEADER fh;
474 HFILE win32handle;
475 ULONG ulAction = 0; /* Action taken by DosOpen */
476 ULONG ulLocal = 0; /* File pointer position after DosSetFilePtr */
477 APIRET rc = NO_ERROR; /* Return code */
478 LPVOID win32file = NULL;
479 ULONG ulRead;
480 int nSections, i;
481
482 if (!findDll(szFileName, filename, sizeof(filename)))
483 {
484 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) findDll failed to find the file.\n",
485 szFileName, rc));
486 return FALSE;
487 }
488
489 rc = DosOpen(filename, /* File path name */
490 &win32handle, /* File handle */
491 &ulAction, /* Action taken */
492 0L, /* File primary allocation */
493 0L, /* File attribute */
494 OPEN_ACTION_FAIL_IF_NEW |
495 OPEN_ACTION_OPEN_IF_EXISTS, /* Open function type */
496 OPEN_FLAGS_NOINHERIT |
497 OPEN_SHARE_DENYNONE |
498 OPEN_ACCESS_READONLY, /* Open mode of the file */
499 0L); /* No extended attribute */
500
501 if (rc != NO_ERROR)
502 {
503 dprintf(("KERNEL32:Win32ImageBase::isPEImage(%s) failed with %u\n",
504 szFileName, rc));
505 return(FALSE);
506 }
507
508 /* Move the file pointer back to the beginning of the file */
509 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
510
511 IMAGE_DOS_HEADER *pdoshdr = (IMAGE_DOS_HEADER *)malloc(sizeof(IMAGE_DOS_HEADER));
512 if(pdoshdr == NULL) {
513 DosClose(win32handle); /* Close the file */
514 return(FALSE);
515 }
516 rc = DosRead(win32handle, pdoshdr, sizeof(IMAGE_DOS_HEADER), &ulRead);
517 if(rc != NO_ERROR) {
518 DosClose(win32handle); /* Close the file */
519 return(FALSE);
520 }
521 ULONG hdrsize = pdoshdr->e_lfanew + SIZE_OF_NT_SIGNATURE + sizeof(IMAGE_FILE_HEADER);
522 free(pdoshdr);
523
524 /* Move the file pointer back to the beginning of the file */
525 DosSetFilePtr(win32handle, 0L, FILE_BEGIN, &ulLocal);
526
527 win32file = malloc(hdrsize);
528 if(win32file == NULL) {
529 DosClose(win32handle); /* Close the file */
530 return(FALSE);
531 }
532 rc = DosRead(win32handle, win32file, hdrsize, &ulRead);
533 if(rc != NO_ERROR) {
534 goto failure;
535 }
536
537 if(GetPEFileHeader (win32file, &fh) == FALSE) {
538 goto failure;
539 }
540
541 if(!(fh.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE)) {//not valid
542 goto failure;
543 }
544 if(fh.Machine != IMAGE_FILE_MACHINE_I386) {
545 goto failure;
546 }
547 //IMAGE_FILE_SYSTEM == only drivers (device/file system/video etc)?
548 if(fh.Characteristics & IMAGE_FILE_SYSTEM) {
549 goto failure;
550 }
551 DosClose(win32handle);
552 return (fh.Characteristics & IMAGE_FILE_DLL ? 1 : 2);
553
554failure:
555 free(win32file);
556 DosClose(win32handle);
557 return(FALSE);
558}
559//******************************************************************************
560//******************************************************************************
561/**
562 * Static helper which finds the Win32ImageBase object corresponding to hModule.
563 * @returns Pointer to Win32ImageBase object corresponding to hModule.
564 * @param hModule Odin32 modulehandler. 0 and -1 is aliases for the executable module
565 * @status completely implemented and tested.
566 * @author knut st. osmundsen
567 */
568Win32ImageBase * Win32ImageBase::findModule(HMODULE hModule)
569{
570 Win32ImageBase *pRet;
571
572 if (hModule == -1 || hModule == 0 || /* note: WinNt 4, SP4 don't accept -1 as the EXE handle.*/
573 (WinExe != NULL && hModule == WinExe->getInstanceHandle())
574 )
575 pRet = WinExe;
576 else
577 pRet = Win32DllBase::findModule(hModule);
578
579 if (pRet == NULL)
580 {
581 if (WinExe == NULL)
582 dprintf(("Win32ImageBase::findModule: Module not found. WinExe is NULL, hModule=%#x\n", hModule));
583 else
584 dprintf(("Win32ImageBase::findModule: Module not found, hModule=%#x\n", hModule));
585 }
586
587 return pRet;
588}
589
590
Note: See TracBrowser for help on using the repository browser.