包装 PropertySheet;如何处理回调?

发布于 2024-08-14 16:26:32 字数 1573 浏览 12 评论 0原文

我正在编写一个(非托管)C++ 类来包装 Windows 属性表。本质上,是这样的:

class PropSheet {
    PROPSHEETHEADER d_header;
    public:
        PropSheet(/* parameters */);
        INT_PTR show();
    private:
        static int CALLBACK *propSheetProc(HWND hwnd, UINT msg, LPARAM lParam);
};

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

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);
}

现在的问题是,因为回调是静态的,所以它无法访问包装类。如果这是一个普通窗口,带有 WindowProc 而不是 PropSheetProc,我可以使用 WNDCLASS,我可以在其中存储返回包装器的指针,如 这篇文章。但属性表不提供此功能。

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

到目前为止,我想出的最佳解决方案是,在显示属性表之前,将指向包装类的指针存储在全局变量内。但这假设我一次只会显示一张属性表,而且无论如何都很难看。

有谁有更好的想法如何解决这个问题?

I'm writing an (unmanaged) C++ class to wrap the Windows PropertySheet. Essentially, something like this:

class PropSheet {
    PROPSHEETHEADER d_header;
    public:
        PropSheet(/* parameters */);
        INT_PTR show();
    private:
        static int CALLBACK *propSheetProc(HWND hwnd, UINT msg, LPARAM lParam);
};

The constructor just initializes the d_header member:

PropSheet::PropSheet(/* parameters */) {
    d_header.dwSize = sizeof(PROPSHEETHEADER);
    d_header.dwFlags = PSH_USECALLBACK;
    // ...
    d_header.pfnCallback = &propSheetProc;
    // ...
}

After which I can show it, modally, with:

INT_PTR PropSheet::show() {
    return PropertySheet(&d_header);
}

Now the problem is, because the callback is static, that it cannot access the wrapper class. If this were a normal window, with a WindowProc instead of a PropSheetProc, I could attach some extra data to the window using cbWndExtra in WNDCLASS, in which I could store a pointer back to the wrapper, like in this article. But property sheets do not offer this functionality.

Furthermore, because the property sheet is shown modally, I can execute no code between the creation and destruction of the actual window, except when that code is executed through the callback or one of the sheets's window procedures.

The best solution I've come up with so far is to, right before showing the property sheet, store a pointer to the wrapper class inside a global variable. But this assumes that I'll only be showing one property sheet at a time, and is quite ugly anyway.

Does anyone have a better idea how to work around this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

过去的过去 2024-08-21 16:26:32

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

As you are showing the property sheet modally, you should be able to use the parent window (i.e. its handle) of the property sheet to map to an instance, using ::GetParent() on the hwndDlg parameter of PropSheetProc().

丶视觉 2024-08-21 16:26:32

太棒了,又一个 Win32 API,它使用没有用户定义的上下文参数的回调。唉,这不是唯一的一个。例如,CreateWindow 很糟糕(它为您提供了用户定义的上下文,但该上下文对于前几个窗口消息不可用),SetWindowsHookEx 更糟糕(根本没有上下文)。

唯一通用且有效的“解决方案”是发出一小段带有硬编码“this”指针的可执行代码。像这样的东西: http: //episteme.arstechnica.com/eve/forums/a/tpc/f/6330927813/m/848000817831?r=848000817831#848000817831

太可怕了。

Awesome, yet another Win32 API that uses callbacks without a user-defined context parameter. It is not the only one, alas. e.g. CreateWindow is bad (it gives you user-defined context, but that context isn't available for the first few window messages), SetWindowsHookEx is even worse (no context at all).

The only "solution" that is general-purpose and effective is to emit a small piece of executable code with a 'this' pointer hardcoded. Something like this: http://episteme.arstechnica.com/eve/forums/a/tpc/f/6330927813/m/848000817831?r=848000817831#848000817831

It's horrible.

玩物 2024-08-21 16:26:32

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

The PROPSHEETPAGE structure has an lParam field available for callbacks. In your PROPSHEETHEADER, you can include the PSH_PROPSHEETPAGE flag to pass an array of PROPSHEETPAGE items describing your pages, or omit the flag to pass an array of preallocated HPROPSHEETPAGE handles instead (which means using CreatePropertySheetPage(), and thus using PROPSHEETPAGE anyway).

调妓 2024-08-21 16:26:32

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

You've already admitted "I can execute no code between the creation and destruction of the actual window". It seems that a global variable wouldn't be a terrible hack.

本王不退位尔等都是臣 2024-08-21 16:26:32

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

I've found another option: using SetProp to add a property that stores the pointer to the wrapper. Only requires the global variable once, to be able call SetProp from the property sheet callback.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文