#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;
}
};