News:

Download Pelles C here: http://www.pellesc.se

Main Menu

Retrieving information from htmlhelp.lib

Started by Vortex, February 10, 2026, 09:11:39 PM

Previous topic - Next topic

Vortex

Hello,

Podump does not display the functions exported by htmlhelp.lib :
\PellesC\bin\podump.exe /EXPORTS \PellesC\lib\win\htmlhelp.lib
Dump of \PellesC\lib\win\htmlhelp.lib

File type: LIB

SUMMARY
      11 .bss
      A4 .rdata
    187 .text

\PellesC\bin\polib.exe /MAKEDEF:htmlhelp.def /MACHINE:x86 \PellesC\lib\win\htmlhelp.lib
The size of htmlhelp.def is 0 byte.

Same issues with the 64-bit version of htmlhelp.lib
Code it... That's all...

TimoVJL

Not actually a bug, as it is a static library.
About Htmlhelp.lib

EDIT: use pope.exe to see linker members / symbols
May the source be with you

Vortex

Hi Timo,

Thanks for the heads up. A better approach :

E:\PellesC\Lib\Win>\PellesC\bin\podump.exe /SYMBOLS htmlhelp.lib

Dump of htmlhelp.lib

File type: LIB

SYMBOL TABLE
0000 00000001 ABS    notype      static       | @feat.00
     compatible with /safeseh
0001 00000000 SECT1  notype      static       | .bss
     length of section   11, #relocations    0, #linenumbers    0
0003 00000000 SECT2  notype      static       | .text
     length of section  187, #relocations   1E, #linenumbers    0
0005 00000000 UNDEF  notype      external     | __imp__RegQueryValueExW@24
0006 00000000 UNDEF  notype      external     | __imp__RegOpenKeyExW@20
0007 00000000 UNDEF  notype      external     | __imp__RegCloseKey@4
0008 00000000 UNDEF  notype      external     | __imp__LoadLibraryW@4
0009 00000000 UNDEF  notype      external     | __imp__GetProcAddress@8
000A 00000000 SECT3  notype      static       | .rdata
     length of section   A4, #relocations    0, #linenumbers    0
000C 00000090 SECT2  notype ()   external     | _HtmlHelpA@16
000D 00000110 SECT2  notype ()   external     | _HtmlHelpW@16
000E 00000000 SECT1  notype      static       | _g_hmodHHCtrl
000F 00000000 SECT2  notype ()   static       | _LoadHHCtrl@0
0010 0000002C SECT3  notype      static       | @1030
0011 0000002A SECT3  notype      static       | @1034
0012 00000014 SECT3  notype      static       | @1040
0013 00000004 SECT1  notype      static       | @1066
0014 00000008 SECT1  notype      static       | @1069
0015 0000000A SECT3  notype      static       | @1078
0016 0000000C SECT1  notype      static       | @1118
0017 00000010 SECT1  notype      static       | @1121
0018 00000000 SECT3  notype      static       | @1130

SUMMARY
      11 .bss
      A4 .rdata
     187 .text
Code it... That's all...

TimoVJL

An adaptation to Matt Pietrek's code for library files.
Yes, an very old code and you can fix it.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

extern TCHAR *szAppName;

extern void WriteOut(HWND hWnd, TCHAR *szText);
DWORD ConvertBigEndian(DWORD bigEndian);
BOOL IsRegularLibSymbol(PSTR pszSymbolName);

//=============================================================================
// Other miscellaneous variables and macros
//=============================================================================
// MakePtr is a macro that allows you to easily add to values (including
// pointers) together without dealing with C's pointer arithmetic.  It
// essentially treats the last two parameters as DWORDs.  The first
// parameter is used to typecast the result to the appropriate pointer type.
#define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))

//=============================================================================
// Start of program code
//=============================================================================

int ProcessFileLibExp(HWND hWnd, PBYTE pMappedFileBase, int iOpt)
{
    TCHAR szTmp[260];

    //if (0 != strncmp((PCHAR)pMappedFileBase, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE))
    if (0 != memcmp((PCHAR)pMappedFileBase, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE))
    {
        //wsprintf(szTmp, TEXT("Not a valid COFF LIB file\n"));
        //WriteOut(hWnd, szTmp);
        MessageBox(NULL, TEXT("Not a valid COFF LIB file\n"), szAppName, MB_OK);
        return 4;
    }
    //WriteOut(hWnd, TEXT("test"));
    // Point to the first archive member.  This entry contains the LIB symbols,
    // and immediately follows the archive start string ("!<arch>\n")
    PIMAGE_ARCHIVE_MEMBER_HEADER pMbrHdr;
    pMbrHdr = MakePtr(PIMAGE_ARCHIVE_MEMBER_HEADER, pMappedFileBase, IMAGE_ARCHIVE_START_SIZE);
    // First DWORD after this member header is a symbol count
    PDWORD pcbSymbols = (PDWORD) (pMbrHdr + 1);    // Pointer math!
    // Following the symbol count is an array of offsets to archive members
    // (essentially, embedded .OBJ files)
    PDWORD pMemberOffsets = pcbSymbols + 1;    // Pointer math!
    // Second header MS libs
    PIMAGE_ARCHIVE_MEMBER_HEADER pMbrHdr2;
    DWORD dwOfs = strtol((char*)pMbrHdr->Size, NULL, 10) + IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR;
    pMbrHdr2 = MakePtr(PIMAGE_ARCHIVE_MEMBER_HEADER, pMbrHdr, dwOfs);
    int iHdr;
    DWORD cSymbols;
    PSTR pszSymbolName, pszSymbolName2 = 0;
    PDWORD pMemberOffsets2 = 0;
    PWORD pIndices = 0;
    if (*(BYTE*)pMbrHdr2 == '/') {     // second header found ?
        iHdr = 2;
        // First DWORD after this member header is a member count of Offset table
       
        PDWORD pcbSMembers2 = (PDWORD) (pMbrHdr2 + 1);    // Pointer math!
        // After that there is symbol count of Index table
        PDWORD pcbSymbols2 = (PDWORD) (pMbrHdr2 + 1) + *pcbSMembers2 + 1;
        cSymbols = *pcbSymbols2;    // use second header symbol count
        pMemberOffsets2 = pcbSMembers2 + 1;    // Pointer math!
        pIndices = MakePtr(PWORD, pMemberOffsets2, *pcbSMembers2 * sizeof(DWORD) + sizeof(DWORD));

        // Following the array of member offsets is an array of offsets to symbol
        // names.
        pszSymbolName2 = MakePtr(PSTR, pcbSymbols2, cSymbols * sizeof(WORD) + sizeof(DWORD));
        pszSymbolName = pszSymbolName2;
    } else {
        iHdr = 1;    // no second header
        // First DWORD after this member header is a symbol count
        //PDWORD pcbSymbols = (PDWORD) (pMbrHdr + 1);    // Pointer math!
        // The symbol count is stored in big endian format, so adjust as
        // appropriate for the target architecture
        cSymbols = ConvertBigEndian(*pcbSymbols);

        // Following the symbol count is an array of offsets to archive members
        // (essentially, embedded .OBJ files)
        pMemberOffsets = pcbSymbols + 1;    // Pointer math!

        // Following the array of member offsets is an array of offsets to symbol
        // names.
        pszSymbolName = MakePtr(PSTR, pMemberOffsets, 4 * cSymbols);
    }
    // Find module name first
    BOOL bImports = 0;
    for (unsigned i = 0; i < cSymbols; i++)
    {
        //if (LibSymbolType(pszSymbolName) == 2) {
        if (0 == memcmp(pszSymbolName, "__IMPORT_DESCRIPTOR_", 20)) {
            bImports = 1;
            wsprintf(szTmp, TEXT("LIBRARY %hs\n"), pszSymbolName+20);
            WriteOut(hWnd, szTmp);
            break;
        }

        if (0 == memcmp(pszSymbolName, "__head_lib32_lib", 16)
            || 0 == memcmp(pszSymbolName, "__head_lib64_lib", 16)
            || 0 == memcmp(pszSymbolName, "__head_lib", 10)) {
            bImports = 1;
            if (*(pszSymbolName+10) != '3' && *(pszSymbolName+10) != '6')
                wsprintf(szTmp, TEXT("LIBRARY %hs"), pszSymbolName+10);
            else wsprintf(szTmp, TEXT("LIBRARY %hs"), pszSymbolName+16);
            int nLen = lstrlen(szTmp);
            szTmp[nLen-2] = 10;
            szTmp[nLen-1] = 0;
            WriteOut(hWnd, szTmp);
            break;
        }

        pMemberOffsets++;    // only for first header
        pszSymbolName += strlen(pszSymbolName) + 1;
    }
    if (!bImports) return 1;    // no export for def file, just give up
    //wsprintf(szTmp, "LIBRARY %s\nEXPORTS\n", pTmp);
    wsprintf(szTmp, TEXT("EXPORTS\n"));
    WriteOut(hWnd, szTmp);

    if (iHdr == 1) {
        // Following the symbol count is an array of offsets to archive members
        // (essentially, embedded .OBJ files)
        pMemberOffsets = pcbSymbols + 1;    // Pointer math!
        // Following the array of member offsets is an array of offsets to symbol
        // names.
        pszSymbolName = MakePtr(PSTR, pMemberOffsets, 4 * cSymbols);
    } else
        pszSymbolName = pszSymbolName2;
    // Loop through every symbol in the second archive member
    //     
    for (unsigned i = 0; i < cSymbols; i++)
    {
        // Call DisplayLibInfoForSymbol, which figures out what kind of symbol
        // it is.  The "IsRegularLibSymbol" filters out symbols that are
        // internal to the linking process
        //printf(TEXT("%04X %hs\n"), offset, pszSymbolName);
        //if (LibSymbolType(pszSymbolName) == 1) {
        if (0 == memcmp(pszSymbolName, "__imp_", 6)) {
            if (iOpt == 1 || iOpt > 4)
                wsprintf(szTmp, TEXT("%hs\n"), pszSymbolName + 6);
            else if (iOpt == 2)
                wsprintf(szTmp, TEXT("\"%hs\"\n"), pszSymbolName + 6);
            else if (iOpt == 3) {
                TCHAR szFunc[260];
                wsprintf(szFunc, TEXT("%hs"), pszSymbolName + 6);
                int iPos = wsprintf(szTmp, TEXT("%s\n"), szFunc);
                for (int iC = iPos; iC > 0; iC--) {
                    if (szTmp[iC] == '@') {
                        szTmp[iC] = 0;
                        iPos = iC;
                        wsprintf(&szTmp[iC], TEXT(" = %s\n"), szFunc);
                        break;
                    }
                }
            }
            else if (iOpt == 4) {
                DWORD offset = pMemberOffsets2[pIndices[i]-1];    // base 1 -> 0
                IMPORT_OBJECT_HEADER *pImpObjHdr = MakePtr(IMPORT_OBJECT_HEADER *, pMappedFileBase, offset + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
                wsprintf(szTmp, TEXT("%hs @%d\n"), pszSymbolName + 6, pImpObjHdr->Hint);
            }
            WriteOut(hWnd, szTmp);
        }

        // Advanced to the next name.
        // symbol names are sequential null-terminated strings
        pMemberOffsets++;    // only for first header
        pszSymbolName += strlen(pszSymbolName) + 1;
    }

    return 0;
}

//=============================================================================
// Converts from big endian to little endian numbers.
//=============================================================================
DWORD ConvertBigEndian(DWORD bigEndian)
{
    DWORD temp = 0;

    temp |= bigEndian >> 24;
    temp |= ((bigEndian & 0x00FF0000) >> 8);
    temp |= ((bigEndian & 0x0000FF00) << 8);
    temp |= ((bigEndian & 0x000000FF) << 24);

    return temp;
}
May the source be with you