diff --git a/CHANGELOG.md b/CHANGELOG.md index a9c119d4..45264e5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.5 (Next Release) +### 1.5 (9/18/2015) * **Features**: * Added `SERVICE_NAME` as an alternative property for specifying service name in Service_Change... calls - [@vladaver](https://github.com/vladaver). @@ -8,6 +8,11 @@ * [#9](https://github.com/dblock/msiext/issues/9) - Fixed build failures if WiX Toolset v3.7 or MSBuild Community Tasks are not installed - [@icnocop](https://github.com/icnocop). * **Misc**: * [#5](https://github.com/dblock/msiext/pull/5) - Fixed WiX UI extension screens: texts, icons, margins, spacing - [@romanws](https://github.com/romanws). + * [#22](https://github.com/dblock/msiext/issues/22) - Added MSBuildCommunityTasksPath msbuild property to allow building without requiring the MSBuild Community Tasks to be installed + Added WinDDK 7600.16385.1, and importing msi.props in projects to set up additional include and library directories to allow building without Visual Studio 2010 to be installed + Updated atlbase.h to fix warning LNK4254: section 'ATL' (50000040) merged into '.rdata' (40000040) with different attributes + Added doxygen 1.8.10 to allow building without requiring doxygen to be installed + Using "localhost" for the DSN ODBC SQL Server address and explicitly specifying the default port number to support accessing a named instance from the default port without specifying the instance name - [@icnocop](https://github.com/icnocop) ### 1.4.1114.0 (11/14/2013) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f5f5a680..8e18fcc3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ This is an open source project, please contribute. * SQL DMO from SQL 2005 Backward Compatibility Components * Java Development Kit 32-bit * [MSXML4 SP3](http://www.microsoft.com/en-us/download/details.aspx?id=15697) -* [Doxygen 1.85](http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.5-setup.exe) +* [Doxygen 1.8.5](http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.5-setup.exe) #### Build Project diff --git a/README.md b/README.md index 6f01d8db..1298a5f6 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ AppSecInc. Community MSI Extensions is a collection of MSI custom actions and WI Essentials ---------- -* [Download v. 1.4](http://code.dblock.org/downloads/msiext/msiext-1.4.zip) -* [v. 1.4 Documentation](http://dblock.github.com/msiext/docs/1.4/) +* [Download v1.5](https://github.com/dblock/msiext/releases/download/1.5/msiext-1.5.zip) +* [v1.5 Documentation](http://dblock.github.com/msiext/docs/1.5/) * [Lots of MSI Demos](src/Demos) * [Need Help? Google Group](https://groups.google.com/group/msiext) * [Old CodePlex Site](http://msiext.codeplex.com) diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..c5226644 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,147 @@ +version: '{build}' +init: +- ps: >- + # MSXML 4.0 Service Pack 3 (Microsoft XML Core Services) + + Write-Host "Downloading MSXML 4.0 Service Pack 3 (Microsoft XML Core Services)..." -ForegroundColor Green + + $msiFilePath = "$($env:USERPROFILE)\msxml.msi" + + $logFilePath = "$($env:TEMP)\msxml.txt" + + (New-Object Net.WebClient).DownloadFile('http://download.microsoft.com/download/A/2/D/A2D8587D-0027-4217-9DAD-38AFDB0A177E/msxml.msi', $msiFilePath) + + $process = (Start-Process -FilePath "msiexec.exe" -ArgumentList "/i $msiFilePath /quiet /l*v $logFilePath" -Wait -Passthru) + + $exitCode = $process.ExitCode + + if ($exitCode -ne 0) + + { + Get-Content $logFilePath + throw "Command failed with exit code $exitCode." + } + + del $msiFilePath + + del $logFilePath + + Write-Host "MSXML 4.0 Service Pack 3 (Microsoft XML Core Services) installed successfully" -ForegroundColor Green + + + # SQL DMO from SQL 2005 Backward Compatibility Components + + Write-Host "Downloading SQL DMO from SQL 2005 Backward Compatibility Components..." -ForegroundColor Green + + $msiFilePath = "$($env:USERPROFILE)\SQLServer2005_BC_x64.msi" + + $logFilePath = "$($env:TEMP)\SQLServer2005_BC_x64.txt" + + (New-Object Net.WebClient).DownloadFile('http://download.microsoft.com/download/3/1/6/316FADB2-E703-4351-8E9C-E0B36D9D697E/SQLServer2005_BC_x64.msi', $msiFilePath) + + $process = (Start-Process -FilePath "msiexec.exe" -ArgumentList "/i $msiFilePath /quiet /l*v $logFilePath" -Wait -Passthru) + + $exitCode = $process.ExitCode + + if ($exitCode -ne 0) + + { + Get-Content $logFilePath + throw "Command failed with exit code $exitCode." + } + + del $msiFilePath + + del $logFilePath + + Write-Host "SQL DMO from SQL 2005 Backward Compatibility Components installed successfully" -ForegroundColor Green + + + # Source: http://geekswithblogs.net/TedStatham/archive/2014/06/13/setting-the-ports-for-a-named-sql-server-instance-using.aspx + + # Set the $instanceName value below to the name of the instance you + + # want to configure a static port for. This could conceivably be + + # passed into the script as a parameter. + + [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null + + [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | Out-Null + + + $instanceName = 'SQL2008R2SP2' + + $computerName = $env:COMPUTERNAME + + $smo = 'Microsoft.SqlServer.Management.Smo.' + + $wmi = New-Object ($smo + 'Wmi.ManagedComputer') + + + # For the named instance, on the current computer, for the TCP protocol, + + # loop through all the IPs and configure them to use the standard port + + # of 1433. + + $uri = "ManagedComputer[@Name='$computerName']/ ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Tcp']" + + $Tcp = $wmi.GetSmoObject($uri) + + $Tcp.IsEnabled = $true + + foreach ($ipAddress in $Tcp.IPAddresses) + + { + $ipAddress.IPAddressProperties["TcpDynamicPorts"].Value = "" + $ipAddress.IPAddressProperties["TcpPort"].Value = "1433" + } + + $Tcp.Alter() + + + # Enable named pipes + + $uri = "ManagedComputer[@Name='$computerName']/ ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Np']" + + $Np = $wmi.GetSmoObject($uri) + + $Np.IsEnabled = $true + + $pipeName = $Np.ProtocolProperties | Where Name -eq "PipeName" + + $pipeName.Value = "\\.\pipe\sql\query" + + $Np.Alter() + + + # Enable shared memory + + $uri = "ManagedComputer[@Name='$computerName']/ ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Sm']" + + $Sm = $wmi.GetSmoObject($uri) + + $Sm.IsEnabled = $true + + $Sm.Alter() + + + # Restart the named instance of SQL Server to enable the changes. + + # Start services + + Set-Service SQLBrowser -StartupType Manual + + Start-Service SQLBrowser + + Start-Service "MSSQL`$$instanceName" +nuget: + disable_publish_on_pr: true +build_script: +- build.cmd all /p:Configuration=Release +test: off +artifacts: +- path: target\Release\drop\msiext*.zip + name: zip +deploy: off \ No newline at end of file diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/afxstr.h b/externals/WinDDK/7600.16385.1/inc/atl71/afxstr.h new file mode 100644 index 00000000..5ef5d193 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/afxstr.h @@ -0,0 +1,107 @@ +// This is a part of the Microsoft Foundation Classes C++ library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Microsoft Foundation Classes Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Microsoft Foundation Classes product. + +///////////////////////////////////////////////////////////////////////////// +// AFXSTR.H - Framework-independent, templateable string class + +#ifndef __AFXSTR_H__ +#define __AFXSTR_H__ + +#pragma once + +#ifndef _AFX +#error afxstr.h can only be used in MFC projects. Use atlstr.h +#endif + +#include + +HINSTANCE AFXAPI AfxGetResourceHandle(); +HINSTANCE AFXAPI AfxFindStringResourceHandle(UINT nID); + +UINT_PTR AFXAPI AfxReadStringLength(CArchive& ar, int& nCharSize); +void AFXAPI AfxWriteStringLength(CArchive& ar, UINT_PTR nLength, BOOL bUnicode); + +#include +#include + +ATL::IAtlStringMgr* AFXAPI AfxGetStringManager(); + +template< typename _CharType = char, class StringIterator = ATL::ChTraitsCRT< _CharType > > +class StrTraitMFC : + public StringIterator +{ +public: + static HINSTANCE FindStringResourceInstance( UINT nID ) throw() + { + return( AfxFindStringResourceHandle( nID ) ); + } + + static ATL::IAtlStringMgr* GetDefaultManager() throw() + { + return( AfxGetStringManager() ); + } +}; + +template< typename _CharType, class StringIterator> +class StrTraitMFC_DLL : public StringIterator +{ +public: + static HINSTANCE FindStringResourceInstance( UINT nID ) throw() + { + return( AfxFindStringResourceHandle( nID ) ); + } + + static ATL::IAtlStringMgr* GetDefaultManager() throw() + { + return( AfxGetStringManager() ); + } +}; + +// MFC-enabled compilation. Use MFC memory management and exceptions; +// also, use MFC module state. + +// Don't import when MFC dll is being built +#if defined(_AFXDLL) + +#if defined(_MFC_DLL_BLD) + +template class ATL::CSimpleStringT< char, true >; +template class ATL::CStringT< char, StrTraitMFC_DLL< char > >; +template class ATL::CSimpleStringT< wchar_t, true >; +template class ATL::CStringT< wchar_t, StrTraitMFC_DLL< wchar_t > >; + +#else + +template class __declspec(dllimport) ATL::CSimpleStringT< char, true >; +template class __declspec(dllimport) ATL::CStringT< char, StrTraitMFC_DLL< char > >; +template class __declspec(dllimport) ATL::CSimpleStringT< wchar_t, true >; +template class __declspec(dllimport) ATL::CStringT< wchar_t, StrTraitMFC_DLL< wchar_t > >; +#if defined(_NATIVE_WCHAR_T) +template class __declspec(dllimport) ATL::CSimpleStringT< unsigned short, true >; +template class __declspec(dllimport) ATL::CStringT< unsigned short, StrTraitMFC_DLL< unsigned short > >; +#endif // _NATIVE_WCHAR_T + +#endif // _MFC_DLL_BLD + +typedef ATL::CStringT< wchar_t, StrTraitMFC_DLL< wchar_t > > CStringW; +typedef ATL::CStringT< char, StrTraitMFC_DLL< char > > CStringA; +typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString; + +#else + +typedef ATL::CStringT< wchar_t, StrTraitMFC< wchar_t > > CStringW; +typedef ATL::CStringT< char, StrTraitMFC< char > > CStringA; +typedef ATL::CStringT< TCHAR, StrTraitMFC< TCHAR > > CString; + +#endif // !_WIN64 && _AFXDLL + + +#endif // __AFXSTR_H__ (whole file) + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlacc.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlacc.h new file mode 100644 index 00000000..65a0272f --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlacc.h @@ -0,0 +1,1219 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLACC_H__ +#define __ATLACC_H__ + +#pragma once + +#include +#include +#include +#include + +#ifndef _ATL_NO_DEFAULT_LIBS +#pragma comment(lib, "oleacc.lib") +#endif // _ATL_NO_DEFAULT_LIBS + + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ + +HRESULT STDMETHODCALLTYPE AtlIAccessibleInvokeHelper( + IAccessible* pAccessible, + DISPID dispIdMember, + REFIID, + LCID, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *, + UINT *puArgErr); + +HRESULT STDMETHODCALLTYPE AtlIAccessibleGetIDsOfNamesHelper( + REFIID, + LPOLESTR *rgszNames, + UINT cNames, + LCID, + DISPID *rgDispId); + + +template +class IAccessibleProxyImpl : public IAccessible, public IAccessibleProxy +{ +public : + IAccessible* m_pAccessible; + IAccessibleServer* m_pAccessibleServer; + IAccessibleProxyImpl() : m_pAccessible(NULL), m_pAccessibleServer(NULL) + { + } + + HRESULT STDMETHODCALLTYPE get_accParent(IDispatch **ppdispParent) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (ppdispParent == NULL) + return E_POINTER; + return m_pAccessible->get_accParent(ppdispParent); + } + + HRESULT STDMETHODCALLTYPE get_accChildCount(long *pcountChildren) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pcountChildren== NULL) + return E_POINTER; + return m_pAccessible->get_accChildCount(pcountChildren); + } + + HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChild, IDispatch **ppdispChild) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (ppdispChild == NULL) + return E_POINTER; + return m_pAccessible->get_accChild(varChild, ppdispChild); + } + + HRESULT STDMETHODCALLTYPE get_accName(VARIANT varChild, BSTR *pszName) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pszName == NULL) + return E_POINTER; + return m_pAccessible->get_accName(varChild, pszName); + } + + HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varChild, BSTR *pszValue) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pszValue == NULL) + return E_POINTER; + return m_pAccessible->get_accValue(varChild, pszValue); + } + + HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varChild, BSTR *pszDescription) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pszDescription == NULL) + return E_POINTER; + return m_pAccessible->get_accDescription(varChild, pszDescription); + } + + HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varChild, VARIANT *pvarRole) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pvarRole == NULL) + return E_POINTER; + return m_pAccessible->get_accRole(varChild, pvarRole); + } + + HRESULT STDMETHODCALLTYPE get_accState(VARIANT varChild, VARIANT *pvarState) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pvarState == NULL) + return E_POINTER; + return m_pAccessible->get_accState(varChild, pvarState); + } + + + HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varChild, BSTR *pszHelp) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pszHelp == NULL) + return E_POINTER; + return m_pAccessible->get_accHelp(varChild, pszHelp); + } + + HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pszHelpFile == NULL) + return E_POINTER; + if (pidTopic == NULL) + return E_POINTER; + return m_pAccessible->get_accHelpTopic(pszHelpFile, varChild, pidTopic); + } + + + HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pszKeyboardShortcut == NULL) + return E_POINTER; + return m_pAccessible->get_accKeyboardShortcut(varChild, pszKeyboardShortcut); + } + + + HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarChild) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pvarChild == NULL) + return E_POINTER; + return m_pAccessible->get_accFocus(pvarChild); + } + + + HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pvarChildren == NULL) + return E_POINTER; + return m_pAccessible->get_accSelection(pvarChildren); + } + + + HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pszDefaultAction == NULL) + return E_POINTER; + return m_pAccessible->get_accDefaultAction(varChild, pszDefaultAction); + } + + + HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varChild) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return m_pAccessible->accSelect(flagsSelect, varChild); + } + + + HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pxLeft == NULL) + return E_POINTER; + + if (pyTop == NULL) + return E_POINTER; + + if (pcxWidth == NULL) + return E_POINTER; + + if (pcyHeight == NULL) + return E_POINTER; + return m_pAccessible->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild); + } + + + HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pvarEndUpAt == NULL) + return E_POINTER; + return m_pAccessible->accNavigate(navDir, varStart, pvarEndUpAt); + } + + + HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarChild) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + if (pvarChild == NULL) + return E_POINTER; + return m_pAccessible->accHitTest(xLeft, yTop, pvarChild); + } + + + HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varChild) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return m_pAccessible->accDoDefaultAction(varChild); + } + + + HRESULT STDMETHODCALLTYPE put_accName(VARIANT /*varChild*/, BSTR /*szName*/) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return E_NOTIMPL; + } + + + HRESULT STDMETHODCALLTYPE put_accValue(VARIANT /*varChild*/, BSTR /*szValue*/) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return E_NOTIMPL; + } + + HRESULT STDMETHODCALLTYPE SetServer(IAccessible *pAccessible, IAccessibleServer* pServer) + { + // hold a weak reference to the server + m_pAccessible = pAccessible; + m_pAccessibleServer = pServer; + return S_OK; + } + virtual HRESULT STDMETHODCALLTYPE Invoke( + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return m_pAccessible->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + } + virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return m_pAccessible->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId); + } + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int* pctinfo) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return m_pAccessible->GetTypeInfoCount(pctinfo); + } + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo** ppTInfo) + { + if (m_pAccessible == NULL) + return RPC_E_DISCONNECTED; + return m_pAccessible->GetTypeInfo(iTInfo, lcid, ppTInfo); + } +}; + +class ATL_NO_VTABLE CAccessibleProxy : + public CComObjectRootEx, + public IAccessibleProxyImpl, + public IOleWindow +{ +public: + CAccessibleProxy() + { + } + virtual ~CAccessibleProxy() + { + } + + HRESULT STDMETHODCALLTYPE GetWindow(HWND* /*phwnd*/) + { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL /*fEnterMode*/) + { + return E_NOTIMPL; + } + + HRESULT FinalRelease() + { + if (m_pAccessibleServer == NULL) + return S_OK; + return m_pAccessibleServer->SetProxy(NULL); + } + +BEGIN_COM_MAP(CAccessibleProxy) + COM_INTERFACE_ENTRY(IAccessibleProxy) + COM_INTERFACE_ENTRY(IAccessible) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IOleWindow) +END_COM_MAP() + +public: +}; + +template +class IAccessibleImpl : public IAccessible, public IAccessibleServer +{ +public : + IAccessibleImpl() : m_pProxy(NULL) + { + } + + IAccessibleProxy* m_pProxy; + CComPtr m_spStdObject; + HRESULT EnsureStdObj() + { + if (m_spStdObject == NULL) + { + T* pT = static_cast(this); + HRESULT hr = CreateStdAccessibleObject(pT->m_hWnd, OBJID_CLIENT, __uuidof(IAccessible), (void**)&m_spStdObject); + if (FAILED(hr)) + return hr; + } + return S_OK; + } + + // Delegate to standard helper? + HRESULT STDMETHODCALLTYPE get_accParent(IDispatch **ppdispParent) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accParent(ppdispParent); + } + + // Delegate to standard helper? + HRESULT STDMETHODCALLTYPE get_accChildCount(long *pcountChildren) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accChildCount(pcountChildren); + } + + // Delegate to standard helper? + HRESULT STDMETHODCALLTYPE get_accChild(VARIANT varChild, IDispatch **ppdispChild) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accChild(varChild, ppdispChild); + } + + // Override in users code + HRESULT STDMETHODCALLTYPE get_accName(VARIANT varChild, BSTR *pszName) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accName(varChild, pszName); + } + + // Override in users code + // Default inplementation will get window text and return it. + HRESULT STDMETHODCALLTYPE get_accValue(VARIANT varChild, BSTR *pszValue) + { + return m_spStdObject->get_accValue(varChild, pszValue); + } + + // Override in users code + HRESULT STDMETHODCALLTYPE get_accDescription(VARIANT varChild, BSTR *pszDescription) + { + return m_spStdObject->get_accDescription(varChild, pszDescription); + } + + // Investigate + HRESULT STDMETHODCALLTYPE get_accRole(VARIANT varChild, VARIANT *pvarRole) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accRole(varChild, pvarRole); + } + + // Investigate + HRESULT STDMETHODCALLTYPE get_accState(VARIANT varChild, VARIANT *pvarState) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accState(varChild, pvarState); + } + + // Override in User's code? + HRESULT STDMETHODCALLTYPE get_accHelp(VARIANT varChild, BSTR *pszHelp) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accHelp(varChild, pszHelp); + } + + // Override in user's code? + HRESULT STDMETHODCALLTYPE get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, long *pidTopic) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accHelpTopic(pszHelpFile, varChild, pidTopic); + } + + // Override in user's code? + HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accKeyboardShortcut(varChild, pszKeyboardShortcut); + } + + // Delegate to standard implementation? + HRESULT STDMETHODCALLTYPE get_accFocus(VARIANT *pvarChild) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accFocus(pvarChild); + } + + // Investigate + HRESULT STDMETHODCALLTYPE get_accSelection(VARIANT *pvarChildren) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accSelection(pvarChildren); + } + + // Override in user's code + HRESULT STDMETHODCALLTYPE get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->get_accDefaultAction(varChild, pszDefaultAction); + } + + // Investigate + HRESULT STDMETHODCALLTYPE accSelect(long flagsSelect, VARIANT varChild) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->accSelect(flagsSelect, varChild); + } + + // Delegate? + HRESULT STDMETHODCALLTYPE accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild); + } + + // Delegate? May have to implement for COM children + HRESULT STDMETHODCALLTYPE accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->accNavigate(navDir, varStart, pvarEndUpAt); + } + + // Delegate? + HRESULT STDMETHODCALLTYPE accHitTest(long xLeft, long yTop, VARIANT *pvarChild) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->accHitTest(xLeft, yTop, pvarChild); + } + + // Override in user's code + HRESULT STDMETHODCALLTYPE accDoDefaultAction(VARIANT varChild) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->accDoDefaultAction(varChild); + } + + // Obsolete + HRESULT STDMETHODCALLTYPE put_accName(VARIANT varChild, BSTR szName) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->put_accName(varChild, szName); + } + + // Obsolete + HRESULT STDMETHODCALLTYPE put_accValue(VARIANT varChild, BSTR szValue) + { + ATLASSUME(m_spStdObject != NULL); + return m_spStdObject->put_accValue(varChild, szValue); + } + + HRESULT STDMETHODCALLTYPE SetProxy(IAccessibleProxy *pUnknown) + { + // We keep a weak reference to the server + m_pProxy = pUnknown; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetHWND(HWND *phWnd) + { + if (phWnd == NULL) + return E_POINTER; + T* pT = static_cast(this); + *phWnd = pT->m_hWnd; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetEnumVariant(IEnumVARIANT **ppEnumVariant) + { + if (ppEnumVariant == NULL) + return E_POINTER; + *ppEnumVariant = NULL; + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Invoke( + DISPID dispIdMember, + REFIID refiid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) + { + return AtlIAccessibleInvokeHelper(this, dispIdMember, refiid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + } + virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( + REFIID refiid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId) + { + return AtlIAccessibleGetIDsOfNamesHelper(refiid, rgszNames, cNames, lcid, rgDispId); + } + + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int* pctinfo) + { + if (pctinfo == NULL) + { + return E_POINTER; + } + *pctinfo = 1; + return S_OK; + } + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int /*iTInfo*/, LCID /*lcid*/, ITypeInfo** /*ppTInfo*/) + { + return E_NOTIMPL; + } + long __stdcall QueryInterface(const struct _GUID &/*refIID*/, void **ppv ) + { + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; +/* if (IsEqualGUID(refIID, __uuidof(IAccessibleServer))) + { + *ppv = static_cast(static_cast(this)); + return S_OK; + } + if (IsEqualGUID(refIID, __uuidof(IAccessible))) + { + *ppv = static_cast(static_cast(this)); + return S_OK; + } + if (IsEqualGUID(refIID, __uuidof(IUnknown))) + { + *ppv = static_cast(static_cast(static_cast(this))); + return S_OK; + } + if (IsEqualGUID(refIID, __uuidof(IDispatch))) + { + *ppv = static_cast(static_cast(static_cast(this))); + return S_OK; + } +*/ + return E_NOINTERFACE; + } + unsigned long __stdcall AddRef(void) + { + return 1; + } + unsigned long __stdcall Release(void) + { + return 1; + } + + HRESULT CreateAccessibleProxy(WPARAM wParam, LPARAM lParam, LRESULT *pResult) + { + ATLASSERT(pResult != NULL); + DWORD dwObjId = (DWORD) lParam; + HRESULT hr = E_FAIL; + + if(pResult == NULL) + return E_INVALIDARG; + + if (dwObjId == OBJID_CLIENT) + { + hr = EnsureStdObj(); + if (SUCCEEDED(hr)) + { + if (m_pProxy == NULL) + { + CComObject *p; + hr = CComObject::CreateInstance(&p); + if (SUCCEEDED(hr)) + { + CComPtr spProx; + hr = p->QueryInterface(&spProx); + if (SUCCEEDED(hr)) + { + m_pProxy = spProx; + spProx->SetServer(static_cast(this), static_cast(this)); + *pResult = LresultFromObject (__uuidof(IAccessible), wParam, m_pProxy); + } + hr = S_OK; + } + } + else + { + *pResult = LresultFromObject (__uuidof(IAccessible), wParam, m_pProxy); + hr = S_OK; + } + } + } + return hr; + } +}; + +inline HRESULT STDMETHODCALLTYPE AtlIAccessibleInvokeHelper( + IAccessible* pAccessible, + DISPID dispIdMember, + REFIID, + LCID, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *, + UINT *puArgErr) +{ + UINT uArgErr; + VARIANT vResult; + vResult.vt = VT_EMPTY; + + if(pAccessible == NULL) + { + return E_INVALIDARG; + } + + if (pDispParams == NULL) + { + return DISP_E_BADVARTYPE; + } + + if (pDispParams->cArgs > 5) + { + return DISP_E_BADPARAMCOUNT; + } + + VARIANTARG * rgpParams[5]; + { + ATLASSERT(pDispParams->cNamedArgs <= pDispParams->cArgs); + UINT i = 0; + for (; i < pDispParams->cNamedArgs; i++) + { + if ((UINT)pDispParams->rgdispidNamedArgs[i] >= pDispParams->cArgs) + { + return DISP_E_BADPARAMCOUNT; + } + rgpParams[pDispParams->rgdispidNamedArgs[i]] = &pDispParams->rgvarg[i]; + } + for (; i < pDispParams->cArgs; i++) + { + rgpParams[pDispParams->cArgs - i - 1] = &pDispParams->rgvarg[i]; + } + } + + HRESULT hr = DISP_E_MEMBERNOTFOUND; + + if(puArgErr == NULL) + { + puArgErr = &uArgErr; + } + + if(pVarResult == NULL) + { + pVarResult = &vResult; + } + VARIANT varg; + VariantInit(&varg); + + switch (dispIdMember) + { + case DISPID_ACC_DODEFAULTACTION : // -5018 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + VARIANT i1 = *rgpParams[0]; + hr = pAccessible->accDoDefaultAction(i1); + break; + } + case DISPID_ACC_HITTEST : // -5017 + { + if(pDispParams->cArgs != 2) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + if (rgpParams[0]->vt != VT_I4) + { + hr = VariantChangeType(&varg, rgpParams[0], 0, VT_I4); + if(FAILED(hr)) + { + *puArgErr = 0; + break; + } + rgpParams[0] = &varg; + } + long i1 = V_I4(rgpParams[0]); + + if (rgpParams[1]->vt != VT_I4) + { + hr = VariantChangeType(&varg, rgpParams[1], 0, VT_I4); + if(FAILED(hr)) + { + *puArgErr = 1; + break; + } + rgpParams[1] = &varg; + } + long i2 = V_I4(rgpParams[1]); + + hr = pAccessible->accHitTest(i1, i2, pVarResult); + break; + } + case DISPID_ACC_NAVIGATE : // -5016 + { + if(pDispParams->cArgs != 2) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + if (rgpParams[0]->vt != VT_I4) + { + hr = VariantChangeType(&varg, rgpParams[0], 0, VT_I4); + if(FAILED(hr)) + { + *puArgErr = 0; + break; + } + rgpParams[0] = &varg; + } + long i1 = V_I4(rgpParams[0]); + + VARIANT i2 = *rgpParams[1]; + + hr = pAccessible->accNavigate(i1, i2, pVarResult); + break; + } + case DISPID_ACC_LOCATION : // -5015 + { + BOOL bError = FALSE; + + if(pDispParams->cArgs != 5) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + long *pI4Params[4]; + for (int iParam = 0; iParam < 4; iParam++) + { + if (!(rgpParams[iParam]->vt & VT_BYREF) || + (rgpParams[iParam]->vt & (VT_VARIANT | VT_I4)) == 0) + { + hr = DISP_E_TYPEMISMATCH; + bError = TRUE; + *puArgErr = iParam; + break; + } + if (rgpParams[iParam]->vt & VT_VARIANT) + { + VariantClear(V_VARIANTREF(rgpParams[iParam])); + V_VARIANTREF(rgpParams[iParam])->vt = VT_I4; + pI4Params[iParam] = &V_I4(V_VARIANTREF(rgpParams[iParam])); + } + else + { + pI4Params[iParam] = V_I4REF(rgpParams[iParam]); + } + } + + if (!bError) + { + VARIANT i5 = *rgpParams[4]; + hr = pAccessible->accLocation(pI4Params[0], pI4Params[1], pI4Params[2], pI4Params[3], i5); + } + break; + } + case DISPID_ACC_SELECT : // -5014 + { + if(pDispParams->cArgs != 2) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + if (rgpParams[0]->vt != VT_I4) + { + hr = VariantChangeType(&varg, rgpParams[0], 0, VT_I4); + if(FAILED(hr)) + { + *puArgErr = 0; + break; + } + rgpParams[0] = &varg; + } + long i1 = V_I4(rgpParams[0]); + + VARIANT i2 = *rgpParams[1]; + + hr = pAccessible->accSelect(i1, i2); + break; + } + case DISPID_ACC_DEFAULTACTION : // -5013 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + VARIANT i1 = *rgpParams[0]; + + BSTR * i2 = &(V_BSTR(pVarResult)); + hr = pAccessible->get_accDefaultAction(i1, i2); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_BSTR; + } + break; + } + case DISPID_ACC_SELECTION : // -5012 + { + hr = pAccessible->get_accSelection(pVarResult); + break; + } + case DISPID_ACC_FOCUS : // -5011 + { + hr = pAccessible->get_accFocus(pVarResult); + break; + } + case DISPID_ACC_KEYBOARDSHORTCUT : // -5010 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + VARIANT i1 = *rgpParams[0]; + + BSTR* i2 = &(V_BSTR(pVarResult)); + hr = pAccessible->get_accKeyboardShortcut(i1, i2); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_BSTR; + } + + break; + } + case DISPID_ACC_HELPTOPIC : // -5009 + { + + if(pDispParams->cArgs != 2) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + BSTR* i1 = NULL; + if ((rgpParams[0]->vt & VT_BYREF) && !(rgpParams[0]->vt & (VT_VARIANT | VT_BSTR))) + { + hr = DISP_E_TYPEMISMATCH; + *puArgErr = 0; + break; + } + if (rgpParams[0]->vt == (VT_VARIANT | VT_BYREF)) + { + VariantClear(V_VARIANTREF(rgpParams[0])); + V_VARIANTREF(rgpParams[0])->vt = VT_BSTR; + i1 = &V_BSTR(V_VARIANTREF(rgpParams[0])); + } + else if (rgpParams[0]->vt == (VT_BSTR | VT_BYREF)) + { + i1 = V_BSTRREF(rgpParams[0]); + } + else + { + VariantClear(rgpParams[0]); + i1 = &V_BSTR(rgpParams[0]); + rgpParams[0]->vt = VT_BSTR; + } + + VARIANT i2 = *rgpParams[1]; + long* i3 = &(V_I4(pVarResult)); + + hr = pAccessible->get_accHelpTopic(i1, i2, i3); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_I4; + } + + break; + } + case DISPID_ACC_HELP : // -5008 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + VARIANT i1 = *rgpParams[0]; + BSTR* i2 = &(V_BSTR(pVarResult)); + hr = pAccessible->get_accHelp(i1, i2); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_BSTR; + } + + break; + } + case DISPID_ACC_STATE : // -5007 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + VARIANT i1 = *rgpParams[0]; + hr = pAccessible->get_accState(i1, pVarResult); + break; + } + case DISPID_ACC_ROLE : // -5006 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + VARIANT i1 = *rgpParams[0]; + hr = pAccessible->get_accRole(i1, pVarResult); + break; + } + case DISPID_ACC_DESCRIPTION : // -5005 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + VARIANT i1 = *rgpParams[0]; + BSTR* i2 = &(V_BSTR(pVarResult)); + hr = pAccessible->get_accDescription(i1, i2); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_BSTR; + } + + break; + } + case DISPID_ACC_VALUE : // -5004 + { + if (wFlags & 2) + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + VARIANT i1 = *rgpParams[0]; + BSTR* i2 = &(V_BSTR(pVarResult)); + hr = pAccessible->get_accValue(i1, i2); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_BSTR; + } + + break; + } + else if (wFlags & 4) + { + if(pDispParams->cArgs != 2) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + + VARIANT i1 = *rgpParams[0]; + + if (rgpParams[1]->vt != VT_BSTR) + { + hr = VariantChangeType(&varg, rgpParams[1], 0, VT_I4); + if(FAILED(hr)) + { + *puArgErr = 1; + break; + } + rgpParams[1] = &varg; + } + BSTR i2 = V_BSTR(rgpParams[1]); + + hr = pAccessible->put_accValue(i1, i2); + break; + } + } + case DISPID_ACC_NAME : // -5003 + { + if (wFlags & 2) + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + VARIANT i1 = *rgpParams[0]; + + BSTR* i2 = &(V_BSTR(pVarResult)); + + hr = pAccessible->get_accName(i1, i2); + + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_BSTR; + } + + break; + } + else if (wFlags & 4) + { + if(pDispParams->cArgs != 2) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + VARIANT i1 = *rgpParams[0]; + + if (rgpParams[1]->vt != VT_BSTR) + { + hr = VariantChangeType(&varg, rgpParams[1], 0, VT_I4); + if(FAILED(hr)) + { + *puArgErr = 1; + break; + } + rgpParams[1] = &varg; + } + BSTR i2 = V_BSTR(rgpParams[1]); + + hr = pAccessible->put_accName(i1, i2); + break; + } + } + case DISPID_ACC_CHILD : // -5002 + { + if(pDispParams->cArgs != 1) + { + hr = DISP_E_BADPARAMCOUNT; + break; + } + VARIANT i1 = *rgpParams[0]; + + IDispatch** i2 = &(V_DISPATCH(pVarResult)); + hr = pAccessible->get_accChild(i1, i2); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_DISPATCH; + } + + break; + } + case DISPID_ACC_CHILDCOUNT : // -5001 + { + long* i1 = &(V_I4(pVarResult)); + hr = pAccessible->get_accChildCount(i1); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_I4; + } + + break; + } + case DISPID_ACC_PARENT : // -5000 + { + IDispatch** i1 = &(V_DISPATCH(pVarResult)); + hr = pAccessible->get_accParent(i1); + if(SUCCEEDED(hr)) + { + pVarResult->vt = VT_DISPATCH; + } + + break; + } + default: + break; + } + + VariantClear(&varg); + return hr; +} + +inline HRESULT STDMETHODCALLTYPE AtlIAccessibleGetIDsOfNamesHelper( + REFIID, + LPOLESTR *rgszNames, + UINT cNames, + LCID, + DISPID *rgDispId) +{ + static LPOLESTR names[] = + { + L"accParent", + L"accChildCount", + L"accChild", + L"accName", + L"accValue", + L"accDescription", + L"accRole", + L"accState", + L"accHelp", + L"accHelpTopic", + L"accKeyboardShortcut", + L"accFocus", + L"accSelection", + L"accDefaultAction", + L"accSelect", + L"accLocation", + L"accNavigate", + L"accHitTest", + L"accDoDefaultAction" + }; + static DISPID dids[] = + { + DISPID_ACC_PARENT, // -5000 + DISPID_ACC_CHILDCOUNT, // -5001 + DISPID_ACC_CHILD, // -5002 + DISPID_ACC_NAME, // -5003 + DISPID_ACC_VALUE, // -5004 + DISPID_ACC_DESCRIPTION, // -5005 + DISPID_ACC_ROLE, // -5006 + DISPID_ACC_STATE, // -5007 + DISPID_ACC_HELP, // -5008 + DISPID_ACC_HELPTOPIC, // -5009 + DISPID_ACC_KEYBOARDSHORTCUT, // -5010 + DISPID_ACC_FOCUS, // -5011 + DISPID_ACC_SELECTION, // -5012 + DISPID_ACC_DEFAULTACTION, // -5013 + DISPID_ACC_SELECT, // -5014 + DISPID_ACC_LOCATION, // -5015 + DISPID_ACC_NAVIGATE, // -5016 + DISPID_ACC_HITTEST, // -5017 + DISPID_ACC_DODEFAULTACTION // -5018 + }; + for (unsigned int i = 0; i < cNames; ++i) + { + bool bFoundIt = false; + for (unsigned int j = 0; j < sizeof(names)/sizeof(LPOLESTR); ++j) + { + if (lstrcmpW(rgszNames[i], names[j]) == 0) + { + bFoundIt = true; + rgDispId[i] = dids[j]; + } + } + if (!bFoundIt) + { + return DISP_E_UNKNOWNNAME; + } + } + return S_OK; +} + +} // namespace ATL +#pragma pack(pop) + +#endif // __ATLACC_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlalloc.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlalloc.h new file mode 100644 index 00000000..df9de630 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlalloc.h @@ -0,0 +1,764 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#pragma once +#ifndef __ATLALLOC_H__ +#define __ATLALLOC_H__ +#endif + +#include +#include + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ + +/* +This is more than a little unsatisfying. /Wp64 warns when we convert a size_t to an int +because it knows such a conversion won't port. +But, when we have overloaded templates, there may well exist both conversions and we need +to fool the warning into not firing on 32 bit builds +*/ +#if !defined(_ATL_W64) +#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) +#define _ATL_W64 __w64 +#else +#define _ATL_W64 +#endif +#endif + +/* Can't use ::std::numeric_limits here because we don't want to introduce a new + deprendency of this code on SCL +*/ + +template +class AtlLimits; + +template<> +class AtlLimits +{ +public: + static const int _Min=INT_MIN; + static const int _Max=INT_MAX; +}; + +template<> +class AtlLimits +{ +public: + static const unsigned int _Min=0; + static const unsigned int _Max=UINT_MAX; +}; + +template<> +class AtlLimits +{ +public: + static const long _Min=LONG_MIN; + static const long _Max=LONG_MAX; +}; + +template<> +class AtlLimits +{ +public: + static const unsigned long _Min=0; + static const unsigned long _Max=ULONG_MAX; +}; + +template<> +class AtlLimits +{ +public: + static const long long _Min=LLONG_MIN; + static const long long _Max=LLONG_MAX; +}; + +template<> +class AtlLimits +{ +public: + static const unsigned long long _Min=0; + static const unsigned long long _Max=ULLONG_MAX; +}; + +/* generic version */ +template +inline HRESULT AtlAdd(T* ptResult, T tLeft, T tRight) +{ + if(::ATL::AtlLimits::_Max-tLeft < tRight) + { + return E_INVALIDARG; + } + *ptResult= tLeft + tRight; + return S_OK; +} + +/* generic but compariatively slow version */ +template +inline HRESULT AtlMultiply(T* ptResult, T tLeft, T tRight) +{ + /* avoid divide 0 */ + if(tLeft==0) + { + *ptResult=0; + return S_OK; + } + if(::ATL::AtlLimits::_Max/tLeft < tRight) + { + return E_INVALIDARG; + } + *ptResult= tLeft * tRight; + return S_OK; +} + +/* fast version for 32 bit integers */ +template<> +inline HRESULT AtlMultiply(int _ATL_W64 *piResult, int _ATL_W64 iLeft, int _ATL_W64 iRight) +{ + __int64 i64Result=static_cast<__int64>(iLeft) * static_cast<__int64>(iRight); + if(i64Result>INT_MAX || i64Result < INT_MIN) + { + return E_INVALIDARG; + } + *piResult=static_cast(i64Result); + return S_OK; +} + +template<> +inline HRESULT AtlMultiply(unsigned int _ATL_W64 *piResult, unsigned int _ATL_W64 iLeft, unsigned int _ATL_W64 iRight) +{ + unsigned __int64 i64Result=static_cast(iLeft) * static_cast(iRight); + if(i64Result>UINT_MAX) + { + return E_INVALIDARG; + } + *piResult=static_cast(i64Result); + return S_OK; +} + +template<> +inline HRESULT AtlMultiply(long _ATL_W64 *piResult, long _ATL_W64 iLeft, long _ATL_W64 iRight) +{ + __int64 i64Result=static_cast<__int64>(iLeft) * static_cast<__int64>(iRight); + if(i64Result>LONG_MAX || i64Result < LONG_MIN) + { + return E_INVALIDARG; + } + *piResult=static_cast(i64Result); + return S_OK; +} + +template<> +inline HRESULT AtlMultiply(unsigned long _ATL_W64 *piResult, unsigned long _ATL_W64 iLeft, unsigned long _ATL_W64 iRight) +{ + unsigned __int64 i64Result=static_cast(iLeft) * static_cast(iRight); + if(i64Result>ULONG_MAX) + { + return E_INVALIDARG; + } + *piResult=static_cast(i64Result); + return S_OK; +} + +template +inline T AtlMultiplyThrow(T tLeft, T tRight) +{ + T tResult; + HRESULT hr=AtlMultiply(&tResult, tLeft, tRight); + if(FAILED(hr)) + { + AtlThrow(hr); + } + return tResult; +} + +template +inline T AtlAddThrow(T tLeft, T tRight) +{ + T tResult; + HRESULT hr=AtlAdd(&tResult, tLeft, tRight); + if(FAILED(hr)) + { + AtlThrow(hr); + } + return tResult; +} + +inline LPVOID AtlCoTaskMemCAlloc(ULONG nCount, ULONG nSize) +{ + HRESULT hr; + ULONG nBytes=0; + if( FAILED(hr=::ATL::AtlMultiply(&nBytes, nCount, nSize))) + { + return NULL; + } + return ::CoTaskMemAlloc(nBytes); +} + +inline LPVOID AtlCoTaskMemRecalloc(void *pvMemory, ULONG nCount, ULONG nSize) +{ + HRESULT hr; + ULONG nBytes=0; + if( FAILED(hr=::ATL::AtlMultiply(&nBytes, nCount, nSize))) + { + return NULL; + } + return ::CoTaskMemRealloc(pvMemory, nBytes); +} + +} // namespace ATL +#pragma pack(pop) + +#pragma pack(push,8) +namespace ATL +{ +// forward declaration of Checked::memcpy_s + +namespace Checked +{ + void __cdecl memcpy_s(__out_bcount_part(s1max,n) void *s1, __in size_t s1max, __in_bcount(n) const void *s2, __in size_t n); +} + +///////////////////////////////////////////////////////////////////////////// +// Allocation helpers + +class CCRTAllocator +{ +public: + static void* Reallocate(void* p, size_t nBytes) throw() + { + return realloc(p, nBytes); + } + + static void* Allocate(size_t nBytes) throw() + { + return malloc(nBytes); + } + + static void Free(void* p) throw() + { + free(p); + } +}; + +class CLocalAllocator +{ +public: + static void* Allocate(size_t nBytes) throw() + { + return ::LocalAlloc(LMEM_FIXED, nBytes); + } + static void* Reallocate(void* p, size_t nBytes) throw() + { + if (p==NULL){ + return ( Allocate(nBytes) ); + + } + if (nBytes==0){ + Free(p); + return NULL; + } + return ::LocalReAlloc(p, nBytes, 0); + + } + static void Free(void* p) throw() + { + ::LocalFree(p); + } +}; + +class CGlobalAllocator +{ +public: + static void* Allocate(size_t nBytes) throw() + { + return ::GlobalAlloc(GMEM_FIXED, nBytes); + } + static void* Reallocate(void* p, size_t nBytes) throw() + { + if (p==NULL){ + return ( Allocate(nBytes) ); + + } + if (nBytes==0){ + Free(p); + return NULL; + } + return ( ::GlobalReAlloc(p, nBytes, 0) ); + } + static void Free(void* p) throw() + { + ::GlobalFree(p); + } +}; + +template +class CHeapPtrBase +{ +protected: + CHeapPtrBase() throw() : + m_pData(NULL) + { + } + CHeapPtrBase(CHeapPtrBase& p) throw() + { + m_pData = p.Detach(); // Transfer ownership + } + explicit CHeapPtrBase(T* pData) throw() : + m_pData(pData) + { + } + +public: + ~CHeapPtrBase() throw() + { + Free(); + } + +protected: + CHeapPtrBase& operator=(CHeapPtrBase& p) throw() + { + if(m_pData != p.m_pData) + Attach(p.Detach()); // Transfer ownership + return *this; + } + +public: + operator T*() const throw() + { + return m_pData; + } + + T* operator->() const throw() + { + ATLASSERT(m_pData != NULL); + return m_pData; + } + + T** operator&() throw() + { +#if defined(ATLASSUME) + ATLASSUME(m_pData == NULL); +#endif + return &m_pData; + } + + // Allocate a buffer with the given number of bytes + bool AllocateBytes(size_t nBytes) throw() + { + ATLASSERT(m_pData == NULL); + m_pData = static_cast(Allocator::Allocate(nBytes)); + if (m_pData == NULL) + return false; + + return true; + } + + // Attach to an existing pointer (takes ownership) + void Attach(T* pData) throw() + { + Allocator::Free(m_pData); + m_pData = pData; + } + + // Detach the pointer (releases ownership) + T* Detach() throw() + { + T* pTemp = m_pData; + m_pData = NULL; + return pTemp; + } + + // Free the memory pointed to, and set the pointer to NULL + void Free() throw() + { + Allocator::Free(m_pData); + m_pData = NULL; + } + + // Reallocate the buffer to hold a given number of bytes + bool ReallocateBytes(size_t nBytes) throw() + { + T* pNew; + + pNew = static_cast(Allocator::Reallocate(m_pData, nBytes)); + if (pNew == NULL) + return false; + m_pData = pNew; + + return true; + } + +public: + T* m_pData; +}; + +template +class CHeapPtr : + public CHeapPtrBase +{ +public: + CHeapPtr() throw() + { + } + CHeapPtr(CHeapPtr& p) throw() : + CHeapPtrBase(p) + { + } + explicit CHeapPtr(T* p) throw() : + CHeapPtrBase(p) + { + } + + CHeapPtr& operator=(CHeapPtr& p) throw() + { + CHeapPtrBase::operator=(p); + + return *this; + } + + // Allocate a buffer with the given number of elements + bool Allocate(size_t nElements = 1) throw() + { + size_t nBytes=0; + if(FAILED(::ATL::AtlMultiply(&nBytes, nElements, sizeof(T)))) + { + return false; + } + return AllocateBytes(nBytes); + } + + // Reallocate the buffer to hold a given number of elements + bool Reallocate(size_t nElements) throw() + { + size_t nBytes=0; + if(FAILED(::ATL::AtlMultiply(&nBytes, nElements, sizeof(T)))) + { + return false; + } + return ReallocateBytes(nBytes); + } +}; + +template< typename T, int t_nFixedBytes = 128, class Allocator = CCRTAllocator > +class CTempBuffer +{ +public: + CTempBuffer() throw() : + m_p( NULL ) + { + } + CTempBuffer( size_t nElements ) throw( ... ) : + m_p( NULL ) + { + Allocate( nElements ); + } + + ~CTempBuffer() throw() + { + if( m_p != reinterpret_cast< T* >( m_abFixedBuffer ) ) + { + FreeHeap(); + } + } + + operator T*() const throw() + { + return( m_p ); + } + T* operator->() const throw() + { + ATLASSERT( m_p != NULL ); + return( m_p ); + } + + T* Allocate( size_t nElements ) throw( ... ) + { + return( AllocateBytes( ::ATL::AtlMultiplyThrow(nElements,sizeof( T )) ) ); + } + + T* Reallocate( size_t nElements ) throw( ... ) + { + ATLENSURE(nElements < size_t(-1)/sizeof(T) ); + size_t nNewSize = nElements*sizeof( T ) ; + + if (m_p == NULL) + return AllocateBytes(nNewSize); + + if (nNewSize > t_nFixedBytes) + { + if( m_p == reinterpret_cast< T* >( m_abFixedBuffer ) ) + { + // We have to allocate from the heap and copy the contents into the new buffer + AllocateHeap(nNewSize); + Checked::memcpy_s(m_p, nNewSize, m_abFixedBuffer, t_nFixedBytes); + } + else + { + ReAllocateHeap( nNewSize ); + } + } + else + { + m_p = reinterpret_cast< T* >( m_abFixedBuffer ); + } + + return m_p; + } + + T* AllocateBytes( size_t nBytes ) + { + ATLASSERT( m_p == NULL ); + if( nBytes > t_nFixedBytes ) + { + AllocateHeap( nBytes ); + } + else + { + m_p = reinterpret_cast< T* >( m_abFixedBuffer ); + } + + return( m_p ); + } + +private: + ATL_NOINLINE void AllocateHeap( size_t nBytes ) + { + T* p = static_cast< T* >( Allocator::Allocate( nBytes ) ); + if( p == NULL ) + { + AtlThrow( E_OUTOFMEMORY ); + } + m_p = p; + } + + ATL_NOINLINE void ReAllocateHeap( size_t nNewSize) + { + T* p = static_cast< T* >( Allocator::Reallocate(m_p, nNewSize) ); + if ( p == NULL ) + { + AtlThrow( E_OUTOFMEMORY ); + } + m_p = p; + } + + ATL_NOINLINE void FreeHeap() throw() + { + Allocator::Free( m_p ); + } + +private: + T* m_p; + BYTE m_abFixedBuffer[t_nFixedBytes]; +}; + + +// Allocating memory on the stack without causing stack overflow. +// Only use these through the _ATL_SAFE_ALLOCA_* macros +namespace _ATL_SAFE_ALLOCA_IMPL +{ + +#ifndef _ATL_STACK_MARGIN +#if defined(_M_IX86) +#define _ATL_STACK_MARGIN 0x2000 // Minimum stack available after call to _ATL_SAFE_ALLOCA +#else //_M_AMD64 _M_IA64 +#define _ATL_STACK_MARGIN 0x4000 +#endif +#endif //_ATL_STACK_MARGIN + +//Verifies if sufficient space is available on the stack. +//Note: This function should never be inlined, because the stack allocation +//may not be freed until the end of the calling function (instead of the end of _AtlVerifyStackAvailable). +//The use of __try/__except preverts inlining in this case. +#if (_ATL_VER > 0x0301) +inline bool _AtlVerifyStackAvailable(SIZE_T Size) +{ + bool bStackAvailable = true; + + __try + { + SIZE_T size=0; + HRESULT hrAdd=::ATL::AtlAdd(&size, Size, static_cast(_ATL_STACK_MARGIN)); + if(FAILED(hrAdd)) + { + ATLASSERT(FALSE); + bStackAvailable = false; + } + else + { + PVOID p = _alloca(size); + if (p) + { + (p); + } + } + } + __except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ? + EXCEPTION_EXECUTE_HANDLER : + EXCEPTION_CONTINUE_SEARCH) + { + bStackAvailable = false; + _resetstkoflw(); + } + return bStackAvailable; +} + + +// Helper Classes to manage heap buffers for _ATL_SAFE_ALLOCA +template < class Allocator> +class CAtlSafeAllocBufferManager +{ +private : + struct CAtlSafeAllocBufferNode + { + CAtlSafeAllocBufferNode* m_pNext; +#if defined(_M_IX86) + BYTE _pad[4]; +#elif defined(_M_IA64) + BYTE _pad[8]; +#elif defined(_M_AMD64) + BYTE _pad[8]; +#else + #error Only supported for X86, AMD64 and IA64 +#endif + void* GetData() + { + return (this + 1); + } + }; + + CAtlSafeAllocBufferNode* m_pHead; +public : + + CAtlSafeAllocBufferManager() : m_pHead(NULL) {}; + void* Allocate(SIZE_T nRequestedSize) + { + CAtlSafeAllocBufferNode *p = (CAtlSafeAllocBufferNode*)Allocator::Allocate(::ATL::AtlAddThrow(nRequestedSize, static_cast(sizeof(CAtlSafeAllocBufferNode)))); + if (p == NULL) + return NULL; + + // Add buffer to the list + p->m_pNext = m_pHead; + m_pHead = p; + + return p->GetData(); + } + ~CAtlSafeAllocBufferManager() + { + // Walk the list and free the buffers + while (m_pHead != NULL) + { + CAtlSafeAllocBufferNode* p = m_pHead; + m_pHead = m_pHead->m_pNext; + Allocator::Free(p); + } + } +}; +#endif + +} // namespace _ATL_SAFE_ALLOCA_IMPL + +} // namespace ATL + #pragma pack(pop) + +// Use one of the following macros before using _ATL_SAFE_ALLOCA +// EX version allows specifying a different heap allocator +#define USES_ATL_SAFE_ALLOCA_EX(x) ATL::_ATL_SAFE_ALLOCA_IMPL::CAtlSafeAllocBufferManager _AtlSafeAllocaManager + +#ifndef USES_ATL_SAFE_ALLOCA +#define USES_ATL_SAFE_ALLOCA USES_ATL_SAFE_ALLOCA_EX(ATL::CCRTAllocator) +#endif + +// nRequestedSize - requested size in bytes +// nThreshold - size in bytes beyond which memory is allocated from the heap. + +#if (_ATL_VER > 0x0301) + +// Defining _ATL_SAFE_ALLOCA_ALWAYS_ALLOCATE_THRESHOLD_SIZE always allocates the size specified +// for threshold if the stack space is available irrespective of requested size. +// This available for testing purposes. It will help determine the max stack usage due to _alloca's +// Disable _alloca not within try-except prefast warning since we verify stack space is available before. +#ifdef _ATL_SAFE_ALLOCA_ALWAYS_ALLOCATE_THRESHOLD_SIZE +#define _ATL_SAFE_ALLOCA(nRequestedSize, nThreshold) \ + __pragma(warning(push))\ + __pragma(warning(disable:4616))\ + __pragma(warning(disable:6255))\ + ((nRequestedSize <= nThreshold && ATL::_ATL_SAFE_ALLOCA_IMPL::_AtlVerifyStackAvailable(nThreshold) ) ? \ + _alloca(nThreshold) : \ + ((ATL::_ATL_SAFE_ALLOCA_IMPL::_AtlVerifyStackAvailable(nThreshold)) ? _alloca(nThreshold) : 0), \ + _AtlSafeAllocaManager.Allocate(nRequestedSize))\ + __pragma(warning(pop)) +#else +#define _ATL_SAFE_ALLOCA(nRequestedSize, nThreshold) \ + __pragma(warning(push))\ + __pragma(warning(disable:4616))\ + __pragma(warning(disable:6255))\ + ((nRequestedSize <= nThreshold && ATL::_ATL_SAFE_ALLOCA_IMPL::_AtlVerifyStackAvailable(nRequestedSize) ) ? \ + _alloca(nRequestedSize) : \ + _AtlSafeAllocaManager.Allocate(nRequestedSize))\ + __pragma(warning(pop)) +#endif + +#endif + +// Use 1024 bytes as the default threshold in ATL +#ifndef _ATL_SAFE_ALLOCA_DEF_THRESHOLD +#define _ATL_SAFE_ALLOCA_DEF_THRESHOLD 1024 +#endif + +#if (_ATL_VER <= 0x0301) // from atlbase.h + +class CComAllocator +{ +public: + static void* Reallocate(void* p, size_t nBytes) throw() + { +#ifdef _WIN64 + if( nBytes > INT_MAX ) + { + return( NULL ); + } +#endif + return ::CoTaskMemRealloc(p, ULONG(nBytes)); + } + static void* Allocate(size_t nBytes) throw() + { +#ifdef _WIN64 + if( nBytes > INT_MAX ) + { + return( NULL ); + } +#endif + return ::CoTaskMemAlloc(ULONG(nBytes)); + } + static void Free(void* p) throw() + { + ::CoTaskMemFree(p); + } +}; + +template +class CComHeapPtr : + public CHeapPtr +{ +public: + CComHeapPtr() throw() + { + } + + explicit CComHeapPtr(T* pData) throw() : + CHeapPtr(pData) + { + } +}; + +#endif + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlassem.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlassem.h new file mode 100644 index 00000000..025ce95f --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlassem.h @@ -0,0 +1,54 @@ +/*** +*atlassem.h - Libraries Assembly information +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +*Purpose: +* This file has information about Libraries Assembly version. +* +* +****/ + +#pragma once + +#ifndef _VC_ASSEMBLY_PUBLICKEYTOKEN +#define _VC_ASSEMBLY_PUBLICKEYTOKEN "1fc8b3b9a1e18e3b" +#endif + +#ifndef _ATL_ASSEMBLY_VERSION +#define _ATL_ASSEMBLY_VERSION "8.0.50608.0" +#endif + +#ifndef __LIBRARIES_ASSEMBLY_NAME_PREFIX +#define __LIBRARIES_ASSEMBLY_NAME_PREFIX "Microsoft.VC80" +#endif + +#if _MSC_FULL_VER >= 140040130 + +#ifdef _M_IX86 + #pragma comment(linker,"/manifestdependency:\"type='win32' " \ + "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".ATL' " \ + "version='" _ATL_ASSEMBLY_VERSION "' " \ + "processorArchitecture='x86' " \ + "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") +#endif + +#ifdef _M_AMD64 + #pragma comment(linker,"/manifestdependency:\"type='win32' " \ + "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".ATL' " \ + "version='" _ATL_ASSEMBLY_VERSION "' " \ + "processorArchitecture='amd64' " \ + "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") +#endif + +#ifdef _M_IA64 + #pragma comment(linker,"/manifestdependency:\"type='win32' " \ + "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".ATL' " \ + "version='" _ATL_ASSEMBLY_VERSION "' " \ + "processorArchitecture='ia64' " \ + "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"") +#endif + +#endif + + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlbase.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlbase.h new file mode 100644 index 00000000..9cb39127 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlbase.h @@ -0,0 +1,7410 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLBASE_H__ +#define __ATLBASE_H__ + +#pragma once + +// Warnings outside of the push/pop sequence will be disabled for all user +// projects. The only warnings that should be disabled outside the push/pop +// are warnings that are a) benign and b) will show up in user projects +// without being directly caused by the user + +#pragma warning(disable: 4505) // unreferenced local function has been removed +#pragma warning(disable: 4710) // function couldn't be inlined +#pragma warning(disable: 4514) // unreferenced inlines are common + +// These two warnings will occur in any class that contains or derives from a +// class with a private copy constructor or copy assignment operator. +#pragma warning(disable: 4511) // copy constructor could not be generated +#pragma warning(disable: 4512) // assignment operator could not be generated + +// This is a very common pattern for us +#pragma warning(disable: 4355) // 'this' : used in base member initializer list + +// Warning 4702 is generated based on compiler backend data flow analysis. This means that for +// some specific instantiations of a template it can be generated even when the code branch is +// required for other instantiations. In future we should find a way to be more selective about this +#pragma warning(disable: 4702) // Unreachable code + +// +// [pfx_parse] - workaround for old PREfix/PREfast parser +// +#if (defined(_PREFIX_) || defined(_PREFAST_)) && (_MSC_VER < 1400) +#pragma warning (push) +#pragma warning(disable: 4081) // expected 'newline' +#endif // old PREfast parser + +#ifdef _ATL_ALL_WARNINGS +#pragma warning( push ) +#endif + +#pragma warning(disable : 4668) // is not defined as a preprocessor macro, replacing with '0' for '#if/#elif +#pragma warning(disable : 4820) // padding added after member +#pragma warning(disable : 4917) // a GUID can only be associated with a class, interface or namespace + +#pragma warning(disable : 4217) // member template functions cannot be used for copy-assignment or copy-construction + +#pragma warning(disable: 4127) // constant expression +#pragma warning(disable: 4097) // typedef name used as synonym for class-name +#pragma warning(disable: 4786) // identifier was truncated in the debug information +#pragma warning(disable: 4291) // allow placement new +#pragma warning(disable: 4201) // nameless unions are part of C++ +#pragma warning(disable: 4103) // pragma pack +#pragma warning(disable: 4268) // const static/global data initialized to zeros + +#pragma warning (push) +#pragma warning(disable: 4571) //catch(...) blocks compiled with /EHs do NOT catch or re-throw Structured Exceptions +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif +#ifndef ATL_NO_LEAN_AND_MEAN +#define ATL_NO_LEAN_AND_MEAN +#endif + +#include + +#ifndef _WINSOCKAPI_ +#include +#endif + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#if !defined(_ATL_MIN_CRT) & defined(_MT) +#include +#include // for _beginthreadex, _endthreadex +#endif + +#include +#include + +#include +#include +#include +#include +#include + +#define _ATL_TYPELIB_INDEX_LENGTH 10 +#define _ATL_QUOTES_SPACE 2 + +#pragma pack(push, _ATL_PACKING) + +#ifndef _ATL_NO_DEFAULT_LIBS + +#if defined(_ATL_DLL) + #pragma comment(lib, "atl.lib") + +#if !defined(_ATL_NOFORCE_MANIFEST) && !defined(_VC_NODEFAULTLIB) + +#include + +#endif // !defined(_ATL_NOFORCE_MANIFEST) && !defined(_VC_NODEFAULTLIB) + +#endif // _ATL_DLL + +#ifdef _DEBUG + #pragma comment(lib, "atlsd.lib") +#else + #pragma comment(lib, "atls.lib") +#ifdef _ATL_MIN_CRT + #pragma comment(lib, "atlmincrt.lib") +#endif +#endif + +#endif // !_ATL_NO_DEFAULT_LIBS + +#if defined(_ATL_DLL) + // Pull in obj file with manifest directive for ATL dll + #if defined(_M_IX86) + #pragma comment(linker, "/include:__forceAtlDllManifest") + #else + #pragma comment(linker, "/include:_forceAtlDllManifest") + #endif +#endif + +extern "C" const __declspec(selectany) GUID LIBID_ATLLib = {0x44EC0535,0x400F,0x11D0,{0x9D,0xCD,0x00,0xA0,0xC9,0x03,0x91,0xD3}}; +extern "C" const __declspec(selectany) CLSID CLSID_Registrar = {0x44EC053A,0x400F,0x11D0,{0x9D,0xCD,0x00,0xA0,0xC9,0x03,0x91,0xD3}}; +extern "C" const __declspec(selectany) IID IID_IRegistrar = {0x44EC053B,0x400F,0x11D0,{0x9D,0xCD,0x00,0xA0,0xC9,0x03,0x91,0xD3}}; +extern "C" const __declspec(selectany) IID IID_IAxWinHostWindow = {0xb6ea2050,0x048a,0x11d1,{0x82,0xb9,0x00,0xc0,0x4f,0xb9,0x94,0x2e}}; +extern "C" const __declspec(selectany) IID IID_IAxWinAmbientDispatch = {0xb6ea2051,0x048a,0x11d1,{0x82,0xb9,0x00,0xc0,0x4f,0xb9,0x94,0x2e}}; +extern "C" const __declspec(selectany) IID IID_IInternalConnection = {0x72AD0770,0x6A9F,0x11d1,{0xBC,0xEC,0x00,0x60,0x08,0x8F,0x44,0x4E}}; +extern "C" const __declspec(selectany) IID IID_IDocHostUIHandlerDispatch = {0x425B5AF0,0x65F1,0x11d1,{0x96,0x11,0x00,0x00,0xF8,0x1E,0x0D,0x0D}}; +extern "C" const __declspec(selectany) IID IID_IAxWinHostWindowLic = {0x3935BDA8,0x4ED9,0x495c,{0x86,0x50,0xE0,0x1F,0xC1,0xE3,0x8A,0x4B}}; +extern "C" const __declspec(selectany) IID IID_IAxWinAmbientDispatchEx = {0xB2D0778B,0xAC99,0x4c58,{0xA5,0xC8,0xE7,0x72,0x4E,0x53,0x16,0xB5}}; + +// REVIEW: Temp until it gets back into UUID.LIB +extern "C" const __declspec(selectany) CLSID CLSID_StdGlobalInterfaceTable = {0x00000323,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; + +#ifndef _delayimp_h +extern "C" IMAGE_DOS_HEADER __ImageBase; +#endif + +#ifdef _AFX +void AFXAPI AfxOleLockApp(); +void AFXAPI AfxOleUnlockApp(); +#endif // _AFX + + + +namespace ATL +{ + +struct _ATL_CATMAP_ENTRY +{ + int iType; + const CATID* pcatid; +}; + +#define _ATL_CATMAP_ENTRY_END 0 +#define _ATL_CATMAP_ENTRY_IMPLEMENTED 1 +#define _ATL_CATMAP_ENTRY_REQUIRED 2 + +typedef HRESULT (WINAPI _ATL_CREATORFUNC)(void* pv, REFIID riid, LPVOID* ppv); +typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(void* pv, REFIID riid, LPVOID* ppv, DWORD_PTR dw); +typedef HRESULT (WINAPI _ATL_MODULEFUNC)(DWORD_PTR dw); +typedef LPCTSTR (WINAPI _ATL_DESCRIPTIONFUNC)(); +typedef const struct _ATL_CATMAP_ENTRY* (_ATL_CATMAPFUNC)(); +typedef void (__stdcall _ATL_TERMFUNC)(DWORD_PTR dw); + +struct _ATL_TERMFUNC_ELEM +{ + _ATL_TERMFUNC* pFunc; + DWORD_PTR dw; + _ATL_TERMFUNC_ELEM* pNext; +}; + +/* +struct _ATL_OBJMAP_ENTRY20 +{ + const CLSID* pclsid; + HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister); + _ATL_CREATORFUNC* pfnGetClassObject; + _ATL_CREATORFUNC* pfnCreateInstance; + IUnknown* pCF; + DWORD dwRegister; + _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription; +}; +*/ + +// Can't inherit from _ATL_OBJMAP_ENTRY20 +// because it messes up the OBJECT_MAP macros +struct _ATL_OBJMAP_ENTRY30 +{ + const CLSID* pclsid; + HRESULT (WINAPI *pfnUpdateRegistry)(BOOL bRegister); + _ATL_CREATORFUNC* pfnGetClassObject; + _ATL_CREATORFUNC* pfnCreateInstance; + IUnknown* pCF; + DWORD dwRegister; + _ATL_DESCRIPTIONFUNC* pfnGetObjectDescription; + _ATL_CATMAPFUNC* pfnGetCategoryMap; + HRESULT WINAPI RevokeClassObject() + { + if (dwRegister == 0) + return S_OK; + return CoRevokeClassObject(dwRegister); + } + HRESULT WINAPI RegisterClassObject(DWORD dwClsContext, DWORD dwFlags) + { + IUnknown* p = NULL; + if (pfnGetClassObject == NULL) + return S_OK; + HRESULT hRes = pfnGetClassObject(pfnCreateInstance, __uuidof(IUnknown), (LPVOID*) &p); + if (SUCCEEDED(hRes)) + hRes = CoRegisterClassObject(*pclsid, p, dwClsContext, dwFlags, &dwRegister); + if (p != NULL) + p->Release(); + return hRes; + } +// Added in ATL 3.0 + void (WINAPI *pfnObjectMain)(bool bStarting); +}; + +typedef _ATL_OBJMAP_ENTRY30 _ATL_OBJMAP_ENTRY; + +// Auto Object Map + +#if defined(_M_IA64) || defined(_M_IX86) || defined (_M_AMD64) + +#pragma section("ATL$__a", read) +#pragma section("ATL$__z", read) +#pragma section("ATL$__m", read) +extern "C" +{ +__declspec(selectany) __declspec(allocate("ATL$__a")) _ATL_OBJMAP_ENTRY* __pobjMapEntryFirst = NULL; +__declspec(selectany) __declspec(allocate("ATL$__z")) _ATL_OBJMAP_ENTRY* __pobjMapEntryLast = NULL; +} + +#if !defined(_M_IA64) +#pragma comment(linker, "/merge:ATL=.rdata") +#endif + +#else + +extern "C" +{ +__declspec(selectany) _ATL_OBJMAP_ENTRY* __pobjMapEntryFirst = NULL; +__declspec(selectany) _ATL_OBJMAP_ENTRY* __pobjMapEntryLast = NULL; +} + +#endif // defined(_M_IA64) || defined(_M_IX86) + +struct _ATL_REGMAP_ENTRY +{ + LPCOLESTR szKey; + LPCOLESTR szData; +}; + +struct _AtlCreateWndData +{ + void* m_pThis; + DWORD m_dwThreadID; + _AtlCreateWndData* m_pNext; +}; + + +// perfmon registration/unregistration function definitions +typedef HRESULT (*_ATL_PERFREGFUNC)(HINSTANCE hDllInstance); +typedef HRESULT (*_ATL_PERFUNREGFUNC)(); +__declspec(selectany) _ATL_PERFREGFUNC _pPerfRegFunc = NULL; +__declspec(selectany) _ATL_PERFUNREGFUNC _pPerfUnRegFunc = NULL; + +///////////////////////////////////////////////////////////////////////////// +// Threading Model Support + +template< class TLock > +class CComCritSecLock +{ +public: + CComCritSecLock( TLock& cs, bool bInitialLock = true ); + ~CComCritSecLock() throw(); + + HRESULT Lock() throw(); + void Unlock() throw(); + +// Implementation +private: + TLock& m_cs; + bool m_bLocked; + +// Private to avoid accidental use + CComCritSecLock( const CComCritSecLock& ) throw(); + CComCritSecLock& operator=( const CComCritSecLock& ) throw(); +}; + +template< class TLock > +inline CComCritSecLock< TLock >::CComCritSecLock( TLock& cs, bool bInitialLock ) : + m_cs( cs ), + m_bLocked( false ) +{ + if( bInitialLock ) + { + HRESULT hr; + + hr = Lock(); + if( FAILED( hr ) ) + { + AtlThrow( hr ); + } + } +} + +template< class TLock > +inline CComCritSecLock< TLock >::~CComCritSecLock() throw() +{ + if( m_bLocked ) + { + Unlock(); + } +} + +template< class TLock > +inline HRESULT CComCritSecLock< TLock >::Lock() throw() +{ + HRESULT hr; + + ATLASSERT( !m_bLocked ); + hr = m_cs.Lock(); + if( FAILED( hr ) ) + { + return( hr ); + } + m_bLocked = true; + + return( S_OK ); +} + +template< class TLock > +inline void CComCritSecLock< TLock >::Unlock() throw() +{ + ATLASSUME( m_bLocked ); + m_cs.Unlock(); + m_bLocked = false; +} + +class CComMultiThreadModelNoCS +{ +public: + static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);} + static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);} + typedef CComFakeCriticalSection AutoCriticalSection; + typedef CComFakeCriticalSection AutoDeleteCriticalSection; + typedef CComFakeCriticalSection CriticalSection; + typedef CComMultiThreadModelNoCS ThreadModelNoCS; +}; + +class CComMultiThreadModel +{ +public: + static ULONG WINAPI Increment(LPLONG p) throw() {return InterlockedIncrement(p);} + static ULONG WINAPI Decrement(LPLONG p) throw() {return InterlockedDecrement(p);} + typedef CComAutoCriticalSection AutoCriticalSection; + typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection; + typedef CComCriticalSection CriticalSection; + typedef CComMultiThreadModelNoCS ThreadModelNoCS; +}; + +class CComSingleThreadModel +{ +public: + static ULONG WINAPI Increment(LPLONG p) throw() {return ++(*p);} + static ULONG WINAPI Decrement(LPLONG p) throw() {return --(*p);} + typedef CComFakeCriticalSection AutoCriticalSection; + typedef CComFakeCriticalSection AutoDeleteCriticalSection; + typedef CComFakeCriticalSection CriticalSection; + typedef CComSingleThreadModel ThreadModelNoCS; +}; + +#if defined(_ATL_SINGLE_THREADED) + +#if defined(_ATL_APARTMENT_THREADED) || defined(_ATL_FREE_THREADED) +#pragma message ("More than one global threading model defined.") +#endif + + typedef CComSingleThreadModel CComObjectThreadModel; + typedef CComSingleThreadModel CComGlobalsThreadModel; + +#elif defined(_ATL_APARTMENT_THREADED) + +#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_FREE_THREADED) +#pragma message ("More than one global threading model defined.") +#endif + + typedef CComSingleThreadModel CComObjectThreadModel; + typedef CComMultiThreadModel CComGlobalsThreadModel; + +#elif defined(_ATL_FREE_THREADED) + +#if defined(_ATL_SINGLE_THREADED) || defined(_ATL_APARTMENT_THREADED) +#pragma message ("More than one global threading model defined.") +#endif + + typedef CComMultiThreadModel CComObjectThreadModel; + typedef CComMultiThreadModel CComGlobalsThreadModel; + +#else +#pragma message ("No global threading model defined") +#endif + +///////////////////////////////////////////////////////////////////////////// +// Module + + +// Used by COM related code in ATL +struct _ATL_COM_MODULE70 +{ + UINT cbSize; + HINSTANCE m_hInstTypeLib; + _ATL_OBJMAP_ENTRY** m_ppAutoObjMapFirst; + _ATL_OBJMAP_ENTRY** m_ppAutoObjMapLast; + CComCriticalSection m_csObjMap; +}; +typedef _ATL_COM_MODULE70 _ATL_COM_MODULE; + + +// Used by Windowing code in ATL +struct _ATL_WIN_MODULE70 +{ + UINT cbSize; + CComCriticalSection m_csWindowCreate; + _AtlCreateWndData* m_pCreateWndList; + CSimpleArray m_rgWindowClassAtoms; +}; +typedef _ATL_WIN_MODULE70 _ATL_WIN_MODULE; + + +struct _ATL_MODULE70 +{ + UINT cbSize; + LONG m_nLockCnt; + _ATL_TERMFUNC_ELEM* m_pTermFuncs; + CComCriticalSection m_csStaticDataInitAndTypeInfo; +}; +typedef _ATL_MODULE70 _ATL_MODULE; + + +///////////////////////////////////////////////////////////////////////////// +//This define makes debugging asserts easier. +#define _ATL_SIMPLEMAPENTRY ((ATL::_ATL_CREATORARGFUNC*)1) + +struct _ATL_INTMAP_ENTRY +{ + const IID* piid; // the interface id (IID) + DWORD_PTR dw; + _ATL_CREATORARGFUNC* pFunc; //NULL:end, 1:offset, n:ptr +}; + +///////////////////////////////////////////////////////////////////////////// +// Global Functions + +///////////////////////////////////////////////////////////////////////////// +// QI Support + +ATLAPI AtlInternalQueryInterface(void* pThis, + const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject); + +///////////////////////////////////////////////////////////////////////////// +// Inproc Marshaling helpers + +ATLAPI AtlFreeMarshalStream(IStream* pStream); +ATLAPI AtlMarshalPtrInProc(IUnknown* pUnk, const IID& iid, IStream** ppStream); +ATLAPI AtlUnmarshalPtr(IStream* pStream, const IID& iid, IUnknown** ppUnk); + +ATLAPI_(BOOL) AtlWaitWithMessageLoop(HANDLE hEvent); + +///////////////////////////////////////////////////////////////////////////// +// Connection Point Helpers + +ATLAPI AtlAdvise(IUnknown* pUnkCP, IUnknown* pUnk, const IID& iid, LPDWORD pdw); +ATLAPI AtlUnadvise(IUnknown* pUnkCP, const IID& iid, DWORD dw); + +///////////////////////////////////////////////////////////////////////////// +// IDispatch Error handling + +ATLAPI AtlSetErrorInfo(const CLSID& clsid, LPCOLESTR lpszDesc, + DWORD dwHelpID, LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes, + HINSTANCE hInst); + +///////////////////////////////////////////////////////////////////////////// +// Module + +ATLAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE* pComModule, DWORD dwClsContext, DWORD dwFlags); +ATLAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE* pComModule); + +ATLAPI AtlComModuleGetClassObject(_ATL_COM_MODULE* pComModule, REFCLSID rclsid, REFIID riid, LPVOID* ppv); + +ATLAPI AtlComModuleRegisterServer(_ATL_COM_MODULE* pComModule, BOOL bRegTypeLib, const CLSID* pCLSID = NULL); +ATLAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE* pComModule, BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL); + +ATLAPI AtlRegisterClassCategoriesHelper( REFCLSID clsid, const struct _ATL_CATMAP_ENTRY* pCatMap, BOOL bRegister ); + +ATLAPI AtlUpdateRegistryFromResourceD(HINSTANCE hInst, LPCOLESTR lpszRes, + BOOL bRegister, struct _ATL_REGMAP_ENTRY* pMapEntries, IRegistrar* pReg = NULL); + +ATLAPI AtlRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex); +ATLAPI AtlUnRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex); +ATLAPI AtlLoadTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex, BSTR* pbstrPath, ITypeLib** ppTypeLib); + +ATLAPI_(DWORD) AtlGetVersion(void* pReserved); + +ATLAPI AtlModuleAddTermFunc(_ATL_MODULE* pModule, _ATL_TERMFUNC* pFunc, DWORD_PTR dw); +ATLAPI_(void) AtlCallTermFunc(_ATL_MODULE* pModule); + +ATLAPI AtlWinModuleInit(_ATL_WIN_MODULE* pWinModule); +ATLAPIINL AtlWinModuleTerm(_ATL_WIN_MODULE* pWinModule, HINSTANCE hInst); + +ATLAPI_(void) AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE* pWinModule, _AtlCreateWndData* pData, void* pObject); +ATLAPI_(void*) AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE* pWinModule); + +///////////////////////////////////////////////////////////////////////////// +// Get Registrar object from ATL DLL. + +#if !defined(_ATL_STATIC_REGISTRY) +#ifdef _ATL_DLL_IMPL +extern "C" HRESULT __stdcall AtlCreateRegistrar(IRegistrar** ppReg); +#else +extern "C" __declspec(dllimport) HRESULT __stdcall AtlCreateRegistrar(IRegistrar** ppReg); +#endif +#endif + +///////////////////////////////////////////////////////////////////////////// +// GUID comparison +inline BOOL WINAPI InlineIsEqualUnknown(REFGUID rguid1) +{ + return ( + ((PLONG) &rguid1)[0] == 0 && + ((PLONG) &rguid1)[1] == 0 && +#ifdef _ATL_BYTESWAP + ((PLONG) &rguid1)[2] == 0xC0000000 && + ((PLONG) &rguid1)[3] == 0x00000046); +#else + ((PLONG) &rguid1)[2] == 0x000000C0 && + ((PLONG) &rguid1)[3] == 0x46000000); +#endif +} + + + +template +LPCTSTR AtlDebugGetClassName(T*) +{ +#ifdef _DEBUG + const _ATL_INTMAP_ENTRY* pEntries = T::_GetEntries(); + return (LPCTSTR)pEntries[-1].dw; +#else + return NULL; +#endif +} + +// Validation macro for OUT pointer +// Used in QI and CreateInstance +#define _ATL_VALIDATE_OUT_POINTER(x)\ + do { \ + ATLASSERT(x != NULL); \ + if (x == NULL) \ + return E_POINTER; \ + *x = NULL; \ + } while(0) + +///////////////////////////////////////////////////////////////////////////// +// Win32 libraries + +#ifndef _ATL_NO_DEFAULT_LIBS +#pragma comment(lib, "kernel32.lib") +#pragma comment(lib, "user32.lib") +#pragma comment(lib, "advapi32.lib") +#pragma comment(lib, "ole32.lib") +#pragma comment(lib, "shell32.lib") +#pragma comment(lib, "oleaut32.lib") +#pragma comment(lib, "uuid.lib") +#pragma comment(lib, "shlwapi.lib") +#endif // !_ATL_NO_DEFAULT_LIBS + +template< typename T > +class CAutoVectorPtr +{ +public: + CAutoVectorPtr() throw() : + m_p( NULL ) + { + } + CAutoVectorPtr( CAutoVectorPtr< T >& p ) throw() + { + m_p = p.Detach(); // Transfer ownership + } + explicit CAutoVectorPtr( T* p ) throw() : + m_p( p ) + { + } + ~CAutoVectorPtr() throw() + { + Free(); + } + + operator T*() const throw() + { + return( m_p ); + } + + CAutoVectorPtr< T >& operator=( CAutoVectorPtr< T >& p ) throw() + { + if(*this==p) + { + if(this!=&p) + { + // If this assert fires, it means you attempted to assign one CAutoVectorPtr to another when they both contained + // a pointer to the same underlying vector. This means a bug in your code, since your vector will get + // double-deleted. + ATLASSERT(FALSE); + + // For safety, we are going to detach the other CAutoVectorPtr to avoid a double-free. Your code still + // has a bug, though. + p.Detach(); + } + else + { + // Alternatively, this branch means that you are assigning a CAutoVectorPtr to itself, which is + // pointless but permissible + + // nothing to do + } + } + else + { + Free(); + Attach( p.Detach() ); // Transfer ownership + } + return( *this ); + } + + // basic comparison operators + bool operator!=(CAutoVectorPtr& p) const + { + return !operator==(p); + } + + bool operator==(CAutoVectorPtr& p) const + { + return m_p==p.m_p; + } + + // Allocate the vector + bool Allocate( size_t nElements ) throw() + { + ATLASSUME( m_p == NULL ); + ATLTRY( m_p = new T[nElements] ); + if( m_p == NULL ) + { + return( false ); + } + + return( true ); + } + // Attach to an existing pointer (takes ownership) + void Attach( T* p ) throw() + { + ATLASSUME( m_p == NULL ); + m_p = p; + } + // Detach the pointer (releases ownership) + T* Detach() throw() + { + T* p; + + p = m_p; + m_p = NULL; + + return( p ); + } + // Delete the vector pointed to, and set the pointer to NULL + void Free() throw() + { + delete[] m_p; + m_p = NULL; + } + +public: + T* m_p; +}; + +template< typename T > +class CAutoPtr +{ +public: + CAutoPtr() throw() : + m_p( NULL ) + { + } + template< typename TSrc > + CAutoPtr( CAutoPtr< TSrc >& p ) throw() + { + m_p = p.Detach(); // Transfer ownership + } +// +// [pfx_parse] - workaround for PREfix parse problems +// +#if (!defined(_PREFIX_)) && (!defined(_PREFAST_)) + CAutoPtr( CAutoPtr< T >& p ) throw() + { + m_p = p.Detach(); // Transfer ownership + } +#endif // !_PREFIX_ + explicit CAutoPtr( T* p ) throw() : + m_p( p ) + { + } + ~CAutoPtr() throw() + { + Free(); + } + + // Templated version to allow pBase = pDerived + template< typename TSrc > + CAutoPtr< T >& operator=( CAutoPtr< TSrc >& p ) throw() + { + if(m_p==p.m_p) + { + // This means that two CAutoPtrs of two different types had the same m_p in them + // which is never correct + ATLASSERT(FALSE); + } + else + { + Free(); + Attach( p.Detach() ); // Transfer ownership + } + return( *this ); + } + CAutoPtr< T >& operator=( CAutoPtr< T >& p ) throw() + { + if(*this==p) + { + if(this!=&p) + { + // If this assert fires, it means you attempted to assign one CAutoPtr to another when they both contained + // a pointer to the same underlying object. This means a bug in your code, since your object will get + // double-deleted. +#ifdef ATL_AUTOPTR_ASSIGNMENT_ASSERT + ATLASSERT(FALSE); +#endif + + // For safety, we are going to detach the other CAutoPtr to avoid a double-free. Your code still + // has a bug, though. + p.Detach(); + } + else + { + // Alternatively, this branch means that you are assigning a CAutoPtr to itself, which is + // pointless but permissible + + // nothing to do + } + } + else + { + Free(); + Attach( p.Detach() ); // Transfer ownership + } + return( *this ); + } + + // basic comparison operators + bool operator!=(CAutoPtr& p) const + { + return !operator==(p); + } + + bool operator==(CAutoPtr& p) const + { + return m_p==p.m_p; + } + + operator T*() const throw() + { + return( m_p ); + } + T* operator->() const throw() + { + ATLASSUME( m_p != NULL ); + return( m_p ); + } + + // Attach to an existing pointer (takes ownership) + void Attach( T* p ) throw() + { + ATLASSUME( m_p == NULL ); + m_p = p; + } + // Detach the pointer (releases ownership) + T* Detach() throw() + { + T* p; + + p = m_p; + m_p = NULL; + + return( p ); + } + // Delete the object pointed to, and set the pointer to NULL + void Free() throw() + { + delete m_p; + m_p = NULL; + } + +public: + T* m_p; +}; + +/* Automatic cleanup for _malloca objects */ +template< typename T > +class CAutoStackPtr +{ +public: + CAutoStackPtr() throw() : + m_p( NULL ) + { + } + template< typename TSrc > + CAutoStackPtr( CAutoStackPtr< TSrc >& p ) throw() + { + m_p = p.Detach(); // Transfer ownership + } + CAutoStackPtr( CAutoStackPtr< T >& p ) throw() + { + m_p = p.Detach(); // Transfer ownership + } + explicit CAutoStackPtr( T* p ) throw() : + m_p( p ) + { + } + ~CAutoStackPtr() throw() + { + Free(); + } + + // Templated version to allow pBase = pDerived + template< typename TSrc > + CAutoStackPtr< T >& operator=( CAutoStackPtr< TSrc >& p ) throw() + { + if(m_p==p.m_p) + { + // This means that two CAutoPtrs of two different types had the same m_p in them + // which is never correct + ATLASSERT(FALSE); + } + else + { + Free(); + Attach( p.Detach() ); // Transfer ownership + } + return( *this ); + } + CAutoStackPtr< T >& operator=( CAutoStackPtr< T >& p ) throw() + { + if(*this==p) + { + if(this!=&p) + { + // If this assert fires, it means you attempted to assign one CAutoPtr to another when they both contained + // a pointer to the same underlying object. This means a bug in your code, since your object will get + // double-deleted. + ATLASSERT(FALSE); + + // For safety, we are going to detach the other CAutoPtr to avoid a double-free. Your code still + // has a bug, though. + p.Detach(); + } + else + { + // Alternatively, this branch means that you are assigning a CAutoPtr to itself, which is + // pointless but permissible + + // nothing to do + } + } + else + { + Free(); + Attach( p.Detach() ); // Transfer ownership + } + return( *this ); + } + + // basic comparison operators + bool operator!=(CAutoStackPtr& p) const + { + return !operator==(p); + } + + bool operator==(CAutoStackPtr& p) const + { + return m_p==p.m_p; + } + + operator T*() const throw() + { + return( m_p ); + } + T* operator->() const throw() + { + ATLASSUME( m_p != NULL ); + return( m_p ); + } + + // Attach to an existing pointer (takes ownership) + void Attach( T* p ) throw() + { + ATLASSUME( m_p == NULL ); + m_p = p; + } + // Detach the pointer (releases ownership) + T* Detach() throw() + { + T* p; + + p = m_p; + m_p = NULL; + + return( p ); + } + // Delete the object pointed to, and set the pointer to NULL + void Free() throw() + { + /* Note: _freea only actually does anything if m_p was heap allocated + If m_p was from the stack, it wouldn't be possible to actually free it here + [wrong function] unless we got inlined. But really all we do if m_p is + stack-based is ignore it and let its alloca storage disappear at the end + of the outer function. + */ + _freea(m_p); + m_p = NULL; + } + +public: + T* m_p; +}; + +// static_cast_auto template functions. Used like static_cast, only they work on CAutoPtr objects +template< class Dest, class Src > +Dest* static_cast_auto( const CAutoPtr< Src >& pSrc ) throw() +{ + return( static_cast< Dest* >( static_cast< Src* >( pSrc ) ) ); +} + + +class CComAllocator +{ +public: + static void* Reallocate(void* p, size_t nBytes) throw() + { +#ifdef _WIN64 + if( nBytes > INT_MAX ) + { + return( NULL ); + } +#endif + return ::CoTaskMemRealloc(p, ULONG(nBytes)); + } + static void* Allocate(size_t nBytes) throw() + { +#ifdef _WIN64 + if( nBytes > INT_MAX ) + { + return( NULL ); + } +#endif + return ::CoTaskMemAlloc(ULONG(nBytes)); + } + static void Free(void* p) throw() + { + ::CoTaskMemFree(p); + } +}; + +template +class CComHeapPtr : + public CHeapPtr +{ +public: + CComHeapPtr() throw() + { + } + + explicit CComHeapPtr(T* pData) throw() : + CHeapPtr(pData) + { + } +}; + +template +T* AtlSafeRealloc(T* pT, size_t cEls) throw() +{ + T* pTemp; + + size_t nBytes=0; + if(FAILED(::ATL::AtlMultiply(&nBytes, cEls, sizeof(T)))) + { + return NULL; + } + pTemp = static_cast(Reallocator::Reallocate(pT, nBytes)); + if (pTemp == NULL) + { + Reallocator::Free(pT); + return NULL; + } + pT = pTemp; + return pTemp; +} + +class CHandle +{ +public: + CHandle() throw(); + CHandle( CHandle& h ) throw(); + explicit CHandle( HANDLE h ) throw(); + ~CHandle() throw(); + + CHandle& operator=( CHandle& h ) throw(); + + operator HANDLE() const throw(); + + // Attach to an existing handle (takes ownership). + void Attach( HANDLE h ) throw(); + // Detach the handle from the object (releases ownership). + HANDLE Detach() throw(); + + // Close the handle. + void Close() throw(); + +public: + HANDLE m_h; +}; + +inline CHandle::CHandle() throw() : + m_h( NULL ) +{ +} + +inline CHandle::CHandle( CHandle& h ) throw() : + m_h( NULL ) +{ + Attach( h.Detach() ); +} + +inline CHandle::CHandle( HANDLE h ) throw() : + m_h( h ) +{ +} + +inline CHandle::~CHandle() throw() +{ + if( m_h != NULL ) + { + Close(); + } +} + +inline CHandle& CHandle::operator=( CHandle& h ) throw() +{ + if( this != &h ) + { + if( m_h != NULL ) + { + Close(); + } + Attach( h.Detach() ); + } + + return( *this ); +} + +inline CHandle::operator HANDLE() const throw() +{ + return( m_h ); +} + +inline void CHandle::Attach( HANDLE h ) throw() +{ + ATLASSUME( m_h == NULL ); + m_h = h; // Take ownership +} + +inline HANDLE CHandle::Detach() throw() +{ + HANDLE h; + + h = m_h; // Release ownership + m_h = NULL; + + return( h ); +} + +inline void CHandle::Close() throw() +{ + if( m_h != NULL ) + { + ::CloseHandle( m_h ); + m_h = NULL; + } +} + +class CCritSecLock +{ +public: + CCritSecLock( CRITICAL_SECTION& cs, bool bInitialLock = true ); + ~CCritSecLock() throw(); + + void Lock(); + void Unlock() throw(); + +// Implementation +private: + CRITICAL_SECTION& m_cs; + bool m_bLocked; + +// Private to avoid accidental use + CCritSecLock( const CCritSecLock& ) throw(); + CCritSecLock& operator=( const CCritSecLock& ) throw(); +}; + +inline CCritSecLock::CCritSecLock( CRITICAL_SECTION& cs, bool bInitialLock ) : + m_cs( cs ), + m_bLocked( false ) +{ + if( bInitialLock ) + { + Lock(); + } +} + +inline CCritSecLock::~CCritSecLock() throw() +{ + if( m_bLocked ) + { + Unlock(); + } +} + +inline void CCritSecLock::Lock() +{ + ATLASSERT( !m_bLocked ); + __try + { + ::EnterCriticalSection( &m_cs ); + } + __except( STATUS_NO_MEMORY == GetExceptionCode() ) + { + AtlThrow( E_OUTOFMEMORY ); + } + m_bLocked = true; +} + +inline void CCritSecLock::Unlock() throw() +{ + ATLASSUME( m_bLocked ); + ::LeaveCriticalSection( &m_cs ); + m_bLocked = false; +} + +///////////////////////////////////////////////////////////////////////////// +// Interface debugging +#if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI) +HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr) throw(); +#endif // _ATL_DEBUG_INTERFACES || _ATL_DEBUG_QI + +#ifdef _ATL_DEBUG_INTERFACES + +struct _QIThunk +{ + STDMETHOD(QueryInterface)(REFIID iid, void** pp) + { + ATLASSUME(m_dwRef >= 0); + ATLASSUME(m_pUnk != NULL); + return m_pUnk->QueryInterface(iid, pp); + } + STDMETHOD_(ULONG, AddRef)() + { + ATLASSUME(m_pUnk != NULL); + if (m_bBreak) + DebugBreak(); + m_pUnk->AddRef(); + return InternalAddRef(); + } + ULONG InternalAddRef() + { + ATLASSUME(m_pUnk != NULL); + if (m_bBreak) + DebugBreak(); + ATLASSUME(m_dwRef >= 0); + long l = InterlockedIncrement(&m_dwRef); + + TCHAR buf[512+1]; +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) + _stprintf_s(buf, _countof(buf), _T("QIThunk - %-10d\tAddRef :\tObject = 0x%p\tRefcount = %d\t"), + m_nIndex, m_pUnk, m_dwRef); +#else +#pragma warning(push) +#pragma warning(disable:4995) // wsprintf is deprecated + wsprintf(buf, _T("QIThunk - %-10d\tAddRef :\tObject = 0x%p\tRefcount = %d\t"), m_nIndex, m_pUnk, m_dwRef); +#pragma warning(pop) +#endif + buf[_countof(buf)-1] = 0; + OutputDebugString(buf); + AtlDumpIID(m_iid, m_lpszClassName, S_OK); + + if (l > m_dwMaxRef) + m_dwMaxRef = l; + return l; + } + STDMETHOD_(ULONG, Release)(); + + STDMETHOD(f3)(); + STDMETHOD(f4)(); + STDMETHOD(f5)(); + STDMETHOD(f6)(); + STDMETHOD(f7)(); + STDMETHOD(f8)(); + STDMETHOD(f9)(); + STDMETHOD(f10)(); + STDMETHOD(f11)(); + STDMETHOD(f12)(); + STDMETHOD(f13)(); + STDMETHOD(f14)(); + STDMETHOD(f15)(); + STDMETHOD(f16)(); + STDMETHOD(f17)(); + STDMETHOD(f18)(); + STDMETHOD(f19)(); + STDMETHOD(f20)(); + STDMETHOD(f21)(); + STDMETHOD(f22)(); + STDMETHOD(f23)(); + STDMETHOD(f24)(); + STDMETHOD(f25)(); + STDMETHOD(f26)(); + STDMETHOD(f27)(); + STDMETHOD(f28)(); + STDMETHOD(f29)(); + STDMETHOD(f30)(); + STDMETHOD(f31)(); + STDMETHOD(f32)(); + STDMETHOD(f33)(); + STDMETHOD(f34)(); + STDMETHOD(f35)(); + STDMETHOD(f36)(); + STDMETHOD(f37)(); + STDMETHOD(f38)(); + STDMETHOD(f39)(); + STDMETHOD(f40)(); + STDMETHOD(f41)(); + STDMETHOD(f42)(); + STDMETHOD(f43)(); + STDMETHOD(f44)(); + STDMETHOD(f45)(); + STDMETHOD(f46)(); + STDMETHOD(f47)(); + STDMETHOD(f48)(); + STDMETHOD(f49)(); + STDMETHOD(f50)(); + STDMETHOD(f51)(); + STDMETHOD(f52)(); + STDMETHOD(f53)(); + STDMETHOD(f54)(); + STDMETHOD(f55)(); + STDMETHOD(f56)(); + STDMETHOD(f57)(); + STDMETHOD(f58)(); + STDMETHOD(f59)(); + STDMETHOD(f60)(); + STDMETHOD(f61)(); + STDMETHOD(f62)(); + STDMETHOD(f63)(); + STDMETHOD(f64)(); + STDMETHOD(f65)(); + STDMETHOD(f66)(); + STDMETHOD(f67)(); + STDMETHOD(f68)(); + STDMETHOD(f69)(); + STDMETHOD(f70)(); + STDMETHOD(f71)(); + STDMETHOD(f72)(); + STDMETHOD(f73)(); + STDMETHOD(f74)(); + STDMETHOD(f75)(); + STDMETHOD(f76)(); + STDMETHOD(f77)(); + STDMETHOD(f78)(); + STDMETHOD(f79)(); + STDMETHOD(f80)(); + STDMETHOD(f81)(); + STDMETHOD(f82)(); + STDMETHOD(f83)(); + STDMETHOD(f84)(); + STDMETHOD(f85)(); + STDMETHOD(f86)(); + STDMETHOD(f87)(); + STDMETHOD(f88)(); + STDMETHOD(f89)(); + STDMETHOD(f90)(); + STDMETHOD(f91)(); + STDMETHOD(f92)(); + STDMETHOD(f93)(); + STDMETHOD(f94)(); + STDMETHOD(f95)(); + STDMETHOD(f96)(); + STDMETHOD(f97)(); + STDMETHOD(f98)(); + STDMETHOD(f99)(); + STDMETHOD(f100)(); + STDMETHOD(f101)(); + STDMETHOD(f102)(); + STDMETHOD(f103)(); + STDMETHOD(f104)(); + STDMETHOD(f105)(); + STDMETHOD(f106)(); + STDMETHOD(f107)(); + STDMETHOD(f108)(); + STDMETHOD(f109)(); + STDMETHOD(f110)(); + STDMETHOD(f111)(); + STDMETHOD(f112)(); + STDMETHOD(f113)(); + STDMETHOD(f114)(); + STDMETHOD(f115)(); + STDMETHOD(f116)(); + STDMETHOD(f117)(); + STDMETHOD(f118)(); + STDMETHOD(f119)(); + STDMETHOD(f120)(); + STDMETHOD(f121)(); + STDMETHOD(f122)(); + STDMETHOD(f123)(); + STDMETHOD(f124)(); + STDMETHOD(f125)(); + STDMETHOD(f126)(); + STDMETHOD(f127)(); + STDMETHOD(f128)(); + STDMETHOD(f129)(); + STDMETHOD(f130)(); + STDMETHOD(f131)(); + STDMETHOD(f132)(); + STDMETHOD(f133)(); + STDMETHOD(f134)(); + STDMETHOD(f135)(); + STDMETHOD(f136)(); + STDMETHOD(f137)(); + STDMETHOD(f138)(); + STDMETHOD(f139)(); + STDMETHOD(f140)(); + STDMETHOD(f141)(); + STDMETHOD(f142)(); + STDMETHOD(f143)(); + STDMETHOD(f144)(); + STDMETHOD(f145)(); + STDMETHOD(f146)(); + STDMETHOD(f147)(); + STDMETHOD(f148)(); + STDMETHOD(f149)(); + STDMETHOD(f150)(); + STDMETHOD(f151)(); + STDMETHOD(f152)(); + STDMETHOD(f153)(); + STDMETHOD(f154)(); + STDMETHOD(f155)(); + STDMETHOD(f156)(); + STDMETHOD(f157)(); + STDMETHOD(f158)(); + STDMETHOD(f159)(); + STDMETHOD(f160)(); + STDMETHOD(f161)(); + STDMETHOD(f162)(); + STDMETHOD(f163)(); + STDMETHOD(f164)(); + STDMETHOD(f165)(); + STDMETHOD(f166)(); + STDMETHOD(f167)(); + STDMETHOD(f168)(); + STDMETHOD(f169)(); + STDMETHOD(f170)(); + STDMETHOD(f171)(); + STDMETHOD(f172)(); + STDMETHOD(f173)(); + STDMETHOD(f174)(); + STDMETHOD(f175)(); + STDMETHOD(f176)(); + STDMETHOD(f177)(); + STDMETHOD(f178)(); + STDMETHOD(f179)(); + STDMETHOD(f180)(); + STDMETHOD(f181)(); + STDMETHOD(f182)(); + STDMETHOD(f183)(); + STDMETHOD(f184)(); + STDMETHOD(f185)(); + STDMETHOD(f186)(); + STDMETHOD(f187)(); + STDMETHOD(f188)(); + STDMETHOD(f189)(); + STDMETHOD(f190)(); + STDMETHOD(f191)(); + STDMETHOD(f192)(); + STDMETHOD(f193)(); + STDMETHOD(f194)(); + STDMETHOD(f195)(); + STDMETHOD(f196)(); + STDMETHOD(f197)(); + STDMETHOD(f198)(); + STDMETHOD(f199)(); + STDMETHOD(f200)(); + STDMETHOD(f201)(); + STDMETHOD(f202)(); + STDMETHOD(f203)(); + STDMETHOD(f204)(); + STDMETHOD(f205)(); + STDMETHOD(f206)(); + STDMETHOD(f207)(); + STDMETHOD(f208)(); + STDMETHOD(f209)(); + STDMETHOD(f210)(); + STDMETHOD(f211)(); + STDMETHOD(f212)(); + STDMETHOD(f213)(); + STDMETHOD(f214)(); + STDMETHOD(f215)(); + STDMETHOD(f216)(); + STDMETHOD(f217)(); + STDMETHOD(f218)(); + STDMETHOD(f219)(); + STDMETHOD(f220)(); + STDMETHOD(f221)(); + STDMETHOD(f222)(); + STDMETHOD(f223)(); + STDMETHOD(f224)(); + STDMETHOD(f225)(); + STDMETHOD(f226)(); + STDMETHOD(f227)(); + STDMETHOD(f228)(); + STDMETHOD(f229)(); + STDMETHOD(f230)(); + STDMETHOD(f231)(); + STDMETHOD(f232)(); + STDMETHOD(f233)(); + STDMETHOD(f234)(); + STDMETHOD(f235)(); + STDMETHOD(f236)(); + STDMETHOD(f237)(); + STDMETHOD(f238)(); + STDMETHOD(f239)(); + STDMETHOD(f240)(); + STDMETHOD(f241)(); + STDMETHOD(f242)(); + STDMETHOD(f243)(); + STDMETHOD(f244)(); + STDMETHOD(f245)(); + STDMETHOD(f246)(); + STDMETHOD(f247)(); + STDMETHOD(f248)(); + STDMETHOD(f249)(); + STDMETHOD(f250)(); + STDMETHOD(f251)(); + STDMETHOD(f252)(); + STDMETHOD(f253)(); + STDMETHOD(f254)(); + STDMETHOD(f255)(); + STDMETHOD(f256)(); + STDMETHOD(f257)(); + STDMETHOD(f258)(); + STDMETHOD(f259)(); + STDMETHOD(f260)(); + STDMETHOD(f261)(); + STDMETHOD(f262)(); + STDMETHOD(f263)(); + STDMETHOD(f264)(); + STDMETHOD(f265)(); + STDMETHOD(f266)(); + STDMETHOD(f267)(); + STDMETHOD(f268)(); + STDMETHOD(f269)(); + STDMETHOD(f270)(); + STDMETHOD(f271)(); + STDMETHOD(f272)(); + STDMETHOD(f273)(); + STDMETHOD(f274)(); + STDMETHOD(f275)(); + STDMETHOD(f276)(); + STDMETHOD(f277)(); + STDMETHOD(f278)(); + STDMETHOD(f279)(); + STDMETHOD(f280)(); + STDMETHOD(f281)(); + STDMETHOD(f282)(); + STDMETHOD(f283)(); + STDMETHOD(f284)(); + STDMETHOD(f285)(); + STDMETHOD(f286)(); + STDMETHOD(f287)(); + STDMETHOD(f288)(); + STDMETHOD(f289)(); + STDMETHOD(f290)(); + STDMETHOD(f291)(); + STDMETHOD(f292)(); + STDMETHOD(f293)(); + STDMETHOD(f294)(); + STDMETHOD(f295)(); + STDMETHOD(f296)(); + STDMETHOD(f297)(); + STDMETHOD(f298)(); + STDMETHOD(f299)(); + STDMETHOD(f300)(); + STDMETHOD(f301)(); + STDMETHOD(f302)(); + STDMETHOD(f303)(); + STDMETHOD(f304)(); + STDMETHOD(f305)(); + STDMETHOD(f306)(); + STDMETHOD(f307)(); + STDMETHOD(f308)(); + STDMETHOD(f309)(); + STDMETHOD(f310)(); + STDMETHOD(f311)(); + STDMETHOD(f312)(); + STDMETHOD(f313)(); + STDMETHOD(f314)(); + STDMETHOD(f315)(); + STDMETHOD(f316)(); + STDMETHOD(f317)(); + STDMETHOD(f318)(); + STDMETHOD(f319)(); + STDMETHOD(f320)(); + STDMETHOD(f321)(); + STDMETHOD(f322)(); + STDMETHOD(f323)(); + STDMETHOD(f324)(); + STDMETHOD(f325)(); + STDMETHOD(f326)(); + STDMETHOD(f327)(); + STDMETHOD(f328)(); + STDMETHOD(f329)(); + STDMETHOD(f330)(); + STDMETHOD(f331)(); + STDMETHOD(f332)(); + STDMETHOD(f333)(); + STDMETHOD(f334)(); + STDMETHOD(f335)(); + STDMETHOD(f336)(); + STDMETHOD(f337)(); + STDMETHOD(f338)(); + STDMETHOD(f339)(); + STDMETHOD(f340)(); + STDMETHOD(f341)(); + STDMETHOD(f342)(); + STDMETHOD(f343)(); + STDMETHOD(f344)(); + STDMETHOD(f345)(); + STDMETHOD(f346)(); + STDMETHOD(f347)(); + STDMETHOD(f348)(); + STDMETHOD(f349)(); + STDMETHOD(f350)(); + STDMETHOD(f351)(); + STDMETHOD(f352)(); + STDMETHOD(f353)(); + STDMETHOD(f354)(); + STDMETHOD(f355)(); + STDMETHOD(f356)(); + STDMETHOD(f357)(); + STDMETHOD(f358)(); + STDMETHOD(f359)(); + STDMETHOD(f360)(); + STDMETHOD(f361)(); + STDMETHOD(f362)(); + STDMETHOD(f363)(); + STDMETHOD(f364)(); + STDMETHOD(f365)(); + STDMETHOD(f366)(); + STDMETHOD(f367)(); + STDMETHOD(f368)(); + STDMETHOD(f369)(); + STDMETHOD(f370)(); + STDMETHOD(f371)(); + STDMETHOD(f372)(); + STDMETHOD(f373)(); + STDMETHOD(f374)(); + STDMETHOD(f375)(); + STDMETHOD(f376)(); + STDMETHOD(f377)(); + STDMETHOD(f378)(); + STDMETHOD(f379)(); + STDMETHOD(f380)(); + STDMETHOD(f381)(); + STDMETHOD(f382)(); + STDMETHOD(f383)(); + STDMETHOD(f384)(); + STDMETHOD(f385)(); + STDMETHOD(f386)(); + STDMETHOD(f387)(); + STDMETHOD(f388)(); + STDMETHOD(f389)(); + STDMETHOD(f390)(); + STDMETHOD(f391)(); + STDMETHOD(f392)(); + STDMETHOD(f393)(); + STDMETHOD(f394)(); + STDMETHOD(f395)(); + STDMETHOD(f396)(); + STDMETHOD(f397)(); + STDMETHOD(f398)(); + STDMETHOD(f399)(); + STDMETHOD(f400)(); + STDMETHOD(f401)(); + STDMETHOD(f402)(); + STDMETHOD(f403)(); + STDMETHOD(f404)(); + STDMETHOD(f405)(); + STDMETHOD(f406)(); + STDMETHOD(f407)(); + STDMETHOD(f408)(); + STDMETHOD(f409)(); + STDMETHOD(f410)(); + STDMETHOD(f411)(); + STDMETHOD(f412)(); + STDMETHOD(f413)(); + STDMETHOD(f414)(); + STDMETHOD(f415)(); + STDMETHOD(f416)(); + STDMETHOD(f417)(); + STDMETHOD(f418)(); + STDMETHOD(f419)(); + STDMETHOD(f420)(); + STDMETHOD(f421)(); + STDMETHOD(f422)(); + STDMETHOD(f423)(); + STDMETHOD(f424)(); + STDMETHOD(f425)(); + STDMETHOD(f426)(); + STDMETHOD(f427)(); + STDMETHOD(f428)(); + STDMETHOD(f429)(); + STDMETHOD(f430)(); + STDMETHOD(f431)(); + STDMETHOD(f432)(); + STDMETHOD(f433)(); + STDMETHOD(f434)(); + STDMETHOD(f435)(); + STDMETHOD(f436)(); + STDMETHOD(f437)(); + STDMETHOD(f438)(); + STDMETHOD(f439)(); + STDMETHOD(f440)(); + STDMETHOD(f441)(); + STDMETHOD(f442)(); + STDMETHOD(f443)(); + STDMETHOD(f444)(); + STDMETHOD(f445)(); + STDMETHOD(f446)(); + STDMETHOD(f447)(); + STDMETHOD(f448)(); + STDMETHOD(f449)(); + STDMETHOD(f450)(); + STDMETHOD(f451)(); + STDMETHOD(f452)(); + STDMETHOD(f453)(); + STDMETHOD(f454)(); + STDMETHOD(f455)(); + STDMETHOD(f456)(); + STDMETHOD(f457)(); + STDMETHOD(f458)(); + STDMETHOD(f459)(); + STDMETHOD(f460)(); + STDMETHOD(f461)(); + STDMETHOD(f462)(); + STDMETHOD(f463)(); + STDMETHOD(f464)(); + STDMETHOD(f465)(); + STDMETHOD(f466)(); + STDMETHOD(f467)(); + STDMETHOD(f468)(); + STDMETHOD(f469)(); + STDMETHOD(f470)(); + STDMETHOD(f471)(); + STDMETHOD(f472)(); + STDMETHOD(f473)(); + STDMETHOD(f474)(); + STDMETHOD(f475)(); + STDMETHOD(f476)(); + STDMETHOD(f477)(); + STDMETHOD(f478)(); + STDMETHOD(f479)(); + STDMETHOD(f480)(); + STDMETHOD(f481)(); + STDMETHOD(f482)(); + STDMETHOD(f483)(); + STDMETHOD(f484)(); + STDMETHOD(f485)(); + STDMETHOD(f486)(); + STDMETHOD(f487)(); + STDMETHOD(f488)(); + STDMETHOD(f489)(); + STDMETHOD(f490)(); + STDMETHOD(f491)(); + STDMETHOD(f492)(); + STDMETHOD(f493)(); + STDMETHOD(f494)(); + STDMETHOD(f495)(); + STDMETHOD(f496)(); + STDMETHOD(f497)(); + STDMETHOD(f498)(); + STDMETHOD(f499)(); + STDMETHOD(f500)(); + STDMETHOD(f501)(); + STDMETHOD(f502)(); + STDMETHOD(f503)(); + STDMETHOD(f504)(); + STDMETHOD(f505)(); + STDMETHOD(f506)(); + STDMETHOD(f507)(); + STDMETHOD(f508)(); + STDMETHOD(f509)(); + STDMETHOD(f510)(); + STDMETHOD(f511)(); + STDMETHOD(f512)(); + STDMETHOD(f513)(); + STDMETHOD(f514)(); + STDMETHOD(f515)(); + STDMETHOD(f516)(); + STDMETHOD(f517)(); + STDMETHOD(f518)(); + STDMETHOD(f519)(); + STDMETHOD(f520)(); + STDMETHOD(f521)(); + STDMETHOD(f522)(); + STDMETHOD(f523)(); + STDMETHOD(f524)(); + STDMETHOD(f525)(); + STDMETHOD(f526)(); + STDMETHOD(f527)(); + STDMETHOD(f528)(); + STDMETHOD(f529)(); + STDMETHOD(f530)(); + STDMETHOD(f531)(); + STDMETHOD(f532)(); + STDMETHOD(f533)(); + STDMETHOD(f534)(); + STDMETHOD(f535)(); + STDMETHOD(f536)(); + STDMETHOD(f537)(); + STDMETHOD(f538)(); + STDMETHOD(f539)(); + STDMETHOD(f540)(); + STDMETHOD(f541)(); + STDMETHOD(f542)(); + STDMETHOD(f543)(); + STDMETHOD(f544)(); + STDMETHOD(f545)(); + STDMETHOD(f546)(); + STDMETHOD(f547)(); + STDMETHOD(f548)(); + STDMETHOD(f549)(); + STDMETHOD(f550)(); + STDMETHOD(f551)(); + STDMETHOD(f552)(); + STDMETHOD(f553)(); + STDMETHOD(f554)(); + STDMETHOD(f555)(); + STDMETHOD(f556)(); + STDMETHOD(f557)(); + STDMETHOD(f558)(); + STDMETHOD(f559)(); + STDMETHOD(f560)(); + STDMETHOD(f561)(); + STDMETHOD(f562)(); + STDMETHOD(f563)(); + STDMETHOD(f564)(); + STDMETHOD(f565)(); + STDMETHOD(f566)(); + STDMETHOD(f567)(); + STDMETHOD(f568)(); + STDMETHOD(f569)(); + STDMETHOD(f570)(); + STDMETHOD(f571)(); + STDMETHOD(f572)(); + STDMETHOD(f573)(); + STDMETHOD(f574)(); + STDMETHOD(f575)(); + STDMETHOD(f576)(); + STDMETHOD(f577)(); + STDMETHOD(f578)(); + STDMETHOD(f579)(); + STDMETHOD(f580)(); + STDMETHOD(f581)(); + STDMETHOD(f582)(); + STDMETHOD(f583)(); + STDMETHOD(f584)(); + STDMETHOD(f585)(); + STDMETHOD(f586)(); + STDMETHOD(f587)(); + STDMETHOD(f588)(); + STDMETHOD(f589)(); + STDMETHOD(f590)(); + STDMETHOD(f591)(); + STDMETHOD(f592)(); + STDMETHOD(f593)(); + STDMETHOD(f594)(); + STDMETHOD(f595)(); + STDMETHOD(f596)(); + STDMETHOD(f597)(); + STDMETHOD(f598)(); + STDMETHOD(f599)(); + STDMETHOD(f600)(); + STDMETHOD(f601)(); + STDMETHOD(f602)(); + STDMETHOD(f603)(); + STDMETHOD(f604)(); + STDMETHOD(f605)(); + STDMETHOD(f606)(); + STDMETHOD(f607)(); + STDMETHOD(f608)(); + STDMETHOD(f609)(); + STDMETHOD(f610)(); + STDMETHOD(f611)(); + STDMETHOD(f612)(); + STDMETHOD(f613)(); + STDMETHOD(f614)(); + STDMETHOD(f615)(); + STDMETHOD(f616)(); + STDMETHOD(f617)(); + STDMETHOD(f618)(); + STDMETHOD(f619)(); + STDMETHOD(f620)(); + STDMETHOD(f621)(); + STDMETHOD(f622)(); + STDMETHOD(f623)(); + STDMETHOD(f624)(); + STDMETHOD(f625)(); + STDMETHOD(f626)(); + STDMETHOD(f627)(); + STDMETHOD(f628)(); + STDMETHOD(f629)(); + STDMETHOD(f630)(); + STDMETHOD(f631)(); + STDMETHOD(f632)(); + STDMETHOD(f633)(); + STDMETHOD(f634)(); + STDMETHOD(f635)(); + STDMETHOD(f636)(); + STDMETHOD(f637)(); + STDMETHOD(f638)(); + STDMETHOD(f639)(); + STDMETHOD(f640)(); + STDMETHOD(f641)(); + STDMETHOD(f642)(); + STDMETHOD(f643)(); + STDMETHOD(f644)(); + STDMETHOD(f645)(); + STDMETHOD(f646)(); + STDMETHOD(f647)(); + STDMETHOD(f648)(); + STDMETHOD(f649)(); + STDMETHOD(f650)(); + STDMETHOD(f651)(); + STDMETHOD(f652)(); + STDMETHOD(f653)(); + STDMETHOD(f654)(); + STDMETHOD(f655)(); + STDMETHOD(f656)(); + STDMETHOD(f657)(); + STDMETHOD(f658)(); + STDMETHOD(f659)(); + STDMETHOD(f660)(); + STDMETHOD(f661)(); + STDMETHOD(f662)(); + STDMETHOD(f663)(); + STDMETHOD(f664)(); + STDMETHOD(f665)(); + STDMETHOD(f666)(); + STDMETHOD(f667)(); + STDMETHOD(f668)(); + STDMETHOD(f669)(); + STDMETHOD(f670)(); + STDMETHOD(f671)(); + STDMETHOD(f672)(); + STDMETHOD(f673)(); + STDMETHOD(f674)(); + STDMETHOD(f675)(); + STDMETHOD(f676)(); + STDMETHOD(f677)(); + STDMETHOD(f678)(); + STDMETHOD(f679)(); + STDMETHOD(f680)(); + STDMETHOD(f681)(); + STDMETHOD(f682)(); + STDMETHOD(f683)(); + STDMETHOD(f684)(); + STDMETHOD(f685)(); + STDMETHOD(f686)(); + STDMETHOD(f687)(); + STDMETHOD(f688)(); + STDMETHOD(f689)(); + STDMETHOD(f690)(); + STDMETHOD(f691)(); + STDMETHOD(f692)(); + STDMETHOD(f693)(); + STDMETHOD(f694)(); + STDMETHOD(f695)(); + STDMETHOD(f696)(); + STDMETHOD(f697)(); + STDMETHOD(f698)(); + STDMETHOD(f699)(); + STDMETHOD(f700)(); + STDMETHOD(f701)(); + STDMETHOD(f702)(); + STDMETHOD(f703)(); + STDMETHOD(f704)(); + STDMETHOD(f705)(); + STDMETHOD(f706)(); + STDMETHOD(f707)(); + STDMETHOD(f708)(); + STDMETHOD(f709)(); + STDMETHOD(f710)(); + STDMETHOD(f711)(); + STDMETHOD(f712)(); + STDMETHOD(f713)(); + STDMETHOD(f714)(); + STDMETHOD(f715)(); + STDMETHOD(f716)(); + STDMETHOD(f717)(); + STDMETHOD(f718)(); + STDMETHOD(f719)(); + STDMETHOD(f720)(); + STDMETHOD(f721)(); + STDMETHOD(f722)(); + STDMETHOD(f723)(); + STDMETHOD(f724)(); + STDMETHOD(f725)(); + STDMETHOD(f726)(); + STDMETHOD(f727)(); + STDMETHOD(f728)(); + STDMETHOD(f729)(); + STDMETHOD(f730)(); + STDMETHOD(f731)(); + STDMETHOD(f732)(); + STDMETHOD(f733)(); + STDMETHOD(f734)(); + STDMETHOD(f735)(); + STDMETHOD(f736)(); + STDMETHOD(f737)(); + STDMETHOD(f738)(); + STDMETHOD(f739)(); + STDMETHOD(f740)(); + STDMETHOD(f741)(); + STDMETHOD(f742)(); + STDMETHOD(f743)(); + STDMETHOD(f744)(); + STDMETHOD(f745)(); + STDMETHOD(f746)(); + STDMETHOD(f747)(); + STDMETHOD(f748)(); + STDMETHOD(f749)(); + STDMETHOD(f750)(); + STDMETHOD(f751)(); + STDMETHOD(f752)(); + STDMETHOD(f753)(); + STDMETHOD(f754)(); + STDMETHOD(f755)(); + STDMETHOD(f756)(); + STDMETHOD(f757)(); + STDMETHOD(f758)(); + STDMETHOD(f759)(); + STDMETHOD(f760)(); + STDMETHOD(f761)(); + STDMETHOD(f762)(); + STDMETHOD(f763)(); + STDMETHOD(f764)(); + STDMETHOD(f765)(); + STDMETHOD(f766)(); + STDMETHOD(f767)(); + STDMETHOD(f768)(); + STDMETHOD(f769)(); + STDMETHOD(f770)(); + STDMETHOD(f771)(); + STDMETHOD(f772)(); + STDMETHOD(f773)(); + STDMETHOD(f774)(); + STDMETHOD(f775)(); + STDMETHOD(f776)(); + STDMETHOD(f777)(); + STDMETHOD(f778)(); + STDMETHOD(f779)(); + STDMETHOD(f780)(); + STDMETHOD(f781)(); + STDMETHOD(f782)(); + STDMETHOD(f783)(); + STDMETHOD(f784)(); + STDMETHOD(f785)(); + STDMETHOD(f786)(); + STDMETHOD(f787)(); + STDMETHOD(f788)(); + STDMETHOD(f789)(); + STDMETHOD(f790)(); + STDMETHOD(f791)(); + STDMETHOD(f792)(); + STDMETHOD(f793)(); + STDMETHOD(f794)(); + STDMETHOD(f795)(); + STDMETHOD(f796)(); + STDMETHOD(f797)(); + STDMETHOD(f798)(); + STDMETHOD(f799)(); + STDMETHOD(f800)(); + STDMETHOD(f801)(); + STDMETHOD(f802)(); + STDMETHOD(f803)(); + STDMETHOD(f804)(); + STDMETHOD(f805)(); + STDMETHOD(f806)(); + STDMETHOD(f807)(); + STDMETHOD(f808)(); + STDMETHOD(f809)(); + STDMETHOD(f810)(); + STDMETHOD(f811)(); + STDMETHOD(f812)(); + STDMETHOD(f813)(); + STDMETHOD(f814)(); + STDMETHOD(f815)(); + STDMETHOD(f816)(); + STDMETHOD(f817)(); + STDMETHOD(f818)(); + STDMETHOD(f819)(); + STDMETHOD(f820)(); + STDMETHOD(f821)(); + STDMETHOD(f822)(); + STDMETHOD(f823)(); + STDMETHOD(f824)(); + STDMETHOD(f825)(); + STDMETHOD(f826)(); + STDMETHOD(f827)(); + STDMETHOD(f828)(); + STDMETHOD(f829)(); + STDMETHOD(f830)(); + STDMETHOD(f831)(); + STDMETHOD(f832)(); + STDMETHOD(f833)(); + STDMETHOD(f834)(); + STDMETHOD(f835)(); + STDMETHOD(f836)(); + STDMETHOD(f837)(); + STDMETHOD(f838)(); + STDMETHOD(f839)(); + STDMETHOD(f840)(); + STDMETHOD(f841)(); + STDMETHOD(f842)(); + STDMETHOD(f843)(); + STDMETHOD(f844)(); + STDMETHOD(f845)(); + STDMETHOD(f846)(); + STDMETHOD(f847)(); + STDMETHOD(f848)(); + STDMETHOD(f849)(); + STDMETHOD(f850)(); + STDMETHOD(f851)(); + STDMETHOD(f852)(); + STDMETHOD(f853)(); + STDMETHOD(f854)(); + STDMETHOD(f855)(); + STDMETHOD(f856)(); + STDMETHOD(f857)(); + STDMETHOD(f858)(); + STDMETHOD(f859)(); + STDMETHOD(f860)(); + STDMETHOD(f861)(); + STDMETHOD(f862)(); + STDMETHOD(f863)(); + STDMETHOD(f864)(); + STDMETHOD(f865)(); + STDMETHOD(f866)(); + STDMETHOD(f867)(); + STDMETHOD(f868)(); + STDMETHOD(f869)(); + STDMETHOD(f870)(); + STDMETHOD(f871)(); + STDMETHOD(f872)(); + STDMETHOD(f873)(); + STDMETHOD(f874)(); + STDMETHOD(f875)(); + STDMETHOD(f876)(); + STDMETHOD(f877)(); + STDMETHOD(f878)(); + STDMETHOD(f879)(); + STDMETHOD(f880)(); + STDMETHOD(f881)(); + STDMETHOD(f882)(); + STDMETHOD(f883)(); + STDMETHOD(f884)(); + STDMETHOD(f885)(); + STDMETHOD(f886)(); + STDMETHOD(f887)(); + STDMETHOD(f888)(); + STDMETHOD(f889)(); + STDMETHOD(f890)(); + STDMETHOD(f891)(); + STDMETHOD(f892)(); + STDMETHOD(f893)(); + STDMETHOD(f894)(); + STDMETHOD(f895)(); + STDMETHOD(f896)(); + STDMETHOD(f897)(); + STDMETHOD(f898)(); + STDMETHOD(f899)(); + STDMETHOD(f900)(); + STDMETHOD(f901)(); + STDMETHOD(f902)(); + STDMETHOD(f903)(); + STDMETHOD(f904)(); + STDMETHOD(f905)(); + STDMETHOD(f906)(); + STDMETHOD(f907)(); + STDMETHOD(f908)(); + STDMETHOD(f909)(); + STDMETHOD(f910)(); + STDMETHOD(f911)(); + STDMETHOD(f912)(); + STDMETHOD(f913)(); + STDMETHOD(f914)(); + STDMETHOD(f915)(); + STDMETHOD(f916)(); + STDMETHOD(f917)(); + STDMETHOD(f918)(); + STDMETHOD(f919)(); + STDMETHOD(f920)(); + STDMETHOD(f921)(); + STDMETHOD(f922)(); + STDMETHOD(f923)(); + STDMETHOD(f924)(); + STDMETHOD(f925)(); + STDMETHOD(f926)(); + STDMETHOD(f927)(); + STDMETHOD(f928)(); + STDMETHOD(f929)(); + STDMETHOD(f930)(); + STDMETHOD(f931)(); + STDMETHOD(f932)(); + STDMETHOD(f933)(); + STDMETHOD(f934)(); + STDMETHOD(f935)(); + STDMETHOD(f936)(); + STDMETHOD(f937)(); + STDMETHOD(f938)(); + STDMETHOD(f939)(); + STDMETHOD(f940)(); + STDMETHOD(f941)(); + STDMETHOD(f942)(); + STDMETHOD(f943)(); + STDMETHOD(f944)(); + STDMETHOD(f945)(); + STDMETHOD(f946)(); + STDMETHOD(f947)(); + STDMETHOD(f948)(); + STDMETHOD(f949)(); + STDMETHOD(f950)(); + STDMETHOD(f951)(); + STDMETHOD(f952)(); + STDMETHOD(f953)(); + STDMETHOD(f954)(); + STDMETHOD(f955)(); + STDMETHOD(f956)(); + STDMETHOD(f957)(); + STDMETHOD(f958)(); + STDMETHOD(f959)(); + STDMETHOD(f960)(); + STDMETHOD(f961)(); + STDMETHOD(f962)(); + STDMETHOD(f963)(); + STDMETHOD(f964)(); + STDMETHOD(f965)(); + STDMETHOD(f966)(); + STDMETHOD(f967)(); + STDMETHOD(f968)(); + STDMETHOD(f969)(); + STDMETHOD(f970)(); + STDMETHOD(f971)(); + STDMETHOD(f972)(); + STDMETHOD(f973)(); + STDMETHOD(f974)(); + STDMETHOD(f975)(); + STDMETHOD(f976)(); + STDMETHOD(f977)(); + STDMETHOD(f978)(); + STDMETHOD(f979)(); + STDMETHOD(f980)(); + STDMETHOD(f981)(); + STDMETHOD(f982)(); + STDMETHOD(f983)(); + STDMETHOD(f984)(); + STDMETHOD(f985)(); + STDMETHOD(f986)(); + STDMETHOD(f987)(); + STDMETHOD(f988)(); + STDMETHOD(f989)(); + STDMETHOD(f990)(); + STDMETHOD(f991)(); + STDMETHOD(f992)(); + STDMETHOD(f993)(); + STDMETHOD(f994)(); + STDMETHOD(f995)(); + STDMETHOD(f996)(); + STDMETHOD(f997)(); + STDMETHOD(f998)(); + STDMETHOD(f999)(); + STDMETHOD(f1000)(); + STDMETHOD(f1001)(); + STDMETHOD(f1002)(); + STDMETHOD(f1003)(); + STDMETHOD(f1004)(); + STDMETHOD(f1005)(); + STDMETHOD(f1006)(); + STDMETHOD(f1007)(); + STDMETHOD(f1008)(); + STDMETHOD(f1009)(); + STDMETHOD(f1010)(); + STDMETHOD(f1011)(); + STDMETHOD(f1012)(); + STDMETHOD(f1013)(); + STDMETHOD(f1014)(); + STDMETHOD(f1015)(); + STDMETHOD(f1016)(); + STDMETHOD(f1017)(); + STDMETHOD(f1018)(); + STDMETHOD(f1019)(); + STDMETHOD(f1020)(); + STDMETHOD(f1021)(); + STDMETHOD(f1022)(); + STDMETHOD(f1023)(); + _QIThunk(IUnknown* pOrig, LPCTSTR p, const IID& i, UINT n, bool b) + { + m_lpszClassName = p; + m_iid = i; + m_nIndex = n; + m_dwRef = 0; + m_dwMaxRef = 0; + ATLENSURE(pOrig); + m_pUnk = pOrig; + m_bBreak = b; + m_bNonAddRefThunk = false; + } + IUnknown* m_pUnk; + long m_dwRef; + long m_dwMaxRef; + LPCTSTR m_lpszClassName; + IID m_iid; + UINT m_nIndex; + bool m_bBreak; + bool m_bNonAddRefThunk; + void Dump() throw(); +}; + +#endif + +///////////////////////////////////////////////////////////////////////////// +// Module Classes + + +#ifdef _ATL_STATIC_REGISTRY +#define UpdateRegistryFromResource UpdateRegistryFromResourceS +#else +#define UpdateRegistryFromResource UpdateRegistryFromResourceD +#endif // _ATL_STATIC_REGISTRY + + +class CAtlComModule : public _ATL_COM_MODULE +{ +public: + + CAtlComModule() throw() + { + cbSize = 0; + + m_hInstTypeLib = reinterpret_cast(&__ImageBase); + + m_ppAutoObjMapFirst = &__pobjMapEntryFirst + 1; + m_ppAutoObjMapLast = &__pobjMapEntryLast; + + if (FAILED(m_csObjMap.Init())) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to initialize critical section in CAtlComModule\n")); + ATLASSERT(0); + CAtlBaseModule::m_bInitFailed = true; + return; + } + // Set cbSize on success. + cbSize = sizeof(_ATL_COM_MODULE); + } + + ~CAtlComModule() + { + Term(); + } + + // Called from ~CAtlComModule or from ~CAtlExeModule. + void Term() + { + if (cbSize == 0) + return; + + for (_ATL_OBJMAP_ENTRY** ppEntry = m_ppAutoObjMapFirst; ppEntry < m_ppAutoObjMapLast; ppEntry++) + { + if (*ppEntry != NULL) + { + _ATL_OBJMAP_ENTRY* pEntry = *ppEntry; + if (pEntry->pCF != NULL) + pEntry->pCF->Release(); + pEntry->pCF = NULL; + } + } + m_csObjMap.Term(); + // Set to 0 to indicate that this function has been called + // At this point no one should be concerned about cbsize + // having the correct value + cbSize = 0; + } + + // Registry support (helpers) + HRESULT RegisterTypeLib() + { + return AtlRegisterTypeLib(m_hInstTypeLib, NULL); + } + HRESULT RegisterTypeLib(LPCTSTR lpszIndex) + { + USES_CONVERSION_EX; + LPCOLESTR pwszTemp = NULL; + if( lpszIndex != NULL ) + { + pwszTemp = T2COLE_EX(lpszIndex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if( pwszTemp == NULL ) + return E_OUTOFMEMORY; +#endif + } + return AtlRegisterTypeLib(m_hInstTypeLib, pwszTemp); + } + HRESULT UnRegisterTypeLib() + { + return AtlUnRegisterTypeLib(m_hInstTypeLib, NULL); + } + HRESULT UnRegisterTypeLib(LPCTSTR lpszIndex) + { + USES_CONVERSION_EX; + LPCOLESTR pwszTemp = NULL; + if( lpszIndex != NULL ) + { + pwszTemp = T2COLE_EX(lpszIndex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if( pwszTemp == NULL ) + return E_OUTOFMEMORY; +#endif + } + return AtlUnRegisterTypeLib(m_hInstTypeLib, pwszTemp); + } + + // RegisterServer walks the ATL Autogenerated object map and registers each object in the map + // If pCLSID is not NULL then only the object referred to by pCLSID is registered (The default case) + // otherwise all the objects are registered + HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL) + { + return AtlComModuleRegisterServer(this, bRegTypeLib, pCLSID); + } + + // UnregisterServer walks the ATL Autogenerated object map and unregisters each object in the map + // If pCLSID is not NULL then only the object referred to by pCLSID is unregistered (The default case) + // otherwise all the objects are unregistered. + HRESULT UnregisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL) + { + return AtlComModuleUnregisterServer(this, bRegTypeLib, pCLSID); + } + + // Implementation + + // Call ObjectMain for all the objects. + void ExecuteObjectMain(bool bStarting) + { + for (_ATL_OBJMAP_ENTRY** ppEntry = m_ppAutoObjMapFirst; ppEntry < m_ppAutoObjMapLast; ppEntry++) + { + if (*ppEntry != NULL) + (*ppEntry)->pfnObjectMain(bStarting); + } + } +}; + +extern CAtlComModule _AtlComModule; + +#ifdef _ATL_DEBUG_INTERFACES + +class CAtlDebugInterfacesModule +{ +public: + CAtlDebugInterfacesModule() throw() : + m_nIndexQI( 0 ), + m_nIndexBreakAt( 0 ) + { + if (FAILED(m_cs.Init())) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to initialize critical section in CAtlDebugInterfacesModule\n")); + ATLASSERT(0); + CAtlBaseModule::m_bInitFailed = true; + } + } + ~CAtlDebugInterfacesModule() throw() + { + // Release all class factories. + _AtlComModule.Term(); + DumpLeakedThunks(); + } + + HRESULT AddThunk(IUnknown** pp, LPCTSTR lpsz, REFIID iid) throw() + { + if ((pp == NULL) || (*pp == NULL)) + return E_POINTER; + IUnknown* p = *pp; + _QIThunk* pThunk = NULL; + CComCritSecLock lock(m_cs, false); + HRESULT hr = lock.Lock(); + if (FAILED(hr)) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in CAtlDebugInterfacesModule\n")); + ATLASSERT(0); + return hr; + } + + // Check if exists for identity + if (InlineIsEqualUnknown(iid)) + { + for (int i = 0; i < m_aThunks.GetSize(); i++) + { + if (m_aThunks[i]->m_pUnk == p && InlineIsEqualGUID(m_aThunks[i]->m_iid, iid)) + { + m_aThunks[i]->InternalAddRef(); + pThunk = m_aThunks[i]; + break; + } + } + } + if (pThunk == NULL) + { + ++m_nIndexQI; + if (m_nIndexBreakAt == m_nIndexQI) + DebugBreak(); + ATLTRY(pThunk = new _QIThunk(p, lpsz, iid, m_nIndexQI, (m_nIndexBreakAt == m_nIndexQI))); + if (pThunk == NULL) + { + return E_OUTOFMEMORY; + } + pThunk->InternalAddRef(); + m_aThunks.Add(pThunk); + } + *pp = (IUnknown*)pThunk; + return S_OK; + } + HRESULT AddNonAddRefThunk(IUnknown* p, LPCTSTR lpsz, IUnknown** ppThunkRet) throw() + { + if (ppThunkRet == NULL) + return E_POINTER; + *ppThunkRet = NULL; + + _QIThunk* pThunk = NULL; + CComCritSecLock lock(m_cs, false); + HRESULT hr = lock.Lock(); + if (FAILED(hr)) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in CAtlDebugInterfacesModule\n")); + ATLASSERT(0); + return hr; + } + + // Check if exists already for identity + for (int i = 0; i < m_aThunks.GetSize(); i++) + { + if (m_aThunks[i]->m_pUnk == p) + { + m_aThunks[i]->m_bNonAddRefThunk = true; + pThunk = m_aThunks[i]; + break; + } + } + if (pThunk == NULL) + { + ++m_nIndexQI; + if (m_nIndexBreakAt == m_nIndexQI) + DebugBreak(); + ATLTRY(pThunk = new _QIThunk(p, lpsz, __uuidof(IUnknown), m_nIndexQI, (m_nIndexBreakAt == m_nIndexQI))); + if (pThunk == NULL) + { + return E_OUTOFMEMORY; + } + pThunk->m_bNonAddRefThunk = true; + m_aThunks.Add(pThunk); + } + *ppThunkRet = (IUnknown*)pThunk; + return S_OK;; + } + void DeleteNonAddRefThunk(IUnknown* pUnk) throw() + { + CComCritSecLock lock(m_cs, false); + HRESULT hr = lock.Lock(); + if (FAILED(hr)) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in CAtlDebugInterfacesModule\n")); + ATLASSERT(0); + return; + } + + for (int i = 0; i < m_aThunks.GetSize(); i++) + { + if (m_aThunks[i]->m_bNonAddRefThunk && m_aThunks[i]->m_pUnk == pUnk) + { + delete m_aThunks[i]; + m_aThunks.RemoveAt(i); + break; + } + } + } + void DeleteThunk(_QIThunk* p) throw() + { + CComCritSecLock lock(m_cs, false); + HRESULT hr = lock.Lock(); + if (FAILED(hr)) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in CAtlDebugInterfacesModule\n")); + ATLASSERT(0); + return; + } + + int nIndex = m_aThunks.Find(p); + if (nIndex != -1) + { + m_aThunks[nIndex]->m_pUnk = NULL; + delete m_aThunks[nIndex]; + m_aThunks.RemoveAt(nIndex); + } + } + bool DumpLeakedThunks() + { + bool b = false; + for (int i = 0; i < m_aThunks.GetSize(); i++) + { + b = true; + m_aThunks[i]->Dump(); + delete m_aThunks[i]; + } + m_aThunks.RemoveAll(); + return b; + } + +public: + UINT m_nIndexQI; + UINT m_nIndexBreakAt; + CSimpleArray<_QIThunk*> m_aThunks; + CComAutoDeleteCriticalSection m_cs; +}; + +extern CAtlDebugInterfacesModule _AtlDebugInterfacesModule; + +#ifndef _ATL_STATIC_LIB_IMPL +// Should not be pulled into the static lib +__declspec (selectany) CAtlDebugInterfacesModule _AtlDebugInterfacesModule; +#endif + +inline ULONG _QIThunk::Release() +{ + ATLASSUME(m_pUnk != NULL); + if (m_bBreak) + DebugBreak(); + ATLASSUME(m_dwRef > 0); + + // save copies of member variables we wish to use after the InterlockedDecrement + UINT nIndex = m_nIndex; + IUnknown* pUnk = m_pUnk; + IID iid = m_iid; + LPCTSTR lpszClassName = m_lpszClassName; + bool bNonAddRefThunk = m_bNonAddRefThunk; + + ULONG l = InterlockedDecrement(&m_dwRef); + + TCHAR buf[512+1]; +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) + _stprintf_s(buf, _countof(buf), _T("QIThunk - %-10d\tRelease :\tObject = 0x%p\tRefcount = %d\t"), nIndex, pUnk, l); +#else +#pragma warning(push) +#pragma warning(disable:4995) // wsprintf is deprecated + wsprintf(buf, _T("QIThunk - %-10d\tRelease :\tObject = 0x%p\tRefcount = %d\t"), nIndex, pUnk, l); +#pragma warning(pop) +#endif + buf[_countof(buf)-1] = 0; + OutputDebugString(buf); + AtlDumpIID(iid, lpszClassName, S_OK); + + bool bDeleteThunk = (l == 0 && !bNonAddRefThunk); + pUnk->Release(); + if (bDeleteThunk) + _AtlDebugInterfacesModule.DeleteThunk(this); + return l; +} + +#endif // _ATL_DEBUG_INTERFACES + + +class CAtlWinModule : public _ATL_WIN_MODULE +{ +public: + CAtlWinModule() + { + cbSize = sizeof(_ATL_WIN_MODULE); + HRESULT hr = AtlWinModuleInit(this); + if (FAILED(hr)) + { + ATLASSERT(0); + CAtlBaseModule::m_bInitFailed = true; + cbSize = 0; + return; + } + } + + ~CAtlWinModule() + { + Term(); + } + + void Term() + { + AtlWinModuleTerm(this, _AtlBaseModule.GetModuleInstance()); + } + + void AddCreateWndData(_AtlCreateWndData* pData, void* pObject) + { + AtlWinModuleAddCreateWndData(this, pData, pObject); + } + + void* ExtractCreateWndData() + { + return AtlWinModuleExtractCreateWndData(this); + } +}; + +extern CAtlWinModule _AtlWinModule; + +class CAtlModule; +__declspec(selectany) CAtlModule* _pAtlModule = NULL; + +#if defined(_M_CEE) && !defined(_ATL_MIXED) + +// This small class takes care of releasing the class factories at managed +// shutdown when we are compiling /clr. We can't wait to call _AtlComModule.Term() +// in _AtlComModule destructor, since _AtlComModule is a native global object, and it +// will be destructed after the managed runtime has been shutdown. + +// Notice that if the user defines _ATL_MIXED, he/she will need to take care +// of releasing the eventual managed class factories at the right time. + +class CAtlReleaseManagedClassFactories +{ +public: + CAtlReleaseManagedClassFactories() { } + ~CAtlReleaseManagedClassFactories() + { + _AtlComModule.Term(); + } +}; + +__declspec (selectany) CAtlReleaseManagedClassFactories _AtlReleaseManagedClassFactories; + +extern "C" +{ +__declspec (selectany) void *_pAtlReleaseManagedClassFactories = &_AtlReleaseManagedClassFactories; +} +#if defined(_M_IX86) + #pragma comment(linker, "/include:__pAtlReleaseManagedClassFactories") +#else + #pragma comment(linker, "/include:_pAtlReleaseManagedClassFactories") +#endif + +#endif + +class ATL_NO_VTABLE CAtlModule : public _ATL_MODULE +{ +public : + static GUID m_libid; + IGlobalInterfaceTable* m_pGIT; + + CAtlModule() throw() + { + // Should have only one instance of a class + // derived from CAtlModule in a project. + ATLASSERT(_pAtlModule == NULL); + cbSize = 0; + m_pTermFuncs = NULL; + + m_nLockCnt = 0; + _pAtlModule = this; + m_pGIT = NULL; + + if (FAILED(m_csStaticDataInitAndTypeInfo.Init())) + { + ATLTRACE(atlTraceGeneral, 0, _T("ERROR : Unable to initialize critical section in CAtlModule\n")); + ATLASSERT(0); + CAtlBaseModule::m_bInitFailed = true; + return; + } + + // Set cbSize on success. + cbSize = sizeof(_ATL_MODULE); + } + + void Term() throw() + { + // cbSize == 0 indicates that Term has already been called + if (cbSize == 0) + return; + + // Call term functions + if (m_pTermFuncs != NULL) + { + AtlCallTermFunc(this); + m_pTermFuncs = NULL; + } + + if (m_pGIT != NULL) + m_pGIT->Release(); + + m_csStaticDataInitAndTypeInfo.Term(); + + cbSize = 0; + } + + virtual ~CAtlModule() throw() + { + Term(); + } + + virtual LONG Lock() throw() + { + return CComGlobalsThreadModel::Increment(&m_nLockCnt); + } + + virtual LONG Unlock() throw() + { + return CComGlobalsThreadModel::Decrement(&m_nLockCnt); + } + + virtual LONG GetLockCount() throw() + { + return m_nLockCnt; + } + + HRESULT AddTermFunc(_ATL_TERMFUNC* pFunc, DWORD_PTR dw) throw() + { + return AtlModuleAddTermFunc(this, pFunc, dw); + } + + virtual HRESULT GetGITPtr(IGlobalInterfaceTable** ppGIT) throw() + { + ATLASSERT(ppGIT != NULL); + + if (ppGIT == NULL) + return E_POINTER; + + HRESULT hr = S_OK; + if (m_pGIT == NULL) + { + hr = ::CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, + __uuidof(IGlobalInterfaceTable), (void**)&m_pGIT); + } + + if (SUCCEEDED(hr)) + { + ATLASSUME(m_pGIT != NULL); + *ppGIT = m_pGIT; + m_pGIT->AddRef(); + } + return hr; + } + + virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* /*pRegistrar*/) throw() = 0; + + // Resource-based Registration +#ifdef _ATL_STATIC_REGISTRY + // Statically linking to Registry Ponent + HRESULT WINAPI UpdateRegistryFromResourceS(LPCTSTR lpszRes, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw(); + HRESULT WINAPI UpdateRegistryFromResourceS(UINT nResID, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw(); +#else + HRESULT WINAPI UpdateRegistryFromResourceD(LPCTSTR lpszRes, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw() + { + if(lpszRes == NULL) + return E_INVALIDARG; + + USES_CONVERSION_EX; + LPCOLESTR pwszTemp = T2COLE_EX(lpszRes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifdef _UNICODE + if(pwszTemp == NULL) + return E_OUTOFMEMORY; +#endif + return UpdateRegistryFromResourceDHelper(pwszTemp, bRegister, pMapEntries); + } + HRESULT WINAPI UpdateRegistryFromResourceD(UINT nResID, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw() + { + return UpdateRegistryFromResourceDHelper((LPCOLESTR)MAKEINTRESOURCE(nResID), bRegister, pMapEntries); + } +#endif + + // Implementation +#if !defined(_ATL_STATIC_REGISTRY) + inline HRESULT WINAPI UpdateRegistryFromResourceDHelper(LPCOLESTR lpszRes, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw() + { + CComPtr spRegistrar; + HRESULT hr = AtlCreateRegistrar(&spRegistrar); + if (FAILED(hr)) + return hr; + + if (NULL != pMapEntries) + { + while (NULL != pMapEntries->szKey) + { + ATLASSERT(NULL != pMapEntries->szData); + spRegistrar->AddReplacement(pMapEntries->szKey, pMapEntries->szData); + pMapEntries++; + } + } + + hr = AddCommonRGSReplacements(spRegistrar); + if (FAILED(hr)) + return hr; + + return AtlUpdateRegistryFromResourceD(_AtlBaseModule.GetModuleInstance(), lpszRes, bRegister, + NULL, spRegistrar); + } +#endif + + static void EscapeSingleQuote(__out_ecount_z(destSizeInChars) LPOLESTR lpDest,__in size_t destSizeInChars, __in_z LPCOLESTR lp) throw() + { + if (destSizeInChars == 0) + { + return; + } + UINT i = 0; + // copy charecters to the destination buffer but leave the last char to be NULL. + for (i=0; i < destSizeInChars-1 && *lp; i++) + { + lpDest[i] = *lp; + // make sure we won't promote lpDest behind the buffer limit. + if (*lp == '\'' && i < destSizeInChars-2) + lpDest[++i] = *lp; + lp++; + } + lpDest[i] = NULL; + } + + ATL_DEPRECATED("CAtlModule::EscapeSingleQuote(dest, src) is unsafe. Instead, use CAtlModule::EscapeSingleQuote(dest, size, src)") + static void EscapeSingleQuote(__out_z LPOLESTR lpDest, __in_z LPCOLESTR lp) throw() + { + EscapeSingleQuote(lpDest, SIZE_MAX/sizeof(OLECHAR), lp); + } + + // search for an occurence of string p2 in string p1 + static LPCTSTR FindOneOf(LPCTSTR p1, LPCTSTR p2) throw() + { + while (p1 != NULL && *p1 != NULL) + { + LPCTSTR p = p2; + while (p != NULL && *p != NULL) + { + if (*p1 == *p) + return CharNext(p1); + p = CharNext(p); + } + p1 = CharNext(p1); + } + return NULL; + } +#pragma warning(push) +#pragma warning(disable : 4302) // 'type cast' : truncation from 'LPSTR' to 'TCHAR' + + static int WordCmpI(LPCTSTR psz1, LPCTSTR psz2) throw() + { + TCHAR c1 = (TCHAR)CharUpper((LPTSTR)*psz1); + TCHAR c2 = (TCHAR)CharUpper((LPTSTR)*psz2); + while (c1 != NULL && c1 == c2 && c1 != ' ' && c1 != '\t') + { + psz1 = CharNext(psz1); + psz2 = CharNext(psz2); + c1 = (TCHAR)CharUpper((LPTSTR)*psz1); + c2 = (TCHAR)CharUpper((LPTSTR)*psz2); + } + if ((c1 == NULL || c1 == ' ' || c1 == '\t') && (c2 == NULL || c2 == ' ' || c2 == '\t')) + return 0; + + return (c1 < c2) ? -1 : 1; + } + +#pragma warning (pop) +}; + +__declspec(selectany) GUID CAtlModule::m_libid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }; + +#define DECLARE_LIBID(libid) \ + static void InitLibId() throw() \ + { \ + ATL::CAtlModule::m_libid = libid; \ + } + +#define DECLARE_REGISTRY_APPID_RESOURCEID(resid, appid) \ + static LPCOLESTR GetAppId() throw() \ + { \ + return OLESTR(appid); \ + } \ + static TCHAR* GetAppIdT() throw() \ + { \ + return _T(appid); \ + } \ + static HRESULT WINAPI UpdateRegistryAppId(BOOL bRegister) throw() \ + { \ + ATL::_ATL_REGMAP_ENTRY aMapEntries [] = \ + { \ + { OLESTR("APPID"), GetAppId() }, \ + { NULL, NULL } \ + }; \ + return ATL::_pAtlModule->UpdateRegistryFromResource(resid, bRegister, aMapEntries); \ + } + +inline HRESULT AtlGetGITPtr(IGlobalInterfaceTable** ppGIT) throw() +{ + if (ppGIT == NULL) + return E_POINTER; + + if (_pAtlModule == NULL) + { + return CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, CLSCTX_INPROC_SERVER, + __uuidof(IGlobalInterfaceTable), (void**)ppGIT); + } + else + { + return _pAtlModule->GetGITPtr(ppGIT); + } +} + +template +class ATL_NO_VTABLE CAtlModuleT : public CAtlModule +{ +public : + CAtlModuleT() throw() + { + T::InitLibId(); + } + + static void InitLibId() throw() + { + } + + HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL) throw() + { + (pCLSID); + (bRegTypeLib); + + HRESULT hr = S_OK; + +#ifndef _ATL_NO_COM_SUPPORT + + hr = _AtlComModule.RegisterServer(bRegTypeLib, pCLSID); + +#endif // _ATL_NO_COM_SUPPORT + + +#ifndef _ATL_NO_PERF_SUPPORT + + if (SUCCEEDED(hr) && _pPerfRegFunc != NULL) + hr = (*_pPerfRegFunc)(_AtlBaseModule.m_hInst); + +#endif + + return hr; + } + + HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL) throw() + { + (bUnRegTypeLib); + (pCLSID); + + HRESULT hr = S_OK; + +#ifndef _ATL_NO_PERF_SUPPORT + + if (_pPerfUnRegFunc != NULL) + hr = (*_pPerfUnRegFunc)(); + +#endif + +#ifndef _ATL_NO_COM_SUPPORT + + if (SUCCEEDED(hr)) + hr = _AtlComModule.UnregisterServer(bUnRegTypeLib, pCLSID); + +#endif // _ATL_NO_COM_SUPPORT + + return hr; + + } + + static HRESULT WINAPI UpdateRegistryAppId(BOOL /*bRegister*/) throw() + { + return S_OK; + } + HRESULT RegisterAppId() throw() + { + return T::UpdateRegistryAppId(TRUE); + } + + HRESULT UnregisterAppId() throw() + { + return T::UpdateRegistryAppId(FALSE); + } + + virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* pRegistrar) throw() + { + return pRegistrar->AddReplacement(L"APPID", T::GetAppId()); + } + static LPCOLESTR GetAppId() throw() + { + return OLESTR(""); + } +}; + +#if !defined(_ATL_NATIVE_INITIALIZATION) +#pragma warning(push) +#pragma warning(disable:4483) +namespace __identifier("") +#pragma warning(pop) +{ + __declspec(selectany) bool DllModuleInitialized = false; +} + +#endif + +template +class ATL_NO_VTABLE CAtlDllModuleT : public CAtlModuleT +{ +public : + CAtlDllModuleT() throw() + { + _AtlComModule.ExecuteObjectMain(true); +#if !defined(_ATL_NATIVE_INITIALIZATION) +#pragma warning(push) +#pragma warning(disable:4483) + using namespace __identifier(""); +#pragma warning(pop) + ATLASSERT(DllModuleInitialized == false); + DllModuleInitialized = true; + _DllMain(DLL_PROCESS_ATTACH, NULL); +#endif + } + + ~CAtlDllModuleT() throw() + { +#if !defined(_ATL_NATIVE_INITIALIZATION) +#pragma warning(push) +#pragma warning(disable:4483) + using namespace __identifier(""); +#pragma warning(pop) + ATLASSERT(DllModuleInitialized == true); + _DllMain(DLL_PROCESS_DETACH, NULL); +#endif + _AtlComModule.ExecuteObjectMain(false); + } + + BOOL WINAPI DllMain(DWORD dwReason, LPVOID lpReserved) throw(); + + BOOL WINAPI _DllMain(DWORD dwReason, LPVOID /* lpReserved */) throw() + { + if (dwReason == DLL_PROCESS_ATTACH) + { + if (CAtlBaseModule::m_bInitFailed) + { + ATLASSERT(0); + return FALSE; + } + +#ifdef _ATL_MIN_CRT + DisableThreadLibraryCalls(_AtlBaseModule.GetModuleInstance()); +#endif + } +#ifdef _DEBUG + else if (dwReason == DLL_PROCESS_DETACH) + { + // Prevent false memory leak reporting. ~CAtlWinModule may be too late. + _AtlWinModule.Term(); + } +#endif // _DEBUG + return TRUE; // ok + } + + HRESULT DllCanUnloadNow() throw() + { + T* pT = static_cast(this); + return (pT->GetLockCount()==0) ? S_OK : S_FALSE; + } + + HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw() + { + T* pT = static_cast(this); + return pT->GetClassObject(rclsid, riid, ppv); + } + + HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE) throw() + { + LCID lcid = GetThreadLocale(); + SetThreadLocale(LOCALE_SYSTEM_DEFAULT); + // registers object, typelib and all interfaces in typelib + T* pT = static_cast(this); + HRESULT hr = pT->RegisterAppId(); + if (SUCCEEDED(hr)) + hr = pT->RegisterServer(bRegTypeLib); + SetThreadLocale(lcid); + return hr; + } + + HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE) throw() + { + LCID lcid = GetThreadLocale(); + SetThreadLocale(LOCALE_SYSTEM_DEFAULT); + T* pT = static_cast(this); + HRESULT hr = pT->UnregisterServer(bUnRegTypeLib); + if (SUCCEEDED(hr)) + hr = pT->UnregisterAppId(); + SetThreadLocale(lcid); + return hr; + } + + // Obtain a Class Factory + HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw() + { + +#ifndef _ATL_OLEDB_CONFORMANCE_TESTS + ATLASSERT(ppv != NULL); +#endif + + return AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv); + } +}; + + +#if (_MSC_VER >= 1400) +#pragma managed(push, off) +#else +#pragma unmanaged +#endif + +template +inline BOOL WINAPI CAtlDllModuleT::DllMain(DWORD dwReason, LPVOID lpReserved) throw() +{ +#if !defined(_ATL_NATIVE_INITIALIZATION) + dwReason; lpReserved; +#pragma warning(push) +#pragma warning(disable:4483) + using namespace __identifier(""); +#pragma warning(pop) + if (dwReason == DLL_PROCESS_ATTACH) + { + ATLASSERT(DllModuleInitialized == false); + } + return TRUE; +#else + return _DllMain(dwReason, lpReserved); +#endif +} + + +#if (_MSC_VER >= 1400) +#pragma managed(pop) +#else +#pragma managed +#endif + +#ifndef _AFX + + +template +class ATL_NO_VTABLE CAtlExeModuleT : public CAtlModuleT +{ +public : +#ifndef _ATL_NO_COM_SUPPORT + + DWORD m_dwMainThreadID; + HANDLE m_hEventShutdown; + DWORD m_dwTimeOut; + DWORD m_dwPause; + bool m_bDelayShutdown; + bool m_bActivity; + bool m_bComInitialized; // Flag that indicates if ATL initialized COM + +#endif // _ATL_NO_COM_SUPPORT + + CAtlExeModuleT() throw() + +#ifndef _ATL_NO_COM_SUPPORT + + : m_dwMainThreadID(::GetCurrentThreadId()), + m_dwTimeOut(5000), + m_dwPause(1000), + m_hEventShutdown(NULL), + m_bDelayShutdown(true), + m_bComInitialized(false) + +#endif // _ATL_NO_COM_SUPPORT + + { +#if !defined(_ATL_NO_COM_SUPPORT) + HRESULT hr = T::InitializeCom(); + if (FAILED(hr)) + { + // Ignore RPC_E_CHANGED_MODE if CLR is loaded. Error is due to CLR initializing + // COM and InitializeCOM trying to initialize COM with different flags. + if (hr != RPC_E_CHANGED_MODE || GetModuleHandle(_T("Mscoree.dll")) == NULL) + { + ATLASSERT(0); + CAtlBaseModule::m_bInitFailed = true; + return; + } + } + else + { + m_bComInitialized = true; + } + + + _AtlComModule.ExecuteObjectMain(true); + +#endif // !defined(_ATL_NO_COM_SUPPORT) + + } + + ~CAtlExeModuleT() throw() + { +#ifndef _ATL_NO_COM_SUPPORT + + _AtlComModule.ExecuteObjectMain(false); + +#endif + + // Call term functions before COM is uninitialized + Term(); + +#ifndef _ATL_NO_COM_SUPPORT + + // Clean up AtlComModule before COM is uninitialized + _AtlComModule.Term(); + + if (m_bComInitialized) + T::UninitializeCom(); +#endif // _ATL_NO_COM_SUPPORT + } + + static HRESULT InitializeCom() throw() + { + +#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) & defined(_ATL_FREE_THREADED) + return CoInitializeEx(NULL, COINIT_MULTITHREADED); +#else + return CoInitialize(NULL); +#endif + } + + static void UninitializeCom() throw() + { + CoUninitialize(); + } + + LONG Unlock() throw() + { + LONG lRet = CComGlobalsThreadModel::Decrement(&m_nLockCnt); + +#ifndef _ATL_NO_COM_SUPPORT + + if (lRet == 0) + { + if (m_bDelayShutdown) + { + m_bActivity = true; + ::SetEvent(m_hEventShutdown); // tell monitor that we transitioned to zero + } + else + { + ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0); + } + } + +#endif // _ATL_NO_COM_SUPPORT + + return lRet; + } +#ifndef _ATL_NO_COM_SUPPORT + + void MonitorShutdown() throw() + { + while (1) + { + ::WaitForSingleObject(m_hEventShutdown, INFINITE); + DWORD dwWait = 0; + do + { + m_bActivity = false; + dwWait = ::WaitForSingleObject(m_hEventShutdown, m_dwTimeOut); + } while (dwWait == WAIT_OBJECT_0); + // timed out + if (!m_bActivity && m_nLockCnt == 0) // if no activity let's really bail + { +#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) & defined(_ATL_FREE_THREADED) + ::CoSuspendClassObjects(); + if (m_nLockCnt == 0) +#endif + break; + } + } + ::CloseHandle(m_hEventShutdown); + ::PostThreadMessage(m_dwMainThreadID, WM_QUIT, 0, 0); + } + + HANDLE StartMonitor() throw() + { + m_hEventShutdown = ::CreateEvent(NULL, false, false, NULL); + if (m_hEventShutdown == NULL) + { + return NULL; + } + DWORD dwThreadID; + HANDLE hThread = ::CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID); + if(hThread==NULL) + { + ::CloseHandle(m_hEventShutdown); + } + return hThread; + } + + static DWORD WINAPI MonitorProc(void* pv) throw() + { + CAtlExeModuleT* p = static_cast*>(pv); + p->MonitorShutdown(); + return 0; + } +#endif // _ATL_NO_COM_SUPPORT + + int WinMain(int nShowCmd) throw() + { + if (CAtlBaseModule::m_bInitFailed) + { + ATLASSERT(0); + return -1; + } + T* pT = static_cast(this); + HRESULT hr = S_OK; + + LPTSTR lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT + if (pT->ParseCommandLine(lpCmdLine, &hr) == true) + hr = pT->Run(nShowCmd); + +#ifdef _DEBUG + // Prevent false memory leak reporting. ~CAtlWinModule may be too late. + _AtlWinModule.Term(); +#endif // _DEBUG + return hr; + } + + // Scan command line and perform registration + // Return value specifies if server should run + + // Parses the command line and registers/unregisters the rgs file if necessary + bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) throw() + { + *pnRetCode = S_OK; + + TCHAR szTokens[] = _T("-/"); + + T* pT = static_cast(this); + LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens); + while (lpszToken != NULL) + { + if (WordCmpI(lpszToken, _T("UnregServer"))==0) + { + *pnRetCode = pT->UnregisterServer(TRUE); + if (SUCCEEDED(*pnRetCode)) + *pnRetCode = pT->UnregisterAppId(); + return false; + } + + // Register as Local Server + if (WordCmpI(lpszToken, _T("RegServer"))==0) + { + *pnRetCode = pT->RegisterAppId(); + if (SUCCEEDED(*pnRetCode)) + *pnRetCode = pT->RegisterServer(TRUE); + return false; + } + + lpszToken = FindOneOf(lpszToken, szTokens); + } + + return true; + } + + HRESULT PreMessageLoop(int /*nShowCmd*/) throw() + { + HRESULT hr = S_OK; + T* pT = static_cast(this); + pT; + +#ifndef _ATL_NO_COM_SUPPORT + +#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) & defined(_ATL_FREE_THREADED) + + hr = pT->RegisterClassObjects(CLSCTX_LOCAL_SERVER, + REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED); + + if (FAILED(hr)) + return hr; + + if (hr == S_OK) + { + if (m_bDelayShutdown) + { + CHandle h(pT->StartMonitor()); + if (h.m_h == NULL) + { + hr = E_FAIL; + } + else + { + hr = CoResumeClassObjects(); + ATLASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) + { + ::SetEvent(m_hEventShutdown); // tell monitor to shutdown + ::WaitForSingleObject(h, m_dwTimeOut * 2); + } + } + } + else + { + hr = CoResumeClassObjects(); + ATLASSERT(SUCCEEDED(hr)); + } + + if (FAILED(hr)) + pT->RevokeClassObjects(); + } + else + { + m_bDelayShutdown = false; + } + +#else + + hr = pT->RegisterClassObjects(CLSCTX_LOCAL_SERVER, + REGCLS_MULTIPLEUSE); + if (hr == S_OK) + { + if (m_bDelayShutdown && !pT->StartMonitor()) + { + hr = E_FAIL; + } + } + else + { + m_bDelayShutdown = false; + } + + +#endif + +#endif // _ATL_NO_COM_SUPPORT + + ATLASSERT(SUCCEEDED(hr)); + return hr; + } + + HRESULT PostMessageLoop() throw() + { + HRESULT hr = S_OK; + +#ifndef _ATL_NO_COM_SUPPORT + + T* pT = static_cast(this); + hr = pT->RevokeClassObjects(); + if (m_bDelayShutdown) + Sleep(m_dwPause); //wait for any threads to finish + +#endif // _ATL_NO_COM_SUPPORT + + return hr; + } + + void RunMessageLoop() throw() + { + MSG msg; + while (GetMessage(&msg, 0, 0, 0) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + HRESULT Run(int nShowCmd = SW_HIDE) throw() + { + HRESULT hr = S_OK; + + T* pT = static_cast(this); + hr = pT->PreMessageLoop(nShowCmd); + + // Call RunMessageLoop only if PreMessageLoop returns S_OK. + if (hr == S_OK) + { + pT->RunMessageLoop(); + } + + // Call PostMessageLoop if PreMessageLoop returns success. + if (SUCCEEDED(hr)) + { + hr = pT->PostMessageLoop(); + } + + ATLASSERT(SUCCEEDED(hr)); + return hr; + } + + // Register/Revoke All Class Factories with the OS (EXE only) + HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) throw() + { + return AtlComModuleRegisterClassObjects(&_AtlComModule, dwClsContext, dwFlags); + } + HRESULT RevokeClassObjects() throw() + { + return AtlComModuleRevokeClassObjects(&_AtlComModule); + } +}; + +#ifndef _ATL_NO_SERVICE +template +class ATL_NO_VTABLE CAtlServiceModuleT : public CAtlExeModuleT +{ +public : + + CAtlServiceModuleT() throw() + { + m_bService = TRUE; + LoadString(_AtlBaseModule.GetModuleInstance(), nServiceNameID, m_szServiceName, sizeof(m_szServiceName) / sizeof(TCHAR)); + + // set up the initial service status + m_hServiceStatus = NULL; + m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + m_status.dwCurrentState = SERVICE_STOPPED; + m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + m_status.dwWin32ExitCode = 0; + m_status.dwServiceSpecificExitCode = 0; + m_status.dwCheckPoint = 0; + m_status.dwWaitHint = 0; + } + + int WinMain(int nShowCmd) throw() + { + if (CAtlBaseModule::m_bInitFailed) + { + ATLASSERT(0); + return -1; + } + + T* pT = static_cast(this); + HRESULT hr = S_OK; + + LPTSTR lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT + if (pT->ParseCommandLine(lpCmdLine, &hr) == true) + hr = pT->Start(nShowCmd); + +#ifdef _DEBUG + // Prevent false memory leak reporting. ~CAtlWinModule may be too late. + _AtlWinModule.Term(); +#endif // _DEBUG + return hr; + } + + HRESULT Start(int nShowCmd) throw() + { + T* pT = static_cast(this); + // Are we Service or Local Server + CRegKey keyAppID; + LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ); + if (lRes != ERROR_SUCCESS) + { + m_status.dwWin32ExitCode = lRes; + return m_status.dwWin32ExitCode; + } + + CRegKey key; + lRes = key.Open(keyAppID, pT->GetAppIdT(), KEY_READ); + if (lRes != ERROR_SUCCESS) + { + m_status.dwWin32ExitCode = lRes; + return m_status.dwWin32ExitCode; + } + + TCHAR szValue[MAX_PATH]; + DWORD dwLen = MAX_PATH; + lRes = key.QueryStringValue(_T("LocalService"), szValue, &dwLen); + + m_bService = FALSE; + if (lRes == ERROR_SUCCESS) + m_bService = TRUE; + + if (m_bService) + { + SERVICE_TABLE_ENTRY st[] = + { + { m_szServiceName, _ServiceMain }, + { NULL, NULL } + }; + if (::StartServiceCtrlDispatcher(st) == 0) + m_status.dwWin32ExitCode = GetLastError(); + return m_status.dwWin32ExitCode; + } + // local server - call Run() directly, rather than + // from ServiceMain() + m_status.dwWin32ExitCode = pT->Run(nShowCmd); + return m_status.dwWin32ExitCode; + } + + inline HRESULT RegisterAppId(bool bService = false) throw() + { + if (IsInstalled()) + return E_FAIL; + + HRESULT hr = T::UpdateRegistryAppId(TRUE); + if (FAILED(hr)) + return hr; + + CRegKey keyAppID; + LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE); + if (lRes != ERROR_SUCCESS) + return AtlHresultFromWin32(lRes); + + CRegKey key; + + lRes = key.Create(keyAppID, T::GetAppIdT()); + if (lRes != ERROR_SUCCESS) + return AtlHresultFromWin32(lRes); + + key.DeleteValue(_T("LocalService")); + + if (!bService) + return S_OK; + + key.SetStringValue(_T("LocalService"), m_szServiceName); + + // Create service + if (!Install()) + return E_FAIL; + return S_OK; + } + + HRESULT UnregisterAppId() throw() + { + if (!Uninstall()) + return E_FAIL; + // First remove entries not in the RGS file. + CRegKey keyAppID; + LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE); + if (lRes != ERROR_SUCCESS) + return AtlHresultFromWin32(lRes); + + CRegKey key; + lRes = key.Open(keyAppID, T::GetAppIdT(), KEY_WRITE); + if (lRes != ERROR_SUCCESS) + return AtlHresultFromWin32(lRes); + key.DeleteValue(_T("LocalService")); + + return T::UpdateRegistryAppId(FALSE); + } + + // Parses the command line and registers/unregisters the rgs file if necessary + bool ParseCommandLine(LPCTSTR lpCmdLine, HRESULT* pnRetCode) throw() + { + if (!CAtlExeModuleT::ParseCommandLine(lpCmdLine, pnRetCode)) + return false; + + TCHAR szTokens[] = _T("-/"); + *pnRetCode = S_OK; + + T* pT = static_cast(this); + LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens); + while (lpszToken != NULL) + { + if (WordCmpI(lpszToken, _T("Service"))==0) + { + *pnRetCode = pT->RegisterAppId(true); + if (SUCCEEDED(*pnRetCode)) + *pnRetCode = pT->RegisterServer(TRUE); + return false; + } + lpszToken = FindOneOf(lpszToken, szTokens); + } + return true; + } + + void ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) throw() + { + lpszArgv; + dwArgc; + // Register the control request handler + m_status.dwCurrentState = SERVICE_START_PENDING; + m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler); + if (m_hServiceStatus == NULL) + { + LogEvent(_T("Handler not installed")); + return; + } + SetServiceStatus(SERVICE_START_PENDING); + + m_status.dwWin32ExitCode = S_OK; + m_status.dwCheckPoint = 0; + m_status.dwWaitHint = 0; + + T* pT = static_cast(this); +#ifndef _ATL_NO_COM_SUPPORT + + HRESULT hr = E_FAIL; + hr = T::InitializeCom(); + if (FAILED(hr)) + { + // Ignore RPC_E_CHANGED_MODE if CLR is loaded. Error is due to CLR initializing + // COM and InitializeCOM trying to initialize COM with different flags. + if (hr != RPC_E_CHANGED_MODE || GetModuleHandle(_T("Mscoree.dll")) == NULL) + { + return; + } + } + else + { + m_bComInitialized = true; + } + + m_bDelayShutdown = false; +#endif //_ATL_NO_COM_SUPPORT + // When the Run function returns, the service has stopped. + m_status.dwWin32ExitCode = pT->Run(SW_HIDE); + +#ifndef _ATL_NO_COM_SUPPORT + if (m_bService && m_bComInitialized) + T::UninitializeCom(); +#endif + + SetServiceStatus(SERVICE_STOPPED); + LogEvent(_T("Service stopped")); + } + + HRESULT Run(int nShowCmd = SW_HIDE) throw() + { + HRESULT hr = S_OK; + T* pT = static_cast(this); + + hr = pT->PreMessageLoop(nShowCmd); + + if (hr == S_OK) + { + if (m_bService) + { + LogEvent(_T("Service started")); + SetServiceStatus(SERVICE_RUNNING); + } + + pT->RunMessageLoop(); + } + + if (SUCCEEDED(hr)) + { + hr = pT->PostMessageLoop(); + } + + return hr; + } + + HRESULT PreMessageLoop(int nShowCmd) throw() + { + HRESULT hr = S_OK; + if (m_bService) + { + m_dwThreadID = GetCurrentThreadId(); + + T* pT = static_cast(this); + hr = pT->InitializeSecurity(); + + if (FAILED(hr)) + return hr; + } + + hr = CAtlExeModuleT::PreMessageLoop(nShowCmd); + if (FAILED(hr)) + return hr; + + return hr; + } + + void OnStop() throw() + { + SetServiceStatus(SERVICE_STOP_PENDING); + PostThreadMessage(m_dwThreadID, WM_QUIT, 0, 0); + } + + void OnPause() throw() + { + } + + void OnContinue() throw() + { + } + + void OnInterrogate() throw() + { + } + + void OnShutdown() throw() + { + } + + void OnUnknownRequest(DWORD /*dwOpcode*/) throw() + { + LogEvent(_T("Bad service request")); + } + + void Handler(DWORD dwOpcode) throw() + { + T* pT = static_cast(this); + + switch (dwOpcode) + { + case SERVICE_CONTROL_STOP: + pT->OnStop(); + break; + case SERVICE_CONTROL_PAUSE: + pT->OnPause(); + break; + case SERVICE_CONTROL_CONTINUE: + pT->OnContinue(); + break; + case SERVICE_CONTROL_INTERROGATE: + pT->OnInterrogate(); + break; + case SERVICE_CONTROL_SHUTDOWN: + pT->OnShutdown(); + break; + default: + pT->OnUnknownRequest(dwOpcode); + } + } + + BOOL IsInstalled() throw() + { + BOOL bResult = FALSE; + + SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + + if (hSCM != NULL) + { + SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG); + if (hService != NULL) + { + bResult = TRUE; + ::CloseServiceHandle(hService); + } + ::CloseServiceHandle(hSCM); + } + return bResult; + } + BOOL Install() throw() + { + if (IsInstalled()) + return TRUE; + + // Get the executable file path + TCHAR szFilePath[MAX_PATH + _ATL_QUOTES_SPACE]; + DWORD dwFLen = ::GetModuleFileName(NULL, szFilePath + 1, MAX_PATH); + if( dwFLen == 0 || dwFLen == MAX_PATH ) + return FALSE; + + // Quote the FilePath before calling CreateService + szFilePath[0] = _T('\"'); + szFilePath[dwFLen + 1] = _T('\"'); + szFilePath[dwFLen + 2] = 0; + + SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hSCM == NULL) + { + TCHAR szBuf[1024]; + if (AtlLoadString(ATL_SERVICE_MANAGER_OPEN_ERROR, szBuf, 1024) == 0) +#ifdef UNICODE + Checked::wcscpy_s(szBuf, _countof(szBuf), _T("Could not open Service Manager")); +#else + Checked::strcpy_s(szBuf, _countof(szBuf), _T("Could not open Service Manager")); +#endif + MessageBox(NULL, szBuf, m_szServiceName, MB_OK); + return FALSE; + } + + SC_HANDLE hService = ::CreateService( + hSCM, m_szServiceName, m_szServiceName, + SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, + SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, + szFilePath, NULL, NULL, _T("RPCSS\0"), NULL, NULL); + + if (hService == NULL) + { + ::CloseServiceHandle(hSCM); + TCHAR szBuf[1024]; + if (AtlLoadString(ATL_SERVICE_START_ERROR, szBuf, 1024) == 0) +#ifdef UNICODE + Checked::wcscpy_s(szBuf, _countof(szBuf), _T("Could not start service")); +#else + Checked::strcpy_s(szBuf, _countof(szBuf), _T("Could not start service")); +#endif + MessageBox(NULL, szBuf, m_szServiceName, MB_OK); + return FALSE; + } + + ::CloseServiceHandle(hService); + ::CloseServiceHandle(hSCM); + return TRUE; + } + + BOOL Uninstall() throw() + { + if (!IsInstalled()) + return TRUE; + + SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + + if (hSCM == NULL) + { + TCHAR szBuf[1024]; + if (AtlLoadString(ATL_SERVICE_MANAGER_OPEN_ERROR, szBuf, 1024) == 0) +#ifdef UNICODE + Checked::wcscpy_s(szBuf, _countof(szBuf), _T("Could not open Service Manager")); +#else + Checked::strcpy_s(szBuf, _countof(szBuf), _T("Could not open Service Manager")); +#endif + MessageBox(NULL, szBuf, m_szServiceName, MB_OK); + return FALSE; + } + + SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_STOP | DELETE); + + if (hService == NULL) + { + ::CloseServiceHandle(hSCM); + TCHAR szBuf[1024]; + if (AtlLoadString(ATL_SERVICE_OPEN_ERROR, szBuf, 1024) == 0) +#ifdef UNICODE + Checked::wcscpy_s(szBuf, _countof(szBuf), _T("Could not open service")); +#else + Checked::strcpy_s(szBuf, _countof(szBuf), _T("Could not open service")); +#endif + MessageBox(NULL, szBuf, m_szServiceName, MB_OK); + return FALSE; + } + SERVICE_STATUS status; + BOOL bRet = ::ControlService(hService, SERVICE_CONTROL_STOP, &status); + if (!bRet) + { + DWORD dwError = GetLastError(); + if (!((dwError == ERROR_SERVICE_NOT_ACTIVE) || (dwError == ERROR_SERVICE_CANNOT_ACCEPT_CTRL && status.dwCurrentState == SERVICE_STOP_PENDING))) + { + TCHAR szBuf[1024]; + if (AtlLoadString(ATL_SERVICE_STOP_ERROR, szBuf, 1024) == 0) +#ifdef UNICODE + Checked::wcscpy_s(szBuf, _countof(szBuf), _T("Could not stop service")); +#else + Checked::strcpy_s(szBuf, _countof(szBuf), _T("Could not stop service")); +#endif + MessageBox(NULL, szBuf, m_szServiceName, MB_OK); + } + } + + + BOOL bDelete = ::DeleteService(hService); + ::CloseServiceHandle(hService); + ::CloseServiceHandle(hSCM); + + if (bDelete) + return TRUE; + + TCHAR szBuf[1024]; + if (AtlLoadString(ATL_SERVICE_DELETE_ERROR, szBuf, 1024) == 0) +#ifdef UNICODE + Checked::wcscpy_s(szBuf, _countof(szBuf), _T("Could not delete service")); +#else + Checked::strcpy_s(szBuf, _countof(szBuf), _T("Could not delete service")); +#endif + MessageBox(NULL, szBuf, m_szServiceName, MB_OK); + return FALSE; + } + + LONG Unlock() throw() + { + LONG lRet; + if (m_bService) + { + // We are running as a service, therefore transition to zero does not + // unload the process + lRet = CAtlModuleT::Unlock(); + } + else + { + // We are running as EXE, use MonitorShutdown logic provided by CExeModule + lRet = CAtlExeModuleT::Unlock(); + } + return lRet; + } + + void LogEventEx(int id, LPCTSTR pszMessage=NULL, WORD type = EVENTLOG_INFORMATION_TYPE) throw() + { + HANDLE hEventSource; + if (m_szServiceName) + { + /* Get a handle to use with ReportEvent(). */ + hEventSource = RegisterEventSource(NULL, m_szServiceName); + if (hEventSource != NULL) + { + /* Write to event log. */ + ReportEvent(hEventSource, + type, + (WORD)0, + id, + NULL, + (WORD)(pszMessage != NULL ? 1 : 0), + 0, + pszMessage != NULL ? &pszMessage : NULL, + NULL); + DeregisterEventSource(hEventSource); + } + } + } + +#pragma warning(push) +#pragma warning(disable : 4793) + void __cdecl LogEvent(LPCTSTR pszFormat, ...) throw() + { + const int LOG_EVENT_MSG_SIZE = 256; + + TCHAR chMsg[LOG_EVENT_MSG_SIZE]; + HANDLE hEventSource; + LPTSTR lpszStrings[1]; + va_list pArg; + + va_start(pArg, pszFormat); +#if _SECURE_ATL + _vsntprintf_s(chMsg, LOG_EVENT_MSG_SIZE, LOG_EVENT_MSG_SIZE-1, pszFormat, pArg); +#else + _vsntprintf(chMsg, LOG_EVENT_MSG_SIZE, pszFormat, pArg); +#endif + va_end(pArg); + + chMsg[LOG_EVENT_MSG_SIZE - 1] = 0; + + lpszStrings[0] = chMsg; + + if (!m_bService) + { + // Not running as a service, so print out the error message + // to the console if possible + _putts(chMsg); + } + + /* Get a handle to use with ReportEvent(). */ + hEventSource = RegisterEventSource(NULL, m_szServiceName); + if (hEventSource != NULL) + { + /* Write to event log. */ + ReportEvent(hEventSource, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (LPCTSTR*) &lpszStrings[0], NULL); + DeregisterEventSource(hEventSource); + } + } +#pragma warning(pop) + + void SetServiceStatus(DWORD dwState) throw() + { + m_status.dwCurrentState = dwState; + ::SetServiceStatus(m_hServiceStatus, &m_status); + } + +//Implementation +protected: + static void WINAPI _ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) throw() + { + ((T*)_pAtlModule)->ServiceMain(dwArgc, lpszArgv); + } + static void WINAPI _Handler(DWORD dwOpcode) throw() + { + ((T*)_pAtlModule)->Handler(dwOpcode); + } + +// data members +public: + TCHAR m_szServiceName[256]; + SERVICE_STATUS_HANDLE m_hServiceStatus; + SERVICE_STATUS m_status; + BOOL m_bService; + DWORD m_dwThreadID; +}; + +#endif // _ATL_NO_SERVICE + +#endif // !_AFX + +#ifdef _AFX + +class CAtlMfcModule : public ATL::CAtlModuleT +{ +public : + virtual LONG Lock() throw() + { +#ifdef _USRDLL + AFX_MANAGE_STATE(AfxGetStaticModuleState()); +#endif + AfxOleLockApp(); + return AfxGetModuleState()->m_nObjectCount; + } + + virtual LONG Unlock() throw() + { +#ifdef _USRDLL + AFX_MANAGE_STATE(AfxGetStaticModuleState()); +#endif + AfxOleUnlockApp(); + return AfxGetModuleState()->m_nObjectCount; + } + + virtual LONG GetLockCount() throw() + { +#ifdef _USRDLL + AFX_MANAGE_STATE(AfxGetStaticModuleState()); +#endif + return AfxGetModuleState()->m_nObjectCount; + } + + // Obtain a Class Factory (DLL only) + HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) + { + return ATL::AtlComModuleGetClassObject(&ATL::_AtlComModule, rclsid, riid, ppv); + } + + // Register/Revoke All Class Factories with the OS (EXE only) + HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) + { + return ATL::AtlComModuleRegisterClassObjects(&ATL::_AtlComModule, dwClsContext, dwFlags); + } + + HRESULT RevokeClassObjects() + { + return ATL::AtlComModuleRevokeClassObjects(&ATL::_AtlComModule); + } +}; + +#endif // _AFX + +///////////////////////////////////////////////////////////////////////////// +// CComModule - Uses the functionality provided by other modules + +#define THREADFLAGS_APARTMENT 0x1 +#define THREADFLAGS_BOTH 0x2 +#define AUTPRXFLAG 0x4 + +#ifndef _ATL_NO_COMMODULE + +class CComModule; + +#if !defined(_ATL_NATIVE_INITIALIZATION) + +#if (_MSC_VER >= 1400) +#pragma managed(push, off) +#else +#pragma unmanaged +#endif + +#pragma warning(push) +#pragma warning(disable:4483) +namespace __identifier("") +#pragma warning(pop) +{ + struct CComModuleHelper + { + CComModule* Module; + HINSTANCE Instance; + _ATL_OBJMAP_ENTRY* ObjectMap; + const GUID* LibraryId; + + // Must NOT have any constructors + // We initialize the object in DllMain *before* + // the constructors would run. + + void Initialize(CComModule* pModule, HINSTANCE hInstance, _ATL_OBJMAP_ENTRY* pObjMap, const GUID* pLibID) + { + Module = pModule; + Instance = hInstance; + ObjectMap = pObjMap; + LibraryId = pLibID; + } + }; + + __declspec(selectany) CComModuleHelper ComModuleHelper; + __declspec(selectany) bool ComModuleInitialized = false; +} + +#if (_MSC_VER >= 1400) +#pragma managed(pop) +#else +#pragma managed +#endif + +#endif + + +__declspec(selectany) CComModule* _pModule = NULL; +class CComModule : public CAtlModuleT +{ +public : + + CComModule() + { + // Should have only one instance of a class + // derived from CComModule in a project. + ATLASSERT(_pModule == NULL); + _pModule = this; +#if !defined(_ATL_NATIVE_INITIALIZATION) +#pragma warning(push) +#pragma warning(disable:4483) + using namespace __identifier(""); +#pragma warning(pop) + ATLASSERT(ComModuleInitialized == false); + // If ComModuleHelper.Module == NULL it mean that DllMain has not been called, so we assume CComModule lives in + // an exe and not in a dll + if (ComModuleHelper.Module != NULL) + { + ATLASSERT(ComModuleHelper.Module == this); + _DllMain(ComModuleHelper.Instance, DLL_PROCESS_ATTACH, NULL, ComModuleHelper.ObjectMap, ComModuleHelper.LibraryId); + } + ComModuleInitialized = true; +#endif + } + + ~CComModule() + { +#if !defined(_ATL_NATIVE_INITIALIZATION) +#pragma warning(push) +#pragma warning(disable:4483) + using namespace __identifier(""); +#pragma warning(pop) + ATLASSERT(ComModuleInitialized == true); + // If ComModuleHelper.Module == NULL it mean that DllMain has not been called, so we assume CComModule lives in + // an exe and not in a dll + if (ComModuleHelper.Module != NULL) + { + ATLASSERT(ComModuleHelper.Module == this); + _DllMain(ComModuleHelper.Instance, DLL_PROCESS_DETACH, NULL, ComModuleHelper.ObjectMap, ComModuleHelper.LibraryId); + } +#endif + } + + __declspec(property(get = get_m_hInst)) HINSTANCE m_hInst; + HINSTANCE& get_m_hInst() const throw() + { + return _AtlBaseModule.m_hInst; + } + + __declspec(property(get = get_m_hInstResource, put = put_m_hInstResource)) HINSTANCE m_hInstResource; + HINSTANCE& get_m_hInstResource() const throw() + { + return _AtlBaseModule.m_hInstResource; + } + void put_m_hInstResource(HINSTANCE h) throw() + { + _AtlBaseModule.SetResourceInstance(h); + } + HINSTANCE SetResourceInstance(HINSTANCE h) throw() + { + return _AtlBaseModule.SetResourceInstance(h); + } + + HINSTANCE GetModuleInstance() throw() + { + return _AtlBaseModule.m_hInst; + } + HINSTANCE GetResourceInstance() throw() + { + return _AtlBaseModule.m_hInstResource; + } + + __declspec(property(get = get_m_hInstTypeLib, put = put_m_hInstTypeLib)) HINSTANCE m_hInstTypeLib; + HINSTANCE& get_m_hInstTypeLib() const throw() + { + return _AtlComModule.m_hInstTypeLib; + } + void put_m_hInstTypeLib(HINSTANCE h) throw() + { + _AtlComModule.m_hInstTypeLib = h; + } + + HINSTANCE GetTypeLibInstance() const throw() + { + return _AtlComModule.m_hInstTypeLib; + } + + // For Backward compatibility + _ATL_OBJMAP_ENTRY* m_pObjMap; + + __declspec(property(get = get_m_csWindowCreate)) CRITICAL_SECTION m_csWindowCreate; + CRITICAL_SECTION& get_m_csWindowCreate() throw(); + + __declspec(property(get = get_m_csObjMap)) CRITICAL_SECTION m_csObjMap; + CRITICAL_SECTION& get_m_csObjMap() throw(); + + __declspec(property(get = get_m_csStaticDataInit)) CRITICAL_SECTION m_csTypeInfoHolder; + __declspec(property(get = get_m_csStaticDataInit)) CRITICAL_SECTION m_csStaticDataInit; + CRITICAL_SECTION& get_m_csStaticDataInit() throw(); + void EnterStaticDataCriticalSection() throw() + { + EnterCriticalSection(&m_csStaticDataInit); + } + + void LeaveStaticDataCriticalSection() throw() + { + LeaveCriticalSection(&m_csStaticDataInit); + } + + __declspec(property(get = get_dwAtlBuildVer)) DWORD dwAtlBuildVer; + DWORD& get_dwAtlBuildVer() throw() + { + return _AtlBaseModule.dwAtlBuildVer; + } + + __declspec(property(get = get_m_pCreateWndList, put = put_m_pCreateWndList)) _AtlCreateWndData* m_pCreateWndList; + _AtlCreateWndData*& get_m_pCreateWndList() throw(); + void put_m_pCreateWndList(_AtlCreateWndData* p) throw(); + + __declspec(property(get = get_pguidVer)) const GUID* pguidVer; + const GUID*& get_pguidVer() throw() + { + return _AtlBaseModule.pguidVer; + } + +#ifdef _ATL_DEBUG_INTERFACES + + __declspec(property(get = get_m_nIndexQI, put = put_m_nIndexQI)) UINT m_nIndexQI; + UINT& get_m_nIndexQI() throw(); + void put_m_nIndexQI(UINT nIndex) throw(); + + __declspec(property(get = get_m_nIndexBreakAt, put = put_m_nIndexBreakAt)) UINT m_nIndexBreakAt; + UINT& get_m_nIndexBreakAt() throw(); + void put_m_nIndexBreakAt(UINT nIndex) throw(); + + __declspec(property(get = get_m_paThunks)) CSimpleArray<_QIThunk*>* m_paThunks; + CSimpleArray<_QIThunk*>* get_m_paThunks() throw(); + HRESULT AddThunk(IUnknown** pp, LPCTSTR lpsz, REFIID iid) throw(); + + HRESULT AddNonAddRefThunk(IUnknown* p, LPCTSTR lpsz, IUnknown** ppThunkRet) throw(); + void DeleteNonAddRefThunk(IUnknown* pUnk) throw(); + void DeleteThunk(_QIThunk* p) throw(); + bool DumpLeakedThunks() throw(); +#endif // _ATL_DEBUG_INTERFACES + + HRESULT Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid = NULL) throw(); + void Term() throw(); + + HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw(); + // Register/Revoke All Class Factories with the OS (EXE only) + HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) throw(); + HRESULT RevokeClassObjects() throw(); + // Registry support (helpers) + HRESULT RegisterTypeLib() throw(); + HRESULT RegisterTypeLib(LPCTSTR lpszIndex) throw(); + HRESULT UnRegisterTypeLib() throw(); + HRESULT UnRegisterTypeLib(LPCTSTR lpszIndex) throw(); + HRESULT RegisterServer(BOOL bRegTypeLib = FALSE, const CLSID* pCLSID = NULL) throw(); + HRESULT UnregisterServer(BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL) throw(); + HRESULT UnregisterServer(const CLSID* pCLSID = NULL) throw(); + + void AddCreateWndData(_AtlCreateWndData* pData, void* pObject) throw() + { + _AtlWinModule.AddCreateWndData(pData, pObject); + } + + void* ExtractCreateWndData() throw() + { + return _AtlWinModule.ExtractCreateWndData(); + } + + // Only used in CComAutoThreadModule + HRESULT CreateInstance(void* /*pfnCreateInstance*/, REFIID /*riid*/, void** /*ppvObj*/) throw() + { + ATLASSERT(0); + ATLTRACENOTIMPL(_T("CComModule::CreateInstance")); + } + + HRESULT RegisterAppId(LPCTSTR pAppId); + HRESULT UnregisterAppId(LPCTSTR pAppId); + + // Resource-based Registration + virtual HRESULT WINAPI UpdateRegistryFromResourceD(LPCTSTR lpszRes, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw() + { +#if defined(_ATL_STATIC_REGISTRY) + (lpszRes); + (bRegister); + (pMapEntries); + return E_FAIL; +#else + return CAtlModuleT::UpdateRegistryFromResourceD(lpszRes, bRegister, pMapEntries); +#endif + } + virtual HRESULT WINAPI UpdateRegistryFromResourceD(UINT nResID, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw() + { +#if defined(_ATL_STATIC_REGISTRY) + (nResID); + (bRegister); + (pMapEntries); + return E_FAIL; +#else + return CAtlModuleT::UpdateRegistryFromResourceD(nResID, bRegister, pMapEntries); +#endif + } + + + // Statically linking to Registry Ponent + virtual HRESULT WINAPI UpdateRegistryFromResourceS(LPCTSTR lpszRes, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw() + { +#ifdef _ATL_STATIC_REGISTRY + return CAtlModuleT::UpdateRegistryFromResourceS(lpszRes, bRegister, pMapEntries); +#else + (lpszRes); + (bRegister); + (pMapEntries); + return E_FAIL; +#endif + } + virtual HRESULT WINAPI UpdateRegistryFromResourceS(UINT nResID, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries = NULL) throw() + { +#ifdef _ATL_STATIC_REGISTRY + return CAtlModuleT::UpdateRegistryFromResourceS(nResID, bRegister, pMapEntries); +#else + (nResID); + (bRegister); + (pMapEntries); + return E_FAIL; +#endif + } + + + // Use RGS file for registration + + ATL_DEPRECATED("CComModule::RegisterProgID is no longer recommended. Instead, use an RGS file for registration.") + static HRESULT RegisterProgID(LPCTSTR lpszCLSID, LPCTSTR lpszProgID, LPCTSTR lpszUserDesc); + // Standard Registration + ATL_DEPRECATED("CComModule::UpdateRegistryClass is no longer recommended. Instead, use an RGS file for registration.") + HRESULT WINAPI UpdateRegistryClass(const CLSID& clsid, LPCTSTR lpszProgID, LPCTSTR lpszVerIndProgID, UINT nDescID, DWORD dwFlags, BOOL bRegister); + ATL_DEPRECATED("CComModule::UpdateRegistryClass is no longer recommended. Instead, use an RGS file for registration.") + HRESULT WINAPI UpdateRegistryClass(const CLSID& clsid, LPCTSTR lpszProgID, LPCTSTR lpszVerIndProgID, LPCTSTR szDesc, DWORD dwFlags, BOOL bRegister); + ATL_DEPRECATED("CComModule::RegisterClassHelper is no longer recommended. Instead, use an RGS file for registration.") + HRESULT WINAPI RegisterClassHelper(const CLSID& clsid, LPCTSTR lpszProgID, LPCTSTR lpszVerIndProgID, LPCTSTR szDesc, DWORD dwFlags); + ATL_DEPRECATED("CComModule::UnregisterClassHelper is no longer recommended. Instead, use an RGS file for registration.") + HRESULT WINAPI UnregisterClassHelper(const CLSID& clsid, LPCTSTR lpszProgID, LPCTSTR lpszVerIndProgID); + + BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */, _ATL_OBJMAP_ENTRY* pObjMap, const GUID* pLibID); + + BOOL WINAPI _DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */, _ATL_OBJMAP_ENTRY* pObjMap, const GUID* pLibID) + { + if (dwReason == DLL_PROCESS_ATTACH) + { + if (CAtlBaseModule::m_bInitFailed) + { + ATLASSERT(0); + return FALSE; + } + + if (FAILED(Init(pObjMap, hInstance, pLibID))) + { + Term(); + return FALSE; + } +#ifdef _ATL_MIN_CRT + DisableThreadLibraryCalls(hInstance); +#endif + } + else if (dwReason == DLL_PROCESS_DETACH) + Term(); + return TRUE; // ok + } + + HRESULT DllCanUnloadNow() throw() + { + return (GetLockCount()==0) ? S_OK : S_FALSE; + } + HRESULT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw() + { + return GetClassObject(rclsid, riid, ppv); + } + + HRESULT DllRegisterServer(BOOL bRegTypeLib = TRUE) throw() + { + // registers object, typelib and all interfaces in typelib + return RegisterServer(bRegTypeLib); + } + + HRESULT DllUnregisterServer(BOOL bUnRegTypeLib = TRUE) throw() + { + return UnregisterServer(bUnRegTypeLib); + } + +}; + + +#if (_MSC_VER >= 1400) +#pragma managed(push, off) +#else +#pragma unmanaged +#endif + +inline BOOL WINAPI CComModule::DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved, _ATL_OBJMAP_ENTRY* pObjMap, const GUID* pLibID) +{ +#if !defined(_ATL_NATIVE_INITIALIZATION) +#pragma warning(push) +#pragma warning(disable:4483) + using namespace __identifier(""); +#pragma warning(pop) + lpReserved; + if (dwReason == DLL_PROCESS_ATTACH) + { + ATLASSERT(ComModuleInitialized == false); + ComModuleHelper.Initialize(this, hInstance, pObjMap, pLibID); + } + return TRUE; +#else + return _DllMain(hInstance, dwReason, lpReserved, pObjMap, pLibID); +#endif +} + + +#if (_MSC_VER >= 1400) +#pragma managed(pop) +#else +#pragma managed +#endif + +#endif // !_ATL_NO_COMMODULE + +///////////////////////////////////////////////////////////////////////////// +// Thread creation helpers + +#if !defined(_ATL_MIN_CRT) && defined(_MT) +// CRTThreadTraits +// This class is for use with CThreadPool or CWorkerThread +// It should be used if the worker class will use CRT +// functions. +class CRTThreadTraits +{ +public: + static HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpsa, DWORD dwStackSize, LPTHREAD_START_ROUTINE pfnThreadProc, void *pvParam, DWORD dwCreationFlags, DWORD *pdwThreadId) throw() + { + ATLASSERT(sizeof(DWORD) == sizeof(unsigned int)); // sanity check for pdwThreadId + + // _beginthreadex calls CreateThread which will set the last error value before it returns. + return (HANDLE) _beginthreadex(lpsa, dwStackSize, (unsigned int (__stdcall *)(void *)) pfnThreadProc, pvParam, dwCreationFlags, (unsigned int *) pdwThreadId); + } +}; + +#endif + +// Win32ThreadTraits +// This class is for use with CThreadPool or CWorkerThread +// It should be used if the worker class will not use CRT +// functions. +class Win32ThreadTraits +{ +public: + static HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpsa, DWORD dwStackSize, LPTHREAD_START_ROUTINE pfnThreadProc, void *pvParam, DWORD dwCreationFlags, DWORD *pdwThreadId) throw() + { + return ::CreateThread(lpsa, dwStackSize, pfnThreadProc, pvParam, dwCreationFlags, pdwThreadId); + } +}; + +#if !defined(_ATL_MIN_CRT) && defined(_MT) + typedef CRTThreadTraits DefaultThreadTraits; +#else + typedef Win32ThreadTraits DefaultThreadTraits; +#endif + +template +HANDLE CreateThreadT(LPSECURITY_ATTRIBUTES lpsa, DWORD dwStackSize, DWORD (WINAPI * pfn)(T *pparam), + T *pparam, DWORD dwCreationFlags, LPDWORD pdw) +{ + return DefaultThreadTraits::CreateThread(lpsa, + dwStackSize, + (LPTHREAD_START_ROUTINE)pfn, + pparam, + dwCreationFlags, + pdw); +} + +template +HANDLE AtlCreateThread(DWORD (WINAPI* pfn)(T *pparam), T *pparam) +{ + return CreateThreadT(0, 0, pfn, pparam, 0, 0); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// Thread Pooling classes + +class _AtlAptCreateObjData +{ +public: + _ATL_CREATORFUNC* pfnCreateInstance; + const IID* piid; + HANDLE hEvent; + LPSTREAM pStream; + HRESULT hRes; +}; + +class CComApartment +{ +public: + CComApartment() + { + m_nLockCnt = 0; + m_hThread = NULL; + } + static UINT ATL_CREATE_OBJECT; + static DWORD WINAPI _Apartment(__in void* pv) + { + ATLENSURE(pv != NULL); + return ((CComApartment*)pv)->Apartment(); + } + DWORD Apartment() + { + CoInitialize(NULL); + MSG msg; + while(GetMessage(&msg, 0, 0, 0) > 0) + { + if (msg.message == ATL_CREATE_OBJECT) + { + _AtlAptCreateObjData* pdata = (_AtlAptCreateObjData*)msg.lParam; + IUnknown* pUnk = NULL; + pdata->hRes = pdata->pfnCreateInstance(NULL, __uuidof(IUnknown), (void**)&pUnk); + if (SUCCEEDED(pdata->hRes)) + pdata->hRes = CoMarshalInterThreadInterfaceInStream(*pdata->piid, pUnk, &pdata->pStream); + if (SUCCEEDED(pdata->hRes)) + { + pUnk->Release(); + ATLTRACE(atlTraceCOM, 2, _T("Object created on thread = %d\n"), GetCurrentThreadId()); + } +#ifdef _DEBUG + else + { + ATLTRACE(atlTraceCOM, 2, _T("Failed to create Object on thread = %d\n"), GetCurrentThreadId()); + } +#endif + SetEvent(pdata->hEvent); + } + DispatchMessage(&msg); + } + CoUninitialize(); + + return 0; + } + LONG Lock() {return CComGlobalsThreadModel::Increment(&m_nLockCnt);} + LONG Unlock(){return CComGlobalsThreadModel::Decrement(&m_nLockCnt); + } + LONG GetLockCount() {return m_nLockCnt;} + + DWORD m_dwThreadID; + HANDLE m_hThread; + LONG m_nLockCnt; +}; + +__declspec(selectany) UINT CComApartment::ATL_CREATE_OBJECT = 0; + +class CComSimpleThreadAllocator +{ +public: + CComSimpleThreadAllocator() + { + m_nThread = 0; + } + int GetThread(CComApartment* /*pApt*/, int nThreads) + { + if (++m_nThread == nThreads) + m_nThread = 0; + return m_nThread; + } + int m_nThread; +}; + +__interface IAtlAutoThreadModule +{ + virtual HRESULT CreateInstance(void* pfnCreateInstance, REFIID riid, void** ppvObj); +}; + +__declspec(selectany) IAtlAutoThreadModule* _pAtlAutoThreadModule; + +template +class ATL_NO_VTABLE CAtlAutoThreadModuleT : public IAtlAutoThreadModule +{ +// This class is not for use in a DLL. +// If this class were used in a DLL, there will be a deadlock when the DLL is unloaded. +// because of dwWait's default value of INFINITE +public: + CAtlAutoThreadModuleT(int nThreads = T::GetDefaultThreads()) + { + ATLASSERT(_pAtlAutoThreadModule == NULL); + _pAtlAutoThreadModule = this; + m_pApartments = NULL; + m_nThreads= 0; + + ATLTRY(m_pApartments = new CComApartment[nThreads]); + ATLASSERT(m_pApartments != NULL); + if(m_pApartments == NULL) + { + CAtlBaseModule::m_bInitFailed = true; + ATLENSURE(0); + } + + memset(m_pApartments, 0, sizeof(CComApartment) * nThreads); + + m_nThreads = nThreads; + for (int i = 0; i < nThreads; i++) + { + +#if !defined(_ATL_MIN_CRT) && defined(_MT) + typedef unsigned ( __stdcall *pfnThread )( void * ); + m_pApartments[i].m_hThread = (HANDLE)_beginthreadex(NULL, 0, (pfnThread)CComApartment::_Apartment, &m_pApartments[i], 0, (UINT*)&m_pApartments[i].m_dwThreadID); + if (m_pApartments[i].m_hThread == NULL) + { + HRESULT hr = E_FAIL; + switch (Checked::get_errno()) + { + case EAGAIN: + hr = HRESULT_FROM_WIN32(ERROR_TOO_MANY_TCBS); + break; + case EINVAL: + hr = E_INVALIDARG; + break; + } + ATLASSERT(0); + CAtlBaseModule::m_bInitFailed = true; + break; + } + +#else + m_pApartments[i].m_hThread = ::CreateThread(NULL, 0, CComApartment::_Apartment, (void*)&m_pApartments[i], 0, &m_pApartments[i].m_dwThreadID); + // clean up allocated threads + if (m_pApartments[i].m_hThread == NULL) + { + ATLASSERT(0); + CAtlBaseModule::m_bInitFailed = true; + break; + } + +#endif + + } + if (!CAtlBaseModule::m_bInitFailed) + CComApartment::ATL_CREATE_OBJECT = RegisterWindowMessage(_T("ATL_CREATE_OBJECT")); + } + + virtual ~CAtlAutoThreadModuleT() + { + if (m_pApartments == NULL) + return; + + DWORD dwCurrentThreadId = GetCurrentThreadId(); + int nCurrentThread = -1; + for (int i=0; i < m_nThreads; i++) + { + if (m_pApartments[i].m_hThread == NULL) + continue; + if (m_pApartments[i].m_dwThreadID == dwCurrentThreadId) + { + nCurrentThread = i; + continue; + } + while (::PostThreadMessage(m_pApartments[i].m_dwThreadID, WM_QUIT, 0, 0) == 0) + { + if (GetLastError() == ERROR_INVALID_THREAD_ID) + { + ATLASSERT(FALSE); + break; + } + ::Sleep(100); + } + ::WaitForSingleObject(m_pApartments[i].m_hThread, dwWait); + CloseHandle(m_pApartments[i].m_hThread); + } + if (nCurrentThread != -1) + CloseHandle(m_pApartments[nCurrentThread].m_hThread); + + delete [] m_pApartments; + m_pApartments = NULL; + } + + HRESULT CreateInstance(void* pfnCreateInstance, REFIID riid, void** ppvObj) + { + ATLASSERT(ppvObj != NULL); + if (ppvObj == NULL) + return E_POINTER; + *ppvObj = NULL; + + _ATL_CREATORFUNC* pFunc = (_ATL_CREATORFUNC*) pfnCreateInstance; + _AtlAptCreateObjData data; + data.pfnCreateInstance = pFunc; + data.piid = &riid; + data.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + data.hRes = S_OK; + int nThread = m_Allocator.GetThread(m_pApartments, m_nThreads); + int nIterations = 0; + while(::PostThreadMessage(m_pApartments[nThread].m_dwThreadID, CComApartment::ATL_CREATE_OBJECT, 0, (LPARAM)&data) == 0 && ++nIterations < 100) + { + Sleep(100); + } + if (nIterations < 100) + { + AtlWaitWithMessageLoop(data.hEvent); + } + else + { + data.hRes = AtlHresultFromLastError(); + } + CloseHandle(data.hEvent); + if (SUCCEEDED(data.hRes)) + data.hRes = CoGetInterfaceAndReleaseStream(data.pStream, riid, ppvObj); + return data.hRes; + } + DWORD dwThreadID; + int m_nThreads; + CComApartment* m_pApartments; + ThreadAllocator m_Allocator; + static int GetDefaultThreads() + { + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwNumberOfProcessors * 4; + } +}; + +class CAtlAutoThreadModule : public CAtlAutoThreadModuleT +{ +public : +}; + +#ifndef _ATL_NO_COMMODULE + +template +class CComAutoThreadModule : + public CComModule, + public CAtlAutoThreadModuleT, ThreadAllocator, dwWait> +{ +public: + CComAutoThreadModule(int nThreads = GetDefaultThreads()) : + CAtlAutoThreadModuleT, ThreadAllocator, dwWait>(nThreads) + { + } + HRESULT Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, const GUID* plibid = NULL, int nThreads = GetDefaultThreads()) + { + nThreads; + ATLASSERT(nThreads == GetDefaultThreads() && _T("Set number of threads through the constructor")); + return CComModule::Init(p, h, plibid); + } +}; + +#endif // !_ATL_NO_COMMODULE + +// Used in CThreadPool +class Win32WaitTraits +{ +public: + static DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwTimeout) + { + return ::WaitForSingleObject(hHandle, dwTimeout); + } +}; + +typedef Win32WaitTraits DefaultWaitTraits; + +///////////////////////////////////////////////////////////////////////////// +// GIT Pointer + +template +class CComGITPtr +{ +public: + CComGITPtr() throw() + { + m_dwCookie = 0; + } + CComGITPtr(T* p) + { + m_dwCookie = 0; + HRESULT hr = Attach(p); + + if (FAILED(hr)) + AtlThrow(hr); + } + CComGITPtr(const CComGITPtr& git) + { + m_dwCookie = 0; + CComPtr spT; + + HRESULT hr = git.CopyTo(&spT); + if (SUCCEEDED(hr)) + hr = Attach(spT); + + if (FAILED(hr)) + AtlThrow(hr); + } + explicit CComGITPtr(DWORD dwCookie) throw() + { + ATLASSUME(m_dwCookie != NULL); + m_dwCookie = dwCookie; + +#ifdef _DEBUG + CComPtr spT; + HRESULT hr = CopyTo(&spT); + ATLASSERT(SUCCEEDED(hr)); +#endif + } + + ~CComGITPtr() throw() + { + Revoke(); + } + CComGITPtr& operator=(const CComGITPtr& git) + { + if(*this!=git) + { + CComPtr spT; + + HRESULT hr = git.CopyTo(&spT); + if (SUCCEEDED(hr)) + { + hr = Attach(spT); + } + + if (FAILED(hr)) + { + AtlThrow(hr); + } + } + return *this; + } + CComGITPtr& operator=(T* p) + { + HRESULT hr = Attach(p); + if (FAILED(hr)) + AtlThrow(hr); + return *this; + } + CComGITPtr& operator=(DWORD dwCookie) + { + if(*this!=dwCookie) + { + HRESULT hr = Attach(dwCookie); + if (FAILED(hr)) + { + AtlThrow(hr); + } + + m_dwCookie = dwCookie; + +#ifdef _DEBUG + CComPtr spT; + hr = CopyTo(&spT); + ATLASSERT(SUCCEEDED(hr)); +#endif + } + return *this; + } + + // basic comparison operators + bool operator!=(CComGITPtr& git) const + { + return !operator==(git); + } + + bool operator!=(DWORD dwCookie) const + { + return !operator==(dwCookie); + } + + bool operator==(CComGITPtr& git) const + { + return m_dwCookie==git.GetCookie(); + } + + bool operator==(DWORD dwCookie) const + { + return m_dwCookie==dwCookie; + } + + // Get the cookie from the class + operator DWORD() const + { + return m_dwCookie; + } + // Get the cookie from the class + DWORD GetCookie() const + { + return m_dwCookie; + } + // Register the passed interface pointer in the GIT + HRESULT Attach(T* p) throw() + { + CComPtr spGIT; + HRESULT hr = E_FAIL; + hr = AtlGetGITPtr(&spGIT); + ATLASSERT(spGIT != NULL); + ATLASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) + return hr; + + if (m_dwCookie != 0) + hr = spGIT->RevokeInterfaceFromGlobal(m_dwCookie); + if (FAILED(hr)) + return hr; + + return spGIT->RegisterInterfaceInGlobal(p, __uuidof(T), &m_dwCookie); + } + + HRESULT Attach(DWORD dwCookie) throw() + { + ATLASSERT(dwCookie != NULL); + HRESULT hr = Revoke(); + if (FAILED(hr)) + return hr; + m_dwCookie = dwCookie; + return S_OK; + } + + // Detach + DWORD Detach() throw() + { + DWORD dwCookie = m_dwCookie; + m_dwCookie = NULL; + return dwCookie; + } + + // Remove the interface from the GIT + HRESULT Revoke() throw() + { + HRESULT hr = S_OK; + if (m_dwCookie != 0) + { + CComPtr spGIT; + HRESULT hr = E_FAIL; + hr = AtlGetGITPtr(&spGIT); + + ATLASSERT(spGIT != NULL); + ATLASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) + return hr; + + hr = spGIT->RevokeInterfaceFromGlobal(m_dwCookie); + if (SUCCEEDED(hr)) + m_dwCookie = 0; + } + return hr; + } + // Get's the interface from the GIT and copies it to the passed pointer. The pointer + // must be released by the caller when finished. + HRESULT CopyTo(T** pp) const throw() + { + CComPtr spGIT; + HRESULT hr = E_FAIL; + hr = AtlGetGITPtr(&spGIT); + + ATLASSERT(spGIT != NULL); + ATLASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) + return hr; + + ATLASSUME(m_dwCookie!=NULL); + return spGIT->GetInterfaceFromGlobal(m_dwCookie, __uuidof(T), (void**)pp); + } + DWORD m_dwCookie; +}; + +///////////////////////////////////////////////////////////////////////////// +// CRegKey + +typedef LONG (WINAPI _ATL_DELETEKEYEXFUNC)(HKEY hKey, LPCTSTR lpSubKey, REGSAM samDesired, DWORD Reserved); +typedef LONG (WINAPI _ATL_DELETEKEYFUNC)(HKEY hKey, LPCTSTR lpSubKey); + +class CRegKey +{ +public: + CRegKey() throw(); + CRegKey( CRegKey& key ) throw(); + explicit CRegKey(HKEY hKey) throw(); + ~CRegKey() throw(); + + CRegKey& operator=( CRegKey& key ) throw(); + +// Attributes +public: + operator HKEY() const throw(); + HKEY m_hKey; + +private: + _ATL_DELETEKEYEXFUNC* pfnDeleteKeyEx; + _ATL_DELETEKEYFUNC* pfnDeleteKey; + +// Operations +public: + ATL_DEPRECATED("CRegKey::SetValue(DWORD, TCHAR *valueName) has been superseded by CRegKey::SetDWORDValue") + LONG SetValue(DWORD dwValue, LPCTSTR lpszValueName); + ATL_DEPRECATED("CRegKey::SetValue(TCHAR *value, TCHAR *valueName) has been superseded by CRegKey::SetStringValue and CRegKey::SetMultiStringValue") + LONG SetValue(LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL, bool bMulti = false, int nValueLen = -1); + LONG SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) throw(); + LONG SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) throw(); + LONG SetBinaryValue(LPCTSTR pszValueName, const void* pValue, ULONG nBytes) throw(); + LONG SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) throw(); + LONG SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) throw(); + LONG SetStringValue(__in_z_opt LPCTSTR pszValueName, __in_z LPCTSTR pszValue, __in DWORD dwType = REG_SZ) throw(...); + LONG SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) throw(...); + + ATL_DEPRECATED("CRegKey::QueryValue(DWORD, TCHAR *valueName) has been superseded by CRegKey::QueryDWORDValue") + LONG QueryValue(__out DWORD& dwValue, __in_z_opt LPCTSTR lpszValueName); + ATL_DEPRECATED("CRegKey::QueryValue(TCHAR *value, TCHAR *valueName) has been superseded by CRegKey::QueryStringValue and CRegKey::QueryMultiStringValue") + LONG QueryValue(__out_ecount_part_z_opt(*pdwCount, *pdwCount) LPTSTR szValue, __in_z_opt LPCTSTR lpszValueName, __inout DWORD* pdwCount); + LONG QueryValue(__in_z_opt LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) throw(); + LONG QueryGUIDValue(__in_z_opt LPCTSTR pszValueName, GUID& guidValue) throw(); + LONG QueryBinaryValue(__in_z_opt LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) throw(); + LONG QueryDWORDValue(__in_z_opt LPCTSTR pszValueName, DWORD& dwValue) throw(); + LONG QueryQWORDValue(__in_z_opt LPCTSTR pszValueName, ULONGLONG& qwValue) throw(); + LONG QueryStringValue(__in_z_opt LPCTSTR pszValueName, __out_ecount_part_z_opt(*pnChars, *pnChars) LPTSTR pszValue, __inout ULONG* pnChars) throw(); + + LONG QueryMultiStringValue(__in_z_opt LPCTSTR pszValueName, __out_ecount_part_z_opt(*pnChars, *pnChars) __out_z LPTSTR pszValue, __inout ULONG* pnChars) throw(); + + // Get the key's security attributes. + LONG GetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd, LPDWORD pnBytes) throw(); + // Set the key's security attributes. + LONG SetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd) throw(); + + LONG SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL) throw(); + static LONG WINAPI SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName, + LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL); + + // Create a new registry key (or open an existing one). + LONG Create(__in HKEY hKeyParent, __in_z LPCTSTR lpszKeyName, + __in_z_opt LPTSTR lpszClass = REG_NONE, __in DWORD dwOptions = REG_OPTION_NON_VOLATILE, + __in REGSAM samDesired = KEY_READ | KEY_WRITE, + __in_opt LPSECURITY_ATTRIBUTES lpSecAttr = NULL, + __in_opt LPDWORD lpdwDisposition = NULL) throw(); + // Open an existing registry key. + LONG Open(HKEY hKeyParent, LPCTSTR lpszKeyName, + REGSAM samDesired = KEY_READ | KEY_WRITE) throw(); + // Close the registry key. + LONG Close() throw(); + // Flush the key's data to disk. + LONG Flush() throw(); + + // Detach the CRegKey object from its HKEY. Releases ownership. + HKEY Detach() throw(); + // Attach the CRegKey object to an existing HKEY. Takes ownership. + void Attach(HKEY hKey) throw(); + + // Enumerate the subkeys of the key. + LONG EnumKey(__in DWORD iIndex, __out_ecount_part_z(*pnNameLength, *pnNameLength) LPTSTR pszName, __inout LPDWORD pnNameLength, __out_opt FILETIME* pftLastWriteTime = NULL) throw(); + LONG NotifyChangeKeyValue(BOOL bWatchSubtree, DWORD dwNotifyFilter, HANDLE hEvent, BOOL bAsync = TRUE) throw(); + + LONG DeleteSubKey(LPCTSTR lpszSubKey) throw(); + LONG RecurseDeleteKey(LPCTSTR lpszKey) throw(); + LONG DeleteValue(LPCTSTR lpszValue) throw(); +}; + +inline CRegKey::CRegKey() throw() : + m_hKey( NULL ), + pfnDeleteKeyEx( NULL ), + pfnDeleteKey( NULL ) +{ +} + +inline CRegKey::CRegKey( CRegKey& key ) throw() : + m_hKey( NULL ), + pfnDeleteKeyEx( NULL ), + pfnDeleteKey( NULL ) +{ + Attach( key.Detach() ); +} + +inline CRegKey::CRegKey(HKEY hKey) throw() : + m_hKey(hKey), + pfnDeleteKeyEx( NULL ), + pfnDeleteKey( NULL ) +{ +} + +inline CRegKey::~CRegKey() throw() +{Close();} + +inline CRegKey& CRegKey::operator=( CRegKey& key ) throw() +{ + if(m_hKey!=key.m_hKey) + { + Close(); + Attach( key.Detach() ); + } + return( *this ); +} + +inline CRegKey::operator HKEY() const throw() +{return m_hKey;} + +inline HKEY CRegKey::Detach() throw() +{ + HKEY hKey = m_hKey; + m_hKey = NULL; + return hKey; +} + +inline void CRegKey::Attach(HKEY hKey) throw() +{ + ATLASSUME(m_hKey == NULL); + m_hKey = hKey; +} + +#pragma warning(push) +#pragma warning(disable : 4191) // 'type cast' : unsafe conversion from 'FARPROC' to 'ATL::_ATL_DELETEKEYEXFUNC' + +inline LONG CRegKey::DeleteSubKey(LPCTSTR lpszSubKey) throw() +{ + ATLASSUME(m_hKey != NULL); + + HINSTANCE hInstDLL = NULL; + + if (pfnDeleteKeyEx == NULL && pfnDeleteKey == NULL) + { + // No DLL loaded yet -- get the appropriate one for the current OS. + // Use GetModuleHandle rather than LoadLibrary for apiset dll + // for two reasons: + // + // 1. On Win7+, it will already be loaded into the process + // + // 2. It ensures that there is no opportunity to get a rogue + // "apiset dll" loaded on a down-level machine + + hInstDLL = ::GetModuleHandle(_T("API-MS-Win-Core-LocalRegistry-L1-1-0.dll")); + if (hInstDLL != NULL) + { +#ifdef UNICODE + pfnDeleteKeyEx = (_ATL_DELETEKEYEXFUNC*)GetProcAddress(hInstDLL, "RegDeleteKeyExW"); +#else + pfnDeleteKeyEx = (_ATL_DELETEKEYEXFUNC*)GetProcAddress(hInstDLL, "RegDeleteKeyExA"); +#endif + } + else + { + // No apiset dll, so load advapi32.dll instead. + // Note that this DLL is never unloaded for two reasons: + // + // 1. It is likely that the CRegKey destructor is called + // during DLL_PROCESS_ATTACH in multiple applications. + // + // 2. Whichever DLL is found (apiset dll or advapi32.dll) + // is almost guaranteed to be in use by other DLLs in the + // process, so the unload would have little (or no) effect. + + hInstDLL = ::LoadLibrary(_T("advapi32.dll")); + if (hInstDLL != NULL) + { +#ifdef UNICODE + pfnDeleteKey = (_ATL_DELETEKEYFUNC*)GetProcAddress(hInstDLL, "RegDeleteKeyW"); +#else + pfnDeleteKey = (_ATL_DELETEKEYFUNC*)GetProcAddress(hInstDLL, "RegDeleteKeyA"); +#endif + } + } + } + + if (pfnDeleteKeyEx != NULL) + { + return pfnDeleteKeyEx(m_hKey, lpszSubKey, 0, 0); + } + else if (pfnDeleteKey != NULL) + { + return pfnDeleteKey(m_hKey, lpszSubKey); + } + + // DLL loads failed + return GetLastError(); +} + +#pragma warning(pop) + +inline LONG CRegKey::DeleteValue(LPCTSTR lpszValue) throw() +{ + ATLASSUME(m_hKey != NULL); + return RegDeleteValue(m_hKey, (LPTSTR)lpszValue); +} + +inline LONG CRegKey::Close() throw() +{ + LONG lRes = ERROR_SUCCESS; + if (m_hKey != NULL) + { + lRes = RegCloseKey(m_hKey); + m_hKey = NULL; + } + return lRes; +} + +inline LONG CRegKey::Flush() throw() +{ + ATLASSUME(m_hKey != NULL); + + return ::RegFlushKey(m_hKey); +} + +inline LONG CRegKey::EnumKey(__in DWORD iIndex, __out_ecount_part_z(*pnNameLength, *pnNameLength) LPTSTR pszName, __inout LPDWORD pnNameLength, __out_opt FILETIME* pftLastWriteTime) throw() +{ + FILETIME ftLastWriteTime; + + ATLASSUME(m_hKey != NULL); + if (pftLastWriteTime == NULL) + { + pftLastWriteTime = &ftLastWriteTime; + } + + return ::RegEnumKeyEx(m_hKey, iIndex, pszName, pnNameLength, NULL, NULL, NULL, pftLastWriteTime); +} + +inline LONG CRegKey::NotifyChangeKeyValue(BOOL bWatchSubtree, DWORD dwNotifyFilter, HANDLE hEvent, BOOL bAsync) throw() +{ + ATLASSUME(m_hKey != NULL); + ATLASSERT((hEvent != NULL) || !bAsync); + + return ::RegNotifyChangeKeyValue(m_hKey, bWatchSubtree, dwNotifyFilter, hEvent, bAsync); +} + +inline LONG CRegKey::Create(__in HKEY hKeyParent, __in_z LPCTSTR lpszKeyName, + __in_z_opt LPTSTR lpszClass, __in DWORD dwOptions, __in REGSAM samDesired, + __in_opt LPSECURITY_ATTRIBUTES lpSecAttr, __in_opt LPDWORD lpdwDisposition) throw() +{ + ATLASSERT(hKeyParent != NULL); + DWORD dw; + HKEY hKey = NULL; + LONG lRes = RegCreateKeyEx(hKeyParent, lpszKeyName, 0, + lpszClass, dwOptions, samDesired, lpSecAttr, &hKey, &dw); + if (lpdwDisposition != NULL) + *lpdwDisposition = dw; + if (lRes == ERROR_SUCCESS) + { + lRes = Close(); + m_hKey = hKey; + } + return lRes; +} + +inline LONG CRegKey::Open(HKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired) throw() +{ + ATLASSERT(hKeyParent != NULL); + HKEY hKey = NULL; + LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyName, 0, samDesired, &hKey); + if (lRes == ERROR_SUCCESS) + { + lRes = Close(); + ATLASSERT(lRes == ERROR_SUCCESS); + m_hKey = hKey; + } + return lRes; +} + +#pragma warning(push) +#pragma warning(disable: 4996) +inline LONG CRegKey::QueryValue(DWORD& dwValue, LPCTSTR lpszValueName) +{ + DWORD dwType = NULL; + DWORD dwCount = sizeof(DWORD); + LONG lRes = RegQueryValueEx(m_hKey, lpszValueName, NULL, &dwType, + (LPBYTE)&dwValue, &dwCount); + ATLASSERT((lRes!=ERROR_SUCCESS) || (dwType == REG_DWORD)); + ATLASSERT((lRes!=ERROR_SUCCESS) || (dwCount == sizeof(DWORD))); + if (dwType != REG_DWORD) + return ERROR_INVALID_DATA; + return lRes; +} + +// +// [pfx_parse] - workaround for PREfix parse problem +// +#if ((defined(_PREFIX_)) || (defined(_PREFAST_))) && (_MSC_VER < 1400) + // do nothing, this pragma not understood by PREfix 5.1 +#else // !_PREFIX_ +#pragma warning(disable: 6053) +#endif //!_PREFIX_ + +inline LONG CRegKey::QueryValue(__out_ecount_part_z_opt(*pdwCount, *pdwCount) LPTSTR pszValue, __in_z_opt LPCTSTR lpszValueName, __inout DWORD* pdwCount) +{ + ATLENSURE(pdwCount != NULL); + DWORD dwType = NULL; + LONG lRes = RegQueryValueEx(m_hKey, lpszValueName, NULL, &dwType, (LPBYTE)pszValue, pdwCount); + ATLASSERT((lRes!=ERROR_SUCCESS) || (dwType == REG_SZ) || + (dwType == REG_MULTI_SZ) || (dwType == REG_EXPAND_SZ)); + if (pszValue != NULL) + { + if(*pdwCount>0) + { + switch(dwType) + { + case REG_SZ: + case REG_EXPAND_SZ: + if ((*pdwCount) % sizeof(TCHAR) != 0 || pszValue[(*pdwCount) / sizeof(TCHAR) - 1] != 0) + { + pszValue[0]=_T('\0'); + return ERROR_INVALID_DATA; + } + break; + case REG_MULTI_SZ: + if ((*pdwCount) % sizeof(TCHAR) != 0 || (*pdwCount) / sizeof(TCHAR) < 1 || pszValue[(*pdwCount) / sizeof(TCHAR) -1] != 0 || (((*pdwCount) / sizeof(TCHAR))>1 && pszValue[(*pdwCount) / sizeof(TCHAR) - 2] != 0) ) + { + pszValue[0]=_T('\0'); + return ERROR_INVALID_DATA; + } + break; + default: + // Ensure termination + pszValue[0]=_T('\0'); + return ERROR_INVALID_DATA; + } + } + else + { + // this is a blank one with no data yet + // Ensure termination + pszValue[0]=_T('\0'); + } + } + return lRes; +} +#pragma warning(pop) + +inline LONG CRegKey::QueryValue(LPCTSTR pszValueName, DWORD* pdwType, void* pData, ULONG* pnBytes) throw() +{ + ATLASSUME(m_hKey != NULL); + + return( ::RegQueryValueEx(m_hKey, pszValueName, NULL, pdwType, static_cast< LPBYTE >( pData ), pnBytes) ); +} + +inline LONG CRegKey::QueryDWORDValue(LPCTSTR pszValueName, DWORD& dwValue) throw() +{ + LONG lRes; + ULONG nBytes; + DWORD dwType; + + ATLASSUME(m_hKey != NULL); + + nBytes = sizeof(DWORD); + lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&dwValue), + &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_DWORD) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; +} +inline LONG CRegKey::QueryQWORDValue(LPCTSTR pszValueName, ULONGLONG& qwValue) throw() +{ + LONG lRes; + ULONG nBytes; + DWORD dwType; + + ATLASSUME(m_hKey != NULL); + + nBytes = sizeof(ULONGLONG); + lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(&qwValue), + &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_QWORD) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; +} + +inline LONG CRegKey::QueryBinaryValue(LPCTSTR pszValueName, void* pValue, ULONG* pnBytes) throw() +{ + LONG lRes; + DWORD dwType; + + ATLASSERT(pnBytes != NULL); + ATLASSUME(m_hKey != NULL); + + lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pValue), + pnBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_BINARY) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; +} + +#pragma warning(push) + +// +// [pfx_parse] - workaround for PREfix parse problem +// +#if ((defined(_PREFIX_)) || (defined(_PREFAST_))) && (_MSC_VER < 1400) + // do nothing, this pragma not understood by PREfix 5.1 +#else // !_PREFIX_ +#pragma warning(disable: 6053) +#endif //!_PREFIX_ + +/* prefast noise VSW 496818 */ +inline LONG CRegKey::QueryStringValue(__in_z_opt LPCTSTR pszValueName, __out_ecount_part_z_opt(*pnChars, *pnChars) __out_z LPTSTR pszValue, __inout ULONG* pnChars) throw() +{ + LONG lRes; + DWORD dwType; + ULONG nBytes; + + ATLASSUME(m_hKey != NULL); + ATLASSERT(pnChars != NULL); + + nBytes = (*pnChars)*sizeof(TCHAR); + *pnChars = 0; + lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), + &nBytes); + + if (lRes != ERROR_SUCCESS) + { + return lRes; + } + + if(dwType != REG_SZ && dwType != REG_EXPAND_SZ) + { + return ERROR_INVALID_DATA; + } + + if (pszValue != NULL) + { + if(nBytes!=0) + { + if ((nBytes % sizeof(TCHAR) != 0) || (pszValue[nBytes / sizeof(TCHAR) -1] != 0)) + { + return ERROR_INVALID_DATA; + } + } + else + { + pszValue[0]=_T('\0'); + } + } + + *pnChars = nBytes/sizeof(TCHAR); + + return ERROR_SUCCESS; +} +#pragma warning(pop) + +#pragma warning(push) + +// +// [pfx_parse] - workaround for PREfix parse problem +// +#if ((defined(_PREFIX_)) || (defined(_PREFAST_))) && (_MSC_VER < 1400) + // do nothing, this pragma not understood by PREfix 5.1 +#else // !_PREFIX_ +#pragma warning(disable: 6053) +#endif // !_PREFIX_ + +/* prefast noise VSW 496818 */ +inline LONG CRegKey::QueryMultiStringValue(__in_z_opt LPCTSTR pszValueName, __out_ecount_part_z_opt(*pnChars, *pnChars) __out_z LPTSTR pszValue, __inout ULONG* pnChars) throw() +{ + LONG lRes; + DWORD dwType; + ULONG nBytes; + + ATLASSUME(m_hKey != NULL); + ATLASSERT(pnChars != NULL); + + if (pszValue != NULL && *pnChars < 2) + return ERROR_INSUFFICIENT_BUFFER; + + nBytes = (*pnChars)*sizeof(TCHAR); + *pnChars = 0; + + lRes = ::RegQueryValueEx(m_hKey, pszValueName, NULL, &dwType, reinterpret_cast(pszValue), + &nBytes); + if (lRes != ERROR_SUCCESS) + return lRes; + if (dwType != REG_MULTI_SZ) + return ERROR_INVALID_DATA; + if (pszValue != NULL && (nBytes % sizeof(TCHAR) != 0 || nBytes / sizeof(TCHAR) < 1 || pszValue[nBytes / sizeof(TCHAR) -1] != 0 || ((nBytes/sizeof(TCHAR))>1 && pszValue[nBytes / sizeof(TCHAR) - 2] != 0))) + return ERROR_INVALID_DATA; + + *pnChars = nBytes/sizeof(TCHAR); + + return ERROR_SUCCESS; +} +#pragma warning(pop) + +inline LONG CRegKey::QueryGUIDValue(LPCTSTR pszValueName, GUID& guidValue) throw() +{ + TCHAR szGUID[64]; + LONG lRes; + ULONG nCount; + HRESULT hr; + + ATLASSUME(m_hKey != NULL); + + guidValue = GUID_NULL; + + nCount = 64; + lRes = QueryStringValue(pszValueName, szGUID, &nCount); + + if (lRes != ERROR_SUCCESS) + return lRes; + + if(szGUID[0] != _T('{')) + return ERROR_INVALID_DATA; + + USES_CONVERSION_EX; + LPOLESTR lpstr = T2OLE_EX(szGUID, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpstr == NULL) + return E_OUTOFMEMORY; +#endif + + hr = ::CLSIDFromString(lpstr, &guidValue); + if (FAILED(hr)) + return ERROR_INVALID_DATA; + + return ERROR_SUCCESS; +} + +inline LONG WINAPI CRegKey::SetValue(HKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName) +{ + ATLASSERT(lpszValue != NULL); + CRegKey key; + LONG lRes = key.Create(hKeyParent, lpszKeyName); + if (lRes == ERROR_SUCCESS) + lRes = key.SetStringValue(lpszValueName, lpszValue); + return lRes; +} + +inline LONG CRegKey::SetKeyValue(LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName) throw() +{ + ATLASSERT(lpszValue != NULL); + CRegKey key; + LONG lRes = key.Create(m_hKey, lpszKeyName); + if (lRes == ERROR_SUCCESS) + lRes = key.SetStringValue(lpszValueName, lpszValue); + return lRes; +} + +#pragma warning(push) +#pragma warning(disable: 4996) +inline LONG CRegKey::SetValue(DWORD dwValue, LPCTSTR pszValueName) +{ + ATLASSUME(m_hKey != NULL); + return SetDWORDValue(pszValueName, dwValue); +} + +inline LONG CRegKey::SetValue(LPCTSTR lpszValue, LPCTSTR lpszValueName, bool bMulti, int nValueLen) +{ + ATLENSURE(lpszValue != NULL); + ATLASSUME(m_hKey != NULL); + + if (bMulti && nValueLen == -1) + return ERROR_INVALID_PARAMETER; + + if (nValueLen == -1) + nValueLen = lstrlen(lpszValue) + 1; + + DWORD dwType = bMulti ? REG_MULTI_SZ : REG_SZ; + + return ::RegSetValueEx(m_hKey, lpszValueName, NULL, dwType, + reinterpret_cast(lpszValue), nValueLen*sizeof(TCHAR)); +} +#pragma warning(pop) + +inline LONG CRegKey::SetValue(LPCTSTR pszValueName, DWORD dwType, const void* pValue, ULONG nBytes) throw() +{ + ATLASSUME(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, static_cast(pValue), nBytes); +} + +inline LONG CRegKey::SetBinaryValue(LPCTSTR pszValueName, const void* pData, ULONG nBytes) throw() +{ + ATLASSUME(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_BINARY, reinterpret_cast(pData), nBytes); +} + +inline LONG CRegKey::SetDWORDValue(LPCTSTR pszValueName, DWORD dwValue) throw() +{ + ATLASSUME(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_DWORD, reinterpret_cast(&dwValue), sizeof(DWORD)); +} + +inline LONG CRegKey::SetQWORDValue(LPCTSTR pszValueName, ULONGLONG qwValue) throw() +{ + ATLASSUME(m_hKey != NULL); + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_QWORD, reinterpret_cast(&qwValue), sizeof(ULONGLONG)); +} + +inline LONG CRegKey::SetStringValue(__in_z_opt LPCTSTR pszValueName, __in_z LPCTSTR pszValue, __in DWORD dwType) throw(...) +{ + ATLASSUME(m_hKey != NULL); + ATLENSURE(pszValue != NULL); + ATLASSERT((dwType == REG_SZ) || (dwType == REG_EXPAND_SZ)); + + return ::RegSetValueEx(m_hKey, pszValueName, NULL, dwType, reinterpret_cast(pszValue), (lstrlen(pszValue)+1)*sizeof(TCHAR)); +} + +inline LONG CRegKey::SetMultiStringValue(LPCTSTR pszValueName, LPCTSTR pszValue) throw(...) +{ + LPCTSTR pszTemp; + ULONG nBytes; + ULONG nLength; + + ATLASSUME(m_hKey != NULL); + ATLENSURE(pszValue != NULL); + + // Find the total length (in bytes) of all of the strings, including the + // terminating '\0' of each string, and the second '\0' that terminates + // the list. + nBytes = 0; + pszTemp = pszValue; + do + { + nLength = lstrlen(pszTemp)+1; + pszTemp += nLength; + nBytes += nLength*sizeof(TCHAR); + } while (nLength != 1); + + return ::RegSetValueEx(m_hKey, pszValueName, NULL, REG_MULTI_SZ, reinterpret_cast(pszValue), + nBytes); +} + +inline LONG CRegKey::SetGUIDValue(LPCTSTR pszValueName, REFGUID guidValue) throw() +{ + OLECHAR szGUID[64]; + + ATLASSUME(m_hKey != NULL); + + ::StringFromGUID2(guidValue, szGUID, 64); + + USES_CONVERSION_EX; + LPCTSTR lpstr = OLE2CT_EX(szGUID, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpstr == NULL) + return E_OUTOFMEMORY; +#endif + return SetStringValue(pszValueName, lpstr); +} + +inline LONG CRegKey::GetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd, LPDWORD pnBytes) throw() +{ + ATLASSUME(m_hKey != NULL); + ATLASSERT(pnBytes != NULL); + + return ::RegGetKeySecurity(m_hKey, si, psd, pnBytes); +} + +inline LONG CRegKey::SetKeySecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR psd) throw() +{ + ATLASSUME(m_hKey != NULL); + ATLASSERT(psd != NULL); + + return ::RegSetKeySecurity(m_hKey, si, psd); +} + +inline LONG CRegKey::RecurseDeleteKey(LPCTSTR lpszKey) throw() +{ + CRegKey key; + LONG lRes = key.Open(m_hKey, lpszKey, KEY_READ | KEY_WRITE); + if (lRes != ERROR_SUCCESS) + { + if (lRes != ERROR_FILE_NOT_FOUND && lRes != ERROR_PATH_NOT_FOUND) + { + ATLTRACE(atlTraceCOM, 0, _T("CRegKey::RecurseDeleteKey : Failed to Open Key %s(Error = %d)\n"), lpszKey, lRes); + } + return lRes; + } + FILETIME time; + DWORD dwSize = 256; + TCHAR szBuffer[256]; + while (RegEnumKeyEx(key.m_hKey, 0, szBuffer, &dwSize, NULL, NULL, NULL, + &time)==ERROR_SUCCESS) + { + lRes = key.RecurseDeleteKey(szBuffer); + if (lRes != ERROR_SUCCESS) + return lRes; + dwSize = 256; + } + key.Close(); + return DeleteSubKey(lpszKey); +} + +#ifndef _ATL_NO_COMMODULE + +inline HRESULT CComModule::RegisterProgID(LPCTSTR lpszCLSID, LPCTSTR lpszProgID, LPCTSTR lpszUserDesc) +{ + CRegKey keyProgID; + LONG lRes = keyProgID.Create(HKEY_CLASSES_ROOT, lpszProgID, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE); + if (lRes == ERROR_SUCCESS) + { + lRes = keyProgID.SetStringValue(NULL, lpszUserDesc); + if (lRes == ERROR_SUCCESS) + { + lRes = keyProgID.SetKeyValue(_T("CLSID"), lpszCLSID); + if (lRes == ERROR_SUCCESS) + return S_OK; + } + } + return AtlHresultFromWin32(lRes); +} + +inline HRESULT CComModule::RegisterAppId(LPCTSTR pAppId) +{ + CRegKey keyAppID; + HRESULT hr = S_OK; + LONG lRet; + + if ( (lRet = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_WRITE)) == ERROR_SUCCESS) + { + TCHAR szModule1[MAX_PATH]; + TCHAR szModule2[MAX_PATH]; + TCHAR* pszFileName; + + DWORD dwFLen = ::GetModuleFileName(GetModuleInstance(), szModule1, MAX_PATH); + if ( dwFLen != 0 && dwFLen != MAX_PATH ) + { + if (::GetFullPathName(szModule1, MAX_PATH, szModule2, &pszFileName) != 0) + { + CRegKey keyAppIDEXE; + if ( (lRet = keyAppIDEXE.Create(keyAppID, pszFileName, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE)) == ERROR_SUCCESS) + { + lRet = keyAppIDEXE.SetStringValue(_T("AppID"), pAppId); + if (lRet != ERROR_SUCCESS) + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::RegisterAppId : Failed to set app id string value\n")); + hr = AtlHresultFromWin32(lRet); + return hr; + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::RegisterAppId : Failed to create file name key\n")); + hr = AtlHresultFromWin32(lRet); + return hr; + } + if ( (lRet = keyAppIDEXE.Create(keyAppID, pAppId, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE)) == ERROR_SUCCESS) + { + lRet = keyAppIDEXE.SetStringValue(NULL, pszFileName); + if (lRet != ERROR_SUCCESS) + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::RegisterAppId : Failed to set file name string value\n")); + hr = AtlHresultFromWin32(lRet); + return hr; + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::RegisterAppId : Failed to create app id key\n")); + hr = AtlHresultFromWin32(lRet); + return hr; + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::RegisterAppId : Failed to get full path name for file %s\n"), szModule1); + hr = AtlHresultFromLastError(); + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::RegisterAppId : Failed to get module name\n")); + if( dwFLen == 0 ) + hr = AtlHresultFromLastError(); + else if( dwFLen == MAX_PATH ) + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::RegisterAppId : Failed to open registry key\n")); + hr = AtlHresultFromWin32(lRet); + } + return hr; +} + +inline HRESULT CComModule::UnregisterAppId(LPCTSTR pAppId) +{ + CRegKey keyAppID; + HRESULT hr = S_OK; + LONG lRet = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ | KEY_WRITE); + + if (lRet == ERROR_SUCCESS) + { + TCHAR szModule1[MAX_PATH]; + TCHAR szModule2[MAX_PATH]; + TCHAR* pszFileName; + + DWORD dwFLen = ::GetModuleFileName(GetModuleInstance(), szModule1, MAX_PATH); + if ( dwFLen != 0 && dwFLen != MAX_PATH ) + { + if (::GetFullPathName(szModule1, MAX_PATH, szModule2, &pszFileName) != 0) + { + if ((lRet = keyAppID.RecurseDeleteKey(pAppId)) != ERROR_SUCCESS) + { + if (lRet != ERROR_FILE_NOT_FOUND) + hr = AtlHresultFromWin32(lRet); + } + if ((lRet = keyAppID.RecurseDeleteKey(pszFileName)) != ERROR_SUCCESS) + { + if (lRet != ERROR_FILE_NOT_FOUND) + hr = AtlHresultFromWin32(lRet); + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::UnregisterAppId : Failed to get full path name for file %s\n"), szModule1); + hr = AtlHresultFromLastError(); + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::UnregisterAppId : Failed to get module name\n")); + if( dwFLen == 0 ) + hr = AtlHresultFromLastError(); + else if( dwFLen == MAX_PATH ) + hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + } + else + { + if (lRet != ERROR_FILE_NOT_FOUND && lRet != ERROR_PATH_NOT_FOUND) + { + ATLTRACE(atlTraceCOM, 0, _T("CComModule::UnregisterAppId : Failed to open registry key\n")); + hr = AtlHresultFromWin32(lRet); + } + } + return hr; +} +#endif // !_ATL_NO_COMMODULE + +#ifdef _ATL_STATIC_REGISTRY +} // namespace ATL + + +#include + + + +namespace ATL +{ + +// Statically linking to Registry Ponent +inline HRESULT WINAPI CAtlModule::UpdateRegistryFromResourceS(LPCTSTR lpszRes, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries /*= NULL*/) throw() +{ + CRegObject ro; + HRESULT hr = ro.FinalConstruct(); + if (FAILED(hr)) + { + return hr; + } + + if (pMapEntries != NULL) + { + while (pMapEntries->szKey != NULL) + { + ATLASSERT(NULL != pMapEntries->szData); + ro.AddReplacement(pMapEntries->szKey, pMapEntries->szData); + pMapEntries++; + } + } + + hr = AddCommonRGSReplacements(&ro); + if (FAILED(hr)) + return hr; + + USES_CONVERSION_EX; + TCHAR szModule[MAX_PATH]; + HINSTANCE hInst = _AtlBaseModule.GetModuleInstance(); + DWORD dwFLen = GetModuleFileName(hInst, szModule, MAX_PATH); + if( dwFLen == 0 ) + return AtlHresultFromLastError(); + else if( dwFLen == MAX_PATH ) + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + + + LPOLESTR pszModule = NULL; + pszModule = T2OLE_EX(szModule, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(pszModule == NULL) + return E_OUTOFMEMORY; +#endif + + OLECHAR pszModuleUnquoted[_MAX_PATH * 2]; + EscapeSingleQuote(pszModuleUnquoted, _countof(pszModuleUnquoted), pszModule); + + HRESULT hRes; + if ((hInst == NULL) || (hInst == GetModuleHandle(NULL))) // register as EXE + { + // If Registering as an EXE, then we quote the resultant path. + // We don't do it for a DLL, because LoadLibrary fails if the path is + // quoted + OLECHAR pszModuleQuote[(_MAX_PATH + _ATL_QUOTES_SPACE)*2]; + pszModuleQuote[0] = OLESTR('\"'); + if(!ocscpy_s(pszModuleQuote + 1, (_MAX_PATH + _ATL_QUOTES_SPACE)*2 - 1, pszModuleUnquoted)) + { + return E_FAIL; + } + size_t nLen = ocslen(pszModuleQuote); + pszModuleQuote[nLen] = OLESTR('\"'); + pszModuleQuote[nLen + 1] = 0; + + hRes = ro.AddReplacement(OLESTR("Module"), pszModuleQuote); + } + else + { + hRes = ro.AddReplacement(OLESTR("Module"), pszModuleUnquoted); + } + + if(FAILED(hRes)) + return hRes; + + hRes = ro.AddReplacement(OLESTR("Module_Raw"), pszModuleUnquoted); + if(FAILED(hRes)) + return hRes; + + LPCOLESTR szType = OLESTR("REGISTRY"); + LPCOLESTR pszRes = T2COLE_EX(lpszRes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(pszRes == NULL) + return E_OUTOFMEMORY; +#endif + hr = (bRegister) ? ro.ResourceRegisterSz(pszModule, pszRes, szType) : + ro.ResourceUnregisterSz(pszModule, pszRes, szType); + return hr; +} +inline HRESULT WINAPI CAtlModule::UpdateRegistryFromResourceS(UINT nResID, BOOL bRegister, + struct _ATL_REGMAP_ENTRY* pMapEntries /*= NULL*/) throw() +{ + CRegObject ro; + HRESULT hr = ro.FinalConstruct(); + if (FAILED(hr)) + { + return hr; + } + + if (pMapEntries != NULL) + { + while (pMapEntries->szKey != NULL) + { + ATLASSERT(NULL != pMapEntries->szData); + ro.AddReplacement(pMapEntries->szKey, pMapEntries->szData); + pMapEntries++; + } + } + + hr = AddCommonRGSReplacements(&ro); + if (FAILED(hr)) + return hr; + + USES_CONVERSION_EX; + TCHAR szModule[MAX_PATH]; + HINSTANCE hInst = _AtlBaseModule.GetModuleInstance(); + DWORD dwFLen = GetModuleFileName(hInst, szModule, MAX_PATH); + if( dwFLen == 0 ) + return AtlHresultFromLastError(); + else if( dwFLen == MAX_PATH ) + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + + LPOLESTR pszModule = NULL; + pszModule = T2OLE_EX(szModule, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(pszModule == NULL) + return E_OUTOFMEMORY; +#endif + + OLECHAR pszModuleUnquoted[_MAX_PATH * 2]; + EscapeSingleQuote(pszModuleUnquoted, _countof(pszModuleUnquoted), pszModule); + + HRESULT hRes; + if ((hInst == NULL) || (hInst == GetModuleHandle(NULL))) // register as EXE + { + // If Registering as an EXE, then we quote the resultant path. + // We don't do it for a DLL, because LoadLibrary fails if the path is + // quoted + OLECHAR pszModuleQuote[(_MAX_PATH + _ATL_QUOTES_SPACE)*2]; + pszModuleQuote[0] = OLESTR('\"'); + if(!ocscpy_s(pszModuleQuote + 1, (_MAX_PATH + _ATL_QUOTES_SPACE)*2 - 1, pszModuleUnquoted)) + { + return E_FAIL; + } + size_t nLen = ocslen(pszModuleQuote); + pszModuleQuote[nLen] = OLESTR('\"'); + pszModuleQuote[nLen + 1] = 0; + + hRes = ro.AddReplacement(OLESTR("Module"), pszModuleQuote); + } + else + { + hRes = ro.AddReplacement(OLESTR("Module"), pszModuleUnquoted); + } + + if(FAILED(hRes)) + return hRes; + + hRes = ro.AddReplacement(OLESTR("Module_Raw"), pszModuleUnquoted); + if(FAILED(hRes)) + return hRes; + + LPCOLESTR szType = OLESTR("REGISTRY"); + hr = (bRegister) ? ro.ResourceRegister(pszModule, nResID, szType) : + ro.ResourceUnregister(pszModule, nResID, szType); + return hr; +} +#endif //_ATL_STATIC_REGISTRY + +#ifndef _ATL_NO_COMMODULE + +#pragma warning( push ) +#pragma warning( disable: 4996 ) // Disable "deprecated symbol" warning + +inline HRESULT WINAPI CComModule::UpdateRegistryClass(const CLSID& clsid, LPCTSTR lpszProgID, + LPCTSTR lpszVerIndProgID, UINT nDescID, DWORD dwFlags, BOOL bRegister) +{ + if (bRegister) + { + TCHAR szDesc[256]; + LoadString(m_hInst, nDescID, szDesc, 256); + return RegisterClassHelper(clsid, lpszProgID, lpszVerIndProgID, szDesc, dwFlags); + } + return UnregisterClassHelper(clsid, lpszProgID, lpszVerIndProgID); +} + +inline HRESULT WINAPI CComModule::UpdateRegistryClass(const CLSID& clsid, LPCTSTR lpszProgID, + LPCTSTR lpszVerIndProgID, LPCTSTR szDesc, DWORD dwFlags, BOOL bRegister) +{ + if (bRegister) + return RegisterClassHelper(clsid, lpszProgID, lpszVerIndProgID, szDesc, dwFlags); + return UnregisterClassHelper(clsid, lpszProgID, lpszVerIndProgID); +} + +inline HRESULT WINAPI CComModule::RegisterClassHelper(const CLSID& clsid, LPCTSTR lpszProgID, + LPCTSTR lpszVerIndProgID, LPCTSTR szDesc, DWORD dwFlags) +{ + static const TCHAR szProgID[] = _T("ProgID"); + static const TCHAR szVIProgID[] = _T("VersionIndependentProgID"); + static const TCHAR szLS32[] = _T("LocalServer32"); + static const TCHAR szIPS32[] = _T("InprocServer32"); + static const TCHAR szThreadingModel[] = _T("ThreadingModel"); + static const TCHAR szAUTPRX32[] = _T("AUTPRX32.DLL"); + static const TCHAR szApartment[] = _T("Apartment"); + static const TCHAR szBoth[] = _T("both"); + USES_CONVERSION_EX; + TCHAR szModule[_MAX_PATH + _ATL_QUOTES_SPACE]; + + ATLENSURE(lpszProgID && lpszVerIndProgID || !lpszProgID && !lpszVerIndProgID); + + if (!szDesc) + { + szDesc = _T(""); + } + + // If the ModuleFileName's length is equal or greater than the 3rd parameter + // (length of the buffer passed),GetModuleFileName fills the buffer (truncates + // if neccessary), but doesn't null terminate it. It returns the same value as + // the 3rd parameter passed. So if the return value is the same as the 3rd param + // then you have a non null terminated buffer (which may or may not be truncated) + // We pass (szModule + 1) because in case it's an EXE we need to quote the PATH + // The quote is done later in this method before the SetKeyValue is called + DWORD dwLen = GetModuleFileName(m_hInst, szModule + 1, MAX_PATH); + if (dwLen == 0) + { + return AtlHresultFromLastError(); + } + else if( dwLen == MAX_PATH ) + { + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + } + + LPOLESTR lpOleStr; + HRESULT hRes = StringFromCLSID(clsid, &lpOleStr); + if (FAILED(hRes)) + return hRes; + + LPTSTR lpszCLSID = OLE2T_EX(lpOleStr, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpszCLSID == NULL) + { + CoTaskMemFree(lpOleStr); + return E_OUTOFMEMORY; + } +#endif + + hRes = lpszProgID ? RegisterProgID(lpszCLSID, lpszProgID, szDesc) : S_OK; + if (hRes == S_OK) + hRes = lpszVerIndProgID ? RegisterProgID(lpszCLSID, lpszVerIndProgID, szDesc) : S_OK; + LONG lRes = ERROR_SUCCESS; + if (hRes == S_OK) + { + CRegKey key; + lRes = key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ | KEY_WRITE); + if (lRes == ERROR_SUCCESS) + { + lRes = key.Create(key, lpszCLSID, REG_NONE, REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE); + if (lRes == ERROR_SUCCESS) + { + lRes = key.SetStringValue(NULL, szDesc); + if (lRes == ERROR_SUCCESS) + { + lRes = lpszProgID ? key.SetKeyValue(szProgID, lpszProgID) : ERROR_SUCCESS; + if (lRes == ERROR_SUCCESS) + { + lRes = lpszVerIndProgID ? key.SetKeyValue(szVIProgID, lpszVerIndProgID) : ERROR_SUCCESS; + if (lRes == ERROR_SUCCESS) + { + if ((m_hInst == NULL) || (m_hInst == GetModuleHandle(NULL))) // register as EXE + { + // If Registering as an EXE, then we quote the resultant path. + // We don't do it for a DLL, because LoadLibrary fails if the path is + // quoted + szModule[0] = _T('\"'); + szModule[dwLen + 1] = _T('\"'); + szModule[dwLen + 2] = 0; + + lRes = key.SetKeyValue(szLS32, szModule); + } + else + { + lRes = key.SetKeyValue(szIPS32, (dwFlags & AUTPRXFLAG) ? szAUTPRX32 : szModule + 1); + if (lRes == ERROR_SUCCESS) + { + LPCTSTR lpszModel = (dwFlags & THREADFLAGS_BOTH) ? szBoth : + (dwFlags & THREADFLAGS_APARTMENT) ? szApartment : NULL; + if (lpszModel != NULL) + lRes = key.SetKeyValue(szIPS32, lpszModel, szThreadingModel); + } + } + } + } + } + } + } + } + CoTaskMemFree(lpOleStr); + if (lRes != ERROR_SUCCESS) + hRes = AtlHresultFromWin32(lRes); + return hRes; +} + +inline HRESULT WINAPI CComModule::UnregisterClassHelper(const CLSID& clsid, LPCTSTR lpszProgID, + LPCTSTR lpszVerIndProgID) +{ + USES_CONVERSION_EX; + CRegKey key; + LONG lRet; + + key.Attach(HKEY_CLASSES_ROOT); + if (lpszProgID != NULL && lpszProgID[0]!=_T('\0')) + { + lRet = key.RecurseDeleteKey(lpszProgID); + if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND && lRet != ERROR_PATH_NOT_FOUND) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to Unregister ProgID : %s\n"), lpszProgID); + key.Detach(); + return AtlHresultFromWin32(lRet); + } + } + if (lpszVerIndProgID != NULL && lpszVerIndProgID[0]!=_T('\0')) + { + lRet = key.RecurseDeleteKey(lpszVerIndProgID); + if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND && lRet != ERROR_PATH_NOT_FOUND) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to Unregister Version Independent ProgID : %s\n"), lpszVerIndProgID); + key.Detach(); + return AtlHresultFromWin32(lRet); + } + } + LPOLESTR lpOleStr; + HRESULT hr = StringFromCLSID(clsid, &lpOleStr); + if (SUCCEEDED(hr)) + { + LPTSTR lpsz = OLE2T_EX(lpOleStr, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpsz == NULL) + { + CoTaskMemFree(lpOleStr); + return E_OUTOFMEMORY; + } +#endif + + lRet = key.Open(key, _T("CLSID"), KEY_READ | KEY_WRITE); + if (lRet == ERROR_SUCCESS) + lRet = key.RecurseDeleteKey(lpsz); + if (lRet != ERROR_SUCCESS && lRet != ERROR_FILE_NOT_FOUND && lRet != ERROR_PATH_NOT_FOUND) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to delete CLSID : %s\n"), lpsz); + hr = AtlHresultFromWin32(lRet); + } + CoTaskMemFree(lpOleStr); + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to delete CLSID : {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"), + clsid.Data1, + clsid.Data2, + clsid.Data3, + clsid.Data4[0], + clsid.Data4[1], + clsid.Data4[2], + clsid.Data4[3], + clsid.Data4[4], + clsid.Data4[5], + clsid.Data4[6], + clsid.Data4[7] + ); + } + key.Detach(); + return hr; +} + +#pragma warning( pop ) // Disable "deprecated symbol" warning + +#endif // !_ATL_NO_COMMODULE + +#ifdef _ATL_DEBUG_INTERFACES + +inline void _QIThunk::Dump() throw() +{ + TCHAR buf[512+1]; + if (m_dwRef != 0) + { +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) + _stprintf_s(buf, _countof(buf), _T("ATL: QIThunk - %-10d\tLEAK :\tObject = 0x%p\tRefcount = %d\tMaxRefCount = %d\t"), + m_nIndex, m_pUnk, m_dwRef, m_dwMaxRef); +#else +#pragma warning(push) +#pragma warning(disable:4995) // wsprintf is deprecated + wsprintf(buf, _T("ATL: QIThunk - %-10d\tLEAK :\tObject = 0x%p\tRefcount = %d\tMaxRefCount = %d\t"), m_nIndex, m_pUnk, m_dwRef, m_dwMaxRef); +#pragma warning(pop) +#endif + buf[_countof(buf)-1] = 0; + OutputDebugString(buf); + AtlDumpIID(m_iid, m_lpszClassName, S_OK); + } + else + { +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) + _stprintf_s(buf, _countof(buf), _T("ATL: QIThunk - %-10d\tNonAddRef LEAK :\tObject = 0x%p\t"), m_nIndex, m_pUnk); +#else +#pragma warning(push) +#pragma warning(disable:4995) // wsprintf is deprecated + wsprintf(buf, _T("ATL: QIThunk - %-10d\tNonAddRef LEAK :\tObject = 0x%p\t"), m_nIndex, m_pUnk); +#pragma warning(pop) +#endif + buf[_countof(buf)-1] = 0; + OutputDebugString(buf); + AtlDumpIID(m_iid, m_lpszClassName, S_OK); + } +} + +#endif // _ATL_DEBUG_INTERFACES + +#if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI) +__forceinline HRESULT WINAPI AtlDumpIID(REFIID iid, LPCTSTR pszClassName, HRESULT hr) throw() +{ + USES_CONVERSION_EX; + CRegKey key; + TCHAR szName[100]; + DWORD dwType; + DWORD dw = sizeof(szName); + + LPOLESTR pszGUID = NULL; + if (FAILED(StringFromCLSID(iid, &pszGUID))) + return hr; + + OutputDebugString(pszClassName); + OutputDebugString(_T(" - ")); + + LPTSTR lpszGUID = OLE2T_EX(pszGUID, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpszGUID == NULL) + { + CoTaskMemFree(pszGUID); + return hr; + } +#endif + // Attempt to find it in the interfaces section + if (key.Open(HKEY_CLASSES_ROOT, _T("Interface"), KEY_READ) == ERROR_SUCCESS) + { + if (key.Open(key, lpszGUID, KEY_READ) == ERROR_SUCCESS) + { + *szName = 0; + if (RegQueryValueEx(key.m_hKey, (LPTSTR)NULL, NULL, &dwType, (LPBYTE)szName, &dw) == ERROR_SUCCESS) + { + OutputDebugString(szName); + } + } + } + // Attempt to find it in the clsid section + if (key.Open(HKEY_CLASSES_ROOT, _T("CLSID"), KEY_READ) == ERROR_SUCCESS) + { + if (key.Open(key, lpszGUID, KEY_READ) == ERROR_SUCCESS) + { + *szName = 0; + dw = sizeof(szName); + if (RegQueryValueEx(key.m_hKey, (LPTSTR)NULL, NULL, &dwType, (LPBYTE)szName, &dw) == ERROR_SUCCESS) + { + OutputDebugString(_T("(CLSID\?\?\?) ")); + OutputDebugString(szName); + } + } + } + else + OutputDebugString(lpszGUID); + + if (hr != S_OK) + OutputDebugString(_T(" - failed")); + OutputDebugString(_T("\n")); + CoTaskMemFree(pszGUID); + + return hr; +} +#endif // _ATL_DEBUG_INTERFACES || _ATL_DEBUG_QI + + + +// WM_FORWARDMSG - used to forward a message to another window for processing +// WPARAM - DWORD dwUserData - defined by user +// LPARAM - LPMSG pMsg - a pointer to the MSG structure +// return value - 0 if the message was not processed, nonzero if it was +#define WM_FORWARDMSG 0x037F + +}; //namespace ATL + + +#ifndef _ATL_NO_AUTOMATIC_NAMESPACE +using namespace ATL; +#endif //!_ATL_NO_AUTOMATIC_NAMESPACE + +#ifdef _ATL_ATTRIBUTES +#include +#endif + + + +namespace ATL +{ + +// All exports go here +// Pull in if building ATL DLL or not linking to ATL DLL +#ifndef _ATL_DLL + +///////////////////////////////////////////////////////////////////////////// +// statics + +static inline UINT WINAPI AtlGetDirLen(LPCOLESTR lpszPathName) throw() +{ + ATLASSERT(lpszPathName != NULL); + if(lpszPathName == NULL) + return 0; + + // always capture the complete file name including extension (if present) + LPCOLESTR lpszTemp = lpszPathName; + for (LPCOLESTR lpsz = lpszPathName; *lpsz != NULL; ) + { + LPCOLESTR lp = CharNextO(lpsz); + // remember last directory/drive separator + if (*lpsz == OLESTR('\\') || *lpsz == OLESTR('/') || *lpsz == OLESTR(':')) + lpszTemp = lp; + lpsz = lp; + } + + return UINT( lpszTemp-lpszPathName ); +} + +static inline LPTSTR AtlFindExtension(LPCTSTR psz) +{ + if (psz == NULL) + return NULL; + LPCTSTR pszRemember = NULL; + while (*psz != NULL) + { + switch(*psz) + { + case _T('\\'): + pszRemember = NULL; + break; + case _T('.'): + pszRemember = psz; + break; + default: + break; + } + psz = CharNext(psz); + } + return (LPTSTR)((pszRemember == NULL) ? psz : pszRemember); +} + + +///////////////////////////////////////////////////////////////////////////// +// TypeLib registration + +#define _ATL_MAX_PATH_PLUS_INDEX (_MAX_PATH + _ATL_TYPELIB_INDEX_LENGTH) + +ATLINLINE ATLAPI AtlLoadTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex, BSTR* pbstrPath, ITypeLib** ppTypeLib) +{ + ATLASSERT(pbstrPath != NULL && ppTypeLib != NULL); + if (pbstrPath == NULL || ppTypeLib == NULL) + return E_POINTER; + + *pbstrPath = NULL; + *ppTypeLib = NULL; + + USES_CONVERSION_EX; + ATLASSERT(hInstTypeLib != NULL); + TCHAR szModule[_ATL_MAX_PATH_PLUS_INDEX]; + + DWORD dwFLen = GetModuleFileName(hInstTypeLib, szModule, MAX_PATH); + if( dwFLen == 0 ) + return AtlHresultFromLastError(); + else if( dwFLen == MAX_PATH ) + return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); + + // get the extension pointer in case of fail + LPTSTR lpszExt = NULL; + + lpszExt = AtlFindExtension(szModule); + + if (lpszIndex != NULL) + { + LPCTSTR lpcszIndex = OLE2CT_EX(lpszIndex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); + if(lpcszIndex == NULL) + { + return E_OUTOFMEMORY; + } + DWORD nIndexLen = lstrlen(lpcszIndex); + + DWORD newLen = dwFLen + nIndexLen; + if ((newLen < dwFLen) || (newLen < nIndexLen) || (newLen >= _ATL_MAX_PATH_PLUS_INDEX)) + return E_FAIL; +#ifdef UNICODE + Checked::wcscpy_s(szModule + dwFLen, _countof(szModule) - dwFLen, lpcszIndex); +#else + Checked::strcpy_s(szModule + dwFLen, _countof(szModule) - dwFLen, lpcszIndex); +#endif + } + LPOLESTR lpszModule = T2OLE_EX(szModule, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpszModule == NULL) + return E_OUTOFMEMORY; +#endif + HRESULT hr = LoadTypeLib(lpszModule, ppTypeLib); + if (!SUCCEEDED(hr)) + { + // typelib not in module, try .tlb instead + TCHAR szExt[] = _T(".tlb"); + if ((lpszExt - szModule + sizeof(szExt)/sizeof(TCHAR)) > _MAX_PATH) + return E_FAIL; + +#ifdef UNICODE + Checked::wcscpy_s(lpszExt, _countof(szModule) - (lpszExt - szModule), szExt); +#else + Checked::strcpy_s(lpszExt, _countof(szModule) - (lpszExt - szModule), szExt); +#endif + lpszModule = T2OLE_EX(szModule, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpszModule == NULL) + return E_OUTOFMEMORY; +#endif + hr = LoadTypeLib(lpszModule, ppTypeLib); + } + if (SUCCEEDED(hr)) + { + *pbstrPath = ::SysAllocString(lpszModule); + if (*pbstrPath == NULL) + hr = E_OUTOFMEMORY; + } + return hr; +} + +ATLINLINE ATLAPI AtlUnRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex) +{ + CComBSTR bstrPath; + CComPtr pTypeLib; + HRESULT hr = AtlLoadTypeLib(hInstTypeLib, lpszIndex, &bstrPath, &pTypeLib); + if (SUCCEEDED(hr)) + { + TLIBATTR* ptla; + hr = pTypeLib->GetLibAttr(&ptla); + if (SUCCEEDED(hr)) + { + hr = UnRegisterTypeLib(ptla->guid, ptla->wMajorVerNum, ptla->wMinorVerNum, ptla->lcid, ptla->syskind); + pTypeLib->ReleaseTLibAttr(ptla); + } + } + return hr; +} + +ATLINLINE ATLAPI AtlRegisterTypeLib(HINSTANCE hInstTypeLib, LPCOLESTR lpszIndex) +{ + CComBSTR bstrPath; + CComPtr pTypeLib; + HRESULT hr = AtlLoadTypeLib(hInstTypeLib, lpszIndex, &bstrPath, &pTypeLib); + if (SUCCEEDED(hr)) + { + CComBSTR bstrHelpFile; + hr = pTypeLib->GetDocumentation(-1, NULL, NULL, NULL, &bstrHelpFile); + if (SUCCEEDED(hr) && (bstrHelpFile.m_str != NULL)) + { + OLECHAR szDir[MAX_PATH]; + Checked::wcsncpy_s(szDir, MAX_PATH, bstrPath.m_str, bstrPath.Length()); + + szDir[MAX_PATH - 1] = 0; + + // If index is specified remove it from the path + if (lpszIndex != NULL) + { + size_t nLenPath = ocslen(szDir); + size_t nLenIndex = ocslen(lpszIndex); + if ((memcmp(szDir + nLenPath - nLenIndex, lpszIndex, nLenIndex) == 0) + && (nLenPath - nLenIndex < MAX_PATH)) + szDir[nLenPath - nLenIndex] = 0; + } + UINT nDirLen = AtlGetDirLen(szDir); + if (nDirLen < MAX_PATH) + szDir[nDirLen] = 0; + + hr = ::RegisterTypeLib(pTypeLib, bstrPath, szDir); + + } + else + { + hr = ::RegisterTypeLib(pTypeLib, bstrPath, NULL); + } + } + return hr; +} + +///////////////////////////////////////////////////////////////////////////// +// Registration + +// AtlComModuleRegisterServer walks the ATL Autogenerated Object Map and registers each object in the map +// If pCLSID is not NULL then only the object referred to by pCLSID is registered (The default case) +// otherwise all the objects are registered +ATLINLINE ATLAPI AtlComModuleRegisterServer(_ATL_COM_MODULE* pComModule, BOOL bRegTypeLib, const CLSID* pCLSID) +{ + ATLASSERT(pComModule != NULL); + if (pComModule == NULL) + return E_INVALIDARG; + ATLASSERT(pComModule->m_hInstTypeLib != NULL); + + HRESULT hr = S_OK; + + for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++) + { + if (*ppEntry != NULL) + { + _ATL_OBJMAP_ENTRY* pEntry = *ppEntry; + if (pCLSID != NULL) + { + if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) + continue; + } + hr = pEntry->pfnUpdateRegistry(TRUE); + if (FAILED(hr)) + break; + hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid, + pEntry->pfnGetCategoryMap(), TRUE ); + if (FAILED(hr)) + break; + } + } + + if (SUCCEEDED(hr) && bRegTypeLib) + hr = AtlRegisterTypeLib(pComModule->m_hInstTypeLib, 0); + + return hr; +} + +// AtlComUnregisterServer walks the ATL Object Map and unregisters each object in the map +// If pCLSID is not NULL then only the object referred to by pCLSID is unregistered (The default case) +// otherwise all the objects are unregistered. +ATLINLINE ATLAPI AtlComModuleUnregisterServer(_ATL_COM_MODULE* pComModule, BOOL bUnRegTypeLib, const CLSID* pCLSID) +{ + ATLASSERT(pComModule != NULL); + if (pComModule == NULL) + return E_INVALIDARG; + + HRESULT hr = S_OK; + + for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++) + { + if (*ppEntry != NULL) + { + _ATL_OBJMAP_ENTRY* pEntry = *ppEntry; + if (pCLSID != NULL) + { + if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) + continue; + } + hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid, pEntry->pfnGetCategoryMap(), FALSE ); + if (FAILED(hr)) + break; + hr = pEntry->pfnUpdateRegistry(FALSE); //unregister + if (FAILED(hr)) + break; + } + } + if (SUCCEEDED(hr) && bUnRegTypeLib) + hr = AtlUnRegisterTypeLib(pComModule->m_hInstTypeLib, 0); + + return hr; +} + +ATLINLINE ATLAPI AtlRegisterClassCategoriesHelper( REFCLSID clsid, + const struct _ATL_CATMAP_ENTRY* pCatMap, BOOL bRegister ) +{ + CComPtr< ICatRegister > pCatRegister; + HRESULT hResult; + const struct _ATL_CATMAP_ENTRY* pEntry; + CATID catid; + + if( pCatMap == NULL ) + { + return( S_OK ); + } + + if (InlineIsEqualGUID(clsid, GUID_NULL)) + { + ATLASSERT(0 && _T("Use OBJECT_ENTRY_NON_CREATEABLE_EX macro if you want to register class categories for non creatable objects.")); + return S_OK; + } + + hResult = CoCreateInstance( CLSID_StdComponentCategoriesMgr, NULL, + CLSCTX_INPROC_SERVER, __uuidof(ICatRegister), (void**)&pCatRegister ); + if( FAILED( hResult ) ) + { + // Since not all systems have the category manager installed, we'll allow + // the registration to succeed even though we didn't register our + // categories. If you really want to register categories on a system + // without the category manager, you can either manually add the + // appropriate entries to your registry script (.rgs), or you can + // redistribute comcat.dll. + return( S_OK ); + } + + hResult = S_OK; + pEntry = pCatMap; + while( pEntry->iType != _ATL_CATMAP_ENTRY_END ) + { + catid = *pEntry->pcatid; + if( bRegister ) + { + if( pEntry->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED ) + { + hResult = pCatRegister->RegisterClassImplCategories( clsid, 1, + &catid ); + } + else + { + ATLASSERT( pEntry->iType == _ATL_CATMAP_ENTRY_REQUIRED ); + hResult = pCatRegister->RegisterClassReqCategories( clsid, 1, + &catid ); + } + if( FAILED( hResult ) ) + { + return( hResult ); + } + } + else + { + if( pEntry->iType == _ATL_CATMAP_ENTRY_IMPLEMENTED ) + { + pCatRegister->UnRegisterClassImplCategories( clsid, 1, &catid ); + } + else + { + ATLASSERT( pEntry->iType == _ATL_CATMAP_ENTRY_REQUIRED ); + pCatRegister->UnRegisterClassReqCategories( clsid, 1, &catid ); + } + } + pEntry++; + } + + // When unregistering remove "Implemented Categories" and "Required Categories" subkeys if they are empty. + if (!bRegister) + { + OLECHAR szGUID[64]; + ::StringFromGUID2(clsid, szGUID, 64); + USES_CONVERSION_EX; + TCHAR* pszGUID = OLE2T_EX(szGUID, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); + if (pszGUID != NULL) + { + TCHAR szKey[128]; +#ifdef UNICODE + Checked::wcscpy_s(szKey, _countof(szKey), _T("CLSID\\")); + Checked::wcscat_s(szKey, _countof(szKey), pszGUID); + Checked::wcscat_s(szKey, _countof(szKey), _T("\\Required Categories")); +#else + Checked::strcpy_s(szKey, _countof(szKey), _T("CLSID\\")); + Checked::strcat_s(szKey, _countof(szKey), pszGUID); + Checked::strcat_s(szKey, _countof(szKey), _T("\\Required Categories")); +#endif + + CRegKey root(HKEY_CLASSES_ROOT); + CRegKey key; + DWORD cbSubKeys = 0; + + LRESULT lRes = key.Open(root, szKey, KEY_READ); + if (lRes == ERROR_SUCCESS) + { + lRes = RegQueryInfoKey(key, NULL, NULL, NULL, &cbSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + key.Close(); + if (lRes == ERROR_SUCCESS && cbSubKeys == 0) + { + root.DeleteSubKey(szKey); + } + } + +#ifdef UNICODE + Checked::wcscpy_s(szKey, _countof(szKey), _T("CLSID\\")); + Checked::wcscat_s(szKey, _countof(szKey), pszGUID); + Checked::wcscat_s(szKey, _countof(szKey), _T("\\Implemented Categories")); +#else + Checked::strcpy_s(szKey, _countof(szKey), _T("CLSID\\")); + Checked::strcat_s(szKey, _countof(szKey), pszGUID); + Checked::strcat_s(szKey, _countof(szKey), _T("\\Implemented Categories")); +#endif + lRes = key.Open(root, szKey, KEY_READ); + if (lRes == ERROR_SUCCESS) + { + lRes = RegQueryInfoKey(key, NULL, NULL, NULL, &cbSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + key.Close(); + if (lRes == ERROR_SUCCESS && cbSubKeys == 0) + { + root.DeleteSubKey(szKey); + } + } + } + } + return( S_OK ); +} + +#endif // _ATL_DLL + +ATLINLINE ATLAPIINL +AtlWinModuleTerm(_ATL_WIN_MODULE* pWinModule, HINSTANCE hInst) +{ + if (pWinModule == NULL) + return E_INVALIDARG; + if (pWinModule->cbSize == 0) + return S_OK; + if (pWinModule->cbSize != sizeof(_ATL_WIN_MODULE)) + return E_INVALIDARG; + + for (int i = 0; i < pWinModule->m_rgWindowClassAtoms.GetSize(); i++) + UnregisterClass((LPCTSTR)pWinModule->m_rgWindowClassAtoms[i], hInst); + pWinModule->m_rgWindowClassAtoms.RemoveAll(); + pWinModule->m_csWindowCreate.Term(); + pWinModule->cbSize = 0; + return S_OK; +} + + + +///////////////////////////////////////////////////////////////////////////// +// General DLL Version Helpers + +#pragma warning(push) +#pragma warning(disable : 4191) // 'type cast' : unsafe conversion from 'FARPROC' to 'DLLGETVERSIONPROC' + +inline HRESULT AtlGetDllVersion(HINSTANCE hInstDLL, DLLVERSIONINFO* pDllVersionInfo) +{ + ATLENSURE(pDllVersionInfo != NULL); + + // We must get this function explicitly because some DLLs don't implement it. + DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC)::GetProcAddress(hInstDLL, "DllGetVersion"); + + if(pfnDllGetVersion == NULL) + { + return E_NOTIMPL; + } + + return (*pfnDllGetVersion)(pDllVersionInfo); +} + +#pragma warning(pop) + +inline HRESULT AtlGetDllVersion(LPCTSTR lpstrDllName, DLLVERSIONINFO* pDllVersionInfo) +{ + HINSTANCE hInstDLL = ::LoadLibrary(lpstrDllName); + if(hInstDLL == NULL) + { + return AtlHresultFromLastError(); + } + HRESULT hRet = AtlGetDllVersion(hInstDLL, pDllVersionInfo); + ::FreeLibrary(hInstDLL); + return hRet; +} + +// Common Control Versions: +// Win95/WinNT 4.0 maj=4 min=00 +// IE 3.x maj=4 min=70 +// IE 4.0 maj=4 min=71 +// IE 5.0 maj=5 min=80 +// Win2000 maj=5 min=81 +inline HRESULT AtlGetCommCtrlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) +{ + ATLENSURE(( pdwMajor != NULL ) && ( pdwMinor != NULL )); + + DLLVERSIONINFO dvi; + memset(&dvi, 0, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + + HRESULT hRet = AtlGetDllVersion(_T("comctl32.dll"), &dvi); + + if(SUCCEEDED(hRet)) + { + *pdwMajor = dvi.dwMajorVersion; + *pdwMinor = dvi.dwMinorVersion; + } + else if(hRet == E_NOTIMPL) + { + // If DllGetVersion is not there, then the DLL is a version + // previous to the one shipped with IE 3.x + *pdwMajor = 4; + *pdwMinor = 0; + hRet = S_OK; + } + + return hRet; +} + +// Shell Versions: +// Win95/WinNT 4.0 maj=4 min=00 +// IE 3.x, IE 4.0 without Web Integrated Desktop maj=4 min=00 +// IE 4.0 with Web Integrated Desktop maj=4 min=71 +// IE 4.01 with Web Integrated Desktop maj=4 min=72 +// Win2000 maj=5 min=00 +inline HRESULT AtlGetShellVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) +{ + ATLENSURE(( pdwMajor != NULL) && ( pdwMinor != NULL )); + + DLLVERSIONINFO dvi; + memset(&dvi, 0, sizeof(dvi)); + dvi.cbSize = sizeof(dvi); + HRESULT hRet = AtlGetDllVersion(_T("shell32.dll"), &dvi); + + if(SUCCEEDED(hRet)) + { + *pdwMajor = dvi.dwMajorVersion; + *pdwMinor = dvi.dwMinorVersion; + } + else if(hRet == E_NOTIMPL) + { + // If DllGetVersion is not there, then the DLL is a version + // previous to the one shipped with IE 4.x + *pdwMajor = 4; + *pdwMinor = 0; + hRet = S_OK; + } + + return hRet; +} + +inline ATL_DEPRECATED("AtlModuleRegisterClassObjects has been replaced by AtlComModuleRegisterClassObjects") +HRESULT AtlModuleRegisterClassObjects(_ATL_MODULE* /*pM*/, DWORD dwClsContext, DWORD dwFlags) +{ + return AtlComModuleRegisterClassObjects(&_AtlComModule, dwClsContext, dwFlags); +} + +inline ATL_DEPRECATED("AtlModuleRevokeClassObjects has been replaced by AtlComModuleRevokeClassObjects") +HRESULT AtlModuleRevokeClassObjects(_ATL_MODULE* /*pM*/) +{ + return AtlComModuleRevokeClassObjects(&_AtlComModule); +} + +inline ATL_DEPRECATED("AtlModuleGetClassObject has been replaced by AtlComModuleGetClassObject") +HRESULT AtlModuleGetClassObject(_ATL_MODULE* /*pM*/, REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ +#ifndef _ATL_OLEDB_CONFORMANCE_TESTS + ATLASSERT(ppv != NULL); +#endif + + return AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv); +} + +inline ATL_DEPRECATED("AtlModuleRegisterServer has been replaced by AtlComModuleRegisterServer") +HRESULT AtlModuleRegisterServer(_ATL_MODULE* /*pM*/, BOOL bRegTypeLib, const CLSID* pCLSID = NULL) +{ + return AtlComModuleRegisterServer(&_AtlComModule, bRegTypeLib, pCLSID); +} + +inline ATL_DEPRECATED("AtlModuleUnregisterServer has been replaced by AtlComModuleUnregisterServer") +HRESULT AtlModuleUnregisterServer(_ATL_MODULE* /*pM*/, const CLSID* pCLSID = NULL) +{ + return AtlComModuleUnregisterServer(&_AtlComModule, FALSE, pCLSID); +} + +inline ATL_DEPRECATED("AtlModuleUnregisterServerEx has been replaced by AtlComModuleUnregisterServer") +HRESULT AtlModuleUnregisterServerEx(_ATL_MODULE* /*pM*/, BOOL bUnRegTypeLib, const CLSID* pCLSID = NULL) +{ + return AtlComModuleUnregisterServer(&_AtlComModule, bUnRegTypeLib, pCLSID); +} + +inline ATL_DEPRECATED("AtlModuleUpdateRegistryFromResourceD has been replaced by AtlUpdateRegistryFromResourceD") +HRESULT AtlModuleUpdateRegistryFromResourceD(_ATL_MODULE* /*pM*/, LPCOLESTR lpszRes, + BOOL bRegister, struct _ATL_REGMAP_ENTRY* pMapEntries, IRegistrar* pReg = NULL) +{ + return AtlUpdateRegistryFromResourceD(_AtlBaseModule.GetModuleInstance(), lpszRes, bRegister, pMapEntries, pReg); +} + +inline ATL_DEPRECATED("AtlModuleRegisterTypeLib has been replaced by AtlRegisterTypeLib") +HRESULT AtlModuleRegisterTypeLib(_ATL_MODULE* /*pM*/, LPCOLESTR lpszIndex) +{ + return AtlRegisterTypeLib(_AtlComModule.m_hInstTypeLib, lpszIndex); +} + +inline ATL_DEPRECATED("AtlModuleUnRegisterTypeLib has been replaced by AtlUnRegisterTypeLib") +HRESULT AtlModuleUnRegisterTypeLib(_ATL_MODULE* /*pM*/, LPCOLESTR lpszIndex) +{ + return AtlUnRegisterTypeLib(_AtlComModule.m_hInstTypeLib, lpszIndex); +} + +inline ATL_DEPRECATED("AtlModuleLoadTypeLib has been replaced by AtlLoadTypeLib") +HRESULT AtlModuleLoadTypeLib(_ATL_MODULE* /*pM*/, LPCOLESTR lpszIndex, BSTR* pbstrPath, ITypeLib** ppTypeLib) +{ + return AtlLoadTypeLib(_AtlComModule.m_hInstTypeLib, lpszIndex, pbstrPath, ppTypeLib); +} + +inline ATL_DEPRECATED("AtlModuleInit is no longer required") +HRESULT AtlModuleInit(_ATL_MODULE* /*pM*/, _ATL_OBJMAP_ENTRY* /*p*/, HINSTANCE /*h*/) +{ + return S_OK; +} + +inline ATL_DEPRECATED("AtlModuleTerm is no longer required") +HRESULT AtlModuleTerm(_ATL_MODULE* /*pM*/) +{ + return S_OK; +} + +inline ATL_DEPRECATED("AtlModuleAddCreateWndData has been replaced by AtlWinModuleAddCreateWndData") +void AtlModuleAddCreateWndData(_ATL_MODULE* /*pM*/, _AtlCreateWndData* pData, void* pObject) +{ + AtlWinModuleAddCreateWndData(&_AtlWinModule, pData, pObject); +} + +inline ATL_DEPRECATED("AtlModuleExtractCreateWndData has been replaced by AtlWinModuleExtractCreateWndData") +void* AtlModuleExtractCreateWndData(_ATL_MODULE* /*pM*/) +{ + return AtlWinModuleExtractCreateWndData(&_AtlWinModule); +} + +#ifndef _ATL_NO_COMMODULE + +inline CRITICAL_SECTION& CComModule::get_m_csWindowCreate() throw() +{ + return _AtlWinModule.m_csWindowCreate.m_sec; +} + +inline CRITICAL_SECTION& CComModule::get_m_csObjMap() throw() +{ + return _AtlComModule.m_csObjMap.m_sec; +} + +inline CRITICAL_SECTION& CComModule::get_m_csStaticDataInit() throw() +{ + return m_csStaticDataInitAndTypeInfo.m_sec; +} + +inline _AtlCreateWndData*& CComModule::get_m_pCreateWndList() throw() +{ + return _AtlWinModule.m_pCreateWndList; +} +inline void CComModule::put_m_pCreateWndList(_AtlCreateWndData* p) throw() +{ + _AtlWinModule.m_pCreateWndList = p; +} +#ifdef _ATL_DEBUG_INTERFACES +inline UINT& CComModule::get_m_nIndexQI() throw() +{ + return _AtlDebugInterfacesModule.m_nIndexQI; +} +inline void CComModule::put_m_nIndexQI(UINT nIndex) throw() +{ + _AtlDebugInterfacesModule.m_nIndexQI = nIndex; +} +inline UINT& CComModule::get_m_nIndexBreakAt() throw() +{ + return _AtlDebugInterfacesModule.m_nIndexBreakAt; +} +inline void CComModule::put_m_nIndexBreakAt(UINT nIndex) throw() +{ + _AtlDebugInterfacesModule.m_nIndexBreakAt = nIndex; +} +inline CSimpleArray<_QIThunk*>* CComModule::get_m_paThunks() throw() +{ + return &_AtlDebugInterfacesModule.m_aThunks; +} +inline HRESULT CComModule::AddThunk(IUnknown** pp, LPCTSTR lpsz, REFIID iid) throw() +{ + return _AtlDebugInterfacesModule.AddThunk(pp, lpsz, iid); +} +inline HRESULT CComModule::AddNonAddRefThunk(IUnknown* p, LPCTSTR lpsz, IUnknown** ppThunkRet) throw() +{ + return _AtlDebugInterfacesModule.AddNonAddRefThunk(p, lpsz, ppThunkRet); +} + +inline void CComModule::DeleteNonAddRefThunk(IUnknown* pUnk) throw() +{ + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(pUnk); +} + +inline void CComModule::DeleteThunk(_QIThunk* p) throw() +{ + _AtlDebugInterfacesModule.DeleteThunk(p); +} + +inline bool CComModule::DumpLeakedThunks() throw() +{ + return _AtlDebugInterfacesModule.DumpLeakedThunks(); +} +#endif // _ATL_DEBUG_INTERFACES + +inline HRESULT CComModule::Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE /*h*/, const GUID* plibid) throw() +{ + if (plibid != NULL) + m_libid = *plibid; + + _ATL_OBJMAP_ENTRY* pEntry; + if (p != (_ATL_OBJMAP_ENTRY*)-1) + { + m_pObjMap = p; + if (m_pObjMap != NULL) + { + pEntry = m_pObjMap; + while (pEntry->pclsid != NULL) + { + pEntry->pfnObjectMain(true); //initialize class resources + pEntry++; + } + } + } + for (_ATL_OBJMAP_ENTRY** ppEntry = _AtlComModule.m_ppAutoObjMapFirst; ppEntry < _AtlComModule.m_ppAutoObjMapLast; ppEntry++) + { + if (*ppEntry != NULL) + (*ppEntry)->pfnObjectMain(true); //initialize class resources + } + return S_OK; +} + +inline void CComModule::Term() throw() +{ + _ATL_OBJMAP_ENTRY* pEntry; + if (m_pObjMap != NULL) + { + pEntry = m_pObjMap; + while (pEntry->pclsid != NULL) + { + if (pEntry->pCF != NULL) + pEntry->pCF->Release(); + pEntry->pCF = NULL; + pEntry->pfnObjectMain(false); //cleanup class resources + pEntry++; + } + } + + for (_ATL_OBJMAP_ENTRY** ppEntry = _AtlComModule.m_ppAutoObjMapFirst; ppEntry < _AtlComModule.m_ppAutoObjMapLast; ppEntry++) + { + if (*ppEntry != NULL) + (*ppEntry)->pfnObjectMain(false); //cleanup class resources + } +#ifdef _DEBUG + // Prevent false memory leak reporting. ~CAtlWinModule may be too late. + _AtlWinModule.Term(); +#endif // _DEBUG + + CAtlModuleT::Term(); +} + +inline HRESULT CComModule::GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) throw() +{ + if (ppv == NULL) + return E_POINTER; + HRESULT hr = S_OK; + _ATL_OBJMAP_ENTRY* pEntry; + if (m_pObjMap != NULL) + { + pEntry = m_pObjMap; + while (pEntry->pclsid != NULL) + { + if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid)) + { + if (pEntry->pCF == NULL) + { + CComCritSecLock lock(_AtlComModule.m_csObjMap, false); + hr = lock.Lock(); + if (FAILED(hr)) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in CComModule::GetClassObject\n")); + ATLASSERT(0); + break; + } + if (pEntry->pCF == NULL) + hr = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF); + } + if (pEntry->pCF != NULL) + hr = pEntry->pCF->QueryInterface(riid, ppv); + break; + } + pEntry++; + } + } + if (*ppv == NULL && hr == S_OK) + hr = AtlComModuleGetClassObject(&_AtlComModule, rclsid, riid, ppv); + return hr; +} + +// Register/Revoke All Class Factories with the OS (EXE only) +inline HRESULT CComModule::RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) throw() +{ + HRESULT hr = S_OK; + _ATL_OBJMAP_ENTRY* pEntry; + if (m_pObjMap != NULL) + { + pEntry = m_pObjMap; + while (pEntry->pclsid != NULL && hr == S_OK) + { + hr = pEntry->RegisterClassObject(dwClsContext, dwFlags); + pEntry++; + } + } + if (hr == S_OK) + hr = AtlComModuleRegisterClassObjects(&_AtlComModule, dwClsContext, dwFlags); + return hr; +} +inline HRESULT CComModule::RevokeClassObjects() throw() +{ + HRESULT hr = S_OK; + _ATL_OBJMAP_ENTRY* pEntry; + if (m_pObjMap != NULL) + { + pEntry = m_pObjMap; + while (pEntry->pclsid != NULL && hr == S_OK) + { + hr = pEntry->RevokeClassObject(); + pEntry++; + } + } + if (hr == S_OK) + hr = AtlComModuleRevokeClassObjects(&_AtlComModule); + return hr; +} + +// Registry support (helpers) +inline HRESULT CComModule::RegisterTypeLib() throw() +{ + return _AtlComModule.RegisterTypeLib(); +} +inline HRESULT CComModule::RegisterTypeLib(LPCTSTR lpszIndex) throw() +{ + return _AtlComModule.RegisterTypeLib(lpszIndex); +} +inline HRESULT CComModule::UnRegisterTypeLib() throw() +{ + return _AtlComModule.UnRegisterTypeLib(); +} +inline HRESULT CComModule::UnRegisterTypeLib(LPCTSTR lpszIndex) throw() +{ + return _AtlComModule.UnRegisterTypeLib(lpszIndex); +} + +inline HRESULT CComModule::RegisterServer(BOOL bRegTypeLib /*= FALSE*/, const CLSID* pCLSID /*= NULL*/) throw() +{ + HRESULT hr = S_OK; + _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap; + if (pEntry != NULL) + { + for (;pEntry->pclsid != NULL; pEntry++) + { + if (pCLSID != NULL) + { + if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) + continue; + } + hr = pEntry->pfnUpdateRegistry(TRUE); + if (FAILED(hr)) + break; + hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid, + pEntry->pfnGetCategoryMap(), TRUE ); + if (FAILED(hr)) + break; + } + } + if (SUCCEEDED(hr)) + hr = CAtlModuleT::RegisterServer(bRegTypeLib, pCLSID); + return hr; +} + +inline HRESULT CComModule::UnregisterServer(BOOL bUnRegTypeLib, const CLSID* pCLSID /*= NULL*/) throw() +{ + HRESULT hr = S_OK; + _ATL_OBJMAP_ENTRY* pEntry = m_pObjMap; + if (pEntry != NULL) + { + for (;pEntry->pclsid != NULL; pEntry++) + { + if (pCLSID != NULL) + { + if (!IsEqualGUID(*pCLSID, *pEntry->pclsid)) + continue; + } + hr = AtlRegisterClassCategoriesHelper( *pEntry->pclsid, + pEntry->pfnGetCategoryMap(), FALSE ); + if (FAILED(hr)) + break; + hr = pEntry->pfnUpdateRegistry(FALSE); //unregister + if (FAILED(hr)) + break; + } + } + if (SUCCEEDED(hr)) + hr = CAtlModuleT::UnregisterServer(bUnRegTypeLib, pCLSID); + return hr; +} + +inline HRESULT CComModule::UnregisterServer(const CLSID* pCLSID /*= NULL*/) throw() +{ + return UnregisterServer(FALSE, pCLSID); +} + +#endif // !_ATL_NO_COMMODULE + +} // namespace ATL + + +#pragma warning( pop ) + +#if !defined(_ATL_DLL) && !defined(_DEBUG) + +#include + +#endif // !_ATL_DLL && !_DEBUG + +#pragma pack(pop) +#ifdef _ATL_ALL_WARNINGS +#pragma warning( pop ) +#endif + +// +// [pfx_parse] - workaround for old PREfix/PREfast parser +// +#if (defined(_PREFIX_) || defined(_PREFAST_)) && (_MSC_VER < 1400) +#pragma warning (pop) +#endif // old PREfast parser + +///////////////////////////////////////////////////////////////////////////// + +#endif // __ATLBASE_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlbase.inl b/externals/WinDDK/7600.16385.1/inc/atl71/atlbase.inl new file mode 100644 index 00000000..f2b2ef81 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlbase.inl @@ -0,0 +1,428 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLBASE_INL__ +#define __ATLBASE_INL__ + +#pragma once + +#ifndef __ATLBASE_H__ + #error atlbase.inl requires atlbase.h to be included first +#endif +#pragma warning(push) +#pragma warning(disable:4571) //catch(...) blocks compiled with /EHs do NOT catch or re-throw Structured Exceptions +namespace ATL +{ + +///////////////////////////////////////////////////////////////////////////// +// Connection Point Helpers + +ATLINLINE ATLAPI AtlAdvise(IUnknown* pUnkCP, IUnknown* pUnk, const IID& iid, LPDWORD pdw) +{ + if(pUnkCP == NULL) + return E_INVALIDARG; + + CComPtr pCPC; + CComPtr pCP; + HRESULT hRes = pUnkCP->QueryInterface(__uuidof(IConnectionPointContainer), (void**)&pCPC); + if (SUCCEEDED(hRes)) + hRes = pCPC->FindConnectionPoint(iid, &pCP); + if (SUCCEEDED(hRes)) + hRes = pCP->Advise(pUnk, pdw); + return hRes; +} + +ATLINLINE ATLAPI AtlUnadvise(IUnknown* pUnkCP, const IID& iid, DWORD dw) +{ + if(pUnkCP == NULL) + return E_INVALIDARG; + + CComPtr pCPC; + CComPtr pCP; + HRESULT hRes = pUnkCP->QueryInterface(__uuidof(IConnectionPointContainer), (void**)&pCPC); + if (SUCCEEDED(hRes)) + hRes = pCPC->FindConnectionPoint(iid, &pCP); + if (SUCCEEDED(hRes)) + hRes = pCP->Unadvise(dw); + return hRes; +} + +///////////////////////////////////////////////////////////////////////////// +// Inproc Marshaling helpers + +//This API should be called from the same thread that called +//AtlMarshalPtrInProc +ATLINLINE ATLAPI AtlFreeMarshalStream(IStream* pStream) +{ + HRESULT hRes=S_OK; + if (pStream != NULL) + { + LARGE_INTEGER l; + l.QuadPart = 0; + pStream->Seek(l, STREAM_SEEK_SET, NULL); + hRes=CoReleaseMarshalData(pStream); + pStream->Release(); + } + return hRes; +} + +ATLINLINE ATLAPI AtlMarshalPtrInProc(IUnknown* pUnk, const IID& iid, IStream** ppStream) +{ + ATLASSERT(ppStream != NULL); + if (ppStream == NULL) + return E_POINTER; + + HRESULT hRes = CreateStreamOnHGlobal(NULL, TRUE, ppStream); + if (SUCCEEDED(hRes)) + { + hRes = CoMarshalInterface(*ppStream, iid, + pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_TABLESTRONG); + if (FAILED(hRes)) + { + (*ppStream)->Release(); + *ppStream = NULL; + } + } + return hRes; +} + +ATLINLINE ATLAPI AtlUnmarshalPtr(IStream* pStream, const IID& iid, IUnknown** ppUnk) +{ + ATLASSERT(ppUnk != NULL); + if (ppUnk == NULL) + return E_POINTER; + + *ppUnk = NULL; + HRESULT hRes = E_INVALIDARG; + if (pStream != NULL) + { + LARGE_INTEGER l; + l.QuadPart = 0; + pStream->Seek(l, STREAM_SEEK_SET, NULL); + hRes = CoUnmarshalInterface(pStream, iid, (void**)ppUnk); + } + return hRes; +} + +///////////////////////////////////////////////////////////////////////////// +// Module + +ATLINLINE ATLAPI AtlComModuleGetClassObject(_ATL_COM_MODULE* pComModule, REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + ATLASSERT(pComModule != NULL); + if (pComModule == NULL) + return E_INVALIDARG; + if (pComModule->cbSize == 0) // Module hasn't been initialized + return E_UNEXPECTED; + + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + + HRESULT hr = S_OK; + + for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast; ppEntry++) + { + if (*ppEntry != NULL) + { + _ATL_OBJMAP_ENTRY* pEntry = *ppEntry; + if ((pEntry->pfnGetClassObject != NULL) && InlineIsEqualGUID(rclsid, *pEntry->pclsid)) + { + if (pEntry->pCF == NULL) + { + CComCritSecLock lock(pComModule->m_csObjMap, false); + hr = lock.Lock(); + if (FAILED(hr)) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in AtlComModuleGetClassObject\n")); + ATLASSERT(0); + break; + } + if (pEntry->pCF == NULL) + hr = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (LPVOID*)&pEntry->pCF); + } + if (pEntry->pCF != NULL) + hr = pEntry->pCF->QueryInterface(riid, ppv); + break; + } + } + } + + if (*ppv == NULL && hr == S_OK) + hr = CLASS_E_CLASSNOTAVAILABLE; + return hr; +} + +ATLINLINE ATLAPI AtlComModuleRegisterClassObjects(_ATL_COM_MODULE* pComModule, DWORD dwClsContext, DWORD dwFlags) +{ + ATLASSERT(pComModule != NULL); + if (pComModule == NULL) + return E_INVALIDARG; + + HRESULT hr = S_FALSE; + for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast && SUCCEEDED(hr); ppEntry++) + { + if (*ppEntry != NULL) + hr = (*ppEntry)->RegisterClassObject(dwClsContext, dwFlags); + } + return hr; +} + +ATLINLINE ATLAPI AtlComModuleRevokeClassObjects(_ATL_COM_MODULE* pComModule) +{ + ATLASSERT(pComModule != NULL); + if (pComModule == NULL) + return E_INVALIDARG; + + HRESULT hr = S_OK; + for (_ATL_OBJMAP_ENTRY** ppEntry = pComModule->m_ppAutoObjMapFirst; ppEntry < pComModule->m_ppAutoObjMapLast && hr == S_OK; ppEntry++) + { + if (*ppEntry != NULL) + hr = (*ppEntry)->RevokeClassObject(); + } + return hr; +} + +ATLINLINE ATLAPI_(BOOL) AtlWaitWithMessageLoop(HANDLE hEvent) +{ + DWORD dwRet; + MSG msg; + + while(1) + { + dwRet = MsgWaitForMultipleObjects(1, &hEvent, FALSE, INFINITE, QS_ALLINPUT); + + if (dwRet == WAIT_OBJECT_0) + return TRUE; // The event was signaled + + if (dwRet != WAIT_OBJECT_0 + 1) + break; // Something else happened + + // There is one or more window message available. Dispatch them + while(PeekMessage(&msg,0,0,0,PM_NOREMOVE)) + { + // check for unicode window so we call the appropriate functions + BOOL bUnicode = ::IsWindowUnicode(msg.hwnd); + BOOL bRet; + + if (bUnicode) + bRet = ::GetMessageW(&msg, NULL, 0, 0); + else + bRet = ::GetMessageA(&msg, NULL, 0, 0); + + if (bRet > 0) + { + ::TranslateMessage(&msg); + + if (bUnicode) + ::DispatchMessageW(&msg); + else + ::DispatchMessageA(&msg); + } + + if (WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) + return TRUE; // Event is now signaled. + } + } + return FALSE; +} + +///////////////////////////////////////////////////////////////////////////// +// QI support + +ATLINLINE ATLAPI AtlInternalQueryInterface(void* pThis, + const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject) +{ + ATLASSERT(pThis != NULL); + ATLASSERT(pEntries!= NULL); + + if(pThis == NULL || pEntries == NULL) + return E_INVALIDARG ; + + // First entry in the com map should be a simple map entry + ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY); + if (ppvObject == NULL) + return E_POINTER; + *ppvObject = NULL; + if (InlineIsEqualUnknown(iid)) // use first interface + { + IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + while (pEntries->pFunc != NULL) + { + BOOL bBlind = (pEntries->piid == NULL); + if (bBlind || InlineIsEqualGUID(*(pEntries->piid), iid)) + { + if (pEntries->pFunc == _ATL_SIMPLEMAPENTRY) //offset + { + ATLASSERT(!bBlind); + IUnknown* pUnk = (IUnknown*)((INT_PTR)pThis+pEntries->dw); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + else //actual function call + { + HRESULT hRes = pEntries->pFunc(pThis, + iid, ppvObject, pEntries->dw); + if (hRes == S_OK || (!bBlind && FAILED(hRes))) + return hRes; + } + } + pEntries++; + } + return E_NOINTERFACE; +} + +ATLINLINE ATLAPI_(DWORD) AtlGetVersion(void* /* pReserved */) +{ + return _ATL_VER; +} + +///////////////////////////////////////////////////////////////////////////// +// Windowing + +ATLINLINE ATLAPI_(void) AtlWinModuleAddCreateWndData(_ATL_WIN_MODULE* pWinModule, _AtlCreateWndData* pData, void* pObject) +{ + if (pWinModule == NULL) + _AtlRaiseException((DWORD)EXCEPTION_ACCESS_VIOLATION); + + ATLASSERT(pData != NULL && pObject != NULL); + if(pData == NULL || pObject == NULL) + _AtlRaiseException((DWORD)EXCEPTION_ACCESS_VIOLATION); + + pData->m_pThis = pObject; + pData->m_dwThreadID = ::GetCurrentThreadId(); + CComCritSecLock lock(pWinModule->m_csWindowCreate, false); + if (FAILED(lock.Lock())) + { + ATLTRACE(atlTraceWindowing, 0, _T("ERROR : Unable to lock critical section in AtlWinModuleAddCreateWndData\n")); + ATLASSERT(0); + return; + } + pData->m_pNext = pWinModule->m_pCreateWndList; + pWinModule->m_pCreateWndList = pData; +} + +ATLINLINE ATLAPI_(void*) AtlWinModuleExtractCreateWndData(_ATL_WIN_MODULE* pWinModule) +{ + if (pWinModule == NULL) + return NULL; + + void* pv = NULL; + CComCritSecLock lock(pWinModule->m_csWindowCreate, false); + if (FAILED(lock.Lock())) + { + ATLTRACE(atlTraceWindowing, 0, _T("ERROR : Unable to lock critical section in AtlWinModuleExtractCreateWndData\n")); + ATLASSERT(0); + return pv; + } + _AtlCreateWndData* pEntry = pWinModule->m_pCreateWndList; + if(pEntry != NULL) + { + DWORD dwThreadID = ::GetCurrentThreadId(); + _AtlCreateWndData* pPrev = NULL; + while(pEntry != NULL) + { + if(pEntry->m_dwThreadID == dwThreadID) + { + if(pPrev == NULL) + pWinModule->m_pCreateWndList = pEntry->m_pNext; + else + pPrev->m_pNext = pEntry->m_pNext; + pv = pEntry->m_pThis; + break; + } + pPrev = pEntry; + pEntry = pEntry->m_pNext; + } + } + return pv; +} + + +ATLINLINE ATLAPI AtlWinModuleInit(_ATL_WIN_MODULE* pWinModule) +{ + if (pWinModule == NULL) + return E_INVALIDARG; + + // check only in the DLL + if (pWinModule->cbSize != sizeof(_ATL_WIN_MODULE)) + return E_INVALIDARG; + + pWinModule->m_pCreateWndList = NULL; + + HRESULT hr = pWinModule->m_csWindowCreate.Init(); + if (FAILED(hr)) + { + ATLTRACE(atlTraceWindowing, 0, _T("ERROR : Unable to initialize critical section in AtlWinModuleInit\n")); + ATLASSERT(0); + } + return hr; +} + +///////////////////////////////////////////////////////////////////////////// +// Module + +ATLINLINE ATLAPI AtlModuleAddTermFunc(_ATL_MODULE* pModule, _ATL_TERMFUNC* pFunc, DWORD_PTR dw) +{ + if (pModule == NULL) + return E_INVALIDARG; + + HRESULT hr = S_OK; + _ATL_TERMFUNC_ELEM* pNew = NULL; + ATLTRY(pNew = new _ATL_TERMFUNC_ELEM); + if (pNew == NULL) + hr = E_OUTOFMEMORY; + else + { + pNew->pFunc = pFunc; + pNew->dw = dw; + CComCritSecLock lock(pModule->m_csStaticDataInitAndTypeInfo, false); + hr = lock.Lock(); + if (SUCCEEDED(hr)) + { + pNew->pNext = pModule->m_pTermFuncs; + pModule->m_pTermFuncs = pNew; + } + else + { + delete pNew; + ATLTRACE(atlTraceGeneral, 0, _T("ERROR : Unable to lock critical section in AtlModuleAddTermFunc\n")); + ATLASSERT(0); + } + } + return hr; +} + +ATLINLINE ATLAPI_(void) AtlCallTermFunc(_ATL_MODULE* pModule) +{ + if (pModule == NULL) + _AtlRaiseException((DWORD)EXCEPTION_ACCESS_VIOLATION); + + _ATL_TERMFUNC_ELEM* pElem = pModule->m_pTermFuncs; + _ATL_TERMFUNC_ELEM* pNext = NULL; + while (pElem != NULL) + { + pElem->pFunc(pElem->dw); + pNext = pElem->pNext; + delete pElem; + pElem = pNext; + } + pModule->m_pTermFuncs = NULL; +} + +} // namespace ATL +#pragma warning(pop) +#endif // __ATLBASE_INL__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlbuild.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlbuild.h new file mode 100644 index 00000000..239c9ec1 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlbuild.h @@ -0,0 +1,21 @@ +// ATLMFC build numbers (YYMMDD) +#pragma once +#define _LIBS_BUILD 50727 +#define _LIBS_USER_BUILD "50727" + +#define _LIBS_PRODUCT_VERSION_MAJOR 8 +#define _LIBS_USER_PRODUCT_VERSION_MAJOR "8" +#define _LIBS_PRODUCT_VERSION_MINOR 0 +#define _LIBS_USER_PRODUCT_VERSION_MINOR "00" + +#define _LIBS_FILE_VERSION_MAJOR 8 +#define _LIBS_USER_FILE_VERSION_MAJOR "8" +#define _LIBS_FILE_VERSION_MINOR 0 +#define _LIBS_USER_FILE_VERSION_MINOR "00" +#define _LIBS_USER_FULL_VER "8.00.50727" + +#ifndef _LIBS_RBLD +#define _LIBS_RBLD 42 +#define _LIBS_USER_RBLD "42" +#endif + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcache.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcache.h new file mode 100644 index 00000000..238d2ddc --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcache.h @@ -0,0 +1,3246 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCACHE_H__ +#define __ATLCACHE_H__ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma warning (push) +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning(disable: 4511) // copy constructor could not be generated +#pragma warning(disable: 4512) // assignment operator could not be generated +#endif //!_ATL_NO_PRAGMA_WARNINGS + +#pragma warning(disable: 4625) // copy constructor could not be generated because a base class copy constructor is inaccessible +#pragma warning(disable: 4626) // assignment operator could not be generated because a base class assignment operator is inaccessible + +#ifndef _CPPUNWIND +#pragma warning(disable: 4702) // unreachable code +#endif +#pragma pack(push,_ATL_PACKING) +namespace ATL { + +//forward declarations; +class CStdStatClass; +class CPerfStatClass; + +typedef struct __CACHEITEM +{ +} *HCACHEITEM; + +//Implementation of a cache that stores pointers to void +extern "C" __declspec(selectany) const IID IID_IMemoryCacheClient = {0xb721b49d, 0xbb57, 0x47bc, { 0xac, 0x43, 0xa8, 0xd4, 0xc0, 0x7d, 0x18, 0x3d } }; +extern "C" __declspec(selectany) const IID IID_IMemoryCache = { 0x9c6cfb46, 0xfbde, 0x4f8b, { 0xb9, 0x44, 0x2a, 0xa0, 0x5d, 0x96, 0xeb, 0x5c } }; +extern "C" __declspec(selectany) const IID IID_IMemoryCacheControl = { 0x7634b28b, 0xd819, 0x409d, { 0xb9, 0x6e, 0xfc, 0x9f, 0x3a, 0xba, 0x32, 0x9f } }; +extern "C" __declspec(selectany) const IID IID_IMemoryCacheStats = { 0xd4b6df2d, 0x4bc0, 0x4734, { 0x8a, 0xce, 0xb7, 0x3a, 0xb, 0x97, 0x59, 0x56 } }; + +__interface ATL_NO_VTABLE __declspec(uuid("b721b49d-bb57-47bc-ac43-a8d4c07d183d")) + IMemoryCacheClient : public IUnknown +{ + // IMemoryCacheClient methods + STDMETHOD( Free )(const void *pvData); +}; + +__interface ATL_NO_VTABLE __declspec(uuid("9c6cfb46-fbde-4f8b-b944-2aa05d96eb5c")) + IMemoryCache : public IUnknown +{ + // IMemoryCache Methods + STDMETHOD(Add)(LPCSTR szKey, void *pvData, DWORD dwSize, + FILETIME *pftExpireTime, + HINSTANCE hInstClient, HCACHEITEM *phEntry, + IMemoryCacheClient *pClient); + + STDMETHOD(LookupEntry)(LPCSTR szKey, HCACHEITEM * phEntry); + STDMETHOD(GetData)(const HCACHEITEM hEntry, void **ppvData, DWORD *pdwSize) const; + STDMETHOD(ReleaseEntry)(const HCACHEITEM hEntry); + STDMETHOD(RemoveEntry)(const HCACHEITEM hEntry); + STDMETHOD(RemoveEntryByKey)(LPCSTR szKey); + + STDMETHOD(Flush)(); +}; + +__interface ATL_NO_VTABLE __declspec(uuid("7634b28b-d819-409d-b96e-fc9f3aba329f")) + IMemoryCacheControl : public IUnknown +{ + // IMemoryCacheControl Methods + STDMETHOD(SetMaxAllowedSize)(DWORD dwSize); + STDMETHOD(GetMaxAllowedSize)(DWORD *pdwSize); + STDMETHOD(SetMaxAllowedEntries)(DWORD dwSize); + STDMETHOD(GetMaxAllowedEntries)(DWORD *pdwSize); + STDMETHOD(ResetCache)(); +}; + +__interface ATL_NO_VTABLE __declspec(uuid("d4b6df2d-4bc0-4734-8ace-b73a0b975956")) + IMemoryCacheStats : public IUnknown +{ + // IMemoryCacheStats Methods + STDMETHOD(ClearStats)(); + STDMETHOD(GetHitCount)(DWORD *pdwSize); + STDMETHOD(GetMissCount)(DWORD *pdwSize); + STDMETHOD(GetCurrentAllocSize)(DWORD *pdwSize); + STDMETHOD(GetMaxAllocSize)(DWORD *pdwSize); + STDMETHOD(GetCurrentEntryCount)(DWORD *pdwSize); + STDMETHOD(GetMaxEntryCount)(DWORD *pdwSize); + +}; + +struct DLL_CACHE_ENTRY +{ + HINSTANCE hInstDll; + DWORD dwRefs; + BOOL bAlive; + CHAR szDllName[MAX_PATH]; +}; + +inline bool operator==(const DLL_CACHE_ENTRY& entry1, const DLL_CACHE_ENTRY& entry2) +{ + return (entry1.hInstDll == entry2.hInstDll); +} + +// +// IDllCache +// An interface that is used to load and unload Dlls. +// +__interface ATL_NO_VTABLE __declspec(uuid("A12478AB-D261-42f9-B525-7589143C1C97")) + IDllCache : public IUnknown +{ + // IDllCache methods + virtual HINSTANCE Load(LPCSTR szFileName, void *pPeerInfo); + virtual BOOL Free(HINSTANCE hInstance); + virtual BOOL AddRefModule(HINSTANCE hInstance); + virtual BOOL ReleaseModule(HINSTANCE hInstance); + virtual HRESULT GetEntries(DWORD dwCount, DLL_CACHE_ENTRY *pEntries, DWORD *pdwCopied); + virtual HRESULT Flush(); +}; + +#ifndef ATL_CACHE_KEY_LENGTH +#define ATL_CACHE_KEY_LENGTH 128 +#endif + +typedef CFixedStringT CFixedStringKey; + +struct CFlusherCacheData +{ + CFlusherCacheData *pNext; + CFlusherCacheData *pPrev; + DWORD dwAccessed; + + CFlusherCacheData() + { + pNext = NULL; + pPrev = NULL; + dwAccessed = 0; + } +}; + +// No flusher -- only expired entries will be removed from the cache +// Also gives the skeleton for all of the flushers +class CNoFlusher +{ +public: + void Add(CFlusherCacheData * /*pItem*/) { } + void Remove(CFlusherCacheData * /*pItem*/) { } + void Access(CFlusherCacheData * /*pItem*/) { } + CFlusherCacheData * GetStart() const { return NULL; } + CFlusherCacheData * GetNext(CFlusherCacheData * /*pCur*/) const { return NULL; } + void Release(CFlusherCacheData * /*pItem*/){ } +}; + +// Old flusher -- oldest items are flushed first +class COldFlusher +{ +public: + CFlusherCacheData * pHead; + CFlusherCacheData * pTail; + + COldFlusher() : pHead(NULL), pTail(NULL) + { + } + + // Add it to the tail of the list + void Add(CFlusherCacheData * pItem) + { + ATLENSURE(pItem); + + pItem->pNext = NULL; + pItem->pPrev = pTail; + if (pHead) + { + pTail->pNext = pItem; + pTail = pItem; + } + else + { + pHead = pItem; + pTail = pItem; + } + } + + void Remove(CFlusherCacheData * pItem) + { + ATLENSURE(pItem); + + CFlusherCacheData * pPrev = pItem->pPrev; + CFlusherCacheData * pNext = pItem->pNext; + + if (pPrev) + pPrev->pNext = pNext; + else + pHead = pNext; + + if (pNext) + pNext->pPrev = pPrev; + else + pTail = pPrev; + + } + + void Access(CFlusherCacheData * /*pItem*/) + { + } + + void Release(CFlusherCacheData * /*pItem*/) + { + } + + CFlusherCacheData * GetStart() const + { + return pHead; + } + + CFlusherCacheData * GetNext(CFlusherCacheData * pCur) const + { + if (pCur != NULL) + return pCur->pNext; + else + return NULL; + } +}; + +// Least recently used flusher -- the item that was accessed the longest time ago is flushed +class CLRUFlusher : public COldFlusher +{ +public: + // Move it to the tail of the list + void Access(CFlusherCacheData * pItem) + { + ATLASSERT(pItem); + + Remove(pItem); + Add(pItem); + } +}; + +// Least often used flusher +class CLOUFlusher : public COldFlusher +{ +public: + // Adds to the tail of the list + void Add(CFlusherCacheData * pItem) + { + ATLENSURE(pItem); + pItem->dwAccessed = 1; + COldFlusher::Add(pItem); + } + + void Access(CFlusherCacheData * pItem) + { + ATLENSURE(pItem); + pItem->dwAccessed++; + + CFlusherCacheData * pMark = static_cast(pItem->pPrev); + if (!pMark) // The item is already at the head + return; + + if (pMark->dwAccessed >= pItem->dwAccessed) // The element before it has + return; // been accessed more times + + Remove(pItem); + + while (pMark && (pMark->dwAccessed < pItem->dwAccessed)) + pMark = static_cast(pMark->pPrev); + + // pMark points to the first element that has been accessed more times, + // so add pItem after pMark + if (pMark) + { + CFlusherCacheData *pNext = static_cast(pMark->pNext); + pMark->pNext = pItem; + pItem->pPrev = pMark; + + pItem->pNext = pNext; + pNext->pPrev = pItem; + } + else // Ran out of items -- put it on the head + { + pItem->pNext = pHead; + pItem->pPrev = NULL; + if (pHead) + pHead->pPrev = pItem; + else // the list was empty + pTail = pItem; + pHead = pItem; + } + } + + // We start at the tail and move forward for this flusher + CFlusherCacheData * GetStart() const + { + return pTail; + } + + CFlusherCacheData * GetNext(CFlusherCacheData * pCur) const + { + if (pCur != NULL) + return static_cast(pCur->pPrev); + else + return NULL; + } +}; + +template +class COrFlushers +{ + CFirst m_First; + CSecond m_Second; + BOOL m_bWhich; +public: + COrFlushers() + { + m_bWhich = FALSE; + } + + BOOL Switch() + { + m_bWhich = !m_bWhich; + return m_bWhich; + } + + void Add(CFlusherCacheData * pItem) + { + ATLASSERT(pItem); + m_First.Add(pItem); + m_Second.Add(pItem); + } + + void Remove(CFlusherCacheData * pItem) + { + ATLASSERT(pItem); + m_First.Remove(pItem); + m_Second.Remove(pItem); + } + + void Access(CFlusherCacheData * pItem) + { + ATLASSERT(pItem); + m_First.Access(pItem); + m_Second.Access(pItem); + } + void Release(CFlusherCacheData * pItem) + { + ATLASSERT(pItem); + m_First.Release(pItem); + m_Second.Release(pItem); + } + + CFlusherCacheData * GetStart() const + { + if (m_bWhich) + return m_First.GetStart(); + else + return m_Second.GetStart(); + } + + CFlusherCacheData * GetNext(CFlusherCacheData * pCur) const + { + if (m_bWhich) + return m_First.GetNext(pCur); + else + return m_Second.GetNext(pCur); + } +}; + +struct CCullerCacheData +{ + CCullerCacheData() + { + pNext = NULL; + pPrev = NULL; + nLifespan = 0; + } + CCullerCacheData *pNext; + CCullerCacheData *pPrev; + ULONGLONG nLifespan; + CFileTime cftExpireTime; +}; + +class CNoExpireCuller +{ +public: + void Add(CCullerCacheData * /*pItem*/) { } + void Commit(CCullerCacheData * /*pItem*/) { } + void Access(CCullerCacheData * /*pItem*/) { } + void Remove(CCullerCacheData * /*pItem*/) { } + void Start() { } + BOOL IsExpired(CCullerCacheData * /*pItem*/) { return FALSE; } + CCullerCacheData * GetExpired() { return NULL; } + void Release(CCullerCacheData * /*pItem*/){} + +}; + +class CExpireCuller +{ +public: + CFileTime m_cftCurrent; + CCullerCacheData *pHead; + CCullerCacheData *pTail; + + CExpireCuller() + { + pHead = NULL; + pTail = NULL; + } + + // Element is being added -- perform necessary initialization + void Add(CCullerCacheData * pItem) + { + (pItem); + ATLASSERT(pItem); + } + + // Expiration data has been set -- add to main list + // Head is the first item to expire + // a FILETIME of 0 indicates that the item should never expire + void Commit(CCullerCacheData * pItem) + { + ATLENSURE(pItem); + if (!pHead) + { + pHead = pItem; + pTail = pItem; + pItem->pNext = NULL; + pItem->pPrev = NULL; + return; + } + + if (CFileTime(pItem->cftExpireTime) == 0) + { + pTail->pNext = pItem; + pItem->pPrev = pTail; + pItem->pNext = NULL; + pTail = pItem; + return; + } + + CCullerCacheData * pMark = pHead; + while (pMark && (pMark->cftExpireTime < pItem->cftExpireTime)) + pMark = pMark->pNext; + + if (pMark) // An entry was found that expires after the added entry + { + CCullerCacheData *pPrev = pMark->pPrev; + if (pPrev) + pPrev->pNext = pItem; + else + pHead = pItem; + + pItem->pNext = pMark; + pItem->pPrev = pPrev; + pMark->pPrev = pItem; + } + else // Ran out of items -- put it on the tail + { + if (pTail) + pTail->pNext = pItem; + pItem->pPrev = pTail; + pItem->pNext = NULL; + pTail = pItem; + } + } + + void Access(CCullerCacheData * /*pItem*/) + { + } + + void Release(CCullerCacheData * /*pItem*/) + { + } + + void Remove(CCullerCacheData * pItem) + { + ATLENSURE(pItem); + CCullerCacheData *pPrev = pItem->pPrev; + CCullerCacheData *pNext = pItem->pNext; + + if (pPrev) + pPrev->pNext = pNext; + else + pHead = pNext; + + if (pNext) + pNext->pPrev = pPrev; + else + pTail = pPrev; + + } + + // About to start culling + void Start() + { + m_cftCurrent = CFileTime::GetCurrentTime(); + } + + BOOL IsExpired(CCullerCacheData *pItem) + { + if ((pItem->cftExpireTime != 0) && + m_cftCurrent > pItem->cftExpireTime) + return TRUE; + + return FALSE; + } + + // Get the next expired entry + CCullerCacheData * GetExpired() + { + if (!pHead) + return NULL; + if (IsExpired(pHead)) + return pHead; + + return NULL; + } +}; + +class CLifetimeCuller : public CExpireCuller +{ +public: + void Add(CCullerCacheData * pItem) + { + ATLENSURE(pItem); + pItem->nLifespan = 0; + CExpireCuller::Add(pItem); + } + + void Commit(CCullerCacheData * pItem) + { + ATLENSURE(pItem); + if (pItem->nLifespan == 0) + pItem->cftExpireTime = 0; + else + pItem->cftExpireTime = CFileTime(CFileTime::GetCurrentTime().GetTime() + pItem->nLifespan); + CExpireCuller::Commit(pItem); + } + + void Access(CCullerCacheData * pItem) + { + ATLASSERT(pItem); + CExpireCuller::Remove(pItem); + Commit(pItem); + } + + CCullerCacheData * GetExpired() + { + return static_cast(CExpireCuller::GetExpired()); + } +}; + +template <__int64 ftLifespan> +class CFixedLifetimeCuller : public CExpireCuller +{ +public: + void Commit(CCullerCacheData * pItem) + { + ATLASSERT(pItem); + __int64 nLifeSpan = ftLifespan; + if (nLifeSpan == 0) + pItem->cftExpireTime = 0; + else + pItem->cftExpireTime = CFileTime::GetCurrentTime() + CFileTimeSpan(ftLifespan); + + CExpireCuller::Commit(pItem); + } + + void Access(CCullerCacheData * pItem) + { + ATLASSERT(pItem); + CExpireCuller::Remove(pItem); + Commit(pItem); + } + + CCullerCacheData * GetExpired() + { + return static_cast(CExpireCuller::GetExpired()); + } +}; + + +template +class COrCullers +{ + CFirst m_First; + CSecond m_Second; +public: + void Add(CCullerCacheData * pItem) + { + m_First.Add(pItem); + m_Second.Add(pItem); + } + + void Access(CCullerCacheData * pItem) + { + m_First.Access(pItem); + m_Second.Access(pItem); + } + + void Remove(CCullerCacheData * pItem) + { + m_First.Remove(pItem); + m_Second.Remove(pItem); + } + + void Start() + { + m_First.Start(); + m_Second.Start(); + } + + void Release(CCullerCacheData *pItem) + { + m_First.Release(pItem); + m_Second.Release(pItem); + } + + void Commit(CCullerCacheData * pItem) + { + m_First.Commit(pItem); + m_Second.Commit(pItem); + } + CCullerCacheData * GetExpired() + { + CCullerCacheData *pItem = m_First.GetExpired(); + if (!pItem) + pItem = m_Second.GetExpired(); + + return pItem; + } + + BOOL IsExpired(CCullerCacheData * pItem) + { + return (m_First.IsExpired(pItem) || m_Second.IsExpired(pItem)); + } +}; + +// +//CMemoryCacheBase +// Description: +// This class provides the implementation of a generic cache that stores +// elements in memory. CMemoryCacheBase uses the CCacheDataBase generic +// cache element structure to hold items in the cache. The cache is +// implemented using the CAtlMap map class. CMemoryCache uses a wide +// character string as it's Key type to identify entries. Entries must +// have unique key values. If you try to add an entry with a key that +// is exactly the same as an existing key, the existing entry will be +// overwritten. +// +// Template Parameters: +// T: The class that inherits from this class. This class must implement +// void OnDestroyEntry(NodeType *pEntry); +// DataType: Specifies the type of the element to be stored in the memory +// cache such as CString or void* +// NodeInfo: Specifies any additional data that should be stored in each item +// in the cache +// keyType, keyTrait : specifies the key type and traits (see CAtlMap) +// Flusher : the class responsible for determining which data should be flushed +// when the cache is at a configuration limit +// Culler : the class responsible for determining which data should be removed +// from the cache due to expiration +// SyncClass:Specifies the class that will be used for thread synchronization +// when accessing the cache. The class interface for SyncClass must +// be identical to that of CComCriticalSection (see atlbase.h) +// StatClass: Class used to contain statistics about this cache. +template , + class Flusher=COldFlusher, + class Culler=CExpireCuller, + class SyncClass=CComCriticalSection, + class StatClass=CStdStatClass > + class CMemoryCacheBase +{ +protected: + typedef keyType keytype; + struct NodeType : public __CACHEITEM, + public NodeInfo, + public CFlusherCacheData, + public CCullerCacheData + { + NodeType() + { + pos = NULL; + dwSize = 0; + dwRef = 0; + } + + DataType Data; + POSITION pos; + DWORD dwSize; + DWORD dwRef; + }; + + typedef CAtlMap mapType; + SyncClass m_syncObj; + StatClass m_statObj; + Flusher m_flusher; + Culler m_culler; + + //memory cache configuration parameters + DWORD m_dwMaxAllocationSize; + DWORD m_dwMaxEntries; + + BOOL m_bInitialized; +public: + + mapType m_hashTable; + CMemoryCacheBase() : + m_dwMaxAllocationSize(0xFFFFFFFF), + m_dwMaxEntries(0xFFFFFFFF), + m_bInitialized(FALSE) + { + + } + + //Initializes the cache and the cache synchronization object + //Also the performance monitoring + HRESULT Initialize() + { + if (m_bInitialized) + return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED); + HRESULT hr; + hr = m_syncObj.Init(); + + if (hr == S_OK) + hr = m_statObj.Initialize(); + + m_bInitialized = TRUE; + + return hr; + } + + //removes all entries whether or not they are initialized. + HRESULT Uninitialize() + { + if (!m_bInitialized) + return S_OK; + + //clear out the hash table + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + return hr; + + RemoveAllEntries(); + m_statObj.Uninitialize(); + + m_syncObj.Unlock(); + m_syncObj.Term(); + + m_bInitialized = FALSE; + + return S_OK; + } + + //Adds an entry to the cache. + //Also, adds an initial reference on the entry if phEntry is not NULL + HRESULT AddEntry( + const keyType &Key, //key for entry + const DataType &data, //See the DataType template parameter + DWORD dwSize, //Size of memory to be stored in the cache + HCACHEITEM *phEntry = NULL //out pointer that will contain a handle to the new + //cache entry on success. + ) + { + _ATLTRY + { + ATLASSUME(m_bInitialized); + + CAutoPtr spEntry(new NodeType); + + if (!spEntry) + return E_OUTOFMEMORY; + + NodeType *pEntry = spEntry; + + //fill entry + if (phEntry) + { + *phEntry = static_cast(pEntry); + pEntry->dwRef++; + } + pEntry->Data = data; + pEntry->dwSize = dwSize; + + CComCritSecLock lock(m_syncObj, false); + + HRESULT hr = lock.Lock(); + if (FAILED(hr)) + { + return hr; + } + + POSITION pos = (POSITION)m_hashTable.Lookup(Key); + + if (pos != NULL) + { + RemoveAt(pos, FALSE); + m_hashTable.GetValueAt(pos) = pEntry; + } + else + { + pos = m_hashTable.SetAt(Key, pEntry); + } + spEntry.Detach(); + + pEntry->pos = pos; + m_statObj.AddElement(dwSize); + m_flusher.Add(pEntry); + m_culler.Add(pEntry); + + lock.Unlock(); + + if (!phEntry) + return CommitEntry(static_cast(pEntry)); + + return S_OK; + } + _ATLCATCHALL() + { + return E_FAIL; + } + } + + // Commits the entry to the cache + HRESULT CommitEntry(const HCACHEITEM hEntry) + { + ATLASSUME(m_bInitialized); + if (!hEntry || hEntry == INVALID_HANDLE_VALUE) + return E_INVALIDARG; + + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + { + return hr; + } + + NodeType *pEntry = static_cast(hEntry); + m_culler.Commit(pEntry); + m_syncObj.Unlock(); + return S_OK; + } + + // Looks up an entry and returns a handle to it, + // also updates access count and reference count + HRESULT LookupEntry(const keyType &Key, HCACHEITEM * phEntry) + { + ATLASSUME(m_bInitialized); + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + { + return hr; + } + + hr = E_FAIL; + + POSITION pos = (POSITION)m_hashTable.Lookup(Key); + if (pos != NULL) + { + NodeType * pEntry = m_hashTable.GetValueAt(pos); + m_flusher.Access(pEntry); + m_culler.Access(pEntry); + if (phEntry) + { + pEntry->dwRef++; + *phEntry = static_cast(pEntry); + } + + m_statObj.Hit(); + + hr = S_OK; + } + else + { + *phEntry = NULL; + m_statObj.Miss(); + } + m_syncObj.Unlock(); + + return hr; + } + + // Gets the data based on the handle. Is thread-safe as long as there is a + // reference on the data + HRESULT GetEntryData(const HCACHEITEM hEntry, DataType *pData, DWORD *pdwSize) const + { + ATLASSUME(m_bInitialized); + ATLASSERT(pData != NULL || pdwSize != NULL); // At least one should not be NULL + + if (!hEntry || hEntry == INVALID_HANDLE_VALUE) + return E_INVALIDARG; + + NodeType * pEntry = static_cast(hEntry); + if (pData) + *pData = pEntry->Data; + if (pdwSize) + *pdwSize = pEntry->dwSize; + + return S_OK; + } + + // Unreferences the entry based on the handle + DWORD ReleaseEntry(const HCACHEITEM hEntry) + { + ATLASSUME(m_bInitialized); + if (!hEntry || hEntry == INVALID_HANDLE_VALUE) + return (DWORD)-1; + + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + return (DWORD)-1; + + NodeType * pEntry = static_cast(hEntry); + m_flusher.Release(pEntry); + m_culler.Release(pEntry); + ATLASSERT(pEntry->dwRef > 0); + + DWORD dwRef = --pEntry->dwRef; + if ((pEntry->pos == NULL) && (pEntry->dwRef == 0)) + InternalRemoveEntry(pEntry); + + m_syncObj.Unlock(); + + return dwRef; + } + + // Increments the entry's reference count + DWORD AddRefEntry(const HCACHEITEM hEntry) + { + ATLASSUME(m_bInitialized); + if (!hEntry || hEntry == INVALID_HANDLE_VALUE) + return (DWORD)-1; + + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + return (DWORD)-1; + + NodeType * pEntry = static_cast(hEntry); + m_flusher.Access(pEntry); + m_culler.Access(pEntry); + DWORD dwRef = ++pEntry->dwRef; + m_syncObj.Unlock(); + + return dwRef; + } + + // Removes an entry from the cache regardless of whether or + // not it has expired. If there are references, it detaches + // the entry so that future lookups will fail, and when + // the ref count drops to zero, it will be deleted + HRESULT RemoveEntryByKey(const keyType &Key) + { + ATLASSUME(m_bInitialized); + HCACHEITEM hEntry; + HRESULT hr = LookupEntry(Key, &hEntry); + if (hr == S_OK) + hr = RemoveEntry(hEntry); + + return hr; + } + + // Removes the element from the cache. If there are still + // references, then the entry is detached. + HRESULT RemoveEntry(const HCACHEITEM hEntry) + { + ATLASSUME(m_bInitialized); + if (!hEntry || hEntry == INVALID_HANDLE_VALUE) + return E_INVALIDARG; + + _ATLTRY + { + CComCritSecLock lock(m_syncObj, false); + + HRESULT hr = lock.Lock(); + if (FAILED(hr)) + return hr; + + NodeType * pEntry = static_cast(hEntry); + m_flusher.Release(pEntry); + m_culler.Release(pEntry); + ATLASSERT(pEntry->dwRef > 0); + pEntry->dwRef--; + if (pEntry->pos) + RemoveAt(pEntry->pos, TRUE); + else if ((long)pEntry->dwRef == 0) + InternalRemoveEntry(pEntry); + lock.Unlock(); + } + _ATLCATCHALL() + { + return E_OUTOFMEMORY; + } + + return S_OK; + } + + // CullEntries removes all expired items + HRESULT CullEntries() + { + ATLASSUME(m_bInitialized); + + _ATLTRY + { + CComCritSecLock lock(m_syncObj, false); + HRESULT hr = lock.Lock(); + if (FAILED(hr)) + return hr; + + m_culler.Start(); + + while (NodeType *pNode = static_cast(m_culler.GetExpired())) + RemoveAt(pNode->pos, TRUE); + + lock.Unlock(); + } + _ATLCATCHALL() + { + return E_OUTOFMEMORY; + } + + return S_OK; + } + + // FlushEntries reduces the cache to meet the configuration requirements + HRESULT FlushEntries() + { + ATLASSUME(m_bInitialized); + HRESULT hr = CullEntries(); + if (FAILED(hr)) + return hr; + + _ATLTRY + { + CComCritSecLock lock(m_syncObj, false); + hr = lock.Lock(); + if (FAILED(hr)) + return hr; + + NodeType * pNode = static_cast(m_flusher.GetStart()); + + while (pNode && + (((m_statObj.GetCurrentEntryCount() > m_dwMaxEntries)) || + ((m_statObj.GetCurrentAllocSize() > m_dwMaxAllocationSize)))) + { + NodeType *pNext = static_cast(m_flusher.GetNext(pNode)); + + if (pNode->dwRef == 0) + RemoveAt(pNode->pos, TRUE); + + pNode = pNext; + } + lock.Unlock(); + } + _ATLCATCHALL() + { + return E_OUTOFMEMORY; + } + + return S_OK; + } + + HRESULT STDMETHODCALLTYPE SetMaxAllowedSize(DWORD dwSize) + { + m_dwMaxAllocationSize = dwSize; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxAllowedSize(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_dwMaxAllocationSize; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE SetMaxAllowedEntries(DWORD dwSize) + { + m_dwMaxEntries = dwSize; + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxAllowedEntries(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_dwMaxEntries; + return S_OK; + } + + + HRESULT ResetCache() + { + ATLASSUME(m_bInitialized); + HRESULT hr = E_UNEXPECTED; + if (SUCCEEDED(ClearStats())) + hr = RemoveAllEntries(); + return hr; + } + + HRESULT ClearStats() + { + m_statObj.ResetCounters(); + return S_OK; + } + + HRESULT RemoveAllEntries() + { + ATLASSUME(m_bInitialized); + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + return hr; + + m_hashTable.DisableAutoRehash(); + POSITION pos = m_hashTable.GetStartPosition(); + POSITION oldpos; + while (pos != NULL) + { + oldpos = pos; + m_hashTable.GetNext(pos); + RemoveAt(oldpos, TRUE); + } + m_hashTable.EnableAutoRehash(); + m_syncObj.Unlock(); + + return S_OK; + } + +protected: + + // Checks to see if the cache can accommodate any new entries within + // its allocation and entry count limits. + bool CanAddEntry(DWORD dwSizeToAdd) + { + return CheckAlloc(dwSizeToAdd) && CheckEntryCount(1); + } + + // Checks to see if the cache can accommodate dwSizeToAdd additional + // allocation within its allocation limit. + bool CheckAlloc(DWORD dwSizeToAdd) + { + if (m_dwMaxAllocationSize == 0xFFFFFFFF) + return true; //max allocation size setting hasn't been set + DWORD dwNew = m_statObj.GetCurrentAllocSize() + dwSizeToAdd; + return dwNew < m_dwMaxAllocationSize; + } + + + // Checks to see if the cache can accommodate dwNumEntriesToAdd + // additional entries within its limits. + bool CheckEntryCount(DWORD dwNumEntriesToAdd) + { + if (m_dwMaxEntries == 0xFFFFFFFF) + return true; //max entry size hasn't been set + DWORD dwNew = m_statObj.GetCurrentEntryCount() + dwNumEntriesToAdd; + return dwNew < m_dwMaxEntries; + + } + +protected: + // Takes the element at pos in the hash table and removes it from + // the cache. If there are no references, then the entry is + // deleted, otherwise it is deleted by ReleaseEntry when the + // refcount goes to zero. + HRESULT RemoveAt(POSITION pos, BOOL bDelete) + { + HRESULT hr = S_OK; + ATLASSERT(pos != NULL); + NodeType * pEntry = m_hashTable.GetValueAt(pos); + m_flusher.Remove(pEntry); + m_culler.Remove(pEntry); + if (bDelete) + m_hashTable.RemoveAtPos(pos); + + if ((long)pEntry->dwRef == 0) + hr = InternalRemoveEntry(pEntry); + else + pEntry->pos = NULL; + + return S_OK; + } + + // Does the actual destruction of the node. Deletes the + // NodeType struct and calls the inherited class's + // OnDestroyEntry function, where other necessary destruction + // can take place. Also updates the cache statistics. + // Inherited classes should call RemoveAt unless the element's + // refcount is zero and it has been removed from the + // culler and flusher lists. + HRESULT InternalRemoveEntry(NodeType * pEntry) + { + ATLENSURE(pEntry != NULL); + + T* pT = static_cast(this); + + ATLASSERT((long)pEntry->dwRef == 0); + + pT->OnDestroyEntry(pEntry); + + m_statObj.ReleaseElement(pEntry->dwSize); + + delete pEntry; + + return S_OK; + } +}; // CMemoryCacheBase + +class CCacheDataBase +{ +}; + +struct CCacheDataEx : public CCacheDataBase +{ + CCacheDataEx() + { + hInstance = NULL; + pClient = NULL; + } + + HINSTANCE hInstance; + IMemoryCacheClient * pClient; +}; + + +template , + class SyncClass=CComCriticalSection, + class CullClass=CExpireCuller > +class CMemoryCache: + public CMemoryCacheBase, DataType, CCacheDataEx, + keyType, KeyTrait, FlushClass, CullClass, SyncClass, StatClass> +{ +protected: + CComPtr m_spServiceProv; + CComPtr m_spDllCache; + typedef CMemoryCacheBase, DataType, CCacheDataEx, + keyType, KeyTrait, FlushClass, CullClass, SyncClass, StatClass> baseClass; +public: + virtual ~CMemoryCache() + { + } + + HRESULT Initialize(IServiceProvider * pProvider) + { + baseClass::Initialize(); + m_spServiceProv = pProvider; + if (pProvider) + return m_spServiceProv->QueryService(__uuidof(IDllCache), __uuidof(IDllCache), (void**)&m_spDllCache); + else + return S_OK; + } + + HRESULT AddEntry( + const keyType &Key, + const DataType &data, + DWORD dwSize, + FILETIME * pftExpireTime = NULL, + HINSTANCE hInstance = NULL, + IMemoryCacheClient * pClient = NULL, + HCACHEITEM *phEntry = NULL + ) + { + _ATLTRY + { + HRESULT hr; + NodeType * pEntry = NULL; + hr = baseClass::AddEntry(Key, data, dwSize, (HCACHEITEM *)&pEntry); + if (hr != S_OK) + return hr; + + pEntry->hInstance = hInstance; + pEntry->pClient = pClient; + if (pftExpireTime) + pEntry->cftExpireTime = *pftExpireTime; + + if (hInstance && m_spDllCache) + m_spDllCache->AddRefModule(hInstance); + + baseClass::CommitEntry(static_cast(pEntry)); + + if (phEntry) + *phEntry = static_cast(pEntry); + else + baseClass::ReleaseEntry(static_cast(pEntry)); + + return S_OK; + } + _ATLCATCHALL() + { + return E_FAIL; + } + } + + virtual void OnDestroyEntry(const NodeType * pEntry) + { + ATLASSERT(pEntry); + if (!pEntry) + return; + + if (pEntry->pClient) + pEntry->pClient->Free((void *)&pEntry->Data); + if (pEntry->hInstance && m_spDllCache) + m_spDllCache->ReleaseModule(pEntry->hInstance); + } +}; // CMemoryCache + +// CStdStatData - contains the data that CStdStatClass keeps track of +#define ATL_PERF_CACHE_OBJECT 100 + +struct CPerfStatObject : public CPerfObject +{ + DECLARE_PERF_CATEGORY(CPerfStatObject, ATL_PERF_CACHE_OBJECT, IDS_PERFMON_CACHE, IDS_PERFMON_CACHE_HELP, -1); + + BEGIN_COUNTER_MAP(CPerfStatObject) + DEFINE_COUNTER(m_nHitCount, IDS_PERFMON_HITCOUNT, IDS_PERFMON_HITCOUNT_HELP, PERF_COUNTER_RAWCOUNT, -1) + DEFINE_COUNTER(m_nMissCount, IDS_PERFMON_MISSCOUNT, IDS_PERFMON_MISSCOUNT_HELP, PERF_COUNTER_RAWCOUNT, -1) + DEFINE_COUNTER(m_nCurrentAllocations, IDS_PERFMON_CURRENTALLOCATIONS, IDS_PERFMON_CURRENTALLOCATIONS_HELP, PERF_COUNTER_RAWCOUNT, -3) + DEFINE_COUNTER(m_nMaxAllocations, IDS_PERFMON_MAXALLOCATIONS, IDS_PERFMON_MAXALLOCATIONS_HELP, PERF_COUNTER_RAWCOUNT, -3) + DEFINE_COUNTER(m_nCurrentEntries, IDS_PERFMON_CURRENTENTRIES, IDS_PERFMON_CURRENTENTRIES_HELP, PERF_COUNTER_RAWCOUNT, -1) + DEFINE_COUNTER(m_nMaxEntries, IDS_PERFMON_MAXENTRIES, IDS_PERFMON_MAXENTRIES_HELP, PERF_COUNTER_RAWCOUNT, -1) + END_COUNTER_MAP() + + long m_nHitCount; + long m_nMissCount; + long m_nCurrentAllocations; + long m_nMaxAllocations; + long m_nCurrentEntries; + long m_nMaxEntries; +}; + +// CCachePerfMon - the interface to CPerfMon, with associated definitions +class CCachePerfMon : public CPerfMon +{ +public: + BEGIN_PERF_MAP(_T("ATL Server:Cache")) + CHAIN_PERF_CATEGORY(CPerfStatObject) + END_PERF_MAP() +}; + +// +//CStdStatClass +// Description +// This class provides the implementation of a standard cache statistics accounting class +class CStdStatClass +{ +protected: + CPerfStatObject* m_pStats; + CPerfStatObject m_stats; + +public: + + CStdStatClass() + { + m_pStats = &m_stats; + } + + // This function is not thread safe by design + HRESULT Initialize(CPerfStatObject* pStats = NULL) + { + if (pStats) + m_pStats = pStats; + else + m_pStats = &m_stats; + + ResetCounters(); + return S_OK; + } + + // This function is not thread safe by design + HRESULT Uninitialize() + { + m_pStats = &m_stats; + return S_OK; + } + + void Hit() + { + InterlockedIncrement(&m_pStats->m_nHitCount); + } + + void Miss() + { + InterlockedIncrement(&m_pStats->m_nMissCount); + } + + void AddElement(DWORD dwBytes) + { + DWORD nCurrentEntries = InterlockedIncrement(&m_pStats->m_nCurrentEntries); + AtlInterlockedUpdateMax(nCurrentEntries, &m_pStats->m_nMaxEntries); + + DWORD nCurrentAllocations = dwBytes + InterlockedExchangeAdd(&m_pStats->m_nCurrentAllocations, dwBytes); + AtlInterlockedUpdateMax(nCurrentAllocations, &m_pStats->m_nMaxAllocations); + } + + void ReleaseElement(DWORD dwBytes) + { + InterlockedDecrement(&m_pStats->m_nCurrentEntries); + InterlockedExchangeAdd(&m_pStats->m_nCurrentAllocations, -((long)dwBytes)); + } + + DWORD GetHitCount() + { + return m_pStats->m_nHitCount; + } + + DWORD GetMissCount() + { + return m_pStats->m_nMissCount; + } + + DWORD GetCurrentAllocSize() + { + return m_pStats->m_nCurrentAllocations; + } + + DWORD GetMaxAllocSize() + { + return m_pStats->m_nMaxAllocations; + } + + DWORD GetCurrentEntryCount() + { + return m_pStats->m_nCurrentEntries; + } + + DWORD GetMaxEntryCount() + { + return m_pStats->m_nMaxEntries; + } + + void ResetCounters() + { + m_pStats->m_nHitCount = 0; + m_pStats->m_nMissCount = 0; + m_pStats->m_nCurrentAllocations = 0; + m_pStats->m_nMaxAllocations = 0; + m_pStats->m_nCurrentEntries = 0; + m_pStats->m_nMaxEntries = 0; + } +}; // CStdStatClass + +// +// CNoStatClass +// This is a noop stat class +class CNoStatClass +{ +public: + HRESULT Initialize(){ return S_OK; } + HRESULT Uninitialize(){ return S_OK; } + void Hit(){ } + void Miss(){ } + void AddElement(DWORD){ } + void ReleaseElement(DWORD){ } + DWORD GetHitCount(){ return 0; } + DWORD GetMissCount(){ return 0; } + DWORD GetCurrentAllocSize(){ return 0; } + DWORD GetMaxAllocSize(){ return 0; } + DWORD GetCurrentEntryCount(){ return 0; } + DWORD GetMaxEntryCount(){ return 0; } + void ResetCounters(){ } +}; // CNoStatClass + +// +//CPerfStatClass +// Description +// This class provides the implementation of a cache statistics gathering class +// with PerfMon support +class CPerfStatClass : public CStdStatClass +{ + CPerfStatObject * m_pPerfObject; + CCachePerfMon m_PerfMon; + +public: + + HRESULT Initialize(__in_z_opt LPWSTR szName=NULL) + { + HRESULT hr; + WCHAR szPath[MAX_PATH]; + + if (!szName) + { + // default name is the name of the module + // we don't care about possible truncation if longer than max_path + // we just need an identifier + HINSTANCE hInst = _AtlBaseModule.GetModuleInstance(); + if (::GetModuleFileNameW(hInst, szPath, MAX_PATH) == 0) + { + return E_FAIL; + } + szPath[MAX_PATH-1] = 0; + szName = szPath; + } + + m_pPerfObject = NULL; + ATLTRACE(atlTraceCache, 2, _T("Initializing m_PerfMon\n")); + hr = m_PerfMon.Initialize(); + if (SUCCEEDED(hr)) + { + CPerfLock lock(&m_PerfMon); + if (FAILED(hr = lock.GetStatus())) + { + return hr; + } + + hr = m_PerfMon.CreateInstance(ATL_PERF_CACHE_OBJECT, 0, szName, reinterpret_cast(&m_pPerfObject)); + if (FAILED(hr)) + { + return hr; + } + + CStdStatClass::Initialize(m_pPerfObject); + } + else + ATLASSUME(m_pPerfObject == NULL); + + return hr; + } + + HRESULT Uninitialize() + { + CStdStatClass::Uninitialize(); + + if (m_pPerfObject != NULL) // Initialized m_pPerfObject successfully above + { + HRESULT hr = m_PerfMon.ReleaseInstance(m_pPerfObject); + if (hr != S_OK) + return hr; + + m_PerfMon.UnInitialize(); + } + + return S_OK; + } +}; // CPerfStatClass + +#ifndef ATL_BLOB_CACHE_TIMEOUT +#ifdef _DEBUG +#define ATL_BLOB_CACHE_TIMEOUT 1000 +#else +#define ATL_BLOB_CACHE_TIMEOUT 5000 +#endif // _DEBUG +#endif // ATL_BLOB_CACHE_TIMEOUT + +// +//CBlobCache +// Description: +// Implements a cache that stores pointers to void. Uses the generic CMemoryCacheBase class +// as the implementation. +template +class CBlobCache : public CMemoryCache, SyncObj, CullClass>, + public IMemoryCache, + public IMemoryCacheControl, + public IMemoryCacheStats, + public IWorkerThreadClient +{ + typedef CMemoryCache, SyncObj, CullClass> cacheBase; + + MonitorClass m_Monitor; + +protected: + HANDLE m_hTimer; + +public: + CBlobCache() : m_hTimer(NULL) + { + } + + HRESULT Initialize(IServiceProvider *pProv) + { + HRESULT hr = cacheBase::Initialize(pProv); + if (FAILED(hr)) + return hr; + hr = m_Monitor.Initialize(); + if (FAILED(hr)) + return hr; + return m_Monitor.AddTimer(ATL_BLOB_CACHE_TIMEOUT, + static_cast(this), (DWORD_PTR) this, &m_hTimer); + } + + template + HRESULT Initialize(IServiceProvider *pProv, CWorkerThread *pWorkerThread) + { + ATLASSERT(pWorkerThread); + + HRESULT hr = cacheBase::Initialize(pProv); + if (FAILED(hr)) + return hr; + + hr = m_Monitor.Initialize(pWorkerThread); + if (FAILED(hr)) + return hr; + + return m_Monitor.AddTimer(ATL_BLOB_CACHE_TIMEOUT, + static_cast(this), (DWORD_PTR) this, &m_hTimer); + } + + HRESULT Execute(DWORD_PTR dwParam, HANDLE /*hObject*/) + { + CBlobCache* pCache = (CBlobCache*)dwParam; + + if (pCache) + pCache->Flush(); + return S_OK; + } + + HRESULT CloseHandle(HANDLE hObject) + { + ATLASSUME(m_hTimer == hObject); + m_hTimer = NULL; + ::CloseHandle(hObject); + return S_OK; + } + + virtual ~CBlobCache() + { + if (m_hTimer) + { + ATLENSURE(SUCCEEDED(m_Monitor.RemoveHandle(m_hTimer))); + } + } + + HRESULT Uninitialize() + { + HRESULT hrMonitor=S_OK; + if (m_hTimer) + { + hrMonitor=m_Monitor.RemoveHandle(m_hTimer); + m_hTimer = NULL; + } + HRESULT hrShut=m_Monitor.Shutdown(); + HRESULT hrCache=cacheBase::Uninitialize(); + if(FAILED(hrMonitor)) + { + return hrMonitor; + } + if(FAILED(hrShut)) + { + return hrShut; + } + return hrCache; + } + // IUnknown methods + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) + { + HRESULT hr = E_NOINTERFACE; + if (!ppv) + hr = E_POINTER; + else + { + if (InlineIsEqualGUID(riid, __uuidof(IUnknown)) || + InlineIsEqualGUID(riid, __uuidof(IMemoryCache))) + { + *ppv = (IUnknown *) (IMemoryCache *) this; + AddRef(); + hr = S_OK; + } + if (InlineIsEqualGUID(riid, __uuidof(IMemoryCacheStats))) + { + *ppv = (IUnknown *) (IMemoryCacheStats*)this; + AddRef(); + hr = S_OK; + } + if (InlineIsEqualGUID(riid, __uuidof(IMemoryCacheControl))) + { + *ppv = (IUnknown *) (IMemoryCacheControl*)this; + AddRef(); + hr = S_OK; + } + + } + return hr; + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + + // IMemoryCache Methods + HRESULT STDMETHODCALLTYPE Add(LPCSTR szKey, void *pvData, DWORD dwSize, + FILETIME *pftExpireTime, + HINSTANCE hInstClient, + HCACHEITEM *phEntry, + IMemoryCacheClient *pClient) + { + HRESULT hr = E_FAIL; + //if it's a multithreaded cache monitor we'll let the monitor take care of + //cleaning up the cache so we don't overflow our configuration settings. + //if it's not a threaded cache monitor, we need to make sure we don't + //overflow the configuration settings by adding a new element + if (m_Monitor.GetThreadHandle()==NULL) + { + if (!cacheBase::CanAddEntry(dwSize)) + { + //flush the entries and check again to see if we can add + cacheBase::FlushEntries(); + if (!cacheBase::CanAddEntry(dwSize)) + return E_OUTOFMEMORY; + } + } + _ATLTRY + { + hr = cacheBase::AddEntry(szKey, pvData, dwSize, + pftExpireTime, hInstClient, pClient, phEntry); + return hr; + } + _ATLCATCHALL() + { + return E_FAIL; + } + } + + HRESULT STDMETHODCALLTYPE LookupEntry(LPCSTR szKey, HCACHEITEM * phEntry) + { + return cacheBase::LookupEntry(szKey, phEntry); + } + + HRESULT STDMETHODCALLTYPE GetData(const HCACHEITEM hKey, void **ppvData, DWORD *pdwSize) const + { + return cacheBase::GetEntryData(hKey, ppvData, pdwSize); + } + + HRESULT STDMETHODCALLTYPE ReleaseEntry(const HCACHEITEM hKey) + { + return cacheBase::ReleaseEntry(hKey); + } + + HRESULT STDMETHODCALLTYPE RemoveEntry(const HCACHEITEM hKey) + { + return cacheBase::RemoveEntry(hKey); + } + + HRESULT STDMETHODCALLTYPE RemoveEntryByKey(LPCSTR szKey) + { + return cacheBase::RemoveEntryByKey(szKey); + } + + HRESULT STDMETHODCALLTYPE Flush() + { + return cacheBase::FlushEntries(); + } + + + HRESULT STDMETHODCALLTYPE SetMaxAllowedSize(DWORD dwSize) + { + return cacheBase::SetMaxAllowedSize(dwSize); + } + + HRESULT STDMETHODCALLTYPE GetMaxAllowedSize(DWORD *pdwSize) + { + return cacheBase::GetMaxAllowedSize(pdwSize); + } + + HRESULT STDMETHODCALLTYPE SetMaxAllowedEntries(DWORD dwSize) + { + return cacheBase::SetMaxAllowedEntries(dwSize); + } + + HRESULT STDMETHODCALLTYPE GetMaxAllowedEntries(DWORD *pdwSize) + { + return cacheBase::GetMaxAllowedEntries(pdwSize); + } + + HRESULT STDMETHODCALLTYPE ResetCache() + { + return cacheBase::ResetCache(); + } + + // IMemoryCacheStats methods + HRESULT STDMETHODCALLTYPE ClearStats() + { + m_statObj.ResetCounters(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetHitCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetHitCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMissCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMissCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxAllocSize(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMaxAllocSize(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetCurrentAllocSize(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetCurrentAllocSize(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxEntryCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMaxEntryCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetCurrentEntryCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetCurrentEntryCount(); + return S_OK; + } + +}; // CBlobCache + + +// +// CDllCache +// This class manages a cache to handle calls to LoadLibrary +// and FreeLibrary. +// It keeps dlls loaded even after the last call to free library +// a worker thread then calls FreeLibrary on unused dlls +// +#ifndef ATL_DLL_CACHE_TIMEOUT + #ifdef _DEBUG + #define ATL_DLL_CACHE_TIMEOUT 1000 // 1 sec default for debug builds + #else + #define ATL_DLL_CACHE_TIMEOUT 10*60000 // 10 minute default for retail builds + #endif +#endif + +class CNoDllCachePeer +{ +public: + struct DllInfo + { + }; + + BOOL Add(HINSTANCE /*hInst*/, DllInfo * /*pInfo*/) + { + return TRUE; + } + + void Remove(HINSTANCE /*hInst*/, DllInfo * /*pInfo*/) + { + } +}; + +// CDllCache +// Implements IDllCache, an interface that is used to load and unload Dlls. +// To use it, construct an instance of a CDllCache and call Initialize. +// The Initialize call has to match with the type of monitor class you +// templatize on. The monitor thread will call IWorkerThreadClient::Execute +// after its timeout expires. Make sure to Uninitialize the object before +// it is destroyed by calling Uninitialize +// +template +class CDllCache : public IDllCache, + public IWorkerThreadClient +{ +protected: + CComCriticalSection m_critSec; + CSimpleArray m_Dlls; + CSimpleArray m_DllInfos; + MonitorClass m_Monitor; + HANDLE m_hTimer; + + void RemoveDllEntry(DLL_CACHE_ENTRY& entry) + { + ::FreeLibrary(entry.hInstDll); + entry.hInstDll = NULL; + m_Dlls.RemoveAt(m_Dlls.GetSize()-1); + } + +public: + Peer m_Peer; + + CDllCache() : + m_hTimer(NULL) + { + + } + + HRESULT Initialize(DWORD dwTimeout=ATL_DLL_CACHE_TIMEOUT) + { + HRESULT hr = m_critSec.Init(); + if (FAILED(hr)) + return hr; + hr = m_Monitor.Initialize(); + if (FAILED(hr)) + return hr; + return m_Monitor.AddTimer(dwTimeout, this, 0, &m_hTimer); + } + + template + HRESULT Initialize(CWorkerThread *pWorkerThread, + DWORD dwTimeout=ATL_DLL_CACHE_TIMEOUT) + { + HRESULT hr = m_critSec.Init(); + if (FAILED(hr)) + return hr; + hr = m_Monitor.Initialize(pWorkerThread); + if (FAILED(hr)) + return hr; + return m_Monitor.AddTimer(dwTimeout, this, 0, &m_hTimer); + } + + HRESULT Uninitialize() + { + HRESULT hr = S_OK; + HRESULT hrLatest = S_OK; + if (m_hTimer) + { + hrLatest=m_Monitor.RemoveHandle(m_hTimer); + if(FAILED(hrLatest) && SUCCEEDED(hr)) + { + hr=hrLatest; + } + m_hTimer = NULL; + } + m_Monitor.Shutdown(); + + // free all the libraries we've cached + int nLen = m_Dlls.GetSize(); + for (int i=0; i 0); + entry.bAlive = TRUE; + entry.dwRefs--; + m_critSec.Unlock(); + return TRUE; + } + } + + m_critSec.Unlock(); + // the dll wasn't found + // in the cache, so just + // pass along to ::FreeLibrary + return ::FreeLibrary(hInstDll); + } + + BOOL AddRefModule(HINSTANCE hInstDll) + { + HRESULT hr = m_critSec.Lock(); + if (FAILED(hr)) + return FALSE; + + int nLen = m_Dlls.GetSize(); + for (int i=0; i 0); + entry.dwRefs++; + m_critSec.Unlock(); + return TRUE; + } + } + + m_critSec.Unlock(); + return FALSE; + } + + BOOL ReleaseModule(HINSTANCE hInstDll) + { + HRESULT hr = m_critSec.Lock(); + if (FAILED(hr)) + return FALSE; + + int nLen = m_Dlls.GetSize(); + for (int i=0; i 0); + entry.bAlive = TRUE; + entry.dwRefs--; + m_critSec.Unlock(); + return TRUE; + } + } + m_critSec.Unlock(); + return FALSE; + } + + HRESULT GetEntries(DWORD dwCount, DLL_CACHE_ENTRY *pEntries, DWORD *pdwCopied) + { + if (!pdwCopied) + return E_POINTER; + + HRESULT hr = m_critSec.Lock(); + if (FAILED(hr)) + return hr; + + if (dwCount==0 || pEntries==NULL) + { + // just return the required size + *pdwCopied = m_Dlls.GetSize(); + m_critSec.Unlock(); + return S_OK; + } + + if (dwCount > (DWORD) m_Dlls.GetSize()) + dwCount = m_Dlls.GetSize(); + Checked::memcpy_s(pEntries, dwCount*sizeof(DLL_CACHE_ENTRY), m_Dlls.GetData(), dwCount*sizeof(DLL_CACHE_ENTRY)); + *pdwCopied = dwCount; + m_critSec.Unlock(); + return S_OK; + } + + HRESULT Flush() + { + HRESULT hr = m_critSec.Lock(); + if (FAILED(hr)) + return hr; + + int nLen = m_Dlls.GetSize(); + for (int i=0; i +class CStencilCache : + public CMemoryCacheBase, void *, CCacheDataEx, + CFixedStringKey, CStringElementTraitsI, + FlushClass, CullClass, SyncClass, StatClass>, + public IStencilCache, + public IStencilCacheControl, + public IWorkerThreadClient, + public IMemoryCacheStats, + public CComObjectRootEx +{ +protected: + typedef CMemoryCacheBase, void *, CCacheDataEx, + CFixedStringKey, CStringElementTraitsI, + FlushClass, CullClass, SyncClass, StatClass> cacheBase; + unsigned __int64 m_dwdwStencilLifespan; + + MonitorClass m_Monitor; + HANDLE m_hTimer; + CComPtr m_spDllCache; + +public: + + CStencilCache() : + m_dwdwStencilLifespan(ATL_STENCIL_LIFESPAN), + m_hTimer(NULL) + { + + } + + ~CStencilCache() + { + if (m_hTimer) + { + ATLENSURE(SUCCEEDED(m_Monitor.RemoveHandle(m_hTimer))); + } + } + + HRESULT Execute(DWORD_PTR dwParam, HANDLE /*hObject*/) + { + CStencilCache* pCache = (CStencilCache*)dwParam; + if (pCache) + pCache->FlushEntries(); + return S_OK; + } + + HRESULT CloseHandle(HANDLE hObject) + { + ATLASSUME(m_hTimer == hObject); + m_hTimer = NULL; + ::CloseHandle(hObject); + return S_OK; + } + + HRESULT Initialize(IServiceProvider *pProv, DWORD dwStencilCacheTimeout=ATL_STENCIL_CACHE_TIMEOUT, + __int64 dwdwStencilLifespan=ATL_STENCIL_LIFESPAN) + { + m_dwdwStencilLifespan = dwdwStencilLifespan; + HRESULT hr = cacheBase::Initialize(); + if (FAILED(hr)) + return hr; + hr = E_FAIL; + if (pProv) + hr = pProv->QueryService(__uuidof(IDllCache), __uuidof(IDllCache), (void**)&m_spDllCache); + if (FAILED(hr)) + return hr; + hr = m_Monitor.Initialize(); + if (FAILED(hr)) + return hr; + return m_Monitor.AddTimer(dwStencilCacheTimeout, this, (DWORD_PTR) this, &m_hTimer); + } + + template + HRESULT Initialize(IServiceProvider *pProv, CWorkerThread *pWorkerThread, + DWORD dwStencilCacheTimeout=ATL_STENCIL_CACHE_TIMEOUT, __int64 dwdwStencilLifespan=ATL_STENCIL_LIFESPAN) + { + m_dwdwStencilLifespan = dwdwStencilLifespan; + HRESULT hr = cacheBase::Initialize(); + if (FAILED(hr)) + return hr; + hr = E_FAIL; + if (pProv) + hr = pProv->QueryService(__uuidof(IDllCache), __uuidof(IDllCache), (void**)&m_spDllCache); + if (FAILED(hr)) + return hr; + hr = m_Monitor.Initialize(pWorkerThread); + if (FAILED(hr)) + return hr; + return m_Monitor.AddTimer(dwStencilCacheTimeout, this, (DWORD_PTR) this, &m_hTimer); + } + + + BEGIN_COM_MAP(CStencilCache) + COM_INTERFACE_ENTRY(IMemoryCacheStats) + COM_INTERFACE_ENTRY(IStencilCache) + COM_INTERFACE_ENTRY(IStencilCacheControl) + END_COM_MAP() +//IStencilCache methods + STDMETHOD(CacheStencil)(LPCSTR szName, void *pStencil, DWORD dwSize, HCACHEITEM *phEntry, + HINSTANCE hInstance, IMemoryCacheClient *pClient) + { + NodeType * pEntry = NULL; + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + return hr; + + _ATLTRY + { + hr = cacheBase::AddEntry(szName, pStencil, dwSize, (HCACHEITEM *)&pEntry); + } + _ATLCATCHALL() + { + hr = E_FAIL; + } + if (hr != S_OK) + { + m_syncObj.Unlock(); + return hr; + } + + pEntry->hInstance = hInstance; + pEntry->pClient = pClient; + pEntry->nLifespan = m_dwdwStencilLifespan; + if (hInstance && m_spDllCache) + m_spDllCache->AddRefModule(hInstance); + + cacheBase::CommitEntry(static_cast(pEntry)); + + if (phEntry) + *phEntry = static_cast(pEntry); + else + cacheBase::ReleaseEntry(static_cast(pEntry)); + + m_syncObj.Unlock(); + return hr; + } + + STDMETHOD(LookupStencil)(LPCSTR szName, HCACHEITEM * phStencil) + { + return cacheBase::LookupEntry(szName, phStencil); + } + + STDMETHOD(GetStencil)(const HCACHEITEM hStencil, void ** pStencil) const + { + return cacheBase::GetEntryData(hStencil, pStencil, NULL); + } + + STDMETHOD(AddRefStencil)(const HCACHEITEM hStencil) + { + return cacheBase::AddRefEntry(hStencil); + } + + STDMETHOD(ReleaseStencil)(const HCACHEITEM hStencil) + { + return cacheBase::ReleaseEntry(hStencil); + } + + //IStencilCacheControl + + STDMETHOD(RemoveStencil)(const HCACHEITEM hStencil) + { + return cacheBase::RemoveEntry(hStencil); + } + + STDMETHOD(RemoveStencilByName)(LPCSTR szStencil) + { + return cacheBase::RemoveEntryByKey(szStencil); + } + + STDMETHOD(RemoveAllStencils)() + { + return cacheBase::RemoveAllEntries(); + } + + STDMETHOD(SetDefaultLifespan)(unsigned __int64 dwdwLifespan) + { + m_dwdwStencilLifespan = dwdwLifespan; + return S_OK; + } + + STDMETHOD(GetDefaultLifespan)(unsigned __int64 *pdwdwLifepsan) + { + HRESULT hr = E_POINTER; + if (pdwdwLifepsan) + { + *pdwdwLifepsan = m_dwdwStencilLifespan; + hr = S_OK; + } + return hr; + } + + virtual void OnDestroyEntry(const NodeType * pEntry) + { + ATLASSERT(pEntry); + if (!pEntry) + return; + + if (pEntry->pClient) + pEntry->pClient->Free((void *)&pEntry->Data); + if (pEntry->hInstance && m_spDllCache) + m_spDllCache->ReleaseModule(pEntry->hInstance); + } + + HRESULT Uninitialize() + { + HRESULT hrMonitor=S_OK; + if (m_hTimer) + { + hrMonitor=m_Monitor.RemoveHandle(m_hTimer); + m_hTimer = NULL; + } + m_Monitor.Shutdown(); + HRESULT hrCache=cacheBase::Uninitialize(); + if(FAILED(hrMonitor)) + { + return hrMonitor; + } + return hrCache; + } + // IMemoryCacheStats methods + HRESULT STDMETHODCALLTYPE ClearStats() + { + m_statObj.ResetCounters(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetHitCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetHitCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMissCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMissCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxAllocSize(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMaxAllocSize(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetCurrentAllocSize(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetCurrentAllocSize(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxEntryCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMaxEntryCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetCurrentEntryCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetCurrentEntryCount(); + return S_OK; + } +}; // CStencilCache + +// {105A8866-4059-45fe-86AE-FA0EABBFBBB4} +extern "C" __declspec(selectany) const IID IID_IFileCache = { 0x105a8866, 0x4059, 0x45fe, { 0x86, 0xae, 0xfa, 0xe, 0xab, 0xbf, 0xbb, 0xb4 } }; + +__interface ATL_NO_VTABLE __declspec(uuid("105A8866-4059-45fe-86AE-FA0EABBFBBB4")) + IFileCache : public IUnknown +{ + // IFileCache Methods + + STDMETHOD(AddFile)( + LPCSTR szFileName, + LPCSTR szTempFileName, + FILETIME *pftExpireTime, + void *pPeerInfo, + HCACHEITEM * phKey); + STDMETHOD(LookupFile)(LPCSTR szFileName, HCACHEITEM * phKey); + STDMETHOD(GetFile)(const HCACHEITEM hKey, LPSTR * pszFileName, void **ppPeerInfo); + STDMETHOD(ReleaseFile)(const HCACHEITEM hKey); + STDMETHOD(RemoveFile)(const HCACHEITEM hKey); + STDMETHOD(RemoveFileByName)(LPCSTR szFileName); + STDMETHOD(Flush)(); +}; + +#ifndef ATL_FILE_CACHE_TIMEOUT + #define ATL_FILE_CACHE_TIMEOUT 1000 +#endif + +class CNoFileCachePeer +{ +public: + struct PeerInfo + { + }; + + static BOOL Add(PeerInfo* /*pDest*/, PeerInfo * /*pSrc*/) + { + return TRUE; + } + + static BOOL Remove(const PeerInfo* /*pFileInfo*/) + { + return TRUE; + } +}; + +template +struct CCacheDataPeer : public CCacheDataBase +{ + typename Peer::PeerInfo PeerData; +}; + +// A class to keep track of files, with maintenance -- maximum size of cache, +// maximum number of entries, expiration of entries, etc. -- inherits from +// CMemoryCacheBase +template < + class MonitorClass, + class StatClass=CStdStatClass, + class FileCachePeer=CNoFileCachePeer, + class FlushClass=COldFlusher, + class SyncClass=CComCriticalSection, + class CullClass=CExpireCuller > +class CFileCache: + public CMemoryCacheBase, LPSTR, CCacheDataPeer, + CFixedStringKey, CStringElementTraits, + FlushClass, CullClass, SyncClass, StatClass>, + public IWorkerThreadClient, + public IFileCache, + public IMemoryCacheControl, + public IMemoryCacheStats +{ + typedef CMemoryCacheBase, LPSTR, CCacheDataPeer, + CFixedStringKey, CStringElementTraits, + FlushClass, CullClass, SyncClass, StatClass> cacheBase; + + MonitorClass m_Monitor; + +protected: + HANDLE m_hTimer; + +public: + + CFileCache() : m_hTimer(NULL) + { + } + + HRESULT Initialize() + { + HRESULT hr = cacheBase::Initialize(); + if (FAILED(hr)) + return hr; + hr = m_Monitor.Initialize(); + if (FAILED(hr)) + return hr; + return m_Monitor.AddTimer(ATL_FILE_CACHE_TIMEOUT, + static_cast(this), (DWORD_PTR) this, &m_hTimer); + } + + template + HRESULT Initialize(CWorkerThread *pWorkerThread) + { + ATLASSERT(pWorkerThread); + + HRESULT hr = cacheBase::Initialize(); + if (FAILED(hr)) + return hr; + hr = m_Monitor.Initialize(pWorkerThread); + if (FAILED(hr)) + return hr; + return m_Monitor.AddTimer(ATL_FILE_CACHE_TIMEOUT, + static_cast(this), (DWORD_PTR) this, &m_hTimer); + } + + + // Callback for CWorkerThread + HRESULT Execute(DWORD_PTR dwParam, HANDLE /*hObject*/) + { + CFileCache* pCache = (CFileCache*)dwParam; + + if (pCache) + pCache->Flush(); + return S_OK; + } + + HRESULT CloseHandle(HANDLE hObject) + { + ATLASSUME(m_hTimer == hObject); + m_hTimer = NULL; + ::CloseHandle(hObject); + return S_OK; + } + + ~CFileCache() + { + if (m_hTimer) + { + ATLENSURE(SUCCEEDED(m_Monitor.RemoveHandle(m_hTimer))); + m_hTimer = NULL; + } + } + + HRESULT Uninitialize() + { + HRESULT hrMonitor=S_OK; + if (m_hTimer) + { + hrMonitor=m_Monitor.RemoveHandle(m_hTimer); + m_hTimer = NULL; + } + m_Monitor.Shutdown(); + HRESULT hrCache=cacheBase::Uninitialize(); + if(FAILED(hrMonitor)) + { + return hrMonitor; + } + return hrCache; + } + + + // IUnknown methods + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) + { + HRESULT hr = E_NOINTERFACE; + if (!ppv) + hr = E_POINTER; + else + { + if (InlineIsEqualGUID(riid, __uuidof(IUnknown)) || + InlineIsEqualGUID(riid, __uuidof(IFileCache))) + { + *ppv = (IUnknown *) (IFileCache *) this; + AddRef(); + hr = S_OK; + } + if (InlineIsEqualGUID(riid, __uuidof(IMemoryCacheStats))) + { + *ppv = (IMemoryCacheStats*)this; + AddRef(); + hr = S_OK; + } + if (InlineIsEqualGUID(riid, __uuidof(IMemoryCacheControl))) + { + *ppv = (IMemoryCacheControl*)this; + AddRef(); + hr = S_OK; + } + + } + return hr; + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + + ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + + // Adds a file to the cache. A file is created with a + // temporary name, and then Add is called with the temp + // file name and the final file name, along with expiration data, + // etc. A search on the file name will return the name of + // the file on disk (i.e. the temporary file) + HRESULT STDMETHODCALLTYPE AddFile( + LPCSTR szFileName, + LPCSTR szTempFileName, + FILETIME *pftExpireTime, + void* pPeerInfo, + HCACHEITEM * phKey = NULL) + { + WIN32_FILE_ATTRIBUTE_DATA fadData; + BOOL bRet = GetFileAttributesExA(szTempFileName, GetFileExInfoStandard, &fadData); + if (!bRet) + return AtlHresultFromLastError(); + + __int64 ddwFileSize = (static_cast<__int64>(fadData.nFileSizeHigh) << 32) + fadData.nFileSizeLow; + + DWORD dwRecordedFileSize = (DWORD) (ddwFileSize >> 10); + // Round the file size up to 1K if it is < 1K + if (dwRecordedFileSize == 0) + dwRecordedFileSize = 1; + + if (m_Monitor.GetThreadHandle()==NULL) + { + if (!cacheBase::CanAddEntry(dwRecordedFileSize)) + { + cacheBase::FlushEntries(); + if (!cacheBase::CanAddEntry(dwRecordedFileSize)) + return E_OUTOFMEMORY; + } + } + + NodeType *pEntry = NULL; + HRESULT hr = m_syncObj.Lock(); + if (FAILED(hr)) + return hr; + + hr = E_FAIL; + + // Make a private copy of the file name + CHeapPtr szTempFileCopy; + if (szTempFileCopy.Allocate(MAX_PATH)) + { + if (strlen(szTempFileName) >= MAX_PATH) + { + m_syncObj.Unlock(); + return E_FAIL; + } + Checked::strncpy_s(szTempFileCopy, MAX_PATH, szTempFileName, _TRUNCATE); + + _ATLTRY + { + hr = cacheBase::AddEntry(szFileName, szTempFileCopy, dwRecordedFileSize, (HCACHEITEM*)&pEntry); + szTempFileCopy.Detach(); + } + _ATLCATCHALL() + { + hr = E_FAIL; + } + } + + if (hr != S_OK) + { + m_syncObj.Unlock(); + return hr; + } + + + hr = (TRUE == FileCachePeer::Add(&pEntry->PeerData, + static_cast(pPeerInfo)) ? S_OK : E_FAIL); + if (hr == S_OK) + hr = cacheBase::CommitEntry(static_cast(pEntry)); + + if (hr != S_OK) + { + cacheBase::RemoveEntry(static_cast(pEntry)); + m_syncObj.Unlock(); + return hr; + } + + + if (pftExpireTime) + pEntry->cftExpireTime = *pftExpireTime; + + if (phKey) + *phKey = static_cast(pEntry); + else + cacheBase::ReleaseEntry(pEntry); + + m_syncObj.Unlock(); + return hr; + } + + // Action to take when the entry is removed from the cache + virtual void OnDestroyEntry(const NodeType * pEntry) + { + ATLASSERT(pEntry); + if (!pEntry) + return; + FileCachePeer::Remove(&pEntry->PeerData); + if (pEntry->Data) + { + DeleteFileA(pEntry->Data); + free(pEntry->Data); + const_cast(pEntry)->Data = NULL; + } + } + + // Looks up a file by name. Must be released after use + HRESULT STDMETHODCALLTYPE LookupFile(LPCSTR szFileName, HCACHEITEM * phKey) + { + return cacheBase::LookupEntry(szFileName, phKey); + } + + // Gets the name of the file on disk + HRESULT STDMETHODCALLTYPE GetFile(__in const HCACHEITEM hKey, __deref_out_z_opt LPSTR * pszFileName, __deref_out_opt void **ppPeerInfo) + { + NodeType *pEntry = (NodeType *)hKey; + if (ppPeerInfo) + *ppPeerInfo = &pEntry->PeerData; + return cacheBase::GetEntryData(hKey, pszFileName, NULL); + } + + // Releases a file + HRESULT STDMETHODCALLTYPE ReleaseFile(const HCACHEITEM hKey) + { + return cacheBase::ReleaseEntry(hKey); + } + + // Releases a file and marks it for deletion + HRESULT STDMETHODCALLTYPE RemoveFile(const HCACHEITEM hKey) + { + return cacheBase::RemoveEntry(hKey); + } + + // Removes a file by name -- this calls IMemoryCacheClient->Free + // on the file name, which by default (for CFileCache) deletes the + // file. + HRESULT STDMETHODCALLTYPE RemoveFileByName(LPCSTR szFileName) + { + return cacheBase::RemoveEntryByKey(szFileName); + } + + // Flushes the entries in the cache, eliminates expired entries, + // or if the cache exceeds the parameters (alloc size, num entries), + // culls items based on the sweep mode + HRESULT STDMETHODCALLTYPE Flush() + { + return cacheBase::FlushEntries(); + } + + // IMemoryCacheControl methods + HRESULT STDMETHODCALLTYPE SetMaxAllowedSize(DWORD dwSize) + { + return cacheBase::SetMaxAllowedSize(dwSize); + } + + HRESULT STDMETHODCALLTYPE GetMaxAllowedSize(DWORD *pdwSize) + { + return cacheBase::GetMaxAllowedSize(pdwSize); + } + + HRESULT STDMETHODCALLTYPE SetMaxAllowedEntries(DWORD dwSize) + { + return cacheBase::SetMaxAllowedEntries(dwSize); + } + + HRESULT STDMETHODCALLTYPE GetMaxAllowedEntries(DWORD *pdwSize) + { + return cacheBase::GetMaxAllowedEntries(pdwSize); + } + + HRESULT STDMETHODCALLTYPE ResetCache() + { + return cacheBase::ResetCache(); + } + + + // IMemoryCacheStats methods + HRESULT STDMETHODCALLTYPE ClearStats() + { + m_statObj.ResetCounters(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetHitCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetHitCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMissCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMissCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxAllocSize(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMaxAllocSize(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetCurrentAllocSize(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetCurrentAllocSize(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetMaxEntryCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetMaxEntryCount(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE GetCurrentEntryCount(DWORD *pdwSize) + { + if (!pdwSize) + return E_POINTER; + *pdwSize = m_statObj.GetCurrentEntryCount(); + return S_OK; + } +}; // CFileCache + +class CDataConnection; // see atldbcli.h +__interface __declspec(uuid("52E7759B-D6CC-4a03-BDF3-80A6BDCA1F94")) +IDataSourceCache : public IUnknown +{ + // Method: Add + // Params: + // szConn: Connection string of data source to connect to + // ppDS: Out pointer to the newly added data source + // Comments: + // Attempts to open a connection to the specified data source + // using a CDataSource object. Once the connection is open, the + // CDatasource is cached. + STDMETHOD(Add)(LPCTSTR szID, LPCOLESTR szConn, CDataConnection *pDS); + + // Method: Remove + // Params: + // szConn: Specifies the connection string of the connection to close + // Comments: + // Closes the specified connection and removes it's entry from the cache + STDMETHOD(Remove)(LPCTSTR szID); + + // Method: Lookup + // Params: + // szConn: Specifies the connection string of the connection to look up + // ppDS: Out pointer to CDataSource object that is connected to the specified + // data source. + STDMETHOD(Lookup)(LPCTSTR szID, CDataConnection *pDS); + + // Method: Uninitialize + // Params: + // None + // Comments: + // Closes removes all connections from the cache. + STDMETHOD(Uninitialize)(); + +}; +#ifndef ATL_DS_CONN_STRING_LEN + #define ATL_DS_CONN_STRING_LEN 512 +#endif + +template <> +class CElementTraits< CDataConnection > : + public CElementTraitsBase< CDataConnection > +{ +public: + static ULONG Hash( INARGTYPE t ) + { + return( ULONG( ULONG_PTR( &t ) ) ); + } + + static bool CompareElements( INARGTYPE element1, INARGTYPE element2 ) + { + return( element1.m_session.m_spOpenRowset == element2.m_session.m_spOpenRowset); + } + + static int CompareElementsOrdered( INARGTYPE /*element1*/, INARGTYPE /*element2*/ ) + { + ATLASSERT(FALSE); + return -1; + } + +}; + +typedef CFixedStringT atlDataSourceKey; +typedef CAtlMap, CElementTraits > atlDataSourceCacheMap; + +template +class CDataSourceCache : + public IDataSourceCache, + public CComObjectRootEx +{ +public: + BEGIN_COM_MAP(CDataSourceCache) + COM_INTERFACE_ENTRY(IDataSourceCache) + END_COM_MAP() + + CDataSourceCache() + { + m_cs.Init(); + } + + virtual ~CDataSourceCache () + { + Uninitialize(); + } + + STDMETHOD(Uninitialize)() + { + HRESULT hr = m_cs.Lock(); + if (SUCCEEDED(hr)) + { + m_ConnectionMap.RemoveAll(); + m_cs.Unlock(); + } + + return hr; + } + + STDMETHOD(Add)(LPCTSTR szID, LPCOLESTR szConn, CDataConnection *pSession) + { + HRESULT hr = E_FAIL; + + if (!szID) + return E_INVALIDARG; // must have session name + + // Do a lookup to make sure we don't add multiple entries + // with the same name. Adding multiple entries with the same name + // could cause some entries to get orphaned. + hr = m_cs.Lock(); + if (FAILED(hr)) + { + return hr; + } + + const atlDataSourceCacheMap::CPair *pPair = + m_ConnectionMap.Lookup(szID); + if (!pPair) + { + // try to open connection + CDataConnection DS; + hr = DS.Open(szConn); + if (hr == S_OK) + { + _ATLTRY + { + if (m_ConnectionMap.SetAt(szID, DS)) + { + if (pSession) // we allow NULL here + *pSession = DS; // copy connection to output. + hr = S_OK; + } + else + hr = E_FAIL; // map add failed + } + _ATLCATCHALL() + { + hr = E_FAIL; + } + } + } + else // lookup succeeded, entry is already in cache + { + // Instead of opening a new connection, just copy + // the one we already have in the cache. + if (pSession) + *pSession = pPair->m_value; + hr = S_OK; + } + m_cs.Unlock(); + return hr; + } + + STDMETHOD(Remove)(LPCTSTR szID) + { + HRESULT hr = E_INVALIDARG; + if (!szID) + return hr; // must have session name + + hr = m_cs.Lock(); + if (SUCCEEDED(hr)) + { + hr = m_ConnectionMap.RemoveKey(szID) ? S_OK : E_FAIL; + m_cs.Unlock(); + } + + return hr; + } + + STDMETHOD(Lookup)(LPCTSTR szID, CDataConnection *pSession) + { + if (!szID||!pSession) + return E_POINTER; + + HRESULT hr = m_cs.Lock(); + bool bRet = true; + if (SUCCEEDED(hr)) + { + bRet = m_ConnectionMap.Lookup(szID, *pSession); + m_cs.Unlock(); + } + + return (bRet && (bool)*pSession)? hr : E_FAIL; + } + +protected: + atlDataSourceCacheMap m_ConnectionMap; + TCritSec m_cs; +}; + + +// Some helpers for using the datasource cache. +// +// Function: GetDataSource +// Params: +// pProvider: Pointer to IServiceProvider that provides the +// data source cache service +// szID: The name of the connection (can be same as szDS) +// szDS: OLEDB connection string for data source +// ppDS: Out pointer to CDataSource. The CDataSource will be connected +// to the OLEDB provider specified by szDS on successful return. +// RetVal: +// Returns S_OK on success. +static HRESULT ATL_NOINLINE GetDataSource(IServiceProvider *pProvider, + LPCTSTR szID, LPCOLESTR szConn, + CDataConnection *pSession) +{ + if (!pProvider || !szID || !szConn) + return E_POINTER; + + CComPtr spDSCache; + HRESULT hr; + hr = pProvider->QueryService(__uuidof(IDataSourceCache), __uuidof(IDataSourceCache), (void**)&spDSCache); + if (hr == S_OK && spDSCache) + { + hr = spDSCache->Add(szID, szConn, pSession); + } + return hr; +} + +// +// Function: RemoveDataSource +// Params: +// pProvider: Pointer to IServiceProvider that provides the +// data source cache service +// szID: Name of the datasource connection to remove from the cache +// RetVal: +// none +// Comments: +// Removes the datasource entry from the datasource cache. Since entries are +// copied to the client on calls to lookup and add, removing an entry will not +// release the connections of existing clients. +static HRESULT ATL_NOINLINE RemoveDataSource(IServiceProvider *pProvider, LPCTSTR szID) +{ + if (!pProvider || !szID) + return E_POINTER; + + CComPtr spDSCache; + HRESULT hr = pProvider->QueryService(__uuidof(IDataSourceCache), __uuidof(IDataSourceCache), (void**)&spDSCache); + if (spDSCache) + hr = spDSCache->Remove(szID); + return hr; +} + +} // namespace ATL +#pragma pack(pop) + +#pragma warning (pop) + +#endif // __ATLCACHE_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlchecked.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlchecked.h new file mode 100644 index 00000000..d58c705f --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlchecked.h @@ -0,0 +1,605 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCHECKED_H__ +#define __ATLCHECKED_H__ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(push) +#pragma warning(disable:4127) + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ + +inline errno_t AtlCrtErrorCheck(errno_t nError) +{ + switch(nError) + { + case ENOMEM: + AtlThrow(E_OUTOFMEMORY); + break; + case EINVAL: + case ERANGE: + AtlThrow(E_INVALIDARG); + break; + case 0: + case STRUNCATE: + break; + default: + AtlThrow(E_FAIL); + break; + } + return nError; +} + +///////////////////////////////////////////////////////////////////////////// +// Secure (Checked) CRT functions + +namespace Checked +{ + +#if _SECURE_ATL + +#ifdef _AFX +#define ATLMFC_CRT_ERRORCHECK(expr) AFX_CRT_ERRORCHECK(expr) +#else +#define ATLMFC_CRT_ERRORCHECK(expr) ATL_CRT_ERRORCHECK(expr) +#endif + +inline void __cdecl memcpy_s(__out_bcount_part(_S1max,_N) void *_S1, __in size_t _S1max, __in_bcount(_N) const void *_S2, __in size_t _N) +{ + ATLMFC_CRT_ERRORCHECK(::memcpy_s(_S1, _S1max, _S2, _N)); +} + +inline void __cdecl wmemcpy_s(__out_ecount_part(_N1,_N) wchar_t *_S1, __in size_t _N1, __in_ecount(_N) const wchar_t *_S2, __in size_t _N) +{ + ATLMFC_CRT_ERRORCHECK(::wmemcpy_s(_S1, _N1, _S2, _N)); +} + +inline void __cdecl memmove_s(__out_bcount_part(_S1max,_N) void *_S1, __in size_t _S1max, __in_bcount(_N) const void *_S2, size_t _N) +{ + ATLMFC_CRT_ERRORCHECK(::memmove_s(_S1, _S1max, _S2, _N)); +} + +inline void __cdecl strcpy_s(__out_ecount(_S1max) char *_S1, __in size_t _S1max, __in_z const char *_S2) +{ + ATLMFC_CRT_ERRORCHECK(::strcpy_s(_S1, _S1max, _S2)); +} + +inline void __cdecl wcscpy_s(__out_ecount(_S1max) wchar_t *_S1, __in size_t _S1max, __in_z const wchar_t *_S2) +{ + ATLMFC_CRT_ERRORCHECK(::wcscpy_s(_S1, _S1max, _S2)); +} + +inline void __cdecl tcscpy_s(__out_ecount(_SizeInChars) TCHAR * _Dst, __in size_t _SizeInChars, __in_z const TCHAR * _Src) +{ +#ifndef _ATL_MIN_CRT + ATLMFC_CRT_ERRORCHECK(::_tcscpy_s(_Dst, _SizeInChars, _Src)); +#else +#ifdef UNICODE + ATLMFC_CRT_ERRORCHECK(::wcscpy_s(_Dst, _SizeInChars, _Src)); +#else + ATLMFC_CRT_ERRORCHECK(::strcpy_s(_Dst, _SizeInChars, _Src)); +#endif +#endif +} + +inline errno_t __cdecl strncpy_s(__out_ecount(_SizeInChars) char *_Dest, __in size_t _SizeInChars, __in_z const char *_Source, __in size_t _Count) +{ + return ATLMFC_CRT_ERRORCHECK(::strncpy_s(_Dest, _SizeInChars, _Source,_Count)); +} + +inline errno_t __cdecl wcsncpy_s(__out_ecount(_SizeInChars) wchar_t *_Dest, __in size_t _SizeInChars, __in_z const wchar_t *_Source, __in size_t _Count) +{ + return ATLMFC_CRT_ERRORCHECK(::wcsncpy_s(_Dest, _SizeInChars, _Source,_Count)); +} + +inline errno_t __cdecl tcsncpy_s(__out_ecount(_SizeInChars) TCHAR *_Dest, __in size_t _SizeInChars, __in_z const TCHAR *_Source, __in size_t _Count) +{ +#ifndef _ATL_MIN_CRT + return ATLMFC_CRT_ERRORCHECK(::_tcsncpy_s(_Dest, _SizeInChars, _Source,_Count)); +#else +#ifdef UNICODE + return ATLMFC_CRT_ERRORCHECK(::wcsncpy_s(_Dest, _SizeInChars, _Source,_Count)); +#else + return ATLMFC_CRT_ERRORCHECK(::strncpy_s(_Dest, _SizeInChars, _Source,_Count)); +#endif +#endif +} + +inline void __cdecl strcat_s(__inout_ecount_z(_SizeInChars) char * _Dst, __in size_t _SizeInChars, __in_z const char * _Src) +{ + ATLMFC_CRT_ERRORCHECK(::strcat_s(_Dst, _SizeInChars, _Src)); +} + +inline void __cdecl wcscat_s(__inout_ecount_z(_SizeInChars) wchar_t * _Dst, __in size_t _SizeInChars, __in_z const wchar_t * _Src) +{ + ATLMFC_CRT_ERRORCHECK(::wcscat_s(_Dst, _SizeInChars, _Src)); +} + +inline void __cdecl tcscat_s(__inout_ecount_z(_SizeInChars) TCHAR * _Dst, __in size_t _SizeInChars, __in_z const TCHAR * _Src) +{ +#ifndef _ATL_MIN_CRT + ATLMFC_CRT_ERRORCHECK(::_tcscat_s(_Dst, _SizeInChars, _Src)); +#else +#ifdef UNICODE + ATLMFC_CRT_ERRORCHECK(::wcscat_s(_Dst, _SizeInChars, _Src)); +#else + ATLMFC_CRT_ERRORCHECK(::strcat_s(_Dst, _SizeInChars, _Src)); +#endif +#endif +} + +inline void __cdecl strlwr_s(__inout_ecount_z(_SizeInChars) char * _Str, __in size_t _SizeInChars) +{ + ATLMFC_CRT_ERRORCHECK(::_strlwr_s(_Str, _SizeInChars)); +} + +inline void __cdecl wcslwr_s(__inout_ecount_z(_SizeInChars) wchar_t * _Str, __in size_t _SizeInChars) +{ + ATLMFC_CRT_ERRORCHECK(::_wcslwr_s(_Str, _SizeInChars)); +} + +#if !defined(_MANAGED) +inline void __cdecl mbslwr_s(__inout_bcount_z(_SizeInChars) unsigned char * _Str, __in size_t _SizeInChars) +{ + ATLMFC_CRT_ERRORCHECK(::_mbslwr_s(_Str, _SizeInChars)); +} +#endif + +inline void __cdecl tcslwr_s(__inout_ecount_z(_SizeInChars) TCHAR * _Str, __in size_t _SizeInChars) +{ +#ifndef _ATL_MIN_CRT + ATLMFC_CRT_ERRORCHECK(::_tcslwr_s(_Str, _SizeInChars)); +#else +#ifdef UNICODE + ATLMFC_CRT_ERRORCHECK(::_wcslwr_s(_Str, _SizeInChars)); +#else + ATLMFC_CRT_ERRORCHECK(::_strlwr_s(_Str, _SizeInChars)); +#endif +#endif +} + +inline void __cdecl strupr_s(__inout_ecount_z(_SizeInChars) char * _Str, __in size_t _SizeInChars) +{ + ATLMFC_CRT_ERRORCHECK(::_strupr_s(_Str, _SizeInChars)); +} + +inline void __cdecl wcsupr_s(__inout_ecount_z(_SizeInChars) wchar_t * _Str, __in size_t _SizeInChars) +{ + ATLMFC_CRT_ERRORCHECK(::_wcsupr_s(_Str, _SizeInChars)); +} + +#if !defined(_MANAGED) +inline void __cdecl mbsupr_s(__inout_bcount_z(_SizeInChars) unsigned char * _Str, __in size_t _SizeInChars) +{ + ATLMFC_CRT_ERRORCHECK(::_mbsupr_s(_Str, _SizeInChars)); +} +#endif + +inline void __cdecl tcsupr_s(__inout_ecount_z(_SizeInChars) TCHAR * _Str, __in size_t _SizeInChars) +{ + ATLMFC_CRT_ERRORCHECK(::_tcsupr_s(_Str, _SizeInChars)); +} + +inline void __cdecl itoa_s(__in int _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_itoa_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl itot_s(__in int _Val, __out_ecount_z(_SizeInChars) TCHAR *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_itot_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl ltoa_s(__in long _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_ltoa_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl ltot_s(__in long _Val, __out_ecount_z(_SizeInChars) TCHAR *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_ltot_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl ultoa_s(__in unsigned long _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_ultoa_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl ultow_s(__in unsigned long _Val, __out_ecount_z(_SizeInChars) wchar_t *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_ultow_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl ultot_s(__in unsigned long _Val, __out_ecount_z(_SizeInChars) TCHAR *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_ultot_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl i64toa_s(__in __int64 _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_i64toa_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl i64tow_s(__in __int64 _Val, __out_ecount_z(_SizeInChars) wchar_t *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_i64tow_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl ui64toa_s(__in unsigned __int64 _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_ui64toa_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl ui64tow_s(__in unsigned __int64 _Val, __out_ecount_z(_SizeInChars) wchar_t *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + ATLMFC_CRT_ERRORCHECK(::_ui64tow_s(_Val, _Buf, _SizeInChars, _Radix)); +} + +inline void __cdecl gcvt_s(__out_ecount_z(_SizeInChars) char *_Buffer, __in size_t _SizeInChars, __in double _Value, __in int _Ndec) +{ + ATLMFC_CRT_ERRORCHECK(::_gcvt_s(_Buffer, _SizeInChars, _Value, _Ndec)); +} + +inline void __cdecl tsplitpath_s(__in_z const TCHAR *_Path, __out_ecount_z_opt(_Drive_len) TCHAR *_Drive, __in size_t _Drive_len, + __out_ecount_z_opt(_Dir_len) TCHAR *_Dir, __in size_t _Dir_len, + __out_ecount_z_opt(_Fname_len) TCHAR *_Fname, __in size_t _Fname_len, + __out_ecount_z_opt(_Ext_len) TCHAR *_Ext, __in size_t _Ext_len) +{ + ATLMFC_CRT_ERRORCHECK(::_tsplitpath_s(_Path, _Drive, _Drive_len, _Dir, _Dir_len, _Fname, _Fname_len, _Ext, _Ext_len)); +} + +inline void __cdecl tmakepath_s(__out_ecount_z(_SizeInChars) TCHAR *_Path, __in size_t _SizeInChars, __in_z const TCHAR *_Drive, + __in_z const TCHAR *_Dir, __in_z const TCHAR *_Fname, __in_z const TCHAR *_Ext) +{ + ATLMFC_CRT_ERRORCHECK(::_tmakepath_s(_Path, _SizeInChars, _Drive, _Dir, _Fname, _Ext)); +} + +inline size_t __cdecl strnlen(__in_ecount(_Maxsize) const char *_Str, __in size_t _Maxsize) +{ + return ::strnlen(_Str, _Maxsize); +} + +inline size_t __cdecl wcsnlen(__in_ecount(_Maxsize) const wchar_t *_Wcs, __in size_t _Maxsize) +{ + return ::wcsnlen(_Wcs, _Maxsize); +} + +inline size_t __cdecl tcsnlen(__in_ecount(_Maxsize) const TCHAR *_Str, __in size_t _Maxsize) +{ + return ::_tcsnlen(_Str, _Maxsize); +} + +inline int get_errno() +{ + int nErrNo; + ATLMFC_CRT_ERRORCHECK(::_get_errno(&nErrNo)); + return nErrNo; +} + +inline void set_errno(__in int _Value) +{ + ATLMFC_CRT_ERRORCHECK(::_set_errno(_Value)); +} + +#else // !_SECURE_ATL + +#define ATLMFC_CRT_ERRORCHECK(expr) do { expr; } while (0) + +inline void __cdecl memcpy_s(__out_bcount(_S1max) void *_S1, __in size_t _S1max, __in_bcount(_N) const void *_S2, size_t _N) +{ + (_S1max); + memcpy(_S1, _S2, _N); +} + +inline void __cdecl wmemcpy_s(__out_ecount(_N1) wchar_t *_S1, __in size_t _N1, __in_ecount(_N) const wchar_t *_S2, __in size_t _N) +{ + (_N1); + ::wmemcpy(_S1, _S2, _N); +} + +inline void __cdecl memmove_s(__out_bcount(_S1max) void *_S1, __in size_t _S1max, __in_bcount(_N) const void *_S2, __in size_t _N) +{ + (_S1max); + memmove(_S1, _S2, _N); +} + +inline void __cdecl strcpy_s(__out_ecount_z(_S1max) char *_S1, __in size_t _S1max, __in_z const char *_S2) +{ + (_S1max); + ::strcpy(_S1, _S2); +} + +inline void __cdecl wcscpy_s(__out_ecount_z(_S1max) wchar_t *_S1, __in size_t _S1max, __in_z const wchar_t *_S2) +{ + (_S1max); + ::wcscpy(_S1, _S2); +} + +inline void __cdecl tcscpy_s(__out_ecount_z(_SizeInChars) TCHAR * _Dst, __in size_t _SizeInChars, __in_z const TCHAR * _Src) +{ + (_SizeInChars); +#ifndef _ATL_MIN_CRT + ::_tcscpy(_Dst, _Src); +#else +#ifdef UNICODE + ::wcscpy(_Dst, _Src); +#else + ::strcpy(_Dst, _Src); +#endif +#endif +} + +/* ensure that strncpy_s null-terminate the dest string */ +inline errno_t __cdecl strncpy_s(__out_ecount_z(_SizeInChars) char *_Dest, __in size_t _SizeInChars, __in_z const char *_Source,__in size_t _Count) +{ + if (_Count == _TRUNCATE) + { + _Count = _SizeInChars - 1; + } + while (_Count > 0 && *_Source != 0) + { + *_Dest++ = *_Source++; + --_Count; + } + *_Dest = 0; + + return (*_Source!=0) ? STRUNCATE : 0; +} + +inline errno_t __cdecl wcsncpy_s(__out_ecount_z(_SizeInChars) wchar_t *_Dest, __in size_t _SizeInChars, __in_z const wchar_t *_Source, __in size_t _Count) +{ + if (_Count == _TRUNCATE) + { + _Count = _SizeInChars - 1; + } + while (_Count > 0 && *_Source != 0) + { + *_Dest++ = *_Source++; + --_Count; + } + *_Dest = 0; + + return (*_Source!=0) ? STRUNCATE : 0; +} + +inline errno_t __cdecl tcsncpy_s(__out_ecount_z(_SizeInChars) TCHAR *_Dest, __in size_t _SizeInChars, __in_z const TCHAR *_Source,__in size_t _Count) +{ + if (_Count == _TRUNCATE) + { + if(_SizeInChars>0) + { + _Count = _SizeInChars - 1; + } + else + { + _Count =0; + } + } + +#ifndef _ATL_MIN_CRT +#pragma warning(push) +#pragma warning(disable: 6535) + ::_tcsncpy(_Dest,_Source,_Count); +#pragma warning(pop) + if(_SizeInChars>0) + { + size_t nulCount = __min(_SizeInChars-1, _Count); + _Dest[nulCount] = 0; + } +#else + while (_Count > 0 && *_Source != 0) + { + *_Dest++ = *_Source++; + --_Count; + } + *_Dest = 0; +#endif + + return (*_Source!=0) ? STRUNCATE : 0; +} + +inline void __cdecl strcat_s(__inout_ecount_z(_SizeInChars) char * _Dst, __in size_t _SizeInChars, __in_z const char * _Src) +{ + (_SizeInChars); + ::strcat(_Dst, _Src); +} + +inline void __cdecl wcscat_s(__inout_ecount_z(_SizeInChars) wchar_t * _Dst, __in size_t _SizeInChars, __in_z const wchar_t * _Src) +{ + (_SizeInChars); + ::wcscat(_Dst, _Src); +} + +inline void __cdecl tcscat_s(__inout_ecount_z(_SizeInChars) TCHAR * _Dst, __in size_t _SizeInChars, __in_z const TCHAR * _Src) +{ + (_SizeInChars); +#ifndef _ATL_MIN_CRT + ::_tcscat(_Dst, _Src); +#else +#ifdef UNICODE + ::wcscat(_Dst, _Src); +#else + ::strcat(_Dst, _Src); +#endif +#endif +} + +inline void __cdecl strlwr_s(__inout_ecount_z(_SizeInChars) char * _Str, size_t _SizeInChars) +{ + (_SizeInChars); + ::_strlwr(_Str); +} + +inline void __cdecl wcslwr_s(__inout_ecount_z(_SizeInChars) wchar_t * _Str, size_t _SizeInChars) +{ + (_SizeInChars); + ::_wcslwr(_Str); +} + +inline void __cdecl mbslwr_s(__inout_bcount_z(_SizeInChars) unsigned char * _Str, size_t _SizeInChars) +{ + (_SizeInChars); + ::_mbslwr(_Str); +} + +inline void __cdecl tcslwr_s(__inout_ecount_z(_SizeInChars) TCHAR * _Str, size_t _SizeInChars) +{ + (_SizeInChars); +#ifndef _ATL_MIN_CRT + ::_tcslwr(_Str); +#else +#ifdef UNICODE + ::_wcslwr(_Str); +#else + ::_strlwr(_Str); +#endif +#endif +} + +inline void __cdecl itoa_s(__in int _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_itoa_s(_Val, _Buf, _SizeInChars, _Radix); +} + +inline void __cdecl itot_s(__in int _Val, __out_ecount_z(_SizeInChars) TCHAR *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_itot(_Val, _Buf, _Radix); +} + +inline void __cdecl ltoa_s(__in long _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_ltoa(_Val, _Buf, _Radix); +} + +inline void __cdecl ltot_s(__in long _Val, __out_ecount_z(_SizeInChars) TCHAR *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_ltot(_Val, _Buf, _Radix); +} + +inline void __cdecl ultoa_s(__in unsigned long _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_ultoa(_Val, _Buf, _Radix); +} + +inline void __cdecl ultow_s(__in unsigned long _Val, __out_ecount_z(_SizeInChars) wchar_t *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_ultow(_Val, _Buf, _Radix); +} + +inline void __cdecl ultot_s(__in unsigned long _Val, __out_ecount_z(_SizeInChars) TCHAR *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_ultot(_Val, _Buf, _Radix); +} + +inline void __cdecl i64toa_s(__in __int64 _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_i64toa(_Val, _Buf, _Radix); +} + +inline void __cdecl i64tow_s(__in __int64 _Val, __out_ecount_z(_SizeInChars) wchar_t *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_i64tow(_Val, _Buf, _Radix); +} + +inline void __cdecl ui64toa_s(__in unsigned __int64 _Val, __out_ecount_z(_SizeInChars) char *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_ui64toa(_Val, _Buf, _Radix); +} + +inline void __cdecl ui64tow_s(__in unsigned __int64 _Val, __out_ecount_z(_SizeInChars) wchar_t *_Buf, __in size_t _SizeInChars, __in int _Radix) +{ + (_SizeInChars); + ::_ui64tow(_Val, _Buf, _Radix); +} + +inline void __cdecl gcvt_s(__out_ecount_z(_SizeInChars) char *_Buffer, __in size_t _SizeInChars, __in double _Value, __in int _Ndec) +{ + (_SizeInChars); + ::_gcvt(_Value, _Ndec, _Buffer); +} + +inline void __cdecl tsplitpath_s(__in_z const TCHAR *_Path, __out_ecount_z_opt(_Drive_len) TCHAR *_Drive, __in size_t _Drive_len, + __out_ecount_z_opt(_Dir_len) TCHAR *_Dir, __in size_t _Dir_len, + __out_ecount_z_opt(_Fname_ext) TCHAR *_Fname, __in size_t _Fname_len, + __out_ecount_z_opt(_Ext_len) TCHAR *_Ext, __in size_t _Ext_len) +{ + (_Drive_len, _Dir_len, _Fname_len, _Ext_len); + ::_tsplitpath(_Path, _Drive, _Dir, _Fname, _Ext); +} + +inline void __cdecl tmakepath_s(__out_ecount_z(_SizeInChars) TCHAR *_Path, __in size_t _SizeInChars, __in_z const TCHAR *_Drive, + __in_z const TCHAR *_Dir, __in_z const TCHAR *_Fname, __in_z const TCHAR *_Ext) +{ + (_SizeInChars); + ::_tmakepath(_Path, _Drive, _Dir, _Fname, _Ext); +} + +inline size_t __cdecl strnlen(__in_ecount(_Maxsize) const char *_Str, __in size_t _Maxsize) +{ + (_Maxsize); + return ::strlen(_Str); +} + +inline size_t __cdecl wcsnlen(__in_ecount(_Maxsize) const wchar_t *_Wcs, __in size_t _Maxsize) +{ + (_Maxsize); + return ::wcslen(_Wcs); +} + +inline size_t __cdecl tcsnlen(__in_ecount(_Maxsize) const TCHAR *_Str, __in size_t _Maxsize) +{ + (_Maxsize); + return ::_tcslen(_Str); +} + +inline int get_errno() +{ + return errno; +} + +inline void set_errno(__in int _Value) +{ + errno = _Value; +} + +#endif // _SECURE_ATL + +} // namespace Checked + +} // namespace ATL +#pragma warning(pop) +#pragma pack(pop) + +#endif // __ATLCHECKED_H__ + +///////////////////////////////////////////////////////////////////////////// + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcoll.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcoll.h new file mode 100644 index 00000000..00880db2 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcoll.h @@ -0,0 +1,4135 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCOLL_H__ +#define __ATLCOLL_H__ + +#pragma once + +#pragma warning(push) +#pragma warning(disable: 4702) // Unreachable code. This file will have lots of it, especially without EH enabled. +#pragma warning(disable: 4512) // assignment operator could not be generated +#pragma warning(disable: 4290) // C++ Exception Specification ignored +#pragma warning(disable: 4127) // conditional expression constant +#pragma warning(disable: 4571) //catch(...) blocks compiled with /EHs do NOT catch or re-throw Structured Exceptions + +// abstract iteration position +#ifndef _AFX +struct __POSITION +{ +}; +#endif +typedef __POSITION* POSITION; + +#include +#include + +#ifndef _AFX_PACKING +#define _AFX_PACKING 4 +#endif + +#pragma pack(push,_ATL_PACKING) +namespace ATL { + +struct CAtlPlex // warning variable length structure +{ + CAtlPlex* pNext; +#if (_AFX_PACKING >= 8) + DWORD dwReserved[1]; // align on 8 byte boundary +#endif + // BYTE data[maxNum*elementSize]; + + void* data() { return this+1; } + + static CAtlPlex* Create(CAtlPlex*& head, size_t nMax, size_t cbElement); + // like 'calloc' but no zero fill + // may throw memory exceptions + + void FreeDataChain(); // free this one and links +}; + +inline CAtlPlex* CAtlPlex::Create( CAtlPlex*& pHead, size_t nMax, size_t nElementSize ) +{ + CAtlPlex* pPlex; + + ATLASSERT( nMax > 0 ); + ATLASSERT( nElementSize > 0 ); + + size_t nBytes=0; + if( FAILED(::ATL::AtlMultiply(&nBytes, nMax, nElementSize)) || + FAILED(::ATL::AtlAdd(&nBytes, nBytes, sizeof(CAtlPlex))) ) + { + return NULL; + } + pPlex = static_cast< CAtlPlex* >( malloc( nBytes ) ); + if( pPlex == NULL ) + { + return( NULL ); + } + + pPlex->pNext = pHead; + pHead = pPlex; + + return( pPlex ); +} + +inline void CAtlPlex::FreeDataChain() +{ + CAtlPlex* pPlex; + + pPlex = this; + while( pPlex != NULL ) + { + CAtlPlex* pNext; + + pNext = pPlex->pNext; + free( pPlex ); + pPlex = pNext; + } +} + +template< typename T > +class CElementTraitsBase +{ +public: + typedef const T& INARGTYPE; + typedef T& OUTARGTYPE; + + static void CopyElements( T* pDest, const T* pSrc, size_t nElements ) + { + for( size_t iElement = 0; iElement < nElements; iElement++ ) + { + pDest[iElement] = pSrc[iElement]; + } + } + + static void RelocateElements( T* pDest, T* pSrc, size_t nElements ) + { + // A simple memmove works for nearly all types. + // You'll have to override this for types that have pointers to their + // own members. + Checked::memmove_s( pDest, nElements*sizeof( T ), pSrc, nElements*sizeof( T )); + } +}; + +template< typename T > +class CDefaultHashTraits +{ +public: + static ULONG Hash( const T& element ) throw() + { + return( ULONG( ULONG_PTR( element ) ) ); + } +}; + +template< typename T > +class CDefaultCompareTraits +{ +public: + static bool CompareElements( const T& element1, const T& element2 ) + { + return( (element1 == element2) != 0 ); // != 0 to handle overloads of operator== that return BOOL instead of bool + } + + static int CompareElementsOrdered( const T& element1, const T& element2 ) + { + if( element1 < element2 ) + { + return( -1 ); + } + else if( element1 == element2 ) + { + return( 0 ); + } + else + { + ATLASSERT( element1 > element2 ); + return( 1 ); + } + } +}; + +template< typename T > +class CDefaultElementTraits : + public CElementTraitsBase< T >, + public CDefaultHashTraits< T >, + public CDefaultCompareTraits< T > +{ +}; + +template< typename T > +class CElementTraits : + public CDefaultElementTraits< T > +{ +}; + +template<> +class CElementTraits< GUID > : + public CElementTraitsBase< GUID > +{ +public: + static ULONG Hash( INARGTYPE guid ) + { + const DWORD* pdwData = reinterpret_cast< const DWORD* >( &guid ); + + return( pdwData[0]^pdwData[1]^pdwData[2]^pdwData[3] ); + } + + static bool CompareElements( INARGTYPE element1, INARGTYPE element2 ) + { + return( (element1 == element2) != 0 ); // != 0 to handle overloads of operator== that return BOOL instead of bool + } + + static int CompareElementsOrdered( INARGTYPE element1, INARGTYPE element2 ) + { + const DWORD* pdwData1 = reinterpret_cast< const DWORD* >( &element1 ); + const DWORD* pdwData2 = reinterpret_cast< const DWORD* >( &element2 ); + + for( int iDWORD = 3; iDWORD >= 0; iDWORD-- ) + { + if( pdwData1[iDWORD] > pdwData2[iDWORD] ) + { + return( 1 ); + } + else if( pdwData1[iDWORD] < pdwData2[iDWORD] ) + { + return( -1 ); + } + } + + return( 0 ); + } +}; + +template<> +class CElementTraits< CComVariant > : + public CElementTraitsBase< CComVariant > +{ +public: + typedef const VARIANT& INARGTYPE; + +// static ULONG Hash( INARGTYPE t ); // variant hashing is problematic + + static bool CompareElements( INARGTYPE element1, INARGTYPE element2 ) + { + return VarCmp(const_cast(&element1), const_cast(&element2), LOCALE_USER_DEFAULT, 0)==static_cast(VARCMP_EQ); + } + + static int CompareElementsOrdered( INARGTYPE element1, INARGTYPE element2 ) + { + HRESULT hr = VarCmp(const_cast(&element1), const_cast(&element2), LOCALE_USER_DEFAULT, 0); + if( hr == static_cast(VARCMP_LT) ) + { + return( -1 ); + } + else if( hr == static_cast(VARCMP_GT) ) + { + return( 1 ); + } + else + { + ATLASSERT( hr == static_cast(VARCMP_EQ) || hr == static_cast(VARCMP_NULL) ); + return( 0 ); + } + } +}; + +template<> +class CElementTraits< CComBSTR > : + public CElementTraitsBase< CComBSTR > +{ +public: + static ULONG Hash( INARGTYPE bstr ) throw() + { + ULONG nHash = 0; + const OLECHAR* pch = bstr; + ULONG nLength = bstr.Length(); + for( ULONG iChar = 0; iChar < nLength; iChar++ ) + { + nHash = (nHash<<5)+nHash+pch[iChar]; + } + + return( nHash ); + } + + static bool CompareElements( INARGTYPE bstr1, INARGTYPE bstr2 ) throw() + { + return( bstr1 == bstr2 ); + } + + static int CompareElementsOrdered( INARGTYPE bstr1, INARGTYPE bstr2 ) throw() + { + if( bstr1 == NULL ) + { + return( (bstr2 == NULL) ? 0 : -1 ); + } + else if( bstr2 == NULL ) + { + return( 1 ); + } + + HRESULT hr = VarBstrCmp( bstr1, bstr2, LOCALE_SYSTEM_DEFAULT, 0 ); + switch( hr ) + { + case static_cast(VARCMP_LT): + return( -1 ); + break; + + case static_cast(VARCMP_GT): + return( 1 ); + break; + + case static_cast(VARCMP_EQ): + return( 0 ); + break; + + default: + ATLASSERT( false ); + return( 0 ); + break; + } + } +}; + +template< typename I, const IID* piid = &__uuidof( I ) > +class CComQIPtrElementTraits : + public CDefaultElementTraits< ATL::CComQIPtr< I, piid > > +{ +public: + typedef I* INARGTYPE; +}; + +template< typename T > +class CAutoPtrElementTraits : + public CDefaultElementTraits< ATL::CAutoPtr< T > > +{ +public: + typedef ATL::CAutoPtr< T >& INARGTYPE; + typedef T*& OUTARGTYPE; + + // Specialise copy elements to allow non-const since we transfer ownership on assignment + static void CopyElements( ::ATL::CAutoPtr< T >* pDest, ::ATL::CAutoPtr< T >* pSrc, size_t nElements ) + { + for( size_t iElement = 0; iElement < nElements; iElement++ ) + { + pDest[iElement] = pSrc[iElement]; + } + } +}; + +template< typename T > +class CAutoVectorPtrElementTraits : + public CDefaultElementTraits< ATL::CAutoVectorPtr< T > > +{ +public: + typedef ATL::CAutoVectorPtr< T >& INARGTYPE; + typedef T*& OUTARGTYPE; + + // Specialise copy elements to allow non-const since we transfer ownership on assignment + static void CopyElements( ::ATL::CAutoVectorPtr< T >* pDest, ::ATL::CAutoVectorPtr< T >* pSrc, size_t nElements ) + { + for( size_t iElement = 0; iElement < nElements; iElement++ ) + { + pDest[iElement] = pSrc[iElement]; + } + } +}; + +template< typename T, class Allocator = ATL::CCRTAllocator > +class CHeapPtrElementTraits : + public CDefaultElementTraits< ATL::CHeapPtr< T, Allocator > > +{ +public: + typedef ATL::CHeapPtr< T, Allocator >& INARGTYPE; + typedef T*& OUTARGTYPE; +}; + +template < typename T > +class CDefaultCharTraits +{ +}; + +template <> +class CDefaultCharTraits +{ +public: + static char CharToUpper(char x) + { + return (char)toupper(x); + } + + static char CharToLower(char x) + { + return (char)tolower(x); + } +}; + +template <> +class CDefaultCharTraits +{ +public: + static wchar_t CharToUpper(wchar_t x) + { + return (wchar_t)towupper(x); + } + + static wchar_t CharToLower(wchar_t x) + { + return (wchar_t)towlower(x); + } +}; + +template< typename T, class CharTraits = CDefaultCharTraits > +class CStringElementTraitsI : + public CElementTraitsBase< T > +{ +public: + typedef typename T::PCXSTR INARGTYPE; + typedef T& OUTARGTYPE; + + static ULONG Hash( INARGTYPE str ) + { + ULONG nHash = 0; + + const T::XCHAR* pch = str; + + ATLENSURE( pch != NULL ); + + while( *pch != 0 ) + { + nHash = (nHash<<5)+nHash+CharTraits::CharToUpper(*pch); + pch++; + } + + return( nHash ); + } + + static bool CompareElements( INARGTYPE str1, INARGTYPE str2 ) throw() + { + return( T::StrTraits::StringCompareIgnore( str1, str2 ) == 0 ); + } + + static int CompareElementsOrdered( INARGTYPE str1, INARGTYPE str2 ) throw() + { + return( T::StrTraits::StringCompareIgnore( str1, str2 ) ); + } +}; + +template< typename T > +class CStringRefElementTraits : + public CElementTraitsBase< T > +{ +public: + static ULONG Hash( INARGTYPE str ) + { + ULONG nHash = 0; + + const T::XCHAR* pch = str; + + ATLENSURE( pch != NULL ); + + while( *pch != 0 ) + { + nHash = (nHash<<5)+nHash+(*pch); + pch++; + } + + return( nHash ); + } + + static bool CompareElements( INARGTYPE element1, INARGTYPE element2 ) throw() + { + return( element1 == element2 ); + } + + static int CompareElementsOrdered( INARGTYPE str1, INARGTYPE str2 ) throw() + { + return( str1.Compare( str2 ) ); + } +}; + +template< typename T > +class CPrimitiveElementTraits : + public CDefaultElementTraits< T > +{ +public: + typedef T INARGTYPE; + typedef T& OUTARGTYPE; +}; + +#define _DECLARE_PRIMITIVE_TRAITS( T ) \ + template<> \ + class CElementTraits< T > : \ + public CPrimitiveElementTraits< T > \ + { \ + }; + +_DECLARE_PRIMITIVE_TRAITS( unsigned char ) +_DECLARE_PRIMITIVE_TRAITS( unsigned short ) +_DECLARE_PRIMITIVE_TRAITS( unsigned int ) +_DECLARE_PRIMITIVE_TRAITS( unsigned long ) +_DECLARE_PRIMITIVE_TRAITS( unsigned __int64 ) +_DECLARE_PRIMITIVE_TRAITS( signed char ) +_DECLARE_PRIMITIVE_TRAITS( char ) +_DECLARE_PRIMITIVE_TRAITS( short ) +_DECLARE_PRIMITIVE_TRAITS( int ) +_DECLARE_PRIMITIVE_TRAITS( long ) +_DECLARE_PRIMITIVE_TRAITS( __int64 ) +_DECLARE_PRIMITIVE_TRAITS( float ) +_DECLARE_PRIMITIVE_TRAITS( double ) +_DECLARE_PRIMITIVE_TRAITS( bool ) +#ifdef _NATIVE_WCHAR_T_DEFINED +_DECLARE_PRIMITIVE_TRAITS( wchar_t ) +#endif +_DECLARE_PRIMITIVE_TRAITS( void* ) + +template< typename E, class ETraits = CElementTraits< E > > +class CAtlArray +{ +public: + typedef typename ETraits::INARGTYPE INARGTYPE; + typedef typename ETraits::OUTARGTYPE OUTARGTYPE; + +public: + CAtlArray() throw(); + + size_t GetCount() const throw(); + bool IsEmpty() const throw(); + bool SetCount( size_t nNewSize, int nGrowBy = -1 ); + + void FreeExtra() throw(); + void RemoveAll() throw(); + + const E& GetAt( size_t iElement ) const; + void SetAt( size_t iElement, INARGTYPE element ); + E& GetAt( size_t iElement ); + + const E* GetData() const throw(); + E* GetData() throw(); + + void SetAtGrow( size_t iElement, INARGTYPE element ); + // Add an empty element to the end of the array + size_t Add(); + // Add an element to the end of the array + size_t Add( INARGTYPE element ); + size_t Append( const CAtlArray< E, ETraits >& aSrc ); + void Copy( const CAtlArray< E, ETraits >& aSrc ); + + const E& operator[]( size_t iElement ) const; + E& operator[]( size_t iElement ); + + void InsertAt( size_t iElement, INARGTYPE element, size_t nCount = 1 ); + void InsertArrayAt( size_t iStart, const CAtlArray< E, ETraits >* paNew ); + void RemoveAt( size_t iElement, size_t nCount = 1 ); + +#ifdef _DEBUG + void AssertValid() const; +#endif // _DEBUG + +private: + bool GrowBuffer( size_t nNewSize ); + +// Implementation +private: + E* m_pData; + size_t m_nSize; + size_t m_nMaxSize; + int m_nGrowBy; + +private: + static void CallConstructors( E* pElements, size_t nElements ); + static void CallDestructors( E* pElements, size_t nElements ) throw(); + +public: + ~CAtlArray() throw(); + +private: + // Private to prevent use + CAtlArray( const CAtlArray& ) throw(); + CAtlArray& operator=( const CAtlArray& ) throw(); +}; + +template< class I, const IID* piid = &__uuidof( I ) > +class CInterfaceArray : + public CAtlArray< ATL::CComQIPtr< I, piid >, CComQIPtrElementTraits< I, piid > > +{ +public: + CInterfaceArray() throw() + { + } + +private: + // Private to prevent use + CInterfaceArray( const CInterfaceArray& ) throw(); + CInterfaceArray& operator=( const CInterfaceArray& ) throw(); +}; + +template< typename E > +class CAutoPtrArray : + public CAtlArray< ATL::CAutoPtr< E >, CAutoPtrElementTraits< E > > +{ +public: + CAutoPtrArray() throw() + { + } + +private: + // Private to prevent use + CAutoPtrArray( const CAutoPtrArray& ) throw(); + CAutoPtrArray& operator=( const CAutoPtrArray& ) throw(); +}; + +template< typename E, class Allocator = ATL::CCRTAllocator > +class CHeapPtrArray : + public CAtlArray< ATL::CHeapPtr< E, Allocator >, CHeapPtrElementTraits< E, Allocator > > +{ +public: + CHeapPtrArray() throw() + { + } + +private: + // Private to prevent use + CHeapPtrArray( const CHeapPtrArray& ) throw(); + CHeapPtrArray& operator=( const CHeapPtrArray& ) throw(); +}; + +template< typename E, class ETraits > +inline size_t CAtlArray< E, ETraits >::GetCount() const throw() +{ + return( m_nSize ); +} + +template< typename E, class ETraits > +inline bool CAtlArray< E, ETraits >::IsEmpty() const throw() +{ + return( m_nSize == 0 ); +} + +template< typename E, class ETraits > +inline void CAtlArray< E, ETraits >::RemoveAll() throw() +{ + SetCount( 0, -1 ); +} + +template< typename E, class ETraits > +inline const E& CAtlArray< E, ETraits >::GetAt( size_t iElement ) const +{ + ATLASSERT( iElement < m_nSize ); + if(iElement >= m_nSize) + AtlThrow(E_INVALIDARG); + + return( m_pData[iElement] ); +} + +template< typename E, class ETraits > +inline void CAtlArray< E, ETraits >::SetAt( size_t iElement, INARGTYPE element ) +{ + ATLASSERT( iElement < m_nSize ); + if(iElement >= m_nSize) + AtlThrow(E_INVALIDARG); + + m_pData[iElement] = element; +} + +template< typename E, class ETraits > +inline E& CAtlArray< E, ETraits >::GetAt( size_t iElement ) +{ + ATLASSERT( iElement < m_nSize ); + if(iElement >= m_nSize) + AtlThrow(E_INVALIDARG); + + return( m_pData[iElement] ); +} + +template< typename E, class ETraits > +inline const E* CAtlArray< E, ETraits >::GetData() const throw() +{ + return( m_pData ); +} + +template< typename E, class ETraits > +inline E* CAtlArray< E, ETraits >::GetData() throw() +{ + return( m_pData ); +} + +template< typename E, class ETraits > +inline size_t CAtlArray< E, ETraits >::Add() +{ + size_t iElement; + + iElement = m_nSize; + bool bSuccess=SetCount( m_nSize+1 ); + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + + return( iElement ); +} + +#pragma push_macro("new") +#undef new + +template< typename E, class ETraits > +inline size_t CAtlArray< E, ETraits >::Add( INARGTYPE element ) +{ + size_t iElement; + + iElement = m_nSize; + if( iElement >= m_nMaxSize ) + { + bool bSuccess = GrowBuffer( iElement+1 ); + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + } + ::new( m_pData+iElement ) E( element ); + m_nSize++; + + return( iElement ); +} + +#pragma pop_macro("new") + +template< typename E, class ETraits > +inline const E& CAtlArray< E, ETraits >::operator[]( size_t iElement ) const +{ + ATLASSERT( iElement < m_nSize ); + if(iElement >= m_nSize) + AtlThrow(E_INVALIDARG); + + return( m_pData[iElement] ); +} + +template< typename E, class ETraits > +inline E& CAtlArray< E, ETraits >::operator[]( size_t iElement ) +{ + ATLASSERT( iElement < m_nSize ); + if(iElement >= m_nSize) + AtlThrow(E_INVALIDARG); + + return( m_pData[iElement] ); +} + +template< typename E, class ETraits > +CAtlArray< E, ETraits >::CAtlArray() throw(): + m_pData( NULL ), + m_nSize( 0 ), + m_nMaxSize( 0 ), + m_nGrowBy( 0 ) +{ +} + +template< typename E, class ETraits > +CAtlArray< E, ETraits >::~CAtlArray() throw() +{ + if( m_pData != NULL ) + { + CallDestructors( m_pData, m_nSize ); + free( m_pData ); + } +} + +template< typename E, class ETraits > +bool CAtlArray< E, ETraits >::GrowBuffer( size_t nNewSize ) +{ + if( nNewSize > m_nMaxSize ) + { + if( m_pData == NULL ) + { + size_t nAllocSize = size_t( m_nGrowBy ) > nNewSize ? size_t( m_nGrowBy ) : nNewSize ; + m_pData = static_cast< E* >( calloc( nAllocSize,sizeof( E ) ) ); + if( m_pData == NULL ) + { + return( false ); + } + m_nMaxSize = nAllocSize; + } + else + { + // otherwise, grow array + size_t nGrowBy = m_nGrowBy; + if( nGrowBy == 0 ) + { + // heuristically determine growth when nGrowBy == 0 + // (this avoids heap fragmentation in many situations) + nGrowBy = m_nSize/8; + nGrowBy = (nGrowBy < 4) ? 4 : ((nGrowBy > 1024) ? 1024 : nGrowBy); + } + size_t nNewMax; + if( nNewSize < (m_nMaxSize+nGrowBy) ) + nNewMax = m_nMaxSize+nGrowBy; // granularity + else + nNewMax = nNewSize; // no slush + + ATLASSERT( nNewMax >= m_nMaxSize ); // no wrap around +#ifdef SIZE_T_MAX + ATLASSERT( nNewMax <= SIZE_T_MAX/sizeof( E ) ); // no overflow +#endif + E* pNewData = static_cast< E* >( calloc( nNewMax,sizeof( E ) ) ); + if( pNewData == NULL ) + { + return false; + } + + // copy new data from old + ETraits::RelocateElements( pNewData, m_pData, m_nSize ); + + // get rid of old stuff (note: no destructors called) + free( m_pData ); + m_pData = pNewData; + m_nMaxSize = nNewMax; + } + } + + return true; +} + +template< typename E, class ETraits > +bool CAtlArray< E, ETraits >::SetCount( size_t nNewSize, int nGrowBy ) +{ + ATLASSERT_VALID(this); + + if( nGrowBy != -1 ) + { + m_nGrowBy = nGrowBy; // set new size + } + + if( nNewSize == 0 ) + { + // shrink to nothing + if( m_pData != NULL ) + { + CallDestructors( m_pData, m_nSize ); + free( m_pData ); + m_pData = NULL; + } + m_nSize = 0; + m_nMaxSize = 0; + } + else if( nNewSize <= m_nMaxSize ) + { + // it fits + if( nNewSize > m_nSize ) + { + // initialize the new elements + CallConstructors( m_pData+m_nSize, nNewSize-m_nSize ); + } + else if( m_nSize > nNewSize ) + { + // destroy the old elements + CallDestructors( m_pData+nNewSize, m_nSize-nNewSize ); + } + m_nSize = nNewSize; + } + else + { + bool bSuccess; + + bSuccess = GrowBuffer( nNewSize ); + if( !bSuccess ) + { + return( false ); + } + + // construct new elements + ATLASSERT( nNewSize > m_nSize ); + CallConstructors( m_pData+m_nSize, nNewSize-m_nSize ); + + m_nSize = nNewSize; + } + + return true; +} + +template< typename E, class ETraits > +size_t CAtlArray< E, ETraits >::Append( const CAtlArray< E, ETraits >& aSrc ) +{ + ATLASSERT_VALID(this); + ATLASSERT( this != &aSrc ); // cannot append to itself + + size_t nOldSize = m_nSize; + bool bSuccess=SetCount( m_nSize+aSrc.m_nSize ); + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + + ETraits::CopyElements( m_pData+nOldSize, aSrc.m_pData, aSrc.m_nSize ); + + return( nOldSize ); +} + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::Copy( const CAtlArray< E, ETraits >& aSrc ) +{ + ATLASSERT_VALID(this); + ATLASSERT( this != &aSrc ); // cannot append to itself + + bool bSuccess=SetCount( aSrc.m_nSize ); + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + + ETraits::CopyElements( m_pData, aSrc.m_pData, aSrc.m_nSize ); +} + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::FreeExtra() throw() +{ + ATLASSERT_VALID(this); + + if( m_nSize != m_nMaxSize ) + { + // shrink to desired size +#ifdef SIZE_T_MAX + ATLASSUME( m_nSize <= (SIZE_T_MAX/sizeof( E )) ); // no overflow +#endif + E* pNewData = NULL; + if( m_nSize != 0 ) + { + pNewData = (E*)calloc( m_nSize,sizeof( E ) ); + if( pNewData == NULL ) + { + return; + } + + // copy new data from old + ETraits::RelocateElements( pNewData, m_pData, m_nSize ); + } + + // get rid of old stuff (note: no destructors called) + free( m_pData ); + m_pData = pNewData; + m_nMaxSize = m_nSize; + } +} + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::SetAtGrow( size_t iElement, INARGTYPE element ) +{ + ATLASSERT_VALID(this); + size_t nOldSize; + + nOldSize = m_nSize; + if( iElement >= m_nSize ) + { + bool bSuccess=SetCount( iElement+1, -1 ); + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + } + + _ATLTRY + { + m_pData[iElement] = element; + } + _ATLCATCHALL() + { + if( m_nSize != nOldSize ) + { + SetCount( nOldSize, -1 ); + } + _ATLRETHROW; + } +} + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::InsertAt( size_t iElement, INARGTYPE element, size_t nElements /*=1*/) +{ + ATLASSERT_VALID(this); + ATLASSERT( nElements > 0 ); // zero size not allowed + + if( iElement >= m_nSize ) + { + // adding after the end of the array + bool bSuccess=SetCount( iElement+nElements, -1 ); // grow so nIndex is valid + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + } + else + { + // inserting in the middle of the array + size_t nOldSize = m_nSize; + bool bSuccess=SetCount( m_nSize+nElements, -1 ); // grow it to new size + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + // destroy intial data before copying over it + CallDestructors( m_pData+nOldSize, nElements ); + // shift old data up to fill gap + ETraits::RelocateElements( m_pData+(iElement+nElements), m_pData+iElement, + nOldSize-iElement ); + + _ATLTRY + { + // re-init slots we copied from + CallConstructors( m_pData+iElement, nElements ); + } + _ATLCATCHALL() + { + ETraits::RelocateElements( m_pData+iElement, m_pData+(iElement+nElements), + nOldSize-iElement ); + SetCount( nOldSize, -1 ); + _ATLRETHROW; + } + } + + // insert new value in the gap + ATLASSERT( (iElement+nElements) <= m_nSize ); + for( size_t iNewElement = iElement; iNewElement < (iElement+nElements); iNewElement++ ) + { + m_pData[iNewElement] = element; + } +} + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::RemoveAt( size_t iElement, size_t nElements ) +{ + ATLASSERT_VALID(this); + ATLASSERT( (iElement+nElements) <= m_nSize ); + + size_t newCount = iElement+nElements; + if ((newCount < iElement) || (newCount < nElements) || (newCount > m_nSize)) + AtlThrow(E_INVALIDARG); + + // just remove a range + size_t nMoveCount = m_nSize-(newCount); + CallDestructors( m_pData+iElement, nElements ); + if( nMoveCount > 0 ) + { + ETraits::RelocateElements( m_pData+iElement, m_pData+(newCount), + nMoveCount ); + } + m_nSize -= nElements; +} + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::InsertArrayAt( size_t iStartElement, + const CAtlArray< E, ETraits >* paNew ) +{ + ATLASSERT_VALID( this ); + ATLENSURE( paNew != NULL ); + ATLASSERT_VALID( paNew ); + + if( paNew->GetCount() > 0 ) + { + InsertAt( iStartElement, paNew->GetAt( 0 ), paNew->GetCount() ); + for( size_t iElement = 0; iElement < paNew->GetCount(); iElement++ ) + { + SetAt( iStartElement+iElement, paNew->GetAt( iElement ) ); + } + } +} + +#ifdef _DEBUG +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::AssertValid() const +{ + if( m_pData == NULL ) + { + ATLASSUME( m_nSize == 0 ); + ATLASSUME( m_nMaxSize == 0 ); + } + else + { + ATLASSUME( m_nSize <= m_nMaxSize ); + ATLASSERT( AtlIsValidAddress( m_pData, m_nMaxSize * sizeof( E ) ) ); + } +} +#endif + +#pragma push_macro("new") +#undef new + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::CallConstructors( E* pElements, size_t nElements ) +{ + size_t iElement = 0; + + _ATLTRY + { + for( iElement = 0; iElement < nElements; iElement++ ) + { + ::new( pElements+iElement ) E; + } + } + _ATLCATCHALL() + { + while( iElement > 0 ) + { + iElement--; + pElements[iElement].~E(); + } + + _ATLRETHROW; + } +} + +#pragma pop_macro("new") + +template< typename E, class ETraits > +void CAtlArray< E, ETraits >::CallDestructors( E* pElements, size_t nElements ) throw() +{ + (void)pElements; + + for( size_t iElement = 0; iElement < nElements; iElement++ ) + { + pElements[iElement].~E(); + } +} + + +template< typename E, class ETraits = CElementTraits< E > > +class CAtlList +{ +public: + typedef typename ETraits::INARGTYPE INARGTYPE; + +private: + class CNode : + public __POSITION + { + public: + CNode() + { + } + CNode( INARGTYPE element ) : + m_element( element ) + { + } + ~CNode() throw() + { + } + + public: + CNode* m_pNext; + CNode* m_pPrev; + E m_element; + + private: + CNode( const CNode& ) throw(); + }; + +public: + CAtlList( UINT nBlockSize = 10 ) throw(); + + size_t GetCount() const throw(); + bool IsEmpty() const throw(); + + E& GetHead(); + const E& GetHead() const; + E& GetTail(); + const E& GetTail() const; + + E RemoveHead(); + E RemoveTail(); + void RemoveHeadNoReturn() throw(); + void RemoveTailNoReturn() throw(); + + POSITION AddHead(); + POSITION AddHead( INARGTYPE element ); + void AddHeadList( const CAtlList< E, ETraits >* plNew ); + POSITION AddTail(); + POSITION AddTail( INARGTYPE element ); + void AddTailList( const CAtlList< E, ETraits >* plNew ); + + void RemoveAll() throw(); + + POSITION GetHeadPosition() const throw(); + POSITION GetTailPosition() const throw(); + E& GetNext( POSITION& pos ) throw(); + const E& GetNext( POSITION& pos ) const throw(); + E& GetPrev( POSITION& pos ) throw(); + const E& GetPrev( POSITION& pos ) const throw(); + + E& GetAt( POSITION pos ); + const E& GetAt( POSITION pos ) const; + void SetAt( POSITION pos, INARGTYPE element ); + void RemoveAt( POSITION pos ) throw(); + + POSITION InsertBefore( POSITION pos, INARGTYPE element ); + POSITION InsertAfter( POSITION pos, INARGTYPE element ); + + POSITION Find( INARGTYPE element, POSITION posStartAfter = NULL ) const throw(); + POSITION FindIndex( size_t iElement ) const throw(); + + void MoveToHead( POSITION pos ); + void MoveToTail( POSITION pos ); + void SwapElements( POSITION pos1, POSITION pos2 ) throw(); + +#ifdef _DEBUG + void AssertValid() const; +#endif // _DEBUG + +// Implementation +private: + CNode* m_pHead; + CNode* m_pTail; + size_t m_nElements; + CAtlPlex* m_pBlocks; + CNode* m_pFree; + UINT m_nBlockSize; + +private: + void GetFreeNode(); + CNode* NewNode( CNode* pPrev, CNode* pNext ); + CNode* NewNode( INARGTYPE element, CNode* pPrev, CNode* pNext ); + void FreeNode( CNode* pNode ) throw(); + +public: + ~CAtlList() throw(); + +private: + // Private to prevent use + CAtlList( const CAtlList& ) throw(); + CAtlList& operator=( const CAtlList& ) throw(); +}; + +template< class I, const IID* piid = &__uuidof( I ) > +class CInterfaceList : + public CAtlList< ATL::CComQIPtr< I, piid >, CComQIPtrElementTraits< I, piid > > +{ +public: + CInterfaceList( UINT nBlockSize = 10 ) throw() : + CAtlList< ATL::CComQIPtr< I, piid >, CComQIPtrElementTraits< I, piid > >( nBlockSize ) + { + } + +private: + // Private to prevent use + CInterfaceList( const CInterfaceList& ) throw(); + CInterfaceList& operator=( const CInterfaceList& ) throw(); +}; + +template< typename E > +class CAutoPtrList : + public CAtlList< ATL::CAutoPtr< E >, CAutoPtrElementTraits< E > > +{ +public: + CAutoPtrList( UINT nBlockSize = 10 ) throw() : + CAtlList< ATL::CAutoPtr< E >, CAutoPtrElementTraits< E > >( nBlockSize ) + { + } + +private: + // Private to prevent use + CAutoPtrList( const CAutoPtrList& ) throw(); + CAutoPtrList& operator=( const CAutoPtrList& ) throw(); +}; + +template< typename E, class Allocator = ATL::CCRTAllocator > +class CHeapPtrList : + public CAtlList< ATL::CHeapPtr< E, Allocator >, CHeapPtrElementTraits< E, Allocator > > +{ +public: + CHeapPtrList( UINT nBlockSize = 10 ) throw() : + CAtlList< ATL::CHeapPtr< E, Allocator >, CHeapPtrElementTraits< E, Allocator > >( nBlockSize ) + { + } + +private: + // Private to prevent use + CHeapPtrList( const CHeapPtrList& ) throw(); + CHeapPtrList& operator=( const CHeapPtrList& ) throw(); +}; + +template< typename E, class ETraits > +inline size_t CAtlList< E, ETraits >::GetCount() const throw() +{ + return( m_nElements ); +} + +template< typename E, class ETraits > +inline bool CAtlList< E, ETraits >::IsEmpty() const throw() +{ + return( m_nElements == 0 ); +} + +template< typename E, class ETraits > +inline E& CAtlList< E, ETraits >::GetHead() +{ + ATLENSURE( m_pHead != NULL ); + return( m_pHead->m_element ); +} + +template< typename E, class ETraits > +inline const E& CAtlList< E, ETraits >::GetHead() const +{ + ATLENSURE( m_pHead != NULL ); + return( m_pHead->m_element ); +} + +template< typename E, class ETraits > +inline E& CAtlList< E, ETraits >::GetTail() +{ + ATLENSURE( m_pTail != NULL ); + return( m_pTail->m_element ); +} + +template< typename E, class ETraits > +inline const E& CAtlList< E, ETraits >::GetTail() const +{ + ATLENSURE( m_pTail != NULL ); + return( m_pTail->m_element ); +} + +template< typename E, class ETraits > +inline POSITION CAtlList< E, ETraits >::GetHeadPosition() const throw() +{ + return( POSITION( m_pHead ) ); +} + +template< typename E, class ETraits > +inline POSITION CAtlList< E, ETraits >::GetTailPosition() const throw() +{ + return( POSITION( m_pTail ) ); +} + +template< typename E, class ETraits > +inline E& CAtlList< E, ETraits >::GetNext( POSITION& pos ) throw() +{ + CNode* pNode; + + ATLENSURE( pos != NULL ); + pNode = (CNode*)pos; + pos = POSITION( pNode->m_pNext ); + + return( pNode->m_element ); +} + +template< typename E, class ETraits > +inline const E& CAtlList< E, ETraits >::GetNext( POSITION& pos ) const throw() +{ + CNode* pNode; + + ATLENSURE( pos != NULL ); + pNode = (CNode*)pos; + pos = POSITION( pNode->m_pNext ); + + return( pNode->m_element ); +} + +template< typename E, class ETraits > +inline E& CAtlList< E, ETraits >::GetPrev( POSITION& pos ) throw() +{ + CNode* pNode; + + ATLENSURE( pos != NULL ); + pNode = (CNode*)pos; + pos = POSITION( pNode->m_pPrev ); + + return( pNode->m_element ); +} + +template< typename E, class ETraits > +inline const E& CAtlList< E, ETraits >::GetPrev( POSITION& pos ) const throw() +{ + CNode* pNode; + + ATLASSERT( pos != NULL ); + pNode = (CNode*)pos; + pos = POSITION( pNode->m_pPrev ); + + return( pNode->m_element ); +} + +template< typename E, class ETraits > +inline E& CAtlList< E, ETraits >::GetAt( POSITION pos ) +{ + ATLENSURE( pos != NULL ); + CNode* pNode = (CNode*)pos; + return( pNode->m_element ); +} + +template< typename E, class ETraits > +inline const E& CAtlList< E, ETraits >::GetAt( POSITION pos ) const +{ + ATLENSURE( pos != NULL ); + CNode* pNode = (CNode*)pos; + return( pNode->m_element ); +} + +template< typename E, class ETraits > +inline void CAtlList< E, ETraits >::SetAt( POSITION pos, INARGTYPE element ) +{ + ATLENSURE( pos != NULL ); + CNode* pNode = (CNode*)pos; + pNode->m_element = element; +} + +template< typename E, class ETraits > +CAtlList< E, ETraits >::CAtlList( UINT nBlockSize ) throw() : + m_nElements( 0 ), + m_pHead( NULL ), + m_pTail( NULL ), + m_nBlockSize( nBlockSize ), + m_pBlocks( NULL ), + m_pFree( NULL ) +{ + ATLASSERT( nBlockSize > 0 ); +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::RemoveAll() +{ + while( m_nElements > 0 ) + { + CNode* pKill = m_pHead; + ATLENSURE( pKill != NULL ); + + m_pHead = m_pHead->m_pNext; + FreeNode( pKill ); + } + + ATLASSUME( m_nElements == 0 ); + m_pHead = NULL; + m_pTail = NULL; + m_pFree = NULL; + + if( m_pBlocks != NULL ) + { + m_pBlocks->FreeDataChain(); + m_pBlocks = NULL; + } +} + +template< typename E, class ETraits > +CAtlList< E, ETraits >::~CAtlList() throw() +{ + RemoveAll(); + ATLASSUME( m_nElements == 0 ); +} + +#pragma push_macro("new") +#undef new + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::GetFreeNode() +{ + if( m_pFree == NULL ) + { + CAtlPlex* pPlex; + CNode* pNode; + + pPlex = CAtlPlex::Create( m_pBlocks, m_nBlockSize, sizeof( CNode ) ); + if( pPlex == NULL ) + { + AtlThrow( E_OUTOFMEMORY ); + } + pNode = (CNode*)pPlex->data(); + pNode += m_nBlockSize-1; + for( int iBlock = m_nBlockSize-1; iBlock >= 0; iBlock-- ) + { + pNode->m_pNext = m_pFree; + m_pFree = pNode; + pNode--; + } + } + ATLASSUME( m_pFree != NULL ); +} + +template< typename E, class ETraits > +typename CAtlList< E, ETraits >::CNode* CAtlList< E, ETraits >::NewNode( CNode* pPrev, CNode* pNext ) +{ + GetFreeNode(); + + CNode* pNewNode = m_pFree; + CNode* pNextFree = m_pFree->m_pNext; + + ::new( pNewNode ) CNode; + + m_pFree = pNextFree; + pNewNode->m_pPrev = pPrev; + pNewNode->m_pNext = pNext; + m_nElements++; + ATLASSUME( m_nElements > 0 ); + + return( pNewNode ); +} + +template< typename E, class ETraits > +typename CAtlList< E, ETraits >::CNode* CAtlList< E, ETraits >::NewNode( INARGTYPE element, CNode* pPrev, + CNode* pNext ) +{ + GetFreeNode(); + + CNode* pNewNode = m_pFree; + CNode* pNextFree = m_pFree->m_pNext; + + ::new( pNewNode ) CNode( element ); + + m_pFree = pNextFree; + pNewNode->m_pPrev = pPrev; + pNewNode->m_pNext = pNext; + m_nElements++; + ATLASSUME( m_nElements > 0 ); + + return( pNewNode ); +} + +#pragma pop_macro("new") + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::FreeNode( CNode* pNode ) throw() +{ + pNode->~CNode(); + pNode->m_pNext = m_pFree; + m_pFree = pNode; + ATLASSUME( m_nElements > 0 ); + m_nElements--; + if( m_nElements == 0 ) + { + RemoveAll(); + } +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::AddHead() +{ + CNode* pNode = NewNode( NULL, m_pHead ); + if( m_pHead != NULL ) + { + m_pHead->m_pPrev = pNode; + } + else + { + m_pTail = pNode; + } + m_pHead = pNode; + + return( POSITION( pNode ) ); +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::AddHead( INARGTYPE element ) +{ + CNode* pNode; + + pNode = NewNode( element, NULL, m_pHead ); + + if( m_pHead != NULL ) + { + m_pHead->m_pPrev = pNode; + } + else + { + m_pTail = pNode; + } + m_pHead = pNode; + + return( POSITION( pNode ) ); +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::AddTail() +{ + CNode* pNode = NewNode( m_pTail, NULL ); + if( m_pTail != NULL ) + { + m_pTail->m_pNext = pNode; + } + else + { + m_pHead = pNode; + } + m_pTail = pNode; + + return( POSITION( pNode ) ); +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::AddTail( INARGTYPE element ) +{ + CNode* pNode; + + pNode = NewNode( element, m_pTail, NULL ); + + if( m_pTail != NULL ) + { + m_pTail->m_pNext = pNode; + } + else + { + m_pHead = pNode; + } + m_pTail = pNode; + + return( POSITION( pNode ) ); +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::AddHeadList( const CAtlList< E, ETraits >* plNew ) +{ + ATLENSURE( plNew != NULL ); + + POSITION pos = plNew->GetTailPosition(); + while( pos != NULL ) + { + INARGTYPE element = plNew->GetPrev( pos ); + AddHead( element ); + } +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::AddTailList( const CAtlList< E, ETraits >* plNew ) +{ + ATLENSURE( plNew != NULL ); + + POSITION pos = plNew->GetHeadPosition(); + while( pos != NULL ) + { + INARGTYPE element = plNew->GetNext( pos ); + AddTail( element ); + } +} + +template< typename E, class ETraits > +E CAtlList< E, ETraits >::RemoveHead() +{ + ATLENSURE( m_pHead != NULL ); + + CNode* pNode = m_pHead; + E element( pNode->m_element ); + + m_pHead = pNode->m_pNext; + if( m_pHead != NULL ) + { + m_pHead->m_pPrev = NULL; + } + else + { + m_pTail = NULL; + } + FreeNode( pNode ); + + return( element ); +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::RemoveHeadNoReturn() +{ + ATLENSURE( m_pHead != NULL ); + + CNode* pNode = m_pHead; + + m_pHead = pNode->m_pNext; + if( m_pHead != NULL ) + { + m_pHead->m_pPrev = NULL; + } + else + { + m_pTail = NULL; + } + FreeNode( pNode ); +} + +template< typename E, class ETraits > +E CAtlList< E, ETraits >::RemoveTail() +{ + ATLENSURE( m_pTail != NULL ); + + CNode* pNode = m_pTail; + + E element( pNode->m_element ); + + m_pTail = pNode->m_pPrev; + if( m_pTail != NULL ) + { + m_pTail->m_pNext = NULL; + } + else + { + m_pHead = NULL; + } + FreeNode( pNode ); + + return( element ); +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::RemoveTailNoReturn() +{ + ATLENSURE( m_pTail != NULL ); + + CNode* pNode = m_pTail; + + m_pTail = pNode->m_pPrev; + if( m_pTail != NULL ) + { + m_pTail->m_pNext = NULL; + } + else + { + m_pHead = NULL; + } + FreeNode( pNode ); +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::InsertBefore( POSITION pos, INARGTYPE element ) +{ + ATLASSERT_VALID(this); + + if( pos == NULL ) + return AddHead( element ); // insert before nothing -> head of the list + + // Insert it before position + CNode* pOldNode = (CNode*)pos; + CNode* pNewNode = NewNode( element, pOldNode->m_pPrev, pOldNode ); + + if( pOldNode->m_pPrev != NULL ) + { + ATLASSERT(AtlIsValidAddress(pOldNode->m_pPrev, sizeof(CNode))); + pOldNode->m_pPrev->m_pNext = pNewNode; + } + else + { + ATLASSERT( pOldNode == m_pHead ); + m_pHead = pNewNode; + } + pOldNode->m_pPrev = pNewNode; + + return( POSITION( pNewNode ) ); +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::InsertAfter( POSITION pos, INARGTYPE element ) +{ + ATLASSERT_VALID(this); + + if( pos == NULL ) + return AddTail( element ); // insert after nothing -> tail of the list + + // Insert it after position + CNode* pOldNode = (CNode*)pos; + CNode* pNewNode = NewNode( element, pOldNode, pOldNode->m_pNext ); + + if( pOldNode->m_pNext != NULL ) + { + ATLASSERT(AtlIsValidAddress(pOldNode->m_pNext, sizeof(CNode))); + pOldNode->m_pNext->m_pPrev = pNewNode; + } + else + { + ATLASSERT( pOldNode == m_pTail ); + m_pTail = pNewNode; + } + pOldNode->m_pNext = pNewNode; + + return( POSITION( pNewNode ) ); +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::RemoveAt( POSITION pos ) +{ + ATLASSERT_VALID(this); + ATLENSURE( pos != NULL ); + + CNode* pOldNode = (CNode*)pos; + + // remove pOldNode from list + if( pOldNode == m_pHead ) + { + m_pHead = pOldNode->m_pNext; + } + else + { + ATLASSERT( AtlIsValidAddress( pOldNode->m_pPrev, sizeof(CNode) )); + pOldNode->m_pPrev->m_pNext = pOldNode->m_pNext; + } + if( pOldNode == m_pTail ) + { + m_pTail = pOldNode->m_pPrev; + } + else + { + ATLASSERT( AtlIsValidAddress( pOldNode->m_pNext, sizeof(CNode) )); + pOldNode->m_pNext->m_pPrev = pOldNode->m_pPrev; + } + FreeNode( pOldNode ); +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::FindIndex( size_t iElement ) const throw() +{ + ATLASSERT_VALID(this); + + if( iElement >= m_nElements ) + return NULL; // went too far + + if(m_pHead == NULL) + return NULL; + + CNode* pNode = m_pHead; + for( size_t iSearch = 0; iSearch < iElement; iSearch++ ) + { + pNode = pNode->m_pNext; + } + + return( POSITION( pNode ) ); +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::MoveToHead( POSITION pos ) +{ + ATLENSURE( pos != NULL ); + + CNode* pNode = static_cast< CNode* >( pos ); + + if( pNode == m_pHead ) + { + // Already at the head + return; + } + + if( pNode->m_pNext == NULL ) + { + ATLASSERT( pNode == m_pTail ); + m_pTail = pNode->m_pPrev; + } + else + { + pNode->m_pNext->m_pPrev = pNode->m_pPrev; + } + + ATLASSERT( pNode->m_pPrev != NULL ); // This node can't be the head, since we already checked that case + pNode->m_pPrev->m_pNext = pNode->m_pNext; + + m_pHead->m_pPrev = pNode; + pNode->m_pNext = m_pHead; + pNode->m_pPrev = NULL; + m_pHead = pNode; +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::MoveToTail( POSITION pos ) +{ + ATLENSURE( pos != NULL ); + CNode* pNode = static_cast< CNode* >( pos ); + + if( pNode == m_pTail ) + { + // Already at the tail + return; + } + + if( pNode->m_pPrev == NULL ) + { + ATLENSURE( pNode == m_pHead ); + m_pHead = pNode->m_pNext; + } + else + { + pNode->m_pPrev->m_pNext = pNode->m_pNext; + } + + pNode->m_pNext->m_pPrev = pNode->m_pPrev; + + m_pTail->m_pNext = pNode; + pNode->m_pPrev = m_pTail; + pNode->m_pNext = NULL; + m_pTail = pNode; +} + +template< typename E, class ETraits > +void CAtlList< E, ETraits >::SwapElements( POSITION pos1, POSITION pos2 ) throw() +{ + ATLASSERT( pos1 != NULL ); + ATLASSERT( pos2 != NULL ); + + if( pos1 == pos2 ) + { + // Nothing to do + return; + } + + CNode* pNode1 = static_cast< CNode* >( pos1 ); + CNode* pNode2 = static_cast< CNode* >( pos2 ); + if( pNode2->m_pNext == pNode1 ) + { + // Swap pNode2 and pNode1 so that the next case works + CNode* pNodeTemp = pNode1; + pNode1 = pNode2; + pNode2 = pNodeTemp; + } + if( pNode1->m_pNext == pNode2 ) + { + // Node1 and Node2 are adjacent + pNode2->m_pPrev = pNode1->m_pPrev; + if( pNode1->m_pPrev != NULL ) + { + pNode1->m_pPrev->m_pNext = pNode2; + } + else + { + ATLASSUME( m_pHead == pNode1 ); + m_pHead = pNode2; + } + pNode1->m_pNext = pNode2->m_pNext; + if( pNode2->m_pNext != NULL ) + { + pNode2->m_pNext->m_pPrev = pNode1; + } + else + { + ATLASSUME( m_pTail == pNode2 ); + m_pTail = pNode1; + } + pNode2->m_pNext = pNode1; + pNode1->m_pPrev = pNode2; + } + else + { + // The two nodes are not adjacent + CNode* pNodeTemp; + + pNodeTemp = pNode1->m_pPrev; + pNode1->m_pPrev = pNode2->m_pPrev; + pNode2->m_pPrev = pNodeTemp; + + pNodeTemp = pNode1->m_pNext; + pNode1->m_pNext = pNode2->m_pNext; + pNode2->m_pNext = pNodeTemp; + + if( pNode1->m_pNext != NULL ) + { + pNode1->m_pNext->m_pPrev = pNode1; + } + else + { + ATLASSUME( m_pTail == pNode2 ); + m_pTail = pNode1; + } + if( pNode1->m_pPrev != NULL ) + { + pNode1->m_pPrev->m_pNext = pNode1; + } + else + { + ATLASSUME( m_pHead == pNode2 ); + m_pHead = pNode1; + } + if( pNode2->m_pNext != NULL ) + { + pNode2->m_pNext->m_pPrev = pNode2; + } + else + { + ATLASSUME( m_pTail == pNode1 ); + m_pTail = pNode2; + } + if( pNode2->m_pPrev != NULL ) + { + pNode2->m_pPrev->m_pNext = pNode2; + } + else + { + ATLASSUME( m_pHead == pNode1 ); + m_pHead = pNode2; + } + } +} + +template< typename E, class ETraits > +POSITION CAtlList< E, ETraits >::Find( INARGTYPE element, POSITION posStartAfter ) const throw() +{ + ATLASSERT_VALID(this); + + CNode* pNode = (CNode*)posStartAfter; + if( pNode == NULL ) + { + pNode = m_pHead; // start at head + } + else + { + ATLASSERT(AtlIsValidAddress(pNode, sizeof(CNode))); + pNode = pNode->m_pNext; // start after the one specified + } + + for( ; pNode != NULL; pNode = pNode->m_pNext ) + { + if( ETraits::CompareElements( pNode->m_element, element ) ) + return( POSITION( pNode ) ); + } + + return( NULL ); +} + +#ifdef _DEBUG +template< typename E, class ETraits > +void CAtlList< E, ETraits >::AssertValid() const +{ + if( IsEmpty() ) + { + // empty list + ATLASSUME(m_pHead == NULL); + ATLASSUME(m_pTail == NULL); + } + else + { + // non-empty list + ATLASSERT(AtlIsValidAddress(m_pHead, sizeof(CNode))); + ATLASSERT(AtlIsValidAddress(m_pTail, sizeof(CNode))); + } +} +#endif + +template< typename K, typename V, class KTraits = CElementTraits< K >, class VTraits = CElementTraits< V > > +class CAtlMap +{ +public: + typedef typename KTraits::INARGTYPE KINARGTYPE; + typedef typename KTraits::OUTARGTYPE KOUTARGTYPE; + typedef typename VTraits::INARGTYPE VINARGTYPE; + typedef typename VTraits::OUTARGTYPE VOUTARGTYPE; + + class CPair : + public __POSITION + { + protected: + CPair( KINARGTYPE key ) : + m_key( key ) + { + } + + public: + const K m_key; + V m_value; + }; + +private: + class CNode : + public CPair + { + public: + CNode( KINARGTYPE key, UINT nHash ) : + CPair( key ), + m_nHash( nHash ) + { + } + + public: + UINT GetHash() const throw() + { + return( m_nHash ); + } + + public: + CNode* m_pNext; + UINT m_nHash; + }; + +public: + CAtlMap( UINT nBins = 17, float fOptimalLoad = 0.75f, + float fLoThreshold = 0.25f, float fHiThreshold = 2.25f, UINT nBlockSize = 10 ) throw(); + + size_t GetCount() const throw(); + bool IsEmpty() const throw(); + + bool Lookup( KINARGTYPE key, VOUTARGTYPE value ) const; + const CPair* Lookup( KINARGTYPE key ) const throw(); + CPair* Lookup( KINARGTYPE key ) throw(); + V& operator[]( KINARGTYPE key ) throw(...); + + POSITION SetAt( KINARGTYPE key, VINARGTYPE value ); + void SetValueAt( POSITION pos, VINARGTYPE value ); + + bool RemoveKey( KINARGTYPE key ) throw(); + void RemoveAll() throw(); + void RemoveAtPos( POSITION pos ) throw(); + + POSITION GetStartPosition() const throw(); + void GetNextAssoc( POSITION& pos, KOUTARGTYPE key, VOUTARGTYPE value ) const; + const CPair* GetNext( POSITION& pos ) const throw(); + CPair* GetNext( POSITION& pos ) throw(); + const K& GetNextKey( POSITION& pos ) const throw(); + const V& GetNextValue( POSITION& pos ) const throw(); + V& GetNextValue( POSITION& pos ) throw(); + void GetAt( POSITION pos, KOUTARGTYPE key, VOUTARGTYPE value ) const; + CPair* GetAt( POSITION pos ) throw(); + const CPair* GetAt( POSITION pos ) const throw(); + const K& GetKeyAt( POSITION pos ) const; + const V& GetValueAt( POSITION pos ) const; + V& GetValueAt( POSITION pos ); + + UINT GetHashTableSize() const throw(); + bool InitHashTable( UINT nBins, bool bAllocNow = true ); + void EnableAutoRehash() throw(); + void DisableAutoRehash() throw(); + void Rehash( UINT nBins = 0 ); + void SetOptimalLoad( float fOptimalLoad, float fLoThreshold, float fHiThreshold, + bool bRehashNow = false ); + +#ifdef _DEBUG + void AssertValid() const; +#endif // _DEBUG + +// Implementation +private: + CNode** m_ppBins; + size_t m_nElements; + UINT m_nBins; + float m_fOptimalLoad; + float m_fLoThreshold; + float m_fHiThreshold; + size_t m_nHiRehashThreshold; + size_t m_nLoRehashThreshold; + ULONG m_nLockCount; + UINT m_nBlockSize; + CAtlPlex* m_pBlocks; + CNode* m_pFree; + +private: + bool IsLocked() const throw(); + UINT PickSize( size_t nElements ) const throw(); + CNode* NewNode( KINARGTYPE key, UINT iBin, UINT nHash ); + void FreeNode( CNode* pNode ) throw(); + void FreePlexes() throw(); + CNode* GetNode( KINARGTYPE key, UINT& iBin, UINT& nHash, CNode*& pPrev ) const throw(); + CNode* CreateNode( KINARGTYPE key, UINT iBin, UINT nHash ) throw(...); + void RemoveNode( CNode* pNode, CNode* pPrev ) throw(); + CNode* FindNextNode( CNode* pNode ) const throw(); + void UpdateRehashThresholds() throw(); + +public: + ~CAtlMap() throw(); + +private: + // Private to prevent use + CAtlMap( const CAtlMap& ) throw(); + CAtlMap& operator=( const CAtlMap& ) throw(); +}; + +template< typename K, typename I, class KTraits = CElementTraits< K > > +class CMapToInterface : + public CAtlMap< K, ATL::CComQIPtr< I >, KTraits, CComQIPtrElementTraits< I > > +{ +public: + CMapToInterface( UINT nBins = 17 ) throw(); + +private: + // Private to prevent use + CMapToInterface( const CMapToInterface& ) throw(); + CMapToInterface& operator=( const CMapToInterface& ) throw(); +}; + +template< typename K, typename I, class KTraits > +inline CMapToInterface< K, I, KTraits >::CMapToInterface( UINT nBins ) throw() : + CAtlMap< K, ATL::CComQIPtr< I >, KTraits, CComQIPtrElementTraits< I > >( nBins ) +{ +} + +template< typename K, typename V, class KTraits = CElementTraits< K > > +class CMapToAutoPtr : + public CAtlMap< K, ATL::CAutoPtr< V >, KTraits, CAutoPtrElementTraits< V > > +{ +public: + CMapToAutoPtr( UINT nBins = 17 ) throw(); + +private: + // Private to prevent use + CMapToAutoPtr( const CMapToAutoPtr& ) throw(); + CMapToAutoPtr& operator=( const CMapToAutoPtr& ) throw(); +}; + +template< typename K, typename V, class KTraits > +inline CMapToAutoPtr< K, V, KTraits >::CMapToAutoPtr( UINT nBins ) throw() : + CAtlMap< K, ATL::CAutoPtr< V >, KTraits, CAutoPtrElementTraits< V > >( nBins ) +{ +} + +template< typename K, typename V, class KTraits, class VTraits > +inline size_t CAtlMap< K, V, KTraits, VTraits >::GetCount() const throw() +{ + return( m_nElements ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline bool CAtlMap< K, V, KTraits, VTraits >::IsEmpty() const throw() +{ + return( m_nElements == 0 ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline V& CAtlMap< K, V, KTraits, VTraits >::operator[]( KINARGTYPE key ) throw(...) +{ + CNode* pNode; + UINT iBin; + UINT nHash; + CNode* pPrev; + + pNode = GetNode( key, iBin, nHash, pPrev ); + if( pNode == NULL ) + { + pNode = CreateNode( key, iBin, nHash ); + } + + return( pNode->m_value ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline UINT CAtlMap< K, V, KTraits, VTraits >::GetHashTableSize() const throw() +{ + return( m_nBins ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline void CAtlMap< K, V, KTraits, VTraits >::GetAt( POSITION pos, KOUTARGTYPE key, VOUTARGTYPE value ) const +{ + ATLENSURE( pos != NULL ); + + CNode* pNode = static_cast< CNode* >( pos ); + + key = pNode->m_key; + value = pNode->m_value; +} + +template< typename K, typename V, class KTraits, class VTraits > +inline typename CAtlMap< K, V, KTraits, VTraits >::CPair* CAtlMap< K, V, KTraits, VTraits >::GetAt( POSITION pos ) throw() +{ + ATLASSERT( pos != NULL ); + + return( static_cast< CPair* >( pos ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline const typename CAtlMap< K, V, KTraits, VTraits >::CPair* CAtlMap< K, V, KTraits, VTraits >::GetAt( POSITION pos ) const throw() +{ + ATLASSERT( pos != NULL ); + + return( static_cast< const CPair* >( pos ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline const K& CAtlMap< K, V, KTraits, VTraits >::GetKeyAt( POSITION pos ) const +{ + ATLENSURE( pos != NULL ); + + CNode* pNode = (CNode*)pos; + + return( pNode->m_key ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline const V& CAtlMap< K, V, KTraits, VTraits >::GetValueAt( POSITION pos ) const +{ + ATLENSURE( pos != NULL ); + + CNode* pNode = (CNode*)pos; + + return( pNode->m_value ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline V& CAtlMap< K, V, KTraits, VTraits >::GetValueAt( POSITION pos ) +{ + ATLENSURE( pos != NULL ); + + CNode* pNode = (CNode*)pos; + + return( pNode->m_value ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline void CAtlMap< K, V, KTraits, VTraits >::DisableAutoRehash() throw() +{ + m_nLockCount++; +} + +template< typename K, typename V, class KTraits, class VTraits > +inline void CAtlMap< K, V, KTraits, VTraits >::EnableAutoRehash() throw() +{ + ATLASSUME( m_nLockCount > 0 ); + m_nLockCount--; +} + +template< typename K, typename V, class KTraits, class VTraits > +inline bool CAtlMap< K, V, KTraits, VTraits >::IsLocked() const throw() +{ + return( m_nLockCount != 0 ); +} + +template< typename K, typename V, class KTraits, class VTraits > +UINT CAtlMap< K, V, KTraits, VTraits >::PickSize( size_t nElements ) const throw() +{ + // List of primes such that s_anPrimes[i] is the smallest prime greater than 2^(5+i/3) + static const UINT s_anPrimes[] = + { + 17, 23, 29, 37, 41, 53, 67, 83, 103, 131, 163, 211, 257, 331, 409, 521, 647, 821, + 1031, 1291, 1627, 2053, 2591, 3251, 4099, 5167, 6521, 8209, 10331, + 13007, 16411, 20663, 26017, 32771, 41299, 52021, 65537, 82571, 104033, + 131101, 165161, 208067, 262147, 330287, 416147, 524309, 660563, + 832291, 1048583, 1321139, 1664543, 2097169, 2642257, 3329023, 4194319, + 5284493, 6658049, 8388617, 10568993, 13316089, UINT_MAX + }; + + size_t nBins = (size_t)(nElements/m_fOptimalLoad); + UINT nBinsEstimate = UINT( UINT_MAX < nBins ? UINT_MAX : nBins ); + + // Find the smallest prime greater than our estimate + int iPrime = 0; + while( nBinsEstimate > s_anPrimes[iPrime] ) + { + iPrime++; + } + + if( s_anPrimes[iPrime] == UINT_MAX ) + { + return( nBinsEstimate ); + } + else + { + return( s_anPrimes[iPrime] ); + } +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CAtlMap< K, V, KTraits, VTraits >::CNode* CAtlMap< K, V, KTraits, VTraits >::CreateNode( + KINARGTYPE key, UINT iBin, UINT nHash ) throw(...) +{ + CNode* pNode; + + if( m_ppBins == NULL ) + { + bool bSuccess; + + bSuccess = InitHashTable( m_nBins ); + if( !bSuccess ) + { + AtlThrow( E_OUTOFMEMORY ); + } + } + + pNode = NewNode( key, iBin, nHash ); + + return( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CAtlMap< K, V, KTraits, VTraits >::GetStartPosition() const throw() +{ + if( IsEmpty() ) + { + return( NULL ); + } + + for( UINT iBin = 0; iBin < m_nBins; iBin++ ) + { + if( m_ppBins[iBin] != NULL ) + { + return( POSITION( m_ppBins[iBin] ) ); + } + } + ATLASSERT( false ); + + return( NULL ); +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CAtlMap< K, V, KTraits, VTraits >::SetAt( KINARGTYPE key, VINARGTYPE value ) +{ + CNode* pNode; + UINT iBin; + UINT nHash; + CNode* pPrev; + + pNode = GetNode( key, iBin, nHash, pPrev ); + if( pNode == NULL ) + { + pNode = CreateNode( key, iBin, nHash ); + _ATLTRY + { + pNode->m_value = value; + } + _ATLCATCHALL() + { + RemoveAtPos( POSITION( pNode ) ); + _ATLRETHROW; + } + } + else + { + pNode->m_value = value; + } + + return( POSITION( pNode ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::SetValueAt( POSITION pos, VINARGTYPE value ) +{ + ATLASSERT( pos != NULL ); + + CNode* pNode = static_cast< CNode* >( pos ); + + pNode->m_value = value; +} + +template< typename K, typename V, class KTraits, class VTraits > +CAtlMap< K, V, KTraits, VTraits >::CAtlMap( UINT nBins, float fOptimalLoad, + float fLoThreshold, float fHiThreshold, UINT nBlockSize ) throw() : + m_ppBins( NULL ), + m_nBins( nBins ), + m_nElements( 0 ), + m_nLockCount( 0 ), // Start unlocked + m_fOptimalLoad( fOptimalLoad ), + m_fLoThreshold( fLoThreshold ), + m_fHiThreshold( fHiThreshold ), + m_nHiRehashThreshold( UINT_MAX ), + m_nLoRehashThreshold( 0 ), + m_pBlocks( NULL ), + m_pFree( NULL ), + m_nBlockSize( nBlockSize ) +{ + ATLASSERT( nBins > 0 ); + ATLASSERT( nBlockSize > 0 ); + + SetOptimalLoad( fOptimalLoad, fLoThreshold, fHiThreshold, false ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::SetOptimalLoad( float fOptimalLoad, float fLoThreshold, + float fHiThreshold, bool bRehashNow ) +{ + ATLASSERT( fOptimalLoad > 0 ); + ATLASSERT( (fLoThreshold >= 0) && (fLoThreshold < fOptimalLoad) ); + ATLASSERT( fHiThreshold > fOptimalLoad ); + + m_fOptimalLoad = fOptimalLoad; + m_fLoThreshold = fLoThreshold; + m_fHiThreshold = fHiThreshold; + + UpdateRehashThresholds(); + + if( bRehashNow && ((m_nElements > m_nHiRehashThreshold) || + (m_nElements < m_nLoRehashThreshold)) ) + { + Rehash( PickSize( m_nElements ) ); + } +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::UpdateRehashThresholds() throw() +{ + m_nHiRehashThreshold = size_t( m_fHiThreshold*m_nBins ); + m_nLoRehashThreshold = size_t( m_fLoThreshold*m_nBins ); + if( m_nLoRehashThreshold < 17 ) + { + m_nLoRehashThreshold = 0; + } +} + +template< typename K, typename V, class KTraits, class VTraits > +bool CAtlMap< K, V, KTraits, VTraits >::InitHashTable( UINT nBins, bool bAllocNow ) +{ + ATLASSUME( m_nElements == 0 ); + ATLASSERT( nBins > 0 ); + + if( m_ppBins != NULL ) + { + delete[] m_ppBins; + m_ppBins = NULL; + } + + if( bAllocNow) + { + if (nBins > SIZE_MAX / sizeof( CNode* )) + { + ATLASSERT(false); + return false; + } + ATLTRY( m_ppBins = new CNode*[nBins] ); + if( m_ppBins == NULL ) + { + return false; + } + memset( m_ppBins, 0, sizeof( CNode* )*nBins); + } + m_nBins = nBins; + + UpdateRehashThresholds(); + + return true; +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::RemoveAll() throw() +{ + DisableAutoRehash(); + if( m_ppBins != NULL ) + { + for( UINT iBin = 0; iBin < m_nBins; iBin++ ) + { + CNode* pNext; + + pNext = m_ppBins[iBin]; + while( pNext != NULL ) + { + CNode* pKill; + + pKill = pNext; + pNext = pNext->m_pNext; + FreeNode( pKill ); + } + } + } + + delete[] m_ppBins; + m_ppBins = NULL; + m_nElements = 0; + + if( !IsLocked() ) + { + InitHashTable( PickSize( m_nElements ), false ); + } + + FreePlexes(); + EnableAutoRehash(); +} + +template< typename K, typename V, class KTraits, class VTraits > +CAtlMap< K, V, KTraits, VTraits >::~CAtlMap() throw() +{ + RemoveAll(); +} + +#pragma push_macro("new") +#undef new + +template< typename K, typename V, class KTraits, class VTraits > +typename CAtlMap< K, V, KTraits, VTraits >::CNode* CAtlMap< K, V, KTraits, VTraits >::NewNode( + KINARGTYPE key, UINT iBin, UINT nHash ) +{ + CNode* pNewNode; + + if( m_pFree == NULL ) + { + CAtlPlex* pPlex; + CNode* pNode; + + pPlex = CAtlPlex::Create( m_pBlocks, m_nBlockSize, sizeof( CNode ) ); + if( pPlex == NULL ) + { + AtlThrow( E_OUTOFMEMORY ); + } + pNode = (CNode*)pPlex->data(); + pNode += m_nBlockSize-1; + for( int iBlock = m_nBlockSize-1; iBlock >= 0; iBlock-- ) + { + pNode->m_pNext = m_pFree; + m_pFree = pNode; + pNode--; + } + } + ATLENSURE(m_pFree != NULL ); + pNewNode = m_pFree; + m_pFree = pNewNode->m_pNext; + + _ATLTRY + { + ::new( pNewNode ) CNode( key, nHash ); + } + _ATLCATCHALL() + { + pNewNode->m_pNext = m_pFree; + m_pFree = pNewNode; + + _ATLRETHROW; + } + m_nElements++; + + pNewNode->m_pNext = m_ppBins[iBin]; + m_ppBins[iBin] = pNewNode; + + if( (m_nElements > m_nHiRehashThreshold) && !IsLocked() ) + { + Rehash( PickSize( m_nElements ) ); + } + + return( pNewNode ); +} + +#pragma pop_macro("new") + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::FreeNode( CNode* pNode ) throw() +{ + ATLENSURE( pNode != NULL ); + + pNode->~CNode(); + pNode->m_pNext = m_pFree; + m_pFree = pNode; + + ATLASSUME( m_nElements > 0 ); + m_nElements--; + + if( (m_nElements < m_nLoRehashThreshold) && !IsLocked() ) + { + Rehash( PickSize( m_nElements ) ); + } + + if( m_nElements == 0 ) + { + FreePlexes(); + } +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::FreePlexes() throw() +{ + m_pFree = NULL; + if( m_pBlocks != NULL ) + { + m_pBlocks->FreeDataChain(); + m_pBlocks = NULL; + } +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CAtlMap< K, V, KTraits, VTraits >::CNode* CAtlMap< K, V, KTraits, VTraits >::GetNode( + KINARGTYPE key, UINT& iBin, UINT& nHash, CNode*& pPrev ) const throw() +{ + CNode* pFollow; + + nHash = KTraits::Hash( key ); + iBin = nHash%m_nBins; + + if( m_ppBins == NULL ) + { + return( NULL ); + } + + pFollow = NULL; + pPrev = NULL; + for( CNode* pNode = m_ppBins[iBin]; pNode != NULL; pNode = pNode->m_pNext ) + { + if( (pNode->GetHash() == nHash) && KTraits::CompareElements( pNode->m_key, key ) ) + { + pPrev = pFollow; + return( pNode ); + } + pFollow = pNode; + } + + return( NULL ); +} + +template< typename K, typename V, class KTraits, class VTraits > +bool CAtlMap< K, V, KTraits, VTraits >::Lookup( KINARGTYPE key, VOUTARGTYPE value ) const +{ + UINT iBin; + UINT nHash; + CNode* pNode; + CNode* pPrev; + + pNode = GetNode( key, iBin, nHash, pPrev ); + if( pNode == NULL ) + { + return( false ); + } + + value = pNode->m_value; + + return( true ); +} + +template< typename K, typename V, class KTraits, class VTraits > +const typename CAtlMap< K, V, KTraits, VTraits >::CPair* CAtlMap< K, V, KTraits, VTraits >::Lookup( KINARGTYPE key ) const throw() +{ + UINT iBin; + UINT nHash; + CNode* pNode; + CNode* pPrev; + + pNode = GetNode( key, iBin, nHash, pPrev ); + + return( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CAtlMap< K, V, KTraits, VTraits >::CPair* CAtlMap< K, V, KTraits, VTraits >::Lookup( KINARGTYPE key ) throw() +{ + UINT iBin; + UINT nHash; + CNode* pNode; + CNode* pPrev; + + pNode = GetNode( key, iBin, nHash, pPrev ); + + return( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +bool CAtlMap< K, V, KTraits, VTraits >::RemoveKey( KINARGTYPE key ) throw() +{ + CNode* pNode; + UINT iBin; + UINT nHash; + CNode* pPrev; + + pPrev = NULL; + pNode = GetNode( key, iBin, nHash, pPrev ); + if( pNode == NULL ) + { + return( false ); + } + + RemoveNode( pNode, pPrev ); + + return( true ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::RemoveNode( CNode* pNode, CNode* pPrev ) +{ + ATLENSURE( pNode != NULL ); + + UINT iBin = pNode->GetHash() % m_nBins; + + if( pPrev == NULL ) + { + ATLASSUME( m_ppBins[iBin] == pNode ); + m_ppBins[iBin] = pNode->m_pNext; + } + else + { + ATLASSERT( pPrev->m_pNext == pNode ); + pPrev->m_pNext = pNode->m_pNext; + } + FreeNode( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::RemoveAtPos( POSITION pos ) +{ + ATLENSURE( pos != NULL ); + + CNode* pNode = static_cast< CNode* >( pos ); + CNode* pPrev = NULL; + UINT iBin = pNode->GetHash() % m_nBins; + + ATLASSUME( m_ppBins[iBin] != NULL ); + if( pNode == m_ppBins[iBin] ) + { + pPrev = NULL; + } + else + { + pPrev = m_ppBins[iBin]; + while( pPrev->m_pNext != pNode ) + { + pPrev = pPrev->m_pNext; + ATLASSERT( pPrev != NULL ); + } + } + RemoveNode( pNode, pPrev ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::Rehash( UINT nBins ) +{ + CNode** ppBins = NULL; + + if( nBins == 0 ) + { + nBins = PickSize( m_nElements ); + } + + if( nBins == m_nBins ) + { + return; + } + + ATLTRACE(atlTraceMap, 2, _T("Rehash: %u bins\n"), nBins ); + + if( m_ppBins == NULL ) + { + // Just set the new number of bins + InitHashTable( nBins, false ); + return; + } + + ATLTRY(ppBins = new CNode*[nBins]); + if (ppBins == NULL) + { + AtlThrow( E_OUTOFMEMORY ); + } + + memset( ppBins, 0, nBins*sizeof( CNode* ) ); + + // Nothing gets copied. We just rewire the old nodes + // into the new bins. + for( UINT iSrcBin = 0; iSrcBin < m_nBins; iSrcBin++ ) + { + CNode* pNode; + + pNode = m_ppBins[iSrcBin]; + while( pNode != NULL ) + { + CNode* pNext; + UINT iDestBin; + + pNext = pNode->m_pNext; // Save so we don't trash it + iDestBin = pNode->GetHash()%nBins; + pNode->m_pNext = ppBins[iDestBin]; + ppBins[iDestBin] = pNode; + + pNode = pNext; + } + } + + delete[] m_ppBins; + m_ppBins = ppBins; + m_nBins = nBins; + + UpdateRehashThresholds(); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::GetNextAssoc( POSITION& pos, KOUTARGTYPE key, + VOUTARGTYPE value ) const +{ + CNode* pNode; + CNode* pNext; + + ATLASSUME( m_ppBins != NULL ); + ATLENSURE( pos != NULL ); + + pNode = (CNode*)pos; + pNext = FindNextNode( pNode ); + + pos = POSITION( pNext ); + key = pNode->m_key; + value = pNode->m_value; +} + +template< typename K, typename V, class KTraits, class VTraits > +const typename CAtlMap< K, V, KTraits, VTraits >::CPair* CAtlMap< K, V, KTraits, VTraits >::GetNext( POSITION& pos ) const throw() +{ + CNode* pNode; + CNode* pNext; + + ATLASSUME( m_ppBins != NULL ); + ATLASSERT( pos != NULL ); + + pNode = (CNode*)pos; + pNext = FindNextNode( pNode ); + + pos = POSITION( pNext ); + + return( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CAtlMap< K, V, KTraits, VTraits >::CPair* CAtlMap< K, V, KTraits, VTraits >::GetNext( + POSITION& pos ) throw() +{ + ATLASSUME( m_ppBins != NULL ); + ATLASSERT( pos != NULL ); + + CNode* pNode = static_cast< CNode* >( pos ); + CNode* pNext = FindNextNode( pNode ); + + pos = POSITION( pNext ); + + return( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +const K& CAtlMap< K, V, KTraits, VTraits >::GetNextKey( POSITION& pos ) const throw() +{ + CNode* pNode; + CNode* pNext; + + ATLASSUME( m_ppBins != NULL ); + ATLENSURE( pos != NULL ); + + pNode = (CNode*)pos; + pNext = FindNextNode( pNode ); + + pos = POSITION( pNext ); + + return( pNode->m_key ); +} + +template< typename K, typename V, class KTraits, class VTraits > +const V& CAtlMap< K, V, KTraits, VTraits >::GetNextValue( POSITION& pos ) const throw() +{ + CNode* pNode; + CNode* pNext; + + ATLASSUME( m_ppBins != NULL ); + ATLENSURE( pos != NULL ); + + pNode = (CNode*)pos; + pNext = FindNextNode( pNode ); + + pos = POSITION( pNext ); + + return( pNode->m_value ); +} + +template< typename K, typename V, class KTraits, class VTraits > +V& CAtlMap< K, V, KTraits, VTraits >::GetNextValue( POSITION& pos ) throw() +{ + CNode* pNode; + CNode* pNext; + + ATLASSUME( m_ppBins != NULL ); + ATLENSURE( pos != NULL ); + + pNode = (CNode*)pos; + pNext = FindNextNode( pNode ); + + pos = POSITION( pNext ); + + return( pNode->m_value ); +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CAtlMap< K, V, KTraits, VTraits >::CNode* CAtlMap< K, V, KTraits, VTraits >::FindNextNode( CNode* pNode ) const throw() +{ + CNode* pNext; + + if(pNode == NULL) + { + ATLASSERT(FALSE); + return NULL; + } + + if( pNode->m_pNext != NULL ) + { + pNext = pNode->m_pNext; + } + else + { + UINT iBin; + + pNext = NULL; + iBin = (pNode->GetHash()%m_nBins)+1; + while( (pNext == NULL) && (iBin < m_nBins) ) + { + if( m_ppBins[iBin] != NULL ) + { + pNext = m_ppBins[iBin]; + } + + iBin++; + } + } + + return( pNext ); +} + +#ifdef _DEBUG +template< typename K, typename V, class KTraits, class VTraits > +void CAtlMap< K, V, KTraits, VTraits >::AssertValid() const +{ + ATLASSUME( m_nBins > 0 ); + // non-empty map should have hash table + ATLASSERT( IsEmpty() || (m_ppBins != NULL) ); +} +#endif + +#pragma push_macro("new") +#undef new + +// +// The red-black tree code is based on the the descriptions in +// "Introduction to Algorithms", by Cormen, Leiserson, and Rivest +// +template< typename K, typename V, class KTraits = CElementTraits< K >, class VTraits = CElementTraits< V > > +class CRBTree +{ +public: + typedef typename KTraits::INARGTYPE KINARGTYPE; + typedef typename KTraits::OUTARGTYPE KOUTARGTYPE; + typedef typename VTraits::INARGTYPE VINARGTYPE; + typedef typename VTraits::OUTARGTYPE VOUTARGTYPE; + +public: + class CPair : + public __POSITION + { + protected: + + CPair( KINARGTYPE key, VINARGTYPE value ) : + m_key( key ), + m_value( value ) + { + } + ~CPair() throw() + { + } + + public: + const K m_key; + V m_value; + }; + +private: + + class CNode : + public CPair + { + public: + enum RB_COLOR + { + RB_RED, + RB_BLACK + }; + + public: + RB_COLOR m_eColor; + CNode* m_pLeft; + CNode* m_pRight; + CNode* m_pParent; + + CNode( KINARGTYPE key, VINARGTYPE value ) : + CPair( key, value ), + m_pParent( NULL ), + m_eColor( RB_BLACK ) + { + } + ~CNode() throw() + { + } + }; + +private: + CNode* m_pRoot; + size_t m_nCount; + CNode* m_pFree; + CAtlPlex* m_pBlocks; + size_t m_nBlockSize; + + // sentinel node + CNode *m_pNil; + + // methods + bool IsNil(CNode *p) const throw(); + void SetNil(CNode **p) throw(); + + CNode* NewNode( KINARGTYPE key, VINARGTYPE value ) throw( ... ); + void FreeNode(CNode* pNode) throw(); + void RemovePostOrder(CNode* pNode) throw(); + CNode* LeftRotate(CNode* pNode) throw(); + CNode* RightRotate(CNode* pNode) throw(); + void SwapNode(CNode* pDest, CNode* pSrc) throw(); + CNode* InsertImpl( KINARGTYPE key, VINARGTYPE value ) throw( ... ); + void RBDeleteFixup(CNode* pNode) throw(); + bool RBDelete(CNode* pZ) throw(); + +#ifdef _DEBUG + + // internal debugging code to verify red-black properties of tree: + // 1) Every node is either red or black + // 2) Every leaf (NIL) is black + // 3) If a node is red, both its children are black + // 4) Every simple path from a node to a descendant leaf node contains + // the same number of black nodes +private: + void VerifyIntegrity(const CNode *pNode, int nCurrBlackDepth, int &nBlackDepth) const throw(); + +public: + void VerifyIntegrity() const throw(); + +#endif // _DEBUG + +protected: + CNode* Minimum(CNode* pNode) const throw(); + CNode* Maximum(CNode* pNode) const throw(); + CNode* Predecessor( CNode* pNode ) const throw(); + CNode* Successor(CNode* pNode) const throw(); + CNode* RBInsert( KINARGTYPE key, VINARGTYPE value ) throw( ... ); + CNode* Find(KINARGTYPE key) const throw(); + CNode* FindPrefix( KINARGTYPE key ) const throw(); + +protected: + explicit CRBTree( size_t nBlockSize = 10 ) throw(); // protected to prevent instantiation + +public: + ~CRBTree() throw(); + + void RemoveAll() throw(); + void RemoveAt(POSITION pos) throw(); + + size_t GetCount() const throw(); + bool IsEmpty() const throw(); + + POSITION FindFirstKeyAfter( KINARGTYPE key ) const throw(); + + POSITION GetHeadPosition() const throw(); + POSITION GetTailPosition() const throw(); + void GetNextAssoc( POSITION& pos, KOUTARGTYPE key, VOUTARGTYPE value ) const; + const CPair* GetNext(POSITION& pos) const throw(); + CPair* GetNext(POSITION& pos) throw(); + const CPair* GetPrev(POSITION& pos) const throw(); + CPair* GetPrev(POSITION& pos) throw(); + const K& GetNextKey(POSITION& pos) const throw(); + const V& GetNextValue(POSITION& pos) const throw(); + V& GetNextValue(POSITION& pos) throw(); + + CPair* GetAt( POSITION pos ) throw(); + const CPair* GetAt( POSITION pos ) const throw(); + void GetAt(POSITION pos, KOUTARGTYPE key, VOUTARGTYPE value) const; + const K& GetKeyAt(POSITION pos) const; + const V& GetValueAt(POSITION pos) const; + V& GetValueAt(POSITION pos); + void SetValueAt(POSITION pos, VINARGTYPE value); + +private: + // Private to prevent use + CRBTree( const CRBTree& ) throw(); + CRBTree& operator=( const CRBTree& ) throw(); +}; + +template< typename K, typename V, class KTraits, class VTraits > +inline bool CRBTree< K, V, KTraits, VTraits >::IsNil(CNode *p) const throw() +{ + return ( p == m_pNil ); +} + +template< typename K, typename V, class KTraits, class VTraits > +inline void CRBTree< K, V, KTraits, VTraits >::SetNil(CNode **p) +{ + ATLENSURE( p != NULL ); + *p = m_pNil; +} + +template< typename K, typename V, class KTraits, class VTraits > +CRBTree< K, V, KTraits, VTraits >::CRBTree( size_t nBlockSize ) throw() : + m_pRoot( NULL ), + m_nCount( 0 ), + m_nBlockSize( nBlockSize ), + m_pFree( NULL ), + m_pBlocks( NULL ), + m_pNil( NULL ) +{ + ATLASSERT( nBlockSize > 0 ); +} + +template< typename K, typename V, class KTraits, class VTraits > +CRBTree< K, V, KTraits, VTraits >::~CRBTree() throw() +{ + RemoveAll(); + if (m_pNil != NULL) + { + free(m_pNil); + } +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::RemoveAll() throw() +{ + if (!IsNil(m_pRoot)) + RemovePostOrder(m_pRoot); + m_nCount = 0; + m_pBlocks->FreeDataChain(); + m_pBlocks = NULL; + m_pFree = NULL; + m_pRoot = m_pNil; +} + +template< typename K, typename V, class KTraits, class VTraits > +size_t CRBTree< K, V, KTraits, VTraits >::GetCount() const throw() +{ + return m_nCount; +} + +template< typename K, typename V, class KTraits, class VTraits > +bool CRBTree< K, V, KTraits, VTraits >::IsEmpty() const throw() +{ + return( m_nCount == 0 ); +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CRBTree< K, V, KTraits, VTraits >::FindFirstKeyAfter( KINARGTYPE key ) const throw() +{ + return( FindPrefix( key ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::RemoveAt(POSITION pos) throw() +{ + ATLASSERT(pos != NULL); + RBDelete(static_cast(pos)); +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CRBTree< K, V, KTraits, VTraits >::GetHeadPosition() const throw() +{ + return( Minimum( m_pRoot ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CRBTree< K, V, KTraits, VTraits >::GetTailPosition() const throw() +{ + return( Maximum( m_pRoot ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::GetNextAssoc( POSITION& pos, KOUTARGTYPE key, VOUTARGTYPE value ) const +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast< CNode* >(pos); + + key = pNode->m_key; + value = pNode->m_value; + + pos = Successor(pNode); +} + +template< typename K, typename V, class KTraits, class VTraits > +const typename CRBTree< K, V, KTraits, VTraits >::CPair* CRBTree< K, V, KTraits, VTraits >::GetNext(POSITION& pos) const throw() +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast< CNode* >(pos); + pos = Successor(pNode); + return pNode; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CPair* CRBTree< K, V, KTraits, VTraits >::GetNext(POSITION& pos) throw() +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast< CNode* >(pos); + pos = Successor(pNode); + return pNode; +} + +template< typename K, typename V, class KTraits, class VTraits > +const typename CRBTree< K, V, KTraits, VTraits >::CPair* CRBTree< K, V, KTraits, VTraits >::GetPrev(POSITION& pos) const throw() +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast< CNode* >(pos); + pos = Predecessor(pNode); + + return pNode; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CPair* CRBTree< K, V, KTraits, VTraits >::GetPrev(POSITION& pos) throw() +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast< CNode* >(pos); + pos = Predecessor(pNode); + + return pNode; +} + +template< typename K, typename V, class KTraits, class VTraits > +const K& CRBTree< K, V, KTraits, VTraits >::GetNextKey(POSITION& pos) const throw() +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast(pos); + pos = Successor(pNode); + + return pNode->m_key; +} + +template< typename K, typename V, class KTraits, class VTraits > +const V& CRBTree< K, V, KTraits, VTraits >::GetNextValue(POSITION& pos) const throw() +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast(pos); + pos = Successor(pNode); + + return pNode->m_value; +} + +template< typename K, typename V, class KTraits, class VTraits > +V& CRBTree< K, V, KTraits, VTraits >::GetNextValue(POSITION& pos) throw() +{ + ATLASSERT(pos != NULL); + CNode* pNode = static_cast(pos); + pos = Successor(pNode); + + return pNode->m_value; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CPair* CRBTree< K, V, KTraits, VTraits >::GetAt( POSITION pos ) throw() +{ + ATLASSERT( pos != NULL ); + + return( static_cast< CPair* >( pos ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +const typename CRBTree< K, V, KTraits, VTraits >::CPair* CRBTree< K, V, KTraits, VTraits >::GetAt( POSITION pos ) const throw() +{ + ATLASSERT( pos != NULL ); + + return( static_cast< const CPair* >( pos ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::GetAt(POSITION pos, KOUTARGTYPE key, VOUTARGTYPE value) const +{ + ATLENSURE( pos != NULL ); + key = static_cast(pos)->m_key; + value = static_cast(pos)->m_value; +} + +template< typename K, typename V, class KTraits, class VTraits > +const K& CRBTree< K, V, KTraits, VTraits >::GetKeyAt(POSITION pos) const +{ + ATLENSURE( pos != NULL ); + return static_cast(pos)->m_key; +} + +template< typename K, typename V, class KTraits, class VTraits > +const V& CRBTree< K, V, KTraits, VTraits >::GetValueAt(POSITION pos) const +{ + ATLENSURE( pos != NULL ); + return static_cast(pos)->m_value; +} + +template< typename K, typename V, class KTraits, class VTraits > +V& CRBTree< K, V, KTraits, VTraits >::GetValueAt(POSITION pos) +{ + ATLENSURE( pos != NULL ); + return static_cast(pos)->m_value; +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::SetValueAt(POSITION pos, VINARGTYPE value) +{ + ATLENSURE( pos != NULL ); + static_cast(pos)->m_value = value; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::NewNode( KINARGTYPE key, VINARGTYPE value ) throw( ... ) +{ + if( m_pFree == NULL ) + { + if (m_pNil == NULL) + { + m_pNil = reinterpret_cast(malloc(sizeof( CNode ))); + if (m_pNil == NULL) + { + AtlThrow( E_OUTOFMEMORY ); + } + memset(m_pNil, 0x00, sizeof(CNode)); + m_pNil->m_eColor = CNode::RB_BLACK; + m_pNil->m_pParent = m_pNil->m_pLeft = m_pNil->m_pRight = m_pNil; + m_pRoot = m_pNil; + } + + CAtlPlex* pPlex = CAtlPlex::Create( m_pBlocks, m_nBlockSize, sizeof( CNode ) ); + if( pPlex == NULL ) + { + AtlThrow( E_OUTOFMEMORY ); + } + CNode* pNode = static_cast< CNode* >( pPlex->data() ); + pNode += m_nBlockSize-1; + for( INT_PTR iBlock = m_nBlockSize-1; iBlock >= 0; iBlock-- ) + { + pNode->m_pLeft = m_pFree; + m_pFree = pNode; + pNode--; + } + } + ATLASSUME( m_pFree != NULL ); + + CNode* pNewNode = m_pFree; + ::new( pNewNode ) CNode( key, value ); + + m_pFree = m_pFree->m_pLeft; + pNewNode->m_eColor = CNode::RB_RED; + SetNil(&pNewNode->m_pLeft); + SetNil(&pNewNode->m_pRight); + SetNil(&pNewNode->m_pParent); + + m_nCount++; + ATLASSUME( m_nCount > 0 ); + + return( pNewNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::FreeNode(CNode* pNode) +{ + ATLENSURE( pNode != NULL ); + pNode->~CNode(); + pNode->m_pLeft = m_pFree; + m_pFree = pNode; + ATLASSUME( m_nCount > 0 ); + m_nCount--; +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::RemovePostOrder(CNode* pNode) throw() +{ + if (IsNil(pNode)) + return; + RemovePostOrder(pNode->m_pLeft); + RemovePostOrder(pNode->m_pRight); + FreeNode( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::LeftRotate(CNode* pNode) throw() +{ + ATLASSERT(pNode != NULL); + if(pNode == NULL) + return NULL; + + CNode* pRight = pNode->m_pRight; + pNode->m_pRight = pRight->m_pLeft; + if (!IsNil(pRight->m_pLeft)) + pRight->m_pLeft->m_pParent = pNode; + + pRight->m_pParent = pNode->m_pParent; + if (IsNil(pNode->m_pParent)) + m_pRoot = pRight; + else if (pNode == pNode->m_pParent->m_pLeft) + pNode->m_pParent->m_pLeft = pRight; + else + pNode->m_pParent->m_pRight = pRight; + + pRight->m_pLeft = pNode; + pNode->m_pParent = pRight; + return pNode; + +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::RightRotate(CNode* pNode) throw() +{ + ATLASSERT(pNode != NULL); + if(pNode == NULL) + return NULL; + + CNode* pLeft = pNode->m_pLeft; + pNode->m_pLeft = pLeft->m_pRight; + if (!IsNil(pLeft->m_pRight)) + pLeft->m_pRight->m_pParent = pNode; + + pLeft->m_pParent = pNode->m_pParent; + if (IsNil(pNode->m_pParent)) + m_pRoot = pLeft; + else if (pNode == pNode->m_pParent->m_pRight) + pNode->m_pParent->m_pRight = pLeft; + else + pNode->m_pParent->m_pLeft = pLeft; + + pLeft->m_pRight = pNode; + pNode->m_pParent = pLeft; + return pNode; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::Find(KINARGTYPE key) const throw() +{ + CNode* pKey = NULL; + CNode* pNode = m_pRoot; + while( !IsNil(pNode) && (pKey == NULL) ) + { + int nCompare = KTraits::CompareElementsOrdered( key, pNode->m_key ); + if( nCompare == 0 ) + { + pKey = pNode; + } + else + { + if( nCompare < 0 ) + { + pNode = pNode->m_pLeft; + } + else + { + pNode = pNode->m_pRight; + } + } + } + + if( pKey == NULL ) + { + return( NULL ); + } + +#pragma warning(push) +#pragma warning(disable:4127) + + while( true ) + { + CNode* pPrev = Predecessor( pKey ); + if( (pPrev != NULL) && KTraits::CompareElements( key, pPrev->m_key ) ) + { + pKey = pPrev; + } + else + { + return( pKey ); + } + } + +#pragma warning(pop) +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::FindPrefix( KINARGTYPE key ) const throw() +{ + // First, attempt to find a node that matches the key exactly + CNode* pParent = NULL; + CNode* pKey = NULL; + CNode* pNode = m_pRoot; + while( !IsNil(pNode) && (pKey == NULL) ) + { + pParent = pNode; + int nCompare = KTraits::CompareElementsOrdered( key, pNode->m_key ); + if( nCompare == 0 ) + { + pKey = pNode; + } + else if( nCompare < 0 ) + { + pNode = pNode->m_pLeft; + } + else + { + pNode = pNode->m_pRight; + } + } + + if( pKey != NULL ) + { + // We found a node with the exact key, so find the first node after + // this one with a different key + while( true ) + { + CNode* pNext = Successor( pKey ); + if ((pNext != NULL) && KTraits::CompareElements( key, pNext->m_key )) + { + pKey = pNext; + } + else + { + return pNext; + } + } + } + else if (pParent != NULL) + { + // No node matched the key exactly, so pick the first node with + // a key greater than the given key + int nCompare = KTraits::CompareElementsOrdered( key, pParent->m_key ); + if( nCompare < 0 ) + { + pKey = pParent; + } + else + { + ATLASSERT( nCompare > 0 ); + pKey = Successor( pParent ); + } + } + + return( pKey ); +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::SwapNode(CNode* pDest, CNode* pSrc) +{ + ATLENSURE( pDest != NULL ); + ATLENSURE( pSrc != NULL ); + + pDest->m_pParent = pSrc->m_pParent; + if (pSrc->m_pParent->m_pLeft == pSrc) + { + pSrc->m_pParent->m_pLeft = pDest; + } + else + { + pSrc->m_pParent->m_pRight = pDest; + } + + pDest->m_pRight = pSrc->m_pRight; + pDest->m_pLeft = pSrc->m_pLeft; + pDest->m_eColor = pSrc->m_eColor; + pDest->m_pRight->m_pParent = pDest; + pDest->m_pLeft->m_pParent = pDest; + + if (m_pRoot == pSrc) + { + m_pRoot = pDest; + } +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::InsertImpl( KINARGTYPE key, VINARGTYPE value ) throw( ... ) +{ + CNode* pNew = NewNode( key, value ); + + CNode* pY = NULL; + CNode* pX = m_pRoot; + + while (!IsNil(pX)) + { + pY = pX; + if( KTraits::CompareElementsOrdered( key, pX->m_key ) <= 0 ) + pX = pX->m_pLeft; + else + pX = pX->m_pRight; + } + + pNew->m_pParent = pY; + if (pY == NULL) + { + m_pRoot = pNew; + } + else if( KTraits::CompareElementsOrdered( key, pY->m_key ) <= 0 ) + pY->m_pLeft = pNew; + else + pY->m_pRight = pNew; + + return pNew; +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::RBDeleteFixup(CNode* pNode) +{ + ATLENSURE( pNode != NULL ); + + CNode* pX = pNode; + CNode* pW = NULL; + + while (( pX != m_pRoot ) && ( pX->m_eColor == CNode::RB_BLACK )) + { + if (pX == pX->m_pParent->m_pLeft) + { + pW = pX->m_pParent->m_pRight; + if (pW->m_eColor == CNode::RB_RED) + { + pW->m_eColor = CNode::RB_BLACK; + pW->m_pParent->m_eColor = CNode::RB_RED; + LeftRotate(pX->m_pParent); + pW = pX->m_pParent->m_pRight; + } + if (pW->m_pLeft->m_eColor == CNode::RB_BLACK && pW->m_pRight->m_eColor == CNode::RB_BLACK) + { + pW->m_eColor = CNode::RB_RED; + pX = pX->m_pParent; + } + else + { + if (pW->m_pRight->m_eColor == CNode::RB_BLACK) + { + pW->m_pLeft->m_eColor = CNode::RB_BLACK; + pW->m_eColor = CNode::RB_RED; + RightRotate(pW); + pW = pX->m_pParent->m_pRight; + } + pW->m_eColor = pX->m_pParent->m_eColor; + pX->m_pParent->m_eColor = CNode::RB_BLACK; + pW->m_pRight->m_eColor = CNode::RB_BLACK; + LeftRotate(pX->m_pParent); + pX = m_pRoot; + } + } + else + { + pW = pX->m_pParent->m_pLeft; + if (pW->m_eColor == CNode::RB_RED) + { + pW->m_eColor = CNode::RB_BLACK; + pW->m_pParent->m_eColor = CNode::RB_RED; + RightRotate(pX->m_pParent); + pW = pX->m_pParent->m_pLeft; + } + if (pW->m_pRight->m_eColor == CNode::RB_BLACK && pW->m_pLeft->m_eColor == CNode::RB_BLACK) + { + pW->m_eColor = CNode::RB_RED; + pX = pX->m_pParent; + } + else + { + if (pW->m_pLeft->m_eColor == CNode::RB_BLACK) + { + pW->m_pRight->m_eColor = CNode::RB_BLACK; + pW->m_eColor = CNode::RB_RED; + LeftRotate(pW); + pW = pX->m_pParent->m_pLeft; + } + pW->m_eColor = pX->m_pParent->m_eColor; + pX->m_pParent->m_eColor = CNode::RB_BLACK; + pW->m_pLeft->m_eColor = CNode::RB_BLACK; + RightRotate(pX->m_pParent); + pX = m_pRoot; + } + } + } + + pX->m_eColor = CNode::RB_BLACK; +} + + +template< typename K, typename V, class KTraits, class VTraits > +bool CRBTree< K, V, KTraits, VTraits >::RBDelete(CNode* pZ) throw() +{ + if (pZ == NULL) + return false; + + CNode* pY = NULL; + CNode* pX = NULL; + if (IsNil(pZ->m_pLeft) || IsNil(pZ->m_pRight)) + pY = pZ; + else + pY = Successor(pZ); + + if (!IsNil(pY->m_pLeft)) + pX = pY->m_pLeft; + else + pX = pY->m_pRight; + + pX->m_pParent = pY->m_pParent; + + if (IsNil(pY->m_pParent)) + m_pRoot = pX; + else if (pY == pY->m_pParent->m_pLeft) + pY->m_pParent->m_pLeft = pX; + else + pY->m_pParent->m_pRight = pX; + + if (pY->m_eColor == CNode::RB_BLACK) + RBDeleteFixup(pX); + + if (pY != pZ) + SwapNode(pY, pZ); + + if (m_pRoot != NULL) + SetNil(&m_pRoot->m_pParent); + + FreeNode( pZ ); + + return true; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::Minimum(CNode* pNode) const throw() +{ + if (pNode == NULL || IsNil(pNode)) + { + return NULL; + } + + CNode* pMin = pNode; + while (!IsNil(pMin->m_pLeft)) + { + pMin = pMin->m_pLeft; + } + + return pMin; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::Maximum(CNode* pNode) const throw() +{ + if (pNode == NULL || IsNil(pNode)) + { + return NULL; + } + + CNode* pMax = pNode; + while (!IsNil(pMax->m_pRight)) + { + pMax = pMax->m_pRight; + } + + return pMax; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::Predecessor( CNode* pNode ) const throw() +{ + if( pNode == NULL ) + { + return( NULL ); + } + if( !IsNil(pNode->m_pLeft) ) + { + return( Maximum( pNode->m_pLeft ) ); + } + + CNode* pParent = pNode->m_pParent; + CNode* pLeft = pNode; + while( !IsNil(pParent) && (pLeft == pParent->m_pLeft) ) + { + pLeft = pParent; + pParent = pParent->m_pParent; + } + + if (IsNil(pParent)) + { + pParent = NULL; + } + return( pParent ); +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::Successor(CNode* pNode) const throw() +{ + if ( pNode == NULL ) + { + return NULL; + } + if ( !IsNil(pNode->m_pRight) ) + { + return Minimum(pNode->m_pRight); + } + + CNode* pParent = pNode->m_pParent; + CNode* pRight = pNode; + while ( !IsNil(pParent) && (pRight == pParent->m_pRight) ) + { + pRight = pParent; + pParent = pParent->m_pParent; + } + + if (IsNil(pParent)) + { + pParent = NULL; + } + return pParent; +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBTree< K, V, KTraits, VTraits >::CNode* CRBTree< K, V, KTraits, VTraits >::RBInsert( KINARGTYPE key, VINARGTYPE value ) throw( ... ) +{ + CNode* pNewNode = InsertImpl( key, value ); + + CNode* pX = pNewNode; + pX->m_eColor = CNode::RB_RED; + CNode* pY = NULL; + while (pX != m_pRoot && pX->m_pParent->m_eColor == CNode::RB_RED) + { + if (pX->m_pParent == pX->m_pParent->m_pParent->m_pLeft) + { + pY = pX->m_pParent->m_pParent->m_pRight; + if (pY != NULL && pY->m_eColor == CNode::RB_RED) + { + pX->m_pParent->m_eColor = CNode::RB_BLACK; + pY->m_eColor = CNode::RB_BLACK; + pX->m_pParent->m_pParent->m_eColor = CNode::RB_RED; + pX = pX->m_pParent->m_pParent; + } + else + { + if (pX == pX->m_pParent->m_pRight) + { + pX = pX->m_pParent; + LeftRotate(pX); + } + pX->m_pParent->m_eColor = CNode::RB_BLACK; + pX->m_pParent->m_pParent->m_eColor = CNode::RB_RED; + RightRotate(pX->m_pParent->m_pParent); + } + } + else + { + pY = pX->m_pParent->m_pParent->m_pLeft; + if (pY != NULL && pY->m_eColor == CNode::RB_RED) + { + pX->m_pParent->m_eColor = CNode::RB_BLACK; + pY->m_eColor = CNode::RB_BLACK; + pX->m_pParent->m_pParent->m_eColor = CNode::RB_RED; + pX = pX->m_pParent->m_pParent; + } + else + { + if (pX == pX->m_pParent->m_pLeft) + { + pX = pX->m_pParent; + RightRotate(pX); + } + pX->m_pParent->m_eColor = CNode::RB_BLACK; + pX->m_pParent->m_pParent->m_eColor = CNode::RB_RED; + LeftRotate(pX->m_pParent->m_pParent); + } + } + } + + m_pRoot->m_eColor = CNode::RB_BLACK; + SetNil(&m_pRoot->m_pParent); + + return( pNewNode ); +} + +#ifdef _DEBUG + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::VerifyIntegrity(const CNode *pNode, int nCurrBlackDepth, int &nBlackDepth) const throw() +{ + bool bCheckForBlack = false; + bool bLeaf = true; + + if (pNode->m_eColor == CNode::RB_RED) + bCheckForBlack = true; + else + nCurrBlackDepth++; + + ATLASSERT(pNode->m_pLeft != NULL); + if (!IsNil(pNode->m_pLeft)) + { + bLeaf = false; + if (bCheckForBlack) + { + ATLASSERT(pNode->m_pLeft->m_eColor == CNode::RB_BLACK); + } + + VerifyIntegrity(pNode->m_pLeft, nCurrBlackDepth, nBlackDepth); + } + + ATLASSERT(pNode->m_pRight != NULL); + if (!IsNil(pNode->m_pRight)) + { + bLeaf = false; + if (bCheckForBlack) + { + ATLASSERT(pNode->m_pRight->m_eColor == CNode::RB_BLACK); + } + + VerifyIntegrity(pNode->m_pRight, nCurrBlackDepth, nBlackDepth); + } + + ATLASSERT( pNode->m_pParent != NULL ); + ATLASSERT( ( IsNil(pNode->m_pParent) ) || + ( pNode->m_pParent->m_pLeft == pNode ) || + ( pNode->m_pParent->m_pRight == pNode ) ); + + if (bLeaf) + { + if (nBlackDepth == 0) + { + nBlackDepth = nCurrBlackDepth; + } + else + { + ATLASSERT(nBlackDepth == nCurrBlackDepth); + } + } +} + +template< typename K, typename V, class KTraits, class VTraits > +void CRBTree< K, V, KTraits, VTraits >::VerifyIntegrity() const throw() +{ + if ((m_pRoot == NULL) || (IsNil(m_pRoot))) + return; + + ATLASSUME(m_pRoot->m_eColor == CNode::RB_BLACK); + int nBlackDepth = 0; + VerifyIntegrity(m_pRoot, 0, nBlackDepth); +} + +#endif // _DEBUG + +template< typename K, typename V, class KTraits = CElementTraits< K >, class VTraits = CElementTraits< V > > +class CRBMap : + public CRBTree< K, V, KTraits, VTraits > +{ +public: + explicit CRBMap( size_t nBlockSize = 10 ) throw(); + ~CRBMap() throw(); + + bool Lookup( KINARGTYPE key, VOUTARGTYPE value ) const throw( ... ); + const CPair* Lookup( KINARGTYPE key ) const throw(); + CPair* Lookup( KINARGTYPE key ) throw(); + POSITION SetAt( KINARGTYPE key, VINARGTYPE value ) throw( ... ); + bool RemoveKey( KINARGTYPE key ) throw(); +}; + +template< typename K, typename V, class KTraits, class VTraits > +CRBMap< K, V, KTraits, VTraits >::CRBMap( size_t nBlockSize ) throw() : + CRBTree< K, V, KTraits, VTraits >( nBlockSize ) +{ +} + +template< typename K, typename V, class KTraits, class VTraits > +CRBMap< K, V, KTraits, VTraits >::~CRBMap() throw() +{ +} + +template< typename K, typename V, class KTraits, class VTraits > +const typename CRBMap< K, V, KTraits, VTraits >::CPair* CRBMap< K, V, KTraits, VTraits >::Lookup( KINARGTYPE key ) const throw() +{ + return Find(key); +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBMap< K, V, KTraits, VTraits >::CPair* CRBMap< K, V, KTraits, VTraits >::Lookup( KINARGTYPE key ) throw() +{ + return Find(key); +} + +template< typename K, typename V, class KTraits, class VTraits > +bool CRBMap< K, V, KTraits, VTraits >::Lookup( KINARGTYPE key, VOUTARGTYPE value ) const throw( ... ) +{ + const CPair* pLookup = Find( key ); + if( pLookup == NULL ) + return false; + + value = pLookup->m_value; + return true; +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CRBMap< K, V, KTraits, VTraits >::SetAt( KINARGTYPE key, VINARGTYPE value ) throw( ... ) +{ + CPair* pNode = Find( key ); + if( pNode == NULL ) + { + return( RBInsert( key, value ) ); + } + else + { + pNode->m_value = value; + + return( pNode ); + } +} + +template< typename K, typename V, class KTraits, class VTraits > +bool CRBMap< K, V, KTraits, VTraits >::RemoveKey( KINARGTYPE key ) throw() +{ + POSITION pos = Lookup( key ); + if( pos != NULL ) + { + RemoveAt( pos ); + + return( true ); + } + else + { + return( false ); + } +} + +template< typename K, typename V, class KTraits = CElementTraits< K >, class VTraits = CElementTraits< V > > +class CRBMultiMap : + public CRBTree< K, V, KTraits, VTraits > +{ +public: + explicit CRBMultiMap( size_t nBlockSize = 10 ) throw(); + ~CRBMultiMap() throw(); + + POSITION Insert( KINARGTYPE key, VINARGTYPE value ) throw( ... ); + size_t RemoveKey( KINARGTYPE key ) throw(); + + POSITION FindFirstWithKey( KINARGTYPE key ) const throw(); + const CPair* GetNextWithKey( POSITION& pos, KINARGTYPE key ) const throw(); + CPair* GetNextWithKey( POSITION& pos, KINARGTYPE key ) throw(); + const V& GetNextValueWithKey( POSITION& pos, KINARGTYPE key ) const throw(); + V& GetNextValueWithKey( POSITION& pos, KINARGTYPE key ) throw(); +}; + +template< typename K, typename V, class KTraits, class VTraits > +CRBMultiMap< K, V, KTraits, VTraits >::CRBMultiMap( size_t nBlockSize ) throw() : + CRBTree< K, V, KTraits, VTraits >( nBlockSize ) +{ +} + +template< typename K, typename V, class KTraits, class VTraits > +CRBMultiMap< K, V, KTraits, VTraits >::~CRBMultiMap() throw() +{ +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CRBMultiMap< K, V, KTraits, VTraits >::Insert( KINARGTYPE key, VINARGTYPE value ) throw( ... ) +{ + return( RBInsert( key, value ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +size_t CRBMultiMap< K, V, KTraits, VTraits >::RemoveKey( KINARGTYPE key ) throw() +{ + size_t nElementsDeleted = 0; + + POSITION pos = FindFirstWithKey( key ); + while( pos != NULL ) + { + POSITION posDelete = pos; + GetNextWithKey( pos, key ); + RemoveAt( posDelete ); + nElementsDeleted++; + } + + return( nElementsDeleted ); +} + +template< typename K, typename V, class KTraits, class VTraits > +POSITION CRBMultiMap< K, V, KTraits, VTraits >::FindFirstWithKey( KINARGTYPE key ) const throw() +{ + return( Find( key ) ); +} + +template< typename K, typename V, class KTraits, class VTraits > +const typename CRBMultiMap< K, V, KTraits, VTraits >::CPair* CRBMultiMap< K, V, KTraits, VTraits >::GetNextWithKey( POSITION& pos, KINARGTYPE key ) const throw() +{ + ATLASSERT( pos != NULL ); + const CPair* pNode = GetNext( pos ); + if( (pos == NULL) || !KTraits::CompareElements( static_cast< CPair* >( pos )->m_key, key ) ) + { + pos = NULL; + } + + return( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +typename CRBMultiMap< K, V, KTraits, VTraits >::CPair* CRBMultiMap< K, V, KTraits, VTraits >::GetNextWithKey( POSITION& pos, KINARGTYPE key ) throw() +{ + ATLASSERT( pos != NULL ); + CPair* pNode = GetNext( pos ); + if( (pos == NULL) || !KTraits::CompareElements( static_cast< CPair* >( pos )->m_key, key ) ) + { + pos = NULL; + } + + return( pNode ); +} + +template< typename K, typename V, class KTraits, class VTraits > +const V& CRBMultiMap< K, V, KTraits, VTraits >::GetNextValueWithKey( POSITION& pos, KINARGTYPE key ) const throw() +{ + const CPair* pPair = GetNextWithKey( pos, key ); + + return( pPair->m_value ); +} + +template< typename K, typename V, class KTraits, class VTraits > +V& CRBMultiMap< K, V, KTraits, VTraits >::GetNextValueWithKey( POSITION& pos, KINARGTYPE key ) throw() +{ + CPair* pPair = GetNextWithKey( pos, key ); + + return( pPair->m_value ); +} + +#pragma pop_macro("new") + +}; // namespace ATL +#pragma pack(pop) + +#pragma warning(pop) + +#endif // __ATLCOLL_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcom.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcom.h new file mode 100644 index 00000000..ea60fb0e --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcom.h @@ -0,0 +1,6453 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCOM_H__ +#define __ATLCOM_H__ + +#pragma once + +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning (push) +#pragma warning(disable: 4702) // unreachable code +#pragma warning(disable: 4355) // 'this' used in initializer list +#pragma warning(disable: 4511) // copy constructor could not be generated +#pragma warning(disable: 4512) // assignment operator could not be generated +#pragma warning(disable : 4668) // is not defined as a preprocessor macro, replacing with '0' for '#if/#elif +#pragma warning(disable : 4820) // padding added after member +#pragma warning(disable : 4571) //catch(...) blocks compiled with /EHs do NOT catch or re-throw Structured Exceptions +#endif //!_ATL_NO_PRAGMA_WARNINGS + +// +// [pfx_parse] - workaround for old PREfix/PREfast parser +// +#if (defined(_PREFIX_) || defined(_PREFAST_)) && (_MSC_VER < 1400) +#pragma warning (push) +#pragma warning(disable: 4081) // expected 'newline' +#pragma warning(disable: 4616) // warning number 'x' out of range, must be between '4001' and '4999' +#endif // old PREfast parser + +#ifdef _ATL_ALL_WARNINGS +#pragma warning( push ) +#endif +#pragma warning(disable: 4127) // constant expression +#pragma warning(disable: 4786) // avoid 255-character limit warnings + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#ifndef __ATLBASE_H__ + #error atlcom.h requires atlbase.h to be included first +#endif + +#include +#pragma pack(push, _ATL_PACKING) + +EXTERN_C const IID IID_ITargetFrame; + +#include + +#pragma pack(push, _ATL_PACKING) +namespace ATL +{ + +#define CComConnectionPointContainerImpl ATL::IConnectionPointContainerImpl +#define CComISupportErrorInfoImpl ATL::ISupportErrorInfoImpl +#define CComProvideClassInfo2Impl ATL::IProvideClassInfoImpl +#define CComDualImpl ATL::IDispatchImpl + +#ifdef _ATL_DEBUG_QI +#ifndef _ATL_DEBUG +#define _ATL_DEBUG +#endif // _ATL_DEBUG +#endif // _ATL_DEBUG_QI + +#ifdef _ATL_DEBUG_QI +#define _ATLDUMPIID(iid, name, hr) AtlDumpIID(iid, name, hr) +#else +#define _ATLDUMPIID(iid, name, hr) hr +#endif + +#define _ATL_DEBUG_ADDREF_RELEASE_IMPL(className)\ + virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0;\ + virtual ULONG STDMETHODCALLTYPE Release(void) = 0; + +///////////////////////////////////////////////////////////////////////////// +// AtlReportError + +inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, const IID& iid = GUID_NULL, + HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance()) +{ + return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), 0, NULL, iid, hRes, hInst); +} + +inline HRESULT WINAPI AtlReportError(const CLSID& clsid, UINT nID, DWORD dwHelpID, + LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0, + HINSTANCE hInst = _AtlBaseModule.GetResourceInstance()) +{ + return AtlSetErrorInfo(clsid, (LPCOLESTR)MAKEINTRESOURCE(nID), dwHelpID, + lpszHelpFile, iid, hRes, hInst); +} + +inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc, + DWORD dwHelpID, LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0) +{ + ATLASSERT(lpszDesc != NULL); + if (lpszDesc == NULL) + return E_POINTER; + USES_CONVERSION_EX; + LPCOLESTR pwszDesc = A2COLE_EX(lpszDesc, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); + if(pwszDesc == NULL) + return E_OUTOFMEMORY; + + LPCWSTR pwzHelpFile = NULL; + if(lpszHelpFile != NULL) + { + pwzHelpFile = A2CW_EX(lpszHelpFile, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); + if(pwzHelpFile == NULL) + return E_OUTOFMEMORY; + } + + return AtlSetErrorInfo(clsid, pwszDesc, dwHelpID, pwzHelpFile, iid, hRes, NULL); +} + +inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCSTR lpszDesc, + const IID& iid = GUID_NULL, HRESULT hRes = 0) +{ + return AtlReportError(clsid, lpszDesc, 0, NULL, iid, hRes); +} + +inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc, + const IID& iid = GUID_NULL, HRESULT hRes = 0) +{ + return AtlSetErrorInfo(clsid, lpszDesc, 0, NULL, iid, hRes, NULL); +} + +inline HRESULT WINAPI AtlReportError(const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID, + LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0) +{ + return AtlSetErrorInfo(clsid, lpszDesc, dwHelpID, lpszHelpFile, iid, hRes, NULL); +} + +// Returns the apartment type that the current thread is in. false is returned +// if the thread isn't in an apartment. +inline bool AtlGetApartmentType(DWORD* pApartmentType) +{ + HRESULT hr = CoInitialize(NULL); + if (SUCCEEDED(hr)) + CoUninitialize(); + + if (hr == S_FALSE) + { + *pApartmentType = COINIT_APARTMENTTHREADED; + return true; + } +#if ((_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)) + else + if (hr == RPC_E_CHANGED_MODE) + { + *pApartmentType = COINIT_MULTITHREADED; + return true; + } +#endif + return false; +} + +///////////////////////////////////////////////////////////////////////////// +// CComTypeAttr + +class CComTypeAttr +{ +// Construction +public: + CComTypeAttr( ITypeInfo* pTypeInfo ) throw() : + m_pTypeAttr( NULL ), + m_pTypeInfo( pTypeInfo ) + { + } + ~CComTypeAttr() throw() + { + Release(); + } + +// Operators +public: + TYPEATTR* operator->() throw() + { + ATLASSUME( m_pTypeAttr != NULL ); + + return m_pTypeAttr; + } + TYPEATTR** operator&() throw() + { + ATLASSUME( m_pTypeAttr == NULL ); + + return &m_pTypeAttr; + } + + operator const TYPEATTR*() const throw() + { + return m_pTypeAttr; + } + +// Operations +public: + void Release() throw() + { + if( m_pTypeAttr != NULL ) + { + ATLASSUME( m_pTypeInfo != NULL ); + m_pTypeInfo->ReleaseTypeAttr( m_pTypeAttr ); + m_pTypeAttr = NULL; + } + } + +public: + TYPEATTR* m_pTypeAttr; + CComPtr< ITypeInfo > m_pTypeInfo; +}; + + +///////////////////////////////////////////////////////////////////////////// +// CComVarDesc + +class CComVarDesc +{ +// Construction +public: + CComVarDesc( ITypeInfo* pTypeInfo ) throw() : + m_pVarDesc( NULL ), + m_pTypeInfo( pTypeInfo ) + { + } + ~CComVarDesc() throw() + { + Release(); + } + +// Operators +public: + VARDESC* operator->() throw() + { + ATLASSUME( m_pVarDesc != NULL ); + + return m_pVarDesc; + } + VARDESC** operator&() throw() + { + ATLASSUME( m_pVarDesc == NULL ); + + return &m_pVarDesc; + } + + operator const VARDESC*() const throw() + { + return m_pVarDesc; + } + +// Operations +public: + void Release() throw() + { + if( m_pVarDesc != NULL ) + { + ATLASSUME( m_pTypeInfo != NULL ); + m_pTypeInfo->ReleaseVarDesc( m_pVarDesc ); + m_pVarDesc = NULL; + } + } + +public: + VARDESC* m_pVarDesc; + CComPtr< ITypeInfo > m_pTypeInfo; +}; + + +///////////////////////////////////////////////////////////////////////////// +// CComFuncDesc + +class CComFuncDesc +{ +// Construction +public: + CComFuncDesc( ITypeInfo* pTypeInfo ) throw() : + m_pFuncDesc( NULL ), + m_pTypeInfo( pTypeInfo ) + { + } + ~CComFuncDesc() throw() + { + Release(); + } + +// Operators +public: + FUNCDESC* operator->() throw() + { + ATLASSUME( m_pFuncDesc != NULL ); + + return m_pFuncDesc; + } + FUNCDESC** operator&() throw() + { + ATLASSUME( m_pFuncDesc == NULL ); + + return &m_pFuncDesc; + } + + operator const FUNCDESC*() const throw() + { + return m_pFuncDesc; + } + +// Operations +public: + void Release() throw() + { + if( m_pFuncDesc != NULL ) + { + ATLASSUME( m_pTypeInfo != NULL ); + m_pTypeInfo->ReleaseFuncDesc( m_pFuncDesc ); + m_pFuncDesc = NULL; + } + } + +public: + FUNCDESC* m_pFuncDesc; + CComPtr< ITypeInfo > m_pTypeInfo; +}; + + +///////////////////////////////////////////////////////////////////////////// +// CComExcepInfo + +class CComExcepInfo : + public EXCEPINFO +{ +// Construction +public: + CComExcepInfo() + { + memset( this, 0, sizeof( *this ) ); + } + ~CComExcepInfo() + { + Clear(); + } + +// Operations +public: + void Clear() + { + ::SysFreeString(bstrSource); + ::SysFreeString(bstrDescription); + ::SysFreeString(bstrHelpFile); + + memset(this, 0, sizeof(*this)); + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// IPersistImpl +template +class ATL_NO_VTABLE IPersistImpl : public IPersist +{ +public: + STDMETHOD(GetClassID)(CLSID *pClassID) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistImpl::GetClassID\n")); + if (pClassID == NULL) + return E_FAIL; + *pClassID = T::GetObjectCLSID(); + return S_OK; + } +}; + +////////////////////////////////////////////////////////////////////////////// +// CFakeFirePropNotifyEvent +class CFakeFirePropNotifyEvent +{ +public: + static HRESULT FireOnRequestEdit(IUnknown* /*pUnk*/, DISPID /*dispID*/) + { + return S_OK; + } + static HRESULT FireOnChanged(IUnknown* /*pUnk*/, DISPID /*dispID*/) + { + return S_OK; + } +}; +typedef CFakeFirePropNotifyEvent _ATL_PROP_NOTIFY_EVENT_CLASS; + + +////////////////////////////////////////////////////////////////////////////// +// ALT_PROP_VAL_MAP + +struct ATL_PROPVALMAP_ENTRY +{ + DISPID dispid; + VARIANT val; + LPCOLESTR szDesc; +}; + +#define BEGIN_PROP_VAL_MAP(theClass) \ + static ATL::ATL_PROPVALMAP_ENTRY* GetPropValMap(int *cnt)\ + {\ + static ATL::ATL_PROPVALMAP_ENTRY pPropMap[] = \ + { + +#define PROP_VAL_INT(dispid, ival, str) \ + {dispid, {VT_I4, 0, 0, 0, ival}, OLESTR(str)}, + + +#define END_PROP_VAL_MAP() \ + }; \ + if (cnt) \ + *cnt = sizeof(pPropMap)/sizeof(pPropMap[0]); \ + return pPropMap; \ + } + +#define DECLARE_EMPTY_PROP_VAL_MAP() \ +public: \ + static ATL::ATL_PROPVALMAP_ENTRY* GetPropValMap(int *cnt)\ + { \ + if (cnt) \ + *cnt = 0; \ + return NULL; \ + } + +////////////////////////////////////////////////////////////////////////////// +// ATL Persistence + +struct ATL_PROPMAP_ENTRY +{ + LPCOLESTR szDesc; + DISPID dispid; + const CLSID* pclsidPropPage; + const IID* piidDispatch; + DWORD dwOffsetData; + DWORD dwSizeData; + VARTYPE vt; +}; + +// This one is DEPRECATED and is used for ATL 2.X controls +// it includes an implicit m_sizeExtent +#define BEGIN_PROPERTY_MAP(theClass) \ + __if_not_exists(__ATL_PROP_NOTIFY_EVENT_CLASS) \ + { \ + typedef ATL::_ATL_PROP_NOTIFY_EVENT_CLASS __ATL_PROP_NOTIFY_EVENT_CLASS; \ + } \ + typedef theClass _PropMapClass; \ + static ATL::ATL_PROPMAP_ENTRY* GetPropertyMap()\ + {\ + static ATL::ATL_PROPMAP_ENTRY pPropMap[] = \ + { \ + {OLESTR("_cx"), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, m_sizeExtent.cx), sizeof(long), VT_UI4}, \ + {OLESTR("_cy"), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, m_sizeExtent.cy), sizeof(long), VT_UI4}, + +// This one can be used on any type of object, but does not +// include the implicit m_sizeExtent +#define BEGIN_PROP_MAP(theClass) \ + __if_not_exists(__ATL_PROP_NOTIFY_EVENT_CLASS) \ + { \ + typedef ATL::_ATL_PROP_NOTIFY_EVENT_CLASS __ATL_PROP_NOTIFY_EVENT_CLASS; \ + } \ + typedef theClass _PropMapClass; \ + static ATL::ATL_PROPMAP_ENTRY* GetPropertyMap()\ + {\ + static ATL::ATL_PROPMAP_ENTRY pPropMap[] = \ + { + +#define PROP_ENTRY(szDesc, dispid, clsid) \ + {OLESTR(szDesc), dispid, &clsid, &__uuidof(IDispatch), 0, 0, VT_EMPTY}, + +#define PROP_ENTRY_EX(szDesc, dispid, clsid, iidDispatch) \ + {OLESTR(szDesc), dispid, &clsid, &iidDispatch, 0, 0, VT_EMPTY}, + +#define PROP_ENTRY_TYPE(szDesc, dispid, clsid, vt) \ + {OLESTR(szDesc), dispid, &clsid, &__uuidof(IDispatch), 0, 0, vt}, + +#define PROP_ENTRY_TYPE_EX(szDesc, dispid, clsid, iidDispatch, vt) \ + {OLESTR(szDesc), dispid, &clsid, &iidDispatch, 0, 0, vt}, + +#define PROP_PAGE(clsid) \ + {NULL, NULL, &clsid, &IID_NULL, 0, 0, 0}, + +#define PROP_DATA_ENTRY(szDesc, member, vt) \ + {OLESTR(szDesc), 0, &CLSID_NULL, NULL, offsetof(_PropMapClass, member), sizeof(((_PropMapClass*)0)->member), vt}, + +#define END_PROPERTY_MAP() \ + {NULL, 0, NULL, &IID_NULL, 0, 0, 0} \ + }; \ + return pPropMap; \ + } + +#define END_PROP_MAP() \ + {NULL, 0, NULL, &IID_NULL, 0, 0, 0} \ + }; \ + return pPropMap; \ + } + +////////////////////////////////////////////////////////////////////////////// +// IPersist* Helpers + +ATLAPI AtlIPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk); +ATLAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk); +ATLAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk); +ATLAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk); + +////////////////////////////////////////////////////////////////////////////// +// IPersistStreamInitImpl +template +class ATL_NO_VTABLE IPersistStreamInitImpl : public IPersistStreamInit +{ +public: + // IPersist + STDMETHOD(GetClassID)(CLSID *pClassID) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::GetClassID\n")); + if (pClassID == NULL) + return E_POINTER; + *pClassID = T::GetObjectCLSID(); + return S_OK; + } + + // IPersistStream + STDMETHOD(IsDirty)() + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::IsDirty\n")); + T* pT = static_cast(this); + return (pT->m_bRequiresSave) ? S_OK : S_FALSE; + } + STDMETHOD(Load)(LPSTREAM pStm) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::Load\n")); + + T* pT = static_cast(this); + return pT->IPersistStreamInit_Load(pStm, T::GetPropertyMap()); + } + STDMETHOD(Save)(LPSTREAM pStm, BOOL fClearDirty) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::Save\n")); + return pT->IPersistStreamInit_Save(pStm, fClearDirty, T::GetPropertyMap()); + } + STDMETHOD(GetSizeMax)(ULARGE_INTEGER* pcbSize) + { + HRESULT hr = S_OK; + T* pT = static_cast(this); + ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::GetSizeMax\n")); + + if (pcbSize == NULL) + return E_POINTER; + + ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap(); + ATLENSURE(pMap != NULL); + + // Start the size with the size of the ATL version we write out. + ULARGE_INTEGER nSize; + nSize.HighPart = 0; + nSize.LowPart = sizeof(DWORD); + + CComPtr pDispatch; + const IID* piidOld = NULL; + for (int i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + if (pMap[i].szDesc == NULL) + continue; + + // check if raw data entry + if (pMap[i].dwSizeData != 0) + { + ULONG ulSize=0; + //Calculate stream size for BSTRs special case + if (pMap[i].vt == VT_BSTR) + { + void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pT); + ATLENSURE( pData >= (void*)(DWORD_PTR)pMap[i].dwOffsetData + && pData >= (void*)(DWORD_PTR)pT ); + BSTR bstr=*reinterpret_cast(pData); + ulSize=CComBSTR::GetStreamSize(bstr); + } else + { + ulSize = pMap[i].dwSizeData; + } + nSize.QuadPart += ulSize; + continue; + } + + CComVariant var; + if (pMap[i].piidDispatch != piidOld) + { + pDispatch.Release(); + if (FAILED(pT->GetUnknown()->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch))) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i); + hr = E_FAIL; + break; + } + piidOld = pMap[i].piidDispatch; + } + + if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var))) + { + ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid); + hr = E_FAIL; + break; + } + nSize.QuadPart += var.GetSize(); + } + *pcbSize = nSize; + return hr; + } + + // IPersistStreamInit + STDMETHOD(InitNew)() + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStreamInitImpl::InitNew\n")); + T* pT = static_cast(this); + pT->m_bRequiresSave = TRUE; + return S_OK; + } + + HRESULT IPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap) + { + T* pT = static_cast(this); + HRESULT hr = AtlIPersistStreamInit_Load(pStm, pMap, pT, pT->GetUnknown()); + if (SUCCEEDED(hr)) + pT->m_bRequiresSave = FALSE; + return hr; + + } + HRESULT IPersistStreamInit_Save(LPSTREAM pStm, BOOL fClearDirty, ATL_PROPMAP_ENTRY* pMap) + { + T* pT = static_cast(this); + HRESULT hr; + hr = AtlIPersistStreamInit_Save(pStm, fClearDirty, pMap, pT, pT->GetUnknown()); + if (fClearDirty && SUCCEEDED(hr)) + { + pT->m_bRequiresSave=FALSE; + } + return hr; + + } +}; + +////////////////////////////////////////////////////////////////////////////// +// IPersistStorageImpl +template +class ATL_NO_VTABLE IPersistStorageImpl : public IPersistStorage +{ +public: + // IPersist + STDMETHOD(GetClassID)(CLSID *pClassID) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::GetClassID\n")); + if (pClassID == NULL) + return E_POINTER; + *pClassID = T::GetObjectCLSID(); + return S_OK; + } + + // IPersistStorage + STDMETHOD(IsDirty)(void) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::IsDirty\n")); + CComPtr p; + p.p = IPSI_GetIPersistStreamInit(); + return (p != NULL) ? p->IsDirty() : E_FAIL; + } + STDMETHOD(InitNew)(IStorage*) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::InitNew\n")); + CComPtr p; + p.p = IPSI_GetIPersistStreamInit(); + return (p != NULL) ? p->InitNew() : E_FAIL; + } + STDMETHOD(Load)(IStorage* pStorage) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::Load\n")); + if (pStorage == NULL) + return E_INVALIDARG; + CComPtr p; + p.p = IPSI_GetIPersistStreamInit(); + HRESULT hr = E_FAIL; + if (p != NULL) + { + CComPtr spStream; + hr = pStorage->OpenStream(OLESTR("Contents"), NULL, + STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, &spStream); + if (SUCCEEDED(hr)) + hr = p->Load(spStream); + } + return hr; + } + STDMETHOD(Save)(IStorage* pStorage, BOOL fSameAsLoad) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::Save\n")); + if (pStorage == NULL) + return E_INVALIDARG; + CComPtr p; + p.p = IPSI_GetIPersistStreamInit(); + HRESULT hr = E_FAIL; + if (p != NULL) + { + CComPtr spStream; + static LPCOLESTR vszContents = OLESTR("Contents"); + hr = pStorage->CreateStream(vszContents, + STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE, + 0, 0, &spStream); + if (SUCCEEDED(hr)) + hr = p->Save(spStream, fSameAsLoad); + } + return hr; + } + STDMETHOD(SaveCompleted)(IStorage* /* pStorage */) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::SaveCompleted\n")); + return S_OK; + } + STDMETHOD(HandsOffStorage)(void) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistStorageImpl::HandsOffStorage\n")); + return S_OK; + } +private: + IPersistStreamInit* IPSI_GetIPersistStreamInit(); +}; + +template +IPersistStreamInit* IPersistStorageImpl::IPSI_GetIPersistStreamInit() +{ + T* pT = static_cast(this); + IPersistStreamInit* p; + if (FAILED(pT->GetUnknown()->QueryInterface(__uuidof(IPersistStreamInit), (void**)&p))) + pT->_InternalQueryInterface(__uuidof(IPersistStreamInit), (void**)&p); + return p; +} + + +////////////////////////////////////////////////////////////////////////////// +// IPersistPropertyBagImpl +template +class ATL_NO_VTABLE IPersistPropertyBagImpl : public IPersistPropertyBag +{ +public: + // IPersist + STDMETHOD(GetClassID)(CLSID *pClassID) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::GetClassID\n")); + if (pClassID == NULL) + return E_POINTER; + *pClassID = T::GetObjectCLSID(); + return S_OK; + } + + // IPersistPropertyBag + // + STDMETHOD(InitNew)() + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::InitNew\n")); + T* pT = static_cast(this); + pT->m_bRequiresSave = TRUE; + return S_OK; + } + STDMETHOD(Load)(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::Load\n")); + T* pT = static_cast(this); + ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap(); + ATLASSERT(pMap != NULL); + return pT->IPersistPropertyBag_Load(pPropBag, pErrorLog, pMap); + } + STDMETHOD(Save)(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties) + { + ATLTRACE(atlTraceCOM, 2, _T("IPersistPropertyBagImpl::Save\n")); + T* pT = static_cast(this); + ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap(); + ATLASSERT(pMap != NULL); + return pT->IPersistPropertyBag_Save(pPropBag, fClearDirty, fSaveAllProperties, pMap); + } + HRESULT IPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap) + { + T* pT = static_cast(this); + HRESULT hr = AtlIPersistPropertyBag_Load(pPropBag, pErrorLog, pMap, pT, pT->GetUnknown()); + if (SUCCEEDED(hr)) + pT->m_bRequiresSave = FALSE; + return hr; + } + HRESULT IPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties, ATL_PROPMAP_ENTRY* pMap) + { + T* pT = static_cast(this); + HRESULT hr; + hr = AtlIPersistPropertyBag_Save(pPropBag, fClearDirty, fSaveAllProperties, pMap, pT, pT->GetUnknown()); + if (fClearDirty && SUCCEEDED(hr)) + { + pT->m_bRequiresSave=FALSE; + } + return hr; + + } +}; + +////////////////////////////////////////////////////////////////////////////// +// CSecurityDescriptor +ATL_DEPRECATED("CSecurityDescriptor has been replaced by CSID") class CSecurityDescriptor +{ +public: + CSecurityDescriptor(); + ~CSecurityDescriptor(); + +public: + HRESULT Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD); + HRESULT AttachObject(HANDLE hObject); + HRESULT Initialize(); + HRESULT InitializeFromProcessToken(BOOL bDefaulted = FALSE); + HRESULT InitializeFromThreadToken(BOOL bDefaulted = FALSE, BOOL bRevertToProcessToken = TRUE); + HRESULT SetOwner(PSID pOwnerSid, BOOL bDefaulted = FALSE); + HRESULT SetGroup(PSID pGroupSid, BOOL bDefaulted = FALSE); + HRESULT Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask); + HRESULT Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask); + HRESULT Revoke(LPCTSTR pszPrincipal); + HRESULT Allow(PSID pSid, DWORD dwAccessMask); + HRESULT Deny(PSID pSid, DWORD dwAccessMask); + HRESULT Revoke(PSID pSid); + + // utility functions + // Any PSID you get from these functions should be free()ed + static HRESULT SetPrivilege(LPCTSTR Privilege, BOOL bEnable = TRUE, HANDLE hToken = NULL); + static HRESULT GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid); + static HRESULT GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid = NULL); + static HRESULT GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid = NULL, BOOL bOpenAsSelf = FALSE); + static HRESULT CopyACL(PACL pDest, PACL pSrc); + static HRESULT GetCurrentUserSID(PSID *ppSid); + static HRESULT GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid); + static HRESULT AddAccessAllowedACEToACL(PACL *Acl, PSID pSid, DWORD dwAccessMask); + static HRESULT AddAccessDeniedACEToACL(PACL *Acl, PSID pSid, DWORD dwAccessMask); + static HRESULT RemovePrincipalFromACL(PACL Acl, PSID pSid); + static HRESULT CloneSID(PSID *ppSIDDest, PSID pSIDSrc) + { + HRESULT hr = S_OK; + if (ppSIDDest == NULL) + return E_POINTER; + + if (*ppSIDDest != NULL) + return E_INVALIDARG; + *ppSIDDest = NULL; + + if (!IsValidSid(pSIDSrc)) + return E_INVALIDARG; + + DWORD dwSize = GetLengthSid(pSIDSrc); + + *ppSIDDest = (PSID) malloc(dwSize); + if (*ppSIDDest == NULL) + return E_OUTOFMEMORY; + if (!CopySid(dwSize, *ppSIDDest, pSIDSrc)) + { + hr = AtlHresultFromLastError(); + ATLASSERT(FALSE); + free(*ppSIDDest); + *ppSIDDest = NULL; + } + return hr; + } + operator PSECURITY_DESCRIPTOR() + { + return m_pSD; + } + +public: + PSECURITY_DESCRIPTOR m_pSD; + PSID m_pOwner; + PSID m_pGroup; + PACL m_pDACL; + PACL m_pSACL; +}; + +inline CSecurityDescriptor::CSecurityDescriptor() +{ + m_pSD = NULL; + m_pOwner = NULL; + m_pGroup = NULL; + m_pDACL = NULL; + m_pSACL= NULL; +} + +inline CSecurityDescriptor::~CSecurityDescriptor() +{ + delete m_pSD; + free(m_pOwner); + free(m_pGroup); + free(m_pDACL); + free(m_pSACL); +} + +inline HRESULT CSecurityDescriptor::Initialize() +{ + delete m_pSD; + m_pSD = NULL; + + free(m_pOwner); + m_pOwner = NULL; + + free(m_pGroup); + m_pGroup = NULL; + + free(m_pDACL); + m_pDACL = NULL; + + free(m_pSACL); + m_pSACL = NULL; + + ATLTRY(m_pSD = new SECURITY_DESCRIPTOR); + if (m_pSD != NULL) + { + if (InitializeSecurityDescriptor(m_pSD, SECURITY_DESCRIPTOR_REVISION)) + return S_OK; + + HRESULT hr = AtlHresultFromLastError(); + delete m_pSD; + m_pSD = NULL; + ATLASSERT(FALSE); + return hr; + } + + return E_OUTOFMEMORY; +} + +inline HRESULT CSecurityDescriptor::InitializeFromProcessToken(BOOL bDefaulted) +{ + HRESULT hr = Initialize(); + if (SUCCEEDED(hr)) + { + PSID pUserSid = NULL; + PSID pGroupSid = NULL; + hr = GetProcessSids(&pUserSid, &pGroupSid); + if (SUCCEEDED(hr)) + { + hr = SetOwner(pUserSid, bDefaulted); + if (SUCCEEDED(hr)) + { + hr = SetGroup(pGroupSid, bDefaulted); + } + free(pUserSid); + free(pGroupSid); + // If something failed reinitialize the object + if (FAILED(hr)) + Initialize(); + } + } + return hr; +} + +inline HRESULT CSecurityDescriptor::InitializeFromThreadToken(BOOL bDefaulted, BOOL bRevertToProcessToken) +{ + HRESULT hr = Initialize(); + if (SUCCEEDED(hr)) + { + PSID pUserSid = NULL; + PSID pGroupSid = NULL; + + hr = GetThreadSids(&pUserSid, &pGroupSid); + if (HRESULT_CODE(hr) == ERROR_NO_TOKEN && bRevertToProcessToken) + hr = GetProcessSids(&pUserSid, &pGroupSid); + if (SUCCEEDED(hr)) + { + hr = SetOwner(pUserSid, bDefaulted); + if (SUCCEEDED(hr)) + hr = SetGroup(pGroupSid, bDefaulted); + free(pUserSid); + free(pGroupSid); + // If something failed reinitialize the object + if (FAILED(hr)) + Initialize(); + } + } + return hr; +} + +inline HRESULT CSecurityDescriptor::SetOwner(PSID pOwnerSid, BOOL bDefaulted) +{ + ATLASSUME(m_pSD); + HRESULT hr = S_OK; + + // Mark the SD as having no owner + if (SetSecurityDescriptorOwner(m_pSD, NULL, bDefaulted)) + { + free(m_pOwner); + m_pOwner = NULL; + + // If they asked for no owner don't do the copy + if (pOwnerSid == NULL) + return S_OK; + + // Make a copy of the Sid for the return value + hr = CloneSID(&m_pOwner, pOwnerSid); + if (SUCCEEDED(hr)) + { + ATLASSERT(IsValidSid(m_pOwner)); + + if (!SetSecurityDescriptorOwner(m_pSD, m_pOwner, bDefaulted)) + { + hr = AtlHresultFromLastError(); + ATLASSERT(FALSE); + free(m_pOwner); + m_pOwner = NULL; + } + } + } + else + { + hr = AtlHresultFromLastError(); + ATLASSERT(FALSE); + } + + return hr; +} + +inline HRESULT CSecurityDescriptor::SetGroup(PSID pGroupSid, BOOL bDefaulted) +{ + ATLASSUME(m_pSD); + HRESULT hr = S_OK; + + // Mark the SD as having no Group + if (SetSecurityDescriptorGroup(m_pSD, NULL, bDefaulted)) + { + free(m_pGroup); + m_pGroup = NULL; + + // If they asked for no Group don't do the copy + if (pGroupSid == NULL) + return S_OK; + + // Make a copy of the Sid for the return value + hr = CloneSID(&m_pGroup, pGroupSid); + if (SUCCEEDED(hr)) + { + ATLASSERT(IsValidSid(m_pGroup)); + + if (!SetSecurityDescriptorGroup(m_pSD, m_pGroup, bDefaulted)) + { + hr = AtlHresultFromLastError(); + ATLASSERT(FALSE); + free(m_pGroup); + m_pGroup = NULL; + } + } + } + else + { + hr = AtlHresultFromLastError(); + ATLASSERT(FALSE); + } + + return hr; +} + +inline HRESULT CSecurityDescriptor::Allow(LPCTSTR pszPrincipal, DWORD dwAccessMask) +{ + PSID pSid; + HRESULT hr = GetPrincipalSID(pszPrincipal, &pSid); + if (SUCCEEDED(hr)) + { + hr = Allow(pSid, dwAccessMask); + free(pSid); + } + return hr; +} + +inline HRESULT CSecurityDescriptor::Deny(LPCTSTR pszPrincipal, DWORD dwAccessMask) +{ + PSID pSid; + HRESULT hr = GetPrincipalSID(pszPrincipal, &pSid); + if (SUCCEEDED(hr)) + { + hr = Deny(pSid, dwAccessMask); + free(pSid); + } + return hr; +} + +inline HRESULT CSecurityDescriptor::Revoke(LPCTSTR pszPrincipal) +{ + PSID pSid; + HRESULT hr = GetPrincipalSID(pszPrincipal, &pSid); + if (SUCCEEDED(hr)) + { + hr = Revoke(pSid); + free(pSid); + } + return hr; +} + +inline HRESULT CSecurityDescriptor::Allow(PSID pSid, DWORD dwAccessMask) +{ + HRESULT hr = AddAccessAllowedACEToACL(&m_pDACL, pSid, dwAccessMask); + if (SUCCEEDED(hr)) + { + if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE)) + hr = AtlHresultFromLastError(); + } + return hr; +} + +inline HRESULT CSecurityDescriptor::Deny(PSID pSid, DWORD dwAccessMask) +{ + HRESULT hr = AddAccessDeniedACEToACL(&m_pDACL, pSid, dwAccessMask); + if (SUCCEEDED(hr)) + { + if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE)) + hr = AtlHresultFromLastError(); + } + return hr; +} + +inline HRESULT CSecurityDescriptor::Revoke(PSID pSid) +{ + HRESULT hr = RemovePrincipalFromACL(m_pDACL, pSid); + if (SUCCEEDED(hr)) + { + if (!SetSecurityDescriptorDacl(m_pSD, TRUE, m_pDACL, FALSE)) + hr = AtlHresultFromLastError(); + } + return hr; +} + +inline HRESULT CSecurityDescriptor::GetProcessSids(PSID* ppUserSid, PSID* ppGroupSid) +{ + HRESULT hr = S_OK; + HANDLE hToken = NULL; + if (ppUserSid) + *ppUserSid = NULL; + if (ppGroupSid) + *ppGroupSid = NULL; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + hr = GetTokenSids(hToken, ppUserSid, ppGroupSid); + CloseHandle(hToken); + } + else + { + // Couldn't open process token + hr = AtlHresultFromLastError(); + ATLASSERT(FALSE); + } + + return hr; +} + +inline HRESULT CSecurityDescriptor::GetThreadSids(PSID* ppUserSid, PSID* ppGroupSid, BOOL bOpenAsSelf) +{ + HRESULT hr = S_OK; + HANDLE hToken = NULL; + if (ppUserSid) + *ppUserSid = NULL; + if (ppGroupSid) + *ppGroupSid = NULL; + if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, bOpenAsSelf, &hToken)) + { + hr = GetTokenSids(hToken, ppUserSid, ppGroupSid); + CloseHandle(hToken); + } + else + // Couldn't open thread token + hr = AtlHresultFromLastError(); + + return hr; +} + +inline HRESULT CSecurityDescriptor::GetTokenSids(HANDLE hToken, PSID* ppUserSid, PSID* ppGroupSid) +{ + DWORD dwSize = 0; + HRESULT hr = S_OK; + if (ppUserSid != NULL) + *ppUserSid = NULL; + if (ppGroupSid != NULL) + *ppGroupSid = NULL; + + if (ppUserSid != NULL) + { + PTOKEN_USER ptkUser = NULL; + + // Get length required for TokenUser by specifying buffer length of 0 + GetTokenInformation(hToken, TokenUser, NULL, 0, &dwSize); + // Expected ERROR_INSUFFICIENT_BUFFER + DWORD dwError = GetLastError(); + if (dwError == ERROR_INSUFFICIENT_BUFFER) + { + ptkUser = (TOKEN_USER*) malloc(dwSize); + if (ptkUser != NULL) + { + // Get Sid of process token. + if (GetTokenInformation(hToken, TokenUser, ptkUser, dwSize, &dwSize)) + { + // Make a copy of the Sid for the return value + hr = CloneSID(ppUserSid, ptkUser->User.Sid); + +#ifdef _DEBUG + if (SUCCEEDED(hr)) + { + ATLASSERT(IsValidSid(*ppUserSid)); + } +#endif + } + else + // Couldn't get user info + hr = AtlHresultFromLastError(); + + free(ptkUser); + ptkUser = NULL; + } + else + hr = E_OUTOFMEMORY; + } + else + { + ATLASSERT(FALSE); + hr = AtlHresultFromWin32(dwError); + } + } + if (SUCCEEDED(hr) && ppGroupSid != NULL) + { + PTOKEN_PRIMARY_GROUP ptkGroup = NULL; + + // Get length required for TokenPrimaryGroup by specifying buffer length of 0 + GetTokenInformation(hToken, TokenPrimaryGroup, NULL, 0, &dwSize); + DWORD dwError = GetLastError(); + // Expected ERROR_INSUFFICIENT_BUFFER + if (dwError == ERROR_INSUFFICIENT_BUFFER) + { + ptkGroup = (TOKEN_PRIMARY_GROUP*) malloc(dwSize); + if (ptkGroup != NULL) + { + // Get Sid of process token. + if (GetTokenInformation(hToken, TokenPrimaryGroup, ptkGroup, dwSize, &dwSize)) + { + // Make a copy of the Sid for the return value + hr = CloneSID(ppGroupSid, ptkGroup->PrimaryGroup); + +#ifdef _DEBUG + if (SUCCEEDED(hr)) + { + ATLASSERT(IsValidSid(*ppGroupSid)); + } +#endif + } + else + // Couldn't get user info + hr = AtlHresultFromLastError(); + + free(ptkGroup); + ptkGroup = NULL; + } + else + hr = E_OUTOFMEMORY; + } + else + hr = AtlHresultFromWin32(dwError); + } + if (FAILED(hr)) + { + if (ppUserSid != NULL) + { + free (*ppUserSid); + *ppUserSid = NULL; + } + if (ppGroupSid != NULL) + { + free (*ppGroupSid); + *ppGroupSid = NULL; + } + } + + return hr; +} + + +inline HRESULT CSecurityDescriptor::GetCurrentUserSID(PSID *ppSid) +{ + if (ppSid == NULL) + return E_POINTER; + *ppSid = NULL; + + HANDLE tkHandle; + HRESULT hr = S_OK; + + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tkHandle)) + { + TOKEN_USER *tkUser = NULL; + DWORD tkSize; + + // Get length required for TokenPrimaryGroup by specifying buffer length of 0 + GetTokenInformation(tkHandle, TokenUser, NULL, 0, &tkSize); + DWORD dwError = GetLastError(); + // Expected ERROR_INSUFFICIENT_BUFFER + if (dwError == ERROR_INSUFFICIENT_BUFFER) + { + tkUser = (TOKEN_USER *) malloc(tkSize); + if (tkUser != NULL) + { + // Now make the real call + if (GetTokenInformation(tkHandle, TokenUser, tkUser, tkSize, &tkSize)) + { + hr = CloneSID(ppSid, tkUser->User.Sid); + +#ifdef _DEBUG + if (SUCCEEDED(hr)) + { + ATLASSERT(IsValidSid(*ppSid)); + } +#endif + } + else + hr = AtlHresultFromLastError(); + + free (tkUser); + tkUser = NULL; + } + else + hr = E_OUTOFMEMORY; + } + else + { + hr = AtlHresultFromWin32(dwError); + ATLASSERT(FALSE); + } + CloseHandle(tkHandle); + } + else + hr = AtlHresultFromLastError(); + + return hr; +} + + +inline HRESULT CSecurityDescriptor::GetPrincipalSID(LPCTSTR pszPrincipal, PSID *ppSid) +{ + if (ppSid == NULL) + return E_POINTER; + if (pszPrincipal == NULL) + return E_INVALIDARG; + *ppSid = NULL; + + HRESULT hr; + LPTSTR pszRefDomain = NULL; + DWORD dwDomainSize = 0; + DWORD dwSidSize = 0; + SID_NAME_USE snu; + DWORD dwError; + + // Call to get size info for alloc + LookupAccountName(NULL, pszPrincipal, NULL, &dwSidSize, NULL, &dwDomainSize, &snu); + + dwError = GetLastError(); + if (dwError == ERROR_INSUFFICIENT_BUFFER) + { + ATLTRY(pszRefDomain = new TCHAR[dwDomainSize]); + if (pszRefDomain != NULL) + { + *ppSid = (PSID) malloc(dwSidSize); + if (*ppSid != NULL) + { + if (LookupAccountName(NULL, pszPrincipal, *ppSid, &dwSidSize, pszRefDomain, &dwDomainSize, &snu)) + { + hr = S_OK; + } + else + { + hr = AtlHresultFromLastError(); + free(*ppSid); + *ppSid = NULL; + } + } + else + hr = E_OUTOFMEMORY; + delete[] pszRefDomain; + } + else + hr = E_OUTOFMEMORY; + } + else + hr = AtlHresultFromWin32(dwError); + + return hr; +} + +inline HRESULT CSecurityDescriptor::Attach(PSECURITY_DESCRIPTOR pSelfRelativeSD) +{ + PACL pDACL = NULL; + PACL pSACL = NULL; + BOOL bDACLPresent, bSACLPresent; + BOOL bDefaulted; + HRESULT hr; + PSID pUserSid; + PSID pGroupSid; + + if (pSelfRelativeSD == NULL || !IsValidSecurityDescriptor(pSelfRelativeSD)) + return E_INVALIDARG; + + hr = Initialize(); + if(FAILED(hr)) + return hr; + + // get the existing DACL. + if (GetSecurityDescriptorDacl(pSelfRelativeSD, &bDACLPresent, &pDACL, &bDefaulted)) + { + if (bDACLPresent) + { + // pDACL should be valid if bDACLPresent is true + ATLENSURE_RETURN(pDACL != NULL); + // allocate new DACL. + m_pDACL = (PACL) malloc(pDACL->AclSize); + if (m_pDACL != NULL) + { + // initialize the DACL + if (InitializeAcl(m_pDACL, pDACL->AclSize, ACL_REVISION)) + { + // copy the ACL + hr = CopyACL(m_pDACL, pDACL); + if (SUCCEEDED(hr) && !IsValidAcl(m_pDACL)) + hr = E_FAIL; + } + else + hr = AtlHresultFromLastError(); + } + else + hr = E_OUTOFMEMORY; + } + // set the DACL + if (SUCCEEDED(hr) && !SetSecurityDescriptorDacl(m_pSD, bDACLPresent, m_pDACL, bDefaulted)) + hr = AtlHresultFromLastError(); + } + else + hr = AtlHresultFromLastError(); + + // get the existing SACL. + if (SUCCEEDED(hr) && GetSecurityDescriptorSacl(pSelfRelativeSD, &bSACLPresent, &pSACL, &bDefaulted)) + { + if (bSACLPresent) + { + // pSACL should be valid if bSACLPresent is true + ATLENSURE_RETURN(pSACL != NULL); + // allocate new SACL. + m_pSACL = (PACL) malloc(pSACL->AclSize); + if (m_pSACL != NULL) + { + // initialize the SACL + if (InitializeAcl(m_pSACL, pSACL->AclSize, ACL_REVISION)) + { + // copy the ACL + hr = CopyACL(m_pSACL, pSACL); + if (SUCCEEDED(hr) && !IsValidAcl(m_pSACL)) + hr = E_FAIL; + } + else + hr = AtlHresultFromLastError(); + } + else + hr = E_OUTOFMEMORY; + } + // set the SACL + if (SUCCEEDED(hr) && !SetSecurityDescriptorSacl(m_pSD, bSACLPresent, m_pSACL, bDefaulted)) + hr = AtlHresultFromLastError(); + } + else if (SUCCEEDED(hr)) + hr = AtlHresultFromLastError(); + + if (SUCCEEDED(hr)) + { + if (GetSecurityDescriptorOwner(pSelfRelativeSD, &pUserSid, &bDefaulted)) + { + if (SUCCEEDED(hr = SetOwner(pUserSid, bDefaulted))) + { + if (GetSecurityDescriptorGroup(pSelfRelativeSD, &pGroupSid, &bDefaulted)) + { + if (SUCCEEDED(hr = SetGroup(pGroupSid, bDefaulted))) + { + if (!IsValidSecurityDescriptor(m_pSD)) + hr = E_FAIL; + } + } + else + hr = AtlHresultFromLastError(); + } + } + else + hr = AtlHresultFromLastError(); + } + + if (FAILED(hr)) + { + free(m_pDACL); + m_pDACL = NULL; + + free(m_pSACL); + m_pSACL = NULL; + + delete m_pSD; + m_pSD = NULL; + } + + return hr; +} + +inline HRESULT CSecurityDescriptor::AttachObject(HANDLE hObject) +{ + HRESULT hr; + DWORD dwError; + DWORD dwSize = 0; + PSECURITY_DESCRIPTOR pSD = NULL; + +#pragma warning(push) +#pragma warning(disable: 6309 6387) + /* prefast noise VSW 497702 */ + GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, NULL, 0, &dwSize); +#pragma warning(pop) + + dwError = GetLastError(); + if (dwError != ERROR_INSUFFICIENT_BUFFER) + return AtlHresultFromWin32(dwError); + + pSD = (PSECURITY_DESCRIPTOR) malloc(dwSize); + if (pSD != NULL) + { + if (GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION, pSD, dwSize, &dwSize)) + + hr = Attach(pSD); + else + hr = AtlHresultFromLastError(); + free(pSD); + } + else + hr = E_OUTOFMEMORY; + + return hr; +} + + +inline HRESULT CSecurityDescriptor::CopyACL(PACL pDest, PACL pSrc) +{ + ACL_SIZE_INFORMATION aclSizeInfo; + LPVOID pAce; + ACE_HEADER *aceHeader; + + if (pDest == NULL) + return E_POINTER; + + if (pSrc == NULL) + return S_OK; + + if (!GetAclInformation(pSrc, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) + return AtlHresultFromLastError(); + + // Copy all of the ACEs to the new ACL + for (UINT i = 0; i < aclSizeInfo.AceCount; i++) + { + if (!GetAce(pSrc, i, &pAce)) + return AtlHresultFromLastError(); + + aceHeader = (ACE_HEADER *) pAce; + + if (!AddAce(pDest, ACL_REVISION, 0xffffffff, pAce, aceHeader->AceSize)) + return AtlHresultFromLastError(); + } + + return S_OK; +} + +inline HRESULT CSecurityDescriptor::AddAccessDeniedACEToACL(PACL *ppAcl, PSID pSid, DWORD dwAccessMask) +{ + ACL_SIZE_INFORMATION aclSizeInfo; + int aclSize; + PACL oldACL, newACL = NULL; + HRESULT hr = S_OK; + + if (ppAcl == NULL) + return E_POINTER; + + oldACL = *ppAcl; + + if (pSid == NULL || !IsValidSid(pSid)) + return E_INVALIDARG; + + aclSizeInfo.AclBytesInUse = 0; + if (*ppAcl != NULL && !GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) + hr = AtlHresultFromLastError(); + + if (SUCCEEDED(hr)) + { + aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_DENIED_ACE) + GetLengthSid(pSid) - sizeof(DWORD); + newACL = (PACL) malloc(aclSize); + if (newACL != NULL) + { + if (InitializeAcl(newACL, aclSize, ACL_REVISION)) + { + // access denied ACEs should be before access allowed ACEs + if (AddAccessDeniedAce(newACL, ACL_REVISION2, dwAccessMask, pSid)) + { + // Copy existing ACEs to the new ACL + hr = CopyACL(newACL, oldACL); + if (SUCCEEDED(hr)) + { + *ppAcl = newACL; + free(oldACL); + } + } + else + hr = AtlHresultFromLastError(); + } + else + hr = AtlHresultFromLastError(); + + if (FAILED(hr)) + free(newACL); + } + else + hr = E_OUTOFMEMORY; + } + return hr; +} + + +inline HRESULT CSecurityDescriptor::AddAccessAllowedACEToACL(PACL *ppAcl, PSID pSid, DWORD dwAccessMask) +{ + ACL_SIZE_INFORMATION aclSizeInfo; + int aclSize; + HRESULT hr = S_OK; + PACL oldACL, newACL = NULL; + + if (ppAcl == NULL) + return E_POINTER; + + oldACL = *ppAcl; + + if (pSid == NULL || !IsValidSid(pSid)) + return E_INVALIDARG; + + aclSizeInfo.AclBytesInUse = 0; + if (*ppAcl != NULL && !GetAclInformation(oldACL, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) + hr = AtlHresultFromLastError(); + + if (SUCCEEDED(hr)) + { + aclSize = aclSizeInfo.AclBytesInUse + sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSid) - sizeof(DWORD); + newACL = (PACL) malloc(aclSize); + if (newACL != NULL) + { + if (InitializeAcl(newACL, aclSize, ACL_REVISION)) + { + // Copy existing ACEs + hr = CopyACL(newACL, oldACL); + if (SUCCEEDED(hr)) + { + // Add access Allowed ACEs after all other existing ACEs (possibly access denied ACEs) + if (AddAccessAllowedAce(newACL, ACL_REVISION2, dwAccessMask, pSid)) + { + *ppAcl = newACL; + free(oldACL); + } + else + hr = AtlHresultFromLastError(); + } + } + else + hr = AtlHresultFromLastError(); + + if (FAILED(hr)) + free(newACL); + } + else + hr = E_OUTOFMEMORY; + } + return hr; +} + +inline HRESULT CSecurityDescriptor::RemovePrincipalFromACL(PACL pAcl, PSID principalSID) +{ + if (pAcl == NULL || principalSID == NULL || !IsValidSid(principalSID)) + return E_INVALIDARG; + + HRESULT hr = S_OK; + ACL_SIZE_INFORMATION aclSizeInfo; + if (!GetAclInformation(pAcl, (LPVOID) &aclSizeInfo, (DWORD) sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) + { + hr = AtlHresultFromLastError(); + aclSizeInfo.AceCount = 0; + } + + for (ULONG i = aclSizeInfo.AceCount; i > 0; i--) + { + ULONG uIndex = i - 1; + LPVOID ace; + if (!GetAce(pAcl, uIndex, &ace)) + { + hr = AtlHresultFromLastError(); + break; + } + + ACE_HEADER *aceHeader = (ACE_HEADER *) ace; + + if (aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) + { + ACCESS_ALLOWED_ACE *accessAllowedAce = (ACCESS_ALLOWED_ACE *) ace; + if (EqualSid(principalSID, (PSID) &accessAllowedAce->SidStart)) + { + DeleteAce(pAcl, uIndex); + } + } + else if (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE) + { + ACCESS_DENIED_ACE *accessDeniedAce = (ACCESS_DENIED_ACE *) ace; + if (EqualSid(principalSID, (PSID) &accessDeniedAce->SidStart)) + { + DeleteAce(pAcl, uIndex); + } + } + else if (aceHeader->AceType == SYSTEM_AUDIT_ACE_TYPE) + { + SYSTEM_AUDIT_ACE *systemAuditAce = (SYSTEM_AUDIT_ACE *) ace; + if (EqualSid(principalSID, (PSID) &systemAuditAce->SidStart)) + { + DeleteAce(pAcl, uIndex); + } + } + } + return hr; +} + +inline HRESULT CSecurityDescriptor::SetPrivilege(LPCTSTR privilege, BOOL bEnable, HANDLE hToken) +{ + TOKEN_PRIVILEGES tpPrevious; + TOKEN_PRIVILEGES tp; + DWORD cbPrevious = sizeof(TOKEN_PRIVILEGES); + LUID luid; + HANDLE hTokenUsed; + + if (!LookupPrivilegeValue(NULL, privilege, &luid )) + goto _Error; + + // if no token specified open process token + if (hToken != 0) + hTokenUsed = hToken; + else + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hTokenUsed)) + goto _Error; + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = 0; + + memset(&tpPrevious, 0, sizeof(tpPrevious)); + + if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &tpPrevious, &cbPrevious)) + goto _Error_CloseHandle; + + if(tpPrevious.PrivilegeCount == 0) + tpPrevious.Privileges[0].Attributes = 0; + + tpPrevious.PrivilegeCount = 1; + tpPrevious.Privileges[0].Luid = luid; + + if (bEnable) + tpPrevious.Privileges[0].Attributes |= SE_PRIVILEGE_ENABLED; + else + tpPrevious.Privileges[0].Attributes &= ~SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(hTokenUsed, FALSE, &tpPrevious, cbPrevious, NULL, NULL)) + goto _Error_CloseHandle; + + if(hToken == 0) + CloseHandle(hTokenUsed); + + return S_OK; + + HRESULT hr; + +_Error: + hr = AtlHresultFromLastError(); + return hr; + +_Error_CloseHandle: + hr = AtlHresultFromLastError(); + if (hToken == 0) + CloseHandle(hTokenUsed); + return hr; +} + +///////////////////////////////////////////////////////////////////////////// +// COM Objects + +#define DECLARE_PROTECT_FINAL_CONSTRUCT()\ + void InternalFinalConstructAddRef() {InternalAddRef();}\ + void InternalFinalConstructRelease() {InternalRelease();} + +template +class CComCreator +{ +public: + static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) + { + ATLASSERT(ppv != NULL); + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + + HRESULT hRes = E_OUTOFMEMORY; + T1* p = NULL; +#pragma warning(push) +#pragma warning(disable: 4068 6014 28197) + /* prefast noise VSW 489981 */ + ATLTRY(p = new T1(pv)) +#pragma warning(pop) + if (p != NULL) + { + p->SetVoid(pv); + p->InternalFinalConstructAddRef(); + hRes = p->_AtlInitialConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->FinalConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->_AtlFinalConstruct(); + p->InternalFinalConstructRelease(); + if (hRes == S_OK) + hRes = p->QueryInterface(riid, ppv); + if (hRes != S_OK) + delete p; + } + return hRes; + } +}; + +template +class CComInternalCreator +{ +public: + static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) + { + ATLASSERT(ppv != NULL); + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + + HRESULT hRes = E_OUTOFMEMORY; + T1* p = NULL; +#pragma warning(push) +#pragma warning(disable: 6014) + ATLTRY(p = new T1(pv)) +#pragma warning(pop) + if (p != NULL) + { + p->SetVoid(pv); + p->InternalFinalConstructAddRef(); + hRes = p->_AtlInitialConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->FinalConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->_AtlFinalConstruct(); + p->InternalFinalConstructRelease(); + if (hRes == S_OK) + hRes = p->_InternalQueryInterface(riid, ppv); + if (hRes != S_OK) + delete p; + } + return hRes; + } +}; + +template +class CComFailCreator +{ +public: + static HRESULT WINAPI CreateInstance(void*, REFIID, LPVOID* ppv) + { + if (ppv == NULL) + return E_POINTER; + *ppv = NULL; + + return hr; + } +}; + +template +class CComCreator2 +{ +public: + static HRESULT WINAPI CreateInstance(void* pv, REFIID riid, LPVOID* ppv) + { + ATLASSERT(ppv != NULL); + + return (pv == NULL) ? + T1::CreateInstance(NULL, riid, ppv) : + T2::CreateInstance(pv, riid, ppv); + } +}; + +#define DECLARE_NOT_AGGREGATABLE(x) public:\ + typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComFailCreator > _CreatorClass; +#define DECLARE_AGGREGATABLE(x) public:\ + typedef ATL::CComCreator2< ATL::CComCreator< ATL::CComObject< x > >, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass; +#define DECLARE_ONLY_AGGREGATABLE(x) public:\ + typedef ATL::CComCreator2< ATL::CComFailCreator, ATL::CComCreator< ATL::CComAggObject< x > > > _CreatorClass; +#define DECLARE_POLY_AGGREGATABLE(x) public:\ + typedef ATL::CComCreator< ATL::CComPolyObject< x > > _CreatorClass; + +struct _ATL_CREATORDATA +{ + _ATL_CREATORFUNC* pFunc; +}; + +template +class _CComCreatorData +{ +public: + static _ATL_CREATORDATA data; +}; + +template +_ATL_CREATORDATA _CComCreatorData::data = {Creator::CreateInstance}; + +struct _ATL_CACHEDATA +{ + DWORD dwOffsetVar; + _ATL_CREATORFUNC* pFunc; +}; + +template +class _CComCacheData +{ +public: + static _ATL_CACHEDATA data; +}; + +template +_ATL_CACHEDATA _CComCacheData::data = {dwVar, Creator::CreateInstance}; + +struct _ATL_CHAINDATA +{ + DWORD_PTR dwOffset; + const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)(); +}; + +template +class _CComChainData +{ +public: + static _ATL_CHAINDATA data; +}; + +template +_ATL_CHAINDATA _CComChainData::data = + {offsetofclass(base, derived), base::_GetEntries}; + +template +class CComAggregateCreator +{ +public: + static HRESULT WINAPI CreateInstance(void* pv, REFIID/*riid*/, LPVOID* ppv) throw() + { + // Only Assert here. CoCreateInstance will return the correct HRESULT if ppv == NULL + ATLASSERT(ppv != NULL && *ppv == NULL); + + ATLASSERT(pv != NULL); + if (pv == NULL) + return E_INVALIDARG; + + T* p = (T*) pv; + // Add the following line to your object if you get a message about + // GetControllingUnknown() being undefined + // DECLARE_GET_CONTROLLING_UNKNOWN() + return CoCreateInstance(*pclsid, p->GetControllingUnknown(), CLSCTX_INPROC, __uuidof(IUnknown), ppv); + } +}; + +#ifdef _ATL_DEBUG +#define DEBUG_QI_ENTRY(x) \ + {NULL, \ + (DWORD_PTR)_T(#x), \ + (ATL::_ATL_CREATORARGFUNC*)0}, +#else +#define DEBUG_QI_ENTRY(x) +#endif //_ATL_DEBUG + +#ifdef _ATL_DEBUG_INTERFACES +#define _ATL_DECLARE_GET_UNKNOWN(x)\ + IUnknown* GetUnknown() throw() \ + { \ + IUnknown* p; \ + ATL::_AtlDebugInterfacesModule.AddNonAddRefThunk(_GetRawUnknown(), _T(#x), &p); \ + return p; \ + } +#else +#define _ATL_DECLARE_GET_UNKNOWN(x) IUnknown* GetUnknown() throw() {return _GetRawUnknown();} +#endif + +//If you get a message that FinalConstruct is ambiguous then you need to +// override it in your class and call each base class' version of this +#define BEGIN_COM_MAP(x) public: \ + typedef x _ComMapClass; \ + static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) throw()\ + {\ + _ComMapClass* p = (_ComMapClass*)pv;\ + p->Lock();\ + HRESULT hRes = E_FAIL; \ + __try \ + { \ + hRes = ATL::CComObjectRootBase::_Cache(pv, iid, ppvObject, dw);\ + } \ + __finally \ + { \ + p->Unlock();\ + } \ + return hRes;\ + }\ + IUnknown* _GetRawUnknown() throw() \ + { ATLASSERT(_GetEntries()[0].pFunc == _ATL_SIMPLEMAPENTRY); return (IUnknown*)((INT_PTR)this+_GetEntries()->dw); } \ + _ATL_DECLARE_GET_UNKNOWN(x)\ + HRESULT _InternalQueryInterface(REFIID iid, void** ppvObject) throw() \ + { return InternalQueryInterface(this, _GetEntries(), iid, ppvObject); } \ + const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetEntries() throw() { \ + static const ATL::_ATL_INTMAP_ENTRY _entries[] = { DEBUG_QI_ENTRY(x) + +// For use by attributes for chaining to existing COM_MAP +#define BEGIN_ATTRCOM_MAP(x) public: \ + typedef x _AttrComMapClass; \ + const static ATL::_ATL_INTMAP_ENTRY* WINAPI _GetAttrEntries() throw() { \ + static const ATL::_ATL_INTMAP_ENTRY _entries[] = { + +#define DECLARE_GET_CONTROLLING_UNKNOWN() public:\ + virtual IUnknown* GetControllingUnknown() throw() {return GetUnknown();} + +#define COM_INTERFACE_ENTRY_BREAK(x)\ + {&_ATL_IIDOF(x), \ + NULL, \ + _Break}, + +#define COM_INTERFACE_ENTRY_NOINTERFACE(x)\ + {&_ATL_IIDOF(x), \ + NULL, \ + _NoInterface}, + +#define COM_INTERFACE_ENTRY(x)\ + {&_ATL_IIDOF(x), \ + offsetofclass(x, _ComMapClass), \ + _ATL_SIMPLEMAPENTRY}, + +#define COM_INTERFACE_ENTRY_IID(iid, x)\ + {&iid,\ + offsetofclass(x, _ComMapClass),\ + _ATL_SIMPLEMAPENTRY}, + +// The impl macros are now obsolete +#define COM_INTERFACE_ENTRY_IMPL(x)\ + COM_INTERFACE_ENTRY_IID(_ATL_IIDOF(x), x##Impl<_ComMapClass>) + +#define COM_INTERFACE_ENTRY_IMPL_IID(iid, x)\ + COM_INTERFACE_ENTRY_IID(iid, x##Impl<_ComMapClass>) +// + +#define COM_INTERFACE_ENTRY2(x, x2)\ + {&_ATL_IIDOF(x),\ + reinterpret_cast(static_cast(static_cast(reinterpret_cast<_ComMapClass*>(8))))-8,\ + _ATL_SIMPLEMAPENTRY}, + +#define COM_INTERFACE_ENTRY2_IID(iid, x, x2)\ + {&iid,\ + reinterpret_cast(static_cast(static_cast(reinterpret_cast<_ComMapClass*>(8))))-8,\ + _ATL_SIMPLEMAPENTRY}, + +#define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)\ + {&iid, \ + dw, \ + func}, + +#define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)\ + {NULL, \ + dw, \ + func}, + +#define COM_INTERFACE_ENTRY_TEAR_OFF(iid, x)\ + {&iid,\ + (DWORD_PTR)&ATL::_CComCreatorData<\ + ATL::CComInternalCreator< ATL::CComTearOffObject< x > >\ + >::data,\ + _Creator}, + +#define COM_INTERFACE_ENTRY_CACHED_TEAR_OFF(iid, x, punk)\ + {&iid,\ + (DWORD_PTR)&ATL::_CComCacheData<\ + ATL::CComCreator< ATL::CComCachedTearOffObject< x > >,\ + (DWORD_PTR)offsetof(_ComMapClass, punk)\ + >::data,\ + _Cache}, + +#define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)\ + {&iid,\ + (DWORD_PTR)offsetof(_ComMapClass, punk),\ + _Delegate}, + +#define COM_INTERFACE_ENTRY_AGGREGATE_BLIND(punk)\ + {NULL,\ + (DWORD_PTR)offsetof(_ComMapClass, punk),\ + _Delegate}, + +#define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)\ + {&iid,\ + (DWORD_PTR)&ATL::_CComCacheData<\ + ATL::CComAggregateCreator<_ComMapClass, &clsid>,\ + (DWORD_PTR)offsetof(_ComMapClass, punk)\ + >::data,\ + _Cache}, + +#define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)\ + {NULL,\ + (DWORD_PTR)&ATL::_CComCacheData<\ + ATL::CComAggregateCreator<_ComMapClass, &clsid>,\ + (DWORD_PTR)offsetof(_ComMapClass, punk)\ + >::data,\ + _Cache}, + +#define COM_INTERFACE_ENTRY_CHAIN(classname)\ + {NULL,\ + (DWORD_PTR)&ATL::_CComChainData::data,\ + _Chain}, + +#ifdef _ATL_DEBUG +#define END_COM_MAP() \ + __if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }\ + {NULL, 0, 0}}; return &_entries[1];} \ + virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; \ + virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; \ + STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0; +#else +#define END_COM_MAP() \ + __if_exists(_GetAttrEntries) {{NULL, (DWORD_PTR)_GetAttrEntries, _ChainAttr }, }\ + {NULL, 0, 0}}; return _entries;} \ + virtual ULONG STDMETHODCALLTYPE AddRef( void) throw() = 0; \ + virtual ULONG STDMETHODCALLTYPE Release( void) throw() = 0; \ + STDMETHOD(QueryInterface)(REFIID, void**) throw() = 0; +#endif // _ATL_DEBUG + +#define END_ATTRCOM_MAP() \ + {NULL, 0, 0}}; return _entries;} + + +#define BEGIN_CATEGORY_MAP(x)\ + static const struct ATL::_ATL_CATMAP_ENTRY* GetCategoryMap() throw() {\ + static const struct ATL::_ATL_CATMAP_ENTRY pMap[] = { +#define IMPLEMENTED_CATEGORY( catid ) { _ATL_CATMAP_ENTRY_IMPLEMENTED, &catid }, +#define REQUIRED_CATEGORY( catid ) { _ATL_CATMAP_ENTRY_REQUIRED, &catid }, +#define END_CATEGORY_MAP()\ + { _ATL_CATMAP_ENTRY_END, NULL } };\ + return( pMap ); } + +#define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = { +#define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}}; +#define OBJECT_ENTRY(clsid, class) {&clsid, class::UpdateRegistry, class::_ClassFactoryCreatorClass::CreateInstance, class::_CreatorClass::CreateInstance, NULL, 0, class::GetObjectDescription, class::GetCategoryMap, class::ObjectMain }, +#define OBJECT_ENTRY_NON_CREATEABLE(class) {&CLSID_NULL, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, class::GetCategoryMap, class::ObjectMain }, +#define OBJECT_ENTRY_NON_CREATEABLE_EX(clsid, class) {&clsid, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, class::GetCategoryMap, class::ObjectMain }, + +#ifndef OBJECT_ENTRY_PRAGMA + +#if defined(_M_IX86) +#define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:___pobjMap_" #class)); +#elif defined(_M_IA64) +#define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pobjMap_" #class)); +#elif defined(_M_AMD64) +#define OBJECT_ENTRY_PRAGMA(class) __pragma(comment(linker, "/include:__pobjMap_" #class)); +#else +#error Unknown Platform. define OBJECT_ENTRY_PRAGMA +#endif + +#endif //OBJECT_ENTRY_PRAGMA + +#define OBJECT_ENTRY_AUTO(clsid, class) \ + __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY __objMap_##class = {&clsid, class::UpdateRegistry, class::_ClassFactoryCreatorClass::CreateInstance, class::_CreatorClass::CreateInstance, NULL, 0, class::GetObjectDescription, class::GetCategoryMap, class::ObjectMain }; \ + extern "C" __declspec(allocate("ATL$__m")) __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY* const __pobjMap_##class = &__objMap_##class; \ + OBJECT_ENTRY_PRAGMA(class) + + +#define OBJECT_ENTRY_NON_CREATEABLE_EX_AUTO(clsid, class) \ + __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY __objMap_##class = {&clsid, class::UpdateRegistry, NULL, NULL, NULL, 0, NULL, class::GetCategoryMap, class::ObjectMain }; \ + extern "C" __declspec(allocate("ATL$__m")) __declspec(selectany) ATL::_ATL_OBJMAP_ENTRY* const __pobjMap_##class = &__objMap_##class; \ + OBJECT_ENTRY_PRAGMA(class) + +// the functions in this class don't need to be virtual because +// they are called from CComObject +class CComObjectRootBase +{ +public: + CComObjectRootBase() + { + m_dwRef = 0L; + } + ~CComObjectRootBase() + { + } + HRESULT FinalConstruct() + { + return S_OK; + } + // For library initialization only + HRESULT _AtlFinalConstruct() + { + return S_OK; + } + void FinalRelease() {} + void _AtlFinalRelease() {} // temp + + void _HRPass(HRESULT hr) // temp + { + (hr); + } + + void _HRFail(HRESULT hr) // temp... + { + (hr); + } + + + //ObjectMain is called during Module::Init and Module::Term + static void WINAPI ObjectMain(bool /* bStarting */); + + static const struct _ATL_CATMAP_ENTRY* GetCategoryMap() {return NULL;}; + static HRESULT WINAPI InternalQueryInterface(void* pThis, + const _ATL_INTMAP_ENTRY* pEntries, REFIID iid, void** ppvObject) + { + // Only Assert here. AtlInternalQueryInterface will return the correct HRESULT if ppvObject == NULL +#ifndef _ATL_OLEDB_CONFORMANCE_TESTS + ATLASSERT(ppvObject != NULL); +#endif + ATLASSERT(pThis != NULL); + // First entry in the com map should be a simple map entry + ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY); + #if defined(_ATL_DEBUG_INTERFACES) || defined(_ATL_DEBUG_QI) + LPCTSTR pszClassName = (LPCTSTR) pEntries[-1].dw; + #endif // _ATL_DEBUG_INTERFACES + HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject); + #ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, pszClassName, iid); + #endif // _ATL_DEBUG_INTERFACES + return _ATLDUMPIID(iid, pszClassName, hRes); + } + +//Outer funcs + ULONG OuterAddRef() + { + return m_pOuterUnknown->AddRef(); + } + ULONG OuterRelease() + { + return m_pOuterUnknown->Release(); + } + HRESULT OuterQueryInterface(REFIID iid, void ** ppvObject) + { + return m_pOuterUnknown->QueryInterface(iid, ppvObject); + } + + void SetVoid(void*) {} + void InternalFinalConstructAddRef() {} + void InternalFinalConstructRelease() + { + ATLASSUME(m_dwRef == 0); + } + // If this assert occurs, your object has probably been deleted + // Try using DECLARE_PROTECT_FINAL_CONSTRUCT() + + + static HRESULT WINAPI _Break(void* /* pv */, REFIID iid, void** /* ppvObject */, DWORD_PTR /* dw */) + { + (iid); + _ATLDUMPIID(iid, _T("Break due to QI for interface "), S_OK); + DebugBreak(); + return S_FALSE; + } + static HRESULT WINAPI _NoInterface(void* /* pv */, REFIID /* iid */, void** /* ppvObject */, DWORD_PTR /* dw */) + { + return E_NOINTERFACE; + } + static HRESULT WINAPI _Creator(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) + { + _ATL_CREATORDATA* pcd = (_ATL_CREATORDATA*)dw; + return pcd->pFunc(pv, iid, ppvObject); + } + static HRESULT WINAPI _Delegate(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) + { + HRESULT hRes = E_NOINTERFACE; + IUnknown* p = *(IUnknown**)((DWORD_PTR)pv + dw); + if (p != NULL) + hRes = p->QueryInterface(iid, ppvObject); + return hRes; + } + static HRESULT WINAPI _Chain(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) + { + _ATL_CHAINDATA* pcd = (_ATL_CHAINDATA*)dw; + void* p = (void*)((DWORD_PTR)pv + pcd->dwOffset); + return InternalQueryInterface(p, pcd->pFunc(), iid, ppvObject); + } + static HRESULT WINAPI _ChainAttr(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) + { + const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)() = (const _ATL_INTMAP_ENTRY* (WINAPI *)())dw; + const _ATL_INTMAP_ENTRY *pEntries = pFunc(); + if (pEntries == NULL) + return S_OK; + return InternalQueryInterface(pv, pEntries, iid, ppvObject); + } + static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD_PTR dw) + { + HRESULT hRes = E_NOINTERFACE; + _ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw; + IUnknown** pp = (IUnknown**)((DWORD_PTR)pv + pcd->dwOffsetVar); + if (*pp == NULL) + hRes = pcd->pFunc(pv, __uuidof(IUnknown), (void**)pp); + if (*pp != NULL) + hRes = (*pp)->QueryInterface(iid, ppvObject); + return hRes; + } + + union + { + long m_dwRef; + IUnknown* m_pOuterUnknown; + }; +}; + +#pragma managed(push, off) +inline void WINAPI CComObjectRootBase::ObjectMain(bool /* bStarting */) +{ +} +#pragma managed(pop) + + +//foward declaration +template +class CComObjectRootEx; + +template +class CComObjectLockT +{ +public: + CComObjectLockT(CComObjectRootEx* p) + { + if (p) + p->Lock(); + m_p = p; + } + + ~CComObjectLockT() + { + if (m_p) + m_p->Unlock(); + } + CComObjectRootEx* m_p; +}; + +template <> class CComObjectLockT; + +template +class CComObjectRootEx : public CComObjectRootBase +{ +public: + typedef ThreadModel _ThreadModel; + typedef typename _ThreadModel::AutoCriticalSection _CritSec; + typedef typename _ThreadModel::AutoDeleteCriticalSection _AutoDelCritSec; + typedef CComObjectLockT<_ThreadModel> ObjectLock; + + ~CComObjectRootEx() {} + + ULONG InternalAddRef() + { + ATLASSUME(m_dwRef != -1L); + return _ThreadModel::Increment(&m_dwRef); + } + ULONG InternalRelease() + { +#ifdef _DEBUG + LONG nRef = _ThreadModel::Decrement(&m_dwRef); + if (nRef < -(LONG_MAX / 2)) + { + ATLASSERT(0 && _T("Release called on a pointer that has already been released")); + } + return nRef; +#else + return _ThreadModel::Decrement(&m_dwRef); +#endif + } + + HRESULT _AtlInitialConstruct() + { + return m_critsec.Init(); + } + void Lock() {m_critsec.Lock();} + void Unlock() {m_critsec.Unlock();} +private: + _AutoDelCritSec m_critsec; +}; + +template <> +class CComObjectRootEx : public CComObjectRootBase +{ +public: + typedef CComSingleThreadModel _ThreadModel; + typedef _ThreadModel::AutoCriticalSection _CritSec; + typedef _ThreadModel::AutoDeleteCriticalSection _AutoDelCritSec; + typedef CComObjectLockT<_ThreadModel> ObjectLock; + + ~CComObjectRootEx() {} + + ULONG InternalAddRef() + { + ATLASSUME(m_dwRef != -1L); + return _ThreadModel::Increment(&m_dwRef); + } + ULONG InternalRelease() + { +#ifdef _DEBUG + long nRef = _ThreadModel::Decrement(&m_dwRef); + if (nRef < -(LONG_MAX / 2)) + { + ATLASSERT(0 && _T("Release called on a pointer that has already been released")); + } + return nRef; +#else + return _ThreadModel::Decrement(&m_dwRef); +#endif + } + + HRESULT _AtlInitialConstruct() + { + return S_OK; + } + + void Lock() {} + void Unlock() {} +}; + +template <> +class CComObjectLockT +{ +public: + CComObjectLockT(CComObjectRootEx*) {} + ~CComObjectLockT() {} +}; + +typedef CComObjectRootEx CComObjectRoot; + +#if defined(_WINDLL) | defined(_USRDLL) +#define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectCached< cf > > _ClassFactoryCreatorClass; +#else +// don't let class factory refcount influence lock count +#define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator< ATL::CComObjectNoLock< cf > > _ClassFactoryCreatorClass; +#endif +#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory) +#define DECLARE_CLASSFACTORY2(lic) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory2) +#define DECLARE_CLASSFACTORY_AUTO_THREAD() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactoryAutoThread) +#define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton) + +#define DECLARE_OBJECT_DESCRIPTION(x)\ + static LPCTSTR WINAPI GetObjectDescription() throw()\ + {\ + return _T(x);\ + } + +#define DECLARE_NO_REGISTRY()\ + static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/) throw()\ + {return S_OK;} + +#define DECLARE_REGISTRY(class, pid, vpid, nid, flags)\ + static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\ + {\ + return _Module.UpdateRegistryClass(GetObjectCLSID(), pid, vpid, nid,\ + flags, bRegister);\ + } + +#define DECLARE_REGISTRY_RESOURCE(x)\ + static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\ + {\ + __if_exists(_GetMiscStatus) \ + { \ + ATL::_ATL_REGMAP_ENTRY regMapEntries[2]; \ + memset(®MapEntries[1], 0, sizeof(ATL::_ATL_REGMAP_ENTRY)); \ + regMapEntries[0].szKey = L"OLEMISC"; \ + TCHAR szOleMisc[32]; \ + ATL::Checked::itot_s(_GetMiscStatus(), szOleMisc, _countof(szOleMisc), 10); \ + USES_CONVERSION_EX; \ + regMapEntries[0].szData = T2OLE_EX(szOleMisc, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); \ + if (regMapEntries[0].szData == NULL) \ + return E_OUTOFMEMORY; \ + __if_exists(_Module) \ + { \ + return _Module.UpdateRegistryFromResource(_T(#x), bRegister, regMapEntries); \ + } \ + __if_not_exists(_Module) \ + { \ + return ATL::_pAtlModule->UpdateRegistryFromResource(_T(#x), bRegister, regMapEntries); \ + } \ + } \ + __if_not_exists(_GetMiscStatus) \ + { \ + __if_exists(_Module) \ + { \ + return _Module.UpdateRegistryFromResource(_T(#x), bRegister); \ + } \ + __if_not_exists(_Module) \ + { \ + return ATL::_pAtlModule->UpdateRegistryFromResource(_T(#x), bRegister); \ + } \ + } \ + } + +#define DECLARE_REGISTRY_RESOURCEID(x)\ + static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()\ + {\ + __if_exists(_GetMiscStatus) \ + { \ + ATL::_ATL_REGMAP_ENTRY regMapEntries[2]; \ + memset(®MapEntries[1], 0, sizeof(ATL::_ATL_REGMAP_ENTRY)); \ + regMapEntries[0].szKey = L"OLEMISC"; \ + TCHAR szOleMisc[32]; \ + ATL::Checked::itot_s(_GetMiscStatus(), szOleMisc, _countof(szOleMisc), 10); \ + USES_CONVERSION_EX; \ + regMapEntries[0].szData = T2OLE_EX(szOleMisc, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); \ + if (regMapEntries[0].szData == NULL) \ + return E_OUTOFMEMORY; \ + __if_exists(_Module) \ + { \ + return _Module.UpdateRegistryFromResource(x, bRegister, regMapEntries); \ + } \ + __if_not_exists(_Module) \ + { \ + return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister, regMapEntries); \ + } \ + } \ + __if_not_exists(_GetMiscStatus) \ + { \ + __if_exists(_Module) \ + { \ + return _Module.UpdateRegistryFromResource(x, bRegister); \ + } \ + __if_not_exists(_Module) \ + { \ + return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister); \ + } \ + } \ + } + +//DECLARE_STATIC_* provided for backward compatibility +#ifdef _ATL_STATIC_REGISTRY +#define DECLARE_STATIC_REGISTRY_RESOURCE(x) DECLARE_REGISTRY_RESOURCE(x) +#define DECLARE_STATIC_REGISTRY_RESOURCEID(x) DECLARE_REGISTRY_RESOURCEID(x) +#endif //_ATL_STATIC_REGISTRY + +#define DECLARE_OLEMISC_STATUS(x) \ + static DWORD _GetMiscStatus() throw() \ + { \ + static DWORD m_dwOleMisc = x; \ + return m_dwOleMisc; \ + } + +template class CComObject; // fwd decl + +template +class CComTearOffObjectBase : public CComObjectRootEx +{ +public: + typedef Owner _OwnerClass; + Owner* m_pOwner; + CComTearOffObjectBase() {m_pOwner = NULL;} +}; + +//Base is the user's class that derives from CComObjectRoot and whatever +//interfaces the user wants to support on the object +template +class CComObject : public Base +{ +public: + typedef Base _BaseClass; + CComObject(void* = NULL) throw() + { + _pAtlModule->Lock(); + } + // Set refcount to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + virtual ~CComObject() throw() + { + m_dwRef = -(LONG_MAX/2); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); +#endif + _pAtlModule->Unlock(); + } + //If InternalAddRef or InternalRelease is undefined then your class + //doesn't derive from CComObjectRoot + STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();} + STDMETHOD_(ULONG, Release)() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() + {return _InternalQueryInterface(iid, ppvObject);} + template + HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) throw() + { + return QueryInterface(__uuidof(Q), (void**)pp); + } + + static HRESULT WINAPI CreateInstance(CComObject** pp) throw(); +}; + +template +HRESULT WINAPI CComObject::CreateInstance(CComObject** pp) throw() +{ + ATLASSERT(pp != NULL); + if (pp == NULL) + return E_POINTER; + *pp = NULL; + + HRESULT hRes = E_OUTOFMEMORY; + CComObject* p = NULL; + ATLTRY(p = new CComObject()) + if (p != NULL) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hRes = p->_AtlInitialConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->FinalConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->_AtlFinalConstruct(); + p->InternalFinalConstructRelease(); + if (hRes != S_OK) + { + delete p; + p = NULL; + } + } + *pp = p; + return hRes; +} + +//Base is the user's class that derives from CComObjectRoot and whatever +//interfaces the user wants to support on the object +// CComObjectCached is used primarily for class factories in DLL's +// but it is useful anytime you want to cache an object +template +class CComObjectCached : public Base +{ +public: + typedef Base _BaseClass; + CComObjectCached(void* = NULL){} + // Set refcount to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + // This will be made virtual again for Beta 2 + /*virtual*/ ~CComObjectCached() + { + m_dwRef = -(LONG_MAX/2); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); +#endif + } + //If InternalAddRef or InternalRelease is undefined then your class + //doesn't derive from CComObjectRoot + STDMETHOD_(ULONG, AddRef)() throw() + { + ULONG l = InternalAddRef(); + if (l == 2) + _pAtlModule->Lock(); + return l; + } + STDMETHOD_(ULONG, Release)() throw() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + else if (l == 1) + _pAtlModule->Unlock(); + return l; + } + //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() + {return _InternalQueryInterface(iid, ppvObject);} + static HRESULT WINAPI CreateInstance(CComObjectCached** pp) throw(); +}; + +template +HRESULT WINAPI CComObjectCached::CreateInstance(CComObjectCached** pp) throw() +{ + ATLASSERT(pp != NULL); + if (pp == NULL) + return E_POINTER; + *pp = NULL; + + HRESULT hRes = E_OUTOFMEMORY; + CComObjectCached* p = NULL; + ATLTRY(p = new CComObjectCached()) + if (p != NULL) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hRes = p->_AtlInitialConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->FinalConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->_AtlFinalConstruct(); + p->InternalFinalConstructRelease(); + if (hRes != S_OK) + { + delete p; + p = NULL; + } + } + *pp = p; + return hRes; +} + + +//Base is the user's class that derives from CComObjectRoot and whatever +//interfaces the user wants to support on the object +template +class CComObjectNoLock : public Base +{ +public: + typedef Base _BaseClass; + CComObjectNoLock(void* = NULL){} + // Set refcount to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + + // This will be made virtual again for Beta 2 + /*virtual*/ ~CComObjectNoLock() + { + m_dwRef = -(LONG_MAX/2); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); +#endif + } + + //If InternalAddRef or InternalRelease is undefined then your class + //doesn't derive from CComObjectRoot + STDMETHOD_(ULONG, AddRef)() throw() {return InternalAddRef();} + STDMETHOD_(ULONG, Release)() throw() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() + {return _InternalQueryInterface(iid, ppvObject);} +}; + + +// It is possible for Base not to derive from CComObjectRoot +// However, you will need to provide _InternalQueryInterface +template +class CComObjectGlobal : public Base +{ +public: + typedef Base _BaseClass; + CComObjectGlobal(void* = NULL) + { + m_hResFinalConstruct = S_OK; + __if_exists(FinalConstruct) + { + __if_exists(InternalFinalConstructAddRef) + { + InternalFinalConstructAddRef(); + } + m_hResFinalConstruct = _AtlInitialConstruct(); + if (SUCCEEDED(m_hResFinalConstruct)) + m_hResFinalConstruct = FinalConstruct(); + __if_exists(InternalFinalConstructRelease) + { + InternalFinalConstructRelease(); + } + } + } + virtual ~CComObjectGlobal() + { + __if_exists(FinalRelease) + { + FinalRelease(); + } +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); +#endif + } + + STDMETHOD_(ULONG, AddRef)() throw() + { + return _pAtlModule->Lock(); + } + STDMETHOD_(ULONG, Release)() throw() + { + return _pAtlModule->Unlock(); + } + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() + { + return _InternalQueryInterface(iid, ppvObject); + } + HRESULT m_hResFinalConstruct; +}; + +// It is possible for Base not to derive from CComObjectRoot +// However, you will need to provide FinalConstruct and InternalQueryInterface +template +class CComObjectStack : public Base +{ +public: + typedef Base _BaseClass; + CComObjectStack(void* = NULL) + { + m_hResFinalConstruct = _AtlInitialConstruct(); + if (SUCCEEDED(m_hResFinalConstruct)) + m_hResFinalConstruct = FinalConstruct(); + } + virtual ~CComObjectStack() + { + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); +#endif + } + + + STDMETHOD_(ULONG, AddRef)() throw() {ATLASSERT(FALSE);return 0;} + STDMETHOD_(ULONG, Release)() throw() {ATLASSERT(FALSE);return 0;} + STDMETHOD(QueryInterface)(REFIID, void**) throw() + {ATLASSERT(FALSE);return E_NOINTERFACE;} + HRESULT m_hResFinalConstruct; +}; + +// Base must be derived from CComObjectRoot +template +class CComObjectStackEx : public Base +{ +public: + typedef Base _BaseClass; + + CComObjectStackEx(void* = NULL) + { +#ifdef _DEBUG + m_dwRef = 0; +#endif + m_hResFinalConstruct = _AtlInitialConstruct(); + if (SUCCEEDED(m_hResFinalConstruct)) + m_hResFinalConstruct = FinalConstruct(); + } + + virtual ~CComObjectStackEx() + { + // This assert indicates mismatched ref counts. + // + // The ref count has no control over the + // lifetime of this object, so you must ensure + // by some other means that the object remains + // alive while clients have references to its interfaces. + ATLASSUME(m_dwRef == 0); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); +#endif + } + + STDMETHOD_(ULONG, AddRef)() throw() + { +#ifdef _DEBUG + return InternalAddRef(); +#else + return 0; +#endif + } + + STDMETHOD_(ULONG, Release)() throw() + { +#ifdef _DEBUG + return InternalRelease(); +#else + return 0; +#endif + } + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() + { + return _InternalQueryInterface(iid, ppvObject); + } + + HRESULT m_hResFinalConstruct; +}; + +template //Base must be derived from CComObjectRoot +class CComContainedObject : public Base +{ +public: + typedef Base _BaseClass; + CComContainedObject(void* pv) {m_pOuterUnknown = (IUnknown*)pv;} +#ifdef _ATL_DEBUG_INTERFACES + virtual ~CComContainedObject() + { + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(m_pOuterUnknown); + } +#endif + + STDMETHOD_(ULONG, AddRef)() throw() {return OuterAddRef();} + STDMETHOD_(ULONG, Release)() throw() {return OuterRelease();} + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() + { + return OuterQueryInterface(iid, ppvObject); + } + template + HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) + { + return QueryInterface(__uuidof(Q), (void**)pp); + } + //GetControllingUnknown may be virtual if the Base class has declared + //DECLARE_GET_CONTROLLING_UNKNOWN() + IUnknown* GetControllingUnknown() throw() + { +#ifdef _ATL_DEBUG_INTERFACES + IUnknown* p; + _AtlDebugInterfacesModule.AddNonAddRefThunk(m_pOuterUnknown, _T("CComContainedObject"), &p); + return p; +#else + return m_pOuterUnknown; +#endif + } +}; + +//contained is the user's class that derives from CComObjectRoot and whatever +//interfaces the user wants to support on the object +template +class CComAggObject : + public IUnknown, + public CComObjectRootEx< typename contained::_ThreadModel::ThreadModelNoCS > +{ +public: + typedef contained _BaseClass; + CComAggObject(void* pv) : m_contained(pv) + { + _pAtlModule->Lock(); + } + HRESULT _AtlInitialConstruct() + { + HRESULT hr = m_contained._AtlInitialConstruct(); + if (SUCCEEDED(hr)) + { + hr = CComObjectRootEx< typename contained::_ThreadModel::ThreadModelNoCS >::_AtlInitialConstruct(); + } + return hr; + } + //If you get a message that this call is ambiguous then you need to + // override it in your class and call each base class' version of this + HRESULT FinalConstruct() + { + CComObjectRootEx::FinalConstruct(); + return m_contained.FinalConstruct(); + } + void FinalRelease() + { + CComObjectRootEx::FinalRelease(); + m_contained.FinalRelease(); + } + // Set refcount to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + virtual ~CComAggObject() + { + m_dwRef = -(LONG_MAX/2); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(this); +#endif + _pAtlModule->Unlock(); + } + + STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();} + STDMETHOD_(ULONG, Release)() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) + { + ATLASSERT(ppvObject != NULL); + if (ppvObject == NULL) + return E_POINTER; + *ppvObject = NULL; + + HRESULT hRes = S_OK; + if (InlineIsEqualUnknown(iid)) + { + *ppvObject = (void*)(IUnknown*)this; + AddRef(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid); +#endif // _ATL_DEBUG_INTERFACES + } + else + hRes = m_contained._InternalQueryInterface(iid, ppvObject); + return hRes; + } + template + HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) + { + return QueryInterface(__uuidof(Q), (void**)pp); + } + static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject** pp) + { + ATLASSERT(pp != NULL); + if (pp == NULL) + return E_POINTER; + *pp = NULL; + + HRESULT hRes = E_OUTOFMEMORY; + CComAggObject* p = NULL; + ATLTRY(p = new CComAggObject(pUnkOuter)) + if (p != NULL) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hRes = p->_AtlInitialConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->FinalConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->_AtlFinalConstruct(); + p->InternalFinalConstructRelease(); + if (hRes != S_OK) + { + delete p; + p = NULL; + } + } + *pp = p; + return hRes; + } + + CComContainedObject m_contained; +}; + +/////////////////////////////////////////////////////////////////////////////// +// CComPolyObject can be either aggregated or not aggregated + +template +class CComPolyObject : + public IUnknown, + public CComObjectRootEx< typename contained::_ThreadModel::ThreadModelNoCS > +{ +public: + typedef contained _BaseClass; + CComPolyObject(void* pv) : m_contained(pv ? pv : this) + { + _pAtlModule->Lock(); + } + HRESULT _AtlInitialConstruct() + { + HRESULT hr = m_contained._AtlInitialConstruct(); + if (SUCCEEDED(hr)) + { + hr = CComObjectRootEx< typename contained::_ThreadModel::ThreadModelNoCS >::_AtlInitialConstruct(); + } + return hr; + } + //If you get a message that this call is ambiguous then you need to + // override it in your class and call each base class' version of this + HRESULT FinalConstruct() + { + InternalAddRef(); + CComObjectRootEx::FinalConstruct(); + HRESULT hr = m_contained.FinalConstruct(); + InternalRelease(); + return hr; + } + void FinalRelease() + { + CComObjectRootEx::FinalRelease(); + m_contained.FinalRelease(); + } + // Set refcount to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + virtual ~CComPolyObject() + { + m_dwRef = -(LONG_MAX/2); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(this); +#endif + _pAtlModule->Unlock(); + } + + STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();} + STDMETHOD_(ULONG, Release)() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) + { +#ifndef _ATL_OLEDB_CONFORMANCE_TESTS + ATLASSERT(ppvObject != NULL); +#endif + if (ppvObject == NULL) + return E_POINTER; + *ppvObject = NULL; + + HRESULT hRes = S_OK; + if (InlineIsEqualUnknown(iid)) + { + *ppvObject = (void*)(IUnknown*)this; + AddRef(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid); +#endif // _ATL_DEBUG_INTERFACES + } + else + hRes = m_contained._InternalQueryInterface(iid, ppvObject); + return hRes; + } + template + HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) + { + return QueryInterface(__uuidof(Q), (void**)pp); + } + static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComPolyObject** pp) + { + ATLASSERT(pp != NULL); + if (pp == NULL) + return E_POINTER; + *pp = NULL; + + + HRESULT hRes = E_OUTOFMEMORY; + CComPolyObject* p = NULL; + ATLTRY(p = new CComPolyObject(pUnkOuter)) + if (p != NULL) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hRes = p->_AtlInitialConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->FinalConstruct(); + if (SUCCEEDED(hRes)) + hRes = p->_AtlFinalConstruct(); + p->InternalFinalConstructRelease(); + if (hRes != S_OK) + { + delete p; + p = NULL; + } + } + *pp = p; + return hRes; + } + + CComContainedObject m_contained; +}; + +template +class CComTearOffObject : public Base +{ +public: + CComTearOffObject(void* pv) + { + ATLASSUME(m_pOwner == NULL); + m_pOwner = reinterpret_cast(pv); + m_pOwner->AddRef(); + } + // Set refcount to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + ~CComTearOffObject() + { + m_dwRef = -(LONG_MAX/2); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown()); +#endif + m_pOwner->Release(); + } + + STDMETHOD_(ULONG, AddRef)() throw() {return InternalAddRef();} + STDMETHOD_(ULONG, Release)() throw() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw() + { + return m_pOwner->QueryInterface(iid, ppvObject); + } +}; + +template +class CComCachedTearOffObject : + public IUnknown, + public CComObjectRootEx +{ +public: + typedef contained _BaseClass; + CComCachedTearOffObject(void* pv) : + m_contained(((contained::_OwnerClass*)pv)->GetControllingUnknown()) + { + ATLASSUME(m_contained.m_pOwner == NULL); + m_contained.m_pOwner = reinterpret_cast(pv); + } + HRESULT _AtlInitialConstruct() + { + HRESULT hr = m_contained._AtlInitialConstruct(); + if (SUCCEEDED(hr)) + { + hr = CComObjectRootEx< typename contained::_ThreadModel::ThreadModelNoCS >::_AtlInitialConstruct(); + } + return hr; + } + //If you get a message that this call is ambiguous then you need to + // override it in your class and call each base class' version of this + HRESULT FinalConstruct() + { + CComObjectRootEx::FinalConstruct(); + return m_contained.FinalConstruct(); + } + void FinalRelease() + { + CComObjectRootEx::FinalRelease(); + m_contained.FinalRelease(); + } + // Set refcount to -(LONG_MAX/2) to protect destruction and + // also catch mismatched Release in debug builds + ~CComCachedTearOffObject() + { + m_dwRef = -(LONG_MAX/2); + FinalRelease(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.DeleteNonAddRefThunk(this); +#endif + } + + + STDMETHOD_(ULONG, AddRef)() {return InternalAddRef();} + STDMETHOD_(ULONG, Release)() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) + { + ATLASSERT(ppvObject != NULL); + if (ppvObject == NULL) + return E_POINTER; + *ppvObject = NULL; + + HRESULT hRes = S_OK; + if (InlineIsEqualUnknown(iid)) + { + *ppvObject = (void*)(IUnknown*)this; + AddRef(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, (LPCTSTR)contained::_GetEntries()[-1].dw, iid); +#endif // _ATL_DEBUG_INTERFACES + } + else + hRes = m_contained._InternalQueryInterface(iid, ppvObject); + return hRes; + } + CComContainedObject m_contained; +}; + + +class CComClassFactory : + public IClassFactory, + public CComObjectRootEx +{ +public: + BEGIN_COM_MAP(CComClassFactory) + COM_INTERFACE_ENTRY(IClassFactory) + END_COM_MAP() + + // This will be made virtual again for Beta 2 + /*virtual*/ ~CComClassFactory() + { + } + + // IClassFactory + STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj) + { + ATLASSUME(m_pfnCreateInstance != NULL); + HRESULT hRes = E_POINTER; + if (ppvObj != NULL) + { + *ppvObj = NULL; + // can't ask for anything other than IUnknown when aggregating + + if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) + { + ATLTRACE(atlTraceCOM, 0, _T("CComClassFactory: asked for non IUnknown interface while creating an aggregated object")); + hRes = CLASS_E_NOAGGREGATION; + } + else + hRes = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); + } + return hRes; + } + + STDMETHOD(LockServer)(BOOL fLock) + { + if (fLock) + _pAtlModule->Lock(); + else + _pAtlModule->Unlock(); + return S_OK; + } + // helper + void SetVoid(void* pv) + { + m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv; + } + _ATL_CREATORFUNC* m_pfnCreateInstance; +}; + +template +class CComClassFactory2 : + public IClassFactory2, + public CComObjectRootEx, + public license +{ +public: + typedef license _LicenseClass; + typedef CComClassFactory2 _ComMapClass; +BEGIN_COM_MAP(CComClassFactory2) + COM_INTERFACE_ENTRY(IClassFactory) + COM_INTERFACE_ENTRY(IClassFactory2) +END_COM_MAP() + // IClassFactory + STDMETHOD(LockServer)(BOOL fLock) + { + if (fLock) + _pAtlModule->Lock(); + else + _pAtlModule->Unlock(); + return S_OK; + } + STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, + REFIID riid, void** ppvObj) + { + ATLASSUME(m_pfnCreateInstance != NULL); + if (ppvObj == NULL) + return E_POINTER; + *ppvObj = NULL; + if (!IsLicenseValid()) + return CLASS_E_NOTLICENSED; + + if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) + return CLASS_E_NOAGGREGATION; + else + return m_pfnCreateInstance(pUnkOuter, riid, ppvObj); + } + // IClassFactory2 + STDMETHOD(CreateInstanceLic)(IUnknown* pUnkOuter, + IUnknown* /* pUnkReserved */, REFIID riid, BSTR bstrKey, + void** ppvObject) + { + ATLASSUME(m_pfnCreateInstance != NULL); + if (ppvObject == NULL) + return E_POINTER; + *ppvObject = NULL; + if ( ((bstrKey != NULL) && !VerifyLicenseKey(bstrKey)) || + ((bstrKey == NULL) && !IsLicenseValid()) ) + return CLASS_E_NOTLICENSED; + if ((pUnkOuter != NULL) && !InlineIsEqualUnknown(riid)) + return CLASS_E_NOAGGREGATION; + else + return m_pfnCreateInstance(pUnkOuter, riid, ppvObject); + } + STDMETHOD(RequestLicKey)(DWORD dwReserved, BSTR* pbstrKey) + { + if (pbstrKey == NULL) + return E_POINTER; + *pbstrKey = NULL; + + if (!IsLicenseValid()) + return CLASS_E_NOTLICENSED; + return GetLicenseKey(dwReserved,pbstrKey) ? S_OK : E_FAIL; + } + STDMETHOD(GetLicInfo)(LICINFO* pLicInfo) + { + if (pLicInfo == NULL) + return E_POINTER; + pLicInfo->cbLicInfo = sizeof(LICINFO); + pLicInfo->fLicVerified = IsLicenseValid(); + BSTR bstr = NULL; + pLicInfo->fRuntimeKeyAvail = GetLicenseKey(0,&bstr); + ::SysFreeString(bstr); + return S_OK; + } + void SetVoid(void* pv) + { + m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv; + } + _ATL_CREATORFUNC* m_pfnCreateInstance; +}; + +///////////////////////////////////////////////////////////////////////////////////////////// +// Thread Pooling class factory +class CComClassFactoryAutoThread : + public IClassFactory, + public CComObjectRootEx +{ +public: + BEGIN_COM_MAP(CComClassFactoryAutoThread) + COM_INTERFACE_ENTRY(IClassFactory) + END_COM_MAP() + + // This will be made virtual again for Beta 2 + /*virtual*/ ~CComClassFactoryAutoThread() + { + } + + // helper + void SetVoid(void* pv) + { + m_pfnCreateInstance = (_ATL_CREATORFUNC*)pv; + } + STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, + REFIID riid, void** ppvObj) + { + ATLASSUME(m_pfnCreateInstance != NULL); + HRESULT hRes = E_POINTER; + if (ppvObj != NULL) + { + *ppvObj = NULL; + // cannot aggregate across apartments + ATLASSERT(pUnkOuter == NULL); + if (pUnkOuter != NULL) + hRes = CLASS_E_NOAGGREGATION; + else + { + ATLASSERT(_pAtlAutoThreadModule && _T("Global instance of CAtlAutoThreadModule not declared")); + if (_pAtlAutoThreadModule == NULL) + return E_FAIL; + + hRes = _pAtlAutoThreadModule->CreateInstance(m_pfnCreateInstance, riid, ppvObj); + } + } + return hRes; + } + STDMETHODIMP LockServer(BOOL fLock) + { + if (fLock) + _pAtlModule->Lock(); + else + _pAtlModule->Unlock(); + return S_OK; + } + _ATL_CREATORFUNC* m_pfnCreateInstance; +}; + + +///////////////////////////////////////////////////////////////////////////////////////////// +// Singleton Class Factory +template +class CComClassFactorySingleton : public CComClassFactory +{ +public: + CComClassFactorySingleton() : m_hrCreate(S_OK) + { + } + // This will be made virtual again for Beta 2 + /*virtual*/ ~CComClassFactorySingleton() + { + } + // IClassFactory + STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj) + { + HRESULT hRes = E_POINTER; + if (ppvObj != NULL) + { + *ppvObj = NULL; + // aggregation is not supported in Singletons + if (pUnkOuter != NULL) + hRes = CLASS_E_NOAGGREGATION; + else + { + if (m_hrCreate == S_OK && m_spObj == NULL) + { + __try + { + Lock(); + // Did another thread get here first? + if (m_hrCreate == S_OK && m_spObj == NULL) + { + CComObjectCached *p; + m_hrCreate = CComObjectCached::CreateInstance(&p); + if (SUCCEEDED(m_hrCreate)) + { + m_hrCreate = p->QueryInterface(IID_IUnknown, (void**)&m_spObj); + if (FAILED(m_hrCreate)) + { + delete p; + } + } + } + } + __finally + { + Unlock(); + } + } + if (m_hrCreate == S_OK) + { + hRes = m_spObj->QueryInterface(riid, ppvObj); + } + else + { + hRes = m_hrCreate; + } + } + } + return hRes; + } + HRESULT m_hrCreate; + CComPtr m_spObj; +}; + + +template +class CComCoClass +{ +public: + DECLARE_CLASSFACTORY() + DECLARE_AGGREGATABLE(T) + typedef T _CoClass; + static const CLSID& WINAPI GetObjectCLSID() {return *pclsid;} + static LPCTSTR WINAPI GetObjectDescription() {return NULL;} + static HRESULT WINAPI Error(LPCOLESTR lpszDesc, + const IID& iid = GUID_NULL, HRESULT hRes = 0) + { + return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes); + } + static HRESULT WINAPI Error(LPCOLESTR lpszDesc, DWORD dwHelpID, + LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0) + { + return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID, lpszHelpFile, + iid, hRes); + } + static HRESULT WINAPI Error(UINT nID, const IID& iid = GUID_NULL, + HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance()) + { + return AtlReportError(GetObjectCLSID(), nID, iid, hRes, hInst); + } + static HRESULT WINAPI Error(UINT nID, DWORD dwHelpID, + LPCOLESTR lpszHelpFile, const IID& iid = GUID_NULL, + HRESULT hRes = 0, HINSTANCE hInst = _AtlBaseModule.GetResourceInstance()) + { + return AtlReportError(GetObjectCLSID(), nID, dwHelpID, lpszHelpFile, + iid, hRes, hInst); + } + static HRESULT WINAPI Error(LPCSTR lpszDesc, + const IID& iid = GUID_NULL, HRESULT hRes = 0) + { + return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes); + } + static HRESULT WINAPI Error(LPCSTR lpszDesc, DWORD dwHelpID, + LPCSTR lpszHelpFile, const IID& iid = GUID_NULL, HRESULT hRes = 0) + { + return AtlReportError(GetObjectCLSID(), lpszDesc, dwHelpID, + lpszHelpFile, iid, hRes); + } + template + static HRESULT CreateInstance(IUnknown* punkOuter, Q** pp) + { + return T::_CreatorClass::CreateInstance(punkOuter, __uuidof(Q), (void**) pp); + } + template + static HRESULT CreateInstance(Q** pp) + { + return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void**) pp); + } +}; + +// ATL doesn't support multiple LCID's at the same time +// Whatever LCID is queried for first is the one that is used. +class CComTypeInfoHolder +{ +// Should be 'protected' but can cause compiler to generate fat code. +public: + const GUID* m_pguid; + const GUID* m_plibid; + WORD m_wMajor; + WORD m_wMinor; + + ITypeInfo* m_pInfo; + long m_dwRef; + struct stringdispid + { + CComBSTR bstr; + int nLen; + DISPID id; + stringdispid() : nLen(0), id(DISPID_UNKNOWN){} + }; + stringdispid* m_pMap; + int m_nCount; + +public: + +#ifdef _ATL_DLL_IMPL + CComTypeInfoHolder(const GUID* pguid, const GUID* plibid, WORD wMajor, WORD wMinor) : + m_pguid(pguid), m_plibid(plibid), m_wMajor(wMajor), m_wMinor(wMinor), + m_pInfo(NULL), m_dwRef(0), m_pMap(NULL), m_nCount(0) + { + } + + ~CComTypeInfoHolder() + { + if (m_pInfo != NULL) + m_pInfo->Release(); + m_pInfo = NULL; + delete [] m_pMap; + m_pMap = NULL; + } +#endif + + HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo) + { + ATLASSERT(ppInfo != NULL); + if (ppInfo == NULL) + return E_POINTER; + + HRESULT hr = S_OK; + if (m_pInfo == NULL) + hr = GetTI(lcid); + *ppInfo = m_pInfo; + if (m_pInfo != NULL) + { + m_pInfo->AddRef(); + hr = S_OK; + } + return hr; + } + HRESULT GetTI(LCID lcid); + HRESULT EnsureTI(LCID lcid) + { + HRESULT hr = S_OK; + if (m_pInfo == NULL || m_pMap == NULL) + hr = GetTI(lcid); + return hr; + } + + // This function is called by the module on exit + // It is registered through _pAtlModule->AddTermFunc() + static void __stdcall Cleanup(DWORD_PTR dw); + + HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) + { + if (itinfo != 0) + { +#ifdef _DEBUG + OutputDebugStringA("CComTypeInfoHolder::GetTypeInfo returning DISP_E_BADINDEX because itinfo != 0\n"); +#endif + return DISP_E_BADINDEX; + } + + return GetTI(lcid, pptinfo); + } + HRESULT GetIDsOfNames(REFIID /* riid */, __deref_in LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgdispid) + { + HRESULT hRes = EnsureTI(lcid); + if (m_pInfo != NULL) + { + hRes = E_FAIL; + // Look in cache if + // cache is populated + // parameter names are not requested + if (m_pMap != NULL && cNames == 1) + { + int n = int( ocslen(rgszNames[0]) ); + for (int j=m_nCount-1; j>=0; j--) + { + if ((n == m_pMap[j].nLen) && + (memcmp(m_pMap[j].bstr, rgszNames[0], m_pMap[j].nLen * sizeof(OLECHAR)) == 0)) + { + rgdispid[0] = m_pMap[j].id; + hRes = S_OK; + break; + } + } + } + // if cache is empty or name not in cache or parameter names are requested, + // delegate to ITypeInfo::GetIDsOfNames + if (FAILED(hRes)) + { + hRes = m_pInfo->GetIDsOfNames(rgszNames, cNames, rgdispid); + } + } + return hRes; + } + + HRESULT Invoke(IDispatch* p, DISPID dispidMember, REFIID /* riid */, + LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, + EXCEPINFO* pexcepinfo, UINT* puArgErr) + { + HRESULT hRes = EnsureTI(lcid); + if (m_pInfo != NULL) + hRes = m_pInfo->Invoke(p, dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); + return hRes; + } + __checkReturn HRESULT LoadNameCache(ITypeInfo* pTypeInfo) + { + TYPEATTR* pta; + HRESULT hr = pTypeInfo->GetTypeAttr(&pta); + if (SUCCEEDED(hr)) + { + stringdispid* pMap = NULL; + m_nCount = pta->cFuncs; + m_pMap = NULL; + if (m_nCount != 0) + { + ATLTRY(pMap = new stringdispid[m_nCount]); + if (pMap == NULL) + { + pTypeInfo->ReleaseTypeAttr(pta); + return E_OUTOFMEMORY; + } + } + for (int i=0; iGetFuncDesc(i, &pfd))) + { + CComBSTR bstrName; + if (SUCCEEDED(pTypeInfo->GetDocumentation(pfd->memid, &bstrName, NULL, NULL, NULL))) + { + pMap[i].bstr.Attach(bstrName.Detach()); + pMap[i].nLen = SysStringLen(pMap[i].bstr); + pMap[i].id = pfd->memid; + } + pTypeInfo->ReleaseFuncDesc(pfd); + } + } + m_pMap = pMap; + pTypeInfo->ReleaseTypeAttr(pta); + } + return S_OK; + } +}; + + inline void __stdcall CComTypeInfoHolder::Cleanup(DWORD_PTR dw) + { + ATLASSERT(dw != 0); + if (dw == 0) + return; + + CComTypeInfoHolder* p = (CComTypeInfoHolder*) dw; + if (p->m_pInfo != NULL) + p->m_pInfo->Release(); + p->m_pInfo = NULL; + delete [] p->m_pMap; + p->m_pMap = NULL; + } + +inline HRESULT CComTypeInfoHolder::GetTI(LCID lcid) +{ + //If this assert occurs then most likely didn't initialize properly + ATLASSUME(m_plibid != NULL && m_pguid != NULL); + ATLASSUME(!InlineIsEqualGUID(*m_plibid, GUID_NULL) && "Did you forget to pass the LIBID to CComModule::Init?"); + + if (m_pInfo != NULL && m_pMap != NULL) + return S_OK; + + CComCritSecLock lock(_pAtlModule->m_csStaticDataInitAndTypeInfo, false); + HRESULT hRes = lock.Lock(); + if (FAILED(hRes)) + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to lock critical section in CComTypeInfoHolder::GetTI\n")); + ATLASSERT(0); + return hRes; + } + hRes = E_FAIL; + if (m_pInfo == NULL) + { + ITypeLib* pTypeLib = NULL; + if (InlineIsEqualGUID(CAtlModule::m_libid, *m_plibid) && m_wMajor == 0xFFFF && m_wMinor == 0xFFFF) + { + TCHAR szFilePath[MAX_PATH]; + DWORD dwFLen = ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szFilePath, MAX_PATH); + if( dwFLen != 0 && dwFLen != MAX_PATH ) + { + USES_CONVERSION_EX; + LPOLESTR pszFile = T2OLE_EX(szFilePath, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if (pszFile == NULL) + return E_OUTOFMEMORY; +#endif + hRes = LoadTypeLib(pszFile, &pTypeLib); + } + } + else + { + hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib); +#ifdef _DEBUG + if (SUCCEEDED(hRes)) + { + // Trace out an warning if the requested TypelibID is the same as the modules TypelibID + // and versions do not match. + // + // In most cases it is due to wrong version template parameters to IDispatchImpl, + // IProvideClassInfoImpl or IProvideClassInfo2Impl. + // Set major and minor versions to 0xFFFF if the modules type lib has to be loaded + // irrespective of its version. + // + // Get the module's file path + TCHAR szFilePath[MAX_PATH]; + DWORD dwFLen = ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szFilePath, MAX_PATH); + if( dwFLen != 0 && dwFLen != MAX_PATH ) + { + USES_CONVERSION_EX; + CComPtr spTypeLibModule; + HRESULT hRes2 = S_OK; + LPOLESTR pszFile = T2OLE_EX(szFilePath, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); + if (pszFile == NULL) + hRes2 = E_OUTOFMEMORY; + else + hRes2 = LoadTypeLib(pszFile, &spTypeLibModule); + if (SUCCEEDED(hRes2)) + { + TLIBATTR* pLibAttr; + hRes2 = spTypeLibModule->GetLibAttr(&pLibAttr); + if (SUCCEEDED(hRes2)) + { + if (InlineIsEqualGUID(pLibAttr->guid, *m_plibid) && + (pLibAttr->wMajorVerNum != m_wMajor || + pLibAttr->wMinorVerNum != m_wMinor)) + { + ATLTRACE(atlTraceCOM, 0, _T("Warning : CComTypeInfoHolder::GetTI : Loaded typelib does not match the typelib in the module : %s\n"), szFilePath); + ATLTRACE(atlTraceCOM, 0, _T("\tSee IDispatchImpl overview help topic for more information\n"), szFilePath); + } + spTypeLibModule->ReleaseTLibAttr(pLibAttr); + } + } + } + } + else + { + ATLTRACE(atlTraceCOM, 0, _T("ERROR : Unable to load Typelibrary. (HRESULT = 0x%x)\n"), hRes); + ATLTRACE(atlTraceCOM, 0, _T("\tVerify TypelibID and major version specified with\n")); + ATLTRACE(atlTraceCOM, 0, _T("\tIDispatchImpl, CStockPropImpl, IProvideClassInfoImpl or IProvideCLassInfo2Impl\n")); + } +#endif + } + if (SUCCEEDED(hRes)) + { + CComPtr spTypeInfo; + hRes = pTypeLib->GetTypeInfoOfGuid(*m_pguid, &spTypeInfo); + if (SUCCEEDED(hRes)) + { + CComPtr spInfo(spTypeInfo); + CComPtr spTypeInfo2; + if (SUCCEEDED(spTypeInfo->QueryInterface(&spTypeInfo2))) + spInfo = spTypeInfo2; + + m_pInfo = spInfo.Detach(); +#ifndef _ATL_DLL_IMPL + _pAtlModule->AddTermFunc(Cleanup, (DWORD_PTR)this); +#endif + } + pTypeLib->Release(); + } + } + else + { + // Another thread has loaded the typeinfo so we're OK. + hRes = S_OK; + } + + if (m_pInfo != NULL && m_pMap == NULL) + { + hRes=LoadNameCache(m_pInfo); + } + + return hRes; +} + + +////////////////////////////////////////////////////////////////////////////// +// IObjectWithSite +// +template +class ATL_NO_VTABLE IObjectWithSiteImpl : public IObjectWithSite +{ +public: + virtual ~IObjectWithSiteImpl() + { + } + + STDMETHOD(SetSite)(IUnknown *pUnkSite) + { + ATLTRACE(atlTraceCOM, 2, _T("IObjectWithSiteImpl::SetSite\n")); + T* pT = static_cast(this); + pT->m_spUnkSite = pUnkSite; + return S_OK; + } + STDMETHOD(GetSite)(REFIID riid, void **ppvSite) + { + ATLTRACE(atlTraceCOM, 2, _T("IObjectWithSiteImpl::GetSite\n")); + T* pT = static_cast(this); + ATLASSERT(ppvSite); + HRESULT hRes = E_POINTER; + if (ppvSite != NULL) + { + if (pT->m_spUnkSite) + hRes = pT->m_spUnkSite->QueryInterface(riid, ppvSite); + else + { + *ppvSite = NULL; + hRes = E_FAIL; + } + } + return hRes; + } + + HRESULT SetChildSite(IUnknown* punkChild) + { + if (punkChild == NULL) + return E_POINTER; + + HRESULT hr; + CComPtr spChildSite; + hr = punkChild->QueryInterface(__uuidof(IObjectWithSite), (void**)&spChildSite); + if (SUCCEEDED(hr)) + hr = spChildSite->SetSite((IUnknown*)this); + + return hr; + } + + static HRESULT SetChildSite(IUnknown* punkChild, IUnknown* punkParent) + { + return AtlSetChildSite(punkChild, punkParent); + } + + CComPtr m_spUnkSite; +}; + +////////////////////////////////////////////////////////////////////////////// +// IServiceProvider +// +template +class ATL_NO_VTABLE IServiceProviderImpl : public IServiceProvider +{ +public: + STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void** ppvObject) + { + ATLTRACE(atlTraceCOM, 2, _T("IServiceProviderImpl::QueryService\n")); + + T* pT = static_cast(this); + return pT->_InternalQueryService(guidService, riid, ppvObject); + } +}; + +#define BEGIN_SERVICE_MAP(x) public: \ + HRESULT _InternalQueryService(REFGUID guidService, REFIID riid, void** ppvObject) \ + { \ + ATLASSERT(ppvObject != NULL); \ + if (ppvObject == NULL) \ + return E_POINTER; \ + *ppvObject = NULL; + +#define SERVICE_ENTRY(x) \ + if (InlineIsEqualGUID(guidService, x)) \ + return QueryInterface(riid, ppvObject); + +#define SERVICE_ENTRY_CHAIN(x) \ + ATL::CComQIPtr spProvider(x); \ + if (spProvider != NULL) \ + return spProvider->QueryService(guidService, riid, ppvObject); + +#define END_SERVICE_MAP() \ + return E_NOINTERFACE; \ + } + + +///////////////////////////////////////////////////////////////////////////// +// IDispEventImpl + +ATLAPI AtlGetObjectSourceInterface(IUnknown* punkObj, GUID* plibid, IID* piid, unsigned short* pdwMajor, unsigned short* pdwMinor); + +#ifdef _M_IA64 +template +class CComStdCallThunk +{ +public: + typedef void (__stdcall T::*TMFP)(); + void* pVtable; + void* pFunc; + _stdcallthunk thunk; + void Init(TMFP dw, void* pThis) + { + pVtable = &pFunc; + pFunc = &thunk; + union { + DWORD_PTR dwFunc; + TMFP pfn; + } pfn; + pfn.pfn = dw; + thunk.Init(pfn.dwFunc, pThis); + } +}; + +#elif defined ( _M_IX86 ) || defined ( _M_AMD64 ) + +extern "C" +{ +void __stdcall CComStdCallThunkHelper(); +} + +template +class CComStdCallThunk +{ +public: + typedef void (__stdcall T::*TMFP)(); + void *pVTable; // pointer to artificial VTABLE + void *pThis; // pointer to the class + TMFP pfn; // Pointer to member function to call + void (__stdcall *pfnHelper)(); // Artificial VTABLE entry. Points to CComStdCallThunkHelper + // which modifies the stack and jumps to pfn + + void Init(TMFP pf, void *p) + { + pfnHelper = CComStdCallThunkHelper; + pVTable = &pfnHelper; + pThis = p; + pfn = pf; + } +}; +#else +#error X86, AMD64 and IA64 +#endif // _M_IX86 | + +#ifndef _ATL_MAX_VARTYPES +#define _ATL_MAX_VARTYPES 8 +#endif + +struct _ATL_FUNC_INFO +{ + CALLCONV cc; + VARTYPE vtReturn; + SHORT nParams; + VARTYPE pVarTypes[_ATL_MAX_VARTYPES]; +}; + +class ATL_NO_VTABLE _IDispEvent +{ +public: + _IDispEvent() : m_libid(GUID_NULL), m_iid(IID_NULL), m_wMajorVerNum(0), m_wMinorVerNum(0), m_dwEventCookie(0xFEFEFEFE) { } + //this method needs a different name than QueryInterface + STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject) = 0; + virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; + virtual ULONG STDMETHODCALLTYPE Release(void) = 0; + GUID m_libid; // used for dynamic case + IID m_iid; // used for dynamic case + unsigned short m_wMajorVerNum; // Major version number. used for dynamic case + unsigned short m_wMinorVerNum; // Minor version number. used for dynamic case + DWORD m_dwEventCookie; + HRESULT DispEventAdvise(IUnknown* pUnk, const IID* piid) + { + ATLENSURE(m_dwEventCookie == 0xFEFEFEFE); + return AtlAdvise(pUnk, (IUnknown*)this, *piid, &m_dwEventCookie); + } + HRESULT DispEventUnadvise(IUnknown* pUnk, const IID* piid) + { + HRESULT hr = AtlUnadvise(pUnk, *piid, m_dwEventCookie); + m_dwEventCookie = 0xFEFEFEFE; + return hr; + } + //---- add Advise & Unadvise for ease of calling from attribute code ---- + HRESULT Advise(IUnknown *punk) + { + HRESULT hr = AtlGetObjectSourceInterface(punk, &m_libid, &m_iid, &m_wMajorVerNum, &m_wMinorVerNum); + if (FAILED(hr)) + return hr; + return DispEventAdvise(punk, &m_iid); + } + HRESULT Unadvise(IUnknown *punk) + { + HRESULT hr = AtlGetObjectSourceInterface(punk, &m_libid, &m_iid, &m_wMajorVerNum, &m_wMinorVerNum); + if (FAILED(hr)) + return hr; + return DispEventUnadvise(punk, &m_iid); + } +}; + +template +class ATL_NO_VTABLE _IDispEventLocator : public _IDispEvent +{ +public: +}; + +template +class ATL_NO_VTABLE IDispEventSimpleImpl : public _IDispEventLocator +{ +public: + STDMETHOD(_LocDEQueryInterface)(REFIID riid, void ** ppvObject) + { + ATLASSERT(ppvObject != NULL); + if (ppvObject == NULL) + return E_POINTER; + *ppvObject = NULL; + + if (InlineIsEqualGUID(riid, IID_NULL)) + return E_NOINTERFACE; + + if (InlineIsEqualGUID(riid, *pdiid) || + InlineIsEqualUnknown(riid) || + InlineIsEqualGUID(riid, __uuidof(IDispatch)) || + InlineIsEqualGUID(riid, m_iid)) + { + *ppvObject = this; + AddRef(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, _T("IDispEventImpl"), riid); +#endif // _ATL_DEBUG_INTERFACES + return S_OK; + } + else + return E_NOINTERFACE; + } + + // These are here only to support use in non-COM objects + virtual ULONG STDMETHODCALLTYPE AddRef() + { + return 1; + } + virtual ULONG STDMETHODCALLTYPE Release() + { + return 1; + } + + STDMETHOD(GetTypeInfoCount)(UINT* /*pctinfo*/) + {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfoCount"));} + + STDMETHOD(GetTypeInfo)(UINT /*itinfo*/, LCID /*lcid*/, ITypeInfo** /*pptinfo*/) + {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetTypeInfo"));} + + STDMETHOD(GetIDsOfNames)(REFIID /*riid*/, LPOLESTR* /*rgszNames*/, UINT /*cNames*/, + LCID /*lcid*/, DISPID* /*rgdispid*/) + {ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetIDsOfNames"));} + + STDMETHOD(Invoke)(DISPID dispidMember, REFIID /*riid*/, + LCID lcid, WORD /*wFlags*/, DISPPARAMS* pdispparams, VARIANT* pvarResult, + EXCEPINFO* /*pexcepinfo*/, UINT* /*puArgErr*/) + { + const _ATL_EVENT_ENTRY* pMap = T::_GetSinkMap(); + const _ATL_EVENT_ENTRY* pFound = NULL; + while (pMap->piid != NULL) + { + if ((pMap->nControlID == nID) && (pMap->dispid == dispidMember) && + (IsEqualIID(*(pMap->piid), *pdiid))) + { + pFound = pMap; + break; + } + pMap++; + } + if (pFound == NULL) + return S_OK; + + + _ATL_FUNC_INFO info; + _ATL_FUNC_INFO* pInfo; + if (pFound->pInfo != NULL) + pInfo = pFound->pInfo; + else + { + pInfo = &info; + HRESULT hr = GetFuncInfoFromId(*pdiid, dispidMember, lcid, info); + if (FAILED(hr)) + return S_OK; + } + return InvokeFromFuncInfo(pFound->pfn, *pInfo, pdispparams, pvarResult); + } + + //Helper for invoking the event + HRESULT InvokeFromFuncInfo(void (__stdcall T::*pEvent)(), _ATL_FUNC_INFO& info, DISPPARAMS* pdispparams, VARIANT* pvarResult) + { + ATLASSERT(pdispparams->cArgs == (UINT)info.nParams); + if (pdispparams->cArgs != (UINT)info.nParams) + { + return E_FAIL; + } + + T* pT = static_cast(this); + + // If this assert occurs, then add + // #define _ATL_MAX_VARTYPES nnnn + // before including atlcom.h + ATLASSERT(info.nParams <= _ATL_MAX_VARTYPES); + if (info.nParams > _ATL_MAX_VARTYPES) + { + return E_FAIL; + } + VARIANTARG* rgVarArgs[_ATL_MAX_VARTYPES]; + VARIANTARG** pVarArgs = info.nParams ? rgVarArgs : 0; + + UINT nIndex = 0; + +#ifndef _ATL_IGNORE_NAMED_ARGS + ATLASSERT(pdispparams->cNamedArgs <= (UINT)info.nParams); + if (pdispparams->cNamedArgs > (UINT)info.nParams) + { + return E_FAIL; + } + // Pre-initialize so we can detect repeated or omitted arguments. + for (nIndex; nIndex < pdispparams->cNamedArgs; nIndex++) + { + pVarArgs[nIndex] = NULL; + } + for (nIndex = 0; nIndex < pdispparams->cNamedArgs; nIndex++) + { + UINT nArgIndex = (UINT)pdispparams->rgdispidNamedArgs[nIndex]; + ATLASSERT(nArgIndex < pdispparams->cNamedArgs); + if ((nArgIndex >= pdispparams->cNamedArgs) || + (nArgIndex >= _countof(rgVarArgs))) + { + return E_FAIL; + } + ATLASSERT(pVarArgs[nArgIndex] == NULL); + if (pVarArgs[nArgIndex] != NULL) + { + return E_FAIL; + } + pVarArgs[nArgIndex] = &pdispparams->rgvarg[nIndex]; + } +#endif + + for (; nIndex < pdispparams->cArgs; nIndex++) + pVarArgs[info.nParams-nIndex-1] = &pdispparams->rgvarg[nIndex]; + + CComStdCallThunk 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; + } + + //Helper for finding the function index for a DISPID + virtual HRESULT GetFuncInfoFromId(const IID& /*iid*/, DISPID /*dispidMember*/, LCID /*lcid*/, _ATL_FUNC_INFO& /*info*/) + { + ATLTRACE(_T("TODO: Classes using IDispEventSimpleImpl should override this method\n")); + ATLASSERT(0); + ATLTRACENOTIMPL(_T("IDispEventSimpleImpl::GetFuncInfoFromId")); + } + //Helpers for sinking events on random IUnknown* + HRESULT DispEventAdvise(IUnknown* pUnk, const IID* piid) + { + ATLENSURE(m_dwEventCookie == 0xFEFEFEFE); + return AtlAdvise(pUnk, (IUnknown*)this, *piid, &m_dwEventCookie); + } + HRESULT DispEventUnadvise(IUnknown* pUnk, const IID* piid) + { + HRESULT hr = AtlUnadvise(pUnk, *piid, m_dwEventCookie); + m_dwEventCookie = 0xFEFEFEFE; + return hr; + } + HRESULT DispEventAdvise(IUnknown* pUnk) + { + return _IDispEvent::DispEventAdvise(pUnk, pdiid); + } + HRESULT DispEventUnadvise(IUnknown* pUnk) + { + return _IDispEvent::DispEventUnadvise(pUnk, pdiid); + } +}; + +//Helper for advising connections points from a sink map +template +inline HRESULT AtlAdviseSinkMap(T* pT, bool bAdvise) +{ + ATLASSERT(::IsWindow(pT->m_hWnd)); + const _ATL_EVENT_ENTRY* pEntries = T::_GetSinkMap(); + if (pEntries == NULL) + return S_OK; + HRESULT hr = S_OK; + while (pEntries->piid != NULL) + { + _IDispEvent* pDE = (_IDispEvent*)((DWORD_PTR)pT+pEntries->nOffset); + bool bNotAdvised = pDE->m_dwEventCookie == 0xFEFEFEFE; + if (bAdvise ^ bNotAdvised) + { + pEntries++; + continue; + } + hr = E_FAIL; + HWND h = pT->GetDlgItem(pEntries->nControlID); + ATLASSERT(h != NULL); + if (h != NULL) + { + CComPtr spUnk; + AtlAxGetControl(h, &spUnk); + ATLASSERT(spUnk != NULL); + if (spUnk != NULL) + { + if (bAdvise) + { + if (!InlineIsEqualGUID(IID_NULL, *pEntries->piid)) + hr = pDE->DispEventAdvise(spUnk, pEntries->piid); + else + { + hr = AtlGetObjectSourceInterface(spUnk, &pDE->m_libid, &pDE->m_iid, &pDE->m_wMajorVerNum, &pDE->m_wMinorVerNum); + if (FAILED(hr)) + return hr; + hr = pDE->DispEventAdvise(spUnk, &pDE->m_iid); + } + } + else + { + if (!InlineIsEqualGUID(IID_NULL, *pEntries->piid)) + hr = pDE->DispEventUnadvise(spUnk, pEntries->piid); + else + hr = pDE->DispEventUnadvise(spUnk, &pDE->m_iid); + } + ATLASSERT(hr == S_OK); + } + } + if (FAILED(hr)) + break; + pEntries++; + } + return hr; +} + +#pragma warning(push) +#pragma warning(disable: 4061) // enumerate XXX not explicitly handled by a case label +inline VARTYPE AtlGetUserDefinedType(ITypeInfo *pTI, HREFTYPE hrt) +{ + ATLENSURE_THROW(pTI != NULL, E_INVALIDARG); + + CComPtr spTypeInfo; + VARTYPE vt = VT_USERDEFINED; + HRESULT hr = E_FAIL; + hr = pTI->GetRefTypeInfo(hrt, &spTypeInfo); + if(FAILED(hr)) + return vt; + TYPEATTR *pta = NULL; + + hr = spTypeInfo->GetTypeAttr(&pta); + if(SUCCEEDED(hr) && pta && (pta->typekind == TKIND_ALIAS || pta->typekind == TKIND_ENUM)) + { + if (pta->tdescAlias.vt == VT_USERDEFINED) + vt = AtlGetUserDefinedType(spTypeInfo, pta->tdescAlias.hreftype); + else + { + switch (pta->typekind) + { + case TKIND_ENUM : + vt = VT_I4; + break; + case TKIND_INTERFACE : + vt = VT_UNKNOWN; + break; + case TKIND_DISPATCH : + vt = VT_DISPATCH; + break; + default: + vt = pta->tdescAlias.vt; + } + } + } + + if(pta) + spTypeInfo->ReleaseTypeAttr(pta); + return vt; + +} +#pragma warning(pop) + +inline HRESULT AtlGetFuncInfoFromId(ITypeInfo* pTypeInfo, const IID& /*iid*/, DISPID dispidMember, LCID /*lcid*/, _ATL_FUNC_INFO& info) +{ + if (pTypeInfo == NULL) + return E_INVALIDARG; + + HRESULT hr = S_OK; + FUNCDESC* pFuncDesc = NULL; + TYPEATTR* pAttr; + hr = pTypeInfo->GetTypeAttr(&pAttr); + if (FAILED(hr)) + return hr; + int i; + for (i=0;icFuncs;i++) + { + hr = pTypeInfo->GetFuncDesc(i, &pFuncDesc); + if (FAILED(hr)) + return hr; + if (pFuncDesc->memid == dispidMember) + break; + pTypeInfo->ReleaseFuncDesc(pFuncDesc); + pFuncDesc = NULL; + } + pTypeInfo->ReleaseTypeAttr(pAttr); + if (pFuncDesc == NULL) + return E_FAIL; + + // If this assert occurs, then add a #define _ATL_MAX_VARTYPES nnnn + // before including atlcom.h + ATLASSERT(pFuncDesc->cParams <= _ATL_MAX_VARTYPES); + if (pFuncDesc->cParams > _ATL_MAX_VARTYPES) + return E_FAIL; + + for (i = 0; i < pFuncDesc->cParams; i++) + { + info.pVarTypes[i] = pFuncDesc->lprgelemdescParam[i].tdesc.vt; + if (info.pVarTypes[i] == VT_PTR) + info.pVarTypes[i] = (VARTYPE)(pFuncDesc->lprgelemdescParam[i].tdesc.lptdesc->vt | VT_BYREF); + if (info.pVarTypes[i] == VT_USERDEFINED) + info.pVarTypes[i] = AtlGetUserDefinedType(pTypeInfo, pFuncDesc->lprgelemdescParam[i].tdesc.hreftype); + } + + VARTYPE vtReturn = pFuncDesc->elemdescFunc.tdesc.vt; + switch(vtReturn) + { + case VT_INT: + vtReturn = VT_I4; + break; + case VT_UINT: + vtReturn = VT_UI4; + break; + case VT_VOID: + vtReturn = VT_EMPTY; // this is how DispCallFunc() represents void + break; + case VT_HRESULT: + vtReturn = VT_ERROR; + break; + } + info.vtReturn = vtReturn; + info.cc = pFuncDesc->callconv; + info.nParams = pFuncDesc->cParams; + pTypeInfo->ReleaseFuncDesc(pFuncDesc); + return S_OK; +} + +template +class ATL_NO_VTABLE IDispEventImpl : public IDispEventSimpleImpl +{ +public: + typedef tihclass _tihclass; + + IDispEventImpl() + { + m_libid = *plibid; + m_iid = *pdiid; + m_wMajorVerNum = wMajor; + m_wMinorVerNum = wMinor; + } + + STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) + { + if (pctinfo == NULL) + return E_POINTER; + *pctinfo = 1; + return S_OK; + } + + STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) + {return _tih.GetTypeInfo(itinfo, lcid, pptinfo);} + + STDMETHOD(GetIDsOfNames)(REFIID riid, __deref_in LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgdispid) + {return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);} + + //Helper for finding the function index for a DISPID + HRESULT GetFuncInfoFromId(const IID& iid, DISPID dispidMember, LCID lcid, _ATL_FUNC_INFO& info) + { + CComPtr spTypeInfo; + + if (InlineIsEqualGUID(*_tih.m_plibid, GUID_NULL)) + { + m_InnerLibid = m_libid; + m_InnerIid = m_iid; + _tih.m_plibid = &m_InnerLibid; + _tih.m_pguid = &m_InnerIid; + _tih.m_wMajor = m_wMajorVerNum; + _tih.m_wMinor = m_wMinorVerNum; + + } + HRESULT hr = _tih.GetTI(lcid, &spTypeInfo); + if (FAILED(hr)) + return hr; + return AtlGetFuncInfoFromId(spTypeInfo, iid, dispidMember, lcid, info); + } + VARTYPE GetUserDefinedType(ITypeInfo *pTI, HREFTYPE hrt) + { + return AtlGetUserDefinedType(pTI, hrt); + } +protected: + static _tihclass _tih; + static GUID m_InnerLibid; // used for dynamic case + static IID m_InnerIid; // used for dynamic case + static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo) + {return _tih.GetTI(lcid, ppInfo);} +}; + +template +typename IDispEventImpl::_tihclass +IDispEventImpl::_tih = + {piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0}; + +template +GUID IDispEventImpl::m_InnerLibid=GUID_NULL; + +template +IID IDispEventImpl::m_InnerIid=IID_NULL; + +template +struct _ATL_EVENT_ENTRY +{ + UINT nControlID; //ID identifying object instance + const IID* piid; //dispinterface IID + int nOffset; //offset of dispinterface from this pointer + DISPID dispid; //DISPID of method/property + void (__stdcall T::*pfn)(); //method to invoke + _ATL_FUNC_INFO* pInfo; +}; + + + +//Sink map is used to set up event handling +#define BEGIN_SINK_MAP(_class)\ + typedef _class _GetSinkMapFinder;\ + static const ATL::_ATL_EVENT_ENTRY<_class>* _GetSinkMap()\ + {\ + PTM_WARNING_DISABLE \ + typedef _class _atl_event_classtype;\ + static const ATL::_ATL_EVENT_ENTRY<_class> map[] = { + + + + +#define SINK_ENTRY_INFO(id, iid, dispid, fn, info) {id, &iid, (int)(INT_PTR)(static_cast*>((_atl_event_classtype*)8))-8, dispid, (void (__stdcall _atl_event_classtype::*)())fn, info}, +#define SINK_ENTRY_EX(id, iid, dispid, fn) SINK_ENTRY_INFO(id, iid, dispid, fn, NULL) +#define SINK_ENTRY(id, dispid, fn) SINK_ENTRY_EX(id, IID_NULL, dispid, fn) +#define END_SINK_MAP() \ + {0, NULL, 0, 0, NULL, NULL} }; return map;\ + PTM_WARNING_RESTORE \ + } + +///////////////////////////////////////////////////////////////////////////// +// IDispatchImpl + +template +class ATL_NO_VTABLE IDispatchImpl : public T +{ +public: + typedef tihclass _tihclass; +// IDispatch + STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) + { + if (pctinfo == NULL) + return E_POINTER; + *pctinfo = 1; + return S_OK; + } + STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) + { + return _tih.GetTypeInfo(itinfo, lcid, pptinfo); + } + STDMETHOD(GetIDsOfNames)(REFIID riid, __deref_in LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgdispid) + { + return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid); + } + STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, + EXCEPINFO* pexcepinfo, UINT* puArgErr) + { + return _tih.Invoke((IDispatch*)this, dispidMember, riid, lcid, + wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr); + } + +#ifdef _ATL_DLL_IMPL + // Do not cache type info if it is used in atl71.dll + IDispatchImpl() : _tih(piid, plibid, wMajor, wMinor) + { + } + virtual ~IDispatchImpl() + { + } + +protected: + _tihclass _tih; + HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo) + { + return _tih.GetTI(lcid, ppInfo); + } + +#else + +protected: + static _tihclass _tih; + static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo) + { + return _tih.GetTI(lcid, ppInfo); + } + +#endif + +}; + +#ifndef _ATL_DLL_IMPL + +template +typename IDispatchImpl::_tihclass +IDispatchImpl::_tih = +{piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0}; + +#endif + +///////////////////////////////////////////////////////////////////////////// +// IProvideClassInfoImpl +template +class ATL_NO_VTABLE IProvideClassInfoImpl : public IProvideClassInfo +{ +public: + typedef tihclass _tihclass; + + STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo) + { + return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo); + } + +protected: + static _tihclass _tih; +}; + +template +typename IProvideClassInfoImpl::_tihclass +IProvideClassInfoImpl::_tih = +{pcoclsid,plibid, wMajor, wMinor, NULL, 0, NULL, 0}; + +///////////////////////////////////////////////////////////////////////////// +// IProvideClassInfo2Impl +template +class ATL_NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2 +{ +public: + typedef tihclass _tihclass; + + STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo) + { + return _tih.GetTypeInfo(0, LANG_NEUTRAL, pptinfo); + } + STDMETHOD(GetGUID)(DWORD dwGuidKind, GUID* pGUID) + { + if (pGUID == NULL) + return E_POINTER; + + if (dwGuidKind == GUIDKIND_DEFAULT_SOURCE_DISP_IID && psrcid != NULL) + { + *pGUID = *psrcid; + return S_OK; + } + *pGUID = GUID_NULL; + return E_FAIL; + } + +protected: + static _tihclass _tih; +}; + + +template +typename IProvideClassInfo2Impl::_tihclass +IProvideClassInfo2Impl::_tih = +{pcoclsid,plibid, wMajor, wMinor, NULL, 0, NULL, 0}; + + +///////////////////////////////////////////////////////////////////////////// +// ISupportErrorInfoImpl + +template +class ATL_NO_VTABLE ISupportErrorInfoImpl : public ISupportErrorInfo +{ +public: + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) + { + return (InlineIsEqualGUID(riid,*piid)) ? S_OK : S_FALSE; + } +}; + + +///////////////////////////////////////////////////////////////////////////// +// CComEnumImpl + +// These _CopyXXX classes are used with enumerators in order to control +// how enumerated items are initialized, copied, and deleted + +// Default is shallow copy with no special init or cleanup +template +class _Copy +{ +public: + static HRESULT copy(T* p1, const T* p2) { Checked::memcpy_s(p1, sizeof(T), p2, sizeof(T)); return S_OK;} + static void init(T*) {} + static void destroy(T*) {} +}; + +template<> +class _Copy +{ +public: + static HRESULT copy(VARIANT* p1, const VARIANT* p2) {p1->vt = VT_EMPTY; return VariantCopy(p1, const_cast(p2));} + static void init(VARIANT* p) {p->vt = VT_EMPTY;} + static void destroy(VARIANT* p) {VariantClear(p);} +}; + +template<> +class _Copy +{ +public: + static HRESULT copy(LPOLESTR* p1, const LPOLESTR* p2) + { + ATLENSURE(p1 != NULL && p2 != NULL); + HRESULT hr = S_OK; + ULONG len = ocslen(*p2)+1; + (*p1) = (LPOLESTR)::ATL::AtlCoTaskMemCAlloc(len, static_cast(sizeof(OLECHAR))); + if (*p1 == NULL) + { + hr = E_OUTOFMEMORY; + } + else + { + if(!ocscpy_s(*p1, len, *p2)) + { + hr = E_FAIL; + } + } + return hr; + } + static void init(LPOLESTR* p) {*p = NULL;} + static void destroy(LPOLESTR* p) { CoTaskMemFree(*p);} +}; + +template<> +class _Copy +{ +public: + static HRESULT copy(OLEVERB* p1, const OLEVERB* p2) + { + ATLENSURE(p1 != NULL && p2 != NULL); + HRESULT hr = S_OK; + *p1 = *p2; + if (p2->lpszVerbName == NULL) + { + return S_OK; + } + + ULONG len = ocslen(p2->lpszVerbName)+1; + p1->lpszVerbName = (LPOLESTR)::ATL::AtlCoTaskMemCAlloc(len, static_cast(sizeof(OLECHAR))); + if (p1->lpszVerbName == NULL) + { + hr = E_OUTOFMEMORY; + } + else + { + if(!ocscpy_s(p1->lpszVerbName, len, p2->lpszVerbName)) + { + hr = E_FAIL; + } + } + return hr; + } + static void init(OLEVERB* p) { p->lpszVerbName = NULL;} + static void destroy(OLEVERB* p) { if (p->lpszVerbName) CoTaskMemFree(p->lpszVerbName);} +}; + +template<> +class _Copy +{ +public: + static HRESULT copy(CONNECTDATA* p1, const CONNECTDATA* p2) + { + ATLENSURE(p1 != NULL && p2 != NULL); + *p1 = *p2; + if (p1->pUnk) + p1->pUnk->AddRef(); + return S_OK; + } + static void init(CONNECTDATA* ) {} + static void destroy(CONNECTDATA* p) {if (p->pUnk) p->pUnk->Release();} +}; + +template +class _CopyInterface +{ +public: + static HRESULT copy(T** p1, T** p2) + { + ATLENSURE(p1 != NULL && p2 != NULL); + *p1 = *p2; + if (*p1) + (*p1)->AddRef(); + return S_OK; + } + static void init(T** ) {} + static void destroy(T** p) {if (*p) (*p)->Release();} +}; + +template +class ATL_NO_VTABLE CComIEnum : public IUnknown +{ +public: + STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched) = 0; + STDMETHOD(Skip)(ULONG celt) = 0; + STDMETHOD(Reset)(void) = 0; + STDMETHOD(Clone)(CComIEnum** ppEnum) = 0; +}; + + +enum CComEnumFlags +{ + //see FlagBits in CComEnumImpl + AtlFlagNoCopy = 0, + AtlFlagTakeOwnership = 2, + AtlFlagCopy = 3 // copy implies ownership +}; + +template +class ATL_NO_VTABLE CComEnumImpl : public Base +{ +public: + CComEnumImpl() {m_begin = m_end = m_iter = NULL; m_dwFlags = 0;} + virtual ~CComEnumImpl(); + STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched); + STDMETHOD(Skip)(ULONG celt); + STDMETHOD(Reset)(void){m_iter = m_begin;return S_OK;} + STDMETHOD(Clone)(Base** ppEnum); + HRESULT Init(T* begin, T* end, IUnknown* pUnk, + CComEnumFlags flags = AtlFlagNoCopy); + CComPtr m_spUnk; + T* m_begin; + T* m_end; + T* m_iter; + DWORD m_dwFlags; +protected: + enum FlagBits + { + BitCopy=1, + BitOwn=2 + }; +}; + +template +CComEnumImpl::~CComEnumImpl() +{ + if (m_dwFlags & BitOwn) + { + for (T* p = m_begin; p != m_end; p++) + Copy::destroy(p); + delete [] m_begin; + } +} + +template +STDMETHODIMP CComEnumImpl::Next(ULONG celt, T* rgelt, + ULONG* pceltFetched) +{ + if (pceltFetched != NULL) + *pceltFetched = 0; + if (celt == 0) + return E_INVALIDARG; + if (rgelt == NULL || (celt != 1 && pceltFetched == NULL)) + return E_POINTER; + if (m_begin == NULL || m_end == NULL || m_iter == NULL) + return E_FAIL; + ULONG nRem = (ULONG)(m_end - m_iter); + HRESULT hRes = S_OK; + if (nRem < celt) + hRes = S_FALSE; + ULONG nMin = celt < nRem ? celt : nRem ; + if (pceltFetched != NULL) + *pceltFetched = nMin; + T* pelt = rgelt; + while(nMin--) + { + HRESULT hr = Copy::copy(pelt, m_iter); + if (FAILED(hr)) + { + while (rgelt < pelt) + Copy::destroy(rgelt++); + if (pceltFetched != NULL) + *pceltFetched = 0; + return hr; + } + pelt++; + m_iter++; + } + return hRes; +} + +template +STDMETHODIMP CComEnumImpl::Skip(ULONG celt) +{ + if (celt == 0) + return E_INVALIDARG; + + ULONG nRem = ULONG(m_end - m_iter); + ULONG nSkip = (celt > nRem) ? nRem : celt; + m_iter += nSkip; + return (celt == nSkip) ? S_OK : S_FALSE; +} + +template +STDMETHODIMP CComEnumImpl::Clone(Base** ppEnum) +{ + typedef CComObject > _class; + HRESULT hRes = E_POINTER; + if (ppEnum != NULL) + { + *ppEnum = NULL; + _class* p; + hRes = _class::CreateInstance(&p); + if (SUCCEEDED(hRes)) + { + // If this object has ownership of the data then we need to keep it around + hRes = p->Init(m_begin, m_end, (m_dwFlags & BitOwn) ? this : m_spUnk); + if (SUCCEEDED(hRes)) + { + p->m_iter = m_iter; + hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum); + } + if (FAILED(hRes)) + delete p; + } + } + return hRes; +} + +template +HRESULT CComEnumImpl::Init(T* begin, T* end, IUnknown* pUnk, + CComEnumFlags flags) +{ + if (flags == AtlFlagCopy) + { + ATLASSUME(m_begin == NULL); //Init called twice? + ATLTRY(m_begin = new T[end-begin]) + m_iter = m_begin; + if (m_begin == NULL) + return E_OUTOFMEMORY; + for (T* i=begin; i != end; i++) + { + Copy::init(m_iter); + HRESULT hr = Copy::copy(m_iter, i); + if (FAILED(hr)) + { + T* p = m_begin; + while (p < m_iter) + Copy::destroy(p++); + delete [] m_begin; + m_begin = m_end = m_iter = NULL; + return hr; + } + m_iter++; + } + m_end = m_begin + (end-begin); + } + else + { + m_begin = begin; + m_end = end; + } + m_spUnk = pUnk; + m_iter = m_begin; + m_dwFlags = flags; + return S_OK; +} + +template +class ATL_NO_VTABLE CComEnum : + public CComEnumImpl, + public CComObjectRootEx< ThreadModel > +{ +public: + typedef CComEnum _CComEnum; + typedef CComEnumImpl _CComEnumBase; + BEGIN_COM_MAP(_CComEnum) + COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase) + END_COM_MAP() +}; + +template +class ATL_NO_VTABLE IEnumOnSTLImpl : public Base +{ +public: + HRESULT Init(IUnknown *pUnkForRelease, CollType& collection) + { + m_spUnk = pUnkForRelease; + m_pcollection = &collection; + m_iter = m_pcollection->begin(); + return S_OK; + } + STDMETHOD(Next)(ULONG celt, T* rgelt, ULONG* pceltFetched); + STDMETHOD(Skip)(ULONG celt); + STDMETHOD(Reset)(void) + { + if (m_pcollection == NULL) + return E_FAIL; + m_iter = m_pcollection->begin(); + return S_OK; + } + STDMETHOD(Clone)(Base** ppEnum); +//Data + CComPtr m_spUnk; + CollType* m_pcollection; + typename CollType::const_iterator m_iter; +}; + +template +STDMETHODIMP IEnumOnSTLImpl::Next(ULONG celt, T* rgelt, + ULONG* pceltFetched) +{ + if (rgelt == NULL || (celt != 1 && pceltFetched == NULL)) + return E_POINTER; + if (pceltFetched != NULL) + *pceltFetched = 0; + if (m_pcollection == NULL) + return E_FAIL; + + ULONG nActual = 0; + HRESULT hr = S_OK; + T* pelt = rgelt; + while (SUCCEEDED(hr) && m_iter != m_pcollection->end() && nActual < celt) + { + hr = Copy::copy(pelt, &*m_iter); + if (FAILED(hr)) + { + while (rgelt < pelt) + Copy::destroy(rgelt++); + nActual = 0; + } + else + { + pelt++; + m_iter++; + nActual++; + } + } + if (SUCCEEDED(hr)) + { + if (pceltFetched) + *pceltFetched = nActual; + if (nActual < celt) + hr = S_FALSE; + } + return hr; +} + +template +STDMETHODIMP IEnumOnSTLImpl::Skip(ULONG celt) +{ + HRESULT hr = S_OK; + while (celt--) + { + if (m_iter != m_pcollection->end()) + m_iter++; + else + { + hr = S_FALSE; + break; + } + } + return hr; +} + +template +STDMETHODIMP IEnumOnSTLImpl::Clone(Base** ppEnum) +{ + typedef CComObject > _class; + HRESULT hRes = E_POINTER; + if (ppEnum != NULL) + { + *ppEnum = NULL; + _class* p; + hRes = _class::CreateInstance(&p); + if (SUCCEEDED(hRes)) + { + hRes = p->Init(m_spUnk, *m_pcollection); + if (SUCCEEDED(hRes)) + { + p->m_iter = m_iter; + hRes = p->_InternalQueryInterface(*piid, (void**)ppEnum); + } + if (FAILED(hRes)) + delete p; + } + } + return hRes; +} + +template +class ATL_NO_VTABLE CComEnumOnSTL : + public IEnumOnSTLImpl, + public CComObjectRootEx< ThreadModel > +{ +public: + typedef CComEnumOnSTL _CComEnum; + typedef IEnumOnSTLImpl _CComEnumBase; + BEGIN_COM_MAP(_CComEnum) + COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase) + END_COM_MAP() +}; + +template +class ICollectionOnSTLImpl : public T +{ +public: + STDMETHOD(get_Count)(long* pcount) + { + if (pcount == NULL) + return E_POINTER; + ATLASSUME(m_coll.size()<=LONG_MAX); + + *pcount = (long)m_coll.size(); + + return S_OK; + } + STDMETHOD(get_Item)(long Index, ItemType* pvar) + { + //Index is 1-based + if (pvar == NULL) + return E_POINTER; + if (Index < 1) + return E_INVALIDARG; + HRESULT hr = E_FAIL; + Index--; + CollType::const_iterator iter = m_coll.begin(); + while (iter != m_coll.end() && Index > 0) + { + iter++; + Index--; + } + if (iter != m_coll.end()) + hr = CopyItem::copy(pvar, &*iter); + return hr; + } + STDMETHOD(get__NewEnum)(IUnknown** ppUnk) + { + if (ppUnk == NULL) + return E_POINTER; + *ppUnk = NULL; + HRESULT hRes = S_OK; + CComObject* p; + hRes = CComObject::CreateInstance(&p); + if (SUCCEEDED(hRes)) + { + hRes = p->Init(this, m_coll); + if (hRes == S_OK) + hRes = p->QueryInterface(__uuidof(IUnknown), (void**)ppUnk); + } + if (hRes != S_OK) + delete p; + return hRes; + } + CollType m_coll; +}; + +////////////////////////////////////////////////////////////////////////////// +// ISpecifyPropertyPagesImpl +template +class ATL_NO_VTABLE ISpecifyPropertyPagesImpl : public ISpecifyPropertyPages +{ +public: + // ISpecifyPropertyPages + // + STDMETHOD(GetPages)(CAUUID* pPages) + { + ATLTRACE(atlTraceCOM, 2, _T("ISpecifyPropertyPagesImpl::GetPages\n")); + ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap(); + return GetPagesHelper(pPages, pMap); + } +protected: + HRESULT GetPagesHelper(CAUUID* pPages, ATL_PROPMAP_ENTRY* pMap) + { + if (pPages == NULL) + return E_POINTER; + ATLASSERT(pMap != NULL); + if (pMap == NULL) + return E_POINTER; + + int nCnt = 0; + int i; + // Get count of unique pages to alloc the array + for (i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + // only allow non data entry types + if (pMap[i].vt == 0) + { + // Does this property have a page? CLSID_NULL means it does not + if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL)) + nCnt++; + } + } + int nAllocCnt = nCnt; + pPages->pElems = NULL; + pPages->pElems = (GUID*) ::ATL::AtlCoTaskMemCAlloc(nAllocCnt, static_cast(sizeof(CLSID))); + if (pPages->pElems == NULL) + return E_OUTOFMEMORY; + // reset count of items we have added to the array + nCnt = 0; + for (i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + // only allow non data entry types + if (pMap[i].vt == 0) + { + // Does this property have a page? CLSID_NULL means it does not + if (!InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL)) + { + BOOL bFound = FALSE; + // Search through array we are building up to see + // if it is already in there + for (int j=0; jpElems[j])) + { + // It's already there, so no need to add it again + bFound = TRUE; + break; + } + } + // If we didn't find it in there then add it + if (!bFound && nCnt < nAllocCnt) + pPages->pElems[nCnt++] = *pMap[i].pclsidPropPage; + } + } + } + pPages->cElems = nCnt; + return S_OK; + } + +}; + +#ifndef _ATL_NO_CONNECTION_POINTS +///////////////////////////////////////////////////////////////////////////// +// Connection Points + +struct _ATL_CONNMAP_ENTRY +{ + DWORD_PTR dwOffset; +}; + + +// We want the offset of the connection point relative to the connection +// point container base class +#define BEGIN_CONNECTION_POINT_MAP(x)\ + __if_not_exists(_atl_conn_classtype) \ + { \ + typedef x _atl_conn_classtype;\ + } \ + static const ATL::_ATL_CONNMAP_ENTRY* GetConnMap(int* pnEntries) {\ + static const ATL::_ATL_CONNMAP_ENTRY _entries[] = { +#define BEGIN_ATTRCONNECTION_POINT_MAP(x)\ + __if_not_exists(_atl_conn_classtype) \ + { \ + typedef x _atl_conn_classtype;\ + } \ + static const ATL::_ATL_CONNMAP_ENTRY* GetAttrConnMap(int* pnEntries) {\ + static const ATL::_ATL_CONNMAP_ENTRY _entries[] = { + +// CONNECTION_POINT_ENTRY computes the offset of the connection point to the +// IConnectionPointContainer interface +#define CONNECTION_POINT_ENTRY(iid){offsetofclass(ATL::_ICPLocator<&iid>, _atl_conn_classtype)-\ + offsetofclass(ATL::IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)}, +#define END_CONNECTION_POINT_MAP() \ + __if_exists(GetAttrConnMap) \ + { \ + {(DWORD_PTR) -2}, \ + {(DWORD_PTR) GetAttrConnMap }, \ + } \ + {(DWORD_PTR)-1} }; \ + if (pnEntries) \ + { \ + __if_exists(GetAttrConnMap) \ + { \ + GetAttrConnMap(pnEntries); \ + *pnEntries += sizeof(_entries)/sizeof(ATL::_ATL_CONNMAP_ENTRY) - 3; \ + } \ + __if_not_exists(GetAttrConnMap) \ + { \ + *pnEntries = sizeof(_entries)/sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \ + } \ + } \ + return _entries;} +#define END_ATTRCONNECTION_POINT_MAP() \ + {(DWORD_PTR)-1} }; \ + if (pnEntries) \ + { \ + *pnEntries = sizeof(_entries)/sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \ + } \ + return _entries;} + + +#ifndef _DEFAULT_VECTORLENGTH +#define _DEFAULT_VECTORLENGTH 4 +#endif + +template +class CComUnkArray +{ +public: + CComUnkArray() + { + memset(m_arr, 0, sizeof(IUnknown*)*nMaxSize); + } + DWORD Add(IUnknown* pUnk); + BOOL Remove(DWORD dwCookie); + // If there is more than one instance of the same IUnknown*, + // this function returns the cookie for the first one. + DWORD WINAPI GetCookie(IUnknown** ppFind) + { + ATLASSERT(ppFind && *ppFind); + if (ppFind && *ppFind) + { + // find IUnknown* in array + for (DWORD dwCookie = 0; dwCookie < nMaxSize; dwCookie++) + { + if (m_arr[dwCookie] == *ppFind) + return dwCookie+1; // cookie minus one is an index into the array + } + } + return 0; + } + IUnknown* WINAPI GetUnknown(DWORD dwCookie) + { + ATLASSERT(dwCookie != 0 && dwCookie <= nMaxSize); + if (dwCookie != 0 && dwCookie <= nMaxSize) + return m_arr[dwCookie-1]; // cookie minus one is an index into the array + else + return NULL; + } + IUnknown** begin() + { + return &m_arr[0]; + } + IUnknown** end() + { + return &m_arr[nMaxSize]; + } +protected: + IUnknown* m_arr[nMaxSize]; +}; + +template +inline DWORD CComUnkArray::Add(IUnknown* pUnk) +{ + DWORD dwCookie = 1; + for (IUnknown** pp = begin(); pp < end(); pp++) + { + if (*pp == NULL) + { + *pp = pUnk; + return dwCookie; + } + aiwdwCookie++; + } + // If this fires then you need a larger array + ATLASSERT(0); + return 0; +} + +template +inline BOOL CComUnkArray::Remove(DWORD dwCookie) +{ + ATLASSERT(dwCookie != 0 && dwCookie <= nMaxSize); + if (dwCookie != 0 && dwCookie <= nMaxSize && m_arr[dwCookie-1] != NULL) + { + m_arr[dwCookie-1] = NULL; + return TRUE; + } + else + return FALSE; +} + +template<> +class CComUnkArray<1> +{ +public: + CComUnkArray() + { + m_arr[0] = NULL; + } + DWORD Add(IUnknown* pUnk) + { + if (m_arr[0] != NULL) + { + // If this fires then you need a larger array + ATLASSERT(0); + return 0; + } + m_arr[0] = pUnk; + return 1; + } + BOOL Remove(DWORD dwCookie) + { + ATLASSERT(dwCookie == 1); + if (dwCookie == 1 && m_arr[0] != NULL) + { + m_arr[0] = NULL; + return TRUE; + } + else + return FALSE; + } + DWORD WINAPI GetCookie(IUnknown** /* pp */) + { + return 1; + } + IUnknown* WINAPI GetUnknown(DWORD dwCookie) + { + ATLASSERT(dwCookie == 1); + if (dwCookie == 1) + return m_arr[0]; + else + return NULL; + } + IUnknown** begin() + { + return &m_arr[0]; + } + IUnknown** end() + { + return (&m_arr[0])+1; + } +protected: + IUnknown* m_arr[1]; +}; + +class CComDynamicUnkArray +{ +public: + CComDynamicUnkArray() + { + m_nSize = 0; + m_ppUnk = NULL; + } + + ~CComDynamicUnkArray() + { + if (m_nSize > 0) + free(m_ppUnk); + } + DWORD Add(IUnknown* pUnk); + BOOL Remove(DWORD dwCookie); + // If there is more than one instance of the same IUnknown*, + // this function returns the cookie for the first one. + DWORD WINAPI GetCookie(IUnknown** ppFind) + { + ATLASSERT(ppFind && *ppFind); + if (ppFind && *ppFind) + { + IUnknown** ppUnk = NULL; + DWORD dwCookie = 1; + // find IUnknown* in array + for (ppUnk = begin(); ppUnk < end(); ppUnk++) + { + if (*ppUnk == *ppFind) + return dwCookie; // cookie minus one is an index into the array + dwCookie++; + } + } + return 0; + } + IUnknown* WINAPI GetUnknown(DWORD dwCookie) + { +#ifndef _ATL_OLEDB_CONFORMANCE_TESTS + ATLASSERT(dwCookie != 0 && dwCookie <= (DWORD)m_nSize); +#endif + if (dwCookie != 0 && dwCookie <= (DWORD)m_nSize) + return GetAt(dwCookie-1); // cookie minus one is an index into the array + else + return NULL; + } + IUnknown** begin() + { + return m_ppUnk; + } + IUnknown** end() + { + return &m_ppUnk[m_nSize]; + } + + IUnknown* GetAt(int nIndex) + { + ATLASSERT(nIndex >= 0 && nIndex < m_nSize); + if (nIndex >= 0 && nIndex < m_nSize) + return m_ppUnk[nIndex]; + else + return NULL; + + } + int GetSize() const + { + return m_nSize; + } + void clear() + { + if (m_nSize > 0) + { + free(m_ppUnk); + m_ppUnk = 0; + } + m_nSize = 0; + } +protected: + IUnknown** m_ppUnk; + int m_nSize; +}; + +inline DWORD CComDynamicUnkArray::Add(IUnknown* pUnk) +{ + IUnknown** pp = NULL; + if (m_nSize == 0) + { + // Create array with _DEFAULT_VECTORLENGTH number of items. + ATLTRY(pp = (IUnknown**)calloc(sizeof(IUnknown*),_DEFAULT_VECTORLENGTH)); + if (pp == NULL) + return 0; + memset(pp, 0, sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH); + m_ppUnk = pp; + m_nSize = _DEFAULT_VECTORLENGTH; + } + // Walk array and use empty slots if any. + DWORD dwCookie = 1; + for (pp = begin(); pp < end(); pp++) + { + if (*pp == NULL) + { + *pp = pUnk; + return dwCookie; // cookie mi nus one is index into array + } + dwCookie++; + } + // No empty slots so resize array. + // # of new slots is double of current size. + int nAlloc = m_nSize*2; + pp = (IUnknown**)_recalloc(m_ppUnk, sizeof(IUnknown*),nAlloc); + if (pp == NULL) + return 0; + m_ppUnk = pp; + memset(&m_ppUnk[m_nSize], 0, sizeof(IUnknown*)*m_nSize); + m_ppUnk[m_nSize] = pUnk; + dwCookie = m_nSize+1; + m_nSize = nAlloc; + return dwCookie; // cookie minus one is index into array +} + +inline BOOL CComDynamicUnkArray::Remove(DWORD dwCookie) +{ + DWORD idx = dwCookie -1; +#ifndef _ATL_OLEDB_CONFORMANCE_TESTS + ATLASSERT(idx < dwCookie && idx < (DWORD)m_nSize); +#endif + if (idx < dwCookie && idx < (DWORD)m_nSize) + { + // cookie minus one is index into array + if (m_ppUnk[idx] == NULL) + return FALSE; + m_ppUnk[idx] = NULL; + return TRUE; + } + else + return FALSE; +} + +template +class ATL_NO_VTABLE _ICPLocator +{ +public: + //this method needs a different name than QueryInterface + STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject) = 0; + virtual ULONG STDMETHODCALLTYPE AddRef(void) = 0; + virtual ULONG STDMETHODCALLTYPE Release(void) = 0; +}; + +template +class ATL_NO_VTABLE IConnectionPointImpl : public _ICPLocator +{ + typedef CComEnum > CComEnumConnections; + typedef CDV _CDV; +public: + ~IConnectionPointImpl(); + STDMETHOD(_LocCPQueryInterface)(REFIID riid, void ** ppvObject) + { +#ifndef _ATL_OLEDB_CONFORMANCE_TESTS + ATLASSERT(ppvObject != NULL); +#endif + if (ppvObject == NULL) + return E_POINTER; + *ppvObject = NULL; + + if (InlineIsEqualGUID(riid, __uuidof(IConnectionPoint)) || InlineIsEqualUnknown(riid)) + { + *ppvObject = this; + AddRef(); +#ifdef _ATL_DEBUG_INTERFACES + _AtlDebugInterfacesModule.AddThunk((IUnknown**)ppvObject, _T("IConnectionPointImpl"), riid); +#endif // _ATL_DEBUG_INTERFACES + return S_OK; + } + else + return E_NOINTERFACE; + } + + STDMETHOD(GetConnectionInterface)(IID* piid2) + { + if (piid2 == NULL) + return E_POINTER; + *piid2 = *piid; + return S_OK; + } + STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer** ppCPC) + { + T* pT = static_cast(this); + // No need to check ppCPC for NULL since QI will do that for us + return pT->QueryInterface(__uuidof(IConnectionPointContainer), (void**)ppCPC); + } + STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie); + STDMETHOD(Unadvise)(DWORD dwCookie); + STDMETHOD(EnumConnections)(IEnumConnections** ppEnum); + CDV m_vec; +}; + +template +IConnectionPointImpl::~IConnectionPointImpl() +{ + IUnknown** pp = m_vec.begin(); + while (pp < m_vec.end()) + { + if (*pp != NULL) + (*pp)->Release(); + pp++; + } +} + +template +STDMETHODIMP IConnectionPointImpl::Advise(IUnknown* pUnkSink, + DWORD* pdwCookie) +{ + T* pT = static_cast(this); + IUnknown* p; + HRESULT hRes = S_OK; + if (pdwCookie != NULL) + *pdwCookie = 0; + if (pUnkSink == NULL || pdwCookie == NULL) + return E_POINTER; + IID iid; + GetConnectionInterface(&iid); + hRes = pUnkSink->QueryInterface(iid, (void**)&p); + if (SUCCEEDED(hRes)) + { + pT->Lock(); + *pdwCookie = m_vec.Add(p); + hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT; + pT->Unlock(); + if (hRes != S_OK) + p->Release(); + } + else if (hRes == E_NOINTERFACE) + hRes = CONNECT_E_CANNOTCONNECT; + if (FAILED(hRes)) + *pdwCookie = 0; + return hRes; +} + +template +STDMETHODIMP IConnectionPointImpl::Unadvise(DWORD dwCookie) +{ + T* pT = static_cast(this); + pT->Lock(); + IUnknown* p = m_vec.GetUnknown(dwCookie); + HRESULT hRes = m_vec.Remove(dwCookie) ? S_OK : CONNECT_E_NOCONNECTION; + pT->Unlock(); + if (hRes == S_OK && p != NULL) + p->Release(); + return hRes; +} + +#pragma warning(push) +#pragma warning(disable: 4068 6014 6211 28197) +template +STDMETHODIMP IConnectionPointImpl::EnumConnections( + IEnumConnections** ppEnum) +{ + if (ppEnum == NULL) + return E_POINTER; + *ppEnum = NULL; + CComObject* pEnum = NULL; + ATLTRY(pEnum = new CComObject) + if (pEnum == NULL) + return E_OUTOFMEMORY; + T* pT = static_cast(this); + pT->Lock(); + CONNECTDATA* pcd = NULL; + ATLTRY(pcd = new CONNECTDATA[m_vec.end()-m_vec.begin()]) + if (pcd == NULL) + { + delete pEnum; + pT->Unlock(); + return E_OUTOFMEMORY; + } + CONNECTDATA* pend = pcd; + // Copy the valid CONNECTDATA's + for (IUnknown** pp = m_vec.begin();ppAddRef(); + pend->pUnk = *pp; + pend->dwCookie = m_vec.GetCookie(pp); + pend++; + } + } + // don't copy the data, but transfer ownership to it + pEnum->Init(pcd, pend, NULL, AtlFlagTakeOwnership); + pT->Unlock(); + HRESULT hRes = pEnum->_InternalQueryInterface(__uuidof(IEnumConnections), (void**)ppEnum); + if (FAILED(hRes)) + delete pEnum; + return hRes; +} +#pragma warning(pop) + +///////////////////////////////////////////////////////////////////////////// +// IConnectionPointContainerImpl + +template +class ATL_NO_VTABLE IConnectionPointContainerImpl : public IConnectionPointContainer +{ + typedef CComEnum > + CComEnumConnectionPoints; +public: +#pragma warning(push) +#pragma warning(disable: 4068 6014 6211 28197) + STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints** ppEnum) + { + if (ppEnum == NULL) + return E_POINTER; + *ppEnum = NULL; + CComEnumConnectionPoints* pEnum = NULL; +#pragma warning(push) +#pragma warning(disable:28197) + ATLTRY(pEnum = new CComObject) +#pragma warning(pop) + if (pEnum == NULL) + return E_OUTOFMEMORY; + + int nCPCount; + const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(&nCPCount); + + // allocate an initialize a vector of connection point object pointers + USES_ATL_SAFE_ALLOCA; + if ((nCPCount < 0) || (nCPCount > (INT_MAX / sizeof(IConnectionPoint*)))) + return E_OUTOFMEMORY; + size_t nBytes=0; + HRESULT hr=S_OK; + if( FAILED(hr=::ATL::AtlMultiply(&nBytes, sizeof(IConnectionPoint*), static_cast(nCPCount)))) + { + return hr; + } + IConnectionPoint** ppCP = (IConnectionPoint**)_ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); + if (ppCP == NULL) + { + delete pEnum; + return E_OUTOFMEMORY; + } + + int i = 0; + while (pEntry->dwOffset != (DWORD_PTR)-1) + { + if (pEntry->dwOffset == (DWORD_PTR)-2) + { + pEntry++; + const _ATL_CONNMAP_ENTRY* (*pFunc)(int*) = (const _ATL_CONNMAP_ENTRY* (*)(int*))(pEntry->dwOffset); + pEntry = pFunc(NULL); + continue; + } + ppCP[i++] = (IConnectionPoint*)((INT_PTR)this+pEntry->dwOffset); + pEntry++; + } + + // copy the pointers: they will AddRef this object + HRESULT hRes = pEnum->Init((IConnectionPoint**)&ppCP[0], + (IConnectionPoint**)&ppCP[nCPCount], + reinterpret_cast(this), AtlFlagCopy); + if (FAILED(hRes)) + { + delete pEnum; + return hRes; + } + hRes = pEnum->QueryInterface(__uuidof(IEnumConnectionPoints), (void**)ppEnum); + if (FAILED(hRes)) + delete pEnum; + return hRes; + } +#pragma warning(pop) + + STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint** ppCP) + { + if (ppCP == NULL) + return E_POINTER; + *ppCP = NULL; + HRESULT hRes = CONNECT_E_NOCONNECTION; + const _ATL_CONNMAP_ENTRY* pEntry = T::GetConnMap(NULL); + IID iid; + while (pEntry->dwOffset != (DWORD_PTR)-1) + { + if (pEntry->dwOffset == (DWORD_PTR)-2) + { + pEntry++; + const _ATL_CONNMAP_ENTRY* (*pFunc)(int*) = (const _ATL_CONNMAP_ENTRY* (*)(int*))(pEntry->dwOffset); + pEntry = pFunc(NULL); + continue; + } + IConnectionPoint* pCP = + (IConnectionPoint*)((INT_PTR)this+pEntry->dwOffset); + if (SUCCEEDED(pCP->GetConnectionInterface(&iid)) && + InlineIsEqualGUID(riid, iid)) + { + *ppCP = pCP; + pCP->AddRef(); + hRes = S_OK; + break; + } + pEntry++; + } + return hRes; + } +}; + +#endif //!_ATL_NO_CONNECTION_POINTS + +///////////////////////////////////////////////////////////////////////////// +// IExternalConnectionImpl + +// An object that implements IExternalConnection should explicitly call +// CoDisconnectObject on itself when its external reference count drops to 0. +// This call will cause the stub manager to call Release on the object so the +// object can destroy itself. + +template +class IExternalConnectionImpl : public IExternalConnection +{ +public: + IExternalConnectionImpl(void) : m_nStrongLocks(0) {} + STDMETHODIMP_(DWORD) AddConnection(DWORD extconn, DWORD /*dwReserved*/) + { + DWORD dw = 0; + if (extconn & EXTCONN_STRONG) + { + dw = T::_ThreadModel::Increment(&m_nStrongLocks); + static_cast(this)->OnAddConnection(dw == 1); + } + return dw; + } + STDMETHODIMP_(DWORD) ReleaseConnection(DWORD extconn, DWORD /*dwReserved*/, BOOL bLastUnlockReleases) + { + DWORD dw = 0; + if (extconn & EXTCONN_STRONG) + { + dw = T::_ThreadModel::Decrement(&m_nStrongLocks); + static_cast(this)->OnReleaseConnection(dw == 0, !!bLastUnlockReleases); + } + return dw; + } + + // Services provided by this class + bool DoIHaveAStub() { return m_nStrongLocks != 0; } + LONG GetStrongConnectionCount() { return m_nStrongLocks; } + // Extensibility points provided by this class + void OnAddConnection(bool bThisIsFirstLock) {} + void OnReleaseConnection(bool bThisIsLastUnlock, bool bLastUnlockReleases) + { + if (bThisIsLastUnlock && bLastUnlockReleases) + CoDisconnectObject(static_cast(this)->GetUnknown(), 0); + } + // Implementation + LONG m_nStrongLocks; +}; + +#pragma pack(pop) + +// All exports go here +#ifndef _ATL_DLL + +///////////////////////////////////////////////////////////////////////////// +// IDispatch Error handling + +ATLINLINE ATLAPI AtlSetErrorInfo(const CLSID& clsid, LPCOLESTR lpszDesc, DWORD dwHelpID, + LPCOLESTR lpszHelpFile, const IID& iid, HRESULT hRes, HINSTANCE hInst) +{ + USES_CONVERSION_EX; + TCHAR szDesc[1024]; + szDesc[0] = NULL; + // For a valid HRESULT the id should be in the range [0x0200, 0xffff] + if (IS_INTRESOURCE(lpszDesc)) //id + { + UINT nID = LOWORD((DWORD_PTR)lpszDesc); + ATLASSERT((nID >= 0x0200 && nID <= 0xffff) || hRes != 0); + if (LoadString(hInst, nID, szDesc, 1024) == 0) + { + ATLASSERT(FALSE); + Checked::tcscpy_s(szDesc, _countof(szDesc), _T("Unknown Error")); + } + lpszDesc = T2OLE_EX(szDesc, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if(lpszDesc == NULL) + return E_OUTOFMEMORY; +#endif + if (hRes == 0) + hRes = MAKE_HRESULT(3, FACILITY_ITF, nID); + } + + CComPtr pICEI; + if (SUCCEEDED(CreateErrorInfo(&pICEI))) + { + CComPtr pErrorInfo; + pICEI->SetGUID(iid); + LPOLESTR lpsz; + ProgIDFromCLSID(clsid, &lpsz); + if (lpsz != NULL) + pICEI->SetSource(lpsz); + if (dwHelpID != 0 && lpszHelpFile != NULL) + { + pICEI->SetHelpContext(dwHelpID); + pICEI->SetHelpFile(const_cast(lpszHelpFile)); + } + CoTaskMemFree(lpsz); + pICEI->SetDescription((LPOLESTR)lpszDesc); + if (SUCCEEDED(pICEI->QueryInterface(__uuidof(IErrorInfo), (void**)&pErrorInfo))) + SetErrorInfo(0, pErrorInfo); + } + return (hRes == 0) ? DISP_E_EXCEPTION : hRes; +} + +///////////////////////////////////////////////////////////////////////////// +// IPersist* helpers. + +ATLINLINE ATLAPI AtlIPersistStreamInit_Load(LPSTREAM pStm, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk) +{ + ATLASSERT(pMap != NULL); + if (pStm == NULL || pMap == NULL || pThis == NULL || pUnk == NULL) + return E_INVALIDARG; + + HRESULT hr = S_OK; + DWORD dwVer; + hr = pStm->Read(&dwVer, sizeof(DWORD), NULL); + if (FAILED(hr)) + return hr; + if (dwVer > _ATL_VER) + return E_FAIL; + + CComPtr pDispatch; + const IID* piidOld = NULL; + for (int i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + if (pMap[i].szDesc == NULL) + continue; + + // check if raw data entry + if (pMap[i].dwSizeData != 0) + { + void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis); + // call CComBSTR::ReadFromStream for BSTRs + if (pMap[i].vt == VT_BSTR) + { + CComBSTR bstrRead; + hr = bstrRead.ReadFromStream(pStm); + (*(BSTR*)pData) = bstrRead.Detach(); + } + else + hr = pStm->Read(pData, pMap[i].dwSizeData, NULL); + if (FAILED(hr)) + return hr; + continue; + } + + CComVariant var; + + hr = var.ReadFromStream(pStm, pMap[i].vt); + if (FAILED(hr)) + break; + + if (pMap[i].piidDispatch != piidOld) + { + pDispatch.Release(); + if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch))) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i); + hr = E_FAIL; + break; + } + piidOld = pMap[i].piidDispatch; + } + + if (FAILED(pDispatch.PutProperty(pMap[i].dispid, &var))) + { + ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid); + hr = E_FAIL; + break; + } + } + return hr; +} + +ATLINLINE ATLAPI AtlIPersistStreamInit_Save(LPSTREAM pStm, + BOOL /* fClearDirty */, ATL_PROPMAP_ENTRY* pMap, + void* pThis, IUnknown* pUnk) +{ + ATLASSERT(pMap != NULL); + if (pStm == NULL || pMap == NULL || pThis == NULL || pUnk == NULL) + return E_INVALIDARG; + + DWORD dw = _ATL_VER; + HRESULT hr = pStm->Write(&dw, sizeof(DWORD), NULL); + if (FAILED(hr)) + return hr; + + CComPtr pDispatch; + const IID* piidOld = NULL; + for (int i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + if (pMap[i].szDesc == NULL) + continue; + + // check if raw data entry + if (pMap[i].dwSizeData != 0) + { + void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis); + // call CComBSTR::WriteToStream for BSTRs + if (pMap[i].vt == VT_BSTR) + { + CComBSTR bstrWrite; + bstrWrite.Attach(*(BSTR*)pData); + hr = bstrWrite.WriteToStream(pStm); + bstrWrite.Detach(); + } + else + hr = pStm->Write(pData, pMap[i].dwSizeData, NULL); + if (FAILED(hr)) + return hr; + continue; + } + + CComVariant var; + if (pMap[i].piidDispatch != piidOld) + { + pDispatch.Release(); + if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch))) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i); + hr = E_FAIL; + break; + } + piidOld = pMap[i].piidDispatch; + } + + if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var))) + { + ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid); + hr = E_FAIL; + break; + } + + hr = var.WriteToStream(pStm, pMap[i].vt); + if (FAILED(hr)) + break; + } + return hr; +} +ATLINLINE ATLAPI AtlIPersistPropertyBag_Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog, ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk) +{ + if (pPropBag == NULL || pMap == NULL || pThis == NULL || pUnk == NULL) + return E_INVALIDARG; + + CComPtr pDispatch; + const IID* piidOld = NULL; + for (int i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + if (pMap[i].szDesc == NULL) + continue; + + CComVariant var; + + // If raw entry skip it - we don't handle it for property bags just yet + if (pMap[i].dwSizeData != 0) + { + var.Clear(); + var.vt = pMap[i].vt; + void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis); + HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog); + if (SUCCEEDED(hr)) + { + // check the type - we only deal with limited set + switch (pMap[i].vt) + { + case VT_UI1: + case VT_I1: + *((BYTE*)pData) = var.bVal; + break; + case VT_BOOL: + *((VARIANT_BOOL*)pData) = var.boolVal; + break; + case VT_I2: + case VT_UI2: + *((short*)pData) = var.iVal; + break; + case VT_I4: + case VT_UI4: + case VT_INT: + case VT_UINT: + *((long*)pData) = var.lVal; + break; + case VT_BSTR: + *((BSTR*)pData) = ::SysAllocString(var.bstrVal); + if (*((BSTR*)pData) == NULL && var.bstrVal != NULL) + return E_OUTOFMEMORY; + break; + } + } + continue; + } + + if (pMap[i].piidDispatch != piidOld) + { + pDispatch.Release(); + if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch))) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i); + return E_FAIL; + } + piidOld = pMap[i].piidDispatch; + } + + VARTYPE vt = pMap[i].vt; + if (vt == VT_EMPTY) + { + if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var))) + { + ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid); + return E_FAIL; + } + vt = var.vt; + } + var.ClearToZero(); + var.vt = vt; + + HRESULT hr = pPropBag->Read(pMap[i].szDesc, &var, pErrorLog); + if (FAILED(hr)) + { +#ifdef _DEBUG + COLE2CT strDesc(pMap[i].szDesc); + LPCTSTR lp = static_cast(strDesc); + + if (hr == E_INVALIDARG) + { + if (lp == NULL) + ATLTRACE(atlTraceCOM, 0, _T("Property not in Bag\n")); + else + ATLTRACE(atlTraceCOM, 0, _T("Property %s not in Bag\n"), lp); + } + else + { + // Many containers return different ERROR values for Member not found + if (lp == NULL) + ATLTRACE(atlTraceCOM, 0, _T("Error attempting to read Property from PropertyBag \n")); + else + ATLTRACE(atlTraceCOM, 0, _T("Error attempting to read Property %s from PropertyBag \n"), lp); + } +#endif + continue; + } + + if (FAILED(pDispatch.PutProperty(pMap[i].dispid, &var))) + { + ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid); + return E_FAIL; + } + } + return S_OK; +} +ATLINLINE ATLAPI AtlIPersistPropertyBag_Save(LPPROPERTYBAG pPropBag, + BOOL /* fClearDirty */, BOOL /* fSaveAllProperties */, + ATL_PROPMAP_ENTRY* pMap, void* pThis, IUnknown* pUnk) +{ + if (pPropBag == NULL) + { + ATLTRACE(atlTraceCOM, 0, _T("PropBag pointer passed in was invalid\n")); + return E_INVALIDARG; + } + if (pMap == NULL || pThis == NULL || pUnk == NULL) + return E_INVALIDARG; + + CComPtr pDispatch; + const IID* piidOld = NULL; + for (int i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + if (pMap[i].szDesc == NULL) + continue; + + CComVariant var; + + // If raw entry skip it - we don't handle it for property bags just yet + if (pMap[i].dwSizeData != 0) + { + void* pData = (void*) (pMap[i].dwOffsetData + (DWORD_PTR)pThis); + // check the type - we only deal with limited set + bool bTypeOK = false; + switch (pMap[i].vt) + { + case VT_UI1: + case VT_I1: + var.bVal = *((BYTE*)pData); + bTypeOK = true; + break; + case VT_BOOL: + var.boolVal = *((VARIANT_BOOL*)pData); + bTypeOK = true; + break; + case VT_UI2: + var.iVal = *((short*)pData); + bTypeOK = true; + break; + case VT_UI4: + case VT_INT: + case VT_UINT: + var.lVal = *((long*)pData); + bTypeOK = true; + break; + case VT_BSTR: + var.bstrVal = ::SysAllocString(*((BSTR*)pData)); + if (var.bstrVal == NULL && *((BSTR*)pData) != NULL) + return E_OUTOFMEMORY; + bTypeOK = true; + break; + } + if (bTypeOK) + { + var.vt = pMap[i].vt; + HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var); + if (FAILED(hr)) + return hr; + } + continue; + } + + if (pMap[i].piidDispatch != piidOld) + { + pDispatch.Release(); + if (FAILED(pUnk->QueryInterface(*pMap[i].piidDispatch, (void**)&pDispatch))) + { + ATLTRACE(atlTraceCOM, 0, _T("Failed to get a dispatch pointer for property #%i\n"), i); + return E_FAIL; + } + piidOld = pMap[i].piidDispatch; + } + + if (FAILED(pDispatch.GetProperty(pMap[i].dispid, &var))) + { + ATLTRACE(atlTraceCOM, 0, _T("Invoked failed on DISPID %x\n"), pMap[i].dispid); + return E_FAIL; + } + + if (pMap[i].vt != VT_EMPTY && pMap[i].vt != var.vt) + { + HRESULT hr = var.ChangeType(pMap[i].vt); + if (FAILED(hr)) + return hr; + } + + if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH) + { + if (var.punkVal == NULL) + { + ATLTRACE(atlTraceCOM, 2, _T("Warning skipping empty IUnknown in Save\n")); + continue; + } + } + + HRESULT hr = pPropBag->Write(pMap[i].szDesc, &var); + if (FAILED(hr)) + return hr; + } + return S_OK; +} + +///////////////////////////////////////////////////////////////////////////// +// Connection Point Sink Helper + +ATLINLINE ATLAPI AtlGetObjectSourceInterface(IUnknown* punkObj, GUID* plibid, IID* piid, unsigned short* pdwMajor, unsigned short* pdwMinor) +{ + if (plibid == NULL || piid == NULL || pdwMajor == NULL || pdwMinor == NULL) + return E_POINTER; + + *plibid = GUID_NULL; + *piid = IID_NULL; + *pdwMajor = 0; + *pdwMinor = 0; + + + HRESULT hr = E_FAIL; + if (punkObj != NULL) + { + CComPtr spDispatch; + hr = punkObj->QueryInterface(__uuidof(IDispatch), (void**)&spDispatch); + if (SUCCEEDED(hr)) + { + CComPtr spTypeInfo; + hr = spDispatch->GetTypeInfo(0, 0, &spTypeInfo); + if (SUCCEEDED(hr)) + { + CComPtr spTypeLib; + hr = spTypeInfo->GetContainingTypeLib(&spTypeLib, 0); + if (SUCCEEDED(hr)) + { + TLIBATTR* plibAttr; + hr = spTypeLib->GetLibAttr(&plibAttr); + if (SUCCEEDED(hr)) + { + Checked::memcpy_s(plibid, sizeof(GUID), &plibAttr->guid, sizeof(GUID)); + *pdwMajor = plibAttr->wMajorVerNum; + *pdwMinor = plibAttr->wMinorVerNum; + spTypeLib->ReleaseTLibAttr(plibAttr); + // First see if the object is willing to tell us about the + // default source interface via IProvideClassInfo2 + CComPtr spProvideClassInfo; + hr = punkObj->QueryInterface(__uuidof(IProvideClassInfo2), (void**)&spProvideClassInfo); + if (SUCCEEDED(hr) && spProvideClassInfo != NULL) + hr = spProvideClassInfo->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID, piid); + else + { + // No, we have to go hunt for it + CComPtr spInfoCoClass; + // If we have a clsid, use that + // Otherwise, try to locate the clsid from IPersist + CComPtr spPersist; + CLSID clsid; + hr = punkObj->QueryInterface(__uuidof(IPersist), (void**)&spPersist); + if (SUCCEEDED(hr)) + { + hr = spPersist->GetClassID(&clsid); + if (SUCCEEDED(hr)) + { + hr = spTypeLib->GetTypeInfoOfGuid(clsid, &spInfoCoClass); + if (SUCCEEDED(hr)) + { + TYPEATTR* pAttr=NULL; + spInfoCoClass->GetTypeAttr(&pAttr); + if (pAttr != NULL) + { + HREFTYPE hRef; + for (int i = 0; i < pAttr->cImplTypes; i++) + { + int nType; + hr = spInfoCoClass->GetImplTypeFlags(i, &nType); + if (SUCCEEDED(hr)) + { + if (nType == (IMPLTYPEFLAG_FDEFAULT | IMPLTYPEFLAG_FSOURCE)) + { + // we found it + hr = spInfoCoClass->GetRefTypeOfImplType(i, &hRef); + if (SUCCEEDED(hr)) + { + CComPtr spInfo; + hr = spInfoCoClass->GetRefTypeInfo(hRef, &spInfo); + if (SUCCEEDED(hr)) + { + TYPEATTR* pAttrIF; + spInfo->GetTypeAttr(&pAttrIF); + if (pAttrIF != NULL) + { + Checked::memcpy_s(piid, sizeof(GUID), &pAttrIF->guid, sizeof(GUID)); + spInfo->ReleaseTypeAttr(pAttrIF); + } + } + } + break; + } + } + } + spInfoCoClass->ReleaseTypeAttr(pAttr); + } + } + } + } + } + } + } + } + } + } + return hr; +} + +#endif // !_ATL_DLL + +} // namespace ATL +#pragma pack(pop) + +#ifdef _ATL_ALL_WARNINGS +#pragma warning( pop ) +#endif + +#if (defined(_PREFIX_) || defined(_PREFAST_)) && (_MSC_VER < 1400) +#pragma warning (pop) +#endif // old PREfast parser + +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning (pop) +#endif + +#endif // __ATLCOM_H__ + +///////////////////////////////////////////////////////////////////////////// + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcomcli.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcomcli.h new file mode 100644 index 00000000..db9975dd --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcomcli.h @@ -0,0 +1,2874 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCOMCLI_H__ +#define __ATLCOMCLI_H__ + +#pragma once + +#include +#include +#include + +#pragma warning (push) +#pragma warning (disable: 4127) // conditional expression constant +#pragma warning (disable: 4571) //catch(...) blocks compiled with /EHs do NOT catch or re-throw Structured Exceptions + + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ +///////////////////////////////////////////////////////////////////////////// +// Error to HRESULT helpers + +ATL_NOINLINE inline HRESULT AtlHresultFromLastError() throw() +{ + DWORD dwErr = ::GetLastError(); + return HRESULT_FROM_WIN32(dwErr); +} + +ATL_NOINLINE inline HRESULT AtlHresultFromWin32(__in DWORD nError) throw() +{ + return( HRESULT_FROM_WIN32( nError ) ); +} + +///////////////////////////////////////////////////////////////////////////// +// Smart Pointer helpers + +ATLAPI_(IUnknown*) AtlComPtrAssign(__deref_out_opt IUnknown** pp, __in_opt IUnknown* lp); +ATLAPI_(IUnknown*) AtlComQIPtrAssign(__deref_out_opt IUnknown** pp, __in_opt IUnknown* lp, REFIID riid); + +#ifndef _ATL_DLL + +ATLINLINE ATLAPI_(IUnknown*) AtlComPtrAssign(__deref_out_opt IUnknown** pp, __in_opt IUnknown* lp) +{ + if (pp == NULL) + return NULL; + + if (lp != NULL) + lp->AddRef(); + if (*pp) + (*pp)->Release(); + *pp = lp; + return lp; +} + +ATLINLINE ATLAPI_(IUnknown*) AtlComQIPtrAssign(__deref_out_opt IUnknown** pp, __in_opt IUnknown* lp, REFIID riid) +{ + if (pp == NULL) + return NULL; + + IUnknown* pTemp = *pp; + *pp = NULL; + if (lp != NULL) + lp->QueryInterface(riid, (void**)pp); + if (pTemp) + pTemp->Release(); + return *pp; +} + +#endif // _ATL_DLL + +///////////////////////////////////////////////////////////////////////////// +// COM Smart pointers + +template +class _NoAddRefReleaseOnCComPtr : public T +{ + private: + STDMETHOD_(ULONG, AddRef)()=0; + STDMETHOD_(ULONG, Release)()=0; +}; + +inline __checkReturn HRESULT AtlSetChildSite(__inout IUnknown* punkChild, __in_opt IUnknown* punkParent) +{ + if (punkChild == NULL) + return E_POINTER; + + HRESULT hr; + IObjectWithSite* pChildSite = NULL; + hr = punkChild->QueryInterface(__uuidof(IObjectWithSite), (void**)&pChildSite); + if (SUCCEEDED(hr) && pChildSite != NULL) + { + hr = pChildSite->SetSite(punkParent); + pChildSite->Release(); + } + return hr; +} + + +//CComPtrBase provides the basis for all other smart pointers +//The other smartpointers add their own constructors and operators +template +class CComPtrBase +{ +protected: + CComPtrBase() throw() + { + p = NULL; + } + CComPtrBase(__in int nNull) throw() + { + ATLASSERT(nNull == 0); + (void)nNull; + p = NULL; + } + CComPtrBase(__in_opt T* lp) throw() + { + p = lp; + if (p != NULL) + p->AddRef(); + } +public: + typedef T _PtrClass; + ~CComPtrBase() throw() + { + if (p) + p->Release(); + } + operator T*() const throw() + { + return p; + } + T& operator*() const + { + ATLENSURE(p!=NULL); + return *p; + } + //The assert on operator& usually indicates a bug. If this is really + //what is needed, however, take the address of the p member explicitly. + T** operator&() throw() + { + ATLASSERT(p==NULL); + return &p; + } + _NoAddRefReleaseOnCComPtr* operator->() const throw() + { + ATLASSERT(p!=NULL); + return (_NoAddRefReleaseOnCComPtr*)p; + } + bool operator!() const throw() + { + return (p == NULL); + } + bool operator<(__in_opt T* pT) const throw() + { + return p < pT; + } + bool operator!=(__in_opt T* pT) const + { + return !operator==(pT); + } + bool operator==(__in_opt T* pT) const throw() + { + return p == pT; + } + + // Release the interface and set to NULL + void Release() throw() + { + T* pTemp = p; + if (pTemp) + { + p = NULL; + pTemp->Release(); + } + } + // Compare two objects for equivalence + bool IsEqualObject(__in_opt IUnknown* pOther) throw() + { + if (p == NULL && pOther == NULL) + return true; // They are both NULL objects + + if (p == NULL || pOther == NULL) + return false; // One is NULL the other is not + + CComPtr punk1; + CComPtr punk2; + p->QueryInterface(__uuidof(IUnknown), (void**)&punk1); + pOther->QueryInterface(__uuidof(IUnknown), (void**)&punk2); + return punk1 == punk2; + } + // Attach to an existing interface (does not AddRef) + void Attach(__in T* p2) throw() + { + if (p) + p->Release(); + p = p2; + } + // Detach the interface (does not Release) + T* Detach() throw() + { + T* pt = p; + p = NULL; + return pt; + } + __checkReturn HRESULT CopyTo(__deref_out_opt T** ppT) throw() + { + ATLASSERT(ppT != NULL); + if (ppT == NULL) + return E_POINTER; + *ppT = p; + if (p) + p->AddRef(); + return S_OK; + } + __checkReturn HRESULT SetSite(__in_opt IUnknown* punkParent) throw() + { + return AtlSetChildSite(p, punkParent); + } + __checkReturn HRESULT Advise(__in IUnknown* pUnk, __in const IID& iid, __out LPDWORD pdw) throw() + { + return AtlAdvise(p, pUnk, iid, pdw); + } + __checkReturn HRESULT CoCreateInstance(__in REFCLSID rclsid, __in_opt LPUNKNOWN pUnkOuter = NULL, __in DWORD dwClsContext = CLSCTX_ALL) throw() + { + ATLASSERT(p == NULL); + return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p); + } + __checkReturn HRESULT CoCreateInstance(__in LPCOLESTR szProgID, __in_opt LPUNKNOWN pUnkOuter = NULL, __in DWORD dwClsContext = CLSCTX_ALL) throw() + { + CLSID clsid; + HRESULT hr = CLSIDFromProgID(szProgID, &clsid); + ATLASSERT(p == NULL); + if (SUCCEEDED(hr)) + hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&p); + return hr; + } + template + __checkReturn HRESULT QueryInterface(__deref_out_opt Q** pp) const throw() + { + ATLASSERT(pp != NULL); + return p->QueryInterface(__uuidof(Q), (void**)pp); + } + T* p; +}; + +template +class CComPtr : public CComPtrBase +{ +public: + CComPtr() throw() + { + } + CComPtr(int nNull) throw() : + CComPtrBase(nNull) + { + } + CComPtr(T* lp) throw() : + CComPtrBase(lp) + + { + } + CComPtr(__in const CComPtr& lp) throw() : + CComPtrBase(lp.p) + { + } + T* operator=(__in_opt T* lp) throw() + { + if(*this!=lp) + { + return static_cast(AtlComPtrAssign((IUnknown**)&p, lp)); + } + return *this; + } + template + T* operator=(__in const CComPtr& lp) throw() + { + if( !IsEqualObject(lp) ) + { + return static_cast(AtlComQIPtrAssign((IUnknown**)&p, lp, __uuidof(T))); + } + return *this; + } + T* operator=(__in const CComPtr& lp) throw() + { + if(*this!=lp) + { + return static_cast(AtlComPtrAssign((IUnknown**)&p, lp)); + } + return *this; + } +}; + +//specialization for IDispatch +template <> +class CComPtr : public CComPtrBase +{ +public: + CComPtr() throw() + { + } + CComPtr(IDispatch* lp) throw() : + CComPtrBase(lp) + { + } + CComPtr(const CComPtr& lp) throw() : + CComPtrBase(lp.p) + { + } + IDispatch* operator=(IDispatch* lp) throw() + { + if(*this!=lp) + { + return static_cast(AtlComPtrAssign((IUnknown**)&p, lp)); + } + return *this; + } + IDispatch* operator=(const CComPtr& lp) throw() + { + if(*this!=lp) + { + return static_cast(AtlComPtrAssign((IUnknown**)&p, lp.p)); + } + return *this; + } + +// IDispatch specific stuff + __checkReturn HRESULT GetPropertyByName(__in LPCOLESTR lpsz, __out VARIANT* pVar) throw() + { + ATLASSERT(p); + ATLASSERT(pVar); + DISPID dwDispID; + HRESULT hr = GetIDOfName(lpsz, &dwDispID); + if (SUCCEEDED(hr)) + hr = GetProperty(dwDispID, pVar); + return hr; + } + __checkReturn HRESULT GetProperty(__in DISPID dwDispID, __out VARIANT* pVar) throw() + { + return GetProperty(p, dwDispID, pVar); + } + __checkReturn HRESULT PutPropertyByName(__in LPCOLESTR lpsz, __in VARIANT* pVar) throw() + { + ATLASSERT(p); + ATLASSERT(pVar); + DISPID dwDispID; + HRESULT hr = GetIDOfName(lpsz, &dwDispID); + if (SUCCEEDED(hr)) + hr = PutProperty(dwDispID, pVar); + return hr; + } + __checkReturn HRESULT PutProperty(__in DISPID dwDispID, __in VARIANT* pVar) throw() + { + return PutProperty(p, dwDispID, pVar); + } + __checkReturn HRESULT GetIDOfName(__in LPCOLESTR lpsz, __out DISPID* pdispid) throw() + { + return p->GetIDsOfNames(IID_NULL, const_cast(&lpsz), 1, LOCALE_USER_DEFAULT, pdispid); + } + // Invoke a method by DISPID with no parameters + __checkReturn HRESULT Invoke0(__in DISPID dispid, __out_opt VARIANT* pvarRet = NULL) throw() + { + DISPPARAMS dispparams = { NULL, NULL, 0, 0}; + return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); + } + // Invoke a method by name with no parameters + __checkReturn HRESULT Invoke0(__in LPCOLESTR lpszName, __out_opt VARIANT* pvarRet = NULL) throw() + { + HRESULT hr; + DISPID dispid; + hr = GetIDOfName(lpszName, &dispid); + if (SUCCEEDED(hr)) + hr = Invoke0(dispid, pvarRet); + return hr; + } + // Invoke a method by DISPID with a single parameter + __checkReturn HRESULT Invoke1(__in DISPID dispid, VARIANT* pvarParam1, __out_opt VARIANT* pvarRet = NULL) throw() + { + DISPPARAMS dispparams = { pvarParam1, NULL, 1, 0}; + return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); + } + // Invoke a method by name with a single parameter + __checkReturn HRESULT Invoke1(__in LPCOLESTR lpszName, VARIANT* pvarParam1, __out_opt VARIANT* pvarRet = NULL) throw() + { + HRESULT hr; + DISPID dispid; + hr = GetIDOfName(lpszName, &dispid); + if (SUCCEEDED(hr)) + hr = Invoke1(dispid, pvarParam1, pvarRet); + return hr; + } + // Invoke a method by DISPID with two parameters + __checkReturn HRESULT Invoke2(__in DISPID dispid, __in VARIANT* pvarParam1, __in VARIANT* pvarParam2, __out_opt VARIANT* pvarRet = NULL) throw(); + // Invoke a method by name with two parameters + __checkReturn HRESULT Invoke2(__in LPCOLESTR lpszName, __in VARIANT* pvarParam1, __in VARIANT* pvarParam2, __out_opt VARIANT* pvarRet = NULL) throw() + { + HRESULT hr; + DISPID dispid; + hr = GetIDOfName(lpszName, &dispid); + if (SUCCEEDED(hr)) + hr = Invoke2(dispid, pvarParam1, pvarParam2, pvarRet); + return hr; + } + // Invoke a method by DISPID with N parameters + __checkReturn HRESULT InvokeN(DISPID dispid, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL) throw() + { + DISPPARAMS dispparams = { pvarParams, NULL, nParams, 0}; + return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); + } + // Invoke a method by name with Nparameters + __checkReturn HRESULT InvokeN(LPCOLESTR lpszName, VARIANT* pvarParams, int nParams, VARIANT* pvarRet = NULL) throw() + { + HRESULT hr; + DISPID dispid; + hr = GetIDOfName(lpszName, &dispid); + if (SUCCEEDED(hr)) + hr = InvokeN(dispid, pvarParams, nParams, pvarRet); + return hr; + } + static __checkReturn HRESULT PutProperty(__inout IDispatch* p, __in DISPID dwDispID, __in VARIANT* pVar) throw() + { + ATLASSERT(p); + ATLASSERT(pVar != NULL); + if (pVar == NULL) + return E_POINTER; + + if(p == NULL) + return E_INVALIDARG; + + ATLTRACE(atlTraceCOM, 2, _T("CPropertyHelper::PutProperty\n")); + DISPPARAMS dispparams = {NULL, NULL, 1, 1}; + dispparams.rgvarg = pVar; + DISPID dispidPut = DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = &dispidPut; + + if (pVar->vt == VT_UNKNOWN || pVar->vt == VT_DISPATCH || + (pVar->vt & VT_ARRAY) || (pVar->vt & VT_BYREF)) + { + HRESULT hr = p->Invoke(dwDispID, IID_NULL, + LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF, + &dispparams, NULL, NULL, NULL); + if (SUCCEEDED(hr)) + return hr; + } + return p->Invoke(dwDispID, IID_NULL, + LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, + &dispparams, NULL, NULL, NULL); + } + static __checkReturn HRESULT GetProperty(__in IDispatch* p, __in DISPID dwDispID, __out VARIANT* pVar) throw() + { + ATLASSERT(p); + ATLASSERT(pVar != NULL); + if (pVar == NULL) + return E_POINTER; + + if(p == NULL) + return E_INVALIDARG; + + ATLTRACE(atlTraceCOM, 2, _T("CPropertyHelper::GetProperty\n")); + DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0}; + return p->Invoke(dwDispID, IID_NULL, + LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, + &dispparamsNoArgs, pVar, NULL, NULL); + } +}; + +template +class CComQIPtr : public CComPtr +{ +public: + CComQIPtr() throw() + { + } + CComQIPtr(__in T* lp) throw() : + CComPtr(lp) + { + } + CComQIPtr(__in const CComQIPtr& lp) throw() : + CComPtr(lp.p) + { + } + CComQIPtr(__in_opt IUnknown* lp) throw() + { + if (lp != NULL) + lp->QueryInterface(*piid, (void **)&p); + } + T* operator=(__in T* lp) throw() + { + if(*this!=lp) + { + return static_cast(AtlComPtrAssign((IUnknown**)&p, lp)); + } + return *this; + } + T* operator=(__in const CComQIPtr& lp) throw() + { + if(*this!=lp) + { + return static_cast(AtlComPtrAssign((IUnknown**)&p, lp.p)); + } + return *this; + } + T* operator=(__in IUnknown* lp) throw() + { + if(*this!=lp) + { + return static_cast(AtlComQIPtrAssign((IUnknown**)&p, lp, *piid)); + } + return *this; + } +}; + +//Specialization to make it work +template<> +class CComQIPtr : public CComPtr +{ +public: + CComQIPtr() throw() + { + } + CComQIPtr(__in IUnknown* lp) throw() + { + //Actually do a QI to get identity + if (lp != NULL) + lp->QueryInterface(__uuidof(IUnknown), (void **)&p); + } + CComQIPtr(__in const CComQIPtr& lp) throw() : + CComPtr(lp.p) + { + } + IUnknown* operator=(__in IUnknown* lp) throw() + { + if(*this!=lp) + { + //Actually do a QI to get identity + return AtlComQIPtrAssign((IUnknown**)&p, lp, __uuidof(IUnknown)); + } + return *this; + } + + IUnknown* operator=(__in const CComQIPtr& lp) throw() + { + if(*this!=lp) + { + return AtlComPtrAssign((IUnknown**)&p, lp.p); + } + return *this; + } +}; + +typedef CComQIPtr CComDispatchDriver; + +#define com_cast ATL::CComQIPtr +#ifndef _ATL_STREAM_MAX_SIZE +#define _ATL_STREAM_MAX_SIZE 0x100000 +#endif + + +///////////////////////////////////////////////////////////////////////////// +// CComBSTR + +class CComBSTR +{ +public: + BSTR m_str; + + CComBSTR() throw() + { + m_str = NULL; + } + + CComBSTR(__in int nSize) + { + if (nSize == 0) + m_str = NULL; + else + { + m_str = ::SysAllocStringLen(NULL, nSize); + if (!*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + } + + CComBSTR(__in int nSize, __in_ecount_opt(nSize) LPCOLESTR sz) + { + if (nSize == 0) + { + m_str = NULL; + } + else + { + m_str = ::SysAllocStringLen(sz, nSize); + if (!*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + } + + CComBSTR(__in_opt LPCOLESTR pSrc) + { + if (pSrc == NULL) + { + m_str = NULL; + } + else + { + m_str = ::SysAllocString(pSrc); + if (!*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + } + + CComBSTR(__in const CComBSTR& src) + { + m_str = src.Copy(); + if (!!src && !*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + + CComBSTR(__in REFGUID guid) + { + OLECHAR szGUID[64]; + ::StringFromGUID2(guid, szGUID, 64); + m_str = ::SysAllocString(szGUID); + if (!*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + + CComBSTR& operator=(__in const CComBSTR& src) + { + if (m_str != src.m_str) + { + ::SysFreeString(m_str); + m_str = src.Copy(); + if (!!src && !*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + return *this; + } + + CComBSTR& operator=(__in_opt LPCOLESTR pSrc) + { + if (pSrc != m_str) + { + ::SysFreeString(m_str); + if (pSrc != NULL) + { + m_str = ::SysAllocString(pSrc); + if (!*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + else + { + m_str = NULL; + } + } + return *this; + } + + ~CComBSTR() throw(); + + unsigned int Length() const throw() + { + return ::SysStringLen(m_str); + } + + unsigned int ByteLength() const throw() + { + return ::SysStringByteLen(m_str); + } + + operator BSTR() const throw() + { + return m_str; + } + + +#ifndef ATL_CCOMBSTR_ADDRESS_OF_ASSERT +// Temp disable CComBSTR::operator& Assert +#define ATL_NO_CCOMBSTR_ADDRESS_OF_ASSERT +#endif + + + BSTR* operator&() throw() + { +#ifndef ATL_NO_CCOMBSTR_ADDRESS_OF_ASSERT +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "We are deliberately checking if this has already been allocated") + ATLASSERT(!*this); +#pragma prefast(pop) +#pragma warning(pop) +#endif + return &m_str; + } + + BSTR Copy() const throw() + { + if (!*this) + { + return NULL; + } + return ::SysAllocStringByteLen((char*)m_str, ::SysStringByteLen(m_str)); + } + + __checkReturn HRESULT CopyTo(__inout_opt BSTR* pbstr) throw() + { + ATLASSERT(pbstr != NULL); + if (pbstr == NULL) + { + return E_POINTER; + } + *pbstr = Copy(); +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "We are checking allocation semantics here") + if ((*pbstr == NULL) && (m_str != NULL)) + { + return E_OUTOFMEMORY; + } +#pragma prefast(pop) +#pragma warning(pop) + return S_OK; + } + + // copy BSTR to VARIANT + __checkReturn HRESULT CopyTo(__out_opt VARIANT *pvarDest) throw() + { + ATLASSERT(pvarDest != NULL); + HRESULT hRes = E_POINTER; + if (pvarDest != NULL) + { + pvarDest->vt = VT_BSTR; + pvarDest->bstrVal = Copy(); +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "We are checking allocation semantics here") + if (pvarDest->bstrVal == NULL && m_str != NULL) + { + hRes = E_OUTOFMEMORY; + } +#pragma prefast(pop) +#pragma warning(pop) + else + { + hRes = S_OK; + } + } + return hRes; + } + + void Attach(__in BSTR src) throw() + { + if (m_str != src) + { + ::SysFreeString(m_str); + m_str = src; + } + } + + BSTR Detach() throw() + { + BSTR s = m_str; + m_str = NULL; + return s; + } + + void Empty() throw() + { + ::SysFreeString(m_str); + m_str = NULL; + } + + bool operator!() const throw() + { +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + return (m_str == NULL); +#pragma prefast(pop) +#pragma warning(pop) + } + + __checkReturn HRESULT Append(__in const CComBSTR& bstrSrc) throw() + { + return AppendBSTR(bstrSrc.m_str); + } + + __checkReturn HRESULT Append(__in_opt LPCOLESTR lpsz) throw() + { + return Append(lpsz, UINT(ocslen(lpsz))); + } + + // a BSTR is just a LPCOLESTR so we need a special version to signify + // that we are appending a BSTR + __checkReturn HRESULT AppendBSTR(__in_opt BSTR p) throw() + { + if (::SysStringLen(p) == 0) + { + return S_OK; + } + BSTR bstrNew = NULL; + HRESULT hr; + hr = VarBstrCat(m_str, p, &bstrNew); + if (SUCCEEDED(hr)) + { + ::SysFreeString(m_str); + m_str = bstrNew; + } + return hr; + } + + __checkReturn HRESULT Append(__in_ecount_opt(nLen) LPCOLESTR lpsz, __in int nLen) throw() + { +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + if (lpsz == NULL || (m_str != NULL && nLen == 0)) +#pragma prefast(pop) +#pragma warning(pop) + return S_OK; + int n1 = Length(); + if (n1+nLen < n1) + return E_OUTOFMEMORY; + BSTR b; + b = ::SysAllocStringLen(NULL, n1+nLen); +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + if (b == NULL) +#pragma prefast(pop) +#pragma warning(pop) + return E_OUTOFMEMORY; + if(::SysStringLen(m_str) > 0) + { + Checked::memcpy_s(b, (n1+nLen)*sizeof(OLECHAR), m_str, n1*sizeof(OLECHAR)); + } + Checked::memcpy_s(b+n1, nLen*sizeof(OLECHAR), lpsz, nLen*sizeof(OLECHAR)); + b[n1+nLen] = NULL; + SysFreeString(m_str); + m_str = b; + return S_OK; + } + + __checkReturn HRESULT Append(__in char ch) throw() + { + OLECHAR chO = ch; + + return( Append( &chO, 1 ) ); + } + + __checkReturn HRESULT Append(__in wchar_t ch) throw() + { + return( Append( &ch, 1 ) ); + } + + __checkReturn HRESULT AppendBytes(__in_ecount_opt(nLen) const char* lpsz, __in int nLen) throw() + { + if (lpsz == NULL || nLen == 0) + return S_OK; + int n1 = ByteLength(); + if (n1+nLen < n1) + return E_OUTOFMEMORY; + BSTR b; + b = ::SysAllocStringByteLen(NULL, n1+nLen); + if (b == NULL) + { + return E_OUTOFMEMORY; + } + Checked::memcpy_s(b, n1+nLen, m_str, n1); + Checked::memcpy_s(((char*)b)+n1, nLen, lpsz, nLen); + *((OLECHAR*)(((char*)b)+n1+nLen)) = NULL; + SysFreeString(m_str); + m_str = b; + return S_OK; + } + + __checkReturn HRESULT AssignBSTR(const BSTR bstrSrc) throw() + { + HRESULT hr = S_OK; + if (m_str != bstrSrc) + { + ::SysFreeString(m_str); +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + if (bstrSrc != NULL) +#pragma prefast(pop) +#pragma warning(pop) + { + m_str = ::SysAllocStringByteLen((char*)bstrSrc, ::SysStringByteLen(bstrSrc)); + if (!*this) + { + hr = E_OUTOFMEMORY; + } + } + else + { + m_str = NULL; + } + } + + return hr; + } + + __checkReturn HRESULT ToLower() throw() + { + if (::SysStringLen(m_str) > 0) + { +#ifdef _UNICODE + // Convert in place + CharLowerBuff(m_str, Length()); +#else + // Cannot use conversion macros due to possible embedded NULLs + UINT _acp = _AtlGetConversionACP(); + int _convert = WideCharToMultiByte(_acp, 0, m_str, Length(), NULL, 0, NULL, NULL); + CTempBuffer pszA; + ATLTRY(pszA.Allocate(_convert)); + if (pszA == NULL) + return E_OUTOFMEMORY; + + int nRet = WideCharToMultiByte(_acp, 0, m_str, Length(), pszA, _convert, NULL, NULL); + if (nRet == 0) + { + ATLASSERT(0); + return AtlHresultFromLastError(); + } + + CharLowerBuff(pszA, nRet); + + _convert = MultiByteToWideChar(_acp, 0, pszA, nRet, NULL, 0); + + CTempBuffer pszW; + ATLTRY(pszW.Allocate(_convert)); + if (pszW == NULL) + return E_OUTOFMEMORY; + + nRet = MultiByteToWideChar(_acp, 0, pszA, nRet, pszW, _convert); + if (nRet <= 0) + { + ATLASSERT(0); + return AtlHresultFromLastError(); + } + + UINT nBytes=0; + HRESULT hr=S_OK; + if( FAILED(hr=::ATL::AtlMultiply(&nBytes, static_cast(nRet), static_cast(sizeof(OLECHAR))))) + { + return hr; + } + BSTR b = ::SysAllocStringByteLen((LPCSTR) (LPWSTR) pszW, nBytes); + if (b == NULL) + return E_OUTOFMEMORY; + SysFreeString(m_str); + m_str = b; +#endif + } + return S_OK; + } + __checkReturn HRESULT ToUpper() throw() + { + if (::SysStringLen(m_str) > 0) + { +#ifdef _UNICODE + // Convert in place + CharUpperBuff(m_str, Length()); +#else + // Cannot use conversion macros due to possible embedded NULLs + UINT _acp = _AtlGetConversionACP(); + int _convert = WideCharToMultiByte(_acp, 0, m_str, Length(), NULL, 0, NULL, NULL); + CTempBuffer pszA; + ATLTRY(pszA.Allocate(_convert)); + if (pszA == NULL) + return E_OUTOFMEMORY; + + int nRet = WideCharToMultiByte(_acp, 0, m_str, Length(), pszA, _convert, NULL, NULL); + if (nRet == 0) + { + ATLASSERT(0); + return AtlHresultFromLastError(); + } + + CharUpperBuff(pszA, nRet); + + _convert = MultiByteToWideChar(_acp, 0, pszA, nRet, NULL, 0); + + CTempBuffer pszW; + ATLTRY(pszW.Allocate(_convert)); + if (pszW == NULL) + return E_OUTOFMEMORY; + + nRet = MultiByteToWideChar(_acp, 0, pszA, nRet, pszW, _convert); + if (nRet <= 0) + { + ATLASSERT(0); + return AtlHresultFromLastError(); + } + + UINT nBytes=0; + HRESULT hr=S_OK; + if( FAILED(hr=::ATL::AtlMultiply(&nBytes, static_cast(nRet), static_cast(sizeof(OLECHAR))))) + { + return hr; + } + BSTR b = ::SysAllocStringByteLen((LPCSTR) (LPWSTR) pszW, nBytes); + if (b == NULL) + return E_OUTOFMEMORY; + SysFreeString(m_str); + m_str = b; +#endif + } + return S_OK; + } + + bool LoadString(__in HINSTANCE hInst, __in UINT nID) throw() + { + ::SysFreeString(m_str); + m_str = NULL; + return LoadStringResource(hInst, nID, m_str); + } + + bool LoadString(__in UINT nID) throw() + { + ::SysFreeString(m_str); + m_str = NULL; + return LoadStringResource(nID, m_str); + } + + CComBSTR& operator+=(__in const CComBSTR& bstrSrc) + { + HRESULT hr; + hr = AppendBSTR(bstrSrc.m_str); + if (FAILED(hr)) + AtlThrow(hr); + return *this; + } + + CComBSTR& operator+=(__in_opt LPCOLESTR pszSrc) + { + HRESULT hr; + hr = Append(pszSrc); + if (FAILED(hr)) + AtlThrow(hr); + return *this; + } + + bool operator<(const CComBSTR& bstrSrc) const throw() + { + return VarBstrCmp(m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_LT); + } + bool operator<(__in_z LPCOLESTR pszSrc) const + { + CComBSTR bstr2(pszSrc); + return operator<(bstr2); + } + bool operator<(__in_z LPOLESTR pszSrc) const + { + return operator<((LPCOLESTR)pszSrc); + } + + bool operator>(const CComBSTR& bstrSrc) const throw() + { + return VarBstrCmp(m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_GT); + } + bool operator>(__in_z LPCOLESTR pszSrc) const + { + CComBSTR bstr2(pszSrc); + return operator>(bstr2); + } + bool operator>(__in_z LPOLESTR pszSrc) const + { + return operator>((LPCOLESTR)pszSrc); + } + + bool operator!=(const CComBSTR& bstrSrc) const throw() + { + return !operator==(bstrSrc); + } + bool operator!=(__in_z LPCOLESTR pszSrc) const + { + return !operator==(pszSrc); + } + bool operator!=(int nNull) const throw() + { + return !operator==(nNull); + } + bool operator!=(__in_z LPOLESTR pszSrc) const + { + return operator!=((LPCOLESTR)pszSrc); + } + + bool operator==(const CComBSTR& bstrSrc) const throw() + { + return VarBstrCmp(m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_EQ); + } + bool operator==(__in_z LPCOLESTR pszSrc) const + { + CComBSTR bstr2(pszSrc); + return operator==(bstr2); + } + bool operator==(__in_z LPOLESTR pszSrc) const + { + return operator==((LPCOLESTR)pszSrc); + } + + bool operator==(int nNull) const throw() + { + ATLASSERT(nNull == NULL); + (void)nNull; + return (!*this); + } + + CComBSTR(__in LPCSTR pSrc) + { + if (pSrc != NULL) + { + m_str = A2WBSTR(pSrc); + if (!*this) + { + AtlThrow(E_OUTOFMEMORY); + } + } + else + { + m_str = NULL; + } + } + + CComBSTR(__in int nSize, __in_ecount_opt(nSize) LPCSTR sz) + { + if (nSize != 0 && sz == NULL) + { + m_str = ::SysAllocStringLen(NULL, nSize); + if (!*this) + { + AtlThrow(E_OUTOFMEMORY); + } + return; + } + + m_str = A2WBSTR(sz, nSize); + if (!*this && nSize != 0) + { + AtlThrow(E_OUTOFMEMORY); + } + } + + __checkReturn HRESULT Append(__in LPCSTR lpsz) throw() + { + if (lpsz == NULL) + return S_OK; + + CComBSTR bstrTemp; + ATLTRY(bstrTemp = lpsz); + if (!bstrTemp) + { + return E_OUTOFMEMORY; + } + return Append(bstrTemp); + } + + CComBSTR& operator=(__in LPCSTR pSrc) + { + ::SysFreeString(m_str); + m_str = A2WBSTR(pSrc); + if (!*this && pSrc != NULL) + { + AtlThrow(E_OUTOFMEMORY); + } + return *this; + } + + bool operator<(__in_z LPCSTR pszSrc) const + { + CComBSTR bstr2(pszSrc); + return operator<(bstr2); + } + bool operator>(__in_z LPCSTR pszSrc) const + { + CComBSTR bstr2(pszSrc); + return operator>(bstr2); + } + bool operator!=(__in_z LPCSTR pszSrc) const + { + return !operator==(pszSrc); + } + bool operator==(__in_z LPCSTR pszSrc) const + { + CComBSTR bstr2(pszSrc); + return operator==(bstr2); + } + + __checkReturn HRESULT WriteToStream(__inout IStream* pStream) throw() + { + ATLASSERT(pStream != NULL); + if(pStream == NULL) + return E_INVALIDARG; + + ULONG cb; + ULONG cbStrLen = CComBSTR::GetStreamSize(m_str) - sizeof(ULONG); + HRESULT hr = pStream->Write((void*) &cbStrLen, sizeof(cbStrLen), &cb); + if (FAILED(hr)) + return hr; + return cbStrLen ? pStream->Write((void*) m_str, cbStrLen, &cb) : S_OK; + } + + __checkReturn HRESULT ReadFromStream(__inout IStream* pStream) throw() + { + ATLASSERT(pStream != NULL); + if(pStream == NULL) + { + return E_INVALIDARG; + } + + ATLASSERT(!*this); // should be empty + Empty(); + + HRESULT hrSeek; + ULARGE_INTEGER nBegOffset; + { + LARGE_INTEGER nZeroOffset; + nZeroOffset.QuadPart = 0L; + hrSeek = pStream->Seek(nZeroOffset, STREAM_SEEK_CUR, &nBegOffset); + } + + ULONG cbRead = 0; + ULONG cbStrLen = 0; + HRESULT hr = pStream->Read(reinterpret_cast(&cbStrLen), sizeof(cbStrLen), &cbRead); + + if (SUCCEEDED(hr)) + { + // invalid data sizes + if (sizeof(cbStrLen) != cbRead) + { + ATLTRACE(atlTraceCOM, 0, _T("Input stream is corrupted.")); + hr = E_FAIL; + } + // check for NULL bstr + else if (cbStrLen == 0) + { + } + // security checks when system hang for huge stream of data + else if (cbStrLen > _ATL_STREAM_MAX_SIZE) + { + ATLTRACE(atlTraceCOM, 0, _T("String exceeded the maximum allowed size see _ATL_STREAM_MAX_SIZE.")); + hr = E_ACCESSDENIED; + } + else + { + //subtract size for terminating NULL which we wrote out + cbStrLen -= sizeof(OLECHAR); + + m_str = ::SysAllocStringByteLen(NULL, cbStrLen); + if (!*this) + { + hr = E_OUTOFMEMORY; + } + else + { + hr = pStream->Read(reinterpret_cast(m_str), cbStrLen, &cbRead); + + if (SUCCEEDED(hr)) + { + if (cbRead != cbStrLen) + { + ATLTRACE(atlTraceCOM, 0, _T("Length of string data is different than expected.")); + hr = E_FAIL; + } + else + { + OLECHAR ch; + hr = pStream->Read(reinterpret_cast(&ch), sizeof(OLECHAR), &cbRead); + + if (SUCCEEDED(hr)) + { + if (cbRead != sizeof(OLECHAR)) + { + ATLTRACE(atlTraceCOM, 0, _T("Cannot read NULL terminator from stream.")); + hr = E_FAIL; + } + else + { + //check if string is properly terminated with NULL + ATLASSERT(ch == L'\0'); + } + } + } + } + + if (FAILED(hr)) + { + ::SysFreeString(m_str); + m_str = NULL; + } + } + } + } + + // If SysAllocStringByteLen or IStream::Read failed, reset seek + // pointer to start of BSTR size. + if (FAILED(hr) && SUCCEEDED(hrSeek)) + { + LARGE_INTEGER nOffset; + nOffset.QuadPart = static_cast(nBegOffset.QuadPart); + pStream->Seek(nOffset, STREAM_SEEK_SET, NULL); + } + + return hr; + } + + static bool LoadStringResource(__in HINSTANCE hInstance, __in UINT uID, __deref_out_opt BSTR& bstrText) throw() + { + const ATLSTRINGRESOURCEIMAGE* pImage; + +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + ATLASSERT(bstrText == NULL); +#pragma prefast(pop) +#pragma warning(pop) + + pImage = AtlGetStringResourceImage(hInstance, uID); + if (pImage != NULL) + { + bstrText = ::SysAllocStringLen(pImage->achString, pImage->nLength); + } +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + return (bstrText != NULL) ? true : false; +#pragma prefast(pop) +#pragma warning(pop) + } + + static bool LoadStringResource(__in UINT uID, __deref_out_opt BSTR& bstrText) throw() + { + const ATLSTRINGRESOURCEIMAGE* pImage; + +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + ATLASSERT(bstrText == NULL); +#pragma prefast(pop) +#pragma warning(pop) + + pImage = AtlGetStringResourceImage(uID); + if (pImage != NULL) + { + bstrText = ::SysAllocStringLen(pImage->achString, pImage->nLength); + } + +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + return (bstrText != NULL) ? true : false; +#pragma prefast(pop) +#pragma warning(pop) + } + + // each character in BSTR is copied to each element in SAFEARRAY + __success(return>=0) HRESULT BSTRToArray(__deref_out LPSAFEARRAY *ppArray) throw() + { + return VectorFromBstr(m_str, ppArray); + } + + // first character of each element in SAFEARRAY is copied to BSTR + __checkReturn HRESULT ArrayToBSTR(__in const SAFEARRAY *pSrc) throw() + { + ::SysFreeString(m_str); + return BstrFromVector((LPSAFEARRAY)pSrc, &m_str); + } + static ULONG GetStreamSize(BSTR bstr) + { + ULONG ulSize=sizeof(ULONG); +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + if (bstr != NULL) +#pragma prefast(pop) +#pragma warning(pop) + { + ulSize += SysStringByteLen(bstr) + sizeof(OLECHAR); + } + return ulSize; + } +}; + +inline CComBSTR::~CComBSTR() throw() + { + ::SysFreeString(m_str); + } + +inline void SysFreeStringHelper(__in CComBSTR& bstr) +{ + bstr.Empty(); +} + +inline void SysFreeStringHelper(BSTR bstr) +{ + ::SysFreeString(bstr); +} + +inline __checkReturn HRESULT SysAllocStringHelper(__out_opt CComBSTR& bstrDest,BSTR bstrSrc) +{ + bstrDest=bstrSrc; + return !bstrDest ? E_OUTOFMEMORY : S_OK; +} + +inline __checkReturn HRESULT SysAllocStringHelper(__out_opt BSTR& bstrDest,BSTR bstrSrc) +{ + bstrDest=::SysAllocString(bstrSrc); +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "The semantics of this function are about allocation, not content") + return bstrDest==NULL ? E_OUTOFMEMORY : S_OK; +#pragma prefast(pop) +#pragma warning(pop) +} + +///////////////////////////////////////////////////////////// +// Class to Adapt CComBSTR and CComPtr for use with STL containers +// the syntax to use it is +// std::vector< CAdapt > vect; + +template +class CAdapt +{ +public: + CAdapt() + { + } + CAdapt(__in const T& rSrc) : + m_T( rSrc ) + { + } + + CAdapt(__in const CAdapt& rSrCA) : + m_T( rSrCA.m_T ) + { + } + + CAdapt& operator=(__in const T& rSrc) + { + m_T = rSrc; + return *this; + } + bool operator<(__in const T& rSrc) const + { + return m_T < rSrc; + } + bool operator==(__in const T& rSrc) const + { + return m_T == rSrc; + } + operator T&() + { + return m_T; + } + + operator const T&() const + { + return m_T; + } + + T m_T; +}; + +///////////////////////////////////////////////////////////////////////////// +// CComVariant + + +#define ATL_VARIANT_TRUE VARIANT_BOOL( -1 ) +#define ATL_VARIANT_FALSE VARIANT_BOOL( 0 ) + +template< typename T > +class CVarTypeInfo +{ +// static const VARTYPE VT; // VARTYPE corresponding to type T +// static T VARIANT::* const pmField; // Pointer-to-member of corresponding field in VARIANT struct +}; + +template<> +class CVarTypeInfo< char > +{ +public: + static const VARTYPE VT = VT_I1; + static char VARIANT::* const pmField; +}; + +__declspec( selectany ) char VARIANT::* const CVarTypeInfo< char >::pmField = &VARIANT::cVal; + +template<> +class CVarTypeInfo< unsigned char > +{ +public: + static const VARTYPE VT = VT_UI1; + static unsigned char VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned char VARIANT::* const CVarTypeInfo< unsigned char >::pmField = &VARIANT::bVal; + +template<> +class CVarTypeInfo< char* > +{ +public: + static const VARTYPE VT = VT_I1|VT_BYREF; + static char* VARIANT::* const pmField; +}; + +__declspec( selectany ) char* VARIANT::* const CVarTypeInfo< char* >::pmField = &VARIANT::pcVal; + +template<> +class CVarTypeInfo< unsigned char* > +{ +public: + static const VARTYPE VT = VT_UI1|VT_BYREF; + static unsigned char* VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned char* VARIANT::* const CVarTypeInfo< unsigned char* >::pmField = &VARIANT::pbVal; + +template<> +class CVarTypeInfo< short > +{ +public: + static const VARTYPE VT = VT_I2; + static short VARIANT::* const pmField; +}; + +__declspec( selectany ) short VARIANT::* const CVarTypeInfo< short >::pmField = &VARIANT::iVal; + +template<> +class CVarTypeInfo< short* > +{ +public: + static const VARTYPE VT = VT_I2|VT_BYREF; + static short* VARIANT::* const pmField; +}; + +__declspec( selectany ) short* VARIANT::* const CVarTypeInfo< short* >::pmField = &VARIANT::piVal; + +template<> +class CVarTypeInfo< unsigned short > +{ +public: + static const VARTYPE VT = VT_UI2; + static unsigned short VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned short VARIANT::* const CVarTypeInfo< unsigned short >::pmField = &VARIANT::uiVal; + +#ifdef _NATIVE_WCHAR_T_DEFINED // Only treat unsigned short* as VT_UI2|VT_BYREF if BSTR isn't the same as unsigned short* +template<> +class CVarTypeInfo< unsigned short* > +{ +public: + static const VARTYPE VT = VT_UI2|VT_BYREF; + static unsigned short* VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned short* VARIANT::* const CVarTypeInfo< unsigned short* >::pmField = &VARIANT::puiVal; +#endif // _NATIVE_WCHAR_T_DEFINED + +template<> +class CVarTypeInfo< int > +{ +public: + static const VARTYPE VT = VT_I4; + static int VARIANT::* const pmField; +}; + +__declspec( selectany ) int VARIANT::* const CVarTypeInfo< int >::pmField = &VARIANT::intVal; + +template<> +class CVarTypeInfo< int* > +{ +public: + static const VARTYPE VT = VT_I4|VT_BYREF; + static int* VARIANT::* const pmField; +}; + +__declspec( selectany ) int* VARIANT::* const CVarTypeInfo< int* >::pmField = &VARIANT::pintVal; + +template<> +class CVarTypeInfo< unsigned int > +{ +public: + static const VARTYPE VT = VT_UI4; + static unsigned int VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned int VARIANT::* const CVarTypeInfo< unsigned int >::pmField = &VARIANT::uintVal; + +template<> +class CVarTypeInfo< unsigned int* > +{ +public: + static const VARTYPE VT = VT_UI4|VT_BYREF; + static unsigned int* VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned int* VARIANT::* const CVarTypeInfo< unsigned int* >::pmField = &VARIANT::puintVal; + +template<> +class CVarTypeInfo< long > +{ +public: + static const VARTYPE VT = VT_I4; + static long VARIANT::* const pmField; +}; + +__declspec( selectany ) long VARIANT::* const CVarTypeInfo< long >::pmField = &VARIANT::lVal; + +template<> +class CVarTypeInfo< long* > +{ +public: + static const VARTYPE VT = VT_I4|VT_BYREF; + static long* VARIANT::* const pmField; +}; + +__declspec( selectany ) long* VARIANT::* const CVarTypeInfo< long* >::pmField = &VARIANT::plVal; + +template<> +class CVarTypeInfo< unsigned long > +{ +public: + static const VARTYPE VT = VT_UI4; + static unsigned long VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned long VARIANT::* const CVarTypeInfo< unsigned long >::pmField = &VARIANT::ulVal; + +template<> +class CVarTypeInfo< unsigned long* > +{ +public: + static const VARTYPE VT = VT_UI4|VT_BYREF; + static unsigned long* VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned long* VARIANT::* const CVarTypeInfo< unsigned long* >::pmField = &VARIANT::pulVal; + +template<> +class CVarTypeInfo< __int64 > +{ +public: + static const VARTYPE VT = VT_I8; + static __int64 VARIANT::* const pmField; +}; + +__declspec( selectany ) __int64 VARIANT::* const CVarTypeInfo< __int64 >::pmField = &VARIANT::llVal; + +template<> +class CVarTypeInfo< __int64* > +{ +public: + static const VARTYPE VT = VT_I8|VT_BYREF; + static __int64* VARIANT::* const pmField; +}; + +__declspec( selectany ) __int64* VARIANT::* const CVarTypeInfo< __int64* >::pmField = &VARIANT::pllVal; + +template<> +class CVarTypeInfo< unsigned __int64 > +{ +public: + static const VARTYPE VT = VT_UI8; + static unsigned __int64 VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned __int64 VARIANT::* const CVarTypeInfo< unsigned __int64 >::pmField = &VARIANT::ullVal; + +template<> +class CVarTypeInfo< unsigned __int64* > +{ +public: + static const VARTYPE VT = VT_UI8|VT_BYREF; + static unsigned __int64* VARIANT::* const pmField; +}; + +__declspec( selectany ) unsigned __int64* VARIANT::* const CVarTypeInfo< unsigned __int64* >::pmField = &VARIANT::pullVal; + +template<> +class CVarTypeInfo< float > +{ +public: + static const VARTYPE VT = VT_R4; + static float VARIANT::* const pmField; +}; + +__declspec( selectany ) float VARIANT::* const CVarTypeInfo< float >::pmField = &VARIANT::fltVal; + +template<> +class CVarTypeInfo< float* > +{ +public: + static const VARTYPE VT = VT_R4|VT_BYREF; + static float* VARIANT::* const pmField; +}; + +__declspec( selectany ) float* VARIANT::* const CVarTypeInfo< float* >::pmField = &VARIANT::pfltVal; + +template<> +class CVarTypeInfo< double > +{ +public: + static const VARTYPE VT = VT_R8; + static double VARIANT::* const pmField; +}; + +__declspec( selectany ) double VARIANT::* const CVarTypeInfo< double >::pmField = &VARIANT::dblVal; + +template<> +class CVarTypeInfo< double* > +{ +public: + static const VARTYPE VT = VT_R8|VT_BYREF; + static double* VARIANT::* const pmField; +}; + +__declspec( selectany ) double* VARIANT::* const CVarTypeInfo< double* >::pmField = &VARIANT::pdblVal; + +template<> +class CVarTypeInfo< VARIANT > +{ +public: + static const VARTYPE VT = VT_VARIANT; +}; + +template<> +class CVarTypeInfo< BSTR > +{ +public: + static const VARTYPE VT = VT_BSTR; + static BSTR VARIANT::* const pmField; +}; + +__declspec( selectany ) BSTR VARIANT::* const CVarTypeInfo< BSTR >::pmField = &VARIANT::bstrVal; + +template<> +class CVarTypeInfo< BSTR* > +{ +public: + static const VARTYPE VT = VT_BSTR|VT_BYREF; + static BSTR* VARIANT::* const pmField; +}; + +__declspec( selectany ) BSTR* VARIANT::* const CVarTypeInfo< BSTR* >::pmField = &VARIANT::pbstrVal; + +template<> +class CVarTypeInfo< IUnknown* > +{ +public: + static const VARTYPE VT = VT_UNKNOWN; + static IUnknown* VARIANT::* const pmField; +}; + +__declspec( selectany ) IUnknown* VARIANT::* const CVarTypeInfo< IUnknown* >::pmField = &VARIANT::punkVal; + +template<> +class CVarTypeInfo< IUnknown** > +{ +public: + static const VARTYPE VT = VT_UNKNOWN|VT_BYREF; + static IUnknown** VARIANT::* const pmField; +}; + +__declspec( selectany ) IUnknown** VARIANT::* const CVarTypeInfo< IUnknown** >::pmField = &VARIANT::ppunkVal; + +template<> +class CVarTypeInfo< IDispatch* > +{ +public: + static const VARTYPE VT = VT_DISPATCH; + static IDispatch* VARIANT::* const pmField; +}; + +__declspec( selectany ) IDispatch* VARIANT::* const CVarTypeInfo< IDispatch* >::pmField = &VARIANT::pdispVal; + +template<> +class CVarTypeInfo< IDispatch** > +{ +public: + static const VARTYPE VT = VT_DISPATCH|VT_BYREF; + static IDispatch** VARIANT::* const pmField; +}; + +__declspec( selectany ) IDispatch** VARIANT::* const CVarTypeInfo< IDispatch** >::pmField = &VARIANT::ppdispVal; + +template<> +class CVarTypeInfo< CY > +{ +public: + static const VARTYPE VT = VT_CY; + static CY VARIANT::* const pmField; +}; + +__declspec( selectany ) CY VARIANT::* const CVarTypeInfo< CY >::pmField = &VARIANT::cyVal; + +template<> +class CVarTypeInfo< CY* > +{ +public: + static const VARTYPE VT = VT_CY|VT_BYREF; + static CY* VARIANT::* const pmField; +}; + +__declspec( selectany ) CY* VARIANT::* const CVarTypeInfo< CY* >::pmField = &VARIANT::pcyVal; + +class CComVariant : public tagVARIANT +{ +// Constructors +public: + CComVariant() throw() + { + ::VariantInit(this); + } + ~CComVariant() throw() + { + Clear(); + } + + CComVariant(__in const VARIANT& varSrc) + { + vt = VT_EMPTY; + InternalCopy(&varSrc); + } + + CComVariant(__in const CComVariant& varSrc) + { + vt = VT_EMPTY; + InternalCopy(&varSrc); + } + CComVariant(__in LPCOLESTR lpszSrc) + { + vt = VT_EMPTY; + *this = lpszSrc; + } + + CComVariant(__in LPCSTR lpszSrc) + { + vt = VT_EMPTY; + *this = lpszSrc; + } + + CComVariant(__in bool bSrc) + { + vt = VT_BOOL; + boolVal = bSrc ? ATL_VARIANT_TRUE : ATL_VARIANT_FALSE; + } + + CComVariant(__in int nSrc, __in VARTYPE vtSrc = VT_I4) throw() + { + ATLASSERT(vtSrc == VT_I4 || vtSrc == VT_INT); + vt = vtSrc; + intVal = nSrc; + } + CComVariant(__in BYTE nSrc) throw() + { + vt = VT_UI1; + bVal = nSrc; + } + CComVariant(__in short nSrc) throw() + { + vt = VT_I2; + iVal = nSrc; + } + CComVariant(__in long nSrc, __in VARTYPE vtSrc = VT_I4) throw() + { + ATLASSERT(vtSrc == VT_I4 || vtSrc == VT_ERROR); + vt = vtSrc; + lVal = nSrc; + } + CComVariant(__in float fltSrc) throw() + { + vt = VT_R4; + fltVal = fltSrc; + } + CComVariant(__in double dblSrc, __in VARTYPE vtSrc = VT_R8) throw() + { + ATLASSERT(vtSrc == VT_R8 || vtSrc == VT_DATE); + vt = vtSrc; + dblVal = dblSrc; + } +#if (_WIN32_WINNT >= 0x0501) || defined(_ATL_SUPPORT_VT_I8) + CComVariant(__in LONGLONG nSrc) throw() + { + vt = VT_I8; + llVal = nSrc; + } + CComVariant(__in ULONGLONG nSrc) throw() + { + vt = VT_UI8; + ullVal = nSrc; + } +#endif + CComVariant(CY __in cySrc) throw() + { + vt = VT_CY; + cyVal.Hi = cySrc.Hi; + cyVal.Lo = cySrc.Lo; + } + CComVariant(__in_opt IDispatch* pSrc) throw() + { + vt = VT_DISPATCH; + pdispVal = pSrc; + // Need to AddRef as VariantClear will Release + if (pdispVal != NULL) + pdispVal->AddRef(); + } + CComVariant(__in_opt IUnknown* pSrc) throw() + { + vt = VT_UNKNOWN; + punkVal = pSrc; + // Need to AddRef as VariantClear will Release + if (punkVal != NULL) + punkVal->AddRef(); + } + CComVariant(__in char cSrc) throw() + { + vt = VT_I1; + cVal = cSrc; + } + CComVariant(__in unsigned short nSrc) throw() + { + vt = VT_UI2; + uiVal = nSrc; + } + CComVariant(__in unsigned long nSrc) throw() + { + vt = VT_UI4; + ulVal = nSrc; + } + CComVariant(__in unsigned int nSrc, __in VARTYPE vtSrc = VT_UI4) throw() + { + ATLASSERT(vtSrc == VT_UI4 || vtSrc == VT_UINT); + vt = vtSrc; + uintVal= nSrc; + } + CComVariant(__in const CComBSTR& bstrSrc) + { + vt = VT_EMPTY; + *this = bstrSrc; + } + CComVariant(__in_opt const SAFEARRAY *pSrc) + { + LPSAFEARRAY pCopy; + if (pSrc != NULL) + { + HRESULT hRes = ::SafeArrayCopy((LPSAFEARRAY)pSrc, &pCopy); + if (SUCCEEDED(hRes) && pCopy != NULL) + { + ::ATL::AtlSafeArrayGetActualVartype((LPSAFEARRAY)pSrc, &vt); + vt |= VT_ARRAY; + parray = pCopy; + } + else + { + vt = VT_ERROR; + scode = hRes; +#ifndef _ATL_NO_VARIANT_THROW + ATLENSURE_THROW(FALSE, E_OUTOFMEMORY); +#endif + } + } + else + { + vt = VT_EMPTY; + } + } +// Assignment Operators +public: + CComVariant& operator=(__in const CComVariant& varSrc) + { + if(this!=&varSrc) + { + InternalCopy(&varSrc); + } + return *this; + } + CComVariant& operator=(__in const VARIANT& varSrc) + { + if(static_cast(this)!=&varSrc) + { + InternalCopy(&varSrc); + } + return *this; + } + + CComVariant& operator=(__in const CComBSTR& bstrSrc) + { + Clear(); + vt = VT_BSTR; + bstrVal = bstrSrc.Copy(); +#pragma warning(push) +#pragma warning(disable:4068) +#pragma prefast(push) +#pragma prefast(disable:325, "We are checking allocation semantics here") + if (bstrVal == NULL && bstrSrc.m_str != NULL) + { + vt = VT_ERROR; + scode = E_OUTOFMEMORY; +#ifndef _ATL_NO_VARIANT_THROW + ATLENSURE_THROW(FALSE, E_OUTOFMEMORY); +#endif + } +#pragma prefast(pop) +#pragma warning(pop) + return *this; + } + + CComVariant& operator=(__in LPCOLESTR lpszSrc) + { + Clear(); + vt = VT_BSTR; + bstrVal = ::SysAllocString(lpszSrc); + + if (bstrVal == NULL && lpszSrc != NULL) + { + vt = VT_ERROR; + scode = E_OUTOFMEMORY; +#ifndef _ATL_NO_VARIANT_THROW + ATLENSURE_THROW(FALSE, E_OUTOFMEMORY); +#endif + + } + return *this; + } + + CComVariant& operator=(__in LPCSTR lpszSrc) + { + USES_CONVERSION_EX; + Clear(); + vt = VT_BSTR; + bstrVal = ::SysAllocString(A2COLE_EX(lpszSrc, _ATL_SAFE_ALLOCA_DEF_THRESHOLD)); + + if (bstrVal == NULL && lpszSrc != NULL) + { + vt = VT_ERROR; + scode = E_OUTOFMEMORY; +#ifndef _ATL_NO_VARIANT_THROW + ATLENSURE_THROW(FALSE, E_OUTOFMEMORY); +#endif + } + return *this; + } + + CComVariant& operator=(__in bool bSrc) + { + if (vt != VT_BOOL) + { + Clear(); + vt = VT_BOOL; + } + boolVal = bSrc ? ATL_VARIANT_TRUE : ATL_VARIANT_FALSE; + return *this; + } + + CComVariant& operator=(__in int nSrc) throw() + { + if (vt != VT_I4) + { + Clear(); + vt = VT_I4; + } + intVal = nSrc; + + return *this; + } + + CComVariant& operator=(__in BYTE nSrc) throw() + { + if (vt != VT_UI1) + { + Clear(); + vt = VT_UI1; + } + bVal = nSrc; + return *this; + } + + CComVariant& operator=(__in short nSrc) throw() + { + if (vt != VT_I2) + { + Clear(); + vt = VT_I2; + } + iVal = nSrc; + return *this; + } + + CComVariant& operator=(__in long nSrc) throw() + { + if (vt != VT_I4) + { + Clear(); + vt = VT_I4; + } + lVal = nSrc; + return *this; + } + + CComVariant& operator=(__in float fltSrc) throw() + { + if (vt != VT_R4) + { + Clear(); + vt = VT_R4; + } + fltVal = fltSrc; + return *this; + } + + CComVariant& operator=(__in double dblSrc) throw() + { + if (vt != VT_R8) + { + Clear(); + vt = VT_R8; + } + dblVal = dblSrc; + return *this; + } + + CComVariant& operator=(__in CY cySrc) throw() + { + if (vt != VT_CY) + { + Clear(); + vt = VT_CY; + } + cyVal.Hi = cySrc.Hi; + cyVal.Lo = cySrc.Lo; + return *this; + } + + CComVariant& operator=(__in_opt IDispatch* pSrc) throw() + { + Clear(); + vt = VT_DISPATCH; + pdispVal = pSrc; + // Need to AddRef as VariantClear will Release + if (pdispVal != NULL) + pdispVal->AddRef(); + return *this; + } + + CComVariant& operator=(__in_opt IUnknown* pSrc) throw() + { + Clear(); + vt = VT_UNKNOWN; + punkVal = pSrc; + + // Need to AddRef as VariantClear will Release + if (punkVal != NULL) + punkVal->AddRef(); + return *this; + } + + CComVariant& operator=(__in char cSrc) throw() + { + if (vt != VT_I1) + { + Clear(); + vt = VT_I1; + } + cVal = cSrc; + return *this; + } + + CComVariant& operator=(__in unsigned short nSrc) throw() + { + if (vt != VT_UI2) + { + Clear(); + vt = VT_UI2; + } + uiVal = nSrc; + return *this; + } + + CComVariant& operator=(__in unsigned long nSrc) throw() + { + if (vt != VT_UI4) + { + Clear(); + vt = VT_UI4; + } + ulVal = nSrc; + return *this; + } + + CComVariant& operator=(__in unsigned int nSrc) throw() + { + if (vt != VT_UI4) + { + Clear(); + vt = VT_UI4; + } + uintVal= nSrc; + return *this; + } + + CComVariant& operator=(__in_opt BYTE* pbSrc) throw() + { + if (vt != (VT_UI1|VT_BYREF)) + { + Clear(); + vt = VT_UI1|VT_BYREF; + } + pbVal = pbSrc; + return *this; + } + + CComVariant& operator=(__in_opt short* pnSrc) throw() + { + if (vt != (VT_I2|VT_BYREF)) + { + Clear(); + vt = VT_I2|VT_BYREF; + } + piVal = pnSrc; + return *this; + } + +#ifdef _NATIVE_WCHAR_T_DEFINED + CComVariant& operator=(__in_opt USHORT* pnSrc) throw() + { + if (vt != (VT_UI2|VT_BYREF)) + { + Clear(); + vt = VT_UI2|VT_BYREF; + } + puiVal = pnSrc; + return *this; + } +#endif + + CComVariant& operator=(__in_opt int* pnSrc) throw() + { + if (vt != (VT_I4|VT_BYREF)) + { + Clear(); + vt = VT_I4|VT_BYREF; + } + pintVal = pnSrc; + return *this; + } + + CComVariant& operator=(__in_opt UINT* pnSrc) throw() + { + if (vt != (VT_UI4|VT_BYREF)) + { + Clear(); + vt = VT_UI4|VT_BYREF; + } + puintVal = pnSrc; + return *this; + } + + CComVariant& operator=(__in_opt long* pnSrc) throw() + { + if (vt != (VT_I4|VT_BYREF)) + { + Clear(); + vt = VT_I4|VT_BYREF; + } + plVal = pnSrc; + return *this; + } + + CComVariant& operator=(__in_opt ULONG* pnSrc) throw() + { + if (vt != (VT_UI4|VT_BYREF)) + { + Clear(); + vt = VT_UI4|VT_BYREF; + } + pulVal = pnSrc; + return *this; + } + +#if (_WIN32_WINNT >= 0x0501) || defined(_ATL_SUPPORT_VT_I8) + CComVariant& operator=(__in LONGLONG nSrc) throw() + { + if (vt != VT_I8) + { + Clear(); + vt = VT_I8; + } + llVal = nSrc; + + return *this; + } + + CComVariant& operator=(__in_opt LONGLONG* pnSrc) throw() + { + if (vt != (VT_I8|VT_BYREF)) + { + Clear(); + vt = VT_I8|VT_BYREF; + } + pllVal = pnSrc; + return *this; + } + + CComVariant& operator=(__in ULONGLONG nSrc) throw() + { + if (vt != VT_UI8) + { + Clear(); + vt = VT_UI8; + } + ullVal = nSrc; + + return *this; + } + + CComVariant& operator=(__in_opt ULONGLONG* pnSrc) throw() + { + if (vt != (VT_UI8|VT_BYREF)) + { + Clear(); + vt = VT_UI8|VT_BYREF; + } + pullVal = pnSrc; + return *this; + } +#endif + +#pragma warning(push) +#pragma warning(disable: 28110) + + CComVariant& operator=(__in_opt float* pfSrc) throw() + { + if (vt != (VT_R4|VT_BYREF)) + { + Clear(); + vt = VT_R4|VT_BYREF; + } + pfltVal = pfSrc; + return *this; + } + + CComVariant& operator=(__in_opt double* pfSrc) throw() + { + if (vt != (VT_R8|VT_BYREF)) + { + Clear(); + vt = VT_R8|VT_BYREF; + } + pdblVal = pfSrc; + return *this; + } + +#pragma warning(pop) + + CComVariant& operator=(__in_opt const SAFEARRAY *pSrc) + { + Clear(); + LPSAFEARRAY pCopy; + if (pSrc != NULL) + { + HRESULT hRes = ::SafeArrayCopy((LPSAFEARRAY)pSrc, &pCopy); + if (SUCCEEDED(hRes) && pCopy != NULL) + { + ::ATL::AtlSafeArrayGetActualVartype((LPSAFEARRAY)pSrc, &vt); + vt |= VT_ARRAY; + parray = pCopy; + } + else + { + vt = VT_ERROR; + scode = hRes; +#ifndef _ATL_NO_VARIANT_THROW + ATLENSURE_THROW(FALSE, E_OUTOFMEMORY); +#endif + } + } + return *this; + } + +// Comparison Operators +public: + bool operator==(__in const VARIANT& varSrc) const throw() + { + // For backwards compatibility + if (vt == VT_NULL && varSrc.vt == VT_NULL) + { + return true; + } + // Variants not equal if types don't match + if (vt != varSrc.vt) + { + return false; + } + return VarCmp((VARIANT*)this, (VARIANT*)&varSrc, LOCALE_USER_DEFAULT, 0) == static_cast(VARCMP_EQ); + } + + bool operator!=(__in const VARIANT& varSrc) const throw() + { + return !operator==(varSrc); + } + + bool operator<(__in const VARIANT& varSrc) const throw() + { + if (vt == VT_NULL && varSrc.vt == VT_NULL) + return false; + return VarCmp((VARIANT*)this, (VARIANT*)&varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_LT); + } + + bool operator>(__in const VARIANT& varSrc) const throw() + { + if (vt == VT_NULL && varSrc.vt == VT_NULL) + return false; + return VarCmp((VARIANT*)this, (VARIANT*)&varSrc, LOCALE_USER_DEFAULT, 0)== static_cast(VARCMP_GT); + } + +// Operations +public: + HRESULT Clear() { return ::VariantClear(this); } + HRESULT ClearToZero() + { + HRESULT hr = ::VariantClear(this); + if( FAILED(hr) ) + { + return hr; + } + memset(this ,0 ,sizeof(tagVARIANT)); + vt = VT_EMPTY; + return hr; + } + + HRESULT Copy(__in const VARIANT* pSrc) { return ::VariantCopy(this, const_cast(pSrc)); } + // copy VARIANT to BSTR + HRESULT CopyTo(__out BSTR *pstrDest) + { + ATLASSERT(pstrDest != NULL && vt == VT_BSTR); + HRESULT hRes = E_POINTER; + if (pstrDest != NULL && vt == VT_BSTR) + { + *pstrDest = ::SysAllocStringByteLen((char*)bstrVal, ::SysStringByteLen(bstrVal)); + if (*pstrDest == NULL) + hRes = E_OUTOFMEMORY; + else + hRes = S_OK; + } + else if (vt != VT_BSTR) + hRes = DISP_E_TYPEMISMATCH; + return hRes; + } + HRESULT Attach(__in VARIANT* pSrc) + { + if(pSrc == NULL) + return E_INVALIDARG; + + // Clear out the variant + HRESULT hr = Clear(); + if (!FAILED(hr)) + { + // Copy the contents and give control to CComVariant + Checked::memcpy_s(this, sizeof(CComVariant), pSrc, sizeof(VARIANT)); + pSrc->vt = VT_EMPTY; + hr = S_OK; + } + return hr; + } + + HRESULT Detach(__out VARIANT* pDest) + { + ATLASSERT(pDest != NULL); + if(pDest == NULL) + return E_POINTER; + + // Clear out the variant + HRESULT hr = ::VariantClear(pDest); + if (!FAILED(hr)) + { + // Copy the contents and remove control from CComVariant + Checked::memcpy_s(pDest, sizeof(VARIANT), this, sizeof(VARIANT)); + vt = VT_EMPTY; + hr = S_OK; + } + return hr; + } + + HRESULT ChangeType(__in VARTYPE vtNew, __in_opt const VARIANT* pSrc = NULL) + { + VARIANT* pVar = const_cast(pSrc); + // Convert in place if pSrc is NULL + if (pVar == NULL) + pVar = this; + // Do nothing if doing in place convert and vts not different + return ::VariantChangeType(this, pVar, 0, vtNew); + } + + template< typename T > + void SetByRef( __in T* pT ) throw() + { + Clear(); + vt = CVarTypeInfo< T >::VT|VT_BYREF; + byref = pT; + } + + HRESULT WriteToStream(__inout IStream* pStream); + HRESULT WriteToStream(__inout IStream* pStream, VARTYPE vtWrite) + { + if (vtWrite != VT_EMPTY && vtWrite != vt) + { + CComVariant varConv; + HRESULT hr = varConv.ChangeType(vtWrite, this); + if (FAILED(hr)) + { + return hr; + } + return varConv.WriteToStream(pStream); + } + return WriteToStream(pStream); + } + HRESULT ReadFromStream(__inout IStream* pStream, VARTYPE vtExpected = VT_EMPTY); + + // Return the size in bytes of the current contents + ULONG GetSize() const; + +// Implementation +public: + HRESULT InternalClear() + { + HRESULT hr = Clear(); + ATLASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) + { + vt = VT_ERROR; + scode = hr; +#ifndef _ATL_NO_VARIANT_THROW + AtlThrow(hr); +#endif + } + return hr; + } + + void InternalCopy(__in const VARIANT* pSrc) + { + HRESULT hr = Copy(pSrc); + if (FAILED(hr)) + { + vt = VT_ERROR; + scode = hr; +#ifndef _ATL_NO_VARIANT_THROW + AtlThrow(hr); +#endif + } + } +}; + +#pragma warning(push) +#pragma warning(disable: 4702) +inline HRESULT CComVariant::WriteToStream(__inout IStream* pStream) +{ + if(pStream == NULL) + return E_INVALIDARG; + + HRESULT hr = pStream->Write(&vt, sizeof(VARTYPE), NULL); + if (FAILED(hr)) + return hr; + + int cbWrite = 0; + switch (vt) + { + case VT_UNKNOWN: + case VT_DISPATCH: + { + CComPtr spStream; + if (punkVal != NULL) + { + hr = punkVal->QueryInterface(__uuidof(IPersistStream), (void**)&spStream); + if (FAILED(hr)) + { + hr = punkVal->QueryInterface(__uuidof(IPersistStreamInit), (void**)&spStream); + if (FAILED(hr)) + return hr; + } + } + if (spStream != NULL) + return OleSaveToStream(spStream, pStream); + return WriteClassStm(pStream, CLSID_NULL); + } + case VT_UI1: + case VT_I1: + cbWrite = sizeof(BYTE); + break; + case VT_I2: + case VT_UI2: + case VT_BOOL: + cbWrite = sizeof(short); + break; + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_INT: + case VT_UINT: + case VT_ERROR: + cbWrite = sizeof(long); + break; + case VT_I8: + case VT_UI8: + cbWrite = sizeof(LONGLONG); + break; + case VT_R8: + case VT_CY: + case VT_DATE: + cbWrite = sizeof(double); + break; + default: + break; + } + if (cbWrite != 0) + return pStream->Write((void*) &bVal, cbWrite, NULL); + + CComBSTR bstrWrite; + CComVariant varBSTR; + if (vt != VT_BSTR) + { + hr = VariantChangeType(&varBSTR, this, VARIANT_NOVALUEPROP, VT_BSTR); + if (FAILED(hr)) + return hr; + bstrWrite.Attach(varBSTR.bstrVal); + } + else + bstrWrite.Attach(bstrVal); + + hr = bstrWrite.WriteToStream(pStream); + bstrWrite.Detach(); + return hr; +} +#pragma warning(pop) // C4702 + +inline HRESULT CComVariant::ReadFromStream(__inout IStream* pStream, VARTYPE vtExpected /* = VT_EMPTY */ ) +{ + ATLASSERT(pStream != NULL); + if(pStream == NULL) + return E_INVALIDARG; + + HRESULT hr; + hr = VariantClear(this); + if (FAILED(hr)) + return hr; + VARTYPE vtRead = VT_EMPTY; + ULONG cbRead = 0; + hr = pStream->Read(&vtRead, sizeof(VARTYPE), &cbRead); + if (hr == S_FALSE || (cbRead != sizeof(VARTYPE) && hr == S_OK)) + hr = E_FAIL; + if (FAILED(hr)) + return hr; + if (vtExpected != VT_EMPTY && vtRead != vtExpected) + return E_FAIL; + + vt = vtRead; + cbRead = 0; + switch (vtRead) + { + case VT_UNKNOWN: + case VT_DISPATCH: + { + punkVal = NULL; + hr = OleLoadFromStream(pStream, + (vtRead == VT_UNKNOWN) ? __uuidof(IUnknown) : __uuidof(IDispatch), + (void**)&punkVal); + // If IPictureDisp or IFontDisp property is not set, + // OleLoadFromStream() will return REGDB_E_CLASSNOTREG. + if (hr == REGDB_E_CLASSNOTREG) + hr = S_OK; + return hr; + } + case VT_UI1: + case VT_I1: + cbRead = sizeof(BYTE); + break; + case VT_I2: + case VT_UI2: + case VT_BOOL: + cbRead = sizeof(short); + break; + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_INT: + case VT_UINT: + case VT_ERROR: + cbRead = sizeof(long); + break; + case VT_I8: + case VT_UI8: + cbRead = sizeof(LONGLONG); + break; + case VT_R8: + case VT_CY: + case VT_DATE: + cbRead = sizeof(double); + break; + default: + break; + } + if (cbRead != 0) + { + hr = pStream->Read((void*) &bVal, cbRead, NULL); + if (hr == S_FALSE) + hr = E_FAIL; + return hr; + } + CComBSTR bstrRead; + + hr = bstrRead.ReadFromStream(pStream); + if (FAILED(hr)) + { + // If CComBSTR::ReadFromStream failed, reset seek pointer to start of + // variant type. + LARGE_INTEGER nOffset; + nOffset.QuadPart = -(static_cast(sizeof(VARTYPE))); + pStream->Seek(nOffset, STREAM_SEEK_CUR, NULL); + vt = VT_EMPTY; + return hr; + } + vt = VT_BSTR; + bstrVal = bstrRead.Detach(); + if (vtRead != VT_BSTR) + hr = ChangeType(vtRead); + return hr; +} + +inline ULONG CComVariant::GetSize() const +{ + ULONG nSize = sizeof(VARTYPE); + HRESULT hr; + + switch (vt) + { + case VT_UNKNOWN: + case VT_DISPATCH: + { + CComPtr spStream; + if (punkVal != NULL) + { + hr = punkVal->QueryInterface(__uuidof(IPersistStream), (void**)&spStream); + if (FAILED(hr)) + { + hr = punkVal->QueryInterface(__uuidof(IPersistStreamInit), (void**)&spStream); + if (FAILED(hr)) + break; + } + } + if (spStream != NULL) + { + ULARGE_INTEGER nPersistSize; + nPersistSize.QuadPart = 0; + spStream->GetSizeMax(&nPersistSize); + nSize += nPersistSize.LowPart + sizeof(CLSID); + } + else + nSize += sizeof(CLSID); + } + break; + case VT_UI1: + case VT_I1: + nSize += sizeof(BYTE); + break; + case VT_I2: + case VT_UI2: + case VT_BOOL: + nSize += sizeof(short); + break; + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_INT: + case VT_UINT: + case VT_ERROR: + nSize += sizeof(long); + break; + case VT_I8: + case VT_UI8: + nSize += sizeof(LONGLONG); + break; + case VT_R8: + case VT_CY: + case VT_DATE: + nSize += sizeof(double); + break; + default: + break; + } + if (nSize == sizeof(VARTYPE)) + { + VARTYPE vtTmp = vt; + BSTR bstr = NULL; + CComVariant varBSTR; + if (vtTmp != VT_BSTR) + { + hr = VariantChangeType(&varBSTR, const_cast((const VARIANT*)this), VARIANT_NOVALUEPROP, VT_BSTR); + if (SUCCEEDED(hr)) + { + bstr = varBSTR.bstrVal; + vtTmp = VT_BSTR; + } + } else + { + bstr = bstrVal; + } + + if (vtTmp == VT_BSTR) + { + // Add the size of the length + string (in bytes) + NULL terminator. + nSize += CComBSTR::GetStreamSize(bstr); + } + } + return nSize; +} + +__checkReturn inline HRESULT CComPtr::Invoke2(__in DISPID dispid, __in VARIANT* pvarParam1, __in VARIANT* pvarParam2, __out_opt VARIANT* pvarRet) throw() +{ + if(pvarParam1 == NULL || pvarParam2 == NULL) + return E_INVALIDARG; + + CComVariant varArgs[2] = { *pvarParam2, *pvarParam1 }; + DISPPARAMS dispparams = { &varArgs[0], NULL, 2, 0}; + return p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &dispparams, pvarRet, NULL, NULL); +} + +} // namespace ATL +#pragma pack(pop) + +#pragma warning (pop) + +#ifndef _ATL_NO_AUTOMATIC_NAMESPACE +using namespace ATL; +#endif //!_ATL_NO_AUTOMATIC_NAMESPACE + +#endif // __ATLCOMCLI_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcommem.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcommem.h new file mode 100644 index 00000000..9b820809 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcommem.h @@ -0,0 +1,180 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCOMMEM_H__ +#define __ATLCOMMEM_H__ + +#pragma once + +#ifndef __ATLMEM_H__ + #error ATLComMem.h requires atlmem.h to be included first +#endif // __ATLMEM_H__ + +#include +#include + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ + +class CComHeap : + public IAtlMemMgr +{ +// IAtlMemMgr +public: + virtual void* Allocate( size_t nBytes ) throw() + { +#ifdef _WIN64 + if( nBytes > INT_MAX ) + { + return( NULL ); + } +#endif + return( ::CoTaskMemAlloc( ULONG( nBytes ) ) ); + } + virtual void Free( void* p ) throw() + { + ::CoTaskMemFree( p ); + } + virtual void* Reallocate( void* p, size_t nBytes ) throw() + { +#ifdef _WIN64 + if( nBytes > INT_MAX ) + { + return( NULL ); + } +#endif + return( ::CoTaskMemRealloc( p, ULONG( nBytes ) ) ); + } + virtual size_t GetSize( void* p ) throw() + { + CComPtr< IMalloc > pMalloc; + + HRESULT hr = ::CoGetMalloc( 1, &pMalloc ); + if (FAILED(hr)) + return 0; + + return( pMalloc->GetSize( p ) ); + } +}; + +///////////////////////////////////////////////////////////////////////////// +// OLE task memory allocation support + +inline LPWSTR AtlAllocTaskWideString(LPCWSTR lpszString) throw() +{ + if (lpszString == NULL) + { + return NULL; + } + UINT nSize = (UINT)((wcslen(lpszString)+1) * sizeof(WCHAR)); + LPWSTR lpszResult = (LPWSTR)CoTaskMemAlloc(nSize); +#if _SECURE_ATL + if (lpszResult == NULL) + { + return NULL; + } + + if(0 != memcpy_s(lpszResult, nSize, lpszString, nSize)) + { + CoTaskMemFree(lpszResult); + return NULL; + } +#else + if (lpszResult != NULL) + memcpy(lpszResult, lpszString, nSize); +#endif + + return lpszResult; +} + +inline LPWSTR AtlAllocTaskWideString(LPCSTR lpszString) throw() +{ + if (lpszString == NULL) + return NULL; + UINT nLen = 0; + + if (FAILED(UIntAdd(lstrlenA(lpszString), 1, &nLen))) + { + return NULL; + } + + LPWSTR lpszResult = (LPWSTR)::ATL::AtlCoTaskMemCAlloc(nLen, static_cast(sizeof(WCHAR))); + if (lpszResult != NULL) + { + int nRet = MultiByteToWideChar(CP_ACP, 0, lpszString, -1, lpszResult, nLen); + ATLASSERT(nRet != 0); + if (nRet == 0) + { + CoTaskMemFree(lpszResult); + lpszResult = NULL; + } + } + return lpszResult; +} + +inline LPSTR AtlAllocTaskAnsiString(LPCWSTR lpszString) throw() +{ + if (lpszString == NULL) + return NULL; + UINT nBytes = (UINT)((wcslen(lpszString)+1)*2); + LPSTR lpszResult = (LPSTR)CoTaskMemAlloc(nBytes); + if (lpszResult != NULL) + { + int nRet = WideCharToMultiByte(CP_ACP, 0, lpszString, -1, lpszResult, nBytes, NULL, NULL); + ATLASSERT(nRet != 0); + if (nRet == 0) + { + CoTaskMemFree(lpszResult); + lpszResult = NULL; + } + } + return lpszResult; +} + +inline LPSTR AtlAllocTaskAnsiString(LPCSTR lpszString) throw() +{ + if (lpszString == NULL) + { + return NULL; + } + UINT nSize = lstrlenA(lpszString)+1; + LPSTR lpszResult = (LPSTR)CoTaskMemAlloc(nSize); +#if _SECURE_ATL + if (lpszResult == NULL) + { + return NULL; + } + + if(0 != memcpy_s(lpszResult, nSize, lpszString, nSize)) + { + CoTaskMemFree(lpszResult); + return NULL; + } +#else + if (lpszResult != NULL) + memcpy(lpszResult, lpszString, nSize); +#endif + return lpszResult; +} + +#ifdef _UNICODE + #define AtlAllocTaskString(x) AtlAllocTaskWideString(x) +#else + #define AtlAllocTaskString(x) AtlAllocTaskAnsiString(x) +#endif + +#define AtlAllocTaskOleString(x) AtlAllocTaskWideString(x) + +} // namespace ATL +#pragma pack(pop) + +#endif // __ATLCOMMEM_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcomtime.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcomtime.h new file mode 100644 index 00000000..8e2e9b14 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcomtime.h @@ -0,0 +1,417 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCOMTIME_H__ +#define __ATLCOMTIME_H__ + +#pragma once + +#pragma warning(push) +#pragma warning(disable:4159) + +#if defined(_M_IX86) +#pragma pack(push, 4) +#else +#pragma pack(push, ATL_PACKING) +#endif + +#include +struct tagVARIANT; +typedef tagVARIANT VARIANT; + +typedef double DATE; + + + +namespace ATL +{ + +class COleDateTimeSpan +{ +// Constructors +public: + COleDateTimeSpan() throw(); + + COleDateTimeSpan(double dblSpanSrc) throw(); + COleDateTimeSpan(LONG lDays, int nHours, int nMins, int nSecs) throw(); + +// Attributes + enum DateTimeSpanStatus + { + valid = 0, + invalid = 1, // Invalid span (out of range, etc.) + null = 2, // Literally has no value + }; + + double m_span; + DateTimeSpanStatus m_status; + + void SetStatus(DateTimeSpanStatus status) throw(); + DateTimeSpanStatus GetStatus() const throw(); + + double GetTotalDays() const throw(); // span in days (about -3.65e6 to 3.65e6) + double GetTotalHours() const throw(); // span in hours (about -8.77e7 to 8.77e6) + double GetTotalMinutes() const throw(); // span in minutes (about -5.26e9 to 5.26e9) + double GetTotalSeconds() const throw(); // span in seconds (about -3.16e11 to 3.16e11) + + LONG GetDays() const throw(); // component days in span + LONG GetHours() const throw(); // component hours in span (-23 to 23) + LONG GetMinutes() const throw(); // component minutes in span (-59 to 59) + LONG GetSeconds() const throw(); // component seconds in span (-59 to 59) + +// Operations + COleDateTimeSpan& operator=(double dblSpanSrc) throw(); + + bool operator==(const COleDateTimeSpan& dateSpan) const throw(); + bool operator!=(const COleDateTimeSpan& dateSpan) const throw(); + bool operator<(const COleDateTimeSpan& dateSpan) const throw(); + bool operator>(const COleDateTimeSpan& dateSpan) const throw(); + bool operator<=(const COleDateTimeSpan& dateSpan) const throw(); + bool operator>=(const COleDateTimeSpan& dateSpan) const throw(); + + // DateTimeSpan math + COleDateTimeSpan operator+(const COleDateTimeSpan& dateSpan) const throw(); + COleDateTimeSpan operator-(const COleDateTimeSpan& dateSpan) const throw(); + COleDateTimeSpan& operator+=(const COleDateTimeSpan dateSpan) throw(); + COleDateTimeSpan& operator-=(const COleDateTimeSpan dateSpan) throw(); + COleDateTimeSpan operator-() const throw(); + + operator double() const throw(); + + void SetDateTimeSpan(LONG lDays, int nHours, int nMins, int nSecs) throw(); + +#ifndef _ATL_MIN_CRT + // formatting + CString Format(LPCTSTR pFormat) const; + CString Format(UINT nID) const; +#endif + +// Implementation + void CheckRange(); + +private: + static const double OLE_DATETIME_HALFSECOND; +}; + +class COleDateTime +{ +// Constructors +public: + static COleDateTime WINAPI GetCurrentTime() throw(); + + COleDateTime() throw(); + + COleDateTime(const VARIANT& varSrc) throw(); + COleDateTime(DATE dtSrc) throw(); + + COleDateTime(__time32_t timeSrc) throw(); + COleDateTime(__time64_t timeSrc) throw(); + + COleDateTime(const SYSTEMTIME& systimeSrc) throw(); + COleDateTime(const FILETIME& filetimeSrc) throw(); + + COleDateTime(int nYear, int nMonth, int nDay, + int nHour, int nMin, int nSec) throw(); + COleDateTime(WORD wDosDate, WORD wDosTime) throw(); + +#ifdef __oledb_h__ + COleDateTime( const DBTIMESTAMP& dbts) throw(); + bool GetAsDBTIMESTAMP( DBTIMESTAMP& dbts ) const throw(); +#endif + +// Attributes + enum DateTimeStatus + { + error = -1, + valid = 0, + invalid = 1, // Invalid date (out of range, etc.) + null = 2, // Literally has no value + }; + + DATE m_dt; + DateTimeStatus m_status; + + void SetStatus(DateTimeStatus status) throw(); + DateTimeStatus GetStatus() const throw(); + + bool GetAsSystemTime(SYSTEMTIME& sysTime) const throw(); + bool GetAsUDATE( UDATE& udate ) const throw(); + + int GetYear() const throw(); + // Month of year (1 = January) + int GetMonth() const throw(); + // Day of month (1-31) + int GetDay() const throw(); + // Hour in day (0-23) + int GetHour() const throw(); + // Minute in hour (0-59) + int GetMinute() const throw(); + // Second in minute (0-59) + int GetSecond() const throw(); + // Day of week (1 = Sunday, 2 = Monday, ..., 7 = Saturday) + int GetDayOfWeek() const throw(); + // Days since start of year (1 = January 1) + int GetDayOfYear() const throw(); + +// Operations + COleDateTime& operator=(const VARIANT& varSrc) throw(); + COleDateTime& operator=(DATE dtSrc) throw(); + + COleDateTime& operator=(const __time32_t& timeSrc) throw(); + COleDateTime& operator=(const __time64_t& timeSrc) throw(); + + COleDateTime& operator=(const SYSTEMTIME& systimeSrc) throw(); + COleDateTime& operator=(const FILETIME& filetimeSrc) throw(); + COleDateTime& operator=(const UDATE& udate) throw(); + + bool operator==(const COleDateTime& date) const throw(); + bool operator!=(const COleDateTime& date) const throw(); + bool operator<(const COleDateTime& date) const throw(); + bool operator>(const COleDateTime& date) const throw(); + bool operator<=(const COleDateTime& date) const throw(); + bool operator>=(const COleDateTime& date) const throw(); + + // DateTime math + COleDateTime operator+(COleDateTimeSpan dateSpan) const throw(); + COleDateTime operator-(COleDateTimeSpan dateSpan) const throw(); + COleDateTime& operator+=(COleDateTimeSpan dateSpan) throw(); + COleDateTime& operator-=(COleDateTimeSpan dateSpan) throw(); + + // DateTimeSpan math + COleDateTimeSpan operator-(const COleDateTime& date) const throw(); + + operator DATE() const throw(); + + int SetDateTime(int nYear, int nMonth, int nDay, + int nHour, int nMin, int nSec) throw(); + int SetDate(int nYear, int nMonth, int nDay) throw(); + int SetTime(int nHour, int nMin, int nSec) throw(); + bool ParseDateTime(LPCTSTR lpszDate, DWORD dwFlags = 0, + LCID lcid = LANG_USER_DEFAULT) throw(); + +#ifndef _ATL_MIN_CRT + // formatting + CString Format(DWORD dwFlags = 0, LCID lcid = LANG_USER_DEFAULT) const; + CString Format(LPCTSTR lpszFormat) const; + CString Format(UINT nFormatID) const; +#endif + +protected: + static double WINAPI DoubleFromDate( DATE date ) throw(); + static DATE WINAPI DateFromDouble( double f ) throw(); + + void CheckRange(); + BOOL ConvertSystemTimeToVariantTime(const SYSTEMTIME& systimeSrc); +}; + +} // namespace ATL + + + + +#ifndef _DEBUG +#define ATLCOMTIME_INLINE inline +#include +#endif + + + +namespace ATL +{ + +inline bool COleDateTime::ParseDateTime(LPCTSTR lpszDate, DWORD dwFlags, LCID lcid) throw() +{ + USES_CONVERSION_EX; + LPCTSTR pszDate = ( lpszDate == NULL ) ? _T("") : lpszDate; + + HRESULT hr; + LPOLESTR p = T2OLE_EX((LPTSTR)pszDate, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); +#ifndef _UNICODE + if( p == NULL ) + { + m_dt = 0; + m_status = invalid; + return false; + } +#endif // _UNICODE + + if (FAILED(hr = VarDateFromStr( p, lcid, dwFlags, &m_dt ))) + { + if (hr == DISP_E_TYPEMISMATCH) + { + // Can't convert string to date, set 0 and invalidate + m_dt = 0; + m_status = invalid; + return false; + } + else if (hr == DISP_E_OVERFLOW) + { + // Can't convert string to date, set -1 and invalidate + m_dt = -1; + m_status = invalid; + return false; + } + else + { + ATLTRACE(atlTraceTime, 0, _T("\nCOleDateTime VarDateFromStr call failed.\n\t")); + // Can't convert string to date, set -1 and invalidate + m_dt = -1; + m_status = invalid; + return false; + } + } + + m_status = valid; + return true; +} + +#ifndef _ATL_MIN_CRT +inline CString COleDateTimeSpan::Format(LPCTSTR pFormat) const +{ + // If null, return empty string + if (GetStatus() == null) + return _T(""); + + CTimeSpan tmp(GetDays(), GetHours(), GetMinutes(), GetSeconds()); + return tmp.Format(pFormat); +} + +inline CString COleDateTimeSpan::Format(UINT nFormatID) const +{ + CString strFormat; + if (!strFormat.LoadString(nFormatID)) + AtlThrow(E_INVALIDARG); + return Format(strFormat); +} +#endif // !_ATL_MIN_CRT + +#ifndef _ATL_MIN_CRT +inline CString COleDateTime::Format(DWORD dwFlags, LCID lcid) const +{ + // If null, return empty string + if (GetStatus() == null) + return _T(""); + + // If invalid, return DateTime global string + if (GetStatus() == invalid) + { + CString str; + if(str.LoadString(ATL_IDS_DATETIME_INVALID)) + return str; + return szInvalidDateTime; + } + + CComBSTR bstr; + if (FAILED(::VarBstrFromDate(m_dt, lcid, dwFlags, &bstr))) + { + CString str; + if(str.LoadString(ATL_IDS_DATETIME_INVALID)) + return str; + return szInvalidDateTime; + } + + CString tmp = CString(bstr); + return tmp; +} + +inline CString COleDateTime::Format(LPCTSTR pFormat) const +{ + ATLENSURE_THROW(pFormat != NULL, E_INVALIDARG); + + // If null, return empty string + if(GetStatus() == null) + return _T(""); + + // If invalid, return DateTime global string + if(GetStatus() == invalid) + { + CString str; + if(str.LoadString(ATL_IDS_DATETIME_INVALID)) + return str; + return szInvalidDateTime; + } + + UDATE ud; + if (S_OK != VarUdateFromDate(m_dt, 0, &ud)) + { + CString str; + if(str.LoadString(ATL_IDS_DATETIME_INVALID)) + return str; + return szInvalidDateTime; + } + + struct tm tmTemp; + tmTemp.tm_sec = ud.st.wSecond; + tmTemp.tm_min = ud.st.wMinute; + tmTemp.tm_hour = ud.st.wHour; + tmTemp.tm_mday = ud.st.wDay; + tmTemp.tm_mon = ud.st.wMonth - 1; + tmTemp.tm_year = ud.st.wYear - 1900; + tmTemp.tm_wday = ud.st.wDayOfWeek; + tmTemp.tm_yday = ud.wDayOfYear - 1; + tmTemp.tm_isdst = 0; + + CString strDate; + LPTSTR lpszTemp = strDate.GetBufferSetLength(256); + _tcsftime(lpszTemp, strDate.GetLength(), pFormat, &tmTemp); + strDate.ReleaseBuffer(); + + return strDate; +} + +inline CString COleDateTime::Format(UINT nFormatID) const +{ + CString strFormat; + ATLENSURE(strFormat.LoadString(nFormatID)); + return Format(strFormat); +} +#endif // !_ATL_MIN_CRT + +#ifdef __oledb_h__ +inline COleDateTime::COleDateTime(const DBTIMESTAMP& dbts) +{ + SYSTEMTIME st; + ::ZeroMemory(&st, sizeof(SYSTEMTIME)); + + st.wYear = WORD(dbts.year); + st.wMonth = WORD(dbts.month); + st.wDay = WORD(dbts.day); + st.wHour = WORD(dbts.hour); + st.wMinute = WORD(dbts.minute); + st.wSecond = WORD(dbts.second); + + m_status = ::SystemTimeToVariantTime(&st, &m_dt) ? valid : invalid; +} + +inline bool COleDateTime::GetAsDBTIMESTAMP(DBTIMESTAMP& dbts) const +{ + UDATE ud; + if (S_OK != VarUdateFromDate(m_dt, 0, &ud)) + return false; + + dbts.year = (SHORT) ud.st.wYear; + dbts.month = (USHORT) ud.st.wMonth; + dbts.day = (USHORT) ud.st.wDay; + dbts.hour = (USHORT) ud.st.wHour; + dbts.minute = (USHORT) ud.st.wMinute; + dbts.second = (USHORT) ud.st.wSecond; + dbts.fraction = 0; + + return true; +} +#endif + +} // namespace ATL +#pragma pack(pop) + +#pragma warning(pop) + +#endif // __ATLCOMTIME_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcomtime.inl b/externals/WinDDK/7600.16385.1/inc/atl71/atlcomtime.inl new file mode 100644 index 00000000..8d3a4f65 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcomtime.inl @@ -0,0 +1,630 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCOMTIME_INL__ +#define __ATLCOMTIME_INL__ + +#pragma once + +#ifndef __ATLCOMTIME_H__ + #error ATLComTime.inl requires ATLComTime.h to be included first +#endif + +#include +#include + +namespace ATL +{ + + +///////////////////////////////////////////////////////////////////////////// +// COleDateTimeSpan +///////////////////////////////////////////////////////////////////////////// + +ATLCOMTIME_INLINE COleDateTimeSpan::COleDateTimeSpan() throw() : m_span(0), m_status(valid) +{ +} + +ATLCOMTIME_INLINE COleDateTimeSpan::COleDateTimeSpan(double dblSpanSrc) throw() : m_span(dblSpanSrc), m_status(valid) +{ + CheckRange(); +} + +ATLCOMTIME_INLINE COleDateTimeSpan::COleDateTimeSpan(LONG lDays, int nHours, int nMins, int nSecs) throw() +{ + SetDateTimeSpan(lDays, nHours, nMins, nSecs); +} + +ATLCOMTIME_INLINE void COleDateTimeSpan::SetStatus(DateTimeSpanStatus status) throw() +{ + m_status = status; +} + +ATLCOMTIME_INLINE COleDateTimeSpan::DateTimeSpanStatus COleDateTimeSpan::GetStatus() const throw() +{ + return m_status; +} + +__declspec(selectany) const double + COleDateTimeSpan::OLE_DATETIME_HALFSECOND = + 1.0 / (2.0 * (60.0 * 60.0 * 24.0)); + +ATLCOMTIME_INLINE double COleDateTimeSpan::GetTotalDays() const throw() +{ + ATLASSERT(GetStatus() == valid); + + return LONG(m_span + (m_span < 0 ? + -OLE_DATETIME_HALFSECOND : OLE_DATETIME_HALFSECOND)); +} + +ATLCOMTIME_INLINE double COleDateTimeSpan::GetTotalHours() const throw() +{ + ATLASSERT(GetStatus() == valid); + + return LONG((m_span + (m_span < 0 ? + -OLE_DATETIME_HALFSECOND : OLE_DATETIME_HALFSECOND)) * 24); +} + +ATLCOMTIME_INLINE double COleDateTimeSpan::GetTotalMinutes() const throw() +{ + ATLASSERT(GetStatus() == valid); + + return LONG((m_span + (m_span < 0 ? + -OLE_DATETIME_HALFSECOND : OLE_DATETIME_HALFSECOND)) * (24 * 60)); +} + +ATLCOMTIME_INLINE double COleDateTimeSpan::GetTotalSeconds() const throw() +{ + ATLASSERT(GetStatus() == valid); + + return LONG((m_span + (m_span < 0 ? + -OLE_DATETIME_HALFSECOND : OLE_DATETIME_HALFSECOND)) * (24 * 60 * 60)); +} + +ATLCOMTIME_INLINE LONG COleDateTimeSpan::GetDays() const throw() +{ + ATLASSERT(GetStatus() == valid); + return LONG(GetTotalDays()); +} + +ATLCOMTIME_INLINE LONG COleDateTimeSpan::GetHours() const throw() +{ + return LONG(GetTotalHours()) % 24; +} + +ATLCOMTIME_INLINE LONG COleDateTimeSpan::GetMinutes() const throw() +{ + return LONG(GetTotalMinutes()) % 60; +} + +ATLCOMTIME_INLINE LONG COleDateTimeSpan::GetSeconds() const throw() +{ + return LONG(GetTotalSeconds()) % 60; +} + +ATLCOMTIME_INLINE COleDateTimeSpan& COleDateTimeSpan::operator=(double dblSpanSrc) throw() +{ + m_span = dblSpanSrc; + m_status = valid; + CheckRange(); + return *this; +} + +ATLCOMTIME_INLINE bool COleDateTimeSpan::operator==(const COleDateTimeSpan& dateSpan) const throw() +{ + if(GetStatus() == dateSpan.GetStatus()) + { + if(GetStatus() == valid) + return (m_span == dateSpan.m_span); + + return (GetStatus() == null); + } + + return false; +} + +ATLCOMTIME_INLINE bool COleDateTimeSpan::operator!=(const COleDateTimeSpan& dateSpan) const throw() +{ + return !operator==(dateSpan); +} + +ATLCOMTIME_INLINE bool COleDateTimeSpan::operator<(const COleDateTimeSpan& dateSpan) const throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + if( (GetStatus() == valid) && (GetStatus() == dateSpan.GetStatus()) ) + return m_span < dateSpan.m_span; + + return false; +} + +ATLCOMTIME_INLINE bool COleDateTimeSpan::operator>(const COleDateTimeSpan& dateSpan) const throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + if( (GetStatus() == valid) && (GetStatus() == dateSpan.GetStatus()) ) + return m_span > dateSpan.m_span ; + + return false; +} + +ATLCOMTIME_INLINE bool COleDateTimeSpan::operator<=(const COleDateTimeSpan& dateSpan) const throw() +{ + return operator<(dateSpan) || operator==(dateSpan); +} + +ATLCOMTIME_INLINE bool COleDateTimeSpan::operator>=(const COleDateTimeSpan& dateSpan) const throw() +{ + return operator>(dateSpan) || operator==(dateSpan); +} + +ATLCOMTIME_INLINE COleDateTimeSpan COleDateTimeSpan::operator+(const COleDateTimeSpan& dateSpan) const throw() +{ + COleDateTimeSpan dateSpanTemp; + + // If either operand Null, result Null + if (GetStatus() == null || dateSpan.GetStatus() == null) + { + dateSpanTemp.SetStatus(null); + return dateSpanTemp; + } + + // If either operand Invalid, result Invalid + if (GetStatus() == invalid || dateSpan.GetStatus() == invalid) + { + dateSpanTemp.SetStatus(invalid); + return dateSpanTemp; + } + + // Add spans and validate within legal range + dateSpanTemp.m_span = m_span + dateSpan.m_span; + dateSpanTemp.CheckRange(); + + return dateSpanTemp; +} + +ATLCOMTIME_INLINE COleDateTimeSpan COleDateTimeSpan::operator-(const COleDateTimeSpan& dateSpan) const throw() +{ + COleDateTimeSpan dateSpanTemp; + + // If either operand Null, result Null + if (GetStatus() == null || dateSpan.GetStatus() == null) + { + dateSpanTemp.SetStatus(null); + return dateSpanTemp; + } + + // If either operand Invalid, result Invalid + if (GetStatus() == invalid || dateSpan.GetStatus() == invalid) + { + dateSpanTemp.SetStatus(invalid); + return dateSpanTemp; + } + + // Subtract spans and validate within legal range + dateSpanTemp.m_span = m_span - dateSpan.m_span; + dateSpanTemp.CheckRange(); + + return dateSpanTemp; +} + +ATLCOMTIME_INLINE COleDateTimeSpan& COleDateTimeSpan::operator+=(const COleDateTimeSpan dateSpan) throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + *this = *this + dateSpan; + CheckRange(); + return *this; +} + +ATLCOMTIME_INLINE COleDateTimeSpan& COleDateTimeSpan::operator-=(const COleDateTimeSpan dateSpan) throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + *this = *this - dateSpan; + CheckRange(); + return *this; +} + +ATLCOMTIME_INLINE COleDateTimeSpan COleDateTimeSpan::operator-() const throw() +{ + return -this->m_span; +} + +ATLCOMTIME_INLINE COleDateTimeSpan::operator double() const throw() +{ + return m_span; +} + +ATLCOMTIME_INLINE void COleDateTimeSpan::SetDateTimeSpan(LONG lDays, int nHours, int nMins, int nSecs) throw() +{ + // Set date span by breaking into fractional days (all input ranges valid) + m_span = lDays + ((double)nHours)/24 + ((double)nMins)/(24*60) + + ((double)nSecs)/(24*60*60); + m_status = valid; + CheckRange(); +} + +ATLCOMTIME_INLINE void COleDateTimeSpan::CheckRange() +{ + if(m_span < -maxDaysInSpan || m_span > maxDaysInSpan) + m_status = invalid; +} + +///////////////////////////////////////////////////////////////////////////// +// COleDateTime +///////////////////////////////////////////////////////////////////////////// + +ATLCOMTIME_INLINE COleDateTime WINAPI COleDateTime::GetCurrentTime() throw() +{ + return COleDateTime(::_time64(NULL)); +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime() throw() : + m_dt( 0 ), m_status(valid) +{ +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime( const VARIANT& varSrc ) throw() : + m_dt( 0 ), m_status(valid) +{ + *this = varSrc; +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime( DATE dtSrc ) throw() : + m_dt( dtSrc ), m_status(valid) +{ +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime( __time32_t timeSrc ) throw() : + m_dt( 0 ), m_status(valid) +{ + *this = timeSrc; +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime( __time64_t timeSrc ) throw() : + m_dt( 0 ), m_status(valid) +{ + *this = timeSrc; +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime( const SYSTEMTIME& systimeSrc ) throw() : + m_dt( 0 ), m_status(valid) +{ + *this = systimeSrc; +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime( const FILETIME& filetimeSrc ) throw() : + m_dt( 0 ), m_status(valid) +{ + *this = filetimeSrc; +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime(int nYear, int nMonth, int nDay, + int nHour, int nMin, int nSec) throw() +{ + SetDateTime(nYear, nMonth, nDay, nHour, nMin, nSec); +} + +ATLCOMTIME_INLINE COleDateTime::COleDateTime(WORD wDosDate, WORD wDosTime) throw() +{ + m_status = ::DosDateTimeToVariantTime(wDosDate, wDosTime, &m_dt) ? + valid : invalid; +} + +ATLCOMTIME_INLINE void COleDateTime::SetStatus(DateTimeStatus status) throw() +{ + m_status = status; +} + +ATLCOMTIME_INLINE COleDateTime::DateTimeStatus COleDateTime::GetStatus() const throw() +{ + return m_status; +} + +ATLCOMTIME_INLINE bool COleDateTime::GetAsSystemTime(SYSTEMTIME& sysTime) const throw() +{ + return GetStatus() == valid && ::VariantTimeToSystemTime(m_dt, &sysTime); +} + +ATLCOMTIME_INLINE bool COleDateTime::GetAsUDATE(UDATE &udate) const throw() +{ + return SUCCEEDED(::VarUdateFromDate(m_dt, 0, &udate)); +} + +ATLCOMTIME_INLINE int COleDateTime::GetYear() const throw() +{ + SYSTEMTIME st; + return GetAsSystemTime(st) ? st.wYear : error; +} + +ATLCOMTIME_INLINE int COleDateTime::GetMonth() const throw() +{ + SYSTEMTIME st; + return GetAsSystemTime(st) ? st.wMonth : error; +} + +ATLCOMTIME_INLINE int COleDateTime::GetDay() const throw() +{ + SYSTEMTIME st; + return GetAsSystemTime(st) ? st.wDay : error; +} + +ATLCOMTIME_INLINE int COleDateTime::GetHour() const throw() +{ + SYSTEMTIME st; + return GetAsSystemTime(st) ? st.wHour : error; +} + +ATLCOMTIME_INLINE int COleDateTime::GetMinute() const throw() +{ + SYSTEMTIME st; + return GetAsSystemTime(st) ? st.wMinute : error; +} + +ATLCOMTIME_INLINE int COleDateTime::GetSecond() const throw() +{ + SYSTEMTIME st; + return GetAsSystemTime(st) ? st.wSecond : error; +} + +ATLCOMTIME_INLINE int COleDateTime::GetDayOfWeek() const throw() +{ + SYSTEMTIME st; + return GetAsSystemTime(st) ? st.wDayOfWeek + 1 : error; +} + +ATLCOMTIME_INLINE int COleDateTime::GetDayOfYear() const throw() +{ + UDATE udate; + return GetAsUDATE(udate) ? udate.wDayOfYear : error; +} + +ATLCOMTIME_INLINE COleDateTime& COleDateTime::operator=(const VARIANT& varSrc) throw() +{ + if (varSrc.vt != VT_DATE) + { + VARIANT varDest; + varDest.vt = VT_EMPTY; + if(SUCCEEDED(::VariantChangeType(&varDest, const_cast(&varSrc), 0, VT_DATE))) + { + m_dt = varDest.date; + m_status = valid; + } + else + m_status = invalid; + } + else + { + m_dt = varSrc.date; + m_status = valid; + } + + return *this; +} + +ATLCOMTIME_INLINE COleDateTime& COleDateTime::operator=(DATE dtSrc) throw() +{ + m_dt = dtSrc; + m_status = valid; + return *this; +} + +ATLCOMTIME_INLINE COleDateTime& COleDateTime::operator=(const __time32_t& timeSrc) throw() +{ + return operator=(static_cast<__time64_t>(timeSrc)); +} + +ATLCOMTIME_INLINE COleDateTime& COleDateTime::operator=(const __time64_t& timeSrc) throw() +{ + SYSTEMTIME st; + CTime tmp(timeSrc); + + m_status = tmp.GetAsSystemTime(st) && + ConvertSystemTimeToVariantTime(st) ? valid : invalid; + return *this; +} + +ATLCOMTIME_INLINE COleDateTime &COleDateTime::operator=(const SYSTEMTIME &systimeSrc) throw() +{ + m_status = ConvertSystemTimeToVariantTime(systimeSrc) ? valid : invalid; + return *this; +} + +ATLCOMTIME_INLINE COleDateTime &COleDateTime::operator=(const FILETIME &filetimeSrc) throw() +{ + FILETIME ftl; + SYSTEMTIME st; + + m_status = ::FileTimeToLocalFileTime(&filetimeSrc, &ftl) && + ::FileTimeToSystemTime(&ftl, &st) && + ConvertSystemTimeToVariantTime(st) ? valid : invalid; + + return *this; +} + +ATLCOMTIME_INLINE BOOL COleDateTime::ConvertSystemTimeToVariantTime(const SYSTEMTIME& systimeSrc) +{ + return AtlConvertSystemTimeToVariantTime(systimeSrc,&m_dt); +} +ATLCOMTIME_INLINE COleDateTime &COleDateTime::operator=(const UDATE &udate) throw() +{ + m_status = (S_OK == VarDateFromUdate((UDATE*)&udate, 0, &m_dt)) ? valid : invalid; + + return *this; +} + +ATLCOMTIME_INLINE bool COleDateTime::operator==( const COleDateTime& date ) const throw() +{ + if(GetStatus() == date.GetStatus()) + { + if(GetStatus() == valid) + return( m_dt == date.m_dt ); + + return (GetStatus() == null); + } + return false; + +} + +ATLCOMTIME_INLINE bool COleDateTime::operator!=( const COleDateTime& date ) const throw() +{ + return !operator==(date); +} + +ATLCOMTIME_INLINE bool COleDateTime::operator<( const COleDateTime& date ) const throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(date.GetStatus() == valid); + if( (GetStatus() == valid) && (GetStatus() == date.GetStatus()) ) + return( DoubleFromDate( m_dt ) < DoubleFromDate( date.m_dt ) ); + + return false; +} + +ATLCOMTIME_INLINE bool COleDateTime::operator>( const COleDateTime& date ) const throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(date.GetStatus() == valid); + if( (GetStatus() == valid) && (GetStatus() == date.GetStatus()) ) + return( DoubleFromDate( m_dt ) > DoubleFromDate( date.m_dt ) ); + + return false; +} + +ATLCOMTIME_INLINE bool COleDateTime::operator<=( const COleDateTime& date ) const throw() +{ + return operator<(date) || operator==(date); +} + +ATLCOMTIME_INLINE bool COleDateTime::operator>=( const COleDateTime& date ) const throw() +{ + return operator>(date) || operator==(date); +} + +ATLCOMTIME_INLINE COleDateTime COleDateTime::operator+( COleDateTimeSpan dateSpan ) const throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + return( COleDateTime( DateFromDouble( DoubleFromDate( m_dt )+(double)dateSpan ) ) ); +} + +ATLCOMTIME_INLINE COleDateTime COleDateTime::operator-( COleDateTimeSpan dateSpan ) const throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + return( COleDateTime( DateFromDouble( DoubleFromDate( m_dt )-(double)dateSpan ) ) ); +} + +ATLCOMTIME_INLINE COleDateTime& COleDateTime::operator+=( COleDateTimeSpan dateSpan ) throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + m_dt = DateFromDouble( DoubleFromDate( m_dt )+(double)dateSpan ); + return( *this ); +} + +ATLCOMTIME_INLINE COleDateTime& COleDateTime::operator-=( COleDateTimeSpan dateSpan ) throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(dateSpan.GetStatus() == valid); + m_dt = DateFromDouble( DoubleFromDate( m_dt )-(double)dateSpan ); + return( *this ); +} + +ATLCOMTIME_INLINE COleDateTimeSpan COleDateTime::operator-(const COleDateTime& date) const throw() +{ + ATLASSERT(GetStatus() == valid); + ATLASSERT(date.GetStatus() == valid); + return DoubleFromDate(m_dt) - DoubleFromDate(date.m_dt); +} + +ATLCOMTIME_INLINE COleDateTime::operator DATE() const throw() +{ + ATLASSERT(GetStatus() == valid); + return( m_dt ); +} + +ATLCOMTIME_INLINE int COleDateTime::SetDateTime(int nYear, int nMonth, int nDay, + int nHour, int nMin, int nSec) throw() +{ + SYSTEMTIME st; + ::ZeroMemory(&st, sizeof(SYSTEMTIME)); + + st.wYear = WORD(nYear); + st.wMonth = WORD(nMonth); + st.wDay = WORD(nDay); + st.wHour = WORD(nHour); + st.wMinute = WORD(nMin); + st.wSecond = WORD(nSec); + + m_status = ConvertSystemTimeToVariantTime(st) ? valid : invalid; + return m_status; +} + +ATLCOMTIME_INLINE int COleDateTime::SetDate(int nYear, int nMonth, int nDay) throw() +{ + return SetDateTime(nYear, nMonth, nDay, 0, 0, 0); +} + +ATLCOMTIME_INLINE int COleDateTime::SetTime(int nHour, int nMin, int nSec) throw() +{ + // Set date to zero date - 12/30/1899 + return SetDateTime(1899, 12, 30, nHour, nMin, nSec); +} + +ATLCOMTIME_INLINE double WINAPI COleDateTime::DoubleFromDate( DATE date ) throw() +{ + double fTemp; + + // No problem if positive + if( date >= 0 ) + { + return( date ); + } + + // If negative, must convert since negative dates not continuous + // (examples: -1.25 to -.75, -1.50 to -.50, -1.75 to -.25) + fTemp = ceil( date ); + + return( fTemp-(date-fTemp) ); +} + +ATLCOMTIME_INLINE DATE WINAPI COleDateTime::DateFromDouble( double f ) throw() +{ + double fTemp; + + // No problem if positive + if( f >= 0 ) + { + return( f ); + } + + // If negative, must convert since negative dates not continuous + // (examples: -.75 to -1.25, -.50 to -1.50, -.25 to -1.75) + fTemp = floor( f ); // fTemp is now whole part + + return( fTemp+(fTemp-f) ); +} + +ATLCOMTIME_INLINE void COleDateTime::CheckRange() +{ + // About year 100 to about 9999 + if(m_dt > VTDATEGRE_MAX || m_dt < VTDATEGRE_MIN) + { + SetStatus(invalid); + } +} + + +} // namespace ATL + +#endif // __ATLCOMTIME_INL__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlconv.cpp b/externals/WinDDK/7600.16385.1/inc/atl71/atlconv.cpp new file mode 100644 index 00000000..f0a56456 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlconv.cpp @@ -0,0 +1,15 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#pragma message("atlconv.cpp is obsolete. Please remove it from your project.") + +/////////////////////////////////////// +// No longer used + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlconv.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlconv.h new file mode 100644 index 00000000..41eb87f0 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlconv.h @@ -0,0 +1,1302 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCONV_H__ +#define __ATLCONV_H__ + +#pragma once + +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning (push) +#pragma warning(disable: 4127) // unreachable code +#endif //!_ATL_NO_PRAGMA_WARNINGS + +// +// [pfx_parse] - workaround for old PREfix/PREfast parser +// +#if (defined(_PREFIX_) || defined(_PREFAST_)) && (_MSC_VER < 1400) +#pragma warning (push) +#pragma warning(disable: 4081) // expected 'newline' +#endif // old PREfast parser + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#include +#include +#include + +#ifndef __wtypes_h__ + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_IX86) +#define _X86_ +#endif + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_AMD64) +#define _AMD64_ +#endif + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_M68K) +#define _68K_ +#endif + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_IA64_) && !defined(_AMD64_) && defined(_M_MPPC) +#define _MPPC_ +#endif + +#if !defined(_68K_) && !defined(_MPPC_) && !defined(_X86_) && !defined(_M_IX86) && !defined(_AMD64_) && defined(_M_IA64) +#if !defined(_IA64_) +#define _IA64_ +#endif // !_IA64_ +#endif + +#include +#include +#include +#include + +#if defined(_WIN32) && !defined(OLE2ANSI) + +typedef WCHAR OLECHAR; +typedef OLECHAR *LPOLESTR; +typedef const OLECHAR *LPCOLESTR; +#define OLESTR(str) L##str + +#else + +typedef char OLECHAR; +typedef LPSTR LPOLESTR; +typedef LPCSTR LPCOLESTR; +#define OLESTR(str) str + +#endif // _WIN32 && !OLE2ANSI +#endif // __wtypes_h__ + +#ifndef _OLEAUTO_H_ +typedef LPWSTR BSTR;// must (semantically) match typedef in oleauto.h + +extern "C" +{ +__declspec(dllimport) BSTR __stdcall SysAllocString(const OLECHAR *); +__declspec(dllimport) BSTR __stdcall SysAllocStringLen(const OLECHAR *, UINT); +__declspec(dllimport) INT __stdcall SysReAllocStringLen(BSTR *, const OLECHAR *, UINT); +__declspec(dllimport) void __stdcall SysFreeString(BSTR); +} +#endif + +// we use our own implementation of InterlockedExchangePointer because of problems with the one in system headers +#ifdef _M_IX86 +#undef InterlockedExchangePointer +inline void* WINAPI InterlockedExchangePointer(void** pp, void* pNew) throw() +{ + return( reinterpret_cast(static_cast(::InterlockedExchange(reinterpret_cast(pp), static_cast(reinterpret_cast(pNew))))) ); +} +#endif + +#ifndef _SECURECRT_FILL_BUFFER_PATTERN +#define _SECURECRT_FILL_BUFFER_PATTERN 0xFD +#endif + +#define ATLCONV_DEADLAND_FILL _SECURECRT_FILL_BUFFER_PATTERN + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ +#ifndef _CONVERSION_DONT_USE_THREAD_LOCALE +inline UINT WINAPI _AtlGetConversionACP() throw() +{ + return( CP_THREAD_ACP ); +} + +#else + +inline UINT WINAPI _AtlGetConversionACP() throw() +{ + return( CP_ACP ); +} + +#endif // _CONVERSION_DONT_USE_THREAD_LOCALE +template +inline void AtlConvAllocMemory(__deref_ecount_opt(nLength) _CharType** ppBuff,__in int nLength,__inout_ecount(nFixedBufferLength) _CharType* pszFixedBuffer,__in int nFixedBufferLength) +{ + ATLENSURE_THROW(ppBuff != NULL, E_INVALIDARG); + ATLENSURE_THROW(nLength >= 0, E_INVALIDARG); + ATLENSURE_THROW(pszFixedBuffer != NULL, E_INVALIDARG); + + //if buffer malloced, try to realloc. + if (*ppBuff != pszFixedBuffer) + { + if( nLength > nFixedBufferLength ) + { + _CharType* ppReallocBuf = static_cast< _CharType* >( _recalloc(*ppBuff, nLength,sizeof( _CharType ) ) ); + if (ppReallocBuf == NULL) + { + AtlThrow( E_OUTOFMEMORY ); + } + *ppBuff = ppReallocBuf; + } else + { + free(*ppBuff); + *ppBuff=pszFixedBuffer; + } + + } else //Buffer is not currently malloced. + { + if( nLength > nFixedBufferLength ) + { + *ppBuff = static_cast< _CharType* >( calloc(nLength,sizeof( _CharType ) ) ); + } else + { + *ppBuff=pszFixedBuffer; + } + } + + if (*ppBuff == NULL) + { + AtlThrow( E_OUTOFMEMORY ); + } + +} + +template +inline void AtlConvFreeMemory(_CharType* pBuff,_CharType* pszFixedBuffer,int nFixedBufferLength) +{ + (nFixedBufferLength); + if( pBuff != pszFixedBuffer ) + { + free( pBuff ); + } +#ifdef _DEBUG + else + { + memset(pszFixedBuffer,ATLCONV_DEADLAND_FILL,nFixedBufferLength*sizeof(_CharType)); + } +#endif + +} + +template< int t_nBufferLength = 128 > +class CW2WEX +{ +public: + CW2WEX( __in_opt LPCWSTR psz ) throw(...) : + m_psz( m_szBuffer ) + { + Init( psz ); + } + CW2WEX( __in_opt LPCWSTR psz, UINT nCodePage ) throw(...) : + m_psz( m_szBuffer ) + { + (void)nCodePage; // Code page doesn't matter + + Init( psz ); + } + ~CW2WEX() throw() + { + AtlConvFreeMemory(m_psz,m_szBuffer,t_nBufferLength); + } + + operator LPWSTR() const throw() + { + return( m_psz ); + } + +private: + void Init( __in_opt LPCWSTR psz ) throw(...) + { + if (psz == NULL) + { + m_psz = NULL; + return; + } + int nLength = lstrlenW( psz )+1; + AtlConvAllocMemory(&m_psz,nLength,m_szBuffer,t_nBufferLength); + Checked::memcpy_s( m_psz, nLength*sizeof( wchar_t ), psz, nLength*sizeof( wchar_t )); + } + +public: + LPWSTR m_psz; + wchar_t m_szBuffer[t_nBufferLength]; + +private: + CW2WEX( const CW2WEX& ) throw(); + CW2WEX& operator=( const CW2WEX& ) throw(); +}; +typedef CW2WEX<> CW2W; + +template< int t_nBufferLength = 128 > +class CA2AEX +{ +public: + CA2AEX( __in_opt LPCSTR psz ) throw(...) : + m_psz( m_szBuffer ) + { + Init( psz ); + } + CA2AEX( __in_opt LPCSTR psz, UINT nCodePage ) throw(...) : + m_psz( m_szBuffer ) + { + (void)nCodePage; // Code page doesn't matter + + Init( psz ); + } + ~CA2AEX() throw() + { + AtlConvFreeMemory(m_psz,m_szBuffer,t_nBufferLength); + } + + operator LPSTR() const throw() + { + return( m_psz ); + } + +private: + void Init( __in_opt LPCSTR psz ) throw(...) + { + if (psz == NULL) + { + m_psz = NULL; + return; + } + int nLength = lstrlenA( psz )+1; + AtlConvAllocMemory(&m_psz,nLength,m_szBuffer,t_nBufferLength); + Checked::memcpy_s( m_psz, nLength*sizeof( char ), psz, nLength*sizeof( char )); + } + +public: + LPSTR m_psz; + char m_szBuffer[t_nBufferLength]; + +private: + CA2AEX( const CA2AEX& ) throw(); + CA2AEX& operator=( const CA2AEX& ) throw(); +}; +typedef CA2AEX<> CA2A; + +template< int t_nBufferLength = 128 > +class CA2CAEX +{ +public: + CA2CAEX( __in LPCSTR psz ) throw(...) : + m_psz( psz ) + { + } + CA2CAEX( __in LPCSTR psz, UINT nCodePage ) throw(...) : + m_psz( psz ) + { + (void)nCodePage; + } + ~CA2CAEX() throw() + { + } + + operator LPCSTR() const throw() + { + return( m_psz ); + } + +public: + LPCSTR m_psz; + +private: + CA2CAEX( const CA2CAEX& ) throw(); + CA2CAEX& operator=( const CA2CAEX& ) throw(); +}; +typedef CA2CAEX<> CA2CA; + +template< int t_nBufferLength = 128 > +class CW2CWEX +{ +public: + CW2CWEX( __in LPCWSTR psz ) throw(...) : + m_psz( psz ) + { + } + CW2CWEX( __in LPCWSTR psz, UINT nCodePage ) throw(...) : + m_psz( psz ) + { + (void)nCodePage; + } + ~CW2CWEX() throw() + { + } + + operator LPCWSTR() const throw() + { + return( m_psz ); + } + +public: + LPCWSTR m_psz; + +private: + CW2CWEX( const CW2CWEX& ) throw(); + CW2CWEX& operator=( const CW2CWEX& ) throw(); +}; +typedef CW2CWEX<> CW2CW; + +template< int t_nBufferLength = 128 > +class CA2WEX +{ +public: + CA2WEX( __in_opt LPCSTR psz ) throw(...) : + m_psz( m_szBuffer ) + { + Init( psz, _AtlGetConversionACP() ); + } + CA2WEX( __in_opt LPCSTR psz, UINT nCodePage ) throw(...) : + m_psz( m_szBuffer ) + { + Init( psz, nCodePage ); + } + ~CA2WEX() throw() + { + AtlConvFreeMemory(m_psz,m_szBuffer,t_nBufferLength); + } + + operator LPWSTR() const throw() + { + return( m_psz ); + } + +private: + void Init( __in_opt LPCSTR psz, UINT nCodePage ) throw(...) + { + if (psz == NULL) + { + m_psz = NULL; + return; + } + int nLengthA = lstrlenA( psz )+1; + int nLengthW = nLengthA; + + AtlConvAllocMemory(&m_psz,nLengthW,m_szBuffer,t_nBufferLength); + + BOOL bFailed=(0 == ::MultiByteToWideChar( nCodePage, 0, psz, nLengthA, m_psz, nLengthW ) ); + if (bFailed) + { + if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) + { + nLengthW = ::MultiByteToWideChar( nCodePage, 0, psz, nLengthA, NULL, 0); + AtlConvAllocMemory(&m_psz,nLengthW,m_szBuffer,t_nBufferLength); + bFailed=(0 == ::MultiByteToWideChar( nCodePage, 0, psz, nLengthA, m_psz, nLengthW ) ); + } + } + if (bFailed) + { + AtlThrowLastWin32(); + } + } + +public: + LPWSTR m_psz; + wchar_t m_szBuffer[t_nBufferLength]; + +private: + CA2WEX( const CA2WEX& ) throw(); + CA2WEX& operator=( const CA2WEX& ) throw(); +}; +typedef CA2WEX<> CA2W; + +template< int t_nBufferLength = 128 > +class CW2AEX +{ +public: + CW2AEX( __in_opt LPCWSTR psz ) throw(...) : + m_psz( m_szBuffer ) + { + Init( psz, _AtlGetConversionACP() ); + } + CW2AEX( __in_opt LPCWSTR psz, UINT nCodePage ) throw(...) : + m_psz( m_szBuffer ) + { + Init( psz, nCodePage ); + } + ~CW2AEX() throw() + { + AtlConvFreeMemory(m_psz,m_szBuffer,t_nBufferLength); + } + + operator LPSTR() const throw() + { + return( m_psz ); + } + +private: + void Init( __in_opt LPCWSTR psz, __in UINT nConvertCodePage ) throw(...) + { + if (psz == NULL) + { + m_psz = NULL; + return; + } + int nLengthW = lstrlenW( psz )+1; + int nLengthA = nLengthW*4; + + AtlConvAllocMemory(&m_psz,nLengthA,m_szBuffer,t_nBufferLength); + + BOOL bFailed=(0 == ::WideCharToMultiByte( nConvertCodePage, 0, psz, nLengthW, m_psz, nLengthA, NULL, NULL )); + if (bFailed) + { + if (GetLastError()==ERROR_INSUFFICIENT_BUFFER) + { + nLengthA = ::WideCharToMultiByte( nConvertCodePage, 0, psz, nLengthW, NULL, 0, NULL, NULL ); + AtlConvAllocMemory(&m_psz,nLengthA,m_szBuffer,t_nBufferLength); + bFailed=(0 == ::WideCharToMultiByte( nConvertCodePage, 0, psz, nLengthW, m_psz, nLengthA, NULL, NULL )); + } + } + if (bFailed) + { + AtlThrowLastWin32(); + } + } + +public: + LPSTR m_psz; + char m_szBuffer[t_nBufferLength]; + +private: + CW2AEX( const CW2AEX& ) throw(); + CW2AEX& operator=( const CW2AEX& ) throw(); +}; +typedef CW2AEX<> CW2A; + +#ifdef _UNICODE + + #define CW2T CW2W + #define CW2TEX CW2WEX + #define CW2CT CW2CW + #define CW2CTEX CW2CWEX + #define CT2W CW2W + #define CT2WEX CW2WEX + #define CT2CW CW2CW + #define CT2CWEX CW2CWEX + + #define CA2T CA2W + #define CA2TEX CA2WEX + #define CA2CT CA2W + #define CA2CTEX CA2WEX + #define CT2A CW2A + #define CT2AEX CW2AEX + #define CT2CA CW2A + #define CT2CAEX CW2AEX + +#else // !_UNICODE + + #define CW2T CW2A + #define CW2TEX CW2AEX + #define CW2CT CW2A + #define CW2CTEX CW2AEX + #define CT2W CA2W + #define CT2WEX CA2WEX + #define CT2CW CA2W + #define CT2CWEX CA2WEX + + #define CA2T CA2A + #define CA2TEX CA2AEX + #define CA2CT CA2CA + #define CA2CTEX CA2CAEX + #define CT2A CA2A + #define CT2AEX CA2AEX + #define CT2CA CA2CA + #define CT2CAEX CA2CAEX + +#endif // !_UNICODE + +#define COLE2T CW2T +#define COLE2TEX CW2TEX +#define COLE2CT CW2CT +#define COLE2CTEX CW2CTEX +#define CT2OLE CT2W +#define CT2OLEEX CT2WEX +#define CT2COLE CT2CW +#define CT2COLEEX CT2CWEX + +}; // namespace ATL +#pragma pack(pop) + +#pragma pack(push,8) + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + +#ifndef _DEBUG + #define USES_CONVERSION int _convert; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw; (_lpw); LPCSTR _lpa; (_lpa) +#else + #define USES_CONVERSION int _convert = 0; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw = NULL; (_lpw); LPCSTR _lpa = NULL; (_lpa) +#endif + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#ifndef _DEBUG + #define USES_CONVERSION_EX int _convert_ex; (_convert_ex); UINT _acp_ex = ATL::_AtlGetConversionACP(); (_acp_ex); LPCWSTR _lpw_ex; (_lpw_ex); LPCSTR _lpa_ex; (_lpa_ex); USES_ATL_SAFE_ALLOCA +#else + #define USES_CONVERSION_EX int _convert_ex = 0; (_convert_ex); UINT _acp_ex = ATL::_AtlGetConversionACP(); (_acp_ex); LPCWSTR _lpw_ex = NULL; (_lpw_ex); LPCSTR _lpa_ex = NULL; (_lpa_ex); USES_ATL_SAFE_ALLOCA +#endif + +#ifdef _WINGDI_ + ATLAPI_(LPDEVMODEA) AtlDevModeW2A(__out LPDEVMODEA lpDevModeA, __in const DEVMODEW* lpDevModeW); +#endif + +///////////////////////////////////////////////////////////////////////////// +// Global UNICODE<>ANSI translation helpers +inline __out_ecount_z_opt(nChars) LPWSTR WINAPI AtlA2WHelper(__out_ecount_z(nChars) LPWSTR lpw, __in_z LPCSTR lpa, __in int nChars, __in UINT acp) throw() +{ + ATLASSERT(lpa != NULL); + ATLASSERT(lpw != NULL); + if (lpw == NULL || lpa == NULL) + return NULL; + // verify that no illegal character present + // since lpw was allocated based on the size of lpa + // don't worry about the number of chars + lpw[0] = '\0'; + int ret = MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars); + if(ret == 0) + { + ATLASSERT(FALSE); + return NULL; + } + return lpw; +} + +inline __out_ecount_z_opt(nChars) LPSTR WINAPI AtlW2AHelper(__out_ecount_z(nChars) LPSTR lpa, __in_z LPCWSTR lpw, __in int nChars, __in UINT acp) throw() +{ + ATLASSERT(lpw != NULL); + ATLASSERT(lpa != NULL); + if (lpa == NULL || lpw == NULL) + return NULL; + // verify that no illegal character present + // since lpa was allocated based on the size of lpw + // don't worry about the number of chars + lpa[0] = '\0'; + int ret = WideCharToMultiByte(acp, 0, lpw, -1, lpa, nChars, NULL, NULL); + if(ret == 0) + { + ATLASSERT(FALSE); + return NULL; + } + return lpa; +} +inline __out_ecount_z_opt(nChars) LPWSTR WINAPI AtlA2WHelper(__out_ecount_z(nChars) LPWSTR lpw, __in_z LPCSTR lpa, __in int nChars) throw() +{ + return AtlA2WHelper(lpw, lpa, nChars, CP_ACP); +} + +inline __out_ecount_z_opt(nChars) LPSTR WINAPI AtlW2AHelper(__out_ecount_z(nChars) LPSTR lpa, __in_z LPCWSTR lpw, __in int nChars) throw() +{ + return AtlW2AHelper(lpa, lpw, nChars, CP_ACP); +} + +#ifndef _CONVERSION_DONT_USE_THREAD_LOCALE + #ifdef ATLA2WHELPER + #undef ATLA2WHELPER + #undef ATLW2AHELPER + #endif + #define ATLA2WHELPER AtlA2WHelper + #define ATLW2AHELPER AtlW2AHelper +#else + #ifndef ATLA2WHELPER + #define ATLA2WHELPER AtlA2WHelper + #define ATLW2AHELPER AtlW2AHelper + #endif +#endif + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + +#define A2W(lpa) (\ + ((_lpa = lpa) == NULL) ? NULL : (\ + _convert = (lstrlenA(_lpa)+1),\ + (INT_MAX/2<_convert)? NULL : \ + ATLA2WHELPER((LPWSTR) alloca(_convert*sizeof(WCHAR)), _lpa, _convert, _acp))) + +#define W2A(lpw) (\ + ((_lpw = lpw) == NULL) ? NULL : (\ + (_convert = (lstrlenW(_lpw)+1), \ + (_convert>INT_MAX/2) ? NULL : \ + ATLW2AHELPER((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw, _convert*sizeof(WCHAR), _acp)))) + +#define A2W_CP(lpa, cp) (\ + ((_lpa = lpa) == NULL) ? NULL : (\ + _convert = (lstrlenA(_lpa)+1),\ + (INT_MAX/2<_convert)? NULL : \ + ATLA2WHELPER((LPWSTR) alloca(_convert*sizeof(WCHAR)), _lpa, _convert, (cp)))) + +#define W2A_CP(lpw, cp) (\ + ((_lpw = lpw) == NULL) ? NULL : (\ + (_convert = (lstrlenW(_lpw)+1), \ + (_convert>INT_MAX/2) ? NULL : \ + ATLW2AHELPER((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw, _convert*sizeof(WCHAR), (cp))))) + +#endif + +// The call to _alloca will not cause stack overflow if _AtlVerifyStackAvailable returns TRUE. +// Notice that nChars is never used in these conversion functions. We cannot change the behavior of +// these functions to actually use nChars because we could potentially break a lot of legacy code. +#define A2W_EX(lpa, nChars) (\ + ((_lpa_ex = lpa) == NULL) ? NULL : (\ + _convert_ex = (lstrlenA(_lpa_ex)+1),\ + FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast(sizeof(WCHAR)))) ? NULL : \ + ATLA2WHELPER( \ + (LPWSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), \ + _lpa_ex, \ + _convert_ex / sizeof(WCHAR), \ + _acp_ex))) + +#define A2W_EX_DEF(lpa) A2W_EX(lpa, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) + +#define W2A_EX(lpw, nChars) (\ + ((_lpw_ex = lpw) == NULL) ? NULL : (\ + _convert_ex = (lstrlenW(_lpw_ex)+1),\ + FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast(sizeof(WCHAR)))) ? NULL : \ + ATLW2AHELPER( \ + (LPSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), \ + _lpw_ex, \ + _convert_ex, \ + _acp_ex))) + +#define W2A_EX_DEF(lpa) W2A_EX(lpa, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) + +#define A2W_CP_EX(lpa, nChars, cp) (\ + ((_lpa_ex = lpa) == NULL) ? NULL : (\ + _convert_ex = (lstrlenA(_lpa_ex)+1),\ + FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast(sizeof(WCHAR)))) ? NULL : \ + ATLA2WHELPER( \ + (LPWSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), \ + _lpa_ex, \ + _convert_ex / sizeof(WCHAR), \ + (cp)))) + +#define W2A_CP_EX(lpw, nChars, cp) (\ + ((_lpw_ex = lpw) == NULL) ? NULL : (\ + _convert_ex = (lstrlenW(_lpw_ex)+1),\ + FAILED(::ATL::AtlMultiply(&_convert_ex, _convert_ex, static_cast(sizeof(WCHAR)))) ? NULL : \ + ATLW2AHELPER( \ + (LPSTR)_ATL_SAFE_ALLOCA(_convert_ex, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), \ + _lpw_ex, \ + _convert_ex, \ + (cp)))) + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + +#define A2CW(lpa) ((LPCWSTR)A2W(lpa)) +#define W2CA(lpw) ((LPCSTR)W2A(lpw)) + +#define A2CW_CP(lpa, cp) ((LPCWSTR)A2W_CP(lpa, (cp))) +#define W2CA_CP(lpw, cp) ((LPCSTR)W2A_CP(lpw, (cp))) + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#define A2CW_EX(lpa, nChar) ((LPCWSTR)A2W_EX(lpa, nChar)) +#define A2CW_EX_DEF(lpa) ((LPCWSTR)A2W_EX_DEF(lpa)) +#define W2CA_EX(lpw, nChar) ((LPCSTR)W2A_EX(lpw, nChar)) +#define W2CA_EX_DEF(lpw) ((LPCSTR)W2A_EX_DEF(lpw)) + +#define A2CW_CP_EX(lpa, nChar, cp) ((LPCWSTR)A2W_CP_EX(lpa, nChar, (cp))) +#define W2CA_CP_EX(lpw, nChar, cp) ((LPCSTR)W2A_CP_EX(lpw, nChar, (cp))) + + inline int ocslen(__in_z LPCOLESTR x) throw() { return lstrlenW(x); } + +#if _SECURE_ATL + inline bool ocscpy_s(__out_ecount_z(maxSize) LPOLESTR dest, __in size_t maxSize, __in_z LPCOLESTR src) throw() + { return 0 == memcpy_s(dest, maxSize*sizeof(WCHAR), src, (ocslen(src)+1)*sizeof(WCHAR)); } + inline bool ocscat_s(__out_ecount_z(maxSize) LPOLESTR dest, __in size_t maxSize, __in_z LPCOLESTR src) throw() + { return 0 == wcscat_s(dest, maxSize,src); } +#else + inline bool ocscpy_s(__out_ecount_z(maxSize) LPOLESTR dest, __in size_t maxSize, __in_z LPCOLESTR src) throw() + { (void)maxSize; memcpy(dest, src, (ocslen(src)+1)*sizeof(WCHAR)); return true; } + inline bool ocscat_s(__out_ecount_z(maxSize) LPOLESTR dest, __in size_t maxSize, __in_z LPCOLESTR src) throw() + { (void)maxSize; wcscat(dest, src); } +#endif + +#if defined(_UNICODE) + +// in these cases the default (TCHAR) is the same as OLECHAR + +#if _SECURE_ATL + _ATL_INSECURE_DEPRECATE("ocscpy is not safe. Intead, use ocscpy_s") + inline OLECHAR* ocscpy(__out_z LPOLESTR dest, __in_z LPCOLESTR src) throw() + { +#pragma warning(push) +#pragma warning(disable:4995) // use of deprecated function +#pragma warning(disable:4996) +#pragma warning(disable:28719) // use of Banned API + return wcscpy(dest, src); +#pragma warning(pop) + } + _ATL_INSECURE_DEPRECATE("ocscat is not safe. Intead, use ocscat_s") + inline OLECHAR* ocscat(__out_z LPOLESTR dest, __in_z LPCOLESTR src) throw() + { +#pragma warning(push) +#pragma warning(disable:4995) // use of deprecated function +#pragma warning(disable:4996) +#pragma warning(disable:28719) // use of Banned API + return wcscat(dest, src); +#pragma warning(pop) + } +#else +#pragma warning(push) +#pragma warning(disable:4995) // use of deprecated function + inline OLECHAR* ocscpy(__out_z LPOLESTR dest, __in_z LPCOLESTR src) throw() { return lstrcpyW(dest, src); } + inline OLECHAR* ocscat(__out_z LPOLESTR dest, __in_z LPCOLESTR src) throw() { return lstrcatW(dest, src); } +#pragma warning(pop) +#endif + + inline LPCOLESTR T2COLE_EX(__in_opt LPCTSTR lp, UINT) { return lp; } + inline LPCOLESTR T2COLE_EX_DEF(__in_opt LPCTSTR lp) { return lp; } + inline LPCTSTR OLE2CT_EX(__in_opt LPCOLESTR lp, UINT) { return lp; } + inline LPCTSTR OLE2CT_EX_DEF(__in_opt LPCOLESTR lp) { return lp; } + inline LPOLESTR T2OLE_EX(__in_opt LPTSTR lp, UINT) { return lp; } + inline LPOLESTR T2OLE_EX_DEF(__in_opt LPTSTR lp) { return lp; } + inline LPTSTR OLE2T_EX(__in_opt LPOLESTR lp, UINT) { return lp; } + inline LPTSTR OLE2T_EX_DEF(__in_opt LPOLESTR lp) { return lp; } + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + + inline LPCOLESTR T2COLE(__in_opt LPCTSTR lp) { return lp; } + inline LPCTSTR OLE2CT(__in_opt LPCOLESTR lp) { return lp; } + inline LPOLESTR T2OLE(__in_opt LPTSTR lp) { return lp; } + inline LPTSTR OLE2T(__in_opt LPOLESTR lp) { return lp; } + inline LPOLESTR CharNextO(__in LPCOLESTR lp) throw() {return CharNextW(lp);} + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#else // !defined(_UNICODE) + +#if _SECURE_ATL + + _ATL_INSECURE_DEPRECATE("ocscpy is not safe. Intead, use ocscpy_s") + inline OLECHAR* ocscpy(__out_z LPOLESTR dest, __in_z LPCOLESTR src) throw() + { +#pragma warning(push) +#pragma warning(disable:4995) // use of deprecated function +#pragma warning(disable:4996) + return (LPOLESTR) memcpy(dest, src, (lstrlenW(src)+1)*sizeof(WCHAR)); +#pragma warning(pop) + } + _ATL_INSECURE_DEPRECATE("ocscat is not safe. Intead, use ocscat_s") + inline OLECHAR* ocscat(__inout_z LPOLESTR dest, __in_z LPCOLESTR src) throw() + { +#pragma warning(push) +#pragma warning(disable:4995) // use of deprecated function +#pragma warning(disable:4996) + return ocscpy(dest+ocslen(dest), src); +#pragma warning(pop) + } + +#else + + //lstrcpyW doesn't work on Win95, so we do this + inline OLECHAR* ocscpy(__out_z LPOLESTR dest, __in_z LPCOLESTR src) throw() + { + return (LPOLESTR) memcpy(dest, src, (lstrlenW(src)+1)*sizeof(WCHAR)); + } + inline OLECHAR* ocscat(__out_z LPOLESTR dest, __in_z LPCOLESTR src) throw() + { + return ocscpy(dest+ocslen(dest), src); + } + +#endif + + //CharNextW doesn't work on Win95 so we use this + #define T2COLE_EX(lpa, nChar) A2CW_EX(lpa, nChar) + #define T2COLE_EX_DEF(lpa) A2CW_EX_DEF(lpa) + #define T2OLE_EX(lpa, nChar) A2W_EX(lpa, nChar) + #define T2OLE_EX_DEF(lpa) A2W_EX_DEF(lpa) + #define OLE2CT_EX(lpo, nChar) W2CA_EX(lpo, nChar) + #define OLE2CT_EX_DEF(lpo) W2CA_EX_DEF(lpo) + #define OLE2T_EX(lpo, nChar) W2A_EX(lpo, nChar) + #define OLE2T_EX_DEF(lpo) W2A_EX_DEF(lpo) + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + + #define T2COLE(lpa) A2CW(lpa) + #define T2OLE(lpa) A2W(lpa) + #define OLE2CT(lpo) W2CA(lpo) + #define OLE2T(lpo) W2A(lpo) + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + + inline LPOLESTR CharNextO(LPCOLESTR lp) throw() {return (LPOLESTR) ((*lp) ? (lp+1) : lp);} + +#endif // defined(_UNICODE) + + inline LPOLESTR W2OLE_EX(__in_opt LPWSTR lp, UINT) { return lp; } + inline LPOLESTR W2OLE_EX_DEF(__in_opt LPWSTR lp) { return lp; } + inline LPWSTR OLE2W_EX(__in_opt LPOLESTR lp, UINT) { return lp; } + inline LPWSTR OLE2W_EX_DEF(__in_opt LPOLESTR lp) { return lp; } + #define A2OLE_EX A2W_EX + #define A2OLE_EX_DEF A2W_EX_DEF + #define OLE2A_EX W2A_EX + #define OLE2A_EX_DEF W2A_EX_DEF + inline LPCOLESTR W2COLE_EX(__in_opt LPCWSTR lp, UINT) { return lp; } + inline LPCOLESTR W2COLE_EX_DEF(__in_opt LPCWSTR lp) { return lp; } + inline LPCWSTR OLE2CW_EX(__in_opt LPCOLESTR lp, UINT) { return lp; } + inline LPCWSTR OLE2CW_EX_DEF(__in_opt LPCOLESTR lp) { return lp; } + #define A2COLE_EX A2CW_EX + #define A2COLE_EX_DEF A2CW_EX_DEF + #define OLE2CA_EX W2CA_EX + #define OLE2CA_EX_DEF W2CA_EX_DEF + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + + inline LPOLESTR W2OLE(__in_opt LPWSTR lp) { return lp; } + inline LPWSTR OLE2W(__in_opt LPOLESTR lp) { return lp; } + #define A2OLE A2W + #define OLE2A W2A + inline LPCOLESTR W2COLE(__in_opt LPCWSTR lp) { return lp; } + inline LPCWSTR OLE2CW(__in_opt LPCOLESTR lp) { return lp; } + #define A2COLE A2CW + #define OLE2CA W2CA + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#if defined(_UNICODE) + + #define T2A_EX W2A_EX + #define T2A_EX_DEF W2A_EX_DEF + #define A2T_EX A2W_EX + #define A2T_EX_DEF A2W_EX_DEF + inline LPWSTR T2W_EX(__in_opt LPTSTR lp, UINT) { return lp; } + inline LPWSTR T2W_EX_DEF(__in_opt LPTSTR lp) { return lp; } + inline LPTSTR W2T_EX(__in_opt LPWSTR lp, UINT) { return lp; } + inline LPTSTR W2T_DEF(__in_opt LPWSTR lp) { return lp; } + #define T2CA_EX W2CA_EX + #define T2CA_EX_DEF W2CA_EX_DEF + #define A2CT_EX A2CW_EX + #define A2CT_EX_DEF A2CW_EX_DEF + inline LPCWSTR T2CW_EX(__in_opt LPCTSTR lp, UINT) { return lp; } + inline LPCWSTR T2CW_EX_DEF(__in_opt LPCTSTR lp) { return lp; } + inline LPCTSTR W2CT_EX(__in_opt LPCWSTR lp, UINT) { return lp; } + inline LPCTSTR W2CT_EX_DEF(__in_opt LPCWSTR lp) { return lp; } + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + + #define T2A W2A + #define A2T A2W + inline LPWSTR T2W(__in_opt LPTSTR lp) { return lp; } + inline LPTSTR W2T(__in_opt LPWSTR lp) { return lp; } + #define T2CA W2CA + #define A2CT A2CW + inline LPCWSTR T2CW(__in_opt LPCTSTR lp) { return lp; } + inline LPCTSTR W2CT(__in_opt LPCWSTR lp) { return lp; } + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#else // !defined(_UNICODE) + + #define T2W_EX A2W_EX + #define T2W_EX_DEF A2W_EX_DEF + #define W2T_EX W2A_EX + #define W2T_EX_DEF W2A_EX_DEF + inline LPSTR T2A_EX(__in_opt LPTSTR lp, UINT) { return lp; } + inline LPSTR T2A_EX_DEF(__in_opt LPTSTR lp) { return lp; } + inline LPTSTR A2T_EX(__in_opt LPSTR lp, UINT) { return lp; } + inline LPTSTR A2T_EX_DEF(__in_opt LPSTR lp) { return lp; } + #define T2CW_EX A2CW_EX + #define T2CW_EX_DEF A2CW_EX_DEF + #define W2CT_EX W2CA_EX + #define W2CT_EX_DEF W2CA_EX_DEF + inline LPCSTR T2CA_EX(__in_opt LPCTSTR lp, UINT) { return lp; } + inline LPCSTR T2CA_EX_DEF(__in_opt LPCTSTR lp) { return lp; } + inline LPCTSTR A2CT_EX(__in_opt LPCSTR lp, UINT) { return lp; } + inline LPCTSTR A2CT_EX_DEF(__in_opt LPCSTR lp) { return lp; } + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + + #define T2W A2W + #define W2T W2A + inline LPSTR T2A(__in_opt LPTSTR lp) { return lp; } + inline LPTSTR A2T(__in_opt LPSTR lp) { return lp; } + #define T2CW A2CW + #define W2CT W2CA + inline LPCSTR T2CA(__in_opt LPCTSTR lp) { return lp; } + inline LPCTSTR A2CT(__in_opt LPCSTR lp) { return lp; } + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#endif // defined(_UNICODE) + +inline __checkReturn BSTR A2WBSTR(__in_opt LPCSTR lp, int nLen = -1) +{ + if (lp == NULL || nLen == 0) + return NULL; + USES_CONVERSION_EX; + BSTR str = NULL; + int nConvertedLen = MultiByteToWideChar(_acp_ex, 0, lp, + nLen, NULL, NULL); + int nAllocLen = nConvertedLen; + if (nLen == -1) + nAllocLen -= 1; // Don't allocate terminating '\0' + str = ::SysAllocStringLen(NULL, nAllocLen); + + if (str != NULL) + { + int nResult; + nResult = MultiByteToWideChar(_acp_ex, 0, lp, nLen, str, nConvertedLen); + ATLASSERT(nResult == nConvertedLen); + if(nResult != nConvertedLen) + { + SysFreeString(str); + return NULL; + } + + } + return str; +} + +inline BSTR OLE2BSTR(__in_opt LPCOLESTR lp) {return ::SysAllocString(lp);} +#if defined(_UNICODE) +// in these cases the default (TCHAR) is the same as OLECHAR + inline BSTR T2BSTR_EX(__in_opt LPCTSTR lp) {return ::SysAllocString(lp);} + inline BSTR A2BSTR_EX(__in_opt LPCSTR lp) {return A2WBSTR(lp);} + inline BSTR W2BSTR_EX(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);} + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + + inline BSTR T2BSTR(__in_opt LPCTSTR lp) {return ::SysAllocString(lp);} + inline BSTR A2BSTR(__in_opt LPCSTR lp) {return A2WBSTR(lp);} + inline BSTR W2BSTR(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);} + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#else // !defined(_UNICODE) + inline BSTR T2BSTR_EX(__in_opt LPCTSTR lp) {return A2WBSTR(lp);} + inline BSTR A2BSTR_EX(__in_opt LPCSTR lp) {return A2WBSTR(lp);} + inline BSTR W2BSTR_EX(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);} + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + + inline BSTR T2BSTR(__in_opt LPCTSTR lp) {return A2WBSTR(lp);} + inline BSTR A2BSTR(__in_opt LPCSTR lp) {return A2WBSTR(lp);} + inline BSTR W2BSTR(__in_opt LPCWSTR lp) {return ::SysAllocString(lp);} + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#endif // defined(_UNICODE) + +#ifdef _WINGDI_ +///////////////////////////////////////////////////////////////////////////// +// Global UNICODE<>ANSI translation helpers +inline LPDEVMODEW AtlDevModeA2W(__out LPDEVMODEW lpDevModeW, __in const DEVMODEA* lpDevModeA) +{ + USES_CONVERSION_EX; + ATLASSERT(lpDevModeW != NULL); + if (lpDevModeA == NULL || lpDevModeW == NULL) + { + return NULL; + } + + AtlA2WHelper(lpDevModeW->dmDeviceName, (LPCSTR)lpDevModeA->dmDeviceName, 32, _acp_ex); + +#if _SECURE_ATL + if(0 != memcpy_s(&lpDevModeW->dmSpecVersion, offsetof(DEVMODEW, dmFormName) - offsetof(DEVMODEW, dmSpecVersion), + &lpDevModeA->dmSpecVersion, offsetof(DEVMODEW, dmFormName) - offsetof(DEVMODEW, dmSpecVersion))) + { + return NULL; + } +#else + memcpy(&lpDevModeW->dmSpecVersion, &lpDevModeA->dmSpecVersion, + offsetof(DEVMODEW, dmFormName) - offsetof(DEVMODEW, dmSpecVersion)); +#endif + + AtlA2WHelper(lpDevModeW->dmFormName, (LPCSTR)lpDevModeA->dmFormName, 32, _acp_ex); + +#if _SECURE_ATL + if(0 != memcpy_s(&lpDevModeW->dmLogPixels, sizeof(DEVMODEW) - offsetof(DEVMODEW, dmLogPixels), + &lpDevModeA->dmLogPixels, sizeof(DEVMODEW) - offsetof(DEVMODEW, dmLogPixels))) + { + return NULL; + } +#else + memcpy(&lpDevModeW->dmLogPixels, &lpDevModeA->dmLogPixels, + sizeof(DEVMODEW) - offsetof(DEVMODEW, dmLogPixels)); +#endif + + if (lpDevModeA->dmDriverExtra != 0) + { + // lpDevModeW holds more info +#pragma warning(push) +// +// [pfx_parse] - workaround for PREfix parse problem +// +#if ((defined(_PREFIX_)) || (defined(_PREFAST_))) && (_MSC_VER < 1400) + // do nothing, this pragma not understood by PREfix 5.1 +#else // !_PREFIX_ +#pragma warning(disable:26000) +#endif +#if _SECURE_ATL + if(0 != memcpy_s(lpDevModeW+1, lpDevModeA->dmDriverExtra, lpDevModeA+1, lpDevModeA->dmDriverExtra)) + { + return NULL; + } +#else + memcpy(lpDevModeW+1, lpDevModeA+1, lpDevModeA->dmDriverExtra); +#endif +#pragma warning(pop) + } + lpDevModeW->dmSize = sizeof(DEVMODEW); + return lpDevModeW; +} + +inline LPTEXTMETRICW AtlTextMetricA2W(__out LPTEXTMETRICW lptmW, __in LPTEXTMETRICA lptmA) +{ + USES_CONVERSION_EX; + ATLASSERT(lptmW != NULL); + if (lptmA == NULL || lptmW == NULL) + return NULL; + +#if _SECURE_ATL + if(0 != memcpy_s(lptmW, sizeof(LONG) * 11, lptmA, sizeof(LONG) * 11)) + { + return NULL; + } +#else + memcpy(lptmW, lptmA, sizeof(LONG) * 11); +#endif + +#if _SECURE_ATL + if(0 != memcpy_s(&lptmW->tmItalic, sizeof(BYTE) * 5, &lptmA->tmItalic, sizeof(BYTE) * 5)) + { + return NULL; + } +#else + memcpy(&lptmW->tmItalic, &lptmA->tmItalic, sizeof(BYTE) * 5); +#endif + + if(MultiByteToWideChar(_acp_ex, 0, (LPCSTR)&lptmA->tmFirstChar, 1, &lptmW->tmFirstChar, 1) == 0) + { + ATLASSERT(FALSE); + return NULL; + } + + if(MultiByteToWideChar(_acp_ex, 0, (LPCSTR)&lptmA->tmLastChar, 1, &lptmW->tmLastChar, 1) == 0) + { + ATLASSERT(FALSE); + return NULL; + } + + if(MultiByteToWideChar(_acp_ex, 0, (LPCSTR)&lptmA->tmDefaultChar, 1, &lptmW->tmDefaultChar, 1)== 0) + { + ATLASSERT(FALSE); + return NULL; + } + + if(MultiByteToWideChar(_acp_ex, 0, (LPCSTR)&lptmA->tmBreakChar, 1, &lptmW->tmBreakChar, 1) == 0) + { + ATLASSERT(FALSE); + return NULL; + } + + return lptmW; +} + +inline LPTEXTMETRICA AtlTextMetricW2A(__out LPTEXTMETRICA lptmA, __in LPTEXTMETRICW lptmW) +{ + USES_CONVERSION_EX; + ATLASSERT(lptmA != NULL); + if (lptmW == NULL || lptmA == NULL) + { + return NULL; + } + +#if _SECURE_ATL + if(0 != memcpy_s(lptmA, sizeof(LONG) * 11, lptmW, sizeof(LONG) * 11)) + { + return NULL; + } +#else + memcpy(lptmA, lptmW, sizeof(LONG) * 11); +#endif + +#if _SECURE_ATL + if(0 != memcpy_s(&lptmA->tmItalic, sizeof(BYTE) * 5, &lptmW->tmItalic, sizeof(BYTE) * 5)) + { + return NULL; + } +#else + memcpy(&lptmA->tmItalic, &lptmW->tmItalic, sizeof(BYTE) * 5); +#endif + + if(WideCharToMultiByte(_acp_ex, 0, &lptmW->tmFirstChar, 1, (LPSTR)&lptmA->tmFirstChar, 1, NULL, NULL) == 0) + { + ATLASSERT(FALSE); + return NULL; + } + + if(WideCharToMultiByte(_acp_ex, 0, &lptmW->tmLastChar, 1, (LPSTR)&lptmA->tmLastChar, 1, NULL, NULL) == 0) + { + ATLASSERT(FALSE); + return NULL; + } + + if(WideCharToMultiByte(_acp_ex, 0, &lptmW->tmDefaultChar, 1, (LPSTR)&lptmA->tmDefaultChar, 1, NULL, NULL) == 0) + { + ATLASSERT(FALSE); + return NULL; + } + + if(WideCharToMultiByte(_acp_ex, 0, &lptmW->tmBreakChar, 1, (LPSTR)&lptmA->tmBreakChar, 1, NULL, NULL) == 0) + { + ATLASSERT(FALSE); + return NULL; + } + + return lptmA; +} + +#ifndef ATLDEVMODEA2W +#define ATLDEVMODEA2W AtlDevModeA2W +#define ATLDEVMODEW2A AtlDevModeW2A +#define ATLTEXTMETRICA2W AtlTextMetricA2W +#define ATLTEXTMETRICW2A AtlTextMetricW2A +#endif + +// Requires USES_CONVERSION_EX or USES_ATL_SAFE_ALLOCA macro before using the _EX versions of the macros +#define DEVMODEW2A_EX(lpw)\ + (((lpw) == NULL) ? NULL : ATLDEVMODEW2A((LPDEVMODEA)_ATL_SAFE_ALLOCA(sizeof(DEVMODEA)+(lpw)->dmDriverExtra, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), (lpw))) +#define DEVMODEA2W_EX(lpa)\ + (((lpa) == NULL) ? NULL : ATLDEVMODEA2W((LPDEVMODEW)_ATL_SAFE_ALLOCA(sizeof(DEVMODEW)+(lpa)->dmDriverExtra, _ATL_SAFE_ALLOCA_DEF_THRESHOLD), (lpa))) +#define TEXTMETRICW2A_EX(lptmw)\ + (((lptmw) == NULL) ? NULL : ATLTEXTMETRICW2A((LPTEXTMETRICA)_ATL_SAFE_ALLOCA(sizeof(TEXTMETRICA), _ATL_SAFE_ALLOCA_DEF_THRESHOLD), (lptmw))) +#define TEXTMETRICA2W_EX(lptma)\ + (((lptma) == NULL) ? NULL : ATLTEXTMETRICA2W((LPTEXTMETRICW)_ATL_SAFE_ALLOCA(sizeof(TEXTMETRICW), _ATL_SAFE_ALLOCA_DEF_THRESHOLD), (lptma))) + +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + +#define DEVMODEW2A(lpw)\ + ((lpw == NULL) ? NULL : ATLDEVMODEW2A((LPDEVMODEA)alloca(sizeof(DEVMODEA)+lpw->dmDriverExtra), lpw)) +#define DEVMODEA2W(lpa)\ + ((lpa == NULL) ? NULL : ATLDEVMODEA2W((LPDEVMODEW)alloca(sizeof(DEVMODEW)+lpa->dmDriverExtra), lpa)) +#define TEXTMETRICW2A(lptmw)\ + ((lptmw == NULL) ? NULL : ATLTEXTMETRICW2A((LPTEXTMETRICA)alloca(sizeof(TEXTMETRICA)), lptmw)) +#define TEXTMETRICA2W(lptma)\ + ((lptma == NULL) ? NULL : ATLTEXTMETRICA2W((LPTEXTMETRICW)alloca(sizeof(TEXTMETRICW)), lptma)) + +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#define DEVMODEOLE DEVMODEW +#define LPDEVMODEOLE LPDEVMODEW +#define TEXTMETRICOLE TEXTMETRICW +#define LPTEXTMETRICOLE LPTEXTMETRICW + +#if defined(_UNICODE) +// in these cases the default (TCHAR) is the same as OLECHAR + inline LPDEVMODEW DEVMODEOLE2T_EX(LPDEVMODEOLE lp) { return lp; } + inline LPDEVMODEOLE DEVMODET2OLE_EX(LPDEVMODEW lp) { return lp; } + inline LPTEXTMETRICW TEXTMETRICOLE2T_EX(LPTEXTMETRICOLE lp) { return lp; } + inline LPTEXTMETRICOLE TEXTMETRICT2OLE_EX(LPTEXTMETRICW lp) { return lp; } +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + inline LPDEVMODEW DEVMODEOLE2T(LPDEVMODEOLE lp) { return lp; } + inline LPDEVMODEOLE DEVMODET2OLE(LPDEVMODEW lp) { return lp; } + inline LPTEXTMETRICW TEXTMETRICOLE2T(LPTEXTMETRICOLE lp) { return lp; } + inline LPTEXTMETRICOLE TEXTMETRICT2OLE(LPTEXTMETRICW lp) { return lp; } +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#else // !defined(_UNICODE) + #define DEVMODEOLE2T_EX(lpo) DEVMODEW2A_EX(lpo) + #define DEVMODET2OLE_EX(lpa) DEVMODEA2W_EX(lpa) + #define TEXTMETRICOLE2T_EX(lptmw) TEXTMETRICW2A_EX(lptmw) + #define TEXTMETRICT2OLE_EX(lptma) TEXTMETRICA2W_EX(lptma) +#ifndef _ATL_EX_CONVERSION_MACROS_ONLY + #define DEVMODEOLE2T(lpo) DEVMODEW2A(lpo) + #define DEVMODET2OLE(lpa) DEVMODEA2W(lpa) + #define TEXTMETRICOLE2T(lptmw) TEXTMETRICW2A(lptmw) + #define TEXTMETRICT2OLE(lptma) TEXTMETRICA2W(lptma) +#endif // _ATL_EX_CONVERSION_MACROS_ONLY + +#endif // defined(_UNICODE) + +#endif //_WINGDI_ + +#pragma pack(pop) + +///////////////////////////////////////////////////////////////////////////// + +#ifndef _ATL_DLL + +#ifdef _WINGDI_ + +ATLINLINE ATLAPI_(LPDEVMODEA) AtlDevModeW2A(__out LPDEVMODEA lpDevModeA, __in const DEVMODEW* lpDevModeW) +{ + USES_CONVERSION_EX; + ATLASSERT(lpDevModeA != NULL); + if (lpDevModeW == NULL || lpDevModeA == NULL) + return NULL; + + AtlW2AHelper((LPSTR)lpDevModeA->dmDeviceName, lpDevModeW->dmDeviceName, 32, _acp_ex); + +#if _SECURE_ATL + if(0 != memcpy_s(&lpDevModeA->dmSpecVersion, offsetof(DEVMODEA, dmFormName) - offsetof(DEVMODEA, dmSpecVersion), + &lpDevModeW->dmSpecVersion, offsetof(DEVMODEA, dmFormName) - offsetof(DEVMODEA, dmSpecVersion))) + { + return NULL; + } +#else + memcpy(&lpDevModeA->dmSpecVersion, &lpDevModeW->dmSpecVersion, + offsetof(DEVMODEA, dmFormName) - offsetof(DEVMODEA, dmSpecVersion)); +#endif + + AtlW2AHelper((LPSTR)lpDevModeA->dmFormName, lpDevModeW->dmFormName, 32, _acp_ex); + +#if _SECURE_ATL + if(0 != memcpy_s(&lpDevModeA->dmLogPixels, sizeof(DEVMODEA) - offsetof(DEVMODEA, dmLogPixels), + &lpDevModeW->dmLogPixels, sizeof(DEVMODEA) - offsetof(DEVMODEA, dmLogPixels))) + { + return NULL; + } +#else + memcpy(&lpDevModeA->dmLogPixels, &lpDevModeW->dmLogPixels, + sizeof(DEVMODEA) - offsetof(DEVMODEA, dmLogPixels)); +#endif + + if (lpDevModeW->dmDriverExtra != 0) + { + // lpDevModeW holds more info +#pragma warning(push) +// +// [pfx_parse] - workaround for PREfix parse problem +// +#if ((defined(_PREFIX_)) || (defined(_PREFAST_))) && (_MSC_VER < 1400) + // do nothing, this pragma not understood by PREfix 5.1 +#else // !_PREFIX_ +#pragma warning(disable:26000) +#endif +#if _SECURE_ATL + if(0 != memcpy_s(lpDevModeA+1, lpDevModeW->dmDriverExtra, lpDevModeW+1, lpDevModeW->dmDriverExtra)) + { + return NULL; + } +#else + memcpy(lpDevModeA+1, lpDevModeW+1, lpDevModeW->dmDriverExtra); +#endif +#pragma warning(pop) + } + + lpDevModeA->dmSize = sizeof(DEVMODEA); + return lpDevModeA; +} + +#endif //_WINGDI + +#endif // !_ATL_DLL + +// +// [pfx_parse] - workaround for old PREfix/PREfast parser +// +#if (defined(_PREFIX_) || defined(_PREFAST_)) && (_MSC_VER < 1400) +#pragma warning (pop) +#endif // old PREfast parser + +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning (pop) +#endif //!_ATL_NO_PRAGMA_WARNINGS + +#endif // __ATLCONV_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcore.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcore.h new file mode 100644 index 00000000..91a33334 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcore.h @@ -0,0 +1,554 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCORE_H__ +#define __ATLCORE_H__ + +#pragma once + +#ifdef _ATL_ALL_WARNINGS +#pragma warning( push ) +#endif + +#pragma warning(disable: 4786) // identifier was truncated in the debug information +#pragma warning(disable: 4127) // constant expression + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ +///////////////////////////////////////////////////////////////////////////// +// Verify that a null-terminated string points to valid memory +inline BOOL AtlIsValidString(LPCWSTR psz, size_t nMaxLength = INT_MAX) +{ + (nMaxLength); + return (psz != NULL); +} + +// Verify that a null-terminated string points to valid memory +inline BOOL AtlIsValidString(LPCSTR psz, size_t nMaxLength = UINT_MAX) +{ + (nMaxLength); + return (psz != NULL); +} + +// Verify that a pointer points to valid memory +inline BOOL AtlIsValidAddress(const void* p, size_t nBytes, + BOOL bReadWrite = TRUE) +{ + (bReadWrite); + (nBytes); + return (p != NULL); +} + +template +inline void AtlAssertValidObject(const T *pOb) +{ + ATLASSERT(pOb); + ATLASSERT(AtlIsValidAddress(pOb, sizeof(T))); + if(pOb) + pOb->AssertValid(); +} +#ifdef _DEBUG +#define ATLASSERT_VALID(x) ATL::AtlAssertValidObject(x) +#else +#define ATLASSERT_VALID(x) __noop; +#endif + +// COM Sync Classes +class CComCriticalSection +{ +public: + CComCriticalSection() throw() + { + memset(&m_sec, 0, sizeof(CRITICAL_SECTION)); + } + ~CComCriticalSection() + { + } + HRESULT Lock() throw() + { + EnterCriticalSection(&m_sec); + return S_OK; + } + HRESULT Unlock() throw() + { + LeaveCriticalSection(&m_sec); + return S_OK; + } + HRESULT Init() throw() + { + HRESULT hRes = E_FAIL; + __try + { + InitializeCriticalSection(&m_sec); + hRes = S_OK; + } + // structured exception may be raised in low memory situations + __except(STATUS_NO_MEMORY == GetExceptionCode()) + { + hRes = E_OUTOFMEMORY; + } + return hRes; + } + + HRESULT Term() throw() + { + DeleteCriticalSection(&m_sec); + return S_OK; + } + CRITICAL_SECTION m_sec; +}; + +class CComAutoCriticalSection : public CComCriticalSection +{ +public: + CComAutoCriticalSection() + { + HRESULT hr = CComCriticalSection::Init(); + if (FAILED(hr)) + AtlThrow(hr); + } + ~CComAutoCriticalSection() throw() + { + CComCriticalSection::Term(); + } +private : + HRESULT Init(); // Not implemented. CComAutoCriticalSection::Init should never be called + HRESULT Term(); // Not implemented. CComAutoCriticalSection::Term should never be called +}; + +class CComSafeDeleteCriticalSection : public CComCriticalSection +{ +public: + CComSafeDeleteCriticalSection(): m_bInitialized(false) + { + } + + ~CComSafeDeleteCriticalSection() throw() + { + if (!m_bInitialized) + { + return; + } + m_bInitialized = false; + CComCriticalSection::Term(); + } + + HRESULT Init() throw() + { + ATLASSERT( !m_bInitialized ); + HRESULT hr = CComCriticalSection::Init(); + if (SUCCEEDED(hr)) + { + m_bInitialized = true; + } + return hr; + } + + HRESULT Term() throw() + { + if (!m_bInitialized) + { + return S_OK; + } + m_bInitialized = false; + return CComCriticalSection::Term(); + } + + HRESULT Lock() + { + // CComSafeDeleteCriticalSection::Init or CComAutoDeleteCriticalSection::Init + // not called or failed. + // m_critsec member of CComObjectRootEx is now of type + // CComAutoDeleteCriticalSection. It has to be initialized + // by calling CComObjectRootEx::_AtlInitialConstruct + ATLASSUME(m_bInitialized); + return CComCriticalSection::Lock(); + } + +private: + bool m_bInitialized; +}; + +class CComAutoDeleteCriticalSection : public CComSafeDeleteCriticalSection +{ +private: + // CComAutoDeleteCriticalSection::Term should never be called + HRESULT Term() throw(); +}; + +class CComFakeCriticalSection +{ +public: + HRESULT Lock() throw() { return S_OK; } + HRESULT Unlock() throw() { return S_OK; } + HRESULT Init() throw() { return S_OK; } + HRESULT Term() throw() { return S_OK; } +}; + +///////////////////////////////////////////////////////////////////////////// +// Module + +// Used by any project that uses ATL +struct _ATL_BASE_MODULE70 +{ + UINT cbSize; + HINSTANCE m_hInst; + HINSTANCE m_hInstResource; + bool m_bNT5orWin98; + DWORD dwAtlBuildVer; + const GUID* pguidVer; + CComCriticalSection m_csResource; + CSimpleArray m_rgResourceInstance; +}; +typedef _ATL_BASE_MODULE70 _ATL_BASE_MODULE; + +class CAtlBaseModule : public _ATL_BASE_MODULE +{ +public : + static bool m_bInitFailed; + CAtlBaseModule() throw(); + ~CAtlBaseModule() throw (); + + HINSTANCE GetModuleInstance() throw() + { + return m_hInst; + } + HINSTANCE GetResourceInstance() throw() + { + return m_hInstResource; + } + HINSTANCE SetResourceInstance(HINSTANCE hInst) throw() + { + return static_cast< HINSTANCE >(InterlockedExchangePointer((void**)&m_hInstResource, hInst)); + } + + bool AddResourceInstance(HINSTANCE hInst) throw(); + bool RemoveResourceInstance(HINSTANCE hInst) throw(); + HINSTANCE GetHInstanceAt(int i) throw(); +}; + +__declspec(selectany) bool CAtlBaseModule::m_bInitFailed = false; +extern CAtlBaseModule _AtlBaseModule; + +///////////////////////////////////////////////////////////////////////////// +// String resource helpers + +#pragma warning(push) +#pragma warning(disable: 4200) + struct ATLSTRINGRESOURCEIMAGE + { + WORD nLength; + __field_ecount(nLength) WCHAR achString[]; + }; +#pragma warning(pop) // C4200 + +inline const ATLSTRINGRESOURCEIMAGE* _AtlGetStringResourceImage( HINSTANCE hInstance, HRSRC hResource, UINT id ) throw() +{ + const ATLSTRINGRESOURCEIMAGE* pImage; + const ATLSTRINGRESOURCEIMAGE* pImageEnd; + ULONG nResourceSize; + HGLOBAL hGlobal; + UINT iIndex; + + hGlobal = ::LoadResource( hInstance, hResource ); + if( hGlobal == NULL ) + { + return( NULL ); + } + + pImage = (const ATLSTRINGRESOURCEIMAGE*)::LockResource( hGlobal ); + if( pImage == NULL ) + { + return( NULL ); + } + + nResourceSize = ::SizeofResource( hInstance, hResource ); + pImageEnd = (const ATLSTRINGRESOURCEIMAGE*)(LPBYTE( pImage )+nResourceSize); + iIndex = id&0x000f; + + while( (iIndex > 0) && (pImage < pImageEnd) ) + { + pImage = (const ATLSTRINGRESOURCEIMAGE*)(LPBYTE( pImage )+(sizeof( ATLSTRINGRESOURCEIMAGE )+(pImage->nLength*sizeof( WCHAR )))); + iIndex--; + } + if( pImage >= pImageEnd ) + { + return( NULL ); + } + if( pImage->nLength == 0 ) + { + return( NULL ); + } + + return( pImage ); +} + +inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( HINSTANCE hInstance, UINT id ) throw() +{ + HRSRC hResource; + + hResource = ::FindResource( hInstance, MAKEINTRESOURCE( ((id>>4)+1) ), RT_STRING ); + if( hResource == NULL ) + { + return( NULL ); + } + + return _AtlGetStringResourceImage( hInstance, hResource, id ); +} + +inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( HINSTANCE hInstance, UINT id, WORD wLanguage ) throw() +{ + HRSRC hResource; + + hResource = ::FindResourceEx( hInstance, RT_STRING, MAKEINTRESOURCE( ((id>>4)+1) ), wLanguage ); + if( hResource == NULL ) + { + return( NULL ); + } + + return _AtlGetStringResourceImage( hInstance, hResource, id ); +} + +inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( UINT id ) throw() +{ + const ATLSTRINGRESOURCEIMAGE* p = NULL; + HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0); + + for (int i = 1; hInst != NULL && p == NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++)) + { + p = AtlGetStringResourceImage(hInst, id); + } + return p; +} + +inline const ATLSTRINGRESOURCEIMAGE* AtlGetStringResourceImage( UINT id, WORD wLanguage ) throw() +{ + const ATLSTRINGRESOURCEIMAGE* p = NULL; + HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0); + + for (int i = 1; hInst != NULL && p == NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++)) + { + p = AtlGetStringResourceImage(hInst, id, wLanguage); + } + return p; +} + +inline int AtlLoadString(__in UINT nID, __out_ecount_part_z(nBufferMax, return + 1) LPTSTR lpBuffer, __in int nBufferMax) throw() +{ + HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0); + int nRet = 0; + + for (int i = 1; hInst != NULL && nRet == 0; hInst = _AtlBaseModule.GetHInstanceAt(i++)) + { + nRet = LoadString(hInst, nID, lpBuffer, nBufferMax); + } + return nRet; +} + +inline HINSTANCE AtlFindResourceInstance(LPCTSTR lpName, LPCTSTR lpType, WORD wLanguage = 0) throw() +{ + ATLASSERT(lpType != RT_STRING); // Call AtlFindStringResourceInstance to find the string + if (lpType == RT_STRING) + return NULL; + + if (ATL_IS_INTRESOURCE(lpType)) + { + /* Prefast false warnings caused by bad-shaped definition of MAKEINTRESOURCE macro from PSDK */ + if (lpType == ATL_RT_ICON) + { + lpType = ATL_RT_GROUP_ICON; + } + else if (lpType == ATL_RT_CURSOR) + { + lpType = ATL_RT_GROUP_CURSOR; + } + } + + HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0); + HRSRC hResource = NULL; + + for (int i = 1; hInst != NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++)) + { + hResource = ::FindResourceEx(hInst, lpType, lpName, wLanguage); + if (hResource != NULL) + { + return hInst; + } + } + + return NULL; +} + +inline HINSTANCE AtlFindResourceInstance(UINT nID, LPCTSTR lpType, WORD wLanguage = 0) throw() +{ + return AtlFindResourceInstance(MAKEINTRESOURCE(nID), lpType, wLanguage); +} + +inline HINSTANCE AtlFindStringResourceInstance(UINT nID, WORD wLanguage = 0) throw() +{ + const ATLSTRINGRESOURCEIMAGE* p = NULL; + HINSTANCE hInst = _AtlBaseModule.GetHInstanceAt(0); + + for (int i = 1; hInst != NULL && p == NULL; hInst = _AtlBaseModule.GetHInstanceAt(i++)) + { + p = AtlGetStringResourceImage(hInst, nID, wLanguage); + if (p != NULL) + return hInst; + } + + return NULL; +} + +/* +Needed by both atlcomcli and atlsafe, so needs to be in here +*/ +inline HRESULT AtlSafeArrayGetActualVartype +( + SAFEARRAY *psaArray, + VARTYPE *pvtType +) +{ + HRESULT hrSystem=::SafeArrayGetVartype(psaArray, pvtType); + + if(FAILED(hrSystem)) + { + return hrSystem; + } + + /* + When Windows has a SAFEARRAY of type VT_DISPATCH with FADF_HAVEIID, + it returns VT_UNKNOWN instead of VT_DISPATCH. We patch the value to be correct + */ + if(pvtType && *pvtType==VT_UNKNOWN) + { + if(psaArray && ((psaArray->fFeatures & FADF_HAVEIID)!=0)) + { + if(psaArray->fFeatures & FADF_DISPATCH) + { + *pvtType=VT_DISPATCH; + } + } + } + + return hrSystem; +} +template +inline _CharType* AtlCharNext(const _CharType* p) throw() +{ + ATLASSUME(p != NULL); // Too expensive to check separately here + if (*p == '\0') // ::CharNextA won't increment if we're at a \0 already + return const_cast<_CharType*>(p+1); + else + return ::CharNextA(p); +} + +template <> +inline wchar_t* AtlCharNext(const wchar_t* p) throw() +{ + return const_cast< wchar_t* >( p+1 ); +} +template +inline const CharType* AtlstrchrT(const CharType* p, CharType ch) throw() +{ + ATLASSERT(p != NULL); + if(p==NULL) + { + return NULL; + } + while( *p != 0 ) + { + if (*p == ch) + { + return p; + } + p = AtlCharNext(p); + } + //strchr for '\0' should succeed - the while loop terminates + //*p == 0, but ch also == 0, so NULL terminator address is returned + return (*p == ch) ? p : NULL; +} +//Ansi and Unicode versions of printf, used with templated CharType trait classes. +#pragma warning(push) +#pragma warning(disable : 4793) +template +inline int AtlprintfT(const CharType* pszFormat,... ) throw() +{ + int retval=0; + va_list argList; + va_start( argList, pszFormat ); + retval=vprintf(pszFormat,argList); + va_end( argList ); + return retval; +} +#pragma warning(pop) + +#pragma warning(push) +#pragma warning(disable : 4793) +template<> +inline int AtlprintfT(const wchar_t* pszFormat,... ) throw() +{ + int retval=0; + va_list argList; + va_start( argList, pszFormat ); + retval=vwprintf(pszFormat, argList); + va_end( argList ); + return retval; +} +#pragma warning(pop) + +#pragma warning(push) +#pragma warning(disable : 4068 28110) + +inline BOOL AtlConvertSystemTimeToVariantTime(const SYSTEMTIME& systimeSrc,double* pVarDtTm) +{ + ATLENSURE(pVarDtTm!=NULL); + //Convert using ::SystemTimeToVariantTime and store the result in pVarDtTm then + //convert variant time back to system time and compare to original system time. + + BOOL ok = ::SystemTimeToVariantTime(const_cast(&systimeSrc), pVarDtTm); + + SYSTEMTIME sysTime; + ::ZeroMemory(&sysTime, sizeof(SYSTEMTIME)); + + ok = ok && ::VariantTimeToSystemTime(*pVarDtTm, &sysTime); + ok = ok && (systimeSrc.wYear == sysTime.wYear && + systimeSrc.wMonth == sysTime.wMonth && + systimeSrc.wDay == sysTime.wDay && + systimeSrc.wHour == sysTime.wHour && + systimeSrc.wMinute == sysTime.wMinute && + systimeSrc.wSecond == sysTime.wSecond); + + return ok; +} +#pragma warning(pop) + +///////////////////////////////////////////////////////////////////////////// + +} // namespace ATL +#pragma pack(pop) + +#ifdef _ATL_ALL_WARNINGS +#pragma warning( pop ) +#endif + +#endif // __ATLCORE_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcrypt.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcrypt.h new file mode 100644 index 00000000..9e18cacb --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcrypt.h @@ -0,0 +1,348 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCRYPT_H__ +#define __ATLCRYPT_H__ + +#pragma once + +#include +#include + + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ + +class CCryptKey; + +class CCryptProv +{ +protected: + HCRYPTPROV m_hProv; + +public: + CCryptProv() throw(); + CCryptProv( const CCryptProv& prov ) throw(); + explicit CCryptProv( HCRYPTPROV hProv, BOOL bTakeOwnership = FALSE ) throw(); + ~CCryptProv() throw(); + + CCryptProv& operator=( const CCryptProv& prov ) throw(); + + HRESULT AddRef() throw(); + void Attach( HCRYPTPROV hProv, BOOL bTakeOwnership = FALSE ) throw(); + HCRYPTPROV Detach() throw(); + HRESULT Release() throw(); + + + HRESULT Initialize(DWORD dwProviderType = PROV_RSA_FULL, + LPCTSTR szContainer = NULL, LPCTSTR szProvider = MS_DEF_PROV, + DWORD dwFlags = 0) throw(); + HRESULT InitVerifyContext(DWORD dwProviderType = PROV_RSA_FULL, + LPCTSTR szProvider = MS_DEF_PROV, DWORD dwFlags = 0) throw(); + HRESULT InitCreateKeySet(DWORD dwProviderType = PROV_RSA_FULL, + LPCTSTR szContainer = NULL, LPCTSTR szProvider = MS_DEF_PROV, + DWORD dwFlags = 0) throw(); + + HRESULT DeleteKeySet(DWORD dwProviderType = PROV_RSA_FULL, + LPCTSTR szContainer = NULL, LPCTSTR szProvider = MS_DEF_PROV, + DWORD dwFlags = 0) throw(); + + HRESULT Uninitialize(); + + HRESULT GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags = 0) throw(); + HRESULT SetParam( DWORD dwParam, BYTE* pbData, DWORD dwFlags = 0) throw(); + HRESULT GetName(__out_ecount_part_z(*pdwLength, *pdwLength) LPSTR szBuf, __inout DWORD * pdwLength) throw(); + HRESULT GetContainer(__out_ecount_part_z(*pdwLength, *pdwLength) LPSTR szBuf, __inout DWORD * pdwLength) throw(); + HRESULT GetImpType(DWORD * pdwImpType) throw(); + HRESULT GetVersion(DWORD * pdwVersion) throw(); + HRESULT GetProvType(DWORD * pdwType) throw(); + HRESULT GetSecurityDesc(SECURITY_INFORMATION * pSecInfo) throw(); + HRESULT SetSecurityDesc(SECURITY_INFORMATION SecInfo) throw(); + + HRESULT GenRandom(ULONG nLength, BYTE* pbBuffer ) throw(); + + inline HCRYPTPROV GetHandle() throw() + { + return m_hProv; + } +}; // class CCryptProv + + +// class CCryptHash +// Provides base functionality of hashes. +class CCryptHash +{ +protected: + HCRYPTHASH m_hHash; + +public: + CCryptHash() throw(); + CCryptHash( const CCryptHash& hash ) throw(); + explicit CCryptHash( HCRYPTHASH hHash, BOOL bTakeOwnership = FALSE ) throw(); + ~CCryptHash() throw(); + + void Attach( HCRYPTHASH hHash, BOOL bTakeOwnership = FALSE ) throw(); + void Destroy() throw(); + HCRYPTHASH Detach() throw(); + HCRYPTHASH Duplicate() const throw(); + + HRESULT Uninitialize() throw(); + HRESULT Detach(HCRYPTHASH * phHash) throw(); + HRESULT AddData(const BYTE * pbData, DWORD dwDataLen, DWORD dwFlags = 0) throw(); + HRESULT AddString(LPCTSTR szData, DWORD dwFlags = 0) throw(); + HRESULT GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags = 0) throw(); + HRESULT SetParam(DWORD dwParam, BYTE * pbData, DWORD dwFlags = 0) throw(); + HRESULT GetAlgId(ALG_ID * pAlgId) throw(); + HRESULT GetSize(DWORD * pdwSize) throw(); + HRESULT GetValue(BYTE * pBuf, DWORD * pdwSize) throw(); + HRESULT SetValue(BYTE * pBuf) throw(); + HRESULT Sign( + BYTE * pbSignature, + DWORD * pdwSigLen, + DWORD dwFlags = 0, + DWORD dwKeySpec = AT_SIGNATURE) throw(); + HRESULT VerifySignature( + const BYTE * pbSignature, + DWORD pdwSignLen, + CCryptKey &PubKey, + DWORD dwFlags = 0) throw(); + + inline HCRYPTHASH GetHandle() + { + return m_hHash; + } + static CCryptHash EmptyHash; + +}; // class CCryptHash + +// class CCryptKey +// Provides the functionality for cryptographic keys, i.e. encrypting, decrypting. +class CCryptKey +{ +protected: + HCRYPTKEY m_hKey; + +public: + CCryptKey() throw(); + CCryptKey( const CCryptKey& key ) throw(); + explicit CCryptKey( HCRYPTKEY hKey, BOOL bTakeOwnership = FALSE ) throw(); + ~CCryptKey() throw(); + + void Attach( HCRYPTKEY hKey, BOOL bTakeOwnership = FALSE ) throw(); + void Destroy() throw(); + HCRYPTKEY Detach() throw(); + HCRYPTKEY Duplicate() const throw(); + + HRESULT Uninitialize() throw(); + HRESULT Encrypt( + BOOL final, + BYTE * pbData, + DWORD * pdwDataLen, + DWORD dwBufLen, + CCryptHash &Hash = CCryptHash::EmptyHash) throw(); + + HRESULT Encrypt( + const BYTE * pbPlainText, + DWORD dwPlainTextLen, + BYTE * pbCipherText, + DWORD * pdwCipherTextLen, + CCryptHash &Hash = CCryptHash::EmptyHash) throw(); + + HRESULT Decrypt( + BOOL final, + BYTE * pbData, + DWORD * pdwDataLen, + CCryptHash &Hash = CCryptHash::EmptyHash) throw(); + HRESULT Decrypt( + const BYTE * pbCipherText, + DWORD dwCipherTextLen, + BYTE * pbPlainText, + DWORD * pdwPlainTextLen, + CCryptHash &Hash = CCryptHash::EmptyHash) throw(); + HRESULT EncryptString( + LPCTSTR szPlainText, + BYTE * pbCipherText, + DWORD * pdwCipherTextLen, + CCryptHash &Hash = CCryptHash::EmptyHash) throw(); + HRESULT ExportSimpleBlob( + CCryptKey &ExpKey, + DWORD dwFlags, + BYTE * pbData, + DWORD * pdwDataLen) throw(); + HRESULT ExportPublicKeyBlob( + CCryptKey &ExpKey, + DWORD dwFlags, + BYTE * pbData, + DWORD * pdwDataLen) throw(); + HRESULT ExportPrivateKeyBlob( + CCryptKey &ExpKey, + DWORD dwFlags, + BYTE * pbData, + DWORD * pdwDataLen) throw(); + HRESULT GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags = 0) throw(); + HRESULT SetParam(DWORD dwParam, BYTE * pbData, DWORD dwFlags = 0) throw(); + HRESULT GetAlgId(ALG_ID * pAlgId) throw(); + HRESULT SetAlgId(ALG_ID AlgId, DWORD dwFlags) throw(); + HRESULT GetBlockLength(DWORD * pdwBlockLen) throw(); + HRESULT GetKeyLength(DWORD * pdwKeyLen) throw(); + HRESULT GetSalt(BYTE * pbSalt, DWORD * pdwLength) throw(); + HRESULT SetSalt(BYTE * pbSalt) throw(); + HRESULT SetSaltEx(_CRYPTOAPI_BLOB * pBlobSalt) throw(); + HRESULT GetPermissions(DWORD * pdwPerms) throw(); + HRESULT SetPermissions(DWORD dwPerms) throw(); + HRESULT GetP(BYTE * pbP, DWORD * pdwLength) throw(); + HRESULT SetP(_CRYPTOAPI_BLOB * pBlobP) throw(); + HRESULT SetP(BYTE * pbP, DWORD dwLength) throw(); + HRESULT GetQ(BYTE * pbQ, DWORD * pdwLength) throw(); + HRESULT SetQ(_CRYPTOAPI_BLOB * pBlobQ) throw(); + HRESULT SetQ(BYTE * pbQ, DWORD dwLength) throw(); + HRESULT GetG(BYTE * pbG, DWORD * pdwLength) throw(); + HRESULT SetG(_CRYPTOAPI_BLOB * pBlobG) throw(); + HRESULT SetG(BYTE * pbG, DWORD dwLength) throw(); + HRESULT SetX() throw(); + HRESULT GetEffKeyLen(DWORD * pdwEffKeyLen) throw(); + HRESULT SetEffKeyLen(DWORD dwEffKeyLen) throw(); + HRESULT GetPadding(DWORD * pdwPadding) throw(); + HRESULT SetPadding(DWORD dwPadding) throw(); + HRESULT GetIV(BYTE * pbIV, DWORD * pdwLength) throw(); + HRESULT SetIV(BYTE * pbIV) throw(); + HRESULT GetMode(DWORD * pdwMode) throw(); + HRESULT SetMode(DWORD dwMode) throw(); + HRESULT GetModeBits(DWORD * pdwModeBits) throw(); + HRESULT SetModeBits(DWORD dwModeBits) throw(); + + inline HCRYPTKEY GetHandle() throw() + { + return m_hKey; + } + + static CCryptKey EmptyKey; +}; // class CCryptKey + + + +// Specific instances of Keys and Hashes + +// class CCryptDerivedKey +// A key that is derived from a hashed password. Two keys derived +// from the same password will be identical. +class CCryptDerivedKey : public CCryptKey +{ +public: + HRESULT Initialize( + CCryptProv &Prov, + CCryptHash &Hash, + ALG_ID algid = CALG_RC4, + DWORD dwFlags = CRYPT_EXPORTABLE) throw(); +}; // class CCryptDerivedKey + +// class CCryptRandomKey +// A randomly generated key. Can be used internally by a program +// to protect data during execution, or can be exported with Crypt.Export +// +// Currently it is possible to pass in AT_KEYEXCHANGE or AT_SIGNATURE +// for algid, but these two will generate keys for the current key set, and +// the resulting handle can only be used for exporting and importing keys or +// signing hashes. +class CCryptRandomKey : public CCryptKey +{ +public: + HRESULT Initialize( + CCryptProv &Prov, + ALG_ID algid = CALG_RC4, + DWORD dwFlags = CRYPT_EXPORTABLE) throw(); +}; // class CCryptRandomKey + +// class CCryptUserExKey +// Obtains the user's key exchange key pair. +class CCryptUserExKey : public CCryptKey +{ +public: + HRESULT Initialize(CCryptProv &Prov) throw(); + HRESULT Create(CCryptProv &Prov) throw(); +}; // class CCryptUserExKey + +// class CCryptUserSigKey +// Obtains the user's signature key pair +class CCryptUserSigKey : public CCryptKey +{ +public: + HRESULT Initialize(CCryptProv &Prov) throw(); + HRESULT Create(CCryptProv &Prov) throw(); +}; // class CCryptUserSigKey + +// class CCryptImportKey +// Forms a key from an imported key blob +class CCryptImportKey : public CCryptKey +{ +public: + HRESULT Initialize( + CCryptProv &Prov, + BYTE * pbData, + DWORD dwDataLen, + CCryptKey &PubKey, + DWORD dwFlags) throw(); +}; // class CCryptImportKey + + +// class CCryptHash +// A generic hash that may or may not take a key. +class CCryptKeyedHash : public CCryptHash +{ +public: + + HRESULT Initialize(CCryptProv &Prov, ALG_ID Algid, CCryptKey &Key, DWORD dwFlags) throw(); +}; // class CCryptKeyedHash + +// class CCryptSHAHash +// The Secure Hash Algorithm hash, from NIST and NSA. Technically, SHA-1. +class CCryptSHAHash : public CCryptHash +{ +public: + + HRESULT Initialize(CCryptProv &Prov, LPCTSTR szText = NULL) throw(); +}; // class CCryptSHAHash + +// The Secure Hash Algorithm, from NIST and NSA. Identical to CCryptSHA +typedef CCryptSHAHash CCryptSHA1Hash; + + +// class CCryptHMACHash +// Hash-base Message Authentication Code keyed hash +class CCryptHMACHash : public CCryptHash +{ +public: + HRESULT Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText = NULL) throw(); +}; // class CCryptHMACHash + +// class CCryptMACHash +// Message Authentication Code keyed hash. Believed to be less secure than HMAC +class CCryptMACHash : public CCryptHash +{ +public: + HRESULT Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText = NULL) throw(); +}; // class CCryptMACHash + +// class CCryptSSL3SHAMD5Hash +// Hash algorithm used by Secure Socket Layer +class CCryptSSL3SHAMD5Hash : public CCryptHash +{ +public: + HRESULT Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText = NULL) throw(); +}; // class CCryptSSl3SHAMD5Hash + +}; // namespace ATL + + +#include +#pragma pack(pop) +#endif // __ATLCRYPT_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcrypt.inl b/externals/WinDDK/7600.16385.1/inc/atl71/atlcrypt.inl new file mode 100644 index 00000000..4d6b0c07 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcrypt.inl @@ -0,0 +1,1023 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + + +#ifndef __ATLCRYPT_INL__ +#define __ATLCRYPT_INL__ + +#pragma once + +#ifndef __ATLCRYPT_H__ + #error atlcrypt.inl requires atlcrypt.h to be included first +#endif + + +namespace ATL +{ + +inline CCryptProv::CCryptProv( const CCryptProv& prov ) throw() +{ + m_hProv = prov.m_hProv; + if (m_hProv) + AddRef(); +} + +inline CCryptProv::CCryptProv( HCRYPTPROV hProv, BOOL bTakeOwnership ) throw() +{ + m_hProv = hProv; + if (m_hProv && !bTakeOwnership) + AddRef(); +} + +inline CCryptProv::~CCryptProv() throw() +{ + Release(); +} + +inline CCryptProv& CCryptProv::operator=( const CCryptProv& prov ) throw() +{ + if(this!=&prov) + { + Release(); + + m_hProv = prov.m_hProv; + if( m_hProv != NULL ) + { + AddRef(); + } + } + return( *this ); +} + +inline HRESULT CCryptProv::AddRef() throw() +{ + ATLASSUME( m_hProv != NULL ); + + if (!CryptContextAddRef( m_hProv, NULL, 0)) + { + return AtlHresultFromLastError(); + } + return S_OK; +} + +inline void CCryptProv::Attach( HCRYPTPROV hProv, BOOL bTakeOwnership ) throw() +{ + ATLASSUME( m_hProv == NULL ); + + m_hProv = hProv; + if (m_hProv && !bTakeOwnership) + AddRef(); +} + +inline HCRYPTPROV CCryptProv::Detach() throw() +{ + HCRYPTPROV hProv; + + hProv = m_hProv; + m_hProv = NULL; + + return( hProv ); +} + + +inline CCryptProv::CCryptProv() throw() : + m_hProv( NULL ) +{ +} + +inline HRESULT CCryptProv::Release() throw() +{ + if( m_hProv != NULL ) + { + if (!CryptReleaseContext( m_hProv, 0 )) + { + return AtlHresultFromLastError(); + } + m_hProv = NULL; + } + return S_OK; +} + +inline HRESULT CCryptProv::Initialize( + DWORD dwProviderType, + LPCTSTR szContainer, + LPCTSTR szProvider, + DWORD dwFlags) throw() +{ + ATLASSUME(m_hProv == NULL); + + if (!CryptAcquireContext(&m_hProv, szContainer, szProvider, dwProviderType, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptProv::InitVerifyContext( + DWORD dwProviderType, + LPCTSTR szProvider, + DWORD dwFlags) throw() +{ + ATLASSUME(m_hProv == NULL); + + if (!CryptAcquireContext(&m_hProv, NULL, szProvider, dwProviderType, CRYPT_VERIFYCONTEXT | dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptProv::InitCreateKeySet( + DWORD dwProviderType, + LPCTSTR szContainer, + LPCTSTR szProvider, + DWORD dwFlags) throw() +{ + ATLASSUME(m_hProv == NULL); + + if (!CryptAcquireContext(&m_hProv, szContainer, szProvider, dwProviderType, CRYPT_NEWKEYSET | dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptProv::DeleteKeySet( + DWORD dwProviderType, + LPCTSTR szContainer, + LPCTSTR szProvider, + DWORD dwFlags) throw() +{ + HCRYPTPROV hProv = NULL; + if (!CryptAcquireContext(&hProv, szContainer, szProvider, dwProviderType, CRYPT_DELETEKEYSET | dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + + +inline HRESULT CCryptProv::Uninitialize() throw() +{ + ATLASSUME(m_hProv != NULL); + + if (!CryptReleaseContext(m_hProv, 0)) + { + return AtlHresultFromLastError(); + } + else + { + m_hProv = NULL; + return S_OK; + } +} + +inline HRESULT CCryptProv::GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags) throw() +{ + ATLASSUME(m_hProv != NULL); + + if (!CryptGetProvParam(m_hProv, dwParam, pbData, pdwDataLen, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptProv::SetParam( DWORD dwParam, BYTE* pbData, DWORD dwFlags) throw() +{ + ATLASSUME(m_hProv != NULL); + + if (!CryptSetProvParam(m_hProv, dwParam, pbData, dwFlags )) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptProv::GetName(__out_bcount_part(*pdwLength, *pdwLength) LPSTR szBuf, __inout DWORD * pdwLength) throw() +{ + return GetParam(PP_NAME, (BYTE *)szBuf, pdwLength); +} + +inline HRESULT CCryptProv::GetContainer(__out_bcount_part(*pdwLength, *pdwLength) LPSTR szBuf, __inout DWORD * pdwLength) throw() +{ + return GetParam(PP_CONTAINER, (BYTE *)szBuf, pdwLength); +} + +inline HRESULT CCryptProv::GetImpType(DWORD * pdwImpType) throw() +{ + DWORD dwLength = sizeof(DWORD); + return GetParam(PP_IMPTYPE, (BYTE *)pdwImpType, &dwLength); +} + +inline HRESULT CCryptProv::GetVersion(DWORD * pdwVersion) throw() +{ + DWORD dwLength = sizeof(DWORD); + return GetParam(PP_VERSION, (BYTE *)pdwVersion, &dwLength); +} + +inline HRESULT CCryptProv::GetProvType(DWORD * pdwType) throw() +{ + DWORD dwLength = sizeof(DWORD); + return GetParam(PP_PROVTYPE, (BYTE * )pdwType, &dwLength); +} + +inline HRESULT CCryptProv::GetSecurityDesc(SECURITY_INFORMATION * pSecInfo) throw() +{ + DWORD dwSize = sizeof(SECURITY_INFORMATION); + return GetParam(PP_KEYSET_SEC_DESCR, (BYTE *)pSecInfo, &dwSize); +} + +inline HRESULT CCryptProv::SetSecurityDesc(SECURITY_INFORMATION SecInfo) throw() +{ + return SetParam(PP_KEYSET_SEC_DESCR, (BYTE *)&SecInfo); +} + +inline HRESULT CCryptProv::GenRandom(ULONG nLength, BYTE* pbBuffer ) throw() +{ + ATLASSUME(m_hProv != NULL); + + if (!CryptGenRandom( m_hProv, nLength, pbBuffer )) + { + return AtlHresultFromLastError(); + } + + return S_OK; +} + +inline CCryptHash::CCryptHash() throw() : + m_hHash( NULL ) +{ +} + +inline CCryptHash::CCryptHash( const CCryptHash& hash ) throw() +{ + m_hHash = hash.Duplicate(); +} + +inline CCryptHash::CCryptHash( HCRYPTHASH hHash, BOOL bTakeOwnership ) throw() +{ + if (bTakeOwnership) + m_hHash = hHash; + else + { + m_hHash = NULL; + BOOL bRet = ::CryptDuplicateHash( hHash, NULL, 0, &m_hHash ); + if (!bRet) + m_hHash = NULL; + } +} + +inline CCryptHash::~CCryptHash() throw() +{ + Destroy(); +} + +inline void CCryptHash::Attach( HCRYPTHASH hHash, BOOL bTakeOwnership ) throw() +{ + ATLASSUME( m_hHash == NULL ); + + if (bTakeOwnership) + m_hHash = hHash; + else + { + m_hHash = NULL; + BOOL bRet = ::CryptDuplicateHash( hHash, NULL, 0, &m_hHash ); + if (!bRet) + m_hHash = NULL; + } +} + +inline void CCryptHash::Destroy() throw() +{ + if( m_hHash != NULL ) + { + BOOL bSuccess; + + bSuccess = ::CryptDestroyHash( m_hHash ); + + // can fail if the cryptographic service provider + // (managed by CCryptProv) has already been destroyed + ATLASSERT( bSuccess ); + m_hHash = NULL; + } +} + +inline HCRYPTHASH CCryptHash::Detach() throw() +{ + HCRYPTHASH hHash; + + hHash = m_hHash; + m_hHash = NULL; + + return hHash; +} + +inline HCRYPTHASH CCryptHash::Duplicate() const throw() +{ + BOOL bSuccess; + HCRYPTHASH hHash; + + ATLASSUME( m_hHash != NULL ); + + hHash = NULL; + bSuccess = ::CryptDuplicateHash( m_hHash, NULL, 0, &hHash ); + if( !bSuccess ) + { + return NULL; + } + + return hHash; +} + +inline HRESULT CCryptHash::Uninitialize() throw() +{ + ATLASSUME(m_hHash != NULL); + + if (!CryptDestroyHash(m_hHash)) + { + return AtlHresultFromLastError(); + } + else + { + m_hHash = NULL; + return S_OK; + } +} + +inline HRESULT CCryptHash::Detach(HCRYPTHASH * phHash) throw() +{ + ATLASSERT(phHash); + if (!phHash) + return E_INVALIDARG; + + *phHash = m_hHash; + m_hHash = NULL; + + return S_OK; +} + +inline HRESULT CCryptHash::AddData(const BYTE * pbData, DWORD dwDataLen, DWORD dwFlags) throw() +{ + ATLASSUME(m_hHash != NULL); + + if (!CryptHashData(m_hHash, pbData, dwDataLen, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; + +} + +inline HRESULT CCryptHash::AddString(LPCTSTR szData, DWORD dwFlags) throw() +{ + return AddData((BYTE *)szData, (DWORD)_tcslen(szData) * sizeof(TCHAR), dwFlags); +} + +inline HRESULT CCryptHash::GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags) throw() +{ + ATLASSUME(m_hHash != NULL); + + if (!CryptGetHashParam(m_hHash, dwParam, pbData, pdwDataLen, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptHash::SetParam(DWORD dwParam, BYTE * pbData, DWORD dwFlags) throw() +{ + ATLASSUME(m_hHash != NULL); + + if (!CryptSetHashParam(m_hHash, dwParam, pbData, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptHash::GetAlgId(ALG_ID * pAlgId) throw() +{ + DWORD dwSize = sizeof(ALG_ID); + return GetParam(HP_ALGID, (BYTE *)pAlgId, &dwSize); +} + +inline HRESULT CCryptHash::GetSize(DWORD * pdwSize) throw() +{ + DWORD dwLength = sizeof(DWORD); + return GetParam(HP_HASHSIZE, (BYTE *)pdwSize, &dwLength); +} + +inline HRESULT CCryptHash::GetValue(BYTE * pBuf, DWORD * pdwSize) throw() +{ + return GetParam(HP_HASHVAL, pBuf, pdwSize); +} + +inline HRESULT CCryptHash::SetValue(BYTE * pBuf) throw() +{ + return SetParam(HP_HASHVAL, pBuf); +} + +inline HRESULT CCryptHash::Sign( + BYTE * pbSignature, + DWORD * pdwSigLen, + DWORD dwFlags, + DWORD dwKeySpec) throw() +{ + ATLASSUME(m_hHash != NULL); + + if (!CryptSignHash(m_hHash, dwKeySpec, NULL, dwFlags, pbSignature, pdwSigLen)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptHash::VerifySignature( + const BYTE * pbSignature, + DWORD dwSigLen, + CCryptKey &PubKey, + DWORD dwFlags) throw() +{ + ATLASSUME(m_hHash != NULL); + + if (!CryptVerifySignature(m_hHash, pbSignature, dwSigLen, PubKey.GetHandle(), NULL, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +__declspec(selectany) CCryptHash CCryptHash::EmptyHash = CCryptHash(); +__declspec(selectany) CCryptKey CCryptKey::EmptyKey = CCryptKey(); +inline CCryptKey::CCryptKey() throw() : + m_hKey( NULL ) +{ +} + +inline CCryptKey::CCryptKey( const CCryptKey& key ) throw() +{ + m_hKey = key.Duplicate(); +} + +inline CCryptKey::CCryptKey( HCRYPTKEY hKey, BOOL bTakeOwnership ) throw() +{ + if (bTakeOwnership) + m_hKey = hKey; + else + { + BOOL bSuccess = ::CryptDuplicateKey( hKey, NULL, 0, &m_hKey ); + if( !bSuccess ) + m_hKey = NULL; + } +} + +inline CCryptKey::~CCryptKey() throw() +{ + Destroy(); +} + +inline void CCryptKey::Attach( HCRYPTKEY hKey, BOOL bTakeOwnership ) throw() +{ + ATLASSUME( m_hKey == NULL ); + if (bTakeOwnership) + m_hKey = hKey; + else + { + BOOL bSuccess = ::CryptDuplicateKey( hKey, NULL, 0, &m_hKey ); + if( !bSuccess ) + m_hKey = NULL; + } +} + +inline void CCryptKey::Destroy() throw() +{ + if( m_hKey != NULL ) + { + BOOL bSuccess; + + bSuccess = ::CryptDestroyKey( m_hKey ); + + // can fail if the cryptographic service provider + // (managed by CCryptProv) has already been destroyed + ATLASSERT( bSuccess ); + m_hKey = NULL; + } +} + +inline HCRYPTKEY CCryptKey::Detach() throw() +{ + HCRYPTKEY hKey; + + hKey = m_hKey; + m_hKey = NULL; + + return( hKey ); +} + +inline HCRYPTKEY CCryptKey::Duplicate() const throw() +{ + BOOL bSuccess; + + ATLASSUME( m_hKey != NULL ); + + HCRYPTKEY hKey = NULL; + bSuccess = ::CryptDuplicateKey( m_hKey, NULL, 0, &hKey ); + if( !bSuccess ) + return NULL; + + return hKey; +} + +inline HRESULT CCryptKey::Uninitialize() throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!CryptDestroyKey(m_hKey)) + { + return AtlHresultFromLastError(); + } + else + { + m_hKey = NULL; + return S_OK; + } +} + +inline HRESULT CCryptKey::Encrypt( + BOOL final, + BYTE * pbData, + DWORD * pdwDataLen, + DWORD dwBufLen, + CCryptHash &Hash) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!::CryptEncrypt(m_hKey, Hash.GetHandle(), final, 0, pbData, pdwDataLen, dwBufLen)) + { + return AtlHresultFromLastError(); + } + else return S_OK; + +} + +inline HRESULT CCryptKey::Decrypt(BOOL final, BYTE * pbData, DWORD * pdwDataLen, CCryptHash &Hash) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!::CryptDecrypt(m_hKey, Hash.GetHandle(), final, 0, pbData, pdwDataLen)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + + +inline HRESULT CCryptKey::Encrypt( + const BYTE * pbPlainText, + DWORD dwPlainTextLen, + BYTE * pbCipherText, + DWORD * pdwCipherTextLen, + CCryptHash &Hash) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (*pdwCipherTextLen < dwPlainTextLen) + return ERROR_MORE_DATA; + + Checked::memcpy_s(pbCipherText, dwPlainTextLen, pbPlainText, dwPlainTextLen); + DWORD dwSize = dwPlainTextLen; + if (!::CryptEncrypt(m_hKey, Hash.GetHandle(), TRUE, 0, pbCipherText, &dwSize, *pdwCipherTextLen)) + { + return AtlHresultFromLastError(); + } + + *pdwCipherTextLen = dwSize; + return S_OK; + +} + +inline HRESULT CCryptKey::Decrypt( + const BYTE * pbCipherText, + DWORD dwCipherTextLen, + BYTE * pbPlainText, + DWORD * pdwPlainTextLen, + CCryptHash &Hash) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (*pdwPlainTextLen < dwCipherTextLen) + return ERROR_MORE_DATA; + + Checked::memcpy_s(pbPlainText, dwCipherTextLen, pbCipherText, dwCipherTextLen); + DWORD dwSize = dwCipherTextLen; + if (!::CryptDecrypt(m_hKey, Hash.GetHandle(), TRUE, 0, pbPlainText, &dwSize)) + { + return AtlHresultFromLastError(); + } + + *pdwPlainTextLen = dwSize; + return S_OK; +} + +inline HRESULT CCryptKey::EncryptString( + LPCTSTR szPlainText, + BYTE * pbCipherText, + DWORD * pdwCipherTextLen, + CCryptHash &Hash) throw() +{ + DWORD dwSize = ((DWORD)_tcslen(szPlainText) + 1) * sizeof(TCHAR); + return Encrypt((BYTE *)szPlainText, dwSize, pbCipherText, pdwCipherTextLen, Hash); +} + +inline HRESULT CCryptKey::ExportSimpleBlob( + CCryptKey &ExpKey, + DWORD dwFlags, + BYTE * pbData, + DWORD * pdwDataLen) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!CryptExportKey(m_hKey, ExpKey.GetHandle(), SIMPLEBLOB, dwFlags, pbData, pdwDataLen)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptKey::ExportPublicKeyBlob( + CCryptKey &ExpKey, + DWORD dwFlags, + BYTE * pbData, + DWORD * pdwDataLen) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!CryptExportKey(m_hKey, ExpKey.GetHandle(), PUBLICKEYBLOB, dwFlags, pbData, pdwDataLen)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptKey::ExportPrivateKeyBlob( + CCryptKey &ExpKey, + DWORD dwFlags, + BYTE * pbData, + DWORD * pdwDataLen) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!CryptExportKey(m_hKey, ExpKey.GetHandle(), PRIVATEKEYBLOB, dwFlags, pbData, pdwDataLen)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptKey::GetParam(DWORD dwParam, BYTE * pbData, DWORD * pdwDataLen, DWORD dwFlags) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!CryptGetKeyParam(m_hKey, dwParam, pbData, pdwDataLen, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptKey::SetParam(DWORD dwParam, BYTE * pbData, DWORD dwFlags) throw() +{ + ATLASSUME(m_hKey != NULL); + + if (!CryptSetKeyParam(m_hKey, dwParam, pbData, dwFlags)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptKey::GetAlgId(ALG_ID * pAlgId) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_ALGID, (BYTE *)pAlgId, &dwSize); +} + +inline HRESULT CCryptKey::SetAlgId(ALG_ID AlgId, DWORD dwFlags) throw() +{ + return SetParam(KP_ALGID, (BYTE *)&AlgId, dwFlags); +} + +inline HRESULT CCryptKey::GetBlockLength(DWORD * pdwBlockLen) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_BLOCKLEN, (BYTE *)pdwBlockLen, &dwSize); +} + +inline HRESULT CCryptKey::GetKeyLength(DWORD * pdwKeyLen) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_KEYLEN, (BYTE *)pdwKeyLen, &dwSize); +} + +inline HRESULT CCryptKey::GetSalt(BYTE * pbSalt, DWORD * pdwLength) throw() +{ + return GetParam(KP_SALT, pbSalt, pdwLength); +} + +inline HRESULT CCryptKey::SetSalt(BYTE * pbSalt) throw() +{ + return SetParam(KP_SALT, pbSalt); +} + +inline HRESULT CCryptKey::SetSaltEx(_CRYPTOAPI_BLOB * pBlobSalt) throw() +{ + return SetParam(KP_SALT_EX, (BYTE *)pBlobSalt); +} + +inline HRESULT CCryptKey::GetPermissions(DWORD * pdwPerms) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_PERMISSIONS, (BYTE *)pdwPerms, &dwSize); +} + +inline HRESULT CCryptKey::SetPermissions(DWORD dwPerms) throw() +{ + return SetParam(KP_PERMISSIONS, (BYTE *)&dwPerms); +} + +inline HRESULT CCryptKey::GetP(BYTE * pbP, DWORD * pdwLength) throw() +{ + return GetParam(KP_P, (BYTE *)pbP, pdwLength); +} + +inline HRESULT CCryptKey::SetP(_CRYPTOAPI_BLOB * pBlobP) throw() +{ + return SetParam(KP_P, (BYTE *)pBlobP); +} + +inline HRESULT CCryptKey::SetP(BYTE * pbP, DWORD dwLength) throw() +{ + _CRYPTOAPI_BLOB blob = { dwLength, pbP }; + return SetParam(KP_P, (BYTE *)&blob); +} + +inline HRESULT CCryptKey::GetQ(BYTE * pbQ, DWORD * pdwLength) throw() +{ + return GetParam(KP_Q, (BYTE *)pbQ, pdwLength); +} + +inline HRESULT CCryptKey::SetQ(_CRYPTOAPI_BLOB * pBlobQ) throw() +{ + return SetParam(KP_Q, (BYTE *)pBlobQ); +} + +inline HRESULT CCryptKey::SetQ(BYTE * pbQ, DWORD dwLength) throw() +{ + _CRYPTOAPI_BLOB blob = { dwLength, pbQ }; + return SetParam(KP_Q, (BYTE *)&blob); +} + +inline HRESULT CCryptKey::GetG(BYTE * pbG, DWORD * pdwLength) throw() +{ + return GetParam(KP_G, (BYTE *)pbG, pdwLength); +} + +inline HRESULT CCryptKey::SetG(_CRYPTOAPI_BLOB * pBlobG) throw() +{ + return SetParam(KP_G, (BYTE *)pBlobG); +} + +inline HRESULT CCryptKey::SetG(BYTE * pbG, DWORD dwLength) throw() +{ + _CRYPTOAPI_BLOB blob = { dwLength, pbG }; + return SetParam(KP_G, (BYTE *)&blob); +} + +inline HRESULT CCryptKey::SetX() throw() +{ + return SetParam(KP_X, NULL); +} + +inline HRESULT CCryptKey::GetEffKeyLen(DWORD * pdwEffKeyLen) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_EFFECTIVE_KEYLEN, (BYTE *)pdwEffKeyLen, &dwSize); +} + +inline HRESULT CCryptKey::SetEffKeyLen(DWORD dwEffKeyLen) throw() +{ + return SetParam(KP_EFFECTIVE_KEYLEN, (BYTE *)&dwEffKeyLen); +} + +inline HRESULT CCryptKey::GetPadding(DWORD * pdwPadding) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_PADDING, (BYTE *)pdwPadding, &dwSize); +} + +inline HRESULT CCryptKey::SetPadding(DWORD dwPadding) throw() +{ + return SetParam(KP_PADDING, (BYTE *)&dwPadding); +} + +inline HRESULT CCryptKey::GetIV(BYTE * pbIV, DWORD * pdwLength) throw() +{ + return GetParam(KP_IV, pbIV, pdwLength); +} + +inline HRESULT CCryptKey::SetIV(BYTE * pbIV) throw() +{ + return SetParam(KP_IV, pbIV); +} + +inline HRESULT CCryptKey::GetMode(DWORD * pdwMode) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_MODE, (BYTE *)pdwMode, &dwSize); +} + +inline HRESULT CCryptKey::SetMode(DWORD dwMode) throw() +{ + return SetParam(KP_MODE, (BYTE *)&dwMode); +} + +inline HRESULT CCryptKey::GetModeBits(DWORD * pdwModeBits) throw() +{ + DWORD dwSize = sizeof(DWORD); + return GetParam(KP_MODE_BITS, (BYTE *)pdwModeBits, &dwSize); +} + +inline HRESULT CCryptKey::SetModeBits(DWORD dwModeBits) throw() +{ + return SetParam(KP_MODE_BITS, (BYTE *)&dwModeBits); +} + +inline HRESULT CCryptDerivedKey::Initialize( + CCryptProv &Prov, + CCryptHash &Hash, + ALG_ID algid, + DWORD dwFlags) throw() +{ + ATLASSUME(m_hKey == NULL); + + if (!CryptDeriveKey(Prov.GetHandle(), algid, Hash.GetHandle(), dwFlags, &m_hKey)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptRandomKey::Initialize(CCryptProv &Prov, ALG_ID algid, DWORD dwFlags) throw() +{ + ATLASSUME(m_hKey == NULL); + + if (!CryptGenKey(Prov.GetHandle(), algid, dwFlags, &m_hKey)) + { + return AtlHresultFromLastError(); + } + else return S_OK; + +} + +inline HRESULT CCryptUserExKey::Initialize(CCryptProv &Prov) throw() +{ + ATLASSUME(m_hKey == NULL); + + if (!CryptGetUserKey(Prov.GetHandle(), AT_KEYEXCHANGE, &m_hKey)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptUserExKey::Create(CCryptProv &Prov) throw() +{ + ATLASSUME(m_hKey == NULL); + + if (!CryptGenKey(Prov.GetHandle(), AT_KEYEXCHANGE, 0, &m_hKey)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptUserSigKey::Initialize(CCryptProv &Prov) throw() +{ + ATLASSUME(m_hKey == NULL); + + if (!CryptGetUserKey(Prov.GetHandle(), AT_SIGNATURE, &m_hKey)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptUserSigKey::Create(CCryptProv &Prov) throw() +{ + ATLASSUME(m_hKey == NULL); + + if (!CryptGenKey(Prov.GetHandle(), AT_SIGNATURE, 0, &m_hKey)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptImportKey::Initialize( + CCryptProv &Prov, + BYTE * pbData, + DWORD dwDataLen, + CCryptKey &PubKey, + DWORD dwFlags) throw() +{ + ATLASSUME(m_hKey == NULL); + + if (!CryptImportKey(Prov.GetHandle(), pbData, dwDataLen, PubKey.GetHandle(), dwFlags, &m_hKey)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptKeyedHash::Initialize( + CCryptProv &Prov, + ALG_ID Algid, + CCryptKey &Key, + DWORD dwFlags) throw() +{ + ATLASSUME(m_hHash == NULL); + + if (!CryptCreateHash(Prov.GetHandle(), Algid, Key.GetHandle(), dwFlags, &m_hHash)) + { + return AtlHresultFromLastError(); + } + else return S_OK; +} + +inline HRESULT CCryptSHAHash::Initialize(CCryptProv &Prov, LPCTSTR szText) throw() +{ + ATLASSUME(m_hHash == NULL); + + if (!CryptCreateHash(Prov.GetHandle(), CALG_SHA, 0, 0, &m_hHash)) + { + return AtlHresultFromLastError(); + } + if (szText!=NULL) + return AddString(szText); + else return S_OK; +} + +inline HRESULT CCryptHMACHash::Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText) throw() +{ + ATLASSUME(m_hHash == NULL); + + if (!CryptCreateHash(Prov.GetHandle(), CALG_HMAC, Key.GetHandle(), 0, &m_hHash)) + { + return AtlHresultFromLastError(); + } + if (szText!=NULL) + return AddString(szText); + else return S_OK; + +} + +inline HRESULT CCryptMACHash::Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText) throw() +{ + ATLASSUME(m_hHash == NULL); + + if (!CryptCreateHash(Prov.GetHandle(), CALG_MAC, Key.GetHandle(), 0, &m_hHash)) + { + return AtlHresultFromLastError(); + } + if (szText!=NULL) + return AddString(szText); + else return S_OK; + +} + +inline HRESULT CCryptSSL3SHAMD5Hash::Initialize(CCryptProv &Prov, CCryptKey &Key, LPCTSTR szText) throw() +{ + ATLASSUME(m_hHash == NULL); + + if (!CryptCreateHash(Prov.GetHandle(), CALG_SSL3_SHAMD5, Key.GetHandle(), 0, &m_hHash)) + { + return AtlHresultFromLastError(); + } + if (szText!=NULL) + return AddString(szText); + else return S_OK; + +} + +}; // namespace ATL + +#endif //__ATLCRYPT_INL__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlctl.cpp b/externals/WinDDK/7600.16385.1/inc/atl71/atlctl.cpp new file mode 100644 index 00000000..e4f8dd12 --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlctl.cpp @@ -0,0 +1,15 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#pragma message("atlctl.cpp is obsolete. Please remove it from your project.") + +/////////////////////////////////////// +// No longer used + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlctl.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlctl.h new file mode 100644 index 00000000..4cc3cf4e --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlctl.h @@ -0,0 +1,4063 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCTL_H__ +#define __ATLCTL_H__ + +#pragma once + +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning (push) +#pragma warning(disable: 4702) // unreachable code +#pragma warning(disable: 4512) // assignment operator could not be generated +#pragma warning(disable: 4127) // constant expression +#endif //!_ATL_NO_PRAGMA_WARNINGS + +#ifndef __cplusplus + #error ATL requires C++ compilation (use a .cpp suffix) +#endif + +#include + +#include +#include + +#ifndef _ATL_NO_DEFAULT_LIBS +#pragma comment(lib, "gdi32.lib") +#pragma comment(lib, "urlmon.lib") +#endif // !_ATL_NO_DEFAULT_LIBS + +#pragma pack(push, _ATL_PACKING) + +#define DECLARE_VIEW_STATUS(statusFlags) \ + DWORD _GetViewStatus() \ + { \ + return statusFlags; \ + } + +// Include GUIDs for the new stock property dialogs contained in the dll MSStkProp.DLL +#include "msstkppg.h" +#include "atliface.h" +#define CLSID_MSStockFont CLSID_StockFontPage +#define CLSID_MSStockColor CLSID_StockColorPage +#define CLSID_MSStockPicture CLSID_StockPicturePage + +#define REFLECTOR_MAP_ID 69 + +struct ATL_DRAWINFO +{ +#ifdef __ATLTMP_H__ + static CRect& GetNullRect() + { + static CRect rc; + return rc; + } + ATL_DRAWINFO() : rcBounds(GetNullRect()), rcWBounds(GetNullRect()) + { + } +#endif + UINT cbSize; + DWORD dwDrawAspect; + LONG lindex; + DVTARGETDEVICE* ptd; + HDC hicTargetDev; + HDC hdcDraw; +#ifdef __ATLTMP_H__ + union + { + LPCRECTL prcBounds; //Rectangle in which to draw + CRect& rcBounds; + }; + union + { + LPCRECTL prcWBounds; //WindowOrg and Ext if metafile + CRect& rcWBounds; + }; +#else + LPCRECTL prcBounds; //Rectangle in which to draw + LPCRECTL prcWBounds; //WindowOrg and Ext if metafile +#endif + BOOL bOptimize; + BOOL bZoomed; + BOOL bRectInHimetric; + SIZEL ZoomNum; //ZoomX = ZoomNum.cx/ZoomNum.cy + SIZEL ZoomDen; +}; + + + +namespace ATL +{ + + + +// Forward declarations +// +class ATL_NO_VTABLE CComControlBase; +template class CComControl; + +////////////////////////////////////////////////////////////////////////////// +// CFirePropNotifyEvent + + +// Helper functions for safely communicating with objects who sink IPropertyNotifySink +class CFirePropNotifyEvent +{ +public: + // Ask any objects sinking the IPropertyNotifySink notification if it is ok to edit a specified property + static HRESULT FireOnRequestEdit(IUnknown* pUnk, DISPID dispID) + { + CComQIPtr pCPC(pUnk); + if (!pCPC) + return S_OK; + CComPtr pCP; + pCPC->FindConnectionPoint(__uuidof(IPropertyNotifySink), &pCP); + if (!pCP) + return S_OK; + CComPtr pEnum; + + if (FAILED(pCP->EnumConnections(&pEnum))) + return S_OK; + CONNECTDATA cd; + while (pEnum->Next(1, &cd, NULL) == S_OK) + { + if (cd.pUnk) + { + HRESULT hr = S_OK; + CComQIPtr pSink(cd.pUnk); +#ifdef _DEBUG + if (pSink == NULL) + { + ATLTRACE(atlTraceControls,2,_T("QI for IPropertyNotifySink failed in CFirePropNotifyEvent::FireOnRequestEdit\n")); + } +#endif + if (pSink != NULL) + hr = pSink->OnRequestEdit(dispID); + + cd.pUnk->Release(); + if (hr == S_FALSE) + return S_FALSE; + } + } + return S_OK; + } + // Notify any objects sinking the IPropertyNotifySink notification that a property has changed + static HRESULT FireOnChanged(IUnknown* pUnk, DISPID dispID) + { + CComQIPtr pCPC(pUnk); + if (!pCPC) + return S_OK; + CComPtr pCP; + pCPC->FindConnectionPoint(__uuidof(IPropertyNotifySink), &pCP); + if (!pCP) + return S_OK; + CComPtr pEnum; + + if (FAILED(pCP->EnumConnections(&pEnum))) + return S_OK; + CONNECTDATA cd; + while (pEnum->Next(1, &cd, NULL) == S_OK) + { + if (cd.pUnk) + { + CComQIPtr pSink(cd.pUnk); +#ifdef _DEBUG + if (pSink == NULL) + { + ATLTRACE(atlTraceControls,2,_T("QI for IPropertyNotifySink failed in CFirePropNotifyEvent::FireOnChanged\n")); + } +#endif + if (pSink != NULL) + pSink->OnChanged(dispID); + cd.pUnk->Release(); + } + } + return S_OK; + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// CComControlBase + +// Holds the essential data members for an ActiveX control and useful helper functions +class ATL_NO_VTABLE CComControlBase +{ +public: + typedef short AppearanceType; // Override in derived class if your + // m_nAppearance stock property isn't of type 'short' +public: + CComControlBase(HWND& h) : m_hWndCD(h) + { + memset(this, 0, sizeof(CComControlBase)); + m_phWndCD = &h; + m_sizeExtent.cx = 2*2540; + m_sizeExtent.cy = 2*2540; + m_sizeNatural = m_sizeExtent; + } + virtual ~CComControlBase() + { + if (m_hWndCD != NULL) + ::DestroyWindow(m_hWndCD); + ATLTRACE(atlTraceControls,2,_T("Control Destroyed\n")); + } + +// methods +public: + // Control helper functions can go here non-virtuals only please + + // Mark the control 'dirty' so the container will save it + void SetDirty(BOOL bDirty) + { + m_bRequiresSave = bDirty; + } + // Obtain the dirty state for the control + BOOL GetDirty() + { + return m_bRequiresSave; + } + // Get the zoom factor (numerator & denominator) which is factor of the natural extent + void GetZoomInfo(ATL_DRAWINFO& di); + // Sends a notification that the moniker for the control has changed + HRESULT SendOnRename(IMoniker *pmk) + { + HRESULT hRes = S_OK; + if (m_spOleAdviseHolder) + hRes = m_spOleAdviseHolder->SendOnRename(pmk); + return hRes; + } + // Sends a notification that the control has just saved its data + HRESULT SendOnSave() + { + HRESULT hRes = S_OK; + if (m_spOleAdviseHolder) + hRes = m_spOleAdviseHolder->SendOnSave(); + return hRes; + } + // Sends a notification that the control has closed its advisory sinks + HRESULT SendOnClose() + { + HRESULT hRes = S_OK; + if (m_spOleAdviseHolder) + hRes = m_spOleAdviseHolder->SendOnClose(); + return hRes; + } + // Sends a notification that the control's data has changed + HRESULT SendOnDataChange(DWORD advf = 0); + // Sends a notification that the control's representation has changed + HRESULT SendOnViewChange(DWORD dwAspect, LONG lindex = -1) + { + if (m_spAdviseSink) + m_spAdviseSink->OnViewChange(dwAspect, lindex); + return S_OK; + } + // Sends a notification to the container that the control has received focus + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + if (m_bInPlaceActive) + { + CComPtr pOleObject; + ControlQueryInterface(__uuidof(IOleObject), (void**)&pOleObject); + if (pOleObject != NULL) + pOleObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, m_spClientSite, 0, m_hWndCD, &m_rcPos); + CComQIPtr spSite(m_spClientSite); + if (m_bInPlaceActive && spSite != NULL) + spSite->OnFocus(TRUE); + } + bHandled = FALSE; + return 1; + } + LRESULT OnKillFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + CComQIPtr spSite(m_spClientSite); + if (m_bInPlaceActive && spSite != NULL && !::IsChild(m_hWndCD, ::GetFocus())) + spSite->OnFocus(FALSE); + bHandled = FALSE; + return 1; + } + LRESULT OnMouseActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + BOOL bUserMode = TRUE; + HRESULT hRet = GetAmbientUserMode(bUserMode); + // UI activate if in user mode only + // allow activation if we can't determine mode + if (FAILED(hRet) || bUserMode) + { + CComPtr pOleObject; + ControlQueryInterface(__uuidof(IOleObject), (void**)&pOleObject); + if (pOleObject != NULL) + pOleObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, m_spClientSite, 0, m_hWndCD, &m_rcPos); + } + bHandled = FALSE; + return 1; + } + BOOL PreTranslateAccelerator(LPMSG /*pMsg*/, HRESULT& /*hRet*/) + { + return FALSE; + } + + HRESULT GetAmbientProperty(DISPID dispid, VARIANT& var) + { + HRESULT hRes = E_FAIL; + if (m_spAmbientDispatch.p != NULL) + hRes = m_spAmbientDispatch.GetProperty(dispid, &var); + return hRes; + } + HRESULT GetAmbientAppearance(short& nAppearance) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_APPEARANCE, var); + ATLASSERT(var.vt == VT_I2 || var.vt == VT_UI2 || var.vt == VT_I4 || var.vt == VT_UI4 || FAILED(hRes)); + if (SUCCEEDED(hRes)) + { + if (var.vt == VT_EMPTY) + hRes = E_FAIL; + else + { + nAppearance = var.iVal; + } + } + return hRes; + } + HRESULT GetAmbientBackColor(OLE_COLOR& BackColor) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_BACKCOLOR, var); + ATLASSERT(var.vt == VT_I4 || var.vt == VT_UI4 || FAILED(hRes)); + BackColor = var.lVal; + return hRes; + } + HRESULT GetAmbientDisplayName(BSTR& bstrDisplayName) + { + CComVariant var; + if (bstrDisplayName) + { + SysFreeString(bstrDisplayName); + bstrDisplayName = NULL; + } + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_DISPLAYNAME, var); + if (SUCCEEDED(hRes)) + { + if (var.vt != VT_BSTR) + return E_FAIL; + bstrDisplayName = var.bstrVal; + var.vt = VT_EMPTY; + var.bstrVal = NULL; + } + return hRes; + } + HRESULT GetAmbientFont(IFont** ppFont) + { + // caller MUST Release the font! + if (ppFont == NULL) + return E_POINTER; + *ppFont = NULL; + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_FONT, var); + ATLASSERT((var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH) || FAILED(hRes)); + if (SUCCEEDED(hRes) && var.pdispVal) + { + if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH) + hRes = var.pdispVal->QueryInterface(__uuidof(IFont), (void**)ppFont); + else + hRes = DISP_E_BADVARTYPE; + } + return hRes; + } + HRESULT GetAmbientFontDisp(IFontDisp** ppFont) + { + // caller MUST Release the font! + if (ppFont == NULL) + return E_POINTER; + *ppFont = NULL; + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_FONT, var); + ATLASSERT((var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH) || FAILED(hRes)); + if (SUCCEEDED(hRes) && var.pdispVal) + { + if (var.vt == VT_UNKNOWN || var.vt == VT_DISPATCH) + hRes = var.pdispVal->QueryInterface(__uuidof(IFontDisp), (void**)ppFont); + else + hRes = DISP_E_BADVARTYPE; + } + return hRes; + } + HRESULT GetAmbientForeColor(OLE_COLOR& ForeColor) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_FORECOLOR, var); + ATLASSERT(var.vt == VT_I4 || var.vt == VT_UI4 || FAILED(hRes)); + ForeColor = var.lVal; + return hRes; + } + HRESULT GetAmbientLocaleID(LCID& lcid) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_LOCALEID, var); + ATLASSERT((var.vt == VT_UI4 || var.vt == VT_I4) || FAILED(hRes)); + lcid = var.lVal; + return hRes; + } + HRESULT GetAmbientScaleUnits(BSTR& bstrScaleUnits) + { + CComVariant var; + if (bstrScaleUnits) + { + SysFreeString(bstrScaleUnits); + bstrScaleUnits = NULL; + } + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_SCALEUNITS, var); + ATLASSERT(var.vt == VT_BSTR || FAILED(hRes)); + if (SUCCEEDED(hRes)) + { + if (var.vt != VT_BSTR) + return E_FAIL; + bstrScaleUnits = var.bstrVal; + var.vt = VT_EMPTY; + var.bstrVal = NULL; + } + return hRes; + } + HRESULT GetAmbientTextAlign(short& nTextAlign) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_TEXTALIGN, var); + ATLASSERT(var.vt == VT_I2 || FAILED(hRes)); + if (SUCCEEDED(hRes)) + { + if (var.vt == VT_EMPTY) + hRes = E_FAIL; + else + nTextAlign = var.iVal; + } + return hRes; + } + HRESULT GetAmbientUserMode(BOOL& bUserMode) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_USERMODE, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bUserMode = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientUIDead(BOOL& bUIDead) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_UIDEAD, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bUIDead = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientShowGrabHandles(BOOL& bShowGrabHandles) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_SHOWGRABHANDLES, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bShowGrabHandles = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientShowHatching(BOOL& bShowHatching) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_SHOWHATCHING, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bShowHatching = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientMessageReflect(BOOL& bMessageReflect) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_MESSAGEREFLECT, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bMessageReflect = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientAutoClip(BOOL& bAutoClip) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_AUTOCLIP, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bAutoClip = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientDisplayAsDefault(BOOL& bDisplaysDefault) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_DISPLAYASDEFAULT, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bDisplaysDefault = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientSupportsMnemonics(BOOL& bSupportMnemonics) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_SUPPORTSMNEMONICS, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bSupportMnemonics = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + HRESULT GetAmbientPalette(HPALETTE& hPalette) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_PALETTE, var); +#ifdef _WIN64 + ATLASSERT(var.vt == VT_I8 || var.vt == VT_UI8 || FAILED(hRes)); + hPalette = reinterpret_cast(static_cast(var.llVal)); +#else + ATLASSERT(var.vt == VT_I4 || var.vt == VT_UI4 || FAILED(hRes)); + hPalette = reinterpret_cast(static_cast(var.lVal)); +#endif + return hRes; + } + + HRESULT GetAmbientCodePage(ULONG& ulCodePage) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_CODEPAGE, var); + ATLASSERT(var.vt == VT_UI4 || FAILED(hRes)); + ulCodePage = var.ulVal; + return hRes; + } + + HRESULT GetAmbientCharSet(BSTR& bstrCharSet) + { + CComVariant var; + if (bstrCharSet) + { + SysFreeString(bstrCharSet); + bstrCharSet = NULL; + } + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_CHARSET, var); + ATLASSERT(var.vt == VT_BSTR || FAILED(hRes)); + if (SUCCEEDED(hRes)) + { + if (var.vt != VT_BSTR) + return E_FAIL; + bstrCharSet = var.bstrVal; + var.vt = VT_EMPTY; + var.bstrVal = NULL; + } + return hRes; + } + + HRESULT GetAmbientRightToLeft(BOOL& bRightToLeft) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_RIGHTTOLEFT, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bRightToLeft = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + + HRESULT GetAmbientTopToBottom(BOOL& bTopToBottom) + { + CComVariant var; + HRESULT hRes = GetAmbientProperty(DISPID_AMBIENT_TOPTOBOTTOM, var); + if(SUCCEEDED(hRes)) + { + ATLASSERT(var.vt == VT_BOOL); + if(var.vt != VT_BOOL) + return DISP_E_TYPEMISMATCH; + bTopToBottom = (var.boolVal != ATL_VARIANT_FALSE) ? TRUE : FALSE; + } + return hRes; + } + + HRESULT InternalGetSite(REFIID riid, void** ppUnkSite) + { + ATLASSERT(ppUnkSite != NULL); + if (ppUnkSite == NULL) + return E_POINTER; + if (m_spClientSite == NULL) + { + *ppUnkSite = NULL; + return E_FAIL; + } + return m_spClientSite->QueryInterface(riid, ppUnkSite); + } + + BOOL DoesVerbUIActivate(LONG iVerb) + { + BOOL b = FALSE; + switch (iVerb) + { + case OLEIVERB_UIACTIVATE: + case OLEIVERB_PRIMARY: + b = TRUE; + break; + } + // if no ambient dispatch then in old style OLE container + if (DoesVerbActivate(iVerb) && m_spAmbientDispatch.p == NULL) + b = TRUE; + return b; + } + + BOOL DoesVerbActivate(LONG iVerb) + { + BOOL b = FALSE; + switch (iVerb) + { + case OLEIVERB_UIACTIVATE: + case OLEIVERB_PRIMARY: + case OLEIVERB_SHOW: + case OLEIVERB_INPLACEACTIVATE: + b = TRUE; + break; + } + return b; + } + + BOOL SetControlFocus(BOOL bGrab); + HRESULT IQuickActivate_QuickActivate(QACONTAINER *pQACont, + QACONTROL *pQACtrl); + HRESULT DoVerbProperties(LPCRECT /* prcPosRect */, HWND hwndParent); + HRESULT InPlaceActivate(LONG iVerb, const RECT* prcPosRect = NULL); + + HRESULT IOleObject_SetClientSite(IOleClientSite *pClientSite); + HRESULT IOleObject_GetClientSite(IOleClientSite **ppClientSite); + HRESULT IOleObject_Advise(IAdviseSink *pAdvSink, DWORD *pdwConnection); + HRESULT IOleObject_Close(DWORD dwSaveOption); + HRESULT IOleObject_SetExtent(DWORD dwDrawAspect, SIZEL *psizel); + HRESULT IOleInPlaceObject_InPlaceDeactivate(void); + HRESULT IOleInPlaceObject_UIDeactivate(void); + HRESULT IOleInPlaceObject_SetObjectRects(LPCRECT prcPos,LPCRECT prcClip); + HRESULT IViewObject_Draw(DWORD dwDrawAspect, LONG lindex, void *pvAspect, + DVTARGETDEVICE *ptd, HDC hicTargetDev, HDC hdcDraw, + LPCRECTL prcBounds, LPCRECTL prcWBounds); + HRESULT IDataObject_GetData(FORMATETC *pformatetcIn, STGMEDIUM *pmedium); + + HRESULT FireViewChange(); + LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& lResult); + + virtual HWND CreateControlWindow(HWND hWndParent, RECT& rcPos) = 0; + virtual HRESULT ControlQueryInterface(const IID& iid, void** ppv) = 0; + virtual HRESULT OnDrawAdvanced(ATL_DRAWINFO& di); + virtual HRESULT OnDraw(ATL_DRAWINFO& di) + { + ::SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE); + LPCTSTR pszText = _T("ATL 8.0"); + ::TextOut(di.hdcDraw, di.prcBounds->left + (di.prcBounds->right - di.prcBounds->left) / 2, di.prcBounds->top + (di.prcBounds->bottom - di.prcBounds->top) / 2, pszText, lstrlen(pszText)); + + return S_OK; + } + +// Attributes +public: + CComPtr m_spInPlaceSite; + CComPtr m_spDataAdviseHolder; + CComPtr m_spOleAdviseHolder; + CComPtr m_spClientSite; + CComPtr m_spAdviseSink; + CComDispatchDriver m_spAmbientDispatch; + + SIZE m_sizeNatural; //unscaled size in himetric + SIZE m_sizeExtent; //current extents in himetric + RECT m_rcPos; // position in pixels +#pragma warning(push) +#pragma warning(disable: 4510 4610) // unnamed union + union + { + HWND& m_hWndCD; + HWND* m_phWndCD; + }; +#pragma warning(pop) + + int m_nFreezeEvents; // count of freezes versus thaws + unsigned m_bNegotiatedWnd:1; + unsigned m_bWndLess:1; + unsigned m_bInPlaceActive:1; + unsigned m_bUIActive:1; + unsigned m_bUsingWindowRgn:1; + unsigned m_bInPlaceSiteEx:1; + unsigned m_bWindowOnly:1; + unsigned m_bRequiresSave:1; + unsigned m_bWasOnceWindowless:1; + unsigned m_bAutoSize:1; //SetExtent fails if size doesn't match existing + unsigned m_bRecomposeOnResize:1; //implies OLEMISC_RECOMPOSEONRESIZE + unsigned m_bResizeNatural:1; //resize natural extent on SetExtent + unsigned m_bDrawFromNatural:1; //instead of m_sizeExtent + unsigned m_bDrawGetDataInHimetric:1; //instead of pixels + + DECLARE_VIEW_STATUS(VIEWSTATUS_OPAQUE) +}; + +inline HRESULT CComControlBase::IQuickActivate_QuickActivate(QACONTAINER *pQACont, + QACONTROL *pQACtrl) +{ + ATLASSERT(pQACont != NULL); + ATLASSERT(pQACtrl != NULL); + if (!pQACont || !pQACtrl) + return E_POINTER; + + HRESULT hRes; + ULONG uCB = pQACtrl->cbSize; + memset(pQACtrl, 0, uCB); + pQACtrl->cbSize = uCB; + + // get all interfaces we are going to need + CComPtr pOO; + ControlQueryInterface(__uuidof(IOleObject), (void**)&pOO); + CComPtr pVOEX; + ControlQueryInterface(__uuidof(IViewObjectEx), (void**)&pVOEX); + CComPtr pPI; + ControlQueryInterface(__uuidof(IPointerInactive), (void**)&pPI); + CComPtr pPCI; + ControlQueryInterface(__uuidof(IProvideClassInfo2), (void**)&pPCI); + + if (pOO == NULL || pVOEX == NULL) + return E_FAIL; + + pOO->SetClientSite(pQACont->pClientSite); + + if (pQACont->pAdviseSink != NULL) + { + ATLTRACE(atlTraceControls,2,_T("Setting up IOleObject Advise\n")); + pVOEX->SetAdvise(DVASPECT_CONTENT, 0, pQACont->pAdviseSink); + } + + CComPtr pCPC; + ControlQueryInterface(__uuidof(IConnectionPointContainer), (void**)&pCPC); + + if (pQACont->pPropertyNotifySink) + { + ATLTRACE(atlTraceControls,2,_T("Setting up PropNotify CP\n")); + CComPtr pCP; + if (pCPC != NULL) + { + hRes = pCPC->FindConnectionPoint(__uuidof(IPropertyNotifySink), &pCP); + if (SUCCEEDED(hRes)) + pCP->Advise(pQACont->pPropertyNotifySink, &pQACtrl->dwPropNotifyCookie); + } + } + + if (pPCI) + { + GUID iidDefaultSrc; + if (SUCCEEDED(pPCI->GetGUID(GUIDKIND_DEFAULT_SOURCE_DISP_IID, + &iidDefaultSrc))) + { + if (pQACont->pUnkEventSink) + { + ATLTRACE(atlTraceControls,2,_T("Setting up Default Out Going Interface\n")); + CComPtr pCP; + if (pCPC != NULL) + { + hRes = pCPC->FindConnectionPoint(iidDefaultSrc, &pCP); + if (SUCCEEDED(hRes)) + pCP->Advise(pQACont->pUnkEventSink, &pQACtrl->dwEventCookie); + } + } + } + } + // give information to container + if (pOO != NULL) + pOO->GetMiscStatus(DVASPECT_CONTENT, &pQACtrl->dwMiscStatus); + + if (pVOEX != NULL) + pVOEX->GetViewStatus(&pQACtrl->dwViewStatus); + + if (pPI != NULL) + pPI->GetActivationPolicy(&pQACtrl->dwPointerActivationPolicy); + return S_OK; +} + +inline BOOL CComControlBase::SetControlFocus(BOOL bGrab) +{ + if (m_bWndLess) + { + if (!m_bUIActive && bGrab) + if (FAILED(InPlaceActivate(OLEIVERB_UIACTIVATE))) + return FALSE; + + return (m_spInPlaceSite->SetFocus(bGrab) == S_OK); + } + else + { + // we've got a window. + // + if (m_bInPlaceActive) + { + HWND hwnd = (bGrab) ? m_hWndCD : ::GetParent(m_hWndCD); + if (!m_bUIActive && bGrab) + return SUCCEEDED(InPlaceActivate(OLEIVERB_UIACTIVATE)); + else + { + if (!::IsChild(hwnd, ::GetFocus())) + ::SetFocus(hwnd); + return TRUE; + } + } + } + return FALSE; +} + +inline HRESULT CComControlBase::DoVerbProperties(LPCRECT /* prcPosRect */, HWND hwndParent) +{ + HRESULT hr = S_OK; + CComQIPtr spPages; + CComQIPtr spObj; + CComQIPtr spSite(m_spClientSite); + + if (spSite) + { + hr = spSite->ShowPropertyFrame(); + if (SUCCEEDED(hr)) + return hr; + } + + CComPtr pUnk; + ControlQueryInterface(__uuidof(IUnknown), (void**)&pUnk); + ATLASSERT(pUnk != NULL); + CAUUID pages; + spPages = pUnk; + if (spPages) + { + hr = spPages->GetPages(&pages); + if (SUCCEEDED(hr)) + { + spObj = pUnk; + if (spObj) + { + LPOLESTR szTitle = NULL; + + spObj->GetUserType(USERCLASSTYPE_SHORT, &szTitle); + + LCID lcid; + if (FAILED(GetAmbientLocaleID(lcid))) + lcid = LOCALE_USER_DEFAULT; + + hr = OleCreatePropertyFrame(hwndParent, m_rcPos.top, m_rcPos.left, szTitle, + 1, &pUnk.p, pages.cElems, pages.pElems, lcid, 0, 0); + + CoTaskMemFree(szTitle); + } + else + { + hr = OLEOBJ_S_CANNOT_DOVERB_NOW; + } + CoTaskMemFree(pages.pElems); + } + } + else + { + hr = OLEOBJ_S_CANNOT_DOVERB_NOW; + } + + return hr; +} + +inline HRESULT CComControlBase::InPlaceActivate(LONG iVerb, const RECT* /*prcPosRect*/) +{ + HRESULT hr; + + if (m_spClientSite == NULL) + return S_OK; + + CComPtr pIPO; + ControlQueryInterface(__uuidof(IOleInPlaceObject), (void**)&pIPO); + ATLASSERT(pIPO != NULL); + + if (!m_bNegotiatedWnd) + { + if (!m_bWindowOnly) + // Try for windowless site + hr = m_spClientSite->QueryInterface(__uuidof(IOleInPlaceSiteWindowless), (void **)&m_spInPlaceSite); + + if (m_spInPlaceSite) + { + m_bInPlaceSiteEx = TRUE; + // CanWindowlessActivate returns S_OK or S_FALSE + if ( m_spInPlaceSite->CanWindowlessActivate() == S_OK ) + { + m_bWndLess = TRUE; + m_bWasOnceWindowless = TRUE; + } + else + { + m_bWndLess = FALSE; + } + } + else + { + m_spClientSite->QueryInterface(__uuidof(IOleInPlaceSiteEx), (void **)&m_spInPlaceSite); + if (m_spInPlaceSite) + m_bInPlaceSiteEx = TRUE; + else + hr = m_spClientSite->QueryInterface(__uuidof(IOleInPlaceSite), (void **)&m_spInPlaceSite); + } + } + + ATLASSUME(m_spInPlaceSite); + if (!m_spInPlaceSite) + return E_FAIL; + + m_bNegotiatedWnd = TRUE; + + if (!m_bInPlaceActive) + { + + BOOL bNoRedraw = FALSE; + if (m_bWndLess) + m_spInPlaceSite->OnInPlaceActivateEx(&bNoRedraw, ACTIVATE_WINDOWLESS); + else + { + if (m_bInPlaceSiteEx) + m_spInPlaceSite->OnInPlaceActivateEx(&bNoRedraw, 0); + else + { + hr = m_spInPlaceSite->CanInPlaceActivate(); + // CanInPlaceActivate returns S_FALSE or S_OK + if (FAILED(hr)) + return hr; + if ( hr != S_OK ) + { + // CanInPlaceActivate returned S_FALSE. + return( E_FAIL ); + } + m_spInPlaceSite->OnInPlaceActivate(); + } + } + } + + m_bInPlaceActive = TRUE; + + // get location in the parent window, + // as well as some information about the parent + // + OLEINPLACEFRAMEINFO frameInfo; + RECT rcPos, rcClip; + CComPtr spInPlaceFrame; + CComPtr spInPlaceUIWindow; + frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); + HWND hwndParent; + if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) + { + m_spInPlaceSite->GetWindowContext(&spInPlaceFrame, + &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo); + + if (!m_bWndLess) + { + if (m_hWndCD) + ShowWindow(m_hWndCD, SW_SHOW); + else + { + HWND h = CreateControlWindow(hwndParent, rcPos); + ATLASSERT(h != NULL); // will assert if creation failed + ATLASSERT(h == m_hWndCD); + if(h == NULL) + return E_FAIL; + } + } + + pIPO->SetObjectRects(&rcPos, &rcClip); + } + + CComPtr spActiveObject; + ControlQueryInterface(__uuidof(IOleInPlaceActiveObject), (void**)&spActiveObject); + + // Gone active by now, take care of UIACTIVATE + if (DoesVerbUIActivate(iVerb)) + { + if (!m_bUIActive) + { + m_bUIActive = TRUE; + hr = m_spInPlaceSite->OnUIActivate(); + if (FAILED(hr)) + { + m_bUIActive = FALSE; + return hr; + } + + SetControlFocus(TRUE); + // set ourselves up in the host. + // + if (spActiveObject) + { + if (spInPlaceFrame) + spInPlaceFrame->SetActiveObject(spActiveObject, NULL); + if (spInPlaceUIWindow) + spInPlaceUIWindow->SetActiveObject(spActiveObject, NULL); + } + + if (spInPlaceFrame) + spInPlaceFrame->SetBorderSpace(NULL); + if (spInPlaceUIWindow) + spInPlaceUIWindow->SetBorderSpace(NULL); + } + } + + m_spClientSite->ShowObject(); + + return S_OK; +} + +inline HRESULT CComControlBase::SendOnDataChange(DWORD advf) +{ + HRESULT hRes = S_OK; + if (m_spDataAdviseHolder) + { + CComPtr pdo; + if (SUCCEEDED(ControlQueryInterface(__uuidof(IDataObject), (void**)&pdo))) + hRes = m_spDataAdviseHolder->SendOnDataChange(pdo, 0, advf); + } + return hRes; +} + +inline HRESULT CComControlBase::IOleObject_SetClientSite(IOleClientSite *pClientSite) +{ + ATLASSERT(pClientSite == NULL || m_spClientSite == NULL); + m_spClientSite = pClientSite; + m_spAmbientDispatch.Release(); + if (m_spClientSite != NULL) + { + m_spClientSite->QueryInterface(__uuidof(IDispatch), + (void**) &m_spAmbientDispatch.p); + } + return S_OK; +} + +inline HRESULT CComControlBase::IOleObject_GetClientSite(IOleClientSite **ppClientSite) +{ + ATLASSERT(ppClientSite); + if (ppClientSite == NULL) + return E_POINTER; + + *ppClientSite = m_spClientSite; + if (m_spClientSite != NULL) + m_spClientSite.p->AddRef(); + return S_OK; +} + +inline HRESULT CComControlBase::IOleObject_Advise(IAdviseSink *pAdvSink, + DWORD *pdwConnection) +{ + HRESULT hr = S_OK; + if (m_spOleAdviseHolder == NULL) + hr = CreateOleAdviseHolder(&m_spOleAdviseHolder); + if (SUCCEEDED(hr)) + hr = m_spOleAdviseHolder->Advise(pAdvSink, pdwConnection); + return hr; +} + +inline HRESULT CComControlBase::IOleObject_Close(DWORD dwSaveOption) +{ + CComPtr pIPO; + ControlQueryInterface(__uuidof(IOleInPlaceObject), (void**)&pIPO); + ATLASSERT(pIPO != NULL); + if (m_hWndCD) + { + if (m_spClientSite) + m_spClientSite->OnShowWindow(FALSE); + } + + if (m_bInPlaceActive) + { + HRESULT hr = pIPO->InPlaceDeactivate(); + if (FAILED(hr)) + return hr; + ATLASSERT(!m_bInPlaceActive); + } + if (m_hWndCD) + { + ATLTRACE(atlTraceControls,2,_T("Destroying Window\n")); + if (::IsWindow(m_hWndCD)) + DestroyWindow(m_hWndCD); + m_hWndCD = NULL; + } + + // handle the save flag. + // + if ((dwSaveOption == OLECLOSE_SAVEIFDIRTY || + dwSaveOption == OLECLOSE_PROMPTSAVE) && m_bRequiresSave) + { + if (m_spClientSite) + m_spClientSite->SaveObject(); + SendOnSave(); + } + + m_spInPlaceSite.Release(); + m_bNegotiatedWnd = FALSE; + m_bWndLess = FALSE; + m_bInPlaceSiteEx = FALSE; + m_spAdviseSink.Release(); + return S_OK; +} + +inline HRESULT CComControlBase::IOleInPlaceObject_InPlaceDeactivate(void) +{ + CComPtr pIPO; + ControlQueryInterface(__uuidof(IOleInPlaceObject), (void**)&pIPO); + ATLENSURE(pIPO != NULL); + + if (!m_bInPlaceActive) + return S_OK; + pIPO->UIDeactivate(); + + m_bInPlaceActive = FALSE; + + // if we have a window, tell it to go away. + // + if (m_hWndCD) + { + ATLTRACE(atlTraceControls,2,_T("Destroying Window\n")); + if (::IsWindow(m_hWndCD)) + DestroyWindow(m_hWndCD); + m_hWndCD = NULL; + } + + if (m_spInPlaceSite) + m_spInPlaceSite->OnInPlaceDeactivate(); + + return S_OK; +} + +inline HRESULT CComControlBase::IOleInPlaceObject_UIDeactivate(void) +{ + // if we're not UIActive, not much to do. + if (!m_bUIActive) + return S_OK; + + m_bUIActive = FALSE; + + HWND hwndParent; + // This call to GetWindow is a fix for Delphi + if (m_spInPlaceSite) + { + if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) + { + // notify frame windows, if appropriate, that we're no longer ui-active. + CComPtr spInPlaceFrame; + CComPtr spInPlaceUIWindow; + OLEINPLACEFRAMEINFO frameInfo; + frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO); + RECT rcPos, rcClip; + + m_spInPlaceSite->GetWindowContext(&spInPlaceFrame, + &spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo); + if (spInPlaceUIWindow) + spInPlaceUIWindow->SetActiveObject(NULL, NULL); + if (spInPlaceFrame) + spInPlaceFrame->SetActiveObject(NULL, NULL); + } + // we don't need to explicitly release the focus here since somebody + // else grabbing the focus is what is likely to cause us to get lose it + m_spInPlaceSite->OnUIDeactivate(FALSE); + } + return S_OK; +} + +inline HRESULT CComControlBase::IOleInPlaceObject_SetObjectRects(LPCRECT prcPos,LPCRECT prcClip) +{ + if (prcPos == NULL || prcClip == NULL) + return E_POINTER; + + m_rcPos = *prcPos; + if (m_hWndCD) + { + // the container wants us to clip, so figure out if we really + // need to + // + RECT rcIXect; + BOOL b = IntersectRect(&rcIXect, prcPos, prcClip); + HRGN tempRgn = NULL; + if (b && !EqualRect(&rcIXect, prcPos)) + { + OffsetRect(&rcIXect, -(prcPos->left), -(prcPos->top)); + tempRgn = CreateRectRgnIndirect(&rcIXect); + } + + SetWindowRgn(m_hWndCD, tempRgn, TRUE); + + // set our control's location, but don't change it's size at all + // [people for whom zooming is important should set that up here] + // + SIZEL size = {prcPos->right - prcPos->left, prcPos->bottom - prcPos->top}; + SetWindowPos(m_hWndCD, NULL, prcPos->left, + prcPos->top, size.cx, size.cy, SWP_NOZORDER | SWP_NOACTIVATE); + } + + return S_OK; +} + +inline HRESULT CComControlBase::IOleObject_SetExtent(DWORD dwDrawAspect, SIZEL *psizel) +{ + if (dwDrawAspect != DVASPECT_CONTENT) + return DV_E_DVASPECT; + if (psizel == NULL) + return E_POINTER; + + BOOL bSizeMatchesNatural = + memcmp(psizel, &m_sizeNatural, sizeof(SIZE)) == 0; + + if (m_bAutoSize) //object can't do any other size + return (bSizeMatchesNatural) ? S_OK : E_FAIL; + + BOOL bResized = FALSE; + if (memcmp(psizel, &m_sizeExtent, sizeof(SIZE)) != 0) + { + m_sizeExtent = *psizel; + bResized = TRUE; + } + if (m_bResizeNatural && !bSizeMatchesNatural) + { + m_sizeNatural = *psizel; + bResized = TRUE; + } + + if (m_bRecomposeOnResize && bResized) + { + SendOnDataChange(); + FireViewChange(); + } + return S_OK; +} + +inline HRESULT CComControlBase::IViewObject_Draw(DWORD dwDrawAspect, LONG lindex, + void *pvAspect, DVTARGETDEVICE *ptd, HDC hicTargetDev, HDC hdcDraw, + LPCRECTL prcBounds, LPCRECTL prcWBounds) +{ + ATLTRACE(atlTraceControls,2,_T("Draw dwDrawAspect=%x lindex=%d ptd=%x hic=%x hdc=%x\n"), + dwDrawAspect, lindex, ptd, hicTargetDev, hdcDraw); +#ifdef _DEBUG + if (prcBounds == NULL) + ATLTRACE(atlTraceControls,2,_T("\tprcBounds=NULL\n")); + else + ATLTRACE(atlTraceControls,2,_T("\tprcBounds=%d,%d,%d,%d\n"), prcBounds->left, + prcBounds->top, prcBounds->right, prcBounds->bottom); + if (prcWBounds == NULL) + ATLTRACE(atlTraceControls,2,_T("\tprcWBounds=NULL\n")); + else + ATLTRACE(atlTraceControls,2,_T("\tprcWBounds=%d,%d,%d,%d\n"), prcWBounds->left, + prcWBounds->top, prcWBounds->right, prcWBounds->bottom); +#endif + + if (prcBounds == NULL) + { + if (!m_bWndLess) + return E_INVALIDARG; + prcBounds = (RECTL*)&m_rcPos; + } + + // support the aspects required for multi-pass drawing + switch (dwDrawAspect) + { + case DVASPECT_CONTENT: + case DVASPECT_OPAQUE: + case DVASPECT_TRANSPARENT: + break; + default: + ATLASSERT(FALSE); + return DV_E_DVASPECT; + break; + } + + // make sure nobody forgets to do this + if (ptd == NULL) + hicTargetDev = NULL; + + BOOL bOptimize = FALSE; + if (pvAspect && ((DVASPECTINFO *)pvAspect)->cb >= sizeof(DVASPECTINFO)) + bOptimize = (((DVASPECTINFO *)pvAspect)->dwFlags & DVASPECTINFOFLAG_CANOPTIMIZE); + + ATL_DRAWINFO di; + memset(&di, 0, sizeof(di)); + di.cbSize = sizeof(di); + di.dwDrawAspect = dwDrawAspect; + di.lindex = lindex; + di.ptd = ptd; + di.hicTargetDev = hicTargetDev; + di.hdcDraw = hdcDraw; + di.prcBounds = prcBounds; + di.prcWBounds = prcWBounds; + di.bOptimize = bOptimize; + return OnDrawAdvanced(di); +} + +inline HRESULT CComControlBase::IDataObject_GetData(FORMATETC *pformatetcIn, + STGMEDIUM *pmedium) +{ + if (pmedium == NULL) + return E_POINTER; + memset(pmedium, 0, sizeof(STGMEDIUM)); + ATLTRACE(atlTraceControls,2,_T("Format = %x\n"), pformatetcIn->cfFormat); + ATLTRACE(atlTraceControls,2,_T("TYMED = %x\n"), pformatetcIn->tymed); + + if ((pformatetcIn->tymed & TYMED_MFPICT) == 0) + return DATA_E_FORMATETC; + + SIZEL sizeMetric, size; + if (m_bDrawFromNatural) + sizeMetric = m_sizeNatural; + else + sizeMetric = m_sizeExtent; + if (!m_bDrawGetDataInHimetric) + AtlHiMetricToPixel(&sizeMetric, &size); + else + size = sizeMetric; + RECTL rectl = {0 ,0, size.cx, size.cy}; + + ATL_DRAWINFO di; + memset(&di, 0, sizeof(di)); + di.cbSize = sizeof(di); + di.dwDrawAspect = DVASPECT_CONTENT; + di.lindex = -1; + di.ptd = NULL; + di.hicTargetDev = NULL; + di.prcBounds = &rectl; + di.prcWBounds = &rectl; + di.bOptimize = TRUE; //we do a SaveDC/RestoreDC + di.bRectInHimetric = m_bDrawGetDataInHimetric; + // create appropriate memory metafile DC + di.hdcDraw = CreateMetaFile(NULL); + + // create attribute DC according to pformatetcIn->ptd + + SaveDC(di.hdcDraw); + SetWindowOrgEx(di.hdcDraw, 0, 0, NULL); + SetWindowExtEx(di.hdcDraw, rectl.right, rectl.bottom, NULL); + OnDrawAdvanced(di); + RestoreDC(di.hdcDraw, -1); + + HMETAFILE hMF = CloseMetaFile(di.hdcDraw); + if (hMF == NULL) + return E_UNEXPECTED; + + HGLOBAL hMem=GlobalAlloc(GMEM_SHARE | GMEM_MOVEABLE, sizeof(METAFILEPICT)); + + if (NULL==hMem) + { + DeleteMetaFile(hMF); + return ResultFromScode(STG_E_MEDIUMFULL); + } + + LPMETAFILEPICT pMF=(LPMETAFILEPICT)GlobalLock(hMem); + pMF->hMF=hMF; + pMF->mm=MM_ANISOTROPIC; + pMF->xExt=sizeMetric.cx; + pMF->yExt=sizeMetric.cy; + GlobalUnlock(hMem); + + pmedium->tymed = TYMED_MFPICT; + pmedium->hGlobal = hMem; + pmedium->pUnkForRelease = NULL; + + return S_OK; +} + +inline HRESULT CComControlBase::FireViewChange() +{ + if (m_bInPlaceActive) + { + // Active + if (m_hWndCD != NULL) + ::InvalidateRect(m_hWndCD, NULL, TRUE); // Window based + else if (m_bWndLess && m_spInPlaceSite != NULL) + m_spInPlaceSite->InvalidateRect(NULL, TRUE); // Windowless + } + else // Inactive + SendOnViewChange(DVASPECT_CONTENT); + return S_OK; +} + +inline void CComControlBase::GetZoomInfo(ATL_DRAWINFO& di) +{ + const RECTL& rcPos = *di.prcBounds; + SIZEL sizeDen; + if (m_bDrawFromNatural) + sizeDen = m_sizeNatural; + else + sizeDen = m_sizeExtent; + if (!di.bRectInHimetric) + AtlHiMetricToPixel(&sizeDen, &sizeDen); + SIZEL sizeNum = {rcPos.right-rcPos.left, rcPos.bottom-rcPos.top}; + di.ZoomNum.cx = sizeNum.cx; + di.ZoomNum.cy = sizeNum.cy; + di.ZoomDen.cx = sizeDen.cx; + di.ZoomDen.cy = sizeDen.cy; + if (sizeDen.cx == 0 || sizeDen.cy == 0 || + sizeNum.cx == 0 || sizeNum.cy == 0) + { + di.ZoomNum.cx = di.ZoomNum.cy = di.ZoomDen.cx = di.ZoomDen.cy = 1; + di.bZoomed = FALSE; + } + else if (sizeNum.cx != sizeDen.cx || sizeNum.cy != sizeDen.cy) + di.bZoomed = TRUE; + else + di.bZoomed = FALSE; +} + +inline HRESULT CComControlBase::OnDrawAdvanced(ATL_DRAWINFO& di) +{ + BOOL bDeleteDC = FALSE; + if (di.hicTargetDev == NULL) + { + di.hicTargetDev = AtlCreateTargetDC(di.hdcDraw, di.ptd); + bDeleteDC = (di.hicTargetDev != di.hdcDraw); + } + RECTL rectBoundsDP = *di.prcBounds; + BOOL bMetafile = GetDeviceCaps(di.hdcDraw, TECHNOLOGY) == DT_METAFILE; + if (!bMetafile) + { + ::LPtoDP(di.hdcDraw, (LPPOINT)&rectBoundsDP, 2); + SaveDC(di.hdcDraw); + SetMapMode(di.hdcDraw, MM_TEXT); + SetWindowOrgEx(di.hdcDraw, 0, 0, NULL); + SetViewportOrgEx(di.hdcDraw, 0, 0, NULL); + di.bOptimize = TRUE; //since we save the DC we can do this + } + di.prcBounds = &rectBoundsDP; + GetZoomInfo(di); + + HRESULT hRes = OnDraw(di); + if (bDeleteDC) + ::DeleteDC(di.hicTargetDev); + if (!bMetafile) + RestoreDC(di.hdcDraw, -1); + return hRes; +} + +inline LRESULT CComControlBase::OnPaint(UINT /* uMsg */, WPARAM wParam, + LPARAM /* lParam */, BOOL& /* lResult */) +{ + RECT rc; + PAINTSTRUCT ps; + + HDC hdc = (wParam != NULL) ? (HDC)wParam : ::BeginPaint(m_hWndCD, &ps); + if (hdc == NULL) + return 0; + ::GetClientRect(m_hWndCD, &rc); + + ATL_DRAWINFO di; + memset(&di, 0, sizeof(di)); + di.cbSize = sizeof(di); + di.dwDrawAspect = DVASPECT_CONTENT; + di.lindex = -1; + di.hdcDraw = hdc; + di.prcBounds = (LPCRECTL)&rc; + + OnDrawAdvanced(di); + if (wParam == NULL) + ::EndPaint(m_hWndCD, &ps); + return 0; +} + + +template > +class ATL_NO_VTABLE CComControl : public CComControlBase, public WinBase +{ +public: + CComControl() : CComControlBase(m_hWnd) {} + + virtual HWND CreateControlWindow(HWND hWndParent, RECT& rcPos) + { + T* pT = static_cast(this); + return pT->Create(hWndParent, rcPos); + } + + HRESULT FireOnRequestEdit(DISPID dispID) + { + T* pT = static_cast(this); + return T::__ATL_PROP_NOTIFY_EVENT_CLASS::FireOnRequestEdit(pT->GetUnknown(), dispID); + } + HRESULT FireOnChanged(DISPID dispID) + { + T* pT = static_cast(this); + return T::__ATL_PROP_NOTIFY_EVENT_CLASS::FireOnChanged(pT->GetUnknown(), dispID); + } + + virtual HRESULT ControlQueryInterface(const IID& iid, void** ppv) + { + T* pT = static_cast(this); + return pT->GetUnknown()->QueryInterface(iid, ppv); + } + + int MessageBox(LPCTSTR lpszText, LPCTSTR lpszCaption = _T(""), UINT nType = MB_OK) + { + if (::IsWindow(m_hWndCD)) + return ::MessageBox(m_hWndCD, lpszText, lpszCaption, nType); + HWND hwndParent; + if (m_spInPlaceSite && m_spInPlaceSite->GetWindow(&hwndParent) == S_OK) + return ::MessageBox(hwndParent, lpszText, lpszCaption, nType); + return ::MessageBox(NULL, lpszText, lpszCaption, nType); + } + + typedef CComControl< T, WinBase > thisClass; + typedef WinBase baseWinClass; + BEGIN_MSG_MAP(thisClass) + __if_not_exists(WinBase::m_wndReflector) + { + MESSAGE_HANDLER(WM_PAINT, CComControlBase::OnPaint) + } + MESSAGE_HANDLER(WM_SETFOCUS, CComControlBase::OnSetFocus) + MESSAGE_HANDLER(WM_KILLFOCUS, CComControlBase::OnKillFocus) + MESSAGE_HANDLER(WM_MOUSEACTIVATE, CComControlBase::OnMouseActivate) + __if_exists(WinBase::m_wndReflector) + { + CHAIN_MSG_MAP(baseWinClass) + } + END_MSG_MAP() +}; + +////////////////////////////////////////////////////////////////////////////// +// CComCompositeControl + +#ifndef _ATL_NO_HOSTING +template +class CComCompositeControl : public CComControl< T, CAxDialogImpl< T > > +{ +public: + CComCompositeControl() + { + m_hbrBackground = NULL; + m_hWndFocus = NULL; + } + ~CComCompositeControl() + { + DeleteObject(m_hbrBackground); + } + HRESULT AdviseSinkMap(bool bAdvise) + { + if(!bAdvise && m_hWnd == NULL) + { + // window is gone, controls are already unadvised + ATLTRACE(atlTraceControls, 1, _T("CComCompositeControl::AdviseSinkMap called after the window was destroyed\n")); + return S_OK; + } + T* pT = static_cast(this); + return AtlAdviseSinkMap(pT, bAdvise); + } + HBRUSH m_hbrBackground; + HRESULT SetBackgroundColorFromAmbient() + { + if (m_hbrBackground != NULL) + { + DeleteObject(m_hbrBackground); + m_hbrBackground = NULL; + } + OLE_COLOR clr; + HRESULT hr = GetAmbientBackColor(clr); + if (SUCCEEDED(hr)) + { + COLORREF rgb; + ::OleTranslateColor(clr, NULL, &rgb); + m_hbrBackground = ::CreateSolidBrush(rgb); + EnumChildWindows(m_hWnd, (WNDENUMPROC)BackgroundColorEnumProc, (LPARAM) clr); + } + return hr; + } + static BOOL CALLBACK BackgroundColorEnumProc(HWND hwnd, LPARAM l) + { + CAxWindow wnd(hwnd); + CComPtr spDispatch; + wnd.QueryHost(&spDispatch); + if (spDispatch != NULL) + spDispatch->put_BackColor((OLE_COLOR)l); + return TRUE; + } + LRESULT OnDialogColor(UINT, WPARAM w, LPARAM, BOOL&) + { + HIGHCONTRAST contrastMode; + memset(&contrastMode, 0, sizeof(HIGHCONTRAST)); + contrastMode.cbSize = sizeof(HIGHCONTRAST); + + if (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST), &contrastMode, 0) && + (contrastMode.dwFlags & HCF_HIGHCONTRASTON) != 0) + + return DefWindowProc(); + + HDC dc = (HDC) w; + LOGBRUSH lb; + ::GetObject(m_hbrBackground, sizeof(lb), (void*)&lb); + ::SetBkColor(dc, lb.lbColor); + return (LRESULT)m_hbrBackground; + } + HWND Create(HWND hWndParent, RECT& /*rcPos*/, LPARAM dwInitParam = NULL) + { + CComControl< T, CAxDialogImpl< T > >::Create(hWndParent, dwInitParam); + SetBackgroundColorFromAmbient(); + if (m_hWnd != NULL) + ShowWindow(SW_SHOWNOACTIVATE); + return m_hWnd; + } + BOOL CalcExtent(SIZE& size) + { + HINSTANCE hInstance = _AtlBaseModule.GetResourceInstance(); + LPCTSTR lpTemplateName = MAKEINTRESOURCE(static_cast(this)->IDD); + HRSRC hDlgTempl = FindResource(hInstance, lpTemplateName, RT_DIALOG); + if (hDlgTempl == NULL) + return FALSE; + HGLOBAL hResource = LoadResource(hInstance, hDlgTempl); + DLGTEMPLATE* pDlgTempl = (DLGTEMPLATE*)LockResource(hResource); + if (pDlgTempl == NULL) + return FALSE; + AtlGetDialogSize(pDlgTempl, &size); + AtlPixelToHiMetric(&size, &size); + return TRUE; + } +//Implementation + BOOL PreTranslateAccelerator(LPMSG pMsg, HRESULT& hRet) + { + hRet = S_OK; + + if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) && + (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST)) + return FALSE; + // find a direct child of the dialog from the window that has focus + HWND hWndCtl = ::GetFocus(); + if (IsChild(hWndCtl) && ::GetParent(hWndCtl) != m_hWnd) + { + do + { + hWndCtl = ::GetParent(hWndCtl); + } + while (::GetParent(hWndCtl) != m_hWnd); + } + // give controls a chance to translate this message + if (::SendMessage(hWndCtl, WM_FORWARDMSG, 0, (LPARAM)pMsg) == 1) + return TRUE; + + // special handling for keyboard messages + LRESULT dwDlgCode = ::SendMessage(pMsg->hwnd, WM_GETDLGCODE, 0, 0); + switch(pMsg->message) + { + case WM_CHAR: + if(dwDlgCode == 0) // no dlgcode, possibly an ActiveX control + return FALSE; // let the container process this + break; + case WM_KEYDOWN: + switch(LOWORD(pMsg->wParam)) + { + case VK_TAB: + // prevent tab from looping inside of our dialog + if((dwDlgCode & DLGC_WANTTAB) == 0) + { + HWND hWndFirstOrLast = ::GetWindow(m_hWnd, GW_CHILD); + if (::GetKeyState(VK_SHIFT) >= 0) // not pressed + hWndFirstOrLast = GetNextDlgTabItem(hWndFirstOrLast, TRUE); + if (hWndFirstOrLast == hWndCtl) + return FALSE; + } + break; + case VK_LEFT: + case VK_UP: + case VK_RIGHT: + case VK_DOWN: + // prevent arrows from looping inside of our dialog + if((dwDlgCode & DLGC_WANTARROWS) == 0) + { + HWND hWndFirstOrLast = ::GetWindow(m_hWnd, GW_CHILD); + if (pMsg->wParam == VK_RIGHT || pMsg->wParam == VK_DOWN) // going forward + hWndFirstOrLast = GetNextDlgTabItem(hWndFirstOrLast, TRUE); + if (hWndFirstOrLast == hWndCtl) + return FALSE; + } + break; + case VK_RETURN: + break; + case VK_EXECUTE: + case VK_ESCAPE: + case VK_CANCEL: + // we don't want to handle these, let the container do it + return FALSE; + } + break; + } + + BOOL bRet; + //Process accel msg + if ( (pMsg->message == WM_SYSCHAR) || (pMsg->message == WM_SYSKEYDOWN) || (pMsg->message == WM_SYSKEYUP) ) + { + T* pT = static_cast(this); + + CONTROLINFO ci; + HRESULT hr = pT->GetControlInfo(&ci); + if (SUCCEEDED(hr)) + { + if (ci.cAccel > 0) + { + ACCEL* pAccel = new ACCEL[ci.cAccel]; + if (pAccel == NULL) + { + //Out of memory, don't send to control site + hRet = E_OUTOFMEMORY; + return TRUE; + } + int cAccel = CopyAcceleratorTable(ci.hAccel, pAccel, ci.cAccel); + ATLASSERT(cAccel == ci.cAccel); + bRet = FALSE; //Accel not processed (invalid) + WORD fVert = (pMsg->message == WM_SYSCHAR) ? FALT : 0; + WORD key = LOWORD(pMsg->wParam); + for (int i = 0; i < cAccel; i++) + { + if (((pAccel[i].fVirt & ~FNOINVERT & ~FVIRTKEY) == fVert) && + ((pAccel[i].key == __ascii_towupper(key)) || pAccel[i].key == __ascii_towlower(key))) + { + bRet = ::IsDialogMessage(m_hWnd, pMsg); //Accel is valid, process + break; + } + } + delete [] pAccel; + } + else + bRet = FALSE; //No accels to process, let the container handle + } + else + { + bRet = ::IsDialogMessage(m_hWnd, pMsg); //Backward compt. (not impl GetControlInfo) + } + } + else + { + bRet = ::IsDialogMessage(m_hWnd, pMsg); //Not an accelerator msg + } + + if (bRet) + { + HWND hWndCtlNewFocus = ::GetFocus(); + if (IsChild(hWndCtlNewFocus)) + m_hWndFocus = hWndCtlNewFocus; + else + m_hWndFocus = NULL; + if (IsChild(hWndCtlNewFocus) && ::GetParent(hWndCtlNewFocus) != m_hWnd) + { + do + { + hWndCtlNewFocus = ::GetParent(hWndCtlNewFocus); + } + while (::GetParent(hWndCtlNewFocus) != m_hWnd); + } + + if (IsChild(hWndCtlNewFocus) && IsChild(hWndCtl) && hWndCtl != hWndCtlNewFocus) + { + CComPtr spUnknown; + HRESULT hr = AtlAxGetControl(hWndCtl, &spUnknown); + if (SUCCEEDED(hr)) + { + CComPtr spIOleInPlaceObject; + hr = spUnknown->QueryInterface(&spIOleInPlaceObject); + if (SUCCEEDED(hr)) + spIOleInPlaceObject->UIDeactivate(); + } + } + } + return bRet; + } + HRESULT IOleInPlaceObject_InPlaceDeactivate(void) + { + AdviseSinkMap(false); //unadvise + return CComControl >::IOleInPlaceObject_InPlaceDeactivate(); + } + HRESULT IOleInPlaceObject_UIDeactivate(void) + { + if (m_hWndFocus != NULL) + { + HWND hWnd = m_hWndFocus; + do + { + hWnd = ::GetParent(hWnd); + } + while (hWnd != NULL && ::GetParent(hWnd) != m_hWnd); + if (hWnd != m_hWndFocus) + { + CComPtr spUnknown; + HRESULT hr = AtlAxGetControl(hWnd, &spUnknown); + if (SUCCEEDED(hr)) + { + CComPtr spIOleInPlaceObject; + hr = spUnknown->QueryInterface(&spIOleInPlaceObject); + if (SUCCEEDED(hr)) + spIOleInPlaceObject->UIDeactivate(); + } + } + } + m_hWndFocus = NULL; + return CComControl >::IOleInPlaceObject_UIDeactivate(); + return S_OK; + } + + virtual HWND CreateControlWindow(HWND hWndParent, RECT& rcPos) + { + T* pT = static_cast(this); + HWND h = pT->Create(hWndParent, rcPos); + if (h != NULL) + AdviseSinkMap(true); + return h; + } + virtual HRESULT OnDraw(ATL_DRAWINFO& di) + { + if(!m_bInPlaceActive) + { + HPEN hPen = (HPEN)::GetStockObject(BLACK_PEN); + HBRUSH hBrush = (HBRUSH)::GetStockObject(GRAY_BRUSH); + ::SelectObject(di.hdcDraw, hPen); + ::SelectObject(di.hdcDraw, hBrush); + ::Rectangle(di.hdcDraw, di.prcBounds->left, di.prcBounds->top, di.prcBounds->right, di.prcBounds->bottom); + ::SetTextColor(di.hdcDraw, ::GetSysColor(COLOR_WINDOWTEXT)); + ::SetBkMode(di.hdcDraw, TRANSPARENT); + ::DrawText(di.hdcDraw, _T("ATL Composite Control"), -1, (LPRECT)di.prcBounds, DT_CENTER | DT_SINGLELINE | DT_VCENTER); + } + return S_OK; + } + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + // initialize controls in dialog with DLGINIT resource section + ExecuteDlgInit(static_cast(this)->IDD); + bHandled = TRUE; + return 1; + } + // save HWND of child that last had focus + LRESULT OnChildKillFocus(WORD /*wNotifyCode*/, WORD /*wID*/, HWND hWndCtl, BOOL& bHandled) + { + m_hWndFocus = hWndCtl; + bHandled = FALSE; + return 0; + } + LRESULT OnNMKillFocus(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) + { + m_hWndFocus = pnmh->hwndFrom; + bHandled = FALSE; + return 0; + } + LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) + { + // Call base class OnSetFocus so control is UI-activated. + baseClass::OnSetFocus(0, 0, 0, bHandled); + // Shift-tab, up or left arrow was pressed, set focus to last control. + if ((GetKeyState(VK_SHIFT) < 0 && GetKeyState(VK_TAB) < 0) || + (GetKeyState(VK_UP) < 0) || (GetKeyState(VK_LEFT) < 0)) + { + ::SetFocus(::GetWindow(::GetWindow(m_hWnd, GW_CHILD), GW_HWNDLAST)); + } + // Tab, down or right arrow was pressed, set focus to first control. + else if (GetKeyState(VK_TAB) < 0 || GetKeyState(VK_DOWN) < 0 || + GetKeyState(VK_RIGHT) < 0) + { + ::SetFocus(::GetWindow(m_hWnd, GW_CHILD)); + } + else + { + if (!::IsWindow(m_hWndFocus) || !::IsChild(m_hWnd, m_hWndFocus)) + m_hWndFocus = ::GetWindow(m_hWnd, GW_CHILD); + // set focus to last child window that had focus + ::SetFocus(m_hWndFocus); + } + + bHandled = TRUE; + return 0; + } + typedef CComControl< T, CAxDialogImpl< T > > baseClass; + LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) + { + ATLTRACE(_T("CComCompositeControl::OnMouseActivate\n")); + HWND hWndFocus = GetFocus(); + if (m_hWndFocus != NULL) + { + if (m_hWndFocus != m_hWnd && hWndFocus != m_hWndFocus) + { + HWND hWnd = m_hWndFocus; + do + { + hWnd = ::GetParent(hWnd); + } + while (hWnd != NULL && ::GetParent(hWnd) != m_hWnd); + + if (hWnd != m_hWndFocus) + { + CComPtr spUnknown; + HRESULT hr = AtlAxGetControl(hWnd, &spUnknown); + if (SUCCEEDED(hr)) + { + CComPtr spIOleInPlaceObject; + hr = spUnknown->QueryInterface(&spIOleInPlaceObject); + if (SUCCEEDED(hr)) + spIOleInPlaceObject->UIDeactivate(); + } + } + } + } + if (IsChild(hWndFocus)) + m_hWndFocus = hWndFocus; + else + m_hWndFocus = NULL; + + return baseClass::OnMouseActivate(uMsg, wParam, lParam, bHandled); + } + + BEGIN_MSG_MAP(CComCompositeControl< T >) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + MESSAGE_HANDLER(WM_CTLCOLORDLG, OnDialogColor) + MESSAGE_HANDLER(WM_CTLCOLORSTATIC, OnDialogColor) + MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) + COMMAND_CODE_HANDLER(EN_KILLFOCUS, OnChildKillFocus) + COMMAND_CODE_HANDLER(BN_KILLFOCUS, OnChildKillFocus) + COMMAND_CODE_HANDLER(LBN_KILLFOCUS, OnChildKillFocus) + COMMAND_CODE_HANDLER(CBN_KILLFOCUS, OnChildKillFocus) + NOTIFY_CODE_HANDLER(NM_KILLFOCUS, OnNMKillFocus) + MESSAGE_HANDLER(WM_KILLFOCUS, baseClass::OnKillFocus) + MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate) + END_MSG_MAP() + + BEGIN_SINK_MAP(T) + END_SINK_MAP() + + HWND m_hWndFocus; +}; +#endif //_ATL_NO_HOSTING + +// Forward declarations +// +template class IPersistStorageImpl; +template class IPersistPropertyBagImpl; + +template class IOleControlImpl; +template class IRunnableObjectImpl; +template class IQuickActivateImpl; +template class IOleObjectImpl; +template class IPropertyPageImpl; +template class IPropertyPage2Impl; +template class IPerPropertyBrowsingImpl; +template class IViewObjectExImpl; +template class IOleWindowImpl; +template class IPointerInactiveImpl; +template class IPropertyNotifySinkCP; +template class IBindStatusCallbackImpl; +template class CBindStatusCallback; + + +////////////////////////////////////////////////////////////////////////////// +// IOleControlImpl +template +class ATL_NO_VTABLE IOleControlImpl : public IOleControl +{ +public: + STDMETHOD(GetControlInfo)(LPCONTROLINFO /* pCI */) + { + ATLTRACENOTIMPL(_T("IOleControlImpl::GetControlInfo")); + } + STDMETHOD(OnMnemonic)(LPMSG /* pMsg */) + { + ATLTRACENOTIMPL(_T("IOleControlImpl::OnMnemonic")); + } + STDMETHOD(OnAmbientPropertyChange)(DISPID dispid) + { + dispid; + ATLTRACE(atlTraceControls,2,_T("IOleControlImpl::OnAmbientPropertyChange\n")); + ATLTRACE(atlTraceControls,2,_T(" -- DISPID = %d\n"), dispid); + return S_OK; + } + STDMETHOD(FreezeEvents)(BOOL bFreeze) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleControlImpl::FreezeEvents\n")); + if (bFreeze) + pT->m_nFreezeEvents++; + else + pT->m_nFreezeEvents--; + return S_OK; + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// IQuickActivateImpl +template +class ATL_NO_VTABLE IQuickActivateImpl : public IQuickActivate +{ +public: + STDMETHOD(QuickActivate)(QACONTAINER *pQACont, QACONTROL *pQACtrl) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IQuickActivateImpl::QuickActivate\n")); + __if_exists(T::m_clrForeColor) + { + pT->m_clrForeColor = pQACont->colorFore; + } + __if_exists(T::m_clrBackColor) + { + pT->m_clrBackColor = pQACont->colorBack; + } + __if_exists(T::m_nAppearance) + { + // If you've declared m_nAppearance as something other than + // 'short', you'll need to typedef AppearanceType to that type + // in your derived class T. + pT->m_nAppearance = static_cast(pQACont->dwAppearance); + } + return pT->IQuickActivate_QuickActivate(pQACont, pQACtrl); + } + STDMETHOD(SetContentExtent)(LPSIZEL pSize) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IQuickActivateImpl::SetContentExtent\n")); + return pT->IOleObjectImpl::SetExtent(DVASPECT_CONTENT, pSize); + } + STDMETHOD(GetContentExtent)(LPSIZEL pSize) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IQuickActivateImpl::GetContentExtent\n")); + return pT->IOleObjectImpl::GetExtent(DVASPECT_CONTENT, pSize); + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// IOleObjectImpl +template +class ATL_NO_VTABLE IOleObjectImpl : public IOleObject +{ +public: + STDMETHOD(SetClientSite)(IOleClientSite *pClientSite) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::SetClientSite\n")); + return pT->IOleObject_SetClientSite(pClientSite); + } + STDMETHOD(GetClientSite)(IOleClientSite **ppClientSite) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::GetClientSite\n")); + return pT->IOleObject_GetClientSite(ppClientSite); + } + STDMETHOD(SetHostNames)(LPCOLESTR /* szContainerApp */, LPCOLESTR /* szContainerObj */) + { + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::SetHostNames\n")); + return S_OK; + } + STDMETHOD(Close)(DWORD dwSaveOption) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::Close\n")); + return pT->IOleObject_Close(dwSaveOption); + } + STDMETHOD(SetMoniker)(DWORD /* dwWhichMoniker */, IMoniker* /* pmk */) + { + ATLTRACENOTIMPL(_T("IOleObjectImpl::SetMoniker")); + } + STDMETHOD(GetMoniker)(DWORD /* dwAssign */, DWORD /* dwWhichMoniker */, IMoniker** /* ppmk */) + { + ATLTRACENOTIMPL(_T("IOleObjectImpl::GetMoniker")); + } + STDMETHOD(InitFromData)(IDataObject* /* pDataObject */, BOOL /* fCreation */, DWORD /* dwReserved */) + { + ATLTRACENOTIMPL(_T("IOleObjectImpl::InitFromData")); + } + STDMETHOD(GetClipboardData)(DWORD /* dwReserved */, IDataObject** /* ppDataObject */) + { + ATLTRACENOTIMPL(_T("IOleObjectImpl::GetClipboardData")); + } + + // Helpers for DoVerb - Over-rideable in user class + HRESULT DoVerbPrimary(LPCRECT prcPosRect, HWND hwndParent) + { + T* pT = static_cast(this); + BOOL bDesignMode = FALSE; + CComVariant var; + // if container doesn't support this property + // don't allow design mode + HRESULT hRes = pT->GetAmbientProperty(DISPID_AMBIENT_USERMODE, var); + if (SUCCEEDED(hRes) && var.vt == VT_BOOL && !var.boolVal) + bDesignMode = TRUE; + if (bDesignMode) + return pT->DoVerbProperties(prcPosRect, hwndParent); + return pT->DoVerbInPlaceActivate(prcPosRect, hwndParent); + } + HRESULT DoVerbShow(LPCRECT prcPosRect, HWND /* hwndParent */) + { + T* pT = static_cast(this); + HRESULT hr; + hr = pT->OnPreVerbShow(); + if (SUCCEEDED(hr)) + { + hr = pT->InPlaceActivate(OLEIVERB_SHOW, prcPosRect); + if (SUCCEEDED(hr)) + hr = pT->OnPostVerbShow(); + } + return hr; + } + HRESULT DoVerbInPlaceActivate(LPCRECT prcPosRect, HWND /* hwndParent */) + { + T* pT = static_cast(this); + HRESULT hr; + hr = pT->OnPreVerbInPlaceActivate(); + if (SUCCEEDED(hr)) + { + hr = pT->InPlaceActivate(OLEIVERB_INPLACEACTIVATE, prcPosRect); + if (SUCCEEDED(hr)) + hr = pT->OnPostVerbInPlaceActivate(); + if (SUCCEEDED(hr)) + pT->FireViewChange(); + } + return hr; + } + HRESULT DoVerbUIActivate(LPCRECT prcPosRect, HWND /* hwndParent */) + { + T* pT = static_cast(this); + HRESULT hr = S_OK; + if (!pT->m_bUIActive) + { + hr = pT->OnPreVerbUIActivate(); + if (SUCCEEDED(hr)) + { + hr = pT->InPlaceActivate(OLEIVERB_UIACTIVATE, prcPosRect); + if (SUCCEEDED(hr)) + hr = pT->OnPostVerbUIActivate(); + } + } + return hr; + } + HRESULT DoVerbHide(LPCRECT /* prcPosRect */, HWND /* hwndParent */) + { + T* pT = static_cast(this); + HRESULT hr; + hr = pT->OnPreVerbHide(); + if (SUCCEEDED(hr)) + { + pT->UIDeactivate(); + if (pT->m_hWnd) + pT->ShowWindow(SW_HIDE); + hr = pT->OnPostVerbHide(); + } + return hr; + } + HRESULT DoVerbOpen(LPCRECT /* prcPosRect */, HWND /* hwndParent */) + { + T* pT = static_cast(this); + HRESULT hr; + hr = pT->OnPreVerbOpen(); + if (SUCCEEDED(hr)) + hr = pT->OnPostVerbOpen(); + return hr; + } + HRESULT DoVerbDiscardUndo(LPCRECT /* prcPosRect */, HWND /* hwndParent */) + { + T* pT = static_cast(this); + HRESULT hr; + hr = pT->OnPreVerbDiscardUndo(); + if (SUCCEEDED(hr)) + hr = pT->OnPostVerbDiscardUndo(); + return hr; + } + STDMETHOD(DoVerb)(LONG iVerb, LPMSG /* pMsg */, IOleClientSite* pActiveSite, LONG /* lindex */, + HWND hwndParent, LPCRECT lprcPosRect) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::DoVerb(%d)\n"), iVerb); + ATLASSERT(pT->m_spClientSite); + + // We don't support getting a different site from the one passed into SetClientSite. + if (!pT->m_spClientSite.IsEqualObject(pActiveSite)) + { + return E_UNEXPECTED; + } + + HRESULT hr; + if (iVerb > 0) + { + pT->DoVerbPrimary(lprcPosRect, hwndParent); + hr = OLEOBJ_S_INVALIDVERB; + } + else + { + hr = E_NOTIMPL; + switch (iVerb) + { + case OLEIVERB_PRIMARY: + hr = pT->DoVerbPrimary(lprcPosRect, hwndParent); + break; + case OLEIVERB_SHOW: + hr = pT->DoVerbShow(lprcPosRect, hwndParent); + break; + case OLEIVERB_INPLACEACTIVATE: + hr = pT->DoVerbInPlaceActivate(lprcPosRect, hwndParent); + break; + case OLEIVERB_UIACTIVATE: + hr = pT->DoVerbUIActivate(lprcPosRect, hwndParent); + break; + case OLEIVERB_HIDE: + hr = pT->DoVerbHide(lprcPosRect, hwndParent); + break; + case OLEIVERB_OPEN: + hr = pT->DoVerbOpen(lprcPosRect, hwndParent); + break; + case OLEIVERB_DISCARDUNDOSTATE: + hr = pT->DoVerbDiscardUndo(lprcPosRect, hwndParent); + break; + case OLEIVERB_PROPERTIES: + hr = pT->DoVerbProperties(lprcPosRect, hwndParent); + } + } + return hr; + } + STDMETHOD(EnumVerbs)(IEnumOLEVERB **ppEnumOleVerb) + { + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::EnumVerbs\n")); + ATLASSERT(ppEnumOleVerb); + if (!ppEnumOleVerb) + return E_POINTER; + return OleRegEnumVerbs(T::GetObjectCLSID(), ppEnumOleVerb); + } + STDMETHOD(Update)(void) + { + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::Update\n")); + return S_OK; + } + STDMETHOD(IsUpToDate)(void) + { + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::IsUpToDate\n")); + return S_OK; + } + STDMETHOD(GetUserClassID)(CLSID *pClsid) + { + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::GetUserClassID\n")); + ATLASSERT(pClsid); + if (!pClsid) + return E_POINTER; + *pClsid = T::GetObjectCLSID(); + return S_OK; + } + STDMETHOD(GetUserType)(DWORD dwFormOfType, LPOLESTR *pszUserType) + { + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::GetUserType\n")); + return OleRegGetUserType(T::GetObjectCLSID(), dwFormOfType, pszUserType); + } + STDMETHOD(SetExtent)(DWORD dwDrawAspect, SIZEL *psizel) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::SetExtent\n")); + return pT->IOleObject_SetExtent(dwDrawAspect, psizel); + } + STDMETHOD(GetExtent)(DWORD dwDrawAspect, SIZEL *psizel) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::GetExtent\n")); + if (dwDrawAspect != DVASPECT_CONTENT) + return E_FAIL; + if (psizel == NULL) + return E_POINTER; + *psizel = pT->m_sizeExtent; + return S_OK; + } + STDMETHOD(Advise)(IAdviseSink *pAdvSink, DWORD *pdwConnection) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::Advise\n")); + return pT->IOleObject_Advise(pAdvSink, pdwConnection); + } + STDMETHOD(Unadvise)(DWORD dwConnection) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::Unadvise\n")); + HRESULT hRes = E_FAIL; + if (pT->m_spOleAdviseHolder != NULL) + hRes = pT->m_spOleAdviseHolder->Unadvise(dwConnection); + return hRes; + } + STDMETHOD(EnumAdvise)(IEnumSTATDATA **ppenumAdvise) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::EnumAdvise\n")); + ATLASSERT(ppenumAdvise != NULL); + if (ppenumAdvise == NULL) + return E_POINTER; + *ppenumAdvise = NULL; + HRESULT hRes = E_FAIL; + if (pT->m_spOleAdviseHolder != NULL) + hRes = pT->m_spOleAdviseHolder->EnumAdvise(ppenumAdvise); + return hRes; + } + STDMETHOD(GetMiscStatus)(DWORD dwAspect, DWORD *pdwStatus) + { + ATLTRACE(atlTraceControls,2,_T("IOleObjectImpl::GetMiscStatus\n")); + return OleRegGetMiscStatus(T::GetObjectCLSID(), dwAspect, pdwStatus); + } + STDMETHOD(SetColorScheme)(LOGPALETTE* /* pLogpal */) + { + ATLTRACENOTIMPL(_T("IOleObjectImpl::SetColorScheme")); + } +// Implementation +public: + HRESULT OnPreVerbShow() { return S_OK; } + HRESULT OnPostVerbShow() { return S_OK; } + HRESULT OnPreVerbInPlaceActivate() { return S_OK; } + HRESULT OnPostVerbInPlaceActivate() { return S_OK; } + HRESULT OnPreVerbUIActivate() { return S_OK; } + HRESULT OnPostVerbUIActivate() { return S_OK; } + HRESULT OnPreVerbHide() { return S_OK; } + HRESULT OnPostVerbHide() { return S_OK; } + HRESULT OnPreVerbOpen() { return S_OK; } + HRESULT OnPostVerbOpen() { return S_OK; } + HRESULT OnPreVerbDiscardUndo() { return S_OK; } + HRESULT OnPostVerbDiscardUndo() { return S_OK; } +}; + +////////////////////////////////////////////////////////////////////////////// +// IPropertyPageImpl +template +class ATL_NO_VTABLE IPropertyPageImpl : public IPropertyPage +{ + +public: + void SetDirty(BOOL bDirty) + { + T* pT = static_cast(this); + if (pT->m_bDirty != bDirty) + { + pT->m_bDirty = bDirty; + pT->m_pPageSite->OnStatusChange(bDirty ? PROPPAGESTATUS_DIRTY : PROPPAGESTATUS_CLEAN); + } + } + + IPropertyPageImpl() + { + T* pT = static_cast(this); + pT->m_pPageSite = NULL; + pT->m_size.cx = 0; + pT->m_size.cy = 0; + pT->m_dwTitleID = 0; + pT->m_dwHelpFileID = 0; + pT->m_dwDocStringID = 0; + pT->m_dwHelpContext = 0; + pT->m_ppUnk = NULL; + pT->m_nObjects = 0; + pT->m_bDirty = FALSE; + pT->m_hWnd = NULL; + } + + ~IPropertyPageImpl() + { + T* pT = static_cast(this); + if (pT->m_pPageSite != NULL) + pT->m_pPageSite->Release(); + + for (UINT i = 0; i < m_nObjects; i++) + pT->m_ppUnk[i]->Release(); + + delete[] pT->m_ppUnk; + } + + // IPropertyPage + // + STDMETHOD(SetPageSite)(IPropertyPageSite *pPageSite) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::SetPageSite\n")); + + if (!pPageSite && pT->m_pPageSite) + { + pT->m_pPageSite->Release(); + pT->m_pPageSite = NULL; + return S_OK; + } + + if (!pPageSite && !pT->m_pPageSite) + return S_OK; + + if (pPageSite && pT->m_pPageSite) + { + ATLTRACE(atlTraceControls,2,_T("Error : setting page site again with non NULL value\n")); + return E_UNEXPECTED; + } + + pT->m_pPageSite = pPageSite; + pT->m_pPageSite->AddRef(); + return S_OK; + } + STDMETHOD(Activate)(HWND hWndParent, LPCRECT pRect, BOOL /* bModal */) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::Activate\n")); + + if (pRect == NULL) + { + ATLTRACE(atlTraceControls,2,_T("Error : Passed a NULL rect\n")); + return E_POINTER; + } + + pT->m_hWnd = pT->Create(hWndParent); + Move(pRect); + + m_size.cx = pRect->right - pRect->left; + m_size.cy = pRect->bottom - pRect->top; + + return S_OK; + + } + STDMETHOD(Deactivate)( void) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::Deactivate\n")); + + if (pT->m_hWnd) + { + ATLTRACE(atlTraceControls,2,_T("Destroying Dialog\n")); + if (::IsWindow(pT->m_hWnd)) + pT->DestroyWindow(); + pT->m_hWnd = NULL; + } + + return S_OK; + + } + STDMETHOD(GetPageInfo)(PROPPAGEINFO *pPageInfo) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::GetPageInfo\n")); + + if (pPageInfo == NULL) + { + ATLTRACE(atlTraceControls,2,_T("Error : PROPPAGEINFO passed == NULL\n")); + return E_POINTER; + } + + HRSRC hRsrc = FindResource(_AtlBaseModule.GetResourceInstance(), + MAKEINTRESOURCE(static_cast(this)->IDD), RT_DIALOG); + if (hRsrc == NULL) + { + ATLTRACE(atlTraceControls,2,_T("Could not find resource template\n")); + return E_UNEXPECTED; + } + + HGLOBAL hGlob = LoadResource(_AtlBaseModule.GetResourceInstance(), hRsrc); + DLGTEMPLATE* pDlgTempl = (DLGTEMPLATE*)LockResource(hGlob); + if (pDlgTempl == NULL) + { + ATLTRACE(atlTraceControls,2,_T("Could not load resource template\n")); + return E_UNEXPECTED; + } + AtlGetDialogSize(pDlgTempl, &m_size, true); + + pPageInfo->cb = sizeof(PROPPAGEINFO); + pPageInfo->pszTitle = LoadStringHelper(pT->m_dwTitleID); + pPageInfo->size = m_size; + pPageInfo->pszHelpFile = LoadStringHelper(pT->m_dwHelpFileID); + pPageInfo->pszDocString = LoadStringHelper(pT->m_dwDocStringID); + pPageInfo->dwHelpContext = pT->m_dwHelpContext; + + return S_OK; + } + + STDMETHOD(SetObjects)(ULONG nObjects, IUnknown **ppUnk) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::SetObjects\n")); + + if (ppUnk == NULL) + return E_POINTER; + + if (pT->m_ppUnk != NULL && pT->m_nObjects > 0) + { + for (UINT iObj = 0; iObj < pT->m_nObjects; iObj++) + pT->m_ppUnk[iObj]->Release(); + + delete [] pT->m_ppUnk; + } + + pT->m_ppUnk = NULL; + ATLTRY(pT->m_ppUnk = new IUnknown*[nObjects]); + + if (pT->m_ppUnk == NULL) + return E_OUTOFMEMORY; + + for (UINT i = 0; i < nObjects; i++) + { + ppUnk[i]->AddRef(); + pT->m_ppUnk[i] = ppUnk[i]; + } + + pT->m_nObjects = nObjects; + + return S_OK; + } + STDMETHOD(Show)(UINT nCmdShow) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::Show\n")); + + if (pT->m_hWnd == NULL) + return E_UNEXPECTED; + + ShowWindow(pT->m_hWnd, nCmdShow); + return S_OK; + } + STDMETHOD(Move)(LPCRECT pRect) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::Move\n")); + + if (pT->m_hWnd == NULL) + return E_UNEXPECTED; + + if (pRect == NULL) + return E_POINTER; + + MoveWindow(pT->m_hWnd, pRect->left, pRect->top, pRect->right - pRect->left, + pRect->bottom - pRect->top, TRUE); + + return S_OK; + + } + STDMETHOD(IsPageDirty)(void) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::IsPageDirty\n")); + return pT->m_bDirty ? S_OK : S_FALSE; + } + STDMETHOD(Apply)(void) + { + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::Apply\n")); + return S_OK; + } + STDMETHOD(Help)(LPCOLESTR pszHelpDir) + { + T* pT = static_cast(this); + USES_CONVERSION_EX; + + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::Help\n")); + CComBSTR szFullFileName(pszHelpDir); + if (szFullFileName == NULL) + return E_OUTOFMEMORY; + CComHeapPtr< OLECHAR > pszFileName(LoadStringHelper(pT->m_dwHelpFileID)); + if (pszFileName == NULL) + return E_OUTOFMEMORY; + HRESULT hr=szFullFileName.Append(OLESTR("\\")); + if(FAILED(hr)) + { + return hr; + } + hr=szFullFileName.Append(pszFileName); + if(FAILED(hr)) + { + return hr; + } + WinHelp(pT->m_hWnd, OLE2CT_EX_DEF(szFullFileName), HELP_CONTEXTPOPUP, NULL); + return S_OK; + } + STDMETHOD(TranslateAccelerator)(MSG *pMsg) + { + ATLTRACE(atlTraceControls,2,_T("IPropertyPageImpl::TranslateAccelerator\n")); + T* pT = static_cast(this); + if ((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) && + (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST)) + return S_FALSE; + + return (IsDialogMessage(pT->m_hWnd, pMsg)) ? S_OK : S_FALSE; + } + + IPropertyPageSite* m_pPageSite; + IUnknown** m_ppUnk; + ULONG m_nObjects; + SIZE m_size; + UINT m_dwTitleID; + UINT m_dwHelpFileID; + UINT m_dwDocStringID; + DWORD m_dwHelpContext; + BOOL m_bDirty; + +//methods +public: + + BEGIN_MSG_MAP(IPropertyPageImpl) + MESSAGE_HANDLER(WM_STYLECHANGING, OnStyleChange) + END_MSG_MAP() + + LRESULT OnStyleChange(UINT, WPARAM wParam, LPARAM lParam, BOOL&) + { + if (wParam == GWL_EXSTYLE) + { + LPSTYLESTRUCT lpss = (LPSTYLESTRUCT) lParam; + lpss->styleNew |= WS_EX_CONTROLPARENT; + return 0; + } + return 1; + } + + LPOLESTR LoadStringHelper(UINT idRes) + { + const ATLSTRINGRESOURCEIMAGE* pString = AtlGetStringResourceImage( + _AtlBaseModule.GetResourceInstance(), idRes); + if (pString == NULL) + { + ATLTRACE(atlTraceControls,2,_T("Error : Failed to load string from res\n")); + return NULL; + } + + CComHeapPtr< OLECHAR > psz; + + psz.Allocate( pString->nLength+1 ); + if (psz != NULL) + { + Checked::memcpy_s(psz, (pString->nLength+1)*sizeof(OLECHAR), pString->achString, pString->nLength*sizeof(OLECHAR)); + psz[pString->nLength] = L'\0'; + } + + return psz.Detach(); + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// IPropertyPage2Impl +template +class ATL_NO_VTABLE IPropertyPage2Impl : public IPropertyPageImpl +{ +public: + + STDMETHOD(EditProperty)(DISPID dispID) + { + ATLTRACENOTIMPL(_T("IPropertyPage2Impl::EditProperty\n")); + } +}; + + + +////////////////////////////////////////////////////////////////////////////// +// IPerPropertyBrowsingImpl +template +class ATL_NO_VTABLE IPerPropertyBrowsingImpl : public IPerPropertyBrowsing +{ +public: + // declare empty map in case derived classes doesn't want to specify one + DECLARE_EMPTY_PROP_VAL_MAP() + + STDMETHOD(GetDisplayString)(DISPID dispID, BSTR *pBstr) + { + ATLTRACE(atlTraceControls,2,_T("IPerPropertyBrowsingImpl::GetDisplayString\n")); + if (pBstr == NULL) + return E_POINTER; + + T* pT = static_cast(this); + *pBstr = NULL; + CComVariant var; + + //---- get current value of property ---- + IDispatch *pdisp = NULL; + pT->QueryInterface(__uuidof(IDispatch), (void **)&pdisp); + if (! pdisp) + return S_FALSE; + HRESULT hr = CComDispatchDriver::GetProperty(pdisp, dispID, &var); + pdisp->Release(); + if (FAILED(hr)) + return S_FALSE; + + //---- try finding a match in the PROP_VAL_MAP ---- + ATL_PROPVALMAP_ENTRY *valmap; + int i, cnt; + BSTR bstrSrc; + + valmap = pT->GetPropValMap(&cnt); + if ((valmap) && (cnt)) + { + for (i=0; i < cnt; i++) + { + if ((valmap[i].dispid == dispID) && (var == valmap[i].val)) + { + bstrSrc = (BSTR)valmap[i].szDesc; + *pBstr = SysAllocString(bstrSrc); + if (*pBstr == NULL && bstrSrc != NULL) + return E_OUTOFMEMORY; + return S_OK; + } + } + } + + //---- not in our PROP_VAL_MAP - let it get standard host treatment ---- + return S_FALSE; + } + + STDMETHOD(MapPropertyToPage)(DISPID dispID, CLSID *pClsid) + { + ATLTRACE(atlTraceControls,2,_T("IPerPropertyBrowsingImpl::MapPropertyToPage\n")); + if (pClsid == NULL) + return E_POINTER; + + ATL_PROPMAP_ENTRY* pMap = T::GetPropertyMap(); + ATLASSERT(pMap != NULL); + if(!pMap) + { + return E_FAIL; + } + for (int i = 0; pMap[i].pclsidPropPage != NULL; i++) + { + if (pMap[i].szDesc == NULL) + continue; + + // reject data entry types + if (pMap[i].dwSizeData != 0) + continue; + + if (pMap[i].dispid == dispID) + { + ATLASSERT(pMap[i].pclsidPropPage != NULL); + *pClsid = *(pMap[i].pclsidPropPage); + // Does this property have a page? CLSID_NULL means it does not + if (InlineIsEqualGUID(*pMap[i].pclsidPropPage, CLSID_NULL)) + return PERPROP_E_NOPAGEAVAILABLE; + return S_OK; + } + } + *pClsid = CLSID_NULL; + return E_INVALIDARG; + } + + STDMETHOD(GetPredefinedStrings)(DISPID dispID, CALPOLESTR *pCaStringsOut,CADWORD *pCaCookiesOut) + { + ATL_PROPVALMAP_ENTRY *valmap; + int i, cnt, matches, addcnt = 0; + + ATLTRACE(atlTraceControls,2,_T("IPerPropertyBrowsingImpl::GetPredefinedStrings\n")); + if (pCaStringsOut == NULL || pCaCookiesOut == NULL) + return E_POINTER; + + valmap = T::GetPropValMap(&cnt); + if ((! valmap) || (! cnt)) + ATLTRACENOTIMPL(_T("IPerPropertyBrowsingImpl::GetPredefinedStrings")); + + //---- first pass thru - count matches ---- + matches = 0; + for (i=0; i < cnt; i++) + { + if (dispID == valmap[i].dispid) + matches++; + } + + DWORD *pCookies = NULL; + LPOLESTR *pStrings = NULL; + + //---- set up the collections to be returned ---- + pCookies = (DWORD *)::ATL::AtlCoTaskMemCAlloc(matches,static_cast(sizeof(DWORD))); + if (! pCookies) + goto outofmem; + + pStrings = (LPOLESTR *)::ATL::AtlCoTaskMemCAlloc(matches,static_cast(sizeof(LPOLESTR))); + if (! pStrings) + goto outofmem; + + //---- second pass thru - collect the items ---- + for (i=0; i < cnt; i++) + { + if (dispID == valmap[i].dispid) + { + LPCOLESTR src; + LPOLESTR dst; + + // store cookie + pCookies[addcnt] = i; + // allocate and store string + src = valmap[i].szDesc; + size_t len = lstrlenW(src)+1; + if(len>ULONG_MAX) + { + goto outofmem; + } + dst = (LPOLESTR)::ATL::AtlCoTaskMemCAlloc(static_cast(len),static_cast(sizeof(WCHAR))); + if (! dst) + goto outofmem; + + if(!ocscpy_s(dst, len, src)) + { + goto outofmem; + } + pStrings[addcnt] = dst; + addcnt++; + } + } + + pCaCookiesOut->cElems = matches; + pCaCookiesOut->pElems = pCookies; + pCaStringsOut->cElems = matches; + pCaStringsOut->pElems = pStrings; + + return S_OK; + +outofmem: + CoTaskMemFree(pCookies); + if (pStrings) + { + for (i=0; i < addcnt; i++) + CoTaskMemFree(pStrings[i]); + CoTaskMemFree(pStrings); + } + + return E_OUTOFMEMORY; + } + + STDMETHOD(GetPredefinedValue)(DISPID /* dispID */, DWORD dwCookie, VARIANT* pVarOut) + { + ATL_PROPVALMAP_ENTRY *valmap; + int cnt, index; + + ATLTRACE(atlTraceControls,2,_T("IPerPropertyBrowsingImpl::GetPredefinedValue\n")); + if (pVarOut == NULL) + return E_POINTER; + + valmap = T::GetPropValMap(&cnt); + if ((! valmap) || (! cnt)) + ATLTRACENOTIMPL(_T("IPerPropertyBrowsingImpl::GetPredefinedValue")); + + index = (int) dwCookie; + if ((index < 0) || (index >= cnt)) + return E_INVALIDARG; + + return VariantCopy(pVarOut, &valmap[index].val); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// IViewObjectExImpl +template +class ATL_NO_VTABLE IViewObjectExImpl : public IViewObjectEx +{ +public: + STDMETHOD(Draw)(DWORD dwDrawAspect, LONG lindex, void *pvAspect, + DVTARGETDEVICE *ptd, HDC hicTargetDev, HDC hdcDraw, + LPCRECTL prcBounds, LPCRECTL prcWBounds, + BOOL (__stdcall * /*pfnContinue*/)(DWORD_PTR dwContinue), + DWORD_PTR /*dwContinue*/) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::Draw\n")); + return pT->IViewObject_Draw(dwDrawAspect, lindex, pvAspect, ptd, hicTargetDev, hdcDraw, + prcBounds, prcWBounds); + } + + STDMETHOD(GetColorSet)(DWORD /* dwDrawAspect */,LONG /* lindex */, void* /* pvAspect */, DVTARGETDEVICE* /* ptd */, HDC /* hicTargetDev */, LOGPALETTE** /* ppColorSet */) + { + ATLTRACENOTIMPL(_T("IViewObjectExImpl::GetColorSet")); + } + STDMETHOD(Freeze)(DWORD /* dwDrawAspect */, LONG /* lindex */, void* /* pvAspect */,DWORD* /* pdwFreeze */) + { + ATLTRACENOTIMPL(_T("IViewObjectExImpl::Freeze")); + } + STDMETHOD(Unfreeze)(DWORD /* dwFreeze */) + { + ATLTRACENOTIMPL(_T("IViewObjectExImpl::Unfreeze")); + } + STDMETHOD(SetAdvise)(DWORD /* aspects */, DWORD /* advf */, IAdviseSink* pAdvSink) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::SetAdvise\n")); + pT->m_spAdviseSink = pAdvSink; + return S_OK; + } + STDMETHOD(GetAdvise)(DWORD* /* pAspects */, DWORD* /* pAdvf */, IAdviseSink** ppAdvSink) + { + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::GetAdvise\n")); + ATLASSERT(ppAdvSink != NULL); + + HRESULT hr = E_POINTER; + if (ppAdvSink != NULL) + { + T* pT = static_cast(this); + *ppAdvSink = pT->m_spAdviseSink; + if (pT->m_spAdviseSink) + pT->m_spAdviseSink.p->AddRef(); + hr = S_OK; + } + return hr; + } + + // IViewObject2 + // + STDMETHOD(GetExtent)(DWORD /* dwDrawAspect */, LONG /* lindex */, DVTARGETDEVICE* /* ptd */, LPSIZEL lpsizel) + { + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::GetExtent\n")); + ATLASSERT(lpsizel != NULL); + if (lpsizel == NULL) + return E_POINTER; + + T* pT = static_cast(this); + *lpsizel = pT->m_sizeExtent; + return S_OK; + } + + // IViewObjectEx + // + STDMETHOD(GetRect)(DWORD /* dwAspect */, LPRECTL /* pRect */) + { + ATLTRACENOTIMPL(_T("IViewObjectExImpl::GetRect")); + } + + STDMETHOD(GetViewStatus)(DWORD* pdwStatus) + { + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::GetViewStatus\n")); + ATLASSERT(pdwStatus != NULL); + if (pdwStatus == NULL) + return E_POINTER; + + T* pT = static_cast(this); + *pdwStatus = pT->_GetViewStatus(); + return S_OK; + } + STDMETHOD(QueryHitPoint)(DWORD dwAspect, LPCRECT pRectBounds, POINT ptlLoc, LONG /* lCloseHint */, DWORD *pHitResult) + { + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::QueryHitPoint\n")); + ATLASSERT(pHitResult != NULL); + if (pHitResult == NULL) + return E_POINTER; + + if (dwAspect == DVASPECT_CONTENT) + { + *pHitResult = PtInRect(pRectBounds, ptlLoc) ? HITRESULT_HIT : HITRESULT_OUTSIDE; + return S_OK; + } + *pHitResult = NULL; + ATLTRACE(atlTraceControls,2,_T("Wrong DVASPECT\n")); + return E_FAIL; + } + STDMETHOD(QueryHitRect)(DWORD dwAspect, LPCRECT pRectBounds, LPCRECT prcLoc, LONG /* lCloseHint */, DWORD* pHitResult) + { + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::QueryHitRect\n")); + ATLASSERT(pHitResult != NULL); + if (pHitResult == NULL) + return E_POINTER; + + if (dwAspect == DVASPECT_CONTENT) + { + RECT rc; + *pHitResult = UnionRect(&rc, pRectBounds, prcLoc) ? HITRESULT_HIT : HITRESULT_OUTSIDE; + return S_OK; + } + *pHitResult = NULL; + ATLTRACE(atlTraceControls,2,_T("Wrong DVASPECT\n")); + return E_FAIL; + } + STDMETHOD(GetNaturalExtent)(DWORD dwAspect, LONG /* lindex */, DVTARGETDEVICE* /* ptd */, HDC /* hicTargetDev */, DVEXTENTINFO* pExtentInfo , LPSIZEL psizel) + { + ATLTRACE(atlTraceControls,2,_T("IViewObjectExImpl::GetNaturalExtent\n")); + ATLASSERT(pExtentInfo != NULL); + ATLASSERT(psizel != NULL); + if ((pExtentInfo == NULL) || (psizel == NULL)) + return E_POINTER; + + HRESULT hRes = E_FAIL; + T* pT = static_cast(this); + if (dwAspect == DVASPECT_CONTENT) + { + if (pExtentInfo->dwExtentMode == DVEXTENT_CONTENT) + { + *psizel = pT->m_sizeNatural; + hRes = S_OK; + } + } + return hRes; + } + +public: +}; + +////////////////////////////////////////////////////////////////////////////// +// IOleInPlaceObjectWindowlessImpl +// +template +class ATL_NO_VTABLE IOleInPlaceObjectWindowlessImpl : public IOleInPlaceObjectWindowless +{ +public: + // IOleWindow + // + + // Change IOleInPlaceActiveObject::GetWindow as well + STDMETHOD(GetWindow)(HWND* phwnd) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceObjectWindowlessImpl::GetWindow\n")); + T* pT = static_cast(this); + HRESULT hRes = E_POINTER; + + if (pT->m_bWasOnceWindowless) + return E_FAIL; + + if (phwnd != NULL) + { + *phwnd = pT->m_hWnd; + hRes = (*phwnd == NULL) ? E_UNEXPECTED : S_OK; + } + return hRes; + } + STDMETHOD(ContextSensitiveHelp)(BOOL /* fEnterMode */) + { + ATLTRACENOTIMPL(_T("IOleInPlaceObjectWindowlessImpl::ContextSensitiveHelp")); + } + + // IOleInPlaceObject + // + STDMETHOD(InPlaceDeactivate)(void) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceObjectWindowlessImpl::InPlaceDeactivate\n")); + return pT->IOleInPlaceObject_InPlaceDeactivate(); + } + STDMETHOD(UIDeactivate)(void) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceObjectWindowlessImpl::UIDeactivate\n")); + return pT->IOleInPlaceObject_UIDeactivate(); + } + STDMETHOD(SetObjectRects)(LPCRECT prcPos,LPCRECT prcClip) + { + T* pT = static_cast(this); + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceObjectWindowlessImpl::SetObjectRects\n")); + return pT->IOleInPlaceObject_SetObjectRects(prcPos, prcClip); + } + STDMETHOD(ReactivateAndUndo)(void) + { + ATLTRACENOTIMPL(_T("IOleInPlaceObjectWindowlessImpl::ReactivateAndUndo")); + } + + // IOleInPlaceObjectWindowless + // + STDMETHOD(OnWindowMessage)(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceObjectWindowlessImpl::OnWindowMessage\n")); + T* pT = static_cast(this); + _ATL_MSG message(NULL, msg, wParam, lParam); + const _ATL_MSG* pOldMsg = pT->m_pCurrentMsg; + pT->m_pCurrentMsg = &message; + BOOL b = pT->ProcessWindowMessage(pT->m_hWnd, msg, wParam, lParam, *plResult); + // restore saved value for the current message + ATLASSERT(pT->m_pCurrentMsg == &message); + pT->m_pCurrentMsg = pOldMsg; + return b ? S_OK : S_FALSE; + } + + STDMETHOD(GetDropTarget)(IDropTarget** /* ppDropTarget */) + { + ATLTRACENOTIMPL(_T("IOleInPlaceObjectWindowlessImpl::GetDropTarget")); + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// IOleInPlaceActiveObjectImpl +// +template +class ATL_NO_VTABLE IOleInPlaceActiveObjectImpl : public IOleInPlaceActiveObject +{ +public: + // IOleWindow + // + + // Change IOleInPlaceObjectWindowless::GetWindow as well + STDMETHOD(GetWindow)(HWND *phwnd) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceActiveObjectImpl::GetWindow\n")); + T* pT = static_cast(this); + HRESULT hRes = E_POINTER; + + if (pT->m_bWasOnceWindowless) + return E_FAIL; + + if (phwnd != NULL) + { + *phwnd = pT->m_hWnd; + hRes = (*phwnd == NULL) ? E_UNEXPECTED : S_OK; + } + return hRes; + } + STDMETHOD(ContextSensitiveHelp)(BOOL /* fEnterMode */) + { + ATLTRACENOTIMPL(_T("IOleInPlaceActiveObjectImpl::ContextSensitiveHelp")); + } + + // IOleInPlaceActiveObject + // + STDMETHOD(TranslateAccelerator)(LPMSG pMsg) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceActiveObjectImpl::TranslateAccelerator\n")); + T* pT = static_cast(this); + HRESULT hRet = S_OK; + MSG msg = *pMsg; + if (pT->PreTranslateAccelerator(&msg, hRet)) + return hRet; + + CComPtr spCtlSite; + hRet = pT->InternalGetSite(__uuidof(IOleControlSite), (void**)&spCtlSite); + if (SUCCEEDED(hRet)) + { + if (spCtlSite != NULL) + { + DWORD dwKeyMod = 0; + if (::GetKeyState(VK_SHIFT) < 0) + dwKeyMod += 1; // KEYMOD_SHIFT + if (::GetKeyState(VK_CONTROL) < 0) + dwKeyMod += 2; // KEYMOD_CONTROL + if (::GetKeyState(VK_MENU) < 0) + dwKeyMod += 4; // KEYMOD_ALT + hRet = spCtlSite->TranslateAccelerator(&msg, dwKeyMod); + } + else + hRet = S_FALSE; + } + return (hRet == S_OK) ? S_OK : S_FALSE; + } + STDMETHOD(OnFrameWindowActivate)(BOOL /* fActivate */) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceActiveObjectImpl::OnFrameWindowActivate\n")); + return S_OK; + } + STDMETHOD(OnDocWindowActivate)(BOOL fActivate) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceActiveObjectImpl::OnDocWindowActivate\n")); + T* pT = static_cast(this); + if (fActivate == FALSE) + pT->IOleInPlaceObject_UIDeactivate(); + return S_OK; + } + STDMETHOD(ResizeBorder)(LPCRECT /* prcBorder */, IOleInPlaceUIWindow* /* pUIWindow */, BOOL /* fFrameWindow */) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceActiveObjectImpl::ResizeBorder\n")); + return S_OK; + } + STDMETHOD(EnableModeless)(BOOL /* fEnable */) + { + ATLTRACE(atlTraceControls,2,_T("IOleInPlaceActiveObjectImpl::EnableModeless\n")); + return S_OK; + } +}; + +////////////////////////////////////////////////////////////////////////////// +// IPointerInactiveImpl +template +class ATL_NO_VTABLE IPointerInactiveImpl : public IPointerInactive +{ +public: + // IPointerInactive + // + STDMETHOD(GetActivationPolicy)(DWORD *pdwPolicy) + { + ATLTRACENOTIMPL(_T("IPointerInactiveImpl::GetActivationPolicy")); + } + STDMETHOD(OnInactiveMouseMove)(LPCRECT pRectBounds, long x, long y, DWORD dwMouseMsg) + { + ATLTRACENOTIMPL(_T("IPointerInactiveImpl::OnInactiveMouseMove")); + } + STDMETHOD(OnInactiveSetCursor)(LPCRECT pRectBounds, long x, long y, DWORD dwMouseMsg, BOOL fSetAlways) + { + ATLTRACENOTIMPL(_T("IPointerInactiveImpl::OnInactiveSetCursor")); + } +}; + +////////////////////////////////////////////////////////////////////////////// +// IRunnableObjectImpl +template +class ATL_NO_VTABLE IRunnableObjectImpl : public IRunnableObject +{ +public: + // IRunnableObject + // + STDMETHOD(GetRunningClass)(LPCLSID lpClsid) + { + ATLTRACE(atlTraceControls,2,_T("IRunnableObjectImpl::GetRunningClass\n")); + *lpClsid = GUID_NULL; + return E_UNEXPECTED; + } + STDMETHOD(Run)(LPBINDCTX) + { + ATLTRACE(atlTraceControls,2,_T("IRunnableObjectImpl::Run\n")); + return S_OK; + } + virtual BOOL STDMETHODCALLTYPE IsRunning() + { + ATLTRACE(atlTraceControls,2,_T("IRunnableObjectImpl::IsRunning\n")); + return TRUE; + } + STDMETHOD(LockRunning)(BOOL /*fLock*/, BOOL /*fLastUnlockCloses*/) + { + ATLTRACE(atlTraceControls,2,_T("IRunnableObjectImpl::LockRunning\n")); + return S_OK; + } + STDMETHOD(SetContainedObject)(BOOL /*fContained*/) + { + ATLTRACE(atlTraceControls,2,_T("IRunnableObjectImpl::SetContainedObject\n")); + return S_OK; + } +}; + + +////////////////////////////////////////////////////////////////////////////// +// IDataObjectImpl +template +class ATL_NO_VTABLE IDataObjectImpl : public IDataObject +{ +public: + STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) + { + ATLTRACE(atlTraceControls,2,_T("IDataObjectImpl::GetData\n")); + T* pT = (T*) this; + return pT->IDataObject_GetData(pformatetcIn, pmedium); + } + STDMETHOD(GetDataHere)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */) + { + ATLTRACENOTIMPL(_T("IDataObjectImpl::GetDataHere")); + } + STDMETHOD(QueryGetData)(FORMATETC* /* pformatetc */) + { + ATLTRACENOTIMPL(_T("IDataObjectImpl::QueryGetData")); + } + STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* /* pformatectIn */,FORMATETC* /* pformatetcOut */) + { + ATLTRACENOTIMPL(_T("IDataObjectImpl::GetCanonicalFormatEtc")); + } + STDMETHOD(SetData)(FORMATETC* /* pformatetc */, STGMEDIUM* /* pmedium */, BOOL /* fRelease */) + { + ATLTRACENOTIMPL(_T("IDataObjectImpl::SetData")); + } + STDMETHOD(EnumFormatEtc)(DWORD /* dwDirection */, IEnumFORMATETC** /* ppenumFormatEtc */) + { + ATLTRACENOTIMPL(_T("IDataObjectImpl::EnumFormatEtc")); + } + STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, + DWORD *pdwConnection) + { + ATLTRACE(atlTraceControls,2,_T("IDataObjectImpl::DAdvise\n")); + T* pT = static_cast(this); + HRESULT hr = S_OK; + if (pT->m_spDataAdviseHolder == NULL) + hr = CreateDataAdviseHolder(&pT->m_spDataAdviseHolder); + + if (hr == S_OK) + hr = pT->m_spDataAdviseHolder->Advise((IDataObject*)this, pformatetc, advf, pAdvSink, pdwConnection); + + return hr; + } + STDMETHOD(DUnadvise)(DWORD dwConnection) + { + ATLTRACE(atlTraceControls,2,_T("IDataObjectImpl::DUnadvise\n")); + T* pT = static_cast(this); + HRESULT hr = S_OK; + if (pT->m_spDataAdviseHolder == NULL) + hr = OLE_E_NOCONNECTION; + else + hr = pT->m_spDataAdviseHolder->Unadvise(dwConnection); + return hr; + } + STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) + { + ATLTRACE(atlTraceControls,2,_T("IDataObjectImpl::EnumDAdvise\n")); + ATLASSERT(ppenumAdvise != NULL); + if (ppenumAdvise == NULL) + return E_POINTER; + *ppenumAdvise = NULL; + + T* pT = static_cast(this); + if (pT->m_spDataAdviseHolder != NULL) + return pT->m_spDataAdviseHolder->EnumAdvise(ppenumAdvise); + return E_FAIL; + } +}; + +////////////////////////////////////////////////////////////////////////////// +// IPropertyNotifySinkCP +template +class ATL_NO_VTABLE IPropertyNotifySinkCP : + public IConnectionPointImpl +{ +public: + typedef CFirePropNotifyEvent __ATL_PROP_NOTIFY_EVENT_CLASS; +}; + + +////////////////////////////////////////////////////////////////////////////// +// IObjectSafety +// +// 2nd template parameter is the supported safety e.g. +// INTERFACESAFE_FOR_UNTRUSTED_CALLER - safe for scripting +// INTERFACESAFE_FOR_UNTRUSTED_DATA - safe for initialization from data + +template +class ATL_NO_VTABLE IObjectSafetyImpl : public IObjectSafety +{ +public: + IObjectSafetyImpl() + { + m_dwCurrentSafety = 0; + } + + STDMETHOD(GetInterfaceSafetyOptions)(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) + { + ATLTRACE(atlTraceControls,2,_T("IObjectSafetyImpl2::GetInterfaceSafetyOptions\n")); + T* pT = static_cast(this); + if (pdwSupportedOptions == NULL || pdwEnabledOptions == NULL) + return E_POINTER; + + HRESULT hr; + IUnknown* pUnk; + // Check if we support this interface + hr = pT->GetUnknown()->QueryInterface(riid, (void**)&pUnk); + if (SUCCEEDED(hr)) + { + // We support this interface so set the safety options accordingly + pUnk->Release(); // Release the interface we just acquired + *pdwSupportedOptions = dwSupportedSafety; + *pdwEnabledOptions = m_dwCurrentSafety; + } + else + { + // We don't support this interface + *pdwSupportedOptions = 0; + *pdwEnabledOptions = 0; + } + return hr; + } + STDMETHOD(SetInterfaceSafetyOptions)(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) + { + ATLTRACE(atlTraceControls,2,_T("IObjectSafetyImpl2::SetInterfaceSafetyOptions\n")); + T* pT = static_cast(this); + IUnknown* pUnk; + + // Check if we support the interface and return E_NOINTEFACE if we don't + if (FAILED(pT->GetUnknown()->QueryInterface(riid, (void**)&pUnk))) + return E_NOINTERFACE; + pUnk->Release(); // Release the interface we just acquired + + // If we are asked to set options we don't support then fail + if (dwOptionSetMask & ~dwSupportedSafety) + return E_FAIL; + + // Set the safety options we have been asked to + m_dwCurrentSafety = (m_dwCurrentSafety & ~dwOptionSetMask) | (dwOptionSetMask & dwEnabledOptions); + return S_OK; + } + DWORD m_dwCurrentSafety; +}; + +template +class ATL_NO_VTABLE IOleLinkImpl : public IOleLink +{ + STDMETHOD(SetUpdateOptions)(DWORD /* dwUpdateOpt */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::SetUpdateOptions")); + } + + STDMETHOD(GetUpdateOptions)(DWORD* /* pdwUpdateOpt */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::GetUpdateOptions")); + } + + STDMETHOD(SetSourceMoniker)(IMoniker* /* pmk */, REFCLSID /* rclsid */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::SetSourceMoniker")); + } + + STDMETHOD(GetSourceMoniker)(IMoniker** /* ppmk */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::GetSourceMoniker")); + }; + + STDMETHOD(SetSourceDisplayName)(LPCOLESTR /* pszStatusText */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::SetSourceDisplayName")); + } + + STDMETHOD(GetSourceDisplayName)(LPOLESTR *ppszDisplayName) + { + ATLTRACE(atlTraceControls,2,_T("IOleLink::GetSourceDisplayName\n")); + *ppszDisplayName = NULL; + return E_FAIL; + } + + STDMETHOD(BindToSource)(DWORD /* bindflags */, IBindCtx* /* pbc */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::BindToSource\n")); + }; + + STDMETHOD(BindIfRunning)() + { + ATLTRACE(atlTraceControls,2,_T("IOleLinkImpl::BindIfRunning\n")); + return S_OK; + }; + + STDMETHOD(GetBoundSource)(IUnknown** /* ppunk */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::GetBoundSource")); + }; + + STDMETHOD(UnbindSource)() + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::UnbindSource")); + }; + + STDMETHOD(Update)(IBindCtx* /* pbc */) + { + ATLTRACENOTIMPL(_T("IOleLinkImpl::Update")); + }; +}; + +template +class ATL_NO_VTABLE CBindStatusCallback : + public CComObjectRootEx, + public IBindStatusCallback +{ +public: + typedef void (T::*ATL_PDATAAVAILABLE)(CBindStatusCallback* pbsc, BYTE* pBytes, DWORD dwSize); + typedef CBindStatusCallback thisClass; + +BEGIN_COM_MAP(thisClass) + COM_INTERFACE_ENTRY(IBindStatusCallback) +END_COM_MAP() + + CBindStatusCallback() + { + m_pT = NULL; + m_pFunc = NULL; + } + ~CBindStatusCallback() + { + ATLTRACE(atlTraceControls,2,_T("~CBindStatusCallback\n")); + } + + STDMETHOD(OnStartBinding)(DWORD /*dwReserved*/, IBinding *pBinding) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::OnStartBinding\n")); + m_spBinding = pBinding; + return S_OK; + } + + STDMETHOD(GetPriority)(LONG *pnPriority) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::GetPriority")); + HRESULT hr = S_OK; + if (pnPriority) + *pnPriority = THREAD_PRIORITY_NORMAL; + else + hr = E_INVALIDARG; + return S_OK; + } + + STDMETHOD(OnLowResource)(DWORD /*reserved*/) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::OnLowResource")); + return S_OK; + } + + STDMETHOD(OnProgress)(ULONG /*ulProgress*/, ULONG /*ulProgressMax*/, ULONG /*ulStatusCode*/, LPCWSTR /*szStatusText*/) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::OnProgress")); + return S_OK; + } + + STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR /*szError*/) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::OnStopBinding\n")); + // Pass NULL as the array of bytes to signify the end. + // Pass the HRESULT for the dwSize parameter + (m_pT->*m_pFunc)(this, NULL, hresult); + m_spBinding.Release(); + m_spBindCtx.Release(); + m_spMoniker.Release(); + return S_OK; + } + + STDMETHOD(GetBindInfo)(DWORD *pgrfBINDF, BINDINFO *pbindInfo) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::GetBindInfo\n")); + + if (pbindInfo==NULL || pbindInfo->cbSize==0 || pgrfBINDF==NULL) + return E_INVALIDARG; + + *pgrfBINDF = nBindFlags; + + ULONG cbSize = pbindInfo->cbSize; // remember incoming cbSize + memset(pbindInfo, 0, cbSize); // zero out structure + pbindInfo->cbSize = cbSize; // restore cbSize + pbindInfo->dwBindVerb = BINDVERB_GET; // set verb + return S_OK; + } + + STDMETHOD(OnDataAvailable)(DWORD grfBSCF, DWORD dwSize, FORMATETC * /*pformatetc*/, STGMEDIUM *pstgmed) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::OnDataAvailable\n")); + HRESULT hr = S_OK; + + // Get the Stream passed + if (BSCF_FIRSTDATANOTIFICATION & grfBSCF) + { + if (!m_spStream && pstgmed->tymed == TYMED_ISTREAM) + m_spStream = pstgmed->pstm; + } + + DWORD dwRead = dwSize - m_dwTotalRead; // Minimum amount available that hasn't been read + DWORD dwActuallyRead = 0; // Placeholder for amount read during this pull + + // If there is some data to be read then go ahead and read them + if (m_spStream) + { + if (dwRead > 0) + { + BYTE* pBytes = NULL; + ATLTRY(pBytes = new BYTE[dwRead + 1]); + if (pBytes == NULL) + return E_OUTOFMEMORY; + hr = m_spStream->Read(pBytes, dwRead, &dwActuallyRead); + if (SUCCEEDED(hr)) + { + pBytes[dwActuallyRead] = 0; + if (dwActuallyRead>0) + { + (m_pT->*m_pFunc)(this, pBytes, dwActuallyRead); + m_dwTotalRead += dwActuallyRead; + } + } + delete[] pBytes; + } + } + + if (BSCF_LASTDATANOTIFICATION & grfBSCF) + m_spStream.Release(); + return hr; + } + + STDMETHOD(OnObjectAvailable)(REFIID /*riid*/, IUnknown * /*punk*/) + { + ATLTRACE(atlTraceControls,2,_T("CBindStatusCallback::OnObjectAvailable")); + return S_OK; + } + + HRESULT _StartAsyncDownload(BSTR bstrURL, IUnknown* pUnkContainer, BOOL bRelative) + { + m_dwTotalRead = 0; + m_dwAvailableToRead = 0; + HRESULT hr = S_OK; + CComQIPtr spServiceProvider(pUnkContainer); + CComPtr spBindHost; + CComPtr spStream; + if (spServiceProvider) + spServiceProvider->QueryService(SID_IBindHost, __uuidof(IBindHost), (void**)&spBindHost); + + if (spBindHost == NULL) + { + if (bRelative) + return E_NOINTERFACE; // relative asked for, but no IBindHost + hr = CreateURLMoniker(NULL, bstrURL, &m_spMoniker); + if (SUCCEEDED(hr)) + hr = CreateBindCtx(0, &m_spBindCtx); + + if (SUCCEEDED(hr)) + hr = RegisterBindStatusCallback(m_spBindCtx, static_cast(this), 0, 0L); + else + m_spMoniker.Release(); + + if (SUCCEEDED(hr)) + hr = m_spMoniker->BindToStorage(m_spBindCtx, 0, __uuidof(IStream), (void**)&spStream); + } + else + { + hr = CreateBindCtx(0, &m_spBindCtx); + if (SUCCEEDED(hr)) + hr = RegisterBindStatusCallback(m_spBindCtx, static_cast(this), 0, 0L); + + if (SUCCEEDED(hr)) + { + if (bRelative) + hr = spBindHost->CreateMoniker(bstrURL, m_spBindCtx, &m_spMoniker, 0); + else + hr = CreateURLMoniker(NULL, bstrURL, &m_spMoniker); + } + + if (SUCCEEDED(hr)) + { + hr = spBindHost->MonikerBindToStorage(m_spMoniker, m_spBindCtx, static_cast(this), __uuidof(IStream), (void**)&spStream); + ATLTRACE(atlTraceControls,2,_T("Bound")); + } + } + return hr; + } + + HRESULT StartAsyncDownload(T* pT, ATL_PDATAAVAILABLE pFunc, BSTR bstrURL, IUnknown* pUnkContainer = NULL, BOOL bRelative = FALSE) + { + m_pT = pT; + m_pFunc = pFunc; + return _StartAsyncDownload(bstrURL, pUnkContainer, bRelative); + } + + static HRESULT Download(T* pT, ATL_PDATAAVAILABLE pFunc, BSTR bstrURL, IUnknown* pUnkContainer = NULL, BOOL bRelative = FALSE) + { + CComObject > *pbsc; + HRESULT hRes = CComObject >::CreateInstance(&pbsc); + if (FAILED(hRes)) + return hRes; + return pbsc->StartAsyncDownload(pT, pFunc, bstrURL, pUnkContainer, bRelative); + } + + CComPtr m_spMoniker; + CComPtr m_spBindCtx; + CComPtr m_spBinding; + CComPtr m_spStream; + T* m_pT; + ATL_PDATAAVAILABLE m_pFunc; + DWORD m_dwTotalRead; + DWORD m_dwAvailableToRead; +}; + +#define IMPLEMENT_STOCKPROP(type, fname, pname, dispid) \ + HRESULT STDMETHODCALLTYPE put_##fname(type pname) \ + { \ + __if_exists(T::m_##pname) \ + { \ + ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::put_%s\n"), #fname); \ + T* pT = (T*) this; \ + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(dispid) == S_FALSE) \ + return S_FALSE; \ + pT->m_##pname = pname; \ + pT->m_bRequiresSave = TRUE; \ + if (pT->m_nFreezeEvents == 0) \ + pT->FireOnChanged(dispid); \ + __if_exists(T::On##fname##Changed) \ + { \ + pT->On##fname##Changed(); \ + } \ + pT->FireViewChange(); \ + pT->SendOnDataChange(NULL); \ + } \ + return S_OK; \ + } \ + HRESULT STDMETHODCALLTYPE get_##fname(type* p##pname) \ + { \ + __if_exists(T::m_##pname) \ + { \ + ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::get_%s\n"), #fname); \ + ATLASSERT(p##pname != NULL); \ + if (p##pname == NULL) \ + return E_POINTER; \ + T* pT = (T*) this; \ + *p##pname = pT->m_##pname; \ + } \ + return S_OK; \ + } + +#define IMPLEMENT_BOOL_STOCKPROP(fname, pname, dispid) \ + HRESULT STDMETHODCALLTYPE put_##fname(VARIANT_BOOL pname) \ + { \ + __if_exists(T::m_##pname) \ + { \ + ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::put_%s\n"), #fname); \ + T* pT = (T*) this; \ + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(dispid) == S_FALSE) \ + return S_FALSE; \ + pT->m_##pname = pname; \ + pT->m_bRequiresSave = TRUE; \ + if (pT->m_nFreezeEvents == 0) \ + pT->FireOnChanged(dispid); \ + __if_exists(T::On##fname##Changed) \ + { \ + pT->On##fname##Changed(); \ + } \ + pT->FireViewChange(); \ + pT->SendOnDataChange(NULL); \ + } \ + return S_OK; \ + } \ + HRESULT STDMETHODCALLTYPE get_##fname(VARIANT_BOOL* p##pname) \ + { \ + __if_exists(T::m_##pname) \ + { \ + ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::get_%s\n"), #fname); \ + ATLASSERT(p##pname != NULL); \ + if (p##pname == NULL) \ + return E_POINTER; \ + T* pT = (T*) this; \ + *p##pname = pT->m_##pname ? ATL_VARIANT_TRUE : ATL_VARIANT_FALSE; \ + } \ + return S_OK; \ + } + +#define IMPLEMENT_BSTR_STOCKPROP(fname, pname, dispid) \ + HRESULT STDMETHODCALLTYPE put_##fname(BSTR pname) \ + { \ + __if_exists(T::m_##pname) \ + { \ + ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::put_%s\n"), #fname); \ + T* pT = (T*) this; \ + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(dispid) == S_FALSE) \ + return S_FALSE; \ + SysFreeStringHelper(pT->m_##pname); \ + HRESULT hr=SysAllocStringHelper(pT->m_##pname,pname); \ + if (FAILED(hr) && pname != NULL) \ + return E_OUTOFMEMORY; \ + pT->m_bRequiresSave = TRUE; \ + if (pT->m_nFreezeEvents == 0) \ + pT->FireOnChanged(dispid); \ + __if_exists(T::On##fname##Changed) \ + { \ + pT->On##fname##Changed(); \ + } \ + pT->FireViewChange(); \ + pT->SendOnDataChange(NULL); \ + } \ + return S_OK; \ + } \ + HRESULT STDMETHODCALLTYPE get_##fname(BSTR* p##pname) \ + { \ + __if_exists(T::m_##pname) \ + { \ + ATLTRACE(ATL::atlTraceControls,2,_T("CStockPropImpl::get_%s\n"), #fname); \ + ATLASSERT(p##pname != NULL); \ + if (p##pname == NULL) \ + return E_POINTER; \ + T* pT = (T*) this; \ + *p##pname = SysAllocString(pT->m_##pname); \ + if (*p##pname == NULL && pT->m_##pname != NULL) \ + return E_OUTOFMEMORY; \ + } \ + return S_OK; \ + } + + +template < class T, class InterfaceName, const IID* piid = &_ATL_IIDOF(InterfaceName), const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1, +WORD wMinor = 0, class tihclass = CComTypeInfoHolder> +class ATL_NO_VTABLE CStockPropImpl : public IDispatchImpl< InterfaceName, piid, plibid, wMajor, wMinor, tihclass > +{ +public: + // Font + HRESULT STDMETHODCALLTYPE put_Font(IFontDisp* pFontDisp) + { + __if_exists(T::m_pFont) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_Font\n")); + T* pT = (T*) this; + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_FONT) == S_FALSE) + return S_FALSE; + pT->m_pFont = 0; + if (pFontDisp) + { + CComQIPtr p(pFontDisp); + if (p) + { + CComPtr pFont; + p->Clone(&pFont); + if (pFont) + { + pFont->QueryInterface(__uuidof(IFontDisp), (void**) &pT->m_pFont); + } + } + } + pT->m_bRequiresSave = TRUE; + if (pT->m_nFreezeEvents == 0) + pT->FireOnChanged(DISPID_FONT); + __if_exists(T::OnFontChanged) + { + pT->OnFontChanged(); + } + pT->FireViewChange(); + pT->SendOnDataChange(NULL); + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE putref_Font(IFontDisp* pFont) + { + __if_exists(T::m_pFont) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::putref_Font\n")); + T* pT = (T*) this; + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_FONT) == S_FALSE) + return S_FALSE; + pT->m_pFont = pFont; + pT->m_bRequiresSave = TRUE; + if (pT->m_nFreezeEvents == 0) + pT->FireOnChanged(DISPID_FONT); + __if_exists(T::OnFontChanged) + { + pT->OnFontChanged(); + } + pT->FireViewChange(); + pT->SendOnDataChange(NULL); + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE get_Font(IFontDisp** ppFont) + { + __if_exists(T::m_pFont) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_Font\n")); + ATLASSERT(ppFont != NULL); + if (ppFont == NULL) + return E_POINTER; + + T* pT = (T*) this; + *ppFont = pT->m_pFont; + if (*ppFont != NULL) + (*ppFont)->AddRef(); + } + return S_OK; + } + // Picture + HRESULT STDMETHODCALLTYPE put_Picture(IPictureDisp* pPicture) + { + __if_exists(T::m_pPicture) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_Picture\n")); + T* pT = (T*) this; + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_PICTURE) == S_FALSE) + return S_FALSE; + pT->m_pPicture = 0; + if (pPicture) + { + CComQIPtr p(pPicture); + if (p) + { + ULARGE_INTEGER l; + p->GetSizeMax(&l); + HGLOBAL hGlob = GlobalAlloc(GHND, l.LowPart); + if (hGlob) + { + CComPtr spStream; + CreateStreamOnHGlobal(hGlob, TRUE, &spStream); + if (spStream) + { + if (SUCCEEDED(p->Save(spStream, FALSE))) + { + LARGE_INTEGER l; + l.QuadPart = 0; + spStream->Seek(l, STREAM_SEEK_SET, NULL); + OleLoadPicture(spStream, l.LowPart, FALSE, __uuidof(IPictureDisp), (void**)&pT->m_pPicture); + } + spStream.Release(); + } + GlobalFree(hGlob); + } + } + } + pT->m_bRequiresSave = TRUE; + if (pT->m_nFreezeEvents == 0) + pT->FireOnChanged(DISPID_PICTURE); + __if_exists(T::OnPictureChanged) + { + pT->OnPictureChanged(); + } + pT->FireViewChange(); + pT->SendOnDataChange(NULL); + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE putref_Picture(IPictureDisp* pPicture) + { + __if_exists(T::m_pPicture) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::putref_Picture\n")); + T* pT = (T*) this; + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_PICTURE) == S_FALSE) + return S_FALSE; + pT->m_pPicture = pPicture; + pT->m_bRequiresSave = TRUE; + if (pT->m_nFreezeEvents == 0) + pT->FireOnChanged(DISPID_PICTURE); + __if_exists(T::OnPictureChanged) + { + pT->OnPictureChanged(); + } + pT->FireViewChange(); + pT->SendOnDataChange(NULL); + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE get_Picture(IPictureDisp** ppPicture) + { + __if_exists(T::m_pPicture) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_Picture\n")); + ATLASSERT(ppPicture != NULL); + if (ppPicture == NULL) + return E_POINTER; + + T* pT = (T*) this; + *ppPicture = pT->m_pPicture; + if (*ppPicture != NULL) + (*ppPicture)->AddRef(); + } + return S_OK; + } + // MouseIcon + HRESULT STDMETHODCALLTYPE put_MouseIcon(IPictureDisp* pPicture) + { + __if_exists(T::m_pMouseIcon) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_MouseIcon\n")); + T* pT = (T*) this; + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_MOUSEICON) == S_FALSE) + return S_FALSE; + pT->m_pMouseIcon = 0; + if (pPicture) + { + CComQIPtr p(pPicture); + if (p) + { + ULARGE_INTEGER l; + p->GetSizeMax(&l); + HGLOBAL hGlob = GlobalAlloc(GHND, l.LowPart); + if (hGlob) + { + CComPtr spStream; + CreateStreamOnHGlobal(hGlob, TRUE, &spStream); + if (spStream) + { + if (SUCCEEDED(p->Save(spStream, FALSE))) + { + LARGE_INTEGER l; + l.QuadPart = 0; + spStream->Seek(l, STREAM_SEEK_SET, NULL); + OleLoadPicture(spStream, l.LowPart, FALSE, __uuidof(IPictureDisp), (void**)&pT->m_pMouseIcon); + } + spStream.Release(); + } + GlobalFree(hGlob); + } + } + } + pT->m_bRequiresSave = TRUE; + if (pT->m_nFreezeEvents == 0) + pT->FireOnChanged(DISPID_MOUSEICON); + __if_exists(T::OnMouseIconChanged) + { + pT->OnMouseIconChanged(); + } + pT->FireViewChange(); + pT->SendOnDataChange(NULL); + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE putref_MouseIcon(IPictureDisp* pPicture) + { + __if_exists(T::m_pMouseIcon) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::putref_MouseIcon\n")); + T* pT = (T*) this; + if (pT->m_nFreezeEvents == 0 && pT->FireOnRequestEdit(DISPID_MOUSEICON) == S_FALSE) + return S_FALSE; + pT->m_pMouseIcon = pPicture; + pT->m_bRequiresSave = TRUE; + if (pT->m_nFreezeEvents == 0) + pT->FireOnChanged(DISPID_MOUSEICON); + __if_exists(T::OnMouseIconChanged) + { + pT->OnMouseIconChanged(); + } + pT->FireViewChange(); + pT->SendOnDataChange(NULL); + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE get_MouseIcon(IPictureDisp** ppPicture) + { + __if_exists(T::m_pMouseIcon) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_MouseIcon\n")); + ATLASSERT(ppPicture != NULL); + if (ppPicture == NULL) + return E_POINTER; + + T* pT = (T*) this; + *ppPicture = pT->m_pMouseIcon; + if (*ppPicture != NULL) + (*ppPicture)->AddRef(); + } + return S_OK; + } + IMPLEMENT_STOCKPROP(OLE_COLOR, BackColor, clrBackColor, DISPID_BACKCOLOR) + IMPLEMENT_STOCKPROP(OLE_COLOR, BorderColor, clrBorderColor, DISPID_BORDERCOLOR) + IMPLEMENT_STOCKPROP(OLE_COLOR, FillColor, clrFillColor, DISPID_FILLCOLOR) + IMPLEMENT_STOCKPROP(OLE_COLOR, ForeColor, clrForeColor, DISPID_FORECOLOR) + IMPLEMENT_BOOL_STOCKPROP(AutoSize, bAutoSize, DISPID_AUTOSIZE) + IMPLEMENT_BOOL_STOCKPROP(Valid, bValid, DISPID_VALID) + IMPLEMENT_BOOL_STOCKPROP(Enabled, bEnabled, DISPID_ENABLED) + IMPLEMENT_BOOL_STOCKPROP(TabStop, bTabStop, DISPID_TABSTOP) + IMPLEMENT_BOOL_STOCKPROP(BorderVisible, bBorderVisible, DISPID_BORDERVISIBLE) + IMPLEMENT_BSTR_STOCKPROP(Text, bstrText, DISPID_TEXT) + IMPLEMENT_BSTR_STOCKPROP(Caption, bstrCaption, DISPID_CAPTION) + HRESULT STDMETHODCALLTYPE put_Window(LONG_PTR hWnd) + { + return put_HWND(hWnd); + } + HRESULT STDMETHODCALLTYPE get_Window(LONG_PTR* phWnd) + { + return get_HWND(phWnd); + } + HRESULT STDMETHODCALLTYPE put_HWND(LONG_PTR /*hWnd*/) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::put_HWND\n")); + return E_FAIL; + } + HRESULT STDMETHODCALLTYPE get_HWND(LONG_PTR* phWnd) + { + __if_exists(T::m_hWnd) + { + ATLTRACE(atlTraceControls,2,_T("CStockPropImpl::get_HWND\n")); + ATLASSERT(phWnd != NULL); + if (phWnd == NULL) + return E_POINTER; + T* pT = (T*) this; + *phWnd = reinterpret_cast(pT->m_hWnd); + } + return S_OK; + } + IMPLEMENT_STOCKPROP(LONG, BackStyle, nBackStyle, DISPID_BACKSTYLE) + IMPLEMENT_STOCKPROP(LONG, BorderStyle, nBorderStyle, DISPID_BORDERSTYLE) + IMPLEMENT_STOCKPROP(LONG, BorderWidth, nBorderWidth, DISPID_BORDERWIDTH) + IMPLEMENT_STOCKPROP(LONG, DrawMode, nDrawMode, DISPID_DRAWMODE) + IMPLEMENT_STOCKPROP(LONG, DrawStyle, nDrawStyle, DISPID_DRAWSTYLE) + IMPLEMENT_STOCKPROP(LONG, DrawWidth, nDrawWidth, DISPID_DRAWWIDTH) + IMPLEMENT_STOCKPROP(LONG, FillStyle, nFillStyle, DISPID_FILLSTYLE) + IMPLEMENT_STOCKPROP(SHORT, Appearance, nAppearance, DISPID_APPEARANCE) + IMPLEMENT_STOCKPROP(LONG, MousePointer, nMousePointer, DISPID_MOUSEPOINTER) + IMPLEMENT_STOCKPROP(LONG, ReadyState, nReadyState, DISPID_READYSTATE) +}; + +#pragma pack(pop) + +}; //namespace ATL + +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning (pop) +#endif //!_ATL_NO_PRAGMA_WARNINGS + +#endif // _ATLCTL_IMPL + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atlcur.h b/externals/WinDDK/7600.16385.1/inc/atl71/atlcur.h new file mode 100644 index 00000000..3c8442ca --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atlcur.h @@ -0,0 +1,428 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLCUR_H__ +#define __ATLCUR_H__ + +#pragma once + +#include + + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ + +const LONGLONG CY_MIN_INTEGER = -922337203685477; +const LONGLONG CY_MAX_INTEGER = 922337203685477; +const SHORT CY_MIN_FRACTION = -9999; +const SHORT CY_MAX_FRACTION = 9999; +const SHORT CY_SCALE = 10000; + +class CComCurrency +{ +public: + +// constructors + CComCurrency() throw() + { + m_currency.int64 = 0; + } + CComCurrency(CURRENCY cySrc) throw() + { + m_currency.int64 = cySrc.int64; + } + CComCurrency(const CComCurrency& curSrc) throw() + { + *this = curSrc; + } + CComCurrency(LONGLONG nInteger, SHORT nFraction) + { + m_currency.int64 = 0; + HRESULT hRes = SetInteger(nInteger); + if (FAILED(hRes)) + AtlThrow(hRes); + hRes = SetFraction(nFraction); + if (FAILED(hRes)) + AtlThrow(hRes); + } + CComCurrency(BYTE bSrc) + { + *this = bSrc; + } + CComCurrency(SHORT sSrc) + { + *this = sSrc; + } + CComCurrency(LONG lSrc) + { + *this = lSrc; + } + CComCurrency(FLOAT fSrc) + { + *this = fSrc; + } + CComCurrency(DOUBLE dSrc) + { + *this = dSrc; + } + CComCurrency(CHAR cSrc) + { + *this = cSrc; + } + CComCurrency(USHORT usSrc) + { + *this = usSrc; + } + CComCurrency(ULONG ulSrc) + { + *this = ulSrc; + } + CComCurrency(DECIMAL dSrc) + { + *this = dSrc; + } + explicit CComCurrency(LPCSTR szSrc) + { + ATLASSERT(szSrc); + if( szSrc == NULL ) + AtlThrow(E_INVALIDARG); + + USES_CONVERSION_EX; + LPOLESTR p = A2OLE_EX(szSrc, _ATL_SAFE_ALLOCA_DEF_THRESHOLD); + if( p == NULL ) + AtlThrow(E_OUTOFMEMORY); + + HRESULT hRes = VarCyFromStr(p, GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + } + explicit CComCurrency(LPCWSTR szSrc) + { + ATLASSERT(szSrc); + HRESULT hRes = VarCyFromStr(const_cast(szSrc), GetThreadLocale(), LOCALE_NOUSEROVERRIDE, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + } + explicit CComCurrency(const VARIANT& varSrc) + { + VARIANT var; + VariantInit(&var); + HRESULT hRes = VariantChangeType(&var, const_cast(&varSrc), 0, VT_CY); + if (FAILED(hRes)) + AtlThrow(hRes); + m_currency.int64 = V_CY(&var).int64; + } + explicit CComCurrency(LPDISPATCH pDispSrc) + { + ATLASSERT(pDispSrc); + HRESULT hRes = VarCyFromDisp(pDispSrc, GetThreadLocale(), &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + } + +// assignment operators + const CComCurrency& operator=(CURRENCY cySrc) throw() + { + m_currency.int64 = cySrc.int64; + return *this; + } + const CComCurrency& operator=(const CComCurrency& curSrc) throw() + { + m_currency.int64 = curSrc.m_currency.int64; + return *this; + } + const CComCurrency& operator=(BYTE bSrc) + { + HRESULT hRes = VarCyFromUI1(bSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(SHORT sSrc) + { + HRESULT hRes = VarCyFromI2(sSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(LONG lSrc) + { + HRESULT hRes = VarCyFromI4(lSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(FLOAT fSrc) + { + HRESULT hRes = VarCyFromR4(fSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(DOUBLE dSrc) + { + HRESULT hRes = VarCyFromR8(dSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(CHAR cSrc) + { + HRESULT hRes = VarCyFromI1(cSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(USHORT usSrc) + { + HRESULT hRes = VarCyFromUI2(usSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(ULONG ulSrc) + { + HRESULT hRes = VarCyFromUI4(ulSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator=(DECIMAL dSrc) + { + HRESULT hRes = VarCyFromDec(&dSrc, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + +// comparison operators + bool operator==(const CComCurrency& cur) const + { + return (static_cast(VARCMP_EQ) == VarCyCmp(m_currency, cur.m_currency)); + } + bool operator!=(const CComCurrency& cur) const + { + return (static_cast(VARCMP_EQ) != VarCyCmp(m_currency, cur.m_currency)); + } + bool operator<(const CComCurrency& cur) const + { + return (static_cast(VARCMP_LT) == VarCyCmp(m_currency, cur.m_currency)); + } + bool operator>(const CComCurrency& cur) const + { + return (static_cast(VARCMP_GT) == VarCyCmp(m_currency, cur.m_currency)); + } + bool operator<=(const CComCurrency& cur) const + { + HRESULT hRes = VarCyCmp(m_currency, cur.m_currency); + return (static_cast(VARCMP_LT) == hRes || (HRESULT)VARCMP_EQ == hRes); + } + bool operator>=(const CComCurrency& cur) const + { + HRESULT hRes = VarCyCmp(m_currency, cur.m_currency); + return (static_cast(VARCMP_GT) == hRes || static_cast(VARCMP_EQ) == hRes); + } + +// math operators + CComCurrency operator+(const CComCurrency& cur) const + { + CURRENCY cy; + HRESULT hRes = VarCyAdd(m_currency, cur.m_currency, &cy); + if (FAILED(hRes)) + AtlThrow(hRes); + return cy; + } + CComCurrency operator-(const CComCurrency& cur) const + { + CURRENCY cy; + HRESULT hRes = VarCySub(m_currency, cur.m_currency, &cy); + if (FAILED(hRes)) + AtlThrow(hRes); + return cy; + } + const CComCurrency& operator+=(const CComCurrency& cur) + { + HRESULT hRes = VarCyAdd(m_currency, cur.m_currency, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + const CComCurrency& operator-=(const CComCurrency& cur) + { + HRESULT hRes = VarCySub(m_currency, cur.m_currency, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + CComCurrency operator*(const CComCurrency& cur) const + { + CURRENCY cy; + HRESULT hRes = VarCyMul(m_currency, cur.m_currency, &cy); + if (FAILED(hRes)) + AtlThrow(hRes); + return cy; + } + const CComCurrency& operator*=(const CComCurrency& cur) + { + HRESULT hRes = VarCyMul(m_currency, cur.m_currency, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + CComCurrency operator*(long nOperand) const + { + CURRENCY cy; + HRESULT hRes = VarCyMulI4(m_currency, nOperand, &cy); + if (FAILED(hRes)) + AtlThrow(hRes); + return cy; + } + const CComCurrency& operator*=(long nOperand) + { + HRESULT hRes = VarCyMulI4(m_currency, nOperand, &m_currency); + if (FAILED(hRes)) + AtlThrow(hRes); + return *this; + } + CComCurrency operator-() const + { + CURRENCY cy; + HRESULT hRes = VarCyNeg(m_currency, &cy); + if (FAILED(hRes)) + AtlThrow(hRes); + return cy; + } + CComCurrency operator/(long nOperand) const + { + ATLASSERT(nOperand); + if( nOperand == 0 ) + AtlThrow(E_INVALIDARG); + + CURRENCY cy; + cy.int64 = m_currency.int64 / nOperand; + return cy; + } + const CComCurrency& operator/=(long nOperand) + { + ATLASSERT(nOperand); + if( nOperand == 0 ) + AtlThrow(E_INVALIDARG); + + m_currency.int64 /= nOperand; + return *this; + } + +// cast operators + operator CURRENCY&() throw() + { + return m_currency; + } + operator const CURRENCY&() const throw() + { + return m_currency; + } + CURRENCY* GetCurrencyPtr() throw() + { + return &m_currency; + } + +// misc functions + HRESULT Round(int nDecimals) + { + ATLASSERT(nDecimals >= 0 && nDecimals <= 4); + if( nDecimals < 0 || nDecimals > 4 ) + return E_INVALIDARG; + + return VarCyRound(m_currency, nDecimals, &m_currency); + } + + HRESULT SetInteger(LONGLONG nInteger) + { + // check if within range + ATLASSERT(nInteger >= CY_MIN_INTEGER && nInteger <= CY_MAX_INTEGER); + if( nInteger < CY_MIN_INTEGER || nInteger > CY_MAX_INTEGER ) + return E_INVALIDARG; + + if (m_currency.int64) + { + // signs must match + if ((m_currency.int64 < 0 && nInteger > 0) || + (m_currency.int64 > 0 && nInteger < 0)) + return TYPE_E_TYPEMISMATCH; + + CURRENCY cyTemp; + // get fractional part + cyTemp.int64 = m_currency.int64 % CY_SCALE; + // check if within range again + if ((nInteger == CY_MAX_INTEGER && cyTemp.int64 > 5807) || + (nInteger == CY_MIN_INTEGER && cyTemp.int64 < -5808)) + return TYPE_E_OUTOFBOUNDS; + // set to fractional part, wiping out integer part + m_currency.int64 = cyTemp.int64; + } + // add new integer part scaled by CY_SCALE + m_currency.int64 += nInteger * CY_SCALE; + return S_OK; + } + + // Based on 4 digits. To set .2, pass 2000, to set .0002, pass a 2 + HRESULT SetFraction(SHORT nFraction) + { + // check if within range + ATLASSERT(nFraction >= CY_MIN_FRACTION && nFraction <= CY_MAX_FRACTION); + if( nFraction < CY_MIN_FRACTION || nFraction > CY_MAX_FRACTION ) + return E_INVALIDARG; + + if (m_currency.int64) + { + // signs must match + if ((m_currency.int64 < 0 && nFraction > 0) || + (m_currency.int64 > 0 && nFraction < 0)) + return TYPE_E_TYPEMISMATCH; + + CURRENCY cyTemp; + // get integer part, wiping out fractional part + cyTemp.int64 = m_currency.int64 / CY_SCALE; + // check if within range again + if ((cyTemp.int64 == CY_MAX_INTEGER && nFraction > 5807) || + (cyTemp.int64 == CY_MIN_INTEGER && nFraction < -5808)) + return TYPE_E_OUTOFBOUNDS; + // scale to CY_SCALE + m_currency.int64 = cyTemp.int64 * CY_SCALE; + } + m_currency.int64 += nFraction; + return S_OK; + } + + LONGLONG GetInteger() const + { + if (m_currency.int64) + return (m_currency.int64 / CY_SCALE); + else + return 0; + } + + SHORT GetFraction() const + { + if (m_currency.int64) + // get fractional part + return static_cast(m_currency.int64 % CY_SCALE); + else + return 0; + } + + CURRENCY m_currency; +}; + +}; //namespace ATL +#pragma pack(pop) +#endif //__ATLSAFE_H__ + diff --git a/externals/WinDDK/7600.16385.1/inc/atl71/atldb.h b/externals/WinDDK/7600.16385.1/inc/atl71/atldb.h new file mode 100644 index 00000000..a6ec9edd --- /dev/null +++ b/externals/WinDDK/7600.16385.1/inc/atl71/atldb.h @@ -0,0 +1,12266 @@ +// This is a part of the Active Template Library. +// Copyright (C) Microsoft Corporation +// All rights reserved. +// +// This source code is only intended as a supplement to the +// Active Template Library Reference and related +// electronic documentation provided with the library. +// See these sources for detailed information regarding the +// Active Template Library product. + +#ifndef __ATLDB_H__ +#define __ATLDB_H__ + +#pragma once + +#ifndef _ATL_NO_PRAGMA_WARNINGS +#pragma warning (push) +#pragma warning(disable: 4702) // unreachable code +#endif //!_ATL_NO_PRAGMA_WARNINGS + +// OLE DB Provider Support + +// Interface Impl Classes +// +// Data Source Object +// +// -Mandatory Interfaces: +// IDBCreateSession +// IDBInitialize +// IDBProperties +// IPersist +// +// Session Object +// +// -Mandatory Interfaces: +// IGetDataSource +// IOpenRowset +// ISessionProperties +// +// -Optional Interfaces: +// IDBCreateCommand +// IDBSchemaRowset +// +// Rowset Object +// +// -Mandatory Interfaces: +// IAccessor +// IColumnsInfo +// IConvertType +// IRowset +// IRowsetInfo +// +// -Optional Interfaces: +// IRowsetIdentity +// +// Command Object +// +// -Mandatory Interfaces: +// ICommand) +// IAccessor) +// ICommandProperties +// ICommandText - derives from ICommand +// IColumnsInfo +// IConvertType + +#include +#include +#include +#include +#include +#include + +#pragma warning(disable: 4244) + + +#pragma pack(push,_ATL_PACKING) +namespace ATL +{ + +inline DBROWCOUNT AbsVal( DBROWCOUNT val ) +{ + if( val < 0 ) + return -val; + else + return val; +} + +/////////////////////////////////////////////////////////////////////////// +// Forwards +template class CUtlPropInfo; +class CColumnIds; + +/////////////////////////////////////////////////////////////////////////// +// Additional Property Flag needed internally +const int DBPROPFLAGS_CHANGE = 0x40000000; + +/////////////////////////////////////////////////////////////////////////// +// ATL Provider Property Definitions +#define ATLDB_NO_STRING 0x01000011 // Arbitrary value for AtlDumpProperty + +/////////////////////////////////////////////////////////////////////////// +// ATL Provider Property Debugging Support + +inline void WINAPI AtlDumpPropsetIID(REFIID iid, DWORD dwStatus) +{ + USES_CONVERSION_EX; + // Handle the most common ones + TCHAR szPropertySetName[100]; + + if(InlineIsEqualGUID(iid, DBPROPSET_DATASOURCEALL)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_DATASOURCEALL -")); + } + else if(InlineIsEqualGUID(iid, DBPROPSET_DATASOURCEINFOALL)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_DATASOURCEINFOALL -")); + } + else if(InlineIsEqualGUID(iid, DBPROPSET_ROWSETALL)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_ROWSETALL -")); + } + else if(InlineIsEqualGUID(iid,DBPROPSET_DBINITALL)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_DBINITALL -")); + } + else if(InlineIsEqualGUID(iid,DBPROPSET_SESSIONALL)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_SESSIONALL -")); + } + if(InlineIsEqualGUID(iid, DBPROPSET_DATASOURCE)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_DATASOURCE -")); + } + else if(InlineIsEqualGUID(iid, DBPROPSET_DATASOURCEINFO)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_DATASOURCEINFO -")); + } + else if(InlineIsEqualGUID(iid, DBPROPSET_ROWSET)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_ROWSET -")); + } + else if(InlineIsEqualGUID(iid,DBPROPSET_DBINIT)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_DBINIT -")); + } + else if(InlineIsEqualGUID(iid,DBPROPSET_SESSION)) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName),_T("DBPROPSET_SESSION -")); + } + else + { + LPOLESTR lpszName = NULL; + if (SUCCEEDED(StringFromCLSID(iid, &lpszName))) + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName), OLE2T_EX(lpszName, _ATL_SAFE_ALLOCA_DEF_THRESHOLD)); + } + else + { + Checked::tcscpy_s(szPropertySetName, _countof(szPropertySetName), _T("Unknown DBPROPSET -")); + } + } + + if (dwStatus & 0x04 /* GETPROP_ERRORSOCCURRED */) + { + Checked::tcscat_s(szPropertySetName, _countof(szPropertySetName), _T(" NOT FOUND\n")); + } + else + { + Checked::tcscat_s(szPropertySetName, _countof(szPropertySetName), _T(" FOUND\n")); + } + + OutputDebugString(szPropertySetName); +} + + +inline void WINAPI AtlDumpProperty(DWORD dwPropertyID, DWORD dwStatus) +{ + TCHAR szProperty[100]; + TCHAR szStatus[24]; + + switch(dwStatus) + { + case DBPROPSTATUS_OK: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("FOUND")); + break; + case DBPROPSTATUS_NOTSUPPORTED: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("NOT SUPPORTED")); + break; + case DBPROPSTATUS_BADVALUE: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("BAD VALUE")); + break; + case DBPROPSTATUS_BADOPTION: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("BAD OPTION")); + break; + case DBPROPSTATUS_BADCOLUMN: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("BAD COLUMN")); + break; + case DBPROPSTATUS_NOTALLSETTABLE: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("NOT ALL SETTABLE")); + break; + case DBPROPSTATUS_NOTSETTABLE: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("NOT SETTABLE")); + break; + case DBPROPSTATUS_NOTSET: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("NOT SET")); + break; + case DBPROPSTATUS_CONFLICTING: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("CONFLICTED")); + break; + case ATLDB_NO_STRING: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("WARNING! NO RESOURCE STRING FOR THIS PROPERTY! ADD IDS_")); + break; + default: + Checked::tcscpy_s(szStatus, _countof(szStatus), _T("INDETERMINATE")); + break; + } + +#if _SECURE_ATL && !defined(_ATL_MIN_CRT) + _stprintf_s(szProperty, _countof(szProperty), _T("Property 0x%lxL -- %s\n"), dwPropertyID, szStatus); +#else +#pragma warning(push) +#pragma warning(disable:4995) // wsprintf is deprecated + wsprintf(szProperty, _T("Property 0x%lxL -- %s\n"), dwPropertyID, szStatus); +#pragma warning(pop) +#endif + OutputDebugString(szProperty); +} + + +/////////////////////////////////////////////////////////////////////////// +// Defines for debugging properties + +#ifdef _ATL_DEBUG_PROVIDER_PROPS +#define _ATLDUMPPROPSETIID(iid, dwStatus) AtlDumpPropsetIID(iid, dwStatus) +#define _ATLDUMPPROPERTY(dwPropertyID, dwStatus) AtlDumpProperty(dwPropertyID, dwStatus) +#else +#define _ATLDUMPPROPSETIID(iid, dwStatus) +#define _ATLDUMPPROPERTY(dwPropertyID, dwStatus) +#endif // _ATL_DEBUG_PROVIDER_PROPS + +// ------------- STRUCTURE DEFINITIONS ----------------------------------- + +struct UPROPVAL +{ + DBPROPOPTIONS dwOption; + CColumnIds* pCColumnIds; + DWORD dwFlags; + VARIANT vValue; +}; + +struct UPROPINFO +{ + DBPROPID dwPropId; + ULONG ulIDS; + VARTYPE VarType; + DBPROPFLAGS dwFlags; + union + { + DWORD_PTR dwVal; + LPOLESTR szVal; + }; + DBPROPOPTIONS dwOption; +}; + +struct UPROP +{ + ULONG cPropIds; + UPROPINFO** rgpUPropInfo; + UPROPVAL* pUPropVal; +}; + +struct PROPCOLID +{ + DBID dbidProperty; // The column id information + DBPROPOPTIONS dwOption; + VARIANT vValue; +}; + +typedef PROPCOLID* PPROPCOLID; + +struct UPROPSET +{ + const GUID* pPropSet; + ULONG cUPropInfo; + UPROPINFO* pUPropInfo; + DWORD dwFlags; + bool bIsChained; +}; + +struct ATLBINDINGS +{ + DBBINDING* pBindings; + DWORD dwRef;//DBREFCOUNT dwRef; + DBCOUNTITEM cBindings; + DBACCESSORFLAGS dwAccessorFlags; +}; + +struct ATLCOLUMNINFO +{ + LPOLESTR pwszName; + ITypeInfo *pTypeInfo; + DBORDINAL iOrdinal; + DBCOLUMNFLAGS dwFlags; + DBLENGTH ulColumnSize; + DBTYPE wType; + BYTE bPrecision; + BYTE bScale; + DBID columnid; + DBBYTEOFFSET cbOffset; +}; + +// +// The following very large sections of defines are to implement auto determination +// of Property map constants based on a stringized prop name. There is one set for +// Type (VT_), one for Init Value, and one for Property flags. +// + +#define ABORTPRESERVE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define ACTIVESESSIONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define APPENDONLY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define ASYNCTXNABORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define ASYNCTXNCOMMIT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define AUTH_CACHE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define AUTH_ENCRYPT_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define AUTH_INTEGRATED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define AUTH_MASK_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define AUTH_PASSWORD_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define AUTH_PERSIST_ENCRYPTED_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define AUTH_USERID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define BLOCKINGSTORAGEOBJECTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define BOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define BOOKMARKSKIPPED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define BOOKMARKTYPE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define BYREFACCESSORS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define CACHEDEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define CANFETCHBACKWARDS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define CANHOLDROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define CANSCROLLBACKWARDS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define CATALOGLOCATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define CATALOGTERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define CATALOGUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define CHANGEINSERTEDROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE ) +#define COL_AUTOINCREMENT_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COL_DEFAULT_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COL_DESCRIPTION_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COL_FIXEDLENGTH_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COL_NULLABLE_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COL_PRIMARYKEY_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COL_UNIQUE_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COLUMNDEFINITION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define COLUMNRESTRICT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define COMMANDTIMEOUT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COMMITPRESERVE_Flags ( DBPROPFLAGS_ROWSET| DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define CONCATNULLBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define CURRENTCATALOG_Flags ( DBPROPFLAGS_DATASOURCE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define DATASOURCENAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define DATASOURCEREADONLY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define DBMSNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define DBMSVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define DEFERRED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define DELAYSTORAGEOBJECTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define DSOTHREADMODEL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define GROUPBY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define HETEROGENEOUSTABLES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define IAccessor_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IColumnsInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IColumnsRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IConnectionPointContainer_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define IConvertType_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IRowsetChange_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowsetIdentity_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IRowsetIndex_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IRowsetInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IRowsetLocate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define IRowsetResynch_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IRowsetScroll_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define IRowsetUpdate_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define ISupportErrorInfo_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define ILockBytes_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define ISequentialStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IStorage_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IStream_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define IMMOBILEROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_AUTOUPDATE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_CLUSTERED_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_FILLFACTOR_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_INITIALSIZE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_NULLCOLLATION_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_NULLS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_PRIMARYKEY_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_SORTBOOKMARKS_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_TEMPINDEX_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_TYPE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INDEX_UNIQUE_Flags ( DBPROPFLAGS_INDEX | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_DATASOURCE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_HWND_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_IMPERSONATION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_LCID_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_LOCATION_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_MODE_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_PROMPT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_PROTECTION_LEVEL_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_PROVIDERSTRING_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_TIMEOUT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define LITERALBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define LITERALIDENTITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MAXINDEXSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MAXOPENROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define MAXPENDINGROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define MAXROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define MAXROWSIZE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MAXROWSIZEINCLUDESBLOB_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MAXTABLESINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MAYWRITECOLUMN_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define MEMORYUSAGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define MULTIPLEPARAMSETS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MULTIPLERESULTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MULTIPLESTORAGEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MULTITABLEUPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define NOTIFICATIONGRANULARITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define NOTIFICATIONPHASES_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYCOLUMNSET_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWFIRSTCHANGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWRESYNCH_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWSETRELEASE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWSETFETCHPOSITIONCHANGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWUNDOCHANGE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWUNDODELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWUNDOINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NOTIFYROWUPDATE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define NULLCOLLATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define OLEOBJECTS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define ORDERBYCOLUMNSINSELECT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define ORDEREDBOOKMARKS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define OTHERINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define OTHERUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define OUTPUTPARAMETERAVAILABILITY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define OWNINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define OWNUPDATEDELETE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define PERSISTENTIDTYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define PREPAREABORTBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define PREPARECOMMITBEHAVIOR_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define PROCEDURETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define PROVIDERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define PROVIDEROLEDBVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define PROVIDERVER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define QUICKRESTART_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define QUOTEDIDENTIFIERCASE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define REENTRANTEVENTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define REMOVEDELETED_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define REPORTMULTIPLECHANGES_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_CHANGE ) +#define RETURNPENDINGINSERTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define ROWRESTRICT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define ROWSETCONVERSIONSONCOMMAND_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define ROWTHREADMODEL_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define SCHEMATERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define SCHEMAUSAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define SERVERCURSOR_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define SESS_AUTOCOMMITISOLEVELS_Flags ( DBPROPFLAGS_SESSION | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE) +#define SQLSUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define STRONGIDENTITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define STRUCTUREDSTORAGE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define SUBQUERIES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define SUPPORTEDTXNDDL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define SUPPORTEDTXNISOLEVELS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define SUPPORTEDTXNISORETAIN_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define TABLETERM_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define TBL_TEMPTABLE_Flags ( DBPROPFLAGS_TABLE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define TRANSACTEDOBJECT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define UPDATABILITY_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define USERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +// 1.5 +#define FILTERCOMPAREOPS_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ ) +#define FINDCOMPAREOPS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define IChapteredRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IDBAsynchStatus_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowsetFind_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowsetView_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IViewChapter_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IViewFilter_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IViewRowset_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IViewSort_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_ASYNCH_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define MAXOPENCHAPTERS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MAXORSINFILTER_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ ) +#define MAXSORTCOLUMNS_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ ) +#define ROWSET_ASYNCH_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define SORTONINDEX_Flags ( DBPROPFLAGS_VIEW | DBPROPFLAGS_READ ) +// 2.0 +#define IMultipleResults_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define DATASOURCE_TYPE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +//MDPROP +#define AXES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define FLATTENING_SUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_JOINCUBES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define NAMED_LEVELS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +//#define RANGEROWSET_Flags ( ) +#define MDX_SLICER_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +//#define MDX_CUBEQUALIFICATION_Flags ( ) +#define MDX_OUTERREFERENCE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_QUERYBYPROPERTY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_CASESUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_STRING_COMPOP_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_DESCFLAGS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_SET_FUNCTIONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_MEMBER_FUNCTIONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_NUMERIC_FUNCTIONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_FORMULAS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define AGGREGATECELL_UPDATE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +//#define MDX_AGGREGATECELL_UPDATE_Flags ( ) +#define MDX_OBJQUALIFICATION_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define MDX_NONMEASURE_EXPRESSONS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +// DBPROP +#define ACCESSORDER_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define BOOKMARKINFO_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define INIT_CATALOG_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define ROW_BULKOPS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) //!!! +#define PROVIDERFRIENDLYNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define LOCKMODE_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define MULTIPLECONNECTIONS_Flags ( DBPROPFLAGS_DATASOURCE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define UNIQUEROWS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define SERVERDATAONINSERT_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +//#define STORAGEFLAGS_Flags ( ) +#define CONNECTIONSTATUS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define ALTERCOLUMN_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define COLUMNLCID_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ ) +#define RESETDATASOURCE_Flags ( DBPROPFLAGS_DATASOURCE | DBPROPFLAGS_WRITE ) +#define INIT_OLEDBSERVICES_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowsetRefresh_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define SERVERNAME_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define IParentRowset_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define HIDDENCOLUMNS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ ) +#define PROVIDERMEMORY_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define CLIENTCURSOR_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +// 2.1 +#define TRUSTEE_USERNAME_Flags ( DBPROPFLAGS_TRUSTEE | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define TRUSTEE_AUTHENTICATION_Flags ( DBPROPFLAGS_TRUSTEE | DBPROPFLAGS_WRITE ) +#define TRUSTEE_NEWAUTHENTICATION_Flags ( DBPROPFLAGS_TRUSTEE | DBPROPFLAGS_WRITE ) +#define IRow_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowChange_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowSchemaChange_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IGetRow_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IScopedOperations_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IBindResource_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define ICreateRow_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_BINDFLAGS_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_LOCKOWNER_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define GENERATEURL_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +//#define IDBBinderProperties_Flags ( ) +#define IColumnsInfo2_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +//#define IRegisterProvider_Flags ( ) +#define IGetSession_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IGetSourceRow_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowsetCurrentIndex_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define OPENROWSETSUPPORT_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define COL_ISLONG_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +// 2.5 +#define COL_SEED_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COL_INCREMENT_Flags ( DBPROPFLAGS_COLUMN | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define INIT_GENERALTIMEOUT_Flags ( DBPROPFLAGS_DBINIT | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define COMSERVICES_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +// 2.6 +#define OUTPUTSTREAM_Flags ( DBPROPFLAGS_STREAM | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define OUTPUTENCODING_Flags ( DBPROPFLAGS_STREAM | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define TABLESTATISTICS_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_READ ) +#define SKIPROWCOUNTRESULTS_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define IRowsetBookmark_Flags ( DBPROPFLAGS_ROWSET | DBPROPFLAGS_READ | DBPROPFLAGS_WRITE ) +#define VISUALMODE_Flags ( DBPROPFLAGS_DATASOURCEINFO | DBPROPFLAGS_WRITE ) + + +#define ABORTPRESERVE_Type VT_BOOL +#define ACTIVESESSIONS_Type VT_I4 +#define APPENDONLY_Type VT_BOOL +#define ASYNCTXNABORT_Type VT_BOOL +#define ASYNCTXNCOMMIT_Type VT_BOOL +#define AUTH_CACHE_AUTHINFO_Type VT_BOOL +#define AUTH_ENCRYPT_PASSWORD_Type VT_BOOL +#define AUTH_INTEGRATED_Type VT_BSTR +#define AUTH_MASK_PASSWORD_Type VT_BOOL +#define AUTH_PASSWORD_Type VT_BSTR +#define AUTH_PERSIST_ENCRYPTED_Type VT_BOOL +#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Type VT_BOOL +#define AUTH_USERID_Type VT_BSTR +#define BLOCKINGSTORAGEOBJECTS_Type VT_BOOL +#define BOOKMARKS_Type VT_BOOL +#define BOOKMARKSKIPPED_Type VT_BOOL +#define BOOKMARKTYPE_Type VT_I4 +#define BYREFACCESSORS_Type VT_BOOL +#define CACHEDEFERRED_Type VT_BOOL +#define CANFETCHBACKWARDS_Type VT_BOOL +#define CANHOLDROWS_Type VT_BOOL +#define CANSCROLLBACKWARDS_Type VT_BOOL +#define CATALOGLOCATION_Type VT_I4 +#define CATALOGTERM_Type VT_BSTR +#define CATALOGUSAGE_Type VT_I4 +#define CHANGEINSERTEDROWS_Type VT_BOOL +#define COL_AUTOINCREMENT_Type VT_BOOL +#define COL_DEFAULT_Type VT_BSTR +#define COL_DESCRIPTION_Type VT_BSTR +#define COL_FIXEDLENGTH_Type VT_BOOL +#define COL_NULLABLE_Type VT_BOOL +#define COL_PRIMARYKEY_Type VT_BOOL +#define COL_UNIQUE_Type VT_BOOL +#define COLUMNDEFINITION_Type VT_I4 +#define COLUMNRESTRICT_Type VT_BOOL +#define COMMANDTIMEOUT_Type VT_I4 +#define COMMITPRESERVE_Type VT_BOOL +#define CONCATNULLBEHAVIOR_Type VT_I4 +#define CURRENTCATALOG_Type VT_BSTR +#define DATASOURCENAME_Type VT_BSTR +#define DATASOURCEREADONLY_Type VT_BOOL +#define DBMSNAME_Type VT_BSTR +#define DBMSVER_Type VT_BSTR +#define DEFERRED_Type VT_BOOL +#define DELAYSTORAGEOBJECTS_Type VT_BOOL +#define DSOTHREADMODEL_Type VT_I4 +#define GROUPBY_Type VT_I4 +#define HETEROGENEOUSTABLES_Type VT_I4 +#define IAccessor_Type VT_BOOL +#define IColumnsInfo_Type VT_BOOL +#define IColumnsRowset_Type VT_BOOL +#define IConnectionPointContainer_Type VT_BOOL +#define IConvertType_Type VT_BOOL +#define IRowset_Type VT_BOOL +#define IRowsetChange_Type VT_BOOL +#define IRowsetIdentity_Type VT_BOOL +#define IRowsetIndex_Type VT_BOOL +#define IRowsetInfo_Type VT_BOOL +#define IRowsetLocate_Type VT_BOOL +#define IRowsetResynch_Type VT_BOOL +#define IRowsetScroll_Type VT_BOOL +#define IRowsetUpdate_Type VT_BOOL +#define ISupportErrorInfo_Type VT_BOOL +#define ILockBytes_Type VT_BOOL +#define ISequentialStream_Type VT_BOOL +#define IStorage_Type VT_BOOL +#define IStream_Type VT_BOOL +#define IDENTIFIERCASE_Type VT_I4 +#define IMMOBILEROWS_Type VT_BOOL +#define INDEX_AUTOUPDATE_Type VT_BOOL +#define INDEX_CLUSTERED_Type VT_BOOL +#define INDEX_FILLFACTOR_Type VT_I4 +#define INDEX_INITIALSIZE_Type VT_I4 +#define INDEX_NULLCOLLATION_Type VT_I4 +#define INDEX_NULLS_Type VT_I4 +#define INDEX_PRIMARYKEY_Type VT_BOOL +#define INDEX_SORTBOOKMARKS_Type VT_BOOL +#define INDEX_TEMPINDEX_Type VT_BOOL +#define INDEX_TYPE_Type VT_I4 +#define INDEX_UNIQUE_Type VT_BOOL +#define INIT_DATASOURCE_Type VT_BSTR +#define INIT_HWND_Type VT_I4 +#define INIT_IMPERSONATION_LEVEL_Type VT_I4 +#define INIT_LCID_Type VT_I4 +#define INIT_LOCATION_Type VT_BSTR +#define INIT_MODE_Type VT_I4 +#define INIT_PROMPT_Type VT_I2 +#define INIT_PROTECTION_LEVEL_Type VT_I4 +#define INIT_PROVIDERSTRING_Type VT_BSTR +#define INIT_TIMEOUT_Type VT_I4 +#define LITERALBOOKMARKS_Type VT_BOOL +#define LITERALIDENTITY_Type VT_BOOL +#define MAXINDEXSIZE_Type VT_I4 +#define MAXOPENROWS_Type VT_I4 +#define MAXPENDINGROWS_Type VT_I4 +#define MAXROWS_Type VT_I4 +#define MAXROWSIZE_Type VT_I4 +#define MAXROWSIZEINCLUDESBLOB_Type VT_BOOL +#define MAXTABLESINSELECT_Type VT_I4 +#define MAYWRITECOLUMN_Type VT_BOOL +#define MEMORYUSAGE_Type VT_I4 +#define MULTIPLEPARAMSETS_Type VT_BOOL +#define MULTIPLERESULTS_Type VT_I4 +#define MULTIPLESTORAGEOBJECTS_Type VT_BOOL +#define MULTITABLEUPDATE_Type VT_BOOL +#define NOTIFICATIONGRANULARITY_Type VT_I4 +#define NOTIFICATIONPHASES_Type VT_I4 +#define NOTIFYCOLUMNSET_Type VT_I4 +#define NOTIFYROWDELETE_Type VT_I4 +#define NOTIFYROWFIRSTCHANGE_Type VT_I4 +#define NOTIFYROWINSERT_Type VT_I4 +#define NOTIFYROWRESYNCH_Type VT_I4 +#define NOTIFYROWSETRELEASE_Type VT_I4 +#define NOTIFYROWSETFETCHPOSITIONCHANGE_Type VT_I4 +#define NOTIFYROWUNDOCHANGE_Type VT_I4 +#define NOTIFYROWUNDODELETE_Type VT_I4 +#define NOTIFYROWUNDOINSERT_Type VT_I4 +#define NOTIFYROWUPDATE_Type VT_I4 +#define NULLCOLLATION_Type VT_I4 +#define OLEOBJECTS_Type VT_I4 +#define ORDERBYCOLUMNSINSELECT_Type VT_BOOL +#define ORDEREDBOOKMARKS_Type VT_BOOL +#define OTHERINSERT_Type VT_BOOL +#define OTHERUPDATEDELETE_Type VT_BOOL +#define OUTPUTPARAMETERAVAILABILITY_Type VT_I4 +#define OWNINSERT_Type VT_BOOL +#define OWNUPDATEDELETE_Type VT_BOOL +#define PERSISTENTIDTYPE_Type VT_I4 +#define PREPAREABORTBEHAVIOR_Type VT_I4 +#define PREPARECOMMITBEHAVIOR_Type VT_I4 +#define PROCEDURETERM_Type VT_BSTR +#define PROVIDERNAME_Type VT_BSTR +#define PROVIDEROLEDBVER_Type VT_BSTR +#define PROVIDERVER_Type VT_BSTR +#define QUICKRESTART_Type VT_BOOL +#define QUOTEDIDENTIFIERCASE_Type VT_I4 +#define REENTRANTEVENTS_Type VT_BOOL +#define REMOVEDELETED_Type VT_BOOL +#define REPORTMULTIPLECHANGES_Type VT_BOOL +#define RETURNPENDINGINSERTS_Type VT_BOOL +#define ROWRESTRICT_Type VT_BOOL +#define ROWSETCONVERSIONSONCOMMAND_Type VT_BOOL +#define ROWTHREADMODEL_Type VT_I4 +#define SCHEMATERM_Type VT_BSTR +#define SCHEMAUSAGE_Type VT_I4 +#define SERVERCURSOR_Type VT_BOOL +#define SESS_AUTOCOMMITISOLEVELS_Type VT_I4 +#define SQLSUPPORT_Type VT_I4 +#define STRONGIDENTITY_Type VT_BOOL +#define STRUCTUREDSTORAGE_Type VT_I4 +#define SUBQUERIES_Type VT_I4 +#define SUPPORTEDTXNDDL_Type VT_I4 +#define SUPPORTEDTXNISOLEVELS_Type VT_I4 +#define SUPPORTEDTXNISORETAIN_Type VT_I4 +#define TABLETERM_Type VT_BSTR +#define TBL_TEMPTABLE_Type VT_BOOL +#define TRANSACTEDOBJECT_Type VT_BOOL +#define UPDATABILITY_Type VT_I4 +#define USERNAME_Type VT_BSTR +// 1.5 +#define FILTERCOMPAREOPS_Type VT_I4 +#define FINDCOMPAREOPS_Type VT_I4 +#define IChapteredRowset_Type VT_BOOL +#define IDBAsynchStatus_Type VT_BOOL +#define IRowsetFind_Type VT_BOOL +#define IRowsetView_Type VT_BOOL +#define IViewChapter_Type VT_BOOL +#define IViewFilter_Type VT_BOOL +#define IViewRowset_Type VT_BOOL +#define IViewSort_Type VT_BOOL +#define INIT_ASYNCH_Type VT_I4 +#define MAXOPENCHAPTERS_Type VT_I4 +#define MAXORSINFILTER_Type VT_I4 +#define MAXSORTCOLUMNS_Type VT_I4 +#define ROWSET_ASYNCH_Type VT_I4 +#define SORTONINDEX_Type VT_BOOL +// 2.0 +#define IMultipleResults_Flags_Type VT_BOOL +#define DATASOURCE_TYPE_Flags_Type VT_I4 +//MDPROP +#define AXES_Type VT_I4 +#define FLATTENING_SUPPORT_Type VT_I4 +#define MDX_JOINCUBES_Type VT_I4 +#define NAMED_LEVELS_Type VT_I4 +//#define RANGEROWSET_Type +#define MDX_SLICER_Type VT_I4 +//#define MDX_CUBEQUALIFICATION_Type +#define MDX_OUTERREFERENCE_Type VT_I4 +#define MDX_QUERYBYPROPERTY_Type VT_BOOL +#define MDX_CASESUPPORT_Type VT_I4 +#define MDX_STRING_COMPOP_Type VT_I4 +#define MDX_DESCFLAGS_Type VT_I4 +#define MDX_SET_FUNCTIONS_Type VT_I4 +#define MDX_MEMBER_FUNCTIONS_Type VT_I4 +#define MDX_NUMERIC_FUNCTIONS_Type VT_I4 +#define MDX_FORMULAS_Type VT_I4 +#define AGGREGATECELL_UPDATE_Type VT_I4 +//#define MDX_AGGREGATECELL_UPDATE_Type +#define MDX_OBJQUALIFICATION_Type VT_I4 +#define MDX_NONMEASURE_EXPRESSONS_Type VT_I4 +// DBPROP +#define ACCESSORDER_Type VT_I4 +#define BOOKMARKINFO_Type VT_I4 +#define INIT_CATALOG_Type VT_BSTR +#define ROW_BULKOPS_Type VT_I4 +#define PROVIDERFRIENDLYNAME_Type VT_BSTR +#define LOCKMODE_Type VT_I4 +#define MULTIPLECONNECTIONS_Type VT_BOOL +#define UNIQUEROWS_Type VT_BOOL +#define SERVERDATAONINSERT_Type VT_BOOL +//#define STORAGEFLAGS_Type +#define CONNECTIONSTATUS_Type VT_I4 +#define ALTERCOLUMN_Type VT_I4 +#define COLUMNLCID_Type VT_I4 +#define RESETDATASOURCE_Type VT_I4 +#define INIT_OLEDBSERVICES_Type VT_I4 +#define IRowsetRefresh_Type VT_BOOL +#define SERVERNAME_Type VT_BSTR +#define IParentRowset_Type VT_BOOL +#define HIDDENCOLUMNS_Type VT_I4 +#define PROVIDERMEMORY_Type VT_BOOL +#define CLIENTCURSOR_Type VT_BOOL +// 2.1 +#define TRUSTEE_USERNAME_Type VT_BSTR +#define TRUSTEE_AUTHENTICATION_Type VT_BSTR +#define TRUSTEE_NEWAUTHENTICATION_Type VT_BSTR +#define IRow_Type VT_BOOL +#define IRowChange_Type VT_BOOL +#define IRowSchemaChange_Type VT_BOOL +#define IGetRow_Type VT_BOOL +#define IScopedOperations_Type VT_BOOL +#define IBindResource_Type VT_BOOL +#define ICreateRow_Type VT_BOOL +#define INIT_BINDFLAGS_Type VT_I4 +#define INIT_LOCKOWNER_Type VT_BSTR +#define GENERATEURL_Type VT_I4 +//#define IDBBinderProperties_Type +#define IColumnsInfo2_Type VT_BOOL +//#define IRegisterProvider_Type +#define IGetSession_Type VT_BOOL +#define IGetSourceRow_Type VT_BOOL +#define IRowsetCurrentIndex_Type VT_BOOL +#define OPENROWSETSUPPORT_Type VT_I4 +#define COL_ISLONG_Type VT_BOOL +// 2.5 +//#define COL_SEED_Type VT_VARIANT //!!! +//#define COL_INCREMENT_Type VT_VARIANT //!!! +#define INIT_GENERALTIMEOUT_Type VT_I4 +#define COMSERVICES_Type VT_I4 +// 2.6 +#define OUTPUTSTREAM_Type VT_UNKNOWN +#define OUTPUTENCODING_Type VT_BSTR +#define TABLESTATISTICS_Type VT_I4 +#define SKIPROWCOUNTRESULTS_Type VT_BOOL +#define IRowsetBookmark_Type VT_BOOL +#define VISUALMODE_Type VT_I4 + + + +#define ABORTPRESERVE_Value ATL_VARIANT_FALSE +#define ACTIVESESSIONS_Value 0 +#define APPENDONLY_Value ATL_VARIANT_FALSE +#define ASYNCTXNABORT_Value ATL_VARIANT_FALSE +#define ASYNCTXNCOMMIT_Value ATL_VARIANT_FALSE +#define AUTH_CACHE_AUTHINFO_Value ATL_VARIANT_FALSE +#define AUTH_ENCRYPT_PASSWORD_Value ATL_VARIANT_FALSE +#define AUTH_INTEGRATED_Value OLESTR("") +#define AUTH_MASK_PASSWORD_Value ATL_VARIANT_FALSE +#define AUTH_PASSWORD_Value OLESTR("") +#define AUTH_PERSIST_ENCRYPTED_Value ATL_VARIANT_FALSE +#define AUTH_PERSIST_SENSITIVE_AUTHINFO_Value ATL_VARIANT_FALSE +#define AUTH_USERID_Value OLESTR("") +#define BLOCKINGSTORAGEOBJECTS_Value ATL_VARIANT_FALSE +#define BOOKMARKS_Value ATL_VARIANT_FALSE +#define BOOKMARKSKIPPED_Value ATL_VARIANT_FALSE +#define BOOKMARKTYPE_Value 0 +#define BYREFACCESSORS_Value ATL_VARIANT_FALSE +#define CACHEDEFERRED_Value ATL_VARIANT_FALSE +#define CANFETCHBACKWARDS_Value ATL_VARIANT_TRUE +#define CANHOLDROWS_Value ATL_VARIANT_TRUE +#define CANSCROLLBACKWARDS_Value ATL_VARIANT_TRUE +#define CATALOGLOCATION_Value 0 +#define CATALOGTERM_Value OLESTR("") +#define CATALOGUSAGE_Value 0 +#define CHANGEINSERTEDROWS_Value ATL_VARIANT_FALSE +#define COL_AUTOINCREMENT_Value ATL_VARIANT_FALSE +#define COL_DEFAULT_Value OLESTR("") +#define COL_DESCRIPTION_Value OLESTR("") +#define COL_FIXEDLENGTH_Value ATL_VARIANT_FALSE +#define COL_NULLABLE_Value ATL_VARIANT_FALSE +#define COL_PRIMARYKEY_Value ATL_VARIANT_FALSE +#define COL_UNIQUE_Value ATL_VARIANT_FALSE +#define COLUMNDEFINITION_Value 0 +#define COLUMNRESTRICT_Value ATL_VARIANT_FALSE +#define COMMANDTIMEOUT_Value 0 +#define COMMITPRESERVE_Value ATL_VARIANT_FALSE +#define CONCATNULLBEHAVIOR_Value 0 +#define CURRENTCATALOG_Value OLESTR("") +#define DATASOURCENAME_Value OLESTR("") +#define DATASOURCEREADONLY_Value ATL_VARIANT_TRUE +#define DBMSNAME_Value OLESTR("") +#define DBMSVER_Value OLESTR("") +#define DEFERRED_Value ATL_VARIANT_FALSE +#define DELAYSTORAGEOBJECTS_Value ATL_VARIANT_FALSE +#define DSOTHREADMODEL_Value DBPROPVAL_RT_APTMTTHREAD +#define GROUPBY_Value 0 +#define HETEROGENEOUSTABLES_Value 0 +#define IAccessor_Value ATL_VARIANT_TRUE +#define IColumnsInfo_Value ATL_VARIANT_TRUE +#define IColumnsRowset_Value ATL_VARIANT_FALSE +#define IConnectionPointContainer_Value ATL_VARIANT_FALSE +#define IConvertType_Value ATL_VARIANT_TRUE +#define IRowset_Value ATL_VARIANT_TRUE +#define IRowsetChange_Value ATL_VARIANT_FALSE +#define IRowsetIdentity_Value ATL_VARIANT_TRUE +#define IRowsetIndex_Value ATL_VARIANT_FALSE +#define IRowsetInfo_Value ATL_VARIANT_TRUE +#define IRowsetLocate_Value ATL_VARIANT_FALSE +#define IRowsetResynch_Value ATL_VARIANT_FALSE +#define IRowsetScroll_Value ATL_VARIANT_FALSE +#define IRowsetUpdate_Value ATL_VARIANT_FALSE +#define ISupportErrorInfo_Value ATL_VARIANT_FALSE +#define ILockBytes_Value ATL_VARIANT_FALSE +#define ISequentialStream_Value ATL_VARIANT_FALSE +#define IStorage_Value ATL_VARIANT_FALSE +#define IStream_Value ATL_VARIANT_FALSE +#define IDENTIFIERCASE_Value 0 +#define IMMOBILEROWS_Value ATL_VARIANT_FALSE +#define INDEX_AUTOUPDATE_Value ATL_VARIANT_FALSE +#define INDEX_CLUSTERED_Value ATL_VARIANT_FALSE +#define INDEX_FILLFACTOR_Value 0 +#define INDEX_INITIALSIZE_Value 0 +#define INDEX_NULLCOLLATION_Value 0 +#define INDEX_NULLS_Value 0 +#define INDEX_PRIMARYKEY_Value ATL_VARIANT_FALSE +#define INDEX_SORTBOOKMARKS_Value ATL_VARIANT_FALSE +#define INDEX_TEMPINDEX_Value ATL_VARIANT_FALSE +#define INDEX_TYPE_Value 0 +#define INDEX_UNIQUE_Value ATL_VARIANT_FALSE +#define INIT_DATASOURCE_Value OLESTR("") +#define INIT_HWND_Value 0 +#define INIT_IMPERSONATION_LEVEL_Value 0 +#define INIT_LCID_Value 0 +#define INIT_LOCATION_Value OLESTR("") +#define INIT_MODE_Value DB_MODE_READ +#define INIT_PROMPT_Value DBPROMPT_NOPROMPT +#define INIT_PROTECTION_LEVEL_Value 0 +#define INIT_PROVIDERSTRING_Value OLESTR("") +#define INIT_TIMEOUT_Value 0 +#define LITERALBOOKMARKS_Value ATL_VARIANT_FALSE +#define LITERALIDENTITY_Value ATL_VARIANT_FALSE +#define MAXINDEXSIZE_Value 0 +#define MAXOPENROWS_Value 0 +#define MAXPENDINGROWS_Value 0 +#define MAXROWS_Value 0 +#define MAXROWSIZE_Value 0 +#define MAXROWSIZEINCLUDESBLOB_Value ATL_VARIANT_FALSE +#define MAXTABLESINSELECT_Value 0 +#define MAYWRITECOLUMN_Value ATL_VARIANT_FALSE +#define MEMORYUSAGE_Value 0 +#define MULTIPLEPARAMSETS_Value ATL_VARIANT_FALSE +#define MULTIPLERESULTS_Value 0 +#define MULTIPLESTORAGEOBJECTS_Value ATL_VARIANT_FALSE +#define MULTITABLEUPDATE_Value ATL_VARIANT_FALSE +#define NOTIFICATIONGRANULARITY_Value DBPROPVAL_NT_SINGLEROW +#define NOTIFICATIONPHASES_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER | DBPROPVAL_NP_FAILEDTODO | DBPROPVAL_NP_DIDEVENT +#define NOTIFYCOLUMNSET_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWDELETE_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWFIRSTCHANGE_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWINSERT_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWRESYNCH_Value 0 +#define NOTIFYROWSETRELEASE_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWSETFETCHPOSITIONCHANGE_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWUNDOCHANGE_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWUNDODELETE_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWUNDOINSERT_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NOTIFYROWUPDATE_Value DBPROPVAL_NP_OKTODO | DBPROPVAL_NP_ABOUTTODO | DBPROPVAL_NP_SYNCHAFTER +#define NULLCOLLATION_Value 0 +#define OLEOBJECTS_Value 0 +#define ORDERBYCOLUMNSINSELECT_Value ATL_VARIANT_FALSE +#define ORDEREDBOOKMARKS_Value ATL_VARIANT_FALSE +#define OTHERINSERT_Value ATL_VARIANT_FALSE +#define OTHERUPDATEDELETE_Value ATL_VARIANT_FALSE +#define OUTPUTPARAMETERAVAILABILITY_Value 0 +#define OWNINSERT_Value ATL_VARIANT_FALSE +#define OWNUPDATEDELETE_Value ATL_VARIANT_FALSE +#define PERSISTENTIDTYPE_Value 0 +#define PREPAREABORTBEHAVIOR_Value 0 +#define PREPARECOMMITBEHAVIOR_Value 0 +#define PROCEDURETERM_Value OLESTR("") +#define PROVIDERNAME_Value OLESTR("") +#define PROVIDEROLEDBVER_Value OLESTR("02.60") +#define PROVIDERVER_Value OLESTR("01.00") +#define QUICKRESTART_Value ATL_VARIANT_FALSE +#define QUOTEDIDENTIFIERCASE_Value 0 +#define REENTRANTEVENTS_Value ATL_VARIANT_FALSE +#define REMOVEDELETED_Value ATL_VARIANT_FALSE +#define REPORTMULTIPLECHANGES_Value ATL_VARIANT_FALSE +#define RETURNPENDINGINSERTS_Value ATL_VARIANT_FALSE +#define ROWRESTRICT_Value ATL_VARIANT_FALSE +#define ROWSETCONVERSIONSONCOMMAND_Value ATL_VARIANT_TRUE +#define ROWTHREADMODEL_Value 0 +#define SCHEMATERM_Value OLESTR("") +#define SCHEMAUSAGE_Value 0 +#define SERVERCURSOR_Value ATL_VARIANT_FALSE +#define SESS_AUTOCOMMITISOLEVELS_Value 0 +#define SQLSUPPORT_Value 0 +#define STRONGIDENTITY_Value ATL_VARIANT_FALSE +#define STRUCTUREDSTORAGE_Value 0 +#define SUBQUERIES_Value 0 +#define SUPPORTEDTXNDDL_Value 0 +#define SUPPORTEDTXNISOLEVELS_Value 0 +#define SUPPORTEDTXNISORETAIN_Value 0 +#define TABLETERM_Value OLESTR("") +#define TBL_TEMPTABLE_Value ATL_VARIANT_FALSE +#define TRANSACTEDOBJECT_Value ATL_VARIANT_FALSE +#define UPDATABILITY_Value 0 +#define USERNAME_Value OLESTR("") +// 1.5 +#define FILTERCOMPAREOPS_Value 0 +#define FINDCOMPAREOPS_Value 0 +#define IChapteredRowset_Value ATL_VARIANT_FALSE +#define IDBAsynchStatus_Value ATL_VARIANT_FALSE +#define IRowsetFind_Value ATL_VARIANT_FALSE +#define IRowsetView_Value ATL_VARIANT_FALSE +#define IViewChapter_Value ATL_VARIANT_FALSE +#define IViewFilter_Value ATL_VARIANT_FALSE +#define IViewRowset_Value ATL_VARIANT_FALSE +#define IViewSort_Value ATL_VARIANT_FALSE +#define INIT_ASYNCH_Value 0 +#define MAXOPENCHAPTERS_Value 0 +#define MAXORSINFILTER_Value 0 +#define MAXSORTCOLUMNS_Value 0 +#define ROWSET_ASYNCH_Value 0 +#define SORTONINDEX_Value ATL_VARIANT_FALSE +// 2.0 +#define IMultipleResults_Value ATL_VARIANT_FALSE +#define DATASOURCE_TYPE_Value 0 +//MDPROP +#define AXES_Value 0 +#define FLATTENING_SUPPORT_Value 0 +#define MDX_JOINCUBES_Value 0 +#define NAMED_LEVELS_Value 0 +//#define RANGEROWSET_Value 0 +#define MDX_SLICER_Value 0 +//#define MDX_CUBEQUALIFICATION_Value +#define MDX_OUTERREFERENCE_Value 0 +#define MDX_QUERYBYPROPERTY_Value ATL_VARIANT_FALSE +#define MDX_CASESUPPORT_Value 0 +#define MDX_STRING_COMPOP_Value 0 +#define MDX_DESCFLAGS_Value 0 +#define MDX_SET_FUNCTIONS_Value 0 +#define MDX_MEMBER_FUNCTIONS_Value 0 +#define MDX_NUMERIC_FUNCTIONS_Value 0 +#define MDX_FORMULAS_Value 0 +#define AGGREGATECELL_UPDATE_Value 0 +//#define MDX_AGGREGATECELL_UPDATE_Value +#define MDX_OBJQUALIFICATION_Value 0 +#define MDX_NONMEASURE_EXPRESSONS_Value 0 +// DBPROP +#define ACCESSORDER_Value 0 +#define BOOKMARKINFO_Value 0 +#define INIT_CATALOG_Value OLESTR("") +#define ROW_BULKOPS_Value 0 +#define PROVIDERFRIENDLYNAME_Value OLESTR("") +#define LOCKMODE_Value 0 +#define MULTIPLECONNECTIONS_Value ATL_VARIANT_FALSE +#define UNIQUEROWS_Value ATL_VARIANT_FALSE +#define SERVERDATAONINSERT_Value ATL_VARIANT_FALSE +//#define STORAGEFLAGS_Value +#define CONNECTIONSTATUS_Value 0 +#define ALTERCOLUMN_Value 0 +#define COLUMNLCID_Value 0 +#define RESETDATASOURCE_Value 0 +#define INIT_OLEDBSERVICES_Value 0 +#define IRowsetRefresh_Value ATL_VARIANT_FALSE +#define SERVERNAME_Value OLESTR("") +#define IParentRowset_Value ATL_VARIANT_FALSE +#define HIDDENCOLUMNS_Value 0 +#define PROVIDERMEMORY_Value ATL_VARIANT_FALSE +#define CLIENTCURSOR_Value ATL_VARIANT_FALSE +// 2.1 +#define TRUSTEE_USERNAME_Value OLESTR("") +#define TRUSTEE_AUTHENTICATION_Value OLESTR("") +#define TRUSTEE_NEWAUTHENTICATION_Value OLESTR("") +#define IRow_Value ATL_VARIANT_FALSE +#define IRowChange_Value ATL_VARIANT_FALSE +#define IRowSchemaChange_Value ATL_VARIANT_FALSE +#define IGetRow_Value ATL_VARIANT_FALSE +#define IScopedOperations_Value ATL_VARIANT_FALSE +#define IBindResource_Value ATL_VARIANT_FALSE +#define ICreateRow_Value ATL_VARIANT_FALSE +#define INIT_BINDFLAGS_Value 0 +#define INIT_LOCKOWNER_Value OLESTR("") +#define GENERATEURL_Value 0 +//#define IDBBinderProperties_Value +#define IColumnsInfo2_Value ATL_VARIANT_FALSE +//#define IRegisterProvider_Value +#define IGetSession_Value ATL_VARIANT_FALSE +#define IGetSourceRow_Value ATL_VARIANT_FALSE +#define IRowsetCurrentIndex_Value ATL_VARIANT_FALSE +#define OPENROWSETSUPPORT_Value 0 +#define COL_ISLONG_Value ATL_VARIANT_FALSE +// 2.5 +//#define COL_SEED_Value +//#define COL_INCREMENT_Value +#define INIT_GENERALTIMEOUT_Value 0 +#define COMSERVICES_Value 0 +// 2.6 +#define OUTPUTSTREAM_Value NULL +#define OUTPUTENCODING_Value NULL +#define TABLESTATISTICS_Value 0 +#define SKIPROWCOUNTRESULTS_Value ATL_VARIANT_FALSE +#define IRowsetBookmark_Value ATL_VARIANT_FALSE +#define VISUALMODE_Value MDPROPVAL_VISUAL_MODE_DEFAULT + + +#define OUT_OF_LINE virtual + +#define BEGIN_PROPSET_MAP(Class) \ +static ATL::UPROPSET* _GetPropSet(ULONG* pNumPropSets, ULONG* pcElemPerSupported, ATL::UPROPSET* pSet = NULL, GUID* pguidSet = NULL) \ +{ \ + typedef Class _PropSetClass; \ + USES_ATL_SAFE_ALLOCA;\ + ULONG& cElemsMax = *pcElemPerSupported; \ + cElemsMax = 0; \ + ULONG nCurProp = 0; \ + int cRemainder = 0; \ + if (pguidSet == NULL) \ + pguidSet = (GUID*)&GUID_NULL; + +#define BEGIN_PROPERTY_SET_EX(guid, flags) \ +if (pNumPropSets != NULL) \ +{ \ + pSet[nCurProp].pPropSet = &guid; \ + pSet[nCurProp].dwFlags = flags; \ + pSet[nCurProp].bIsChained = false; \ +} \ +static const ATL::UPROPINFO aProperty##guid[] = \ +{ + +#define BEGIN_PROPERTY_SET(guid) BEGIN_PROPERTY_SET_EX(guid, 0) + +//DBPROP_ macros + +#define PROPERTY_INFO_ENTRY_EX(dwPropID, vt, dwFlags, value, options) DBPROP_##dwPropID, IDS_DBPROP_##dwPropID, vt, dwFlags, (DWORD_PTR)value, (DBPROPOPTIONS)options, + +#define PROPERTY_INFO_ENTRY_VALUE(dwPropID, value) PROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, dwPropID##_Flags, value, 0) + +#define PROPERTY_INFO_ENTRY_VALUE_FLAGS(dwPropID, value, dwFlags) PROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, dwFlags, value, 0) + +#define PROPERTY_INFO_ENTRY(dwPropID) PROPERTY_INFO_ENTRY_VALUE(dwPropID, dwPropID##_Value) + + +//MDPROP_ macros + +#define MDPROPERTY_INFO_ENTRY_EX(dwPropID, vt, dwFlags, value, options) MDPROP_##dwPropID, IDS_MDPROP_##dwPropID, vt, dwFlags, (DWORD_PTR)value, (DBPROPOPTIONS)options, + +#define MDPROPERTY_INFO_ENTRY_VALUE(dwPropID, value) MDPROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, dwPropID##_Flags, value, 0) + +#define MDPROPERTY_INFO_ENTRY_VALUE_FLAGS(dwPropID, value, dwFlags) MDPROPERTY_INFO_ENTRY_EX(dwPropID, dwPropID##_Type, dwFlags, value, 0) + +#define MDPROPERTY_INFO_ENTRY(dwPropID) MDPROPERTY_INFO_ENTRY_VALUE(dwPropID, dwPropID##_Value) + + +#define END_PROPERTY_SET(guid) \ + }; \ + if (pNumPropSets != NULL) \ + { \ + pSet[nCurProp].pUPropInfo = (ATL::UPROPINFO*)aProperty##guid; \ + pSet[nCurProp].cUPropInfo = sizeof(aProperty##guid) / sizeof(ATL::UPROPINFO); \ + cRemainder = (pSet[nCurProp].cUPropInfo % 32) ? 1 : 0; \ + if (cElemsMax < (pSet[nCurProp].cUPropInfo / 32 + cRemainder)) \ + { \ + cElemsMax = (pSet[nCurProp].cUPropInfo / 32 + cRemainder); \ + } \ + } \ + nCurProp++; + +#define CHAIN_PROPERTY_SET(ChainClass) \ + ULONG cPropSets##ChainClass, cElsSupported##ChainClass; \ + int cSets##ChainClass = (int)(DWORD_PTR)ChainClass::_GetPropSet(NULL, &cElsSupported##ChainClass); \ + if (pNumPropSets != NULL) \ + { \ + ATL::UPROPSET* pSetA=(ATL::UPROPSET*)_ATL_SAFE_ALLOCA(::ATL::AtlMultiplyThrow(static_cast(sizeof(ATL::UPROPSET)),cSets##ChainClass),_ATL_SAFE_ALLOCA_DEF_THRESHOLD);\ + ATL::UPROPSET* pSetTemp = ChainClass::_GetPropSet(&cPropSets##ChainClass, &cElsSupported##ChainClass, pSetA); \ + cElemsMax = (cElemsMax < cElsSupported##ChainClass) ? cElsSupported##ChainClass : cElemsMax; \ + ATLENSURE(pSetTemp); \ + for (ULONG iSet = nCurProp; iSet < nCurProp+cPropSets##ChainClass; iSet++) \ + { \ + pSet[iSet].pPropSet = pSetTemp[iSet-nCurProp].pPropSet; \ + pSet[iSet].dwFlags = pSetTemp[iSet-nCurProp].dwFlags; \ + pSet[iSet].pUPropInfo = pSetTemp[iSet-nCurProp].pUPropInfo; \ + pSet[iSet].cUPropInfo = pSetTemp[iSet-nCurProp].cUPropInfo; \ + pSet[iSet].bIsChained = true; \ + } \ + } \ + nCurProp += cSets##ChainClass; + +#define END_PROPSET_MAP() \ + if (pNumPropSets != NULL) \ + { \ + if (IsEqualGUID(*pguidSet, GUID_NULL)) \ + { \ + *pNumPropSets = nCurProp; \ + return pSet; \ + } \ + else \ + { \ + *pNumPropSets = 1; \ + UINT i = 0; \ + for (; i < nCurProp && IsEqualGUID(*(pSet[i].pPropSet), *pguidSet); i++); \ + return (i == nCurProp ) ? &pSet[0] : &pSet[i]; \ + } \ + } \ + return (ATL::UPROPSET*)(DWORD_PTR)nCurProp; \ + } + + +// For DataSource flags IDBInitialize::m_dwStatus +enum DATASOURCE_FLAGS { + DSF_MASK_INIT = 0xFFFFF00F, // Mask for stuff lasting over init/uninit. + DSF_PERSIST_DIRTY = 0x00000001, // Set if init string changes. + DSF_INITIALIZED = 0x00000010, // Have we been initialized. +}; + + +#define DBID_USE_GUID_OR_PGUID(e) \ + ((1<<(e)) & \ + ( 1<> 5) // dw / 32 = dw / (sizeof(DWORD)*8) +#define ModDword(dw) (dw & (32-1)) // dw % 32 +#define DwordSizeofBits(nBits) (nBits/32+1) // Use in array declarations +#define CLEARBITARRAY( rgdwFlags ) memset( rgdwFlags, 0, sizeof(rgdwFlags) ) + +template +BOOL InRange(const T& val, const T& valMin, const T& valMax) +{ + return ( valMin <= val && val <= valMax ); +} +// Implementation Class +class CBitFieldOps +{ +public: + void SETBIT( DWORD rgdwFlags[], const DWORD dwBit ) + { + rgdwFlags[DivDword(dwBit)] |= 1 << ModDword(dwBit); + } + + void CLEARBIT( DWORD rgdwFlags[], const DWORD dwBit ) + { + rgdwFlags[DivDword(dwBit)] &= ~( 1 << ModDword(dwBit) ); + } + + DWORD TESTBIT( const DWORD rgdwFlags[], const DWORD dwBit ) + { + //old//Note: Not {0,1}, but from {0...2^32-1}. + // Note: Now returns {0,1}. + return ( rgdwFlags[DivDword(dwBit)] & ( 1 << ModDword(dwBit) ) ) != 0; + } +}; + +// Implementation Class +class CDBIDOps +{ +public: + HRESULT CompareDBIDs(const DBID* pdbid1, const DBID* pdbid2) + { + // Array of valid eKind matches, in addition to matching exactly. + static const BYTE s_rgbKind[] = + { + DBKIND_PGUID_NAME, // DBKIND_GUID_NAME + DBKIND_PGUID_PROPID, // DBKIND_GUID_PROPID + DBKIND_NAME, // DBKIND_NAME + DBKIND_GUID_NAME, // DBKIND_PGUID_NAME + DBKIND_GUID_PROPID, // DBKIND_PGUID_PROPID + DBKIND_PROPID, // DBKIND_PROPID + DBKIND_GUID // DBKIND_GUID + }; + + if( !pdbid1 || !pdbid2 ) + return S_FALSE; + + // Assume a match, and discard early if we can. + DBKIND tmp1 = 0; + DBKIND tmp2 = (DBKIND)(sizeof(s_rgbKind)/sizeof(*s_rgbKind) - 1); + if (!InRange(pdbid2->eKind, tmp1, tmp2)) + { + ATLTRACE(atlTraceDBProvider, 0, _T("Column ID out of Range\n")); + return E_FAIL; + } + if (pdbid1->eKind != pdbid2->eKind + && pdbid1->eKind != s_rgbKind[pdbid2->eKind]) + return S_FALSE; + + if (DBID_USE_GUID_OR_PGUID(pdbid1->eKind)) + { + if (!DBID_USE_GUID_OR_PGUID(pdbid2->eKind)) + return S_FALSE; + // Compare GUIDs. + // Note that _GUID_ is equivalent to _PGUID_. + if (!InlineIsEqualGUID( + DBID_USE_PGUID(pdbid1->eKind) ? *(pdbid1->uGuid.pguid) : pdbid1->uGuid.guid, + DBID_USE_PGUID(pdbid2->eKind) ? *(pdbid2->uGuid.pguid) : pdbid2->uGuid.guid )) + return S_FALSE; + } + if (DBID_USE_NAME(pdbid1->eKind)) + { + if (!DBID_USE_NAME(pdbid2->eKind)) + return S_FALSE; + // Compare names. + // Need to check if 1 is null and the other is not. + if ((pdbid1->uName.pwszName == NULL) != (pdbid2->uName.pwszName == NULL)) + return S_FALSE; + // Since the above check does not rule out both being null, which is + // a valid comparison, and wcscmp will GPF if they were, we need + // to check for valid pointers + if( pdbid1->uName.pwszName && pdbid2->uName.pwszName ) + { + // Assume null-terminated. + // Assume LCID match is OK (note diff with lstrcmp(), CompareString().) + if (wcscmp(pdbid1->uName.pwszName, pdbid2->uName.pwszName) != 0) + return S_FALSE; + } + } + if (DBID_USE_PROPID(pdbid1->eKind)) + { + if (!DBID_USE_PROPID(pdbid2->eKind)) + return S_FALSE; + // Compare PROPID. + if (pdbid1->uName.ulPropid != pdbid2->uName.ulPropid) + return S_FALSE; + } + + // No reason to discard, so must have matched each field successfully. + return S_OK; + } + + static HRESULT IsValidDBID(const DBID* pdbid1) + { + ATLASSERT( pdbid1 ); + + if( pdbid1 && + ((pdbid1->eKind == DBKIND_GUID_NAME) || + (pdbid1->eKind == DBKIND_GUID_PROPID) || + (pdbid1->eKind == DBKIND_NAME) || + (pdbid1->eKind == DBKIND_PGUID_NAME) || + (pdbid1->eKind == DBKIND_PGUID_PROPID) || + (pdbid1->eKind == DBKIND_PROPID) || + (pdbid1->eKind == DBKIND_GUID)) ) + return S_OK; + else + return S_FALSE; + } + HRESULT CopyDBIDs(DBID* pdbidDest, const DBID* pdbidSrc) + { + ULONG cwchBuffer; + + ATLASSERT( pdbidDest || pdbidSrc ); + + if( !pdbidDest || !pdbidSrc ) + return S_FALSE; + + // Save eKind + pdbidDest->eKind = pdbidSrc->eKind; + + switch( pdbidSrc->eKind ) + { + + case DBKIND_GUID_NAME: + pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid; + cwchBuffer = ocslen(pdbidSrc->uName.pwszName); + cwchBuffer++; + pdbidDest->uName.pwszName = (PWSTR)::ATL::AtlCoTaskMemCAlloc(cwchBuffer, static_cast(sizeof(WCHAR))); + if( pdbidDest->uName.pwszName ) + { + Checked::memcpy_s(pdbidDest->uName.pwszName, cwchBuffer * sizeof(WCHAR), pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR)); + } + else + { + return E_OUTOFMEMORY; + } + break; + + case DBKIND_GUID_PROPID: + pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid; + pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid; + break; + case DBKIND_NAME: + cwchBuffer = ocslen(pdbidSrc->uName.pwszName); + cwchBuffer++; + pdbidDest->uName.pwszName = (PWSTR)::ATL::AtlCoTaskMemCAlloc(cwchBuffer, static_cast(sizeof(WCHAR))); + if( pdbidDest->uName.pwszName ) + { + Checked::memcpy_s(pdbidDest->uName.pwszName, cwchBuffer*sizeof(WCHAR), pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR)); + } + else + { + return E_OUTOFMEMORY; + } + break; + case DBKIND_PGUID_NAME: + pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID)); + if( pdbidDest->uGuid.pguid ) + { + *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid); + cwchBuffer = ocslen(pdbidSrc->uName.pwszName); + cwchBuffer++; + pdbidDest->uName.pwszName = (PWSTR)::ATL::AtlCoTaskMemCAlloc(cwchBuffer, static_cast(sizeof(WCHAR))); + if( pdbidDest->uName.pwszName ) + { + Checked::memcpy_s(pdbidDest->uName.pwszName, cwchBuffer*sizeof(WCHAR), pdbidSrc->uName.pwszName, cwchBuffer*sizeof(WCHAR)); + break; + } + else + { + CoTaskMemFree(pdbidDest->uGuid.pguid); + pdbidDest->uGuid.pguid = NULL; + } + } + return E_OUTOFMEMORY; + case DBKIND_PGUID_PROPID: + pdbidDest->uGuid.pguid = (GUID*)CoTaskMemAlloc(sizeof(GUID)); + if( pdbidDest->uGuid.pguid ) + *(pdbidDest->uGuid.pguid) = *(pdbidSrc->uGuid.pguid); + else + return E_OUTOFMEMORY; + pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid; + break; + case DBKIND_PROPID: + pdbidDest->uName.ulPropid = pdbidSrc->uName.ulPropid; + break; + case DBKIND_GUID: + pdbidDest->uGuid.guid = pdbidSrc->uGuid.guid; + break; + default: + ATLASSERT(L"Unhandled dbid1.ekind"); + return S_FALSE; + } + + return S_OK; + } + static GUID* GetDBIDpGuid(DBID& dbid) + { + GUID* pGuid; + switch (dbid.eKind) + { + case DBKIND_PGUID_NAME: + case DBKIND_PGUID_PROPID: + pGuid = dbid.uGuid.pguid; + break; + case DBKIND_GUID_NAME: + case DBKIND_GUID_PROPID: + case DBKIND_GUID: + pGuid = &(dbid.uGuid.guid); + break; + default: + pGuid = NULL; + } + + return pGuid; + } + static ULONG GetPropIDFromDBID(DBID& dbid) + { + switch (dbid.eKind) + { + case DBKIND_GUID_PROPID: + case DBKIND_PGUID_PROPID: + case DBKIND_PROPID: + return dbid.uName.ulPropid; + default: + return 0; + } + } + void FreeDBIDs(DBID* pdbidSrc) + { + switch( pdbidSrc->eKind ) + { + + case DBKIND_GUID_NAME: + CoTaskMemFree(pdbidSrc->uName.pwszName); + break; + case DBKIND_NAME: + CoTaskMemFree(pdbidSrc->uName.pwszName); + break; + case DBKIND_PGUID_NAME: + CoTaskMemFree(pdbidSrc->uGuid.pguid); + CoTaskMemFree(pdbidSrc->uName.pwszName); + break; + case DBKIND_PGUID_PROPID: + CoTaskMemFree(pdbidSrc->uGuid.pguid); + break; + case DBKIND_GUID_PROPID: + case DBKIND_PROPID: + case DBKIND_GUID: + break; + default: + ATLASSERT(L"Unhandled dbid1.ekind"); + break; + } + } +}; + +class CConvertHelper +{ +public: + CConvertHelper() {} + HRESULT FinalConstruct() + { + HRESULT hr = ::CoCreateInstance(CLSID_OLEDB_CONVERSIONLIBRARY, NULL, + CLSCTX_INPROC_SERVER, __uuidof(IDataConvert), (void**)&m_spConvert); + + if (FAILED(hr)) + return hr; + + // Check to see if the data conversion routine is 2.0 capable, if so. Initialize + // the conversion routine to be 2.0. + DCINFO rgInfo[] = {{DCINFOTYPE_VERSION, {VT_UI4, 0, 0, 0, 0x0}}}; + CComPtr spIDCInfo; + + hr = m_spConvert->QueryInterface(&spIDCInfo); + if (hr == S_OK) + { + V_UI4(&rgInfo->vData) = 0x200; // OLEDB Version 02.00 + spIDCInfo->SetInfo(1, rgInfo); + } + + return hr; + } + CComPtr m_spConvert; +}; + +// IDBCreateSessionImpl +template +class ATL_NO_VTABLE IDBCreateSessionImpl : public IDBCreateSession +{ +public: + STDMETHOD(CreateSession)(IUnknown *pUnkOuter, + REFIID riid, + IUnknown **ppDBSession) + { + ATLTRACE(atlTraceDBProvider, 2, _T("IDBCreateSessionImpl::CreateSession\n")); + if (ppDBSession == NULL) + return E_INVALIDARG; + *ppDBSession = NULL; + T* pT = (T*)this; + if (!(pT->m_dwStatus & DSF_INITIALIZED)) + { + ATLTRACE(atlTraceDBProvider, 0, _T("IDBCreateSessionImpl::CreateSession : Error not initialized\n")); + *ppDBSession = NULL; + return E_UNEXPECTED; + } + CComPolyObject *pSession; + + // You can't QI for an interface other than IUnknown when aggregating + // and creating the object. You might ask for your own interface, + // which would be bad. Note, we return DB_E_NOAGGREGATION instead of + // CLASS_E_NOAGGREGATION due to OLE DB constraints. + if (pUnkOuter != NULL && !InlineIsEqualUnknown(riid)) + return DB_E_NOAGGREGATION; + + HRESULT hr = CComPolyObject::CreateInstance(pUnkOuter, &pSession); + if (SUCCEEDED(hr)) + { + CComPtr spCreator; + hr = pSession->QueryInterface(__uuidof(IObjectWithSite), (void**)&spCreator); + if (SUCCEEDED(hr)) + { + CComPtr spOuterUnk; + hr = pT->QueryInterface(__uuidof(IUnknown), (void**)&spOuterUnk); + if (SUCCEEDED(hr)) + { + hr = spCreator->SetSite(spOuterUnk); + if (SUCCEEDED(hr)) + { + hr = pSession->QueryInterface(riid, (void**)ppDBSession); + } + } + } + else + { + delete pSession; + } + } + return hr; + } +}; + +// IDBInitializeImpl +template +class ATL_NO_VTABLE IDBInitializeImpl : public IDBInitialize +{ +public: + IDBInitializeImpl() + { + m_dwStatus = 0; + m_pCUtlPropInfo = NULL; + m_cSessionsOpen = 0; + } + ~IDBInitializeImpl() + { + delete m_pCUtlPropInfo; + } + + STDMETHOD(Uninitialize)(void) + { + ATLTRACE(atlTraceDBProvider, 2, _T("IDBInitializeImpl::Uninitialize\n")); + T* pT = (T*)this; + T::ObjectLock lock(pT); + if (pT->m_cSessionsOpen != 0) + { + ATLTRACE(atlTraceDBProvider, 0, _T("Uninitialized called with Open Sessions\n")); + return DB_E_OBJECTOPEN; + } + delete m_pCUtlPropInfo; + m_pCUtlPropInfo = NULL; + pT->m_dwStatus |= DSF_PERSIST_DIRTY; + pT->m_dwStatus &= DSF_MASK_INIT; // Clear all non-init flags. + return S_OK; + + } + + DWORD m_dwStatus; + CUtlPropInfo* m_pCUtlPropInfo; + LONG m_cSessionsOpen; + + STDMETHOD(Initialize)(void) + { + + ATLTRACE(atlTraceDBProvider, 2, _T("IDBInitializeImpl::Initialize\n")); + T *pT = (T*)(this); + T::ObjectLock lock(pT); + HRESULT hr; + if (pT->m_dwStatus & DSF_INITIALIZED) + { + ATLTRACE(atlTraceDBProvider, 0, _T("IDBInitializeImpl::Initialize Error : Already Initialized\n")); + return DB_E_ALREADYINITIALIZED; + } + delete m_pCUtlPropInfo; + m_pCUtlPropInfo = NULL; + ATLTRY(m_pCUtlPropInfo = new CUtlPropInfo()) + if (m_pCUtlPropInfo == NULL) + { + ATLTRACE(atlTraceDBProvider, 0, _T("IDBInitializeImpl::Initialize Error : OOM\n")); + return E_OUTOFMEMORY; + } + hr = m_pCUtlPropInfo->FInit(); + if (hr == S_OK) + { + pT->m_dwStatus |= DSF_INITIALIZED; + } + else + { + delete m_pCUtlPropInfo; + m_pCUtlPropInfo = NULL; + } + return hr; + } + +}; + + +// Implementation Class + +class CPropColID : + public PROPCOLID, + public CDBIDOps +{ +public: + CPropColID() + { + VariantInit(&vValue); + } + ~CPropColID() + { + FreeDBIDs(&dbidProperty); + VariantClear(&vValue); + } + bool operator==(const CPropColID& colId) + { + return (CompareDBIDs(&dbidProperty, &(colId.dbidProperty)) == S_OK) ? true : false; + } + +}; + +class CColumnIds : + public CDBIDOps, + public CAtlArray + +{ +public: + PPROPCOLID AddNode() + { + CPropColID colID; + _ATLTRY + { + Add(colID); + } + _ATLCATCH( e ) + { + _ATLDELETEEXCEPTION( e ) + return NULL; + } + return &(GetAt(GetCount()-1)); + } + HRESULT RemoveColumnId(const DBID* pdbidProp) + { + for (size_t i = 0; i < GetCount(); i++) + { + if (CompareDBIDs(pdbidProp, &(GetAt(i).dbidProperty)) == S_OK) + { + if( i < 0 || i >= GetCount() ) + return E_FAIL; + RemoveAt(i); + return S_OK; + } + } + + return E_FAIL; + } + HRESULT AddColumnId(DBPROP* pProp) + { + CPropColID colID; + HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pProp->colid)); + if(FAILED(hr)) + return hr; + colID.dwOption = pProp->dwOptions; + hr = VariantCopy(&(colID.vValue),&(pProp->vValue)); + if(FAILED(hr)) + return hr; + //return (Add(colID)) ? S_OK : E_OUTOFMEMORY; + _ATLTRY + { + Add(colID); + } + _ATLCATCH( e ) + { + _ATLDELETEEXCEPTION( e ); + return E_OUTOFMEMORY; + } + return S_OK; + } + HRESULT AddColumnId(PPROPCOLID pPropNode) + { + CPropColID colID; + HRESULT hr = CopyDBIDs(&(colID.dbidProperty),&(pPropNode->dbidProperty)); + if(FAILED(hr)) + return hr; + colID.dwOption = pPropNode->dwOption; + hr = VariantCopy(&(colID.vValue),&(pPropNode->vValue)); + if(FAILED(hr)) + return hr; + //return (Add(colID)) ? S_OK : E_OUTOFMEMORY; + _ATLTRY + { + Add(colID); + } + _ATLCATCH( e ) + { + _ATLDELETEEXCEPTION( e ); + return E_OUTOFMEMORY; + } + return S_OK; + } + ULONG GetCountOfPropColids(){ return (ULONG)GetCount();} + PPROPCOLID FindColumnId(const DBID* pdbidProp) + { + for (size_t i = 0; i < GetCount(); i++) + { + if (CompareDBIDs(pdbidProp, &(GetAt(i).dbidProperty)) == S_OK) + return &(GetAt(i)); + } + + return NULL; + } + HRESULT GetValue(size_t iColId, DWORD* pdwOptions, DBID* pColid, VARIANT* pvValue) + { + HRESULT hr; + + ATLENSURE_RETURN(pdwOptions && pColid && pvValue); + ATLASSERT(iColId >= 0 && iColId < GetCount()); + + CPropColID& colId = GetAt(iColId); + *pdwOptions = colId.dwOption; + hr = CopyDBIDs( pColid, &(colId.dbidProperty) ); + if(FAILED(hr) || hr == S_FALSE) + { + return hr; + } + if(FAILED(hr = VariantCopy(pvValue, &(colId.vValue)))) + return hr; + return S_OK; + } +}; + +const ULONG cchDescBuffSize = 256; +const DWORD DBINTERNFLAGS_CHANGED = 0x00000001; +// Rules for GetPropertiesArgChk +const DWORD ARGCHK_PROPERTIESINERROR = 0x00000001; + +// Implementation Class +template +class CUtlPropInfo : public CBitFieldOps, public CDBIDOps +{ +public: + enum EnumGetPropInfo + { + GETPROPINFO_ALLPROPIDS = 0x0001, + GETPROPINFO_NOTSUPPORTED = 0x0002, + GETPROPINFO_ERRORSOCCURRED = 0x0004, + GETPROPINFO_VALIDPROP = 0x0008 + }; + + CUtlPropInfo() + { + m_cUPropSet = 0; + m_pUPropSet = NULL; + + m_cPropSetDex = 0; + + m_cElemPerSupported = 0; + } + ~CUtlPropInfo() + { + CoTaskMemFree(m_pUPropSet); + } + + //Determine the number of description buffers needed + ULONG CalcDescripBuffers(ULONG cPropInfoSet, DBPROPINFOSET* pPropInfoSet) + { + ULONG cBuffers = 0; + + ATLASSUME(m_pUPropSet); + ATLENSURE(cPropInfoSet && pPropInfoSet); + + for(ULONG ulSet=0; ulSet lock(m_oCriticalSection); + HRESULT hr; + + hr = InitAvailUPropSets(&m_cUPropSet, &m_pUPropSet, &m_cElemPerSupported, pguidSet); + if (FAILED(hr)) + return hr; + ATLASSERT((m_cUPropSet != 0) && (m_cElemPerSupported != 0)); + if(!m_cUPropSet || !m_cElemPerSupported) + return E_FAIL; + + m_rgdwSupported = NULL; + ATLTRY(m_rgdwSupported.Allocate(::ATL::AtlMultiplyThrow(m_cUPropSet, m_cElemPerSupported))); + if(m_rgdwSupported == NULL) + { + m_cUPropSet=0; + m_cElemPerSupported=0; + return E_OUTOFMEMORY; + } + + if(FAILED(hr = InitUPropSetsSupported())) + { + m_cUPropSet=0; + m_cElemPerSupported=0; + m_rgdwSupported.Free(); + return hr; + } + if(m_cUPropSet) + { + ATLTRY(m_rgiPropSetDex.Allocate(m_cUPropSet)) + if(m_rgiPropSetDex == NULL) + { + m_cUPropSet=0; + m_cElemPerSupported=0; + m_rgdwSupported.Free(); + return E_OUTOFMEMORY; + } + } + return S_OK; + } + HRESULT GetPropertyInfo(__in ULONG cPropertySets, + __in_ecount_opt(cPropertySets) const DBPROPIDSET rgPropertySets[], __out ULONG* pcPropertyInfoSets, + __deref_opt_out_ecount(*pcPropertyInfoSets) DBPROPINFOSET** prgPropertyInfoSets, + __deref_opt_out_opt WCHAR** ppDescBuffer, __in bool bInitialized = true, + __in_opt const GUID* pGuid = NULL) + { + CComCritSecLock lock(m_oCriticalSection); + HRESULT hr = S_OK; + ULONG ul, ulSet, ulNext, ulEnd; + ULONG ulOutIndex; + ULONG cSets; + ULONG cPropInfos; + //ULONG ulIndex = 0; + ULONG cBuffers = 0; + DWORD dwStatus = 0; + DBPROPINFO* pPropInfo = NULL; + DBPROPINFO* pCurPropInfo = NULL; + WCHAR* pDescBuffer = NULL; + WCHAR* pDescBufferEnd = NULL; + DBPROPINFOSET* pPropInfoSet = NULL; + UPROPINFO* pUPropInfo = NULL; + WCHAR wszBuff[256]; + int cch; + CAtlArray rgInitPropsetIndexes; + + // If the consumer does not restrict the property sets + // by specify an array of property sets and a cPropertySets + // greater than 0, then we need to make sure we + // have some to return + if(cPropertySets == 0) + { + // Determine the number of property sets supported + // In this case, it usually the enumerator or data source asking for + // DBPROPSET_DBINIT information. + + if (pGuid != NULL) + { + // Need to determine if there are any UPROPSET_USERINIT sets here + // they should be added to DBINIT. + ULONG ulUserInitSets = 0; + for (ULONG l=0; l(sizeof(DBPROPINFOSET))); + if(pPropInfoSet == NULL) + { + ATLTRACE(atlTraceDBProvider, 0, _T("Could not allocate DBPROPSET array for GetProperties\n")); + hr = E_OUTOFMEMORY; + goto EXIT; + } + + memset(pPropInfoSet, 0, cSets * sizeof(DBPROPINFOSET)); + + ulOutIndex = 0; + ULONG ulTempPropsetIndex = 0; + ulEnd = cPropertySets == 0 ? cSets : cPropertySets; + // Fill in the output array + for(ulSet=0; ulSet(sizeof(DBPROPINFO))); + if( pPropInfo ) + { + // Initialize Buffer + memset(pPropInfo, 0, cPropInfos * sizeof(DBPROPINFO)); + for(ULONG ulProp=0; ulProppwszDescription = pDescBuffer; + + // Load the string into temp buffer + cch = LoadDescription(pUPropInfo[ulProp].ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff))); + if( cch ) + { + // Adjust for '\0' + cch++; + + // Transfer to official buffer if room +#if _SECURE_ATL + if (pDescBuffer > pDescBufferEnd) + { + return E_FAIL; + } +#endif + Checked::memcpy_s(pDescBuffer, (pDescBufferEnd-pDescBuffer)*sizeof(WCHAR), wszBuff, cch * sizeof(WCHAR)); + pDescBuffer += cch; + } + else + { +#if _SECURE_ATL + if(pDescBuffer > pDescBufferEnd) + { + return E_FAIL; + } +#endif + Checked::wcscpy_s(pDescBuffer, pDescBufferEnd-pDescBuffer, L"UNKNOWN"); + pDescBuffer += (wcslen(L"UNKNOWN") + 1); + _ATLDUMPPROPERTY(pCurPropInfo->dwPropertyID, ATLDB_NO_STRING); + } + } + + pCurPropInfo->dwPropertyID = pUPropInfo[ulProp].dwPropId; + + // Strip out any user defined flags that may be around. Note, + // this isn't a full-proof thing because properties change. It + // won't work in OLE DB 2.5 if someone does a property like 0x40000 + DWORD dwFlags = pUPropInfo[ulProp].dwFlags & 0xfffff; + + pCurPropInfo->dwFlags = dwFlags; + pCurPropInfo->vtType = pUPropInfo[ulProp].VarType; + pCurPropInfo->vValues.vt = VT_EMPTY; + + dwStatus |= GETPROPINFO_VALIDPROP; + // Increment to next available buffer + ulNext++; + _ATLDUMPPROPERTY(pCurPropInfo->dwPropertyID, pCurPropInfo->dwFlags); + } + } + else + { + ATLASSUME( m_cPropSetDex == 1 ); + ULONG cIterations = ((cPropInfos>cBuffers) && (ppDescBuffer)) ? cBuffers : cPropInfos; + + for( ULONG ulProp = 0; ulProp < cIterations; ulProp++, ulNext++ ) + { + pCurPropInfo = &(pPropInfo[ulNext]); + + // Process Properties based on Restriction array. + pCurPropInfo->dwPropertyID = rgPropertySets[ulSet].rgPropertyIDs[ulProp]; + + if( GetUPropInfoPtr(m_rgiPropSetDex[ul], pCurPropInfo->dwPropertyID, &pUPropInfo) + == S_OK ) + { + // If the ppDescBuffer pointer was not NULL, then + // we need supply description of the properties + if( ppDescBuffer ) + { + // Set Buffer pointer + pCurPropInfo->pwszDescription = pDescBuffer; + + // Load the string into temp buffer + cch = LoadDescription(pUPropInfo->ulIDS, wszBuff, (sizeof(wszBuff)/sizeof(*wszBuff))); + if( cch ) + { + // Adjust for '\0' + cch++; + + // Transfer to official buffer if room +#if _SECURE_ATL + if(pDescBuffer > pDescBufferEnd) + return E_FAIL; +#endif + Checked::memcpy_s(pDescBuffer, (pDescBufferEnd-pDescBuffer)*sizeof(WCHAR), wszBuff, cch * sizeof(WCHAR)); + pDescBuffer += cch; + } + else + { +#if _SECURE_ATL + if(pDescBuffer > pDescBufferEnd) + { + return E_FAIL; + } +#endif + Checked::wcscpy_s(pDescBuffer, pDescBufferEnd-pDescBuffer, L"UNKNOWN"); + pDescBuffer += (wcslen(L"UNKNOWN") + 1); + _ATLDUMPPROPERTY(pCurPropInfo->dwPropertyID, ATLDB_NO_STRING); + } + } + + pCurPropInfo->dwPropertyID = pUPropInfo->dwPropId; + + // Strip out any user defined flags that may be around. Note, + // this isn't a full-proof thing because properties change. It + // won't work in OLE DB 2.5 if someone does a property like 0x40000 + DWORD dwFlags = pUPropInfo->dwFlags & 0xfffff; + + pCurPropInfo->dwFlags = dwFlags; + pCurPropInfo->vtType = pUPropInfo->VarType; + + dwStatus |= GETPROPINFO_VALIDPROP; + } + else + { + // Not Supported + pCurPropInfo->dwFlags = DBPROPFLAGS_NOTSUPPORTED; + dwStatus |= GETPROPINFO_ERRORSOCCURRED; + } + _ATLDUMPPROPERTY(pCurPropInfo->dwPropertyID, pCurPropInfo->dwFlags); + } + } + } + } + else + { + hr = E_OUTOFMEMORY; + goto EXIT; + } + +NEXT_SET: + pPropInfoSet[ulSet].cPropertyInfos = ulNext; + pPropInfoSet[ulSet].rgPropertyInfos = pPropInfo; + } + + // Success, set return values + *pcPropertyInfoSets = cSets; + *prgPropertyInfoSets = pPropInfoSet; + + // At least one propid was marked as not S_OK + if( dwStatus & GETPROPINFO_ERRORSOCCURRED ) + { + // If at least 1 property was set + if( dwStatus & GETPROPINFO_VALIDPROP ) + return DB_S_ERRORSOCCURRED; + else + { + // Do not free any of the rgPropertyInfoSets, but + // do free the ppDescBuffer + if( pDescBuffer ) + { + ATLASSERT( ppDescBuffer ); + CoTaskMemFree(pDescBuffer); + *ppDescBuffer = NULL; + } + return DB_E_ERRORSOCCURRED; + } + } + + return S_OK; +EXIT: + // Check if failure and clean up any allocated memory + if( FAILED(hr) && + (hr != DB_E_ERRORSOCCURRED) ) + { + // Free Description Buffer + if( pDescBuffer ) + { + ATLASSERT( ppDescBuffer ); + + CoTaskMemFree(pDescBuffer); + *ppDescBuffer = NULL; + } + + if( pPropInfoSet ) + { + // Loop through Property Sets + for(ulSet=0; ulSet m_rgiPropSetDex;//array of UPropSet Index values + ULONG m_cElemPerSupported; //number of DWORDS per UPropSet to indicate supported UPropIds + CAutoVectorPtr m_rgdwSupported;//array of DWORDs indicating supported UPropIds + + enum EnumUPropSetFlags + { + UPROPSET_HIDDEN = 0x1, + UPROPSET_PASSTHROUGH = 0x2, + UPROPSET_USERINIT = 0x4 + }; + + HRESULT InitAvailUPropSets(ULONG* pcUPropSet, UPROPSET** ppUPropSet, ULONG* pcElemPerSupported, GUID* pguid) + { + ATLENSURE_RETURN(pcUPropSet && ppUPropSet); + CoTaskMemFree(*ppUPropSet); + *ppUPropSet = NULL; + int cSets = (int)(ULONG_PTR)T::_GetPropSet(NULL, pcElemPerSupported); + UPROPSET* pSet = (UPROPSET*)::ATL::AtlCoTaskMemCAlloc(static_cast(sizeof(UPROPSET)), cSets); + if (pSet == NULL) + { + *pcUPropSet=0; + *ppUPropSet=NULL; + *pcElemPerSupported=0; + return E_OUTOFMEMORY; + } + *ppUPropSet = T::_GetPropSet(pcUPropSet, pcElemPerSupported, pSet, pguid); + return S_OK; + } + OUT_OF_LINE HRESULT InitUPropSetsSupported() + { + ULONG cPropSet = 0, cElemsPerSupported = 0; + int cSets = (int)(ULONG_PTR)T::_GetPropSet(NULL, &cElemsPerSupported); + UPROPSET* pSet = (UPROPSET*)::ATL::AtlCoTaskMemCAlloc(static_cast(sizeof(UPROPSET)), cSets); + if (pSet == NULL) + return E_OUTOFMEMORY; + pSet = T::_GetPropSet(&cPropSet, &cElemsPerSupported, pSet); + memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD)); + CoTaskMemFree(pSet); + return S_OK; + } + //Load a localized description + int LoadDescription(__in ULONG ids, __out_ecount_part_z(nLen, return + 1) PWSTR pwszBuff, __in ULONG cchBuff) + { + USES_CONVERSION_EX; + CTempBuffer tmpBuffer; + TCHAR* pszBuf = tmpBuffer.Allocate(cchBuff); + if (pszBuf == NULL) + return 0; + int nTemp = LoadString(_AtlBaseModule.GetResourceInstance(), ids, pszBuf, cchBuff); + if (nTemp != 0) + { + Checked::wcscpy_s(pwszBuff, cchBuff, T2W_EX_DEF(pszBuf)); + } + return nTemp; + } +}; + +class ATL_NO_VTABLE CUtlPropsBase : public CBitFieldOps, public CDBIDOps +{ +public: + + CComAutoCriticalSection m_oCriticalSection; // critical section to synchronize access to the class + ULONG m_cUPropSet; //count of UPropSet items + UPROPSET* m_pUPropSet; //Pointer to UPropset items + CAutoVectorPtr< UPROP > m_pUProp; + ULONG m_cUPropSetHidden; //Count of Hidden items + DWORD m_dwFlags; //Configuration flags + ULONG m_cPropSetDex; //count of UPropSet Indexes + CAutoVectorPtr< ULONG > m_rgiPropSetDex; //pointer to Array of UPropSet Index values + ULONG m_cElemPerSupported;//number of DWORDS per UPropSet to indicate supported UPropIds + CAutoVectorPtr< DWORD > m_rgdwSupported; //pointer to array of DWORDs indicating supported UPropIds + CAutoVectorPtr< DWORD > m_rgdwPropsInError;//pointer to array of DWORDs indicating if property is in error + + enum EnumUPropSetFlags + { + UPROPSET_HIDDEN = 0x1, + UPROPSET_PASSTHROUGH = 0x2, + UPROPSET_USERINIT = 0x4 + }; + enum EnumGetProp + { + GETPROP_ALLPROPIDS = 0x0001, + GETPROP_NOTSUPPORTED = 0x0002, + GETPROP_ERRORSOCCURRED = 0x0004, + GETPROP_VALIDPROP = 0x0008, + GETPROP_PROPSINERROR = 0x0010 + }; + + enum EnumSetProp + { + SETPROP_BADOPTION = 0x0001, + SETPROP_NOTSUPPORTED = 0x0002, + SETPROP_VALIDPROP = 0x0004, + SETPROP_ERRORS = 0x0008, + SETPROP_COLUMN_LEVEL = 0x0010, + SETPROP_WAS_REQUIRED = 0x0020 + }; + + HRESULT SetPassThrough(const DBPROPSET* pPropSet) + { + ATLENSURE_RETURN(pPropSet); + + DBPROP* pProp = pPropSet->rgProperties; + + //Default implementation just sets all properties as NOTSUPPORTED + for( ULONG ul=0; ulcProperties; ul++, pProp++ ) + pProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED; + + return DB_E_ERRORSOCCURRED; + } + + HRESULT GetIndexofPropIdinPropSet(ULONG iCurSet, DBPROPID dwPropertyId, ULONG* piCurPropId) + { + ATLENSURE_RETURN(piCurPropId); + UPROPINFO* pUPropInfo = m_pUPropSet[iCurSet].pUPropInfo; + for(ULONG ul=0; ulvValue; + if (var.vt == VT_BOOL) + { + if (var.boolVal != ATL_VARIANT_TRUE && var.boolVal != ATL_VARIANT_FALSE) + return S_FALSE; + } + + return S_OK; + } + + virtual HRESULT OnInterfaceRequested(REFIID riid) + { + // This function exists as part of the change in the OLE DB spec. If + // a consumer opens an object and requests an optional interface, the + // provider should automatically set the property representating that + // interface to true. + CDBPropSet propset(DBPROPSET_ROWSET); + const GUID* ppGuid[1]; + ppGuid[0] = &DBPROPSET_ROWSET; + + if (InlineIsEqualGUID(riid, __uuidof(IRowsetChange))) + { + if(!propset.AddProperty(DBPROP_IRowsetChange, true)) + { + return E_FAIL; + } + } + else if (InlineIsEqualGUID(riid, __uuidof(IRowsetUpdate))) + { + if(!propset.AddProperty(DBPROP_IRowsetUpdate, true)) + { + return E_FAIL; + } + } + else if (InlineIsEqualGUID(riid, __uuidof(IRowsetLocate))) + { + if(!propset.AddProperty(DBPROP_IRowsetLocate, true)) + { + return E_FAIL; + } + } + else if (InlineIsEqualGUID(riid, __uuidof(IConnectionPointContainer))) + { + if(!propset.AddProperty(DBPROP_IConnectionPointContainer, true)) + { + return E_FAIL; + } + } + else if (InlineIsEqualGUID(riid, __uuidof(IRowsetScroll))) + { + if(!propset.AddProperty(DBPROP_IRowsetScroll, true)) + { + return E_FAIL; + } + } + + if (propset.cProperties > 0) + return SetProperties(0, 1, &propset, 1, ppGuid); + + return S_OK; + } + + virtual HRESULT OnPropertyChanged(ULONG /*iCurSet*/, DBPROP* /*pDBProp*/) = 0; + +#pragma warning(push) +#pragma warning(disable: 6014) + /* prefast noise VSW 498981 */ + HRESULT SetProperty(ULONG iCurSet, ULONG iCurProp, DBPROP* pDBProp) + { + HRESULT hr = S_OK; + UPROP* pUProp; + UPROPVAL* pUPropVal; + UPROPINFO* pUPropInfo; + ULONG iUProp; + + ATLENSURE_RETURN( pDBProp ); + + // Set pointer to correct set + pUProp = &(m_pUProp[iCurSet]); + ATLENSURE_RETURN( pUProp ); + + pUPropInfo = &(m_pUPropSet[iCurSet].pUPropInfo[iCurProp]); + ATLENSURE_RETURN( pUPropInfo ); + + // Determine the index within m_pUProp + for(iUProp=0; iUPropcPropIds; iUProp++) + { + if( (pUProp->rgpUPropInfo[iUProp])->dwPropId == pDBProp->dwPropertyID ) + break; + } + + if( iUProp >= pUProp->cPropIds ) + { + ATLASSERT( !"Should have found index of property to set" ); + hr = E_FAIL; + pDBProp->dwStatus = DBPROPSTATUS_NOTSUPPORTED; + goto EXIT; + } + + //Get the UPROPVAL node pointer within that propset. + pUPropVal = &(pUProp->pUPropVal[iUProp]); + ATLENSURE_RETURN( pUPropVal ); + + // Handle VT_EMPTY, which indicates to the provider to + // reset this property to the providers default + if( pDBProp->vValue.vt == VT_EMPTY ) + { + if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) + { + // Remove any nodes, because the default applies to + // all columns + delete pUPropVal->pCColumnIds; + pUPropVal->pCColumnIds = NULL; + } + + // Should clear here, since previous values may already + // have been cached and need to be replaced. + VariantClear(&(pUPropVal->vValue)); + + pUPropVal->dwFlags &= ~DBINTERNFLAGS_CHANGED; + hr = GetDefaultValue(iCurSet, pDBProp->dwPropertyID, + &(pUPropVal->dwOption), &(pUPropVal->vValue)); + + goto EXIT; + } + + + // Column Level + if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) + { + // Check to see if it applies to all + if( (CompareDBIDs(&(pDBProp->colid), &DB_NULLID) == S_OK) ) + { + // Remove the Columns Storage object + delete pUPropVal->pCColumnIds; + pUPropVal->pCColumnIds = NULL; + pUPropVal->dwOption = pDBProp->dwOptions; + if( FAILED(hr = VariantCopy(&(pUPropVal->vValue), + &(pDBProp->vValue))) ) + goto EXIT; + pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED; + } + else // Does not apply to all columns + { + if( pUPropVal->pCColumnIds == NULL ) + { + ATLTRY(pUPropVal->pCColumnIds = new CColumnIds) + } + + if( pUPropVal->pCColumnIds ) + { + if( FAILED(hr = (pUPropVal->pCColumnIds)->AddColumnId(pDBProp)) ) + goto EXIT; + pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED; + } + else + { + hr = E_OUTOFMEMORY; + goto EXIT; + } + + } + } + else + { + // Set for non-column level properties + pUPropVal->dwOption = pDBProp->dwOptions; + + // Our provider has no limit on the maximum number of rows + // that can have pending changes, therefore the value of the + // DBPROP_MAXPENDINGROWS property will always be zero (default), + // regardless of what the user attempts to set it to. + // In the code below, we modify the property value only if + // this is not the DBPROP_MAXPENDINGROWS property. + if( pDBProp->dwPropertyID != DBPROP_MAXPENDINGROWS ) + { + if( FAILED(hr = VariantCopy(&(pUPropVal->vValue), + &(pDBProp->vValue))) ) + goto EXIT; + } + if( FAILED(hr = OnPropertyChanged(iCurSet, pDBProp))) + goto EXIT; + pUPropVal->dwFlags |= DBINTERNFLAGS_CHANGED; + } + +EXIT: + if( hr == S_OK ) + pDBProp->dwStatus = DBPROPSTATUS_OK; + + return hr; + } +#pragma warning(pop) + + HRESULT SetProperties(const DWORD /*dwStatus*/, const ULONG cPropertySets, + const DBPROPSET rgPropertySets[], const ULONG cSelectProps = 1, + const GUID* const ppGuid[] = NULL, bool bIsCreating = false) + { + DWORD dwState = 0; + ULONG ulCurSet, ulCurProp, ulProp; + DBPROP* rgDBProp; + UPROPINFO* pUPropInfo; + CComVariant vDefaultValue; + DWORD dwOption; + + CComCritSecLock lock(m_oCriticalSection); + + // ppGuid specifies the property sets that the consumer can set based + // on the interface that called this function. + ATLENSURE_RETURN(ppGuid != NULL); + + if ((cPropertySets != 0) && (rgPropertySets == NULL)) + return E_INVALIDARG; + + // Process property sets + for(ULONG ulSet=0; ulSetdwFlags & DBPROPFLAGS_WRITE) == 0 ) + { + rgDBProp[ulProp].dwStatus = DBPROPSTATUS_OK; + + vDefaultValue.Clear(); + + // VT_EMPTY against a read only property should be a no-op since + // the VT_EMPTY means the default. + if( V_VT(&rgDBProp[ulProp].vValue) == VT_EMPTY ) + { + dwState |= SETPROP_VALIDPROP; + continue; + } + + if( SUCCEEDED(GetDefaultValue(ulCurSet, rgDBProp[ulProp].dwPropertyID, + &dwOption, &(vDefaultValue))) ) + { + if( V_VT(&rgDBProp[ulProp].vValue) == V_VT(&vDefaultValue) ) + { + switch( V_VT(&vDefaultValue) ) + { + case VT_BOOL: + if( V_BOOL(&rgDBProp[ulProp].vValue) == V_BOOL(&vDefaultValue) ) + { + dwState |= SETPROP_VALIDPROP; + continue; + } + break; + case VT_I2: + if( V_I2(&rgDBProp[ulProp].vValue) == V_I2(&vDefaultValue) ) + { + dwState |= SETPROP_VALIDPROP; + continue; + } + break; + case VT_I4: + if( V_I4(&rgDBProp[ulProp].vValue) == V_I4(&vDefaultValue) ) + { + dwState |= SETPROP_VALIDPROP; + continue; + } + break; + case VT_BSTR: + if( wcscmp(V_BSTR(&rgDBProp[ulProp].vValue), V_BSTR(&vDefaultValue)) == 0 ) + { + dwState |= SETPROP_VALIDPROP; + continue; + } + break; + } + } + } + + dwState |= SETPROP_ERRORS; + dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; + rgDBProp[ulProp].dwStatus = (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_OPTIONAL) ? DBPROPSTATUS_NOTSET : DBPROPSTATUS_NOTSETTABLE; + _ATLDUMPPROPERTY(rgDBProp[ulProp].dwPropertyID, rgDBProp[ulProp].dwStatus); + continue; + } + + // Check that the property is being set with the correct VARTYPE + if( (rgDBProp[ulProp].vValue.vt != pUPropInfo->VarType) && + (rgDBProp[ulProp].vValue.vt != VT_EMPTY) ) + { + dwState |= SETPROP_ERRORS; + dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; + rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE; + _ATLDUMPPROPERTY(rgDBProp[ulProp].dwPropertyID, rgDBProp[ulProp].dwStatus); + continue; + } + + // Check that the value is legal + if( (rgDBProp[ulProp].vValue.vt != VT_EMPTY) && + IsValidValue(ulCurSet, &(rgDBProp[ulProp])) == S_FALSE ) + { + dwState |= SETPROP_ERRORS; + dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; + rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADVALUE; + _ATLDUMPPROPERTY(rgDBProp[ulProp].dwPropertyID, rgDBProp[ulProp].dwStatus); + continue; + } + + + // Check for a bad COLID, we only catch bad DBIDs + if( pUPropInfo->dwFlags & DBPROPFLAGS_COLUMNOK ) + { + if( CDBIDOps::IsValidDBID(&(rgDBProp[ulProp].colid)) == S_FALSE ) + { + dwState |= SETPROP_ERRORS; + dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; + rgDBProp[ulProp].dwStatus = DBPROPSTATUS_BADCOLUMN; + _ATLDUMPPROPERTY(rgDBProp[ulProp].dwPropertyID, rgDBProp[ulProp].dwStatus); + continue; + } + dwState |= SETPROP_COLUMN_LEVEL; + + } + + if(SetProperty(ulCurSet, ulCurProp, /*pUPropInfo,*/ &(rgDBProp[ulProp])) == S_OK) + { + dwState |= SETPROP_VALIDPROP; + } + else + { + dwState |= SETPROP_ERRORS; + dwState |= (rgDBProp[ulProp].dwOptions == DBPROPOPTIONS_REQUIRED) ? SETPROP_WAS_REQUIRED : 0; + } + _ATLDUMPPROPERTY(rgDBProp[ulProp].dwPropertyID, rgDBProp[ulProp].dwStatus); + } + } + + vDefaultValue.Clear(); + + // At least one propid was marked as not S_OK + if( dwState & SETPROP_ERRORS ) + { + if (!bIsCreating) + { + return (dwState & SETPROP_VALIDPROP) ? DB_S_ERRORSOCCURRED : DB_E_ERRORSOCCURRED; + } + else + { + return (dwState & SETPROP_WAS_REQUIRED) ? DB_E_ERRORSOCCURRED : DB_S_ERRORSOCCURRED; + } + } + + return S_OK; + } + + OUT_OF_LINE HRESULT CopyUPropVal(ULONG iPropSet, UPROPVAL* rgUPropVal) + { + HRESULT hr = S_OK; + UPROP* pUProp; + UPROPVAL* pUPropVal; + DBPROP dbProp; + + ATLENSURE_RETURN(rgUPropVal); + ATLASSERT(iPropSet < m_cUPropSet); + + VariantInit(&dbProp.vValue); + + pUProp = &(m_pUProp[iPropSet]); + for(ULONG ul=0; ulcPropIds; ul++) + { + pUPropVal = &(pUProp->pUPropVal[ul]); + + // Transfer dwOptions + rgUPropVal[ul].dwOption = pUPropVal->dwOption; + + // Transfer Flags + rgUPropVal[ul].dwFlags = pUPropVal->dwFlags; + + // Transfer Column Properties + if( pUPropVal->pCColumnIds ) + { + ATLTRY(rgUPropVal[ul].pCColumnIds = new CColumnIds) + if( rgUPropVal[ul].pCColumnIds ) + { + CColumnIds* pColIds = pUPropVal->pCColumnIds; + for (size_t i = 0; i < pColIds->GetCount(); i++) + { + hr = (pUPropVal->pCColumnIds)->GetValue(i, &(dbProp.dwOptions),&(dbProp.colid), &(dbProp.vValue)); + if( FAILED(hr) ) + goto EXIT; + if( FAILED(hr = (rgUPropVal[ul].pCColumnIds)->AddColumnId(&dbProp)) ) + goto EXIT; + } + } + else + { + hr = E_OUTOFMEMORY; + goto EXIT; + } + } + else + { + rgUPropVal[ul].pCColumnIds = NULL; + } + + // Transfer value + VariantInit(&(rgUPropVal[ul].vValue)); + if( FAILED(hr = VariantCopy(&(rgUPropVal[ul].vValue), + &(pUPropVal->vValue))) ) + goto EXIT; + } + +EXIT: + VariantClear(&(dbProp.vValue)); + return hr; + } + void ClearPropertyInError() + { + ATLASSUME( m_rgdwPropsInError ); + memset(m_rgdwPropsInError, 0, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); + } + + void CopyUPropSetsSupported(DWORD* rgdwSupported) + { + Checked::memcpy_s(rgdwSupported, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD), + m_rgdwSupported, m_cUPropSet * m_cElemPerSupported * sizeof(DWORD)); + } + + virtual HRESULT InitUPropSetsSupported() = 0; + + virtual HRESULT GetIndexofPropSet(const GUID* pPropSet, ULONG* pulCurSet) = 0; + + ULONG GetCountofWritablePropsInPropSet(ULONG iPropSet) + { + ULONG cWritable = 0; + UPROPINFO* pUPropInfo; + + ATLENSURE( m_pUPropSet ); + ATLASSERT( iPropSet < m_cUPropSet ); + + pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo; + + for(ULONG ul=0; ul(sizeof(UPROPSET)), cSets); + if (pPropSet == NULL) + return E_OUTOFMEMORY; + pPropSet = (*pfnGetSet)(&cPropSet, &cElemsPerSupported, pPropSet, (GUID*)&GUID_NULL); + memset(m_rgdwSupported, 0xFFFF, cPropSet * cElemsPerSupported * sizeof(DWORD)); + CoTaskMemFree(pPropSet); + return S_OK; + } + + HRESULT InternalGetDefaultValue(PGetPropSet pfnGetSet, ULONG iPropSet, DBPROPID dwPropId, DWORD* pdwOption, VARIANT* pVar) + { + if (pdwOption == NULL || pVar == NULL) + return E_INVALIDARG; + + ULONG cUPropSet = 0, cElemPerSupported =0; + + int cSets = (int)(DWORD_PTR)(*pfnGetSet)(NULL, &cElemPerSupported, NULL, (GUID*)&GUID_NULL); + UPROPSET* pPropSet = (UPROPSET*)::ATL::AtlCoTaskMemCAlloc(static_cast(sizeof(UPROPSET)), cSets); + if (pPropSet == NULL) + return E_OUTOFMEMORY; + pPropSet = (*pfnGetSet)(&cUPropSet, &cElemPerSupported, pPropSet, (GUID*)&GUID_NULL); + + ATLASSERT(iPropSet < cUPropSet); + for (ULONG iProp = 0; iProp < pPropSet[iPropSet].cUPropInfo; iProp++) + { + UPROPINFO& rInfo = pPropSet[iPropSet].pUPropInfo[iProp]; + if (rInfo.dwPropId == dwPropId) + { + HRESULT hr = S_OK; + pVar->vt = rInfo.VarType; + *pdwOption = rInfo.dwOption; + switch(rInfo.VarType) + { + case VT_BSTR: + pVar->bstrVal = SysAllocString(rInfo.szVal); + if (pVar->bstrVal == NULL && rInfo.szVal != NULL) + hr = E_OUTOFMEMORY; + break; + default: + pVar->lVal = (DWORD)rInfo.dwVal; + break; + } + CoTaskMemFree(pPropSet); + return hr; + } + } + CoTaskMemFree(pPropSet); + return E_FAIL; + } + + HRESULT InternalFInit(PGetPropSet pfnGetSet, CUtlPropsBase* pCopyMe = NULL) + { + HRESULT hr; + ULONG ulPropId; + ULONG cPropIds; + ULONG iPropSet; + ULONG iNewDex; + UPROPINFO* pUPropInfo; + + // If a pointer is passed in, we should copy that property object + if( pCopyMe ) + { + // Establish some base values + m_cUPropSet = pCopyMe->m_cUPropSet; + CoTaskMemFree(m_pUPropSet); + m_pUPropSet = NULL; + m_pUPropSet = (UPROPSET*)::ATL::AtlCoTaskMemCAlloc(static_cast(sizeof(UPROPSET)), m_cUPropSet); + if (m_pUPropSet == NULL) + { + m_cUPropSet = 0; + m_cElemPerSupported = 0; + return E_OUTOFMEMORY; + } + Checked::memcpy_s(m_pUPropSet, sizeof(UPROPSET) * m_cUPropSet, pCopyMe->m_pUPropSet, sizeof(UPROPSET) * m_cUPropSet); + m_cElemPerSupported = pCopyMe->m_cElemPerSupported; + ATLENSURE_RETURN( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) ); + // Retrieve Supported Bitmask + m_rgdwSupported = NULL; + m_rgdwPropsInError = NULL; + ATLTRY(m_rgdwSupported.Allocate(::ATL::AtlMultiplyThrow(m_cUPropSet, m_cElemPerSupported))); + ATLTRY(m_rgdwPropsInError.Allocate(::ATL::AtlMultiplyThrow(m_cUPropSet, m_cElemPerSupported))); + if( m_rgdwSupported == NULL|| m_rgdwPropsInError == NULL) + { + + m_cUPropSet = 0; + m_cElemPerSupported = 0; + m_rgdwSupported.Free(); + m_rgdwPropsInError.Free(); + CoTaskMemFree(m_pUPropSet); + m_pUPropSet = NULL; + return E_OUTOFMEMORY; + } + ClearPropertyInError(); + pCopyMe->CopyUPropSetsSupported(m_rgdwSupported); + + } + else + { + int cSets = (int)(DWORD_PTR)(*pfnGetSet)(NULL, &m_cElemPerSupported, NULL, (GUID*)&GUID_NULL); + UPROPSET* pSet = (UPROPSET*)::ATL::AtlCoTaskMemCAlloc(static_cast(sizeof(UPROPSET)), cSets); + if (pSet == NULL) + return E_OUTOFMEMORY; + pSet = (*pfnGetSet)(&m_cUPropSet, &m_cElemPerSupported, pSet, (GUID*)&GUID_NULL); + CoTaskMemFree(m_pUPropSet); + m_pUPropSet = pSet; + ATLASSERT( (m_cUPropSet != 0) && (m_cElemPerSupported != 0) ); + if( !m_cUPropSet || !m_cElemPerSupported ) + { + return E_FAIL; + } + + + m_rgdwSupported = NULL; + m_rgdwPropsInError = NULL; + ATLTRY(m_rgdwSupported.Allocate(::ATL::AtlMultiplyThrow(m_cUPropSet, m_cElemPerSupported))); + ATLTRY(m_rgdwPropsInError.Allocate(::ATL::AtlMultiplyThrow(m_cUPropSet, m_cElemPerSupported))); + if( m_rgdwSupported == NULL || m_rgdwPropsInError == NULL) + { + m_cUPropSet = 0; + m_cElemPerSupported = 0; + m_rgdwSupported.Free(); + m_rgdwPropsInError.Free(); + CoTaskMemFree(m_pUPropSet); + m_pUPropSet = NULL; + return E_OUTOFMEMORY; + } + else + ClearPropertyInError(); + + if( FAILED(hr = InitUPropSetsSupported()) ) + { + m_rgdwSupported.Free(); + return hr; + } + } + + // Allocate UPROPS structures for the count of Property sets + ATLTRY(m_pUProp.Allocate(m_cUPropSet)); + if( m_pUProp) + { + memset(m_pUProp, 0, m_cUPropSet * sizeof(UPROP)); + } + else + { + m_cUPropSet = 0; + return E_OUTOFMEMORY; + } + + // With in the UPROPS Structure allocate and intialize the + // Property IDs that belong to this property set. + for(iPropSet=0; iPropSet 0 ) + { + CAutoVectorPtr< UPROPINFO* > rgpUPropInfo; + CAutoVectorPtr< UPROPVAL > rgUPropVal; + + rgpUPropInfo.Allocate( cPropIds ); + rgUPropVal.Allocate( cPropIds ); + if ( (rgpUPropInfo == NULL) || (rgUPropVal == NULL) ) + { + return E_OUTOFMEMORY; + } + if( pCopyMe ) + { + pCopyMe->CopyUPropInfo(iPropSet, rgpUPropInfo); + if( FAILED(hr = pCopyMe->CopyUPropVal(iPropSet, rgUPropVal)) ) + { + m_cUPropSet = 0; + m_cElemPerSupported = 0; + m_rgdwSupported.Free(); + m_rgdwPropsInError.Free(); + CoTaskMemFree(m_pUPropSet); + m_pUPropSet = NULL; + return hr; + } + } + else + { + // Clear Pointer Array + memset(rgpUPropInfo, 0, cPropIds * sizeof(UPROPINFO*)); + + // Set Pointer to correct property ids with a property set + pUPropInfo = m_pUPropSet[iPropSet].pUPropInfo; + + // Set up the writable property buffers + iNewDex = 0; + for(ulPropId=0; ulPropId