// This is a part of the Microsoft Management Console. // Copyright 1995 - 1997 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Management Console and related // electronic documentation provided with the interfaces. #include "stdafx.h" #include "Service.h" #include "CSnapin.h" #include "DataObj.h" #include "afxdlgs.h" #include "resource.h" #include "genpage.h" // Step 3 #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // All data is static for the sample FOLDER_DATA FolderData[NUM_FOLDERS] = { {L"User Data", L"1111", L"Info about users", USER}, {L"Company Data", L"2222", L"Info about Companies", COMPANY}, {L"Virtual Data", L"3333", L"Info about virtual items", VIRTUAL}, {L"", L"", L"",STATIC} }; FOLDER_DATA ExtFolderData[NUM_FOLDERS] = { {L"1:", L"1111", L"Info about users", EXT_USER}, {L"2:", L"2222", L"Info about Companies", EXT_COMPANY}, {L"3:", L"3333", L"Infor about virtual items", EXT_VIRTUAL}, {L"", L"", L"",STATIC} }; static MMCBUTTON SnapinButtons[] = { { 0, 1, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Folder", L"New Folder" }, { 1, 2, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Inbox", L"Mail Inbox"}, { 2, 3, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Outbox", L"Mail Outbox" }, { 3, 4, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Send", L"Send Message" }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, L" ", L"" }, { 4, 5, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Trash", L"Trash" }, { 5, 6, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Open", L"Open Folder"}, { 6, 7, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"News", L"Today's News" }, { 7, 8, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"INews", L"Internet News" }, }; static MMCBUTTON SnapinButtons2[] = { { 0, 10, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Compose", L"Compose Message" }, { 1, 20, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Print", L"Print Message" }, { 2, 30, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Find", L"Find Message" }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, L" ", L"" }, { 3, 40, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Inbox", L"Inbox" }, { 4, 50, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Smile", L"Smile :-)" }, { 5, 60, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Reply", L"Reply" }, { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP , L" ", L"" }, { 6, 70, TBSTATE_ENABLED, TBSTYLE_BUTTON, L"Reply All", L"Reply All" }, }; enum { // Identifiers for each of the commands/views to be inserted into the context menu. IDM_COMMAND1, IDM_COMMAND2, IDM_DEFAULT_MESSAGE_VIEW, IDM_SAMPLE_OCX_VIEW, IDM_SAMPLE_WEB_VIEW }; static int n_count = 0; #define ODS OutputDebugString #ifdef DBX void DbxPrint(LPTSTR pszFmt, ...) { va_list va; va_start (va, pszFmt); TCHAR buf[250]; wsprintf(buf, pszFmt, va); OutputDebugString(buf); va_end(va); } //#define DBX_PRINT DbxPrint inline void __DummyTrace(LPTSTR, ...) { } #define DBX_PRINT 1 ? (void)0 : ::__DummyTrace #else inline void __DummyTrace(LPTSTR, ...) { } #define DBX_PRINT 1 ? (void)0 : ::__DummyTrace #endif // // The sample snap-in only has 1 property type and it's the workstation name // // // Extracts the coclass guid format from the data object // template TYPE* Extract(LPDATAOBJECT lpDataObject, unsigned int ucf) { ASSERT(lpDataObject != NULL); TYPE* p = NULL; CLIPFORMAT cf = (CLIPFORMAT)ucf; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; FORMATETC formatetc = { cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; // Allocate memory for the stream int len = (cf == CDataObject::m_cfWorkstation) ? ((MAX_COMPUTERNAME_LENGTH+1) * sizeof(TYPE)) : sizeof(TYPE); stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, len); // Get the workstation name from the data object do { if (stgmedium.hGlobal == NULL) break; if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium))) break; p = reinterpret_cast(stgmedium.hGlobal); if (p == NULL) break; } while (FALSE); return p; } template void ReleaseExtracted (T* t) { GlobalFree (reinterpret_cast(t)); } BOOL IsMMCMultiSelectDataObject(IDataObject* pDataObject) { if (pDataObject == NULL) return FALSE; static CLIPFORMAT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = (CLIPFORMAT)RegisterClipboardFormat(W2T(CCF_MMC_MULTISELECT_DATAOBJECT)); } FORMATETC fmt = {s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; return (pDataObject->QueryGetData(&fmt) == S_OK); } BOOL IsMyMultiSelectDataObject(IDataObject* pIDataObject) { if (pIDataObject == NULL) return FALSE; CDataObject* pCDataObject = dynamic_cast(pIDataObject); if (pCDataObject == NULL) return FALSE; return pCDataObject->IsMultiSelDobj(); } // Data object extraction helpers CLSID* ExtractClassID(LPDATAOBJECT lpDataObject) { return Extract(lpDataObject, CDataObject::m_cfCoClass); } GUID* ExtractNodeType(LPDATAOBJECT lpDataObject) { return Extract(lpDataObject, CDataObject::m_cfNodeType); } wchar_t* ExtractWorkstation(LPDATAOBJECT lpDataObject) { return Extract(lpDataObject, CDataObject::m_cfWorkstation); } INTERNAL* ExtractInternalFormat(LPDATAOBJECT lpDataObject) { return Extract(lpDataObject, CDataObject::m_cfInternal); } void ReleaseClassID (CLSID* pclsid) { ReleaseExtracted(pclsid); } void ReleaseNodeType (GUID* pguid) { ReleaseExtracted(pguid); } void ReleaseWorkstation (wchar_t* p) { ReleaseExtracted(p); } void ReleaseInternalFormat (INTERNAL* pInternal) { ReleaseExtracted(pInternal); } HRESULT _QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, CComponentDataImpl* pImpl, LPDATAOBJECT* ppDataObject) { ASSERT(ppDataObject != NULL); ASSERT(pImpl != NULL); CComObject* pObject; CComObject::CreateInstance(&pObject); ASSERT(pObject != NULL); // Save cookie and type for delayed rendering pObject->SetType(type); pObject->SetCookie(cookie); #ifdef _DEBUG pObject->SetComponentData(pImpl); #endif // Store the coclass with the data object pObject->SetClsid(pImpl->GetCoClassID()); return pObject->QueryInterface(IID_IDataObject, reinterpret_cast(ppDataObject)); } DWORD GetItemType(MMC_COOKIE cookie) { // folder = CFoder* is cookie // result = RESULT_DATA* is the cookie return (*reinterpret_cast(cookie)); } ///////////////////////////////////////////////////////////////////////////// // Return TRUE if we are enumerating our main folder BOOL CSnapin::IsEnumerating(LPDATAOBJECT lpDataObject) { BOOL bResult = FALSE; ASSERT(lpDataObject); GUID* nodeType = ExtractNodeType(lpDataObject); // Is this my main node (static folder node type) if (::IsEqualGUID(*nodeType, cNodeTypeStatic) == TRUE) bResult = TRUE; // Free resources ::GlobalFree(reinterpret_cast(nodeType)); return bResult; } ///////////////////////////////////////////////////////////////////////////// // CSnapin's IComponent implementation // guid for custom view static WCHAR* szCalendarGUID = L"{8E27C92B-1264-101C-8A2F-040224009C02}"; static WCHAR* szMicrosoftURL = L"www.microsoft.com"; STDMETHODIMP CSnapin::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType, long* pViewOptions) { *pViewOptions = MMC_VIEW_OPTIONS_MULTISELECT; // if list view if (m_CustomViewID == VIEW_DEFAULT_LV) { m_bVirtualView = FALSE; // if static folder not selected if (cookie != NULL) { // See if virtual data folder is selected CFolder* pFolder = reinterpret_cast(cookie); ASSERT(pFolder->itemType == SCOPE_ITEM); FOLDER_TYPES ftype = pFolder->GetType(); m_bVirtualView = (ftype == VIRTUAL || ftype == EXT_VIRTUAL); if (m_bVirtualView) *pViewOptions |= MMC_VIEW_OPTIONS_OWNERDATALIST; } return S_FALSE; } WCHAR szMessageViewGUID[40]; WCHAR* pszView; switch (m_CustomViewID) { case VIEW_CALENDAR_OCX: pszView = szCalendarGUID; break; case VIEW_MICROSOFT_URL: pszView = szMicrosoftURL; break; case VIEW_DEFAULT_MESSAGE_VIEW: StringFromGUID2 (CLSID_MessageView, szMessageViewGUID, ARRAYLEN(szMessageViewGUID)); pszView = szMessageViewGUID; break; default: ASSERT (false && "CSnapin::GetResultViewType: Unknown view ID"); return (S_FALSE); break; } UINT uiByteLen = (wcslen(pszView) + 1) * sizeof(WCHAR); LPOLESTR psz = (LPOLESTR)::CoTaskMemAlloc(uiByteLen); USES_CONVERSION; if (psz != NULL) { wcscpy(psz, pszView); *ppViewType = psz; return S_OK; } return S_FALSE; } STDMETHODIMP CSnapin::Initialize(LPCONSOLE lpConsole) { DBX_PRINT(_T(" ---------- CSnapin::Initialize<0x08x>\n"), this); ASSERT(lpConsole != NULL); m_bInitializedC = true; 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); return S_OK; } STDMETHODIMP CSnapin::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (IS_SPECIAL_DATAOBJECT(lpDataObject)) { if (event == MMCN_BTN_CLICK) { if (m_CustomViewID != VIEW_DEFAULT_LV) { switch (param) { case MMC_VERB_REFRESH: ::AfxMessageBox(_T("MMCN_BTN_CLICK::MMC_VERB_REFRESH")); _OnRefresh(lpDataObject); break; case MMC_VERB_PROPERTIES: ::AfxMessageBox(_T("MMCN_BTN_CLICK::MMC_VERB_PROPERTIES")); break; default: ::AfxMessageBox(_T("MMCN_BTN_CLICK::param unknown")); break; } } } else { switch (event) { case MMCN_REFRESH: ::AfxMessageBox(_T("MMCN_BTN_CLICK::MMCN_REFRESH")); _OnRefresh(lpDataObject); break; } } return S_OK; } HRESULT hr = S_OK; MMC_COOKIE cookie; if (event == MMCN_PROPERTY_CHANGE) { hr = OnPropertyChange(lpDataObject); } else if (event == MMCN_VIEW_CHANGE) { hr = OnUpdateView(lpDataObject); } else if (event == MMCN_DESELECT_ALL) { DBX_PRINT(_T("CSnapin::Notify -> MMCN_DESELECT_ALL \n")); } else if (event == MMCN_COLUMN_CLICK) { DBX_PRINT(_T("CSnapin::Notify -> MMCN_COLUMN_CLICK \n")); } else if (event == MMCN_SNAPINHELP) { AfxMessageBox(_T("CSnapin::Notify ->MMCN_SNAPINHELP")); } else { INTERNAL* pInternal = NULL; if (IsMMCMultiSelectDataObject(lpDataObject) == FALSE) { pInternal = ExtractInternalFormat(lpDataObject); if (pInternal == NULL) { ASSERT(FALSE); return S_OK; } if (pInternal) cookie = pInternal->m_cookie; } switch(event) { case MMCN_ACTIVATE: break; case MMCN_CLICK: hr = OnResultItemClk(pInternal->m_type, cookie); break; case MMCN_DBLCLICK: if (pInternal->m_type == CCT_RESULT) Command(IDM_COMMAND1, lpDataObject); else hr = S_FALSE; break; case MMCN_ADD_IMAGES: OnAddImages(cookie, arg, param); break; case MMCN_SHOW: hr = OnShow(cookie, arg, param); break; case MMCN_MINIMIZED: hr = OnMinimize(cookie, arg, param); break; case MMCN_INITOCX: // ::MessageBox(NULL, _T("MMCN_INITOCX"), _T("TRACE"), MB_OK); ASSERT(param != 0); break; case MMCN_DESELECT_ALL: case MMCN_SELECT: HandleStandardVerbs((event == MMCN_DESELECT_ALL), arg, lpDataObject); break; case MMCN_PASTE: AfxMessageBox(_T("CSnapin::MMCN_PASTE")); break; case MMCN_DELETE: AfxMessageBox(_T("CSnapin::MMCN_DELETE")); break; case MMCN_CONTEXTHELP: hr = OnContextHelp(lpDataObject); break; case MMCN_REFRESH: AfxMessageBox(_T("CSnapin::MMCN_REFRESH")); _OnRefresh(lpDataObject); break; case MMCN_PRINT: AfxMessageBox(_T("CSnapin::MMCN_PRINT")); break; case MMCN_RENAME: // ODS(_T("\n\n\t\tCSnapin::MMCN_RENAME\n\n")); break; case MMCN_RESTORE_VIEW: { // user selected Back or Forward buttons: // we get the same info back that we gave // MMC during the GetResultViewType call. MMC_RESTORE_VIEW* pmrv = (MMC_RESTORE_VIEW*)arg; BOOL * b = (BOOL*)param; *b = TRUE; // we're handling it // first, setup m_bVirtualMode m_bVirtualView = FALSE; CFolder* pFolder = reinterpret_cast(pmrv->cookie); if (pFolder != NULL) if (pFolder->GetType() == VIRTUAL) m_bVirtualView = TRUE; WCHAR szMessageViewGUID[40]; StringFromGUID2 (CLSID_MessageView, szMessageViewGUID, ARRAYLEN(szMessageViewGUID)); // also, maintain m_CustomViewID if (pmrv->pViewType == NULL) m_CustomViewID = VIEW_DEFAULT_LV; else if (!wcscmp (pmrv->pViewType, szCalendarGUID)) m_CustomViewID = VIEW_CALENDAR_OCX; else if (!wcscmp (pmrv->pViewType, szMicrosoftURL)) m_CustomViewID = VIEW_MICROSOFT_URL; else if (!wcscmp (pmrv->pViewType, szMessageViewGUID)) m_CustomViewID = VIEW_DEFAULT_MESSAGE_VIEW; else // doesn't look like one of mine, but it is: // if the URL leads to another URL. This is // sent to you can still maintain your checks // in the view menu. m_CustomViewID = VIEW_MICROSOFT_URL; // also, you could be re-directed via script or asp. // also, you may have neglected } break; // Note - Future expansion of notify types possible default: hr = E_UNEXPECTED; break; } if (pInternal != NULL) { ::GlobalFree(reinterpret_cast(pInternal)); } } if (m_pResult) m_pResult->SetDescBarText(L"hello world"); return hr; } void CSnapin::_OnRefresh(LPDATAOBJECT pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); INTERNAL* pInternal = ExtractInternalFormat(pDataObject); if (pInternal == NULL) return; USES_CONVERSION; if (pInternal->m_type == CCT_SCOPE) { CComponentDataImpl* pData = dynamic_cast(m_pComponentData); if (pData->IsPrimaryImpl()) { CFolder* pFolder = pData->FindObject(pInternal->m_cookie); ::AfxMessageBox(pInternal->m_cookie ? OLE2T(pFolder->m_pszName) : _T("Files")); pData->DeleteAndReinsertAll(); } } else { RESULT_DATA* pData = reinterpret_cast(pInternal->m_cookie); ::AfxMessageBox(OLE2T(pData->szName)); } } HRESULT CSnapin::OnContextHelp(LPDATAOBJECT pdtobj) { TCHAR name[128]; GetItemName(pdtobj, name); TCHAR buf[200]; wsprintf(buf, _T("Context help requested for item: %s"), name); ::MessageBox(NULL, buf, _T("TRACE"), MB_OK); return S_OK; } STDMETHODIMP CSnapin::Destroy(MMC_COOKIE cookie) { DBX_PRINT(_T(" ---------- CSnapin::Destroy<0x08x>\n"), this); ASSERT(m_bInitializedC); m_bDestroyedC = true; 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; } typedef CArray CGUIDArray; void GuidArray_Add(CGUIDArray& rgGuids, const GUID& guid) { for (int i=rgGuids.GetUpperBound(); i >= 0; --i) { if (rgGuids[i] == guid) break; } if (i < 0) rgGuids.Add(guid); } HRESULT CSnapin::QueryMultiSelectDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { ASSERT(ppDataObject != NULL); if (ppDataObject == NULL) return E_POINTER; CGUIDArray rgGuids; if (m_bVirtualView == TRUE) { GuidArray_Add(rgGuids, cNodeTypeCompany); } else { // Determine the items selected ASSERT(m_pResult != NULL); RESULTDATAITEM rdi; ZeroMemory(&rdi, sizeof(rdi)); rdi.mask = RDI_STATE; rdi.nIndex = -1; rdi.nState = TVIS_SELECTED; while (m_pResult->GetNextItem(&rdi) == S_OK) { FOLDER_TYPES fType; DWORD* pdw = reinterpret_cast(rdi.lParam); if (*pdw == SCOPE_ITEM) { CFolder* pFolder = reinterpret_cast(rdi.lParam); fType = pFolder->m_type; } else { ASSERT(*pdw == RESULT_ITEM); RESULT_DATA* pData = reinterpret_cast(rdi.lParam); fType = pData->parentType; } const GUID* pguid; switch (fType) { case STATIC: pguid = &cNodeTypeStatic; break; case COMPANY: pguid = &cNodeTypeCompany; break; case USER: pguid = &cNodeTypeUser; break; case EXT_COMPANY: pguid = &cNodeTypeExtCompany; break; case EXT_USER: pguid = &cNodeTypeExtUser; break; case VIRTUAL: case EXT_VIRTUAL: pguid = &cNodeTypeVirtual; break; default: return E_FAIL; } GuidArray_Add(rgGuids, *pguid); } } CComObject* pObject; CComObject::CreateInstance(&pObject); ASSERT(pObject != NULL); // Save cookie and type for delayed rendering pObject->SetType(type); pObject->SetCookie(cookie); pObject->SetMultiSelDobj(); CComponentDataImpl* pImpl = dynamic_cast(m_pComponentData); #ifdef _DEBUG pObject->SetComponentData(pImpl); #endif // Store the coclass with the data object pObject->SetClsid(pImpl->GetCoClassID()); UINT cb = rgGuids.GetSize() * sizeof(GUID); GUID* pGuid = new GUID[rgGuids.GetSize()]; CopyMemory(pGuid, rgGuids.GetData(), cb); pObject->SetMultiSelData((BYTE*)pGuid, cb); return pObject->QueryInterface(IID_IDataObject, reinterpret_cast(ppDataObject)); return S_OK; } STDMETHODIMP CSnapin::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { if (cookie == MMC_MULTI_SELECT_COOKIE) return QueryMultiSelectDataObject(cookie, type, ppDataObject); ASSERT(type == CCT_RESULT); #ifdef _DEBUG if (cookie != MMC_MULTI_SELECT_COOKIE && m_bVirtualView == FALSE) { DWORD dwItemType = GetItemType(cookie); ASSERT(dwItemType == RESULT_ITEM); } #endif // Delegate it to the IComponentData ASSERT(m_pComponentData != NULL); CComponentDataImpl* pImpl = dynamic_cast(m_pComponentData); ASSERT(pImpl != NULL); return _QueryDataObject(cookie, type, pImpl, ppDataObject); } ///////////////////////////////////////////////////////////////////////////// // CSnapin's implementation specific members DEBUG_DECLARE_INSTANCE_COUNTER(CSnapin); CSnapin::CSnapin() : m_bIsDirty(TRUE), m_bInitializedC(false), m_bDestroyedC(false) { DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapin); Construct(); } CSnapin::~CSnapin() { #if DBG==1 ASSERT(dbg_cRef == 0); #endif DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapin); SAFE_RELEASE(m_pToolbar1); SAFE_RELEASE(m_pToolbar2); SAFE_RELEASE(m_pMenuButton1); SAFE_RELEASE(m_pControlbar); // Make sure the interfaces have been released ASSERT(m_pConsole == NULL); ASSERT(m_pHeader == NULL); ASSERT(m_pToolbar1 == NULL); ASSERT(m_pToolbar2 == NULL); delete m_pbmpToolbar1; delete m_pbmpToolbar2; ASSERT(!m_bInitializedC || m_bDestroyedC); Construct(); } void CSnapin::Construct() { #if DBG==1 dbg_cRef = 0; #endif m_pConsole = NULL; m_pHeader = NULL; m_pResult = NULL; m_pImageResult = NULL; m_pComponentData = NULL; m_pToolbar1 = NULL; m_pToolbar2 = NULL; m_pControlbar = NULL; m_pMenuButton1 = NULL; m_pbmpToolbar1 = NULL; m_pbmpToolbar2 = NULL; m_pConsoleVerb = NULL; m_CustomViewID = VIEW_DEFAULT_LV; // m_CustomViewID = VIEW_MICROSOFT_URL; // m_CustomViewID = VIEW_CALENDAR_OCX; // m_CustomViewID = VIEW_DEFAULT_MESSAGE_VIEW; m_bVirtualView = FALSE; m_dwVirtualSortOptions = 0; } void CSnapin::LoadResources() { // Load strings from resources m_column1.LoadString(IDS_NAME); m_column2.LoadString(IDS_SIZE); m_column3.LoadString(IDS_TYPE); } HRESULT CSnapin::InitializeHeaders(MMC_COOKIE cookie) { HRESULT hr = S_OK; ASSERT(m_pHeader); USES_CONVERSION; // Put the correct headers depending on the cookie // Note - cookie ignored for this sample m_pHeader->InsertColumn(0, T2COLE(m_column1), LVCFMT_LEFT, 180); // Name m_pHeader->InsertColumn(1, T2COLE(m_column2), LVCFMT_RIGHT, 90); // Size m_pHeader->InsertColumn(2, T2COLE(m_column3), LVCFMT_LEFT, 160); // Type return hr; } HRESULT CSnapin::InitializeBitmaps(MMC_COOKIE cookie) { ASSERT(m_pImageResult != NULL); ::CBitmap bmp16x16; ::CBitmap bmp32x32; // Load the bitmaps from the dll bmp16x16.LoadBitmap(IDB_16x16); bmp32x32.LoadBitmap(IDB_32x32); // Set the images m_pImageResult->ImageListSetStrip( reinterpret_cast(static_cast(bmp16x16)), reinterpret_cast(static_cast(bmp32x32)), 0, RGB(255, 0, 255)); return S_OK; } WCHAR* StringFromFolderType(FOLDER_TYPES type) { static WCHAR* s_szStatic = L"Static"; static WCHAR* s_szCompany = L"Company"; static WCHAR* s_szUser = L"User"; static WCHAR* s_szVirtual = L"Virtual"; static WCHAR* s_szUnknown = L"Unknown"; switch (type) { case STATIC: return s_szStatic; case COMPANY: return s_szCompany; case USER: return s_szUser; case VIRTUAL: return s_szVirtual; default: return s_szUnknown; } } STDMETHODIMP CSnapin::GetDisplayInfo(LPRESULTDATAITEM pResult) { static WCHAR* s_szSize = L"200"; ASSERT(pResult != NULL); if (pResult) { if (pResult->bScopeItem == TRUE) { CFolder* pFolder = reinterpret_cast(pResult->lParam); if (pResult->mask & RDI_STR) { if (pResult->nCol == 0) pResult->str = pFolder->m_pszName; else if (pResult->nCol == 1) pResult->str = (LPOLESTR)s_szSize; else pResult->str = (LPOLESTR)StringFromFolderType(pFolder->m_type); ASSERT(pResult->str != NULL); if (pResult->str == NULL) pResult->str = (LPOLESTR)L""; } if (pResult->mask & RDI_IMAGE) { switch(pFolder->GetType()) { case USER: case EXT_USER: pResult->nImage = USER_IMAGE; break; case COMPANY: case EXT_COMPANY: pResult->nImage = COMPANY_IMAGE; break; case VIRTUAL: pResult->nImage = VIRTUAL_IMAGE; break; } } } else { RESULT_DATA* pData; // if virtual, derive result item from index // else lParam is the item pointer if (m_bVirtualView) pData = GetVirtualResultItem(pResult->nIndex); else pData= reinterpret_cast(pResult->lParam); if (pResult->mask & RDI_STR) { if (pResult->nCol == 0) pResult->str = (LPOLESTR)pData->szName; else if(pResult->nCol == 1) pResult->str = (LPOLESTR)pData->szSize; else pResult->str = (LPOLESTR)pData->szType; ASSERT(pResult->str != NULL); if (pResult->str == NULL) pResult->str = (LPOLESTR)L""; } // MMC can request image and indent for virtual data if (pResult->mask & RDI_IMAGE) pResult->nImage = 4; } } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // IExtendContextMenu Implementation // Array of menu item commands to be inserted into the contest menu. // Note - the first item is the menu text, // CCM_SPECIAL_DEFAULT_ITEM // the second item is the status string static CONTEXTMENUITEM menuItems[] = { { L"Command 1", L"Sample extension menu added by snapin (Command 1)", IDM_COMMAND1, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0 }, { L"Command 2", L"Sample extension menu added by snapin (Command 2)", IDM_COMMAND2, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0 }, { NULL, NULL, 0, 0, 0 } }; // Array of view items to be inserted into the context menu. static CONTEXTMENUITEM viewItems[] = { { L"Message View", L"Default message view", IDM_DEFAULT_MESSAGE_VIEW, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0 }, { L"Calendar", L"Sample OCX custom view", IDM_SAMPLE_OCX_VIEW, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0 }, { szMicrosoftURL, L"Sample WEB custom view", IDM_SAMPLE_WEB_VIEW, CCM_INSERTIONPOINTID_PRIMARY_VIEW, 0, 0 }, { NULL, NULL, 0, 0, 0 }, }; // guid for custom view static GUID CLSID_SmGraphControl = {0xC4D2D8E0L,0xD1DD,0x11CE,0x94,0x0F,0x00,0x80,0x29,0x00,0x43,0x47}; STDMETHODIMP CSnapin::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK pContextMenuCallback, long *pInsertionAllowed) { #if 1 //testing ASSERT(pDataObject != NULL); if (pDataObject && IsMMCMultiSelectDataObject(pDataObject)) { static CLIPFORMAT s_cf = 0; if (s_cf == 0) { USES_CONVERSION; s_cf = (CLIPFORMAT)RegisterClipboardFormat(W2T(CCF_MULTI_SELECT_SNAPINS)); } FORMATETC fmt = {s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; STGMEDIUM stgm = { TYMED_HGLOBAL, NULL }; HRESULT hr = pDataObject->GetData(&fmt, &stgm); SMMCDataObjects* pData = (SMMCDataObjects*)stgm.hGlobal; int count = pData->count; IDataObject* pDO = NULL; hr = pData->lpDataObject[0]->QueryInterface(IID_IDataObject, (void**)&pDO); pDO->Release(); } #endif viewItems[0].fFlags = (m_CustomViewID == VIEW_DEFAULT_MESSAGE_VIEW) ? MF_CHECKED : 0; viewItems[1].fFlags = (m_CustomViewID == VIEW_CALENDAR_OCX) ? MF_CHECKED : 0; viewItems[2].fFlags = (m_CustomViewID == VIEW_MICROSOFT_URL) ? MF_CHECKED : 0; CComponentDataImpl* pCCD = dynamic_cast(m_pComponentData); HRESULT hr = pCCD->AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed); #if 0 /* * add do-nothing commands on odd numbered items in the virtual list view */ if (SUCCEEDED (hr) && (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) && m_bVirtualView) { INTERNAL* pInternal = pDataObject ? ExtractInternalFormat(pDataObject) : NULL; if (pInternal && (pInternal->m_cookie % 2)) { CONTEXTMENUITEM cmi; cmi.strName = L"Another command (odd, virtual-only)"; cmi.strStatusBarText = NULL; cmi.lCommandID = 0xDDDD; cmi.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP; cmi.fFlags = 0; cmi.fSpecialFlags = 0; pContextMenuCallback->AddItem (&cmi); ReleaseInternalFormat (pInternal); } } #endif return (hr); } STDMETHODIMP CSnapin::Command(long nCommandID, LPDATAOBJECT pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); INTERNAL* pInternal = ExtractInternalFormat(pDataObject); if (pInternal == NULL) return E_FAIL; if (pInternal->m_type == CCT_SCOPE) { // Handle view specific commands here switch (nCommandID) { case IDM_SAMPLE_WEB_VIEW: case IDM_SAMPLE_OCX_VIEW: case IDM_DEFAULT_MESSAGE_VIEW: m_CustomViewID = (nCommandID == IDM_SAMPLE_OCX_VIEW) ? VIEW_CALENDAR_OCX : (nCommandID == IDM_SAMPLE_WEB_VIEW) ? VIEW_MICROSOFT_URL : VIEW_DEFAULT_MESSAGE_VIEW; // Ask console to reslelect the node to force a new view if (pInternal->m_cookie == 0) { CComponentDataImpl* pCCDI = dynamic_cast(m_pComponentData); ASSERT(pCCDI != NULL); m_pConsole->SelectScopeItem(pCCDI->m_pStaticRoot); } else { CFolder* pFolder = reinterpret_cast(pInternal->m_cookie); m_pConsole->SelectScopeItem(pFolder->m_pScopeItem->ID); } break; case MMCC_STANDARD_VIEW_SELECT: m_CustomViewID = VIEW_DEFAULT_LV; break; default: // Pass non-view specific commands to ComponentData return dynamic_cast(m_pComponentData)-> Command(nCommandID, pDataObject); } } else if (pInternal->m_type == CCT_RESULT) { // Handle each of the commands. switch (nCommandID) { case IDM_COMMAND1: case IDM_COMMAND2: { m_pResult->ModifyViewStyle(MMC_SINGLESEL, (MMC_RESULT_VIEW_STYLE)0); RESULTDATAITEM rdi; ZeroMemory(&rdi, sizeof(rdi)); rdi.mask = RDI_STATE; rdi.nState = LVIS_SELECTED; rdi.nIndex = -1; m_pResult->GetNextItem(&rdi); int iSel = rdi.nIndex; int nImage = rdi.nImage; HRESULTITEM hri = 0; RESULT_DATA* pData; // if virtual view, derive result item from the index if (m_bVirtualView) { pData = GetVirtualResultItem(iSel); } // else get the cookie (which is result item ptr) else { ZeroMemory(&rdi, sizeof(rdi)); rdi.mask = RDI_PARAM | RDI_IMAGE; rdi.nIndex = iSel; HRESULT hr = m_pResult->GetItem(&rdi); nImage = rdi.nImage; ASSERT(SUCCEEDED(hr)); ASSERT(rdi.lParam != 0); m_pResult->FindItemByLParam (rdi.lParam, &hri); pData = reinterpret_cast(rdi.lParam); } #if 0 static int nIconIndex = 12; nIconIndex = (nIconIndex == 12) ? 13 : 12; HICON hIcon = ExtractIcon (AfxGetInstanceHandle(), _T("%SystemRoot%\\system32\\shell32.dll"), nIconIndex); IImageList* pil; m_pConsole->QueryResultImageList(&pil); _asm int 3; pil->ImageListSetIcon((LONG_PTR*) hIcon, nImage); pil->ImageListSetIcon((LONG_PTR*) hIcon, ILSI_SMALL_ICON (nImage)); pil->ImageListSetIcon((LONG_PTR*) hIcon, ILSI_LARGE_ICON (nImage)); pil->Release(); m_pResult->UpdateItem (hri); #else CString strBuf = (nCommandID == IDM_COMMAND1) ? _T("\t Command 1 executed.\n\n") : _T("\t Command 2 executed.\n\n"); strBuf += pData->szName; strBuf += _T(" is the currently selected item."); AfxMessageBox(strBuf); // change image in list if (!m_bVirtualView) { ZeroMemory(&rdi, sizeof(rdi)); rdi.mask = RDI_IMAGE; rdi.nIndex = iSel; rdi.nImage = 3; HRESULT hr = m_pResult->SetItem(&rdi); ASSERT(SUCCEEDED(hr)); } #endif } break; default: ASSERT(FALSE); // Unknown command! break; } } else { ASSERT(0); } ::GlobalFree(reinterpret_cast(pInternal)); return S_OK; } STDMETHODIMP CSnapin::GetClassID(CLSID *pClassID) { ASSERT(pClassID != NULL); // Copy the CLSID for this snapin *pClassID = CLSID_Snapin; return E_NOTIMPL; } STDMETHODIMP CSnapin::IsDirty() { // Always save / Always dirty. return ThisIsDirty() ? S_OK : S_FALSE; } STDMETHODIMP CSnapin::Load(IStream *pStm) { DBX_PRINT(_T(" ---------- CSnapin::Load<0x08x>\n"), this); ASSERT(m_bInitializedC); ASSERT(pStm); // Read the string char psz[10]; ULONG nBytesRead; HRESULT hr = pStm->Read(psz, 10, &nBytesRead); // Verify that the read succeeded ASSERT(SUCCEEDED(hr) && nBytesRead == 10); // check to see if the string is the correct string ASSERT(strcmp("987654321", psz) == 0); ClearDirty(); return SUCCEEDED(hr) ? S_OK : E_FAIL; } STDMETHODIMP CSnapin::Save(IStream *pStm, BOOL fClearDirty) { DBX_PRINT(_T(" ---------- CSnapin::Save<0x08x>\n"), this); ASSERT(m_bInitializedC); ASSERT(pStm); // Write the string ULONG nBytesWritten; HRESULT hr = pStm->Write("987654321", 10, &nBytesWritten); // Verify that the write operation succeeded ASSERT(SUCCEEDED(hr) && nBytesWritten == 10); if (FAILED(hr)) return STG_E_CANTSAVE; if (fClearDirty) ClearDirty(); return S_OK; } STDMETHODIMP CSnapin::GetSizeMax(ULARGE_INTEGER *pcbSize) { ASSERT(pcbSize); // Set the size of the string to be saved ULISet32(*pcbSize, 10); return S_OK; } /////////////////////////////////////////////////////////////////////////////// // IComponentData implementation DEBUG_DECLARE_INSTANCE_COUNTER(CComponentDataImpl); CComponentDataImpl::CComponentDataImpl() : m_bIsDirty(TRUE), m_pScope(NULL), m_pConsole(NULL), m_bInitializedCD(false), m_bDestroyedCD(false) { DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentDataImpl); #ifdef _DEBUG m_cDataObjects = 0; #endif } CComponentDataImpl::~CComponentDataImpl() { DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentDataImpl); ASSERT(m_pScope == NULL); ASSERT(!m_bInitializedCD || m_bDestroyedCD); // Some snap-in is hanging on to data objects. // If they access, it will crash!!! ASSERT(m_cDataObjects <= 1); } STDMETHODIMP CComponentDataImpl::Initialize(LPUNKNOWN pUnknown) { DBX_PRINT(_T(" ---------- CComponentDataImpl::Initialize<0x08x>\n"), this); m_bInitializedCD = true; ASSERT(pUnknown != NULL); HRESULT hr; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // MMC should only call ::Initialize once! ASSERT(m_pScope == NULL); pUnknown->QueryInterface(IID_IConsoleNameSpace, reinterpret_cast(&m_pScope)); // add the images for the scope tree ::CBitmap bmp16x16; LPIMAGELIST lpScopeImage; hr = pUnknown->QueryInterface(IID_IConsole, reinterpret_cast(&m_pConsole)); ASSERT(hr == S_OK); hr = m_pConsole->QueryScopeImageList(&lpScopeImage); ASSERT(hr == S_OK); // Load the bitmaps from the dll bmp16x16.LoadBitmap(IDB_16x16); // Set the images lpScopeImage->ImageListSetStrip( reinterpret_cast(static_cast(bmp16x16)), reinterpret_cast(static_cast(bmp16x16)), 0, RGB(255, 0, 255)); lpScopeImage->Release(); return S_OK; } STDMETHODIMP CComponentDataImpl::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 CComponentDataImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { AFX_MANAGE_STATE (AfxGetStaticModuleState()); ASSERT(m_pScope != NULL); HRESULT hr; // 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 = OnProperties(param); } else { INTERNAL* pInternal = ExtractInternalFormat(lpDataObject); if (pInternal == NULL) { return S_OK; } MMC_COOKIE cookie = pInternal->m_cookie; ::GlobalFree(reinterpret_cast(pInternal)); switch(event) { case MMCN_PASTE: AfxMessageBox(_T("CSnapin::MMCN_PASTE")); break; case MMCN_DELETE: AfxMessageBox(_T("CD::MMCN_DELETE")); //hr = OnDelete(cookie); break; case MMCN_REMOVE_CHILDREN: hr = OnRemoveChildren(arg); break; case MMCN_RENAME: hr = OnRename(cookie, arg, param); break; case MMCN_EXPAND: hr = OnExpand(lpDataObject, arg, param); break; default: break; } } return hr; } STDMETHODIMP CComponentDataImpl::Destroy() { DBX_PRINT(_T(" ---------- CComponentDataImpl::Destroy<0x08x>\n"), this); ASSERT(m_bInitializedCD); m_bDestroyedCD = true; // Delete enumerated scope items DeleteList(); SAFE_RELEASE(m_pScope); SAFE_RELEASE(m_pConsole); return S_OK; } STDMETHODIMP CComponentDataImpl::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject) { #ifdef _DEBUG if (cookie == 0) { ASSERT(type != CCT_RESULT); } else { ASSERT(type == CCT_SCOPE); DWORD dwItemType = GetItemType(cookie); ASSERT(dwItemType == SCOPE_ITEM); } #endif return _QueryDataObject(cookie, type, this, ppDataObject); } /////////////////////////////////////////////////////////////////////////////// //// IPersistStream interface members STDMETHODIMP CComponentDataImpl::GetClassID(CLSID *pClassID) { ASSERT(pClassID != NULL); // Copy the CLSID for this snapin *pClassID = CLSID_Snapin; return E_NOTIMPL; } STDMETHODIMP CComponentDataImpl::IsDirty() { // Always save / Always dirty. return ThisIsDirty() ? S_OK : S_FALSE; } STDMETHODIMP CComponentDataImpl::Load(IStream *pStm) { DBX_PRINT(_T(" ---------- CComponentDataImpl::Load<0x08x>\n"), this); ASSERT(pStm); ASSERT(m_bInitializedCD); // Read the string char psz[10]; ULONG nBytesRead; HRESULT hr = pStm->Read(psz, 10, &nBytesRead); // Verify that the read succeeded ASSERT(SUCCEEDED(hr) && nBytesRead == 10); // check to see if the string is the correct string ASSERT(strcmp("123456789", psz) == 0); ClearDirty(); return SUCCEEDED(hr) ? S_OK : E_FAIL; } STDMETHODIMP CComponentDataImpl::Save(IStream *pStm, BOOL fClearDirty) { DBX_PRINT(_T(" ---------- CComponentDataImpl::Save<0x08x>\n"), this); ASSERT(pStm); ASSERT(m_bInitializedCD); // Write the string ULONG nBytesWritten; HRESULT hr = pStm->Write("123456789", 10, &nBytesWritten); // Verify that the write operation succeeded ASSERT(SUCCEEDED(hr) && nBytesWritten == 10); if (FAILED(hr)) return STG_E_CANTSAVE; if (fClearDirty) ClearDirty(); return S_OK; } STDMETHODIMP CComponentDataImpl::GetSizeMax(ULARGE_INTEGER *pcbSize) { ASSERT(pcbSize); // Set the size of the string to be saved ULISet32(*pcbSize, 10); return S_OK; } /////////////////////////////////////////////////////////////////////////////// //// Notify handlers for IComponentData HRESULT CComponentDataImpl::OnDelete(MMC_COOKIE cookie) { return S_OK; } HRESULT CComponentDataImpl::OnRemoveChildren(LPARAM arg) { return S_OK; } HRESULT CComponentDataImpl::OnRename(MMC_COOKIE cookie, LPARAM arg, LPARAM param) { if (arg == 0) return S_OK; LPOLESTR pszNewName = reinterpret_cast(param); if (pszNewName == NULL) return E_INVALIDARG; CFolder* pFolder = reinterpret_cast(cookie); ASSERT(pFolder != NULL); if (pFolder == NULL) return E_INVALIDARG; pFolder->SetName(pszNewName); return S_OK; } HRESULT CComponentDataImpl::OnExpand(LPDATAOBJECT lpDataObject, LPARAM arg, LPARAM param) { if (arg == TRUE) { // Did Initialize get called? ASSERT(m_pScope != NULL); EnumerateScopePane(lpDataObject, param); } return S_OK; } HRESULT CComponentDataImpl::OnSelect(MMC_COOKIE cookie, LPARAM arg, LPARAM param) { return E_UNEXPECTED; } HRESULT CComponentDataImpl::OnProperties(LPARAM param) { if (param == NULL) { return S_OK; } ASSERT(param != NULL); CFolder* pFolder = new CFolder(); // Create a new folder object pFolder->Create( reinterpret_cast(param), 0, 0, STATIC, FALSE); // The static folder in the last item in the list POSITION pos = m_scopeItemList.GetTailPosition(); if (pos == 0) { // CreateFolderList(); pos = m_scopeItemList.GetTailPosition(); } ASSERT(pos); // Add it to the internal list if (pos) { CFolder* pItem = m_scopeItemList.GetAt(pos); m_scopeItemList.InsertBefore(pos, pFolder); pFolder->m_pScopeItem->relativeID = pItem->m_pScopeItem->relativeID; // Set the folder as the cookie pFolder->m_pScopeItem->mask |= SDI_PARAM; pFolder->m_pScopeItem->lParam = reinterpret_cast(pFolder); pFolder->SetCookie(reinterpret_cast(pFolder)); m_pScope->InsertItem(pFolder->m_pScopeItem); } ::GlobalFree(reinterpret_cast(param)); return S_OK; } void CComponentDataImpl::CreateFolderList(LPDATAOBJECT lpDataObject) { CFolder* pFolder; ASSERT(lpDataObject != NULL); wchar_t* pWkStation = ExtractWorkstation(lpDataObject); ASSERT(pWkStation != NULL); CLSID* pCoClassID = ExtractClassID(lpDataObject); ASSERT(pCoClassID != NULL); // Determine which folder set to use based on context information FOLDER_DATA* pFolderSet = FolderData; BOOL bExtend = FALSE; if (!IsEqualCLSID(*pCoClassID, GetCoClassID())) { pFolderSet = ExtFolderData; bExtend = TRUE; // TRACE(_T("Using Extension Data\n")); } ASSERT(m_scopeItemList.GetCount() == 0); wchar_t buf[100]; for (int i=0; i < NUM_FOLDERS; i++) { pFolder = new CFolder(); buf[0] = NULL; USES_CONVERSION; wcscpy(buf, pFolderSet[i].szName); // Add context info to the folder name if (bExtend) wcscat(buf, pWkStation); int nImage = 0; switch(pFolderSet[i].type) { case USER: case EXT_USER: nImage = USER_IMAGE; break; case COMPANY: case EXT_COMPANY: nImage = COMPANY_IMAGE; break; case VIRTUAL: nImage = VIRTUAL_IMAGE; break; } // Create the folder objects with static data pFolder->Create(buf, nImage/*FOLDER_IMAGE_IDX*/, OPEN_FOLDER_IMAGE_IDX, pFolderSet[i].type, FALSE); m_scopeItemList.AddTail(pFolder); } // mark cookie for last item pFolder->SetCookie(NULL); // Free memory from data object extraction ::GlobalFree(reinterpret_cast(pWkStation)); ::GlobalFree(reinterpret_cast(pCoClassID)); } void CComponentDataImpl::EnumerateScopePane(LPDATAOBJECT lpDataObject, HSCOPEITEM pParent) { int i; ASSERT(m_pScope != NULL); // make sure we QI'ed for the interface ASSERT(lpDataObject != NULL); INTERNAL* pInternal = ExtractInternalFormat(lpDataObject); if (pInternal == NULL) return ; MMC_COOKIE cookie = pInternal->m_cookie; #ifndef RECURSIVE_NODE_EXPANSION // Only the static node has enumerated children if (cookie != NULL) return ; #endif ::GlobalFree(reinterpret_cast(pInternal)); // Initialize folder list if empty if (m_scopeItemList.GetCount() == 0) CreateFolderList(lpDataObject); // Enumerate the scope pane // return the folder object that represents the cookie // Note - for large list, use dictionary CFolder* pStatic = FindObject(cookie); #ifndef RECURSIVE_NODE_EXPANSION ASSERT(!pStatic->IsEnumerated()); // Note - Each cookie in the scope pane represents a folder. // A released product may have more then one level of children. // This sample assumes the parent node is one level deep. #endif ASSERT(pParent != NULL); // Cache the HSCOPEITEM of the static root. if (cookie == NULL) m_pStaticRoot = pParent; POSITION pos = m_scopeItemList.GetHeadPosition(); CFolder* pFolder; for (i=0; (i < (NUM_FOLDERS - 1)) && (pos != NULL); i++) { pFolder = m_scopeItemList.GetNext(pos); ASSERT(pFolder); // Set the parent pFolder->m_pScopeItem->relativeID = pParent; // Set the folder as the cookie pFolder->m_pScopeItem->mask |= SDI_PARAM; pFolder->m_pScopeItem->lParam = reinterpret_cast(pFolder); pFolder->SetCookie(reinterpret_cast(pFolder)); m_pScope->InsertItem(pFolder->m_pScopeItem); // Note - On return, the ID member of 'm_pScopeItem' // contains the handle to the newly inserted item! ASSERT(pFolder->m_pScopeItem->ID != NULL); } // Last folder added is the static folder pStatic->Set(TRUE); // folder has been enumerated pStatic->m_pScopeItem->relativeID = pParent; } void CComponentDataImpl::DeleteAndReinsertAll() { ASSERT(m_pScope != NULL); // make sure we QI'ed for the interface ASSERT (m_scopeItemList.GetCount() > 0); //m_pStaticRoot HRESULT hr = m_pScope->DeleteItem(m_pStaticRoot, FALSE); ASSERT(SUCCEEDED(hr)); POSITION pos = m_scopeItemList.GetHeadPosition(); CFolder* pFolder; for (UINT i=0; (i < (NUM_FOLDERS - 1)) && (pos != NULL); i++) { pFolder = m_scopeItemList.GetNext(pos); ASSERT(pFolder); // clear old ID pFolder->m_pScopeItem->ID = NULL; // Set the parent pFolder->m_pScopeItem->relativeID = m_pStaticRoot; // Set the folder as the cookie pFolder->m_pScopeItem->mask |= SDI_PARAM; pFolder->m_pScopeItem->lParam = reinterpret_cast(pFolder); pFolder->SetCookie(reinterpret_cast(pFolder)); m_pScope->InsertItem(pFolder->m_pScopeItem); // Note - On return, the ID member of 'm_pScopeItem' // contains the handle to the newly inserted item! ASSERT(pFolder->m_pScopeItem->ID != NULL); } } void CComponentDataImpl::DeleteList() { POSITION pos = m_scopeItemList.GetHeadPosition(); while (pos) delete m_scopeItemList.GetNext(pos); } CFolder* CComponentDataImpl::FindObject(MMC_COOKIE cookie) { POSITION pos = m_scopeItemList.GetHeadPosition(); CFolder* pFolder = NULL; while(pos) { pFolder = m_scopeItemList.GetNext(pos); if (*pFolder == cookie) return pFolder; } return NULL; } STDMETHODIMP CComponentDataImpl::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem) { ASSERT(pScopeDataItem != NULL); if (pScopeDataItem == NULL) return E_POINTER; CFolder* pFolder = reinterpret_cast(pScopeDataItem->lParam); ASSERT(pScopeDataItem->mask & SDI_STR); pScopeDataItem->displayname = pFolder ? pFolder->m_pszName : L"Snapin Data"; //ASSERT(pScopeDataItem->displayname != NULL); return S_OK; } STDMETHODIMP CComponentDataImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { if (lpDataObjectA == NULL || lpDataObjectB == NULL) return E_POINTER; // Make sure both data object are mine INTERNAL* pA; INTERNAL* pB; HRESULT hr = S_FALSE; pA = ExtractInternalFormat(lpDataObjectA); pB = ExtractInternalFormat(lpDataObjectA); if (pA != NULL && pB != NULL) hr = (*pA == *pB) ? S_OK : S_FALSE; ::GlobalFree(reinterpret_cast(pA)); ::GlobalFree(reinterpret_cast(pB)); return hr; } ///////////////////////////////////////////////////////////////////////////// // IExtendPropertySheet2 Implementation HRESULT CComponentDataImpl::DoInsertWizard(LPPROPERTYSHEETCALLBACK lpProvider) { CStartUpWizard* pWizard = new CStartUpWizard; CStartupWizard1* pWizard1 = new CStartupWizard1; MMCPropPageCallback(&pWizard->m_psp97); MMCPropPageCallback(&pWizard1->m_psp97); HPROPSHEETPAGE hPage = CreatePropertySheetPage(&pWizard->m_psp97); if (hPage == NULL) return E_UNEXPECTED; lpProvider->AddPage(hPage); hPage = CreatePropertySheetPage(&pWizard1->m_psp97); if (hPage == NULL) return E_UNEXPECTED; lpProvider->AddPage(hPage); return S_OK; } STDMETHODIMP CComponentDataImpl::GetWatermarks( LPDATAOBJECT lpIDataObject, HBITMAP* lphWatermark, HBITMAP* lphHeader, HPALETTE* lphPalette, BOOL* pbStretch) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); *lphHeader = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BANNER)); *lphWatermark = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_WATERMARK)); *pbStretch = TRUE; // force the watermark bitmap to stretch return S_OK; } STDMETHODIMP CComponentDataImpl::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider, LONG_PTR handle, LPDATAOBJECT lpIDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Look at the data object and determine if this an extension or a primary ASSERT(lpIDataObject != NULL); // Look at the data object and see if the snap-in manager is asking for pages INTERNAL* pInternal= ExtractInternalFormat(lpIDataObject); if (pInternal != NULL) { DATA_OBJECT_TYPES type = pInternal->m_type; FREE_DATA(pInternal); if (type == CCT_SNAPIN_MANAGER) { HRESULT hr = DoInsertWizard(lpProvider); return hr; } } CLSID* pCoClassID = ExtractClassID(lpIDataObject); if(pCoClassID == NULL) { ASSERT(FALSE); return E_UNEXPECTED; } CPropertyPage* pBasePage; // Determine which // Note: Should check the node type, but the sample only has 1 if (IsEqualCLSID(*pCoClassID, GetCoClassID())) { // Create the primary property page CGeneralPage* pPage = new CGeneralPage(); pPage->m_hConsoleHandle = handle; pBasePage = pPage; } else { // Create the extension property page CExtensionPage* pPage = new CExtensionPage(); pBasePage = pPage; wchar_t* pWkStation = ExtractWorkstation(lpIDataObject); if (pWkStation == NULL) { ASSERT(FALSE); return E_FAIL; } // Save the workstation name pPage->m_szText = pWkStation; FREE_DATA(pWkStation); } FREE_DATA(pCoClassID); // Object gets deleted when the page is destroyed ASSERT(lpProvider != NULL); HRESULT hr = MMCPropPageCallback(&pBasePage->m_psp); if (SUCCEEDED(hr)) { HPROPSHEETPAGE hPage = CreatePropertySheetPage(&pBasePage->m_psp); if (hPage == NULL) return E_UNEXPECTED; lpProvider->AddPage(hPage); } return hr; } STDMETHODIMP CComponentDataImpl::QueryPagesFor(LPDATAOBJECT lpDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); // Get the node type and see if it's one of mine // if (nodetype == one of mine) // do this // else // see which node type it is and answer the question return S_OK; } BOOL CComponentDataImpl::IsScopePaneNode(LPDATAOBJECT lpDataObject) { BOOL bResult = FALSE; INTERNAL* pInternal = ExtractInternalFormat(lpDataObject); if (pInternal->m_cookie == NULL && (pInternal->m_type == CCT_SCOPE || pInternal->m_type == CCT_RESULT)) bResult = TRUE; FREE_DATA(pInternal); return bResult; } /////////////////////////////////////////////////////////////////////////////// // IExtendContextMenu implementation // STDMETHODIMP CComponentDataImpl::AddMenuItems(LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK pContextMenuCallback, long *pInsertionAllowed) { HRESULT hr = S_OK; // Note - snap-ins need to look at the data object and determine // in what context, menu items need to be added. They must also // observe the insertion allowed flags to see what items can be // added. if (IsMMCMultiSelectDataObject(pDataObject) == TRUE) return S_FALSE; INTERNAL* pInternal = ExtractInternalFormat(pDataObject); BOOL bCmd1IsDefault = (pInternal->m_type == CCT_RESULT); if (bCmd1IsDefault) menuItems[0].fSpecialFlags = CCM_SPECIAL_DEFAULT_ITEM; else menuItems[0].fSpecialFlags = 0; // Loop through and add each of the menu items if (*pInsertionAllowed & CCM_INSERTIONALLOWED_TOP) { for (LPCONTEXTMENUITEM m = menuItems; m->strName; m++) { hr = pContextMenuCallback->AddItem(m); if (FAILED(hr)) break; } } // Loop through and add each of the view items if (*pInsertionAllowed & CCM_INSERTIONALLOWED_VIEW) { for (LPCONTEXTMENUITEM m = viewItems; m->strName; m++) { hr = pContextMenuCallback->AddItem(m); if (FAILED(hr)) break; } } return hr; } STDMETHODIMP CComponentDataImpl::Command(long nCommandID, LPDATAOBJECT pDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); #ifdef DOBJ_NOCONSOLE if (pDataObject == DOBJ_NOCONSOLE) { TCHAR szMsg[256]; wsprintf (szMsg, _T("CComponentDataImpl::Command invoked from outside the context of MMC (nCommandID = %d)."), nCommandID); AfxMessageBox (szMsg); return (S_OK); } #endif // DOBJ_NOCONSOLE // Note - snap-ins need to look at the data object and determine // in what context the command is being called. // Handle each of the commands. switch (nCommandID) { case IDM_COMMAND1: { ASSERT(m_pConsole); m_pConsole->MessageBox(L"Snapin Menu Comand Selected", menuItems[nCommandID].strName, MB_OK, NULL); if (1) { IConsole2* pc2 = NULL; m_pConsole->QueryInterface(IID_IConsole2, (void**)&pc2); ASSERT(pc2 != NULL); pc2->IsTaskpadViewPreferred(); pc2->Release(); break; } INTERNAL* pi = ExtractInternalFormat(pDataObject); ASSERT(pi); ASSERT(pi->m_type != CCT_RESULT); CFolder* pFolder = reinterpret_cast(pi->m_cookie); if (pFolder) { m_pConsole->SelectScopeItem(pFolder->m_pScopeItem->ID); } else { SCOPEDATAITEM si; ZeroMemory(&si, sizeof(si)); si.ID = m_pStaticRoot; si.mask = SDI_STR; si.displayname = MMC_TEXTCALLBACK; // _T("Sample snapin's static folder"); m_pScope->SetItem(&si); } break; } case IDM_COMMAND2: ASSERT(m_pConsole); m_pConsole->MessageBox(L"Snapin Menu Comand Selected", menuItems[nCommandID].strName, MB_OK, NULL); break; default: ASSERT(FALSE); // Unknown command! break; } return S_OK; } /////////////////////////////////////////////////////////////////////////////// // IExtendControlbar implementation // STDMETHODIMP CSnapin::SetControlbar(LPCONTROLBAR pControlbar) { // TRACE(_T("CSnapin::SetControlbar(%ld)\n"),pControlbar); // Please don't delete this. Required to make sure we pick up the bitmap AFX_MANAGE_STATE(AfxGetStaticModuleState()); if (pControlbar != NULL) { // Hold on to the controlbar interface. if (m_pControlbar) { m_pControlbar->Release(); } m_pControlbar = pControlbar; m_pControlbar->AddRef(); HRESULT hr=S_FALSE; if (!m_pMenuButton1) { hr = m_pControlbar->Create(MENUBUTTON, this, reinterpret_cast(&m_pMenuButton1)); ASSERT(SUCCEEDED(hr)); } if (m_pMenuButton1) { // Unlike toolbar buttons, menu buttons need to be added every time. hr = m_pMenuButton1->AddButton(FOLDEREX_MENU, L"FolderEx", L"Extended Folder Menu"); ASSERT(SUCCEEDED(hr)); hr = m_pMenuButton1->AddButton(FILEEX_MENU, L"FileEx", L"Extended File Menu"); ASSERT(SUCCEEDED(hr)); } // Create the Toolbar 1 if (!m_pToolbar1) { hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast(&m_pToolbar1)); ASSERT(SUCCEEDED(hr)); // Add the bitmap m_pbmpToolbar1 = new ::CBitmap; m_pbmpToolbar1->LoadBitmap(IDB_TOOLBAR1); hr = m_pToolbar1->AddBitmap(11, *m_pbmpToolbar1, 16, 16, RGB(255, 0, 255)); ASSERT(SUCCEEDED(hr)); // Add the buttons to the toolbar hr = m_pToolbar1->AddButtons(ARRAYLEN(SnapinButtons), SnapinButtons); ASSERT(SUCCEEDED(hr)); } // TOOLBAR 2 // Create the Toolbar 2 if (!m_pToolbar2) { hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast(&m_pToolbar2)); ASSERT(SUCCEEDED(hr)); // Add the bitmap m_pbmpToolbar2 = new ::CBitmap; m_pbmpToolbar2->LoadBitmap(IDB_TOOLBAR2); hr = m_pToolbar2->AddBitmap(36, *m_pbmpToolbar2, 16, 16, RGB(192,192,192)); ASSERT(SUCCEEDED(hr)); // Add the buttons to the toolbar hr = m_pToolbar2->AddButtons(ARRAYLEN(SnapinButtons2), SnapinButtons2); ASSERT(SUCCEEDED(hr)); } } else { SAFE_RELEASE(m_pControlbar); } return S_OK; } void CSnapin::OnButtonClick(LPDATAOBJECT pdtobj, LONG_PTR idBtn) { TCHAR name[128]; GetItemName(pdtobj, name); TCHAR buf[200]; wsprintf(buf, _T("Toolbar button<%d> was clicked. \nThe currently selected result item is <%s>"), idBtn, name); ::MessageBox(NULL, buf, _T("TRACE"), MB_OK); } STDMETHODIMP CSnapin::ControlbarNotify(MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param) { HRESULT hr=S_FALSE; AFX_MANAGE_STATE(AfxGetStaticModuleState()); switch (event) { case MMCN_BTN_CLICK: //TCHAR szMessage[MAX_PATH]; //wsprintf(szMessage, _T("CommandID %ld"),param); //AfxMessageBox(szMessage); OnButtonClick(reinterpret_cast(arg), param); break; case MMCN_DESELECT_ALL: case MMCN_SELECT: HandleExtToolbars((event == MMCN_DESELECT_ALL), arg, param); break; case MMCN_MENU_BTNCLICK: HandleExtMenus(arg, param); break; default: break; } return S_OK; } // This compares two data objects to see if they are the same object. // return // S_OK if equal otherwise S_FALSE // // Note: check to make sure both objects belong to the snap-in. // STDMETHODIMP CSnapin::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB) { return S_FALSE; } // This compare is used to sort the item's in the listview // // Parameters: // // lUserParam - user param passed in when IResultData::Sort() was called // cookieA - first item to compare // cookieB - second item to compare // pnResult [in, out]- contains the col on entry, // -1, 0, 1 based on comparison for return value. // // Note: Assum sort is ascending when comparing. STDMETHODIMP CSnapin::Compare(LPARAM lUserParam, MMC_COOKIE cookieA, MMC_COOKIE cookieB, int* pnResult) { if (pnResult == NULL) { ASSERT(FALSE); return E_POINTER; } // check col range int nCol = *pnResult; ASSERT(nCol >=0 && nCol< 3); *pnResult = 0; USES_CONVERSION; LPTSTR szStringA; LPTSTR szStringB; RESULT_DATA* pDataA = reinterpret_cast(cookieA); RESULT_DATA* pDataB = reinterpret_cast(cookieB); ASSERT(pDataA != NULL && pDataB != NULL); if (nCol == 0) { szStringA = OLE2T(pDataA->szName); szStringB = OLE2T(pDataB->szName); } else if(nCol == 1) { szStringA = OLE2T(pDataA->szSize); szStringB = OLE2T(pDataB->szSize); } else { szStringA = OLE2T(pDataA->szType); szStringB = OLE2T(pDataB->szType) ; } ASSERT(szStringA != NULL); ASSERT(szStringB != NULL); *pnResult = _tcscmp(szStringA, szStringB); return S_OK; } /////////////////////////////////////////////////////////////////////////////// // IResultOwnerData implementation // STDMETHODIMP CSnapin::FindItem (LPRESULTFINDINFO pFindInfo, int* pnFoundIndex) { // find next item that matches the string (exact or partial) // if matched found, set FoundIndex and return S_OK // For the sample all items are named by their index number // so we don't do a real string search. Also, to simplify the code // the routine assumes a partial match search with wrap, which is what // keyboard navigation calls use. ASSERT((pFindInfo->dwOptions & (RFI_PARTIAL | RFI_WRAP)) == (RFI_PARTIAL | RFI_WRAP)); USES_CONVERSION; TCHAR* lpszFind = OLE2T(pFindInfo->psz); // TRACE(_T("CSnapin::FindItem(\"%s\")"), lpszFind); // convert search string to number int nMatchVal = 0; TCHAR* pch = lpszFind; while (*pch >= _T('0') && *pch <= _T('9') && nMatchVal < NUM_VIRTUAL_ITEMS) nMatchVal = nMatchVal * 10 + (*pch++ - _T('0')); // if string has a non-decimal char or is too large, it won't match anything if (*pch != 0 || nMatchVal >= NUM_VIRTUAL_ITEMS) return S_FALSE; // if ascending sequence if (!(m_dwVirtualSortOptions & RSI_DESCENDING)) { int nStartVal = pFindInfo->nStart; // if match is less than start (but not zero), locate first value above start that matches // otherwise the match number itself it the answer if (nMatchVal < nStartVal && nMatchVal != 0) { // find scale factor to reach value >= start value int nScale = 1; while (nMatchVal * nScale < nStartVal) nScale *= 10; // check special case of start value beginning with the match digits int nTestVal = (nStartVal * 10 - nMatchVal * nScale) < nScale ? nStartVal : nMatchVal * nScale; // if not too big it's the match, else the match value is the match if (nTestVal < NUM_VIRTUAL_ITEMS) nMatchVal = nTestVal; } } else // descending sequence { // convert start index to start value int nStartVal = (NUM_VIRTUAL_ITEMS - 1) - pFindInfo->nStart; if (nMatchVal != 0) { // if match number > start, we will have to wrap to find a match // so use max index as our target int nTargetVal = (nMatchVal > nStartVal) ? NUM_VIRTUAL_ITEMS - 1 : nStartVal; // find scale factor that gets closest without going over target int nScale = 1; while (nMatchVal * nScale * 10 < nTargetVal) nScale *= 10; // check special case of target value beginning with the match digits nMatchVal = (nTargetVal - nMatchVal * nScale) < nScale ? nTargetVal : (nMatchVal + 1) * nScale - 1; } // convert match value back to an item index nMatchVal = (NUM_VIRTUAL_ITEMS - 1) - nMatchVal; } *pnFoundIndex = nMatchVal; return S_OK; } STDMETHODIMP CSnapin::CacheHint (int nStartIndex, int nEndIndex) { // If advantageous, use this hint to pre-fetch the result item info that // is about to be requested. // TRACE(_T("CSnapin::CacheHint(%d,%d)\n"), nStartIndex, nEndIndex); return S_OK; } STDMETHODIMP CSnapin::SortItems (int nColumn, DWORD dwSortOptions, LPARAM lUserParam) { // sort request for user owned result items // if item order changed return S_OK, else S_FALSE // Sample only sorts on the first column (item name) if ((nColumn == 0) && (m_dwVirtualSortOptions != dwSortOptions)) { m_dwVirtualSortOptions = dwSortOptions; return S_OK; } return S_FALSE; } void CSnapin::HandleStandardVerbs(bool bDeselectAll, LPARAM arg, LPDATAOBJECT lpDataObject) { WORD bScope = LOWORD(arg); WORD bSelect = HIWORD(arg); #if 0 // trace { TCHAR buf[250]; static UINT s_count1 = 0; wsprintf(buf, _T("<%4d> %s - %s\n"), ++s_count1, bScope ? _T("Scope") : _T("Result"), bSelect ? _T("selected") : _T("de-selected")); OutputDebugString(buf); } #endif if (!bScope) { if (m_CustomViewID == VIEW_MICROSOFT_URL) { m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE); return; } else if (m_CustomViewID == VIEW_CALENDAR_OCX) { m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE); m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE); return; } } if (!bDeselectAll && lpDataObject == NULL) return; // 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. #if 0 TCHAR buf[40]; wsprintf(buf, _T(" %4d - CSnapin::OnSelect<%d, %d>\n"), ++n_count, bScope, bSelect); ODS(buf); #else DBX_PRINT(_T(" %4d - CSnapin::OnSelect<%d, %d>\n"), ++n_count, bScope, bSelect); #endif if (!bDeselectAll && IsMyMultiSelectDataObject(lpDataObject) == TRUE) { m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE); m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, ENABLED, TRUE); m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE); return; } INTERNAL* pInternal = lpDataObject ? ExtractInternalFormat(lpDataObject) : NULL; if (bSelect && (pInternal != NULL) && (pInternal->m_type == CCT_SCOPE)) { IConsole2* pConsole2; m_pConsole->QueryInterface (IID_IConsole2, (void**)&pConsole2); CFolder* pFolder = reinterpret_cast(pInternal->m_cookie); if (pFolder != NULL) { switch (pFolder->GetType()) { case USER: pConsole2->SetStatusText (L"User node selected||third pane"); break; case COMPANY: pConsole2->SetStatusText (L"Company node selected|%25|third pane"); break; case VIRTUAL: pConsole2->SetStatusText (L" Virtual node selected | %50 | third pane "); break; } } else pConsole2->SetStatusText (L"Static root node selected||third pane"); pConsole2->Release (); } if (bDeselectAll || !bSelect) { if (bScope) { m_pConsoleVerb->SetVerbState(MMC_VERB_OPEN, ENABLED, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, ENABLED, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, ENABLED, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, FALSE); } else { // Result pane background m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, ENABLED, TRUE); if (pInternal && pInternal->m_cookie == 0) { m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE); } m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE); } return; } if (m_pConsoleVerb && pInternal) { if (pInternal->m_type == CCT_SCOPE) { // Standard funcitonality support by scope items m_pConsoleVerb->SetVerbState(MMC_VERB_OPEN, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_OPEN, ENABLED, TRUE); m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE); // Enable properties for static node only. if (pInternal->m_cookie == 0) { m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE); //m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES); m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN); } else { m_pConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_PRINT, ENABLED, TRUE); m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN); } // Standard funcitonality NOT support by scope items m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, ENABLED, TRUE); m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE); m_pConsoleVerb->SetVerbState(MMC_VERB_CUT, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_CUT, ENABLED, FALSE); //m_pConsoleVerb->SetVerbState(MMC_VERB_CUT, ENABLED, TRUE); } else { // Standard funcitonality support by result items m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE); m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, FALSE); m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE); m_pConsoleVerb->SetDefaultVerb(MMC_VERB_NONE); // Standard funcitonality NOT support by result items } m_pConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, TRUE); // Standard funcitonality NOT support by all items //m_pConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE); //m_pConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE); } } void EnableToolbar(LPTOOLBAR pToolbar, MMCBUTTON rgSnapinButtons[], int nRgSize, BOOL bEnable) { for (int i=0; i < nRgSize; ++i) { if (rgSnapinButtons[i].idCommand != 0) pToolbar->SetButtonState(rgSnapinButtons[i].idCommand, ENABLED, bEnable); } } void EnableMenuBtns(LPMENUBUTTON pMenuBtn, MMCBUTTON rgSnapinButtons[], int nRgSize, BOOL bEnable) { for (int i=0; i < nRgSize; ++i) { if (rgSnapinButtons[i].idCommand != 0) pMenuBtn->SetButtonState(rgSnapinButtons[i].idCommand, ENABLED, bEnable); } } void CSnapin::HandleExtToolbars(bool bDeselectAll, LPARAM arg, LPARAM param) { INTERNAL* pInternal = NULL; HRESULT hr; BOOL bScope = (BOOL) LOWORD(arg); BOOL bSelect = (BOOL) HIWORD(arg); #if 0 #if 1 { if (param) { LPDATAOBJECT pDataObject = reinterpret_cast(param); pInternal = ExtractInternalFormat(pDataObject); } TCHAR buf[200]; wsprintf(buf, _T(" %4d - CExtendControlbar::OnSelect<%d, %d> = %d\n"), ++n_count, bScope, bSelect, pInternal ? pInternal->m_cookie : 0); ODS(buf); } #else DBX_PRINT(_T(" %4d - CExtendControlbar::OnSelect<%d, %d>\n"), ++n_count, bScope, bSelect); #endif #endif if (bDeselectAll || bSelect == FALSE) { ASSERT(m_pToolbar1); EnableToolbar(m_pToolbar1, SnapinButtons, ARRAYLEN(SnapinButtons), FALSE); ASSERT(m_pToolbar2); EnableToolbar(m_pToolbar2, SnapinButtons2, ARRAYLEN(SnapinButtons2), FALSE); ASSERT(m_pMenuButton1 != NULL); m_pMenuButton1->SetButtonState(FOLDEREX_MENU, ENABLED, FALSE); m_pMenuButton1->SetButtonState(FILEEX_MENU, ENABLED, FALSE); return; } ASSERT(bSelect == TRUE); bool bFileExBtn = false; if (bScope == TRUE) { LPDATAOBJECT pDataObject = reinterpret_cast(param); pInternal = ExtractInternalFormat(pDataObject); if (pInternal == NULL) return; CFolder* pFolder = reinterpret_cast(pInternal->m_cookie); if (pInternal->m_cookie == 0) { if (IsPrimaryImpl() == TRUE) { // Attach the toolbars to the window hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1); ASSERT(SUCCEEDED(hr)); hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2); ASSERT(SUCCEEDED(hr)); } } else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == COMPANY) || (IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_COMPANY)) { // Detach the toolbar2 from the window hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2); ASSERT(SUCCEEDED(hr)); // Attach the toolbar1 to the window hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1); ASSERT(SUCCEEDED(hr)); } else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == USER) || (IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_USER)) { // Detach the toolbar1 from the window hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1); ASSERT(SUCCEEDED(hr)); // Attach the toolbar2 to the window hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2); ASSERT(SUCCEEDED(hr)); } else { // Detach the toolbars from the window hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1); ASSERT(SUCCEEDED(hr)); hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2); ASSERT(SUCCEEDED(hr)); } FREE_DATA(pInternal); EnableToolbar(m_pToolbar1, SnapinButtons, ARRAYLEN(SnapinButtons), FALSE); EnableToolbar(m_pToolbar2, SnapinButtons2, ARRAYLEN(SnapinButtons2), FALSE); } else // result item selected. { LPDATAOBJECT pDataObject = reinterpret_cast(param); if (pDataObject != NULL) pInternal = ExtractInternalFormat(pDataObject); if (pInternal == NULL) return; if (pInternal->m_type == CCT_RESULT) { bFileExBtn = true; ASSERT(m_pToolbar1); EnableToolbar(m_pToolbar1, SnapinButtons, ARRAYLEN(SnapinButtons), TRUE); m_pToolbar1->SetButtonState(1, ENABLED, FALSE); m_pToolbar1->SetButtonState(2, CHECKED, TRUE); m_pToolbar1->SetButtonState(3, HIDDEN, TRUE); m_pToolbar1->SetButtonState(4, INDETERMINATE, TRUE); m_pToolbar1->SetButtonState(5, BUTTONPRESSED, TRUE); // Above is the correct way ASSERT(m_pToolbar2); m_pToolbar2->SetButtonState(20, CHECKED, TRUE); m_pToolbar2->SetButtonState(30, HIDDEN, TRUE); m_pToolbar2->SetButtonState(40, INDETERMINATE, TRUE); m_pToolbar2->SetButtonState(50, BUTTONPRESSED, TRUE); EnableToolbar(m_pToolbar2, SnapinButtons2, ARRAYLEN(SnapinButtons2), TRUE); } else // sub folder slected { CFolder* pFolder = reinterpret_cast(pInternal->m_cookie); ASSERT(m_pControlbar); if (pInternal->m_cookie == 0) { if (IsPrimaryImpl() == TRUE) { // Attach the toolbars to the window hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1); ASSERT(SUCCEEDED(hr)); hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2); ASSERT(SUCCEEDED(hr)); } } else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == COMPANY) || (IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_COMPANY)) { // Detach the toolbar2 from the window hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2); ASSERT(SUCCEEDED(hr)); // Attach the toolbar1 to the window hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1); ASSERT(SUCCEEDED(hr)); } else if ((IsPrimaryImpl() == TRUE && pFolder->GetType() == USER) || (IsPrimaryImpl() == FALSE && pFolder->GetType() == EXT_USER)) { // Detach the toolbar1 from the window hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1); ASSERT(SUCCEEDED(hr)); // Attach the toolbar2 to the window hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2); ASSERT(SUCCEEDED(hr)); } else { // Detach the toolbars from the window hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar1); ASSERT(SUCCEEDED(hr)); hr = m_pControlbar->Detach((LPUNKNOWN)m_pToolbar2); ASSERT(SUCCEEDED(hr)); } ASSERT(m_pToolbar1); EnableToolbar(m_pToolbar1, SnapinButtons, ARRAYLEN(SnapinButtons), TRUE); m_pToolbar1->SetButtonState(1, ENABLED, FALSE); m_pToolbar1->SetButtonState(2, CHECKED, TRUE); m_pToolbar1->SetButtonState(3, ENABLED, TRUE); m_pToolbar1->SetButtonState(4, INDETERMINATE, TRUE); m_pToolbar1->SetButtonState(5, BUTTONPRESSED, TRUE); ASSERT(m_pToolbar2); EnableToolbar(m_pToolbar2, SnapinButtons2, ARRAYLEN(SnapinButtons2), TRUE); // Above is the correct way m_pToolbar2->SetButtonState(20, CHECKED, FALSE); m_pToolbar2->SetButtonState(30, ENABLED, TRUE); m_pToolbar2->SetButtonState(40, INDETERMINATE, FALSE); m_pToolbar2->SetButtonState(50, BUTTONPRESSED, TRUE); } } if (m_pMenuButton1) { // Always make sure the menuButton is attached m_pControlbar->Attach(MENUBUTTON, m_pMenuButton1); if (bFileExBtn) { m_pMenuButton1->SetButtonState(FILEEX_MENU, HIDDEN, FALSE); m_pMenuButton1->SetButtonState(FOLDEREX_MENU, HIDDEN, TRUE); m_pMenuButton1->SetButtonState(FILEEX_MENU, ENABLED, TRUE); } else { m_pMenuButton1->SetButtonState(FOLDEREX_MENU, HIDDEN, FALSE); m_pMenuButton1->SetButtonState(FILEEX_MENU, HIDDEN, TRUE); m_pMenuButton1->SetButtonState(FOLDEREX_MENU, ENABLED, TRUE); } } } void CSnapin::HandleExtMenus(LPARAM arg, LPARAM param) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); LPDATAOBJECT* ppDataObject = reinterpret_cast(arg); LPMENUBUTTONDATA pMenuData = reinterpret_cast(param); if (ppDataObject == NULL || pMenuData == NULL) { ASSERT(FALSE); return; } ::CMenu menu; ::CMenu* pMenu = NULL; switch (pMenuData->idCommand) { case FOLDEREX_MENU: menu.LoadMenu(FOLDEREX_MENU); pMenu = menu.GetSubMenu(0); break; case FILEEX_MENU: menu.LoadMenu(FILEEX_MENU); pMenu = menu.GetSubMenu(0); break; default: ASSERT(FALSE); } if (pMenu == NULL) return; pMenu->TrackPopupMenu(TPM_RETURNCMD | TPM_NONOTIFY, pMenuData->x, pMenuData->y, AfxGetMainWnd()); } void CSnapin::GetItemName(LPDATAOBJECT pdtobj, LPTSTR pszName) { ASSERT(pszName != NULL); pszName[0] = 0; INTERNAL* pInternal = ExtractInternalFormat(pdtobj); ASSERT(pInternal != NULL); if (pInternal == NULL) return; OLECHAR *pszTemp; USES_CONVERSION; if (pInternal->m_type == CCT_RESULT) { RESULT_DATA* pData; // if virtual, derive result item from index // else cookie is the item pointer if (m_bVirtualView) pData = GetVirtualResultItem(pInternal->m_cookie); else pData = reinterpret_cast(pInternal->m_cookie); ASSERT(pData != NULL); pszTemp = pData->szName; } else { CFolder* pFolder = reinterpret_cast(pInternal->m_cookie); if (pFolder == 0) pszTemp = L"Static folder"; else pszTemp = pFolder->m_pszName; } lstrcpy(pszName, OLE2T(pszTemp)); } /* end of file */