// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #include #define new DEBUG_NEW // from docmgr.cpp extern BOOL AFXAPI _AfxDeleteRegKey(LPCTSTR lpszKey); ////////////////////////////////////////////////////////////////////////////// // data for UpdateRegistry functionality // %1 - class ID // %2 - class name // %3 - SFN executable path // %4 - short type name // %5 - long type name // %6 - long application name // %7 - icon index // %8 - Creator(xxxxxxxx) [mac-only] // %8 - File extension Description [non-mac only] // %9 - (not used yet) [mac-only] // %9 - File extension *.TLA [non-mac only] // %A - (not used yet) #define NUM_REG_VARS 10 class _AFX_OLESYMBOLTABLE { protected: LPTSTR* m_strEntries; int m_nEntries; public: _AFX_OLESYMBOLTABLE(int nEntries); ~_AFX_OLESYMBOLTABLE(); LPCTSTR* GetArray() { return (LPCTSTR*) m_strEntries; } LPCTSTR GetAt(int nIndex) const; void SetAt(int nIndex, LPCTSTR pstr); LPCTSTR operator[](int nIndex) const { return GetAt(nIndex); } }; _AFX_OLESYMBOLTABLE::_AFX_OLESYMBOLTABLE(int nEntries) { m_strEntries = new LPTSTR[nEntries]; memset(m_strEntries, 0, sizeof(LPTSTR) * nEntries); m_nEntries = nEntries; } _AFX_OLESYMBOLTABLE::~_AFX_OLESYMBOLTABLE() { int nIndex; for (nIndex = 0; nIndex < m_nEntries; nIndex++) free(m_strEntries[nIndex]); delete [] m_strEntries; } void _AFX_OLESYMBOLTABLE::SetAt(int nIndex, LPCTSTR pstr) { ASSERT(nIndex < m_nEntries && nIndex >= 0); free(m_strEntries[nIndex]); m_strEntries[nIndex] = pstr ? _tcsdup(pstr) : NULL; } LPCTSTR _AFX_OLESYMBOLTABLE::GetAt(int nIndex) const { if (nIndex < m_nEntries || nIndex < 0) return m_strEntries[nIndex]; else return NULL; } static const TCHAR sz00[] = _T("%2\0") _T("%5"); static const TCHAR sz01[] = _T("%2\\CLSID\0") _T("%1"); static const TCHAR sz02[] = _T("%2\\Insertable\0") _T(""); static const TCHAR sz03[] = _T("%2\\protocol\\StdFileEditing\\verb\\0\0") _T("&Edit"); static const TCHAR sz04[] = _T("%2\\protocol\\StdFileEditing\\server\0") _T("%3"); static const TCHAR sz05[] = _T("CLSID\\%1\0") _T("%5"); static const TCHAR sz06[] = _T("CLSID\\%1\\ProgID\0") _T("%2"); static const TCHAR sz07[] = _T("CLSID\\%1\\InprocHandler32\0") _T("ole32.dll"); static const TCHAR sz08[] = _T("CLSID\\%1\\LocalServer32\0") _T("%3"); static const TCHAR sz09[] = _T("CLSID\\%1\\Verb\\0\0") _T("&Edit,0,2"); static const TCHAR sz10[] = _T("CLSID\\%1\\Verb\\1\0") _T("&Open,0,2"); static const TCHAR sz11[] = _T("CLSID\\%1\\Insertable\0") _T(""); static const TCHAR sz12[] = _T("CLSID\\%1\\AuxUserType\\2\0") _T("%4"); static const TCHAR sz13[] = _T("CLSID\\%1\\AuxUserType\\3\0") _T("%6"); static const TCHAR sz14[] = _T("CLSID\\%1\\DefaultIcon\0") _T("%3,%7"); static const TCHAR sz15[] = _T("CLSID\\%1\\MiscStatus\0") _T("32"); static const TCHAR sz16[] = _T("\0") _T(""); static const TCHAR sz17[] = _T("CLSID\\%1\\InProcServer32\0") _T("%3"); static const TCHAR sz18[] = _T("CLSID\\%1\\DocObject\0" _T("0")); // CLSIDDocObject static const TCHAR sz19[] = _T("%2\\DocObject\0" _T("0")); // ProgIDDocObject static const TCHAR sz20[] = _T("CLSID\\%1\\Printable\0"); // szPrintable static const TCHAR sz21[] = _T("CLSID\\%1\\DefaultExtension\0%9, %8"); // szDefaultExt // registration for OAT_INPLACE_SERVER static const LPCTSTR rglpszInPlaceRegister[] = { sz00, sz02, sz03, sz05, sz09, sz10, sz11, sz12, sz13, sz15, NULL }; // registration for OAT_SERVER static const LPCTSTR rglpszServerRegister[] = { sz00, sz02, sz03, sz05, sz09, sz11, sz12, sz13, sz15, NULL }; // registration for OAT_DOC_OBJECT_SERVER static const LPCTSTR rglpszDocObjectRegister[] = { sz00, sz02, sz03, sz05, sz09, sz10, sz11, sz12, sz13, sz15, sz18, sz19, sz20, NULL }; // overwrite entries for OAT_SERVER & OAT_INPLACE_SERVER static const LPCTSTR rglpszServerOverwrite[] = { sz01, sz04, sz06, sz07, sz08, sz14, NULL }; // overwrite entries for OAT_SERVER & OAT_INPLACE_SERVER (dll) static const LPCTSTR rglpszServerOverwriteDLL[] = { sz01, sz04, sz06, sz17, sz14, NULL }; // registration for OAT_CONTAINER static const LPCTSTR rglpszContainerRegister[] = { sz00, sz05, NULL }; // overwrite entries for OAT_CONTAINER static const LPCTSTR rglpszContainerOverwrite[] = { sz01, sz06, sz07, sz08, sz14, NULL }; // registration for OAT_DISPATCH_OBJECT static const LPCTSTR rglpszDispatchRegister[] = { sz00, sz05, NULL }; // overwrite entries for OAT_DISPATCH_OBJECT static const LPCTSTR rglpszDispatchOverwrite[] = { sz01, sz06, sz07, sz08, NULL }; // overwrite entries for OAT_DISPATCH_OBJECT (dll) static const LPCTSTR rglpszDispatchOverwriteDLL[] = { sz01, sz06, sz17, NULL }; // overwrite entries for OAT_DOC_OBJECT_SERVER static const LPCTSTR rglpszDocObjectOverwrite[] = { sz01, sz04, sz06, sz07, sz08, sz14, sz21, NULL }; struct STANDARD_ENTRY { const LPCTSTR* rglpszRegister; const LPCTSTR* rglpszOverwrite; }; static const STANDARD_ENTRY rgStdEntries[] = { { rglpszInPlaceRegister, rglpszServerOverwrite }, { rglpszServerRegister, rglpszServerOverwrite }, { rglpszContainerRegister, rglpszContainerOverwrite }, { rglpszDispatchRegister, rglpszDispatchOverwrite }, { rglpszDocObjectRegister, rglpszDocObjectOverwrite }, }; static const STANDARD_ENTRY rgStdEntriesDLL[] = { { rglpszInPlaceRegister, rglpszServerOverwriteDLL }, { rglpszServerRegister, rglpszServerOverwriteDLL }, { rglpszContainerRegister, rglpszContainerOverwrite }, { rglpszDispatchRegister, rglpszDispatchOverwriteDLL }, { rglpszDocObjectRegister, rglpszDocObjectOverwrite }, }; ///////////////////////////////////////////////////////////////////////////// // Special registration for apps that wish not to use REGLOAD AFX_STATIC BOOL AFXAPI _AfxOleMakeSymbolTable(_AFX_OLESYMBOLTABLE& refTable, REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName, LPCTSTR lpszLongTypeName, int nIconIndex, LPCTSTR lpszFilterName, LPCTSTR lpszFilterExt) { // 0 - class ID // 1 - class name // 2 - SFN executable path // 3 - short type name // 4 - long type name // 5 - long application name // 6 - icon index // 7 - Creator(xxxxxxxx) [Mac only] // 8 - Creator(xxxxxxxx) [mac-only] // 9 - Filter description // convert the CLSID to a string LPTSTR lpszClassID = NULL; LPOLESTR lpOleStr; if(SUCCEEDED(::StringFromCLSID(clsid, &lpOleStr))) { lpszClassID = TASKSTRINGOLE2T(lpOleStr); } if (lpszClassID == NULL) { TRACE(traceOle, 0, "Warning: StringFromCLSID failed in AfxOleRegisterServerName --\n"); TRACE(traceOle, 0, "\tperhaps AfxOleInit() has not been called.\n"); return FALSE; } refTable.SetAt(0, lpszClassID); refTable.SetAt(1, lpszClassName); // free memory for class ID ASSERT(lpszClassID != NULL); CoTaskMemFree(lpszClassID); // get path name to server CString strPathName; AfxGetModuleFileName(AfxGetInstanceHandle(), strPathName); CString strPathNameQuoted; strPathNameQuoted = "\""; strPathNameQuoted += strPathName; strPathNameQuoted += "\""; refTable.SetAt(2, strPathNameQuoted); // fill in rest of symbols refTable.SetAt(3, lpszShortTypeName); refTable.SetAt(4, lpszLongTypeName); refTable.SetAt(5, AfxGetAppName()); // will usually be long, readable name CString strIconIndex; if (nIconIndex != 0) { HICON hIcon = ::ExtractIcon(AfxGetInstanceHandle(), strPathName, nIconIndex); if (hIcon != NULL) DestroyIcon(hIcon); else nIconIndex = 0; // couldn't find specified icon so use default } strIconIndex.Format(_T("%d"), nIconIndex); refTable.SetAt(6, strIconIndex); refTable.SetAt(7, lpszFilterName); CString strFileExtension; if (lpszFilterExt != NULL && *lpszFilterExt != 0) { // use file extension provided strFileExtension = lpszFilterExt; } else { // otherwise, try to find the extension from the description // parse the actual extension (eg "*.TLA") from the // filter name (eg, "Three Letter Acronym Files (*.TLA)") strFileExtension = lpszFilterName; int nBeginning = strFileExtension.Find('('); if (nBeginning == -1) strFileExtension.Empty(); else { strFileExtension = strFileExtension.Mid(1+nBeginning); nBeginning = strFileExtension.Find('.'); if (nBeginning == -1) strFileExtension.Empty(); else { strFileExtension = strFileExtension.Mid(nBeginning); int nEnd = strFileExtension.Find(')'); if (nEnd == -1) strFileExtension.Empty(); else strFileExtension = strFileExtension.Left(nEnd); } } } refTable.SetAt(8, strFileExtension); return TRUE; } BOOL AFXAPI AfxOleRegisterServerClass( REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName, LPCTSTR lpszLongTypeName, OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister, LPCTSTR* rglpszOverwrite, int nIconIndex, LPCTSTR lpszFilterName) { return AfxOleRegisterServerClass(clsid, lpszClassName, lpszShortTypeName, lpszLongTypeName, nAppType, rglpszRegister, rglpszOverwrite, nIconIndex, lpszFilterName, NULL); } BOOL AFXAPI AfxOleRegisterServerClass( REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName, LPCTSTR lpszLongTypeName, OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister, LPCTSTR* rglpszOverwrite, int nIconIndex, LPCTSTR lpszFilterName, LPCTSTR lpszFilterExt) { ASSERT(AfxIsValidString(lpszClassName)); ASSERT(AfxIsValidString(lpszShortTypeName)); ASSERT(*lpszShortTypeName != 0); ASSERT(AfxIsValidString(lpszLongTypeName)); ASSERT(*lpszLongTypeName != 0); ASSERT(nAppType == OAT_INPLACE_SERVER || nAppType == OAT_SERVER || nAppType == OAT_CONTAINER || nAppType == OAT_DISPATCH_OBJECT || nAppType == OAT_DOC_OBJECT_SERVER); ASSERT(nAppType >= 0 && nAppType < _countof(rgStdEntries)); // use standard registration entries if non given if (rglpszRegister == NULL) rglpszRegister = (LPCTSTR*)rgStdEntries[nAppType].rglpszRegister; if (rglpszOverwrite == NULL) { // DLL contexts have special strings if (!afxContextIsDLL) rglpszOverwrite = (LPCTSTR*)rgStdEntries[nAppType].rglpszOverwrite; else rglpszOverwrite = (LPCTSTR*)rgStdEntriesDLL[nAppType].rglpszOverwrite; } _AFX_OLESYMBOLTABLE table(NUM_REG_VARS); if (!_AfxOleMakeSymbolTable(table, clsid, lpszClassName, lpszShortTypeName, lpszLongTypeName, nIconIndex, lpszFilterName, lpszFilterExt)) { return FALSE; } // protect against registering an invalid DocObject server ASSERT(nAppType != OAT_DOC_OBJECT_SERVER || (AtlStrLen(table.GetAt(8)) != 0 && lstrcmp(table.GetAt(8), _T(".*")) != 0)); // update the registry with helper function BOOL bResult; bResult = AfxOleRegisterHelper(rglpszRegister, table.GetArray(), NUM_REG_VARS, FALSE); if (bResult && rglpszOverwrite != NULL) { bResult = AfxOleRegisterHelper(rglpszOverwrite, table.GetArray(), NUM_REG_VARS, TRUE); } // free memory for class ID return bResult; } BOOL AFXAPI AfxOleUnregisterServerClass( REFCLSID clsid, LPCTSTR lpszClassName, LPCTSTR lpszShortTypeName, LPCTSTR lpszLongTypeName, OLE_APPTYPE nAppType, LPCTSTR* rglpszRegister, LPCTSTR* rglpszOverwrite) { if (nAppType < 0 || nAppType >= _countof(rgStdEntries)) { return FALSE; } // use standard registration entries if non given if (rglpszRegister == NULL) rglpszRegister = (LPCTSTR*)rgStdEntries[nAppType].rglpszRegister; if (rglpszOverwrite == NULL) { // DLL contexts have special strings if (!afxContextIsDLL) rglpszOverwrite = (LPCTSTR*)rgStdEntries[nAppType].rglpszOverwrite; else rglpszOverwrite = (LPCTSTR*)rgStdEntriesDLL[nAppType].rglpszOverwrite; } _AFX_OLESYMBOLTABLE table(NUM_REG_VARS); if (!_AfxOleMakeSymbolTable(table, clsid, lpszClassName, lpszShortTypeName, lpszLongTypeName, 0, NULL, NULL)) { return FALSE; } // clean up the the registry with helper function BOOL bResult; bResult = AfxOleUnregisterHelper(rglpszRegister, table.GetArray(), NUM_REG_VARS); if (bResult && rglpszOverwrite != NULL) { bResult = AfxOleUnregisterHelper(rglpszOverwrite, table.GetArray(), NUM_REG_VARS); } return bResult; } // removes key/value pairs from system registry BOOL AFXAPI AfxOleUnregisterHelper(LPCTSTR const* rglpszRegister, LPCTSTR const* rglpszSymbols, int nSymbols, HKEY hKeyRoot /* = HKEY_CLASSES_ROOT */) { ASSERT(rglpszRegister != NULL); ASSERT(nSymbols == 0 || rglpszSymbols != NULL); CString strKey; CString strValue; // keeping a key open makes this go a bit faster HKEY hKeyTemp = NULL; if (hKeyRoot == HKEY_CLASSES_ROOT) { AfxRegOpenKeyEx(HKEY_CLASSES_ROOT, _T("CLSID"), 0, KEY_READ, &hKeyTemp); } #pragma warning (suppress: 6387) // Constructor throws with null, suppress warning ::ATL::CRegKey rkTemp(hKeyTemp); BOOL bResult = TRUE; while (*rglpszRegister != NULL) { LPCTSTR lpszKey = *rglpszRegister++; if ((hKeyRoot == HKEY_CLASSES_ROOT) && (*lpszKey == '\0')) continue; AfxFormatStrings(strKey, lpszKey, rglpszSymbols, nSymbols); if ((hKeyRoot == HKEY_CLASSES_ROOT) && strKey.IsEmpty()) { TRACE(traceOle, 0, _T("Warning: skipping empty key '%Ts'.\n"), lpszKey); continue; } _AfxDeleteRegKey(strKey); } return bResult; } // writes key/value pairs to system registry BOOL AFXAPI AfxOleRegisterHelper(LPCTSTR const* rglpszRegister, LPCTSTR const* rglpszSymbols, int nSymbols, BOOL bReplace, HKEY hKeyRoot /* = HKEY_CLASSES_ROOT */) { ASSERT(rglpszRegister != NULL); ASSERT(nSymbols == 0 || rglpszSymbols != NULL); CString strKey; CString strValue; // keeping a key open makes this go a bit faster HKEY hKeyTemp = NULL; if (hKeyRoot == HKEY_CLASSES_ROOT) { AfxRegOpenKeyEx(HKEY_CLASSES_ROOT, _T("CLSID"), 0, KEY_READ, &hKeyTemp); } #pragma warning (suppress: 6387) // Constructor throws with null, suppress warning ::ATL::CRegKey rkTemp(hKeyTemp); BOOL bResult = TRUE; while (*rglpszRegister != NULL) { LPCTSTR lpszKey = *rglpszRegister++; if ((hKeyRoot == HKEY_CLASSES_ROOT) && (*lpszKey == '\0')) continue; LPCTSTR lpszValue = lpszKey + AtlStrLen(lpszKey) + 1; AfxFormatStrings(strKey, lpszKey, rglpszSymbols, nSymbols); AfxFormatStrings(strValue, lpszValue, rglpszSymbols, nSymbols); if ((hKeyRoot == HKEY_CLASSES_ROOT) && strKey.IsEmpty()) { TRACE(traceOle, 0, _T("Warning: skipping empty key '%Ts'.\n"), lpszKey); continue; } if (!bReplace) { TCHAR szBuffer[256]; LONG lSize = sizeof(szBuffer); if (AfxRegQueryValue(hKeyRoot, strKey, szBuffer, &lSize) == ERROR_SUCCESS) { #ifdef _DEBUG if (strValue != szBuffer) { TRACE(traceOle, 0, _T("Warning: Leaving value '%Ts' for key '%Ts' in registry\n"), szBuffer, (LPCTSTR)strKey); TRACE(traceOle, 0, _T("\tintended value was '%Ts'.\n"), (LPCTSTR)strValue); } #endif continue; } } LONG lResult = AfxRegSetValue(hKeyRoot, strKey, REG_SZ, strValue, AtlStrLen(strValue) * sizeof(TCHAR)); if(lResult != ERROR_SUCCESS) { TRACE(traceOle, 0, _T("Error: failed setting key '%Ts' to value '%Ts'.\n"), (LPCTSTR)strKey, (LPCTSTR)strValue); if(lResult != ERROR_ACCESS_DENIED) { bResult = FALSE; } break; } } return bResult; } AFX_STATIC_DATA const TCHAR _afxPreviewHostCLSID [] = _T("{8895b1c6-b41f-4c1c-a562-0d564250836f}"); AFX_STATIC_DATA const TCHAR _afxThumbnailHostCLSID [] = _T("{E357FCCD-A995-4576-B01F-234630154E96}"); AFX_STATIC_DATA const TCHAR _afxPreviewHandlersRegPath [] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\PreviewHandlers"); AFX_STATIC_DATA const TCHAR _afxShellExFormat [] = _T("%Ts\\ShellEx\\%Ts"); AFX_STATIC_DATA const TCHAR _afxTreatmentValueName [] = _T("Treatment"); BOOL AFXAPI AfxRegisterPreviewHandler(LPCTSTR lpszCLSID, LPCTSTR lpszShortTypeName, LPCTSTR lpszFilterExt) { CString strData = lpszShortTypeName; strData.Append(_T(" Preview Handler")); CRegKey regPreviewHandlersKey(HKEY_LOCAL_MACHINE); regPreviewHandlersKey.Create(HKEY_LOCAL_MACHINE, _afxPreviewHandlersRegPath); if (regPreviewHandlersKey.SetStringValue(lpszCLSID, strData) != ERROR_SUCCESS) { TRACE(traceOle, 0, _T("Error: failed setting value '%Ts' for key HKEY_LOCAL_MACHINE\\'%Ts'.\n"), lpszCLSID, _afxPreviewHandlersRegPath); return FALSE; } CString strShellExKey; strShellExKey.Format(_afxShellExFormat, lpszFilterExt, _afxPreviewHostCLSID); CRegKey regKey(HKEY_CLASSES_ROOT); regKey.Create(HKEY_CLASSES_ROOT, strShellExKey); if (regKey.SetValue(NULL, REG_SZ, (LPCVOID)lpszCLSID, (ULONG)(AtlStrLen(lpszCLSID) * sizeof(TCHAR))) != ERROR_SUCCESS) { TRACE(traceOle, 0, _T("Error: failed setting value '%Ts' for key HKEY_CLASSES_ROOT\\'%Ts'.\n"), lpszCLSID, strShellExKey.GetString()); return FALSE; } return TRUE; } BOOL AFXAPI AfxUnRegisterPreviewHandler(LPCTSTR lpszCLSID) { CRegKey regKey(HKEY_LOCAL_MACHINE); if (regKey.Open (HKEY_LOCAL_MACHINE, _afxPreviewHandlersRegPath) == ERROR_SUCCESS) { regKey.DeleteValue (lpszCLSID); regKey.Close(); } if (regKey.Open(HKEY_CLASSES_ROOT, _T("CLSID")) == ERROR_SUCCESS) { regKey.RecurseDeleteKey(lpszCLSID); regKey.Close(); } return TRUE; } BOOL AFXAPI AfxRegisterThumbnailHandler(LPCTSTR lpszCLSID, LPCTSTR lpszFilterExt, DWORD nTreatment) { CString strShellExKey; strShellExKey.Format(_afxShellExFormat, lpszFilterExt, _afxThumbnailHostCLSID); CRegKey regKey(HKEY_CLASSES_ROOT); regKey.Create(HKEY_CLASSES_ROOT, strShellExKey); if (regKey.SetValue(NULL, REG_SZ, (LPCVOID) lpszCLSID, (ULONG)(AtlStrLen(lpszCLSID) * sizeof(TCHAR))) != ERROR_SUCCESS) { TRACE(traceOle, 0, _T("Error: failed setting value '%Ts' for key HKEY_CLASSES_ROOT\\'%Ts'.\n"), lpszCLSID, strShellExKey.GetString()); return FALSE; } else { regKey.Close (); regKey.Open(HKEY_CLASSES_ROOT, lpszFilterExt); // set Treatment value - default to 1. Other possible values advanced users can set calling this method directly regKey.SetValue(_T("Treatment"), REG_DWORD, (LPVOID)&nTreatment, sizeof(DWORD)); } return TRUE; } static TCHAR szApartment[] = _T("Apartment"); static TCHAR szBoth[] = _T("Both"); static TCHAR szFree[] = _T("Free"); BOOL AFXAPI AfxOleInprocRegisterHelper(HKEY hkeyProgID, HKEY hkeyClassID, int nRegFlags) { BOOL bSuccess = TRUE; if (nRegFlags & afxRegInsertable) { ASSERT(hkeyProgID != NULL); ::ATL::CRegKey hkeyProgIDInsertable; ::ATL::CRegKey hkeyClassIDInsertable; bSuccess = (hkeyProgIDInsertable.Create(hkeyProgID, _T("Insertable"), NULL, 0, KEY_READ | KEY_WRITE, NULL, NULL) == ERROR_SUCCESS) && (hkeyClassIDInsertable.Create(hkeyClassID, _T("Insertable"), NULL, 0, KEY_READ | KEY_WRITE, NULL, NULL) == ERROR_SUCCESS); } LPTSTR pstrThreadingModel = NULL; if (!bSuccess) goto Error; if (nRegFlags & afxRegApartmentThreading) pstrThreadingModel = szApartment; if (nRegFlags & afxRegFreeThreading) pstrThreadingModel = szFree; if ((nRegFlags & (afxRegFreeThreading | afxRegApartmentThreading)) == (afxRegFreeThreading | afxRegApartmentThreading)) { pstrThreadingModel = szBoth; } if (pstrThreadingModel != NULL) { HKEY hkeyInprocServer32; bSuccess = (::RegOpenKeyExW(hkeyClassID, L"InprocServer32", 0, KEY_WRITE, &hkeyInprocServer32) == ERROR_SUCCESS); if (bSuccess) { ASSERT(hkeyInprocServer32 != NULL); bSuccess = (::RegSetValueEx(hkeyInprocServer32, _T("ThreadingModel"), 0, REG_SZ, (const BYTE*) pstrThreadingModel, (static_cast(AtlStrLen(pstrThreadingModel))+1) * sizeof(TCHAR)) == ERROR_SUCCESS); ::RegCloseKey(hkeyInprocServer32); } else { if (!afxContextIsDLL) { bSuccess = TRUE; //ignore failure to find InprocServer32 in exe context. } } } if (bSuccess) { return TRUE; } Error: // Cleanup any values set in the registry if (nRegFlags & afxRegInsertable) { RegDeleteKey(hkeyClassID, _T("Insertable")); RegDeleteKey(hkeyProgID, _T("Insertable")); } return bSuccess; } /////////////////////////////////////////////////////////////////////////////