第三个`SetWindowSubclass`参数中的`uIdSubclass`是什么?

问题描述 投票:0回答:2

根据:http://msdn.microsoft.com/en-us/library/windows/desktop/bb762102(v=vs.85).aspx

SetWindowSubclass 原型是:

BOOL SetWindowSubclass(
   __in  HWND hWnd,
   __in  SUBCLASSPROC pfnSubclass,
   __in  UINT_PTR uIdSubclass,
   __in  DWORD_PTR dwRefData
);

好的,我明白了

hWnd
pfnSubclass
dwRefData

我找不到好的信息是,我将

uIdSubclass
设置为什么?

MSDN 说:

子类 ID。该 ID 与子类过程一起唯一标识 一个子类。要删除子类,请将子类过程和此值传递给 RemoveWindowSubclass 函数。该值被传递给子类过程 uId子类参数。

好的,明白了,但是,我从哪里得到这个 ID?它是我创造的还是我在某个地方得到的?如果它是我创造的东西,它应该是什么样子?

我在 C++ 和 Win32 API 中做这件事,没有别的。

谢谢。

c++ winapi
2个回答
0
投票

Karl E. Peterson 在 Visual Studio Magazine 07/16/2009 中写到 uIdSubclass 参数的用途 Karl E. Peterson 文章中讨论的主题: 使用 uIdSubclass 存储一个 this 指针 [或 HWND]。

使用 dwRefData 传递可选数据,例如创建数据的指针。

    重要的是在pfnSubclass中处理WM_NCDESTROY并调用 RemoveWindowSubclass() 传递用于调用 SetWindowSubclass() 的 uIdSubclass。
  1. 引自 Karl E. Peterson 的文章
  2. 每个子类都标识了两条数据以及窗口的 hWnd——它们是指向新消息处理过程的指针和由您生成的唯一 ID。您还可以选择将一个 Long 值作为额外参数传递给每个回调,无论您想要什么目的。立即打动我的想法是使用 ObjPtr() 作为每个子类的唯一 ID。什么对象?将处理回调的那个!

关于我遇到的唯一未记录的警告是您必须确保在销毁窗口之前取消挂钩您的子类。如果您使用我的技术将处理程序嵌入在 Form_Unload 方法期间销毁的窗体或类中,这应该永远不会成为问题。如果你真的不想冒险,你可以在你的处理例程中插入一个简单的分支:

Select Case uiMsg Case WM_THIS ' Case WM_THAT ' Case WM_NCDESTROY Call Unhook ' !!! End Select

Explorer Browser Search Sample
也有一个使用 uIdSubclass 存储指向 this 的指针的示例。
void CExplorerBrowserSearchApp::_OnInitializeDialog()
{
    ...
        // Register the searchbox icon to receive hover and mouseclick events
        SetWindowSubclass(GetDlgItem(_hdlg, IDC_SEARCHIMG), s_SearchIconProc, (UINT_PTR)this, 0);
    ...
}

Raymond Chen 的博客“The Old New Thing”文章Safer subclassing

也提到了在 pfnSubclass 中处理 WM_NCDESTROY 以调用 RemoveWindowSubclass() 的重要性。
引自Raymond Chen的文章

文档中没有清楚解释的一个问题是,您必须在被子类化的窗口被销毁之前删除您的窗口子类。这通常是通过在您的临时需求过去后删除子类来完成的,或者如果您正在安装永久子类,则通过在子类过程本身中插入对 RemoveWindowSubclass 的调用来完成:

case WM_NCDESTROY: RemoveWindowSubclass(hwnd, thisfunctionname, uIdSubclass); return DefSubclassProc(...);

作为旁注,Microsoft

SetWindowSubclass
文档警告说 SetWindowSubclass() 仅限于每个线程。

警告您不能使用子类化辅助函数跨线程对窗口进行子类化。

假设我们有

ListViewHelper
C++ 类,它对

0
投票
控件做了一些有用的事情。此类必须继承

ListView

及其父类(对话框,以接收通知):
// constructor
ListViewHelper(HWND hwndListView)
{
    SetWindowSubclass(hwndListView, listViewSubclassProc,
        0, reinterpret_cast<DWORD_PTR>(this)));
    SetWindowSubclass(GetParent(hwndListView), parentSubclassProc,
        0, reinterpret_cast<DWORD_PTR>(this)));
}
在这种情况下,
uIdSubclass

不需要,可以是任何数字,通常是0。
但是如果对话框包含两个

ListView

 控件怎么办? 
ListViewHelper

的第二个实例将使用与第一个实例相同的参数调用

SetWindowSubclass()

,但 
dwRefData
 除外,因此 
SetWindowSubclass()
 不会子类化,而只会更改 
dwRefData
。糟糕,
ListViewHelper
的第一个实例已停止工作。
在我们的例子中,我们需要提供一个不同的
uIdSubclass
,以使用相同的
pfnSubclass

子类化相同的窗口。您可以在

static unsigned int

 类中定义 
ListViewHelper
 变量,并在每个 
ListViewHelper
 实例中递增它。但更简单、更合乎逻辑的方法是使用
hwndListView
SetWindowSubclass(GetParent(hwndListView), parentSubclassProc,
    reinterpret_cast<UINT_PTR>(hwndListView), reinterpret_cast<DWORD_PTR>(this)));
我认为还有其他情况应该使用
uIdSubclass

    

© www.soinside.com 2019 - 2024. All rights reserved.