mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4245 lines
125 KiB
4245 lines
125 KiB
// 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 ];
|
|
::LoadString( GetStringModule(), ID_SNP_MANAGER_TITLE, titleBuffer, sizeof(titleBuffer) / sizeof(TCHAR) );
|
|
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))
|
|
// if ( 0 == _wcsicmp(szSnapinNameOrCLSIDOrProgID, pTempSnapInfo->GetSnapinName()) )
|
|
{
|
|
*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 = MAX_PATH;
|
|
|
|
// 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];
|
|
_stprintf(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)
|
|
{
|
|
NMLVDISPINFO* pNMDispInfo = (NMLVDISPINFO*)pNMHDR;
|
|
|
|
PSNAPININFO pSnapInfo = reinterpret_cast<PSNAPININFO>(pNMDispInfo->item.lParam);
|
|
|
|
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)
|
|
{
|
|
lstrcpyn(pNMDispInfo->item.pszText, OLE2T(pSnapInfo->GetCompanyName()), pNMDispInfo->item.cchTextMax);
|
|
}
|
|
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);
|
|
|
|
lstrcpyn(pNMDispInfo->item.pszText, m_strNotInstalled, pNMDispInfo->item.cchTextMax);
|
|
|
|
}
|
|
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);
|
|
}
|
|
|
|
|
|
|