Как сериализовать VARIANT или BSTR? - PullRequest
3 голосов
/ 10 июня 2019

Я пытаюсь выяснить некоторые функции сортировки COM.В конце концов, я хочу сохранить вложенный массив вариантов в файл, но сначала я пытаюсь использовать простую строку.Я понимаю, что эти API предназначены для удаленных вызовов процедур, но я надеялся, что эта сериализация также подходит для сохранения файлов.

Я много работаю с Excel VBA, и обнаружение, что эти API-интерфейсы сериализации действительно открывают глаза.

Приведенный ниже код сериализует BSTR в буфер, буфер копируется, что будет служить заменой для сохранения и загрузки из файла.

В настоящее время проблема в том, что BSTR_UserUnmarshal вызывает исключение Unhandled exception at 0x7631C762 (KernelBase.dll) in RPCMarshalling.exe: 0x00000057: The parameter is incorrect. occurred

Возможно, у меня неправильный синтаксис, потому что я работаю с клочками примера кода.Цель состоит в том, чтобы получить строку из srctest для desttest с помощью вызовов API сериализации RPC.

// RPCMarshalling.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>

//https://searchcode.com/file/140723732/dlls/oleaut32/tmarshal.c#l-818

typedef struct _marshal_state {
    LPBYTE  base;
    int     size;
    int     curoff;
} marshal_state;


int main()
{
    ::CoInitialize(0);

    CComBSTR srctest("Hello");
    marshal_state srcbuf;
    memset(&srcbuf, 0, sizeof(srcbuf));
    ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);

    ULONG size = ::BSTR_UserSize(&flags, 0, &srctest);

    DWORD newsize = max(size, 256);
    (&srcbuf)->base = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
    if (!(&srcbuf)->base)
        return E_OUTOFMEMORY;

    ::BSTR_UserMarshal(&flags, (&srcbuf)->base + (&srcbuf)->curoff, &srctest);
    (&srcbuf)->curoff = size;


    std::cout << "Hello World!\n" << size << "\n";


    marshal_state destbuf;
    memset(&destbuf, 0, sizeof(destbuf));

    (&destbuf)->base = (LPBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
    if (!(&destbuf)->base)
        return E_OUTOFMEMORY;

    /* pretend we are loading from file saved by src buffer */
    RtlCopyMemory((&destbuf)->base, (&srcbuf)->base, newsize);


    CComBSTR desttest("");
    BSTR deststring;

    try
    {
        unsigned char *buffer;
        buffer = ::BSTR_UserUnmarshal(&flags, (&destbuf)->base, &deststring);
    }
    catch (int e)
    {
        std::cout << "Error:" << e << "\n" << size << "\n";
    }



    ::CoUninitialize();

}

Ответы [ 2 ]

0 голосов
/ 10 июня 2019

И на самом деле, если сериализация является целью, то почему бы не сериализовать в IStream

int main()
{
    ::CoInitialize(0);

    CComVariant srctest("Hello");

    CComPtr<IStream> pStream;
    HRESULT hr;
    hr = CreateStreamOnHGlobal(NULL, TRUE,(LPSTREAM *) &pStream.p);
    if (hr != S_OK) return hr;

    hr = srctest.WriteToStream(pStream, VT_BSTR);
    if (hr != S_OK) return hr;

    {
        // stream needs resetting to the start before we 
        // attempt to read it
        LARGE_INTEGER  dlibMove;
        dlibMove.HighPart = 0;
        dlibMove.LowPart = 0;
        DWORD dwOrigin;
        dwOrigin = 0;
        ULARGE_INTEGER  libNewPosition;
        hr = pStream->Seek(dlibMove, dwOrigin, &libNewPosition);
        if (hr != S_OK) return hr;
    }

    CComVariant pvDest;
    hr = pvDest.ReadFromStream(pStream, VT_BSTR);
    if (hr != S_OK) return hr;

    CComBSTR strDest(pvDest.bstrVal);
    std::cout << "This got serialized:\n" << LPCSTR(_bstr_t(strDest, true)) << "\n";
    //std::cout << "This got serialized:\n" << strDest.m_str << "\n";

    ::CoUninitialize();
}
0 голосов
/ 10 июня 2019

Альтернативный метод для достижения цели сериализации варианта (согласно тексту вопроса ОП). Работа в процессе, с использованием предложения Саймона Мурье о StgSerializePropVariant

int main()
{
    ::CoInitialize(0);

    CComVariant srctest("Hello");

    SERIALIZEDPROPERTYVALUE* serialized;
    ULONG cb;
    ::StgSerializePropVariant((PROPVARIANT*)&srctest, &serialized, &cb);

    CComVariant pvDest;
    ::StgDeserializePropVariant(serialized, cb, (PROPVARIANT*)&pvDest);

    CoTaskMemFree(serialized);

    CComBSTR strDest(pvDest.bstrVal);
    std::cout << "This got serialized:\n" << LPCSTR(_bstr_t(strDest, true)) << "\n";

    ::CoUninitialize();
}
...