문제

C ++의 MSMQ 메시지를 통해 COM 객체를 보내려고합니다. 이것은 내 대상입니다.

class ATL_NO_VTABLE CAnalisis :
    public CComObjectRootEx,
    public CComCoClass,
    public ISupportErrorInfo,
    public IDispatchImpl,
    public IPersistStreamInit
{
private:
    typedef struct {
        DOUBLE size;
        float color;
        float light;

        BSTR imgName;

        BSTR  uname;

    } Image;

    Image img;
    STDMETHOD(Load)(IStream *pStm);
    STDMETHOD(Save)(IStream *pStm,  BOOL fClearDirty);

모든 것이 잘 진행되고 BSTR 유형이지만 전체 객체를 얻을 수 있습니다. 부유물과 정수가 올바르게 보내져 수신됩니다. 그러나 BSTR 유형은 작동하지 않습니다. 나는 줄을 보내려고 노력하고 있으며 길을 찾을 수 없습니다. 대신 변형으로 시도했고 결과도 잘못되었습니다. 어쨌든 문자열이 직렬화되지 않은 것처럼 보입니다.

이것들은 내 ATL 구성 요소의 get and set 함수 중 일부입니다.

이것은 잘 작동합니다.

STDMETHODIMP CAnalisis::getLight(FLOAT* light)
{

    *light=img.light;
    return S_OK;
}

STDMETHODIMP CAnalisis::setLight(FLOAT light)
{
    img.light=light;
    return S_OK;
}

이것은 그렇지 않습니다 :

STDMETHODIMP CAnalisis::getImgName(BSTR* imgName)
{
    *imgName = img.imgName;

    return S_OK;
}

STDMETHODIMP CAnalisis::setImgName(BSTR imgName)
{

    img.imgName=imgName;
    return S_OK;
}

그리고 이것이 MSMQ 메시지를 만들고 제작자의 값을 채우는 방법입니다.

// For these ActiveX components we need only smart interface pointer
        IMSMQQueueInfosPtr  pQueueInfos; 
        IMSMQQueueInfoPtr   pQueueInfo; 
        IMSMQQueuePtr       pQueue;
        IUnknownPtr         pIUnknown;
        // Instanciate the follwing ActiveX components
        IMSMQQueryPtr       pQuery(__uuidof(MSMQQuery));
        IMSMQMessagePtr     pMessage(__uuidof(MSMQMessage));


        IAnalisisPtr pAnalisis(__uuidof(Analisis));

                WCHAR *  imagen;        
        imagen = L"imagen1.jpg";
                pAnalisis->setImgName(imagen);


                 (...)

                pAnalisis->setFruitSize(20.00);

                 (...)

                pQueueInfo = new IMSMQQueueInfoPtr( __uuidof(MSMQQueueInfo) );

        pQueueInfo->PathName = "MYCOMPUTER\\private$\\myprivatequeue";

            pQueue = pQueueInfo->Open(MQ_SEND_ACCESS, MQ_DENY_NONE);
        pMessage->Body = static_cast(pAnalisis);
                pMessage->Send(pQueue);


직렬화 코드는 다음과 같습니다

STDMETHODIMP CAnalisis::Load( IStream *pStm )
{
    ULONG           cb;
    HRESULT         hr;
    if (NULL==pStm)
        return ResultFromScode(E_POINTER);
    // Read an object from the stream.
    //
    hr=pStm->Read(&img, sizeof(Image), &cb);
    if (FAILED(hr))
        return hr;
    if (sizeof(Image) != cb)
        return E_FAIL;

    return NOERROR;
}

STDMETHODIMP CAnalisis::Save( IStream *pStm, BOOL bClearDirty )
{
    ULONG           cb;
    HRESULT         hr;
    if (NULL==pStm)
        return ResultFromScode(E_POINTER);

    // Write an object into the stream.
    hr=pStm->Write(&img, (ULONG)sizeof(Image), &cb);
    if (FAILED(hr) || sizeof(Image)!=cb)
       return ResultFromScode(STG_E_WRITEFAULT);

    return NOERROR;
}

생산자에서 BSTR 값을 얻는 경우 (직렬화 전) pAnalisis-getImgName(), 그것은 잘 작동합니다. 대조적으로, 소비자에게 그것을 얻으려고 할 때, 대기열에서 메시지를 읽은 후에는 아무것도 반환하지 않습니다. 크기와 같은 다른 값은 문제없이 반환됩니다.

MSMQ를 통해 COM 객체 내에서 BSTR 값을 보내는 방법을 아는 사람이 있습니까?

나는 비슷한 예를 찾으려고 노력했지만 완전히 헛된 것입니다.

문제는 내가 값을 추출하는 방법에 따라 이상한 캐릭터 또는 16 진수 값을 가진 매우 이상한 값을 얻는 것입니다.

그러나 나는 궁금했다. 우리는 BSTR 가치를 보낼 수 있다고 확신합니까? 내가 틀리지 않으면 문자열에 대한 포인터입니다 ... 두 가지 다른 프로세스 (예 : 생산자와 소비자)를 실행하고 있기 때문에 다른 메모리 블록을 사용하여 다른 기계에서 실행해야합니다. ..

이 정보를 변형 유형으로 보내려고했지만 손실되었습니다. 그러나 이것은 BSTR을 보내는 것보다 조금 덜 가져온 것 같습니다.

이것에 대한 아이디어가 있습니까?

도움이 되었습니까?

해결책

문제는 이미지 클래스의 직렬화가이를 인접한 메모리 블록으로 취급한다는 것입니다. BSTR은 실제로 포인터이므로 포인터 값은 직렬화되고 BSTR 페이로드가 손실됩니다.

대신 BSTR을 제외한 모든 필드를 바이너리로 작성하고 BSTR를 별도로 작성해야합니다. 예를 들어, BSTR 길이를 먼저 정수로 작성한 다음 페이로드로 작성할 수 있습니다. 읽을 때 길이를 먼저 읽을 때 sysallocstringlen ()을 호출하여 버퍼를 할당 한 다음 페이로드를 읽습니다.

간단한 필드의 직렬화 (ipersiststreaminit :: save ()) :

pStm->Write(&(img.color), (ULONG)sizeof(float), &cb);

BSTRS의 경우 다음을 수행합니다.

int length = SysStringLen( img.uname );
pStm->Write(&length, (ULONG)sizeof(int), &cb);
if( length > 0 ) {
   pStm->Write( img.uname, (ULONG)(length * sizeof(WCHAR) ), &cb);
}

읽기와 유사합니다 (ipersiststreaminit :: load ()) :

int length;
pStm->Read(&length, (ULONG)sizeof(int), &cb);
if( length > 0 ) {
   img.uname = SysAllocStringLen( 0, length );
   pStm->Read( img.uname, (ULONG)( length * sizeof( WCHAR) ), &cb);
} else {
   img.uname = 0;
}

이 코드는 문자열 길이를 작성/읽은 다음 유니 코드 문자로 구성된 페이로드를 작성/읽습니다. 유니 코드 문자는 각각 둘 이상의 바이트를 차지하므로 ISTREAM 읽기/쓰기 메소드 호출의 곱셈.

다른 팁

단순히 WCHA를 통과하면 길이 정보가 손실됩니다. BSTR은 기형이며 이것은 아마도 모든 슬픔을 일으킬 것입니다. 사용해야합니다 SysAllocString 구성 요소에서 사용합니다. 보다 MSDN - 발언 부분. 노력하다:

BSTR imagen = SysAllocString(L"imagen1.jpg");

좋아,이 대답은 요즘 이상한 일을하는 것에 달려 있지만 적용 할 수 있습니다. 오래 전에 나는 VB 앱에서 VB6 및 VC ++ 6 (PRO)에 따라 VB 문자열을 통과해야했습니다. VC ++ 앱에. 길이는 괜찮아졌지만 다른 쪽에서는 종종 한 캐릭터를 받았습니다.

문제는 수신 앱이었습니다. 유니 코드가 아니라 ANSI 프로젝트로 편집되었습니다. 전송의 먼쪽에 포장을 풀었던 com 계층 코드는 책 발췌문에서 MSDN의 모호한 코너에서 문서화 된 흥미로운 트릭을 수행했습니다.

ABSTR은 실제로 유형이 아닙니다. 선언 할 방법이 없습니다. 실제로 BSTR의 기본 저장소의 재구성이므로 C ++의 ASCII 숯* 인 척 할 수 있습니다. 이것은 먼저 BSTR이 헤더 후 첫 번째 문자를 가리키도록하여 수행됩니다 (C ++, IIRC의 그러한 구조에 대한 일반). 그 다음에 실제 문자열 데이터를 섞어 첫 번째 바이트와 두 번째 바이트가 모두 포함되도록합니다. 이것의 또 다른 이름은 "순수한 악"입니다.

매우 나쁜 것들 이런 식으로 일어날 수 있습니다 :이 변환이 완료되고 결과를 여전히 넓은 문자열 인 것처럼 취급하면 횡설수설이됩니다. 그것이 끝나지 않고 결과를 ASCII 문자 배열로 취급한다면, 원본에 ASCII 범위 문자 만 포함 된 경우 일반적으로 단일 문자를 얻을 수 있습니다. 넓은 표현에서 다른 바이트는 0이고 높은 바이트는 두 번째입니다.

이것이 당신에게 일어난 일이라면 당신의 설명에서 말할 수 없습니다. 그러나 디버거에서 물건을 중지하고 수신 된 값 아래의 모든 문자열 데이터를 예상치 못한 방식으로 개편했는지 확인하는 것이 좋습니다. 섞인 경우 왜 스스로에게 물어보고 프로젝트를 구축하는 방식을 살펴보십시오.

거의 문서화되지 않은 형식의 사실은 기존 유형으로 기존 유형으로 묶여있는 대체 메모리 레이아웃으로서 MS 개발의 How-many-string-formats-can-we-make-make-up 표준에 의해서도 저를 만들었습니다. 비명. 현재 실행 파일의 경로를 얻는 데 사용하는 기능만큼 처음으로 "getModuleFilename"을 식별하려고 시도하는 것만 큼 나빴습니다.

객체는 Getter와 Setter에서 문자열 사본을 만들어야합니다.

STDMETHODIMP CAnalisis::getImgName(BSTR* imgName)
{
    *imgName = SysAllocString(img.imgName);

    return S_OK;
}

STDMETHODIMP CAnalisis::setImgName(BSTR imgName)
{
    SysFreeString(img.imgName);
    img.imgName=SysAllocString(imgName);
    return S_OK;
}

물론, 당신은 소멸자의 줄을 제거하고, null ptrs 등을 확인해야합니다.

또는 BSTR 대신 CCombstr를 사용할 수 있습니다. Ccombstr는 BSTR보다 똑똑하며 메모리를 할당하고 거래하는 것을 관리합니다.

내 제안은 필드를 변형에 넣은 다음 (일시적으로도) 변형 스트리밍 코드를 사용하여 데이터를 평평하게하고 다른 쪽에서는 필자화하는 것입니다.

여기에 사용할 수있는 스트리밍 코드가 있습니다 (죄송합니다 20 세입니다 :))

링크: https://github.com/kasajian/variantstream/blob/master/variantstream.h

이 코드는 여기에 붙여 넣기가 약간 장점입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top