这个程序是用于查询Windows函数所返回的错误号的对应描述信息。在这里我主要记录一下该程序是如何实现某些功能以及自己当前还不明白的一些函数调用。
1. 对于GUI程序,其入口为:
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int)。本程序的_tWinMain函数的内容为:
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int) {
// 下面FindWindow的功能应该是标题为Error Show的对话框。第一个参数什么意思呢?
HWND hwnd = FindWindow(TEXT("#32770"), TEXT("Error Show"));
if (IsWindow(hwnd)) { // IsWindow用于判断hwnd是否是窗口?
// An instance is already running, activate it and send it the new #
// 顾名思义,SendMessage用于给hwnd发送消息。消息类型为ESM_POKECODEANDLOOKUP.
// 后面连个应该是针对该消息的参数吧。
SendMessage(hwnd, ESM_POKECODEANDLOOKUP, _ttoi(pszCmdLine), 0);
} else {
// 下面这个函数应该是用于显示Error Show对话框的。IDD_ERRORSHOW是该对话框的ID。
// 那么MAKEINTRESOURCE的所有又是什么呢?Dlg_Proc是用户定义的一个函数的名字。
// 该函数的功能好像是对消息进行处理的。后面介绍。这里有出现了_ttoi。它是什么作用?
DialogBoxParam(hinstExe, MAKEINTRESOURCE(IDD_ERRORSHOW),
NULL, Dlg_Proc, _ttoi(pszCmdLine));
}
return(0);
}
2. 消息处理函数,一般是用户自己编写的。下面是本程序中的消息处理函数Dlg_Proc的源码。
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
// 下面这两个宏(应该是吧?)的作用应该是用Dlg_OnInitDialg函数和Dlg_OnCommand函数
// 来处理WM_INITDIALOG和WM_COMMAND消息吧。
// 这个宏是由作者自己写的。位于文件"CmnHdr.h"中。
chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
case ESM_POKECODEANDLOOKUP:
// 下面这个函数应该是为文本框IDC_ERRORCODE指定值吧。值的类型为INT。由函数名可推出。
SetDlgItemInt(hwnd, IDC_ERRORCODE, (UINT) wParam, FALSE);
// 这个宏的功能是模拟用户按了IDOK按钮。
FORWARD_WM_COMMAND(hwnd, IDOK, GetDlgItem(hwnd, IDOK), BN_CLICKED,
PostMessage);
// 将进程hwnd置于其他窗口之前。
SetForegroundWindow(hwnd);
break;
}
return(FALSE);
}
3. 根据上面两个函数,我们可以总结出如何编程使Windows处理消息。
a. 用于自己编写一个消息处理函数,其原型可参见Dlg_Proc。该函数所要做的就是switch(uMsg),然后根据uMsg的类型调用不同的处理函数。
b. 利用DialogBoxParam函数将该消息处理函数对应到某个对话框。
c. 利用SendMessage函数模拟消息的传送。这里用户可以自定义所发送的消息的类型。比如程序中的ESM_POKECODEANDLOOKUP就是作者自定义的。利用
#define ESM_POKECODEANDLOOKUP (WM_USER + 100)
4. 如果我们需要对Dialog进行初始化的话,我们可以处理WM_INITDIALOG消息,并编写一个处理函数。本程序中该消息的处理函数为Dlg_OnInitDialog。
BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam) {
chSETDLGICONS(hwnd, IDI_ERRORSHOW);
// Don't accept error codes more than 5 digits long
Edit_LimitText(GetDlgItem(hwnd, IDC_ERRORCODE), 5);
// Look up the command-line passed error number
SendMessage(hwnd, ESM_POKECODEANDLOOKUP, lParam, 0);
return(TRUE);
}
5. 在Windows中,我们可以处理消息,我们也可以处理Command。对Command的处理是通过消息WM_COMMAND的处理函数来进行的。当然这个处理函数也应该由我们自己编写。在本程序中,该处理函数是Dlg_OnCommand。通过对此函数的分析,我们可以学习对Command处理的大致模式了。
void Dlg_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify) {
// 这里的id记录的就是我们应该处理的Command的编号了。但我们按下了一个按钮之后,id应该记录的
// 就是该按钮的ID吧。
switch (id) {
case IDCANCEL:
EndDialog(hwnd, id);
break;
case IDC_ALWAYSONTOP:
SetWindowPos(hwnd, IsDlgButtonChecked(hwnd, IDC_ALWAYSONTOP)
? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
break;
case IDC_ERRORCODE:
EnableWindow(GetDlgItem(hwnd, IDOK), Edit_GetTextLength(hwndCtl) > 0);
break;
case IDOK:
// Get the error code
DWORD dwError = GetDlgItemInt(hwnd, IDC_ERRORCODE, NULL, FALSE);
HLOCAL hlocal = NULL; // Buffer that gets the error message string
// Get the error code's textual description
BOOL fOk = FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, dwError, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(PTSTR) &hlocal, 0, NULL);
if (!fOk) {
// Is it a network-related error?
HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL,
DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL) {
FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM,
hDll, dwError, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(PTSTR) &hlocal, 0, NULL);
FreeLibrary(hDll);
}
}
if (hlocal != NULL) {
SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));
LocalFree(hlocal);
} else {
SetDlgItemText(hwnd, IDC_ERRORTEXT, TEXT("Error number not found."));
}
break;
}
}
6. 对Dialog的处理总结:
a. 利用DialogBoxParam(hinstExe, MAKEINTRESOURCE(IDD_ERRORSHOW), NULL, Dlg_Proc, _ttoi(pszCmdLine));
为对话框IDD_ERRORSHOW设置消息处理函数Dlg_Proc
b. 在消息处理函数Dlg_Proc中利用 chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand); 为对话框hwnd设置WM_INITDIALOG和WM_COMMAND的消息处理函数。
c. 利用SendMessage(hwnd, ESM_POKECODEANDLOOKUP, _ttoi(pszCmdLine), 0);给hwnd发送消息ESM_POKECODEANDLOOKUP以便在程序中促使消息处理函数的调用。
d. 利用FORWARD_WM_COMMAND(hwnd, IDOK, GetDlgItem(hwnd, IDOK), BN_CLICKED,
PostMessage);促发hwnd的WM_COMMAND消息,从而调用hwnd的Command处理函数对ID_OK命令进行处理。
e. 利用GetDlgItem(hwnd, IDOK)获取对话框hwnd中ID为IDOK的控件的HANDLE
f. 利用EndDialog(hwnd, id);
关闭对话框。
7. 对Button的处理总结:
8. 对Checkbox的处理总结:
a. 利用IsDlgButtonChecked(hwnd, IDC_ALWAYSONTOP)检查CheckBox是否被选中。
9. 对文本框的处理总结:
a. 利用SetDlgItemInt(hwnd, IDC_ERRORCODE, (UINT) wParam, FALSE)和GetDlgItemInt(hwnd, IDC_ERRORCODE, NULL, FALSE)设置或读取文本框中的值。
b. 利用Edit_LimitText(GetDlgItem(hwnd, IDC_ERRORCODE), 5);设置文本框控件中可输入的文本的长度。
c. 利用Edit_GetTextLength(hwndCtl)可以获取文本框控件中文本的长度。
d. 利用SetDlgItemText(hwnd, IDC_ERRORTEXT, (PCTSTR) LocalLock(hlocal));为文本框控件设置值。
10. 对DLL文件的处理。其中LoadLibraryEx加载dll,而FreeLiarary释放该dll.
HMODULE hDll = LoadLibraryEx(TEXT("netmsg.dll"), NULL,
DONT_RESOLVE_DLL_REFERENCES);
if (hDll != NULL) {
FormatMessage(
FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM,
hDll, dwError, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
(PTSTR) &hlocal, 0, NULL);
FreeLibrary(hDll);
}
10. 整个程序也为我们创建一个Dialog应用程序提供了模板。
阅读(1699) | 评论(2) | 转发(0) |