Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

enum exported functions without any helper dll's

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • enum exported functions without any helper dll's

    the code below is a quick port from c++, that works for me
    in my actual code. there are no dependencies to any helper
    dll's.

    The function EnumFunctions(fName, hw_cmb) enumerates all funnctions in the
    executable module fName and puts any found function in the
    combobox hw_cmb. if you want to compile, you must include
    win32api.inc

    Code:
    '#COMPILE DLL
    '#INCLUDE "win32api.inc"
    
    %IMAGE_DOS_SIGNATURE                    = &H5A4D      '// MZ
    %IMAGE_NT_SIGNATURE                     = &H00004550  '// PE00
    %IMAGE_SIZEOF_SHORT_NAME                = 8
    %IMAGE_SIZEOF_SECTION_HEADER            = 40
    
    UNION MISC
        PhysicalAddress                     AS DWORD
        VirtualSize                         AS DWORD
    END UNION
    
    TYPE IMAGE_SECTION_HEADER
        Name_(%IMAGE_SIZEOF_SHORT_NAME - 1) AS BYTE
        Misc                                AS MISC
        VirtualAddress                      AS DWORD
        SizeOfRawData                       AS DWORD
        PointerToRawData                    AS DWORD
        PointerToRelocations                AS DWORD
        PointerToLinenumbers                AS DWORD
        NumberOfRelocations                 AS WORD
        NumberOfLinenumbers                 AS WORD
        Characteristics                     AS DWORD
    END TYPE
    
    TYPE IMAGE_DATA_DIRECTORY
        VirtualAddress                      AS DWORD
        nSize                               AS DWORD
    END TYPE
    
    TYPE IMAGE_OPTIONAL_HEADER
        '
        ' Standard fields.
        '
        Magic                               AS WORD
        MajorLinkerVersion                  AS BYTE
        MinorLinkerVersion                  AS BYTE
        SizeOfCode                          AS DWORD
        SizeOfInitializedData               AS DWORD
        SizeOfUninitializedData             AS DWORD
        AddressOfEntryPoint                 AS DWORD
        BaseOfCode                          AS DWORD
        BaseOfData                          AS DWORD
    
        '
        ' NT additional fields.
        '
        ImageBase                           AS DWORD
        SectionAlignment                    AS DWORD
        FileAlignment                       AS DWORD
        MajorOperatingSystemVersion         AS WORD
        MinorOperatingSystemVersion         AS WORD
        MajorImageVersion                   AS WORD
        MinorImageVersion                   AS WORD
        MajorSubsystemVersion               AS WORD
        MinorSubsystemVersion               AS WORD
        Reserved1                           AS DWORD
        SizeOfImage                         AS DWORD
        SizeOfHeaders                       AS DWORD
        CheckSum                            AS DWORD
        Subsystem                           AS WORD
        DllCharacteristics                  AS WORD
        SizeOfStackReserve                  AS DWORD
        SizeOfStackCommit                   AS DWORD
        SizeOfHeapReserve                   AS DWORD
        SizeOfHeapCommit                    AS DWORD
        LoaderFlags                         AS DWORD
        NumberOfRvaAndSizes                 AS DWORD
        DataDirectory(%IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1) AS IMAGE_DATA_DIRECTORY
    END TYPE
    
    TYPE IMAGE_FILE_HEADER
        Machine                             AS WORD
        NumberOfSections                    AS WORD
        TimeDateStamp                       AS DWORD
        PointerToSymbolTable                AS DWORD
        NumberOfSymbols                     AS DWORD
        SizeOfOptionalHeader                AS WORD
        Characteristics                     AS WORD
    END TYPE
    
    TYPE IMAGE_NT_HEADERS
        Signature                           AS DWORD
        FileHeader                          AS IMAGE_FILE_HEADER
        OptionalHeader                      AS IMAGE_OPTIONAL_HEADER
    END TYPE
    
    TYPE IMAGE_EXPORT_DIRECTORY
        Characteristics                     AS DWORD
        TimeDateStamp                       AS DWORD
        MajorVersion                        AS WORD
        MinorVersion                        AS WORD
        nName                               AS DWORD
        nBase                               AS DWORD
        NumberOfFunctions                   AS DWORD
        NumberOfNames                       AS DWORD
        AddressOfFunctions                  AS DWORD
        AddressOfNames                      AS DWORD
        AddressOfNameOrdinals               AS DWORD
    END TYPE
    
    TYPE IMAGE_DOS_HEADER          ' DOS .EXE header
        e_magic                             AS WORD
        e_cblp                              AS WORD
        e_cp                                AS WORD
        e_crlc                              AS WORD
        e_cparhdr                           AS WORD
        e_minalloc                          AS WORD
        e_maxalloc                          AS WORD
        e_ss                                AS WORD
        e_sp                                AS WORD
        e_csum                              AS WORD
        e_ip                                AS WORD
        e_cs                                AS WORD
        e_lfarlc                            AS WORD
        e_ovno                              AS WORD
        e_res(3)                            AS WORD
        e_oemid                             AS WORD
        e_oeminfo                           AS WORD
        e_res2(9)                           AS WORD
        e_lfanew                            AS LONG
    END TYPE
    
    FUNCTION IMAGE_FIRST_SECTION(pNTHeader AS IMAGE_NT_HEADERS PTR ) AS DWORD
        FUNCTION =  pNTHeader + 24 + @pNTHeader.FileHeader.SizeOfOptionalHeader
    END FUNCTION
    
    FUNCTION GetEnclosingSectionHeader(BYVAL rva AS DWORD, pNTHeader AS IMAGE_NT_HEADERS PTR) AS DWORD
    
        DIM section AS IMAGE_SECTION_HEADER PTR
        DIM i       AS LONG
        section = IMAGE_FIRST_SECTION(BYVAL pNTHeader)
    
        FOR i=0 TO @pNTHeader.FileHeader.NumberOfSections
            ' Is the RVA within this section?
            IF ( (rva >= @section.VirtualAddress) AND (rva < (@section.VirtualAddress + @section.Misc.VirtualSize))) THEN
                FUNCTION = section
                EXIT FUNCTION
            END IF
            section = section + SIZEOF(@section)
        NEXT
    
    END FUNCTION
    
    FUNCTION DumpExportsSection(BYVAL pBase AS DWORD, BYVAL hw_cmb AS LONG, pNTHeader AS IMAGE_NT_HEADERS PTR) AS LONG
    
        DIM pExportDir      AS IMAGE_EXPORT_DIRECTORY PTR
        DIM pHeader         AS IMAGE_SECTION_HEADER PTR
        DIM delta           AS LONG
        DIM i               AS DWORD
        DIM pFunctions      AS DWORD PTR
        DIM pOrdinals       AS WORD PTR
        DIM pNames          AS DWORD PTR
        DIM exportsStartRVA AS DWORD
        DIM exportsEndRVA   AS DWORD
        DIM s               AS STRING
        DIM entryPointRVA   AS DWORD
        DIM j               AS DWORD
        DIM flag            AS LONG
        DIM pFunction       AS ASCIIZ * 256
        DIM sLen            AS LONG
        DIM cPos            AS LONG
    
        exportsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).VirtualAddress
        exportsEndRVA = exportsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).nSize
    
        pHeader = GetEnclosingSectionHeader( exportsStartRVA, BYVAL pNTHeader )
        IF pHeader = 0 THEN
            FUNCTION = 0
            EXIT FUNCTION
        END IF
    
        delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
        pExportDir  = pBASE + exportsStartRVA - delta
        pFunctions  = @pExportDir.AddressOfFunctions    - delta + pBase
        pOrdinals   = @pExportDir.AddressOfNameOrdinals - delta + pBase
        pNames      = @pExportDir.AddressOfNames        - delta + pBase
        FOR i = 0 TO @pExportDir.NumberOfFunctions - 1
            entryPointRVA   = @pFunctions[i]
            j               = 0
            flag            = 0
    
            IF entryPointRVA <> 0 THEN
    '        // See IF this FUNCTION has an associated NAME exported FOR it.
                FOR j=0 TO @pExportDir.NumberOfNames - 1
                    IF @pOrdinals[j] = i THEN
                        sLen = wsprintf(pFunction, "%s", BYVAL @pNames[j] - delta + pBase, BYVAL i + @pExportDir.nBase)
                        IF (UCASE$(LEFT$(pFunction, sLen)) <> "LIBMAIN") AND (UCASE$(LEFT$(pFunction, sLen)) <> "DLLMAIN") THEN
                            IF hw_cmb <> 0 THEN
                                cPos = SendMessage(hw_cmb, %CB_ADDSTRING, 0&, VARPTR(pFunction))
                            END IF
                        END IF
                        flag    =   1
                    END IF
                NEXT
    '            // Is it a forwarder?  IF so, the entry point RVA is inside the
    '            // .edata section, AND is an RVA TO the DllName.EntryPointName
                IF (entryPointRVA >= exportsStartRVA) AND (entryPointRVA <= exportsEndRVA) THEN
    '                printf("%s\[email protected]%u", entryPointRVA - delta + pBase, i + @pExportDir.nBase)
                    sLen = wsprintf(pFunction, "%s\[email protected]%05u", BYVAL entryPointRVA - delta + pBase, BYVAL i + @pExportDir.nBase)
                    s = s + LEFT$(pFunction, slen) + $CRLF
                    flag    =   1
                END IF
            END IF
        NEXT
        FUNCTION = 1
    
    END FUNCTION
    
    
    FUNCTION DumpExeFile(BYVAL hw_cmb AS LONG, dosHeader AS IMAGE_DOS_HEADER PTR ) AS LONG
    
        DIM pNTHeader   AS IMAGE_NT_HEADERS PTR
        DIM pBase       AS DWORD
    
        pBase       = dosHeader
        pNTHeader   = dosHeader + @dosHeader.e_lfanew
    
        IF ( IsBadReadPtr(pNTHeader, SIZEOF(pNTHeader)) OR  @pNTHeader.Signature <> %IMAGE_NT_SIGNATURE ) THEN
            FUNCTION = 0
            EXIT FUNCTION
        END IF
    
        FUNCTION = DumpExportsSection(pBase, hw_cmb, BYVAL pNTHeader)
    
    END FUNCTION
    
    FUNCTION EnumFunctions(fName AS ASCIIZ, BYVAL hw_cmb AS LONG) AS LONG
    
        DIM hFile           AS LONG
        DIM hFileMapping    AS LONG
        DIM lpFileBase      AS LONG
        DIM dosHeader       AS IMAGE_DOS_HEADER PTR
    
        DIM pResult         AS ASCIIZ * 5000
        DIM pFormat         AS LONG
    
        hFile = CreateFile(fName, %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0&, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0)
    
        IF hFile = %INVALID_HANDLE_VALUE THEN
            FUNCTION = 0
            EXIT FUNCTION
        END IF
    
        hFileMapping = CreateFileMapping(hFile, BYVAL 0&, %PAGE_READONLY, 0, 0, BYVAL 0&)
        IF hFileMapping = 0 THEN
            CALL CloseHandle(hFile)
            FUNCTION = 0
            EXIT FUNCTION
        END IF
    
        lpFileBase = MapViewOfFile(hFileMapping, %FILE_MAP_READ, 0, 0, 0)
        IF lpFileBase = 0 THEN
            CALL CloseHandle(hFileMapping)
            CALL CloseHandle(hFile)
            FUNCTION = 0
            EXIT FUNCTION
        END IF
    
    
        dosHeader = lpFileBase
        IF ( @dosHeader.e_magic = %IMAGE_DOS_SIGNATURE ) THEN
            FUNCTION = DumpExeFile(hw_cmb, BYVAL dosHeader)
        END IF
    
        CALL UnmapViewOfFile(lpFileBase)
        CALL CloseHandle(hFileMapping)
        CALL CloseHandle(hFile)
    
    END FUNCTION
    ------------------

  • #2
    Here is a practical application for Torsten's excellent code that I used to solve a problem. (This post is probably about 98% Torsten's code, 2% mine)
    Basically, I'd developed a program but couldn't figure out why it wasn't loading under Win9x (and there weren't any helpful error messages). Even a MSGBOX at PBMAIN wasn't showing. I correctly assumed it was because one of the DLLs or functions my program was importing wasn't available under Win9x, so I modified Torsten's code to search for the functions that a program imports, so as to tell me 1) if any DLLs are being imported that don't exist, and 2) if any functions from DLLs are being imported that don't exist. It told me that I was loading psapi.dll which wasn't available under Win9x, so I was then quickly able to correct the problem and move on - cheers Torsten

    Code:
    #COMPILE EXE 
    #INCLUDE "win32api.inc"
     
    GLOBAL hDlg                             AS LONG
    %IMAGE_ORDINAL_FLAG                     = &H80000000
     
    TYPE IMAGE_IMPORT_DESCRIPTOR
        OriginalFirstThunk                  AS DWORD
        TimeDateStamp                       AS DWORD
        ForwarderChain                      AS DWORD
        Name_                               AS DWORD
        FirstThunk                          AS DWORD
    END TYPE
     
    UNION u1    DWORD
        ForwarderString                     AS BYTE PTR
        pFunction                           AS DWORD PTR
        Ordinal                             AS DWORD
        AddressOfData                       AS DWORD
    END UNION
     
    TYPE IMAGE_THUNK_DATA
        u1                                  AS u1
    END TYPE
      
    FUNCTION PtrToString(inPtr AS BYTE PTR) AS STRING
        DIM i                               AS LONG
        DIM s                               AS STRING
        DO WHILE @inPtr[i] <> 0
            s = s + CHR$(@inPtr[i])
            INCR i
        LOOP
        FUNCTION = s
    END FUNCTION
     
    FUNCTION IMAGE_FIRST_SECTION(pNTHeader AS IMAGE_NT_HEADERS PTR ) AS DWORD
        FUNCTION =  pNTHeader + 24 + @pNTHeader.FileHeader.SizeOfOptionalHeader
    END FUNCTION
     
    FUNCTION GetEnclosingSectionHeader(BYVAL rva AS DWORD, pNTHeader AS IMAGE_NT_HEADERS PTR) AS DWORD
        DIM section                         AS IMAGE_SECTION_HEADER PTR
        DIM i                               AS LONG
        section = IMAGE_FIRST_SECTION(BYVAL pNTHeader)
        FOR i=0 TO @pNTHeader.FileHeader.NumberOfSections
            IF ( (rva >= @section.VirtualAddress) AND (rva < (@section.VirtualAddress + @section.Misc.VirtualSize))) THEN
                FUNCTION = section
                EXIT FUNCTION
            END IF
            section = section + SIZEOF(@section)
        NEXT
    END FUNCTION
    
    FUNCTION DumpImportsSection(BYVAL pBase AS DWORD, pNTHeader AS IMAGE_NT_HEADERS PTR) AS LONG
        DIM pHeader                         AS IMAGE_SECTION_HEADER PTR
        DIM pImportDesc                     AS IMAGE_IMPORT_DESCRIPTOR PTR
        DIM pThunk                          AS IMAGE_THUNK_DATA PTR
        DIM delta                           AS LONG
        DIM importsStartRVA                 AS DWORD
        DIM importsEndRVA                   AS DWORD
        DIM entryPointRVA                   AS DWORD
        DIM exportsStartRVA                 AS DWORD
        DIM exportsEndRVA                   AS DWORD
        DIM i                               AS DWORD
        DIM j                               AS DWORD
        DIM sFunctionName                   AS ASCIIZ * 512
        DIM sDll                            AS ASCIIZ * 512
        DIM hLib AS LONG, hProc AS LONG
        importsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).VirtualAddress
        importsEndRVA = importsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).nSize
        pHeader = GetEnclosingSectionHeader( importsStartRVA, BYVAL pNTHeader )
        IF pHeader = 0 THEN
            EXIT FUNCTION
        END IF
        delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
        pImportDesc = pBase + importsStartRVA - delta
        i = 0
        DO
            IF (@pImportDesc[i].TimeDateStamp = 0) AND (@pImportDesc[i].Name_= 0 ) THEN
                EXIT DO
            END IF
            sDll = PtrToString(BYVAL @pImportDesc[i].Name_ - delta + pBase)
            'STDOUT sDll
            IF hLib <> 0 THEN FreeLibrary hLib
            hLib = LoadLibrary(sDll)
            IF hLib = 0 THEN
                STDOUT "DLL missing: " & sDLL
            END IF
            j = 0
            pThunk = @pImportDesc[i].FirstThunk - delta + pBase
            exportsStartRVA = @pHeader.VirtualAddress
            exportsEndRVA= exportsStartRVA + @pHeader.SizeOfRawData
            IF (pThunk <= exportsStartRVA) OR (pThunk >= exportsEndRVA) THEN
                IF (@pImportDesc[i].OriginalFirstThunk = 0) THEN
                    EXIT FUNCTION
                END IF
                pThunk = @pImportDesc[i].OriginalFirstThunk
                IF (pThunk <= exportsStartRVA) OR (pThunk >= exportsEndRVA) THEN
                    EXIT FUNCTION
                END IF
                pThunk = pThunk - delta + pBase
            END IF
            DO
                IF (@pThunk[j].u1.AddressOfData = 0) THEN
                    EXIT DO
                END IF
                IF (@pThunk[j].u1.Ordinal AND %IMAGE_ORDINAL_FLAG) THEN
                    sFunctionName = "Ordinal #" + FORMAT$(@pThunk[j].u1.Ordinal AND &HFFFF??)
                    IF hLib <> 0 THEN
                        hProc = 0
                        hProc = GetProcAddress(hLib, BYVAL (@pThunk[j].u1.Ordinal AND &HFFFF??))
                        IF hProc = 0 THEN STDOUT " Missing " & sFunctionName
                    END IF
                ELSE
                    sFunctionName = PtrToString(BYVAL @pThunk[j].u1.AddressOfData - delta + pBase + 2)
                    IF hLib <> 0 THEN
                        hProc = 0
                        hProc = GetProcAddress(hLib, sFunctionName)
                        IF hProc = 0 THEN STDOUT " Missing " & sFunctionName
                    END IF
                END IF
                'STDOUT " - " & sFunctionName
                INCR j
            LOOP
            INCR i
        LOOP
    END FUNCTION
    
    FUNCTION DumpExeFile(dosHeader AS IMAGE_DOS_HEADER PTR ) AS LONG
        DIM pNTHeader                       AS IMAGE_NT_HEADERS PTR
        DIM pBase                           AS DWORD
        pBase       = dosHeader
        pNTHeader   = dosHeader + @dosHeader.e_lfanew
        IF ( IsBadReadPtr(pNTHeader, SIZEOF(pNTHeader)) OR  @pNTHeader.Signature <> %IMAGE_NT_SIGNATURE ) THEN
            STDOUT "Unhandled EXE type, or invalid .EXE"
            EXIT FUNCTION
        END IF
        CALL DumpImportsSection(pBase, BYVAL pNTHeader)
    
    END FUNCTION
    
    FUNCTION Dump(sFileToDump AS STRING) AS LONG
        DIM hFile                           AS LONG
        DIM hFileMapping                    AS LONG
        DIM lpFileBase                      AS LONG
        DIM dosHeader                       AS IMAGE_DOS_HEADER PTR
        DIM fName                           AS ASCIIZ * 512
        fName = sFileToDump
        hFile = CreateFile(fName, %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0&, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0)
        IF hFile = %INVALID_HANDLE_VALUE THEN
            STDOUT "Couldn't open file with CreateFile()"
            EXIT FUNCTION
        END IF
        hFileMapping = CreateFileMapping(hFile, BYVAL 0&, %PAGE_READONLY, 0, 0, BYVAL 0&)
        IF hFileMapping = 0 THEN
            CALL CloseHandle(hFile)
            STDOUT "Couldn't open file mapping with CreateFileMapping()"
            EXIT FUNCTION
        END IF
        lpFileBase = MapViewOfFile(hFileMapping, %FILE_MAP_READ, 0, 0, 0)
        IF lpFileBase = 0 THEN
            CALL CloseHandle(hFileMapping)
            CALL CloseHandle(hFile)
            STDOUT "Couldn't map view of file with MapViewOfFile()"
            EXIT FUNCTION
        END IF
        dosHeader = lpFileBase
        IF ( @dosHeader.e_magic = %IMAGE_DOS_SIGNATURE ) THEN
            CALL DumpExeFile(BYVAL dosHeader)
        END IF
        CALL UnmapViewOfFile(lpFileBase)
        CALL CloseHandle(hFileMapping)
        CALL CloseHandle(hFile)
    END FUNCTION
    
    FUNCTION PBMAIN
        DIM sFile AS STRING
        sFile = COMMAND$
        IF sFile = "" THEN
            STDOUT "Test your system to ensure compatibility with a DLL"
            STDOUT "Useful to find unavailable imports"
            STDOUT "Usage: imptest <file>"
            WAITKEY$
            EXIT FUNCTION
        END IF
        Dump sFile
        STDOUT "Done. Press any key to continue . . ."
        WAITKEY$
    END FUNCTION

    ------------------
    The PowerBASIC Crypto Archives - My Email - What's mine is yours...
    -

    Comment


    • #3
      Oops.. posted a response to wrong message...sorry about that..
      MCM



      [This message has been edited by Michael Mattias (edited October 02, 2003).]
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        hey, this time i *am* in the right place...

        update of mr rienow's code, changes noted in comments.
        Code:
        ' enum_imp_exp.bas
        ' Show Imports and Exports for PE Executable files on screen with option to print to text file and show
        ' --[ HISTORY ]----------
        ' ORIGINAL: [URL="http://www.powerbasic.com/support/pbforums/../forums/Forum7/HTML/001212.html"]http://www.powerbasic.com/support/forums/Forum7/HTML/001212.html[/URL] 
        '           Torsten Rienow  11/21/2001 (PB/DLL 6.0)
        ' 6/4/04   (MCM) Migrated to compiler PB win v7.02 from 6.0 to see if it still works;
        '          added suffix "_I" to many UDTS, which are now defined in Win32API.INC, often differently.
        '          Got compiled with 7.02 And apparently running just fine.' 8/7/04 (MCM) Add: Browse for file...print lists, explicit exit button. Cosmetic changes too.
        '          Change from control level callback on ID_ENUM to explicit call in DlgProc, add target file
        '          version literal string, only enable enum button if we have a good file. Change from hard-coded
        '          control ID literals to equates, drop IDs where not needed, change from label+Listbox to listboxes
        '          using WS_CAPTION style.
        ' -----[ USE AND DISTRIBUTION ]-------------------------------------------------------------------
        '  Mr Rienow put no disclaimer in this code. Mr. Mattias places whatever portions of this program
        '  were his into the public domain. August 7 2004.
        '-------------------------------------------------------------------------------------------------
        ' == [ TO DO aka "wishlist" ] ========
        ' 1. Set up enum to do a callback e.g.,
        '  FUNCTION EnumExports (szFile, cbAddr, dwUser)  ' needs to send one message per function
        '  FUNCTION EnumImports (szFile, cbAddr, dwUser)    needs to send one message per imported DLL, plus one message per function
        '  (For TsExit Testbench upgrades)
        '--------------------------------------------------------------
        ' BEGIN ORIGINAL & MODIFIED CODE
        'the code below is suggested by Matt Pietrek's PEDUMP.
        'You are not allowed to use this code or any derivate
        'for any hacking (api hijacking) tools.
        'Wayne, you should save me a favor :-)
        'From previous version i have removed the wsprintf function
        'and wrote my own PtrToString.
        '
        #COMPILE EXE
        #DIM     ALL
        %NOMMIDS =  1
        #INCLUDE "win32api.inc"    ' date 5/9/02
        #INCLUDE "comdlg32.inc"    ' added 8/6/04 MCM; date 4/1/02
        ' === [ GLOBAL VARIABLES ]=============
        GLOBAL hDlg                             AS LONG
        ' ===================================================
        '  equates and positionally-required DECLAREs
        '====================================================
        %ID_SOURCE_FILE  = 1002&
        %ID_ENUM         = 1003&
        %ID_EXPORTS      = 1005&
        %ID_IMPORTS      = 1007&
        %LB_STYLE             = %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %WS_GROUP OR %WS_CAPTION OR %WS_VSCROLL
        %ID_BROWSE_FILE       =   1011&
        %ID_VERSION_LITERAL   =   1012&
        %ID_PRINT_EXPORTS     =   1013&
        %ID_PRINT_IMPORTS     =   1014&
        %ID_CLOSE             =   1015&
        DECLARE FUNCTION BrowseForPEFile (BYVAL hWnd AS LONG) AS STRING
        DECLARE FUNCTION FileVersionString(szFile AS ASCIIZ) AS STRING
        ' === [ End equates and declares ]
        
        %IMAGE_DOS_SIGNATURE                    = &H5A4D
        %IMAGE_NT_SIGNATURE                     = &H00004550
        %IMAGE_SIZEOF_SHORT_NAME                = 8
        %IMAGE_SIZEOF_SECTION_HEADER            = 40
        %IMAGE_ORDINAL_FLAG                     = &H80000000
        UNION MISC
            PhysicalAddress                     AS DWORD
            VirtualSize                         AS DWORD
        END UNION
        ' IMAGE_SECTION_HEADER now defined in Win32API.INC.. differently
        TYPE IMAGE_SECTION_HEADER_I
            Name_(%IMAGE_SIZEOF_SHORT_NAME - 1) AS BYTE
            Misc                                AS MISC
            VirtualAddress                      AS DWORD
            SizeOfRawData                       AS DWORD
            PointerToRawData                    AS DWORD
            PointerToRelocations                AS DWORD
            PointerToLinenumbers                AS DWORD
            NumberOfRelocations                 AS WORD
            NumberOfLinenumbers                 AS WORD
            Characteristics                     AS DWORD
        END TYPE
        TYPE IMAGE_DATA_DIRECTORY
          VirtualAddress                        AS DWORD
          nSize                                 AS DWORD
        END TYPE
        ' also now defined in Win32API.INC.. differently
        TYPE IMAGE_OPTIONAL_HEADER_I
          Magic                                 AS WORD
          MajorLinkerVersion                    AS BYTE
          MinorLinkerVersion                    AS BYTE
          SizeOfCode                            AS DWORD
          SizeOfInitializedData                 AS DWORD
          SizeOfUninitializedData               AS DWORD
          AddressOfEntryPoint                   AS DWORD
          BaseOfCode                            AS DWORD
          BaseOfData                            AS DWORD
          ImageBase                             AS DWORD
          SectionAlignment                      AS DWORD
          FileAlignment                         AS DWORD
          MajorOperatingSystemVersion           AS WORD
          MinorOperatingSystemVersion           AS WORD
          MajorImageVersion                     AS WORD
          MinorImageVersion                     AS WORD
          MajorSubsystemVersion                 AS WORD
          MinorSubsystemVersion                 AS WORD
          Reserved1                             AS DWORD
          SizeOfImage                           AS DWORD
          SizeOfHeaders                         AS DWORD
          CheckSum                              AS DWORD
          Subsystem                             AS WORD
          DllCharacteristics                    AS WORD
          SizeOfStackReserve                    AS DWORD
          SizeOfStackCommit                     AS DWORD
          SizeOfHeapReserve                     AS DWORD
          SizeOfHeapCommit                      AS DWORD
          LoaderFlags                           AS DWORD
          NumberOfRvaAndSizes                   AS DWORD
          DataDirectory(%IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1) AS IMAGE_DATA_DIRECTORY
        END TYPE
        TYPE IMAGE_FILE_HEADER
          Machine                               AS WORD
          NumberOfSections                      AS WORD
          TimeDateStamp                         AS DWORD
          PointerToSymbolTable                  AS DWORD
          NumberOfSymbols                       AS DWORD
          SizeOfOptionalHeader                  AS WORD
          Characteristics                       AS WORD
        END TYPE
        TYPE IMAGE_NT_HEADERS_I
          Signature                             AS DWORD
          FileHeader                            AS IMAGE_FILE_HEADER
          OptionalHeader                        AS IMAGE_OPTIONAL_HEADER_I
        END TYPE
        TYPE IMAGE_EXPORT_DIRECTORY_I
          Characteristics                       AS DWORD
          TimeDateStamp                         AS DWORD
          MajorVersion                          AS WORD
          MinorVersion                          AS WORD
          nName                                 AS DWORD
          nBase                                 AS DWORD
          NumberOfFunctions                     AS DWORD
          NumberOfNames                         AS DWORD
          AddressOfFunctions                    AS DWORD
          AddressOfNames                        AS DWORD
          AddressOfNameOrdinals                 AS DWORD
        END TYPE
        TYPE IMAGE_IMPORT_DESCRIPTOR
            OriginalFirstThunk                  AS DWORD
            TimeDateStamp                       AS DWORD
            ForwarderChain                      AS DWORD
            Name_                               AS DWORD
            FirstThunk                          AS DWORD
        END TYPE
        TYPE IMAGE_IMPORT_BY_NAME
            Hint                                AS WORD
            Name_                               AS BYTE
        END TYPE
        UNION u1    DWORD
            ForwarderString                     AS BYTE PTR
            pFunction                           AS DWORD PTR
            Ordinal                             AS DWORD
            AddressOfData                       AS DWORD
        END UNION
        TYPE IMAGE_THUNK_DATA
            u1                                  AS u1
        END TYPE
        TYPE IMAGE_DOS_HEADER
          e_magic                               AS WORD
          e_cblp                      ”¦’‘p;nbsp;        AS WORD
          e_cp                                  AS WORD
          e_crlc                                AS WORD
          e_cparhdr                             AS WORD
          e_minalloc                            AS WORD
          e_maxalloc                            AS WORD
          e_ss                                  AS WORD
          e_sp                                  AS WORD
          e_csum                                AS WORD
          e_ip                                  AS WORD
          e_cs                                  AS WORD
          e_lfarlc                              AS WORD
          e_ovno                                AS WORD
          e_res(3)                              AS WORD
          e_oemid                               AS WORD
          e_oeminfo                             AS WORD
          e_res2(9)                             AS WORD
          e_lfanew                              AS LONG
        END TYPE
        FUNCTION PtrToString(inPtr AS BYTE PTR) AS STRING
            DIM i                               AS LONG
            DIM s                               AS STRING
            DO WHILE @inPtr[i] <> 0
                s = s + CHR$(@inPtr[i])
                INCR i
            LOOP
            FUNCTION = s
        END FUNCTION
        
        FUNCTION IMAGE_FIRST_SECTION(pNTHeader AS IMAGE_NT_HEADERS_I PTR ) AS DWORD
            FUNCTION =  pNTHeader + 24 + @pNTHeader.FileHeader.SizeOfOptionalHeader
        END FUNCTION
        FUNCTION GetEnclosingSectionHeader(BYVAL rva AS DWORD, pNTHeader AS IMAGE_NT_HEADERS_I PTR) AS DWORD
            DIM section                         AS IMAGE_SECTION_HEADER_I PTR
            DIM i                               AS LONG
            section = IMAGE_FIRST_SECTION(BYVAL pNTHeader)
            FOR i=0 TO @pNTHeader.FileHeader.NumberOfSections
                IF ( (rva >= @section.VirtualAddress) AND (rva < (@section.VirtualAddress + @section.Misc.VirtualSize))) THEN
                    FUNCTION = section
                    EXIT FUNCTION
                END IF
                section = section + SIZEOF(@section)
            NEXT
        END FUNCTION
        FUNCTION DumpImportsSection(BYVAL pBase AS DWORD, pNTHeader AS IMAGE_NT_HEADERS_I PTR) AS LONG
            DIM pHeader                         AS IMAGE_SECTION_HEADER_I PTR
            DIM pImportDesc                     AS IMAGE_IMPORT_DESCRIPTOR PTR
            DIM pThunk                          AS IMAGE_THUNK_DATA PTR
            DIM delta                           AS LONG
            DIM importsStartRVA                 AS DWORD
            DIM importsEndRVA                   AS DWORD
            DIM entryPointRVA                   AS DWORD
            DIM exportsStartRVA                 AS DWORD
            DIM exportsEndRVA                   AS DWORD
            DIM i                               AS DWORD
            DIM j                               AS DWORD
            DIM sFunctionName                   AS ASCIIZ * 512
            DIM sDll                            AS ASCIIZ * 512
            importsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).VirtualAddress
            importsEndRVA = importsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).nSize
            pHeader = GetEnclosingSectionHeader( importsStartRVA, BYVAL pNTHeader )
            IF pHeader = 0 THEN
                EXIT FUNCTION
            END IF
            delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
            pImportDesc = pBase + importsStartRVA - delta
            i = 0
            DO
                IF (@pImportDesc[i].TimeDateStamp = 0) AND (@pImportDesc[i].Name_= 0 ) THEN
                    EXIT DO
                END IF
                sDll = PtrToString(BYVAL @pImportDesc[i].Name_ - delta + pBase)
                ' HERE IS THE LIBNAME
                CONTROL SEND hDlg, %ID_IMPORTS, %LB_INSERTSTRING, -1&, VARPTR(sDll)
                j = 0
                pThunk = @pImportDesc[i].FirstThunk - delta + pBase
                exportsStartRVA = @pHeader.VirtualAddress
                exportsEndRVA= exportsStartRVA + @pHeader.SizeOfRawData
                IF (pThunk <= exportsStartRVA) OR (pThunk >= exportsEndRVA) THEN
                    IF (@pImportDesc[i].OriginalFirstThunk = 0) THEN
                        EXIT FUNCTION
                    END IF
                    pThunk = @pImportDesc[i].OriginalFirstThunk
                    IF (pThunk <= exportsStartRVA) OR (pThunk >= exportsEndRVA) THEN
                        EXIT FUNCTION
                    END IF
                    pThunk = pThunk - delta + pBase
                END IF
                DO
                    IF (@pThunk[j].u1.AddressOfData = 0) THEN
                        EXIT DO
                    END IF
                    IF (@pThunk[j].u1.Ordinal AND %IMAGE_ORDINAL_FLAG) THEN
                        sFunctionName = "    #" + FORMAT$(@pThunk[j].u1.Ordinal AND &HFFFF??)
                    ELSE
                        sFunctionName = "    " + PtrToString(BYVAL @pThunk[j].u1.AddressOfData - delta + pBase + 2)
                    END IF
                    ' HERE IS THE FUNCTION NAME
                    CONTROL SEND hDlg, %ID_IMPORTS, %LB_INSERTSTRING, -1&, VARPTR(sFunctionName)
                    INCR j
                LOOP
                INCR i
            LOOP
        END FUNCTION
        FUNCTION DumpExportsSection(BYVAL pBase AS DWORD, pNTHeader AS IMAGE_NT_HEADERS_I PTR) AS LONG
            DIM pExportDir                      AS IMAGE_EXPORT_DIRECTORY_I PTR
            DIM pHeader                         AS IMAGE_SECTION_HEADER_I PTR
            DIM delta                           AS LONG
            DIM entryPointRVA                   AS DWORD
            DIM exportsStartRVA                 AS DWORD
            DIM exportsEndRVA                   AS DWORD
            DIM pFunctions                      AS DWORD PTR
            DIM pOrdinals                       AS WORD PTR
            DIM pNames                          AS DWORD PTR
            DIM i                               AS DWORD
            DIM j                               AS DWORD
            DIM flag                            AS LONG
            DIM sFunctionName                   AS ASCIIZ * 256
            exportsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).VirtualAddress
            exportsEndRVA = exportsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).nSize
            pHeader = GetEnclosingSectionHeader( exportsStartRVA, BYVAL pNTHeader )
            IF pHeader = 0 THEN
                EXIT FUNCTION
            END IF
            delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
            pExportDir  = pBASE + exportsStartRVA - delta
            pFunctions  = @pExportDir.AddressOfFunctions    - delta + pBase
            pOrdinals   = @pExportDir.AddressOfNameOrdinals - delta + pBase
            pNames      = @pExportDir.AddressOfNames        - delta + pBase
            FOR i = 0 TO @pExportDir.NumberOfFunctions - 1
                entryPointRVA   = @pFunctions[i]
                j               = 0
                flag            = 0
                IF entryPointRVA <> 0 THEN
                    FOR j=0 TO @pExportDir.NumberOfNames - 1
                        IF @pOrdinals[j] = i THEN
                            sFunctionName = PtrToString(BYVAL @pNames[j] - delta + pBase)
                            ' HERE IS WHERE EACH EXPORTED FUNCTION NAME IS AVAILABLE
                            CONTROL SEND hDlg, %ID_EXPORTS, %LB_INSERTSTRING, -1&, VARPTR(sFunctionName)
                            flag    =   1
                        END IF
                    NEXT
                    IF (entryPointRVA >= exportsStartRVA) AND (entryPointRVA <= exportsEndRVA) THEN
                        sFunctionName = PtrToString(BYVAL entryPointRVA - delta + pBase)
                        flag    =   1
                    END IF
                END IF
            NEXT
        END FUNCTION
        FUNCTION DumpExeFile(dosHeader AS IMAGE_DOS_HEADER PTR ) AS LONG
            DIM pNTHeader                       AS IMAGE_NT_HEADERS_I PTR
            DIM pBase                           AS DWORD
            pBase &nbVScw    = dosHeader
            pNTHeader   = dosHeader + @dosHeader.e_lfanew
            CONTROL SEND hDlg, %ID_EXPORTS, %LB_RESETCONTENT, 0&, 0&
            CONTROL SEND hDlg, %ID_IMPORTS, %LB_RESETCONTENT, 0&, 0&
            IF ( IsBadReadPtr(pNTHeader, SIZEOF(pNTHeader)) OR  @pNTHeader.Signature <> %IMAGE_NT_SIGNATURE ) THEN
                MSGBOX "Unhandled EXE type, or invalid .EXE"
                EXIT FUNCTION
            END IF
            CALL DumpExportsSection(pBase, BYVAL pNTHeader)
            CALL DumpImportsSection(pBase, BYVAL pNTHeader)
        END FUNCTION
        FUNCTION Dump() AS LONG
            DIM hFile                           AS LONG
            DIM hFileMapping                    AS LONG
            DIM lpFileBase                      AS LONG
            DIM dosHeader                       AS IMAGE_DOS_HEADER PTR
            DIM fName                           AS ASCIIZ * 512
            CONTROL GET TEXT hDlg, %ID_SOURCE_FILE TO fName
            hFile = CreateFile(fName, %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0&, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0)
            IF hFile = %INVALID_HANDLE_VALUE THEN
                MSGBOX "Couldn't open file with CreateFile()"
                EXIT FUNCTION
            END IF
            hFileMapping = CreateFileMapping(hFile, BYVAL 0&, %PAGE_READONLY, 0, 0, BYVAL 0&)
            IF hFileMapping = 0 THEN
                CALL CloseHandle(hFile)
                MSGBOX "Couldn't open file mapping with CreateFileMapping()"
                EXIT FUNCTION
            END IF
            lpFileBase = MapViewOfFile(hFileMapping, %FILE_MAP_READ, 0, 0, 0)
            IF lpFileBase = 0 THEN
                CALL CloseHandle(hFileMapping)
                CALL CloseHandle(hFile)
                MSGBOX "Couldn't map view of file with MapViewOfFile()"
                EXIT FUNCTION
            END IF
            dosHeader = lpFileBase
            IF ( @dosHeader.e_magic = %IMAGE_DOS_SIGNATURE ) THEN
                CALL DumpExeFile(BYVAL dosHeader)
            END IF
            CALL UnmapViewOfFile(lpFileBase)
            CALL CloseHandle(hFileMapping)
            CALL CloseHandle(hFile)
        END FUNCTION
        
        CALLBACK FUNCTION DlgProc () AS LONG
           LOCAL sFileName AS STRING, hCtrl AS LONG, w AS STRING
           SELECT CASE AS LONG CBMSG
                CASE %WM_COMMAND
                    SELECT CASE AS LONG CBCTL
                        CASE %ID_BROWSE_FILE
                            
                            sFileName  = BrowseForPEFile (CBHNDL)
                            IF LEN(sFileName) THEN
                                CONTROL SET TEXT    CBHNDL, %ID_SOURCE_FILE, sFileName
                                'd'))et the listbox contents.
                                LISTBOX RESET CBHNDL, %ID_IMPORTS
                                LISTBOX RESET CBHNDL, %ID_EXPORTS
                                ' null out the version literal
                                CONTROL SET TEXT hDlg, %ID_VERSION_LITERAL, ""
                                
                            END IF
                            
                        CASE %ID_CLOSE
                            DIALOG END CBHNDL, 0
                            
                        CASE %ID_ENUM
                            
                            CALL Dump()
                            
                            CONTROL GET TEXT  hDlg, %ID_SOURCE_FILE TO sFileName
                            w  = FileVersionString (BYCOPY sFileName)
                            CONTROL SET TEXT  hDlg, %ID_VERSION_lITERAL, W
                            
                        CASE %ID_PRINT_IMPORTS
                            CALL  PRintTheListboxContents (CBHNDL, %ID_IMPORTS)
                            
                        CASE %ID_PRINT_EXPORTS
                            CALL  PrintTheListboxContents (CBHNDL, %ID_EXPORTS)
                            
                        CASE %ID_SOURCE_FILE
                            IF CBCTLMSG = %EN_CHANGE THEN
                                CONTROL     GET TEXT CBHNDL, %ID_SOURCE_FILE TO sFileName
                                IF DIR$(sFileName) = "" THEN
                                    CONTROL DISABLE CBHNDL, %ID_ENUM
                                ELSE
                                    CONTROL ENABLE  CBHNDL, %ID_ENUM
                                END IF
                            END IF
                    END SELECT  ' of CBCTL
                             
           END SELECT
        
        END FUNCTION
        
        ' returns: name of file selected or NULL if no file
        FUNCTION BrowseForPEFile (BYVAL hWnd AS LONG) AS STRING
            
          LOCAL OFN AS OPENFILENAME
          
          LOCAL sFilter AS STRING, sTitle AS STRING, szFileTitle AS ASCIIZ * %MAX_PATH
          LOCAL Stat AS LONG
          LOCAL pFullName AS ASCIIZ PTR * %MAX_PATH
          LOCAL EC AS LONG
          LOCAL W AS STRING
          OFN.lStructSize                 = SIZEOF(OFN)
          OFN.hInstance                   = %NULL
          OFN.lpstrCustomFilter           = %NULL
          OFN.nMaxCustFilter              = %NULL
          OFN.nFilterIndex                = 1
          OFN.lCustData                   = 0
          OFN.lpfnHook                    = 0
          OFN.lpTemplateName              = %NULL
          OFN.lpstrDefExt                 = %NULL
          OFN.nFileOffset                 = 0
          OFN.nFileExtension              = %NULL
          
          sTitle                          = "Select Input File "
          OFN.LpStrTitle                  = STRPTR (sTitle)
          
          sFilter                         = "Executable Files (*.exe, *.dll)" & $NUL & "*.exe;*.dll" & $NUL & "All Files (*.*)" & $NUL & "*.*" & $NUL & $NUL
          OFN.lpStrFilter                 = STRPTR (sFilter)
          OFN.Flags                       = %OFN_FILEMUSTEXIST OR %OFN_HIDEREADONLY OR %OFN_LONGNAMES OR %OFN_PATHMUSTEXIST OR %OFN_NOCHANGEDIR
          
          OFN.LpStrDefExt                 = %NULL
          OFN.nFilterIndex                = 0&
        
          ' set the common stuff which does not vary...
          szFileTitle                     = ""   ' no default filenamme
          OFN.LpStrFile                   = VARPTR (szFileTitle)
          OFN.nMaxFile                    = SIZEOF (szFileTitle)
          ' since the owner window may vary for the same sub across calls...
          OFN.hWndOwner                   = hWnd
          
          ' call the common dialog
          Stat = GetOpenFileName (OFN)
          IF ISTRUE (Stat) THEN
             W                    = SPACE$(OFN.NMaxFile)
             pFullName            = OFN.LpStrFile
             W                    = @pFullName
             W                    = TRIM$(W, ANY CHR$(0, &h20))
             FUNCTION             = W
          ELSE
             LOCAL eCD AS DWORD
             eCD                  = CommDlgExtendedError
             IF ECD <> 0 THEN
                MSGBOX "GetOpen/SaveFileName failed on error#" & STR$(eCD), %MB_APPLMODAL OR %MB_ICONINFORMATION, "Yikes!!!
             END IF
             FUNCTION             = ""
          END IF
        END FUNCTION
           
        FUNCTION PBMAIN
            DIALOG NEW %HWND_DESKTOP, "Enum Export/Import Functions from an Executable Image", 10, 10, 400, 260, %DS_CENTER OR %WS_SYSMENU TO hDlg
            
            CONTROL ADD LABEL,      hDlg, -1,   "Image Path", 2, 3, 40, 12,
            CONTROL ADD TEXTBOX,    hDlg, %ID_SOURCE_FILE, "", 48, 2, 294, 12,
            CONTROL ADD BUTTON,     hDlg, %ID_ENUM, "Enum", 346, 2, 47, 14
            CONTROL ADD BUTTON,     hDlg, %ID_BROWSE_FILE, "Browse", 48, 16, 47,14
            
            ' add a place for file version
            
            CONTROL ADD LABEL,     hdlg, -1, "File version",       2,  36, 40, 12
            CONTROL ADD LABEL,     hDlg, %ID_VERSION_LITERAL, "", 43,  36, 60, 12
            CONTROL ADD LISTBOX,   hDlg, %ID_EXPORTS, ,   2, 46, 194, 163, %LB_STYLE
            CONTROL ADD LISTBOX,   hDlg, %ID_IMPORTS, , 200, 46, 194, 163, %LB_STYLE
            
            ' add captions to the listboxes (no DDT Command)
            CONTROL SET TEXT hDlg, %ID_IMPORTS, "Imports"
            CONTROL SET TEXT hDlg, %ID_EXPORTS, "Exports"
            
            ' add buttons for printing the lists...
            CONTROL ADD BUTTON,     hDlg, %ID_PRINT_EXPORTS, "Print Export List", 68,  206, 60,14
            CONTROL ADD BUTTON,     hDlg, %ID_PRINT_IMPORTS, "Print Import List", 262, 206, 60,14
            
            ' and add exit button so you can exit without trying to hit that dinky little 'x'
            CONTROL ADD BUTTON,     hDLG, %ID_CLOSE,        "E&xit",  2, 230, 60,14
            
            DIALOG SHOW MODAL hDlg  CALL DlgProc
            
            
        END FUNCTION
        FUNCTION PrintTheListBoxContents (BYVAL hDlg AS LONG, BYVAL idCtrl AS LONG) AS LONG
        ' idctrl: Listbox Control ID, assumed child of hDlg
        ' No DDT command to retrieve listbox text by index (row #).  Bummer.
        
          LOCAL szFile AS ASCIIZ * %MAX_PATH, hFile AS LONG, e AS LONG, nRow AS LONG, Z AS LONG
          LOCAL szItem AS ASCIIZ * 128
          LOCAL w AS STRING, sFilename AS STRING
          
          szFile  = "enum_imp_Exp_listing.txt"
          
          hFile = FREEFILE
          OPEN    szFile FOR OUTPUT AS hFile
          
          CONTROL GET TEXT  hDlg, %ID_SOURCE_FILE TO sFileName
          
          W        = "Listing of " & IIF$(idCtrl=%ID_IMPORTS, "imported", "exported") & " functions for file " & sFilename
          PRINT       #hFile, W
          W        = "Run Date & Time " & DATE$ & SPACE$(4) & TIME$
          PRINT       #hFile, W
          PRINT       #hFile,
          
          CONTROL SEND hDlg, idCtrl, %LB_GETCOUNT , 0,0 TO nRow    ' how many items in lb?
          
          FOR Z = 0 TO nRow -1
                CONTROL SEND hDlg, idctrl, %LB_GETTEXT, Z, VARPTR(szItem)
                PRINT #hFile, szItem
          NEXT
          
          w = SPACE$(8) &  USING$("END OF REPORT  #####  items printed", nRow)
          PRINT #hFile, w
          
          CLOSE hFile
          
          E  = SHELL ("notepad.exe " & szFile)
          
          
        END FUNCTION
        FUNCTION FileVersionString(szFile AS ASCIIZ) AS STRING
          LOCAL major AS LONG, Minor AS LONG, Build AS LONG, SubBuild AS LONG
          LOCAL ResSize AS LONG
          LOCAL ffi  AS VS_FIXEDFILEINFO PTR
          LOCAL  ret AS LONG
          LOCAL Buffer AS STRING
          Major=0: Minor = 0:  Build = 0
          ResSize = GetFileVersionInfoSize (szFile, ret)
          IF ResSize= 0 THEN
            FUNCTION = "No Version Info"
            EXIT FUNCTION
          END IF
          Buffer      = SPACE$(ResSize)
          Ret         =  GetFileVersionInfo(szFile, %NULL, ResSize, BYVAL STRPTR(Buffer))
        ' ** Read the VS_FIXEDFILEINFO info
          VerQueryValue BYVAL STRPTR(Buffer), "\", ffi, SIZEOF(@ffi)
          Major        = @ffi.dwProductVersionMs  \ &h10000
          Minor        = @ffi.dwProductVersionMs MOD &h10000
          Build        = @ffi.dwProductVersionLS MOD &h10000  ' this is for MY software which uses VERSION_MAJOR, VERSION_MINOR, 0, VERSION_BUILD under FILEVERSION
          SubBuild     = @ffi.dwProductVersionLS \  &h10000
          FUNCTION = STR$(Major) & "." & TRIM$(STR$(Minor)) & "." & LTRIM$(STR$(Build))  & "." & LTRIM$(STR$(SubBuild))
        END FUNCTION
        ' // END OF FILE
        -
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          For PB9 on XP Pro SP3, make the following 3 edits to Michael's update code, posted just above:

          1. Wherever a FUNCTION definition has a pointer parameter, insert BYVAL. For example:
          Code:
          (pNTHeader As IMAGE_NT_HEADERS_I Ptr)
          becomes:
          Code:
          (ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr)
          There are 6 FUNCTIONs that need this edit.

          2. Remove what appears to be vestigal HTML chars in the second line of the IMAGE_DOS_HEADER type:

          Code:
            e_cblp                      ”¦’‘p;nbsp;        As Word
          That same line cleaned up:
          Code:
            e_cblp  As Word

          3. Remove spurious chars from the third line in DumpExeFile:
          Code:
              pBase &nbVScw    = dosHeader
          Cleaned up:
          Code:
              pBase = dosHeader

          Clean compile and run was possible after these edits.

          Comment


          • #6
            Posting of the code after edits mentioned above.

            Code:
            'Purpose: Open an .EXE or .DLL and display what function calls it imports and exports, with option to print to text file
            ' --[ HISTORY ]----------
            ' ORIGINAL: http://www.powerbasic.com/support/forums/Forum7/HTML/001212.html
            '           Torsten Rienow  11/21/2001 (PB/DLL 6.0)
            ' 6/4/04   (MCM) Migrated to compiler PB win v7.02 from 6.0 to see if it still works;
            '          added suffix "_I" to many UDTS, which are now defined in Win32API.INC, often differently.
            '          Got compiled with 7.02 And apparently running just fine.
            ' 8/7/04 (MCM) Add: Browse for file...print lists, explicit exit button. Cosmetic changes too.
            '          Change from control level callback on ID_ENUM to explicit call in DlgProc, add target file
            '          version literal string, only enable enum button if we have a good file. Change from hard-coded
            '          control ID literals to equates, drop IDs where not needed, change from label+Listbox to listboxes
            '          using WS_CAPTION style.
            '2/14/09 (jhm) edited out spurious chars, fixed pointer params to be BYVAL.
            '                   Raised Exit button to be more accessible.
            ' -----[ USE AND DISTRIBUTION ]-------------------------------------------------------------------
            '  Mr Rienow put no disclaimer in this code. Mr. Mattias places whatever portions of this program
            '  were his into the public domain. August 7 2004.
            '-------------------------------------------------------------------------------------------------
            ' == [ TO DO aka "wishlist" ] ========
            ' 1. Set up enum to do a callback e.g.,
            '  FUNCTION EnumExports (szFile, cbAddr, dwUser)  ' needs to send one message per function
            '  FUNCTION EnumImports (szFile, cbAddr, dwUser)    needs to send one message per imported DLL, plus one message per function
            '  (For TsExit Testbench upgrades)
            '--------------------------------------------------------------
            ' BEGIN ORIGINAL & MODIFIED CODE
            'the code below is suggested by Matt Pietrek's PEDUMP.
            'You are not allowed to use this code or any derivate
            'for any hacking (api hijacking) tools.
            'Wayne, you should save me a favor :-)
            'From previous version i have removed the wsprintf function
            'and wrote my own PtrToString.
            '
            #compiler PBWIN 9
            #Compile Exe "enum_imp_exp.exe"
            #Dim     All
            %NOMMIDS =  1
            #Include "win32api.inc"    ' date 5/9/02
            #Include "comdlg32.inc"    ' added 8/6/04 MCM; date 4/1/02
            ' === [ GLOBAL VARIABLES ]=============
            Global hDlg                             As Long
            ' ===================================================
            '  equates and positionally-required DECLAREs
            '====================================================
            %ID_SOURCE_FILE  = 1002&
            %ID_ENUM         = 1003&
            %ID_EXPORTS      = 1005&
            %ID_IMPORTS      = 1007&
            %LB_STYLE             = %ws_child Or %ws_visible Or %ws_tabstop Or %ws_group Or %ws_caption Or %ws_vscroll
            %ID_BROWSE_FILE       =   1011&
            %ID_VERSION_LITERAL   =   1012&
            %ID_PRINT_EXPORTS     =   1013&
            %ID_PRINT_IMPORTS     =   1014&
            %ID_CLOSE             =   1015&
            
            Declare Function BrowseForPEFile (ByVal hWnd As Long) As String
            Declare Function FileVersionString(szFile As Asciiz) As String
            ' === [ End equates and declares ]
            
            %IMAGE_DOS_SIGNATURE                    = &H5A4D
            %IMAGE_NT_SIGNATURE                     = &H00004550
            %IMAGE_SIZEOF_SHORT_NAME                = 8
            %IMAGE_SIZEOF_SECTION_HEADER            = 40
            %IMAGE_ORDINAL_FLAG                     = &H80000000
            Union MISC
                PhysicalAddress                     As Dword
                VirtualSize                         As Dword
            End Union
            ' IMAGE_SECTION_HEADER now defined in Win32API.INC.. differently
            Type IMAGE_SECTION_HEADER_I
                Name_(%IMAGE_SIZEOF_SHORT_NAME - 1) As Byte
                Misc                                As MISC
                VirtualAddress                      As Dword
                SizeOfRawData                       As Dword
                PointerToRawData                    As Dword
                PointerToRelocations                As Dword
                PointerToLinenumbers                As Dword
                NumberOfRelocations                 As Word
                NumberOfLinenumbers                 As Word
                Characteristics                     As Dword
            End Type
            Type IMAGE_DATA_DIRECTORY
              VirtualAddress                        As Dword
              nSize                                 As Dword
            End Type
            ' also now defined in Win32API.INC.. differently
            Type IMAGE_OPTIONAL_HEADER_I
              Magic                                 As Word
              MajorLinkerVersion                    As Byte
              MinorLinkerVersion                    As Byte
              SizeOfCode                            As Dword
              SizeOfInitializedData                 As Dword
              SizeOfUninitializedData               As Dword
              AddressOfEntryPoint                   As Dword
              BaseOfCode                            As Dword
              BaseOfData                            As Dword
              ImageBase                             As Dword
              SectionAlignment                      As Dword
              FileAlignment                         As Dword
              MajorOperatingSystemVersion           As Word
              MinorOperatingSystemVersion           As Word
              MajorImageVersion                     As Word
              MinorImageVersion                     As Word
              MajorSubsystemVersion                 As Word
              MinorSubsystemVersion                 As Word
              Reserved1                             As Dword
              SizeOfImage                           As Dword
              SizeOfHeaders                         As Dword
              CheckSum                              As Dword
              Subsystem                             As Word
              DllCharacteristics                    As Word
              SizeOfStackReserve                    As Dword
              SizeOfStackCommit                     As Dword
              SizeOfHeapReserve                     As Dword
              SizeOfHeapCommit                      As Dword
              LoaderFlags                           As Dword
              NumberOfRvaAndSizes                   As Dword
              DataDirectory(%IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1) As IMAGE_DATA_DIRECTORY
            End Type
            Type IMAGE_FILE_HEADER
              Machine                               As Word
              NumberOfSections                      As Word
              TimeDateStamp                         As Dword
              PointerToSymbolTable                  As Dword
              NumberOfSymbols                       As Dword
              SizeOfOptionalHeader                  As Word
              Characteristics                       As Word
            End Type
            Type IMAGE_NT_HEADERS_I
              Signature                             As Dword
              FileHeader                            As IMAGE_FILE_HEADER
              OptionalHeader                        As IMAGE_OPTIONAL_HEADER_I
            End Type
            Type IMAGE_EXPORT_DIRECTORY_I
              Characteristics                       As Dword
              TimeDateStamp                         As Dword
              MajorVersion                          As Word
              MinorVersion                          As Word
              nName                                 As Dword
              nBase                                 As Dword
              NumberOfFunctions                     As Dword
              NumberOfNames                         As Dword
              AddressOfFunctions                    As Dword
              AddressOfNames                        As Dword
              AddressOfNameOrdinals                 As Dword
            End Type
            Type IMAGE_IMPORT_DESCRIPTOR
                OriginalFirstThunk                  As Dword
                TimeDateStamp                       As Dword
                ForwarderChain                      As Dword
                Name_                               As Dword
                FirstThunk                          As Dword
            End Type
            Type IMAGE_IMPORT_BY_NAME
                Hint                                As Word
                Name_                               As Byte
            End Type
            Union u1    Dword
                ForwarderString                     As Byte Ptr
                pFunction                           As Dword Ptr
                Ordinal                             As Dword
                AddressOfData                       As Dword
            End Union
            
            Type IMAGE_THUNK_DATA
                u1                                  As u1
            End Type
            
            Type IMAGE_DOS_HEADER
              e_magic                               As Word
              e_cblp                                As Word
              e_cp                                  As Word
              e_crlc                                As Word
              e_cparhdr                             As Word
              e_minalloc                            As Word
              e_maxalloc                            As Word
              e_ss                                  As Word
              e_sp                                  As Word
              e_csum                                As Word
              e_ip                                  As Word
              e_cs                                  As Word
              e_lfarlc                              As Word
              e_ovno                                As Word
              e_res(3)                              As Word
              e_oemid                               As Word
              e_oeminfo                             As Word
              e_res2(9)                             As Word
              e_lfanew                              As Long
            End Type
            
            Function PtrToString(ByVal inPtr As Byte Ptr) As String
                Dim i                               As Long
                Dim s                               As String
                Do While @inPtr[i] <> 0
                    s = s + Chr$(@inPtr[i])
                    Incr i
                Loop
                Function = s
            End Function
            
            
            Function IMAGE_FIRST_SECTION(ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr) As Dword
                Function =  pNTHeader + 24 + @pNTHeader.FileHeader.SizeOfOptionalHeader
            End Function
            
            
            Function GetEnclosingSectionHeader(ByVal rva As Dword, ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr) As Dword
                Dim section                         As IMAGE_SECTION_HEADER_I Ptr
                Dim i                               As Long
                section = IMAGE_FIRST_SECTION(ByVal pNTHeader)
                For i=0 To @pNTHeader.FileHeader.NumberOfSections
                    If ( (rva >= @section.VirtualAddress) And (rva < (@section.VirtualAddress + @section.Misc.VirtualSize))) Then
                        Function = section
                        Exit Function
                    End If
                    section = section + SizeOf(@section)
                Next
            End Function
            
            Function DumpImportsSection(ByVal pBase As Dword, ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr) As Long
                Dim pHeader                         As IMAGE_SECTION_HEADER_I Ptr
                Dim pImportDesc                     As IMAGE_IMPORT_DESCRIPTOR Ptr
                Dim pThunk                          As IMAGE_THUNK_DATA Ptr
                Dim delta                           As Long
                Dim importsStartRVA                 As Dword
                Dim importsEndRVA                   As Dword
                Dim entryPointRVA                   As Dword
                Dim exportsStartRVA                 As Dword
                Dim exportsEndRVA                   As Dword
                Dim i                               As Dword
                Dim j                               As Dword
                Dim sFunctionName                   As Asciiz * 512
                Dim sDll                            As Asciiz * 512
                importsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).VirtualAddress
                importsEndRVA = importsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).nSize
                pHeader = GetEnclosingSectionHeader( importsStartRVA, ByVal pNTHeader )
                If pHeader = 0 Then
                    Exit Function
                End If
                delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
                pImportDesc = pBase + importsStartRVA - delta
                i = 0
                Do
                    If (@pImportDesc[i].TimeDateStamp = 0) And (@pImportDesc[i].Name_= 0 ) Then
                        Exit Do
                    End If
                    sDll = PtrToString(ByVal @pImportDesc[i].Name_ - delta + pBase)
                    ' HERE IS THE LIBNAME
                    Control Send hDlg, %ID_IMPORTS, %LB_INSERTSTRING, -1&, VarPtr(sDll)
                    j = 0
                    pThunk = @pImportDesc[i].FirstThunk - delta + pBase
                    exportsStartRVA = @pHeader.VirtualAddress
                    exportsEndRVA= exportsStartRVA + @pHeader.SizeOfRawData
                    If (pThunk <= exportsStartRVA) Or (pThunk >= exportsEndRVA) Then
                        If (@pImportDesc[i].OriginalFirstThunk = 0) Then
                            Exit Function
                        End If
                        pThunk = @pImportDesc[i].OriginalFirstThunk
                        If (pThunk <= exportsStartRVA) Or (pThunk >= exportsEndRVA) Then
                            Exit Function
                        End If
                        pThunk = pThunk - delta + pBase
                    End If
                    Do
                        If (@pThunk[j].u1.AddressOfData = 0) Then
                            Exit Do
                        End If
                        If (@pThunk[j].u1.Ordinal And %IMAGE_ORDINAL_FLAG) Then
                            sFunctionName = "    #" + Format$(@pThunk[j].u1.Ordinal And &HFFFF??)
                        Else
                            sFunctionName = "    " + PtrToString(ByVal @pThunk[j].u1.AddressOfData - delta + pBase + 2)
                        End If
                        ' HERE IS THE FUNCTION NAME
                        Control Send hDlg, %ID_IMPORTS, %LB_INSERTSTRING, -1&, VarPtr(sFunctionName)
                        Incr j
                    Loop
                    Incr i
                Loop
            End Function
            
            Function DumpExportsSection(ByVal pBase As Dword, ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr) As Long
                Dim pExportDir                      As IMAGE_EXPORT_DIRECTORY_I Ptr
                Dim pHeader                         As IMAGE_SECTION_HEADER_I Ptr
                Dim delta                           As Long
                Dim entryPointRVA                   As Dword
                Dim exportsStartRVA                 As Dword
                Dim exportsEndRVA                   As Dword
                Dim pFunctions                      As Dword Ptr
                Dim pOrdinals                       As Word Ptr
                Dim pNames                          As Dword Ptr
                Dim i                               As Dword
                Dim j                               As Dword
                Dim flag                            As Long
                Dim sFunctionName                   As Asciiz * 256
                exportsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).VirtualAddress
                exportsEndRVA = exportsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).nSize
                pHeader = GetEnclosingSectionHeader( exportsStartRVA, ByVal pNTHeader )
                If pHeader = 0 Then
                    Exit Function
                End If
                delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
                pExportDir  = pBASE + exportsStartRVA - delta
                pFunctions  = @pExportDir.AddressOfFunctions    - delta + pBase
                pOrdinals   = @pExportDir.AddressOfNameOrdinals - delta + pBase
                pNames      = @pExportDir.AddressOfNames        - delta + pBase
                For i = 0 To @pExportDir.NumberOfFunctions - 1
                    entryPointRVA   = @pFunctions[i]
                    j               = 0
                    flag            = 0
                    If entryPointRVA <> 0 Then
                        For j=0 To @pExportDir.NumberOfNames - 1
                            If @pOrdinals[j] = i Then
                                sFunctionName = PtrToString(ByVal @pNames[j] - delta + pBase)
                                ' HERE IS WHERE EACH EXPORTED FUNCTION NAME IS AVAILABLE
                                Control Send hDlg, %ID_EXPORTS, %LB_INSERTSTRING, -1&, VarPtr(sFunctionName)
                                flag    =   1
                            End If
                        Next
                        If (entryPointRVA >= exportsStartRVA) And (entryPointRVA <= exportsEndRVA) Then
                            sFunctionName = PtrToString(ByVal entryPointRVA - delta + pBase)
                            flag    =   1
                        End If
                    End If
                Next
            End Function
            
            Function DumpExeFile(ByVal dosHeader As IMAGE_DOS_HEADER Ptr ) As Long
                Dim pNTHeader                       As IMAGE_NT_HEADERS_I Ptr
                Dim pBase                           As Dword
                pBase = dosHeader
                pNTHeader   = dosHeader + @dosHeader.e_lfanew
                Control Send hDlg, %ID_EXPORTS, %LB_RESETCONTENT, 0&, 0&
                Control Send hDlg, %ID_IMPORTS, %LB_RESETCONTENT, 0&, 0&
                If ( IsBadReadPtr(pNTHeader, SizeOf(pNTHeader)) Or  @pNTHeader.Signature <> %IMAGE_NT_SIGNATURE ) Then
                    MsgBox "Unhandled EXE type, or invalid .EXE"
                    Exit Function
                End If
                Call DumpExportsSection(pBase, ByVal pNTHeader)
                Call DumpImportsSection(pBase, ByVal pNTHeader)
            End Function
            Function Dump() As Long
                Dim hFile                           As Long
                Dim hFileMapping                    As Long
                Dim lpFileBase                      As Long
                Dim dosHeader                       As IMAGE_DOS_HEADER Ptr
                Dim fName                           As Asciiz * 512
                Control Get Text hDlg, %ID_SOURCE_FILE To fName
                hFile = CreateFile(fName, %GENERIC_READ, %FILE_SHARE_READ, ByVal 0&, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0)
                If hFile = %INVALID_HANDLE_VALUE Then
                    MsgBox "Couldn't open file with CreateFile()"
                    Exit Function
                End If
                hFileMapping = CreateFileMapping(hFile, ByVal 0&, %PAGE_READONLY, 0, 0, ByVal 0&)
                If hFileMapping = 0 Then
                    Call CloseHandle(hFile)
                    MsgBox "Couldn't open file mapping with CreateFileMapping()"
                    Exit Function
                End If
                lpFileBase = MapViewOfFile(hFileMapping, %FILE_MAP_READ, 0, 0, 0)
                If lpFileBase = 0 Then
                    Call CloseHandle(hFileMapping)
                    Call CloseHandle(hFile)
                    MsgBox "Couldn't map view of file with MapViewOfFile()"
                    Exit Function
                End If
                dosHeader = lpFileBase
                If ( @dosHeader.e_magic = %IMAGE_DOS_SIGNATURE ) Then
                    Call DumpExeFile(ByVal dosHeader)
                End If
                Call UnmapViewOfFile(lpFileBase)
                Call CloseHandle(hFileMapping)
                Call CloseHandle(hFile)
            End Function
            
            CallBack Function DlgProc () As Long
               Local sFileName As String, hCtrl As Long, w As String
               Select Case As Long CbMsg
                    Case %wm_command
                        Select Case As Long CbCtl
                            Case %ID_BROWSE_FILE
            
                                sFileName  = BrowseForPEFile (CbHndl)
                                If Len(sFileName) Then
                                    Control Set Text    CbHndl, %ID_SOURCE_FILE, sFileName
                                    'd'))et the listbox contents.
                                    ListBox Reset CbHndl, %ID_IMPORTS
                                    ListBox Reset CbHndl, %ID_EXPORTS
                                    ' null out the version literal
                                    Control Set Text hDlg, %ID_VERSION_LITERAL, ""
            
                                End If
            
                            Case %ID_CLOSE
                                Dialog End CbHndl, 0
            
                            Case %ID_ENUM
            
                                Call Dump()
            
                                Control Get Text  hDlg, %ID_SOURCE_FILE To sFileName
                                w  = FileVersionString (ByCopy sFileName)
                                Control Set Text  hDlg, %ID_VERSION_lITERAL, W
            
                            Case %ID_PRINT_IMPORTS
                                Call  PRintTheListboxContents (CbHndl, %ID_IMPORTS)
            
                            Case %ID_PRINT_EXPORTS
                                Call  PrintTheListboxContents (CbHndl, %ID_EXPORTS)
            
                            Case %ID_SOURCE_FILE
                                If CbCtlMsg = %en_change Then
                                    Control     Get Text CbHndl, %ID_SOURCE_FILE To sFileName
                                    If Dir$(sFileName) = "" Then
                                        Control Disable CbHndl, %ID_ENUM
                                    Else
                                        Control Enable  CbHndl, %ID_ENUM
                                    End If
                                End If
                        End Select  ' of CBCTL
            
               End Select
            
            End Function
            
            ' returns: name of file selected or NULL if no file
            Function BrowseForPEFile (ByVal hWnd As Long) As String
            
              Local OFN As OPENFILENAME
            
              Local sFilter As String, sTitle As String, szFileTitle As Asciiz * %MAX_PATH
              Local Stat As Long
              Local pFullName As Asciiz Ptr * %MAX_PATH
              Local EC As Long
              Local W As String
              OFN.lStructSize                 = SizeOf(OFN)
              OFN.hInstance                   = %NULL
              OFN.lpstrCustomFilter           = %NULL
              OFN.nMaxCustFilter              = %NULL
              OFN.nFilterIndex                = 1
              OFN.lCustData                   = 0
              OFN.lpfnHook                    = 0
              OFN.lpTemplateName              = %NULL
              OFN.lpstrDefExt                 = %NULL
              OFN.nFileOffset                 = 0
              OFN.nFileExtension              = %NULL
            
              sTitle                          = "Select Input File "
              OFN.LpStrTitle                  = StrPtr (sTitle)
            
              sFilter                         = "Executable Files (*.exe, *.dll)" & $Nul & "*.exe;*.dll" & $Nul & "All Files (*.*)" & $Nul & "*.*" & $Nul & $Nul
              OFN.lpStrFilter                 = StrPtr (sFilter)
              OFN.Flags                       = %ofn_filemustexist Or %ofn_hidereadonly Or %ofn_longnames Or %ofn_pathmustexist Or %ofn_nochangedir
            
              OFN.LpStrDefExt                 = %NULL
              OFN.nFilterIndex                = 0&
            
              ' set the common stuff which does not vary...
              szFileTitle                     = ""   ' no default filenamme
              OFN.LpStrFile                   = VarPtr (szFileTitle)
              OFN.nMaxFile                    = SizeOf (szFileTitle)
              ' since the owner window may vary for the same sub across calls...
              OFN.hWndOwner                   = hWnd
            
              ' call the common dialog
              Stat = GetOpenFileName (OFN)
              If IsTrue (Stat) Then
                 W                    = Space$(OFN.NMaxFile)
                 pFullName            = OFN.LpStrFile
                 W                    = @pFullName
                 W                    = Trim$(W, Any Chr$(0, &h20))
                 Function             = W
              Else
                 Local eCD As Dword
                 eCD                  = CommDlgExtendedError
                 If ECD <> 0 Then
                    MsgBox "GetOpen/SaveFileName failed on error#" & Str$(eCD), %mb_applmodal Or %mb_iconinformation, "Yikes!!!
                 End If
                 Function             = ""
              End If
            End Function
            
            Function PBMain
                Dialog New %HWND_DESKTOP, "Enum Export/Import Functions from an Executable Image", 10, 10, 400, 260, %ds_center Or %ws_sysmenu To hDlg
            
                Control Add Label,      hDlg, -1,   "Image Path", 2, 3, 40, 12,
                Control Add TextBox,    hDlg, %ID_SOURCE_FILE, "", 48, 2, 294, 12,
                Control Add Button,     hDlg, %ID_ENUM, "Enum", 346, 2, 47, 14
                Control Add Button,     hDlg, %ID_BROWSE_FILE, "Browse", 48, 16, 47,14
            
                ' add a place for file version
                Control Add Label,     hdlg, -1, "File version",       2,  36, 40, 12
                Control Add Label,     hDlg, %ID_VERSION_LITERAL, "", 43,  36, 60, 12
                Control Add ListBox,   hDlg, %ID_EXPORTS, ,   2, 46, 194, 163, %LB_STYLE
                Control Add ListBox,   hDlg, %ID_IMPORTS, , 200, 46, 194, 163, %LB_STYLE
            
                ' add captions to the listboxes (no DDT Command)
                Control Set Text hDlg, %ID_IMPORTS, "Imports"
                Control Set Text hDlg, %ID_EXPORTS, "Exports"
            
                ' add buttons for printing the lists...
                Control Add Button,     hDlg, %ID_PRINT_EXPORTS, "Print Export List", 68,  206, 60,14
                Control Add Button,     hDlg, %ID_PRINT_IMPORTS, "Print Import List", 262, 206, 60,14
            
                ' and add exit button so you can exit without trying to hit that dinky little 'x'
                Control Add Button,     hDLG, %ID_CLOSE,        "E&xit",  2, 224, 60,14
            
                Dialog Show Modal hDlg  Call DlgProc
            
            
            End Function
            Function PrintTheListBoxContents (ByVal hDlg As Long, ByVal idCtrl As Long) As Long
            ' idctrl: Listbox Control ID, assumed child of hDlg
            ' No DDT command to retrieve listbox text by index (row #).  Bummer.
            
              Local szFile As Asciiz * %MAX_PATH, hFile As Long, e As Long, nRow As Long, Z As Long
              Local szItem As Asciiz * 128
              Local w As String, sFilename As String
            
              szFile  = "enum_imp_Exp_listing.txt"
            
              hFile = FreeFile
              Open    szFile For Output As hFile
            
              Control Get Text  hDlg, %ID_SOURCE_FILE To sFileName
            
              W        = "Listing of " & IIf$(idCtrl=%ID_IMPORTS, "imported", "exported") & " functions for file " & sFilename
              Print       #hFile, W
              W        = "Run Date & Time " & Date$ & Space$(4) & Time$
              Print       #hFile, W
              Print       #hFile,
            
              Control Send hDlg, idCtrl, %LB_GETCOUNT , 0,0 To nRow    ' how many items in lb?
            
              For Z = 0 To nRow -1
                    Control Send hDlg, idctrl, %LB_GETTEXT, Z, VarPtr(szItem)
                    Print #hFile, szItem
              Next
            
              w = Space$(8) &  Using$("END OF REPORT  #####  items printed", nRow)
              Print #hFile, w
            
              Close hFile
            
              E  = Shell ("notepad.exe " & szFile)
            
            
            End Function
            Function FileVersionString(szFile As Asciiz) As String
              Local major As Long, Minor As Long, Build As Long, SubBuild As Long
              Local ResSize As Long
              Local ffi  As VS_FIXEDFILEINFO Ptr
              Local  ret As Long
              Local Buffer As String
              Major=0: Minor = 0:  Build = 0
              ResSize = GetFileVersionInfoSize (szFile, ret)
              If ResSize= 0 Then
                Function = "No Version Info"
                Exit Function
              End If
              Buffer      = Space$(ResSize)
              Ret         =  GetFileVersionInfo(szFile, %NULL, ResSize, ByVal StrPtr(Buffer))
            ' ** Read the VS_FIXEDFILEINFO info
              VerQueryValue ByVal StrPtr(Buffer), "\", ffi, SizeOf(@ffi)
              Major        = @ffi.dwProductVersionMs  \ &h10000
              Minor        = @ffi.dwProductVersionMs Mod &h10000
              Build        = @ffi.dwProductVersionLS Mod &h10000  ' this is for MY software which uses VERSION_MAJOR, VERSION_MINOR, 0, VERSION_BUILD under FILEVERSION
              SubBuild     = @ffi.dwProductVersionLS \  &h10000
              Function = Str$(Major) & "." & Trim$(Str$(Minor)) & "." & LTrim$(Str$(Build))  & "." & LTrim$(Str$(SubBuild))
            End Function
            ' // END OF FILE
            Last edited by John Montenigro; 14 Feb 2009, 05:17 PM. Reason: per request, added compiler version

            Comment


            • #7
              added: Copy 1 line to Clipboard

              I've done some cosmetic renovation in order to accomodate adding a new "Copy 1 line to Clipboard" button and a statusbar. I just wanted to make it easier to get an entry into the SDK for searching...(plus the exercise was a good learning experience for me).
              -jhm

              ADDED: For those who do not have PBWin9, I've attached a .ZIP with the .EXE...


              Code:
              ' enum_imp_exp.bas    by various artists
              
              'Purpose:
              'Open an .EXE or .DLL and display what function calls it imports and exports, with the option to print to text file.
              '(jhm) and option to copy a line from a listbox to the clipboard to facilitate searching in the SDK help!
              
              ' --[ HISTORY ]----------
              ' ORIGINAL: http://www.powerbasic.com/support/forums/Forum7/HTML/001212.html
              '           Torsten Rienow  11/21/2001 (PB/DLL 6.0)
              ' 6/4/04   (MCM) Migrated to compiler PB win v7.02 from 6.0 to see if it still works;
              '          added suffix "_I" to many UDTS, which are now defined in Win32API.INC, often differently.
              '          Got compiled with 7.02 And apparently running just fine.
              
              ' 8/7/04 (MCM) Add: Browse for file...print lists, explicit exit button. Cosmetic changes too.
              '          Change from control level callback on ID_ENUM to explicit call in DlgProc, add target file
              '          version literal string, only enable enum button if we have a good file. Change from hard-coded
              '          control ID literals to equates, drop IDs where not needed, change from label+Listbox to listboxes
              '          using WS_CAPTION style.
              ' 2/14/09 (jhm) removed spurious chars and updated pointer params to BYVAL
              '               Raised the Exit button position.
              ' 2/16/09 (jhm) Re-arranged controls for my comfort, and added CopyToClipboard and statusbar
              
              ' -----[ USE AND DISTRIBUTION ]-------------------------------------------------------------------
              '  Mr Rienow put no disclaimer in this code. Mr. Mattias places whatever portions of this program
              '  were his into the public domain. August 7 2004.
              '-------------------------------------------------------------------------------------------------
              
              ' == [ TO DO aka "wishlist" ] ========
              ' 1. Set up enum to do a callback e.g.,
              '  FUNCTION EnumExports (szFile, cbAddr, dwUser)  ' needs to send one message per function
              '  FUNCTION EnumImports (szFile, cbAddr, dwUser)    needs to send one message per imported DLL, plus one message per function
              '  (For TsExit Testbench upgrades)
              '--------------------------------------------------------------
              
              ' BEGIN ORIGINAL & MODIFIED CODE
              'the code below is suggested by Matt Pietrek's PEDUMP.
              'You are not allowed to use this code or any derivate for any hacking (api hijacking) tools.
              'Wayne, you should save me a favor :-)
              '
              'From previous version i have removed the wsprintf function and wrote my own PtrToString.
              
              #Compiler PBWin 9
              #Compile Exe
              #Dim     All
              
              %NOMMIDS =  1
              #Include "win32api.inc"    ' date 5/9/02
              #Include "comdlg32.inc"    ' added 8/6/04 MCM; date 4/1/02
              
              ' === [ GLOBAL VARIABLES ]=============
              Global hDlg       As Long
              Global hList      As Long     'added by jhm
              
              '====================================================
              '  equates and positionally-required DECLAREs
              '====================================================
              %ID_SOURCE_FILE      = 1002&
              %ID_ENUM             = 1003&
              %ID_EXPORTS          = 1005&
              %ID_IMPORTS          = 1007&
              %CMD_CopyToClipboard = 1008&  'added by jhm
              %SB_statusbar        = 1009&  'added by jhm
              
              %LB_STYLE             = %ws_child Or %ws_visible Or %ws_tabstop Or %ws_group Or %ws_caption Or %ws_vscroll
              
              %ID_BROWSE_FILE       =   1011&
              %ID_VERSION_LITERAL   =   1012&
              %ID_PRINT_EXPORTS     =   1013&
              %ID_PRINT_IMPORTS     =   1014&
              %ID_CLOSE             =   1015&
              
              Declare Function BrowseForPEFile (ByVal hWnd As Long) As String
              Declare Function FileVersionString(szFile As Asciiz) As String
              ' === [ End equates and declares ]
              
              
              %IMAGE_DOS_SIGNATURE                    = &H5A4D
              %IMAGE_NT_SIGNATURE                     = &H00004550
              %IMAGE_SIZEOF_SHORT_NAME                = 8
              %IMAGE_SIZEOF_SECTION_HEADER            = 40
              %IMAGE_ORDINAL_FLAG                     = &H80000000
              
              Union MISC
                  PhysicalAddress                     As Dword
                  VirtualSize                         As Dword
              End Union
              ' IMAGE_SECTION_HEADER now defined in Win32API.INC.. differently
              Type IMAGE_SECTION_HEADER_I
                  Name_(%IMAGE_SIZEOF_SHORT_NAME - 1) As Byte
                  Misc                                As MISC
                  VirtualAddress                      As Dword
                  SizeOfRawData                       As Dword
                  PointerToRawData                    As Dword
                  PointerToRelocations                As Dword
                  PointerToLinenumbers                As Dword
                  NumberOfRelocations                 As Word
                  NumberOfLinenumbers                 As Word
                  Characteristics                     As Dword
              End Type
              
              Type IMAGE_DATA_DIRECTORY
                VirtualAddress                        As Dword
                nSize                                 As Dword
              End Type
              ' also now defined in Win32API.INC.. differently
              Type IMAGE_OPTIONAL_HEADER_I
                Magic                                 As Word
                MajorLinkerVersion                    As Byte
                MinorLinkerVersion                    As Byte
                SizeOfCode                            As Dword
                SizeOfInitializedData                 As Dword
                SizeOfUninitializedData               As Dword
                AddressOfEntryPoint                   As Dword
                BaseOfCode                            As Dword
                BaseOfData                            As Dword
                ImageBase                             As Dword
                SectionAlignment                      As Dword
                FileAlignment                         As Dword
                MajorOperatingSystemVersion           As Word
                MinorOperatingSystemVersion           As Word
                MajorImageVersion                     As Word
                MinorImageVersion                     As Word
                MajorSubsystemVersion                 As Word
                MinorSubsystemVersion                 As Word
                Reserved1                             As Dword
                SizeOfImage                           As Dword
                SizeOfHeaders                         As Dword
                CheckSum                              As Dword
                Subsystem                             As Word
                DllCharacteristics                    As Word
                SizeOfStackReserve                    As Dword
                SizeOfStackCommit                     As Dword
                SizeOfHeapReserve                     As Dword
                SizeOfHeapCommit                      As Dword
                LoaderFlags                           As Dword
                NumberOfRvaAndSizes                   As Dword
                DataDirectory(%IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1) As IMAGE_DATA_DIRECTORY
              End Type
              
              Type IMAGE_FILE_HEADER
                Machine                               As Word
                NumberOfSections                      As Word
                TimeDateStamp                         As Dword
                PointerToSymbolTable                  As Dword
                NumberOfSymbols                       As Dword
                SizeOfOptionalHeader                  As Word
                Characteristics                       As Word
              End Type
              
              Type IMAGE_NT_HEADERS_I
                Signature                             As Dword
                FileHeader                            As IMAGE_FILE_HEADER
                OptionalHeader                        As IMAGE_OPTIONAL_HEADER_I
              End Type
              
              Type IMAGE_EXPORT_DIRECTORY_I
                Characteristics                       As Dword
                TimeDateStamp                         As Dword
                MajorVersion                          As Word
                MinorVersion                          As Word
                nName                                 As Dword
                nBase                                 As Dword
                NumberOfFunctions                     As Dword
                NumberOfNames                         As Dword
                AddressOfFunctions                    As Dword
                AddressOfNames                        As Dword
                AddressOfNameOrdinals                 As Dword
              End Type
              
              Type IMAGE_IMPORT_DESCRIPTOR
                  OriginalFirstThunk                  As Dword
                  TimeDateStamp                       As Dword
                  ForwarderChain                      As Dword
                  Name_                               As Dword
                  FirstThunk                          As Dword
              End Type
              
              Type IMAGE_IMPORT_BY_NAME
                  Hint                                As Word
                  Name_                               As Byte
              End Type
              
              Union u1    Dword
                  ForwarderString                     As Byte Ptr
                  pFunction                           As Dword Ptr
                  Ordinal                             As Dword
                  AddressOfData                       As Dword
              End Union
              
              Type IMAGE_THUNK_DATA
                  u1                                  As u1
              End Type
              
              Type IMAGE_DOS_HEADER
                e_magic                               As Word
                e_cblp                                As Word
                e_cp                                  As Word
                e_crlc                                As Word
                e_cparhdr                             As Word
                e_minalloc                            As Word
                e_maxalloc                            As Word
                e_ss                                  As Word
                e_sp                                  As Word
                e_csum                                As Word
                e_ip                                  As Word
                e_cs                                  As Word
                e_lfarlc                              As Word
                e_ovno                                As Word
                e_res(3)                              As Word
                e_oemid                               As Word
                e_oeminfo                             As Word
                e_res2(9)                             As Word
                e_lfanew                              As Long
              End Type
              
              Function PtrToString(ByVal inPtr As Byte Ptr) As String
                  Dim i                               As Long
                  Dim s                               As String
              
                  Do While @inPtr[i] <> 0
                      s = s + Chr$(@inPtr[i])
                      Incr i
                  Loop
                  Function = s
              End Function
              
              Function IMAGE_FIRST_SECTION(ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr ) As Dword
                  Function =  pNTHeader + 24 + @pNTHeader.FileHeader.SizeOfOptionalHeader
              End Function
              
              Function GetEnclosingSectionHeader(ByVal rva As Dword, ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr) As Dword
                  Dim section                         As IMAGE_SECTION_HEADER_I Ptr
                  Dim i                               As Long
              
                  section = IMAGE_FIRST_SECTION(ByVal pNTHeader)
              
                  For i=0 To @pNTHeader.FileHeader.NumberOfSections
                      If ( (rva >= @section.VirtualAddress) And (rva < (@section.VirtualAddress + @section.Misc.VirtualSize))) Then
                          Function = section
                          Exit Function
                      End If
                      section = section + SizeOf(@section)
                  Next
              End Function
              
              Function DumpImportsSection(ByVal pBase As Dword, ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr) As Long
                  Dim pHeader                         As IMAGE_SECTION_HEADER_I Ptr
                  Dim pImportDesc                     As IMAGE_IMPORT_DESCRIPTOR Ptr
                  Dim pThunk                          As IMAGE_THUNK_DATA Ptr
                  Dim delta                           As Long
                  Dim importsStartRVA                 As Dword
                  Dim importsEndRVA                   As Dword
                  Dim entryPointRVA                   As Dword
                  Dim exportsStartRVA                 As Dword
                  Dim exportsEndRVA                   As Dword
                  Dim i                               As Dword
                  Dim j                               As Dword
                  Dim sFunctionName                   As Asciiz * 512
                  Dim sDll                            As Asciiz * 512
              
                  importsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).VirtualAddress
                  importsEndRVA = importsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).nSize
              
                  pHeader = GetEnclosingSectionHeader( importsStartRVA, ByVal pNTHeader )
              
                  If pHeader = 0 Then
                      Exit Function
                  End If
              
                  delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
                  pImportDesc = pBase + importsStartRVA - delta
              
                  i = 0
                  Do
                      If (@pImportDesc[i].TimeDateStamp = 0) And (@pImportDesc[i].Name_= 0 ) Then
                          Exit Do
                      End If
                      sDll = PtrToString(ByVal @pImportDesc[i].Name_ - delta + pBase)
                      ' HERE IS THE LIBNAME
                      Control Send hDlg, %ID_IMPORTS, %LB_INSERTSTRING, -1&, VarPtr(sDll)
                      j = 0
                      pThunk = @pImportDesc[i].FirstThunk - delta + pBase
              
                      exportsStartRVA = @pHeader.VirtualAddress
                      exportsEndRVA= exportsStartRVA + @pHeader.SizeOfRawData
              
                      If (pThunk <= exportsStartRVA) Or (pThunk >= exportsEndRVA) Then
                          If (@pImportDesc[i].OriginalFirstThunk = 0) Then
                              Exit Function
                          End If
                          pThunk = @pImportDesc[i].OriginalFirstThunk
                          If (pThunk <= exportsStartRVA) Or (pThunk >= exportsEndRVA) Then
                              Exit Function
                          End If
                          pThunk = pThunk - delta + pBase
                      End If
              
                      Do
                          If (@pThunk[j].u1.AddressOfData = 0) Then
                              Exit Do
                          End If
                          If (@pThunk[j].u1.Ordinal And %IMAGE_ORDINAL_FLAG) Then
                              sFunctionName = "    #" + Format$(@pThunk[j].u1.Ordinal And &HFFFF??)
                          Else
                              sFunctionName = "    " + PtrToString(ByVal @pThunk[j].u1.AddressOfData - delta + pBase + 2)
                          End If
                          ' HERE IS THE FUNCTION NAME
                          Control Send hDlg, %ID_IMPORTS, %LB_INSERTSTRING, -1&, VarPtr(sFunctionName)
                          Incr j
                      Loop
                      Incr i
                  Loop
              End Function
              
              Function DumpExportsSection(ByVal pBase As Dword, ByVal pNTHeader As IMAGE_NT_HEADERS_I Ptr) As Long
                  Dim pExportDir                      As IMAGE_EXPORT_DIRECTORY_I Ptr
                  Dim pHeader                         As IMAGE_SECTION_HEADER_I Ptr
                  Dim delta                           As Long
                  Dim entryPointRVA                   As Dword
                  Dim exportsStartRVA                 As Dword
                  Dim exportsEndRVA                   As Dword
                  Dim pFunctions                      As Dword Ptr
                  Dim pOrdinals                       As Word Ptr
                  Dim pNames                          As Dword Ptr
                  Dim i                               As Dword
                  Dim j                               As Dword
                  Dim flag                            As Long
                  Dim sFunctionName                   As Asciiz * 256
              
                  exportsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).VirtualAddress
                  exportsEndRVA = exportsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).nSize
              
                  pHeader = GetEnclosingSectionHeader( exportsStartRVA, ByVal pNTHeader )
              
                  If pHeader = 0 Then
                      Exit Function
                  End If
              
                  delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
                  pExportDir  = pBASE + exportsStartRVA - delta
                  pFunctions  = @pExportDir.AddressOfFunctions    - delta + pBase
                  pOrdinals   = @pExportDir.AddressOfNameOrdinals - delta + pBase
                  pNames      = @pExportDir.AddressOfNames        - delta + pBase
                  For i = 0 To @pExportDir.NumberOfFunctions - 1
                      entryPointRVA   = @pFunctions[i]
                      j               = 0
                      flag            = 0
              
                      If entryPointRVA <> 0 Then
                          For j=0 To @pExportDir.NumberOfNames - 1
                              If @pOrdinals[j] = i Then
                                  sFunctionName = PtrToString(ByVal @pNames[j] - delta + pBase)
                                  ' HERE IS WHERE EACH EXPORTED FUNCTION NAME IS AVAILABLE
                                  Control Send hDlg, %ID_EXPORTS, %LB_INSERTSTRING, -1&, VarPtr(sFunctionName)
                                  flag    =   1
                              End If
                          Next
                          If (entryPointRVA >= exportsStartRVA) And (entryPointRVA <= exportsEndRVA) Then
                              sFunctionName = PtrToString(ByVal entryPointRVA - delta + pBase)
                              flag    =   1
                          End If
                      End If
                  Next
              End Function
              
              Function DumpExeFile(ByVal dosHeader As IMAGE_DOS_HEADER Ptr ) As Long
                  Dim pNTHeader                       As IMAGE_NT_HEADERS_I Ptr
                  Dim pBase                           As Dword
              
                  pBase       = dosHeader
                  pNTHeader   = dosHeader + @dosHeader.e_lfanew
              
                  Control Send hDlg, %ID_EXPORTS, %LB_RESETCONTENT, 0&, 0&
                  Control Send hDlg, %ID_IMPORTS, %LB_RESETCONTENT, 0&, 0&
              
                  If ( IsBadReadPtr(pNTHeader, SizeOf(pNTHeader)) Or  @pNTHeader.Signature <> %IMAGE_NT_SIGNATURE ) Then
                      MsgBox "Unhandled EXE type, or invalid .EXE"
                      Exit Function
                  End If
              
                  Call DumpExportsSection(pBase, ByVal pNTHeader)
                  Call DumpImportsSection(pBase, ByVal pNTHeader)
              End Function
              
              Function Dump() As Long
                  Dim hFile                           As Long
                  Dim hFileMapping                    As Long
                  Dim lpFileBase                      As Long
                  Dim dosHeader                       As IMAGE_DOS_HEADER Ptr
                  Dim fName                           As Asciiz * 512
              
                  Control Get Text hDlg, %ID_SOURCE_FILE To fName
              
                  hFile = CreateFile(fName, %GENERIC_READ, %FILE_SHARE_READ, ByVal 0&, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0)
              
                  If hFile = %INVALID_HANDLE_VALUE Then
                      MsgBox "Couldn't open file with CreateFile()"
                      Exit Function
                  End If
              
                  hFileMapping = CreateFileMapping(hFile, ByVal 0&, %PAGE_READONLY, 0, 0, ByVal 0&)
                  If hFileMapping = 0 Then
                      Call CloseHandle(hFile)
                      MsgBox "Couldn't open file mapping with CreateFileMapping()"
                      Exit Function
                  End If
              
                  lpFileBase = MapViewOfFile(hFileMapping, %FILE_MAP_READ, 0, 0, 0)
                  If lpFileBase = 0 Then
                      Call CloseHandle(hFileMapping)
                      Call CloseHandle(hFile)
                      MsgBox "Couldn't map view of file with MapViewOfFile()"
                      Exit Function
                  End If
              
                  dosHeader = lpFileBase
                  If ( @dosHeader.e_magic = %IMAGE_DOS_SIGNATURE ) Then
                      Call DumpExeFile(ByVal dosHeader)
                  End If
              
                  Call UnmapViewOfFile(lpFileBase)
                  Call CloseHandle(hFileMapping)
                  Call CloseHandle(hFile)
              End Function
              
              
              ' returns: name of file selected or NULL if no file
              Function BrowseForPEFile (ByVal hWnd As Long) As String
                Local OFN As OPENFILENAME
              
                Local sFilter As String, sTitle As String, szFileTitle As Asciiz * %MAX_PATH
                Local Stat As Long
                Local pFullName As Asciiz Ptr * %MAX_PATH
                Local EC As Long
                Local W As String
              
                OFN.lStructSize                 = SizeOf(OFN)
                OFN.hInstance                   = %NULL
                OFN.lpstrCustomFilter           = %NULL
                OFN.nMaxCustFilter              = %NULL
                OFN.nFilterIndex                = 1
                OFN.lCustData                   = 0
                OFN.lpfnHook                    = 0
                OFN.lpTemplateName              = %NULL
                OFN.lpstrDefExt                 = %NULL
                OFN.nFileOffset                 = 0
                OFN.nFileExtension              = %NULL
              
              
                sTitle                          = "Select Input File "
                OFN.LpStrTitle                  = StrPtr (sTitle)
              
                sFilter                         = "Executable Files (*.exe, *.dll)" & $Nul & "*.exe;*.dll" & $Nul & "All Files (*.*)" & $Nul & "*.*" & $Nul & $Nul
                OFN.lpStrFilter                 = StrPtr (sFilter)
                OFN.Flags                       = %ofn_filemustexist Or %ofn_hidereadonly Or %ofn_longnames Or %ofn_pathmustexist Or %ofn_nochangedir
              
                OFN.LpStrDefExt                 = %NULL
                OFN.nFilterIndex                = 0&
              
              
                ' set the common stuff which does not vary...
                szFileTitle                     = ""   ' no default filenamme
                OFN.LpStrFile                   = VarPtr (szFileTitle)
                OFN.nMaxFile                    = SizeOf (szFileTitle)
                ' since the owner window may vary for the same sub across calls...
                OFN.hWndOwner                   = hWnd
              
                ' call the common dialog
                Stat = GetOpenFileName (OFN)
              
                If IsTrue (Stat) Then
                   W                    = Space$(OFN.NMaxFile)
                   pFullName            = OFN.LpStrFile
                   W                    = @pFullName
                   W                    = Trim$(W, Any Chr$(0, &h20))
                   Function             = W
                Else
                   Local eCD As Dword
                   eCD                  = CommDlgExtendedError
                   If ECD <> 0 Then
                      MsgBox "GetOpen/SaveFileName failed on error#" & Str$(eCD), %mb_applmodal Or %mb_iconinformation, "Yikes!!!
                   End If
                   Function             = ""
                End If
              End Function
              
              
              '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
              'jhm: added callback for Copy button
              CallBack Function CB_CopyToClipboard() As Long
                 'we only copy the current line
                 Local CurrentItem, ItemLength, lResult As Long
                 Local sBuf As String
                 If Cb.Msg = %wm_command And Cb.CtlMsg = %bn_clicked Then
                    CurrentItem = SendMessage(hList, %LB_GETCURSEL,  0, 0) 'Get 0-based index of current listbox item
                    ItemLength = SendMessage(hList, %LB_GETTEXTLEN, CurrentItem, 0) 'get the length of the current item
                    sBuf = Space$((ItemLength + 1)) 'create a buffer
                    SendMessage(hList, %LB_GETTEXT, CurrentItem, StrPtr(sBuf)) 'retrieve item's text
                    sBuf = Trim$(sBuf, Any $Spc & Chr$(0)) 'clean up the text
                    If Len(sBuf) = 0 Then
                       Statusbar Set Text hDlg, %SB_statusbar, 1, 0, "Nothing was selected!" ' (If multiple lines were selected, only the last was copied.)
                       MessageBeep (%mb_iconerror)      'make a noise to indicate failure
                    Else
                       Clipboard Set Text sBuf & $CrLf To lResult   'now using the new internal PB function
                       Statusbar Set Text hDlg, %SB_statusbar, 1, 0, "One line copied to the clipboard!" ' (If multiple lines were selected, only the last was copied.)
                       Sleep 600
                       MessageBeep (%mb_iconexclamation)      'make a noise to indicate "OK, Done."
                       Function = 1 'needs no further processing
                    End If
                    Sleep 1200
                    Statusbar Set Text hDlg, %SB_statusbar, 1, 0, ""
                 End If
              End Function     
              
              'jhm: added; enables user to click on listbox to select and copy current line to clipboard
              Macro mListboxClick
                 If Cb.CtlMsg = %lbn_selchange Then
                   Control Set Focus hDlg, %CMD_CopyToClipboard    'Put focus onto button, ready for Space bar or Enter activation
                 End If
                 If Cb.CtlMsg = %lbn_dblclk Then  'but if double clicked, do it immediately!
                   Control Send Cb.Hndl, %CMD_CopyToClipboard, %BM_CLICK, 0, 0
                 End If
              End Macro
              '++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
              
              
              '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
              '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
              CallBack Function DlgProc () As Long
              
                 Local sFileName As String, hCtrl As Long, w As String
              
                 Select Case As Long CbMsg
                 Case %wm_command
                    Select Case As Long CbCtl
                       Case %ID_BROWSE_FILE
              
                          sFileName  = BrowseForPEFile (CbHndl)
                          If Len(sFileName) Then
                             Control Set Text    CbHndl, %ID_SOURCE_FILE, sFileName
                             ' reset the listbox contents.
                             ListBox Reset CbHndl, %ID_IMPORTS
                             ListBox Reset CbHndl, %ID_EXPORTS
                             ' null out the version literal
                             Control Set Text hDlg, %ID_VERSION_LITERAL, ""
                          End If
              
                       Case %ID_CLOSE
                          Dialog End CbHndl, 0
              
                       Case %ID_IMPORTS
                          hList = GetDlgItem(CbHndl, %ID_IMPORTS)                   'Get listbox handle
                          mListboxClick
              
                       Case %ID_EXPORTS
                          hList = GetDlgItem(CbHndl, %ID_EXPORTS)                   'Get listbox handle
                          mListboxClick
              
                       Case %ID_ENUM
                          Call Dump()
              
                          Control Get Text  hDlg, %ID_SOURCE_FILE To sFileName
                          w  = FileVersionString (ByCopy sFileName)
                          Control Set Text  hDlg, %ID_VERSION_lITERAL, W
              
                       Case %ID_PRINT_IMPORTS
                          Call  PRintTheListboxContents (CbHndl, %ID_IMPORTS)
              
                       Case %ID_PRINT_EXPORTS
                          Call  PrintTheListboxContents (CbHndl, %ID_EXPORTS)
              
                       Case %ID_SOURCE_FILE
                          If CbCtlMsg = %en_change Then
                             Control Get Text CbHndl, %ID_SOURCE_FILE To sFileName
                             If Dir$(sFileName) = "" Then
                                Control Disable CbHndl, %ID_ENUM
                             Else
                                Control Enable  CbHndl, %ID_ENUM
                             End If
                          End If
                    End Select  ' of CBCTL
                 End Select
              End Function
              
              
              Function PBMain
                 
                  Dialog New %HWND_DESKTOP, "Enumerate Export/Import Functions from an Executable Image", 10, 10, 400, 260, %ds_center Or %ws_sysmenu To hDlg
              
                  Control Add Label,      hDlg, -1,   "Image Path", 2, 6, 40, 12,
                  Control Add TextBox,    hDlg, %ID_SOURCE_FILE, "", 44, 4, 294, 12,
                  Control Add Button,     hDlg, %ID_ENUM, "Enumerate", 174, 194, 47, 14
              
                  Control Add Button,     hDlg, %ID_BROWSE_FILE, "Browse", 342, 4, 47,14
              
                  ' add a place for file version
              
                  Control Add Label,     hdlg, -1, "File version",       2,  20, 40, 12
                  Control Add Label,     hDlg, %ID_VERSION_LITERAL, "", 43,  20, 60, 12
              
                  Control Add ListBox,   hDlg, %ID_EXPORTS, ,   2, 33, 194, 163, %LB_STYLE
                  Control Add ListBox,   hDlg, %ID_IMPORTS, , 200, 33, 194, 163, %LB_STYLE
              
                  ' add captions to the listboxes (no DDT Command)
                  Control Set Text hDlg, %ID_IMPORTS, "Imports"
                  Control Set Text hDlg, %ID_EXPORTS, "Exports"
              
                  ' add buttons for printing the lists...
              
                  Control Add Button,     hDlg, %ID_PRINT_EXPORTS, "Print Export List", 68,  194, 60,14
                  Control Add Button,     hDlg, %ID_PRINT_IMPORTS, "Print Import List", 262, 194, 60,14
              
                  ' and add exit button so you can exit without trying to hit that dinky little 'x'
                  Control Add Button,     hDLG, %ID_CLOSE,        "E&xit",  342, 212, 47,14
              
                  'jhm: added button (code will be added in the future)
                  Control Add Button,     hDLG, %CMD_CopyToClipboard, "&Copy 1 line to clipboard", 156, 212, 85, 14, %ws_tabstop Call CB_CopyToClipboard
                  Control Add Statusbar,  hDlg, %SB_statusbar, "", 0, 0, 40, 12
              
                  Dialog Show Modal hDlg  Call DlgProc
              End Function
              '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
              '%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
              
              Function PrintTheListBoxContents (ByVal hDlg As Long, ByVal idCtrl As Long) As Long
              ' idctrl: Listbox Control ID, assumed child of hDlg
              ' No DDT command to retrieve listbox text by index (row #).  Bummer.
              
                Local szFile As Asciiz * %MAX_PATH, hFile As Long, e As Long, nRow As Long, Z As Long
                Local szItem As Asciiz * 128
                Local w As String, sFilename As String
              
                szFile  = "enum_imp_exp_listing.txt"
              
                hFile = FreeFile
                Open    szFile For Output As hFile
              
                Control Get Text  hDlg, %ID_SOURCE_FILE To sFileName
              
                W        = "Listing of " & IIf$(idCtrl=%ID_IMPORTS, "imported", "exported") & " functions for file " & sFilename
                Print       #hFile, W
              
                'added from an MCM forum message:
                Control Get Text  hDlg, %ID_VERSION_LITERAL To W
                Print # hFile, Using$ ("File version &", W)
              
                W        = "Run Date & Time " & Date$ & Space$(4) & Time$
                Print       #hFile, W
                Print       #hFile,
              
                Control Send hDlg, idCtrl, %LB_GETCOUNT , 0,0 To nRow    ' how many items in lb?
              
                For Z = 0 To nRow -1
                      Control Send hDlg, idctrl, %LB_GETTEXT, Z, VarPtr(szItem)
                      Print #hFile, szItem
                Next
              
                w = Space$(8) &  Using$("END OF REPORT  #####  items printed", nRow)
                Print #hFile, w
              
                Close hFile
              
                E  = Shell ("notepad.exe " & szFile)
              End Function
              
              
              Function FileVersionString(szFile As Asciiz) As String
                Local major As Long, Minor As Long, Build As Long, SubBuild As Long
                Local ResSize As Long
                Local ffi  As VS_FIXEDFILEINFO Ptr
                Local  ret As Long
                Local Buffer As String
              
                Major=0: Minor = 0:  Build = 0
              
                ResSize = GetFileVersionInfoSize (szFile, ret)
                If ResSize= 0 Then
                  Function = "No Version Info"
                  Exit Function
                End If
              
                Buffer      = Space$(ResSize)
                Ret         =  GetFileVersionInfo(szFile, %NULL, ResSize, ByVal StrPtr(Buffer))
              
              ' ** Read the VS_FIXEDFILEINFO info
                VerQueryValue ByVal StrPtr(Buffer), "\", ffi, SizeOf(@ffi)
                Major        = @ffi.dwProductVersionMs  \ &h10000
                Minor        = @ffi.dwProductVersionMs Mod &h10000
                Build        = @ffi.dwProductVersionLS Mod &h10000  ' this is for MY software which uses VERSION_MAJOR, VERSION_MINOR, 0, VERSION_BUILD under FILEVERSION
                SubBuild     = @ffi.dwProductVersionLS \  &h10000
              
                Function = Str$(Major) & "." & Trim$(Str$(Minor)) & "." & LTrim$(Str$(Build))  & "." & LTrim$(Str$(SubBuild))
              
              End Function
              ' // END OF FILE
              Attached Files
              Last edited by John Montenigro; 16 Feb 2009, 07:16 PM. Reason: modified Copy, in case nothing selected; added zip of soure and exe

              Comment


              • #8
                just another flavour of it

                Code:
                'enum_imp_exp.bas    by various artists
                'the basic code below is suggested by Matt Pietrek's PEDUMP.
                
                'Purpose:
                'Open an .EXE or .DLL and display what function calls it imports and exports
                
                ' --[ HISTORY ]----------
                ' ORIGINAL: http://www.powerbasic.com/support/forums/Forum7/HTML/001212.html
                '           Torsten Rienow  11/21/2001 (PB/DLL 6.0)
                ' 6/4/04   (MCM) Migrated to compiler PB win v7.02 from 6.0 to see if it still works;
                '          added suffix "_I" to many UDTS, which are now defined in Win32API.INC, often differently.
                '          Got compiled with 7.02 And apparently running just fine.
                
                ' 8/7/04 (MCM) Add: Browse for file...print lists, explicit exit button. Cosmetic changes too.
                '          Change from control level callback on ID_ENUM to explicit call in DlgProc, add target file
                '          version literal string, only enable enum button if we have a good file. Change from hard-coded
                '          control ID literals to equates, drop IDs where not needed, change from label+Listbox to listboxes
                '          using WS_CAPTION style.
                ' 2/14/09 (jhm) removed spurious chars and updated pointer params to BYVAL
                '               Raised the Exit button position.
                ' 2/16/09 (jhm) Re-arranged controls for my comfort, and added CopyToClipboard and statusbar
                '
                ' 7/2/2013 [jk] a new GUI with a search option, removed some portions of previous code
                
                ' -----[ USE AND DISTRIBUTION ]-------------------------------------------------------------------
                '  Mr Rienow put no disclaimer in this code. Mr. Mattias places whatever portions of this program
                '  were his into the public domain. August 7 2004.
                '  my changes and additions are public domain, jk june 22 2013
                '-------------------------------------------------------------------------------------------------
                
                
                '*************************************************************************************************
                ' To Do:
                
                '***********************************************************************************************
                ' clipboard
                ' print
                
                
                '***********************************************************************************************
                '***********************************************************************************************
                
                
                '#UTILITY gpf
                
                #DIM ALL
                #COMPILER PBWIN 10
                #COMPILE EXE
                #INCLUDE "win32api.inc"
                
                
                #RESOURCE PBR "imp-exp-spy.pbr"
                
                
                '***********************************************************************************************
                ' global variables
                '***********************************************************************************************
                GLOBAL hwnd  AS LONG                                  'main window handle
                GLOBAL hinst AS DWORD                                 'instance handle
                GLOBAL hstatus AS DWORD                               'statusbar handle
                GLOBAL hcombo AS DWORD                                'combobox handle
                GLOBAL hedit AS DWORD                                 'edit window in combobox handle
                GLOBAL tflag     AS LONG                              'threadflag (control watch thread)
                GLOBAL oldstatusproc AS DWORD
                
                GLOBAL hlv1 AS DWORD                                  'right listview handle
                GLOBAL hlv2 AS DWORD                                  'middle listview handle
                GLOBAL hlv3 AS DWORD                                  'left listview handle
                
                
                TYPE bytetype
                  st AS BYTE                                          'reserved
                  fc AS BYTE                                          'foreground color
                  bc AS BYTE                                          'background color
                  xx AS BYTE                                          'stateicon (import/export)
                END TYPE
                
                
                TYPE bytetype1
                  i  AS LONG                                          'index
                  st AS BYTE                                          'stateicon (plus/minus)
                  fc AS BYTE                                          'foreground color
                  bc AS BYTE                                          'background color
                  xx AS BYTE                                          'reserved
                END TYPE
                
                
                TYPE exinfo
                  stat  AS DWORD                                      'stateicon
                  ex    AS DWORD                                      '1=exe, 2=dll
                  expos AS DWORD                                      'index for a2()
                  excnt AS DWORD                                      '# of exports
                  impos AS DWORD                                      'index for a3()
                  imcnt AS DWORD                                      '# of imports
                  bc    AS DWORD                                      'backcolor (searchmode)
                END TYPE
                
                
                GLOBAL xd() AS exinfo                                 'extra info
                GLOBAL a1() AS STRING                                 'filename(s)
                GLOBAL a2() AS STRING                                 'filename1/exports, filename2/exports ...
                GLOBAL a3() AS STRING                                 'filename1/imort lib/imports, filename2/import lib/imports ...
                
                
                GLOBAL t1() AS bytetype1                              'drawing info for a1()
                GLOBAL t2() AS bytetype                               'drawing info for a2()
                GLOBAL t3() AS bytetype                               'drawing info for a3()
                
                
                GLOBAL n1   AS DWORD                                  '# of entries in a1() (-1, zerobased)
                GLOBAL n2   AS DWORD                                  '# of entries in a2() (-1, zerobased)
                GLOBAL n3   AS DWORD                                  '# of entries in a3() (-1, zerobased)
                
                
                '*************************************************************************************************
                ' equates
                '*************************************************************************************************
                %mg                          = 10                     'gap for drawing
                %st                          = 3                      '# of parts in statusbar (zero based)
                
                
                %IDC_STATUS                  = 109&
                %IDC_COMBO                   = 110&
                %IDC_LV1                     = 111&
                %IDC_LV2                     = 112&
                %IDC_LV3                     = 113&
                
                
                %ID_BROWSE_FILE              = 1011&
                %ID_PRINT                    = 1013&
                %ID_CLEAR                    = 1001&
                %ID_CLOSE                    = 1015&
                %ID_OpenCombo                = 1016&
                
                %ID_SEARCH                   = 2001&
                %ID_TOOLTIP                  = 2002&
                
                %ID_HELP                     = 9016&
                %ID_ABOUT                    = 9017&
                
                
                %OFN_FILEBUFFERSIZE = 16384
                
                %IMAGE_DOS_SIGNATURE         = &H5A4D
                %IMAGE_NT_SIGNATURE          = &H00004550
                %IMAGE_SIZEOF_SHORT_NAME     = 8
                %IMAGE_SIZEOF_SECTION_HEADER = 40
                %IMAGE_ORDINAL_FLAG          = &H80000000
                
                
                '***********************************************************************************************
                ' types
                '***********************************************************************************************
                
                
                UNION MISC
                  PhysicalAddress AS DWORD
                  VirtualSize     AS DWORD
                END UNION
                
                
                TYPE IMAGE_SECTION_HEADER_I
                  Name_(%IMAGE_SIZEOF_SHORT_NAME - 1) AS BYTE
                  Misc                                AS MISC
                  VirtualAddress                      AS DWORD
                  SizeOfRawData                       AS DWORD
                  PointerToRawData                    AS DWORD
                  PointerToRelocations                AS DWORD
                  PointerToLinenumbers                AS DWORD
                  NumberOfRelocations                 AS WORD
                  NumberOfLinenumbers                 AS WORD
                  Characteristics                     AS DWORD
                END TYPE
                
                
                TYPE IMAGE_DATA_DIRECTORY
                  VirtualAddress AS DWORD
                  nSize          AS DWORD
                END TYPE
                
                
                TYPE IMAGE_OPTIONAL_HEADER_I
                  Magic                                                AS WORD
                  MajorLinkerVersion                                   AS BYTE
                  MinorLinkerVersion                                   AS BYTE
                  SizeOfCode                                           AS DWORD
                  SizeOfInitializedData                                AS DWORD
                  SizeOfUninitializedData                              AS DWORD
                  AddressOfEntryPoint                                  AS DWORD
                  BaseOfCode                                           AS DWORD
                  BaseOfData                                           AS DWORD
                  ImageBase                                            AS DWORD
                  SectionAlignment                                     AS DWORD
                  FileAlignment                                        AS DWORD
                  MajorOperatingSystemVersion                          AS WORD
                  MinorOperatingSystemVersion                          AS WORD
                  MajorImageVersion                                    AS WORD
                  MinorImageVersion                                    AS WORD
                  MajorSubsystemVersion                                AS WORD
                  MinorSubsystemVersion                                AS WORD
                  Reserved1                                            AS DWORD
                  SizeOfImage                                          AS DWORD
                  SizeOfHeaders                                        AS DWORD
                  CheckSum                                             AS DWORD
                  Subsystem                                            AS WORD
                  DllCharacteristics                                   AS WORD
                  SizeOfStackReserve                                   AS DWORD
                  SizeOfStackCommit                                    AS DWORD
                  SizeOfHeapReserve                                    AS DWORD
                  SizeOfHeapCommit                                     AS DWORD
                  LoaderFlags                                          AS DWORD
                  NumberOfRvaAndSizes                                  AS DWORD
                  DataDirectory(%IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1) AS IMAGE_DATA_DIRECTORY
                END TYPE
                
                
                TYPE IMAGE_FILE_HEADER
                  Machine              AS WORD
                  NumberOfSections     AS WORD
                  TimeDateStamp        AS DWORD
                  PointerToSymbolTable AS DWORD
                  NumberOfSymbols      AS DWORD
                  SizeOfOptionalHeader AS WORD
                  Characteristics      AS WORD
                END TYPE
                
                
                TYPE IMAGE_NT_HEADERS_I
                  Signature      AS DWORD
                  FileHeader     AS IMAGE_FILE_HEADER
                  OptionalHeader AS IMAGE_OPTIONAL_HEADER_I
                END TYPE
                
                
                TYPE IMAGE_EXPORT_DIRECTORY_I
                  Characteristics       AS DWORD
                  TimeDateStamp         AS DWORD
                  MajorVersion          AS WORD
                  MinorVersion          AS WORD
                  nName                 AS DWORD
                  nBase                 AS DWORD
                  NumberOfFunctions     AS DWORD
                  NumberOfNames         AS DWORD
                  AddressOfFunctions    AS DWORD
                  AddressOfNames        AS DWORD
                  AddressOfNameOrdinals AS DWORD
                END TYPE
                
                
                TYPE IMAGE_IMPORT_DESCRIPTOR_I
                  OriginalFirstThunk AS DWORD
                  TimeDateStamp      AS DWORD
                  ForwarderChain     AS DWORD
                  Name_              AS DWORD
                  FirstThunk         AS DWORD
                END TYPE
                
                
                UNION u1 DWORD
                  ForwarderString AS BYTE PTR
                  pFunction       AS DWORD PTR
                  Ordinal         AS DWORD
                  AddressOfData   AS DWORD
                END UNION
                
                
                TYPE IMAGE_THUNK_DATA_I
                  u1 AS u1
                END TYPE
                
                
                TYPE IMAGE_DOS_HEADER
                  e_magic    AS WORD
                  e_cblp     AS WORD
                  e_cp       AS WORD
                  e_crlc     AS WORD
                  e_cparhdr  AS WORD
                  e_minalloc AS WORD
                  e_maxalloc AS WORD
                  e_ss       AS WORD
                  e_sp       AS WORD
                  e_csum     AS WORD
                  e_ip       AS WORD
                  e_cs       AS WORD
                  e_lfarlc   AS WORD
                  e_ovno     AS WORD
                  e_res(3)   AS WORD
                  e_oemid    AS WORD
                  e_oeminfo  AS WORD
                  e_res2(9)  AS WORD
                  e_lfanew   AS LONG
                END TYPE
                
                
                '*************************************************************************************************
                '***********************************************************************************************
                
                
                FUNCTION PtrToString(BYVAL inPtr AS BYTE PTR) AS STRING
                '*************************************************************************************************
                '
                '*************************************************************************************************
                  DIM i AS LONG
                  DIM s AS STRING
                
                  DO WHILE @inPtr[i] <> 0
                    s = s + CHR$(@inPtr[i])
                    INCR i
                  LOOP
                
                  FUNCTION = s
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION IMAGE_FIRST_SECTION(BYVAL pNTHeader AS IMAGE_NT_HEADERS_I PTR) AS DWORD
                '*************************************************************************************************
                '
                '*************************************************************************************************
                  FUNCTION = pNTHeader + 24 + @pNTHeader.FileHeader.SizeOfOptionalHeader
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION GetEnclosingSectionHeader(BYVAL rva AS DWORD, BYVAL pNTHeader AS IMAGE_NT_HEADERS_I PTR) AS DWORD
                '*************************************************************************************************
                '
                '*************************************************************************************************
                  DIM section AS IMAGE_SECTION_HEADER_I PTR
                  DIM i AS LONG
                
                  section = IMAGE_FIRST_SECTION(BYVAL pNTHeader)
                
                  FOR i = 0 TO @pNTHeader.FileHeader.NumberOfSections
                    IF((rva >= @section.VirtualAddress) AND(rva <(@section.VirtualAddress + @section.Misc.VirtualSize))) THEN
                      FUNCTION = section
                      EXIT FUNCTION
                    END IF
                
                    section = section + SIZEOF(@section)
                  NEXT
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION DumpImportsSection(BYVAL pBase AS DWORD, BYVAL pNTHeader AS IMAGE_NT_HEADERS_I PTR) AS LONG
                '*************************************************************************************************
                '
                '*************************************************************************************************
                  DIM pHeader AS IMAGE_SECTION_HEADER_I PTR
                  DIM pImportDesc AS IMAGE_IMPORT_DESCRIPTOR_I PTR
                  DIM pThunk AS IMAGE_THUNK_DATA_I PTR
                  DIM delta AS LONG
                  DIM importsStartRVA AS DWORD
                  DIM importsEndRVA AS DWORD
                '  DIM entryPointRVA AS DWORD
                  DIM exportsStartRVA AS DWORD
                  DIM exportsEndRVA AS DWORD
                  DIM i AS DWORD
                  DIM j AS DWORD
                  DIM sFunctionName AS ASCIIZ * 512
                  DIM sDll AS ASCIIZ * 512
                LOCAL fv AS STRING
                LOCAL n AS LONG
                
                
                  importsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).VirtualAddress
                  importsEndRVA = importsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_IMPORT).nSize
                
                  pHeader = GetEnclosingSectionHeader(importsStartRVA, BYVAL pNTHeader)
                
                  IF pHeader = 0 THEN
                    EXIT FUNCTION
                  END IF
                
                
                  IF n3 MOD 1000 = 0 THEN REDIM PRESERVE a3(0 TO n3+1000) : REDIM PRESERVE t3(0 TO n3+1000)
                  a3(n3)=a1(n1-1)
                  t3(n3).fc=xd(n1-1).ex
                  n=n3
                  INCR n3
                
                
                  delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
                  pImportDesc = pBase + importsStartRVA - delta
                
                  i = 0
                
                  DO
                    IF(@pImportDesc[i].TimeDateStamp = 0) AND(@pImportDesc[i].Name_ = 0) THEN
                      EXIT DO
                    END IF
                
                    sDll = PtrToString(BYVAL @pImportDesc[i].Name_ - delta + pBase)
                    IF n3 MOD 1000 = 0 THEN REDIM PRESERVE a3(0 TO n3+1000) : REDIM PRESERVE t3(0 TO n3+1000)
                    fv=FileVersionString(sdll)
                    a3(n3)="  "+UCASE$(sdll)+"|"+fv
                    IF UCASE$(RIGHT$(sdll, 4)) = ".EXE" THEN
                      xd(n1).ex = 1                                     'exe
                      t3(n3).fc = 1
                    ELSE
                      xd(n1).ex = 2                                     'dll
                      t3(n3).fc = 2
                    END IF
                
                    xd(n1-1).imcnt = n3 - xd(n1-1).impos
                    xd(n1).impos = n3 + 1
                
                    a1(n1)= "  " + MCASE$(MID$(sdll, 1, INSTR(-1, sdll, ".")-1))+LCASE$(PATHNAME$(EXTN, sdll))+"|"+fv 'store name
                    INCR n1
                    INCR n3
                
                    j = 0
                    pThunk = @pImportDesc[i].FirstThunk - delta + pBase
                
                    exportsStartRVA = @pHeader.VirtualAddress
                    exportsEndRVA = exportsStartRVA + @pHeader.SizeOfRawData
                
                    IF(pThunk <= exportsStartRVA) OR(pThunk >= exportsEndRVA) THEN
                      IF(@pImportDesc[i].OriginalFirstThunk = 0) THEN
                        EXIT FUNCTION
                      END IF
                
                      pThunk = @pImportDesc[i].OriginalFirstThunk
                
                      IF(pThunk <= exportsStartRVA) OR(pThunk >= exportsEndRVA) THEN
                        EXIT FUNCTION
                      END IF
                
                      pThunk = pThunk - delta + pBase
                    END IF
                
                    DO
                      IF(@pThunk[j].u1.AddressOfData = 0) THEN
                        EXIT DO
                      END IF
                
                      IF(@pThunk[j].u1.Ordinal AND %IMAGE_ORDINAL_FLAG) THEN
                        sFunctionName = "      #" + FORMAT$(@pThunk[j].u1.Ordinal AND &HFFFF??)
                
                      ELSE
                        sFunctionName = "      " + PtrToString(BYVAL @pThunk[j].u1.AddressOfData - delta + pBase + 2)
                      END IF
                
                      IF n3 MOD 1000 = 0 THEN REDIM PRESERVE a3(0 TO n3+1000) : REDIM PRESERVE t3(0 TO n3+1000)
                      a3(n3)=sFunctionName
                      t3(n3).xx=4
                      INCR n3
                      AddToCombo(sFunctionname)
                
                      INCR j
                    LOOP
                
                    INCR i
                  LOOP
                
                
                  IF n3=n+1 THEN                                      'no imports
                    n3=n                                              'remove module entry
                  ELSE
                    xd(n1-1).imcnt = n3 - xd(n1-1).impos              'complete imports count
                  END IF
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION DumpExportsSection(BYVAL pBase AS DWORD, BYVAL pNTHeader AS IMAGE_NT_HEADERS_I PTR) AS LONG
                '*************************************************************************************************
                '
                '*************************************************************************************************
                  DIM pExportDir AS IMAGE_EXPORT_DIRECTORY_I PTR
                  DIM pHeader AS IMAGE_SECTION_HEADER_I PTR
                  DIM delta AS LONG
                  DIM entryPointRVA AS DWORD
                  DIM exportsStartRVA AS DWORD
                  DIM exportsEndRVA AS DWORD
                  DIM pFunctions AS DWORD PTR
                  DIM pOrdinals AS WORD PTR
                  DIM pNames AS DWORD PTR
                  DIM i AS DWORD
                  DIM j AS DWORD
                  DIM flag AS LONG
                  DIM sFunctionName AS ASCIIZ * 256
                LOCAL n AS LONG
                
                
                  exportsStartRVA = @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).VirtualAddress
                  exportsEndRVA = exportsStartRVA + @pNTHeader.OptionalHeader.DataDirectory(%IMAGE_DIRECTORY_ENTRY_EXPORT).nSize
                
                  pHeader = GetEnclosingSectionHeader(exportsStartRVA, BYVAL pNTHeader)
                
                  IF pHeader = 0 THEN
                    EXIT FUNCTION
                  END IF
                
                
                  n=n2                                                'save initial value
                  IF n2 MOD 1000 = 0 THEN REDIM PRESERVE a2(0 TO n2+1000) : REDIM PRESERVE t2(0 TO n2+1000)
                  a2(n2)=a1(n1-1)
                  t2(n2).fc=xd(n1-1).ex
                  INCR n2
                
                
                  delta = @pHeader.VirtualAddress - @pHeader.PointerToRawData
                  pExportDir = pBASE + exportsStartRVA - delta
                  pFunctions = @pExportDir.AddressOfFunctions - delta + pBase
                  pOrdinals = @pExportDir.AddressOfNameOrdinals - delta + pBase
                  pNames = @pExportDir.AddressOfNames - delta + pBase
                
                  FOR i = 0 TO @pExportDir.NumberOfFunctions - 1
                    entryPointRVA = @pFunctions[i]
                    j = 0
                    flag = 0
                
                    IF entryPointRVA <> 0 THEN
                      FOR j = 0 TO @pExportDir.NumberOfNames - 1
                        IF @pOrdinals[j] = i THEN
                          sFunctionName = PtrToString(BYVAL @pNames[j] - delta + pBase)
                
                          IF n2 MOD 1000 = 0 THEN REDIM PRESERVE a2(0 TO n2+1000) : REDIM PRESERVE t2(0 TO n2+1000)
                          a2(n2)="  "+sFunctionName
                          t2(n2).xx=3
                          INCR n2
                          AddToCombo(sFunctionname)
                
                          flag = 1
                        END IF
                      NEXT
                
                      IF(entryPointRVA >= exportsStartRVA) AND(entryPointRVA <= exportsEndRVA) THEN
                        sFunctionName = PtrToString(BYVAL entryPointRVA - delta + pBase)
                        flag = 1
                      END IF
                    END IF
                  NEXT
                
                
                  IF n2=n+1 THEN n2=n                                 'reset in case there are no exports !
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION DumpExeFile(BYVAL dosHeader AS IMAGE_DOS_HEADER PTR) AS LONG
                '*************************************************************************************************
                '
                '*************************************************************************************************
                  DIM pNTHeader AS IMAGE_NT_HEADERS_I PTR
                  DIM pBase AS DWORD
                
                  pBase = dosHeader
                  pNTHeader = dosHeader + @dosHeader.e_lfanew
                
                
                  IF(IsBadReadPtr(pNTHeader, SIZEOF(pNTHeader)) OR @pNTHeader.Signature <> %IMAGE_NT_SIGNATURE) THEN
                    MSGBOX "Unhandled EXE type, or invalid .EXE", %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                    EXIT FUNCTION
                  END IF
                
                  CALL DumpExportsSection(pBase, BYVAL pNTHeader)
                  CALL DumpImportsSection(pBase, BYVAL pNTHeader)
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION Dump(fname AS ASCIIZ) AS LONG
                '*************************************************************************************************
                '
                '*************************************************************************************************
                DIM hFile AS LONG
                DIM hFileMapping AS LONG
                DIM lpFileBase AS LONG
                DIM dosHeader AS IMAGE_DOS_HEADER PTR
                LOCAL szext AS ASCIIZ * 32
                LOCAL n AS LONG
                
                
                  szext = LCASE$(PATHNAME$(EXTN, fname))
                  IF (szext <> ".exe" AND szext <> ".dll") THEN EXIT FUNCTION
                
                
                  hFile = CreateFile(fName, %GENERIC_READ, %FILE_SHARE_READ, BYVAL 0&, %OPEN_EXISTING, %FILE_ATTRIBUTE_NORMAL, 0)
                
                  IF hFile = %INVALID_HANDLE_VALUE THEN
                    MSGBOX "Couldn't open file with CreateFile()", %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                    EXIT FUNCTION
                  END IF
                
                  hFileMapping = CreateFileMapping(hFile, BYVAL 0&, %PAGE_READONLY, 0, 0, BYVAL 0&)
                
                  IF hFileMapping = 0 THEN
                    CALL CloseHandle(hFile)
                    MSGBOX "Couldn't open file mapping with CreateFileMapping()", %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                    EXIT FUNCTION
                  END IF
                
                  lpFileBase = MapViewOfFile(hFileMapping, %FILE_MAP_READ, 0, 0, 0)
                
                  IF lpFileBase = 0 THEN
                    CALL CloseHandle(hFileMapping)
                    CALL CloseHandle(hFile)
                    MSGBOX "Couldn't map view of file with MapViewOfFile()", %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                    EXIT FUNCTION
                  END IF
                
                
                  showwindow hcombo, %SW_HIDE
                  n=n1                                                'save initial value
                  xd(n1).expos = n2
                  xd(n1).impos = n3
                
                
                  IF n1 MOD 1000 = 0 THEN REDIM PRESERVE a1(0 TO n1+1000)
                  a1(n1)=MCASE$(MID$(fname, 1, INSTR(-1, fname, ".")-1))+LCASE$(PATHNAME$(EXTN, fname))+"|"+FileVersionString(fname) 'store name
                
                  IF UCASE$(RIGHT$(fname, 4)) = ".EXE" THEN
                    xd(n1).ex = 1                                     'exe
                  ELSE
                    xd(n1).ex = 2                                     'dll
                  END IF
                  xd(n1).stat = 1
                  INCR n1
                
                
                  dosHeader = lpFileBase
                
                  IF(@dosHeader.e_magic = %IMAGE_DOS_SIGNATURE) THEN
                    CALL DumpExeFile(BYVAL dosHeader)
                  END IF
                
                  CALL UnmapViewOfFile(lpFileBase)
                  CALL CloseHandle(hFileMapping)
                  CALL CloseHandle(hFile)
                
                
                  xd(n).excnt = n2 - xd(n).expos                    'store count
                  xd(n).imcnt = n3 - xd(n).impos
                
                  FUNCTION = 1
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION ofnhook( BYVAL hdlg AS LONG, BYVAL wMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG ) AS LONG
                '***********************************************************************************************
                ' getopenfilename callback (center in parent)
                '***********************************************************************************************
                LOCAL X AS LONG, Y AS LONG, R AS RECT, ofnPtr AS OFNOTIFY PTR
                
                
                  SELECT CASE wMsg
                     CASE %WM_NOTIFY
                        ofnPtr = lParam
                        SELECT CASE @ofnPtr.hdr.Code
                           CASE %CDN_INITDONE
                                                                      'CENTER DIALOG IN PARENT
                              GetWindowRect GetParent(GetParent(hdlg)), R     'get parent's data - dialog is child of child..
                              X = R.nLeft + ((R.nRight   - R.nLeft) \ 2)      'calculate parent's width
                              Y = R.nTop  + ((R.nBottom  - R.nTop)  \ 2)      'calculate parent's height
                
                              GetWindowRect GetParent(hdlg), R                'get dialog's width and height
                              X = X - (( R.nRight   - R.nLeft ) \ 2)
                              Y = Y - (( R.nBottom  - R.nTop  ) \ 2)
                              SetWindowPos GetParent(hdlg), %NULL, X, Y, 0, 0, %SWP_NOSIZE OR %SWP_NOZORDER 'set centered pos
                
                              FUNCTION = %true
                              EXIT FUNCTION
                
                        END SELECT
                  END SELECT
                  FUNCTION = %false
                
                END FUNCTION
                
                
                '***********************************************************************************************
                
                
                FUNCTION BrowseForPEFile(BYVAL hWnd AS LONG) AS STRING
                '*************************************************************************************************
                ' returns: name of file selected or NULL if no file
                '*************************************************************************************************
                LOCAL OFN         AS OPENFILENAME
                LOCAL eCD         AS DWORD
                LOCAL sFilter     AS STRING
                LOCAL sTitle      AS STRING
                LOCAL szFileTitle AS STRING
                LOCAL Stat        AS LONG
                LOCAL W           AS STRING
                
                
                  OFN.lStructSize = SIZEOF(OFN)
                  OFN.nFilterIndex = 1
                  OFN.lpfnHook = CODEPTR(ofnhook)
                
                
                  sTitle = "Select Input File "
                  OFN.LpStrTitle = STRPTR(sTitle)
                
                  sFilter = "Executable Files (*.exe, *.dll)" & $NUL & "*.exe;*.dll" & $NUL & "All Files (*.*)" & $NUL & "*.*" & $NUL & $NUL
                  OFN.lpStrFilter = STRPTR(sFilter)
                  OFN.Flags = %OFN_ALLOWMULTISELECT OR %OFN_FILEMUSTEXIST OR %OFN_HIDEREADONLY OR %OFN_LONGNAMES OR %OFN_PATHMUSTEXIST OR %OFN_NOCHANGEDIR OR %OFN_Enablehook OR %OFN_EXPLORER
                
                
                  szFileTitle = $NUL+SPACE$(%OFN_FILEBUFFERSIZE)
                  OFN.LpStrFile = STRPTR(szFileTitle)
                  OFN.nMaxFile = LEN(szFileTitle)
                  OFN.hWndOwner = hWnd
                
                
                  Stat = GetOpenFileName(OFN)                         'call the common dialog
                  IF ISTRUE(Stat) THEN
                    W = EXTRACT$(szfiletitle, $NUL+$NUL)
                    FUNCTION = W
                  ELSE
                    eCD = CommDlgExtendedError
                    IF ECD <> 0 THEN
                      MSGBOX "GetOpen/SaveFileName failed on error#" & HEX$(eCD), %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                    END IF
                
                    FUNCTION = ""
                  END IF
                
                
                END FUNCTION
                
                
                '***********************************************************************************************
                
                
                CALLBACK FUNCTION DlgProc() AS LONG
                '*************************************************************************************************
                ' main callback
                '*************************************************************************************************
                LOCAL lvhit AS LV_HITTESTINFO
                LOCAL pNMLV   AS NM_LISTVIEW PTR
                LOCAL pLNMM     AS NMMOUSE PTR
                LOCAL pNMCUST AS NMLVCUSTOMDRAW PTR
                LOCAL pLVDI   AS LV_DISPINFO PTR
                'LOCAL pLVKD   AS NMLVKEYDOWN PTR
                'LOCAL pDis    AS DRAWITEMSTRUCT PTR
                LOCAL szName  AS ASCIIZ * %MAX_PATH
                LOCAL pt      AS POINT
                LOCAL p$
                LOCAL f$
                
                LOCAL pNMHDR  AS NMHDR PTR
                LOCAL i AS LONG
                LOCAL n AS LONG
                LOCAL z AS LONG
                LOCAL sFileName AS STRING
                LOCAL t         AS ASCIIZ * 128
                LOCAL lv        AS LONG                               'lv #
                LOCAL tm AS textmetric
                LOCAL textface AS ASCIIZ * 64
                LOCAL lf AS logfont
                LOCAL pNMI   AS NMLVGetinfotip PTR
                LOCAL pw     AS WSTRINGZ PTR
                
                
                STATIC fnd    AS ASCIIZ * 128
                STATIC s      AS ASCIIZ * 128
                STATIC bfont  AS DWORD                                 'bold font
                STATIC fflag  AS LONG                                  'firstflag (ensure this is done only once)
                STATIC wtext  AS WSTRINGZ * %MAX_PATH
                STATIC ttflag AS LONG
                STATIC fs     AS LONG
                
                
                  SELECT CASE AS LONG CBMSG
                    CASE %WM_INITDIALOG                               'init
                      IF COMMAND$<>"" THEN
                        postmessage hwnd, %WM_USER + 1001, 0, 0       'handle commandline arguments
                      END IF
                
                      checkmenuitem getmenu(hwnd), %ID_Tooltip, %MF_CHECKED
                      ttflag=1                                        'show tooltips
                
                
                   CASE %WM_DROPFILES                                 'drag´n drop
                     i=listview_getitemcount(hlv1)
                
                     n = DragQueryFile(CB.WPARAM, -1&, BYVAL 0, 0)    'get # of dropped files
                     z = 0
                     FOR i = 0 TO n - 1                               'Retrieve each file name
                       CALL DragQueryFile(CB.WPARAM, i, szname, %MAX_PATH)
                       z = z + dump(BYVAL VARPTR(szname))             'process single name
                     NEXT
                
                     CALL DragFinish(CB.WPARAM)
                     IF z>0 THEN
                       showwindow hcombo, %SW_HIDE
                       FOR n=0 TO n1                                  'reset backcolor in all listviews
                         t1(n).bc=0
                         xd(n).bc=0
                       NEXT n
                
                       FOR n=0 TO n2
                         t2(n).bc=0
                       NEXT n
                
                       FOR n=0 TO n3
                         t3(n).bc=0
                       NEXT n
                
                       postmessage hwnd, %WM_USER + 1000, i, 0        'setup listviews for display
                     ELSE
                       MSGBOX "No executables dropped !  ", %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                     END IF
                
                
                    CASE %WM_USER + 1001                              'process commandline
                      z=0 : n=0
                      WHILE 1
                        n = n + 1
                        sfilename=TRIM$(COMMAND$(n), CHR$(34))
                        IF sfilename="" THEN EXIT LOOP
                
                        IF PATHNAME$(PATH, sfilename)="" THEN
                          IF p$<>"" THEN
                            sfilename=p$+sfilename
                          ELSE
                            sfilename=CURDIR$+"\"+sfilename
                          END IF
                        ELSE
                          p$=PATHNAME$(PATH, sfilename)
                        END IF
                
                         z = z + dump(BYVAL STRPTR(sfilename))        'process single name
                      WEND
                
                      IF z>0 THEN
                        postmessage hwnd, %WM_USER + 1000, 0, 0       'setup listviews for display
                      ELSE
                        MSGBOX "No Executables in Commandline !  ", %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                      END IF
                
                
                    CASE %WM_USER + 1000                              'setup listviews for display
                      i=CB.WPARAM                                     'index
                
                      REDIM t1(0 TO n1)
                
                      z=0
                      FOR n=0 TO n1-1                                 'setup t1()
                        t1(z).st = xd(n).stat
                        t1(z).fc = xd(n).ex
                        t1(z).bc = xd(n).bc
                        t1(z).i  = n
                        INCR z
                
                        IF xd(n).stat=1 THEN                          'compressed -> skip following
                          DO
                            n = n +1
                            IF xd(n).stat<>0 THEN                     'until next
                              n = n -1
                              EXIT LOOP
                            END IF
                
                            IF n=n1-1 THEN EXIT LOOP                  'or until done
                          LOOP
                        END IF
                      NEXT n
                
                
                      ListView_SetItemCountEx hlv1, z, 0
                      ListView_SetItemCountEx hlv2, n2, 0
                      ListView_SetItemCountEx hlv3, n3, 0
                
                
                      n=xd(t1(i).i).impos
                      sendmessage hlv3, %WM_VSCROLL, %SB_BOTTOM, 0
                      listview_ensurevisible hlv3, n, 0
                      listview_setitemstate hlv3, n, %LVIS_Focused OR %LVIS_Selected, %LVIS_Focused OR %LVIS_Selected
                      listview_redrawitems hlv3, n, n
                
                
                      n=xd(t1(i).i).expos
                      sendmessage hlv2, %WM_VSCROLL, %SB_BOTTOM, 0
                      listview_ensurevisible hlv2, n, 0
                      listview_setitemstate hlv2, n, %LVIS_Focused OR %LVIS_Selected, %LVIS_Focused OR %LVIS_Selected
                      listview_redrawitems hlv2, n, n
                
                
                      listview_setitemstate hlv1, i, %LVIS_Focused OR %LVIS_Selected, %LVIS_Focused OR %LVIS_Selected
                      listview_redrawitems hlv1, i, i
                      setfocus hlv1
                
                
                      s=""
                      IF xd(t1(i).i).excnt>0 THEN
                        s="     "+CHR$(34)+TRIM$(PARSE$(a1(t1(i).i), "|", 1))+CHR$(34)+":  exports"+STR$(xd(t1(i).i).excnt-1)+" procedures"
                      END IF
                      IF xd(t1(i).i).imcnt>0 THEN
                        IF s="" THEN
                          s="     "+CHR$(34)+TRIM$(PARSE$(a1(t1(i).i), "|", 1))+CHR$(34)+":  imports"+STR$(xd(t1(i).i).imcnt)+" procedures"
                        ELSE
                          s=s+"  and imports"+STR$(xd(t1(i).i).imcnt)+" procedures"
                        END IF
                      END IF
                
                      IF xd(t1(i).i).stat=0 THEN
                        REPLACE "imports" WITH "supplies" IN s
                        IF ISFALSE (iswindowvisible(hcombo)) THEN
                          sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(s)                  'set status text
                        END IF
                        sendmessage hlv3, %WM_VSCROLL, %SB_BOTTOM, 0
                        listview_ensurevisible hlv3, xd(t1(i).i).impos-1, 0
                        EXIT FUNCTION
                
                
                      ELSE
                        IF xd(t1(i).i).imcnt>0 THEN                   'if there are imports -> count libs
                          z=0
                          FOR n=t1(i).i+1 TO n1-1
                            IF xd(n).stat>0 THEN EXIT FOR
                            z=z+1
                          NEXT n
                          IF z=1 THEN
                            s=s+" from 1 library"
                          ELSE
                            s=s+" from"+STR$(z)+" libraries
                          END IF
                          REPLACE "imports"+STR$(xd(t1(i).i).imcnt)+" procedures" WITH _
                                  "imports"+STR$(xd(t1(i).i).imcnt-z-1)+" procedures" IN s
                        END IF
                      END IF
                
                      IF ISFALSE (iswindowvisible(hcombo)) THEN
                        sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(s)                    'set status text
                      END IF
                
                
                    CASE %WM_NOTIFY                                   'notify messages for listviews and statusbar
                      IF LOWRD(CBWPARAM) = %idc_status THEN           'statusbar
                        pNMHDR = CBLPARAM
                        SELECT CASE @pNMHDR.code
                          CASE %NM_CLICK                              'click    (%NM_DBLCLK)
                            pLNMM = CBLPARAM
                            IF @pLNMM.dwItemSpec = 0 THEN
                              GOTO setsearchmode                      'if part 1 was clicked at -> enter search mode
                '            ELSEIF @pLNMM.dwItemSpec = 1 THEN
                '              IF iswindowvisible(hcombo) THEN
                '                [email protected]
                '                screentoclient hcombo, pt
                '                postmessage hcombo, %WM_LBUTTONDOWN, 0, MAK(DWORD, pt.x, @pLNMM.pt.y)
                '                postmessage hcombo, %WM_LBUTTONUP, 0, MAK(DWORD, pt.x, @pLNMM.pt.y)
                '***********************************************************************************************
                ' workaround to activate and expand combo, doesn´t work otherwise (why?)
                ' -> set statusbar as new parent, manage focus issues by subclass
                '***********************************************************************************************
                '              END IF
                            END IF
                        END SELECT
                
                
                      ELSEIF LOWRD(CBWPARAM) = %idc_LV1 THEN          'lv1
                        lv=1
                        GOTO dolv
                      ELSEIF LOWRD(CBWPARAM) = %idc_LV2 THEN          'lv1
                        lv=2
                        GOTO dolv
                      ELSEIF LOWRD(CBWPARAM) = %idc_LV3 THEN          'lv1
                        lv=3
                dolv:
                          pNMLV = CBLPARAM                            ' Obtain the NM_LISTVIEW pointer from CBLPARAM
                
                          SELECT CASE @pNMLV.hdr.code
                '            CASE %NM_HOVER                            'process mousehover (%LVS_Ex_Trackselect)
                
                
                            CASE %NM_CUSTOMDRAW                       'customdraw for listview
                              pNMCUST = CBLPARAM
                
                              SELECT CASE @pNMCUST.nmcd.dwDrawStage
                                CASE %CDDS_PREPAINT
                                    FUNCTION = %CDRF_NOTIFYITEMDRAW
                                    EXIT FUNCTION
                
                                CASE %CDDS_ITEMPREPAINT
                                    FUNCTION = %CDRF_NOTIFYSUBITEMDRAW
                                    EXIT FUNCTION
                
                                CASE %CDDS_ITEM OR %CDDS_SUBITEM OR %CDDS_PREPAINT
                                  IF fflag=0 THEN                     'do it only once
                                    fflag=1
                                    gettextmetrics @pNMCUST.nmcd.hdc, tm
                                    gettextface @pNMCUST.nmcd.hdc, 64, textface
                
                                    lf.lfHeight        = tm.tmHeight
                                    lf.lfWeight        = %FW_BOLD
                                    lf.lfItalic        = tm.tmItalic
                                    lf.lfUnderline     = tm.tmUnderlined
                                    lf.lfStrikeOut     = tm.tmStruckOut
                                    lf.lfCharSet       = tm.tmCharSet
                                    lf.lfPitchAndFamily = tm.tmPitchAndFamily
                                    lf.lfFaceName       = textface
                
                                    bfont = createfontindirect(lf)    'create a bold version of current listview font
                                  END IF
                
                
                                  IF (@pNMCUST.nmcd.uitemstate AND %CDIS_FOCUS) = %CDIS_FOCUS THEN
                                    @pNMCUST.clrTextBK = RGB(230, 230, 255)                 'set selection back color
                                  END IF
                
                '                   @[email protected] AND &HFFEE 'suppress selection and focus
                                  @[email protected] AND &HFFFE 'suppress selection
                
                
                                  SELECT CASE lv
                                    CASE 1
                                      IF t1(@pNMCUST.nmcd.dwItemSpec).fc = 1 THEN
                                        selectobject(@pNMCUST.nmcd.hdc, bfont)
                                        @pNMCUST.clrText = %BLUE
                                      ELSEIF t1(@pNMCUST.nmcd.dwItemSpec).fc = 2 THEN
                                        selectobject(@pNMCUST.nmcd.hdc, bfont)
                                        @pNMCUST.clrText = %MAGENTA
                                      END IF
                
                                      IF t1(@pNMCUST.nmcd.dwItemSpec).bc = 1 THEN
                                        @pNMCUST.clrTextBK = RGB(255, 230, 230)
                                      ELSEIF t1(@pNMCUST.nmcd.dwItemSpec).bc = 2 THEN
                                        @pNMCUST.clrTextBK = RGB(230, 255, 230)
                                      END IF
                
                                    CASE 2
                                      IF t2(@pNMCUST.nmcd.dwItemSpec).fc = 1 THEN
                                        selectobject(@pNMCUST.nmcd.hdc, bfont)
                                        @pNMCUST.clrText = %BLUE
                                      ELSEIF t2(@pNMCUST.nmcd.dwItemSpec).fc = 2 THEN
                                        selectobject(@pNMCUST.nmcd.hdc, bfont)
                                        @pNMCUST.clrText = %MAGENTA
                                      ELSE
                                        @pNMCUST.clrText = %BLACK
                                        IF t2(@pNMCUST.nmcd.dwItemSpec).bc = 1 THEN
                                          @pNMCUST.clrTextBK = RGB(255, 230, 230)
                                        END IF
                                      END IF
                
                                    CASE 3
                                      IF t3(@pNMCUST.nmcd.dwItemSpec).fc = 1 THEN
                                        selectobject(@pNMCUST.nmcd.hdc, bfont)
                                        @pNMCUST.clrText = %BLUE
                                      ELSEIF t3(@pNMCUST.nmcd.dwItemSpec).fc = 2 THEN
                                        selectobject(@pNMCUST.nmcd.hdc, bfont)
                                        @pNMCUST.clrText = %MAGENTA
                                      ELSE
                                        @pNMCUST.clrText = %BLACK
                                        IF t3(@pNMCUST.nmcd.dwItemSpec).bc = 2 THEN
                                          @pNMCUST.clrTextBK = RGB(230, 255, 230)
                                        END IF
                                      END IF
                                  END SELECT
                
                                FUNCTION = %CDRF_NEWFONT              'do customdraw
                                EXIT FUNCTION
                              END SELECT
                
                
                            CASE %LVN_GETINFOTIPW                     'virtual ListView asks for tooltip text
                              IF ttflag=0 THEN FUNCTION=1 : EXIT FUNCTION
                
                              pNMI=CB.LPARAM
                              SELECT CASE lv
                                CASE 1
                                  IF t1(@pNMI.iItem).fc>0 THEN
                                    wtext = PARSE$(a1(t1(@pNMI.iItem).i), "|", 2)
                                    wtext = LEFT$(wtext, @pNMI.cchTextMax)                'cut to appropriate size, if necessary
                                    [email protected]                  'get buffer pointer
                                    @pw=wtext                         'fill buffer with own info
                                    EXIT FUNCTION
                                  END IF
                                CASE 2
                                  IF t2(@pNMI.iItem).fc>0 THEN
                                    wtext = PARSE$(a2(@pNMI.iItem), "|", 2)
                                    wtext = LEFT$(wtext, @pNMI.cchTextMax)                'cut to appropriate size, if necessary
                                    [email protected]                  'get buffer pointer
                                    @pw=wtext                         'fill buffer with own info
                                    EXIT FUNCTION
                                  END IF
                                CASE 3
                                  IF t3(@pNMI.iItem).fc>0 THEN
                                    wtext = PARSE$(a3(@pNMI.iItem), "|", 2)
                                    wtext = LEFT$(wtext, @pNMI.cchTextMax)                'cut to appropriate size, if necessary
                                    [email protected]                  'get buffer pointer
                                    @pw=wtext                         'fill buffer with own info
                                    EXIT FUNCTION
                                  END IF
                
                              END SELECT
                
                
                            CASE %LVN_GETDISPINFOW                    'virtual ListView asks for Item text
                              pLVDI = CB.LPARAM
                              IF (@pLVDI.item.mask AND %LVIF_TEXT) THEN
                                SELECT CASE lv
                                  CASE 1
                                    wtext = PARSE$(a1(t1(@pLVDI.item.iItem).i), "|", 1)
                                  CASE 2
                                    wtext = PARSE$(a2(@pLVDI.item.iItem), "|", 1)
                                  CASE 3
                                    wtext = PARSE$(a3(@pLVDI.item.iItem), "|", 1)
                                END SELECT
                                @pLVDI.item.pszText = VARPTR(wtext)
                              END IF
                
                              IF lv=1 THEN
                                IF (@pLVDI.item.mask AND %LVIF_IMAGE) THEN
                                    @pLVDI.item.mask =%LVIF_STATE OR %LVIF_TEXT           'to show the state images the mask and statemask
                                    @pLVDI.item.statemask =%LVIS_STATEIMAGEMASK           'must be set to the following parameters
                                END IF
                
                                IF (@pLVDI.item.mask AND %LVIF_STATE) THEN                'virtual ListView asks for Item state image
                                  @pLVDI.item.state = INDEXTOSTATEIMAGEMASK(t1(@pLVDI.item.iItem).st)
                                END IF
                              ELSEIF lv=2 THEN
                                IF (@pLVDI.item.mask AND %LVIF_IMAGE) THEN
                                    @pLVDI.item.mask =%LVIF_STATE OR %LVIF_TEXT           'to show the state images the mask and statemask
                                    @pLVDI.item.statemask =%LVIS_STATEIMAGEMASK           'must be set to the following parameters
                                END IF
                
                                IF (@pLVDI.item.mask AND %LVIF_STATE) THEN                'virtual ListView asks for Item state image
                                  @pLVDI.item.state = INDEXTOSTATEIMAGEMASK(t2(@pLVDI.item.iItem).xx)
                                END IF
                              ELSEIF lv=3 THEN
                                IF (@pLVDI.item.mask AND %LVIF_IMAGE) THEN
                                    @pLVDI.item.mask =%LVIF_STATE OR %LVIF_TEXT           'to show the state images the mask and statemask
                                    @pLVDI.item.statemask =%LVIS_STATEIMAGEMASK           'must be set to the following parameters
                                END IF
                
                                IF (@pLVDI.item.mask AND %LVIF_STATE) THEN                'virtual ListView asks for Item state image
                                  @pLVDI.item.state = INDEXTOSTATEIMAGEMASK(t3(@pLVDI.item.iItem).xx)
                                END IF
                              END IF
                
                              FUNCTION=%true
                              EXIT FUNCTION
                
                
                            CASE %LVN_COLUMNCLICK                     ' Click on column header
                '                hHeader = SendMessage( hlv, %LVM_GETHEADER, 0, BYVAL 0)
                '                  szItem      = "File           "
                '                  hdi.mask    = %HDI_BITMAP OR %HDI_FORMAT OR %HDI_TEXT
                '                  hdi.pszText = VARPTR(szItem)
                '                  hdi.fmt     = %HDF_STRING OR %HDF_BITMAP OR %HDF_BITMAP_ON_RIGHT OR %HDF_Sortdown
                ''                  hdi.hbm  = hdown
                '                  SendMessage( hHeader, %HDM_SETITEM, 0, VARPTR(hdi))
                '                  hflag=1
                '
                '                  CALL sortlv(1)
                '
                
                            CASE %NM_CLICK
                              IF lv=1 THEN                            'this is for listview 1
                                [email protected]                        'get item #
                                IF n<0 THEN EXIT FUNCTION
                
                                IF xd(t1(n).i).stat=0 THEN
                
                                ELSE
                                  GetCursorPos lvhit.pt
                                  ScreenToClient hlv1, lvhit.pt
                
                                  SendMessage hlv1, %LVM_HITTEST, 0, VARPTR(lvhit)
                                  IF lvhit.flags = %LVHT_ONITEMSTATEICON THEN
                                    IF xd(t1(n).i).stat=1 THEN
                                      xd(t1(n).i).stat=2
                                    ELSE
                                      xd(t1(n).i).stat=1
                                    END IF
                                  END IF
                                END IF
                
                
                                postmessage hwnd, %WM_USER + 1000, n, 0                   'setup listviews for display
                              END IF
                
                '              [email protected]                   'store item
                '              [email protected]             'store subitem
                
                
                            CASE %NM_DBLCLK                         ' If double-click in ListView,
                              [email protected]                        'get item #
                              IF lv=1 THEN
                                EXIT FUNCTION
                              ELSE
                startsearch:
                                IF lv=2 THEN
                                  IF n<0 THEN EXIT FUNCTION
                
                                  IF t2(n).xx > 0 THEN
                                    fnd=TRIM$(a2(n))
                                    fs=2
                                  ELSE
                                    EXIT FUNCTION
                                  END IF
                                ELSEIF lv=3 THEN
                                  IF n<0 THEN EXIT FUNCTION
                
                                  IF t3(n).xx > 0 THEN
                                    fnd=TRIM$(a3(n))
                                    fs=3
                                  ELSE
                                    EXIT FUNCTION
                                  END IF
                                END IF
                
                                t="   Search Imports/Exports:"
                                sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(t)
                                setfocus hcombo
                                showwindow hcombo, %SW_SHOW
                                COMBOBOX FIND EXACT hstatus, %IDC_COMBO, 1, " "+fnd TO n
                                COMBOBOX SELECT hstatus, %IDC_COMBO, n
                                postmessage hwnd, %WM_COMMAND, MAKDWD(1, %BN_CLICKED), 10000
                              END IF
                
                
                '            CASE %LVN_KEYDOWN                         'keystroke in ListView,
                '              pLVKD = CBLPARAM
                
                
                        END SELECT
                
                
                '      ELSE                                            'not statusbar or a listview
                      END IF
                
                
                    CASE %WM_COMMAND
                      SELECT CASE AS LONG CB.CTL
                        CASE %ID_SEARCH                               'enter search mode
                setsearchmode:
                          t="   Search Imports/Exports:"
                          sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(t)                  'change part 1
                          showwindow hcombo, %SW_SHOW
                          setfocus hcombo
                          FUNCTION = %true
                          EXIT FUNCTION
                
                
                        CASE %IDOK                                    '<enter>
                          IF getfocus=hedit THEN
                            IF CB.CTLMSG=%BN_CLICKED THEN
                              sendmessage hcombo, %WM_Gettext, 128, VARPTR(fnd)
                              fnd=" "+TRIM$(fnd)
                              COMBOBOX FIND EXACT hstatus, %IDC_COMBO, 1, fnd TO n
                              IF n=0 THEN
                                setwindowtext hedit, ""
                                MSGBOX CHR$(34)+fnd+CHR$(34)+ "  not found !  ", %MB_ICONEXCLAMATION OR %MB_TOPMOST, "  Spy Error"
                              ELSE
                                fnd=LCASE$(TRIM$(fnd))
                
                                IF CB.LPARAM<>10000 THEN fs=0
                
                
                                FOR n=0 TO n1                         'reset backcolor in all listviews
                                  xd(n).bc=0
                                NEXT n
                
                                z=0
                                FOR n=0 TO n2-1                       'search for export
                                  t2(n).bc=0
                                  IF fnd=LCASE$(TRIM$(a2(n))) THEN
                                    t2(n).bc = 1
                                    FOR i=0 TO n1-1
                                      IF xd(i).stat>0 THEN
                                        IF xd(i).expos>n THEN
                                          EXIT FOR
                                        ELSE
                                          z=i
                                        END IF
                                      END IF
                                    NEXT i
                
                                    IF xd(z).excnt>0 THEN
                                      xd(z).bc = 1
                                    END IF
                                  END IF
                                NEXT n
                
                                z=0
                                FOR n=0 TO n3-1                       'search for import
                                  t3(n).bc=0
                                  IF fnd=LCASE$(TRIM$(a3(n))) THEN
                                    t3(n).bc = 2
                                    FOR i=0 TO n1-1
                                      IF xd(i).stat>0 THEN
                                        IF xd(i).impos>n THEN
                                          EXIT FOR
                                        ELSE
                                          z=i
                                        END IF
                                      END IF
                                    NEXT i
                
                                    IF xd(z).imcnt>0 THEN
                                      xd(z).bc = 2
                                    END IF
                                  END IF
                                NEXT n
                
                
                                z=listview_getitemcount(hlv1)
                
                                FOR n=0 TO z
                                  t1(n).bc = xd(t1(n).i).bc
                                NEXT n
                
                
                                FOR n=0 TO n3-1
                                  IF t3(n).bc>0 THEN
                                    IF fs<>3 THEN
                                      sendmessage hlv3, %WM_VSCROLL, %SB_BOTTOM, 0
                                      listview_ensurevisible hlv3, n, 0
                                    ELSE
                                      setfocus hlv3
                                    END IF
                                    listview_setitemstate hlv3, n, %LVIS_Focused OR %LVIS_Selected, %LVIS_Focused OR %LVIS_Selected
                                    EXIT FOR
                                  END IF
                                NEXT n
                                listview_redrawitems hlv3, 0, n3
                
                
                                FOR n=0 TO n2-1
                                  IF t2(n).bc>0 THEN
                                    IF fs<>2 THEN
                                      sendmessage hlv2, %WM_VSCROLL, %SB_BOTTOM, 0
                                      listview_ensurevisible hlv2, n, 0
                                    ELSE
                                      setfocus hlv2
                                    END IF
                                    listview_setitemstate hlv2, n, %LVIS_Focused OR %LVIS_Selected, %LVIS_Focused OR %LVIS_Selected
                                    EXIT FOR
                                  END IF
                                NEXT n
                                listview_redrawitems hlv2, 0, n2
                
                
                                FOR n=0 TO z
                                  IF xd(t1(n).i).bc>0 THEN
                                    sendmessage hlv1, %WM_VSCROLL, %SB_BOTTOM, 0
                                    listview_ensurevisible hlv1, n, 0
                                    listview_setitemstate hlv1, n, %LVIS_Focused OR %LVIS_Selected, %LVIS_Focused OR %LVIS_Selected
                                    EXIT FOR
                                  END IF
                                NEXT n
                                listview_redrawitems hlv1, 0, z
                
                
                                IF fs=0 THEN setfocus hlv1
                
                              END IF
                              FUNCTION=%true
                              EXIT FUNCTION
                            END IF
                
                
                          ELSEIF getfocus=hlv2 THEN
                            lv=2
                            LISTVIEW GET SELECT hwnd, %IDC_LV2 TO n
                            n=n-1
                            fs=2
                            GOTO startsearch
                
                
                          ELSEIF getfocus=hlv3 THEN
                            lv=3
                            LISTVIEW GET SELECT hwnd, %IDC_LV3 TO n
                            n=n-1
                            fs=3
                            GOTO startsearch
                          END IF
                
                
                        CASE %IDCANCEL                                '<esc>
                          IF CB.CTLMSG=%BN_CLICKED THEN               'exit search mode
                            sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(s)                'restore status text
                            showwindow hcombo, %SW_HIDE
                            FOR n=0 TO n1                             'reset backcolor in all listviews
                              t1(n).bc=0
                              xd(n).bc=0
                            NEXT n
                
                            FOR n=0 TO n2
                              t2(n).bc=0
                            NEXT n
                
                            FOR n=0 TO n3
                              t3(n).bc=0
                            NEXT n
                
                            setfocus hlv1
                          END IF
                
                
                        CASE %IDC_COMBO
                          IF CB.CTLMSG=%CBN_SELENDOK THEN
                            postmessage hwnd, %WM_COMMAND, MAKDWD(1, %BN_CLICKED), 0
                          END IF
                
                
                        CASE %ID_OpenCombo
                          IF getfocus=hedit THEN
                            postmessage hcombo, %CB_Showdropdown, -1, 0
                          END IF
                
                
                        CASE %ID_BROWSE_FILE
                          showwindow hcombo, %SW_HIDE
                          FOR n=0 TO n1                             'reset backcolor in all listviews
                            t1(n).bc=0
                            xd(n).bc=0
                          NEXT n
                
                          FOR n=0 TO n2
                            t2(n).bc=0
                          NEXT n
                
                          FOR n=0 TO n3
                            t3(n).bc=0
                          NEXT n
                
                          z=listview_getitemcount(hlv1)
                          sFileName = BrowseForPEFile(CBHNDL)
                
                          IF LEN(sFileName) THEN
                            n=PARSECOUNT(sfilename, $NUL)
                            IF n>1 THEN                               'multiple filenames
                              p$=PARSE$(sfilename, $NUL, 1)
                
                              FOR i=2 TO n                            'parse parts
                                f$=p$+"\"+PARSE$(sfilename, $NUL, i)
                                dump(BYVAL STRPTR(f$))
                              NEXT i
                
                            ELSE
                              dump(BYVAL STRPTR(sfilename))           'process single name
                            END IF
                
                            postmessage hwnd, %WM_USER + 1000, z, 0   'setup listviews for display
                          END IF
                
                
                        CASE %ID_Clear                                'clear all
                          ListView_SetItemCountEx hlv1, 0, 0
                          ListView_SetItemCountEx hlv2, 0, 0
                          ListView_SetItemCountEx hlv3, 0, 0
                          n1=0 : n2=0 : n3=0
                          REDIM xd(0 TO 1000)
                          REDIM a1(0 TO 1000)
                          REDIM a2(0 TO 1000)
                          REDIM a3(0 TO 1000)
                          REDIM t1(0 TO 1000)
                          REDIM t2(0 TO 1000)
                          REDIM t3(0 TO 1000)
                          fnd=""
                          COMBOBOX RESET hstatus, %IDC_COMBO
                          s=""
                          sendmessage hstatus, %SB_SETTEXT, 1, VARPTR(s)                    'set status text
                
                
                        CASE %ID_About                               'show about box
                          DialogBox hInst, "ABOUT", hwnd, CODEPTR(AboutProc)
                          FUNCTION = 0
                          EXIT FUNCTION
                
                
                        CASE %ID_HELP                                'show help
                          f$="Export/Import Spy lists all subs and functions exported by an executable (.exe/.dll)"+$CRLF+ _
                             "and imported from other libraries. It offers a search mode, where you can look for which"+$CRLF+ _
                             "module exportes or imports a certain sub or function."+$CRLF+$CRLF+$CRLF+ _
                             "One or more file(s) to be inspected can be added in 3 ways:"+$CRLF+ _
                             " - using the Menu:  File -> Open"+$CRLF+ _
                             " - by Commandline argument(s)"+$CRLF+ _
                             " - by drag and drop"+$CRLF+$CRLF+$CRLF+ _
                             "Shortcuts available:"+$CRLF+$CRLF+ _
                             "F1"+$TAB+"-     Help"+$CRLF+ _
                             "Ctrl+F1"+$TAB+"-     About"+$CRLF+ _
                             "F3"+$TAB+"-     Open file(s)"+$CRLF+ _
                             "F5"+$TAB+"-     Open explorer"+$CRLF+ _
                             "Ctrl+F"+$TAB+"-     Enter search mode"+$CRLF+ _
                             "Ctrl+R"+$TAB+"-     Reset and clear screen"+$CRLF+ _
                             "Esc"+$TAB+"-     Exit search mode"+$CRLF+ _
                             "Alt+X"+$TAB+"-     Exit"+$CRLF+$CRLF+$CRLF+ _
                             "A sub/function name to be searched for can be selected using the combobox or entering   "+$CRLF+ _
                             "a name in the edit control and pressing ""Return"" or by pressing ""Return"" when a name"+$CRLF+ _
                             "is selected in a listview of finally by doubleclicking a name in a listview"+$CRLF+$CRLF+$CRLF+ _
                             "Items in the leftmost listview with a ""plus"" icon can be expanded and collapsed"+$CRLF+$CRLF
                
                             MSGBOX f$,,"  Inport/Export Spy"
                
                
                
                        CASE 9999                                    'explorer
                '          n=SHELL("explorer.exe /e,"+CURDIR$,1)
                          n=SHELL("explorer.exe /e,C:",1)
                
                
                        CASE %ID_TOOLTIP                              'toggle tooltip mode
                          IF ttflag=0 THEN
                            checkmenuitem getmenu(hwnd), %ID_Tooltip, %MF_CHECKED
                            ttflag=1
                          ELSE
                            checkmenuitem getmenu(hwnd), %ID_Tooltip, %MF_UNCHECKED
                            ttflag=0
                          END IF
                
                
                        CASE %ID_CLOSE                                'exit
                          deleteobject bfont                          'clean up
                          DIALOG END CBHNDL, 0
                
                
                        CASE %ID_PRINT
                
                
                      END SELECT
                  END SELECT
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                '*************************************************************************************************
                
                
                FUNCTION PBMAIN
                '*************************************************************************************************
                ' main
                '***********************************************************************************************
                LOCAL sx     AS LONG
                LOCAL sy     AS LONG
                LOCAL xx     AS LONG
                LOCAL yy     AS LONG
                LOCAL hicon  AS LONG
                LOCAL t      AS ASCIIZ * 50
                LOCAL s      AS systemtime
                LOCAL r      AS rect
                LOCAL hAccelHandle AS DWORD
                LOCAL wstyle AS LONG
                LOCAL hbmp   AS DWORD
                LOCAL hil AS DWORD
                LOCAL n AS LONG
                LOCAL hacc AS DWORD
                
                
                DIM xd(0 TO 1000)
                DIM a1(0 TO 1000)
                DIM a2(0 TO 1000)
                DIM a3(0 TO 1000)
                DIM t1(0 TO 1000)
                DIM t2(0 TO 1000)
                DIM t3(0 TO 1000)
                
                
                  hacc = loadaccelerators(hinst, "ACC")               'get accelerator resource
                  n    = copyacceleratortable(hacc, BYVAL 0, BYVAL 0)
                  DIM ac(0 TO n) AS ACCELAPI
                  n=copyacceleratortable(hacc, BYVAL VARPTR(ac(0)), BYVAL n)              'make it usable for DDT
                
                
                'DIM ac(0 TO 7) AS ACCELAPI
                '
                '
                ' ac(0).fvirt = %FCONTROL OR %FVIRTKEY
                ' ac(0).key = %VK_F1
                ' ac(0).cmd = %id_about
                '
                ' ac(1).fvirt = %FALT OR %FVIRTKEY
                ' ac(1).key = %VK_X
                ' ac(1).cmd = %id_close
                '
                ' ac(2).fvirt = %FVIRTKEY
                ' ac(2).key = %VK_F1
                ' ac(2).cmd = %id_help
                '
                ' ac(3).fvirt = %FVIRTKEY
                ' ac(3).key = %VK_F5
                ' ac(3).cmd = 9999
                '
                ' ac(4).fvirt = %FCONTROL OR %FVIRTKEY
                ' ac(4).key = %VK_F
                ' ac(4).cmd = %id_search
                '
                ' ac(5).fvirt = %FCONTROL OR %FVIRTKEY
                ' ac(5).key = %VK_Return
                ' ac(5).cmd = %id_opencombo
                '
                ' ac(6).fvirt = %FVIRTKEY
                ' ac(6).key = %VK_F3
                ' ac(6).cmd = %id_browse_file
                '
                ' ac(7).fvirt = %FCONTROL OR %FVIRTKEY
                ' ac(7).key = %VK_R
                ' ac(7).cmd = %id_clear
                
                
                
                
                  hinst=getmodulehandle(BYVAL 0)
                  sx=getsystemmetrics(%SM_CXScreen)
                  sy=getsystemmetrics(%SM_CYScreen)
                
                  DIALOG NEW PIXELS, %HWND_DESKTOP, "  Import/Export Spy", 0, 0, 0, 0, %WS_SYSMENU TO hwnd
                  DIALOG SET SIZE hwnd, sx, sy
                  DIALOG SET ICON hwnd, "app"
                
                  MENU ATTACH LoadMenu(hinst,"MAINMENU"), hwnd
                  ACCEL ATTACH hwnd, ac() TO hAccelHandle
                
                
                  IMAGELIST NEW BITMAP 16, 16, 32, 2 TO hil
                
                  hbmp = loadimage(hinst, "#200", %IMAGE_BITMAP, 0, 0, %LR_DEFAULTCOLOR) '#l %LR_loadtransparent)
                  IMAGELIST ADD BITMAP hil, hbmp
                  deleteobject hbmp
                  hbmp = loadimage(hinst, "#201", %IMAGE_BITMAP, 0, 0, %LR_DEFAULTCOLOR) '#l %LR_loadtransparent)
                  IMAGELIST ADD BITMAP hil, hbmp
                  deleteobject hbmp
                
                  hbmp = loadimage(hinst, "#202", %IMAGE_BITMAP, 0, 0, %LR_DEFAULTCOLOR) '#l %LR_loadtransparent)
                  IMAGELIST ADD BITMAP hil, hbmp
                  deleteobject hbmp
                
                  hbmp = loadimage(hinst, "#203", %IMAGE_BITMAP, 0, 0, %LR_DEFAULTCOLOR) '#l %LR_loadtransparent)
                  IMAGELIST ADD BITMAP hil, hbmp
                  deleteobject hbmp
                
                
                  getclientrect hwnd, r
                  xx=(r.nright-r.nleft-4*%mg)/3
                  xx = xx - 4 - GetSystemMetrics(%SM_CXVSCROLL)       'Adjust for vertical scrollbar
                  yy = r.nbottom-r.ntop
                
                
                  wstyle = %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %LVS_REPORT OR %WS_VSCROLL OR _
                          %LVS_OWNERDATA OR %LVS_SINGLESEL OR %WS_BORDER
                
                  CONTROL ADD LISTVIEW, hwnd, %IDC_LV1, "", 0,0,0,0, wstyle, %WS_EX_CLIENTEDGE
                  CONTROL HANDLE hwnd, %IDC_LV1 TO hlv1
                  CONTROL SEND hwnd, %IDC_LV1, %LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0 TO wstyle
                  wstyle = wstyle OR %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES OR %LVS_EX_INFOTIP
                  CONTROL SEND hwnd, %IDC_LV1, %LVM_SETEXTENDEDLISTVIEWSTYLE, 0, wstyle
                  setwindowpos hlv1, BYVAL 0, r.nleft+%mg, r.ntop+%mg, (r.nright-r.nleft-4*%mg)/3, _
                                              r.nbottom-r.ntop-2*%mg-getsystemmetrics(%SM_CYCAPTION), %SWP_NoZorder
                  LISTVIEW INSERT COLUMN hwnd, %IDC_LV1, 1, "Executable", xx, 0
                  CONTROL SEND hwnd, %IDC_LV1, %LVM_SETIMAGELIST, %LVSIL_STATE, hil
                
                
                  wstyle = %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %LVS_REPORT OR %WS_VSCROLL OR _
                          %LVS_OWNERDATA OR %LVS_SINGLESEL OR %WS_BORDER
                  CONTROL ADD LISTVIEW, hwnd, %IDC_LV2, "", 0,0,0,0, wstyle, %WS_EX_CLIENTEDGE
                  CONTROL HANDLE hwnd, %IDC_LV2 TO hlv2
                  CONTROL SEND hwnd, %IDC_LV2, %LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0 TO wstyle
                  wstyle = wstyle OR %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES OR %LVS_EX_INFOTIP
                  CONTROL SEND hwnd, %IDC_LV2, %LVM_SETEXTENDEDLISTVIEWSTYLE, 0, wstyle
                  setwindowpos hlv2, BYVAL 0, r.nleft+%mg+(r.nright-r.nleft-4*%mg)/3+%mg, r.ntop+%mg, (r.nright-r.nleft-4*%mg)/3, _
                                              r.nbottom-r.ntop-2*%mg-getsystemmetrics(%SM_CYCAPTION), %SWP_NoZorder
                  LISTVIEW INSERT COLUMN hwnd, %IDC_LV2, 1, "Exports", xx, 0
                  CONTROL SEND hwnd, %IDC_LV2, %LVM_SETIMAGELIST, %LVSIL_STATE, hil
                
                
                  wstyle = %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %LVS_REPORT OR %WS_VSCROLL OR _
                          %LVS_OWNERDATA OR %LVS_SINGLESEL OR %WS_BORDER
                  CONTROL ADD LISTVIEW, hwnd, %IDC_LV3, "", 0,0,0,0, wstyle, %WS_EX_CLIENTEDGE
                  CONTROL HANDLE hwnd, %IDC_LV3 TO hlv3
                  CONTROL SEND hwnd, %IDC_LV3, %LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0 TO wstyle
                  wstyle = wstyle OR %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES OR %LVS_EX_INFOTIP
                  CONTROL SEND hwnd, %IDC_LV3, %LVM_SETEXTENDEDLISTVIEWSTYLE, 0, wstyle
                  setwindowpos hlv3, BYVAL 0, r.nleft+%mg+(r.nright-r.nleft-4*%mg)/3*2+2*%mg, r.ntop+%mg, (r.nright-r.nleft-4*%mg)/3, _
                                              r.nbottom-r.ntop-2*%mg-getsystemmetrics(%SM_CYCAPTION), %SWP_NoZorder
                  LISTVIEW INSERT COLUMN hwnd, %IDC_LV3, 1, "Imports", xx, 0
                  CONTROL SEND hwnd, %IDC_LV3, %LVM_SETIMAGELIST, %LVSIL_STATE, hil
                
                
                '***********************************************************************************************
                
                
                  CONTROL ADD STATUSBAR, hwnd, %IDC_STATUS, "", 0, 0, 40, 12, %WS_TABSTOP
                
                  STATUSBAR SET PARTS hwnd, %IDC_STATUS, 23, sx-223, 115, 9999
                  CONTROL HANDLE hwnd, %IDC_STATUS TO hstatus
                
                
                '***********************************************************************************************
                  tflag=1
                  THREAD CREATE watch(0) TO xx
                  THREAD CLOSE xx TO xx
                
                  hicon=loadimage(hinst, "search", %Image_Icon, 14, 14, %LR_LOADMAP3DCOLORS)
                  sendmessage hstatus, %SB_SETICON, 0, hicon
                  hicon=loadimage(hinst, "time", %Image_Icon, 14, 14, %LR_LOADMAP3DCOLORS)
                  sendmessage hstatus, %SB_SETICON, %st, hicon
                  hicon=loadimage(hinst, "date", %Image_Icon, 14, 14, %LR_LOADMAP3DCOLORS)
                  sendmessage hstatus, %SB_SETICON, %st-1, hicon
                
                
                  t=MID$(DATE$,4,2)+"."+MID$(DATE$,1,2)+"."+MID$(DATE$,7,4)
                  CALL getlocaltime(s)
                
                  SELECT CASE s.wdayofweek
                    CASE 0
                      t="  Su. "+t
                    CASE 1
                      t="  Mo. "+t
                    CASE 2
                      t="  Tu. "+t
                    CASE 3
                      t="  We. "+t
                    CASE 4
                      t="  Th. "+t
                    CASE 5
                      t="  Fr. "+t
                    CASE 6
                      t="  Sa. "+t
                  END SELECT
                
                  sendmessage hstatus, %SB_SETTEXT, %st-1, VARPTR(t)  'set date part
                
                
                
                  sendmessage hstatus, %SB_GETRECT, 1, VARPTR(r)      'get rect of part 1
                  CONTROL ADD COMBOBOX, hwnd, %IDC_COMBO, , 0,0,0,0, %CBS_DROPDOWN OR %CBS_SORT OR _
                                                                     %CBS_DISABLENOSCROLL OR %WS_VSCROLL 'OR %WS_TABSTOP
                
                  CONTROL HANDLE hwnd, %IDC_COMBO TO hcombo
                  hedit=getwindow(hcombo, %GW_Child)
                  setwindowpos hcombo, 0, r.nleft+170, r.ntop, 300, yy-3.5*%mg, %SWP_NOZorder OR %SWP_Hidewindow
                  setparent hcombo, hstatus
                  oldstatusproc = setwindowlong(hstatus, %GWL_Wndproc, CODEPTR(newstatusproc))
                
                
                  CALL DragAcceptFiles(hwnd, %TRUE)
                  DIALOG SHOW MODAL hwnd CALL DlgProc
                  tflag=0
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                CALLBACK FUNCTION newstatusproc
                '***********************************************************************************************
                ' manage focus change via tab key
                '***********************************************************************************************
                
                  SELECT CASE CB.MSG
                    CASE %WM_SETFOCUS
                      IF iswindowvisible(hcombo) THEN
                        setfocus hcombo
                      ELSE
                        setfocus hlv1
                      END IF
                
                      EXIT FUNCTION
                
                  END SELECT
                
                
                  FUNCTION=callwindowproc(oldstatusproc,CBHNDL,CBMSG,CBWPARAM,CBLPARAM)
                
                
                END FUNCTION
                
                
                '***********************************************************************************************
                
                
                SUB AddToCombo(sname AS ASCIIZ)
                '***********************************************************************************************
                ' populate combobox, avoid doubles
                '***********************************************************************************************
                LOCAL n AS LONG
                LOCAL s AS STRING
                
                
                  s = " " + TRIM$(sname)
                  COMBOBOX FIND EXACT hstatus, %IDC_COMBO, 1, s TO n
                  IF n=0 THEN
                    COMBOBOX ADD hstatus, %IDC_Combo, s
                  END IF
                
                
                END SUB
                
                
                '***********************************************************************************************
                
                
                FUNCTION FileVersionString(szFile AS ASCIIZ) AS STRING
                '*************************************************************************************************
                ' return versioninfo, if any
                '*************************************************************************************************
                LOCAL major    AS LONG
                LOCAL Minor    AS LONG
                LOCAL Build    AS LONG
                LOCAL revision AS LONG
                LOCAL lret      AS LONG
                LOCAL Buffer   AS STRING
                LOCAL d$
                STATIC r$
                LOCAL lzStr AS ASCIIZ * %MAX_PATH
                LOCAL lFFIPtr AS VS_FIXEDFILEINFO PTR
                LOCAL lzBufPtr AS ASCIIZ PTR
                LOCAL pLang AS LONG PTR
                LOCAL sLangID AS STRING
                
                
                  Major = 0 : Minor = 0 : Build = 0 : revision = 0
                  lret = GetFileVersionInfoSize(szFile, 0)
                
                  IF lret = 0 THEN
                    FUNCTION = szfile + $CRLF+"No Version Info"
                    EXIT FUNCTION                                     'no info -> exit
                  END IF
                
                
                  r$=""
                
                  Buffer = SPACE$(lret)
                  GetFileVersionInfo szfile, 0, lRet, BYVAL STRPTR(Buffer)                'Data to buffer
                
                '***********************************************************************************************
                ' Check language id - default to American English if not found
                '***********************************************************************************************
                
                  IF ISFALSE VerQueryValue(BYVAL STRPTR(Buffer), "\VarFileInfo\Translation", pLang, lret) THEN
                     sLangID = "040904E4"                             ' American English/ANSI
                  ELSE
                     sLangID = HEX$(LOWRD(@pLang), 4) + HEX$(HIWRD(@pLang), 4)
                  END IF
                
                  lzStr = "\StringFileInfo\"+ sLangID+"\"
                
                '***********************************************************************************************
                ' get values
                '***********************************************************************************************
                
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\Author", lzBufPtr, lRet   'Get author name
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Author:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\CompanyName", lzBufPtr, lRet 'Get company name
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Company Name:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\ProductName", lzBufPtr, lRet 'Get productname
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Product Name:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\Comment", lzBufPtr, lRet  'Get comment
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Comment:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\LegalTradeMarks",lzBufPtr, lRet 'Get trademarks
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Legal Trade Marks:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\SerialNumber", lzBufPtr, lRet 'Get serial
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Serial Number:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\LegalCopyright", lzBufPtr, lRet 'Get copyright
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Legal Copyright:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\FileDescription",lzBufPtr, lRet 'Get description
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"File Desciption:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\ProductionDate", lzBufPtr, lRet 'Get production date
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Production Date:"+$TAB+d$+"  "+$CRLF
                  VerQueryValue BYVAL STRPTR(buffer), lzStr + "\OriginalFilename",lzBufPtr,lRet 'Get original filename
                  IF lRet THEN d$ = TRIM$(@lzBufPtr) : IF LEN(d$) THEN r$=r$+"Original Name:"+$TAB+d$+"  "+$CRLF
                
                '***********************************************************************************************
                ' get fileversion
                '***********************************************************************************************
                
                  VerQueryValue BYVAL STRPTR(buffer), "\", lFFIPtr, lRet                  'get FixedFileInfo Ptr
                  IF lret THEN
                    Major    = HIWRD(@lFFIPtr.dwFileVersionMS)
                    Minor    = LOWRD(@lFFIPtr.dwFileVersionMS)
                    Revision = HIWRD(@lFFIPtr.dwFileVersionLS)
                    Build    = LOWRD(@lFFIPtr.dwFileVersionLS)
                    d$ = FORMAT$(Major,"0") + "." + FORMAT$(Minor,"0") + "." + _
                                    FORMAT$(Revision,"000") + "." + FORMAT$(Build,"000")
                    IF LEN(d$) THEN r$=r$+"Version:"+$TAB+$TAB+d$+"  "+$CRLF
                  END IF
                
                
                  FUNCTION = RTRIM$(r$, $CRLF)
                
                
                END FUNCTION
                
                
                '*************************************************************************************************
                
                
                FUNCTION AboutProc(BYVAL hDlg AS LONG, BYVAL wMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                '***********************************************************************************************
                ' about callback
                '***********************************************************************************************
                LOCAL hDC      AS LONG
                LOCAL r        AS RECT
                LOCAL LpPaint  AS PaintStruct
                
                STATIC hTimer AS LONG
                
                
                  SELECT CASE wMsg
                    CASE %WM_INITDIALOG
                      hTimer = SetTimer(hDlg, BYVAL &H0000FEED, 10000, BYVAL %NULL)
                      CenterWindow hDlg
                      EnableWindow hwnd, %FALSE
                
                      FUNCTION = 1
                
                
                    CASE %WM_TIMER
                      SendMessage hDlg, %WM_COMMAND, %IDOK, %NULL
                
                
                    CASE %WM_COMMAND
                      SELECT CASE LOWRD(wParam)
                        CASE %IDCANCEL
                          KillTimer %NULL, hTimer
                          EndDialog hDlg, 0
                          EnableWindow hwnd, %TRUE
                          FUNCTION = 1
                
                        CASE %IDOK, 101
                          KillTimer %NULL, hTimer
                          EndDialog hDlg, 1
                          EnableWindow hwnd, %TRUE
                          FUNCTION = 1
                
                      END SELECT
                
                
                    CASE %WM_PAINT
                      hDC = BeginPaint(getdlgitem(hdlg,100), LpPaint)
                
                
                        GetclientRect getdlgitem(hdlg,100), r
                        SetBkMode hDC, %TRANSPARENT
                        SetTextColor hDC, %CYAN
                        r.nleft=r.nleft+1
                        r.ntop=r.ntop+2
                        DrawText hDC, "Import/Export Spy", -1, r, %DT_SINGLELINE
                        SetTextColor hDC, %MAGENTA
                        r.nleft=r.nleft-1
                        r.ntop=r.ntop-2
                        DrawText hDC, "Import/Export Spy", -1, r, %DT_SINGLELINE
                
                
                      EndPaint getdlgitem(hdlg,100), LpPaint
                
                
                      FUNCTION = 0
                      EXIT FUNCTION
                
                
                    CASE %WM_DESTROY
                
                
                  END SELECT
                
                
                END FUNCTION
                
                
                '***********************************************************************************************
                
                
                SUB CenterWindow(BYVAL hdlg AS LONG)
                '***********************************************************************************************
                ' center this window in apps client space
                '***********************************************************************************************
                
                  DIM WndRect AS RECT
                  DIM r       AS rect
                  DIM x       AS LONG
                  DIM y       AS LONG
                
                  GetWindowRect hdlg, WndRect
                  GetWindowRect hwnd, r
                
                ' center in screen
                '  x = (GetSystemMetrics(%SM_CXSCREEN)-(WndRect.nRight-WndRect.nLeft))\2
                '  y = (GetSystemMetrics(%SM_CYSCREEN)-(WndRect.nBottom-WndRect.nTop+GetSystemMetrics(%SM_CYCAPTION)))\2
                
                  x = r.nleft+((r.nright-r.nleft)\2)-((WndRect.nRight-WndRect.nLeft)\2)
                  y = r.ntop+((r.nbottom-r.ntop)\2)-((WndRect.nBottom-WndRect.nTop)\2)
                
                
                  SetWindowPos hdlg, %NULL, x, y, 0, 0, %SWP_NOSIZE OR %SWP_NOZORDER
                
                
                END SUB
                
                
                '***********************************************************************************************
                
                
                THREAD FUNCTION watch(BYVAL dummy AS LONG) AS LONG
                '***********************************************************************************************
                ' watch thread, set date/time in statusbar
                '***********************************************************************************************
                LOCAL t AS ASCIIZ * 50
                LOCAL s AS systemtime
                
                
                  WHILE tflag>0
                
                    t=" "+TIME$
                    sendmessage hstatus, %SB_SETTEXT, %st, VARPTR(t)  'set current time
                    IF t="  00:00:01" THEN
                      t=MID$(DATE$,4,2)+"."+MID$(DATE$,1,2)+"."+MID$(DATE$,7,4)
                      CALL getlocaltime(s)
                
                      SELECT CASE s.wdayofweek
                        CASE 0
                          t=" Su. "+t
                        CASE 1
                          t=" Mo. "+t
                        CASE 2
                          t=" Tu. "+t
                        CASE 3
                          t=" We. "+t
                        CASE 4
                          t=" Th. "+t
                        CASE 5
                          t=" Fr. "+t
                        CASE 6
                          t=" Sa. "+t
                      END SELECT
                
                      sendmessage hstatus, %SB_SETTEXT, %st-1, VARPTR(t)  ' set current date
                
                    END IF
                    SLEEP 100
                
                  WEND
                
                
                END FUNCTION
                
                
                '***********************************************************************************************
                '***********************************************************************************************
                '***********************************************************************************************

                PB10 code as shown above, all the remainig stuff inside the attachment


                Have fun...
                Attached Files

                Comment

                Working...
                X