C中void指针类型转换到C#的问题.

jeffreyhu1990 2012-04-07 10:27:57
我用C#调用C编译的dll中有这样一个函数,函数大概的功能就是把数据保存到buf缓冲区中:
int retrieve(int scanno,void* buf);

在C中是通过先定义一个结构体再调用这个函数的:

#define COUNT_DIMENSION_MAX 256
typedef struct tagVECTOR_st {
int dimension;
double vector[COUNT_DIMENSION_MAX];
} VECTOR_st;
struct tagSample_st {
int ID;
VECTOR_st Vec; //
} rec;
retrieveall(scanno,&rec);

请问各位大牛,这个retrieve函数的参数void* buf在C#中应该转换成什么?C#中并不能定义void*,我查找过一些资料,貌似说是转换成IntPtr,

public static extern int retrieveall(int scanno, IntPtr buf);

但是在C#中调用的时候应该传递什么样的参数给buf呢?C#中又不能写成&rec这种形式。希望大家帮忙解答!谢谢各位!
...全文
1157 10 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
WAN 2012-04-08
  • 打赏
  • 举报
回复
以tagSample_st为例:
    public partial class LibWrap
{
const int COUNT_DIMENSION_MAX = 256;

[StructLayout(LayoutKind.Sequential)]
public struct tagVECTOR_st
{
int dimension;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = COUNT_DIMENSION_MAX)]
double[] vector;
}

[StructLayout(LayoutKind.Sequential)]
public struct tagSample_st
{
int ID;
tagVECTOR_st Vec;
}

[DllImport("MyDll.dll")]
public static extern int retrieveall(int scanno, IntPtr buf);
}

LibWrap.tagSample_st rec = new LibWrap.tagSample_st();
int cb = Marshal.SizeOf(typeof(LibWrap.tagSample_st));
IntPtr ptr = Marshal.AllocCoTaskMem(cb);
//Marshal.StructureToPtr(rec, ptr, true);

int iResult = LibWrap.retrieveall(0, ptr);

Marshal.PtrToStructure(ptr, rec);
Marshal.FreeCoTaskMem(ptr);


其实如果不同的表,对应不同的字段,定义不同的结构,也可以利用函数重载,使用ref
mingcsharp 2012-04-07
  • 打赏
  • 举报
回复
struct tagSample_st {
int ID;
VECTOR_st Vec; //
} rec;
这不是个结构吗,你用类来写,试试传引用
WAN 2012-04-07
  • 打赏
  • 举报
回复
用IntPtr也是可以的,但这样需要自行申请和释放非托管内存
建议的方法是定义为ref tagSample_st buffer,即使用引用传递tagSample_st结构,这相当于向C传递该tagSample_st结构的指针
threenewbee 2012-04-07
  • 打赏
  • 举报
回复
传结构体嘛。

EnForGrass 2012-04-07
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

引用 3 楼 的回复:

C和C++中的结构要转换到C#中,要在C#中重新定义这个C或者C++的结构,后通过指针转换到结构。

我知道要在C#中重新定义结构了,关键在于我不知道int retrieve(int scanno,void* buf)这个函数在C#中怎么声明,因为C#没办法把函数的参数声明成void* buf
[/Quote]
是应该用void*C#对应的就是IntPtr啊
jeffreyhu1990 2012-04-07
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

用IntPtr也是可以的,但这样需要自行申请和释放非托管内存
建议的方法是定义为ref tagSample_st buffer,即使用引用传递tagSample_st结构,这相当于向C传递该tagSample_st结构的指针
[/Quote]
由于这个函数int retrieve(int scanno,void* buf)是用于读取数据库中某一个表中某条记录的所有字段,而数据库中不同表拥有的字段也是不同的(那个struct结构体就是用来定义一个表中的每个字段的),所以并不能将参数声明成统一的结构体,只能声明成一个指针。
那么如果只能用IntPtr的话,如何自行申请和释放非托管内存?
jeffreyhu1990 2012-04-07
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

C和C++中的结构要转换到C#中,要在C#中重新定义这个C或者C++的结构,后通过指针转换到结构。
[/Quote]
我知道要在C#中重新定义结构了,关键在于我不知道int retrieve(int scanno,void* buf)这个函数在C#中怎么声明,因为C#没办法把函数的参数声明成void* buf
fubo880 2012-04-07
  • 打赏
  • 举报
回复
C和C++中的结构要转换到C#中,要在C#中重新定义这个C或者C++的结构,后通过指针转换到结构。
EnForGrass 2012-04-07
  • 打赏
  • 举报
回复
[Quote=引用楼主 的回复:]
我用C#调用C编译的dll中有这样一个函数,函数大概的功能就是把数据保存到buf缓冲区中:
C/C++ code
int retrieve(int scanno,void* buf);

在C中是通过先定义一个结构体再调用这个函数的:
C/C++ code

#define COUNT_DIMENSION_MAX 256
typedef struct tagVECTOR_s……
[/Quote]
C#中的IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。
资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针(因此也可以包含资源的名称)。
举个例子
[DllImport("winmm.dll")]
private static extern long mciSendString(string a,string b,uint c,IntPtr d);

然后用这样的方法调用:
mciSendString("set cdaudio door open", null, 0, this.Handle);

您也可以使用IntPtr.Zero将句柄设置为0;
或者使用类型强制转换:
mciSendString("set cdaudio door open", null, 0, (IntPtr)0 );

或者,使用IntPtr构造函数:
IntPtr a = new IntPtr(2121);
sam190 2012-04-07
  • 打赏
  • 举报
回复
如果是.net4可以使用dynamic 类型再转换

111,098

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