/*++ Copyright (c) 1997 Microsoft Corporation Module Name: custerr.cxx Abstract: Custom Error Utility Author: Keith Moore (keithmo) 04-Sep-1997 Revision History: --*/ #include "precomp.hxx" #pragma hdrstop // // Private constants. // #define TEST_HRESULT(api,hr,fatal) \ if( FAILED(hr) ) { \ \ wprintf( \ L"%S:%lu failed, error %lx %S\n", \ (api), \ __LINE__, \ (result), \ (fatal) \ ? "ABORTING" \ : "CONTINUING" \ ); \ \ if( fatal ) { \ \ goto cleanup; \ \ } \ \ } else #define ALLOC( cb ) (PVOID)LocalAlloc( LPTR, (cb) ) #define FREE( ptr ) (VOID)LocalFree( (HLOCAL)(ptr) ) // // Private types. // // // Private globals. // // // Private prototypes. // VOID Usage( VOID ); VOID SetCustomError( IMSAdminBase * AdmCom, LPWSTR MetaPath, LPWSTR FileName ); VOID DumpCustomError( IMSAdminBase * AdmCom, LPWSTR MetaPath ); // // Public functions. // INT __cdecl wmain( INT argc, LPWSTR argv[] ) { HRESULT result; IMSAdminBase * admCom; LPWSTR metaPath; LPWSTR fileName; LPWSTR arg; INT i; // // Setup locals so we know how to cleanup on exit. // admCom = NULL; // // Establish defaults. // metaPath = L"w3svc"; fileName = NULL; // // Validate the command line arguments. // for( i = 1 ; i < argc ; i++ ) { arg = argv[i]; if( arg[0] != L'-' || arg[1] == L'\0' || arg[2] != L':' || arg[3] == L'\0' ) { Usage(); return 1; } switch( arg[1] ) { case L'h' : case L'H' : case L'?' : Usage(); return 1; case L'p' : case L'P' : metaPath = arg + 3; break; case L'f' : case L'F' : fileName = arg + 3; break; default : Usage(); return 1; } } // // Initialize COM. // result = CoInitializeEx( NULL, COINIT_MULTITHREADED ); TEST_HRESULT( "CoInitializeEx()", result, TRUE ); // // Get the admin object. // result = MdGetAdminObject( &admCom ); TEST_HRESULT( "MdGetAdminObject()", result, TRUE ); // // Do it. // if( fileName == NULL ) { DumpCustomError( admCom, metaPath ); } else { SetCustomError( admCom, metaPath, fileName ); } cleanup: // // Release the admin object. // if( admCom != NULL ) { result = MdReleaseAdminObject( admCom ); TEST_HRESULT( "MdReleaseAdminObject()", result, FALSE ); } // // Shutdown COM. // CoUninitialize(); return 0; } // main // // Private functions. // VOID Usage( VOID ) { wprintf( L"use: custerr [options]\n" L"\n" L"valid options are:\n" L"\n" L" -p:meta_path\n" L" -f:error_file\n" L"\n" ); } // Usage VOID SetCustomError( IMSAdminBase * AdmCom, LPWSTR MetaPath, LPWSTR FileName ) { HANDLE fileHandle; DWORD length; DWORD lengthHigh; DWORD bytesRemaining; HANDLE mappingHandle; PCHAR view; PCHAR viewScan; PWCHAR multiSz; PWCHAR multiSzScan; HRESULT result; BOOL gotOne; METADATA_HANDLE metaHandle; METADATA_RECORD metaRecord; DWORD err; CHAR ansiFileName[MAX_PATH]; WCHAR fullMetaPath[MAX_PATH]; // // Setup locals so we know how to cleanup on exit. // fileHandle = INVALID_HANDLE_VALUE; mappingHandle = NULL; view = NULL; multiSz = NULL; metaHandle = 0; // // Open the file, get its length. // sprintf( ansiFileName, "%S", FileName ); fileHandle = CreateFileA( ansiFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( fileHandle == INVALID_HANDLE_VALUE ) { err = GetLastError(); wprintf( L"custerr: cannot open %s, error %lu\n", FileName, err ); goto cleanup; } length = GetFileSize( fileHandle, &lengthHigh ); if( length == 0xFFFFFFFF || lengthHigh > 0 ) { err = GetLastError(); wprintf( L"custerr: cannot read %s, error %lu\n", FileName, err ); goto cleanup; } // // Map it in. // mappingHandle = CreateFileMapping( fileHandle, NULL, PAGE_READONLY, 0, 0, NULL ); if( mappingHandle == NULL ) { err = GetLastError(); wprintf( L"custerr: cannot read %s, error %lu\n", FileName, err ); goto cleanup; } view = (PCHAR)MapViewOfFile( mappingHandle, FILE_MAP_READ, 0, 0, 0 ); if( view == NULL ) { err = GetLastError(); wprintf( L"custerr: cannot read %s, error %lu\n", FileName, err ); goto cleanup; } // // Allocate the multisz buffer. Assume it will be roughly the same // size as the file. // multiSz = (PWCHAR) ALLOC( length * sizeof(WCHAR) ); if( multiSz == NULL ) { wprintf( L"custerr: not enough memory\n" ); goto cleanup; } // // Build the multisz. // viewScan = view; multiSzScan = multiSz; bytesRemaining = length; while( bytesRemaining > 0 ) { // // Skip leading whitespace. // while( bytesRemaining > 0 && ( *viewScan == ' ' || *viewScan == '\t' || *viewScan == '\r' || *viewScan == '\n' ) ) { bytesRemaining--; viewScan++; } // // Copy it over, collapse embedded whitespace, perform // cheesy ANSI-to-UNICODE conversion. // gotOne = FALSE; while( bytesRemaining > 0 && ( *viewScan != '\r' && *viewScan != '\n' ) ) { bytesRemaining--; if( *viewScan != ' ' && *viewScan != '\t' ) { *multiSzScan++ = (WCHAR)*viewScan; gotOne = TRUE; } viewScan++; } if( gotOne ) { *multiSzScan++ = L'\0'; } } *multiSzScan++ = L'\0'; // // Open the metabase. // swprintf( fullMetaPath, L"/%S/%s", IIS_MD_LOCAL_MACHINE_PATH, MetaPath ); result = AdmCom->OpenKey( METADATA_MASTER_ROOT_HANDLE, fullMetaPath, METADATA_PERMISSION_WRITE, METABASE_OPEN_TIMEOUT, &metaHandle ); TEST_HRESULT( "AdmCom->OpenKey()", result, TRUE ); // // Write the new custom error value. // length = ( multiSzScan - multiSz ) * sizeof(WCHAR); INITIALIZE_METADATA_RECORD( &metaRecord, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, length, multiSz ); result = AdmCom->SetData( metaHandle, L"", &metaRecord ); TEST_HRESULT( "AdmCom->SetData()", result, TRUE ); cleanup: if( metaHandle != 0 ) { AdmCom->CloseKey( metaHandle ); } if( multiSz != NULL ) { FREE( multiSz ); } if( view != NULL ) { UnmapViewOfFile( view ); } if( mappingHandle != NULL ) { CloseHandle( mappingHandle ); } if( fileHandle != INVALID_HANDLE_VALUE ) { CloseHandle( fileHandle ); } } // SetCustomError VOID DumpCustomError( IMSAdminBase * AdmCom, LPWSTR MetaPath ) { HRESULT result; METADATA_HANDLE metaHandle; METADATA_RECORD metaRecord; DWORD bytesRequired; PWCHAR buffer; PWCHAR bufferScan; WCHAR fullMetaPath[MAX_PATH]; // // Setup locals so we know how to cleanup on exit. // metaHandle = 0; buffer = NULL; // // Open the metabase. // swprintf( fullMetaPath, L"/%S/%s", IIS_MD_LOCAL_MACHINE_PATH, MetaPath ); result = AdmCom->OpenKey( METADATA_MASTER_ROOT_HANDLE, fullMetaPath, METADATA_PERMISSION_READ, METABASE_OPEN_TIMEOUT, &metaHandle ); TEST_HRESULT( "AdmCom->OpenKey()", result, TRUE ); // // Get the data size. // INITIALIZE_METADATA_RECORD( &metaRecord, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, 2, L"" ); result = AdmCom->GetData( metaHandle, L"", &metaRecord, &bytesRequired ); if( result != RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER ) ) { TEST_HRESULT( "AdmCom->GetData()", result, TRUE ); } // // Allocate our data buffer. // buffer = (PWCHAR)ALLOC( bytesRequired ); if( buffer == NULL ) { wprintf( L"custerr: not enough memory\n" ); goto cleanup; } // // Now actually read it. // INITIALIZE_METADATA_RECORD( &metaRecord, MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, bytesRequired, buffer ); result = AdmCom->GetData( metaHandle, L"", &metaRecord, &bytesRequired ); TEST_HRESULT( "AdmCom->GetData()", result, TRUE ); // // Print it. // bufferScan = buffer; while( *bufferScan != L'\0' ) { wprintf( L"%s\n", bufferScan ); bufferScan += wcslen( bufferScan ) + 1; } cleanup: if( buffer != NULL ) { FREE( buffer ); } if( metaHandle != 0 ) { AdmCom->CloseKey( metaHandle ); } } // DumpCustomError