//+---------------------------------------------------------------------------- // // Windows NT Directory Service Property Pages // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2001 // // File: misc.cxx, this file is #include'd into the two dllmisc.cxx files. // // Contents: DS property pages class objects handler DLL fcns. Also, error // reporting, message, and miscelaneous functions. // // History: 10-May-01 EricB created // //----------------------------------------------------------------------------- #include "pch.h" #include "proppage.h" #include "objlist.h" #if defined(DSPROP_ADMIN) # include "chklist.h" # include "fpnw.h" #endif #include #include DECLARE_INFOLEVEL(DsProp); HINSTANCE g_hInstance = NULL; ULONG CDll::s_cObjs = 0; ULONG CDll::s_cLocks = 0; UINT g_uChangeMsg = 0; int g_iInstance = 0; #ifndef DSPROP_ADMIN CRITICAL_SECTION g_csNotifyCreate; #endif ULONG g_ulMemberFilterCount = DSPROP_MEMBER_FILTER_COUNT_DEFAULT; ULONG g_ulMemberQueryLimit = DSPROP_MEMBER_QUERY_LIMIT_DEFAULT; #define DIRECTORY_UI_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\Directory UI") #define MEMBER_QUERY_VALUE TEXT("GroupMemberFilterCount") #define MEMBER_LIMIT_VALUE TEXT("GroupMemberQueryLimit") #if defined(DSPROP_ADMIN) Cache g_FPNWCache; #endif HRESULT GlobalInit(void); void GlobalUnInit(void); void ReportErrorFallback(HWND hWndMsg, HRESULT hr = ERROR_SUCCESS) { ReportError( hr, 0, hWndMsg ); } //+---------------------------------------------------------------------------- // To set a non-default debug info level outside of the debugger, create the // below registry key and in it create a value whose name is the component's // debugging tag name (the "comp" parameter to the DECLARE_INFOLEVEL macro) and // whose data is the desired infolevel in REG_DWORD format. //----------------------------------------------------------------------------- #define SMDEBUGKEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AdminDebug" #ifndef DSPROP_ADMIN //+---------------------------------------------------------------------------- // // Class: CNotifyCreateCriticalSection // // Purpose: Prevents creation race conditions. Without this protection, // a second call to CNotifyObj::Create that comes in before the // first has created the hidden window will get NULL back from // FindSheetNoSetFocus and then go on to create a second hidden // window. // //----------------------------------------------------------------------------- CNotifyCreateCriticalSection::CNotifyCreateCriticalSection() { TRACE(CNotifyCreateCriticalSection, CNotifyCreateCriticalSection); EnterCriticalSection(&g_csNotifyCreate); }; CNotifyCreateCriticalSection::~CNotifyCreateCriticalSection() { TRACE(CNotifyCreateCriticalSection, ~CNotifyCreateCriticalSection); LeaveCriticalSection(&g_csNotifyCreate); }; #endif #define MAX_STRING 1024 //+---------------------------------------------------------------------------- // // Function: LoadStringToTchar // // Synopsis: Loads the given string into an allocated buffer that must be // caller freed using delete. // //----------------------------------------------------------------------------- BOOL LoadStringToTchar(int ids, PTSTR * pptstr) { TCHAR szBuf[MAX_STRING]; if (!LoadString(g_hInstance, ids, szBuf, MAX_STRING - 1)) { return FALSE; } *pptstr = new TCHAR[_tcslen(szBuf) + 1]; CHECK_NULL(*pptstr, return FALSE); _tcscpy(*pptstr, szBuf); return TRUE; } //+---------------------------------------------------------------------------- // Function: LoadStringReport // Purpose: attempts to load a string, returns FALSE and gives error message // if a failure occurs. //----------------------------------------------------------------------------- BOOL LoadStringReport(int ids, PTSTR ptz, int len, HWND hwnd) { if (!LoadString(g_hInstance, ids, ptz, len - 1)) { DWORD dwErr = GetLastError(); dspDebugOut((DEB_ERROR, "LoadString of %d failed with error %lu\n", ids, dwErr)); ReportError(dwErr, 0, hwnd); return FALSE; } return TRUE; } //+---------------------------------------------------------------------------- // // Function: LoadErrorMessage // // Synopsis: Attempts to get a user-friendly error message from the system. // //----------------------------------------------------------------------------- void LoadErrorMessage(HRESULT hr, int nStr, PTSTR* pptsz) // free with delete[] { dspAssert( NULL != pptsz && NULL == *pptsz ); PTSTR ptzFormat = NULL, ptzSysMsg; int cch; if (nStr) { LoadStringToTchar(nStr, &ptzFormat); } cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (PTSTR)&ptzSysMsg, 0, NULL); if (!cch) { // Try ADSI errors. // cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle(TEXT("activeds.dll")), hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (PTSTR)&ptzSysMsg, 0, NULL); } if (!cch) { PTSTR ptzMsgTemplate = NULL; BOOL fDelMsgTemplate = TRUE; LoadStringToTchar(IDS_DEFAULT_ERROR_MSG, &ptzMsgTemplate); if (NULL == ptzMsgTemplate) { ptzMsgTemplate = TEXT("The operation failed with error code %d (0x%08x)"); fDelMsgTemplate = FALSE; } *pptsz = new TCHAR[ lstrlen(ptzMsgTemplate)+10 ]; dspAssert( NULL != *pptsz ); if (NULL != *pptsz) { wsprintf(*pptsz, ptzMsgTemplate, hr, hr); } if (fDelMsgTemplate) { delete ptzMsgTemplate; } } else { PTSTR ptzMsg; BOOL fDelMsg = FALSE; if (ptzFormat) { ptzMsg = new TCHAR[lstrlen(ptzFormat) + lstrlen(ptzSysMsg) + 1]; if (ptzMsg) { wsprintf(ptzMsg, ptzFormat, ptzSysMsg); fDelMsg = TRUE; } else { ptzMsg = ptzSysMsg; } } else { ptzMsg = ptzSysMsg; } *pptsz = new TCHAR[ lstrlen(ptzMsg)+1 ]; if (NULL != *pptsz) { lstrcpy( *pptsz, ptzMsg ); } dspAssert( NULL != *pptsz ); LocalFree(ptzSysMsg); if (fDelMsg) { delete[] ptzMsg; } if (ptzFormat) { delete ptzFormat; } } } //+---------------------------------------------------------------------------- // // Function: CheckADsError // // Synopsis: Checks the result code from an ADSI call. // // Returns: TRUE if no error. // //----------------------------------------------------------------------------- BOOL CheckADsError(HRESULT * phr, BOOL fIgnoreAttrNotFound, PSTR file, int line, HWND hWnd) { if (SUCCEEDED(*phr)) { return TRUE; } if (((E_ADS_PROPERTY_NOT_FOUND == *phr) || (HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) == *phr)) && fIgnoreAttrNotFound) { *phr = S_OK; return TRUE; } HWND hWndMsg = hWnd; if (!hWndMsg) { hWndMsg = GetDesktopWindow(); } DWORD dwErr; WCHAR wszErrBuf[MAX_PATH+1]; WCHAR wszNameBuf[MAX_PATH+1]; ADsGetLastError(&dwErr, wszErrBuf, MAX_PATH, wszNameBuf, MAX_PATH); if ((LDAP_RETCODE)dwErr == LDAP_NO_SUCH_ATTRIBUTE && fIgnoreAttrNotFound) { *phr = S_OK; return TRUE; } if (dwErr) { dspDebugOut((DEB_ERROR, "Extended Error 0x%x: %ws %ws <%s @line %d>.\n", dwErr, wszErrBuf, wszNameBuf, file, line)); ReportError(dwErr, IDS_ADS_ERROR_FORMAT, hWndMsg); } else { dspDebugOut((DEB_ERROR, "Error %08lx <%s @line %d>\n", *phr, file, line)); ReportError(*phr, IDS_ADS_ERROR_FORMAT, hWndMsg); } return FALSE; } //+---------------------------------------------------------------------------- // // Function: ReportError // // Synopsis: Displays an error using a user-friendly error message from the // system. // //----------------------------------------------------------------------------- void ReportErrorWorker(HWND hWnd, PTSTR ptzMsg) { HWND hWndMsg = hWnd; if (!hWndMsg) { hWndMsg = GetDesktopWindow(); } PTSTR ptzTitle = NULL; if (!LoadStringToTchar(IDS_MSG_TITLE, &ptzTitle)) { MessageBox(hWndMsg, ptzMsg, TEXT("Active Directory"), MB_OK | MB_ICONEXCLAMATION); return; } MessageBox(hWndMsg, ptzMsg, ptzTitle, MB_OK | MB_ICONEXCLAMATION); delete ptzTitle; } void ReportError(HRESULT hr, int nStr, HWND hWnd) { PTSTR ptzMsg = NULL; LoadErrorMessage(hr, nStr, &ptzMsg); //NTRAID#NTBUG9-573448-2002/03/10-jmessec Unlocalized text in code. if (NULL == ptzMsg) { TCHAR tzBuf[80]; wsprintf(tzBuf, TEXT("Active Directory failure with code '0x%08x'!"), hr); ReportErrorWorker( hWnd, tzBuf ); return; } ReportErrorWorker( hWnd, ptzMsg ); delete ptzMsg; } #if defined(DSADMIN) //+---------------------------------------------------------------------------- // // Function: SuperMsgBox // // Synopsis: Displays a message obtained from a string resource with // the parameters expanded. The error param, dwErr, if // non-zero, is converted to a string and becomes the first // replaceable param. // // Note: this function is UNICODE-only. // //----------------------------------------------------------------------------- int SuperMsgBox( HWND hWnd, // owning window. int nMessageId, // string resource ID of message. Must have replacable params to match nArguments. int nTitleId, // string resource ID of the title. If zero, uses IDS_MSG_TITLE. UINT ufStyle, // MessageBox flags. DWORD dwErr, // Error code, or zero if not needed. PVOID * rgpvArgs, // array of pointers/values for substitution in the nMessageId string. int nArguments, // count of pointers in string array. BOOL fTryADSiErrors,// If the failure is the result of an ADSI call, see if an ADSI extended error. PSTR szFile, // use the __FILE__ macro. ignored in retail build. int nLine // use the __LINE__ macro. ignored in retail build. ) { CStrW strTitle; PWSTR pwzMsg = NULL; strTitle.LoadString(g_hInstance, (nTitleId) ? nTitleId : IDS_MSG_TITLE); if (0 == strTitle.GetLength()) { ReportErrorFallback(hWnd, dwErr); return 0; } DspFormatMessage(nMessageId, dwErr, rgpvArgs, nArguments, fTryADSiErrors, &pwzMsg, hWnd); if (!pwzMsg) { return 0; } if (dwErr) { dspDebugOut((DEB_ERROR, "*+*+*+*+* Error <%s @line %d> -> 0x%08x, with message:\n\t%ws\n", szFile, nLine, dwErr, pwzMsg)); } else { dspDebugOut((DEB_ERROR, "*+*+*+*+* Message <%s @line %d>:\n\t%ws\n", szFile, nLine, pwzMsg)); } int retval = MessageBox(hWnd, pwzMsg, strTitle, ufStyle); LocalFree(pwzMsg); return retval; } //+---------------------------------------------------------------------------- // // Function: DspFormatMessage // // Synopsis: Loads a string resource with replaceable parameters and uses // FormatMessage to populate the replaceable params from the // argument array. If dwErr is non-zero, will load the system // description for that error and include it in the argument array. // //----------------------------------------------------------------------------- void DspFormatMessage( int nMessageId, // string resource ID of message. Must have replacable params to match nArguments. DWORD dwErr, // Error code, or zero if not needed. PVOID * rgpvArgs, // array of pointers/values for substitution in the nMessageId string. int nArguments, // count of pointers in string array. BOOL fTryADSiErrors,// If the failure is the result of an ADSI call, see if an ADSI extended error. PWSTR * ppwzMsg, // The returned error string, free with LocalFree. HWND hWnd // owning window, defaults to NULL. ) { int cch; PWSTR pwzSysErr = NULL; if (dwErr) { if (fTryADSiErrors) { DWORD dwStatus; WCHAR Buf1[256], Buf2[256]; ADsGetLastError(&dwStatus, Buf1, 256, Buf2, 256); dspDebugOut((DEB_ERROR, "ADsGetLastError returned status of %lx, error: %s, name %s\n", dwStatus, Buf1, Buf2)); if ((ERROR_INVALID_DATA != dwStatus) && (0 != dwStatus)) { dwErr = dwStatus; } } cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (PWSTR)&pwzSysErr, 0, NULL); if (!cch) { ReportErrorFallback(hWnd, dwErr); return; } } PWSTR * rgpvArguments = new PWSTR[nArguments + 1]; if (!rgpvArguments) { ReportErrorFallback(hWnd, dwErr); return; } int nOffset = 0; if (dwErr) { rgpvArguments[0] = pwzSysErr; nOffset = 1; } if (0 != nArguments) { CopyMemory(rgpvArguments + nOffset, rgpvArgs, nArguments * sizeof(PVOID)); } CStrW strFormat; strFormat.LoadString(g_hInstance, nMessageId); if (0 == strFormat.GetLength()) { ReportErrorFallback(hWnd, dwErr); // NTRAID#NTBUG9-693720-2002/09/03-sburns delete[] rgpvArguments; return; } cch = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, strFormat, 0, 0, (PWSTR)ppwzMsg, 0, (va_list *)rgpvArguments); if (pwzSysErr) LocalFree(pwzSysErr); if (!cch) { ReportErrorFallback(hWnd, dwErr); } delete[] rgpvArguments; return; } #endif // defined(DSADMIN) //+---------------------------------------------------------------------------- // // Function: ErrMsg // // Synopsis: Displays an error message obtained from a string resource. // //----------------------------------------------------------------------------- void ErrMsg(UINT MsgID, HWND hWndParam) { PTSTR ptz = TEXT(""); ErrMsgParam(MsgID, (LPARAM)ptz, hWndParam); } //+---------------------------------------------------------------------------- // // Function: ErrMsgParam // // Synopsis: Displays an error message obtained from a string resource with // an insertion parameter. // // Note: fixed-size stack buffers are used for the strings because trying to // report an allocation failure using dynamically allocated string // buffers is not a good idea. //----------------------------------------------------------------------------- void ErrMsgParam(UINT MsgID, LPARAM param, HWND hWndParam) { HWND hWnd; if (hWndParam == NULL) { hWnd = GetDesktopWindow(); } else { hWnd = hWndParam; } TCHAR szTitle[MAX_TITLE+1]; TCHAR szFormat[MAX_ERRORMSG+1]; TCHAR szMsg[MAX_ERRORMSG+1]; //NTRAID#NTBUG9-573453-2002/03/10-jmessec Why fall back to a message beep? //1) It's offensive in some languages (Japanese) //2) It's unhelpful...why did this thing just beep at me? //3) It's arbitrary...this particular failure beeps, but most in this code don't LOAD_STRING(IDS_MSG_TITLE, szTitle, MAX_TITLE, MessageBeep(MB_ICONEXCLAMATION); return); LOAD_STRING(MsgID, szFormat, MAX_ERRORMSG, MessageBeep(MB_ICONEXCLAMATION); return); //NTRAID#NTBUG9-573453-2002/03/10-jmessec Possible buffer overrun; not checking any lengths here wsprintf(szMsg, szFormat, param); MessageBox(hWnd, szMsg, szTitle, MB_OK | MB_ICONEXCLAMATION); } //+---------------------------------------------------------------------------- // // Function: MsgBox // // Synopsis: Displays a message obtained from a string resource. // //----------------------------------------------------------------------------- void MsgBox(UINT MsgID, HWND hWnd) { MsgBox2(MsgID, 0, hWnd); } //+---------------------------------------------------------------------------- // // Function: MsgBox2 // // Synopsis: Displays a message obtained from a string resource which is // assumed to have a replacable parameter where the InsertID // string is inserted. // //----------------------------------------------------------------------------- void MsgBox2(UINT MsgID, UINT InsertID, HWND hWnd) { CStr strInsert; PTSTR pszInsert = NULL; if (InsertID) { if (!strInsert.LoadString(g_hInstance, InsertID)) { REPORT_ERROR(GetLastError(), hWnd); return; } pszInsert = strInsert.GetBuffer(0); } MsgBoxParam(MsgID, (LPARAM)pszInsert, hWnd); } //+---------------------------------------------------------------------------- // // Function: MsgBoxParam // // Synopsis: Displays a message obtained from a string resource which is // assumed to have a replacable parameter where the argument // LPARAM is inserted. // //----------------------------------------------------------------------------- int MsgBoxParam(UINT MsgID, LPARAM lParam, HWND hWnd, int nStyle) { CStr strMsg, strFormat, strInsert, strTitle; if (!strTitle.LoadString(g_hInstance, IDS_MSG_TITLE)) { REPORT_ERROR(GetLastError(), hWnd); return IDCANCEL; } if (!strFormat.LoadString(g_hInstance, MsgID)) { REPORT_ERROR(GetLastError(), hWnd); return IDCANCEL; } strMsg.Format(strFormat, lParam); if (!nStyle) { nStyle = MB_OK | MB_ICONINFORMATION; } return MessageBox(hWnd, strMsg, strTitle, nStyle); } //+---------------------------------------------------------------------------- // // DLL functions // //----------------------------------------------------------------------------- //+---------------------------------------------------------------------------- // // Function: DllMain // // Synopsis: Provide a DllMain for Win32 // // Arguments: hInstance - HANDLE to this dll // dwReason - Reason this function was called. Can be // Process/Thread Attach/Detach. // // Returns: BOOL - TRUE if no error, FALSE otherwise // // History: 24-May-95 EricB created. // //----------------------------------------------------------------------------- extern "C" BOOL DllMain(HINSTANCE hInstance, DWORD dwReason, PVOID) { switch (dwReason) { case DLL_PROCESS_ATTACH: dspDebugOut((DEB_ITRACE, "DllMain: DLL_PROCESS_ATTACH\n")); // // Get instance handle // g_hInstance = hInstance; // // Disable thread notification from OS // DisableThreadLibraryCalls(hInstance); HRESULT hr; // // Initialize the global values. // hr = GlobalInit(); if (FAILED(hr)) { ERR_OUT("GlobalInit", hr); return FALSE; } LinkWindow_RegisterClass (); break; case DLL_PROCESS_DETACH: LinkWindow_UnregisterClass (hInstance); dspDebugOut((DEB_ITRACE, "DllMain: DLL_PROCESS_DETACH\n")); GlobalUnInit(); break; } return(TRUE); } //+---------------------------------------------------------------------------- // // Function: DllGetClassObject // // Synopsis: Creates a class factory for the requested object. // // Arguments: [cid] - the requested class object // [iid] - the requested interface // [ppvObj] - returned pointer to class object // // Returns: HRESULTS // //----------------------------------------------------------------------------- STDAPI DllGetClassObject(REFCLSID cid, REFIID iid, void **ppvObj) { IUnknown *pUnk = NULL; HRESULT hr = S_OK; for (int i = 0; i < g_DsPPClasses.cClasses; i++) { if (cid == *g_DsPPClasses.rgpClass[i]->pcid) { pUnk = CDsPropPagesHostCF::Create(g_DsPPClasses.rgpClass[i]); if (pUnk != NULL) { hr = pUnk->QueryInterface(iid, ppvObj); pUnk->Release(); } else { return E_OUTOFMEMORY; } return hr; } } return E_NOINTERFACE; } //+---------------------------------------------------------------------------- // // Function: DllCanUnloadNow // // Synopsis: Indicates whether the DLL can be removed if there are no // objects in existence. // // Returns: S_OK or S_FALSE // //----------------------------------------------------------------------------- STDAPI DllCanUnloadNow(void) { dspDebugOut((DEB_ITRACE, "DllCanUnloadNow: CDll::CanUnloadNow()? %s\n", (CDll::CanUnloadNow() == S_OK) ? "TRUE" : "FALSE")); return CDll::CanUnloadNow(); } TCHAR const c_szServerType[] = TEXT("InProcServer32"); TCHAR const c_szThreadModel[] = TEXT("ThreadingModel"); TCHAR const c_szThreadModelValue[] = TEXT("Apartment"); //+---------------------------------------------------------------------------- // // Function: DllRegisterServer // // Synopsis: Adds entries to the system registry. // // Returns: S_OK or error code. // // Notes: The keys look like this: // // HKC\CLSID\clsid REG_SZ name.progid // \InPropServer32 : REG_SZ : adprop.dll/dsprop.dll // ThreadingModel : REG_SZ : Apartment //----------------------------------------------------------------------------- STDAPI DllRegisterServer(void) { HRESULT hr = S_OK; HKEY hKeyCLSID, hKeyDsPPClass, hKeySvr; long lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_WRITE, &hKeyCLSID); if (lRet != ERROR_SUCCESS) { dspDebugOut((DEB_ITRACE, "RegOpenKeyEx failed: %d", lRet)); return (HRESULT_FROM_WIN32(lRet)); } LPOLESTR pszCLSID; PTSTR ptzCLSID; DWORD dwDisposition; for (int i = 0; i < g_DsPPClasses.cClasses; i++) { hr = StringFromCLSID(*g_DsPPClasses.rgpClass[i]->pcid, &pszCLSID); if (FAILED(hr)) { DBG_OUT("StringFromCLSID failed"); continue; } if (!UnicodeToTchar(pszCLSID, &ptzCLSID)) { DBG_OUT("Memory Allocation failure!"); CoTaskMemFree(pszCLSID); hr = E_OUTOFMEMORY; continue; } CoTaskMemFree(pszCLSID); lRet = RegCreateKeyEx(hKeyCLSID, ptzCLSID, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyDsPPClass, &dwDisposition); delete ptzCLSID; if (lRet != ERROR_SUCCESS) { dspDebugOut((DEB_ITRACE, "RegCreateKeyEx failed: %d", lRet)); hr = HRESULT_FROM_WIN32(lRet); continue; } TCHAR szProgID[MAX_PATH]; _tcscpy(szProgID, c_szDsProppagesProgID); _tcscat(szProgID, g_DsPPClasses.rgpClass[i]->szProgID); lRet = RegSetValueEx(hKeyDsPPClass, NULL, 0, REG_SZ, (CONST BYTE *)szProgID, sizeof(TCHAR) * (static_cast(_tcslen(szProgID) + 1))); if (lRet != ERROR_SUCCESS) { RegCloseKey(hKeyDsPPClass); dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet)); hr = HRESULT_FROM_WIN32(lRet); continue; } lRet = RegCreateKeyEx(hKeyDsPPClass, c_szServerType, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeySvr, &dwDisposition); RegCloseKey(hKeyDsPPClass); if (lRet != ERROR_SUCCESS) { dspDebugOut((DEB_ITRACE, "RegCreateKeyEx failed: %d", lRet)); hr = HRESULT_FROM_WIN32(lRet); continue; } lRet = RegSetValueEx(hKeySvr, NULL, 0, REG_SZ, (CONST BYTE *)c_szDsProppagesDllName, sizeof(TCHAR) * (static_cast(_tcslen(c_szDsProppagesDllName) + 1))); if (lRet != ERROR_SUCCESS) { dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet)); hr = HRESULT_FROM_WIN32(lRet); } lRet = RegSetValueEx(hKeySvr, c_szThreadModel, 0, REG_SZ, (CONST BYTE *)c_szThreadModelValue, sizeof(TCHAR) * (static_cast(_tcslen(c_szThreadModelValue) + 1))); if (lRet != ERROR_SUCCESS) { dspDebugOut((DEB_ITRACE, "RegSetValueEx failed: %d", lRet)); hr = HRESULT_FROM_WIN32(lRet); } RegCloseKey(hKeySvr); } RegCloseKey(hKeyCLSID); return hr; } //+---------------------------------------------------------------------------- // // Function: DllUnregisterServer // // Synopsis: Removes the entries from the system registry. // // Returns: S_OK or S_FALSE // // Notes: The keys look like this: // // HKC\CLSID\clsid REG_SZ name.progid // \InPropServer32 : REG_SZ : dsprop.dll // ThreadingModel : REG_SZ : Apartment //----------------------------------------------------------------------------- STDAPI DllUnregisterServer(void) { HRESULT hr = S_OK; HKEY hKeyCLSID, hKeyClass; long lRet = RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, KEY_ALL_ACCESS, &hKeyCLSID); if (lRet != ERROR_SUCCESS) { dspDebugOut((DEB_ITRACE, "RegOpenKeyEx failed: %d", lRet)); return (HRESULT_FROM_WIN32(lRet)); } LPOLESTR pszCLSID; PTSTR ptzCLSID; for (int i = 0; i < g_DsPPClasses.cClasses; i++) { hr = StringFromCLSID(*g_DsPPClasses.rgpClass[i]->pcid, &pszCLSID); if (FAILED(hr)) { DBG_OUT("StringFromCLSID failed"); continue; } if (!UnicodeToTchar(pszCLSID, &ptzCLSID)) { DBG_OUT("CLSID string memory allocation failure!"); CoTaskMemFree(pszCLSID); hr = E_OUTOFMEMORY; continue; } CoTaskMemFree(pszCLSID); lRet = RegOpenKeyEx(hKeyCLSID, ptzCLSID, 0, KEY_ALL_ACCESS, &hKeyClass); if (lRet != ERROR_SUCCESS) { dspDebugOut((DEB_ITRACE, "Failed to open key %S\n", ptzCLSID)); lRet = ERROR_SUCCESS; hr = S_FALSE; } else { lRet = RegDeleteKey(hKeyClass, c_szServerType); RegCloseKey(hKeyClass); dspDebugOut((DEB_ITRACE, "Delete of key %S returned code %d\n", c_szServerType, lRet)); if (lRet != ERROR_SUCCESS) { lRet = ERROR_SUCCESS; hr = S_FALSE; } } lRet = RegDeleteKey(hKeyCLSID, ptzCLSID); dspDebugOut((DEB_ITRACE, "Delete of key %S returned code %d\n", ptzCLSID, lRet)); delete ptzCLSID; if (lRet != ERROR_SUCCESS) { lRet = ERROR_SUCCESS; hr = S_FALSE; } } RegCloseKey(hKeyCLSID); return hr; } //+---------------------------------------------------------------------------- // // Function: GlobalInit // // Synopsis: Sets up the global environment. // // Returns: S_OK or S_FALSE // //----------------------------------------------------------------------------- HRESULT GlobalInit(void) { #if defined(DSADMIN) // // Enable themed common controls. // if (!SHFusionInitializeFromModule(g_hInstance)) { dspDebugOut((DEB_ITRACE, "SHFusionInitializeFromModule failed with error %d\n", GetLastError())); } #endif // // Initialize common controls // InitCommonControls(); INITCOMMONCONTROLSEX icce = {0}; icce.dwSize = sizeof(icce); icce.dwICC = ICC_DATE_CLASSES | ICC_WIN95_CLASSES; if (!InitCommonControlsEx(&icce)) { dspDebugOut((DEB_ITRACE, "InitCommonControlsEx failed with error %d\n", GetLastError())); } #if defined(DSPROP_ADMIN) // // Register the "CHECKLIST" control // RegisterCheckListWndClass(); // // Register the Credential Manager control. // CredUIInitControls(); #endif #ifndef DSPROP_ADMIN // // Register the window class for the notification window. // RegisterNotifyClass(); #endif // // Register the attribute-changed message. // g_uChangeMsg = RegisterWindowMessage(DSPROP_ATTRCHANGED_MSG); CHECK_NULL(g_uChangeMsg, ;); // // Major cheesy hack to allow locating windows that are unique to this // instance (since hInstance is invariant). // srand((unsigned)time(NULL)); g_iInstance = rand(); #ifndef DSPROP_ADMIN ExceptionPropagatingInitializeCriticalSection(&g_csNotifyCreate); #endif HRESULT hr = CheckRegisterClipFormats(); dspAssert( SUCCEEDED(hr) ); // If found, read the value of the Member class query clause count and // number-of-members limit. // HKEY hKey; LONG lRet; lRet = RegOpenKeyEx(HKEY_CURRENT_USER, DIRECTORY_UI_KEY, 0, KEY_READ, &hKey); if (lRet == ERROR_SUCCESS) { DWORD dwSize = sizeof(ULONG); RegQueryValueEx(hKey, MEMBER_QUERY_VALUE, NULL, NULL, (LPBYTE)&g_ulMemberFilterCount, &dwSize); RegQueryValueEx(hKey, MEMBER_LIMIT_VALUE, NULL, NULL, (LPBYTE)&g_ulMemberQueryLimit, &dwSize); RegCloseKey(hKey); } dspDebugOut((DEB_ITRACE | DEB_USER14, "GroupMemberFilterCount set to %d\n", g_ulMemberFilterCount)); dspDebugOut((DEB_ITRACE | DEB_USER14, "GroupMemberQueryLimit set to %d\n", g_ulMemberQueryLimit)); return S_OK; } //+---------------------------------------------------------------------------- // // Function: GlobalUnInit // // Synopsis: Do resource freeing. // //----------------------------------------------------------------------------- inline void GlobalUnInit(void) { #if defined(DSPROP_ADMIN) if (!g_FPNWCache.empty()) { for (Cache::iterator i = g_FPNWCache.begin(); i != g_FPNWCache.end(); i++) { PFPNWCACHE pElem = (*i).second; if (pElem) { if (pElem->pwzPDCName) { LocalFree(pElem->pwzPDCName); } LocalFree(pElem); } } g_FPNWCache.clear(); } #endif g_ClassIconCache.ClearAll(); #ifndef DSPROP_ADMIN DeleteCriticalSection(&g_csNotifyCreate); #endif #if defined(DSADMIN) SHFusionUninitialize(); #endif } //+---------------------------------------------------------------------------- // // Debugging routines. // //----------------------------------------------------------------------------- #if DBG == 1 ////////////////////////////////////////////////////////////////////////////// unsigned long SmAssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP; BOOL fInfoLevelInit = FALSE; ////////////////////////////////////////////////////////////////////////////// static int _cdecl w4dprintf(const char *format, ...); static int _cdecl w4smprintf(const char *format, va_list arglist); ////////////////////////////////////////////////////////////////////////////// static int _cdecl w4dprintf(const char *format, ...) { int ret; va_list va; va_start(va, format); ret = w4smprintf(format, va); va_end(va); return ret; } static int _cdecl w4smprintf(const char *format, va_list arglist) { int ret; char szMessageBuf[DSP_DEBUG_BUF_SIZE]; ret = wvnsprintfA(szMessageBuf, DSP_DEBUG_BUF_SIZE - 1, format, arglist); OutputDebugStringA(szMessageBuf); return ret; } //+--------------------------------------------------------------------------- // // Function: _asdprintf // // Synopsis: Calls smprintf to output a formatted message. // // History: 18-Oct-91 vich Created // //---------------------------------------------------------------------------- inline void __cdecl _asdprintf( char const *pszfmt, ...) { va_list va; va_start(va, pszfmt); smprintf(DEB_FORCE, "Assert", pszfmt, va); va_end(va); } //+--------------------------------------------------------------------------- // // Function: SmAssertEx, private // // Synopsis: Display assertion information // // Effects: Called when an assertion is hit. // //---------------------------------------------------------------------------- void APINOT SmAssertEx( char const * szFile, int iLine, char const * szMessage) { if (SmAssertLevel & ASSRT_MESSAGE) { DWORD tid = GetCurrentThreadId(); _asdprintf("%s File: %s Line: %u, thread id %d\n", szMessage, szFile, iLine, tid); } if (SmAssertLevel & ASSRT_POPUP) { int id = PopUpError(szMessage,iLine,szFile); if (id == IDCANCEL) { DebugBreak(); } } else if (SmAssertLevel & ASSRT_BREAK) { DebugBreak(); } } //+------------------------------------------------------------ // Function: PopUpError // // Synopsis: Displays a dialog box using provided text, // and presents the user with the option to // continue or cancel. // // Arguments: // szMsg -- The string to display in main body of dialog // iLine -- Line number of file in error // szFile -- Filename of file in error // // Returns: // IDCANCEL -- User selected the CANCEL button // IDOK -- User selected the OK button //------------------------------------------------------------- int APINOT PopUpError( char const *szMsg, int iLine, char const *szFile) { int id; static char szAssertCaption[128]; static char szModuleName[MAX_PATH+1] = {0}; DWORD tid = GetCurrentThreadId(); DWORD pid = GetCurrentProcessId(); char * pszModuleName; if (GetModuleFileNameA(NULL, szModuleName, MAX_PATH)) { pszModuleName = szModuleName; } else { pszModuleName = "Unknown"; } //NTRAID#NTBUG9-573457-2002/03/10-jmessec Unlocalized text wsprintfA(szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d", pszModuleName, szFile, iLine, pid, tid); id = MessageBoxA(NULL, szMsg, szAssertCaption, MB_SETFOREGROUND | MB_DEFAULT_DESKTOP_ONLY | MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL); // // If id == 0, then an error occurred. There are two possibilities // that can cause the error: Access Denied, which means that this // process does not have access to the default desktop, and everything // else (usually out of memory). // #ifdef DSPROP_ADMIN if (0 == id) { if (GetLastError() == ERROR_ACCESS_DENIED) { // // Retry this one with the SERVICE_NOTIFICATION flag on. That // should get us to the right desktop. // id = MessageBoxA(NULL, szMsg, szAssertCaption, MB_SETFOREGROUND | MB_SERVICE_NOTIFICATION | MB_TASKMODAL | MB_ICONEXCLAMATION | MB_OKCANCEL); } } #endif return id; } //+------------------------------------------------------------ // Function: smprintf // // Synopsis: Prints debug output using a pointer to the // variable information. Used primarily by the // xxDebugOut macros // // Arguements: // ulCompMask -- Component level mask used to determine // output ability // pszComp -- String const of component prefix. // ppszfmt -- Pointer to output format and data // //------------------------------------------------------------- void APINOT smprintf( unsigned long ulCompMask, char const *pszComp, char const *ppszfmt, va_list pargs) { if ((ulCompMask & DEB_FORCE) == DEB_FORCE || (ulCompMask | DEF_INFOLEVEL)) { DWORD tid = GetCurrentThreadId(); DWORD pid = GetCurrentProcessId(); if ((DEF_INFOLEVEL & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT) { if (! (ulCompMask & DEB_NOCOMPNAME)) { w4dprintf("%x.%03x> %s: ", pid, tid, pszComp); } SYSTEMTIME st; GetLocalTime(&st); w4dprintf("%02d:%02d:%02d ", st.wHour, st.wMinute, st.wSecond); w4smprintf(ppszfmt, pargs); } } } //+---------------------------------------------------------------------------- // Function: CheckInit // // Synopsis: Performs debugging library initialization // including reading the registry for the desired infolevel // //----------------------------------------------------------------------------- void APINOT CheckInit(char * pInfoLevelString, unsigned long * pulInfoLevel) { HKEY hKey; LONG lRet; DWORD dwSize; if (fInfoLevelInit) return; fInfoLevelInit = TRUE; lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, SMDEBUGKEY, 0, KEY_READ, &hKey); if (lRet == ERROR_SUCCESS) { dwSize = sizeof(unsigned long); lRet = RegQueryValueExA(hKey, pInfoLevelString, NULL, NULL, (LPBYTE)pulInfoLevel, &dwSize); if (lRet != ERROR_SUCCESS) { *pulInfoLevel = DEF_INFOLEVEL; } RegCloseKey(hKey); } } #endif // DBG == 1 // This wrapper function required to make prefast shut up when we are // initializing a critical section in a constructor. void ExceptionPropagatingInitializeCriticalSection(LPCRITICAL_SECTION critsec) { __try { ::InitializeCriticalSection(critsec); } // // propagate the exception to our caller. // __except (EXCEPTION_CONTINUE_SEARCH) { } } //+---------------------------------------------------------------------------- // // Function: GetFilterEscapedValue // // Synopsis: This will take any value that is to be used in an LDAP search // filter and make sure that the special characters are escaped // per RFC 2254 // //----------------------------------------------------------------------------- void GetFilterEscapedValue(PCWSTR value, CStrW& filterEscapedValue) { if (!value) { return; } filterEscapedValue.Empty(); PCWSTR current = value; while (current && *current != L'\0') { switch (*current) { case L'*': filterEscapedValue += L"\\2a"; break; case L'(': filterEscapedValue += L"\\28"; break; case L')': filterEscapedValue += L"\\29"; break; case L'\\': filterEscapedValue += L"\\5c"; break; default: filterEscapedValue += *current; break; } current++; } }