包装属性表;如何处理回调? 我正在编写一个(非托管)C++类来包装窗口。基本上是这样的: class PropSheet { PROPSHEETHEADER d_header; public: PropSheet(/* parameters */); INT_PTR show(); private: static int CALLBACK *propSheetProc(HWND hwnd, UINT msg, LPARAM lParam); };

包装属性表;如何处理回调? 我正在编写一个(非托管)C++类来包装窗口。基本上是这样的: class PropSheet { PROPSHEETHEADER d_header; public: PropSheet(/* parameters */); INT_PTR show(); private: static int CALLBACK *propSheetProc(HWND hwnd, UINT msg, LPARAM lParam); };,c++,winapi,callback,wrapper,propertysheet,C++,Winapi,Callback,Wrapper,Propertysheet,构造函数只是初始化d_头成员: PropSheet::PropSheet(/* parameters */) { d_header.dwSize = sizeof(PROPSHEETHEADER); d_header.dwFlags = PSH_USECALLBACK; // ... d_header.pfnCallback = &propSheetProc; // ... } 之后,我可以通过以下方式展示: INT_PTR PropSheet:

构造函数只是初始化
d_头
成员:

PropSheet::PropSheet(/* parameters */) {
    d_header.dwSize = sizeof(PROPSHEETHEADER);
    d_header.dwFlags = PSH_USECALLBACK;
    // ...
    d_header.pfnCallback = &propSheetProc;
    // ...
}
之后,我可以通过以下方式展示:

INT_PTR PropSheet::show() {
    return PropertySheet(&d_header);
}
现在的问题是,因为回调是静态的,所以它无法访问包装器类。如果这是一个普通窗口,使用a而不是a,我可以使用
cbWndExtra
in将一些额外的数据附加到该窗口,在该窗口中我可以存储指向包装器的指针,如中所示。但属性页不提供此功能

此外,由于属性表是以模式显示的,所以在实际窗口的创建和销毁之间,我不能执行任何代码,除非该代码是通过回调或该表的窗口过程之一执行的

到目前为止,我提出的最佳解决方案是,在显示属性表之前,将指向包装器类的指针存储在全局变量中。但这假设了我一次只显示一个属性表,而且非常难看


有人知道如何更好地解决这个问题吗?

当您以模式显示属性表时,您应该能够使用属性表的父窗口(即其句柄)映射到一个实例,使用
::GetParent()
hwndDlg
参数的
PropSheetProc()

上,还有一个Win32 API,它使用回调而不使用用户定义的上下文参数。唉,这不是唯一的一个。e、 g.CreateWindow不好(它提供用户定义的上下文,但该上下文不适用于前几个窗口消息),SetWindowsHookEx更差(根本没有上下文)

唯一通用且有效的“解决方案”是使用硬编码的“this”指针发出一小段可执行代码。大概是这样的:


太可怕了

PROPSHEETPAGE结构有一个lParam字段可用于回调。在PROPSHEETHEADER中,您可以包含PSH_PROPSHEETPAGE标志以传递描述页面的PROPSHEETPAGE项目数组,也可以省略该标志以传递预分配的HPROPSHEETPAGE句柄数组(这意味着使用CreatePropertySheetPage(),因此仍然使用PROPSHEETPAGE)。

您已经承认了“在创建和销毁实际窗口之间,我无法执行任何代码“。似乎全局变量不是一个可怕的黑客行为。

我发现了另一个选项:使用添加一个存储指向包装器指针的属性。只需要全局变量一次,就可以从属性表回调调用
SetProp

唉,它没有父变量。此外,如果父级生成多个属性表,也会出现相同的问题。(我知道这很少见,但可能会发生。)或者你是在建议我将
PropSheet*
转换为
HWND
?如果Windows试图访问
HWND
,它的头会不会爆炸?我是不是误解了什么?在
PROPSHEETHEADER
(即
hwndprent
)上设置(或应该设置)父窗口。在
PropSheetProc()
中,您可以获得对话框的句柄,作为第一个参数,您可以对其调用
GetParent()
。此外
PropSheetPageProc()
还可以获得一个
LPPROPSHEETPAGE
,您可以使用它进行标识。。。。我看不出一个窗口是如何产生多模态对话框的。如果要从属性表创建新的模式对话框,请将父句柄设置为对话框句柄。CreateWindow()具有一个lParam参数,允许您将用户定义的值传递给新窗口。该值在WM_CREATE消息的CREATESTRUCT结构中可用,然后可以将其复制到HWND中,例如使用SetWindowLong(GWL_USERDATA)或SetProp(),以便在以后的消息中使用。如果WM_CREATE是您收到的第一条消息,那将是非常棒的。不是。哇,这是我从没想到过的一个黑客。但是我不敢走这条路。ATL使用了类似的技术(或者至少,它过去使用过,可能现在不再使用)来设置每个对象的WndProcs,所以这不是前所未有的。MFC还做了一些值得研究的事情,但我记不起是什么了。另一个大头钉;我认为.NET可以为您合成合适的代码,因此,如果您定义合适的委托类型并使用托管代码,这就行了。注意,这是一种相当迂回的动态生成可执行代码的方法!Borland的VCL还使用此类可执行代理来处理Win32窗口过程的“this”指针。根据
PropSheetProc()
的文档,
lParam
包含0,例如,
PSCB_按钮按下了
。是的,各个页面的窗口过程没有问题。整个属性表的回调引起了我的头疼。在无法由单个页面回调处理的表回调中,您需要做什么?@gf-是的,因为该回调中的LPRAM不是用户定义的值。我指的是PropSheetPageProc()回调,它提供对用户定义的LPRAM的访问。