Frage

Ich versuche, ein COM-Objekt über eine MSMQ Nachricht in C ++ zu senden. Das ist mein Ziel:

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

Alles geht gut, und ich kann das ganze Objekt aber die BSTR Typen. Floats und ganze Zahlen sind richtig gesendet und empfangen werden. Aber die BSTR-Typen arbeiten nicht. Ich versuche, Strings zu senden und kann den Weg nicht finden. Ich habe versucht mit VARIANT statt und das Ergebnis war auch falsch. Irgendwie sieht es aus wie die Saiten nicht serialisiert werden.

Dies sind einige der Get- und Set-Funktionen für meine ATL-Komponente:

Dies funktioniert gut:

STDMETHODIMP CAnalisis::getLight(FLOAT* light)
{

    *light=img.light;
    return S_OK;
}

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

Dieses nicht:

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

    return S_OK;
}

STDMETHODIMP CAnalisis::setImgName(BSTR imgName)
{

    img.imgName=imgName;
    return S_OK;
}

und das ist die Art, wie ich die MSMQ-Nachricht erstellen und die Werte in meinem Produzenten füllen:

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


Hier ist die Serialisierung Code

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;
}

Wenn ich den BSTR Wert in dem Erzeuger (vor Serialisierung), pAnalisis-getImgName() erhalten, es funktioniert gut. Im Gegensatz dazu, wenn ich versuche, es in den Verbrauchern zu erhalten, nachdem er die Nachricht aus der Warteschlange zu lesen, kehrt es nichts. Die anderen Werte, wie zB die Größe, sind ohne Probleme zurückgegeben.

Wer weiß, wie man einen BSTR Wert in einem COM-Objekt durch MSMQ senden?

Ich habe versucht, einige ähnliche Beispiele zu finden, aber völlig vergeblich.

Die Sache ist, dass ich erhalte entweder einen sehr seltsamen Wert mit seltsamen Zeichen oder einen hexadezimalen Wert, je nachdem, wie ich den Wert extrahierte .. die Sache ist, dass ich den richtigen Wert noch nie bekommen.

und ich habe mich gefragt, aber ... sind wir sicher, dass es möglich ist, ein BSTR Wert zu schicken? wenn ich nicht irre, ist es ein Zeiger auf einen String ... Ich bin mit zwei verschiedenen Verfahren (dh Erzeuger und Verbraucher), so verwenden sie unterschiedliche Speicherblöcke, und sie sollen so auf verschiedenen Maschinen ausgeführt werden. ..

Ich habe versucht, diese Informationen als VARIANT-Typen zu senden .. bekam aber auch verloren. Dies scheint jedoch ein bisschen weniger weit hergeholt, als einen BSTR senden.

Jede gute Idee?

War es hilfreich?

Lösung

Das Problem ist, dass die Serialisierung der Image-Klasse als ein zusammenhängender Speicherblock behandelt. Da BSTR nur wirklich ein Zeiger der Zeigerwert serialisiert und die BSTR Nutzlast verloren.

Stattdessen sollten Sie alle Felder außer BSTRs als binäre und Prozess BSTRs separat schreiben. Zum Beispiel können Sie BSTR Länge als integer zuerst, dann seine Nutzlast schreiben. Beim Lesen Sie Länge gelesen werden zuerst, ruft SysAllocStringLen () einen Puffer zuzuweisen, und die Nutzlast lesen.

Lassen Sie die Serialisierung von einfachen Feldern, wie es ist (die IPersistStreamInit :: Save ()):

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

Für BSTRs dies zu tun:

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

Ähnliche zum Lesen (die 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;
}
Hinweis

, dass dieser Code schreibt / liest Stringlänge und dann schreibt / liest die Nutzlast, die von Unicode-Zeichen besteht. Unicode-Zeichen belegen mehr als ein Byte je -. Damit die Multiplikation in IStream Read / Write-Methoden aufrufen

Andere Tipps

