docstats.dpr
来自「一本已经绝版的好书」· DPR 代码 · 共 228 行
DPR
228 行
// Module name: DocStats.C ->> DocStats.dpr
// Notices: Copyright (c) 1995-1997 Jeffrey Richter
// Translator: 刘麻子, Liu_mazi@126.com
program DocStats;
{$R 'DocStats.res' 'DocStats.rc'}
uses
Windows, Messages, CommDlg,
Other in '..\Other.pas', CmnHdr in '..\CmnHdr.pas', WindowsX in '..\WindowsX.pas';
const
g_szModName = 'DocStats';
IDD_DOCSTATS = 1;
IDC_FILESELECT = 101;
IDI_DOCSTATS = 102;
IDC_FILENAME = 1000;
IDC_DODOCSTATS = 1001;
IDC_NUMLETTERS = 1002;
IDC_NUMWORDS = 1003;
IDC_NUMLINES = 1004;
const
STAT_LETTERS = 0;
STAT_WORDS = 1;
STAT_LINES = 2;
STAT_FIRST = STAT_LETTERS;
STAT_LAST = STAT_LINES;
type
TStatType = STAT_FIRST..STAT_LAST;
var
g_hEventsDataReady: array[TStatType] of THandle; // 数据已经准备好
g_hEventsProcIdle: array[TStatType] of THandle; // 数据已经处理过
g_bFileBuf: array[0..1023] of Byte; // 文件内容缓冲区
g_dwNumBytesInBuf: DWORD; // 缓冲区数据长度
// 处理线程
function StatThreadFunc(StatType: TStatType): Integer;
var
dwByteIndex: Integer;
bByte: Byte;
fInWord, fIsWordSep: BOOL;
begin
Result := 0;
fInWord := FALSE;
repeat
WaitForSingleObject(g_hEventsDataReady[StatType], INFINITE); // 等待数据
case (StatType) of
STAT_LETTERS: // 字母
for dwByteIndex := 0 to g_dwNumBytesInBuf - 1 do
begin
bByte := g_bFileBuf[dwByteIndex];
if IsCharAlpha(Char(bByte)) then Inc(Result);
end;
STAT_WORDS: // 单词
for dwByteIndex := 0 to g_dwNumBytesInBuf - 1 do
begin
bByte := g_bFileBuf[dwByteIndex];
fIsWordSep := StrChr(' '#9#13#10, Char(bByte)) <> nil; // 是否分隔符
if (fInWord = FALSE) and (fIsWordSep = FALSE) then // 遇到新的单词
begin
Inc(Result);
fInWord := TRUE; // 当前处于单词中
end else
if (fInWord) and (fIsWordSep) then fInWord := FALSE; // 遇到单词后第一个分隔符
end;
STAT_LINES: // 行
for dwByteIndex := 0 to g_dwNumBytesInBuf - 1 do
begin
bByte := g_bFileBuf[dwByteIndex];
if (bByte = 13) then Inc(Result);
end;
end;
SetEvent(g_hEventsProcIdle[StatType]); // 处理完毕
until (g_dwNumBytesInBuf = 0);
end;
// 统计文档
function Doc_Stats(const pszPathname: PChar; var pdwNumLetters, pdwNumWords, pdwNumLines: DWORD): BOOL;
var
hFile: THandle;
hThreads: array[TStatType] of THandle;
dwThreadID: DWORD;
StatType: TStatType;
begin
Result := FALSE;
pdwNumLetters := 0;
pdwNumWords := 0;
pdwNumLines := 0;
// 以只读方式打开文件
hFile := CreateFile(pszPathname, GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile = INVALID_HANDLE_VALUE) then
begin
chMB('File could not be opened ', g_szModName);
Exit;
end;
// 建立事件对象和线程
for StatType := STAT_FIRST to STAT_LAST do
begin
g_hEventsDataReady[StatType] := CreateEvent(nil, FALSE, FALSE, nil); // 数据还未准备好
g_hEventsProcIdle[StatType] := CreateEvent(nil, FALSE, TRUE, nil); // 没有数据未处理
hThreads[StatType] := BeginThread(nil, 0, @StatThreadFunc, Pointer(StatType), 0, dwThreadID);
end;
// 分批读出文件并处理
repeat
// 等待处理完毕
WaitForMultipleObjects(STAT_LAST - STAT_FIRST + 1, @g_hEventsProcIdle, TRUE, INFINITE);
// 读出部分内容
ReadFile(hFile, g_bFileBuf, chDIMOF(g_bFileBuf), g_dwNumBytesInBuf, nil);
// 唤醒处理线程
for StatType := STAT_FIRST to STAT_LAST do SetEvent(g_hEventsDataReady[StatType]);
until (g_dwNumBytesInBuf = 0);
// 关闭文件句柄
CloseHandle(hFile);
// 等待线程结束
WaitForMultipleObjects(STAT_LAST - STAT_FIRST + 1, @hThreads, TRUE, INFINITE);
// 取得统计结果
GetExitCodeThread(hThreads[STAT_LETTERS], pdwNumLetters);
GetExitCodeThread(hThreads[STAT_WORDS], pdwNumWords);
GetExitCodeThread(hThreads[STAT_LINES], pdwNumLines);
// 清除内核对象
for StatType := STAT_FIRST to STAT_LAST do
begin
CloseHandle(hThreads[StatType]);
CloseHandle(g_hEventsDataReady[StatType]);
CloseHandle(g_hEventsProcIdle[StatType]);
end;
Result := TRUE;
end;
// WM_INITDIALOG
function Dlg_OnInitDialog(hWnd, hWndFocus: HWND; lParam: LPARAM): BOOL;
begin
chSETDLGICONS(hWnd, IDI_DOCSTATS, IDI_DOCSTATS);
EnableWindow(GetDlgItem(hWnd, IDC_DODOCSTATS), FALSE);
Result := TRUE;
end;
// WM_COMMAND
procedure Dlg_OnCommand(hWnd: HWND; id: Integer; hWndCtl: HWND; codeNotify: UINT);
var
szPathname: array[0..MAX_PATH] of Char;
ofn: TOpenFilename;
dwNumLetters, dwNumWords, dwNumLines: DWORD;
begin
case (id) of
IDC_FILENAME: // 文件名Edit
begin
EnableWindow(GetDlgItem(hWnd, IDC_DODOCSTATS), Edit_GetTextLength(hWndCtl) > 0);
end;
IDC_FILESELECT: // 选择文件
begin
chINITSTRUCT(ofn, SizeOf(ofn), TRUE);
ofn.hWndOwner := hWnd;
ofn.lpstrFile := szPathname;
ofn.lpstrFile[0] := #0;
ofn.nMaxFile := chDIMOF(szPathname);
ofn.lpstrTitle := 'Select file for reversing';
ofn.Flags := OFN_EXPLORER or OFN_FILEMUSTEXIST;
GetOpenFileName(ofn);
SetDlgItemText(hWnd, IDC_FILENAME, ofn.lpstrFile);
SetFocus(GetDlgItem(hWnd, IDC_DODOCSTATS));
end;
IDC_DODOCSTATS: // 统计
begin
GetDlgItemText(hWnd, IDC_FILENAME, szPathname, chDIMOF(szPathname));
if Doc_Stats(szPathname, dwNumLetters, dwNumWords, dwNumLines) then
begin
SetDlgItemInt(hWnd, IDC_NUMLETTERS, dwNumLetters, FALSE);
SetDlgItemInt(hWnd, IDC_NUMWORDS, dwNumWords, FALSE);
SetDlgItemInt(hWnd, IDC_NUMLINES, dwNumLines, FALSE);
end;
end;
IDCANCEL: // 退出程序
begin
EndDialog(hWnd, id);
end;
end;
end;
// 对话框回调
function Dlg_Proc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall;
begin
case (uMsg) of
WM_INITDIALOG:
begin
Result := SetDlgMsgResult(hWnd, LRESULT(Dlg_OnInitDialog(hWnd, wParam, lParam)));
end;
WM_COMMAND:
begin
Dlg_OnCommand(hWnd, LOWORD(wParam), lParam, HIWORD(wParam));
Result := TRUE;
end;
else Result := FALSE;
end;
end;
// 主线程入口
begin
chWARNIFUNICODEUNDERWIN95();
DialogBox(HInstance, MakeIntResource(IDD_DOCSTATS), 0, @Dlg_Proc);
end.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?