/******************************************************************************* * * (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" const CHAR s_PrintLineBreak[] = ",\n "; PRINTDLG g_PrintDlg; typedef struct _PRINT_IO { BOOL fContinueJob; UINT ErrorStringID; HWND hRegPrintAbortWnd; UINT CharsPerLine; UINT CurrentColumn; int LineHeight; int xLeft; int yTop; int xRight; int yBottom; int yCurrent; PSTR pLineBuffer; } PRINT_IO; #define CANCEL_NONE 0x0000 #define CANCEL_MEMORY_ERROR 0x0001 #define CANCEL_PRINTER_ERROR 0x0002 #define CANCEL_ABORT 0x0004 PRINT_IO s_PrintIo; BOOL CALLBACK RegPrintAbortProc( HDC hDC, int Error ); BOOL CALLBACK RegPrintAbortDlgProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam ); VOID PASCAL PrintBranch( HKEY hKey, LPSTR lpFullKeyName ); VOID PASCAL PrintLiteral( LPCSTR lpLiteral ); VOID PASCAL PrintBinary( CONST BYTE FAR* lpBuffer, DWORD cbBytes ); BOOL PASCAL PrintChar( CHAR Char ); /******************************************************************************* * * 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; HKEY hKey; TEXTMETRIC TextMetric; DOCINFO DocInfo; g_PrintDlg.lStructSize = sizeof(PRINTDLG); g_PrintDlg.hwndOwner = hWnd; g_PrintDlg.Flags = PD_ENABLEPRINTHOOK | PD_ENABLEPRINTTEMPLATE | PD_NOPAGENUMS | PD_SHOWHELP | PD_RETURNDC; g_PrintDlg.hInstance = g_hInstance; g_PrintDlg.lpfnPrintHook = RegCommDlgHookProc; g_PrintDlg.lpPrintTemplateName = MAKEINTRESOURCE(IDD_REGPRINT); g_RegCommDlgDialogTemplate = IDD_REGPRINT; if (!PrintDlg(&g_PrintDlg)) return; s_PrintIo.ErrorStringID = IDS_PRINTERRNOMEMORY; if ((lpDevNames = GlobalLock(g_PrintDlg.hDevNames)) == NULL) goto error_ShowDialog; if (!g_fRangeAll) { if (EditRegistryKey(&hKey, g_SelectedPath, ERK_OPEN) != ERROR_SUCCESS) goto error_UnlockDevNames; } // // Calculate the dimensions of the page and of the font being used. // GetTextMetrics(g_PrintDlg.hDC, &TextMetric); s_PrintIo.LineHeight = TextMetric.tmHeight; // // 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). // s_PrintIo.yTop = GetDeviceCaps(g_PrintDlg.hDC, LOGPIXELSY) / 2; s_PrintIo.yCurrent = s_PrintIo.yTop; s_PrintIo.yBottom = GetDeviceCaps(g_PrintDlg.hDC, VERTRES) - s_PrintIo.yTop; s_PrintIo.xLeft = GetDeviceCaps(g_PrintDlg.hDC, LOGPIXELSX) * 3 / 4; s_PrintIo.xRight = GetDeviceCaps(g_PrintDlg.hDC, HORZRES) - s_PrintIo.xLeft; s_PrintIo.CharsPerLine = (s_PrintIo.xRight - s_PrintIo.xLeft) / TextMetric.tmAveCharWidth; s_PrintIo.CurrentColumn = 0; // // // // BUGBUG: Allocate 2x for DBCS? if ((s_PrintIo.pLineBuffer = (PSTR) LocalAlloc(LPTR, s_PrintIo.CharsPerLine)) == NULL) goto error_DeleteDC; 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.fContinueJob = TRUE; SetAbortProc(g_PrintDlg.hDC, RegPrintAbortProc); DocInfo.cbSize = sizeof(DOCINFO); DocInfo.lpszDocName = LoadDynamicString(IDS_REGEDIT); DocInfo.lpszOutput = (LPSTR) 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 the desired range of the registry. // if (g_fRangeAll) { lstrcpy(g_SelectedPath, g_RegistryRoots[INDEX_HKEY_LOCAL_MACHINE].lpKeyName); PrintBranch(HKEY_LOCAL_MACHINE, g_SelectedPath); lstrcpy(g_SelectedPath, g_RegistryRoots[INDEX_HKEY_USERS].lpKeyName); PrintBranch(HKEY_USERS, g_SelectedPath); } else PrintBranch(hKey, g_SelectedPath); // // Eject the last page and end the print job. // if (s_PrintIo.ErrorStringID == 0 && s_PrintIo.fContinueJob) { if ((s_PrintIo.yCurrent != s_PrintIo.yTop && EndPage(g_PrintDlg.hDC) <= 0) || 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); } 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); if (!g_fRangeAll) RegCloseKey(hKey); error_UnlockDevNames: 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); } /******************************************************************************* * * 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), * *******************************************************************************/ BOOL 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 PASCAL PrintBranch( HKEY hKey, LPSTR lpFullKeyName ) { DWORD EnumIndex; DWORD cbValueName; DWORD cbValueData; DWORD Type; LPSTR lpSubKeyName; int MaximumSubKeyLength; HKEY hSubKey; // // Write out the section header. // PrintChar('['); PrintLiteral(lpFullKeyName); PrintLiteral("]\n"); // // Write out all of the value names and their data. // EnumIndex = 0; while (s_PrintIo.fContinueJob) { cbValueName = sizeof(g_ValueNameBuffer); cbValueData = MAXDATA_LENGTH; if (RegEnumValue(hKey, EnumIndex++, g_ValueNameBuffer, &cbValueName, NULL, &Type, g_ValueDataBuffer, &cbValueData) != ERROR_SUCCESS) break; // // If cbValueName is zero, then this is the default value of // the key, or the Windows 3.1 compatible key value. // if (cbValueName) PrintLiteral(g_ValueNameBuffer); else PrintChar('@'); PrintChar('='); switch (Type) { case REG_SZ: PrintLiteral(g_ValueDataBuffer); break; default: PrintBinary((LPBYTE) g_ValueDataBuffer, cbValueData); break; } PrintChar('\n'); } PrintChar('\n'); // // Write out all of the subkeys and recurse into them. // MaximumSubKeyLength = lstrlen(lpFullKeyName); lpSubKeyName = lpFullKeyName + MaximumSubKeyLength; *lpSubKeyName++ = '\\'; MaximumSubKeyLength = SIZE_SELECTED_PATH - MaximumSubKeyLength - 1; EnumIndex = 0; while (s_PrintIo.fContinueJob) { if (RegEnumKey(hKey, EnumIndex++, lpSubKeyName, MaximumSubKeyLength) != ERROR_SUCCESS) break; if (RegOpenKey(hKey, lpSubKeyName, &hSubKey) == ERROR_SUCCESS) { PrintBranch(hSubKey, lpFullKeyName); RegCloseKey(hSubKey); } else { DbgPrintf(("RegOpenKey failed.")); } } } /******************************************************************************* * * PrintLiteral * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/ VOID PASCAL PrintLiteral( LPCSTR lpLiteral ) { if (s_PrintIo.fContinueJob) while (*lpLiteral != '\0' && PrintChar(*lpLiteral++)); } /******************************************************************************* * * PrintBinary * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/ VOID PASCAL PrintBinary( CONST BYTE FAR* lpBuffer, DWORD cbBytes ) { BOOL fFirstByteOnLine; UINT EndColumn; BYTE Byte; fFirstByteOnLine = TRUE; // // Figure out the last column where we can print out the start of a // hexadecimal number without breaking it across lines. // EndColumn = s_PrintIo.CharsPerLine - 5; while (cbBytes--) { if (s_PrintIo.CurrentColumn > EndColumn) { PrintLiteral(s_PrintLineBreak); fFirstByteOnLine = TRUE; } if (!fFirstByteOnLine) PrintChar(','); Byte = *lpBuffer++; PrintChar(g_HexConversion[Byte >> 4]); PrintChar(g_HexConversion[Byte & 0x0F]); fFirstByteOnLine = FALSE; } } /******************************************************************************* * * PrintChar * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/ BOOL PASCAL PrintChar( CHAR 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 (Char != '\n') { // BUGBUG: DBCS enabling here?! s_PrintIo.pLineBuffer[s_PrintIo.CurrentColumn++] = Char; if (s_PrintIo.CurrentColumn != s_PrintIo.CharsPerLine) return TRUE; } if (s_PrintIo.yCurrent == s_PrintIo.yTop) if (StartPage(g_PrintDlg.hDC) <= 0) goto error_SetErrorCode; TextOut(g_PrintDlg.hDC, s_PrintIo.xLeft, s_PrintIo.yCurrent, s_PrintIo.pLineBuffer, s_PrintIo.CurrentColumn); s_PrintIo.yCurrent += s_PrintIo.LineHeight; if (s_PrintIo.yCurrent >= s_PrintIo.yBottom) { if (EndPage(g_PrintDlg.hDC) <= 0) { error_SetErrorCode: if (s_PrintIo.fContinueJob) { s_PrintIo.fContinueJob = FALSE; s_PrintIo.ErrorStringID = IDS_PRINTERRPRINTER; } return FALSE; } s_PrintIo.yCurrent = s_PrintIo.yTop; } s_PrintIo.CurrentColumn = 0; return TRUE; }