#include "atlcomcli.h"
#include "atlalloc.h"
#include "comcat.h"
+#include "tchar.h"
#ifdef _MSC_VER
// It is common to use this in ATL constructors. They only store this for later use, so the usage is safe.
#define ATL_NO_VTABLE __declspec(novtable)
#endif
+#ifndef ATL_DEPRECATED
+#define ATL_DEPRECATED __declspec(deprecated)
+#endif
+
#define offsetofclass(base, derived) (reinterpret_cast<DWORD_PTR>(static_cast<base *>(reinterpret_cast<derived *>(_ATL_PACKING))) - _ATL_PACKING)
namespace ATL
LPCOLESTR szData;
};
-HRESULT __stdcall AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule);
-HRESULT __stdcall AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst);
-HRESULT __stdcall AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject);
-void __stdcall AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject);
-void *__stdcall AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule);
-HRESULT __stdcall AtlComModuleGetClassObject(_ATL_COM_MODULE *pComModule, REFCLSID rclsid, REFIID riid, LPVOID *ppv);
+HRESULT WINAPI AtlWinModuleInit(_ATL_WIN_MODULE *pWinModule);
+HRESULT WINAPI AtlWinModuleTerm(_ATL_WIN_MODULE *pWinModule, HINSTANCE hInst);
+HRESULT WINAPI AtlInternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject);
+void WINAPI AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE *pWinModule, _AtlCreateWndData *pData, void *pObject);
+void *WINAPI AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE *pWinModule);
+HRESULT WINAPI AtlComModuleGetClassObject(_ATL_COM_MODULE *pComModule, REFCLSID rclsid, REFIID riid, LPVOID *ppv);
+
+HRESULT WINAPI AtlComModuleRegisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid);
+HRESULT WINAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid);
-HRESULT __stdcall AtlComModuleRegisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid);
-HRESULT __stdcall AtlComModuleUnregisterServer(_ATL_COM_MODULE *mod, BOOL bRegTypeLib, const CLSID *clsid);
+HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags);
+HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module);
template<class TLock>
}
};
+
+template <class T>
+class CAtlExeModuleT : public CAtlModuleT<T>
+{
+public:
+ DWORD m_dwMainThreadID;
+ //DWORD m_dwTimeOut;
+ //DWORD m_dwPause;
+ //bool m_bDelayShutdown;
+
+ CAtlExeModuleT()
+ :m_dwMainThreadID(::GetCurrentThreadId())
+ {
+ }
+
+ ~CAtlExeModuleT()
+ {
+ }
+
+ int WinMain(int nShowCmd)
+ {
+ HRESULT hr = T::InitializeCom();
+ if (FAILED(hr))
+ return hr;
+
+ T* pThis = static_cast<T*>(this);
+
+ LPCTSTR lpCommandLine = GetCommandLine();
+ if (pThis->ParseCommandLine(lpCommandLine, &hr))
+ {
+ hr = pThis->Run(nShowCmd);
+ }
+
+ T::UninitializeCom();
+ return hr;
+ }
+
+
+ HRESULT Run(int nShowCmd = SW_HIDE)
+ {
+ HRESULT hr = S_OK;
+
+ T* pThis = static_cast<T*>(this);
+ hr = pThis->PreMessageLoop(nShowCmd);
+
+ if (hr == S_OK)
+ {
+ pThis->RunMessageLoop();
+ hr = pThis->PostMessageLoop();
+ }
+
+ return hr;
+ }
+
+ LONG Lock()
+ {
+ return CoAddRefServerProcess();
+ }
+
+ LONG Unlock()
+ {
+ LONG lRet = CoReleaseServerProcess();
+ if (lRet == 0)
+ {
+ ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0);
+ }
+ return lRet;
+ }
+
+ bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode)
+ {
+ // unimplemented!
+ return true;
+ }
+
+ HRESULT PreMessageLoop(int nShowCmd)
+ {
+ T* pThis = static_cast<T*>(this);
+ return pThis->RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
+ }
+
+ void RunMessageLoop()
+ {
+ MSG msg;
+ while (GetMessage(&msg, 0, 0, 0) > 0)
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ HRESULT PostMessageLoop()
+ {
+ T* pThis = static_cast<T*>(this);
+ return pThis->RevokeClassObjects();
+ }
+
+ HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags)
+ {
+ return AtlComModuleRegisterClassObjects(&_AtlComModule, dwClsContext, dwFlags);
+ }
+
+ HRESULT RevokeClassObjects()
+ {
+ return AtlComModuleRevokeClassObjects(&_AtlComModule);
+ }
+
+ static HRESULT InitializeCom()
+ {
+ return ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ }
+
+ static void UninitializeCom()
+ {
+ ::CoUninitialize();
+ }
+
+};
+
+
+
class CComModule : public CAtlModuleT<CComModule>
{
public:
}
};
+class CRegKey
+{
+public:
+ HKEY m_hKey;
+#if 0
+ // FIXME & TODO:
+ CAtlTransactionManager* m_pTM;
+#endif
+
+public:
+
+ CRegKey() throw()
+ : m_hKey(NULL)
+ {
+ }
+
+ CRegKey(CRegKey& key) throw()
+ : m_hKey(key.Detach())
+ {
+ }
+
+ explicit CRegKey(HKEY hKey) throw()
+ : m_hKey(hKey)
+ {
+ }
+
+#if 0
+ // FIXME & TODO:
+ CRegKey(CAtlTransactionManager* pTM) throw()
+ {
+ ...
+ }
+#endif
+
+ ~CRegKey() throw()
+ {
+ }
+
+ void Attach(HKEY hKey) throw()
+ {
+ m_hKey = hKey;
+ }
+
+ LONG Close() throw()
+ {
+ if (m_hKey)
+ {
+ HKEY hKey = Detach();
+ return ::RegCloseKey(hKey);
+ }
+ return ERROR_SUCCESS;
+ }
+
+ HKEY Detach() throw()
+ {
+ HKEY hKey = m_hKey;
+ m_hKey = NULL;
+ return hKey;
+ }
+
+ LONG Open(HKEY hKeyParent, LPCTSTR lpszKeyName,
+ REGSAM samDesired = KEY_READ | KEY_WRITE) throw()
+ {
+ ATLASSERT(hKeyParent);
+ ATLASSERT(lpszKeyName);
+
+ HKEY hKey = NULL;
+ LONG lRes = ::RegOpenKeyEx(hKeyParent, lpszKeyName, NULL, samDesired, &hKey);
+ if (lRes != ERROR_SUCCESS)
+ {
+ samDesired |= KEY_WOW64_64KEY;
+ lRes = ::RegOpenKeyEx(hKeyParent, lpszKeyName, NULL, samDesired, &hKey);
+ }
+ if (lRes == ERROR_SUCCESS)
+ {
+ Close();
+ m_hKey = hKey;
+ }
+ return lRes;
+ }
+
+ LONG Create(HKEY hKeyParent, LPCTSTR lpszKeyName,
+ LPTSTR lpszClass = REG_NONE,
+ DWORD dwOptions = REG_OPTION_NON_VOLATILE,
+ REGSAM samDesired = KEY_READ | KEY_WRITE,
+ LPSECURITY_ATTRIBUTES lpSecAttr = NULL,
+ LPDWORD lpdwDisposition = NULL) throw()
+ {
+ ATLASSERT(hKeyParent);
+ ATLASSERT(lpszKeyName);
+
+ HKEY hKey = NULL;
+ LONG lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, NULL, lpszClass,
+ dwOptions, samDesired, lpSecAttr, &hKey,
+ lpdwDisposition);
+ if (lRes != ERROR_SUCCESS)
+ {
+ samDesired |= KEY_WOW64_64KEY;
+ lRes = ::RegCreateKeyEx(hKeyParent, lpszKeyName, NULL, lpszClass,
+ dwOptions, samDesired, lpSecAttr, &hKey,
+ lpdwDisposition);
+ }
+ if (lRes == ERROR_SUCCESS)
+ {
+ Close();
+ m_hKey = hKey;
+ }
+ return lRes;
+ }
+
+ LONG QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) throw()
+ {
+ ATLASSERT(m_hKey);
+ return ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, (LPBYTE)pData, pnBytes);
+ }
+
+ LONG QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) throw()
+ {
+ ULONG size = sizeof(DWORD);
+ DWORD type = 0;
+ LONG lRet = QueryValue(pszValueName, &type, &dwValue, &size);
+
+ if (lRet == ERROR_SUCCESS && type != REG_DWORD)
+ lRet = ERROR_INVALID_DATA;
+
+ return lRet;
+ }
+
+ LONG QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) throw()
+ {
+ DWORD type = 0;
+ LONG lRet = QueryValue(pszValueName, &type, pValue, pnBytes);
+
+ if (lRet == ERROR_SUCCESS && type != REG_BINARY)
+ lRet = ERROR_INVALID_DATA;
+
+ return lRet;
+ }
+
+ LONG QueryStringValue(LPCTSTR pszValueName, LPTSTR pszValue, ULONG* pnChars) throw()
+ {
+ ULONG size = (*pnChars) * sizeof(TCHAR);
+ DWORD type = 0;
+ LONG lRet = QueryValue(pszValueName, &type, pszValue, &size);
+
+ if (lRet == ERROR_SUCCESS && type != REG_SZ && type != REG_EXPAND_SZ)
+ lRet = ERROR_INVALID_DATA;
+
+ *pnChars = size / sizeof(TCHAR);
+ return lRet;
+ }
+
+ LONG QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) throw()
+ {
+ OLECHAR buf[40] = {0};
+ ULONG nChars = 39;
+ LONG lRet;
+
+#ifdef UNICODE
+ lRet = QueryStringValue(pszValueName, buf, &nChars);
+#else
+ CHAR bufA[40] = {0};
+ lRet = QueryStringValue(pszValueName, bufA, &nChars);
+ if (lRet != ERROR_SUCCESS)
+ return lRet;
+ if (!::MultiByteToWideChar(CP_THREAD_ACP, 0, bufA, -1, buf, 39))
+ lRet = ERROR_INVALID_DATA;
+#endif
+ if (lRet != ERROR_SUCCESS)
+ return lRet;
+
+ if (!SUCCEEDED(::CLSIDFromString(buf, &guidValue)))
+ return ERROR_INVALID_DATA;
+
+ return lRet;
+ }
+
+ LONG QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) throw()
+ {
+ ULONG size = sizeof(ULONGLONG);
+ DWORD type = 0;
+ LONG lRet = QueryValue(pszValueName, &type, &qwValue, &size);
+
+ if (lRet == ERROR_SUCCESS && type != REG_QWORD)
+ lRet = ERROR_INVALID_DATA;
+
+ return lRet;
+ }
+
+ LONG QueryMultiStringValue(LPCTSTR pszValueName, LPTSTR pszValue,
+ ULONG* pnChars) throw()
+ {
+ ULONG size = (*pnChars) * sizeof(TCHAR);
+ DWORD type;
+ LONG lRet = QueryValue(pszValueName, &type, pszValue, &size);
+
+ if (lRet == ERROR_SUCCESS && type != REG_MULTI_SZ)
+ lRet = ERROR_INVALID_DATA;
+
+ *pnChars = size / sizeof(TCHAR);
+ return lRet;
+ }
+
+ LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) throw()
+ {
+ ATLASSERT(m_hKey);
+ return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, (const BYTE*)pValue, nBytes);
+ }
+
+ LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) throw()
+ {
+ return SetValue(pszValueName, REG_DWORD, &dwValue, sizeof(DWORD));
+ }
+
+ LONG SetStringValue(LPCTSTR pszValueName, LPCTSTR pszValue, DWORD dwType = REG_SZ) throw()
+ {
+ ULONG length;
+ switch (dwType)
+ {
+ case REG_SZ:
+ case REG_EXPAND_SZ:
+ length = (_tcslen(pszValue) + 1) * sizeof(TCHAR);
+ return SetValue(pszValueName, dwType, pszValue, length);
+ case REG_MULTI_SZ:
+ return SetMultiStringValue(pszValueName, pszValue);
+ default:
+ return ERROR_INVALID_DATA;
+ }
+ }
+
+ LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) throw()
+ {
+ OLECHAR buf[40] = {0};
+ ::StringFromGUID2(guidValue, buf, 39);
+#ifdef UNICODE
+ return SetStringValue(pszValueName, buf);
+#else
+ CHAR bufA[40] = {0};
+ ::WideCharToMultiByte(CP_THREAD_ACP, 0, buf, -1, bufA, 40, NULL, NULL);
+ return SetStringValue(pszValueName, bufA);
+#endif
+ }
+
+ LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) throw()
+ {
+ return SetValue(pszValueName, REG_BINARY, pValue, nBytes);
+ }
+
+ LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) throw()
+ {
+ ULONG dwSize = CRegKey::_GetMultiStringSize(pszValue);
+ return SetValue(pszValueName, REG_MULTI_SZ, pszValue, dwSize);
+ }
+
+ LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) throw()
+ {
+ ULONG dwSize = sizeof(ULONGLONG);
+ return SetValue(pszValueName, REG_QWORD, &qwValue, dwSize);
+ }
+
+ LONG NotifyChangeKeyValue(BOOL bWatchSubtree, DWORD dwNotifyFilter,
+ HANDLE hEvent, BOOL bAsync = TRUE) throw()
+ {
+ ATLASSERT(m_hKey);
+ LONG ret = ::RegNotifyChangeKeyValue(m_hKey, bWatchSubtree,
+ dwNotifyFilter, hEvent, bAsync);
+ return ret;
+ }
+
+ LONG Flush() throw()
+ {
+ ATLASSERT(m_hKey);
+ LONG ret = ::RegFlushKey(m_hKey);
+ return ret;
+ }
+
+ static LONG WINAPI SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName,
+ LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL)
+ {
+ CRegKey key;
+ LONG lRet = key.Create(hKeyParent, lpszKeyName);
+ if (lRet == ERROR_SUCCESS)
+ {
+ lRet = key.SetStringValue(lpszValueName, lpszValue);
+ }
+ return lRet;
+ }
+
+ LONG SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue,
+ LPCTSTR lpszValueName = NULL) throw()
+ {
+ CRegKey key;
+ LONG lRet = key.Create(m_hKey, lpszKeyName);
+ if (lRet == ERROR_SUCCESS)
+ {
+ lRet = key.SetStringValue(lpszValueName, lpszValue);
+ }
+ return lRet;
+ }
+
+ LONG DeleteValue(LPCTSTR lpszValue) throw()
+ {
+ ATLASSERT(m_hKey);
+ return ::RegDeleteValue(m_hKey, lpszValue);
+ }
+
+ LONG DeleteSubKey(LPCTSTR lpszSubKey) throw()
+ {
+ ATLASSERT(m_hKey);
+ ATLASSERT(lpszSubKey);
+ return ::RegDeleteKey(m_hKey, lpszSubKey);
+ }
+
+ LONG RecurseDeleteKey(LPCTSTR lpszKey) throw()
+ {
+ ATLASSERT(m_hKey);
+ ATLASSERT(lpszKey);
+ return CRegKey::_DoDeleteKeyTree(m_hKey, lpszKey);
+ }
+
+ LONG EnumKey(DWORD iIndex, LPTSTR pszName, LPDWORD pnNameLength,
+ FILETIME* pftLastWriteTime = NULL) throw()
+ {
+ ATLASSERT(m_hKey);
+ LONG ret = ::RegEnumKeyEx(m_hKey, iIndex, pszName, pnNameLength, NULL,
+ NULL, NULL, pftLastWriteTime);
+ return ret;
+ }
+
+ LONG GetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd,
+ LPDWORD pnBytes) throw()
+ {
+ ATLASSERT(m_hKey);
+ LONG ret = ::RegGetKeySecurity(m_hKey, si, psd, pnBytes);
+ return ret;
+ }
+
+ LONG SetKeySecurity(SECURITY_INFORMATION si,
+ PSECURITY_DESCRIPTOR psd) throw()
+ {
+ ATLASSERT(m_hKey);
+ LONG ret = ::RegSetKeySecurity(m_hKey, si, psd);
+ return ret;
+ }
+
+ operator HKEY() const throw()
+ {
+ return m_hKey;
+ }
+
+ CRegKey& operator=(CRegKey& key) throw()
+ {
+ Attach(key.Detach());
+ return *this;
+ }
+
+protected:
+ // get the total size of a multistring
+ static ULONG _GetMultiStringSize(LPCTSTR pszz)
+ {
+ int count = 0;
+ do
+ {
+ int len = _tcslen(pszz);
+ count += len + 1;
+ pszz += len + 1;
+ } while (*pszz != TEXT('\0'));
+ ++count;
+ return count * sizeof(TCHAR);
+ }
+
+ // delete key recursively
+ static LONG _DoDeleteKeyTree(HKEY hParentKey, LPCTSTR lpszKey)
+ {
+ ATLASSERT(hParentKey);
+ ATLASSERT(lpszKey);
+
+ // open the key
+ CRegKey key;
+ LONG ret = key.Open(hParentKey, lpszKey);
+ if (ret != ERROR_SUCCESS)
+ {
+ return ret; // failure
+ }
+
+ // get the longest length of subkey names
+ DWORD NameMax;
+ ret = ::RegQueryInfoKey(key, NULL, NULL, NULL, NULL, &NameMax, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+ if (ret != ERROR_SUCCESS)
+ {
+ return ret; // failure
+ }
+ ++NameMax; // for NUL
+
+ // allocate the string buffer for names if necessary
+ TCHAR szNameBuf[MAX_PATH], *pszName;
+ if (NameMax > MAX_PATH)
+ {
+ pszName = (TCHAR *)malloc(NameMax * sizeof(TCHAR));
+ ATLASSERT(pszName);
+ if (pszName == NULL)
+ {
+ return ERROR_OUTOFMEMORY; // failure
+ }
+ }
+ else
+ {
+ NameMax = MAX_PATH;
+ pszName = szNameBuf;
+ }
+
+ // enumerate every subkey and delete
+ for (;;)
+ {
+ DWORD Count = NameMax;
+ ret = key.EnumKey(0, pszName, &Count);
+ if (ret != ERROR_SUCCESS)
+ {
+ if (ret == ERROR_NO_MORE_ITEMS)
+ ret = ERROR_SUCCESS;
+ break;
+ }
+
+ ret = CRegKey::_DoDeleteKeyTree(key, pszName);
+ if (ret != ERROR_SUCCESS)
+ break;
+ }
+
+ // close key
+ key.Close();
+
+ // delete the subkey
+ if (ret == ERROR_SUCCESS)
+ ret = ::RegDeleteKey(hParentKey, lpszKey);
+
+ // delete the buffer if any
+ if (pszName != szNameBuf)
+ free(pszName);
+
+ return ret;
+ }
+};
template<class T>
class CComHeapPtr : public CHeapPtr<T, CComAllocator>
else
{
hResult = pEntries[i].pFunc(pThis, iid, ppvObject, 0);
- if (hResult == S_OK || (FAILED(hResult) && pEntries[i].piid != NULL))
+ if (hResult == S_OK)
return hResult;
+ if (FAILED(hResult) && pEntries[i].piid != NULL)
+ break;
}
- break;
}
i++;
}
}
+// Adapted from dll/win32/atl/atl.c
+inline HRESULT WINAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE *module, DWORD context, DWORD flags)
+{
+ _ATL_OBJMAP_ENTRY **iter;
+ IUnknown* unk = NULL;
+ HRESULT hr;
+
+ if (!module)
+ return E_INVALIDARG;
+
+ for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++)
+ {
+ if (!(*iter)->pfnGetClassObject)
+ continue;
+
+ hr = (*iter)->pfnGetClassObject((void*)(*iter)->pfnCreateInstance, IID_IUnknown, (void**)&unk);
+ if (FAILED(hr))
+ return hr;
+
+ hr = CoRegisterClassObject(*(*iter)->pclsid, unk, context, flags, &(*iter)->dwRegister);
+ unk->Release();
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
+// Adapted from dll/win32/atl/atl.c
+inline HRESULT WINAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE *module)
+{
+ _ATL_OBJMAP_ENTRY **iter;
+ HRESULT hr;
+
+ if (!module)
+ return E_INVALIDARG;
+
+ for (iter = module->m_ppAutoObjMapFirst; iter < module->m_ppAutoObjMapLast; iter++)
+ {
+ hr = CoRevokeClassObject((*iter)->dwRegister);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ return S_OK;
+}
+
+
}; // namespace ATL
#ifndef _ATL_NO_AUTOMATIC_NAMESPACE