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中类型的变通使用的主要内容,如果未能解决你的问题,请参考以下文章

27.5 API中类型的变通使用

ES的QueryFilterMetricBucketing使用详解

ES的QueryFiltermetricbucketing使用详解

java枚举类型变通

27.5 任务

受限操作的变通解决方案