home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / ctlreg.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  15KB  |  569 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFXCTL_FACT_SEG
  14. #pragma code_seg(AFXCTL_FACT_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. #define new DEBUG_NEW
  23.  
  24. #define GUID_CCH    39  // Characters in string form of guid, including '\0'
  25.  
  26. inline BOOL _AfxRegDeleteKeySucceeded(LONG error)
  27. {
  28.     return (error == ERROR_SUCCESS) || (error == ERROR_BADKEY) ||
  29.         (error == ERROR_FILE_NOT_FOUND);
  30. }
  31.  
  32. // Under Win32, a reg key may not be deleted unless it is empty.
  33. // Thus, to delete a tree,  one must recursively enumerate and
  34. // delete all of the sub-keys.
  35.  
  36. LONG AFXAPI _AfxRecursiveRegDeleteKey(HKEY hParentKey, LPTSTR szKeyName)
  37. {
  38.     // one implementation for everybody
  39.     return AfxDelRegTreeHelper(hParentKey, szKeyName);
  40. }
  41.  
  42. void _AfxUnregisterInterfaces(ITypeLib* pTypeLib)
  43. {
  44.     TCHAR szKey[128];
  45.     lstrcpy(szKey, _T("Interface\\"));
  46.     LPTSTR pszGuid = szKey + lstrlen(szKey);
  47.  
  48.     int cTypeInfo = pTypeLib->GetTypeInfoCount();
  49.  
  50.     for (int i = 0; i < cTypeInfo; i++)
  51.     {
  52.         TYPEKIND tk;
  53.         if (SUCCEEDED(pTypeLib->GetTypeInfoType(i, &tk)) &&
  54.             (tk == TKIND_DISPATCH || tk == TKIND_INTERFACE))
  55.         {
  56.             ITypeInfo* pTypeInfo = NULL;
  57.             if (SUCCEEDED(pTypeLib->GetTypeInfo(i, &pTypeInfo)))
  58.             {
  59.                 TYPEATTR* pTypeAttr;
  60.                 if (SUCCEEDED(pTypeInfo->GetTypeAttr(&pTypeAttr)))
  61.                 {
  62. #if defined(_UNICODE) || defined(OLE2ANSI)
  63.                     StringFromGUID2(pTypeAttr->guid, pszGuid, GUID_CCH);
  64. #else
  65.                     WCHAR wszGuid[39];
  66.                     StringFromGUID2(pTypeAttr->guid, wszGuid, GUID_CCH);
  67.                     _wcstombsz(pszGuid, wszGuid, GUID_CCH);
  68. #endif
  69.                     _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  70.                     pTypeInfo->ReleaseTypeAttr(pTypeAttr);
  71.                 }
  72.  
  73.                 pTypeInfo->Release();
  74.             }
  75.         }
  76.     }
  77. }
  78.  
  79. BOOL AFXAPI AfxOleRegisterTypeLib(HINSTANCE hInstance, REFGUID tlid,
  80.     LPCTSTR pszFileName, LPCTSTR pszHelpDir)
  81. {
  82.     USES_CONVERSION;
  83.  
  84.     BOOL bSuccess = FALSE;
  85.     CString strPathName;
  86.     TCHAR *szPathName = strPathName.GetBuffer(_MAX_PATH);
  87.     ::GetModuleFileName(hInstance, szPathName, _MAX_PATH);
  88.     strPathName.ReleaseBuffer();
  89.     LPTYPELIB ptlib = NULL;
  90.  
  91.     // If a filename was specified, replace final component of path with it.
  92.     if (pszFileName != NULL)
  93.     {
  94.         int iBackslash = strPathName.ReverseFind('\\');
  95.         if (iBackslash != -1)
  96.             strPathName = strPathName.Left(iBackslash+1);
  97.         strPathName += pszFileName;
  98.     }
  99.  
  100.     if (SUCCEEDED(LoadTypeLib(T2COLE(strPathName), &ptlib)))
  101.     {
  102.         ASSERT_POINTER(ptlib, ITypeLib);
  103.  
  104.         LPTLIBATTR pAttr;
  105.         GUID tlidActual = GUID_NULL;
  106.  
  107.         if (SUCCEEDED(ptlib->GetLibAttr(&pAttr)))
  108.         {
  109.             ASSERT_POINTER(pAttr, TLIBATTR);
  110.             tlidActual = pAttr->guid;
  111.             ptlib->ReleaseTLibAttr(pAttr);
  112.         }
  113.  
  114.         // Check that the guid of the loaded type library matches
  115.         // the tlid parameter.
  116.         ASSERT(IsEqualGUID(tlid, tlidActual));
  117.  
  118.         if (IsEqualGUID(tlid, tlidActual))
  119.         {
  120.             // Register the type library.
  121.             if (SUCCEEDED(RegisterTypeLib(ptlib,
  122.                     T2OLE((LPTSTR)(LPCTSTR)strPathName), T2OLE((LPTSTR)pszHelpDir))))
  123.                 bSuccess = TRUE;
  124.         }
  125.  
  126.         RELEASE(ptlib);
  127.     }
  128.     else
  129.     {
  130.         TRACE1("Warning: Could not load type library from %s\n", (LPCTSTR)strPathName);
  131.     }
  132.  
  133.     return bSuccess;
  134. }
  135.  
  136. #define TYPELIBWIN   _T("win32")
  137. #define TYPELIBWIN_2 _T("win16")
  138.  
  139. BOOL AFXAPI AfxOleUnregisterTypeLib(REFGUID tlid, WORD wVerMajor,
  140.     WORD wVerMinor, LCID lcid)
  141. {
  142.     USES_CONVERSION;
  143.  
  144.     // Load type library before unregistering it.
  145.     ITypeLib* pTypeLib = NULL;
  146.     if (wVerMajor != 0)
  147.     {
  148.         if (FAILED(LoadRegTypeLib(tlid, wVerMajor, wVerMinor, lcid, &pTypeLib)))
  149.             pTypeLib = NULL;
  150.     }
  151.  
  152.     // Format typelib guid as a string
  153.     OLECHAR szTypeLibID[GUID_CCH];
  154.     int cchGuid = ::StringFromGUID2(tlid, szTypeLibID, GUID_CCH);
  155.  
  156.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  157.     if (cchGuid != GUID_CCH)
  158.         return FALSE;
  159.  
  160.     TCHAR szKeyTypeLib[_MAX_PATH];
  161.     BOOL bSurgical = FALSE;
  162.     LONG error = ERROR_SUCCESS;
  163.  
  164.     wsprintf(szKeyTypeLib, _T("TYPELIB\\%s"), OLE2CT(szTypeLibID));
  165.  
  166.     HKEY hKeyTypeLib;
  167.     if (RegOpenKey(HKEY_CLASSES_ROOT, szKeyTypeLib, &hKeyTypeLib) ==
  168.         ERROR_SUCCESS)
  169.     {
  170.         int iKeyVersion = 0;
  171.         HKEY hKeyVersion;
  172.         TCHAR szVersion[_MAX_PATH];
  173.  
  174.         // Iterate through all installed versions of the control
  175.  
  176.         while (RegEnumKey(hKeyTypeLib, iKeyVersion, szVersion, _MAX_PATH) ==
  177.             ERROR_SUCCESS)
  178.         {
  179.             hKeyVersion = NULL;
  180.             BOOL bSurgicalVersion = FALSE;
  181.  
  182.             if (RegOpenKey(hKeyTypeLib, szVersion, &hKeyVersion) !=
  183.                 ERROR_SUCCESS)
  184.             {
  185.                 ++iKeyVersion;
  186.                 continue;
  187.             }
  188.  
  189.             int iKeyLocale = 0;
  190.             HKEY hKeyLocale;
  191.             TCHAR szLocale[_MAX_PATH];
  192.  
  193.             // Iterate through all registered locales for this version
  194.  
  195.             while (RegEnumKey(hKeyVersion, iKeyLocale, szLocale, _MAX_PATH) ==
  196.                 ERROR_SUCCESS)
  197.             {
  198.                 // Don't remove HELPDIR or FLAGS keys.
  199.                 if ((lstrcmpi(szLocale, _T("HELPDIR")) == 0) ||
  200.                     (lstrcmpi(szLocale, _T("FLAGS")) == 0))
  201.                 {
  202.                     ++iKeyLocale;
  203.                     continue;
  204.                 }
  205.  
  206.                 hKeyLocale = NULL;
  207.  
  208.                 if (RegOpenKey(hKeyVersion, szLocale, &hKeyLocale) !=
  209.                     ERROR_SUCCESS)
  210.                 {
  211.                     ++iKeyLocale;
  212.                     continue;
  213.                 }
  214.  
  215.                 // Check if a 16-bit key is found when unregistering 32-bit
  216.                 HKEY hkey;
  217.                 if (RegOpenKey(hKeyLocale, TYPELIBWIN_2, &hkey) ==
  218.                     ERROR_SUCCESS)
  219.                 {
  220.                     RegCloseKey(hkey);
  221.  
  222.                     // Only remove the keys specific to the 32-bit version
  223.                     // of control, leaving things intact for 16-bit version.
  224.                     error = _AfxRecursiveRegDeleteKey(hKeyLocale, TYPELIBWIN);
  225.                     bSurgicalVersion = TRUE;
  226.                     RegCloseKey(hKeyLocale);
  227.                 }
  228.                 else
  229.                 {
  230.                     // Delete everything for this locale.
  231.                     RegCloseKey(hKeyLocale);
  232.                     if (_AfxRecursiveRegDeleteKey(hKeyVersion, szLocale) ==
  233.                         ERROR_SUCCESS)
  234.                     {
  235.                         // Start over again, so we don't skip anything.
  236.                         iKeyLocale = 0;
  237.                         continue;
  238.                     }
  239.                 }
  240.                 ++iKeyLocale;
  241.             }
  242.             RegCloseKey(hKeyVersion);
  243.  
  244.             if (bSurgicalVersion)
  245.             {
  246.                 bSurgical = TRUE;
  247.             }
  248.             else
  249.             {
  250.                 if (_AfxRecursiveRegDeleteKey(hKeyTypeLib, szVersion) ==
  251.                     ERROR_SUCCESS)
  252.                 {
  253.                     // Start over again, to make sure we don't skip anything.
  254.                     iKeyVersion = 0;
  255.                     continue;
  256.                 }
  257.             }
  258.  
  259.             ++iKeyVersion;
  260.         }
  261.         RegCloseKey(hKeyTypeLib);
  262.     }
  263.  
  264.     if (!bSurgical)
  265.         error = _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT, szKeyTypeLib);
  266.  
  267.     if (_AfxRegDeleteKeySucceeded(error))
  268.     {
  269.         // If type library was unregistered successfully, then also unregister
  270.         // interfaces.
  271.         if (pTypeLib != NULL)
  272.         {
  273.             ITypeLib* pDummy = NULL;
  274.             if (FAILED(LoadRegTypeLib(tlid, wVerMajor, wVerMinor, lcid, &pDummy)))
  275.                 _AfxUnregisterInterfaces(pTypeLib);
  276.             else
  277.                 pDummy->Release();
  278.  
  279.             pTypeLib->Release();
  280.         }
  281.     }
  282.  
  283.     return _AfxRegDeleteKeySucceeded(error);
  284. }
  285.  
  286. AFX_STATIC_DATA const LPCTSTR _afxCtrlProgID[] =
  287. {
  288.     _T("\0") _T("%1"),
  289.     _T("CLSID\0") _T("%2"),
  290.     NULL
  291. };
  292.  
  293. #define INPROCSERVER   _T("InprocServer32")
  294. #define INPROCSERVER_2 _T("InprocServer")
  295. #define TOOLBOXBITMAP  _T("ToolboxBitmap32")
  296.  
  297. AFX_STATIC_DATA const LPCTSTR _afxCtrlClassID[] =
  298. {
  299.     _T("\0") _T("%1"),
  300.     _T("ProgID\0") _T("%2"),
  301.     INPROCSERVER _T("\0%3"),
  302.     TOOLBOXBITMAP _T("\0%3, %4"),
  303.     _T("MiscStatus\0") _T("0"),
  304.     _T("MiscStatus\\1\0") _T("%5"),
  305.     _T("Control\0") _T(""),
  306.     _T("TypeLib\0") _T("%6"),
  307.     _T("Version\0") _T("%7"),
  308.     NULL
  309. };
  310.  
  311. BOOL AFXAPI AfxOleRegisterControlClass(HINSTANCE hInstance,
  312.     REFCLSID clsid, LPCTSTR pszProgID, UINT idTypeName, UINT idBitmap,
  313.     int nRegFlags, DWORD dwMiscStatus, REFGUID tlid, WORD wVerMajor,
  314.     WORD wVerMinor)
  315. {
  316.     USES_CONVERSION;
  317.  
  318.     BOOL bSuccess = FALSE;
  319.  
  320.     // Format class ID as a string
  321.     OLECHAR szClassID[GUID_CCH];
  322.     int cchGuid = ::StringFromGUID2(clsid, szClassID, GUID_CCH);
  323.     LPCTSTR lpszClassID = OLE2CT(szClassID);
  324.  
  325.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  326.     if (cchGuid != GUID_CCH)
  327.         return FALSE;
  328.  
  329.     // Format typelib guid as a string
  330.     OLECHAR szTypeLibID[GUID_CCH];
  331.     cchGuid = ::StringFromGUID2(tlid, szTypeLibID, GUID_CCH);
  332.  
  333.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  334.     if (cchGuid != GUID_CCH)
  335.         return FALSE;
  336.  
  337.     CString strPathName;
  338.     AfxGetModuleShortFileName(hInstance, strPathName);
  339.  
  340.     CString strTypeName;
  341.     if (!strTypeName.LoadString(idTypeName))
  342.     {
  343.         ASSERT(FALSE);  // Name string not present in resources
  344.         strTypeName = lpszClassID; // Use Class ID instead
  345.     }
  346.  
  347.     TCHAR szBitmapID[_MAX_PATH];
  348.     _itot(idBitmap, szBitmapID, 10);
  349.  
  350.     TCHAR szMiscStatus[_MAX_PATH];
  351.     _ltot(dwMiscStatus, szMiscStatus, 10);
  352.  
  353.     // Format version string as "major.minor"
  354.     TCHAR szVersion[_MAX_PATH];
  355.     wsprintf(szVersion, _T("%d.%d"), wVerMajor, wVerMinor);
  356.  
  357.     // Attempt to open registry keys.
  358.     HKEY hkeyClassID = NULL;
  359.     HKEY hkeyProgID = NULL;
  360.  
  361.     TCHAR szScratch[_MAX_PATH];
  362.     wsprintf(szScratch, _T("CLSID\\%s"), lpszClassID);
  363.     if (::RegCreateKey(HKEY_CLASSES_ROOT, szScratch, &hkeyClassID) !=
  364.         ERROR_SUCCESS)
  365.         goto Error;
  366.     if (::RegCreateKey(HKEY_CLASSES_ROOT, pszProgID, &hkeyProgID) !=
  367.         ERROR_SUCCESS)
  368.         goto Error;
  369.  
  370.     ASSERT(hkeyClassID != NULL);
  371.     ASSERT(hkeyProgID != NULL);
  372.  
  373.     LPCTSTR rglpszSymbols[7];
  374.     rglpszSymbols[0] = strTypeName;
  375.     rglpszSymbols[1] = lpszClassID;
  376.     bSuccess = AfxOleRegisterHelper(_afxCtrlProgID, rglpszSymbols, 2,
  377.         TRUE, hkeyProgID);
  378.  
  379.     if (!bSuccess)
  380.         goto Error;
  381.  
  382.     rglpszSymbols[1] = pszProgID;
  383.     rglpszSymbols[2] = strPathName;
  384.     rglpszSymbols[3] = szBitmapID;
  385.     rglpszSymbols[4] = szMiscStatus;
  386.     rglpszSymbols[5] = OLE2CT(szTypeLibID);
  387.     rglpszSymbols[6] = szVersion;
  388.     bSuccess = AfxOleRegisterHelper(_afxCtrlClassID, rglpszSymbols, 7,
  389.         TRUE, hkeyClassID);
  390.  
  391.     if (!bSuccess)
  392.         goto Error;
  393.  
  394.     if (nRegFlags & afxRegInsertable)
  395.     {
  396.         bSuccess =
  397.             (::RegSetValue(hkeyProgID, _T("Insertable"), REG_SZ, _T(""), 0) ==
  398.                 ERROR_SUCCESS) &&
  399.             (::RegSetValue(hkeyClassID, _T("Insertable"), REG_SZ, _T(""), 0) ==
  400.                 ERROR_SUCCESS);
  401.     }
  402.  
  403.     if (nRegFlags & afxRegApartmentThreading)
  404.     {
  405.         HKEY hkeyInprocServer32;
  406.         bSuccess = (::RegOpenKey(hkeyClassID, INPROCSERVER,
  407.             &hkeyInprocServer32) == ERROR_SUCCESS);
  408.         if (!bSuccess)
  409.             goto Error;
  410.         ASSERT(hkeyInprocServer32 != NULL);
  411.         static TCHAR szApartment[] = _T("Apartment");
  412.         bSuccess = (::RegSetValueEx(hkeyInprocServer32, _T("ThreadingModel"), 0,
  413.             REG_SZ, (const BYTE*)szApartment, (lstrlen(szApartment)+1) * sizeof(TCHAR)) ==
  414.             ERROR_SUCCESS);
  415.         ::RegCloseKey(hkeyInprocServer32);
  416.     }
  417.  
  418. Error:
  419.     if (hkeyProgID != NULL)
  420.         ::RegCloseKey(hkeyProgID);
  421.  
  422.     if (hkeyClassID != NULL)
  423.         ::RegCloseKey(hkeyClassID);
  424.  
  425.     return bSuccess;
  426. }
  427.  
  428. BOOL AFXAPI AfxOleUnregisterClass(REFCLSID clsid, LPCTSTR pszProgID)
  429. {
  430.     USES_CONVERSION;
  431.  
  432.     // Format class ID as a string
  433.     OLECHAR szClassID[GUID_CCH];
  434.     int cchGuid = ::StringFromGUID2(clsid, szClassID, GUID_CCH);
  435.     LPCTSTR lpszClassID = OLE2CT(szClassID);
  436.  
  437.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  438.     if (cchGuid != GUID_CCH)
  439.         return FALSE;
  440.  
  441.     TCHAR szKey[_MAX_PATH];
  442.     long error;
  443.     BOOL bRetCode = TRUE;
  444.  
  445.     // check to see if a 16-bit InprocServer key is found when unregistering
  446.     // 32-bit (or vice versa).
  447.     wsprintf(szKey, _T("CLSID\\%s\\%s"), lpszClassID, INPROCSERVER_2);
  448.     HKEY hkey;
  449.     BOOL bSurgical = RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hkey) ==
  450.         ERROR_SUCCESS;
  451.  
  452.     if (bSurgical)
  453.     {
  454.         // Only remove the keys specific to this version of the control,
  455.         // leaving things in tact for the other version.
  456.         wsprintf(szKey, _T("CLSID\\%s\\%s"), lpszClassID, INPROCSERVER);
  457.         error = RegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  458.         bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  459.  
  460.         wsprintf(szKey, _T("CLSID\\%s\\%s"), lpszClassID, TOOLBOXBITMAP);
  461.         error = RegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  462.         bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  463.     }
  464.     else
  465.     {
  466.         // No other versions of this control were detected,
  467.         // so go ahead and remove the control completely.
  468.         wsprintf(szKey, _T("CLSID\\%s"), lpszClassID);
  469.         error = _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  470.         bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  471.  
  472.         if (pszProgID != NULL)
  473.         {
  474.             error = _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT,
  475.                 (LPTSTR)pszProgID);
  476.             bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  477.         }
  478.     }
  479.  
  480.     return bRetCode;
  481. }
  482.  
  483. AFX_STATIC_DATA const LPCTSTR _afxPropPageClass[] =
  484. {
  485.     _T("\0") _T("%1"),
  486.     INPROCSERVER _T("\0%2"),
  487.     NULL
  488. };
  489.  
  490. BOOL AFXAPI AfxOleRegisterPropertyPageClass(HINSTANCE hInstance,
  491.     REFCLSID clsid, UINT idTypeName)
  492. {
  493.     return AfxOleRegisterPropertyPageClass(hInstance, clsid, idTypeName, 0);
  494. }
  495.  
  496. BOOL AFXAPI AfxOleRegisterPropertyPageClass(HINSTANCE hInstance,
  497.     REFCLSID clsid, UINT idTypeName, int nRegFlags)
  498. {
  499.     ASSERT(!(nRegFlags & afxRegInsertable));    // can't be insertable
  500.  
  501.     USES_CONVERSION;
  502.  
  503.     BOOL bSuccess = FALSE;
  504.  
  505.     // Format class ID as a string
  506.     OLECHAR szClassID[GUID_CCH];
  507.     int cchGuid = ::StringFromGUID2(clsid, szClassID, GUID_CCH);
  508.     LPCTSTR lpszClassID = OLE2CT(szClassID);
  509.  
  510.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  511.     if (cchGuid != GUID_CCH)
  512.         return FALSE;
  513.  
  514.     CString strPathName;
  515.     AfxGetModuleShortFileName(hInstance, strPathName);
  516.  
  517.     CString strTypeName;
  518.     if (!strTypeName.LoadString(idTypeName))
  519.     {
  520.         ASSERT(FALSE);  // Name string not present in resources
  521.         strTypeName = lpszClassID; // Use Class ID instead
  522.     }
  523.  
  524.     HKEY hkeyClassID = NULL;
  525.  
  526.     TCHAR szKey[_MAX_PATH];
  527.     wsprintf(szKey, _T("CLSID\\%s"), lpszClassID);
  528.     if (::RegCreateKey(HKEY_CLASSES_ROOT, szKey, &hkeyClassID) !=
  529.         ERROR_SUCCESS)
  530.         goto Error;
  531.  
  532.     LPCTSTR rglpszSymbols[2];
  533.     rglpszSymbols[0] = strTypeName;
  534.     rglpszSymbols[1] = strPathName;
  535.     bSuccess = AfxOleRegisterHelper(_afxPropPageClass, rglpszSymbols,
  536.         2, TRUE, hkeyClassID);
  537.  
  538.     if (!bSuccess)
  539.         goto Error;
  540.  
  541.     if (nRegFlags & afxRegApartmentThreading)
  542.     {
  543.         HKEY hkeyInprocServer32;
  544.         bSuccess = (::RegOpenKey(hkeyClassID, INPROCSERVER,
  545.             &hkeyInprocServer32) == ERROR_SUCCESS);
  546.         if (!bSuccess)
  547.             goto Error;
  548.         ASSERT(hkeyInprocServer32 != NULL);
  549.         static TCHAR szApartment[] = _T("Apartment");
  550.         bSuccess = (::RegSetValueEx(hkeyInprocServer32, _T("ThreadingModel"), 0,
  551.             REG_SZ, (const BYTE*)szApartment, (lstrlen(szApartment)+1) * sizeof(TCHAR)) ==
  552.             ERROR_SUCCESS);
  553.         ::RegCloseKey(hkeyInprocServer32);
  554.     }
  555.  
  556. Error:
  557.     if (hkeyClassID != NULL)
  558.         ::RegCloseKey(hkeyClassID);
  559.  
  560.     return bSuccess;
  561. }
  562.  
  563. /////////////////////////////////////////////////////////////////////////////
  564. // Force any extra compiler-generated code into AFX_INIT_SEG
  565.  
  566. #ifdef AFX_INIT_SEG
  567. #pragma code_seg(AFX_INIT_SEG)
  568. #endif
  569.