受欢迎的博客标签

C#调用C++编写的DLL函数各种参数传递问题

Published

1. 不返回值的参数

C++ 原型: bool SendNewSms(char *szTel, char *szMessage);

C#引用;

[DllImport( "CdmaCard.dll",EntryPoint="SendNewSms")]
public static extern bool SendNewSms(string phone,string msg);

2. 带返回值(char *)

 

C++原型:

BOOL GetCardErrorMessage(char *szErrorMessage , int errorCode);
 
C#引用
[DllImport( "CdmaCard.dll",EntryPoint="GetCardErrorMessage")]
public static extern int GetCardErrorMessage(StringBuilder msg,int errorCode);
StringBuilder buf = new StringBuilder(1024);//指定的Buf大小必须大于可能的最大长度
GetCardErrorMessage(buf,1);

3. 带返回值(其他类型)

 

C++原型:

 

   BOOL GetSmsSaveStation (int *nSmsStation);
 

C#引用

 

 

  1.  
    [DllImport( "CdmaCard.dll",EntryPoint="GetSmsSaveStation")]
  2.  
    public static extern bool GetSmsSaveStation(ref int nStation);
 

4. 传递结构体指针(C++填充)

C++原型:

C++中结构体定义

typedef struct // 平面
{
  double time; 
  float normal[3];
  float center[3]; 
} plane;

C++中方法声明:

public void GetPlanes(plane *planes, int size);
C#引用
C#中结构体声明:
[StructLayout(LayoutKind.Sequential)]
public struct GPlane
{
  public double timestamp;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
  public float[] normal;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
  public float[] center;
}
​

C#中方法声明:
[DllImport(LibFileName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern bool Pvr_getAirGlassPlanes([In, Out]GPlane[] plane, int size);
​
C#中调用该方法:
int size = 2;
GPlane[] plane = new GPlane[size];
Pvr_getAirGlassPlanes(plane, size);​
 
 
5. 传递结构体数组(C++来填充)
C++原型:
  1.  
    struct UIM_BOOK_STRUCT
  2.  
    {
  3.  
    int UimIndex;
  4.  
    char szName[15];
  5.  
    char szPhone[21];
  6.  
    };
  7.  
    int ReadUimAllBook(UIM_BOOK_STRUCT lpUimBookItem[],int nMaxArraySize);
 

C#引用
  1.  
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]//可以指定编码类型
  2.  
    public struct UIM_BOOK_STRUCT
  3.  
    {
  4.  
    public int UimIndex;
  5.  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst= 15)]
  6.  
    public string szName;
  7.  
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst= 21)]
  8.  
    public string szPhone;
  9.  
    };
  10.  
    [DllImport( "CdmaCard.dll",EntryPoint="ReadUimAllBook")]
  11.  
    public static extern int ReadUimAllBook([Out] UIM_BOOK_STRUCT [] lpUimBookItem,int nMaxArraySize);
  12.  
    UIM_BOOK_STRUCT[] p = new UIM_BOOK_STRUCT[20];
  13.  
    int ret = ReadUimAllBook(p,p.Length);
 
6. 注意问题

 

类型不一致,会导致调用失败,
(1) long 类型,在C++中是4字节的整数,在C#中是8字节的整数;
(2) 字符串类型的设置不正确;

 

以下是几个简单的window调用

 

  1.  
    [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
  2.  
    [DllImport("User32.dll", CharSet=CharSet.Auto)]
  3.  
    public static extern bool ScreenToClient(IntPtr hWnd, ref System.Drawing.Point rect);
  4.  
     
  5.  
    [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
  6.  
    [DllImport("User32.dll", CharSet=CharSet.Auto)]
  7.  
    public static extern bool GetWindowRect(IntPtr hWnd, out System.Drawing.Rectangle rect);
  8.  
     
  9.  
    [System.Security.SuppressUnmanagedCodeSecurity] // We won't use this maliciously
  10.  
    [DllImport("User32.dll", CharSet=CharSet.Auto)]
  11.  
    public static extern bool UnregisterClass([MarshalAs(UnmanagedType.LPTStr)] string className, IntPtr instanceHandle);
     
     
     

 

C#调用C++DLL类库中的类的方法

1. 方式1

C#调用C++DLL类库中的类的方法

vs c++ 将一个class写成DLL,导出整个类

2. 方式2

The only way to directly call methods on a C++ object from C# (and most other languages) is to create a full-fledged COM object out of it.

An easier way with a level of indirection: Develop an API of purely static methods that reflect the object's operations. Then you can call that from .NET easily.

C++

MyClass* WINAPI CreateMyClass() { return new MyClass(); }
void WINAPI CallFoo(MyClass* o) { o->foo(); }

C#

[DllImport("MyDLL")]
private static IntPtr CreateMyClass();

[DllImport("MyDLL")]
private static void CallFoo(IntPtr o);