DDEのラッパクラス群 (CDde, CDdeData, CDdeClient, CDdeServer)

(2007.05.15)
#pragma once
 
// WAC.com Class Liblary for Visual C++
// Copyright (C) WAC.com Inc. All rights reserved.
//
// This file is a part of the WAC.com Class Liblary.
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.TXT at the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by
// the terms of this license. You must not remove this notice, or
// any other, from this software.
 
// '04.12.01 : コードの整備 (sha)
// '04.12.30 : コードの整備 (sha)
// '06.03.22 : atlrx.hのワーニング対策 (sha)
// '06.03.23 : UNICODEビルドに対応 (sha)
// '06.09.28 : UNICODEビルドに対応 (sha)
// '06.10.13 : CAtlRegExpをUNICODEで処理するようにした (his)
// '07.04.05 : WAC1316 : AppVerifierエラー mdxファイルをダブルクリックして起動したときのエラーに対応(imatsu)
// '07.04.20 : x64対応 (sha)
// '07.05.09 : コードの整備 (sha)
// '07.05.15 : 依存関係の最小化 (sha)
 
#include <vector>
 
#include <ddeml.h>
 
#pragma warning(disable: 4018)
#include <atlrx.h>
#pragma warning(default: 4018)
 
 
/////////////////////////////////////////////////////////////////////////////
// CDde
// DDEの単純なラッパクラス
 
