CustomDialogProc 必须是静态的吗? WinAPI
Do CustomDialogProc have to be static. WinAPI
我一直在考虑使用 WinApi 为我的应用程序创建自定义控件,并且我制作了一个 class,其中包含 CustomDialogProc
和 CreateWindowEx
以及 RegisterClass()
职能。
我可以在 CustomDialogProc
中设置一个断点并且它命中,因此 class 被正确注册。
但是,我必须将 class
的 CustomDialogProc 函数声明为 static int header
static LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam);
如果我不将其设置为静态,则会出现错误
Error C3867 'CustomControl::CustomDialogProc': non-standard syntax; use '&' to create a pointer to member
这是必要的吗,这要求我在此控件中创建的所有控件也都是静态的。如果我想要此控件的多个实例怎么办?
我该如何解决这个问题?主要的 MsgProc 似乎不是静态函数。下面显示的第一个 link 中的 UpDownDialogProc
也不是
下面是我的 CustomControl.h 代码,以备不时之需。
从以下位置找到的代码放在一起:
https://msdn.microsoft.com/en-us/library/windows/desktop/hh298353(v=vs.85).aspx
https://www.codeproject.com/Articles/485767/True-Windows-control-subclassing
谢谢,
#pragma once
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
class CustomControl
{
public:
CustomControl();
~CustomControl();
LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//DO STUFF HERE
break;
}
}
bool CreateControl(HWND hwnd, HINSTANCE* m_hApp_instance)
{
g_hInst = m_hApp_instance;
RegisterSubClass(*g_hInst, WC_LISTBOX, TEXT("CustomControl"), CustomDialogProc);
HWND hwndCustom = CreateWindow(TEXT("CustomControl"), NULL, WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, hwnd, (HMENU)100, *g_hInst, NULL);
return true;
}
private:
HINSTANCE* g_hInst;
WNDPROC RegisterSubClass(HINSTANCE hInstance, LPCTSTR ParentClass, LPCTSTR ChildClassName, WNDPROC ChildProc) {
WNDCLASSEX twoWayStruct;
WNDPROC parentWndProc;
if (GetClassInfoEx(NULL, ParentClass, &twoWayStruct)) {
parentWndProc = twoWayStruct.lpfnWndProc; // save the original message handler
twoWayStruct.cbSize = sizeof(WNDCLASSEX); // does not always get filled properly
twoWayStruct.hInstance = hInstance;
twoWayStruct.lpszClassName = ChildClassName;
twoWayStruct.lpfnWndProc = ChildProc;
/* Register the window class, and if it fails return 0 */
if (RegisterClassEx(&twoWayStruct))
return parentWndProc; // returns the parent class WndProc pointer;
// subclass MUST call it instead of DefWindowProc();
// if you do not save it, this function is wasted
}
return 0;
}
};
最常见的方法是使用 SetWindowLongPtr
存储指向与 window 句柄关联的对象的指针。
HWND hWnd = CreateWindow(...);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) this);
然后在您的对话过程中,获取该指针并调用您的 class:
// this static method is registered with your window class
static LRESULT CALLBACK CustomDialogProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
auto pThis = (CustomControl*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pThis != NULL)
return pThis->CustomDialogProcInstance(hWnd, uMsg, wParam, lParam);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// this instance method is called by the static method
LRESULT CustomDialogProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
}
确保适当地管理 window 和 class 生命周期,以防止 window 过程调用已删除的对象实例。在许多情况下,这就像确保在 class 被破坏时调用 DestroyWindow
一样简单。
Windows API 基于 C
语言。它对 C++
、non-static 成员函数、对象等一无所知
所以是的,所有将与 Windows API 直接 通信的功能必须 static
class 成员函数,或 non-class / global / "free" 函数。
这并不妨碍您为 C
API 编写 C++
包装器。这就是 Microsoft 的 MFC
或旧的 Borland OWL
库完成的任务。其他独立小组也为 Windows API 编写了包装器。
请注意,这些不同的库以不同的方式实现了将基于 C
的 API 挂接到 C++
的目标。一种是使用@MichaelGunter给出的答案中提到的SetWindowLongPtr
方法。另一种方法是使用映射来关联 window 句柄和静态 Window 过程。
我建议您在自己尝试此操作(创建包装器)之前,调查一下其他人是如何完成此操作的,然后选择最适合的方法。另一个建议是,在创建包装器之前,您应该了解基于 C
的 API,而不仅仅是粗略的了解。如果您希望包装器在不同场景下相对完美地工作,您需要对任何 C
API 计划创建一个包装器的 C++
包装器有高级到专业的知识。
我一直在考虑使用 WinApi 为我的应用程序创建自定义控件,并且我制作了一个 class,其中包含 CustomDialogProc
和 CreateWindowEx
以及 RegisterClass()
职能。
我可以在 CustomDialogProc
中设置一个断点并且它命中,因此 class 被正确注册。
但是,我必须将 class
的 CustomDialogProc 函数声明为 static int headerstatic LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam);
如果我不将其设置为静态,则会出现错误
Error C3867 'CustomControl::CustomDialogProc': non-standard syntax; use '&' to create a pointer to member
这是必要的吗,这要求我在此控件中创建的所有控件也都是静态的。如果我想要此控件的多个实例怎么办?
我该如何解决这个问题?主要的 MsgProc 似乎不是静态函数。下面显示的第一个 link 中的 UpDownDialogProc
也不是
下面是我的 CustomControl.h 代码,以备不时之需。 从以下位置找到的代码放在一起: https://msdn.microsoft.com/en-us/library/windows/desktop/hh298353(v=vs.85).aspx https://www.codeproject.com/Articles/485767/True-Windows-control-subclassing
谢谢,
#pragma once
#include <windows.h>
#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")
class CustomControl
{
public:
CustomControl();
~CustomControl();
LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
//DO STUFF HERE
break;
}
}
bool CreateControl(HWND hwnd, HINSTANCE* m_hApp_instance)
{
g_hInst = m_hApp_instance;
RegisterSubClass(*g_hInst, WC_LISTBOX, TEXT("CustomControl"), CustomDialogProc);
HWND hwndCustom = CreateWindow(TEXT("CustomControl"), NULL, WS_CHILD | WS_VISIBLE,
0, 0, 0, 0, hwnd, (HMENU)100, *g_hInst, NULL);
return true;
}
private:
HINSTANCE* g_hInst;
WNDPROC RegisterSubClass(HINSTANCE hInstance, LPCTSTR ParentClass, LPCTSTR ChildClassName, WNDPROC ChildProc) {
WNDCLASSEX twoWayStruct;
WNDPROC parentWndProc;
if (GetClassInfoEx(NULL, ParentClass, &twoWayStruct)) {
parentWndProc = twoWayStruct.lpfnWndProc; // save the original message handler
twoWayStruct.cbSize = sizeof(WNDCLASSEX); // does not always get filled properly
twoWayStruct.hInstance = hInstance;
twoWayStruct.lpszClassName = ChildClassName;
twoWayStruct.lpfnWndProc = ChildProc;
/* Register the window class, and if it fails return 0 */
if (RegisterClassEx(&twoWayStruct))
return parentWndProc; // returns the parent class WndProc pointer;
// subclass MUST call it instead of DefWindowProc();
// if you do not save it, this function is wasted
}
return 0;
}
};
最常见的方法是使用 SetWindowLongPtr
存储指向与 window 句柄关联的对象的指针。
HWND hWnd = CreateWindow(...);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) this);
然后在您的对话过程中,获取该指针并调用您的 class:
// this static method is registered with your window class
static LRESULT CALLBACK CustomDialogProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
auto pThis = (CustomControl*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (pThis != NULL)
return pThis->CustomDialogProcInstance(hWnd, uMsg, wParam, lParam);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
// this instance method is called by the static method
LRESULT CustomDialogProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
}
确保适当地管理 window 和 class 生命周期,以防止 window 过程调用已删除的对象实例。在许多情况下,这就像确保在 class 被破坏时调用 DestroyWindow
一样简单。
Windows API 基于 C
语言。它对 C++
、non-static 成员函数、对象等一无所知
所以是的,所有将与 Windows API 直接 通信的功能必须 static
class 成员函数,或 non-class / global / "free" 函数。
这并不妨碍您为 C
API 编写 C++
包装器。这就是 Microsoft 的 MFC
或旧的 Borland OWL
库完成的任务。其他独立小组也为 Windows API 编写了包装器。
请注意,这些不同的库以不同的方式实现了将基于 C
的 API 挂接到 C++
的目标。一种是使用@MichaelGunter给出的答案中提到的SetWindowLongPtr
方法。另一种方法是使用映射来关联 window 句柄和静态 Window 过程。
我建议您在自己尝试此操作(创建包装器)之前,调查一下其他人是如何完成此操作的,然后选择最适合的方法。另一个建议是,在创建包装器之前,您应该了解基于 C
的 API,而不仅仅是粗略的了解。如果您希望包装器在不同场景下相对完美地工作,您需要对任何 C
API 计划创建一个包装器的 C++
包装器有高级到专业的知识。