VARIANT 类型 punkVal 给出未定义的值?

发布于 2024-11-14 12:51:22 字数 537 浏览 0 评论 0原文

我使用一些 CComVariant 类型变量来存储接口指针。但是,有时我需要将接口指针作为 NULL 传递。在这种情况下,当我这样做时:

CComVariant vAData,vBData;
......
....
CComQIPtr<IBData> pAData = vAData.punkVal; //vAData is {0, VT_I4} when I pass NULL 

CComQIPtr<IBData>pBData = vBData.punkVal;  //vBData is {0, VT_I4} when I pass NULL

第一行失败并抛出异常,因为 vAData.punkVal = 0xffffffff00000000< /代码> 但第二行运行良好,没有错误,并且具有有效的 vBData.punkVal 值 (0x0000000000000000)。

我想知道为什么两个 punkVal 都为 NULL 时不同? 有人知道为什么会发生这种情况吗? 这仅在 64 位机器上引发异常。

I am using few CComVariant type variables to store interface pointers.However, sometime I need to pass interface pointer as NULL.In this case when I do this:

CComVariant vAData,vBData;
......
....
CComQIPtr<IBData> pAData = vAData.punkVal; //vAData is {0, VT_I4} when I pass NULL 

CComQIPtr<IBData>pBData = vBData.punkVal;  //vBData is {0, VT_I4} when I pass NULL

The first line fails and throws exception since the vAData.punkVal = 0xffffffff00000000
But the second line passes fine with no error and it has valid vBData.punkVal value(0x0000000000000000).

I am wondering why the two punkVal are different when both are NULL??
Does anybody has any idea why this is happening??
This throws exception only on 64bit machines.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无言温柔 2024-11-21 12:51:22

关于 VARIANT 的一些附加信息:它们有点奇怪,因为它们是复合类型:它基本上是几种类型的联合,每种类型的字段(bstrVal、lVal、punkVal 等)都占用内存中的相同空间,并且vt 字段指示哪个字段有效。

您应该只尝试访问与 vt 值匹配的字段。所以如果vt是VT_BSTR,那么只有bstrVal有效;朋克瓦尔是禁区。如果 vt 是 VT_I4,则仅应使用 lVal 字段。

VT_EMPTY 表示“此变量尚未设置为任何值,因此不代表任何内容”;当 vt 为 VT_EMPTY 时,所有字段都是禁止的 - 它们可能是之前堆栈上恰好出现的任何垃圾 - 这就是您在这里看到的。

在Win64中,整数仍然是32位,但指针是64位。 VT_I4 类型且值为 0 的变体将表示整数的 32 位全部设置为 0,但变体中的其余内存可能是任何剩余的垃圾。如果您尝试将该内存视为 64 位指针 - 通过访问 punkVal - 那么您最终会得到一个由这 32 个 0 位组成的指针,而且还来自从未正确初始化的相邻 32 位 - 这可能就是原因您在这里看到了两种情况之间的差异。

在 Win32 中,你很幸运:指针的大小与 int 相同,因此如果你访问 0 的 VT_I4 并读取 punkVal(你不应该这样做!),在这种情况下你最终会得到一个 NULL 指针。

Some additional information about VARIANTs: they're somewhat weird in that they are compound types: it's basically a union of several types, with the fields for each type (bstrVal, lVal, punkVal, etc) all occupying the same space in memory, and the vt field indicating which field is valid.

You should only attempt to access the field that matches the value of vt. So if vt is VT_BSTR, then only bstrVal is valid; punkVal is off-limits. If vt is VT_I4, then only the lVal field should be used.

VT_EMPTY means "this variant hasn't been set to any value, so doesn't represent anything"; when vt is VT_EMPTY, all fields are off-limits - they might be whatever garbage just happened to be on the stack before - which is what you are seeing here.

In Win64, integers are still 32-bits, but pointers are 64 bits. A variant that is of type VT_I4 with value 0 will have the 32 bits that represent the integer all set to 0, but the rest of the memory in the variant could be any leftover garbage. If you try to treat that memory as a 64-bit pointer - by accessing punkVal - then you'll end up with a pointer made from those 32 0 bits, but also from an adjacent 32bits that have never been properly initialized - that's likely why you're seeing differences between the two cases here.

In Win32, you get lucky: the pointer is the same size as the int, so if you access a VT_I4 that's 0 and read the punkVal (which you shouldn't!), you would end up getting a NULL pointer in that case.

拍不死你 2024-11-21 12:51:22

CComVariant 在构造函数中调用 VariantInit(),并将 vt 设置为 VT_EMPTY,但留下 punkVal code> 未初始化(不会使其为空)。

因此,您尝试做的是未定义的行为,因为您尝试构造一个 CComQIPtr 并将其传递给一个未初始化的指针。

如果您想要一个 CComVariant 持有 null IUnknown*,您可以这样做:

CComVariant variant( static_cast<IUnknown*>( 0 ) ); // null IUnknown*, VT_UNKNOWN type

现在构造一个 CComQIPtr 是完全合法的:

CComQIPtr<IWhatever> whatever( variant.punkVal ); //punknVal is null - legal

CComVariant calls VariantInit() in constructor and that sets vt to VT_EMPTY, but leaves punkVal uninitialized (doesn't make it null).

What you try to do is therefore undefined behavior since you try to construct a CComQIPtr passing it an uninitialized pointer.

If you want a CComVariant holding a null IUnknown* you can do this:

CComVariant variant( static_cast<IUnknown*>( 0 ) ); // null IUnknown*, VT_UNKNOWN type

now it's perfectly legal to construct a CComQIPtr:

CComQIPtr<IWhatever> whatever( variant.punkVal ); //punknVal is null - legal
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文