PInvoke的DLL在C# [英] PInvoke DLL in C#
问题描述
我想传递给C函数的结构和我写了下面的code。
当我运行它,第一个功能 - Foo1
工作,然后功能富
得到一个例外。你能帮我了解的问题是什么?...
在C code:
typedef结构
{
INT大小;
//字符*阵;
} TTEST;__declspec(dllexport)的无效美孚(无效*测试);
__declspec(dllexport)的INT Foo1();无效美孚(void *的测试)
{
TTEST * X =(t检验*)测试;
INT I = X-GT&;尺寸;
/ *的for(int i = 0; I<&测试 - GT;尺寸;试验++)
{
试验 - >数组[我] = 127;
} * /
}INT Foo1()
{
返回10;
}
在C#code:
使用系统;
使用System.Runtime.InteropServices;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;命名空间的ConsoleApplication1
{
[StructLayout(LayoutKind.Sequential)]
公共类TTEST
{
公众诠释大小;
} 类节目
{
函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto)
公共静态外部无效美孚(
[的MarshalAs(UnmanagedType.LPStruct)
TTEST lplf //特点
); 函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto)
公共静态外部INT Foo1(); 静态无效的主要(字串[] args)
{
TTEST测试=新TTEST();
Test.Size = 25; INT XX = Program.Foo1();
Program.Foo(试验);
}
}
}
应用于downvoters :这个答案解决了两个问题:调用约定的直接的问题/的 MarhsalAs
属性,他很快就会发现在那里,如果他需要我的转弯建议他的 t检验
参数将无法工作的问题 TTEST
成一个结构。
您本地code是要求一个无效*
,这在C#是的IntPtr
。首先,你应该定义 t检验
为结构而不是类。其次,你应该富
的声明更改为:
函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto,CallingConvention = CallingConvention.Cdecl)
公共静态外部无效美孚(IntPtr的lplf);
第三,你应该钉住 t检验
使用固定
关键字并通过它的指针富
。如果您使用的是类,你可以使用 Marhsal.StructureToPtr
来获得的IntPtr
从 TTEST
。
这提供了两侧,其中一个指向任何类型中可以通过相同的功能,还可以编写过载与您要使用,因为它们都等同于虚空中的所有类类型*
关于本机端。有了一个结构,你的参数会以 REF ppended $ P $
。
我很好奇的是什么,为什么你的本地code想要一个无效*
,而不是 t检验*
当你在非托管code做的第一件事被转换为 t检验*
。如果您切换参数为 t检验*
,然后提供相同的功能变得更简单。你的声明将成为:
函数[DllImport(@C:\\网络课程\\ unmanaged1 \\ unmanaged3 \\调试\\ unmanaged3.dll,字符集= CharSet.Auto,CallingConvention = CallingConvention.Cdecl)
公共静态外部无效美孚(参考TTEST lplf);
和你会调用该函数为 Program.Foo(参考测试);
如果您使用的类,在 REF
不是必要的,因为类是引用类型。
I want to pass a structure to C function and I write the following code.
When I run it, the first function - Foo1
is working and then function Foo
gets an exception. Can you help me to understand what the problem is?...
The C code:
typedef struct
{
int Size;
//char *Array;
}TTest;
__declspec(dllexport) void Foo(void *Test);
__declspec(dllexport) int Foo1();
void Foo(void *Test)
{
TTest *X = (TTest *)Test;
int i = X->Size;
/*for(int i=0;i<Test->Size;Test++)
{
Test->Array[i] = 127;
}*/
}
int Foo1()
{
return 10;
}
The C# code:
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
[StructLayout(LayoutKind.Sequential)]
public class TTest
{
public int Size;
}
class Program
{
[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
public static extern void Foo(
[MarshalAs(UnmanagedType.LPStruct)]
TTest lplf // characteristics
);
[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto)]
public static extern int Foo1();
static void Main(string[] args)
{
TTest Test = new TTest();
Test.Size = 25;
int XX = Program.Foo1();
Program.Foo(Test);
}
}
}
To the downvoters: This answer solves two issues: the immediate issue of the calling convention/the MarhsalAs
attribute, and the issue he will soon find where his TTest
parameter won't work if he takes my suggestion of turning TTest
into a struct.
Your native code is asking for a void*
, which in C# is an IntPtr
. First you should define TTest
as a struct and not a class. Second, you should change the declaration of Foo
to:
[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void Foo(IntPtr lplf);
And third, you should pin the TTest
using the fixed
keyword and pass it's pointer to Foo
. If you're using a class, you can use Marhsal.StructureToPtr
to get an IntPtr
from your TTest
.
This provides the same functionality on both sides, where a pointer to any type can be passed in. You can also write overloads with all the class types that you want to use since they all equate to void*
on the native side. With a struct, your parameters would be prepended with a ref
.
What I'm curious about is why your native code wants a void*
instead of a TTest*
when the first thing you do in the unmanaged code is cast to a TTest*
. If you switched the parameter to a TTest*
, then providing identical functionality becomes simpler. You declaration would become:
[DllImport(@"C:\.net course\unmanaged1\unmanaged3\Debug\unmanaged3.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern void Foo(ref TTest lplf);
And you would call the function as Program.Foo(ref Test);
If you're using the class, the ref
isn't necessary as classes are reference types.
这篇关于PInvoke的DLL在C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!