mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
429 lines
10 KiB
429 lines
10 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
|
|
|