class CDde
{
public:
    CDde()
    {
        m_idInst = 0;
    }
    CDde(DWORD idInst)
    {
        m_idInst = idInst;
    }
    virtual ~CDde()
    {
    }
 
public:
    bool IsValid()
    {
        if(m_idInst == 0)
        {
            return false;
        }
 
        return true;
    }
 
public:
    void Attach(DWORD idInst)
    {
        ATLASSERT(m_idInst == 0);
        ATLASSERT(idInst != 0);
        m_idInst = idInst;
    }
    DWORD Detach()
    {
        DWORD idInst = m_idInst;
        m_idInst = 0;
        return idInst;
    }
 
public:
    CDde& operator=(DWORD idInst)
    {
        m_idInst = idInst;
        return *this;
    }
    operator DWORD()
    { 
        return m_idInst; 
    }
 
public:
    UINT DdeInitialize(PFNCALLBACK pfnCallback, DWORD afCmd, DWORD ulRes)
    {
//        ATLASSERT(m_idInst);
        return ::DdeInitialize(&m_idInst, pfnCallback, afCmd, ulRes);
    }
    BOOL DdeUninitialize()
    {
        ATLASSERT(m_idInst);
        DWORD idInst = m_idInst;
        m_idInst = 0;
        return ::DdeUninitialize(idInst);
    }
/*
    HSZ DdeCreateStringHandle(LPCTSTR psz, int iCodePage)
    {
        ATLASSERT(m_idInst);
        return ::DdeCreateStringHandle(m_idInst, psz, iCodePage);
    }
*/
    HSZ DdeCreateStringHandle(LPCTSTR psz)
    {
        ATLASSERT(m_idInst);
#ifdef UNICODE
        int iCodePage = CP_WINUNICODE;
#else
        int iCodePage = CP_WINANSI;
#endif
        return ::DdeCreateStringHandle(m_idInst, psz, iCodePage);
    }
    BOOL DdeFreeStringHandle(HSZ hsz)
    {
        ATLASSERT(m_idInst);
        return ::DdeFreeStringHandle(m_idInst, hsz);
    }
    HDDEDATA DdeNameService(HSZ hsz1, HSZ hsz2, UINT afCmd)
    {
        ATLASSERT(m_idInst);
        return ::DdeNameService(m_idInst, hsz1, hsz2, afCmd);
    }
    HCONV DdeConnect(HSZ hszService, HSZ hszTopic, PCONVCONTEXT pCC)
    {
        ATLASSERT(m_idInst);
        return ::DdeConnect(m_idInst, hszService, hszTopic, pCC);
    }
    HCONVLIST DdeConnectList(HSZ hszService, HSZ hszTopic, HCONVLIST hConvList, PCONVCONTEXT pCC)
    {
        ATLASSERT(m_idInst);
        return ::DdeConnectList(m_idInst, hszService, hszTopic, hConvList, pCC);
    }
    BOOL DdePostAdvise(HSZ hszTopic, HSZ hszItem)
    {
        ATLASSERT(m_idInst);
        return ::DdePostAdvise(m_idInst, hszTopic, hszItem);
    }
    UINT DdeGetLastError()
    {
        ATLASSERT(m_idInst);
        return ::DdeGetLastError(m_idInst);
    }
/*
    DWORD DdeQueryString(HSZ hsz, LPTSTR psz, DWORD cchMax, int iCodePage)
    {
        ATLASSERT(m_idInst);
        return ::DdeQueryString(m_idInst, hsz, psz, cchMax, iCodePage);
    }
*/
    // TODO: CString& 版も作成する
    DWORD DdeQueryString(HSZ hsz, LPTSTR psz, DWORD cchMax)
    {
        ATLASSERT(m_idInst);
#ifdef UNICODE
        int iCodePage = CP_WINUNICODE;
#else
        int iCodePage = CP_WINANSI;
#endif
        return ::DdeQueryString(m_idInst, hsz, psz, cchMax, iCodePage);
    }
    BOOL DdeKeepStringHandle(HSZ hsz)
    {
        ATLASSERT(m_idInst);
        return ::DdeKeepStringHandle(m_idInst, hsz);
    }
    BOOL DdeAbandonTransaction(HCONV hConv, DWORD idTransaction)
    {
        ATLASSERT(m_idInst);
        return ::DdeAbandonTransaction(m_idInst, hConv, idTransaction);
    }
    BOOL DdeEnableCallback(HCONV hConv, UINT wCmd)
    {
        ATLASSERT(m_idInst);
        return ::DdeEnableCallback(m_idInst, hConv, wCmd);
    }
 
public:
    DWORD m_idInst;
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CDdeData
 
class CDdeData
{
public:
    CDdeData()
    {
        m_hData = NULL;
    }
    CDdeData(HDDEDATA hData)
    {
        m_hData = hData;
    }
    virtual ~CDdeData()
    {
    }
 
public:
    bool IsValid()
    {
        if (m_hData == NULL)
        {
            return false;
        }
 
        return true;
    }
 
public:
    void Attach(HDDEDATA hData)
    {
        ATLASSERT(m_hData == NULL);
        ATLASSERT(hData != NULL);
        m_hData = hData;
    }
    HDDEDATA Detach()
    {
        HDDEDATA hData = m_hData;
        m_hData = NULL;
        return hData;
    }
 
public:
    CDdeData& operator=(HDDEDATA hData)
    {
        m_hData = hData;
        return *this;
    }
    operator HDDEDATA()
    { 
        return m_hData; 
    }
 
public:
    // オブジェクト内のデータへのアクセスを開始します
    LPBYTE DdeAccessData(LPDWORD pcbDataSize)
    {
        ATLASSERT(m_hData);
        return ::DdeAccessData(m_hData, pcbDataSize);
    }
    // オブジェクトへのアクセスを終了します。
    // DDE オブジェクトへのアクセスが終わったら、この関数を呼び出してください。
    BOOL DdeUnaccessData()
    {
        ATLASSERT(m_hData);
        return ::DdeUnaccessData(m_hData);
    }
    DWORD DdeGetData(LPBYTE pDst, DWORD cbMax, DWORD cbOff)
    {
        ATLASSERT(m_hData);
        return ::DdeGetData(m_hData, pDst, cbMax, cbOff);
    }
    HDDEDATA DdeAddData(LPBYTE pSrc, DWORD cb, DWORD cbOff)
    {
        ATLASSERT(m_hData);
        return ::DdeAddData(m_hData, pSrc, cb, cbOff);
    }
    BOOL DdeFreeDataHandle()
    {
        ATLASSERT(m_hData);
        HDDEDATA hData = m_hData;
        m_hData = NULL;
        return ::DdeFreeDataHandle(hData);
    }
 
public:
    HDDEDATA m_hData;
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CDdeServer
 
template <class T, class TBase = CDde>
class CDdeServer : public TBase
{
public:
    CDdeServer()
    {
        m_hszService = 0;
//        m_hszTopic = 0;
    }
    virtual ~CDdeServer()
    {
    }
 
public:
    HRESULT Init(DWORD afCmd = APPCLASS_STANDARD, DWORD ulRes = 0)
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == true)
        {
            return E_FAIL;
        }
 
