2017-01-25 78 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; 
}