我想我和之前的许多人一样落入了同样的陷阱,我试图在 win32 API 编程上强加一个很好的 OO 方法。没有 MFC,没有 AFX,我什至没有使用 VC++,我使用 C::B 和 gcc。
我认为我正在尝试做的事情是不可能的,但是由于 MFC 存在(尽管我没有使用它),所以必须有某种方法。
我创建了一个包含多个窗口控件的类。它实现了 WM_CREATE 和 WM_COMMAND 的处理程序,并跟踪我的一小组控件(ID 代码和 HWND)周围的所有相关数据。
它适用于按钮、静态控件,甚至是轻量级 GDI 方法,但是当我尝试对编辑控件进行子类化时,这一切都崩溃了。
真的,我只是想捕获“回车”键,但正如任何曾经走过这条路的人都会证明的那样,当编辑控件获得焦点时,父窗口不会收到 WM_KEYDOWN 或 WM_COMMAND,我们只能自己实现过程。超级跛脚。
好的,如果 editProc 是全局或静态的,那么子类化编辑控件就可以了。我知道这是因为 SetWindowLongPtr 需要一个函数地址,而这个概念对于成员函数来说是模糊的。
所以我的类的对象在父 WndProc 中被声明为“静态”。但是该函数不是“静态的”,因为这样我就无法访问非静态数据成员(完全违背了本练习的目的)。我希望因为对象本身是静态的,所以我应该能够正确定义其成员函数之一的地址。
以前尝试过的读者要么已经放弃并使用 MFC 或其他东西,要么可能找到了一个聪明的解决方法。
我将让这个示例代码完成剩下的讨论:(简化 - 不会这样编译)
/**** myprogram.c ****/
#include "MyControlGroup.h"
int winMain(){ // etc... }
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// object is static becuse it only needs to be initialized once
static MyControlGroup myControl;
if (msg == WM_CREATE)
myControl.onWMCreate(hWnd);
else if (msg == WM_COMMAND)
myControl.onWMCommand( wParam, lParam );
else if (msg == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProcW(l_hWnd, l_msg, l_wParam, l_lParam);
}
我的班级的头文件:
/**** MyControlGroup.h ****/
class MyControlGroup
{
private:
HWND m_hWndParent;
HWND m_hWndEditBox;
int m_editBoxID;
public:
MyControlGroup();
void onWMCreate(HWND);
void onWMCommand(WPARAM, LPARAM);
// want to find a way to pass the address of this function to SetWindowLongPtr
LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
};
...和实施:
/**** MyControlGroup.cpp ****/
static int staticID = 1;
MyControlGroup::MyControlGroup()
{
m_editBoxID = staticID++;
}
void MyControlGroup::onWMCreate(HWND hWnd)
{
// My control group has buttons, static controls, and other stuff which are created here with CreateWindowW. It also has an edit control:
m_hWndEditBox = CreateWindowW(L"EDIT", L"initial text", WS_CHILD | WS_VISIBLE | WS_BORDER, 10, 10, 150, 20, hWnd, (HMENU)m_editBoxID, NULL, NULL);
/*
To subclass the edit control, I need a pointer to my customized proc. That means I
need a pointer-to-member-function, but SetWindowLongPtr needs a pointer to global or
static function (__stdcall or CALLBACK, but not __thiscall).
*/
// I'd like to do something like this, adapted from a great write-up at
// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible
LERSULT (MyControlGroup::*myEditProcPtr)(HWND, UINT, WPARAM, LPARAM);
myEditProcPtr = &MyControlGroup::myEditProc;
// Up to now it compiles ok, but then when I try to pass it to SetWindowLongPtr, I get
// an "invalid cast" error. Any ideas?
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProcPtr);
}
void MyControlGroup::onWMCommand(WPARAM wParam, LPARAM lParam){ /* process parent window messages. Editboxes don't generate WM_COMMAND or WM_KEYDOWN in the parent :''( */}
LRESULT MyControlGroup::myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// process messages like IDOK, WM_KEYDOWN and so on in the edit control
}
即使我完成了这项工作,我仍然需要想办法将父 WndProc 的地址传递给 myEditProc 以获得返回值,但在我克服这一点之前,没有必要担心这一点。
提前感谢您的阅读!