392 lines
9.3 KiB
C
392 lines
9.3 KiB
C
#include "windows.h"
|
|
#include "windowsx.h"
|
|
#include "shlwapi.h"
|
|
#include "commctrl.h"
|
|
#include "comctrlp.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#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 <stub list> <module>"
|
|
//
|
|
// 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:
|
|
//
|
|
// <result type>,<result>,<function>,<arguments>
|
|
//
|
|
// 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: <src> <module>\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;
|
|
}
|