1

我们有一个旧的 C++ COM .dll,客户从他们的 C++ 客户端调用它。

我们正在尝试用一个用 .NET 编写的新 COM 注册的替换旧的 .dll。

C++ 客户端可以调用我们的新 .dll,但在调用特定方法后崩溃。

似乎我们在变量“outNoOfChildren”或下面的 outChildList 数组中返回了错误。

(客户端中的错误消息为:“捕获到未知异常。测量的子节点数:-2147467259 限制:= 2”,它期望我们尝试返回 2。)

奇怪的是,我们新的 .NET .dll 中的方法调用似乎可以在我们拥有的另一个测试客户端(VB6)上工作。

这是我们试图替换的 C++ .dll 中的函数:

STDMETHODIMP marcomBase::XgetChildren(VARIANT inUser,
                                  VARIANT inId,
                                  VARIANT *outNoOfChildren,
                                  VARIANT *outChildList,
                                  VARIANT *outErrMsg,
                                  VARIANT *status)
  long stat= 1;
  char user[255+1];
  char id[255+1];
  long noOfChildren = 0;
  char errMsg[255+1] = "";
  _bstr_t temp_bstr;
  long inparamType;
  long dumInt;
  SAFEARRAY *pArray;
  long ix[2];
  VARIANT var;
  SAFEARRAYBOUND rgsabound[2];
  ChildT childList;
  ChildT *childListTemp = NULL;
  ChildT *childListTempNext = NULL;

  childList.nextChild = NULL;

  getInParam( inUser, &inparamType, user, &dumInt);
  if (inparamType != VT_BSTR)
  {
    strcpy(errMsg, "Parameter 1 incorrect, type must be VT_BSTR");
    stat = 0;
  }

  if (stat == 1)
  {
    getInParam( inId, &inparamType, id, &dumInt);
    if (inparamType != VT_BSTR)
    {
      strcpy(errMsg, "Parameter 2 incorrect, type must be VT_BSTR");
      stat = 0;
    }
  }

  if (stat == 1)
  {
    stat = barApiObj.getChildren(user, id, &noOfChildren, childList, errMsg);
  }

  outNoOfChildren->vt = VT_I4;
  outNoOfChildren->lVal = noOfChildren;

  rgsabound[0].lLbound = 1;
  rgsabound[0].cElements = noOfChildren;
  rgsabound[1].lLbound = 1;
  rgsabound[1].cElements = 3;

  pArray = ::SafeArrayCreate(VT_VARIANT, 2, rgsabound);
  outChildList->vt = VT_ARRAY|VT_VARIANT;
  outChildList->parray = pArray;

  ix[0] = 1;

  childListTemp = childList.nextChild;

  while (childListTemp != NULL)
  {
    temp_bstr = childListTemp->child;
    var.vt = VT_BSTR;
    var.bstrVal = temp_bstr.copy();
    ix[1] = 1;
    ::SafeArrayPutElement(pArray, ix, &var);

    temp_bstr = childListTemp->prodNo;
    var.vt = VT_BSTR;
    var.bstrVal = temp_bstr.copy();
    ix[1] = 2;
    ::SafeArrayPutElement(pArray, ix, &var);

    temp_bstr = childListTemp->rev;
    var.vt = VT_BSTR;
    var.bstrVal = temp_bstr.copy();
    ix[1] = 3;
    ::SafeArrayPutElement(pArray, ix, &var);

    ix[0] = ix[0] + 1;

    childListTempNext = childListTemp->nextChild;
    delete childListTemp;
    childListTemp = childListTempNext;
  }

  temp_bstr = errMsg;
  outErrMsg->vt = VT_BSTR;
  outErrMsg->bstrVal = temp_bstr.copy();

  status->vt = VT_I4;
  status->lVal = stat;

  return S_OK;
}

这是我们编写的 .NET .dll:

.NET 接口:

...
[DispId(12)]
 [Description("method XgetChildren")]
object XgetChildren(object inUser, object inId, out object outNoOfChildren, out object outChildList, out object outErrMsg);
...

.NET 类

public object XgetChildren(object inUser, object inId, out object outNoOfChildren, out object outChildList, out object outErrMsg)
{
    outNoOfChildren = 0;
    outChildList = null;
    outErrMsg = "";

    List<IndividualInfo> children = null;
    try
    {
        PrevasMesExternalServiceClient client = getClient();
        children = client.GetChildren(new SerialNo() { Number = inId.ToString() });
    }
    catch (Exception ex)
    {
       return Constants.STATUS_FAIL;
    }

    int[] myLengthsArray = { children.Count, 3 }; //Length of each array 
    int[] myBoundsArray = { 1, 1 }; //Start index of each array

    Array myArray = Array.CreateInstance(typeof(string), myLengthsArray, myBoundsArray); //Create 1-based array of arrays

    for (int i = 0; i < children.Count; i++)
    {
        myArray.SetValue(Utils.getStrValue(children[i].SerialNumber, Constants.pmesIDNO_LENGTH), i+1, 1);
        myArray.SetValue(Utils.getStrValue(children[i].ProductNumber, Constants.pmesPRODUCTNO_LENGTH), i+1, 2);
        myArray.SetValue(Utils.getStrValue(children[i].Revision, Constants.pmesRSTATE_LENGTH), i+1, 3);
    }

    outChildList = myArray;
    outNoOfChildren = children.Count;

    return Constants.STATUS_OK;
}

更新:原始 C++ .dll 在 OLE/COM 对象查看器中如下所示:

    [id(0x0000000c), helpstring("method XgetChildren")]
    HRESULT XgetChildren(
                    [in] VARIANT inUser, 
                    [in] VARIANT inId, 
                    [out] VARIANT* outNoOfChildren, 
                    [out] VARIANT* outChildList, 
                    [out] VARIANT* outErrMsg, 
                    [out, retval] VARIANT* status);

注册我们的新 .NET .dll 后,它在 OLE/COM 对象查看器中如下所示:

    [id(0x0000000c), helpstring("method ")]
    HRESULT XgetChildren(
                    [in] VARIANT inUser, 
                    [in] VARIANT inId, 
                    [out] VARIANT* outNoOfChildren, 
                    [out] VARIANT* outChildList, 
                    [out] VARIANT* outErrMsg, 
                    [out, retval] VARIANT* pRetVal);

更新2:我开始怀疑错误可能不在“outNoOfChildren”中,而是在数组“outChildList”中。我已经更新了问题并为此修改了代码示例。

任何想法都非常感谢!

4

1 回答 1

1

测量:-2147467259 限制:= 2"

这是一个神奇的数字。将其转换为十六进制,您将得到 0x80004005。这是一个错误代码,臭名昭著的 E_FAIL 或“未指定错误”。因此,在我们看不到的点中,您将错误返回值解释为数字。可能是 vtError 类型的变体并忽略变体类型。这就是从问题中可以得出的全部结论,请查看代码中的错误处理。

于 2012-05-17T11:09:07.723 回答