在Windows 7中,VS2012编译器
PostQueuedCompletionStatus(hCompletionPort, 0, (DWORD) pContext, &pOverlap->m_ol);
上面的API调用工作正常。
但是在Windows 10和VS2017编译器上,无法访问pContext
结构中的成员变量。
当我们从DWORD
更改为ULONG_PTR
时,它在Windows 10中可以正常工作
PostQueuedCompletionStatus(hCompletionPort, 0, (ULONG_PTR) pContext, &pOverlap->m_ol);
这种行为的原因是什么?
答案 0 :(得分:8)
很可能新版本不仅在Windows版本中有所不同,而且您还在编译为64位,而以前是32位。
更新 :OP澄清了两个版本都是64位的,但这很容易解释。见下文。
即使在Windows 7/32位上,强制转换为DWORD
在概念上也是错误的。实际上,API定义需要ULONG_PTR
,它是一个无符号整数类型,其大小足以容纳一个指针而不会丢失数据。因此,编译为32位时为32位类型,编译为64位时为64位。
相反,您将指针投射到DWORD
上; DWORD
始终是32位无符号类型,因此,在构建32位Windows时,一切都进行得很顺利(指针只需要不超过32位即可完整地到达另一端),但是在64位Windows上,您将失去顶部指针的32位。
现在,此甚至可以在64位Windows 7上运行;为什么?
如注释中所述,此指针来自堆,默认情况下,在Windows 7上,堆从64位地址空间的“低”部分开始提供内存。因此,除非您消耗大量内存,否则您将始终获得前32位为零的地址,因此即使将前32位砍掉也可以继续使用。
This changed since Windows 8,因为ASLR(在构建64位可执行文件时默认由链接器启用)使堆在虚拟地址空间中的位置随机化,这意味着您将获得具有非零上位的指针32位,将被强制转换为DWORD
。
长话短说:修复您的演员表 1 ,一切都会正常。另外,将来始终要警惕从指针到不以_ptr
或_PTR
结尾的整数类型的强制转换-您很可能会犯错。
注释
void *
才能使这些强制转换正常工作,即,仅针对uintptr_t
保证通过void *
的往返(也许{{1 }}?我必须检查标准),如果char *
还不是(ULONG_PTR)(LPVOID)pContext
,则应该为pContext
。但是,这是Win32,我敢肯定,即使没有额外的转换,它也能保证正常工作。