这是Delphi 7中的简化方案:
procedure TMyClass.InternalGetData;
var
pRequest: HINTERNET;
/// nested Callback
procedure HTTPOpenRequestCallback(hInet: HINTERNET; Context: PDWORD; Status: DWORD; pInformation: Pointer; InfoLength: DWORD); stdcall;
begin
// [...] make something with pRequest
end;
begin
pRequest := HTTPOpenRequest(...);
// [...]
if (InternetSetStatusCallback(pRequest, @HTTPOpenRequestCallback) = PFNInternetStatusCallback(INTERNET_INVALID_STATUS_CALLBACK)) then
raise Exception.Create('InternetSetStatusCallback failed');
// [...]
end;
整个似乎工作正常,但它是否真的正确且安全?
我希望以这种方式封装它,因为它更具可读性和清洁性。我怀疑嵌套过程是否是一个简单的,正常的过程,因此它可以有自己的调用约定(stdcall
)并安全地引用外部方法的局部变量(pRequest
)
谢谢。
答案 0 :(得分:13)
在Windows的32位Delphi编译器中实现本地函数意味着这样的代码可以按照您的意图运行。前提是您没有参考封闭功能中的任何内容。您不能引用包含Self
引用的局部变量。您的评论表明您希望引用本地变量pRequest
。由于上述原因,您不得不这样做。
但是,即使遵循这些规则,它也只能由于实现细节而起作用。在documentation:
中明确指出它是非法的嵌套过程和函数(在其他例程中声明的例程)不能用作过程值。
如果您将代码带到其他平台(例如64位Windows),那么它将失败。此处详细介绍了此问题:Why cannot take address to a nested local function in 64 bit Delphi?
我的建议是你根本不用这种方式使用本地功能。这样做只会为自己设置陷阱,以便将来某个时候陷入困境。
我还建议对回调函数使用强类型声明,以便编译器可以检查您的回调是否具有正确的签名。这需要重新装修任何Win32 API函数,因为Embarcadero使用无类型指针的草率声明。您还想放弃使用@来获取函数指针,让编译器为您工作。
答案 1 :(得分:6)