#include "windows.h" #include "windowsx.h" #include "shlwapi.h" #include "commctrl.h" #include "comctrlp.h" #include #include #define VERSION TEXT("0.00") #define SIZEOF(x) sizeof(x) #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) typedef struct { WORD wOrdinal; LPTSTR pFunction; } EXPORTENTRY, * LPEXPORTENTRY; // // read a line, skipping leading and trailing white space and placing the output // into the specified buffer. // LPTSTR _ReadLine(LPTSTR pSource, LPTSTR pBuffer, INT cchBuffer) { // // skip leading white space // *pBuffer = TEXT('\0'); while ( (*pSource == TEXT(' ')) || (*pSource == TEXT('\t')) ) { pSource++; } if ( !*pSource ) return NULL; while ( (*pSource != TEXT('\r')) && (*pSource != TEXT('\n')) && (*pSource != TEXT('\0')) && (cchBuffer >= 1) ) { *pBuffer++ = *pSource++; cchBuffer--; } *pBuffer++ = TEXT('\0'); while ( (*pSource == TEXT('\r')) || (*pSource == TEXT('\n')) ) { pSource++; } return pSource; } // // Get string element, given an index into the buffer copy out the element // that we want. // BOOL _GetStringElement(LPTSTR pString, INT index, BOOL fEntireLine, LPTSTR pBuffer, INT cchBuffer) { for ( ; *pString && (index > 0) ; index-- ) { while ( *pString != TEXT(',') && *pString != TEXT('\0') ) pString++; if ( *pString == TEXT(',') ) pString++; } if ( index ) return FALSE; while ( *pString == TEXT(' ') ) pString++; while ( *pString && (cchBuffer > 1) ) { if ( !fEntireLine && (*pString == TEXT(',')) ) break; *pBuffer++ = *pString++; cchBuffer--; } *pBuffer = TEXT('\0'); return TRUE; } // // Get a stub function name given its module and function name. // static TCHAR szStubFunction[MAX_PATH]; LPTSTR _GetStubFunction(LPTSTR pModule, LPTSTR pFunction) { wnsprintf(szStubFunction, ARRAYSIZE(szStubFunction), TEXT("_%s_%s"), pModule, pFunction); return szStubFunction; } // // Generate stub // // This takes a line from the file and get the information we need from it. // BOOL _GenerateStub(LPTSTR pModule, LPTSTR pBuffer, HDPA hdpaFunctions, HDPA hdpaOrdinals) { TCHAR szResultType[MAX_PATH]; TCHAR szResult[MAX_PATH]; TCHAR szFunction[MAX_PATH]; TCHAR szArguments[MAX_PATH*2]; LPTSTR pFunction; LPTSTR pOrdinal; INT iByName, iByOrdinal; LPEXPORTENTRY pExport; // get the fields, all are required if ( !_GetStringElement(pBuffer, 0, FALSE, szResultType, ARRAYSIZE(szResultType)) ) return FALSE; if ( !_GetStringElement(pBuffer, 1, FALSE, szResult, ARRAYSIZE(szResult)) ) return FALSE; if ( !_GetStringElement(pBuffer, 2, FALSE, szFunction, ARRAYSIZE(szFunction)) ) return FALSE; if ( !_GetStringElement(pBuffer, 3, TRUE, szArguments, ARRAYSIZE(szArguments)) ) return FALSE; // if the function name is bla@4 then it has an ordinal therefore we must attempt // to get the ordinal number. pOrdinal = StrChr(szFunction, TEXT('@')); if ( pOrdinal ) *pOrdinal++ = TEXT('\0'); // allocate an export, adding both the ordinals and the functions as required. // if pOrdinal != NULL then we assume that we should parse the int. pExport = LocalAlloc(LPTR, SIZEOF(EXPORTENTRY)); if ( !pExport ) return FALSE; Str_SetPtr(&pFunction, szFunction); if ( !pFunction ) { LocalFree(pExport); return FALSE; } pExport->wOrdinal = (WORD) StrToInt(pOrdinal ? pOrdinal:TEXT("")); pExport->pFunction = pFunction; iByOrdinal = iByName = DPA_AppendPtr(hdpaFunctions, pExport); if ( pOrdinal ) iByOrdinal = DPA_AppendPtr(hdpaOrdinals, pExport); if ( (iByName == -1) || (iByOrdinal == -1) ) { if ( iByName != -1 ) DPA_DeletePtr(hdpaFunctions, iByName); LocalFree(pExport); Str_SetPtr(&pFunction, NULL); return FALSE; } // spew out the function name printf(TEXT("\n")); printf(TEXT("%s %s%s\n"), szResultType, _GetStubFunction(pModule, pFunction), szArguments); printf(TEXT("{\n")); if ( szResult[0] ) printf(TEXT(" return %s;\n"), szResult); printf(TEXT("}\n")); return TRUE; } // // "stubgen " // // The stub list is a text file that lists all the exports you want to generate // stubs for, each stub is a simple function which returns a specified result. // // The format of the file is: // // ,,, // // eg: // // BOOL, FALSE, SHBrowseForContainer, (bla, bla, bla) // // Which generates a stub: // // BOOL SHBrowseForContainer(bla, bla, bla) // { // return FALSE; // } // INT _SortNameCB(LPVOID p1, LPVOID p2, LPARAM lParam) { LPEXPORTENTRY pExport1 = (LPEXPORTENTRY)p1; LPEXPORTENTRY pExport2 = (LPEXPORTENTRY)p2; return StrCmpI(pExport1->pFunction, pExport2->pFunction); } INT _SortOrdinalCB(LPVOID p1, LPVOID p2, LPARAM lParam) { LPEXPORTENTRY pExport1 = (LPEXPORTENTRY)p1; LPEXPORTENTRY pExport2 = (LPEXPORTENTRY)p2; return pExport1->wOrdinal - pExport2->wOrdinal; } INT __cdecl main(INT cArgs, LPTSTR pArgs[]) { TCHAR szSource[MAX_PATH]; TCHAR szModule[MAX_PATH]; HANDLE hFile; LPTSTR pStubFile; DWORD dwSize, dwRead; HDPA hdpaFunctions; HDPA hdpaOrdinals; INT i; if ( cArgs < 2 ) { printf(TEXT("stubgen: \n")); return -1; } StrCpy(szSource, pArgs[1]); StrCpy(szModule, pArgs[2]); // // load the source file into memory and then lets generate the stub table, // add a TCHAR to the file size to get it null terminated // hFile = CreateFile(szSource, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( hFile == INVALID_HANDLE_VALUE ) return -1; dwSize = GetFileSize(hFile, NULL); pStubFile = LocalAlloc(LPTR, dwSize+SIZEOF(TCHAR)); if ( !pStubFile || !ReadFile(hFile, pStubFile, dwSize, &dwRead, NULL) || dwRead != dwSize ) { CloseHandle(hFile); return -1; } CloseHandle(hFile); // // Create the DPA we will use for storing the function names // hdpaFunctions = DPA_Create(16); hdpaOrdinals = DPA_Create(16); if ( !hdpaFunctions || ! hdpaOrdinals ) return -1; // // output header information // for ( i = 3 ; i < cArgs ; i++ ) printf(TEXT("#include \"%s\"\n"), pArgs[i]); printf(TEXT("#pragma hdrstop\n")); printf(TEXT("\n")); printf(TEXT("// Generate from %s by stubgen.exe\n"), szSource); printf(TEXT("// *** DO NOT EDIT THIS FILE ***\n\n")); // // now lets parse the file, trying to the function prototypes from it, // we skip all lines that start with a ';', '#' or '/' (as in //) // while ( pStubFile ) { TCHAR szBuffer[1024]; pStubFile = _ReadLine(pStubFile, szBuffer, ARRAYSIZE(szBuffer)); if ( pStubFile ) { switch ( szBuffer[0] ) { case TEXT('#'): case TEXT(';'): case TEXT('/'): // comments are stripped break; default: _GenerateStub(szModule, szBuffer, hdpaFunctions, hdpaOrdinals); break; } } } // // if hdpaFunctions contains anything then we have generated a set of // stubs, so lets sort it and output that. // if ( DPA_GetPtrCount(hdpaFunctions) ) { DPA_Sort(hdpaFunctions, _SortNameCB, 0); printf(TEXT("\n")); printf(TEXT("const INT g_c%sExportTable = %d;\n"), szModule, DPA_GetPtrCount(hdpaFunctions)); printf(TEXT("const EXPORTTABLE g_%sExportTable[] =\n"), szModule); printf(TEXT("{\n")); for ( i = 0 ; i < DPA_GetPtrCount(hdpaFunctions); i++ ) { LPEXPORTENTRY pExport = (LPEXPORTENTRY)DPA_GetPtr(hdpaFunctions, i); TCHAR szBuffer[MAX_PATH]; StrCpy(szBuffer, pExport->pFunction); #if UNICODE _wcslwr(szBuffer); #else _strlwr(szBuffer); #endif printf(TEXT(" \"%s\", (FARPROC)%s,\n"), szBuffer, _GetStubFunction(szModule, pExport->pFunction)); } printf(TEXT("};\n")); } if ( DPA_GetPtrCount(hdpaOrdinals) ) { DPA_Sort(hdpaFunctions, _SortOrdinalCB, 0); printf(TEXT("\n")); printf(TEXT("const INT g_c%sOrdinalTable = %d;\n"), szModule, DPA_GetPtrCount(hdpaOrdinals)); printf(TEXT("const ORDINALTABLE g_%sOrdinalTable[] =\n"), szModule); printf(TEXT("{\n")); for ( i = 0 ; i < DPA_GetPtrCount(hdpaOrdinals); i++ ) { LPEXPORTENTRY pExport = (LPEXPORTENTRY)DPA_GetPtr(hdpaOrdinals, i); printf(TEXT(" %d, (FARPROC)%s,\n"), pExport->wOrdinal, _GetStubFunction(szModule, pExport->pFunction)); } printf(TEXT("};\n")); } return 0; }