Wenn Sie einfach eine WCHAR passieren - die Längeninformation verloren. Der BSTR ist falsch formatiert und dies wahrscheinlich verursacht Sie alle Trauer. Sie müssen SysAllocString verwenden, um es über Komponenten zu verwenden. Siehe MSDN - die Bemerkungen . Versuchen Sie:

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

OK, hängt diese Antwort auf Sie etwas Merkwürdiges in diesen Tagen tun, aber vielleicht anwendbar. Eine lange, lange Zeit hatte ich ++ 6 (pro) aus einer VB-Anwendung, um einen VB-String unter VB6 und VC zu übergeben. zu einem VC ++ App. Die Länge kam durch OK, aber ich erhielt oft ein Zeichen auf der anderen Seite.

Das Problem war, dass der Empfang App. wurde nicht für Unicode kompiliert, sondern als Projekt ANSI. Der COM-Schicht-Code, der es auf der anderen Seite der Übertragung ausgepackt hat einen interessanten Trick, den ich nur in einer dunklen Ecke des MSDN in einem Buchauszug dokumentiert gefunden:. Es erstellt eine Abstr

Ein Abstr ist nicht wirklich ein Typ. Es gibt keine Möglichkeit, eine zu erklären. Es ist eigentlich eine Neuformatierung eines zugrunde liegenden Speicher des BSTR, so dass Sie es ist ein ASCII char * in C ++ vorgeben kann. Dies, indem zunächst sicherstellen, dass die BSTR Punkte auf das erste Zeichen nach seinem Header (typisch ohnehin für solche Strukturen in C ++, IIRC) durchgeführt wird und und die aktuellen String-Daten schlurfen so daß sie alle ersten Bytes durch alle zweiten Bytes gefolgt. Ein anderer Name dafür ist "pure Böse".

Zwei sehr schlecht Dinge können auf diese Weise geschehen: Wenn diese Konvertierung durchgeführt, und das Ergebnis zu behandeln, als ob es immer noch eine große Zeichenfolge, erhalten Sie Kauderwelsch. Wenn es nicht getan hat und Sie die Ergebnisse als ASCII-Zeichen-Array behandeln, erhalten Sie in der Regel ein einzelnes Zeichen, wenn das Original nur ASCII-Range-Zeichen enthalten, in der breiten Darstellung, da jedes andere Byte eine Null und die hohen Bytes kommen Sekunde.

Ich kann nicht ganz von Ihrer Beschreibung sagen, ob dies ist, was mit dir passiert. Aber ich empfehle das Ding in einem Debugger zu stoppen und Blick auf all die String-Daten unter diesem empfangenen Wert zu sehen, ob es in einer unerwarteten Weise neu gemischt worden ist. Wenn es gemischt wurde, fragen Sie sich, warum und sehen Sie, wie Sie das Projekt gebaut.

Die Tatsache eines fast ohne Papiere Format in eine bestehende Art als Alternative Speicherlayout verkeilt, die wirklich schwer zu finden, auch durch die wie-viele-String-Formate-can-wir-Make-up-Standards der MS-Entwicklung, nur über mich schreien. Es war fast so schlimm wie der Versuch, „GetModuleFileName“ zum ersten Mal zu identifizieren, wie die Funktion der aktuellen ausführbaren Pfad zu erhalten zu verwenden.

Ihr Objekt muss eine Kopie der Zeichenfolge erstellen sowohl im Getter und 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;
}

Natürlich müssen Sie die Zeichenfolge in dem destructor befreien, überprüfen Sie für NULL PTRs etc.

Alternativ können Sie CComBSTR statt BSTR verwenden. CComBSTR ist ein intelligenter als BSTR, es kümmert sich um die Zuteilung und Aufheben der Zuweisung des Speichers.

Mein Vorschlag ist, Ihre Felder in einer Variante (auch wenn vorübergehend) setzen dann die Daten verwenden Variant-Streaming-Code zu glätten, und es am anderen Ende deserialisieren.

Hier ist Code-Streaming Sie verwenden können (sorry, es ist etwa 20 Jahre alt :))

Link: https://github.com/kasajian/VariantStream/blob /master/VariantStream.h

Der Code ist ein bisschen ausführliche hier einzufügen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top