home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / olereg.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  16KB  |  538 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. #include <shellapi.h>
  13.  
  14. #ifdef AFX_OLE4_SEG
  15. #pragma code_seg(AFX_OLE4_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. // from docmgr.cpp
  26. extern BOOL AFXAPI _AfxDeleteRegKey(LPCTSTR lpszKey);
  27.  
  28.  
  29. //////////////////////////////////////////////////////////////////////////////
  30. // data for UpdateRegistry functionality
  31.  
  32. // %1 - class ID
  33. // %2 - class name
  34. // %3 - SFN executable path
  35. // %4 - short type name
  36. // %5 - long type name
  37. // %6 - long application name
  38. // %7 - icon index
  39. // %8 - Creator(xxxxxxxx) [mac-only]
  40. // %8 - File extension Description [non-mac only]
  41. // %9 - (not used yet) [mac-only]
  42. // %9 - File extension *.TLA [non-mac only]
  43. // %A - (not used yet)
  44. #define NUM_REG_VARS 10
  45.  
  46. class CAfxOleSymbolTable
  47. {
  48. protected:
  49.     LPTSTR* m_strEntries;
  50.     int m_nEntries;
  51.  
  52. public:
  53.     CAfxOleSymbolTable(int nEntries);
  54.     ~CAfxOleSymbolTable();
  55.  
  56.     LPCTSTR* GetArray() { return (LPCTSTR*) m_strEntries; }
  57.     LPCTSTR GetAt(int nIndex) const;
  58.     void SetAt(int nIndex, LPCTSTR pstr);
  59.     LPCTSTR operator[](int nIndex) const { return GetAt(nIndex); }
  60. };
  61.  
  62. CAfxOleSymbolTable::CAfxOleSymbolTable(int nEntries)
  63. {
  64.     m_strEntries = new LPTSTR[nEntries];
  65.     memset(m_strEntries, 0, sizeof(LPTSTR) * nEntries);
  66.     m_nEntries = nEntries;
  67. }
  68.  
  69. CAfxOleSymbolTable::~CAfxOleSymbolTable()
  70. {
  71.     int nIndex;
  72.     for (nIndex = 0; nIndex < m_nEntries; nIndex++)
  73.         free(m_strEntries[nIndex]);
  74.     delete [] m_strEntries;
  75. }
  76.  
  77. void CAfxOleSymbolTable::SetAt(int nIndex, LPCTSTR pstr)
  78. {
  79.     ASSERT(nIndex < m_nEntries && nIndex >= 0);
  80.  
  81.     free(m_strEntries[nIndex]);
  82.     m_strEntries[nIndex] = pstr ? _tcsdup(pstr) : NULL;
  83. }
  84.  
  85. LPCTSTR CAfxOleSymbolTable::GetAt(int nIndex) const
  86. {
  87.     if (nIndex < m_nEntries || nIndex < 0)
  88.         return m_strEntries[nIndex];
  89.     else
  90.         return NULL;
  91. }
  92.  
  93. static const TCHAR sz00[] = _T("%2\0") _T("%5");
  94. static const TCHAR sz01[] = _T("%2\\CLSID\0") _T("%1");
  95. static const TCHAR sz02[] = _T("%2\\Insertable\0") _T("");
  96. static const TCHAR sz03[] = _T("%2\\protocol\\StdFileEditing\\verb\\0\0") _T("&Edit");
  97. static const TCHAR sz04[] = _T("%2\\protocol\\StdFileEditing\\server\0") _T("%3");
  98. static const TCHAR sz05[] = _T("CLSID\\%1\0") _T("%5");
  99. static const TCHAR sz06[] = _T("CLSID\\%1\\ProgID\0") _T("%2");
  100. static const TCHAR sz07[] = _T("CLSID\\%1\\InprocHandler32\0") _T("ole32.dll");
  101. static const TCHAR sz08[] = _T("CLSID\\%1\\LocalServer32\0") _T("%3");
  102. static const TCHAR sz09[] = _T("CLSID\\%1\\Verb\\0\0") _T("&Edit,0,2");
  103. static const TCHAR sz10[] = _T("CLSID\\%1\\Verb\\1\0") _T("&Open,0,2");
  104. static const TCHAR sz11[] = _T("CLSID\\%1\\Insertable\0") _T("");
  105. static const TCHAR sz12[] = _T("CLSID\\%1\\AuxUserType\\2\0") _T("%4");
  106. static const TCHAR sz13[] = _T("CLSID\\%1\\AuxUserType\\3\0") _T("%6");
  107. static const TCHAR sz14[] = _T("CLSID\\%1\\DefaultIcon\0") _T("%3,%7");
  108. static const TCHAR sz15[] = _T("CLSID\\%1\\MiscStatus\0") _T("32");
  109. static const TCHAR sz16[] = _T("\0") _T("");
  110. static const TCHAR sz17[] = _T("CLSID\\%1\\InProcServer32\0") _T("%3");
  111. static const TCHAR sz18[] = _T("CLSID\\%1\\DocObject\0" _T("0")); // CLSIDDocObject
  112. static const TCHAR sz19[] = _T("%2\\DocObject\0" _T("0")); // ProgIDDocObject
  113. static const TCHAR sz20[] = _T("CLSID\\%1\\Printable\0"); // szPrintable
  114. static const TCHAR sz21[] = _T("CLSID\\%1\\DefaultExtension\0%9, %8"); // szDefaultExt
  115.  
  116. // registration for OAT_INPLACE_SERVER
  117. static const LPCTSTR rglpszInPlaceRegister[] =
  118. {
  119.     sz00, sz02, sz03, sz05, sz09, sz10, sz11, sz12,
  120.     sz13, sz15,
  121.     NULL
  122. };
  123.  
  124. // registration for OAT_SERVER
  125. static const LPCTSTR rglpszServerRegister[] =
  126. {
  127.     sz00, sz02, sz03, sz05, sz09, sz11, sz12,
  128.     sz13, sz15,
  129.     NULL
  130. };
  131.  
  132. // registration for OAT_DOC_OBJECT_SERVER
  133. static const LPCTSTR rglpszDocObjectRegister[] =
  134. {
  135.     sz00, sz02, sz03, sz05, sz09, sz10, sz11, sz12,
  136.     sz13, sz15, sz18, sz19, sz20,
  137.     NULL
  138. };
  139.  
  140. // overwrite entries for OAT_SERVER & OAT_INPLACE_SERVER
  141. static const LPCTSTR rglpszServerOverwrite[] =
  142. {
  143.     sz01, sz04, sz06, sz07, sz08, sz14, NULL
  144. };
  145. // overwrite entries for OAT_SERVER & OAT_INPLACE_SERVER (dll)
  146. static const LPCTSTR rglpszServerOverwriteDLL[] =
  147. {
  148.     sz01, sz04, sz06,
  149.     sz17,
  150.     sz14,
  151.     NULL
  152. };
  153.  
  154. // registration for OAT_CONTAINER
  155. static const LPCTSTR rglpszContainerRegister[] =
  156. {
  157.     sz00, sz05, NULL
  158. };
  159. // overwrite entries for OAT_CONTAINER
  160. static const LPCTSTR rglpszContainerOverwrite[] =
  161. {
  162.     sz01, sz06, sz07, sz08, sz14, NULL
  163. };
  164.  
  165. // registration for OAT_DISPATCH_OBJECT
  166. static const LPCTSTR rglpszDispatchRegister[] =
  167. {
  168.     sz00, sz05, NULL
  169. };
  170. // overwrite entries for OAT_DISPATCH_OBJECT
  171. static const LPCTSTR rglpszDispatchOverwrite[] =
  172. {
  173.     sz01, sz06, sz07, sz08, NULL
  174. };
  175. // overwrite entries for OAT_DISPATCH_OBJECT (dll)
  176. static const LPCTSTR rglpszDispatchOverwriteDLL[] =
  177. {
  178.     sz01, sz06,
  179.     sz17,
  180.     NULL
  181. };
  182.  
  183. // overwrite entries for OAT_DOC_OBJECT_SERVER
  184. static const LPCTSTR rglpszDocObjectOverwrite[] =
  185. {
  186.     sz01, sz04, sz06, sz07, sz08, sz14, sz21,
  187.     NULL
  188. };
  189.  
  190. struct STANDARD_ENTRY
  191. {
  192.     const LPCTSTR* rglpszRegister;
  193.     const LPCTSTR* rglpszOverwrite;
  194. };
  195.  
  196. static const STANDARD_ENTRY rgStdEntries[] =
  197. {
  198.     { rglpszInPlaceRegister, rglpszServerOverwrite },
  199.     { rglpszServerRegister, rglpszServerOverwrite },
  200.     { rglpszContainerRegister, rglpszContainerOverwrite },
  201.     { rglpszDispatchRegister, rglpszDispatchOverwrite },
  202.     { rglpszDocObjectRegister, rglpszDocObjectOverwrite },
  203. };
  204.  
  205. static const STANDARD_ENTRY rgStdEntriesDLL[] =
  206. {
  207.     { rglpszInPlaceRegister, rglpszServerOverwriteDLL },
  208.     { rglpszServerRegister, rglpszServerOverwriteDLL },
  209.     { rglpszContainerRegister, rglpszContainerOverwrite },
  210.     { rglpszDispatchRegister, rglpszDispatchOverwriteDLL },
  211.     { rglpszDocObjectRegister, rglpszDocObjectOverwrite },
  212. };
  213.  
  214. /////////////////////////////////////////////////////////////////////////////
  215. // Special registration for apps that wish not to use REGLOAD
  216.  
  217. BOOL AFXAPI AfxOleRegisterServerClassCompat(
  218.     REFCLSID clsid, LPCTSTR lpszClassName,
  219.     LPCTSTR lpszShortTypeName, LPCTSTR lpszLongTypeName,
  220.     OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister, LPCTSTR* rglpszOverwrite)
  221. {
  222.     return AfxOleRegisterServerClass(clsid, lpszClassName, lpszShortTypeName,
  223.         lpszLongTypeName, nAppType, rglpszRegister, rglpszOverwrite);
  224. }
  225.  
  226. AFX_STATIC BOOL AFXAPI _AfxOleMakeSymbolTable(CAfxOleSymbolTable& refTable,
  227.     REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName,
  228.     LPCTSTR lpszLongTypeName, int nIconIndex,
  229.     LPCTSTR lpszFilterName, LPCTSTR lpszFilterExt)
  230. {
  231.     // 0 - class ID
  232.     // 1 - class name
  233.     // 2 - SFN executable path
  234.     // 3 - short type name
  235.     // 4 - long type name
  236.     // 5 - long application name
  237.     // 6 - icon index
  238.     // 7 - Creator(xxxxxxxx) [Mac only]
  239.     // 8 - Creator(xxxxxxxx) [mac-only]
  240.     // 9 - Filter description
  241.  
  242.     // convert the CLSID to a string
  243.     LPTSTR lpszClassID;
  244.     LPOLESTR lpOleStr;
  245.     ::StringFromCLSID(clsid, &lpOleStr);
  246.     lpszClassID = TASKSTRINGOLE2T(lpOleStr);
  247.     if (lpszClassID == NULL)
  248.     {
  249.         TRACE0("Warning: StringFromCLSID failed in AfxOleRegisterServerName --\n");
  250.         TRACE0("\tperhaps AfxOleInit() has not been called.\n");
  251.         return FALSE;
  252.     }
  253.     refTable.SetAt(0, lpszClassID);
  254.     refTable.SetAt(1, lpszClassName);
  255.  
  256.     // free memory for class ID
  257.     ASSERT(lpszClassID != NULL);
  258.     CoTaskMemFree(lpszClassID);
  259.  
  260.     // get path name to server
  261.     CString strPathName;
  262.     AfxGetModuleShortFileName(AfxGetInstanceHandle(), strPathName);
  263.     refTable.SetAt(2, strPathName);
  264.  
  265.     // fill in rest of symbols
  266.     refTable.SetAt(3, lpszShortTypeName);
  267.     refTable.SetAt(4, lpszLongTypeName);
  268.     refTable.SetAt(5, AfxGetAppName()); // will usually be long, readable name
  269.  
  270.     CString strIconIndex;
  271.     if (nIconIndex != 0)
  272.     {
  273.         HICON hIcon = ::ExtractIcon(AfxGetInstanceHandle(), strPathName, nIconIndex);
  274.         if (hIcon != NULL)
  275.             DestroyIcon(hIcon);
  276.         else
  277.             nIconIndex = 0; // couldn't find specified icon so use default
  278.     }
  279.     strIconIndex.Format(_T("%d"), nIconIndex);
  280.     refTable.SetAt(6, strIconIndex);
  281.  
  282.     refTable.SetAt(7, lpszFilterName);
  283.  
  284.     CString strFileExtension;
  285.     if (lpszFilterExt != NULL && *lpszFilterExt != 0)
  286.     {
  287.         // use file extension provided
  288.         strFileExtension = lpszFilterExt;
  289.     }
  290.     else
  291.     {
  292.         // otherwise, try to find the extension from the description
  293.  
  294.         // parse the actual extension (eg "*.TLA") from the
  295.         // filter name (eg, "Three Letter Acronym Files (*.TLA)")
  296.  
  297.         strFileExtension = lpszFilterName;
  298.         int nBeginning = strFileExtension.Find('(');
  299.         if (nBeginning == -1)
  300.             strFileExtension.Empty();
  301.         else
  302.         {
  303.             strFileExtension = strFileExtension.Mid(1+nBeginning);
  304.             nBeginning = strFileExtension.Find('.');
  305.             if (nBeginning == -1)
  306.                 strFileExtension.Empty();
  307.             else
  308.             {
  309.                 strFileExtension = strFileExtension.Mid(nBeginning);
  310.  
  311.                 int nEnd = strFileExtension.Find(')');
  312.                 if (nEnd == -1)
  313.                     strFileExtension.Empty();
  314.                 else
  315.                     strFileExtension = strFileExtension.Left(nEnd);
  316.             }
  317.         }
  318.     }
  319.     refTable.SetAt(8, strFileExtension);
  320.     return TRUE;
  321. }
  322.  
  323. BOOL AFXAPI AfxOleRegisterServerClass(
  324.     REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName,
  325.     LPCTSTR lpszLongTypeName, OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister,
  326.     LPCTSTR* rglpszOverwrite, int nIconIndex,
  327.     LPCTSTR lpszFilterName)
  328. {
  329.     return AfxOleRegisterServerClass(clsid, lpszClassName, lpszShortTypeName,
  330.         lpszLongTypeName, nAppType, rglpszRegister, rglpszOverwrite, nIconIndex,
  331.         lpszFilterName, NULL);
  332. }
  333.  
  334.  
  335. BOOL AFXAPI AfxOleRegisterServerClass(
  336.     REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName,
  337.     LPCTSTR lpszLongTypeName, OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister,
  338.     LPCTSTR* rglpszOverwrite, int nIconIndex,
  339.     LPCTSTR lpszFilterName, LPCTSTR lpszFilterExt)
  340. {
  341.     ASSERT(AfxIsValidString(lpszClassName));
  342.     ASSERT(AfxIsValidString(lpszShortTypeName));
  343.     ASSERT(*lpszShortTypeName != 0);
  344.     ASSERT(AfxIsValidString(lpszLongTypeName));
  345.     ASSERT(*lpszLongTypeName != 0);
  346.     ASSERT(nAppType == OAT_INPLACE_SERVER || nAppType == OAT_SERVER ||
  347.         nAppType == OAT_CONTAINER || nAppType == OAT_DISPATCH_OBJECT ||
  348.         nAppType == OAT_DOC_OBJECT_SERVER);
  349.     ASSERT(nAppType >= 0 && nAppType < _countof(rgStdEntries));
  350.  
  351.     // use standard registration entries if non given
  352.     if (rglpszRegister == NULL)
  353.         rglpszRegister = (LPCTSTR*)rgStdEntries[nAppType].rglpszRegister;
  354.     if (rglpszOverwrite == NULL)
  355.     {
  356.         // DLL contexts have special strings
  357.         if (!afxContextIsDLL)
  358.             rglpszOverwrite = (LPCTSTR*)rgStdEntries[nAppType].rglpszOverwrite;
  359.         else
  360.             rglpszOverwrite = (LPCTSTR*)rgStdEntriesDLL[nAppType].rglpszOverwrite;
  361.     }
  362.  
  363.     CAfxOleSymbolTable table(NUM_REG_VARS);
  364.  
  365.     if (!_AfxOleMakeSymbolTable(table, clsid, lpszClassName,
  366.                 lpszShortTypeName, lpszLongTypeName,
  367.                 nIconIndex, lpszFilterName, lpszFilterExt))
  368.     {
  369.         return FALSE;
  370.     }
  371.  
  372.     // protect against registering an invalid DocObject server
  373.     ASSERT(nAppType != OAT_DOC_OBJECT_SERVER ||
  374.         (lstrlen(table.GetAt(8)) != 0 && lstrcmp(table.GetAt(8), _T(".*")) != 0));
  375.  
  376.     // update the registry with helper function
  377.     BOOL bResult;
  378.     bResult = AfxOleRegisterHelper(rglpszRegister, table.GetArray(),
  379.         NUM_REG_VARS, FALSE);
  380.     if (bResult && rglpszOverwrite != NULL)
  381.     {
  382.         bResult = AfxOleRegisterHelper(rglpszOverwrite, table.GetArray(),
  383.             NUM_REG_VARS, TRUE);
  384.     }
  385.  
  386.     // free memory for class ID
  387.     return bResult;
  388. }
  389.  
  390. BOOL AFXAPI AfxOleUnregisterServerClass(
  391.     REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName,
  392.     LPCTSTR lpszLongTypeName, OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister,
  393.     LPCTSTR* rglpszOverwrite)
  394. {
  395.     // use standard registration entries if non given
  396.     if (rglpszRegister == NULL)
  397.         rglpszRegister = (LPCTSTR*)rgStdEntries[nAppType].rglpszRegister;
  398.     if (rglpszOverwrite == NULL)
  399.     {
  400.         // DLL contexts have special strings
  401.         if (!afxContextIsDLL)
  402.             rglpszOverwrite = (LPCTSTR*)rgStdEntries[nAppType].rglpszOverwrite;
  403.         else
  404.             rglpszOverwrite = (LPCTSTR*)rgStdEntriesDLL[nAppType].rglpszOverwrite;
  405.     }
  406.  
  407.     CAfxOleSymbolTable table(NUM_REG_VARS);
  408.  
  409.     if (!_AfxOleMakeSymbolTable(table, clsid, lpszClassName,
  410.                 lpszShortTypeName, lpszLongTypeName, 0, NULL, NULL))
  411.     {
  412.         return FALSE;
  413.     }
  414.  
  415.     // clean up the the registry with helper function
  416.     BOOL bResult;
  417.     bResult = AfxOleUnregisterHelper(rglpszRegister, table.GetArray(),
  418.         NUM_REG_VARS);
  419.     if (bResult && rglpszOverwrite != NULL)
  420.     {
  421.         bResult = AfxOleUnregisterHelper(rglpszOverwrite, table.GetArray(),
  422.             NUM_REG_VARS);
  423.     }
  424.  
  425.     return bResult;
  426. }
  427.  
  428. // removes key/value pairs from system registry
  429. BOOL AFXAPI AfxOleUnregisterHelper(LPCTSTR const* rglpszRegister,
  430.     LPCTSTR const* rglpszSymbols, int nSymbols,
  431.     HKEY hKeyRoot /* = HKEY_CLASSES_ROOT */)
  432. {
  433.     ASSERT(rglpszRegister != NULL);
  434.     ASSERT(nSymbols == 0 || rglpszSymbols != NULL);
  435.  
  436.     CString strKey;
  437.     CString strValue;
  438.  
  439.     // keeping a key open makes this go a bit faster
  440.     HKEY hKeyTemp = NULL;
  441.     if (hKeyRoot == HKEY_CLASSES_ROOT)
  442.         RegOpenKey(HKEY_CLASSES_ROOT, _T("CLSID"), &hKeyTemp);
  443.  
  444.     BOOL bResult = TRUE;
  445.     while (*rglpszRegister != NULL)
  446.     {
  447.         LPCTSTR lpszKey = *rglpszRegister++;
  448.         if ((hKeyRoot == HKEY_CLASSES_ROOT) && (*lpszKey == '\0'))
  449.             continue;
  450.  
  451.         AfxFormatStrings(strKey, lpszKey, rglpszSymbols, nSymbols);
  452.  
  453.         if ((hKeyRoot == HKEY_CLASSES_ROOT) && strKey.IsEmpty())
  454.         {
  455.             TRACE1("Warning: skipping empty key '%s'.\n", lpszKey);
  456.             continue;
  457.         }
  458.  
  459.         _AfxDeleteRegKey(strKey);
  460.     }
  461.  
  462.     if (hKeyTemp != NULL)
  463.         RegCloseKey(hKeyTemp);
  464.  
  465.     return bResult;
  466. }
  467.  
  468. // writes key/value pairs to system registry
  469. BOOL AFXAPI AfxOleRegisterHelper(LPCTSTR const* rglpszRegister,
  470.     LPCTSTR const* rglpszSymbols, int nSymbols, BOOL bReplace,
  471.     HKEY hKeyRoot /* = HKEY_CLASSES_ROOT */)
  472. {
  473.     ASSERT(rglpszRegister != NULL);
  474.     ASSERT(nSymbols == 0 || rglpszSymbols != NULL);
  475.  
  476.     CString strKey;
  477.     CString strValue;
  478.  
  479.     // keeping a key open makes this go a bit faster
  480.     HKEY hKeyTemp = NULL;
  481.     if (hKeyRoot == HKEY_CLASSES_ROOT)
  482.         RegOpenKey(HKEY_CLASSES_ROOT, _T("CLSID"), &hKeyTemp);
  483.  
  484.     BOOL bResult = TRUE;
  485.     while (*rglpszRegister != NULL)
  486.     {
  487.         LPCTSTR lpszKey = *rglpszRegister++;
  488.         if ((hKeyRoot == HKEY_CLASSES_ROOT) && (*lpszKey == '\0'))
  489.             continue;
  490.  
  491.         LPCTSTR lpszValue = lpszKey + lstrlen(lpszKey) + 1;
  492.  
  493.         AfxFormatStrings(strKey, lpszKey, rglpszSymbols, nSymbols);
  494.         AfxFormatStrings(strValue, lpszValue, rglpszSymbols, nSymbols);
  495.  
  496.         if ((hKeyRoot == HKEY_CLASSES_ROOT) && strKey.IsEmpty())
  497.         {
  498.             TRACE1("Warning: skipping empty key '%s'.\n", lpszKey);
  499.             continue;
  500.         }
  501.  
  502.         if (!bReplace)
  503.         {
  504.             TCHAR szBuffer[256];
  505.             LONG lSize = sizeof(szBuffer);
  506.             if (::RegQueryValue(hKeyRoot, strKey, szBuffer, &lSize) ==
  507.                 ERROR_SUCCESS)
  508.             {
  509. #ifdef _DEBUG
  510.                 if (strValue != szBuffer)
  511.                 {
  512.                     TRACE2("Warning: Leaving value '%s' for key '%s' in registry\n",
  513.                         szBuffer, (LPCTSTR)strKey);
  514.                     TRACE1("\tintended value was '%s'.\n", (LPCTSTR)strValue);
  515.                 }
  516. #endif
  517.                 continue;
  518.             }
  519.         }
  520.  
  521.         if (::RegSetValue(hKeyRoot, strKey, REG_SZ, strValue, lstrlen(strValue) * sizeof(TCHAR))
  522.             != ERROR_SUCCESS)
  523.         {
  524.             TRACE2("Error: failed setting key '%s' to value '%s'.\n",
  525.                 (LPCTSTR)strKey, (LPCTSTR)strValue);
  526.             bResult = FALSE;
  527.             break;
  528.         }
  529.     }
  530.  
  531.     if (hKeyTemp != NULL)
  532.         RegCloseKey(hKeyTemp);
  533.  
  534.     return bResult;
  535. }
  536.  
  537. /////////////////////////////////////////////////////////////////////////////
  538.