将值 C#/COM 返回到客户端C++

Returning values C#/COM to C++ client?

本文关键字:客户端 C++ 返回 COM 将值      更新时间:2023-10-16

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

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

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"数组中。我已经更新了问题并为此修改了代码示例。

任何想法非常感谢!

测量: -2147467259 极限: = 2">

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