home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / MS_VC.50 / VC / MFC / SRC / CTLREG.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-03  |  20.9 KB  |  805 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1997 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 _MAC
  14. #include <macname1.h>
  15. #include <macos\files.h>
  16. #include <macos\folders.h>
  17. #include <macname2.h>
  18. #include <plstring.h>
  19.  
  20. // from winlm.h.  Included here so we don't have to include codefrag.h
  21. extern "C" BOOL WINAPI GetMacInstanceInformationEx(HINSTANCE hInstance,
  22.     long* pcid, short* prn, char *szFragment, int cchFragment);
  23.  
  24. STDAPI EnsureTypeLibFolder(void);
  25. HRESULT TypeLibFspFromFullPath(const char *szPathName, FSSpec *pfspTlb);
  26. OSErr FullPathFromFSSpec(char *szFileName, FSSpec *pfsp);
  27. HRESULT _LoadTypeLibGetMacPath(const char *szPathName, char *szMacPath, ITypeLib **ppTypeLib);
  28. #endif //_MAC
  29.  
  30. #ifdef AFXCTL_FACT_SEG
  31. #pragma code_seg(AFXCTL_FACT_SEG)
  32. #endif
  33.  
  34. #ifdef _DEBUG
  35. #undef THIS_FILE
  36. static char THIS_FILE[] = __FILE__;
  37. #endif
  38.  
  39. #define new DEBUG_NEW
  40.  
  41. #define GUID_CCH    39  // Characters in string form of guid, including '\0'
  42.  
  43. #define ERROR_BADKEY_WIN16  2   // needed when running on Win32s
  44.  
  45. inline BOOL _AfxRegDeleteKeySucceeded(LONG error)
  46. {
  47.     return (error == ERROR_SUCCESS) || (error == ERROR_BADKEY) ||
  48.         (error == ERROR_FILE_NOT_FOUND);
  49. }
  50.  
  51. // Under Win32, a reg key may not be deleted unless it is empty.
  52. // Thus, to delete a tree,  one must recursively enumerate and
  53. // delete all of the sub-keys.
  54.  
  55. LONG AFXAPI _AfxRecursiveRegDeleteKey(HKEY hParentKey, LPTSTR szKeyName)
  56. {
  57.     DWORD   dwIndex = 0L;
  58.     TCHAR   szSubKeyName[256];
  59.     HKEY    hCurrentKey;
  60.     DWORD   dwResult;
  61.  
  62.     if ((dwResult = RegOpenKey(hParentKey, szKeyName, &hCurrentKey)) ==
  63.         ERROR_SUCCESS)
  64.     {
  65.         // Remove all subkeys of the key to delete
  66.         while ((dwResult = RegEnumKey(hCurrentKey, 0, szSubKeyName, 255)) ==
  67.             ERROR_SUCCESS)
  68.         {
  69.             if ((dwResult = _AfxRecursiveRegDeleteKey(hCurrentKey,
  70.                 szSubKeyName)) != ERROR_SUCCESS)
  71.                 break;
  72.         }
  73.  
  74.         // If all went well, we should now be able to delete the requested key
  75.         if ((dwResult == ERROR_NO_MORE_ITEMS) || (dwResult == ERROR_BADKEY) ||
  76.             (dwResult == ERROR_BADKEY_WIN16))
  77.         {
  78.             dwResult = RegDeleteKey(hParentKey, szKeyName);
  79.         }
  80.     }
  81.  
  82.     RegCloseKey(hCurrentKey);
  83.     return dwResult;
  84. }
  85.  
  86. void _AfxUnregisterInterfaces(ITypeLib* pTypeLib)
  87. {
  88.     TCHAR szKey[128];
  89.     _tcscpy(szKey, _T("Interface\\"));
  90.     LPTSTR pszGuid = szKey + _tcslen(szKey);
  91.  
  92.     int cTypeInfo = pTypeLib->GetTypeInfoCount();
  93.  
  94.     for (int i = 0; i < cTypeInfo; i++)
  95.     {
  96.         TYPEKIND tk;
  97.         if (SUCCEEDED(pTypeLib->GetTypeInfoType(i, &tk)) &&
  98.             (tk == TKIND_DISPATCH || tk == TKIND_INTERFACE))
  99.         {
  100.             ITypeInfo* pTypeInfo = NULL;
  101.             if (SUCCEEDED(pTypeLib->GetTypeInfo(i, &pTypeInfo)))
  102.             {
  103.                 TYPEATTR* pTypeAttr;
  104.                 if (SUCCEEDED(pTypeInfo->GetTypeAttr(&pTypeAttr)))
  105.                 {
  106. #if defined(_UNICODE) || defined(OLE2ANSI)
  107.                     StringFromGUID2(pTypeAttr->guid, pszGuid, GUID_CCH);
  108. #else
  109.                     WCHAR wszGuid[39];
  110.                     StringFromGUID2(pTypeAttr->guid, wszGuid, GUID_CCH);
  111.                     _wcstombsz(pszGuid, wszGuid, GUID_CCH);
  112. #endif
  113.                     _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  114.                     pTypeInfo->ReleaseTypeAttr(pTypeAttr);
  115.                 }
  116.  
  117.                 pTypeInfo->Release();
  118.             }
  119.         }
  120.     }
  121. }
  122.  
  123. BOOL AFXAPI AfxOleRegisterTypeLib(HINSTANCE hInstance, REFGUID tlid,
  124.     LPCTSTR pszFileName, LPCTSTR pszHelpDir)
  125. {
  126.     USES_CONVERSION;
  127.  
  128.     BOOL bSuccess = FALSE;
  129.     CString strPathName;
  130.     TCHAR *szPathName = strPathName.GetBuffer(_MAX_PATH);
  131.     ::GetModuleFileName(hInstance, szPathName, _MAX_PATH);
  132. #ifndef _MAC
  133.     strPathName.ReleaseBuffer();
  134. #endif
  135.  
  136.     LPTYPELIB ptlib = NULL;
  137.  
  138.     // If a filename was specified, replace final component of path with it.
  139.     if (pszFileName != NULL)
  140.     {
  141. #ifdef _MAC
  142.         FSSpec fsp;
  143.         UnwrapFile(szPathName, &fsp);
  144.         lstrcpy((char*)&fsp.name+1, pszFileName);
  145.         *fsp.name = (BYTE)strlen(pszFileName);
  146.         WrapFile(&fsp, szPathName, sizeof(szPathName));
  147.     }
  148.  
  149.     EnsureTypeLibFolder();
  150.     HRESULT hr = _LoadTypeLibGetMacPath(szPathName, szPathName, &ptlib);
  151.     strPathName.ReleaseBuffer();
  152.     if (SUCCEEDED(hr))
  153. #else
  154.         int iBackslash = strPathName.ReverseFind('\\');
  155.         if (iBackslash != -1)
  156.             strPathName = strPathName.Left(iBackslash+1);
  157.         strPathName += pszFileName;
  158.     }
  159.  
  160.     if (SUCCEEDED(LoadTypeLib(T2COLE(strPathName), &ptlib)))
  161. #endif
  162.     {
  163.         ASSERT_POINTER(ptlib, ITypeLib);
  164.  
  165.         LPTLIBATTR pAttr;
  166.         GUID tlidActual = GUID_NULL;
  167.  
  168.         if (SUCCEEDED(ptlib->GetLibAttr(&pAttr)))
  169.         {
  170.             ASSERT_POINTER(pAttr, TLIBATTR);
  171.             tlidActual = pAttr->guid;
  172.             ptlib->ReleaseTLibAttr(pAttr);
  173.         }
  174.  
  175.         // Check that the guid of the loaded type library matches
  176.         // the tlid parameter.
  177.         ASSERT(IsEqualGUID(tlid, tlidActual));
  178.  
  179.         if (IsEqualGUID(tlid, tlidActual))
  180.         {
  181.             // Register the type library.
  182.             if (SUCCEEDED(RegisterTypeLib(ptlib,
  183.                     T2OLE((LPTSTR)(LPCTSTR)strPathName), T2OLE((LPTSTR)pszHelpDir))))
  184.                 bSuccess = TRUE;
  185.         }
  186.  
  187.         RELEASE(ptlib);
  188.     }
  189.     else
  190.     {
  191.         TRACE1("Warning: Could not load type library from %s\n", (LPCTSTR)strPathName);
  192.     }
  193.  
  194.  
  195.     return bSuccess;
  196. }
  197.  
  198. #define TYPELIBWIN   _T("win32")
  199. #define TYPELIBWIN_2 _T("win16")
  200.  
  201. BOOL AFXAPI AfxOleUnregisterTypeLib(REFGUID tlid, WORD wVerMajor,
  202.     WORD wVerMinor, LCID lcid)
  203. {
  204.     USES_CONVERSION;
  205.  
  206.     // Load type library before unregistering it.
  207.     ITypeLib* pTypeLib = NULL;
  208.     if (wVerMajor != 0)
  209.     {
  210.         if (FAILED(LoadRegTypeLib(tlid, wVerMajor, wVerMinor, lcid, &pTypeLib)))
  211.             pTypeLib = NULL;
  212.     }
  213.  
  214.     // Format typelib guid as a string
  215.     OLECHAR szTypeLibID[GUID_CCH];
  216.     int cchGuid = ::StringFromGUID2(tlid, szTypeLibID, GUID_CCH);
  217.  
  218.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  219.     if (cchGuid != GUID_CCH)
  220.         return FALSE;
  221.  
  222.     TCHAR szKeyTypeLib[_MAX_PATH];
  223.     BOOL bSurgical = FALSE;
  224.     LONG error = ERROR_SUCCESS;
  225.  
  226.     wsprintf(szKeyTypeLib, _T("TYPELIB\\%s"), OLE2CT(szTypeLibID));
  227.  
  228.     HKEY hKeyTypeLib;
  229.     if (RegOpenKey(HKEY_CLASSES_ROOT, szKeyTypeLib, &hKeyTypeLib) ==
  230.         ERROR_SUCCESS)
  231.     {
  232.         int iKeyVersion = 0;
  233.         HKEY hKeyVersion;
  234.         TCHAR szVersion[_MAX_PATH];
  235.  
  236.         // Iterate through all installed versions of the control
  237.  
  238.         while (RegEnumKey(hKeyTypeLib, iKeyVersion, szVersion, _MAX_PATH) ==
  239.             ERROR_SUCCESS)
  240.         {
  241.             hKeyVersion = NULL;
  242.             BOOL bSurgicalVersion = FALSE;
  243.  
  244.             if (RegOpenKey(hKeyTypeLib, szVersion, &hKeyVersion) !=
  245.                 ERROR_SUCCESS)
  246.             {
  247.                 ++iKeyVersion;
  248.                 continue;
  249.             }
  250.  
  251.             int iKeyLocale = 0;
  252.             HKEY hKeyLocale;
  253.             TCHAR szLocale[_MAX_PATH];
  254.  
  255.             // Iterate through all registered locales for this version
  256.  
  257.             while (RegEnumKey(hKeyVersion, iKeyLocale, szLocale, _MAX_PATH) ==
  258.                 ERROR_SUCCESS)
  259.             {
  260.                 // Don't remove HELPDIR or FLAGS keys.
  261.                 if ((_tcsicmp(szLocale, _T("HELPDIR")) == 0) ||
  262.                     (_tcsicmp(szLocale, _T("FLAGS")) == 0))
  263.                 {
  264.                     ++iKeyLocale;
  265.                     continue;
  266.                 }
  267.  
  268.                 hKeyLocale = NULL;
  269.  
  270.                 if (RegOpenKey(hKeyVersion, szLocale, &hKeyLocale) !=
  271.                     ERROR_SUCCESS)
  272.                 {
  273.                     ++iKeyLocale;
  274.                     continue;
  275.                 }
  276.  
  277.                 // Check if a 16-bit key is found when unregistering 32-bit
  278.                 HKEY hkey;
  279.                 if (RegOpenKey(hKeyLocale, TYPELIBWIN_2, &hkey) ==
  280.                     ERROR_SUCCESS)
  281.                 {
  282.                     RegCloseKey(hkey);
  283.  
  284.                     // Only remove the keys specific to the 32-bit version
  285.                     // of control, leaving things intact for 16-bit version.
  286.                     error = _AfxRecursiveRegDeleteKey(hKeyLocale, TYPELIBWIN);
  287.                     bSurgicalVersion = TRUE;
  288.                     RegCloseKey(hKeyLocale);
  289.                 }
  290.                 else
  291.                 {
  292.                     // Delete everything for this locale.
  293.                     RegCloseKey(hKeyLocale);
  294.                     if (_AfxRecursiveRegDeleteKey(hKeyVersion, szLocale) ==
  295.                         ERROR_SUCCESS)
  296.                     {
  297.                         // Start over again, so we don't skip anything.
  298.                         iKeyLocale = 0;
  299.                         continue;
  300.                     }
  301.                 }
  302.                 ++iKeyLocale;
  303.             }
  304.             RegCloseKey(hKeyVersion);
  305.  
  306.             if (bSurgicalVersion)
  307.             {
  308.                 bSurgical = TRUE;
  309.             }
  310.             else
  311.             {
  312.                 if (_AfxRecursiveRegDeleteKey(hKeyTypeLib, szVersion) ==
  313.                     ERROR_SUCCESS)
  314.                 {
  315.                     // Start over again, to make sure we don't skip anything.
  316.                     iKeyVersion = 0;
  317.                     continue;
  318.                 }
  319.             }
  320.  
  321.             ++iKeyVersion;
  322.         }
  323.         RegCloseKey(hKeyTypeLib);
  324.     }
  325.  
  326.     if (!bSurgical)
  327.         error = _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT, szKeyTypeLib);
  328.  
  329.     if (_AfxRegDeleteKeySucceeded(error))
  330.     {
  331.         // If type library was unregistered successfully, then also unregister
  332.         // interfaces.
  333.         if (pTypeLib != NULL)
  334.         {
  335.             ITypeLib* pDummy = NULL;
  336.             if (FAILED(LoadRegTypeLib(tlid, wVerMajor, wVerMinor, lcid, &pDummy)))
  337.                 _AfxUnregisterInterfaces(pTypeLib);
  338.             else
  339.                 pDummy->Release();
  340.  
  341.             pTypeLib->Release();
  342.         }
  343.     }
  344.  
  345.     return _AfxRegDeleteKeySucceeded(error);
  346. }
  347.  
  348. static const LPCTSTR rglpszCtrlProgID[] =
  349. {
  350.     _T("\0") _T("%1"),
  351.     _T("CLSID\0") _T("%2"),
  352.     NULL
  353. };
  354.  
  355. #ifdef _MAC
  356. #define INPROCSERVER   _T("InprocServer")
  357. #define INPROCSERVER_2 _T("InprocServer")
  358. #define TOOLBOXBITMAP  _T("ToolboxBitmap")
  359. #else
  360. #define INPROCSERVER   _T("InprocServer32")
  361. #define INPROCSERVER_2 _T("InprocServer")
  362. #define TOOLBOXBITMAP  _T("ToolboxBitmap32")
  363. #endif
  364.  
  365. static const LPCTSTR rglpszCtrlClassID[] =
  366. {
  367.     _T("\0") _T("%1"),
  368.     _T("ProgID\0") _T("%2"),
  369.     INPROCSERVER _T("\0%3"),
  370.     TOOLBOXBITMAP _T("\0%3, %4"),
  371.     _T("MiscStatus\0") _T("0"),
  372.     _T("MiscStatus\\1\0") _T("%5"),
  373.     _T("Control\0") _T(""),
  374.     _T("TypeLib\0") _T("%6"),
  375.     _T("Version\0") _T("%7"),
  376.     NULL
  377. };
  378.  
  379. BOOL AFXAPI AfxOleRegisterControlClass(HINSTANCE hInstance,
  380.     REFCLSID clsid, LPCTSTR pszProgID, UINT idTypeName, UINT idBitmap,
  381.     int nRegFlags, DWORD dwMiscStatus, REFGUID tlid, WORD wVerMajor,
  382.     WORD wVerMinor)
  383. {
  384.     USES_CONVERSION;
  385.  
  386.     BOOL bSuccess = FALSE;
  387.  
  388.     // Format class ID as a string
  389.     OLECHAR szClassID[GUID_CCH];
  390.     int cchGuid = ::StringFromGUID2(clsid, szClassID, GUID_CCH);
  391.     LPCTSTR lpszClassID = OLE2CT(szClassID);
  392.  
  393.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  394.     if (cchGuid != GUID_CCH)
  395.         return FALSE;
  396.  
  397.     // Format typelib guid as a string
  398.     OLECHAR szTypeLibID[GUID_CCH];
  399.     cchGuid = ::StringFromGUID2(tlid, szTypeLibID, GUID_CCH);
  400.  
  401.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  402.     if (cchGuid != GUID_CCH)
  403.         return FALSE;
  404.  
  405.     CString strPathName;
  406.     AfxGetModuleShortFileName(hInstance, strPathName);
  407.  
  408.     CString strTypeName;
  409.     if (!strTypeName.LoadString(idTypeName))
  410.     {
  411.         ASSERT(FALSE);  // Name string not present in resources
  412.         strTypeName = lpszClassID; // Use Class ID instead
  413.     }
  414.  
  415.     TCHAR szBitmapID[_MAX_PATH];
  416.     _itot(idBitmap, szBitmapID, 10);
  417.  
  418.     TCHAR szMiscStatus[_MAX_PATH];
  419.     _ltot(dwMiscStatus, szMiscStatus, 10);
  420.  
  421.     // Format version string as "major.minor"
  422.     TCHAR szVersion[_MAX_PATH];
  423.     wsprintf(szVersion, _T("%d.%d"), wVerMajor, wVerMinor);
  424.  
  425.     // Attempt to open registry keys.
  426.     HKEY hkeyClassID = NULL;
  427.     HKEY hkeyProgID = NULL;
  428.  
  429.     TCHAR szScratch[_MAX_PATH];
  430.     wsprintf(szScratch, _T("CLSID\\%s"), lpszClassID);
  431.     if (::RegCreateKey(HKEY_CLASSES_ROOT, szScratch, &hkeyClassID) !=
  432.         ERROR_SUCCESS)
  433.         goto Error;
  434.     if (::RegCreateKey(HKEY_CLASSES_ROOT, pszProgID, &hkeyProgID) !=
  435.         ERROR_SUCCESS)
  436.         goto Error;
  437.  
  438.     ASSERT(hkeyClassID != NULL);
  439.     ASSERT(hkeyProgID != NULL);
  440.  
  441.     LPCTSTR rglpszSymbols[7];
  442.     rglpszSymbols[0] = strTypeName;
  443.     rglpszSymbols[1] = lpszClassID;
  444.     bSuccess = AfxOleRegisterHelper(rglpszCtrlProgID, rglpszSymbols, 2,
  445.         TRUE, hkeyProgID);
  446.  
  447.     if (!bSuccess)
  448.         goto Error;
  449.  
  450.     rglpszSymbols[1] = pszProgID;
  451. #ifndef _MAC
  452.     rglpszSymbols[2] = strPathName;
  453. #else
  454.     // get the code fragment name, which Mac OLE uses to load dlls
  455.     GetMacInstanceInformationEx(hInstance, NULL, NULL, szScratch, sizeof(szScratch));
  456.     rglpszSymbols[2] = szScratch;
  457. #endif
  458.     rglpszSymbols[3] = szBitmapID;
  459.     rglpszSymbols[4] = szMiscStatus;
  460.     rglpszSymbols[5] = OLE2CT(szTypeLibID);
  461.     rglpszSymbols[6] = szVersion;
  462.     bSuccess = AfxOleRegisterHelper(rglpszCtrlClassID, rglpszSymbols, 7,
  463.         TRUE, hkeyClassID);
  464.  
  465.     if (!bSuccess)
  466.         goto Error;
  467.  
  468.     if (nRegFlags & afxRegInsertable)
  469.     {
  470.         bSuccess =
  471.             (::RegSetValue(hkeyProgID, _T("Insertable"), REG_SZ, _T(""), 0) ==
  472.                 ERROR_SUCCESS) &&
  473.             (::RegSetValue(hkeyClassID, _T("Insertable"), REG_SZ, _T(""), 0) ==
  474.                 ERROR_SUCCESS);
  475.     }
  476.  
  477. #ifndef _MAC
  478.     if (nRegFlags & afxRegApartmentThreading)
  479.     {
  480.         HKEY hkeyInprocServer32;
  481.         bSuccess = (::RegOpenKey(hkeyClassID, INPROCSERVER,
  482.             &hkeyInprocServer32) == ERROR_SUCCESS);
  483.         if (!bSuccess)
  484.             goto Error;
  485.         ASSERT(hkeyInprocServer32 != NULL);
  486.         static TCHAR szApartment[] = _T("Apartment");
  487.         bSuccess = (::RegSetValueEx(hkeyInprocServer32, _T("ThreadingModel"), 0,
  488.             REG_SZ, (const BYTE*)szApartment, (lstrlen(szApartment)+1) * sizeof(TCHAR)) ==
  489.             ERROR_SUCCESS);
  490.         ::RegCloseKey(hkeyInprocServer32);
  491.     }
  492. #endif
  493.  
  494. Error:
  495.     if (hkeyProgID != NULL)
  496.         ::RegCloseKey(hkeyProgID);
  497.  
  498.     if (hkeyClassID != NULL)
  499.         ::RegCloseKey(hkeyClassID);
  500.  
  501.     return bSuccess;
  502. }
  503.  
  504. BOOL AFXAPI AfxOleUnregisterClass(REFCLSID clsid, LPCTSTR pszProgID)
  505. {
  506.     USES_CONVERSION;
  507.  
  508.     // Format class ID as a string
  509.     OLECHAR szClassID[GUID_CCH];
  510.     int cchGuid = ::StringFromGUID2(clsid, szClassID, GUID_CCH);
  511.     LPCTSTR lpszClassID = OLE2CT(szClassID);
  512.  
  513.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  514.     if (cchGuid != GUID_CCH)
  515.         return FALSE;
  516.  
  517.     TCHAR szKey[_MAX_PATH];
  518.     long error;
  519.     BOOL bRetCode = TRUE;
  520.  
  521. #ifndef _MAC
  522.     // check to see if a 16-bit InprocServer key is found when unregistering
  523.     // 32-bit (or vice versa).
  524.     wsprintf(szKey, _T("CLSID\\%s\\%s"), lpszClassID, INPROCSERVER_2);
  525.     HKEY hkey;
  526.     BOOL bSurgical = RegOpenKey(HKEY_CLASSES_ROOT, szKey, &hkey) ==
  527.         ERROR_SUCCESS;
  528.  
  529.     if (bSurgical)
  530.     {
  531.         // Only remove the keys specific to this version of the control,
  532.         // leaving things in tact for the other version.
  533.         wsprintf(szKey, _T("CLSID\\%s\\%s"), lpszClassID, INPROCSERVER);
  534.         error = RegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  535.         bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  536.  
  537.         wsprintf(szKey, _T("CLSID\\%s\\%s"), lpszClassID, TOOLBOXBITMAP);
  538.         error = RegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  539.         bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  540.     }
  541.     else
  542. #endif
  543.     {
  544.         // No other versions of this control were detected,
  545.         // so go ahead and remove the control completely.
  546.         wsprintf(szKey, _T("CLSID\\%s"), lpszClassID);
  547.         error = _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT, szKey);
  548.         bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  549.  
  550.         if (pszProgID != NULL)
  551.         {
  552.             error = _AfxRecursiveRegDeleteKey(HKEY_CLASSES_ROOT,
  553.                 (LPTSTR)pszProgID);
  554.             bRetCode = bRetCode && _AfxRegDeleteKeySucceeded(error);
  555.         }
  556.     }
  557.  
  558.     return bRetCode;
  559. }
  560.  
  561. static const LPCTSTR rglpszPropPageClass[] =
  562. {
  563.     _T("\0") _T("%1"),
  564.     INPROCSERVER _T("\0%2"),
  565.     NULL
  566. };
  567.  
  568. BOOL AFXAPI AfxOleRegisterPropertyPageClass(HINSTANCE hInstance,
  569.     REFCLSID clsid, UINT idTypeName)
  570. {
  571.     return AfxOleRegisterPropertyPageClass(hInstance, clsid, idTypeName, 0);
  572. }
  573.  
  574. BOOL AFXAPI AfxOleRegisterPropertyPageClass(HINSTANCE hInstance,
  575.     REFCLSID clsid, UINT idTypeName, int nRegFlags)
  576. {
  577.     ASSERT(!(nRegFlags & afxRegInsertable));    // can't be insertable
  578.  
  579.     USES_CONVERSION;
  580.  
  581.     BOOL bSuccess = FALSE;
  582.  
  583.     // Format class ID as a string
  584.     OLECHAR szClassID[GUID_CCH];
  585.     int cchGuid = ::StringFromGUID2(clsid, szClassID, GUID_CCH);
  586.     LPCTSTR lpszClassID = OLE2CT(szClassID);
  587.  
  588.     ASSERT(cchGuid == GUID_CCH);    // Did StringFromGUID2 work?
  589.     if (cchGuid != GUID_CCH)
  590.         return FALSE;
  591.  
  592.     CString strPathName;
  593. #ifndef _MAC
  594.     AfxGetModuleShortFileName(hInstance, strPathName);
  595. #else
  596.     GetMacInstanceInformationEx(hInstance, NULL, NULL,
  597.         strPathName.GetBuffer(64), 64);
  598.     strPathName.ReleaseBuffer();
  599. #endif
  600.  
  601.     CString strTypeName;
  602.     if (!strTypeName.LoadString(idTypeName))
  603.     {
  604.         ASSERT(FALSE);  // Name string not present in resources
  605.         strTypeName = lpszClassID; // Use Class ID instead
  606.     }
  607.  
  608.     HKEY hkeyClassID = NULL;
  609.  
  610.     TCHAR szKey[_MAX_PATH];
  611.     wsprintf(szKey, _T("CLSID\\%s"), lpszClassID);
  612.     if (::RegCreateKey(HKEY_CLASSES_ROOT, szKey, &hkeyClassID) !=
  613.         ERROR_SUCCESS)
  614.         goto Error;
  615.  
  616.     LPCTSTR rglpszSymbols[2];
  617.     rglpszSymbols[0] = strTypeName;
  618.     rglpszSymbols[1] = strPathName;
  619.     bSuccess = AfxOleRegisterHelper(rglpszPropPageClass, rglpszSymbols,
  620.         2, TRUE, hkeyClassID);
  621.  
  622.     if (!bSuccess)
  623.         goto Error;
  624.  
  625. #ifndef _MAC
  626.     if (nRegFlags & afxRegApartmentThreading)
  627.     {
  628.         HKEY hkeyInprocServer32;
  629.         bSuccess = (::RegOpenKey(hkeyClassID, INPROCSERVER,
  630.             &hkeyInprocServer32) == ERROR_SUCCESS);
  631.         if (!bSuccess)
  632.             goto Error;
  633.         ASSERT(hkeyInprocServer32 != NULL);
  634.         static TCHAR szApartment[] = _T("Apartment");
  635.         bSuccess = (::RegSetValueEx(hkeyInprocServer32, _T("ThreadingModel"), 0,
  636.             REG_SZ, (const BYTE*)szApartment, (lstrlen(szApartment)+1) * sizeof(TCHAR)) ==
  637.             ERROR_SUCCESS);
  638.         ::RegCloseKey(hkeyInprocServer32);
  639.     }
  640. #endif
  641.  
  642. Error:
  643.     if (hkeyClassID != NULL)
  644.         ::RegCloseKey(hkeyClassID);
  645.  
  646.     return bSuccess;
  647. }
  648.  
  649. #ifdef _MAC
  650. //+--------------------------------------------------------------
  651. //  Function:   FullPathFromDirID
  652. //
  653. //  Synopsis:   Prepends the input string with the full path of
  654. //              the given directory.  If the input string isn't
  655. //              empty, it should begin with a mac path separator
  656. //              character, ':'
  657. //
  658. //  Arguments:  LONG idDir directory id of target dir
  659. //              SHORT rnVol volume ref num
  660. //              CHAR *pchPathBuf buffer to receive path
  661. //
  662. //  Returns:    noErr if full path returned, otherwise error code
  663. //
  664. //  History:    24-Jan-95   jamesdu   Created
  665. //---------------------------------------------------------------
  666.  
  667. static OSErr FullPathFromDirID(long idDir, short rnVol, char *pchPathBuf)
  668. {
  669.     CInfoPBRec cipb;
  670.     OSErr oserr;
  671.     char szBuildPath[_MAX_PATH];
  672.  
  673.     memset(&cipb, 0, sizeof(cipb));
  674.     cipb.dirInfo.ioFDirIndex = -1; // use the directory ID
  675.     cipb.dirInfo.ioNamePtr = (unsigned char *)szBuildPath;
  676.     cipb.dirInfo.ioVRefNum = rnVol; // use the directory ID
  677.     cipb.dirInfo.ioDrDirID = idDir;
  678.  
  679.     do
  680.     {
  681.         oserr = PBGetCatInfoSync(&cipb);
  682.         if (noErr != oserr)
  683.         {
  684.             return oserr;
  685.         }
  686.         szBuildPath[*szBuildPath+1] = '\0';
  687.         *szBuildPath = ':';
  688.         strcat(szBuildPath, pchPathBuf);
  689.         cipb.dirInfo.ioDrDirID = cipb.dirInfo.ioDrParID;
  690.         // don't copy the leading colon if we've reached the root
  691.         strcpy(pchPathBuf, szBuildPath + (1 == cipb.dirInfo.ioDrDirID));
  692.     }
  693.     while (cipb.dirInfo.ioDrDirID != 1); // until root reached
  694.  
  695.     return noErr;
  696. }
  697.  
  698.  
  699. ///////////////////////////////////////
  700. //
  701.  
  702. OSErr FullPathFromFSSpec(char *szFileName, FSSpec *pfsp)
  703. {
  704.     *szFileName = ':';
  705.     strncpy(szFileName+1, (char *)pfsp->name+1, *pfsp->name);
  706.     *(szFileName + *pfsp->name+1) = '\0';
  707.     return FullPathFromDirID(pfsp->parID, pfsp->vRefNum, szFileName);
  708. }
  709.  
  710. // EnsureTypeLibFolder should go into the WLM OLE dll.
  711.  
  712. // fills in the fsspec's parent ID and vRefNum fields to point to
  713. // the extensions:Type Libraries folder.  Leaves the name field unchanged.
  714. // Entire fsspec is unchanged if an error occurs
  715.  
  716. STDAPI EnsureTypeLibFolder(void)
  717. {
  718.     FSSpec fsp;
  719.     OSErr oserr;
  720.     char szPath[_MAX_PATH];
  721.  
  722.  
  723.     oserr = FindFolder((unsigned short)kOnSystemDisk, kExtensionFolderType, kDontCreateFolder,
  724.         &fsp.vRefNum, &fsp.parID);
  725.     if (noErr == oserr)
  726.     {
  727.         strcpy((char *)&fsp.name, (char *)"\pType Libraries");
  728.         oserr = FullPathFromFSSpec(szPath, &fsp);
  729.         if (noErr == oserr)
  730.             RegisterTypeLibFolder(szPath);
  731.     }
  732.  
  733.     return oserr == noErr ? S_OK : E_INVALIDARG;
  734. }
  735.  
  736. HRESULT TypeLibFspFromFullPath(const char *szPathName, FSSpec *pfspTlb)
  737. {
  738.     char *pch;
  739. // truncate to 27 chars if necessary and append ".tlb" to filename
  740.     if (!UnwrapFile(szPathName, pfspTlb))
  741.         return ERROR_INVALID_NAME;
  742.  
  743.     pfspTlb->name[1+*pfspTlb->name] = '\0';
  744.     pfspTlb->name[28] = '\0';
  745.  
  746.     // remove any "dot extension"
  747.     pch = PLstrrchr(pfspTlb->name, '.');
  748.     if (NULL != pch)
  749.         *pch = '\0';
  750.     strcat((char *)pfspTlb->name+1, ".tlb");
  751.     *pfspTlb->name = (BYTE)lstrlen((char *)pfspTlb->name+1);
  752.     return NOERROR;
  753. }
  754.  
  755. #undef LoadTypeLib
  756. #ifdef _AFXDLL
  757. #define LoadTypeLib _afxOLE.pfnLoadTypeLib
  758. #endif
  759.  
  760. HRESULT _LoadTypeLibGetMacPath(const char *szPathName, char *szMacPath, ITypeLib **ppTypeLib)
  761. {
  762.     HRESULT hr;
  763.     FSSpec fspTlb;
  764.  
  765.     TypeLibFspFromFullPath(szPathName, &fspTlb);
  766.     hr = LoadTypeLibFSp(&fspTlb, ppTypeLib);
  767.     if (FAILED(hr))
  768.     {
  769.         // try in type lib folder
  770.         BSTR bstr;
  771.         hr = QueryTypeLibFolder(&bstr);
  772.         if (SUCCEEDED(hr))
  773.         {
  774.             int i = SysStringLen(bstr);
  775.             ASSERT(i < 256 - 31);
  776.             lstrcpy(szMacPath, bstr);
  777.             SysFreeString(bstr);
  778.             lstrcat(szMacPath, ":");
  779.             lstrcat(szMacPath, (char*)fspTlb.name+1);
  780.             hr = LoadTypeLib(szMacPath, ppTypeLib);
  781.         }
  782.     }
  783.     else
  784.     {
  785.         FullPathFromFSSpec(szMacPath, &fspTlb);
  786.     }
  787.  
  788.     return hr;
  789. }
  790.  
  791. STDAPI _LoadTypeLib(const char *szPathName, ITypeLib **ppTypeLib)
  792. {
  793.     char szMacPath[256];
  794.     return _LoadTypeLibGetMacPath(szPathName, szMacPath, ppTypeLib);
  795. }
  796.  
  797. #endif
  798.  
  799. /////////////////////////////////////////////////////////////////////////////
  800. // Force any extra compiler-generated code into AFX_INIT_SEG
  801.  
  802. #ifdef AFX_INIT_SEG
  803. #pragma code_seg(AFX_INIT_SEG)
  804. #endif
  805.