有一个东西,是如此奇妙,今天我们需要讲讲。
在不同的函数中,这个东西有着不同的名字,但实际它都是同一个东西。
例如,
RegisterWaitForSingleObject 这个 API,它的原型如下:
BOOL
RegisterWaitForSingleObject(
[out] PHANDLE phNewWaitObject,
[in] HANDLE hObject,
[in] WAITORTIMERCALLBACK Callback,
[in, optional] PVOID Context,
[in] ULONG dwMilliseconds,
[in] ULONG dwFlags
);
请先看其中的 Context 参数,猜猜它是做什么的。
再来看看 SetWindowSubclass 的函数原型:
BOOL SetWindowSubclass(
[in] HWND hWnd,
[in] SUBCLASSPROC pfnSubclass,
[in] UINT_PTR uIdSubclass,
[in] DWORD_PTR dwRefData
);
看看其中的 dwRefData 这个参数。
再来看看 EnumWindows:
BOOL EnumWindows(
[in] WNDENUMPROC lpEnumFunc,
[in] LPARAM lParam
);
其中有一个 lParam 参数。
最后是 CreateThread,也有一个类似的 lpParameter 参数。
HANDLE CreateThread(
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in, optional] __drv_aliasesMem LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out, optional] LPDWORD lpThreadId
);
以上这些参数,你是否感觉,冥冥之中,它们都是同样的东西?
你的感觉是对的。
它们确实是同样的一个东西,即函数将会原封不动的传递给你的东西,至于它的值是什么,函数本身并不关心,它只是将参数的值传递给你(调用者)。
调用者负责解释参数值的意义。
如果需要传递比单个指针更多的上下文,该怎么办?如果你想传递,比如说,两个指针怎么办?然后将两个指针放在一个结构中,并将指针传递到该结构。
执行此操作时,会引入生存期问题,因此请确保您有一个计划来决定谁负责在不再需要内存时释放内存。
你可能会问了:”为什么 MSDN中 没有这方面详细的描述呢? 否则,调用 CreateThread 的用户将不知道该参数需要是指向此结构的指针,并且线程过程需要释放内存。”
MSDN 中没有与之相关的描述,因为 MSDN 并不关心。这完全是程序中的约定。你有责任确保调用 CreateThread 的代码和线程过程就线程参数的含义以及应如何管理它达成一致。
总结
所以,亲爱的开发者,不要被 MSDN 中各种你没有见过的名称术语吓倒,当你深入了解了事物的本质,就会明白这些这是台面上的东西,没有什么可以畏惧的。
最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Some call it context, others call it reference data, but whatever it is, it’s yours》