286 lines
7.6 KiB
C
286 lines
7.6 KiB
C
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
// File: N C A T L . H
|
||
|
//
|
||
|
// Contents: Common code for use with ATL.
|
||
|
//
|
||
|
// Notes: Pollute this under penalty of death.
|
||
|
//
|
||
|
// Author: shaunco 22 Sep 1997
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#pragma once
|
||
|
#ifndef _NCATL_H_
|
||
|
#define _NCATL_H_
|
||
|
|
||
|
#include "ncbase.h"
|
||
|
#include "ncstring.h"
|
||
|
|
||
|
//
|
||
|
// This file should be included *after* your standard ATL include sequence.
|
||
|
//
|
||
|
// #include <atlbase.h>
|
||
|
// extern CComModule _Module;
|
||
|
// #include <atlcom.h>
|
||
|
// #include "ncatl.h" <------
|
||
|
//
|
||
|
// We cannot directly include that sequence here because _Module may be
|
||
|
// derived from CComModule as opposed to an instance of it.
|
||
|
//
|
||
|
|
||
|
class CExceptionSafeComObjectLock
|
||
|
{
|
||
|
public:
|
||
|
CExceptionSafeComObjectLock (CComObjectRootEx <CComMultiThreadModel>* pObj)
|
||
|
{
|
||
|
AssertH (pObj);
|
||
|
m_pObj = pObj;
|
||
|
TraceTag (ttidEsLock,
|
||
|
"Entered critical section object of COM object 0x%08x",
|
||
|
&m_pObj);
|
||
|
pObj->Lock ();
|
||
|
}
|
||
|
|
||
|
~CExceptionSafeComObjectLock ()
|
||
|
{
|
||
|
TraceTag (ttidEsLock,
|
||
|
"Leaving critical section object of COM object 0x%08x",
|
||
|
&m_pObj);
|
||
|
|
||
|
m_pObj->Unlock ();
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
CComObjectRootEx <CComMultiThreadModel>* m_pObj;
|
||
|
};
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: HrCopyIUnknownArrayWhileLocked
|
||
|
//
|
||
|
// Purpose: Allocate and copy an array of IUnknown pointers from an ATL
|
||
|
// CComDynamicUnkArray while holding the object which controls
|
||
|
// the CComDynamicUnkArray locked. This is needed by objects
|
||
|
// which dispatch calls on a connection point's advise sink
|
||
|
// to prevent the CComDynamicUnkArray from being modified (via
|
||
|
// calls to Advise/Unadvise on other threads) while they are
|
||
|
// dispatching. An atomic copy is made so the dispatcher can
|
||
|
// then make the lengthy callbacks without the need to hold
|
||
|
// the owner object locked.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// pObj [in] Pointer to object which has Lock/Unlock methods.
|
||
|
// pVec [in] ATL array of IUnknown's to copy.
|
||
|
// pcUnk [out] Address of returned count of IUnknown pointerss
|
||
|
// in *paUnk.
|
||
|
// paUnk [out] Address of allocated pointer to the array of IUnknown
|
||
|
// pointers.
|
||
|
//
|
||
|
// Returns: S_OK or E_OUTOFMEMORY
|
||
|
//
|
||
|
// Author: shaunco 3 Dec 1998
|
||
|
//
|
||
|
// Notes: The returned count and array may be NULL when no IUnknowns
|
||
|
// existed in the input array. S_OK will be returned for this
|
||
|
// case too, so be sure to check *pcUnk and *paUnk too.
|
||
|
//
|
||
|
inline
|
||
|
HRESULT
|
||
|
HrCopyIUnknownArrayWhileLocked (
|
||
|
IN CComObjectRootEx <CComMultiThreadModel>* pObj,
|
||
|
IN CComDynamicUnkArray* pVec,
|
||
|
OUT ULONG* pcpUnk,
|
||
|
OUT IUnknown*** papUnk)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
IUnknown** ppUnkSrc;
|
||
|
IUnknown** ppUnkDst;
|
||
|
|
||
|
// Initialize the output parameters.
|
||
|
//
|
||
|
*pcpUnk = 0;
|
||
|
*papUnk = NULL;
|
||
|
|
||
|
pObj->Lock();
|
||
|
|
||
|
// First, count the number of IUnknown's we need to copy.
|
||
|
//
|
||
|
ULONG cpUnk = 0;
|
||
|
for (ppUnkSrc = pVec->begin(); ppUnkSrc < pVec->end(); ppUnkSrc++)
|
||
|
{
|
||
|
if (ppUnkSrc && *ppUnkSrc)
|
||
|
{
|
||
|
cpUnk++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Allocate space and copy the IUnknown's. (Be sure to AddRef them.)
|
||
|
//
|
||
|
if (cpUnk)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
ppUnkDst = (IUnknown**)MemAlloc (cpUnk * sizeof(IUnknown*));
|
||
|
if (ppUnkDst)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
|
||
|
*pcpUnk = cpUnk;
|
||
|
*papUnk = ppUnkDst;
|
||
|
|
||
|
for (ppUnkSrc = pVec->begin(); ppUnkSrc < pVec->end(); ppUnkSrc++)
|
||
|
{
|
||
|
if (ppUnkSrc && *ppUnkSrc)
|
||
|
{
|
||
|
*ppUnkDst = *ppUnkSrc;
|
||
|
AddRefObj(*ppUnkDst);
|
||
|
ppUnkDst++;
|
||
|
cpUnk--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We should have copied what we counted.
|
||
|
//
|
||
|
AssertH(0 == cpUnk);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pObj->Unlock();
|
||
|
|
||
|
TraceHr (ttidError, FAL, hr, FALSE, "HrCopyIUnknownArrayWhileLocked");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
#define DECLARE_CLASSFACTORY_DEFERRED_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(CComClassFactoryDeferredSingleton<obj>)
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
// Deferred Singleton Class Factory
|
||
|
//
|
||
|
template <class T>
|
||
|
class CComClassFactoryDeferredSingleton : public CComClassFactory
|
||
|
{
|
||
|
public:
|
||
|
CComClassFactoryDeferredSingleton () : m_pObj(NULL) {}
|
||
|
~CComClassFactoryDeferredSingleton() { delete m_pObj; }
|
||
|
|
||
|
// IClassFactory
|
||
|
STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj)
|
||
|
{
|
||
|
HRESULT hr = E_POINTER;
|
||
|
if (ppvObj != NULL)
|
||
|
{
|
||
|
// can't ask for anything other than IUnknown when aggregating
|
||
|
//
|
||
|
AssertH(!pUnkOuter || InlineIsEqualUnknown(riid));
|
||
|
if (pUnkOuter && !InlineIsEqualUnknown(riid))
|
||
|
{
|
||
|
hr = CLASS_E_NOAGGREGATION;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Need to protect m_pObj from being created more than once
|
||
|
// by multiple threads calling this method simultaneously.
|
||
|
// (I've seen this happen on multi-proc machines.)
|
||
|
//
|
||
|
Lock ();
|
||
|
|
||
|
if (m_pObj)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
m_pObj = new CComObjectGlobal<T>;
|
||
|
if (m_pObj)
|
||
|
{
|
||
|
hr = m_pObj->m_hResFinalConstruct;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Unlock ();
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = m_pObj->QueryInterface(riid, ppvObj);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
CComObjectGlobal<T>* m_pObj;
|
||
|
};
|
||
|
|
||
|
// We have our own version of AtlModuleRegisterServer coded here
|
||
|
// because the former brings in oleaut32.dll so it can register
|
||
|
// type libraries. We don't care to have a type library registered
|
||
|
// so we can avoid the whole the mess associated with oleaut32.dll.
|
||
|
//
|
||
|
inline
|
||
|
HRESULT
|
||
|
NcAtlModuleRegisterServer(
|
||
|
_ATL_MODULE* pM
|
||
|
)
|
||
|
{
|
||
|
AssertH (pM);
|
||
|
AssertH(pM->m_hInst);
|
||
|
AssertH(pM->m_pObjMap);
|
||
|
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
for (_ATL_OBJMAP_ENTRY* pEntry = pM->m_pObjMap;
|
||
|
pEntry->pclsid;
|
||
|
pEntry++)
|
||
|
{
|
||
|
if (pEntry->pfnGetObjectDescription() != NULL)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
hr = pEntry->pfnUpdateRegistry(TRUE);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TraceError ("NcAtlModuleRegisterServer", hr);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#ifdef __ATLCOM_H__
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: WszLoadIds
|
||
|
//
|
||
|
// Purpose: Loads the given string ID from the resource file.
|
||
|
//
|
||
|
// Arguments:
|
||
|
// unId [in] ID of string resource to load.
|
||
|
//
|
||
|
// Returns: Read-only version of resource string.
|
||
|
//
|
||
|
// Author: shaunco 24 Mar 1997
|
||
|
//
|
||
|
// Notes: 1) You must be compiling with ATL support to use this function.
|
||
|
// 2) The returned string CANNOT be modified.
|
||
|
// 3) You must compile your RC file with the -N option for this
|
||
|
// to work properly.
|
||
|
//
|
||
|
inline
|
||
|
PCWSTR
|
||
|
WszLoadIds (
|
||
|
UINT unId)
|
||
|
{
|
||
|
return WszLoadString (_Module.GetResourceInstance(), unId);
|
||
|
}
|
||
|
#endif //!__ATLCOM_H__
|
||
|
|
||
|
#endif // _NCATL_H_
|
||
|
|