Changeset 129 for trunk/src/helpers/dosh2.c
- Timestamp:
- Jan 8, 2002, 7:29:57 PM (24 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/dosh2.c
r127 r129 350 350 351 351 return (arc); // V0.9.9 (2001-04-04) [umoeller] 352 }353 354 /*355 *@@category: Helpers\Control program helpers\Executable info356 * these functions can retrieve BLDLEVEL information,357 * imported modules information, exported functions information,358 * and resources information from any executable module. See359 * doshExecOpen.360 */361 362 /********************************************************************363 *364 * Executable functions365 *366 ********************************************************************/367 368 /*369 *@@ doshExecOpen:370 * this opens the specified executable file371 * (which can be an .EXE, .COM, .DLL, or372 * driver file) for use with the other373 * doshExec* functions.374 *375 * If no error occurs, NO_ERROR is returned376 * and a pointer to a new EXECUTABLE structure377 * is stored in *ppExec. Consider this pointer a378 * handle and pass it to doshExecClose to clean379 * up.380 *381 * If NO_ERROR is returned, all the fields through382 * ulOS are set in EXECUTABLE. The psz* fields383 * which follow afterwards require an additional384 * call to doshExecQueryBldLevel.385 *386 * NOTE: If NO_ERROR is returned, the executable387 * file has been opened by this function. It will388 * only be closed when you call doshExecClose.389 *390 * If errors occur, this function returns the391 * following error codes:392 *393 * -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.394 *395 * -- ERROR_INVALID_EXE_SIGNATURE (191): header is396 * neither plain DOS, nor NE, nor LX, nor PE.397 * The given file probably isn't even an398 * executable. This you will get if you399 * pass in COM, BAT, or CMD files.400 *401 * -- ERROR_BAD_EXE_FORMAT (193): header was402 * recognized, but the header data was403 * not understood.404 *405 * -- ERROR_INVALID_PARAMETER: ppExec is NULL.406 *407 * plus those of DosOpen, DosSetFilePtr, and408 * DosRead.409 *410 * The following executable types are supported411 * (see EXECUTABLE for details):412 *413 * -- Plain DOS 3.x executable without new header.414 *415 * -- New Executable (NE), used by Win16 and416 * 16-bit OS/2 and still many of today's drivers.417 *418 * -- Linear Executable (LX), OS/2 2.x and above.419 *420 * -- Portable Executable (PE), used by Win32.421 *422 * V0.9.12 adds support for NOSTUB executables,423 * which are new-style executables (NE or LX)424 * without a leading DOS header. The executable425 * then starts directly with the NE or LX header.426 * I am not sure whether PE supports such things427 * as well... if so, it should be supported too.428 *429 * @@todo:430 *431 * win95 \WINDOWS\extract.exe is NE with a non-standard format432 * win16 \WINDOWS\EXPAND.EXE433 * win16 \WINDOWS\MSD.EXE"434 *435 *@@added V0.9.0 [umoeller]436 *@@changed V0.9.1 (2000-02-13) [umoeller]: fixed 32-bits flag437 *@@changed V0.9.7 (2000-12-20) [lafaix]: fixed ulNewHeaderOfs438 *@@changed V0.9.10 (2001-04-08) [lafaix]: added PE support439 *@@changed V0.9.10 (2001-04-08) [umoeller]: now setting ppExec only if NO_ERROR is returned440 *@@changed V0.9.12 (2001-05-03) [umoeller]: added support for NOSTUB newstyle executables441 *@@changed V0.9.16 (2001-12-08) [umoeller]: now using OPEN_SHARE_DENYWRITE442 *@@changed V0.9.16 (2001-12-08) [umoeller]: fLibrary was never set, works for LX and NE now443 *@@changed V0.9.16 (2001-12-08) [umoeller]: some speed optimizations, changed some return codes444 *@@changed V0.9.16 (2002-01-04) [umoeller]: added fixes for COM, BAT, CMD extensions445 */446 447 APIRET doshExecOpen(const char* pcszExecutable,448 PEXECUTABLE* ppExec)449 {450 APIRET arc = NO_ERROR;451 452 PEXECUTABLE pExec = NULL;453 454 PXFILE pFile = NULL;455 ULONG cbFile = 0;456 PCSZ pExt;457 BOOL fOpenFile = FALSE;458 459 if (!ppExec)460 return (ERROR_INVALID_PARAMETER);461 462 if (!(pExec = (PEXECUTABLE)malloc(sizeof(EXECUTABLE))))463 return (ERROR_NOT_ENOUGH_MEMORY);464 465 memset(pExec, 0, sizeof(EXECUTABLE));466 467 // check some of the default extensions468 // V0.9.16 (2002-01-04) [umoeller]469 if (pExt = doshGetExtension(pcszExecutable))470 {471 if (!stricmp(pExt, "COM"))472 {473 // I am not willing to find out more about the474 // .COM executable format, so for this one case,475 // let OS/2 determine what we have here476 ULONG ulDosAppType = 0;477 if (!(arc = DosQueryAppType((PSZ)pcszExecutable, &ulDosAppType)))478 {479 if (ulDosAppType & FAPPTYP_DOS) // 0x20480 pExec->ulOS = EXEOS_DOS3;481 else482 pExec->ulOS = EXEOS_OS2;483 484 pExec->ulExeFormat = EXEFORMAT_COM;485 }486 }487 else if (!stricmp(pExt, "BAT"))488 {489 pExec->ulOS = EXEOS_DOS3;490 pExec->ulExeFormat = EXEFORMAT_TEXT_BATCH;491 }492 else if (!stricmp(pExt, "CMD"))493 {494 pExec->ulOS = EXEOS_OS2;495 pExec->ulExeFormat = EXEFORMAT_TEXT_CMD;496 }497 else498 fOpenFile = TRUE;499 }500 501 if ( (fOpenFile)502 && (!(arc = doshOpen((PSZ)pcszExecutable,503 XOPEN_READ_EXISTING,504 &cbFile,505 &pFile)))506 )507 {508 // file opened successfully:509 pExec->pFile = pFile;510 511 // read old DOS EXE header512 if (!(pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER))))513 arc = ERROR_NOT_ENOUGH_MEMORY;514 else515 {516 pExec->cbDosExeHeader = sizeof(DOSEXEHEADER);517 if (!(arc = doshReadAt(pFile,518 0,519 &pExec->cbDosExeHeader, // in/out520 (PBYTE)pExec->pDosExeHeader)))521 {522 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]523 BOOL fLoadNewHeader = FALSE;524 525 // now check if we really have a DOS header526 if (pExec->pDosExeHeader->usDosExeID != 0x5a4d)527 {528 // arc = ERROR_INVALID_EXE_SIGNATURE;529 530 // V0.9.12 (2001-05-03) [umoeller]531 // try loading new header directly; there are532 // drivers which were built with NOSTUB, and533 // the exe image starts out with the NE or LX534 // image directly535 fLoadNewHeader = TRUE;536 // ulNewHeaderOfs is 0 now537 538 // remove the DOS header info, since we have none539 // V0.9.12 (2001-05-03) [umoeller]540 FREE(pExec->pDosExeHeader);541 }542 else543 {544 // we have a DOS header:545 if (pExec->pDosExeHeader->usRelocTableOfs < 0x40)546 {547 // neither LX nor PE nor NE:548 pExec->ulOS = EXEOS_DOS3;549 pExec->ulExeFormat = EXEFORMAT_OLDDOS;550 }551 else552 {553 // we have a new header offset:554 fLoadNewHeader = TRUE;555 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;556 }557 }558 559 if (fLoadNewHeader)560 {561 // either LX or PE or NE:562 // read in new header...563 // ulNewHeaderOfs is now either 0 (if no DOS header564 // was found) or pDosExeHeader->ulNewHeaderOfs565 // V0.9.12 (2001-05-03) [umoeller]566 ULONG cbRead;567 PBYTE pbHeader;568 569 // now, we used to read in the first two chars570 // to check out if we have PE or LX or NE and571 // then read the header accordingly... but572 // that wasn't terribly efficient. So load573 // a chunk of data and then do a realloc()574 // instead.575 576 // take the largest of LXHEADER and NEHEADER and PEHEADER577 cbRead = sizeof(LXHEADER);578 if (sizeof(NEHEADER) > cbRead)579 cbRead = sizeof(NEHEADER);580 if (sizeof(PEHEADER) > cbRead)581 cbRead = sizeof(PEHEADER);582 583 if (!(pbHeader = (PBYTE)malloc(cbRead)))584 arc = ERROR_NOT_ENOUGH_MEMORY;585 else if (!(arc = doshReadAt(pFile,586 ulNewHeaderOfs,587 &cbRead,588 pbHeader)))589 {590 PBYTE pbCheckOS = NULL;591 592 PSZ achNewHeaderType = (PSZ)pbHeader;593 594 if (!memcmp(achNewHeaderType, "NE", 2))595 {596 // New Executable:597 pExec->ulExeFormat = EXEFORMAT_NE;598 599 if (cbRead < sizeof(NEHEADER))600 {601 arc = ERROR_BAD_EXE_FORMAT;602 FREE(pbHeader);603 }604 else605 {606 pExec->pNEHeader = (PNEHEADER)realloc(pbHeader,607 sizeof(NEHEADER));608 pExec->cbNEHeader = sizeof(NEHEADER);609 pbCheckOS = &pExec->pNEHeader->bTargetOS;610 // set library flag V0.9.16 (2001-12-08) [umoeller]611 if (pExec->pNEHeader->usFlags & 0x8000)612 // library:613 pExec->fLibrary = TRUE;614 }615 }616 else if ( (!memcmp(achNewHeaderType, "LX", 2))617 || (!memcmp(achNewHeaderType, "LE", 2))618 // this is used by SMARTDRV.EXE619 )620 {621 // OS/2 Linear Executable:622 pExec->ulExeFormat = EXEFORMAT_LX;623 624 if (cbRead < sizeof(LXHEADER))625 {626 arc = ERROR_BAD_EXE_FORMAT;627 FREE(pbHeader);628 }629 else630 {631 pExec->pLXHeader = (PLXHEADER)realloc(pbHeader,632 sizeof(LXHEADER));633 // read in LX header634 pExec->cbLXHeader = sizeof(LXHEADER);635 pbCheckOS = (PBYTE)(&pExec->pLXHeader->usTargetOS);636 // set library flag V0.9.16 (2001-12-08) [umoeller]637 if (pExec->pLXHeader->ulFlags & 0x8000)638 // library:639 pExec->fLibrary = TRUE;640 }641 }642 else if (!memcmp(achNewHeaderType, "PE", 2))643 {644 pExec->ulExeFormat = EXEFORMAT_PE;645 646 if (cbRead < sizeof(PEHEADER))647 {648 arc = ERROR_BAD_EXE_FORMAT;649 FREE(pbHeader);650 }651 else652 {653 // PE has a standard header of 24 bytes654 // plus an extended header, so check what655 // we've got656 ULONG cbPE = sizeof(PEHEADER); // 24657 // + ((PPEHEADER)pbHeader)->usHeaderSize;658 pExec->pPEHeader = (PPEHEADER)realloc(pbHeader,659 cbPE);660 661 pExec->cbPEHeader = cbPE;662 pExec->ulOS = EXEOS_WIN32;663 pExec->f32Bits = TRUE;664 665 /*666 // we have the first 24 bytes already, so667 // go for the next chunk, if this is more668 // than we have in PEHEADER669 if ( (cbRead < cbPE)670 && (cbRead = pExec->pPEHeader->usHeaderSize)671 )672 {673 _Pmpf((" usHdrSize %d, sizeof(PEHEADER) %d, cbRead %d, cbPE %d --> reading extended header",674 pExec->pPEHeader->usHeaderSize,675 sizeof(PEHEADER),676 cbRead,677 cbPE));678 if (!(arc = doshReadAt(hFile,679 ulNewHeaderOfs + 24,680 FILE_BEGIN,681 &cbRead,682 (PBYTE)pExec->pPEHeader + 24)))683 {684 }685 else686 {687 arc = ERROR_BAD_EXE_FORMAT;688 FREE(pExec->pPEHeader);689 }690 }691 else692 _Pmpf((" already got extended header"));693 */694 }695 }696 else697 {698 // strange type:699 arc = ERROR_INVALID_EXE_SIGNATURE;700 FREE(pbHeader);701 }702 703 if ((!arc) && (pbCheckOS))704 {705 // BYTE to check for operating system706 // (NE and LX):707 switch (*pbCheckOS)708 {709 case NEOS_OS2:710 pExec->ulOS = EXEOS_OS2;711 if (pExec->ulExeFormat == EXEFORMAT_LX)712 pExec->f32Bits = TRUE;713 break;714 715 case NEOS_WIN16:716 pExec->ulOS = EXEOS_WIN16;717 break;718 719 case NEOS_DOS4:720 pExec->ulOS = EXEOS_DOS4;721 break;722 723 case NEOS_WIN386:724 pExec->ulOS = EXEOS_WIN386;725 pExec->f32Bits = TRUE;726 break;727 }728 }729 } // end if (!(arc = doshReadAt(hFile,730 } // end if (fLoadNewHeader)731 } // end if (!(arc = doshReadAt(hFile,732 } // end else if (!(pExec->pDosExeHeader = (PDOSEXEHEADER)malloc(sizeof(DOSEXEHEADER))))733 734 } // end if (!(arc = DosOpen((PSZ)pcszExecutable,735 736 if (arc != NO_ERROR)737 // error: clean up738 doshExecClose(&pExec);739 else740 *ppExec = pExec;741 742 return (arc);743 }744 745 /*746 *@@ ParseBldLevel:747 * called from doshExecQueryBldLevel to parse748 * the BLDLEVEL string.749 *750 * On entry, caller has copied the string into751 * pExec->pszDescription. The string is752 * null-terminated.753 *754 * The BLDLEVEL string comes in two flavors.755 *756 * -- The standard format is:757 *758 + @#VENDOR:VERSION#@DESCRIPTION759 *760 * DESCRIPTION can have leading spaces, but761 * need to have them.762 *763 * -- However, there is an extended version764 * in that the DESCRIPTION field is split765 * up even more. The marker for this seems766 * to be that the description starts out767 * with "##1##".768 *769 + ##1## DATETIME BUILDMACHINE:ASD:LANG:CTRY:REVISION:UNKNOWN:FIXPAK@@DESCRIPTION770 *771 * The problem is that the DATETIME field comes772 * in several flavors. IBM uses things like773 *774 + "Thu Nov 30 15:30:37 2000 BWBLD228"775 *776 * while DANIS506.ADD has777 *778 + "15.12.2000 18:22:57 Nachtigall"779 *780 * Looks like the date/time string is standardized781 * to have 24 characters then.782 *783 *@@added V0.9.12 (2001-05-18) [umoeller]784 *@@changed V0.9.12 (2001-05-19) [umoeller]: added extended BLDLEVEL support785 */786 787 VOID ParseBldLevel(PEXECUTABLE pExec)788 {789 const char // *pStartOfAuthor = 0,790 *pStartOfVendor = 0;791 792 // @#VENDOR:VERSION#@ DESCRIPTION793 // but skip the first byte, which has the string length794 pStartOfVendor = strstr(pExec->pszDescription,795 "@#");796 if (pStartOfVendor)797 {798 const char *pStartOfInfo = strstr(pStartOfVendor + 2,799 "#@");800 if (pStartOfInfo)801 {802 const char *pEndOfVendor = strchr(pStartOfVendor + 2,803 ':');804 if (pEndOfVendor)805 {806 pExec->pszVendor = strhSubstr(pStartOfVendor + 2,807 pEndOfVendor);808 pExec->pszVersion = strhSubstr(pEndOfVendor + 1,809 pStartOfInfo);810 // skip "@#" in DESCRIPTION string811 pStartOfInfo += 2;812 813 // now check if we have extended DESCRIPTION V0.9.12 (2001-05-19) [umoeller]814 if ( (strlen(pStartOfInfo) > 6)815 && (!memcmp(pStartOfInfo, "##1##", 5))816 )817 {818 // yes: parse that beast819 const char *p = pStartOfInfo + 5;820 821 // get build date/time822 if (strlen(p) > 24)823 {824 // date/time seems to be fixed 24 chars in length825 if (pExec->pszBuildDateTime = (PSZ)malloc(25))826 {827 memcpy(pExec->pszBuildDateTime,828 p,829 24);830 pExec->pszBuildDateTime[24] = '\0';831 832 p += 24;833 834 // now we're at the colon-separated835 // strings, first of which is the836 // build machine;837 // skip leading spaces838 while (*p == ' ')839 p++;840 841 if (*p)842 {843 char **papsz[] =844 {845 &pExec->pszBuildMachine,846 &pExec->pszASD,847 &pExec->pszLanguage,848 &pExec->pszCountry,849 &pExec->pszRevision,850 &pExec->pszUnknown,851 &pExec->pszFixpak852 };853 ULONG ul;854 855 for (ul = 0;856 ul < sizeof(papsz) / sizeof(papsz[0]);857 ul++)858 {859 BOOL fStop = FALSE;860 const char *pNextColon = strchr(p, ':'),861 *pDoubleAt = strstr(p, "@@");862 if (!pNextColon)863 {864 // last item:865 if (pDoubleAt)866 pNextColon = pDoubleAt;867 else868 pNextColon = p + strlen(p);869 870 fStop = TRUE;871 }872 873 if ( (fStop)874 || ( (pNextColon)875 && ( (!pDoubleAt)876 || (pNextColon < pDoubleAt)877 )878 )879 )880 {881 if (pNextColon > p + 1)882 *(papsz[ul]) = strhSubstr(p, pNextColon);883 }884 else885 break;886 887 if (fStop)888 break;889 890 p = pNextColon + 1;891 }892 }893 }894 }895 896 pStartOfInfo = strstr(p,897 "@@");898 if (pStartOfInfo)899 pStartOfInfo += 2;900 }901 902 // -- if we had no extended DESCRIPTION,903 // pStartOfInfo points to regular description now904 // -- if we parse the extended DESCRIPTION above,905 // pStartOfInfo points to after @@ now906 // -- if we had an error, pStartOfInfo is NULL907 if (pStartOfInfo)908 {909 // add the regular DESCRIPTION then910 // skip leading spaces in info string911 while (*pStartOfInfo == ' ')912 pStartOfInfo++;913 if (*pStartOfInfo) // V0.9.9 (2001-04-04) [umoeller]914 // and copy until end of string915 pExec->pszInfo = strdup(pStartOfInfo);916 }917 }918 }919 }920 }921 922 /*923 *@@ doshExecQueryBldLevel:924 * this retrieves buildlevel information for an925 * LX or NE executable previously opened with926 * doshExecOpen.927 *928 * BuildLevel information must be contained in the929 * DESCRIPTION field of an executable's module930 * definition (.DEF) file. In order to be readable931 * by BLDLEVEL.EXE (which ships with OS/2), this932 * string must have the following format:933 *934 + Description '@#AUTHOR:VERSION#@ DESCRIPTION'935 *936 * Example:937 *938 + Description '@#Ulrich Mller:0.9.0#@ XWorkplace Sound Support Module'939 *940 * The "Description" entry always ends up as the941 * very first entry in the non-resident name table942 * in LX and NE executables. So this is what we retrieve943 * here.944 *945 * If the first entry in that table exists, NO_ERROR is946 * returned and at least the pszDescription field in947 * EXECUTABLE is set to that information.948 *949 * If that string is in IBM BLDLEVEL format, the string950 * is automatically parsed, and the pszVendor, pszVersion,951 * and pszInfo fields are also set. In the above examples,952 * this would return the following information:953 + pszVendor = "Ulrich Mller"954 + pszVersion = "0.9.0"955 + pszInfo = "XWorkplace Sound Support Module"956 *957 * If that string is not in BLDLEVEL format, only pszDescription958 * will be set. The other fields remain NULL.959 *960 * This returns the following errors:961 *962 * -- ERROR_INVALID_PARAMETER: pExec invalid963 *964 * -- ERROR_INVALID_EXE_SIGNATURE (191): pExec is not in LX or NE format965 *966 * -- ERROR_INVALID_DATA (13): non-resident name table not found.967 *968 * -- ERROR_NOT_ENOUGH_MEMORY: malloc() failed.969 *970 * plus the error codes of DosSetFilePtr and DosRead.971 *972 *@@added V0.9.0 [umoeller]973 *@@changed V0.9.0 (99-10-22) [umoeller]: NE format now supported974 *@@changed V0.9.1 (99-12-06): fixed memory leak975 *@@changed V0.9.9 (2001-04-04) [umoeller]: added more error checking976 *@@changed V0.9.12 (2001-05-18) [umoeller]: extracted ParseBldLevel977 */978 979 APIRET doshExecQueryBldLevel(PEXECUTABLE pExec)980 {981 APIRET arc = NO_ERROR;982 983 if (!pExec)984 arc = ERROR_INVALID_PARAMETER;985 else986 {987 PXFILE pFile = pExec->pFile;988 989 ULONG ulNRNTOfs = 0;990 991 if (pExec->ulExeFormat == EXEFORMAT_LX)992 {993 // OK, LX format:994 // check if we have a non-resident name table995 if (pExec->pLXHeader == NULL)996 arc = ERROR_INVALID_DATA;997 else if (pExec->pLXHeader->ulNonResdNameTblOfs == 0)998 arc = ERROR_INVALID_DATA;999 else1000 ulNRNTOfs = pExec->pLXHeader->ulNonResdNameTblOfs;1001 }1002 else if (pExec->ulExeFormat == EXEFORMAT_NE)1003 {1004 // OK, NE format:1005 // check if we have a non-resident name table1006 if (pExec->pNEHeader == NULL)1007 arc = ERROR_INVALID_DATA;1008 else if (pExec->pNEHeader->ulNonResdTblOfs == 0)1009 arc = ERROR_INVALID_DATA;1010 else1011 ulNRNTOfs = pExec->pNEHeader->ulNonResdTblOfs;1012 }1013 else1014 // neither LX nor NE: stop1015 arc = ERROR_INVALID_EXE_SIGNATURE;1016 1017 if ( (!arc)1018 && (ulNRNTOfs)1019 )1020 {1021 ULONG ulLocal = 0,1022 ulBytesRead = 0;1023 1024 // move EXE file pointer to offset of non-resident name table1025 // (from LX header)1026 if (!(arc = DosSetFilePtr(pFile->hf, // file is still open1027 ulNRNTOfs, // ofs determined above1028 FILE_BEGIN,1029 &ulLocal)))1030 {1031 // allocate memory as necessary1032 PSZ pszNameTable = (PSZ)malloc(2001); // should suffice, because each entry1033 // may only be 255 bytes in length1034 if (!pszNameTable)1035 arc = ERROR_NOT_ENOUGH_MEMORY;1036 else1037 {1038 if (!(arc = DosRead(pFile->hf,1039 pszNameTable,1040 2000,1041 &ulBytesRead)))1042 {1043 if (*pszNameTable == 0)1044 // first byte (length byte) is null:1045 arc = ERROR_INVALID_DATA;1046 else1047 {1048 // now copy the string, which is in Pascal format1049 pExec->pszDescription = (PSZ)malloc((*pszNameTable) + 1); // addt'l null byte1050 if (!pExec->pszDescription)1051 arc = ERROR_NOT_ENOUGH_MEMORY;1052 else1053 {1054 memcpy(pExec->pszDescription,1055 pszNameTable + 1, // skip length byte1056 *pszNameTable); // length byte1057 // terminate string1058 *(pExec->pszDescription + (*pszNameTable)) = 0;1059 1060 ParseBldLevel(pExec);1061 }1062 }1063 }1064 1065 free(pszNameTable);1066 } // end if PSZ pszNameTable = (PSZ)malloc(2001);1067 }1068 }1069 } // end if (!pExec)1070 1071 return (arc);1072 }1073 1074 /*1075 *@@ doshExecQueryImportedModules:1076 * returns an array of FSYSMODULE structure describing all1077 * imported modules.1078 *1079 * *pcModules receives the # of items in the array (not the1080 * array size!). Use doshFreeImportedModules to clean up.1081 *1082 * This returns a standard OS/2 error code, which might be1083 * any of the codes returned by DosSetFilePtr and DosRead.1084 * In addition, this may return:1085 *1086 * -- ERROR_NOT_ENOUGH_MEMORY1087 *1088 * -- ERROR_INVALID_EXE_SIGNATURE: exe is in a format other1089 * than LX or NE, which is not understood by this function.1090 *1091 * Even if NO_ERROR is returned, the array pointer might still1092 * be NULL if the module contains no such data.1093 *1094 *@@added V0.9.9 (2001-03-11) [lafaix]1095 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET1096 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code1097 *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support1098 *@@changed V0.9.10 (2001-04-13) [lafaix]: removed 127 characters limit1099 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support1100 */1101 1102 APIRET doshExecQueryImportedModules(PEXECUTABLE pExec,1103 PFSYSMODULE *ppaModules, // out: modules array1104 PULONG pcModules) // out: array item count1105 {1106 if ( (pExec)1107 && ( (pExec->ulOS == EXEOS_OS2)1108 || (pExec->ulOS == EXEOS_WIN16)1109 || (pExec->ulOS == EXEOS_WIN386)1110 )1111 )1112 {1113 ENSURE_BEGIN;1114 ULONG cModules = 0;1115 PFSYSMODULE paModules = NULL;1116 int i;1117 HFILE hfExe = pExec->pFile->hf;1118 1119 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]1120 1121 if (pExec->pDosExeHeader)1122 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]1123 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;1124 1125 if (pExec->ulExeFormat == EXEFORMAT_LX)1126 {1127 // 32-bit OS/2 executable:1128 cModules = pExec->pLXHeader->ulImportModTblCnt;1129 1130 if (cModules)1131 {1132 ULONG cb = sizeof(FSYSMODULE) * cModules; // V0.9.9 (2001-04-03) [umoeller]1133 ULONG ulDummy;1134 1135 paModules = (PFSYSMODULE)malloc(cb);1136 if (!paModules)1137 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY); // V0.9.9 (2001-04-03) [umoeller]1138 1139 memset(paModules, 0, cb); // V0.9.9 (2001-04-03) [umoeller]1140 1141 ENSURE_SAFE(DosSetFilePtr(hfExe,1142 pExec->pLXHeader->ulImportModTblOfs1143 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]1144 FILE_BEGIN,1145 &ulDummy));1146 1147 for (i = 0; i < cModules; i++)1148 {1149 BYTE bLen = 0;1150 1151 // reading the length of the module name1152 ENSURE_SAFE(DosRead(hfExe, &bLen, 1, &ulDummy));1153 1154 // reading the module name1155 ENSURE_SAFE(DosRead(hfExe,1156 paModules[i].achModuleName,1157 bLen,1158 &ulDummy));1159 1160 // module names are not null terminated, so we must1161 // do it now1162 paModules[i].achModuleName[bLen] = 0;1163 } // end for1164 }1165 } // end LX1166 else if (pExec->ulExeFormat == EXEFORMAT_NE)1167 {1168 // 16-bit executable:1169 cModules = pExec->pNEHeader->usModuleTblEntries;1170 1171 if (cModules)1172 {1173 ULONG cb = sizeof(FSYSMODULE) * cModules;1174 1175 paModules = (PFSYSMODULE)malloc(cb);1176 if (!paModules)1177 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY); // V0.9.9 (2001-04-03) [umoeller]1178 1179 memset(paModules, 0, cb); // V0.9.9 (2001-04-03) [umoeller]1180 1181 for (i = 0; i < cModules; i ++)1182 {1183 BYTE bLen;1184 USHORT usOfs;1185 ULONG ulDummy;1186 1187 // the module reference table contains offsets1188 // relative to the import table; we hence read1189 // the offset in the module reference table, and1190 // then we read the name in the import table1191 1192 ENSURE_SAFE(DosSetFilePtr(hfExe,1193 pExec->pNEHeader->usModRefTblOfs1194 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]1195 + sizeof(usOfs) * i,1196 FILE_BEGIN,1197 &ulDummy));1198 1199 ENSURE_SAFE(DosRead(hfExe, &usOfs, 2, &ulDummy));1200 1201 ENSURE_SAFE(DosSetFilePtr(hfExe,1202 pExec->pNEHeader->usImportTblOfs1203 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]1204 + usOfs,1205 FILE_BEGIN,1206 &ulDummy));1207 1208 ENSURE_SAFE(DosRead(hfExe, &bLen, 1, &ulDummy));1209 1210 ENSURE_SAFE(DosRead(hfExe,1211 paModules[i].achModuleName,1212 bLen,1213 &ulDummy));1214 1215 paModules[i].achModuleName[bLen] = 0;1216 } // end for1217 }1218 } // end NE1219 else1220 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]1221 1222 // no error: output data1223 *ppaModules = paModules;1224 *pcModules = cModules;1225 1226 ENSURE_FINALLY;1227 // if we had an error above, clean up1228 free(paModules);1229 ENSURE_END;1230 }1231 else1232 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]1233 1234 ENSURE_OK;1235 }1236 1237 /*1238 *@@ doshExecFreeImportedModules:1239 * frees resources allocated by doshExecQueryImportedModules.1240 *1241 *@@added V0.9.9 (2001-03-11)1242 */1243 1244 APIRET doshExecFreeImportedModules(PFSYSMODULE paModules)1245 {1246 free(paModules);1247 return (NO_ERROR);1248 }1249 1250 /*1251 *@@ ScanLXEntryTable:1252 * returns the number of exported entries in the entry table.1253 *1254 * If paFunctions is not NULL, then successive entries are1255 * filled with the found type and ordinal values.1256 *1257 *@@added V0.9.9 (2001-03-30) [lafaix]1258 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET1259 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code1260 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support1261 */1262 1263 APIRET ScanLXEntryTable(PEXECUTABLE pExec,1264 PFSYSFUNCTION paFunctions,1265 PULONG pcEntries) // out: entry table entry count; ptr can be NULL1266 {1267 ULONG ulDummy;1268 USHORT usOrdinal = 1,1269 usCurrent = 0;1270 int i;1271 1272 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]1273 HFILE hfExe = pExec->pFile->hf;1274 1275 if (pExec->pDosExeHeader)1276 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]1277 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;1278 1279 ENSURE(DosSetFilePtr(hfExe,1280 pExec->pLXHeader->ulEntryTblOfs1281 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]1282 FILE_BEGIN,1283 &ulDummy));1284 1285 while (TRUE)1286 {1287 BYTE bCnt,1288 bType,1289 bFlag;1290 1291 ENSURE(DosRead(hfExe, &bCnt, 1, &ulDummy));1292 1293 if (bCnt == 0)1294 // end of the entry table1295 break;1296 1297 ENSURE(DosRead(hfExe, &bType, 1, &ulDummy));1298 1299 switch (bType & 0x7F)1300 {1301 /*1302 * unused entries1303 *1304 */1305 1306 case 0:1307 usOrdinal += bCnt;1308 break;1309 1310 /*1311 * 16-bit entries1312 *1313 * the bundle type is followed by the object number1314 * and by bCnt bFlag+usOffset entries1315 *1316 */1317 1318 case 1:1319 ENSURE(DosSetFilePtr(hfExe,1320 sizeof(USHORT),1321 FILE_CURRENT,1322 &ulDummy));1323 1324 for (i = 0; i < bCnt; i ++)1325 {1326 ENSURE(DosRead(hfExe, &bFlag, 1, &ulDummy));1327 1328 if (bFlag & 0x01)1329 {1330 if (paFunctions)1331 {1332 paFunctions[usCurrent].ulOrdinal = usOrdinal;1333 paFunctions[usCurrent].ulType = 1;1334 paFunctions[usCurrent].achFunctionName[0] = 0;1335 }1336 usCurrent++;1337 }1338 1339 usOrdinal++;1340 1341 ENSURE(DosSetFilePtr(hfExe,1342 sizeof(USHORT),1343 FILE_CURRENT,1344 &ulDummy));1345 1346 } // end for1347 break;1348 1349 /*1350 * 286 call gate entries1351 *1352 * the bundle type is followed by the object number1353 * and by bCnt bFlag+usOffset+usCallGate entries1354 *1355 */1356 1357 case 2:1358 ENSURE(DosSetFilePtr(hfExe,1359 sizeof(USHORT),1360 FILE_CURRENT,1361 &ulDummy));1362 1363 for (i = 0; i < bCnt; i ++)1364 {1365 ENSURE(DosRead(hfExe, &bFlag, 1, &ulDummy));1366 1367 if (bFlag & 0x01)1368 {1369 if (paFunctions)1370 {1371 paFunctions[usCurrent].ulOrdinal = usOrdinal;1372 paFunctions[usCurrent].ulType = 2;1373 paFunctions[usCurrent].achFunctionName[0] = 0;1374 }1375 usCurrent++;1376 }1377 1378 usOrdinal++;1379 1380 ENSURE(DosSetFilePtr(hfExe,1381 sizeof(USHORT) + sizeof(USHORT),1382 FILE_CURRENT,1383 &ulDummy));1384 1385 } // end for1386 break;1387 1388 /*1389 * 32-bit entries1390 *1391 * the bundle type is followed by the object number1392 * and by bCnt bFlag+ulOffset entries1393 *1394 */1395 1396 case 3:1397 ENSURE(DosSetFilePtr(hfExe,1398 sizeof(USHORT),1399 FILE_CURRENT,1400 &ulDummy));1401 1402 for (i = 0; i < bCnt; i ++)1403 {1404 ENSURE(DosRead(hfExe, &bFlag, 1, &ulDummy));1405 1406 if (bFlag & 0x01)1407 {1408 if (paFunctions)1409 {1410 paFunctions[usCurrent].ulOrdinal = usOrdinal;1411 paFunctions[usCurrent].ulType = 3;1412 paFunctions[usCurrent].achFunctionName[0] = 0;1413 }1414 usCurrent++;1415 }1416 1417 usOrdinal++;1418 1419 ENSURE(DosSetFilePtr(hfExe,1420 sizeof(ULONG),1421 FILE_CURRENT,1422 &ulDummy));1423 } // end for1424 break;1425 1426 /*1427 * forwarder entries1428 *1429 * the bundle type is followed by a reserved word1430 * and by bCnt bFlag+usModOrd+ulOffsOrdNum entries1431 *1432 */1433 1434 case 4:1435 ENSURE(DosSetFilePtr(hfExe,1436 sizeof(USHORT),1437 FILE_CURRENT,1438 &ulDummy));1439 1440 for (i = 0; i < bCnt; i ++)1441 {1442 ENSURE(DosSetFilePtr(hfExe,1443 sizeof(BYTE) + sizeof(USHORT) + sizeof(ULONG),1444 FILE_CURRENT,1445 &ulDummy));1446 1447 if (paFunctions)1448 {1449 paFunctions[usCurrent].ulOrdinal = usOrdinal;1450 paFunctions[usCurrent].ulType = 4;1451 paFunctions[usCurrent].achFunctionName[0] = 0;1452 }1453 usCurrent++;1454 1455 usOrdinal++;1456 } // end for1457 break;1458 1459 /*1460 * unknown bundle type1461 *1462 * we don't know how to handle this bundle, so we must1463 * stop parsing the entry table here (as we don't know the1464 * bundle size); if paFunctions is not null, we fill it with1465 * informative data1466 */1467 1468 default:1469 if (paFunctions)1470 {1471 paFunctions[usCurrent].ulOrdinal = usOrdinal;1472 paFunctions[usCurrent].ulType = bType;1473 sprintf(paFunctions[usCurrent].achFunctionName,1474 "Unknown bundle type encountered (%d). Aborting entry table scan.",1475 bType);1476 1477 usCurrent++;1478 }1479 ENSURE_FAIL(ERROR_INVALID_LIST_FORMAT);1480 // whatever1481 // V0.9.9 (2001-04-03) [umoeller]1482 } // end switch (bType & 0x7F)1483 } // end while (TRUE)1484 1485 if (pcEntries)1486 *pcEntries = usCurrent;1487 1488 ENSURE_OK;1489 }1490 1491 /*1492 *@@ ScanNEEntryTable:1493 * returns the number of exported entries in the entry table.1494 *1495 * if paFunctions is not NULL, then successive entries are1496 * filled with the found type and ordinal values.1497 *1498 *@@added V0.9.9 (2001-03-30) [lafaix]1499 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET1500 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code1501 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support1502 */1503 1504 APIRET ScanNEEntryTable(PEXECUTABLE pExec,1505 PFSYSFUNCTION paFunctions,1506 PULONG pcEntries) // out: entry table entry count; ptr can be NULL1507 {1508 ULONG ulDummy;1509 USHORT usOrdinal = 1,1510 usCurrent = 0;1511 int i;1512 1513 ULONG ulNewHeaderOfs = 0;1514 HFILE hfExe = pExec->pFile->hf;1515 1516 if (pExec->pDosExeHeader)1517 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]1518 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;1519 1520 ENSURE(DosSetFilePtr(hfExe,1521 pExec->pNEHeader->usEntryTblOfs1522 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]1523 FILE_BEGIN,1524 &ulDummy));1525 1526 while (TRUE)1527 {1528 BYTE bCnt,1529 bType,1530 bFlag;1531 1532 ENSURE(DosRead(hfExe, &bCnt, 1, &ulDummy));1533 1534 if (bCnt == 0)1535 // end of the entry table1536 break;1537 1538 ENSURE(DosRead(hfExe, &bType, 1, &ulDummy));1539 1540 if (bType)1541 {1542 for (i = 0; i < bCnt; i++)1543 {1544 ENSURE(DosRead(hfExe,1545 &bFlag,1546 1,1547 &ulDummy));1548 1549 if (bFlag & 0x01)1550 {1551 if (paFunctions)1552 {1553 paFunctions[usCurrent].ulOrdinal = usOrdinal;1554 paFunctions[usCurrent].ulType = 1; // 16-bit entry1555 paFunctions[usCurrent].achFunctionName[0] = 0;1556 }1557 usCurrent++;1558 }1559 1560 usOrdinal++;1561 1562 if (bType == 0xFF)1563 {1564 // moveable segment1565 ENSURE(DosSetFilePtr(hfExe,1566 5,1567 FILE_CURRENT,1568 &ulDummy));1569 }1570 else1571 {1572 // fixed segment or constant (0xFE)1573 ENSURE(DosSetFilePtr(hfExe,1574 2,1575 FILE_CURRENT,1576 &ulDummy));1577 }1578 1579 } // end for1580 }1581 else1582 usOrdinal += bCnt;1583 } // end while (TRUE)1584 1585 if (pcEntries)1586 *pcEntries = usCurrent;1587 1588 ENSURE_OK;1589 }1590 1591 /*1592 *@@ Compare:1593 * binary search helper1594 *1595 *@@added V0.9.9 (2001-04-01) [lafaix]1596 *@@changed V0.9.9 (2001-04-07) [umoeller]: added _Optlink, or this won't compile as C++1597 */1598 1599 int _Optlink Compare(const void *key,1600 const void *element)1601 {1602 USHORT usOrdinal = *((PUSHORT) key);1603 PFSYSFUNCTION pFunction = (PFSYSFUNCTION)element;1604 1605 if (usOrdinal > pFunction->ulOrdinal)1606 return (1);1607 else if (usOrdinal < pFunction->ulOrdinal)1608 return (-1);1609 else1610 return (0);1611 }1612 1613 /*1614 *@@ ScanNameTable:1615 * scans a resident or non-resident name table, and fills the1616 * appropriate paFunctions entries when it encounters exported1617 * entries names.1618 *1619 * This functions works for both NE and LX executables.1620 *1621 *@@added V0.9.9 (2001-03-30) [lafaix]1622 *@@changed V0.9.9 (2001-04-02) [lafaix]: the first entry is special1623 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET1624 *@@changed V0.9.9 (2001-04-05) [lafaix]: removed the 127 char limit1625 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code1626 */1627 1628 APIRET ScanNameTable(PEXECUTABLE pExec,1629 ULONG cFunctions,1630 PFSYSFUNCTION paFunctions)1631 {1632 ULONG ulDummy;1633 1634 USHORT usOrdinal;1635 PFSYSFUNCTION pFunction;1636 HFILE hfExe = pExec->pFile->hf;1637 1638 while (TRUE)1639 {1640 BYTE bLen;1641 CHAR achName[256];1642 // int i;1643 1644 ENSURE(DosRead(hfExe, &bLen, 1, &ulDummy));1645 1646 if (bLen == 0)1647 // end of the name table1648 break;1649 1650 ENSURE(DosRead(hfExe, &achName, bLen, &ulDummy));1651 achName[bLen] = 0;1652 1653 ENSURE(DosRead(hfExe, &usOrdinal, sizeof(USHORT), &ulDummy));1654 1655 if ((pFunction = (PFSYSFUNCTION)bsearch(&usOrdinal,1656 paFunctions,1657 cFunctions,1658 sizeof(FSYSFUNCTION),1659 Compare)))1660 {1661 memcpy(pFunction->achFunctionName,1662 achName,1663 bLen+1);1664 }1665 }1666 1667 ENSURE_OK;1668 }1669 1670 /*1671 *@@ doshExecQueryExportedFunctions:1672 * returns an array of FSYSFUNCTION structure describing all1673 * exported functions.1674 *1675 * *pcFunctions receives the # of items in the array (not the1676 * array size!). Use doshFreeExportedFunctions to clean up.1677 *1678 * Note that the returned array only contains entry for exported1679 * functions. Empty export entries are _not_ included.1680 *1681 * This returns a standard OS/2 error code, which might be1682 * any of the codes returned by DosSetFilePtr and DosRead.1683 * In addition, this may return:1684 *1685 * -- ERROR_NOT_ENOUGH_MEMORY1686 *1687 * -- ERROR_INVALID_EXE_SIGNATURE: exe is in a format other1688 * than LX or NE, which is not understood by this function.1689 *1690 * -- If ERROR_INVALID_LIST_FORMAT is returned, the format of an1691 * export entry wasn't understood here.1692 *1693 * Even if NO_ERROR is returned, the array pointer might still1694 * be NULL if the module contains no such data.1695 *1696 *@@added V0.9.9 (2001-03-11) [lafaix]1697 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET1698 *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code1699 *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support1700 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support1701 */1702 1703 APIRET doshExecQueryExportedFunctions(PEXECUTABLE pExec,1704 PFSYSFUNCTION *ppaFunctions, // out: functions array1705 PULONG pcFunctions) // out: array item count1706 {1707 if ( (pExec)1708 && ( (pExec->ulOS == EXEOS_OS2)1709 || (pExec->ulOS == EXEOS_WIN16)1710 || (pExec->ulOS == EXEOS_WIN386)1711 )1712 )1713 {1714 ENSURE_BEGIN;1715 ULONG cFunctions = 0;1716 PFSYSFUNCTION paFunctions = NULL;1717 1718 ULONG ulDummy;1719 1720 HFILE hfExe = pExec->pFile->hf;1721 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]1722 1723 if (pExec->pDosExeHeader)1724 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]1725 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;1726 1727 if (pExec->ulExeFormat == EXEFORMAT_LX)1728 {1729 // It's a 32bit OS/2 executable1730 1731 // the number of exported entry points is not stored1732 // in the executable header; we have to count them in1733 // the entry table1734 1735 ENSURE(ScanLXEntryTable(pExec, NULL, &cFunctions));1736 1737 // we now have the number of exported entries; let us1738 // build them1739 1740 if (cFunctions)1741 {1742 ULONG cb = sizeof(FSYSFUNCTION) * cFunctions;1743 1744 paFunctions = (PFSYSFUNCTION)malloc(cb);1745 if (!paFunctions)1746 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);1747 1748 // we rescan the entry table (the cost is not as bad1749 // as it may seem, due to disk caching)1750 1751 ENSURE_SAFE(ScanLXEntryTable(pExec, paFunctions, NULL));1752 1753 // we now scan the resident name table entries1754 1755 ENSURE_SAFE(DosSetFilePtr(hfExe,1756 pExec->pLXHeader->ulResdNameTblOfs1757 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]1758 FILE_BEGIN,1759 &ulDummy));1760 1761 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));1762 1763 // we now scan the non-resident name table entries,1764 // whose offset is _from the begining of the file_1765 1766 ENSURE_SAFE(DosSetFilePtr(hfExe,1767 pExec->pLXHeader->ulNonResdNameTblOfs,1768 FILE_BEGIN,1769 &ulDummy));1770 1771 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));1772 } // end if (cFunctions)1773 }1774 else if (pExec->ulExeFormat == EXEFORMAT_NE)1775 {1776 // it's a "new" segmented 16bit executable1777 1778 // here too the number of exported entry points1779 // is not stored in the executable header; we1780 // have to count them in the entry table1781 1782 ENSURE(ScanNEEntryTable(pExec, NULL, &cFunctions));1783 1784 // we now have the number of exported entries; let us1785 // build them1786 1787 if (cFunctions)1788 {1789 // USHORT usOrdinal = 1;1790 // usCurrent = 0;1791 1792 paFunctions = (PFSYSFUNCTION)malloc(sizeof(FSYSFUNCTION) * cFunctions);1793 if (!paFunctions)1794 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);1795 1796 // we rescan the entry table (the cost is not as bad1797 // as it may seem, due to disk caching)1798 1799 ENSURE_SAFE(ScanNEEntryTable(pExec, paFunctions, NULL));1800 1801 // we now scan the resident name table entries1802 1803 ENSURE_SAFE(DosSetFilePtr(hfExe,1804 pExec->pNEHeader->usResdNameTblOfs1805 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]1806 FILE_BEGIN,1807 &ulDummy));1808 1809 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));1810 1811 // we now scan the non-resident name table entries,1812 // whose offset is _from the begining of the file_1813 1814 ENSURE_SAFE(DosSetFilePtr(hfExe,1815 pExec->pNEHeader->ulNonResdTblOfs,1816 FILE_BEGIN,1817 &ulDummy));1818 1819 ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));1820 }1821 }1822 else1823 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]1824 1825 // no error: output data1826 *ppaFunctions = paFunctions;1827 *pcFunctions = cFunctions;1828 1829 ENSURE_FINALLY;1830 // if we had an error above, clean up1831 free(paFunctions);1832 ENSURE_END;1833 }1834 else1835 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]1836 1837 ENSURE_OK;1838 }1839 1840 /*1841 *@@ doshExecFreeExportedFunctions:1842 * frees resources allocated by doshExecQueryExportedFunctions.1843 *1844 *@@added V0.9.9 (2001-03-11)1845 */1846 1847 APIRET doshExecFreeExportedFunctions(PFSYSFUNCTION paFunctions)1848 {1849 free(paFunctions);1850 1851 return (NO_ERROR);1852 }1853 1854 /*1855 *@@ doshExecQueryResources:1856 * returns an array of FSYSRESOURCE structures describing all1857 * available resources in the module.1858 *1859 * *pcResources receives the no. of items in the array1860 * (not the array size!). Use doshExecFreeResources to clean up.1861 *1862 * This returns a standard OS/2 error code, which might be1863 * any of the codes returned by DosSetFilePtr and DosRead.1864 * In addition, this may return:1865 *1866 * -- ERROR_NOT_ENOUGH_MEMORY1867 *1868 * -- ERROR_INVALID_EXE_SIGNATURE: exe is in a format other1869 * than LX or NE, which is not understood by this function.1870 *1871 * Even if NO_ERROR is returned, the array pointer might still1872 * be NULL if the module contains no such data.1873 *1874 *@@added V0.9.7 (2000-12-18) [lafaix]1875 *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET1876 *@@changed V0.9.10 (2001-04-10) [lafaix]: added Win16 and Win386 support1877 *@@changed V0.9.12 (2001-05-03) [umoeller]: adjusted for new NOSTUB support1878 */1879 1880 APIRET doshExecQueryResources(PEXECUTABLE pExec, // in: executable from doshExecOpen1881 PFSYSRESOURCE *ppaResources, // out: res's array1882 PULONG pcResources) // out: array item count1883 {1884 if ( (pExec)1885 && ( (pExec->ulOS == EXEOS_OS2)1886 || (pExec->ulOS == EXEOS_WIN16)1887 || (pExec->ulOS == EXEOS_WIN386)1888 )1889 )1890 {1891 ENSURE_BEGIN;1892 ULONG cResources = 0;1893 PFSYSRESOURCE paResources = NULL;1894 1895 HFILE hfExe = pExec->pFile->hf;1896 ULONG ulNewHeaderOfs = 0; // V0.9.12 (2001-05-03) [umoeller]1897 1898 if (pExec->pDosExeHeader)1899 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]1900 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;1901 1902 if (pExec->ulExeFormat == EXEFORMAT_LX)1903 {1904 // 32-bit OS/2 executable:1905 PLXHEADER pLXHeader = pExec->pLXHeader;1906 if (cResources = pLXHeader->ulResTblCnt)1907 {1908 #pragma pack(1) // V0.9.9 (2001-04-02) [umoeller]1909 struct rsrc32 // Resource Table Entry1910 {1911 unsigned short type; // Resource type1912 unsigned short name; // Resource name1913 unsigned long cb; // Resource size1914 unsigned short obj; // Object number1915 unsigned long offset; // Offset within object1916 } rs;1917 1918 struct o32_obj // Flat .EXE object table entry1919 {1920 unsigned long o32_size; // Object virtual size1921 unsigned long o32_base; // Object base virtual address1922 unsigned long o32_flags; // Attribute flags1923 unsigned long o32_pagemap; // Object page map index1924 unsigned long o32_mapsize; // Number of entries in object page map1925 unsigned long o32_reserved; // Reserved1926 } ot;1927 #pragma pack() // V0.9.9 (2001-04-03) [umoeller]1928 1929 ULONG cb = sizeof(FSYSRESOURCE) * cResources;1930 ULONG ulDummy;1931 int i;1932 ULONG ulCurOfs;1933 1934 paResources = (PFSYSRESOURCE)malloc(cb);1935 if (!paResources)1936 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);1937 1938 memset(paResources, 0, cb); // V0.9.9 (2001-04-03) [umoeller]1939 1940 ENSURE_SAFE(DosSetFilePtr(hfExe,1941 pLXHeader->ulResTblOfs1942 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]1943 FILE_BEGIN,1944 &ulDummy));1945 1946 for (i = 0; i < cResources; i++)1947 {1948 ENSURE_SAFE(DosRead(hfExe, &rs, 14, &ulDummy));1949 1950 paResources[i].ulID = rs.name;1951 paResources[i].ulType = rs.type;1952 paResources[i].ulSize = rs.cb;1953 paResources[i].ulFlag = rs.obj; // Temp storage for Object1954 // number. Will be filled1955 // with resource flag1956 // later.1957 }1958 1959 for (i = 0; i < cResources; i++)1960 {1961 ULONG ulOfsThis = pLXHeader->ulObjTblOfs1962 + ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]1963 + ( sizeof(ot)1964 * (paResources[i].ulFlag - 1));1965 1966 ENSURE_SAFE(DosSetFilePtr(hfExe,1967 ulOfsThis,1968 FILE_BEGIN,1969 &ulDummy));1970 1971 ENSURE_SAFE(DosRead(hfExe, &ot, sizeof(ot), &ulDummy));1972 1973 paResources[i].ulFlag = ((ot.o32_flags & OBJWRITE)1974 ? 01975 : RNPURE);1976 paResources[i].ulFlag |= ((ot.o32_flags & OBJDISCARD)1977 ? 40961978 : 0);1979 paResources[i].ulFlag |= ((ot.o32_flags & OBJSHARED)1980 ? RNMOVE1981 : 0);1982 paResources[i].ulFlag |= ((ot.o32_flags & OBJPRELOAD)1983 ? RNPRELOAD1984 : 0);1985 } // end for1986 } // end if (cResources)1987 } // end if (pExec->ulExeFormat == EXEFORMAT_LX)1988 else if (pExec->ulExeFormat == EXEFORMAT_NE)1989 {1990 PNEHEADER pNEHeader = pExec->pNEHeader;1991 1992 if (pExec->ulOS == EXEOS_OS2)1993 {1994 // 16-bit OS/2 executable:1995 cResources = pNEHeader->usResSegmCount;1996 1997 if (cResources)1998 {1999 #pragma pack(1) // V0.9.9 (2001-04-02) [umoeller]2000 struct {unsigned short type; unsigned short name;} rti;2001 struct new_seg // New .EXE segment table entry2002 {2003 unsigned short ns_sector; // File sector of start of segment2004 unsigned short ns_cbseg; // Number of bytes in file2005 unsigned short ns_flags; // Attribute flags2006 unsigned short ns_minalloc; // Minimum allocation in bytes2007 } ns;2008 #pragma pack()2009 2010 ULONG cb = sizeof(FSYSRESOURCE) * cResources;2011 ULONG ulDummy;2012 int i;2013 2014 paResources = (PFSYSRESOURCE)malloc(cb);2015 if (!paResources)2016 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);2017 2018 memset(paResources, 0, cb); // V0.9.9 (2001-04-03) [umoeller]2019 2020 // we first read the resources IDs and types2021 2022 ENSURE_SAFE(DosSetFilePtr(hfExe,2023 pNEHeader->usResTblOfs2024 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]2025 FILE_BEGIN,2026 &ulDummy));2027 2028 for (i = 0; i < cResources; i++)2029 {2030 ENSURE_SAFE(DosRead(hfExe, &rti, sizeof(rti), &ulDummy));2031 2032 paResources[i].ulID = rti.name;2033 paResources[i].ulType = rti.type;2034 }2035 2036 // we then read their sizes and flags2037 2038 for (i = 0; i < cResources; i++)2039 {2040 ENSURE_SAFE(DosSetFilePtr(hfExe,2041 ulNewHeaderOfs // V0.9.12 (2001-05-03) [umoeller]2042 + pNEHeader->usSegTblOfs2043 + (sizeof(ns)2044 * ( pNEHeader->usSegTblEntries2045 - pNEHeader->usResSegmCount2046 + i)),2047 FILE_BEGIN,2048 &ulDummy));2049 2050 ENSURE_SAFE(DosRead(hfExe, &ns, sizeof(ns), &ulDummy));2051 2052 paResources[i].ulSize = ns.ns_cbseg;2053 2054 paResources[i].ulFlag = (ns.ns_flags & OBJPRELOAD) ? RNPRELOAD : 0;2055 paResources[i].ulFlag |= (ns.ns_flags & OBJSHARED) ? RNPURE : 0;2056 paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? RNMOVE : 0;2057 paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? 4096 : 0;2058 }2059 } // end if (cResources)2060 }2061 else2062 {2063 // 16-bit Windows executable2064 USHORT usAlignShift;2065 ULONG ulDummy;2066 2067 ENSURE(DosSetFilePtr(hfExe,2068 pNEHeader->usResTblOfs2069 + ulNewHeaderOfs, // V0.9.12 (2001-05-03) [umoeller]2070 FILE_BEGIN,2071 &ulDummy));2072 2073 ENSURE(DosRead(hfExe,2074 &usAlignShift,2075 sizeof(usAlignShift),2076 &ulDummy));2077 2078 while (TRUE)2079 {2080 USHORT usTypeID;2081 USHORT usCount;2082 2083 ENSURE(DosRead(hfExe,2084 &usTypeID,2085 sizeof(usTypeID),2086 &ulDummy));2087 2088 if (usTypeID == 0)2089 break;2090 2091 ENSURE(DosRead(hfExe,2092 &usCount,2093 sizeof(usCount),2094 &ulDummy));2095 2096 ENSURE(DosSetFilePtr(hfExe,2097 sizeof(ULONG),2098 FILE_CURRENT,2099 &ulDummy));2100 2101 cResources += usCount;2102 2103 // first pass, skip NAMEINFO table2104 ENSURE(DosSetFilePtr(hfExe,2105 usCount*6*sizeof(USHORT),2106 FILE_CURRENT,2107 &ulDummy));2108 }2109 2110 if (cResources)2111 {2112 USHORT usCurrent = 0;2113 ULONG cb = sizeof(FSYSRESOURCE) * cResources;2114 2115 paResources = (PFSYSRESOURCE)malloc(cb);2116 if (!paResources)2117 ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);2118 2119 memset(paResources, 0, cb);2120 2121 ENSURE_SAFE(DosSetFilePtr(hfExe,2122 pNEHeader->usResTblOfs2123 + ulNewHeaderOfs,2124 FILE_BEGIN,2125 &ulDummy));2126 2127 ENSURE_SAFE(DosRead(hfExe,2128 &usAlignShift,2129 sizeof(usAlignShift),2130 &ulDummy));2131 2132 while (TRUE)2133 {2134 USHORT usTypeID;2135 USHORT usCount;2136 int i;2137 2138 ENSURE_SAFE(DosRead(hfExe,2139 &usTypeID,2140 sizeof(usTypeID),2141 &ulDummy));2142 2143 if (usTypeID == 0)2144 break;2145 2146 ENSURE_SAFE(DosRead(hfExe,2147 &usCount,2148 sizeof(usCount),2149 &ulDummy));2150 2151 ENSURE_SAFE(DosSetFilePtr(hfExe,2152 sizeof(ULONG),2153 FILE_CURRENT,2154 &ulDummy));2155 2156 // second pass, read NAMEINFO table2157 for (i = 0; i < usCount; i++)2158 {2159 USHORT usLength,2160 usFlags,2161 usID;2162 2163 ENSURE_SAFE(DosSetFilePtr(hfExe,2164 sizeof(USHORT),2165 FILE_CURRENT,2166 &ulDummy));2167 2168 ENSURE_SAFE(DosRead(hfExe,2169 &usLength,2170 sizeof(USHORT),2171 &ulDummy));2172 ENSURE_SAFE(DosRead(hfExe,2173 &usFlags,2174 sizeof(USHORT),2175 &ulDummy));2176 ENSURE_SAFE(DosRead(hfExe,2177 &usID,2178 sizeof(USHORT),2179 &ulDummy));2180 2181 ENSURE_SAFE(DosSetFilePtr(hfExe,2182 2*sizeof(USHORT),2183 FILE_CURRENT,2184 &ulDummy));2185 2186 // !!! strings ids and types not handled yet2187 // !!! 15th bit is used to denotes strings2188 // !!! offsets [lafaix]2189 paResources[usCurrent].ulType = usTypeID ^ 0x8000;2190 paResources[usCurrent].ulID = usID ^ 0x8000;2191 paResources[usCurrent].ulSize = usLength << usAlignShift;2192 paResources[usCurrent].ulFlag = usFlags & 0x70;2193 2194 usCurrent++;2195 }2196 }2197 }2198 }2199 } // end else if (pExec->ulExeFormat == EXEFORMAT_NE)2200 else2201 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]2202 2203 *ppaResources = paResources;2204 *pcResources = cResources;2205 2206 ENSURE_FINALLY;2207 // if we had an error above, clean up2208 free(paResources);2209 ENSURE_END;2210 }2211 else2212 ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]2213 2214 ENSURE_OK;2215 }2216 2217 /*2218 *@@ doshExecFreeResources:2219 * frees resources allocated by doshExecQueryResources.2220 *2221 *@@added V0.9.7 (2000-12-18) [lafaix]2222 */2223 2224 APIRET doshExecFreeResources(PFSYSRESOURCE paResources)2225 {2226 free(paResources);2227 return (NO_ERROR);2228 }2229 2230 /*2231 *@@ doshLoadLXMaps:2232 * loads the three main LX maps into the given2233 * EXECUTABLE structure.2234 *2235 * This loads:2236 *2237 * 1) the LX resource table;2238 *2239 * 2) the LX object table;2240 *2241 * 3) the LX object _page_ table (object map).2242 *2243 * Note that this is not automatically called2244 * by doshExecOpen to save time, since the LX2245 * maps are not needed for all the other exe2246 * functions.2247 *2248 * This returns:2249 *2250 * -- NO_ERROR: all three LX maps were loaded,2251 * and pExec->fLXMapsLoaded was set to TRUE.2252 *2253 * -- ERROR_INVALID_PARAMETER2254 *2255 * -- ERROR_INVALID_EXE_SIGNATURE: pExec does2256 * not specify an LX executable.2257 *2258 * -- ERROR_NO_DATA: at least one of the structs2259 * does not exist.2260 *2261 * -- ERROR_NOT_ENOUGH_MEMORY2262 *2263 * plus the error codes of doshReadAt.2264 *2265 * Call doshFreeLXMaps to clean up explicitly, but2266 * that func automatically gets called by doshExecClose.2267 *2268 *@@added V0.9.16 (2001-12-08) [umoeller]2269 */2270 2271 APIRET doshLoadLXMaps(PEXECUTABLE pExec)2272 {2273 APIRET arc;2274 2275 PLXHEADER pLXHeader;2276 2277 if (!pExec)2278 arc = ERROR_INVALID_PARAMETER;2279 else if (pExec->fLXMapsLoaded)2280 // already loaded:2281 arc = NO_ERROR;2282 else if ( (pExec->ulExeFormat != EXEFORMAT_LX)2283 || (!(pLXHeader = pExec->pLXHeader))2284 )2285 arc = ERROR_INVALID_EXE_SIGNATURE;2286 else2287 {2288 PXFILE pFile = pExec->pFile;2289 ULONG ulNewHeaderOfs = 0;2290 ULONG cb;2291 2292 if (pExec->pDosExeHeader)2293 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]2294 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;2295 2296 // resource table2297 if ( (!(arc = doshAllocArray(pLXHeader->ulResTblCnt,2298 sizeof(RESOURCETABLEENTRY),2299 (PBYTE*)&pExec->pRsTbl,2300 &cb)))2301 && (!(arc = doshReadAt(pFile,2302 pLXHeader->ulResTblOfs2303 + ulNewHeaderOfs,2304 &cb,2305 (PBYTE)pExec->pRsTbl)))2306 )2307 {2308 // object table2309 if ( (!(arc = doshAllocArray(pLXHeader->ulObjCount,2310 sizeof(OBJECTTABLEENTRY),2311 (PBYTE*)&pExec->pObjTbl,2312 &cb)))2313 && (!(arc = doshReadAt(pFile,2314 pLXHeader->ulObjTblOfs2315 + ulNewHeaderOfs,2316 &cb,2317 (PBYTE)pExec->pObjTbl)))2318 )2319 {2320 // object page table2321 if ( (!(arc = doshAllocArray(pLXHeader->ulPageCount,2322 sizeof(OBJECTPAGETABLEENTRY),2323 (PBYTE*)&pExec->pObjPageTbl,2324 &cb)))2325 && (!(arc = doshReadAt(pFile,2326 pLXHeader->ulObjPageTblOfs2327 + ulNewHeaderOfs,2328 &cb,2329 (PBYTE)pExec->pObjPageTbl)))2330 )2331 {2332 }2333 }2334 }2335 2336 if (!arc)2337 pExec->fLXMapsLoaded = TRUE;2338 else2339 doshFreeLXMaps(pExec);2340 }2341 2342 return (arc);2343 }2344 2345 /*2346 *@@ doshFreeLXMaps:2347 * frees only the LX maps allocated by doshLoadLXMaps.2348 * This gets called automatically by doshExecClose.2349 *2350 *@@added V0.9.16 (2001-12-08) [umoeller]2351 */2352 2353 VOID doshFreeLXMaps(PEXECUTABLE pExec)2354 {2355 FREE(pExec->pRsTbl);2356 FREE(pExec->pObjTbl);2357 FREE(pExec->pObjPageTbl);2358 pExec->fLXMapsLoaded = FALSE;2359 }2360 2361 /*2362 *@@ doshLoadOS2NEMaps:2363 *2364 * This works only if2365 *2366 * -- ulExeFormat == EXEFORMAT_NE and2367 *2368 * -- ulOS == EXEOS_OS2,2369 *2370 * but not with Win16 NE executables.2371 *2372 *@@added V0.9.16 (2001-12-08) [umoeller]2373 */2374 2375 APIRET doshLoadOS2NEMaps(PEXECUTABLE pExec)2376 {2377 APIRET arc;2378 2379 PNEHEADER pNEHeader;2380 2381 if (!pExec)2382 arc = ERROR_INVALID_PARAMETER;2383 else if (pExec->fOS2NEMapsLoaded)2384 // already loaded:2385 arc = NO_ERROR;2386 else if ( (pExec->ulExeFormat != EXEFORMAT_NE)2387 || (pExec->ulOS != EXEOS_OS2)2388 || (!(pNEHeader = pExec->pNEHeader))2389 )2390 arc = ERROR_INVALID_EXE_SIGNATURE;2391 else2392 {2393 PXFILE pFile = pExec->pFile;2394 ULONG ulNewHeaderOfs = 0;2395 ULONG cb;2396 2397 if (pExec->pDosExeHeader)2398 // executable has DOS stub: V0.9.12 (2001-05-03) [umoeller]2399 ulNewHeaderOfs = pExec->pDosExeHeader->ulNewHeaderOfs;2400 2401 // resource table2402 if ( (!(arc = doshAllocArray(pNEHeader->usResSegmCount,2403 sizeof(OS2NERESTBLENTRY),2404 (PBYTE*)&pExec->paOS2NEResTblEntry,2405 &cb)))2406 && (!(arc = doshReadAt(pFile,2407 pNEHeader->usResTblOfs2408 + ulNewHeaderOfs,2409 &cb,2410 (PBYTE)pExec->paOS2NEResTblEntry)))2411 )2412 {2413 // resource segments2414 if ( (!(arc = doshAllocArray(pNEHeader->usResSegmCount,2415 sizeof(OS2NESEGMENT),2416 (PBYTE*)&pExec->paOS2NESegments,2417 &cb)))2418 && (!(arc = doshReadAt(pFile,2419 pNEHeader->usResTblOfs2420 + ulNewHeaderOfs2421 - cb, // pNEHeader->usResSegmCount * sizeof(struct new_seg)2422 &cb,2423 (PBYTE)pExec->paOS2NESegments)))2424 )2425 {2426 }2427 }2428 2429 if (!arc)2430 pExec->fOS2NEMapsLoaded = TRUE;2431 else2432 doshFreeNEMaps(pExec);2433 }2434 2435 return (arc);2436 }2437 2438 /*2439 *@@ doshFreeNEMaps:2440 *2441 *@@added V0.9.16 (2001-12-08) [umoeller]2442 */2443 2444 VOID doshFreeNEMaps(PEXECUTABLE pExec)2445 {2446 FREE(pExec->paOS2NEResTblEntry);2447 FREE(pExec->paOS2NESegments);2448 pExec->fOS2NEMapsLoaded = FALSE;2449 }2450 2451 /*2452 *@@ doshExecClose:2453 * this closes an executable opened with doshExecOpen.2454 * Always call this function if NO_ERROR was returned by2455 * doshExecOpen.2456 *2457 * This automaticall calls doshFreeLXMaps.2458 *2459 *@@added V0.9.0 [umoeller]2460 *@@changed V0.9.16 (2001-12-08) [umoeller]: fixed memory leaks2461 *@@changed V0.9.16 (2001-12-08) [umoeller]: changed prototype to null the pExec ptr2462 */2463 2464 APIRET doshExecClose(PEXECUTABLE *ppExec)2465 {2466 APIRET arc = NO_ERROR;2467 PEXECUTABLE pExec;2468 if ( (ppExec)2469 && (pExec = *ppExec)2470 )2471 {2472 char **papsz[] =2473 {2474 (char**)&pExec->pDosExeHeader,2475 (char**)&pExec->pNEHeader,2476 (char**)&pExec->pLXHeader,2477 (char**)&pExec->pPEHeader,2478 2479 &pExec->pszDescription,2480 &pExec->pszVendor,2481 &pExec->pszVersion,2482 &pExec->pszInfo,2483 2484 &pExec->pszBuildDateTime,2485 &pExec->pszBuildMachine,2486 &pExec->pszASD,2487 &pExec->pszLanguage,2488 &pExec->pszCountry,2489 &pExec->pszRevision,2490 &pExec->pszUnknown,2491 &pExec->pszFixpak2492 };2493 ULONG ul;2494 2495 doshFreeLXMaps(pExec);2496 doshFreeNEMaps(pExec);2497 2498 // fixed the memory leaks with the missing fields,2499 // turned this into a loop2500 for (ul = 0;2501 ul < sizeof(papsz) / sizeof(papsz[0]);2502 ul++)2503 {2504 PSZ pThis;2505 if (pThis = *papsz[ul])2506 {2507 free(pThis);2508 pThis = NULL;2509 }2510 }2511 2512 doshClose(&pExec->pFile);2513 2514 free(pExec);2515 *ppExec = NULL;2516 }2517 else2518 arc = ERROR_INVALID_PARAMETER;2519 2520 return (arc);2521 352 } 2522 353
Note:
See TracChangeset
for help on using the changeset viewer.