TimeOfDay.h
class CTimeOfDay : public ITimeOfDay
{
public:
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
// ITimeOfDay
STDMETHOD(GetDateString)(/*[out, retval]*/ BSTR *pVal);
STDMETHOD(GetTimeString)(/*[out, retval]*/ BSTR *pVal);
CTimeOfDay();
~CTimeOfDay();
private:
long m_lRefCount;
};
TimeOfDay.cpp
#include "stdafx.h"
#include "TimeSvr.h"
#include "TimeOfDay.h"
extern long g_lObjCount;
CTimeOfDay::CTimeOfDay()
: m_lRefCount(1)
{
InterlockedIncrement(&g_lObjCount);
}
CTimeOfDay::~CTimeOfDay()
{
InterlockedDecrement(&g_lObjCount);
}
STDMETHODIMP CTimeOfDay::QueryInterface(const IID& iid, void** ppv)
{
if ((iid == IID_IUnknown) || (iid == IID_ITimeOfDay))
{
*ppv = static_cast<ITimeOfDay*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK ;
}
STDMETHODIMP_(ULONG) CTimeOfDay::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(ULONG) CTimeOfDay::Release()
{
if (InterlockedDecrement(&m_lRefCount) == 0)
{
delete this;
return 0;
}
return m_lRefCount;
}
STDMETHODIMP CTimeOfDay::GetTimeString(BSTR* pVal)
{
int nSize = GetTimeFormat(NULL, 0, NULL, NULL, NULL, 0);
TCHAR* sTimeBuffer = new TCHAR[nSize];
GetTimeFormat(NULL, 0, NULL, NULL, sTimeBuffer, nSize);
*pVal = _bstr_t(sTimeBuffer).copy();
delete [] sTimeBuffer;
return S_OK;
}
STDMETHODIMP CTimeOfDay::GetDateString(BSTR* pVal)
{
int nSize = GetDateFormat(NULL, DATE_LONGDATE, NULL, NULL, NULL, 0);
TCHAR* sDateBuffer = new TCHAR[nSize];
GetDateFormat(NULL, DATE_LONGDATE, NULL, NULL, sDateBuffer, nSize);
*pVal = _bstr_t(sDateBuffer).copy();
delete [] sDateBuffer;
return S_OK;
}
Factory.cpp
#include "stdafx.h"
#include "TimeSvr.h"
#include "TimeOfDay.h"
#include "Factory.h"
long CTimeSvrFactory::m_lLockCount = 0;
STDMETHODIMP CTimeSvrFactory::QueryInterface(const IID& iid, void** ppv)
{
if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))
{
*ppv = static_cast<IClassFactory*>(this);
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef();
return S_OK ;
}
STDMETHODIMP_(ULONG) CTimeSvrFactory::AddRef()
{
return InterlockedIncrement(&m_lRefCount);
}
STDMETHODIMP_(ULONG) CTimeSvrFactory::Release()
{
if (InterlockedDecrement(&m_lRefCount) == 0)
{
delete this;
return 0;
}
return m_lRefCount;
}
STDMETHODIMP CTimeSvrFactory::CreateInstance(
IUnknown* pUnknownOuter, const IID& iid, void** ppv)
{
if (pUnknownOuter != NULL)
return CLASS_E_NOAGGREGATION;
CTimeOfDay* pObject = new CTimeOfDay;
if (pObject == NULL)
return E_OUTOFMEMORY;
HRESULT hr = pObject->QueryInterface(iid, ppv);
pObject->Release();
return hr;
}
STDMETHODIMP CTimeSvrFactory::LockServer(BOOL bLock)
{
if (bLock)
InterlockedIncrement(&m_lLockCount);
else
InterlockedDecrement(&m_lLockCount);
return S_OK;
}
TimeSvr.cpp
#include "stdafx.h"
#include "resource.h"
#include "Factory.h"
#include "TimeSvr.h"
#include "TimeSvr_i.c"
long g_lObjCount = 0;
static HINSTANCE g_hModule;
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
if (dwReason == DLL_PROCESS_ATTACH)
g_hModule = hInstance;
return TRUE;
}
STDAPI DllCanUnloadNow(void)
{
return (g_lObjCount == 0) ? S_OK : S_FALSE;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
if (rclsid != CLSID_TimeOfDay)
return CLASS_E_CLASSNOTAVAILABLE;
// Create class factory.
CTimeSvrFactory* pFactory = new CTimeSvrFactory;
if (pFactory == NULL)
return E_OUTOFMEMORY;
// Get requested interface.
HRESULT hr = pFactory->QueryInterface(riid, ppv);
pFactory->Release();
return hr;
}
BOOL SetRegistryValue(LPCTSTR szKey, LPCTSTR szSubkey, LPCTSTR szValue)
{
HKEY hKey;
TCHAR szKeyBuf[1024];
lstrcpy(szKeyBuf, szKey);
if (szSubkey != NULL)
{
lstrcat(szKeyBuf, _T("\\"));
lstrcat(szKeyBuf, szSubkey);
}
long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT, szKeyBuf, 0, NULL, 0,
KEY_ALL_ACCESS, NULL, &hKey, NULL);
if (lResult != ERROR_SUCCESS)
return FALSE;
if (szValue != NULL)
{
RegSetValueEx(hKey, NULL, 0, REG_SZ,(BYTE*)szValue,
lstrlen(szValue)+1);
}
RegCloseKey(hKey);
return TRUE;
}
STDAPI DllRegisterServer(void)
{
// Get the filename of our COM server
TCHAR* szModule = new TCHAR[_MAX_PATH];
GetModuleFileName(g_hModule, szModule, _MAX_PATH);
// Get the class name string for TimeOfDay class
LPOLESTR wszCLSID = NULL;
StringFromCLSID(CLSID_TimeOfDay, &wszCLSID);
int nLen = lstrlenW(wszCLSID);
TCHAR* szCLSID = new TCHAR[nLen + 1];
#ifndef _UNICODE
wcstombs(szCLSID, wszCLSID, nLen);
szCLSID[nLen] = 0;
#else
lstrcpy(szCLSID, wszCLSID);
#endif
CoTaskMemFree(wszCLSID);
// Register the TimeOfDay server
TCHAR* szKey = new TCHAR[_MAX_PATH];
lstrcpy(szKey, _T("CLSID\\"));
lstrcat(szKey, szCLSID);
SetRegistryValue(szKey, NULL, _T("TimeOfDay Server"));
SetRegistryValue(szKey, _T("InprocServer32"), szModule);
SetRegistryValue(szKey, _T("ProgID"), _T("ExtremeCPP.TimeOfDay.1"));
SetRegistryValue(szKey, _T("VersionIndependentProgID"),
_T("ExtremeCPP.TimeOfDay"));
SetRegistryValue(_T("ExtremeCPP.TimeOfDay"), NULL, _T("TimeOfDay Server"));
SetRegistryValue(_T("ExtremeCPP.TimeOfDay"), _T("CLSID"), szCLSID);
SetRegistryValue(_T("ExtremeCPP.TimeOfDay"), _T("CurVer"),
_T("ExtremeCPP.TimeOfDay.1"));
SetRegistryValue(_T("ExtremeCPP.TimeOfDay.1"), "CLSID", szCLSID);
SetRegistryValue(_T("ExtremeCPP.TimeOfDay.1"), NULL,
_T("TimeOfDay Server"));
delete [] szKey;
delete [] szCLSID;
delete [] szModule;
return S_OK;
}
LONG RecursiveDeleteKey(HKEY hKeyParent, LPCTSTR lpszKeyChild)
{
HKEY hKeyChild;
LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,
KEY_ALL_ACCESS, &hKeyChild);
if (lRes != ERROR_SUCCESS)
return lRes;
char szBuffer[_MAX_PATH];
DWORD dwSize = _MAX_PATH;
while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,
NULL, NULL, NULL) == S_OK)
{
lRes = RecursiveDeleteKey(hKeyChild, szBuffer);
if (lRes != ERROR_SUCCESS)
{
RegCloseKey(hKeyChild);
return lRes;
}
dwSize = _MAX_PATH;
}
RegCloseKey(hKeyChild);
return RegDeleteKey(hKeyParent, lpszKeyChild);
}
STDAPI DllUnregisterServer(void)
{
// Get the class name string for TimeOfDay class
LPOLESTR wszCLSID = NULL;
StringFromCLSID(CLSID_TimeOfDay, &wszCLSID);
int nLen = lstrlenW(wszCLSID);
TCHAR* szCLSID = new TCHAR[nLen + 1];
#ifndef _UNICODE
wcstombs(szCLSID, wszCLSID, nLen);
szCLSID[nLen] = 0;
#else
lstrcpy(szCLSID, wszCLSID);
#endif
CoTaskMemFree(wszCLSID);
// Unregister the TimeOfDay server
TCHAR* szKey = new TCHAR[_MAX_PATH];
lstrcpy(szKey, _T("CLSID\\"));
lstrcat(szKey, szCLSID);
RecursiveDeleteKey(HKEY_CLASSES_ROOT, szKey);
RecursiveDeleteKey(HKEY_CLASSES_ROOT, _T("ExtremeCPP.TimeOfDay"));
RecursiveDeleteKey(HKEY_CLASSES_ROOT, _T("ExtremeCPP.TimeOfDay.1"));
delete [] szKey;
delete [] szCLSID;
return S_OK;
}
Figure 2 Time Server in ATL
TimeOfDay.h
#ifndef __TIMEOFDAY_H_
#define __TIMEOFDAY_H_
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CTimeOfDay
class ATL_NO_VTABLE CTimeOfDay :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CTimeOfDay, &CLSID_TimeOfDay>,
public IDispatchImpl<ITimeOfDay, &IID_ITimeOfDay, &LIBID_TIMESVRLib>
{
public:
CTimeOfDay()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_TIMEOFDAY)
BEGIN_COM_MAP(CTimeOfDay)
COM_INTERFACE_ENTRY(ITimeOfDay)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
// ITimeOfDay
public:
STDMETHOD(get_DateString)(/*[out, retval]*/ BSTR *pVal);
STDMETHOD(get_TimeString)(/*[out, retval]*/ BSTR *pVal);
};
#endif //__TIMEOFDAY_H_
TimeSvr.cpp
#include "stdafx.h"
#include "resource.h"
#include "initguid.h"
#include "TimeSvr.h"
#include "TimeSvr_i.c"
#include "TimeOfDay.h"
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_TimeOfDay, CTimeOfDay)
END_OBJECT_MAP()
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
_Module.Init(ObjectMap, hInstance);
DisableThreadLibraryCalls(hInstance);
}
else if (dwReason == DLL_PROCESS_DETACH)
_Module.Term();
return TRUE; // ok
}
STDAPI DllCanUnloadNow(void)
{
return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
}
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _Module.GetClassObject(rclsid, riid, ppv);
}
STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
return _Module.RegisterServer(TRUE);
}
STDAPI DllUnregisterServer(void)
{
_Module.UnregisterServer();
return S_OK;
}
TimeSvr.idl
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(3AF29C10-0853-11D1-9A27-00A0C91EF7B9),
dual,
helpstring("ITimeOfDay Interface"),
pointer_default(unique)
]
interface ITimeOfDay : IDispatch
{
[propget, id(1), helpstring("property TimeString")] HRESULT TimeString([out,
retval] BSTR *pVal);
[propget, id(2), helpstring("property DateString")] HRESULT DateString([out,
retval] BSTR *pVal);
};
[
uuid(3AF29C03-0853-11D1-9A27-00A0C91EF7B9),
version(1.0),
helpstring("TimeSvr 1.0 Type Library")
]
library TIMESVRLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(3AF29C11-0853-11D1-9A27-00A0C91EF7B9),
helpstring("TimeOfDay Class")
]
coclass TimeOfDay
{
[default] interface ITimeOfDay;
};
};
Figure 3 New COM+ Services
New Service | Description | Disadvantage |
Class Exposure | COM+ will allow you to directly expose classes in addition to traditional interfaces, making it easier to share objects. | Interfaces are a rich, effective way of separating behavior from implementation. Exposing classes directly will tend to increase the coupling between client and server. Furthermore, class references will only be understood by applications and tools that support COM+, meaning that legacy applications will have to be rebuilt to be able to import object references. |
Implementation Inheritance | COM+ will allow you to subclass the functionalitynot just the interfacesof directly exposed classes. You'll be able to extend COM+ objects easily using inheritance instead of aggregation. | Even though the lack of implementation inheritance is one of the most widely criticized "limitations" in COM, there is a good reason for it. Without a complete documentation for an objectits source code, in other wordsit's nearly impossible to determine how to safely override that object's behavior. Since a derived class must learn some of the details of the base class to accurately augment its behavior, implementation inheritance tends to increase the coupling between objects. |
Extended Security | COM+ will provide a security model that extends many of the features provided by COM, MTS, and the Microsoft Java Virtual Machine. You'll be able to define role-based security privileges to your components and let administrators decide which users to assign to those roles. | It is unclear whether existing COM objects will be able to take advantage of the extended security model. The COM+ services will impose runtime overhead. |
Garbage Collection | COM+ will handle reference counting, so you won't have to worry about making paired calls to AddRef and Release to manage the lifetime of objects. COM+ will release objects automatically when it determines that they are no longer in use. | A garbage collection algorithmnot the clientwill ultimately determine the lifetime of an object. As a result, an object might actually stay in memory long after its reference count has dropped to zero. This will require you to consider race conditionsthe indeterminate order in which two or more objects are freedand resource allocation issues. |