6181 lines
190 KiB
Plaintext
6181 lines
190 KiB
Plaintext
#include "priv.h"
|
|
#include "shbrowse.h"
|
|
#include "ieframe.h"
|
|
#include <fsmenu.h>
|
|
#include "stdenum.h"
|
|
#include <iethread.h>
|
|
#include "iedde.h"
|
|
#include "bindcb.h"
|
|
#include "explorer.h"
|
|
#include "dochost.h"
|
|
#include "favorite.h"
|
|
#include "winlist.h"
|
|
#include <shdguid.h>
|
|
#include <isguids.h>
|
|
#include "cabdde.h"
|
|
#include "desktop.h"
|
|
#include "htregmng.h"
|
|
#include <htmlguid.h>
|
|
#include <shperf.h>
|
|
#include "findsim.h"
|
|
#include <ntverp.h>
|
|
#include "bands.h"
|
|
#include "deskbar.h"
|
|
#include "events.h"
|
|
#include "itbdrop.h"
|
|
#include "inpobj.h"
|
|
|
|
//
|
|
// BUGBUG: Remove this #include by defining _pauto as IWebBrowserApp, just like
|
|
// Explorer.exe.
|
|
//
|
|
#include "hlframe.h"
|
|
|
|
#define SUPERCLASS CBaseBrowser
|
|
|
|
//3531F060-22B3-11D0-969E-00AA00B60104
|
|
// used when communicating with the Internet Toolbar.
|
|
const GUID CGID_ShellBrowser = { 0x3531F060L, 0x22B3, 0x11D0, 0x96, 0x9E, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04 };
|
|
// Command group for private communication with CITBar
|
|
// 67077B95-4F9D-11D0-B884-00AA00B60104
|
|
const GUID CGID_PrivCITCommands = { 0x67077B95L, 0x4F9D, 0x11D0, 0xB8, 0x84, 0x00, 0xAA, 0x00, 0xB6, 0x01, 0x04 };
|
|
|
|
|
|
const TCHAR c_szHelpFile[] = TEXT("iexplore.hlp");
|
|
const TCHAR c_szExploreClass[] = TEXT("ExploreWClass");
|
|
const TCHAR c_szOpenIDL[] = TEXT("/idlist,:%ld:%ld,/root,/idlist,:%ld:%ld");
|
|
const TCHAR c_szExploreIDL[] = TEXT(",/e");
|
|
const TCHAR c_szIExploreClass[] = TEXT("IEFrame");
|
|
const TCHAR c_szCabinetClass[] =
|
|
#ifdef IE3CLASSNAME
|
|
TEXT("IEFrame");
|
|
#else
|
|
TEXT("CabinetWClass");
|
|
#endif
|
|
|
|
// Names of autodial monitor windows - send messages to these guys when
|
|
// it's a good time to hang up
|
|
const TCHAR szAutodialMonitorClass[] = TEXT("MS_AutodialMonitor");
|
|
const TCHAR szWebCheckMonitorClass[] = TEXT("MS_WebcheckMonitor");
|
|
|
|
// Increment this when the saved structure changes
|
|
const USHORT c_uVersion = 0x8001;
|
|
|
|
//
|
|
// g_pidlRoot is a pidl to the "visual root" on the tree from the "logical"
|
|
// root. The logical root is typically the desktop.
|
|
//
|
|
// g_pidlRootClass normally NULL, which indicates that the logical root
|
|
// is the desktop. g_pidlRootClass is non-NULL if we are dealing with
|
|
// an external name-space.
|
|
//
|
|
// g_psfDesktop is the IShellFolder interface to the logical root (which
|
|
// is indicated by g_pidlRootClass).
|
|
//
|
|
|
|
LPCITEMIDLIST g_pidlRoot = &s_idlNULL;
|
|
LPCITEMIDLIST g_pidlRootClass = NULL;
|
|
IShellFolder* g_psfDesktop = NULL;
|
|
|
|
int g_iRootImage = -1;
|
|
LONG g_lSessionCount = 0; // this is the ref count of how many internet windows we have open
|
|
|
|
UINT g_sysmenuTimer = 0;
|
|
|
|
void IEInitializeClassFactoryObject(IUnknown* punkAuto);
|
|
|
|
IStream *GetITBarStream(LPITEMIDLIST pidl, DWORD grfMode);
|
|
|
|
|
|
#define VALIDATEPENDINGSTATE() ASSERT((_psvPending && _psfPending) || (!_psvPending && !_psfPending))
|
|
|
|
#define DM_TRSITE 0
|
|
#define DM_NAV TF_SHDNAVIGATE
|
|
#define DM_ZONE TF_SHDNAVIGATE
|
|
#define DM_IEDDE TF_SHDAUTO
|
|
#define DM_CANCELMODE 0
|
|
#define DM_UIWINDOW 0
|
|
#define DM_ENABLEMODELESS 0
|
|
#define DM_EXPLORERMENU 0
|
|
#define DM_BACKFORWARD 0
|
|
#define DM_PROTOCOL 0
|
|
#define DM_ITBAR 0
|
|
#define DM_STARTUP 0
|
|
#define DM_AUTOLIFE 0
|
|
#define DM_PALETTE 0
|
|
#define DM_ACCELERATOR 0
|
|
#define DM_SESSIONCOUNT 0
|
|
#define DM_FOCUS 0
|
|
|
|
#define THRMSG2(psz, x) TraceMsg(0, "ief THREAD::%s %x", psz, x)
|
|
#define PARKMSG(psz, x) TraceMsg(TF_SHDTHREAD, "ief PARK::%s %x", psz, x)
|
|
#define MSGMSG(psz, x) TraceMsg(TF_SHDTHREAD, "ief MSG::%s %x", psz, x)
|
|
|
|
// BUGBUG: Put it in tlog.h
|
|
LPITEMIDLIST GetLinkTarget(LPTSTR pszLink, DWORD dwAttribs);
|
|
|
|
extern BOOL CDownload_MayProcessMessage(MSG* pmsg);
|
|
extern BOOL ViewIDFromViewMode(UINT uViewMode, SHELLVIEWID *pvid);
|
|
UINT GetAutoObjMsg(void);
|
|
BOOL IsExplorerWindow(HWND hwnd);
|
|
|
|
#ifdef DEBUG
|
|
DWORD g_dwPerf = 0;
|
|
#endif
|
|
|
|
typedef struct _NAVREQUEST
|
|
{
|
|
int cbNavData;
|
|
BYTE *lpNavData;
|
|
struct _NAVREQUEST *pnext;
|
|
} NAVREQUEST;
|
|
|
|
// copied from explore/cabwnd.h
|
|
#define MH_POPUP 0x0010
|
|
#define MH_TOOLBAR 0x0020
|
|
|
|
#define TBOFFSET_NONE 50
|
|
#define TBOFFSET_STD 0
|
|
#define TBOFFSET_HIST 1
|
|
#define TBOFFSET_VIEW 2
|
|
|
|
extern DWORD g_dwStopWatchMode; // Shell performance mode
|
|
|
|
extern HRESULT TargetQueryService(LPUNKNOWN punk, REFIID riid, void **ppvObj);
|
|
// #define PAINTINGOPTS
|
|
|
|
STDAPI_(void) IEAboutBox( HWND hWnd );
|
|
|
|
STDAPI SafeGetItemObject(LPSHELLVIEW psv, UINT uItem, REFIID riid, LPVOID *ppv);
|
|
|
|
#define MAIL_DEF_KEY TEXT("Software\\Clients\\Mail")
|
|
#define NEWS_DEF_KEY TEXT("Software\\Clients\\News")
|
|
|
|
HMENU g_hmenuTemplateSB = NULL;
|
|
HMENU g_hmenuFullSB = NULL;
|
|
HMENU _MenuTemplate(int id);
|
|
|
|
#define SHELLBROWSER_FSNOTIFY_FLAGS (SHCNE_DRIVEADDGUI | SHCNE_SERVERDISCONNECT | \
|
|
SHCNE_MEDIAREMOVED | SHCNE_RMDIR | \
|
|
SHCNE_UPDATEDIR | SHCNE_NETUNSHARE | \
|
|
SHCNE_DRIVEREMOVED | SHCNE_UPDATEITEM | \
|
|
SHCNE_RENAMEFOLDER | SHCNE_UPDATEIMAGE | \
|
|
SHCNE_MEDIAINSERTED | SHCNE_DRIVEADD)
|
|
|
|
#pragma warning(disable:4355) // using 'this' in constructor
|
|
CShellBrowser::CShellBrowser() :
|
|
_fStatusBar(TRUE),
|
|
_fShowMenu(TRUE),
|
|
_trsiteSB(SAFECAST(this, CBaseBrowser *))
|
|
{
|
|
_SetTopBrowser();
|
|
_aTBar[ITB_ITBAR].fShow = TRUE;
|
|
_itbLastFocus = ITB_VIEW;
|
|
_hdpaDLM = DPA_Create(4);
|
|
_nTBTextRows = -1;
|
|
_InitSysImageLists();
|
|
|
|
// Initilaize the base class transition site pointer.
|
|
_ptrsite = &_trsiteSB;
|
|
}
|
|
#pragma warning(default:4355) // using 'this' in constructor
|
|
|
|
HRESULT CShellBrowser_CreateInstance(HWND hwnd, LPVOID* ppsb)
|
|
{
|
|
*ppsb = new CShellBrowser();
|
|
|
|
return CBaseBrowser_Validate(hwnd, ppsb);
|
|
}
|
|
|
|
CShellBrowser::~CShellBrowser()
|
|
{
|
|
// If automation was enabled, kill it now
|
|
if (_hmenuFav)
|
|
FileMenu_Destroy(_hmenuFav);
|
|
if (_pxtb)
|
|
_pxtb->Release();
|
|
if (_lpPendingBtns)
|
|
LocalFree(_lpPendingBtns);
|
|
if (_ptrsite)
|
|
_ptrsite = NULL;
|
|
|
|
TraceMsg(TF_SHDLIFE, "dtor CShellBrowser %x", this);
|
|
}
|
|
|
|
int CDECL MRUILIsEqual(const void *pidl1, const void *pidl2, size_t cb)
|
|
{
|
|
// First cheap hack to see if they are 100 percent equal for performance
|
|
int iCmp = memcmp(pidl1, pidl2, cb);
|
|
|
|
if (iCmp == 0)
|
|
return 0;
|
|
|
|
if (ILIsEqual((LPITEMIDLIST)pidl1, (LPITEMIDLIST)pidl2))
|
|
return 0;
|
|
|
|
return iCmp;
|
|
}
|
|
|
|
void CShellBrowser::v_FillCabStateHeader(CABSH* pcabsh, FOLDERSETTINGS* pfs)
|
|
{
|
|
WINDOWPLACEMENT wp;
|
|
|
|
|
|
pcabsh->wv.bToolBar = FALSE;
|
|
pcabsh->wv.bITBar = _aTBar[ITB_ITBAR].fShow;
|
|
pcabsh->wv.bStatusBar = _fStatusBar;
|
|
|
|
wp.length = SIZEOF(WINDOWPLACEMENT);
|
|
GetWindowPlacement(_hwnd, &wp);
|
|
|
|
pcabsh->dwHotkey = (UINT)SendMessage(_hwnd, WM_GETHOTKEY, 0, 0);
|
|
|
|
//
|
|
// Now Lets convert all of this common stuff into a
|
|
// non 16/32 bit dependant data structure, such that both
|
|
// can us it.
|
|
//
|
|
pcabsh->dwSize = SIZEOF(*pcabsh);
|
|
pcabsh->flags = wp.flags;
|
|
|
|
// Don't store us as minimized
|
|
if (wp.showCmd == SW_SHOWMINIMIZED ||
|
|
wp.showCmd == SW_MINIMIZE)
|
|
pcabsh->showCmd = SW_SHOWNORMAL;
|
|
else
|
|
pcabsh->showCmd = wp.showCmd;
|
|
pcabsh->ptMinPosition.x = wp.ptMinPosition.x;
|
|
pcabsh->ptMinPosition.y = wp.ptMinPosition.y;
|
|
pcabsh->ptMaxPosition.x = wp.ptMaxPosition.x;
|
|
pcabsh->ptMaxPosition.y = wp.ptMaxPosition.y;
|
|
|
|
pcabsh->rcNormalPosition = *((RECTL*)&wp.rcNormalPosition);
|
|
|
|
// Now the folder settings
|
|
pcabsh->ViewMode = pfs->ViewMode;
|
|
// NB Don't ever preserve the best-fit flag or the nosubfolders flag.
|
|
pcabsh->fFlags = pfs->fFlags & ~FWF_NOSUBFOLDERS & ~FWF_BESTFITWINDOW;
|
|
|
|
pcabsh->fMask = CABSHM_VERSION;
|
|
pcabsh->dwVersionId = CABSH_VER;
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Closing a cabinet window.
|
|
//
|
|
// save it's local view info in the directory it is looking at
|
|
//
|
|
// NOTE: this will fail on read only media like net or cdrom
|
|
//
|
|
// REVIEW: we may not want to save this info on removable media
|
|
// (but if we don't allow a switch to force this!)
|
|
//
|
|
void CShellBrowser::_SaveState()
|
|
{
|
|
|
|
// Don't save any state info if restrictions are in place.
|
|
|
|
// We are trying to give a way for automation scripts to run that do not
|
|
// update the view state. To handle this we say if the window is not visible
|
|
// (the script can set or unset visibility) than do not save the state (unless
|
|
// falways add...)
|
|
// Notwithstanding the above comments, suppress updating view state if UI
|
|
// was set by automation
|
|
if (_fUISetByAutomation ||
|
|
!g_CabState.fSaveLocalView ||
|
|
(SHRestricted(REST_NOSAVESET) || !IsWindowVisible(_hwnd)))
|
|
return;
|
|
|
|
if (_psv)
|
|
{
|
|
IStream* pstm = NULL;
|
|
|
|
IShellView2 *psv2;
|
|
SHELLVIEWID vid;
|
|
BOOL bGotVID = FALSE;
|
|
|
|
if (SUCCEEDED(_psv->QueryInterface(IID_IShellView2,
|
|
(LPVOID*)&psv2)))
|
|
{
|
|
if (NOERROR == psv2->GetView(&vid, SV2GV_CURRENTVIEW))
|
|
{
|
|
bGotVID = TRUE;
|
|
}
|
|
|
|
psv2->Release();
|
|
}
|
|
|
|
if (!_fSBWSaved) {
|
|
pstm = v_GetViewStream(_pidlCur, STGM_WRITE, TEXT("CabView"));
|
|
_fSBWSaved = TRUE;
|
|
}
|
|
|
|
FOLDERSETTINGS fs;
|
|
|
|
// Now get the view information
|
|
_psv->GetCurrentInfo(&fs);
|
|
|
|
// if these keys are down, save the current states
|
|
if (IsCShellBrowser() &&
|
|
GetAsyncKeyState(VK_CONTROL) < 0) {
|
|
|
|
if (g_CabState.fNewWindowMode) {
|
|
g_dfs.bDefToolBarMulti = FALSE;
|
|
} else {
|
|
g_dfs.bDefToolBarSingle = FALSE;
|
|
}
|
|
|
|
g_dfs.fFlags = fs.fFlags & ( FWF_AUTOARRANGE ); // choose the ones we case about
|
|
g_dfs.uDefViewMode = fs.ViewMode;
|
|
g_dfs.bDefStatusBar = _fStatusBar;
|
|
|
|
g_dfs.bUseVID = bGotVID;
|
|
if (bGotVID)
|
|
{
|
|
g_dfs.vid = vid;
|
|
}
|
|
else
|
|
{
|
|
ViewIDFromViewMode(g_dfs.uDefViewMode, &g_dfs.vid);
|
|
}
|
|
|
|
SaveDefaultFolderSettings();
|
|
}
|
|
|
|
|
|
if (pstm)
|
|
{
|
|
ULARGE_INTEGER uliOffset = {0, 0};
|
|
LARGE_INTEGER li = {0, 0};
|
|
CABSH cabsh;
|
|
|
|
v_FillCabStateHeader(&cabsh, &fs);
|
|
|
|
if (bGotVID)
|
|
{
|
|
cabsh.vid = vid;
|
|
cabsh.fMask |= CABSHM_VIEWID;
|
|
}
|
|
|
|
//
|
|
// First output the common non view specific information
|
|
//
|
|
pstm->Write(&cabsh, SIZEOF(cabsh), NULL);
|
|
|
|
// And release it, which will commit it to disk..
|
|
pstm->Release();
|
|
|
|
// Last but not least save away the view state.
|
|
_psv->SaveViewState();
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (g_dwPrototype & 0x00000010) {
|
|
//
|
|
// Save toolbars
|
|
//
|
|
pstm = v_GetViewStream(_pidlCur, STGM_WRITE, TEXT("Toolbars"));
|
|
if (pstm) {
|
|
_SaveToolbars(pstm);
|
|
pstm->Release();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
IStream* GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCTSTR pszName, LPCTSTR pszStreamMRU, LPCTSTR pszStreams)
|
|
{
|
|
IStream *pstm = NULL;
|
|
HANDLE hmru;
|
|
int iFoundSlot = -1;
|
|
UINT cbPidl;
|
|
MRUINFO mi = {
|
|
SIZEOF(MRUINFO),
|
|
50, // we store this many view streams
|
|
MRU_BINARY,
|
|
HKEY_CURRENT_USER,
|
|
pszStreamMRU,
|
|
(MRUCMPPROC)MRUILIsEqual,
|
|
};
|
|
|
|
ASSERT(pidl);
|
|
|
|
// Now lets try to save away the other information associated with view.
|
|
hmru = CreateMRUList(&mi);
|
|
if (!hmru)
|
|
return NULL;
|
|
|
|
cbPidl = ILGetSize(pidl);
|
|
|
|
FindMRUData(hmru, pidl, cbPidl, &iFoundSlot);
|
|
|
|
// Did we find the item?
|
|
if (iFoundSlot < 0 && ((grfMode & (STGM_READ|STGM_WRITE|STGM_READWRITE)) == STGM_READ))
|
|
{
|
|
// Do not create the stream if it does not exist and we are
|
|
// only reading
|
|
}
|
|
else
|
|
{
|
|
HKEY hkCabStreams;
|
|
|
|
ASSERT(g_hkeyExplorer);
|
|
|
|
// Note that we always create the key here, since we have
|
|
// already checked whether we are just reading and the MRU
|
|
// thing does not exist
|
|
if (RegCreateKey(g_hkeyExplorer, pszStreams, &hkCabStreams) == ERROR_SUCCESS)
|
|
{
|
|
HKEY hkValues;
|
|
TCHAR szValue[32], szSubVal[64];
|
|
|
|
wsprintf(szValue, TEXT("%d"), AddMRUData(hmru, pidl, cbPidl));
|
|
|
|
if (iFoundSlot < 0 && RegOpenKey(hkCabStreams, szValue, &hkValues) == ERROR_SUCCESS)
|
|
{
|
|
// This means that we have created a new MRU
|
|
// item for this PIDL, so clear out any
|
|
// information residing at this slot
|
|
// Note that we do not just delete the key,
|
|
// since that could fail if it has any sub-keys
|
|
DWORD dwType, dwSize = ARRAYSIZE(szSubVal);
|
|
|
|
while (RegEnumValue(hkValues, 0, szSubVal, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
|
|
{
|
|
if (RegDeleteValue(hkValues, szSubVal) != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkValues);
|
|
}
|
|
pstm = OpenRegStream(hkCabStreams, szValue, pszName, grfMode);
|
|
RegCloseKey(hkCabStreams);
|
|
}
|
|
}
|
|
|
|
FreeMRUList(hmru);
|
|
|
|
return pstm;
|
|
}
|
|
|
|
IStream *CShellBrowser::v_GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCTSTR pszName)
|
|
{
|
|
if (pidl)
|
|
return ::GetViewStream(pidl, grfMode, pszName, c_szStreamMRU, c_szStreams);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL CShellBrowser::_ReadSettingsFromStream(LPSTREAM pstm, PIETHREADPARAM piei)
|
|
{
|
|
ULONG cbRead;
|
|
CABSH cabsh;
|
|
|
|
// Now read in the state from the stream file.
|
|
// read the old header first.
|
|
pstm->Read(&cabsh, SIZEOF(CABSHOLD), &cbRead);
|
|
|
|
// Sanity test to make sure we read in as many bytes as expected
|
|
if ((cbRead != (ULONG)SIZEOF(CABSHOLD)) || (cabsh.dwSize < SIZEOF(CABSHOLD)))
|
|
return FALSE;
|
|
|
|
// We'll set the mask in the read
|
|
if (cabsh.dwSize<SIZEOF(CABSH) || NOERROR!=pstm->Read(((LPBYTE)&cabsh)+SIZEOF(CABSHOLD), SIZEOF(CABSH)-SIZEOF(CABSHOLD), &cbRead)
|
|
|| SIZEOF(CABSH)-SIZEOF(CABSHOLD)!=cbRead)
|
|
{
|
|
cabsh.fMask = 0;
|
|
}
|
|
|
|
// Now extract the data and put it into appropriate structures
|
|
|
|
// first the window placement info
|
|
piei->wp.length = SIZEOF(piei->wp);
|
|
piei->wp.flags = (UINT)cabsh.flags;
|
|
piei->wp.showCmd = (UINT)cabsh.showCmd;
|
|
|
|
ASSERT(SIZEOF(piei->wp.ptMinPosition) == SIZEOF(cabsh.ptMinPosition));
|
|
piei->wp.ptMinPosition = *((LPPOINT)&cabsh.ptMinPosition);
|
|
piei->wp.ptMaxPosition = *((LPPOINT)&cabsh.ptMaxPosition);
|
|
|
|
ASSERT(SIZEOF(piei->wp.rcNormalPosition) == SIZEOF(cabsh.rcNormalPosition));
|
|
piei->wp.rcNormalPosition = *((RECT*)&cabsh.rcNormalPosition);
|
|
|
|
// Do some simple sanity checks to make sure that the returned
|
|
// information appears to be reasonable and not random garbage
|
|
// We want the Show command to be normal or minimize or maximize.
|
|
// Only need one test as they are consectutive and start at zero
|
|
// DON'T try to validate too much of the WINDOWPLACEMENT--
|
|
// SetWindowPlacement does a much better job, especially in
|
|
// multiple-monitor scenarios...
|
|
//
|
|
if (piei->wp.showCmd > SW_MAX)
|
|
return FALSE;
|
|
|
|
// Now the folder settings
|
|
piei->fs.ViewMode = (UINT)cabsh.ViewMode;
|
|
piei->fs.fFlags = (UINT)cabsh.fFlags;
|
|
piei->TreeSplit = (UINT)cabsh.TreeSplit;
|
|
|
|
if (cabsh.fMask & CABSHM_VIEWID)
|
|
{
|
|
piei->m_vidRestore = cabsh.vid;
|
|
piei->m_bRestoreView = TRUE;
|
|
}
|
|
if (!(cabsh.fMask & CABSHM_VERSION) || (cabsh.dwVersionId < CABSH_VER))
|
|
{
|
|
piei->m_vidRestore = DFS_VID_Default;
|
|
piei->m_bRestoreView = TRUE;
|
|
}
|
|
|
|
// And the Hotkey
|
|
piei->wHotkey = (UINT)cabsh.dwHotkey;
|
|
|
|
piei->wv = cabsh.wv;
|
|
piei->fs.fFlags &= ~FWF_BESTFITWINDOW;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CShellBrowser::_LoadBrowserWindowSettings(PIETHREADPARAM piei, LPCITEMIDLIST pidl)
|
|
{
|
|
IStream* pstm = v_GetViewStream(pidl, STGM_READ, TEXT("CabView"));
|
|
|
|
if (g_fCleanBoot || !pstm || !_ReadSettingsFromStream(pstm, piei))
|
|
v_GetDefaultSettings(piei);
|
|
|
|
//Copy the two restore settings from piei to ShellBrowser.
|
|
_vidRestore = piei->m_vidRestore;
|
|
_bRestoreView = piei->m_bRestoreView;
|
|
|
|
if (pstm)
|
|
pstm->Release();
|
|
|
|
_aTBar[ITB_ITBAR].fShow = piei->wv.bITBar;
|
|
|
|
_fStatusBar = piei->wv.bStatusBar;
|
|
_fs = piei->fs;
|
|
SendMessage(_hwnd, WM_SETHOTKEY, piei->wHotkey, 0);
|
|
|
|
#ifdef DEBUG
|
|
if (g_dwPrototype & 0x00000010) {
|
|
//
|
|
// Load toolbars
|
|
//
|
|
pstm = v_GetViewStream(pidl, STGM_READ, TEXT("Toolbars"));
|
|
if (pstm) {
|
|
_LoadToolbars(pstm);
|
|
pstm->Release();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CShellBrowser::_ReleaseShellView(void)
|
|
{
|
|
SUPERCLASS::_ReleaseShellView();
|
|
|
|
// NOTES: (SatoNa)
|
|
//
|
|
// This is the best time to clean up the left-over from UI-negotiation
|
|
// from the previous DocObject. Excel 97, for some reason, takes 16
|
|
// pixels from the top (for the formula bar) when we UI-deactivate it
|
|
// by callin gIOleDocumentView::UIActivate(FALSE), which we call when
|
|
// we call SUPERCLASS::_ReleaseShellView().
|
|
//
|
|
SetRect(&_rcBorderDoc, 0, 0, 0, 0);
|
|
}
|
|
|
|
void CShellBrowser::_UpdateChildWindowSize(void)
|
|
{
|
|
if (!_fFullScreen) {
|
|
if (_hwndStatus && _fStatusBar) {
|
|
SendMessage(_hwndStatus, WM_SIZE, 0, 0L);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// This is a virtual member of CBaseBrowser class, which we call when we
|
|
// set the size and position of IShellView rectangle.
|
|
//
|
|
void CShellBrowser::_GetViewRect(RECT* prc)
|
|
{
|
|
SUPERCLASS::_GetViewRect(prc);
|
|
|
|
// Subtract document toolbar margin
|
|
prc->left += _rcBorderDoc.left;
|
|
prc->top += _rcBorderDoc.top;
|
|
prc->right -= _rcBorderDoc.right;
|
|
prc->bottom -= _rcBorderDoc.bottom;
|
|
|
|
TraceMsg(DM_UIWINDOW, "ief _GetViewRect _rcBorderDoc=%x,%x,%x,%x",
|
|
_rcBorderDoc.left, _rcBorderDoc.top, _rcBorderDoc.right, _rcBorderDoc.bottom);
|
|
TraceMsg(DM_UIWINDOW, "ief _GetViewRect prc=%x,%x,%x,%x",
|
|
prc->left, prc->top, prc->right, prc->bottom);
|
|
}
|
|
|
|
|
|
void CShellBrowser::v_ShowHideChildWindows(BOOL fChildOnly)
|
|
{
|
|
if (_hwndStatus)
|
|
ShowWindow(_hwndStatus, (!_fFullScreen && _fStatusBar) ? SW_SHOW : SW_HIDE);
|
|
|
|
_UpdateCommands();
|
|
|
|
_UpdateChildWindowSize();
|
|
|
|
SUPERCLASS::v_ShowHideChildWindows(fChildOnly);
|
|
|
|
// We should call _UpdateBackForwardState after the parent show/hide
|
|
// toolbars.
|
|
_UpdateBackForwardState();
|
|
}
|
|
|
|
void CShellBrowser::_SetupSysMenu()
|
|
{
|
|
HMENU hmenu = _GetMenuFromID(FCIDM_MENU_VIEW);
|
|
if (hmenu) {
|
|
HMENU hmenuSys;
|
|
// First reset the system menu, then get a modifiable copy
|
|
//
|
|
GetSystemMenu(_hwnd, TRUE);
|
|
hmenuSys = GetSystemMenu(_hwnd, FALSE);
|
|
// put a few special menu cmds on the sys menu
|
|
// steal the text from the regular menu
|
|
if (hmenuSys) {
|
|
_CopyMenu(hmenu, hmenuSys, FCIDM_VIEWTOOLBAR);
|
|
_CopyMenu(hmenu, hmenuSys, FCIDM_VIEWSTATUSBAR);
|
|
|
|
InsertMenu(hmenuSys, SC_CLOSE, MF_BYCOMMAND | MF_SEPARATOR, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::v_GetAppTitleTemplate(LPTSTR pszBuffer, LPTSTR pszTitle)
|
|
{
|
|
if (_fInternetStart) {
|
|
TCHAR szBuffer[80];
|
|
_GetAppTitle(szBuffer, SIZEOF(szBuffer));
|
|
wsprintf(pszBuffer, TEXT("%%s - %s"), szBuffer);
|
|
} else {
|
|
// don't tack on "intenet explorer" if we didn't start there
|
|
#ifdef DEBUG
|
|
lstrcpy(pszBuffer, TEXT("%s (shdocvw)"));
|
|
#else
|
|
lstrcpy(pszBuffer, TEXT("%s"));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::_GetAppTitle(LPTSTR pszBuffer, DWORD dwSize)
|
|
{
|
|
pszBuffer[0] = 0;
|
|
if (_GetRegKeyValue(HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
|
|
TEXT("Window Title"), NULL, (LPBYTE)pszBuffer, &dwSize) != ERROR_SUCCESS)
|
|
LoadString(HINST_THISDLL, IDS_TITLE, pszBuffer, dwSize / SIZEOF(TCHAR));
|
|
}
|
|
|
|
STDAPI SHFlushClipboard(void);
|
|
void CShellBrowser::_OnDestroy()
|
|
{
|
|
|
|
SUPERCLASS::_OnDestroy();
|
|
|
|
SHFlushClipboard();
|
|
|
|
if (_uNotifyFav)
|
|
SHChangeNotifyDeregister(_uNotifyFav);
|
|
|
|
if (_uFSNotify)
|
|
SHChangeNotifyDeregister(_uFSNotify);
|
|
|
|
if (_fAutomation) {
|
|
IECleanUpAutomationObject();
|
|
}
|
|
|
|
if (g_hwndProxyDesktop)
|
|
PostMessage(g_hwndProxyDesktop, DTM_RELEASEPROXYDESKTOP, 0, 0);
|
|
|
|
_DecrNetSessionCount();
|
|
|
|
_DLMDestroy();
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
BOOL CShellBrowser::_CreateToolbar()
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
void CShellBrowser::v_InitMembers()
|
|
{
|
|
_SetTitle(NULL);
|
|
|
|
_hmenuTemplate = g_hmenuTemplateSB;
|
|
_hmenuFull = g_hmenuFullSB;
|
|
_hmenuCur = _hmenuTemplate;
|
|
|
|
|
|
// things we don't want our subclass to inherit
|
|
if (v_InitMembers == CShellBrowser::v_InitMembers) {
|
|
|
|
// register to get filesys notifications
|
|
_uFSNotify = RegisterNotify(_hwnd, CWM_FSNOTIFY, NULL, SHELLBROWSER_FSNOTIFY_FLAGS, 0, TRUE);
|
|
}
|
|
|
|
|
|
_SetupSysMenu();
|
|
|
|
TraceMsg(DM_STARTUP, "ief TR WM_CREATE _hmenuTemplate=%x", _hmenuTemplate);
|
|
_hwndStatus = CreateStatusWindow(WS_CHILD | SBARS_SIZEGRIP | WS_CLIPSIBLINGS,
|
|
NULL, _hwnd, FCIDM_STATUS);
|
|
_CreateToolbar();
|
|
|
|
ASSERT(HINST_THISDLL);
|
|
_hacc = LoadAccelerators(HINST_THISDLL, MAKEINTRESOURCE(ACCEL_MERGE));
|
|
ASSERT(_hacc);
|
|
|
|
}
|
|
|
|
|
|
// REVIEW UNDONE - Stuff in programs defaults to save positions ???
|
|
void CShellBrowser::v_GetDefaultSettings(PIETHREADPARAM piei)
|
|
{
|
|
// set the flags
|
|
|
|
// Best fit window means get the window to size according to the
|
|
// contents of the view so that windows without existing settings
|
|
// come up looking OK.
|
|
piei->fs.fFlags = FWF_BESTFITWINDOW | g_dfs.fFlags;
|
|
piei->wv.bStatusBar = g_dfs.bDefStatusBar;
|
|
|
|
if (g_CabState.fSimpleDefault && g_CabState.fNewWindowMode)
|
|
{
|
|
piei->wv.bToolBar = g_dfs.bDefToolBarMulti;
|
|
}
|
|
else
|
|
{
|
|
piei->wv.bToolBar = g_dfs.bDefToolBarSingle;
|
|
}
|
|
|
|
//By default, the ITBar must be turned On!
|
|
piei->wv.bITBar = TRUE;
|
|
|
|
piei->fs.ViewMode = g_dfs.uDefViewMode;
|
|
piei->m_vidRestore = g_dfs.vid;
|
|
piei->m_bRestoreView = g_dfs.bUseVID;
|
|
ASSERT(piei->wp.length == 0);
|
|
}
|
|
|
|
//
|
|
// The following is the message that autodial monitors expect to receive
|
|
// when it's a good time to hang up
|
|
//
|
|
#define WM_IEXPLORER_EXITING (WM_USER + 103)
|
|
|
|
long SetQueryNetSessionCount(enum SessionOp Op)
|
|
{
|
|
long lCount;
|
|
|
|
switch(Op) {
|
|
case SESSION_QUERY:
|
|
TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount g_lSessionCount=%d (query)", g_lSessionCount);
|
|
break;
|
|
case SESSION_INCREMENT:
|
|
lCount = g_lSessionCount;
|
|
InterlockedIncrement(&g_lSessionCount);
|
|
TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount g_lSessionCount=%d (incr)", g_lSessionCount);
|
|
if(!lCount) {
|
|
|
|
DetectAndFixAssociations();
|
|
}
|
|
break;
|
|
case SESSION_DECREMENT:
|
|
InterlockedDecrement(&g_lSessionCount);
|
|
TraceMsg(DM_SESSIONCOUNT, "SetQueryNetSessionCount g_lSessionCount=%d (decr)", g_lSessionCount);
|
|
if(!g_lSessionCount) {
|
|
// if we've closed all the net browsers, we need to flush the cache
|
|
InternetSetOption(NULL, INTERNET_OPTION_FLUSH_PASSWORD_CACHE, NULL, 0);
|
|
|
|
// Inform dial monitor that it's a good time to hang up
|
|
HWND hwndMonitorWnd = FindWindow(szAutodialMonitorClass,NULL);
|
|
if (hwndMonitorWnd) {
|
|
PostMessage(hwndMonitorWnd,WM_IEXPLORER_EXITING,0,0);
|
|
}
|
|
hwndMonitorWnd = FindWindow(szWebCheckMonitorClass,NULL);
|
|
if (hwndMonitorWnd) {
|
|
PostMessage(hwndMonitorWnd,WM_IEXPLORER_EXITING,0,0);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return g_lSessionCount;
|
|
}
|
|
|
|
void CShellBrowser::_DecrNetSessionCount()
|
|
{
|
|
TraceMsg(DM_SESSIONCOUNT, "_DecrNetSessionCount");
|
|
|
|
if (_fVisitedNet) {
|
|
SetQueryNetSessionCount(SESSION_DECREMENT);
|
|
_fVisitedNet = FALSE;
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::_IncrNetSessionCount()
|
|
{
|
|
TraceMsg(DM_SESSIONCOUNT, "_IncrNetSessionCount");
|
|
|
|
if (!_fVisitedNet) {
|
|
if (SetQueryNetSessionCount(SESSION_INCREMENT) == 1) {
|
|
// if we're the first instance, we need to run ICW
|
|
if (CheckRunICW()) {
|
|
if (!_pidlCur) {
|
|
// if this was a first navigate,
|
|
// shut it this browser down.
|
|
_pautoWB2->put_Visible(FALSE);
|
|
_pautoWB2->Quit();
|
|
}
|
|
}
|
|
}
|
|
|
|
_fVisitedNet = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// Initialize the Internet Toolbar. Create a dummy class to trap all the Messages that
|
|
// are sent to the old toolbar
|
|
BOOL CShellBrowser::_PrepareInternetToolbar(LPITEMIDLIST pidlInitial)
|
|
{
|
|
HRESULT hresT;
|
|
TCHAR szScratch[32] = {0};
|
|
DWORD dwDefaultBands = VBF_TOOLS | VBF_ADDRESS;
|
|
|
|
if (_nTBTextRows == -1) {
|
|
if (LoadString(HINST_THISDLL, IDS_SHELL_TB_TEXTROWS, szScratch, ARRAYSIZE(szScratch)))
|
|
_nTBTextRows = (UINT)StrToInt(szScratch);
|
|
else
|
|
_nTBTextRows = 0;
|
|
}
|
|
|
|
if (_nTBTextRows == 1)
|
|
dwDefaultBands |= VBF_ONELINETEXT;
|
|
else if (_nTBTextRows == 2)
|
|
dwDefaultBands |= VBF_TWOLINESTEXT;
|
|
|
|
//If this is a URL we definitely want the branding!
|
|
if(!pidlInitial || IsURLChild(pidlInitial, FALSE))
|
|
dwDefaultBands |= VBF_BRAND | VBF_LINKS;
|
|
|
|
if (!_GetITBar())
|
|
{
|
|
HRESULT hresT;
|
|
hresT = SHCoCreateInstance(NULL, &CLSID_InternetToolbar, NULL, IID_IDockingWindow, (LPVOID*) &_aTBar[ITB_ITBAR]);
|
|
|
|
TraceMsg(DM_ITBAR|DM_STARTUP, "CSB::_OnCreate CoCreate(CLS_ITBAR) returned %x", hresT);
|
|
|
|
if (SUCCEEDED(hresT)) {
|
|
_GetITBar()->SetToolbarSite(SAFECAST(this, IShellBrowser*));
|
|
// Look at the type of folder using "pidlInitial" and
|
|
// see if we have a stream for this type.
|
|
// If so, open it and call IPersistStreamInit::Load(pstm);
|
|
// else, call IPersistStreamInit::InitNew(void);
|
|
|
|
IPersistStreamInit *pITbarPSI;
|
|
IOleCommandTarget *pCmdTarget;
|
|
|
|
//Get the pointer to
|
|
if(SUCCEEDED(_GetITBar()->QueryInterface(IID_IPersistStreamInit, (void **)&pITbarPSI)))
|
|
{
|
|
IStream *pstm = NULL;
|
|
|
|
pstm = GetITBarStream(pidlInitial, STGM_READ);
|
|
if (SUCCEEDED(pITbarPSI->QueryInterface(IID_IOleCommandTarget, (void **)&pCmdTarget)))
|
|
{
|
|
if(!pidlInitial || IsURLChild(pidlInitial, FALSE))
|
|
// The initial toolbar needs to be the Web toolbar
|
|
pCmdTarget->Exec(&CGID_PrivCITCommands, CITIDM_INITIALPIDL, 1, NULL, NULL);
|
|
else
|
|
// The initial toolbar needs to be the Shell toolbar
|
|
pCmdTarget->Exec(&CGID_PrivCITCommands, CITIDM_INITIALPIDL, 0, NULL, NULL);
|
|
pCmdTarget->Release();
|
|
}
|
|
|
|
|
|
if(pstm)
|
|
{
|
|
//Stream exists. Let's load it from there.
|
|
pITbarPSI->Load(pstm);
|
|
pstm->Release();
|
|
}
|
|
else
|
|
{
|
|
//No stream already exists. Initialize from the old location!
|
|
pITbarPSI->InitNew();
|
|
}
|
|
|
|
pITbarPSI->Release();
|
|
}
|
|
|
|
} else {
|
|
TraceMsg(DM_ERROR, "ief ER: _OnCreate failed to create Shell Toolbar!!!");
|
|
return FALSE;
|
|
}
|
|
SUPERCLASS::v_ShowHideChildWindows(TRUE);
|
|
|
|
if (!_hwndDummyTB)
|
|
{
|
|
_hwndDummyTB = CreateWorkerWindow(DummyTBWndProc, _hwnd, 0, WS_CHILD, (HMENU)9999, this);
|
|
}
|
|
}
|
|
|
|
if (!_pxtb)
|
|
hresT = QueryService(SID_SExplorerToolbar, IID_IExplorerToolbar, (LPVOID*)&_pxtb);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL DoWindowPlacement(HWND hwnd, WINDOWPLACEMENT * pwndpl)
|
|
{
|
|
BOOL fRetVal = FALSE;
|
|
|
|
if (pwndpl) {
|
|
DWORD dwSize = sizeof(WINDOWPLACEMENT);
|
|
if (_GetRegKeyValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
|
|
TEXT("Window_Placement"), NULL, (PBYTE)pwndpl, &dwSize) == ERROR_SUCCESS)
|
|
fRetVal = TRUE;
|
|
} else {
|
|
WINDOWPLACEMENT wndpl;
|
|
|
|
wndpl.length = sizeof(WINDOWPLACEMENT);
|
|
if (GetWindowPlacement(hwnd, &wndpl)) {
|
|
// Don't store us as minimized - that isn't what the user intended.
|
|
// I.E. right click on minimized IE 3.0 in tray, pick close. Since
|
|
// we are minmized in that scenario we want to force normal
|
|
// instead so we at least show up.
|
|
if (wndpl.showCmd == SW_SHOWMINIMIZED ||
|
|
wndpl.showCmd == SW_MINIMIZE)
|
|
wndpl.showCmd = SW_SHOWNORMAL;
|
|
|
|
fRetVal = (_SetRegKeyValue(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Internet Explorer\\Main"),
|
|
TEXT("Window_Placement"), REG_BINARY, (const BYTE *)&wndpl, sizeof(WINDOWPLACEMENT)) == ERROR_SUCCESS);
|
|
}
|
|
}
|
|
|
|
return fRetVal;
|
|
}
|
|
|
|
void CalcWindowPlacementForURLBrowser(HWND hwnd, IETHREADPARAM * piei, WINDOWPLACEMENT * pwndpl)
|
|
{
|
|
if (DoWindowPlacement(NULL, pwndpl)) {
|
|
HWND hwndT = NULL;
|
|
RECT rc;
|
|
|
|
// If the show command specifies a normal show (i.e., our initial
|
|
// display setting is not being overridden by the command line or
|
|
// CreateProcess setting) then use the saved window state show command.
|
|
// Otherwise, use the show command passed in to us.
|
|
if (piei->nCmdShow == SW_SHOWNORMAL)
|
|
piei->nCmdShow = pwndpl->showCmd;
|
|
|
|
// Cascade if there is an IE window directly under us.
|
|
while (hwndT = FindWindowEx(NULL, hwndT, c_szIExploreClass, NULL)) {
|
|
if ((GetWindowRect(hwndT, &rc)) &&
|
|
(pwndpl->rcNormalPosition.left == rc.left) &&
|
|
(pwndpl->rcNormalPosition.top == rc.top)) {
|
|
// We invalidate the window placement structure in this case
|
|
// which will cause OnCreate to honor the initial create size
|
|
// for the window which specifies CW_USEDEFAULT.
|
|
pwndpl->length = 0;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
pwndpl->length = 0;
|
|
}
|
|
}
|
|
|
|
LRESULT CShellBrowser::_OnCreate(LPCREATESTRUCT pcs)
|
|
{
|
|
HRESULT hres;
|
|
IETHREADPARAM* piei = (IETHREADPARAM*)pcs->lpCreateParams;
|
|
BOOL fUseHomePage = !(BOOL)piei->hevent;
|
|
HDPA hdpa = NULL;
|
|
|
|
//
|
|
// Make this thread foreground here so that any UI from
|
|
// USERCLASS::_OnCreate will be on the top of other windows.
|
|
// We used to call this in _AfterWindowCreate, but it is
|
|
// too late for dialog boxes we popup while processing WM_CREATE
|
|
// message.
|
|
//
|
|
// Note that we do call SetForegroundWindow even if this window
|
|
// is not created as a result of CoCreateInstance. The automation
|
|
// client is supposed to make it visible and bring it to the
|
|
// foreground if it needs to.
|
|
//
|
|
if (!piei->hevent) {
|
|
SetForegroundWindow(_hwnd);
|
|
}
|
|
|
|
SUPERCLASS::_OnCreate(pcs);
|
|
|
|
EnsureWebViewRegSettings();
|
|
if (!_PrepareInternetToolbar(piei->pidl))
|
|
return E_FAIL;
|
|
|
|
v_InitMembers();
|
|
|
|
#ifdef DEBUG // {
|
|
#if 0
|
|
if (g_dwPrototype & 0x00000004) {
|
|
HRESULT hresT;
|
|
IDockingWindow* ptbar;
|
|
hresT = SHCoCreateInstance(NULL, &CLSID_DeskBarApp, NULL, IID_IDockingWindow, (LPVOID*)&ptbar);
|
|
if (SUCCEEDED(hresT)) {
|
|
AddToolbar(ptbar, NULL, NULL);
|
|
ptbar->Release();
|
|
} else {
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
#else
|
|
// new code down below, after pidl known
|
|
#endif
|
|
#endif // }
|
|
|
|
ASSERT(piei);
|
|
|
|
|
|
TCHAR szVeryFirstPage[MAX_URL_STRING]; // must be with pszCmdLine
|
|
|
|
LPCTSTR pszCmdLine = piei->pszCmdLine;
|
|
hdpa = piei->hdpa;
|
|
|
|
if (piei->fCheckFirstOpen) {
|
|
|
|
if (IsRooted() || g_pidlRootClass) {
|
|
// if we're rooted, don't use the std location, use home
|
|
piei->pidl = ILClone(&s_idlNULL);
|
|
} else {
|
|
//
|
|
// We don't want to go to the very first page, if this window
|
|
// is created as the result of CoCreateInstnace.
|
|
//
|
|
if (!piei->hevent) {
|
|
HRESULT hresT = _GetStdLocation(szVeryFirstPage, ARRAYSIZE(szVeryFirstPage), IDM_GOFIRSTHOME);
|
|
TraceMsg(DM_NAV, "CSB::_OnCreate _GetStdLocation(IDM_GOFIRSTHOME) returned %x", hresT);
|
|
if (SUCCEEDED(hresT)) {
|
|
pszCmdLine = szVeryFirstPage;
|
|
TraceMsg(DM_NAV, "CSB::_OnCreate _GetStdLocation(IDM_GOFIRSTHOME) returned %s", pszCmdLine);
|
|
}
|
|
}
|
|
}
|
|
piei->fCheckFirstOpen = FALSE;
|
|
}
|
|
|
|
// NOTE: These flags and corresponding ones in IETHREADPARAM are set to FALSE at creation,
|
|
// ParseCommandLine() is the only place where they are set. -- dli
|
|
_fNoLocalFileWarning = piei->fNoLocalFileWarning;
|
|
_fFullScreen = piei->fFullScreen;
|
|
_fNoDragDrop = piei->fNoDragDrop;
|
|
_fAutomation = piei->fAutomation;
|
|
|
|
// If someone deliberately tell us not to use home page.
|
|
if (piei->fDontUseHomePage)
|
|
fUseHomePage = 0;
|
|
|
|
if (!hdpa && ((pszCmdLine && pszCmdLine[0]) || piei->pidl) && !_fAutomation)
|
|
{
|
|
hdpa = DPA_Create(4);
|
|
if (hdpa) {
|
|
LPITEMIDLIST pidlCmdLine = NULL;
|
|
HRESULT hresT = S_OK;
|
|
if (piei->pidl) {
|
|
pidlCmdLine = ILClone(piei->pidl);
|
|
if (!pidlCmdLine) {
|
|
hresT = E_OUTOFMEMORY;
|
|
}
|
|
} else {
|
|
hresT = _ConvertPathToPidl(pszCmdLine, &pidlCmdLine);
|
|
TraceMsg(DM_STARTUP, "_OnCreate ConvertPathToPidl(pszCmdLine) returns %x", hresT);
|
|
}
|
|
|
|
if (hresT == S_OK) {
|
|
DPA_InsertPtr(hdpa, 9999, pidlCmdLine);
|
|
} else {
|
|
DPA_Destroy(hdpa);
|
|
hdpa = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
if (hdpa) {
|
|
int cidl = DPA_GetPtrCount(hdpa);
|
|
|
|
TraceMsg(0, "ief TR: _OnCreate DPA_GetPtrCount got %d", cidl);
|
|
|
|
if (cidl>=1) {
|
|
for (int i=0; i<cidl-1; i++) {
|
|
pidl = (LPITEMIDLIST)DPA_GetPtr(hdpa, i);
|
|
TraceMsg(DM_STARTUP, "ief TR: calling TLonNavigate with %x", pidl);
|
|
if (pidl) { // paranoia
|
|
_OnNavigateComplete(pidl, 0);
|
|
}
|
|
}
|
|
pidl = ILClone((LPITEMIDLIST)DPA_GetPtr(hdpa, cidl-1));
|
|
}
|
|
|
|
TraceMsg(DM_STARTUP, "ief OnCreate calling _DeletePidlDPA");
|
|
_DeletePidlDPA(hdpa);
|
|
|
|
fUseHomePage = FALSE;
|
|
|
|
} else if (ISROOTEDCLASS()) {
|
|
// If rooted class browser such as MSN browse to their desktop...
|
|
pidl = ILClone(&s_idlNULL);
|
|
|
|
} else if (fUseHomePage) {
|
|
// if we're not top level, assume we're going to be told
|
|
// where to browse
|
|
TCHAR szPath[MAX_URL_STRING];
|
|
|
|
hres = _GetStdLocation(szPath, SIZEOF(szPath), IDM_GOHOME);
|
|
if (SUCCEEDED(hres)) {
|
|
IECreateFromPath(NULL, szPath, &pidl);
|
|
|
|
// if this is not within our namespace, just go to the root
|
|
if (!_ValidTargetPidl(pidl)) {
|
|
ILFree(pidl);
|
|
pidl = ILClone(g_pidlRoot);
|
|
}
|
|
}
|
|
}
|
|
|
|
// do this here after we've found what pidl we're looking at
|
|
_LoadBrowserWindowSettings(piei, pidl);
|
|
|
|
#ifdef DEBUG // {
|
|
if (g_dwPrototype & 0x00000004) {
|
|
IStream* pstm;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
if (_SaveToolbars(NULL) == S_OK) {
|
|
// _LoadBrowserWindowSettings did a v_GetViewStream/ _LoadToolbars
|
|
// if it succeeded (i.e. if we have > 0 toolbars), we're done
|
|
// BUGBUG actually, even 0 toolbars could mean success, oh well...
|
|
hres = S_OK;
|
|
}
|
|
|
|
// if the stream doesn't exist OR
|
|
// the LoadToolbars failed due to version change
|
|
if (FAILED(hres)) {
|
|
// BUGBUG proto: use Desktop (not Browser) stream for now (!)
|
|
extern IStream *GetDesktopViewStream(DWORD grfMode, LPCTSTR pszName);
|
|
pstm = GetDesktopViewStream(STGM_READ, TEXT("Toolbars"));
|
|
if (pstm) {
|
|
hres = _LoadToolbars(pstm);
|
|
pstm->Release();
|
|
}
|
|
}
|
|
|
|
if (FAILED(hres)) {
|
|
// uh-oh...
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
#endif // }
|
|
|
|
if (pidl) { // paranoia
|
|
|
|
hres = _NavigateToPidl(pidl, 0, 0);
|
|
if (FAILED(hres)) {
|
|
|
|
if (IsURLChild(pidl, TRUE)) {
|
|
// if we failed, but this was a URL child, we should still activate and go to blank.htm
|
|
hres = S_FALSE;
|
|
}
|
|
TraceMsg(DM_ERROR, "_OnCreate _NavigateToPidl failed %x", hres);
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
|
|
if ((_pidlPending && IsURLChild(_pidlPending, TRUE)) || fUseHomePage) {
|
|
_fInternetStart = TRUE;
|
|
_IncrNetSessionCount();
|
|
CalcWindowPlacementForURLBrowser(_hwnd, piei, &piei->wp);
|
|
}
|
|
|
|
|
|
if (piei->wp.length == SIZEOF(piei->wp)) {
|
|
// we do a SetWindowPlacement first with SW_HIDE
|
|
// to get the size right firsth
|
|
// then we really show it.
|
|
if (piei->nCmdShow == SW_SHOWNORMAL)
|
|
piei->nCmdShow = piei->wp.showCmd;
|
|
piei->wp.showCmd = SW_HIDE;
|
|
|
|
SetWindowPlacement(_hwnd, &piei->wp);
|
|
}
|
|
|
|
v_ShowHideChildWindows(TRUE);
|
|
|
|
//
|
|
// If this is a browser-only release, we Initialize/Register the class
|
|
// object when the first browser window is created.
|
|
//
|
|
if (WhichPlatform() == PLATFORM_IE3 && g_tidParking == GetCurrentThreadId()) {
|
|
// If automation, now is good time to register ourself...
|
|
IEInitializeClassFactoryObject((_fAutomation) ?
|
|
_pautoWB2 : NULL); // IWebBrowser2 inherits from IDispatch
|
|
} else if (piei->hevent) {
|
|
TraceMsg(TF_COCREATE, "CSB::_OnCreate found hevent. Signaling back (tid=%x)",
|
|
GetCurrentThreadId());
|
|
|
|
//
|
|
// By turning on this MAX_DEBUG flag, we can prove that our thread
|
|
// syncrhonization for CoCreateInstance does not cause a dead lock.
|
|
//
|
|
// #define MAX_DEBUG
|
|
#ifdef MAX_DEBUG
|
|
SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0);
|
|
Sleep(5);
|
|
SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0, 0);
|
|
#endif
|
|
//
|
|
// WARNING: Note that we must SetEvent even though we can't return
|
|
// the marshalled automation object for some reason. Not signaling
|
|
// the event will block the caller thread for a long time.
|
|
//
|
|
ASSERT(piei->pstm);
|
|
if (SUCCEEDED(hres)) {
|
|
piei->hres = CoMarshalInterface(piei->pstm, IID_IUnknown, _pautoWB2,
|
|
MSHCTX_INPROC, 0, MSHLFLAGS_NORMAL);
|
|
} else {
|
|
piei->hres = hres;
|
|
}
|
|
SetEvent(piei->hevent);
|
|
}
|
|
|
|
//
|
|
// Delay register our window now.
|
|
// Note that we need to do it after SetEvent(piei->hevent) to avoid
|
|
// soft dead-lock in OLE.
|
|
//
|
|
_psw = WinList_GetShellWindows(FALSE);
|
|
if (_psw) {
|
|
_psw->Register(NULL, (long)_hwnd, (piei->uFlags & COF_EXPLORE) ? SWC_EXPLORER : SWC_BROWSER, &_dwRegisterWinList);
|
|
}
|
|
|
|
if (g_tidParking == GetCurrentThreadId()) {
|
|
//
|
|
// Tell IEDDE that automation services are now available.
|
|
//
|
|
IEDDE_AutomationStarted();
|
|
}
|
|
|
|
if (g_hwndProxyDesktop)
|
|
PostMessage(g_hwndProxyDesktop, DTM_ADDREFPROXYDESKTOP, 0, 0);
|
|
|
|
TraceMsg(DM_STARTUP, "ief OnCreate returning %d (SUCCEEDED(%x))", SUCCEEDED(hres), hres);
|
|
if (FAILED(hres))
|
|
{
|
|
SetMenu(_hwnd, NULL);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void _CheckSearch(BOOL fCheck, IExplorerToolbar* _pxtb)
|
|
{
|
|
UINT uiState;
|
|
|
|
if (_pxtb)
|
|
{
|
|
if (SUCCEEDED(_pxtb->GetState(&CLSID_NULL, TBIDM_SEARCH, &uiState)))
|
|
{
|
|
if (fCheck)
|
|
uiState |= TBSTATE_CHECKED;
|
|
else
|
|
uiState &= ~TBSTATE_CHECKED;
|
|
_pxtb->SetState(&CLSID_NULL, TBIDM_SEARCH, uiState);
|
|
}
|
|
}
|
|
}
|
|
|
|
extern HRESULT DeskBar_Create(IUnknown** ppunk, IUnknown** ppbs);
|
|
|
|
//*** _ToggleSearchBar -- create/show/hide "search" BrowserBar
|
|
HRESULT CShellBrowser::_ToggleSearchBar()
|
|
{
|
|
HRESULT hres;
|
|
IDockingWindow *ptbSearch = NULL;
|
|
IBandSite *pbs;
|
|
IUnknown *punkBar;
|
|
IUnknown *punkBandSite;
|
|
#define DBSEARCH_TBNAME L"DBSearch"
|
|
#define SEARCH_WIDTH 240
|
|
|
|
hres = FindToolbar(DBSEARCH_TBNAME, IID_IDockingWindow, (LPVOID*)&ptbSearch);
|
|
TraceMsg(DM_TRACE, "CSB::_ToggleSearchBar FindToolbar returned %x", hres);
|
|
|
|
if (hres==S_OK) {
|
|
// already have one, toggle show/hide state
|
|
_fShowSearchBar = !_fShowSearchBar;
|
|
ShowToolbar(ptbSearch, _fShowSearchBar);
|
|
ptbSearch->Release();
|
|
_CheckSearch(_fShowSearchBar, _pxtb);
|
|
} else {
|
|
// 1st time, create a new one
|
|
|
|
HRESULT hres = DeskBar_Create(&punkBar, &punkBandSite);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
hres = punkBar->QueryInterface(IID_IDockingWindow, (LPVOID *) &ptbSearch);
|
|
ASSERT(SUCCEEDED(hres));
|
|
punkBar->Release();
|
|
}
|
|
if (SUCCEEDED(hres)) {
|
|
|
|
CDeskBarPropertyBag* ppb;
|
|
|
|
// BUGBUG - this needs to be persisted and restored
|
|
// when % widths are implemented, should use that
|
|
|
|
ppb = new CDeskBarPropertyBag();
|
|
if (ppb) {
|
|
HKEY hkey;
|
|
UINT uiSearchWidth;
|
|
UINT uiValue;
|
|
DWORD cbSize;
|
|
|
|
// If the reg entry doesn't exist, we default SEARCH_WIDTH
|
|
uiSearchWidth = SEARCH_WIDTH;
|
|
|
|
// Get IE 4.0 style search initial width
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_MAIN, &hkey)==ERROR_SUCCESS) {
|
|
cbSize = sizeof(uiValue);
|
|
if ( RegQueryValueEx(hkey, "IE40 Search Size", 0, NULL, (LPBYTE)&uiValue, &cbSize) == ERROR_SUCCESS &&
|
|
cbSize == sizeof(uiValue))
|
|
uiSearchWidth = uiValue;
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
|
|
ppb->SetDataDWORD(PROPDATA_MODE, WBM_BBOTTOMMOST);
|
|
ppb->SetDataDWORD(PROPDATA_SIDE, ABE_LEFT); // LEFT
|
|
ppb->SetDataDWORD(PROPDATA_LEFT, uiSearchWidth);
|
|
ppb->SetDataDWORD(PROPDATA_RIGHT, uiSearchWidth);
|
|
|
|
LoadFromPropertyBag(ptbSearch, ppb);
|
|
ppb->Release();
|
|
}
|
|
|
|
|
|
punkBandSite->QueryInterface(IID_IBandSite, (LPVOID*)&pbs);
|
|
|
|
if (pbs) {
|
|
IShellToolband *pSearchBand;
|
|
|
|
pSearchBand = CSearchBand_Create();
|
|
|
|
if (pSearchBand) {
|
|
|
|
hres = AddToolbar(ptbSearch, DBSEARCH_TBNAME, NULL);
|
|
if (SUCCEEDED(hres)) {
|
|
hres = pbs->AddBand(pSearchBand);
|
|
ASSERT(SUCCEEDED(hres));
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
_CheckSearch(TRUE, _pxtb);
|
|
_fShowSearchBar = TRUE;
|
|
}
|
|
}
|
|
pSearchBand->Release();
|
|
}
|
|
pbs->Release();
|
|
}
|
|
punkBandSite->Release();
|
|
ptbSearch->Release();
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
// BUGBUG jcordell: begin temp code for beta 1
|
|
//*** _RemoveSearchBar -- remove "search" BrowserBar
|
|
HRESULT CShellBrowser::_RemoveSearchBar()
|
|
{
|
|
HRESULT hres;
|
|
IDockingWindow *ptbSearch = NULL;
|
|
|
|
hres = FindToolbar(DBSEARCH_TBNAME, IID_IDockingWindow, (LPVOID*)&ptbSearch);
|
|
TraceMsg(DM_TRACE, "CSB::_ToggleSearchBar FindToolbar returned %x", hres);
|
|
|
|
if (hres==S_OK) {
|
|
hres = RemoveToolbar( (IUnknown*) ptbSearch, (DWORD) 0);
|
|
_fShowSearchBar = FALSE;
|
|
ptbSearch->Release();
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
// BUGBUG jcordell: end temp code for beta 1
|
|
|
|
void CShellBrowser::_OrganizeFavorites()
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
|
|
if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_FAVORITES, TRUE))
|
|
{
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
{
|
|
SHELLEXECUTEINFO shei = { 0 };
|
|
|
|
shei.cbSize = sizeof(shei);
|
|
shei.fMask = SEE_MASK_INVOKEIDLIST;
|
|
shei.nShow = SW_SHOWNORMAL;
|
|
shei.lpIDList = ILCreateFromPath(szPath);
|
|
ShellExecuteEx(&shei);
|
|
|
|
ILFree((LPITEMIDLIST)shei.lpIDList);
|
|
}
|
|
else
|
|
DoOrganizeFavDlg(_hwnd, szPath);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CShellBrowser::_AddToFavorites(LPCITEMIDLIST pidl, LPCTSTR pszTitle, BOOL fDisplayUI)
|
|
{
|
|
if (AddToFavorites(_hwnd, pidl ? pidl : _pidlCur, pszTitle, fDisplayUI) == S_OK)
|
|
_OnFavsChanged(0, 0);
|
|
}
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Handle WM_COMMAND for favorites menu
|
|
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
void CShellBrowser::_FavoriteOnCommand(HMENU hmenu, UINT idCmd)
|
|
{
|
|
// Should the file menu code handle this command?
|
|
if (FileMenu_ProcessCommand(_hwnd, _hmenuTemplate, FCIDM_MENU_FAVORITES, hmenu, idCmd))
|
|
{
|
|
// Yes; make our cloned menu (on the menu bar) get updated
|
|
_fFavMenuChanged = TRUE;
|
|
return ;
|
|
}
|
|
|
|
switch (idCmd)
|
|
{
|
|
case FCIDM_ORGANIZEFAVORITES:
|
|
_OrganizeFavorites();
|
|
break;
|
|
|
|
case FCIDM_ADDTOFAVORITES:
|
|
_AddToFavorites(NULL, NULL, TRUE);
|
|
break;
|
|
|
|
case FCIDM_UPDATESUBSCRIPTIONS:
|
|
UpdateSubscriptions();
|
|
break;
|
|
|
|
case FCIDM_FAVS_MORE:
|
|
{
|
|
SHELLEXECUTEINFO shei = { 0 };
|
|
|
|
// Get the folder associated with this command. (This
|
|
// command may appear on cascaded menus, as well as the
|
|
// top-level favorites menu.)
|
|
|
|
FileMenu_GetLastSelectedItemPidls(hmenu, NULL, (LPITEMIDLIST *)&shei.lpIDList);
|
|
if (shei.lpIDList)
|
|
{
|
|
shei.cbSize = SIZEOF(shei);
|
|
shei.fMask = SEE_MASK_INVOKEIDLIST;
|
|
shei.nShow = SW_SHOWNORMAL;
|
|
ShellExecuteEx(&shei);
|
|
|
|
ILFree((LPITEMIDLIST)shei.lpIDList);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0:
|
|
// nothin' doin'
|
|
// BUGBUG (scotth): what the heck is this for??
|
|
break;
|
|
|
|
default: {
|
|
LPITEMIDLIST pidlFolder, pidlItem;
|
|
if (FileMenu_GetLastSelectedItemPidls(hmenu, &pidlFolder, &pidlItem))
|
|
{ // This function call will fail if the user selected "(Empty)"
|
|
LPITEMIDLIST pidlGoto = ILCombine(pidlFolder, pidlItem);
|
|
if (pidlGoto)
|
|
{
|
|
TCHAR szPath[MAX_PATH]; // BUGBUG: Review SHGetpathFromIDList
|
|
|
|
SHGetPathFromIDList(pidlGoto, szPath);
|
|
ILFree(pidlGoto);
|
|
|
|
pidlGoto = _GetLinkTarget(szPath);
|
|
if (pidlGoto)
|
|
{
|
|
_NavigateToPidl(pidlGoto, 0, 0);
|
|
|
|
ILFree(pidlGoto);
|
|
}
|
|
else
|
|
{
|
|
ShellMessageBox(HINST_THISDLL, _hwnd,
|
|
MAKEINTRESOURCE(IDS_ERROR_GOTO),
|
|
MAKEINTRESOURCE(IDS_TITLE),
|
|
MB_OK | MB_SETFOREGROUND | MB_ICONSTOP,
|
|
szPath);
|
|
// _ExecItemByPidls(_hwnd, pidlFolder, pidlItem);
|
|
}
|
|
|
|
}
|
|
ILFree(pidlFolder);
|
|
ILFree(pidlItem);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// BUGBUG: Bad-hack
|
|
#define HLNF_NAVIGATINGFORWARDEND (HLNF_NAVIGATINGFORWARD | 0x1000)
|
|
|
|
PTLOGLINK _TLGetLink(PTRAVELLOG ptl, DWORD grfHLNF);
|
|
#if 0
|
|
void CShellBrowser::_RecentOnCommand(UINT id)
|
|
{
|
|
|
|
PTRAVELLOG ptl = &_tl;
|
|
PTRAVELLOG ptlGlobal = &_tlGlobal;
|
|
|
|
//
|
|
// Note that id specifies the relative location from the current page.
|
|
//
|
|
int i = ( id - (FCIDM_RECENTFIRST+CRECENTMENU_MAX) );
|
|
PTLOGLINK ptll = _TLGetLink(ptl, 0); // get current
|
|
PTLOGLINK ptllGlobal = _TLGetLink(ptlGlobal, 0);
|
|
|
|
while (i < 0 && ptll) {
|
|
ptll = ptll->GetPrevLink();
|
|
ptllGlobal = ptllGlobal->GetPrevLinkHLFrame(_phlf);
|
|
ASSERT((ptll && ptllGlobal) ||
|
|
(!ptll && !ptllGlobal))
|
|
i++;
|
|
}
|
|
while (i > 0 && ptll) {
|
|
ptll = ptll->GetNextLink();
|
|
ptllGlobal = ptllGlobal->GetNextLinkHLFrame(_phlf);
|
|
ASSERT((ptll && ptllGlobal) ||
|
|
(!ptll && !ptllGlobal))
|
|
i--;
|
|
}
|
|
|
|
ASSERT(ptll && !i);
|
|
if (ptll) {
|
|
|
|
// HACKHACK: for right now, we don't implement recent command back
|
|
// to an external top level app.
|
|
if (ptll->FExternal())
|
|
return;
|
|
|
|
if (ptll != ptl->ptllCurrent) {
|
|
if (SUCCEEDED(_NavigateToPidl(ptll->GetPidlPtr(), (DWORD)-1, 0))) {
|
|
ptl->ptllCurrent = ptll;
|
|
ptlGlobal->ptllCurrent = ptllGlobal;
|
|
_UpdateBackForwardState();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
extern BOOL CALLBACK ViewOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
extern BOOL CALLBACK FolderOptionsDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
void CShellBrowser::_AddViewOptionsPage(PROPSHEETHEADER *ppsh)
|
|
{
|
|
PROPSHEETPAGE psp;
|
|
|
|
psp.dwSize = SIZEOF(psp);
|
|
psp.dwFlags = PSP_DEFAULT;
|
|
psp.hInstance = HINST_THISDLL;
|
|
|
|
//
|
|
// Add View options dialog
|
|
//
|
|
psp.pszTemplate = MAKEINTRESOURCE(DLG_VIEWOPTIONS);
|
|
psp.pfnDlgProc = (DLGPROC)ViewOptionsDlgProc;
|
|
psp.lParam = (LPARAM)this;
|
|
|
|
_AddPropSheetPage(CreatePropertySheetPage(&psp), (LPARAM)ppsh);
|
|
}
|
|
|
|
void CShellBrowser::_AddFolderOptionsPage(PROPSHEETHEADER *ppsh)
|
|
{
|
|
PROPSHEETPAGE psp;
|
|
|
|
psp.dwSize = SIZEOF(psp);
|
|
psp.dwFlags = PSP_DEFAULT;
|
|
psp.hInstance = HINST_THISDLL;
|
|
|
|
//
|
|
// Add Folder option dialog if we don't have the tree
|
|
// AND this is not a rooted explorer.
|
|
//
|
|
if (!IsRooted()) {
|
|
psp.pszTemplate = MAKEINTRESOURCE(DLG_FOLDEROPTIONS);
|
|
psp.pfnDlgProc = (DLGPROC)FolderOptionsDlgProc;
|
|
psp.lParam = (LPARAM)this;
|
|
|
|
_AddPropSheetPage(CreatePropertySheetPage(&psp), (LPARAM)ppsh);
|
|
}
|
|
}
|
|
|
|
|
|
void CShellBrowser::v_AddBrowserPropertySheetPages(PROPSHEETHEADER* ppsh)
|
|
{
|
|
_AddFolderOptionsPage(ppsh);
|
|
_AddViewOptionsPage(ppsh);
|
|
}
|
|
|
|
void CShellBrowser::_DoOptions(VARIANT* pvar)
|
|
{
|
|
DWORD dwFlags = SBO_DEFAULT;
|
|
|
|
if (!_psv)
|
|
return;
|
|
|
|
if (pvar && pvar->vt == VT_I4)
|
|
dwFlags = pvar->lVal;
|
|
|
|
|
|
PROPSHEETHEADER psh;
|
|
HPROPSHEETPAGE rPages[MAX_PAGES];
|
|
|
|
psh.dwSize = SIZEOF(psh);
|
|
psh.dwFlags = PSH_DEFAULT;
|
|
psh.hInstance = HINST_THISDLL;
|
|
psh.hwndParent = _hwnd;
|
|
psh.pszCaption = MAKEINTRESOURCE(IDS_OPTIONS);
|
|
psh.nPages = 0;
|
|
psh.nStartPage = 0;
|
|
psh.phpage = rPages;
|
|
|
|
if (dwFlags != SBO_NOBROWSERPAGES)
|
|
v_AddBrowserPropertySheetPages(&psh);
|
|
|
|
// now let the view add pages
|
|
_psv->AddPropertySheetPages(0, _AddPropSheetPage, (LPARAM)(LPPROPSHEETHEADER)&psh);
|
|
|
|
_psv->EnableModelessSV(FALSE);
|
|
PropertySheet(&psh);
|
|
_psv->EnableModelessSV(TRUE);
|
|
}
|
|
|
|
void CShellBrowser::_OpenHistory()
|
|
{
|
|
TCHAR szHistPath[MAX_PATH];
|
|
DWORD dwSize = SIZEOF(szHistPath);
|
|
|
|
if (_GetRegKeyValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_URLHISTORY ,
|
|
REGSTR_VAL_DIRECTORY, NULL, (LPBYTE)szHistPath, &dwSize) != ERROR_SUCCESS)
|
|
{
|
|
TCHAR szWindows[MAX_PATH];
|
|
|
|
GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
|
|
PathCombine(szHistPath, szWindows, TEXT("history"));
|
|
}
|
|
|
|
// BUGBUG: need to fix this for nashville
|
|
|
|
SHELLEXECUTEINFO shei = { 0 };
|
|
|
|
shei.cbSize = sizeof(shei);
|
|
shei.fMask = SEE_MASK_INVOKEIDLIST;
|
|
shei.nShow = SW_SHOWNORMAL;
|
|
shei.lpIDList = ILCreateFromPath(szHistPath);
|
|
ShellExecuteEx(&shei);
|
|
|
|
ILFree((LPITEMIDLIST)shei.lpIDList);
|
|
|
|
#if 0
|
|
// or we could do it this way
|
|
LPITEMIDLIST pidlHistoryFolder = ILCreateFromPath(szHistPath);
|
|
BrowseObject(pidlHistoryFolder, SBSP_NEWBROWSER|SBSP_ABSOLUTE);
|
|
ILFree(pidlHistoryFolder);
|
|
|
|
#endif
|
|
}
|
|
|
|
// BUGBUG: [rayen] Depending on what we end up doing with the subscription
|
|
// folder, we may want to combine this with _OpenHistory() above.
|
|
void CShellBrowser::_OpenSubscription()
|
|
{
|
|
TCHAR szHistPath[MAX_PATH];
|
|
DWORD dwSize = SIZEOF(szHistPath);
|
|
|
|
if (_GetRegKeyValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION,
|
|
REGSTR_VAL_DIRECTORY, NULL, (LPBYTE)szHistPath, &dwSize) != ERROR_SUCCESS)
|
|
{
|
|
TCHAR szWindows[MAX_PATH];
|
|
|
|
GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
|
|
PathCombine(szHistPath, szWindows, TEXT("Subscriptions"));
|
|
}
|
|
|
|
// BUGBUG: need to fix this for nashville
|
|
|
|
SHELLEXECUTEINFO shei = { 0 };
|
|
|
|
shei.cbSize = sizeof(shei);
|
|
shei.fMask = SEE_MASK_INVOKEIDLIST;
|
|
shei.nShow = SW_SHOWNORMAL;
|
|
shei.lpIDList = ILCreateFromPath(szHistPath);
|
|
ShellExecuteEx(&shei);
|
|
|
|
ILFree((LPITEMIDLIST)shei.lpIDList);
|
|
|
|
#if 0
|
|
// or we could do it this way
|
|
LPITEMIDLIST pidlHistoryFolder = ILCreateFromPath(szHistPath);
|
|
BrowseObject(pidlHistoryFolder, SBSP_NEWBROWSER|SBSP_ABSOLUTE);
|
|
ILFree(pidlHistoryFolder);
|
|
|
|
#endif
|
|
}
|
|
|
|
//*** csb::_CycleFocus
|
|
// ENTRY/EXIT
|
|
// return S_OK if cycling w/in ourself; o.w. S_FALSE
|
|
HRESULT CShellBrowser::_CycleFocus(LPMSG lpMsg)
|
|
{
|
|
UINT itbNext = 0; // assumes we give it to the first toolbar
|
|
UINT citb = 1;
|
|
|
|
if (GetAsyncKeyState(VK_SHIFT) < 0) {
|
|
itbNext = ITB_MAX-1; // start from the last
|
|
citb = (UINT)-1; // go backward
|
|
}
|
|
|
|
//
|
|
// Check if the last focused toolbar still has the focus or not.
|
|
//
|
|
if (_HasToolbarFocus()) {
|
|
//
|
|
// Yes, then give it to the next one.
|
|
//
|
|
itbNext = _itbLastFocus + citb;
|
|
}
|
|
else {
|
|
// our caller (v_MayTA) did _FixToolbarFocus
|
|
ASSERT(_itbLastFocus == ITB_VIEW);
|
|
}
|
|
|
|
//
|
|
// Find the next visible toolbar and set the focus to it. Otherwise,
|
|
// set the focus to the view window.
|
|
//
|
|
HWND hwndFocusNext = _hwndView; // assume the view will get it.
|
|
for (UINT i=itbNext; i<ITB_MAX; i+=citb ) {
|
|
if (_aTBar[i].ptbar && _aTBar[i].fShow) {
|
|
_aTBar[i].ptbar->GetWindow(&hwndFocusNext);
|
|
ASSERT(hwndFocusNext);
|
|
//ASSERT(IsWindowVisible(hwndFocusNext));
|
|
if (!IsWindowVisible(hwndFocusNext)) {
|
|
DebugMsg(DM_ERROR, TEXT("csb._cf: !IsWindowVisible"));
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!IsWindowVisible(hwndFocusNext))
|
|
hwndFocusNext = _hwndView;
|
|
|
|
TraceMsg(DM_ITBAR, "CSB::_OnCommand giving the focus to hwnd=%x", hwndFocusNext);
|
|
|
|
SetFocus(hwndFocusNext); // ie3 compatibility
|
|
|
|
// make sure we tell our parent
|
|
if (hwndFocusNext == _hwndView) {
|
|
if (_itbLastFocus != ITB_VIEW)
|
|
_FixToolbarFocus(); // steal the focus
|
|
return S_FALSE;
|
|
}
|
|
else {
|
|
UnkUIActivateIO(_aTBar[i].ptbar, TRUE, lpMsg);
|
|
// the UIActIO will cause an OnUIActIS which will do _OnFocusChange
|
|
return S_OK;
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
#if 0 // { work-in-progress, 970130
|
|
|
|
HRESULT CShellBrowser::_CycleFocus(LPMSG lpMsg)
|
|
{
|
|
BOOL fToolbarHasFocus;
|
|
UINT itbNext = 0;
|
|
UINT citb = 1;
|
|
|
|
if (GetAsyncKeyState(VK_SHIFT) < 0) {
|
|
itbNext = ITB_MAX - 1; // start from the last
|
|
citb = (UINT)-1; // go backward
|
|
}
|
|
|
|
if (lpMsg == NULL) {
|
|
ASSERT(0); // BUGBUG todo: NYI
|
|
return S_FALSE;
|
|
}
|
|
|
|
fToolbarHasFocus = _HasToolbarFocus();
|
|
if (fToolbarHasFocus) {
|
|
ASSERT(_itbLastFocus != ITB_VIEW);
|
|
itbNext = _itbLastFocus + citb;
|
|
}
|
|
// (o.w. we need to call _FixToolbarFocus; but our caller v_MayTA did..)
|
|
ASSERT(fToolbarHasFocus == (_itbLastFocus != ITB_VIEW));
|
|
|
|
// go thru the 'path':
|
|
// tb,+ tb,-
|
|
// xxxxx <----------------------------------> xxxxx
|
|
// tb(i)..tb(i+1)..tb(N)..view..tb(0)..tb(i-1)..tb(i)..tb(N)..view
|
|
// xxxx <--------------------------> xxxx
|
|
// v+ v-
|
|
// start in the path at 1 past wherever the focus last was;
|
|
// (if we've lost it from where it last was, start at view);
|
|
// and go fwd/bkwd as appropriate.
|
|
// n.b. we don't ever re-try where focus last was.
|
|
|
|
// 1st, do remaining toolbar guys (all of them if we're in the view)
|
|
if (_IterToolbarTA(itbNext, ITB_MAX - 1, citb, lpMsg) == S_OK) {
|
|
return S_OK;
|
|
}
|
|
|
|
// 2nd, try view (unless that's where we started)
|
|
if (fToolbarHasFocus) {
|
|
SetFocus(_hwndView);
|
|
if (_itbLastFocus != ITB_VIEW)
|
|
_FixToolbarFocus(); // steal the focus
|
|
}
|
|
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT CShellBrowser::_IterToolbarTA(UINT iFirst, UINT iLast, UINT dIncr, LPMSG lpMsg)
|
|
{
|
|
UINT i;
|
|
|
|
for (i = iFirst; i <= iLast; i += dIncr) {
|
|
if (_aTBar[i].ptbar && _aTBar[i].fShow) {
|
|
HWND hwnd;
|
|
|
|
_aTBar[i].ptbar->GetWindow(&hwnd);
|
|
ASSERT(IsWindow(hwnd));
|
|
#if 1
|
|
// BUGBUG workaround toolbar/deskbar bug
|
|
// (db->ShowDW doesn't notify _aTBar[i])
|
|
if (!IsWindowVisible(hwnd)) {
|
|
// BUGBUG hmm, make sure autohide *is* in TAB order?
|
|
DebugMsg(DM_ERROR, TEXT("csb._itbta: hwnd=%x fShow && !visible (?)"), hwnd);
|
|
continue;
|
|
}
|
|
#else
|
|
ASSERT(IsWindowVisible(hwnd));
|
|
#endif
|
|
// do a SetFocus for ie3 compatibility
|
|
SetFocus(hwnd);
|
|
|
|
HRESULT hres;
|
|
hres = UnkTranslateAcceleratorIO(_aTBar[i].ptbar, lpMsg);
|
|
if (hres == S_OK) {
|
|
return S_OK;
|
|
}
|
|
else if (FAILED(hres)) {
|
|
// compatibility w/ old guys
|
|
DebugMsg(DM_ERROR, TEXT("csb._itbta: hres=%x => S_OK (compat)"), hres);
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
#endif // }
|
|
|
|
BOOL CShellBrowser::_ValidTargetPidl(LPCITEMIDLIST pidl)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
// validate that this is an allowable target to browse to.
|
|
// check that it is a child of our root.
|
|
if (IsRooted()) {
|
|
fRet = (BOOL)ILFindChild(g_pidlRoot, pidl);
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT CShellBrowser::_SaveITbarLayout(void)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
|
|
if (_fUISetByAutomation)
|
|
{
|
|
return S_OK;
|
|
}
|
|
if(_GetITBar())
|
|
{
|
|
IPersistStreamInit *pITbarPSI;
|
|
|
|
//Yes! It's a different type. We may need to save the stream
|
|
if(SUCCEEDED(_GetITBar()->QueryInterface(IID_IPersistStreamInit, (void **)&pITbarPSI)))
|
|
{
|
|
IStream *pstm = NULL;
|
|
|
|
//Do we need to save the stream?
|
|
if(pITbarPSI->IsDirty() == S_OK)
|
|
{
|
|
pstm = GetITBarStream(_pidlCur, STGM_WRITE);
|
|
|
|
if(pstm)
|
|
{
|
|
//Stream exists. Save it there!.
|
|
hres = pITbarPSI->Save(pstm, TRUE);
|
|
pstm->Release();
|
|
}
|
|
else
|
|
{
|
|
//Stream creation failed! Why?
|
|
TraceMsg(DM_ITBAR, "CSB::_NavigateToPidl ITBar Stream creation failed");
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
else
|
|
hres = S_OK; // No need to save. Return success!
|
|
|
|
pITbarPSI->Release();
|
|
}
|
|
#ifdef DEBUG
|
|
else
|
|
{
|
|
//ITBar doesn't support IPersistStreamInit?
|
|
TraceMsg(DM_ITBAR, "CSB::_NavigateToPidl ITBar doesn't support IPersistStreamInit");
|
|
ASSERT(0);
|
|
}
|
|
#endif //DEBUG
|
|
}
|
|
|
|
return(hres);
|
|
}
|
|
|
|
HRESULT CShellBrowser::_NavigateToPidl(LPCITEMIDLIST pidl, DWORD grfHLNF, DWORD dwFlags)
|
|
{
|
|
if (pidl) {
|
|
|
|
if (!_ValidTargetPidl(pidl)) {
|
|
// we can't navigate to it... create a new top level dude
|
|
SHELLEXECUTEINFO shei = { 0 };
|
|
|
|
shei.cbSize = sizeof(shei);
|
|
shei.fMask = SEE_MASK_INVOKEIDLIST;
|
|
shei.nShow = SW_SHOWNORMAL;
|
|
shei.lpIDList = (LPITEMIDLIST)pidl;
|
|
ShellExecuteEx(&shei);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (!_fVisitedNet && IsURLChild(pidl, TRUE)) {
|
|
_IncrNetSessionCount();
|
|
}
|
|
}
|
|
|
|
// See if we are about to navigate to a pidl of a different type. If so,
|
|
// open the stream and call the ITBar's IPersistStreamInit::save to save.
|
|
if(_GetITBar())
|
|
{
|
|
//Check if we are about to navigate to a different "type" of folder
|
|
if(((BOOL)_pidlCur && !IsURLChild(_pidlCur, FALSE)) !=
|
|
((BOOL)pidl && !IsURLChild(pidl, FALSE)))
|
|
_SaveITbarLayout();
|
|
}
|
|
|
|
return SUPERCLASS::_NavigateToPidl(pidl, grfHLNF, dwFlags);
|
|
}
|
|
|
|
HRESULT CShellBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
|
|
{
|
|
// turn explore to newbrowser
|
|
if (IsCShellBrowser() && (wFlags & SBSP_EXPLOREMODE))
|
|
{
|
|
wFlags &= ~(SBSP_DEFBROWSER | SBSP_SAMEBROWSER);
|
|
wFlags |= SBSP_NEWBROWSER;
|
|
}
|
|
|
|
// REVIEW: do this only if NEWBROWSER is not set?
|
|
if (pidl && pidl != (LPCITEMIDLIST)-1 && !_ValidTargetPidl(pidl))
|
|
return E_FAIL;
|
|
|
|
if ((wFlags & SBSP_PARENT) && !v_ShouldAllowNavigateParent())
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
return SUPERCLASS::BrowseObject(pidl, wFlags);
|
|
}
|
|
|
|
|
|
void CShellBrowser::_ToolTipFromCmd(LPTOOLTIPTEXT pnm)
|
|
{
|
|
UINT idCommand = pnm->hdr.idFrom;
|
|
LPTSTR pszText = pnm->szText;
|
|
int cchText = ARRAYSIZE(pnm->szText);
|
|
DWORD dwStyle;
|
|
|
|
if (pnm->hdr.hwndFrom)
|
|
dwStyle = GetWindowLong(pnm->hdr.hwndFrom, GWL_STYLE);
|
|
|
|
switch (idCommand) {
|
|
case FCIDM_NAVIGATEBACK:
|
|
if (TLGetToolTipText(&_tl, pszText, cchText, HLNF_NAVIGATINGBACK, IDS_NAVIGATEBACKTO)) {
|
|
if (pnm->hdr.hwndFrom)
|
|
SetWindowLong(pnm->hdr.hwndFrom, GWL_STYLE, dwStyle | TTS_NOPREFIX);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case FCIDM_NAVIGATEFORWARD:
|
|
if (TLGetToolTipText(&_tl, pszText, cchText, HLNF_NAVIGATINGFORWARD, IDS_NAVIGATEFORWARDTO)) {
|
|
if (pnm->hdr.hwndFrom)
|
|
SetWindowLong(pnm->hdr.hwndFrom, GWL_STYLE, dwStyle | TTS_NOPREFIX);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (pnm->hdr.hwndFrom)
|
|
SetWindowLong(pnm->hdr.hwndFrom, GWL_STYLE, dwStyle & ~(TTS_NOPREFIX));
|
|
if (!LoadString(HINST_THISDLL, idCommand + MH_TTBASE, pszText, cchText))
|
|
*pszText = 0;
|
|
}
|
|
|
|
STDAPI_(BOOL) OpenFolderWindow(IETHREADPARAM* pieiIn);
|
|
|
|
void CShellBrowser::v_ParentFolder()
|
|
{
|
|
if (v_ShouldAllowNavigateParent()) {
|
|
IETHREADPARAM* piei = new IETHREADPARAM();
|
|
if (piei) {
|
|
piei->hwndCaller = _hwnd;
|
|
piei->pidl = ILClone(_pidlCur);
|
|
ILRemoveLastID(piei->pidl);
|
|
piei->uFlags = COF_NORMAL;
|
|
piei->nCmdShow = SW_NORMAL;
|
|
piei->psbCaller = this;
|
|
AddRef();
|
|
OpenFolderWindow(piei);
|
|
delete piei;
|
|
}
|
|
}
|
|
else if (!IsRooted())
|
|
{
|
|
// tell user the correct way to browse to the desktop
|
|
ShellMessageBox(HINST_THISDLL, _hwnd, MAKEINTRESOURCE(IDS_CANTBROWSEDESKTOP), NULL, MB_ICONHAND | MB_OK);
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::v_ForwardMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
_ForwardViewMsg(uMsg, wParam, lParam);
|
|
}
|
|
|
|
void CShellBrowser::_OnCommand(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (_ShouldForwardMenu(WM_COMMAND, wParam, lParam)) {
|
|
_ForwardViewMsg(WM_COMMAND, wParam, lParam);
|
|
return;
|
|
}
|
|
|
|
|
|
UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam);
|
|
HWND hwndControl = GET_WM_COMMAND_HWND(wParam, lParam);
|
|
switch(idCmd)
|
|
{
|
|
case FCIDM_FINDFILES:
|
|
if (!SHRestricted(REST_NOFIND)) {
|
|
if (!_pcmdt || FAILED(_pcmdt->Exec(NULL, OLECMDID_FIND, OLECMDEXECOPT_PROMPTUSER, NULL, NULL)))
|
|
SHFindFiles(_pidlCur, NULL);
|
|
}
|
|
break;
|
|
|
|
case FCIDM_BACKSPACE:
|
|
if (_pidlCur && IsURLChild(_pidlCur, TRUE)) {
|
|
if (TLGetPidl(&_tlGlobal, HLNF_NAVIGATINGBACK, NULL) == S_OK)
|
|
{
|
|
_OnCommand(GET_WM_COMMAND_MPS(FCIDM_NAVIGATEBACK,
|
|
GET_WM_COMMAND_HWND(wParam, lParam),
|
|
GET_WM_COMMAND_CMD(wParam, lParam)));
|
|
}
|
|
} else {
|
|
_OnCommand(GET_WM_COMMAND_MPS(FCIDM_PREVIOUSFOLDER,
|
|
GET_WM_COMMAND_HWND(wParam, lParam),
|
|
GET_WM_COMMAND_CMD(wParam, lParam)));
|
|
}
|
|
break;
|
|
|
|
case FCIDM_PREVIOUSFOLDER:
|
|
// missnamed... is really parent folder
|
|
v_ParentFolder();
|
|
break;
|
|
|
|
case FCIDM_FILECLOSE:
|
|
PostMessage(_hwnd, WM_CLOSE, 0, 0);
|
|
break;
|
|
|
|
case FCIDM_BROWSEROPTIONS:
|
|
_DoOptions(NULL);
|
|
break;
|
|
|
|
case FCIDM_MAIL:
|
|
RunIndirectRegCommand(_hwnd, HKEY_LOCAL_MACHINE, MAIL_DEF_KEY);
|
|
break;
|
|
|
|
case FCIDM_NEWS:
|
|
RunIndirectRegCommand(_hwnd, HKEY_LOCAL_MACHINE, NEWS_DEF_KEY);
|
|
break;
|
|
|
|
case FCIDM_NEWMESSAGE:
|
|
DropOnMailRecipient(NULL, FALSE);
|
|
break;
|
|
|
|
case FCIDM_SENDLINK:
|
|
if (_pidlCur)
|
|
SendDocToMailRecipient(_pidlCur, FALSE);
|
|
break;
|
|
|
|
case FCIDM_SENDDOCUMENT:
|
|
if (_pidlCur)
|
|
SendDocToMailRecipient(_pidlCur, TRUE);
|
|
break;
|
|
case FCIDM_STARTPAGE:
|
|
case FCIDM_SEARCHPAGE:
|
|
case FCIDM_UPDATEPAGE:
|
|
case FCIDM_TODAYSLINKPAGE:
|
|
ASSERT(IDP_START == 0);
|
|
ASSERT(FCIDM_STARTPAGE+IDP_SEARCH == FCIDM_SEARCHPAGE);
|
|
ASSERT(FCIDM_STARTPAGE+IDP_UPDATE == FCIDM_UPDATEPAGE);
|
|
ASSERT(FCIDM_STARTPAGE+IDP_TODAYSLINK == FCIDM_TODAYSLINKPAGE);
|
|
{
|
|
LPITEMIDLIST pidl = NULL;
|
|
HRESULT hres = SHDGetPageLocation(_hwnd, idCmd-FCIDM_STARTPAGE, NULL, 0, &pidl);
|
|
if (SUCCEEDED(hres)) {
|
|
hres = _NavigateToPidl(pidl, 0, 0);
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case FCIDM_SEARCHSIMILAR:
|
|
if (_pautoWB2)
|
|
FindSimilar(_pautoWB2, FALSE);
|
|
break;
|
|
|
|
case FCIDM_HELPABOUT:
|
|
{
|
|
TCHAR szWindows[64];
|
|
LoadString(HINST_THISDLL, g_fRunningOnNT ? IDS_WINDOWSNT : IDS_WINDOWS95, szWindows, ARRAYSIZE(szWindows));
|
|
ShellAbout(_hwnd, szWindows, NULL, NULL);
|
|
break;
|
|
}
|
|
|
|
case FCIDM_NAVIGATEBACK:
|
|
if (_psvPending)
|
|
_CancelPendingView();
|
|
else
|
|
NavigateToPidl(NULL, HLNF_NAVIGATINGBACK);
|
|
break;
|
|
|
|
case FCIDM_NAVIGATEFORWARD:
|
|
NavigateToPidl(NULL, HLNF_NAVIGATINGFORWARD);
|
|
break;
|
|
|
|
case FCIDM_ADDTOFAVNOUI:
|
|
_AddToFavorites(NULL, NULL, FALSE);
|
|
break;
|
|
|
|
case FCIDM_REFRESH:
|
|
Exec(NULL, OLECMDID_REFRESH, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
|
|
break;
|
|
|
|
case FCIDM_NEXTCTL:
|
|
_CycleFocus(NULL);
|
|
break;
|
|
|
|
case FCIDM_OPEN_HISTORY:
|
|
_OpenHistory();
|
|
break;
|
|
|
|
case FCIDM_OPEN_SUBSCRIPTION:
|
|
_OpenSubscription();
|
|
break;
|
|
|
|
case FCIDM_VIEWOFFLINE:
|
|
_Offline(SBSC_TOGGLE);
|
|
break;
|
|
|
|
case FCIDM_VIEWTOOLBAR:
|
|
v_ShowControl(FCW_INTERNETBAR, SBSC_TOGGLE);
|
|
break;
|
|
|
|
case FCIDM_VIEWSTATUSBAR:
|
|
v_ShowControl(FCW_STATUS, SBSC_TOGGLE);
|
|
break;
|
|
|
|
default:
|
|
if (IsInRange(idCmd, FCIDM_FAVORITECMDFIRST, FCIDM_FAVORITECMDLAST)) {
|
|
_FavoriteOnCommand(_hmenuFav, idCmd);
|
|
} else if (IsInRange(idCmd, FCIDM_RECENTFIRST, FCIDM_RECENTLAST)) {
|
|
NavigateToTLItem(idCmd - (FCIDM_RECENTFIRST+CRECENTMENU_MAX) );
|
|
} else {
|
|
SUPERCLASS::_OnCommand(wParam, lParam);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HMENU CShellBrowser::_GetMenuFromID(UINT uID)
|
|
{
|
|
return GetMenuFromID(_hmenuCur, uID);
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Construct the top-level favorites menu
|
|
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
void
|
|
CShellBrowser::_FavoritesConstructTop()
|
|
{
|
|
if ( !_hmenuFav )
|
|
_hmenuFav = FileMenu_Create((COLORREF)-1, 0, NULL, 0, FMF_NONE);
|
|
|
|
if (_hmenuFav)
|
|
{
|
|
LPITEMIDLIST pidlFavorites = SHCloneSpecialIDList(NULL, CSIDL_FAVORITES, TRUE);
|
|
HMENU hmenuStatic = LoadMenuPopup(MENU_FAVORITES);
|
|
if (hmenuStatic)
|
|
{
|
|
FMCOMPOSE fmc;
|
|
HRESULT hres;
|
|
int cy;
|
|
|
|
// Calculate how much screen height we want to take.
|
|
// (7/8 of the screen generally). Account for separator
|
|
// and possible "More..." menu item too.
|
|
|
|
cy = (GetSystemMetrics(SM_CYSCREEN) * 7) / 8;
|
|
cy -= ((2 + GetMenuItemCount(hmenuStatic)) * GetSystemMetrics(SM_CYMENUSIZE));
|
|
|
|
fmc.cbSize = SIZEOF(fmc);
|
|
fmc.dwMask = FMC_FLAGS | FMC_FILTER | FMC_PIDL |
|
|
FMC_CXMAX | FMC_CYSPACING | FMC_CYMAX |
|
|
FMC_FILTERTYPES | FMC_CALLBACK;
|
|
fmc.id = FCIDM_FAVORITE_ITEM;
|
|
fmc.dwFlags = FMF_RESTRICTHEIGHT | FMF_MOREITEMS | FMF_TOOLTIPS | FMF_CANORDER;
|
|
fmc.dwFSFilter = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
|
|
fmc.pidlFolder = pidlFavorites;
|
|
fmc.pfnCallback = Favorites_Callback;
|
|
fmc.cxMax = 200; // some reasonable arbitrary width
|
|
fmc.cyMax = cy;
|
|
fmc.cySpacing = 2; // Start menu defaults to 6
|
|
fmc.pszFilterTypes = TEXT("url\0");
|
|
|
|
hres = FileMenu_Compose(_hmenuFav, FMCM_APPEND, &fmc);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (0 < fmc.cItems)
|
|
FileMenu_InsertSeparator(_hmenuFav, 0);
|
|
|
|
// Register for notification of changes to these things
|
|
if (!_uNotifyFav)
|
|
_uNotifyFav = RegisterNotify(_hwnd, WMC_FAV_CHANGE, pidlFavorites, SHCNE_DISKEVENTS, 0, TRUE);
|
|
}
|
|
|
|
FileMenu_InsertMenu(_hmenuFav, hmenuStatic, 0);
|
|
DestroyMenu(hmenuStatic);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Handle WM_INITMENUPOPUP for favorites menu
|
|
|
|
This function builds the favorites menu on the fly.
|
|
Cascaded menus are not built until they are expanded.
|
|
|
|
This can be tricky. _hmenuFav is the master favorites
|
|
menu. The displayed favorites menu is actually the
|
|
hmenu passed in as an argument here. This function
|
|
creates the favorites menu (if necessary) and keeps
|
|
it stored in _hmenuFav, and copies it to hmenu.
|
|
The submenus are NOT ever copied -- both favorite
|
|
menu popups hold handles to the same submenus.
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void
|
|
CShellBrowser::_FavoriteInitPopup(
|
|
IN HMENU hmenu,
|
|
IN BOOL fTopLevel)
|
|
{
|
|
// Is this the top-level menu?
|
|
if (fTopLevel)
|
|
{
|
|
// Yes
|
|
if ( !_hmenuFav )
|
|
_FavoritesConstructTop();
|
|
|
|
if (_hmenuFav)
|
|
{
|
|
if (FileMenu_IsDelayedInvalid(_hmenuFav))
|
|
{
|
|
Menu_RemoveAllSubMenus(hmenu);
|
|
FileMenu_DeleteAllItems(_hmenuFav);
|
|
_FavoritesConstructTop();
|
|
Menu_Replace(hmenu, _hmenuFav);
|
|
}
|
|
else if (!FileMenu_IsFileMenu(hmenu) || _fFavMenuChanged)
|
|
{
|
|
// The browser maintains a copy of the _hmenuFav. Any
|
|
// changes made to _hmenuFav need to be propagated to
|
|
// the copy. But don't blow away the submenus in the
|
|
// process!
|
|
Menu_RemoveAllSubMenus(hmenu);
|
|
Menu_Replace(hmenu, _hmenuFav);
|
|
_fFavMenuChanged = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No; this is a submenu
|
|
FileMenu_InitMenuPopup(hmenu);
|
|
}
|
|
}
|
|
|
|
BOOL CShellBrowser::_FavoritesHandleMeasureItem(LPMEASUREITEMSTRUCT lpmi)
|
|
{
|
|
if (lpmi->CtlType == ODT_MENU &&
|
|
(IsInRange(lpmi->itemID, FCIDM_FAVORITECMDFIRST, FCIDM_FAVORITECMDLAST) ||
|
|
lpmi->itemID == 0))
|
|
{
|
|
FileMenu_MeasureItem(NULL, lpmi);
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL CShellBrowser::_FavoritesHandleDrawItem(LPDRAWITEMSTRUCT lpdi)
|
|
{
|
|
// BUGBUG: remove this after jeff fixes the wm_drawitem zero extend bug
|
|
// ASSERT(LOWORD(lpdi->itemID) == lpdi->itemID);
|
|
// TraceMsg(0, "HandleDrawItem itemID = %d", lpdi->itemID);
|
|
lpdi->itemID = LOWORD(lpdi->itemID);
|
|
|
|
if (lpdi->CtlType == ODT_MENU &&
|
|
(IsInRange(lpdi->itemID, FCIDM_FAVORITECMDFIRST, FCIDM_FAVORITECMDLAST) ||
|
|
lpdi->itemID == 0))
|
|
{
|
|
FileMenu_DrawItem(NULL, lpdi);
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL CShellBrowser::_FavoritesHandleMenuChar(HMENU hmenu, TCHAR ch, LRESULT *plres)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
UINT id = GetMenuItemID(hmenu, 0);
|
|
|
|
if (IsInRange(id, FCIDM_FAVORITECMDFIRST, FCIDM_FAVORITECMDLAST))
|
|
{
|
|
*plres = FileMenu_HandleMenuChar(hmenu, ch);
|
|
fRet = TRUE;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOL IsRegistered(LPCTSTR pszReg)
|
|
{
|
|
LONG cbSize = 0;
|
|
return (RegQueryValue(HKEY_LOCAL_MACHINE, pszReg, NULL, &cbSize) == ERROR_SUCCESS) &&
|
|
(cbSize > 1);
|
|
}
|
|
|
|
void CShellBrowser::_AddMailNewsMenu(HMENU hmenu)
|
|
{
|
|
// actually, this removes the mail & news menu if it's not registered
|
|
// and if neither are there, remove the separator too
|
|
BOOL fRemoveSeparator = TRUE;
|
|
|
|
if (IsRegistered(MAIL_DEF_KEY))
|
|
{
|
|
fRemoveSeparator = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DeleteMenu(hmenu, FCIDM_MAIL, MF_BYCOMMAND);
|
|
}
|
|
|
|
if (IsRegistered(NEWS_DEF_KEY))
|
|
{
|
|
fRemoveSeparator = FALSE;
|
|
}
|
|
else
|
|
{
|
|
DeleteMenu(hmenu, FCIDM_NEWS, MF_BYCOMMAND);
|
|
}
|
|
|
|
if (fRemoveSeparator)
|
|
DeleteMenu(hmenu, FCIDM_MAILNEWSSEPARATOR, MF_BYCOMMAND);
|
|
}
|
|
|
|
LRESULT CShellBrowser::v_OnInitMenuPopup(HMENU hmenuPopup, int nIndex, BOOL fSystemMenu)
|
|
{
|
|
if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_EXPLORE))
|
|
{
|
|
TraceMsg(DM_BACKFORWARD, "_OnInitMenuPopup TLGetPidl(BACK) returns %x", TLGetPidl(&_tlGlobal, HLNF_NAVIGATINGBACK, NULL));
|
|
TraceMsg(DM_BACKFORWARD, "_OnInitMenuPopup TLGetPidl(FORW) returns %x", TLGetPidl(&_tlGlobal, HLNF_NAVIGATINGFORWARD, NULL));
|
|
|
|
EnableMenuItem(hmenuPopup, FCIDM_NAVIGATEBACK,
|
|
(S_OK == TLGetPidl(&_tlGlobal, HLNF_NAVIGATINGBACK, NULL)) ? ( MF_BYCOMMAND| MF_ENABLED) : (MF_BYCOMMAND | MF_GRAYED));
|
|
EnableMenuItem(hmenuPopup, FCIDM_NAVIGATEFORWARD,
|
|
(S_OK == TLGetPidl(&_tlGlobal, HLNF_NAVIGATINGFORWARD, NULL)) ? ( MF_BYCOMMAND| MF_ENABLED) : (MF_BYCOMMAND | MF_GRAYED));
|
|
EnableMenuItem(hmenuPopup, FCIDM_PREVIOUSFOLDER,
|
|
v_ShouldAllowNavigateParent() ? ( MF_BYCOMMAND| MF_ENABLED) : (MF_BYCOMMAND | MF_GRAYED));
|
|
|
|
// This feature is now turned off by default, until we figure out the business issues.
|
|
// Only show Search Similar command if it's enabled in the registry.
|
|
// We should also remove it when we're browsing folders.
|
|
|
|
HKEY hkey;
|
|
if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_MAIN, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwTemp = 0;
|
|
DWORD dwType = REG_DWORD;
|
|
DWORD cbSize = sizeof(dwTemp);
|
|
|
|
if ((RegQueryValueEx(hkey, "Show_SearchSimilar", 0, &dwType, (LPBYTE)&dwTemp, &cbSize) != ERROR_SUCCESS) ||
|
|
(dwTemp == 0))
|
|
{
|
|
RemoveMenu(hmenuPopup, FCIDM_SEARCHSIMILAR, MF_BYCOMMAND);
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (IsRooted() || ISROOTEDCLASS()) {
|
|
DeleteMenu(hmenuPopup, FCIDM_STARTPAGE, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuPopup, FCIDM_SEARCHPAGE, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuPopup, FCIDM_TODAYSLINKPAGE, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuPopup, FCIDM_LINKSSEPARATOR, MF_BYCOMMAND);
|
|
}
|
|
|
|
_AddMailNewsMenu(hmenuPopup);
|
|
|
|
TLInitRecentMenu(&_tl, hmenuPopup, MenuIndexFromID(hmenuPopup, FCIDM_RECENTMENU) + 1);
|
|
}
|
|
else if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_VIEW) ||
|
|
hmenuPopup == GetSystemMenu(_hwnd, FALSE))
|
|
{
|
|
CheckMenuItem(hmenuPopup, FCIDM_VIEWTOOLBAR,
|
|
v_ShowControl(FCW_INTERNETBAR, SBSC_QUERY) == SBSC_SHOW ? (MF_BYCOMMAND | MF_CHECKED) : (MF_BYCOMMAND | MF_UNCHECKED));
|
|
CheckMenuItem(hmenuPopup, FCIDM_VIEWSTATUSBAR,
|
|
v_ShowControl(FCW_STATUS, SBSC_QUERY) == SBSC_SHOW ? (MF_BYCOMMAND | MF_CHECKED) : (MF_BYCOMMAND | MF_UNCHECKED));
|
|
|
|
}
|
|
else if (hmenuPopup == _GetMenuFromID(FCIDM_MENU_FILE)) {
|
|
EnableMenuItem(hmenuPopup, FCIDM_FILECLOSE, _fDisableModeless() ?
|
|
(MF_BYCOMMAND | MF_GRAYED) : ( MF_BYCOMMAND| MF_ENABLED));
|
|
if(_pidlCur && IsURLChild(_pidlCur, TRUE))
|
|
{
|
|
CheckMenuItem(hmenuPopup, FCIDM_VIEWOFFLINE,
|
|
_Offline(SBSC_QUERY) == TRUE ? (MF_BYCOMMAND | MF_CHECKED) : (MF_BYCOMMAND | MF_UNCHECKED));
|
|
}
|
|
else
|
|
{
|
|
DeleteMenu(hmenuPopup, FCIDM_VIEWOFFLINE, MF_BYCOMMAND);
|
|
}
|
|
|
|
|
|
}
|
|
else if (_GetMenuFromID(FCIDM_MENU_FAVORITES) == hmenuPopup)
|
|
{
|
|
_FavoriteInitPopup(hmenuPopup, TRUE);
|
|
}
|
|
else if (GetMenuItemID(hmenuPopup, 0) == FCIDM_FAVORITE_ITEM)
|
|
{
|
|
_FavoriteInitPopup(hmenuPopup, FALSE);
|
|
}
|
|
else if (GetMenuItemID(hmenuPopup, 0) == FCIDM_MAIL)
|
|
{
|
|
if (!IsRegistered(MAIL_DEF_KEY))
|
|
{
|
|
DeleteMenu(hmenuPopup, FCIDM_MAIL, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuPopup, FCIDM_NEWMESSAGE, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuPopup, FCIDM_SENDLINK, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuPopup, FCIDM_MAILNEWSSEPARATOR, MF_BYCOMMAND);
|
|
}
|
|
|
|
if (!IsRegistered(NEWS_DEF_KEY))
|
|
{
|
|
DeleteMenu(hmenuPopup, FCIDM_MAILNEWSSEPARATOR, MF_BYCOMMAND);
|
|
DeleteMenu(hmenuPopup, FCIDM_NEWS, MF_BYCOMMAND);
|
|
}
|
|
}
|
|
else if (_pcmSendTo)
|
|
_pcmSendTo->HandleMenuMsg(WM_INITMENUPOPUP, (WPARAM)hmenuPopup, (LPARAM)MAKELONG(nIndex, fSystemMenu));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#pragma warning (disable:4200)
|
|
typedef struct {
|
|
int nItemOffset;
|
|
int nPopupOffset;
|
|
struct {
|
|
UINT uID;
|
|
HMENU hPopup;
|
|
} sPopupIDs[];
|
|
} MENUHELPIDS;
|
|
#pragma warning (default:4200)
|
|
|
|
LRESULT CShellBrowser::_OnMenuSelect(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]; // OK with MAX_PATH
|
|
UINT uMenuFlags = GET_WM_MENUSELECT_FLAGS(wParam, lParam);
|
|
WORD wID = GET_WM_MENUSELECT_CMD(wParam, lParam);
|
|
HMENU hMenu = GET_WM_MENUSELECT_HMENU(wParam, lParam);
|
|
|
|
Favorites_HandleMenuSelect(wParam, lParam);
|
|
|
|
if (!hMenu && LOWORD(uMenuFlags)==0xffff)
|
|
{
|
|
SendMessage(_hwndStatus, SB_SIMPLE, 0, 0L);
|
|
return 0L;
|
|
}
|
|
|
|
// Clear this out just in case, but don't update yet
|
|
SendMessage(_hwndStatus, SB_SETTEXT, SBT_NOBORDERS|255, (LPARAM)(LPTSTR)c_szNULL);
|
|
SendMessage(_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 (!_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;
|
|
//
|
|
// NOTES: We are eliminating this range check so that we can display
|
|
// help-text on sub-menus. I'm not sure why explorer.exe has this check.
|
|
//
|
|
#if 0
|
|
if(!IsInRange(wID, FCIDM_GLOBALFIRST, FCIDM_GLOBALLAST))
|
|
return 0L;
|
|
#endif
|
|
uMenuFlags = 0;
|
|
}
|
|
|
|
if (!IsInRange(wID, FCIDM_FIRST, FCIDM_LAST))
|
|
return 0L; // not ours
|
|
|
|
#if 0
|
|
if (IsInRange(wID, FCIDM_RECENTFIRST, FCIDM_RECENTLAST)) {
|
|
wID = FCIDM_RECENTFIRST;
|
|
}
|
|
#endif
|
|
|
|
szHint[0] = 0;
|
|
|
|
sMenuHelpIDs.sPopupIDs[0].uID = 0;
|
|
sMenuHelpIDs.sPopupIDs[0].hPopup = NULL;
|
|
|
|
DoMenuHelp:
|
|
MenuHelp(WM_MENUSELECT, wParam, lParam, _hmenuCur, HINST_THISDLL,
|
|
_hwndStatus, (UINT *)&sMenuHelpIDs);
|
|
|
|
return 1L;
|
|
}
|
|
|
|
LRESULT CShellBrowser::_ThunkTTNotify(LPTOOLTIPTEXTA pnmTTTA)
|
|
{
|
|
TOOLTIPTEXTW tttw;
|
|
|
|
tttw.hdr = pnmTTTA->hdr;
|
|
tttw.hdr.code = TTN_NEEDTEXTW;
|
|
|
|
tttw.lpszText = tttw.szText;
|
|
tttw.hinst = pnmTTTA->hinst;
|
|
tttw.uFlags = pnmTTTA->uFlags;
|
|
tttw.lParam = pnmTTTA->lParam;
|
|
|
|
LRESULT lRes = SUPERCLASS::_OnNotify(&tttw.hdr);
|
|
|
|
pnmTTTA->hdr = tttw.hdr;
|
|
pnmTTTA->hdr.code = TTN_NEEDTEXTA;
|
|
|
|
pnmTTTA->hinst = tttw.hinst;
|
|
pnmTTTA->uFlags = tttw.uFlags;
|
|
pnmTTTA->lParam = tttw.lParam;
|
|
|
|
if (tttw.lpszText == LPSTR_TEXTCALLBACKW)
|
|
pnmTTTA->lpszText = LPSTR_TEXTCALLBACKA;
|
|
else if (!tttw.lpszText)
|
|
pnmTTTA->lpszText = NULL;
|
|
else if (!HIWORD(tttw.lpszText))
|
|
pnmTTTA->lpszText = (LPSTR)tttw.lpszText;
|
|
else {
|
|
WideCharToMultiByte(CP_ACP, 0, tttw.lpszText, -1,
|
|
pnmTTTA->szText, ARRAYSIZE(pnmTTTA->szText), NULL, NULL);
|
|
}
|
|
|
|
return lRes;
|
|
}
|
|
|
|
|
|
LRESULT CShellBrowser::_OnNotify(LPNMHDR pnm)
|
|
{
|
|
switch (pnm->idFrom) {
|
|
|
|
case 0: // special WM_NOTIFY msg
|
|
if (pnm->code == SEN_DDEEXECUTE) {
|
|
|
|
// short cut notifier around the dde conv.
|
|
|
|
return DDEHandleViewFolderNotify(this, _hwnd, (LPNMVIEWFOLDER)pnm);
|
|
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (IsInRange(pnm->idFrom, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST)) {
|
|
|
|
if (pnm->code == TTN_NEEDTEXTA && _fUnicode) {
|
|
return _ThunkTTNotify((LPTOOLTIPTEXTA)pnm);
|
|
} else {
|
|
return SUPERCLASS::_OnNotify(pnm);
|
|
}
|
|
|
|
} else {
|
|
switch (pnm->code) {
|
|
case TTN_NEEDTEXT:
|
|
_ToolTipFromCmd((LPTOOLTIPTEXT)pnm);
|
|
break;
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
BOOL CShellBrowser::_ActivatePendingView(void)
|
|
{
|
|
_fTitleSet = FALSE;
|
|
|
|
// NOTES: (SatoNa)
|
|
//
|
|
// Notice that we no longer call SetRect(&_rcBorderDoc, 0, 0, 0, 0)
|
|
// here. We call it in CShellBrowser::_ReleaseShellView instead.
|
|
// See my comment over there for detail.
|
|
//
|
|
if (!SUPERCLASS::_ActivatePendingView())
|
|
return FALSE;
|
|
|
|
_SetTitle(NULL);
|
|
v_SetIcon();
|
|
VALIDATEPENDINGSTATE();
|
|
|
|
if (_pxtb )
|
|
_pxtb->SendToolbarMsg(&CGID_ShellBrowser, TB_ENABLEBUTTON, FCIDM_PREVIOUSFOLDER, v_ShouldAllowNavigateParent(), NULL);
|
|
|
|
if (_psw) {
|
|
WinList_NotifyNewLocation(_psw, _dwRegisterWinList, _pidlCur);
|
|
}
|
|
|
|
if (!_HasToolbarFocus()) {
|
|
SetFocus(_hwndView);
|
|
}
|
|
|
|
_fUnicode = (SendMessage (_hwndView, WM_NOTIFYFORMAT,
|
|
(WPARAM)_hwnd, NF_QUERY) == NFR_UNICODE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CShellBrowser::_UpdateBackForwardState()
|
|
{
|
|
// update the back/forward state
|
|
// BOOL fEnable = (_psvPending != NULL) || (TLGetPidl(&_tlGlobal, HLNF_NAVIGATINGBACK, NULL) == S_OK);
|
|
// SendMessage(_hwndToolbar, TB_ENABLEBUTTON, FCIDM_NAVIGATEBACK, fEnable);
|
|
|
|
// fEnable = (TLGetPidl(&_tlGlobal, HLNF_NAVIGATINGFORWARD, NULL) == S_OK);
|
|
// SendMessage(_hwndToolbar, TB_ENABLEBUTTON, FCIDM_NAVIGATEFORWARD, fEnable);
|
|
|
|
SUPERCLASS::_UpdateBackForwardState();
|
|
}
|
|
|
|
HRESULT CShellBrowser::_TryShell2Rename(IShellView* psv, LPCITEMIDLIST pidlNew)
|
|
{
|
|
HRESULT hres = SUPERCLASS::_TryShell2Rename(psv, pidlNew);
|
|
if (SUCCEEDED(hres)) {
|
|
_SetTitle(NULL);
|
|
|
|
//if (_aTBar[ITB_STBAR].fShow)
|
|
//DriveList_UpdatePath(this, FALSE);
|
|
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
void CShellBrowser::_OnFavsChanged(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (g_fNewNotify && (wParam || lParam))
|
|
{
|
|
// New style of notifications need to lock and unlock in order to free the memory...
|
|
LPSHChangeNotificationLock pshcnl;
|
|
LPITEMIDLIST *ppidl;
|
|
LONG lEvent;
|
|
pshcnl = _SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
|
|
if (pshcnl)
|
|
{
|
|
_SHChangeNotification_Unlock(pshcnl);
|
|
}
|
|
}
|
|
|
|
if (_hmenuFav)
|
|
FileMenu_DelayedInvalidate(_hmenuFav);
|
|
}
|
|
|
|
|
|
BOOL CShellBrowser::_ShouldForwardMenu(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
if (!_fTryHelpMenuMerge)
|
|
return FALSE;
|
|
|
|
switch (uMsg) {
|
|
case WM_MENUSELECT:
|
|
{
|
|
HMENU hmenu = GET_WM_MENUSELECT_HMENU(wParam, lParam);
|
|
|
|
// if the message is menu select and the menu is our main menubar,
|
|
// then there can be a change to/from one of the browser's menu
|
|
// this can only be the view's menu
|
|
if (hmenu) {
|
|
|
|
if (hmenu == _hmenuCur &&
|
|
_hmenuCur != _hmenuTemplate) {
|
|
|
|
_fForwardMenu = FALSE;
|
|
|
|
if (GET_WM_MENUSELECT_CMD(wParam, lParam) ==
|
|
(GetMenuItemCount(_hmenuCur) - 1)) {
|
|
// if it was a select on the help menu
|
|
HMENU hmenuPopup = GetSubMenu(hmenu, GET_WM_MENUSELECT_CMD(wParam, lParam));
|
|
|
|
if (_hmenuHelp != hmenuPopup) {
|
|
// but it wasn't our help menu
|
|
_fForwardMenu = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
// didn't come from a menu
|
|
if (_fForwardMenu) {
|
|
// after handling a command, this is false again
|
|
_fForwardMenu = FALSE;
|
|
|
|
// if it wasn't from an accelerator, forward it
|
|
if (!HIWORD(wParam))
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return _fForwardMenu;
|
|
}
|
|
|
|
DWORD CShellBrowser::v_RestartFlags()
|
|
{
|
|
return COF_CREATENEWWINDOW;
|
|
}
|
|
|
|
void CShellBrowser::_CloseAllParents()
|
|
{
|
|
LPITEMIDLIST pidl = ILClone(_pidlCur);
|
|
if (pidl) {
|
|
|
|
for (ILRemoveLastID(pidl); !ILIsEmpty(pidl); ILRemoveLastID(pidl)) {
|
|
HWND hwnd;
|
|
|
|
if (WinList_FindFolderWindow(pidl, NULL, &hwnd, NULL) == S_OK) {
|
|
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
|
}
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::_OnConfirmedClose()
|
|
{
|
|
if (_pidlCur && IsCShellBrowser() && (GetKeyState(VK_SHIFT) < 0)) {
|
|
_CloseAllParents();
|
|
}
|
|
|
|
// Save view states before closing all toolbars
|
|
_SaveState();
|
|
|
|
// Save the Internet toolbar before we close it!
|
|
_SaveITbarLayout();
|
|
|
|
_CloseAndReleaseToolbars();
|
|
|
|
// If this is done by automation, maybe we should not update the defaults, so
|
|
// to detect this we say if the window isnot visible, don't save away the defaults
|
|
if (IsWindowVisible(_hwnd) && !_fUISetByAutomation) {
|
|
|
|
// for the internet, save one setting for all, otherwise use the win95
|
|
// view stream mru
|
|
if (_pidlCur && IsURLChild(_pidlCur, TRUE)) {
|
|
DoWindowPlacement(_hwnd, NULL);
|
|
}
|
|
|
|
} else
|
|
_fDontSaveViewOptions = TRUE;
|
|
|
|
|
|
// If you wait until WM_DESTROY to do this, some OCs (like shockwave)
|
|
// will hang (probably posting themselves a message)
|
|
// To prevent flashing, we move the window off the screen, unfortunately
|
|
// we can't hide it as shockwave briefly puts up dialog which causes
|
|
// an ugly blank taskbar icon to appear.
|
|
|
|
// BUGBUG: this won't look too good with multi monitors...
|
|
SetWindowPos(_hwnd, NULL, 10000, 0, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
|
|
_CancelPendingView();
|
|
_ReleaseShellView();
|
|
|
|
SetMenu(_hwnd, NULL);
|
|
|
|
DestroyWindow(_hwnd);
|
|
}
|
|
|
|
|
|
// these three functions, CommonHandleFielSysChange,
|
|
// v_HandleFileSysChange and this one
|
|
// may seem strange, but the idea is that the notify may come in from
|
|
// different sources (OneTree vs, win95 style fsnotify vs nt style)
|
|
// _OnFSNotify cracks the input, unifies it and calls CommonHnaldeFileSysChange
|
|
// that calls to v_HandleFIleSysChange. The Common...() is for stuff both needs
|
|
// the v_Handle...() is for overridden ones
|
|
void CShellBrowser::_OnFSNotify(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LPSHChangeNotificationLock pshcnl = NULL;
|
|
LONG lEvent;
|
|
LPITEMIDLIST *ppidl;
|
|
IShellChangeNotify * pIFSN;
|
|
|
|
if (g_fNewNotify && (wParam || lParam))
|
|
{
|
|
// New style of notifications need to lock and unlock in order to free the memory...
|
|
pshcnl = _SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
|
|
} else {
|
|
lEvent = lParam;
|
|
ppidl = (LPITEMIDLIST*)wParam;
|
|
}
|
|
|
|
//
|
|
// If we haven't initialized "this" yet, we should ignore all the
|
|
// notification.
|
|
//
|
|
if (_pidlCur)
|
|
_CommonHandleFileSysChange(lEvent, ppidl[0], ppidl[1]);
|
|
|
|
//
|
|
// Forward to ITBar too...
|
|
//
|
|
if(_GetITBar() && SUCCEEDED(_GetITBar()->QueryInterface(IID_IShellChangeNotify, (void **)&pIFSN)))
|
|
{
|
|
pIFSN->OnChange(lEvent, ppidl[0], ppidl[1]);
|
|
pIFSN->Release();
|
|
}
|
|
|
|
if (pshcnl)
|
|
{
|
|
_SHChangeNotification_Unlock(pshcnl);
|
|
}
|
|
}
|
|
|
|
|
|
// 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 CShellBrowser::_FSChangeCheckClose(LPITEMIDLIST pidl, BOOL fDisconnect)
|
|
{
|
|
if (ILIsParent(pidl, _pidlCur, FALSE))
|
|
{
|
|
if (!fDisconnect) {
|
|
TCHAR szPath[MAX_URL_STRING];
|
|
if (SHGetPathFromIDList(_pidlCur, szPath)) {
|
|
if (!PathFileExists(szPath)) {
|
|
fDisconnect = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fDisconnect) {
|
|
_pautoWB2->Quit();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::v_HandleFileSysChange(LONG lEvent, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2)
|
|
{
|
|
BOOL fDisconnectAlways = FALSE;
|
|
|
|
//
|
|
// If we are in the middle of changing folders,
|
|
// ignore this event.
|
|
//
|
|
if (_psvPending) {
|
|
return;
|
|
}
|
|
|
|
// README:
|
|
// If you need to add events here, then you must change SHELLBROWSER_FSNOTIFY_FLAGS in
|
|
// order to get the notifications
|
|
switch(lEvent)
|
|
{
|
|
case SHCNE_DRIVEADDGUI:
|
|
if (ILIsParent(pidl1, _pidlCur, FALSE)) {
|
|
PostMessage(_hwnd, WM_COMMAND, FCIDM_REFRESH, 0L);
|
|
}
|
|
break;
|
|
|
|
case SHCNE_SERVERDISCONNECT:
|
|
case SHCNE_MEDIAREMOVED:
|
|
fDisconnectAlways = TRUE;
|
|
// fall thru
|
|
|
|
case SHCNE_RMDIR:
|
|
if (g_fRunningOnNT)
|
|
fDisconnectAlways = TRUE;
|
|
// fall thru
|
|
|
|
case SHCNE_UPDATEDIR:
|
|
case SHCNE_NETUNSHARE:
|
|
case SHCNE_DRIVEREMOVED:
|
|
_FSChangeCheckClose(pidl1, fDisconnectAlways);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
void CShellBrowser::_CommonHandleFileSysChange(LONG lEvent, LPITEMIDLIST pidl1, LPITEMIDLIST pidl2)
|
|
{
|
|
v_HandleFileSysChange(lEvent, pidl1, pidl2);
|
|
|
|
if (_psvPending) {
|
|
return;
|
|
}
|
|
|
|
// stuff that needs to be done tree or no tree
|
|
switch (lEvent) {
|
|
|
|
// README:
|
|
// If you need to add events here, then you must change SHELLBROWSER_FSNOTIFY_FLAGS in
|
|
// order to get the notifications
|
|
|
|
case SHCNE_UPDATEITEM:
|
|
// the name could have changed
|
|
if (ILIsEqual(_pidlCur, pidl1))
|
|
_SetTitle(NULL);
|
|
break;
|
|
|
|
case SHCNE_RENAMEFOLDER:
|
|
{
|
|
// the rename might be ourselfs or our parent... if it's
|
|
// our parent, we want to tack on the child idl's from the renamed
|
|
// parent to us onto the new pidl (pidlExtra).
|
|
// then show that result.
|
|
LPITEMIDLIST pidlChild;
|
|
|
|
pidlChild = ILFindChild(pidl1, _pidlCur);
|
|
if (pidlChild) {
|
|
LPITEMIDLIST pidlTarget;
|
|
|
|
pidlTarget = ILCombine(pidl2, pidlChild);
|
|
if (pidlTarget) {
|
|
|
|
if (FAILED(_TryShell2Rename(_psv, pidlTarget))) {
|
|
|
|
LPITEMIDLIST pidlReal = GetFullPidl(pidlTarget);
|
|
|
|
if (pidlReal) {
|
|
BrowseObject(pidlReal, SBSP_REDIRECT | SBSP_SAMEBROWSER);
|
|
|
|
if (pidlReal != pidlTarget) {
|
|
ILFree(pidlReal);
|
|
}
|
|
}
|
|
}
|
|
|
|
ILFree(pidlTarget);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SHCNE_UPDATEIMAGE:
|
|
v_SetIcon();
|
|
break;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Helper Function to see if a pidl is on a network drive which is not
|
|
// persistent. This is useful if we are shuting down and saving a list
|
|
// of the open windows to restore as we won't be able to restore these.
|
|
#define AnsiUpperChar(c) ( (TCHAR)LOWORD(CharUpper((LPTSTR)MAKELONG(c, 0))) )
|
|
|
|
BOOL FPidlOnNonPersistentDrive(LPCITEMIDLIST pidl)
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
HANDLE hEnum;
|
|
BOOL fRet = TRUE;
|
|
|
|
if (!SHGetPathFromIDList(pidl, szPath) || (szPath[0] == TEXT('\0')))
|
|
return(FALSE); // not file system pidl assume ok.
|
|
|
|
if (PathIsUNC(szPath) || !IsNetDrive(DRIVEID(szPath)))
|
|
{
|
|
fRet = FALSE;
|
|
goto End;
|
|
}
|
|
|
|
// Ok we got here so now we have a network drive ...
|
|
// we will have to enumerate over
|
|
//
|
|
if (WNetOpenEnum(RESOURCE_REMEMBERED, RESOURCETYPE_DISK,
|
|
RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED,
|
|
NULL, &hEnum) == WN_SUCCESS)
|
|
{
|
|
DWORD dwCount=1;
|
|
union
|
|
{
|
|
NETRESOURCE nr; // Large stack usage but I
|
|
TCHAR buf[1024]; // Dont think it is thunk to 16 bits...
|
|
}nrb;
|
|
|
|
DWORD dwBufSize = SIZEOF(nrb);
|
|
|
|
while (WNetEnumResource(hEnum, &dwCount, &nrb.buf,
|
|
&dwBufSize) == WN_SUCCESS)
|
|
{
|
|
// We only want to add items if they do not have a local
|
|
// name. If they had a local name we would have already
|
|
// added them!
|
|
if ((nrb.nr.lpLocalName != NULL) &&
|
|
(AnsiUpperChar(*(nrb.nr.lpLocalName)) == AnsiUpperChar(szPath[0])))
|
|
{
|
|
fRet = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
WNetCloseEnum(hEnum);
|
|
}
|
|
|
|
End:
|
|
TraceMsg(DM_TRACE, "c.c_arl: %s, is Persistent? %d", szPath, fRet);
|
|
return(fRet);
|
|
|
|
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Restore all of the window that asked to save a command line to be
|
|
// restarted when windows was exited.
|
|
//
|
|
STDAPI_(BOOL) AddToRestartList(UINT flags, LPCITEMIDLIST pidl)
|
|
{
|
|
// See if this is the first one...
|
|
int cItems;
|
|
TCHAR szSubKey[80];
|
|
BOOL fRet = FALSE;
|
|
DWORD cbData;
|
|
USHORT us;
|
|
LPSTREAM pstm;
|
|
|
|
// If in clean boot mode don't save away the list.
|
|
if (g_fCleanBoot)
|
|
return(FALSE);
|
|
|
|
if (FPidlOnNonPersistentDrive(pidl))
|
|
return FALSE;
|
|
|
|
ASSERT(g_hkeyExplorer);
|
|
|
|
cbData = SIZEOF(cItems);
|
|
|
|
if (ERROR_SUCCESS !=
|
|
_GetRegKeyValue(g_hkeyExplorer, TEXT("RestartCommands"), TEXT("Count"), NULL, (PBYTE)&cItems, &cbData))
|
|
cItems = 0;
|
|
|
|
// Now Lets Create a registry Stream for this guy...
|
|
wsprintf(szSubKey, TEXT("%d"), cItems);
|
|
pstm = OpenRegStream(g_hkeyExplorer, TEXT("RestartCommands"), szSubKey, STGM_WRITE);
|
|
if (pstm)
|
|
{
|
|
// Now Write a preamble to the start of the line that
|
|
// tells us that this is an explorer
|
|
us = (USHORT)-1; // SIZEOF of cmd line == -1 implies pidl...
|
|
pstm->Write(&us, SIZEOF(us), NULL);
|
|
|
|
// Now Write out the version number of this stream
|
|
// Make sure to inc the version number if the structure changes
|
|
pstm->Write(&c_uVersion, SIZEOF(c_uVersion), NULL);
|
|
|
|
// Now Write out the flags
|
|
pstm->Write(&flags, SIZEOF(flags), NULL);
|
|
|
|
// And the root pidl;
|
|
ILSaveToStream(pstm, g_pidlRoot);
|
|
|
|
// And the pidl;
|
|
ILSaveToStream(pstm, ILFindChild(g_pidlRoot, pidl));
|
|
|
|
// And Release the stream;
|
|
pstm->Release();
|
|
|
|
cItems++; // Say that there are twice as many items...
|
|
|
|
fRet = (ERROR_SUCCESS == _SetRegKeyValue(g_hkeyExplorer,
|
|
TEXT("RestartCommands"), TEXT("Count"), REG_BINARY, (LPBYTE)&cItems, SIZEOF(cItems)));
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// returns:
|
|
// TRUE if the user wants to abort the startup sequence
|
|
// FALSE keep going
|
|
//
|
|
// note: this is a switch, once on it will return TRUE to all
|
|
// calls so these keys don't need to be pressed the whole time
|
|
BOOL AbortStartup()
|
|
{
|
|
static BOOL bAborted = FALSE; // static so it sticks!
|
|
|
|
// TraceMsg(DM_TRACE, "Abort Startup?");
|
|
|
|
if (bAborted)
|
|
return TRUE; // don't do funky startup stuff
|
|
else {
|
|
bAborted = (g_fCleanBoot || ((GetAsyncKeyState(VK_CONTROL) < 0) || (GetAsyncKeyState(VK_SHIFT) < 0)));
|
|
return bAborted;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
void _CreateSavedWindows(void)
|
|
{
|
|
// See if this is the first one...
|
|
int cItems;
|
|
TCHAR szName[80];
|
|
DWORD cbData;
|
|
TCHAR szCmdLine[MAX_PATH+1]; // +1 for the first character of c_szShellExecute
|
|
|
|
cbData = SIZEOF(cItems);
|
|
if (ERROR_SUCCESS != _GetRegKeyValue(g_hkeyExplorer, TEXT("RestartCommands"), TEXT("Count"), NULL, (PBYTE)&cItems, &cbData)) {
|
|
return;
|
|
}
|
|
|
|
if (cItems == 0)
|
|
return; // nothing to do
|
|
|
|
// Restart in the reverse order that they were added.
|
|
while (cItems--)
|
|
{
|
|
LPSTREAM pstm;
|
|
USHORT us;
|
|
MSG msg;
|
|
|
|
wsprintf(szName, TEXT("%d"), cItems);
|
|
if (AbortStartup())
|
|
break;
|
|
|
|
// This is a semi hack but we want to process any of the messages
|
|
// we get back from the hook for any new windows we create as to
|
|
// not overlflow our maximum limit... We know that it is a
|
|
// registered message so only process those messages...
|
|
while (PeekMessage(&msg, NULL, 0xc000, 0xffff, PM_REMOVE))
|
|
{
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
pstm = OpenRegStream(g_hkeyExplorer, TEXT("RestartCommands"), szName, STGM_READ);
|
|
if (pstm)
|
|
{
|
|
// Now Write a preamble to the start of the line that
|
|
// tells us that this is an explorer
|
|
if (FAILED(pstm->Read(&us, SIZEOF(us), NULL)))
|
|
goto Error1; // try the next one...
|
|
|
|
if (us == (USHORT)-1)
|
|
{
|
|
UINT flags;
|
|
LPITEMIDLIST pidl;
|
|
LPITEMIDLIST pidlRoot;
|
|
USHORT version;
|
|
|
|
// We have a folder serialized so get version, flags, pidlRoot,
|
|
// and pidl;
|
|
// Now Read the version
|
|
if (FAILED(pstm->Read(&version, SIZEOF(version), NULL))
|
|
|| version != c_uVersion)
|
|
{
|
|
goto Error1;
|
|
}
|
|
|
|
// Now Write out the flags
|
|
pstm->Read(&flags, SIZEOF(flags), NULL);
|
|
|
|
// And the root pidl;
|
|
pidl = NULL; // Load will try to free non null values...
|
|
if (FAILED(ILLoadFromStream(pstm, &pidl)) || (pidl == NULL))
|
|
goto Error1;
|
|
|
|
if (ILIsEmpty(pidl))
|
|
{
|
|
pidlRoot = NULL;
|
|
}
|
|
else
|
|
{
|
|
pidlRoot = ILGlobalClone(pidl);
|
|
if (!pidlRoot)
|
|
{
|
|
goto Error2;
|
|
}
|
|
}
|
|
ILFree(pidl);
|
|
|
|
// And the pidl;
|
|
pidl = NULL; // Load will try to free non null values...
|
|
if (FAILED(ILLoadFromStream(pstm, &pidl)) || (pidl == NULL))
|
|
goto Error2;
|
|
|
|
if (pidlRoot)
|
|
{
|
|
SHELLEXECUTEINFO ei;
|
|
TCHAR szExplorer[MAX_PATH];
|
|
HANDLE hIdList;
|
|
HANDLE hIdListRoot;
|
|
|
|
hIdList = SHAllocShared(pidl,ILGetSize(pidl),GetCurrentProcessId());
|
|
hIdListRoot = SHAllocShared(pidlRoot,ILGetSize(pidlRoot),GetCurrentProcessId());
|
|
|
|
if (hIdList && hIdListRoot)
|
|
{
|
|
|
|
// This should not fail
|
|
GetModuleFileName(NULL, szExplorer, ARRAYSIZE(szExplorer));
|
|
|
|
// We need a new instance of the Cabinet; this may be a
|
|
// little slow, but what can I do?
|
|
|
|
wsprintf(szCmdLine, c_szOpenIDL, hIdList, GetCurrentProcessId(),
|
|
hIdListRoot, GetCurrentProcessId());
|
|
|
|
if (flags & COF_EXPLORE)
|
|
{
|
|
lstrcat(szCmdLine, c_szExploreIDL);
|
|
}
|
|
|
|
FillExecInfo(ei, NULL, NULL, szExplorer, szCmdLine,
|
|
NULL, SW_SHOWNORMAL);
|
|
if (ShellExecuteEx(&ei))
|
|
{
|
|
// These are now owned by the new instance
|
|
hIdList = NULL;
|
|
hIdListRoot = NULL;
|
|
}
|
|
}
|
|
|
|
if (hIdList)
|
|
SHFreeShared(hIdList,GetCurrentProcessId());
|
|
if (hIdListRoot)
|
|
SHFreeShared(hIdListRoot,GetCurrentProcessId());
|
|
}
|
|
else
|
|
{
|
|
// If we are a folder and there is already a folder open
|
|
// on this pidl, blow it off, as we need to handle the case
|
|
// where a user puts a link to a folder in the startup group
|
|
// which opens fine the first time, but if they don't close
|
|
// it we will restore that window and also have the window
|
|
// from the startup group.
|
|
//
|
|
IETHREADPARAM* piei = new IETHREADPARAM();
|
|
if (piei) {
|
|
piei->pidl = ILClone(pidl);
|
|
piei->uFlags = flags;
|
|
piei->nCmdShow = SW_SHOWDEFAULT;
|
|
OpenFolderWindow(piei);
|
|
delete piei;
|
|
}
|
|
}
|
|
|
|
Error2:
|
|
if (pidlRoot)
|
|
{
|
|
ILGlobalFree(pidlRoot);
|
|
}
|
|
if (pidl)
|
|
{
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
else if (us < MAX_PATH)
|
|
{
|
|
CHAR aszScratch[MAX_PATH];
|
|
pstm->Read(aszScratch, us, NULL);
|
|
WinExec(aszScratch, SW_SHOWNORMAL); // the show cmd will be ignored
|
|
}
|
|
|
|
Error1:
|
|
pstm->Release();
|
|
}
|
|
}
|
|
|
|
SHDeleteKey(g_hkeyExplorer, TEXT("RestartCommands"));
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// 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 CShellBrowser::v_OnContextMenu(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BOOL fProcessed = FALSE;
|
|
|
|
TraceMsg(DM_TRACE, "CABWND.C Got WM_CONTEXTMENU");
|
|
|
|
if (_pidlCur && !ILIsEmpty(_pidlCur) && SendMessage(_hwnd, WM_NCHITTEST, 0, lParam) == HTSYSMENU)
|
|
{
|
|
IShellFolder *psfParent;
|
|
LPCITEMIDLIST pidlChild;
|
|
|
|
if (SUCCEEDED(BindToParentFolder(_pidlCur, &psfParent, &pidlChild)))
|
|
{
|
|
IContextMenu * pcm;
|
|
HRESULT hres = psfParent->GetUIObjectOf(_hwnd, 1, (LPCITEMIDLIST*)&pidlChild, IID_IContextMenu, NULL, (LPVOID*)&pcm);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
HMENU hpopup = LoadMenuPopup(MENU_SYSPOPUP);
|
|
if (hpopup)
|
|
{
|
|
UINT idCmd;
|
|
UINT ipos;
|
|
UINT citems = GetMenuItemCount(hpopup);
|
|
pcm->QueryContextMenu(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->GetCommandString(
|
|
idCmd-IDSYSPOPUP_FIRST,
|
|
GCS_VERB,
|
|
NULL,
|
|
(LPSTR)szVerb,
|
|
ARRAYSIZE(szVerb));
|
|
#ifdef UNICODE
|
|
if (FAILED(hres) || *szVerb == TEXT('\0'))
|
|
{
|
|
CHAR szVerbAnsi[40];
|
|
|
|
hres = pcm->GetCommandString(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,TEXT("open"))==0)
|
|
{
|
|
DeleteMenu(hpopup, ipos, MF_BYPOSITION);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// For sendto menu, we go on even if this fails
|
|
pcm->QueryInterface(IID_IContextMenu2, (LPVOID *)&_pcmSendTo);
|
|
|
|
idCmd = TrackPopupMenu(hpopup,
|
|
TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
|
|
GET_X_LPARAM(lParam),
|
|
GET_Y_LPARAM(lParam),
|
|
0, _hwnd, NULL);
|
|
|
|
switch(idCmd)
|
|
{
|
|
case 0:
|
|
break; // canceled
|
|
|
|
case IDSYSPOPUP_CLOSE:
|
|
_pautoWB2->Quit();
|
|
break;
|
|
|
|
default:
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
CMINVOKECOMMANDINFOEX ici = {
|
|
SIZEOF(CMINVOKECOMMANDINFOEX),
|
|
0L,
|
|
_hwnd,
|
|
(LPSTR)MAKEINTRESOURCE(idCmd - IDSYSPOPUP_FIRST),
|
|
NULL,
|
|
NULL,
|
|
SW_NORMAL,
|
|
};
|
|
#ifdef UNICODE
|
|
CHAR szPathAnsi[MAX_PATH];
|
|
SHGetPathFromIDListA(_pidlCur, szPathAnsi);
|
|
SHGetPathFromIDList(_pidlCur, szPath);
|
|
ici.lpDirectory = szPathAnsi;
|
|
ici.lpDirectoryW = szPath;
|
|
ici.fMask |= CMIC_MASK_UNICODE;
|
|
#else
|
|
SHGetPathFromIDList(_pidlCur, szPath);
|
|
ici.lpDirectory = szPath;
|
|
#endif
|
|
pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_pcmSendTo)
|
|
ATOMICRELEASE(_pcmSendTo);
|
|
DestroyMenu(hpopup);
|
|
}
|
|
pcm->Release();
|
|
}
|
|
psfParent->Release();
|
|
|
|
fProcessed=TRUE;
|
|
}
|
|
}
|
|
return fProcessed;
|
|
}
|
|
|
|
|
|
void CShellBrowser::_OnClose()
|
|
{
|
|
// We are not supposed to process WM_CLOSE if modeless operation is
|
|
// disabled.
|
|
if (_fDisableModeless()) {
|
|
TraceMsg(DM_ERROR, "CShellBrowser::_OnClose called when _fDisableModeless() is TRUE. Ignored.");
|
|
MessageBeep(0);
|
|
return;
|
|
}
|
|
|
|
// we cannot close in the middle of creating view window.
|
|
// someone dispatched messages and it wasn't us...
|
|
// we WILL fault.
|
|
// bugbug: after ie3, we can flag this and close when we're done tryingto create the
|
|
// viewwindow
|
|
if (_fCreatingViewWindow)
|
|
return;
|
|
|
|
if (_MaySaveChanges() != S_FALSE)
|
|
{
|
|
// Close the browse context and release it.
|
|
IHlinkBrowseContext * phlbc = NULL;
|
|
|
|
if (_phlf)
|
|
_phlf->GetBrowseContext(&phlbc);
|
|
|
|
if (phlbc) {
|
|
_phlf->SetBrowseContext(NULL);
|
|
phlbc->Close(0);
|
|
phlbc->Release();
|
|
}
|
|
|
|
FireEvent_Quit(_pautoEDS);
|
|
|
|
// this is once we KNOW that we're going to close down
|
|
// give subclasses a chance to clean up
|
|
_OnConfirmedClose();
|
|
}
|
|
}
|
|
|
|
//
|
|
// stolen from comctl32
|
|
//
|
|
// in:
|
|
// hwnd to do check on
|
|
// x, y in client coordinates
|
|
//
|
|
// returns:
|
|
// TRUE the user began to drag (moved mouse outside double click rect)
|
|
// FALSE mouse came up inside click rect
|
|
//
|
|
// BUGBUG, should support VK_ESCAPE to cancel
|
|
|
|
BOOL CheckForDragBegin(HWND hwnd, int x, int y)
|
|
{
|
|
RECT rc;
|
|
int dxClickRect = GetSystemMetrics(SM_CXDRAG);
|
|
int dyClickRect = GetSystemMetrics(SM_CYDRAG);
|
|
|
|
ASSERT((dxClickRect > 1) && (dyClickRect > 1));
|
|
|
|
// See if the user moves a certain number of pixels in any direction
|
|
|
|
SetRect(&rc, x - dxClickRect, y - dyClickRect, x + dxClickRect, y + dyClickRect);
|
|
|
|
MapWindowRect(hwnd, NULL, &rc);
|
|
|
|
SetCapture(hwnd);
|
|
|
|
do
|
|
{
|
|
MSG msg;
|
|
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
// See if the application wants to process the message...
|
|
if (CallMsgFilter(&msg, MSGF_COMMCTRL_BEGINDRAG) != 0)
|
|
continue;
|
|
|
|
switch (msg.message) {
|
|
case WM_LBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
ReleaseCapture();
|
|
return FALSE;
|
|
|
|
case WM_MOUSEMOVE:
|
|
if (!PtInRect(&rc, msg.pt))
|
|
{
|
|
ReleaseCapture();
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// WM_CANCELMODE messages will unset the capture, in that
|
|
// case I want to exit this loop
|
|
} while (GetCapture() == hwnd);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT _SetPreferedDropEffect(IDataObject *pdtobj, DWORD dwEffect)
|
|
{
|
|
HRESULT hres = E_OUTOFMEMORY;
|
|
DWORD *pdw = (DWORD *)GlobalAlloc(GPTR, sizeof(DWORD));
|
|
if (pdw)
|
|
{
|
|
STGMEDIUM medium;
|
|
FORMATETC fmte = { RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT),
|
|
NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
|
|
*pdw = dwEffect;
|
|
|
|
medium.tymed = TYMED_HGLOBAL;
|
|
medium.hGlobal = pdw;
|
|
medium.pUnkForRelease = NULL;
|
|
|
|
hres = pdtobj->SetData(&fmte, &medium, TRUE);
|
|
|
|
if (FAILED(hres))
|
|
GlobalFree((HGLOBAL)pdw);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
BOOL CShellBrowser::_OnSysMenuClick(BOOL bLeftClick, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
|
DWORD dwStart = GetTickCount();
|
|
|
|
MapWindowPoints(NULL, _hwnd, &pt, 1);
|
|
|
|
if (!CheckForDragBegin(_hwnd, pt.x, pt.y))
|
|
{
|
|
if (bLeftClick)
|
|
{
|
|
DWORD dwDelta = (GetTickCount() - dwStart);
|
|
DWORD dwDblClick = GetDoubleClickTime();
|
|
|
|
if (dwDelta < dwDblClick)
|
|
{
|
|
// HACK: use the lParam (coords) as the timer ID to communicate
|
|
// that to the WM_TIMER handler
|
|
//
|
|
// HACK: store the timer id in a global. Since there's only one
|
|
// double-click on a sysmenu at a time, this should be fine.
|
|
if (g_sysmenuTimer)
|
|
KillTimer(_hwnd, g_sysmenuTimer);
|
|
g_sysmenuTimer = SetTimer(_hwnd, lParam, dwDblClick - dwDelta, NULL);
|
|
}
|
|
else
|
|
DefWindowProc(_hwnd, WM_CONTEXTMENU, (WPARAM)_hwnd, lParam);
|
|
}
|
|
else
|
|
SendMessage(_hwnd, WM_CONTEXTMENU, (WPARAM)_hwnd, lParam);
|
|
return FALSE;
|
|
}
|
|
|
|
IShellFolder *psfParent;
|
|
LPCITEMIDLIST pidlChild;
|
|
|
|
if (SUCCEEDED(BindToParentFolder(_pidlCur, &psfParent, &pidlChild)))
|
|
{
|
|
HRESULT hres;
|
|
IDataObject *pdtobj;
|
|
LPTSTR pszFile = NULL;
|
|
DWORD dwAttrib = SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR |
|
|
DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK;
|
|
|
|
psfParent->GetAttributesOf(1, &pidlChild, &dwAttrib);
|
|
|
|
hres = psfParent->GetUIObjectOf(NULL, 1, &pidlChild, IID_IDataObject, NULL, (void**)&pdtobj);
|
|
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
DWORD dwEffect = (DROPEFFECT_MOVE | DROPEFFECT_COPY | DROPEFFECT_LINK) & dwAttrib;
|
|
|
|
ASSERT(dwEffect);
|
|
|
|
_SetPreferedDropEffect(pdtobj, DROPEFFECT_LINK);
|
|
|
|
SHDoDragDrop(_hwnd, pdtobj, NULL, dwEffect, &dwEffect);
|
|
|
|
pdtobj->Release();
|
|
}
|
|
|
|
psfParent->Release();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT CShellBrowser::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg)
|
|
{
|
|
case CWM_CLONEPIDL:
|
|
if (_pidlCur)
|
|
{
|
|
return(LRESULT)SHAllocShared(_pidlCur,
|
|
ILGetSize(_pidlCur),
|
|
wParam);
|
|
}
|
|
break;
|
|
|
|
case CWM_SELECTITEM:
|
|
{
|
|
LPITEMIDLIST pidl = (LPITEMIDLIST)SHLockShared((HANDLE)lParam, GetCurrentProcessId());
|
|
if (pidl)
|
|
{
|
|
if (_psv)
|
|
_psv->SelectItem(pidl, wParam);
|
|
SHUnlockShared(pidl);
|
|
}
|
|
SHFreeShared((HANDLE)lParam, GetCurrentProcessId()); // Receiver responsible for freeing
|
|
break;
|
|
}
|
|
|
|
case CWM_GLOBALSTATECHANGE:
|
|
// need to update the title
|
|
_SetTitle(NULL);
|
|
break;
|
|
|
|
|
|
case CWM_FSNOTIFY:
|
|
_OnFSNotify(wParam, lParam);
|
|
break;
|
|
|
|
case CWM_SHOWDRAGIMAGE:
|
|
return DAD_ShowDragImage((BOOL)lParam);
|
|
|
|
case WMC_FAV_CHANGE:
|
|
TraceMsg(0, "ief WndProc got WMC_FAV_CHANGE");
|
|
_OnFavsChanged(wParam, lParam);
|
|
break;
|
|
|
|
case WM_ENDSESSION:
|
|
if (wParam && !SHRestricted(REST_NOSAVESET) &&
|
|
IsWindowVisible(_hwnd) && _pidlCur)
|
|
{
|
|
AddToRestartList(v_RestartFlags(), _pidlCur);
|
|
}
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
if (g_sysmenuTimer)
|
|
{
|
|
KillTimer(_hwnd, g_sysmenuTimer);
|
|
g_sysmenuTimer = 0;
|
|
}
|
|
// the timer ID is the lParam from the left click!
|
|
SendMessage(_hwnd, WM_SYSMENU, 0, wParam);
|
|
break;
|
|
|
|
case WM_NCLBUTTONDOWN:
|
|
case WM_NCRBUTTONDOWN:
|
|
if (wParam != HTSYSMENU)
|
|
goto DoDefault;
|
|
|
|
_OnSysMenuClick(uMsg == WM_NCLBUTTONDOWN, wParam, lParam);
|
|
break;
|
|
|
|
case WM_NCLBUTTONDBLCLK:
|
|
// We fault while shutting down the window if the timing is bad.
|
|
// We're not sure why, but USER get's mightily confused. The only
|
|
// difference between this scheme and a normal double-click-on-sysmenu
|
|
// is the timer we have hanging around. Kill the timer before
|
|
// processing this message. Hopefully that will work [mikesh/cheechew]
|
|
//
|
|
// HACK: remember this timer id is stored in a global variable
|
|
//
|
|
if (g_sysmenuTimer)
|
|
{
|
|
KillTimer(_hwnd, g_sysmenuTimer);
|
|
g_sysmenuTimer = 0;
|
|
}
|
|
|
|
// We still want to process this DBLCLK
|
|
goto DoDefault;
|
|
|
|
case WM_CONTEXTMENU:
|
|
if (!v_OnContextMenu(wParam, lParam))
|
|
goto DoDefault;
|
|
break;
|
|
|
|
case WM_INITMENUPOPUP:
|
|
v_OnInitMenuPopup((HMENU)wParam, LOWORD(lParam), HIWORD(lParam));
|
|
v_ForwardMenuMsg(uMsg, wParam, lParam);
|
|
break;
|
|
|
|
case WM_MENUSELECT:
|
|
if (_ShouldForwardMenu(uMsg, wParam, lParam))
|
|
{
|
|
_ForwardViewMsg(uMsg, wParam, lParam);
|
|
}
|
|
else if (!_OnMenuSelect(wParam, lParam, 0))
|
|
{
|
|
if ((GET_WM_MENUSELECT_FLAGS(wParam, lParam)&MF_POPUP)
|
|
|| IsInRange(LOWORD(wParam), FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST))
|
|
{
|
|
_ForwardViewMsg(uMsg, wParam, lParam);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_EXITMENULOOP:
|
|
case WM_ENTERMENULOOP:
|
|
_ForwardViewMsg(uMsg, wParam, lParam);
|
|
break;
|
|
|
|
case WM_DRAWITEM:
|
|
if (!_FavoritesHandleDrawItem((LPDRAWITEMSTRUCT)lParam))
|
|
{
|
|
//ASSERT(_pcmSendTo);
|
|
if (!(_pcmSendTo && (_pcmSendTo->HandleMenuMsg(uMsg, wParam, lParam) == NOERROR)))
|
|
v_ForwardMenuMsg(uMsg, wParam, lParam);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
case WM_MEASUREITEM:
|
|
if (!_FavoritesHandleMeasureItem((LPMEASUREITEMSTRUCT)lParam))
|
|
{
|
|
//ASSERT(_pcmSendTo);
|
|
if (!(_pcmSendTo && (_pcmSendTo->HandleMenuMsg(uMsg, wParam, lParam) == NOERROR)))
|
|
v_ForwardMenuMsg(uMsg, wParam, lParam);
|
|
}
|
|
return TRUE;
|
|
case WM_CLOSE:
|
|
#if !defined(_X86_)
|
|
// On risc NT we need to call CoFreeUnusedLibraries in case any x86 dlls
|
|
// were loaded by Ole32.
|
|
CoFreeUnusedLibraries();
|
|
#endif
|
|
_OnClose();
|
|
break;
|
|
|
|
case WM_SYSCOMMAND:
|
|
switch (wParam) {
|
|
case FCIDM_VIEWTOOLBAR:
|
|
case FCIDM_VIEWSTATUSBAR:
|
|
_OnCommand(wParam, lParam);
|
|
break;
|
|
|
|
default:
|
|
goto DoDefault;
|
|
}
|
|
break;
|
|
|
|
case WM_MENUCHAR:
|
|
{
|
|
LRESULT lres;
|
|
if (_FavoritesHandleMenuChar((HMENU)lParam, (TCHAR)LOWORD(wParam) , &lres))
|
|
return lres;
|
|
}
|
|
break;
|
|
|
|
case WMC_MARSHALIDISPATCH:
|
|
HRESULT hres;
|
|
|
|
_fMarshalledDispatch = TRUE;
|
|
hres = CoMarshalInterface((IStream *)lParam, IID_IDispatch,
|
|
_pautoWB2, MSHCTX_NOSHAREDMEM, NULL, MSHLFLAGS_NORMAL);
|
|
ASSERT(SUCCEEDED(hres));
|
|
return (SUCCEEDED(hres));
|
|
|
|
default:
|
|
|
|
DoDefault:
|
|
return SUPERCLASS::WndProc(uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
LRESULT CALLBACK IEFrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CShellBrowser* psb = (CShellBrowser*)GetWindowLong(hwnd, 0);
|
|
|
|
switch(uMsg)
|
|
{
|
|
case WM_NCCREATE:
|
|
{
|
|
IETHREADPARAM* piei = (IETHREADPARAM*)((LPCREATESTRUCT)lParam)->lpCreateParams;
|
|
|
|
ASSERT(psb == NULL);
|
|
if (piei->uFlags & COF_EXPLORE)
|
|
{
|
|
CExplorerBrowser_CreateInstance(hwnd, (LPVOID*)&psb);
|
|
}
|
|
else
|
|
{
|
|
CShellBrowser_CreateInstance(hwnd, (LPVOID*)&psb);
|
|
}
|
|
|
|
if (psb)
|
|
{
|
|
SetWindowLong(hwnd, 0, (LONG)psb);
|
|
|
|
//
|
|
// Tell IEDDE that a new browser window is available.
|
|
//
|
|
IEDDE_NewWindow(hwnd);
|
|
}
|
|
|
|
return (LRESULT)psb;
|
|
}
|
|
|
|
case WM_NCDESTROY:
|
|
|
|
//
|
|
// Tell IEDDE that a browser window is no longer available.
|
|
//
|
|
IEDDE_WindowDestroyed(hwnd);
|
|
|
|
// WM_NCDESTROY is supposed to be the last message we ever
|
|
// receive, but let's be paranoid just in case...
|
|
SetWindowLong(hwnd, 0, (LONG)NULL);
|
|
|
|
if (psb) {
|
|
psb->_hwnd = NULL;
|
|
if (psb->_dwRegisterWinList)
|
|
{
|
|
if (psb->_fMarshalledDispatch)
|
|
{
|
|
IShellWindows* psw = WinList_GetShellWindows(TRUE);
|
|
if (psw)
|
|
{
|
|
psw->Revoke(psb->_dwRegisterWinList);
|
|
psw->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (psb->_psw)
|
|
psb->_psw->Revoke(psb->_dwRegisterWinList);
|
|
}
|
|
}
|
|
if (psb->_psw)
|
|
ATOMICRELEASE(psb->_psw);
|
|
psb->_fMarshalledDispatch = 0;
|
|
psb->_dwRegisterWinList = 0;
|
|
psb->Release();
|
|
}
|
|
|
|
if (g_tidParking != GetCurrentThreadId())
|
|
{
|
|
PostQuitMessage(0); // Terminate the thread.
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return psb ? psb->WndProc(uMsg, wParam, lParam) : DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// *** IShellBrowser methods *** (same as IOleInPlaceFrame)
|
|
|
|
HRESULT CShellBrowser::InsertMenusSB(HMENU hmenu, LPOLEMENUGROUPWIDTHS lpMenuWidths)
|
|
{
|
|
if (_hmenuTemplate) {
|
|
Shell_MergeMenus(hmenu, (_itbLastFocus == ITB_VIEW ) ? _hmenuTemplate : _hmenuFull, 0, 0, FCIDM_BROWSERLAST, MM_SUBMENUSHAVEIDS);
|
|
lpMenuWidths->width[0] = 1; // File
|
|
lpMenuWidths->width[2] = 2; // Edit, View
|
|
lpMenuWidths->width[4] = 1; // Help
|
|
|
|
// we need to save away these menus
|
|
_hmenuHelp = GetSubMenu(hmenu, 3);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CShellBrowser::SetMenuSB(HMENU hmenu, HOLEMENU hmenuRes, HWND hwnd)
|
|
{
|
|
if (hmenu) {
|
|
_hmenuCur = hmenu;
|
|
} else {
|
|
_hmenuCur = _hmenuTemplate;
|
|
}
|
|
_fTryHelpMenuMerge = FALSE;
|
|
_fForwardMenu = FALSE;
|
|
|
|
if (!_fFullScreen)
|
|
{
|
|
if (_fShowMenu)
|
|
SetMenu(_hwnd, _hmenuCur);
|
|
else
|
|
SetMenu(_hwnd, NULL);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Remove menus that are shared with other menus from
|
|
the given browser menu.
|
|
|
|
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
HRESULT CShellBrowser::RemoveMenusSB(HMENU hmenuShared)
|
|
{
|
|
// Generally, there is no need to remove most of the menus because
|
|
// they were cloned and inserted into this menu. However, the
|
|
// Favorites menu is an exception because it is shared with
|
|
// _hmenuFav.
|
|
|
|
HMENU hmenu = GetMenuFromID(hmenuShared, FCIDM_MENU_FAVORITES);
|
|
if (hmenu)
|
|
{
|
|
int cItems = GetMenuItemCount(hmenu);
|
|
int i;
|
|
|
|
for (i=cItems-1; i>=0; i--)
|
|
{
|
|
if (GetSubMenu(hmenu, i))
|
|
RemoveMenu(hmenu, i, MF_BYPOSITION);
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CShellBrowser::GetControlWindow(UINT id, HWND * lphwnd)
|
|
{
|
|
// the defaults
|
|
HRESULT hres = E_FAIL;
|
|
*lphwnd = NULL;
|
|
|
|
switch (id)
|
|
{
|
|
case FCW_INTERNETBAR:
|
|
if (_GetITBar() && _aTBar[ITB_ITBAR].fShow)
|
|
hres = _GetITBar()->GetWindow(lphwnd);
|
|
break;
|
|
|
|
case FCW_TOOLBAR:
|
|
*lphwnd = _hwndDummyTB;
|
|
break;
|
|
|
|
case FCW_STATUS:
|
|
*lphwnd = _hwndStatus;
|
|
break;
|
|
}
|
|
|
|
if (*lphwnd) {
|
|
hres = S_OK;
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
// the dwData holds the index for bitmap offsets
|
|
const TBBUTTON c_tbExplorer[] = {
|
|
// FCIDM_DRIVELIST iBitmap is patched up to the real width as we insert it
|
|
// { 0, FCIDM_DRIVELIST, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, TBOFFSET_NONE, -1 },
|
|
// { 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, TBOFFSET_NONE, -1 },
|
|
// { HIST_BACK, FCIDM_NAVIGATEBACK, TBSTATE_ENABLED, (BYTE) TBSTYLE_BUTTON, {0,0}, TBOFFSET_HIST, -1 },
|
|
// { HIST_FORWARD, FCIDM_NAVIGATEFORWARD, TBSTATE_ENABLED, (BYTE) TBSTYLE_BUTTON, {0,0}, TBOFFSET_HIST, -1 },
|
|
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, TBOFFSET_NONE, -1 },
|
|
{ VIEW_PARENTFOLDER, FCIDM_PREVIOUSFOLDER, TBSTATE_ENABLED, (BYTE) TBSTYLE_BUTTON, {0,0}, TBOFFSET_VIEW, -1 },
|
|
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, TBOFFSET_NONE, -1 },
|
|
{ HIST_VIEWTREE, FCIDM_VIEWTREE, TBSTATE_ENABLED, (BYTE) TBSTYLE_CHECK, {0,0}, TBOFFSET_HIST, -1 },
|
|
{ 0, 0, TBSTATE_ENABLED, TBSTYLE_SEP, {0,0}, TBOFFSET_NONE, -1 },
|
|
};
|
|
|
|
BOOL CShellBrowser::v_PreprocessButtonInfo(LPTBBUTTON pbtn)
|
|
{
|
|
switch (pbtn->idCommand) {
|
|
|
|
case FCIDM_VIEWTREE:
|
|
return FALSE;
|
|
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
//==========================================================================
|
|
#define SHELLGLYPHS_OFFSET 15
|
|
HRESULT CShellBrowser::SetToolbarItems(LPTBBUTTON pViewButtons, UINT nButtons,
|
|
UINT uFlags)
|
|
{
|
|
LPTBBUTTON pStart= NULL, pbtn= NULL;
|
|
int nFirstDiff = 0, nTotalButtons = 0;
|
|
BOOL bVisible = FALSE;
|
|
|
|
if (uFlags & FCT_CONFIGABLE)
|
|
{
|
|
return NOERROR;
|
|
}
|
|
|
|
// Allocate buffer for the default buttons plus the ones passed in
|
|
//
|
|
pStart = (LPTBBUTTON)LocalAlloc(LPTR, SIZEOF(c_tbExplorer) + (nButtons * SIZEOF(TBBUTTON)));
|
|
if (!pStart)
|
|
return NOERROR;
|
|
|
|
pbtn = pStart;
|
|
nTotalButtons = 0;
|
|
|
|
if (uFlags & FCT_MERGE)
|
|
{
|
|
int i;
|
|
int iButtonsAdded = 0;
|
|
|
|
// copy buttons (and offset bitmap indexes)
|
|
for (i = 0; i < ARRAYSIZE(c_tbExplorer); i++)
|
|
{
|
|
pbtn[iButtonsAdded] = c_tbExplorer[i];
|
|
if (!v_PreprocessButtonInfo(&pbtn[iButtonsAdded])) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
switch (pbtn[iButtonsAdded].dwData)
|
|
{
|
|
case TBOFFSET_NONE:
|
|
break;
|
|
|
|
case TBOFFSET_HIST:
|
|
pbtn[iButtonsAdded].iBitmap += SHELLGLYPHS_OFFSET;
|
|
break;
|
|
|
|
case TBOFFSET_STD:
|
|
pbtn[iButtonsAdded].iBitmap += SHELLGLYPHS_OFFSET + HIST_MAX;
|
|
break;
|
|
|
|
case TBOFFSET_VIEW:
|
|
pbtn[iButtonsAdded].iBitmap += SHELLGLYPHS_OFFSET + HIST_MAX + STD_MAX;
|
|
break;
|
|
}
|
|
iButtonsAdded++;
|
|
}
|
|
|
|
pbtn += iButtonsAdded;
|
|
nTotalButtons += iButtonsAdded;
|
|
}
|
|
|
|
if (pViewButtons)
|
|
{
|
|
int i;
|
|
for (i = nButtons - 1; i >= 0; --i)
|
|
{
|
|
// copy in the callers buttons
|
|
//
|
|
pbtn[i] = pViewButtons[i];
|
|
|
|
}
|
|
|
|
pbtn += nButtons;
|
|
nTotalButtons += nButtons;
|
|
}
|
|
|
|
|
|
if (_pxtb)
|
|
{
|
|
DWORD dwFlags = VBF_TOOLS | VBF_ADDRESS;
|
|
TCHAR szScratch[32];
|
|
|
|
if (_nTBTextRows == -1) {
|
|
if (LoadString(HINST_THISDLL, IDS_SHELL_TB_TEXTROWS, szScratch, ARRAYSIZE(szScratch)))
|
|
_nTBTextRows = (UINT)StrToInt(szScratch);
|
|
else
|
|
_nTBTextRows = 0;
|
|
}
|
|
|
|
if (_nTBTextRows == 1)
|
|
dwFlags |= VBF_ONELINETEXT;
|
|
else if (_nTBTextRows == 2)
|
|
dwFlags |= VBF_TWOLINESTEXT;
|
|
|
|
_pxtb->SetCommandTarget((IUnknown *)SAFECAST(this, IOleCommandTarget *), &CGID_ShellBrowser, dwFlags);
|
|
if (_lpPendingBtns)
|
|
LocalFree(_lpPendingBtns );
|
|
_lpPendingBtns = (TBBUTTON*)pStart;
|
|
_nButtonsPending = nTotalButtons;
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
BOOL CShellBrowser::v_MayTranslateAccelerator(MSG* pmsg)
|
|
{
|
|
if (!(WM_KEYFIRST <= pmsg->message && pmsg->message < WM_KEYLAST)) {
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL fToolbarHasFocus = _HasToolbarFocus();
|
|
|
|
if (fToolbarHasFocus)
|
|
{
|
|
ASSERT(_itbLastFocus < ITB_MAX);
|
|
// toolbar has focus -- give it first chance to translate
|
|
//
|
|
// Notes:
|
|
// Notice that we don't give a chance to translate its accelerators
|
|
// to other toolbars. This is by-design right now. We might want to
|
|
// change it later, but it will be tricky to do it right.
|
|
//
|
|
if (UnkTranslateAcceleratorIO(_aTBar[_itbLastFocus].ptbar, pmsg) == S_OK) {
|
|
TraceMsg(DM_ACCELERATOR, "CSB::v_MayTA a bar(%d) (focused) translated %x,%x",
|
|
_itbLastFocus, pmsg->message, pmsg->wParam);
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: used 1st-chance tb %d"), _itbLastFocus);
|
|
return(TRUE);
|
|
}
|
|
if (pmsg->message == WM_KEYDOWN)
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: passed 1st-chance tb %d"), _itbLastFocus);
|
|
} else {
|
|
if (_itbLastFocus != ITB_VIEW) {
|
|
// view got focus back, update cache
|
|
_FixToolbarFocus();
|
|
}
|
|
|
|
// view has focus -- give it first chance to translate
|
|
if (_psv && _psv->TranslateAccelerator(pmsg) == NOERROR) {
|
|
TraceMsg(DM_ACCELERATOR, "CSB::v_MayTA View (focus) translated %x,%x",
|
|
pmsg->message, pmsg->wParam);
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: used 1st-chance view (tb'=%d)"), _itbLastFocus);
|
|
return TRUE;
|
|
}
|
|
if (pmsg->message == WM_KEYDOWN)
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: passed 1st-chance view (tb'=%d)"), _itbLastFocus);
|
|
}
|
|
|
|
// Then, handle our own accelerators (with special code for TAB key).
|
|
BOOL fTabKey = FALSE;
|
|
if (pmsg->message == WM_KEYDOWN) {
|
|
|
|
switch (pmsg->wParam) {
|
|
case VK_TAB:
|
|
// _CycleFocus returns TRUE if we are cycling within ourself.
|
|
TraceMsg(DM_ACCELERATOR, "CSB::v_MayTA calling _CycleFocus for %x,%x",
|
|
pmsg->message, pmsg->wParam);
|
|
if (_CycleFocus(pmsg) == S_OK) {
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: used 2nd-chance self"));
|
|
return TRUE;
|
|
}
|
|
TraceMsg(TF_SHDUIACTIVATE, "CSB::v_MayTranslateAccelerator _CycleFocus returned FALSE");
|
|
fTabKey = TRUE;
|
|
break;
|
|
|
|
case VK_F4:
|
|
// special case the f4 key for back compat. even if the toolbar doesn't have focus,
|
|
// f4 gives it focus and drops it down
|
|
if (UnkTranslateAcceleratorIO(_aTBar[ITB_ITBAR].ptbar, pmsg) == S_OK)
|
|
return TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fTabKey && _hacc && ::TranslateAccelerator(_hwnd, _hacc, pmsg)) {
|
|
TraceMsg(DM_ACCELERATOR, "CSB::v_MayTA TA(_hacc) ate %x,%x",
|
|
pmsg->message, pmsg->wParam);
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: used 2nd-chance ::ta"));
|
|
return TRUE;
|
|
}
|
|
|
|
// If a toolbar has focus, we ask the view last.
|
|
if (fToolbarHasFocus) {
|
|
if (fTabKey) {
|
|
TraceMsg(TF_SHDUIACTIVATE, "CSB::v_MayTranslateAccelerator calling psv->TranslateAccelerator with VK_TAB");
|
|
}
|
|
if (_psv && _psv->TranslateAccelerator(pmsg) == NOERROR) {
|
|
TraceMsg(DM_ACCELERATOR, "CSB::v_MayTA view (nofocus) translated %x,%x",
|
|
pmsg->message, pmsg->wParam);
|
|
if (fTabKey) {
|
|
TraceMsg(TF_SHDUIACTIVATE, "CSB::v_MayTranslateAccelerator calling psv returned NOERROR on VK_TAB");
|
|
}
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: used 3rd-chance view"));
|
|
return TRUE;
|
|
}
|
|
}
|
|
//
|
|
// NOTES: I'm removing this else block because this is bogus. We should not
|
|
// call TranslateAcceleratorST of a toolbar if it does not have a focus.
|
|
// (SatoNa)
|
|
//
|
|
#if 0
|
|
else {
|
|
|
|
// otherwise ask the toolbar last
|
|
if (_itbLastFocus < ITB_MAX &&
|
|
_aTBar[_itbLastFocus].ptbar &&
|
|
UnkTranslateAcceleratorIO(_aTBar[_itbLastFocus].ptbar, pmsg) == S_OK) {
|
|
TraceMsg(DM_ACCELERATOR, "CSB::v_MayTA a bar(%d) (nofocus)ranslated %x,%x",
|
|
_itbLastFocus, pmsg->message, pmsg->wParam);
|
|
DebugMsg(DM_FOCUS, TEXT("csb.ta: used 3rd-chance tb"));
|
|
return(TRUE);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// TraceMsg(DM_ACCELERATOR, "CSB::v_MayTA nobody translated %x,%x", pmsg->message, pmsg->wParam);
|
|
|
|
//DebugMsg(DM_FOCUS, TEXT("csb.ta: (used none)"));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
//---------------------------------------------------------------------------
|
|
// Copy the exception info so we can get debug info for Raised exceptions
|
|
// which don't go through the debugger.
|
|
void _CopyExceptionInfo(LPEXCEPTION_POINTERS pep)
|
|
{
|
|
PEXCEPTION_RECORD per;
|
|
|
|
per = pep->ExceptionRecord;
|
|
TraceMsg(DM_ERROR, "Exception %x at %#08x.", per->ExceptionCode, per->ExceptionAddress);
|
|
|
|
if (per->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
|
{
|
|
// If the first param is 1 then this was a write.
|
|
// If the first param is 0 then this was a read.
|
|
if (per->ExceptionInformation[0])
|
|
{
|
|
TraceMsg(DM_ERROR, "Invalid write to %#08x.", per->ExceptionInformation[1]);
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(DM_ERROR, "Invalid read of %#08x.", per->ExceptionInformation[1]);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
#define _CopyExceptionInfo(x) TRUE
|
|
#endif
|
|
|
|
|
|
// initialize ourselves in the rooted explorer mode.
|
|
// set g_pidlRoot
|
|
// and (in the future) psfDesktop if we are in a separate namespace.
|
|
// if we're in the shell's namespace. psfDesktop stays the shell's psfDesktop.
|
|
//
|
|
// each process is only allowed to set this once. every time afterwards
|
|
// it must be the same.
|
|
// for debugging we verify and assert this is true
|
|
|
|
void InitRoot(IETHREADPARAM* piei)
|
|
{
|
|
static BOOL fInited = FALSE;
|
|
|
|
if (!fInited)
|
|
{
|
|
ENTERCRITICAL;
|
|
if (!fInited)
|
|
{
|
|
fInited = TRUE;
|
|
|
|
// GROSS!
|
|
// if there's a rootclass, the pidlroot is the pidl with witch to initialize
|
|
// the class.
|
|
// if there's no class, then it's a rooted explorer rooted within the shell namespace
|
|
if (piei->uFlags & COF_ROOTCLASS) {
|
|
// if we're initing this, this needs to be the FIRST class initialized!
|
|
ASSERT(!g_psfDesktop);
|
|
InitPSFDesktop(&piei->clsid, piei->pidlRoot);
|
|
|
|
} else {
|
|
|
|
if (piei->pidlRoot) {
|
|
LPITEMIDLIST pidl = ILClone(piei->pidlRoot);
|
|
|
|
ASSERT(pidl);
|
|
if (pidl) {
|
|
g_pidlRoot = pidl;
|
|
}
|
|
}
|
|
|
|
InitPSFDesktop(NULL, NULL);
|
|
}
|
|
}
|
|
LEAVECRITICAL;
|
|
}
|
|
else
|
|
{
|
|
// mirror the above
|
|
if (piei->uFlags & COF_ROOTCLASS) {
|
|
ASSERT(ILIsEqual(g_pidlRootClass, piei->pidlRoot));
|
|
} else if (piei->pidlRoot) {
|
|
ASSERT(ILIsEqual(g_pidlRoot, piei->pidlRoot));
|
|
}
|
|
}
|
|
}
|
|
|
|
#define SVSI_SELFLAGS (SVSI_SELECT|SVSI_FOCUSED|SVSI_DESELECTOTHERS|SVSI_ENSUREVISIBLE)
|
|
|
|
void _BrowserSelectItem(HWND hwnd, UINT uFlags, LPCITEMIDLIST pidlSelect)
|
|
{
|
|
HANDLE hData = SHAllocShared(pidlSelect, ILGetSize(pidlSelect), GetCurrentProcessId());
|
|
|
|
if (hData)
|
|
{
|
|
SendMessage(hwnd, CWM_SELECTITEM, uFlags, (LPARAM)hData);
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::_AfterWindowCreated(IETHREADPARAM *piei)
|
|
{
|
|
|
|
// Let interested people know we are alive
|
|
//
|
|
if (piei->uFlags & COF_SELECT)
|
|
{
|
|
IShellView* psv = _psv;
|
|
|
|
if (!psv)
|
|
psv = _psvPending;
|
|
|
|
if (psv) {
|
|
psv->SelectItem(piei->pidlSelect, SVSI_SELFLAGS);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Keep it hidden if this is the first instance which is started
|
|
// with "/automation" flag or this object is being created as the
|
|
// result of our CreateInstance.
|
|
//
|
|
if (!_fAutomation && !piei->hevent)
|
|
{
|
|
if (_fFullScreen)
|
|
{
|
|
// Turn off flag as we need to let the next function set it...
|
|
_fFullScreen = FALSE;
|
|
|
|
// Hack -1 implies
|
|
ShowControlWindow((UINT)-1, TRUE);
|
|
}
|
|
|
|
MSG msg;
|
|
|
|
// if we have a WM_CLOSE in the queue, then someone called pauto->Quit
|
|
// as we were coming up. we should not show the window because
|
|
// we're only going to shut it down right when we get this close message
|
|
if (!PeekMessage(&msg, _hwnd, WM_CLOSE, WM_CLOSE, PM_NOREMOVE)) {
|
|
ShowWindow(_hwnd, piei->nCmdShow);
|
|
// we need to do this setforegroundwindow
|
|
// because of a bug in user. if the previous thread didn't have
|
|
// activation, ShowWindow will NOT give us activation even though
|
|
// it's supposed to
|
|
switch (piei->nCmdShow) {
|
|
case SW_SHOWNORMAL:
|
|
case SW_SHOWMAXIMIZED:
|
|
case SW_SHOW:
|
|
SetForegroundWindow(_hwnd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
SignalFileOpen(piei->pidl);
|
|
|
|
}
|
|
|
|
LRESULT CALLBACK IEFrameWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
BOOL IsExplorerWindow(HWND hwnd)
|
|
{
|
|
TCHAR szClass[32];
|
|
|
|
GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
|
|
return lstrcmp(szClass, c_szExploreClass) == 0;
|
|
}
|
|
|
|
BOOL IsFolderWindow(HWND hwnd)
|
|
{
|
|
TCHAR szClass[32];
|
|
|
|
GetClassName(hwnd, szClass, ARRAYSIZE(szClass));
|
|
return (lstrcmp(szClass, c_szCabinetClass) == 0) || (lstrcmp(szClass, c_szIExploreClass) == 0);
|
|
}
|
|
|
|
|
|
void InitializeExplorerClass()
|
|
{
|
|
static BOOL fInited = FALSE;
|
|
|
|
if (!fInited)
|
|
{
|
|
ENTERCRITICAL;
|
|
if (!fInited) {
|
|
fInited = TRUE;
|
|
|
|
WNDCLASS wc;
|
|
|
|
ZeroMemory(&wc, SIZEOF(wc));
|
|
wc.style = CS_BYTEALIGNWINDOW;
|
|
wc.lpfnWndProc = IEFrameWndProc;
|
|
//wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = SIZEOF(LPVOID);
|
|
wc.hInstance = HINST_THISDLL;
|
|
wc.hIcon = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(ICO_TREEUP));
|
|
wc.hCursor = LoadCursor(NULL, IDC_SIZEWE);
|
|
//wc.lpszMenuName = NULL;
|
|
wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
|
|
wc.lpszClassName = c_szExploreClass;
|
|
|
|
RegisterClass(&wc);
|
|
|
|
wc.hIcon = LoadIcon(HINST_THISDLL, MAKEINTRESOURCE(IDI_STATE_NORMAL));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
//wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = c_szCabinetClass;
|
|
|
|
RegisterClass(&wc);
|
|
wc.lpszClassName = c_szIExploreClass;
|
|
RegisterClass(&wc);
|
|
|
|
g_hmenuTemplateSB = _MenuTemplate(MENU_TEMPLATE);
|
|
g_hmenuFullSB = _MenuTemplate(MENU_FULL);
|
|
|
|
// HACKHACK:
|
|
// this is to avoid having two menu templates in the resource... one for folder mode
|
|
// and one for explorer mode
|
|
// if we're NOT subclassed, remove this command. we don't support
|
|
// the tree
|
|
|
|
DeleteMenu(g_hmenuTemplateSB, FCIDM_MENU_TOOLS, MF_BYCOMMAND);
|
|
DeleteMenu(g_hmenuFullSB, FCIDM_MENU_TOOLS, MF_BYCOMMAND);
|
|
|
|
HMENU hmenuView = GetMenuFromID(g_hmenuTemplateSB, FCIDM_MENU_VIEW);
|
|
DeleteMenu(hmenuView, FCIDM_VIEWTREE, MF_BYCOMMAND);
|
|
hmenuView = GetMenuFromID(g_hmenuFullSB, FCIDM_MENU_VIEW);
|
|
DeleteMenu(hmenuView, FCIDM_VIEWTREE, MF_BYCOMMAND);
|
|
|
|
|
|
}
|
|
LEAVECRITICAL;
|
|
}
|
|
}
|
|
|
|
void CShellBrowser_Uninitialize(void)
|
|
{
|
|
extern HMENU g_hmenuTemplateExplorer;
|
|
extern HMENU g_hmenuFullExplorer;
|
|
ENTERCRITICAL;
|
|
if (g_hmenuTemplateSB) {
|
|
DestroyMenu(g_hmenuTemplateSB);
|
|
g_hmenuTemplateSB=NULL;
|
|
}
|
|
if (g_hmenuFullSB) {
|
|
DestroyMenu(g_hmenuFullSB);
|
|
g_hmenuFullSB = NULL;
|
|
}
|
|
if (g_hmenuTemplateExplorer) {
|
|
DestroyMenu(g_hmenuTemplateExplorer);
|
|
g_hmenuTemplateExplorer=NULL;
|
|
}
|
|
if (g_hmenuFullExplorer) {
|
|
DestroyMenu(g_hmenuFullExplorer);
|
|
g_hmenuFullExplorer = NULL;
|
|
}
|
|
LEAVECRITICAL;
|
|
}
|
|
|
|
void FileTimeToDateTimeString(LPFILETIME pft, LPTSTR pszBuf, int cchBuf)
|
|
{
|
|
SYSTEMTIME st;
|
|
|
|
FileTimeToLocalFileTime(pft, pft);
|
|
FileTimeToSystemTime(pft, &st);
|
|
|
|
int cch = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuf, cchBuf);
|
|
cchBuf -= cch;
|
|
pszBuf += cch - 1;
|
|
|
|
*pszBuf++ = TEXT(' ');
|
|
*pszBuf = 0; // (in case GetTimeFormat doesn't add anything)
|
|
cchBuf--;
|
|
|
|
GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszBuf, cchBuf);
|
|
}
|
|
|
|
int WELCallback(LPVOID p, LPVOID pData)
|
|
{
|
|
STATURL* pstat = (STATURL*)p;
|
|
if (pstat->pwcsUrl) {
|
|
OleFree(pstat->pwcsUrl);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int _CompareFiletime(FILETIME* pft1, FILETIME* pft2)
|
|
{
|
|
if (pft1->dwHighDateTime < pft2->dwHighDateTime) {
|
|
return 1;
|
|
} else if (pft1->dwHighDateTime > pft2->dwHighDateTime) {
|
|
return -1;
|
|
} else if (pft1->dwLowDateTime < pft2->dwLowDateTime) {
|
|
return 1;
|
|
} else if (pft1->dwLowDateTime > pft2->dwLowDateTime) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int CALLBACK WELCompare(LPVOID p1, LPVOID p2, LPARAM lParam)
|
|
{
|
|
HDSA hdsa = (HDSA)lParam;
|
|
STATURL* pstat1 = (STATURL*)DSA_GetItemPtr(hdsa, (int)p1);
|
|
STATURL* pstat2 = (STATURL*)DSA_GetItemPtr(hdsa, (int)p2);
|
|
if (pstat1 && pstat2) {
|
|
return _CompareFiletime(&pstat1->ftLastVisited, &pstat2->ftLastVisited);
|
|
}
|
|
|
|
ASSERT(0);
|
|
return 0;
|
|
}
|
|
|
|
void IEWriteErrorLog(const EXCEPTION_RECORD* pexr)
|
|
{
|
|
HANDLE hfile = INVALID_HANDLE_VALUE;
|
|
_try
|
|
{
|
|
TCHAR szWindows[MAX_PATH];
|
|
GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
|
|
PathAppend(szWindows, TEXT("IE4 Error Log.txt"));
|
|
HANDLE hfile = CreateFile(szWindows, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if(hfile != INVALID_HANDLE_VALUE)
|
|
{
|
|
const static TCHAR c_szHeader[] = TEXT("Microsoft Internet Explorer 4.0 Error Log -- %d.%d.%d.%d\r\n");
|
|
const static TCHAR c_szCRLF[] = TEXT("\r\n");
|
|
DWORD cbWritten;
|
|
CHAR szBuf[MAX_URL_STRING];
|
|
|
|
// Write the title and product version.
|
|
wsprintf(szBuf, c_szHeader, VER_PRODUCTVERSION);
|
|
WriteFile(hfile, szBuf, lstrlen(szBuf), &cbWritten, NULL);
|
|
|
|
// Write the current time.
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &ft);
|
|
FileTimeToDateTimeString(&ft, szBuf, SIZEOF(szBuf));
|
|
const static TCHAR c_szCurrentTime[] = TEXT("CurrentTime: ");
|
|
WriteFile(hfile, c_szCurrentTime, SIZEOF(c_szCurrentTime)-1, &cbWritten, NULL);
|
|
WriteFile(hfile, szBuf, lstrlen(szBuf), &cbWritten, NULL);
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
|
|
if (pexr) {
|
|
const static TCHAR c_szExcCode[] = TEXT("Exception Info: Code=%x Flags=%x Address=%x\r\n");
|
|
const static TCHAR c_szExcParam[] = TEXT("Exception Param:");
|
|
wsprintf(szBuf, c_szExcCode, pexr->ExceptionCode, pexr->ExceptionFlags, pexr->ExceptionAddress);
|
|
WriteFile(hfile, szBuf, lstrlen(szBuf), &cbWritten, NULL);
|
|
|
|
if (pexr->NumberParameters) {
|
|
WriteFile(hfile, c_szExcParam, SIZEOF(c_szExcParam)-1, &cbWritten, NULL);
|
|
for (UINT iParam=0; iParam<pexr->NumberParameters; iParam++) {
|
|
wsprintf(szBuf, " %x", pexr->ExceptionInformation[iParam]);
|
|
WriteFile(hfile, szBuf, lstrlen(szBuf), &cbWritten, NULL);
|
|
}
|
|
}
|
|
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
}
|
|
|
|
IUrlHistoryStg* pUrlHistStg;
|
|
HRESULT hres = SHCoCreateInstance(NULL, &CLSID_CUrlHistory, NULL,
|
|
IID_IUrlHistoryStg, (LPVOID *)&pUrlHistStg);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
IEnumSTATURL* penum;
|
|
hres = pUrlHistStg->EnumUrls(&penum);
|
|
if (SUCCEEDED(hres)) {
|
|
// Allocate DSA for an array of STATURL
|
|
HDSA hdsa = DSA_Create(SIZEOF(STATURL), 32);
|
|
if (hdsa) {
|
|
// Allocate DPA for sorting
|
|
HDPA hdpa = DPA_Create(32);
|
|
if (hdpa) {
|
|
STATURL stat;
|
|
stat.cbSize = SIZEOF(stat.cbSize);
|
|
while(penum->Next(1, &stat, NULL)==S_OK && stat.pwcsUrl) {
|
|
DSA_AppendItem(hdsa, &stat);
|
|
DPA_AppendPtr(hdpa, (LPVOID)(DSA_GetItemCount(hdsa)-1));
|
|
}
|
|
|
|
DPA_Sort(hdpa, WELCompare, (LPARAM)hdsa);
|
|
|
|
for (int i=0; i<10 && i<DPA_GetPtrCount(hdpa) ; i++) {
|
|
STATURL* pstat = (STATURL*)DSA_GetItemPtr(hdsa, (int)DPA_GetPtr(hdpa, i));
|
|
if (pstat && pstat->pwcsUrl) {
|
|
|
|
FileTimeToDateTimeString(&pstat->ftLastVisited, szBuf, SIZEOF(szBuf));
|
|
WriteFile(hfile, szBuf, lstrlen(szBuf), &cbWritten, NULL);
|
|
const static TCHAR c_szColumn[] = TEXT(" -- ");
|
|
WriteFile(hfile, c_szColumn, SIZEOF(c_szColumn)-1, &cbWritten, NULL);
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, pstat->pwcsUrl, -1,
|
|
szBuf, ARRAYSIZE(szBuf), NULL, NULL);
|
|
WriteFile(hfile, szBuf, lstrlen(szBuf), &cbWritten, NULL);
|
|
|
|
WriteFile(hfile, c_szCRLF, SIZEOF(c_szCRLF)-1, &cbWritten, NULL);
|
|
} else {
|
|
ASSERT(0);
|
|
}
|
|
}
|
|
|
|
DPA_Destroy(hdpa);
|
|
}
|
|
DSA_DestroyCallback(hdsa, WELCallback, NULL);
|
|
}
|
|
penum->Release();
|
|
} else {
|
|
ASSERT(0);
|
|
}
|
|
pUrlHistStg->Release();
|
|
} else {
|
|
ASSERT(0);
|
|
}
|
|
|
|
CloseHandle( hfile );
|
|
hfile = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
_except(SetErrorMode(SEM_NOGPFAULTERRORBOX),
|
|
_CopyExceptionInfo(GetExceptionInformation()),
|
|
UnhandledExceptionFilter(GetExceptionInformation())
|
|
)
|
|
{
|
|
// We hit an exception while handling an exception.
|
|
// Do nothing; we have already displayed the error dialog box.
|
|
if(hfile != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hfile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void IEFrame_ThreadProc(IETHREADPARAM* piei)
|
|
{
|
|
BOOL bFolderTiming;
|
|
UINT tidCur = GetCurrentThreadId();
|
|
CHAR szText[MAX_PATH];
|
|
|
|
#ifdef DEBUG
|
|
if (GetAsyncKeyState(VK_CONTROL) < 0) {
|
|
piei->pidlRoot = ILCreateFromPath(TEXT("c:\\windows"));
|
|
}
|
|
#endif
|
|
|
|
if(g_dwStopWatchMode)
|
|
{
|
|
char *psz = szText;
|
|
wsprintfA(szText, (LPCSTR)"Shell Folder: Start %s(", (piei->uFlags & COF_EXPLORE ?"explore " :""));
|
|
psz += lstrlenA(szText);
|
|
ILGetDisplayName(piei->pidl, psz);
|
|
lstrcatA(szText, (LPCSTR)")");
|
|
|
|
StopWatch_Start(tidCur, (LPCSTR)szText, SPMODE_MEMLOG | SPMODE_DEBUGOUT);
|
|
bFolderTiming = TRUE;
|
|
}
|
|
|
|
InitRoot(piei);
|
|
|
|
TraceMsg(TF_SHDTHREAD, "IE_ThreadProc(%x) just started. fParking ==",
|
|
tidCur, (tidCur==g_tidParking));
|
|
|
|
#if 0
|
|
#define DWSTYLE WS_OVERLAPPEDWINDOW
|
|
#else
|
|
#define DWSTYLE WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN
|
|
#endif
|
|
|
|
#ifdef DEBUG_EXPLORER
|
|
piei->wv.bTree = TRUE;
|
|
piei->TreeSplit = 200; // some random default
|
|
#endif
|
|
|
|
InitializeExplorerClass();
|
|
|
|
TraceMsg(TF_COCREATE, "IEFrame_ThreadProc calling CreateWindowEx");
|
|
|
|
LPCTSTR pszClass;
|
|
if (piei->uFlags & COF_EXPLORE) {
|
|
pszClass = c_szExploreClass;
|
|
} else if (piei->uFlags & COF_IEXPLORE) {
|
|
pszClass = c_szIExploreClass;
|
|
} else {
|
|
pszClass = c_szCabinetClass;
|
|
}
|
|
|
|
HWND hwnd = CreateWindowEx(WS_EX_WINDOWEDGE,
|
|
pszClass,
|
|
NULL, DWSTYLE,
|
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
|
NULL, g_hmenuFullSB, HINST_THISDLL, piei);
|
|
|
|
if (hwnd)
|
|
{
|
|
CShellBrowser* psb = (CShellBrowser*)SendMessage(hwnd, WMC_GETTHISPTR, 0, 0);
|
|
|
|
if (psb)
|
|
{
|
|
psb->_AfterWindowCreated(piei);
|
|
|
|
TraceMsg(TF_SHDTHREAD, "IE_ThreadProc(%x) about to start the message loop", tidCur);
|
|
|
|
while (1)
|
|
{
|
|
MSG msg;
|
|
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (msg.message == WM_QUIT)
|
|
{
|
|
TraceMsg(TF_SHDTHREAD, "IE_ThreadProc(%x) got WM_QUIT. Quitting", tidCur);
|
|
break;
|
|
}
|
|
|
|
|
|
if (psb->_hwnd && IsWindow(psb->_hwnd))
|
|
{
|
|
if (psb->v_MayTranslateAccelerator(&msg))
|
|
continue;
|
|
}
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
|
|
if(g_dwStopWatchMode)
|
|
{
|
|
if(g_dwStopWatchMode & SPMODE_TEST) // This is used to verify message assumptions
|
|
{
|
|
wsprintfA((LPSTR)szText, (LPCSTR)"PM 0x%x\r\n", msg.message);
|
|
OutputDebugString((LPCSTR)szText);
|
|
}
|
|
|
|
if(!bFolderTiming &&
|
|
(((msg.message == WM_KEYUP) && (msg.wParam == VK_RETURN)) ||
|
|
((msg.message == WM_KEYUP) && (msg.wParam == VK_BACK)))
|
|
) // Navigating within the same window
|
|
{
|
|
char *psz = szText;
|
|
DWORD dwLen;
|
|
wsprintfA(szText, (LPCSTR)"Shell Folder: Start %s same (", (piei->uFlags == COF_EXPLORE ?"explore" :""));
|
|
dwLen = lstrlenA(szText);
|
|
psz += dwLen;
|
|
GetWindowText(hwnd, psz, MAX_PATH - dwLen - 1);
|
|
lstrcatA(szText, (LPCSTR)")");
|
|
|
|
StopWatch_Start(tidCur, (LPCSTR)szText, SPMODE_MEMLOG | SPMODE_DEBUGOUT);
|
|
bFolderTiming = TRUE; // This handles the case where we are navigating within the same frame
|
|
}
|
|
|
|
if(bFolderTiming && !PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) // Stop when there are no more messages
|
|
{
|
|
StopWatch_Stop(tidCur, (LPCSTR)"Shell Folder: Stop", SPMODE_MEMLOG | SPMODE_DEBUGOUT);
|
|
bFolderTiming = FALSE;
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We wait slightly differently if this is the parking
|
|
// thread AND the window is already destroyed.
|
|
//
|
|
if ((tidCur==g_tidParking) && (psb->_hwnd==NULL)) {
|
|
//
|
|
// We need to wait with timeout to see if this is the
|
|
// last thread or not occasionally.
|
|
//
|
|
DWORD dwWait = MsgWaitForMultipleObjects(0, NULL, FALSE, 500, QS_ALLINPUT);
|
|
|
|
if (dwWait == WAIT_TIMEOUT) {
|
|
//
|
|
// Note that as far as we are checking for 1,
|
|
// we don't need to worry about race-condition
|
|
// because g_cThreads == 1 indicates that there is
|
|
// no other thread accessing g_cThread.
|
|
//
|
|
if (g_cThreads == 1 && g_cModelessDlg == 0) {
|
|
// Yes, this is the last thread.
|
|
TraceMsg(TF_SHDTHREAD, "IE_ThreadProc(%x) Calling PostQuitMessage", tidCur);
|
|
PostQuitMessage(0);
|
|
} else {
|
|
TraceMsg(TF_SHDTHREAD, "IE_ThreadProc(%x) keep this parking thread alive g_cThread=%d, g_cMDlg=%d",
|
|
tidCur, g_cThreads, g_cModelessDlg);
|
|
}
|
|
}
|
|
} else {
|
|
WaitMessage();
|
|
}
|
|
}
|
|
|
|
TraceMsg(TF_SHDTHREAD, "IE_ThreadProc(%x) end of message loop", tidCur);
|
|
psb->Release();
|
|
}
|
|
} else {
|
|
// Unregister any pending that may be there
|
|
WinList_Revoke(piei->dwRegister);
|
|
TraceMsg(DM_ERROR, "IE_ThreadProc CreateWindow failed");
|
|
}
|
|
|
|
delete piei;
|
|
}
|
|
|
|
DWORD CALLBACK IEFrame_ProtectedThreadProc(LPVOID pv)
|
|
{
|
|
EXCEPTION_RECORD exr;
|
|
|
|
DebugMemLeak(DML_TYPE_THREAD | DML_BEGIN);
|
|
|
|
OleInitialize(NULL);
|
|
|
|
_try
|
|
{
|
|
IEFrame_ThreadProc((IETHREADPARAM*)pv);
|
|
}
|
|
_except(
|
|
exr = *((GetExceptionInformation())->ExceptionRecord),
|
|
_CopyExceptionInfo(GetExceptionInformation()),
|
|
UnhandledExceptionFilter(GetExceptionInformation())
|
|
)
|
|
{
|
|
LPCSTR pszMsg;
|
|
// we will try to display a message box to tell the user
|
|
// that a thread has died...
|
|
//
|
|
if (GetExceptionCode() == STATUS_NO_MEMORY) {
|
|
pszMsg = MAKEINTRESOURCE(IDS_EXCEPTIONNOMEMORY);
|
|
} else {
|
|
pszMsg = (WhichPlatform() == PLATFORM_IE3) ?
|
|
MAKEINTRESOURCE(IDS_EXCEPTIONMSG) : MAKEINTRESOURCE(IDS_EXCEPTIONMSGSH);
|
|
}
|
|
|
|
ShellMessageBox(HINST_THISDLL, NULL, pszMsg,
|
|
MAKEINTRESOURCE(IDS_TITLE), MB_ICONEXCLAMATION|MB_SETFOREGROUND);
|
|
|
|
if (GetExceptionCode() != STATUS_NO_MEMORY) {
|
|
IEWriteErrorLog(&exr);
|
|
}
|
|
}
|
|
|
|
|
|
OleUninitialize();
|
|
|
|
DebugMemLeak(DML_TYPE_THREAD | DML_END);
|
|
return 0;
|
|
}
|
|
|
|
|
|
IETHREADPARAM::IETHREADPARAM(LPCTSTR pszCmdLineIn, int nCmdShowIn, HDPA hdpaIn,
|
|
HANDLE heventIn, IStream* pstmIn)
|
|
: pszCmdLine(pszCmdLineIn), nCmdShow(nCmdShowIn), hdpa(hdpaIn),
|
|
hevent(heventIn), pstm(pstmIn), hres(E_UNEXPECTED)
|
|
{
|
|
if (pstm) {
|
|
pstm->AddRef();
|
|
}
|
|
InterlockedIncrement(&g_cThreads);
|
|
THRMSG2("Just called InterlockIncrement", g_cThreads);
|
|
}
|
|
|
|
IETHREADPARAM::IETHREADPARAM(const IETHREADPARAM * piei)
|
|
{
|
|
InterlockedIncrement(&g_cThreads);
|
|
*this = *piei;
|
|
if (pstm) {
|
|
pstm->AddRef();
|
|
}
|
|
if (piei->pidl) {
|
|
pidl = ILClone(piei->pidl);
|
|
}
|
|
|
|
if (piei->pidlSelect) {
|
|
pidl = ILClone(piei->pidlSelect);
|
|
}
|
|
|
|
if (piei->pidlRoot) {
|
|
pidlRoot = ILClone(piei->pidlRoot);
|
|
}
|
|
|
|
if (psbCaller)
|
|
psbCaller->AddRef();
|
|
};
|
|
|
|
IETHREADPARAM::~IETHREADPARAM()
|
|
{
|
|
THRMSG2("About to call InterlockDecrement", g_cThreads);
|
|
InterlockedDecrement(&g_cThreads);
|
|
|
|
if (pstm) {
|
|
pstm->Release();
|
|
}
|
|
|
|
if (pidl)
|
|
ILFree(pidl);
|
|
|
|
if (pidlSelect)
|
|
ILFree(pidlSelect);
|
|
|
|
if (pidlRoot)
|
|
ILFree(pidlRoot);
|
|
|
|
if (psbCaller)
|
|
psbCaller->Release();
|
|
}
|
|
|
|
STDAPI_(BOOL) OpenFolderWindow(IETHREADPARAM* pieiIn)
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
_InitAppGlobals();
|
|
|
|
//
|
|
// Check to see if we can reuse the existing window first
|
|
//
|
|
if (pieiIn->psbCaller &&
|
|
!(pieiIn->uFlags & COF_CREATENEWWINDOW) &&
|
|
(!g_CabState.fNewWindowMode || (pieiIn->uFlags & COF_EXPLORE))) {
|
|
|
|
// in this case we should reuse the current window
|
|
if (pieiIn->pidl) {
|
|
UINT uFlags = SBSP_SAMEBROWSER;
|
|
|
|
if (pieiIn->uFlags & COF_EXPLORE)
|
|
uFlags |= SBSP_EXPLOREMODE;
|
|
else
|
|
uFlags |= SBSP_OPENMODE;
|
|
|
|
HRESULT hres = pieiIn->psbCaller->BrowseObject(pieiIn->pidl, uFlags);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Don't look for an existing window if we are opening an explorer.
|
|
//
|
|
if (!((pieiIn->uFlags & COF_EXPLORE)||(pieiIn->uFlags & COF_NOFINDWINDOW))) {
|
|
HWND hwnd;
|
|
HRESULT hres;
|
|
|
|
if ((hres = WinList_FindFolderWindow(pieiIn->pidl, pieiIn->pidlRoot, &hwnd, NULL)) == S_OK) {
|
|
SetForegroundWindow(hwnd);
|
|
ShowWindow(hwnd, pieiIn->nCmdShow ? pieiIn->nCmdShow : SW_SHOWNORMAL);
|
|
return TRUE;
|
|
}
|
|
else if (hres == E_PENDING)
|
|
return TRUE; // Assume it will come up sooner or later
|
|
}
|
|
|
|
IETHREADPARAM* piei = new IETHREADPARAM(pieiIn);
|
|
if (piei) {
|
|
DWORD idThread;
|
|
HANDLE hthread;
|
|
|
|
if (piei->pidl && IsURLChild(piei->pidl, TRUE)) {
|
|
piei->uFlags |= COF_IEXPLORE;
|
|
}
|
|
|
|
// Create suspended to allow us to register them without race condition...
|
|
if (hthread = CreateThread(NULL, 0, IEFrame_ProtectedThreadProc, (LPVOID)piei, CREATE_SUSPENDED, &idThread)) {
|
|
WinList_RegisterPending(idThread, pieiIn->pidl, pieiIn->pidlRoot, &piei->dwRegister);
|
|
ResumeThread(hthread);
|
|
CloseHandle(hthread);
|
|
fSuccess = TRUE;
|
|
} else {
|
|
delete piei;
|
|
fSuccess = FALSE;
|
|
}
|
|
}
|
|
return fSuccess;
|
|
}
|
|
|
|
//
|
|
// Notes: pidlNew will be freed
|
|
//
|
|
HRESULT _OpenNewFrame(LPITEMIDLIST pidlNew, TRAVELLOG* ptl, UINT uFlags)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
DWORD idThread;
|
|
HANDLE hthread;
|
|
HDPA hdpa = DPA_Create(16);
|
|
if (hdpa)
|
|
{
|
|
if (ptl)
|
|
{
|
|
PTLOGLINK ptll = ptl->ptllCurrent;
|
|
if (ptll)
|
|
{
|
|
// First find the first one.
|
|
while (ptll->GetPrevLink()) {
|
|
ptll = ptll->GetPrevLink();
|
|
}
|
|
|
|
// Copy all the pidl's upto the current point
|
|
do {
|
|
LPITEMIDLIST pidlCopy;
|
|
ptll->GetPidl(&pidlCopy);
|
|
if (pidlCopy) {
|
|
DPA_InsertPtr(hdpa, 9999, pidlCopy);
|
|
}
|
|
} while((ptll != ptl->ptllCurrent) && (ptll = ptll->GetNextLink()));
|
|
|
|
}
|
|
}
|
|
|
|
// Then, add the new pidl we are opening
|
|
if (pidlNew) {
|
|
// Don't add it if the last pidl is this one.
|
|
int cdpa = DPA_GetPtrCount(hdpa);
|
|
if ((!IsEURLPidl(pidlNew)) && cdpa>0) {
|
|
LPCITEMIDLIST pidlLast = (LPCITEMIDLIST)DPA_GetPtr(hdpa, cdpa-1);
|
|
if (ILIsEqual(pidlLast, pidlNew)) {
|
|
ILFree(pidlNew);
|
|
pidlNew = NULL;
|
|
}
|
|
}
|
|
|
|
if (pidlNew) {
|
|
DPA_InsertPtr(hdpa, 9999, pidlNew);
|
|
if (IsURLChild(pidlNew, TRUE))
|
|
uFlags |= COF_IEXPLORE;
|
|
pidlNew = NULL;
|
|
}
|
|
}
|
|
|
|
IETHREADPARAM* piei = new IETHREADPARAM(NULL, SW_SHOWNORMAL, hdpa);
|
|
if (piei) {
|
|
piei->uFlags = uFlags;
|
|
if (hthread = CreateThread(NULL, 0, IEFrame_ProtectedThreadProc, (LPVOID)piei, 0, &idThread)) {
|
|
CloseHandle(hthread);
|
|
hres = S_OK;
|
|
} else {
|
|
delete piei;
|
|
hres = E_FAIL;
|
|
}
|
|
} else {
|
|
hres = E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (FAILED(hres)) {
|
|
//
|
|
// If it failed, we need to clean it up.
|
|
//
|
|
_DeletePidlDPA(hdpa);
|
|
}
|
|
}
|
|
|
|
if (pidlNew) {
|
|
ILFree(pidlNew);
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
//
|
|
// This is an implementation of IOleInPlaceUIWindow::GetBorder.
|
|
//
|
|
// This function returns the bounding rectangle for the active object.
|
|
// It gets the effective client area, then subtract border area taken by
|
|
// all "frame" toolbars.
|
|
//
|
|
HRESULT CShellBrowser::GetBorder(LPRECT lprectBorder)
|
|
{
|
|
_GetViewBorderRect(lprectBorder);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CShellBrowser::SetBorderSpace(LPCBORDERWIDTHS pborderwidths)
|
|
{
|
|
if (pborderwidths) {
|
|
TraceMsg(TF_SHDUIACTIVATE, "UIW::SetBorderSpace pborderwidths=%x,%x,%x,%x",
|
|
pborderwidths->left, pborderwidths->top, pborderwidths->right, pborderwidths->bottom);
|
|
_rcBorderDoc = *pborderwidths;
|
|
} else {
|
|
TraceMsg(TF_SHDUIACTIVATE, "UIW::SetBorderSpace pborderwidths=NULL");
|
|
SetRect(&_rcBorderDoc, 0, 0, 0, 0);
|
|
}
|
|
|
|
SUPERCLASS::SetBorderSpace(pborderwidths);
|
|
return S_OK;
|
|
}
|
|
|
|
#define MAX_TOOLTIP_STRING 80
|
|
|
|
HRESULT CShellBrowser::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
|
|
OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
HRESULT hres = SUPERCLASS::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
|
|
|
|
if (pguidCmdGroup == NULL)
|
|
{
|
|
//
|
|
// If the curretly focused toolbar suppors the IOleCommandTarget
|
|
// ask it the status of clipboard commands.
|
|
//
|
|
if (_itbLastFocus < ITB_MAX && _aTBar[_itbLastFocus].ptbar)
|
|
{
|
|
IOleCommandTarget* pcmd;
|
|
HRESULT hresT = _aTBar[_itbLastFocus].ptbar->QueryInterface(
|
|
IID_IOleCommandTarget, (void**)&pcmd);
|
|
if (SUCCEEDED(hresT))
|
|
{
|
|
for (ULONG i = 0; i < cCmds; i++)
|
|
{
|
|
switch (rgCmds[i].cmdID)
|
|
{
|
|
case OLECMDID_CUT:
|
|
case OLECMDID_COPY:
|
|
case OLECMDID_PASTE:
|
|
pcmd->QueryStatus(pguidCmdGroup, 1, &rgCmds[i], pcmdtext);
|
|
break;
|
|
}
|
|
}
|
|
pcmd->Release();
|
|
}
|
|
}
|
|
}
|
|
else if (IsEqualGUID(CGID_ShellBrowser, *pguidCmdGroup))
|
|
{
|
|
ASSERT(cCmds == 1);
|
|
|
|
switch (pcmdtext->cmdtextf)
|
|
{
|
|
case OLECMDTEXTF_NAME:
|
|
{
|
|
TOOLTIPTEXT ttt = { NULL };
|
|
ttt.hdr.code = TTN_NEEDTEXTA;
|
|
ttt.hdr.idFrom = rgCmds[0].cmdID;
|
|
pcmdtext->cwActual = 0;
|
|
hres = _OnNotify((LPNMHDR)&ttt);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (lstrlen(ttt.szText))
|
|
{
|
|
pcmdtext->cwActual = MultiByteToWideChar(CP_ACP, 0, ttt.szText, -1, pcmdtext->rgwz, pcmdtext->cwBuf);
|
|
pcmdtext->cwActual -= 1;
|
|
}
|
|
else if (ttt.hinst)
|
|
{
|
|
TCHAR szTemp[MAX_TOOLTIP_STRING];
|
|
if (LoadString(ttt.hinst, (UINT)ttt.lpszText, szTemp, ARRAYSIZE(szTemp)))
|
|
{
|
|
pcmdtext->cwActual = MultiByteToWideChar(CP_ACP, 0, szTemp, -1, pcmdtext->rgwz, pcmdtext->cwBuf);
|
|
pcmdtext->cwActual -= 1;
|
|
}
|
|
}
|
|
else if (ttt.lpszText)
|
|
{
|
|
pcmdtext->cwActual = MultiByteToWideChar(CP_ACP, 0, ttt.lpszText, -1, pcmdtext->rgwz, pcmdtext->cwBuf);
|
|
pcmdtext->cwActual -= 1;
|
|
}
|
|
}
|
|
hres = S_OK;
|
|
break;
|
|
}
|
|
default:
|
|
hres = E_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
|
|
{
|
|
// BUGBUG: should fill pcmdtext as well
|
|
|
|
for (ULONG i = 0 ; i < cCmds ; i++)
|
|
{
|
|
switch (rgCmds[i].cmdID)
|
|
{
|
|
case SBCMDID_OPTIONS:
|
|
case SBCMDID_SHOWCONTROL:
|
|
case SBCMDID_DOFAVORITESMENU:
|
|
case SBCMDID_ACTIVEOBJECTMENUS:
|
|
case SBCMDID_SEARCHBAR:
|
|
case SBCMDID_ADDTOFAVORITES:
|
|
rgCmds[i].cmdf = OLECMDF_ENABLED; // support these unconditionally
|
|
break;
|
|
|
|
case SBCMDID_DOMAILMENU:
|
|
rgCmds[i].cmdf = IsRegistered(NEWS_DEF_KEY) || IsRegistered(MAIL_DEF_KEY) ? OLECMDF_ENABLED : 0;
|
|
break;
|
|
}
|
|
}
|
|
hres = S_OK;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
// fill a buffer with a variant, return a pointer to that buffer on success of the conversion
|
|
|
|
LPCTSTR VariantToString(const VARIANT *pv, LPTSTR pszBuf, UINT cch)
|
|
{
|
|
*pszBuf = 0;
|
|
|
|
if (pv && pv->vt == VT_BSTR && pv->bstrVal)
|
|
{
|
|
#ifdef UNICODE
|
|
lstrcpyn(pszBuf, pv->bstrVal, cch);
|
|
#else
|
|
OleStrToStrN(pszBuf, cch, pv->bstrVal, -1);
|
|
#endif
|
|
if (*pszBuf)
|
|
return pszBuf;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT CShellBrowser::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
|
|
VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
HRESULT hres = SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
|
|
if (pguidCmdGroup == NULL)
|
|
{
|
|
DefaultCommandGroup:
|
|
|
|
switch (nCmdID)
|
|
{
|
|
case OLECMDID_REFRESH:
|
|
v_ShowHideChildWindows();
|
|
hres = S_OK;
|
|
break;
|
|
|
|
// Clipboard commands and common operations will be dispatched
|
|
// to the currently focused toolbar.
|
|
|
|
case OLECMDID_CUT:
|
|
case OLECMDID_COPY:
|
|
case OLECMDID_PASTE:
|
|
case OLECMDID_DELETE:
|
|
case OLECMDID_PROPERTIES:
|
|
|
|
ASSERT(hres == OLECMDERR_E_NOTSUPPORTED);
|
|
|
|
if (_itbLastFocus < ITB_MAX && _aTBar[_itbLastFocus].ptbar)
|
|
{
|
|
IOleCommandTarget* pcmd;
|
|
HRESULT hresT = _aTBar[_itbLastFocus].ptbar->QueryInterface(
|
|
IID_IOleCommandTarget, (LPVOID*)&pcmd);
|
|
if (SUCCEEDED(hresT))
|
|
{
|
|
hres = pcmd->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
pcmd->Release();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(CGID_ShellBrowser, *pguidCmdGroup))
|
|
{
|
|
// toolbar buttons we put there ourselves
|
|
|
|
hres = S_OK; // assume accepted
|
|
|
|
switch (nCmdID)
|
|
{
|
|
case FCIDM_PREVIOUSFOLDER:
|
|
v_ParentFolder();
|
|
break;
|
|
|
|
default:
|
|
// pass off the nCmdID to the view for processing / translation.
|
|
DFVCMDDATA cd;
|
|
|
|
cd.pva = pvarargIn;
|
|
cd.hwnd = _hwnd;
|
|
cd.nCmdIDTranslated = 0;
|
|
SendMessage(_hwndView, WM_COMMAND, nCmdID, (LONG)&cd);
|
|
|
|
if (cd.nCmdIDTranslated)
|
|
{
|
|
// We sent the private nCmdID to the view. The view did not
|
|
// process it (probably because it didn't have the focus),
|
|
// but instead translated it into a standard OLECMDID for
|
|
// further processing by the toolbar with the focus.
|
|
|
|
pguidCmdGroup = NULL;
|
|
nCmdID = cd.nCmdIDTranslated;
|
|
hres = OLECMDERR_E_NOTSUPPORTED;
|
|
goto DefaultCommandGroup;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
|
|
{
|
|
hres = S_OK; // assume we will get it
|
|
|
|
switch(nCmdID)
|
|
{
|
|
case SBCMDID_ACTIVEOBJECTMENUS:
|
|
_fTryHelpMenuMerge = TRUE;
|
|
break;
|
|
|
|
case SBCMDID_OPTIONS:
|
|
_DoOptions(pvarargIn);
|
|
break;
|
|
|
|
case SBCMDID_SEARCHBAR:
|
|
// search bar
|
|
// BUGBUG jcordell: begin temp code for beta 1
|
|
if ( pvarargIn && pvarargIn->vt == VT_BOOL && pvarargIn->boolVal )
|
|
_RemoveSearchBar();
|
|
else
|
|
// BUGBUG jcordell: end temp code for beta 1
|
|
_ToggleSearchBar();
|
|
break;
|
|
|
|
case SBCMDID_SHOWCONTROL:
|
|
{
|
|
DWORD dwRet;
|
|
int iControl;
|
|
int iCmd;
|
|
|
|
if (nCmdexecopt == OLECMDEXECOPT_DODEFAULT &&
|
|
pvarargIn &&
|
|
pvarargIn->vt == VT_I4)
|
|
{
|
|
iControl = (int)(short)LOWORD(pvarargIn->lVal);
|
|
iCmd = (int)(short)HIWORD(pvarargIn->lVal);
|
|
}
|
|
else
|
|
{
|
|
iControl = (int)(short)LOWORD(nCmdexecopt);
|
|
iCmd = (HIWORD(nCmdexecopt) ? SBSC_SHOW : SBSC_HIDE);
|
|
}
|
|
|
|
dwRet = v_ShowControl(iControl, iCmd);
|
|
if (dwRet == (DWORD)-1)
|
|
break;
|
|
|
|
if (pvarargOut)
|
|
{
|
|
pvarargOut->vt = VT_I4;
|
|
pvarargOut->lVal = dwRet;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SBCMDID_ADDTOFAVORITES:
|
|
{
|
|
TCHAR szTitle[128];
|
|
LPITEMIDLIST pidl = VariantToIDList(pvarargIn); // may be NULL
|
|
|
|
_AddToFavorites(pidl, VariantToString(pvarargOut, szTitle, ARRAYSIZE(szTitle)),
|
|
nCmdexecopt == OLECMDEXECOPT_PROMPTUSER);
|
|
|
|
if (pidl)
|
|
ILFree(pidl);
|
|
}
|
|
break;
|
|
|
|
case SBCMDID_DOFAVORITESMENU:
|
|
case SBCMDID_DOMAILMENU:
|
|
{
|
|
HMENU hmenu = NULL;
|
|
|
|
if (nCmdID == SBCMDID_DOFAVORITESMENU)
|
|
{
|
|
HMENU hmenuWnd = GetMenu(_hwnd);
|
|
if (hmenuWnd)
|
|
{
|
|
hmenu = GetMenuFromID(hmenuWnd, FCIDM_MENU_FAVORITES);
|
|
}
|
|
}
|
|
else
|
|
hmenu = LoadMenuPopup(MENU_MAILNEWS);
|
|
|
|
if (hmenu)
|
|
{
|
|
if (pvarargIn && pvarargIn->vt == VT_I4)
|
|
{
|
|
TrackPopupMenu(hmenu, 0,
|
|
(int)(short)LOWORD(pvarargIn->lVal), (int)(short)HIWORD(pvarargIn->lVal),
|
|
0, _hwnd, NULL);
|
|
}
|
|
if (nCmdID == SBCMDID_DOMAILMENU)
|
|
DestroyMenu(hmenu);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hres = OLECMDERR_E_NOTSUPPORTED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
/**********************************************\
|
|
FUNCTION: CShellBrowser::_SetTitle
|
|
|
|
PARAMETERS:
|
|
LPCSTR pszName - The Name of the URL, not
|
|
limited in size, but the result will
|
|
be truncated if the imput is too long.
|
|
|
|
DESCRIPTION:
|
|
The title will be generated by taking the
|
|
title of the HTML page (pszName) and appending
|
|
the name of the browser to the end in the
|
|
following format:
|
|
"HTML_TITLE - BROWSER_NAME", like:
|
|
"My Web Page - Microsoft Internet Explorer"
|
|
\**********************************************/
|
|
|
|
|
|
void CShellBrowser::_SetTitle(LPCSTR pszName)
|
|
{
|
|
TCHAR szTitle[MAX_BROWSER_WINDOW_TITLE];
|
|
TCHAR szFullName[MAX_URL_STRING];
|
|
|
|
if (!pszName && _fTitleSet) {
|
|
// if the content has once set our title,
|
|
// don't revert to our own mocked up name
|
|
return;
|
|
}
|
|
|
|
if (pszName)
|
|
{
|
|
lstrcpyn(szFullName, pszName, ARRAYSIZE(szFullName));
|
|
_fTitleSet = TRUE;
|
|
}
|
|
else if (_pidlCur)
|
|
{
|
|
UINT uType;
|
|
|
|
if (ISROOTEDCLASS() && ILIsEmpty(_pidlCur))
|
|
{
|
|
// g_pidlRootClass is a pidl in the SHELL namespace
|
|
// so this needs to NOT go to IEGetDisplayName
|
|
if (g_CabState.fFullPathTitle)
|
|
uType = ILGDN_FULLNAME;
|
|
else
|
|
uType = ILGDN_ITEMONLY;
|
|
|
|
ILGetDisplayNameEx(NULL, g_pidlRootClass, szFullName, uType);
|
|
}
|
|
else
|
|
{
|
|
uType = SHGDN_INFOLDER;
|
|
|
|
// BUGBUG: we should let the view set the title too
|
|
if (IsURLChild(_pidlCur, TRUE))
|
|
{
|
|
uType = SHGDN_NORMAL;
|
|
}
|
|
else if (g_CabState.fFullPathTitle)
|
|
{
|
|
uType = SHGDN_FORPARSING;
|
|
}
|
|
else if (!ILIsEmpty(_pidlCur))
|
|
{
|
|
IShellFolder *psfParent;
|
|
LPCITEMIDLIST pidlChild;
|
|
NameFromParent:
|
|
if (SUCCEEDED(BindToParentFolder(_pidlCur, &psfParent, &pidlChild)))
|
|
{
|
|
STRRET sr;
|
|
if (SUCCEEDED(psfParent->GetDisplayNameOf(pidlChild,
|
|
SHGDN_NORMAL, &sr)))
|
|
{
|
|
StrRetToStrN(szFullName, ARRAYSIZE(szFullName), &sr, pidlChild);
|
|
uType = (UINT)-1;
|
|
}
|
|
psfParent->Release();
|
|
}
|
|
}
|
|
if (uType != (UINT)-1) {
|
|
HRESULT hres = ::IEGetDisplayName(_pidlCur, szFullName, uType);
|
|
if (FAILED(hres) && !ILIsEmpty(_pidlCur)) {
|
|
uType = (UINT)-1;
|
|
goto NameFromParent;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
szFullName[0] = 0;
|
|
|
|
szFullName[100] = 0; // any more than 60 is useless anyways
|
|
|
|
if (szFullName[0])
|
|
{
|
|
TCHAR szBuf[128];
|
|
|
|
v_GetAppTitleTemplate(szBuf, szFullName);
|
|
|
|
// Truncate HTML_TITLE so it will fit when the " - BROWSER_NAME" is appended to the end.
|
|
szFullName[MAX_BROWSER_WINDOW_TITLE - lstrlen(szBuf)] = TEXT('\0');
|
|
wsprintf(szTitle, szBuf, szFullName);
|
|
}
|
|
else
|
|
{
|
|
_GetAppTitle(szTitle, SIZEOF(szTitle));
|
|
}
|
|
SendMessage(_hwnd, WM_SETTEXT, 0, (LPARAM)szTitle);
|
|
}
|
|
|
|
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 (!(hIcon = ImageList_ExtractIcon(hinstCabinet,
|
|
bLarge ? g_himlSysLarge : g_himlSysSmall,
|
|
nIndex)))
|
|
return;
|
|
|
|
hOldIcon = (HICON)SendMessage(hwndMain, WM_SETICON, bLarge, (LPARAM)hIcon);
|
|
if (hOldIcon &&
|
|
(hOldIcon != hIcon))
|
|
{
|
|
DestroyIcon(hOldIcon);
|
|
}
|
|
}
|
|
|
|
void CShellBrowser::v_SetIcon()
|
|
{
|
|
int iSelectedImage = _GetIconIndex();
|
|
if (iSelectedImage != -1)
|
|
{
|
|
_WindowIconFromImagelist(_hwnd, iSelectedImage, FALSE);
|
|
_WindowIconFromImagelist(_hwnd, iSelectedImage, TRUE);
|
|
}
|
|
}
|
|
|
|
HRESULT CShellBrowser::SetTitle(LPCWSTR lpszName)
|
|
{
|
|
|
|
TCHAR szTitle[MAX_BROWSER_WINDOW_TITLE];
|
|
|
|
OleStrToStrN(szTitle, ARRAYSIZE(szTitle), lpszName, (UINT)-1);
|
|
_SetTitle(szTitle);
|
|
|
|
|
|
SUPERCLASS::SetTitle(lpszName);
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT CShellBrowser::UpdateWindowList(void)
|
|
{
|
|
if (_psw) {
|
|
WinList_NotifyNewLocation(_psw, _dwRegisterWinList, _pidlCur);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
DWORD CShellBrowser::v_ShowControl(UINT iControl, int iCmd)
|
|
{
|
|
int iShowing = -1;
|
|
|
|
switch (iControl) {
|
|
case FCW_STATUS:
|
|
iShowing = (_fStatusBar ? SBSC_SHOW : SBSC_HIDE);
|
|
if (iCmd != SBSC_QUERY &&
|
|
(iShowing != iCmd)) {
|
|
_fStatusBar = !_fStatusBar;
|
|
v_ShowHideChildWindows();
|
|
}
|
|
break;
|
|
|
|
case FCW_INTERNETBAR:
|
|
iShowing = (_aTBar[ITB_ITBAR].fShow ? SBSC_SHOW : SBSC_HIDE);
|
|
if (iCmd != SBSC_QUERY &&
|
|
(iShowing != iCmd)) {
|
|
_aTBar[ITB_ITBAR].fShow = !_aTBar[ITB_ITBAR].fShow;
|
|
v_ShowHideChildWindows();
|
|
}
|
|
break;
|
|
}
|
|
|
|
return iShowing;
|
|
}
|
|
|
|
HRESULT CShellBrowser::ShowControlWindow(UINT id, BOOL fShow)
|
|
{
|
|
switch (id)
|
|
{
|
|
case (UINT)-1: // Set into Kiosk mode...
|
|
if (_fFullScreen != fShow)
|
|
{
|
|
_fFullScreen = fShow;
|
|
if (_fFullScreen)
|
|
{
|
|
_wndpl.length = SIZEOF(WINDOWPLACEMENT);
|
|
GetWindowPlacement(_hwnd, &_wndpl);
|
|
SetWindowLong(_hwnd, GWL_STYLE, GetWindowLong(_hwnd, GWL_STYLE) &
|
|
~(WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
|
|
SetWindowLong(_hwnd, GWL_EXSTYLE, GetWindowLong(_hwnd, GWL_EXSTYLE) &
|
|
~(WS_EX_WINDOWEDGE));
|
|
SetMenu(_hwnd, NULL);
|
|
SetWindowPos(_hwnd, NULL, 0, 0, GetSystemMetrics(SM_CXSCREEN),
|
|
GetSystemMetrics(SM_CYSCREEN), SWP_NOZORDER);
|
|
}
|
|
else
|
|
{
|
|
if (_fShowMenu)
|
|
SetMenu(_hwnd, _hmenuCur);
|
|
else
|
|
SetMenu(_hwnd, NULL);
|
|
|
|
SetWindowLong(_hwnd, GWL_STYLE, GetWindowLong(_hwnd, GWL_STYLE) |
|
|
(WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
|
|
SetWindowLong(_hwnd, GWL_EXSTYLE, GetWindowLong(_hwnd, GWL_EXSTYLE) |
|
|
(WS_EX_WINDOWEDGE));
|
|
SetWindowPlacement(_hwnd, &_wndpl);
|
|
}
|
|
|
|
// Let window manager know to recalculate things...
|
|
v_ShowHideChildWindows();
|
|
|
|
SetWindowPos(_hwnd, NULL, 0, 0, 0, 0,
|
|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
|
|
}
|
|
break;
|
|
|
|
case FCW_INTERNETBAR:
|
|
case FCW_STATUS:
|
|
v_ShowControl(id, fShow ? SBSC_SHOW : SBSC_HIDE);
|
|
break;
|
|
|
|
case FCW_MENUBAR:
|
|
if (_fShowMenu != fShow)
|
|
{
|
|
_fShowMenu = fShow;
|
|
if (_fShowMenu)
|
|
{
|
|
SetMenu(_hwnd, _hmenuCur);
|
|
}
|
|
else
|
|
{
|
|
SetMenu(_hwnd, NULL);
|
|
}
|
|
|
|
// Let window manager know to recalculate things...
|
|
v_ShowHideChildWindows();
|
|
|
|
SetWindowPos(_hwnd, NULL, 0, 0, 0, 0,
|
|
SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_FRAMECHANGED);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return E_INVALIDARG; // Not one of the ones we support...
|
|
}
|
|
return NOERROR;
|
|
}
|
|
|
|
BOOL CShellBrowser::v_ShouldAllowNavigateParent()
|
|
{
|
|
if (_pidlCur) {
|
|
// in the rooted case, we can navigate to parent up to the desktop.
|
|
// in the non-rooted (shell) case, destkp is already shown, so don't allow
|
|
// going up to the desktop folder
|
|
if (IsRooted()) {
|
|
|
|
return !ILIsEqual(_pidlCur, g_pidlRoot);
|
|
|
|
} else {
|
|
LPCITEMIDLIST pidl = ILFindChild(g_pidlRoot, _pidlCur);
|
|
|
|
if (pidl && pidl->mkid.cb) {
|
|
pidl = _ILNext(pidl);
|
|
|
|
if (pidl->mkid.cb)
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT CShellBrowser::IsControlWindowShown(UINT id, BOOL *pfShown)
|
|
{
|
|
switch (id)
|
|
{
|
|
case (UINT)-1: // Set into Kiosk mode...
|
|
*pfShown = _fFullScreen;
|
|
break;
|
|
|
|
case FCW_INTERNETBAR:
|
|
*pfShown = _aTBar[ITB_ITBAR].fShow;
|
|
break;
|
|
|
|
case FCW_STATUS:
|
|
*pfShown = _fStatusBar;
|
|
break;
|
|
|
|
case FCW_MENUBAR:
|
|
*pfShown = _fShowMenu;
|
|
break;
|
|
|
|
default:
|
|
return E_INVALIDARG; // Not one of the ones we support...
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT CShellBrowser::_CheckZoneCrossing(LPCITEMIDLIST pidl)
|
|
{
|
|
//
|
|
// Call InternetConfirmZoneCrossing API only if this is the top-level
|
|
// browser (not a browser control) AND there is a current page.
|
|
//
|
|
if (_pidlCur) {
|
|
|
|
HRESULT hresT = S_OK;
|
|
// Get the URL of the current page.
|
|
TCHAR szURLPrev[MAX_URL_STRING];
|
|
|
|
const TCHAR c_szURLFile[] = "file:///c:\\"; // dummy one
|
|
LPCSTR pszURLPrev = c_szURLFile; // assume file:
|
|
|
|
if (IsURLChild(_pidlCur, FALSE)) {
|
|
hresT = ::IEGetDisplayName(_pidlCur, szURLPrev, SHGDN_FORPARSING);
|
|
pszURLPrev = szURLPrev;
|
|
}
|
|
|
|
if (SUCCEEDED(hresT))
|
|
{
|
|
// Get the URL of the new page.
|
|
TCHAR szURLNew[MAX_URL_STRING];
|
|
LPCSTR pszURLNew = c_szURLFile;
|
|
if (IsURLChild(pidl, FALSE)) {
|
|
hresT = ::IEGetDisplayName(pidl, szURLNew, SHGDN_FORPARSING);
|
|
pszURLNew = szURLNew;
|
|
}
|
|
|
|
if (pszURLPrev!=pszURLNew && SUCCEEDED(hresT))
|
|
{
|
|
// HACK: This API takes LPTSTR instead of LPCTSTR.
|
|
DWORD err = InternetConfirmZoneCrossing(_hwnd, (LPTSTR)pszURLPrev, (LPTSTR)pszURLNew, FALSE);
|
|
|
|
TraceMsg(DM_ZONE, "CSB::_Nav InetConfirmZoneXing %s %s returned %d", pszURLPrev, pszURLNew, err);
|
|
if (err != ERROR_SUCCESS) {
|
|
//
|
|
// Either the user cancelled it or there is not enough
|
|
// memory. Abort the navigation.
|
|
//
|
|
TraceMsg(DM_ERROR, "CSB::_CheckZoneCrossing ICZC returned error (%d)", err);
|
|
return HRESULT_FROM_WIN32(err);
|
|
}
|
|
} else {
|
|
TraceMsg(DM_ZONE, "CSB::_Nav IEGetDisplayName(pidl) failed %x", hresT);
|
|
}
|
|
} else {
|
|
TraceMsg(DM_ZONE, "CSB::_Nav IEGetDisplayName(_pidlCur) failed %x", hresT);
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT FindBrowserWindowOfClass(LPCTSTR pszClass, WPARAM wParam, LPARAM lParam, BOOL fPostMessage, HWND* phwnd)
|
|
{
|
|
//If there is no window, assume the user is in the process of shutting down IE, and return E_FAIL
|
|
|
|
//Otherwise, if there is at least one window, start cycling through the windows until you find
|
|
//one that's not busy, and give it our message. If all are busy, return
|
|
//HRESULT_FROM_WIN32(ERROR_BUSY)
|
|
DWORD idProcessCur = GetCurrentProcessId();
|
|
HWND hwnd = NULL;
|
|
HRESULT hres = E_FAIL;
|
|
while (FAILED(hres)
|
|
&& (hwnd = FindWindowEx(NULL, hwnd, pszClass, NULL)) != NULL)
|
|
{
|
|
hres = HRESULT_FROM_WIN32(ERROR_BUSY);
|
|
DWORD idProcess;
|
|
GetWindowThreadProcessId(hwnd, &idProcess);
|
|
if (idProcess == idProcessCur && IsWindowEnabled(hwnd) && IsWindowVisible(hwnd))
|
|
{
|
|
//if we have to do a PostMessage, we still use SendMessageTimeout to determine which
|
|
//window the navigation should occur in. Then we post the actual navigation message
|
|
//with a PostMessage.
|
|
BOOL fRet = SendMessageTimeout(hwnd,WMC_DISPATCH, (fPostMessage ? DSID_NOACTION : wParam),
|
|
lParam,SMTO_ABORTIFHUNG, 400, (LPDWORD)&hres);
|
|
if (SUCCEEDED(hres) && fPostMessage)
|
|
PostMessage(hwnd,WMC_DISPATCH,wParam,lParam);
|
|
TraceMsg(DM_IEDDE, "CDDEAuto_Common called SendMsgTimeOut fRet=%d hres=%x", fRet, hres);
|
|
}
|
|
}
|
|
|
|
*phwnd = hwnd;
|
|
return hres;
|
|
}
|
|
|
|
|
|
//This common function gets called when the DDE engine doesn't seem to care in which window something
|
|
//happens. It returns in which window that something happened. -1 means no windows are open,
|
|
//0 means all windows are busy.
|
|
HRESULT CDDEAuto_Common(WPARAM wParam, LPARAM lParam, HWND *phwnd, BOOL fPostMessage)
|
|
//phwnd: a pointer the hwnd to which to send the message. <= 0 means any window will do.
|
|
// this is also an out parameter that specifies in which window it happened.
|
|
//fPostMessage: when doing navigations, we have to do a PostMessage instead of a SendMessageTimeout
|
|
// or a CoCreateInstance later on in CDocObjectHost::_BindFileMoniker will fail. So when
|
|
// this function is called from CDDEAuto_Navigate, we make this flag TRUE
|
|
{
|
|
HRESULT hres;
|
|
HWND hwnd;
|
|
|
|
// BUGBUG: Once we finish moving desktop window code to shdocvw, we should
|
|
// change this Assert to do real assert.
|
|
ASSERT(g_tidParking==0 || g_tidParking == GetCurrentThreadId());
|
|
|
|
//if we're told to go to a specific window
|
|
if (phwnd && (*phwnd != (HWND)-1))
|
|
{
|
|
if (fPostMessage)
|
|
hres = (PostMessage(*phwnd,WMC_DISPATCH,wParam,lParam) ? S_OK : E_FAIL);
|
|
else
|
|
SendMessageTimeout(*phwnd,WMC_DISPATCH,wParam,lParam,SMTO_ABORTIFHUNG, 400, (LPDWORD)&hres);
|
|
return hres;
|
|
}
|
|
|
|
hres = FindBrowserWindowOfClass(c_szIExploreClass, wParam, lParam, fPostMessage, &hwnd);
|
|
if (!hwnd)
|
|
hres = FindBrowserWindowOfClass(c_szCabinetClass, wParam, lParam, fPostMessage, &hwnd);
|
|
|
|
if (phwnd)
|
|
*phwnd = hwnd;
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDDEAuto_Navigate(BSTR str, HWND *phwnd, long) //the long is for lTransID, which is currently
|
|
//turned off
|
|
{
|
|
DDENAVIGATESTRUCT *pddens = new DDENAVIGATESTRUCT;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
if (pddens == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (phwnd == NULL)
|
|
{
|
|
delete pddens;
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
pddens->wszUrl = StrDupW(str);
|
|
if (!pddens->wszUrl)
|
|
{
|
|
delete pddens;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
#if 0
|
|
pddens->transID = lTransID;
|
|
#endif
|
|
|
|
// Don't do the navigate if *phwnd == 0, in that case we want to either
|
|
// create a new window or activate an existing one that already is viewing
|
|
// this URL.
|
|
if (*phwnd != (HWND)0)
|
|
hres = CDDEAuto_Common(DSID_NAVIGATE, (LPARAM)pddens, phwnd, TRUE);
|
|
|
|
if (SUCCEEDED(hres) && (*phwnd != 0) && (*phwnd != (HWND)-1))
|
|
{
|
|
// We found an existing browser window and successfully sent the
|
|
// navigate message to it. Make the window foreground.
|
|
SetForegroundWindow(*phwnd);
|
|
|
|
if (IsIconic(*phwnd))
|
|
ShowWindowAsync(*phwnd,SW_RESTORE);
|
|
}
|
|
|
|
//
|
|
// If we are using whatever window and all the browser windows are busy
|
|
// (*phwnd == 0), or if there's no browser window opened (*phwnd == -1)
|
|
// or we are asked to create a new one, then take the official OLE automation
|
|
// route to start a new window.
|
|
//
|
|
if ((*phwnd == 0) ||
|
|
(*phwnd == (HWND)-1))
|
|
{
|
|
//BUGBUG: this route doesn't give us the ability to return the hwnd of the window
|
|
//in which the navigation took place (while we could - it's too hard and not worth it)
|
|
LPITEMIDLIST pidlNew;
|
|
TCHAR szURL[MAX_URL_STRING];
|
|
OleStrToStrN(szURL, ARRAYSIZE(szURL), str, (UINT)-1);
|
|
hres = IECreateFromPath(NULL, szURL, &pidlNew);
|
|
if (SUCCEEDED(hres)) {
|
|
// See if there is already a browser viewing this URL, if so just
|
|
// make him foreground otherwise create a new browser.
|
|
if ((hres = WinList_FindFolderWindow(pidlNew, NULL, phwnd, NULL)) == S_OK) {
|
|
ILFree(pidlNew);
|
|
SetForegroundWindow(*phwnd);
|
|
ShowWindow(*phwnd, SW_SHOWNORMAL);
|
|
}
|
|
else
|
|
{
|
|
_OpenNewFrame(pidlNew, NULL, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDDEAuto_get_LocationURL(BSTR * pstr, HWND hwnd)
|
|
{
|
|
return CDDEAuto_Common(DSID_GETLOCATIONURL, (LPARAM)pstr, &hwnd, FALSE);
|
|
}
|
|
|
|
HRESULT CDDEAuto_get_LocationTitle(BSTR * pstr, HWND hwnd)
|
|
{
|
|
return CDDEAuto_Common(DSID_GETLOCATIONTITLE, (LPARAM)pstr, &hwnd, FALSE);
|
|
}
|
|
|
|
HRESULT CDDEAuto_get_HWND(long * phwnd)
|
|
{
|
|
return CDDEAuto_Common(DSID_GETHWND, (LPARAM)phwnd, NULL, FALSE);
|
|
}
|
|
|
|
#if 0
|
|
HRESULT CDDEAuto_Cancel(HWND hwnd)
|
|
{
|
|
return CDDEAuto_Common_Specific(DSID_CANCEL, NULL, hwnd, FALSE);
|
|
}
|
|
#endif
|
|
|
|
HRESULT CDDEAuto_Exit()
|
|
{
|
|
return CDDEAuto_Common(DSID_EXIT, (LPARAM)NULL, NULL, FALSE);
|
|
}
|
|
|
|
HRESULT CShellBrowser::QueryService(REFGUID guidService, REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualGUID(guidService, SID_SExplorerToolbar)) {
|
|
if (_aTBar[ITB_ITBAR].ptbar) {
|
|
return _aTBar[ITB_ITBAR].ptbar->QueryInterface(riid, ppvObj);
|
|
}
|
|
}
|
|
|
|
return SUPERCLASS::QueryService(guidService, riid, ppvObj);
|
|
}
|
|
|
|
HRESULT CShellBrowser::EnableModelessSB(BOOL fEnable)
|
|
{
|
|
HRESULT hres = SUPERCLASS::EnableModelessSB(fEnable);
|
|
EnableMenuItem(GetSystemMenu(_hwnd, FALSE), SC_CLOSE, _fDisableModeless() ?
|
|
(MF_BYCOMMAND | MF_GRAYED) : ( MF_BYCOMMAND| MF_ENABLED));
|
|
return hres;
|
|
}
|
|
|
|
LRESULT CALLBACK CShellBrowser::DummyTBWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CShellBrowser* pSB = (CShellBrowser*)GetWindowLong(hwnd, 0);
|
|
LRESULT lRes = 0L;
|
|
|
|
if (uMsg < WM_USER)
|
|
return(DefWindowProc(hwnd, uMsg, wParam, lParam));
|
|
else
|
|
{
|
|
switch (uMsg) {
|
|
|
|
case TB_ADDBITMAP:
|
|
pSB->_pxtb->AddBitmap(&CGID_ShellBrowser, BITMAP_NORMAL, (UINT)wParam, (TBADDBITMAP*)lParam, &lRes, RGB(192,192,192));
|
|
pSB->_pxtb->AddBitmap(&CGID_ShellBrowser, BITMAP_HOT, (UINT)wParam, (TBADDBITMAP*)lParam, &lRes, RGB(192,192,192));
|
|
break;
|
|
|
|
default:
|
|
if (pSB->_pxtb)
|
|
pSB->_pxtb->SendToolbarMsg(&CGID_ShellBrowser, uMsg, wParam, lParam, &lRes);
|
|
return lRes;
|
|
}
|
|
}
|
|
return lRes;
|
|
}
|
|
|
|
// When a view adds buttons with no text, the CInternet toolbar may call back and ask
|
|
// for the tooltip strings. Unfortunately, at that time _hwndView is not yet set and therefore
|
|
// the tooltip texts will not be set.
|
|
//
|
|
// So, to get around that, we do not add the buttons if there is no _hwndView (see ::SetToolbarItem)
|
|
// The CBaseBrowser's ::_SwitchActivationNow() is the one that sets the _hwndView. So when this hwnd is
|
|
// set then we add the buttons
|
|
//
|
|
// We send the WM_NOTIFYFORMAT because when CInternetToolbar::AddButtons calls back with the WM_NOTIFYs
|
|
// for the tooltips, we need to know whether or not the view is UNICODE or not.
|
|
void CShellBrowser::_SwitchActivationNow()
|
|
{
|
|
ASSERT(_psvPending);
|
|
|
|
SUPERCLASS::_SwitchActivationNow();
|
|
if (_lpPendingBtns)
|
|
{
|
|
_fUnicode = (SendMessage (_hwndView, WM_NOTIFYFORMAT, (WPARAM)_hwnd, NF_QUERY) == NFR_UNICODE);
|
|
if ((_pxtb) && (_hwndView))
|
|
_pxtb->AddButtons(&CGID_ShellBrowser, _nButtonsPending, _lpPendingBtns);
|
|
LocalFree(_lpPendingBtns);
|
|
_lpPendingBtns = NULL;
|
|
_nButtonsPending = 0;
|
|
}
|
|
}
|
|
|