source: trunk/src/kernel32/winimagepe2lx.cpp@ 3433

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

Corrected TLS handling to work with BORLAND/INPRISE executables.

File size: 24.0 KB
Line 
1/* $Id: winimagepe2lx.cpp,v 1.10 2000-04-19 22:16:49 bird Exp $ */
2
3/*
4 * Win32 PE2LX Image base class
5 *
6 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998-1999 knut st. osmundsen (knut.stange.osmundsen@pmsc.no)
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13/*******************************************************************************
14* Defined Constants And Macros *
15*******************************************************************************/
16#define INCL_DOSERRORS /* DOS Error values */
17#define INCL_DOSPROFILE /* DosQuerySysState (Toolkit 4.5) */
18#define INCL_DOSMODULEMGR /* DOS Module management */
19
20#define ALIGN(a, alignment) (((a) + (alignment - 1UL)) & ~(alignment - 1UL))
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <os2wrap.h> //Odin32 OS/2 api wrappers
27
28#include <malloc.h>
29#include <process.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include <win32type.h>
34#include <misc.h>
35#include <winimagebase.h>
36#include <winimagepe2lx.h>
37
38#define DBG_LOCALLOG DBG_winimagepe2lx
39#include "dbglocal.h"
40
41/*******************************************************************************
42* Structures and Typedefs *
43*******************************************************************************/
44#ifndef QS_MTE
45 /* From OS/2 Toolkit v4.5 (BSEDOS.H) */
46
47 /* Global Record structure
48 * Holds all global system information. Placed first in user buffer
49 */
50 typedef struct qsGrec_s { /* qsGrec */
51 ULONG cThrds;
52 ULONG c32SSem;
53 ULONG cMFTNodes;
54 }qsGrec_t;
55
56 /*
57 * System wide MTE information
58 * ________________________________
59 * | pNextRec |----|
60 * |-------------------------------| |
61 * | hmte | |
62 * |-------------------------------| |
63 * | ctImpMod | |
64 * |-------------------------------| |
65 * | ctObj | |
66 * |-------------------------------| |
67 * | pObjInfo |----|----------|
68 * |-------------------------------| | |
69 * | pName |----|----| |
70 * |-------------------------------| | | |
71 * | imported module handles | | | |
72 * | . | | | |
73 * | . | | | |
74 * | . | | | |
75 * |-------------------------------| <--|----| |
76 * | "pathname" | | |
77 * |-------------------------------| <--|----------|
78 * | Object records | |
79 * | (if requested) | |
80 * |_______________________________| |
81 * <-----
82 * NOTE that if the level bit is set to QS_MTE, the base Lib record will be followed
83 * by a series of object records (qsLObj_t); one for each object of the
84 * module.
85 */
86
87 typedef struct qsLObjrec_s { /* qsLOrec */
88 ULONG oaddr; /* object address */
89 ULONG osize; /* object size */
90 ULONG oflags; /* object flags */
91 } qsLObjrec_t;
92
93 typedef struct qsLrec_s { /* qsLrec */
94 void FAR *pNextRec; /* pointer to next record in buffer */
95 USHORT hmte; /* handle for this mte */
96 USHORT fFlat; /* true if 32 bit module */
97 ULONG ctImpMod; /* # of imported modules in table */
98 ULONG ctObj; /* # of objects in module (mte_objcnt)*/
99 qsLObjrec_t FAR *pObjInfo; /* pointer to per object info if any */
100 UCHAR FAR *pName; /* -> name string following struc */
101 } qsLrec_t;
102
103
104
105 /* Pointer Record Structure
106 * This structure is the first in the user buffer.
107 * It contains pointers to heads of record types that are loaded
108 * into the buffer.
109 */
110
111 typedef struct qsPtrRec_s { /* qsPRec */
112 qsGrec_t *pGlobalRec;
113 void *pProcRec; /* ptr to head of process records */
114 void *p16SemRec; /* ptr to head of 16 bit sem recds */
115 void *p32SemRec; /* ptr to head of 32 bit sem recds */
116 void *pMemRec; /* ptr to head of shared mem recs */
117 qsLrec_t *pLibRec; /* ptr to head of mte records */
118 void *pShrMemRec; /* ptr to head of shared mem records */
119 void *pFSRec; /* ptr to head of file sys records */
120 } qsPtrRec_t;
121
122#endif
123
124
125/*******************************************************************************
126* External Functions *
127*******************************************************************************/
128#ifndef QS_MTE
129 /* from OS/2 Toolkit v4.5 */
130
131 APIRET APIENTRY DosQuerySysState(ULONG EntityList, ULONG EntityLevel, PID pid,
132 TID tid, PVOID pDataBuf, ULONG cbBuf);
133 #define QS_MTE 0x0004
134#endif
135
136
137
138/**
139 * Constructor - creates an pe2lx image object from a module handle to a pe2lx module.
140 * @param hinstance OS/2 module handle.
141 * @param fWin32k TRUE: Win32k module.
142 * FALSE: Pe2Lx module.
143 * @status partially implemented.
144 * @author knut st. osmundsen, Sander van Leeuwen
145 */
146Win32Pe2LxImage::Win32Pe2LxImage(HINSTANCE hinstance, BOOL fWin32k)
147 : Win32ImageBase(hinstance),
148 paSections(NULL), cSections(0), pNtHdrs(NULL), fWin32k(fWin32k)
149{
150 setFullPath(szFileName);
151}
152
153
154/**
155 * Free memory associated with this object.
156 * @status completely implemented.
157 * @author knut st. osmundsen, Sander van Leeuwen
158 */
159Win32Pe2LxImage::~Win32Pe2LxImage()
160{
161 cleanup();
162}
163
164
165/**
166 * Initiates the object.
167 * Must be called immediately after the object construction.
168 * @returns Success indicator, TRUE == success; FALSE = failure.
169 * @sketch Get section placement and sizes for this module. (paSections, cSections)
170 * Verify that there is at least one section - the header section.
171 * Locate the NT headers.
172 * Set pNtHdrs pointer.
173 * Validate the NT headers.
174 * Read the PE section table the set the RVAs in paSections.
175 * Locate and set the entrypoint.
176 * Locate the resource directory (if any). (pResDir, ulRVAResourceSection)
177 * TLS - FIXME!
178 * @status completely implemented.
179 * @author knut st. osmundsen
180 * @remark Object must be destroyed if failure!
181 */
182BOOL Win32Pe2LxImage::init()
183{
184 APIRET rc;
185
186 /* Get section placement and sizes for this module. (paSections, cSections) */
187 rc = getSections();
188 if (rc != NO_ERROR)
189 {
190 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: error - getSection failed with rc=%d\n",
191 rc));
192 return FALSE;
193 }
194
195 /* Verify that there is at least one section - the header section. */
196 if (cSections < 1)
197 {
198 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: no header section, cSections is 0\n"));
199 return FALSE;
200 }
201
202 /* Locate the NT headers. */
203 PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)paSections[0].ulAddress;
204 if ((pDosHdr->e_magic != IMAGE_DOS_SIGNATURE
205 || pDosHdr->e_lfanew < sizeof(IMAGE_DOS_HEADER) /* Larger than 64 bytes */
206 || pDosHdr->e_lfanew > 0x04000000UL /* or less that 64MB. */
207 )
208 && !*(PDWORD)paSections[0].ulAddress == IMAGE_NT_SIGNATURE
209 )
210 {
211 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
212 return FALSE;
213 }
214
215 /* Set pNtHdrs pointer. */
216 if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
217 pNtHdrs = (PIMAGE_NT_HEADERS)(paSections[0].ulAddress + pDosHdr->e_lfanew);
218 else
219 pNtHdrs = (PIMAGE_NT_HEADERS)paSections[0].ulAddress;
220
221 /* Validate the NT headers. */
222 if (pNtHdrs->Signature != IMAGE_NT_SIGNATURE
223 || pNtHdrs->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC
224 || pNtHdrs->FileHeader.Machine != IMAGE_FILE_MACHINE_I386
225 || (cSections != 1 /* all in one object */
226 && pNtHdrs->FileHeader.NumberOfSections
227 > cSections - 1 - (pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL ? 0 : 1) /* hdr section and stack */
228 )
229 /* TODO: add more tests? */
230 )
231 {
232 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: Not a pe2lx image!(?)\n"));
233 return FALSE;
234 }
235
236 /* set RVAs */
237 rc = setSectionRVAs();
238 if (rc != NO_ERROR)
239 {
240 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: setSectionRVAs failed with rc=%d\n", rc));
241 return FALSE;
242 }
243
244 /* Locate and set the entrypoint. */
245 setEntryPoint((ULONG)getPointerFromRVA(pNtHdrs->OptionalHeader.AddressOfEntryPoint));
246 if (entryPoint == 0UL &&
247 (pNtHdrs->OptionalHeader.AddressOfEntryPoint != NULL /* getPointerFromRVA failed... */
248 || !(pNtHdrs->FileHeader.Characteristics & IMAGE_FILE_DLL)) /* EXEs must have and entry point! */
249 )
250 {
251 dprintf(("Win32Pe2LxImage::Win32Pe2LxImage: entrypoint is incorrect, AddrOfEP=0x%08x, entryPoint=0x%08x\n",
252 pNtHdrs->OptionalHeader.AddressOfEntryPoint, entryPoint));
253 return FALSE;
254 }
255
256 /* Locate the resource directory (if any) */
257 if (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_RESOURCE
258 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress > 0UL)
259 {
260 ulRVAResourceSection = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
261 pResDir = (PIMAGE_RESOURCE_DIRECTORY)getPointerFromRVA(ulRVAResourceSection);
262 }
263
264 /* TLS - Thread Local Storage */
265 if (pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress != 0UL
266 && pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size != 0UL)
267 {
268 PIMAGE_TLS_DIRECTORY pTLSDir;
269 pTLSDir = (PIMAGE_TLS_DIRECTORY)getPointerFromRVA(pNtHdrs->OptionalHeader.
270 DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].
271 VirtualAddress);
272
273 if (pTLSDir != NULL)
274 {
275 PVOID pv;
276 ULONG ulBorlandRVAFix = 0UL;
277
278 pv = getPointerFromRVA(pTLSDir->StartAddressOfRawData);
279 /*
280 * Borland seems to have problems getting things right...
281 * Needs to subtract image base to make the TLSDir "RVA"s real
282 * RVAs before converting them to pointers.
283 */
284 if ((pv == NULL || pTLSDir->StartAddressOfRawData == 0UL)
285 && pTLSDir->StartAddressOfRawData > this->pNtHdrs->OptionalHeader.ImageBase)
286 {
287 ulBorlandRVAFix = this->pNtHdrs->OptionalHeader.ImageBase;
288 pv = getPointerFromRVA(pTLSDir->StartAddressOfRawData - ulBorlandRVAFix);
289 }
290 if (pv == NULL || pTLSDir->StartAddressOfRawData == 0UL)
291 {
292 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS StartAddressOfRawData - %#8x.\n",
293 pTLSDir->StartAddressOfRawData));
294 return FALSE;
295 }
296 setTLSAddress(pv);
297 setTLSInitSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData);
298 setTLSTotalSize(pTLSDir->EndAddressOfRawData - pTLSDir->StartAddressOfRawData + pTLSDir->SizeOfZeroFill);
299 pv = getPointerFromRVA((ULONG)pTLSDir->AddressOfIndex - ulBorlandRVAFix);
300 if (pv == NULL)
301 {
302 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOffIndex - %#8x.\n",
303 pTLSDir->AddressOfIndex));
304 return FALSE;
305 }
306 setTLSIndexAddr((LPDWORD)pv);
307 pv = getPointerFromRVA((ULONG)pTLSDir->AddressOfCallBacks - ulBorlandRVAFix);
308 if (pv == NULL)
309 {
310 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS AddressOffIndex - %#8x.\n",
311 pTLSDir->AddressOfIndex));
312 return FALSE;
313 }
314 setTLSCallBackAddr((PIMAGE_TLS_CALLBACK*)pv);
315 }
316 else
317 {
318 eprintf(("Win32Pe2LxImage::init: invalid RVA to TLS Dir - %#8x. (getPointerFromRVA failed)\n",
319 pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress));
320 return FALSE;
321 }
322 }
323 return TRUE;
324}
325
326
327
328/**
329 * Gets the object layout for this module. Creates the paSections array.
330 * @returns OS2 errorcode. (NO_ERROR == success)
331 * @sketch Allocate output buffer.
332 * Call DosQuerySysState.
333 * IF buffer overflow THEN retry calling it with larger buffers, until buffer size is 1MB.
334 * IF success THEN
335 * BEGIN
336 * Find record for this module.
337 * IF record found THEN allocate memory for object table and copy it. (paSections, cSections)
338 * END
339 * @status Completely implemented.
340 * @author knut st. osmundsen
341 */
342ULONG Win32Pe2LxImage::getSections()
343{
344 APIRET rc = NO_ERROR;
345 qsPtrRec_t * pPtrRec;
346 ULONG cbBuf = 65536;
347
348 pPtrRec = (qsPtrRec_t *)malloc(cbBuf);
349 if (pPtrRec != NULL)
350 {
351 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
352 while (cbBuf < 1024*1024 && rc == ERROR_BUFFER_OVERFLOW)
353 {
354 PVOID pv = pPtrRec;
355 cbBuf += 65536;
356 pPtrRec = (qsPtrRec_t *)realloc(pv, cbBuf);
357 if (pPtrRec != NULL)
358 rc = DosQuerySysState(QS_MTE, QS_MTE, getpid(), 0L, pPtrRec, cbBuf);
359 else
360 {
361 rc = ERROR_NOT_ENOUGH_MEMORY;
362 free(pv);
363 }
364 }
365
366 if (rc == NO_ERROR)
367 {
368 qsLrec_t * pLrec = pPtrRec->pLibRec;
369 while (pLrec != NULL)
370 {
371 /*
372 * Bug detected in OS/2 FP13. Probably a problem which occurs
373 * in _LDRSysMteInfo when qsCheckCache is calle before writing
374 * object info. The result is that the cache flushed and the
375 * attempt of updating the qsLrec_t next and object pointer is
376 * not done. This used to work earlier and on Aurora AFAIK.
377 *
378 * The fix for this problem is to check if the pObjInfo is NULL
379 * while the number of objects isn't 0 and correct this. pNextRec
380 * will also be NULL at this time. This will be have to corrected
381 * before we exit the loop or moves to the next record.
382 * There is also a nasty alignment of the object info... Hope
383 * I got it right. (This aligment seems new to FP13.)
384 */
385 if (pLrec->pObjInfo == NULL /*&& pLrec->pNextRec == NULL*/ && pLrec->ctObj > 0)
386 {
387 pLrec->pObjInfo = (qsLObjrec_t*)(
388 (char*)pLrec
389 + ((sizeof(qsLrec_t) /* size of the lib record */
390 + pLrec->ctImpMod * sizeof(short) /* size of the array of imported modules */
391 + strlen((char*)pLrec->pName) + 1 /* size of the filename */
392 + 3) & ~3)); /* the size is align on 4 bytes boundrary */
393 pLrec->pNextRec = (qsLrec_t*)((char*)pLrec->pObjInfo
394 + sizeof(qsLObjrec_t) * pLrec->ctObj);
395 }
396 if (pLrec->hmte == hinstance)
397 break;
398
399 /*
400 * Next record
401 */
402 pLrec = (qsLrec_t*)pLrec->pNextRec;
403 }
404
405
406 if (pLrec)
407 {
408 if (pLrec->pObjInfo != NULL)
409 {
410 /* Allocate memory for paSections */
411 paSections = (PSECTION)malloc(pLrec->ctObj*sizeof(SECTION));
412 if (paSections != NULL)
413 {
414 /* objects -> section array */
415 for (int i = 0; i < pLrec->ctObj; i++)
416 {
417 paSections[i].ulRVA = ~0UL;
418 paSections[i].cbVirtual = pLrec->pObjInfo[i].osize;
419 paSections[i].ulAddress = pLrec->pObjInfo[i].oaddr;
420 }
421 cSections = pLrec->ctObj;
422 }
423 else
424 rc = ERROR_NOT_ENOUGH_MEMORY;
425 }
426 else
427 {
428 rc = ERROR_BAD_EXE_FORMAT;
429 dprintf(("Win32Pe2LxImage::getSections: Error - no object table!\n"));
430 }
431 }
432 else
433 rc = ERROR_MOD_NOT_FOUND;
434 }
435 else
436 dprintf(("DosQuerySysState - failed with rc=%d (cbBuf=%d)\n", rc, cbBuf));
437
438 if (pPtrRec != NULL)
439 free(pPtrRec);
440 }
441 else
442 rc = ERROR_NOT_ENOUGH_MEMORY;
443
444 return rc;
445}
446
447
448/**
449 * Sets the ulRVA according to the original PE section table.
450 * @returns OS/2 errorcode. (NO_ERROR == success)
451 * @sketch DEBUG: Validate pNtHdrs
452 * Make pointer to start of PE section table.
453 * Set RVA for the header section.
454 * IF not all in one object exe? THEN
455 * Loop thru the sections in the PE section table.
456 * Note: due to the header section: PE section no. + 1 == LX object no.
457 * ELSE
458 * BEGIN
459 * (try) Reallocate paSections to NumberOfSections + 3.
460 * Loop thru the PE sections and make paSections from them.
461 * Add final Stack or TIBFix+Stack section if necessary.
462 * Resize header section.
463 * END
464 * @status completely implemented.
465 * @author knut st. osmundsen
466 * @remark Must not be called before pNtHdrs is set.
467 */
468ULONG Win32Pe2LxImage::setSectionRVAs()
469{
470 #if DEBUG
471 if (pNtHdrs == NULL)
472 {
473 DebugInt3();
474 return ERROR_INVALID_PARAMETER;
475 }
476 #endif
477
478 PIMAGE_SECTION_HEADER paPESections = (PIMAGE_SECTION_HEADER)
479 ((unsigned)pNtHdrs + sizeof(*pNtHdrs) +
480 (pNtHdrs->OptionalHeader.NumberOfRvaAndSizes - IMAGE_NUMBEROF_DIRECTORY_ENTRIES) * sizeof(IMAGE_DATA_DIRECTORY)
481 );
482
483 /* set RVA for the header section to 0UL. */
484 paSections[0].ulRVA = 0UL;
485
486 /* All in one object exe? */
487 if (pNtHdrs->FileHeader.NumberOfSections < cSections)
488 {
489 /* loop thru the other sections */
490 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
491 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
492 }
493 else
494 { /* all in one object */
495 /* (try) Reallocate paSections to NumberOfSections + 3. */
496 PVOID pv = realloc(paSections, sizeof(paSections[0]) * (pNtHdrs->FileHeader.NumberOfSections + 3));
497 if (pv != NULL)
498 {
499 paSections = (PSECTION)pv;
500
501 /* loop thru the PE sections */
502 for (int i = 0; i < pNtHdrs->FileHeader.NumberOfSections; i++)
503 {
504 if (paSections[0].cbVirtual < paPESections[i].VirtualAddress)
505 {
506 dprintf(("Win32Pe2LxImage::setSectionRVAs: mismatch between section table and all-in-one-object"
507 "paSections[0].cbVirtual %#x paPESections[i].VirtualAddress %#x\n",
508 paSections[0].cbVirtual, paPESections[i].VirtualAddress
509 ));
510 return ERROR_BAD_EXE_FORMAT;
511 }
512 paSections[i+1].ulRVA = paPESections[i].VirtualAddress;
513 paSections[i+1].cbVirtual = max(paPESections[i].Misc.VirtualSize, paPESections[i].SizeOfRawData);
514 paSections[i+1].ulAddress = paSections[0].ulAddress + paPESections[i].VirtualAddress;
515 }
516 cSections = pNtHdrs->FileHeader.NumberOfSections + 1;
517
518 /* add final Stack or TIBFix+Stack section if necessary */
519 if (paSections[0].cbVirtual > paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000))
520 {
521 paSections[i+1].ulRVA = ~0UL;
522 paSections[i+1].cbVirtual = paSections[0].cbVirtual - paSections[i].ulRVA + ALIGN(paSections[i].cbVirtual, 0x1000);
523 paSections[i+1].ulAddress = paSections[i].ulAddress + ALIGN(paSections[i].cbVirtual, 0x1000);
524 i++;
525 cSections++;
526 }
527
528 /* resize header section */
529 paSections[0].cbVirtual = paSections[1].ulRVA; /*....*/
530 }
531 else
532 return ERROR_NOT_ENOUGH_MEMORY;
533 }
534
535 return NO_ERROR;
536}
537
538
539/**
540 * Frees memory used by this object.
541 * When an exception is to be thrown, this function is called first to clean up
542 * the object. Base class(es) are automatically clean up by theire destructor(s).
543 * @status completely implemented.
544 * @author knut st. osmundsen
545 */
546VOID Win32Pe2LxImage::cleanup()
547{
548 if (paSections != NULL)
549 {
550 free(paSections);
551 paSections = NULL;
552 cSections = 0;
553 }
554}
555
556
557/**
558 * Converts a RVA to an pointer.
559 * @returns Pointer matching the given RVA, NULL on error.
560 * @param ulRVA An address relative to the imagebase of the original PE image.
561 * If this is 0UL NULL is returned.
562 * @sketch DEBUG: validate state, paSections != NULL
563 * IF ulRVA is 0 THEN return NULL
564 * LOOP while more section left and ulRVA is not within section
565 * next section
566 * IF section matching ulRVA is not found THEN fail.
567 * return pointer matching RVA.
568 * @status completely implemented.
569 * @author knut st. osmundsen
570 * @remark Should not be called until getSections has returned successfully.
571 * RVA == 0 is ignored.
572 */
573PVOID Win32Pe2LxImage::getPointerFromRVA(ULONG ulRVA)
574{
575 int i;
576 #ifdef DEBUG
577 if (paSections == NULL)
578 return NULL;
579 #endif
580
581 if (ulRVA == 0UL)
582 return NULL;
583
584 i = 0;
585 while (i < cSections &&
586 !(paSections[i].ulRVA <= ulRVA && paSections[i].ulRVA + paSections[i].cbVirtual > ulRVA)) /* ALIGN on page too? */
587 i++;
588
589 if (i >= cSections)
590 return NULL;
591
592 return (PVOID)(ulRVA - paSections[i].ulRVA + paSections[i].ulAddress);
593}
594
595/**
596 * Gets pointer to an exported procedure by procedure name.
597 * @returns Address of exported procedure. 0UL if not found.
598 * @param name Exported procedure name.
599 * @status completely implemented.
600 * @author Sander van Leeuwen
601 * @remark
602 */
603ULONG Win32Pe2LxImage::getApi(char *name)
604{
605 APIRET rc;
606 ULONG ulApiAddr;
607
608 rc = DosQueryProcAddr(hinstance, 0, name, (PFN *)&ulApiAddr);
609 return rc == NO_ERROR ? ulApiAddr : 0;
610}
611
612
613/**
614 * Gets pointer to an exported procedure by ordinal.
615 * @returns Pointer to an exported procedure. 0UL if not found.
616 * @param ordinal Export ordinal number.
617 * @status completely implemented.
618 * @author Sander van Leeuwen
619 * @remark FIXME:
620 * This function should be implemented for both Exe and Dll images!
621 * It could be done similar in both peldr image and pe2lx images by
622 * accessing PE structures.
623 */
624ULONG Win32Pe2LxImage::getApi(int ordinal)
625{
626 APIRET rc;
627 ULONG ulApiAddr;
628
629 rc = DosQueryProcAddr(hinstance, ordinal, NULL, (PFN *)&ulApiAddr);
630
631 return rc == NO_ERROR ? ulApiAddr : 0;
632}
Note: See TracBrowser for help on using the repository browser.