/////////////////////////////////////////////////////////////////////////////// 
// DumpRes.cpp : Main CPP for dumpres.exe
// See http://msdn.microsoft.com/en-us/library/ms648008%28VS.85%29.aspx
// The code is 'quick 'n dirty' so don't use it as a guideline ;-)
//
// www.oette.info; marko@oette.info
//

#include "windows.h"
#include "stdio.h"
#include "tchar.h"

// Declare callback functions.
BOOL EnumTypesFunc(
       HMODULE hModule,
       LPTSTR lpType,
       LONG lParam);
   
BOOL EnumNamesFunc(
       HMODULE hModule,
       LPCTSTR lpType,
       LPTSTR lpName,
       LONG lParam);
   
BOOL EnumLangsFunc(
       HMODULE hModule,
       LPCTSTR lpType,
       LPCTSTR lpName,
       WORD wLang,
       LONG lParam);

void PrintLastError();
void PrintResType( USHORT nType );

#define DUMP_BINARIES 0x0000001

int _tmain(int argc, _TCHAR* argv[])
{
	if( argc < 2 )
	{
		_tprintf( _T( "DumpRes is a command line utility to dump all resources contained in a EXE or DLL File\n\n" )  
					_T(  "dumpres.exe [file] [-dump]\n" )
					_T(	  "\t-dump = Dumps the content of each single resource into a binary file.\n\n" )
					_T(	  "Written on 29th December 2009 by Marko Oette (www.oette.info; marko@oette.info)" ) );
		exit(-1);
	}

	HMODULE hExe;        // handle to module

	// Load the .EXE whose resources you want to list.
	hExe = LoadLibrary( argv[1] );
	if (hExe == NULL)
	{
		// Add code to fail as securely as possible.	 
		PrintLastError();
		exit( -3 );
	}

	// Find all of the loaded file's resources.
	_tprintf( TEXT("The file contains the following resources:\r\n\r\n") );
	
	LONG lParam = 0;

	if( argc == 3 && _tcsicmp( (LPCTSTR)argv[2], _T("-dump") ) == 0 )
		lParam |= DUMP_BINARIES;

	EnumResourceTypes(hExe,              // module handle
		(ENUMRESTYPEPROC)EnumTypesFunc,  // callback function
		lParam );                        // extra parameter

	// Unload the executable file whose resources were
	// enumerated and close the file created to contain
	// the resource information.
	FreeLibrary(hExe);

	return 0;
}


//    FUNCTION: EnumTypesFunc(HANDLE, LPSTR, LONG)
//
//    PURPOSE:  Resource type callback
BOOL EnumTypesFunc(
        HMODULE hModule,  // module handle
        LPTSTR lpType,    // address of resource type
        LONG lParam)      // extra parameter, could be
                          // used for error checking
{
    // Write the resource type to a resource information file.
    // The type may be a string or an unsigned decimal
    // integer, so test before printing.
    if (!IS_INTRESOURCE(lpType))
    {
        _tprintf( TEXT("Type: %s\r\n"), lpType);
    }
    else
    {
        PrintResType( (USHORT)lpType );
    }

	// Find the names of all resources of type lpType.
    EnumResourceNames(hModule,
        lpType,
        (ENUMRESNAMEPROC)EnumNamesFunc,
        lParam);

    return TRUE;
}

//    FUNCTION: EnumNamesFunc(HANDLE, LPSTR, LPSTR, LONG)
//
//    PURPOSE:  Resource name callback
BOOL EnumNamesFunc(
        HMODULE hModule,  // module handle
        LPCTSTR lpType,   // address of resource type
        LPTSTR lpName,    // address of resource name
        LONG lParam)      // extra parameter, could be
                          // used for error checking
{
    // Write the resource name to a resource information file.
    // The name may be a string or an unsigned decimal
    // integer, so test before printing.
    if (!IS_INTRESOURCE(lpName))
    {
        _tprintf( TEXT("\tName: %s\r\n"), lpName );
    }
    else
    {
        _tprintf( TEXT("\tName: %u\r\n"), (USHORT)lpName );
    }

	// Find the languages of all resources of type
    // lpType and name lpName.
    EnumResourceLanguages(hModule,
        lpType,
        lpName,
        (ENUMRESLANGPROC)EnumLangsFunc,
        lParam);

    return TRUE;
}

