27.5 API中类型的变通使用
Posted VB.Net
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了27.5 API中类型的变通使用相关的知识,希望对你有一定的参考价值。
API中的类型并非是一成不变的,有时候需要根据实际情况灵活使用。
比如GetUserName这个API函数作用是获取当前系统登录的用户账户名称。它的C原型为:
BOOL WINAPI GetUserName(LPTSTR lpBuffer , LPDWORD lpnSize );
通常对应的VB.Net声明为:
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
但是如下的声明也可以正常使用:
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer() As Byte, ByRef nSize As Integer) As Integer
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As IntPtr, ByRef nSize As Integer) As Integer
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As Text.StringBuilder, ByRef nSize As Integer) As Integer
【例 27A.5】【项目:code27A-005】获得当前登录的用户名。
以下代码用了四种不同类型的变量作为API函数GetUserName的参数,最终都能获得需要的用户名。
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Integer) As Integer
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer() As Byte, ByRef nSize As Integer) As Integer
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As IntPtr, ByRef nSize As Integer) As Integer
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As Text.StringBuilder, ByRef nSize As Integer) As Integer
'使用字符串
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim username As String = New String(" "c, 250)
Dim usernamesize As Integer = 250
Dim result As Integer
result = GetUserName(username, usernamesize)
If result <> 0 Then
username = username.Substring(0, usernamesize - 1)
TextBox1.Text = username
Else
TextBox1.Text = ""
End If
End Sub
'使用字节数组
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim username As String
Dim bteUsername(249) As Byte
Dim usernamesize As Integer = 250
Dim result As Integer
result = GetUserName(bteUsername, usernamesize)
If result <> 0 Then
'使用ASCII编码
username = System.Text.Encoding.ASCII.GetString(bteUsername)
username = username.Substring(0, usernamesize - 1)
TextBox1.Text = username
Else
TextBox1.Text = ""
End If
End Sub
'使用指针
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim username As String
Dim ptrUsername As IntPtr
'给指针分配内存
ptrUsername = System.Runtime.InteropServices.Marshal.AllocHGlobal(250)
Dim usernamesize As Integer = 250
Dim result As Integer
result = GetUserName(ptrUsername, usernamesize - 1)
If result <> 0 Then
'将指针转为Ansi字符串
username = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptrUsername, usernamesize)
TextBox1.Text = username
Else
TextBox1.Text = ""
End If
End Sub
'使用StringBuilder
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim username As New Text.StringBuilder(250)
Dim usernamesize As Integer = 250
Dim result As Integer
result = GetUserName(username, usernamesize)
If result <> 0 Then
TextBox1.Text = username.ToString
End If
End Sub
运行结果如下图所示:
图27A-5 获得用户名称
通常情况下,可以将结构变更为字节数组或者指针,有时候,还需要将结构变为类使用。
【例 27A.6】【项目:code27A-006】获得Windows系统版本信息。
本例与【例 27A.3】有所不同,将API函数RtlGetVersion中的参数从结构更改为了数组和指针:
<StructLayout(LayoutKind.Sequential)>
Public Structure OSVERSIONINFOEx
Public dwOSVersionInfoSize As Int32
Public dwMajorVersion As Int32
Public dwMinorVersion As Int32
Public dwBuildNumber As Int32
Public dwPlatformId As Int32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=128)> Public szCSDVersion() As Char
Public wServicePackMajor As Int16
Public wServicePackMinor As Int16
Public wSuiteMask As Int16
Public wProductType As Byte
Public wReserved As Byte
End Structure
Public Declare Function RtlGetVersion Lib "ntdll.dll" (ByVal ptrOsvi As IntPtr) As Integer
Public Declare Function RtlGetVersion Lib "ntdll.dll" (ByVal bteOsvi() As Byte) As Integer
'byte数组方式
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim result As Integer
Dim osInfo As New OSVERSIONINFOEx
Dim osviSize As Integer = Marshal.SizeOf(osInfo)
'定义字节数组
Dim bteOsvi() As Byte
'字节数组大小设置为结构大小
ReDim bteOsvi(osviSize - 1)
result = RtlGetVersion(bteOsvi)
If result >= 0 Then
'定义指针并分配内存
Dim ptrOsInfo As IntPtr = Marshal.AllocHGlobal(osviSize)
'字节数组->指针
Marshal.Copy(bteOsvi, 0, ptrOsInfo, osviSize)
'指针->结构(类)
Marshal.PtrToStructure(ptrOsInfo, osInfo)
MessageBox.Show("RtlGetVersion获得系统版本号:" & osInfo.dwMajorVersion & "." & osInfo.dwMinorVersion & "." & osInfo.dwBuildNumber)
End If
End Sub
'直接指针方式
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim result As Integer
Dim osInfo As New OSVERSIONINFOEx
Dim osviSize As Integer = Marshal.SizeOf(osInfo)
'定义指针并分配内存
Dim ptrOsInfo As IntPtr = Marshal.AllocHGlobal(osviSize)
result = RtlGetVersion(ptrOsInfo)
If result >= 0 Then
'指针->结构(类)
Marshal.PtrToStructure(ptrOsInfo, osInfo)
MessageBox.Show("RtlGetVersion获得系统版本号:" & osInfo.dwMajorVersion & "." & osInfo.dwMinorVersion & "." & osInfo.dwBuildNumber)
End If
End Sub
但是当使用Marshal.PtrToStructure()时,会出现错误提示:此结构不得为值类。
图27A-6 Marshal.PtrToStructure错误提示
这个错误的处理方式是将结构更改为类:
<StructLayout(LayoutKind.Sequential)>
Public Class OSVERSIONINFOEx
Public dwOSVersionInfoSize As Int32
……
Public wReserved As Byte
End Class
其余代码不变,运行正常。运行结果同【例 27A.3】。
读者可以参看笔者博客上《在vb.net中使用Iphlpapi.dll获取网络信息》系列文章,里面有很多网络相关的API函数的使用,都列出了C原型和VB、VB.Net的定义,以及VB.Net下如何使用,熟练了这系列文章,相信在API上可以做到运用自如。
由于.net平台下C#和vb.NET很相似,本文也可以为C#爱好者提供参考。
学习更多vb.net知识,请参看vb.net 教程 目录
以上是关于27.5 API中类型的变通使用的主要内容,如果未能解决你的问题,请参考以下文章
ES的QueryFilterMetricBucketing使用详解