Archive for the ‘Win32 API’ Category

  1. Hello, Win32 API(F#) World!

    Posted on 4月 25th, 2012 by cx20

    Win32 API(F#)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は F# にて DllImport 属性を用いた呼出し例である。

    ソースコード

    open System
    open System.Runtime.InteropServices
     
    [<DllImport("user32.dll")>]
    extern int MessageBox( UInt32 hWnd, String lpText, String lpCaption, UInt32 uType)
     
    let x = MessageBox( 0u, "Hello, Win32 API(F#) World!", "Hello, World!", 0u )

    コンパイル方法

    C:¥> fsc Hello.fs

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(F#) World!
    ---------------------------
    OK   
    ---------------------------
  2. Hello, Win32 API(VB.NET) World!

    Posted on 4月 24th, 2012 by cx20

    Win32 API(VB.NET)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は VB.NET にて Declare ステートメントを用いた呼出し例である。

    ソースコード

    Imports System
    Imports System.Runtime.InteropServices
     
    Module Hello
        Declare Auto Function MessageBox Lib "user32.dll" Alias "MessageBox" ( _
            ByVal hWnd As IntPtr, _
            ByVal lpText As String, _
            ByVal lpCaption As String, _
            ByVal nType As UInteger _
        ) As Integer
     
        Sub Main()
            MessageBox( New IntPtr(0), "Hello, Win32 API(VB.NET) World!", "Hello, World!", 0 )
        End Sub
    End Module

    「文字セット」に「Auto」を指定した場合は「エイリアス名」「プラットフォーム」に応じて、呼び出される API 関数名が自動判別される。
    「文字セット」に「Ansi」もしくは「Unicode」を指定した場合は「エイリアス名」が API 関数名として使用される為、”A” / “W” のどちらのバージョンであるか明示的に指定する必要がある。(指定を行わない場合、関数名が見つからずエラーとなる)

    文字セット指定 エイリアス名 プラットフォーム 文字変換 判別 API関数名
    Auto MessageBox Windows 9x系 ANSI “A” MessageBoxA
    Auto MessageBox Windows NT系 Unicode “W” MessageBoxW
    Ansi または 省略 MessageBox ANSI Not Found
    Ansi または 省略 MessageBoxA ANSI MessageBoxA
    Unicode MessageBox Unicode Not Found
    Unicode MessageBoxW Unicode MessageBoxW

    また、Win32 データ型と VB.NET データ型の対応は主に以下のようになっている。「(2.0)」は、.NET Framework 2.0 で追加された型を示す。文字関連の型に関しては文字セット指定が必要なことに注意。

    Win32 データ型 C/C++ データ型 .NET データ型 VB.NET データ型
    HANDLE void * IntPtr
    BYTE unsigned char Byte Byte
    SHORT short Int16 Short
    WORD unsigned short UInt16 UShort (2.0)
    INT int Int32 Integer
    UINT unsigned int UInt32 UInteger (2.0)
    LONG long Int32 Integer
    BOOL int Int32 Integer
    DWORD unsigned long UInt32 UInteger (2.0)
    ULONG unsigned long UInt32 UInteger (2.0)
    CHAR char Char (Ansi) Char (Ansi)
    WCHAR wchar_t Char (Unicode) Char (Unicode)
    LPSTR char * StringBuilder (Ansi)
    LPCSTR const char * String (Ansi) String (Ansi)
    LPWSTR wchar_t * StringBuilder (Unicode)
    LPCWSTR const wchar_t * String (Unicode) String (Unicode)
    FLOAT float Single Single
    DOUBLE double Double Double

    コンパイル方法

    C:¥> vbc Hello.vb

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(VB.NET) World!
    ---------------------------
    OK   
    ---------------------------
  3. Hello, Win32 API(C#) World!

    Posted on 4月 23rd, 2012 by cx20

    Win32 API(C#)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は C# にて DllImport 属性を用いた呼出し例である。

    ソースコード

    using System;
    using System.Runtime.InteropServices;
     
    class Hello
    {
         [DllImport("user32.dll", CharSet=CharSet.Auto)]
         private extern static uint MessageBox(IntPtr hWnd, string lpText, string lpCaption, uint uType);
         static void Main(string[] args)
        {
            MessageBox( new IntPtr(0), "Hello, Win32 API(C#) World!", "Hello, World!", 0 );
        }
    }

    「文字セット」に「Auto」を指定した場合は「関数定義」「プラットフォーム」に応じて、呼び出される API 関数名が自動判別される。
    「文字セット」に「Ansi」もしくは「Unicode」を指定した場合それぞれ、末尾が “A” / “W” の API 関数名として自動判別される。

    文字セット指定 関数定義 プラットフォーム 文字変換 判別 API関数名
    Auto MessageBox Windows 9x系 ANSI “A” MessageBoxA
    Auto MessageBox Windows NT系 Unicode “W” MessageBoxW
    Ansi または 省略 MessageBox ANSI “A” MessageBoxA
    Ansi または 省略 MessageBoxA ANSI MessageBoxA
    Unicode MessageBox Unicode “W” MessageBoxW
    Unicode MessageBoxW Unicode MessageBoxW

    また、Win32 データ型と C# データ型の対応は主に以下のようになっている。文字関連の型に関しては文字セット指定が必要なことに注意。

    Win32 データ型 C/C++ データ型 .NET データ型 C# データ型
    HANDLE void * IntPtr
    BYTE unsigned char Byte byte
    SHORT short Int16 short
    WORD unsigned short UInt16 ushort
    INT int Int32 int
    UINT unsigned int UInt32 uint
    LONG long Int32 int
    BOOL int Int32 int
    DWORD unsigned long UInt32 uint
    ULONG unsigned long UInt32 uint
    CHAR char Char (Ansi) char (Ansi)
    WCHAR wchar_t Char (Unicode) char (Unicode)
    LPSTR char * StringBuilder (Ansi)
    LPCSTR const char * String (Ansi) string (Ansi)
    LPWSTR wchar_t * StringBuilder (Unicode)
    LPCWSTR const wchar_t * String (Unicode) string (Unicode)
    FLOAT float Single float
    DOUBLE double Double double

    コンパイル方法

    C:¥> csc Hello.cs

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(C#) World!
    ---------------------------
    OK   
    ---------------------------
  4. Hello, Win32 API(PowerShell) World!

    Posted on 4月 22nd, 2012 by cx20

    Win32 API(PowerShell)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は PowerShell での P/Invoke による呼出し例である。

    ソースコード

    function Main
    {
       MessageBox 0 "Hello, Win32 API(PowerShell)!" "Hello, World!" 0
    }
     
    ## Invoke a Win32 P/Invoke call. 
    ## http://www.leeholmes.com/blog/2006/07/21/get-the-owner-of-a-process-in-powershell-%e2%80%93-pinvoke-and-refout-parameters/
    function Invoke-Win32([string] $dllName, [Type] $returnType, [string] $methodName,  
       [Type[]] $parameterTypes, [Object[]] $parameters) 
    { 
       ## Begin to build the dynamic assembly 
       $domain = [AppDomain]::CurrentDomain 
       $name = New-Object Reflection.AssemblyName 'PInvokeAssembly' 
       $assembly = $domain.DefineDynamicAssembly($name, 'Run') 
       $module = $assembly.DefineDynamicModule('PInvokeModule') 
       $type = $module.DefineType('PInvokeType', "Public,BeforeFieldInit") 
     
       ## Define the actual P/Invoke method
       $method = $type.DefineMethod($methodName, 'Public,HideBySig,Static,PinvokeImpl',  
          $returnType, $parameterTypes) 
     
       ## Apply the P/Invoke constructor 
       $ctor = [Runtime.InteropServices.DllImportAttribute].GetConstructor([string]) 
       $attr = New-Object Reflection.Emit.CustomAttributeBuilder $ctor, $dllName 
       $method.SetCustomAttribute($attr) 
     
       ## Create the temporary type, and invoke the method. 
       $realType = $type.CreateType() 
       $realType.InvokeMember($methodName, 'Public,Static,InvokeMethod', $null, $null,  
          $parameters) 
    } 
     
    function MessageBox([Int32] $hWnd, [String] $lpText, [String] $lpCaption, [Int32] $uType) 
    { 
       $parameterTypes = [Int32], [String], [String], [Int32]
       $parameters = $hWnd, $lpText, $lpCaption, $uType
     
       Invoke-Win32 "user32.dll" ([Int32]) "MessageBoxA" $parameterTypes $parameters
    } 
     
    . Main

    実行方法

    C:¥> PowerShell -file hello.ps1

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(PowerShell) World!
    ---------------------------
    OK   
    ---------------------------
  5. Hello, Win32 API(JScript) World!

    Posted on 4月 21st, 2012 by cx20

    Win32 API(JScript)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    JScript には Win32 API を直接呼び出す機能は存在しないが、他のコンポーネントを経由することで、呼び出すことが可能である。
    Win32 API を呼び出すことが可能なコンポーネントとしては「DynamicWrapper」「SFC mini」「Excel」等がある。
    以下は DynamicWrapper を経由した Win32 API 呼出し例である。

    ソースコード(JScript + COM + DynamicWrapper + Win32 API)

    main();
     
    function main() {
        var win32 = new ActiveXObject("DynamicWrapper");
        win32.Register( "user32.dll", "MessageBoxA", "i=hssu", "f=s", "r=l" );
        win32.MessageBoxA( 0, "Hello, Win32 API(JScript) World!", "Hello, World!", 0 );
    }

    以下は SFC mini を経由した Win32 API 呼出し例である。

    ソースコード(JScript + COM + SFC miin + Win32 API)

    main();
     
    function main() {
       var messageBox = new ActiveXObject("SfcMini.DynaCall");
       messageBox.Declare( "user32", "MessageBoxA" );
       messageBox( 0, "Hello, Win32 API(JScript) World!", "Hello, World!", 0 );
    }

    以下は Excel を経由した Win32 API 呼出し例である。実際には、Excel の「Call 関数」を ExecuteExcel4Macro メソッド経由で呼び出す例となっている。

    ソースコード(JScript + COM + Excel + Call 関数 + Win32 API)

    main();
     
    function main() {
        var excel = new ActiveXObject("Excel.Application");
        var strMacro = 'CALL("user32", "MessageBoxA", "JJCCJ", 0,"Hello, Win32 API(JScript) World!", "Hello, World!", 0)'
        excel.ExecuteExcel4Macro( strMacro );
    }

    実行方法

    C:¥> CSciprt hello.js

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(JScript) World!
    ---------------------------
    OK   
    ---------------------------
  6. Hello, Win32 API(VBScript) World!

    Posted on 4月 20th, 2012 by cx20

    Win32 API(VBScript)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。VBScript には Win32 API を直接呼び出す機能は存在しないが、他のコンポーネントを経由することで、呼び出すことが可能である。
    Win32 API を呼び出すことが可能なコンポーネントとしては「DynamicWrapper」「SFC mini」「Excel」等がある。
    以下は DynamicWrapper を経由した Win32 API 呼出し例である。

    ソースコード(VBScript + COM + DynamicWrapper + Win32 API)

    Option Explicit
     
    Call Main()
     
    Sub Main()
        Dim win32
        Set win32 = CreateObject("DynamicWrapper")
        win32.Register "user32.dll", "MessageBoxA", "i=hssu", "f=s", "r=l"
        win32.MessageBoxA Null, "Hello, Win32 API(VBScript) World!", "Hello, World!", 0
    End Sub

    以下は SFC mini を経由した Win32 API 呼出し例である。

    ソースコード(VBScript + COM + SFC mini + Win32 API)

    Option Explicit
     
    Call Main()
     
    Sub Main()
       Dim MessageBox
       Set MessageBox = CreateObject("SfcMini.DynaCall")
       MessageBox.Declare "user32", "MessageBoxA"
       MessageBox 0, "Hello, Win32 API(VBScript) World!", "Hello, World!", vbOkOnly
    End Sub

    以下は Excel を経由した Win32 API 呼出し例である。実際には、Excel の「Call 関数」を ExecuteExcel4Macro メソッド経由で呼び出す例となっている。

    ソースコード(VBScript + COM + Excel + Call 関数 + Win32 API)

    Option Explicit
     
    Call Main()
     
    Sub Main()
        Dim excel
        Set excel = CreateObject("Excel.Application")
        Dim strMacro
        strMacro = "CALL('user32', 'MessageBoxA', 'JJCCJ', 0, 'Hello, Win32 API(VBScript) World!', 'Hello, World!', 0)"
        strMacro = Replace( strMacro, "'", """" )
        excel.ExecuteExcel4Macro( strMacro )
    End Sub

    なお、Call 関数で使用している、”JJCCJ” のコード値は MessageBoxA 関数の戻り値ならびに各引数のデータ型に対応している。詳細は「CALL 関数と REGISTER 関数の使い方」を参照のこと。

    コード 説明 渡す方法 C 言語での宣言
    A 論理値 (FALSE = 0、TRUE = 1) short int
    B IEEE 8 バイト浮動小数点数 値 (Windows)
    参照 (Macintosh)
    double (Windows)
    double * (Macintosh)
    C 末尾が Null の文字列 (最大文字列長 = 255) 参照 char *
    D バイト数を含む文字列 (先頭バイトが文字列の長さ、最大文字列長 = 255) 参照 unsigned char *
    E IEEE 8 バイト浮動小数点数 参照 double *
    F 末尾が Null の文字列 (最大文字列長 = 255) 参照 (指定した引数の変更) char *
    G バイト数を含む文字列 (先頭バイトが文字列の長さ、最大文字列長 = 255) 参照 (指定した引数の変更) unsigned char *
    H 符号なし 2 バイト整数 unsigned short int
    I 符号付き 2 バイト整数 short int
    J 符号付き 4 バイト整数 long int
    K 配列 参照 FP *
    L 論理値 (FALSE = 0、TRUE = 1) 参照 short int *
    M 符号付き 2 バイト整数 参照 short int *
    N 符号付き 4 バイト整数 参照 long int *
    O 配列 参照 引数は次の 3 種類
    unsigned short int *
    unsigned short int *
    double [ ]
    P Excel の OPER データ構造体 参照 OPER *
    R Excel の XLOPER データ構造体 参照 XLOPER *

    実行方法

    C:¥> CSciprt hello.vbs

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(VBScript) World!
    ---------------------------
    OK   
    ---------------------------
  7. Hello, Win32 API(VBA) World!

    Posted on 4月 19th, 2012 by cx20

    Win32 API(VBA)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は VBA(Microsoft Visual Basic for Applications)からの呼出し例である。

    ソースコード(Excel VBA / 32bit版)

    Declare Function MessageBox Lib "User32.dll" Alias "MessageBoxA" ( _
        ByVal hWnd As Long, _
        ByVal lpText As String, _
        ByVal lpCaption As String, _
        ByVal uType As Long _
    ) As Integer
     
    Sub Main()
        MessageBox 0, "Hello, Win32 API(VBA) World!", "Hello, World!", vbOKOnly
    End Sub

    64bit 版 VBA では Win32 API 使用時に PtrSafe を指定する必要がある。

    ソースコード(Excel VBA / 64bit版)

    Declare PtrSafe Function MessageBox Lib "User32.dll" Alias "MessageBoxA" ( _
        ByVal hWnd As Long, _
        ByVal lpText As String, _
        ByVal lpCaption As String, _
        ByVal uType As Long _
    ) As Integer
     
    Sub Main()
        MessageBox 0, "Hello, Win32 API(VBA) World!", "Hello, World!", vbOKOnly
    End Sub

    なお、PtrSfae 属性は Office 2010 からの機能である為、下位互換の為に以下の条件付きコンパイル属性を指定することが推奨されている。

    ソースコード(Excel VBA / 互換性を考慮した記述)

    #If VBA7 And Win64 Then
        Declare PtrSafe Function MessageBox Lib "User32.dll" Alias "MessageBoxA" ( _
            ByVal hWnd As Long, _
            ByVal lpText As String, _
            ByVal lpCaption As String, _
            ByVal uType As Long _
        ) As Integer
    #else
        Declare Function MessageBox Lib "User32.dll" Alias "MessageBoxA" ( _
            ByVal hWnd As Long, _
            ByVal lpText As String, _
            ByVal lpCaption As String, _
            ByVal uType As Long _
        ) As Integer
    #end if
     
    Sub Main()
        MessageBox 0, "Hello, Win32 API(VBA) World!", "Hello, World!", vbOKOnly
    End Sub

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(VBA) World!
    ---------------------------
    OK   
    ---------------------------
  8. Hello, Win32 API(VB6) World!

    Posted on 4月 18th, 2012 by cx20

    Win32 API(VB6)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は VB6 からの呼出し例である。

    ソースコード

    Declare Function MessageBox Lib "User32.dll" Alias "MessageBoxA" ( _
        ByVal hWnd As Long, _
        ByVal lpText As String, _
        ByVal lpCaption As String, _
        ByVal uType As Long _
    ) As Integer
     
    Sub Main()
        MessageBox 0, "Hello, Win32 API(VB6) World!", "Hello, World!", vbOKOnly
    End Sub

    Win32 データ型と VB6 データ型の対応は主に以下のようになっている。

    Win32 データ型 C/C++ データ型 VB6
    HANDLE void * Long
    BYTE unsigned char Byte
    SHORT short Integer
    WORD unsigned short Integer
    INT int Long
    UINT unsigned int Long
    LONG long Long
    BOOL int Long
    DWORD unsigned long Long
    ULONG unsigned long Long
    CHAR char Byte
    WCHAR wchar_t Integer
    LPSTR char * String
    LPCSTR const char * String
    LPWSTR wchar_t * Long (StrPtr)
    LPCWSTR const wchar_t * Long (StrPtr)
    FLOAT float Single
    DOUBLE double Double

    コンパイル方法

    C:¥> vb6 /make hello.vbp

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(VB6) World!
    ---------------------------
    OK   
    ---------------------------
  9. Hello, Win32 API(MASM) World!

    Posted on 4月 17th, 2012 by cx20

    Win32 API(MASM)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は MASM からの呼出し例である。

    ソースコード(MASM)

    ; Listing generated by Microsoft (R) Optimizing Compiler Version 14.00.50727.762 
     
            TITLE   hello.c
            .686P
            .XMM
            include listing.inc
            .model  flat
     
    INCLUDELIB LIBCMT
    INCLUDELIB OLDNAMES
     
    _DATA   SEGMENT
    $SG77810 DB     'Hello, World!', 00H
            ORG $+2
    $SG77811 DB     'Hello, Win32 API(MASM) World!', 00H
    _DATA   ENDS
    PUBLIC  _main
    EXTRN   __imp__MessageBoxA@16:PROC
    ; Function compile flags: /Odtp
    _TEXT   SEGMENT
    _argc$ = 8                                              ; size = 4
    _argv$ = 12                                             ; size = 4
    _main   PROC
    ; File hello.c
    ; Line 4
            push    ebp
            mov     ebp, esp
    ; Line 5
            push    0
            push    OFFSET $SG77810
            push    OFFSET $SG77811
            push    0
            call    DWORD PTR __imp__MessageBoxA@16
    ; Line 6
            xor     eax, eax
    ; Line 7
            pop     ebp
            ret     0
    _main   ENDP
    _TEXT   ENDS
    END

    上記コードは、下記の C のソースを「cl hello.c /FA」にてアセンブラ出力したものである。

    ソースコード(C言語)

    #include <windows.h>
     
    int main( int argc, char* argv[] )
    {
        MessageBoxA( NULL, "Hello, Win32 API(MASM) World!", "Hello, World!", MB_OK );
        return 0;
    }

    コンパイル方法(Visual C++)

    C:¥> ml hello.asm
    C:¥> link hello.obj user32.lib

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(MASM) World!
    ---------------------------
    OK   
    ---------------------------
  10. Hello, Win32 API(DLL) World!

    Posted on 4月 16th, 2012 by cx20

    Win32 API(DLL)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    Win32 API は DLL として提供されており、ライブラリのリンク方法としては、インポートライブラリを使用した「暗黙的リンク」と LoadLibrary() による「明示的リンク」の2つの方法がある。
    ここでは C言語による LoadLibrary() を用いた DLL の呼出しの例(明示的リンク)を記載する。

    ソースコード

    #include <windows.h>
    #include <tchar.h>
     
    #ifdef UNICODE
        typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCWSTR, LPCWSTR, UINT);
    #else
        typedef int (WINAPI *PFNMESSAGEBOX)(HWND, LPCSTR, LPCSTR, UINT);
    #endif
     
    int _tmain( int argc, TCHAR* argv[] )
    {
        HINSTANCE hInstance = LoadLibrary( _T("user32.dll") );
    #ifdef UNICODE
        PROC pfunc = GetProcAddress( hInstance, "MessageBoxW" );
    #else
        PROC pfunc = GetProcAddress( hInstance, "MessageBoxA" );
    #endif
        ((PFNMESSAGEBOX)pfunc)( NULL, _T("Hello, Win32 API(DLL) World!"), _T("Hello, World!"), MB_OK );
     
        return 0;
    }

    Win32 API は内部的に UNICODE 版(例:MessageBoxW)と ANSI 版(例:MessageBoxA)の2つのバージョンをもっており、GetProcAddress() による呼出しの場合は、UNICODE/ANSI どちらの関数であるか指定する必要がある。

    Win32 API のプロトタイプ宣言(参考)

    WINUSERAPI
    int
    WINAPI
    MessageBoxA(
        __in_opt HWND hWnd,
        __in_opt LPCSTR lpText,
        __in_opt LPCSTR lpCaption,
        __in UINT uType);
    WINUSERAPI
    int
    WINAPI
    MessageBoxW(
        __in_opt HWND hWnd,
        __in_opt LPCWSTR lpText,
        __in_opt LPCWSTR lpCaption,
        __in UINT uType);
    #ifdef UNICODE
    #define MessageBox  MessageBoxW
    #else
    #define MessageBox  MessageBoxA
    #endif // !UNICODE

    コンパイル方法(Visual C++ / UNICODE ビルド)

    C:¥> cl hello.c /DUNICODE /D_UNICODE

    上記の「/D」オプションで指定している定義「UNICODE」は Win32 API 用、「_UNICODE」は、C ランタイム用の定義となっている。

    コンパイル方法(Visual C++ / ANSI ビルド)

    C:¥> cl hello.c

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(DLL) World!
    ---------------------------
    OK   
    ---------------------------