//+------------------------------------------------------------------------- // // Windows NT Directory Service Administration SnapIn // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1999 // // File: dssnap.cpp // // Contents: DS App // // History: 02-Oct-96 WayneSc Created // 06-Mar-97 EricB - added Property Page Extension support // 24-Jul-97 Dan Morin - Integrated "Generic Create" wizard // //-------------------------------------------------------------------------- #include "stdafx.h" #include "resource.h" #include "util.h" #include "uiutil.h" #include "dsutil.h" #include "dssnap.h" #include "ContextMenu.h" #include "DataObj.h" #include "dsctx.h" #include "DSdirect.h" #include "dsdlgs.h" #include "DSEvent.h" #include "dsfilter.h" #include "dsthread.h" #include "fsmoui.h" #include "helpids.h" #include "newobj.h" // CNewADsObjectCreateInfo #include "query.h" #include "queryui.h" #include "querysup.h" #include "rename.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define STRING_LEN (32 * sizeof(OLECHAR)) extern LPWSTR g_lpszLoggedInUser; #define INITGUID #include #include const wchar_t* SNAPIN_INTERNAL = L"DS_ADMIN_INTERNAL"; // Define the profiling statics IMPLEMENT_PROFILING; ////////////////////////////////////////////////////////////////////////////////// // standard attributes array (for queries) const INT g_nStdCols = 8; const LPWSTR g_pStandardAttributes[g_nStdCols] = {L"ADsPath", L"name", L"displayName", L"objectClass", L"groupType", L"description", L"userAccountControl", L"systemFlags"}; extern const INT g_nADsPath = 0; extern const INT g_nName = 1; extern const INT g_nDisplayName = 2; extern const INT g_nObjectClass = 3; extern const INT g_nGroupType = 4; extern const INT g_nDescription = 5; extern const INT g_nUserAccountControl = 6; extern const INT g_nSystemFlags = 7; /////////////////////////////////////////////////////////////////////////////////// HRESULT WINAPI CDsAdminModule::UpdateRegistryCLSID(const CLSID& clsid, BOOL bRegister) { static const WCHAR szIPS32[] = _T("InprocServer32"); static const WCHAR szCLSID[] = _T("CLSID"); static const WCHAR szThreadingModel[] = _T("ThreadingModel"); static const WCHAR szThreadModelValue[] = _T("Both"); HRESULT hRes = S_OK; LPOLESTR lpOleStrCLSIDValue; ::StringFromCLSID(clsid, &lpOleStrCLSIDValue); CRegKey key; if (bRegister) { LONG lRes = key.Open(HKEY_CLASSES_ROOT, szCLSID); if (lRes == ERROR_SUCCESS) { lRes = key.Create(key, lpOleStrCLSIDValue); if (lRes == ERROR_SUCCESS) { WCHAR szModule[_MAX_PATH]; ::GetModuleFileName(m_hInst, szModule, _MAX_PATH); lRes = key.SetKeyValue(szIPS32, szModule); if (lRes == ERROR_SUCCESS) { lRes = key.Open(key, szIPS32); if (lRes == ERROR_SUCCESS) { key.SetValue(szThreadModelValue, szThreadingModel); } } } } if (lRes != ERROR_SUCCESS) hRes = HRESULT_FROM_WIN32(lRes); } else { key.Attach(HKEY_CLASSES_ROOT); if (key.Open(key, szCLSID) == ERROR_SUCCESS) key.RecurseDeleteKey(lpOleStrCLSIDValue); } ::CoTaskMemFree(lpOleStrCLSIDValue); return hRes; } CDsAdminModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_DSSnapin, CDSSnapin) OBJECT_ENTRY(CLSID_DSSnapinEx, CDSSnapinEx) OBJECT_ENTRY(CLSID_SiteSnapin, CSiteSnapin) OBJECT_ENTRY(CLSID_DSAboutSnapin, CDSSnapinAbout) OBJECT_ENTRY(CLSID_SitesAboutSnapin, CSitesSnapinAbout) OBJECT_ENTRY(CLSID_DSContextMenu, CDSContextMenu) OBJECT_ENTRY(CLSID_DsAdminCreateObj, CDsAdminCreateObj) OBJECT_ENTRY(CLSID_DsAdminChooseDCObj, CDsAdminChooseDCObj) OBJECT_ENTRY(CLSID_DSAdminQueryUIForm, CQueryFormBase) END_OBJECT_MAP() CCommandLineOptions _commandLineOptions; class CDSApp : public CWinApp { public: virtual BOOL InitInstance(); virtual int ExitInstance(); }; CDSApp theApp; BOOL CDSApp::InitInstance() { _Module.Init(ObjectMap, m_hInstance); InitGroupTypeStringTable(); _commandLineOptions.Initialize(); return CWinApp::InitInstance(); } int CDSApp::ExitInstance() { _Module.Term(); return CWinApp::ExitInstance(); } ///////////////////////////////////////////////////////////////////////////// // DLL Entry Point #if (FALSE) extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) { if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok } #endif ///////////////////////////////////////////////////////////////////////////// // Used to determine whether the DLL can be unloaded by OLE STDAPI DllCanUnloadNow(void) { #ifdef _USE_MFC AFX_MANAGE_STATE(AfxGetStaticModuleState()); return (AfxDllCanUnloadNow()==S_OK && _Module.GetLockCount()==0) ? S_OK : S_FALSE; #else return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; #endif } ///////////////////////////////////////////////////////////////////////////// // Returns a class factory to create an object of the requested type STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { return _Module.GetClassObject(rclsid, riid, ppv); } LPCTSTR g_cszBasePath = _T("Software\\Microsoft\\MMC\\SnapIns"); LPCTSTR g_cszNameString = _T("NameString"); LPCTSTR g_cszNameStringIndirect = _T("NameStringIndirect"); LPCTSTR g_cszProvider = _T("Provider"); LPCTSTR g_cszVersion = _T("Version"); LPCTSTR g_cszAbout = _T("About"); LPCTSTR g_cszStandAlone = _T("StandAlone"); LPCTSTR g_cszExtension = _T("Extension"); LPCTSTR g_cszNodeTypes = _T("NodeTypes"); LPCTSTR GUIDToCString(REFGUID guid, CString & str) { USES_CONVERSION; OLECHAR lpszGUID[128]; int nChars = ::StringFromGUID2(guid, lpszGUID, 128); LPTSTR lpString = OLE2T(lpszGUID); LPTSTR lpGUID = str.GetBuffer(nChars); if (lpGUID) { CopyMemory(lpGUID, lpString, nChars*sizeof(TCHAR)); str.ReleaseBuffer(); } return str; } HRESULT _RegisterSnapinHelper(CRegKey& rkBase, REFGUID guid, REFGUID about, UINT nNameStringID, BOOL bStandalone, CRegKey& rkCLSID) { HRESULT hr = S_OK; CString strKey; AFX_MANAGE_STATE(AfxGetStaticModuleState()); try { CString str; BOOL result; // Create snapin GUID key and set properties rkCLSID.Create(rkBase, GUIDToCString(guid, str)); result = str.LoadString (nNameStringID); rkCLSID.SetValue(str, g_cszNameString); // JonN 4/26/00 100624: MUI: MMC: Shared Folders snap-in // stores its display information in the registry { WCHAR szModule[_MAX_PATH]; ::GetModuleFileName(AfxGetInstanceHandle(), szModule, _MAX_PATH); str.Format( _T("@%s,-%d"), szModule, nNameStringID ); rkCLSID.SetValue(str, g_cszNameStringIndirect); } str.LoadString (IDS_SNAPIN_PROVIDER); rkCLSID.SetValue(str, g_cszProvider); rkCLSID.SetValue(CString(_T("1.0")), g_cszVersion); // Create "StandAlone" or "Extension" key CRegKey rkStandAloneOrExtension; rkStandAloneOrExtension.Create(rkCLSID, bStandalone ? g_cszStandAlone : g_cszExtension); rkCLSID.SetValue (GUIDToCString(about, str), g_cszAbout); } catch(CMemoryException * e) { e->Delete(); hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } catch(COleException * e) { e->Delete(); hr = SELFREG_E_CLASS; } return hr; } void _RegisterNodeTypes(CRegKey& rkCLSID, UINT) { // Create "NodeTypes" key CRegKey rkNodeTypes; rkNodeTypes.Create(rkCLSID, g_cszNodeTypes); // NodeTypes guids CString str; str.LoadString (IDS_SNAPIN_PROVIDER); CRegKey rkN1; rkN1.Create(rkNodeTypes, GUIDToCString(cDefaultNodeType, str)); } void _RegisterQueryForms() { PWSTR pszDSQueryCLSID = NULL; ::StringFromCLSID(CLSID_DsQuery, &pszDSQueryCLSID); ASSERT(pszDSQueryCLSID != NULL); if (pszDSQueryCLSID != NULL) { CString szForms = pszDSQueryCLSID; ::CoTaskMemFree(pszDSQueryCLSID); szForms = L"CLSID\\" + szForms; CRegKey rkCLSID_DSQUERY_FORM; LONG status = rkCLSID_DSQUERY_FORM.Open(HKEY_CLASSES_ROOT, szForms); if (status != ERROR_SUCCESS) { return; } CRegKey rkDSUIFormKey; status = rkDSUIFormKey.Create(rkCLSID_DSQUERY_FORM, L"Forms"); if (status == ERROR_SUCCESS) { PWSTR pszDSAFormCLSID = NULL; ::StringFromCLSID(CLSID_DSAdminQueryUIForm, &pszDSAFormCLSID); ASSERT(pszDSAFormCLSID != NULL); if (pszDSAFormCLSID != NULL) { CRegKey rkDSAdminFormKey; status = rkDSAdminFormKey.Create(rkDSUIFormKey, pszDSAFormCLSID); if (status == ERROR_SUCCESS) { rkDSAdminFormKey.SetValue(pszDSAFormCLSID, L"CLSID"); } ::CoTaskMemFree(pszDSAFormCLSID); } } } } HRESULT RegisterSnapin() { HRESULT hr = S_OK; CString strKey; AFX_MANAGE_STATE(AfxGetStaticModuleState()); try { CString str; CRegKey rkBase; INT status; status = rkBase.Open(HKEY_LOCAL_MACHINE, g_cszBasePath); if (status || !rkBase.m_hKey) return hr; // REGISTER DS ADMIN STANDALONE CRegKey rkCLSID_DS; hr = _RegisterSnapinHelper(rkBase, CLSID_DSSnapin, CLSID_DSAboutSnapin, IDS_DS_MANAGER, TRUE, rkCLSID_DS); if (SUCCEEDED(hr)) { _RegisterNodeTypes(rkCLSID_DS, IDS_DS_MANAGER); } // REGISTER DS ADMIN EXTENSION CRegKey rkCLSID_DS_EX; hr = _RegisterSnapinHelper(rkBase, CLSID_DSSnapinEx, GUID_NULL, IDS_DS_MANAGER_EX, FALSE, rkCLSID_DS_EX); if (SUCCEEDED(hr) && rkCLSID_DS_EX.m_hKey != NULL) { _RegisterNodeTypes(rkCLSID_DS_EX, IDS_DS_MANAGER_EX); } // REGISTER SITE ADMIN STANDALONE CRegKey rkCLSID_SITE; hr = _RegisterSnapinHelper(rkBase, CLSID_SiteSnapin, CLSID_SitesAboutSnapin, IDS_SITE_MANAGER, TRUE, rkCLSID_SITE); if (SUCCEEDED(hr) && rkCLSID_SITE.m_hKey != NULL) { _RegisterNodeTypes(rkCLSID_SITE, IDS_SITE_MANAGER); } // // Register dsquery forms extension // _RegisterQueryForms(); } catch(CMemoryException * e) { e->Delete(); hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } catch(COleException * e) { e->Delete(); hr = SELFREG_E_CLASS; } return hr; } HRESULT UnregisterSnapin() { HRESULT hr = S_OK; try { CRegKey rkBase; rkBase.Open(HKEY_LOCAL_MACHINE, g_cszBasePath); if (rkBase.m_hKey != NULL) { CString str; rkBase.RecurseDeleteKey(GUIDToCString(CLSID_DSSnapin, str)); rkBase.RecurseDeleteKey(GUIDToCString(CLSID_DSSnapinEx, str)); rkBase.RecurseDeleteKey(GUIDToCString(CLSID_SiteSnapin, str)); } } catch(CException * e) { DWORD err = ::GetLastError(); hr = HRESULT_FROM_WIN32(err); e->Delete(); } return hr; } ///////////////////////////////////////////////////////////////////////////// // DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void) { HRESULT hRes = S_OK; // registers objects hRes = _Module.RegisterServer(FALSE); if (FAILED(hRes)) return hRes; hRes = RegisterSnapin(); return hRes; } ///////////////////////////////////////////////////////////////////////////// // DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void) { _Module.UnregisterServer(); UnregisterSnapin(); return S_OK; } ///////////////////////////////////////////////////////////////////////////// // CTargetingInfo const DWORD CTargetingInfo::m_dwSaveDomainFlag = 0x1; #ifdef _MMC_ISNAPIN_PROPERTY // properties the snapin supports LPCWSTR g_szServer = L"Server"; LPCWSTR g_szDomain = L"Domain"; LPCWSTR g_szRDN = L"RDN"; HRESULT CTargetingInfo::InitFromSnapinProperties(long cProps, //property count MMC_SNAPIN_PROPERTY* pProps) //properties array { TRACE(L"CTargetingInfo::InitFromSnapinProperties()\n"); // loop through the list of properties and set the variables BOOL bDomainSpecified = FALSE; for (long k=0; k< cProps; k++) { if (!bDomainSpecified && (_wcsicmp(pProps[k].pszPropName, g_szServer) == 0)) { m_szStoredTargetName = pProps[k].varValue.bstrVal; } else if (_wcsicmp(pProps[k].pszPropName, g_szDomain) == 0) { // domain takes the precedence over server name bDomainSpecified = TRUE; m_szStoredTargetName = pProps[k].varValue.bstrVal; } else if (_wcsicmp(pProps[k].pszPropName, g_szRDN) == 0) { m_szRootRDN = pProps[k].varValue.bstrVal; } } // remove leading and trailing blanks m_szStoredTargetName.TrimLeft(); m_szStoredTargetName.TrimRight(); return S_OK; } #endif // _MMC_ISNAPIN_PROPERTY void CTargetingInfo::_InitFromCommandLine() { // get the command line switches /Domain or /Server LPCWSTR lpszDomainRoot = _commandLineOptions.GetDomainOverride(); LPCWSTR lpszServerName = _commandLineOptions.GetServerOverride(); // domain takes the precedence over server name m_szStoredTargetName = (lpszDomainRoot != NULL) ? lpszDomainRoot : lpszServerName; // remove leading and trailing blanks m_szStoredTargetName.TrimLeft(); m_szStoredTargetName.TrimRight(); m_szRootRDN = _commandLineOptions.GetRDNOverride(); } HRESULT CTargetingInfo::Load(IStream* pStm) { DWORD dwFlagsTemp; HRESULT hr = LoadDWordHelper(pStm, (DWORD*)&dwFlagsTemp); if (FAILED(hr)) return hr; if (dwFlagsTemp == 0) return S_OK; if (m_szStoredTargetName.IsEmpty()) { // no command line parameters: // read flags and string from stream m_dwFlags = dwFlagsTemp; hr = LoadStringHelper(m_szStoredTargetName, pStm); } else { // have command line parameters: // we do the load to preserve the loading sequence, // but we discard the results CString szThrowAway; hr = LoadStringHelper(szThrowAway, pStm); } return hr; } HRESULT CTargetingInfo::Save(IStream* pStm, LPCWSTR lpszCurrentTargetName) { HRESULT hr = SaveDWordHelper(pStm, m_dwFlags); if (FAILED(hr)) return hr; if (m_dwFlags == 0) return S_OK; CString szTemp = lpszCurrentTargetName; return SaveStringHelper(szTemp, pStm); } ///////////////////////////////////////////////////////////////////////////// // CIconManager HRESULT CIconManager::Init(IImageList* pScpImageList, SnapinType snapintype) { if (pScpImageList == NULL) return E_INVALIDARG; m_pScpImageList = pScpImageList; HRESULT hr; hr = _LoadIconFromResource( (snapintype == SNAPINTYPE_SITE) ? IDI_SITEREPL : IDI_DSADMIN, &m_iRootIconIndex); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; hr = _LoadIconFromResource( (snapintype == SNAPINTYPE_SITE) ? IDI_SITEREPL_ERR : IDI_DSADMIN_ERR, &m_iRootIconErrIndex); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; hr = _LoadIconFromResource(IDI_ICON_WAIT, &m_iWaitIconIndex); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; hr = _LoadIconFromResource(IDI_ICON_WARN, &m_iWarnIconIndex); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; hr = _LoadIconFromResource(IDI_FAVORITES, &m_iFavoritesIconIndex); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; hr = _LoadIconFromResource(IDI_QUERY, &m_iQueryIconIndex); ASSERT(SUCCEEDED(hr)); hr = _LoadIconFromResource(IDI_QUERY_INVALID, &m_iQueryInvalidIconIndex); ASSERT(SUCCEEDED(hr)); return hr; } HRESULT _SetIconHelper(IImageList* pImageList, HICON hiClass16, HICON hiClass32, int iIndex, BOOL bAdd32 = FALSE) { HRESULT hr = pImageList->ImageListSetIcon((LONG_PTR *)hiClass16, iIndex); if (SUCCEEDED(hr) && (hiClass32 != NULL)) { #ifdef ILSI_LARGE_ICON if (bAdd32) { HRESULT hr1 = pImageList->ImageListSetIcon((LONG_PTR *)hiClass32, ILSI_LARGE_ICON(iIndex)); ASSERT(SUCCEEDED(hr1)); } #endif } return hr; } HRESULT CIconManager::FillInIconStrip(IImageList* pImageList) { // cannot do this passing a scope pane image list interface ASSERT(m_pScpImageList != pImageList); HRESULT hr = S_OK; INT iTempIndex = _GetBaseIndex(); for (POSITION pos = m_IconInfoList.GetHeadPosition(); pos != NULL; ) { CIconInfo* pInfo = m_IconInfoList.GetNext(pos); hr = _SetIconHelper(pImageList, pInfo->m_hiClass16, pInfo->m_hiClass32, iTempIndex, TRUE); if (FAILED(hr)) break; iTempIndex++; } return hr; } HRESULT CIconManager::AddClassIcon(IN LPCWSTR lpszClass, IN MyBasePathsInfo* pPathInfo, IN DWORD dwFlags, INOUT int* pnIndex) { HICON hiClass16 = pPathInfo->GetIcon(lpszClass, dwFlags, 16,16); HICON hiClass32 = pPathInfo->GetIcon(lpszClass, dwFlags, 32,32); return AddIcon(hiClass16, hiClass32, pnIndex); } HRESULT CIconManager::AddIcon(IN HICON hiClass16, IN HICON hiClass32, INOUT int* pnIndex) { ASSERT(pnIndex != NULL); ASSERT(hiClass16 != NULL); ASSERT(m_pScpImageList != NULL); *pnIndex = -1; int iNextIcon = _GetNextFreeIndex(); HRESULT hr = _SetIconHelper(m_pScpImageList, hiClass16, hiClass32, iNextIcon); if (FAILED(hr)) return hr; CIconInfo* pInfo = new CIconInfo; if (pInfo) { pInfo->m_hiClass16 = hiClass16; pInfo->m_hiClass32 = hiClass32; m_IconInfoList.AddTail(pInfo); *pnIndex = iNextIcon; } return hr; } HRESULT CIconManager::_LoadIconFromResource(IN UINT nIconResID, INOUT int* pnIndex) { ASSERT(pnIndex != NULL); ASSERT(m_pScpImageList != NULL); HICON hIcon = ::LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(nIconResID)); ASSERT(hIcon != NULL); if (hIcon == NULL) return E_INVALIDARG; return AddIcon(hIcon, NULL, pnIndex); } ///////////////////////////////////////////////////////////////////////////// // CInternalFormatCracker HRESULT CInternalFormatCracker::Extract(LPDATAOBJECT lpDataObject) { _Free(); if (lpDataObject == NULL) return E_INVALIDARG; SMMCDataObjects * pDO = NULL; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { CDSDataObject::m_cfInternal, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; FORMATETC formatetc2 = { CDSDataObject::m_cfMultiSelDataObjs, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; HRESULT hr = lpDataObject->GetData(&formatetc2, &stgmedium); if (FAILED(hr)) { // Attempt to get data from the object do { hr = lpDataObject->GetData(&formatetc, &stgmedium); if (FAILED(hr)) break; m_pInternalFormat = reinterpret_cast(stgmedium.hGlobal); if (m_pInternalFormat == NULL) { if (SUCCEEDED(hr)) hr = E_FAIL; break; } } while (FALSE); return hr; } else { pDO = reinterpret_cast(stgmedium.hGlobal); for (UINT i = 0; i < pDO->count; i++) { hr = pDO->lpDataObject[i]->GetData(&formatetc, &stgmedium); if (FAILED(hr)) break; m_pInternalFormat = reinterpret_cast(stgmedium.hGlobal); if (m_pInternalFormat != NULL) break; } } return hr; } LPDATAOBJECT CInternalFormatCracker::ExtractMultiSelect(LPDATAOBJECT lpDataObject) { _Free(); if (lpDataObject == NULL) return NULL; SMMCDataObjects * pDO = NULL; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { CDSDataObject::m_cfMultiSelDataObjs, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; if (FAILED(lpDataObject->GetData(&formatetc, &stgmedium))) { return NULL; } else { pDO = reinterpret_cast(stgmedium.hGlobal); return pDO->lpDataObject[0]; //assume that ours is the 1st } } ///////////////////////////////////////////////////////////////////// // CObjectNamesFormatCracker CLIPFORMAT CObjectNamesFormatCracker::m_cfDsObjectNames = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSOBJECTNAMES); HRESULT CObjectNamesFormatCracker::Extract(LPDATAOBJECT lpDataObject) { _Free(); if (lpDataObject == NULL) return E_INVALIDARG; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { m_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; HRESULT hr = lpDataObject->GetData(&formatetc, &stgmedium); if (FAILED(hr)) { return hr; } m_pDsObjectNames = reinterpret_cast(stgmedium.hGlobal); if (m_pDsObjectNames == NULL) { if (SUCCEEDED(hr)) hr = E_FAIL; } return hr; } ///////////////////////////////////////////////////////////////////// // CDSNotifyHandlerManager typedef struct { DWORD cNotifyExtensions; // how many extension CLSIDs? CLSID aNotifyExtensions[1]; } DSCLASSNOTIFYINFO, * LPDSCLASSNOTIFYINFO; HRESULT DsGetClassNotifyInfo(IN MyBasePathsInfo* pBasePathInfo, OUT LPDSCLASSNOTIFYINFO* ppInfo) { static LPCWSTR lpszSettingsObjectClass = L"dsUISettings"; static LPCWSTR lpszSettingsObject = L"cn=DS-UI-Default-Settings"; static LPCWSTR lpszNotifyProperty = L"dsUIAdminNotification"; if ( (ppInfo == NULL) || (pBasePathInfo == NULL) ) return E_INVALIDARG; *ppInfo = NULL; // get the display specifiers locale container (e.g. 409) CComPtr spLocaleContainer; HRESULT hr = pBasePathInfo->GetDisplaySpecifier(NULL, IID_IADsContainer, (void**)&spLocaleContainer); if (FAILED(hr)) return hr; // bind to the settings object CComPtr spIDispatchObject; hr = spLocaleContainer->GetObject((LPWSTR)lpszSettingsObjectClass, (LPWSTR)lpszSettingsObject, &spIDispatchObject); if (FAILED(hr)) return hr; CComPtr spSettingsObject; hr = spIDispatchObject->QueryInterface(IID_IADs, (void**)&spSettingsObject); if (FAILED(hr)) return hr; // get multivaled property in string list form CComVariant var; CStringList stringList; hr = spSettingsObject->Get((LPWSTR)lpszNotifyProperty, &var); if (FAILED(hr)) return hr; hr = HrVariantToStringList(var, stringList); if (FAILED(hr)) return hr; size_t nCount = stringList.GetCount(); // allocate memory DWORD cbCount = sizeof(DSCLASSNOTIFYINFO); if (nCount>1) cbCount += static_cast((nCount-1)*sizeof(CLSID)); *ppInfo = (LPDSCLASSNOTIFYINFO)::LocalAlloc(LPTR, cbCount); if ((*ppInfo) == NULL) return E_OUTOFMEMORY; ZeroMemory(*ppInfo, cbCount); (*ppInfo)->cNotifyExtensions = 0; int* pArr = new int[nCount]; if (!pArr) { return E_OUTOFMEMORY; } CString szEntry, szIndex, szGUID; for (POSITION pos = stringList.GetHeadPosition(); pos != NULL; ) { szEntry = stringList.GetNext(pos); int nComma = szEntry.Find(L","); if (nComma == -1) continue; szIndex = szEntry.Left(nComma); int nIndex = _wtoi((LPCWSTR)szIndex); if (nIndex <= 0) continue; // allow from 1 up // strip leading and traling blanks szGUID = szEntry.Mid(nComma+1); szGUID.TrimLeft(); szGUID.TrimRight(); GUID* pGuid= &((*ppInfo)->aNotifyExtensions[(*ppInfo)->cNotifyExtensions]); hr = ::CLSIDFromString((LPWSTR)(LPCWSTR)szGUID, pGuid); if (SUCCEEDED(hr)) { pArr[(*ppInfo)->cNotifyExtensions] = nIndex; ((*ppInfo)->cNotifyExtensions)++; } } if (((*ppInfo)->cNotifyExtensions) > 1) { // need to sort by index in pArr while (TRUE) { BOOL bSwapped = FALSE; for (UINT k=1; k < ((*ppInfo)->cNotifyExtensions); k++) { if (pArr[k] < pArr[k-1]) { // swap int nTemp = pArr[k]; pArr[k] = pArr[k-1]; pArr[k-1] = nTemp; GUID temp = (*ppInfo)->aNotifyExtensions[k]; (*ppInfo)->aNotifyExtensions[k] = (*ppInfo)->aNotifyExtensions[k-1]; (*ppInfo)->aNotifyExtensions[k-1] = temp; bSwapped = TRUE; } } if (!bSwapped) break; } } delete[] pArr; pArr = 0; return S_OK; } HRESULT CDSNotifyHandlerManager::Init() { _Free(); // prepare for delayed initialization return S_OK; } HRESULT CDSNotifyHandlerManager::Load(MyBasePathsInfo* pBasePathInfo) { if (m_state != uninitialized) return S_OK; // already done, bail out // start the initialization process ASSERT(m_pInfoArr == NULL); m_state = noHandlers; LPDSCLASSNOTIFYINFO pInfo = NULL; HRESULT hr = DsGetClassNotifyInfo(pBasePathInfo, &pInfo); if (SUCCEEDED(hr) && (pInfo != NULL) && (pInfo->cNotifyExtensions > 0)) { m_nArrSize = pInfo->cNotifyExtensions; m_pInfoArr = new CDSNotifyHandlerInfo[m_nArrSize]; for (DWORD i=0; icNotifyExtensions; i++) { hr = ::CoCreateInstance(pInfo->aNotifyExtensions[i], NULL, CLSCTX_INPROC_SERVER, IID_IDsAdminNotifyHandler, (void**)(&m_pInfoArr[i].m_spIDsAdminNotifyHandler)); if (SUCCEEDED(hr) && m_pInfoArr[i].m_spIDsAdminNotifyHandler != NULL) { hr = m_pInfoArr[i].m_spIDsAdminNotifyHandler->Initialize(NULL, &(m_pInfoArr[i].m_nRegisteredEvents)); if (FAILED(hr) || m_pInfoArr[i].m_nRegisteredEvents == 0) { // release if init failed or not registered for any event m_pInfoArr[i].m_spIDsAdminNotifyHandler = NULL; } else { m_state = hasHandlers; } //if } //if } // for } // if if (pInfo != NULL) ::LocalFree(pInfo); return S_OK; } void CDSNotifyHandlerManager::Begin(ULONG uEvent, IDataObject* pArg1, IDataObject* pArg2) { ASSERT(m_state == hasHandlers); HRESULT hr; for (UINT i=0; iBegin( uEvent, pArg1, pArg2, &(m_pInfoArr[i].m_nFlags), &bstr); if (SUCCEEDED(hr) && (bstr != NULL) && (bstr[0] != NULL)) { // // extension accepted the notification // m_pInfoArr[i].m_bNeedsNotify = TRUE; m_pInfoArr[i].m_szDisplayString = bstr; } // // mark the extension with a pending transaction // on it. we will have to call End() // m_pInfoArr[i].m_bTransactionPending = TRUE; } //if } // for } void CDSNotifyHandlerManager::Notify(ULONG nItem, ULONG uEvent) { ASSERT(m_state == hasHandlers); HRESULT hr; for (UINT i=0; iNotify(nItem, m_pInfoArr[i].m_nFlags); } //if } // for } void CDSNotifyHandlerManager::End(ULONG uEvent) { ASSERT(m_state == hasHandlers); HRESULT hr; for (UINT i=0; iEnd(); // reset the state flags m_pInfoArr[i].m_bNeedsNotify = FALSE; m_pInfoArr[i].m_bTransactionPending = FALSE; m_pInfoArr[i].m_nFlags= 0; m_pInfoArr[i].m_szDisplayString.Empty(); } //if } // for } UINT CDSNotifyHandlerManager::NeedNotifyCount(ULONG uEvent) { ASSERT(m_state == hasHandlers); UINT iCount = 0; for (UINT i=0; iInsertString(iListBoxIndex, m_pInfoArr[i].m_szDisplayString); int nCheck = 0; if (m_pInfoArr[i].m_nFlags & DSA_NOTIFY_FLAG_ADDITIONAL_DATA) nCheck = 1; pCheckListBox->SetCheck(iListBoxIndex, nCheck); if (m_pInfoArr[i].m_nFlags & DSA_NOTIFY_FLAG_FORCE_ADDITIONAL_DATA) pCheckListBox->Enable(iListBoxIndex, FALSE); pCheckListBox->SetItemData(iListBoxIndex, (DWORD_PTR)(&m_pInfoArr[i])); iListBoxIndex++; } //if } // for } void CDSNotifyHandlerManager::ReadFromCheckListBox(CCheckListBox* pCheckListBox, ULONG) { ASSERT(m_state == hasHandlers); int nCount = pCheckListBox->GetCount(); ASSERT(nCount != LB_ERR); for (int i=0; i< nCount; i++) { int nCheck = pCheckListBox->GetCheck(i); CDSNotifyHandlerInfo* pInfo = (CDSNotifyHandlerInfo*) pCheckListBox->GetItemData(i); ASSERT(pInfo != NULL); if ((pInfo->m_nFlags & DSA_NOTIFY_FLAG_FORCE_ADDITIONAL_DATA) == 0) { if (nCheck == 0) pInfo->m_nFlags &= ~DSA_NOTIFY_FLAG_ADDITIONAL_DATA; else pInfo->m_nFlags |= DSA_NOTIFY_FLAG_ADDITIONAL_DATA; } } // for } ////////////////////////////////////////////////////////////////////// // IComponentData implementation // WARNING this ctor passes an incomplete "this" pointer to other ctors CDSComponentData::CDSComponentData() : m_pShlInit(NULL), m_pScope(NULL), m_pFrame(NULL) #ifdef _MMC_ISNAPIN_PROPERTY , m_pProperties(NULL) #endif //_MMC_ISNAPIN_PROPERTY { ExceptionPropagatingInitializeCriticalSection(&m_cs); m_ActiveDS = NULL; m_pClassCache = NULL; m_pQueryFilter = NULL; m_pFavoritesNodesHolder = NULL; m_pHiddenWnd = NULL; m_pBackgroundThreadInfo = new CBackgroundThreadInfo; m_pScpImageList = NULL; m_bRunAsPrimarySnapin = TRUE; m_bAddRootWhenExtended = FALSE; m_bDirty = FALSE; m_SerialNumber = 1000; // arbitrary starting point m_ColumnWidths[0] = DEFAULT_NAME_COL_WIDTH; m_ColumnWidths[1] = DEFAULT_TYPE_COL_WIDTH; m_ColumnWidths[2] = DEFAULT_DESC_COL_WIDTH; m_InitSuccess = FALSE; m_InitAttempted = FALSE; m_lpszSnapinHelpFile = NULL; } HRESULT CDSComponentData::FinalConstruct() { // This must be delayed until this ctor so that the virtual // callouts work propery // create and initialize hidden window m_pHiddenWnd = new CHiddenWnd(this); if (m_pHiddenWnd == NULL) return E_OUTOFMEMORY; if (!m_pHiddenWnd->Create()) { TRACE(_T("Failed to create hidden window\n")); ASSERT(FALSE); return E_FAIL; } // create directory object m_ActiveDS = new CDSDirect (this); if (m_ActiveDS == NULL) return E_OUTOFMEMORY; // create class cache m_pClassCache = new CDSCache; if (m_pClassCache == NULL) return E_OUTOFMEMORY; m_pClassCache->Initialize(QuerySnapinType(), GetBasePathsInfo(), TRUE); // create saved queries holder if (QuerySnapinType() == SNAPINTYPE_DS) { m_pFavoritesNodesHolder = new CFavoritesNodesHolder(); if (m_pFavoritesNodesHolder == NULL) return E_OUTOFMEMORY; // REVIEW_MARCOC_PORT this is just to test/demo // m_pFavoritesNodesHolder->BuildTestTree(_commandLineOptions.GetSavedQueriesXMLFile(), // QuerySnapinType()); // graft the subtree under the snapin root m_RootNode.GetFolderInfo()->AddNode(m_pFavoritesNodesHolder->GetFavoritesRoot()); } // create filter m_pQueryFilter = new CDSQueryFilter(); if (m_pQueryFilter == NULL) return E_OUTOFMEMORY; /* BUGBUG BUGBUG: this is a gross hack to get around a blunder in dsuiext.dll. in order to see get DS extension information, we MUST have USERDNSDOMAIN set in the environment */ { WCHAR * pszUDD = NULL; pszUDD = _wgetenv (L"USERDNSDOMAIN"); if (pszUDD == NULL) { _wputenv (L"USERDNSDOMAIN=not-present"); } } return S_OK; } void CDSComponentData::FinalRelease() { _DeleteHiddenWnd(); // Dump the profiling data DUMP_PROFILING_RESULTS; } CDSComponentData::~CDSComponentData() { TRACE(_T("~CDSComponentData entered...\n")); ::DeleteCriticalSection(&m_cs); ASSERT(m_pScope == NULL); if (m_pBackgroundThreadInfo != NULL) { delete m_pBackgroundThreadInfo; } // clean up the Class Cache if (m_pClassCache != NULL) { delete m_pClassCache; m_pClassCache = NULL; } // cleanup saved queries holder if (m_pFavoritesNodesHolder != NULL) { m_RootNode.GetFolderInfo()->RemoveNode(m_pFavoritesNodesHolder->GetFavoritesRoot()); delete m_pFavoritesNodesHolder; m_pFavoritesNodesHolder = NULL; } // clean up the ADSI interface if (m_ActiveDS != NULL) { delete m_ActiveDS; m_ActiveDS = NULL; } if (m_pShlInit) { m_pShlInit->Release(); m_pShlInit = NULL; } if (m_pScpImageList) { m_pScpImageList->Release(); m_pScpImageList = NULL; } if (m_pQueryFilter) { delete m_pQueryFilter; m_pQueryFilter = NULL; } if (g_lpszLoggedInUser != NULL) { delete[] g_lpszLoggedInUser; g_lpszLoggedInUser = NULL; } TRACE(_T("~CDSComponentData leaving...\n")); } HWND CDSComponentData::GetHiddenWindow() { ASSERT(m_pHiddenWnd != NULL); ASSERT(::IsWindow(m_pHiddenWnd->m_hWnd)); return m_pHiddenWnd->m_hWnd; } void CDSComponentData::_DeleteHiddenWnd() { if (m_pHiddenWnd == NULL) return; AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (m_pHiddenWnd->m_hWnd != NULL) { VERIFY(m_pHiddenWnd->DestroyWindow()); } delete m_pHiddenWnd; m_pHiddenWnd = NULL; } BOOL CDSComponentData::ExpandComputers() { Lock(); BOOL b = m_pQueryFilter->ExpandComputers(); Unlock(); return b; } BOOL CDSComponentData::IsAdvancedView() { return m_pQueryFilter->IsAdvancedView(); } BOOL CDSComponentData::ViewServicesNode() { return m_pQueryFilter->ViewServicesNode(); } class CLockHandler { public: CLockHandler(CDSComponentData* pCD) { m_pCD = pCD; m_pCD->Lock(); } ~CLockHandler() { m_pCD->Unlock(); } private: CDSComponentData* m_pCD; }; STDMETHODIMP CDSComponentData::Initialize(LPUNKNOWN pUnknown) { ASSERT(pUnknown != NULL); HRESULT hr; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // MMC should only call ::Initialize once! ASSERT(m_pScope == NULL); pUnknown->QueryInterface(IID_IConsoleNameSpace2, reinterpret_cast(&m_pScope)); // Get console's pre-registered clipboard formats hr = pUnknown->QueryInterface(IID_IConsole3, reinterpret_cast(&m_pFrame)); if (FAILED(hr)) { TRACE(TEXT("QueryInterface for IID_IConsole3 failed, hr: 0x%x\n"), hr); return hr; } // // Bind to the property sheet COM object at startup and hold its pointer // until shutdown so that its cache can live as long as us. // hr = CoCreateInstance(CLSID_DsPropertyPages, NULL, CLSCTX_INPROC_SERVER, IID_IShellExtInit, (void **)&m_pShlInit); if (FAILED(hr)) { TRACE(TEXT("CoCreateInstance on CLSID_DsPropertyPages failed, hr: 0x%x\n"), hr); return hr; } hr = m_pFrame->QueryScopeImageList (&m_pScpImageList); if (FAILED(hr)) { TRACE(TEXT("Query for ScopeImageList failed, hr: 0x%x\n"), hr); return hr; } hr = m_iconManager.Init(m_pScpImageList, QuerySnapinType()); if (FAILED(hr)) { TRACE(TEXT("m_iconManager.Init() failed, hr: 0x%x\n"), hr); return hr; } if (!_StartBackgroundThread()) return E_FAIL; m_pFrame->GetMainWindow(&m_hwnd); // NOTICE: we should initialize the filter only if the MyBasePathsInfo // initialization call has succeeded (need schema path for filtering). // In reality, we need the filter initialized for loading from a stream: // with a failure, this initialization is "wrong" because it has // bad naming context info, but we will re initalize when we get good // info through retargeting hr = m_pQueryFilter->Init(this); if (FAILED(hr)) return hr; return S_OK; } STDMETHODIMP CDSComponentData::CreateComponent(LPCOMPONENT* ppComponent) { ASSERT(ppComponent != NULL); CComObject* pObject; CComObject::CreateInstance(&pObject); ASSERT(pObject != NULL); // Store IComponentData pObject->SetIComponentData(this); return pObject->QueryInterface(IID_IComponent, reinterpret_cast(ppComponent)); } STDMETHODIMP CDSComponentData::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); ASSERT(m_pScope != NULL); HRESULT hr = S_FALSE; CUINode* pUINode = NULL; // Since it's my folder it has an internal format. // Design Note: for extension. I can use the fact, that the data object doesn't have // my internal format and I should look at the node type and see how to extend it. if (lpDataObject != NULL) { CInternalFormatCracker dobjCracker; if (FAILED(dobjCracker.Extract(lpDataObject))) { if ((event == MMCN_EXPAND) && (arg == TRUE) && !m_bRunAsPrimarySnapin) { // this is a namespace extension, need to add // the root of the snapin hr = _OnNamespaceExtensionExpand(lpDataObject, param); if (FAILED(hr)) { hr = S_FALSE; } return hr; } return S_OK; } // got a valid data object pUINode = dobjCracker.GetCookie(); } if (event == MMCN_PROPERTY_CHANGE) { TRACE(_T("CDSComponentData::Notify() - property change, pDataObj = 0x%08x, param = 0x%08x, arg = %d.\n"), lpDataObject, param, arg); if (param != 0) { hr = _OnPropertyChange((LPDATAOBJECT)param, TRUE); if (FAILED(hr)) { hr = S_FALSE; } return hr; } return S_FALSE; } if (pUINode == NULL) return S_FALSE; switch (event) { case MMCN_PRELOAD: { _OnPreload((HSCOPEITEM)arg); hr = S_OK; } break; case MMCN_EXPANDSYNC: { MMC_EXPANDSYNC_STRUCT* pExpandStruct = reinterpret_cast(param); if (pExpandStruct->bExpanding) { _OnExpand(pUINode, pExpandStruct->hItem,event); pExpandStruct->bHandled = TRUE; hr = S_OK; } } break; case MMCN_EXPAND: if (arg == TRUE) { // Show _OnExpand(pUINode,(HSCOPEITEM)param,event); hr = S_OK; } break; case MMCN_DELETE: { CDSUINode* pDSUINode = dynamic_cast(pUINode); if (pDSUINode == NULL) { hr = pUINode->Delete(this); } else { hr = _DeleteFromBackendAndUI(lpDataObject, pDSUINode); } if (FAILED(hr)) { hr = S_FALSE; } } break; case MMCN_RENAME: hr = _Rename (pUINode, (LPWSTR)param); if (FAILED(hr)) { hr = S_FALSE; } break; case MMCN_REFRESH: hr = Refresh (pUINode); if (FAILED(hr)) { hr = S_FALSE; } break; default: hr = S_FALSE; } return hr; } STDMETHODIMP CDSComponentData::Destroy() { // sever all ties with cookies having pending requests m_queryNodeTable.Reset(); // wait for all the threads to shut down. _ShutDownBackgroundThread(); // destroy the hidden window _DeleteHiddenWnd(); if (m_pScope) { m_pScope->Release(); m_pScope = NULL; } if (m_pFrame) { m_pFrame->Release(); m_pFrame = NULL; } #ifdef _MMC_ISNAPIN_PROPERTY if (m_pProperties) { m_pProperties->Release(); m_pProperties = NULL; } #endif //_MMC_ISNAPIN_PROPERTY return S_OK; } STDMETHODIMP CDSComponentData::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { ASSERT(ppDataObject != NULL); HRESULT hr; CUINode* pNode; CComObject* pObject; CComObject::CreateInstance(&pObject); ASSERT(pObject != NULL); if (pObject != NULL) { // Check to see if we have a valid cookie or we should use the snapin // cookie // pNode = reinterpret_cast(cookie); if (pNode == NULL) { pNode = &m_RootNode; } // Save cookie and type for delayed rendering pObject->SetType(type, QuerySnapinType()); pObject->SetComponentData(this); pObject->SetCookie(pNode); hr = pObject->QueryInterface(IID_IDataObject, reinterpret_cast(ppDataObject)); //TRACE(_T("xx.%03x> CDSComponentData::QueryDataObject (CDsDataObject 0x%x)\n"), // GetCurrentThreadId(), *ppDataObject); } else { hr = E_OUTOFMEMORY; } return hr; } STDMETHODIMP CDSComponentData::GetDisplayInfo(LPSCOPEDATAITEM scopeInfo) { CUINode* pNode = reinterpret_cast(scopeInfo->lParam); ASSERT(pNode != NULL); ASSERT(pNode->IsContainer()); if (scopeInfo->mask & SDI_STR) { #ifdef DBG BOOL bNoName = (pNode->GetParent() == &m_RootNode) && _commandLineOptions.IsNoNameCommandLine(); scopeInfo->displayname = bNoName ? L"" : const_cast(pNode->GetName()); #else scopeInfo->displayname = const_cast(pNode->GetName()); #endif } if (scopeInfo->mask & SDI_IMAGE) { scopeInfo->nImage = GetImage(pNode, FALSE); } if (scopeInfo->mask & SDI_OPENIMAGE) { scopeInfo->nOpenImage = GetImage(pNode, TRUE); } return S_OK; } /////////////////////////////////////////////////////////////////////////////// //// IPersistStream interface members STDMETHODIMP CDSComponentData::GetClassID(CLSID *pClassID) { ASSERT(pClassID != NULL); ASSERT(m_bRunAsPrimarySnapin); // Copy the CLSID for this snapin switch (QuerySnapinType()) { case SNAPINTYPE_DS: *pClassID = CLSID_DSSnapin; break; case SNAPINTYPE_DSEX: *pClassID = CLSID_DSSnapinEx; break; case SNAPINTYPE_SITE: *pClassID = CLSID_SiteSnapin; break; default: ASSERT(FALSE); return E_FAIL; } return S_OK; } STDMETHODIMP CDSComponentData::IsDirty() { ASSERT(m_bRunAsPrimarySnapin); m_pFrame->UpdateAllViews(NULL, NULL, DS_CHECK_COLUMN_WIDTHS); return m_bDirty ? S_OK : S_FALSE; } // IMPORTANT NOTICE: this value has to be bumped up EVERY time // a change is made to the stream format #define DS_STREAM_VERSION ((DWORD)0x08) #define DS_STREAM_BEFORE_SAVED_QUERIES ((DWORD)0x07) #define DS_STREAM_W2K_VERSION ((DWORD)0x07) STDMETHODIMP CDSComponentData::Load(IStream *pStm) { // serialization on extensions not supported if (!m_bRunAsPrimarySnapin) return E_FAIL; ASSERT(pStm); // read the version ## DWORD dwVersion; HRESULT hr = LoadDWordHelper(pStm, &dwVersion); // if ( FAILED(hr) ||(dwVersion != DS_STREAM_VERSION) ) if (FAILED(hr) || dwVersion < DS_STREAM_W2K_VERSION) return E_FAIL; // read targeting info hr = m_targetingInfo.Load(pStm); if (FAILED(hr)) return hr; // // Initialize the root from the target info so that columns // can be loaded from the DS // hr = _InitRootFromCurrentTargetInfo(); if (FAILED(hr)) return hr; // read filtering options hr = m_pQueryFilter->Load(pStm); if (FAILED(hr)) return hr; // read the class cache information hr = m_pClassCache->Load(pStm); if (FAILED(hr)) return hr; if (dwVersion > DS_STREAM_BEFORE_SAVED_QUERIES) { hr = m_pFavoritesNodesHolder->Load(pStm, this); if (FAILED(hr)) { return hr; } } m_bDirty = FALSE; // start clean return hr; } STDMETHODIMP CDSComponentData::Save(IStream *pStm, BOOL fClearDirty) { // serialization on extensions not supported if (!m_bRunAsPrimarySnapin) return E_FAIL; ASSERT(pStm); // write the version ## HRESULT hr = SaveDWordHelper(pStm, DS_STREAM_VERSION); if (FAILED(hr)) return hr; // save targeting info hr = m_targetingInfo.Save(pStm, GetBasePathsInfo()->GetDomainName()); if (FAILED(hr)) return hr; // save filtering options hr = m_pQueryFilter->Save(pStm); if (FAILED(hr)) return hr; // save the class cache information hr = m_pClassCache->Save(pStm); if (FAILED(hr)) return hr; if (QuerySnapinType() == SNAPINTYPE_DS) { // // Save the saved queries folder for dsadmin only // hr = m_pFavoritesNodesHolder->Save(pStm); if (FAILED(hr)) return hr; } if (fClearDirty) m_bDirty = FALSE; return hr; } STDMETHODIMP CDSComponentData::GetSizeMax(ULARGE_INTEGER *pcbSize) { ASSERT(pcbSize); ASSERT(FALSE); // // Arbitrary values but I don't think we ever get called // pcbSize->LowPart = 0xffff; pcbSize->HighPart= 0x0; return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IExtendPropertySheet Implementation //+---------------------------------------------------------------------------- // // Member: CDSComponentData::IExtendPropertySheet::CreatePropertyPages // // Synopsis: Called in response to a user click on the Properties context // menu item. // //----------------------------------------------------------------------------- STDMETHODIMP CDSComponentData::CreatePropertyPages(LPPROPERTYSHEETCALLBACK pCall, LONG_PTR lNotifyHandle, LPDATAOBJECT pDataObject) { CDSCookie* pCookie = NULL; TRACE(_T("xx.%03x> CDSComponentData::CreatePropertyPages()\n"), GetCurrentThreadId()); // // Validate Inputs // if (pCall == NULL) { return E_INVALIDARG; } AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = S_OK; CInternalFormatCracker dobjCracker; if (FAILED(dobjCracker.Extract(pDataObject))) { return E_NOTIMPL; } // // Pass the Notify Handle to the data object. // PROPSHEETCFG SheetCfg = {lNotifyHandle}; FORMATETC fe = {CDSDataObject::m_cfPropSheetCfg, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM sm = {TYMED_HGLOBAL, NULL, NULL}; sm.hGlobal = (HGLOBAL)&SheetCfg; pDataObject->SetData(&fe, &sm, FALSE); if (dobjCracker.GetCookieCount() > 1) // multiple selection { // // Pass a unique identifier to the data object // GUID guid; hr = ::CoCreateGuid(&guid); if (FAILED(hr)) { ASSERT(FALSE); return hr; } WCHAR pszGuid[40]; if (!::StringFromGUID2(guid, pszGuid, 40)) { ASSERT(FALSE); return E_FAIL; } FORMATETC multiSelectfe = {CDSDataObject::m_cfMultiSelectProppage, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM multiSelectsm = {TYMED_HGLOBAL, NULL, NULL}; multiSelectsm.hGlobal = (HGLOBAL)pszGuid; pDataObject->SetData(&multiSelectfe, &multiSelectsm, FALSE); hr = GetClassCache()->TabCollect_AddMultiSelectPropertyPages(pCall, lNotifyHandle, pDataObject, GetBasePathsInfo()); } else // single selection { CUINode* pUINode = dobjCracker.GetCookie(); if (pUINode == NULL) { return E_NOTIMPL; } CDSUINode* pDSUINode = dynamic_cast(pUINode); if (pDSUINode == NULL) { // // Delegate page creation to the node // return pUINode->CreatePropertyPages(pCall, lNotifyHandle, pDataObject, this); } pCookie = GetDSCookieFromUINode(pDSUINode); ASSERT(pCookie != NULL); CString szPath; GetBasePathsInfo()->ComposeADsIPath(szPath, pCookie->GetPath()); FORMATETC mfe = {CDSDataObject::m_cfMultiSelectProppage, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM msm = {TYMED_HGLOBAL, NULL, NULL}; msm.hGlobal = (HGLOBAL)(LPCWSTR)szPath; pDataObject->SetData(&mfe, &msm, FALSE); // // See if a sheet is already up for this object. // if (IsSheetAlreadyUp(pDataObject)) { return S_OK; } // // Initialize and create the pages. Create an instance of the // CDsPropertyPages object for each sheet because each sheet runs on its // own thread. // IShellExtInit * pShlInit; hr = CoCreateInstance(CLSID_DsPropertyPages, NULL, CLSCTX_INPROC_SERVER, IID_IShellExtInit, (void **)&pShlInit); if (FAILED(hr)) { TRACE(TEXT("CoCreateInstance on CLSID_DsPropertyPages failed, hr: 0x%x\n"), hr); return hr; } // // Initialize the sheet with the data object // hr = pShlInit->Initialize(NULL, pDataObject, 0); if (FAILED(hr)) { TRACE(TEXT("pShlInit->Initialize failed, hr: 0x%x\n"), hr); pShlInit->Release(); return hr; } IShellPropSheetExt * pSPSE; hr = pShlInit->QueryInterface(IID_IShellPropSheetExt, (void **)&pSPSE); pShlInit->Release(); if (FAILED(hr)) { TRACE(TEXT("pShlInit->QI for IID_IShellPropSheetExt failed, hr: 0x%x\n"), hr); return hr; } // // Add pages to the sheet // hr = pSPSE->AddPages(AddPageProc, (LPARAM)pCall); if (FAILED(hr)) { TRACE(TEXT("pSPSE->AddPages failed, hr: 0x%x\n"), hr); pSPSE->Release(); return hr; } pSPSE->Release(); } // REVIEW_MARCOC_PORT: need to clean up and leave the locking/unlocking // working for non DS property pages //_SheetLockCookie(pUINode); return hr; } //+---------------------------------------------------------------------------- // // Member: CDSComponentData::IExtendPropertySheet::QueryPagesFor // // Synopsis: Called before a context menu is posted. If we support a // property sheet for this object, then return S_OK. // //----------------------------------------------------------------------------- STDMETHODIMP CDSComponentData::QueryPagesFor(LPDATAOBJECT pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); TRACE(TEXT("CDSComponentData::QueryPagesFor().\n")); BOOL bHasPages = FALSE; // // Look at the data object and see if it an item in the scope pane. // CInternalFormatCracker dobjCracker; HRESULT hr = dobjCracker.Extract(pDataObject); if (FAILED(hr) || !dobjCracker.HasData()) { // // not internal format, not ours // return S_FALSE; } // // this is the MMC snapin wizard, we do not have one // if (dobjCracker.GetType() == CCT_SNAPIN_MANAGER) { return S_FALSE; } if (dobjCracker.GetCookieCount() > 1) // multiple selection { bHasPages = TRUE; } else // single selection { CUINode* pUINode = dobjCracker.GetCookie(); if (pUINode == NULL) { return S_FALSE; } bHasPages = pUINode->HasPropertyPages(pDataObject); } return (bHasPages) ? S_OK : S_FALSE; } //+---------------------------------------------------------------------------- // // Member: CDSComponentData::IComponentData::CompareObjects // // Synopsis: If the data objects belong to the same DS object, then return // S_OK. // //----------------------------------------------------------------------------- class CCompareCookieByDN { public: CCompareCookieByDN(LPCWSTR lpszDN) { m_lpszDN = lpszDN;} bool operator()(CDSUINode* pUINode) { CDSCookie* pCookie = GetDSCookieFromUINode(pUINode); if (pCookie == NULL) { return FALSE; } return (_wcsicmp(m_lpszDN, pCookie->GetPath()) == 0); } private: LPCWSTR m_lpszDN; }; STDMETHODIMP CDSComponentData::CompareObjects(LPDATAOBJECT pDataObject1, LPDATAOBJECT pDataObject2) { TRACE(TEXT("CDSComponentData::CompareObjects().\n")); CInternalFormatCracker dobjCracker1; CInternalFormatCracker dobjCracker2; if (FAILED(dobjCracker1.Extract(pDataObject1)) || FAILED(dobjCracker2.Extract(pDataObject2))) { return S_FALSE; // could not get internal format } CUINode* pUINode1 = dobjCracker1.GetCookie(); CUINode* pUINode2 = dobjCracker2.GetCookie(); // // must have valid nodes // if ( (pUINode1 == NULL) || (pUINode2 == NULL) ) { return S_FALSE; } if (dobjCracker1.GetCookieCount() == 1 && dobjCracker2.GetCookieCount() == 1 && pUINode1 == pUINode2) { // // same pointer, they are the same (either both from real nodes // or both from secondary pages) // return S_OK; } // // if they are not the same, we compare them by DN, because we // support only property pages on DS objects // CObjectNamesFormatCracker objectNamesFormatCracker1; CObjectNamesFormatCracker objectNamesFormatCracker2; if ( (FAILED(objectNamesFormatCracker1.Extract(pDataObject1))) || (FAILED(objectNamesFormatCracker2.Extract(pDataObject2))) ) { // one or both not a DS object: we assume they are different return S_FALSE; } if ( (objectNamesFormatCracker1.GetCount() != 1) || (objectNamesFormatCracker2.GetCount() != 1) ) { // // We are allowing as many multiple selection pages up as the user wants // return S_FALSE; } TRACE(L"CDSComponentData::CompareObjects(%s, %s)\n", objectNamesFormatCracker1.GetName(0), objectNamesFormatCracker2.GetName(0)); return (_wcsicmp(objectNamesFormatCracker1.GetName(0), objectNamesFormatCracker2.GetName(0)) == 0) ? S_OK : S_FALSE; } /////////////////////////////////////////////////////////////////////////////// // IExtendContextMenu implementation // STDMETHODIMP CDSComponentData::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK pContextMenuCallback, long *pInsertionAllowed) { HRESULT hr = S_OK; TRACE(_T("CDSComponentData::AddMenuItems()\n")); AFX_MANAGE_STATE(AfxGetStaticModuleState()); DATA_OBJECT_TYPES dotType; CUINode* pUINode = NULL; CUIFolderInfo* pFolderInfo = NULL; CInternalFormatCracker dobjCracker; hr = dobjCracker.Extract(pDataObject); if (FAILED(hr)) { ASSERT (FALSE); // Invalid Data Object return E_UNEXPECTED; } dotType = dobjCracker.GetType(); pUINode = dobjCracker.GetCookie(); if (pUINode==NULL || dotType==0) { ASSERT(FALSE); // Invalid args return E_UNEXPECTED; } // // Retrieve context menu verb handler form node // CContextMenuVerbs* pMenuVerbs = pUINode->GetContextMenuVerbsObject(this); if (pMenuVerbs == NULL) { ASSERT(FALSE); return E_UNEXPECTED; } if (pUINode->IsContainer()) { pFolderInfo = pUINode->GetFolderInfo(); ASSERT(pFolderInfo != NULL); pFolderInfo->UpdateSerialNumber(this); } // // Use the IContextMenuCallback2 interface so that we can use // language independent IDs on the menu items. // CComPtr spMenuCallback2; hr = pContextMenuCallback->QueryInterface(IID_IContextMenuCallback2, (PVOID*)&spMenuCallback2); if (FAILED(hr)) { ASSERT(FALSE && L"Failed to QI for the IContextMenuCallback2 interface."); return E_UNEXPECTED; } if (*pInsertionAllowed & CCM_INSERTIONALLOWED_NEW) { // // Load New Menu // hr = pMenuVerbs->LoadNewMenu(spMenuCallback2, m_pShlInit, pDataObject, pUINode, pInsertionAllowed); ASSERT(SUCCEEDED(hr)); } if ( *pInsertionAllowed & CCM_INSERTIONALLOWED_TOP ) { // // Load Top Menu // hr = pMenuVerbs->LoadTopMenu(spMenuCallback2, pUINode); ASSERT(SUCCEEDED(hr)); } if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TASK) { // // Load Task Menu // hr = pMenuVerbs->LoadTaskMenu(spMenuCallback2, pUINode); ASSERT(SUCCEEDED(hr)); } if (*pInsertionAllowed & CCM_INSERTIONALLOWED_VIEW) { // // Load View Menu // hr = pMenuVerbs->LoadViewMenu(spMenuCallback2, pUINode); ASSERT(SUCCEEDED(hr)); } return hr; } STDMETHODIMP CDSComponentData::Command(long nCommandID, LPDATAOBJECT pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (nCommandID >= IDM_NEW_OBJECT_BASE) { // creation of a new DS object return _CommandNewDSObject(nCommandID, pDataObject); } if ((nCommandID >= MENU_MERGE_BASE) && (nCommandID <= MENU_MERGE_LIMIT)) { // range of menu ID's coming from shell extensions return _CommandShellExtension(nCommandID, pDataObject); } HRESULT hr = S_OK; CInternalFormatCracker dobjCracker; hr = dobjCracker.Extract(pDataObject); if (FAILED(hr)) { ASSERT (FALSE); // Invalid Data Object return hr; } DATA_OBJECT_TYPES dotType = dobjCracker.GetType(); CUINode* pUINode = dobjCracker.GetCookie(); if (pUINode == NULL || dotType == 0) { ASSERT(FALSE); // Invalid args return E_FAIL; } if (IS_CLASS(*pUINode, CDSUINode)) { CDSCookie* pCookie = GetDSCookieFromUINode(pUINode); // menu ID's from standard DSA hard coded values switch (nCommandID) { case IDM_DS_OBJECT_FIND: { LPCWSTR lpszPath = NULL; if (pCookie == NULL) { lpszPath = m_RootNode.GetPath(); } else { lpszPath = pCookie->GetPath(); } m_ActiveDS->DSFind(m_hwnd, lpszPath); } break; case IDM_GEN_TASK_MOVE: { CDSUINode* pDSUINode = dynamic_cast(pUINode); ASSERT(pDSUINode != NULL); _MoveObject(pDSUINode); m_pFrame->UpdateAllViews (NULL, NULL, DS_UPDATE_OBJECT_COUNT); } break; case IDM_VIEW_COMPUTER_HACK: if (CanRefreshAll()) { Lock(); m_pQueryFilter->ToggleExpandComputers(); Unlock(); BOOL fDoRefresh = m_pClassCache->ToggleExpandSpecialClasses(m_pQueryFilter->ExpandComputers()); m_bDirty = TRUE; if (fDoRefresh) { RefreshAll(); } } break; case IDM_GEN_TASK_SELECT_DOMAIN: case IDM_GEN_TASK_SELECT_FOREST: if (CanRefreshAll()) { GetDomain(); } break; case IDM_GEN_TASK_SELECT_DC: if (CanRefreshAll()) { GetDC(); } break; #ifdef FIXUPDC case IDM_GEN_TASK_FIXUP_DC: #endif // FIXUPDC case IDM_GEN_TASK_RUN_KCC: { ASSERT(pCookie != NULL); // // Pass the LDAP path of the parent cookie to _FixupDC or _RunKCC. // The current cookie is a nTDSDSA object, // and the parent cookie must be a server object // CUINode* pParentUINode = pUINode->GetParent(); ASSERT(pParentUINode != NULL); CDSCookie *pParentCookie = GetDSCookieFromUINode(pParentUINode); ASSERT(pParentCookie != NULL); CString strServerPath = pParentCookie->GetPath(); CString strPath = GetBasePathsInfo()->GetProviderAndServerName(); strPath += strServerPath; #ifdef FIXUPDC switch (nCommandID) { case IDM_GEN_TASK_FIXUP_DC: _FixupDC(strPath); break; case IDM_GEN_TASK_RUN_KCC: #endif // FIXUPDC _RunKCC(strPath); #ifdef FIXUPDC break; default: ASSERT(FALSE); break; } #endif // FIXUPDC } break; case IDM_GEN_TASK_EDIT_FSMO: { EditFSMO(); } break; case IDM_GEN_TASK_RAISE_VERSION: RaiseVersion(); break; case IDM_VIEW_ADVANCED: { if (CanRefreshAll()) { ASSERT( SNAPINTYPE_SITE != QuerySnapinType() ); m_pQueryFilter->ToggleAdvancedView(); m_bDirty = TRUE; RefreshAll(); } } break; case IDM_VIEW_SERVICES_NODE: { if (CanRefreshAll()) { ASSERT( SNAPINTYPE_SITE == QuerySnapinType() ); m_pQueryFilter->ToggleViewServicesNode(); m_bDirty = TRUE; if (m_RootNode.GetFolderInfo()->IsExpanded()) { Refresh(&m_RootNode, FALSE /*bFlushCache*/ ); } } } break; case IDM_VIEW_FILTER_OPTIONS: { if (CanRefreshAll()) { ASSERT(m_bRunAsPrimarySnapin); if (m_pQueryFilter->EditFilteringOptions()) { m_bDirty = TRUE; RefreshAll(); } } } break; } // switch } else // Other node types { pUINode->OnCommand(nCommandID, this); } return S_OK; } HRESULT CDSComponentData::_CommandNewDSObject(long nCommandID, LPDATAOBJECT pDataObject) { ASSERT(nCommandID >= IDM_NEW_OBJECT_BASE); UINT objIndex = nCommandID - IDM_NEW_OBJECT_BASE; if (pDataObject == NULL) return E_INVALIDARG; CInternalFormatCracker internalFormat; HRESULT hr = internalFormat.Extract(pDataObject); if (FAILED(hr)) { return hr; } if (!internalFormat.HasData() || (internalFormat.GetCookieCount() != 1)) { return E_INVALIDARG; } CUINode* pContainerUINode = internalFormat.GetCookie(); ASSERT(pContainerUINode != NULL); // can do this for DS objects only CDSUINode* pContainerDSUINode = dynamic_cast(pContainerUINode); if (pContainerDSUINode == NULL) { ASSERT(FALSE); // should never happen return E_INVALIDARG; } CDSUINode* pNewDSUINode = NULL; // pNewCookie is filled in if it is a leaf, then we call UpdateAllViews hr = _CreateDSObject(pContainerDSUINode, pContainerDSUINode->GetCookie()->GetChildListEntry(objIndex), NULL, &pNewDSUINode); if (SUCCEEDED(hr) && (hr != S_FALSE) && (pNewDSUINode != NULL)) { m_pFrame->UpdateAllViews(pDataObject, (LPARAM)pNewDSUINode, DS_CREATE_OCCURRED); m_pFrame->UpdateAllViews(pDataObject, (LPARAM)pContainerDSUINode, DS_UNSELECT_OBJECT); } m_pFrame->UpdateAllViews (NULL, NULL, DS_UPDATE_OBJECT_COUNT); return S_OK; } HRESULT CDSComponentData::_CommandShellExtension(long nCommandID, LPDATAOBJECT pDataObject) { CComPtr spICM; HRESULT hr = m_pShlInit->QueryInterface(IID_IContextMenu, (void **)&spICM); if (FAILED(hr)) { ASSERT(FALSE); return hr; } // just call the shell extension HWND hwnd; CMINVOKECOMMANDINFO cmiCommand; hr = m_pFrame->GetMainWindow (&hwnd); ASSERT (hr == S_OK); cmiCommand.hwnd = hwnd; cmiCommand.cbSize = sizeof (CMINVOKECOMMANDINFO); cmiCommand.fMask = SEE_MASK_ASYNCOK; cmiCommand.lpVerb = MAKEINTRESOURCEA(nCommandID - MENU_MERGE_BASE); spICM->InvokeCommand(&cmiCommand); // get the internal clibard format to see if it was one of our objects // from the DS context emnu extension CInternalFormatCracker internalFormat; hr = internalFormat.Extract(pDataObject); if (FAILED(hr)) { return hr; } if (!internalFormat.HasData() || (internalFormat.GetCookieCount() != 1)) { return E_INVALIDARG; } CUINode* pUINode = internalFormat.GetCookie(); ASSERT(pUINode != NULL); if (pUINode->GetExtOp() & OPCODE_MOVE) { // REVIEW_MARCOC_PORT: need to generalize this for all folder types CDSUINode* pDSUINode = dynamic_cast(pUINode); ASSERT(pDSUINode != NULL); if (pDSUINode != NULL) { CUINode* pNewParentNode = MoveObjectInUI(pDSUINode); if (pNewParentNode && pNewParentNode->GetFolderInfo()->IsExpanded()) { Refresh(pNewParentNode); } } } return hr; } ///////////////////////////////////////////////////////////////////////////// // CDSComponentData::ISnapinHelp2 members STDMETHODIMP CDSComponentData::GetHelpTopic(LPOLESTR* lpCompiledHelpFile) { if (lpCompiledHelpFile == NULL) return E_INVALIDARG; if (m_lpszSnapinHelpFile == NULL) { *lpCompiledHelpFile = NULL; return E_NOTIMPL; } CString szHelpFilePath; LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH); UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH); if (nLen == 0) return E_FAIL; szHelpFilePath.ReleaseBuffer(); szHelpFilePath += L"\\help\\"; szHelpFilePath += m_lpszSnapinHelpFile; UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR); *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes); if (*lpCompiledHelpFile != NULL) { memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes); } return S_OK; } STDMETHODIMP CDSComponentData::GetLinkedTopics(LPOLESTR* lpCompiledHelpFile) { if (lpCompiledHelpFile == NULL) return E_INVALIDARG; CString szHelpFilePath; LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH); UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH); if (nLen == 0) return E_FAIL; szHelpFilePath.ReleaseBuffer(); szHelpFilePath += L"\\help\\"; szHelpFilePath += DSADMIN_LINKED_HELP_FILE; UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR); *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes); if (*lpCompiledHelpFile != NULL) { memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes); } return S_OK; } #ifdef _MMC_ISNAPIN_PROPERTY ///////////////////////////////////////////////////////////////////////////// // CDSComponentData::ISnapinProperties members // struct defining each entry struct CSnapinPropertyEntry { LPCWSTR lpszName; DWORD dwFlags; }; // actual table static const CSnapinPropertyEntry g_snapinPropertyArray[] = { { g_szServer, MMC_PROP_CHANGEAFFECTSUI|MMC_PROP_MODIFIABLE|MMC_PROP_PERSIST}, { g_szDomain, MMC_PROP_CHANGEAFFECTSUI|MMC_PROP_MODIFIABLE|MMC_PROP_PERSIST}, { g_szRDN, MMC_PROP_CHANGEAFFECTSUI|MMC_PROP_MODIFIABLE|MMC_PROP_PERSIST}, { NULL, 0x0} // end of table marker }; STDMETHODIMP CDSComponentData::Initialize( Properties* pProperties) /* I:my snap-in's properties */ { TRACE(L"CDSComponentData::ISnapinProperties::Initialize()\n"); if (pProperties == NULL) { return E_INVALIDARG; } ASSERT(m_pProperties == NULL); // assume called only once // save the interface pointer, // it will be released during IComponentData::Destroy() m_pProperties = pProperties; m_pProperties->AddRef(); return S_OK; } STDMETHODIMP CDSComponentData::QueryPropertyNames( ISnapinPropertiesCallback* pCallback) /* I:interface to add prop names*/ { TRACE(L"CDSComponentData::QueryPropertyNames()\n"); HRESULT hr = S_OK; // just loop through the table and add the entries for (int k= 0; g_snapinPropertyArray[k].lpszName != NULL; k++) { hr = pCallback->AddPropertyName(g_snapinPropertyArray[k].lpszName, NULL, g_snapinPropertyArray[k].dwFlags); if (FAILED(hr)) { break; } } return hr; } /*+-------------------------------------------------------------------------* * CDSComponentData::PropertiesChanged * * This method is called when the snap-in's property set has changed. * * Returns: * S_OK change was successful * S_FALSE change was ignored * E_INVALIDARG a changed property was invalid (e.g. a malformed * computer name) * E_FAIL a changed property was valid, but couldn't be used * (e.g. a valid name for a computer that couldn't be * located) *--------------------------------------------------------------------------*/ STDMETHODIMP CDSComponentData::PropertiesChanged( long cChangedProps, /* I:changed property count */ MMC_SNAPIN_PROPERTY* pChangedProps) /* I:changed properties */ { TRACE(L"CDSComponentData::PropertiesChanged()\n"); // for the time being we do not allow any property change, // we accept only initialization, so make a quick change and bail out // if things are not such for (long k=0; k< cChangedProps; k++) { if (pChangedProps[k].eAction != MMC_PROPACT_INITIALIZING) { return S_FALSE; // change ignored } if (pChangedProps[k].varValue.vt != VT_BSTR) { // something is wrong, refuse return E_INVALIDARG; } } // delegate to the targeting info object HRESULT hr = m_targetingInfo.InitFromSnapinProperties(cChangedProps, pChangedProps); // need to add here the properties for advanced view and alike return hr; } #endif //_MMC_ISNAPIN_PROPERTY ///////////////////////////////////////////////////////////////////////////// // internal helpers HRESULT CDSComponentData::_InitRootFromBasePathsInfo(MyBasePathsInfo* pBasePathsInfo) { // we assume the MyBasePathsInfo we get is valid, // we just swap info around and rebuild the related // data structures GetBasePathsInfo()->InitFromInfo(pBasePathsInfo); m_InitSuccess = TRUE; TRACE(_T("in _InitRootFromBasePathsInfo, set m_InitSuccess to true\n")); return _InitRootFromValidBasePathsInfo(); } HRESULT CDSComponentData::_InitRootFromCurrentTargetInfo() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CWaitCursor wait; HRESULT hr = S_OK; // // This function may be called twice if we are loading from a file, // so don't try to initialize a second time // if (m_InitAttempted) { return S_OK; } BOOL bLocalLogin; bLocalLogin = IsLocalLogin(); //if user logged in locally and noting given on //command line LPCWSTR lpszServerOrDomain = m_targetingInfo.GetTargetString(); BOOL bNoTarget = ( (lpszServerOrDomain == NULL) || (lpszServerOrDomain[0] == NULL) ); if( bNoTarget && bLocalLogin && (SNAPINTYPE_SITE != QuerySnapinType())) { TRACE(_T("LoggedIn as Local User and No Command Line arguments\n")); CString szMsg; szMsg.LoadString(IDS_LOCAL_LOGIN_ERROR); CComPtr spIDisplayHelp; hr = m_pFrame->QueryInterface (IID_IDisplayHelp, (void **)&spIDisplayHelp); CMoreInfoMessageBox dlg(m_hwnd, spIDisplayHelp , FALSE); dlg.SetMessage(szMsg); dlg.SetURL(DSADMIN_MOREINFO_LOCAL_LOGIN_ERROR); dlg.DoModal(); m_InitSuccess = FALSE; TRACE(_T("in _InitRootFromCurrentTargetInfo, set m_InitSuccess to false\n")); } else { // initialize base paths hr = GetBasePathsInfo()->InitFromName(lpszServerOrDomain); // // JonN 5/4/00 // 55400: SITEREPL: Should default to local DC regardless of credentials // If the local machine is in the target forest, we target the domain // containing the local machine. // do // false loop { // We cannot follow this procedudure if we couldn't bind initially if (FAILED(hr)) break; // Skip this if the user specified a target if (!bNoTarget) break; // only do this for SITEREPL if (SNAPINTYPE_SITE != QuerySnapinType()) break; // Check whether the user is logged onto the local domain. CString strComputer; // empty string CString strLocalDomain; HRESULT hr2 = GetDnsNameOfDomainOrForest( strComputer, strLocalDomain, FALSE, TRUE ); if (FAILED(hr2) || strLocalDomain.IsEmpty()) break; CString strTargetDomain = GetBasePathsInfo()->GetDomainName(); if (strTargetDomain.IsEmpty()) break; if (!strLocalDomain.CompareNoCase(strTargetDomain)) break; // The user is not logged onto the local domain. // We need to determine whether the user is logged onto // the same forest as the local forest. CString strLocalForest; hr2 = GetDnsNameOfDomainOrForest( strComputer, strLocalForest, FALSE, FALSE ); if (FAILED(hr2) || strLocalForest.IsEmpty()) break; CString strTargetForest; strComputer = GetBasePathsInfo()->GetServerName(); hr2 = GetDnsNameOfDomainOrForest( strComputer, strTargetForest, FALSE, FALSE ); if (FAILED(hr2) || strTargetForest.IsEmpty()) break; if (strLocalForest.CompareNoCase(strTargetForest)) break; // The user is logged on to a different domain than the local // domain, but one in the same forest. There are probably closer DCs // than the one just located, so use them instead. // start using hr again here rather than hr2 TRACE(_T("_InitRootFromCurrentTargetInfo() rebinding\n")); hr = GetBasePathsInfo()->InitFromName(strLocalDomain); if (FAILED(hr)) { // try to fall back to initial focus TRACE(_T("_InitRootFromCurrentTargetInfo() reverting\n")); hr = GetBasePathsInfo()->InitFromName(lpszServerOrDomain); } } while (false); // false loop // NOTICE: if we fail, we out out the error message, and // we keep a flag to avoid query expansions, but // we continue, because we have to keep consistency in all // the data structures (class cache, filter, etc.) if (FAILED(hr)) { TRACE(_T("_InitRootFromCurrentTargetInfo() failed\n")); ReportErrorEx (m_hwnd, IDS_CANT_GET_ROOTDSE,hr, MB_OK | MB_ICONERROR, NULL, 0); m_InitSuccess = FALSE; TRACE(_T("in _InitRootFromCurrentTargetInfo(), set m_InitSuccess to false\n")); } else { m_InitSuccess = TRUE; TRACE(_T("in _InitRootFromCurrentTargetInfo(), set m_InitSuccess to true\n")); } } _InitRootFromValidBasePathsInfo(); m_InitAttempted = TRUE; return hr; } HRESULT CDSComponentData::_InitRootFromValidBasePathsInfo() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = S_OK; // now set the root node strings. This will be reset below // with the DNS name of the domain if everything succeeds CString str; str.LoadString( ResourceIDForSnapinType[ QuerySnapinType() ] ); m_RootNode.SetName(str); // rebuild the display spec options struct for Data Objects hr = BuildDsDisplaySpecOptionsStruct(); if (FAILED(hr)) return hr; // reset the notification handler GetNotifyHandlerManager()->Init(); // reset the query filter (already initialized in IComponentData::Initialize()) hr = m_pQueryFilter->Bind(); if (FAILED(hr)) return hr; CString szServerName = GetBasePathsInfo()->GetServerName(); if (!szServerName.IsEmpty()) { str += L" ["; str += szServerName; str += L"]"; } m_RootNode.SetName(str); if (QuerySnapinType() == SNAPINTYPE_SITE) { //fix the default root path str = GetBasePathsInfo()->GetConfigNamingContext(); } else { LPCWSTR lpszRootRDN = m_targetingInfo.GetRootRDN(); if ( (lpszRootRDN != NULL) && (lpszRootRDN[0] != NULL) ) { // add RDN below default naming context // REVIEW_MARCOC_PORT: need to make sure the RDN is valid str = m_targetingInfo.GetRootRDN(); str += L","; str += GetBasePathsInfo()->GetDefaultRootNamingContext(); } else { // just use the default naming context str = GetBasePathsInfo()->GetDefaultRootNamingContext(); } } m_RootNode.SetPath(str); // update UI if we already have inserted the root (retargeting case) HSCOPEITEM hScopeItemID = m_RootNode.GetFolderInfo()->GetScopeItem(); if (hScopeItemID != NULL) { SCOPEDATAITEM Item; CString csRoot; Item.ID = m_RootNode.GetFolderInfo()->GetScopeItem(); Item.mask = SDI_STR; csRoot = m_RootNode.GetName(); Item.displayname = (LPWSTR)(LPCWSTR)csRoot; m_pScope->SetItem(&Item); m_RootNode.SetExtOp(m_InitSuccess ? 0 : OPCODE_ENUM_FAILED); ChangeScopeItemIcon(&m_RootNode); } return hr; } void CDSComponentData::GetDomain() { CChooseDomainDlg DomainDlg; // load current bind info DomainDlg.m_csTargetDomain = GetBasePathsInfo()->GetDomainName(); DomainDlg.m_bSiteRepl = (SNAPINTYPE_SITE == QuerySnapinType()); DomainDlg.m_bSaveCurrent = m_targetingInfo.GetSaveCurrent(); // // invoke the dialog // if (DomainDlg.DoModal() == IDOK) { CWaitCursor cwait; // attempt to bind MyBasePathsInfo tempBasePathsInfo; HRESULT hr = tempBasePathsInfo.InitFromName(DomainDlg.m_csTargetDomain); if (SUCCEEDED(hr)) { hr = _InitRootFromBasePathsInfo(&tempBasePathsInfo); if (SUCCEEDED(hr)) { m_targetingInfo.SetSaveCurrent(DomainDlg.m_bSaveCurrent); m_bDirty = TRUE; ClearClassCacheAndRefreshRoot(); } } if (FAILED(hr)) { ReportErrorEx( m_hwnd, (DomainDlg.m_bSiteRepl ? IDS_RETARGET_FOREST_FAILED : IDS_RETARGET_DOMAIN_FAILED), hr, MB_OK | MB_ICONERROR, NULL, 0); } } return; } void CDSComponentData::GetDC() { CChooseDCDlg DCdlg(CWnd::FromHandle(m_hwnd)); // load current bind info DCdlg.m_bSiteRepl = (SNAPINTYPE_SITE == QuerySnapinType()); DCdlg.m_csTargetDomain = GetBasePathsInfo()->GetDomainName(); DCdlg.m_csTargetDomainController = GetBasePathsInfo()->GetServerName(); // // invoke the dialog // if (DCdlg.DoModal() == IDOK) { CWaitCursor cwait; CString csNewTarget; csNewTarget = DCdlg.m_csTargetDomainController; if (csNewTarget.IsEmpty()) csNewTarget = DCdlg.m_csTargetDomain; // attempt to bind MyBasePathsInfo tempBasePathsInfo; HRESULT hr = tempBasePathsInfo.InitFromName(csNewTarget); if (SUCCEEDED(hr)) { hr = _InitRootFromBasePathsInfo(&tempBasePathsInfo); if (SUCCEEDED(hr)) ClearClassCacheAndRefreshRoot(); } if (FAILED(hr)) { ReportErrorEx( m_hwnd, IDS_RETARGET_DC_FAILED, hr, MB_OK | MB_ICONERROR, NULL, 0); } } return; } void CDSComponentData::EditFSMO() { CComPtr spIDisplayHelp; HRESULT hr = m_pFrame->QueryInterface (IID_IDisplayHelp, (void **)&spIDisplayHelp); ASSERT(spIDisplayHelp != NULL); if (SUCCEEDED(hr)) { HWND hWnd; m_pFrame->GetMainWindow(&hWnd); LPCWSTR lpszTODO = L""; CFsmoPropertySheet sheet(GetBasePathsInfo(), hWnd, spIDisplayHelp, lpszTODO); sheet.DoModal(); } } void CDSComponentData::RaiseVersion(void) { HWND hWnd; m_pFrame->GetMainWindow(&hWnd); CString strPath; GetBasePathsInfo()->GetDefaultRootPath(strPath); PCWSTR pwzDnsName = GetBasePathsInfo()->GetDomainName(); ASSERT(pwzDnsName); DSPROP_DomainVersionDlg(strPath, pwzDnsName, hWnd); } HRESULT CDSComponentData::_OnPreload(HSCOPEITEM hRoot) { HRESULT hr = S_OK; AFX_MANAGE_STATE(AfxGetStaticModuleState()); CString str; str.LoadString( ResourceIDForSnapinType[ QuerySnapinType() ] ); m_RootNode.SetName(str); if (GetBasePathsInfo()->IsInitialized()) { CString szServerName = GetBasePathsInfo()->GetServerName(); if (!szServerName.IsEmpty()) { str += L" ["; str += szServerName; str += L"]"; } m_RootNode.SetName(str); } SCOPEDATAITEM Item; Item.ID = hRoot; Item.mask = SDI_STR; Item.displayname = (LPWSTR)(LPCWSTR)str; hr = m_pScope->SetItem(&Item); return hr; } HRESULT CDSComponentData::_OnExpand(CUINode* pNode, HSCOPEITEM hParent, MMC_NOTIFY_TYPE event) { HRESULT hr = S_OK; if ((pNode == NULL) || (!pNode->IsContainer()) ) { ASSERT(FALSE); // Invalid Arguments return E_INVALIDARG; } BEGIN_PROFILING_BLOCK("CDSComponentData::_OnExpand"); CWaitCursor cwait; if (pNode->GetFolderInfo()->IsExpanded()) { END_PROFILING_BLOCK; // // Short circuit the expansion because the node is already expanded // return S_OK; } pNode->GetFolderInfo()->SetExpanded(); if (pNode == &m_RootNode) { // initialize the paths and targeting _InitRootFromCurrentTargetInfo(); // add the root cookie to MMC pNode->GetFolderInfo()->SetScopeItem(hParent); SCOPEDATAITEM Item; Item.ID = hParent; Item.mask = SDI_STR; Item.displayname = (LPWSTR)(LPCWSTR)(m_RootNode.GetName()); m_pScope->SetItem (&Item); // also add the root for the saved queries, if present if (m_pFavoritesNodesHolder != NULL) { // add the favorite queries subtree _AddScopeItem(m_pFavoritesNodesHolder->GetFavoritesRoot(), m_RootNode.GetFolderInfo()->GetScopeItem()); } } if (IS_CLASS(*pNode, CFavoritesNode)) { // just add the favorites subfolders and query folders CUINodeList* pNodeList = pNode->GetFolderInfo()->GetContainerList(); for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; ) { CUINode* pCurrChildNode = pNodeList->GetNext(pos); _AddScopeItem(pCurrChildNode, pNode->GetFolderInfo()->GetScopeItem()); } END_PROFILING_BLOCK; // return because we do not need to spawn any background // thread query return S_OK; } if (!_PostQueryToBackgroundThread(pNode)) { END_PROFILING_BLOCK; // no background thread query generated, we are done return S_OK; } // need to spawn a query request pNode->SetExtOp(OPCODE_EXPAND_IN_PROGRESS); TIMER(_T("posting request to bg threads\n")); if (MMCN_EXPANDSYNC == event) { // if sync expand, have to wait for the query to complete MSG tempMSG; TRACE(L"MMCN_EXPANDSYNC, before while()\n"); while(m_queryNodeTable.IsPresent(pNode)) { if (::PeekMessage(&tempMSG,m_pHiddenWnd->m_hWnd,CHiddenWnd::s_ThreadStartNotificationMessage, CHiddenWnd::s_ThreadDoneNotificationMessage, PM_REMOVE)) { DispatchMessage(&tempMSG); } } // while TRACE(L"MMCN_EXPANDSYNC, after while()\n"); } END_PROFILING_BLOCK; return hr; } HRESULT CDSComponentData::_AddScopeItem(CUINode* pUINode, HSCOPEITEM hParent, BOOL bSetSelected) { if (pUINode==NULL) { ASSERT(FALSE); // Invalid Arguments return E_INVALIDARG; } ASSERT(pUINode->IsContainer()); HRESULT hr=S_OK; SCOPEDATAITEM tSDItem; ZeroMemory(&tSDItem, sizeof(SCOPEDATAITEM)); tSDItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_STATE | SDI_PARAM |SDI_CHILDREN | SDI_PARENT; tSDItem.relativeID = hParent; if (IS_CLASS(*pUINode, CSavedQueryNode)) { tSDItem.cChildren = 0; } else { tSDItem.cChildren=1; } tSDItem.nState = 0; // insert item into tree control tSDItem.lParam = reinterpret_cast(pUINode); tSDItem.displayname=(LPWSTR)-1; tSDItem.nOpenImage = GetImage(pUINode, TRUE); tSDItem.nImage = GetImage(pUINode, FALSE); hr = m_pScope->InsertItem(&tSDItem); if (SUCCEEDED(hr) && tSDItem.ID != NULL) { pUINode->GetFolderInfo()->SetScopeItem(tSDItem.ID); if (bSetSelected) { m_pFrame->SelectScopeItem(tSDItem.ID); } } return hr; } HRESULT CDSComponentData::ChangeScopeItemIcon(CUINode* pUINode) { ASSERT(pUINode->IsContainer()); SCOPEDATAITEM tSDItem; ZeroMemory(&tSDItem, sizeof(SCOPEDATAITEM)); tSDItem.mask = SDI_IMAGE | SDI_OPENIMAGE; tSDItem.nOpenImage = GetImage(pUINode, TRUE); tSDItem.nImage = GetImage(pUINode, FALSE); tSDItem.ID = pUINode->GetFolderInfo()->GetScopeItem(); return m_pScope->SetItem(&tSDItem); } HRESULT CDSComponentData::_ChangeResultItemIcon(CUINode* pUINode) { ASSERT(!pUINode->IsContainer()); return m_pFrame->UpdateAllViews(NULL,(LPARAM)pUINode, DS_UPDATE_OCCURRED); } HRESULT CDSComponentData::ToggleDisabled(CDSUINode* pDSUINode, BOOL bDisable) { HRESULT hr = S_OK; CDSCookie* pCookie = pDSUINode->GetCookie(); ASSERT(pCookie != NULL); if (pCookie == NULL) { return E_INVALIDARG; } if (pCookie->IsDisabled() != bDisable) { // changed state if (bDisable) pCookie->SetDisabled(); else pCookie->ReSetDisabled(); // now need to change icon if (pDSUINode->IsContainer()) return ChangeScopeItemIcon(pDSUINode); else return _ChangeResultItemIcon(pDSUINode); } return hr; } HRESULT CDSComponentData::UpdateItem(CUINode* pNode) { if (pNode->IsContainer()) { // // this is a scope pane item // return _UpdateScopeItem(pNode); } else { // // this is a result pane item // tell the views to update // return m_pFrame->UpdateAllViews(NULL,(LPARAM)pNode, DS_UPDATE_OCCURRED); } } HRESULT CDSComponentData::_UpdateScopeItem(CUINode* pNode) { ASSERT(pNode->IsContainer()); SCOPEDATAITEM tSDItem; ZeroMemory(&tSDItem, sizeof(SCOPEDATAITEM)); tSDItem.mask = SDI_STR; tSDItem.displayname = MMC_CALLBACK; tSDItem.ID = pNode->GetFolderInfo()->GetScopeItem(); return m_pScope->SetItem(&tSDItem); } HRESULT CDSComponentData::AddClassIcon(IN LPCWSTR lpszClass, IN DWORD dwFlags, INOUT int* pnIndex) { Lock(); HRESULT hr = m_iconManager.AddClassIcon(lpszClass, GetBasePathsInfo(), dwFlags, pnIndex); Unlock(); return hr; } HRESULT CDSComponentData::FillInIconStrip(IImageList* pImageList) { Lock(); HRESULT hr = m_iconManager.FillInIconStrip(pImageList); Unlock(); return hr; } BOOL CDSComponentData::IsNotHiddenClass (LPWSTR pwszClass, CDSCookie* pParentCookie) { BOOL bApproved = FALSE; if (m_CreateInfo.IsEmpty()) { return FALSE; } POSITION pos; pos = m_CreateInfo.GetHeadPosition(); while (pos) { if (!m_CreateInfo.GetNext(pos).CompareNoCase(pwszClass)) { bApproved = TRUE; goto done; } else { if ( (!wcscmp (pwszClass, L"sitesContainer")) || (!wcscmp (pwszClass, L"site")) || (!wcscmp (pwszClass, L"siteLink")) || (!wcscmp (pwszClass, L"siteLinkBridge")) || (!wcscmp (pwszClass, L"licensingSiteSettings")) || (!wcscmp (pwszClass, L"nTDSSiteSettings")) || (!wcscmp (pwszClass, L"serversContainer")) || (!wcscmp (pwszClass, L"server")) || (!wcscmp (pwszClass, L"nTDSDSA")) || (!wcscmp (pwszClass, L"subnet")) #ifdef FRS_CREATE || (!wcscmp (pwszClass, L"nTDSConnection")) || (!wcscmp (pwszClass, L"nTFRSSettings")) || (!wcscmp (pwszClass, L"nTFRSReplicaSet")) || (!wcscmp (pwszClass, L"nTFRSMember")) || (!wcscmp (pwszClass, L"nTFRSSubscriptions")) || (!wcscmp (pwszClass, L"nTFRSSubscriber")) #endif // FRS_CREATE ) { bApproved = TRUE; goto done; } #ifndef FRS_CREATE else if ( !wcscmp(pwszClass, L"nTDSConnection")) { LPCWSTR pwszParentClass = (pParentCookie) ? pParentCookie->GetClass() : L""; if ( NULL != pwszParentClass && wcscmp(pwszParentClass, L"nTFRSSettings") && wcscmp(pwszParentClass, L"nTFRSReplicaSet") && wcscmp(pwszParentClass, L"nTFRSMember") ) { bApproved = TRUE; goto done; } } #endif // !FRS_CREATE } } done: return bApproved; } HRESULT CDSComponentData::FillInChildList(CDSCookie * pCookie) { HRESULT hr = S_OK; LPWSTR pszClasses = L"allowedChildClassesEffective"; LONG uBound, lBound; UINT index, index2 = 0; UINT cChildCount = 0; CString Path; WCHAR **ppChildren = NULL; VARIANT *pNames = NULL; WCHAR *pNextFree; CComVariant Var; CComVariant VarProp; CComVariant varHints; CComPtr spDSObject; GetBasePathsInfo()->ComposeADsIPath(Path, pCookie->GetPath()); hr = DSAdminOpenObject(Path, IID_IADsPropertyList, (void **)&spDSObject, TRUE /*bServer*/); if (FAILED(hr)) { TRACE(_T("Bind to Container for IPropertyList failed: %lx.\n"), hr); goto error; } else { CComPtr spDSObject2; hr = spDSObject->QueryInterface (IID_IADs, (void **)&spDSObject2); if (FAILED(hr)) { TRACE(_T("QI to Container for IADs failed: %lx.\n"), hr); goto error; } ADsBuildVarArrayStr (&pszClasses, 1, &varHints); spDSObject2->GetInfoEx(varHints, 0); } hr = spDSObject->GetPropertyItem (pszClasses, ADSTYPE_CASE_IGNORE_STRING, &VarProp); if (!SUCCEEDED(hr)) { TRACE(_T("GetPropertyTtem failed: %lx.\n"), hr); goto error; } if (V_VT(&VarProp) == VT_EMPTY) { TRACE(_T("GetPropertyTtem return empty VARIANT: vtype is %lx.\n"), V_VT(&VarProp)); goto error; } { // scope to allow goto's to compile IDispatch * pDisp = NULL; pDisp = V_DISPATCH(&VarProp); CComPtr spPropEntry; hr = pDisp->QueryInterface(IID_IADsPropertyEntry, (void **)&spPropEntry); hr = spPropEntry->get_Values(&Var); } hr = SafeArrayGetUBound (V_ARRAY(&Var), 1, &uBound); hr = SafeArrayGetLBound (V_ARRAY(&Var), 1, &lBound); hr = SafeArrayAccessData(V_ARRAY(&Var), (void **)&pNames); if (FAILED(hr)) { TRACE(_T("Accessing safearray data failed: %lx.\n"), hr); goto error; } else { if (uBound >= 0) { cChildCount = (UINT) (uBound - lBound); ppChildren = (WCHAR **) LocalAlloc (LPTR, (cChildCount + 1) * STRING_LEN); if (ppChildren != NULL) { pNextFree = (WCHAR*)(ppChildren + cChildCount + 1); index2 = 0; for (index = lBound; index <= (UINT)uBound; index++) { CComPtr spEntry; hr = (pNames[index].pdispVal)->QueryInterface (IID_IADsPropertyValue, (void **)&spEntry); if (SUCCEEDED(hr)) { CComBSTR bsObject; hr = spEntry->get_CaseIgnoreString (&bsObject); TRACE(_T("----->allowed object number %d: %s\n"), index, bsObject); if (IsNotHiddenClass(bsObject, pCookie)) { TRACE(_T("-----------approved.\n")); ppChildren[index2] = pNextFree; pNextFree += wcslen(bsObject)+ sizeof (WCHAR); wcscpy (ppChildren[index2], bsObject); index2 ++; } // if } // if } // for } // if } // if uBound #ifdef DBG else { TRACE(_T("--- no classes returned, no creation allowed here.\n")); } #endif VERIFY(SUCCEEDED(SafeArrayUnaccessData(V_ARRAY(&Var)))); } error: if (index2 != 0) { SortChildList (ppChildren, index2); pCookie->SetChildList (ppChildren); } pCookie->SetChildCount (index2); return hr; } // routine to sort the entries for the "Create New" menu // simple-minded bubble sort; its a small list BOOL CDSComponentData::SortChildList (LPWSTR *ppszChildList, UINT cChildCount) { LPWSTR Temp; BOOL IsSorted = FALSE; while (!IsSorted) { IsSorted = TRUE; // TRACE(_T("At top of while. ready to go again.\n")); for (UINT index = 0; index < cChildCount - 1; index++) { if (wcscmp (ppszChildList[index], ppszChildList[index + 1]) > 0) { Temp = ppszChildList[index]; ppszChildList[index] = ppszChildList[index + 1]; ppszChildList[index + 1] = Temp; //TRACE(_T("Swapped %s and %ws. still not done.\n"), // ppszChildList[index], ppszChildList[index + 1]); IsSorted = FALSE; } } } return IsSorted; } ///////////////////////////////////////////////////////////////////// // CDSComponentData::_CreateDSObject() // // Create a new ADs object. // HRESULT CDSComponentData::_CreateDSObject(CDSUINode* pContainerDSUINode, // IN: container where to create object LPCWSTR lpszObjectClass, // IN: class of the object to be created IN CDSUINode* pCopyFromDSUINode, // IN: (optional) object to be copied OUT CDSUINode** ppSUINodeNew) // OUT: OPTIONAL: Pointer to new node { CDSCookie* pNewCookie = NULL; HRESULT hr = GetActiveDS()->CreateDSObject(pContainerDSUINode, lpszObjectClass, pCopyFromDSUINode, &pNewCookie); if (SUCCEEDED(hr) && (hr != S_FALSE) && (pNewCookie != NULL)) { // make sure we update the icon cache m_pFrame->UpdateAllViews(/*unused*/NULL /*pDataObj*/, /*unused*/(LPARAM)0, DS_ICON_STRIP_UPDATE); // create a UI node to hold the cookie *ppSUINodeNew = new CDSUINode(NULL); (*ppSUINodeNew)->SetCookie(pNewCookie); if (pNewCookie->IsContainerClass()) { (*ppSUINodeNew)->MakeContainer(); } // Add the new node to the link list pContainerDSUINode->GetFolderInfo()->AddNode(*ppSUINodeNew); if ((*ppSUINodeNew)->IsContainer()) { // // Add the scope item and select it // _AddScopeItem(*ppSUINodeNew, pContainerDSUINode->GetFolderInfo()->GetScopeItem(), TRUE); *ppSUINodeNew = NULL; } } return hr; } // // return S_OK if can copy, S_FALSE if not, some hr error if failed // HRESULT CDSComponentData::_CanCopyDSObject(IDataObject* pCopyFromDsObject) { if (pCopyFromDsObject == NULL) { return E_INVALIDARG; } CInternalFormatCracker internalFormat; HRESULT hr = internalFormat.Extract(pCopyFromDsObject); if (FAILED(hr)) { return hr; } if (!internalFormat.HasData() || (internalFormat.GetCookieCount() != 1)) { return E_INVALIDARG; } // // Get the node data // CUINode* pUINode = internalFormat.GetCookie(); CDSCookie* pCopyFromDsCookie = NULL; if (IS_CLASS(*pUINode, CDSUINode)) { pCopyFromDsCookie = GetDSCookieFromUINode(pUINode); } if (pCopyFromDsCookie == NULL) { return E_INVALIDARG; } // // get the parent node data // CUINode* pParentUINode = pUINode->GetParent(); CDSCookie* pContainerDsCookie = NULL; if (IS_CLASS(*pParentUINode, CDSUINode)) { pContainerDsCookie = GetDSCookieFromUINode(pParentUINode); } if (pContainerDsCookie == NULL) { return E_INVALIDARG; } // // get the class to be created // LPCWSTR lpszObjectClass = pCopyFromDsCookie->GetClass(); // // try to find the class in the possible child classes of the container // WCHAR ** ppChildren = pContainerDsCookie->GetChildList(); if (ppChildren == NULL) { FillInChildList(pContainerDsCookie); ppChildren = pContainerDsCookie->GetChildList(); } // // loop trough the class list to find a match // int cChildCount = pContainerDsCookie->GetChildCount(); for (int index = 0; index < cChildCount; index++) { if (wcscmp(pContainerDsCookie->GetChildListEntry(index), lpszObjectClass) == 0) { return S_OK; // got one, can create } } return S_FALSE; // not found, cannot create } HRESULT CDSComponentData::_CopyDSObject(IDataObject* pCopyFromDsObject) // IN object to be copied { if (pCopyFromDsObject == NULL) return E_INVALIDARG; CInternalFormatCracker internalFormat; HRESULT hr = internalFormat.Extract(pCopyFromDsObject); if (FAILED(hr)) { return hr; } if (!internalFormat.HasData() || (internalFormat.GetCookieCount() != 1)) { return E_INVALIDARG; } CUINode* pCopyFromUINode = internalFormat.GetCookie(); ASSERT(pCopyFromUINode != NULL); // can do this for DS objects only CDSUINode* pCopyFromDSUINode = dynamic_cast(pCopyFromUINode); if (pCopyFromDSUINode == NULL) { ASSERT(FALSE); // should never happen return E_INVALIDARG; } // get the parent cookie CDSUINode* pContainerDSUINode = dynamic_cast(pCopyFromDSUINode->GetParent()); if(pContainerDSUINode == NULL) { ASSERT(FALSE); // should never happen return E_INVALIDARG; } // get the class to be created LPCWSTR lpszObjectClass = pCopyFromDSUINode->GetCookie()->GetClass(); // call the object creation code CDSUINode* pNewDSUINode = NULL; hr = _CreateDSObject(pContainerDSUINode, lpszObjectClass, pCopyFromDSUINode, &pNewDSUINode); // update if result pane item // (if it were a scope item, _CreateDSObject() would update it if (SUCCEEDED(hr) && (hr != S_FALSE) && (pNewDSUINode != NULL)) { m_pFrame->UpdateAllViews(pCopyFromDsObject, (LPARAM)pNewDSUINode, DS_CREATE_OCCURRED_RESULT_PANE); m_pFrame->UpdateAllViews(NULL, (LPARAM)pCopyFromDSUINode, DS_UNSELECT_OBJECT); } return S_OK; } HRESULT CDSComponentData::_DeleteFromBackendAndUI(IDataObject* pDataObject, CDSUINode* pDSUINode) { HRESULT hr = S_OK; ASSERT(pDSUINode != NULL); ASSERT(pDSUINode->IsContainer()); // guard against property sheet open on this cookie if (_WarningOnSheetsUp(pDSUINode)) return S_OK; CWaitCursor cwait; // this call will handle the notifications to extensions CDSCookie* pCookie = GetDSCookieFromUINode(pDSUINode); hr = _DeleteFromBackEnd(pDataObject, pCookie); // if deletion happened, delete the scope item from the UI if (SUCCEEDED(hr) && (hr != S_FALSE)) { hr = RemoveContainerFromUI(pDSUINode); delete pDSUINode; } return S_OK; } HRESULT CDSComponentData::RemoveContainerFromUI(CUINode* pUINode) { HRESULT hr = S_OK; ASSERT(pUINode->IsContainer()); HSCOPEITEM ItemID, ParentItemID; ItemID = pUINode->GetFolderInfo()->GetScopeItem(); CUINode* pParentNode = NULL; hr = m_pScope->GetParentItem(ItemID, &ParentItemID, (MMC_COOKIE *)&pParentNode); m_pScope->DeleteItem(ItemID, TRUE); if (SUCCEEDED(hr)) { ASSERT(pParentNode->IsContainer()); // delete memory pParentNode->GetFolderInfo()->RemoveNode(pUINode); } m_pFrame->UpdateAllViews(NULL, NULL, DS_UPDATE_OBJECT_COUNT); // // Remove the '+' sign in the UI if this was the last container child in this container // if (pParentNode != NULL && ParentItemID != 0 && pParentNode->GetFolderInfo()->GetContainerList()->GetCount() == 0) { SCOPEDATAITEM sdi; memset(&sdi, 0, sizeof(SCOPEDATAITEM)); sdi.ID = ParentItemID; sdi.mask |= SDI_CHILDREN; sdi.cChildren = 0; hr = m_pScope->SetItem(&sdi); } return hr; } /////////////////////////////////////////////////////////////////////////// // CSnapinSingleDeleteHandler class CSnapinSingleDeleteHandler : public CSingleDeleteHandlerBase { public: CSnapinSingleDeleteHandler(CDSComponentData* pComponentData, HWND hwnd, CDSCookie* pCookie) : CSingleDeleteHandlerBase(pComponentData, hwnd) { m_pCookie = pCookie; GetComponentData()->GetBasePathsInfo()->ComposeADsIPath( m_strItemPath, m_pCookie->GetPath()); } protected: CDSCookie* m_pCookie; CString m_strItemPath; virtual HRESULT BeginTransaction() { return GetTransaction()->Begin(m_pCookie, NULL, NULL, FALSE); } virtual HRESULT DeleteObject() { return GetComponentData()->GetActiveDS()->DeleteObject(m_pCookie ,FALSE); } virtual HRESULT DeleteSubtree() { return GetComponentData()->_DeleteSubtreeFromBackEnd(m_pCookie); } virtual void GetItemName(OUT CString& szName){ szName = m_pCookie->GetName(); } virtual LPCWSTR GetItemClass(){ return m_pCookie->GetClass(); } virtual LPCWSTR GetItemPath(){ return m_strItemPath; } }; /* NOTICE: the function will return S_OK on success, S_FALSE if aborted by user, some FAILED(hr) otherwise */ HRESULT CDSComponentData::_DeleteFromBackEnd(IDataObject*, CDSCookie* pCookie) { ASSERT(pCookie != NULL); CSnapinSingleDeleteHandler deleteHandler(this, m_hwnd, pCookie); return deleteHandler.Delete(); } HRESULT CDSComponentData::_DeleteSubtreeFromBackEnd(CDSCookie* pCookie) { HRESULT hr = S_OK; CComPtr spObj; CString szPath; GetBasePathsInfo()->ComposeADsIPath(szPath, pCookie->GetPath()); hr = DSAdminOpenObject(szPath, IID_IADsDeleteOps, (void **)&spObj, TRUE /*bServer*/); if (SUCCEEDED(hr)) { hr = spObj->DeleteObject(NULL); //flag is reserved by ADSI } return hr; } HRESULT CDSComponentData::_Rename(CUINode* pUINode, LPWSTR NewName) { // // Verify parameters // if (pUINode == NULL || NewName == NULL) { ASSERT(FALSE); return E_INVALIDARG; } CWaitCursor cwait; HRESULT hr = S_OK; CDSCookie* pCookie = NULL; CString szPath; // // guard against property sheet open on this cookie // if (_WarningOnSheetsUp(pUINode)) { return E_FAIL; } if (pUINode->IsSheetLocked()) { ReportErrorEx (m_hwnd,IDS_SHEETS_UP_RENAME,hr, MB_OK | MB_ICONINFORMATION, NULL, 0); return hr; } if (IS_CLASS(*pUINode, CDSUINode)) { pCookie = GetDSCookieFromUINode(pUINode); if (pCookie == NULL) { return E_FAIL; } CDSRenameObject* pRenameObject = NULL; CString strClass = pCookie->GetClass(); CString szDN = pCookie->GetPath(); GetBasePathsInfo()->ComposeADsIPath(szPath, szDN); // // Rename user object // if (strClass == L"user" #ifdef INETORGPERSON || strClass == L"inetOrgPerson" #endif ) { // // Rename user // pRenameObject = new CDSRenameUser(pUINode, pCookie, NewName, m_hwnd, this); } else if (strClass == L"group") { // // Rename group // pRenameObject = new CDSRenameGroup(pUINode, pCookie, NewName, m_hwnd, this); } else if (strClass == L"contact") { // // rename contact // pRenameObject = new CDSRenameContact(pUINode, pCookie, NewName, m_hwnd, this); } else if (strClass == L"site") { // // Rename site // pRenameObject = new CDSRenameSite(pUINode, pCookie, NewName, m_hwnd, this); } else if (strClass == L"subnet") { // // Rename subnet // pRenameObject = new CDSRenameSubnet(pUINode, pCookie, NewName, m_hwnd, this); } else if (strClass == L"nTDSConnection") { // // Rename nTDSConnection // pRenameObject = new CDSRenameNTDSConnection(pUINode, pCookie, NewName, m_hwnd, this); } else { // // Rename other object // pRenameObject = new CDSRenameObject(pUINode, pCookie, NewName, m_hwnd, this); } if (pRenameObject != NULL) { hr = pRenameObject->DoRename(); } else { hr = E_FAIL; } } else // !CDSUINode { hr = pUINode->Rename(NewName, this); } if (SUCCEEDED(hr) && !szPath.IsEmpty()) { CStringList pathList; pathList.AddTail(szPath); InvalidateSavedQueriesContainingObjects(pathList); } return hr; } void CDSComponentData::ClearSubtreeHelperForRename(CUINode* pUINode) { // // Verify parameters // if (pUINode == NULL) { ASSERT(FALSE); return; } HSCOPEITEM ItemID; CUIFolderInfo* pFolderInfo = NULL; pFolderInfo = pUINode->GetFolderInfo(); if (pFolderInfo != NULL) { // // remove the folder subtree in the UI // ItemID = pFolderInfo->GetScopeItem(); m_pScope->DeleteItem(ItemID, /* this node*/FALSE); // // clear list of children // pFolderInfo->DeleteAllLeafNodes(); pFolderInfo->DeleteAllContainerNodes(); // // remove the descendants from the pending query table // m_queryNodeTable.RemoveDescendants(pUINode); pFolderInfo->ReSetExpanded(); // make sure MMC knows the + sign should show SCOPEDATAITEM scopeItem; ZeroMemory(&scopeItem, sizeof(SCOPEDATAITEM)); scopeItem.ID = ItemID; scopeItem.mask = SDI_CHILDREN; scopeItem.cChildren = 1; m_pScope->SetItem(&scopeItem); } } CUINode* CDSComponentData::MoveObjectInUI(CDSUINode* pDSUINode) { CUINode* pParentUINode = pDSUINode->GetParent(); HSCOPEITEM ParentItemID = NULL; HRESULT hr = S_OK; ASSERT(pParentUINode != NULL && pParentUINode->IsContainer()); // // find the new parent node // CUINode* pNewParentNode = NULL; hr = FindParentCookie(pDSUINode->GetCookie()->GetPath(), &pNewParentNode); if (pDSUINode->IsContainer()) { HSCOPEITEM ItemID = pDSUINode->GetFolderInfo()->GetScopeItem(); hr = m_pScope->GetParentItem(ItemID, &ParentItemID, (MMC_COOKIE *)&pParentUINode); // // remove node from MMC // m_pScope->DeleteItem(ItemID, TRUE); if (SUCCEEDED(hr)) { // // remove it from the list of children // pParentUINode->GetFolderInfo()->RemoveNode(pDSUINode); } if ((hr == S_OK) && pNewParentNode && pNewParentNode->GetFolderInfo()->IsExpanded()) { // // add to new child list // pDSUINode->ClearParent(); if (pNewParentNode != NULL) { pNewParentNode->GetFolderInfo()->AddNode(pDSUINode); // // add to MMC scope pane // _AddScopeItem(pDSUINode, pNewParentNode->GetFolderInfo()->GetScopeItem()); } } else { // will get it later on when enumerating delete pDSUINode; } } else // leaf node { if ((pNewParentNode) && (pNewParentNode->GetFolderInfo()->IsExpanded())) { pDSUINode->ClearParent(); pNewParentNode->GetFolderInfo()->AddNode(pDSUINode); } m_pFrame->UpdateAllViews(NULL, (LPARAM)pDSUINode, DS_MOVE_OCCURRED); } return pNewParentNode; } HRESULT CDSComponentData::_MoveObject(CDSUINode* pDSUINode) { // guard against property sheet open on this cookie if (_WarningOnSheetsUp(pDSUINode)) return S_OK; CWaitCursor cwait; // call the backend to do the delete HRESULT hr = m_ActiveDS->MoveObject(pDSUINode->GetCookie()); if (SUCCEEDED(hr) && (hr != S_FALSE)) { // we actually moved the object, move in the folders and MMC CUINode* pNewParentNode = MoveObjectInUI(pDSUINode); if (pNewParentNode && pNewParentNode->GetFolderInfo()->IsExpanded()) { Refresh(pNewParentNode); } } return hr; } HRESULT CDSComponentData::Refresh(CUINode* pNode, BOOL bFlushCache, BOOL bFlushColumns) { HRESULT hr = S_OK; TRACE(_T("CDSComponentData::Refresh: cookie is %s\n"), pNode->GetName()); if (m_queryNodeTable.IsLocked(pNode)) { // this might happen if MMC's verb management bent out of shape (BUG?) // like in the case of the "*" (num keypad) command (expand the whole tree) // just ignore the command return S_OK; } if (_WarningOnSheetsUp(pNode)) return hr; if ((pNode == &m_RootNode) && !m_InitSuccess) { hr = _InitRootFromCurrentTargetInfo(); if (FAILED(hr)) { m_InitSuccess = FALSE; TRACE(_T("in Refresh, set m_InitSuccess to false\n")); return hr; } else { m_InitSuccess = TRUE; TRACE(_T("in Refresh, set m_InitSuccess to true\n")); } } // remove the folder subtree in the UI HSCOPEITEM ItemID = NULL; if (pNode->IsContainer()) { ItemID = pNode->GetFolderInfo()->GetScopeItem(); } if (ItemID == NULL) { // let's try the parent CUINode* pParent = pNode->GetParent(); ASSERT(pParent != NULL); ASSERT(pParent->IsContainer()); ItemID = pParent->GetFolderInfo()->GetScopeItem(); if (ItemID == NULL) { return S_OK; } else { pNode = pParent; } } m_pScope->DeleteItem(ItemID, /* this node*/FALSE); // delete result pane items in the UI TIMER(_T("calling update all views...")); m_pFrame->UpdateAllViews(NULL, (LPARAM)pNode, DS_REFRESH_REQUESTED); // clear list of children TIMER(_T("back from UpdateAllViews.\ncleaning up data structs...")); if (pNode == &m_RootNode) { if (m_pFavoritesNodesHolder != NULL) { // do not remove the favorites, just detach them from tree m_RootNode.GetFolderInfo()->RemoveNode(m_pFavoritesNodesHolder->GetFavoritesRoot()); m_pFavoritesNodesHolder->GetFavoritesRoot()->ClearParent(); m_pFavoritesNodesHolder->GetFavoritesRoot()->GetFolderInfo()->ReSetExpanded(); // clean up all the query folders, but otherwise leave the // subtree intact m_pFavoritesNodesHolder->GetFavoritesRoot()->RemoveQueryResults(); } // remove the remaining folders m_RootNode.GetFolderInfo()->DeleteAllLeafNodes(); m_RootNode.GetFolderInfo()->DeleteAllContainerNodes(); if (m_pFavoritesNodesHolder != NULL) { // re-attach the favorites underneath the root m_RootNode.GetFolderInfo()->AddNode(m_pFavoritesNodesHolder->GetFavoritesRoot()); // add the favorite queries subtree _AddScopeItem(m_pFavoritesNodesHolder->GetFavoritesRoot(), m_RootNode.GetFolderInfo()->GetScopeItem()); } } else if (IS_CLASS(*pNode, CFavoritesNode)) { // recurse down to other query folders to do cleanup dynamic_cast(pNode)->RemoveQueryResults(); // just add the favorites subfolders and query folders CUINodeList* pNodeList = pNode->GetFolderInfo()->GetContainerList(); for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; ) { CUINode* pCurrChildNode = pNodeList->GetNext(pos); _AddScopeItem(pCurrChildNode, pNode->GetFolderInfo()->GetScopeItem()); } } else if (IS_CLASS(*pNode, CSavedQueryNode)) { pNode->GetFolderInfo()->DeleteAllLeafNodes(); pNode->GetFolderInfo()->DeleteAllContainerNodes(); dynamic_cast(pNode)->SetValid(TRUE); } else { ASSERT(IS_CLASS(*pNode, CDSUINode) ); // standard DS container, just remove all sub objects pNode->GetFolderInfo()->DeleteAllLeafNodes(); pNode->GetFolderInfo()->DeleteAllContainerNodes(); } TIMER(_T("datastructs cleaned up\n")); // remove the descendants from the pending query table m_queryNodeTable.RemoveDescendants(pNode); if ((pNode == &m_RootNode) && bFlushCache) { TRACE(L"CDSComponentData::Refresh: flushing the cache\n"); m_pClassCache->Initialize(QuerySnapinType(), GetBasePathsInfo(), bFlushColumns); } // post a query TRACE(L"CDSComponentData::Refresh: posting query\n"); _PostQueryToBackgroundThread(pNode); TRACE(L"CDSComponentData::Refresh: returning\n"); return hr; } #if (FALSE) HRESULT CDSComponentData::_OnPropertyChange(LPDATAOBJECT pDataObject, BOOL bScope) { if (pDataObject == NULL) { return E_INVALIDARG; } CInternalFormatCracker dobjCracker; VERIFY(SUCCEEDED(dobjCracker.Extract(pDataObject))); CDSCookie* pCookie = NULL; CUINode* pUINode = dobjCracker.GetCookie(); if (pUINode == NULL) { return E_INVALIDARG; } // // Right now we are not supporting properties on other node types // if (IS_CLASS(*pUINode, CDSUINode)) { pCookie = GetDSCookieFromUINode(pUINode); } if (pCookie == NULL) { // not a DS object return S_OK; } { // // notify the extension that an object has changed // CDSNotifyHandlerTransaction transaction(this); transaction.SetEventType(DSA_NOTIFY_PROP); transaction.Begin(pDataObject, NULL, NULL, FALSE); // // we do not call Confirm() because this is an asynchrnous call after the fact // transaction.Notify(0); transaction.End(); } // // update the data to be displayed // // // update all the possible instances in the query namespace // if (m_pFavoritesNodesHolder != NULL) { // find the list of items to update CUINodeList queryNamespaceNodeList; m_pFavoritesNodesHolder->GetFavoritesRoot()->FindCookiesInQueries(pCookie->GetPath(), &queryNamespaceNodeList); // update all of them for (POSITION pos = queryNamespaceNodeList.GetHeadPosition(); pos != NULL; ) { CUINode* pCurrUINode = queryNamespaceNodeList.GetNext(pos); HRESULT hrCurr = UpdateFromDS(pCurrUINode); if (SUCCEEDED(hrCurr)) { UpdateItem(pCurrUINode); } } } // // figure out if the notification cookie is in the query namespace or // in the DS one // BOOL bNodeFromQueryNamespace = IS_CLASS(*(pUINode->GetParent()), CSavedQueryNode); CUINode* pUINodeToUpdate = NULL; if (bNodeFromQueryNamespace) { // find the item FindCookieInSubtree(&m_RootNode, pCookie->GetPath(), QuerySnapinType(), &pUINodeToUpdate); } else { pUINodeToUpdate = pUINode; } if (pUINodeToUpdate != NULL) { HRESULT hr = UpdateFromDS(pUINodeToUpdate); if (SUCCEEDED(hr)) { return UpdateItem(pUINodeToUpdate); } } return S_OK; } #endif HRESULT CDSComponentData::_OnPropertyChange(LPDATAOBJECT pDataObject, BOOL) { if (pDataObject == NULL) { return E_INVALIDARG; } CInternalFormatCracker ifc; if (FAILED(ifc.Extract(pDataObject))) { ASSERT(FALSE); return E_INVALIDARG; } CUINode* pUINode = ifc.GetCookie(); if (pUINode != NULL) { if (!IS_CLASS(*pUINode, CDSUINode)) { UpdateItem(pUINode); return S_OK; } } CObjectNamesFormatCracker objectNamesFormatCracker; if (FAILED(objectNamesFormatCracker.Extract(pDataObject))) { ASSERT(FALSE); return E_INVALIDARG; } { // // notify the extension that an object has changed // CDSNotifyHandlerTransaction transaction(this); transaction.SetEventType(DSA_NOTIFY_PROP); transaction.Begin(pDataObject, NULL, NULL, FALSE); // // we do not call Confirm() because this is an asynchrnous call after the fact // transaction.Notify(0); transaction.End(); } for (UINT idx = 0; idx < objectNamesFormatCracker.GetCount(); idx ++) { // // update the data to be displayed, need the DN out of the ADSI path // CComBSTR bstrDN; CPathCracker pathCracker; pathCracker.Set((LPWSTR)objectNamesFormatCracker.GetName(idx), ADS_SETTYPE_FULL); pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bstrDN); // // update all the possible instances in the query namespace // if (m_pFavoritesNodesHolder != NULL) { // find the list of items to update CUINodeList queryNamespaceNodeList; m_pFavoritesNodesHolder->GetFavoritesRoot()->FindCookiesInQueries(bstrDN, &queryNamespaceNodeList); // update all of them for (POSITION pos = queryNamespaceNodeList.GetHeadPosition(); pos != NULL; ) { CUINode* pCurrUINode = queryNamespaceNodeList.GetNext(pos); HRESULT hrCurr = UpdateFromDS(pCurrUINode); if (SUCCEEDED(hrCurr)) { UpdateItem(pCurrUINode); } } } // // find node in the DS namespace and update it // CUINode* pUINodeToUpdate = NULL; // find the item FindCookieInSubtree(&m_RootNode, bstrDN, QuerySnapinType(), &pUINodeToUpdate); if (pUINodeToUpdate != NULL) { HRESULT hr = UpdateFromDS(pUINodeToUpdate); if (SUCCEEDED(hr)) { UpdateItem(pUINodeToUpdate); } } } return S_OK; } /* --------------------------------------------------------- Helper function to create an LDAP query string to retrieve a single element inside a given container. Input: the DN of the object to query for. e.g.: "cn=foo,ou=bar,dc=mydom,dc=com" Output: a query string containing the leaf node properly escaped, (as per RFC 2254) e.g.: "(cn=foo)" NOTES: * we do not deal with embedded NULLs (we have regular C/C++ strings) * any \ character remaining after the path cracked full unescaping has to be escaped along the other special characters by using the \HexHex sequences. ------------------------------------------------------------*/ HRESULT _CreateLdapQueryFilterStringFromDN(IN LPCWSTR lpszDN, OUT CString& szQueryString) { szQueryString.Empty(); CPathCracker pathCracker; // remove any LDAP/ADSI escaping from the DN pathCracker.Set((LPWSTR)lpszDN, ADS_SETTYPE_DN); pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF_EX); // retrieve the leaf element CString szNewElement; CComBSTR bstrLeafElement; HRESULT hr = pathCracker.GetElement(0, &bstrLeafElement); if (FAILED(hr)) { return hr; } LPCWSTR lpszTemp = bstrLeafElement; TRACE(L"bstrLeafElement = %s\n", lpszTemp); // do LDAP escaping (as per RFC 2254) szQueryString = L"("; for (WCHAR* pChar = bstrLeafElement; (*pChar) != NULL; pChar++) { switch (*pChar) { case L'*': szQueryString += L"\\2a"; break; case L'(': szQueryString += L"\\28"; break; case L')': szQueryString += L"\\29"; break; case L'\\': szQueryString += L"\\5c"; break; default: szQueryString += (*pChar); } // switch } // for // finish wrapping with parentheses, // to get something like "(cn=foo)" szQueryString += L")"; return S_OK; } HRESULT CDSComponentData::UpdateFromDS(CUINode* pUINode) { ASSERT(pUINode != NULL); // // get the node data // CDSCookie* pCookie = NULL; if (IS_CLASS(*pUINode, CDSUINode)) { pCookie = GetDSCookieFromUINode(pUINode); } if (pCookie == NULL) { ASSERT(FALSE); // should never happen return E_FAIL; } // // get the container node // CUINode* pParentUINode = pUINode->GetParent(); ASSERT(pParentUINode != NULL); // // get the distinguished name of the parent by using the path in the cookie // and removing the leaf element using the path cracker. // e.g., given a DN "cn=x,ou=foo,...", the parent DN will be "ou=foo,..." // CComBSTR bstrParentDN; CPathCracker pathCracker; HRESULT hr = pathCracker.Set((LPWSTR)pCookie->GetPath(), ADS_SETTYPE_DN); ASSERT(SUCCEEDED(hr)); if (pParentUINode != GetRootNode()) { hr = pathCracker.RemoveLeafElement(); ASSERT(SUCCEEDED(hr)); } hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bstrParentDN); ASSERT(SUCCEEDED(hr)); // // get the LDAP path of the parent // CString szParentLdapPath; GetBasePathsInfo()->ComposeADsIPath(szParentLdapPath, bstrParentDN); // // find a matching column set // CDSColumnSet* pColumnSet = pParentUINode->GetColumnSet(this); if (pColumnSet == NULL) { return hr; } // // create a search object and init it // CDSSearch ContainerSrch(m_pClassCache, this); TRACE(L"ContainerSrch.Init(%s)\n", (LPCWSTR)szParentLdapPath); hr = ContainerSrch.Init(szParentLdapPath); if (FAILED(hr)) { return hr; } // // create a query string to look for the naming attribute // eg, given a DN "cn=x,ou=foo,..." the search string // will look like "(cn=x)" // CString szQueryString; hr = _CreateLdapQueryFilterStringFromDN(pCookie->GetPath(), szQueryString); if (FAILED(hr)) { return hr; } TRACE(L"szQueryString = %s\n", (LPCWSTR)szQueryString); ContainerSrch.SetAttributeListForContainerClass(pColumnSet); ContainerSrch.SetFilterString((LPWSTR)(LPCWSTR)szQueryString); if (pParentUINode == GetRootNode()) { ContainerSrch.SetSearchScope(ADS_SCOPE_BASE); } else { ContainerSrch.SetSearchScope(ADS_SCOPE_ONELEVEL); } hr = ContainerSrch.DoQuery(); if (FAILED(hr)) { return hr; } // // get the only row // hr = ContainerSrch.GetNextRow(); if (hr == S_ADS_NOMORE_ROWS) { hr = E_INVALIDARG; } if (FAILED(hr)) { return hr; } // // update the cookie itself // hr = ContainerSrch.SetCookieFromData(pCookie, pColumnSet); // // special case if it is a domain DNS object, // we want fo get the canonical name for display // if (wcscmp(pCookie->GetClass(), L"domainDNS") == 0) { ADS_SEARCH_COLUMN Column; CString csCanonicalName; int slashLocation; LPWSTR canonicalNameAttrib = L"canonicalName"; ContainerSrch.SetAttributeList (&canonicalNameAttrib, 1); hr = ContainerSrch.DoQuery(); if (FAILED(hr)) { return hr; } hr = ContainerSrch.GetNextRow(); if (FAILED(hr)) { return hr; } hr = ContainerSrch.GetColumn(canonicalNameAttrib, &Column); if (FAILED(hr)) { return hr; } ColumnExtractString (csCanonicalName, pCookie, &Column); slashLocation = csCanonicalName.Find('/'); if (slashLocation != 0) { csCanonicalName = csCanonicalName.Left(slashLocation); } pCookie->SetName(csCanonicalName); TRACE(L"canonical name pCookie->GetName() = %s\n", pCookie->GetName()); // // Free column data // ContainerSrch.FreeColumn(&Column); } return hr; } BOOL CDSComponentData::CanRefreshAll() { return !_WarningOnSheetsUp(&m_RootNode); } void CDSComponentData::RefreshAll() { ASSERT(!m_RootNode.IsSheetLocked()); // need to refresh the tree (all containers below the root) CUINodeList* pContainerNodeList = m_RootNode.GetFolderInfo()->GetContainerList(); for (POSITION pos = pContainerNodeList->GetHeadPosition(); pos != NULL; ) { CUINode* pNode = pContainerNodeList->GetNext(pos); ASSERT(pNode->IsContainer()); if (pNode->GetFolderInfo()->IsExpanded()) { Refresh(pNode); } } } void CDSComponentData::ClearClassCacheAndRefreshRoot() { ASSERT(!m_RootNode.IsSheetLocked()); if (m_RootNode.GetFolderInfo()->IsExpanded()) { Refresh(&m_RootNode, TRUE /*bFlushCache*/, FALSE ); } } // REVIEW_MARCOC_PORT: this function is not going to work with // items that are of different types. Need to generalize as see fit. BOOL _SearchList(CUINodeList* pContainers, LPCWSTR lpszParentDN, CUINode** ppParentUINode) { for (POSITION pos = pContainers->GetHeadPosition(); pos != NULL; ) { CUINode* pCurrentNode = pContainers->GetNext(pos); ASSERT(pCurrentNode->IsContainer()); if (!IS_CLASS(*pCurrentNode, CDSUINode)) { // not a node with a cookie, just skip continue; } /* is this the right cookie? */ CDSCookie* pCurrentCookie = GetDSCookieFromUINode(pCurrentNode); LPCWSTR lpszCurrentPath = pCurrentCookie->GetPath(); TRACE (_T("--SearchList: Looking at: %s\n"), lpszCurrentPath); if (_wcsicmp(lpszCurrentPath, lpszParentDN) == 0) { TRACE (_T("--SearchList: Found it!\n")); *ppParentUINode = pCurrentNode; return TRUE; // got it!!! } else { TRACE (L"--SearchList: not found...\n"); TRACE (_T("-- going down the tree: %s\n"), lpszCurrentPath); CUINodeList* pSubContainers = pCurrentNode->GetFolderInfo()->GetContainerList(); if (_SearchList(pSubContainers, lpszParentDN, ppParentUINode)) { return TRUE; // got it!!! } } } // for return FALSE; // not found } /* given a cookie, find the cookie corresponding to its parent node, if it exists. this is an expensive operation this is used for figuring out where to refresh after having moved an object. we know the new path to the object, but have no idea where or if that parent cookie exists in the tree. HUNT IT DOWN!! */ HRESULT CDSComponentData::FindParentCookie(LPCWSTR lpszCookieDN, CUINode** ppParentUINode) { // init outout variable *ppParentUINode = NULL; // bind to the ADSI aobject CString szPath; GetBasePathsInfo()->ComposeADsIPath(szPath, lpszCookieDN); CComPtr spDSObj; HRESULT hr = DSAdminOpenObject(szPath, IID_IADs, (void **)&spDSObj, TRUE /*bServer*/); if (FAILED(hr)) { return hr; // could not bind } // get the LDAP path of the parent CComBSTR ParentPath; hr = spDSObj->get_Parent(&ParentPath); if (FAILED(hr)) { return hr; } CString szParentDN; StripADsIPath(ParentPath, szParentDN); TRACE(_T("goin on a cookie hunt.. (for %s)\n"), ParentPath); // start a search from the root CUINodeList* pContainers = m_RootNode.GetFolderInfo()->GetContainerList(); BOOL bFound = _SearchList(pContainers, szParentDN, ppParentUINode); return bFound ? S_OK : S_FALSE; } // // This is a recursive search of the currently expanded domain tree starting at // the root looking at all CDSUINodes for a matching DN. // // NOTE : this may be an extremely expensive operation if a lot // of containers have been expanded or they have a lot of // children. // BOOL CDSComponentData::FindUINodeByDN(CUINode* pContainerNode, PCWSTR pszDN, CUINode** ppFoundNode) { if (ppFoundNode == NULL) { return FALSE; } *ppFoundNode = NULL; if (pContainerNode == NULL || !pContainerNode->IsContainer()) { return FALSE; } // // First look through the leaf nodes // CUINodeList* pLeafList = pContainerNode->GetFolderInfo()->GetLeafList(); POSITION leafPos = pLeafList->GetHeadPosition(); while (leafPos != NULL) { CUINode* pCurrentLeaf = pLeafList->GetNext(leafPos); if (pCurrentLeaf == NULL || !IS_CLASS(*pCurrentLeaf, CDSUINode)) { // // We can only search for DNs if the node is a CDSUINode // continue; } CDSCookie* pCurrentCookie = GetDSCookieFromUINode(pCurrentLeaf); LPCWSTR lpszCurrentPath = pCurrentCookie->GetPath(); if (_wcsicmp(lpszCurrentPath, pszDN) == 0) { *ppFoundNode = pCurrentLeaf; return TRUE; } } // // If not found in the leaf list then do a recursive search on the containers // CUINodeList* pContainerList = pContainerNode->GetFolderInfo()->GetContainerList(); POSITION containerPos = pContainerList->GetHeadPosition(); while (containerPos != NULL) { CUINode* pCurrentContainer = pContainerList->GetNext(containerPos); if (pCurrentContainer == NULL || !IS_CLASS(*pCurrentContainer, CDSUINode)) { // // We can only search for DNs if the node is a CDSUINode // continue; } CDSCookie* pCurrentCookie = GetDSCookieFromUINode(pCurrentContainer); LPCWSTR lpszCurrentPath = pCurrentCookie->GetPath(); if (_wcsicmp(lpszCurrentPath, pszDN) == 0) { *ppFoundNode = pCurrentContainer; return TRUE; } else { // // Start the recursion // if (FindUINodeByDN(pCurrentContainer, pszDN, ppFoundNode)) { return TRUE; } } } return FALSE; } // // This looks for nodes in the saved query tree that has the same DN as // the any of the objects in the list and then invalidates the containing // saved query node // void CDSComponentData::InvalidateSavedQueriesContainingObjects(const CUINodeList& refUINodeList) { if (QuerySnapinType() != SNAPINTYPE_SITE) { // // Make a list of DNs // CStringList szDNList; POSITION pos = refUINodeList.GetHeadPosition(); while (pos) { CDSUINode* pDSUINode = dynamic_cast(refUINodeList.GetNext(pos)); if (!pDSUINode) { // // Ignore anything that is not a DS node // continue; } CDSCookie* pCookie = GetDSCookieFromUINode(pDSUINode); if (!pCookie) { ASSERT(FALSE); continue; } szDNList.AddTail(pCookie->GetPath()); } if (szDNList.GetCount() > 0) { // // Now search through saved query tree invalidating query nodes // that contain items in the list // GetFavoritesNodeHolder()->InvalidateSavedQueriesContainingObjects(this, szDNList); } } } // // This looks for nodes in the saved query tree that has the same DN as // the any of the objects in the list and then invalidates the containing // saved query node // void CDSComponentData::InvalidateSavedQueriesContainingObjects(const CStringList& refPathList) { if (QuerySnapinType() != SNAPINTYPE_SITE) { CStringList szDNList; CPathCracker pathCracker; // // Convert all the paths to DNs // POSITION pos = refPathList.GetHeadPosition(); while (pos) { CString szPath = refPathList.GetNext(pos); HRESULT hr = pathCracker.Set((PWSTR)(PCWSTR)szPath, ADS_SETTYPE_FULL); if (SUCCEEDED(hr)) { CComBSTR sbstrDN; hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN, &sbstrDN); if (SUCCEEDED(hr)) { szDNList.AddTail(sbstrDN); } } } if (szDNList.GetCount() > 0) { // // Now search through saved query tree invalidating query nodes // that contain items in the list // GetFavoritesNodeHolder()->InvalidateSavedQueriesContainingObjects(this, szDNList); } } } void CDSComponentData::ReclaimCookies() { AddToLRUList (&m_RootNode); CUINode* pUINode = NULL; POSITION pos, pos2; CUINodeList* pContainers = NULL; #ifdef DBG TRACE (_T("dumping LRU list...\n")); pos = m_LRUList.GetHeadPosition(); while (pos) { pUINode = m_LRUList.GetNext(pos); CUIFolderInfo* pFolderInfo = pUINode->GetFolderInfo(); if (pFolderInfo != NULL) { TRACE (_T("\tcontainer: %s (%d)\n"), pUINode->GetName(), pFolderInfo->GetSerialNumber()); } } #endif // // Get Root folder info // CUIFolderInfo* pRootFolderInfo = m_RootNode.GetFolderInfo(); ASSERT(pRootFolderInfo != NULL); TRACE (_T("-->total count is %d: reclaiming cookies from LRU list...\n"), pRootFolderInfo->GetObjectCount()); UINT maxitems = m_pQueryFilter->GetMaxItemCount(); pos = m_LRUList.GetHeadPosition(); while (pos) { CUIFolderInfo* pUIFolderInfo = NULL; pUINode = m_LRUList.GetNext(pos); pUIFolderInfo = pUINode->GetFolderInfo(); if (pUIFolderInfo != NULL) { TRACE (_T("!!--!!container %s (sn:%d) containing %d objects is being reclaimed\n"), pUINode->GetName(), pUIFolderInfo->GetSerialNumber(), pUIFolderInfo->GetObjectCount()); // // clean all of the leaves out // pUIFolderInfo->DeleteAllLeafNodes(); // // clean all of the containers here out of the tree view // pContainers = pUIFolderInfo->GetContainerList(); if (pContainers) { HSCOPEITEM ItemID; CUINode* pUIContNode= NULL; pos2 = pContainers->GetHeadPosition(); while (pos2) { pUIContNode = pContainers->GetNext(pos2); CUIFolderInfo* pFolderInfo = pUIContNode->GetFolderInfo(); if (pFolderInfo != NULL) { ItemID = pFolderInfo->GetScopeItem(); m_pScope->DeleteItem (ItemID, TRUE); } } } pUIFolderInfo->DeleteAllContainerNodes(); pUIFolderInfo->ReSetExpanded(); if (pRootFolderInfo->GetObjectCount() < (maxitems * 5)) { break; } } } TRACE (_T("--> done reclaiming cookies from LRU list. total count is now %d: ..\n"), pRootFolderInfo->GetObjectCount()); // // Empty the LRU list // while (!m_LRUList.IsEmpty()) { m_LRUList.RemoveTail(); } } BOOL CDSComponentData::IsSelectionAnywhere(CUINode* pUINode) { ASSERT(pUINode->IsContainer()); UINODESELECTION nodeSelection; nodeSelection.pUINode = pUINode; nodeSelection.IsSelection = FALSE; // if any view has this cookie selected, the IsSelection member // will be TRUE when we return. m_pFrame->UpdateAllViews (NULL, (LPARAM)&nodeSelection, DS_IS_COOKIE_SELECTION); return nodeSelection.IsSelection; } void CDSComponentData::AddToLRUList (CUINode* pUINode) { HRESULT hr = S_OK; CUIFolderInfo* pUIFolderInfo = pUINode->GetFolderInfo(); if (pUIFolderInfo != NULL) { CUINodeList* pContainers = pUIFolderInfo->GetContainerList(); CUINode* pUIContNode = NULL; size_t cContainers = pContainers->GetCount(); BOOL foundSpot = FALSE; POSITION pos; if (cContainers > 0) { pos = pContainers->GetHeadPosition(); while (pos) { pUIContNode = pContainers->GetNext(pos); if (pUIContNode != NULL) { AddToLRUList (pUIContNode); } } } // // now we've taken care of the children, let's add // this one to the list // // // first, let's see if it is expanded // this doesn't work currently - asking MMC guys why // SCOPEDATAITEM ScopeData; ZeroMemory (&ScopeData, sizeof(SCOPEDATAITEM)); ScopeData.ID = pUIFolderInfo->GetScopeItem(); ScopeData.mask = SDI_STATE | SDI_PARAM; hr = m_pScope->GetItem (&ScopeData); if (!pUINode->IsSheetLocked() && (!IsSelectionAnywhere (pUINode)) && (pUIFolderInfo->GetSerialNumber() != SERIALNUM_NOT_TOUCHED) && (!((ScopeData.nState & TVIS_EXPANDED) == TVIS_EXPANDED))) { pos = m_LRUList.GetHeadPosition(); if (!pos) { m_LRUList.AddHead(pUINode); TRACE(_T("adding head: %s[%d]\n"), pUINode->GetName(), pUIFolderInfo->GetSerialNumber); } else { CUINode* pLRUNode = NULL; CUIFolderInfo* pLRUFolderInfo = NULL; while (pos) { pLRUNode = m_LRUList.GetAt(pos); pLRUFolderInfo = pLRUNode->GetFolderInfo(); if (pLRUFolderInfo != NULL) { if (pUIFolderInfo->GetSerialNumber() < pLRUFolderInfo->GetSerialNumber()) { foundSpot = TRUE; break; } else { pLRUNode = m_LRUList.GetNext(pos); } } } if (!foundSpot) { m_LRUList.AddTail(pUINode); TRACE(_T("adding tail: %s [%d]\n"), pUINode->GetName(), pUIFolderInfo->GetSerialNumber()); } else { m_LRUList.InsertBefore (pos, pUINode); TRACE(_T("inserting: %s [%d]\n"), pUINode->GetName(), pUIFolderInfo->GetSerialNumber()); } } } } } HRESULT CDSComponentData::_OnNamespaceExtensionExpand(LPDATAOBJECT, HSCOPEITEM hParent) { HRESULT hr = E_FAIL; ASSERT(!m_bRunAsPrimarySnapin); // namespace extension only for DS snapin if (QuerySnapinType() != SNAPINTYPE_DSEX) return hr; // need to crack the data object to set the context // retrieve the query string m_pQueryFilter->SetExtensionFilterString(L"(objectClass=*)"); if (m_bAddRootWhenExtended) { hr = _AddScopeItem(&m_RootNode, hParent); } else { // need to directly expand the root and add children underneath hr = _OnExpand(&m_RootNode, hParent, MMCN_EXPAND); } return hr; } // // Right now this only checks adding group to group and user to group. Any other object class returns FALSE // BOOL CDSComponentData::CanAddCookieToGroup(CDSCookie* pCookie, INT iGroupType, BOOL bMixedMode) { BOOL bCanAdd = FALSE; if (pCookie != NULL) { if (_wcsicmp(pCookie->GetClass(), L"group") == 0) { CDSCookieInfoGroup* pExtraInfo = dynamic_cast(pCookie->GetExtraInfo()); if (pExtraInfo != NULL) { INT iAddGroupType = pExtraInfo->m_GroupType; if (bMixedMode) { // // Determine if the group can't be added // if (iGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - UG SE // bCanAdd = FALSE; } else { // // Mixed Mode // Target - Builtin SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - LG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - Builtin SE // Member - UG SD // bCanAdd = TRUE; } else { // // Mixed Mode // Target - Builtin SE // Member - ? SD // bCanAdd = TRUE; } } } else if (iGroupType & GROUP_TYPE_ACCOUNT_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - GG SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - GG SE // Member - GG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - GG SE // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - GG SE // Member - UG SE // bCanAdd = FALSE; } else { // // Mixed Mode // Target - GG SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - GG SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - GG SE // Member - GG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - GG SE // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - GG SE // Member - UG SD // bCanAdd = FALSE; } else { // // Mixed Mode // Target - GG SE // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_RESOURCE_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - LG SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - LG SE // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - LG SE // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - LG SE // Member - UG SE // bCanAdd = FALSE; } else { // // Mixed Mode // Target - LG SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - LG SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - LG SE // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - LG SE // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - LG SE // Member - UG SD // bCanAdd = TRUE; } else { // // Mixed Mode // Target - LG SE // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - UG SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - UG SE // Member - GG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - UG SE // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - UG SE // Member - UG SE // bCanAdd = FALSE; } else { // // Mixed Mode // Target - UG SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - UG SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - UG SE // Member - GG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - UG SE // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - UG SE // Member - UG SD // bCanAdd = FALSE; } else { // // Mixed Mode // Target - UG SE // Member - ? SD // bCanAdd = FALSE; } } } else { // // Mixed Mode // Target - ? SE // Member - ? ? // bCanAdd = FALSE; } } else // Distribution group { if (iGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - UG SE // bCanAdd = TRUE; } else { // // Mixed Mode // Target - Builtin SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - Builtin SD // Member - UG SD // bCanAdd = TRUE; } else { // // Mixed Mode // Target - Builtin SD // Member - ? SD // bCanAdd = TRUE; } } } else if (iGroupType & GROUP_TYPE_ACCOUNT_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - GG SD // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - GG SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - GG SD // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - GG SD // Member - UG SE // bCanAdd = FALSE; } else { // // Mixed Mode // Target - GG SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - GG SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - GG SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - GG SD // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - GG SD // Member - UG SD // bCanAdd = FALSE; } else { // // Mixed Mode // Target - GG SD // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_RESOURCE_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - LG SD // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - LG SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - LG SD // Member - LG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - LG SD // Member - UG SE // bCanAdd = FALSE; } else { // // Mixed Mode // Target - LG SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - LG SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - LG SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - LG SD // Member - LG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - LG SD // Member - UG SD // bCanAdd = TRUE; } else { // // Mixed Mode // Target - LG SD // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - UG SD // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - UG SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - UG SD // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - UG SD // Member - UG SE // bCanAdd = FALSE; } else { // // Mixed Mode // Target - UG SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Mixed Mode // Target - UG SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Mixed Mode // Target - UG SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Mixed Mode // Target - UG SD // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Mixed Mode // Target - UG SD // Member - UG SD // bCanAdd = TRUE; } else { // // Mixed Mode // Target - UG SD // Member - ? SD // bCanAdd = FALSE; } } } else { // // Mixed Mode // Target - ? SD // Member - ? ? // bCanAdd = FALSE; } } } else // native mode { // // Determine if the group can't be added // if (iGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - Builtin SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - Builtin SE // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - Builtin SE // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - Builtin SE // Member - UG SE // bCanAdd = FALSE; } else { // // Native Mode // Target - Builtin SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - Builtin SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - Builtin SE // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - Builtin SE // Member - LG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - Builtin SE // Member - UG SD // bCanAdd = TRUE; } else { // // Native Mode // Target - Builtin SE // Member - ? SD // bCanAdd = TRUE; } } } else if (iGroupType & GROUP_TYPE_ACCOUNT_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - GG SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - GG SE // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - GG SE // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - GG SE // Member - UG SE // bCanAdd = FALSE; } else { // // Native Mode // Target - GG SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - GG SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - GG SE // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - GG SE // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - GG SE // Member - UG SD // bCanAdd = FALSE; } else { // // Native Mode // Target - GG SE // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_RESOURCE_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - LG SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - LG SE // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - LG SE // Member - LG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - LG SE // Member - UG SE // bCanAdd = TRUE; } else { // // Native Mode // Target - LG SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - LG SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - LG SE // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - LG SE // Member - LG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - LG SE // Member - UG SD // bCanAdd = TRUE; } else { // // Native Mode // Target - LG SE // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - UG SE // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - UG SE // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - UG SE // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - UG SE // Member - UG SE // bCanAdd = TRUE; } else { // // Native Mode // Target - UG SE // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - UG SE // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - UG SE // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - UG SE // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - UG SE // Member - UG SD // bCanAdd = TRUE; } else { // // Native Mode // Target - UG SE // Member - ? SD // bCanAdd = FALSE; } } } else { // // Native Mode // Target - ? SE // Member - ? ? // bCanAdd = FALSE; } } else // Distribution group { if (iGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - Builtin SD // Member - Buitlin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - Builtin SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - Builtin SD // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - Builtin SD // Member - UG SE // bCanAdd = TRUE; } else { // // Native Mode // Target - Builtin SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - Builtin SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - Builtin SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - Builtin SD // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - Builtin SD // Member - UG SD // bCanAdd = TRUE; } else { // // Native Mode // Target - Builtin SD // Member - ? SD // bCanAdd = TRUE; } } } else if (iGroupType & GROUP_TYPE_ACCOUNT_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - GG SD // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - GG SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - GG SD // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - GG SD // Member - UG SE // bCanAdd = FALSE; } else { // // Native Mode // Target - GG SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - GG SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - GG SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - GG SD // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - GG SD // Member - UG SD // bCanAdd = FALSE; } else { // // Native Mode // Target - GG SD // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_RESOURCE_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - LG SD // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - LG SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - LG SD // Member - LG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - LG SD // Member - UG SE // bCanAdd = TRUE; } else { // // Native Mode // Target - LG SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - LG SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - LG SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - LG SD // Member - LG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - LG SD // Member - UG SD // bCanAdd = TRUE; } else { // // Native Mode // Target - LG SD // Member - ? SD // bCanAdd = FALSE; } } } else if (iGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { if (iAddGroupType & GROUP_TYPE_SECURITY_ENABLED) { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - UG SD // Member - Builtin SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - UG SD // Member - GG SE // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - UG SD // Member - LG SE // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - UG SD // Member - UG SE // bCanAdd = TRUE; } else { // // Native Mode // Target - UG SD // Member - ? SE // bCanAdd = FALSE; } } else // group to add is a distribution group { if (iAddGroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP) { // // Native Mode // Target - UG SD // Member - Builtin SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_ACCOUNT_GROUP) { // // Native Mode // Target - UG SD // Member - GG SD // bCanAdd = TRUE; } else if (iAddGroupType & GROUP_TYPE_RESOURCE_GROUP) { // // Native Mode // Target - UG SD // Member - LG SD // bCanAdd = FALSE; } else if (iAddGroupType & GROUP_TYPE_UNIVERSAL_GROUP) { // // Native Mode // Target - UG SD // Member - UG SD // bCanAdd = TRUE; } else { // // Native Mode // Target - UG SD // Member - ? SD // bCanAdd = FALSE; } } } else { // // Native Mode // Target - ? SD // Member - ? ? // bCanAdd = FALSE; } } } } } else if (_wcsicmp(pCookie->GetClass(), L"user") == 0 || #ifdef INETORGPERSON _wcsicmp(pCookie->GetClass(), L"inetOrgPerson") == 0 || #endif _wcsicmp(pCookie->GetClass(), L"contact") == 0 || _wcsicmp(pCookie->GetClass(), L"computer") == 0) { bCanAdd = TRUE; } else { BOOL bSecurity = (iGroupType & GROUP_TYPE_SECURITY_ENABLED) ? TRUE : FALSE; bCanAdd = m_pClassCache->CanAddToGroup(GetBasePathsInfo(), pCookie->GetClass(), bSecurity); } } else { bCanAdd = TRUE; } return bCanAdd; } //////////////////////////////////////////////////////////////////// // CDSComponentData thread API's BOOL CDSComponentData::_StartBackgroundThread() { ASSERT(m_pHiddenWnd != NULL); ASSERT(::IsWindow(m_pHiddenWnd->m_hWnd)); if ((m_pHiddenWnd == NULL) || !::IsWindow(m_pHiddenWnd->m_hWnd) ) return FALSE; CDispatcherThread* pThreadObj = new CDispatcherThread; ASSERT(pThreadObj != NULL); if (pThreadObj == NULL) return FALSE; // start the the thread ASSERT(m_pBackgroundThreadInfo->m_nThreadID == 0); ASSERT(m_pBackgroundThreadInfo->m_hThreadHandle == NULL); ASSERT(m_pBackgroundThreadInfo->m_state == notStarted); ASSERT(pThreadObj->m_bAutoDelete); if (!pThreadObj->Start(m_pHiddenWnd->m_hWnd, this)) return FALSE; ASSERT(pThreadObj->m_nThreadID != 0); ASSERT(pThreadObj->m_hThread != NULL); // copy the thread info we need from the thread object m_pBackgroundThreadInfo->m_hThreadHandle = pThreadObj->m_hThread; m_pBackgroundThreadInfo->m_nThreadID = pThreadObj->m_nThreadID; // wait for the thread to start and be ready to receive messages _WaitForBackGroundThreadStartAck(); ASSERT(m_pBackgroundThreadInfo->m_state == running); TRACE(L"dispatcher thread (HANDLE = 0x%x) running\n", m_pBackgroundThreadInfo->m_hThreadHandle); return TRUE; } void CDSComponentData::_WaitForBackGroundThreadStartAck() { ASSERT(m_pHiddenWnd != NULL); ASSERT(::IsWindow(m_pHiddenWnd->m_hWnd)); ASSERT(m_pBackgroundThreadInfo->m_state == notStarted); MSG tempMSG; while(m_pBackgroundThreadInfo->m_state == notStarted) { if (::PeekMessage(&tempMSG,m_pHiddenWnd->m_hWnd,CHiddenWnd::s_ThreadStartNotificationMessage, CHiddenWnd::s_ThreadStartNotificationMessage, PM_REMOVE)) { DispatchMessage(&tempMSG); } } ASSERT(m_pBackgroundThreadInfo->m_state == running); } void CDSComponentData::_ShutDownBackgroundThread() { TRACE(L"CDSComponentData::_ShutDownBackgroundThread()\n"); // set thread state to shutdown mode // to avoid any spurious processing ASSERT(m_pBackgroundThreadInfo->m_nThreadID != 0); ASSERT(m_pBackgroundThreadInfo->m_hThreadHandle != NULL); ASSERT(m_pBackgroundThreadInfo->m_state == running); m_pBackgroundThreadInfo->m_state = shuttingDown; // post a message to the dispatcher thread to signal shutdown _PostMessageToBackgroundThread(THREAD_SHUTDOWN_MSG, 0,0); // wait for the dispatcher thread to acknowledge // (i.e. all worker threads have shut down) TRACE(L"Waiting for CHiddenWnd::s_ThreadShutDownNotificationMessage\n"); MSG tempMSG; while(m_pBackgroundThreadInfo->m_state == shuttingDown) { if (::PeekMessage(&tempMSG,m_pHiddenWnd->m_hWnd,CHiddenWnd::s_ThreadShutDownNotificationMessage, CHiddenWnd::s_ThreadShutDownNotificationMessage, PM_REMOVE)) { DispatchMessage(&tempMSG); } } ASSERT(m_pBackgroundThreadInfo->m_state == terminated); // wait for the dispatcher thread handle to become signalled TRACE(L"before WaitForThreadShutdown(0x%x) on dispatcher thread\n", m_pBackgroundThreadInfo->m_hThreadHandle); WaitForThreadShutdown(&(m_pBackgroundThreadInfo->m_hThreadHandle), 1); TRACE(L"after WaitForThreadShutdown() on dispatcher thread\n"); } BOOL CDSComponentData::_PostQueryToBackgroundThread(CUINode* pUINode) { CThreadQueryInfo* pQueryInfo = NULL; if (pUINode == &m_RootNode) { // enumerating the root of the namespace CDSThreadQueryInfo* pDSQueryInfo = new CDSThreadQueryInfo; pDSQueryInfo->SetQueryDSQueryParameters(rootFolder, m_RootNode.GetPath(), NULL, // class m_pQueryFilter->GetQueryString(), m_pQueryFilter->GetMaxItemCount(), TRUE, // bOneLevel m_RootNode.GetColumnSet(this)->GetColumnID()); pQueryInfo = pDSQueryInfo; } else if (IS_CLASS(*pUINode, CDSUINode)) { // enumerating regular DS folder CDSThreadQueryInfo* pDSQueryInfo = new CDSThreadQueryInfo; CDSCookie* pCookie = GetDSCookieFromUINode(pUINode); ASSERT(pCookie != NULL); pDSQueryInfo->SetQueryDSQueryParameters(dsFolder, pCookie->GetPath(), pCookie->GetClass(), m_pQueryFilter->GetQueryString(), m_pQueryFilter->GetMaxItemCount(), TRUE, // bOneLevel pUINode->GetColumnSet(this)->GetColumnID()); pQueryInfo = pDSQueryInfo; } else if (IS_CLASS(*pUINode, CSavedQueryNode)) { // enumerating a saved query folder CDSThreadQueryInfo* pDSQueryInfo = new CDSThreadQueryInfo; if (pDSQueryInfo != NULL) { CSavedQueryNode* pSavedQueryNode = dynamic_cast(pUINode); ASSERT(pSavedQueryNode != NULL); if (pSavedQueryNode != NULL) { if (pSavedQueryNode->IsFilterLastLogon()) { if (GetBasePathsInfo()->GetDomainBehaviorVersion() == DS_BEHAVIOR_WIN2000) { CString szText, szCaption; VERIFY(szText.LoadString(IDS_FILTER_LAST_LOGON_VERSION)); VERIFY(szCaption.LoadString(IDS_DSSNAPINNAME)); MessageBox(GetHWnd(), szText, szCaption, MB_OK | MB_ICONSTOP); return FALSE; } } pDSQueryInfo->SetQueryDSQueryParameters(queryFolder, pSavedQueryNode->GetRootPath(), NULL, // class pSavedQueryNode->GetQueryString(), UINT_MAX, // don't limit the number of items the query returns pSavedQueryNode->IsOneLevel(), pUINode->GetColumnSet(this)->GetColumnID()); pQueryInfo = pDSQueryInfo; } else { TRACE(_T("Failed to dynamically cast to CSavedQueryNode in CDSComponentData::_PostQueryToBackgroundThread()")); ASSERT(FALSE); } } else { TRACE(_T("Failed to allocate memory for CDSThreadQueryInfo in CDSComponentData::_PostQueryToBackgroundThread()")); ASSERT(FALSE); } } if (pQueryInfo == NULL) { return FALSE; } TRACE(_T("CDSComponentData::_PostQueryToBackgroundThread: cookie is %s\n"), pUINode->GetName()); ASSERT(pUINode->IsContainer()); ASSERT(m_pBackgroundThreadInfo->m_nThreadID != 0); ASSERT(m_pBackgroundThreadInfo->m_hThreadHandle != NULL); ASSERT(m_pBackgroundThreadInfo->m_state == running); m_queryNodeTable.Add(pUINode); m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_VERB_UPDATE); VERIFY(SUCCEEDED(ChangeScopeItemIcon(pUINode))); TRACE(L"CDSComponentData::_PostQueryToBackgroundThread: posting DISPATCH_THREAD_RUN_MSG\n"); return _PostMessageToBackgroundThread(DISPATCH_THREAD_RUN_MSG, (WPARAM)pUINode, (LPARAM)pQueryInfo); } BOOL CDSComponentData::_PostMessageToBackgroundThread(UINT Msg, WPARAM wParam, LPARAM lParam) { ASSERT(m_pBackgroundThreadInfo->m_nThreadID != 0); ASSERT(m_pBackgroundThreadInfo->m_hThreadHandle != NULL); return ::PostThreadMessage(m_pBackgroundThreadInfo->m_nThreadID, Msg, wParam, lParam); } void CDSComponentData::_OnTooMuchData(CUINode* pUINode) { if (!m_queryNodeTable.IsPresent(pUINode)) return; // cookie not found, node not there anymore AFX_MANAGE_STATE(AfxGetStaticModuleState()); BOOL bHandledWithApproximation = FALSE; CDSCookie* pDSCookie = GetDSCookieFromUINode(pUINode); if (pDSCookie != NULL) { CString szPath; GetBasePathsInfo()->ComposeADsIPath(szPath, pDSCookie->GetPath()); // // Bind to the object and determine approximately how many // objects are in the container // CComPtr spDirObject; HRESULT hr = DSAdminOpenObject(szPath, IID_IDirectoryObject, (PVOID*)&spDirObject, TRUE /*bServer*/); if (SUCCEEDED(hr)) { // // Retrieve the approximation through the constructed attribute // const int iAttrCount = 1; PWSTR pszAttribs[] = { L"msDS-Approx-Immed-Subordinates" }; PADS_ATTR_INFO pAttrInfo = NULL; DWORD dwNumRet = 0; CComVariant var; hr = spDirObject->GetObjectAttributes(pszAttribs, iAttrCount, &pAttrInfo, &dwNumRet); if (SUCCEEDED(hr)) { ASSERT(dwNumRet == 1); ASSERT(pAttrInfo != NULL && pAttrInfo->pADsValues != NULL); if (dwNumRet == 1 && pAttrInfo != NULL && pAttrInfo->pADsValues != NULL) { UINT nCount = static_cast(pAttrInfo->pADsValues->Integer); UINT nRetrieved = m_pQueryFilter->GetMaxItemCount(); UINT nApprox = __max(nCount, nRetrieved); // // Format the message // CString szMsg; szMsg.Format(IDS_MSG_QUERY_TOO_MANY_ITEMS_WITH_APPROX, nRetrieved, nApprox, pUINode->GetName()); PVOID apv[1] = {(LPWSTR)(LPCWSTR)szMsg}; ReportErrorEx (m_hwnd,IDS_STRING,S_OK, MB_OK | MB_ICONINFORMATION, apv, 1); // // We were able to retrieve the approximation of the contained objects and post an error // so we don't have to resort to the old message // bHandledWithApproximation = TRUE; pUINode->GetFolderInfo()->SetTooMuchData(TRUE, nCount); m_pFrame->UpdateAllViews (NULL, NULL, DS_UPDATE_OBJECT_COUNT); } if (pAttrInfo != NULL) { FreeADsMem(pAttrInfo); pAttrInfo = NULL; } } } } // // Resort to using the old message if we are unable to retrieve the approximation // if (!bHandledWithApproximation) { CString szFmt; szFmt.LoadString(IDS_MSG_QUERY_TOO_MANY_ITEMS); CString szMsg; szMsg.Format(szFmt, pUINode->GetName()); PVOID apv[1] = {(LPWSTR)(LPCWSTR)szMsg}; ReportErrorEx (m_hwnd,IDS_STRING,S_OK, MB_OK | MB_ICONINFORMATION, apv, 1); } } void CDSComponentData::AddScopeItemToUI(CUINode* pUINode, BOOL bSetSelected) { if (pUINode->IsContainer()) { CUIFolderInfo* pParentInfo = pUINode->GetFolderInfo()->GetParentNode()->GetFolderInfo(); if (pParentInfo != NULL) { _AddScopeItem(pUINode, pParentInfo->GetScopeItem(), bSetSelected); } } } void CDSComponentData::AddListOfNodesToUI(CUINode* pUINode, CUINodeList* pNodeList) { CComPtr spDataObj; HRESULT hr = QueryDataObject ((MMC_COOKIE)pUINode, CCT_SCOPE, &spDataObj); ASSERT(SUCCEEDED(hr)); // add the icon just in case m_pFrame->UpdateAllViews(spDataObj, /*unused*/(LPARAM)0, DS_ICON_STRIP_UPDATE); TIMER(_T("adding containers to scope pane\n")); // the cookie is good, add all the cookies for (POSITION pos = pNodeList->GetHeadPosition(); pos != NULL; ) { CUINode* pNewUINode = pNodeList->GetNext(pos); pUINode->GetFolderInfo()->AddNode(pNewUINode); // add to the linked lists if (pNewUINode->IsContainer()) { // add to the scope pane _AddScopeItem(pNewUINode, pUINode->GetFolderInfo()->GetScopeItem()); } } // for // for the leaf nodes, do a bulk update on the result pane TIMER(_T("sending have-data notification to views\n")); m_pFrame->UpdateAllViews(spDataObj, (LPARAM)pNodeList, DS_HAVE_DATA); } HRESULT CDSComponentData::ReadUINodeFromLdapPath(IN CDSUINode* pContainerDSUINode, IN LPCWSTR lpszLdapPath, OUT CDSUINode** ppSUINodeNew) { CDSCookie* pNewCookie = NULL; HRESULT hr = GetActiveDS()->ReadDSObjectCookie(pContainerDSUINode, lpszLdapPath, &pNewCookie); if (SUCCEEDED(hr) && (hr != S_FALSE) && (pNewCookie != NULL)) { // make sure we update the icon cache m_pFrame->UpdateAllViews(/*unused*/NULL /*pDataObj*/, /*unused*/(LPARAM)0, DS_ICON_STRIP_UPDATE); // create a UI node to hold the cookie *ppSUINodeNew = new CDSUINode(NULL); (*ppSUINodeNew)->SetCookie(pNewCookie); if (pNewCookie->IsContainerClass()) { (*ppSUINodeNew)->MakeContainer(); } } return hr; } void CDSComponentData::_OnHaveData(CUINode* pUINode, CThreadQueryResult* pResult) { ASSERT(pUINode != NULL); ASSERT(pUINode->IsContainer()); TRACE(_T("CDSComponentData::_OnHaveData()\n")); if ( m_queryNodeTable.IsPresent(pUINode) && (pResult != NULL) ) { AddListOfNodesToUI(pUINode, &(pResult->m_nodeList)); pResult->m_bOwnMemory = FALSE; // relinquish ownership of pointers } if (m_RootNode.GetFolderInfo()->GetObjectCount() > (m_pQueryFilter->GetMaxItemCount() * 5)) { ReclaimCookies(); } if (pResult != NULL) { delete pResult; } } void CDSComponentData::_OnDone(CUINode* pUINode, HRESULT hr) { ASSERT(pUINode != NULL); ASSERT(pUINode->IsContainer()); if (!m_queryNodeTable.Remove(pUINode)) return; // cookie not found, node not there anymore // change the icon state pUINode->SetExtOp(SUCCEEDED(hr) ? 0 : OPCODE_ENUM_FAILED); VERIFY(SUCCEEDED(ChangeScopeItemIcon(pUINode))); m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_VERB_UPDATE); // update serial number pUINode->GetFolderInfo()->UpdateSerialNumber(this); TIMER(_T("got on-done notification\n")); if (SUCCEEDED(hr)) { if (pUINode->GetExtOp() & OPCODE_EXPAND_IN_PROGRESS) { m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_DELAYED_EXPAND); } } else if (m_InitSuccess) { if (IS_CLASS(*pUINode, CSavedQueryNode)) { CSavedQueryNode* pQueryNode = dynamic_cast(pUINode); if (pQueryNode != NULL) { if (HRESULT_CODE(hr) == ERROR_DS_FILTER_UNKNOWN) { // // Error message for an invalid query filter // PVOID apv[2] = {(PVOID)pQueryNode->GetQueryString()}; ReportErrorEx (m_hwnd,IDS_ERRMSG_QUERY_FILTER_NOT_VALID, hr, MB_OK | MB_ICONERROR, apv, 1); } else if (HRESULT_CODE(hr) == ERROR_DS_NO_SUCH_OBJECT) { // // Error message for an invalid query root // PVOID apv[2] = {(PVOID)pQueryNode->GetRootPath(), (PVOID)GetBasePathsInfo()->GetServerName()}; ReportErrorEx (m_hwnd,IDS_ERRMSG_QUERY_ROOT_NOT_VALID, hr, MB_OK | MB_ICONERROR, apv, 2); } else { // // Error message for any other error // ReportErrorEx (m_hwnd,IDS_ERRMSG_QUERY_FAILED, hr, MB_OK | MB_ICONERROR, NULL, 0); } } } else { PVOID apv[2] = {(PVOID)GetBasePathsInfo()->GetServerName(), (PVOID)pUINode->GetName()}; ReportErrorEx (m_hwnd,IDS_12_CANT_GET_DATA, hr, MB_OK | MB_ICONERROR, apv, 2); } } SortResultPane(pUINode); } void CDSComponentData::_OnSheetClose(CUINode* /*pUINode*/) { /* ASSERT(pUINode != NULL); // REVIEW_MARCOC_PORT: sheet locking is skipped for // DS nodes, because we let them float CDSUINode* pDSUINode = dynamic_cast(pUINode); if (pDSUINode != NULL) { return; } // not a DS object, need too do the usual thing _SheetUnlockCookie(pUINode); */ } HRESULT CreateSecondarySheet(HWND hWndParent, LPCONSOLE pIConsole, IUnknown* pUnkComponentData, CDSUINode* pCookie, IDataObject* pDataObject, LPCWSTR lpszTitle) { ASSERT(pIConsole != NULL); ASSERT(pDataObject != NULL); ASSERT(pUnkComponentData != NULL); // get an interface to a sheet provider CComPtr spSheetProvider; HRESULT hr = pIConsole->QueryInterface(IID_IPropertySheetProvider,(void**)&spSheetProvider); ASSERT(SUCCEEDED(hr)); ASSERT(spSheetProvider != NULL); // get an interface to a sheet callback CComPtr spSheetCallback; hr = pIConsole->QueryInterface(IID_IPropertySheetCallback,(void**)&spSheetCallback); ASSERT(SUCCEEDED(hr)); ASSERT(spSheetCallback != NULL); ASSERT(pDataObject != NULL); // get a sheet MMC_COOKIE cookie = reinterpret_cast(pCookie); hr = spSheetProvider->CreatePropertySheet(lpszTitle, TRUE, cookie, pDataObject, 0x0 /*dwOptions*/); ASSERT(SUCCEEDED(hr)); hr = spSheetProvider->AddPrimaryPages(pUnkComponentData, FALSE /*bCreateHandle*/, hWndParent, FALSE /* bScopePane*/); hr = spSheetProvider->AddExtensionPages(); ASSERT(SUCCEEDED(hr)); hr = spSheetProvider->Show(reinterpret_cast(hWndParent), 0); ASSERT(SUCCEEDED(hr)); return hr; } void CDSComponentData::_OnSheetCreate(PDSA_SEC_PAGE_INFO pDsaSecondaryPageInfo) { ASSERT(pDsaSecondaryPageInfo != NULL); // // get the info from the packed structure // HWND hwndParent = pDsaSecondaryPageInfo->hwndParentSheet; LPCWSTR lpszTitle = (LPCWSTR)((BYTE*)pDsaSecondaryPageInfo + pDsaSecondaryPageInfo->offsetTitle); DSOBJECTNAMES* pDsObjectNames = &(pDsaSecondaryPageInfo->dsObjectNames); ASSERT(pDsObjectNames->cItems == 1); DSOBJECT* pDsObject = &(pDsObjectNames->aObjects[0]); LPCWSTR lpszName = (LPCWSTR)((BYTE*)pDsObject + pDsObject->offsetName); LPCWSTR lpszClass = (LPCWSTR)((BYTE*)pDsObject + pDsObject->offsetClass); CDSUINode* pDSUINode = 0; CDSCookie* pNewCookie = 0; try { // // Create a node and cookie // pDSUINode = new CDSUINode(NULL); if (!pDSUINode) { return; } pNewCookie = new CDSCookie(); if (!pNewCookie) { delete pDSUINode; pDSUINode = 0; return; } } catch(CMemoryException *) { if (pDSUINode) { delete pDSUINode; pDSUINode = 0; } if (pNewCookie) { delete pNewCookie; pNewCookie = 0; } return; } // // get the DN out of the LDAP path // CString szLdapPath = lpszName; CString szDN; StripADsIPath(szLdapPath, szDN); pNewCookie->SetPath(szDN); CDSClassCacheItemBase* pItem = m_pClassCache->FindClassCacheItem(this, lpszClass, szLdapPath); ASSERT(pItem != NULL); if (pItem == NULL) { delete pDSUINode; pDSUINode = 0; delete pNewCookie; pNewCookie = 0; return; } pNewCookie->SetCacheItem(pItem); // // Set the cookie in the node (from now on the node owns the cookie and its memory // pDSUINode->SetCookie(pNewCookie); if (pNewCookie->IsContainerClass()) { pDSUINode->MakeContainer(); } // // with the cookie, can call into ourselves to get a data object // CComPtr spDataObject; MMC_COOKIE cookie = reinterpret_cast(pDSUINode); HRESULT hr = QueryDataObject(cookie, CCT_UNINITIALIZED, &spDataObject); if (FAILED(hr) || (spDataObject == NULL) || IsSheetAlreadyUp(spDataObject)) { // // we failed to create a data object (rare) // or the sheet is already up // delete pDSUINode; pDSUINode = 0; return; } // // Pass the parent sheet handle to the data object. // PROPSHEETCFG SheetCfg = {0}; SheetCfg.hwndParentSheet = hwndParent; FORMATETC fe = {CDSDataObject::m_cfPropSheetCfg, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM sm = {TYMED_HGLOBAL, NULL, NULL}; sm.hGlobal = (HGLOBAL)&SheetCfg; hr = spDataObject->SetData(&fe, &sm, FALSE); ASSERT(SUCCEEDED(hr)); // // with the data object, call into MMC to get the sheet // hr = CreateSecondarySheet(GetHWnd(), m_pFrame, GetUnknown(), pDSUINode, spDataObject, lpszTitle); delete pDSUINode; } HRESULT CDSComponentData::SelectScopeNode(CUINode* pUINode) { if (!pUINode->IsContainer()) { ASSERT(pUINode->IsContainer()); return E_INVALIDARG; } return m_pFrame->SelectScopeItem(pUINode->GetFolderInfo()->GetScopeItem()); } void CDSComponentData::SortResultPane(CUINode* pUINode) { if(pUINode != NULL) m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_SORT_RESULT_PANE); } HRESULT CDSComponentData::QueryFromWorkerThread(CThreadQueryInfo* pQueryInfo, CWorkerThread* pWorkerThread) { HRESULT hr = S_OK; if (!m_InitSuccess) return E_FAIL; //if (IDYES == ::MessageBox (NULL, L"Fail Query ?", L"DS Admin", MB_YESNO)) //{ // return E_FAIL; //} // function called in the context of a worker thread if (IS_CLASS(*pQueryInfo, CDSThreadQueryInfo)) { CDSThreadQueryInfo* pDSQueryInfo = dynamic_cast(pQueryInfo); if (pDSQueryInfo != NULL) { ASSERT(pDSQueryInfo->GetType() != unk); if (pDSQueryInfo->GetType() == rootFolder) { hr = m_ActiveDS->EnumerateRootContainer(pDSQueryInfo, pWorkerThread); } else if ((pDSQueryInfo->GetType() == dsFolder) || (pDSQueryInfo->GetType() == queryFolder)) { hr = m_ActiveDS->EnumerateContainer(pDSQueryInfo, pWorkerThread); } } else { TRACE(_T("Failed to dynamically cast to CDSThreadQueryInfo in CDSComponentData::QueryFromWorkerThread()")); ASSERT(FALSE); hr = E_OUTOFMEMORY; } } return hr; } BOOL CDSComponentData::CanEnableVerb(CUINode* pUINode) { return !m_queryNodeTable.IsLocked(pUINode); } int CDSComponentData::GetImage(CUINode* pNode, BOOL bOpen) { ASSERT(pNode != NULL); int imageIndex = -1; if (m_queryNodeTable.IsPresent(pNode)) { // executing a query, same icon across the board imageIndex = m_iconManager.GetWaitIndex(); } else if (pNode->GetExtOp() & OPCODE_ENUM_FAILED) { // error condition if (pNode == GetRootNode()) imageIndex = m_iconManager.GetRootErrIndex(); else imageIndex = m_iconManager.GetWarnIndex(); } else { // normal state icon for the cookie if (pNode == GetRootNode()) { // this is the root imageIndex = m_iconManager.GetRootIndex(); } else if (IS_CLASS(*pNode, CFavoritesNode)) { imageIndex = m_iconManager.GetFavoritesIndex(); } else if (IS_CLASS(*pNode, CSavedQueryNode)) { CSavedQueryNode* pSavedQueryNode = dynamic_cast(pNode); if (pSavedQueryNode->IsValid()) { imageIndex = m_iconManager.GetQueryIndex(); } else { imageIndex = m_iconManager.GetQueryInvalidIndex(); } } else { imageIndex = pNode->GetImage(bOpen); } } TRACE(_T("CDSComponentData::GetImage() returning: %d\n"), imageIndex); return imageIndex; } void CDSComponentData::_SheetLockCookie(CUINode* pNode) { pNode->IncrementSheetLockCount(); m_sheetNodeTable.Add(pNode); } void CDSComponentData::_SheetUnlockCookie(CUINode* pNode) { pNode->DecrementSheetLockCount(); m_sheetNodeTable.Remove(pNode); } BOOL CDSComponentData::_WarningOnSheetsUp(CUINode* pNode, BOOL bShowMessage, BOOL bActivate) { if (!pNode->IsSheetLocked()) return FALSE; // no warning, all is cool if (bShowMessage) { // warning to user that oeration cannot be performed ReportErrorEx (m_hwnd,IDS_SHEETS_UP_DELETE,S_OK, MB_OK | MB_ICONINFORMATION, NULL, 0); } // need to bring sheets on the foreground and activate it m_sheetNodeTable.BringToForeground(pNode, this, bActivate); return TRUE; } BOOL CDSComponentData::_WarningOnSheetsUp(CInternalFormatCracker* pInternalFormatCracker) { ASSERT(pInternalFormatCracker != NULL); if (!pInternalFormatCracker->HasData()) { return FALSE; } UINT cCookieTotalCount = pInternalFormatCracker->GetCookieCount(); // // protect against operations with sheets up // BOOL bStop = FALSE; BOOL bFirstOne = TRUE; for (UINT cCount=0; cCount < cCookieTotalCount; cCount++) { CUINode* pUINode = pInternalFormatCracker->GetCookie(cCount); if (_WarningOnSheetsUp(pUINode, bFirstOne, bFirstOne)) { bStop = TRUE; bFirstOne = FALSE; } } // for return bStop; } HRESULT CDSComponentData::ColumnsChanged(CDSEvent* pDSEvent, CUINode* pUINode, MMC_VISIBLE_COLUMNS* pVisibleColumns, BOOL bRefresh) { ASSERT(pUINode != NULL); ASSERT(pUINode->IsContainer()); if (bRefresh && m_RootNode.IsSheetLocked()) { // warning to user that oeration cannot be performed ReportErrorEx (m_hwnd,IDS_SHEETS_UP_COLUMNS_CHANGED,S_OK, MB_OK | MB_ICONINFORMATION, NULL, 0); // need to bring sheets on the foreground and activate it m_sheetNodeTable.BringToForeground(&m_RootNode, this, TRUE); // tell MMC to discard the column changes return E_UNEXPECTED; } CDSColumnSet* pColumnSet = pUINode->GetColumnSet(this); pColumnSet->ClearVisibleColumns(); if (pVisibleColumns != NULL) { ASSERT(pDSEvent != NULL); pDSEvent->SetUpdateAllViewsOrigin(TRUE); pColumnSet->AddVisibleColumns(pVisibleColumns); // set the dirty flag, need to save to stream to be in sync m_bDirty = TRUE; } m_pFrame->UpdateAllViews(NULL, (LPARAM)pUINode, DS_UPDATE_VISIBLE_COLUMNS); if (pDSEvent != NULL) pDSEvent->SetUpdateAllViewsOrigin(FALSE); if (IS_CLASS(*pUINode, CSavedQueryNode)) { Refresh(pUINode); } else { if (bRefresh) { ASSERT(!m_RootNode.IsSheetLocked()); ::PostMessage(m_pHiddenWnd->m_hWnd, CHiddenWnd::s_RefreshAllNotificationMessage, 0, 0); } } return S_OK; } void CDSComponentData::ForceRefreshAll() { m_bDirty = TRUE; RefreshAll(); } HRESULT CDSComponentData::SetRenameMode(CUINode* pUINode) { HRESULT hr = S_OK; if (pUINode->IsContainer()) { CUIFolderInfo* pFolderInfo = pUINode->GetFolderInfo(); hr = m_pFrame->RenameScopeItem(pFolderInfo->GetScopeItem()); } else { // // REVIEW_JEFFJON : Codework to implement for result pane items // Need to do an UpdateAllViews with new message and handler // } return hr; } ///////////////////////////////////////////////////////////////////// // functionality for snapin CoClasses SnapinType CDSSnapin::QuerySnapinType() {return SNAPINTYPE_DS;} SnapinType CDSSnapinEx::QuerySnapinType() {return SNAPINTYPE_DSEX;} SnapinType CSiteSnapin::QuerySnapinType() {return SNAPINTYPE_SITE;} int ResourceIDForSnapinType[SNAPINTYPE_NUMTYPES] = { IDS_DSSNAPINNAME, IDS_DS_MANAGER_EX, IDS_SITESNAPINNAME }; ///////////////////////////////////////////////////////////////////// // CDSSnapin (DS standalone) CDSSnapin::CDSSnapin() { m_lpszSnapinHelpFile = L"dsadmin.chm"; } ///////////////////////////////////////////////////////////////////// // CDSSnapinEx (DS namespace extension) CDSSnapinEx::CDSSnapinEx() { m_bRunAsPrimarySnapin = FALSE; m_bAddRootWhenExtended = TRUE; m_lpszSnapinHelpFile = L"dsadmin.chm"; } ///////////////////////////////////////////////////////////////////// // CSiteSnapin (Site manager standalone) CSiteSnapin::CSiteSnapin() { m_lpszSnapinHelpFile = L"dssite.chm"; } ////////////////////////////////////////////////////////////////////////// // CDSSnapinAbout CDSSnapinAbout::CDSSnapinAbout() { m_uIdStrProvider = IDS_SNAPIN_PROVIDER; m_uIdStrVersion = IDS_SNAPIN_VERSION; m_uIdStrDestription = IDS_SNAPINABOUT_DESCRIPTION; m_uIdIconImage = IDI_DSADMIN; m_uIdBitmapSmallImage = IDB_DSADMIN; m_uIdBitmapSmallImageOpen = IDB_DSADMIN; m_uIdBitmapLargeImage = IDB_DSADMIN_LG; m_crImageMask = RGB(255,0,255); } ////////////////////////////////////////////////////////////////////////// // CDSSnapinAbout CSitesSnapinAbout::CSitesSnapinAbout() { m_uIdStrProvider = IDS_SNAPIN_PROVIDER; m_uIdStrVersion = IDS_SNAPIN_VERSION; m_uIdStrDestription = IDS_SITES_SNAPINABOUT_DESCRIPTION; m_uIdIconImage = IDI_SITEREPL; m_uIdBitmapSmallImage = IDB_SITEREPL; m_uIdBitmapSmallImageOpen = IDB_SITEREPL; m_uIdBitmapLargeImage = IDB_SITEREPL_LG; m_crImageMask = RGB(255,0,255); }