如何使用SetWindowLong来解决类成员函数?

时间:2013-01-17 20:51:19

标签: c++ oop winapi callback

  

可能重复:
  To pass a pointer to a member function

当我离开课程时,WNDPROC DefEditProc;EditKeyProc一切正常。但是现在当我粘贴代码时,它无法编译错误error: invalid use of member function (did you forget the '()' ?)。所以我的问题是如何将这些代码压缩到类中,这样我就不会污染全局命名空间了?

#include <windows.h>
#include <richedit.h>

class richEdit {
  HWND richeditWindow;
  WNDPROC DefEditProc;
  public:

  LRESULT EditKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    return CallWindowProc(DefEditProc, hwnd, uMsg, wParam, lParam);
  }
  richEdit() {
    HMODULE richedit_library = LoadLibrary("Msftedit.dll");
    if (NULL == richedit_library) abort();

    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(0);
    richeditWindow = CreateWindowExW (
      WS_EX_TOPMOST,
      MSFTEDIT_CLASS,
      L"window text",
      WS_OVERLAPPED | WS_SYSMENU | ES_MULTILINE | WS_VISIBLE,
      0, 0, 500, 500,
      NULL, NULL, hInstance, NULL
    );
    DefEditProc = (WNDPROC)SetWindowLong(richeditWindow, GWL_WNDPROC, (long)EditKeyProc);
  }
  ~richEdit() {
    MSG msg;
    while( GetMessageW( &msg, richeditWindow, 0, 0 ) ) {
      TranslateMessage( &msg );
      DispatchMessageW( &msg );
    }
  }
};

int main() {
  richEdit re;
}

3 个答案:

答案 0 :(得分:4)

您应该使用自由函数而不是成员函数,因为成员函数具有隐式this参数。您必须将EditKeyProc声明为static CALLBACK,并在需要时找到另一种传递this指针的方法。

static LRESULT CALLBACK EditKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    :::
}

此外,您可以使用SetWindowSubclass来处理正确的子类,并为您保留额外的指针参数。

答案 1 :(得分:3)

试试这个:

#include <windows.h>
#include <richedit.h>

class richEdit
{
private:
    HWND richeditWindow;
    WNDPROC DefEditProc;

    static LRESULT CALLBACK EditKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        richEdit *pThis = (richEdit*) GetWindowLongPtr(hwnd, GWL_USERDATA);
        return CallWindowProc(pThis->DefEditProc, hwnd, uMsg, wParam, lParam);
    }

public:
    richEdit()
        : richeditWindow(NULL), DefEditProc(NULL)
    {
        HMODULE richedit_library = LoadLibrary("Msftedit.dll");
        if (NULL == richedit_library) abort();

        HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(0);
        richeditWindow = CreateWindowExW (
          WS_EX_TOPMOST,
          MSFTEDIT_CLASS,
          L"window text",
          WS_OVERLAPPED | WS_SYSMENU | ES_MULTILINE | WS_VISIBLE,
          0, 0, 500, 500,
          NULL, NULL, hInstance, NULL
        );
        if (NULL == richeditWindow) abort();

        SetWindowLongPtr(richeditWindow, GWL_USERDATA, (LONG_PTR)this);
        DefEditProc = (WNDPROC) SetWindowLongPtr(richeditWindow, GWL_WNDPROC, (LONG_PTR)&EditKeyProc);
    }

    ~richEdit()
    {
        if (richeditWindow != NULL)
        {
            SetWindowLongPtr(richeditWindow, GWL_WNDPROC, (LONG_PTR)DefEditProc);
            DestroyWindow(richeditWindow);
        }
    }
};

或者:

#include <windows.h>
#include <richedit.h>

namespace myNS
{
    LRESULT CALLBACK richEditKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

    class richEdit
    {
    private:
        HWND richeditWindow;
        WNDPROC DefEditProc;

    public:
        richEdit()
            : richeditWindow(NULL), DefEditProc(NULL)
        {
            HMODULE richedit_library = LoadLibrary("Msftedit.dll");
            if (NULL == richedit_library) abort();

            HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(0);
            richeditWindow = CreateWindowExW (
              WS_EX_TOPMOST,
              MSFTEDIT_CLASS,
              L"window text",
              WS_OVERLAPPED | WS_SYSMENU | ES_MULTILINE | WS_VISIBLE,
              0, 0, 500, 500,
              NULL, NULL, hInstance, NULL
            );
            if (NULL == richeditWindow) abort();

            SetWindowLongPtr(richeditWindow, GWL_USERDATA, (LONG_PTR)this);
            DefEditProc = (WNDPROC) SetWindowLongPtr(richeditWindow, GWL_WNDPROC, (LONG_PTR)&richEditKeyProc);
        }

        ~richEdit()
        {
            if (richeditWindow != NULL)
            {
                SetWindowLongPtr(richeditWindow, GWL_WNDPROC, (LONG_PTR)DefEditProc);
                DestroyWindow(richeditWindow);
            }
        }
    };

    LRESULT CALLBACK richEditKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        richEdit *pThis = (richEdit*) GetWindowLongPtr(hwnd, GWL_USERDATA);
        return CallWindowProc(pThis->DefEditProc, hwnd, uMsg, wParam, lParam);
    }
}

答案 2 :(得分:0)

您不能将指向成员函数的指针用作窗口过程,因为Windows需要常规函数指针。在内部,在某些情况下,它不会有足够的存储空间用于成员指针(它们在MSVC中最多可以是16个字节,32位),并且在任何情况下它都不会知道要使用什么“this”指针。 / p>

如果您唯一的兴趣是避免命名空间污染,那么最简单的解决方案是使用命名空间而不是类。否则,您必须使EditKeyProc成为该类的静态成员,并使用SetWindowLong存储“this”指针的副本,以供EditKeyProc访问。