// 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 #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(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(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(&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(&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(static_cast(bmp16x16)), reinterpret_cast(static_cast(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::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 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(&m_pScope)); ASSERT(hr == S_OK); hr = pUnknown->QueryInterface(IID_IConsole, reinterpret_cast(&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(static_cast(bmp16x16)), reinterpret_cast(static_cast(bmp32x32)), 0, RGB(255,0,255)); return S_OK; } STDMETHODIMP CComponentDataImpl::CreateComponent(LPCOMPONENT* ppComponent) { ASSERT(ppComponent != NULL); CComObject* pObject; CComObject::CreateInstance(&pObject); ASSERT(pObject != NULL); m_pSnapin = pObject; // Store IComponentData pObject->SetIComponentData(this); return pObject->QueryInterface(IID_IComponent, reinterpret_cast(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(&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* pObject; CComObject::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(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::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 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::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; 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::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 ::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(&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(&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(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; }