【问题标题】:Error: "bad variable type" in CComVariant::Copy when iterating through CComSafeArray错误:迭代 CComSafeArray 时 CComVariant::Copy 中的“错误变量类型”
【发布时间】:2011-12-20 23:46:51
【问题描述】:
CComSafeArray<VARIANT> fields;
hr = _tab_file->get_Fields(fields.GetSafeArrayPtr());

for ( LONG i = fields.GetLowerBound(), ie = fields.GetUpperBound(); i <= ie; ++i)
{
    CComVariant fld = fields.GetAt(i); // (1) raises DISP_E_BADVARTYPE (0x80020008L)

    // Next code works fine                
    CComQIPtr<ITabField> field = fields.GetAt(i).punkVal; // (2) Ok
    _bstr_t fieldName;
    hr = field->get_Name(fieldName.GetAddress());
    ::OutputDebugString(fieldName + _T("\n")); // Ok
}

第 (1) 行:fields.GetAt(i) 返回 CComVariant。当我尝试将此值分配给 CComVariant fld 时,在复制构造函数中调用了复制构造函数和方法 CComVariant::Copy。它引发异常(“错误的变量类型”,DISP_E_BADVARTYPE (0x80020008L))。 同时,第 (2) 行运行良好。第 (1) 行有什么问题,以及如何解决。

编辑:这是get_Field 的代码(填充SAFEARRAY)。

STDMETHODIMP TabFile::get_Fields( SAFEARRAY** fields )
{
  if(mapInfoFile_ == 0)
    return E_UNEXPECTED;
  int fieldCount = getFieldCount();
  SAFEARRAY* arr = ::SafeArrayCreateVector(VT_UNKNOWN, 0, fieldCount);
  for(LONG i = 0; i < fieldCount; i++)
  {
    QField* field = getQField(i);
    ITabField* tabField = TabField::CreateInstance();
    tabField->put_Name(_bstr_t(field->GetNameRef()));
    tabField->put_Type(field->GetNativeFieldType(i));
    ::SafeArrayPutElement(arr, &i, tabField);
    tabField->Release();
  }
  *fields = arr;
  return S_OK;
} 

【问题讨论】:

  • GetAt(i) 将为您提供CComVariant&amp; 类型。因此,您可以将您的 fld 变量更新为引用类型,并检查您在那里拥有的内容以及为什么该事物没有通过赋值/复制。
  • @RomanR。好的,我像这样CComVariant &amp;fld = fields.GetAt(i); 重写了(1)。工作正常,但我现在不知道如何理解,复制构造函数有什么问题
  • 现在你有了fld 变量,你可以检查它了。检查其.vt 是否良好且不是垃圾。毕竟这个值对copy是无效的,所以应该是有问题,用调试器应该可以看到。
  • .vt 正是问题所在。您的变体是.vt + .punkVal.punkVal 似乎是有效的,但 .vt 必须类似于 VT_UNKNOWNVT_DISPATCH 以便 API 意识到你在那里有一个接口。你似乎有垃圾所以 API 失败了。这就是原因,您最终会遇到原因。
  • 您创建了一个IUnknowns 数组,然后您尝试将其解释为VARIANT 数组。这些应该是相同的类型,您想要未知数组,然后将接口打包到 CComVariant 中,然后再将其放入 getter 的数组中,否则调用者将处理接口数组。

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


【解决方案1】:

您创建了一个IUnknowns 数组,然后您尝试解释 是VARIANT 的数组。那些应该是相同的类型,你想要 任一未知数组,然后将接口打包到CComVariant 在将其放入 getter 中的数组之前,否则调用者将 处理接口数组。

当您发现实际数组元素类型与您将其转换为的类型不匹配时,您将需要更新您的 getter 实现和调用者代码以相互匹配。

我个人的偏好是创建一个变体数组VT_ARRAY | VT_VARIANT,并将该数组放入[out] VARIANT* 参数中。调用者会将其从变量展开回数组,检查数组类型,然后获取元素。这是最小的开销,并且围绕VARIANT 类型的代码在互操作性方面是最好的 - 平均而言 - 就互操作性而言(在您的特定情况下,您肯定可以很好地使用原始类型,并且根本没有变体)。

【讨论】:

    【解决方案2】:

    我认为您遇到了典型的一对一错误。 ie 是最后一个元素之后的一个元素,所以fields.GetAt(i)i == ie 将返回一个不存在的元素。尝试在for 循环终止条件中将i &lt;= ie 替换为i &lt; ie,看看它是否有效。

    即使CComVariant 复制构造函数对i == ie 失败,下一个赋值可能似乎有效,因为CComQIPtr&lt;ITabField&gt; 复制构造函数可能对在虚假CComVariantpunkVal 字段中检索到的任何内容感到满意.

    【讨论】:

    • 安全数组边界包含两端,即GetAt(GetUpperBound()) 可以。
    猜你喜欢
    • 2016-03-10
    • 1970-01-01
    • 2021-02-13
    • 2018-01-03
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多