home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / ocfsrc.pak / AUTOSRV.CPP < prev    next >
C/C++ Source or Header  |  1997-07-23  |  22KB  |  685 lines

  1. //
  2. //----------------------------------------------------------------------------
  3. // ObjectComponents
  4. // (C) Copyright 1994 by Borland International, All Rights Reserved
  5. //
  6. // OLE Automation Server Implementation, except TServedObject (in typelib.cpp)
  7. //----------------------------------------------------------------------------
  8. #include <ocf/ocfpch.h>
  9. #include <ocf/appdesc.h>
  10. #include <ocf/ocreg.h>
  11.  
  12. TAutoType TAutoVoid       ::ClassInfo = {atVoid};
  13. TAutoType TAutoByte       ::ClassInfo = {atByte};
  14. TAutoType TAutoShort      ::ClassInfo = {atShort};
  15. TAutoType TAutoLong       ::ClassInfo = {atLong};
  16. TAutoType TAutoFloat      ::ClassInfo = {atFloat};
  17. TAutoType TAutoDouble     ::ClassInfo = {atDouble};
  18. TAutoType TAutoCurrency   ::ClassInfo = {atCurrency};
  19. TAutoType TAutoDate       ::ClassInfo = {atDatetime};
  20. TAutoType TAutoString     ::ClassInfo = {atString};
  21. TAutoType TAutoBool       ::ClassInfo = {atBool};
  22. TAutoType TAutoUnknown    ::ClassInfo = {atUnknown};
  23. TAutoType TAutoDispatch   ::ClassInfo = {atObject};
  24. TAutoType TAutoShortRef   ::ClassInfo = {atByRef|atShort};
  25. TAutoType TAutoLongRef    ::ClassInfo = {atByRef|atLong};
  26. TAutoType TAutoFloatRef   ::ClassInfo = {atByRef|atFloat};
  27. TAutoType TAutoDoubleRef  ::ClassInfo = {atByRef|atDouble};
  28. TAutoType TAutoCurrencyRef::ClassInfo = {atByRef|atCurrency};
  29. TAutoType TAutoDateRef    ::ClassInfo = {atByRef|atDatetime};
  30. TAutoType TAutoStringRef  ::ClassInfo = {atByRef|atString};
  31. TAutoType TAutoVariantRef ::ClassInfo = {atByRef|atVariant};
  32. TAutoType TAutoBoolRef    ::ClassInfo = {atByRef|atBool};
  33. TAutoType TAutoByteRef    ::ClassInfo = {atByRef|atByte};
  34.  
  35. void SendObituary(const void far* obj, const typeinfo& typeInfo)
  36. {
  37.   TAppDescriptor* appDesc = ::GetAppDescriptor();
  38.   if (appDesc)
  39.     appDesc->InvalidateObject(::MostDerived(obj, typeInfo));
  40. }
  41.  
  42. //____________________________________________________________________________
  43. //
  44. // TAutoClass implementation
  45. //____________________________________________________________________________
  46.  
  47. TAutoClass::TClassList TAutoClass::ClassList = {0,0,0};// MUST BE MODULE GLOBAL
  48.  
  49. TAutoClass::TAutoClass(TAutoSymbol* table, TAutoSymbol* classSymbol,
  50.              const typeinfo& typeInfo, TAggregator aggregator)
  51.            : Table(table), ClassSymbol(classSymbol), TypeInfo(typeInfo),
  52.              Aggregator(aggregator)
  53. {
  54.   Type = atObject | atAutoClass;
  55.   NextClass = ClassList.List;
  56.   ClassList.List = this;
  57.   ClassList.Count++;
  58. }
  59.  
  60. TAutoClass::~TAutoClass()  // do we really need to support dynamic AutoClass?
  61. {
  62.   for (TAutoClass** link = &ClassList.List; *link != 0; link = &(*link)->NextClass)
  63.     if (*link == this) {
  64.       *link = NextClass;
  65.       break;
  66.     }
  67. }
  68.  
  69. short TAutoClass::CountCommands()
  70. {
  71.   TAutoSymbol* sym;
  72.   if (!CommandCount) {
  73.     for (sym = Table; !sym->IsTerminator(); sym++) {
  74.       int attr = sym->GetFlags();
  75.       if (attr & asAnyCommand) {
  76.         CommandCount++;
  77.         if (attr & asOleType) {
  78.           if ((attr & asGetSet) == asGetSet)
  79.             VariableCount++;
  80.           else
  81.             FunctionCount++;
  82.         }
  83.       } else if (sym->TestFlag(asClass)) {
  84.         TAutoClass* cls = sym->GetClass();
  85.         if (!sym->SymCount)
  86.           sym->SymCount = cls->CountCommands();
  87.         CommandCount  += cls->CommandCount;
  88.         VariableCount += cls->VariableCount;
  89.         FunctionCount += cls->FunctionCount;
  90.       }
  91.     }
  92.   }
  93.   return CommandCount;
  94. }
  95.  
  96. TAutoSymbol* TAutoClass::FindId(short id, ObjectPtr& obj)
  97. {
  98.   TAutoSymbol* sym;
  99.   int cmdId;
  100.   if (id <= 0) {         // reserved dispatch ID if negative or zero
  101.     for (sym = Table; !sym->IsTerminator(); sym++) {
  102.       if (sym->TestFlag(asAnyCommand) && sym->DispId == id)
  103.         return sym;
  104.  
  105.       if (sym->TestFlag(asClass)) {
  106.         ObjectPtr adjObj = sym->Convert(obj);  // this pointer adjustment
  107.         TAutoSymbol* fsym = sym->GetClass()->FindId(id, adjObj);
  108.         if (fsym) {
  109.           obj = adjObj;
  110.           return fsym;
  111.         }
  112.       }
  113.     }
  114.   } else {
  115.     for (cmdId = 0, sym = Table; !sym->IsTerminator(); sym++) {
  116.       if (sym->TestFlag(asClass)) {
  117.         if (!sym->SymCount)
  118.           sym->SymCount = sym->GetClass()->CountCommands();
  119.         if (cmdId + sym->SymCount >= id) {    // symbol in nested class
  120.           obj = sym->Convert(obj);
  121.           return sym->GetClass()->FindId(short(id-cmdId), obj);
  122.         }
  123.         cmdId += sym->SymCount;
  124.       }
  125.       else if (sym->TestFlag(asAnyCommand)) {
  126.         cmdId++;
  127.         if (cmdId == id)
  128.           return sym;
  129.       }
  130.     }
  131.   }
  132.   return 0;
  133. }
  134.  
  135. TAutoSymbol* TAutoClass::FindFunction(unsigned index, int& retId)
  136. {
  137.   TAutoSymbol* sym;
  138.   int funcCount = 0;
  139.   int cmdId = retId;
  140.   for (sym = Table; !sym->IsTerminator(); sym++) {
  141.     int attr = sym->GetFlags();
  142.     if (attr & asAnyCommand) {
  143.       cmdId++;
  144.       if ((attr & asOleType) != 0 && (attr & asGetSet) != asGetSet) {
  145.         if (funcCount++ == index) {
  146.           retId = sym->DispId == -1 ? cmdId : sym->DispId;
  147.           return sym;
  148.         }
  149.       }
  150.     } else if (sym->TestFlag(asClass)) {
  151.       TAutoClass* cls = sym->GetClass();
  152.       if (!sym->SymCount)
  153.         sym->SymCount = cls->CountCommands();
  154.       if (funcCount + cls->FunctionCount > index) {
  155.         retId = cmdId;
  156.         return cls->FindFunction(index - funcCount, retId);
  157.       }
  158.       funcCount += cls->FunctionCount;
  159.       cmdId     += cls->CommandCount;
  160.     }
  161.   }
  162.   return 0;  // should never happen unless caller overruns total count
  163. }
  164.  
  165. TAutoSymbol* TAutoClass::FindVariable(unsigned index, int& retId)
  166. {
  167.   TAutoSymbol* sym;
  168.   int varCount = 0;
  169.   int cmdId = retId;
  170.   for (sym = Table; !sym->IsTerminator(); sym++) {
  171.     int attr = sym->GetFlags();
  172.     if (attr & asAnyCommand) {
  173.       cmdId++;
  174.       if ((attr & asGetSet) == asGetSet) {
  175.         if (varCount++ == index) {
  176.           retId = sym->DispId == -1 ? cmdId : sym->DispId;
  177.           return sym;
  178.         }
  179.       }
  180.     } else if (sym->TestFlag(asClass)) {
  181.       TAutoClass* cls = sym->GetClass();
  182.       if (!sym->SymCount)
  183.         sym->SymCount = cls->CountCommands();
  184.       if (varCount + cls->VariableCount > index) {
  185.         retId = cmdId;
  186.         return cls->FindVariable(index - varCount, retId);
  187.       }
  188.       varCount += cls->VariableCount;
  189.       cmdId    += cls->CommandCount;
  190.     }
  191.   }
  192.   return 0;  // should never happen unless caller overruns total count
  193. }
  194.  
  195. short TAutoClass::GetArgCount(TAutoSymbol& sym)
  196. {
  197.   short count = 0;
  198.   TAutoSymbol* arg = &sym;
  199.   while ((++arg)->TestFlag(asArgument))
  200.     count++;
  201.   return count;
  202. }
  203.  
  204. TAutoSymbol* TAutoClass::Lookup(char far* name, TLangId lang, short symflags,
  205.                                 long far& retid)
  206. {
  207.   int cmdId = 0;
  208.   for (TAutoSymbol* sym = Table; !sym->IsTerminator(); sym++) {
  209.     if (sym->TestFlag(asAnyCommand))
  210.       cmdId++;
  211.     if (sym->TestFlag(symflags) && sym->Name.Compare(name, lang) == 0) {
  212.       retid = sym->DispId == -1 ? (long)cmdId : (long)sym->DispId;
  213.       return sym;
  214.     }
  215.     else if (sym->TestFlag(asClass)) {
  216.       TAutoClass* cls = sym->GetClass();
  217.       if (!sym->SymCount)
  218.         sym->SymCount = cls->CountCommands();
  219.       long id;
  220.       TAutoSymbol* found = cls->Lookup(name, lang, symflags, id);
  221.       if (found) {
  222.         retid = id > 0 ? id + (long)cmdId : id;
  223.         return found;
  224.       }
  225.       cmdId += sym->SymCount;
  226.     }
  227.   }
  228.   return 0;
  229. }
  230.  
  231. TAutoSymbol* TAutoClass::LookupArg(char far* name, TLangId lang,
  232.                                    TAutoSymbol* sym, long far& retid)
  233. {
  234.   PRECONDITION(sym);
  235.  
  236.    for (int i = 0; (++sym)->TestFlag(asArgument); ++i)
  237.      if (sym->Name.Compare(name, lang) == 0) {
  238.        retid = (long)i;
  239.        return sym;
  240.      }
  241.    return 0;
  242. }
  243.  
  244. TAutoCommand* AutoQuitBuild(ObjectPtr obj, int/*attr*/, TAutoStack& args)
  245. {
  246.   TServedObject& owner = *args.Owner;
  247.  
  248.   // if the automation object is not in control of the app, execute a no-op
  249.   //
  250.   if (owner.Destruct == TObjectDescriptor::Quiet)
  251.     return new TAutoCommand(0);
  252.  
  253.   // if registered as the active object, free it to release OLE's refcnt
  254.   //
  255.   if (owner.Creator.AppDesc.IsActiveObject(&owner))
  256.     owner.Creator.AppDesc.UnregisterObject();
  257.  
  258.   // disconnect automation from app to prevent further access
  259.   //
  260.   owner.Object = 0; 
  261.   owner.RootObject = 0;
  262.  
  263.   // build command object for destructor, will either delete or PostQuitMsg
  264.   //
  265.   return owner.Class->GetDestructor()(obj, owner.Destruct);
  266. }
  267.  
  268. TXAuto::TError TAutoClass::Dispatch(ObjectPtr obj, TAutoCreator& creator,
  269.             TUnknown& owner, int attr, TAutoStack& args, TAutoVal far* retval)
  270. {
  271.   TAutoCommand*  cmdobj = 0;
  272.   TAutoIterator* iterator = 0;
  273.   try {
  274.     if (args.Symbol->IsIterator()) {
  275.       iterator = args.Symbol->BuildIter(obj, creator, owner, args.LangId);
  276.       iterator->SetSymbol(args.Symbol);
  277.       iterator->Init();
  278.       *retval = (IUnknown*)*iterator; // remains until RefCnt->0
  279.     } else {
  280.       cmdobj = args.Symbol->Build(obj, attr, args);
  281.       cmdobj->SetSymbol(args.Symbol);
  282.       if (args.ArgCount>0 && !cmdobj->Validate()) {// no validate for prop get
  283.         delete cmdobj;
  284.         return TXAuto::xValidateFailure;
  285.       }
  286.       cmdobj->Invoke();
  287.       if ((args.ErrorCode = cmdobj->Report()) != 0) {
  288.         args.ErrorMsg = TAutoCommand::LookupError(args.ErrorCode);
  289.         if (!args.ErrorMsg && args.Symbol)  // if no error message available
  290.           args.ErrorMsg = args.Symbol->Name.Translate(args.LangId);
  291.         delete cmdobj;
  292.         return TXAuto::xErrorStatus;
  293.       }
  294.       if (retval) {
  295.         cmdobj->Return(*retval);
  296.         if (args.Symbol->IsEnum())
  297.           args.Symbol->GetEnum()->Convert(*retval, args.LangId);
  298.         TObjectDescriptor objDesc;
  299.         if (retval->GetObjDesc(objDesc)) {
  300.           if (!objDesc.Object)     // null pointer returned from function
  301.             // there are three choices for behavior here:
  302.             // 1. Allow a dead object to be returned, fail when passed back
  303.             // 2. Fail now, however this prevents testing for null pointer
  304.             // 3. Return an empty variant, causing script to fail when used
  305.             *retval = TAutoVoid();  // return an empty value if no object
  306.           else
  307.             *retval = creator.CreateDispatch(objDesc);
  308.         }
  309.       }
  310.       delete cmdobj;
  311.     }
  312.   }
  313.   catch(TXAuto& xobj) {
  314.     delete cmdobj;
  315.     delete iterator;
  316.     return xobj.ErrorCode;
  317.   }
  318.   return TXAuto::xNoError;
  319. }
  320.  
  321. TAutoClass::TExtLink::TExtLink(TClassList* list, HINSTANCE module)
  322.            : Classes(list), Module(module), Next(0)
  323. {
  324.   for (Prev = &ClassList.Link; *Prev; Prev = &(*Prev)->Next)
  325.     ;               // link to end of list
  326. }
  327.  
  328. TAutoClass::TExtLink::~TExtLink()
  329. {
  330.   *Prev = Next;
  331.   if (Next)
  332.     Next->Prev = Prev;
  333. }
  334.  
  335. //____________________________________________________________________________
  336. //
  337. // TAutoStack implementation
  338. //____________________________________________________________________________
  339.  
  340. TAutoStack::TAutoStack(VARIANT far* stack, TLocaleId locale, int argcount,
  341.                        int named, long far* map, TServedObject* owner)
  342. :
  343.   Owner(owner), Stack((TAutoVal far*)stack), LangId(LANGIDFROMLCID(locale)),
  344.   ArgCount(argcount), NamedCount(named), NamedIds(map), CurrentArg(-1)
  345. {
  346. }
  347.  
  348. TAutoStack::~TAutoStack()
  349. {
  350.   TAutoVal far* val;
  351.   for (val = Stack; ArgCount; --*const_cast<int*>(&ArgCount), val++)
  352.     val->Restore();
  353. }
  354.  
  355. TAutoVal& TAutoStack::operator [](int index)
  356. {
  357.   if (index >= ArgSymbolCount /* && index != TAutoStack::SetValue */)
  358.     throw TXAuto(TXAuto::xNoArgSymbol);
  359.   TAutoSymbol* argSymbol = index >= 0 ? Symbol + index + 1 : Symbol;
  360.   int vIndex = ArgCount - index - 1;        // index if not a named argument
  361.   if (index == TAutoStack::SetValue ||      // property value to set
  362.       index >= ArgCount-NamedCount) { // named or out of range
  363.     for (vIndex = NamedCount; --vIndex >= 0; )
  364.       if (NamedIds[vIndex] == index) {
  365.         break;
  366.       }
  367.   }
  368.   TAutoVal far* val;
  369.   if (vIndex >= 0) {
  370.     CurrentArg = vIndex;   // save index for error return
  371.     val = Stack[vIndex].DereferenceVariant();
  372.     val->SetLocale(LangId);
  373.     if (val->GetDataType() == atString &&
  374.         argSymbol->IsEnum() &&
  375.         argSymbol->GetEnum()->Convert(*val, Default))
  376.       return Default;
  377.   }
  378.   else if (index == TAutoStack::SetValue) {
  379.     throw TXAuto(TXAuto::xParameterMissing);
  380.   }
  381.   else {
  382.     val = &Default;
  383.     val->SetLocale(LangId);
  384.     const char* dfltStr = argSymbol->Doc.Translate(LangId); // load default
  385.     if (!dfltStr)
  386.       throw TXAuto(TXAuto::xNoDefaultValue);
  387.     Default = dfltStr;    // makes a BSTR in order to use OLE conversions
  388.   }
  389.   return *val;
  390. }
  391.  
  392. //____________________________________________________________________________
  393. //
  394. // Dynamic casting routines implementation
  395. //____________________________________________________________________________
  396.  
  397. // temporary defines for using typeinfo with dynamic cast
  398.  
  399. void far* __cdecl __DynamicCast(void far* object, void far* vtable,
  400.                                 void far* srctyp, void far* dsttyp,
  401.                                 int reference = 0);
  402. struct tpid {int s; short m; short n; int VptrOffs; int Flags;};  // partial
  403. #define CF_HAS_FARVPTR  0x1000
  404.  
  405. const void far*
  406. DynamicCast(const void far* obj, const typeinfo& src, const typeinfo& dst)
  407. {
  408.   int vtblOff;
  409.   if (!obj)
  410.     return obj;
  411.   else if ((vtblOff = src.tpp->VptrOffs) == -1)
  412.     return src==dst ? obj : 0;
  413.   else if (src.tpp->Flags & CF_HAS_FARVPTR)
  414.     return __DynamicCast(const_cast<void far*>(obj),
  415.                          *(void far**)((char*)obj+vtblOff), src.tpp, dst.tpp);
  416.   else
  417.     return __DynamicCast(const_cast<void far*>(obj),
  418.                          *(void near**)((char*)obj+vtblOff), src.tpp,dst.tpp);
  419. }
  420.  
  421. const void far*
  422. MostDerived(const void far* obj, const typeinfo& src)
  423. {
  424.   int vtblOff;
  425.   if (!obj || (vtblOff = src.tpp->VptrOffs) == -1)
  426.     return obj;
  427.  
  428.   else if (src.tpp->Flags & CF_HAS_FARVPTR)
  429.     return __DynamicCast(const_cast<void far*>(obj),
  430.                          *(void far**)((char*)obj+vtblOff), src.tpp, 0);
  431.   else
  432.     return __DynamicCast(const_cast<void far*>(obj),
  433.                          *(void near**)((char*)obj+vtblOff), src.tpp, 0);
  434. }
  435.  
  436. //____________________________________________________________________________
  437. //
  438. // TAutoCommand implementation - inlined to allow definition of _AUTOCLASS
  439. //____________________________________________________________________________
  440.  
  441. TAutoCommand::TErrorMsgHook TAutoCommand_ErrorLookup = 0; // module static
  442.  
  443. TAutoCommand::TCommandHook  TAutoCommand_InvokeHook = 0;  // module static
  444.  
  445. //____________________________________________________________________________
  446. //
  447. // TAutoIterator implementation
  448. //____________________________________________________________________________
  449.  
  450. TAutoIterator::TAutoIterator(TAutoCreator& creator,IUnknown* owner,TLangId lang)
  451. : Creator(creator), Owner(owner), Symbol(0), RefCnt(0), Class(0), Lang(lang) {}
  452.      // note: RefCnt = 0 on creation, will ++ in TAutoVal operator(IUnknown*)
  453.  
  454. TAutoIterator::TAutoIterator(TAutoIterator& copy)
  455. :
  456.   Symbol(copy.Symbol), Owner(copy.Owner), Class(copy.Class), Lang(copy.Lang),
  457.   Creator(copy.Creator), RefCnt(1)
  458. {
  459.   Owner->AddRef();
  460. }
  461.  
  462. TAutoIterator::~TAutoIterator()
  463. {
  464.   Owner->Release();
  465. }
  466.  
  467. //
  468. // IEnumVARIANT implementation
  469. //
  470.  
  471. HRESULT _IFUNC
  472. TAutoIterator::QueryInterface(const GUID far& iid, void far*far* pif)
  473. {
  474.   if (iid!=IID_IUnknown && iid!=IID_IEnumVARIANT) {
  475.     *pif = 0;
  476.     return HR_NOINTERFACE;
  477.   }
  478.   *pif = this;
  479.   ++RefCnt;
  480.   return HR_NOERROR;
  481. }
  482. unsigned long _IFUNC TAutoIterator::AddRef()
  483. {
  484.   return ++RefCnt;
  485. }
  486. unsigned long _IFUNC TAutoIterator::Release()
  487. {
  488.   return --RefCnt==0 ? delete this,0 : RefCnt;
  489. }
  490.  
  491. HRESULT _IFUNC TAutoIterator::Next(unsigned long count, VARIANT far* retvals,
  492.                     unsigned long far* retcount)
  493. {
  494.   unsigned long index = 0;
  495.   try {
  496.     while(index < count) {
  497.       if (!Test())
  498.         break;
  499.       TAutoVal far& retval = ((TAutoVal far*)retvals)[(int)index];
  500.       Return(retval);
  501.       if (Symbol->IsEnum())
  502.         Symbol->GetEnum()->Convert(retval, Lang);
  503.       TObjectDescriptor objDesc;
  504.       if (retval.GetObjDesc(objDesc)) {
  505.         if (!objDesc.Object)     // null pointer returned from function
  506.           retval = TAutoVoid();  // return an empty value if no object
  507.         else
  508.           retval = Creator.CreateDispatch(objDesc);
  509.       }
  510.       Step();
  511.       index++;
  512.     }
  513.   }
  514.   catch(...) {
  515.   }
  516.   if (retcount)
  517.     *retcount = index;
  518.   return index==count ? HR_NOERROR : HR_FALSE;
  519. }
  520.  
  521. HRESULT _IFUNC TAutoIterator::Skip(unsigned long count)
  522. {
  523.   while(count--) {
  524.     if (!Test())
  525.       return HR_FALSE;
  526.     Step();
  527.   }
  528.   return HR_NOERROR;
  529. }
  530.  
  531. HRESULT _IFUNC TAutoIterator::Reset()
  532. {
  533.   Init();
  534.   return HR_NOERROR;
  535. }
  536.  
  537. HRESULT _IFUNC TAutoIterator::Clone(IEnumVARIANT* FAR* ppenum)
  538. {
  539.   try {
  540.     *ppenum = Copy();
  541.     return HR_NOERROR;
  542.   }
  543.   catch (...) {
  544.     return HR_OUTOFMEMORY;
  545.   }
  546. }
  547.  
  548. //____________________________________________________________________________
  549. //
  550. // TDispatch implementation
  551. //____________________________________________________________________________
  552.  
  553. TUnknown* TDispatchCreator::CreateObject(TObjectDescriptor objDesc,
  554.                                    IUnknown* outer)
  555. {
  556.   return new TDispatch(objDesc, outer);
  557. }
  558.  
  559. IDispatch* TDispatchCreator::CreateDispatch(TObjectDescriptor objDesc,
  560.                                             IUnknown* outer)
  561. {
  562.   TDispatch* obj = new TDispatch(objDesc, outer);
  563.   return *obj;
  564. }
  565.  
  566. DEFINE_QI_OLEBASE(IDispatch,      0x20400L)
  567.  
  568. DEFINE_COMBASES1(TDispatchCOM, IDispatch)
  569.  
  570. TDispatch::TDispatch(TObjectDescriptor& objDesc, IUnknown* outer)
  571. :
  572.   Object(const_cast<void*>(objDesc.Object)), Class(objDesc.Class)
  573. {
  574.   SetOuter(outer ? outer
  575.        : &objDesc.Class->Aggregate(const_cast<void*>(objDesc.Object), *this));
  576. } // note: RefCnt = 0 on creation, will ++ in TAutoVal operator(IDispatch*)
  577.  
  578. // IDispatch implementation
  579.  
  580. HRESULT _IFUNC
  581. TDispatch::GetTypeInfoCount(unsigned int far* pctinfo)
  582. {
  583.   *pctinfo = 0;
  584.   return HR_NOERROR;
  585. }
  586.  
  587. HRESULT _IFUNC
  588. TDispatch::GetTypeInfo(unsigned int, LCID, ITypeInfo* far*)
  589. {
  590.   return HR_NOTIMPL;
  591. }
  592.  
  593. HRESULT _IFUNC
  594. TDispatch::GetIDsOfNames(const IID far& riid, OLECHAR far* far* names,
  595.                           unsigned int cNames, LCID lcid, DISPID far* dispIds)
  596. {
  597.   if (riid != IID_NULL)
  598.     return HR_DISP_UNKNOWNINTERFACE;
  599.  
  600.   HRESULT retval = HR_NOERROR;
  601.   TAutoSymbol* symbol;
  602.   for (int i = 0; i < cNames; i++) {
  603.     dispIds[i] = -1;
  604.     if (i == 0) {
  605.     symbol = Class->Lookup(OleStr(names[0]), LANGIDFROMLCID(lcid),
  606.                            asAnyCommand, dispIds[0]);
  607.       if (!symbol)
  608.         retval = HR_DISP_UNKNOWNNAME;
  609.     }
  610.     else if (symbol) {
  611.       if (!Class->LookupArg(OleStr(names[i]), LANGIDFROMLCID(lcid), symbol, dispIds[i]))
  612.         retval = HR_DISP_UNKNOWNNAME;
  613.     }
  614.   }
  615.   return retval;
  616. }
  617.  
  618. HRESULT _IFUNC
  619. TDispatch::Invoke(DISPID dispidMember, const IID far& /*riid*/, LCID lcid,
  620.                       unsigned short wFlags, DISPPARAMS far* dispparams,
  621.                       VARIANT far* varResult, EXCEPINFO far* exceptInfo,
  622.                       unsigned int far* retArgErr)
  623. {
  624.   ObjectPtr object = Object;  // make copy in case of this pointer adjustment
  625.   if (!object)      // check if C++ object still exists
  626.     return HR_DISP_MEMBERNOTFOUND;
  627.   TAutoStack stack(dispparams->rgvarg, lcid, dispparams->cArgs,
  628.                    dispparams->cNamedArgs, dispparams->rgdispidNamedArgs, 0);
  629.   stack.Symbol = Class->FindId((short)dispidMember, object);
  630.   if (!stack.Symbol)
  631.     return HR_DISP_MEMBERNOTFOUND;
  632.   if (!stack.Symbol->TestFlag(wFlags)) // check attr bits for supported type
  633.     return HR_DISP_MEMBERNOTFOUND;
  634.   if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
  635.     varResult = 0;
  636.   if ((stack.ArgSymbolCount=Class->GetArgCount(*stack.Symbol)) +
  637.   ((wFlags&(DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF))!=0) < stack.ArgCount)
  638.     return HR_DISP_BADPARAMCOUNT;
  639.  
  640.   switch(Class->Dispatch(object, TDispatchCreator(), *this, wFlags, stack,
  641.                          (TAutoVal far*)varResult)) {
  642.   case TXAuto::xNoError:
  643.     return HR_NOERROR;
  644.  
  645.   case TXAuto::xNotIDispatch:
  646.   case TXAuto::xForeignIDispatch:
  647.     return HR_DISP_BADVARTYPE;
  648.  
  649.   case TXAuto::xValidateFailure:
  650.     *retArgErr = stack.CurrentArg;
  651.     return HR_DISP_OVERFLOW;
  652.  
  653.   case TXAuto::xConversionFailure:
  654.   case TXAuto::xTypeMismatch:
  655.     *retArgErr = stack.CurrentArg;
  656.     return HR_DISP_TYPEMISMATCH;
  657.  
  658.   case TXAuto::xNoArgSymbol:
  659.     *retArgErr = stack.CurrentArg;
  660.     return HR_DISP_PARAMNOTFOUND;
  661.  
  662.   case TXAuto::xParameterMissing:
  663.   case TXAuto::xNoDefaultValue:
  664.     return HR_DISP_PARAMNOTOPTIONAL;
  665.  
  666.   case TXAuto::xErrorStatus:
  667.     if (exceptInfo) {
  668.       exceptInfo->wCode = (unsigned short)stack.ErrorCode;
  669.       exceptInfo->wReserved = 0;
  670.       exceptInfo->bstrSource = 0; //::SysAllocString(AppDesc.GetAppName(LANGIDFROMLCID(lcid)));
  671.       exceptInfo->bstrDescription = ::SysAllocString(stack.ErrorMsg);
  672.       exceptInfo->bstrHelpFile = 0;
  673.       exceptInfo->pfnDeferredFillIn = 0;
  674.       exceptInfo->scode = E_FAIL;  // how to get better code? matters?
  675.     }
  676.     return HR_DISP_EXCEPTION;
  677.  
  678.   case TXAuto::xExecutionFailure:
  679.   default:
  680.     return HR_DISP_OVERFLOW;  // no appropriate error for other
  681.   }
  682. }
  683.  
  684.  
  685.