简体   繁体   English

在Windows API应用程序定义的回调函数中,指针参数数据的生存期是多少? 回调返回后是否继续存在?

[英]In Windows API application-defined callback functions, what is the lifetime of pointer parameter data? Does it persist after the callback returns?

As an example, let's look at EnumWindowStations() , which requires the caller to pass an EnumWindowStationsProc() callback function. 例如,让我们看一下EnumWindowStations() ,它要求调用者传递一个EnumWindowStationsProc()回调函数。 The callback function will be invoked once for every window station in the current terminal session. 对于当前终端会话中的每个窗口站,回调函数将被调用一次。 Let's look at the signature of the callback function: 让我们看一下回调函数的签名:

BOOL CALLBACK EnumWindowStationProc(
    _In_ LPTSTR lpszWindowStation,
    _In_ LPARAM lParam
);

The first parameter is a pointer to string data. 第一个参数是指向字符串数据的指针。 Was that string buffer allocated explicitly for the callback invocation, and will it be freed immediately after the callback returns, or perhaps immediately before the enumeration function returns? 该字符串缓冲区是为回调调用显式分配的,是否将在回调返回后立即或枚举函数返回之前立即释放? Or, does the pointer point to some kind of persistent memory, such that the string buffer will remain allocated and usable afterward? 或者,指针是否指向某种持久性内存,以便字符串缓冲区在以后仍保持分配和可用状态?

This is an important point, because if it is not persistent, then it would be incorrect to, for example, store the raw pointer in a global container to be accessed after the callback and full enumeration process have finished. 这一点很重要,因为如果它不是持久性的,那么例如将原始指针存储在要在回调和完整枚举过程完成后访问的全局容器中将是不正确的。 Instead, it would be necessary to copy the underlying string data to a buffer controlled by the application, before the callback returns. 相反,在回调返回之前 ,有必要将基础字符串数据复制到应用程序控制的缓冲区中。

The official documentation does not seem to make clear what the lifetime of the string data is. 官方文档似乎并未阐明字符串数据的生存期。 There's only one line in the description of the parameter: 参数的说明中只有一行:

lpszWindowStation [in] lpszWindowStation [输入]

The name of the window station. 窗口站的名称。

And nowhere on the documentation page does it talk about the lifetime of the string data. 而且在文档页面上的任何地方都没有提到字符串数据的生存期。 Nor can I recall ever finding an MSDN page that answers this question "once and for all", ie for all uses of the callback idiom in the Windows API. 我也不会想起曾经找到过一个“一劳永逸”的MSDN页面,即Windows API中对回调惯用法的所有使用。

At the moment I am most interested in the EnumWindowStations() / EnumWindowStationsProc() case, but it would be best if answerers would address the general case, ie what to assume for all Windows API callback functions. 目前,我对EnumWindowStations() / EnumWindowStationsProc()案例最感兴趣,但是最好是回答者解决一般情况,即对所有Windows API回调函数承担什么。

Generally if the memory is allocated by the system you can rely on it being valid for the duration of the callback and no more. 通常,如果内存是由系统分配的,则可以依靠它在回调期间有效,而不再需要更多内存。 That is the case for lpszWindowStation in your example. 在您的示例中, lpszWindowStation就是这种情况。 You would need to access and copy the string inside your callback function and must not refer to the system supplied data outside your callback. 您将需要访问并复制回调函数中的字符串,并且不得在回调之外引用系统提供的数据。

You can deduce this with a little thought experiment. 您可以通过一些思想实验来推断出这一点。 If this string could be accessed after the callback returned when would it become invalid? 如果在回调返回后可以访问此字符串,它将何时无效? When would it be deallocated? 什么时候将其释放? You'd have to tell the system that you were done with it. 您必须告诉系统您已完成操作。 Since there is no API indicated to do that the only conclusion is that stated above. 由于没有指示要这样做的API,因此唯一的结论就是上述内容。

Things are different for lParam . lParam情况有所不同。 That value was supplied by you when you called EnumWindowStations and so you manage the lifetime of whatever it points to, if indeed you are using it as a pointer. 该值是在您调用EnumWindowStations时由您提供的,因此,如果确实将其用作指针,则可以管理它所指向的内容的生命周期。

In general pointers passed to callback functions by WINAPI are only guaranteed to be valid for the duration of the callback (unless otherwise specified in the documentation of the specific callback). 通常,只有通过WINAPI传递给回调函数的指针才能保证在回调期间有效(除非在特定回调的文档中另行指定)。 Once the callback returns, the pointer should be assumed to be invalid (it may be freed or it may point to a temporary buffer that will be overwriten in the next iteration of an enumeration etc). 一旦回调返回,就应该假定该指针无效(可以释放该指针或指向一个临时缓冲区,该缓冲区在枚举的下一次迭代中将被覆盖)。

The callback function is responsible for creating a copy of whatever data it may need to persist after it returns. 回调函数负责创建返回后可能需要保留的所有数据的副本。 In the case of the above example you should allocate your own bufffer and copy the string from lpszWindowStation if you need to use it after the callback returns. 在上述示例中,如果需要在回调返回后使用它,则应分配自己的bufffer并从lpszWindowStation复制该字符串。 Of course you should also manage the lifetime of the allocated buffer(s). 当然,您还应该管理分配的缓冲区的生存期。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM