该示例说明如何将两种对象作为参数传递给需要具有嵌入字符缓冲区的结构的非托管函数,一种对象是通过值传递的格式化类,一种对象是通过引用传递的结构。
OSInfo 示例使用以下非托管函数(这里同时显示其原始函数声明):
从 Kernel32.dll 导出的 GetVersionEx。
// BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo);
// BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo);
传递到该函数的初始结构包含以下元素:
typedef struct _OSVERSIONINFO
{
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
TCHAR szCSDVersion[ 128 ];
} OSVERSIONINFO;
typedef struct _OSVERSIONINFO
{
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
TCHAR szCSDVersion[ 128 ];
} OSVERSIONINFO;
在该示例中,当传递给非托管函数时,OSVersionInfo 类和 OSVersionInfo2 结构将产生相同的结果。MarshalAsAttribute 属性将 UnmanagedType 枚举值设置为 ByValTStr,后者用于标识在非托管结构中出现的内联的、固定长度的字符数组。
LibWrap 类包含两个原型:GetVersionEx 将该类作为参数传递,GetVersionEx2 将结构作为参数传递。通过显式应用 InAttribute 和 OutAttribute 属性,该示例确保将 OSVersionInfo 作为 In/Out 参数进行封送处理并且调用方可以查看封送回的更改。(为了提高性能,类的默认方向属性为 In,以防止调用方查看封送回的更改。)
通常通过值传递的 OSVersionInfo2 结构使用 ref(在 Visual Basic 中为 ByRef)关键字声明并通过引用传递。Marshal.SizeOf 方法确定非托管结构的大小(以字节为单位)。
下面的代码示例的源代码由 .NET Framework 平台调用技术示例提供。
声明原型
[ StructLayout( LayoutKind.Sequential )]
public class OSVersionInfo
{
public int OSVersionInfoSize;
…
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String versionString;
}
[ StructLayout( LayoutKind.Sequential )]
public struct OSVersionInfo2
{
public int OSVersionInfoSize;
…
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String versionString;
}
public class LibWrap
{
[ DllImport( "kernel32" )]
public static extern bool GetVersionEx( [In, Out] OSVersionInfo osvi );
[ DllImport( "kernel32", EntryPoint="GetVersionEx" )]
public static extern bool GetVersionEx2( ref OSVersionInfo2 osvi );
}
[ StructLayout( LayoutKind.Sequential )]
public class OSVersionInfo
{
public int OSVersionInfoSize;
…
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String versionString;
}
[ StructLayout( LayoutKind.Sequential )]
public struct OSVersionInfo2
{
public int OSVersionInfoSize;
…
[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String versionString;
}
public class LibWrap
{
[ DllImport( "kernel32" )]
public static extern bool GetVersionEx( [In, Out] OSVersionInfo osvi );
[ DllImport( "kernel32", EntryPoint="GetVersionEx" )]
public static extern bool GetVersionEx2( ref OSVersionInfo2 osvi );
}
调用函数
public class App
{
public static void Main()
{
Console.WriteLine( "\nPassing OSVersionInfo as class" );
OSVersionInfo osvi = new OSVersionInfo();
osvi.OSVersionInfoSize = Marshal.SizeOf( osvi );
LibWrap.GetVersionEx( osvi );
Console.WriteLine( "Class size: {0}", osvi.OSVersionInfoSize );
…
Console.WriteLine( "\nPassing OSVersionInfo as struct" );
OSVersionInfo2 osvi2 = new OSVersionInfo2();
osvi2.OSVersionInfoSize = Marshal.SizeOf( osvi2 );
LibWrap.GetVersionEx2( ref osvi2 );
Console.WriteLine( "Struct size: {0}", osvi2.OSVersionInfoSize );
…
}
}