typedef struct tagTrimInformation
{
int p_trim_count;
LPRECT p_trim_areas;
HBITMAP *p_trim_image;
} TRIMINFORMATION;
typedef TRIMINFORMATION FAR* LPTRIMINFORMATION;
int WINAPI TrimImage
( HBITMAP v_hbitmap,
HPALETTE v_color_palette,
TRIMINFORMATION &v_trim_information
);
22 个解决方案
#1
这样转换:
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct TRIMINFORMATION{
public int p_trim_count;
public IntPtr p_trim_areas;
public IntPtr p_trim_image;
}
[ DllImport( "xxx.dll" ,CharSet = CharSet.Ansi)]
public static extern int TrimImage(IntPtr v_hbitmap,IntPtr v_color_palette,ref TRIMINFORMATION v_trim_information);
#2
要传这个 LPRECT 类型的数组应该怎么传阿?
#3
我以为这么简单的问题只有我不会呢!!!!!!
#4
不明白你这个api是干什么的. 不过介绍c# 关于api的资料的确很少
vb尼玛超级多 不公平 啊 不公平
vb尼玛超级多 不公平 啊 不公平
#5
这是我们用C++自己写的一个API,我就想知道怎么在C#中调用!!
#6
这是我们自己用C++写的API,我就想知道怎么在C#中调用!!!
#7
这个API是我们自己用C++写的。我现在想知道怎么在C#中调用它!
#8
楼主,这个问题,看似简单,其实复杂!NET提供的互操作技术远比想象中复杂和晦涩!有时一个小问题,你可能几天都搞不定!
花了近两个时,并测试了,给你完整的例子:
C++部分:
C#部分:
你自己可以拿我的源码测试,看看是不是得到正确结果。。。
花了近两个时,并测试了,给你完整的例子:
C++部分:
struct TrimInfo
{
int count; //数组成员个数
LPRECT pTrim; //这里是RECT数组
};
extern "C" void __declspec(dllexport) TestTrim(TrimInfo* pInfo);
C#部分:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TrimInfo
{
public int count;
public IntPtr pTrim;
};
[DllImport(@"E:\pvcs\utscada\Debug\ExamDll.dll", EntryPoint = "TestTrim")]
public static extern bool TestTrim(ref TrimInfo info);
private void Form1_Load(object sender, EventArgs e)
{
RECT[] rcArr = new RECT[2];
for(int i=0;i<rcArr.Length;i++)
{
rcArr[i].left = i + 1;
rcArr[i].top = i + 1;
rcArr[i].right = i + 1;
rcArr[i].bottom = i + 1;
}
ptr=MashalStructArrayToPtr<RECT>(rcArr);
TrimInfo info=new TrimInfo();
info.count=2;
info.pTrim=ptr;
TestTrim(ref info);
}
public static IntPtr MashalStructArrayToPtr<T>(T[] StructArray)
{
List<byte[]> byteArrayList = new List<byte[]>();
// T[] ArrayA = new T[StructArray.Length];
for (int i = 0; i < StructArray.Length; i++)
{
byte[] buf = StructToBytes(StructArray[i]);
byteArrayList.Add(buf);
}
int totalLength = 0;
// 获取在内存存放的总长度
for (int i = 0; i < byteArrayList.Count; i++)
{
totalLength += byteArrayList[i].Length;
}
// 开辟一个Byte 数组
byte[] allBuffuer = new byte[totalLength];
int startIndex = 0;
// 然后依次把byteArrayList的数据拷贝到allBuffuer
for (int i = 0; i < byteArrayList.Count; i++)
{
byteArrayList[i].CopyTo(allBuffuer, startIndex);
startIndex = startIndex + byteArrayList[i].Length;
}
//指针所需的内存空间
IntPtr BufferPtr = Marshal.AllocCoTaskMem(totalLength);
//把C#结构体数组拷贝至这个指针
Marshal.Copy(allBuffuer, 0, BufferPtr, totalLength);
return BufferPtr;
}
public static Byte[] StructToBytes(Object structure)
{
Int32 size = Marshal.SizeOf(structure);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structure, buffer, false);
Byte[] bytes = new Byte[size];
Marshal.Copy(buffer, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
你自己可以拿我的源码测试,看看是不是得到正确结果。。。
#9
还有一种简单的办法:参数分解!这需要开发者在C++那边做技术处理,也就要求具备一定的C/C++的开发能力!
C++:
C#:
这种技术:就是通常所说的结构体“扁平化”,是参数传递变得简单。
C++:
extern "C" void __declspec(dllexport) TestTrim2(LPRECT pTrim,int count);
void TestTrim2(LPRECT pTrim,int count)
{
TrimInfo info;
info.count=count;
info.pTrim=pTrim;
TestTrim(&info);
}
C#:
[DllImport(@"E:\pvcs\utscada\Debug\ExamDll.dll", EntryPoint = "TestTrim2")]
public static extern void TestTrim2([In, Out]RECT[] rcArr, int count);
private void Form1_Load(object sender, EventArgs e)
{
RECT[] rcArr = new RECT[2];
for(int i=0;i<rcArr.Length;i++)
{
rcArr[i].left = i + 1;
rcArr[i].top = i + 1;
rcArr[i].right = i + 1;
rcArr[i].bottom = i + 1;
}
TestTrim2(rcArr, rcArr.Length); //换成的新的接口
}
这种技术:就是通常所说的结构体“扁平化”,是参数传递变得简单。
#10
非常感谢你,我试试嫩故不能达到我的要求,
而且我还有一个问题。函数运行完,这个结构的*p_trim_image指向返回的一个HBITMAP数组,应该怎么使用呢?
typedef struct tagTrimInformation
{
int p_trim_count;
LPRECT p_trim_areas;
HBITMAP *p_trim_image;
} TRIMINFORMATION;
#11
这个结构体:
这个: public IntPtr p_trim_image;中的p_trim_image,对应的是IntPtr数组。
得到返回值后,根据我给你的方法,反过来处理:
强调一下:如果你复杂的结构体和函数不好调通,你先自己写个简单些的结构体和函数调试。
你把调通了,就打通了一条路!对平台调用、互操作技术有直观的认识。然后逐步搞复杂的,
就会能较快定位问题。
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct TRIMINFORMATION{
public int p_trim_count;
public IntPtr p_trim_areas;
public IntPtr p_trim_image;
}
这个: public IntPtr p_trim_image;中的p_trim_image,对应的是IntPtr数组。
得到返回值后,根据我给你的方法,反过来处理:
IntPtr[] ptrArr=new IntPtr[p_trim_count];//个数与结构体的保持一致
Marshal.Copy(p_trim_image,ptrArr,0,p_trim_count);
foreach(IntPtr ptr in ptrArr)
{
//这里处理每一个ptr
}
强调一下:如果你复杂的结构体和函数不好调通,你先自己写个简单些的结构体和函数调试。
你把调通了,就打通了一条路!对平台调用、互操作技术有直观的认识。然后逐步搞复杂的,
就会能较快定位问题。
#12
public string 参数名(string 参数)
{
//语句
}
{
//语句
}
#13
我对互操作没接触过,一窍不通。我还有两个小问题。
1.非托管DLL分配的空间是否学要C#释放?怎么释放?
2.怎么把IntPtr强制转换成BitMap?
真的非常非常感谢你的回答,连我的同事都说你这人真好。呵呵
#14
1、这个问题涉及到较多方面,要叙述清楚,非一两句能说清楚的。
先简明扼要说说:C、C++、COM如何分配内存,直接影响net这边的释放!
非托管代码三种内存分配、释放方式:
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree
内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,不止net支持的方式,必须还是由非托管方来释放!
2、不需再转换,直接使用IntPtr:
Bitmap bmp=Image.FromHbitmap(ptr);
先简明扼要说说:C、C++、COM如何分配内存,直接影响net这边的释放!
非托管代码三种内存分配、释放方式:
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree
内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,不止net支持的方式,必须还是由非托管方来释放!
2、不需再转换,直接使用IntPtr:
Bitmap bmp=Image.FromHbitmap(ptr);
#15
真是太感谢你了!!!
#16
你是CSDN最热心的人!!
#17
v_trim_information.p_trim_image = (HBITMAP *)GlobalAlloc(GPTR, sizeof(HBITMAP) * v_trim_information.p_trim_count);
我看C++ 这边是这么分配内存的,需要释放么?
我看C++ 这边是这么分配内存的,需要释放么?
#18
IntPtr.Zero
#19
成对使用,必须用非托管代码释放:GlobalFree(ptr),也就是:你要做C++和C#两边都封装一个相应的释放函数!
#20
非常感谢你!!
#21
这个帖子再放几个小时再结贴,让大家学学!
学习技术的同时,也学学助人为乐的精神。
学习技术的同时,也学学助人为乐的精神。
#22
Import[dll]
#1
这样转换:
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct TRIMINFORMATION{
public int p_trim_count;
public IntPtr p_trim_areas;
public IntPtr p_trim_image;
}
[ DllImport( "xxx.dll" ,CharSet = CharSet.Ansi)]
public static extern int TrimImage(IntPtr v_hbitmap,IntPtr v_color_palette,ref TRIMINFORMATION v_trim_information);
#2
要传这个 LPRECT 类型的数组应该怎么传阿?
#3
我以为这么简单的问题只有我不会呢!!!!!!
#4
不明白你这个api是干什么的. 不过介绍c# 关于api的资料的确很少
vb尼玛超级多 不公平 啊 不公平
vb尼玛超级多 不公平 啊 不公平
#5
这是我们用C++自己写的一个API,我就想知道怎么在C#中调用!!
#6
这是我们自己用C++写的API,我就想知道怎么在C#中调用!!!
#7
这个API是我们自己用C++写的。我现在想知道怎么在C#中调用它!
#8
楼主,这个问题,看似简单,其实复杂!NET提供的互操作技术远比想象中复杂和晦涩!有时一个小问题,你可能几天都搞不定!
花了近两个时,并测试了,给你完整的例子:
C++部分:
C#部分:
你自己可以拿我的源码测试,看看是不是得到正确结果。。。
花了近两个时,并测试了,给你完整的例子:
C++部分:
struct TrimInfo
{
int count; //数组成员个数
LPRECT pTrim; //这里是RECT数组
};
extern "C" void __declspec(dllexport) TestTrim(TrimInfo* pInfo);
C#部分:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct TrimInfo
{
public int count;
public IntPtr pTrim;
};
[DllImport(@"E:\pvcs\utscada\Debug\ExamDll.dll", EntryPoint = "TestTrim")]
public static extern bool TestTrim(ref TrimInfo info);
private void Form1_Load(object sender, EventArgs e)
{
RECT[] rcArr = new RECT[2];
for(int i=0;i<rcArr.Length;i++)
{
rcArr[i].left = i + 1;
rcArr[i].top = i + 1;
rcArr[i].right = i + 1;
rcArr[i].bottom = i + 1;
}
ptr=MashalStructArrayToPtr<RECT>(rcArr);
TrimInfo info=new TrimInfo();
info.count=2;
info.pTrim=ptr;
TestTrim(ref info);
}
public static IntPtr MashalStructArrayToPtr<T>(T[] StructArray)
{
List<byte[]> byteArrayList = new List<byte[]>();
// T[] ArrayA = new T[StructArray.Length];
for (int i = 0; i < StructArray.Length; i++)
{
byte[] buf = StructToBytes(StructArray[i]);
byteArrayList.Add(buf);
}
int totalLength = 0;
// 获取在内存存放的总长度
for (int i = 0; i < byteArrayList.Count; i++)
{
totalLength += byteArrayList[i].Length;
}
// 开辟一个Byte 数组
byte[] allBuffuer = new byte[totalLength];
int startIndex = 0;
// 然后依次把byteArrayList的数据拷贝到allBuffuer
for (int i = 0; i < byteArrayList.Count; i++)
{
byteArrayList[i].CopyTo(allBuffuer, startIndex);
startIndex = startIndex + byteArrayList[i].Length;
}
//指针所需的内存空间
IntPtr BufferPtr = Marshal.AllocCoTaskMem(totalLength);
//把C#结构体数组拷贝至这个指针
Marshal.Copy(allBuffuer, 0, BufferPtr, totalLength);
return BufferPtr;
}
public static Byte[] StructToBytes(Object structure)
{
Int32 size = Marshal.SizeOf(structure);
IntPtr buffer = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structure, buffer, false);
Byte[] bytes = new Byte[size];
Marshal.Copy(buffer, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(buffer);
}
}
你自己可以拿我的源码测试,看看是不是得到正确结果。。。
#9
还有一种简单的办法:参数分解!这需要开发者在C++那边做技术处理,也就要求具备一定的C/C++的开发能力!
C++:
C#:
这种技术:就是通常所说的结构体“扁平化”,是参数传递变得简单。
C++:
extern "C" void __declspec(dllexport) TestTrim2(LPRECT pTrim,int count);
void TestTrim2(LPRECT pTrim,int count)
{
TrimInfo info;
info.count=count;
info.pTrim=pTrim;
TestTrim(&info);
}
C#:
[DllImport(@"E:\pvcs\utscada\Debug\ExamDll.dll", EntryPoint = "TestTrim2")]
public static extern void TestTrim2([In, Out]RECT[] rcArr, int count);
private void Form1_Load(object sender, EventArgs e)
{
RECT[] rcArr = new RECT[2];
for(int i=0;i<rcArr.Length;i++)
{
rcArr[i].left = i + 1;
rcArr[i].top = i + 1;
rcArr[i].right = i + 1;
rcArr[i].bottom = i + 1;
}
TestTrim2(rcArr, rcArr.Length); //换成的新的接口
}
这种技术:就是通常所说的结构体“扁平化”,是参数传递变得简单。
#10
非常感谢你,我试试嫩故不能达到我的要求,
而且我还有一个问题。函数运行完,这个结构的*p_trim_image指向返回的一个HBITMAP数组,应该怎么使用呢?
typedef struct tagTrimInformation
{
int p_trim_count;
LPRECT p_trim_areas;
HBITMAP *p_trim_image;
} TRIMINFORMATION;
#11
这个结构体:
这个: public IntPtr p_trim_image;中的p_trim_image,对应的是IntPtr数组。
得到返回值后,根据我给你的方法,反过来处理:
强调一下:如果你复杂的结构体和函数不好调通,你先自己写个简单些的结构体和函数调试。
你把调通了,就打通了一条路!对平台调用、互操作技术有直观的认识。然后逐步搞复杂的,
就会能较快定位问题。
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public struct TRIMINFORMATION{
public int p_trim_count;
public IntPtr p_trim_areas;
public IntPtr p_trim_image;
}
这个: public IntPtr p_trim_image;中的p_trim_image,对应的是IntPtr数组。
得到返回值后,根据我给你的方法,反过来处理:
IntPtr[] ptrArr=new IntPtr[p_trim_count];//个数与结构体的保持一致
Marshal.Copy(p_trim_image,ptrArr,0,p_trim_count);
foreach(IntPtr ptr in ptrArr)
{
//这里处理每一个ptr
}
强调一下:如果你复杂的结构体和函数不好调通,你先自己写个简单些的结构体和函数调试。
你把调通了,就打通了一条路!对平台调用、互操作技术有直观的认识。然后逐步搞复杂的,
就会能较快定位问题。
#12
public string 参数名(string 参数)
{
//语句
}
{
//语句
}
#13
我对互操作没接触过,一窍不通。我还有两个小问题。
1.非托管DLL分配的空间是否学要C#释放?怎么释放?
2.怎么把IntPtr强制转换成BitMap?
真的非常非常感谢你的回答,连我的同事都说你这人真好。呵呵
#14
1、这个问题涉及到较多方面,要叙述清楚,非一两句能说清楚的。
先简明扼要说说:C、C++、COM如何分配内存,直接影响net这边的释放!
非托管代码三种内存分配、释放方式:
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree
内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,不止net支持的方式,必须还是由非托管方来释放!
2、不需再转换,直接使用IntPtr:
Bitmap bmp=Image.FromHbitmap(ptr);
先简明扼要说说:C、C++、COM如何分配内存,直接影响net这边的释放!
非托管代码三种内存分配、释放方式:
malloc free
new delete
CoTaskMemAlloc CoTaskMemFree
内存分配、释放必须成对使用,否则也会造成内存泄露!net互操作默认是方式是CoTaskMemAlloc,其垃圾回收自动调用的是CoTaskMemFree,也就是说,如果非托管代码采用COM方式分配内存,可以不用显示释放内存,net帮你搞定!而其他两种,不止net支持的方式,必须还是由非托管方来释放!
2、不需再转换,直接使用IntPtr:
Bitmap bmp=Image.FromHbitmap(ptr);
#15
真是太感谢你了!!!
#16
你是CSDN最热心的人!!
#17
v_trim_information.p_trim_image = (HBITMAP *)GlobalAlloc(GPTR, sizeof(HBITMAP) * v_trim_information.p_trim_count);
我看C++ 这边是这么分配内存的,需要释放么?
我看C++ 这边是这么分配内存的,需要释放么?
#18
IntPtr.Zero
#19
成对使用,必须用非托管代码释放:GlobalFree(ptr),也就是:你要做C++和C#两边都封装一个相应的释放函数!
#20
非常感谢你!!
#21
这个帖子再放几个小时再结贴,让大家学学!
学习技术的同时,也学学助人为乐的精神。
学习技术的同时,也学学助人为乐的精神。
#22
Import[dll]