お客様が 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" にあるのではないかと疑い始めています。質問を更新し、コード サンプルを修正しました。
どんなアイデアでも大歓迎です!