WOW64下のVisualBasicからGetNativeSystemInfo関数を呼び出す

|

前回は32ビット環境、今回は64ビット環境でVisualBasicからアンマネージド関数を呼び出してみる事に。

マイクロソフトのGetSystemInfo関数のドキュメントに、

To retrieve accurate information for an application running on WOW64, call the GetNativeSystemInfo function.

とあったので、GetNativeSystemInfo関数を呼び出すだけのサンプルを作ってみました。

★凡そ10年前の Windows7 は当然、現役のバリバリ。

それはさて置き、前回作成の32ビット版だと思っていたプログラムが、WOW64下(?)で思いがけない動作結果に。

取得SYSTEM_INFO_32データ

取得SYSTEM_INFO2_32データ


CPUタイプなど、一部不確かなデータを拾ってきてしまいます。試しに Windows7 64Bit 版でもプログラムを作成・実行してみると、同様の結果に。

調べてみると、初期設定(インストール時)のままのIDEでは、Visual Basic は実行対象OSが 32bit/64bit のどちらのバージョンでも、ネイティブ動作するようにコンパイルするようです。

マイクロソフトドキュメント ⇒ 任意のプラットフォーム上で実行されるように、アセンブリをコンパイルします。アプリケーションは、Windowsの32ビットバージョンでは32ビットアプリケーションとして、Windowsの64ビットバージョンでは64ビットアプリケーションとして実行されます。この anycpu フラグが既定値です。


★例え32ビットのOS上でコンパイルしても、上記の動作をするのには驚きだわ! 各.NET開発言語によって作成される中間言語(MSIL)は、CPUや各Windowsプラットフォームに依存しないコードになっていて、実行される際に順次ネイティブコードにコンパイルされます(=JITコンパイラだそうな)。


・と言う訳で、規定値設定のVisualBasicで作成された実行ファイル(exe)は、WOW64配下には入らず64ビットCLR上で動作します。

・なので、以下の3メンバーを ULong に直してやれば構造体サイズには不満は残るけど、それなりの動作結果に。

LPVOID    lpMinimumApplicationAddress;
LPVOID    lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;

・自分的には、ムズイ。意識していないと、多分ど壺に嵌るな、きっと。


<注意点>

・Win64 ではC/C++のポインタサイズは8バイト、ポインタ精度変数のサイズも8バイト。つまり、Long 型です。

・DWORD_PTR も Win64 では8バイトで Long 型。LPVOID は IntPtr の方が好ましい?

・Visual Basic のデフォルトの文字セットは、UNICODE です。


お試し環境
  WindowsXP 32bit Edition、Windows7 64bit Edition
  Visual Basic 2008


/*-------------------------------- お試し結果 ------------------------------*/

・GetNativeSystemInfo 関数の取得データ

取得SYSTEM_INFO_64データ


・GetSystemInfo 関数の取得データ

取得SYSTEM_INFO2_64データ

/*----------------------------------------------------------------------------*/


/*-------------------------------- お試しソース ----------------------------*/

Imports System.Runtime.InteropServices

