Archive for the ‘library’ Category

  1. Hello, COM(MASM) World!

    Posted on 5月 12th, 2012 by cx20

    COM(MASM)

    COM(Component Object Model)はマイクロソフトの提唱するプログラム部品の仕様である。
    COM を用いて開発された部品であれば言語を問わず利用することができる。
    以下は MASM による COM クライアントの例となっている。

    ソースコード

    ; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.40219.01 
     
    	TITLE	hello.c
    	.686P
    	.XMM
    	include listing.inc
    	.model	flat
     
    INCLUDELIB LIBCMT
    INCLUDELIB OLDNAMES
     
    _DATA	SEGMENT
    $SG113507 DB	'H', 00H, 'e', 00H, 'l', 00H, 'l', 00H, 'o', 00H, ',', 00H
    	DB	' ', 00H, 'C', 00H, 'O', 00H, 'M', 00H, '(', 00H, 'M', 00H, 'A'
    	DB	00H, 'S', 00H, 'M', 00H, ')', 00H, ' ', 00H, 'W', 00H, 'o', 00H
    	DB	'r', 00H, 'l', 00H, 'd', 00H, '!', 00H, 00H, 00H
    _DATA	ENDS
    PUBLIC	_main
    EXTRN	__imp__CoUninitialize@0:PROC
    EXTRN	__imp__CoCreateInstance@20:PROC
    EXTRN	_CLSID_Shell:BYTE
    EXTRN	_IID_IShellDispatch:BYTE
    EXTRN	__imp__CoInitialize@4:PROC
    ; Function compile flags: /Odtp
    _TEXT	SEGMENT
    _pFolder$ = -36						; size = 4
    _vRootFolder$ = -32					; size = 16
    _folder$ = -12						; size = 4
    _pShell$ = -4						; size = 4
    _argc$ = 8						; size = 4
    _argv$ = 12						; size = 4
    _main	PROC
    ; File hello.c
    ; Line 4
            push    ebp
            mov     ebp, esp
            sub     esp, 36                                 ; 00000024H
    ; Line 11
            push    0
            call    DWORD PTR __imp__CoInitialize@4
    ; Line 13
            lea     eax, DWORD PTR _pShell$[ebp]
            push    eax
            push    OFFSET _IID_IShellDispatch
            push    1
            push    0
            push    OFFSET _CLSID_Shell
            call    DWORD PTR __imp__CoCreateInstance@20
    ; Line 15
            mov     ecx, 3
            mov     WORD PTR _vRootFolder$[ebp], cx
    ; Line 16
            mov     DWORD PTR _vRootFolder$[ebp+8], 36      ; 00000024H
    ; Line 17
            lea     edx, DWORD PTR _folder$[ebp]
            mov     DWORD PTR _pFolder$[ebp], edx
    ; Line 19
            lea     eax, DWORD PTR _pFolder$[ebp]
            push    eax
            sub     esp, 16                                 ; 00000010H
            mov     ecx, esp
            mov     edx, DWORD PTR _vRootFolder$[ebp]
            mov     DWORD PTR [ecx], edx
            mov     eax, DWORD PTR _vRootFolder$[ebp+4]
            mov     DWORD PTR [ecx+4], eax
            mov     edx, DWORD PTR _vRootFolder$[ebp+8]
            mov     DWORD PTR [ecx+8], edx
            mov     eax, DWORD PTR _vRootFolder$[ebp+12]
            mov     DWORD PTR [ecx+12], eax
            push    0
            push    OFFSET $SG113507
            push    0
            mov     ecx, DWORD PTR _pShell$[ebp]
            push    ecx
            mov     edx, DWORD PTR _pShell$[ebp]
            mov     eax, DWORD PTR [edx]
            mov     ecx, DWORD PTR [eax+40]
            call    ecx
    ; Line 20
            cmp     DWORD PTR _pFolder$[ebp], 0
            je      SHORT $LN1@main
    ; Line 22
            mov     edx, DWORD PTR _pFolder$[ebp]
            push    edx
            mov     eax, DWORD PTR _pFolder$[ebp]
            mov     ecx, DWORD PTR [eax]
            mov     edx, DWORD PTR [ecx+8]
            call    edx
    $LN1@main:
    ; Line 24
            mov     eax, DWORD PTR _pShell$[ebp]
            push    eax
            mov     ecx, DWORD PTR _pShell$[ebp]
            mov     edx, DWORD PTR [ecx]
            mov     eax, DWORD PTR [edx+8]
            call    eax
    ; Line 26
            call    DWORD PTR __imp__CoUninitialize@0
    ; Line 28
            xor     eax, eax
    ; Line 29
            mov     esp, ebp
            pop     ebp
            ret     0
    _main   ENDP
    _TEXT   ENDS
    END

    上記コードは以下のC言語のソースを VC++ でアセンブリコード出力(cl /FA hello.c)したものに相当する。

    #include <shlobj.h>
     
    int main( int argc, char* argv[] )
    {
        HRESULT hResult;
        IShellDispatch* pShell;
        VARIANT vRootFolder;
        Folder* pFolder;
     
        CoInitialize( NULL );
     
        CoCreateInstance( &CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void**)&pShell );
     
        VariantInit( &vRootFolder );
        vRootFolder.vt = VT_I4;
        vRootFolder.lVal = ssfWINDOWS;
     
        pShell->lpVtbl->BrowseForFolder( (void*)pShell, 0, L"Hello, COM(MASM) World!", 0, vRootFolder, &pFolder );
        VariantClear( &vRootFolder );
        if ( pFolder != NULL )
        {
            pFolder->lpVtbl->Release( (void*)pFolder );
        }
        pShell->lpVtbl->Release( (void*)pShell );
     
        CoUninitialize();
     
        return 0;
    }

    コンパイル&リンク方法

    C:¥> ml -c hello.asm
    C:¥> midl shldisp.idl
    C:¥> cl shldisp_i.c
    C:¥> link hello.obj shldisp_i.obj ole32.lib oleaut32.lib

    実行結果

    +----------------------------------------+
    |Browse For Folder                    [X]|
    +----------------------------------------+
    | Hello, COM(MASM) Wolrd!                |
    |                                        |
    | +------------------------------------+ |
    | |[Windows]                           | |
    | | +[addins]                          | |
    | | +[AppCompat]                       | |
    | | +[AppPatch]                        | |
    | | +[assembly]                        | |
    | |     :                              | |
    | |     :                              | |
    | |     :                              | |
    | +------------------------------------+ |
    | [Make New Folder]    [  OK  ] [Cancel] |
    +----------------------------------------+
  2. Hello, COM(MFC) World!

    Posted on 5月 11th, 2012 by cx20

    COM(MFC)

    COM(Component Object Model)はマイクロソフトの提唱するプログラム部品の仕様である。
    COM を用いて開発された部品であれば言語を問わず利用することができる。
    以下は Visual C++ / MFC による COM クライアント(事前バインディングならびに実行時バインディング)の例となっている。

    ソースコード(事前バインディング)

    #include <afxdisp.h>
     
    // [Typelib クラス追加ウィザード] で作成された IDispatch ラッパー クラスより一部抜粋
    class CFolder : public COleDispatchDriver
    {
    public:
        CFolder(){}
        CFolder(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
        CFolder(const CFolder& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
    public:
        CString get_Title()
        {
            CString result;
            InvokeHelper(0x0, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);
            return result;
        }
    };
     
    // [Typelib クラス追加ウィザード] で作成された IDispatch ラッパー クラスより一部抜粋
    class CShellDispatch : public COleDispatchDriver
    {
    public:
        CShellDispatch(){}
        CShellDispatch(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
        CShellDispatch(const CShellDispatch& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
    public:
        LPDISPATCH BrowseForFolder(long Hwnd, LPCTSTR Title, long Options, VARIANT& RootFolder)
        {
            LPDISPATCH result;
            static BYTE parms[] = VTS_I4 VTS_BSTR VTS_I4 VTS_VARIANT ;
            InvokeHelper(0x60020003, DISPATCH_METHOD, VT_DISPATCH, (void*)&result, parms, Hwnd, Title, Options, &RootFolder);
            return result;
        }
    };
     
    int _tmain(int argc, TCHAR* argv[] )
    {
        CoInitialize( NULL );
     
        CFolder folder;
        CShellDispatch shell;
        shell.CreateDispatch( _T("Shell.Application") );
     
        COleVariant vRootFolder( (long)ssfWINDOWS );
        folder = shell.BrowseForFolder( 0, _T("Hello, COM(MFC) World!"), 0, vRootFolder );
        if ( folder != NULL )
        {
            folder.DetachDispatch();
            folder.ReleaseDispatch();
        }
        shell.DetachDispatch();
        shell.ReleaseDispatch();
     
        CoUninitialize();
        return 0;
    }

    ソースコード(実行時バインディング)

    #include <afxdisp.h>
     
    int _tmain(int argc, TCHAR* argv[] )
    {
        CoInitialize( NULL );
     
        COleDispatchDriver shell;
        shell.CreateDispatch( _T("Shell.Application") );
     
        DISPID  dispid;
        OLECHAR* ptName = L"BrowseForFolder";
        ((LPDISPATCH)shell)->GetIDsOfNames( IID_NULL, &ptName, 1, GetUserDefaultLCID(), &dispid );
     
        LPDISPATCH pResult;
        COleVariant vRootFolder( 36L );    // ssfWINDOWS
        BYTE parms[] = VTS_I4 VTS_BSTR VTS_I4 VTS_VARIANT;
        shell.InvokeHelper( dispid, DISPATCH_METHOD, VT_DISPATCH, &pResult, parms, 0, _T("Hello, COM(MFC) World!"), 0, &vRootFolder);
     
        COleDispatchDriver folder = pResult;
        if ( folder != NULL )
        {
            folder.DetachDispatch();
            folder.ReleaseDispatch();
        }
        shell.DetachDispatch();
        shell.ReleaseDispatch();
     
        CoUninitialize();
        return 0;
    }

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

    C:¥> cl hello.cpp

    実行結果

    +----------------------------------------+
    |Browse For Folder                    [X]|
    +----------------------------------------+
    | Hello, COM(MFC) Wolrd!                 |
    |                                        |
    | +------------------------------------+ |
    | |[Windows]                           | |
    | | +[addins]                          | |
    | | +[AppCompat]                       | |
    | | +[AppPatch]                        | |
    | | +[assembly]                        | |
    | |     :                              | |
    | |     :                              | |
    | |     :                              | |
    | +------------------------------------+ |
    | [Make New Folder]    [  OK  ] [Cancel] |
    +----------------------------------------+
  3. Hello, COM(ATL) World!

    Posted on 5月 10th, 2012 by cx20

    COM(ATL)

    COM(Component Object Model)はマイクロソフトの提唱するプログラム部品の仕様である。
    COM を用いて開発された部品であれば言語を問わず利用することができる。
    以下は Visual C++ / ATL による COM クライアント(事前バインディングならびに実行時バインディング)の例となっている。

    ソースコード(事前バインディング)

    #include <atlbase.h>
    #include <shlobj.h>
     
    int _tmain(int argc, TCHAR* argv[] )
    {
        CoInitialize( NULL );
     
        CComPtr<Folder> pFolder;
        CComPtr<IShellDispatch> pShell;
        pShell.CoCreateInstance( CLSID_Shell );
     
        CComVariant vRootFolder( ssfWINDOWS );
        pShell->BrowseForFolder( 0, L"Hello, COM(ATL) World!", 0, vRootFolder, &pFolder );
        if ( pFolder != NULL )
        {
            pFolder = NULL;
        }
        pShell = NULL;
     
        CoUninitialize();
     
        return 0;
    }

    ソースコード(実行時バインディング)

    #include <atlbase.h>
     
    int _tmain(int argc, TCHAR* argv[] )
    {
        CoInitialize( NULL );
     
        CComPtr<IDispatch> pShell;
        pShell.CoCreateInstance( L"Shell.Application" );
     
        DISPPARAMS param = { NULL, NULL, 0, 0 };
        CComVariant varg[4];
        varg[0] = 36L;  // VT_I4 ssfWINDOWS 
        varg[1] = 0L;   // VT_I4
        varg[2] = L"Hello, COM(ATL) World!"; //  VT_BSTR
        varg[3] = 0L;   // VT_I4
     
        CComVariant vResult;
        pShell.InvokeN(L"BrowseForFolder", varg, 4, &vResult );
     
        CComPtr<IDispatch> pFolder = vResult.pdispVal;
        if ( pFolder != NULL )
        {
            pFolder = NULL;
        }
        pShell = NULL;
     
        CoUninitialize();
     
        return 0;
    }

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

    C:¥> cl hello.cpp

    実行結果

    +----------------------------------------+
    |Browse For Folder                    [X]|
    +----------------------------------------+
    | Hello, COM(ATL) Wolrd!                 |
    |                                        |
    | +------------------------------------+ |
    | |[Windows]                           | |
    | | +[addins]                          | |
    | | +[AppCompat]                       | |
    | | +[AppPatch]                        | |
    | | +[assembly]                        | |
    | |     :                              | |
    | |     :                              | |
    | |     :                              | |
    | +------------------------------------+ |
    | [Make New Folder]    [  OK  ] [Cancel] |
    +----------------------------------------+
  4. Hello, COM(#import) World!

    Posted on 5月 9th, 2012 by cx20

    COM(#import)

    COM(Component Object Model)はマイクロソフトの提唱するプログラム部品の仕様である。
    COM を用いて開発された部品であれば言語を問わず利用することができる。
    以下は Visual C++ のコンパイラ機能である #import ディレクティブを使用した COM クライアントの例となっている。

    ソースコード(事前バインディング)

    #import "shell32.dll"
    using namespace Shell32;
     
    int main( int argc, char* argv[] )
    {
        CoInitialize( NULL );
     
        IShellDispatchPtr pShell("Shell.Application");
        FolderPtr pFolder = NULL;
     
        _variant_t vRootFolder( ssfWINDOWS );
        pFolder = pShell->BrowseForFolder( 0, L"Hello, COM(#import) World!", 0, vRootFolder );
        if ( pFolder != NULL )
        {
            pFolder = NULL;
        }
        pShell = NULL;
     
        CoUninitialize();
     
        return 0;
    }

    #import ディレクティブにより、以下の2ファイル(「*.tlh(タイプライブラリヘッダ)」「*.tli(タイプライブラリ実装ファイル)」)が自動生成されタイプライブラリの情報が C++ ヘッダとして取り込まれる。

    ソースコード(タイプライブラリヘッダ)

    // #import "shell32.dll" にて自動生成された shell32.tlh より一部抜粋
     
    #include <comdef.h>
    namespace Shell32 {
     
    enum ShellSpecialFolderConstants;
    struct __declspec(uuid("bbcbde60-c3ff-11ce-8350-444553540000"))
    /* dual interface */ Folder;
    struct __declspec(uuid("d8f015c0-c278-11ce-a49e-444553540000"))
    /* dual interface */ IShellDispatch;
     
    _COM_SMARTPTR_TYPEDEF(Folder, __uuidof(Folder));
    _COM_SMARTPTR_TYPEDEF(IShellDispatch, __uuidof(IShellDispatch));
     
    enum __declspec(uuid("ca31ea20-48d0-11cf-8350-444553540000"))
    ShellSpecialFolderConstants
    {
        ssfWINDOWS = 36,
    };
     
    struct __declspec(uuid("d8f015c0-c278-11ce-a49e-444553540000"))
    IShellDispatch : IDispatch
    {
        // Wrapper methods for error-handling
        FolderPtr BrowseForFolder (
            long Hwnd,
            _bstr_t Title,
            long Options,
            const _variant_t & RootFolder = vtMissing );
     
        // Raw methods provided by interface
          virtual HRESULT __stdcall get_Application (
            /*[out,retval]*/ IDispatch * * ppid ) = 0;
          virtual HRESULT __stdcall get_Parent (
            /*[out,retval]*/ IDispatch * * ppid ) = 0;
          virtual HRESULT __stdcall raw_NameSpace (
            /*[in]*/ VARIANT vDir,
            /*[out,retval]*/ struct Folder * * ppsdf ) = 0;
          virtual HRESULT __stdcall raw_BrowseForFolder (
            /*[in]*/ long Hwnd,
            /*[in]*/ BSTR Title,
            /*[in]*/ long Options,
            /*[in]*/ VARIANT RootFolder,
            /*[out,retval]*/ struct Folder * * ppsdf ) = 0;
          virtual HRESULT __stdcall raw_Windows (
            /*[out,retval]*/ IDispatch * * ppid ) = 0;
          virtual HRESULT __stdcall raw_Open (
            /*[in]*/ VARIANT vDir ) = 0;
          virtual HRESULT __stdcall raw_Explore (
            /*[in]*/ VARIANT vDir ) = 0;
          virtual HRESULT __stdcall raw_MinimizeAll ( ) = 0;
          virtual HRESULT __stdcall raw_UndoMinimizeALL ( ) = 0;
          virtual HRESULT __stdcall raw_FileRun ( ) = 0;
          virtual HRESULT __stdcall raw_CascadeWindows ( ) = 0;
          virtual HRESULT __stdcall raw_TileVertically ( ) = 0;
          virtual HRESULT __stdcall raw_TileHorizontally ( ) = 0;
          virtual HRESULT __stdcall raw_ShutdownWindows ( ) = 0;
          virtual HRESULT __stdcall raw_Suspend ( ) = 0;
          virtual HRESULT __stdcall raw_EjectPC ( ) = 0;
          virtual HRESULT __stdcall raw_SetTime ( ) = 0;
          virtual HRESULT __stdcall raw_TrayProperties ( ) = 0;
          virtual HRESULT __stdcall raw_Help ( ) = 0;
          virtual HRESULT __stdcall raw_FindFiles ( ) = 0;
          virtual HRESULT __stdcall raw_FindComputer ( ) = 0;
          virtual HRESULT __stdcall raw_RefreshMenu ( ) = 0;
          virtual HRESULT __stdcall raw_ControlPanelItem (
            /*[in]*/ BSTR bstrDir ) = 0;
    };
     
    struct __declspec(uuid("bbcbde60-c3ff-11ce-8350-444553540000"))
    Folder : IDispatch
    {
        // Property data
        __declspec(property(get=GetTitle))
        _bstr_t Title;
     
        // Wrapper methods for error-handling
        _bstr_t GetTitle ( );
     
        // Raw methods provided by interface
          virtual HRESULT __stdcall get_Title (
            /*[out,retval]*/ BSTR * pbs ) = 0;
          virtual HRESULT __stdcall get_Application (
            /*[out,retval]*/ IDispatch * * ppid ) = 0;
          virtual HRESULT __stdcall get_Parent (
            /*[out,retval]*/ IDispatch * * ppid ) = 0;
          virtual HRESULT __stdcall get_ParentFolder (
            /*[out,retval]*/ struct Folder * * ppsf ) = 0;
          virtual HRESULT __stdcall raw_Items (
            /*[out,retval]*/ struct FolderItems * * ppid ) = 0;
          virtual HRESULT __stdcall raw_ParseName (
            /*[in]*/ BSTR bName,
            /*[out,retval]*/ struct FolderItem * * ppid ) = 0;
          virtual HRESULT __stdcall raw_NewFolder (
            /*[in]*/ BSTR bName,
            /*[in]*/ VARIANT vOptions = vtMissing ) = 0;
          virtual HRESULT __stdcall raw_MoveHere (
            /*[in]*/ VARIANT vItem,
            /*[in]*/ VARIANT vOptions = vtMissing ) = 0;
          virtual HRESULT __stdcall raw_CopyHere (
            /*[in]*/ VARIANT vItem,
            /*[in]*/ VARIANT vOptions = vtMissing ) = 0;
          virtual HRESULT __stdcall raw_GetDetailsOf (
            /*[in]*/ VARIANT vItem,
            /*[in]*/ int iColumn,
            /*[out,retval]*/ BSTR * pbs ) = 0;
    };
     
    // Wrapper method implementations
    #include "shell32.tli"
     
    } // namespace Shell32

    ソースコード(タイプライブラリ実装ファイル)

    // #import "shell32.dll" にて自動生成された shell32.tli より一部抜粋
     
    // interface IShellDispatch wrapper method implementations
    inline FolderPtr IShellDispatch::BrowseForFolder ( long Hwnd, _bstr_t Title, long Options, const _variant_t & RootFolder ) {
        struct Folder * _result = 0;
        HRESULT _hr = raw_BrowseForFolder(Hwnd, Title, Options, RootFolder, &_result);
        if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
        return FolderPtr(_result, false);
    }
     
    // interface Folder wrapper method implementations
    inline _bstr_t Folder::GetTitle ( ) {
        BSTR _result = 0;
        HRESULT _hr = get_Title(&_result);
        if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
        return _bstr_t(_result, false);
    }

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

    C:¥> cl hello.cpp

    実行結果

    +----------------------------------------+
    |Browse For Folder                    [X]|
    +----------------------------------------+
    | Hello, COM(#import) Wolrd!             |
    |                                        |
    | +------------------------------------+ |
    | |[Windows]                           | |
    | | +[addins]                          | |
    | | +[AppCompat]                       | |
    | | +[AppPatch]                        | |
    | | +[assembly]                        | |
    | |     :                              | |
    | |     :                              | |
    | |     :                              | |
    | +------------------------------------+ |
    | [Make New Folder]    [  OK  ] [Cancel] |
    +----------------------------------------+
  5. Hello, COM(C++) World!

    Posted on 5月 8th, 2012 by cx20

    COM(C++)

    COM(Component Object Model)はマイクロソフトの提唱するプログラム部品の仕様である。
    COM を用いて開発された部品であれば言語を問わず利用することができる。
    以下は C++ による COM クライアント(事前バインディングならびに実行時バインディング)の例となっている。

    ソースコード(事前バインディング)

    #include <shlobj.h>
     
    int main( int argc, char* argv[] )
    {
        CoInitialize( NULL );
     
        IShellDispatch* pShell;
        CoCreateInstance( CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShell) );
     
        VARIANT vRootFolder;
        VariantInit( &vRootFolder );
        vRootFolder.vt = VT_I4;
        vRootFolder.lVal = ssfWINDOWS;
     
        Folder* pFolder;
        pShell->BrowseForFolder( 0, L"Hello, COM(C++) World!", 0, vRootFolder, &pFolder );
        VariantClear( &vRootFolder );
        if ( pFolder != NULL )
        {
            pFolder->Release();
        }
        pShell->Release();
     
        CoUninitialize();
     
        return 0;
    }

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

    C:¥> cl hello.cpp /link ole32.lib

    ソースコード(実行時バインディング)

    #include <ole2.h>
     
    int main( int argc, char* argv[] )
    {
        CoInitialize( NULL );
     
        CLSID clsid;
        CLSIDFromProgID( L"Shell.Application", &clsid );
        IDispatch* pShell;
        CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pShell) );
     
        DISPID dispid;
        OLECHAR* ptName = L"BrowseForFolder";
        pShell->GetIDsOfNames( IID_NULL, &ptName, 1, GetUserDefaultLCID(), &dispid );
     
        DISPPARAMS param = { NULL, NULL, 0, 0 };
        VARIANT varg[4];
        VariantInit( &varg[0] );
        varg[0].vt = VT_I4;
        varg[0].lVal = 36L;  // ssfWINDOWS 
     
        VariantInit( &varg[1] );
        varg[1].vt = VT_I4;
        varg[1].lVal = 0L;
     
        VariantInit( &varg[2] );
        varg[2].vt = VT_BSTR;
        varg[2].bstrVal = SysAllocString(L"Hello, COM(C++) World!"); 
     
        VariantInit( &varg[3] );
        varg[3].vt = VT_I4;
        varg[3].lVal = 0L;
     
        param.cArgs = 4;
        param.rgvarg = varg;
     
        VARIANT vResult;
        pShell->Invoke( dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, &param, &vResult, NULL, NULL );
     
        VariantClear( &varg[0] );
        VariantClear( &varg[1] );
        VariantClear( &varg[2] );
        VariantClear( &varg[3] );
     
        IDispatch* pFolder = V_DISPATCH( &vResult );
        if ( pFolder != NULL )
        {
            pFolder->Release();
        }
        pShell->Release();
     
        CoUninitialize();
    }

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

    C:¥> cl hello.cpp /link ole32.lib oleaut32.lib

    以下は、コンパイラ COM サポートクラス(comdef.h で定義されている)を使用した例となっている。

    ソースコード(実行時バインディング)

    #include <comdef.h>
     
    int main( int argc, char* argv[] )
    {
        CoInitialize( NULL );
     
        IDispatchPtr pShell( L"Shell.Application" );
     
        DISPID dispid;
        OLECHAR* ptName = L"BrowseForFolder";
        pShell->GetIDsOfNames( IID_NULL, &ptName, 1, GetUserDefaultLCID(), &dispid );
     
        DISPPARAMS param = { NULL, NULL, 0, 0 };
        _variant_t varg[4];
        varg[0] = 36L;  // ssfWINDOWS 
        varg[1] = 0L;
        varg[2] = L"Hello, COM(C++) World!"; 
        varg[3] = 0L;
     
        param.cArgs = 4;
        param.rgvarg = varg;
     
        _variant_t vResult;
        pShell->Invoke( dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, &param, &vResult, NULL, NULL );
     
        IDispatchPtr pFolder = V_DISPATCH(&vResult);
        if ( pFolder != NULL )
        {
            pFolder = NULL;
        }
        pShell = NULL;
     
        CoUninitialize();
    }

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

    C:¥> cl hello.cpp

    実行結果

    +----------------------------------------+
    |Browse For Folder                    [X]|
    +----------------------------------------+
    | Hello, COM(C++) Wolrd!                 |
    |                                        |
    | +------------------------------------+ |
    | |[Windows]                           | |
    | | +[addins]                          | |
    | | +[AppCompat]                       | |
    | | +[AppPatch]                        | |
    | | +[assembly]                        | |
    | |     :                              | |
    | |     :                              | |
    | |     :                              | |
    | +------------------------------------+ |
    | [Make New Folder]    [  OK  ] [Cancel] |
    +----------------------------------------+
  6. Hello, COM(C言語) World!

    Posted on 5月 7th, 2012 by cx20

    COM(C言語)

    COM(Component Object Model)はマイクロソフトの提唱するプログラム部品の仕様である。
    COM を用いて開発された部品であれば言語を問わず利用することができる。
    以下は C言語による COM クライアント(事前バインディングならびに実行時バインディング)の例となっている。
    ここでは Windows 標準のプログラム部品である Shell.Application(Shell オブジェクト)の呼出しを例としてる。

    ソースコード(事前バインディング)

    #include <shlobj.h>
     
    int main( int argc, char* argv[] )
    {
        HRESULT hResult;
        IShellDispatch* pShell;
        VARIANT vRootFolder;
        Folder* pFolder;
     
        CoInitialize( NULL );
     
        CoCreateInstance( &CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, &IID_IShellDispatch, (void**)&pShell );
     
        VariantInit( &vRootFolder );
        vRootFolder.vt = VT_I4;
        vRootFolder.lVal = ssfWINDOWS;
     
        pShell->lpVtbl->BrowseForFolder( (void*)pShell, 0, L"Hello, COM World!", 0, vRootFolder, &pFolder );
        VariantClear( &vRootFolder );
        if ( pFolder != NULL )
        {
            pFolder->lpVtbl->Release( (void*)pFolder );
        }
        pShell->lpVtbl->Release( (void*)pShell );
     
        CoUninitialize();
     
        return 0;
    }

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

    C:¥> cl hello.c /link ole32.lib

    ソースコード(実行時バインディング)

    #include <ole2.h>
     
    int main( int argc, char* argv[] )
    {
        CLSID clsid;
        IDispatch* pShell;
        IDispatch* pFolder;
        DISPID dispid;
        OLECHAR* ptName = L"BrowseForFolder";
        DISPPARAMS param = { NULL, NULL, 0, 0 };
        VARIANT varg[4];
        VARIANT vResult;
     
        CoInitialize( NULL );
     
        CLSIDFromProgID(L"Shell.Application", &clsid );
        CoCreateInstance( &clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IDispatch, (void**)&pShell);
        pShell->lpVtbl->GetIDsOfNames( (void*)pShell, &IID_NULL, &ptName, 1, GetUserDefaultLCID(), &dispid );
     
        VariantInit( &varg[0] );
        varg[0].vt = VT_I4;
        varg[0].lVal = 36L;  /* ssfWINDOWS */
     
        VariantInit( &varg[1] );
        varg[1].vt = VT_I4;
        varg[1].lVal = 0L;
     
        VariantInit( &varg[2] );
        varg[2].vt = VT_BSTR;
        varg[2].bstrVal = SysAllocString(L"Hello, COM World!"); 
     
        VariantInit( &varg[3] );
        varg[3].vt = VT_I4;
        varg[3].lVal = 0L;
     
        param.cArgs = 4;
        param.rgvarg = varg;
     
        pShell->lpVtbl->Invoke( (void*)pShell, dispid, &IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, &param, &vResult, NULL, NULL );
     
        VariantInit( &varg[0] );
        VariantInit( &varg[1] );
        VariantInit( &varg[2] );
        VariantInit( &varg[3] );
     
        pFolder = V_DISPATCH( &vResult );
        if ( pFolder != NULL )
        {
            pFolder->lpVtbl->Release( (void*)pFolder );
        }
        pShell->lpVtbl->Release( (void*)pShell );
     
        CoUninitialize();
     
        return 0;
    }

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

    C:¥> cl hello.c /link ole32.lib oleaut32.lib

    コンパイル方法(MinGW 版 gcc)

    C:¥> gcc -o hello hello.c -l ole32 -l oleaut32 -l uuid

    実行結果

    +----------------------------------------+
    |Browse For Folder                    [X]|
    +----------------------------------------+
    | Hello, COM Wolrd!                      |
    |                                        |
    | +------------------------------------+ |
    | |[Windows]                           | |
    | | +[addins]                          | |
    | | +[AppCompat]                       | |
    | | +[AppPatch]                        | |
    | | +[assembly]                        | |
    | |     :                              | |
    | |     :                              | |
    | |     :                              | |
    | +------------------------------------+ |
    | [Make New Folder]    [  OK  ] [Cancel] |
    +----------------------------------------+
  7. Hello, Win32 API(Go) World!

    Posted on 5月 6th, 2012 by cx20

    Win32 API(Go)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は Go言語 にて syscall.Syscall 関数を用いた呼出し例である。

    ソースコード

    package main 
     
    import ( 
        "syscall" 
        "unsafe" 
    ) 
     
    var ( 
        user32, _          = syscall.LoadLibrary("user32.dll") 
        procMessageBoxW, _ = syscall.GetProcAddress(user32, "MessageBoxW") 
    )
     
    func MessageBox(hwnd uintptr, text string, caption string, style uintptr) (int32) { 
        ret, _, _ := syscall.Syscall6(
            uintptr(procMessageBoxW), 
            4, 
            hwnd,
            uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), 
            uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))), 
            style, 
            0,
            0 ) 
        return int32(ret)
    } 
     
    func main() { 
        defer syscall.FreeLibrary(user32) 
        MessageBox( 0, "Hello, Win32 API(Go) World!", "Hello, World!", 0 )
    }

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

    Win32 データ型 C/C++ データ型 Go データ型
    HANDLE void * uintptr
    BYTE unsigned char uint8, byte
    SHORT short int16
    WORD unsigned short uint16
    INT int int32, int
    UINT unsigned int uint32
    LONG long int32
    BOOL int int
    DWORD unsigned long uint32
    ULONG unsigned long uint32
    CHAR char byte
    WCHAR wchar_t uint16
    LPSTR char * *byte
    LPCSTR const char * *byte, syscall.StringByPtr()
    LPWSTR wchar_t * *uint16
    LPCWSTR const wchar_t * *uint16, syscall.StringToUTF16Ptr()
    FLOAT float float32
    DOUBLE double float64
    LONGLONG __int64 int64
    DWORD64 unsigned __int64 uint64

    コンパイル方法

    C:¥> SET GOROOT=C:go
    C:¥> go build -ldflags -Hwindowsgui hello.go

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(Go) World!
    ---------------------------
    OK   
    ---------------------------
  8. Hello, Win32 API(Delphi) World!

    Posted on 5月 5th, 2012 by cx20

    Win32 API(Delphi)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は Delphi からの呼出し例である。
    Win32 API の参照方法としては、external 宣言を用いる方法の他、Winapi.Windows ライブラリを用いる方法などがある。

    ソースコード(external 宣言)

    program hello;
     
    function MessageBox(hWnd: THandle; lpText: PAnsiChar; lpCaption: PAnsiChar; uType: Cardinal): Integer;
        stdcall; external 'user32.dll' name 'MessageBoxA';
     
    begin
        MessageBox( 0, 'Hello, Win32 API(Delphi) World!', 'Hello, World!', 0 );
    end.

    ソースコード(Winapi.Windows ライブラリ)

    program hello;
     
    uses
        Windows;
     
    begin
        MessageBox( 0, 'Hello, Win32 API(Delphi) World!', 'Hello, World!', MB_OK );
    end.

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

    Win32 データ型 C/C++ データ型 Delphi データ型
    HANDLE void * THandle
    BYTE unsigned char Byte
    SHORT short Smallint
    WORD unsigned short Word
    INT int Integer
    UINT unsigned int Cardinal
    LONG long Integer
    BOOL int LongBool
    DWORD unsigned long LongWord
    ULONG unsigned long LongWord
    CHAR char AnsiChar
    WCHAR wchar_t WideChar, Char
    LPSTR char * PAnsiChar
    LPCSTR const char * PAnsiChar
    LPWSTR wchar_t * PWideChar, PChar
    LPCWSTR const wchar_t * PWideChar, PChar
    FLOAT float Single
    DOUBLE double Double
    LONGLONG __int64 Int64
    DWORD64 unsigned __int64 UInt64

    コンパイル方法(Delphi XE2)

    C:¥> dcc32 hello.pas

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(Delphi) World!
    ---------------------------
    OK   
    ---------------------------
  9. Hello, Win32 API(D言語) World!

    Posted on 5月 4th, 2012 by cx20

    Win32 API(D言語)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は D言語 からの呼出し例である。
    D言語では、Platform SDK のヘッダファイル相当のものがプロトタイプ宣言されている為、基本的な Win32 API であれば、C/C++ の場合と同様に、呼び出すことが可能となっている。

    ソースコード

    import std.c.windows.windows;
     
    int main( char[][] args )
    {
        MessageBoxA( null, "Hello, Win32 API(D) World!", "Hello, World!", MB_OK );
        return 0;
    }

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

    extern (Windows)
    {
          :
    int MessageBoxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);
    int MessageBoxW(HWND hWnd, LPCWSTR lpText, LPCWSTR lpCaption, UINT uType);
          :
    }

    また、Win32 データ型に関しても、同じ名前の型が、D言語用に定義されている為、特段、言語の差異を意識することなく使うことが可能となっている。

    Win32 データ型 C/C++ データ型 D言語データ型
    HANDLE void * void *
    BYTE unsigned char ubyte
    SHORT short short
    WORD unsigned short ushort
    INT int int
    UINT unsigned int uint
    LONG long int
    BOOL int int
    DWORD unsigned long uint
    ULONG unsigned long uint
    CHAR char char
    WCHAR wchar_t wchar
    LPSTR char * char *
    LPCSTR const char * const(char) *
    LPWSTR wchar_t * wchar *
    LPCWSTR const wchar_t * const(wchar) *
    FLOAT float float
    DOUBLE double double
    LONGLONG __int64 long
    DWORD64 unsigned __int64 ulong

    コンパイル方法(Digital Mars D コンパイラ)

    C:¥> dmd hello.d

    実行結果

    ---------------------------
    Hello, World!
    ---------------------------
    Hello, Win32 API(D) World!
    ---------------------------
    OK   
    ---------------------------
  10. Hello, Win32 API(JNI) World!

    Posted on 5月 3rd, 2012 by cx20

    Win32 API(JNI)

    Win32 API は、Windows の機能にアクセスする為の API(Application Programming Interface)である。
    以下は JNI(Java Native Interface)による呼出し例である。
    Java からは 直接、Win32 API を呼び出すことは出来ないが、JNI 用の DLL を作成することで呼び出すことが可能となっている。

    ソースコード(Java)

    import java.io.*;
     
    public class Hello {
        static {
            System.loadLibrary("Hello");
        }
     
        public native int MessageBox( int hwnd, String text, String title, int type );
     
        public static void main(String args[]) {
            Hello hello = new Hello();
            hello.MessageBox( 0, "Hello, Win32 API(JNI) World!", "Hello, World!", 0 );
        }
    }

    C ヘッダファイル作成

    C:¥> javah -jni Hello

    ソースコード(C ヘッダファイル)

    /* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class Hello */
     
    #ifndef _Included_Hello
    #define _Included_Hello
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     Hello
     * Method:    MessageBox
     * Signature: (ILjava/lang/String;Ljava/lang/String;I)I
     */
    JNIEXPORT jint JNICALL Java_Hello_MessageBox
      (JNIEnv *, jobject, jint, jstring, jstring, jint);
     
    #ifdef __cplusplus
    }
    #endif
    #endif

    ソースコード(C 実装ファイル)

    #include "Hello.h"
    #include <windows.h>
     
    /*
     * Class:     Hello
     * Method:    MessageBox
     * Signature: (ILjava/lang/String;Ljava/lang/String;I)I
     */
    JNIEXPORT jint JNICALL Java_Hello_MessageBox
      (JNIEnv* env, jobject me, jint hwnd, jstring text, jstring caption, jint type)
    {
    #ifdef UNICODE
        const jchar* _text = env->GetStringChars(text, 0); 
        const jchar* _caption = env->GetStringChars(caption, 0); 
        const int result = MessageBoxW(NULL, (LPCWSTR)_text, (LPCWSTR)_caption, type); 
        env->ReleaseStringChars(text, _text); 
        env->ReleaseStringChars(caption, _caption); 
    #else
        /* このコードはマルチバイト文字(MBCS)を考慮していない為、全角文字列を渡した場合に文字化けする。正しくは SJIS に変換する処理が必要。*/
        const char* _text = env->GetStringUTFChars(text, 0); 
        const char* _caption = env->GetStringUTFChars(caption, 0); 
        const int result = MessageBoxA(NULL, (LPCSTR)_text, (LPCSTR)_caption, type); 
        env->ReleaseStringUTFChars(text, _text); 
        env->ReleaseStringUTFChars(caption, _caption); 
    #endif
        return result; 
    }

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

    Win32 データ型 C/C++ データ型 JNI データ型 Java データ型
    BOOL int jboolean boolean
    BYTE char jbyte byte
    WCHAR wchar_t jchar char
    SHORT short jshort short
    INT int jint int
    LONGLONG __int64 jlong long
    FLOAT float jfloat float
    DOUBLE double jdouble double
    VOID void void void
    LPCSTR const char * jstring string
    LPCWSTR const wchar_t * jstring string

    なお、jstring については、使用時に、正しい C/C++ データ型(ANSI, MBCS / UNICODE)に適宜、変換する必要がある。

    DLL作成(Visual C++)

    C:¥> SET INCLUDE=%JAVA_HOME%include;%JAVA_HOME%includewin32;%INCLUDE%
    C:¥> cl Hello.cpp /LD /link user32.lib

    コンパイル&実行方法

    C:¥> javac Hello.java
    C:¥> java Hello

    実行結果

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