2320 lines
70 KiB
C++
2320 lines
70 KiB
C++
// This is a part of the Microsoft Management Console.
|
|
// Copyright (C) 1995-1996 Microsoft Corporation
|
|
// All rights reserved.
|
|
//
|
|
// This source code is only intended as a supplement to the
|
|
// Microsoft Management Console and related
|
|
// electronic documentation provided with the interfaces.
|
|
|
|
|
|
#include "precomp.hxx"
|
|
|
|
#include "process.h"
|
|
|
|
#include <atlimpl.cpp>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
LRESULT SetPropPageToDeleteOnClose(void * vpsp);
|
|
|
|
HRESULT UpdateClassStore(
|
|
IClassAdmin * pIClassAdmin,
|
|
char * szFilePath,
|
|
char * szAuxPath,
|
|
char * szPackageName,
|
|
DWORD cchPackageName,
|
|
DWORD dwFlags,
|
|
HWND hwnd);
|
|
|
|
long CSnapin::lDataObjectRefCount = 0;
|
|
|
|
// Internal private format
|
|
const wchar_t* SNAPIN_INTERNAL = L"APPMGR_INTERNAL";
|
|
|
|
#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
|
|
|
|
// Utility function to delete an registry key and all of it's children
|
|
LONG RegDeleteTree(HKEY hKey, LPCTSTR lpSubKey)
|
|
{
|
|
HKEY hKeyNew;
|
|
LONG lResult = RegOpenKey(hKey, lpSubKey, &hKeyNew);
|
|
if (lResult != ERROR_SUCCESS)
|
|
{
|
|
return lResult;
|
|
}
|
|
TCHAR szName[256];
|
|
while (ERROR_SUCCESS == RegEnumKey(hKeyNew, 0, szName, 256))
|
|
{
|
|
RegDeleteTree(hKeyNew, szName);
|
|
}
|
|
RegCloseKey(hKeyNew);
|
|
return RegDeleteKey(hKey, lpSubKey);
|
|
}
|
|
|
|
|
|
INTERNAL* ExtractInternalFormat(LPDATAOBJECT lpDataObject)
|
|
{
|
|
INTERNAL* internal = NULL;
|
|
|
|
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
|
|
FORMATETC formatetc = { CDataObject::m_cfInternal, NULL,
|
|
DVASPECT_CONTENT, -1, TYMED_HGLOBAL
|
|
};
|
|
|
|
if (!lpDataObject)
|
|
return NULL;
|
|
|
|
|
|
// Allocate memory for the stream
|
|
stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(INTERNAL));
|
|
|
|
// Attempt to get data from the object
|
|
do
|
|
{
|
|
if (stgmedium.hGlobal == NULL)
|
|
break;
|
|
|
|
if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium)))
|
|
break;
|
|
|
|
internal = reinterpret_cast<INTERNAL*>(stgmedium.hGlobal);
|
|
|
|
if (internal == NULL)
|
|
break;
|
|
|
|
} while (FALSE);
|
|
|
|
return internal;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Return TRUE if we are enumerating our main folder
|
|
|
|
BOOL CSnapin::IsEnumerating(LPDATAOBJECT lpDataObject)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
|
|
STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
|
|
FORMATETC formatetc = { CDataObject::m_cfNodeType, NULL,
|
|
DVASPECT_CONTENT, -1, TYMED_HGLOBAL
|
|
};
|
|
|
|
// Allocate memory for the stream
|
|
stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(GUID));
|
|
|
|
// Attempt to get data from the object
|
|
do
|
|
{
|
|
if (stgmedium.hGlobal == NULL)
|
|
break;
|
|
|
|
if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium)))
|
|
break;
|
|
|
|
GUID* nodeType = reinterpret_cast<GUID*>(stgmedium.hGlobal);
|
|
|
|
if (nodeType == NULL)
|
|
break;
|
|
|
|
// Is this my main node (static folder node type)
|
|
if (*nodeType == cNodeType)
|
|
bResult = TRUE;
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
// Free resources
|
|
if (stgmedium.hGlobal != NULL)
|
|
GlobalFree(stgmedium.hGlobal);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSnapin's IComponent implementation
|
|
|
|
STDMETHODIMP CSnapin::GetResultViewType(long cookie, BSTR* ppViewType, LONG * pViewOptions)
|
|
{
|
|
// Use default view
|
|
return S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::Initialize(LPCONSOLE lpConsole)
|
|
{
|
|
ASSERT(lpConsole != NULL);
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// Save the IConsole pointer
|
|
m_pConsole = lpConsole;
|
|
m_pConsole->AddRef();
|
|
|
|
// Load resource strings
|
|
LoadResources();
|
|
|
|
// QI for a IHeaderCtrl
|
|
HRESULT hr = m_pConsole->QueryInterface(IID_IHeaderCtrl,
|
|
reinterpret_cast<void**>(&m_pHeader));
|
|
|
|
hr = m_pConsole->QueryInterface(IID_IPropertySheetProvider,
|
|
(void **)&m_pIPropertySheetProvider);
|
|
|
|
// Give the console the header control interface pointer
|
|
if (SUCCEEDED(hr))
|
|
m_pConsole->SetHeader(m_pHeader);
|
|
|
|
m_pConsole->QueryInterface(IID_IResultData,
|
|
reinterpret_cast<void**>(&m_pResult));
|
|
|
|
hr = m_pConsole->QueryResultImageList(&m_pImageResult);
|
|
ASSERT(hr == S_OK);
|
|
|
|
hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
|
|
ASSERT(hr == S_OK);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, long arg, long param)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
long cookie;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
|
|
if (event == MMCN_PROPERTY_CHANGE)
|
|
{
|
|
hr = OnPropertyChange(param);
|
|
}
|
|
else if (event == MMCN_VIEW_CHANGE)
|
|
{
|
|
hr = OnUpdateView(lpDataObject);
|
|
}
|
|
else
|
|
{
|
|
INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);
|
|
|
|
if (pInternal == NULL)
|
|
{
|
|
cookie = 0;
|
|
}
|
|
else
|
|
{
|
|
cookie = pInternal->m_cookie;
|
|
}
|
|
|
|
|
|
switch(event)
|
|
{
|
|
case MMCN_ACTIVATE:
|
|
hr = OnActivate(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_CLICK:
|
|
hr = OnResultItemClkOrDblClk(cookie, FALSE);
|
|
break;
|
|
|
|
case MMCN_DBLCLICK:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
hr = OnResultItemClkOrDblClk(cookie, TRUE);
|
|
else
|
|
hr = S_FALSE;
|
|
break;
|
|
|
|
case MMCN_ADD_IMAGES:
|
|
hr = OnAddImages(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_SHOW:
|
|
hr = OnShow(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_MINIMIZED:
|
|
hr = OnMinimize(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_SELECT:
|
|
hr = OnSelect(pInternal->m_type, cookie, arg, param);
|
|
break;
|
|
|
|
// Note - Future expansion of notify types possible
|
|
default:
|
|
ASSERT(FALSE); // Handle new messages
|
|
hr = E_UNEXPECTED;
|
|
break;
|
|
}
|
|
|
|
FREE_INTERNAL(pInternal);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::Destroy(long cookie)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// Release the interfaces that we QI'ed
|
|
if (m_pConsole != NULL)
|
|
{
|
|
// Tell the console to release the header control interface
|
|
m_pConsole->SetHeader(NULL);
|
|
SAFE_RELEASE(m_pHeader);
|
|
|
|
SAFE_RELEASE(m_pResult);
|
|
SAFE_RELEASE(m_pImageResult);
|
|
SAFE_RELEASE(m_pConsoleVerb);
|
|
|
|
// Release the IConsole interface last
|
|
SAFE_RELEASE(m_pConsole);
|
|
if (m_pComponentData)
|
|
{
|
|
((IComponentData*)m_pComponentData)->Release(); // QI'ed in IComponentDataImpl::CreateComponent
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::QueryDataObject(long cookie, DATA_OBJECT_TYPES type,
|
|
LPDATAOBJECT* ppDataObject)
|
|
{
|
|
// Delegate it to the IComponentData
|
|
ASSERT(m_pComponentData != NULL);
|
|
return m_pComponentData->QueryDataObject(cookie, type, ppDataObject);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSnapin's implementation specific members
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CSnapin);
|
|
|
|
CSnapin::CSnapin()
|
|
{
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CSnapin);
|
|
CSnapin::lDataObjectRefCount = 0;
|
|
m_lViewMode = LVS_REPORT;
|
|
Construct();
|
|
}
|
|
|
|
CSnapin::~CSnapin()
|
|
{
|
|
#if DBG
|
|
ASSERT(dbg_cRef == 0);
|
|
#endif
|
|
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapin);
|
|
|
|
// Make sure the interfaces have been released
|
|
ASSERT(m_pConsole == NULL);
|
|
ASSERT(m_pHeader == NULL);
|
|
|
|
Construct();
|
|
|
|
ASSERT(CSnapin::lDataObjectRefCount == 0);
|
|
}
|
|
|
|
void CSnapin::Construct()
|
|
{
|
|
#if DBG
|
|
dbg_cRef = 0;
|
|
#endif
|
|
|
|
m_pConsole = NULL;
|
|
m_pHeader = NULL;
|
|
|
|
m_pResult = NULL;
|
|
m_pImageResult = NULL;
|
|
m_pComponentData = NULL;
|
|
}
|
|
|
|
CString szExtension;
|
|
CString szFilter;
|
|
|
|
void CSnapin::LoadResources()
|
|
{
|
|
// Load strings from resources
|
|
|
|
m_column1.LoadString(IDS_NAME);
|
|
m_column2.LoadString(IDS_VERSION);
|
|
m_column3.LoadString(IDS_STAGE);
|
|
m_column4.LoadString(IDS_RELATION);
|
|
m_column5.LoadString(IDS_STATE);
|
|
m_column6.LoadString(IDS_AUTOINST);
|
|
m_column7.LoadString(IDS_LOC);
|
|
m_column8.LoadString(IDS_MACH);
|
|
m_column9.LoadString(IDS_SOURCE);
|
|
m_column10.LoadString(IDS_MODS);
|
|
m_column11.LoadString(IDS_PUB);
|
|
szExtension.LoadString(IDS_DEF_EXTENSION);
|
|
szFilter.LoadString(IDS_EXTENSION_FILTER);
|
|
m_szFolderTitle.LoadString(IDS_FOLDER_TITLE);
|
|
}
|
|
|
|
HRESULT CSnapin::InitializeHeaders(long cookie)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ASSERT(m_pHeader);
|
|
|
|
// Put the correct headers depending on the cookie
|
|
// Note - cookie ignored for this sample
|
|
m_pHeader->InsertColumn(0, m_column1, LVCFMT_LEFT, 150); // name
|
|
m_pHeader->InsertColumn(1, m_column2, LVCFMT_LEFT, 50); // version
|
|
m_pHeader->InsertColumn(2, m_column3, LVCFMT_LEFT, 85); // stage
|
|
m_pHeader->InsertColumn(3, m_column4, LVCFMT_LEFT, 125); // relation
|
|
m_pHeader->InsertColumn(4, m_column5, LVCFMT_LEFT, 100); // state
|
|
m_pHeader->InsertColumn(5, m_column6, LVCFMT_LEFT, 75); // auto-inst
|
|
m_pHeader->InsertColumn(6, m_column7, LVCFMT_LEFT, 75); // loc
|
|
m_pHeader->InsertColumn(7, m_column8, LVCFMT_LEFT, 75); // mach
|
|
m_pHeader->InsertColumn(8, m_column9, LVCFMT_LEFT, 150); // source
|
|
m_pHeader->InsertColumn(9, m_column10, LVCFMT_LEFT, 150); // mods
|
|
m_pHeader->InsertColumn(10, m_column11, LVCFMT_LEFT, 150); // pub
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CSnapin::InitializeBitmaps(long cookie)
|
|
{
|
|
ASSERT(m_pImageResult != NULL);
|
|
|
|
CBitmap bmp16x16;
|
|
CBitmap bmp32x32;
|
|
|
|
// Load the bitmaps from the dll
|
|
bmp16x16.LoadBitmap(IDB_16x16);
|
|
bmp32x32.LoadBitmap(IDB_32x32);
|
|
|
|
// Set the images
|
|
m_pImageResult->ImageListSetStrip(reinterpret_cast<long*>(static_cast<HBITMAP>(bmp16x16)),
|
|
reinterpret_cast<long*>(static_cast<HBITMAP>(bmp32x32)),
|
|
0, RGB(255,0,255));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IExtendContextMenu Implementation
|
|
|
|
STDMETHODIMP CSnapin::AddMenuItems(LPDATAOBJECT pDataObject,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback, LONG * pInsertionAllowed)
|
|
{
|
|
return m_pComponentData->
|
|
AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed);
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::Command(long nCommandID, LPDATAOBJECT pDataObject)
|
|
{
|
|
return m_pComponentData->
|
|
Command(nCommandID, pDataObject);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// IComponentData implementation
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CComponentDataImpl);
|
|
|
|
CComponentDataImpl::CComponentDataImpl()
|
|
: m_bIsDirty(TRUE)
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwDisp;
|
|
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentDataImpl);
|
|
|
|
m_pToolDefs = NULL;
|
|
m_pCatList = NULL;
|
|
m_pFileExt = NULL;
|
|
|
|
m_fMachine = FALSE;
|
|
m_pScope = NULL;
|
|
m_pConsole = NULL;
|
|
m_pIClassAdmin = NULL;
|
|
m_fLoaded = FALSE;
|
|
m_fExtension = FALSE;
|
|
m_pIGPEInformation = NULL;
|
|
m_lLastAllocated = 0;
|
|
m_ToolDefaults.NPBehavior = NP_WIZARD;
|
|
m_ToolDefaults.fAutoInstall = FALSE;
|
|
m_ToolDefaults.UILevel = INSTALLUILEVEL_DEFAULT;
|
|
m_ToolDefaults.szStartPath = L""; // UNDONE - need to come up with a
|
|
// good default setting for this
|
|
m_ToolDefaults.iDebugLevel = 0;
|
|
m_ToolDefaults.fShowPkgDetails = 0;
|
|
|
|
//
|
|
// This creates the magic "GPTSupport" key in HKCR so that Darwin
|
|
// generates full link files.
|
|
//
|
|
|
|
if (RegCreateKeyEx (HKEY_CLASSES_ROOT, TEXT("GPTSupport"), 0, NULL,
|
|
REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey,
|
|
&dwDisp) == ERROR_SUCCESS)
|
|
{
|
|
RegCloseKey (hKey);
|
|
}
|
|
}
|
|
|
|
CComponentDataImpl::~CComponentDataImpl()
|
|
{
|
|
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentDataImpl);
|
|
|
|
ASSERT(m_pScope == NULL);
|
|
ASSERT(CSnapin::lDataObjectRefCount == 0);
|
|
}
|
|
#include <msi.h>
|
|
|
|
STDMETHODIMP CComponentDataImpl::Initialize(LPUNKNOWN pUnknown)
|
|
{
|
|
ASSERT(pUnknown != NULL);
|
|
HRESULT hr;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
// MMC should only call ::Initialize once!
|
|
ASSERT(m_pScope == NULL);
|
|
pUnknown->QueryInterface(IID_IConsoleNameSpace,
|
|
reinterpret_cast<void**>(&m_pScope));
|
|
ASSERT(hr == S_OK);
|
|
|
|
hr = pUnknown->QueryInterface(IID_IConsole, reinterpret_cast<void**>(&m_pConsole));
|
|
ASSERT(hr == S_OK);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CSnapin::OnAddImages(long cookie, long arg, long param)
|
|
{
|
|
if (arg == 0)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// add the images for the scope tree
|
|
CBitmap bmp16x16;
|
|
CBitmap bmp32x32;
|
|
LPIMAGELIST lpScopeImage = (LPIMAGELIST)arg;
|
|
|
|
// Load the bitmaps from the dll
|
|
bmp16x16.LoadBitmap(IDB_16x16);
|
|
bmp32x32.LoadBitmap(IDB_32x32);
|
|
|
|
// Set the images
|
|
lpScopeImage->ImageListSetStrip(reinterpret_cast<long*>(static_cast<HBITMAP>(bmp16x16)),
|
|
reinterpret_cast<long*>(static_cast<HBITMAP>(bmp32x32)),
|
|
0, RGB(255,0,255));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::CreateComponent(LPCOMPONENT* ppComponent)
|
|
{
|
|
ASSERT(ppComponent != NULL);
|
|
|
|
CComObject<CSnapin>* pObject;
|
|
CComObject<CSnapin>::CreateInstance(&pObject);
|
|
ASSERT(pObject != NULL);
|
|
|
|
m_pSnapin = pObject;
|
|
|
|
|
|
// Store IComponentData
|
|
pObject->SetIComponentData(this);
|
|
|
|
return pObject->QueryInterface(IID_IComponent,
|
|
reinterpret_cast<void**>(ppComponent));
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, long arg, long param)
|
|
{
|
|
ASSERT(m_pScope != NULL);
|
|
HRESULT hr = S_OK;
|
|
|
|
// Since it's my folder it has an internal format.
|
|
// Design Note: for extension. I can use the fact, that the data object doesn't have
|
|
// my internal format and I should look at the node type and see how to extend it.
|
|
if (event == MMCN_PROPERTY_CHANGE)
|
|
{
|
|
SaveToolDefaults();
|
|
hr = OnProperties(param);
|
|
}
|
|
else
|
|
{
|
|
INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);
|
|
long cookie = 0;
|
|
if (pInternal != NULL)
|
|
{
|
|
cookie = pInternal->m_cookie;
|
|
FREE_INTERNAL(pInternal);
|
|
}
|
|
else
|
|
{
|
|
// only way we could not be able to extract our own format is if we're operating as an extension
|
|
m_fExtension = TRUE;
|
|
}
|
|
|
|
if (m_pIGPEInformation == NULL)
|
|
{
|
|
hr = lpDataObject->QueryInterface(IID_IGPEInformation,
|
|
reinterpret_cast<void**>(&m_pIGPEInformation));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR szBuffer[MAX_PATH];
|
|
do
|
|
{
|
|
hr = m_pIGPEInformation->GetDSPath(m_fMachine ? GPO_SECTION_MACHINE : GPO_SECTION_USER, szBuffer, MAX_PATH);
|
|
if (FAILED(hr))
|
|
{
|
|
break;
|
|
}
|
|
m_szLDAP_Path = szBuffer;
|
|
|
|
hr = GetClassStore();
|
|
|
|
hr = m_pIGPEInformation->GetFileSysPath(m_fMachine ? GPO_SECTION_MACHINE : GPO_SECTION_USER, szBuffer, MAX_PATH);
|
|
if (FAILED(hr)) break;
|
|
m_szGPT_Path = szBuffer;
|
|
|
|
// find the last element in the path
|
|
int iBreak = m_szGPT_Path.ReverseFind(L'{');
|
|
m_szGPT_Path += L"\\Applications";
|
|
// m_szGPTRoot gets everything before the '\\' found above...
|
|
m_szGPTRoot = m_szGPT_Path.Left(iBreak-1);
|
|
// m_szScriptRoot gets everything after the '\\' found above...
|
|
m_szScriptRoot = m_szGPT_Path.Mid(iBreak);
|
|
if (CreateNestedDirectory ((LPOLESTR)((LPCOLESTR)m_szGPT_Path), NULL))
|
|
{
|
|
m_fLoaded = TRUE;
|
|
#if UGLY_SUBDIRECTORY_HACK
|
|
CString sz = m_szGPT_Path;
|
|
sz += L"\\assigned\\x86";
|
|
CreateNestedDirectory((LPOLESTR)((LPCOLESTR)sz), NULL);
|
|
sz = m_szGPT_Path;
|
|
sz += L"\\assigned\\alpha";
|
|
CreateNestedDirectory((LPOLESTR)((LPCOLESTR)sz), NULL);
|
|
#endif
|
|
}
|
|
LoadToolDefaults();
|
|
} while (0);
|
|
}
|
|
}
|
|
|
|
|
|
switch(event)
|
|
{
|
|
case MMCN_DELETE:
|
|
hr = OnDelete(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_RENAME:
|
|
hr = OnRename(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_EXPAND:
|
|
{
|
|
hr = OnExpand(cookie, arg, param);
|
|
}
|
|
break;
|
|
|
|
case MMCN_SELECT:
|
|
hr = OnSelect(cookie, arg, param);
|
|
break;
|
|
|
|
case MMCN_CONTEXTMENU:
|
|
hr = OnContextMenu(cookie, arg, param);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::Destroy()
|
|
{
|
|
// Delete enumerated scope items
|
|
DeleteList();
|
|
|
|
SAFE_RELEASE(m_pScope);
|
|
SAFE_RELEASE(m_pConsole);
|
|
SAFE_RELEASE(m_pIClassAdmin);
|
|
SAFE_RELEASE(m_pIGPEInformation);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::QueryDataObject(long cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject)
|
|
{
|
|
ASSERT(ppDataObject != NULL);
|
|
|
|
CComObject<CDataObject>* pObject;
|
|
|
|
CComObject<CDataObject>::CreateInstance(&pObject);
|
|
ASSERT(pObject != NULL);
|
|
|
|
pObject->m_fMachine = m_fMachine;
|
|
// Save cookie and type for delayed rendering
|
|
pObject->SetType(type);
|
|
pObject->SetCookie(cookie);
|
|
|
|
return pObject->QueryInterface(IID_IDataObject,
|
|
reinterpret_cast<void**>(ppDataObject));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//// IPersistStreamInit interface members
|
|
|
|
STDMETHODIMP CComponentDataImpl::GetClassID(CLSID *pClassID)
|
|
{
|
|
ASSERT(pClassID != NULL);
|
|
|
|
// Copy the CLSID for this snapin
|
|
if (m_fMachine)
|
|
*pClassID = CLSID_MachineSnapin;
|
|
else
|
|
*pClassID = CLSID_Snapin;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::IsDirty()
|
|
{
|
|
// Always save / Always dirty.
|
|
return ThisIsDirty() ? S_OK : S_FALSE;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::Load(IStream *pStm)
|
|
{
|
|
ASSERT(pStm);
|
|
|
|
// Read the string
|
|
TCHAR psz[MAX_PATH]; // BUGBUG - really should be WCHAR to avoid problems in case
|
|
// it's ever compiled for MBCS
|
|
ULONG nBytesRead;
|
|
ULONG cb;
|
|
HRESULT hr = pStm->Read(&cb, sizeof(ULONG), &nBytesRead);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pStm->Read(psz, cb, &nBytesRead);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (cb > MAX_PATH * sizeof(TCHAR))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
m_szLDAP_Path = psz;
|
|
|
|
hr = pStm->Read(&cb, sizeof(ULONG), &nBytesRead);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (cb > MAX_PATH * sizeof(TCHAR))
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
hr = pStm->Read(psz, cb, &nBytesRead);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
m_szGPT_Path = psz;
|
|
// find the last element in the path
|
|
int iBreak = m_szGPT_Path.ReverseFind(L'{');
|
|
// m_szGPTRoot gets everything before the '\\' found above...
|
|
m_szGPTRoot = m_szGPT_Path.Left(iBreak-1);
|
|
// m_szScriptRoot gets everything after the '\\' found above...
|
|
m_szScriptRoot = m_szGPT_Path.Mid(iBreak);
|
|
m_fLoaded = TRUE;
|
|
ClearDirty();
|
|
LoadToolDefaults();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return SUCCEEDED(hr) ? S_OK : E_FAIL;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::Save(IStream *pStm, BOOL fClearDirty)
|
|
{
|
|
ASSERT(pStm);
|
|
|
|
// Write the string
|
|
ULONG nBytesWritten;
|
|
ULONG cb = (m_szLDAP_Path.GetLength() + 1) * sizeof(TCHAR);
|
|
HRESULT hr = pStm->Write(&cb, sizeof(ULONG), &nBytesWritten);
|
|
if (FAILED(hr))
|
|
return STG_E_CANTSAVE;
|
|
hr = pStm->Write(m_szLDAP_Path, cb, &nBytesWritten);
|
|
if (FAILED(hr))
|
|
return STG_E_CANTSAVE;
|
|
|
|
cb = (m_szGPT_Path.GetLength() + 1) * sizeof(TCHAR);
|
|
hr = pStm->Write(&cb, sizeof(ULONG), &nBytesWritten);
|
|
if (FAILED(hr))
|
|
return STG_E_CANTSAVE;
|
|
hr = pStm->Write(m_szGPT_Path, cb, &nBytesWritten);
|
|
|
|
if (FAILED(hr))
|
|
return STG_E_CANTSAVE;
|
|
|
|
if (fClearDirty)
|
|
ClearDirty();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::GetSizeMax(ULARGE_INTEGER *pcbSize)
|
|
{
|
|
ASSERT(pcbSize);
|
|
|
|
ULONG cb = (m_szLDAP_Path.GetLength() + m_szGPT_Path.GetLength() + 2) * sizeof(TCHAR) + 2 * sizeof(ULONG);
|
|
// Set the size of the string to be saved
|
|
ULISet32(*pcbSize, cb);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::InitNew(void)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
void CComponentDataImpl::LoadToolDefaults()
|
|
{
|
|
CString szFileName = m_szGPT_Path;
|
|
szFileName += L"\\";
|
|
szFileName += CFGFILE;
|
|
FILE * f = _wfopen(szFileName, L"rt");
|
|
if (f)
|
|
{
|
|
WCHAR sz[256];
|
|
CString szData;
|
|
CString szKey;
|
|
while (fgetws(sz, 256, f))
|
|
{
|
|
szData = sz;
|
|
szKey = szData.SpanExcluding(L"=");
|
|
szData = szData.Mid(szKey.GetLength()+1);
|
|
szData.TrimRight();
|
|
szData.TrimLeft();
|
|
szKey.TrimRight();
|
|
if (0 == szKey.CompareNoCase(KEY_NPBehavior))
|
|
{
|
|
swscanf(szData, L"%i", &m_ToolDefaults.NPBehavior);
|
|
}
|
|
else if (0 == szKey.CompareNoCase(KEY_fAutoInstall))
|
|
{
|
|
swscanf(szData, L"%i", &m_ToolDefaults.fAutoInstall);
|
|
}
|
|
else if (0 == szKey.CompareNoCase(KEY_UILevel))
|
|
{
|
|
swscanf(szData, L"%i", &m_ToolDefaults.UILevel);
|
|
}
|
|
else if (0 == szKey.CompareNoCase(KEY_szStartPath))
|
|
{
|
|
m_ToolDefaults.szStartPath = szData;
|
|
}
|
|
else if (0 == szKey.CompareNoCase(KEY_iDebugLevel))
|
|
{
|
|
swscanf(szData, L"%i", &m_ToolDefaults.iDebugLevel);
|
|
}
|
|
else if (0 == szKey.CompareNoCase(KEY_fShowPkgDetails))
|
|
{
|
|
swscanf(szData, L"%i", &m_ToolDefaults.fShowPkgDetails);
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
void CComponentDataImpl::SaveToolDefaults()
|
|
{
|
|
CString szFileName = m_szGPT_Path;
|
|
szFileName += L"\\";
|
|
szFileName += CFGFILE;
|
|
FILE * f = _wfopen(szFileName, L"wt");
|
|
if (f)
|
|
{
|
|
fwprintf(f, L"%s=%i\n", KEY_NPBehavior, m_ToolDefaults.NPBehavior);
|
|
fwprintf(f, L"%s=%i\n", KEY_fAutoInstall, m_ToolDefaults.fAutoInstall);
|
|
fwprintf(f, L"%s=%i\n", KEY_UILevel, m_ToolDefaults.UILevel);
|
|
fwprintf(f, L"%s=%s\n", KEY_szStartPath, m_ToolDefaults.szStartPath);
|
|
if (m_ToolDefaults.iDebugLevel > 0)
|
|
{
|
|
fwprintf(f, L"%s=%i\n", KEY_iDebugLevel, m_ToolDefaults.iDebugLevel);
|
|
}
|
|
if (m_ToolDefaults.fShowPkgDetails > 0)
|
|
{
|
|
fwprintf(f, L"%s=%i\n", KEY_fShowPkgDetails, m_ToolDefaults.fShowPkgDetails);
|
|
}
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Member: CComponentDataImpl::GetClassStore
|
|
//
|
|
// Synopsis: gets the IClassAdmin interface and creates a class store if
|
|
// it doesn't already exist.
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// Modifies: m_pIClassAdmin
|
|
//
|
|
// Derivation:
|
|
//
|
|
// History: 2-11-1998 stevebl Created
|
|
//
|
|
// Notes: Assumes m_szLDAP_Path contains the path to the class store
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
HRESULT CComponentDataImpl::GetClassStore(void)
|
|
{
|
|
HRESULT hr;
|
|
IADsPathname * pADsPathname = NULL;
|
|
hr = CoCreateInstance(CLSID_Pathname,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IADsPathname,
|
|
(LPVOID*)&pADsPathname);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
hr = pADsPathname->Set((LPOLESTR)((LPCOLESTR)m_szLDAP_Path), ADS_SETTYPE_FULL);
|
|
if (FAILED(hr))
|
|
{
|
|
pADsPathname->Release();
|
|
return hr;
|
|
}
|
|
|
|
hr = pADsPathname->AddLeafElement(L"CN=Class Store");
|
|
if (FAILED(hr))
|
|
{
|
|
pADsPathname->Release();
|
|
return hr;
|
|
}
|
|
|
|
BSTR bstr;
|
|
|
|
hr = pADsPathname->Retrieve(ADS_FORMAT_X500_NO_SERVER, &bstr);
|
|
|
|
pADsPathname->Release();
|
|
if (FAILED(hr))
|
|
{
|
|
return hr;
|
|
}
|
|
|
|
CString szCSPath = bstr;
|
|
|
|
SysFreeString(bstr);
|
|
|
|
// UNDONE - build class store path
|
|
hr = CsGetClassStore((LPOLESTR)((LPCOLESTR)szCSPath), (LPVOID*)&m_pIClassAdmin);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = CsCreateClassStore((LPOLESTR)((LPCOLESTR)m_szLDAP_Path), L"CN=Class Store");
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CsGetClassStore((LPOLESTR)((LPCOLESTR)szCSPath), (LPVOID*)&m_pIClassAdmin);
|
|
// If this fails then we've really got problems and we'll just
|
|
// have to return the failure.
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
UINT CComponentDataImpl::CreateNestedDirectory (LPTSTR lpDirectory, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
{
|
|
TCHAR szDirectory[MAX_PATH];
|
|
LPTSTR lpEnd;
|
|
|
|
|
|
//
|
|
// Check for NULL pointer
|
|
//
|
|
|
|
if (!lpDirectory || !(*lpDirectory)) {
|
|
SetLastError(ERROR_INVALID_DATA);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//
|
|
// First, see if we can create the directory without having
|
|
// to build parent directories.
|
|
//
|
|
|
|
if (CreateDirectory (lpDirectory, lpSecurityAttributes)) {
|
|
return 1;
|
|
}
|
|
|
|
//
|
|
// If this directory exists already, this is OK too.
|
|
//
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
return ERROR_ALREADY_EXISTS;
|
|
}
|
|
|
|
|
|
//
|
|
// No luck, copy the string to a buffer we can munge
|
|
//
|
|
|
|
lstrcpy (szDirectory, lpDirectory);
|
|
|
|
|
|
//
|
|
// Find the first subdirectory name
|
|
//
|
|
|
|
lpEnd = szDirectory;
|
|
|
|
if (szDirectory[1] == TEXT(':')) {
|
|
lpEnd += 3;
|
|
} else if (szDirectory[1] == TEXT('\\')) {
|
|
|
|
//
|
|
// Skip the first two slashes
|
|
//
|
|
|
|
lpEnd += 2;
|
|
|
|
//
|
|
// Find the slash between the server name and
|
|
// the share name.
|
|
//
|
|
|
|
while (*lpEnd && *lpEnd != TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
if (!(*lpEnd)) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Skip the slash, and find the slash between
|
|
// the share name and the directory name.
|
|
//
|
|
|
|
lpEnd++;
|
|
|
|
while (*lpEnd && *lpEnd != TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
if (!(*lpEnd)) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Leave pointer at the beginning of the directory.
|
|
//
|
|
|
|
lpEnd++;
|
|
|
|
|
|
} else if (szDirectory[0] == TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
while (*lpEnd) {
|
|
|
|
while (*lpEnd && *lpEnd != TEXT('\\')) {
|
|
lpEnd++;
|
|
}
|
|
|
|
if (*lpEnd == TEXT('\\')) {
|
|
*lpEnd = TEXT('\0');
|
|
|
|
if (!CreateDirectory (szDirectory, NULL)) {
|
|
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
*lpEnd = TEXT('\\');
|
|
lpEnd++;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Create the final directory
|
|
//
|
|
|
|
if (CreateDirectory (szDirectory, lpSecurityAttributes)) {
|
|
return 1;
|
|
}
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
|
return ERROR_ALREADY_EXISTS;
|
|
}
|
|
|
|
|
|
//
|
|
// Failed
|
|
//
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//// Notify handlers for IComponentData
|
|
|
|
HRESULT CComponentDataImpl::OnAdd(long cookie, long arg, long param)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
HRESULT CComponentDataImpl::OnDelete(long cookie, long arg, long param)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CComponentDataImpl::OnRename(long cookie, long arg, long param)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CComponentDataImpl::OnExpand(long cookie, long arg, long param)
|
|
{
|
|
if (arg == TRUE)
|
|
{
|
|
// Did Initialize get called?
|
|
ASSERT(m_pScope != NULL);
|
|
|
|
EnumerateScopePane(cookie,
|
|
param);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CComponentDataImpl::OnSelect(long cookie, long arg, long param)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
|
|
HRESULT CComponentDataImpl::OnContextMenu(long cookie, long arg, long param)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CComponentDataImpl::OnProperties(long param)
|
|
{
|
|
if (param == NULL)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
ASSERT(param != NULL);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
void CComponentDataImpl::EnumerateScopePane(long cookie, HSCOPEITEM pParent)
|
|
{
|
|
// We only have one folder so this is really easy.
|
|
if (cookie != NULL)
|
|
return ;
|
|
|
|
if (m_fExtension)
|
|
{
|
|
// if we're an extension then add a root folder to hang everything off of
|
|
SCOPEDATAITEM * m_pScopeItem = new SCOPEDATAITEM;
|
|
memset(m_pScopeItem, 0, sizeof(SCOPEDATAITEM));
|
|
m_pScopeItem->mask = SDI_STR | SDI_PARAM;
|
|
m_pScopeItem->relativeID = pParent;
|
|
m_pScopeItem->displayname = (unsigned short *)-1;
|
|
m_pScopeItem->lParam = -1; // made up cookie for my main folder
|
|
m_pScope->InsertItem(m_pScopeItem);
|
|
}
|
|
}
|
|
|
|
void CComponentDataImpl::DeleteList()
|
|
{
|
|
return;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
ASSERT(pScopeDataItem != NULL);
|
|
if (pScopeDataItem == NULL)
|
|
return E_POINTER;
|
|
|
|
if (pScopeDataItem->lParam == -1)
|
|
{
|
|
m_szFolderTitle.LoadString(IDS_FOLDER_TITLE);
|
|
pScopeDataItem->displayname = (unsigned short *)((LPCOLESTR)m_szFolderTitle);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pScopeDataItem->mask == TVIF_TEXT);
|
|
pScopeDataItem->displayname = (unsigned short *)((LPCOLESTR)m_AppData[pScopeDataItem->lParam].pDetails->pszPackageName);
|
|
}
|
|
|
|
ASSERT(pScopeDataItem->displayname != NULL);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CComponentDataImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
|
|
{
|
|
if (lpDataObjectA == NULL || lpDataObjectB == NULL)
|
|
return E_POINTER;
|
|
|
|
// Make sure both data object are mine
|
|
INTERNAL* pA;
|
|
INTERNAL* pB;
|
|
HRESULT hr = S_FALSE;
|
|
|
|
pA = ExtractInternalFormat(lpDataObjectA);
|
|
pB = ExtractInternalFormat(lpDataObjectB);
|
|
|
|
if (pA != NULL && pB != NULL)
|
|
hr = ((pA->m_type == pB->m_type) && (pA->m_cookie == pB->m_cookie)) ? S_OK : S_FALSE;
|
|
|
|
FREE_INTERNAL(pA);
|
|
FREE_INTERNAL(pB);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IExtendPropertySheet Implementation
|
|
|
|
// Result item property pages:
|
|
STDMETHODIMP CSnapin::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
|
|
long handle,
|
|
LPDATAOBJECT lpIDataObject)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
INTERNAL* pInternal = ExtractInternalFormat(lpIDataObject);
|
|
if (m_pIClassAdmin)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DWORD cookie = pInternal->m_cookie;
|
|
APP_DATA & data = m_pComponentData->m_AppData[cookie];
|
|
FREE_INTERNAL(pInternal);
|
|
|
|
//
|
|
// Create the Product property page
|
|
//
|
|
data.pProduct = new CProduct();
|
|
data.pProduct->m_ppThis = &data.pProduct;
|
|
data.pProduct->m_pData = &data;
|
|
data.pProduct->m_cookie = cookie;
|
|
data.pProduct->m_hConsoleHandle = handle;
|
|
data.pProduct->m_pAppData = &m_pComponentData->m_AppData;
|
|
// marshal the IClassAdmin interface to the page
|
|
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(data.pProduct->m_pIStream));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetPropPageToDeleteOnClose(&data.pProduct->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hProduct = CreatePropertySheetPage(&data.pProduct->m_psp);
|
|
if (hProduct == NULL)
|
|
return E_UNEXPECTED;
|
|
lpProvider->AddPage(hProduct);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the Depeployment property page
|
|
//
|
|
data.pDeploy = new CDeploy();
|
|
data.pDeploy->m_ppThis = &data.pDeploy;
|
|
data.pDeploy->m_pData = &data;
|
|
data.pDeploy->m_cookie = cookie;
|
|
data.pDeploy->m_hConsoleHandle = handle;
|
|
#ifdef UGLY_SUBDIRECTORY_HACK
|
|
data.pDeploy->m_szGPTRoot = m_pComponentData->m_szGPTRoot;
|
|
#endif
|
|
// marshal the IClassAdmin interface to the page
|
|
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(data.pDeploy->m_pIStream));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetPropPageToDeleteOnClose(&data.pDeploy->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hDeploy = CreatePropertySheetPage(&data.pDeploy->m_psp);
|
|
if (hDeploy == NULL)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
lpProvider->AddPage(hDeploy);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the locale property page
|
|
//
|
|
data.pLocPkg = new CLocPkg();
|
|
data.pLocPkg->m_ppThis = &data.pLocPkg;
|
|
data.pLocPkg->m_pData = &data;
|
|
data.pLocPkg->m_cookie = cookie;
|
|
data.pLocPkg->m_hConsoleHandle = handle;
|
|
// marshal the IClassAdmin interface to the page
|
|
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(data.pLocPkg->m_pIStream));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetPropPageToDeleteOnClose(&data.pLocPkg->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hLocPkg = CreatePropertySheetPage(&data.pLocPkg->m_psp);
|
|
if (hLocPkg == NULL)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
lpProvider->AddPage(hLocPkg);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the Category property page
|
|
//
|
|
data.pCategory = new CCategory();
|
|
data.pCategory->m_ppThis = &data.pCategory;
|
|
data.pCategory->m_pData = &data;
|
|
data.pCategory->m_cookie = cookie;
|
|
data.pCategory->m_hConsoleHandle = handle;
|
|
// marshal the IClassAdmin interface to the page
|
|
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(data.pCategory->m_pIStream));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetPropPageToDeleteOnClose(&data.pCategory->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hCategory = CreatePropertySheetPage(&data.pCategory->m_psp);
|
|
if (hCategory == NULL)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
lpProvider->AddPage(hCategory);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create the Xforms property page
|
|
//
|
|
data.pXforms = new CXforms();
|
|
data.pXforms->m_ppThis = &data.pXforms;
|
|
data.pXforms->m_pData = &data;
|
|
data.pXforms->m_cookie = cookie;
|
|
data.pXforms->m_hConsoleHandle = handle;
|
|
// marshal the IClassAdmin interface to the page
|
|
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(data.pXforms->m_pIStream));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetPropPageToDeleteOnClose(&data.pXforms->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hXforms = CreatePropertySheetPage(&data.pXforms->m_psp);
|
|
if (hXforms == NULL)
|
|
{
|
|
return E_UNEXPECTED;
|
|
}
|
|
lpProvider->AddPage(hXforms);
|
|
}
|
|
}
|
|
|
|
if (m_pComponentData->m_ToolDefaults.fShowPkgDetails)
|
|
{
|
|
//
|
|
// Create the Package Details page (debug only)
|
|
//
|
|
data.pPkgDetails = new CPackageDetails();
|
|
data.pPkgDetails->m_ppThis = &data.pPkgDetails;
|
|
data.pPkgDetails->m_hConsoleHandle = handle;
|
|
data.pPkgDetails->m_pData = &data;
|
|
hr = SetPropPageToDeleteOnClose(&data.pPkgDetails->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hDetails = CreatePropertySheetPage(&data.pPkgDetails->m_psp);
|
|
|
|
if (hDetails == NULL)
|
|
return E_UNEXPECTED;
|
|
lpProvider->AddPage(hDetails);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
return S_FALSE;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// Result items property pages:
|
|
STDMETHODIMP CSnapin::QueryPagesFor(LPDATAOBJECT lpDataObject)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
// Look at the data object and see if it an item that we want to have a property sheet
|
|
INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);
|
|
if (CCT_RESULT == pInternal->m_type)
|
|
{
|
|
FREE_INTERNAL(pInternal);
|
|
return S_OK;
|
|
}
|
|
|
|
FREE_INTERNAL(pInternal);
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Scope item property pages:
|
|
STDMETHODIMP CComponentDataImpl::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
|
|
long handle,
|
|
LPDATAOBJECT lpIDataObject)
|
|
{
|
|
HRESULT hr;
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
INTERNAL* pInternal = ExtractInternalFormat(lpIDataObject);
|
|
|
|
DWORD cookie = pInternal->m_cookie;
|
|
FREE_INTERNAL(pInternal);
|
|
|
|
//
|
|
// Create the ToolDefs property page
|
|
//
|
|
m_pToolDefs = new CToolDefs();
|
|
m_pToolDefs->m_ppThis = &m_pToolDefs;
|
|
m_pToolDefs->m_pToolDefaults = & m_ToolDefaults;
|
|
m_pToolDefs->m_cookie = cookie;
|
|
m_pToolDefs->m_hConsoleHandle = handle;
|
|
hr = SetPropPageToDeleteOnClose(&m_pToolDefs->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hToolDefs = CreatePropertySheetPage(&m_pToolDefs->m_psp);
|
|
if (hToolDefs == NULL)
|
|
return E_UNEXPECTED;
|
|
lpProvider->AddPage(hToolDefs);
|
|
}
|
|
|
|
//
|
|
// Create the CatList property page
|
|
//
|
|
m_pCatList = new CCatList();
|
|
m_pCatList->m_ppThis = &m_pCatList;
|
|
hr = SetPropPageToDeleteOnClose(&m_pCatList->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hCatList = CreatePropertySheetPage(&m_pCatList->m_psp);
|
|
if (hCatList == NULL)
|
|
return E_UNEXPECTED;
|
|
lpProvider->AddPage(hCatList);
|
|
}
|
|
|
|
//
|
|
// Create the FileExt property page
|
|
//
|
|
m_pFileExt = new CFileExt();
|
|
m_pFileExt->m_ppThis = &m_pFileExt;
|
|
m_pFileExt->m_pCDI = this;
|
|
// marshal the IClassAdmin interface to the page
|
|
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(m_pFileExt->m_pIStream));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SetPropPageToDeleteOnClose(&m_pFileExt->m_psp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HPROPSHEETPAGE hFileExt = CreatePropertySheetPage(&m_pFileExt->m_psp);
|
|
if (hFileExt == NULL)
|
|
return E_UNEXPECTED;
|
|
lpProvider->AddPage(hFileExt);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// Scope item property pages:
|
|
STDMETHODIMP CComponentDataImpl::QueryPagesFor(LPDATAOBJECT lpDataObject)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
// Look at the data object and see if it an item that we want to have a property sheet
|
|
INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);
|
|
if (CCT_SCOPE == pInternal->m_type)
|
|
{
|
|
FREE_INTERNAL(pInternal);
|
|
return S_OK;
|
|
}
|
|
|
|
FREE_INTERNAL(pInternal);
|
|
return S_FALSE;
|
|
}
|
|
|
|
BOOL CComponentDataImpl::IsScopePaneNode(LPDATAOBJECT lpDataObject)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);
|
|
|
|
if (pInternal->m_type == CCT_SCOPE)
|
|
bResult = TRUE;
|
|
|
|
FREE_INTERNAL(pInternal);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// IExtendContextMenu implementation
|
|
//
|
|
STDMETHODIMP CComponentDataImpl::AddMenuItems(LPDATAOBJECT pDataObject,
|
|
LPCONTEXTMENUCALLBACK pContextMenuCallback,
|
|
LONG * pInsertionAllowed)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
|
|
|
|
CONTEXTMENUITEM menuitem;
|
|
WCHAR szName[256];
|
|
WCHAR szStatus[256];
|
|
menuitem.strName = szName;
|
|
menuitem.strStatusBarText = szStatus;
|
|
menuitem.fFlags = 0;
|
|
menuitem.fSpecialFlags = 0;
|
|
|
|
do {
|
|
|
|
if ((*pInsertionAllowed) & CCM_INSERTIONALLOWED_NEW)
|
|
{
|
|
//
|
|
// Add Application menu item
|
|
//
|
|
::LoadString(ghInstance, IDM_ADD_APP, szName, 256);
|
|
::LoadString(ghInstance, IDS_ADD_APP_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_ADD_APP;
|
|
menuitem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_NEW;
|
|
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Update & Remove application if this is a result pane item
|
|
//
|
|
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA & data = m_AppData[pInternal->m_cookie];
|
|
DWORD dwFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
|
|
if ((*pInsertionAllowed) & CCM_INSERTIONALLOWED_TOP)
|
|
{
|
|
::LoadString(ghInstance, IDM_AUTOINST, szName, 256);
|
|
::LoadString(ghInstance, IDS_AUTOINST_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_AUTOINST;
|
|
menuitem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TOP;
|
|
|
|
// only enable for published apps
|
|
if ((dwFlags & (ACTFLG_OnDemandInstall | ACTFLG_UserInstall)) && !(dwFlags & ACTFLG_Assigned))
|
|
menuitem.fFlags = 0;
|
|
else
|
|
menuitem.fFlags = MFS_DISABLED;
|
|
if (dwFlags & ACTFLG_OnDemandInstall)
|
|
menuitem.fFlags += MFS_CHECKED;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
::LoadString(ghInstance, IDM_ASSIGN, szName, 256);
|
|
::LoadString(ghInstance, IDS_ASSIGN_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_ASSIGN;
|
|
if (dwFlags & ACTFLG_Assigned)
|
|
menuitem.fFlags = MFS_DISABLED;
|
|
else
|
|
menuitem.fFlags = 0;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
::LoadString(ghInstance, IDM_PUBLISH, szName, 256);
|
|
::LoadString(ghInstance, IDS_PUBLISH_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_PUBLISH;
|
|
if ((dwFlags & (ACTFLG_OnDemandInstall | ACTFLG_UserInstall)) && !(dwFlags & ACTFLG_Assigned))
|
|
menuitem.fFlags = MFS_DISABLED;
|
|
else
|
|
menuitem.fFlags = 0;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
::LoadString(ghInstance, IDM_DISABLE, szName, 256);
|
|
::LoadString(ghInstance, IDS_DISABLE_DESC, szStatus, 256);
|
|
|
|
if (dwFlags & (ACTFLG_OnDemandInstall | ACTFLG_UserInstall | ACTFLG_Assigned))
|
|
menuitem.fFlags = 0;
|
|
else
|
|
menuitem.fFlags = MFS_DISABLED;
|
|
menuitem.lCommandID = IDM_DISABLE;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
menuitem.lCommandID = 0;
|
|
menuitem.fFlags = MFT_SEPARATOR;
|
|
menuitem.fSpecialFlags = CCM_SPECIAL_SEPARATOR;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
if ((*pInsertionAllowed) & CCM_INSERTIONALLOWED_TASK)
|
|
{
|
|
::LoadString(ghInstance, IDM_ASSIGN, szName, 256);
|
|
::LoadString(ghInstance, IDS_ASSIGN_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_ASSIGN_T;
|
|
menuitem.fSpecialFlags = 0;
|
|
if (dwFlags & ACTFLG_Assigned)
|
|
menuitem.fFlags = MFS_DISABLED;
|
|
else
|
|
menuitem.fFlags = 0;
|
|
menuitem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TASK;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
::LoadString(ghInstance, IDM_PUBLISH, szName, 256);
|
|
::LoadString(ghInstance, IDS_PUBLISH_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_PUBLISH_T;
|
|
if ((dwFlags & (ACTFLG_OnDemandInstall | ACTFLG_UserInstall)) && !(dwFlags & ACTFLG_Assigned))
|
|
menuitem.fFlags = MFS_DISABLED;
|
|
else
|
|
menuitem.fFlags = 0;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
::LoadString(ghInstance, IDM_DISABLE, szName, 256);
|
|
::LoadString(ghInstance, IDS_DISABLE_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_DISABLE_T;
|
|
if (dwFlags & (ACTFLG_OnDemandInstall | ACTFLG_UserInstall | ACTFLG_Assigned))
|
|
menuitem.fFlags = 0;
|
|
else
|
|
menuitem.fFlags = MFS_DISABLED;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
menuitem.lCommandID = 0;
|
|
menuitem.fFlags = MFT_SEPARATOR;
|
|
menuitem.fSpecialFlags = CCM_SPECIAL_SEPARATOR;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
::LoadString(ghInstance, IDM_DEL_APP, szName, 256);
|
|
::LoadString(ghInstance, IDS_DEL_APP_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_DEL_APP;
|
|
menuitem.fFlags = 0;
|
|
menuitem.fSpecialFlags = 0;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
//
|
|
// Upgrade support menu items.
|
|
//
|
|
|
|
// Migrate - enable only on the new app (the old app might
|
|
// get upgraded by more than one app and it doesn't make
|
|
// sense to migrate them all at once).
|
|
|
|
// Finish Upgrade - Enable on both apps.
|
|
// If selected on an app that is both an upgrade and is
|
|
// being upgraded, then the older relationship takes
|
|
// precidence.
|
|
// Example: C upgrades B which upgrades A. User chooses
|
|
// "Finish Upgrade" on B. ADE removes A and sets B
|
|
// to the "deployed" state. User chooses "Finish
|
|
// Upgrade" on B again. This time ADE removes B
|
|
// and sets C to the deployed state.
|
|
|
|
// Check upgrade relationships for apps I'm upgrading and
|
|
// apps that are upgrading me.
|
|
BOOL fIUpgrade = FALSE;
|
|
UINT n = data.pDetails->pInstallInfo->cUpgrades;
|
|
while (n-- && ! fIUpgrade)
|
|
{
|
|
// BUGBUG - eventually we'll want to try and look this up on other
|
|
// OUs as well.
|
|
std::map<CString,long>::iterator i = m_ScriptIndex.find(data.pDetails->pInstallInfo->prgUpgradeScript[n]);
|
|
if (m_ScriptIndex.end() != i)
|
|
{
|
|
fIUpgrade = TRUE;
|
|
}
|
|
}
|
|
|
|
BOOL fIAmBeingUpgraded = 0 < data.sUpgrades.size();
|
|
|
|
::LoadString(ghInstance, IDM_MIGRATE, szName, 256);
|
|
::LoadString(ghInstance, IDS_MIGRATE_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_MIGRATE;
|
|
menuitem.fFlags = fIUpgrade ? 0 : MFS_DISABLED;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
::LoadString(ghInstance, IDM_FINISH, szName, 256);
|
|
::LoadString(ghInstance, IDS_FINISH_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_FINISH;
|
|
menuitem.fFlags = (fIUpgrade | fIAmBeingUpgraded) ? 0 : MFS_DISABLED;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
|
|
menuitem.lCommandID = 0;
|
|
menuitem.fFlags = MFT_SEPARATOR;
|
|
menuitem.fSpecialFlags = CCM_SPECIAL_SEPARATOR;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ((*pInsertionAllowed) & CCM_INSERTIONALLOWED_TASK)
|
|
{
|
|
::LoadString(ghInstance, IDM_REFRESH, szName, 256);
|
|
::LoadString(ghInstance, IDS_REFRESH_DESC, szStatus, 256);
|
|
menuitem.lCommandID = IDM_REFRESH;
|
|
menuitem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TASK;
|
|
menuitem.fFlags = 0;
|
|
menuitem.fSpecialFlags = 0;
|
|
hr = pContextMenuCallback->AddItem(&menuitem);
|
|
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
FREE_INTERNAL(pInternal);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CComponentDataImpl::InitializeClassAdmin()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fCancel = FALSE;
|
|
do
|
|
{
|
|
if (!m_pIClassAdmin)
|
|
{
|
|
// get the IClassAdmin
|
|
hr = GetClassStore();
|
|
// make sure directories are created:
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CreateNestedDirectory ((LPOLESTR)((LPCOLESTR)m_szGPT_Path), NULL);
|
|
#if UGLY_SUBDIRECTORY_HACK
|
|
CString sz = m_szGPT_Path;
|
|
sz += L"\\assigned\\x86";
|
|
CreateNestedDirectory((LPOLESTR)((LPCOLESTR)sz), NULL);
|
|
sz = m_szGPT_Path;
|
|
sz += L"\\assigned\\alpha";
|
|
CreateNestedDirectory((LPOLESTR)((LPCOLESTR)sz), NULL);
|
|
#endif
|
|
}
|
|
if (FAILED(hr))
|
|
{
|
|
m_fLoaded = FALSE;
|
|
TCHAR szBuffer[256];
|
|
if (!m_pIClassAdmin)
|
|
{
|
|
::LoadString(ghInstance, IDS_CSADMINFAILED, szBuffer, 256);
|
|
}
|
|
else
|
|
{
|
|
m_pIClassAdmin->Release();
|
|
m_pIClassAdmin = NULL;
|
|
::LoadString(ghInstance, IDS_GPTFAILED, szBuffer, 256);
|
|
}
|
|
int iReturn = ::MessageBox(NULL, m_szLDAP_Path,
|
|
szBuffer,
|
|
MB_RETRYCANCEL);
|
|
if (iReturn == IDCANCEL)
|
|
{
|
|
fCancel = TRUE;
|
|
}
|
|
}
|
|
}
|
|
} while ((!fCancel) && (!m_pIClassAdmin));
|
|
return hr;
|
|
}
|
|
|
|
#include <list>
|
|
|
|
typedef struct tagCABLIST
|
|
{
|
|
FILETIME ft;
|
|
CString szPath;
|
|
bool operator<(const struct tagCABLIST& st)
|
|
{
|
|
return CompareFileTime(&ft, &st.ft) < 0;
|
|
}
|
|
} CABLIST;
|
|
|
|
|
|
STDMETHODIMP CComponentDataImpl::Command(long nCommandID, LPDATAOBJECT pDataObject)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
|
|
|
|
// Note - snap-ins need to look at the data object and determine
|
|
// in what context the command is being called.
|
|
|
|
// Handle each of the commands.
|
|
switch (nCommandID)
|
|
{
|
|
case IDM_AUTOINST:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA &data = m_AppData[pInternal->m_cookie];
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags ^ ACTFLG_OnDemandInstall;
|
|
ChangePackageState(data, dwNewFlags, TRUE);
|
|
}
|
|
break;
|
|
case IDM_ASSIGN:
|
|
case IDM_ASSIGN_T:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA &data = m_AppData[pInternal->m_cookie];
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~(ACTFLG_Published | ACTFLG_UserInstall);
|
|
dwNewFlags |= (ACTFLG_Assigned | ACTFLG_OnDemandInstall);
|
|
ChangePackageState(data, dwNewFlags, TRUE);
|
|
}
|
|
break;
|
|
case IDM_PUBLISH:
|
|
case IDM_PUBLISH_T:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA &data = m_AppData[pInternal->m_cookie];
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~ACTFLG_Assigned;
|
|
dwNewFlags |= ACTFLG_Published | ACTFLG_UserInstall;
|
|
ChangePackageState(data, dwNewFlags, TRUE);
|
|
}
|
|
break;
|
|
case IDM_DISABLE:
|
|
case IDM_DISABLE_T:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA &data = m_AppData[pInternal->m_cookie];
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~(ACTFLG_OnDemandInstall | ACTFLG_Assigned | ACTFLG_UserInstall);
|
|
dwNewFlags |= ACTFLG_Published;
|
|
ChangePackageState(data, dwNewFlags, TRUE);
|
|
}
|
|
break;
|
|
case IDM_MIGRATE:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA &data = m_AppData[pInternal->m_cookie];
|
|
// Walk the list of things that I am upgrading, making flag
|
|
// changes as necessary. Take note if anything I'm
|
|
// upgrading is assigned.
|
|
BOOL fAssigned = FALSE;
|
|
|
|
UINT n = data.pDetails->pInstallInfo->cUpgrades;
|
|
while (n--)
|
|
{
|
|
// BUGBUG - eventually we'll want to try and look this up on other
|
|
// OUs as well.
|
|
std::map<CString,long>::iterator i = m_ScriptIndex.find(data.pDetails->pInstallInfo->prgUpgradeScript[n]);
|
|
if (m_ScriptIndex.end() != i)
|
|
{
|
|
// found something
|
|
APP_DATA & data_old = m_AppData[i->second];
|
|
DWORD dwActFlags = data_old.pDetails->pInstallInfo->dwActFlags;
|
|
if (dwActFlags & ACTFLG_Assigned)
|
|
{
|
|
// old app is assigned
|
|
fAssigned = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// old app is published - turn off auto-install
|
|
dwActFlags &= ~ACTFLG_OnDemandInstall;
|
|
ChangePackageState(data_old, dwActFlags, FALSE);
|
|
}
|
|
}
|
|
}
|
|
if (fAssigned)
|
|
{
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~(ACTFLG_Published | ACTFLG_UserInstall);
|
|
dwNewFlags |= (ACTFLG_Assigned | ACTFLG_OnDemandInstall);
|
|
ChangePackageState(data, dwNewFlags, FALSE);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~ACTFLG_Assigned;
|
|
dwNewFlags |= ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
|
ChangePackageState(data, dwNewFlags, FALSE);
|
|
}
|
|
}
|
|
break;
|
|
case IDM_FINISH:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA &data = m_AppData[pInternal->m_cookie];
|
|
// If selected on an app that is both an upgrade and is
|
|
// being upgraded, then the older relationship takes
|
|
// precidence.
|
|
// Example: C upgrades B which upgrades A. User chooses
|
|
// "Finish Upgrade" on B. ADE removes A and sets B
|
|
// to the "deployed" state. User chooses "Finish
|
|
// Upgrade" on B again. This time ADE removes B
|
|
// and sets C to the deployed state.
|
|
BOOL fIUpgrade = FALSE;
|
|
BOOL fAssigned = FALSE;
|
|
UINT n = data.pDetails->pInstallInfo->cUpgrades;
|
|
while (n--)
|
|
{
|
|
// BUGBUG - eventually we'll want to try and look this up on other
|
|
// OUs as well.
|
|
std::map<CString,long>::iterator i = m_ScriptIndex.find(data.pDetails->pInstallInfo->prgUpgradeScript[n]);
|
|
if (m_ScriptIndex.end() != i)
|
|
{
|
|
fIUpgrade = TRUE;
|
|
APP_DATA & data_old = m_AppData[i->second];
|
|
DWORD dwActFlags = data_old.pDetails->pInstallInfo->dwActFlags;
|
|
if (dwActFlags & ACTFLG_Assigned)
|
|
fAssigned = TRUE;
|
|
RemovePackage(i->second);
|
|
}
|
|
}
|
|
if (fIUpgrade)
|
|
{
|
|
// Everything I upgrade has been deleted, now I just set
|
|
// the appropriate flags on me.
|
|
if (fAssigned)
|
|
{
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~(ACTFLG_Published | ACTFLG_UserInstall);
|
|
dwNewFlags |= (ACTFLG_Assigned | ACTFLG_OnDemandInstall);
|
|
ChangePackageState(data, dwNewFlags, FALSE);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~ACTFLG_Assigned;
|
|
dwNewFlags |= ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
|
ChangePackageState(data, dwNewFlags, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// I didn't upgrade anyone so I need to delete myself
|
|
// and set the appropriate flags on anyone that upgrades
|
|
// me.
|
|
BOOL fAssigned = data.pDetails->pInstallInfo->dwActFlags & ACTFLG_Assigned;
|
|
std::set<long>::iterator i;
|
|
for (i = data.sUpgrades.begin(); i != data.sUpgrades.end(); i++)
|
|
{
|
|
APP_DATA & data_new = m_AppData[*i];
|
|
if (fAssigned)
|
|
{
|
|
DWORD dwNewFlags = data_new.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~(ACTFLG_Published | ACTFLG_UserInstall);
|
|
dwNewFlags |= (ACTFLG_Assigned | ACTFLG_OnDemandInstall);
|
|
ChangePackageState(data_new, dwNewFlags, FALSE);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwNewFlags = data_new.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~ACTFLG_Assigned;
|
|
dwNewFlags |= ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
|
ChangePackageState(data_new, dwNewFlags, FALSE);
|
|
}
|
|
}
|
|
RemovePackage(pInternal->m_cookie);
|
|
}
|
|
}
|
|
break;
|
|
case IDM_ADD_APP:
|
|
{
|
|
// start browsing in the default start path
|
|
CString szFileName;
|
|
|
|
CFileDialog cfd(TRUE,
|
|
szExtension,
|
|
szFileName,
|
|
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST,
|
|
szFilter);
|
|
|
|
cfd.m_ofn.lpstrInitialDir = m_ToolDefaults.szStartPath;
|
|
|
|
if (IDOK == cfd.DoModal())
|
|
{
|
|
// user selected an application
|
|
UNIVERSAL_NAME_INFO * pUni = new UNIVERSAL_NAME_INFO;
|
|
ULONG cbSize = sizeof(UNIVERSAL_NAME_INFO);
|
|
HRESULT hr = WNetGetUniversalName(cfd.m_ofn.lpstrFile,
|
|
UNIVERSAL_NAME_INFO_LEVEL,
|
|
pUni,
|
|
&cbSize);
|
|
if (ERROR_MORE_DATA == hr) // we expect this to be true
|
|
{
|
|
delete [] pUni;
|
|
pUni = (UNIVERSAL_NAME_INFO *) new BYTE [cbSize];
|
|
hr = WNetGetUniversalName(cfd.m_ofn.lpstrFile,
|
|
UNIVERSAL_NAME_INFO_LEVEL,
|
|
pUni,
|
|
&cbSize);
|
|
}
|
|
|
|
CString szPackagePath;
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
szPackagePath = pUni->lpUniversalName;
|
|
}
|
|
else
|
|
{
|
|
// BUGBUG Do we put up an error message here?
|
|
szPackagePath = cfd.m_ofn.lpstrFile;
|
|
}
|
|
delete[] pUni;
|
|
|
|
hr = AddMSIPackage(szPackagePath, cfd.m_ofn.lpstrFileTitle);
|
|
|
|
// Notify clients of change
|
|
if (SUCCEEDED(hr) && m_pIGPEInformation)
|
|
{
|
|
m_pIGPEInformation->PolicyChanged();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_REFRESH:
|
|
if (m_pIClassAdmin)
|
|
{
|
|
|
|
std::map <long, APP_DATA>::iterator i;
|
|
for (i=m_AppData.begin(); i != m_AppData.end(); i++)
|
|
{
|
|
m_pSnapin->m_pResult->DeleteItem(i->second.itemID, 0);
|
|
FreePackageDetail(i->second.pDetails);
|
|
m_AppData.erase(i);
|
|
}
|
|
m_ScriptIndex.erase(m_ScriptIndex.begin(), m_ScriptIndex.end());
|
|
m_lLastAllocated = 0;
|
|
m_pSnapin->EnumerateResultPane(0);
|
|
}
|
|
break;
|
|
case IDM_DEL_APP:
|
|
if (pInternal->m_type == CCT_RESULT)
|
|
{
|
|
APP_DATA & data = m_AppData[pInternal->m_cookie];
|
|
CRemove dlg;
|
|
// Check to see if there is an upgrade relationship.
|
|
// NOTE: I am only checking to see if this app is
|
|
// being upgraded by another, not if this app
|
|
// upgrades another. It makes sense that if
|
|
// the user chose "remove" then he
|
|
// specifically meant to remove this app.
|
|
if (0 == data.sUpgrades.size())
|
|
{
|
|
// there is no upgrade relationship here
|
|
dlg.m_iState = 1;
|
|
}
|
|
int iReturn = dlg.DoModal();
|
|
|
|
if (IDOK == iReturn)
|
|
{
|
|
switch (dlg.m_iState)
|
|
{
|
|
case 0:
|
|
// force upgrade
|
|
{
|
|
BOOL fAssigned = data.pDetails->pInstallInfo->dwActFlags & ACTFLG_Assigned;
|
|
std::set<long>::iterator i;
|
|
for (i = data.sUpgrades.begin(); i != data.sUpgrades.end(); i++)
|
|
{
|
|
APP_DATA & data_new = m_AppData[*i];
|
|
if (fAssigned)
|
|
{
|
|
DWORD dwNewFlags = data_new.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~(ACTFLG_Published | ACTFLG_UserInstall);
|
|
dwNewFlags |= (ACTFLG_Assigned | ACTFLG_OnDemandInstall);
|
|
ChangePackageState(data_new, dwNewFlags, FALSE);
|
|
}
|
|
else
|
|
{
|
|
DWORD dwNewFlags = data_new.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~ACTFLG_Assigned;
|
|
dwNewFlags |= ACTFLG_Published | ACTFLG_UserInstall | ACTFLG_OnDemandInstall;
|
|
ChangePackageState(data_new, dwNewFlags, FALSE);
|
|
}
|
|
}
|
|
RemovePackage(pInternal->m_cookie);
|
|
}
|
|
break;
|
|
case 1:
|
|
// remove app
|
|
RemovePackage(pInternal->m_cookie);
|
|
break;
|
|
case 2:
|
|
// disable app
|
|
DWORD dwNewFlags = data.pDetails->pInstallInfo->dwActFlags;
|
|
dwNewFlags &= ~(ACTFLG_OnDemandInstall | ACTFLG_Assigned | ACTFLG_UserInstall);
|
|
dwNewFlags |= ACTFLG_Published;
|
|
ChangePackageState(data, dwNewFlags, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
|
|
{
|
|
if (lpDataObjectA == NULL || lpDataObjectB == NULL)
|
|
return E_POINTER;
|
|
|
|
// Make sure both data object are mine
|
|
INTERNAL* pA;
|
|
INTERNAL* pB;
|
|
HRESULT hr = S_FALSE;
|
|
|
|
pA = ExtractInternalFormat(lpDataObjectA);
|
|
pB = ExtractInternalFormat(lpDataObjectB);
|
|
|
|
if (pA != NULL && pB != NULL)
|
|
hr = ((pA->m_type == pB->m_type) && (pA->m_cookie == pB->m_cookie)) ? S_OK : S_FALSE;
|
|
|
|
FREE_INTERNAL(pA);
|
|
FREE_INTERNAL(pB);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CSnapin::Compare(long lUserParam, long cookieA, long cookieB, int* pnResult)
|
|
{
|
|
if (pnResult == NULL)
|
|
{
|
|
ASSERT(FALSE);
|
|
return E_POINTER;
|
|
}
|
|
|
|
// check col range
|
|
int nCol = *pnResult;
|
|
|
|
*pnResult = 0;
|
|
|
|
APP_DATA & dataA = m_pComponentData->m_AppData[cookieA];
|
|
APP_DATA & dataB = m_pComponentData->m_AppData[cookieB];
|
|
// compare the two based on column and the cookies
|
|
CString szA, szB;
|
|
|
|
switch (nCol)
|
|
{
|
|
case 0:
|
|
szA = dataA.pDetails->pszPackageName;
|
|
szB = dataB.pDetails->pszPackageName;
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 1:
|
|
dataA.GetSzVersion(szA);
|
|
dataB.GetSzVersion(szB);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 2:
|
|
dataA.GetSzStage(szA, m_pComponentData);
|
|
dataB.GetSzStage(szB, m_pComponentData);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 3:
|
|
dataA.GetSzRelation(szA, m_pComponentData);
|
|
dataB.GetSzRelation(szB, m_pComponentData);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 4:
|
|
dataA.GetSzDeployment(szA);
|
|
dataB.GetSzDeployment(szB);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 5:
|
|
dataA.GetSzAutoInstall(szA);
|
|
dataB.GetSzAutoInstall(szB);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 6:
|
|
dataA.GetSzLocale(szA);
|
|
dataB.GetSzLocale(szB);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 7:
|
|
dataA.GetSzPlatform(szA);
|
|
dataB.GetSzPlatform(szB);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 8:
|
|
dataA.GetSzSource(szA);
|
|
dataB.GetSzSource(szB);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 9:
|
|
dataA.GetSzMods(szA);
|
|
dataB.GetSzMods(szB);
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
case 10:
|
|
szA = dataA.szPublisher;
|
|
szB = dataB.szPublisher;
|
|
*pnResult = szA.CompareNoCase(szB);
|
|
break;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CSnapin::GetDisplayInfo(LPRESULTDATAITEM pResult)
|
|
{
|
|
static CString sz;
|
|
ASSERT(pResult != NULL);
|
|
if (pResult)
|
|
{
|
|
if (pResult->lParam == -1)
|
|
{
|
|
switch (pResult->nCol)
|
|
{
|
|
case 0:
|
|
pResult->str = (unsigned short *)((LPCOLESTR)m_szFolderTitle);
|
|
break;
|
|
default:
|
|
pResult->str = (BSTR)_T("");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::map<long, APP_DATA>::iterator i = m_pComponentData->m_AppData.find(pResult->lParam);
|
|
if (i != m_pComponentData->m_AppData.end())
|
|
{
|
|
APP_DATA & data = i->second;
|
|
switch (pResult->nCol)
|
|
{
|
|
case 0:
|
|
sz = data.pDetails->pszPackageName;
|
|
break;
|
|
case 1:
|
|
data.GetSzVersion(sz);
|
|
break;
|
|
case 2:
|
|
data.GetSzStage(sz, m_pComponentData);
|
|
break;
|
|
case 3:
|
|
data.GetSzRelation(sz, m_pComponentData);
|
|
break;
|
|
case 4:
|
|
data.GetSzDeployment(sz);
|
|
break;
|
|
case 5:
|
|
data.GetSzAutoInstall(sz);
|
|
break;
|
|
case 6:
|
|
data.GetSzLocale(sz);
|
|
break;
|
|
case 7:
|
|
data.GetSzPlatform(sz);
|
|
break;
|
|
case 8:
|
|
data.GetSzSource(sz);
|
|
break;
|
|
case 9:
|
|
data.GetSzMods(sz);
|
|
break;
|
|
case 10:
|
|
sz = data.szPublisher;
|
|
break;
|
|
default:
|
|
sz = "";
|
|
break;
|
|
}
|
|
pResult->str = (unsigned short *)((LPCOLESTR)sz);
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// This code is needed to ensure that property pages get cleaned up properly.
|
|
// This ensures that when the property sheet is closed all my of property
|
|
// pages that are associated with that property sheet will get deleted.
|
|
LPFNPSPCALLBACK _MMCHookProp;
|
|
|
|
UINT CALLBACK HookPropertySheetProp(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
|
|
{
|
|
UINT i = _MMCHookProp(hwnd, uMsg, ppsp);
|
|
switch (uMsg)
|
|
{
|
|
case PSPCB_RELEASE:
|
|
delete (CPropertyPage *) ppsp->lParam;
|
|
return TRUE;
|
|
default:
|
|
break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
LRESULT SetPropPageToDeleteOnClose(void * vpsp)
|
|
{
|
|
HRESULT hr = MMCPropPageCallback(vpsp);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (vpsp == NULL)
|
|
return E_POINTER;
|
|
|
|
LPPROPSHEETPAGE psp = (LPPROPSHEETPAGE)vpsp;
|
|
|
|
if ((void*)psp->pfnCallback == (void*)HookPropertySheetProp)
|
|
return E_UNEXPECTED;
|
|
|
|
_MMCHookProp = psp->pfnCallback;
|
|
|
|
psp->pfnCallback = HookPropertySheetProp;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|