        UINT nr = TBase::DdeInitialize(T::DdeServerCallback, afCmd, ulRes);
        if (nr != DMLERR_NO_ERROR)
        { 
            return E_FAIL;
        } 
 
        return S_OK; 
    }
    void Term()
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
//            ATLASSERT(0);
            return;
        }
 
        BOOL br = TBase::DdeUninitialize();
        if (br != DMLERR_NO_ERROR)
        {
            // 無視する。。
        }
    }
 
public:
    HRESULT RegisterService(LPCTSTR szService)
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        m_hszService = TBase::DdeCreateStringHandle(szService);
//        m_hszTopic = TBase::DdeCreateStringHandle(szTopic);
 
        CDdeData data = TBase::DdeNameService(m_hszService, 0, DNS_REGISTER); 
        if (data.IsValid() == false)
        {
            return E_FAIL;
        }
 
        return S_OK;
    }
    HRESULT UnregisterService()
    { 
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
            return S_FALSE;
        }
 
        CDdeData data = TBase::DdeNameService(m_hszService, 0, DNS_UNREGISTER);
        if (data.IsValid() == false) 
        {
            // 無視する。。
        }
    
        BOOL br = TBase::DdeFreeStringHandle(m_hszService);
        if (br == 0)
        {
            // 無視する。。
        }
 
/*
        br = TBase::DdeFreeStringHandle(m_hszTopic); 
        if (br == 0)
        {
            // 無視する。。
        }
*/
 
        return S_OK; 
    }
 
