//----------------------------------------------------------------------------
// ObjectComponents
// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
//
/// \file
/// OLE Automation Server Implementation, except TServedObject (in typelib.cpp)
//----------------------------------------------------------------------------
#include <ocf/pch.h>
#include <ocf/appdesc.h>
#include <ocf/ocreg.h>
#include <ocf/occtrl.h>
namespace ocf {
using namespace owl;
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 TAutoVariant ::ClassInfo = {atVariant};
TAutoType TAutoSafeArray ::ClassInfo = {atSafeArray};
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};
_OCFFUNC(void) SendObituary(const void * obj, const std::type_info& typeInfo)
{
TAppDescriptor* appDesc = ocf::GetAppDescriptor();
if (appDesc)
appDesc->InvalidateObject(ocf::MostDerived(obj, typeInfo));
}
//----------------------------------------------------------------------------
// TAutoClass implementation
//
TAutoClass::TClassList TAutoClass::ClassList = {0,0,0};// MUST BE MODULE GLOBAL
TAutoClass::TAutoClass(TAutoSymbol* table, TAutoSymbol* classSymbol,
const std::type_info& typeInfo, TAggregator aggregator)
: Table(table), ClassSymbol(classSymbol), TypeInfo(typeInfo),
Aggregator(aggregator), AutoIds (TRUE)
{
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(long id, ObjectPtr& obj)
{
TAutoSymbol* sym;
long cmdId;
if ((id <= 0) || !(AutoIds)) {
// reserved dispatch ID if negative or zero or AutoIDs is false
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(id-cmdId, obj);
}
cmdId += sym->SymCount;
}
else if (sym->TestFlag(asAnyCommand)) {
cmdId++;
if (cmdId == id) {
if (sym->DispId == -1)
return sym;
else
break;
}
}
}
}
return 0;
}
TAutoSymbol* TAutoClass::FindFunction(unsigned index, MEMBERID& retId)
{
TAutoSymbol* sym;
int funcCount = 0;
long 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++ == (int)index) {
retId = (sym->DispId == -1L) ? 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 > (int)index) {
retId = int(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, MEMBERID& retId)
{
TAutoSymbol* sym;
int varCount = 0;
long cmdId = retId;
for (sym = Table; !sym->IsTerminator(); sym++) {
int attr = sym->GetFlags();
if (attr & asAnyCommand) {
cmdId++;
if ((attr & asGetSet) == asGetSet) {
if (varCount++ == (int)index) {
retId = (sym->DispId == -1L) ? 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 > (int)index){
retId = int(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(_TCHAR * name, TLangId lang, short symflags,
long & retid)
{
long 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 ? cmdId : 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(_TCHAR * name, TLangId lang,
TAutoSymbol* sym, long & 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;
}
TXAuto::TError TAutoClass::Dispatch(ObjectPtr obj, TAutoCreator& creator,
TUnknown& owner, int attr,
TAutoStack& args, TAutoVal* 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;
}
//
//
//
int
TAutoClass::TClassList::CountAutoClasses()
{
int count = Count;
for (TExtLink* link = Link; link; link = link->Next)
count += link->Classes->CountAutoClasses();
return count;
}
//
//
//
TAutoClass::TAutoClassRef*
TAutoClass::TClassList::MergeAutoClasses(TAutoClass::TAutoClassRef* array)
{
for (TAutoClass* cls = List; cls; cls = cls->NextClass, array++)
array->Class = cls;
for (TExtLink* link = Link; link; link = link->Next)
array = link->Classes->MergeAutoClasses(array);
return array;
}
// ----------------------------------------------------------------------
// Helper routines
//
//
//
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.GetAppDesc().IsActiveObject(&owner))
owner.Creator.GetAppDesc().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);
}
#if defined(BI_COMP_BORLANDC)
} // OCF namespace
//
// Temporary defines for using std::type_info with dynamic cast
//
void* __cdecl __DynamicCast(void* object, void* vtable,
void* srctyp, void* dsttyp,
int reference = 0);
struct tpid {int s; short m; short n; int VptrOffs; int Flags;}; // partial
namespace ocf {
#endif
//
//
const void*
DynamicCast(const void* obj, const std::type_info& src, const std::type_info& dst)
{
#if defined(__clang__) // TODO: This needs review!
return __DynamicCast((void*)obj, 0, (void*)&src, (void*)&dst, 0);
#elif defined(BI_COMP_BORLANDC)
int vtblOff;
if (!obj)
return obj;
else if ((vtblOff = src.tpp->VptrOffs) == -1)
return src==dst ? obj : 0;
else
return __DynamicCast(const_cast<void *>(obj),
*(void **)((char*)obj+vtblOff), src.tpp,dst.tpp);
#else
return __RTDynamicCast((void*)obj,0,(void*)&src,(void*)&dst,0);
#endif //BI_COMP_BORLANDC
}
//
//
const void *
MostDerived(const void * obj, const std::type_info& src)
{
#if defined(BI_COMP_BORLANDC) && !defined(__clang__) // TODO: This needs review for Clang!
int vtblOff;
if (!obj || (vtblOff = src.tpp->VptrOffs) == -1)
return obj;
else
return __DynamicCast(const_cast<void *>(obj),
*(void **)((char*)obj+vtblOff), src.tpp, 0);
#else
return obj;
#endif
}
//____________________________________________________________________________
//
// TAutoCommand implementation - inlined to allow definition of _AUTOCLASS
//____________________________________________________________________________
_OCFDATA(TAutoCommand::TErrorMsgHook) TAutoCommand_ErrorLookup = 0; // module static
_OCFDATA(TAutoCommand::TCommandHook) TAutoCommand_InvokeHook = 0; // module static
} // OCF namespace
//==============================================================================
↑ V595 The 'args.Symbol' pointer was utilized before it was verified against nullptr. Check lines: 269, 278.
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: CommandCount, FunctionCount, VariableCount.
↑ V522 There might be dereferencing of a potential null pointer 'cls'.
↑ V522 There might be dereferencing of a potential null pointer 'sym->GetClass()'.
↑ V522 There might be dereferencing of a potential null pointer 'cls'.
↑ V522 There might be dereferencing of a potential null pointer 'cls'.
↑ V522 There might be dereferencing of a potential null pointer 'cls'.
↑ V522 There might be dereferencing of a potential null pointer 'args.Symbol->GetEnum()'.