我正在尝试将一个字节数组从c#传递给c ++。我正在使用组件对象模型。这是我的第一次COM体验。如何将字节数组从c#传递给c ++?有什么建议?当我尝试传递除二进制数组
之外的其他类型(字符串,int等)时没有问题由于
我得到的错误
1-)error C2440: '=' : cannot convert from 'SAFEARRAY' to 'byte'
2-)IntelliSense: no suitable conversion function from "SAFEARRAY" to "byte" exists
这是我写的代码
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();
答案 0 :(得分:2)
您需要分配不安全的内存,如@KinKulling的答案所示,或者将数组作为适当标记的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;
}
答案 1 :(得分:0)
您需要将您的字节数组编组到unsave c ++世界中。您可以使用Marshal类来执行此操作:https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal_methods(v=vs.110).aspx
所以你可以使用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;
}
在c ++中,您应该能够使用此指针,如:
CoInitialize(NULL);
IDBCPtr obj;
obj.CreateInstance(__uuidof(DBC));
IntPtr intPtr = obj->GetImage();
CoUninitialize();
在C ++中使用它之后不要忘记释放已分配的不安全内存:
// Free the unmanaged memory.
Marshal.FreeHGlobal(pnt);
希望这可以帮到你。