windows-nt/Source/XPSP1/NT/com/ole32/cs/csadmin/appmgr/csnapin.cpp

2513 lines
76 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
// 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
long CSnapin::lDataObjectRefCount = 0;
#if 1 // BUGBUG - until this gets put in the regular build environment
extern const IID IID_IClassAdmin; /* = {0x00000191,0x0000,0x0000,{0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}}; */
#endif
extern const CLSID CLSID_Snapin = {0xbdc67e00,0x8ea5,0x11d0,{0x8d,0x3c,0x00,0xa0,0xc9,0x0d,0xca,0xe7}};
extern const wchar_t * szCLSID_Snapin = L"{bdc67e00-8ea5-11d0-8d3c-00a0c90dcae7}";
//const CLSID CLSID_Snapin = {0x18731372,0x1D79,0x11D0,{0xA2,0x9B,0x00,0xC0,0x4F,0xD9,0x09,0xDD}};
// Main NodeType GUID on numeric format
extern const GUID cNodeType = {0xf8b3a900,0x8ea5,0x11d0,{0x8d,0x3c,0x00,0xa0,0xc9,0x0d,0xca,0xe7}};
//const GUID cNodeType = {0x44092d22,0x1d7e,0x11D0,{0xA2,0x9B,0x00,0xC0,0x4F,0xD9,0x09,0xDD}};
// Main NodeType GUID on string format
extern const wchar_t* cszNodeType = L"{f8b3a900-8ea5-11d0-8d3c-00a0c90dcae7}";
//const wchar_t* cszNodeType = L"{44092d22-1d7e-11d0-a29b-00c04fd909dd}";
// Internal private format
const wchar_t* SNAPIN_INTERNAL = L"APPMGR_INTERNAL";
#define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
static MMCBUTTON SnapinButtons[] =
{
{ 0, 1, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Folder"), _T("New Folder") },
{ 1, 2, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Inbox"), _T("Mail Inbox")},
{ 2, 3, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Outbox"), _T("Mail Outbox") },
{ 3, 4, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Send"), _T("Send Message") },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, _T(" "), _T("") },
{ 4, 5, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Trash"), _T("Trash") },
{ 5, 6, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Open"), _T("Open Folder")},
{ 6, 7, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("News"), _T("Today's News") },
{ 7, 8, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("INews"), _T("Internet News") },
};
static MMCBUTTON SnapinButtons2[] =
{
{ 0, 10, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Compose"), _T("Compose Message") },
{ 1, 20, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Print"), _T("Print Message") },
{ 2, 30, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Find"), _T("Find Message") },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, _T(" "), _T("") },
{ 3, 40, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Inbox"), _T("Inbox") },
{ 4, 50, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Smile"), _T("Smile :-)") },
{ 5, 60, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Reply"), _T("Reply") },
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP , _T(" "), _T("") },
{ 6, 70, TBSTATE_ENABLED, TBSTYLE_BUTTON, _T("Reply All"), _T("Reply All") },
};
// 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
}
SAFE_RELEASE(m_pIAppManagerActions); // ditto
}
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==1
ASSERT(dbg_cRef == 0);
#endif
DEBUG_DECREMENT_INSTANCE_COUNTER(CSnapin);
// SAFE_RELEASE(m_pToolbar1);
// SAFE_RELEASE(m_pToolbar2);
// SAFE_RELEASE(m_pControlbar);
// Make sure the interfaces have been released
ASSERT(m_pConsole == NULL);
ASSERT(m_pHeader == NULL);
// ASSERT(m_pToolbar1 == NULL);
// ASSERT(m_pToolbar2 == NULL);
// delete m_pbmpToolbar1;
// delete m_pbmpToolbar2;
Construct();
ASSERT(CSnapin::lDataObjectRefCount == 0);
}
void CSnapin::Construct()
{
#if DBG==1
dbg_cRef = 0;
#endif
m_pConsole = NULL;
m_pHeader = NULL;
m_pResult = NULL;
m_pImageResult = NULL;
m_pComponentData = NULL;
m_pIAppManagerActions = NULL;
// m_pToolbar1 = NULL;
// m_pToolbar2 = NULL;
// m_pControlbar = NULL;
// m_pbmpToolbar1 = NULL;
// m_pbmpToolbar2 = NULL;
}
// Array of menu item commands to be inserted into the context menu.
// Note - the first item is the menu text,
// the second item is the status string
CONTEXTMENUITEM menuItems[] =
{
{
L"", L"",
0, CCM_INSERTIONPOINTID_PRIMARY_TOP, MFT_SEPARATOR, CCM_SPECIAL_SEPARATOR
},
{
L"", L"",
IDM_ADD_APP, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0
},
{
L"", L"",
IDM_UPDATE_APP, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0
},
{
L"", L"",
IDM_DEL_APP, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0
},
{
L"", L"",
IDM_ADD_FROM_IE, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0
},
{
L"", L"",
IDM_REFRESH, CCM_INSERTIONPOINTID_PRIMARY_TOP, 0, 0
}
};
CString szExtension;
CString szFilter;
void CSnapin::LoadResources()
{
// Load strings from resources
m_column1.LoadString(IDS_NAME);
m_column2.LoadString(IDS_TYPE);
m_column3.LoadString(IDS_SIZE);
m_column4.LoadString(IDS_LOC);
m_column5.LoadString(IDS_MACH);
m_column6.LoadString(IDS_DESC);
m_column7.LoadString(IDS_PATH);
m_szAddApp.LoadString(IDM_ADD_APP);
m_szAddAppDesc.LoadString(IDS_ADD_APP_DESC);
m_szDelApp.LoadString(IDM_DEL_APP);
m_szDelAppDesc.LoadString(IDS_DEL_APP_DESC);
m_szUpdateApp.LoadString(IDM_UPDATE_APP);
m_szUpdateAppDesc.LoadString(IDS_UPDATE_APP_DESC);
m_szRefresh.LoadString(IDM_REFRESH);
m_szRefreshDesc.LoadString(IDS_REFRESH_DESC);
m_szAddFromIe.LoadString(IDM_ADD_FROM_IE);
m_szAddFromIeDesc.LoadString(IDS_ADD_FROM_IE_DESC);
menuItems[1].strName = (LPWSTR)((LPCOLESTR)m_szAddApp);
menuItems[1].strStatusBarText = (LPWSTR)((LPCOLESTR)m_szAddAppDesc);
menuItems[2].strName = (LPWSTR)((LPCOLESTR)m_szUpdateApp);
menuItems[2].strStatusBarText = (LPWSTR)((LPCOLESTR)m_szUpdateAppDesc);
menuItems[3].strName = (LPWSTR)((LPCOLESTR)m_szDelApp);
menuItems[3].strStatusBarText = (LPWSTR)((LPCOLESTR)m_szDelAppDesc);
menuItems[4].strName = (LPWSTR)((LPCOLESTR)m_szAddFromIe);
menuItems[4].strStatusBarText = (LPWSTR)((LPCOLESTR)m_szAddFromIeDesc);
menuItems[5].strName = (LPWSTR)((LPCOLESTR)m_szRefresh);
menuItems[5].strStatusBarText = (LPWSTR)((LPCOLESTR)m_szRefreshDesc);
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, 100); // Name
m_pHeader->InsertColumn(1, m_column2, LVCFMT_LEFT, 75); // Type
// m_pHeader->InsertColumn(2, m_column3, LVCFMT_RIGHT, 50); // Size
m_pHeader->InsertColumn(2, m_column4, LVCFMT_RIGHT, 100); // localle
m_pHeader->InsertColumn(3, m_column5, LVCFMT_LEFT, 75); // machine
m_pHeader->InsertColumn(4, m_column6, LVCFMT_LEFT, 75); // description
m_pHeader->InsertColumn(5, m_column7, LVCFMT_LEFT, 150); // path
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;
}
STDMETHODIMP CSnapin::GetDisplayInfo(LPRESULTDATAITEM pResult)
{
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:
pResult->str = (unsigned short *)((LPCOLESTR)data.szName);
break;
case 1:
pResult->str = (unsigned short *)((LPCOLESTR)data.szType);
break;
case 2:
pResult->str = (unsigned short *)((LPCOLESTR)data.szLoc);
break;
case 3:
pResult->str = (unsigned short *)((LPCOLESTR)data.szMach);
break;
case 4:
pResult->str = (unsigned short *)((LPCOLESTR)data.szDesc);
break;
case 5:
pResult->str = (unsigned short *)((LPCOLESTR)data.szIconPath);
break;
}
if (pResult->str == NULL)
pResult->str = (BSTR)_T("");
}
}
}
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_pScope = NULL;
m_pConsole = NULL;
m_pIClassAdmin = NULL;
m_fLoaded = FALSE;
m_fExtension = FALSE;
m_pIGPTInformation = NULL;
m_lLastAllocated = 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;
// Since it's my folder it has an internal format.
// Design Note: for extension. I can use the fact, that the data object doesn't have
// my internal format and I should look at the node type and see how to extend it.
if (event == MMCN_PROPERTY_CHANGE)
{
hr = OnProperties(param);
}
else
{
INTERNAL* pInternal = ExtractInternalFormat(lpDataObject);
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_pIGPTInformation == NULL)
{
hr = lpDataObject->QueryInterface(IID_IGPTInformation,
reinterpret_cast<void**>(&m_pIGPTInformation));
if (SUCCEEDED(hr))
{
WCHAR szBuffer[MAX_PATH];
do
{
hr = m_pIGPTInformation->GetCSPath(szBuffer, MAX_PATH);
if (FAILED(hr)) break;
m_szLDAP_Path = "ADCS:";
m_szLDAP_Path += szBuffer;
hr = m_pIGPTInformation->GetGPTPath(GPT_SECTION_USER, szBuffer, MAX_PATH);
if (FAILED(hr)) break;
m_szGPT_Path = szBuffer;
m_szGPT_Path += L"\\Applications";
if (SUCCEEDED(CreateApplicationDirectories()))
{
m_fLoaded = TRUE;
}
} while (0);
}
}
switch(event)
{
// case MMCN_ADD:
// hr = OnAdd(cookie, arg, param);
// break;
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_pIGPTInformation);
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);
// 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
*pClassID = CLSID_Snapin;
return E_NOTIMPL;
}
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;
m_fLoaded = TRUE;
ClearDirty();
}
}
}
}
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;
}
// IAppManagerActions methods
STDMETHODIMP CComponentDataImpl::CanPackageBeAssigned(ULONG cookie)
{
HRESULT hr = E_FAIL;
std::map<long, APP_DATA>::iterator i = m_AppData.find(cookie);
if (i != m_AppData.end())
{
APP_DATA & data = i->second;
// If it is already assigned or if the path points to the GPT then it can
// be assigned.
if (data.pDetails->dwActFlags & ACTFLG_Assigned)
{
hr = S_OK;
}
else
{
CString szTemp = data.szPath;
szTemp.MakeLower();
int i = szTemp.Find(_T("\\published\\"));
if (i < 0)
{
i = szTemp.Find(_T("\\assigned\\")); // cover all the bases
}
if (i >= 0)
{
// finally make sure it's got an .aas extension
if (szTemp.Right(4) == _T(".aas"))
{
DWORD dwAttributes = GetFileAttributes(data.szPath);
if ((dwAttributes != 0xffffffff) && ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0))
{
hr = S_OK;
}
}
}
}
}
return hr;
}
STDMETHODIMP CComponentDataImpl::NotifyClients(BOOL f)
{
// Notify clients of change
if (m_pIGPTInformation)
{
m_pIGPTInformation->NotifyClients(f);
}
return S_OK;
}
STDMETHODIMP CComponentDataImpl::MovePackageToAssigned(ULONG cookie)
{
HRESULT hr = E_FAIL;
// first validate that we've got a script file that can be moved
if (SUCCEEDED(CanPackageBeAssigned(cookie)))
{
APP_DATA & data = m_AppData[cookie];
// don't need to validate the cookie because CanPackageBeAssigned does it.
// need to build the destination path
CString szTemp = data.szPath;
szTemp.MakeLower();
int iSplitpoint = szTemp.Find(_T("published"));
if (iSplitpoint >= 0)
{
CString szDestination = data.szPath.Left(iSplitpoint);
szDestination += _T("assigned");
szDestination += data.szPath.Mid(iSplitpoint + strlen("published"));
// move the script file
if (!MoveFileEx(data.szPath, szDestination, MOVEFILE_COPY_ALLOWED|MOVEFILE_WRITE_THROUGH))
return (hr);
// update the path in the data packet
data.szPath = szDestination;
data.pDetails->pszPath = (LPOLESTR)(LPCOLESTR) data.szPath;
}
else
{
if (szTemp.Find(_T("assigned")) >= 0)
{
hr = S_OK; // already in the assigned directory
}
}
}
return hr;
}
STDMETHODIMP CComponentDataImpl::MovePackageToPublished(ULONG cookie)
{
HRESULT hr = E_FAIL;
// first validate that we've got a script file that can be moved
if (SUCCEEDED(CanPackageBeAssigned(cookie)))
{
APP_DATA & data = m_AppData[cookie];
// don't need to validate pData because CanPackageBeAssigned does it.
// need to build the destination path
CString szTemp = data.szPath;
szTemp.MakeLower();
int iSplitpoint = szTemp.Find(_T("assigned"));
if (iSplitpoint >= 0)
{
CString szDestination = data.szPath.Left(iSplitpoint);
szDestination += _T("published");
szDestination += data.szPath.Mid(iSplitpoint + strlen("assigned"));
// move the script file
if (!MoveFileEx(data.szPath, szDestination, MOVEFILE_COPY_ALLOWED|MOVEFILE_WRITE_THROUGH))
return(hr);
// update the path in the data packet
data.szPath = szDestination;
data.pDetails->pszPath = (LPOLESTR)(LPCOLESTR) data.szPath;
// Notify clients of change
if (m_pIGPTInformation)
{
m_pIGPTInformation->NotifyClients(FALSE);
}
hr = S_OK;
}
else
{
if (szTemp.Find(_T("published")) >= 0)
{
hr = S_OK; // already in the published directory
}
}
}
return hr;
}
STDMETHODIMP CComponentDataImpl::ReloadPackageData(ULONG cookie)
{
// put up an hourglass (this could take a while)
CHourglass hourglass;
return E_NOTIMPL;
}
HRESULT CComponentDataImpl::CreateApplicationDirectories(VOID)
{
TCHAR szDir[MAX_PATH];
LPTSTR lpEnd;
HRESULT hr = S_OK;
lstrcpy (szDir, m_szGPT_Path);
lpEnd = szDir + lstrlen(szDir);
do
{
#if 0
lstrcpy (lpEnd, TEXT("\\Assigned\\x86\\WinNT"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
lstrcpy (lpEnd, TEXT("\\Assigned\\x86\\Win95"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
#else
lstrcpy (lpEnd, TEXT("\\Assigned\\x86"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
#endif
lstrcpy (lpEnd, TEXT("\\Assigned\\Alpha"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
#if 0
lstrcpy (lpEnd, TEXT("\\Published\\x86\\WinNT"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
lstrcpy (lpEnd, TEXT("\\Published\\x86\\Win95"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
#else
lstrcpy (lpEnd, TEXT("\\Published\\x86"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
#endif
lstrcpy (lpEnd, TEXT("\\Published\\Alpha"));
if (!CreateNestedDirectory (szDir, NULL))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
} while (FALSE);
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)
{
ASSERT(pScopeDataItem != NULL);
if (pScopeDataItem == NULL)
return E_POINTER;
if (pScopeDataItem->lParam == -1)
{
TCHAR szBuffer[256];
::LoadString(ghInstance, IDS_FOLDER_TITLE, szBuffer, 256);
m_szFolderTitle = szBuffer;
pScopeDataItem->displayname = (unsigned short *)((LPCOLESTR)m_szFolderTitle);
}
else
{
ASSERT(pScopeDataItem->mask == TVIF_TEXT);
pScopeDataItem->displayname = (unsigned short *)((LPCOLESTR)m_AppData[pScopeDataItem->lParam].szName);
}
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 == *pB) ? S_OK : S_FALSE;
FREE_INTERNAL(pA);
FREE_INTERNAL(pB);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// IExtendPropertySheet Implementation
STDMETHODIMP CSnapin::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
long handle,
LPDATAOBJECT lpIDataObject)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
INTERNAL* pInternal = ExtractInternalFormat(lpIDataObject);
if (m_pIClassAdmin && (pInternal->m_type == CCT_RESULT))
{
HRESULT hr;
APP_DATA & data = m_pComponentData->m_AppData[pInternal->m_cookie];
// Create the property page
CGeneralPage* pPage = new CGeneralPage();
CPackageDetails * pDetails = new CPackageDetails();
pPage->m_hConsoleHandle = handle;
pPage->m_pData = &data;
pPage->m_cookie = pInternal->m_cookie;
FREE_INTERNAL(pInternal);
pPage->m_szName = data.szName;
pDetails->m_hConsoleHandle = handle;
pDetails->m_pData = &data;
// marshal the IClassAdmin interface to the details page
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(pDetails->m_pIStream));
// marshal the IClassAdmin interface to the general page
hr = CoMarshalInterThreadInterfaceInStream(IID_IClassAdmin, m_pIClassAdmin, &(pPage->m_pIStream));
// marshal the IAppManagerActions interface to the general page
hr = CoMarshalInterThreadInterfaceInStream(IID_IAppManagerActions, m_pIAppManagerActions, & (pPage->m_pIStreamAM));
// Object gets deleted when the page is destroyed
ASSERT(lpProvider != NULL);
hr = MMCPropPageCallback(&pPage->m_psp);
if (SUCCEEDED(hr))
{
hr = MMCPropPageCallback(&pDetails->m_psp);
if (SUCCEEDED(hr))
{
HPROPSHEETPAGE hPage = CreatePropertySheetPage(&pPage->m_psp);
HPROPSHEETPAGE hDetails = CreatePropertySheetPage(&pDetails->m_psp);
if (hPage == NULL || hDetails == NULL)
return E_UNEXPECTED;
lpProvider->AddPage(hPage);
#if DBG==1
lpProvider->AddPage(hDetails);
#endif
}
}
}
return S_OK;
}
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;
}
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);
do {
//
// Add Application menu item
//
hr = pContextMenuCallback->AddItem(&menuItems[1]);
if (FAILED(hr))
break;
//
// Update & Remove application if this is a result pane item
//
if (pInternal->m_type == CCT_RESULT)
{
hr = pContextMenuCallback->AddItem(&menuItems[2]);
if (FAILED(hr))
break;
hr = pContextMenuCallback->AddItem(&menuItems[3]);
if (FAILED(hr))
break;
}
//
// Separator
//
hr = pContextMenuCallback->AddItem(&menuItems[0]);
if (FAILED(hr))
break;
//
// Import Application menu item
//
hr = pContextMenuCallback->AddItem(&menuItems[4]);
if (FAILED(hr))
break;
//
// Separator
//
hr = pContextMenuCallback->AddItem(&menuItems[0]);
if (FAILED(hr))
break;
//
// Refresh menu item
//
hr = pContextMenuCallback->AddItem(&menuItems[5]);
if (FAILED(hr))
break;
} while (FALSE);
FREE_INTERNAL(pInternal);
return hr;
}
HRESULT CComponentDataImpl::InitializeClassAdmin()
{
HRESULT hr = S_OK;
BOOL fCancel = FALSE;
#if 0
if (!m_fLoaded)
{
// initialize dialog with a default path
// MH Remember last URL
GetProfileString(L"Appmgr", L"DefCS", L"ADCS:LDAP:", m_szLDAP_Path.GetBuffer(_MAX_PATH), _MAX_PATH);
m_szLDAP_Path.ReleaseBuffer();
m_szGPT_Path = "C:\\GPT\\User\\Applications";
}
#endif
do
{
#if 0
if (!m_fLoaded)
{
// If I have to ask for a path then I must not have recieved one
// from the GPT so the GPT snapin is probably in an invalid
// state. Therefore I should forget about the GPT snapin.
// If I don't do this then the GPT snapin is very likely to
// throw exceptions when I try to send it notifications.
if (m_pIGPTInformation)
{
SAFE_RELEASE(m_pIGPTInformation);
m_pIGPTInformation = NULL;
}
// ask for a path
CInitDlg dlgInit;
dlgInit.m_szLDAP_Path = m_szLDAP_Path;
dlgInit.m_szGPT_Path = m_szGPT_Path;
int iReturn = dlgInit.DoModal();
if (iReturn = IDOK)
{
m_szLDAP_Path= dlgInit.m_szLDAP_Path;
WriteProfileString(L"Appmgr", L"DefCS", m_szLDAP_Path); // MH Remember last URL
m_szGPT_Path = dlgInit.m_szGPT_Path;
}
m_fLoaded = TRUE;
}
#endif
if (!m_pIClassAdmin)
{
// get the IClassAdmin
LPBC pbc = NULL;
hr = CreateBindCtx(0, &pbc);
if (SUCCEEDED(hr))
{
ULONG chEaten = 0;
IMoniker * pmk = NULL;
hr = MkParseDisplayName(pbc, (LPCOLESTR) m_szLDAP_Path, &chEaten, &pmk);
if (SUCCEEDED(hr))
{
hr = pmk->BindToObject(pbc, NULL, IID_IClassAdmin, (void **) & m_pIClassAdmin);
// make sure directories are created:
if (SUCCEEDED(hr))
{
hr = CreateApplicationDirectories();
}
SAFE_RELEASE(pmk);
}
SAFE_RELEASE(pbc);
}
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)
{
// 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_ADD_APP:
case IDM_UPDATE_APP:
{
// put up an hourglass (this could take a while)
CHourglass hourglass;
CString szFileName;
if (nCommandID == IDM_UPDATE_APP)
{
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
if (pInternal)
{
APP_DATA & data = m_AppData[pInternal->m_cookie];
szFileName = data.szIconPath;
FREE_INTERNAL(pInternal);
}
}
CFileDialog cfd(TRUE,
szExtension,
szFileName,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_FILEMUSTEXIST,
szFilter);
if (IDOK == cfd.DoModal())
{
if (nCommandID == IDM_ADD_APP)
{
LONG index;
BOOL bFound = FALSE;
// make sure the user isn't adding something that
// already exists
std::map<long, APP_DATA>::iterator i = m_AppData.begin();
while (i != m_AppData.end())
{
APP_DATA &Data = i->second;
TCHAR Drive [_MAX_DRIVE];
TCHAR Dir [_MAX_DIR];
TCHAR Name [_MAX_FNAME];
TCHAR Ext [_MAX_EXT];
TCHAR szFile[_MAX_PATH];
_tsplitpath( Data.szIconPath, Drive, Dir, Name, Ext );
lstrcpy( szFile, Name );
lstrcat( szFile, Ext );
if (lstrcmpi (szFile, cfd.m_ofn.lpstrFileTitle) == 0)
{
bFound = TRUE;
break;
}
i++;
}
if (bFound)
{
TCHAR szBuffer[256];
TCHAR szTitle[100];
::LoadString(ghInstance, IDS_ADDEXISTSALREADY, szBuffer, 256);
::LoadString(ghInstance, IDS_SNAPIN_DESC, szTitle, 100);
m_pConsole->MessageBox(szBuffer,
szTitle,
MB_OK, NULL);
break;
}
}
// user selected an application
UNIVERSAL_NAME_INFO * pUni = new UNIVERSAL_NAME_INFO;
ULONG cbSize = sizeof(UNIVERSAL_NAME_INFO);
BOOL bAssigned = FALSE;
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);
}
int i;
char * szPackagePath = NULL;
if (S_OK == hr)
{
i = WTOALEN(pUni->lpUniversalName);
szPackagePath = new char [i+1];
WTOA(szPackagePath, pUni->lpUniversalName, i);
}
else
{
i = WTOALEN(cfd.m_ofn.lpstrFile);
szPackagePath = new char [i+1];
WTOA(szPackagePath, cfd.m_ofn.lpstrFile, i);
}
delete[] pUni;
i = WTOALEN((LPCOLESTR)m_szGPT_Path);
char * szFilePath = new char [i+1];
WTOA(szFilePath, m_szGPT_Path, i);
if (nCommandID == IDM_UPDATE_APP)
{
if (SUCCEEDED(RemovePackage(pDataObject, &bAssigned)))
{
hr = AddMSIPackage(pDataObject, szPackagePath, szFilePath, cfd.m_ofn.lpstrFileTitle, &bAssigned);
}
}
else
{
hr = AddMSIPackage(pDataObject, szPackagePath, szFilePath, cfd.m_ofn.lpstrFileTitle, &bAssigned);
}
delete [] szPackagePath;
delete [] szFilePath;
// Notify clients of change
if (SUCCEEDED(hr) && m_pIGPTInformation && bAssigned)
{
m_pIGPTInformation->NotifyClients(FALSE);
}
}
}
break;
case IDM_ADD_FROM_IE:
if (m_pIClassAdmin)
{
// Locate IE4
HKEY hkey;
LONG r;
TCHAR szPath[MAX_PATH];
TCHAR szFullPath[MAX_PATH];
r = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\IE4\\Setup"),
0,
KEY_READ,
&hkey);
if (ERROR_SUCCESS == r)
{
DWORD cbData = MAX_PATH * sizeof(TCHAR);
r = RegQueryValueEx(hkey,
TEXT("Path"),
0,
NULL,
(LPBYTE)szPath,
&cbData);
if (ERROR_SUCCESS == r)
{
ExpandEnvironmentStrings(szPath, szFullPath, MAX_PATH);
lstrcat(szFullPath, TEXT("\\iexplore.exe"));
}
RegCloseKey(hkey);
}
if (ERROR_SUCCESS == r)
{
// Put up dialog informing user to close IE4 when he's ready
// to continue.
TCHAR szBuffer[1024];
TCHAR szCaption[256];
::LoadString(ghInstance, IDS_SPAWNMSG, szBuffer, 1024);
::LoadString(ghInstance, IDS_SPAWNCAPTION, szCaption, 256);
int iReturn = ::MessageBox(NULL,
szBuffer,
szCaption,
MB_YESNO);
if (IDYES == iReturn)
{
// Take the starting time stamp
FILETIME ftStart;
GetSystemTimeAsFileTime(&ftStart);
// Start IE4 and wait for it to be closed
BOOL f;
STARTUPINFO startupinfo;
memset (&startupinfo, 0, sizeof(startupinfo));
PROCESS_INFORMATION processinfo;
f = CreateProcess(NULL,
szFullPath,
NULL, // process attributes
NULL, // thread attributes
FALSE, // bInheritHandles
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS,
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&startupinfo,
&processinfo);
if (f)
{
DWORD dw;
MSG msg;
do
{
dw = MsgWaitForMultipleObjects(1, &processinfo.hProcess, FALSE, INFINITE, QS_ALLINPUT);
// if we don't process Windows messages
// here, we run the risk of causing a
// deadlock
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage(&msg);
}
} while (dw != WAIT_OBJECT_0 );
}
// Take the ending time stamp
FILETIME ftEnd;
GetSystemTimeAsFileTime(&ftEnd);
r = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Code Store Database\\Distribution Units"),
0,
KEY_READ,
&hkey);
if (ERROR_SUCCESS == r)
{
DWORD cSubKeys,
cbMaxSubKeyLen;
r = RegQueryInfoKey(hkey,
NULL, // lpClass
NULL, // lpcbClass
0, // reserved
&cSubKeys,
&cbMaxSubKeyLen,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL);
// Build a list of cab files installed after the
// time stamp and order them by time.
std::list<CABLIST> cablist;
LPTSTR lpName = new TCHAR[cbMaxSubKeyLen + 1];
DWORD iSubKey;
DWORD cbName;
FILETIME ftSubKey;
for (iSubKey = 0; iSubKey < cSubKeys; iSubKey++)
{
HKEY hkSubKey;
cbName = cbMaxSubKeyLen + 1;
r = RegEnumKeyEx(hkey,
iSubKey,
lpName,
&cbName,
0,
NULL,
NULL,
&ftSubKey);
if ((ERROR_SUCCESS == r) &&
(CompareFileTime(&ftStart, &ftSubKey) <= 0) &&
(CompareFileTime(&ftSubKey, &ftEnd) <= 0))
{
CString szSubKey = lpName;
szSubKey += "\\DownloadInformation";
HKEY hkeyInfo;
r = RegOpenKeyEx(hkey,
szSubKey,
0,
KEY_READ,
&hkeyInfo);
if (ERROR_SUCCESS == r)
{
TCHAR szPath[MAX_PATH];
DWORD cbData = MAX_PATH * sizeof(TCHAR);
r = RegQueryValueEx(hkeyInfo,
TEXT("CODEBASE"),
0,
NULL,
(LPBYTE)szPath,
&cbData);
if (ERROR_SUCCESS == r)
{
// add this one to the list
CABLIST cl;
cl.szPath = szPath;
cl.ft = ftSubKey;
cablist.push_back(cl);
}
RegCloseKey(hkeyInfo);
}
}
}
RegCloseKey(hkey);
delete [] lpName;
// sort the list by file time stamps
cablist.sort();
// for each cab file in the list
std::list<CABLIST>::iterator i;
for (i=cablist.begin(); i != cablist.end(); i++)
{
int x;
char * szPackagePath = NULL;
x = WTOALEN(i->szPath);
szPackagePath = new char [x+1];
WTOA(szPackagePath, i->szPath, x);
x = WTOALEN((LPCOLESTR)m_szGPT_Path);
char * szFilePath = new char [x+1];
WTOA(szFilePath, m_szGPT_Path, x);
HWND hwnd;
m_pConsole->GetMainWindow(&hwnd);
// install the cab file
HRESULT hr = UpdateClassStoreFromIE(m_pIClassAdmin, szPackagePath, szFilePath, 1, ftStart, i->ft, hwnd);
ftStart = i->ft;
delete [] szPackagePath;
delete [] szFilePath;
if (S_OK != hr)
{
TCHAR szBuffer[256];
::LoadString(ghInstance, IDS_ADDFAILED, szBuffer, 256);
m_pConsole->MessageBox(szBuffer,
i->szPath,
MB_OK, NULL);
}
else
{
// add an entry to the result pane
PACKAGEDETAIL * pd = new PACKAGEDETAIL;
int n = i->szPath.ReverseFind('/');
CString szName = i->szPath.Mid(n+1);
hr = m_pIClassAdmin->GetPackageDetails((LPOLESTR)((LPCOLESTR) szName), pd);
if (SUCCEEDED(hr))
{
APP_DATA data;
data.szName = pd->pszPackageName;
if (pd->dwActFlags & ACTFLG_Assigned)
{
data.type = DT_ASSIGNED;
}
else
{
data.type = DT_PUBLISHED;
}
data.szPath = pd->pszPath;
data.szIconPath = pd->pszIconPath;
data.szDesc = pd->pszProductName;
data.pDetails = pd;
RESULTDATAITEM resultItem;
resultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
resultItem.str = MMC_CALLBACK;
resultItem.nImage = 1;
data.fBlockDeletion = FALSE;
SetStringData(&data);
m_lLastAllocated++;
m_AppData[m_lLastAllocated] = data;
// BUGBUG - need to make sure that m_lLastAllocated
// hasn't already been used!
resultItem.lParam = m_lLastAllocated;
hr = m_pSnapin->m_pResult->InsertItem(&resultItem);
if (SUCCEEDED(hr))
{
m_AppData[m_lLastAllocated].itemID = resultItem.itemID;
m_pSnapin->m_pResult->Sort(0, 0, -1);
}
// Notify clients of change
if (m_pIGPTInformation && (data.type == DT_ASSIGNED))
{
m_pIGPTInformation->NotifyClients(FALSE);
}
}
}
}
}
}
}
else
{
// put up dialog informing user that IE4 isn't installed
// on this machine
// UNDONE
}
}
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);
m_AppData.erase(i);
}
m_lLastAllocated = 0;
m_pSnapin->EnumerateResultPane(0);
}
break;
case IDM_DEL_APP:
{
BOOL bAssigned = FALSE;
if (SUCCEEDED(RemovePackage(pDataObject, &bAssigned)))
{
// Notify clients of change
if (m_pIGPTInformation && bAssigned)
{
m_pIGPTInformation->NotifyClients(FALSE);
}
}
}
break;
default:
break;
}
return S_OK;
}
HRESULT CComponentDataImpl::AddMSIPackage(LPDATAOBJECT pDataObject, LPSTR szPackagePath, LPSTR szFilePath, LPOLESTR lpFileTitle, BOOL *bAssigned)
{
HRESULT hr = E_FAIL;
if (m_pIClassAdmin)
{
ASSERT(m_pConsole);
{
char szPackageName[MAX_PATH];
DWORD cchPackageName = MAX_PATH;
HWND hwnd;
m_pConsole->GetMainWindow(&hwnd);
hr = UpdateClassStore(m_pIClassAdmin, szPackagePath, szFilePath, szPackageName, cchPackageName, !(*bAssigned), hwnd);
if (S_OK != hr)
{
TCHAR szBuffer[256];
// check to see if the reason is because there
// were no COM Serverss
if (hr == MAKE_HRESULT( SEVERITY_SUCCESS, 0, 1 ))
{
::LoadString(ghInstance, IDS_NOCOMSVR, szBuffer, 256);
}
else
{
::LoadString(ghInstance, IDS_ADDFAILED, szBuffer, 256);
//#if DBG == 1
#if 0
TCHAR szDebugBuffer[256];
DWORD dw = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
0,
szDebugBuffer,
sizeof(szDebugBuffer) / sizeof(szDebugBuffer[0]),
NULL);
if (0 == dw)
{
wsprintf(szDebugBuffer, TEXT("(HRESULT: 0x%lX)"), hr);
}
wcscat(szBuffer, szDebugBuffer);
#endif
}
m_pConsole->MessageBox(szBuffer,
lpFileTitle,
MB_OK, NULL);
}
else
{
PACKAGEDETAIL * pd = new PACKAGEDETAIL;
WCHAR wszPackageName[MAX_PATH];
ATOW(wszPackageName, szPackageName, MAX_PATH);
hr = m_pIClassAdmin->GetPackageDetails(wszPackageName, pd);
//hr = m_pIClassAdmin->GetPackageDetails(lpFileTitle, pd);
if (SUCCEEDED(hr))
{
APP_DATA data;
data.szName = pd->pszPackageName;
if (pd->dwActFlags & ACTFLG_Assigned)
{
data.type = DT_ASSIGNED;
}
else
{
data.type = DT_PUBLISHED;
}
data.szPath = pd->pszPath;
data.szIconPath = pd->pszIconPath;
data.szDesc = pd->pszProductName;
data.pDetails = pd;
data.fBlockDeletion = FALSE;
SetStringData(&data);
m_lLastAllocated++;
m_AppData[m_lLastAllocated] = data;
RESULTDATAITEM resultItem;
resultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
resultItem.str = MMC_CALLBACK;
resultItem.nImage = 1;
// BUGBUG - need to make sure that m_lLastAllocated
// hasn't already been used!
resultItem.lParam = m_lLastAllocated;
hr = m_pSnapin->m_pResult->InsertItem(&resultItem);
if (SUCCEEDED(hr))
{
m_AppData[m_lLastAllocated].itemID = resultItem.itemID;
m_pSnapin->m_pResult->Sort(0, 0, -1);
}
// Notify clients of change
if (data.type == DT_ASSIGNED)
{
*bAssigned = TRUE;
}
}
}
}
}
return hr;
}
HRESULT CComponentDataImpl::RemovePackage(LPDATAOBJECT pDataObject, BOOL *bAssigned)
{
HRESULT hr = E_FAIL;
if (m_pIClassAdmin)
{
ASSERT(m_pConsole);
INTERNAL* pInternal = ExtractInternalFormat(pDataObject);
if (pInternal->m_type == CCT_RESULT)
{
// put up an hourglass (this could take a while)
CHourglass hourglass;
APP_DATA & data = m_AppData[pInternal->m_cookie];
if (!data.fBlockDeletion) // make sure it's not being held open by a property page
{
// We need to make sure it gets removed from
// the GPT before we delete it from the class store.
if (data.pDetails->PathType==DrwFilePath) // MH: don't touch the GPT for anything but Darwin files!
DeleteFile(data.szPath);
if (data.type == DT_ASSIGNED)
*bAssigned = TRUE;
hr = DeletePackageAndDependants(m_pIClassAdmin, (LPOLESTR)((LPCOLESTR) data.szName), data.pDetails);
if (SUCCEEDED(hr))
{
hr = m_pSnapin->m_pResult->DeleteItem(data.itemID, 0);
if (SUCCEEDED(hr))
{
m_AppData.erase(pInternal->m_cookie);
m_pSnapin->m_pResult->Sort(0, 0, -1);
}
}
}
}
FREE_INTERNAL(pInternal);
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
// IExtendControlbar implementation
//
#if 0
STDMETHODIMP CSnapin::SetControlbar(LPCONTROLBAR pControlbar)
{
TRACE(_T("CSnapin::SetControlbar(%ld)\n"),pControlbar);
// Please don't delete this. Required to make sure we pick up the bitmap
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if (pControlbar != NULL)
{
// Hold on to the controlbar interface.
if (m_pControlbar)
{
m_pControlbar->Release();
}
m_pControlbar = pControlbar;
m_pControlbar->AddRef();
HRESULT hr=S_FALSE;
// Create the Toolbar 1
if (!m_pToolbar1)
{
hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&m_pToolbar1));
ASSERT(SUCCEEDED(hr));
// Add the bitmap
m_pbmpToolbar1 = new CBitmap;
m_pbmpToolbar1->LoadBitmap(IDB_TOOLBAR1);
hr = m_pToolbar1->AddBitmap(11, *m_pbmpToolbar1, 16, 16, RGB(255, 0, 255));
ASSERT(SUCCEEDED(hr));
// Add the buttons to the toolbar
hr = m_pToolbar1->AddButtons(ARRAYLEN(SnapinButtons), SnapinButtons);
ASSERT(SUCCEEDED(hr));
}
// TOOLBAR 2
// Create the Toolbar 2
if (!m_pToolbar2)
{
hr = m_pControlbar->Create(TOOLBAR, this, reinterpret_cast<LPUNKNOWN*>(&m_pToolbar2));
ASSERT(SUCCEEDED(hr));
// Add the bitmap
m_pbmpToolbar2 = new CBitmap;
m_pbmpToolbar2->LoadBitmap(IDB_TOOLBAR2);
hr = m_pToolbar2->AddBitmap(36, *m_pbmpToolbar2, 16, 16, RGB(192,192,192));
ASSERT(SUCCEEDED(hr));
// Add the buttons to the toolbar
hr = m_pToolbar2->AddButtons(ARRAYLEN(SnapinButtons2), SnapinButtons2);
ASSERT(SUCCEEDED(hr));
}
}
else
{
SAFE_RELEASE(m_pControlbar);
}
return S_OK;
}
STDMETHODIMP CSnapin::ControlbarNotify(MMC_NOTIFY_TYPE event, long arg, long param)
{
HRESULT hr=S_FALSE;
// Temp temp
static BOOL bSwap=FALSE;
switch (event)
{
#if 0
case MMCN_ACTIVATE:
TRACE(_T("CSnapin::ControlbarNotify - MMCN_ACTIVATE\n"));
// Need to handle this.
// Verify that we can enable and disable buttons based on selection
if (arg == TRUE)
{
m_pToolbar1->SetButtonState(3, BUTTONPRESSED, TRUE);
}
else
{
BOOL bState=FALSE;
hr = m_pToolbar1->GetButtonState(3, BUTTONPRESSED, &bState);
ASSERT(SUCCEEDED(hr));
if (bState)
m_pToolbar1->SetButtonState(3, BUTTONPRESSED, FALSE);
}
break;
#endif // 0
case MMCN_BTN_CLICK:
TRACE(_T("CSnapin::ControlbarNotify - MMCN_BTN_CLICK\n"));
// Temp code
TCHAR szMessage[MAX_PATH];
wsprintf(szMessage,_T("CommandID %ld was not handled by the snapin!!!"),param);
AfxMessageBox(szMessage);
break;
case MMCN_SELECT:
TRACE(_T("CSnapin::ControlbarNotify - MMCN_SEL_CHANGE\n"));
{
LPDATAOBJECT* ppDataObject = reinterpret_cast<LPDATAOBJECT*>(param);
// Attach the toolbars to the window
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar1);
ASSERT(SUCCEEDED(hr));
hr = m_pControlbar->Attach(TOOLBAR, (LPUNKNOWN) m_pToolbar2);
ASSERT(SUCCEEDED(hr));
}
bSwap = !bSwap ;
if (bSwap == TRUE)
{
m_pToolbar1->SetButtonState(1, ENABLED, FALSE); // 1 = CMD ID
m_pToolbar1->SetButtonState(2, CHECKED, TRUE); // 2 = CMD ID
m_pToolbar1->SetButtonState(3, HIDDEN, TRUE); // 3 = CMD ID
m_pToolbar1->SetButtonState(4, INDETERMINATE, TRUE); // 4 = CMD ID
m_pToolbar1->SetButtonState(5, BUTTONPRESSED, TRUE); // 5 = CMD ID
// Just for fun let's add another style
m_pToolbar1->SetButtonState(2, BUTTONPRESSED, TRUE); // 4 = CMD ID
}
else
{
BOOL bState=FALSE;
hr = m_pToolbar1->GetButtonState(1, ENABLED, &bState);
ASSERT(SUCCEEDED(hr));
if (bState == FALSE)
m_pToolbar1->SetButtonState(1, ENABLED, TRUE);
// Above is the correct way
m_pToolbar1->SetButtonState(2, CHECKED, FALSE);
m_pToolbar1->SetButtonState(3, HIDDEN, FALSE);
m_pToolbar1->SetButtonState(4, INDETERMINATE, FALSE);
m_pToolbar1->SetButtonState(5, BUTTONPRESSED, FALSE);
// Better remove the additional style
m_pToolbar1->SetButtonState(2, BUTTONPRESSED, FALSE); // 4 = CMD ID
}
break;
default:
ASSERT(FALSE); // Unhandle event
}
return S_OK;
}
#endif
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 == *pB) ? 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
switch (nCol)
{
case 0:
*pnResult = dataA.szName.CompareNoCase(dataB.szName);
break;
case 1:
*pnResult = dataA.szType.CompareNoCase(dataB.szType);
break;
case 2:
*pnResult = dataA.pDetails->Locale - dataB.pDetails->Locale;
break;
case 3:
*pnResult = dataA.szMach.CompareNoCase(dataB.szMach);
break;
case 4:
*pnResult = dataA.szDesc.CompareNoCase(dataB.szDesc);
break;
case 5:
*pnResult = dataA.szIconPath.CompareNoCase(dataB.szIconPath);
break;
}
return S_OK;
}