public:
    // DDEコールバック関数 
    static HDDEDATA CALLBACK DdeServerCallback(
        UINT wType,                                // トランザクション型
        UINT wFmt,                                // クリップボードデータ形式
        HCONV hConv,                            // 対話のハンドル
        HSZ hsz1,                                // 文字列のハンドル
        HSZ hsz2,                                // 文字列のハンドル
        HDDEDATA hData,                            // グローバルメモリオブジェクトのハンドル
        ULONG_PTR dwData1,                        // トランザクション固有データ
        ULONG_PTR dwData2)                        // トランザクション固有データ
    {
        HDDEDATA hDdeData = FALSE;
 
        switch (wType)
        {
__if_exists (T::OnDDeAdvStart)
{
        case XTYP_ADVSTART:
            hDdeData = T::OnDDeAdvStart(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDDeConnect)
{
        case XTYP_CONNECT:
            hDdeData = T::OnDDeConnect(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeAdvReq)
{
        case XTYP_ADVREQ:
            hDdeData = T::OnDdeAdvReq(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeRequest)
{
        case XTYP_REQUEST:
            hDdeData = T::OnDdeRequest(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeWildConnect)
{
        case XTYP_WILDCONNECT:
            hDdeData = T::OnDdeWildConnect(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeAdvData)
{
        case XTYP_ADVDATA:
            hDdeData = T::OnDdeAdvData(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeExecute)
{
        case XTYP_EXECUTE:
            hDdeData = T::OnDdeExecute(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdePoke)
{
        case XTYP_POKE:
            hDdeData = T::OnDdePoke(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeAdvStop)
{
        case XTYP_ADVSTOP:
            hDdeData = T::OnDdeAdvStop(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeConnectConfirm)
{
        case XTYP_CONNECT_CONFIRM:
            hDdeData = T::OnDdeConnectConfirm(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeDisconnect)
{
        case XTYP_DISCONNECT:
            hDdeData = T::OnDdeDisconnect(wFmt, hConv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeError)
{
        case XTYP_ERROR:
            hDdeData = T::OnDdeError(wFmt, hconv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeMonitor)
{
        case XTYP_MONITOR:
            hDdeData = T::OnDdeMonitor(wFmt, hconv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeRegister)
{
        case XTYP_REGISTER:
            hDdeData = T::OnDdeRegister(wFmt, hconv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeXactComplete)
{
        case XTYP_XACT_COMPLETE:
            hDdeData = T::OnDdeXactComplete(wFmt, hconv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeUnregister)
{
        case XTYP_UNREGISTER:
            hDdeData = T::OnDdeUnregister(wFmt, hconv, hsz1, hsz2, hData, dwData1, dwData2);
            break;
}
        default:
            break;
        }
 
        return hDdeData;
    }
 
public:
    HSZ m_hszService;
//    HSZ m_hszTopic;
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CDdeClient
 
template <class T, class TBase = CDde>
class CDdeClient : public TBase
{
public:
    CDdeClient()
    {
        m_hConv = 0;
        m_hszService = 0;
        m_hszTopic = 0;
    }
    virtual ~CDdeClient()
    {
    }
 
public:
    HRESULT Init(DWORD afCmd = APPCMD_CLIENTONLY, DWORD ulRes = 0)
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == true)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        UINT nr = TBase::DdeInitialize(T::DdeClientCallback, afCmd, ulRes);
        if (nr != DMLERR_NO_ERROR) 
        {
            return E_FAIL;
        }
 
        return S_OK;
    }
    void Term()
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
//            ATLASSERT(0);
            return;
        }
 
        BOOL br = TBase::DdeUninitialize(); 
        if (br != DMLERR_NO_ERROR)
        {
            // 無視する。。
        }
    }
 
public:
    HRESULT Connect(LPCSTR szService, LPCSTR szTopic)
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        m_hszService = TBase::DdeCreateStringHandle(szService, CP_WINANSI); 
        m_hszTopic = TBase::DdeCreateStringHandle(szTopic, CP_WINANSI); 
        
        m_hConv = TBase::DdeConnect(m_hszService, m_hszTopic, NULL); 
        UINT nr = TBase::DdeGetLastError();
        if (nr != DMLERR_NO_ERROR)
        {
            return E_FAIL;
        } 
        
        return S_OK;
    }
    HRESULT Disconnect()
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
            return S_FALSE;
        }
 
        if (m_hConv)
        { 
            BOOL br = TBase::DdeFreeStringHandle(m_hszService);
            if (br == 0)
            {
                // 無視する。。
            }
 
            br = TBase::DdeFreeStringHandle(m_hszTopic);
            if (br == 0)
            {
                // 無視する。。
            }
 
            br = TBase::DdeDisconnect(m_hConv);
            if (br == 0)
            {
                // 無視する。。
            }
 
            m_hConv = 0;
        } 
 
        return S_OK; 
    }
 
public:
    HRESULT GetData(LPCSTR szItem, LPBYTE lpData, int nLength)
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        if (m_hConv) 
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        HSZ hszItem = TBase::DdeCreateStringHandle(szItem, CP_WINANSI);
        CDdeData data = ::DdeClientTransaction(NULL, 0, m_hConv, hszItem, CF_TEXT, XTYP_REQUEST, 30000, NULL);
        if (data.IsValid() == false)
        {
            return E_FAIL;
        }
 
        UINT nr = TBase::DdeGetLastError();
        if (nr != DMLERR_NO_ERROR)
        { 
            return E_FAIL;
        } 
 
        data.DdeGetData(lpData, nLength, 0);
        TBase::DdeFreeStringHandle(hszItem); 
        data::DdeFreeDataHandle();
 
        return S_OK;
    }
    HRESULT SetData(LPCSTR szItem, LPBYTE lpData, int nLength)
    {
        bool bIsValid = TBase::IsValid();
        if (bIsValid == false)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        if (!m_hConv)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        HSZ hszItem = TBase::DdeCreateStringHandle(szItem, CP_WINANSI);
 
        DWORD dwResult = 0;
        CDdeData data = ::DdeClientTransaction(lpData, nLength + 1, m_hConv, hszItem, CF_TEXT, XTYP_POKE, 10000, &dwResult); 
        if (data.IsValid() == false)
        {
            return E_FAIL;
        }
        
        UINT nr = TBase::DdeGetLastError();
        if (nr != DMLERR_NO_ERROR)
        {
            return E_FAIL;
        } 
 
        TBase::DdeFreeStringHandle(hszItem);
        TBase::DdeFreeDataHandle();
 
        return S_OK;
    }
 
public:
        // DDEコールバック関数 
    static HDDEDATA CALLBACK DdeClientCallback(
        UINT uType,                                // トランザクション型
        UINT uFmt,                                // クリップボードデータ形式
        HCONV hconv,                            // 対話のハンドル
        HSZ hsz1,                                // 文字列のハンドル
        HSZ hsz2,                                // 文字列のハンドル
        HDDEDATA hdata,                            // グローバルメモリオブジェクトのハンドル
        ULONG_PTR dwData1,                        // トランザクション固有データ
        ULONG_PTR dwData2)                        // トランザクション固有データ
    {
        HDDEDATA hDdeData = FALSE;
    
        switch (uType)
        {
__if_exists (T::OnDDeAdvStart)
{
        case XTYP_ADVSTART:
            hDdeData = T::OnDDeAdvStart(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDDeConnect)
{
        case XTYP_CONNECT:
            hDdeData = T::OnDDeConnect(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeAdvReq)
{
        case XTYP_ADVREQ:
            hDdeData = T::OnDdeAdvReq(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeRequest)
{
        case XTYP_REQUEST:
            hDdeData = T::OnDdeRequest(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeWildConnect)
{
        case XTYP_WILDCONNECT:
            hDdeData = T::OnDdeWildConnect(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeAdvData)
{
        case XTYP_ADVDATA:
            hDdeData = T::OnDdeAdvData(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeExecute)
{
        case XTYP_EXECUTE:
            hDdeData = T::OnDdeExecute(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdePoke)
{
        case XTYP_POKE:
            hDdeData = T::OnDdePoke(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeAdvStop)
{
        case XTYP_ADVSTOP:
            hDdeData = T::OnDdeAdvStop(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeConnectConfirm)
{
        case XTYP_CONNECT_CONFIRM:
            hDdeData = T::OnDdeConnectConfirm(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeDisconnect)
{
        case XTYP_DISCONNECT:
            hDdeData = T::OnDdeDisconnect(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeError)
{
        case XTYP_ERROR:
            hDdeData = T::OnDdeError(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeMonitor)
{
        case XTYP_MONITOR:
            hDdeData = T::OnDdeMonitor(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeRegister)
{
        case XTYP_REGISTER:
            DDeData = T::OnDdeRegister(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeXactComplete)
{
        case XTYP_XACT_COMPLETE:
            hDdeData = T::OnDdeXactComplete(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
__if_exists (T::OnDdeUnregister)
{
        case XTYP_UNREGISTER:
            hDdeData = T::OnDdeUnregister(uFmt, hconv, hsz1, hsz2, hdata, dwData1, dwData2);
            break;
}
        case default:
            break;
        }
 
        return hDdeData;
    }
 
public:
    HCONV m_hConv; 
    HSZ m_hszService;
    HSZ m_hszTopic;
};
 
 
/////////////////////////////////////////////////////////////////////////////
// CDdeHelper
 
 
class CDdeHelper
{
protected:
    typedef CDdeHelper                            thisClass;
 
protected:
    CDdeHelper();                                // 実装しない
    virtual ~CDdeHelper();
 
public:
    typedef std::pair<CString, CString>            CDdeMessage;
    static HRESULT ParseDdeCommand(LPCTSTR szBuffer, std::vector<CDdeMessage>& ddeMessages)
    {
        if (szBuffer == NULL)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        HRESULT hr = S_OK;
 
        ddeMessages.clear();
 
        // メッセージの分割 [command("")] 形式
        std::vector<CString> strDdeMessages;
        hr = thisClass::SplitDdeMessage(szBuffer, strDdeMessages);    
        if (FAILED(hr))
        {
            return hr;
        }
 
        for (int i = 0; i < (int)strDdeMessages.size() ; i++)
        {
            CString& strDdeMessage = strDdeMessages[i];
 
            // メッセージのパース
            CDdeMessage ddeMessage;
            hr = thisClass::ParseDdeMessage(strDdeMessage, ddeMessage);
            if (FAILED(hr))
            {
                // 無視する。。
                continue;
            }
 
            ddeMessages.push_back(ddeMessage);
        }
 
        return hr;
    }
    // メッセージの分割 [command("","",.....)] 形式
    static HRESULT SplitDdeMessage(LPCTSTR szBuffer, std::vector<CString>& strDdeMessages)
    {
        USES_CONVERSION;
 
        if (szBuffer == NULL)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        HRESULT hr = S_OK;
 
        strDdeMessages.clear();
 
#if 1
        // NOTE: 日本語を使用する場合UNICODEで処理しないと落ちる
        CAtlRegExp<CAtlRECharTraitsW> regExp;
 
        CStringW strRE = L"\\[{.+}\\]+";
        if (regExp.Parse(strRE, FALSE) != REPARSE_ERROR_OK)
        {
            return E_FAIL;
        }
 
        CStringW strBuffer = T2W((LPTSTR)szBuffer);
        CAtlREMatchContext<CAtlRECharTraitsW> context;
        while (regExp.Match(strBuffer, &context))
        {
            CStringW strDdeMessage = context.m_Match.szStart;
            int nLength = (int)(context.m_Match.szEnd - context.m_Match.szStart);
            strDdeMessage = strDdeMessage.Mid (1, nLength - 2);
            strDdeMessages.push_back(W2T((LPWSTR)(LPCWSTR)strDdeMessage));
 
            if (strBuffer.GetBuffer() + strBuffer.GetLength() <= context.m_Match.szEnd)
            {
                // szEnd は、一致グループの末尾より 1 文字後ろの位置を指します。
                break;
            }
 
            strBuffer = context.m_Match.szEnd;
        }
#else 
        // 1コマンド限定処理
        CString strBuffer = szBuffer;
        int nLength = strBuffer.GetLength();
        if (nLength < 2)
        {
            return E_FAIL;
        }
        strBuffer.Mid(1, strBuffer.GetLength() - 2);
        strDdeMessages.push_back(strBuffer);
#endif
 
        return S_OK;
    }
    // メッセージのパース
    static HRESULT ParseDdeMessage(LPCTSTR szDdeMessage, CDdeMessage& ddeMessage)
    {
        USES_CONVERSION;
 
        if (szDdeMessage == NULL)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        HRESULT hr = S_OK;
 
        ddeMessage.first.Empty();
        ddeMessage.second.Empty();
 
        // NOTE: 日本語を使用する場合UNICODEで処理しないと落ちる
        CAtlRegExp<CAtlRECharTraitsW> regExp;
 
        CStringW strRE = L"{\\a+}\\({.+}\\)";
        if (regExp.Parse(strRE, FALSE) != REPARSE_ERROR_OK)
        {
            return E_FAIL;
        }
 
        CStringW strDdeMessage = T2W((LPTSTR)szDdeMessage);
        CAtlREMatchContext<CAtlRECharTraitsW> context;
        if (regExp.Match(strDdeMessage, &context))
        {
            const CAtlREMatchContext<CAtlRECharTraitsW>::RECHAR* szStart = NULL;
            const CAtlREMatchContext<CAtlRECharTraitsW>::RECHAR* szEnd = NULL;
 
            context.GetMatch(0, &szStart, &szEnd); 
            CStringW strTemp = szStart;
            ddeMessage.first = W2T((LPWSTR)(LPCWSTR)(strTemp.Mid(0, (int)(szEnd - szStart))));
 
            context.GetMatch(1, &szStart, &szEnd);
            strTemp = szStart;
            ddeMessage.second = W2T((LPWSTR)(LPCWSTR)(strTemp.Mid(0, (int)(szEnd - szStart))));
        }
 
        return S_OK;
    }
    // パラメータを","ごとに分割
    static HRESULT SplitToken(LPCTSTR szBuffer, std::vector<CString>& strTokens)
    {
        USES_CONVERSION;
 
        if (szBuffer == NULL)
        {
            ATLASSERT(0);
            return E_FAIL;
        }
 
        HRESULT hr = S_OK;
 
        strTokens.clear();
 
        // NOTE: 日本語を使用する場合UNICODEで処理しないと落ちる
        CAtlRegExp<CAtlRECharTraitsW> regExp;
 
        CStringW strRE = L"\\q";
        if (regExp.Parse(strRE, FALSE) != REPARSE_ERROR_OK)
        {
            return E_FAIL;
        }
 
        CStringW strBuffer = T2W((LPTSTR)szBuffer);
        CAtlREMatchContext<CAtlRECharTraitsW> context;
        while (regExp.Match(strBuffer, &context))
        {
            CStringW strToken = context.m_Match.szStart;
            int nLength = (int)(context.m_Match.szEnd - context.m_Match.szStart);
            strToken = strToken.Mid (0, nLength);
            strTokens.push_back(W2T((LPWSTR)(LPCWSTR)strToken));
 
            if (strBuffer.GetBuffer() + strBuffer.GetLength() <= context.m_Match.szEnd)
            {
                // szEnd は、一致グループの末尾より 1 文字後ろの位置を指します。
                break;
            }
 
            strBuffer = context.m_Match.szEnd;
        }
 
        return S_OK;
    }
 
public:
    // 拡張子の登録
    // TODO: 2度目の登録は大丈夫?
    static HRESULT RegisterShellFileType(LPCTSTR lpszExt, LPCTSTR lpszDesc, int nIconId, LPCTSTR lpszDdeService)
    {
        // 拡張子に"."が無い場合はエラー
        CString strExt = lpszExt;
        int nr = strExt.Find(_T("."));
        if (nr == -1)
        {
            return E_FAIL;
        }
 
        // ".dde" を "dde" にします。
        strExt = strExt.Right(strExt.GetLength() - (nr + 1));
 
        CString strAppPath = thisClass::GetModuleFileName();
        ::GetShortPathName(strAppPath, strAppPath.GetBuffer(), strAppPath.GetLength());
        strAppPath.ReleaseBuffer();
 
        CString strKey;
        CString strValue;
 
        // 拡張子のキーを作成し、その名前なしの値に、拡張子の名前を登録する。
        strKey = lpszExt;
        // "ddefile"になります。
        strValue.Format(_T("%sfile"), strExt);
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, strValue);
    
        // 拡張子のキーを作成し、その日本語の説明を登録する。
        strKey = strValue;
        strValue = lpszDesc;
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, strValue);
 
        // デフォルトアイコンを設定する。
        strKey += _T("\\DefaultIcon");
        strValue.Format(_T("%s,-%d"), strAppPath, nIconId);
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, strValue);
 
        strKey.Format(_T("%sfile\\shell"), strExt);
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, _T(""));
 
        // コマンド名の登録
        strKey.Format(_T("%sfile\\shell\\open"), strExt);
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, _T("open")); // アクション名はopen
 
        // コマンドの内容を登録
        strKey.Format(_T("%sfile\\shell\\open\\Command"), strExt);
        strAppPath = thisClass::GetModuleFileName();
        strValue.Format(_T("\"%s\" \"%%1\""), strAppPath);
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, strValue);
 
        // DDEを登録する。 DDEメッセージ
        strKey.Format(_T("%sfile\\shell\\open\\ddeexec"), strExt);
        strValue = _T("[open(\"%1\")]");
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, strValue);
 
        // DDEのサービス名を登録
        strKey.Format(_T("%sfile\\shell\\open\\ddeexec\\application"), strExt);
        strValue = lpszDdeService;
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, strValue);
 
        // DDEのトピックを登録
        // トピック名の"system"は、登録しなくてもよい。
        strKey.Format(_T("%sfile\\shell\\open\\ddeexec\\topic"), strExt);
        strValue = _T("system");
        thisClass::SHRegSetString(HKEY_CLASSES_ROOT, strKey, NULL, strValue);
 
        return S_OK;
    }
    // 未実装
    static HRESULT UnregisterShellFileType(LPCSTR lpszExt)
    {
        return E_NOTIMPL;
    }
 
protected:
    // RegHelper.h より、コピー
    static DWORD SHRegSetString(
        HKEY hkey,
        LPCTSTR pszSubKey,
        LPCTSTR pszValue,
        LPCTSTR pszData)
    {
        ULONG dwType = REG_SZ;
        DWORD dwResult = ::SHSetValue(            // SHLWAPI 4.71
            hkey,
            pszSubKey,
            pszValue,
            dwType,
            pszData,
            (DWORD)(_tcslen(pszData) * sizeof(TCHAR)));
 
        return dwResult;
    }
    // ModuleFileName.h より、コピー
    static CString GetModuleFileName(HINSTANCE hInstance = NULL)
    {
//        ATLASSERT(hInstance);
 
        TCHAR szResult[_MAX_PATH] = { 0 };
        DWORD dwResult = ::GetModuleFileName(hInstance, szResult, _countof(szResult));
        if (dwResult == 0)
        {
            return _T("");
        }
 
        return szResult;
    }
};
 
一覧に戻る
© 2003 WAC.com All Right Reserved.