COM interop - pass an [in, out] array

haton 21 Reputation points
2020-12-24T07:37:54.913+00:00

Hello, I want to call FileStream.Read from COM Interop. The .Read method wants an [in, out] byte[] buffer to write to. What parameter and variant type should I pass to .invoke?
I tried passing a safearray of bytes with VT_ARRAY+VT_UI1. The .Read call succeeds and returns the number of bytes requested, but the buffer is not written to. Thanks

C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,723 questions
.NET Runtime
.NET Runtime
.NET: Microsoft Technologies based on the .NET software framework.Runtime: An environment required to run apps that aren't compiled to machine language.
1,159 questions
{count} votes

Accepted answer
  1. RLWA32 45,476 Reputation points
    2020-12-24T11:21:56.9+00:00

    If you want to use IDispatch, try the following example ( use the debugger to examine the LPBYTE pointer after Invoke returns) -

    SAFEARRAY *pByteArray = CreateEmptyByteArray(16);
    
    DISPID did{ 0 };
    DISPPARAMS dispparams = { nullptr, nullptr, 0, 0 };
    PWSTR pszMethod = L"PassByteArray";
    HRESULT hr = ptrTest->GetIDsOfNames(IID_NULL, &pszMethod, 1, LOCALE_USER_DEFAULT, &did);
    if (SUCCEEDED(hr))
    {
        VARIANT vByteArray, vResult;
    
        VariantInit(&vByteArray);
        VariantInit(&vResult);
    
        V_VT(&vByteArray) = VT_ARRAY | VT_BYREF | VT_UI1;
        V_ARRAYREF(&vByteArray) = &pByteArray;
    
        dispparams.rgvarg = &vByteArray;
        dispparams.cArgs = 1;
    
        hr = ptrTest->Invoke(did, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, &vResult, nullptr, nullptr);
        if (SUCCEEDED(hr))
        {
            LPBYTE pBytes = nullptr;
            hr = SafeArrayAccessData(pByteArray, (LPVOID*) &pBytes);
            hr = SafeArrayUnaccessData(pByteArray);
        }
    
    }
    
    SafeArrayDestroy(pByteArray);
    

1 additional answer

Sort by: Most helpful
  1. RLWA32 45,476 Reputation points
    2020-12-24T10:13:41.16+00:00

    To pass a buffer from unmanaged code to a managed COM Server that wants a read/write byte[] array in the managed code you can refer to the following example.

    C# COM Server method -

    public void PassByteArray(ref byte[] bArr)
    {
        int len = bArr.Length;
        bool ro = bArr.IsReadOnly;
        for (int x = 0; x < len; x++)
            bArr[x] = 0xFF;
    }
    

    The above example just writes some data to be buffer it receives from the unmanaged code.

    Example C++ code (no error checking) to create SAFEARRAY for buffer and pass it to managed COM Server -

    SAFEARRAY * CreateEmptyByteArray(int nBytes)
    {
        ULONG nElements = nBytes;
        SAFEARRAYBOUND bound = { nElements, 0 };
    
        return SafeArrayCreate(VT_UI1, 1, &bound);
    }
    
    -----------------------------------------
    
    SAFEARRAY *pByteArray = CreateEmptyByteArray(16);
    
    hr = ptrTest->PassByteArray(&pByteArray);
    

    After the call to the COM method returns you can see that the SAFEARRAY reflects the changes made by the COM Server.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.