c# 如何调用非托管函数2-传递结构和类

原文: 刘武|c# 如何调用非托管函数2-传递结构和类  

在上一篇 c# 如何调用非托管函数 中介绍了调用非托管函数的简单方法,其中传递的都是简单的值类型,如uint等。本篇将介绍如何传递结构或类到非托管函数。

以系统函数 GetSystemTime 为例,以下分别演示了如何传递结构和类。

一 传递结构 

参考MSDN可以知道他的定义为:

void WINAPI GetSystemTime(__out LPSYSTEMTIME lpSystemTime);

其中LPSYSTEMTIME 就是一个结构体:

typedef struct _SYSTEMTIME {
  WORD wYear;
  WORD wMonth;
  WORD wDayOfWeek;
  WORD wDay;
  WORD wHour;
  WORD wMinute;
  WORD wSecond;
  WORD wMilliseconds;
} SYSTEMTIME,
 *PSYSTEMTIME;

根据原始定义我们可以把它转成C#的形式(word类型相当于c#中的ushort)

[StructLayout(LayoutKind.Sequential)]
public struct SystemTime
{
    public ushort wYear;
    public ushort wMonth;
    public ushort wDayOfWeek;
    public ushort wDay;
    public ushort wHour;
    public ushort wMinute;
    public ushort wSecond;
    public ushort wMilliseconds;
}

由于该结构是作为out参数传递的,因此在c#中我们必须通过引用来传递:

[DllImport("Kernel32.dll")]
public static extern void GetSystemTime(ref SystemTime st);

以下是完整代码:

public class Kernel32
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SystemTime
    {
        public ushort wYear;
        public ushort wMonth;
        public ushort wDayOfWeek;
        public ushort wDay;
        public ushort wHour;
        public ushort wMinute;
        public ushort wSecond;
        public ushort wMilliseconds;
    }


    [DllImport("Kernel32.dll")]
    public static extern void GetSystemTime(ref SystemTime st);
}

调用起来也比较简单:

private void btnGetSysTime_Click(object sender, EventArgs e)
{
    Kernel32.SystemTime sysTime = new Kernel32.SystemTime();
    Kernel32.GetSystemTime(ref sysTime);


    MessageBox.Show(string.Format("{0}-{1}-{2} {3}:{4}:{5}",
        sysTime.wYear,
        sysTime.wMonth,
        sysTime.wDay,
        sysTime.wHour,
        sysTime.wMinute,
        sysTime.wSecond));
}

二 传递类

对于以上的例子,我们也可以把结构改成类传递给非托管函数,因为类是引用类型,所以我们不再需要ref声明:

public class Kernel32
{
    [StructLayout(LayoutKind.Sequential)]
    public class SystemTime
    {
        public ushort wYear;
        public ushort wMonth;
        public ushort wDayOfWeek;
        public ushort wDay;
        public ushort wHour;
        public ushort wMinute;
        public ushort wSecond;
        public ushort wMilliseconds;
    }


    [DllImport("Kernel32.dll")]
    public static extern void GetSystemTime(SystemTime st);
}

注意这里只是一个特例,并不是所有的情况既可以定义成结构类型也可以定义成类类型,通常我们应遵循以下原则:

  • 在非托管函数不要求任何间接寻址时使用按值传递的结构。
  • 在非托管函数要求一级间接寻址时使用按引用传递或按类传递的结构。
  • 在非托管函数要求二级间接寻址时使用按引用传递的类。

参考:

你可能感兴趣的:(C#)