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

  1. //
  2. //----------------------------------------------------------------------------
  3. // ObjectComponents
  4. // (C) Copyright 1994 by Borland International, All Rights Reserved
  5. //
  6. //   OLE Registration implementation
  7. //----------------------------------------------------------------------------
  8. #include <ocf/ocfpch.h>
  9. #include <ocf/ocreg.h>
  10. #include <ocf/appdesc.h>
  11. #include <shellapi.h>
  12. #include <string.h>
  13. #include <stdlib.h>  // atol()
  14.  
  15. DIAG_DEFINE_GROUP(OcDll, true, 1);
  16. DIAG_DECLARE_GROUP(OcRefCount);
  17.  
  18. #if defined(BI_APP_DLL)
  19.   extern TRegistrar* DllRegistrar;
  20. #endif
  21.  
  22. void TXRegistry::Check(long stat, const char* key)
  23. {
  24.   if (stat != 0 && !InstanceCount) {
  25.     if (stat == 1)      // default bool true to a generic E_FAIL
  26.       stat = E_FAIL;
  27.     char buf[100];
  28.     wsprintf(buf, "Registry failure on key: %s, ErrorCode = %lX\n",
  29.              (const char far*)key, stat); 
  30.     WARN(stat != 0, buf);
  31.     throw TXRegistry(buf, key);
  32.   }
  33. }
  34.  
  35. //____________________________________________________________________________
  36. //
  37. // Internal registration template table and registration item key table
  38. //____________________________________________________________________________
  39.  
  40. char OcRegEntryHeader[] = "HKEY_CLASSES_ROOT\\";
  41. char OcRegEntryAssign[] = " = ";
  42.  
  43. struct TRegParam {
  44.   char*  Param;    // substituted parameter name
  45.   char*  Default;  // default value, 0 if required
  46.   char*  TplList;  // list of template indices to invoke
  47.   static int Find(const char* param); // associative lookup of value by param
  48. };
  49.  
  50. //
  51. // Registration template table, ordering determines sequence of registration
  52. //  note: the parameter table is dependent on template indices in this table
  53. //
  54. char* OcRegTemplates[] = {
  55. #if defined(BI_PLAT_WIN32)
  56. /* 001 */ "CLSID\\<clsid>\\<serverctx>Server32 = <debugger> <path> <cmdline><extraopt>",
  57. #else
  58. /* 001 */ "CLSID\\<clsid>\\<serverctx>Server = <debugger> <path> <cmdline><extraopt>",
  59. #endif
  60. /* 002 */ "CLSID\\<clsid>\\ProgID = <progid>",
  61. /* 003 */ "CLSID\\<clsid> = <description>",
  62. /* 004 */ "CLSID\\<clsid>\\DefaultIcon = <path>,<iconindex>",
  63. #if defined(BI_PLAT_WIN32)
  64. /* 005 */ "CLSID\\<clsid>\\InprocHandler32 = <handler>",
  65. #else
  66. /* 005 */ "CLSID\\<clsid>\\InprocHandler = <handler>",
  67. #endif
  68. /* 006 */ "<progid>\\CLSID = <clsid>",
  69. /* 007 */ "<progid> = <description>",
  70.  
  71. /* 010 */ "<progid>\\protocol\\StdFileEditing\\verb\\0 = <verb0>",
  72. /* 011 */ "<progid>\\protocol\\StdFileEditing\\verb\\1 = <verb1>",
  73. /* 012 */ "<progid>\\protocol\\StdFileEditing\\verb\\2 = <verb2>",
  74. /* 013 */ "<progid>\\protocol\\StdFileEditing\\verb\\3 = <verb3>",
  75. /* 014 */ "<progid>\\protocol\\StdFileEditing\\verb\\4 = <verb4>",
  76. /* 015 */ "<progid>\\protocol\\StdFileEditing\\verb\\5 = <verb5>",
  77. /* 016 */ "<progid>\\protocol\\StdFileEditing\\verb\\6 = <verb6>",
  78. /* 017 */ "<progid>\\protocol\\StdFileEditing\\verb\\7 = <verb7>",
  79.  
  80. /* 020 */ "CLSID\\<clsid>\\Verb\\0 = <verb0>,<verb0opt>",
  81. /* 021 */ "CLSID\\<clsid>\\Verb\\1 = <verb1>,<verb1opt>",
  82. /* 022 */ "CLSID\\<clsid>\\Verb\\2 = <verb2>,<verb2opt>",
  83. /* 023 */ "CLSID\\<clsid>\\Verb\\3 = <verb3>,<verb3opt>",
  84. /* 024 */ "CLSID\\<clsid>\\Verb\\4 = <verb4>,<verb4opt>",
  85. /* 025 */ "CLSID\\<clsid>\\Verb\\5 = <verb5>,<verb5opt>",
  86. /* 026 */ "CLSID\\<clsid>\\Verb\\6 = <verb6>,<verb6opt>",
  87. /* 027 */ "CLSID\\<clsid>\\Verb\\7 = <verb7>,<verb7opt>",
  88.  
  89. /* 030 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\0 = <format0>",
  90. /* 031 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\1 = <format1>",
  91. /* 032 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\2 = <format2>",
  92. /* 033 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\3 = <format3>",
  93. /* 034 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\4 = <format4>",
  94. /* 035 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\5 = <format5>",
  95. /* 036 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\6 = <format6>",
  96. /* 037 */ "CLSID\\<clsid>\\DataFormats\\GetSet\\7 = <format7>",
  97.  
  98. /* 040 */ "CLSID\\<clsid>\\MiscStatus = <aspectall>",
  99. /* 041 */ "CLSID\\<clsid>\\MiscStatus\\1 = <aspectcontent>",
  100. /* 042 */ "CLSID\\<clsid>\\MiscStatus\\2 = <aspectthumbnail>",
  101. /* 043 */ "CLSID\\<clsid>\\MiscStatus\\4 = <aspecticon>",
  102. /* 044 */ "CLSID\\<clsid>\\MiscStatus\\8 = <aspectdocprint>",
  103. /* 045 */ "CLSID\\<clsid>\\AuxUserType\\2 = <menuname>",
  104. /* 046 */ "CLSID\\<clsid>\\AuxUserType\\3 = <appname>",
  105. /* 047 */ "CLSID\\<clsid>\\Insertable",
  106.  
  107. /* 050 */ "<permid> = <permname>",
  108. /* 051 */ "<permid>\\CLSID = <clsid>",
  109. /* 052 */ "<permid>\\CurVer = <progid>",
  110. /* 053 */ "CLSID\\<clsid>\\VersionIndependentProgID = <permid>",
  111.  
  112. /* 054 */ "CLSID\\<clsid>\\Version = <version>",
  113. /* 055 */ "CLSID\\<clsid>\\DataFormats\\DefaultFile = <filefmt>",
  114. /* 056 */ "CLSID\\<clsid>\\Ole1Class = <progid>",  // is this really needed?
  115. /* 057 */ ".<extension> = <progid>",
  116.  
  117. /* 060 */ "<progid>\\Shell\\Print\\Command = <path> %1",
  118. /* 061 */ "<progid>\\Shell\\Open\\Command = <path> %1",
  119. /* 062 */ "<progid>\\protocol\\StdFileEditing\\server = <debugger> <path><extraopt>",
  120. /* 063 */ "<progid>\\Insertable",
  121.            };
  122.  
  123. const int OcRegTemplateCount   = sizeof(OcRegTemplates)/sizeof(char*);
  124.  
  125. //
  126. // Registration parameter table, ordering is arbitrary, parameters lowercase
  127. //
  128. TRegParam OcRegParams[] = {
  129.   {"clsid",             0, ""                },// GUID standard string form
  130.   {"progid",            0, "\001\002\003\005\006\007"},// a unique string
  131.   {"insertable",        0, "\046\047\062\063" },// defined to publish server
  132.   {"usage",  ocrSingleUse, ""                },// class factory registration
  133.   {"description",       0, ""                },// human readable, 40 chars max
  134. #if defined(BI_PLAT_WIN32)
  135.   {"handler", "ole32.dll", "\005"            },// inproc handler
  136. #else
  137.   {"handler",  "ole2.dll", "\005"            },// inproc handler
  138. #endif
  139.   {"serverctx",         0, "\001"            },// "Local"(EXE) or "Inproc"(DLL)
  140.   {"path",              0, ""                },// OC defaults to load path
  141.   {"cmdline",          "", ""                },// /Automation if app class
  142.   {"debugger",         "", ""                },// debugger to invoke server
  143.   {"permid",            0, "\050\051\053"    },// version independent clsid
  144.   {"permname",          0, "\052"            },// version independent progid
  145.   {"iconindex",       "0", "\004"            },// zero-based resource icon
  146.   {"menuname",         "", "\045"            },// 15 characters maximum
  147.   {"appname",           0, ""                },// AppName, AuxUserType/3
  148.   {"verb0",             0, "\010\020"        },// name of primary verb
  149.   {"verb1",             0, "\011\021"        },
  150.   {"verb2",             0, "\012\022"        },
  151.   {"verb3",             0, "\013\023"        },
  152.   {"verb4",             0, "\014\024"        },
  153.   {"verb5",             0, "\015\025"        },
  154.   {"verb6",             0, "\016\026"        },
  155.   {"verb7",             0, "\017\027"        },
  156.   {"verb8",             0, "\018\028"        },
  157.   {"verb0opt",      "0,2", "\020"            },//generated from REGVERBOBT macro
  158.   {"verb1opt",      "0,2", "\021"            },
  159.   {"verb2opt",      "0,2", "\022"            },
  160.   {"verb3opt",      "0,2", "\023"            },
  161.   {"verb4opt",      "0,2", "\024"            },
  162.   {"verb5opt",      "0,2", "\025"            },
  163.   {"verb6opt",      "0,2", "\026"            },
  164.   {"verb7opt",      "0,2", "\027"            },
  165.   {"verb8opt",      "0,2", "\028"            },
  166.   {"format0",           0, "\030"            },//generated from REGFORMAT macro
  167.   {"format1",           0, "\031"            },
  168.   {"format2",           0, "\032"            },
  169.   {"format3",           0, "\033"            },
  170.   {"format4",           0, "\034"            },
  171.   {"format5",           0, "\035"            },
  172.   {"format6",           0, "\036"            },
  173.   {"format7",           0, "\037"            },
  174.   {"format8",           0, "\038"            },
  175.   {"filefmt",           0, "\055"            },// default file format name
  176.   {"aspectall",       "0", "\040"            },// option flags for all aspects
  177.   {"aspectcontent",     0, "\041"            },// option flags for content view
  178.   {"aspectthumbnail",   0, "\042"            },// option flags thumbnail view
  179.   {"aspecticon",        0, "\043"            },// option flags for icon view
  180.   {"aspectdocprint",    0, "\044"            },// option flags docprint view
  181.   {"extension",         0, "\057\060\061"    },// extension for shell loading
  182.   {"version",           0, "\054"            },// app/typelib version string
  183.   {"helpdir",           0, ""                },// help directory for typehelp
  184.   {"typehelp",          0, ""                },// help file for type library
  185.   {"language",          0, ""                },// set internally from func arg
  186.   {"docflags",        "0", ""                },
  187.   {"directory",         0, ""                },
  188.   {"docfilter",         0, ""                },
  189.   {"debugclsid",        0, ""/*INTERNAL GEN*/},// internal,NOT USER SPECIFIED 
  190.   {"extraopt",         "", ""/*INTERNAL USE*/},// cmdline debug/non-debug flag
  191.   {"debugprogid",       0, ""                },// define to force debug reg
  192.   {"debugdesc",         0, ""                },// different string for debug
  193. };
  194. const int OcRegParamCount = sizeof(OcRegParams)/sizeof(TRegParam);
  195.  
  196. int TRegParam::Find(const char* param)
  197. {
  198.   PRECONDITION(param);
  199.  
  200.   int i = ::OcRegParamCount;
  201.   while (--i >= 0) {
  202.     if (strcmp(::OcRegParams[i].Param, param) == 0)
  203.       break;
  204.   }
  205.   return i;
  206. }
  207.  
  208. //____________________________________________________________________________
  209. //
  210. // Generate registration file image to an output stream
  211. //____________________________________________________________________________
  212.  
  213. static int OcRegWrite(const char* key, const char* val, ostream& out)
  214. {
  215.   PRECONDITION(key);
  216.  
  217.   out << OcRegEntryHeader << key;
  218.   if (val)
  219.     out << OcRegEntryAssign << val;
  220.   out << '\n';
  221.   return 0;
  222. }
  223.  
  224. long OcRegisterClass(TRegList& regInfo, HINSTANCE module, ostream& out,
  225.                      TLangId lang, char* filter, TRegItem* defaults,
  226.                      TRegItem* extra)
  227. {
  228.   long docFlags = 0;
  229.   const char* pc;
  230.   int i;
  231.   TRegItem* regItem;
  232.   const int bufSize  = 512;
  233.   const int pathSize = 512;
  234.   const int langSize = 10;
  235.   const int guidSize = 64;
  236.   struct _buf {
  237.     char* buf;
  238.     _buf() { buf = new char[ bufSize + pathSize + langSize + guidSize
  239.                            + OcRegTemplateCount * sizeof(char)
  240.                            + OcRegParamCount * sizeof(char*) ]; }
  241.    ~_buf() {delete[] buf;}
  242.     operator char*() {return buf;}
  243.   } buf;
  244.   char*  path = buf + bufSize;
  245.   char*  langBuf = path + pathSize;
  246.   char*  guidBuf = langBuf + langSize;
  247.   signed char* tplEnab = (signed char*)(guidBuf + guidSize);
  248.   const char** paramVal = (const char**)(tplEnab + OcRegTemplateCount);
  249.   ::GetModuleFileName(module, path, pathSize);
  250.  
  251.   // Check to see if the reg format buffer overflowed during startup
  252.   //
  253.   if (TRegItem::Heap.Used > TRegItem::Heap.Size) {
  254.     const char frmt[] = "REGISTRATION_FORMAT_BUFFER Overflow. Need %d bytes total.";
  255.     char msg[sizeof frmt + 11];
  256.     wsprintf(msg, frmt, TRegItem::Heap.Used);
  257.     throw TXRegistry(msg, 0);
  258.   }
  259.  
  260.   // Check for language defaulted to system configuration
  261.   //
  262.   if (lang == LangSysDefault)
  263.     lang = TLocaleString::SystemDefaultLangId;
  264.   else if (lang == LangUserDefault)
  265.     lang = TLocaleString::UserDefaultLangId;
  266.  
  267.   // initialize local arrays of paramater values and template enable flags
  268.   //
  269.   int userKeyCount = 0;
  270.   for (i = OcRegParamCount; --i >= 0; paramVal[i] = OcRegParams[i].Default)
  271.     ;
  272.   if (filter) {
  273.     memset(tplEnab, 0x80, OcRegTemplateCount);  // disable all templates
  274.     for (pc = filter; (i = *pc++) != 0; )
  275.       tplEnab[i-1] = 0;                         // selectively allow enable
  276.   }
  277.   else {
  278.     memset(tplEnab, 0, OcRegTemplateCount);     // initialize to unselected
  279.   }
  280.  
  281.   // assign path parameter initially to current module load path
  282.   //
  283.   i = TRegParam::Find("path");
  284.   paramVal[i] = path;
  285.  
  286.   // assign server context based on whether it is an EXE or a DLL
  287.   //
  288.   i = TRegParam::Find("serverctx");
  289. #if defined (BI_PTR_0_32)
  290.   if (::GetModuleHandle(0) == module)   // check instance handle for EXE
  291.     paramVal[i] = "Local";
  292.   else
  293.     paramVal[i] = "Inproc";
  294. #else
  295.   if (((unsigned)module | 1) == _SS) // check instance handle for 16-bit EXE
  296.     paramVal[i] = "Local";
  297.   else
  298.     paramVal[i] = "Inproc";
  299. #endif
  300.  
  301.   // assign language parameter to value passed in function argument
  302.   //
  303.   i = TRegParam::Find("language");
  304.   wsprintf(langBuf, "%X", lang);
  305.   paramVal[i] = langBuf;
  306.  
  307.   // scan through defaults list(0), user list of parameters and custom keys(1),
  308.   // and extra list(2)
  309.   //
  310.   int step = 0;
  311.   for (regItem = defaults; ; regItem++) {
  312.  
  313.     while (step <= 2 && (!regItem || (pc = regItem->Key) == 0)) {
  314.       switch (step++) {
  315.         case 0:
  316.           regItem = regInfo.Items;
  317.           break;
  318.         case 1:
  319.           regItem = extra;
  320.           break;
  321.         case 2:
  322.           regItem = 0;
  323.       }
  324.     }
  325.     if (!regItem || !pc)
  326.       break;
  327.  
  328.     // note presence of user-specified key and value, process afterwards
  329.     //
  330.     if (*pc == ' ') {
  331.       userKeyCount++;
  332.     }
  333.     else {
  334.       // replace default with user-specified parameter value
  335.       //
  336.       TXRegistry::Check((i = TRegParam::Find(pc)) < 0, pc);
  337.       paramVal[i] = regItem->Value.Translate(lang);
  338.  
  339.       // enable all templates invoked by parameter
  340.       //      
  341.       for (char* pEnab = OcRegParams[i].TplList; (i = *pEnab++) != 0; )
  342.         tplEnab[i-1]++;
  343.     }
  344.   }
  345.  
  346.   // decode document template flags
  347.   //
  348.   if ((i = TRegParam::Find("docflags")) >= 0)
  349.     docFlags = atol(paramVal[i]);
  350.  
  351.   // process enabled templates, substituting parameter values
  352.   //
  353.   regItem = regInfo.Items;
  354.   for (int itpl = 0; itpl < OcRegTemplateCount || userKeyCount--; itpl++) {
  355.     char* val = 0;
  356.     char* pb = buf;
  357.     const char* pt;
  358.     char c;
  359.     const char* userval = 0;
  360.     if (itpl < OcRegTemplateCount) {  // processing standard template array
  361.       if (tplEnab[itpl] <= 0)
  362.         continue;
  363.       pt = OcRegTemplates[itpl];
  364.     }
  365.     else {                       // now processing user-defined templates
  366.       while (*(pt = regItem->Key) != ' ')
  367.         regItem++;
  368.       pt++;
  369.       userval = regItem->Value;
  370.     }
  371.     do switch (c = *pt++) {
  372.       case 0:
  373.         *pb++ = 0;
  374.         if (!userval)
  375.           break;
  376.         pt = userval;
  377.         userval = 0;
  378.         val = pb;
  379.         c++;
  380.         continue;
  381.       case '<':
  382.         pc = pb;
  383.         continue;
  384.       case '>':
  385.         *pb = 0;
  386.         pb = (char*)pc;
  387.         TXRegistry::Check((i = TRegParam::Find(pc)) < 0, pc); // internal err
  388.         TXRegistry::Check((pc = paramVal[i]) == 0, OcRegParams[i].Param);
  389.         if (*pc == 0 && *pt == ' ')
  390.           pt++;
  391.         while (*pc != 0)
  392.           *pb++ = *pc++;
  393.         continue;
  394.       case '=':
  395.         while (*(pb-1) == ' ')
  396.           pb--;
  397.         *pb++ = 0;
  398.         val = pb;
  399.         while (*pt == ' ')
  400.           pt++;
  401.         continue;
  402.       default:
  403.         *pb++ = c;
  404.     } while (c);
  405.     OcRegWrite(buf, val, out);
  406.   }
  407.   return docFlags;
  408. }
  409.  
  410. void OcRegistryUpdate(istream& in)
  411. {
  412.   struct TempKey {
  413.     HKEY key;
  414.     TempKey() {::RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", &key);}
  415.    ~TempKey() {::RegCloseKey(key);}
  416.   } tempKey;
  417.   while (!in.eof()) {
  418.     char buf[512];
  419.     char* pc;
  420.     char* val;
  421.     in.getline(buf, sizeof(OcRegEntryHeader));
  422.     if (strcmp(buf,        OcRegEntryHeader) != 0)
  423.       continue;
  424.     in.getline(buf, sizeof(buf));
  425.     if ((val = pc = strchr(buf, '=')) != 0) {
  426.       while (*(pc-1) == ' ')
  427.         pc--;
  428.       *pc = 0;
  429.       while (*(++val) == ' ')
  430.         ;
  431.     }
  432.     else
  433.       val = "";
  434.     TXRegistry::Check(::RegSetValue(HKEY_CLASSES_ROOT,buf, REG_SZ,val,0),buf);
  435.   }
  436. }
  437.  
  438. //____________________________________________________________________________
  439. //
  440. // Unregister application or class from registration database
  441. //____________________________________________________________________________
  442.  
  443. char* OcUnregParams[] = {
  444.   "extension",    // special case: extension key needs '.' prepended
  445.   "debugclsid",
  446.   "debugprogid",
  447.   "clsid",
  448.   "progid",
  449.   "permid",
  450. };
  451. const int OcUnregParamCount = sizeof(OcUnregParams)/sizeof(char*);
  452.  
  453. int OcUnregisterClass(TRegList& regInfo, TRegItem* extra)
  454. {
  455.   struct TempKey {
  456.     HKEY Key;
  457.     TempKey() {::RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", &Key);}
  458.    ~TempKey() {::RegCloseKey(Key);}
  459.   } tempKey;
  460.   int  errorCount = 0;
  461.  
  462.   // Loop to remove each root level key, thus cleaning up all nested keys too
  463.   //
  464.   for (int i = 0; i < OcUnregParamCount; i++) {
  465.     const char* regKey = regInfo[OcUnregParams[i]];
  466.     if (!regKey && extra && strcmp(extra->Key, OcUnregParams[i]) == 0)
  467.       regKey = extra->Value;
  468.     if (regKey) {
  469.       char buff[16];
  470.       if (i == 0) {       // special case prepending of '.' to extension
  471.         buff[0] = '.';
  472.         strcpy(buff+1, regKey);
  473.         regKey = buff;
  474.       }
  475.       if (::RegDeleteKey(*regKey=='{' ? tempKey.Key : HKEY_CLASSES_ROOT, regKey)
  476.           != ERROR_SUCCESS)   // }matching brace for brace counting editors
  477.         errorCount++;         // should throw exception if certain errors?
  478.     }
  479.   }
  480.   return errorCount;
  481. }
  482.  
  483. int OcRegistryValidate(istream& in)
  484. {
  485.   struct TempKey {
  486.     HKEY key;
  487.     TempKey() {::RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", &key);}
  488.    ~TempKey() {::RegCloseKey(key);}
  489.   } tempKey;
  490.   int diffCount = 0;
  491.   while (!in.eof()) {
  492.     char entry[512];
  493.     char buf[300];
  494.     long bufSize = sizeof(buf);
  495.     char* pc;
  496.     char* val;
  497.     in.getline(entry, sizeof(OcRegEntryHeader));
  498.     if (strcmp(entry,        OcRegEntryHeader) != 0)
  499.       continue;
  500.     in.getline(entry, sizeof(entry));
  501.     if ((val = pc = strchr(entry, '=')) != 0) {
  502.       while (*(pc-1) == ' ')
  503.         pc--;
  504.       *pc = 0;
  505.       while (*(++val) == ' ')
  506.         ;
  507.     }
  508.     if (::RegQueryValue(HKEY_CLASSES_ROOT,entry,buf,&bufSize) != ERROR_SUCCESS
  509.         || (val && strcmp(val, buf) != 0))
  510.       diffCount++;
  511.   }
  512.   return diffCount;
  513. }
  514.  
  515. //____________________________________________________________________________
  516. //
  517. // Separate debugging registration for application and documents
  518. // Overrides non-debug values with values from debug keys
  519. //____________________________________________________________________________
  520.  
  521. struct DebugRegKey { enum {  progid,        clsid,  description,   extraopt};};
  522. char* OcReplaceKeys[] =  {  "progid",      "clsid","description", "extraopt"};
  523. char* OcDebugKeys[] = {"debugprogid", "debugclsid","debugdesc",   "debugopt"};
  524. const int DebugReplaceCount = sizeof(OcReplaceKeys)/sizeof(char*);
  525.  
  526. TRegItem OcRegNoDebug[] = { {"debugger", {""}}, {0,{0}} };
  527. TRegItem OcRegNotDll[]  = { {"cmdline", {""}}, {"debugger", {""}}, {0,{0}} };
  528. char AppDebugFilter[] = "\001\002\003\005\006\007";
  529. char DocDebugFilter[] = "\001\002\003\005\006\007"
  530.                         "\020\021\022\023\024\025\026\027"
  531.                         "\030\031\032\033\034\035\036\037"
  532.                         "\040\041\042\043\044\045\046\047"
  533.                         "\054\055\062\063";
  534.  
  535. int OcSetupDebugReg(TRegList& regInfo, TRegItem* regDebug, TLangId lang,
  536.                     char* clsid)
  537. {
  538.   int stat = -1;  // initialize for user-supplied clsid
  539.   char** oldKey = OcReplaceKeys;
  540.   char** newKey = OcDebugKeys;
  541.   for (int i = 0; i < DebugReplaceCount; i++,oldKey++,newKey++,regDebug++) {
  542.     const char* value = regInfo.Lookup(*newKey, lang);
  543.     if (!value) {
  544.       switch(i) {
  545.         case DebugRegKey::progid:
  546.           return 0;                   // no debug registration
  547.         case DebugRegKey::extraopt:
  548.           value = " /Debug";
  549.           break;
  550.         case DebugRegKey::clsid:
  551.           if (clsid) {
  552.             value = clsid;
  553.             stat = 1;    // flag use of supplied clsid
  554.             break;
  555.           } // else fall through to throw exception
  556.         case DebugRegKey::description:
  557.           TXRegistry::Check(1, *newKey); // incomplete debug registration
  558.       }
  559.     }
  560.     regDebug->Key  = *oldKey;
  561.     regDebug->Value = value;
  562.   }
  563.   regDebug->Key = 0;    // null-terminate reg list
  564.   return stat;
  565. }
  566.  
  567. //____________________________________________________________________________
  568. //
  569. // TRegistrar - Application registration manager interface class
  570. //____________________________________________________________________________
  571.  
  572. TRegistrar* TRegistrar::RegistrarList = 0;
  573.  
  574. TRegistrar::TRegistrar(TRegList& regInfo, TComponentFactory callback,
  575.                        string& cmdLine, HINSTANCE hInst)
  576. :
  577.   AppDesc(*new TAppDescriptor(regInfo, callback, cmdLine, hInst))
  578. {
  579.   Next = RegistrarList;
  580.   RegistrarList = this;
  581.   TRACEX(OcRefCount, 1, "TRegistrar() @" << (void*)this);
  582. }
  583.  
  584. TRegistrar::TRegistrar(TAppDescriptor& appDesc) : AppDesc(appDesc)
  585. {
  586.   Next = RegistrarList;
  587.   RegistrarList = this;
  588. }
  589.  
  590. TRegistrar::~TRegistrar()
  591. {
  592.   // since TRegistrars are destroyed when the module is shutdown
  593.   // we do not need to detach each registrar from the linked list
  594.   delete &AppDesc;
  595. }
  596.  
  597. TRegistrar* TRegistrar::GetNext(TRegistrar* reg)
  598. {
  599.   return reg ? reg->Next : RegistrarList;
  600. }
  601.  
  602. void far* TRegistrar::GetFactory(const GUID& clsid, const GUID far& iid)
  603. {
  604.   void far* retObj = 0;
  605.   if (clsid != AppDesc.AppClassId)
  606.     return 0;
  607.   ((IUnknown&)AppDesc).QueryInterface(iid, &retObj);
  608.   return retObj;   // QueryInterface sets to null if fails
  609. }
  610.  
  611. bool TRegistrar::CanUnload()
  612. {
  613.   return static_cast<bool>(!AppDesc.IsBound());
  614. }
  615.  
  616. int TRegistrar::Run()
  617. {
  618.   if (!IsOptionSet(amExeModule))
  619.     return 0;    // inproc server waits until class factory created and called
  620.   TComponentFactory factory = AppDesc.GetFactory();
  621.   if (!factory)
  622.     return 1;
  623.   if (AppDesc.IsAutomated() && IsOptionSet(amAutomation))
  624.     RegisterAppClass();
  625.   IUnknown* ifc = factory(0, GetOptions() | amRun);  // create app and run it
  626.  
  627.   // app is now running its message loop, factory may get called again by OLE
  628.   //
  629.   ifc = factory(ifc, GetOptions() | amShutdown);  // EXE finished, destroy it
  630.   if (ifc && !(GetOptions() & amServedApp))
  631.     ifc->Release();  // we own the reference count, else container released it
  632.   return 0;
  633. }
  634.  
  635. void TRegistrar::Shutdown(IUnknown* releasedObj, uint32 options)
  636. {
  637.   if (!AppDesc.GetFactory())
  638.     return;
  639.   releasedObj = AppDesc.GetFactory()(releasedObj, options|amShutdown);
  640.   if (releasedObj)
  641.     releasedObj->Release();
  642. }
  643.  
  644. //____________________________________________________________________________
  645. //
  646. // DLL server entry points
  647. //____________________________________________________________________________
  648.  
  649. //
  650. // Entry point for complete registration management via command line
  651. //
  652. STDAPI __export DllRegisterCommand(const char far* cmdLine)
  653. {
  654.   try {
  655.     bool isDebug = false;
  656.     TRegistrar* registrar = 0;
  657.  
  658.     // Need to set up typelibrary state information in case multiple components
  659.     //
  660.     while ((registrar = TRegistrar::GetNext(registrar)) != 0) {
  661.       string cmd(cmdLine);
  662.       registrar->ProcessCmdLine(cmd);
  663.       if (registrar->IsOptionSet(amDebug))
  664.         isDebug = true;
  665.     }
  666.     if (isDebug)
  667.       __emit__(0xCC); // force debugg trap if REGISTER.EXE loaded with debugger
  668.     return HR_OK;
  669.   }
  670.   catch (...) {
  671.     return HR_FAIL;
  672.   }
  673. }
  674.  
  675. //
  676. // OLE 2.0 entry point for obtaining a class factory for a particular CLSID
  677. //
  678. STDAPI __export DllGetClassObject(const GUID far& clsid, const GUID far& iid,
  679.                                   void far* far* retObj)
  680. {
  681.   try {
  682.     TRegistrar* registrar = 0;
  683.     while ((registrar = TRegistrar::GetNext(registrar)) != 0) {
  684.       *retObj = registrar->GetFactory(clsid, iid);
  685.       if (*retObj)
  686.         return HR_OK;
  687.     }
  688.     return HR_FAIL;
  689.   }
  690.   catch (...) {
  691.     return HR_FAIL;
  692.   }
  693. }
  694.  
  695. //
  696. // OLE 2.0 entry point for checking if DLL has no clients and can be unloaded
  697. //
  698. STDAPI __export DllCanUnloadNow(void)
  699. {  
  700.   TRegistrar* registrar = 0;
  701.   while ((registrar = TRegistrar::GetNext(registrar)) != 0) {
  702.     if (!registrar->CanUnload()) {
  703.       TRACEX(OcDll, 1, "DllCanUnloadNow returning " << hex << uint32(HR_FALSE));
  704.       return HR_FALSE;
  705.     }
  706.   }
  707.   TRACEX(OcDll, 1, "DllCanUnloadNow returning " << hex << uint32(HR_OK));
  708.   return HR_OK;
  709. }     
  710.  
  711. //
  712. // OLE 2.0 entry point for registering DLL, no locale info passed
  713. //
  714. STDAPI __export DllRegisterServer()
  715. {
  716.   return DllRegisterCommand("/RegServer");
  717. }
  718.  
  719. //
  720. // OLE 2.0 entry point for unregistering DLL
  721. //
  722. STDAPI __export DllUnregisterServer()
  723. {
  724.   return DllRegisterCommand("/UnregServer");
  725. }
  726.  
  727.