//    FUNCTION: EnumLangsFunc(HANDLE, LPSTR, LPSTR, WORD, LONG)
//
//    PURPOSE:  Resource language callback
BOOL EnumLangsFunc(
        HMODULE hModule, // module handle
        LPCTSTR lpType,  // address of resource type
        LPCTSTR lpName,  // address of resource name
        WORD wLang,      // resource language
        LONG lParam)     // extra parameter, could be
                         // used for error checking
{
    HRSRC hResInfo;

	hResInfo = FindResourceEx(hModule, lpType, lpName, wLang);
    // Write the resource language to the resource information file.
    _tprintf( TEXT("\t\tLanguage: %u\r\n"), (USHORT) wLang );

    // Write the resource handle and size to buffer.
	DWORD nSize = SizeofResource(hModule, hResInfo);
    _tprintf( TEXT("\t\tSize == %lu\r\n\r\n"),
				nSize );

	if( lParam & DUMP_BINARIES )
	{	// LoadResource, not a real HGLOBAL anymore
		HGLOBAL hRes = LoadResource( hModule, hResInfo );
		if( hRes )
		{
			LPVOID pRes = LockResource( hRes );
			if( pRes )
			{
				TCHAR szFile[MAX_PATH];
				if( !IS_INTRESOURCE( lpType ) )
					_stprintf_s( szFile, _T("%s_%s.bin"), lpType, lpName );
				else
					_stprintf_s( szFile, _T("%u_%u.bin"), lpType, lpName );

				FILE *pFile = _tfopen( szFile, _T("w") );
				if( pFile )
				{
					fwrite( pRes,1,nSize, pFile );
					fflush( pFile );
					fclose( pFile );
					_tprintf( _T("\t\tDump file:%s\n" ), szFile );
				}
			}
		}
	}

    return TRUE;
}

//    FUNCTION: PrintLastError(void)
//
//    PURPOSE:  Print the last windows error code in human readable form
void PrintLastError()
{
	LPVOID lpMsgBuf;
	if (!FormatMessage( 
		FORMAT_MESSAGE_ALLOCATE_BUFFER | 
		FORMAT_MESSAGE_FROM_SYSTEM | 
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		GetLastError(),
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
		(LPTSTR) &lpMsgBuf,
		0,
		NULL ))
	{
	   // Handle the error.
		_tprintf( _T("An unknown error occured. Sorry ;-)" ) );
	   return;
	}

	// Display the string.
	_tprintf( (LPCTSTR)lpMsgBuf );

	// Free the buffer.
	LocalFree( lpMsgBuf );
}

//    FUNCTION: PrintResType(USHORT nType)
//
//    PURPOSE:  Print the resource type 'USHORT nType' in human readable form
void PrintResType( USHORT nType )
{
	_tprintf( _T("Type: ") );
	switch( nType )
	{
	case RT_ACCELERATOR:
		_tprintf( _T( "%u \t RT_ACCELERATOR\tAccelerator table\n" ), nType );
		break;
	case RT_ANICURSOR:
		_tprintf( _T( "%u \t RT_ANICURSOR\tAnimated cursor\n" ), nType );
		break;
	case RT_ANIICON:
		_tprintf( _T( "%u \t RT_ANIICON\tAnimated icon\n" ), nType );
		break;
	case RT_BITMAP:
		_tprintf( _T( "%u \t RT_BITMAP\tBitmap resource\n" ), nType );
		break;
	case RT_CURSOR:
		_tprintf( _T( "%u \t RT_CURSOR\tHardware-dependent cursor resource\n" ), nType );
		break;
	case RT_DIALOG:
		_tprintf( _T( "%u \t RT_DIALOG\tDialog box\n" ), nType );
		break;
	case RT_DLGINCLUDE:
		_tprintf( _T( "%u \t RT_DLGINCLUDE\n" ), nType );
		break;
	case RT_FONT:
		_tprintf( _T( "%u \t RT_FONT\tFont resource\n" ), nType );
		break;
	case RT_FONTDIR:
		_tprintf( _T( "%u \t RT_FONTDIR\tFont directory resource\n" ), nType );
		break;
	case RT_GROUP_CURSOR:
		_tprintf( _T( "%u \t RT_GROUP_CURSOR\tHardware-independent cursor resource\n" ), nType );
		break;
	case RT_GROUP_ICON:
		_tprintf( _T( "%u \t RT_GROUP_ICON\tHardware-independent icon resource\n" ), nType );
		break;
	case RT_HTML:
		_tprintf( _T( "%u \t RT_HTML\tHTML resource\n" ), nType );
		break;
	case RT_ICON:
		_tprintf( _T( "%u \t RT_ICON\tHardware-dependent icon resource\n" ), nType );
		break;
	case RT_MANIFEST:
		_tprintf( _T( "%u \t RT_MANIFEST\tMicrosoft® Windows® Side-by-Side Assembly XML Manifest\n" ), nType );
		break;
	case RT_MENU:
		_tprintf( _T( "%u \t RT_MENU\tMenu resource\n" ), nType );
		break;
	case RT_MESSAGETABLE:
		_tprintf( _T( "%u \t RT_MESSAGETABLE\tMessage-table entries\n" ), nType );
		break;
	case RT_PLUGPLAY:
		_tprintf( _T( "%u \t RT_PLUGPLAY\tPlug and Play resource\n" ), nType );
		break;
	case RT_RCDATA:
		_tprintf( _T( "%u \t RT_RCDATA\tApplication-defined resource (raw data)\n" ), nType );
		break;
	case RT_STRING:
		_tprintf( _T( "%u \t RT_STRING\tString-table entries\n" ), nType );
		break;
	case RT_VXD:
		_tprintf( _T( "%u \t RT_VXD\tVXD\n" ), nType );
		break;

	default:
		_tprintf( _T( "%u\n" ), nType );

	}

}