/******************************************************************************* * * (C) COPYRIGHT MICROSOFT CORP., 1993-1994 * * TITLE: REGPRINT.C * * VERSION: 4.0 * * AUTHOR: Tracy Sharpe * * DATE: 21 Nov 1993 * * Print routines for the Registry Editor. * *******************************************************************************/ #include "pch.h" #include "regprint.h" #include "regcdhk.h" #include "regresid.h" #include "regedit.h" #include "richedit.h" #include "regporte.h" #include "reg1632.h" #include extern void PrintResourceData(PBYTE pbData, UINT uSize, DWORD dwType); const TCHAR s_PrintLineBreak[] = TEXT(",\n "); PRINTDLGEX g_PrintDlg; typedef struct _PRINT_IO { BOOL fContinueJob; UINT ErrorStringID; HWND hRegPrintAbortWnd; RECT rcPage; RECT rcOutput; PTSTR pLineBuffer; UINT cch; UINT cBufferPos; LPTSTR lpNewLineChars; } PRINT_IO; #define CANCEL_NONE 0x0000 #define CANCEL_MEMORY_ERROR 0x0001 #define CANCEL_PRINTER_ERROR 0x0002 #define CANCEL_ABORT 0x0004 #define INITIAL_PRINTBUFFER_SIZE 8192 PRINT_IO s_PrintIo; BOOL CALLBACK RegPrintAbortProc( HDC hDC, int Error ); INT_PTR CALLBACK RegPrintAbortDlgProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam ); void RegPrintSubtree(); void PrintBranch(HKEY hKey, LPTSTR lpFullKeyName); void PrintKeyValues(HKEY hKey); void PrintValueData(PBYTE pbValueData, DWORD cbValueData, DWORD dwType); void PrintKeyHeader(HKEY hKey, LPTSTR lpFullKeyName); void PrintClassName(HKEY hKey); void PrintLastWriteTime(HKEY hKey); void PrintDynamicString(UINT uStringID); void PrintType(DWORD dwType); void PrintBinaryData(PBYTE ValueData, UINT cbcbValueData); void PrintDWORDData(PBYTE ValueData, UINT cbcbValueData); void PrintLiteral(PTSTR lpLiteral); BOOL PrintChar(TCHAR Char); void PrintMultiString(LPTSTR pszData, int cbData); UINT PrintToSubTreeError(UINT uPrintErrorStringID); void PrintNewLine(); /******************************************************************************* * * Implement IPrintDialogCallback * * DESCRIPTION: * This interface is necessary to handle messages through PrintDlgEx * This interface doesn't need to have all the correct semantics of a COM * Object * *******************************************************************************/ typedef struct { IPrintDialogCallback ipcb; } CPrintCallback; #define IMPL(type, pos, ptr) (type*) static HRESULT CPrintCallback_QueryInterface(IPrintDialogCallback *ppcb, REFIID riid, void **ppv) { CPrintCallback *this = (CPrintCallback*)ppcb; if (IsEqualIID (riid, &IID_IUnknown) || IsEqualIID (riid, &IID_IPrintDialogCallback)) *ppv = &this->ipcb; else { *ppv = 0; return E_NOINTERFACE; } this->ipcb.lpVtbl->AddRef(&this->ipcb); return NOERROR; } static ULONG CPrintCallback_AddRef(IPrintDialogCallback *ppcb) { CPrintCallback *this = (CPrintCallback*)ppcb; return 1; } static ULONG CPrintCallback_Release(IPrintDialogCallback *ppcb) { CPrintCallback *this = (CPrintCallback*)ppcb; return 1; } static HRESULT CPrintCallback_InitDone(IPrintDialogCallback *ppcb) { return S_OK; } static HRESULT CPrintCallback_SelectionChange(IPrintDialogCallback *ppcb) { return S_OK; } static HRESULT CPrintCallback_HandleMessage( IPrintDialogCallback *ppcb, HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult) { *pResult = RegCommDlgHookProc(hDlg, uMsg, wParam, lParam); return S_OK; } static IPrintDialogCallbackVtbl vtblPCB = { CPrintCallback_QueryInterface, CPrintCallback_AddRef, CPrintCallback_Release, CPrintCallback_InitDone, CPrintCallback_SelectionChange, CPrintCallback_HandleMessage }; CPrintCallback g_callback; /******************************************************************************* * * RegEdit_OnCommandPrint * * DESCRIPTION: * Handles the selection of the "Print" option by the user for the RegEdit * dialog box. * * PARAMETERS: * hWnd, handle of RegPrint window. * *******************************************************************************/ VOID PASCAL RegEdit_OnCommandPrint( HWND hWnd ) { LPDEVNAMES lpDevNames; TEXTMETRIC TextMetric; DOCINFO DocInfo; LOGFONT lf; HGLOBAL hDevMode; HGLOBAL hDevNames; RECT rc; HWND hRichEdit; FORMATRANGE fr; HINSTANCE hInstRichEdit; int nOffsetX; int nOffsetY; PTSTR pszFontName; g_callback.ipcb.lpVtbl = &vtblPCB; // We have to completely fill out the PRINTDLGEX structure // correctly or the PrintDlgEx function will return an error. // The easiest way is to memset it to 0 hDevMode = g_PrintDlg.hDevMode; hDevNames = g_PrintDlg.hDevNames; memset(&g_PrintDlg, 0, sizeof(g_PrintDlg)); g_PrintDlg.lStructSize = sizeof(PRINTDLGEX); g_PrintDlg.hwndOwner = hWnd; g_PrintDlg.hDevMode = hDevMode; g_PrintDlg.hDevNames = hDevNames; g_PrintDlg.hDC = NULL; g_PrintDlg.Flags = PD_NOPAGENUMS | PD_RETURNDC | PD_ENABLEPRINTTEMPLATE; g_PrintDlg.Flags2 = 0; g_PrintDlg.ExclusionFlags = 0; g_PrintDlg.hInstance = g_hInstance; g_PrintDlg.nCopies = 1; g_PrintDlg.nStartPage = START_PAGE_GENERAL; g_PrintDlg.lpCallback = (IUnknown*) &g_callback.ipcb; g_PrintDlg.lpPrintTemplateName = MAKEINTRESOURCE(IDD_REGPRINT); g_RegCommDlgDialogTemplate = IDD_REGPRINT; if (FAILED(PrintDlgEx(&g_PrintDlg))) return; if (g_PrintDlg.dwResultAction != PD_RESULT_PRINT) return; s_PrintIo.ErrorStringID = IDS_PRINTERRNOMEMORY; if ((lpDevNames = GlobalLock(g_PrintDlg.hDevNames)) == NULL) goto error_ShowDialog; // // For now, assume a page with top and bottom margins of 1/2 inch and // left and right margins of 3/4 inch (the defaults of Notepad). // rcPage and rcOutput are in TWIPS (1/20th of a point) // rc.left = rc.top = 0; rc.bottom = GetDeviceCaps(g_PrintDlg.hDC, PHYSICALHEIGHT); rc.right = GetDeviceCaps(g_PrintDlg.hDC, PHYSICALWIDTH); nOffsetX = GetDeviceCaps(g_PrintDlg.hDC, PHYSICALOFFSETX); nOffsetY = GetDeviceCaps(g_PrintDlg.hDC, PHYSICALOFFSETY); s_PrintIo.rcPage.left = s_PrintIo.rcPage.top = 0; s_PrintIo.rcPage.right = MulDiv(rc.right, 1440, GetDeviceCaps(g_PrintDlg.hDC, LOGPIXELSX)); s_PrintIo.rcPage.bottom = MulDiv(rc.bottom, 1440, GetDeviceCaps(g_PrintDlg.hDC, LOGPIXELSY)); s_PrintIo.rcOutput.left = 1080; s_PrintIo.rcOutput.top = 720; s_PrintIo.rcOutput.right = s_PrintIo.rcPage.right - 1080; s_PrintIo.rcOutput.bottom = s_PrintIo.rcPage.bottom - 720; // // // if ((s_PrintIo.pLineBuffer = (PTSTR) LocalAlloc(LPTR, INITIAL_PRINTBUFFER_SIZE*sizeof(TCHAR))) == NULL) goto error_DeleteDC; s_PrintIo.cch = INITIAL_PRINTBUFFER_SIZE; s_PrintIo.cBufferPos = 0; if ((s_PrintIo.hRegPrintAbortWnd = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_REGPRINTABORT), hWnd, RegPrintAbortDlgProc)) == NULL) goto error_FreeLineBuffer; EnableWindow(hWnd, FALSE); // // Prepare the document for printing. // s_PrintIo.ErrorStringID = 0; s_PrintIo.fContinueJob = TRUE; s_PrintIo.lpNewLineChars = TEXT("\n"); SetAbortProc(g_PrintDlg.hDC, RegPrintAbortProc); DocInfo.cbSize = sizeof(DOCINFO); DocInfo.lpszDocName = LoadDynamicString(IDS_REGEDIT); DocInfo.lpszOutput = (LPTSTR) lpDevNames + lpDevNames-> wOutputOffset; DocInfo.lpszDatatype = NULL; DocInfo.fwType = 0; s_PrintIo.ErrorStringID = 0; if (StartDoc(g_PrintDlg.hDC, &DocInfo) <= 0) { if (GetLastError() != ERROR_PRINT_CANCELLED) s_PrintIo.ErrorStringID = IDS_PRINTERRPRINTER; goto error_DeleteDocName; } // Print registry subtree. RegPrintSubtree(); if (s_PrintIo.ErrorStringID != 0) { InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(s_PrintIo.ErrorStringID), MAKEINTRESOURCE(IDS_REGEDIT), MB_ICONERROR | MB_OK); } hInstRichEdit = LoadLibrary(TEXT("riched20.dll")); hRichEdit = CreateWindowEx(0, RICHEDIT_CLASS, NULL, ES_MULTILINE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); SendMessage(hRichEdit, WM_SETTEXT, 0, (LPARAM)s_PrintIo.pLineBuffer); pszFontName = LoadDynamicString(IDS_PRINT_FONT); if (pszFontName) { CHARFORMAT cf; cf.cbSize = sizeof(CHARFORMAT); cf.dwMask = CFM_FACE | CFM_BOLD; cf.dwEffects = 0x00; cf.bPitchAndFamily = FIXED_PITCH | FF_MODERN; wsprintf(cf.szFaceName, TEXT("%s"), pszFontName); SendMessage(hRichEdit, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf); DeleteDynamicString(pszFontName); } fr.hdc = g_PrintDlg.hDC; fr.hdcTarget = g_PrintDlg.hDC; fr.rc = s_PrintIo.rcOutput; fr.rcPage = s_PrintIo.rcPage; fr.chrg.cpMin = 0; fr.chrg.cpMax = -1; while (fr.chrg.cpMin < (int) s_PrintIo.cBufferPos) { StartPage(g_PrintDlg.hDC); // We have to adjust the origin because 0,0 is not at the corner of the paper // but is at the corner of the printable region SetViewportOrgEx(g_PrintDlg.hDC, -nOffsetX, -nOffsetY, NULL); fr.chrg.cpMin = (LONG)SendMessage(hRichEdit, EM_FORMATRANGE, TRUE, (LPARAM)&fr); SendMessage(hRichEdit, EM_DISPLAYBAND, 0, (LPARAM)&s_PrintIo.rcOutput); EndPage(g_PrintDlg.hDC); if (!s_PrintIo.fContinueJob) break; } SendMessage(hRichEdit, EM_FORMATRANGE, FALSE, 0); // // End the print job. // if (s_PrintIo.ErrorStringID == 0 && s_PrintIo.fContinueJob) { if (EndDoc(g_PrintDlg.hDC) <= 0) { s_PrintIo.ErrorStringID = IDS_PRINTERRPRINTER; goto error_AbortDoc; } } // // Either a printer error occurred or the user cancelled the printing, so // abort the print job. // else { error_AbortDoc: AbortDoc(g_PrintDlg.hDC); } DestroyWindow(hRichEdit); FreeLibrary(hInstRichEdit); error_DeleteDocName: DeleteDynamicString(DocInfo.lpszDocName); // error_DestroyRegPrintAbortWnd: EnableWindow(hWnd, TRUE); DestroyWindow(s_PrintIo.hRegPrintAbortWnd); error_FreeLineBuffer: LocalFree((HLOCAL)s_PrintIo.pLineBuffer); error_DeleteDC: DeleteDC(g_PrintDlg.hDC); g_PrintDlg.hDC = NULL; GlobalUnlock(g_PrintDlg.hDevNames); error_ShowDialog: if (s_PrintIo.ErrorStringID != 0) InternalMessageBox(g_hInstance, hWnd, MAKEINTRESOURCE(s_PrintIo.ErrorStringID), MAKEINTRESOURCE(IDS_REGEDIT), MB_ICONERROR | MB_OK); } //------------------------------------------------------------------------------ // RegEdit_SaveAsSubtree // // DESCRIPTION: Saves a subtree to a file // // PARAMETERS: LPTSTR lpFileName - file name // LPTSTR lpSelectedPath - path to key //------------------------------------------------------------------------------ UINT RegEdit_SaveAsSubtree(LPTSTR lpFileName, LPTSTR lpSelectedPath) { s_PrintIo.pLineBuffer = (PTSTR) LocalAlloc(LPTR, INITIAL_PRINTBUFFER_SIZE*sizeof(TCHAR)); if (s_PrintIo.pLineBuffer) { FILE_HANDLE hFile; // Init the printing info s_PrintIo.pLineBuffer[0] = 0xFEFF; //unicode byte order mark s_PrintIo.cch = INITIAL_PRINTBUFFER_SIZE; s_PrintIo.cBufferPos = 1; s_PrintIo.fContinueJob = TRUE; s_PrintIo.ErrorStringID = 0; s_PrintIo.lpNewLineChars = TEXT("\r\n"); RegPrintSubtree(); // write the buffer to the file if (OPENWRITEFILE(lpFileName, hFile)) { DWORD cbWritten = 0; if (!WRITEFILE(hFile, s_PrintIo.pLineBuffer, s_PrintIo.cBufferPos*sizeof(TCHAR), &cbWritten)) { s_PrintIo.ErrorStringID = IDS_EXPFILEERRFILEWRITE; } CLOSEFILE(hFile); } else { s_PrintIo.ErrorStringID = IDS_EXPFILEERRFILEOPEN; } LocalFree(s_PrintIo.pLineBuffer); } return PrintToSubTreeError(s_PrintIo.ErrorStringID); } //------------------------------------------------------------------------------ // PrintToSubTreeError // // DESCRIPTION: Prints a subtree // // PARAMETER: UINT uPrintErrorStringID - print error string id //------------------------------------------------------------------------------ UINT PrintToSubTreeError(UINT uPrintErrorStringID) { UINT uError = uPrintErrorStringID; switch (uPrintErrorStringID) { case IDS_PRINTERRNOMEMORY: uError = IDS_SAVETREEERRNOMEMORY; case IDS_PRINTERRCANNOTREAD: uError = IDS_SAVETREEERRCANNOTREAD; } return uError; } //------------------------------------------------------------------------------ // RegPrintSubtree // // DESCRIPTION: Prints a subtree //------------------------------------------------------------------------------ void RegPrintSubtree() { HTREEITEM hSelectedTreeItem = TreeView_GetSelection(g_RegEditData.hKeyTreeWnd); if (g_fRangeAll) { HTREEITEM hComputerItem = RegEdit_GetComputerItem(hSelectedTreeItem); lstrcpy(g_SelectedPath, g_RegistryRoots[INDEX_HKEY_LOCAL_MACHINE].lpKeyName); PrintBranch(Regedit_GetRootKeyFromComputer(hComputerItem, g_SelectedPath), g_SelectedPath); lstrcpy(g_SelectedPath, g_RegistryRoots[INDEX_HKEY_USERS].lpKeyName); PrintBranch(Regedit_GetRootKeyFromComputer(hComputerItem, g_SelectedPath), g_SelectedPath); } else { HKEY hKey; if (EditRegistryKey(RegEdit_GetComputerItem(hSelectedTreeItem), &hKey, g_SelectedPath, ERK_OPEN) == ERROR_SUCCESS) { PrintBranch(hKey, g_SelectedPath); RegCloseKey(hKey); } } } /******************************************************************************* * * RegPrintAbortProc * * DESCRIPTION: * Callback procedure to check if the print job should be canceled. * * PARAMETERS: * hDC, handle of printer device context. * Error, specifies whether an error has occurred. * (returns), TRUE to continue the job, else FALSE to cancel the job. * *******************************************************************************/ BOOL CALLBACK RegPrintAbortProc( HDC hDC, int Error ) { while (s_PrintIo.fContinueJob && MessagePump(s_PrintIo.hRegPrintAbortWnd)) ; return s_PrintIo.fContinueJob; UNREFERENCED_PARAMETER(hDC); UNREFERENCED_PARAMETER(Error); } /******************************************************************************* * * RegPrintAbortDlgProc * * DESCRIPTION: * Callback procedure for the RegPrintAbort dialog box. * * PARAMETERS: * hWnd, handle of RegPrintAbort window. * Message, * wParam, * lParam, * (returns), * *******************************************************************************/ INT_PTR CALLBACK RegPrintAbortDlgProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam ) { switch (Message) { case WM_INITDIALOG: break; case WM_CLOSE: case WM_COMMAND: s_PrintIo.fContinueJob = FALSE; break; default: return FALSE; } return TRUE; } /******************************************************************************* * * PrintBranch * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/ void PrintBranch(HKEY hKey, LPTSTR lpFullKeyName) { // Write out the section header. PrintKeyHeader(hKey, lpFullKeyName); // Print the vales for the key. PrintKeyValues(hKey); if (s_PrintIo.ErrorStringID == 0) { HKEY hSubKey; int nLenFullKey; DWORD EnumIndex = 0; LPTSTR lpSubKeyName; LPTSTR lpTempFullKeyName; // Write out all of the subkeys and recurse into them. //copy the existing key into a new buffer with enough room for the next key nLenFullKey = lstrlen(lpFullKeyName); lpTempFullKeyName = (LPTSTR) alloca( (nLenFullKey+MAXKEYNAME)*sizeof(TCHAR)); lstrcpy(lpTempFullKeyName, lpFullKeyName); lpSubKeyName = lpTempFullKeyName + nLenFullKey; *lpSubKeyName++ = TEXT('\\'); *lpSubKeyName = 0; PrintNewLine(); while (s_PrintIo.fContinueJob) { if (RegEnumKey(hKey, EnumIndex++, lpSubKeyName, MAXKEYNAME-1) != ERROR_SUCCESS) break; if(RegOpenKeyEx(hKey,lpSubKeyName,0,KEY_ENUMERATE_SUB_KEYS|KEY_QUERY_VALUE,&hSubKey) == NO_ERROR) { PrintBranch(hSubKey, lpTempFullKeyName); RegCloseKey(hSubKey); } else { DebugPrintf(("RegOpenKey failed.")); } } } } //------------------------------------------------------------------------------ // PrintKeyHeader // // DESCRIPTION: Prints the header information of a key // // PARAMETERS: HKEY hKey - key // LPTSTR lpFullKeyName - path to key //------------------------------------------------------------------------------ void PrintKeyValues(HKEY hKey) { DWORD EnumIndex = 0; // Write out all of the value names and their data. while (s_PrintIo.fContinueJob) { DWORD Type; DWORD cbValueData; PBYTE pbValueData; TCHAR acAuxNumber[MAXVALUENAME_LENGTH]; DWORD cchValueName = ARRAYSIZE(g_ValueNameBuffer); // Query for data size if (RegEnumValue(hKey, EnumIndex++, g_ValueNameBuffer, &cchValueName, NULL, &Type, NULL, &cbValueData) != ERROR_SUCCESS) { break; } // Print value number PrintDynamicString(IDS_PRINT_NUMBER); wsprintf(acAuxNumber, TEXT("%d"), EnumIndex - 1); PrintLiteral(acAuxNumber); PrintNewLine(); // Print key name PrintDynamicString(IDS_PRINT_NAME); if (cchValueName) { PrintLiteral(g_ValueNameBuffer); } else { PrintDynamicString(IDS_PRINT_NO_NAME); } PrintNewLine(); // Print Type PrintType(Type); // allocate memory for data pbValueData = LocalAlloc(LPTR, cbValueData+ExtraAllocLen(Type)); if (pbValueData) { if (RegEdit_QueryValueEx(hKey, g_ValueNameBuffer, NULL, &Type, pbValueData, &cbValueData) == ERROR_SUCCESS) { PrintValueData(pbValueData, cbValueData, Type); } else { s_PrintIo.ErrorStringID = IDS_PRINTERRCANNOTREAD; } if (pbValueData) { LocalFree(pbValueData); pbValueData = NULL; } } else { s_PrintIo.ErrorStringID = IDS_PRINTERRNOMEMORY; break; } } } //------------------------------------------------------------------------------ // PrintValueData // // DESCRIPTION: Prints the header information of a key // // PARAMETERS: pbValueData - byte data // cbValueData - count of bytes // dwType - data type //------------------------------------------------------------------------------ void PrintValueData(PBYTE pbValueData, DWORD cbValueData, DWORD dwType) { PrintDynamicString(IDS_PRINT_DATA); switch (dwType) { case REG_MULTI_SZ: PrintMultiString((LPTSTR)pbValueData, cbValueData); break; case REG_SZ: case REG_EXPAND_SZ: PrintLiteral((LPTSTR)pbValueData); PrintNewLine(); break; case REG_DWORD: PrintDWORDData((PBYTE)pbValueData, cbValueData); break; case REG_RESOURCE_LIST: case REG_FULL_RESOURCE_DESCRIPTOR: case REG_RESOURCE_REQUIREMENTS_LIST: PrintResourceData((PBYTE)pbValueData, cbValueData, dwType); break; default: PrintBinaryData((PBYTE)pbValueData, cbValueData); break; } PrintNewLine(); } //------------------------------------------------------------------------------ // PrintKeyHeader // // DESCRIPTION: Prints the header information of a key // // PARAMETERS: HKEY hKey - key // LPTSTR lpFullKeyName - path to key //------------------------------------------------------------------------------ void PrintKeyHeader(HKEY hKey, LPTSTR lpFullKeyName) { PrintDynamicString(IDS_PRINT_KEY_NAME); PrintLiteral(lpFullKeyName); PrintNewLine(); PrintClassName(hKey); PrintLastWriteTime(hKey); } //------------------------------------------------------------------------------ // PrintClassName // // DESCRIPTION: Prints the class name // // PARAMETERS: HKEY hKey - key //------------------------------------------------------------------------------ void PrintClassName(HKEY hKey) { PTSTR pszClass; PrintDynamicString(IDS_PRINT_CLASS_NAME); pszClass = LocalAlloc(LPTR, ALLOCATION_INCR); if (pszClass) { HRESULT hr; DWORD cbClass = sizeof(pszClass); hr = RegQueryInfoKey(hKey, pszClass, &cbClass, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (hr == ERROR_MORE_DATA) { // need a bigger buffer PBYTE pbValueData = LocalReAlloc(pszClass, cbClass + 1, LMEM_MOVEABLE); if (pbValueData) { pszClass = (PTSTR)pbValueData; hr = RegQueryInfoKey(hKey, pszClass, &cbClass, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } } if (cbClass && (hr == ERROR_SUCCESS)) { PrintLiteral(pszClass); } else { PrintDynamicString(IDS_PRINT_NO_CLASS); } LocalFree(pszClass); } PrintNewLine(); } //------------------------------------------------------------------------------ // PrintLastWriteTime // // DESCRIPTION: Prints the last write time // // PARAMETERS: HKEY hKey - key //------------------------------------------------------------------------------ void PrintLastWriteTime(HKEY hKey) { FILETIME ftLastWriteTime; PrintDynamicString(IDS_PRINT_LAST_WRITE_TIME); if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ftLastWriteTime) == ERROR_SUCCESS) { FILETIME ftLocalLastWriteTime; if (FileTimeToLocalFileTime(&ftLastWriteTime, &ftLocalLastWriteTime)) { SYSTEMTIME stLastWriteTime; if (FileTimeToSystemTime(&ftLocalLastWriteTime, &stLastWriteTime)) { TCHAR achData[50]; TCHAR achTime[50]; GetDateFormat(GetSystemDefaultLCID(), DATE_SHORTDATE, &stLastWriteTime, NULL, achData, ARRAYSIZE(achData)); GetTimeFormat(GetSystemDefaultLCID(), TIME_NOSECONDS, &stLastWriteTime, NULL, achTime, ARRAYSIZE(achTime)); PrintLiteral(achData); PrintLiteral(TEXT(" - ")); PrintLiteral(achTime); } } } PrintNewLine(); } //------------------------------------------------------------------------------ // PrintDynamicString // // DESCRIPTION: Prints the dynamic string // // PARAMETERS: UINT uStringID - resource string id //------------------------------------------------------------------------------ void PrintDynamicString(UINT uStringID) { PTSTR psz = LoadDynamicString(uStringID); if (psz) { PrintLiteral(psz); DeleteDynamicString(psz); } } //------------------------------------------------------------------------------ // PrintType // // DESCRIPTION: Prints the value type // // PARAMETERS: HKEY hKey - key //------------------------------------------------------------------------------ void PrintType(DWORD dwType) { UINT uTypeStringId; switch (dwType) { case REG_NONE: uTypeStringId = IDS_PRINT_TYPE_REG_NONE; break; case REG_SZ: uTypeStringId = IDS_PRINT_TYPE_REG_SZ; break; case REG_EXPAND_SZ: uTypeStringId = IDS_PRINT_TYPE_REG_EXPAND_SZ; break; case REG_BINARY: uTypeStringId = IDS_PRINT_TYPE_REG_BINARY; break; case REG_DWORD: uTypeStringId = IDS_PRINT_TYPE_REG_DWORD; break; case REG_LINK: uTypeStringId = IDS_PRINT_TYPE_REG_LINK; break; case REG_MULTI_SZ: uTypeStringId = IDS_PRINT_TYPE_REG_MULTI_SZ; break; case REG_RESOURCE_LIST: uTypeStringId = IDS_PRINT_TYPE_REG_RESOURCE_LIST; break; case REG_FULL_RESOURCE_DESCRIPTOR: uTypeStringId = IDS_PRINT_TYPE_REG_FULL_RESOURCE_DESCRIPTOR; break; case REG_RESOURCE_REQUIREMENTS_LIST: uTypeStringId = IDS_PRINT_TYPE_REG_RESOURCE_REQUIREMENTS_LIST; break; case REG_QWORD: uTypeStringId = IDS_PRINT_TYPE_REG_REG_QWORD; break; default: uTypeStringId = IDS_PRINT_TYPE_REG_UNKNOWN; } PrintDynamicString(IDS_PRINT_TYPE); PrintDynamicString(uTypeStringId); PrintNewLine(); } /******************************************************************************* * * PrintLiteral * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/ VOID PrintLiteral(PTSTR lpLiteral) { if (s_PrintIo.fContinueJob) while (*lpLiteral != 0 && PrintChar(*lpLiteral++)); } //------------------------------------------------------------------------------ // PrintBinaryData // // DESCRIPTION: Print a string that contains the binary data // // PARAMETERS: ValueData - Buffer that contains the binary data // cbValueData - Number of bytes in the buffer //------------------------------------------------------------------------------ void PrintBinaryData(PBYTE ValueData, UINT cbValueData) { DWORD dwDataIndex; DWORD dwDataIndex2 = 0; //tracks multiples of 16. if (cbValueData && ValueData) { // Display rows of 16 bytes of data. TCHAR achAuxData[80]; PrintNewLine(); for(dwDataIndex = 0; dwDataIndex < ( cbValueData >> 4 ); dwDataIndex++, dwDataIndex2 = dwDataIndex << 4 ) { // The string that contains the format in the sprintf below // cannot be broken because cfront on mips doesn't like it. wsprintf(achAuxData, TEXT("%08x %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c"), dwDataIndex2, ValueData[ dwDataIndex2 + 0 ], ValueData[ dwDataIndex2 + 1 ], ValueData[ dwDataIndex2 + 2 ], ValueData[ dwDataIndex2 + 3 ], ValueData[ dwDataIndex2 + 4 ], ValueData[ dwDataIndex2 + 5 ], ValueData[ dwDataIndex2 + 6 ], ValueData[ dwDataIndex2 + 7 ], ValueData[ dwDataIndex2 + 8 ], ValueData[ dwDataIndex2 + 9 ], ValueData[ dwDataIndex2 + 10 ], ValueData[ dwDataIndex2 + 11 ], ValueData[ dwDataIndex2 + 12 ], ValueData[ dwDataIndex2 + 13 ], ValueData[ dwDataIndex2 + 14 ], ValueData[ dwDataIndex2 + 15 ], iswprint( ValueData[ dwDataIndex2 + 0 ] ) ? ValueData[ dwDataIndex2 + 0 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 1 ] ) ? ValueData[ dwDataIndex2 + 1 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 2 ] ) ? ValueData[ dwDataIndex2 + 2 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 3 ] ) ? ValueData[ dwDataIndex2 + 3 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 4 ] ) ? ValueData[ dwDataIndex2 + 4 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 5 ] ) ? ValueData[ dwDataIndex2 + 5 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 6 ] ) ? ValueData[ dwDataIndex2 + 6 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 7 ] ) ? ValueData[ dwDataIndex2 + 7 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 8 ] ) ? ValueData[ dwDataIndex2 + 8 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 9 ] ) ? ValueData[ dwDataIndex2 + 9 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 10 ] ) ? ValueData[ dwDataIndex2 + 10 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 11 ] ) ? ValueData[ dwDataIndex2 + 11 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 12 ] ) ? ValueData[ dwDataIndex2 + 12 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 13 ] ) ? ValueData[ dwDataIndex2 + 13 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 14 ] ) ? ValueData[ dwDataIndex2 + 14 ] : TEXT('.'), iswprint( ValueData[ dwDataIndex2 + 15 ] ) ? ValueData[ dwDataIndex2 + 15 ] : TEXT('.')); PrintLiteral(achAuxData); PrintNewLine(); } // If the cbValueData is not an even multiple of 16 // then there is one additonal line of data to display. if( cbValueData % 16 != 0 ) { UINT cchBlanks = 0; UINT uLinePos = 0; DWORD dwSeperatorChars = 0; UINT uIndex = wsprintf(achAuxData, TEXT("%08x "), dwDataIndex << 4 ); // Display the remaining data, one byte at a time in hex. for(dwDataIndex = dwDataIndex2; dwDataIndex < cbValueData; dwDataIndex++ ) { uIndex += wsprintf((achAuxData + uIndex ), TEXT("%02x "), ValueData[dwDataIndex]); // If eight data values have been displayed, print the seperator. if( dwDataIndex % 8 == 7 ) { uIndex += wsprintf( &achAuxData[uIndex], TEXT("%s"), TEXT("- ")); // Remember that two seperator characters were displayed. dwSeperatorChars = 2; } } // Fill with blanks to the printable characters position. // That is position 64 less 8 spaces for the 'address', // 3 blanks, 3 spaces for each value displayed, possibly // two for the seperator plus two blanks at the end. uLinePos = (8 + 3 + (( dwDataIndex % 16 ) * 3 ) + dwSeperatorChars + 2 ); uLinePos = min(uLinePos, 64); for(cchBlanks = 64 - uLinePos; cchBlanks > 0; cchBlanks--) { achAuxData[uIndex++] = TEXT(' '); } // Display the remaining data, one byte at a time as // printable characters. for( dwDataIndex = dwDataIndex2; dwDataIndex < cbValueData; dwDataIndex++ ) { uIndex += wsprintf(&achAuxData[ uIndex ], TEXT("%c"), iswprint( ValueData[ dwDataIndex ] ) ? ValueData[ dwDataIndex ] : TEXT('.')); } PrintLiteral(achAuxData); } } PrintNewLine(); } //------------------------------------------------------------------------------ // PrintDWORDData // // DESCRIPTION: Prints a DWORD // // PARAMETERS: ValueData - Buffer that contains the binary data // cbValueData - Number of bytes in the buffer //------------------------------------------------------------------------------ void PrintDWORDData(PBYTE ValueData, UINT cbValueData) { DWORD dwData = *((PDWORD)ValueData); if (cbValueData && ValueData) { TCHAR achAuxData[20]; // the largest dword string is only 8 hex digits wsprintf(achAuxData, TEXT("%#x"), dwData); PrintLiteral(achAuxData); } PrintNewLine(); } /******************************************************************************* * * PrintChar * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/ BOOL PrintChar(TCHAR Char) { // // Keep track of what column we're currently at. This is useful in cases // such as writing a large binary registry record. Instead of writing one // very long line, the other Print* routines can break up their output. // if (s_PrintIo.cBufferPos == s_PrintIo.cch) { PTSTR pNewBuffer = LocalAlloc(LPTR, 2*s_PrintIo.cch*sizeof(TCHAR)); if (pNewBuffer == NULL) return FALSE; memcpy(pNewBuffer, s_PrintIo.pLineBuffer, s_PrintIo.cch*sizeof(TCHAR)); LocalFree(s_PrintIo.pLineBuffer); s_PrintIo.pLineBuffer = pNewBuffer; s_PrintIo.cch *= 2; } s_PrintIo.pLineBuffer[s_PrintIo.cBufferPos++] = Char; return TRUE; } //------------------------------------------------------------------------------ // PrintMultiString // // DESCRIPTION: Prints a multi-string // // PARAMETERS: pszData - string // cbData - number of bytes in string, including nulls //------------------------------------------------------------------------------ VOID PrintMultiString(LPTSTR pszData, int cbData) { if (s_PrintIo.fContinueJob) { int i = 0; int ccData = (cbData / sizeof(TCHAR)) - 2; // don't want last null of last string or multi-string for(i = 0; i < ccData; i++) { if (pszData[i] == TEXT('\0')) { PrintNewLine(); PrintDynamicString(IDS_PRINT_KEY_NAME_INDENT); } else { PrintChar(pszData[i]); } } } PrintNewLine(); } //------------------------------------------------------------------------------ // PrintNewLine() // // DESCRIPTION: Prints the newline chars. // // PARAMETERS: pszData - string // cbData - number of bytes in string, including nulls //------------------------------------------------------------------------------ void PrintNewLine() { PrintLiteral(s_PrintIo.lpNewLineChars); }