我需要从一个dll中包含的C api调用一个函数。函数原型如下所示....
int func( char* name, void* value );
其中指针值的内容可以引用依赖于传递名称的任何类型。我不确定如何设置Dll inport来正确地编组这个空洞*。我一直在尝试使用IntPtr,这似乎适用于值为int但我无法正确检索浮点数等值。
我正在尝试导入这样的函数......
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func( string name, ref IntPtr value );
请注意,值是输出。指向任何类型的值的指针,即已知类型的值的全局存储器区域中的地址(调用者已知)。在c prog中,调用者将被期望将此void *转换为所需类型并取消引用以获得存储在那里的实际值。到目前为止给出的答案似乎是基于一个假设,即函数会将结果写入传入的指针位置。我的错误,因为我没有太具体。抱歉。 C#不是我的包,我甚至都不知道IntPtr是否可以去这里......
答案 0 :(得分:10)
解决这个问题的最好方法是提供函数的重载,这样C#端的所有内容都是干净利落的。像这样:
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func(string name, out int value);
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func(string name, out float value);
// etc, one each for each type
答案 1 :(得分:2)
您不需要ref
- IntPtr
是将void*
传递给本机代码的方法。
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func( string name, IntPtr value );
编辑:
C代码可以使用输入写入所需的内存。您面临的问题是托管代码知道为每种可能的返回值类型分配多少内存。然后,可以使用Marshal.AllocHGlobal
或Marshal.AllocCoTaskMem
分配适当大小的块,一旦托管代码完成,释放(根据您使用的分配方法)通过FreeHGlobal
或FreeCoTaskMem
使用与输出值。
请参阅@Alex Farber的答案。
答案 2 :(得分:2)
[DllImport("dllname.dll", CharSet = CharSet.Ansi)] public static extern int func( string name, IntPtr value ); ... // n - number of bytes which is enough to keep any type used by function IntPtr ptr = Marshal.AllocHGlobal(n); func(name, ptr); // Use Marshal.ReadByte, Marshal.ReadInt32 ... or Marshal.Copy // to copy from ptr filled by func to managed variable. For example: byte b = Marshal.ReadByte(ptr); Marshal.FreeHGlobal(IntPtr);
答案 3 :(得分:0)
有时,使用这种方法可能更容易。
声明:
[DllImport("dllname.dll", CharSet = CharSet.Ansi)]
public static extern int func([MarshalAs(UnmanagedType.LPTStr)] string name, [MarshalAs(UnmanagedType.AsAny)] object value);
传递值的示例用法:
func("some string", (int)12);
func("some string", (double)12);
传递字符串的示例用法:
func("some string", "test");
传递变量的示例用法:
int value = 12;
func("some string", value);