|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: S H U T I L . C P P
//
// Contents: Various shell utilities to be used by the connections shell
//
// Notes:
//
// Author: jeffspr 21 Oct 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
//+---------------------------------------------------------------------------
//
// Function: HrDupeShellStringLength
//
// Purpose: Duplicate a string using SHAlloc, so we can return it to the
// shell. This is required because the shell typically releases
// the strings that we pass it (so we need to use their
// allocator).
//
// Arguments:
// pszInput [in] String to duplicate
// cchInput [in] Count of characters to copy (not including null term)
// ppszOutput [out] Return pointer for the newly allocated string.
//
// Returns:
//
// Author: jeffspr 21 Oct 1997
//
// Notes:
//
HRESULT HrDupeShellStringLength( PCWSTR pszInput, ULONG cchInput, PWSTR * ppszOutput) { HRESULT hr = S_OK;
Assert(pszInput); Assert(ppszOutput);
ULONG cbString = (cchInput + 1) * sizeof(WCHAR);
// Allocate a new POLESTR block, which the shell can then free.
//
PWSTR pszOutput = (PWSTR) SHAlloc(cbString);
// If the alloc failed, return E_OUTOFMEMORY
//
if (NULL != pszOutput) { // Copy the memory into the alloc'd block
//
CopyMemory(pszOutput, pszInput, cbString); pszOutput[cchInput] = 0; *ppszOutput = pszOutput; } else { *ppszOutput = NULL; hr = E_OUTOFMEMORY; }
TraceHr(ttidError, FAL, hr, FALSE, "HrDupeShellStringLength"); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrLoadPopupMenu
//
// Purpose: Load a popup menu as the first child of a loadable parent
// menu
//
// Arguments:
// hinst [in] Our instance handle
// id [in] ID of the parent menu
// phmenu [out] Return pointer for the popup menu
//
// Returns:
//
// Author: jeffspr 27 Oct 1997
//
// Notes:
//
HRESULT HrLoadPopupMenu( HINSTANCE hinst, UINT id, HMENU * phmenu) { HRESULT hr = S_OK; HMENU hmParent = NULL; HMENU hmPopup = NULL;
Assert(id); Assert(hinst); Assert(phmenu);
// Load the parent menu
//
hmParent = LoadMenu(hinst, MAKEINTRESOURCE(id)); if (NULL == hmParent) { AssertSz(FALSE, "Can't load parent menu in HrLoadPopupMenu"); hr = HrFromLastWin32Error(); } else { // Load the popup from the parent (first submenu), then
// remove the parent menu
//
hmPopup = GetSubMenu(hmParent, 0); RemoveMenu(hmParent, 0, MF_BYPOSITION); DestroyMenu(hmParent); }
if (phmenu) { *phmenu = hmPopup; }
TraceHr(ttidError, FAL, hr, FALSE, "HrLoadPopupMenu"); return hr; }
HRESULT HrGetMenuFromID( HMENU hmenuMain, UINT uID, HMENU * phmenu) { HRESULT hr = S_OK; HMENU hmenuReturn = NULL; MENUITEMINFO mii = {0};
Assert(hmenuMain); Assert(uID); Assert(phmenu);
mii.cbSize = sizeof(mii); mii.fMask = MIIM_SUBMENU; mii.cch = 0; // just in case
if (!GetMenuItemInfo(hmenuMain, uID, FALSE, &mii)) { hr = E_FAIL; } else { hmenuReturn = mii.hSubMenu; }
if (phmenu) { *phmenu = mii.hSubMenu; }
TraceHr(ttidError, FAL, hr, FALSE, "HrGetMenuFromID"); return hr; }
INT IMergePopupMenus( HMENU hmMain, HMENU hmMerge, int idCmdFirst, int idCmdLast) { HRESULT hr = S_OK; int iCount = 0; int idTemp = 0; int idMax = idCmdFirst; HMENU hmFromId = NULL;
for (iCount = GetMenuItemCount(hmMerge) - 1; iCount >= 0; --iCount) { MENUITEMINFO mii = {0};
mii.cbSize = sizeof(mii); mii.fMask = MIIM_ID | MIIM_SUBMENU; mii.cch = 0; // just in case
mii.hSubMenu = NULL;
if (!GetMenuItemInfo(hmMerge, iCount, TRUE, &mii)) { TraceHr(ttidError, FAL, E_FAIL, FALSE, "GetMenuItemInfo failed in iMergePopupMenus"); continue; }
hr = HrGetMenuFromID(hmMain, mii.wID, &hmFromId); if (SUCCEEDED(hr)) { idTemp = Shell_MergeMenus( hmFromId, mii.hSubMenu, 0, idCmdFirst, idCmdLast, MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
if (idMax < idTemp) { idMax = idTemp; } } else { TraceHr(ttidError, FAL, E_FAIL, FALSE, "HrGetMenuFromId failed in iMergePopupMenus"); continue; } }
return idMax; }
VOID MergeMenu( HINSTANCE hinst, UINT idMainMerge, UINT idPopupMerge, LPQCMINFO pqcm) { HMENU hmMerge = NULL; UINT idMax = 0; UINT idTemp = 0;
Assert(pqcm); Assert(idMainMerge || idPopupMerge); Assert(hinst);
idMax = pqcm->idCmdFirst;
if (idMainMerge && (SUCCEEDED(HrLoadPopupMenu(hinst, idMainMerge, &hmMerge)))) { Assert(hmMerge);
if (hmMerge) { idMax = Shell_MergeMenus( pqcm->hmenu, hmMerge, pqcm->indexMenu, pqcm->idCmdFirst, pqcm->idCmdLast, MM_SUBMENUSHAVEIDS);
DestroyMenu(hmMerge); } }
if (idPopupMerge && (hmMerge = LoadMenu(hinst, MAKEINTRESOURCE(idPopupMerge))) != NULL) { idTemp = IMergePopupMenus( pqcm->hmenu, hmMerge, pqcm->idCmdFirst, pqcm->idCmdLast);
if (idMax < idTemp) { idMax = idTemp; }
DestroyMenu(hmMerge); }
pqcm->idCmdFirst = idMax; }
//+---------------------------------------------------------------------------
//
// Function: GenerateEvent
//
// Purpose: Generate a Shell Notification event.
//
// Arguments:
// lEventId [in] The event ID to post
// pidlFolder [in] Folder pidl
// pidlIn [in] First pidl that we reference
// pidlNewIn [in] If needed, the second pidl.
//
// Returns:
//
// Author: jeffspr 16 Dec 1997
//
// Notes:
//
VOID GenerateEvent(LONG lEventId, const LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlIn, LPCITEMIDLIST pidlNewIn) { // Build an absolute pidl from the folder pidl + the object pidl
//
LPITEMIDLIST pidl = ILCombinePriv(pidlFolder, pidlIn); if (pidl) { // If we have two pidls, call the notify with both
//
if (pidlNewIn) { // Build the second absolute pidl
//
LPITEMIDLIST pidlNew = ILCombinePriv(pidlFolder, pidlNewIn); if (pidlNew) { // Make the notification, and free the new pidl
//
SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, pidlNew); FreeIDL(pidlNew); } } else { // Make the single-pidl notification
//
SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, NULL); }
// Always refresh, then free the newly allocated pidl
//
SHChangeNotifyHandleEvents(); FreeIDL(pidl); } }
VOID ForceRefresh(HWND hwnd) { LPSHELLBROWSER psb = FileCabinet_GetIShellBrowser(hwnd); LPSHELLVIEW psv = NULL;
// Did we get the shellview?
#if 0 // We can't require this, since we may need to refresh without a folder
// actually being open
AssertSz(psb, "FileCabinet_GetIShellBrowser failed in ForceRefresh()"); #endif
if (psb && SUCCEEDED(psb->QueryActiveShellView(&psv))) { // $$TODO: Flush the connection list
//
Assert(psv); if (psv) { psv->Refresh(); psv->Release(); } } else { // $$TODO: Refresh the connection list.
} }
//+---------------------------------------------------------------------------
//
// Function: HrShellView_GetSelectedObjects
//
// Purpose: Get the selected data objects. We only care about the first
// one (we'll ignore the rest)
//
// Arguments:
// hwnd [in] Our window handle
// papidlSelection [out] Return array for selected pidls
// lpcidl [out] Count of returned pidls
//
// Returns: S_OK if 1 or more items are selected.
// S_FALSE if 0 items are selected
// OLE HRESULT otherwise
//
// Author: jeffspr 13 Jan 1998
//
// Notes:
//
HRESULT HrShellView_GetSelectedObjects( HWND hwnd, LPCITEMIDLIST ** papidlSelection, UINT * lpcidl) { HRESULT hr = S_OK; LPCITEMIDLIST * apidl = NULL; UINT cpidl = 0;
// Get the selected object list from the shell
//
cpidl = ShellFolderView_GetSelectedObjects(hwnd, &apidl);
// If the GetSelectedObjects failed, NULL out the return
// params.
//
if (-1 == cpidl) { cpidl = 0; apidl = NULL; hr = E_OUTOFMEMORY; } else { // If no items were selected, return S_FALSE
//
if (0 == cpidl) { Assert(!apidl); hr = S_FALSE; } }
// Fill in the out params
//
*papidlSelection = apidl; *lpcidl = cpidl;
TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "HrShellView_GetSelectedObjects"); return hr; }
|