2513 lines
76 KiB
C++
2513 lines
76 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
|
||
|
|
||
|
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;
|
||
|
}
|