2017-01-25 164 views
1

我试图从C#的字节数组传递到C++。我正在使用组件对象模型。这是我第一次使用COM的经验。我怎样才能将字节数组从C#传递给C++?有什么建议?还有当我试图通过另一种类型(字符串,INT等),除了二进制数组传字节数组从C#到C++(COM)

感谢

错误,我得到

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

这里是没有问题的,我写

代码C#方,

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++侧

CoInitialize(NULL); 

IDBCPtr obj; 

obj.CreateInstance(__uuidof(DBC)); 

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

CoUninitialize(); 
+0

哪一行代码获取错误?它显示在这里吗? – Baldrick

+0

@Baldrick当我尝试将返回值分配给字节数组时,我从C++端得到错误 – CodeJam

回答

0

你需要马歇尔的字节数组到取消保存C++的世界。您可以使用元帅级要做到这一点:https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal_methods(v=vs.110).aspx

所以,你可以通过使用封送返回不安全的指针TOR C++:

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

在C++中,你应该能够使用这个指针,如:

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

而且不要忘了用C使用后++,以释放分配安全存储器:

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

希望这可以帮助你。

+0

感谢您的回答。你能告诉我如何从C++获得指针吗? – CodeJam

+0

你能告诉你C++代码吗? – KimKulling

+0

我添加了C++代码来问题 – CodeJam

2

你要么需要分配不安全内存为@ KimKulling的回答暗示,或发送数组作为适当标记SafeArray。下面摘录了演示三种不同方法的示例,并且available on github

C#的界面看上去会是什么样子:

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

对于C#服务器实现的:

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

和一个C++客户端:

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