オートメーション - サンプルオートメーションサーバ

いちごパック > COM/ActiveXの解説 > オートメーション - サンプルオートメーションサーバ
今までの説明に基づき、DLLとして実装したオートメーションサーバのサンプルコードを示します。 今回説明していない部分はDLLサーバとしての実装になります。
コード全体をコピーしたい場合は、著作権表示といちごパックへのリンクを残した形でコピーしてください。 サンプルコードとしてその一部を利用、参照いただくぶんには問題ありません。
ヘルパ関数については、説明を簡潔にするために別ページでまとめています。 サンプルで用いたヘルパ関数もあわせてご覧ください。
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 <iostream>
    #include <new>
    #include <exception>
    #include <vector>
    
    
    #define LOGFILENAME L"c:\\tmp\\ichigo3.txt"
    
    #define PROGID_Ichigo3          L"Ichigo3.Logwriter"
    #define DISPID_Ichigo3_Write    1
    
    #define ICHIGO_LOGLINE_MAX      80
    
    HINSTANCE   g_hinstDLL = NULL;
    LONG        g_nLockDLL = 0;
    
    
    // {316E547D-CBB4-495F-A839-DC4414842C8F}
    const CLSID CLSID_Ichigo3 =
    { 0x316e547d, 0xcbb4, 0x495f, { 0xa8, 0x39, 0xdc, 0x44, 0x14, 0x84, 0x2c, 0x8f } };
    #define AppID_Ichigo3 CLSID_Ichigo3
    
    class CIchigo3Factory : public IClassFactory
    {
    public:
        CIchigo3Factory();
        ~CIchigo3Factory();
    
        // 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 );
    private:
        LONG    m_nRef;
    };
    
    class CIchigo3 : public IDispatch
    {
    public:
        CIchigo3();
        ~CIchigo3();
    
        // IUnknown
        HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID* ppv );
        ULONG STDMETHODCALLTYPE AddRef();
        ULONG STDMETHODCALLTYPE Release();
        // IDispatch
        HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT* pcTInfo);
        HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid,
                                              ITypeInfo** ppTInfo);
        HRESULT STDMETHODCALLTYPE GetIDsOfNames(
            REFIID riidNull, LPOLESTR* rgszNames, UINT cNames,
            LCID lcid, DISPID* rgDispId);
        HRESULT STDMETHODCALLTYPE Invoke(
            DISPID dispIdMember, REFIID riidNull, LCID lcid,
            WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
            EXCEPINFO* pExcepInfo, UINT* puArgErr);
    
    private:
        HRESULT Write( BSTR bstrWrite );
    
    private:
        LONG    m_nRef;
    };
    
    /***********************************************************************/
    
    EXTERN_C BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason,
                                  LPVOID pvReserved )
    {
        if ( dwReason == DLL_PROCESS_ATTACH ) {
            g_hinstDLL = hinstDLL;
        }
        return TRUE;
    }
    
    
    EXTERN_C HRESULT STDAPICALLTYPE DllInstall( BOOL bInstall,
            LPCWSTR pwszCmdline )
    {
        const bool per_user_flag = suppIsPerUserRequest( pwszCmdline );
        try {
            HKEY    hkeyRoot;
            std::wstring    wstrSubkey;
            LONG    regerr;
            if ( bInstall ) {
                std::wstring    wstrName = suppGetModuleFileName( g_hinstDLL );
                std::wstring    wstrValue;
                // Coclass
                wstrSubkey = suppGetRegKeyCLSID( &hkeyRoot, per_user_flag, CLSID_Ichigo3,
                                                 L"InprocServer32" );
                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;
                }
                // ProgID
                wstrSubkey = suppGetRegKeyCLSID( &hkeyRoot, per_user_flag, CLSID_Ichigo3,
                                                 L"ProgID" );
                if ( wstrSubkey.empty() ) {
                    return E_FAIL;
                }
                regerr = suppRegSetStringW(hkeyRoot, wstrSubkey.c_str(), NULL,
                                           PROGID_Ichigo3 );
                if ( regerr != ERROR_SUCCESS ) {
                    return SELFREG_E_CLASS;
                }
                wstrSubkey = suppGetRegKeyProgID( &hkeyRoot, per_user_flag,
                                                  PROGID_Ichigo3, L"CLSID" );
                wstrValue = suppGuidToString( CLSID_Ichigo3, true );
                if ( wstrSubkey.empty() || wstrValue.empty() ) {
                    return E_FAIL;
                }
                regerr = suppRegSetStringW(hkeyRoot, wstrSubkey.c_str(), NULL,
                                           wstrValue.c_str() );
                if ( regerr != ERROR_SUCCESS ) {
                    return SELFREG_E_CLASS;
                }
                // AppID
                wstrSubkey = suppGetRegKeyCLSID( &hkeyRoot, per_user_flag, CLSID_Ichigo3,
                                                 NULL );
                wstrValue = suppGuidToString( AppID_Ichigo3, true );
                if ( wstrSubkey.empty() || wstrValue.empty() ) {
                    return E_FAIL;
                }
                regerr = suppRegSetStringW(hkeyRoot, wstrSubkey.c_str(), L"AppID",
                                           wstrValue.c_str() );
                if ( regerr != ERROR_SUCCESS ) {
                    return SELFREG_E_CLASS;
                }
                wstrSubkey = suppGetRegKeyAppID( &hkeyRoot, per_user_flag, AppID_Ichigo3,
                                                 NULL );
                if ( wstrSubkey.empty() ) {
                    return E_FAIL;
                }
                regerr = suppRegSetStringW(hkeyRoot, wstrSubkey.c_str(), L"DllSurrogate",
                                           L"" );
                if ( regerr != ERROR_SUCCESS ) {
                    return SELFREG_E_CLASS;
                }
            } else {
                wstrSubkey = suppGetRegKeyCLSID( &hkeyRoot, per_user_flag, CLSID_Ichigo3,
                                                 NULL );
                if ( wstrSubkey.empty() ) {
                    return E_FAIL;
                }
                regerr = suppRegRemoveKeyW(hkeyRoot, wstrSubkey.c_str());
                if ( regerr != ERROR_SUCCESS ) {
                    return SELFREG_E_CLASS;
                }
                wstrSubkey = suppGetRegKeyProgID( &hkeyRoot, per_user_flag,
                                                  PROGID_Ichigo3, NULL );
                if ( wstrSubkey.empty() ) {
                    return E_FAIL;
                }
                regerr = suppRegRemoveKeyW(hkeyRoot, wstrSubkey.c_str());
                if ( regerr != ERROR_SUCCESS ) {
                    return SELFREG_E_CLASS;
                }
                wstrSubkey = suppGetRegKeyAppID( &hkeyRoot, per_user_flag, AppID_Ichigo3,
                                                 NULL );
                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;
    }
    
    
    EXTERN_C HRESULT STDAPICALLTYPE DllRegisterServer()
    {
        return DllInstall( TRUE, NULL );
    }
    
    EXTERN_C HRESULT STDAPICALLTYPE DllUnregisterServer()
    {
        return DllInstall( FALSE, NULL );
    }
    
    EXTERN_C HRESULT STDAPICALLTYPE DllCanUnloadNow()
    {
        return (g_nLockDLL <= 0) ? S_OK : S_FALSE;
    }
    
    EXTERN_C HRESULT STDAPICALLTYPE DllGetClassObject( REFCLSID rclsid,
            REFIID riid, LPVOID* ppv )
    {
        static CIchigo3Factory g_factory;
        *ppv = NULL;
        if ( rclsid == CLSID_Ichigo3 ) {
            return g_factory.QueryInterface( riid, ppv );
        }
        return CLASS_E_CLASSNOTAVAILABLE;
    }
    
    /***********************************************************************/
    
    CIchigo3Factory::CIchigo3Factory() : m_nRef(0)
    {
    }
    
    CIchigo3Factory::~CIchigo3Factory()
    {
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3Factory::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 CIchigo3Factory::AddRef()
    {
        if (m_nRef++ == 0) {
            ++g_nLockDLL;
        }
        return m_nRef;
    }
    
    ULONG STDMETHODCALLTYPE CIchigo3Factory::Release()
    {
        if (--m_nRef == 0) {
            --g_nLockDLL;
        }
        return m_nRef;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3Factory::CreateInstance(
        IUnknown* pUnkOuter, REFIID riid, LPVOID* ppv )
    {
        *ppv = NULL;
        if ( pUnkOuter != NULL ) {
            return CLASS_E_NOAGGREGATION;
        }
        CIchigo3* pObj = new (std::nothrow) CIchigo3();
        if ( pObj == NULL ) {
            return E_OUTOFMEMORY;
        }
        HRESULT hr = pObj->QueryInterface( riid, ppv );
        pObj->Release();
        return hr;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3Factory::LockServer( BOOL fLock )
    {
        if ( fLock ) {
            ++g_nLockDLL;
        } else {
            --g_nLockDLL;
        }
        return S_OK;
    }
    
    /***********************************************************************/
    
    CIchigo3::CIchigo3() : m_nRef(1)
    {
        ++g_nLockDLL;
    }
    
    CIchigo3::~CIchigo3()
    {
        --g_nLockDLL;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3::QueryInterface( REFIID riid,
            LPVOID* ppv )
    {
        *ppv = NULL;
        if ( riid == IID_IUnknown || riid == IID_IDispatch ) {
            *ppv = static_cast<IDispatch*>( this );
            AddRef();
            return S_OK;
        }
        return E_NOINTERFACE;
    }
    
    ULONG STDMETHODCALLTYPE CIchigo3::AddRef()
    {
        return ++m_nRef;
    }
    
    ULONG STDMETHODCALLTYPE CIchigo3::Release()
    {
        if ( --m_nRef == 0 ) {
            delete this;
            return 0;
        }
        return m_nRef;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3::GetTypeInfoCount(UINT* pcTInfo)
    {
        *pcTInfo = 0;
        return S_OK;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3::GetTypeInfo(UINT iTInfo, LCID lcid,
            ITypeInfo** ppTInfo)
    {
        return E_NOTIMPL;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3::GetIDsOfNames(
        REFIID riidNull, LPOLESTR* rgszNames, UINT cNames,
        LCID lcid, DISPID* rgDispId)
    {
        UINT    iName;
        HRESULT hr = S_OK;
        if ( riidNull != IID_NULL ) {
            return DISP_E_UNKNOWNINTERFACE;
        }
        for ( iName = 0; iName < cNames; ++iName ) {
            DISPID  id = DISPID_UNKNOWN;
            if ( lstrcmpW( rgszNames[iName], L"Write" ) == 0 ) {
                id = DISPID_Ichigo3_Write;
            }
            rgDispId[iName] = id;
            if ( id == DISPID_UNKNOWN ) {
                hr = DISP_E_UNKNOWNNAME;
            }
        }
        return hr;
    }
    
    HRESULT STDMETHODCALLTYPE CIchigo3::Invoke(
        DISPID dispIdMember, REFIID riidNull, LCID lcid,
        WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
        EXCEPINFO* pExcepInfo, UINT* puArgErr)
    {
        UINT    uArgErrTemp;
        if ( puArgErr == NULL ) {
            puArgErr = &uArgErrTemp;
        }
        if ( riidNull != IID_NULL ) {
            return DISP_E_UNKNOWNINTERFACE;
        }
    
        HRESULT hr;
        if ( (wFlags & DISPATCH_METHOD) != 0 &&
             dispIdMember == DISPID_Ichigo3_Write ) {
            if ( pDispParams->cArgs != 1 ) {
                return DISP_E_BADPARAMCOUNT;
            }
            // rgvarg: reverse order
            if ( pDispParams->rgvarg[0].vt != VT_BSTR ) {
                *puArgErr = 0;
                return DISP_E_TYPEMISMATCH;
            }
            hr = Write( pDispParams->rgvarg[0].bstrVal );
        } else {
            return DISP_E_MEMBERNOTFOUND;
        }
        if ( FAILED(hr) ) {
            if ( pExcepInfo != NULL ) {
                pExcepInfo->scode = hr;
                pExcepInfo->wCode = 0;
                pExcepInfo->wReserved = 0;
                pExcepInfo->bstrSource = NULL;
                pExcepInfo->bstrDescription = NULL;
                pExcepInfo->bstrHelpFile = NULL;
                pExcepInfo->dwHelpContext = 0;
                pExcepInfo->pvReserved = NULL;
                pExcepInfo->pfnDeferredFillIn = NULL;
            }
            IErrorInfo* pei = NULL;
            if ( S_OK == GetErrorInfo(0, &pei) ) {
                if ( pExcepInfo != NULL ) {
                    if ( FAILED(pei->GetSource( &pExcepInfo->bstrSource )) )
                        pExcepInfo->bstrSource = NULL;
                    if ( FAILED(pei->GetDescription( &pExcepInfo->bstrDescription )) )
                        pExcepInfo->bstrDescription = NULL;
                    if ( FAILED(pei->GetHelpFile( &pExcepInfo->bstrHelpFile )) )
                        pExcepInfo->bstrHelpFile = NULL;
                    if ( FAILED(pei->GetHelpContext( &pExcepInfo->dwHelpContext )) )
                        pExcepInfo->dwHelpContext = 0;
                }
                pei->Release();
            }
            if ( pExcepInfo != NULL && pExcepInfo->bstrSource == NULL )
                pExcepInfo->bstrSource = SysAllocString( PROGID_Ichigo3 );
            return DISP_E_EXCEPTION;
        }
        return hr;
    }
    
    
    HRESULT CIchigo3::Write( BSTR bstrWrite )
    {
        try {
            UINT    cLen = SysStringLen(bstrWrite);
            if ( cLen >= ICHIGO_LOGLINE_MAX ) {
                HRESULT hr;
                ICreateErrorInfo* pcreateei = NULL;
                IErrorInfo* pei = NULL;
                hr = CreateErrorInfo(&pcreateei);
                if ( SUCCEEDED(hr) ) {
                    pcreateei->SetSource( PROGID_Ichigo3 );
                    pcreateei->SetDescription(
                        L"SysStringLen(bstrWrite) >= ICHIGO_LOGLINE_MAX" );
                    hr = pcreateei->QueryInterface(
                        IID_IErrorInfo, (LPVOID*)&pei );
                    if ( SUCCEEDED(hr) ) {
                        SetErrorInfo(0, pei);
                        pei->Release();
                    }
                    pcreateei->Release();
                }
                return E_INVALIDARG;
            }
    
            std::vector<char>   buf;
            int     cLenMB;
            cLenMB = WideCharToMultiByte(
                CP_ACP, 0, bstrWrite, cLen, NULL,
                0, NULL, NULL );
            if ( cLenMB <= 0 ) {
                return E_FAIL;
            }
            buf.resize( cLenMB );
            cLenMB = WideCharToMultiByte(
                CP_ACP, 0, bstrWrite, cLen, &buf[0],
                buf.size(), NULL, NULL );
            if ( cLenMB <= 0 ) {
                return E_FAIL;
            }
            return suppLogFileAppendW( LOGFILENAME, &buf[0], cLenMB );
        } catch ( const std::exception& ) {
            return E_FAIL;
        }
    }
    
    
    

    関連ページ

  • COM/ActiveXの解説ページ 目次
  • メソッド呼び出しの実装