home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1998 May
/
Pcwk5b98.iso
/
Borland
/
Cplus45
/
BC45
/
OCFSRC.PAK
/
AUTOSRV.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-29
|
22KB
|
685 lines
//
//----------------------------------------------------------------------------
// ObjectComponents
// (C) Copyright 1994 by Borland International, All Rights Reserved
//
// OLE Automation Server Implementation, except TServedObject (in typelib.cpp)
//----------------------------------------------------------------------------
#include <ocf/ocfpch.h>
#include <ocf/appdesc.h>
#include <ocf/ocreg.h>
TAutoType TAutoVoid ::ClassInfo = {atVoid};
TAutoType TAutoByte ::ClassInfo = {atByte};
TAutoType TAutoShort ::ClassInfo = {atShort};
TAutoType TAutoLong ::ClassInfo = {atLong};
TAutoType TAutoFloat ::ClassInfo = {atFloat};
TAutoType TAutoDouble ::ClassInfo = {atDouble};
TAutoType TAutoCurrency ::ClassInfo = {atCurrency};
TAutoType TAutoDate ::ClassInfo = {atDatetime};
TAutoType TAutoString ::ClassInfo = {atString};
TAutoType TAutoBool ::ClassInfo = {atBool};
TAutoType TAutoUnknown ::ClassInfo = {atUnknown};
TAutoType TAutoDispatch ::ClassInfo = {atObject};
TAutoType TAutoShortRef ::ClassInfo = {atByRef|atShort};
TAutoType TAutoLongRef ::ClassInfo = {atByRef|atLong};
TAutoType TAutoFloatRef ::ClassInfo = {atByRef|atFloat};
TAutoType TAutoDoubleRef ::ClassInfo = {atByRef|atDouble};
TAutoType TAutoCurrencyRef::ClassInfo = {atByRef|atCurrency};
TAutoType TAutoDateRef ::ClassInfo = {atByRef|atDatetime};
TAutoType TAutoStringRef ::ClassInfo = {atByRef|atString};
TAutoType TAutoVariantRef ::ClassInfo = {atByRef|atVariant};
TAutoType TAutoBoolRef ::ClassInfo = {atByRef|atBool};
TAutoType TAutoByteRef ::ClassInfo = {atByRef|atByte};
void SendObituary(const void far* obj, const typeinfo& typeInfo)
{
TAppDescriptor* appDesc = ::GetAppDescriptor();
if (appDesc)
appDesc->InvalidateObject(::MostDerived(obj, typeInfo));
}
//____________________________________________________________________________
//
// TAutoClass implementation
//____________________________________________________________________________
TAutoClass::TClassList TAutoClass::ClassList = {0,0,0};// MUST BE MODULE GLOBAL
TAutoClass::TAutoClass(TAutoSymbol* table, TAutoSymbol* classSymbol,
const typeinfo& typeInfo, TAggregator aggregator)
: Table(table), ClassSymbol(classSymbol), TypeInfo(typeInfo),
Aggregator(aggregator)
{
Type = atObject | atAutoClass;
NextClass = ClassList.List;
ClassList.List = this;
ClassList.Count++;
}
TAutoClass::~TAutoClass() // do we really need to support dynamic AutoClass?
{
for (TAutoClass** link = &ClassList.List; *link != 0; link = &(*link)->NextClass)
if (*link == this) {
*link = NextClass;
break;
}
}
short TAutoClass::CountCommands()
{
TAutoSymbol* sym;
if (!CommandCount) {
for (sym = Table; !sym->IsTerminator(); sym++) {
int attr = sym->GetFlags();
if (attr & asAnyCommand) {
CommandCount++;
if (attr & asOleType) {
if ((attr & asGetSet) == asGetSet)
VariableCount++;
else
FunctionCount++;
}
} else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
CommandCount += cls->CommandCount;
VariableCount += cls->VariableCount;
FunctionCount += cls->FunctionCount;
}
}
}
return CommandCount;
}
TAutoSymbol* TAutoClass::FindId(short id, ObjectPtr& obj)
{
TAutoSymbol* sym;
int cmdId;
if (id <= 0) { // reserved dispatch ID if negative or zero
for (sym = Table; !sym->IsTerminator(); sym++) {
if (sym->TestFlag(asAnyCommand) && sym->DispId == id)
return sym;
if (sym->TestFlag(asClass)) {
ObjectPtr adjObj = sym->Convert(obj); // this pointer adjustment
TAutoSymbol* fsym = sym->GetClass()->FindId(id, adjObj);
if (fsym) {
obj = adjObj;
return fsym;
}
}
}
} else {
for (cmdId = 0, sym = Table; !sym->IsTerminator(); sym++) {
if (sym->TestFlag(asClass)) {
if (!sym->SymCount)
sym->SymCount = sym->GetClass()->CountCommands();
if (cmdId + sym->SymCount >= id) { // symbol in nested class
obj = sym->Convert(obj);
return sym->GetClass()->FindId(short(id-cmdId), obj);
}
cmdId += sym->SymCount;
}
else if (sym->TestFlag(asAnyCommand)) {
cmdId++;
if (cmdId == id)
return sym;
}
}
}
return 0;
}
TAutoSymbol* TAutoClass::FindFunction(unsigned index, int& retId)
{
TAutoSymbol* sym;
int funcCount = 0;
int cmdId = retId;
for (sym = Table; !sym->IsTerminator(); sym++) {
int attr = sym->GetFlags();
if (attr & asAnyCommand) {
cmdId++;
if ((attr & asOleType) != 0 && (attr & asGetSet) != asGetSet) {
if (funcCount++ == index) {
retId = sym->DispId == -1 ? cmdId : sym->DispId;
return sym;
}
}
} else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
if (funcCount + cls->FunctionCount > index) {
retId = cmdId;
return cls->FindFunction(index - funcCount, retId);
}
funcCount += cls->FunctionCount;
cmdId += cls->CommandCount;
}
}
return 0; // should never happen unless caller overruns total count
}
TAutoSymbol* TAutoClass::FindVariable(unsigned index, int& retId)
{
TAutoSymbol* sym;
int varCount = 0;
int cmdId = retId;
for (sym = Table; !sym->IsTerminator(); sym++) {
int attr = sym->GetFlags();
if (attr & asAnyCommand) {
cmdId++;
if ((attr & asGetSet) == asGetSet) {
if (varCount++ == index) {
retId = sym->DispId == -1 ? cmdId : sym->DispId;
return sym;
}
}
} else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
if (varCount + cls->VariableCount > index) {
retId = cmdId;
return cls->FindVariable(index - varCount, retId);
}
varCount += cls->VariableCount;
cmdId += cls->CommandCount;
}
}
return 0; // should never happen unless caller overruns total count
}
short TAutoClass::GetArgCount(TAutoSymbol& sym)
{
short count = 0;
TAutoSymbol* arg = &sym;
while ((++arg)->TestFlag(asArgument))
count++;
return count;
}
TAutoSymbol* TAutoClass::Lookup(char far* name, TLangId lang, short symflags,
long far& retid)
{
int cmdId = 0;
for (TAutoSymbol* sym = Table; !sym->IsTerminator(); sym++) {
if (sym->TestFlag(asAnyCommand))
cmdId++;
if (sym->TestFlag(symflags) && sym->Name.Compare(name, lang) == 0) {
retid = sym->DispId == -1 ? (long)cmdId : (long)sym->DispId;
return sym;
}
else if (sym->TestFlag(asClass)) {
TAutoClass* cls = sym->GetClass();
if (!sym->SymCount)
sym->SymCount = cls->CountCommands();
long id;
TAutoSymbol* found = cls->Lookup(name, lang, symflags, id);
if (found) {
retid = id > 0 ? id + (long)cmdId : id;
return found;
}
cmdId += sym->SymCount;
}
}
return 0;
}
TAutoSymbol* TAutoClass::LookupArg(char far* name, TLangId lang,
TAutoSymbol* sym, long far& retid)
{
PRECONDITION(sym);
for (int i = 0; (++sym)->TestFlag(asArgument); ++i)
if (sym->Name.Compare(name, lang) == 0) {
retid = (long)i;
return sym;
}
return 0;
}
TAutoCommand* AutoQuitBuild(ObjectPtr obj, int/*attr*/, TAutoStack& args)
{
TServedObject& owner = *args.Owner;
// if the automation object is not in control of the app, execute a no-op
//
if (owner.Destruct == TObjectDescriptor::Quiet)
return new TAutoCommand(0);
// if registered as the active object, free it to release OLE's refcnt
//
if (owner.Creator.AppDesc.IsActiveObject(&owner))
owner.Creator.AppDesc.UnregisterObject();
// disconnect automation from app to prevent further access
//
owner.Object = 0;
owner.RootObject = 0;
// build command object for destructor, will either delete or PostQuitMsg
//
return owner.Class->GetDestructor()(obj, owner.Destruct);
}
TXAuto::TError TAutoClass::Dispatch(ObjectPtr obj, TAutoCreator& creator,
TUnknown& owner, int attr, TAutoStack& args, TAutoVal far* retval)
{
TAutoCommand* cmdobj = 0;
TAutoIterator* iterator = 0;
try {
if (args.Symbol->IsIterator()) {
iterator = args.Symbol->BuildIter(obj, creator, owner, args.LangId);
iterator->SetSymbol(args.Symbol);
iterator->Init();
*retval = (IUnknown*)*iterator; // remains until RefCnt->0
} else {
cmdobj = args.Symbol->Build(obj, attr, args);
cmdobj->SetSymbol(args.Symbol);
if (args.ArgCount>0 && !cmdobj->Validate()) {// no validate for prop get
delete cmdobj;
return TXAuto::xValidateFailure;
}
cmdobj->Invoke();
if ((args.ErrorCode = cmdobj->Report()) != 0) {
args.ErrorMsg = TAutoCommand::LookupError(args.ErrorCode);
if (!args.ErrorMsg && args.Symbol) // if no error message available
args.ErrorMsg = args.Symbol->Name.Translate(args.LangId);
delete cmdobj;
return TXAuto::xErrorStatus;
}
if (retval) {
cmdobj->Return(*retval);
if (args.Symbol->IsEnum())
args.Symbol->GetEnum()->Convert(*retval, args.LangId);
TObjectDescriptor objDesc;
if (retval->GetObjDesc(objDesc)) {
if (!objDesc.Object) // null pointer returned from function
// there are three choices for behavior here:
// 1. Allow a dead object to be returned, fail when passed back
// 2. Fail now, however this prevents testing for null pointer
// 3. Return an empty variant, causing script to fail when used
*retval = TAutoVoid(); // return an empty value if no object
else
*retval = creator.CreateDispatch(objDesc);
}
}
delete cmdobj;
}
}
catch(TXAuto& xobj) {
delete cmdobj;
delete iterator;
return xobj.ErrorCode;
}
return TXAuto::xNoError;
}
TAutoClass::TExtLink::TExtLink(TClassList* list, HINSTANCE module)
: Classes(list), Module(module), Next(0)
{
for (Prev = &ClassList.Link; *Prev; Prev = &(*Prev)->Next)
; // link to end of list
}
TAutoClass::TExtLink::~TExtLink()
{
*Prev = Next;
if (Next)
Next->Prev = Prev;
}
//____________________________________________________________________________
//
// TAutoStack implementation
//____________________________________________________________________________
TAutoStack::TAutoStack(VARIANT far* stack, TLocaleId locale, int argcount,
int named, long far* map, TServedObject* owner)
:
Owner(owner), Stack((TAutoVal far*)stack), LangId(LANGIDFROMLCID(locale)),
ArgCount(argcount), NamedCount(named), NamedIds(map), CurrentArg(-1)
{
}
TAutoStack::~TAutoStack()
{
TAutoVal far* val;
for (val = Stack; ArgCount; --*const_cast<int*>(&ArgCount), val++)
val->Restore();
}
TAutoVal& TAutoStack::operator [](int index)
{
if (index >= ArgSymbolCount /* && index != TAutoStack::SetValue */)
throw TXAuto(TXAuto::xNoArgSymbol);
TAutoSymbol* argSymbol = index >= 0 ? Symbol + index + 1 : Symbol;
int vIndex = ArgCount - index - 1; // index if not a named argument
if (index == TAutoStack::SetValue || // property value to set
index >= ArgCount-NamedCount) { // named or out of range
for (vIndex = NamedCount; --vIndex >= 0; )
if (NamedIds[vIndex] == index) {
break;
}
}
TAutoVal far* val;
if (vIndex >= 0) {
CurrentArg = vIndex; // save index for error return
val = Stack[vIndex].DereferenceVariant();
val->SetLocale(LangId);
if (val->GetDataType() == atString &&
argSymbol->IsEnum() &&
argSymbol->GetEnum()->Convert(*val, Default))
return Default;
}
else if (index == TAutoStack::SetValue) {
throw TXAuto(TXAuto::xParameterMissing);
}
else {
val = &Default;
val->SetLocale(LangId);
const char* dfltStr = argSymbol->Doc.Translate(LangId); // load default
if (!dfltStr)
throw TXAuto(TXAuto::xNoDefaultValue);
Default = dfltStr; // makes a BSTR in order to use OLE conversions
}
return *val;
}
//____________________________________________________________________________
//
// Dynamic casting routines implementation
//____________________________________________________________________________
// temporary defines for using typeinfo with dynamic cast
void far* __cdecl __DynamicCast(void far* object, void far* vtable,
void far* srctyp, void far* dsttyp,
int reference = 0);
struct tpid {int s; short m; short n; int VptrOffs; int Flags;}; // partial
#define CF_HAS_FARVPTR 0x1000
const void far*
DynamicCast(const void far* obj, const typeinfo& src, const typeinfo& dst)
{
int vtblOff;
if (!obj)
return obj;
else if ((vtblOff = src.tpp->VptrOffs) == -1)
return src==dst ? obj : 0;
else if (src.tpp->Flags & CF_HAS_FARVPTR)
return __DynamicCast(const_cast<void far*>(obj),
*(void far**)((char*)obj+vtblOff), src.tpp, dst.tpp);
else
return __DynamicCast(const_cast<void far*>(obj),
*(void near**)((char*)obj+vtblOff), src.tpp,dst.tpp);
}
const void far*
MostDerived(const void far* obj, const typeinfo& src)
{
int vtblOff;
if (!obj || (vtblOff = src.tpp->VptrOffs) == -1)
return obj;
else if (src.tpp->Flags & CF_HAS_FARVPTR)
return __DynamicCast(const_cast<void far*>(obj),
*(void far**)((char*)obj+vtblOff), src.tpp, 0);
else
return __DynamicCast(const_cast<void far*>(obj),
*(void near**)((char*)obj+vtblOff), src.tpp, 0);
}
//____________________________________________________________________________
//
// TAutoCommand implementation - inlined to allow definition of _AUTOCLASS
//____________________________________________________________________________
TAutoCommand::TErrorMsgHook TAutoCommand_ErrorLookup = 0; // module static
TAutoCommand::TCommandHook TAutoCommand_InvokeHook = 0; // module static
//____________________________________________________________________________
//
// TAutoIterator implementation
//____________________________________________________________________________
TAutoIterator::TAutoIterator(TAutoCreator& creator,IUnknown* owner,TLangId lang)
: Creator(creator), Owner(owner), Symbol(0), RefCnt(0), Class(0), Lang(lang) {}
// note: RefCnt = 0 on creation, will ++ in TAutoVal operator(IUnknown*)
TAutoIterator::TAutoIterator(TAutoIterator& copy)
:
Symbol(copy.Symbol), Owner(copy.Owner), Class(copy.Class), Lang(copy.Lang),
Creator(copy.Creator), RefCnt(1)
{
Owner->AddRef();
}
TAutoIterator::~TAutoIterator()
{
Owner->Release();
}
//
// IEnumVARIANT implementation
//
HRESULT _IFUNC
TAutoIterator::QueryInterface(const GUID far& iid, void far*far* pif)
{
if (iid!=IID_IUnknown && iid!=IID_IEnumVARIANT) {
*pif = 0;
return HR_NOINTERFACE;
}
*pif = this;
++RefCnt;
return HR_NOERROR;
}
unsigned long _IFUNC TAutoIterator::AddRef()
{
return ++RefCnt;
}
unsigned long _IFUNC TAutoIterator::Release()
{
return --RefCnt==0 ? delete this,0 : RefCnt;
}
HRESULT _IFUNC TAutoIterator::Next(unsigned long count, VARIANT far* retvals,
unsigned long far* retcount)
{
unsigned long index = 0;
try {
while(index < count) {
if (!Test())
break;
TAutoVal far& retval = ((TAutoVal far*)retvals)[(int)index];
Return(retval);
if (Symbol->IsEnum())
Symbol->GetEnum()->Convert(retval, Lang);
TObjectDescriptor objDesc;
if (retval.GetObjDesc(objDesc)) {
if (!objDesc.Object) // null pointer returned from function
retval = TAutoVoid(); // return an empty value if no object
else
retval = Creator.CreateDispatch(objDesc);
}
Step();
index++;
}
}
catch(...) {
}
if (retcount)
*retcount = index;
return index==count ? HR_NOERROR : HR_FALSE;
}
HRESULT _IFUNC TAutoIterator::Skip(unsigned long count)
{
while(count--) {
if (!Test())
return HR_FALSE;
Step();
}
return HR_NOERROR;
}
HRESULT _IFUNC TAutoIterator::Reset()
{
Init();
return HR_NOERROR;
}
HRESULT _IFUNC TAutoIterator::Clone(IEnumVARIANT* FAR* ppenum)
{
try {
*ppenum = Copy();
return HR_NOERROR;
}
catch (...) {
return HR_OUTOFMEMORY;
}
}
//____________________________________________________________________________
//
// TDispatch implementation
//____________________________________________________________________________
TUnknown* TDispatchCreator::CreateObject(TObjectDescriptor objDesc,
IUnknown* outer)
{
return new TDispatch(objDesc, outer);
}
IDispatch* TDispatchCreator::CreateDispatch(TObjectDescriptor objDesc,
IUnknown* outer)
{
TDispatch* obj = new TDispatch(objDesc, outer);
return *obj;
}
DEFINE_QI_OLEBASE(IDispatch, 0x20400L)
DEFINE_COMBASES1(TDispatchCOM, IDispatch)
TDispatch::TDispatch(TObjectDescriptor& objDesc, IUnknown* outer)
:
Object(const_cast<void*>(objDesc.Object)), Class(objDesc.Class)
{
SetOuter(outer ? outer
: &objDesc.Class->Aggregate(const_cast<void*>(objDesc.Object), *this));
} // note: RefCnt = 0 on creation, will ++ in TAutoVal operator(IDispatch*)
// IDispatch implementation
HRESULT _IFUNC
TDispatch::GetTypeInfoCount(unsigned int far* pctinfo)
{
*pctinfo = 0;
return HR_NOERROR;
}
HRESULT _IFUNC
TDispatch::GetTypeInfo(unsigned int, LCID, ITypeInfo* far*)
{
return HR_NOTIMPL;
}
HRESULT _IFUNC
TDispatch::GetIDsOfNames(const IID far& riid, OLECHAR far* far* names,
unsigned int cNames, LCID lcid, DISPID far* dispIds)
{
if (riid != IID_NULL)
return HR_DISP_UNKNOWNINTERFACE;
HRESULT retval = HR_NOERROR;
TAutoSymbol* symbol;
for (int i = 0; i < cNames; i++) {
dispIds[i] = -1;
if (i == 0) {
symbol = Class->Lookup(OleStr(names[0]), LANGIDFROMLCID(lcid),
asAnyCommand, dispIds[0]);
if (!symbol)
retval = HR_DISP_UNKNOWNNAME;
}
else if (symbol) {
if (!Class->LookupArg(OleStr(names[i]), LANGIDFROMLCID(lcid), symbol, dispIds[i]))
retval = HR_DISP_UNKNOWNNAME;
}
}
return retval;
}
HRESULT _IFUNC
TDispatch::Invoke(DISPID dispidMember, const IID far& /*riid*/, LCID lcid,
unsigned short wFlags, DISPPARAMS far* dispparams,
VARIANT far* varResult, EXCEPINFO far* exceptInfo,
unsigned int far* retArgErr)
{
ObjectPtr object = Object; // make copy in case of this pointer adjustment
if (!object) // check if C++ object still exists
return HR_DISP_MEMBERNOTFOUND;
TAutoStack stack(dispparams->rgvarg, lcid, dispparams->cArgs,
dispparams->cNamedArgs, dispparams->rgdispidNamedArgs, 0);
stack.Symbol = Class->FindId((short)dispidMember, object);
if (!stack.Symbol)
return HR_DISP_MEMBERNOTFOUND;
if (!stack.Symbol->TestFlag(wFlags)) // check attr bits for supported type
return HR_DISP_MEMBERNOTFOUND;
if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
varResult = 0;
if ((stack.ArgSymbolCount=Class->GetArgCount(*stack.Symbol)) +
((wFlags&(DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF))!=0) < stack.ArgCount)
return HR_DISP_BADPARAMCOUNT;
switch(Class->Dispatch(object, TDispatchCreator(), *this, wFlags, stack,
(TAutoVal far*)varResult)) {
case TXAuto::xNoError:
return HR_NOERROR;
case TXAuto::xNotIDispatch:
case TXAuto::xForeignIDispatch:
return HR_DISP_BADVARTYPE;
case TXAuto::xValidateFailure:
*retArgErr = stack.CurrentArg;
return HR_DISP_OVERFLOW;
case TXAuto::xConversionFailure:
case TXAuto::xTypeMismatch:
*retArgErr = stack.CurrentArg;
return HR_DISP_TYPEMISMATCH;
case TXAuto::xNoArgSymbol:
*retArgErr = stack.CurrentArg;
return HR_DISP_PARAMNOTFOUND;
case TXAuto::xParameterMissing:
case TXAuto::xNoDefaultValue:
return HR_DISP_PARAMNOTOPTIONAL;
case TXAuto::xErrorStatus:
if (exceptInfo) {
exceptInfo->wCode = (unsigned short)stack.ErrorCode;
exceptInfo->wReserved = 0;
exceptInfo->bstrSource = 0; //::SysAllocString(AppDesc.GetAppName(LANGIDFROMLCID(lcid)));
exceptInfo->bstrDescription = ::SysAllocString(stack.ErrorMsg);
exceptInfo->bstrHelpFile = 0;
exceptInfo->pfnDeferredFillIn = 0;
exceptInfo->scode = E_FAIL; // how to get better code? matters?
}
return HR_DISP_EXCEPTION;
case TXAuto::xExecutionFailure:
default:
return HR_DISP_OVERFLOW; // no appropriate error for other
}
}