Windows最初发行时的主要目标之一就是提倡一种标准化的用户界面。对于公用菜单 项来说,这一目标实现得很快。几乎所有的软件制造商都采用了Alt-File-Open组合来打开 文件。但是,真正用来打开文件的对话框却经常很不一样。
从Windows 3.1开始,这一问题的解决方案开始出现。这一方案被称作“公用对话框库”(common dialogue box library)。这个库包括了一些函数,可以用来激活打开和存储文件、 查找和替换、选择颜色、选择字体以及打印(将在第十三章中演示)的对话框。
在使用这些函数时,基本上要初始化一个结构的一些字段并将该结构的指针传递给公用对话框库的某个函数。该函数会创建并显示相应对话框。当用户关闭对话框时,函数将控制权返还给程序,然后程序可以从此前传递给函数的结构中获取信息。
需要在所有用到公用对话框库的C源文件中包括COMMDLG.H头文件。
本节必须掌握的知识点:
公用对话框
第68练:完善的POPPAD
第69练:颜色对话框模板
10.3.1 公用对话框
■打开文件公用对话框
要打开文件的公用对话框,可以使用 Windows API 中的 GetOpenFileName 函数。该函数允许用户选择一个文件,并返回所选文件的路径。
以下是 GetOpenFileName 函数的函数原型:
BOOL GetOpenFileName(
LPOPENFILENAME lpofn
);
参数说明:
lpofn:指向 OPENFILENAME 结构体的指针,它包含了打开文件对话框的各种参数和选项。
返回值:
如果用户选择了文件并点击了打开按钮,函数返回非零值 (TRUE)。
如果用户取消了对话框或者发生了错误,函数返回零值 (FALSE)。
OPENFILENAME 是一个结构体,用于配置和传递给 GetOpenFileName 和 GetSaveFileName 函数的参数和选项。它定义了打开文件对话框和保存文件对话框的行为。
以下是 OPENFILENAME 结构体的定义:
typedef struct tagOFN {
DWORD lStructSize;// 结构体的大小,必须设置为 sizeof(OPENFILENAME)
HWND hwndOwner; // 父窗口的句柄
HINSTANCE hInstance; // 应用程序实例句柄
LPCTSTR lpstrFilter; // 文件过滤器
LPTSTR lpstrCustomFilter; // 自定义过滤器
DWORD nMaxCustFilter; // 自定义过滤器的最大长度
DWORD nFilterIndex; // 初始选择的过滤器索引
LPTSTR lpstrFile; // 接收选择的文件路径的缓冲区
DWORD nMaxFile; // lpstrFile 缓冲区的大小
LPTSTR lpstrFileTitle; // 接收选择的文件名的缓冲区
DWORD nMaxFileTitle; // lpstrFileTitle 缓冲区的大小
LPCTSTR lpstrInitialDir; // 初始目录
LPCTSTR lpstrTitle; // 对话框标题
DWORD Flags; // 选项标志
WORD nFileOffset; // 文件名在 lpstrFile 中的偏移量
WORD nFileExtension; // 文件扩展名在 lpstrFile 中的偏移量
LPCTSTR lpstrDefExt; // 默认文件扩展名
LPARAM lCustData; // 自定义数据
LPOFNHOOKPROC lpfnHook; // 钩子函数
LPCTSTR lpTemplateName; // 自定义模板的资源名称
#if (_WIN32_WINNT >= 0x0500)
void * pvReserved; // 保留,不要使用
DWORD dwReserved; // 保留,不要使用
DWORD FlagsEx; // 扩展选项标志
#endif // (_WIN32_WINNT >= 0x0500)
} OPENFILENAME, *LPOPENFILENAME;
OPENFILENAME 结构体的注释详细说明了每个成员的作用和用法,您可以根据需要设置相应的成员来配置打开文件对话框的行为和选项。
●使用 GetOpenFileName 函数的一般步骤如下:
1.初始化 OPENFILENAME 结构体,设置各种参数和选项。
2.调用 GetOpenFileName 函数,并传递指向初始化的 OPENFILENAME 结构体的指针。
3.检查 GetOpenFileName 的返回值,判断用户是否选择了文件并点击了打开按钮。
4.如果返回值为非零,通过 OPENFILENAME 结构体的 lpstrFile 成员获取所选文件的路径。
●以下是一个简单的示例代码,演示如何使用 GetOpenFileName 函数:
#include <windows.h>
#include <commdlg.h>
int main()
{
OPENFILENAME ofn = { 0 };
TCHAR szFile[MAX_PATH] = { 0 };
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL; // 父窗口句柄,可设置为 NULL
ofn.lpstrFilter = _T("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"); // 文件过滤器
ofn.lpstrFile = szFile; // 存储用户选择的文件路径
ofn.nMaxFile = MAX_PATH; // szFile 缓冲区大小
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST; // 选项
if (GetOpenFileName(&ofn))
{
// 用户选择了文件并点击了打开按钮
MessageBox(NULL, ofn.lpstrFile, _T("Selected File"), MB_OK);
}
return 0;
}
以上示例代码使用 GetOpenFileName 函数打开一个包含文件过滤器的打开文件对话框。用户可以选择一个文本文件 (.txt) 或任何文件 (所有文件选项)。如果用户选择了文件并点击了打开按钮,则通过 MessageBox 函数显示所选文件的路径。
【注意】示例代码中使用了 _T 宏,它根据编译选项确定是使用 ANSI 字符集还是 Unicode 字符集。在 Unicode 编译模式下,TCHAR 被定义为 wchar_t,在 ANSI 编译模式下,TCHAR 被定义为 char。因此,字符串参数和结构体成员使用 _T 宏进行宽字符/窄字符兼容处理。
■存储文件公用对话框
要使用公共文件对话框来存储文件,您可以使用 GetSaveFileName 函数和 OPENFILENAME 结构体。以下是一个简单的示例代码,展示如何配置和使用公共文件对话框来存储文件:
#include <windows.h>
#include <commdlg.h>
int main()
{
// 初始化 OPENFILENAME 结构体
OPENFILENAME ofn = {0};
TCHAR szFile[MAX_PATH] = {0};
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL; // 父窗口的句柄,这里设置为 NULL
ofn.lpstrFilter = TEXT("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"); // 文件过滤器
ofn.lpstrFile = szFile; // 用于接收文件路径的缓冲区
ofn.nMaxFile = MAX_PATH; // 缓冲区大小
ofn.lpstrDefExt = TEXT("txt"); // 默认文件扩展名
ofn.Flags = OFN_OVERWRITEPROMPT; // 显示覆盖提示对话框
// 显示存储文件对话框
if (GetSaveFileName(&ofn))
{
// 用户点击了保存按钮,可以使用 ofn.lpstrFile 获取选择的文件路径
MessageBox(NULL, ofn.lpstrFile, TEXT("Selected File"), MB_OK);
}
return 0;
}
以上代码首先初始化了 OPENFILENAME 结构体,并设置了相关的成员,如文件过滤器、文件路径缓冲区、默认文件扩展名等。然后,使用 GetSaveFileName 函数来显示存储文件对话框。如果用户点击了保存按钮并选择了文件路径,您可以通过 ofn.lpstrFile 获取选择的文件路径,并进行相应的处理。
■查找和替换公用对话框
要使用公共文件对话框来进行查找和替换操作,您可以使用 FindText 和 ReplaceText 函数以及相应的结构体。以下是一个简单的示例代码,演示如何配置和使用公共文件对话框来进行查找和替换:
#include <windows.h>
#include <commdlg.h>
int main()
{
// 初始化 FINDREPLACE 结构体
FINDREPLACE fr = {0};
TCHAR szFind[MAX_PATH] = {0};
TCHAR szReplace[MAX_PATH] = {0};
fr.lStructSize = sizeof(FINDREPLACE);
fr.hwndOwner = NULL; // 父窗口的句柄,这里设置为 NULL
fr.lpstrFindWhat = szFind; // 用于接收查找文本的缓冲区
fr.wFindWhatLen = MAX_PATH; // 缓冲区大小
fr.lpstrReplaceWith = szReplace; // 用于接收替换文本的缓冲区
fr.wReplaceWithLen = MAX_PATH; // 缓冲区大小
fr.Flags = FR_DOWN; // 查找方向为向下
// 显示查找和替换对话框
if (FindText(&fr))
{
// 用户点击了查找或替换按钮,可以使用 fr.lpstrFindWhat
//和 fr.lpstrReplaceWith 获取查找和替换文本
MessageBox(NULL, fr.lpstrFindWhat, TEXT("Find Text"), MB_OK);
MessageBox(NULL, fr.lpstrReplaceWith, TEXT("Replace Text"), MB_OK);
}
return 0;
}
以上代码首先初始化了 FINDREPLACE 结构体,并设置了相关的成员,如查找文本缓冲区、替换文本缓冲区等。然后,使用 FindText 函数来显示查找和替换对话框。如果用户点击了查找或替换按钮,您可以通过 fr.lpstrFindWhat 和 fr.lpstrReplaceWith 获取查找和替换文本,并进行相应的处理。
●以下是 FINDREPLACE 结构体的定义,每个成员都有相应的注释说明其作用和用法:
typedef struct tagFINDREPLACE {
DWORD lStructSize; // 结构体的大小,必须设置为 sizeof(FINDREPLACE)
HWND hwndOwner; // 父窗口的句柄
HINSTANCE hInstance; // 应用程序实例句柄
DWORD Flags; // 选项标志
LPCTSTR lpstrFindWhat; // 查找文本的缓冲区
LPCTSTR lpstrReplaceWith; // 替换文本的缓冲区
WORD wFindWhatLen; // 查找文本的缓冲区大小
WORD wReplaceWithLen; // 替换文本的缓冲区大小
LPARAM lCustData; // 自定义数据
LPFRHOOKPROC lpfnHook; // 钩子函数
LPCTSTR lpTemplateName; // 自定义模板的资源名称
} FINDREPLACE, *LPFINDREPLACE;
■选择字体公用对话框
要使用公共字体对话框来选择字体,您可以使用 ChooseFont 函数和 CHOOSEFONT 结构体。以下是一个简单的示例代码,展示如何配置和使用公共字体对话框来选择字体:
#include <windows.h>
#include <commdlg.h>
int main()
{
// 初始化 CHOOSEFONT 结构体
CHOOSEFONT cf = {0};
LOGFONT lf = {0};
cf.lStructSize = sizeof(CHOOSEFONT);
cf.hwndOwner = NULL; // 父窗口的句柄,这里设置为 NULL
cf.lpLogFont = &lf; // 用于接收选择的字体信息的 LOGFONT 结构体指针
cf.Flags = CF_SCREENFONTS | CF_EFFECTS; // 显示屏幕字体和效果选项
// 显示选择字体对话框
if (ChooseFont(&cf))
{
// 用户点击了确定按钮,可以使用 lf 字段获取选择的字体信息
MessageBox(NULL, lf.lfFaceName, TEXT("Selected Font"), MB_OK);
}
return 0;
}
以下是 CHOOSEFONT 结构体的定义,其中包含了选择字体对话框的相关配置信息:
typedef struct tagCHOOSEFONT {
DWORD lStructSize; // 结构体的大小,必须设置为 sizeof(CHOOSEFONT)
HWND hwndOwner; // 父窗口的句柄
HDC hDC; // 设备上下文句柄
LPLOGFONT lpLogFont; // 用于接收选择的字体信息的 LOGFONT 结构体指针
INT iPointSize; // 字体大小(以 1/10 点为单位)
DWORD Flags; // 选项标志
COLORREF rgbColors; // 初始文本颜色和背景颜色
LPARAM lCustData // 自定义数据
LPCFHOOKPROC lpfnHook; // 钩子函数
LPCTSTR lpTemplateName; // 自定义模板的资源名称
HINSTANCE hInstance; // 应用程序实例句柄
LPTSTR lpszStyle; // 预定义样式列表
WORD nFontType; // 字体类型标志
WORD ___MISSING_ALIGNMENT__; // 未使用
INT nSizeMin; // 最小可选择的字体大小
INT nSizeMax; // 最大可选择的字体大小
} CHOOSEFONT, *LPCHOOSEFONT;
■选择颜色公用对话框
要使用公共颜色对话框来选择颜色,您可以使用 ChooseColor 函数和 CHOOSECOLOR 结构体。以下是一个简单的示例代码,展示如何配置和使用公共颜色对话框来选择颜色:
#include <windows.h>
#include <commdlg.h>
int main()
{
// 初始化 CHOOSECOLOR 结构体
CHOOSECOLOR cc = {0};
COLORREF acrCustColors[16] = {0};
cc.lStructSize = sizeof(CHOOSECOLOR);
cc.hwndOwner = NULL; // 父窗口的句柄,这里设置为 NULL
cc.lpCustColors = acrCustColors; // 自定义颜色数组
cc.Flags = CC_FULLOPEN | CC_RGBINIT; // 全部颜色打开和初始颜色设置
// 显示选择颜色对话框
if (ChooseColor(&cc))
{
// 用户点击了确定按钮,可以使用 cc.rgbResult 获取选择的颜色
COLORREF selectedColor = cc.rgbResult;
MessageBox(NULL, TEXT("Selected Color"), TEXT("Selected Color"), MB_OK);
}
return 0;
}
以上代码首先初始化了 CHOOSECOLOR 结构体,并设置了相关的成员,如父窗口句柄、自定义颜色数组、显示选项等。然后,使用 ChooseColor 函数来显示选择颜色对话框。如果用户点击了确定按钮并选择了颜色,您可以通过 cc.rgbResult 获取选择的颜色,并进行相应的处理。
以下是 CHOOSECOLOR 结构体的定义,其中包含了选择颜色对话框的相关配置信息:
typedef struct tagCHOOSECOLOR {
DWORD lStructSize; // 结构体的大小,必须设置为 sizeof(CHOOSECOLOR)
HWND hwndOwner; // 父窗口的句柄
HWND hInstance; // 应用程序实例句柄
COLORREF rgbResult; // 选择的颜色
COLORREF* lpCustColors; // 自定义颜色数组
DWORD Flags; // 选项标志
LPARAM lCustData; // 自定义数据
LPCCHOOKPROC lpfnHook; // 钩子函数
LPCTSTR lpTemplateName; // 自定义模板的资源名称
} CHOOSECOLOR, *LPCHOOSECOLOR;
10.3.2 第68练:完善的POPPAD
■POPPAD.C
/*------------------------------------------------------------------------
068 WIN32 API 每日一练
第68个例子POPPAD.C:公用对话框-文本编辑器
POPPAD.C //主程序
POPFILE.C //文件菜单处理
POPFIND.C //SEARCH菜单处理
POPFONT.C //FONT菜单处理
POPPRINTO.C //打印处理(第十三章讲述)
(c) www.bcdaren.com 编程达人
-----------------------------------------------------------------------*/
#include <windows.h>
#include <commdlg.h> //公用对话框库
#include "resource.h"
#define EDITID 1 //顶级菜单ID:FILE 0 ,EDIT 1,SEARCH 2,FORMAT 3,HELP 4
#define UNTITLED TEXT ("(untitled)")
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
// Functions in POPFILE.C
void PopFileInitialize (HWND) ; //初始化File对话框
BOOL PopFileOpenDlg (HWND, PTSTR, PTSTR) ; //创建“打开”文件对话框
BOOL PopFileSaveDlg (HWND, PTSTR, PTSTR) ; //创建“保存”文件对话框
BOOL PopFileRead (HWND, PTSTR) ; //读文件
BOOL PopFileWrite (HWND, PTSTR) ; //写文件
// Functions in POPFIND.C
HWND PopFindFindDlg (HWND) ; //初始化Find对话框
HWND PopFindReplaceDlg (HWND) ; //初始化FindReplace对话框
BOOL PopFindFindText (HWND, int *, LPFINDREPLACE) ; //查找字符串
BOOL PopFindReplaceText (HWND, int *, LPFINDREPLACE) ; //替换字符串
BOOL PopFindNextText (HWND, int *) ; //查找下一处
BOOL PopFindValidFind (void) ; //无效查找
// Functions in POPFONT.C
void PopFontInitialize (HWND) ; //初始化对话框字体
BOOL PopFontChooseFont (HWND) ; //选择字体
void PopFontSetFont (HWND) ; //设置字体
void PopFontDeinitialize (void) ; //删除字体
// Functions in POPPRNT.C
BOOL PopPrntPrintFile (HINSTANCE, HWND, HWND, PTSTR) ; //打印文件
// Global 变量
static HWND hDlgModeless ; //通用对话框句柄
static TCHAR szAppName[] = TEXT ("PopPad") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MSG msg;
HWND hwnd;
HACCEL hAccel;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, szAppName);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = szAppName;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, NULL,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, szCmdLine);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
hAccel = LoadAccelerators(hInstance, szAppName);
while (GetMessage(&msg, NULL, 0, 0))
{//对话框为空或不是对话框消息时
if (hDlgModeless == NULL || !IsDialogMessage(hDlgModeless, &msg))
{//如果加速键消息未被翻译过TranslateAccelerator函数返回值为0
if (!TranslateAccelerator(hwnd, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return msg.wParam;
}
//设置标题
void DoCaption (HWND hwnd, TCHAR * szTitleName)
{
TCHAR szCaption[64 + MAX_PATH];
wsprintf(szCaption, TEXT("%s - %s"), szAppName,
szTitleName[0] ? szTitleName : UNTITLED);
SetWindowText(hwnd, szCaption);
}
//向用户显示消息框提示信息
void OkMessage (HWND hwnd, TCHAR * szMessage, TCHAR * szTitleName)
{
TCHAR szBuffer[64 + MAX_PATH];
wsprintf(szBuffer, szMessage, szTitleName[0] ? szTitleName : UNTITLED);
MessageBox(hwnd, szBuffer, szAppName, MB_OK | MB_ICONEXCLAMATION);
}
// 是否保存文件
short AskAboutSave (HWND hwnd, TCHAR * szTitleName)
{
TCHAR szBuffer[64 + MAX_PATH];
int iReturn;
wsprintf(szBuffer, TEXT("Save current changes in %s?"),
szTitleName[0] ? szTitleName : UNTITLED);
iReturn = MessageBox(hwnd, szBuffer, szAppName,
MB_YESNOCANCEL | MB_ICONQUESTION);
if (iReturn == IDYES)
if (!SendMessage(hwnd, WM_COMMAND, IDM_FILE_SAVE, 0))//IDM_FILE_SAVE返回0为失败,1成功
iReturn = IDCANCEL;//YES但保存失败
return iReturn;
}
//主窗口过程
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM
lParam)
{
static BOOL bNeedSave = FALSE ;
static HINSTANCE hInst ;
static HWND hwndEdit ;
static int iOffset ;
//完全路径文件名缓冲区和文件名缓冲区
static TCHAR szFileName[MAX_PATH], szTitleName[MAX_PATH] ;
static UINT messageFindReplace ;
int iSelBeg, iSelEnd, iEnable ;
LPFINDREPLACE pfr ;
switch (message)
{
case WM_CREATE:
hInst = ((LPCREATESTRUCT) lParam) -> hInstance ;
// 创建编辑控件子窗口
hwndEdit = CreateWindow (TEXT ("edit"), NULL,
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
WS_BORDER | ES_LEFT | ES_MULTILINE |
//ES_NOHIDESEL反转所选文本
ES_NOHIDESEL | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
0, 0, 0, 0,
hwnd, (HMENU) EDITID, hInst, NULL) ;
//设置文本编辑控件的最大字符数,0L为long类型常量0
SendMessage (hwndEdit, EM_LIMITTEXT, 32000, 0L) ;
// 初始化公用对话框
PopFileInitialize (hwnd) ;//初始化文件公用对话框
PopFontInitialize (hwndEdit) ; //创建字体
/*定义一个新的窗口消息,仅当多个应用程序必须处理同一条消息时才使用RegisterWindowMessage。“查找或替换”对话框会将 FINDMSGSTRING 注册的消息发送到其所有者窗口的窗口过程。*/
messageFindReplace = RegisterWindowMessage (FINDMSGSTRING) ;
DoCaption (hwnd, szTitleName) ; //窗口标题栏显示文件名
return 0 ;
case WM_SETFOCUS:
SetFocus(hwndEdit);//设置焦点
return 0;
case WM_SIZE:
MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam),TRUE);
return 0;
//当下拉菜单或子菜单即将变为活动状态时发送
case WM_INITMENUPOPUP:
switch (lParam)
{
case 1: // Edit 菜单
// 如果有撤销操作,启用“Undo”菜单
//启用,禁用或显示指定的菜单项
EnableMenuItem ((HMENU) wParam, IDM_EDIT_UNDO,
SendMessage (hwndEdit, EM_CANUNDO, 0, 0L) ?
MF_ENABLED : MF_GRAYED) ;
// 如果文本在剪贴板中,则启用粘贴
EnableMenuItem ((HMENU) wParam, IDM_EDIT_PASTE,
IsClipboardFormatAvailable (CF_TEXT) ? //剪贴板是否有内容
MF_ENABLED : MF_GRAYED) ;
//如果有选中文本字符串,启用剪切、复制和删除选中的文本
//获取选定文本的位置信息
SendMessage (hwndEdit, EM_GETSEL, (WPARAM) &iSelBeg,
(LPARAM) &iSelEnd) ;
//如果开始位置等于结束位置,禁用菜单
iEnable = iSelBeg != iSelEnd ? MF_ENABLED : MF_GRAYED ;
EnableMenuItem ((HMENU) wParam, IDM_EDIT_CUT,iEnable) ;
EnableMenuItem ((HMENU) wParam, IDM_EDIT_COPY,iEnable) ;
EnableMenuItem ((HMENU) wParam, IDM_EDIT_CLEAR,iEnable) ;
break ;
case 2: // Search 菜单
//如果非模态对话框==NULL时,激活菜单
iEnable = hDlgModeless == NULL ? MF_ENABLED : MF_GRAYED ;
EnableMenuItem ((HMENU) wParam, IDM_SEARCH_FIND,iEnable) ;
EnableMenuItem ((HMENU) wParam, IDM_SEARCH_NEXT, iEnable) ;
EnableMenuItem ((HMENU) wParam, IDM_SEARCH_REPLACE, iEnable) ;
break ;
}
return 0 ;
case WM_COMMAND:
// 处理"EDIT"控件消息
if (lParam && LOWORD (wParam) == EDITID)
{
switch (HIWORD (wParam)) //控件通知码
{ //当编辑控件即将重绘时发送。
//在控件格式化文本之后但在显示文本之前发送此通知代码。
case EN_UPDATE :
bNeedSave = TRUE ;
return 0 ;
case EN_ERRSPACE : //空间不足
case EN_MAXTEXT :
MessageBox(hwnd, TEXT("Edit control out of space."),
szAppName, MB_OK | MB_ICONSTOP);
return 0;
}
break ;
}
switch (LOWORD (wParam)) //加速键ID或菜单ID,这里两个ID相等
{
//处理"FILE"菜单消息
case IDM_FILE_NEW:
//保存旧文件,如果保存时失败,则什么都不做,直接返回。
if (bNeedSave && IDCANCEL == AskAboutSave
(hwnd, szTitleName))
return 0;
//清除编辑框内容
SetWindowText(hwndEdit, TEXT("\0"));//设置标题栏缓冲区为空
szFileName[0] = '\0';//设置文件名缓冲区为空
szTitleName[0] = '\0';//设置标题缓冲区为空
DoCaption(hwnd, szTitleName);//显示标题栏
bNeedSave = FALSE;
return 0;
case IDM_FILE_OPEN:
//保存旧文件,如果保存时失败,则什么都不做,直接返回。
if (bNeedSave && IDCANCEL == AskAboutSave(hwnd, szTitleName))
return 0;
if (PopFileOpenDlg(hwnd, szFileName, szTitleName))
{
if (!PopFileRead(hwndEdit, szFileName))
{
OkMessage(hwnd, TEXT("Could not read file %s!"),
szTitleName);
szFileName[0] = '\0';
szTitleName[0] = '\0';
}
}
DoCaption(hwnd, szTitleName);
bNeedSave = FALSE;
return 0;
case IDM_FILE_SAVE:
if (szFileName[0])
{
if (PopFileWrite(hwndEdit, szFileName))
{
bNeedSave = FALSE;
return 1;
}
else
{
OkMessage(hwnd, TEXT("Could not write file %s"),
szTitleName);
return 0;
}
}
//继续往下执行
case IDM_FILE_SAVE_AS:
if (PopFileSaveDlg(hwnd, szFileName, szTitleName))
{
DoCaption(hwnd, szTitleName);
if (PopFileWrite(hwndEdit, szFileName))
{
bNeedSave = FALSE;
return 1;
}
else
{
OkMessage(hwnd, TEXT("Could not write file %s"),
szTitleName);
return 0;
}
}
return 0;
case IDM_FILE_PRINT:
if (!PopPrntPrintFile(hInst, hwnd, hwndEdit,
szTitleName))
OkMessage(hwnd, TEXT("Could not print file %s"),
szTitleName);
return 0;
case IDM_APP_EXIT:
SendMessage(hwnd, WM_CLOSE, 0, 0);
return 0;
// Edit 菜单消息
case IDM_EDIT_UNDO:
SendMessage (hwndEdit, WM_UNDO, 0, 0) ;
return 0 ;
case IDM_EDIT_CUT:
SendMessage (hwndEdit, WM_CUT, 0, 0) ;
return 0 ;
case IDM_EDIT_COPY:
SendMessage(hwndEdit, WM_COPY, 0, 0);
return 0;
case IDM_EDIT_PASTE:
SendMessage (hwndEdit, WM_PASTE, 0, 0) ;
return 0 ;
case IDM_EDIT_CLEAR:
SendMessage(hwndEdit, WM_CLEAR, 0, 0);
return 0;
case IDM_EDIT_SELECT_ALL:
SendMessage(hwndEdit, EM_SETSEL, 0, -1);
return 0;
// Search 菜单消息
case IDM_SEARCH_FIND:
//查找将从iOffset位置开始(首获取选中文本后面的位置iOffset)
SendMessage(hwndEdit, EM_GETSEL, 0, (LPARAM)&iOffset);
hDlgModeless = PopFindFindDlg(hwnd);
return 0;
case IDM_SEARCH_NEXT:
SendMessage(hwndEdit, EM_GETSEL, 0, (LPARAM)&iOffset);
if (PopFindValidFind())
PopFindNextText(hwndEdit, &iOffset);
else
hDlgModeless = PopFindFindDlg(hwnd);
return 0;
case IDM_SEARCH_REPLACE:
SendMessage (hwndEdit, EM_GETSEL, 0, (LPARAM) &iOffset) ;
hDlgModeless = PopFindReplaceDlg (hwnd) ;
return 0 ;
case IDM_FORMAT_FONT:
if (PopFontChooseFont(hwnd))
PopFontSetFont(hwndEdit);
return 0 ;
// Help菜单消息
case IDM_HELP:
OkMessage(hwnd, TEXT("Help not yet implemented!"),
TEXT("\0"));
return 0;
case IDM_APP_ABOUT:
DialogBox(hInst, TEXT("AboutBox"), hwnd, AboutDlgProc);
return 0 ;
}
break ;
case WM_CLOSE:
if (!bNeedSave || IDCANCEL != AskAboutSave (hwnd, szTitleName))
DestroyWindow (hwnd) ;
return 0 ;
//结束会话或者系统关机发送的消息
case WM_QUERYENDSESSION :
if (!bNeedSave || IDCANCEL != AskAboutSave(hwnd, szTitleName))
return 1;//结束
return 0;//不结束
case WM_DESTROY:
PopFontDeinitialize();
PostQuitMessage(0);
return 0;
default:
//处理“查找”、“替换”发送的特殊消息
if (message == messageFindReplace)
{
pfr = (LPFINDREPLACE)lParam;
//用户点击了“取消”按钮
if (pfr->Flags & FR_DIALOGTERM)
hDlgModeless = NULL;
//用户点击了“查找下一个”按钮
if (pfr->Flags & FR_FINDNEXT)
if (!PopFindFindText(hwndEdit, &iOffset, pfr))
OkMessage(hwnd, TEXT("Text not found!"), TEXT("\0"));
//用户点击了“替换”或“替换全部”
if (pfr->Flags & FR_REPLACE || pfr->Flags & FR_REPLACEALL)
if (!PopFindReplaceText(hwndEdit, &iOffset, pfr))
OkMessage(hwnd, TEXT("Text not found!"), TEXT("\0"));
if (pfr->Flags & FR_REPLACEALL)
while (PopFindReplaceText(hwndEdit, &iOffset, pfr));
return 0;
}
break ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
//About模态对话框窗口过程
BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message,WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
EndDialog(hDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
■POPFILE.C
/*--------------------------------------------------------------------------
POPFILE.C -- Popup Editor File Functions
------------------------------------------------------------------------*/
#include <windows.h>
#include <commdlg.h>
static OPENFILENAME ofn ;
//初始化对话框
void PopFileInitialize (HWND hwnd)
{
static TCHAR szFilter[] = TEXT ("Text Files (*.TXT)\0*.txt\0") \
TEXT("ASCII Files (*.ASC)\0*.asc\0") \
TEXT("All Files (*.*)\0*.*\0\0");
ofn.lStructSize = sizeof (OPENFILENAME) ; //结构体的大小
ofn.hwndOwner = hwnd ; //所属窗口,可以为NULL
ofn.hInstance = NULL ; //对话框模板或模块句柄,ofn.Flags字段相关
ofn.lpstrFilter = szFilter ; //文件筛选字符串
ofn.lpstrCustomFilter = NULL ; //缓冲区,保留用户选择的过滤样式
ofn.nMaxCustFilter = 0 ; //以TCHAR为单位的缓冲大小
ofn.nFilterIndex = 0 ; //当前选择的过滤器的索引
ofn.lpstrFile = NULL ; // 在打开和关闭函数中设置,全路径文件名缓冲区
ofn.nMaxFile = MAX_PATH ;
// 在打开和关闭函数中设置,接收不含路径的文件名的缓冲区
ofn.lpstrFileTitle = NULL ;
ofn.nMaxFileTitle = MAX_PATH ;
ofn.lpstrInitialDir = NULL ; //在这个字符串中指定初始目录
ofn.lpstrTitle = NULL ; //对话框标题,默认为“打开”或“保存”
// 在打开和关闭函数中设置,,对话框不同行为的标志,只读,多选,覆盖等
ofn.Flags = 0;
ofn.nFileOffset = 0 ; //返回文件名字符串中,文件名的起始位置
ofn.nFileExtension = 0 ; //扩展名在字符串中的起始位置
ofn.lpstrDefExt = TEXT ("txt") ; //指定默认的扩展名
//系统传递给由lpfnHook成员标识的hook过程的应用程序定义的数据
ofn.lCustData = 0L ;
ofn.lpfnHook = NULL ; //指向一个钩子程序
ofn.lpTemplateName = NULL ; //是对话框模板资源
}
//创建一个“打开”文件对话框
BOOL PopFileOpenDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
{
ofn.hwndOwner = hwnd;
ofn.lpstrFile = pstrFileName;//全路径文件名
ofn.lpstrFileTitle = pstrTitleName;//文件名(含扩展名)
//隐藏只读复选框,如果文件不存在,则创建文件
ofn.Flags = OFN_HIDEREADONLY | OFN_CREATEPROMPT;
//创建一个“打开”文件对话框,该对话框允许用户指定驱动器,
//目录以及要打开的文件或文件集的名称。
return GetOpenFileName(&ofn);
}
//创建一个“保存”文件对话框
BOOL PopFileSaveDlg (HWND hwnd, PTSTR pstrFileName, PTSTR pstrTitleName)
{
ofn.hwndOwner = hwnd;
ofn.lpstrFile = pstrFileName;
ofn.lpstrFileTitle = pstrTitleName;
//如果所选文件已存在,则使 “另存为”对话框生成一个消息框。
//用户必须确认是否覆盖文件。
ofn.Flags = OFN_OVERWRITEPROMPT;
//创建一个“保存”对话框,该对话框允许用户指定要保存的文件的驱动器,目录和名称。
return GetSaveFileName(&ofn);
}
//读取文件
BOOL PopFileRead (HWND hwndEdit, PTSTR pstrFileName)
{
BYTE bySwap ;
DWORD dwBytesRead ;
HANDLE hFile ;
int i, iFileLength, iUniTest ;
PBYTE pBuffer, pText, pConv ;
// 打开文件
if (INVALID_HANDLE_VALUE ==
(hFile = CreateFile(pstrFileName, GENERIC_READ,
FILE_SHARE_READ,
NULL, OPEN_EXISTING, 0, NULL)))
return FALSE;
// 获取文件大小,以字节为单位,并为读取分配内存。
iFileLength = GetFileSize (hFile, NULL) ;
pBuffer = malloc (iFileLength + 2) ; //多出两个字节存放两个'\0'
//读文件到缓冲区,并在文件末尾放\0结束符
ReadFile (hFile, pBuffer, iFileLength, &dwBytesRead, NULL) ;
CloseHandle (hFile) ;
pBuffer[iFileLength] = '\0' ;
pBuffer[iFileLength + 1] = '\0' ;
//测试文本是否是Unicode编码,前两个字节为0xFEFF或0xFFFE
//IS_TEXT_UNICODE_SIGNATURE——0xFEFF(小端:高高低低)
//IS_TEXT_UNICODE_REVERSE_SIGNATURE——0xFFFE(大端)
iUniTest = IS_TEXT_UNICODE_SIGNATURE | IS_TEXT_UNICODE_REVERSE_SIGNATURE ;
if (IsTextUnicode (pBuffer, iFileLength, &iUniTest))
{
pText = pBuffer + 2;//跳过前两个字节,指向正文部分
iFileLength -= 2;
//如果大端存储,调换字节顺序
if (iUniTest & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
{
for (i = 0; i < iFileLength / 2; i++)
{
bySwap = ((BYTE *)pText)[2 * i];
((BYTE *)pText)[2 * i] = ((BYTE *)pText)[2 * i + 1];
((BYTE *)pText)[2 * i + 1] = bySwap;
}
}
//为可能的字符串转换分配内存
pConv = malloc (iFileLength + 2) ;
//Edit控件使用Unicode,则显示之前将Unicode文本转化为多字节文本
#ifndef UNICODE
WideCharToMultiByte (CP_ACP, 0, (PWSTR) pText, -1, pConv,
iFileLength + 2, NULL, NULL) ; //共iFileLength+2字节,含2个\0
//Edit控件是非Unicode,则直接拷贝文本
#else
lstrcpy ((PTSTR) pConv, (PTSTR) pText) ;
#endif
}
else //非Unicode文件
{
pText = pBuffer ;
//ASCII转Unicode,需2倍的空间。额外加两个\0。
pConv = malloc (2 * iFileLength + 2) ;
// 如果编辑控件是Unicode,则转换ASCII文本。
#ifdef UNICODE
MultiByteToWideChar (CP_ACP, 0, pText, -1, (PTSTR) pConv,
iFileLength + 1) ;
// 如果不是,则直接拷贝
#else
lstrcpy ((PTSTR) pConv, (PTSTR) pText) ;
#endif
}
SetWindowText (hwndEdit, (PTSTR) pConv) ; //将内容写入到编辑框
free (pBuffer) ;
free (pConv) ;
return TRUE ;
}
//写文件
BOOL PopFileWrite (HWND hwndEdit, PTSTR pstrFileName)
{
DWORD dwBytesWritten ;
HANDLE hFile ;
int iLength ;
PTSTR pstrBuffer ;
//小端模式时,前两个字节被写入FF FE。大端时被写入FE FF
WORD wByteOrderMark = 0xFEFF ;
//打开文件,必要时可创建文件
if (INVALID_HANDLE_VALUE ==
(hFile = CreateFile(pstrFileName, GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS, 0, NULL)))
return FALSE;
//获取编辑框中的字符个数,并分配内存
iLength = GetWindowTextLength (hwndEdit) ;
pstrBuffer = (PTSTR) malloc ((iLength + 1) * sizeof (TCHAR)) ;
if (!pstrBuffer)
{
CloseHandle(hFile);
return FALSE;
}
// 如果编辑框使用Unicode编码,则写入Unicode字节序
#ifdef UNICODE
WriteFile (hFile, &wByteOrderMark, 2, &dwBytesWritten, NULL) ;
#endif
//获取编辑框中的文本,并输出到文件
GetWindowText (hwndEdit, pstrBuffer, iLength + 1) ;
WriteFile (hFile, pstrBuffer, iLength * sizeof (TCHAR),
&dwBytesWritten, NULL) ;
if ((iLength * sizeof (TCHAR)) != (int) dwBytesWritten)
{
CloseHandle(hFile);
free(pstrBuffer);
return FALSE;
}
CloseHandle (hFile) ;
free (pstrBuffer) ;
return TRUE ;
}
■POPFIND.C
/*--------------------------------------------------------------------------
POPFIND.C -- Popup Editor Search and Replace Functions
------------------------------------------------------------------------*/
#include <windows.h>
#include <commdlg.h>
#include <tchar.h> // for _tcsstr (strstr for Unicode & non-Unicode)
#define MAX_STRING_LEN 256
static TCHAR szFindText [MAX_STRING_LEN] ;
static TCHAR szReplText [MAX_STRING_LEN] ;
//初始化Find对话框
HWND PopFindFindDlg (HWND hwnd)
{
static FINDREPLACE fr ; // 非模态对话框必须是静态的!!
fr.lStructSize = sizeof (FINDREPLACE) ; //结构的长度(以字节为单位)。
fr.hwndOwner = hwnd ; //拥有对话框的窗口的句柄。
fr.hInstance = NULL ;
//隐藏搜索方向单选按钮,隐藏“区分大小写”复选框,
fr.Flags = FR_HIDEUPDOWN | FR_HIDEMATCHCASE |
FR_HIDEWHOLEWORD ; //隐藏“仅匹配整个单词”复选框
fr.lpstrFindWhat = szFindText ; //键入的搜索字符串缓冲区的长度
fr.lpstrReplaceWith = NULL; //键入的替换字符串缓冲区的长度,
//如果FINDMSGSTRING消息指定FR_REPLACE或FR_REPLACEALL标志,
//则lpstrReplaceWith包含替换字符串,该FINDTEXT函数忽略这个成员。
//lpstrFindWhat成员指向的缓冲区的长度(以字节为单位)。
fr.wFindWhatLen = MAX_STRING_LEN ;
//lpstrReplaceWith成员指向的缓冲区的长度(以字节为单位)。
fr.wReplaceWithLen = 0 ;
fr.lCustData = 0 ; //Hook过程的应用程序定义的数据
//指向FRHookProc Hook过程的指针,该过程可以处理用于对话框的消息。
fr.lpfnHook = NULL ;
fr.lpTemplateName = NULL;//hInstance成员标识的模块中对话框模板资源的名称。
return FindText (&fr) ; //创建查找对话框并返回其句柄
}
//初始化FindReplace对话框
HWND PopFindReplaceDlg (HWND hwnd)
{
static FINDREPLACE fr ; // 非模态对话框必须是静态的!!
fr.lStructSize = sizeof (FINDREPLACE) ;
fr.hwndOwner = hwnd ;
fr.hInstance = NULL ;
fr.Flags = FR_HIDEUPDOWN | FR_HIDEMATCHCASE |
FR_HIDEWHOLEWORD ;
fr.lpstrFindWhat = szFindText ;
fr.lpstrReplaceWith = szReplText ;
fr.wFindWhatLen = MAX_STRING_LEN ;
fr.wReplaceWithLen = MAX_STRING_LEN ;
fr.lCustData = 0 ;
fr.lpfnHook = NULL ;
fr.lpTemplateName = NULL ;
return ReplaceText (&fr) ;
}
//查找字符串
BOOL PopFindFindText (HWND hwndEdit, int * piSearchOffset, LPFINDREPLACE pfr)
{
int iLength, iPos ;
PTSTR pstrDoc, pstrPos ; //文件指针和当前位置指针
//读取编辑框内容
iLength = GetWindowTextLength (hwndEdit) ;
if (NULL == (pstrDoc = (PTSTR) malloc ((iLength + 1) * sizeof (TCHAR))))
return FALSE ;
GetWindowText (hwndEdit, pstrDoc, iLength + 1) ;
// 在文档中搜索查找字符串
pstrPos = _tcsstr (pstrDoc + * piSearchOffset, pfr->lpstrFindWhat) ;
free (pstrDoc) ;
//如果找不到,返回FALSE
if (pstrPos == NULL)
return FALSE ;
//找到字符串,将偏移设置到新的位置
iPos = pstrPos - pstrDoc ;
//偏移设到找到的字符串的后面。
* piSearchOffset = iPos + lstrlen (pfr->lpstrFindWhat) ;
//选中找到的文本
SendMessage (hwndEdit, EM_SETSEL, iPos, * piSearchOffset) ;
//可视窗口滚动到插入符号的位置,以便可见找到的文本。
SendMessage (hwndEdit, EM_SCROLLCARET, 0, 0) ;
return TRUE ;
}
//查找下一处
BOOL PopFindNextText (HWND hwndEdit, int * piSearchOffset)
{
FINDREPLACE fr;
fr.lpstrFindWhat = szFindText;
return PopFindFindText(hwndEdit, piSearchOffset, &fr);
}
//替换文本字符串
BOOL PopFindReplaceText (HWND hwndEdit, int * piSearchOffset, LPFINDREPLACE pfr)
{
//查找文本
if (!PopFindFindText (hwndEdit, piSearchOffset, pfr))
return FALSE ;
// 替换
SendMessage ( hwndEdit, EM_REPLACESEL, 0, (LPARAM) pfr->
lpstrReplaceWith) ;
return TRUE ;
}
//无效查找
BOOL PopFindValidFind (void)
{
return * szFindText != '\0' ; //没输入查找文本时,是无效的查找。
}
■POPFONT.C
/*----------------------------------------------------
POPFONT.C -- Popup Editor Font Functions
------------------------------------------------------*/
#include <windows.h>
#include <commdlg.h>
static LOGFONT logfont ; //字体的属性结构变量
static HFONT hFont ;
//选择字体
BOOL PopFontChooseFont (HWND hwnd)
{
CHOOSEFONT cf ; //包含ChooseFont函数用来初始化“字体”对话框的信息。用户
//关闭对话框后,系统将在此结构中返回有关用户选择的信息。
cf.lStructSize = sizeof (CHOOSEFONT) ; //结构的长度,以字节为单位。
cf.hwndOwner = hwnd ; //拥有对话框的窗口的句柄。
cf.hDC = NULL ; //忽略
cf.lpLogFont = &logfont ; //指向LOGFONT结构的指针 。
cf.iPointSize = 0 ; //选择的字体的大小,单位是1/10磅
//用logfont初始化对话框,屏幕字体、效果复选框
cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS |
CF_EFFECTS ;
cf.rgbColors = 0 ; //文本颜色
cf.lCustData = 0 ;
cf.lpfnHook = NULL ;
cf.lpTemplateName = NULL ;
cf.hInstance = NULL ;
cf.lpszStyle = NULL ; //字体样式
cf.nFontType = 0 ; // 所选的字体
cf.nSizeMin = 0 ; //用户可以选择的最小点数
cf.nSizeMax = 0 ; //用户可以选择的最大点数
return ChooseFont (&cf) ;
}
//初始化对话框字体
void PopFontInitialize (HWND hwndEdit)
{
GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), //获取系统字体
(PTSTR)&logfont);
hFont = CreateFontIndirect(&logfont); //创建字体
SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hFont,0);//初始化对话框为系统字体
}
//设置字体
void PopFontSetFont (HWND hwndEdit)
{
HFONT hFontNew;
RECT rect;
hFontNew = CreateFontIndirect(&logfont);
SendMessage(hwndEdit, WM_SETFONT, (WPARAM)hFontNew, 0);//改变对话框字体
DeleteObject(hFont);
hFont = hFontNew;
GetClientRect(hwndEdit, &rect);
InvalidateRect(hwndEdit, &rect, TRUE);
}
//删除字体
void PopFontDeinitialize (void)
{
DeleteObject (hFont) ;
}
■POPPRINTO.C
/*------------------------------------------------------------------------
POPPRNTO.C -- Popup Editor Printing Functions (dummy version)
--------------------------------------------------------------------------*/
#include <windows.h>
BOOL PopPrntPrintFile ( HINSTANCE hInst, HWND hwnd, HWND hwndEdit,
PTSTR pstrTitleName)
{
return FALSE ;
}
■资源脚本文件068_POPPAD3.rc
包含一个快捷键资源、对话框资源、ICON图标资源和菜单资源。
/
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
PopPad ICON "favicon.ico"
/
//
// Menu
//
PopPad MENU
BEGIN
POPUP "&FILE"
BEGIN
MENUITEM "&NEW\tCtrl+N", IDM_FILE_NEW
MENUITEM "&OPEN...\tCtrl+O", IDM_FILE_OPEN
MENUITEM "&SAVE\tCtrl+S", IDM_FILE_SAVE
MENUITEM "SAVE &AS...", IDM_FILE_SAVE_AS
MENUITEM SEPARATOR
MENUITEM "&PRINT\tCtrl+P", IDM_FILE_PRINT
MENUITEM SEPARATOR
MENUITEM "E&XIT", IDM_APP_EXIT
END
POPUP "&EDIT"
BEGIN
MENUITEM "&UNDO\tCtrl+Z", IDM_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM "CU&T\tCtrl+X", IDM_EDIT_CUT
MENUITEM "©\tCtrl+C", IDM_EDIT_COPY
MENUITEM "&PASTE\tCtrl+V", IDM_EDIT_PASTE
MENUITEM "DE&LETE\tDEL", IDM_EDIT_CLEAR
MENUITEM SEPARATOR
MENUITEM "&SELECT ALL", IDM_EDIT_SELECT_ALL
END
POPUP "&SEARCH"
BEGIN
MENUITEM "&FIND...\tCtrl+F", IDM_SEARCH_FIND
MENUITEM "FIND &NEXT\tF3", IDM_SEARCH_NEXT
MENUITEM "&REPLEACE...\tCtrl+R", IDM_SEARCH_REPLACE
END
POPUP "F&ORMAT"
BEGIN
MENUITEM "&FONT...", IDM_FORMAT_FONT
END
POPUP "&HELP"
BEGIN
MENUITEM "&HELP", IDM_HELP
MENUITEM "&ABOUT POPPAD...", IDM_APP_ABOUT
END
END
/
//
// Dialog
//
ABOUTBOX DIALOGEX 32, 32, 309, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "确定",IDOK,122,156,50,14
ICON "PopPad",IDC_STATIC,15,12,20,20
CTEXT "POPPAD",IDC_STATIC,113,28,58,8
CTEXT "PopPad Editor for Windows",IDC_STATIC,93,68,119,8
CTEXT "(C) Charles Petzold,1998",IDC_STATIC,91,88,115,8
END
PRINTDLGBOX DIALOGEX 0, 0, 309, 176
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "POPPAD"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "取消",IDCANCEL,127,155,50,14
CTEXT "Sending",IDC_STATIC,113,24,72,8
LTEXT "",IDC_STATIC,30,48,246,72
CTEXT "to print spooler.",IDC_STATIC,116,138,72,8
END
/
//
// Accelerator
//
IDR_ACCELERATOR1 ACCELERATORS
BEGIN
VK_BACK, IDM_EDIT_UNDO, VIRTKEY, ALT, NOINVERT
VK_DELETE, IDM_EDIT_CLEAR, VIRTKEY, NOINVERT
VK_F1, IDM_HELP, VIRTKEY, NOINVERT
VK_F3, IDM_SEARCH_NEXT, VIRTKEY, NOINVERT
VK_INSERT, IDM_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
"C", IDM_EDIT_COPY, VIRTKEY, NOINVERT
"F", IDM_SEARCH_FIND, VIRTKEY, NOINVERT
"N", IDM_FILE_NEW, VIRTKEY, NOINVERT
"P", IDM_FILE_PRINT, VIRTKEY, NOINVERT
"R", IDM_SEARCH_REPLEACE, VIRTKEY, NOINVERT
"S", IDM_FILE_SAVE, VIRTKEY, NOINVERT
"V", IDM_EDIT_PASTE, VIRTKEY, NOINVERT
"X", IDM_EDIT_CUT, VIRTKEY, NOINVERT
"Z", IDM_EDIT_UNDO, VIRTKEY, NOINVERT
END
■运行结果:
图10-13 公用对话框——文本编辑器
总结
实例POPPAD程序加入菜单时,并没有实现几种标准菜单项。现在我们有了充分的准备可以实现POPPAD中打开文件、读取文件、存储文件的程序逻辑。在此过程中,我们还将添加选择字体和査找并替换文本的程序逻辑。
为避免重复第十三章的源代码,在POPPAD3.C的菜单定义中加上了打印选项以及其他一些相关代码。
POPPAD.C包含程序的所有基本源代码。
POPFILE.C中包含了激活打开文件和存储文件对话框的代码,以及文件I/O例程。
POPFIND.C包含了査找和替换文本的程序逻辑。
POPFONT.C包含了选择字体的程序逻辑。
POPPRNTO.C没有实质功能,它将在第十三章被POPPRNT.C所替换,并完成最终的POPPAD程序。
【注意】实例POPPAD程序中关于公用对话框初始化的部分可以被简化,直接将相应的公用对话框结构体初始化为零,然后再初始化几个必要的字段就可以了(参见上一节)。
●Unicode文件的判断——IsTextUnicode(lpBuffer,cb, lpi)
1.lpBuffer参数:要测试的字符串,其缓冲区地址。
2.cb个参数:lpBuffer指向的字节数(注意是不是字符数)
3.lpi:是个in/out类型的,传入时指定哪些测试项目,传出时为符合哪个测试项目。
4.返回值:TRUE或FALSE
●字符串的转化——这里的多字节是广义的,即可指ANSI,也可指UTF_8等。
1.WideCharToMultiByte——将Unicode字符串转为多字节字符串
字段 | 功能 |
CodePage | CodePage参数用于标识要为转换新的字符串的相关代码页,如CP_ACP实现了Unicode与ANSI的转换;CP_UTF8 实现了Unicode与UTF-8的转换 |
dwFlags | 进行额外的控制,会影响使用了读音符号(比如重音)的字符 |
lpWideCharStr | 转换为宽字节字符串的缓冲区 |
cchWideChar | lpWideCharStr指向的缓冲区的字符个数。如果-1,字符串将被设定为以NULL为结束符的字符串,并且自动计算长度(含\0)。 |
lpMultiByteStr | 接收被转换字符串的缓冲区 |
cchMultiByte | lpMultiByteStr指向的缓冲区最大值(用字节来计量) |
lpDefaultChar | 遇到一个不能转换的宽字符,函数便会使用该参数指向的字符。 |
pfUsedDefaultChar | 只要遇到任何一个不能被转换的字符,就会被函数设为TRUE。 |
2.MultiByteToWideChar——将多字节字符串转为Unicode字符串
字段 | 功能 |
CodePage | 用来标记与一个多字节字符串相关的代码页 |
dwFlags | 进行额外的控制,会影响使用了读音符号(比如重音)的字符 |
lpWideCharStr | 转换为宽字节字符串的缓冲区 |
cchWideChar | lpWideCharStr指向的缓冲区的字符个数,如果-1,字符串将被设定为以NULL为结束符的字符串,并且自动计算长度(含\0)。 |
lpMultiByteStr | 接收被转换字符串的缓冲区 |
cchMultiByte | lpMultiByteStr指向的缓冲区最大值(用字节来计量) |
lpDefaultChar | 遇到一个不能转换的宽字符,函数便会使用该参数指向的字符。 |
pfUsedDefaultChar | 只要遇到任何一个不能被转换的字符,就会被函数设为TRUE。 |
●查找和替换公用对话框
1.对话框是非模态的,所以消息循环应该调用IsDialogMessage。
2.FINDREPLACE结构不能声明为窗口过程的局部变量,必须是静态变量或全局变量。因为当调用FindText或ReplaceText调出对话框后,PopFindFindDlg(PopFindReplaceDlg)这些函数会立即返回。但该结构会作为消息的lParam参数被发送到父窗口的消息过程。为防止该结构被释放,要声明为静态变量。
3.“查找”或“替换”对话框与父窗口会进行一种特殊的消息进行通信。
所以程序首先须通过FINDMSGSTR这个名字,向系统申请获得该特殊消息的ID号,即msgID =RegisterWindowMessage (FINDMSGSTRING)后就可以利用msgID进行通信了。