mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
611 lines
12 KiB
611 lines
12 KiB
/*******************************************************************************
|
|
*
|
|
* (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;
|
|
|
|
}
|