当前位置:编程学习 > C#/ASP.NET >>

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

我用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这种形式。希望大家帮忙解答!谢谢各位! --------------------编程问答-------------------- 如果是.net4可以使用dynamic 类型再转换 --------------------编程问答--------------------
引用楼主  的回复:
我用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……

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);  --------------------编程问答-------------------- C和C++中的结构要转换到C#中,要在C#中重新定义这个C或者C++的结构,后通过指针转换到结构。 --------------------编程问答--------------------
引用 3 楼  的回复:
C和C++中的结构要转换到C#中,要在C#中重新定义这个C或者C++的结构,后通过指针转换到结构。

我知道要在C#中重新定义结构了,关键在于我不知道int retrieve(int scanno,void* buf)这个函数在C#中怎么声明,因为C#没办法把函数的参数声明成void* buf --------------------编程问答--------------------
引用 4 楼  的回复:
引用 3 楼  的回复:

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

我知道要在C#中重新定义结构了,关键在于我不知道int retrieve(int scanno,void* buf)这个函数在C#中怎么声明,因为C#没办法把函数的参数声明成void* buf

是应该用void*C#对应的就是IntPtr啊 --------------------编程问答-------------------- 传结构体嘛。

--------------------编程问答-------------------- 用IntPtr也是可以的,但这样需要自行申请和释放非托管内存
建议的方法是定义为ref tagSample_st buffer,即使用引用传递tagSample_st结构,这相当于向C传递该tagSample_st结构的指针 --------------------编程问答-------------------- struct tagSample_st {
    int        ID;
    VECTOR_st    Vec;    //
} rec;
这不是个结构吗,你用类来写,试试传引用 --------------------编程问答--------------------
引用 7 楼  的回复:
用IntPtr也是可以的,但这样需要自行申请和释放非托管内存
建议的方法是定义为ref tagSample_st buffer,即使用引用传递tagSample_st结构,这相当于向C传递该tagSample_st结构的指针

由于这个函数int retrieve(int scanno,void* buf)是用于读取数据库中某一个表中某条记录的所有字段,而数据库中不同表拥有的字段也是不同的(那个struct结构体就是用来定义一个表中的每个字段的),所以并不能将参数声明成统一的结构体,只能声明成一个指针。
那么如果只能用IntPtr的话,如何自行申请和释放非托管内存? --------------------编程问答-------------------- 以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
补充:.NET技术 ,  C#
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,