2
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;
} 
4

2 回答 2

2

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

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

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

于 2011-11-03T14:46:18.207 回答
0

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

即使CComVariant复制构造函数失败了i == ie,下一个赋值也可能会起作用,因为复制构造函数可能对在 spurious 字段中CComQIPtr<ITabField>检索到的任何内容感到满意。punkValCComVariant

于 2011-11-03T11:26:12.437 回答