' Lothar Pink %NO_ORDINAL = -1 FUNCTION GetProcAddressPE(libname AS STRING, procname AS ASCIIZ, BYVAL ordinal AS LONG) AS LONG ' this function is similar to GetProcAddress() but it also returns addresses to "hidden" win9x functions like "VxdCall" ' it may also return function addresses by ordinal; if you want to get a function by name, ' please pass %NO_ORDINAL for the "ordinal" parameter ' pe structure pointers LOCAL dosHeader AS IMAGE_DOS_HEADER PTR LOCAL ntHeaders AS IMAGE_NT_HEADERS PTR LOCAL eData AS IMAGE_EXPORT_DIRECTORY PTR ' handles, pointers, etc. LOCAL psFuncName AS ASCIIZ PTR LOCAL pwOrdinal AS WORD PTR LOCAL pDllName AS ASCIIZ PTR LOCAL paf AS DWORD PTR LOCAL pan AS DWORD PTR LOCAL pao AS WORD PTR LOCAL pBase AS LONG LOCAL lExportOffset AS LONG LOCAL lExportLen AS LONG LOCAL lFnDiff AS LONG LOCAL z AS LONG ' ret val LOCAL lRet AS LONG ' get base address pBase = LoadLibrary(BYCOPY libname) e& = GetLastError IF pBase = %NULL THEN MSGBOX "GetProcAddressAll(): LoadLibrary failed: " + FORMAT$(e&) EXIT FUNCTION END IF ' read dos header dosHeader = pBase ' verify dos header IF ISFALSE @dosHeader.e_magic = %IMAGE_DOS_SIGNATURE THEN MSGBOX "GetProcAddressAll(): Invalid DOS header." EXIT FUNCTION END IF ' read nt header ntHeaders = dosHeader + @dosHeader.e_lfanew ' get rva of export table lExportOffset = @ntHeaders.OptionalHeader.DataDirectory(0).VirtualAddress lExportLen = @ntHeaders.OptionalHeader.DataDirectory(0).nSize eData = pBase + lExportOffset pDllName = pBase + @eData.nName paf = pBase + @eData.AddressOfFunctions pan = pBase + @eData.AddressOfNames pao = pBase + @eData.AddressOfNameOrdinals lFnDiff = @eData.NumberOfFunctions - @eData.NumberOfNames ' unlike documented at msdn, this may differ, if there are functions without names / ordinals, for example on win9x' kernel32.dll. ' find function FOR z = 0 TO @eData.NumberOfFunctions - 1 ' func name psFuncName = pBase + @pan[z] IF ISFALSE ordinal = %NO_ORDINAL THEN ' we don't use the AddressOfNameOrdinals() array here, because there aren't ordinals without names. IF z + @eData.nBase = ordinal THEN lRet = pBase + @paf[z] EXIT FOR END IF ELSE IF @psFuncName = procname THEN lRet = pBase + @paf[z + lFnDiff] EXIT FOR END IF END IF NEXT z FUNCTION = lRet END FUNCTION