2012-05-16 3 views
1

고객이 C++ 클라이언트에서 호출 한 오래된 C++ COM .dll이 있습니다.C#/COM에서 C++ 클라이언트로 값을 반환 하시겠습니까?

우리는 이전 .dll을 .NET으로 작성된 새로운 COM 등록 된 것으로 바꾸려고합니다.

C++ 클라이언트는 새로운 .dll을 호출 할 수 있지만 특정 메서드를 호출하면 충돌이 발생합니다.

"outNoOfChildren"변수 또는 아래의 outChildList 배열에서 잘못된 것을 반환하는 것으로 보입니다.

은 (클라이언트에 오류 메시지가 읽습니다 : "알 수없는 예외가 잡힌 차일의 수 측정 :. -2147467259 제한 : = 2"., 그것은이 기대 우리가 반환하려고하는)

이상한 일이다 새로운 .NET .dll의 메서드 호출은 우리가 가지고있는 다른 테스트 클라이언트 (VB6)에서 작동하는 것 같습니다.

.NET 인터페이스 :

이것은 우리가 쓴 .NET의 .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; 
} 

:

우리가 대체하려고하는 것을 .DLL ++은 C의 기능입니다
... 
[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; 
} 

업데이트 :

[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); 
: 우리의 새로운 .NET 그것이 OLE/COM 개체 뷰어에서 다음과 같습니다 .DLL 등록하면

[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); 

: 원래 C++ .DLL은 OLE/COM 개체 뷰어에서 다음과 같습니다

업데이트 2 : 오류가 "outNoOfChildren"에 없지만 "outChildList"배열에있을 것으로 의심되기 시작했습니다. 질문을 업데이트하고 이에 대한 코드 샘플을 수정했습니다.

많은 아이디어가 감사합니다!

+0

상태 매개 변수는 어떻게 되었습니까? –

+0

알아두기 마지막 매개 변수는 함수의 반환 값입니다. – Poppert

+0

.NET .dll로 스와핑하기 전후에 OLE/COM Object Viewer에서 어떻게 표시되는지 질문이 업데이트되었습니다. 나는 C# 함수 반환 값이 "[out, retval] VARIANT *"로 번역 된 것으로 가정하고 그 것이 좋습니다. 하지만 C++ 스 니펫에는 상태 매개 변수와 S_OK의 반환이 모두 이상하다고 보입니다. – Poppert

답변

1

측정 : -2147467259 제한 : = 2 ". 매직 넘버의

그것을 변환을 진수하고 당신은 0X80004005를 얻을이 오류 코드, 악명 높은 E_FAIL 또는입니다."지정되지 않은 오류 " 그래서 우리가 볼 수없는 점들에서 오류 반환 값을 숫자로 해석하고 있습니다. 아마도 vtError 유형의 변형이며 변형 유형을 무시할 것입니다. 그게 문제에서 결론을 내릴 수있는 전부입니다. 오류 처리를 검토하십시오.

+0

한스, 답변 해 주셔서 감사합니다. 그러나 그 오류는 고객의 클라이언트에서 볼 수있는 것입니다 (우리가 할 수있는 일은 아닙니다). 문제는 왜 오류가 발생 했는가?.NET COM .dll이 클라이언트가 기대하는 것 이외의 것을 반환 할 것 같아요? (원래의 전체 C++ .dll 코드와 새로운 .NET 대체 코드를 포함 시켰습니다.) 그러나 나는 어둠 속에서 정말 우스꽝 스럽다 ... – Poppert

+0

C++ .dll에서 그들은 "SafeArray"(pArray 참조)를 사용한다. 그것이 문제일까요? 예 : 고객의 클라이언트는 "SafeArray"를 예상하지만 .NET .dll은 단순히 "일반"배열을 반환합니다. .NET .dll에서 "SafeArray"를 반환하려면 무엇이든해야합니까? – Poppert

+0

아니요, CLR이 자동으로 변환합니다. –

관련 문제