EXEサーバ - サンプルCOMサーバ

いちごパック > COM/ActiveXの解説 > EXEサーバ - サンプルCOMサーバ
EXEサーバ - クラスのビルドで説明したサンプルプログラムです。 コード全体をコピーしたい場合は、著作権表示といちごパックへのリンクを残した形でコピーしてください。 サンプルコードとしてその一部を利用、参照いただくぶんには問題ありません。
ヘルパ関数については、説明を簡潔にするために別ページでまとめています。 サンプルで用いたヘルパ関数もあわせてご覧ください。
COMを使う32ビットまたは64ビットプログラムの場合は、リンク時に次のライブラリを与えてください。
kernel32.libuser32.libadvapi32.librpcrt4.libole32.liboleaut32.lib

このコードをVisual C++のプロジェクトとしてビルドしたい場合は、次の準備を行ったうえでビルドしてください。
  • Visual C++ → Win32 → Win32プロジェクトを選択して空のプロジェクトを作成
  • サンプルコードを.cppファイルとして追加
  • プロジェクトのプロパティを開き、リンカの設定でリンク時のライブラリとして上記のライブラリを追加

  • //
    // Copyright (c) 2016 The Ichigopack Project (http://ichigopack.net/).
    //
    
    #include "ichigocomhelper.h"
    #include <olectl.h>
    #include <sstream>
    #include <iomanip>
    #include <string.h>
    #include <new>
    #include <exception>
    
    
    #define LOGFILENAME L"c:\\tmp\\ichigo2.txt"
    
    // {425C76F4-E126-456C-837D-1EE96DB89126}
    static const GUID CLSID_Ichigo2 =
    { 0x425c76f4, 0xe126, 0x456c, { 0x83, 0x7d, 0x1e, 0xe9, 0x6d, 0xb8, 0x91, 0x26 } };
    
    class CIchigo2Factory : public IClassFactory
    {
    public:
        CIchigo2Factory();
        ~CIchigo2Factory();
    
        // IUnknown
        HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID* ppv );
        ULONG STDMETHODCALLTYPE AddRef();
        ULONG STDMETHODCALLTYPE Release();
        // IClassFactory
        HRESULT STDMETHODCALLTYPE CreateInstance( IUnknown* pUnkOuter,
                REFIID riid, LPVOID* ppv );
        HRESULT STDMETHODCALLTYPE LockServer( BOOL fLock );
    };
    
    class CIchigo2 : public ISequentialStream
    {
    public:
        CIchigo2();
        ~CIchigo2();
    
        // IUnknown
        HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID* ppv );
        ULONG STDMETHODCALLTYPE AddRef();
        ULONG STDMETHODCALLTYPE Release();
        // ISequentialStream
        HRESULT STDMETHODCALLTYPE Read( void* pv, ULONG cb, ULONG* pcbRead);
        HRESULT STDMETHODCALLTYPE Write( const void* pv, ULONG cb,
                                         ULONG* pcbWritten);
    private:
        LONG    m_nRef;
    };
    
    /***********************************************************************/
    
    HRESULT RunRegisterServer( HINSTANCE hinstEXE,
                               bool per_user_flag ) throw()
    {
        try {
            std::wstring    wstrName = suppGetModuleFileName( hinstEXE );
            HKEY    hkeyRoot;
            std::wstring    wstrSubkey = suppGetRegKeyCLSID( &hkeyRoot, per_user_flag,
                                         CLSID_Ichigo2, L"LocalServer32" );
            LONG    regerr;
            if ( wstrSubkey.empty() || wstrName.empty() ) {
                return E_FAIL;
            }
            regerr = suppRegSetStringW(hkeyRoot, wstrSubkey.c_str(), NULL,
                                       wstrName.c_str() );
            if ( regerr != ERROR_SUCCESS ) {
                return SELFREG_E_CLASS;
            }
        } catch ( const std::exception& ) {
            return E_FAIL;
        }
        return S_OK;
    }
    
    HRESULT RunUnregisterServer( bool per_user_flag ) throw()
    {
        try {
            HKEY    hkeyRoot;
            std::wstring    wstrSubkey = suppGetRegKeyCLSID( &hkeyRoot, per_user_flag,
                                         CLSID_Ichigo2, NULL );
            LONG    regerr;
            if ( wstrSubkey.empty() ) {
                return E_FAIL;
            }
            regerr = suppRegRemoveKeyW(hkeyRoot, wstrSubkey.c_str());
            if ( regerr != ERROR_SUCCESS ) {
                return SELFREG_E_CLASS;
            }
        } catch ( const std::exception& ) {
            return E_FAIL;
        }
        return S_OK;
    }
    
    /***********************************************************************/
    
    void LockServerProcess()
    {
        CoAddRefServerProcess();
    }
    
    void UnlockServerProcess()
    {
        if ( CoReleaseServerProcess() == 0 ) {
            PostQuitMessage(0);
        }
    }
    
    HRESULT RunEmbedding( HINSTANCE hinstEXE )
    {
        CIchigo2Factory factory;
        HRESULT hr;
        DWORD   dwRegister = 0;
        hr = CoRegisterClassObject(
                 CLSID_Ichigo2, static_cast<IClassFactory*>(&factory),
                 CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED, &dwRegister);
        if ( FAILED(hr) ) {
            return hr;
        }
        hr = CoResumeClassObjects();
        if ( SUCCEEDED(hr) ) {
            MSG msg;
            while (GetMessage(&msg, NULL, 0, 0) > 0) {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
        CoRevokeClassObject(dwRegister);
        return hr;
    }
    
    EXTERN_C int APIENTRY WinMain( HINSTANCE hinstEXE, HINSTANCE hinstNull,
                                   LPSTR lpCmdLine, int nCmdShow )
    {
        HRESULT hr;
        hr = CoInitialize(NULL);
        if ( FAILED(hr) ) {
            MessageBoxW( NULL, L"CoInitialize()", L"IchigoCom2", MB_OK );
            return 1;
        }
        const char* pcommand;
        bool invalid_command = false;
        pcommand = strchr(lpCmdLine, '/');
        if ( pcommand == NULL ) {
            pcommand = strchr(lpCmdLine, '-');
        }
        if ( pcommand == NULL ) {
            invalid_command = true;
        }
        if ( pcommand != NULL ) {
            char* ptoken = _strdup(pcommand + 1);
            if ( ptoken == NULL ) {
                hr = E_OUTOFMEMORY;
            } else {
                strtok( ptoken, " \t\r\n" );
                if ( _stricmp(ptoken, "embedding") == 0 ) {
                    hr = RunEmbedding( hinstEXE );
                } else if ( _stricmp(ptoken, "regserver") == 0 ) {
                    hr = RunRegisterServer( hinstEXE, false );
                } else if ( _stricmp(ptoken, "regserverperuser") == 0 ) {
                    hr = RunRegisterServer( hinstEXE, true );
                } else if ( _stricmp(ptoken, "unregserver") == 0 ) {
                    hr = RunUnregisterServer( false );
                } else if ( _stricmp(ptoken, "unregserverperuser") == 0 ) {
                    hr = RunUnregisterServer( true );
                } else {
                    invalid_command = true;
                }
                free(ptoken);
            }
        }
        CoUninitialize();
        if ( invalid_command ) {
            MessageBoxW( NULL, L"ichigocom2 /regserver|/unregserver", L"IchigoCom2",
                         MB_OK );
            return 1;
        }
        if ( FAILED(hr) ) {
            std::wostringstream wos;
            wos << L"error " << std::hex << std::setfill(L'0') << std::setw(8) << hr;
            MessageBoxW( NULL, wos.str().c_str(), L"IchigoCom2", MB_OK );
            return 1;
        }
        return 0;
    }
    
    /***********************************************************************/
    
    CIchigo2Factory::CIchigo2Factory()
    {
    }
    
    CIchigo2Factory::~CIchigo2Factory()
    {
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo2Factory::QueryInterface( REFIID riid,
            LPVOID* ppv )
    {
        *ppv = NULL;
        if ( riid == IID_IUnknown || riid == IID_IClassFactory ) {
            *ppv = static_cast<IClassFactory*>( this );
            AddRef();
            return S_OK;
        }
        return E_NOINTERFACE;
    }
    
    ULONG STDMETHODCALLTYPE CIchigo2Factory::AddRef()
    {
        return 1;
    }
    
    ULONG STDMETHODCALLTYPE CIchigo2Factory::Release()
    {
        return 1;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo2Factory::CreateInstance(
        IUnknown* pUnkOuter, REFIID riid, LPVOID* ppv )
    {
        *ppv = NULL;
        if ( pUnkOuter != NULL ) {
            return CLASS_E_NOAGGREGATION;
        }
        CIchigo2* pObj = new (std::nothrow) CIchigo2();
        if ( pObj == NULL ) {
            return E_OUTOFMEMORY;
        }
        HRESULT hr = pObj->QueryInterface( riid, ppv );
        pObj->Release();
        return hr;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo2Factory::LockServer( BOOL fLock )
    {
        if ( fLock ) {
            LockServerProcess();
        } else {
            UnlockServerProcess();
        }
        return S_OK;
    }
    
    /***********************************************************************/
    
    CIchigo2::CIchigo2() : m_nRef(1)
    {
        LockServerProcess();
    }
    
    CIchigo2::~CIchigo2()
    {
        UnlockServerProcess();
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo2::QueryInterface( REFIID riid,
            LPVOID* ppv )
    {
        *ppv = NULL;
        if ( riid == IID_IUnknown || riid == IID_ISequentialStream ) {
            *ppv = static_cast<ISequentialStream*>( this );
            AddRef();
            return S_OK;
        }
        return E_NOINTERFACE;
    }
    
    ULONG STDMETHODCALLTYPE CIchigo2::AddRef()
    {
        return ++m_nRef;
    }
    
    ULONG STDMETHODCALLTYPE CIchigo2::Release()
    {
        if ( --m_nRef == 0 ) {
            delete this;
            return 0;
        }
        return m_nRef;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo2::Read( void* pv, ULONG cb,
            ULONG* pcbRead)
    {
        *pcbRead = 0;
        return E_NOTIMPL;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo2::Write( const void* pv, ULONG cb,
            ULONG* pcbWritten)
    {
        return suppLogFileAppendW( LOGFILENAME, pv, cb, pcbWritten );
    }
    
    

    関連ページ

  • COM/ActiveXの解説ページ 目次
  • クラスのビルドと動作確認