WindowsXP-SP1/shell/tools/stubgen/stubgen.c

392 lines
9.7 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;
}