mirror of https://github.com/lianthony/NT4.0
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.
1635 lines
47 KiB
1635 lines
47 KiB
#include "cabinet.h"
|
|
#include <winnetwk.h>
|
|
|
|
#include "drivlist.h"
|
|
#include "rcids.h"
|
|
#include "tree.h"
|
|
#include "cabwnd.h"
|
|
#include "help.h" // Help IDs
|
|
#include <regstr.h> // for REGSTR_PATH_EXPLORER
|
|
// Copied from shelldll\ole2dup.h
|
|
#define GUIDSTR_MAX (1+ 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1)
|
|
|
|
void FileCabinet_CycleFocus(PFileCabinet this);
|
|
BOOL _Restricted(HWND hwnd, RESTRICTIONS rest);
|
|
|
|
HMENU Cabinet_GetMenuFromID(HMENU hmMain, UINT uID)
|
|
{
|
|
MENUITEMINFO miiSubMenu;
|
|
|
|
if (!hmMain)
|
|
return NULL;
|
|
|
|
miiSubMenu.cbSize = SIZEOF(MENUITEMINFO);
|
|
miiSubMenu.fMask = MIIM_SUBMENU;
|
|
if (!GetMenuItemInfo(hmMain, uID, FALSE, &miiSubMenu))
|
|
return NULL;
|
|
|
|
return miiSubMenu.hSubMenu;
|
|
}
|
|
|
|
|
|
void ToolTipFromCmd(UINT idCommand, LPTSTR pszText, int cchText)
|
|
{
|
|
VDATEINPUTBUF(pszText, TCHAR, cchText);
|
|
|
|
if (!LoadString(hinstCabinet, idCommand + MH_TTBASE, pszText, cchText))
|
|
*pszText = 0;
|
|
}
|
|
|
|
void MenuHelpFromCmd(UINT idCommand, LPTSTR pszText, int cchText)
|
|
{
|
|
VDATEINPUTBUF(pszText, TCHAR, cchText);
|
|
|
|
if (!LoadString(hinstCabinet, idCommand + MH_ITEMS, pszText, cchText))
|
|
*pszText = 0;
|
|
}
|
|
|
|
#pragma warning(disable: 4200) /* zero-sized array in struct */
|
|
|
|
typedef struct {
|
|
int nItemOffset;
|
|
int nPopupOffset;
|
|
struct {
|
|
UINT uID;
|
|
HMENU hPopup;
|
|
} sPopupIDs[];
|
|
} MENUHELPIDS;
|
|
|
|
#define MENUHELP_DONE MAKELPARAM(-1, 0)
|
|
|
|
// previously, Cabinet_OnMenuSelect and GetMenuHelpText were one
|
|
// procedure.
|
|
// I've broken them into two procedures....
|
|
// one that gets the string, and one (this one) that shows it.
|
|
// I think this is a bit cleaner, and also I want to reuse the GetMenuHelpText
|
|
// for tool tips.
|
|
LRESULT Cabinet_OnMenuSelect(PFileCabinet pfc, WPARAM wParam, LPARAM lParam, UINT uHelpFlags)
|
|
{
|
|
MENUHELPIDS sMenuHelpIDs = {
|
|
MH_ITEMS, MH_POPUPS,
|
|
0, NULL, // Placeholder for specific menu
|
|
0, NULL // This list must be NULL terminated
|
|
};
|
|
TCHAR szHint[MAX_PATH];
|
|
UINT uMenuFlags = GET_WM_MENUSELECT_FLAGS(wParam, lParam);
|
|
DWORD wID = GET_WM_MENUSELECT_CMD(wParam, lParam);
|
|
HMENU hMenu = GET_WM_MENUSELECT_HMENU(wParam, lParam);
|
|
|
|
if (!hMenu && LOWORD(uMenuFlags)==0xffff)
|
|
{
|
|
SendMessage(pfc->hwndStatus, SB_SIMPLE, 0, 0L);
|
|
return 0L;
|
|
}
|
|
|
|
// Clear this out just in case, but don't update yet
|
|
SendMessage(pfc->hwndStatus, SB_SETTEXT, SBT_NOBORDERS|255, (LPARAM)(LPTSTR)c_szNULL);
|
|
SendMessage(pfc->hwndStatus, SB_SIMPLE, 1, 0L);
|
|
|
|
if (uMenuFlags & MF_SYSMENU)
|
|
{
|
|
// We don't put special items on the system menu any more, so go
|
|
// straight to the MenuHelp
|
|
goto DoMenuHelp;
|
|
}
|
|
|
|
if (uMenuFlags & MH_POPUP)
|
|
{
|
|
MENUITEMINFO miiSubMenu;
|
|
|
|
if (!pfc->hmenuCur)
|
|
{
|
|
return(0L);
|
|
}
|
|
|
|
miiSubMenu.cbSize = SIZEOF(MENUITEMINFO);
|
|
miiSubMenu.fMask = MIIM_SUBMENU|MIIM_ID;
|
|
if (!GetMenuItemInfo(GET_WM_MENUSELECT_HMENU(wParam, lParam), wID, TRUE, &miiSubMenu))
|
|
{
|
|
// Check if this was a top level menu
|
|
return(0L);
|
|
}
|
|
|
|
|
|
// Change the parameters to simulate a "normal" menu item
|
|
wID = wParam = miiSubMenu.wID;
|
|
if(!IsInRange(wID, FCIDM_GLOBALFIRST, FCIDM_GLOBALLAST))
|
|
return 0L;
|
|
uMenuFlags = 0;
|
|
}
|
|
|
|
#if defined(WINDOWS_ME)
|
|
if (IsInRange(wID, FCIDM_MENU_TOOLS_FINDFIRST, FCIDM_MENU_TOOLS_FINDLAST)) {
|
|
if (FAILED(pfc->pcmFind->lpVtbl->GetCommandString(pfc->pcmFind, wID - FCIDM_MENU_TOOLS_FINDFIRST,
|
|
GCS_HELPTEXT, NULL, &szHint[2], ARRAYSIZE(szHint)-2)))
|
|
{
|
|
szHint[0] = TEXT('\0'); // Null out the text in an error. The caller should have...
|
|
szHint[1] = TEXT('\0'); // Null out the text in an error. The caller should have...
|
|
}
|
|
SendMessage(pfc->hwndStatus, SB_SETTEXT, SBT_RTLREADING | SBT_NOBORDERS|255,
|
|
(LPARAM)(LPTSTR)szHint);
|
|
#else
|
|
if (IsInRange(wID, FCIDM_MENU_TOOLS_FINDFIRST, FCIDM_MENU_TOOLS_FINDLAST)) {
|
|
if (FAILED(pfc->pcmFind->lpVtbl->GetCommandString(pfc->pcmFind,
|
|
wID - FCIDM_MENU_TOOLS_FINDFIRST,
|
|
GCS_HELPTEXT, NULL,
|
|
(LPSTR)szHint, ARRAYSIZE(szHint))))
|
|
{
|
|
szHint[0] = TEXT('\0'); // Null out the text in an error. The caller should have...
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
if (*szHint == TEXT('\0'))
|
|
{
|
|
CHAR szHintAnsi[MAX_PATH];
|
|
|
|
if (FAILED(pfc->pcmFind->lpVtbl->GetCommandString(pfc->pcmFind,
|
|
wID - FCIDM_MENU_TOOLS_FINDFIRST,
|
|
GCS_HELPTEXTA, NULL,
|
|
szHintAnsi,
|
|
ARRAYSIZE(szHintAnsi))))
|
|
{
|
|
szHint[0] = TEXT('\0'); // Null out the text in an error. The caller should have...
|
|
}
|
|
MultiByteToWideChar(CP_ACP, 0,
|
|
szHintAnsi, -1,
|
|
szHint, ARRAYSIZE(szHint));
|
|
|
|
}
|
|
#endif
|
|
SendMessage(pfc->hwndStatus, SB_SETTEXT, SBT_NOBORDERS|255,
|
|
(LPARAM)(LPTSTR)szHint);
|
|
#endif
|
|
} else {
|
|
if (!IsInRange(wID, FCIDM_FIRST, FCIDM_LAST))
|
|
return 0L; // not ours
|
|
|
|
szHint[0] = 0;
|
|
|
|
sMenuHelpIDs.sPopupIDs[0].uID = 0;
|
|
sMenuHelpIDs.sPopupIDs[0].hPopup = NULL;
|
|
|
|
DoMenuHelp:
|
|
MenuHelp(WM_MENUSELECT, wParam, lParam, pfc->hmenuCur, hinstCabinet,
|
|
pfc->hwndStatus, (int *)&sMenuHelpIDs);
|
|
}
|
|
|
|
return 1L;
|
|
}
|
|
|
|
DWORD DoNetConnect(HWND hwnd)
|
|
{
|
|
HRESULT hres;
|
|
|
|
hres = SHStartNetConnectionDialog(NULL, NULL, RESOURCETYPE_DISK);
|
|
|
|
return (DWORD)hres; // Nobody looks at this...
|
|
}
|
|
|
|
|
|
DWORD DoNetDisconnect(HWND hwnd)
|
|
{
|
|
DWORD ret = WNetDisconnectDialog(NULL, RESOURCETYPE_DISK);
|
|
|
|
SHChangeNotifyHandleEvents(); // flush any drive notifications
|
|
|
|
DebugMsg(DM_TRACE, TEXT("shell:CNet - TRACE: DisconnectDialog returned (%lx)"), ret);
|
|
if (ret == WN_EXTENDED_ERROR)
|
|
{
|
|
// BUGBUG: is this still needed
|
|
// There has been a bug with this returning this but then still
|
|
// doing the disconnect. For now lets bring up a message and then
|
|
// still do the notify to have the shell attempt to cleanup.
|
|
TCHAR szErrorMsg[MAX_PATH]; // should be big enough
|
|
TCHAR szName[80]; // The name better not be any bigger.
|
|
DWORD dwError;
|
|
WNetGetLastError(&dwError, szErrorMsg, ARRAYSIZE(szErrorMsg),
|
|
szName, ARRAYSIZE(szName));
|
|
|
|
ShellMessageBox(hinstCabinet, NULL,
|
|
MAKEINTRESOURCE(IDS_NETERROR), MAKEINTRESOURCE(IDS_DISCONNECTERROR),
|
|
MB_ICONHAND | MB_OK, dwError, szName, szErrorMsg);
|
|
}
|
|
|
|
// BUGBUG: deal with error, perhaps open a window on this drive
|
|
return ret;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
void Cabinet_ViewFolder(PFileCabinet pfc, BOOL fPrev)
|
|
{
|
|
if (!pfc->pidl)
|
|
return;
|
|
|
|
if (fPrev)
|
|
{
|
|
LPOneTreeNode lpnd;
|
|
|
|
Assert(pfc->lpndOpen);
|
|
|
|
lpnd = OTGetParent(pfc->lpndOpen);
|
|
|
|
if (lpnd == s_lpnRoot && !pfc->hwndTree && OTIsDesktopRoot())
|
|
{
|
|
// don't allow to go up to the desktop when in non-explorer mode
|
|
ShellMessageBox(hinstCabinet, pfc->hwndMain, MAKEINTRESOURCE(IDS_CANTBROWSEDESKTOP), NULL, MB_ICONHAND | MB_OK);
|
|
}
|
|
else if (lpnd)
|
|
{
|
|
LPITEMIDLIST pidl=OTCreateIDListFromNode(lpnd);
|
|
if (pidl)
|
|
{
|
|
NEWFOLDERINFO fi;
|
|
|
|
fi.hwndCaller = pfc->hwndMain;
|
|
fi.pidl = pidl;
|
|
fi.uFlags = COF_USEOPENSETTINGS | COF_NOTRANSLATE
|
|
| (pfc->hwndTree ? COF_EXPLORE : 0);
|
|
fi.nShow = SW_SHOWNORMAL;
|
|
fi.dwHotKey = 0;
|
|
|
|
Cabinet_OpenFolder(&fi);
|
|
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageBeep(MB_ICONASTERISK);
|
|
}
|
|
|
|
OTRelease(lpnd);
|
|
}
|
|
else
|
|
{
|
|
Cabinet_SetPath(pfc, 0, pfc->pidl);
|
|
}
|
|
}
|
|
|
|
//
|
|
// BUGBUG: none of our callers verify that the commands are legal!!!
|
|
//
|
|
BOOL Cabinet_InvokeCommandOnItem(PFileCabinet pfc, LPCTSTR pszCmd)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
LPCITEMIDLIST pidlLast;
|
|
|
|
Assert(pfc->hwndMain);
|
|
|
|
if (pfc->pidl && (NULL != (pidlLast = ILFindLastID(pfc->pidl))))
|
|
{
|
|
LPOneTreeNode lpn1 = OTGetNodeFromIDList(pfc->pidl, OTGNF_TRYADD);
|
|
if (lpn1)
|
|
{
|
|
IContextMenu *pcm;
|
|
HRESULT hres;
|
|
LPOneTreeNode lpn = OTGetParent(lpn1);
|
|
CMINVOKECOMMANDINFOEX ici = {
|
|
SIZEOF(CMINVOKECOMMANDINFOEX),
|
|
0L,
|
|
pfc->hwndMain,
|
|
NULL,
|
|
NULL, NULL,
|
|
SW_NORMAL,
|
|
};
|
|
#ifdef UNICODE
|
|
CHAR szVerbAnsi[MAX_PATH];
|
|
WideCharToMultiByte(CP_ACP, 0,
|
|
pszCmd, -1,
|
|
szVerbAnsi, ARRAYSIZE(szVerbAnsi),
|
|
NULL, NULL);
|
|
ici.lpVerb = szVerbAnsi;
|
|
ici.lpVerbW = pszCmd;
|
|
ici.fMask |= CMIC_MASK_UNICODE;
|
|
#else
|
|
ici.lpVerb = pszCmd;
|
|
#endif
|
|
|
|
OTRelease(lpn1);
|
|
if (lpn)
|
|
{
|
|
LPSHELLFOLDER psfParent = OTBindToFolder(lpn);
|
|
OTRelease(lpn);
|
|
if (psfParent)
|
|
{
|
|
hres = psfParent->lpVtbl->GetUIObjectOf(psfParent, pfc->hwndMain,
|
|
1, &pidlLast, &IID_IContextMenu, NULL, &pcm);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
fSuccess = SUCCEEDED(pcm->lpVtbl->InvokeCommand(pcm,
|
|
(LPCMINVOKECOMMANDINFO)&ici));
|
|
pcm->lpVtbl->Release(pcm);
|
|
}
|
|
psfParent->lpVtbl->Release(psfParent);
|
|
}
|
|
} else {
|
|
LPSHELLFOLDER psf = OTBindToFolder(lpn1);
|
|
// it's the desktop folder. do a CreateViewObject
|
|
hres = psf->lpVtbl->CreateViewObject(psf, pfc->hwndMain,
|
|
&IID_IContextMenu, &pcm);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
fSuccess = SUCCEEDED(pcm->lpVtbl->InvokeCommand(pcm,
|
|
(LPCMINVOKECOMMANDINFO)&ici));
|
|
if (!fSuccess)
|
|
MessageBeep(0);
|
|
pcm->lpVtbl->Release(pcm);
|
|
}
|
|
psf->lpVtbl->Release(psf);
|
|
}
|
|
}
|
|
}
|
|
|
|
// do any visuals for cut state
|
|
if (fSuccess && pfc->hwndTree && !lstrcmpi(pszCmd, c_szMove)) {
|
|
HTREEITEM hti = TreeView_GetSelection(pfc->hwndTree);
|
|
if (hti) {
|
|
Tree_SetItemState(pfc, hti, TVIS_CUT, TVIS_CUT);
|
|
Assert(!pfc->hwndNextViewer);
|
|
pfc->hwndNextViewer = SetClipboardViewer(pfc->hwndMain);
|
|
DebugMsg(DM_TRACE, TEXT("CABINET: Set ClipboardViewer %d %d"), pfc->hwndMain, pfc->hwndNextViewer);
|
|
pfc->htiCut = hti;
|
|
}
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
void Cabinet_StateChanged(void);
|
|
|
|
//---------------------------------------------------------------------------
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
const static DWORD aFolderOptsHelpIDs[] = { // Context Help IDs
|
|
IDC_GROUPBOX, IDH_COMM_GROUPBOX,
|
|
IDC_NO_HELP_1, NO_HELP,
|
|
IDC_NO_HELP_2, NO_HELP,
|
|
IDC_NO_HELP_3, NO_HELP,
|
|
IDC_NO_HELP_4, NO_HELP,
|
|
IDC_ALWAYS, IDH_FCAB_FOLDEROPTIONS_ALWAYS,
|
|
IDB_MULTWIN, IDH_FCAB_FOLDEROPTIONS_ALWAYS,
|
|
IDC_NEVER, IDH_FCAB_FOLDEROPTIONS_NEVER,
|
|
IDB_ONEWIN, IDH_FCAB_FOLDEROPTIONS_NEVER,
|
|
|
|
0, 0
|
|
};
|
|
#pragma data_seg()
|
|
|
|
BOOL CALLBACK FolderOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg) {
|
|
case WM_INITDIALOG:
|
|
// Deal with the new window stuff...
|
|
|
|
if (g_CabState.fNewWindowMode) {
|
|
// Note the default here and in the PSN_APPLY is to create
|
|
// a new window
|
|
CheckRadioButton(hDlg, IDC_ALWAYS, IDC_NEVER, IDC_ALWAYS);
|
|
} else {
|
|
CheckRadioButton(hDlg, IDC_ALWAYS, IDC_NEVER, IDC_NEVER);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR *)lParam)->code) {
|
|
case PSN_APPLY:
|
|
{
|
|
BOOL fOldValue = (g_CabState.fNewWindowMode ? 1 : 0);
|
|
|
|
if (IsDlgButtonChecked(hDlg, IDC_NEVER))
|
|
g_CabState.fNewWindowMode = 0;
|
|
else
|
|
g_CabState.fNewWindowMode = TRUE;
|
|
|
|
// notify if there was a change
|
|
if (fOldValue != (g_CabState.fNewWindowMode ? 1 : 0))
|
|
Cabinet_StateChanged();
|
|
return TRUE;
|
|
}
|
|
|
|
case PSN_KILLACTIVE:
|
|
// validate here
|
|
// SetWindowLong(hDlg, DWL_MSGRESULT, !ValidateLink()); // don't allow close
|
|
return TRUE;
|
|
|
|
case PSN_SETACTIVE:
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
|
|
HELP_WM_HELP, (DWORD)(LPTSTR) aFolderOptsHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
|
|
(DWORD)(LPVOID)aFolderOptsHelpIDs);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDC_ALWAYS:
|
|
case IDC_NEVER:
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
|
|
SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void FillHiddenExtsList(HWND hLB)
|
|
{
|
|
SHELLSTATE ss;
|
|
SHFILEINFO sfi;
|
|
TCHAR szHiddenFileExts[MAX_PATH];
|
|
TCHAR szExt[MAX_PATH];
|
|
LPTSTR pszThis, pszThat;
|
|
int iTabWid;
|
|
UINT uLen;
|
|
|
|
ss.pszHiddenFileExts = szHiddenFileExts;
|
|
ss.cbHiddenFileExts = SIZEOF(szHiddenFileExts);
|
|
|
|
SHGetSetSettings(&ss, SSF_HIDDENFILEEXTS, FALSE);
|
|
|
|
iTabWid = 30;
|
|
ListBox_SetTabStops(hLB, 1, &iTabWid);
|
|
|
|
szExt[0] = TEXT('.');
|
|
|
|
for (pszThat=szHiddenFileExts; ; )
|
|
{
|
|
pszThis = pszThat;
|
|
while (*pszThis <= TEXT(' '))
|
|
{
|
|
// skip all control characters, which cannot be
|
|
// DBCS lead bytes
|
|
|
|
if (!*pszThis)
|
|
{
|
|
// We got to the end of the string
|
|
goto NoMoreExts;
|
|
}
|
|
|
|
// We're just looking for old MS-DOS extensions, which
|
|
// cannot have spaces
|
|
++pszThis;
|
|
}
|
|
|
|
for (pszThat=pszThis; *pszThat>TEXT(' '); pszThat=CharNext(pszThat))
|
|
{
|
|
// skip to the next space
|
|
// HACKHACK: note we are checking for greater than
|
|
// space, so we will stop at control characters or
|
|
// NULL, which will be dealt with at the beginning of
|
|
// the next iteration of this loop
|
|
}
|
|
|
|
uLen = pszThat-pszThis;
|
|
if (uLen > 3)
|
|
{
|
|
// This is an invalid old MS-DOS extension
|
|
continue;
|
|
}
|
|
|
|
lstrcpyn(szExt+1, pszThis, uLen+1);
|
|
szExt[uLen+1] = TEXT('\0');
|
|
CharUpper(szExt);
|
|
|
|
SHGetFileInfo(szExt, 0, &sfi, SIZEOF(sfi), SHGFI_TYPENAME|SHGFI_USEFILEATTRIBUTES);
|
|
|
|
lstrcat(szExt, TEXT("\t("));
|
|
lstrcat(szExt, sfi.szTypeName);
|
|
lstrcat(szExt, TEXT(")"));
|
|
|
|
|
|
ListBox_AddString(hLB, szExt);
|
|
}
|
|
|
|
NoMoreExts:
|
|
LoadString(hinstCabinet, IDS_HIDDENFILES, szExt, ARRAYSIZE(szExt));
|
|
ListBox_InsertString(hLB, 0, szExt);
|
|
}
|
|
|
|
|
|
BOOL CALLBACK Cabinet_RefreshEnum(HWND hwnd, LPARAM lParam)
|
|
{
|
|
if (Cabinet_IsFolderWindow(hwnd) || Cabinet_IsExplorerWindow(hwnd))
|
|
{
|
|
PostMessage(hwnd, WM_COMMAND, FCIDM_REFRESH, 0L);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
void Cabinet_RefreshAll(void)
|
|
{
|
|
PostMessage(v_hwndDesktop, WM_COMMAND, FCIDM_REFRESH, 0L);
|
|
PostMessage(v_hwndTray, WM_COMMAND, FCIDM_REFRESH, 0L);
|
|
|
|
EnumWindows(Cabinet_RefreshEnum, 0);
|
|
}
|
|
|
|
|
|
BOOL CALLBACK Cabinet_GlobalStateEnum(HWND hwnd, LPARAM lParam)
|
|
{
|
|
if (Cabinet_IsFolderWindow(hwnd) || Cabinet_IsExplorerWindow(hwnd))
|
|
{
|
|
PostMessage(hwnd, CWM_GLOBALSTATECHANGE, 0, 0L);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
void Cabinet_StateChanged(void)
|
|
{
|
|
// Save the new settings away...
|
|
WriteCabinetState( &g_CabState );
|
|
EnumWindows(Cabinet_GlobalStateEnum, 0);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
const static DWORD aViewOptsHelpIDs[] = { // Context Help IDs
|
|
IDC_GROUPBOX, IDH_COMM_GROUPBOX,
|
|
IDC_SHOWALL, IDH_FCAB_VIEWOPTIONS_SHOWALL,
|
|
IDC_SHOWSOME, IDH_FCAB_VIEWOPTIONS_HIDDENEXTS,
|
|
IDC_HIDDENEXTS, IDH_FCAB_VIEWOPTIONS_HIDDENEXTS,
|
|
IDC_SHOWFULLPATH, IDH_FCAB_VIEWOPTIONS_SHOWFULLPATH,
|
|
IDC_HIDEEXTS, IDH_FCAB_VIEWOPTIONS_HIDEEXTS,
|
|
IDC_SHOWDESCBAR, IDH_FCAB_VIEWOPTIONS_SHOWDESCBAR,
|
|
IDC_SHOWCOMPCOLOR,IDH_FCAB_VIEWOPTIONS_SHOWCOMPCOLOR,
|
|
|
|
0, 0
|
|
};
|
|
#pragma data_seg()
|
|
|
|
BOOL CALLBACK ViewOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPPROPSHEETPAGE psp;
|
|
LPFileCabinet pfc;
|
|
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
psp = (LPPROPSHEETPAGE)lParam;
|
|
SetWindowLong(hDlg, DWL_USER, lParam);
|
|
}
|
|
else
|
|
{
|
|
psp = (LPPROPSHEETPAGE)GetWindowLong(hDlg, DWL_USER);
|
|
}
|
|
|
|
if (psp == NULL)
|
|
return(FALSE); // Not initialized yet, dont process anything
|
|
|
|
pfc = (LPFileCabinet)psp->lParam;
|
|
|
|
switch (uMsg) {
|
|
case WM_INITDIALOG:
|
|
{
|
|
SHELLSTATE ss;
|
|
|
|
if (g_CabState.fFullPathTitle)
|
|
{
|
|
CheckDlgButton(hDlg, IDC_SHOWFULLPATH, TRUE);
|
|
}
|
|
|
|
if (pfc->hwndTree)
|
|
{
|
|
if (!g_CabState.fDontShowDescBar)
|
|
{
|
|
CheckDlgButton(hDlg, IDC_SHOWDESCBAR, TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HWND hCtl = GetDlgItem(hDlg, IDC_SHOWDESCBAR);
|
|
|
|
// Makes no sense if not Explorer
|
|
ShowWindow(hCtl, SW_HIDE);
|
|
// Need to NULL the text so the accelerator does not work
|
|
SetWindowText(hCtl, c_szNULL);
|
|
}
|
|
|
|
SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS | SSF_SHOWEXTENSIONS | SSF_SHOWCOMPCOLOR, FALSE);
|
|
|
|
CheckRadioButton(hDlg, IDC_SHOWALL, IDC_SHOWSOME,
|
|
ss.fShowAllObjects ? IDC_SHOWALL : IDC_SHOWSOME);
|
|
|
|
CheckDlgButton(hDlg, IDC_HIDEEXTS, !ss.fShowExtensions);
|
|
CheckDlgButton(hDlg, IDC_SHOWCOMPCOLOR, ss.fShowCompColor);
|
|
|
|
FillHiddenExtsList(GetDlgItem(hDlg, IDC_HIDDENEXTS));
|
|
|
|
break;
|
|
}
|
|
|
|
case WM_NOTIFY:
|
|
switch (((NMHDR *)lParam)->code) {
|
|
case PSN_APPLY:
|
|
{
|
|
SHELLSTATE ss, oldss;
|
|
CABINETSTATE oldstate;
|
|
BOOL fChanged = FALSE;
|
|
|
|
oldstate = g_CabState;
|
|
|
|
g_CabState.fFullPathTitle = IsDlgButtonChecked(hDlg, IDC_SHOWFULLPATH);
|
|
if (pfc->hwndTree)
|
|
{
|
|
g_CabState.fDontShowDescBar = !IsDlgButtonChecked(hDlg, IDC_SHOWDESCBAR );
|
|
}
|
|
|
|
if ((g_CabState.fDontShowDescBar != oldstate.fDontShowDescBar) ||
|
|
(g_CabState.fFullPathTitle != oldstate.fFullPathTitle))
|
|
{
|
|
fChanged = TRUE;
|
|
}
|
|
|
|
// Now get the checkbox...
|
|
ss.fShowAllObjects = IsDlgButtonChecked(hDlg, IDC_SHOWALL) ? 1 : 0;
|
|
ss.fShowExtensions = IsDlgButtonChecked(hDlg, IDC_HIDEEXTS) ? 0 : 1;
|
|
ss.fShowCompColor = IsDlgButtonChecked(hDlg, IDC_SHOWCOMPCOLOR) ? 1 : 0;
|
|
SHGetSetSettings(&oldss, SSF_SHOWALLOBJECTS | SSF_SHOWEXTENSIONS | SSF_SHOWCOMPCOLOR, FALSE);
|
|
|
|
//
|
|
// We post a message to our self as to avoind having it
|
|
// try to update while the dialog is still showing
|
|
// Only post the refresh if something changed
|
|
//
|
|
if (ss.fShowAllObjects!=oldss.fShowAllObjects
|
|
|| ss.fShowExtensions!=oldss.fShowExtensions
|
|
|| ss.fShowCompColor!=oldss.fShowCompColor)
|
|
{
|
|
SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS | SSF_SHOWEXTENSIONS | SSF_SHOWCOMPCOLOR, TRUE);
|
|
fChanged = TRUE;
|
|
g_fShowCompColor = ss.fShowCompColor;
|
|
}
|
|
|
|
// Save the new setting right away and tell other windows
|
|
if (fChanged)
|
|
{
|
|
LPOneTreeNode pdn = pfc->lpndOpen;
|
|
Cabinet_StateChanged();
|
|
|
|
// Go up the the root of the namespace and invalidate the onetree nodes
|
|
|
|
|
|
DoInvalidateAll(s_lpnRoot, -1);
|
|
Cabinet_RefreshAll();
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case PSN_KILLACTIVE:
|
|
case PSN_SETACTIVE:
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp((HWND)((LPHELPINFO) lParam)->hItemHandle, NULL,
|
|
HELP_WM_HELP, (DWORD)(LPTSTR) aViewOptsHelpIDs);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND) wParam, NULL, HELP_CONTEXTMENU,
|
|
(DWORD)(LPVOID)aViewOptsHelpIDs);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case IDC_SHOWALL:
|
|
case IDC_SHOWSOME:
|
|
case IDC_SHOWFULLPATH:
|
|
case IDC_HIDEEXTS:
|
|
case IDC_SHOWDESCBAR:
|
|
#ifdef WINNT
|
|
case IDC_SHOWCOMPCOLOR:
|
|
#endif
|
|
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
|
|
SendMessage(GetParent(hDlg), PSM_CHANGED, (WPARAM)hDlg, 0L);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
#define MAX_PAGES 16 // limit on the number of pages we can have
|
|
|
|
BOOL CALLBACK _AddPropSheetPage(HPROPSHEETPAGE hpage, LPARAM lParam)
|
|
{
|
|
PROPSHEETHEADER * ppsh = (PROPSHEETHEADER *)lParam;
|
|
|
|
if (ppsh->nPages < MAX_PAGES)
|
|
{
|
|
ppsh->phpage[ppsh->nPages++] = hpage;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef NO_FILE_TYPES_PROP_SHEET_HOOK
|
|
|
|
/*
|
|
* Returns:
|
|
* S_OK Do not add standard File Types property sheet.
|
|
* S_FALSE Add standard File Types property sheet.
|
|
* E_... Error invoking hook. Add standard File Types property sheet.
|
|
*/
|
|
HRESULT InvokeFileTypesPropSheetHook(LPCLSID pclsidHook,
|
|
LPFNADDPROPSHEETPAGE pfnAddPage,
|
|
LPPROPSHEETHEADER ppsh)
|
|
{
|
|
HRESULT hr;
|
|
IUnknown *punk;
|
|
|
|
hr = SHCoCreateInstance(NULL, pclsidHook, NULL, &IID_IUnknown, &punk);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
IShellPropSheetExt *pspse;
|
|
|
|
hr = punk->lpVtbl->QueryInterface(punk, &IID_IShellPropSheetExt, &pspse);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
UINT ucPagesBefore = ppsh->nPages;
|
|
|
|
pspse->lpVtbl->ReplacePage(pspse, EXPPS_FILETYPES, pfnAddPage,
|
|
(LPARAM)ppsh);
|
|
|
|
if (ppsh->nPages > ucPagesBefore)
|
|
hr = S_OK;
|
|
else
|
|
{
|
|
pspse->lpVtbl->AddPages(pspse, pfnAddPage, (LPARAM)ppsh);
|
|
|
|
hr = S_FALSE;
|
|
}
|
|
|
|
pspse->lpVtbl->Release(pspse);
|
|
}
|
|
|
|
punk->lpVtbl->Release(punk);
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
const TCHAR c_szFileTypesPropSheetHookSubKey[] = REGSTR_PATH_EXPLORER TEXT("\\FileTypesPropertySheetHook");
|
|
|
|
/*
|
|
* Returns:
|
|
* S_OK Do not add standard File Types property sheet.
|
|
* S_FALSE Add standard File Types property sheet.
|
|
* E_... Error invoking hook. Add standard File Types property sheet.
|
|
*/
|
|
HRESULT ReplaceStandardFileTypesPropSheet(LPFNADDPROPSHEETPAGE pfnAddPage,
|
|
LPPROPSHEETHEADER ppsh)
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szCLSID[GUIDSTR_MAX];
|
|
DWORD dwcbCLSIDLen = SIZEOF(szCLSID);
|
|
|
|
// The File Types hook is registered by the CLSID of an object whose
|
|
// IShellPropSheetExt should be used to add a replacement property sheet.
|
|
|
|
if (RegQueryValue(HKEY_LOCAL_MACHINE, c_szFileTypesPropSheetHookSubKey, szCLSID,
|
|
&dwcbCLSIDLen) == ERROR_SUCCESS)
|
|
{
|
|
CLSID clsidHook;
|
|
|
|
hr = SHCLSIDFromString(szCLSID, &clsidHook);
|
|
|
|
if (hr == S_OK)
|
|
hr = InvokeFileTypesPropSheetHook(&clsidHook, pfnAddPage, ppsh);
|
|
}
|
|
else
|
|
hr = S_FALSE;
|
|
|
|
return(hr);
|
|
}
|
|
|
|
#endif // ! NO_FILE_TYPES_PROP_SHEET_HOOK
|
|
|
|
void Cabinet_DoOptions(PFileCabinet pfc)
|
|
{
|
|
PROPSHEETHEADER psh;
|
|
PROPSHEETPAGE psp;
|
|
HPROPSHEETPAGE rPages[MAX_PAGES];
|
|
int niStart;
|
|
|
|
psh.dwSize = SIZEOF(psh);
|
|
psh.dwFlags = PSH_DEFAULT;
|
|
psh.hInstance = hinstCabinet;
|
|
psh.hwndParent = pfc->hwndMain;
|
|
psh.pszCaption = MAKEINTRESOURCE(IDS_OPTIONS);
|
|
psh.nPages = 0;
|
|
psh.nStartPage = 0;
|
|
psh.phpage = rPages;
|
|
|
|
psp.dwSize = SIZEOF(psp);
|
|
psp.dwFlags = PSP_DEFAULT;
|
|
psp.hInstance = hinstCabinet;
|
|
|
|
//
|
|
// Add Folder option dialog if we don't have the tree
|
|
// AND this is not a rooted explorer.
|
|
//
|
|
if (!pfc->hwndTree && OTIsDesktopRoot()) {
|
|
psp.pszTemplate = MAKEINTRESOURCE(DLG_FOLDEROPTIONS);
|
|
psp.pfnDlgProc = FolderOptionsDlgProc;
|
|
psp.lParam = (LPARAM)pfc;
|
|
|
|
psh.phpage[psh.nPages] = CreatePropertySheetPage(&psp);
|
|
if (psh.phpage[psh.nPages])
|
|
psh.nPages++;
|
|
}
|
|
|
|
//
|
|
// Add View options dialog
|
|
//
|
|
psp.pszTemplate = MAKEINTRESOURCE(DLG_VIEWOPTIONS);
|
|
psp.pfnDlgProc = ViewOptionsDlgProc;
|
|
psp.lParam = (LPARAM)pfc;
|
|
|
|
psh.phpage[psh.nPages] = CreatePropertySheetPage(&psp);
|
|
if (psh.phpage[psh.nPages])
|
|
psh.nPages++;
|
|
|
|
niStart = psh.nPages;
|
|
|
|
#ifndef NO_FILE_TYPES_PROP_SHEET_HOOK
|
|
|
|
// Check for replacement File Types property sheet.
|
|
|
|
if (ReplaceStandardFileTypesPropSheet(_AddPropSheetPage, &psh) == S_OK)
|
|
;
|
|
else
|
|
|
|
#endif
|
|
|
|
if (psh.nPages < ARRAYSIZE(rPages))
|
|
{
|
|
HRESULT hres;
|
|
IShellPropSheetExt* pspse;
|
|
|
|
hres = SHCoCreateInstance(NULL, &CLSID_FileTypes, NULL, &IID_IShellPropSheetExt, (LPVOID*)&pspse);
|
|
if ( SUCCEEDED(hres) )
|
|
{
|
|
hres = pspse->lpVtbl->AddPages(pspse, _AddPropSheetPage, (LPARAM)(LPPROPSHEETHEADER)&psh);
|
|
pspse->lpVtbl->Release(pspse);
|
|
}
|
|
}
|
|
|
|
// now let the view add pages
|
|
pfc->psv->lpVtbl->AddPropertySheetPages(pfc->psv, 0, _AddPropSheetPage, (LPARAM)(LPPROPSHEETHEADER)&psh);
|
|
|
|
PropertySheet(&psh);
|
|
}
|
|
|
|
|
|
// fDisconnectAlways means we shouldn't try to re-open the folder (like when
|
|
// someone logs off of a share, reconnecting would ask them for
|
|
// a password again when they just specified that they want to log off
|
|
void FileSysChange_CloseCabinet(PFileCabinet this, LPNMOTFSEINFO lpnm, BOOL fDisconnectAlways)
|
|
{
|
|
if (ILIsParent(lpnm->pidl, this->pidl, FALSE))
|
|
{
|
|
LPOneTreeNode lpNode;
|
|
if (fDisconnectAlways || !(lpNode = OTGetNodeFromIDList(this->pidl, OTGNF_VALIDATE))) {
|
|
// lpndOpen is invalid -- we shouldn't use it any more!
|
|
OTRelease(this->lpndOpen);
|
|
this->lpndOpen = NULL;
|
|
OTUnregister(this->hwndMain);
|
|
FolderList_UnregisterWindow(this->hwndMain);
|
|
PostMessage(this->hwndMain, WM_CLOSE, 0, 0L);
|
|
} else
|
|
OTRelease(lpNode);
|
|
}
|
|
}
|
|
|
|
void NoTree_HandleFileSysChange(PFileCabinet this, LPNMOTFSEINFO lpnm)
|
|
{
|
|
BOOL fDisconnectAlways = FALSE;
|
|
|
|
switch(lpnm->lEvent)
|
|
{
|
|
case SHCNE_UPDATEDIR:
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
if (SHGetPathFromIDList(this->pidl, szPath)) {
|
|
if (!PathFileExists(szPath)) {
|
|
FileSysChange_CloseCabinet(this, lpnm, TRUE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SHCNE_DRIVEADDGUI:
|
|
if (ILIsParent(lpnm->pidl, this->pidl, FALSE)) {
|
|
PostMessage(this->hwndMain, WM_COMMAND, FCIDM_REFRESH, 0L);
|
|
}
|
|
break;
|
|
|
|
case SHCNE_SERVERDISCONNECT:
|
|
case SHCNE_MEDIAREMOVED:
|
|
case SHCNE_RMDIR:
|
|
fDisconnectAlways = TRUE;
|
|
case SHCNE_NETUNSHARE:
|
|
case SHCNE_DRIVEREMOVED:
|
|
FileSysChange_CloseCabinet(this, lpnm, fDisconnectAlways);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void Cabinet_HandleFileSysChange(PFileCabinet this, LPNMOTFSEINFO lpnm)
|
|
{
|
|
HTREEITEM hti;
|
|
|
|
//
|
|
// If we haven't initialized "this" yet, we should ignore all the
|
|
// notification.
|
|
//
|
|
if (this->pidl == NULL)
|
|
return;
|
|
|
|
//
|
|
// If we are in the middle of Cabinet_ChangeView function,
|
|
// ignore this event.
|
|
//
|
|
if (this->fChangingFolder) {
|
|
if (this->hwndTree) {
|
|
this->fUpdateTree = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (this->hwndTree)
|
|
Tree_HandleFileSysChange(this, lpnm);
|
|
else
|
|
NoTree_HandleFileSysChange(this, lpnm);
|
|
|
|
|
|
|
|
// stuff that needs to be done tree or no tree
|
|
switch (lpnm->lEvent) {
|
|
case SHCNE_RENAMEFOLDER:
|
|
if (ILIsParent(lpnm->pidl, this->pidl, FALSE)) {
|
|
LPITEMIDLIST pidlTarget;
|
|
LPITEMIDLIST pidlReal;
|
|
|
|
LPITEMIDLIST pidlCur = this->pidl;
|
|
LPITEMIDLIST pidlCurSave = NULL;
|
|
LPITEMIDLIST pidlNotify = lpnm->pidlExtra;
|
|
LPITEMIDLIST pidlNotifySave = NULL;
|
|
HRESULT hres;
|
|
LPSHELLFOLDER psf = NULL;
|
|
USHORT uSave;
|
|
|
|
// First we need to walk through our pidl and the old pidl to get that parts that
|
|
// are common.
|
|
while (!ILIsEmpty(pidlNotify))
|
|
{
|
|
pidlNotifySave = pidlNotify;
|
|
pidlNotify = _ILNext(pidlNotify);
|
|
pidlCurSave = pidlCur;
|
|
pidlCur = _ILNext(pidlCur);
|
|
}
|
|
|
|
// We now need to bind to the parent folder
|
|
if (pidlNotifySave != lpnm->pidlExtra)
|
|
{
|
|
|
|
uSave = pidlNotifySave->mkid.cb;
|
|
pidlNotifySave->mkid.cb = 0;
|
|
hres = s_pshfRoot->lpVtbl->BindToObject(s_pshfRoot, lpnm->pidlExtra, NULL, &IID_IShellFolder,
|
|
&psf);
|
|
pidlNotifySave->mkid.cb = uSave;
|
|
|
|
}
|
|
else
|
|
psf = s_pshfRoot;
|
|
|
|
if (psf)
|
|
{
|
|
if (SUCCEEDED(SHGetRealIDL(psf, pidlNotifySave, &pidlReal)))
|
|
{
|
|
if (pidlCurSave != this->pidl)
|
|
{
|
|
uSave = pidlCurSave->mkid.cb;
|
|
pidlCurSave->mkid.cb = 0;
|
|
pidlTarget = ILCombine(this->pidl, pidlReal);
|
|
pidlCurSave->mkid.cb = uSave;
|
|
ILFree(pidlReal);
|
|
}
|
|
else
|
|
pidlTarget = pidlReal;
|
|
|
|
if (pidlTarget && !ILIsEmpty(pidlCur))
|
|
{
|
|
// There is still trailing stuff on the pidl...
|
|
pidlReal = pidlTarget;
|
|
pidlTarget = ILCombine(pidlReal, pidlCur);
|
|
ILFree(pidlReal);
|
|
}
|
|
if (pidlTarget)
|
|
{
|
|
LPOneTreeNode lpNode = OTGetNodeFromIDList(pidlTarget, OTGNF_VALIDATE | OTGNF_TRYADD);
|
|
Cabinet_ChangeView(this, lpNode, pidlTarget, FALSE);
|
|
ILFree(pidlTarget);
|
|
}
|
|
}
|
|
if (psf != s_pshfRoot)
|
|
psf->lpVtbl->Release(psf);
|
|
} else {
|
|
// error case
|
|
FileSysChange_CloseCabinet(this, lpnm, FALSE);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SHCNE_UPDATEIMAGE:
|
|
{
|
|
LPSHChangeDWORDAsIDList pImage;
|
|
int iOldImage;
|
|
|
|
pImage = (LPSHChangeDWORDAsIDList)lpnm->pidl;
|
|
iOldImage = pImage->dwItem1;
|
|
|
|
if (this->iImage == iOldImage || iOldImage == -1) {
|
|
_SetCabinetIcons(this, this->lpndOpen, this->iImage); // this binds
|
|
if (this->hwndDrives)
|
|
InvalidateRect(this->hwndDrives, NULL, TRUE);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (IsWindowVisible(this->hwndDrives))
|
|
{
|
|
switch (lpnm->lEvent)
|
|
{
|
|
case SHCNE_DRIVEREMOVED:
|
|
// Fall through to update the path...
|
|
if (this->hwndTree)
|
|
{
|
|
// We may have removed the drive that we were viewing
|
|
// if so we should reset the tree location to the
|
|
// current tree selection which may have changed in
|
|
// the tree handling of the notification. No tree, no
|
|
// worry because we would have blown away the window...
|
|
hti = TreeView_GetSelection(this->hwndTree);
|
|
if (this->lpndOpen != Tree_GetFCTreeData(this->hwndTree, hti))
|
|
this->lpndOpen = NULL; // Will get reset when tree updates...
|
|
|
|
}
|
|
|
|
case SHCNE_MEDIAREMOVED:
|
|
case SHCNE_MEDIAINSERTED:
|
|
case SHCNE_DRIVEADD:
|
|
DriveList_UpdatePath(this, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoAboutChicago(HWND hwnd)
|
|
{
|
|
TCHAR szChicago[64]; // Should not be able to exceed this?
|
|
|
|
LoadString(hinstCabinet, IDS_WINDOWS, szChicago, ARRAYSIZE(szChicago));
|
|
|
|
// BUGBUG: ShellAbout() should take a MAKEINTRESOURCE(IDS_WINDOWS)
|
|
ShellAbout(hwnd, szChicago, NULL, NULL);
|
|
}
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
|
|
#define IN_STD_BMP 0x8000
|
|
|
|
struct {
|
|
USHORT idCmd;
|
|
USHORT idBmp;
|
|
} c_AllButtons[] = {
|
|
FCIDM_DRIVELIST, 0,
|
|
FCIDM_PREVIOUSFOLDER, 0,
|
|
|
|
FCIDM_DELETE, 5 | IN_STD_BMP,
|
|
FCIDM_RENAME, 6,
|
|
FCIDM_PROPERTIES, 10 | IN_STD_BMP,
|
|
|
|
FCIDM_MOVE, 0 | IN_STD_BMP,
|
|
FCIDM_COPY, 1 | IN_STD_BMP,
|
|
// Help Topic... is provided by the view
|
|
#if 0
|
|
FCIDM_HELPSEARCH, 11 | IN_STD_BMP,
|
|
#endif
|
|
};
|
|
#pragma data_seg()
|
|
|
|
|
|
LRESULT Toolbar_FwdTBNotify(PFileCabinet pfc, LPTBNOTIFY ptbn)
|
|
{
|
|
HWND hwndView;
|
|
|
|
if (pfc->hwndView)
|
|
hwndView = pfc->hwndView;
|
|
else if (pfc->psv)
|
|
{
|
|
// if we are inside IShellView::CreateViewWindow() we don't have
|
|
// pfc->hwndView yet, but the view does, so we ask it for it.
|
|
//
|
|
pfc->psv->lpVtbl->GetWindow(pfc->psv, &hwndView);
|
|
}
|
|
else
|
|
hwndView = NULL;
|
|
|
|
if (hwndView)
|
|
{
|
|
ptbn->iItem -= ARRAYSIZE(c_AllButtons);
|
|
return SendMessage(hwndView, WM_NOTIFY, ptbn->hdr.idFrom, (LPARAM)ptbn);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern int DrivesComboWidth();
|
|
|
|
LRESULT Toolbar_OnNotify(PFileCabinet pfc, LPNMHDR pnm)
|
|
{
|
|
#define ptbn ((LPTBNOTIFY)pnm)
|
|
|
|
switch (pnm->code) {
|
|
case TBN_BEGINDRAG:
|
|
if (IsInRange(ptbn->iItem, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST))
|
|
{
|
|
Cabinet_ForwardViewMsg(pfc, WM_NOTIFY, ptbn->hdr.idFrom, (LPARAM)ptbn);
|
|
// Cabinet_ForwardViewMsg(pfc, WM_MENUSELECT, GET_WM_MENUSELECT_MPS(ptbn->iItem, 0, NULL));
|
|
}
|
|
else
|
|
{
|
|
Cabinet_OnMenuSelect(pfc, GET_WM_MENUSELECT_MPS(ptbn->iItem, 0, NULL), MH_TOOLBAR);
|
|
}
|
|
break;
|
|
|
|
case TBN_ENDDRAG:
|
|
Cabinet_OnMenuSelect(pfc, GET_WM_MENUSELECT_MPS(0, 0xffff, NULL), MH_TOOLBAR);
|
|
break;
|
|
|
|
case TBN_GETBUTTONINFO:
|
|
|
|
if (ptbn->iItem < ARRAYSIZE(c_AllButtons))
|
|
{
|
|
ptbn->tbButton.idCommand = c_AllButtons[ptbn->iItem].idCmd;
|
|
if (ptbn->tbButton.idCommand == FCIDM_DRIVELIST)
|
|
{
|
|
ptbn->tbButton.iBitmap = DrivesComboWidth();
|
|
ptbn->tbButton.fsStyle = TBSTYLE_SEP;
|
|
}
|
|
else
|
|
{
|
|
if (c_AllButtons[ptbn->iItem].idBmp & IN_STD_BMP)
|
|
ptbn->tbButton.iBitmap = (c_AllButtons[ptbn->iItem].idBmp & ~IN_STD_BMP) + pfc->iStdTBOffset;
|
|
else
|
|
ptbn->tbButton.iBitmap = c_AllButtons[ptbn->iItem].idBmp + pfc->iTBOffset;
|
|
ptbn->tbButton.fsStyle = TBSTYLE_BUTTON;
|
|
}
|
|
ptbn->tbButton.fsState = TBSTATE_ENABLED;
|
|
ptbn->tbButton.dwData = 0;
|
|
ptbn->tbButton.iString = 0;
|
|
if (ptbn->pszText)
|
|
MenuHelpFromCmd(ptbn->tbButton.idCommand, ptbn->pszText, ptbn->cchText);
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
return Toolbar_FwdTBNotify(pfc, ptbn);
|
|
|
|
case TBN_QUERYINSERT:
|
|
case TBN_QUERYDELETE:
|
|
if (ptbn->iItem < ARRAYSIZE(c_AllButtons))
|
|
{
|
|
// can't insert before or delete drive list
|
|
return ptbn->iItem != 0;
|
|
}
|
|
else
|
|
return Toolbar_FwdTBNotify(pfc, ptbn);
|
|
|
|
case TBN_RESET:
|
|
case TBN_BEGINADJUST:
|
|
case TBN_ENDADJUST:
|
|
case TBN_TOOLBARCHANGE:
|
|
case TBN_CUSTHELP:
|
|
return SendMessage(pfc->hwndView, WM_NOTIFY, ptbn->hdr.idFrom, (LPARAM)ptbn);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Cabinet_OnWaitCursorNotify(PFileCabinet pfc, LPNMHDR pnm)
|
|
{
|
|
pfc->iWaitCount += (pnm->code == NM_STARTWAIT ? 1 :-1);
|
|
Assert(pfc->iWaitCount >= 0);
|
|
// Don't let it go negative or we'll never get rid of it.
|
|
if (pfc->iWaitCount < 0)
|
|
pfc->iWaitCount = 0;
|
|
// what we really want is for user to simulate a mouse move/setcursor
|
|
SetCursor(LoadCursor(NULL, pfc->iWaitCount ? IDC_APPSTARTING : IDC_ARROW));
|
|
}
|
|
|
|
int GotoFolder(PFileCabinet pfc, LPNMRUNFILE pnm)
|
|
{
|
|
TCHAR szFullPath[MAX_PATH];
|
|
BOOL fFound;
|
|
LPCTSTR dirs[2] = { pnm->lpszWorkingDir, NULL};
|
|
lstrcpy(szFullPath, pnm->lpszCmd);
|
|
|
|
|
|
// call PathResolve twice to give preference to non extension things
|
|
fFound = PathResolve(szFullPath, dirs, PRF_FIRSTDIRDEF) && PathFileExists(szFullPath);
|
|
if (!fFound) {
|
|
lstrcpy(szFullPath, pnm->lpszCmd);
|
|
PathResolve(szFullPath, dirs, PRF_VERIFYEXISTS | PRF_TRYPROGRAMEXTENSIONS | PRF_FIRSTDIRDEF);
|
|
}
|
|
if (fFound) {
|
|
NEWFOLDERINFO fi;
|
|
|
|
fi.hwndCaller = pfc->hwndMain;
|
|
fi.pidl = ILCreateFromPath(szFullPath);
|
|
fi.uFlags = COF_EXPLORE | COF_USEOPENSETTINGS | COF_CHANGEROOTOK;
|
|
fi.nShow = pnm->nShowCmd;
|
|
|
|
if (!PathIsDirectory(szFullPath)) {
|
|
// this is NOT folder... goto it and select it
|
|
fi.uFlags |= COF_SELECT;
|
|
}
|
|
Cabinet_OpenFolder(&fi);
|
|
|
|
ILFree(fi.pidl);
|
|
|
|
return RFR_SUCCESS;
|
|
|
|
} else {
|
|
ShellMessageBox(hinstCabinet, pfc->hwndMain, MAKEINTRESOURCE(IDS_GOTO_ERROR),
|
|
MAKEINTRESOURCE(IDS_GOTOTITLE), MB_OK|MB_SETFOREGROUND|MB_ICONSTOP,
|
|
PathFindFileName(pnm->lpszCmd));
|
|
return RFR_FAILURE;
|
|
}
|
|
|
|
}
|
|
|
|
LRESULT Cabinet_OnNotify(PFileCabinet pfc, LPNMHDR pnm)
|
|
{
|
|
switch (pnm->idFrom) {
|
|
case FCIDM_TREE:
|
|
return Tree_OnNotify(pfc, pnm);
|
|
|
|
case FCIDM_TOOLBAR:
|
|
return Toolbar_OnNotify(pfc, pnm);
|
|
|
|
case 0: // special WM_NOTIFY msgs
|
|
|
|
switch (pnm->code) {
|
|
|
|
case SEN_DDEEXECUTE:
|
|
return DDEHandleViewFolderNotify(pfc, (LPNMVIEWFOLDER)pnm);
|
|
|
|
case RFN_EXECUTE:
|
|
return GotoFolder(pfc, (LPNMRUNFILE)pnm);
|
|
|
|
case NM_STARTWAIT:
|
|
case NM_ENDWAIT:
|
|
Cabinet_OnWaitCursorNotify(pfc, pnm);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
// the id is from the view, probably one of the toolbar items
|
|
|
|
if (IsInRange(pnm->idFrom, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST))
|
|
{
|
|
if (pfc->hwndView)
|
|
SendMessage(pfc->hwndView, WM_NOTIFY, pnm->idFrom, (LPARAM)pnm);
|
|
}
|
|
else
|
|
{
|
|
switch (pnm->code) {
|
|
case TTN_NEEDTEXT:
|
|
#define ptt ((LPTOOLTIPTEXT)pnm)
|
|
|
|
ToolTipFromCmd(pnm->idFrom, ptt->szText, ARRAYSIZE(ptt->szText));
|
|
|
|
#undef ptt
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
struct {
|
|
int idBmp;
|
|
UINT idCmd;
|
|
} c_idBitmapCmdMap[] = {
|
|
{STD_CUT, FCIDM_MOVE},
|
|
{STD_COPY, FCIDM_COPY},
|
|
{STD_PASTE, FCIDM_PASTE},
|
|
{STD_DELETE, FCIDM_DELETE},
|
|
{STD_PROPERTIES, FCIDM_PROPERTIES},
|
|
};
|
|
#pragma data_seg()
|
|
|
|
|
|
|
|
UINT InterceptToolbarCommand(PFileCabinet pfc, UINT idCmd)
|
|
{
|
|
int idBitmap = SendMessage(pfc->hwndToolbar, TB_GETBITMAP, idCmd, 0) - pfc->iStdTBOffset;
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAYSIZE(c_idBitmapCmdMap); i++) {
|
|
if (c_idBitmapCmdMap[i].idBmp == idBitmap) {
|
|
idCmd = c_idBitmapCmdMap[i].idCmd;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return idCmd;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// dispatch WM_COMMAND messages
|
|
//
|
|
|
|
void Cabinet_OnCommand(PFileCabinet pfc, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam);
|
|
HWND hwnd = GET_WM_COMMAND_HWND(wParam, lParam);
|
|
|
|
if (pfc->hwndTree && pfc->nSelChangeTimer)
|
|
Tree_RealHandleSelChange(pfc);
|
|
|
|
if (hwnd && hwnd == pfc->hwndToolbar &&
|
|
GetFocus() == pfc->hwndTree) {
|
|
idCmd = InterceptToolbarCommand(pfc, idCmd);
|
|
}
|
|
|
|
switch (idCmd) {
|
|
|
|
case FCIDM_DRIVELIST:
|
|
DriveList_Command(pfc, GET_WM_COMMAND_CMD(wParam, lParam));
|
|
break;
|
|
|
|
case FCIDM_FILECLOSE:
|
|
// lpndOpen is invalid -- we shouldn't use it any more!
|
|
pfc->lpndOpen = NULL;
|
|
PostMessage(pfc->hwndMain, WM_CLOSE, 0, 0);
|
|
break;
|
|
|
|
#ifdef WANT_MENUONOFF
|
|
case FCIDM_VIEWMENU:
|
|
pfc->wv.bMenuBar ^= -1;
|
|
goto ShowHide;
|
|
#endif // WANT_MENUONOFF
|
|
|
|
case FCIDM_VIEWTOOLBAR:
|
|
pfc->wv.bToolBar ^= -1;
|
|
if (pfc->hwndDrives && !IsWindowVisible(pfc->hwndDrives)) {
|
|
DriveList_UpdatePath(pfc, FALSE);
|
|
}
|
|
goto ShowHide;
|
|
case FCIDM_VIEWSTATUSBAR:
|
|
pfc->wv.bStatusBar ^= -1;
|
|
goto ShowHide;
|
|
|
|
ShowHide:
|
|
SetWindowStates(pfc);
|
|
break;
|
|
|
|
case FCIDM_CONNECT:
|
|
DoNetConnect(pfc->hwndMain);
|
|
break;
|
|
|
|
case FCIDM_DISCONNECT:
|
|
DoNetDisconnect(pfc->hwndMain);
|
|
break;
|
|
|
|
case FCIDM_FINDFILES:
|
|
SHFindFiles(pfc->pidl, NULL);
|
|
break;
|
|
|
|
case FCIDM_GOTO:
|
|
if (pfc->hwndTree)
|
|
{
|
|
LPITEMIDLIST pidlAbs = OTCloneAbsIDList(pfc->pidl);
|
|
|
|
if (pidlAbs)
|
|
{
|
|
_RunFileDlg(pfc->hwndMain, ICO_GOTO, pidlAbs, IDS_GOTOTITLE, IDS_GOTOPROMPT,
|
|
RFD_NODEFFILE|RFD_NOBROWSE|RFD_NOSHOWOPEN|RFD_NOSEPMEMORY_BOX);
|
|
ILFree(pidlAbs);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FCIDM_OPTIONS: // View.Options...
|
|
Cabinet_DoOptions(pfc);
|
|
break;
|
|
|
|
case FCIDM_PREVIOUSFOLDER:
|
|
Cabinet_ViewFolder(pfc, TRUE);
|
|
break;
|
|
|
|
// Help Topic... is provided by the view
|
|
#if 0
|
|
case FCIDM_HELPSEARCH:
|
|
WinHelp(pfc->hwndMain, c_szWindowsHlp, HELP_FINDER, 0);
|
|
break;
|
|
#endif
|
|
|
|
case FCIDM_HELPABOUT:
|
|
DoAboutChicago(pfc->hwndMain);
|
|
break;
|
|
|
|
case FCIDM_NEXTCTL:
|
|
FileCabinet_CycleFocus(pfc);
|
|
break;
|
|
|
|
case FCIDM_DROPDRIVLIST:
|
|
DriveList_OpenClose(OCDL_TOGGLE, pfc->hwndDrives);
|
|
break;
|
|
|
|
case FCIDM_REFRESH:
|
|
// REVIEW: we may want to invalidate the current drive
|
|
{
|
|
BOOL fChangedView = FALSE;
|
|
|
|
if (pfc->pidl)
|
|
{
|
|
// If we are on a drive we invalidate the
|
|
// drive...
|
|
TCHAR szPath[MAX_PATH];
|
|
if (SHGetPathFromIDList(pfc->pidl, szPath) &&
|
|
!PathIsUNC(szPath) && (szPath[1] == TEXT(':')))
|
|
{
|
|
int iDrive;
|
|
if (szPath[0] >= TEXT('a') && szPath[0] <= TEXT('z'))
|
|
iDrive = szPath[0] - TEXT('a');
|
|
else
|
|
iDrive = szPath[0] - TEXT('A');
|
|
InvalidateDriveType(iDrive);
|
|
}
|
|
}
|
|
|
|
if (pfc->hwndMain != v_hwndDesktop)
|
|
Cabinet_GlobalStateChange(pfc);
|
|
|
|
if (pfc->hwndTree) {
|
|
|
|
OTInvalidateAll();
|
|
fChangedView = Tree_RefreshAll(pfc);
|
|
}
|
|
|
|
if (pfc->hwndDrives && IsWindowVisible(pfc->hwndDrives))
|
|
DriveList_UpdatePath(pfc, TRUE);
|
|
|
|
// Notify the ShellView of this user action. We don't care
|
|
// about the return value.
|
|
//
|
|
if (pfc->psv && !fChangedView) {
|
|
pfc->psv->lpVtbl->Refresh(pfc->psv);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FCIDM_MOVE:
|
|
Cabinet_InvokeCommandOnItem(pfc, c_szMove);
|
|
break;
|
|
|
|
case FCIDM_COPY:
|
|
Cabinet_InvokeCommandOnItem(pfc, c_szCopy);
|
|
break;
|
|
|
|
case FCIDM_PASTE:
|
|
Cabinet_InvokeCommandOnItem(pfc, c_szPaste);
|
|
break;
|
|
|
|
case FCIDM_LINK:
|
|
Cabinet_InvokeCommandOnItem(pfc, c_szLink);
|
|
break;
|
|
|
|
case FCIDM_DELETE:
|
|
{
|
|
#if 0
|
|
LPITEMIDLIST pidlParent = ILClone(pfc->pidl);
|
|
#endif
|
|
|
|
Cabinet_InvokeCommandOnItem(pfc, c_szDelete);
|
|
|
|
// BUGBUG: if the delete was canceled this is bogus
|
|
// perhaps just let the file sys change notify do the right thing
|
|
#if 0
|
|
if (pidlParent)
|
|
{
|
|
if (ILRemoveLastID(pidlParent))
|
|
{
|
|
Cabinet_SetPath(pfc, 0, pidlParent);
|
|
Tree_Refresh(pfc, pidlParent);
|
|
}
|
|
ILFree(pidlParent);
|
|
}
|
|
#endif
|
|
if (pfc->hwndTree)
|
|
SHChangeNotifyHandleEvents();
|
|
}
|
|
break;
|
|
|
|
case FCIDM_PROPERTIES:
|
|
Cabinet_InvokeCommandOnItem(pfc, c_szProperties);
|
|
break;
|
|
|
|
case FCIDM_RENAME:
|
|
{
|
|
HTREEITEM hti = TreeView_GetSelection(pfc->hwndTree);
|
|
if (hti)
|
|
TreeView_EditLabel(pfc->hwndTree, hti);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DebugMsg(DM_TRACE, TEXT("Cabinet_OnCommand, (%d) in default"), idCmd);
|
|
if (IsInRange(idCmd, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST))
|
|
{
|
|
if (pfc->hwndView)
|
|
SendMessage(pfc->hwndView, WM_COMMAND, wParam, lParam);
|
|
else
|
|
DebugMsg(DM_TRACE, TEXT("view cmd id with NULL view"));
|
|
}
|
|
else if (IsInRange(idCmd, FCIDM_MENU_TOOLS_FINDFIRST, FCIDM_MENU_TOOLS_FINDLAST) &&
|
|
!_Restricted(pfc->hwndMain, REST_NOFIND))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
if (pfc->pcmFind) {
|
|
CMINVOKECOMMANDINFOEX ici = {
|
|
SIZEOF(CMINVOKECOMMANDINFOEX),
|
|
0L,
|
|
pfc->hwndMain,
|
|
(LPSTR)MAKEINTRESOURCE(idCmd - FCIDM_MENU_TOOLS_FINDFIRST),
|
|
NULL, NULL,
|
|
SW_NORMAL,
|
|
};
|
|
|
|
if (pfc->pidl) {
|
|
#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
|
|
}
|
|
pfc->pcmFind->lpVtbl->InvokeCommand(pfc->pcmFind,
|
|
(LPCMINVOKECOMMANDINFO)&ici);
|
|
|
|
} else {
|
|
DebugMsg(DM_TRACE, TEXT("find cmd with NULL pcmFind"));
|
|
}
|
|
|
|
} else {
|
|
DebugMsg(DM_ERROR, TEXT("command.c ERROR: command not processed %x"), wParam);
|
|
#ifdef DEBUG
|
|
MessageBeep(0);
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
}
|