|
|
// AddSnpIn.cpp : implementation file
//
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: AddSnpIn.cpp
//
// Contents: Add snapin manager
//
// History: 20-Sept-96 WayneSc Created
//--------------------------------------------------------------------------
#include "stdafx.h"
#include <stdio.h>
#include "winreg.h"
#include "macros.h"
#ifndef DECLSPEC_UUID
#if _MSC_VER >= 1100
#define DECLSPEC_UUID(x) __declspec(uuid(x))
#else
#define DECLSPEC_UUID(x)
#endif
#endif
#include "ndmgr.h"
#include "nodemgr.h"
#include "strings.h"
//using namespace AMC;
using namespace MMC_ATL;
#include "AddSnpIn.h"
#include "policy.h"
#include "msimodul.h"
#include "process.h"
#include "siprop.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
#define BITMAPS_COUNT 5
#define __PDC_UNAVAILABLE
#include "about.h"
// GUID for looking up snap-in components
const TCHAR* g_szMMCSnapInGuid = TEXT("{374F2F70-060F-11d2-B9A8-0060977B1D78}");
HRESULT AmcNodeWizard(MID_LIST NewNodeType, CMTNode* pNode, HWND hWnd); void EnableButton(HWND hwndDialog, int iCtrlID, BOOL bEnable);
/////////////////////////////////////////////////////////////////////////////
#ifdef DBG
CTraceTag tagAboutInfoThread (TEXT("Snapin Manager"), TEXT("CAboutInfo")); CTraceTag tagSnapinManager (TEXT("Snapin Manager"), TEXT("CSnapinManager")); CTraceTag tagSnapinManagerThread(TEXT("Snapin Manager"), TEXT("Snapin Manager Thread")); #endif //DBG
/////////////////////////////////////////////////////////////////////////////
//TEMP TEMP TEMP
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
#ifndef __PDC_UNAVAILABLE
typedef struct tag_teststr { TCHAR szCLSID[64]; } TESTSTR;
static TESTSTR s_teststr[] = { {_T("{12345601-EA27-11CF-ADCF-00AA00A80033}")}, {_T("{19876201-EA27-11CF-ADCF-00AA00A80033}")}, {_T("{1eeeeeee-d390-11cf-b607-00c04fd8d565}")}, };
#endif //__PDC_UNAVAILABLE
//############################################################################
//############################################################################
//
// Debug routines
//
//############################################################################
//############################################################################
#ifdef DBG
void CSnapinInfoCache::Dump(void) {
TRACE(_T("===========Dump of SnapinInfoCache ===============\n")); POSITION pos = GetStartPosition(); while(pos != NULL) { PSNAPININFO pSnapInfo; GUID clsid; TCHAR* pszAction;
GetNextAssoc(pos, clsid, pSnapInfo);
if (pSnapInfo->IsUsed() && (pSnapInfo->GetSnapIn() == NULL)) pszAction = _T("Add"); else if (!pSnapInfo->IsUsed() && (pSnapInfo->GetSnapIn() != NULL)) pszAction = _T("Remove"); else continue;
TRACE(_T("\n")); TRACE(_T("%s: %s\n"), pSnapInfo->GetSnapinName(), pszAction);
PEXTENSIONLINK pExt = pSnapInfo->GetExtensions(); while (pExt) { if (pExt->IsChanged()) { pszAction = pExt->GetState() ? _T("Add") : _T("Remove"); TRACE(_T(" %s: %s\n"), pExt->GetSnapinInfo()->GetSnapinName(),pszAction); } pExt = pExt->Next(); } } }
#endif // DBG
//############################################################################
//############################################################################
//
// Implementation of class CCheckList
//
//############################################################################
//############################################################################
LRESULT CCheckList::OnKeyDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { bHandled = FALSE; int iItem;
if ((int)wParam == VK_SPACE) { // Is the focused item selected ?
if ( (iItem = GetNextItem(-1, LVNI_FOCUSED|LVNI_SELECTED)) >= 0) { // if so, set all selected and enabled items to the opposite state
BOOL bNewState = !GetItemCheck(iItem);
iItem = -1; while( (iItem = GetNextItem(iItem, LVNI_SELECTED)) >= 0) { BOOL bEnable; GetItemCheck(iItem, &bEnable);
if (bEnable) SetItemCheck(iItem, bNewState); } } else { if ( (iItem = GetNextItem(-1, LVNI_FOCUSED)) >= 0) { BOOL bEnable; GetItemCheck(iItem, &bEnable);
if (bEnable) ToggleItemCheck(iItem);
SetItemState(iItem, LVIS_SELECTED, LVIS_SELECTED); } }
bHandled = TRUE; }
return 0; }
LRESULT CCheckList::OnLButtonDown( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { LV_HITTESTINFO info;
info.pt.x = LOWORD( lParam ); info.pt.y = HIWORD( lParam );
int iItem = HitTest( &info );
if( iItem >= 0 && (info.flags & LVHT_ONITEMSTATEICON)) { BOOL bEnable; GetItemCheck(iItem, &bEnable);
if (bEnable) ToggleItemCheck(iItem);
bHandled = TRUE; } else { bHandled = FALSE; }
return 0; }
LRESULT CCheckList::OnLButtonDblClk( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { LV_HITTESTINFO info;
info.pt.x = LOWORD( lParam ); info.pt.y = HIWORD( lParam );
int iItem = HitTest( &info ); if( iItem >= 0 ) { BOOL bEnable; GetItemCheck(iItem, &bEnable);
if (bEnable) ToggleItemCheck(iItem); }
return 0; }
//############################################################################
//############################################################################
//
// Implementation of class CAboutInfoThread
//
//############################################################################
//############################################################################
CAboutInfoThread::~CAboutInfoThread() { DEBUG_DECREMENT_INSTANCE_COUNTER(CAboutInfoThread);
Trace(tagAboutInfoThread, TEXT("CAboutInfoThread::~CAboutInfoThread"));
// Make sure the thread is dead before MMC quits
if (m_hThread != NULL) { PostThreadMessage(m_uThreadID, WM_QUIT, 0, 0);
MSG msg; while (TRUE) { // Wait either for the thread to be signaled or any input event.
DWORD dwStat = MsgWaitForMultipleObjects(1, &m_hThread, FALSE, INFINITE, QS_ALLINPUT);
if (WAIT_OBJECT_0 == dwStat) break; // The thread is signaled.
// There is one or more window message available.
// Dispatch them and wait.
if (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
CloseHandle(m_hThread); CloseHandle(m_hEvent); } }
//-----------------------------------------------------------------------------
// CAboutInfoThread::StartThread
//
// Start the thread
//-----------------------------------------------------------------------------
BOOL CAboutInfoThread::StartThread() { // If thread exists, just return
if (m_hThread != NULL) return TRUE;
BOOL bRet = FALSE; do // False loop
{ // Create start event
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (m_hEvent == NULL) break;
// Start the thread
m_hThread = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, this, 0, &m_uThreadID); if (m_hThread == NULL) break;
// Wait for start event
DWORD dwEvStat = WaitForSingleObject(m_hEvent, 10000); if (dwEvStat != WAIT_OBJECT_0) break;
bRet = TRUE; } while (0);
ASSERT(bRet);
// Clean up on failure
if (!bRet) { if (m_hEvent) { CloseHandle(m_hEvent); m_hEvent = NULL; }
if (m_hThread) { CloseHandle(m_hThread); m_hThread = NULL; } }
return bRet; }
BOOL CAboutInfoThread::PostRequest(CSnapinInfo* pSnapInfo, HWND hWndNotify) { // make sure thread is active
if (!StartThread()) return FALSE;
// Ref the info object to keep it alive until the thread releases it
pSnapInfo->AddRef();
BOOL bRet = PostThreadMessage(m_uThreadID, MSG_LOADABOUT_REQUEST, (WPARAM)pSnapInfo, LPARAM(hWndNotify));
// if failed to post, delete the ref
if (!bRet) pSnapInfo->Release();
return bRet; }
unsigned _stdcall CAboutInfoThread::ThreadProc(void* pVoid ) { // Do a PeekMessage to create the message queue
MSG msg; PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
// Then signal that thread is started
CAboutInfoThread* pThis = reinterpret_cast<CAboutInfoThread*>(pVoid); ASSERT(pThis->m_hEvent != NULL); SetEvent(pThis->m_hEvent);
CoInitialize(NULL);
// Mesage loop
while (TRUE) { long lStat = GetMessage(&msg, NULL, 0, 0);
// zero => WM_QUIT received, so exit thread function
if (lStat == 0) break;
if (lStat > 0) { // Only process thread message of the expected type
if (msg.hwnd == NULL && msg.message == MSG_LOADABOUT_REQUEST) { // Get SnapinInfo instance
PSNAPININFO pSnapinInfo = reinterpret_cast<PSNAPININFO>(msg.wParam); ASSERT(pSnapinInfo != NULL);
// Get the requested items
pSnapinInfo->LoadAboutInfo();
// Release our ref to the info
pSnapinInfo->Release();
// Send completion notification (if window still exists)
if (msg.lParam != NULL && IsWindow((HWND)msg.lParam)) PostMessage((HWND)msg.lParam, MSG_LOADABOUT_COMPLETE, (WPARAM)pSnapinInfo, (LPARAM)0); } else { DispatchMessage(&msg); } } } // WHILE (TRUE)
Trace(tagSnapinManagerThread, TEXT("Snapin manager thread about to exit"));
CoUninitialize();
return 0; }
//############################################################################
//############################################################################
//
// Implementation of class CSnapinInfo
//
//############################################################################
//############################################################################
//-----------------------------------------------------------------------------
// CSnapinInfo::~CSnapinInfo
//
// Destructor
//-----------------------------------------------------------------------------
CSnapinInfo::~CSnapinInfo() { DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapinInfo);
// Delete all the extension links
PEXTENSIONLINK pExt = m_pExtensions; PEXTENSIONLINK pNext;
while (pExt != NULL) { pNext = pExt->Next(); delete pExt; pExt = pNext; } }
//-----------------------------------------------------------------------------
// CSnapinInfo::InitFromMMCReg
//
// Initialize the snapin info from the supplied registry key. The caller is
// responsible for openning and closing the key.
//-----------------------------------------------------------------------------
BOOL CSnapinInfo::InitFromMMCReg(GUID& clsid, CRegKeyEx& regkey, BOOL bPermitted) { TCHAR szValue[MAX_PATH]; long lStat; DWORD dwCnt; DWORD dwType; LPOLESTR lpsz;
USES_CONVERSION;
// save class ID
m_clsid = clsid;
// Save permission
m_bPolicyPermission = bPermitted;
// Get name string
WTL::CString strName; SC sc = ScGetSnapinNameFromRegistry (regkey, strName); if (!sc.IsError()) { SetSnapinName(T2COLE(strName)); } else { // need to protect ourselves from the invalid snapin registration.
// see windows bug #401220 ( ntbugs9 5/23/2001 )
OLECHAR szCLSID[40]; int iRet = StringFromGUID2(GetCLSID(), szCLSID, countof(szCLSID)); if (iRet == 0) SetSnapinName( L"" ); else SetSnapinName( szCLSID ); }
// get "About" class ID
dwCnt = sizeof(szValue); lStat = RegQueryValueEx(regkey, g_szAbout, NULL, &dwType, (LPBYTE)szValue, &dwCnt); if (lStat == ERROR_SUCCESS && dwType == REG_SZ) { if (CLSIDFromString( T2OLE(szValue), &m_clsidAbout) == S_OK) { m_bAboutValid = TRUE; } else { ASSERT(FALSE); } }
MMC_ATL::CRegKey TestKey;
// Test for StandAlone key
m_bStandAlone = FALSE; lStat = TestKey.Open(regkey, g_szStandAlone, KEY_READ); if (lStat == ERROR_SUCCESS) { m_bStandAlone = TRUE; TestKey.Close(); }
// Test for NodeTypes key to see if extendable
m_bExtendable = FALSE; lStat = TestKey.Open(regkey, g_szNodeTypes, KEY_READ); if (lStat == ERROR_SUCCESS) { m_bExtendable = TRUE; TestKey.Close(); }
// Mark registered snap-ins as installed
m_bInstalled = TRUE;
return TRUE; }
//-----------------------------------------------------------------------------
// CSnapinInfo::InitFromComponentReg
//
// Initialize the snapin info from component registry information. This is done
// for snap-in that are not yet installed on the local machine.
//-----------------------------------------------------------------------------
BOOL CSnapinInfo::InitFromComponentReg(GUID& clsid, LPCTSTR pszName, BOOL bStandAlone, BOOL bPermitted) {
USES_CONVERSION;
// save class ID
m_clsid = clsid;
// Save permission
m_bPolicyPermission = bPermitted;
// Set name string
ASSERT(pszName != NULL); SetSnapinName(T2COLE(pszName));
// stand-alone or extension
m_bStandAlone = bStandAlone;
// With no information, must assume that it could be extendable
m_bExtendable = TRUE;
return TRUE; }
/*+-------------------------------------------------------------------------*
* * CSnapinInfo::ScInstall * * PURPOSE: Call the installer to install this snap-in. If the install works then * update the snap-in info from the MMC registry. * If loading an extension snap-in the clsid of extended snap-in must be * provided. * * PARAMETERS: * CLSID* pclsidPrimaryComp : * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CSnapinInfo::ScInstall(CLSID* pclsidPrimaryComp) { DECLARE_SC(sc, TEXT("CSnapinInfo::Install"));
USES_CONVERSION;
LPCTSTR pszPrimaryCLSID; OLECHAR szCLSIDPrimary[40];
if (pclsidPrimaryComp != NULL) { int iRet = StringFromGUID2(*pclsidPrimaryComp, szCLSIDPrimary, countof(szCLSIDPrimary)); if (iRet == 0) return(sc = E_UNEXPECTED);
pszPrimaryCLSID = OLE2T(szCLSIDPrimary); } else { pszPrimaryCLSID = g_szMMCSnapInGuid; }
OLECHAR szCLSID[40]; int iRet = StringFromGUID2(GetCLSID(), szCLSID, countof(szCLSID)); if (iRet == 0) return(sc = E_UNEXPECTED);
TCHAR szCompPath[MAX_PATH]; DWORD dwPathCnt = MAX_PATH;
// install the snapin on the machine
sc.FromWin32(MsiModule().ProvideQualifiedComponent(pszPrimaryCLSID, OLE2T(szCLSID), INSTALLMODE_DEFAULT, szCompPath, &dwPathCnt)); if (sc) return sc;
// the caller should call CSnapinManager::ScLoadSnapinInfo to update all the snapin info objects
return sc; }
//--------------------------------------------------------------------
// CSnapinInfo::AttachSnapIn
//
// Attach to the CSnapin associated with this info. If the snapin has
// active extensions, then add extension links for them. Recursively
// call AttachSnapIn for any extension snapins linked to.
//--------------------------------------------------------------------
void CSnapinInfo::AttachSnapIn(CSnapIn* pSnapIn, CSnapinInfoCache& InfoCache) { // If already attached, nothing to do
if (m_spSnapin != NULL) { ASSERT(m_spSnapin == pSnapIn); // Better be the same one!
return; }
// Save ref to snapin
m_spSnapin = pSnapIn;
// If not extendable, there's nothing more to do
if (!IsExtendable()) return;
// If required extensions not yet loaded, do it now
if (!pSnapIn->RequiredExtensionsLoaded() && IsPermittedByPolicy()) { // Create instance of snapin
IComponentDataPtr spICD; HRESULT hr = CreateSnapIn(m_clsid, &spICD, FALSE); ASSERT(SUCCEEDED(hr) && spICD != NULL);
if (SUCCEEDED(hr) && spICD != NULL) { // Load required extensions into snapin cache
LoadRequiredExtensions(pSnapIn, spICD); } }
// Copy state of Enable All flags
SetEnableAllExtensions(pSnapIn->AreAllExtensionsEnabled());
// Do for all snapin's extensions
CExtSI* pSnapInExt = pSnapIn->GetExtensionSnapIn(); while (pSnapInExt != NULL) { // Find snapin info entry for the extension snapin
PSNAPININFO pSnapInfo = InfoCache.FindEntry(pSnapInExt->GetSnapIn()->GetSnapInCLSID());
if (pSnapInfo != NULL) { // Create new link and add to list
PEXTENSIONLINK pNewExt = new CExtensionLink(pSnapInfo); pNewExt->SetNext(m_pExtensions); m_pExtensions = pNewExt;
// Initialize to ON
pNewExt->SetInitialState(CExtensionLink::EXTEN_ON); pNewExt->SetState(CExtensionLink::EXTEN_ON);
// Copy Required state
pNewExt->SetRequired(pSnapInExt->IsRequired());
// recursively connect the extension snapin info to its snapin
pSnapInfo->AttachSnapIn(pSnapInExt->GetSnapIn(), InfoCache); }
pSnapInExt = pSnapInExt->Next(); } }
//--------------------------------------------------------------------
// CSnapinInfo::LoadImages
//
// Get small bitmap images from the snapin and add them to the image list.
//--------------------------------------------------------------------
void CSnapinInfo::LoadImages( WTL::CImageList iml ) { DECLARE_SC(sc, TEXT("CSnapinInfo::LoadImages"));
// if already loaded, just return
if (m_iImage != -1) return;
// try to get images from the snap-in About object
// Get basic info from snapin
if (HasAbout() && !HasBasicInformation()) { GetBasicInformation(m_clsidAbout); }
ASSERT(iml != NULL);
// get the small bitmaps
HBITMAP hImage = NULL; HBITMAP hOpenImage = NULL; COLORREF cMask; GetSmallImages(&hImage, &hOpenImage, &cMask);
// Add to the image list
if (hImage != NULL) m_iImage = iml.Add(hImage, cMask);
/*
* if the snap-in didn't give us an open image, just use the "closed" image */ if (hOpenImage != NULL) m_iOpenImage = iml.Add(hOpenImage, cMask); else m_iOpenImage = m_iImage;
// if couldn't get from snap-in, try getting default icon from CLSID key
if (m_iImage == -1) do // dummy loop
{ USES_CONVERSION;
OLECHAR szCLSID[40]; int iRet = StringFromGUID2(GetCLSID(), szCLSID, countof(szCLSID)); if (iRet == 0) { (sc = E_UNEXPECTED).TraceAndClear(); break; }
CStr strKeyName(TEXT("CLSID\\")); strKeyName += W2T(szCLSID); strKeyName += TEXT("\\DefaultIcon");
CRegKeyEx regKey; sc = regKey.ScOpen (HKEY_CLASSES_ROOT, strKeyName, KEY_QUERY_VALUE); if (sc) { sc.Clear(); break; }
TCHAR szIconPath[MAX_PATH]; DWORD dwSize = sizeof(szIconPath); DWORD dwType;
sc = regKey.ScQueryValue (NULL, &dwType, szIconPath, &dwSize); if (sc) { sc.Clear(); break; }
if (dwType != REG_SZ) break;
// Icon path has the form <file path>,<icon index>
// if no index, use default of zero
int nIconIndex = 0;
TCHAR *pcComma = _tcsrchr(szIconPath, TEXT(',')); if (pcComma != NULL) { // terminate path name at ','
*(pcComma++) = TEXT('\0');
// Convert rest of string to an index value
if ((*pcComma != '-') && *pcComma < TEXT('0') || *pcComma > TEXT('9')) { ASSERT(FALSE); break; }
nIconIndex = _ttoi(pcComma); }
HICON hiconSmall;
UINT nIcons = ExtractIconEx(szIconPath, nIconIndex, NULL, &hiconSmall, 1); if (nIcons != 1 || hiconSmall == NULL) break;
// Add to image list (returns -1 on failure)
m_iImage = m_iOpenImage = iml.AddIcon(hiconSmall); ASSERT(m_iImage != -1);
DestroyIcon(hiconSmall);
} while (0); // Dummy loop
// Use default images on failure
if (m_iImage == -1) { WTL::CBitmap bmp; VERIFY (bmp.LoadBitmap (IDB_FOLDER_16)); m_iImage = iml.Add (bmp, RGB (255, 0, 255)); }
if (m_iOpenImage == -1) { WTL::CBitmap bmp; VERIFY (bmp.LoadBitmap (IDB_FOLDEROPEN_16)); m_iOpenImage = iml.Add (bmp, RGB (255, 0, 255)); } }
//--------------------------------------------------------------------
// CSnapinInfo::ShowAboutPages
//
// Show About property pages for this snapin
//--------------------------------------------------------------------
void CSnapinInfo::ShowAboutPages(HWND hWndParent) { // Load information if not already there
if (m_bAboutValid && !HasInformation()) { GetSnapinInformation(m_clsidAbout); }
// If it's there, show it
if (HasInformation()) { ShowAboutBox(); } }
//--------------------------------------------------------------------
// CSnapinInfo::AddUseRef
//
// Handle increment of use count. If count was zero, then set all
// READY extensions to the ON state. Note this can cascade as
// activated links cause other SnapinInfo ref counts to increment.
//--------------------------------------------------------------------
void CSnapinInfo::AddUseRef(void) { // If first reference, activate all READY extensions
if (m_nUseCnt++ == 0) { PEXTENSIONLINK pExt = GetExtensions(); while(pExt != NULL) { if (pExt->GetState() == CExtensionLink::EXTEN_READY) pExt->SetState(CExtensionLink::EXTEN_ON); pExt = pExt->Next(); } } }
//--------------------------------------------------------------------
// CSnapinInfo::DeleteUseRef
//
// Handle decrement of use count. If count reaches zero, then
// set all ON extensions to a READY state. Note this can cascade as
// deactivated links cause other SnapinInfo ref counts to drop.
//--------------------------------------------------------------------
void CSnapinInfo::DeleteUseRef(void) { ASSERT(m_nUseCnt > 0);
// If no more references, turn off all extensions
if (--m_nUseCnt == 0) { PEXTENSIONLINK pExt = GetExtensions(); while(pExt != NULL) { if (pExt->GetState() == CExtensionLink::EXTEN_ON) pExt->SetState(CExtensionLink::EXTEN_READY); pExt = pExt->Next(); } } }
//--------------------------------------------------------------------
// CSnapinInfo::GetAvailableExtensions
//
// Return list of available extensions for this snapin.
// On first call, create the list from the registry.
//--------------------------------------------------------------------
PEXTENSIONLINK CSnapinInfo::GetAvailableExtensions(CSnapinInfoCache* pInfoCache,CPolicy* pMMCPolicy) { DECLARE_SC(sc, TEXT("CSnapinInfo::GetAvailableExtensions"));
// if already loaded, return the pointer
if (m_bExtensionsLoaded) return m_pExtensions;
// set flag even on failure, so we don't keep retrying
m_bExtensionsLoaded = TRUE;
// call service to get extension CLSIDs
CExtensionsCache ExtCache; HRESULT hr = MMCGetExtensionsForSnapIn(m_clsid, ExtCache); if (FAILED(hr)) return NULL;
// Create an extension link for each one found
CExtensionsCacheIterator ExtIter(ExtCache); for (; ExtIter.IsEnd() == FALSE; ExtIter.Advance()) { // if can't be used statically, skip it
if ((ExtIter.GetValue() & CExtSI::EXT_TYPE_STATIC) == 0) continue;
GUID clsid = ExtIter.GetKey();
// See if extension is already in the list
PEXTENSIONLINK pExt = FindExtension(clsid);
// if link isn't present
if (pExt == NULL) { // Locate snapin info for the extension
PSNAPININFO pSnapInfo = pInfoCache->FindEntry(clsid); ASSERT(pSnapInfo != NULL);
if (pSnapInfo) { // Create new link and add to list
PEXTENSIONLINK pNewExt = new CExtensionLink(pSnapInfo); ASSERT(pNewExt != NULL);
pNewExt->SetNext(m_pExtensions); m_pExtensions = pNewExt;
// Save extension type flags
pNewExt->SetExtTypes(ExtIter.GetValue()); } } else { pExt->SetExtTypes(ExtIter.GetValue()); } }
// If no installer module present, return now
if (!MsiModule().IsPresent()) return m_pExtensions;
// Enumerate uninstalled extensions for this snap-in
DWORD dwQualifCnt; DWORD dwAppDataCnt; TCHAR szQualifBuf[MAX_PATH]; TCHAR szAppDataBuf[MAX_PATH];
USES_CONVERSION;
OLECHAR szSnapInGUID[40]; int iRet = StringFromGUID2(m_clsid, szSnapInGUID, countof(szSnapInGUID)); if (iRet == 0) { sc = E_UNEXPECTED; return m_pExtensions; }
LPTSTR pszSnapInGUID = OLE2T(szSnapInGUID);
// Snap-in extension components are registerd as qualifiers of the snap-in component
for (int iIndex = 0; TRUE; iIndex++) { dwQualifCnt = dwAppDataCnt = MAX_PATH; szQualifBuf[0] = szAppDataBuf[0] = 0;
UINT uRet = MsiModule().EnumComponentQualifiers(pszSnapInGUID, iIndex, szQualifBuf, &dwQualifCnt, szAppDataBuf, &dwAppDataCnt);
ASSERT(uRet == ERROR_SUCCESS || uRet == ERROR_NO_MORE_ITEMS || uRet == ERROR_UNKNOWN_COMPONENT); if (uRet != ERROR_SUCCESS) break;
ASSERT(dwQualifCnt != 0); ASSERT(dwAppDataCnt != 0);
GUID clsidExt; HRESULT hr = CLSIDFromString(T2OLE(szQualifBuf), &clsidExt); ASSERT(SUCCEEDED(hr));
// Skip it if this extension has already been found
if (FindExtension(clsidExt) != NULL) continue;
// Locate snap-in info for extension
PSNAPININFO pSnapInfo = pInfoCache->FindEntry(clsidExt);
// if extension is not in the MMC registry, create a snapin info for it
if (pSnapInfo == NULL) { pSnapInfo = new CSnapinInfo; ASSERT(pSnapInfo != NULL);
ASSERT(pMMCPolicy != NULL); BOOL bPermission = pMMCPolicy->IsPermittedSnapIn(clsidExt);
if (pSnapInfo->InitFromComponentReg(clsidExt, szAppDataBuf, FALSE, bPermission)) { pInfoCache->AddEntry(pSnapInfo); } else { delete pSnapInfo; pSnapInfo = NULL; } }
if (pSnapInfo != NULL) { // Create new link and add to list
PEXTENSIONLINK pNewExt = new CExtensionLink(pSnapInfo); ASSERT(pNewExt != NULL);
pNewExt->SetNext(m_pExtensions); m_pExtensions = pNewExt;
// Since we don't know, assume that extension can be static or dynamic
pNewExt->SetExtTypes(CExtSI::EXT_TYPE_STATIC|CExtSI::EXT_TYPE_DYNAMIC); } }
return m_pExtensions; }
//---------------------------------------------------------------------------
// CSnapinInfo::FindExtension
//
// Search snap-in's extension list for an extension with the specified CLSID.
// If foudn, return a pointer to it, else return NULL.
//----------------------------------------------------------------------------
CExtensionLink* CSnapinInfo::FindExtension(CLSID& clsid) { PEXTENSIONLINK pExt = m_pExtensions;
while (pExt != NULL) { if (IsEqualCLSID(clsid, pExt->GetSnapinInfo()->GetCLSID())) break;
pExt = pExt->Next(); }
return pExt; }
//############################################################################
//############################################################################
//
// Implementation of class CExtensionLink
//
//############################################################################
//############################################################################
//---------------------------------------------------------------------------
// CExtensionLink::SetState
//
// Set state of extension link. If state changes to or from EXTEN_ON, add or
// remove a reference to the extension snapin info.
//----------------------------------------------------------------------------
void CExtensionLink::SetState(EXTENSION_STATE eNewState) { if (eNewState == m_eCurState) return;
EXTENSION_STATE eOldState = m_eCurState; m_eCurState = eNewState;
ASSERT(m_pSnapInfo != NULL);
if (eNewState == EXTEN_ON) { m_pSnapInfo->AddUseRef(); } else if (eOldState == EXTEN_ON) { m_pSnapInfo->DeleteUseRef(); } }
//############################################################################
//############################################################################
//
// Implementation of class CManagerNode
//
//############################################################################
//############################################################################
//-------------------------------------------------------------------
// CManagerNode::~CManagerNode
//-------------------------------------------------------------------
CManagerNode::~CManagerNode() { // Delete ref to snapin info
if (m_pSnapInfo) { m_pSnapInfo->DeleteUseRef(); }
// Delete all child nodes
POSITION pos = m_ChildList.GetHeadPosition(); while (pos != NULL) { PMANAGERNODE pmgNode = m_ChildList.GetNext(pos); delete pmgNode; } }
//--------------------------------------------------------------------
// CManagerNode::AddChild
//
// Add a child node to this node.
//--------------------------------------------------------------------
VOID CManagerNode::AddChild(PMANAGERNODE pmgNode) { ASSERT(pmgNode != NULL);
// up link to parent
pmgNode->m_pmgnParent = this;
// set indent level for combo box display
pmgNode->m_iIndent = m_iIndent + 1;
// add node to CList
m_ChildList.AddTail(pmgNode); }
//--------------------------------------------------------------------
// CManagerNode::RemoveChild
//
// Remove a child node from this node
//--------------------------------------------------------------------
VOID CManagerNode::RemoveChild(PMANAGERNODE pmgNode) { ASSERT(pmgNode && pmgNode->m_pmgnParent == this);
// delete child from CList
POSITION pos = m_ChildList.Find(pmgNode); ASSERT(pos != NULL);
m_ChildList.RemoveAt(pos); }
//############################################################################
//############################################################################
//
// Implementation of class CNewTreeNode
//
//############################################################################
//############################################################################
//-----------------------------------------------------------------------
// CNewTreeNode::AddChild
//
// Add a child node to this node.
//------------------------------------------------------------------------
VOID CNewTreeNode::AddChild(PNEWTREENODE pntNode) { ASSERT(pntNode != NULL);
// up link to parent
pntNode->m_pParent = this;
// Add child node to end of linked
if (m_pChild == NULL) { m_pChild = pntNode; } else { PNEWTREENODE pChild= m_pChild; while (pChild->m_pNext != NULL) pChild = pChild->m_pNext;
pChild->m_pNext = pntNode; } }
//----------------------------------------------------------------------
// CNewTreeNode::RemoveChild
//
// Remove a child node from this node
//----------------------------------------------------------------------
VOID CNewTreeNode::RemoveChild(PNEWTREENODE pntNode) { ASSERT(pntNode && pntNode->m_pParent == this);
// locate child node in linked list and unlink it
if (m_pChild == pntNode) { m_pChild = pntNode->m_pNext; } else { PNEWTREENODE pChild = m_pChild; while (pChild && pChild->m_pNext != pntNode) { pChild = pChild->m_pNext; }
ASSERT(pChild != NULL); pChild->m_pNext = pntNode->m_pNext; } }
//############################################################################
//############################################################################
//
// Implementation of class CSnapinManager
//
//############################################################################
//############################################################################
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapinManager);
//-------------------------------------------------------------------------
// CSnapinManager::CSnapinManager
//
// Constructor
//--------------------------------------------------------------------------
CSnapinManager::CSnapinManager(CMTNode *pmtNode) : m_pmtNode(pmtNode), m_proppStandAlone(this), m_proppExtension(this), m_bInitialized(false) { DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapinManager);
static TCHAR titleBuffer[ 256 ] = {0}; ::LoadString( GetStringModule(), ID_SNP_MANAGER_TITLE, titleBuffer, countof(titleBuffer) ); m_psh.pszCaption = titleBuffer;
ASSERT(m_pmtNode != NULL);
// Add the property pages
AddPage( m_proppStandAlone ); AddPage( m_proppExtension );
// hide the Apply button
m_psh.dwFlags |= PSH_NOAPPLYNOW;
m_pMMCPolicy = NULL;
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapinManager); }
//-------------------------------------------------------------------------
// CSnapinManager::~CSnapinManager
//
// Destructor
//-------------------------------------------------------------------------
CSnapinManager::~CSnapinManager() { DECLARE_SC(sc, TEXT("CSnapinManager::~CSnapinManager"));
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapinManager);
Trace(tagSnapinManager, TEXT("CSnapinManager::~CSnapinManager"));
// Delete all manager nodes
if (m_mgNodeList.GetCount() > 0) { ASSERT(m_mgNodeList.GetCount() == 1); delete m_mgNodeList.GetHead(); m_mgNodeList.RemoveAll(); }
// Delete added nodes
POSITION pos = m_NewNodesList.GetHeadPosition(); while (pos!=NULL) { delete m_NewNodesList.GetNext(pos); } m_NewNodesList.RemoveAll();
// Clear deleted node list
m_mtnDeletedNodesList.RemoveAll();
// Free snapin info cache
GUID guid; PSNAPININFO pSnapInfo;
pos = m_SnapinInfoCache.GetStartPosition(); while(pos != NULL) { m_SnapinInfoCache.GetNextAssoc(pos, guid, pSnapInfo); pSnapInfo->Release(); } m_SnapinInfoCache.RemoveAll();
if (m_pMMCPolicy) delete m_pMMCPolicy;
// destroy imagelist
m_iml.Destroy();
// purge the snapin cache, since we released all references
// and some snapins should die
CSnapInsCache* pSnapInCache = theApp.GetSnapInsCache(); sc = ScCheckPointers( pSnapInCache, E_UNEXPECTED ); if ( !sc.IsError() ) pSnapInCache->Purge();
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapinManager); }
//+-------------------------------------------------------------------
//
// Member: CSnapinManager::ScGetSnapinInfo
//
// Synopsis: Given Class-id or prog-id or name of a snapin, return
// the snapins's CSnapinInfo object. (Assumes the
// CSnapinInfoCache is already populated).
//
// Arguments: [szSnapinNameOrCLSIDOrProgID] - [In] snapin name or class-id or prog-id.
// [ppSnapinInfo] - [Out] param to return CSnapinInfo value.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSnapinManager::ScGetSnapinInfo(LPCWSTR szSnapinNameOrCLSIDOrProgID, CSnapinInfo **ppSnapinInfo) { DECLARE_SC(sc, _T("CSnapinManager::ScFindSnapinAndInitSnapinInfo")); sc = ScCheckPointers(szSnapinNameOrCLSIDOrProgID, ppSnapinInfo); if (sc) return sc;
// 0. The given string may be snapin name, class-id or prog-id.
// 1. convert the string to a CLSID
CLSID SnapinCLSID; sc = CLSIDFromString( const_cast<LPWSTR>(szSnapinNameOrCLSIDOrProgID), &SnapinCLSID);
// 2. improper formatting. try to interpret the string as a ProgID
if(sc == SC(CO_E_CLASSSTRING)) sc = CLSIDFromProgID( const_cast<LPWSTR>(szSnapinNameOrCLSIDOrProgID), &SnapinCLSID);
// 3. If class-id is extracted successfully find the CSnapinInfo in the cache and return.
if (! sc.IsError()) { *ppSnapinInfo = m_SnapinInfoCache.FindEntry(SnapinCLSID); return sc; }
// 4. Else interpret the string as snapin name.
USES_CONVERSION;
const tstring& strSnapinName = OLE2CT(szSnapinNameOrCLSIDOrProgID); // This assumes the snapincache is populated.
POSITION pos = m_SnapinInfoCache.GetStartPosition(); while(pos != NULL) { GUID guid; PSNAPININFO pTempSnapInfo = NULL; m_SnapinInfoCache.GetNextAssoc(pos, guid, pTempSnapInfo);
sc = ScCheckPointers(pTempSnapInfo, E_UNEXPECTED); if (sc) return sc;
// Match the name. (Exact match).
if ( CSTR_EQUAL == CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, strSnapinName.data() , -1, OLE2CT(pTempSnapInfo->GetSnapinName()), -1)) { *ppSnapinInfo = pTempSnapInfo; return sc; } }
return (sc = MMC_E_SNAPINNOTFOUND); }
/*+-------------------------------------------------------------------------*
* * CSnapinManager::ScAddSnapin * * PURPOSE: Adds the snapin specified by pSnapinInfo to the console file, * below Console Root. * TODO: Allow the caller to specify the parent node. * * PARAMETERS: * szSnapinNameOrCLSIDOrProgID : [IN] Specifies the snapin to be added (class-id * or prog-id or full name). * pProperties : [IN] Any properties. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CSnapinManager::ScAddSnapin(LPCWSTR szSnapinNameOrCLSIDOrProgID, SnapIn* pParentSnapinNode, Properties *pProperties) { DECLARE_SC(sc, TEXT("CSnapinManager::ScAddSnapin"));
CSnapinStandAlonePage dlgStandalonePage(this);
sc = ScInitialize(); if (sc) return sc;
// Above ScInitialize has populated CSnapinInfoCache, now is a good time
// to get CSnapinInfo for given snapin
CSnapinInfo *pSnapinInfo = NULL; sc = ScGetSnapinInfo(szSnapinNameOrCLSIDOrProgID, &pSnapinInfo); if (sc) return sc;
sc = ScCheckPointers(pSnapinInfo, E_UNEXPECTED); if (sc) return sc;
// Set the given properties in the SnapinInfo.
pSnapinInfo->SetInitProperties(pProperties);
// Set the node under which this snapin will be added as console root)
PMANAGERNODE pmgNodeParent = NULL;
// If a parent snapin under which this snapin should be added is given then
// get the parent MANAGERNODE (else it is console root as above).
if (pParentSnapinNode) { // Get the MTNode for this snapin root.
CMTSnapInNode *pMTSnapinNode = NULL;
sc = CMTSnapInNode::ScGetCMTSnapinNode(pParentSnapinNode, &pMTSnapinNode); if (sc) return sc;
// Find the MANAGERNODE from MTNode.
pmgNodeParent = FindManagerNode(m_mgNodeList, static_cast<CMTNode*>(pMTSnapinNode)); if (! pmgNodeParent) return (sc = E_UNEXPECTED); } else pmgNodeParent = m_mgNodeList.GetHead();
sc = dlgStandalonePage.ScAddOneSnapin(pmgNodeParent, pSnapinInfo); if(sc) return sc;
// Caller must provide master tree before each DoModal
m_pmtNode = NULL;
// Apply changes
UpdateSnapInCache();
return sc; }
//+-------------------------------------------------------------------
//
// Member: CSnapinManager::FindManagerNode
//
// Synopsis: Given MTNode of a snapin, find the managernode
//
// Arguments: [mgNodeList] - the MANAGERNODE list.
// [pMTNode] - the CMTNode* whose MANAGERNODE representation is needed.
//
// Returns: The CManagerNode ptr or NULL.
//
//--------------------------------------------------------------------
PMANAGERNODE CSnapinManager::FindManagerNode(const ManagerNodeList& mgNodeList, CMTNode *pMTNode) { PMANAGERNODE pmgNode = NULL;
POSITION pos = mgNodeList.GetHeadPosition(); while (pos) { pmgNode = mgNodeList.GetNext(pos);
if (pmgNode->m_pmtNode == pMTNode) { return pmgNode; }
// One standalone snapin can be added below another.
pmgNode = FindManagerNode(pmgNode->m_ChildList, pMTNode);
if (pmgNode) return pmgNode; }
return NULL; }
//+-------------------------------------------------------------------
//
// Member: CSnapinManager::ScRemoveSnapin
//
// Synopsis: Remove the snapin represented by given CMTNode*.
//
// Arguments: [pMTNode] - the snapin to be removed.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSnapinManager::ScRemoveSnapin (CMTNode *pMTNode) { DECLARE_SC(sc, _T("CSnapinManager::ScRemoveSnapin"));
CSnapinStandAlonePage dlgStandalonePage(this);
sc = ScInitialize(); if (sc) return sc;
// Find the MANAGERNODE from MTNode.
PMANAGERNODE pmgNode = FindManagerNode(m_mgNodeList, pMTNode); if (! pmgNode) return (sc = E_UNEXPECTED);
// Remove the snapin.
sc = dlgStandalonePage.ScRemoveOneSnapin(pmgNode, /*iItem*/ -1, /*bVisible*/ false); if(sc) return sc;
delete pmgNode;
// Apply changes
UpdateSnapInCache();
return (sc); }
//+-------------------------------------------------------------------
//
// Member: CSnapinManager::ScInitialize
//
// Synopsis: Initialize the snapin mgr object by loading snapin-info
// MTNode tree & creating imagelist for snapins.
//
// Arguments:
//
// Returns: SC
//
// Note: Should be called only once per CSnapinManager instance.
//
//--------------------------------------------------------------------
SC CSnapinManager::ScInitialize () { DECLARE_SC(sc, _T("CSnapinManager::ScInitialize"));
sc = ScCheckPointers(m_pmtNode, E_UNEXPECTED); if (sc) return sc;
// If already initialized just Reload the MTNode tree.
if (m_bInitialized) { if (!LoadMTNodeTree(NULL, m_pmtNode)) return (sc = E_FAIL);
return sc; }
m_pMMCPolicy = new CPolicy; sc = ScCheckPointers(m_pMMCPolicy, E_OUTOFMEMORY); if (sc) return sc;
sc = m_pMMCPolicy->ScInit(); if (sc) return sc;
sc = ScLoadSnapinInfo(); if (sc) return sc;
// Create the image list
if (!m_iml.Create (16/*cx*/, 16/*cy*/, ILC_COLOR | ILC_MASK, 16/*nInitial*/, 16/*cGrow*/)) return (sc = E_FAIL);
if (!LoadMTNodeTree(NULL, m_pmtNode)) return (sc = E_FAIL);
m_bInitialized = true;
return (sc); }
//+-------------------------------------------------------------------
//
// Member: CSnapinManager::ScEnableAllExtensions
//
// Synopsis: Enable all the extensions for the given snapin
//
// Arguments: [clsidSnapin] - Snapin clsid for which extensions be enabled.
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSnapinManager::ScEnableAllExtensions (const CLSID& clsidSnapin, BOOL bEnable) { DECLARE_SC(sc, _T("CSnapinManager::ScEnableAllExtensions"));
sc = ScInitialize(); if (sc) return sc;
// Get the snapin's SnapinInfo.
CSnapinInfo *pSnapinInfo = m_SnapinInfoCache.FindEntry(clsidSnapin); sc = ScCheckPointers(pSnapinInfo, E_UNEXPECTED); if (sc) return sc;
if (!pSnapinInfo->IsUsed()) return (ScFromMMC(MMC_E_SnapinNotAdded));
PEXTENSIONLINK pExt = pSnapinInfo->GetAvailableExtensions(&m_SnapinInfoCache, m_pMMCPolicy); if (!pExt) return (sc = S_FALSE); // No extensions
pSnapinInfo->SetEnableAllExtensions(bEnable);
// if enabling all extensions, turn on all installed extensions
if (pSnapinInfo->AreAllExtensionsEnabled()) { PEXTENSIONLINK pExt = pSnapinInfo->GetExtensions(); while (pExt != NULL) { if (pExt->GetSnapinInfo()->IsInstalled()) pExt->SetState(CExtensionLink::EXTEN_ON);
pExt = pExt->Next(); } }
// Update the snapin mgr's snapin cache.
UpdateSnapInCache();
return (sc); }
//+-------------------------------------------------------------------
//
// Member: CSnapinManager::ScEnableExtension
//
// Synopsis: Enable or disable an extension.
//
// Arguments: [clsidPrimarySnapin] -
// [clsidExtension] - snapin to be enabled/disabled
// [bEnable] - Enable or disable
//
// Returns: SC
//
//--------------------------------------------------------------------
SC CSnapinManager::ScEnableExtension (const CLSID& clsidPrimarySnapin, const CLSID& clsidExtension, bool bEnable) { DECLARE_SC(sc, _T("CSnapinManager::ScEnableExtension"));
sc = ScInitialize(); if (sc) return sc;
// Get the snapin's SnapinInfo.
CSnapinInfo *pSnapinInfo = m_SnapinInfoCache.FindEntry(clsidPrimarySnapin); sc = ScCheckPointers(pSnapinInfo, E_UNEXPECTED); if (sc) return sc;
if (!pSnapinInfo->IsUsed()) return (ScFromMMC(MMC_E_SnapinNotAdded));
// If disable make sure all extensions are not enabled.
if ( (!bEnable) && (pSnapinInfo->AreAllExtensionsEnabled()) ) return ScFromMMC(MMC_E_CannotDisableExtension);
// Load the extensions for the primary.
PEXTENSIONLINK pExt = pSnapinInfo->GetAvailableExtensions(&m_SnapinInfoCache, m_pMMCPolicy); if (!pExt) return (sc = S_FALSE); // No extensions
// Find our extension.
while (pExt) { CSnapinInfo *pExtSnapinInfo = pExt->GetSnapinInfo(); sc = ScCheckPointers(pExtSnapinInfo, E_UNEXPECTED); if (sc) return sc;
if (pExtSnapinInfo->GetCLSID() == clsidExtension) break;
pExt = pExt->Next(); }
sc = ScCheckPointers(pExt, E_UNEXPECTED); if (sc) return sc;
pExt->SetState(bEnable ? CExtensionLink::EXTEN_ON : CExtensionLink::EXTEN_OFF);
// Update the snapin mgr's snapin cache.
UpdateSnapInCache();
return (sc); }
//--------------------------------------------------------------------------
// CSnapinManager::DoModal
//
// Initialize local data structures and present the manager property sheet.
// Return user selection (OK or Cancel).
//
// Note: Should be called only once per CSnapinManager instance.
//
//-------------------------------------------------------------------------
int CSnapinManager::DoModal() { DECLARE_SC(sc, TEXT("CSnapinManager::DoModal"));
int iResp = 0; // 0 is failure
sc = ScCheckPointers(m_pmtNode, E_UNEXPECTED); if (sc) return iResp;
// init ComboBoxEx window class
INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_USEREX_CLASSES;
if (!InitCommonControlsEx(&icex)) { sc = E_FAIL; return iResp; }
sc = ScInitialize(); if (sc) return iResp;
// Do the property sheet
iResp = CPropertySheet::DoModal();
// Caller must provide master tree before each DoModal
m_pmtNode = NULL;
if (iResp == IDOK) { // Apply changes
UpdateSnapInCache(); }
// Delete all manager nodes
ASSERT(m_mgNodeList.GetCount() == 1); delete m_mgNodeList.GetHead(); m_mgNodeList.RemoveAll();
return iResp; }
//----------------------------------------------------------------------
// CSnapinManager::UpdateSnapInCache
//
// Apply changes recorded in the SnapinInfo cache to the SnapinCache.
//----------------------------------------------------------------------
void CSnapinManager::UpdateSnapInCache(void) { CSnapInsCache* pSnapInCache = theApp.GetSnapInsCache(); ASSERT(pSnapInCache != NULL);
GUID guid; PSNAPININFO pSnapInfo; POSITION pos;
// First create any new snapins
pos = m_SnapinInfoCache.GetStartPosition(); while(pos != NULL) { m_SnapinInfoCache.GetNextAssoc(pos, guid, pSnapInfo);
// if snapin is ref'd but doesn't exist yet
if (pSnapInfo->IsUsed() && pSnapInfo->GetSnapIn() == NULL) { CSnapInPtr spSnapIn; SC sc = pSnapInCache->ScGetSnapIn(pSnapInfo->GetCLSID(), &spSnapIn); ASSERT(!sc.IsError()); if (!sc.IsError()) pSnapInfo->SetSnapIn(spSnapIn); } }
// Next add or remove all changed extensions
pos = m_SnapinInfoCache.GetStartPosition(); while(pos != NULL) { m_SnapinInfoCache.GetNextAssoc(pos, guid, pSnapInfo); CSnapIn* pSnapIn = pSnapInfo->GetSnapIn();
if (pSnapInfo->IsUsed()) { // Update state of Enable All flag
pSnapIn->SetAllExtensionsEnabled(pSnapInfo->AreAllExtensionsEnabled());
// Error to override the snap-in's enable
ASSERT(!(pSnapIn->DoesSnapInEnableAll() && !pSnapIn->AreAllExtensionsEnabled())); }
PEXTENSIONLINK pExt = pSnapInfo->GetExtensions(); while (pExt) { // if extension added or removed
if (pExt->IsChanged()) { CSnapIn* pExtSnapIn = pExt->GetSnapinInfo()->GetSnapIn(); ASSERT(pExtSnapIn != NULL);
// Apply change to SnapIn
if (pExtSnapIn) { if (pExt->GetState() == CExtensionLink::EXTEN_ON) { CExtSI* pExtSI = pSnapIn->AddExtension(pExtSnapIn); ASSERT(pExtSI != NULL); pExtSI->SetExtensionTypes(pExt->GetExtTypes()); pExt->SetInitialState(CExtensionLink::EXTEN_ON); } else { pSnapIn->MarkExtensionDeleted(pExtSnapIn); pExt->SetInitialState(CExtensionLink::EXTEN_OFF); } }
// if namespace extension changed, mark SnapIn as changed
if (pExt->GetExtTypes() & CExtSI::EXT_TYPE_NAMESPACE) { pSnapIn->SetNameSpaceChanged(); }
// Change in extension set the help collection dirty.
pSnapInCache->SetHelpCollectionDirty();
} pExt = pExt->Next(); } }
// Propagate snapin change flags up the tree
// This is needed in case an extension that extends another extension has changed
BOOL bChange; do { bChange = FALSE;
pos = m_SnapinInfoCache.GetStartPosition(); while(pos != NULL) { m_SnapinInfoCache.GetNextAssoc(pos, guid, pSnapInfo); CSnapIn* pSnapIn = pSnapInfo->GetSnapIn();
if (pSnapIn && !pSnapIn->HasNameSpaceChanged()) { PEXTENSIONLINK pExt = pSnapInfo->GetExtensions(); while (pExt) { CSnapIn* pExtSnapIn = pExt->GetSnapinInfo()->GetSnapIn();
if (pExtSnapIn && pExtSnapIn->HasNameSpaceChanged()) { pSnapIn->SetNameSpaceChanged(); bChange = TRUE; break; } pExt = pExt->Next(); } } } } while (bChange);
// Next release snapin info refs to snapins that aren't used
pos = m_SnapinInfoCache.GetStartPosition(); while(pos != NULL) { m_SnapinInfoCache.GetNextAssoc(pos, guid, pSnapInfo);
// if snapin exists, but isn't ref'd
if (pSnapInfo->GetSnapIn() != NULL && !pSnapInfo->IsUsed()) { pSnapInfo->DetachSnapIn(); } }
#ifdef DBG
pSnapInCache->DebugDump(); #endif
}
//----------------------------------------------------------------------
// CSnapinManager::LoadSnapinInfo
//
// Read snapin registry information. Create a snapin info object for
// each registered snapin and place in CMap indexed by snapin CLSID.
// Then enumerate snap-ins that are registered as components, but are
// not in the MMC snap-in registry. These are snap-in that will have to
// be downloaded/installed when created.
//----------------------------------------------------------------------
SC CSnapinManager::ScLoadSnapinInfo(void) { DECLARE_SC(sc, TEXT("CSnapinManager::LoadSnapinInfo"));
GUID SnapinCLSID; MMC_ATL::CRegKey SnapinKey; CRegKeyEx ItemKey; long lStat; TCHAR szItemKey[MAX_PATH];
USES_CONVERSION;
// open MMC\Snapins key
lStat = SnapinKey.Open(HKEY_LOCAL_MACHINE, SNAPINS_KEY, KEY_READ); ASSERT(lStat == ERROR_SUCCESS);
if (lStat == ERROR_SUCCESS) { DWORD dwIndex = 0; DWORD dwLen = countof(szItemKey);
// enumerate all snapin keys
while (RegEnumKeyEx(SnapinKey, dwIndex, szItemKey, &dwLen, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { sc = CLSIDFromString( T2OLE(szItemKey), &SnapinCLSID); if (!sc) { // Open the snapin key and create a SnapinInfo object
// from it. Add the object to the cache (CMap)
lStat = ItemKey.Open(SnapinKey, szItemKey, KEY_READ); ASSERT(lStat == ERROR_SUCCESS); if (lStat == ERROR_SUCCESS) { BOOL bPermission = m_pMMCPolicy->IsPermittedSnapIn(SnapinCLSID);
// Don't create a new entry if a CSnapinInfo object already exists; just re-initialize it
PSNAPININFO pSnapInfo = m_SnapinInfoCache.FindEntry(SnapinCLSID); if(pSnapInfo != NULL) { //re-initialize it
if(!pSnapInfo->InitFromMMCReg(SnapinCLSID, ItemKey, bPermission)) return (sc=E_FAIL); } else { // create a new object
pSnapInfo = new CSnapinInfo; sc = ScCheckPointers(pSnapInfo, E_OUTOFMEMORY); if(sc) return sc;
if (pSnapInfo->InitFromMMCReg(SnapinCLSID, ItemKey, bPermission)) { m_SnapinInfoCache.AddEntry(pSnapInfo); } else { delete pSnapInfo; } }
ItemKey.Close(); } }
dwIndex++; dwLen = MAX_PATH; } }
// If no installer module present, return now
if (!MsiModule().IsPresent()) return sc;
// Enumerate standalone snapin components
DWORD dwQualifCnt; DWORD dwAppDataCnt; TCHAR szQualifBuf[MAX_PATH]; TCHAR szAppDataBuf[MAX_PATH];
// enumerate all standalone snap-in components and create snap info entries
for (int iIndex = 0; TRUE; iIndex++) { dwQualifCnt = dwAppDataCnt = MAX_PATH; szQualifBuf[0] = szAppDataBuf[0] = 0;
UINT uRet = MsiModule().EnumComponentQualifiers(const_cast<TCHAR*>(g_szMMCSnapInGuid), iIndex, szQualifBuf, &dwQualifCnt, szAppDataBuf, &dwAppDataCnt);
ASSERT(uRet == ERROR_SUCCESS || uRet == ERROR_NO_MORE_ITEMS || uRet == ERROR_UNKNOWN_COMPONENT || uRet == ERROR_CALL_NOT_IMPLEMENTED);
if (uRet != ERROR_SUCCESS) break;
ASSERT(dwQualifCnt != 0); ASSERT(dwAppDataCnt != 0);
sc = CLSIDFromString(T2OLE(szQualifBuf), &SnapinCLSID); if (sc) { sc.TraceAndClear(); continue; }
// Skip if this snap-in was already found in the MMC registry
if (m_SnapinInfoCache.FindEntry(SnapinCLSID) != NULL) continue;
PSNAPININFO pSnapInfo = new CSnapinInfo;
BOOL bPermission = m_pMMCPolicy->IsPermittedSnapIn(SnapinCLSID);
if (pSnapInfo->InitFromComponentReg(SnapinCLSID, szAppDataBuf, TRUE, bPermission)) { m_SnapinInfoCache.AddEntry(pSnapInfo); } else { delete pSnapInfo; }
}
return sc; }
//---------------------------------------------------------------------------
// CSnapinManager::LoadMTNodeTree
//
// Recursively walk the static portion of the master tree provided by and
// create a parallel tree of manager nodes.
//---------------------------------------------------------------------------
BOOL CSnapinManager::LoadMTNodeTree(PMANAGERNODE pmgnParent, CMTNode* pmtNode) { ManagerNodeList* pChildList; int iIndent;
// Determine child list to add to
if (pmgnParent == NULL) { pChildList = &m_mgNodeList; iIndent = 0; } else { pChildList = &pmgnParent->m_ChildList; iIndent = pmgnParent->m_iIndent + 1; }
// Do for all nodes
while (pmtNode != NULL) { // Only walk static portions
if (pmtNode->IsStaticNode()) { // Create a manager node
PMANAGERNODE pmgNode = new CManagerNode; if ( pmgNode == NULL ) return FALSE;
pmgNode->m_pmtNode = pmtNode; pmgNode->m_pmgnParent = pmgnParent; pmgNode->m_iIndent = iIndent;
tstring strName = pmtNode->GetDisplayName(); pmgNode->m_strValue = strName.data();
// See if this node is provided by a snapin
CSnapIn* pSnapin = pmtNode->GetPrimarySnapIn();
if (pSnapin) { pmgNode->m_nType = ADDSNP_SNAPIN;
// get snapin's CLSID and use it to look up the snapin info object
PSNAPININFO pSnapInfo = m_SnapinInfoCache.FindEntry( pmtNode->GetPrimarySnapInCLSID()); if (pSnapInfo) { // link node to snapin info
pmgNode->m_pSnapInfo = pSnapInfo; pSnapInfo->AddUseRef();
// Link snapin to snapin info
pSnapInfo->AttachSnapIn(pSnapin, m_SnapinInfoCache);
// get images from snapin
pSnapInfo->LoadImages(m_iml); pmgNode->m_iImage = pSnapInfo->GetImage(); pmgNode->m_iOpenImage = pSnapInfo->GetOpenImage(); } } else { pmgNode->m_nType = ADDSNP_STATICNODE;
// for built-ins, get image info directly from node
pmgNode->m_iImage = pmtNode->GetImage(); pmgNode->m_iOpenImage = pmtNode->GetOpenImage(); }
// add node to child list
pChildList->AddTail(pmgNode);
// add all children of this node
if (!LoadMTNodeTree(pmgNode, pmtNode->Child())) return FALSE; }
// go on to node next sibling
pmtNode = pmtNode->Next(); }
return TRUE; }
//############################################################################
//############################################################################
//
// Implementation of class CSnapinStandAlonePage
//
//############################################################################
//############################################################################
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::CSnapinStandAlonePage()
//
// Contructor
//----------------------------------------------------------------------------
CSnapinStandAlonePage::CSnapinStandAlonePage(CSnapinManager* pManager) : m_pManager(pManager), m_pmgnParent(NULL), m_pmgnChild(NULL), m_dlgAdd(pManager, this) { }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::~CSnapinStandAlonePage()
//
// Destructor
//----------------------------------------------------------------------------
CSnapinStandAlonePage::~CSnapinStandAlonePage() { m_snpComboBox.Detach(); m_snpListCtrl.Detach(); }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnInitDialog
//
// Initialize the property page controls.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnInitDialog( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { static TBBUTTON tbBtn[] = {{ 0, ID_SNP_UP, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 0 }};
// Attach control objects to control windows
m_snpComboBox.Attach( ::GetDlgItem(m_hWnd, IDC_SNAPIN_COMBOEX ) ); m_snpListCtrl.Attach( ::GetDlgItem(m_hWnd, IDC_SNAPIN_ADDED_LIST) );
// The following code is needed because a toolbar created by the dialog resource
// won't accept any buttons. This should be investigated further.
// Get rect from dummy placeholder control
HWND hWndStatic = GetDlgItem(IDC_TOOLBAR); ASSERT(hWndStatic != NULL);
RECT rc; ::GetWindowRect( hWndStatic, &rc); ::ScreenToClient( m_hWnd, (LPPOINT)&rc); ::ScreenToClient( m_hWnd, ((LPPOINT)&rc)+1);
// for RLT locales this mapping may produce wrong
// result ( since client coordinated are mirrored)
// following is to fix that:
if (GetExStyle() & WS_EX_LAYOUTRTL) { // Swap left and right
LONG temp = rc.left; rc.left = rc.right; rc.right = temp; }
// Create a toolbar with the same coordiantes
// BOOL bStat = m_ToolbarCtrl.Create( WS_VISIBLE|WS_CHILD|TBSTYLE_TOOLTIPS|CCS_NORESIZE|CCS_NODIVIDER, rc, this, 1);
// ASSERT(bStat);
HWND hToolBar = ::CreateWindow( TOOLBARCLASSNAME, _T( "" ), WS_VISIBLE|WS_CHILD|TBSTYLE_TOOLTIPS|TBSTYLE_TRANSPARENT|CCS_NORESIZE|CCS_NODIVIDER, rc.left, rc.top, ( rc.right - rc.left ), ( rc.bottom - rc.top ), *this, (HMENU) IDC_TOOLBAR, _Module.GetModuleInstance(), NULL ); ASSERT( hToolBar ); ::SendMessage( hToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L ); m_ToolbarCtrl.Attach( hToolBar );
int iStat = m_ToolbarCtrl.AddBitmap( 1, IDB_SNP_MANAGER ); ASSERT(iStat != -1);
BOOL bStat = m_ToolbarCtrl.AddButtons( 1, tbBtn ); ASSERT(bStat);
// attach image list to the combo box and list view controls
m_snpComboBox.SetImageList(m_pManager->m_iml); m_snpListCtrl.SetImageList(m_pManager->m_iml, LVSIL_SMALL);
// Apply workarounds for NT4 comboboxex bugs
m_snpComboBox.FixUp();
// Load combo box list with current node tree
AddNodeListToTree(m_pManager->m_mgNodeList);
// Add single column to list box
m_snpListCtrl.GetClientRect(&rc);
LV_COLUMN lvc; lvc.mask = LVCF_WIDTH | LVCF_SUBITEM; lvc.cx = rc.right - rc.left - GetSystemMetrics(SM_CXVSCROLL); lvc.iSubItem = 0;
int iCol = m_snpListCtrl.InsertColumn(0, &lvc); ASSERT(iCol == 0);
// Select the first node as the current parent
PMANAGERNODE pmgNode = m_pManager->m_mgNodeList.GetHead();
if (pmgNode != NULL) SelectParentNodeItem(pmgNode);
// Turn off the scroll bar in description edit box.
::ShowScrollBar(GetDlgItem(IDC_SNAPIN_DESCR), SB_VERT, FALSE);
return TRUE; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::AddNodeListToTree
//
// Populate the ComboBoxEx control from the manager node tree.
//----------------------------------------------------------------------------
VOID CSnapinStandAlonePage::AddNodeListToTree(ManagerNodeList& NodeList) { COMBOBOXEXITEM ComboItem;
ComboItem.mask = CBEIF_INDENT | CBEIF_LPARAM | CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE; ComboItem.iItem = -1;
// Add each node in list to the combo box
POSITION pos = NodeList.GetHeadPosition(); while (pos != NULL) { PMANAGERNODE pmgNode = NodeList.GetNext(pos);
ComboItem.iIndent = pmgNode->m_iIndent; ComboItem.iImage = pmgNode->m_iImage; ComboItem.iSelectedImage = pmgNode->m_iOpenImage; ComboItem.lParam = reinterpret_cast<LPARAM>(pmgNode); ComboItem.pszText = const_cast<LPTSTR>((LPCTSTR)pmgNode->m_strValue);
m_snpComboBox.InsertItem(&ComboItem);
// Add node's children directly under the node
AddNodeListToTree(pmgNode->m_ChildList); } }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::AddChildToTree
//
// Add new manager node to ComboBoxEx control
//----------------------------------------------------------------------------
int CSnapinStandAlonePage::AddChildToTree(PMANAGERNODE pmgNode) { COMBOBOXEXITEM ComboItem;
PMANAGERNODE pmgnParent = pmgNode->m_pmgnParent; ASSERT(pmgnParent != NULL);
// Get item index of parent
ComboItem.mask = CBEIF_LPARAM; ComboItem.lParam = (LPARAM)pmgnParent; int iItem = m_snpComboBox.FindItem(&ComboItem); ASSERT(iItem != -1);
// Locate index of next sibling (or higher) node
iItem = m_snpComboBox.FindNextBranch(iItem);
// Insert new node at that position
ComboItem.mask = CBEIF_INDENT | CBEIF_LPARAM | CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE; ComboItem.iItem = iItem; ComboItem.iIndent = pmgNode->m_iIndent; ComboItem.iImage = pmgNode->m_iImage; ComboItem.iSelectedImage = pmgNode->m_iOpenImage; ComboItem.lParam = (LPARAM)pmgNode; ComboItem.pszText = const_cast<LPTSTR>((LPCTSTR)pmgNode->m_strValue);
iItem = m_snpComboBox.InsertItem(&ComboItem); ASSERT(iItem != -1);
return iItem; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::DisplayChildList
//
// Display a list of nodes in the listbox control. This is called whenever
// the current parent node is changed.
//----------------------------------------------------------------------------
VOID CSnapinStandAlonePage::DisplayChildList(ManagerNodeList& NodeList) {
// Clear old list
m_snpListCtrl.DeleteAllItems();
int iIndex = 0;
// Add each node from the list
POSITION pos = NodeList.GetHeadPosition(); while (pos != NULL) { PMANAGERNODE pmgNode = NodeList.GetNext(pos); AddChildToList(pmgNode, iIndex++); }
// Clear current selection
SetupChildNode(NULL);
// Set focus to the first item
m_snpListCtrl.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED); }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::AddChildToList
//
// Add a manager node to the listview control.
//----------------------------------------------------------------------------
int CSnapinStandAlonePage::AddChildToList(PMANAGERNODE pmgNode, int iIndex) { LV_ITEM LVItem;
LVItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; LVItem.iItem = (iIndex >= 0) ? iIndex : m_snpListCtrl.GetItemCount(); LVItem.iSubItem = 0; LVItem.iImage = pmgNode->m_iImage; LVItem.pszText = const_cast<LPTSTR>((LPCTSTR)pmgNode->m_strValue); LVItem.lParam = reinterpret_cast<LPARAM>(pmgNode);
iIndex = m_snpListCtrl.InsertItem(&LVItem); ASSERT (iIndex != -1);
return iIndex; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnTreeItemSelect
//
// Handle selection of item from ComboBoxEx control. Make the selected
// item the current parent node.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnTreeItemSelect( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { int iItem = m_snpComboBox.GetCurSel(); ASSERT(iItem >= 0); if (iItem < 0) return 0;
COMBOBOXEXITEM ComboItem; ComboItem.mask = CBEIF_LPARAM; ComboItem.iItem = iItem;
BOOL bStat = m_snpComboBox.GetItem(&ComboItem); ASSERT(bStat);
PMANAGERNODE pMgrNode = reinterpret_cast<PMANAGERNODE>(ComboItem.lParam); ASSERT(pMgrNode != NULL);
SetupParentNode(pMgrNode);
return 0; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnTreeUp
//
// Handle activation of folder-up button. Make parent of the current parent
// node the new current parent.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnTreeUp( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { ASSERT(m_pmgnParent != NULL && m_pmgnParent->m_pmgnParent != NULL);
SelectParentNodeItem(m_pmgnParent->m_pmgnParent);
return 0; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::SelectParentNodeItem
//
// Handle selection of item from ComboBoxEx control. Make the selected
// item the current parent node.
//----------------------------------------------------------------------------
void CSnapinStandAlonePage::SelectParentNodeItem(PMANAGERNODE pMgrNode) { // Locate node entry in the dropdown combo box
COMBOBOXEXITEM ComboItem; ComboItem.mask = CBEIF_LPARAM; ComboItem.lParam = reinterpret_cast<LPARAM>(pMgrNode);
int iComboItem = m_snpComboBox.FindItem(&ComboItem); ASSERT(iComboItem != -1); if (iComboItem < 0) return;
// Select the combo box entry
m_snpComboBox.SetCurSel(iComboItem);
SetupParentNode(pMgrNode); }
/*+-------------------------------------------------------------------------*
* * CSnapinStandAlonePage::SetupParentNode * * PURPOSE: Setup a manger node as the current parent. * * PARAMETERS: * PMANAGERNODE pMgrNode : * bool bVisible : false if this dialog is not being shown. * * RETURNS: * void * *+-------------------------------------------------------------------------*/ void CSnapinStandAlonePage::SetupParentNode(PMANAGERNODE pMgrNode, bool bVisible) { ASSERT(pMgrNode != NULL);
// Set node as current parent
m_pmgnParent = pMgrNode;
if(!bVisible) return;
// Display children in list view
DisplayChildList(pMgrNode->m_ChildList);
// Enable folder-up button if current parent has a parent
m_ToolbarCtrl.EnableButton(ID_SNP_UP,( pMgrNode->m_pmgnParent != NULL));
// Present selection to Visual Test (It can't get it through the ComboBoxEx)
TCHAR VTBuf[100]; (void) StringCchPrintf(VTBuf,countof(VTBuf), _T("%d,%s\0"), pMgrNode->m_iIndent, pMgrNode->m_strValue); ::SetWindowText( GetDlgItem(IDC_VTHELPER), VTBuf ); }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::SetupChildNode
//
// Setup a manger node as the current child.
//----------------------------------------------------------------------------
void CSnapinStandAlonePage::SetupChildNode(PMANAGERNODE pMgrNode) { // Set node as current child
m_pmgnChild = pMgrNode;
// Enable/disable Delete button
EnableButton(m_hWnd, IDC_SNAPIN_MANAGER_DELETE, m_snpListCtrl.GetSelectedCount() != 0);
// Enable/disable About button
EnableButton(m_hWnd, IDC_SNAPIN_ABOUT, m_pmgnChild && m_pmgnChild->HasAboutInfo()); }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnListItemChanged
//
// Handle selection of item from listview control. Update description text
// and Delete button state.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnListItemChanged( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pnmh; PMANAGERNODE pmgNode = NULL;
// if item selected
if (~pNMListView->uOldState & pNMListView->uNewState & LVIS_SELECTED) { // get description text from snapin info
pmgNode = (PMANAGERNODE)pNMListView->lParam;
// Get description text if any available
LPOLESTR lpsz = NULL; if (pmgNode->GetSnapinInfo()) { pmgNode->GetSnapinInfo()->LoadAboutInfo(); lpsz = pmgNode->GetSnapinInfo()->GetDescription(); }
// display in description window
USES_CONVERSION; SC sc = ScSetDescriptionUIText(GetDlgItem(IDC_SNAPIN_DESCR), lpsz ? OLE2CT(lpsz ): _T("")); if (sc) sc.TraceAndClear();
// Make node the current child
SetupChildNode(pmgNode); } else { SetupChildNode(NULL); }
return 0; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnListItemDblClick
//
// Handle double click of listview item. Make the selected node the current
// parent node.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnListItemDblClick( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { // Get the selected item
int iItem = m_snpListCtrl.GetNextItem(-1, LVNI_SELECTED); if (iItem < 0) return 0;
// Get the item data (ManagerNode pointer)
PMANAGERNODE pmgNode = reinterpret_cast<PMANAGERNODE>(m_snpListCtrl.GetItemData(iItem));
// Select this node as the current parent
SelectParentNodeItem(pmgNode);
return 0; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnListKeyDown
//
// Handle double click of listview item. Make the selected node the current
// parent node.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnListKeyDown( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { LV_KEYDOWN* pNotify = reinterpret_cast<LV_KEYDOWN*>(pnmh);
if (pNotify->wVKey == VK_DELETE) { OnDeleteSnapin( 1, IDC_SNAPIN_MANAGER_DELETE, (HWND)GetDlgItem(IDC_SNAPIN_MANAGER_DELETE), bHandled ); } else { bHandled = FALSE; }
return 0; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnAddSnapin
//
// Handle activation of Add Snapin button. Bring up the Add dialog and create
// a NewTreeNode for the selected snapin type.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnAddSnapin( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { ASSERT(m_pmgnParent != NULL);
// display the Add dialog
GetAddDialog().DoModal();
return 0; }
/*+-------------------------------------------------------------------------*
* * CSnapinStandAlonePage::ScAddOneSnapin * * PURPOSE: Called to add a single snapin underneath the specified node. * Does not use the UI. * * PARAMETERS: * PMANAGERNODE pmgNodeParent: The parent node to add this below * PSNAPININFO pSnapInfo : The snapin to add. * * RETURNS: * SC * *+-------------------------------------------------------------------------*/ SC CSnapinStandAlonePage::ScAddOneSnapin(PMANAGERNODE pmgNodeParent, PSNAPININFO pSnapInfo) { DECLARE_SC(sc, TEXT("CSnapinStandAlonePage::ScAddOneSnapin"));
// check parameters
if( (NULL == pmgNodeParent) || (NULL == pSnapInfo) ) { sc = E_POINTER; return sc; }
// set up the parent node pointer
SetupParentNode(pmgNodeParent, false /*bVisible*/);
// add the snapin.
sc = AddOneSnapin(pSnapInfo, false /*bVisual*/); if (sc) return sc;
return sc; }
/*+-------------------------------------------------------------------------*
* * CSnapinStandAlonePage::AddOneSnapin * * PURPOSE: This method is called from the add snap-in dialog each time the user requests * to add a snap-in node. The method creates the node and adds it to the * snap-in manager's copy of the master tree. * * PARAMETERS: * PSNAPININFO pSnapInfo : * bool bVisible : true if the addition is being done with * the snapin manager being visible, false * if the addition is being done by automation. * * RETURNS: * LRESULT * *+-------------------------------------------------------------------------*/ HRESULT CSnapinStandAlonePage::AddOneSnapin(PSNAPININFO pSnapInfo, bool bVisible) { DECLARE_SC(sc, TEXT("CSnapinStandAlonePage::AddOneSnapin"));
if (pSnapInfo == NULL) return S_FALSE;
// If this snapin type is not currrently in use
if (pSnapInfo->GetSnapIn() == NULL) { // ensure that the snapin is in the cache so if the user
// requests help from the wizard pages, the help collection
// will contain this snapin's topics
CSnapInsCache* pSnapInCache = theApp.GetSnapInsCache(); ASSERT(pSnapInCache != NULL);
// use a smart pointer because we don't need to hold it once
// the cache entry is created
CSnapInPtr spSnapIn; sc = pSnapInCache->ScFindSnapIn(pSnapInfo->GetCLSID(), &spSnapIn); if (sc) { sc = pSnapInCache->ScGetSnapIn(pSnapInfo->GetCLSID(), &spSnapIn); if(sc) sc.TraceAndClear(); // not a big issue - we can ignore it
// - just normaly shouldn't be so
// Set stand-alone change, to invalidate help collection
pSnapInCache->SetHelpCollectionDirty(); } }
// If component is not installed yet, do it now
if (!pSnapInfo->IsInstalled()) { // 1. install the component
sc = pSnapInfo->ScInstall(NULL); if(sc) return sc.ToHr();
// 2. update all the snapin info objects from the registry. This is because installing a
// single msi package may install several snapins.
sc = ScCheckPointers(m_pManager, E_UNEXPECTED); if(sc) return sc.ToHr();
sc = m_pManager->ScLoadSnapinInfo(); if(sc) return sc.ToHr(); }
// Run wizard to get component data
// (returns a ref'd interface)
HWND hWndParent = NULL; if(bVisible) { hWndParent = GetAddDialog().m_hWnd; } else { hWndParent = ::GetDesktopWindow(); }
IComponentDataPtr spIComponentData; PropertiesPtr spSnapinProps;
sc = ScRunSnapinWizard (pSnapInfo->GetCLSID(), hWndParent, pSnapInfo->GetInitProperties(), *&spIComponentData, *&spSnapinProps); if (sc) return (sc.ToHr());
// if the creation succeeded
if (spIComponentData != NULL) { // Create new tree node
CNewTreeNode* pNewTreeNode = new CNewTreeNode; if (pNewTreeNode == NULL) return ((sc = E_OUTOFMEMORY).ToHr());
// if snapin node
pNewTreeNode->m_spIComponentData = spIComponentData; pNewTreeNode->m_clsidSnapIn = pSnapInfo->GetCLSID(); pNewTreeNode->m_spSnapinProps = spSnapinProps;
// must be child of existing MT node or another new node
ASSERT(m_pmgnParent->m_pmtNode || m_pmgnParent->m_pNewNode);
// If adding to existing node
if (m_pmgnParent->m_pmtNode) { // Add directly to new nodes list
pNewTreeNode->m_pmtNode = m_pmgnParent->m_pmtNode; m_pManager->m_NewNodesList.AddTail(pNewTreeNode); } else { // Add as child to new node
pNewTreeNode->m_pParent = m_pmgnParent->m_pNewNode; m_pmgnParent->m_pNewNode->AddChild(pNewTreeNode); }
// Create new manger node
PMANAGERNODE pmgNode = new CManagerNode; pmgNode->m_pNewNode = pNewTreeNode;
pSnapInfo->AddUseRef(); pmgNode->m_pSnapInfo = pSnapInfo; pmgNode->m_nType = ADDSNP_SNAPIN;
// if this snapin type isn't currently in use
if (pSnapInfo->GetSnapIn() == NULL) { // if so, get the snapin's cache entry so we can
// determine its required extensions.
CSnapInsCache* pSnapInCache = theApp.GetSnapInsCache(); ASSERT(pSnapInCache != NULL);
CSnapInPtr spSnapIn; SC sc = pSnapInCache->ScGetSnapIn(pSnapInfo->GetCLSID(), &spSnapIn); ASSERT(!sc.IsError());
if (!sc.IsError()) { // Load the extensions then call AttachSnapIn so snapin manager
// will load the required extensions from the cache and turn
// them on by default. (Do the load here to prevent AttachSnapIn
// from creating another instance of the snapin.)
LoadRequiredExtensions(spSnapIn, spIComponentData); pSnapInfo->AttachSnapIn(spSnapIn, m_pManager->m_SnapinInfoCache); } } if(bVisible) { // Get images from snapin
pSnapInfo->LoadImages(m_pManager->m_iml); pmgNode->m_iImage = pSnapInfo->GetImage(); pmgNode->m_iOpenImage = pSnapInfo->GetOpenImage(); }
// get display name from component data
if ( FAILED(LoadRootDisplayName(spIComponentData, pmgNode->m_strValue)) ) { ASSERT(FALSE); pmgNode->m_strValue = pSnapInfo->GetSnapinName(); }
// Add to manager node tree, listview and combobox controls
m_pmgnParent->AddChild(pmgNode);
if(bVisible) { AddChildToTree(pmgNode);
int iIndex = AddChildToList(pmgNode);
// Give focus to new item and make it visible
m_snpListCtrl.EnsureVisible(iIndex, FALSE); m_snpListCtrl.SetItemState(iIndex,LVIS_FOCUSED,LVIS_FOCUSED); } }
return S_OK; }
//+-------------------------------------------------------------------
//
// Member: CSnapinStandAlonePage::ScRemoveOneSnapin
//
// Synopsis: Removes the snapin from the snapin manager data structures.
//
// Arguments: [pmgNode] - The (MANAGERNODE of) snapin to be removed.
// [iItem] - index of the snapin in snapin mgr,
// valid only if snapin mgr is visible.
// [bVisible] - Snapin mgr UI is visible/hidden.
//
// Returns: SC
//
// Note: The caller should delete PMANAGERNODE passed else memory will leak.
//
//--------------------------------------------------------------------
SC CSnapinStandAlonePage::ScRemoveOneSnapin ( PMANAGERNODE pmgNode, int iItem, bool bVisible /*= true*/) { DECLARE_SC(sc, _T("CSnapinStandAlonePage::ScRemoveOneSnapin")); sc = ScCheckPointers(pmgNode); if (sc) return sc;
sc = ScCheckPointers(m_pManager, pmgNode->m_pmgnParent, E_UNEXPECTED); if (sc) return sc;
// If existing MT node
if (pmgNode->m_pmtNode != NULL) { // Add MT node to delete list
m_pManager->m_mtnDeletedNodesList.AddTail(pmgNode->m_pmtNode);
// Delete any new nodes attached to this one
POSITION pos = m_pManager->m_NewNodesList.GetHeadPosition(); while (pos) { POSITION posTemp = pos;
PNEWTREENODE pNew = m_pManager->m_NewNodesList.GetNext(pos); sc = ScCheckPointers(pNew, E_UNEXPECTED); if (sc) return sc;
if (pNew->m_pmtNode == pmgNode->m_pmtNode) { m_pManager->m_NewNodesList.RemoveAt(posTemp); delete pNew; // delete and release IComponent
} } } else // if new node
{ PNEWTREENODE pNew = pmgNode->m_pNewNode;
// This is a new node.
if (NULL == pNew) return (sc = E_UNEXPECTED);
// If child of an existing MT node?
if (pNew->GetMTNode()) { // Locate in new node list
POSITION pos = m_pManager->m_NewNodesList.Find(pNew); if(pos == NULL) return (sc = E_UNEXPECTED);
// delete this item and all it's children
m_pManager->m_NewNodesList.RemoveAt(pos); delete pNew; // delete and release IComponent
} else // child of new node
{ if (NULL == pNew->Parent()) return (sc = E_UNEXPECTED);
pNew->Parent()->RemoveChild(pNew); delete pNew; } }
// Remove from manager tree
pmgNode->m_pmgnParent->RemoveChild(pmgNode);
CSnapInsCache* pSnapInCache = theApp.GetSnapInsCache(); sc = ScCheckPointers(pSnapInCache, E_UNEXPECTED); if (sc) return sc;
// Snapin removed set help collection invalid.
pSnapInCache->SetHelpCollectionDirty();
if (bVisible) { m_snpListCtrl.DeleteItem(iItem);
// Remove item and all children from combo box
COMBOBOXEXITEM ComboItem; ComboItem.mask = CBEIF_LPARAM; ComboItem.lParam = (LPARAM)pmgNode; int iCombo = m_snpComboBox.FindItem(&ComboItem);
ASSERT(iCombo != -1); m_snpComboBox.DeleteBranch(iCombo); }
return (sc); }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnDeleteSnapin
//
// Handle activation of Delete button. Delete all selected snapins.
// item the current parent node.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnDeleteSnapin( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { DECLARE_SC(sc, _T("CSnapinStandAlonePage::OnDeleteSnapin"));
BOOL bChildren = FALSE;
// Check if any of the selected node have children
int iItem = -1; while ((iItem = m_snpListCtrl.GetNextItem(iItem, LVNI_SELECTED)) >= 0) { PMANAGERNODE pmgNode = (PMANAGERNODE)m_snpListCtrl.GetItemData(iItem); if (!pmgNode->m_ChildList.IsEmpty()) { bChildren = TRUE; break; } }
// If so, give user a chance to cancel
if (bChildren) { CStr strTitle; strTitle.LoadString(GetStringModule(), SNP_DELETE_TITLE);
CStr strText; strText.LoadString(GetStringModule(), SNP_DELETE_TEXT);
if (MessageBox(strText, strTitle, MB_ICONQUESTION|MB_YESNO) != IDYES) { return 0; } }
// Do for all selected items in listview
int iLastDelete = -1; iItem = -1; while ((iItem = m_snpListCtrl.GetNextItem(iItem, LVNI_SELECTED)) >= 0) { // get manager node from item
PMANAGERNODE pmgNode = (PMANAGERNODE)m_snpListCtrl.GetItemData(iItem);
sc = ScRemoveOneSnapin(pmgNode, iItem, true); if (sc) return 0;
// destroy the removed node (and its children)
delete pmgNode;
iLastDelete = iItem; iItem--; }
// if items deleted, set focus near last deleted item
if (iLastDelete != -1) { int nCnt = m_snpListCtrl.GetItemCount(); if (nCnt > 0) { // if deleted the last item, backup to previous one
if (iLastDelete >= nCnt) iLastDelete = nCnt - 1;
m_snpListCtrl.SetItemState(iLastDelete, LVIS_FOCUSED, LVIS_FOCUSED); } }
SetupChildNode(NULL);
// Clear description text
sc = ScSetDescriptionUIText(GetDlgItem(IDC_SNAPIN_DESCR), _T("")); if (sc) sc.TraceAndClear();
return 0; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::OnAboutSnapin
//
// Handle activation of About button. Display About dialog for the selected
// child node's snapin.
//----------------------------------------------------------------------------
LRESULT CSnapinStandAlonePage::OnAboutSnapin( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { if (m_pmgnChild && m_pmgnChild->HasAboutInfo()) m_pmgnChild->GetSnapinInfo()->ShowAboutPages(m_pManager->m_hWnd);
return 0; }
//----------------------------------------------------------------------------
// CSnapinStandAlonePage::ScRunSnapinWizard
//
// Run Snapin wizard to create snapin instance and return the IComponentData.
//----------------------------------------------------------------------------
SC CSnapinStandAlonePage::ScRunSnapinWizard ( const CLSID& clsid, /* I:snap-in to create */ HWND hwndParent, /* I:parent of wizard */ Properties* pInitProps, /* I:properties to init with */ IComponentData*& rpComponentData, /* O:snap-in's IComponentData */ Properties*& rpSnapinProps) /* O:snap-in's properties */ { DECLARE_SC (sc, _T("CSnapinStandAlonePage::ScRunSnapinWizard"));
rpComponentData = NULL; rpSnapinProps = NULL;
/*
* create a new node manager for the snap-in */ IUnknownPtr pIunkNodemgr; sc = pIunkNodemgr.CreateInstance(CLSID_NodeInit, NULL, MMC_CLSCTX_INPROC); if (sc) return (sc);
if (pIunkNodemgr == NULL) return (sc = E_UNEXPECTED);
/*
* create the snap-in */ sc = CreateSnapIn(clsid, &rpComponentData, false); if (sc) return (sc);
if (rpComponentData == NULL) return (sc = E_UNEXPECTED);
/*-----------------------------------------------------------------
* From this point on a failure isn't considered catastrophic. If * anything fails, we'll return at that point, but return success. */
/*
* if we got properties to initialize with, see if the snap-in * supports ISnapinProperties */ ISnapinPropertiesPtr spISP;
if (pInitProps && ((spISP = rpComponentData) != NULL)) { CComObject<CSnapinProperties>* pSnapinProps; CComObject<CSnapinProperties>::CreateInstance (&pSnapinProps);
/*
* Initialize the snap-in with the initial properties. If the * snap-in fails to initialize, we'll release the CSnapinProperties * we created (because the spSnapinProps smart pointer will go out * of scope), but we won't return failure. */ if (pSnapinProps != NULL) { /*
* add a ref here, if ScInitialize fails, the balancing * Release will delete the Properties object */ pSnapinProps->AddRef();
if (!pSnapinProps->ScInitialize(spISP, pInitProps, NULL).IsError()) { /* `
* If we get here, the snap-in's ISnapinProperties was * initilialized correctly. Put a ref on for the client. */ rpSnapinProps = pSnapinProps; rpSnapinProps->AddRef(); }
/*
* release the ref we put on above, if ScInitialize failed, * this release will delete the Properties */ pSnapinProps->Release(); } }
/*
* get the snap-in's data object */ IDataObjectPtr pIDataObject; sc = rpComponentData->QueryDataObject(NULL, CCT_SNAPIN_MANAGER, &pIDataObject); if (sc.IsError() || (pIDataObject == NULL)) return (sc);
IPropertySheetProviderPtr pIPSP = pIunkNodemgr;
if (pIPSP == NULL) return (sc);
IPropertySheetCallbackPtr pIPSC = pIunkNodemgr;
if (pIPSC == NULL) return (sc);
// determine which pointer to use
IExtendPropertySheetPtr spExtend = rpComponentData; IExtendPropertySheet2Ptr spExtend2 = rpComponentData;
IExtendPropertySheet* pIPSE;
if (spExtend2 != NULL) pIPSE = spExtend2; else pIPSE = spExtend;
// Snap-in may not have a property sheet to set the properties of the snap-in
if (pIPSE == NULL) return (sc);
do { // Create the PropertySheet , FALSE = WIZARD
sc = pIPSP->CreatePropertySheet( L"", FALSE, NULL, pIDataObject, MMC_PSO_NEWWIZARDTYPE); if(sc.ToHr() != S_OK) break;
// Add Primary pages without notify handle
sc = pIPSP->AddPrimaryPages(rpComponentData, FALSE, NULL, FALSE);
if (sc.ToHr() == S_OK) { // Show the property sheet
sc = pIPSP->Show((LONG_PTR)hwndParent, 0); if (sc.ToHr() != S_OK) break; } else { // force the property sheet to be destroyed
pIPSP->Show(-1, 0);
// abort if snapin had a failure
if (sc) break; }
return sc; } while (0);
// already checked for NULL above, but repeating the check here
if(rpComponentData != NULL) { rpComponentData->Release(); rpComponentData = NULL; }
return (sc); }
//############################################################################
//############################################################################
//
// Implementation of class CSnapinExtensionPage
//
//############################################################################
//############################################################################
//----------------------------------------------------------------------------
// CSnapinExtensionPage::~CSnapinExtensionPage
//
// Destructor
//----------------------------------------------------------------------------
CSnapinExtensionPage::~CSnapinExtensionPage() { m_ilCheckbox.Destroy(); m_SnapComboBox.Detach(); m_ExtListCtrl.Detach(); }
//----------------------------------------------------------------------------
// CSnapinExtensionPage::OnInitDialog
//
// Initialize the property page controls.
//----------------------------------------------------------------------------
LRESULT CSnapinExtensionPage::OnInitDialog( UINT mMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) { // Attach control objects to control windows
m_SnapComboBox.Attach( ::GetDlgItem(m_hWnd, IDC_SNAPIN_COMBOEX ) ); m_ExtListCtrl.SubclassWindow( ::GetDlgItem( *this, IDC_EXTENSION_LIST ) );
// attach shared image list to both listviews
m_SnapComboBox.SetImageList(m_pManager->m_iml); m_ExtListCtrl.SetImageList(m_pManager->m_iml, LVSIL_SMALL);
// Add single column to list box
RECT rc; m_ExtListCtrl.GetClientRect(&rc);
LV_COLUMN lvc; lvc.mask = LVCF_WIDTH | LVCF_SUBITEM; lvc.cx = rc.right - rc.left - GetSystemMetrics(SM_CXVSCROLL); lvc.iSubItem = 0;
int iCol = m_ExtListCtrl.InsertColumn(0, &lvc); ASSERT(iCol == 0);
// Load checkbox images
if (m_ilCheckbox.Create(IDB_CHECKBOX, 16, 3, RGB(255,0,255))) { // Set background color to match list control, so checkboxes aren't drawn transparently
m_ilCheckbox.SetBkColor(m_ExtListCtrl.GetBkColor()); m_ExtListCtrl.SetImageList(m_ilCheckbox, LVSIL_STATE); } else { ASSERT(FALSE); // Unable to create imagelist
}
// Apply workarounds for NT4 comboboxex bugs
m_SnapComboBox.FixUp();
// Turn off the scroll bar in description edit box.
::ShowScrollBar(GetDlgItem(IDC_SNAPIN_DESCR), SB_VERT, FALSE);
return 0; }
//--------------------------------------------------------------------------
// CSnapinExtensionPage::OnSetActive
//
// Update the data
//--------------------------------------------------------------------------
BOOL CSnapinExtensionPage::OnSetActive() { BC::OnSetActive();
BuildSnapinList();
return TRUE; }
//-------------------------------------------------------------------------
// CSnapinExtensionPage::OnSnapinDropDown
//
// Called when snapin dropdown is about to be displayed. Rebuilds the list
// if the update flag is set.
//-------------------------------------------------------------------------
LRESULT CSnapinExtensionPage::OnSnapinDropDown( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { if (m_bUpdateSnapinList) { BuildSnapinList(); }
return 0; }
//--------------------------------------------------------------------------
// CSnapinExtensionPage::OnSnapinSelect
//
// Handle selection of snapin from combobox. Make it the current snapin
// and display its extension list.
//--------------------------------------------------------------------------
LRESULT CSnapinExtensionPage::OnSnapinSelect( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { int iItem = m_SnapComboBox.GetCurSel(); ASSERT(iItem >= 0); if (iItem < 0) return 0;
PSNAPININFO pSnapInfo = reinterpret_cast<PSNAPININFO>(m_SnapComboBox.GetItemDataPtr(iItem)); ASSERT((LONG_PTR)pSnapInfo != -1);
m_pCurSnapInfo = pSnapInfo; BuildExtensionList(pSnapInfo);
return 0; }
//----------------------------------------------------------------------------
// CSnapinExtensionPage::OnAboutSnapin
//
// Handle activation of About button. Display About dialog for the selected
// extension's snapin.
//----------------------------------------------------------------------------
LRESULT CSnapinExtensionPage::OnAboutSnapin( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { if (m_pExtLink && m_pExtLink->GetSnapinInfo()->HasAbout()) { m_pExtLink->GetSnapinInfo()->ShowAboutPages(m_hWnd); }
return 0; }
//----------------------------------------------------------------------------
// CSnapinExtensionPage::OnDownloadSnapin
//
// Handle activation of Download button. Download the selected extension
// snapin.
//----------------------------------------------------------------------------
LRESULT CSnapinExtensionPage::OnDownloadSnapin( WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled ) { DECLARE_SC(sc, TEXT("CSnapinExtensionPage::OnDownloadSnapin"));
ASSERT(m_pExtLink && m_pExtLink->GetSnapinInfo());
// 1. install the component
sc = m_pExtLink->GetSnapinInfo()->ScInstall(&m_pCurSnapInfo->GetCLSID()); if(sc) return 0;
// 2. update all the snapin info objects from the registry. This is because installing a
// single msi package may install several snapins.
sc = ScCheckPointers(m_pManager, E_UNEXPECTED); if(sc) return 0;
sc = m_pManager->ScLoadSnapinInfo(); if(sc) return 0;
// Better to update the individual extention
// For now, just rebuild the list
BuildExtensionList(m_pCurSnapInfo);
return 0; }
//----------------------------------------------------------------------------
// CSnapinExtensionPage::BuildSnapinList
//
// Load the combo box with the existing snapins and extensions
//----------------------------------------------------------------------------
void CSnapinExtensionPage::BuildSnapinList() { CSnapinInfoCache* pInfoCache = &m_pManager->m_SnapinInfoCache;
// Clear the items
m_SnapComboBox.ResetContent();
COMBOBOXEXITEM ComboItem; ComboItem.mask = CBEIF_LPARAM | CBEIF_IMAGE | CBEIF_TEXT | CBEIF_SELECTEDIMAGE;
int iCount = 0;
// Do for all snapinfo objects
POSITION pos = pInfoCache->GetStartPosition(); while (pos != NULL) { USES_CONVERSION; GUID clsid; PSNAPININFO pSnapInfo;
pInfoCache->GetNextAssoc(pos, clsid, pSnapInfo); ASSERT(pSnapInfo != NULL);
// Only show snapins that are used and have extensions available
if (pSnapInfo->IsUsed() && pSnapInfo->IsPermittedByPolicy() && pSnapInfo->GetAvailableExtensions(pInfoCache, m_pManager->m_pMMCPolicy)) { ComboItem.lParam = reinterpret_cast<LPARAM>(pSnapInfo); pSnapInfo->LoadImages(m_pManager->m_iml); ComboItem.iImage = pSnapInfo->GetImage(); ComboItem.iSelectedImage = pSnapInfo->GetOpenImage(); ComboItem.pszText = OLE2T(pSnapInfo->GetSnapinName());
// CComboBoxEx doesn't support CBS_SORT and has no add method, only insert
// So we need to find the insertion point ourselves. Because it's a short
// list, just do a linear search.
int iInsert; for (iInsert = 0; iInsert < iCount; iInsert++) { PSNAPININFO pSnapEntry = reinterpret_cast<PSNAPININFO>(m_SnapComboBox.GetItemData(iInsert));
// need to protect ourselves from the invalid snapin registration.
// see windows bug #401220 ( ntbugs9 5/23/2001 )
if ( NULL == pSnapInfo->GetSnapinName() || NULL == pSnapEntry->GetSnapinName() ) break;
if( wcscmp( pSnapInfo->GetSnapinName(), pSnapEntry->GetSnapinName() ) < 0) break; } ComboItem.iItem = iInsert;
int iItem = m_SnapComboBox.InsertItem(&ComboItem); if (iItem != -1) { iCount++; } else { ASSERT(FALSE); } } }
int iSelect = -1;
// if any items in list
if (iCount > 0) { // try to get index of previously selected snapin
if (m_pCurSnapInfo) { for (int iFind = 0; iFind < iCount; iFind++) { if (m_SnapComboBox.GetItemData(iFind) == reinterpret_cast<LPARAM>(m_pCurSnapInfo)) iSelect = iFind; } }
// if not in list any more, select first item by default
if (iSelect == -1) { m_pCurSnapInfo = reinterpret_cast<PSNAPININFO>(m_SnapComboBox.GetItemData(0)); iSelect = 0; }
m_SnapComboBox.SetCurSel(iSelect); m_SnapComboBox.EnableWindow(TRUE); } else { // NT 4.0 comctl32 has a bug that displays garbage characters in an empty
// comboboxex control, so create a phoney item with an blank name.
// The control is disabled, so the user can't select the item.
ComboItem.mask = CBEIF_TEXT; ComboItem.pszText = _T(""); ComboItem.iItem = 0; m_SnapComboBox.InsertItem(&ComboItem); m_SnapComboBox.SetCurSel(0);
m_pCurSnapInfo = NULL; m_SnapComboBox.EnableWindow(FALSE); }
::EnableWindow(GetDlgItem(IDC_SNAPIN_LABEL), (iCount > 0));
BuildExtensionList(m_pCurSnapInfo);
// reset update flag
m_bUpdateSnapinList = FALSE; }
//----------------------------------------------------------------------------
// CSnapinExtensionPage::BuildExtensionList
//
// Load list control with available extensions for a snapin.
//----------------------------------------------------------------------------
void CSnapinExtensionPage::BuildExtensionList(PSNAPININFO pSnapInfo) { // Clear the list
m_ExtListCtrl.DeleteAllItems();
if (pSnapInfo != NULL) { LV_ITEM LVItem; LVItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE | LVIF_STATE; LVItem.stateMask = LVIS_STATEIMAGEMASK; LVItem.iItem = 0; LVItem.iSubItem = 0;
CStr strNotInst;
// Do for all extensions
PEXTENSIONLINK pExt = pSnapInfo->GetExtensions(); while (pExt != NULL) { PSNAPININFO pExtInfo = pExt->GetSnapinInfo();
// if permitted by policy
if (pExtInfo->IsPermittedByPolicy()) { LVItem.lParam = reinterpret_cast<LPARAM>(pExt); pExtInfo->LoadImages(m_pManager->m_iml); LVItem.iImage = pExtInfo->GetImage();
USES_CONVERSION; CStr strName = OLE2T(pExtInfo->GetSnapinName());
if (!pExtInfo->IsInstalled()) { if (strNotInst.IsEmpty()) strNotInst.LoadString(GetStringModule(), IDS_NOT_INSTALLED);
strName += _T(" "); strName += strNotInst; }
LVItem.pszText = const_cast<LPTSTR>((LPCTSTR)strName);
// Due to a bug in the ListView code, the checkbox state must be off
// for insertions to prevent an OFF transition notification
LVItem.state = CCheckList::CHECKOFF_STATE;
int iIndex = m_ExtListCtrl.InsertItem(&LVItem); ASSERT (iIndex != -1);
if (iIndex >= 0) { // Set checkbox if extension is ON
if (pExt->GetState() == CExtensionLink::EXTEN_ON) { // Disable checkbox if it is required by snap-in
// or is not installed or all extensiosn are enabled
m_ExtListCtrl.SetItemCheck(iIndex, TRUE, !( pExt->IsRequired() || !pExtInfo->IsInstalled() || pSnapInfo->AreAllExtensionsEnabled()) ); } else { // if extension is not installed, then disable it
if (!pExtInfo->IsInstalled()) m_ExtListCtrl.SetItemCheck(iIndex, FALSE, FALSE); }
LVItem.iItem++; } }
pExt = pExt->Next(); }
// Set focus to the first item
m_ExtListCtrl.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
// Provide name of current snapin to Visual Test (it can't get it from a ComboBoxEx)
USES_CONVERSION; ::SetWindowText( GetDlgItem(IDC_VTHELPER), OLE2CT(pSnapInfo->GetSnapinName()) ); }
// Set state of "Enable All" checkbox for this snap-in
BOOL bState = pSnapInfo && pSnapInfo->AreAllExtensionsEnabled(); ::SendMessage(GetDlgItem(IDC_SNAPIN_ENABLEALL), BM_SETCHECK, (WPARAM)bState, 0);
// Enable "Enable All" checkbox if it isn't controled by the snap-in
BOOL bEnable = pSnapInfo && !(pSnapInfo->GetSnapIn() && pSnapInfo->GetSnapIn()->DoesSnapInEnableAll()); ::EnableWindow(GetDlgItem(IDC_SNAPIN_ENABLEALL), bEnable);
// Enable window if extendable snapin selected
bEnable = pSnapInfo && pSnapInfo->GetExtensions();
m_ExtListCtrl.EnableWindow(bEnable); ::EnableWindow(GetDlgItem(IDC_EXTENSION_LABEL), bEnable); ::EnableWindow(GetDlgItem(IDC_SNAPIN_DESCR_LABEL), bEnable); ::EnableWindow(GetDlgItem(IDC_SNAPIN_DESCR), bEnable);
// disable "About" and "Download" until extension is selected
EnableButton(m_hWnd, IDC_SNAPIN_ABOUT, FALSE); EnableButton(m_hWnd, IDC_SNAPIN_DOWNLOAD, FALSE);
// Clear the description text
SC sc = ScSetDescriptionUIText(GetDlgItem(IDC_SNAPIN_DESCR), _T("")); if (sc) sc.TraceAndClear(); }
//----------------------------------------------------------------------------
// CSnapinExtensionPage::OnEnableAllChange
//
// Handle change to "enable all extensions" checkbox
//----------------------------------------------------------------------------
LRESULT CSnapinExtensionPage::OnEnableAllChanged( WORD wNotifyCode, WORD wID, HWND hWndCtrl, BOOL& bHandled ) { if (m_pCurSnapInfo) { m_pCurSnapInfo->SetEnableAllExtensions(!m_pCurSnapInfo->AreAllExtensionsEnabled());
// if enabling all extensions, turn on all installed extensions
if (m_pCurSnapInfo->AreAllExtensionsEnabled()) { PEXTENSIONLINK pExt = m_pCurSnapInfo->GetExtensions(); while (pExt != NULL) { if (pExt->GetSnapinInfo()->IsInstalled()) pExt->SetState(CExtensionLink::EXTEN_ON);
pExt = pExt->Next(); } }
BuildExtensionList(m_pCurSnapInfo); }
return 0; }
//----------------------------------------------------------------------------
// CSnapinExtensionPage::OnExtensionChange
//
// Handle change to extension item
//----------------------------------------------------------------------------
LRESULT CSnapinExtensionPage::OnExtensionChanged( int idCtrl, LPNMHDR pnmh, BOOL& bHandled ) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pnmh; PEXTENSIONLINK pExt = (PEXTENSIONLINK)pNMListView->lParam; ASSERT(pExt != NULL);
// if selection state change
if ( (pNMListView->uOldState ^ pNMListView->uNewState) & LVIS_SELECTED) { LPOLESTR lpsz = NULL;
// if selected
if (pNMListView->uNewState & LVIS_SELECTED) { // Get description text if any
if (pExt->GetSnapinInfo()) { pExt->GetSnapinInfo()->LoadAboutInfo(); lpsz = pExt->GetSnapinInfo()->GetDescription(); }
// Save current selection
m_pExtLink = pExt; } else { m_pExtLink = NULL; }
// Update description field
USES_CONVERSION; SC sc = ScSetDescriptionUIText(GetDlgItem(IDC_SNAPIN_DESCR), lpsz ? OLE2T(lpsz) : _T("")); if (sc) sc.TraceAndClear(); }
// if image state change
if ((pNMListView->uOldState ^ pNMListView->uNewState) & LVIS_STATEIMAGEMASK) { // Set extension state based on check state
if ((pNMListView->uNewState & LVIS_STATEIMAGEMASK) == CCheckList::CHECKON_STATE) { pExt->SetState(CExtensionLink::EXTEN_ON); } else if ((pNMListView->uNewState & LVIS_STATEIMAGEMASK) == CCheckList::CHECKOFF_STATE) { pExt->SetState(CExtensionLink::EXTEN_OFF); }
// Trigger rebuild of extendable snapins
m_bUpdateSnapinList = TRUE; }
// Enable/disable About button
EnableButton(m_hWnd, IDC_SNAPIN_ABOUT, (m_pExtLink && m_pExtLink->GetSnapinInfo()->HasAbout()));
// Enable/disable Download button
EnableButton(m_hWnd, IDC_SNAPIN_DOWNLOAD, (m_pExtLink && !m_pExtLink->GetSnapinInfo()->IsInstalled()));
return 0; }
//############################################################################
//############################################################################
//
// Implementation of class CSnapinManagerAdd
//
//############################################################################
//############################################################################
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapinManagerAdd);
//----------------------------------------------------------------------------
// CSnapinManagerAdd::CSnapinManagerAdd
//
// Constructor
//----------------------------------------------------------------------------
CSnapinManagerAdd::CSnapinManagerAdd(CSnapinManager* pManager, CSnapinStandAlonePage* pStandAlonePage) { ASSERT(pManager != NULL);
m_pListCtrl = NULL; m_pManager = pManager; m_pStandAlonePage = pStandAlonePage;
m_pInfoSelected = NULL; m_bDoOnce = TRUE;
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapinManagerAdd); }
//----------------------------------------------------------------------------
// CSnapinManagerAdd::CSnapinManagerAdd
//
// Destructor
//----------------------------------------------------------------------------
CSnapinManagerAdd::~CSnapinManagerAdd() { delete m_pListCtrl;
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapinManagerAdd); }
//----------------------------------------------------------------------------
// CSnapinManagerAdd::OnInitDialog
//
// Initialize the listview control. Load it with the available snapins.
//----------------------------------------------------------------------------
LRESULT CSnapinManagerAdd::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // Move the dialog a single pixel. This disables the default centering
// so that the coordinates specified in the dialog resource are used.
RECT rc; GetWindowRect(&rc); ::OffsetRect(&rc, 1, 1); MoveWindow(&rc);
InitCommonControls();
m_pListCtrl = new WTL::CListViewCtrl; ASSERT(m_pListCtrl != NULL); // check the pointer before using it
// prefix bug #294766 ntbug9 6/27/01
if ( m_pListCtrl == NULL ) { // get out as quickly as you can
EndDialog(IDCANCEL); return TRUE; }
// Attach list control to member object
m_pListCtrl->Attach( ::GetDlgItem( m_hWnd, IDC_SNAPIN_LV ) );
// Attach shared imagelist to it
m_pListCtrl->SetImageList( m_pManager->m_iml, LVSIL_SMALL );
// Setup Snap-in and Vendor columns
m_pListCtrl->GetClientRect(&rc);
// Adjust width if there will be a vertical scrollbar
if (m_pListCtrl->GetCountPerPage() < m_pManager->m_SnapinInfoCache.GetCount()) rc.right -= GetSystemMetrics(SM_CXVSCROLL);
LV_COLUMN lvc; lvc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
CStr temp; temp.LoadString(GetStringModule(), IDS_SNAPINSTR); lvc.pszText = const_cast<LPTSTR>((LPCTSTR)temp);
lvc.cx = (rc.right*3)/5; lvc.iSubItem = 0;
int iCol = m_pListCtrl->InsertColumn(0, &lvc); ASSERT(iCol == 0);
temp.LoadString(GetStringModule(), IDS_VENDOR); lvc.pszText = const_cast<LPTSTR>((LPCTSTR)temp);
lvc.cx = rc.right - lvc.cx; lvc.iSubItem = 1;
iCol = m_pListCtrl->InsertColumn(1, &lvc); ASSERT(iCol == 1);
m_iGetInfoIndex = -1;
// Load snapin items
BuildSnapinList();
// Turn off the scroll bar in description edit box.
::ShowScrollBar(GetDlgItem(IDC_SNAPIN_DESCR), SB_VERT, FALSE);
return TRUE; }
//----------------------------------------------------------------------------
// CSnapinManagerAdd::BuildSnapinList
//
// Add item to listview for each standalone snapin in the snapin info cache.
//----------------------------------------------------------------------------
void CSnapinManagerAdd::BuildSnapinList() { USES_CONVERSION; CSnapinInfoCache* pCache = &m_pManager->m_SnapinInfoCache;
LV_ITEM LVItem; LVItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE; LVItem.iItem = 0; LVItem.iSubItem = 0;
POSITION pos = pCache->GetStartPosition(); while (pos != NULL) { GUID clsid; PSNAPININFO pSnapInfo;
pCache->GetNextAssoc(pos, clsid, pSnapInfo); ASSERT(pSnapInfo != NULL);
if (pSnapInfo->IsStandAlone() && pSnapInfo->IsPermittedByPolicy()) { // Set image to callback to defer costly image access from ISnapinHelp object.
LVItem.iImage = I_IMAGECALLBACK ; LVItem.pszText = OLE2T( pSnapInfo->GetSnapinName() ); LVItem.lParam = reinterpret_cast<LPARAM>(pSnapInfo);
int iIndex = m_pListCtrl->InsertItem(&LVItem); ASSERT(iIndex != -1);
LVItem.iItem++; } }
// LV_Item for setting vendor column
LV_ITEM LVItem2; LVItem2.mask = LVIF_TEXT; LVItem2.iSubItem = 1; LVItem2.pszText = _T("");
// select the first item
LVItem.mask = LVIF_STATE; LVItem.state = LVIS_SELECTED|LVIS_FOCUSED; LVItem.stateMask = LVIS_SELECTED|LVIS_FOCUSED; LVItem.iItem = 0; m_pListCtrl->SetItem(&LVItem);
// Post a NULL completion msg to kick off info collection
PostMessage(MSG_LOADABOUT_COMPLETE, 0, 0); }
//--------------------------------------------------------------------------
// CSnapinManagerAdd::OnShowWindow
//
// First time dialog is shown, position it offset from its parent
//--------------------------------------------------------------------------
LRESULT CSnapinManagerAdd::OnShowWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { BOOL bShow = (BOOL) wParam; int nStatus = (int) lParam;
::ShowWindow(m_hWnd, bShow);
// Repos window below of Snapin Manager window
if (bShow == TRUE && m_bDoOnce == FALSE) { RECT rc; GetWindowRect(&rc); ::SetWindowPos(m_hWnd, HWND_TOP, rc.left+14, rc.top+21, 0, 0, SWP_NOSIZE|SWP_NOZORDER); m_bDoOnce=FALSE; }
return TRUE; }
//--------------------------------------------------------------------------
// CSnapinManagerAdd::OnGetDispInfo
//
// Handle deferred loading of item image and vendor information
//--------------------------------------------------------------------------
LRESULT CSnapinManagerAdd::OnGetDispInfo(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled) { DECLARE_SC(sc, TEXT("CSnapinManagerAdd::OnGetDispInfo")); sc = ScCheckPointers(pNMHDR); if(sc) return 0;
NMLVDISPINFO* pNMDispInfo = (NMLVDISPINFO*)pNMHDR;
PSNAPININFO pSnapInfo = reinterpret_cast<PSNAPININFO>(pNMDispInfo->item.lParam);
sc = ScCheckPointers(pSnapInfo); if(sc) return 0;
switch (pNMDispInfo->item.iSubItem) { case 0: // Should only request image for primary item
ASSERT(pNMDispInfo->item.mask == LVIF_IMAGE);
// if don't have images yet
if (pSnapInfo->GetImage() == -1) { // if snapin supports about
if (pSnapInfo->HasAbout()) { // use folder for now, background thread will get the image
pNMDispInfo->item.iImage = eStockImage_Folder; } else { // Load images now (will get from MSI database)
pSnapInfo->LoadImages(m_pManager->m_iml); pNMDispInfo->item.iImage = pSnapInfo->GetImage(); } } else { pNMDispInfo->item.iImage = pSnapInfo->GetImage(); } break;
case 1: { // Should only request text for sub item
ASSERT(pNMDispInfo->item.mask == LVIF_TEXT); ASSERT(pNMDispInfo->item.pszText != NULL);
USES_CONVERSION;
if (pSnapInfo->IsInstalled()) { if (pSnapInfo->GetCompanyName() != NULL) { sc = StringCchCopy(pNMDispInfo->item.pszText, pNMDispInfo->item.cchTextMax, OLE2T(pSnapInfo->GetCompanyName())); if(sc) return 0; } else { pNMDispInfo->item.pszText[0] = 0; } } else { // if snap-in is not installed, display "Not Installed in vendor column
if (m_strNotInstalled.IsEmpty()) m_strNotInstalled.LoadString(GetStringModule(), IDS_NOT_INSTALLED2);
sc = StringCchCopy(pNMDispInfo->item.pszText, pNMDispInfo->item.cchTextMax, m_strNotInstalled); if(sc) return 0;
} break; }
default: ASSERT(FALSE); return 0; }
bHandled = TRUE;
return 0; }
LRESULT CSnapinManagerAdd::OnLoadAboutComplete(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { // If real request just completed, do completion processing
if (wParam != 0) { PSNAPININFO pSnapInfo = reinterpret_cast<PSNAPININFO>(wParam);
// If About object exists but didn't provide a ISnapinAbout interface
// it probably didn't register a threading model so can't be created on
// a secondary thread. Give it another try on the main thread.
if (pSnapInfo->GetObjectStatus() == E_NOINTERFACE) { // Reset error state first or LoadAboutInfo() won't try again
pSnapInfo->ResetAboutInfo(); pSnapInfo->LoadAboutInfo(); }
// Locate snapin item in list
LV_FINDINFO find; find.flags = LVFI_PARAM; find.lParam = wParam;
int iIndex = m_pListCtrl->FindItem(&find, -1); ASSERT(iIndex >= 0);
// Force update of list item
pSnapInfo->LoadImages(m_pManager->m_iml); m_pListCtrl->Update(iIndex);
// If item is currently selected
if (pSnapInfo == m_pInfoSelected) { // Update the description field
USES_CONVERSION; LPOLESTR lpsz = m_pInfoSelected->GetDescription();
SC sc = ScSetDescriptionUIText(::GetDlgItem(m_hWnd, IDC_SNAPIN_DESCR), lpsz ? OLE2T(lpsz) : _T("")); if (sc) sc.TraceAndClear(); } }
PSNAPININFO pInfoNext = NULL;
// If selected item doesn't have info, it has first priority
if (m_pInfoSelected != NULL && m_pInfoSelected->HasAbout() && !m_pInfoSelected->HasInformation()) { pInfoNext = m_pInfoSelected; } else { // Else starting with first visible item find snapin that needs info
int iVisible = m_pListCtrl->GetTopIndex(); int iItemMax = min(m_pListCtrl->GetItemCount(), iVisible + m_pListCtrl->GetCountPerPage());
for (int i=0; i<iItemMax; i++) { LPARAM lParam = m_pListCtrl->GetItemData(i); PSNAPININFO pSnapInfo = reinterpret_cast<PSNAPININFO>(lParam);
if (pSnapInfo->HasAbout() && !pSnapInfo->HasInformation()) { pInfoNext = pSnapInfo; break; } } }
// If all visible items handled, continue through the full list
if (pInfoNext == NULL) { // Locate next snap-in
int iCnt = m_pListCtrl->GetItemCount(); while (++m_iGetInfoIndex < iCnt) { LPARAM lParam = m_pListCtrl->GetItemData(m_iGetInfoIndex); PSNAPININFO pSnapInfo = reinterpret_cast<PSNAPININFO>(lParam);
if (pSnapInfo->HasAbout() && !pSnapInfo->HasInformation()) { pInfoNext = pSnapInfo; break; } } }
// if item found, post the info request
if (pInfoNext != NULL) m_pManager->m_AboutInfoThread.PostRequest(pInfoNext, m_hWnd);
bHandled = TRUE; return 0; }
//--------------------------------------------------------------------------
// CSnapinManagerAdd::OnItemChanged
//
// Handle selection of listview item. Display description text for item.
//--------------------------------------------------------------------------
LRESULT CSnapinManagerAdd::OnItemChanged(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; LPOLESTR lpsz = NULL;
// if select change
if ((pNMListView->uOldState ^ pNMListView->uNewState) & LVIS_SELECTED) { if (pNMListView->uNewState & LVIS_SELECTED) {
m_pInfoSelected = reinterpret_cast<PSNAPININFO>(pNMListView->lParam);
// get description text from snapin info
if (m_pInfoSelected->HasInformation() || !m_pInfoSelected->HasAbout()) lpsz = m_pInfoSelected->GetDescription(); } else { m_pInfoSelected = NULL; }
// display description
USES_CONVERSION; SC sc = ScSetDescriptionUIText(::GetDlgItem(m_hWnd, IDC_SNAPIN_DESCR), lpsz ? OLE2T(lpsz) : _T("")); if (sc) sc.TraceAndClear(); }
return TRUE; }
//--------------------------------------------------------------------------
// CSnapinManagerAdd::OnListDblClick
//
// Handle double click in listview. If item selected, do OK processing.
//--------------------------------------------------------------------------
LRESULT CSnapinManagerAdd::OnListDblClick(int idCtrl, LPNMHDR pNMHDR, BOOL& bHandled) {
// Get mouse position in screen co-ord
POINT pt; DWORD dwPos=GetMessagePos(); pt.x=LOWORD(dwPos); pt.y=HIWORD(dwPos);
// Find position in result control
m_pListCtrl->ScreenToClient(&pt);
// Check for tree object hit
UINT fHit; int iItem = m_pListCtrl->HitTest(pt, &fHit);
if (iItem!=-1) { HRESULT hr = m_pStandAlonePage->AddOneSnapin(m_pInfoSelected); }
return TRUE; }
LRESULT CSnapinManagerAdd::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { WORD wID = LOWORD(wParam);
switch (wID) { case IDOK: m_pStandAlonePage->AddOneSnapin(m_pInfoSelected); break;
case IDCANCEL: EndDialog(wID); break;
default: bHandled=FALSE; }
return TRUE; }
LRESULT CSnapinManagerAdd::OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (wParam == SC_CLOSE) EndDialog(IDCANCEL); else bHandled=FALSE;
return TRUE; }
//--------------------------------------------------------------------------
// EnableButton
//
// Enables or disables a dialog control. If the control has the focus when
// it is disabled, the focus is moved to the next control
//--------------------------------------------------------------------------
void EnableButton(HWND hwndDialog, int iCtrlID, BOOL bEnable) { HWND hWndCtrl = ::GetDlgItem(hwndDialog, iCtrlID); ASSERT(::IsWindow(hWndCtrl));
if (!bEnable && ::GetFocus() == hWndCtrl) { HWND hWndNextCtrl = ::GetNextDlgTabItem(hwndDialog, hWndCtrl, FALSE); if (hWndNextCtrl != NULL && hWndNextCtrl != hWndCtrl) { ::SetFocus(hWndNextCtrl); } }
::EnableWindow(hWndCtrl, bEnable); }
|