Windows2000/private/shell/shdocvw/shbrowse.cpp.1488
2020-09-30 17:12:32 +02:00

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;
}
}