template <class T>
struct _ATL_NAMESINK_EVENT_ENTRY
{
DISPID dispid;
TCHAR* szDispIdName;
void (__stdcall T::*pfn)(); //method to invoke
_ATL_FUNC_INFO* pInfo;
};
#define BEGIN_NAMESINK_MAP(_class, start_id)\
enum _START_ID { _start_id = start_id };\
static const _ATL_NAMESINK_EVENT_ENTRY<_class>* _GetNameSinkMap()\
{\
typedef _class _atl_event_classtype;\
static const _ATL_NAMESINK_EVENT_ENTRY<_class> namemap[] = {
#define NAMESINK_ENTRY_INFO(dispidName, fn, info) {_start_id + __LINE__, _T(#dispidName), (void (__stdcall _atl_event_classtype::*)())fn, info},
#define END_NAMESINK_MAP() {0, NULL, NULL, NULL} }; return namemap;}
template <class T>
class INameDispEventSimpleImpl
{
public:
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject)
{
if (InlineIsEqualUnknown(iid) || ::InlineIsEqualGUID(iid, IID_IDispatch))
{
if (ppvObject == NULL)
return E_POINTER;
*ppvObject = this;
return S_OK;
}
else
return E_NOINTERFACE;
}
virtual ULONG STDMETHODCALLTYPE AddRef()
{
return 1;
}
virtual ULONG STDMETHODCALLTYPE Release()
{
return 1;
}
STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
{return E_NOTIMPL;}
STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{return E_NOTIMPL;}
STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
LCID lcid, DISPID* rgdispid)
{
HRESULT hr = S_OK;
for (UINT i = 0; i < cNames; ++i)
{
const _ATL_NAMESINK_EVENT_ENTRY<T>* pMap = T::_GetNameSinkMap();
bool found = false;
while (pMap->szDispIdName != NULL)
{
USES_CONVERSION;
if (wcscmp(T2W(pMap->szDispIdName), rgszNames[i]) == 0)
{
rgdispid[i] = pMap->dispid;
found = true;
break;
}
pMap++;
}
if (!found)
{
hr = DISP_E_UNKNOWNNAME;
rgdispid[i] = DISPID_UNKNOWN;
return hr;
}
}
return hr;
}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
LCID lcid, WORD /*wFlags*/, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* /*pexcepinfo*/, UINT* /*puArgErr*/)
{
const _ATL_NAMESINK_EVENT_ENTRY<T>* pMap = T::_GetNameSinkMap();
const _ATL_NAMESINK_EVENT_ENTRY<T>* pFound = NULL;
void (__stdcall T::*pEvent)() = NULL;
while (pMap->szDispIdName != NULL)
{
if (pMap->dispid == dispidMember)
{
pFound = pMap;
break;
}
pMap++;
}
if (pFound == NULL || pFound->pInfo == NULL)
return S_OK;
InvokeFromFuncInfo(pFound->pfn, *pFound->pInfo, pdispparams, pvarResult);
return S_OK;
}
HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(), _ATL_FUNC_INFO& info, DISPPARAMS* pdispparams, VARIANT* pvarResult)
{
T* pT = static_cast<T*>(this);
VARIANTARG** pVarArgs = info.nParams ? (VARIANTARG**)alloca(sizeof(VARIANTARG*)*info.nParams) : 0;
for (int i=0; i<info.nParams; i++)
pVarArgs[i] = &pdispparams->rgvarg[info.nParams - i - 1];
CComStdCallThunk<T> thunk;
thunk.Init(pEvent, pT);
CComVariant tmpResult;
if (pvarResult == NULL)
pvarResult = &tmpResult;
HRESULT hr = DispCallFunc(
&thunk,
0,
info.cc,
info.vtReturn,
info.nParams,
info.pVarTypes,
pVarArgs,
pvarResult);
ATLASSERT(SUCCEEDED(hr));
return hr;
}
};
应用
class CScriptEventHandler
: public INameDispEventSimpleImpl<CScriptEventHandler>
{
public:
explicit CScriptEventHandler(CMainFrame* owner)
: owner_(owner)
{
}
BEGIN_NAMESINK_MAP(CScriptEventHandler, 0)
NAMESINK_ENTRY_INFO(Output, &Output, &Output_Info)
NAMESINK_ENTRY_INFO(GetVer, &GetVer, &StringOut_Info)
NAMESINK_ENTRY_INFO(GetMacValue, &GetMacValue, &StringOut_Info)
NAMESINK_ENTRY_INFO(EncryptCode, &EncryptCode, &StringInOut_Info)
NAMESINK_ENTRY_INFO(callapi, &CallAPI, &CallAPI_Info)
NAMESINK_ENTRY_INFO(CreateActiveXObject, &CreateObject, &CreateActiveXObject_Info)
NAMESINK_ENTRY_INFO(GetAppPath$, &GetAppPath, &StringOut_Info)
NAMESINK_ENTRY_INFO(GetAppFullPath, &GetAppFullPath, &StringOut_Info)
NAMESINK_ENTRY_INFO(GetResourceFile, &GetResourceFile, &StringOut_Info)
NAMESINK_ENTRY_INFO(GetParentProcess, &GetParentProcess, &StringOut_Info)
NAMESINK_ENTRY_INFO(CreateShortcut, &CreateShortcut, &CreateDesktopShortcut_Info)
END_NAMESINK_MAP()
public:
CMainFrame* owner_;
static _ATL_FUNC_INFO Output_Info;
static _ATL_FUNC_INFO OpenGameWindow_Info;
static _ATL_FUNC_INFO StringOut_Info;
static _ATL_FUNC_INFO StringInOut_Info;
static _ATL_FUNC_INFO CallAPI_Info;
static _ATL_FUNC_INFO CreateActiveXObject_Info;
static _ATL_FUNC_INFO CreateDesktopShortcut_Info;
static _ATL_FUNC_INFO Void_Info;
static _ATL_FUNC_INFO SetStartRun_Info;
void __stdcall Output(BSTR strInfo);
void __stdcall OnOpenGameWindow(BSTR strUrl, BSTR strInfo, BOOL bFullScreen);
BSTR __stdcall GetVer();
BSTR __stdcall GetMacValue();
BSTR __stdcall EncryptCode(BSTR strInfo);
LONG __stdcall CallAPI(BSTR libName, BSTR funcName, VARIANT params);
IDispatch* __stdcall CreateObject(BSTR objId);
BSTR __stdcall GetAppPath();
BSTR __stdcall GetAppFullPath();
BSTR __stdcall GetResourceFile();
BSTR __stdcall GetParentProcess();
UINT __stdcall CreateShortcut(BSTR target, BSTR name, BSTR iconPath, UINT iconIndex);
void __stdcall PlayIcon();
LONG __stdcall SetStartRun(BSTR name, BSTR cmd);
BSTR __stdcall GetStartRun(BSTR name);
};
实现:
ATL::_ATL_FUNC_INFO CScriptEventHandler::Output_Info = { CC_STDCALL, VT_EMPTY, 1, { VT_BSTR} };
ATL::_ATL_FUNC_INFO CScriptEventHandler::OpenGameWindow_Info = { CC_STDCALL, VT_EMPTY, 3, { VT_BSTR, VT_BSTR, VT_BOOL } };
ATL::_ATL_FUNC_INFO CScriptEventHandler::StringOut_Info = { CC_STDCALL, VT_BSTR, 0, { 0 } };
ATL::_ATL_FUNC_INFO CScriptEventHandler::StringInOut_Info = { CC_STDCALL, VT_BSTR, 1, { VT_BSTR } };
ATL::_ATL_FUNC_INFO CScriptEventHandler::CallAPI_Info = { CC_STDCALL, VT_UI4, 3, { VT_BSTR, VT_BSTR, VT_VARIANT } };
ATL::_ATL_FUNC_INFO CScriptEventHandler::CreateActiveXObject_Info = { CC_STDCALL, VT_DISPATCH, 1, { VT_BSTR } };
ATL::_ATL_FUNC_INFO CScriptEventHandler::CreateDesktopShortcut_Info = { CC_STDCALL, VT_UI4, 4, { VT_BSTR, VT_BSTR, VT_BSTR, VT_UI4 } };
ATL::_ATL_FUNC_INFO CScriptEventHandler::Void_Info = { CC_STDCALL, VT_EMPTY, 0, { 0 } };
ATL::_ATL_FUNC_INFO CScriptEventHandler::SetStartRun_Info = { CC_STDCALL, VT_UI4, 2, { VT_BSTR, VT_BSTR } };
void __stdcall CScriptEventHandler::OnOpenGameWindow(BSTR strUrl, BSTR strInfo, BOOL bFullScreen)
{
if (owner_)
owner_->OnOpenGameWindow(strUrl, strInfo, bFullScreen);
}
BSTR __stdcall CScriptEventHandler::GetVer()
{
TCHAR file[MAX_PATH] = {0};
::GetModuleFileName(_Module.GetModuleInstance(), file, MAX_PATH);
DWORD nSize = ::GetFileVersionInfoSize(file, NULL);
LPVOID pData = malloc(nSize);
::GetFileVersionInfo(file, 0, nSize, pData);
VS_FIXEDFILEINFO* pFileInfo = NULL;
UINT n;
::VerQueryValue(pData, _T("\\"), (LPVOID*)&pFileInfo, &n);
CString str;
str.Format(_T("%d.%d.%d.%d"),
pFileInfo->dwFileVersionMS >> 16 & 0xFFFF,
pFileInfo->dwFileVersionMS & 0xFFFF,
pFileInfo->dwFileVersionLS >> 16 & 0xFFFF,
pFileInfo->dwFileVersionLS & 0xFFFF);
return str.AllocSysString();
}
void __stdcall CScriptEventHandler::Output(BSTR strInfo)
{
ATLTRACE(_T("***Web Output: %s\n"), strInfo);
}
BSTR __stdcall CScriptEventHandler::GetMacValue()
{
return GetMacAddress();
}
BSTR __stdcall CScriptEventHandler::EncryptCode(BSTR strInfo)
{
return EncodeInfo(strInfo);
}
LONG __stdcall CScriptEventHandler::CallAPI(BSTR libName, BSTR funcName, VARIANT params)
{
return CallDllFunction(libName, funcName, ¶ms);
}
IDispatch* __stdcall CScriptEventHandler::CreateObject(BSTR objId)
{
IDispatch* ret = NULL;
CLSID clsid;
HRESULT hr = CLSIDFromProgID(objId, &clsid);
if (SUCCEEDED(hr))
hr = ::CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void**)&ret);
return ret;
}
BSTR __stdcall CScriptEventHandler::GetAppPath()
{
CString strPath;
LPTSTR p = strPath.GetBuffer(MAX_PATH);
::GetModuleFileName(_Module.GetModuleInstance(), p, MAX_PATH);
::PathRemoveFileSpec(p);
strPath.ReleaseBuffer();
return strPath.AllocSysString();
}
BSTR __stdcall CScriptEventHandler::GetAppFullPath()
{
CString strPath;
LPTSTR p = strPath.GetBuffer(MAX_PATH);
::GetModuleFileName(_Module.GetModuleInstance(), p, MAX_PATH);
strPath.ReleaseBuffer();
return strPath.AllocSysString();
}
BSTR __stdcall CScriptEventHandler::GetParentProcess()
{
CString str;
HANDLE h = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (h != INVALID_HANDLE_VALUE)
{
DWORD pid = ::GetCurrentProcessId();
PROCESSENTRY32 pe = {0};
pe.dwSize = sizeof(pe);
BOOL b = ::Process32First(h, &pe);
while (b)
{
if (pe.th32ProcessID == pid)
break;
b = ::Process32Next(h, &pe);
}
if (b)
{
pid = pe.th32ParentProcessID;
b = ::Process32First(h, &pe);
while(b)
{
if (pe.th32ProcessID == pid)
{
str = pe.szExeFile;
break;
}
b = ::Process32Next(h, &pe);
}
}
}
return str.AllocSysString();
}
UINT __stdcall CScriptEventHandler::CreateShortcut(BSTR target, BSTR name, BSTR iconPath, UINT iconIndex)
{
USES_CONVERSION;
return CreateDesktopShortcut(OLE2T(target), OLE2T(name), OLE2T(iconPath), iconIndex);
}
BSTR __stdcall CScriptEventHandler::GetResourceFile()
{
TCHAR szFile[MAX_PATH] = {0};
::GetModuleFileName(_Module.GetModuleInstance(), szFile, MAX_PATH);
CString strRes(szFile);
return strRes.AllocSysString();
}
void __stdcall CScriptEventHandler::PlayIcon()
{
RunApplication(kICON);
}
const TCHAR szWinRunKey[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
LONG __stdcall CScriptEventHandler::SetStartRun(BSTR name, BSTR cmd)
{
HKEY keyFolder = {0};
LONG ret = ::RegOpenKey(HKEY_CURRENT_USER, szWinRunKey, &keyFolder);
if (ret != ERROR_SUCCESS) return ret;
USES_CONVERSION;
ret = ::RegSetValueEx(keyFolder, OLE2T(name), 0, REG_SZ, (BYTE*)OLE2T(cmd), wcslen(cmd) * sizeof(TCHAR));
::RegCloseKey(keyFolder);
return ret;
}
BSTR __stdcall CScriptEventHandler::GetStartRun(BSTR name)
{
CString strRet;
HKEY keyFolder = {0};
LONG ret = ::RegOpenKey(HKEY_CURRENT_USER, szWinRunKey, &keyFolder);
if (ret == ERROR_SUCCESS)
{
USES_CONVERSION;
DWORD nSize = 0;
DWORD nType = 0;
::RegQueryValueEx(keyFolder, OLE2T(name), 0, &nType, NULL, &nSize);
if (nType == REG_SZ && nSize > 0)
{
LPTSTR pStr = strRet.GetBuffer(nSize);
::RegQueryValueEx(keyFolder, OLE2T(name), 0, &nType, (LPBYTE)pStr, &nSize);
strRet.ReleaseBuffer();
}
::RegCloseKey(keyFolder);
}
return strRet.AllocSysString();
}