home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / OCFSRC.PAK / APPDESC.CPP next >
C/C++ Source or Header  |  1995-08-29  |  25KB  |  811 lines

  1. //
  2. //----------------------------------------------------------------------------
  3. // ObjectComponents
  4. // (C) Copyright 1994 by Borland International, All Rights Reserved
  5. //
  6. // Application class factory and type library implementation
  7. //----------------------------------------------------------------------------
  8. #include <ocf/ocfpch.h>
  9. #include <ocf/appdesc.h>
  10. #include <ocf/ocreg.h>
  11. #include <strstrea.h>
  12.  
  13. DIAG_DECLARE_GROUP(OcDll);
  14.  
  15. static TLangId ParseLangId(const char* text);
  16.  
  17. //____________________________________________________________________________
  18. //
  19. // TAppDescriptor implementation
  20. //____________________________________________________________________________
  21.  
  22. TAppDescriptor* TAppDescriptor::This = 0;// for components, other DLL use table
  23.  
  24. TAppDescriptor::TAppDescriptor(TRegList& regInfo, TComponentFactory callback,
  25.                                string& cmdLine, HINSTANCE hInst,
  26.                                const TRegLink* linkHead)
  27. :
  28.   AppClassId(regInfo), RegInfo(regInfo),
  29.   AppInstance (hInst), LinkHead(linkHead),
  30.   FactoryCallback(callback)
  31. {
  32.   Init(0);
  33.   ProcessCmdLine(cmdLine);
  34. }
  35.  
  36. //
  37. //
  38. //
  39. #if defined(BI_PLAT_WIN32)
  40. void TAppDescriptor::Init(IMalloc*)
  41. #else
  42. void TAppDescriptor::Init(IMalloc* alloc)
  43. #endif
  44. {
  45.   AppProgId= &RegInfo.LookupRef("progid");
  46.   AppName  = &RegInfo.LookupRef("appname");
  47.   AppDoc   = &RegInfo.LookupRef("description");
  48.   HelpFile = &RegInfo.LookupRef("typehelp");
  49.   This = this;    // direct access for destructors from component main module
  50.   RegClassHdl = RegObjectHdl = ClassCount = LinkGuidCount = 0;
  51.   DebugGuidOffset = LinkGuidOffset = LibGuidOffset = 0;
  52.   ServedList = ActiveObject = 0;
  53.   RefCnt = 0;
  54.   LockCount = 0;
  55.   TypeLib = 0;
  56.   Options = 0;
  57.   ClassList = 0;
  58.  
  59.   // Determine if we are running an EXE or a DLL, initialize OLE if an EXE
  60.   //
  61. #if defined(BI_PTR_0_32)
  62.   if (::GetModuleHandle(0) == AppInstance) { // check instance handle for EXE
  63.     Options = amExeModule | amExeMode;
  64.     OLECALL(OleInitialize(0), "OleInitialize");
  65.   }
  66. #else
  67.   if ((unsigned)AppInstance + 1 == _SS) { // check instance handle for EXE
  68.     Options = amExeModule | amExeMode;
  69.     OLECALL(OleInitialize(alloc), "OleInitialize");
  70.   }
  71. #endif
  72.  
  73.   // Set the initial usage mode based on the reglist entry and module type
  74.   //
  75.   if (Options & amExeModule) {   // inproc servers are multiple-use
  76.     const char* usage = RegInfo.Lookup("usage");
  77.     char su[] = ocrSingleUse;
  78.     if (usage && *usage == *su)
  79.       Options |= amSingleUse;
  80.   }
  81.  
  82.   // Set the app language to the one in the reglist if provided
  83.   //
  84.   const char* regLang = RegInfo.Lookup("language");
  85.   AppLang = regLang ? ParseLangId(regLang) : TLocaleString::UserDefaultLangId;
  86.  
  87.   // Lookup the version, providing a default of 1.0
  88.   //
  89.   Version = RegInfo.Lookup("version", AppLang);
  90.   if (!Version)
  91.     Version = "1.0";
  92.  
  93.   // Assign GUID for debug registration
  94.   //
  95.   if ((Options & amExeModule) &&
  96.       RegInfo.Lookup("debugprogid"))  // check if alternate debug registration
  97.     DebugGuidOffset = AppClassId.AllocId();  // allocate GUID for debugging
  98.  
  99.   // Generate array of all automated classes and assign GUIDs
  100.   //
  101.   MergeAutoClasses();
  102. }
  103.  
  104. TAppDescriptor::~TAppDescriptor()
  105. {
  106.   UnregisterClass();
  107.   delete TypeLib;
  108.   delete[] ClassList;
  109.   This = 0;
  110.   if (RefCnt > 0)
  111.     ::CoDisconnectObject(this,0);   // should not normally happen
  112.   if (Options & amExeModule)
  113.     ::OleUninitialize();       // must happen after everything is unregistered
  114. }
  115.  
  116. TUnknown*
  117. TAppDescriptor::CreateAutoApp(TObjectDescriptor objDesc, uint32 options,
  118.                               IUnknown* outer)
  119. {
  120.   if (objDesc.Destruct == TObjectDescriptor::Delete) {
  121.     if (!(options & (amServedApp | amAutomation)))
  122.       objDesc.Destruct = TObjectDescriptor::Quiet;
  123.     else if (options & amExeMode)
  124.       objDesc.Destruct = TObjectDescriptor::PostQuit;
  125.   }
  126.   TServedObjectCreator* creator = new TServedObjectCreator(*this);
  127.   TUnknown* obj = creator->CreateObject(objDesc, outer); // RefCnt=0
  128.   RegisterObject(objDesc);                        // OLE will do an AddRef()
  129.   return obj;     // RefCnt++ when Aggregated or converted to IUnknown*
  130. }
  131.  
  132. void
  133. TAppDescriptor::ReleaseAutoApp(TObjectDescriptor app)
  134. {
  135.   TServedObject* obj;
  136.   if (ActiveObject && (obj = FindServed(app)) != 0 && obj == ActiveObject)
  137.     UnregisterObject();
  138. }
  139.  
  140. TUnknown*
  141. TAppDescriptor::CreateAutoObject(TObjectDescriptor objDesc, TServedObject& app,
  142.                                  IUnknown* outer)
  143. {
  144.   return app.Creator.CreateObject(objDesc, outer); // RefCnt initially 0
  145. }
  146.  
  147. TUnknown*
  148. TAppDescriptor::CreateAutoObject(const void* obj, const typeinfo& objInfo,
  149.                                  const void* app, const typeinfo& appInfo,
  150.                                  IUnknown* outer)
  151. {
  152.   TServedObject* autoApp = FindServed(MostDerived(app, appInfo));
  153.   TServedObjectCreator& creator = autoApp ? autoApp->Creator
  154.                                           : *new TServedObjectCreator(*this);
  155.   TAutoClass::TAutoClassRef* ref = ClassList;
  156.   for (int i = 0; i < ClassCount; i++, ref++)
  157.     if (objInfo == ref->Class->TypeInfo)
  158.       return creator.CreateObject(TObjectDescriptor(obj, *ref->Class), outer);
  159.   return 0;
  160. }
  161.  
  162. HRESULT _IFUNC
  163. TAppDescriptor::QueryInterface(const IID far& riid, void far* far* retIface)
  164. {
  165.   if (riid == IID_IUnknown || riid == IID_IClassFactory) {
  166.     AddRef();
  167.     *retIface = (IUnknown*)this;
  168.     return HR_NOERROR;
  169.   }
  170.   *retIface = 0;
  171.   return HR_NOINTERFACE;
  172. }
  173.  
  174. unsigned long _IFUNC
  175. TAppDescriptor::AddRef()
  176. {
  177.   return ++RefCnt;
  178. }
  179.  
  180. unsigned long _IFUNC
  181. TAppDescriptor::Release()
  182. {
  183.   return --RefCnt;  // note: this object will not delete itself
  184. }
  185.  
  186. HRESULT _IFUNC
  187. TAppDescriptor::CreateInstance(IUnknown* outer, const IID far& riid,
  188.                                void far* far* ppv)
  189. {
  190.   *ppv = 0;
  191.   IUnknown* obj;
  192.   if (!FactoryCallback)
  193.     return HR_FAIL;
  194.  
  195.   try {
  196.     // Test for special condition to force run DLL as an EXE
  197.     //
  198.     if (outer && outer->QueryInterface(IID_NULL, ppv) == HR_NOERROR)
  199.       obj = FactoryCallback(0, Options | amServedApp | amExeMode | amRun);
  200.     else
  201.       obj = FactoryCallback(outer, Options | amServedApp);
  202.     if (!obj)
  203.       return HR_FAIL;
  204.     if (Options & amSingleUse)
  205.       UnregisterClass();
  206.     if (riid == IID_IUnknown) {  // can't return outer if aggregated
  207.       *ppv = obj;
  208.       return HR_OK;
  209.     }
  210.     HRESULT stat = obj->QueryInterface(riid, ppv);
  211.     obj->Release();
  212.     return stat;
  213.   }
  214.   catch (...) {  // we can't throw any exception through OLE
  215.     return HR_OUTOFMEMORY;  // probably a resource problem, better error code?
  216.   }
  217. }
  218.  
  219. HRESULT _IFUNC
  220. TAppDescriptor::LockServer(BOOL fLock)
  221. {
  222.   if (fLock)
  223.     LockCount++;
  224.   else
  225.     LockCount--;    // should notify app when count reaches 0?
  226.  
  227.   TRACEX(OcDll, 1, "LockServer(" << fLock << ") Count:" << LockCount);
  228.  
  229.   return HR_NOERROR;
  230. }
  231.  
  232. uint16
  233. TAppDescriptor::GetVersionField(unsigned field)
  234. {
  235.   const char* cp = Version;
  236.   char c;
  237.   while (field--) {
  238.     while ((c = *cp++) != '.') {
  239.       if (c < '0' || c > '9')
  240.         return 0;    // terminate on null or invalid digit
  241.     }
  242.   }
  243.   uint16 ver = 0;
  244.   while ((c = *cp++) >= '0' && c <= '9')
  245.     ver = uint16(ver * 10 + c - '0');
  246.   return ver;
  247. }
  248.  
  249. void
  250. TAppDescriptor::RegisterClass()
  251. {
  252.   int guidOffset = IsOptionSet(amDebug) ? DebugGuidOffset : 0;
  253.   if (!RegClassHdl) {
  254.     OLECALL(::CoRegisterClassObject(AppClassId[guidOffset], this,
  255.                       CLSCTX_LOCAL_SERVER, (Options & amSingleUse) ?
  256.                       REGCLS_SINGLEUSE : REGCLS_MULTIPLEUSE, &RegClassHdl),
  257.                       "Register App class");
  258.   }
  259. }
  260.  
  261. void
  262. TAppDescriptor::UnregisterClass()
  263. {
  264.   if (RegClassHdl) {
  265.     OLECALL(::CoRevokeClassObject(RegClassHdl), "Unregister App class");
  266.     RegClassHdl = 0;
  267.   }
  268. }
  269.  
  270. bool
  271. TAppDescriptor::RegisterObject(TObjectDescriptor app)
  272. {
  273.   if (ActiveObject)
  274.     return false;
  275.   TServedObject* obj = FindServed(app);
  276.   if (!obj)
  277.     return false;
  278.   int guidOffset = IsOptionSet(amDebug) ? DebugGuidOffset : 0;
  279.  
  280.   // Refcnt may be zero, protect against AddRef/Release
  281.   //
  282.   obj->AdjustRefCount(+1);
  283.  
  284.   // Register object with Ole. OLE 2.02 suggests ACTIVEOBJECT_WEAK, but that
  285.   // does not appear to provide adequate locking.
  286.   //
  287.   OLECALL(::RegisterActiveObject(&(IUnknown&)*obj,
  288.                                  AppClassId[guidOffset],
  289.                                  ACTIVEOBJECT_STRONG,
  290.                                  &RegObjectHdl),
  291.           "Register App as active");
  292.  
  293.   obj->AdjustRefCount(-1);
  294.   ActiveObject = obj;
  295.   return true;
  296. }
  297.  
  298. void
  299. TAppDescriptor::UnregisterObject()
  300. {
  301.   if (RegObjectHdl) {
  302.     ActiveObject = 0;  // must zero before OLE call in case obj destructor run
  303.     OLECALL(::RevokeActiveObject(RegObjectHdl, 0), "Unregister App");
  304.     RegObjectHdl = 0;
  305.   }
  306. }
  307.  
  308. int
  309. TAppDescriptor::GetClassIndex(TAutoClass* cls)
  310. {
  311.   TAutoClass::TAutoClassRef* ref = ClassList;
  312.   for (int index = 0; index < ClassCount; ref++, index++) {
  313.     if (ref->Class == cls)
  314.       return index;
  315.   }
  316.   return -1;
  317. }
  318.  
  319. bool
  320. TAppDescriptor::GetClassId(TAutoClass* cls, GUID& retId)
  321. {
  322.   int offset;
  323.   if (cls) {
  324.     int index = GetClassIndex(cls);
  325.     if (index == -1)
  326.       return false;
  327.     offset = ClassList[index].GuidOffset;
  328.   } else {          // null class arg means type library itself
  329.     offset = LibGuidOffset;
  330.   }
  331.   retId = AppClassId[offset];
  332.   return true;
  333. }
  334.  
  335. TClassId
  336. TAppDescriptor::GetLinkGuid(int index)
  337. {
  338.   while (index >= LinkGuidCount) {
  339.     int id = AppClassId.AllocId();
  340.     if (!LinkGuidOffset)
  341.       LinkGuidOffset = id;
  342.     LinkGuidCount++;
  343.   }
  344.   return AppClassId[LinkGuidOffset + index];
  345. }
  346.  
  347. TAutoClass*
  348. TAppDescriptor::GetAutoClass(unsigned index)
  349. {
  350.   if (index >= ClassCount)
  351.     return 0;
  352.   return ClassList[index].Class;
  353. }
  354.  
  355. TAutoClass*
  356. TAppDescriptor::GetAutoClass(const GUID far& clsid)
  357. {
  358.   int offset = AppClassId.GetOffset(clsid);
  359.   if (offset != -1) {
  360.     TAutoClass::TAutoClassRef* ref = ClassList;
  361.     for (int count = ClassCount; count--; ref++) {
  362.       if (ref->GuidOffset == offset)
  363.         return ref->Class;
  364.     }
  365.   }
  366.   return 0;
  367. }
  368.  
  369. //
  370. // Get the document template with the given GUID
  371. //
  372. TRegLink*
  373. TAppDescriptor::GetRegLink(const GUID far& clsid)
  374. {
  375.   int linkGuidIndex = 0;
  376.   for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
  377.     TRegList& regList = link->GetRegList();
  378.     if (regList["progid"]) {
  379.       const char* id = regList["clsid"];
  380.       if (!id) {
  381.         if (clsid == (GUID&)GetLinkGuid(linkGuidIndex++))
  382.           return const_cast<TRegLink*>(link);
  383.       }
  384.       else {
  385.         TClassId classId(id);
  386.         if (clsid == (GUID&) classId)
  387.           return const_cast<TRegLink*>(link);
  388.       }
  389.     }
  390.   }
  391.  
  392.   return 0;
  393. }
  394.  
  395. ITypeLib*
  396. TAppDescriptor::GetTypeLibrary()
  397. {
  398.   if (!ClassCount)
  399.     return 0;
  400.   if (!TypeLib) {
  401.     TypeLib = new TTypeLibrary(*this, AppLang);
  402.   }
  403.   ((IUnknown&)*TypeLib).AddRef();
  404.   return TypeLib;
  405. }
  406.  
  407. // TServedObject list management
  408.  
  409. TServedObject*
  410. TAppDescriptor::FindServed(const void far* mostDerivedObj)
  411. {
  412.   for (TServedObject* p = ServedList; p; p = p->Next)
  413.     if (p->RootObject == mostDerivedObj)
  414.       break;
  415.   return p;
  416. }
  417.  
  418. TServedObject*
  419. TAppDescriptor::FindServed(TObjectDescriptor& objDesc)
  420. {
  421.   if (objDesc.Object)
  422.     return FindServed(objDesc.MostDerived());
  423.   for (TServedObject* p = ServedList; p; p = p->Next)
  424.     if (p->Object == 0 && p->Class == objDesc.Class)
  425.       return p;
  426.   return 0;
  427. }
  428.  
  429. void
  430. TAppDescriptor::AddServed(TServedObject& obj) {
  431.   if (ServedList)
  432.     ServedList->Prev = &obj.Next;
  433.   obj.Next = ServedList;
  434.   obj.Prev = &ServedList;
  435.   ServedList = &obj;
  436. }
  437.  
  438. void
  439. TAppDescriptor::RemoveServed(TServedObject& obj) {
  440.   *obj.Prev = obj.Next;
  441.   if (obj.Next)
  442.     obj.Next->Prev = obj.Prev;
  443. }
  444.  
  445. void
  446. TAppDescriptor::FlushServed() {
  447.   while (ServedList)
  448.     delete ServedList;
  449. }
  450.  
  451. void
  452. TAppDescriptor::InvalidateObject(const void far* obj)
  453. {
  454.   TServedObject* p = FindServed(obj);
  455.   if (p) {
  456.     p->RootObject = 0;
  457.     p->Object = 0;
  458.   }
  459. }
  460.  
  461. void
  462. TAppDescriptor::ReleaseObject(const void far* obj)
  463. {
  464.   TServedObject* p = FindServed(obj);
  465.   if (p) {
  466.     p->RootObject = 0;
  467.     p->Object = 0;
  468.     ((IUnknown&)*p).Release();   // destructs if no external connections
  469.   }
  470. }
  471.  
  472. ITypeInfo*
  473. TAppDescriptor::CreateITypeInfo(TAutoClass& cls)
  474. {
  475.   TServedObjectCreator& creator = ServedList ? ServedList->Creator
  476.                                              : *new TServedObjectCreator(*this);
  477.   TUnknown* obj = creator.CreateObject(TObjectDescriptor(0, cls));
  478.   IUnknown& unk = (IUnknown&)*obj;
  479.   ITypeInfo* typeInfo = 0;
  480.   unk.QueryInterface(IID_ITypeInfo, (void far* far*) &typeInfo);
  481.   return typeInfo;
  482. }
  483.  
  484. //____________________________________________________________________________
  485. //
  486. // Parse command line for Ole flags.
  487. // Check for [-/] and remove options that are found. Gets option arguments
  488. // and performs any immediate option actions
  489. //____________________________________________________________________________
  490.  
  491. void
  492. TAppDescriptor::RegisterServer(TLangId lang, const char* regFilename)
  493. {
  494.   try {
  495.     TRegItem regDebug[DebugRegCount];
  496.  
  497.     // Check if registration output to Registry or to user-specified reg file
  498.     //
  499.     char guidStr[40];
  500.     strstream regStrm;
  501.     ostream* strm = ®Strm;
  502.     bool alwaysReg = IsOptionSet(amRegServer);
  503.     ofstream  fileStrm;
  504.     if (regFilename) {
  505.       fileStrm.open(regFilename);
  506.       if (!fileStrm.good())
  507.         throw TXRegistry(regFilename, "file");
  508.       strm = &fileStrm;
  509.       fileStrm << "REGEDIT\n";  // write registration file header
  510.       alwaysReg = true;
  511.     }
  512.     SetOption(amUnregServer, false);// cancel unregister on reregister
  513.  
  514.     // Make sure that the app reginfo is in the registry
  515.     //
  516.     bool forceReg = alwaysReg;
  517.     if (AppProgId) {       // don't attempt register app if no progid reg key
  518.       if (!forceReg) {
  519.         strstream vstrm;
  520.         ::OcRegisterClass(RegInfo, AppInstance, vstrm, lang, "\001\002\006");
  521.         if (::OcRegistryValidate(vstrm) != 0)
  522.           forceReg = true;
  523.       }
  524.       if (forceReg) {
  525.         char* debugGuid = 0;
  526.         if (DebugGuidOffset) {                // setup reg item for debug reg
  527.           TClassId debugClsid(AppClassId[DebugGuidOffset]);
  528.           lstrcpy(guidStr, debugClsid);
  529.           debugGuid = guidStr;
  530.           if (::OcSetupDebugReg(RegInfo, regDebug, lang, debugGuid)) {
  531.             ::OcRegisterClass(RegInfo, AppInstance, *strm, lang, 0, 0, OcRegNoDebug);
  532.             ::OcRegisterClass(RegInfo, AppInstance, *strm, lang, AppDebugFilter,
  533.                                                                     0, regDebug);
  534.           } else {
  535.             debugGuid = 0;  // if debug registration fails, use normal
  536.           }
  537.         }
  538.         if (!debugGuid)
  539.           ::OcRegisterClass(RegInfo, AppInstance, *strm, lang, 0, 0,
  540.                             (Options & amExeModule) ? 0 : OcRegNotDll);
  541.       }
  542.     }
  543.  
  544.     // Write templates to registration file as needed
  545.     //
  546.     int linkGuidIndex = 0;
  547.     TRegItem regAppName[2] = {{"appname",{RegInfo["appname"]}}, {0,{0}}};
  548.     for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
  549.       TRegList& regList = link->GetRegList();
  550.       if (regList["progid"]) {
  551.         char guidStr[40];
  552.         int debugStat = (Options & amExeModule) ?
  553.                         ::OcSetupDebugReg(regList, regDebug, lang, guidStr) : 0;
  554.         TRegItem regClsid[3] = {{"debugger",{""}}, {"clsid",{guidStr}}, {0,{0}}};
  555.         TRegItem* clsInfo = regClsid;
  556.         if (!debugStat && Options & amExeModule)
  557.           clsInfo++;     // no cancel debugger if no debugprogid
  558.         if (!regList["clsid"]) {      // check if GUID needs to be assigned
  559.           TClassId linkClsid(GetLinkGuid(linkGuidIndex++));
  560.           lstrcpy(guidStr, linkClsid);
  561.         } else {
  562.           regClsid[1].Key = 0;  // shorten list to exclude auto-assigned clsid
  563.         }
  564.         if (!alwaysReg) {
  565.           strstream checkStrm;
  566.           ::OcRegisterClass(regList, AppInstance, checkStrm, lang,
  567.                             "\001\002\006", 0, clsInfo);
  568.           if (::OcRegistryValidate(checkStrm) == 0)
  569.             continue;
  570.         }
  571.         if (debugStat) {
  572.           ::OcRegisterClass(regList, AppInstance, *strm, lang, 0, regAppName, regClsid);
  573.           if (debugStat == 1) {   // needs generated guid string
  574.             TClassId linkClsid(GetLinkGuid(linkGuidIndex++));
  575.             lstrcpy(guidStr, linkClsid);
  576.           }
  577.           ::OcRegisterClass(regList, AppInstance, *strm, lang, DocDebugFilter,
  578.                                                         regAppName, regDebug);
  579.         } else {
  580.           ::OcRegisterClass(regList, AppInstance, *strm, lang, 0, regAppName, clsInfo);
  581.         }
  582.         forceReg = true;
  583.       }
  584.     }
  585.     if (forceReg && !regFilename)
  586.       ::OcRegistryUpdate(regStrm);
  587.     if (forceReg)
  588.       ::RegDeleteKey(HKEY_CLASSES_ROOT, "OcErr_RegServer");
  589.   }
  590.   catch (TXBase& xcpt) {
  591.     ::RegSetValue(HKEY_CLASSES_ROOT, "OcErr_RegServer", REG_SZ, AppClassId, 0);
  592.     if (!(Options & amQuietReg))
  593.       throw;
  594.   }
  595.   return;
  596. }
  597.  
  598. void
  599. TAppDescriptor::UnregisterServer(TLangId, const char*)
  600. {
  601.   // remove application and all type library info from registry
  602.   //
  603.   HKEY Key;
  604.   char guidStr[40];
  605.   TRegItem debugItem = {"debugclsid", {guidStr}};
  606.   TRegItem* debugInfo = 0;              // init to no debug registration
  607.   if (AppProgId) {          // don't attempt unregister app if no progid reg key
  608.     if (DebugGuidOffset) {                // setup reg item for debug reg
  609.       TClassId debugClsid(AppClassId[DebugGuidOffset]);
  610.       lstrcpy(guidStr, debugClsid);
  611.       debugInfo = &debugItem;
  612.     }
  613.     ::OcUnregisterClass(RegInfo, debugInfo);   // unregister app
  614.     if (LibGuidOffset) {
  615.       ::RegOpenKey(HKEY_CLASSES_ROOT, "TypeLib", &Key);
  616.       ::RegDeleteKey(Key, AppClassId[LibGuidOffset]);
  617.       ::RegCloseKey(Key);
  618.     }
  619.     if (ClassCount) {
  620.       ::RegOpenKey(HKEY_CLASSES_ROOT, "Interface", &Key);
  621.       for (int i= 0; i < ClassCount; i++)
  622.         ::RegDeleteKey(Key, AppClassId[ClassList[i].GuidOffset]);
  623.       ::RegCloseKey(Key);
  624.     }
  625.   }
  626.  
  627.   // remove templates from registration file as needed
  628.   //
  629.   int linkGuidIndex = 0;
  630.   for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
  631.     TRegList& regList = link->GetRegList();
  632.     if (regList["progid"]) {
  633.       if (!regList["clsid"]) {      // check if GUID needs to be computed
  634.         TClassId linkClsid(GetLinkGuid(linkGuidIndex++));
  635.         lstrcpy(guidStr, linkClsid);
  636.         TRegItem clsItem = {"clsid", {guidStr}};
  637.         ::OcUnregisterClass(regList, &clsItem);
  638.       } else
  639.         ::OcUnregisterClass(regList);
  640.     }
  641.   }
  642. }
  643.  
  644. void
  645. TAppDescriptor::SetLangId(TLangId /*prevLang*/, const char* langIdStr)
  646. {
  647.   AppLang = ParseLangId(langIdStr);
  648. }
  649.  
  650. void
  651. TAppDescriptor::MakeTypeLib(TLangId lang, const char* typeLibName)
  652. {
  653.   if (!ClassCount)
  654.     return;
  655.  
  656.   // write the typelib file to <typeLibName>
  657.   //
  658.   char fullPath[_MAX_PATH];
  659.   char exeDrive[_MAX_DRIVE];
  660.   char exeDir  [_MAX_DIR];
  661.   char exeFName[_MAX_FNAME];
  662.   char exeExt  [_MAX_EXT];
  663.   char libDrive[_MAX_DRIVE];
  664.   char libDir  [_MAX_DIR];
  665.   char libFName[_MAX_FNAME];
  666.   char libExt  [_MAX_EXT];
  667.   ::GetModuleFileName(AppInstance, fullPath, sizeof(fullPath));
  668.   _splitpath(typeLibName? typeLibName:"", libDrive, libDir, libFName, libExt);
  669.   _splitpath(fullPath, exeDrive, exeDir, exeFName, exeExt);
  670.   _makepath (fullPath,
  671.              libDrive[0] ? libDrive : exeDrive,
  672.              libDir[0]   ? libDir   : exeDir,
  673.              libFName[0] ? libFName : exeFName,
  674.              libExt[0]   ? libExt   : "OLB");
  675.   try {
  676.     WriteTypeLibrary(lang, fullPath);
  677.     ::RegDeleteKey(HKEY_CLASSES_ROOT, "OcErr_Typelib");
  678.   }
  679.   catch (TXOle&) {
  680.     ::RegSetValue(HKEY_CLASSES_ROOT, "OcErr_Typelib", REG_SZ, AppClassId, 0);
  681.     if (!(Options & amQuietReg))
  682.       throw;
  683.   }
  684. }
  685.  
  686. //
  687. //
  688. //
  689. void
  690. TAppDescriptor::ProcessCmdLine(string& cmdLine)
  691. {
  692.   struct {
  693.     uint32 Flag;
  694.     char*  String;
  695.     void   (TAppDescriptor::*Action)(TLangId, const char*);
  696.   }
  697.   optionTbl[] = {
  698.     { amRegServer,    "RegServer",     &TAppDescriptor::RegisterServer },
  699.     { amUnregServer,  "UnregServer",   &TAppDescriptor::UnregisterServer },
  700.     { amAutomation,   "Automation",    0 },
  701.     { amEmbedding,    "Embedding",     0 },
  702.     { amLangId,       "Language",      &TAppDescriptor::SetLangId },
  703.     { amTypeLib,      "TypeLib",       &TAppDescriptor::MakeTypeLib },
  704.     { amNoRegValidate,"NoRegValidate", 0 },
  705.     { amQuietReg ,    "QuietReg",      0 },
  706.     { amDebug,        "Debug",         0 },
  707.   };
  708.   const int optionTblCount = sizeof(optionTbl)/sizeof(optionTbl[0]);
  709.   TCmdLine cmd(cmdLine.c_str());
  710.  
  711.   while (cmd.Kind != TCmdLine::Done) {
  712.     switch (cmd.Kind) {
  713.       default:
  714.         cmd.NextToken();        // ignore token, not one of ours
  715.         break;
  716.       case TCmdLine::Option:
  717.         for (int i = 0; i < optionTblCount; i++) {
  718.           if (strnicmp(cmd.Token, optionTbl[i].String, cmd.TokenLen) == 0) {
  719.             Options |= optionTbl[i].Flag;
  720.             cmd.NextToken(true);    // eat token & get next
  721.             if (cmd.Kind == TCmdLine::Value) {
  722.               string optionArg(cmd.Token, 0, cmd.TokenLen);
  723.               while (cmd.NextToken(true) == TCmdLine::Value)
  724.                 ; // eat token & get next (keep going if more Values are there)
  725.               if (optionTbl[i].Action)
  726.                 (this->*optionTbl[i].Action)(AppLang, optionArg.c_str());
  727.             }
  728.             else {
  729.               if (optionTbl[i].Action)
  730.                 (this->*optionTbl[i].Action)(AppLang, 0);
  731.             }
  732.             break; // out of for loop
  733.           }
  734.         }
  735.         if (i >= optionTblCount)
  736.           cmd.NextToken();        // ignore token, wasn't one of ours
  737.         break;
  738.     }
  739.   }
  740.   cmdLine = cmd.GetLine();
  741.  
  742.   // Set single use if this is an automated exe server
  743.   //
  744.   if ((Options & (amAutomation | amExeModule)) == (amAutomation | amExeModule))
  745.     Options |= amSingleUse;
  746.  
  747.   // Perform normal registry update if no other registry option was specified
  748.   //
  749.   if (!(Options & (amRegServer | amUnregServer | amNoRegValidate)))
  750.     RegisterServer(0);
  751. }
  752.  
  753. static char HexChar[] = "0123456789ABCDEF0123456789abcdef";
  754. static TLangId ParseLangId(const char* text)
  755. {
  756.   TLangId lang = 0;
  757.   unsigned char c;
  758.   char* pc;
  759.   while (text && (c = *text++) != 0) {
  760.     if ((pc = strchr(HexChar, c)) == 0)
  761.       return 0;   // illegal character
  762.     lang = TLangId((lang << 4) + (short(pc-HexChar) & 15));
  763.   }
  764.   return lang ? lang : TLocaleString::UserDefaultLangId;
  765. }
  766.  
  767. void
  768. TAppDescriptor::MergeAutoClasses()
  769. {
  770.   int oldCount = ClassCount;
  771.   ClassCount = TAutoClass::ClassList.CountAutoClasses();
  772.   if (ClassCount) {
  773.     if (!LibGuidOffset)
  774.       LibGuidOffset = AppClassId.AllocId();  // allocate GUID for type library
  775.     TAutoClass::TAutoClassRef* oldList  = ClassList;
  776.     ClassList = new TAutoClass::TAutoClassRef[ClassCount];
  777.     TAutoClass::ClassList.MergeAutoClasses(ClassList);
  778.     TAutoClass::TAutoClassRef* ref = ClassList;
  779.     for (int count = ClassCount; count--; ref++) {
  780.       if (oldCount) {
  781.         ref->GuidOffset = oldList->GuidOffset;
  782.         oldCount--;
  783.         oldList++;
  784.       } else {
  785.         ref->GuidOffset = AppClassId.AllocId();
  786.       }
  787.     }
  788.   }
  789. }
  790.  
  791. int
  792. TAutoClass::TClassList::CountAutoClasses()
  793. {
  794.   int count = Count;
  795.   for (TExtLink* link = Link; link; link = link->Next)
  796.     count += link->Classes->CountAutoClasses();
  797.   return count;
  798. }
  799.  
  800. TAutoClass::TAutoClassRef*
  801. TAutoClass::TClassList::MergeAutoClasses(TAutoClass::TAutoClassRef* array)
  802. {
  803.   for (TAutoClass* cls = List; cls; cls = cls->NextClass, array++)
  804.     array->Class = cls;
  805.   for (TExtLink* link = Link; link; link = link->Next)
  806.     array = link->Classes->MergeAutoClasses(array);
  807.   return array;
  808. }
  809.  
  810.  
  811.