c++ - 从用户定义的类/指向成员函数的指针子类化编辑控件

标签 c++ c winapi subclass editbox

我想我已经陷入了与我之前的许多人相同的陷阱,我试图在 win32 API 编程中强加一种很好的 OO 方法。没有 MFC,没有 AFX,我什至没有使用 VC++,我使用的是 C::B 和 gcc。

我认为我正在尝试做的事情是不可能的,但是既然 MFC 存在(虽然我没有使用它),那么一定有某种方法。

我创建了一个包含多个窗口控件的类。它实现 WM_CREATE 和 WM_COMMAND 的处理程序,并跟踪我的小组控件(ID 代码和 HWND)周围的所有关联数据。

它非常适用于按钮、静态控件,甚至是简单的 GDI 方法,但当我尝试子类化编辑控件时,一切都崩溃了。

真的,我只是想捕获“enter”键,但是任何曾经走过这条路的人都会证明,当编辑控件获得焦点时,父窗口不会收到 WM_KEYDOWN 或 WM_COMMAND,我们只能实现我们自己的过程。 super 蹩脚。

好的,如果 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 作为返回值,但在我完成此操作之前,没有必要为此担心。

提前感谢阅读!

最佳答案

myEditProc 需要是静态函数。 完成后,您可以直接传递函数的地址,而无需通过中间变量:

static LRESULT myEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
...
SetWindowLongPtr(m_hWndEditBox, GWLP_WNDPROC, (LPARAM)myEditProc);

要从静态函数访问您的类数据,您可以将其保存在编辑控件的用户数据字段中,例如:

// before sub-classing the control
SetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA, (LPARAM)this);

// in the sub-class procedure
MyControlGroup* pThis = (MyControlGroup*)GetWindowLongPtr(m_hWndEditBox, GWLP_USERDATA);

但正如@K-ballo 所建议的那样,SetWindowSubclass 绝对是执行此操作的方法,除非您希望与 pre-XP 兼容。它自动为您处理子类化过程,让您关联一个自动传递给子类化过程的用户数据指针(例如 this),并在最后安全地处理删除子类.

关于c++ - 从用户定义的类/指向成员函数的指针子类化编辑控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14187674/

相关文章:

c++ - 如何将 makefile 从生成可执行文件更改为生成共享库

c++ - 我如何最好地消除有关未使用变量的警告?

c - C中的1U和1有什么区别吗?

c++ - 无法将参数从 'SIZE_T *' 转换为 'size_t *' - 如何转换?

c++ - 访问任何进程的内存

C++ 猜谜游戏 : unable to get midpoint properly

c - 适用于 Linux 的 Windows Beep()

C中按值调用函数

c++ - 在 win32 窗口中使用 OpenGL 渲染图像

c - 使用Rundll32.exe执行DLL导出的函数