mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
926 lines
22 KiB
926 lines
22 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1997.
|
|
//
|
|
// File: cdispmgr.cxx
|
|
//
|
|
// Contents: The dispatch manager -- a class to manage
|
|
// multiple IDispatch-callable interfaces.
|
|
//
|
|
// Classes: CDispatchMgr
|
|
//
|
|
// Functions: None external.
|
|
//
|
|
// History: ??-???-?? KrishnaG created
|
|
// 07-Sep-97 t-blakej Commented, cleaned up, made
|
|
// independent of ADSI.
|
|
//
|
|
// See cdispmgr.hxx for a more thorough description of the dispatch manager.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
// Since this class is useful outside of ADSI, some work has been taken to
|
|
// make it not depend on any ADSI-specific code. It needs two ADSI header
|
|
// files (cdispmgr.hxx and iprops.hxx), but they only depend on definitions
|
|
// from standard system header files.
|
|
//
|
|
// To accomodate the current building method in ADSI, the precompiled
|
|
// header "procs.hxx" is included; this includes all the necessary ADSI
|
|
// header files and definitions. But for use outside of ADSI, the few
|
|
// necessary header files are explicitly included below; see the comment by
|
|
// "#ifndef ADsAssert".
|
|
//
|
|
// So if not compiling for ADSI, comment the following two lines out.
|
|
//
|
|
|
|
#include "procs.hxx"
|
|
#pragma hdrstop
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// General helper definitions, routines, and inclusions:
|
|
|
|
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Begin Non-ADSI compile stuff
|
|
//
|
|
// This macro is defined by the precompiled header file, so the following
|
|
// will only be included if not compiling for ADSI.
|
|
//
|
|
#ifndef ADsAssert
|
|
|
|
//
|
|
// Necessary system headers.
|
|
//
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
#define _OLEAUT32_
|
|
#define INC_OLE2
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
|
|
//
|
|
// Necessary class definitions used by the dispatch manager.
|
|
// Edit these paths if necessary.
|
|
//
|
|
#include "cdispmgr.hxx"
|
|
#include "iprops.hxx"
|
|
|
|
#endif // ADsAssert
|
|
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- End Non-ADSI compile stuff
|
|
|
|
//
|
|
// Error recovery.
|
|
//
|
|
#define BAIL_ON_FAILURE(hr) if (FAILED(hr)) { goto cleanup; }
|
|
|
|
//
|
|
// A simple assert function.
|
|
//
|
|
#if DBG == 1
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: AssertEx
|
|
//
|
|
// Synopsis: Display assertion information.
|
|
//
|
|
// Effects: Called when an assertion is hit.
|
|
//
|
|
// History: Simplified from Win4AssertEx, to make this dispatch manager
|
|
// not depend on other files.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
static void
|
|
AssertEx(char const *szFile, int iLine, char const *szMessage)
|
|
{
|
|
static char szAssertCaption[199];
|
|
DWORD dwCount = strlen("File: %s line %u, thread id %d");
|
|
|
|
if (szFile) {
|
|
dwCount += strlen(szFile);
|
|
}
|
|
|
|
dwCount += 15; // for the line number and thread id
|
|
|
|
if (dwCount > 199) {
|
|
sprintf(szAssertCaption, "Error, could not get more infomration");
|
|
}
|
|
else {
|
|
sprintf(szAssertCaption, "File: %s line %u, thread id %d",
|
|
szFile, iLine, GetCurrentThreadId());
|
|
}
|
|
|
|
if (IDCANCEL == MessageBoxA(
|
|
NULL,
|
|
(char *) szMessage,
|
|
(LPSTR) szAssertCaption,
|
|
MB_SETFOREGROUND |
|
|
MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL
|
|
))
|
|
{
|
|
DebugBreak();
|
|
}
|
|
}
|
|
# define DispMgrAssert(x) (void)((x) || (AssertEx(__FILE__, __LINE__, #x),0))
|
|
#else
|
|
# define AssertEx(f,l,m) do {} while(0)
|
|
# define DispMgrAssert(x) do {} while(0)
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Inline routines:
|
|
|
|
static inline LONG
|
|
getDispMgrId(DISPID InputDispId)
|
|
{
|
|
return (InputDispId & 0x7f000000) >> 24;
|
|
}
|
|
|
|
static inline LONG
|
|
getTypeInfoId(DISPID InputDispId)
|
|
{
|
|
return (InputDispId & 0x00ff0000) >> 16;
|
|
}
|
|
|
|
static inline LONG
|
|
getDispId(DISPID InputDispId)
|
|
{
|
|
return (InputDispId & 0x0000ffff);
|
|
}
|
|
|
|
static inline void
|
|
MakeDISPID(LONG TypeInfoId, LONG DispId, DISPID *pResult)
|
|
{
|
|
if (DispId == DISPID_UNKNOWN)
|
|
*pResult = DispId;
|
|
else if (TypeInfoId < 0 || TypeInfoId >= 0x100 ||
|
|
DispId < 0 || DispId >= 0x10000)
|
|
{
|
|
//
|
|
// Might happen if some object has very large dispid's.
|
|
// But we can't handle it if it does.
|
|
//
|
|
*pResult = DISPID_UNKNOWN;
|
|
}
|
|
else
|
|
*pResult = ((TypeInfoId & 0xff) << 16) | (DispId & 0xffff);
|
|
|
|
}
|
|
|
|
static inline void
|
|
IncDispMgrIds(DISPID *rgdispid, unsigned int cNames)
|
|
{
|
|
for (unsigned int i = 0; i < cNames; ++i)
|
|
{
|
|
if (rgdispid[i] == DISPID_UNKNOWN)
|
|
continue;
|
|
|
|
//
|
|
// This is either a stack of DispMgrs >127 high, or
|
|
// a programming error. More likely the latter.
|
|
//
|
|
DispMgrAssert(getDispMgrId(rgdispid[i]) < 0x7f);
|
|
|
|
rgdispid[i] =
|
|
(rgdispid[i] & 0x00ffffff) |
|
|
(((getDispMgrId(rgdispid[i]) + 1) & 0x7f) << 24);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
DecDispMgrIds(DISPID *rgdispid, unsigned int cNames)
|
|
{
|
|
for (unsigned int i = 0; i < cNames; ++i)
|
|
{
|
|
//
|
|
// It should never be less than zero, and the only place
|
|
// this is called from guarantees it is not zero.
|
|
//
|
|
DispMgrAssert(getDispMgrId(rgdispid[i]) > 0);
|
|
|
|
rgdispid[i] =
|
|
(rgdispid[i] & 0x00ffffff) |
|
|
(((getDispMgrId(rgdispid[i]) - 1) & 0x7f) << 24);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
MakeDISPIDs(LONG TypeInfoId, DISPID *rgdispid, unsigned int cNames)
|
|
{
|
|
for (unsigned int i = 0; i < cNames; i++)
|
|
{
|
|
MakeDISPID(TypeInfoId, rgdispid[i], &rgdispid[i]);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Struct defs
|
|
//
|
|
typedef struct _typeinfotable
|
|
{
|
|
GUID iid;
|
|
ITypeInfo * pTypeInfo;
|
|
struct _typeinfotable *pNext;
|
|
}TYPEINFO_TABLE, *PTYPEINFO_TABLE;
|
|
|
|
|
|
PTYPEINFO_TABLE gpTypeInfoTable = NULL;
|
|
|
|
CRITICAL_SECTION g_DispTypeInfoCritSect;
|
|
|
|
#define ENTER_DISP_TYPEINFO_CRITSECT() EnterCriticalSection(&g_DispTypeInfoCritSect)
|
|
#define LEAVE_DISP_TYPEINFO_CRITSECT() LeaveCriticalSection(&g_DispTypeInfoCritSect)
|
|
|
|
LONG glnObjCount = 0;
|
|
LONG glnTypesOfInfo = 0;
|
|
LONG glnOledbObjCnt = 0;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Public methods:
|
|
|
|
CDispatchMgr::CDispatchMgr()
|
|
{
|
|
_pTypeInfoEntry = NULL;
|
|
_pDispidNewEnum = NULL;
|
|
_dwTypeInfoId = 0;
|
|
_pDispidValue = NULL;
|
|
_pPropertyCache = NULL;
|
|
_dwPropCacheID = 0;
|
|
_pDispatch = NULL;
|
|
}
|
|
|
|
CDispatchMgr::~CDispatchMgr()
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry = NULL;
|
|
PTYPEINFOENTRY pTemp = NULL;
|
|
ITypeInfo *pTypeInfo = NULL;
|
|
|
|
pTypeInfoEntry = _pTypeInfoEntry;
|
|
|
|
while (pTypeInfoEntry) {
|
|
|
|
pTemp = pTypeInfoEntry;
|
|
|
|
pTypeInfo = (ITypeInfo *)pTypeInfoEntry->ptypeinfo;
|
|
pTypeInfo->Release();
|
|
|
|
InterlockedDecrement(&glnObjCount);
|
|
|
|
pTypeInfoEntry = pTemp->pNext;
|
|
|
|
LocalFree(pTemp);
|
|
}
|
|
|
|
ENTER_DISP_TYPEINFO_CRITSECT();
|
|
if (glnObjCount == glnTypesOfInfo) {
|
|
//
|
|
// We need to clean up the list
|
|
//
|
|
FreeTypeInfoTable();
|
|
|
|
glnObjCount = glnTypesOfInfo = 0;
|
|
|
|
}
|
|
LEAVE_DISP_TYPEINFO_CRITSECT();
|
|
|
|
if (_pDispatch)
|
|
_pDispatch->Release();
|
|
}
|
|
|
|
void
|
|
CDispatchMgr::RegisterPropertyCache(IPropertyCache *pPropertyCache)
|
|
{
|
|
_pPropertyCache = pPropertyCache;
|
|
_dwPropCacheID = gentypeinfoid();
|
|
}
|
|
|
|
void
|
|
CDispatchMgr::RegisterBaseDispatchPtr(IDispatch *pDispatch)
|
|
{
|
|
_pDispatch = pDispatch;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CDispatchMgr::GetTypeInfoCount(unsigned int *pctinfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CDispatchMgr::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo **pptinfo)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CDispatchMgr::GetIDsOfNames(REFIID iid, LPWSTR *rgszNames,
|
|
unsigned int cNames, LCID lcid, DISPID *rgdispid)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfo = NULL;
|
|
HRESULT hr = DISP_E_UNKNOWNNAME;
|
|
|
|
//
|
|
// Try our list of TypeInfos.
|
|
//
|
|
pTypeInfo = _pTypeInfoEntry;
|
|
while (pTypeInfo) {
|
|
hr = DispGetIDsOfNames(((ITypeInfo *)pTypeInfo->ptypeinfo),
|
|
rgszNames,
|
|
cNames,
|
|
rgdispid
|
|
);
|
|
if (SUCCEEDED(hr)) {
|
|
MakeDISPIDs(pTypeInfo->TypeInfoId, rgdispid, cNames);
|
|
return hr;
|
|
}
|
|
pTypeInfo = pTypeInfo->pNext;
|
|
}
|
|
|
|
//
|
|
// Try our property cache.
|
|
//
|
|
if (FAILED(hr) && _pPropertyCache) {
|
|
hr = S_OK;
|
|
for (DWORD dw = 0; dw < cNames; dw++) {
|
|
if (FAILED(_pPropertyCache->locateproperty(rgszNames[dw],
|
|
(PDWORD)(rgdispid + dw)))) {
|
|
hr = DISP_E_UNKNOWNNAME;
|
|
rgdispid[dw] = DISPID_UNKNOWN;
|
|
}
|
|
}
|
|
if (SUCCEEDED(hr)) {
|
|
MakeDISPIDs(_dwPropCacheID, rgdispid, cNames);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Try our "base class" dispatch pointer.
|
|
//
|
|
if (FAILED(hr) && _pDispatch) {
|
|
hr = _pDispatch->GetIDsOfNames(iid, rgszNames, cNames, lcid, rgdispid);
|
|
|
|
if (SUCCEEDED(hr)) {
|
|
IncDispMgrIds(rgdispid, cNames);
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CDispatchMgr::Invoke(DISPID dispidMember, REFIID iid, LCID lcid,
|
|
unsigned short wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult,
|
|
EXCEPINFO *pexcepinfo, unsigned int *puArgErr)
|
|
{
|
|
//
|
|
// Clear the error object before we call invoke.
|
|
//
|
|
SetErrorInfo(0, NULL);
|
|
|
|
return TypeInfoInvoke(dispidMember,
|
|
iid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Private methods and helper functions:
|
|
|
|
void *
|
|
CDispatchMgr::getInterfacePtr(LONG TypeInfoId)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry = FindTypeInfoEntry(TypeInfoId);
|
|
return (pTypeInfoEntry ? pTypeInfoEntry->pInterfacePointer : NULL);
|
|
}
|
|
|
|
ITypeInfo *
|
|
CDispatchMgr::getTypeInfo(LONG TypeInfoId)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry = FindTypeInfoEntry(TypeInfoId);
|
|
return (ITypeInfo *)(pTypeInfoEntry ? pTypeInfoEntry->ptypeinfo : NULL);
|
|
}
|
|
|
|
PTYPEINFOENTRY
|
|
CDispatchMgr::FindTypeInfoEntry(LONG TypeInfoId)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry;
|
|
|
|
pTypeInfoEntry = _pTypeInfoEntry;
|
|
while (pTypeInfoEntry) {
|
|
if (pTypeInfoEntry->TypeInfoId == TypeInfoId) {
|
|
return pTypeInfoEntry;
|
|
}
|
|
pTypeInfoEntry = pTypeInfoEntry->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
PTYPEINFOENTRY
|
|
CDispatchMgr::FindTypeInfo(void *pTypeInfo)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry;
|
|
|
|
pTypeInfoEntry = _pTypeInfoEntry;
|
|
while (pTypeInfoEntry) {
|
|
if (pTypeInfoEntry->ptypeinfo == pTypeInfo) {
|
|
return pTypeInfoEntry;
|
|
}
|
|
pTypeInfoEntry = pTypeInfoEntry->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT
|
|
CDispatchMgr::AddTypeInfo(void *ptypeinfo, void *pIntfptr)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry = NULL;
|
|
HRESULT hr;
|
|
|
|
if (FindTypeInfo(ptypeinfo)) {
|
|
return E_FAIL;
|
|
}
|
|
pTypeInfoEntry = (PTYPEINFOENTRY)LocalAlloc(LPTR,sizeof(TYPEINFOENTRY));
|
|
if (!pTypeInfoEntry) {
|
|
BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
|
|
}
|
|
|
|
pTypeInfoEntry->ptypeinfo = ptypeinfo;
|
|
pTypeInfoEntry->TypeInfoId = gentypeinfoid();
|
|
pTypeInfoEntry->pInterfacePointer = pIntfptr;
|
|
|
|
pTypeInfoEntry->pNext = _pTypeInfoEntry;
|
|
_pTypeInfoEntry = pTypeInfoEntry;
|
|
|
|
return S_OK;
|
|
|
|
cleanup:
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CDispatchMgr::TypeInfoInvoke(DISPID dispidMember, REFIID iid, LCID lcid,
|
|
unsigned short wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult,
|
|
EXCEPINFO *pexcepinfo, unsigned int *puArgErr)
|
|
{
|
|
void *pInterfacePtr = NULL;
|
|
DISPID dispid = 0;
|
|
DISPID typeinfoid = 0;
|
|
ITypeInfo *pTypeInfo = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (dispidMember <= 0) {
|
|
|
|
//
|
|
// One of the special DISPIDs.
|
|
//
|
|
// If we have an interface pointer for it, use that.
|
|
// If we don't, and we have a base IDispatch pointer,
|
|
// pass it to the base pointer's Invoke() method.
|
|
// If we don't, and we don't have a base IDispatch pointer,
|
|
// return failure.
|
|
//
|
|
|
|
dispid = dispidMember;
|
|
switch (dispid) {
|
|
|
|
case DISPID_VALUE:
|
|
if (_pDispidValue) {
|
|
pTypeInfo = (ITypeInfo *)_pDispidValue->ptypeinfo;
|
|
pInterfacePtr = _pDispidValue->pInterfacePointer;
|
|
}
|
|
break;
|
|
|
|
case DISPID_NEWENUM:
|
|
if (_pDispidNewEnum) {
|
|
pTypeInfo = (ITypeInfo *)_pDispidNewEnum->ptypeinfo;
|
|
pInterfacePtr = _pDispidNewEnum->pInterfacePointer;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!pInterfacePtr) {
|
|
if (_pDispatch) {
|
|
return _pDispatch->Invoke(dispidMember, iid, lcid, wFlags,
|
|
pdispparams, pvarResult, pexcepinfo, puArgErr);
|
|
} else {
|
|
BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
|
|
}
|
|
}else {
|
|
|
|
//
|
|
// Fill in the special case scenarios here
|
|
//
|
|
|
|
hr = DispInvoke(
|
|
pInterfacePtr,
|
|
pTypeInfo,
|
|
dispid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
|
|
return(hr);
|
|
|
|
}
|
|
|
|
} else if (getDispMgrId(dispidMember)) {
|
|
|
|
//
|
|
// A regular DISPID of a "base class" dispatch manager.
|
|
//
|
|
|
|
if (!_pDispatch){
|
|
|
|
char szMessage[80];
|
|
sprintf(szMessage, "_pDispatch is NULL, dispid = 0x%08x",
|
|
dispidMember);
|
|
AssertEx(__FILE__, __LINE__, szMessage);
|
|
return DISP_E_MEMBERNOTFOUND;
|
|
}
|
|
|
|
DecDispMgrIds(&dispidMember, 1);
|
|
|
|
hr = _pDispatch->Invoke(
|
|
dispidMember,
|
|
iid,
|
|
lcid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
return(hr);
|
|
|
|
} else {
|
|
|
|
//
|
|
// A regular DISPID of ours.
|
|
//
|
|
|
|
typeinfoid = getTypeInfoId(dispidMember);
|
|
dispid = getDispId(dispidMember);
|
|
|
|
if ((_pPropertyCache == NULL) || (typeinfoid != _dwPropCacheID)) {
|
|
pInterfacePtr = getInterfacePtr(typeinfoid);
|
|
pTypeInfo = getTypeInfo(typeinfoid);
|
|
if (!pTypeInfo)
|
|
//
|
|
// Shouldn't happen.
|
|
//
|
|
BAIL_ON_FAILURE(hr = DISP_E_MEMBERNOTFOUND);
|
|
}
|
|
|
|
if ((_pPropertyCache == NULL) || (typeinfoid != _dwPropCacheID)) {
|
|
|
|
//
|
|
// A regular interface.
|
|
//
|
|
|
|
hr = DispInvoke(
|
|
pInterfacePtr,
|
|
pTypeInfo,
|
|
dispid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult,
|
|
pexcepinfo,
|
|
puArgErr
|
|
);
|
|
}else {
|
|
|
|
//
|
|
// A "dynamic DISPID", for the property cache.
|
|
//
|
|
|
|
hr = DynamicDispidInvoke(
|
|
_pPropertyCache,
|
|
dispid,
|
|
wFlags,
|
|
pdispparams,
|
|
pvarResult
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cleanup:
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DynamicDispidInvoke(
|
|
IPropertyCache * pPropertyCache,
|
|
DISPID dispid,
|
|
unsigned short wFlags,
|
|
DISPPARAMS *pdispparams,
|
|
VARIANT * pvarResult
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!pPropertyCache) {
|
|
|
|
return(E_INVALIDARG);
|
|
}
|
|
|
|
if (wFlags & DISPATCH_PROPERTYGET) {
|
|
|
|
if (!pvarResult) {
|
|
BAIL_ON_FAILURE(hr = E_INVALIDARG);
|
|
}
|
|
|
|
hr = pPropertyCache->getproperty((DWORD)dispid,pvarResult);
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
#if 1
|
|
// This lets us return S_OK and a VT_EMPTY variant if
|
|
// there's no data. #if this out to disable it.
|
|
V_VT(pvarResult) = VT_EMPTY;
|
|
hr = S_OK;
|
|
#else
|
|
|
|
V_VT(pvarResult) = VT_ERROR;
|
|
#endif
|
|
|
|
}
|
|
}else if (wFlags & DISPATCH_PROPERTYPUT) {
|
|
|
|
if (pdispparams[0].cArgs != 1){
|
|
hr = DISP_E_BADPARAMCOUNT;
|
|
}
|
|
else {
|
|
|
|
hr = pPropertyCache->putproperty(
|
|
(DWORD)dispid,
|
|
pdispparams[0].rgvarg[0]
|
|
);
|
|
}
|
|
|
|
}else {
|
|
hr = E_INVALIDARG;
|
|
}
|
|
|
|
cleanup:
|
|
return(hr);
|
|
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CDispatchMgr::MarkAsNewEnum(void *pTypeInfo)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry;
|
|
|
|
if (!pTypeInfo) {
|
|
return E_FAIL;
|
|
}
|
|
if (!(pTypeInfoEntry = FindTypeInfo(pTypeInfo))) {
|
|
return E_FAIL;
|
|
}
|
|
_pDispidNewEnum = pTypeInfoEntry;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CDispatchMgr::MarkAsItem(void *pTypeInfo)
|
|
{
|
|
PTYPEINFOENTRY pTypeInfoEntry;
|
|
|
|
if (!pTypeInfo) {
|
|
return E_FAIL;
|
|
}
|
|
if (!(pTypeInfoEntry = FindTypeInfo(pTypeInfo))) {
|
|
return E_FAIL;
|
|
}
|
|
_pDispidValue = pTypeInfoEntry;
|
|
return S_OK;
|
|
}
|
|
|
|
LONG
|
|
CDispatchMgr::gentypeinfoid()
|
|
{
|
|
//
|
|
// This would mean we've registered 65536 IDispatch methods
|
|
// in this object's dispatch manager. We lose.
|
|
//
|
|
DispMgrAssert(_dwTypeInfoId < 0xffff);
|
|
|
|
return (_dwTypeInfoId++);
|
|
}
|
|
|
|
ITypeInfo *
|
|
FindTypeInfo(
|
|
PTYPEINFO_TABLE pTypeInfoTable,
|
|
REFIID iid
|
|
)
|
|
{
|
|
PTYPEINFO_TABLE pTemp = NULL;
|
|
|
|
pTemp = pTypeInfoTable;
|
|
|
|
while (pTemp) {
|
|
if (IsEqualIID(iid, pTemp->iid)) {
|
|
return pTemp->pTypeInfo;
|
|
}
|
|
pTemp = pTemp->pNext;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PTYPEINFO_TABLE
|
|
AddTypeInfo(
|
|
PTYPEINFO_TABLE pTypeInfoTable,
|
|
REFIID iid,
|
|
ITypeInfo * pTypeInfo
|
|
)
|
|
{
|
|
PTYPEINFO_TABLE pTemp = NULL;
|
|
|
|
pTemp = (PTYPEINFO_TABLE)LocalAlloc(LPTR, sizeof(TYPEINFO_TABLE));
|
|
if (!pTemp) {
|
|
return NULL;
|
|
}
|
|
|
|
memcpy(&pTemp->iid, &iid, sizeof(GUID));
|
|
pTemp->pTypeInfo = pTypeInfo;
|
|
pTemp->pNext = pTypeInfoTable;
|
|
|
|
return pTemp;
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: LoadTypeInfo
|
|
//
|
|
// Synopsis: Loads a typeinfo from a registered typelib.
|
|
//
|
|
// Arguments: [clsidTL] -- TypeLib GUID
|
|
// [clsidTI] -- TypeInfo GUID
|
|
// [ppTI] -- Resulting typeInfo
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
LoadTypeInfo(CLSID clsidTL, CLSID clsidTI, LPTYPEINFO *ppTI)
|
|
{
|
|
HRESULT hr;
|
|
ITypeLib * pTL;
|
|
|
|
DispMgrAssert(ppTI);
|
|
*ppTI = NULL;
|
|
hr = LoadRegTypeLib(clsidTL, 1, 0, LOCALE_SYSTEM_DEFAULT, &pTL);
|
|
if (!SUCCEEDED(hr))
|
|
return hr;
|
|
|
|
hr = pTL->GetTypeInfoOfGuid(clsidTI, ppTI);
|
|
pTL->Release();
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CDispatchMgr::LoadTypeInfoEntry(
|
|
REFIID libid,
|
|
REFIID iid,
|
|
void * pIntf,
|
|
DISPID SpecialId
|
|
)
|
|
{
|
|
ITypeInfo * pTypeInfo = NULL;
|
|
HRESULT hr;
|
|
|
|
ENTER_DISP_TYPEINFO_CRITSECT();
|
|
|
|
pTypeInfo = ::FindTypeInfo(gpTypeInfoTable, iid);
|
|
|
|
if (!pTypeInfo) {
|
|
|
|
LEAVE_DISP_TYPEINFO_CRITSECT();
|
|
|
|
hr = LoadTypeInfo(libid, iid, &pTypeInfo);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
ENTER_DISP_TYPEINFO_CRITSECT();
|
|
|
|
gpTypeInfoTable = ::AddTypeInfo(
|
|
gpTypeInfoTable,
|
|
iid,
|
|
pTypeInfo
|
|
);
|
|
if (!gpTypeInfoTable) {
|
|
|
|
LEAVE_DISP_TYPEINFO_CRITSECT();
|
|
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
//
|
|
// Increment the global list of the types of type info's.
|
|
//
|
|
InterlockedIncrement(&glnTypesOfInfo);
|
|
|
|
InterlockedIncrement(&glnObjCount);
|
|
}
|
|
pTypeInfo->AddRef();
|
|
|
|
|
|
hr = AddTypeInfo(pTypeInfo, pIntf);
|
|
|
|
if (FAILED(hr)) {
|
|
LEAVE_DISP_TYPEINFO_CRITSECT();
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
//
|
|
// We have a ref on the object as add was succesful
|
|
//
|
|
InterlockedIncrement(&glnObjCount);
|
|
LEAVE_DISP_TYPEINFO_CRITSECT();
|
|
|
|
if (SpecialId == -4) {
|
|
hr = MarkAsNewEnum(pTypeInfo);
|
|
} else if (SpecialId == DISPID_VALUE) {
|
|
hr = MarkAsItem(pTypeInfo);
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
cleanup:
|
|
if (pTypeInfo)
|
|
pTypeInfo->Release();
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Kept for backwards compatibility.
|
|
//
|
|
HRESULT
|
|
LoadTypeInfoEntry(
|
|
CDispatchMgr *pDispMgr,
|
|
REFIID libid,
|
|
REFIID iid,
|
|
void * pIntf,
|
|
DISPID SpecialId
|
|
)
|
|
{
|
|
return pDispMgr->LoadTypeInfoEntry(libid, iid, pIntf, SpecialId);
|
|
}
|
|
|
|
void
|
|
FreeTypeInfoTable()
|
|
{
|
|
PTYPEINFO_TABLE pTypeInfoTable = NULL;
|
|
PTYPEINFO_TABLE pTemp = NULL;
|
|
ITypeInfo * pTypeInfo = NULL;
|
|
|
|
pTypeInfoTable = gpTypeInfoTable;
|
|
|
|
while (pTypeInfoTable) {
|
|
|
|
pTypeInfo = pTypeInfoTable->pTypeInfo;
|
|
|
|
pTypeInfo->Release();
|
|
|
|
|
|
pTemp = pTypeInfoTable;
|
|
|
|
pTypeInfoTable = pTypeInfoTable->pNext;
|
|
|
|
LocalFree(pTemp);
|
|
}
|
|
|
|
gpTypeInfoTable = NULL;
|
|
}
|
|
|
|
BOOL
|
|
DllReadyToUnload()
|
|
{
|
|
BOOL retVal = FALSE;
|
|
|
|
ENTER_DISP_TYPEINFO_CRITSECT();
|
|
retVal = ((glnTypesOfInfo == 0) && (glnOledbObjCnt == 0));
|
|
LEAVE_DISP_TYPEINFO_CRITSECT();
|
|
|
|
return retVal;
|
|
|
|
}
|