1

お客様が C++ クライアントから呼び出す古い C++ COM .dll があります。

古い .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" にあるのではないかと疑い始めています。質問を更新し、コード サンプルを修正しました。

どんなアイデアでも大歓迎です!

4

1 に答える 1

1

測定値: -2147467259 制限: = 2"

それは魔法の数です。これを 16 進数に変換すると、0x80004005 が得られます。それはエラー コード、悪名高い E_FAIL または「未特定のエラー」です。そのため、見えないドットのどこかで、エラーの戻り値を数値として解釈しています。vtError 型のバリアントであり、バリアント型を無視している可能性があります。質問から結論付けられるのはそれだけです。コードのエラー処理を確認してください。

于 2012-05-17T11:09:07.723 に答える