简体   繁体   中英

Passing Byte Array From C# to C++ (COM)

I am trying to pass a byte array from c# to c++ . I am using Component Object Model.This is my first COM experience. How can i pass byte array from c# to c++? Any advice? There is no problem when i try to pass another types (strings, int etc.) except binary arrays

Thanks

Errors i get

1-)error C2440: '=' : cannot convert from 'SAFEARRAY' to 'byte'     
2-)IntelliSense: no suitable conversion function from "SAFEARRAY" to "byte" exists  

Here is the code i wrote

C# Side,

public byte[] GetImage()
{

    try
    {

       SqlCommand command = new SqlCommand("this command returns Varbinary ", conn);
       SqlDataAdapter dataAdapter = new SqlDataAdapter(command);
       ImgBlobDT = new DataTable("ImgBlobDT");
       dataAdapter.Fill(ImgBlobDT);
       DataRow dr = ImgBlobDT.Rows[0];
       imgBytes = (byte[])dr["ImgBinary"];

    }
    catch ()
    {
        //some codes
    }


    return imgBytes;

}

C++ Side

CoInitialize(NULL);

IDBCPtr obj;

obj.CreateInstance(__uuidof(DBC));

byte bytesArr[] = obj->GetImage();

CoUninitialize();

You either need to allocate unsafe memory as @KimKulling's answer suggests, or send the array as an appropriately marked SafeArray . An example demonstrating three different methods is excerpted below, and available on github .

The C# interface looks would look like:

[ComVisible(true)]
[Guid("7FE927E1-79D3-42DB-BE7F-B830C7CD32AE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IImageProvider
{
    [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
    byte[] GetImage(int foo);

    IntPtr GetImageAsUnmanaged(int foo, out int cbBuff);

    void GetImageAsUnmanagedPreallocated(int foo, ref int cbBuff, IntPtr pBuff);
}

With a C# server implementation of:

[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
[Guid("D133B928-A98B-4006-8B00-4AA09BD042E7")]
[ProgId("CSByteArrayServer.ImageProvider")]
public class ImageProvider : IImageProvider
{
    private const int E_INVALIDARG = unchecked((int)0x80070057);

    RNGCryptoServiceProvider crng = new RNGCryptoServiceProvider();

    [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_UI1)]
    public byte[] GetImage(int foo)
    {
        return GetBytes();
    }

    private byte[] GetBytes()
    {
        byte[] data = new byte[500];
        crng.GetBytes(data);
        return data;
    }

    public IntPtr GetImageAsUnmanaged(int foo, out int cbBuff)
    {
        var data = GetBytes();

        var result = Marshal.AllocCoTaskMem(data.Length);
        Marshal.Copy(data, 0, result, data.Length);

        cbBuff = data.Length;
        return result;
    }

    public void GetImageAsUnmanagedPreallocated(int foo, ref int cbBuff, IntPtr pBuff)
    {
        var data = GetBytes();

        if (cbBuff < data.Length)
        {
            cbBuff = data.Length;
            throw Marshal.GetExceptionForHR(E_INVALIDARG);
        }

        cbBuff = data.Length;
        Marshal.Copy(data, 0, pBuff, data.Length);
    }
}

And a C++ client of:

int main()
{
    CoInitialize(NULL);

    IImageProvider *pImgProvider;
    CoCreateInstance(__uuidof(ImageProvider), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IImageProvider), (LPVOID*)&pImgProvider);

    int imageId = 0;

    // with SafeArray
    {
        SAFEARRAY *pSafeArray;
        auto hr = pImgProvider->GetImage(0, &pSafeArray);
        assert(hr == S_OK);
        CComSafeArray<BYTE> safeArray;
        safeArray.Attach(pSafeArray);
        ManipulateData(&safeArray);
        // CComSafeArray will free the memory allocated by pSafeArray
    }

    // with CoTaskMemAlloc
    {
        char *pData;
        int cbData;
        auto hr = pImgProvider->GetImageAsUnmanaged(0, (long*)&cbData, (long*)&pData);
        assert(hr == S_OK);

        ManipulateData(pData, cbData);
        CoTaskMemFree(pData);
    }

    // with caller allocate
    {
        int cbData;
        auto hr = pImgProvider->GetImageAsUnmanagedPreallocated(imageId, (long*)&cbData, (long)nullptr);
        assert(hr == E_INVALIDARG);

        char *pData = new char[cbData];
        hr = pImgProvider->GetImageAsUnmanagedPreallocated(imageId, (long*)&cbData, (long)pData);
        assert(hr == S_OK);

        ManipulateData(pData, cbData);

        delete[] pData;
    }

    system("pause");

    CoUninitialize();
    return 0;
}

void ManipulateData(char* pBuff, int cbBuff)
{
    char hash = 0;
    for (int i = 0; i < cbBuff; i++)
    {
        hash ^= pBuff[i];
    }

    std::cout << "Hash is " << +hash << std::endl;
}

void ManipulateData(CComSafeArray<BYTE> *pSafeArray)
{
    BYTE hash = 0;
    for (ULONG i = 0; i < pSafeArray->GetCount(); i++)
    {
        hash ^= pSafeArray->GetAt(i);
    }

    std::cout << "Hash is " << +hash << std::endl;
}

You need to marshall your byte array into the unsave c++ world. You can use the Marshal-class to do this: https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal_methods(v=vs.110).aspx

So you can return an unsafe pointer tor c++ by using Marshaling:

public IntPtr GetImage() {
    DataRow dr = ImgBlobDT.Rows[0];
    byte[] imgBytes = (byte[])dr["ImgBinary"];

    // Initialize unmanaged memory to hold the array.
    int size = Marshal.SizeOf(imgBytes [0]) * imgBytes .Length;
    IntPtr pnt = Marshal.AllocHGlobal(size);

    // Copy the array to unmanaged memory.
    Marshal.Copy(imgBytes , 0, pnt, imgBytes .Length);

    // your method will return a unmanaged pointer instead of byte[]
    return pnt;
}

In c++ you should be able to use this pointer like:

CoInitialize(NULL);
IDBCPtr obj;
obj.CreateInstance(__uuidof(DBC));
IntPtr intPtr = obj->GetImage();
CoUninitialize();

And don't forget to release the allocated unsafe memory after using it in C++:

        // Free the unmanaged memory.
        Marshal.FreeHGlobal(pnt);

Hopefully this could help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM