相关文章推荐
英姿勃勃的胡萝卜  ·  'import' ...·  1 年前    · 
打篮球的野马  ·  Go ...·  2 年前    · 
void __stdcall PrintString(char * hello)
 public




    
 static extern void PrintStringByBytes(byte[] hello);
 public static extern void PrintStringByMarshal([MarshalAs(UnmanagedType.LPStr)]string hello);
char * __stdcall GetStringReturn()
[DllImport("TestDll", EntryPoint = "GetStringReturn")]
public static extern IntPtr GetStringReturnByBytes();
[DllImport("TestDll", EntryPoint = "GetStringReturn")]
[return:MarshalAs(UnmanagedType.LPStr)]
public static extern string GetStringReturnByMarshal();
Console.WriteLine(Marshal.PtrToStringAnsi(GetStringReturnByBytes()));
封送字符串数组
C++
int TestArrayOfStrings(char* ppStrArray[], int size);
C#:
[ DllImport( "test.dll" )]
public static extern int TestArrayOfStrings( [In, Out]   String[] ppStrArray, int size );
String[] strArray = { "one", "two", "three", "four", "five" };
int lenSum = LibWrap.TestArrayOfStrings( strArray, strArray.Length );

结构体传送

按顺序字节方式即可:[StructLayout(LayoutKind.Sequential)]

struct Lable1 { BYTELabFilterChan0[4][256]; BYTELabFilterChan1[4][256]; C#: [StructLayout(LayoutKind.Sequential)] public structByteStru { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] public byte[]a; [StructLayout(LayoutKind.Sequential)] public structLabel1 { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] publicByteStru[] LabFilterChan0 ; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public ByteStru[] LabFilterChan1 ; typedef struct _MYPERSON{ char* first; //字符指针 } MYPERSON, *LP_MYPERSON; [ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )] public struct MyPerson { public String first; typedef struct _MYPERSON1{ char first[20]; //字符数组 } MYPERSON1, *LP_MYPERSON1; C#: [ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )] public struct MyPerson1 { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] public String first; typedef struct _MYARRAYSTRUCT{ bool flag; int vals[ 3 ]; //值类型数组 } MYARRAYSTRUCT; C#: public struct MyArrayStruct { public bool flag; [ MarshalAs( UnmanagedType.ByValArray, SizeConst=3 )] public int[] vals;
  • 结构体声明必须保证:字段声明顺序、字段类型、字段在内存中的大小原来的一致!结构体名称,其成员名称可以不同。
  • 结构体中,char*与 char[]在 C#声明区别很大,前者直接对应 string,后者(字符数组)很容易被初学者误用 char[]来对应,它还是要用 string 来对应,但还需要用[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]来指明该字段的封送行为。
  • 其他值类型的数组,直接用数组方式对应,但也需要用[ MarshalAs( UnmanagedType.ByValArray, SizeConst=3 )] 指明封送行为。
  • 有直接结构体对应的结构体指针,建议直接用 ref + 具体类型,而不采用 IntPtr,省去一些不必要的转换操作,
  • TestArrayInStruct、TestStructInStruct2、TestStructInStruct3 都是如此。

    结构体作为函数返回值

    C++
    MYPERSON* TestReturnStruct();
    void FreeStruct(MYPERSON* pStruct);
    C#:
    [ DllImport( "test.dll" ,CharSet = CharSet.Ansi)]
    public static extern IntPtr TestReturnStruct();         //注意对应的是IntPtr指针
    [ DllImport( "test.dll" ,CharSet = CharSet.Ansi)]
    public static extern void FreeStruct(IntPtr pStruct);
    IntPtr pStruct=TestReturnStruct();
    MYPERSON person=(MYPERSON)Marshal.PtrToStructure(pStruct,typeof(MYPERSON));
    

    //在非托管代码,大多用 new/malloc 分配内存,net 无法正确释放,
    //需要对应的调用释放内存的方法释放非托管内存

    FreeStruct(pStruct);
    

    结构体数组作为输入输出参数

    C++
    int TestArrayOfStructs2 (MYPERSON* pPersonArray, int size);
    [ DllImport( "test.dll" )]
    public static
    
    
    
    
        
     extern int TestArrayOfStructs2( [In, Out] MyPerson[] personArray, int size );
    MyPerson[] persons = { new MyPerson( "Kim", "Akers" ), new MyPerson( "Adam", "Barr" )};
    int namesSum = TestArrayOfStructs2( persons, persons.Length );
    
  • 一般我们数组作为输入输出参数,需要显式加上[In,Out]属性,标识为输入输入参数。如果不写,默认为 In 方向,CLR 将不会回传修改后的内存值
  • 结构体嵌套结构体

