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

时间:2011-06-09 11:38:10

标签: c++ visual-c++ com

我使用很少的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位计算机上引发异常。

2 个答案:

答案 0 :(得分:4)

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

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

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

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

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

答案 1 :(得分:3)

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

因此,尝试构建一个CComQIPtr传递未初始化的指针时,您尝试执行的操作是未定义的行为。

如果您希望CComVariant持有空IUnknown*,则可以执行此操作:

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

现在构建CComQIPtr

是完全合法的
CComQIPtr<IWhatever> whatever( variant.punkVal ); //punknVal is null - legal