C++ CancelIoEx:函数指针类型def
以下代码是从MS Async Filter复制的。假设以下代码正在调用CancelIo或CancelIoEx。我看不出CancelIoEx在哪里。假设typedef代表CancelIoEx,但从未调用过。行C++ CancelIoEx:函数指针类型def,c++,function,pointers,typedef,cancelio,C++,Function,Pointers,Typedef,Cancelio,以下代码是从MS Async Filter复制的。假设以下代码正在调用CancelIo或CancelIoEx。我看不出CancelIoEx在哪里。假设typedef代表CancelIoEx,但从未调用过。行bResult=(pfncancelionex)(m_hFile,NULL)的具体内容正在做什么 // Cancel: Cancels pending I/O requests. HRESULT CFileStream::Cancel() { CAutoLock lock(&m
bResult=(pfncancelionex)(m_hFile,NULL)的具体内容代码>正在做什么
// Cancel: Cancels pending I/O requests.
HRESULT CFileStream::Cancel()
{
CAutoLock lock(&m_CritSec);
// Use CancelIoEx if available, otherwise use CancelIo.
typedef BOOL (*CANCELIOEXPROC)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
BOOL bResult = 0;
CANCELIOEXPROC pfnCancelIoEx = NULL;
HMODULE hKernel32 = LoadLibrary(L"Kernel32.dll");
if (hKernel32){
//propably bad code !!! Take Care.
bResult = (pfnCancelIoEx)(m_hFile, NULL);
FreeLibrary(hKernel32);
}
else {
bResult = CancelIo(m_hFile);
}
if (!bResult) {
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}
假设这就是所有的代码,它有一个严重的错误。这:
CANCELIOEXPROC pfnCancelIoEx = NULL;
将pfnCancelIoEx
定义为指向签名与CancelIoEx
匹配的函数的指针。指针初始化为空值,明显的目的是稍后将其指向CancelIoEx
该函数是在Kernel32.dll
中定义的,因此加载该函数是合乎逻辑的下一步。如果此操作成功,代码应继续执行以下操作:
pfnCancelIoEx = GetProcAddress(hKernel32, "CancelIoEx");
然后它应该检查结果。然而,这两者都不能做到
接下来,在这一行:
bResult = (pfnCancelIoEx)(m_hFile, NULL);
它尝试调用由pfncancelionex
指向的函数。但是,此指针永远不会更改其初始空值,因此这将尝试取消对空指针的引用,导致未定义的行为,并可能导致崩溃。这真的是所有代码吗?我假设pfncancelionex
在被调用之前会被分配到。类似于pfncancelionex=GetProcAddress(…“CancelIoEx”…)
yes就是这样。我附上完整的功能(一些评论是我的)是的,我绝对同意你。。。但是我认为直接调用CancelIoEx会更容易,而不是做一个编程循环来完成同样的事情:-)我不明白重点!!!你?@Maverick如果该功能在某些情况下不可用(例如,如果它仅在某些版本的Windows上可用),你通常会使用这种技巧。Hoever,根据它的文档,CancelIoEx
从Windows 95开始就可以使用,所以这里的情况似乎不是这样。。。我想不出其他原因。函数CancelIoEx在Vista和更高版本的操作系统中可用(您可以在上检查),但在这种情况下,我不认为仅仅检查它是否可以加载Kernel32.dll就表明它是Vista操作系统或实现了特定的函数。我说的对吗?@Maverick哎呀,我打开的MSDN页面错了。感谢您更正功能可用性。代码实际上并不是在调用CancelIoEx
(即使它恰好在加载的Kernel32
中),而是去引用一个空指针。是的,我同意你关于指针去引用的观点,当然这是错误的。原始代码本身应该使用代码“if(hKernel32)”检查新CancelIoEx的可用性,如果是真的,则很明显CancelIoEx存在并被调用(某种方式也是错误的)。现在,在hKernel32检查失败的情况下,正如您在代码中看到的,它被称为旧的CancelIo。正如我所说,这段代码是错误的,因为您无法确定CancelIoEx的可用性或存在性,只需检查Kernel32.dll是否可以毫无问题地加载即可。