    C++
    typedef struct _MYPERSON2{
    	MYPERSON* person;
    	int age;
    } MYPERSON2, *LP_MYPERSON2;
    typedef struct _MYPERSON3{
    	MYPERSON person;
    	int age;
    } MYPERSON3;
    int TestStructInStruct(MYPERSON2* pPerson2);
    void TestStructInStruct3(MYPERSON3 person3);
    [ StructLayout( LayoutKind.Sequential )]
    public struct MyPerson2 {
    	public IntPtr person;
    	public int age;
    [ StructLayout( LayoutKind.Sequential )]
    public struct MyPerson3 {
    	public MyPerson person;
    	public int age;
    [ DllImport( "test.dll" )]
    public static extern int TestStructInStruct( ref MyPerson2 person2 );
    [ DllImport( "test.dll" )]
    public static extern int TestStructInStruct3( MyPerson3 person3 );
    MyPerson personName;
    personName.first = "Mark";
    personName.last = "Lee";
    MyPerson2 personAll;
    personAll.age = 30;
    IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( personName ));
    Marshal.StructureToPtr( personName, buffer, false );
    personAll.person = buffer;
    int res = TestStructInStruct( ref personAll );
    MyPerson personRes = (MyPerson)Marshal.PtrToStructure( personAll.person, typeof( MyPerson ));
    Marshal.FreeCoTaskMem( buffer );
    MyPerson3 person3 = new MyPerson3();
    person3.person.first = "John";
    person3.person.last = "Evens";
    person3.age = 27;
    TestStructInStruct3( person3 );
    
  • 结构体嵌套,如果是实体成员,直接用结构体类型对应,如上面的 MyPerson3;
  • 如果是指针变量,则用 IntPtr 对应,如上面的 MYPERSON2;
  • 如果嵌套的是结构体数组,那么,出来办法以值类型数组方式对应,如 MYARRAYSTRUCT,只不过,类型为具体的结构体类型。这里不另外在举例。(还是给个例子)
  • C++
    typedef struct Student  {
    	char name[20];
    	int age;
    	double scores[32];
    }Student;
    typedef struct Class  {
    	int number;
    	Student students[126];
    }Class;
    	[StructLayout(LayoutKind.Sequential)]
    	public struct Student
               [MarshalAs(UnmanagedType.ByValTStr,SizeConst=20)]
               public string name;
               public int age;
               [MarshalAs(UnmanagedType.ByValArray,SizeConst=32)]
               public double[] scores;
    	[StructLayout(LayoutKind.Sequential)]
    	struct Class
              public int number;
              [MarshalAs(UnmanagedType.ByValArray,SizeConst=126)]
              public Student[] students;
    int TestStructInStruct1(MYPERSON pPerson);
    int TestStructInStruct2(MYPERSON* pPerson);
    int TestStructInStruct3(MYPERSON1* pPerson);
    void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
    C#:
    [ DllImport( "test.dll" ,CharSet = CharSet.Ansi)]
    public static extern int TestStructInStruct( MyPerson person);
    [ DllImport( "test.dll" ,CharSet = CharSet.Ansi)]
    public static extern int TestStructInStruct1(ref  MyPerson person);
    [ DllImport( "test.dll" ,CharSet = CharSet.Ansi)]
    public static extern int TestStructInStruct2(ref  MyPerson1 person);
    [ DllImport( "test.dll" ,CharSet = CharSet.Ansi)]
    public static extern int TestArrayInStruct(ref MYARRAYSTRUCT person);
    

    函数调用标准

        // Summary:
        //     Specifies the calling convention required to call methods implemented in
        //     unmanaged code.
        [Serializable]
        [ComVisible(true)]
        public enum CallingConvention
            // Summary:
            //     This member is not actually a calling convention, but instead uses the default
            //     platform calling convention. For example, on Windows the default is System.Runtime.InteropServices.CallingConvention.StdCall
            //     and on Windows CE.NET it is System.Runtime.InteropServices.CallingConvention.Cdecl.
            Winapi = 1,
            // Summary:
            //     The caller cleans the stack. This enables calling functions with varargs,
            //     which makes it appropriate to use for methods that accept a variable number
            //     of parameters, such as Printf.
            Cdecl = 2,
            // Summary:
            //     The callee cleans the stack. This is the default convention for calling unmanaged
            //     functions with platform invoke.
            StdCall = 3,
            // Summary:
            //     The first parameter is the this pointer and is stored in register ECX. Other
            //     parameters are pushed on the stack. This calling convention is used to call
            //     methods on classes exported from an unmanaged DLL.
            ThisCall = 4,
            // Summary:
            //     This calling convention is not supported.
            FastCall = 5,