OWLNext    7.0
Borland's Object Windows Library for the modern age
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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