《Windows API每日一练》10.3 公用对话框
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进行通信了。
相关文章:
《Windows API每日一练》10.3 公用对话框
Windows最初发行时的主要目标之一就是提倡一种标准化的用户界面。对于公用菜单 项来说,这一目标实现得很快。几乎所有的软件制造商都采用了Alt-File-Open组合来打开 文件。但是,真正用来打开文件的对话框却经常很不一样。 从Windows 3.1开始,…...
C++中的引用
在C中,我们要学习一个新的概念,叫做引用。引用不是对象,它只是给变量取一个别名。就好比,我们每个人总会右一下外号,或者是小名。当朋友或者家长不管是直接叫你的名字,还是叫你的小名,你都会答应…...
【自学安全防御】三、企业双机热备和带宽管理的综合实验
实验拓扑: 实验任务: 12,对现有网络进行改造升级,将当个防火墙组网改成双机热备的组网形式,做负载分担模式,游客区和DMZ区走FW3,生产区和办公区的流量走FW1 13,办公区上网用户限制流…...
无极与有极电容的区别
无极性电容与有极性电容:差异与应用探索 在电子元件的广阔世界里,电容器无疑是不可或缺的一部分。它们以储存电荷和调节电路中的电压与电流而闻名。然而,电容器并非一概而论,其中最为显著的区别之一就是无极性电容与有极性电容。…...
入坑树莓派(2)——树莓派4B与手机蓝牙通信
入坑树莓派(2)——树莓派4B与手机蓝牙通信 1、引言 在入坑树莓派(1)中已经搞掂了可视化问题。现在继续开展下一步,尝试与手机通信,一开始是想弄wifi连接的,但发现基于wifi的APP比较难弄,为了降低开发的难度,又因为树莓派板子自带蓝牙模块,所以直接选用蓝牙连接手机…...
RocketMQ单结点安装/Dashboard安装
目录 1.安装NameServer 2.安装Broker 3.使用自带工具测试数据发送 4.使用DashBoard进行查看 5.关闭相关设备 前置条件:两台虚拟机CentOS Linux release 7.5.1804(ps:当然也可以都部署在一台机器上) RocketMq属于天生集群。需要同时启动nameServer和Broker进行…...
【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第二篇 Linux系统编程篇-第三十四章 进程基础
i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…...
使用LVS+NGinx+Netty实现数据接入
数据接入 链接参考文档 LVSKeepalived项目 车辆数据上收,TBox通过TCP协议连接到TSP平台 建立连接后进行数据上传。也可借由该连接实现远程控制等操作。 通过搭建 LV—NGinx—Netty实现高并发数据接入 LVS:四层负载均衡(位于内核层&#x…...
云手机结合自主ADB命令接口 提升海外营销效率
现在,跨境电商直播已经成为在线零售的重要渠道,在大环境下,确保直播应用的稳定性和用户体验至关重要。 云手机支持自主ADB命令接口,为电商直播营销提供了技术支持,使得应用开发、测试、优化和运维更加高效。 什么是A…...
【计算机视觉前沿研究 热点 顶会】CVPR 2024中与域适应、分布外目标检测相关的论文
测试时间线性分布外检测 分布外( OOD)检测旨在通过在输入样本显著偏离训练分布(分布中)时触发警报来解决神经网络的过度置信度预测,这表明输出可能不可靠。当前的 OOD 检测方法探索各种线索来识别 OOD 数据࿰…...
首次由国产8K摄像机服务巴黎奥运会8K公用信号
法国巴黎时间16日上午,中央广播电视总台“中国红”8K转播车穿越大半个地球,抵达法兰西体育场,顺利完成与奥林匹克转播公司(OBS)的交接。 (1)“中国红”8K转播车 作为适合户外露天项目的“移动制作域”,“…...
idea怎么配置gradle多个版本
1.背景 gradle版本很多,而且很多时候版本是不兼容的,我们希望拉取下来的代码就包含已经配置好的版本,而不是去配置本机的gradle版本..... 意思就是要实现项目A可以用6.X版本 项目B可以使用7.X版本 项目C可以用9.X版本..... 2.配置方式 步骤一:项目根路径下保留一个文件夹…...
SpringCloudAlibaba-Seata2.0.0与Nacos2.2.1
一、下载 ## 下载seata wget https://github.com/apache/incubator-seata/releases/download/v2.0.0/seata-server-2.0.0.tar.gz## 解压 tar zxvf seata-server-2.0.0.tar.gz二、执行sql文件 ## 取出sql文件执行 cd /seata/script/server/db/mysql ## 找个mysql数据库执行三、…...
【编程语言】C++和C的异同点
文章目录 相同点不同点cin和scanf()结构体struct指针:NULL、nullptr、void* 有一段时间没有发博客了,从笔记里摘录一些发两篇。 相同点 C有很多从C继承过来的东西,因此C书(《C Primer》、《C Primer Plus》)中有一些基础的东西讲的并没有C书…...
【日常记录】【插件】excel.js导出的时候给单元格设置下拉选择、数据校验等
文章目录 1. 代码基本结构2. 导出的excel 某单元格的值设置为下拉选择3. 如何把下拉选择项设置为动态4. 单元格设置校验、提示5. 在WPS上的设置 1. 代码基本结构 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><…...
分布式 I/O 系统Modbus TCP 耦合器BL200
BL200 耦合器是一个数据采集和控制系统,基于强大的 32 位微处理器设计,采用 Linux 操作系统,可以快速接入现场 PLC、SCADA 以及 ERP 系统, 内置逻辑控制、边缘计算应用,支持标准 Modbus TCP 服务器通讯,以太…...
人工智能导论-机器学习
机器学习概述 概述 本章主要介绍的机器学习的概念、发展历程、发展趋势、相关应用,着重拓展机监督学习和无监督学习的相关知识。 重点:机器学习的定义和应用; 难点:机器学习算法及分类。 机器学习 - 重要性 MachineLeaning出…...
计算机网络——网络层(路由选择协议、路由器工作原理、IP多播、虚拟专用网和网络地址转换)
目录 路由选择协议 因特网的路由选择协议特点 路由信息协议RIP RIP衡量目的网络距离 RIP选择路由器的方式 RIP具有以下三个重要特点 RIP的基本工作流程 RIP的距离向量算法 编辑 编辑 RIP存在的问题——“坏消息传播得慢” RIP的封装 开放最短路径优先协议OSPF…...
对接企业微信API自建应用配置企业可信IP
前言 为了实现系统调用团队会议功能,组织发起企业微信会议,于是需要和企业微信做API对接。对接过程很难受,文档不清晰、没有SDK、没有技术支持甚至文档报文和实际接口报文都不匹配,只能说企业微信的API是从业以来见过的最难用的AP…...
Windows右键新建Markdown文件类型配置 | Typora | VSCode
🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 今天毛毛张分享的是如何在右键的新建菜单中添加新建MarkdownFile文件,这是毛毛张分享的关于Typora软件的相关知识的第三期 文章目录 1.前言🏝…...
PyTorch构建一个肺部CT图像分类模型来分辨肺癌
当你有5万个标注的肺部CT DICOM图像数据,并且希望使用PyTorch构建一个肺部CT图像分类模型来分辨肺癌,以下是详细的步骤和示例代码: 数据准备 首先,确保你的数据集被正确分为训练集、验证集和测试集,并且每个图像都有相…...
MySQL简介及数据库
mysql简介 mysql是一个轻量级关系型数据库管理系统,具有体积小,速度快,开源的优点 sql是一种结构化查询语言(Structured Query Language),专门用来管理和处理关系型数据库的标准化编程语言,mysql实现了SQL标准…...
服务器基础1
服务器基础复习01 1.环境部署 系统:华为欧拉系统 网络简单配置nmtui 因为华为欧拉系统密码需要复杂度 所以我们可以进入后更改密码 echo 123 | passwd --stdin root也可以 echo "root:123" | chpasswd2.关闭防火墙,禁用SElinux 首先先关…...
<数据集>光伏板缺陷检测数据集<目标检测>
数据集格式:VOCYOLO格式 图片数量:2400张 标注数量(xml文件个数):2400 标注数量(txt文件个数):2400 标注类别数:4 标注类别名称:[Crack,Grid,Spot] 序号类别名称图片数框数1Crack8688922Grid8248843S…...
leetcode 513. 找树左下角的值
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示: 二叉树的节点个数的范围是 [1,104]-231 < Node.val &…...
C++并发编程实战学习笔记
一、C的并发: 多进程并发: 将应用程序分为多个独立的进程,它们在同一时刻运行,就像同 时进行网页浏览和文字处理一样。独立的进程可以通过进程间常规的通信渠道传递讯息(信号、套接字、文件、管道等等)。不过,这种进程…...
【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【25】【分布式事务】
持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【25】【分布式事务】 本地事务事务的基本性质事务的隔离级别(下面四个越往下,隔离级 别越高,并发能力越差)事务的传播行为(是否…...
HC05主从一体蓝牙模块的裸机使用——单片机<-->蓝牙模块
HC-05是一种常用的蓝牙模块,具有低功耗、低成本、易于使用的特点。它可以实现与其他蓝牙设备(如手机、电脑等)进行无线通信。HC-05蓝牙模块具有串口通信接口,可以通过串口与主控制器(如Arduino、Raspberry Pi等&#x…...
“点点通“餐饮点餐小程序-计算机毕业设计源码11264
"点点通"餐饮点餐小程序 XXX专业XX级XX班:XXX 指导教师:XXX 摘要 随着中国经济的飞速增长,消费者的智能化水平不断提高,许多智能手机和相关的软件正在得到更多的关注和支持。其中,微信的餐饮点餐小程序更…...
C#知识|账号管理系统-账号信息管理界面[1]:账号分类选择框、Panel面板设置
哈喽,你好啊,我是雷工! 前一节实现了多条件查询后端代码的编写, 接下来继续学习账号信息管理界面的功能编写,本节主要记录账号分类选择框和Panel的设置, 以下为学习笔记。 01 功能说明 本节实现以下功能: ①:账号分类选择框只能选择,无法自由输入; ②:账号分类框默认…...
企业简介范文大全/谷歌网站推广优化
怎样在VS2008自带的SQl2005里使用sql server身份验证登陆 (转载) 相信很多用过vs2005或最近用vs2008的朋友可能有这样的困惑:VS自带的sql server 登陆时默认的是用windows身份验证登陆,而不是用sql server身份验证。因为在这里的sql时集成在v…...
重庆建筑特种作业查询网/专业网站优化外包
Exchange2013不同于2010的最大之处就在于使用Web管理控制台!在 Exchange 2013 中,原本在 Exchange 2007 和 Exchange 2010 中使用的管理控制台EMC已经不存在了,新的管理控制台是基于Web模式的,它可以在无需安装任何管理工具的电脑中访问和管理…...
网站数据抓取怎么做/有哪些平台可以发布推广信息
解决报错,包版本低了,特别是用的低版本springboot自动引入的 解决:自己去引入 <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.9</version><…...
search everything wordpress/长尾关键词挖掘
将企业软件中进行数据交换的业务对象,例如客户、订单或产品等常规模型进行标准化,让它们包含所有属性与关联信息,这种做法看上去似乎是一种吸引人的目标,但在Stefan Tilkov看来,这种方式将产生标准数据模型(…...
社区门户网站建设招标公告/优化游戏卡顿的软件
实验要求:1.R6为ISP只能配置IP地址 2.R1/4/5为全连MGRE结构,R1/2/3为星型结构,R1为中心站点 3.所有私有网段可以互相通讯,私有网段使用OSPF协议 首先我们先进行IP地址的规划 和进行IP地址的配置 对R1: interface GigabitEthernet…...
网站开发建设/厦门seo排名优化方式
OpenMP --- 线程同步 1. 引言 在OpenMP中,线程同步机制包括互斥锁同步机制和事件同步机制。 2. 互斥锁同步 互斥锁同步的概念类似于Windows中的临界区(CriticalSection)以及Windows和Linux中的Mutex以及VxWorks中的SemTake和SemGiveÿ…...