//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1998 - 1999 // // File: cdomain.cpp // //-------------------------------------------------------------------------- #include "stdafx.h" //#include "afxdlgs.h" #include #include "activeds.h" #include // for DnsFlushResolverCache() #include "domobj.h" #include "Cdomain.h" #include "DataObj.h" #include "notify.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define DOMADMIN_LINKED_HELP_FILE L"ADconcepts.chm" #define DOMADMIN_SNAPIN_HELP_FILE L"domadmin.chm" int _MessageBox(HWND hWnd, // handle to owner window LPCTSTR lpText, // pointer to text in message box UINT uType); // style of message box ///////////////////////////////////////////////////////////////////////////// // macros #define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0])) ///////////////////////////////////////////////////////////////////////////// // constants // {19B9A3F8-F975-11d1-97AD-00A0C9A06D2D} static const GUID CLSID_DomainSnapinAbout = { 0x19b9a3f8, 0xf975, 0x11d1, { 0x97, 0xad, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } }; const CLSID CLSID_DomainAdmin = { /* ebc53a38-a23f-11d0-b09b-00c04fd8dca6 */ 0xebc53a38, 0xa23f, 0x11d0, {0xb0, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xdc, 0xa6} }; const GUID cDefaultNodeType = { /* 4c06495e-a241-11d0-b09b-00c04fd8dca6 */ 0x4c06495e, 0xa241, 0x11d0, {0xb0, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xdc, 0xa6} }; const wchar_t* cszDefaultNodeType = _T("4c06495e-a241-11d0-b09b-00c04fd8dca6"); // Internal private format const wchar_t* CCF_DS_DOMAIN_TREE_SNAPIN_INTERNAL = L"DS_DOMAIN_TREE_SNAPIN_INTERNAL"; ///////////////////////////////////////////////////////////////////////////// // global functions //forward decl void PrintColumn( PADS_SEARCH_COLUMN pColumn, LPWSTR pszColumnName ); BOOL IsMMCMultiSelectDataObject(IDataObject* pDataObject) { if (pDataObject == NULL) return FALSE; static UINT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = RegisterClipboardFormat(W2T(CCF_MMC_MULTISELECT_DATAOBJECT)); } FORMATETC fmt = {(CLIPFORMAT)s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return (pDataObject->QueryGetData(&fmt) == S_OK); } #define NEXT_HELP_TABLE_ENTRY(p) ((p)+2) #define TABLE_ENTRY_CTRL_ID(p) (*p) #define TABLE_ENTRY_HELP_ID(p) (*(p+1)) #define IS_LAST_TABLE_ENTRY(p) (TABLE_ENTRY_CTRL_ID(p) == 0) BOOL FindDialogContextTopic(/*IN*/ DWORD* pTable, /*IN*/ HELPINFO* pHelpInfo, /*OUT*/ ULONG* pnContextTopic) { ASSERT(pHelpInfo != NULL); *pnContextTopic = 0; // look inside the table while (!IS_LAST_TABLE_ENTRY(pTable)) { if (TABLE_ENTRY_CTRL_ID(pTable) == (DWORD)pHelpInfo->iCtrlId) { *pnContextTopic = TABLE_ENTRY_HELP_ID(pTable); return TRUE; } pTable = NEXT_HELP_TABLE_ENTRY(pTable); } return FALSE; } void DialogContextHelp(DWORD* pTable, HELPINFO* pHelpInfo) { ULONG nContextTopic; if (FindDialogContextTopic(pTable, pHelpInfo, &nContextTopic)) { CString szHelpFilePath; LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH+1); UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH); if (nLen == 0) return; // NOTICE-2002/03/07-ericb - SecurityPush: using wcsncpy now. GetBuffer above null terminates the buffer. wcsncpy(&lpszBuffer[nLen], L"\\HELP\\DOMADMIN.HLP", 2*MAX_PATH - nLen); szHelpFilePath.ReleaseBuffer(); ::WinHelp((HWND) pHelpInfo->hItemHandle, szHelpFilePath, HELP_CONTEXTPOPUP, nContextTopic); } } LPCWSTR GetServerNameFromCommandLine() { const WCHAR szOverrideSrvCommandLine[] = L"/Server="; // Not subject to localization const int cchOverrideSrvCommandLine = (sizeof(szOverrideSrvCommandLine)/sizeof(WCHAR)) - 1; static CString g_strOverrideServerName; // retrieve the command line arguments LPCWSTR* lpServiceArgVectors; // Array of pointers to string int cArgs = 0; // Count of arguments lpServiceArgVectors = (LPCWSTR *)CommandLineToArgvW(GetCommandLineW(), OUT &cArgs); if (lpServiceArgVectors == NULL) { return NULL; } CString str; for (int i = 1; i < cArgs; i++) { ASSERT(lpServiceArgVectors[i] != NULL); str = lpServiceArgVectors[i]; // Copy the string TRACE (_T("command line arg: %s\n"), lpServiceArgVectors[i]); str = str.Left(cchOverrideSrvCommandLine); if (str.CompareNoCase(szOverrideSrvCommandLine) == 0) { g_strOverrideServerName = lpServiceArgVectors[i] + cchOverrideSrvCommandLine; break; } } // for LocalFree(lpServiceArgVectors); TRACE(L"GetServerNameFromCommandLine() returning <%s>\n", (LPCWSTR)g_strOverrideServerName); return g_strOverrideServerName.IsEmpty() ? NULL : (LPCWSTR)g_strOverrideServerName; } ///////////////////////////////////////////////////////////////////////////// // CInternalFormatCracker BOOL CInternalFormatCracker::Extract(LPDATAOBJECT lpDataObject) { if (m_pInternalFormat != NULL) { FREE_INTERNAL(m_pInternalFormat); m_pInternalFormat = NULL; } if (lpDataObject == NULL) return FALSE; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { (CLIPFORMAT)CDataObject::m_cfInternal, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; // Allocate memory for the stream stgmedium.hGlobal = ::GlobalAlloc(GMEM_SHARE, sizeof(INTERNAL)); // Attempt to get data from the object do { if (stgmedium.hGlobal == NULL) break; if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium))) break; m_pInternalFormat = reinterpret_cast(stgmedium.hGlobal); if (m_pInternalFormat == NULL) return FALSE; } while (FALSE); return TRUE; } BOOL CInternalFormatCracker::GetContext(LPDATAOBJECT pDataObject, // input CFolderObject** ppFolderObject, // output DATA_OBJECT_TYPES* pType // output ) { *ppFolderObject = NULL; *pType = CCT_UNINITIALIZED; BOOL bRet = FALSE; if (!Extract(pDataObject)) return bRet; // have to figure out which kind of cookie we have if ( (GetInternal()->m_type == CCT_RESULT) || (GetInternal()->m_type == CCT_SCOPE) ) { if (GetInternal()->m_cookie == 0) { // this is the root *ppFolderObject = m_pCD->GetRootFolder(); bRet = TRUE; } else { // regular cookie (scope or result pane) *ppFolderObject = reinterpret_cast(GetInternal()->m_cookie); _ASSERTE(*ppFolderObject != NULL); *pType = GetInternal()->m_type; bRet = TRUE; } } else if (GetInternal()->m_type == CCT_UNINITIALIZED) { // no data in the object, just ignore if(GetInternal()->m_cookie == -1) { bRet = TRUE; } else { // secondary page cookie *ppFolderObject = reinterpret_cast(GetInternal()->m_cookie); bRet = TRUE; } } else //CCT_SNAPIN_MANAGER { ASSERT(GetInternal()->m_type == CCT_SNAPIN_MANAGER); bRet = TRUE; *pType = GetInternal()->m_type; } return bRet; } /////////////////////////////////////////////////////////////////////////////// ////////////////////////// CComponentDataImpl (i.e. scope pane side) ////////// /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // IComponentData implementation DEBUG_DECLARE_INSTANCE_COUNTER(CComponentDataImpl); CComponentDataImpl::CComponentDataImpl() : m_rootFolder(this) { DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentDataImpl); m_bInitSuccess = FALSE; m_hDomainIcon = NULL; m_pConsoleNameSpace = NULL; m_pConsole = NULL; /* HACK WARNING: 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"); } } } HRESULT CComponentDataImpl::FinalConstruct() { // create and initialize hidden window m_pHiddenWnd = new CHiddenWnd(this); ASSERT(m_pHiddenWnd); if (!m_pHiddenWnd->Create()) { TRACE(_T("Failed to create hidden window\n")); ASSERT(FALSE); } return S_OK; } CComponentDataImpl::~CComponentDataImpl() { DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentDataImpl); ASSERT(m_pConsoleNameSpace == NULL); } void CComponentDataImpl::FinalRelease() { _DeleteHiddenWnd(); } STDMETHODIMP CComponentDataImpl::Initialize(LPUNKNOWN pUnknown) { ASSERT(pUnknown != NULL); HRESULT hr; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // MMC should only call ::Initialize once! ASSERT(m_pConsoleNameSpace == NULL); pUnknown->QueryInterface(IID_IConsoleNameSpace, reinterpret_cast(&m_pConsoleNameSpace)); // add the images for the scope tree CBitmap bmp16x16; LPIMAGELIST lpScopeImage; hr = pUnknown->QueryInterface(IID_IConsole, reinterpret_cast(&m_pConsole)); ASSERT(hr == S_OK); if (FAILED(hr)) { return hr; } hr = m_pConsole->QueryScopeImageList(&lpScopeImage); ASSERT(hr == S_OK); if (FAILED(hr)) { return hr; } // Load the bitmaps from the dll bmp16x16.LoadBitmap(IDB_DOMAIN_SMALL); // Set the images lpScopeImage->ImageListSetStrip(reinterpret_cast(static_cast(bmp16x16)), reinterpret_cast(static_cast(bmp16x16)), 0, RGB(128, 0, 0)); lpScopeImage->Release(); // bind to the path info hr = GetBasePathsInfo()->InitFromName(GetServerNameFromCommandLine()); m_bInitSuccess = SUCCEEDED(hr); if (FAILED(hr)) { HWND hWndParent; GetMainWindow(&hWndParent); ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr); // TODO: error handling, change icon } return S_OK; } HWND CComponentDataImpl::GetHiddenWindow() { ASSERT(m_pHiddenWnd != NULL); ASSERT(::IsWindow(m_pHiddenWnd->m_hWnd)); return m_pHiddenWnd->m_hWnd; } void CComponentDataImpl::_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; } STDMETHODIMP CComponentDataImpl::CreateComponent(LPCOMPONENT* ppComponent) { ASSERT(ppComponent != NULL); CComObject* pObject; HRESULT hr = CComObject::CreateInstance(&pObject); if (FAILED(hr)) { ASSERT(FALSE && "CComObject::CreateInstance(&pObject) failed"); return hr; } ASSERT(pObject != NULL); // Store IComponentData pObject->SetIComponentData(this); return pObject->QueryInterface(IID_IComponent, reinterpret_cast(ppComponent)); } STDMETHODIMP CComponentDataImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { ASSERT(m_pConsoleNameSpace != NULL); HRESULT hr = S_OK; // 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 (event == MMCN_PROPERTY_CHANGE) { hr = OnPropertyChange(param); } else { if (lpDataObject == NULL) return S_OK; CFolderObject* pFolderObject = NULL; DATA_OBJECT_TYPES type; CInternalFormatCracker dobjCracker(this); if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type)) { // Extensions not supported. ASSERT(FALSE); return S_OK; } switch(event) { case MMCN_EXPAND: hr = OnExpand(pFolderObject, arg, param); break; case MMCN_REFRESH: OnRefreshVerbHandler(pFolderObject, NULL); break; default: break; } } return hr; } STDMETHODIMP CComponentDataImpl::Destroy() { SAFE_RELEASE(m_pConsoleNameSpace); SAFE_RELEASE(m_pConsole); return S_OK; } STDMETHODIMP CComponentDataImpl::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { ASSERT(ppDataObject != NULL); if (ppDataObject == NULL) return E_INVALIDARG; // create data object CComObject* pObject = NULL; CComObject::CreateInstance(&pObject); ASSERT(pObject != NULL); if ( !pObject ) return E_OUTOFMEMORY; // Save cookie and type for delayed rendering pObject->SetType(type); pObject->SetCookie(cookie); // set pointer to IComponentData pObject->SetIComponentData(this); if (cookie != NULL) { // object is not the root CDomainObject * pDomain = (CDomainObject *)cookie; pObject->SetClass( pDomain->GetClass()); } return pObject->QueryInterface(IID_IDataObject, reinterpret_cast(ppDataObject)); } /////////////////////////////////////////////////////////////////////////////// //// Notify handlers for IComponentData HRESULT CComponentDataImpl::OnExpand(CFolderObject* pFolderObject, LPARAM arg, LPARAM param) { if (arg == TRUE) { // Did Initialize get called? ASSERT(m_pConsoleNameSpace != NULL); EnumerateScopePane(pFolderObject, param); } return S_OK; } HRESULT CComponentDataImpl::OnPropertyChange(LPARAM param) { return S_OK; } void CComponentDataImpl::EnumerateScopePane(CFolderObject* pFolderObject, HSCOPEITEM pParent) { ASSERT(m_pConsoleNameSpace != NULL); // make sure we QI'ed for the interface HRESULT hr = S_OK; HWND hWndParent; GetMainWindow(&hWndParent); AFX_MANAGE_STATE(AfxGetStaticModuleState()); CWaitCursor cWait; CRootFolderObject* pRootFolder = GetRootFolder(); if (pFolderObject == pRootFolder) // asked to enumerate the root { pRootFolder->SetScopeID(pParent); if (m_bInitSuccess && (!pRootFolder->HasData())) { hr = GetDsDisplaySpecOptionsCFHolder()->Init(GetBasePathsInfo()); ASSERT(SUCCEEDED(hr)); hr = pRootFolder->Bind(); if (FAILED(hr)) { ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr); // TODO: error handling, change icon return; } hr = pRootFolder->GetData(); if (FAILED(hr)) { ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr); return; } } pRootFolder->EnumerateRootFolder(this); } else // asked to enumerate a subfolder of the root { if (pRootFolder->HasData()) { pRootFolder->EnumerateFolder(pFolderObject, pParent, this); } } } STDMETHODIMP CComponentDataImpl::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem) { ASSERT(pScopeDataItem != NULL); if (pScopeDataItem == NULL) return E_POINTER; CDomainObject* pDomain = reinterpret_cast(pScopeDataItem->lParam); ASSERT(pScopeDataItem->mask & SDI_STR); pScopeDataItem->displayname = (LPWSTR)pDomain->GetDisplayString(0); ASSERT(pScopeDataItem->displayname != NULL); return S_OK; } class CCompareDomainObjectByDN { public: CCompareDomainObjectByDN(LPCWSTR lpszDN) { m_lpszDN = lpszDN;} bool operator()(CDomainObject* p) { // NOTICE-2002/03/07-ericb - SecurityPush: checking both strings for null before dereferencing. if (!m_lpszDN || !p || !p->GetNCName()) { ASSERT(m_lpszDN); ASSERT(p); ASSERT(p->GetNCName()); return false; } return (_wcsicmp(m_lpszDN, p->GetNCName()) == 0); } private: LPCWSTR m_lpszDN; }; STDMETHODIMP CComponentDataImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { if (lpDataObjectA == NULL || lpDataObjectB == NULL) return E_POINTER; CFolderObject *pFolderObjectA, *pFolderObjectB; DATA_OBJECT_TYPES typeA, typeB; CInternalFormatCracker dobjCrackerA(this), dobjCrackerB(this); if ( (!dobjCrackerA.GetContext(lpDataObjectA, &pFolderObjectA, &typeA)) || (!dobjCrackerB.GetContext(lpDataObjectB, &pFolderObjectB, &typeB)) ) return E_INVALIDARG; // something went wrong // must have valid cookies if ( (pFolderObjectA == NULL) || (pFolderObjectB == NULL) ) { return S_FALSE; } if (pFolderObjectA == pFolderObjectB) { // same pointer, they are the same (either both from real nodes // or both from secondary pages) return S_OK; } // the two cookies are different, but one of them might be from a secondary property page // and another from a real node CDomainObject* pA = dynamic_cast(pFolderObjectA); CDomainObject* pB = dynamic_cast(pFolderObjectB); if ((pA == NULL) || (pB == NULL)) { return S_FALSE; } BOOL bSecondaryA = m_secondaryPagesManager.IsCookiePresent(pA); BOOL bSecondaryB = m_secondaryPagesManager.IsCookiePresent(pB); BOOL bTheSame = FALSE; if (bSecondaryA && !bSecondaryB) { bTheSame = m_secondaryPagesManager.FindCookie(CCompareDomainObjectByDN(pB->GetNCName())) != NULL; } else if (!bSecondaryA && bSecondaryB) { bTheSame = m_secondaryPagesManager.FindCookie(CCompareDomainObjectByDN(pA->GetNCName())) != NULL; } return bTheSame ? S_OK : S_FALSE; } HRESULT CComponentDataImpl::AddFolder(CFolderObject* pFolderObject, HSCOPEITEM pParentScopeItem, BOOL bHasChildren) { TRACE(L"CComponentDataImpl::AddFolder(%s)\n", pFolderObject->GetDisplayString(0)); SCOPEDATAITEM scopeItem; // NOTICE-2002/03/07-ericb - SecurityPush: zeroing a struct. memset(&scopeItem, 0, sizeof(SCOPEDATAITEM)); // set parent scope item scopeItem.mask |= SDI_PARENT; scopeItem.relativeID = pParentScopeItem; // Add node name, we implement callback scopeItem.mask |= SDI_STR; scopeItem.displayname = MMC_CALLBACK; // Add the lParam scopeItem.mask |= SDI_PARAM; scopeItem.lParam = reinterpret_cast(pFolderObject); // Add close image scopeItem.mask |= SDI_IMAGE; scopeItem.nImage = pFolderObject->GetImageIndex(); // Add open image scopeItem.mask |= SDI_OPENIMAGE; scopeItem.nOpenImage = pFolderObject->GetImageIndex(); // Add button to node if the folder has children if (bHasChildren == TRUE) { scopeItem.mask |= SDI_CHILDREN; scopeItem.cChildren = 1; } pFolderObject->SetScopeID(0); HRESULT hr = m_pConsoleNameSpace->InsertItem(&scopeItem); if (SUCCEEDED(hr)) pFolderObject->SetScopeID(scopeItem.ID); return hr; } HRESULT CComponentDataImpl::AddDomainIcon() { if (m_hDomainIcon != NULL) return S_OK; m_hDomainIcon = GetBasePathsInfo()->GetIcon(L"domainDNS", DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, 0, 0); if (m_hDomainIcon == NULL) return S_OK; LPIMAGELIST lpScopeImage; HRESULT hr = m_pConsole->QueryScopeImageList(&lpScopeImage); ASSERT(SUCCEEDED(hr)); if (FAILED(hr)) return hr; // Set the images hr = lpScopeImage->ImageListSetIcon((LONG_PTR*)m_hDomainIcon,DOMAIN_IMAGE_IDX); lpScopeImage->Release(); return hr; } HRESULT CComponentDataImpl::AddDomainIconToResultPane(LPIMAGELIST lpImageList) { if (m_hDomainIcon == NULL) return S_OK; return lpImageList->ImageListSetIcon((LONG_PTR*)m_hDomainIcon,DOMAIN_IMAGE_IDX); } int CComponentDataImpl::GetDomainImageIndex() { return (m_hDomainIcon != NULL) ? DOMAIN_IMAGE_IDX : DOMAIN_IMAGE_DEFAULT_IDX; } ///////////////////////////////////////////////////////////////////////////// // IExtendPropertySheet Implementation //+---------------------------------------------------------------------------- // // Function: AddPageProc // // Synopsis: The IShellPropSheetExt->AddPages callback. // //----------------------------------------------------------------------------- BOOL CALLBACK AddPageProc(HPROPSHEETPAGE hPage, LPARAM pCall) { TRACE(_T("xx.%03x> AddPageProc()\n"), GetCurrentThreadId()); HRESULT hr; hr = ((LPPROPERTYSHEETCALLBACK)pCall)->AddPage(hPage); return hr == S_OK; } STDMETHODIMP CComponentDataImpl::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpIDataObject) { TRACE(_T("xx.%03x> CComponentDataImpl::CreatePropertyPages()\n"), GetCurrentThreadId()); // Validate Inputs if (lpProvider == NULL) { return E_INVALIDARG; } AFX_MANAGE_STATE(AfxGetStaticModuleState()); HRESULT hr = S_OK; CWaitCursor wait; CFolderObject* pFolderObject = NULL; DATA_OBJECT_TYPES type; CInternalFormatCracker dobjCracker(this); if ( (!dobjCracker.GetContext(lpIDataObject, &pFolderObject, &type)) || (pFolderObject == NULL)) return E_NOTIMPL; // unknown format // special case the root if (pFolderObject == GetRootFolder()) { return GetRootFolder()->OnAddPages(lpProvider, handle); } // See if a sheet is already up for this object. // if (IsSheetAlreadyUp(lpIDataObject)) { return S_OK; } if (pFolderObject->GetParentFolder() == GetRootFolder()) { TRACE(L"\t!!!!! This is the root domain\n"); } // See if a PDC is available. // CDomainObject * pDomainObject = (CDomainObject *)pFolderObject; PCWSTR wzDomain = pDomainObject->GetDomainName(); // If the domain name is null, then launching a secondary page. The domain // object properties have already been set in _OnSheetCreate. // if (wzDomain && *wzDomain) { TRACE(L"Calling DsGetDcName on %s\n", wzDomain); CString strCachedPDC; PDOMAIN_CONTROLLER_INFOW pDCInfo = NULL; // Get the cached PDC name for display later if the PDC can't be contacted. // DWORD dwRet = DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_PDC_REQUIRED, &pDCInfo); int nID = IDS_NO_PDC_MSG; if (ERROR_SUCCESS == dwRet) { strCachedPDC = pDCInfo->DomainControllerName + 2; NetApiBufferFree(pDCInfo); } // Now do a NetLogon cache update (with the force flag) to see if the PDC // is actually available. // dwRet = DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDCInfo); if (ERROR_SUCCESS == dwRet) { CString strPDC; strPDC = pDCInfo->DomainControllerName + 2; // skip the UNC backslashes. NetApiBufferFree(pDCInfo); TRACE(L"PDC: %s\n", (PCWSTR)strPDC); if (strPDC.IsEmpty()) { return E_OUTOFMEMORY; } pDomainObject->SetPDC(strPDC); pDomainObject->SetPdcAvailable(true); } else { pDomainObject->SetPdcAvailable(false); CString strMsg; if (strCachedPDC.IsEmpty()) { strMsg.LoadString(IDS_UNKNOWN_PDC_MSG); } else { strMsg.Format(IDS_NO_PDC_MSG, strCachedPDC); } HWND hWndParent; GetMainWindow(&hWndParent); _MessageBox(hWndParent, strMsg, MB_OK | MB_ICONEXCLAMATION); } } // // Pass the Notify Handle to the data object. // PROPSHEETCFG SheetCfg = {handle}; FORMATETC fe = {CDataObject::m_cfGetIPropSheetCfg, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM sm = {TYMED_HGLOBAL, NULL, NULL}; sm.hGlobal = (HGLOBAL)&SheetCfg; lpIDataObject->SetData(&fe, &sm, FALSE); // // Initialize and create the pages. // // 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. // CComPtr spShlInit; hr = CoCreateInstance(CLSID_DsPropertyPages, NULL, CLSCTX_INPROC_SERVER, IID_IShellExtInit, (void **)&spShlInit); if (FAILED(hr)) { TRACE(TEXT("CoCreateInstance on CLSID_DsPropertyPages failed, hr: 0x%x\n "), hr); return hr; } hr = spShlInit->Initialize(NULL, lpIDataObject, 0); if (FAILED(hr)) { TRACE(TEXT("spShlInit->Initialize failed, hr: 0x%x\n"), hr); return hr; } CComPtr spSPSE; hr = spShlInit->QueryInterface(IID_IShellPropSheetExt, (void **)&spSPSE); if (FAILED(hr)) { TRACE(TEXT("spShlInit->QI for IID_IShellPropSheetExt failed, hr: 0x%x\n"), hr); return hr; } hr = spSPSE->AddPages(AddPageProc, (LONG_PTR)lpProvider); if (FAILED(hr)) { TRACE(TEXT("pSPSE->AddPages failed, hr: 0x%x\n"), hr); return hr; } _SheetLockCookie(pFolderObject); return hr; } // Sheet locking and unlocking add by JEFFJON 1/26/99 // void CComponentDataImpl::_OnSheetClose(CFolderObject* pCookie) { ASSERT(pCookie != NULL); _SheetUnlockCookie(pCookie); CDomainObject* pDomObj = dynamic_cast(pCookie); if (pDomObj != NULL) m_secondaryPagesManager.OnSheetClose(pDomObj); } void CComponentDataImpl::_OnSheetCreate(PDSA_SEC_PAGE_INFO pDsaSecondaryPageInfo, PWSTR pwzDC) { 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); // with the given info, create a cookie and set it CDomainObject* pNewCookie = new CDomainObject(); pNewCookie->InitializeForSecondaryPage(lpszName, lpszClass, GetDomainImageIndex()); // The parent sheet will be in read-only mode if a PDC is not available. pNewCookie->SetPdcAvailable(!(pDsObject->dwFlags & DSOBJECT_READONLYPAGES)); if (pwzDC && !IsBadReadPtr(pwzDC, sizeof(PWSTR))) { pNewCookie->SetPDC(pwzDC); } // with the cookie, can call into ourselves to get a data object CComPtr spDataObject; MMC_COOKIE cookie = reinterpret_cast(pNewCookie); 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 pNewCookie; return; } // // Pass the parent sheet handle to the data object. // PROPSHEETCFG SheetCfg = {0}; SheetCfg.hwndParentSheet = hwndParent; FORMATETC fe = {CDataObject::m_cfGetIPropSheetCfg, 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 = m_secondaryPagesManager.CreateSheet(GetHiddenWindow(), m_pConsole, GetUnknown(), pNewCookie, spDataObject, lpszTitle); // if failed, the cookie can be discarded, // if succeeded, the cookie has been inserted into // the secondary pages manager cookie list if (FAILED(hr)) { delete pNewCookie; } } void CComponentDataImpl::_SheetLockCookie(CFolderObject* pCookie) { pCookie->IncrementSheetLockCount(); m_sheetCookieTable.Add(pCookie); } void CComponentDataImpl::_SheetUnlockCookie(CFolderObject* pCookie) { pCookie->DecrementSheetLockCount(); m_sheetCookieTable.Remove(pCookie); } STDMETHODIMP CComponentDataImpl::QueryPagesFor(LPDATAOBJECT lpDataObject) { CFolderObject* pFolderObject; DATA_OBJECT_TYPES type; CInternalFormatCracker dobjCracker(this); if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type)) { // not internal format, not ours return S_FALSE; } // this is the MMC snzpin wizard, we do not have one if (type == CCT_SNAPIN_MANAGER) { return S_FALSE; } // if NULL no pages if (pFolderObject == NULL) { return S_FALSE; } // secondary pages data objects have to be checked first, // because they look like the root (no parents, but they // have CCT_UNINITIALIZED if ( (pFolderObject->GetParentFolder() == NULL) || (type == CCT_UNINITIALIZED) ) { return S_OK; } // check if this is the root if (GetRootFolder() == pFolderObject) { // this is the root ASSERT(type == CCT_SCOPE); return S_OK; } // default case, have DSPROP property pages return S_OK; } BOOL CComponentDataImpl::IsScopePaneNode(LPDATAOBJECT lpDataObject) { CFolderObject* pFolderObject; DATA_OBJECT_TYPES type; CInternalFormatCracker dobjCracker(this); if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type)) return FALSE; return (dobjCracker.GetInternal()->m_type == CCT_SCOPE); } /////////////////////////////////////////////////////////////////////////////// // IExtendContextMenu implementation // STDMETHODIMP CComponentDataImpl::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK pContextMenuCallback, long *pInsertionAllowed) { HRESULT hr = S_OK; CFolderObject* pFolderObject; DATA_OBJECT_TYPES type; CInternalFormatCracker dobjCracker(this); if (!dobjCracker.GetContext(pDataObject, &pFolderObject, &type)) return E_FAIL; return pFolderObject->OnAddMenuItems(pContextMenuCallback, pInsertionAllowed); } STDMETHODIMP CComponentDataImpl::Command(long nCommandID, LPDATAOBJECT pDataObject) { // Note - snap-ins need to look at the data object and determine // in what context the command is being called. CFolderObject* pFolderObject; DATA_OBJECT_TYPES type; CInternalFormatCracker dobjCracker(this); if (!dobjCracker.GetContext(pDataObject, &pFolderObject, &type)) return E_FAIL; return pFolderObject->OnCommand(this, nCommandID); } ///////////////////////////////////////////////////////////////////////////// // CComponentDataImpl::ISnapinHelp2 members STDMETHODIMP CComponentDataImpl::GetHelpTopic(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 += DOMADMIN_SNAPIN_HELP_FILE; UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR); *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes); if (NULL == *lpCompiledHelpFile) { return E_OUTOFMEMORY; } // NOTICE-2002/03/07-ericb - SecurityPush: reviewed, usage is safe. memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes); return S_OK; } // CODEWORK-2002/03/07-ericb - use a common helper for these two functions. STDMETHODIMP CComponentDataImpl::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 += DOMADMIN_LINKED_HELP_FILE; UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR); *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes); if (NULL == *lpCompiledHelpFile) { return E_OUTOFMEMORY; } // NOTICE-2002/03/07-ericb - SecurityPush: reviewed, usage is safe. memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes); return S_OK; } ///////////////////////////////////////////////////////////////////// void CComponentDataImpl::HandleStandardVerbsHelper(CComponentImpl* pComponentImpl, LPCONSOLEVERB pConsoleVerb, BOOL bScope, BOOL bSelect, CFolderObject* pFolderObject, DATA_OBJECT_TYPES type) { // You should crack the data object and enable/disable/hide standard // commands appropriately. The standard commands are reset everytime you get // called. So you must reset them back. ASSERT(pConsoleVerb != NULL); ASSERT(pComponentImpl != NULL); ASSERT(pFolderObject != NULL); // reset the selection pComponentImpl->SetSelection(NULL, CCT_UNINITIALIZED); if (bSelect) { // special case the root BOOL bIsRoot = (pFolderObject == GetRootFolder()); // setting the selection, if any pComponentImpl->SetSelection(pFolderObject, type); // the default just disables all the non implemented verbs pConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE); pConsoleVerb->SetVerbState(MMC_VERB_COPY, ENABLED, FALSE); pConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE); pConsoleVerb->SetVerbState(MMC_VERB_PASTE, ENABLED, FALSE); pConsoleVerb->SetVerbState(MMC_VERB_RENAME, HIDDEN, TRUE); pConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, FALSE); pConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, TRUE); pConsoleVerb->SetVerbState(MMC_VERB_PRINT, ENABLED, FALSE); // handling of standard verbs // MMC_VERB_DELETE (always disabled) pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, FALSE); pConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, TRUE); // MMC_VERB_REFRESH (enabled only for root) if (bIsRoot) { pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE); pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE); } else { pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, FALSE); pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, TRUE); } // MMC_VERB_PROPERTIES // passing NULL pFolderObject means multiple selection BOOL bHasProperties = (pFolderObject != NULL); BOOL bHideProperties = !bHasProperties; pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, bHasProperties); pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, bHideProperties); // SET DEFAULT VERB // assume only folders: only one default verb (i.e. will not have MMC_VERB_PROPERTIES) pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN); } } void CComponentDataImpl::OnRefreshVerbHandler(CFolderObject* pFolderObject, CComponentImpl* pComponentImpl, BOOL bBindAgain) { TRACE(L"CComponentDataImpl::OnRefreshVerbHandler(...,..., %d)\n", bBindAgain); if (pFolderObject->_WarningOnSheetsUp(this)) return; // make sure the DNS cache is flushed, in case a somain was added. VERIFY(::DnsFlushResolverCache()); // NOTICE: only the root folder allows refresh ASSERT(pFolderObject == GetRootFolder()); // remove all the children of the root from the UI m_pConsoleNameSpace->DeleteItem(m_rootFolder.GetScopeID(), /*fDeleteThis*/ FALSE); HRESULT hr = S_OK; if (bBindAgain) { // the server name has changed hr = m_rootFolder.Bind(); TRACE(L"m_rootFolder.Bind() returned hr = 0x%x\n", hr); } if (SUCCEEDED(hr)) { // refresh the data from the server hr = m_rootFolder.GetData(); TRACE(L"m_rootFolder.GetData() returned hr = 0x%x\n", hr); } if (FAILED(hr)) { HWND hWndParent; GetMainWindow(&hWndParent); ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr); } if (FAILED(hr)) return; // re-enumerate m_rootFolder.EnumerateRootFolder(this); } //+--------------------------------------------------------------------------- // // Function: LocaleStrCmp // // Synopsis: Do a case insensitive string compare that is safe for any // locale. // // Arguments: [ptsz1] - strings to compare // [ptsz2] // // Returns: -1, 0, or 1 just like lstrcmpi // // History: 10-28-96 DavidMun Created // // Notes: This is slower than lstrcmpi, but will work when sorting // strings even in Japanese. // //---------------------------------------------------------------------------- int LocaleStrCmp(LPCTSTR ptsz1, LPCTSTR ptsz2) { int iRet = 0; iRet = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH, ptsz1, -1, ptsz2, -1); if (iRet) { iRet -= 2; // convert to lstrcmpi-style return -1, 0, or 1 if ( 0 == iRet ) { UNICODE_STRING unistr1; unistr1.Length = (USHORT)(::lstrlen(ptsz1)*sizeof(WCHAR)); unistr1.MaximumLength = unistr1.Length; unistr1.Buffer = (LPWSTR)ptsz1; UNICODE_STRING unistr2; unistr2.Length = (USHORT)(::lstrlen(ptsz2)*sizeof(WCHAR)); unistr2.MaximumLength = unistr2.Length; unistr2.Buffer = (LPWSTR)ptsz2; iRet = ::RtlCompareUnicodeString( &unistr1, &unistr2, FALSE ); } } else { DWORD dwErr = GetLastError (); if (dwErr != 0) { TRACE(L"CompareString (%s, %s) failed: 0x%x\n", ptsz1, ptsz2, dwErr); } } return iRet; } /////////////////////////////////////////////////////////////////////////////// ///////////////////// CComponentImpl (i.e. result pane side) ////////////////// /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CComponentImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { return S_FALSE; } //+--------------------------------------------------------------------------- // // Function: CComponentImpl::IResultDataCompareEx::Compare // // Synopsis: This compare is used to sort the item's in the listview // // Note: Assume sort is ascending when comparing. // //---------------------------------------------------------------------------- STDMETHODIMP CComponentImpl::Compare(RDCOMPARE* prdc, int* pnResult) { if (pnResult == NULL) { ASSERT(FALSE); return E_POINTER; } if (prdc == NULL) { ASSERT(FALSE); return E_POINTER; } *pnResult = 0; LPCTSTR szStringA; LPCTSTR szStringB; CDomainObject* pDataA = reinterpret_cast(prdc->prdch1->cookie); CDomainObject* pDataB = reinterpret_cast(prdc->prdch2->cookie); ASSERT(pDataA != NULL && pDataB != NULL); // Currently DomAdmin has just two columns, Name and Type. The value of // the type column is always "DomainDNS", so there is nothing to compare // for that column and the default *pnResult, set to zero above, is // returned. if (0 == prdc->nColumn) { szStringA = pDataA->GetDomainName(); szStringB = pDataB->GetDomainName(); ASSERT(szStringA != NULL); ASSERT(szStringB != NULL); *pnResult = LocaleStrCmp(szStringA, szStringB); } return S_OK; } void CComponentImpl::HandleStandardVerbs(BOOL bScope, BOOL bSelect, CFolderObject* pFolderObject, DATA_OBJECT_TYPES type) { // delegate it to the IComponentData helper function ASSERT(m_pCD != NULL); m_pCD->HandleStandardVerbsHelper( this, m_pConsoleVerb, bScope, bSelect, pFolderObject, type); } void CComponentImpl::Refresh(CFolderObject* pFolderObject) { ASSERT(m_pComponentData != NULL); // delegate it to the IComponentData helper function ((CComponentDataImpl*)m_pComponentData)->OnRefreshVerbHandler(pFolderObject, this); } // utility routines //////////////////////////////////////////////////////////////////// // // Print the data depending on its type. // #ifdef DBG void PrintColumn( PADS_SEARCH_COLUMN pColumn, LPWSTR pszColumnName ) { ULONG i, j, k; if (!pColumn) { return; } TRACE(_T( "%s = "), pszColumnName ); for (k=0; k < pColumn->dwNumValues; k++) { if (k > 0) TRACE(_T("# ")); switch(pColumn->dwADsType) { case ADSTYPE_DN_STRING : TRACE(_T( "%s "), (LPWSTR) pColumn->pADsValues[k].DNString ); break; case ADSTYPE_CASE_EXACT_STRING : TRACE(_T( "%s "), (LPWSTR) pColumn->pADsValues[k].CaseExactString ); break; case ADSTYPE_CASE_IGNORE_STRING: TRACE(_T( "%s "), (LPWSTR) pColumn->pADsValues[k].CaseIgnoreString ); break; case ADSTYPE_PRINTABLE_STRING : TRACE(_T( "%s "), (LPWSTR) pColumn->pADsValues[k].PrintableString ); break; case ADSTYPE_NUMERIC_STRING : TRACE(_T( "%s "), (LPWSTR) pColumn->pADsValues[k].NumericString ); break; case ADSTYPE_BOOLEAN : TRACE(_T( "%s "), (DWORD) pColumn->pADsValues[k].Boolean ? L"TRUE" : L"FALSE" ); break; case ADSTYPE_INTEGER : TRACE(_T( "%d "), (DWORD) pColumn->pADsValues[k].Integer ); break; case ADSTYPE_OCTET_STRING : for (j=0; jpADsValues[k].OctetString.dwLength; j++) { TRACE(_T( "%02x"), ((BYTE *)pColumn->pADsValues[k].OctetString.lpValue)[j] ); } break; case ADSTYPE_LARGE_INTEGER : TRACE(_T( "%e = "), (double) pColumn->pADsValues[k].Integer ); break; case ADSTYPE_UTC_TIME : TRACE(_T( "(date value) " )); break; case ADSTYPE_PROV_SPECIFIC : TRACE(_T( "(provider specific value) " )); break; } } TRACE(_T("\n")); } #endif ///////////////////////////////////////////////////////////////////////////// // Return TRUE if we are enumerating our main folder BOOL CComponentImpl::IsEnumerating(LPDATAOBJECT lpDataObject) { BOOL bResult = FALSE; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { (CLIPFORMAT)CDataObject::m_cfNodeType, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; // Allocate memory for the stream stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(GUID)); // Attempt to get data from the object do { if (stgmedium.hGlobal == NULL) break; if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium))) break; GUID* nodeType = reinterpret_cast(stgmedium.hGlobal); if (nodeType == NULL) break; // Is this my main node (static folder node type) if (*nodeType == cDefaultNodeType) bResult = TRUE; } while (FALSE); // Free resources if (stgmedium.hGlobal != NULL) GlobalFree(stgmedium.hGlobal); return bResult; } ///////////////////////////////////////////////////////////////////////////// // CComponentImpl's IComponent implementation STDMETHODIMP CComponentImpl::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType, long *pViewOptions) { // Use default view *pViewOptions = 0; return S_FALSE; } STDMETHODIMP CComponentImpl::Initialize(LPCONSOLE lpConsole) { ASSERT(lpConsole != NULL); AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Save the IConsole pointer m_pConsole = lpConsole; m_pConsole->AddRef(); // Load resource strings LoadResources(); // QI for a IHeaderCtrl HRESULT hr = m_pConsole->QueryInterface(IID_IHeaderCtrl, reinterpret_cast(&m_pHeader)); // Give the console the header control interface pointer if (SUCCEEDED(hr)) m_pConsole->SetHeader(m_pHeader); m_pConsole->QueryInterface(IID_IResultData, reinterpret_cast(&m_pResult)); hr = m_pConsole->QueryResultImageList(&m_pImageResult); ASSERT(hr == S_OK); hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb); ASSERT(hr == S_OK); //InitializeHeaders(NULL); //InitializeBitmaps(NULL); return S_OK; } STDMETHODIMP CComponentImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { HRESULT hr = S_OK; AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (event == MMCN_PROPERTY_CHANGE) { hr = OnPropertyChange(lpDataObject); } else if (event == MMCN_VIEW_CHANGE) { hr = OnUpdateView(lpDataObject); } else if (event == MMCN_CONTEXTHELP) { CComPtr spHelp; hr = m_pConsole->QueryInterface(IID_IDisplayHelp, (void **)&spHelp); ASSERT(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { TRACE(L"Setting the help topic to adconcepts.chm::/domadmin_top.htm\n"); spHelp->ShowTopic(L"adconcepts.chm::/domadmin_top.htm"); } } else { if (lpDataObject == NULL) return S_OK; CFolderObject* pFolderObject = NULL; DATA_OBJECT_TYPES type; CInternalFormatCracker dobjCracker(m_pCD); if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type)) { // Extensions not supported. ASSERT(FALSE); return S_OK; } ASSERT(pFolderObject != NULL); switch(event) { case MMCN_SHOW: hr = OnShow(pFolderObject, arg, param); break; case MMCN_ADD_IMAGES: hr = OnAddImages(pFolderObject, arg, param); break; case MMCN_SELECT: if (IsMMCMultiSelectDataObject(lpDataObject) == TRUE) pFolderObject = NULL; HandleStandardVerbs( (BOOL) LOWORD(arg)/*bScope*/, (BOOL) HIWORD(arg)/*bSelect*/, pFolderObject, type); break; case MMCN_REFRESH: Refresh(pFolderObject); break; default: break; } // switch } // else if (m_pResult) { // should put something here, someday? ; } return hr; } STDMETHODIMP CComponentImpl::Destroy(MMC_COOKIE cookie) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Release the interfaces that we QI'ed if (m_pConsole != NULL) { // Tell the console to release the header control interface m_pConsole->SetHeader(NULL); SAFE_RELEASE(m_pHeader); SAFE_RELEASE(m_pResult); SAFE_RELEASE(m_pImageResult); // Release the IConsole interface last SAFE_RELEASE(m_pConsole); SAFE_RELEASE(m_pComponentData); // QI'ed in IComponentDataImpl::CreateComponent SAFE_RELEASE(m_pConsoleVerb); } return S_OK; } STDMETHODIMP CComponentImpl::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { // Delegate it to the IComponentData ASSERT(m_pComponentData != NULL); return m_pComponentData->QueryDataObject(cookie, type, ppDataObject); } ///////////////////////////////////////////////////////////////////////////// // CComponentImpl's implementation specific members DEBUG_DECLARE_INSTANCE_COUNTER(CComponentImpl); CComponentImpl::CComponentImpl() { DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentImpl); Construct(); } CComponentImpl::~CComponentImpl() { #if DBG==1 ASSERT(dbg_cRef == 0); #endif DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentImpl); // Make sure the interfaces have been released ASSERT(m_pConsole == NULL); ASSERT(m_pHeader == NULL); Construct(); } void CComponentImpl::Construct() { #if DBG==1 dbg_cRef = 0; #endif m_pConsole = NULL; m_pHeader = NULL; m_pResult = NULL; m_pImageResult = NULL; m_pComponentData = NULL; m_pCD = NULL; m_pConsoleVerb = NULL; m_selectedType = CCT_UNINITIALIZED; m_pSelectedFolderObject = NULL; } void CComponentImpl::LoadResources() { // Load strings from resources m_column1.LoadString(IDS_NAME); m_column2.LoadString(IDS_TYPE); } HRESULT CComponentImpl::InitializeHeaders(CFolderObject* pFolderObject) { HRESULT hr = S_OK; ASSERT(m_pHeader); // NOTICE: we ignore the cookie, keep always the same columns m_pHeader->InsertColumn(0, m_column1, LVCFMT_LEFT, 200); // Name m_pHeader->InsertColumn(1, m_column2, LVCFMT_LEFT, 80); // Type return hr; } HRESULT CComponentImpl::InitializeBitmaps(CFolderObject* pFolderObject) { ASSERT(m_pImageResult != NULL); AFX_MANAGE_STATE(AfxGetStaticModuleState()); CBitmap bmp16x16; CBitmap bmp32x32; // Load the bitmaps from the dll VERIFY(bmp16x16.LoadBitmap(IDB_DOMAIN_SMALL)); VERIFY(bmp32x32.LoadBitmap(IDB_DOMAIN_LARGE)); // Set the images HRESULT hr = m_pImageResult->ImageListSetStrip(reinterpret_cast(static_cast(bmp16x16)), reinterpret_cast(static_cast(bmp32x32)), 0, RGB(128, 0, 0)); if (FAILED(hr)) return hr; return ((CComponentDataImpl*)m_pComponentData)->AddDomainIconToResultPane(m_pImageResult); } STDMETHODIMP CComponentImpl::GetDisplayInfo(LPRESULTDATAITEM pResult) { ASSERT(pResult != NULL); CDomainObject* pDomain = reinterpret_cast(pResult->lParam); if ( (pDomain != NULL) && (pResult->mask & RDI_STR) ) { pResult->str = (LPWSTR)pDomain->GetDisplayString(pResult->nCol); TRACE(L"pResult->str = %s\n", pResult->str); } if ((pResult->mask & RDI_IMAGE) && (pResult->nCol == 0)) { pResult->nImage = pDomain->GetImageIndex(); } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IExtendContextMenu Implementation STDMETHODIMP CComponentImpl::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK pContextMenuCallback, long * pInsertionAllowed) { return dynamic_cast(m_pComponentData)-> AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed); } STDMETHODIMP CComponentImpl::Command(long nCommandID, LPDATAOBJECT pDataObject) { return dynamic_cast(m_pComponentData)-> Command(nCommandID, pDataObject); } HRESULT CComponentImpl::OnShow(CFolderObject* pFolderObject, LPARAM arg, LPARAM param) { // Note - arg is TRUE when it is time to enumerate if (arg == TRUE) { // Show the headers for this nodetype InitializeHeaders(pFolderObject); Enumerate(pFolderObject, param); } return S_OK; } HRESULT CComponentImpl::OnAddImages(CFolderObject* pFolderObject, LPARAM arg, LPARAM param) { return InitializeBitmaps(pFolderObject); } HRESULT CComponentImpl::OnPropertyChange(LPDATAOBJECT lpDataObject) { return S_OK; } HRESULT CComponentImpl::OnUpdateView(LPDATAOBJECT lpDataObject) { return S_OK; } void CComponentImpl::Enumerate(CFolderObject* pFolderObject, HSCOPEITEM pParent) { } ////////////////////////////////////////////////////////////////////////// // CDomainSnapinAbout CDomainSnapinAbout::CDomainSnapinAbout(): CSnapinAbout(IDS_SNAPINABOUT_DESCRIPTION, IDI_DOMAIN, IDB_DOMAIN_SMALL, IDB_DOMAIN_SMALL, IDB_DOMAIN_LARGE, RGB(255,0,255)) { } //////////////////////////////////////////////////////////////////// // CHiddenWnd const UINT CHiddenWnd::s_SheetCloseNotificationMessage = WM_DSA_SHEET_CLOSE_NOTIFY; const UINT CHiddenWnd::s_SheetCreateNotificationMessage = WM_DSA_SHEET_CREATE_NOTIFY; BOOL CHiddenWnd::Create() { RECT rcPos; // NOTICE-2002/03/07-ericb - SecurityPush: zeroing a struct ZeroMemory(&rcPos, sizeof(RECT)); HWND hWnd = CWindowImpl::Create( NULL, //HWND hWndParent, rcPos, //RECT& rcPos, NULL, //LPCTSTR szWindowName = NULL, WS_POPUP, //DWORD dwStyle = WS_CHILD | WS_VISIBLE, 0x0, //DWORD dwExStyle = 0, 0 //UINT nID = 0 ); if (!hWnd) { TRACE(L"Hidden Window creation failed with error %d\n", GetLastError()); return FALSE; } return TRUE; } LRESULT CHiddenWnd::OnSheetCloseNotification(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ASSERT(m_pCD != NULL); CFolderObject* pCookie = reinterpret_cast(wParam); m_pCD->_OnSheetClose(pCookie); return 1; } LRESULT CHiddenWnd::OnSheetCreateNotification(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ASSERT(m_pCD != NULL); PDSA_SEC_PAGE_INFO pDsaSecondaryPageInfo = reinterpret_cast(wParam); ASSERT(pDsaSecondaryPageInfo != NULL); PWSTR pwzDC = (PWSTR)lParam; m_pCD->_OnSheetCreate(pDsaSecondaryPageInfo, pwzDC); ::LocalFree(pDsaSecondaryPageInfo); if (pwzDC && !IsBadReadPtr(pwzDC, sizeof(PWSTR))) { ::LocalFree(pwzDC); } return 1; }