Mozilla/mozilla/xpcom/proxy/src/nsProxyEventClass.cpp
dougt%netscape.com a539b0b3d7 Landing xpcom proxies.
git-svn-id: svn://10.0.0.236/trunk@30725 18797224-902f-48f8-a5cc-f745e15eee43
1999-05-07 20:01:37 +00:00

280 lines
7.9 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsProxyEvent.h"
#include "nsProxyObjectManager.h"
#include "nsProxyEventPrivate.h"
#include "nsRepository.h"
#include "nsIServiceManager.h"
#include "nsCOMPtr.h"
#include "nsIAllocator.h"
#include "nsHashtable.h"
#include "nsIInterfaceInfoManager.h"
#include "xptcall.h"
static uint32 zero_methods_descriptor;
//////////////////////////////////////////////////////////////////////////////////////////////////
// nsProxyEventClass
//////////////////////////////////////////////////////////////////////////////////////////////////
static NS_DEFINE_IID(kProxyEventClassIID, NS_PROXYEVENT_CLASS_IID);
NS_IMPL_ISUPPORTS(nsProxyEventClass, kProxyEventClassIID)
// static
nsProxyEventClass*
nsProxyEventClass::GetNewOrUsedClass(REFNSIID aIID)
{
/* find in our hash table */
nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap();
nsProxyEventClass* clazz = NULL;
nsIDKey key(aIID);
if(iidToClassMap->Exists(&key))
{
clazz = (nsProxyEventClass*) iidToClassMap->Get(&key);
NS_ADDREF(clazz);
}
else
{
nsIInterfaceInfoManager* iimgr;
if(NULL != (iimgr = XPTI_GetInterfaceInfoManager()))
{
nsIInterfaceInfo* info;
if(NS_SUCCEEDED(iimgr->GetInfoForIID(&aIID, &info)))
{
/*
Check to see if IsISupportsDescendent
*/
nsIInterfaceInfo* oldest = info;
nsIInterfaceInfo* parent;
NS_ADDREF(oldest);
while(NS_SUCCEEDED(oldest->GetParent(&parent)))
{
NS_RELEASE(oldest);
oldest = parent;
}
PRBool IsISupportsDescendent = PR_FALSE;
nsID* iid;
if(NS_SUCCEEDED(oldest->GetIID(&iid)))
{
IsISupportsDescendent = iid->Equals(nsISupports::GetIID());
nsAllocator::Free(iid);
}
NS_RELEASE(oldest);
NS_ASSERTION(IsISupportsDescendent,"!IsISupportsDescendent");
if (IsISupportsDescendent)
{
clazz = new nsProxyEventClass(aIID, info);
if(!clazz->mDescriptors)
NS_RELEASE(clazz); // sets clazz to NULL
}
NS_RELEASE(info);
}
NS_RELEASE(iimgr);
}
}
return clazz;
}
nsProxyEventClass::nsProxyEventClass(REFNSIID aIID, nsIInterfaceInfo* aInfo)
: mInfo(aInfo),
mIID(aIID),
mDescriptors(NULL)
{
NS_ADDREF(mInfo);
NS_INIT_REFCNT();
NS_ADDREF_THIS();
/* add use to the used classes */
nsIDKey key(aIID);
nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap();
iidToClassMap->Put(&key, this);
uint16 methodCount;
if(NS_SUCCEEDED(mInfo->GetMethodCount(&methodCount)))
{
if(methodCount)
{
int wordCount = (methodCount/32)+1;
if(NULL != (mDescriptors = new uint32[wordCount]))
{
int i;
// init flags to 0;
for(i = wordCount-1; i >= 0; i--)
mDescriptors[i] = 0;
}
}
else
{
mDescriptors = &zero_methods_descriptor;
}
}
}
nsProxyEventClass::~nsProxyEventClass()
{
if(mDescriptors && mDescriptors != &zero_methods_descriptor)
delete [] mDescriptors;
nsIDKey key(mIID);
nsProxyObjectManager *manager = nsProxyObjectManager::GetInstance();
nsHashtable *iidToClassMap = manager->GetIIDToProxyClassMap();
iidToClassMap->Remove(&key);
NS_RELEASE(mInfo);
}
nsProxyEventObject*
nsProxyEventClass::CallQueryInterfaceOnProxy(nsProxyEventObject* self, REFNSIID aIID)
{
nsISupports* aInstancePtr;
// The functions we will call: QueryInterface(REFNSIID aIID, void** aInstancePtr)
nsXPTCMiniVariant *var = new nsXPTCMiniVariant[2];
if (var == nsnull) return nsnull;
(&var[0])->val.p = (void*)&aIID;
(&var[1])->val.p = &aInstancePtr;
nsIInterfaceInfoManager *iim = XPTI_GetInterfaceInfoManager();
nsIInterfaceInfo *nsISupportsInfo;
const nsXPTMethodInfo *mi;
iim->GetInfoForName("nsISupports", &nsISupportsInfo);
nsISupportsInfo->GetMethodInfo(0, &mi); // 0 is QueryInterface
nsresult rv = self->CallMethod(0, mi, var);
aInstancePtr = (nsISupports*) *((void**)var[1].val.p);
delete [] var;
if (rv == NS_OK)
{
nsProxyEventObject* proxyObj = nsProxyEventObject::GetNewOrUsedProxy(self->GetQueue(), aInstancePtr, aIID);
if(proxyObj)
{
return proxyObj;
}
}
return nsnull;
}
/***************************************************************************/
// This 'ProxyEventClassIdentity' class and singleton allow us to figure out if
// any given nsISupports* is implemented by a nsProxy object. This is done
// using a QueryInterface call on the interface pointer with our ID. If
// that call returns NS_OK and the pointer is to our singleton, then the
// interface must be implemented by a nsProxy object. NOTE: the
// 'ProxyEventClassIdentity' object is not a real XPCOM object and should not be
// used for anything else (hence it is declared in this implementation file).
/* eea90d45-b059-11d2-915e-c12b696c9333 */
#define NS_PROXYEVENT_IDENTITY_CLASS_IID \
{ 0xeea90d45, 0xb059, 0x11d2, \
{ 0x91, 0x5e, 0xc1, 0x2b, 0x69, 0x6c, 0x93, 0x33 } }
class ProxyEventClassIdentity
{
// no instance methods...
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_PROXYEVENT_IDENTITY_CLASS_IID)
static void* GetSingleton()
{
static ProxyEventClassIdentity* singleton = NULL;
if(!singleton)
singleton = new ProxyEventClassIdentity();
return (void*) singleton;
}
};
NS_IMETHODIMP
nsProxyEventClass::DelegatedQueryInterface(nsProxyEventObject* self,
REFNSIID aIID,
void** aInstancePtr)
{
if(aIID.Equals(nsISupports::GetIID()))
{
nsProxyEventObject* root = self->GetRootProxyObject();
*aInstancePtr = (void*) root;
NS_ADDREF(root);
return NS_OK;
}
else if(aIID.Equals(self->GetIID()))
{
*aInstancePtr = (void*) self;
NS_ADDREF(self);
return NS_OK;
}
else if(aIID.Equals(ProxyEventClassIdentity::GetIID()))
{
*aInstancePtr = ProxyEventClassIdentity::GetSingleton();
return NS_OK;
}
else
{
*aInstancePtr = CallQueryInterfaceOnProxy(self, aIID);
if (*aInstancePtr == nsnull)
return NS_NOINTERFACE;
else
return NS_OK;
}
*aInstancePtr = NULL;
return NS_NOINTERFACE;
}
nsProxyEventObject*
nsProxyEventClass::GetRootProxyObject(nsProxyEventObject* anObject)
{
nsProxyEventObject* result = CallQueryInterfaceOnProxy(anObject, nsISupports::GetIID());
return result ? result : anObject;
}