OSInfo 範例
這個範例示範如何以傳值方式傳遞格式化的類別或以傳址方式傳遞結構做為 Unmanaged 函式的參數,這個 Unmanaged 函式預期具有內嵌字元緩衝區的結構。
OSInfo 範例使用下列 Unmanaged 函式,顯示其原始函式宣告:
從 Kernel32.dll 匯出 GetVersionEx。
// BOOL GetVersionEx(LPOSVERSIONINFO lpVersionInfo);
傳遞到函式的原始結構包含以下元素:
typedef struct _OSVERSIONINFO
{
DWORD dwOSVersionInfoSize;
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
DWORD dwPlatformId;
TCHAR szCSDVersion[ 128 ];
} OSVERSIONINFO;
在這個範例中,當傳遞至 Unmanaged 函式時,OSVersionInfo 類別和 OSVersionInfo2 結構會產生相同的結果。 MarshalAsAttribute 屬性會將 UnmanagedType 列舉值設定為 ByValTStr,用來識別出現在 Unmanaged 結構之中的內嵌、固定長度的字元陣列。
LibWrap 類別包含兩個原型:GetVersionEx 傳遞類別當成參數,而 GetVersionEx2 傳遞結構當成參數。 在這個範例中,藉由明確套用 InAttribute 和 OutAttribute 屬性,可以確保將 OSVersionInfo 封送處理為 In/Out 參數,而呼叫端可以查看封送處理回的變更 (由於效能因素,類別的預設方向屬性是 In,避免呼叫端查看封送處理回的變更)。
一般以傳值 (By Value) 方式傳遞的 OSVersionInfo2 結構,會用 ref (Visual Basic 中為 ByRef) 關鍵字宣告,並且以傳址 (By Reference) 方式傳遞。 Marshal.SizeOf 方法會決定 Unmanaged 結構的大小 (以位元組為單位)。
宣告原型
<StructLayout(LayoutKind.Sequential)> _
Public Class OSVersionInfo
Public OSVersionInfoSize As Integer
Public MajorVersion As Integer
Public MinorVersion As Integer
Public BuildNumber As Integer
Public PlatformId As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> _
Public CSDVersion As String
End Class
<StructLayout(LayoutKind.Sequential)> _
Public Structure OSVersionInfo2
Public OSVersionInfoSize As Integer
Public MajorVersion As Integer
Public MinorVersion As Integer
Public BuildNumber As Integer
Public PlatformId As Integer
<MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)> _
Public CSDVersion As String
End Structure
Public Class LibWrap
Declare Ansi Function GetVersionEx Lib "kernel32" Alias _
"GetVersionExA" ( <[In], Out> ByVal osvi As OSVersionInfo ) As Boolean
Declare Ansi Function GetVersionEx2 Lib "kernel32" Alias _
"GetVersionExA" ( ByRef osvi As OSVersionInfo2 ) As Boolean
End Class
[StructLayout(LayoutKind.Sequential)]
public class OSVersionInfo
{
public int OSVersionInfoSize;
public int MajorVersion;
public int MinorVersion;
public int BuildNumber;
public int PlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public String CSDVersion;
}
[StructLayout(LayoutKind.Sequential)]
public struct OSVersionInfo2
{
public int OSVersionInfoSize;
public int MajorVersion;
public int MinorVersion;
public int BuildNumber;
public int PlatformId;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public String CSDVersion;
}
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 ref class OSVersionInfo
{
public:
int OSVersionInfoSize;
int MajorVersion;
int MinorVersion;
int BuildNumber;
int PlatformId;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst=128)]
String^ CSDVersion;
};
[StructLayout(LayoutKind::Sequential)]
public value struct OSVersionInfo2
{
public:
int OSVersionInfoSize;
int MajorVersion;
int MinorVersion;
int BuildNumber;
int PlatformId;
[MarshalAs(UnmanagedType::ByValTStr, SizeConst=128)]
String^ CSDVersion;
};
public ref class LibWrap
{
public:
[DllImport("kernel32")]
static bool GetVersionEx([In, Out] OSVersionInfo^ osvi);
[DllImport("kernel32", EntryPoint="GetVersionEx")]
static bool GetVersionEx2(OSVersionInfo2% osvi);
};
呼叫函式
Public Class App
Public Shared Sub Main()
Console.WriteLine(vbNewLine + "Passing OSVersionInfo as a class")
Dim osvi As New OSVersionInfo()
osvi.OSVersionInfoSize = Marshal.SizeOf(osvi)
LibWrap.GetVersionEx(osvi)
Console.WriteLine("Class size: {0}", osvi.OSVersionInfoSize)
Console.WriteLine("OS Version: {0}.{1}", osvi.MajorVersion, osvi.MinorVersion)
Console.WriteLine(vbNewLine + "Passing OSVersionInfo2 as a struct")
Dim osvi2 As new OSVersionInfo2()
osvi2.OSVersionInfoSize = Marshal.SizeOf(osvi2)
LibWrap.GetVersionEx2(osvi2)
Console.WriteLine("Struct size: {0}", osvi2.OSVersionInfoSize)
Console.WriteLine("OS Version: {0}.{1}", osvi2.MajorVersion, osvi2.MinorVersion)
End Sub
End Class
public class App
{
public static void Main()
{
Console.WriteLine("\nPassing OSVersionInfo as a class");
OSVersionInfo osvi = new OSVersionInfo();
osvi.OSVersionInfoSize = Marshal.SizeOf(osvi);
LibWrap.GetVersionEx(osvi);
Console.WriteLine("Class size: {0}", osvi.OSVersionInfoSize);
Console.WriteLine("OS Version: {0}.{1}", osvi.MajorVersion, osvi.MinorVersion);
Console.WriteLine("\nPassing OSVersionInfo as a struct" );
OSVersionInfo2 osvi2 = new OSVersionInfo2();
osvi2.OSVersionInfoSize = Marshal.SizeOf(osvi2);
LibWrap.GetVersionEx2(ref osvi2);
Console.WriteLine("Struct size: {0}", osvi2.OSVersionInfoSize);
Console.WriteLine("OS Version: {0}.{1}", osvi2.MajorVersion, osvi2.MinorVersion);
}
}
public ref class App
{
public:
static void Main()
{
Console::WriteLine("\nPassing OSVersionInfo as a class");
OSVersionInfo^ osvi = gcnew OSVersionInfo();
osvi->OSVersionInfoSize = Marshal::SizeOf(osvi);
LibWrap::GetVersionEx(osvi);
Console::WriteLine("Class size: {0}", osvi->OSVersionInfoSize);
Console::WriteLine("OS Version: {0}.{1}", osvi->MajorVersion, osvi->MinorVersion);
Console::WriteLine("\nPassing OSVersionInfo as a struct" );
OSVersionInfo2 osvi2;
osvi2.OSVersionInfoSize = Marshal::SizeOf(osvi2);
LibWrap::GetVersionEx2(osvi2);
Console::WriteLine("Struct size: {0}", osvi2.OSVersionInfoSize);
Console::WriteLine("OS Version: {0}.{1}", osvi2.MajorVersion, osvi2.MinorVersion);
}
};
請參閱
概念
其他資源
Creating Prototypes in Managed Code