OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
appdesc.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectComponents
3// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
4/// \file
5/// Application class factory and type library implementation
6//----------------------------------------------------------------------------
7#include <ocf/pch.h>
8
9#include <ocf/appdesc.h>
10#include <ocf/ocreg.h>
11#include <owl/cmdline.h>
13#include <algorithm>
14#include <utility>
15#include <optional>
16#include <type_traits>
17
18namespace ocf {
19
20using namespace owl;
21using namespace std;
22
23
25
26static TLangId ParseLangId(LPCTSTR text);
27
28//----------------------------------------------------------------------------
29// TAppDescriptor implementation
30//
31
32// Provides access to the AppDescriptor of this component
33//
34TAppDescriptor* TAppDescriptor::This = 0;
35
36//
37//
38//
41 const TRegLink* linkHead,
43:
44 AppClassId(regInfo), RegInfo(regInfo),
45 Module(module), LinkHead(linkHead),
46 FactoryCallback(callback),
47 LicKeyFactoryCallback(0)
48{
49 Init(0);
50 Options |= preselectedOptions;
52}
53
54//
55//
56//
58 TLicenseKeyFactory* factory,
60 const TRegLink* linkHead,
62:
63 AppClassId(regInfo), RegInfo(regInfo),
64 Module(module), LinkHead(linkHead),
65 FactoryCallback(callback),
66 LicKeyFactoryCallback(factory)
67{
68 Init(0);
69 Options |= preselectedOptions;
71}
72
73//
74//
75//
76void
77TAppDescriptor::Init(IMalloc*)
78{
79 AppProgId= &RegInfo.LookupRef("progid");
80 AppName = &RegInfo.LookupRef("appname");
81 AppDoc = &RegInfo.LookupRef("description");
82 HelpFile = &RegInfo.LookupRef("typehelp");
83
84 // Provide direct access for destructors from component main module
85 //
86 This = this;
87 RegClassHdl = RegObjectHdl = ClassCount = LinkGuidCount = 0;
88 DebugGuidOffset = LinkGuidOffset = LibGuidOffset = 0;
89 ServedList = ActiveObject = 0;
90 RefCnt = 0;
91 LockCount = 0;
92 TypeLib = 0;
93 Options = 0;
94 ClassList = 0;
95 //-------
96 Creator = 0;
97
98 // Determine if we are running an EXE or a DLL, initialize OLE if an EXE
99 //
100 if (::GetModuleHandle(0) == Module->GetHandle()) { // check instance handle for EXE
101 Options = amExeModule | amExeMode;
102 OLECALL(OleInitialize(0), _T("OleInitialize"));
103 }
104
105 // Set the initial usage mode based on the reglist entry and module type
106 // NOTE: InProc servers are multiple-user
107 //
108 if (Options & amExeModule) {
109 LPCTSTR usage = RegInfo.Lookup("usage");
111 if (usage && *usage == *su)
112 Options |= amSingleUse;
113 }
114
115 // Set the app language to the one in the reglist if provided
116 //
117 LPCTSTR regLang = RegInfo.Lookup("language");
118 AppLang = regLang ? ParseLangId(regLang) : TLocaleString::UserDefaultLangId;
119
120 // Lookup the version, providing a default of 1.0
121 //
122 Version = RegInfo.Lookup("version", AppLang);
123 if (!Version)
124 Version = _T("1.0");
125
126 // Assign GUID for debug registration
127 // Check if alternate debug registration has been provided and allocated GUID
128 //
129 if ((Options & amExeModule) && RegInfo.Lookup("debugprogid"))
130 DebugGuidOffset = AppClassId.AllocId();
131
132 // Generate array of all automated classes and assign GUIDs
133 //
135}
136
137//
138//
139//
141{
143 delete TypeLib;
144 delete[] ClassList;
145 This = 0;
146
147 // Following should not normally happen - but just in case
148 //
149 if (RefCnt > 0)
150 ::CoDisconnectObject(this,0);
151
152 // And last, uninitialize OLE
153 //
154 if (Options & amExeModule)
156}
157
158/// Creates a TServedObject helper object which implements an IDispatch
159/// implementation on behalf of the 'Application' object.
160//
163 IUnknown* outer)
164{
165 if (objDesc.Destruct == TObjectDescriptor::Delete) {
166 if (!(options & (amServedApp | amAutomation)))
168 else if (options & amExeMode)
170 }
171
172 // NOTE: Creator is destroyed via delegation
173 //
174 Creator = new TServedObjectCreator(*this);
175
176 // NOTE : Object is created with ref. count of '0'
177 //
178 TUnknown* obj = Creator->CreateObject(objDesc, outer);
179
180 // NOTE: OLE's 'RegisterActiveObject' will do an 'AddRef()'
181 //
183
184 // NOTE: Object will be RefCnt++ when aggregated or converted to IUnknown*
185 //
186 return obj;
187}
188
189/// Releases the helper object (TServedObject) implementing IDispatch on behalf
190/// of the 'Application' object.
191//
192void
194{
196 if (ActiveObject && (obj = FindServed(app)) != 0 && obj == ActiveObject)
198}
199
200/// Creates a TServedObject helper which implements IDispatch on behalf of
201/// the class described via the 'objDesc' parameter.
202/// \note The returned object initial ref. count is '0'.
203//
206 IUnknown* outer)
207{
208 return app.Creator.CreateObject(objDesc, outer);
209}
210
211/// Creates a TServedObject helper which implements IDispatch on behalf of the
212/// class instance passed in via 'obj' and 'objInfo' parameters.
213//
215TAppDescriptor::CreateAutoObject(const void* obj, const std::type_info& objInfo,
216 const void* app, const std::type_info& appInfo,
217 IUnknown* outer)
218{
219 TServedObject* autoApp = FindServed(MostDerived(app, appInfo)); //?????????????????????????????
220 TServedObjectCreator *creator = autoApp ? &(autoApp->Creator) : Creator;
221 if (!creator) {
222 // NOTE: Destroyed through delegation
223 //
224 Creator = new TServedObjectCreator(*this);
225 creator = Creator;
226 }
227
228 TAutoClass::TAutoClassRef* ref = ClassList;
229 for (int i = 0; i < ClassCount; i++, ref++)
230 if (objInfo == ref->Class->TypeInfo)
231 return creator->CreateObject(TObjectDescriptor(obj, *ref->Class), outer);
232 return 0;
233}
234
235/// QueryInterface: Hands out IUnknown or IClassFactory
236//
238TAppDescriptor::QueryInterface(const IID& riid, void** retIface)
239{
241 AddRef();
242 *retIface = (IUnknown*)this;
243 return HR_NOERROR;
244 }
245 *retIface = 0;
246 return HR_NOINTERFACE;
247}
248
249/// Usual IUnknown 'AddRef'
250//
252TAppDescriptor::AddRef()
253{
254 return ++RefCnt;
255}
256
257/// Usual IUnknown 'Release'
258/// \note This object does *NOT* delete itself
259/// \todo !BB Why?? Find out
260//
262TAppDescriptor::Release()
263{
264 return --RefCnt;
265}
266
267//
268//
269//
272 void** ppv)
273{
274
275#if 0 // !BB Tweak while playing with Active Controls
276
277 // Display which interface is being asked for
278 //
279 const char* p = OCFStringFromIID(riid);
280
282 return SUCCEEDED(oleCtl->QueryInterface(riid, ppv));
283
284#else
285
286 *ppv = 0;
287 IUnknown* obj;
288 if (!FactoryCallback)
289 return HR_FAIL;
290
291 try {
292 // Test for special condition to force run DLL as an EXE
293 //
294 if (outer && outer->QueryInterface(IID_NULL, ppv) == HR_NOERROR)
295 obj = FactoryCallback(0, Options | amServedApp | amExeMode | amRun, 0);
296 else
297 obj = FactoryCallback(outer, Options | amServedApp, 0);
298 if (!obj)
299 return HR_FAIL;
300 if (Options & amSingleUse)
302
303 // Cannot return outer if aggregated
304 //
305 if (riid == IID_IUnknown) {
306 *ppv = obj;
307 return HR_OK;
308 }
309 HRESULT stat = obj->QueryInterface(riid, ppv);
310 obj->Release();
311 return stat;
312 }
313 catch (...) {
314 // NOTE: Cannot throw any exception through OLE
315 // We'll assume a resource problem;
316 // Is there a better error code to express an exception ??
317 //
318 return HR_OUTOFMEMORY;
319 }
320
321#endif
322}
323
324// LockServer [IClassFactory]
325//
328{
329 if (lock)
330 LockCount++;
331 else {
332 // NOTE: Should we notify app when count reaches 0?
333 //
334 LockCount--;
335 }
336
337 TRACEX(OcfDll, 1, _T("LockServer(") << lock << _T(") Count:") << LockCount);
338
339 return HR_NOERROR;
340}
341
342// GetLicInfo [IClassFactory2]
343//
346{
347 if(LicKeyFactoryCallback)
348 return LicKeyFactoryCallback->GetLicInfo(licInfo);
349 return E_UNEXPECTED;
350}
351
352// RequestLicKey [IClassFactory2]
353//
356{
357 if(LicKeyFactoryCallback)
358 return LicKeyFactoryCallback->RequestLicKey(retKey);
359 return E_NOTIMPL;
360}
361// CreateInstanceLic [IClassFactory2]
362//
364TAppDescriptor::CreateInstanceLic(IUnknown* outer, IUnknown* /*reserved*/,
365 const IID & iid, BSTR key,
366 void** retObject )
367{
368 if(LicKeyFactoryCallback){
369 HRESULT hr = LicKeyFactoryCallback->QueryLicKey(key);
370 if(SUCCEEDED(hr))
372 return hr;
373 }
374 return E_NOTIMPL;
375}
376/// Returns version as a whole number
377//
378uint16
380{
381 LPCTSTR cp = Version;
382 TCHAR c;
383 while (field--) {
384 while ((c = *cp++) != _T('.')) {
385 if (c < _T('0') || c > _T('9'))
386 return 0; // terminate on null or invalid digit
387 }
388 }
389 uint16 ver = 0;
390 while ((c = *cp++) >= _T('0') && c <= _T('9'))
391 ver = uint16(ver * 10 + c - _T('0'));
392 return ver;
393}
394
395
396/// Register an EXE class object with OLE so that other applications can connect to it
397//
398void
400{
401 int guidOffset = IsOptionSet(amDebug) ? DebugGuidOffset : 0;
402 if (!RegClassHdl) {
405 (Options & amSingleUse) ? REGCLS_SINGLEUSE :
407 &RegClassHdl),
408 _T("Register App class"));
409 }
410}
411
412/// Invalidates application class registered earlier with 'RegisterClass'
413//
414void
416{
417 if (RegClassHdl) {
418 OLECALL(::CoRevokeClassObject(RegClassHdl), _T("Unregister App class"));
419 RegClassHdl = 0;
420 }
421}
422
423/// Registers the helper object (TServedObject) of the class described via
424/// the 'app' parameter as the active object for its classId.
425//
426bool
428{
429 if (ActiveObject)
430 return false;
432 if (!obj)
433 return false;
434 int guidOffset = IsOptionSet(amDebug) ? DebugGuidOffset : 0;
435
436 // Refcnt may be zero, protect against AddRef/Release
437 //
438 obj->AdjustRefCount(+1);
439
440 // Register object with Ole. OLE 2.02 suggests ACTIVEOBJECT_WEAK, but that
441 // does not appear to provide adequate locking.
442 //
443 IUnknown* unkObj = &(IUnknown&)*(TUnknown*)obj;
444// OLECALL(::RegisterActiveObject(&(IUnknown&)*obj, // BUG_BUG_BUG
448 &RegObjectHdl),
449 _T("Register App as active"));
450
451 obj->AdjustRefCount(-1);
452 ActiveObject = obj;
453 return true;
454}
455
456/// Invalidates a helper object registers with RegisterObject earlier
457//
458void
460{
461 if (RegObjectHdl) {
462 // NOTE: Zero before OLE call in case obj. destructor is invoked
463 //
464 ActiveObject = 0;
465 OLECALL(::RevokeActiveObject(RegObjectHdl, 0), _T("Unregister App"));
466 RegObjectHdl = 0;
467 }
468}
469
470/// Returns the index of a 'TAutoClass' instance
471//
472int
474{
475 TAutoClass::TAutoClassRef* ref = ClassList;
476 for (int index = 0; index < ClassCount; ref++, index++) {
477 if (ref->Class == cls)
478 return index;
479 }
480 return -1;
481}
482
483/// Retrieves the GUID of the specified TAutoClass instance.
484/// \note Passing '0' as the 'cls' return the GUID of the type Library.
485///
486/// Returns 'true' if successful, or 'false' otherwise.
487//
488bool
490{
491 int offset;
492 if (cls) {
493 int index = GetClassIndex(cls);
494 if (index == -1)
495 return false;
496 offset = ClassList[index].GuidOffset;
497 } else {
498 offset = LibGuidOffset;
499 }
501 return true;
502}
503
504/// Returns the GUID allocated as the specified index.
505/// \note Will allocate a new GUID if 'index' has not been allocated yet.
506//
509{
510 while (index >= LinkGuidCount) {
511 int id = AppClassId.AllocId();
512 if (!LinkGuidOffset)
513 LinkGuidOffset = id;
514 LinkGuidCount++;
515 }
516 return AppClassId[LinkGuidOffset + index];
517}
518
519/// Returns the TAutoClass instance as the specified index.
520//
523{
524 if (index >= (unsigned)ClassCount)
525 return 0;
526 return ClassList[index].Class;
527}
528
529/// Returns the TAutoClass instance assigned the specified GUID.
530//
533{
534 int offset = AppClassId.GetOffset(clsid);
535 if (offset != -1) {
536 TAutoClass::TAutoClassRef* ref = ClassList;
537 for (int count = ClassCount; count--; ref++) {
538 if (ref->GuidOffset == offset)
539 return ref->Class;
540 }
541 }
542 return 0;
543}
544
545/// Get the document template with the given GUID
546//
549{
550 int linkGuidIndex = 0;
551 for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
552 TRegList& regList = link->GetRegList();
553 if (regList["progid"]) {
554 LPCTSTR id = regList["clsid"];
555 if (!id) {
556 if (clsid == /*(GUID&)*/ GetLinkGuid(linkGuidIndex++))
557 return const_cast<TRegLink*>(link);
558 }
559 else {
560 TClassId classId(id);
561 if (clsid == (GUID&) classId)
562 return const_cast<TRegLink*>(link);
563 }
564 }
565 }
566
567 return 0;
568}
569
570/// Returns the 'ITypeLib' interface pointer describing the objects exposed by
571/// this instance of 'TAppDescriptor'.
572//
573ITypeLib*
575{
576 if (!ClassCount)
577 return 0;
578 if (!TypeLib) {
579 TypeLib = new TTypeLibrary(*this, AppLang);
580 }
581 ((IUnknown&)*TypeLib).AddRef();
582 return TypeLib;
583}
584
585//----------------------------------------------------------------------------
586// TServedObject list management
587//
588
589//
590//
591//
594{
595 TServedObject* p = ServedList;
596 for (; p; p = p->Next)
597 if (p->RootObject == mostDerivedObj)
598 break;
599 return p;
600}
601
602//
603//
604//
607{
608 if (objDesc.Object)
609 return FindServed(objDesc.MostDerived());
610 for (TServedObject* p = ServedList; p; p = p->Next)
611 if (p->Object == 0 && p->Class == objDesc.Class)
612 return p;
613 return 0;
614}
615
616//
617//
618//
619void
621{
622 if (ServedList)
623 ServedList->Prev = &obj.Next;
624 obj.Next = ServedList;
625 obj.Prev = &ServedList;
626 ServedList = &obj;
627}
628
629//
630//
631//
632void
634{
635 *obj.Prev = obj.Next;
636 if (obj.Next)
637 obj.Next->Prev = obj.Prev;
638}
639
640//
641//
642//
643void
645{
646 while (ServedList)
647 delete ServedList;
648}
649
650
651//
652//
653//
654void
656{
657 if (Creator)
658 {
659 delete Creator;
660 Creator = 0;
661 }
662}
663
664
665//
666//
667//
668void
670{
672 if (p) {
673 p->RootObject = 0;
674 p->Object = 0;
675 }
676}
677
678//
679//
680//
681void
683{
685 if (p) {
686 p->RootObject = 0;
687 p->Object = 0;
688 ((IUnknown*)(void*)p)->Release(); // destructs if no external connections ????????????????
689 }
690}
691
692//
693//
694//
695ITypeInfo*
697{
698 TServedObjectCreator& creator = ServedList ? ServedList->Creator
699 : *new TServedObjectCreator(*this);
700 TUnknown* obj = creator.CreateObject(TObjectDescriptor(0, cls));
701 IUnknown& unk = (IUnknown&)*obj;
702 ITypeInfo* typeInfo = 0;
703 unk.QueryInterface(IID_ITypeInfo, (void * *) &typeInfo);
704 return typeInfo;
705}
706
708{
709 AppLang = ParseLangId(langIdStr);
710}
711
712//
713/// Writes application and type library information to the given file.
714/// If the given \p regFilename is `nullptr`, then the information is written to the registry.
715///
716/// \exception TXRegistry may be thrown, if access to the registry is denied, unless the option
717/// \ref amQuietReg is specified, in which case such exceptions will be suppressed. Note that
718/// \ref amQuietReg will also suppress any other exception derived from \ref TXBase.
719//
721{
722 try {
724 tostream* strm = &regStrm;
726
727 // Check if registration output to Registry or to user-specified reg file
728 //
729 _TCHAR guidStr[40];
731#ifdef UNICODE
732 wofstream fileStrm;
733#else
734 ofstream fileStrm;
735#endif
736 if (regFilename) {
739 if (!fileStrm.good())
740 throw TXRegistry(regFilename, _T("file"));
741 strm = &fileStrm;
742 fileStrm << _T("REGEDIT\n"); // write registration file header
743 alwaysReg = true;
744 }
745 SetOption(amUnregServer, false);// cancel unregister on reregister
746
747 // Make sure that the app reginfo is in the registry
748 //
749 bool forceReg = alwaysReg;
750 if (AppProgId) { // don't attempt register app if no progid reg key
751 if (!forceReg) {
753 ocf::OcRegisterClass(RegInfo, Module, vstrm, AppLang, _T("\001\002\006"));
755 forceReg = true;
756 }
757 if (forceReg) {
758 _TCHAR* debugGuid = 0;
759 if (DebugGuidOffset) { // setup reg item for debug reg
760 TClassId debugClsid(AppClassId[DebugGuidOffset]);
763 if (ocf::OcSetupDebugReg(RegInfo, regDebug, AppLang, debugGuid)) {
764 ocf::OcRegisterClass(RegInfo, Module, *strm, AppLang, 0, 0, OcRegNoDebug);
765 ocf::OcRegisterClass(RegInfo, Module, *strm, AppLang, AppDebugFilter,
766 0, regDebug);
767 }
768 else {
769 debugGuid = 0; // if debug registration fails, use normal
770 }
771 }
772 if (!debugGuid)
773 ocf::OcRegisterClass(RegInfo, Module, *strm, AppLang, 0, 0,
774 (Options & amExeModule) ? 0 : OcRegNotDll);
775 }
776 }
777
778 // Write templates to registration file as needed
779 //
780 int linkGuidIndex = 0;
781 TRegItem regAppName[2] = {{"appname",{RegInfo["appname"]}}, {0,{0}}};
782 for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
783 TRegList& regList = link->GetRegList();
784 if (regList["progid"]) {
785 _TCHAR guidStr[40];
786 int debugStat = (Options & amExeModule) ?
788 TRegItem regClsid[3] = {{"debugger",{_T("")}}, {"clsid",{guidStr}}, {0,{0}}};
790 if (!debugStat && Options & amExeModule)
791 clsInfo++; // no cancel debugger if no debugprogid
792 if (!regList["clsid"]) { // check if GUID needs to be assigned
795 }
796 else {
797 regClsid[1].Key = 0; // shorten list to exclude auto-assigned clsid
798 }
799 if (!alwaysReg) {
801 ocf::OcRegisterClass(regList, Module, checkStrm, AppLang,
802 _T("\001\002\006"), 0, clsInfo);
804 continue;
805 }
806 if (debugStat) {
807 ocf::OcRegisterClass(regList, Module, *strm, AppLang, 0, regAppName, regClsid);
808 if (debugStat == 1) { // needs generated guid string
811 }
812 ocf::OcRegisterClass(regList, Module, *strm, AppLang, DocDebugFilter,
814 }
815 else {
816 ocf::OcRegisterClass(regList, Module, *strm, AppLang, 0, regAppName, clsInfo);
817 }
818 forceReg = true;
819 }
820 }
821 if (forceReg && !regFilename)
823 if (forceReg && TRegKey::GetClassesRoot().HasSubkey(_T("OcErr_RegServer")))
824 TRegKey::GetClassesRoot().DeleteKey(_T("OcErr_RegServer"));
825 }
826 catch ([[maybe_unused]] const TXBase& x)
827 {
828 TRACEX(OcfDll, 0, _T("TAppDescriptor::RegisterServer: Exception: ") << x.why());
829 try
830 {
831 TRegKey::GetClassesRoot().SetValue(_T("OcErr_RegServer"), tstring{AppClassId});
832 }
833 catch (...)
834 {
835 WARNX(OcfDll, true, 0, _T("TAppDescriptor::RegisterServer: Failed to set HKEY_CLASSES_ROOT\\OcErr_RegServer."));
836 }
838 throw;
839 WARNX(OcfDll, true, 0, _T("TAppDescriptor::RegisterServer: Exception suppressed."));
840 }
841}
842
843//
844/// Removes all application and type library information from the registry.
845///
846/// \exception TXRegistry may be thrown, if access to the registry is denied, unless the option
847/// \ref amQuietReg is specified, in which case such exceptions will be suppressed. Note that
848/// \ref amQuietReg will also suppress any other exception derived from \ref TXBase.
849//
851{
852 try
853 {
854 const auto ocUnregisterClass = [&](TRegList& regInfo, const TRegItem& overrides)
855 {
856 return OcUnregisterClass(regInfo, overrides.Key ? const_cast<TRegItem*>(&overrides) : nullptr);
857 };
858
859 // Unregister the app, provided an application ProgId is defined.
860 //
861 if (AppProgId)
862 {
863 const auto deleteSubkeyIfExists = [](TRegKey& key, LPCTSTR subkey)
864 {
865 if (key.HasSubkey(subkey))
866 key.DeleteKey(subkey);
867 };
868
869 ocUnregisterClass(RegInfo, DebugGuidOffset ? TRegItem{"debugclsid", AppClassId[DebugGuidOffset]} : TRegItem{}); // AppClassId[] returns a temporary to which TRegItem refers, so this needs to be performed in one statement!
870 if (LibGuidOffset)
871 if (auto typeLibKey = TRegKey::GetClassesRoot().GetSubkey(_T("TypeLib")))
873 if (ClassCount > 0)
874 if (auto interfaceKey = TRegKey::GetClassesRoot().GetSubkey(_T("Interface")))
875 for (auto i = 0; i != ClassCount; ++i)
876 deleteSubkeyIfExists(*interfaceKey, AppClassId[ClassList[i].GuidOffset]);
877 }
878
879 // Remove any defined templates from the registry.
880 //
881 auto linkGuidIndex = 0;
882 for (auto link = LinkHead; link; link = link->GetNext())
883 {
884 auto& regList = link->GetRegList();
885 if (regList["progid"])
886 ocUnregisterClass(regList, !regList["clsid"] ? TRegItem{"clsid", GetLinkGuid(linkGuidIndex++)} : TRegItem{}); // GetLinkGuid returns a temporary to which TRegItem refers, so this needs to be performed in one statement!
887 }
888 }
889 catch ([[maybe_unused]] const TXBase& x)
890 {
891 TRACEX(OcfDll, 0, _T("TAppDescriptor::UnregisterServer: Exception: ") << x.why());
893 throw;
894 WARNX(OcfDll, true, 0, _T("TAppDescriptor::UnregisterServer: Exception suppressed."));
895 }
896}
897
898//
899/// Writes a type library description for this application to the given file.
900///
901/// \exception TXRegistry may be thrown, if access to the registry is denied, unless the option
902/// \ref amQuietReg is specified, in which case such exceptions will be suppressed. Note that
903/// \ref amQuietReg will also suppress any other exception derived from \ref TXBase.
904//
906{
907 if (ClassCount <= 0) return;
908 try
909 {
919 ::GetModuleFileName(*Module, fullPath, COUNTOF(fullPath));
924 libDir[0] ? libDir : exeDir,
926 libExt[0] ? libExt : _T("OLB"));
927 WriteTypeLibrary(AppLang, fullPath); // Note: Implemented in "typelib.cpp".
928 if (TRegKey::GetClassesRoot().HasSubkey(_T("OcErr_Typelib")))
929 TRegKey::GetClassesRoot().DeleteKey(_T("OcErr_Typelib"));
930 }
931 catch ([[maybe_unused]] const TXBase& x)
932 {
933 TRACEX(OcfDll, 0, _T("TAppDescriptor::MakeTypeLib: Exception: ") << x.why());
934 try
935 {
936 TRegKey::GetClassesRoot().SetValue(_T("OcErr_Typelib"), tstring{AppClassId});
937 }
938 catch (...)
939 {
940 WARNX(OcfDll, true, 0, _T("TAppDescriptor::MakeTypeLib: Failed to set HKEY_CLASSES_ROOT\\OcErr_Typelib."));
941 }
943 throw;
944 WARNX(OcfDll, true, 0, _T("TAppDescriptor::MakeTypeLib: Exception suppressed."));
945 }
946}
947
948//
949/// Processes known options on the command line.
950///
951/// Registry options (one allowed):
952///
953/// - RegServer [&lt;regfile&gt;]
954/// - UnregServer/Unregister
955/// - NoRegValidate
956///
957/// Auxiliary options:
958///
959/// - Automation
960/// - Debug
961/// - Embedding
962/// - Language &lt;langid&gt;
963/// - QuietReg
964/// - TypeLib [&lt;name&gt;]
965///
966/// On return, the given \p cmdLine will have the processed options removed.
967///
968/// \note If no registry option (\p RegServer, \p UnregServer or \p NoRegValidate) is specified on
969/// the command line, then validation of the registry entries will be performed. If validation
970/// fails, then the registry is updated as if registration was specified. Pass \p NoRegValidate to
971/// suppress this behaviour.
972///
973/// \exception TXRegistry may be thrown, if access to the registry is denied, unless the option
974/// \p QuietReg is specified, in which case such exceptions will be suppressed. Note that
975/// \p QuietReg will also suppress any other exception derived from \ref TXBase.
976//
978{
979 struct
980 {
981 TOcAppMode Flag;
982 LPCTSTR Option;
983 bool IsAction;
984 }
985 const optionTbl[] =
986 {
987 // Registry options (one allowed):
988 //
989 {amRegServer, _T("RegServer"), true},
990 {amUnregServer, _T("UnregServer"), true},
991 {amUnregServer, _T("Unregister"), true},
992 {amNoRegValidate, _T("NoRegValidate"), false},
993
994 // Auxiliary options:
995 //
996 {amAutomation, _T("Automation"), false},
997 {amDebug, _T("Debug"), false},
998 {amEmbedding, _T("Embedding"), false},
999 {amLangId, _T("Language"), false},
1000 {amQuietReg, _T("QuietReg"), false},
1001 {amTypeLib, _T("TypeLib"), true},
1002 };
1003
1004 const auto isRegistryOptionSet = [](uint32 flags)
1005 {
1006 return (flags & (amRegServer | amUnregServer | amNoRegValidate)) != 0;
1007 };
1008
1009 // Parse the command line.
1010 //
1011 using TAction = pair<TOcAppMode, tstring>; // Option flag and argument.
1012 auto actions = vector<TAction>{};
1013 auto cl = TCmdLine{cmdLine};
1014 while (cl.GetTokenKind() != TCmdLine::Done)
1015 switch (cl.GetTokenKind())
1016 {
1017 case TCmdLine::Option:
1018 {
1019 const auto option = cl.GetToken();
1020 const auto i = find_if(begin(optionTbl), end(optionTbl), [&option](const auto& entry)
1021 { return _tcsicmp(entry.Option, option.c_str()) == 0; });
1022 if (i == end(optionTbl))
1023 {
1024 WARNX(OcfDll, true, 1, _T("TAppDescriptor::ProcessCmdLine: Unknown option: ") << option);
1025 cl.NextToken(false); // Skip this option, but leave it on the command line.
1026 break;
1027 }
1028
1029 // Record this option.
1030 //
1031 const auto hasMultipleRegistryOptions = (isRegistryOptionSet(Options) && isRegistryOptionSet(i->Flag));
1032 WARNX(OcfDll, hasMultipleRegistryOptions, 0, _T("TAppDescriptor::ProcessCmdLine: Multiple registry options are specified."));
1033 SetOption(i->Flag, true);
1034 cl.NextToken(true); // Remove the option from the command line.
1035 const auto arg = (cl.GetTokenKind() == TCmdLine::Value) ? cl.GetToken() : tstring{};
1036 if (i->IsAction)
1037 actions.push_back(make_pair(i->Flag, arg));
1038 else if (i->Flag == amLangId && !arg.empty())
1039 SetLangId(AppLang, arg.c_str());
1040 while (cl.GetTokenKind() == TCmdLine::Value)
1041 cl.NextToken(true); // Remove all arguments following the option.
1042 break;
1043 }
1044 default:
1045 cl.NextToken(); // Skip.
1046 break;
1047 }
1048
1049 // Set single use, if this is an automated exe server.
1050 //
1052 SetOption(amSingleUse, true);
1053
1054 // Perform specified actions.
1055 //
1056 for (const auto& a : actions)
1057 {
1058 const auto arg = a.second.empty() ? nullptr : a.second.c_str();
1059 switch (a.first)
1060 {
1061 case amRegServer: RegisterServer(AppLang, arg); break;
1062 case amUnregServer: UnregisterServer(); break;
1063 case amTypeLib: MakeTypeLib(AppLang, arg); break;
1064 default: CHECKX(false, _T("TAppDescriptor::ProcessCmdLine: Unexpected action flag: ") + to_tstring(a.first));
1065 }
1066 }
1067 cmdLine = cl.GetLine(); // Update the command line with processed options removed.
1068
1069 // Perform registry validation, if no registry option was specified.
1070 //
1071 // Note: RegisterServer executes in validation mode when amRegServer is not set. If validation
1072 // fails, the registry will be updated, as if registration was specified. See the implementation
1073 // for details. The registry option NoRegValidate can be specified on the command line to
1074 // suppress this validation call.
1075 //
1076 if (!isRegistryOptionSet(Options))
1077 RegisterServer(0); // Validate registry entries.
1078}
1079
1080//
1081// //?????????????????????????? What with UNICODE
1082//
1083static TLangId ParseLangId(LPCTSTR text)
1084{
1085 static _TCHAR HexChar[] = _T("0123456789ABCDEF0123456789abcdef");
1086 TLangId lang = 0;
1087 _TUCHAR c;
1088 _TCHAR* pc;
1089 while (text && (c = *text++) != 0) {
1090 if ((pc = _tcschr(HexChar, c)) == 0)
1091 return 0; // illegal character
1092 lang = TLangId((lang << 4) + (short(pc-HexChar) & 15));//????????????????????
1093 }
1095}
1096
1097//
1098//
1099//
1100void
1102{
1103 int oldCount = ClassCount;
1104 ClassCount = TAutoClass::ClassList.CountAutoClasses();
1105 if (ClassCount) {
1106
1107 // Allocated GUID for type Library
1108 //
1109 if (!LibGuidOffset)
1110 LibGuidOffset = AppClassId.AllocId();
1111
1112 TAutoClass::TAutoClassRef* oldList = ClassList;
1113 ClassList = new TAutoClass::TAutoClassRef[ClassCount];
1114 TAutoClass::ClassList.MergeAutoClasses(ClassList);
1115 TAutoClass::TAutoClassRef* ref = ClassList;
1116 for (int count = ClassCount; count--; ref++) {
1117 if (oldCount) {
1118 ref->GuidOffset = oldList->GuidOffset;
1119 oldCount--;
1120 oldList++;
1121 }
1122 else {
1123 ref->GuidOffset = AppClassId.AllocId();
1124 }
1125 }
1126 }
1127}
1128
1129} // OCF namespace
1130
1131//==============================================================================
1132
TAppDescriptor - OLE application descriptor definitions.
#define WARNX(group, condition, level, message)
Definition checks.h:277
#define CHECKX(condition, message)
Definition checks.h:245
#define DIAG_DECLARE_GROUP(group)
Definition checks.h:404
#define TRACEX(group, level, message)
Definition checks.h:263
void ProcessCmdLine(owl::tstring &cmdLine)
Processes known options on the command line.
Definition appdesc.cpp:977
void RegisterServer(owl::TLangId lang, LPCTSTR regFile=0)
Writes application and type library information to the given file.
Definition appdesc.cpp:720
void SetOption(owl::uint32 bit, bool state)
Definition appdesc.h:75
bool GetClassId(TAutoClass *cls, GUID &retId)
Retrieves the GUID of the specified TAutoClass instance.
Definition appdesc.cpp:489
TAutoClass * GetAutoClass(unsigned index)
Returns the TAutoClass instance as the specified index.
Definition appdesc.cpp:522
void SetLangId(owl::TLangId prevLang, LPCTSTR langIdStr)
Definition appdesc.cpp:707
HRESULT _IFUNC GetLicInfo(LICINFO *licInfo)
Definition appdesc.cpp:345
bool RegisterObject(TObjectDescriptor app)
Registers the helper object (TServedObject) of the class described via the 'app' parameter as the act...
Definition appdesc.cpp:427
TAppDescriptor(owl::TRegList &regInfo, TComponentFactory callback, owl::tstring &cmdLine, owl::TModule *module=&owl::GetGlobalModule(), const owl::TRegLink *regLink=0, owl::uint32 preselectedOptions=0)
Definition appdesc.cpp:39
bool IsOptionSet(owl::uint32 option) const
Definition appdesc.h:73
void AddServed(TServedObject &obj)
Definition appdesc.cpp:620
void RegisterClass()
Register an EXE class object with OLE so that other applications can connect to it.
Definition appdesc.cpp:399
friend class _ICLASS TTypeLibrary
Definition appdesc.h:194
void UnregisterObject()
Invalidates a helper object registers with RegisterObject earlier.
Definition appdesc.cpp:459
void MakeTypeLib(owl::TLangId lang, LPCTSTR str=0)
Writes a type library description for this application to the given file.
Definition appdesc.cpp:905
void WriteTypeLibrary(owl::TLangId lang, LPCTSTR file)
Definition typelib.cpp:195
void UnregisterServer(owl::TLangId lang=0, LPCTSTR str=0)
Removes all application and type library information from the registry.
Definition appdesc.cpp:850
ITypeLib * GetTypeLibrary()
Returns the 'ITypeLib' interface pointer describing the objects exposed by this instance of 'TAppDesc...
Definition appdesc.cpp:574
void RemoveServed(TServedObject &obj)
Definition appdesc.cpp:633
TUnknown * CreateAutoApp(TObjectDescriptor app, owl::uint32 options, IUnknown *outer=0)
Creates a TServedObject helper object which implements an IDispatch implementation on behalf of the '...
Definition appdesc.cpp:162
void ReleaseObject(const void *obj)
Definition appdesc.cpp:682
TUnknown * CreateAutoObject(TObjectDescriptor obj, TServedObject &app, IUnknown *outer=0)
Creates a TServedObject helper which implements IDispatch on behalf of the class described via the 'o...
Definition appdesc.cpp:205
void UnregisterClass()
Invalidates application class registered earlier with 'RegisterClass'.
Definition appdesc.cpp:415
owl::uint16 GetVersionField(owl::uint field)
Returns version as a whole number.
Definition appdesc.cpp:379
void InvalidateObject(const void *obj)
Definition appdesc.cpp:669
HRESULT _IFUNC CreateInstanceLic(IUnknown *outer, IUnknown *reserved, const IID &iid, BSTR key, void **retObject)
Definition appdesc.cpp:364
ITypeInfo * CreateITypeInfo(TAutoClass &cls)
Definition appdesc.cpp:696
TBaseClassId AppClassId
Definition appdesc.h:136
HRESULT _IFUNC RequestLicKey(DWORD reserved, BSTR *retKey)
Definition appdesc.cpp:355
HRESULT _IFUNC LockServer(int lock)
Definition appdesc.cpp:327
HRESULT _IFUNC CreateInstance(IUnknown *outer, const IID &iid, void **retObject)
Definition appdesc.cpp:271
int GetClassIndex(TAutoClass *cls)
Returns the index of a 'TAutoClass' instance.
Definition appdesc.cpp:473
TClassId GetLinkGuid(int index)
Returns the GUID allocated as the specified index.
Definition appdesc.cpp:508
owl::TRegLink * GetRegLink(const GUID &clsid)
Get the document template with the given GUID.
Definition appdesc.cpp:548
void ReleaseAutoApp(TObjectDescriptor app)
Releases the helper object (TServedObject) implementing IDispatch on behalf of the 'Application' obje...
Definition appdesc.cpp:193
TServedObject * FindServed(const void *mostDerivedObj)
Definition appdesc.cpp:593
int GetOffset(const GUID &guid)
Definition oleutil.cpp:168
GUID/IID/CLSID management.
Definition oleutil.h:171
TUnknown * CreateObject(TObjectDescriptor objDesc, IUnknown *outer=0)
Definition autosrv.cpp:32
OLE object exposed for automated access of internal object.
Definition autodefs.h:972
TServedObjectCreator & Creator
Definition autodefs.h:985
void * Object
pointer to C++ object instance, 0 if deleted
Definition autodefs.h:982
const void * RootObject
pointer to object of most derived class
Definition autodefs.h:983
Standard implementation of a controlling IUnknown for an object, to be inherited with other COM inter...
Definition oleutil.h:264
Command line argument processing class, processes in the form:
Definition cmdline.h:35
@ Option
Option type token. Leading / or - skipped by Token.
Definition cmdline.h:40
@ Value
Value for name or option. Leading : or = skipped by Token.
Definition cmdline.h:41
@ Done
No more tokens.
Definition cmdline.h:42
ObjectWindows dynamic-link libraries (DLLs) construct an instance of TModule, which acts as an object...
Definition module.h:75
Encapsulates a registration key in the Windows Registry.
Definition registry.h:115
static auto GetClassesRoot() -> TRegKey &
Special predefined root key used by shell and OLE applications (HKEY_CLASSES_ROOT).
Definition registry.cpp:32
auto HasSubkey(const tstring &keyName) const -> bool
Returns true if this key has a subkey with the given name.
Definition registry.cpp:354
long DeleteKey(LPCTSTR subKeyName)
Deletes the specified subkey of this registry key.
Definition registry.h:878
A registration parameter table, composed of a list of TRegItems.
Definition registry.h:531
TLocaleString & LookupRef(LPCSTR key)
Looks up and returns a reference to a local string value associated with a particular item name (key)...
Definition regheap.cpp:80
LPCTSTR Lookup(LPCSTR key, TLangId lang=TLocaleString::UserDefaultLangId)
Performs the lookup of the TRegItems using a key (an item name such as progid) and returns the value ...
Definition regheap.cpp:58
Derived from xmsg, TXBase is the base class for ObjectWindows and ObjectComponents exception-handling...
Definition exbase.h:41
Thrown for errors within the Registry classes.
Definition registry.h:457
Command line parsing class.
char TCHAR
Definition cygwin.h:42
#define _tcscpy
Definition cygwin.h:79
#define _MAX_PATH
Definition cygwin.h:97
#define _tcsicmp
Definition cygwin.h:76
#define _T(x)
Definition cygwin.h:51
#define _tcschr
Definition cygwin.h:85
THandle GetHandle() const
Return the instance handle of the library module represented by the TModule obect.
Definition module.h:1233
#define ocrSingleUse
Single client per instance.
Definition registry.h:726
Include for OC, gets common headers when precompiled headers are enabled.
#define _W2A(lpw)
Definition memory.h:219
#define _USES_CONVERSION
Definition memory.h:217
Object Component Framework (COM encapsulation)
Definition appdesc.h:22
int OcRegistryValidate(owl::tistream &in)
Definition ocreg.h:46
const int DebugRegCount
Definition ocreg.h:62
IUnknown *(* TComponentFactory)(IUnknown *outer, owl::uint32 options, owl::uint32 id)
Definition appdesc.h:35
TCHAR DocDebugFilter[]
Definition ocreg.cpp:311
int OcSetupDebugReg(owl::TRegList &regInfo, owl::TRegItem *regDebug, owl::TLangId lang, TCHAR *clsid)
Walk thru a reginfo list using debug entries to create a parallel non-debug set for alternate,...
Definition ocreg.cpp:332
const void * MostDerived(const void *obj, const std::type_info &src)
Definition autosym.cpp:416
void OcRegistryUpdate(owl::tistream &in)
Definition ocreg.h:50
TCHAR AppDebugFilter[]
Definition ocreg.cpp:310
owl::TRegItem OcRegNotDll[]
Definition ocreg.cpp:305
const GUID & iid
Definition appdesc.h:328
owl::TRegItem OcRegNoDebug[]
Definition ocreg.cpp:304
long OcRegisterClass(owl::TRegList &regInfo, owl::TModule *module, owl::tostream &out, owl::TLangId lang, LPCTSTR filter=0, owl::TRegItem *defaults=0, owl::TRegItem *overrides=0)
Generate OLE registration file image to an output stream.
Definition ocreg.cpp:187
TOcAppMode
Application running mode and registration flags these are initialized when processing command line or...
Definition ocreg.h:78
@ amAutomation
set from cmdline when EXE lauched for automation
Definition ocreg.h:81
@ amQuietReg
suppress error UI during registration processing
Definition ocreg.h:91
@ amTypeLib
requested typelib to be generated and registered
Definition ocreg.h:84
@ amRegServer
complete registration database update requested
Definition ocreg.h:79
@ amUnregServer
registration database unregistration requested
Definition ocreg.h:80
@ amSingleUse
set from app reg, may be forced on per instance
Definition ocreg.h:90
@ amServedApp
per instance flag, app refcnt held by container
Definition ocreg.h:89
@ amLangId
user registration requested a particular LangId
Definition ocreg.h:83
@ amExeMode
may be overridden per instance if running DLL
Definition ocreg.h:88
@ amExeModule
set for EXE components, 0 if DLL inproc server
Definition ocreg.h:87
@ amDebug
user requested launching for debugging
Definition ocreg.h:85
@ amNoRegValidate
user request to suppress registry validation
Definition ocreg.h:86
@ amEmbedding
cmdline, overridden per Instance if embedded DLL
Definition ocreg.h:82
@ amRun
set in factory call to run application msg loop
Definition ocreg.h:92
int OcUnregisterClass(owl::TRegList &regInfo, owl::TRegItem *overrides=0)
Unregister application or class from registration database.
Definition ocreg.cpp:282
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
unsigned long ulong
Definition number.h:26
unsigned long uint32
Definition number.h:34
owl::uint16 TLangId
Holds a language ID, a predefined number that represents a base language and dialect.
Definition lclstrng.h:26
std::stringstream tstringstream
Definition strmdefs.h:38
TModule * Module
Definition global.cpp:34
unsigned short uint16
Definition number.h:33
std::string tstring
Definition defs.h:79
std::ostream tostream
Definition strmdefs.h:40
auto to_tstring(const T &v) -> tstring
Definition defs.h:82
#define HR_NOINTERFACE
Definition defs.h:79
#define HR_OK
Definition defs.h:74
#define HR_NOERROR
Definition defs.h:73
#define HR_OUTOFMEMORY
Definition defs.h:77
#define HR_FAIL
Definition defs.h:83
#define OLECALL(func, msg)
Definition except.h:78
OLE Registration definitions.
#define _IFUNC
Definition oleutil.h:28
#define COUNTOF(s)
Array element count Important: Only use this with an argument of array type.
Definition defs.h:376
virtual HRESULT _IFUNC RequestLicKey(BSTR *retKey)=0
virtual HRESULT _IFUNC GetLicInfo(LICINFO *licInfo)=0
virtual HRESULT _IFUNC QueryLicKey(BSTR key)=0
@ Delete
automation object deletes the C++ object serviced
Definition autodefs.h:473
@ PostQuit
automation object posts a quit message to application
Definition autodefs.h:474
@ Quiet
behavior when an automation helper is freed
Definition autodefs.h:472
Designed to provide support for localized registration parameters, the TLocaleString Struct defines a...
Definition lclstrng.h:68
static TLangId UserDefaultLangId
The user-defined default language identifier.
Definition lclstrng.h:87
A single registration list entry.
Definition registry.h:508