Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1998 lines
61 KiB

//---------------------------------------------------------------------------
// Init the Cabinet (ie the top level browser).
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Includes...
#include "cabinet.h"
#include "cabwnd.h"
#include "tree.h"
#include "rcids.h"
#include "drivlist.h"
#include <dbt.h> // for WM_DEVICECHANGE
#include <shellp.h> // for Read/WriteCabinetState
const TCHAR c_szOpen[] = TEXT("open");
const TCHAR c_szExplore[] = TEXT("explore");
//---------------------------------------------------------------------------
// Global to everybody.
int g_iTreeUpIndex = -1;
void Cabinet_HandleFileSysChange(PFileCabinet this, LPNMOTFSEINFO lpnm);
void Cabinet_InitGlobalMetrics(WPARAM, LPTSTR);
void CheckWinIniForAssocs(void);
extern UINT g_msgMSWheel;
LPCTSTR _PathDisplayName(LPCTSTR pszPath)
{
// Change the window title.
//
if (PathIsRoot(pszPath))
return pszPath;
return (LPCTSTR)PathFindFileName(pszPath);
}
void _SetCabinetTitle(PFileCabinet pfc, LPOneTreeNode lpnd, LPCITEMIDLIST pidl)
{
TCHAR szT[MAX_PATH + 40];
TCHAR szViewTitle[MAX_PATH + 40];
LPTSTR lpsz = szT;
if (!g_CabState.fFullPathTitle || !OTGetDisplayName(pidl,lpsz))
{
LPSHELLFOLDER psfParent = OTBindToFolder(lpnd->lpnParent);
if (psfParent)
{
STRRET strret;
psfParent->lpVtbl->GetDisplayNameOf(psfParent,
OTGetFolderID(lpnd), SHGDN_NORMAL, &strret);
StrRetToStrN(lpsz, ARRAYSIZE(szT), &strret, OTGetFolderID(lpnd));
psfParent->lpVtbl->Release(psfParent);
}
else
{
OTGetNodeName(lpnd, lpsz, ARRAYSIZE(szT) );
}
}
if (pfc->hwndViewTitle) {
TCHAR szContentsOf[80];
LoadString(hinstCabinet, IDS_CONTENTSOF, szContentsOf, ARRAYSIZE(szContentsOf));
wsprintf(szViewTitle, szContentsOf, lpsz);
SetWindowText(pfc->hwndViewTitle, szViewTitle);
}
if (pfc->hwndTree && Cabinet_IsVisible(pfc->hwndTree)) {
LoadString(hinstCabinet, IDS_FILECABINET, szViewTitle, ARRAYSIZE(szViewTitle));
lstrcat(szViewTitle, TEXT(" - "));
lstrcat(szViewTitle, szT);
lpsz = szViewTitle;
}
SetWindowText(pfc->hwndMain, lpsz);
}
void _WindowIconFromImagelist(HWND hwndMain, int nIndex, BOOL bLarge)
{
HICON hIcon, hOldIcon;
// if we're using the def open icon or if extracting fails,
// use the icon we've already created.
if (nIndex == g_nDefOpenSysIndex ||
!(hIcon = ImageList_ExtractIcon(hinstCabinet,
bLarge ? g_himlSysLarge : g_himlSysSmall,
nIndex))) {
if (bLarge)
hIcon = g_hIconDefOpenLarge;
else
hIcon = g_hIconDefOpenSmall;
}
#ifdef WINICON_DEBUG
// bug in user putting up the wrong icon.
// this block helps show the bug
{
static BOOL foo = FALSE;
HDC hdc = GetDC(NULL);
DrawIcon(hdc, 0, foo ? 0 : 100, hIcon);
ReleaseDC(NULL, hdc);
DebugMsg(DM_TRACE, TEXT("_WindowIconFromImagelIST : index = %d"), nIndex);
foo = !foo;
}
#endif
hOldIcon = (HICON)SendMessage(hwndMain, WM_SETICON, bLarge, (LPARAM)hIcon);
if (hOldIcon &&
(hOldIcon != hIcon) &&
(hOldIcon != g_hIconDefOpenSmall) &&
(hOldIcon != g_hIconDefOpenLarge))
{
DestroyIcon(hOldIcon);
}
}
// this needs now to be exported to tree.c because it gets filesys notifications
int _SetCabinetIcons(PFileCabinet pfc, LPOneTreeNode lpnd, int nOldIndex)
{
int nSysNormalIndex, nSysIndex;
if (!lpnd || (pfc->hwndTree && IsWindowVisible(pfc->hwndTree))) {
nSysIndex = g_iTreeUpIndex;
} else {
// BUGBUG... this is because the compiler has a bug in
// generating our code.
nSysNormalIndex = g_nDefNormalSysIndex;
OTGetImageIndex(lpnd, &nSysNormalIndex, &nSysIndex);
if (nSysIndex == g_nDefOpenSysIndex && nSysNormalIndex != g_nDefNormalSysIndex)
nSysIndex = nSysNormalIndex;
}
// set the small one first to prevent user stretch blt on the large one
if (nOldIndex != nSysIndex)
{
_WindowIconFromImagelist(pfc->hwndMain, nSysIndex, FALSE);
_WindowIconFromImagelist(pfc->hwndMain, nSysIndex, TRUE);
pfc->iImage = nSysIndex;
}
return(nSysIndex);
}
//---------------------------------------------------------------------------
void FileCabinet_GetViewRect(PFileCabinet this, RECT * prc)
{
static const int s_rgnViews[] = {1, 0, 1, FCIDM_STATUS, 1, FCIDM_TOOLBAR, 0, 0};
// static const int s_rgnViews[] = {1, 0, 1, FCIDM_STATUS, 0, 0 }; // , 1, FCIDM_TOOLBAR, 0, 0};
UINT uSplit;
GetEffectiveClientRect(this->hwndMain, prc, (LPINT)s_rgnViews);
// We have to subtract a little more if the "map" is visible
//
if (this->hwndTree && Cabinet_IsVisible(this->hwndTree))
{
uSplit = this->TreeSplit;
if (uSplit > (UINT) (prc->right - (prc->left + g_cxSizeFrame - g_cxEdge)))
{
uSplit = prc->right - (prc->left + g_cxSizeFrame - g_cxEdge);
}
prc->left += uSplit + g_cxSizeFrame - (g_cxEdge/2);
if (!g_CabState.fDontShowDescBar)
{
prc->top += this->iTitleHeight + 1;
}
}
}
void Cabinet_GetWindowRect(CFileCabinet * this, UINT uWindow, LPRECT prc)
{
switch (uWindow)
{
case FCW_TOOLBAR:
GetWindowRect(this->hwndToolbar, prc);
break;
case FCW_STATUS:
GetWindowRect(this->hwndStatus, prc);
break;
case FCW_TREE:
if (this->hwndTree)
GetWindowRect(this->hwndTree, prc);
else {
prc->left = prc->right = prc->top = prc->bottom = 0;
}
break;
case FCW_TABS:
case FCW_VIEW:
FileCabinet_GetViewRect(this, prc);
return; // don't do MapWindowPoints() below
default:
DebugMsg(DM_ERROR, TEXT("bogus FCW_"));
return;
}
// Convert the toolbar, status and tree windows to client coordinates
//
MapWindowPoints(NULL, this->hwndMain, (LPPOINT)prc, 2);
}
void Cabinet_RegisterDropTarget(PFileCabinet pfc, BOOL fRegister)
{
Assert(pfc->psv);
if (fRegister)
{
// We are registering it.
LPDROPTARGET pdtg = NULL;
Assert(!pfc->bDropTarget);
if (SUCCEEDED(pfc->psv->lpVtbl->QueryInterface(pfc->psv, &IID_IDropTarget, &pdtg)))
{
if (SUCCEEDED(SHRegisterDragDrop(pfc->hwndMain, pdtg)))
{
pfc->bDropTarget = TRUE;
}
pdtg->lpVtbl->Release(pdtg);
}
}
else
{
// We are revoking it.
if (pfc->bDropTarget)
{
SHRevokeDragDrop(pfc->hwndMain);
pfc->bDropTarget = FALSE;
}
}
}
//---------------------------------------------------------------------------
// Set up a viewer for a new directory.
// If there is no "specific" viewer, then use the default file system view.
// Note that all new information (like the browser window and the psv object)
// just gets put into the pfc structure.
//
HRESULT _BrowseNewDir(PFileCabinet pfc, LPOneTreeNode lpnd, LPCITEMIDLIST pidl)
{
RECT rcView;
LPSHELLVIEW psvNew = NULL; // assume error
BOOL fOpeningFolder = ((pfc->psv==NULL) && (pfc->hwndTree==NULL));
HRESULT hres;
LPSHELLFOLDER pshf = NULL;
int nIconIndex;
//
// LATER: Remove ifndef portion later
//
#define FIX_14332
#ifdef FIX_14332
HWND hwndViewNew = NULL;
struct {
LPOneTreeNode lpndOpen;
LPSHELLVIEW psv;
LPITEMIDLIST pidl;
} viewPrev = { NULL, NULL, NULL };
#endif // FIX_14332
hres = OTBindToFolderEx(lpnd, &pshf);
if (SUCCEEDED(hres))
{
hres = pshf->lpVtbl->CreateViewObject(pshf, pfc->hwndMain, &IID_IShellView, &psvNew);
pshf->lpVtbl->Release(pshf);
}
if (FAILED(hres))
{
#ifdef DEBUG
TCHAR szPath[MAX_PATH];
OTGetDisplayName(pidl, szPath);
DebugMsg(DM_ERROR, TEXT("cabwnd.c _BrowseNewDir - ERRROR: BindTo (%s) failed"), szPath);
MessageBeep(0);
#endif
return hres;
}
Assert(psvNew);
nIconIndex = _SetCabinetIcons(pfc, lpnd, -1); // this binds!
_SetCabinetTitle(pfc, lpnd, pidl);
SendMessage(pfc->hwndToolbar, TB_ENABLEBUTTON, FCIDM_PREVIOUSFOLDER, lpnd == s_lpnRoot ? FALSE : TRUE);
#ifndef FIX_14332
//
// Deactivate the view window, if any.
//
if (pfc->psv)
pfc->psv->lpVtbl->UIActivate(pfc->psv, SVUIA_DEACTIVATE);
//
// We should make it sure that we no longer has a shared menu.
//
Assert(pfc->hmenuCur == Cabinet_MenuTemplate(TRUE, (BOOL)pfc->hwndTree));
// Clean up the old browser object
//
if (pfc->psv)
{
// Destory pfc->hwndView and Release pfc->psv, pidl, lpndOpen
Cabinet_ReleaseShellView(pfc);
Assert(pfc->hwndView==NULL);
Assert(pfc->psv==NULL);
Assert(pfc->lpndOpen==NULL);
Assert(pfc->pidl==NULL);
GetSystemMenu(pfc->hwndMain, TRUE);
//
// We need this assert just in case IShellView::DestroyViewWindow
// sets the menu back.
//
Assert(pfc->hmenuCur == Cabinet_MenuTemplate(TRUE, (BOOL)pfc->hwndTree));
}
//
// Set pidl, lpnd, psv correctly before calling ISV::CreateViewWindow.
//
pfc->pidl = ILClone(pidl);
OTAddRef(lpnd);
pfc->lpndOpen = lpnd;
pfc->psv = psvNew;
FileCabinet_GetViewRect(pfc, &rcView);
hres=psvNew->lpVtbl->CreateViewWindow(psvNew, NULL, &pfc->fs, &pfc->sb,
&rcView, &pfc->hwndView);
#else // FIX_14332
//
// Unplug the old view object.
//
if (pfc->psv)
{
Cabinet_RegisterDropTarget(pfc, FALSE);
//
// WARNING: We should not alter the state of the view window
// (since we don't own it). All the optimization should be
// done though psvPrev parameter of ISV::CreateViewWindow
//
// SendMessage(pfc->hwndView, WM_SETREDRAW, 0, 0L);
//
viewPrev.lpndOpen = pfc->lpndOpen;
viewPrev.psv = pfc->psv;
viewPrev.pidl = pfc->pidl;
pfc->lpndOpen = NULL;
pfc->psv = NULL;
pfc->pidl = NULL;
pfc->hwndView = NULL;
}
//
// Set pidl, lpnd, psv correctly before calling ISV::CreateViewWindow.
//
pfc->pidl = ILClone(pidl);
OTAddRef(lpnd);
pfc->lpndOpen = lpnd;
pfc->psv = psvNew;
FileCabinet_GetViewRect(pfc, &rcView);
//
// Create the new view object. Note that we don't let it put the window
// handle to pfc->hwndView directly. Having only pfc->psv without
// pfc->hwndView indicates that we are in the middle of the view
// switching. We set pfc->hwndView after destroying the old view
// window.
//
// if there's no previous view, pass in &pfc->hwndView so that the
// bestfitstuff will work. it calls back to resize us, andwe need
// to have their handle in our variable so that we can resize them back
hres=psvNew->lpVtbl->CreateViewWindow(psvNew, viewPrev.psv, &pfc->fs, &pfc->sb,
&rcView, viewPrev.psv ? &hwndViewNew : &pfc->hwndView);
//
// Destroy the old view object.
//
if (viewPrev.psv)
{
viewPrev.psv->lpVtbl->UIActivate(viewPrev.psv, SVUIA_DEACTIVATE);
viewPrev.psv->lpVtbl->DestroyViewWindow(viewPrev.psv);
if (viewPrev.lpndOpen)
{
OTRelease(viewPrev.lpndOpen);
}
if (viewPrev.pidl)
{
ILFree(viewPrev.pidl);
}
viewPrev.psv->lpVtbl->Release(viewPrev.psv);
pfc->hwndView = hwndViewNew;
}
#endif // FIX_14332
//
// Destroy the new view object, if ISV::CreateViewWindow failed.
//
if (FAILED(hres))
{
Cabinet_ReleaseShellView(pfc);
Assert(pfc->hwndView==NULL);
Assert(pfc->psv==NULL);
Assert(pfc->lpndOpen==NULL);
Assert(pfc->pidl==NULL);
return hres;
}
//
// Notify the desktop that we are browsing a new dir
//
FolderList_RegisterWindow(pfc->hwndMain, pfc->pidl);
//
// Register the cabinet window as a drop target.
//
Cabinet_RegisterDropTarget(pfc, TRUE);
//
// Set the focus to the view window.
//
if (pfc->uFocus == FOCUS_VIEW)
{
//
// We need to actually set the focus. The subsequent UIActivate
// call is typically not necessary because the view usually
// process the WM_SETFOCUS message and activate itself appropriately.
//
SetFocus(pfc->hwndView);
pfc->psv->lpVtbl->UIActivate(pfc->psv, SVUIA_ACTIVATE_FOCUS);
}
else
{
pfc->psv->lpVtbl->UIActivate(pfc->psv, SVUIA_ACTIVATE_NOFOCUS);
}
// Call this a second time to handle cases where the icon may change
// during the processing. This typically happens when we gain access
// to a network location that was previously not available...
// we only do it when no tree view as the explorer has a static icon...
if (pfc->hwndTree == NULL)
_SetCabinetIcons(pfc, lpnd, nIconIndex); // this binds!
UpdateWindow(pfc->hwndMain);
return hres;
}
//
// We should save the old dir, so if hwndView does
// not get created we display a message and go back. If that
// fails, we might want to run back to the Desktop as a
// default.
//
// Returns:
// S_OK, if successfully changed or switched the view.
// S_FALSE, if failed to change, and SETPATH is posted.
// others, all fallback mechanism failed.
//
HRESULT _BrowseNewDirRetry(PFileCabinet pfc, LPOneTreeNode lpnd, LPCITEMIDLIST pidl)
{
HRESULT hres;
static const ITEMIDLIST c_idlRoot = { {0} }; // empty idl.
//
// Retry only if we are browsing from one folder to another.
//
if (pfc->psv)
{
LPITEMIDLIST pidlPrev = ILClone(pfc->pidl);
//
// First attempt.
//
hres = _BrowseNewDir(pfc, lpnd, pidl);
if (FAILED(hres) && (hres!=(E_OUTOFMEMORY)))
{
//
// First attempt failed. Try the previoud folder.
//
if (pfc->hwndTree)
{
//
// We have the tree.
//
HTREEITEM hti = Tree_GetItemFromIDList(pfc->hwndTree, pidlPrev);
DebugMsg(DM_TRACE, TEXT("sh TR _BNDR: first _BrowseNewDir failed -- selecting previous item in the tree (%x)"), hti);
//
// If the previous folder is already gone (hti==NULL),
// set the focus to the root.
//
if (Cabinet_SetPath(pfc, CSP_REPOST,
hti ? pidlPrev : (LPITEMIDLIST)&c_idlRoot))
{
hres = (S_FALSE);
}
}
else
{
LPOneTreeNode lpndPrev = OTGetNodeFromIDList(pidlPrev, OTGNF_TRYADD);
DebugMsg(DM_TRACE, TEXT("sh TR _BNDR: first _BrowseNewDir failed (calling _BrowseNewDir for the previous folder)"));
if (lpndPrev)
{
//
// Second attept, open the previously selected folder.
//
hres = _BrowseNewDir(pfc, lpndPrev, pidlPrev);
if (FAILED(hres) && (hres!=(E_OUTOFMEMORY)))
{
//
// Second attempt failed.
//
LPOneTreeNode lpndRoot = OTGetRootNode();
LPITEMIDLIST pidlRoot = OTCreateIDListFromNode(lpndRoot);
DebugMsg(DM_TRACE, TEXT("sh TR _BNDR: second _BrowseNewDir failed (calling _BrowseNewDir for the desktop)"));
if (pidlRoot)
{
//
// Third attempt, opening the desktop.
//
hres = _BrowseNewDir(pfc, lpndPrev, pidlPrev);
ILFree(pidlRoot);
}
}
OTRelease(lpndPrev);
}
}
}
ILFree(pidlPrev);
}
else
{
hres = _BrowseNewDir(pfc, lpnd, pidl);
if (FAILED(hres) && (hres!=(E_OUTOFMEMORY)))
{
// It failed.
if (pfc->hwndTree)
{
//
// It failed, but we have the tree. Select the desktop.
//
DebugMsg(DM_TRACE, TEXT("sh TR _BNDR: _BrowseNewDir failed (no previous folder)"));
if (Cabinet_SetPath(pfc, CSP_REPOST, (LPITEMIDLIST)&c_idlRoot))
{
hres = (S_FALSE);
}
}
}
}
return hres;
}
//---------------------------------------------------------------------------
// Create the appropriate view window based on the hti.
//
HRESULT Cabinet_ChangeView(PFileCabinet pfc, LPOneTreeNode lpnd,
LPCITEMIDLIST pidl, BOOL fNew)
{
HRESULT hres;
MSG msg;
if (pfc->fChangingFolder)
{
//
// This function should not be re-entered. We'll come here only
// if the shell has a bug.
//
Assert(0);
return E_UNEXPECTED;
}
pfc->fChangingFolder = TRUE;
// Gotta change viewers.
// NB The state ptrs won't be valid after a DestroyWindow so we
// must copy them.
//
if (!fNew)
{
// we are switching the folder.
if (pfc->psv)
{
// Save the current state if we are switching around in the tree
Cabinet_SaveState(pfc->hwndMain, NULL, FALSE, FALSE, FALSE);
pfc->psv->lpVtbl->GetCurrentInfo(pfc->psv, &pfc->fs);
}
// Now create the window with the new information.
// Stomp on the autosize flag (this should only ever
// be used when creating a new window.
pfc->fs.fFlags &= ~FWF_BESTFITWINDOW;
}
// We never use this single selection mode from the cabinet.
pfc->fs.fFlags &= ~FWF_SINGLESEL;
// The view specific info is not passed between views of different
// types.
// REVIEW - we need to save this information.
// REVIEW - we need to rethink this whole process.
// Now we've copied all the pertinent info it's safe to destroy
// the old view. Check whether the viewer creation was successful
//
{
DECLAREWAITCURSOR;
SetWaitCursor();
hres = _BrowseNewDirRetry(pfc, lpnd, pidl);
ResetWaitCursor();
}
if (SUCCEEDED(hres))
{
//
// Note that _BrowseNewDirRetry may return S_FALSE after posting
// a message CWM_SETPATH.
//
if (pfc->hwndView)
{
if (lpnd && pfc->wv.bToolBar)
DriveList_UpdatePath(pfc, FALSE);
}
}
else
{
DebugMsg(DM_ERROR, TEXT("c.cvw: Unable to create view window (%x)."), hres);
pfc->fPostCloseLater = TRUE;
}
Assert(pfc->fChangingFolder);
pfc->fChangingFolder = FALSE;
if (pfc->fPostCloseLater)
{
//
// It failed to create the view window. Post WM_CLOSE message
// if we haven't done it already.
//
if (!PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE, PM_NOREMOVE))
{
//
// Popup a message box only this is caused by out-of-memory.
//
if (hres==(E_OUTOFMEMORY))
{
SHOutOfMemoryMessageBox(pfc->hwndMain, NULL,
MB_OK|MB_ICONHAND);
}
PostMessage(pfc->hwndMain, WM_CLOSE, 0, 0L);
DebugMsg(DM_TRACE, TEXT("ca TR - Cabinet_ChangeView -- posting WM_CLOSE"));
}
}
return hres;
}
//---------------------------------------------------------------------------
// Get the given folder to view the given path.
BOOL Cabinet_SetPath(PFileCabinet pfc, UINT type, LPITEMIDLIST pid)
{
BOOL fSuccess = FALSE;
// The path can either be a handle or a string and we can either
// handle the message now or post it back to ourselves and handle
// it later.
// The default is to post on a string.
if (type & CSP_REPOST)
{
HANDLE hPath;
DWORD dwProcId;
GetWindowThreadProcessId(pfc->hwndMain, &dwProcId);
hPath = SHAllocShared(pid,ILGetSize(pid),dwProcId);
// Post it on.
if (!PostMessage(pfc->hwndMain, CWM_SETPATH, 0, (LPARAM)hPath))
{
SHFreeShared(hPath,dwProcId);
return(FALSE);
}
return TRUE;
}
else
{
LPOneTreeNode lpnd;
// Don't post it on - handle it now.
// Set the path for the view.
// if the tree exists, use it.. this will help consistency.
lpnd = OTGetNodeFromIDList(pid, OTGNF_TRYADD );
if (lpnd)
{
if (pfc->hwndTree)
{
// We need Tree_Build here to create nodes that
// do not currently exist
// HACK: Note that Tree_Build selects the item
Tree_Build(pfc, pid, FALSE, TRUE);
//
// We need to get the one tree node again, since
// Tree_Build may have invalidated it.
//
OTRelease(lpnd);
lpnd = OTGetNodeFromIDList(pid, OTGNF_NEARESTMATCH | OTGNF_TRYADD);
}
if (lpnd)
{
fSuccess = SUCCEEDED(Cabinet_ChangeView(pfc, lpnd, pid, FALSE));
OTRelease(lpnd); // cabient_changeview will addref
}
}
return fSuccess;
}
}
void _DisableMenuItems(PFileCabinet pfc, HMENU hmenuPopup)
{
//
// Disable all the menu items.
//
EnableMenuItem(hmenuPopup, FCIDM_DELETE, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hmenuPopup, FCIDM_RENAME, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hmenuPopup, FCIDM_PROPERTIES, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hmenuPopup, FCIDM_MOVE, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hmenuPopup, FCIDM_LINK, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hmenuPopup, FCIDM_COPY, MF_BYCOMMAND|MF_GRAYED);
}
void Cabinet_EnableMenuItemsByAttribs(PFileCabinet pfc, HMENU hmenuPopup, UINT dwAttr)
{
if (hmenuPopup == Cabinet_GetMenuFromID(pfc->hmenuCur, FCIDM_MENU_FILE))
{
if (dwAttr & SFGAO_CANDELETE)
EnableMenuItem(hmenuPopup, FCIDM_DELETE, MF_BYCOMMAND|MF_ENABLED);
if (dwAttr & SFGAO_CANRENAME)
EnableMenuItem(hmenuPopup, FCIDM_RENAME, MF_BYCOMMAND|MF_ENABLED);
if (dwAttr & SFGAO_HASPROPSHEET)
EnableMenuItem(hmenuPopup, FCIDM_PROPERTIES, MF_BYCOMMAND|MF_ENABLED);
}
else if (hmenuPopup == Cabinet_GetMenuFromID(pfc->hmenuCur, FCIDM_MENU_EDIT))
{
if (dwAttr & SFGAO_CANMOVE)
EnableMenuItem(hmenuPopup, FCIDM_MOVE, MF_BYCOMMAND|MF_ENABLED);
if (dwAttr & SFGAO_CANLINK)
EnableMenuItem(hmenuPopup, FCIDM_LINK, MF_BYCOMMAND|MF_ENABLED);
if (dwAttr & SFGAO_CANCOPY)
EnableMenuItem(hmenuPopup, FCIDM_COPY, MF_BYCOMMAND|MF_ENABLED);
}
}
void _InitMenuPopup2(PFileCabinet pfc, HMENU hmenuPopup, UINT uFlags)
{
// the first set are handled by us ragardless of whether or not we
// have focus.
#define FC_CHECKED (MF_BYCOMMAND|MF_CHECKED)
#define FC_UNCHECKED (MF_BYCOMMAND|MF_UNCHECKED)
if ((uFlags & MI_VIEW) == MI_VIEW) {
// VIEW only menus
CheckMenuItem(hmenuPopup, FCIDM_VIEWSTATUSBAR,
pfc->wv.bStatusBar ? FC_CHECKED : FC_UNCHECKED);
#ifdef WANT_TABS
CheckMenuItem(hmenuPopup, FCIDM_VIEWTABS,
pfc->bTabs ? FC_CHECKED : FC_UNCHECKED);
#endif
#ifdef WANT_MENUONOFF
} else if ((uFlags & MI_SYSTEM) == MI_SYSTEM) {
// SYSTEM only menus
CheckMenuItem(hmenuPopup, FCIDM_VIEWMENU,
pfc->wv.bMenuBar ? FC_CHECKED : FC_UNCHECKED);
#endif // WANT_MENUONOFF
}
// menu stuff common to SYSTEM and VIEW menus
if (uFlags & (MI_SYSTEM|MI_VIEW)) {
if (pfc->hwndToolbar) {
CheckMenuItem(hmenuPopup, FCIDM_VIEWTOOLBAR,
pfc->wv.bToolBar ? FC_CHECKED : FC_UNCHECKED);
}
}
if (uFlags == MI_POPUP && pfc->hwndTree) {
// if uFlags hasn't been dirtied by anything else, then there's still a chance it's
// the find menu.
HMENU hmenu = Cabinet_GetMenuFromID(pfc->hmenuCur, FCIDM_MENU_TOOLS);
MENUITEMINFO mii;
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_ID;
if (GetMenuItemInfo(hmenu, FCIDM_MENU_FIND, FALSE, &mii) &&
(mii.hSubMenu == hmenuPopup)) {
if (!SHRestricted(REST_NOFIND)) {
DebugMsg(DM_TRACE, TEXT("cabinet InitMenuPopup of Find commands"));
if (pfc->pcmFind)
{
pfc->pcmFind->lpVtbl->Release(pfc->pcmFind);
pfc->pcmFind = NULL;
}
pfc->pcmFind = SHFind_InitMenuPopup(mii.hSubMenu, pfc->hwndMain, FCIDM_MENU_TOOLS_FINDFIRST, FCIDM_MENU_TOOLS_FINDLAST);
}
}
}
// Remove the find menu if restrictions are in effect.
if (uFlags == (MI_POPUP|MI_TOOLS))
{
MENUITEMINFO mii;
if (SHRestricted(REST_NOFIND)) {
TCHAR szDummy[MAX_PATH];
DebugMsg(DM_TRACE, TEXT("c.imp2: Find menu restricted - removing."));
DeleteMenu(hmenuPopup, FCIDM_MENU_FIND, MF_BYCOMMAND);
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_TYPE;
mii.dwTypeData = szDummy;
GetMenuItemInfo(hmenuPopup, 0, TRUE, &mii);
if (mii.fType & MFT_SEPARATOR)
{
DeleteMenu(hmenuPopup, 0, MF_BYPOSITION);
}
}
}
// the rest are optionally handled by us
if (pfc->uFocus == FOCUS_VIEW)
return;
_DisableMenuItems(pfc, hmenuPopup);
if (pfc->lpndOpen)
{
UINT dwAttr = OTGetAttributesOf(pfc->lpndOpen);
Cabinet_EnableMenuItemsByAttribs(pfc, hmenuPopup, dwAttr);
}
}
LRESULT Cabinet_OnInitMenuPopup(PFileCabinet pfc, HMENU hSubMenu, int nIndex, BOOL fSystemMenu)
{
MENUITEMINFO mii;
UINT uFlags = MI_POPUP;
if (fSystemMenu)
{
uFlags |= MI_SYSTEM;
}
else if (pfc->bMainMenuInit)
{
// This is a popup from the main menu bar (not necessarily
// a top level popup)
mii.cbSize = SIZEOF(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU|MIIM_ID;
if (GetMenuItemInfo(pfc->hmenuCur, nIndex, TRUE, &mii)
&& mii.hSubMenu==hSubMenu)
{
switch (mii.wID)
{
case FCIDM_MENU_FILE:
uFlags |= MI_FILE;
break;
case FCIDM_MENU_EDIT:
uFlags |= MI_EDIT;
break;
case FCIDM_MENU_VIEW:
uFlags |= MI_VIEW;
break;
case FCIDM_MENU_TOOLS:
uFlags |= MI_TOOLS;
break;
case FCIDM_MENU_HELP:
uFlags |= MI_HELP;
break;
default:
break;
}
}
}
else
{
// We assume that any menu not associated with the main menu
// is a context menu
uFlags |= MI_CONTEXT;
}
_InitMenuPopup2(pfc, hSubMenu, uFlags);
return 0L;
}
//---------------------------------------------------------------------------
LRESULT Cabinet_OnInitMenu(PFileCabinet pfc, WPARAM wParam, LPARAM lParam)
{
HMENU hmMain, hmFile;
#if 0
MENUITEMINFO miiBackTo;
#endif
hmMain = GetMenu(pfc->hwndMain);
if (!hmMain || hmMain!=pfc->hmenuCur || hmMain!=(HMENU)wParam)
{
pfc->bMainMenuInit = FALSE;
return(1L);
}
pfc->bMainMenuInit = TRUE;
#if 0
miiBackTo.cbSize = SIZEOF(MENUITEMINFO);
miiBackTo.fMask = MIIM_STATE|MIIM_SUBMENU;
#endif
hmFile = Cabinet_GetMenuFromID(hmMain, FCIDM_MENU_FILE);
if (hmFile)
{
if (pfc->pidl)
{
LPCITEMIDLIST pidlLast = ILFindLastID(pfc->pidl);
EnableMenuItem(hmFile,
FCIDM_PREVIOUSFOLDER,
pidlLast == pfc->pidl
? MF_GRAYED|MF_BYCOMMAND
: MF_ENABLED|MF_BYCOMMAND);
}
}
return(0L);
}
//---------------------------------------------------------------------------
// Handle sizing of a folder window.
BOOL Cabinet_NewSize(PFileCabinet pfc, BOOL fEnsureVisible)
{
RECT rc;
HDWP hdwp;
RECT rc2;
Assert(pfc);
hdwp = BeginDeferWindowPos(7);
if (!hdwp)
return FALSE;
// REVIEW, do this right...
if (pfc->hwndStatus && pfc->wv.bStatusBar)
{
SendMessage(pfc->hwndStatus, WM_SIZE, 0, 0L);
}
// REVIEW, do this right...
if (pfc->hwndToolbar && pfc->wv.bToolBar)
{
SendMessage(pfc->hwndToolbar, WM_SIZE, 0, 0L);
}
// REVIEW, do this right...
// Get the space between the toolbar and the statusbar.
if (pfc->hwndTree)
{
HTREEITEM hti;
// bugbug, calculate the real height of the titles
// This should all be calculated in one place
//
Cabinet_GetWindowRect(pfc, FCW_TABS, &rc);
rc.right = rc.left - g_cxSizeFrame + (g_cxEdge/2);
rc.left = 0;
// Note the description bar gets moved even if invisible
rc2 = rc;
rc2.bottom = rc2.top - 1;
rc2.top = rc2.bottom - pfc->iTitleHeight;
hdwp = DeferWindowPos(hdwp, pfc->hwndTreeTitle, NULL, rc2.left,
rc2.top, rc2.right-rc2.left, rc2.bottom - rc2.top,
SWP_NOZORDER |SWP_NOACTIVATE);
hdwp = DeferWindowPos(hdwp, pfc->hwndTree, NULL, rc.left,
rc.top, rc.right - rc.left, rc.bottom - rc.top,
SWP_NOZORDER | SWP_NOACTIVATE);
if (fEnsureVisible) {
hti = TreeView_GetSelection(pfc->hwndTree);
if (hti)
TreeView_EnsureVisible(pfc->hwndTree, hti);
}
}
Cabinet_GetWindowRect(pfc, FCW_VIEW, &rc);
if (pfc->hwndViewTitle) {
// Note the description bar gets moved even if invisible
rc2 = rc;
rc2.bottom = rc2.top - 1;
rc2.top = rc2.bottom - pfc->iTitleHeight;
hdwp = DeferWindowPos(hdwp, pfc->hwndViewTitle, NULL, rc2.left,
rc2.top, rc2.right-rc2.left, rc2.bottom - rc2.top,
SWP_NOZORDER |SWP_NOACTIVATE);
}
if (pfc->hwndView)
{
// Size the viewers window.
#ifdef WANT_TABS
if (pfc->bTabs)
{
Cabinet_GetWindowRect(pfc, FCW_TABS, &rc);
hdwp = DeferWindowPos(hdwp, pfc->hwndTabs, NULL, rc.left,
rc.top, rc.right - rc.left, rc.bottom - rc.top,
SWP_NOZORDER | SWP_NOACTIVATE);
}
#endif
// keep the view window on top of the tabs window
// (ie don't use SWP_NOZORDER)
hdwp = DeferWindowPos(hdwp, pfc->hwndView, HWND_TOP, rc.left,
rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE);
}
EndDeferWindowPos(hdwp);
return TRUE;
}
//---------------------------------------------------------------------------
// Handle sizing of a folder window.
LRESULT Cabinet_OnSize(PFileCabinet pfc, WPARAM wSizeType)
{
Assert(pfc);
// Ignore minimise.
if (wSizeType == SIZE_MINIMIZED)
return 0;
Cabinet_NewSize(pfc, FALSE);
}
//---------------------------------------------------------------------------
// Process the message by propagating it to all of our child windows
void Cabinet_PropagateMessage(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{
HWND hwndChild;
for (hwndChild = GetWindow(hwnd, GW_CHILD); hwndChild != NULL;
hwndChild = GetWindow(hwndChild, GW_HWNDNEXT))
{
SendMessage(hwndChild, uMessage, wParam, lParam);
}
}
//---------------------------------------------------------------------------
// Process the WM_WININICHANGE message by propagating it to all of our
// child windows
void Cabinet_OnWinIniChange(PFileCabinet pfc, WPARAM wParam, LPARAM lParam)
{
#ifdef DEBUG
DebugMsg(DM_TRACE, TEXT("c.c_owic: Win Ini Change..."));
if (wParam)
DebugMsg(DM_TRACE, TEXT("c.c_owic: wParam %#08x."), wParam);
else if (lParam && *(LPTSTR)lParam)
DebugMsg(DM_TRACE, TEXT("c.c_owic: %s section "), (LPTSTR)lParam);
#endif
if (lParam && (lstrcmpi((LPTSTR)lParam, c_szExtensions) == 0))
{
DebugMsg(DM_TRACE, TEXT("dwp: Extensions may have changed."));
CheckWinIniForAssocs();
}
#ifdef WINNT
//
// NT has a control panel applet that allows users to change the
// environment with-which to spawn new applications. On NT, we need
// to pick up that environment change so that anything we spawn in
// the future will pick up those updated environment values.
//
if (lParam && (lstrcmpi((LPTSTR)lParam, c_szEnvironment) == 0))
{
PVOID pEnv ;
RegenerateUserEnvironment(&pEnv, TRUE);
}
#endif
Cabinet_PropagateMessage(pfc->hwndMain, WM_WININICHANGE, wParam, lParam);
// Lets see if we need to change the size of the toolbar fonts...
if (pfc->hwndDrives &&
((wParam == 0) ||
(wParam == SPI_SETICONTITLELOGFONT) ||
(wParam == SPI_SETNONCLIENTMETRICS)))
{
// This is sortof bugus as we depend on the the fact that this
// function does not process any of the members...
MEASUREITEMSTRUCT mi;
UINT cyItem;
DriveList_MeasureItem(pfc, &mi);
cyItem = (UINT)SendMessage(pfc->hwndDrives, CB_GETITEMHEIGHT, 0, 0);
// Make sure the font is set correctly, as it could have changed and
// still have the same height
SendMessage(pfc->hwndDrives, WM_SETFONT,
(WPARAM)(HFONT)SendMessage(pfc->hwndToolbar, WM_GETFONT, 0, 0),
0);
// We need to set the height of the items.
if (cyItem != mi.itemHeight)
{
SendMessage(pfc->hwndDrives, CB_SETITEMHEIGHT, 0, mi.itemHeight);
SendMessage(pfc->hwndDrives, CB_SETITEMHEIGHT, (WPARAM)-1, mi.itemHeight);
}
}
if (pfc->hwndTree && wParam == SPI_SETNONCLIENTMETRICS)
{
TreeView_SetImageList(pfc->hwndTree, g_himlSysSmall, TVSIL_NORMAL);
}
// Make sure it is sized correctly!
SendMessage(pfc->hwndMain, WM_SIZE, 0, 0L);
}
LRESULT Cabinet_ForwardViewMsg(PFileCabinet pfc, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return pfc->hwndView ? SendMessage(pfc->hwndView, uMsg, wParam, lParam) : 0;
}
void Cabinet_ForwardMenuMsg(PFileCabinet pfc, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (pfc->pcmTree) {
IContextMenu2 *pcm2;
if (SUCCEEDED(pfc->pcmTree->lpVtbl->QueryInterface(pfc->pcmTree, &IID_IContextMenu2, &pcm2)))
{
pcm2->lpVtbl->HandleMenuMsg(pcm2, uMsg, wParam, lParam);
pcm2->lpVtbl->Release(pcm2);
}
} else {
Cabinet_ForwardViewMsg(pfc, uMsg, wParam, lParam);
}
}
BOOL CursorInTitles(PFileCabinet pfc, BOOL fCursorPos)
{
DWORD dw;
RECT rc;
POINT pt;
if (pfc->hwndTreeTitle) {
if (fCursorPos)
{
GetCursorPos(&pt);
}
else
{
dw = GetMessagePos();
pt.x = LOWORD(dw);
pt.y = HIWORD(dw);
}
GetWindowRect(pfc->hwndTreeTitle, &rc);
rc.top--;// grow the rect because we have some space between title and view
rc.bottom+=2;
if (PtInRect(&rc, pt))
return TRUE;
GetWindowRect(pfc->hwndViewTitle, &rc);
rc.top--;// grow the rect because we have some space between title and view
rc.bottom+=2;
if (PtInRect(&rc, pt))
return TRUE;
}
return FALSE;
}
void Cabinet_GlobalStateChange(PFileCabinet pfc)
{
CABINETSTATE sCabState;
// Reading the cabinet state handled by the shell32.dll now
if ( ReadCabinetState( &sCabState, SIZEOF(sCabState) ) )
{
g_CabState = sCabState;
}
//
// Ignore this message if lpndOpen has not been set yet.
//
if (pfc->lpndOpen)
{
_SetCabinetTitle(pfc, pfc->lpndOpen, pfc->pidl);
SetWindowStates(pfc);
}
}
void Tree_KeyboardContextMenu(PFileCabinet pfc);
//
// This code intercept the WM_CONTEXTMENU message from USER and popups
// up the context menu of the folder itself when the user clicks the icon
// at the left-top corner of the frame (only when it is in the folder mode).
//
BOOL Cabinet_OnContextMenu(PFileCabinet pfc, WPARAM wParam, LPARAM lParam)
{
BOOL fProcessed = FALSE;
DebugMsg(DM_TRACE, TEXT("CABWND.C Got WM_CONTEXTMENU"));
if (!pfc->hwndTree) {
if (pfc->lpndOpen && pfc->pidl && SendMessage(pfc->hwndMain, WM_NCHITTEST, 0, lParam)==HTSYSMENU)
{
LPOneTreeNode lpnParent;
Assert(pfc->lpndOpen);
Assert(pfc->pidl);
lpnParent = OTGetParent(pfc->lpndOpen);
if (lpnParent)
{
LPSHELLFOLDER psfParent = OTBindToFolder(lpnParent);
OTRelease(lpnParent);
if (psfParent)
{
LPCONTEXTMENU pcm;
HRESULT hres;
LPCITEMIDLIST pidlLast = ILFindLastID(pfc->pidl);
hres = psfParent->lpVtbl->GetUIObjectOf(psfParent,
pfc->hwndMain, 1, &pidlLast, &IID_IContextMenu, NULL, &pcm);
if (SUCCEEDED(hres))
{
HMENU hmenu = LoadMenu(hinstCabinet, MAKEINTRESOURCE(MENU_SYSPOPUP));
HMENU hpopup;
if (hmenu && (NULL != (hpopup=GetSubMenu(hmenu, 0))))
{
UINT idCmd;
UINT ipos;
LPCTSTR pszDisable = (pfc->hwndTree) ? c_szExplore : c_szOpen;
UINT citems = GetMenuItemCount(hpopup);
pcm->lpVtbl->QueryContextMenu(pcm, hpopup, citems,
IDSYSPOPUP_FIRST, IDSYSPOPUP_LAST, 0);
//
// We need to remove "open" and "explore"
//
// Notes: We assume the context menu handles
// GetCommandString AND they are top-level menuitems.
//
for (ipos=GetMenuItemCount(hpopup)-1; ipos>=citems; ipos--)
{
idCmd = GetMenuItemID(hpopup, ipos);
if (IsInRange(idCmd, IDSYSPOPUP_FIRST, IDSYSPOPUP_LAST))
{
TCHAR szVerb[40];
hres = pcm->lpVtbl->GetCommandString(pcm,
idCmd-IDSYSPOPUP_FIRST,
GCS_VERB,
NULL,
(LPSTR)szVerb,
ARRAYSIZE(szVerb));
#ifdef UNICODE
if (FAILED(hres) || *szVerb == TEXT('\0'))
{
CHAR szVerbAnsi[40];
hres = pcm->lpVtbl->GetCommandString(pcm,
idCmd-IDSYSPOPUP_FIRST,
GCS_VERBA,
NULL,
szVerbAnsi,
ARRAYSIZE(szVerbAnsi));
MultiByteToWideChar(CP_ACP, 0,
szVerbAnsi, -1,
szVerb, ARRAYSIZE(szVerb));
}
#endif
if (SUCCEEDED(hres))
{
if (lstrcmp(szVerb,pszDisable)==0)
{
DeleteMenu(hpopup, ipos, MF_BYPOSITION);
}
}
}
}
idCmd = TrackPopupMenu(hpopup,
TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
LOWORD(lParam), HIWORD(lParam), 0, pfc->hwndMain, NULL);
switch(idCmd)
{
case 0:
break; // canceled
case IDSYSPOPUP_CLOSE:
PostMessage(pfc->hwndMain, WM_CLOSE, 0, 0L);
break;
default:
{
TCHAR szPath[MAX_PATH];
CMINVOKECOMMANDINFOEX ici = {
SIZEOF(CMINVOKECOMMANDINFOEX),
0L,
pfc->hwndMain,
(LPSTR)MAKEINTRESOURCE(idCmd - IDSYSPOPUP_FIRST),
NULL,
NULL,
SW_NORMAL,
};
#ifdef UNICODE
CHAR szPathAnsi[MAX_PATH];
SHGetPathFromIDListA(pfc->pidl, szPathAnsi);
SHGetPathFromIDList(pfc->pidl, szPath);
ici.lpDirectory = szPathAnsi;
ici.lpDirectoryW = szPath;
ici.fMask |= CMIC_MASK_UNICODE;
#else
SHGetPathFromIDList(pfc->pidl, szPath);
ici.lpDirectory = szPath;
#endif
pcm->lpVtbl->InvokeCommand(pcm,
(LPCMINVOKECOMMANDINFO)&ici);
break;
}
}
DestroyMenu(hmenu);
}
pcm->lpVtbl->Release(pcm);
}
psfParent->lpVtbl->Release(psfParent);
}
}
fProcessed=TRUE;
}
} else if ((((HWND)wParam) == pfc->hwndTree) && (lParam == -1)) {
Tree_KeyboardContextMenu(pfc);
fProcessed = TRUE;
}
return fProcessed;
}
BOOL CALLBACK CloseParentsEnumProc(HWND hwnd, LPARAM lParam)
{
PFileCabinet pfc = (PFileCabinet)lParam;
// test for parents of folder windows
if (Cabinet_IsFolderWindow(hwnd) && (pfc->hwndMain != hwnd))
{
HANDLE hidl;
DWORD dwProcId;
UINT uidlSize;
dwProcId = GetCurrentProcessId();
uidlSize = ILGetSize(pfc->pidl);
hidl = SHAllocShared(NULL, SIZEOF(BOOL)+uidlSize, dwProcId);
if (hidl)
{
LPBYTE lpb;
lpb = SHLockShared(hidl, dwProcId);
if (lpb)
{
*(BOOL *)lpb = TRUE; // Yes, parent comparison
hmemcpy(lpb+SIZEOF(BOOL),pfc->pidl,uidlSize);
SHUnlockShared(lpb);
if (SendMessage(hwnd, CWM_COMPAREPIDL, (WPARAM)dwProcId, (LPARAM)hidl))
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
SHFreeShared(hidl,dwProcId);
}
}
return TRUE;
}
void Cabinet_SelectPath(PFileCabinet pfc, UINT uFlags, LPCTSTR pszItem)
{
LPITEMIDLIST pidl;
IShellFolder * psfOpen;
ULONG chEaten;
WCHAR wszItem[MAX_PATH];
if (IsBadInterfacePtr(pfc->psv, IShellView))
{
return;
}
psfOpen = OTBindToFolder(pfc->lpndOpen);
StrToOleStrN(wszItem, ARRAYSIZE(wszItem), pszItem, -1);
if (!psfOpen)
{
return;
}
if (SUCCEEDED(psfOpen->lpVtbl->ParseDisplayName(psfOpen,
NULL, NULL, wszItem, &chEaten, &pidl, NULL)))
{
pfc->psv->lpVtbl->SelectItem(pfc->psv, pidl, uFlags);
SHFree(pidl);
}
psfOpen->lpVtbl->Release(psfOpen);
}
void PushRecursion(PFileCabinet pfc)
{
if (pfc->hwndTree) {
pfc->uRecurse++;
}
}
void PopRecursion(PFileCabinet pfc)
{
if (pfc && pfc->hwndTree) {
Assert(pfc->uRecurse);
if (pfc->uRecurse == 1) {
if (pfc->fPostCloseLater)
{
MSG msg;
if (!PeekMessage(&msg, NULL, WM_CLOSE, WM_CLOSE, PM_NOREMOVE)) {
PostMessage(pfc->hwndMain, WM_CLOSE, 0, 0L);
DebugMsg(DM_TRACE, TEXT("ca TR - PopRecursion -- posting WM_CLOSE"));
}
} else {
if (pfc->fUpdateTree && !pfc->fChangingFolder) {
// If any of FSNotify message is ignored during this function,
// update the tree now.
Tree_RefreshAll(pfc);
pfc->fUpdateTree = FALSE;
}
}
}
pfc->uRecurse--;
}
}
BOOL IsDescendent(HWND hwndParent, HWND hwndChild)
{
do {
if (hwndParent == hwndChild)
return TRUE;
} while (hwndChild = GetParent(hwndChild));
return FALSE;
}
BOOL FilterMouseWheel(PFileCabinet pfc, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
POINT pt;
HWND hwndT = NULL;
LRESULT lRes = 0;
RECT rc;
// Don't do any funky processing if this isn't the original message
// generated by the driver, infinite loop city!
if (uMsg == g_msgMSWheel) {
if (hwnd != pfc->hwndMain)
return FALSE;
} else {
if (hwnd != GetFocus())
return FALSE;
}
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
#ifdef DONT_SCROLL_PANE_UNDER_MOUSE
if (GetKeyState(VK_SHIFT) < 0) {
// Data zooming case - defined as working on the window under the cursor
GetWindowRect(pfc->hwndMain, &rc);
// Map to the point under one of our child windows. If it is
// completely outside our window then bail.
if (PtInRect(&rc, pt))
hwndT = WindowFromPoint(pt);
else
return FALSE;
} else {
// Scrolling case - defined as going to the focus window
hwndT = GetFocus();
}
#else
hwndT = WindowFromPoint(pt);
if (hwndT != pfc->hwndTree && pfc->hwndView) {
if (uMsg == g_msgMSWheel) // Need propogation to direct child?
{
if (IsDescendent(pfc->hwndView, hwndT))
hwndT = pfc->hwndView;
else
hwndT = NULL;
}
}
// If we didn't hit either then pass it to the focus window
if (!hwndT) {
// Bail completely in the data zooming case if the mouse lies outside
// our main window.
if (GetKeyState(VK_SHIFT) < 0) {
GetWindowRect(pfc->hwndMain, &rc);
if (!PtInRect(&rc, pt))
return FALSE;
}
hwndT = GetFocus();
// If the focus window is a child of the view window, then pass
// the message to the view window.
if (uMsg == g_msgMSWheel) // Need propogation to direct child?
{
if (pfc->hwndView && IsDescendent(pfc->hwndView, hwndT))
hwndT = pfc->hwndView;
}
}
#endif
lRes = SendMessage(hwndT, uMsg, wParam, lParam);
#ifdef NASHVILLE
// If the message wasn't handled and shift is down, map
// to history navigation.
if (!lRes && GetKeyState(VK_SHIFT) < 0) {
TLNavigate(&pfc->_tlGlobal, ((int)wParam < 0) ? HLNF_NAVIGATINGBACK : HLNF_NAVIGATINGFORWARD);
}
#endif
return TRUE;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK CabinetWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
POINT pt;
RECT rc;
int i;
PFileCabinet pfc = GetPFC(hwnd);
LRESULT lres = 0;
// First process messages which do not require pfc
switch(uMsg)
{
case WM_CREATE:
return Cabinet_OnCreate(hwnd, (LPCREATESTRUCT)lParam);
case WM_ENDSESSION:
if (wParam)
{
Cabinet_SaveState(hwnd, NULL, FALSE, TRUE, FALSE);
if (pfc)
{
Cabinet_ReleaseShellView(pfc);
}
ShowWindow(hwnd, SW_HIDE);
}
break;
case WM_DESTROY:
return Cabinet_OnDestroy(hwnd);
// Don't go to default wnd proc for this one...
case WM_INPUTLANGCHANGEREQUEST:
if (wParam)
return DefWindowProc(hwnd, uMsg, wParam, lParam);
else
return(LRESULT)0L;
}
if (!pfc)
goto DoDefault;
switch (uMsg)
{
case WM_CLOSE:
OTUnregister(pfc->hwndMain);
FolderList_UnregisterWindow(pfc->hwndMain);
if (pfc->fChangingFolder || pfc->uRecurse)
{
pfc->fPostCloseLater = TRUE;
DebugMsg(DM_TRACE, TEXT("ca TR - CabinetWndProc got WM_CLOSE while pfc->fChanging==TRUE"));
break;
}
if (pfc->pidl && (GetKeyState(VK_SHIFT) < 0))
EnumWindows(CloseParentsEnumProc, (LPARAM)pfc);
lres = Cabinet_SaveState(hwnd, NULL, FALSE, FALSE, TRUE);
break;
case CWM_SELECTITEM:
if (!IsBadInterfacePtr(pfc->psv, IShellView))
{
LPITEMIDLIST pidl;
pidl = SHLockShared((HANDLE)lParam, GetCurrentProcessId());
if (pidl)
{
pfc->psv->lpVtbl->SelectItem(pfc->psv, pidl, wParam);
SHUnlockShared(pidl);
SHFreeShared((HANDLE)lParam,GetCurrentProcessId()); // Receiver responsible for freeing
}
}
break;
case CWM_SELECTPATH:
Cabinet_SelectPath(pfc, wParam, (LPCTSTR)lParam);
break;
case CWM_COMPAREPIDL:
if (pfc->pidl) {
LPBYTE lpb;
lpb = SHLockShared((HANDLE)lParam, (DWORD)wParam);
if (lpb)
{
BOOL fParent;
LPITEMIDLIST pidl;
fParent = *(BOOL *)lpb;
pidl = (LPITEMIDLIST)(lpb + SIZEOF(BOOL));
if (fParent)
lres = ILIsParent(pfc->pidl, pidl, FALSE);
else
lres = ILIsEqual(pfc->pidl, pidl);
SHUnlockShared(lpb);
}
}
break;
case CWM_COMPAREROOT:
// Just forward this to our desktop window
lres = (SendMessage(v_hwndDesktop, uMsg, wParam, lParam));
break;
case CWM_CLONEPIDL:
if (pfc->pidl)
{
lres = (LRESULT)SHAllocShared(pfc->pidl,
ILGetSize(pfc->pidl),
wParam);
}
break;
case CWM_SETPATH:
//
// If we are about changing the folder, we can't process this message.
//
if (!pfc->fChangingFolder)
{
MSG msg;
LPITEMIDLIST pidl;
pidl = SHLockShared((HANDLE)lParam, GetCurrentProcessId());
//
// If another CWM_SETPATH is in the queue, we can't process this message.
//
if (!PeekMessage(&msg, hwnd, CWM_SETPATH, CWM_SETPATH, PM_NOREMOVE|PM_NOYIELD))
{
if (pidl)
{
//
// NOTES: We should always return TRUE in this case,
// even though Cabinet_SetPath failed. Returning TRUE
// simply means we have processed this message.
//
Cabinet_SetPath(pfc, wParam, pidl);
lres = TRUE; // We have processed this message.
}
}
if (pidl)
{
SHUnlockShared(pidl);
SHFreeShared((HANDLE)lParam,GetCurrentProcessId());
}
}
break;
case CWM_GETISHELLBROWSER:
lres = ((LRESULT)&(pfc->sb));
break;
case CWM_ONETREEFSE:
PushRecursion(pfc);
Cabinet_HandleFileSysChange(pfc, (LPNMOTFSEINFO)lParam);
PopRecursion(pfc);
break;
case CWM_GLOBALSTATECHANGE:
Cabinet_GlobalStateChange(pfc);
break;
case WM_ACTIVATE:
if (pfc->hwndView)
SendMessage(pfc->hwndView, uMsg, wParam, lParam);
if (wParam == WA_INACTIVE)
break;
OTActivate();
// go through
case WM_SETFOCUS:
//
// Set the focus to whoever supposed to have.
//
switch (pfc->uFocus) {
case FOCUS_TREE:
Assert(pfc->hwndTree);
SetFocus(pfc->hwndTree);
break;
case FOCUS_VIEW:
if (pfc->hwndView) {
SetFocus(pfc->hwndView);
}
break;
case FOCUS_DRIVES:
Assert(pfc->hwndDrives);
SetFocus(pfc->hwndDrives);
break;
}
break;
case WM_GETMINMAXINFO:
if (IsWindowVisible(pfc->hwndMain) && pfc->hwndView)
{
GetWindowRect(pfc->hwndMain, &rc);
i = rc.bottom - rc.top;
GetWindowRect(pfc->hwndView, &rc);
i = i - (rc.bottom - rc.top);
if (i > 0)
((MINMAXINFO *)lParam)->ptMinTrackSize.y = i;
}
break;
case WM_SIZE:
lres = Cabinet_OnSize(pfc, wParam);
break;
case WM_COMMAND:
Cabinet_OnCommand(pfc, wParam, lParam);
break;
case WM_INITMENU:
Cabinet_OnInitMenu(pfc, wParam, lParam);
break;
case WM_INITMENUPOPUP:
Cabinet_OnInitMenuPopup(pfc, (HMENU)wParam, LOWORD(lParam), HIWORD(lParam));
Cabinet_ForwardMenuMsg(pfc, uMsg, wParam, lParam);
break;
case WM_MENUSELECT:
if (!Cabinet_OnMenuSelect(pfc, wParam, lParam, 0))
{
if ((GET_WM_MENUSELECT_FLAGS(wParam, lParam)&MF_POPUP)
|| IsInRange(LOWORD(wParam), FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST))
{
Cabinet_ForwardViewMsg(pfc, uMsg, wParam, lParam);
}
}
break;
case WM_ENTERMENULOOP:
case WM_EXITMENULOOP:
Cabinet_ForwardViewMsg(pfc, uMsg, wParam, lParam);
break;
case WM_DRAWITEM:
#define lpdis ((LPDRAWITEMSTRUCT)lParam)
if (lpdis->CtlID == FCIDM_DRIVELIST)
DriveList_DrawItem(pfc, lpdis);
else
Cabinet_ForwardMenuMsg(pfc, uMsg, wParam, lParam);
#undef lpdis
break;
case WM_MEASUREITEM:
#define lpmis ((LPMEASUREITEMSTRUCT)lParam)
if (lpmis->CtlID == FCIDM_DRIVELIST)
DriveList_MeasureItem(pfc, lpmis);
else
Cabinet_ForwardMenuMsg(pfc, uMsg, wParam, lParam);
#undef lpmis
break;
#if 0
// make the drive list paint with grey background
case WM_CTLCOLORLISTBOX:
if (GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg) == pfc->hwndDrives)
{
lParam = GET_WM_CTLCOLOR_MPS(
GET_WM_CTLCOLOR_HDC(wParam, lParam, uMsg),
GET_WM_CTLCOLOR_HWND(wParam, lParam, uMsg), CTLCOLOR_STATIC);
lres = (BOOL)DefWindowProc(hwnd, uMsg, wParam, lParam);
}
break;
#endif
case WM_NOTIFY:
Assert(wParam == ((LPNMHDR)lParam)->idFrom);
lres = Cabinet_OnNotify(pfc, (LPNMHDR)lParam);
break;
// this keeps our window from comming to the front on button down
// instead, we activate the window on the up click
// we only want this for the tree and the view window
// (the view window does this itself)
case WM_MOUSEACTIVATE:
GetCursorPos(&pt);
if (pfc->hwndTree)
GetWindowRect(pfc->hwndTree, &rc);
if (LOWORD(lParam) == HTCLIENT &&
pfc->hwndTree && PtInRect(&rc, pt)) {
lres = MA_NOACTIVATE;
} else
goto DoDefault;
break;
case WM_LBUTTONDOWN:
if (CursorInTitles(pfc, FALSE)) {
goto DoDefault;
} else {
lres = Tree_HandleSplitDrag(pfc, LOWORD(lParam));
break;
}
case WM_SETCURSOR:
if (pfc->iWaitCount) {
//DebugMsg(DM_TRACE,"########### SET WAIT CURSOR WM_SETCURSOR %d", pfc->iWaitCount);
SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
} else if (CursorInTitles(pfc, TRUE)) {
SetCursor(LoadCursor(NULL, IDC_ARROW));
} else
goto DoDefault;
lres = TRUE;
break;
case WM_DRAWCLIPBOARD:
if (pfc->hwndNextViewer) {
SendMessage(pfc->hwndNextViewer, uMsg, wParam, lParam);
}
DebugMsg(DM_TRACE, TEXT("CABINET: Nuking tree cut state"));
if (pfc->htiCut) {
Tree_NukeCutState(pfc);
}
break;
case WM_CHANGECBCHAIN:
DebugMsg(DM_TRACE, TEXT("CABINET: change cbchain %d %d %d"), wParam, lParam, pfc->hwndNextViewer);
if ((HWND)wParam == pfc->hwndNextViewer) {
pfc->hwndNextViewer = (HWND)lParam;
lres =TRUE;
} else {
if (pfc->hwndNextViewer)
lres = SendMessage(pfc->hwndNextViewer, uMsg, wParam, lParam);
}
break;
case WM_ACTIVATEAPP:
case WM_DEVICECHANGE:
case WM_PALETTECHANGED:
case WM_QUERYNEWPALETTE:
if (pfc->hwndView)
return SendMessage(pfc->hwndView, uMsg, wParam, lParam);
break;
case WM_WININICHANGE:
Cabinet_InitGlobalMetrics(wParam, (LPTSTR)lParam);
Cabinet_OnWinIniChange(pfc, wParam, lParam);
break;
case WM_SYSCOLORCHANGE:
case WM_FONTCHANGE:
Cabinet_PropagateMessage(hwnd, uMsg, wParam, lParam);
break;
case WM_CONTEXTMENU:
if (Cabinet_OnContextMenu(pfc, wParam, lParam))
break;
goto DoDefault;
case 0x20a /* WM_MOUSEWHEEL */:
// Yuck! The message param's are different between the registered
// message and the defined one!
wParam = MAKEWPARAM(HIWORD(wParam), 0);
goto HandleMouseWheelNavigation;
break;
case WM_ERASEBKGND:
if (pfc->hwndTreeTitle) {
// HACKHACK: do this because these static controls don't clear their backgrounds
RedrawWindow(pfc->hwndTreeTitle, NULL, NULL, RDW_INVALIDATE |RDW_UPDATENOW);
RedrawWindow(pfc->hwndViewTitle, NULL, NULL, RDW_INVALIDATE |RDW_UPDATENOW);
// now just invalidate so that it will get WM_PAINT. UGH!
RedrawWindow(pfc->hwndTreeTitle, NULL, NULL, RDW_INVALIDATE);
RedrawWindow(pfc->hwndViewTitle, NULL, NULL, RDW_INVALIDATE);
}
// fall through
default:
if (uMsg == g_msgMSWheel) {
HandleMouseWheelNavigation:
#ifdef NASHVILLE
// If the message wasn't handled and shift is down, map
// to history navigation.
if (GetKeyState(VK_SHIFT) < 0) {
TLNavigate(&pfc->_tlGlobal, ((int)wParam < 0) ? HLNF_NAVIGATINGBACK : HLNF_NAVIGATINGFORWARD);
lres = 1;
}
#endif
return lres;
}
DoDefault:
lres = DefWindowProc(hwnd, uMsg, wParam, lParam);
break;
}
return lres;
}