Public Class Form4

    Const PROCESSOR_ARCHITECTURE_INTEL As Integer = 0 ' x86
    Const PROCESSOR_ARCHITECTURE_ARM As Integer = 5 ' ARM
    Const PROCESSOR_ARCHITECTURE_IA64 As Integer = 6 ' Intel Itanium-based
    Const PROCESSOR_ARCHITECTURE_AMD64 As Integer = 9 ' x64(AMD or Intel)
    Const PROCESSOR_ARCHITECTURE_ARM64 As Integer = 12 ' ARM64
    Const PROCESSOR_ARCHITECTURE_UNKNOWN As Integer = &HFFFF ' Unknown architecture

    Const PROCESSOR_INTEL_386 As Integer = 386
    Const PROCESSOR_INTEL_486 As Integer = 486
    Const PROCESSOR_INTEL_PENTIUM As Integer = 586
    Const PROCESSOR_INTEL_IA64 As Integer = 2200
    Const PROCESSOR_AMD_X8664 As Integer = 8664
    ' Const PROCESSOR_ARM As Integer = Reserved

    Structure SYSTEM_INFO
        Dim wProcessorArchitecture As UShort
        Dim wReserved As UShort
        Dim dwPageSize As UInteger
        Dim lpMinimumApplicationAddress As ULong
        Dim lpMaximumApplicationAddress As ULong
        Dim dwActiveProcessorMask As ULong
        Dim dwNumberOfProcessors As UInteger
        Dim dwProcessorType As UInteger
        Dim dwAllocationGranularity As UInteger
        Dim wProcessorLevel As UShort
        Dim wProcessorRevision As UShort
    End Structure

    Structure SYSTEM_INFO2
        Dim wProcessorArchitecture As UShort
        Dim wReserved As UShort
        Dim dwPageSize As UInteger
        Dim lpMinimumApplicationAddress As IntPtr
        Dim lpMaximumApplicationAddress As IntPtr
        Dim dwActiveProcessorMask As ULong
        Dim dwNumberOfProcessors As UInteger
        Dim dwProcessorType As UInteger
        Dim dwAllocationGranularity As UInteger
        Dim wProcessorLevel As UShort
        Dim wProcessorRevision As UShort
    End Structure

    Declare Auto Sub GNSInfo Lib "kernel32.dll" Alias "GetNativeSystemInfo" (ByRef sysInfo As SYSTEM_INFO)
    Declare Auto Sub GSInfo Lib "kernel32.dll" Alias "GetSystemInfo" (ByRef sysInfo As SYSTEM_INFO2)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim sInfo As SYSTEM_INFO
        Dim sInfo2 As SYSTEM_INFO2
        Dim msg1, msg2 As String

        GNSInfo(sInfo)
        GSInfo(sInfo2)

        msg1 = "wProcessorArchitecture = " & sInfo.wProcessorArchitecture & vbCrLf & _
               "wReserved = " & sInfo.wReserved & vbCrLf & _
               "dwPageSize = " & sInfo.dwPageSize & vbCrLf & _
               "lpMinimumApplicationAddress = " & sInfo.lpMinimumApplicationAddress.ToString("x") & vbCrLf & _
               "lpMaximumApplicationAddress = " & sInfo.lpMaximumApplicationAddress.ToString("x") & vbCrLf & _
               "dwActiveProcessorMask = " & sInfo.dwActiveProcessorMask & vbCrLf & _
               "dwNumberOfProcessors = " & sInfo.dwNumberOfProcessors & vbCrLf & _
               "dwProcessorType = " & sInfo.dwProcessorType & vbCrLf & _
               "dwAllocationGranularity = " & sInfo.dwAllocationGranularity & vbCrLf & _
               "wProcessorLevel = " & sInfo.wProcessorLevel & vbCrLf & _
               "wProcessorRevision = " & sInfo.wProcessorRevision

        msg2 = "wProcessorArchitecture = " & sInfo2.wProcessorArchitecture & vbCrLf & _
               "wReserved = " & sInfo2.wReserved & vbCrLf & _
               "dwPageSize = " & sInfo2.dwPageSize & vbCrLf & _
               "lpMinimumApplicationAddress = " & sInfo2.lpMinimumApplicationAddress.ToString("x") & vbCrLf & _
               "lpMaximumApplicationAddress = " & sInfo2.lpMaximumApplicationAddress.ToString("x") & vbCrLf & _
               "dwActiveProcessorMask = " & sInfo2.dwActiveProcessorMask & vbCrLf & _
               "dwNumberOfProcessors = " & sInfo2.dwNumberOfProcessors & vbCrLf & _
               "dwProcessorType = " & sInfo2.dwProcessorType & vbCrLf & _
               "dwAllocationGranularity = " & sInfo2.dwAllocationGranularity & vbCrLf & _
               "wProcessorLevel = " & sInfo2.wProcessorLevel & vbCrLf & _
               "wProcessorRevision = " & sInfo2.wProcessorRevision

        MessageBox.Show(msg1, "SYSTEM_INFO arg data")
        MessageBox.Show(msg2, "SYSTEM_INFO2 arg data")

        Select Case sInfo.wProcessorArchitecture
            Case PROCESSOR_ARCHITECTURE_INTEL
                MessageBox.Show("32ビット", "OSのタイプ")
            Case PROCESSOR_ARCHITECTURE_ARM
            Case PROCESSOR_ARCHITECTURE_IA64
            Case PROCESSOR_ARCHITECTURE_AMD64
                MessageBox.Show("64ビット", "OSのタイプ", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Case PROCESSOR_ARCHITECTURE_ARM64
            Case PROCESSOR_ARCHITECTURE_UNKNOWN
        End Select

        Select Case sInfo.dwProcessorType
            Case PROCESSOR_INTEL_386
            Case PROCESSOR_INTEL_486
            Case PROCESSOR_INTEL_PENTIUM
                MessageBox.Show("Pentium4", "CPUのタイプ")
            Case PROCESSOR_INTEL_IA64
            Case PROCESSOR_AMD_X8664
                MessageBox.Show("AMD Ryzen?" & vbCrLf & "な訳ありません", "CPUのタイプ", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End Select

        MessageBox.Show(sInfo.dwNumberOfProcessors & " Core", "プロセッサ数", MessageBoxButtons.OK, MessageBoxIcon.Information)

    End Sub
End Class

/*----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------*/
/*============================================================================*/