4075 lines
131 KiB
C++
4075 lines
131 KiB
C++
// stuff to fix:
|
|
// _hwndTray
|
|
// REVIEW, BUGBUG
|
|
|
|
// questions for chee:
|
|
// why no WinList_Register/WinList_Revoke
|
|
// - because we don't want targeted links and stuff to find us
|
|
// and navigate us
|
|
// need desktop to keep rooted PIDL info (g_psCR)?
|
|
// Desktop_GetRootPidl, used for persisting ROOTed explorers, qualifying
|
|
// for saving view info
|
|
|
|
|
|
#include "stdafx.h"
|
|
#pragma hdrstop
|
|
|
|
#include "bitbuck.h"
|
|
#include <iethread.h>
|
|
#include "apithk.h"
|
|
|
|
#include "mtpt.h"
|
|
|
|
#define DM_FOCUS 0 // focus
|
|
#define DM_SHUTDOWN DM_TRACE // shutdown
|
|
#define TF_SHDAUTO 0
|
|
#define DM_MISC DM_TRACE // misc/tmp
|
|
|
|
STDAPI_(void) CheckWinIniForAssocs();
|
|
|
|
BOOL GetOldWorkAreas(LPRECT lprc, DWORD* pdwNoOfOldWA);
|
|
void SaveOldWorkAreas(LPCRECT lprc, DWORD nOldWA);
|
|
|
|
BOOL UpdateAllDesktopSubscriptions();
|
|
|
|
//This is in deskreg.cpp
|
|
BOOL AdjustDesktopComponents(LPCRECT prcNewWorkAreas, int nNewWorkAreas,
|
|
LPCRECT prcOldMonitors, LPCRECT prcOldWorkAreas, int nOldWorkAreas);
|
|
|
|
// in defview.cpp
|
|
BOOL IsFolderWindow(HWND hwnd);
|
|
|
|
// in deskfldr.cpp
|
|
STDAPI_(void) Desktop_InvalidateEnumCache(LPCITEMIDLIST pidl, LONG lEvent);
|
|
|
|
|
|
// copied from tray.c if changing here, change there also
|
|
#define GHID_FIRST 500
|
|
|
|
#define g_cxPrimaryDisplay GetSystemMetrics(SM_CXSCREEN)
|
|
#define g_cyPrimaryDisplay GetSystemMetrics(SM_CYSCREEN)
|
|
#define g_xVirtualScreen GetSystemMetrics(SM_XVIRTUALSCREEN)
|
|
#define g_yVirtualScreen GetSystemMetrics(SM_YVIRTUALSCREEN)
|
|
#define g_cxVirtualScreen GetSystemMetrics(SM_CXVIRTUALSCREEN)
|
|
#define g_cyVirtualScreen GetSystemMetrics(SM_CYVIRTUALSCREEN)
|
|
#define g_cxEdge GetSystemMetrics(SM_CXEDGE)
|
|
#define g_cyEdge GetSystemMetrics(SM_CYEDGE)
|
|
|
|
// TOID_Desktop is the id for ShellTasks added by the desktop
|
|
GUID TOID_Desktop = { /* 6aec6a60-b7a4-11d1-be89-0000f805ca57 */
|
|
0x6aec6a60,
|
|
0xb7a4,
|
|
0x11d1,
|
|
{0xbe, 0x89, 0x00, 0x00, 0xf8, 0x05, 0xca, 0x57}
|
|
};
|
|
|
|
// Private interface to talk to explorer.exe
|
|
IDeskTray* g_pdtray = NULL;
|
|
|
|
#define RECTWIDTH(rc) ((rc).right-(rc).left)
|
|
#define RECTHEIGHT(rc) ((rc).bottom-(rc).top)
|
|
|
|
#define IDT_DISKFULL 2 // one timer ID for each possible drive
|
|
#define IDT_DISKFULLLAST (IDT_DISKFULL + 26)
|
|
|
|
#define DISKFULL_TIMEOUT (3 * 1000) // 3 seconds
|
|
|
|
void FireEventSz(LPCTSTR szEvent)
|
|
{
|
|
HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, szEvent);
|
|
if (hEvent)
|
|
{
|
|
SetEvent(hEvent);
|
|
CloseHandle(hEvent);
|
|
}
|
|
}
|
|
|
|
#ifdef UNICODE // {
|
|
#define FireEventW(pszEvent) FireEventSz(pszEvent)
|
|
#else
|
|
void FireEventW(LPCWSTR pszEvent)
|
|
{
|
|
CHAR szEvent[MAX_IEEVENTNAME];
|
|
SHUnicodeToAnsi(pszEvent, szEvent, ARRAYSIZE(szEvent));
|
|
FireEventSz(szEvent);
|
|
}
|
|
#endif // }
|
|
|
|
// MISC stuff duplicated in browseui {
|
|
HRESULT _ConvertPathToPidlW(IBrowserService2 *pbs, HWND hwnd, LPCWSTR pszPath, LPITEMIDLIST * ppidl)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
WCHAR wszCmdLine[MAX_URL_STRING]; // must be with pszPath
|
|
TCHAR szFixedUrl[MAX_URL_STRING];
|
|
TCHAR szParsedUrl[MAX_URL_STRING] = {'\0'};
|
|
DWORD dwUrlLen = ARRAYSIZE(szParsedUrl);
|
|
|
|
// Copy the command line into a temporary buffer
|
|
// so we can remove the surrounding quotes (if
|
|
// they exist)
|
|
SHUnicodeToTChar(pszPath, szFixedUrl, ARRAYSIZE(szFixedUrl));
|
|
PathUnquoteSpaces(szFixedUrl);
|
|
|
|
if (ParseURLFromOutsideSource(szFixedUrl, szParsedUrl, &dwUrlLen, NULL))
|
|
SHTCharToUnicode(szParsedUrl, wszCmdLine, ARRAYSIZE(wszCmdLine));
|
|
else
|
|
StrCpyNW(wszCmdLine, pszPath, ARRAYSIZE(wszCmdLine));
|
|
|
|
hres = pbs->IEParseDisplayName(CP_ACP, wszCmdLine, ppidl);
|
|
pbs->DisplayParseError(hres, wszCmdLine);
|
|
return hres;
|
|
}
|
|
// END of MISC stuff duplicated in browseui }
|
|
|
|
// Several places rely on the fact that IShellBrowser is the first interface
|
|
// we inherit (and therefore is what we use as our canonical IUnknown).
|
|
// Grep for IUnknownIdentity to find them.
|
|
|
|
class CDesktopBrowser :
|
|
public IShellBrowser
|
|
,public IServiceProvider
|
|
,public IOleCommandTarget
|
|
,public IDockingWindowSite
|
|
,public IInputObjectSite
|
|
,public IDropTarget
|
|
,public IDockingWindowFrame
|
|
,public IMultiMonitorDockingSite
|
|
,public IBrowserService2
|
|
{
|
|
public:
|
|
// IUnknown
|
|
STDMETHOD(QueryInterface)(REFIID riid, void * *ppvObj);
|
|
virtual STDMETHODIMP_(ULONG) AddRef(void);
|
|
virtual STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
// IShellBrowser (same as IOleInPlaceFrame)
|
|
virtual STDMETHODIMP GetWindow(HWND * lphwnd);
|
|
virtual STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode);
|
|
virtual STDMETHODIMP InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
|
|
virtual STDMETHODIMP SetMenuSB(HMENU hmenuShared, HOLEMENU holemenu, HWND hwnd);
|
|
virtual STDMETHODIMP RemoveMenusSB(HMENU hmenuShared);
|
|
virtual STDMETHODIMP SetStatusTextSB(LPCOLESTR lpszStatusText);
|
|
virtual STDMETHODIMP EnableModelessSB(BOOL fEnable);
|
|
virtual STDMETHODIMP TranslateAcceleratorSB(LPMSG lpmsg, WORD wID);
|
|
virtual STDMETHODIMP BrowseObject(LPCITEMIDLIST pidl, UINT wFlags);
|
|
virtual STDMETHODIMP GetViewStateStream(DWORD grfMode, LPSTREAM *ppStrm);
|
|
virtual STDMETHODIMP GetControlWindow(UINT id, HWND * lphwnd);
|
|
virtual STDMETHODIMP SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret);
|
|
virtual STDMETHODIMP QueryActiveShellView(struct IShellView ** ppshv);
|
|
virtual STDMETHODIMP OnViewWindowActive(struct IShellView * ppshv);
|
|
virtual STDMETHODIMP SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags);
|
|
|
|
// IServiceProvider
|
|
virtual STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppvObj);
|
|
|
|
// IOleCommandTarget
|
|
virtual STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext);
|
|
virtual STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
|
|
|
|
// IDockingWindowSite (also IOleWindow)
|
|
virtual STDMETHODIMP GetBorderDW(IUnknown* punkSrc, LPRECT lprectBorder);
|
|
virtual STDMETHODIMP RequestBorderSpaceDW(IUnknown* punkSrc, LPCBORDERWIDTHS pborderwidths);
|
|
virtual STDMETHODIMP SetBorderSpaceDW(IUnknown* punkSrc, LPCBORDERWIDTHS pborderwidths);
|
|
|
|
// IInputObjectSite
|
|
virtual STDMETHODIMP OnFocusChangeIS(IUnknown* punkSrc, BOOL fSetFocus);
|
|
|
|
// IDropTarget
|
|
virtual STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
|
|
virtual STDMETHODIMP DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
|
|
virtual STDMETHODIMP DragLeave(void);
|
|
virtual STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
|
|
|
|
// IDockingWindowFrame (also IOleWindow)
|
|
virtual STDMETHODIMP AddToolbar(IUnknown* punkSrc, LPCWSTR pwszItem, DWORD dwReserved);
|
|
virtual STDMETHODIMP RemoveToolbar(IUnknown* punkSrc, DWORD dwFlags);
|
|
virtual STDMETHODIMP FindToolbar(LPCWSTR pwszItem, REFIID riid, void **ppvObj);
|
|
|
|
// IMultiMonitorDockingSite
|
|
virtual STDMETHODIMP GetMonitor(IUnknown* punkSrc, HMONITOR * phMon);
|
|
virtual STDMETHODIMP RequestMonitor(IUnknown* punkSrc, HMONITOR * phMon);
|
|
virtual STDMETHODIMP SetMonitor(IUnknown* punkSrc, HMONITOR hMon, HMONITOR * phMonOld);
|
|
|
|
static LRESULT CALLBACK DesktopWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
static LRESULT CALLBACK RaisedWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
void _MessageLoop();
|
|
HWND GetTrayWindow(void) { return _hwndTray; }
|
|
HWND GetDesktopWindow(void) { return _pbbd->_hwnd; }
|
|
|
|
// IBrowserService
|
|
// *** IBrowserService specific methods ***
|
|
virtual STDMETHODIMP GetParentSite( IOleInPlaceSite** ppipsite) ;
|
|
virtual STDMETHODIMP SetTitle( IShellView* psv, LPCWSTR pszName) ;
|
|
virtual STDMETHODIMP GetTitle( IShellView* psv, LPWSTR pszName, DWORD cchName) ;
|
|
virtual STDMETHODIMP GetOleObject( IOleObject** ppobjv) ;
|
|
virtual STDMETHODIMP GetTravelLog( ITravelLog** pptl) ;
|
|
virtual STDMETHODIMP ShowControlWindow( UINT id, BOOL fShow) ;
|
|
virtual STDMETHODIMP IsControlWindowShown( UINT id, BOOL *pfShown) ;
|
|
virtual STDMETHODIMP IEGetDisplayName( LPCITEMIDLIST pidl, LPWSTR pwszName, UINT uFlags) ;
|
|
virtual STDMETHODIMP IEParseDisplayName( UINT uiCP, LPCWSTR pwszPath, LPITEMIDLIST * ppidlOut) ;
|
|
virtual STDMETHODIMP DisplayParseError( HRESULT hres, LPCWSTR pwszPath) ;
|
|
virtual STDMETHODIMP NavigateToPidl( LPCITEMIDLIST pidl, DWORD grfHLNF) ;
|
|
virtual STDMETHODIMP SetNavigateState( BNSTATE bnstate) ;
|
|
virtual STDMETHODIMP GetNavigateState ( BNSTATE *pbnstate) ;
|
|
virtual STDMETHODIMP NotifyRedirect ( IShellView* psv, LPCITEMIDLIST pidl, BOOL *pfDidBrowse) ;
|
|
virtual STDMETHODIMP UpdateWindowList () ;
|
|
virtual STDMETHODIMP UpdateBackForwardState () ;
|
|
virtual STDMETHODIMP SetFlags( DWORD dwFlags, DWORD dwFlagMask) ;
|
|
virtual STDMETHODIMP GetFlags( DWORD *pdwFlags) ;
|
|
virtual STDMETHODIMP CanNavigateNow () ;
|
|
virtual STDMETHODIMP GetPidl( LPITEMIDLIST *ppidl) ;
|
|
virtual STDMETHODIMP SetReferrer ( LPITEMIDLIST pidl) ;
|
|
virtual STDMETHODIMP_(DWORD) GetBrowserIndex() ;
|
|
virtual STDMETHODIMP GetBrowserByIndex( DWORD dwID, IUnknown **ppunk) ;
|
|
virtual STDMETHODIMP GetHistoryObject( IOleObject **ppole, IStream **pstm, IBindCtx **ppbc) ;
|
|
virtual STDMETHODIMP SetHistoryObject( IOleObject *pole, BOOL fIsLocalAnchor) ;
|
|
virtual STDMETHODIMP CacheOLEServer( IOleObject *pole) ;
|
|
virtual STDMETHODIMP GetSetCodePage( VARIANT* pvarIn, VARIANT* pvarOut) ;
|
|
virtual STDMETHODIMP OnHttpEquiv( IShellView* psv, BOOL fDone, VARIANT* pvarargIn, VARIANT* pvarargOut) ;
|
|
virtual STDMETHODIMP GetPalette( HPALETTE * hpal ) ;
|
|
virtual STDMETHODIMP RegisterWindow( BOOL fUnregister, int swc) ;
|
|
virtual STDMETHODIMP_(LRESULT) WndProcBS( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) ;
|
|
virtual STDMETHODIMP OnSize(WPARAM wParam);
|
|
virtual STDMETHODIMP OnCreate(LPCREATESTRUCT pcs);
|
|
virtual STDMETHODIMP_(LRESULT) OnCommand(WPARAM wParam, LPARAM lParam);
|
|
virtual STDMETHODIMP OnDestroy();
|
|
virtual STDMETHODIMP_(LRESULT) OnNotify(NMHDR * pnm);
|
|
virtual STDMETHODIMP OnSetFocus();
|
|
virtual STDMETHODIMP OnFrameWindowActivateBS(BOOL fActive);
|
|
virtual STDMETHODIMP ReleaseShellView( ) ;
|
|
virtual STDMETHODIMP ActivatePendingView( ) ;
|
|
virtual STDMETHODIMP CreateViewWindow(IShellView* psvNew, IShellView* psvOld, LPRECT prcView, HWND* phwnd);
|
|
virtual STDMETHODIMP GetBaseBrowserData( LPCBASEBROWSERDATA* ppbd );
|
|
virtual STDMETHODIMP_(LPBASEBROWSERDATA) PutBaseBrowserData();
|
|
virtual STDMETHODIMP SetAsDefFolderSettings() { ASSERT(FALSE); return E_NOTIMPL;}
|
|
virtual STDMETHODIMP SetTopBrowser();
|
|
virtual STDMETHODIMP UpdateSecureLockIcon(int eSecureLock);
|
|
virtual STDMETHODIMP Offline(int iCmd);
|
|
virtual STDMETHODIMP InitializeDownloadManager();
|
|
virtual STDMETHODIMP InitializeTransitionSite();
|
|
virtual STDMETHODIMP GetFolderSetData(struct tagFolderSetData* pfsd) { *pfsd = _fsd; return S_OK; };
|
|
virtual STDMETHODIMP _OnFocusChange(UINT itb);
|
|
virtual STDMETHODIMP v_ShowHideChildWindows(BOOL fChildOnly);
|
|
virtual STDMETHODIMP CreateBrowserPropSheetExt(THIS_ REFIID riid, void **ppvObj);
|
|
virtual STDMETHODIMP SetActivateState(UINT uActivate);
|
|
virtual STDMETHODIMP AllowViewResize(BOOL f);
|
|
virtual STDMETHODIMP _Initialize(HWND hwnd, IUnknown *pauto);
|
|
virtual STDMETHODIMP_(UINT) _get_itbLastFocus();
|
|
virtual STDMETHODIMP _put_itbLastFocus(UINT itbLastFocus);
|
|
virtual STDMETHODIMP _UIActivateView(UINT uState) ;
|
|
virtual STDMETHODIMP _CancelPendingNavigationAsync() ;
|
|
virtual STDMETHODIMP _MaySaveChanges() ;
|
|
virtual STDMETHODIMP _PauseOrResumeView( BOOL fPaused) ;
|
|
virtual STDMETHODIMP _DisableModeless() ;
|
|
virtual STDMETHODIMP _NavigateToPidl( LPCITEMIDLIST pidl, DWORD grfHLNF, DWORD dwFlags);
|
|
virtual STDMETHODIMP _TryShell2Rename( IShellView* psv, LPCITEMIDLIST pidlNew);
|
|
virtual STDMETHODIMP _SwitchActivationNow( );
|
|
virtual STDMETHODIMP _CancelPendingView() ;
|
|
virtual STDMETHODIMP _ExecChildren(IUnknown *punkBar, BOOL fBroadcast,
|
|
const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
|
|
VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
|
|
virtual STDMETHODIMP _SendChildren(HWND hwndBar, BOOL fBroadcast,
|
|
UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
virtual STDMETHODIMP v_MayGetNextToolbarFocus(LPMSG lpMsg, UINT itbNext, int citb, LPTOOLBARITEM * pptbi, HWND * phwnd);
|
|
virtual STDMETHODIMP _SetFocus(LPTOOLBARITEM ptbi, HWND hwnd, LPMSG lpMsg) { ASSERT(FALSE); return E_NOTIMPL; }
|
|
virtual STDMETHODIMP _GetViewBorderRect(RECT* prc);
|
|
virtual STDMETHODIMP _UpdateViewRectSize();
|
|
virtual STDMETHODIMP _ResizeNextBorder(UINT itb);
|
|
virtual STDMETHODIMP _ResizeView();
|
|
virtual STDMETHODIMP _GetEffectiveClientArea(LPRECT lprectBorder, HMONITOR hmon);
|
|
virtual STDMETHODIMP GetCurrentFolderSettings(DEFFOLDERSETTINGS *pdfs, int cbDfs) { ASSERT(FALSE); return E_NOTIMPL; }
|
|
virtual STDMETHODIMP GetViewRect(RECT* prc);
|
|
virtual STDMETHODIMP GetViewWindow(HWND * phwndView);
|
|
virtual STDMETHODIMP InitializeTravelLog(ITravelLog* ptl, DWORD dw);
|
|
|
|
// Desktop needs to override these:
|
|
virtual STDMETHODIMP_(IStream*) v_GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCWSTR pwszName);
|
|
|
|
// Desktop needs access to these:
|
|
virtual STDMETHODIMP_(LRESULT) ForwardViewMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) { ASSERT(FALSE); return 0; };
|
|
virtual STDMETHODIMP SetAcceleratorMenu(HACCEL hacc) { ASSERT(FALSE); return E_FAIL; }
|
|
virtual STDMETHODIMP_(int) _GetToolbarCount(THIS) { ASSERT(FALSE); return 0; }
|
|
virtual STDMETHODIMP_(LPTOOLBARITEM) _GetToolbarItem(THIS_ int itb) { ASSERT(FALSE); return NULL; }
|
|
virtual STDMETHODIMP _SaveToolbars(IStream* pstm) { ASSERT(FALSE); return E_NOTIMPL; }
|
|
virtual STDMETHODIMP _LoadToolbars(IStream* pstm) { ASSERT(FALSE); return E_NOTIMPL; }
|
|
virtual STDMETHODIMP _CloseAndReleaseToolbars(BOOL fClose) { ASSERT(FALSE); return E_NOTIMPL; }
|
|
virtual STDMETHODIMP_(UINT) _FindTBar(IUnknown* punkSrc) { ASSERT(FALSE); return (UINT)-1; };
|
|
virtual STDMETHODIMP v_MayTranslateAccelerator(MSG* pmsg) { ASSERT(FALSE); return E_NOTIMPL; }
|
|
virtual STDMETHODIMP _GetBorderDWHelper(IUnknown* punkSrc, LPRECT lprectBorder, BOOL bUseHmonitor) { ASSERT(FALSE); return E_NOTIMPL; }
|
|
|
|
// Shell browser overrides this.
|
|
virtual STDMETHODIMP v_CheckZoneCrossing(LPCITEMIDLIST pidl) {return S_OK;};
|
|
|
|
// Desktop and basesb need access to these:
|
|
virtual STDMETHODIMP _ResizeNextBorderHelper(UINT itb, BOOL bUseHmonitor);
|
|
|
|
// it just for us of course!
|
|
void StartBackgroundShellTasks(void);
|
|
protected:
|
|
CDesktopBrowser();
|
|
~CDesktopBrowser();
|
|
|
|
friend HRESULT CDesktopBrowser_CreateInstance(HWND hwnd, void **ppsb);
|
|
HRESULT SetInner(IUnknown* punk);
|
|
|
|
long _cRef;
|
|
|
|
// cached pointers on inner object
|
|
IUnknown* _punkInner;
|
|
IBrowserService2* _pbsInner;
|
|
IShellBrowser* _psbInner;
|
|
IServiceProvider* _pspInner;
|
|
IOleCommandTarget* _pctInner;
|
|
IDockingWindowSite* _pdwsInner;
|
|
IDockingWindowFrame* _pdwfInner;
|
|
IInputObjectSite* _piosInner;
|
|
IDropTarget* _pdtInner;
|
|
|
|
LPCBASEBROWSERDATA _pbbd;
|
|
|
|
LRESULT _RaisedWndProc(UINT msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
void _PositionViewWindow(HWND hwnd, LPRECT prc);
|
|
void _OnChangeNotify(LONG lNotification, LPITEMIDLIST *ppidl);
|
|
void _SetViewArea();
|
|
|
|
void _GetViewBorderRects(int nRects, LPRECT prc); // does not have the tool bars
|
|
void _SetWorkAreas(int nWorkAreas, RECT * prcWork);
|
|
|
|
void _SubtractBottommostTray(LPRECT prc);
|
|
void _SaveState();
|
|
void _InitDeskbars();
|
|
void _SaveDesktopToolbars();
|
|
|
|
void _OnRaise(WPARAM wParam, LPARAM lParam);
|
|
void _SetupAppRan(WPARAM wParam, LPARAM lParam);
|
|
#ifdef WINNT
|
|
BOOL _QueryHKCRChanged(HWND hwnd, LPDWORD pdwCookie);
|
|
#endif //WINNT
|
|
void _Lower();
|
|
void _Raise();
|
|
void _SwapParents(HWND hwndOldParent, HWND hwndNewParent);
|
|
|
|
BOOL _OnCopyData(PCOPYDATASTRUCT pcds);
|
|
void _OnAddToRecent( HANDLE hMem, DWORD dwProcId );
|
|
BOOL _InitScheduler(void);
|
|
HRESULT _AddDesktopTask(IRunnableTask *ptask, DWORD dwPriority);
|
|
|
|
BOOL _PtOnDesktopEdge(POINTL* ppt, LPUINT puEdge);
|
|
#ifdef DEBUG
|
|
void _CreateDeskbars();
|
|
#endif
|
|
|
|
HRESULT _CreateDeskBarForBand(UINT uEdge, IUnknown *punk, POINTL *pptl, IBandSite **pbs);
|
|
|
|
virtual void v_PropagateMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fSend);
|
|
HRESULT _OnFocusMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
HRESULT _CreateDesktopView();
|
|
HWND _GetDesktopListview();
|
|
UINT _PeekForAMessage();
|
|
|
|
void _InitMonitors();
|
|
|
|
#ifdef ENABLE_CHANNELS
|
|
void _MaybeLaunchChannelBand(void );
|
|
#endif
|
|
|
|
virtual void _ViewChange(DWORD dwAspect, LONG lindex);
|
|
|
|
HWND _hwndTray;
|
|
int _iWaitCount;
|
|
DWORD _dwDiskFullDrives;
|
|
ULONG _uNotifyID;
|
|
|
|
DWORD _grfKeyState;
|
|
DWORD _dwEffectOnEdge; // what's the drop effect that desktop should return on dragging over the edge
|
|
|
|
BOOL _fRaised :1;
|
|
HWND _hwndRaised; // this is the parent of all of desktop's children when raised
|
|
|
|
struct tagFolderSetData _fsd;
|
|
|
|
int _nMonitors; // number of monitors on this desktop
|
|
HMONITOR _hMonitors[LV_MAX_WORKAREAS]; // the order of these hmonitors need to be preserved
|
|
RECT _rcWorkArea; // cached work-area
|
|
RECT _rcOldWorkAreas[LV_MAX_WORKAREAS]; // Old work areas before settings change
|
|
DWORD _nOldWork;
|
|
RECT _rcOldMonitors[LV_MAX_WORKAREAS]; // Old monitor sizes before settings change
|
|
|
|
// for _OnAddToRecent()
|
|
IShellTaskScheduler *_psched;
|
|
|
|
#ifdef WINNT
|
|
DWORD _cChangeEvents;
|
|
HANDLE _rghChangeEvents[2]; // we watch HKCR and HKCR\CLSID
|
|
DWORD _dwChangeCookie;
|
|
DWORD _rgdwQHKCRCookies[QHKCRID_MAX - QHKCRID_MIN];
|
|
HKEY _hkClsid;
|
|
#endif
|
|
|
|
WCHAR _wzDesktopTitle[64]; // Localized Title
|
|
|
|
// IUnknownIdentity - for uniformity w.r.t. aggregation
|
|
// We are not aggregatable, so we are our own Outer.
|
|
IUnknown *_GetOuter() { return SAFECAST(this, IShellBrowser*); }
|
|
|
|
};
|
|
|
|
HRESULT CDesktopBrowser_CreateInstance(HWND hwnd, void **ppsb)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CDesktopBrowser *pdb = new CDesktopBrowser();
|
|
|
|
if (pdb)
|
|
{
|
|
hr = pdb->_Initialize(hwnd, NULL); // aggregation, etc.
|
|
if (FAILED(hr))
|
|
ATOMICRELEASE(pdb);
|
|
}
|
|
|
|
*ppsb = pdb;
|
|
return hr;
|
|
}
|
|
|
|
CDesktopBrowser::CDesktopBrowser() :
|
|
_cRef(1)
|
|
{
|
|
TraceMsg(TF_LIFE, "ctor CDesktopBrowser %x", this);
|
|
}
|
|
|
|
CDesktopBrowser::~CDesktopBrowser()
|
|
{
|
|
SaveOldWorkAreas(_rcOldWorkAreas, _nOldWork);
|
|
|
|
#ifdef WINNT
|
|
// cleanup for QueryHKCRChanged()
|
|
for (int i = 0; i < ARRAYSIZE(_rghChangeEvents); i++)
|
|
{
|
|
if (_rghChangeEvents[i])
|
|
CloseHandle(_rghChangeEvents[i]);
|
|
}
|
|
|
|
if (_hkClsid)
|
|
RegCloseKey(_hkClsid);
|
|
#endif // WINNT
|
|
|
|
TraceMsg(TF_LIFE, "dtor CDesktopBrowser %x", this);
|
|
}
|
|
|
|
|
|
HRESULT CDesktopBrowser::_Initialize(HWND hwnd, IUnknown* pauto)
|
|
{
|
|
IUnknown* punk;
|
|
|
|
HRESULT hres = CoCreateInstance(CLSID_CCommonBrowser, _GetOuter(), CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&punk);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = SetInner(punk); // paired w/ Release in outer (TBS::Release)
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
// we must initialize the inner guy BEFORE we call through any of these pointers.
|
|
hres = _pbsInner->_Initialize(hwnd, pauto);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
_pbsInner->GetBaseBrowserData(&_pbbd);
|
|
ASSERT(_pbbd);
|
|
|
|
// Restore the old settings from the registry that we persist.
|
|
if (!GetOldWorkAreas(_rcOldWorkAreas, &_nOldWork) || _nOldWork == 0)
|
|
{
|
|
// We didn't find it in the registry
|
|
_nOldWork = 0; // Since this is 0, we don't have to set _rcOldWorkAreas.
|
|
//We will recover from this in _SetWorkAreas()
|
|
}
|
|
|
|
SetTopBrowser();
|
|
_put_itbLastFocus(ITB_VIEW); // focus on desktop (w95 compat)
|
|
|
|
HACCEL hacc = LoadAccelerators(HINST_THISDLL, MAKEINTRESOURCE(ACCEL_DESKTOP));
|
|
ASSERT(hacc);
|
|
_pbsInner->SetAcceleratorMenu(hacc);
|
|
|
|
// Perf: never fire events from the desktop.
|
|
ASSERT(_pbbd->_pautoEDS);
|
|
ATOMICRELEASE(_pbbd->_pautoEDS);
|
|
|
|
_InitMonitors();
|
|
|
|
// Initialise _rcOldMonitors
|
|
for (int i = 0; i < _nMonitors; i++)
|
|
{
|
|
GetMonitorRect(_hMonitors[i], &_rcOldMonitors[i]);
|
|
}
|
|
#ifdef WINNT
|
|
// NOTE: if we have any more keys to watch, then
|
|
// we should create a static struct to walk
|
|
// so that it is easier to add more event/key pairs
|
|
_rghChangeEvents[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
_rghChangeEvents[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (_rghChangeEvents[0] && _rghChangeEvents[1])
|
|
{
|
|
if (ERROR_SUCCESS == RegNotifyChangeKeyValue(HKEY_CLASSES_ROOT, TRUE,
|
|
REG_NOTIFY_CHANGE_LAST_SET |REG_NOTIFY_CHANGE_NAME, _rghChangeEvents[0], TRUE))
|
|
{
|
|
_cChangeEvents = 1;
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("CLSID"), 0, MAXIMUM_ALLOWED, &_hkClsid)
|
|
&& ERROR_SUCCESS == RegNotifyChangeKeyValue(_hkClsid, TRUE, REG_NOTIFY_CHANGE_LAST_SET |REG_NOTIFY_CHANGE_NAME, _rghChangeEvents[1], TRUE))
|
|
{
|
|
// we need to leave the key open,
|
|
// or the event is signaled right away
|
|
_cChangeEvents++;
|
|
}
|
|
}
|
|
}
|
|
#endif //WINNT
|
|
}
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(!"CoCreateInstance(CLSID_CCommonBrowser failed - big trouble");
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
|
|
// The refcount in the punk is transferred to us. We do not need to
|
|
// and indeed should not AddRef it.
|
|
|
|
// If any of these steps fails, we will clean up in our destructor.
|
|
|
|
HRESULT CDesktopBrowser::SetInner(IUnknown* punk)
|
|
{
|
|
HRESULT hres;
|
|
|
|
ASSERT(_punkInner == NULL);
|
|
|
|
_punkInner = punk;
|
|
|
|
#define INNERCACHE(iid, p) do { \
|
|
hres = SHQueryInnerInterface(_GetOuter(), punk, iid, (void **)&p); \
|
|
if (!EVAL(SUCCEEDED(hres))) return E_FAIL; \
|
|
} while (0)
|
|
|
|
INNERCACHE(IID_IBrowserService2, _pbsInner);
|
|
INNERCACHE(IID_IShellBrowser, _psbInner);
|
|
INNERCACHE(IID_IServiceProvider, _pspInner);
|
|
INNERCACHE(IID_IOleCommandTarget, _pctInner);
|
|
INNERCACHE(IID_IDockingWindowSite, _pdwsInner);
|
|
INNERCACHE(IID_IDockingWindowFrame, _pdwfInner);
|
|
INNERCACHE(IID_IInputObjectSite, _piosInner);
|
|
INNERCACHE(IID_IDropTarget, _pdtInner);
|
|
|
|
#undef INNERCACHE
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG CDesktopBrowser::AddRef()
|
|
{
|
|
return InterlockedIncrement(&_cRef);
|
|
}
|
|
|
|
ULONG CDesktopBrowser::Release()
|
|
{
|
|
ASSERT(_cRef > 0);
|
|
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
_cRef = 1000; // guard against recursion
|
|
|
|
RELEASEINNERINTERFACE(_GetOuter(), _pbsInner);
|
|
RELEASEINNERINTERFACE(_GetOuter(), _psbInner);
|
|
RELEASEINNERINTERFACE(_GetOuter(), _pspInner);
|
|
RELEASEINNERINTERFACE(_GetOuter(), _pctInner);
|
|
RELEASEINNERINTERFACE(_GetOuter(), _pdwsInner);
|
|
RELEASEINNERINTERFACE(_GetOuter(), _pdwfInner);
|
|
RELEASEINNERINTERFACE(_GetOuter(), _piosInner);
|
|
RELEASEINNERINTERFACE(_GetOuter(), _pdtInner);
|
|
|
|
// this must come last
|
|
ATOMICRELEASE(_punkInner); // paired w/ CCI aggregation
|
|
|
|
ASSERT(_cRef == 1000);
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::QueryInterface(REFIID riid, void * * ppvObj)
|
|
{
|
|
// IUnknownIdentity - The interface we use for IUnknown must come first.
|
|
static const QITAB qit[] = {
|
|
QITABENT(CDesktopBrowser, IShellBrowser),
|
|
QITABENT(CDesktopBrowser, IBrowserService2),
|
|
QITABENTMULTI(CDesktopBrowser, IBrowserService, IBrowserService2),
|
|
QITABENTMULTI(CDesktopBrowser, IOleWindow, IShellBrowser),
|
|
QITABENTMULTI2(CDesktopBrowser, SID_SShellDesktop, IShellBrowser), // effectively an IUnknown supported only by this class
|
|
QITABENT(CDesktopBrowser, IServiceProvider),
|
|
QITABENT(CDesktopBrowser, IOleCommandTarget),
|
|
QITABENT(CDesktopBrowser, IDockingWindowSite),
|
|
QITABENT(CDesktopBrowser, IInputObjectSite),
|
|
QITABENT(CDesktopBrowser, IMultiMonitorDockingSite),
|
|
QITABENT(CDesktopBrowser, IDropTarget),
|
|
{ 0 },
|
|
};
|
|
|
|
HRESULT hres = QISearch(this, qit, riid, ppvObj);
|
|
|
|
if (FAILED(hres)) {
|
|
if (_punkInner)
|
|
{
|
|
// don't let these get through to our base class...
|
|
// IID_IOleCommandTarget, IID_IOleInPlaceUIWindow
|
|
// BUGBUG 970414 adp: spoke to SatoNa, these *can* go thru
|
|
// i'll remove this week
|
|
if (IsEqualIID(riid, IID_IOleInPlaceUIWindow))
|
|
{
|
|
*ppvObj = NULL;
|
|
hres = E_NOINTERFACE;
|
|
}
|
|
else
|
|
{
|
|
hres = _punkInner->QueryInterface(riid, ppvObj);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
void _InitDesktopMetrics(WPARAM wParam, LPCTSTR pszSection)
|
|
{
|
|
BOOL fForce = (!pszSection || !*pszSection);
|
|
|
|
if (fForce || (wParam == SPI_SETNONCLIENTMETRICS) || !lstrcmpi(pszSection, TEXT("WindowMetrics")))
|
|
{
|
|
FileIconInit(TRUE); // Tell the shell we want to play with a full deck
|
|
|
|
// BUGBUG do this
|
|
// InvalidateImageIndices();
|
|
}
|
|
}
|
|
|
|
typedef struct _EnumMonitorsData
|
|
{
|
|
int iMonitors;
|
|
HMONITOR * phMonitors;
|
|
} EnumMonitorsData;
|
|
|
|
BOOL CALLBACK MultiMonEnumCallBack(HMONITOR hMonitor, HDC hdc, LPRECT lprc, LPARAM lData)
|
|
{
|
|
EnumMonitorsData * pEmd = (EnumMonitorsData *)lData;
|
|
|
|
if (pEmd->iMonitors > LV_MAX_WORKAREAS - 1)
|
|
//ignore the other monitors because we can only handle up to LV_MAX_WORKAREAS
|
|
//BUGBUG: should we dynamically allocated this?
|
|
return FALSE;
|
|
|
|
pEmd->phMonitors[pEmd->iMonitors++] = hMonitor;
|
|
return TRUE;
|
|
}
|
|
|
|
// Initialize the number of monitors and the hmonitors array
|
|
|
|
void CDesktopBrowser::_InitMonitors()
|
|
{
|
|
HMONITOR hMonPrimary = GetPrimaryMonitor();
|
|
|
|
EnumMonitorsData emd;
|
|
emd.iMonitors = 0;
|
|
emd.phMonitors = _hMonitors;
|
|
|
|
EnumDisplayMonitors(NULL, NULL, MultiMonEnumCallBack, (LPARAM)&emd);
|
|
_nMonitors = GetNumberOfMonitors();
|
|
|
|
// Always move the primary monitor to the first location.
|
|
if (_hMonitors[0] != hMonPrimary)
|
|
{
|
|
int iMon;
|
|
for (iMon = 1; iMon < _nMonitors; iMon++)
|
|
{
|
|
if (_hMonitors[iMon] == hMonPrimary)
|
|
{
|
|
_hMonitors[iMon] = _hMonitors[0];
|
|
_hMonitors[0] = hMonPrimary;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Gets the persisted old work areas, from the registry
|
|
BOOL GetOldWorkAreas(LPRECT lprc, DWORD* pdwNoOfOldWA)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
*pdwNoOfOldWA = 0;
|
|
HKEY hkey;
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, REG_DESKCOMP_OLDWORKAREAS, 0, KEY_READ, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD dwType, cbSize = SIZEOF(*pdwNoOfOldWA);
|
|
// Read in the no of old work areas
|
|
if (SHQueryValueEx(hkey, REG_VAL_OLDWORKAREAS_COUNT, NULL, &dwType, (LPBYTE)pdwNoOfOldWA, &cbSize) == ERROR_SUCCESS)
|
|
{
|
|
// Read in the old work area rects
|
|
cbSize = SIZEOF(*lprc) * (*pdwNoOfOldWA);
|
|
if (SHQueryValueEx(hkey, REG_VAL_OLDWORKAREAS_RECTS, NULL, &dwType, (LPBYTE)lprc, &cbSize) == ERROR_SUCCESS)
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
return fRet;
|
|
}
|
|
|
|
// Saves the old work areas into the registry
|
|
void SaveOldWorkAreas(LPCRECT lprc, DWORD nOldWA)
|
|
{
|
|
// Recreate the registry key.
|
|
HKEY hkey;
|
|
if (RegCreateKey(HKEY_CURRENT_USER, REG_DESKCOMP_OLDWORKAREAS, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
// Write out the no. of old work areas
|
|
RegSetValueEx(hkey, REG_VAL_OLDWORKAREAS_COUNT, 0, REG_DWORD, (LPBYTE)&nOldWA, SIZEOF(nOldWA));
|
|
// Write out the no work area rectangles
|
|
RegSetValueEx(hkey, REG_VAL_OLDWORKAREAS_RECTS, 0, REG_BINARY, (LPBYTE)lprc, SIZEOF(*lprc) * nOldWA);
|
|
// Close out the reg key
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
//*** CDesktopBrowser::IOleCommandTarget::* {
|
|
|
|
STDMETHODIMP CDesktopBrowser::QueryStatus(const GUID *pguidCmdGroup,
|
|
ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
STDMETHODIMP CDesktopBrowser::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
|
|
DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
|
|
{
|
|
if (pguidCmdGroup == NULL) {
|
|
/*NOTHING*/
|
|
}
|
|
else if (IsEqualGUID(CGID_ShellDocView, *pguidCmdGroup)) {
|
|
switch (nCmdID) {
|
|
case SHDVID_RAISE:
|
|
// n.b.: DTRF_RAISE/DTRF_LOWER go down; DTRF_QUERY goes up
|
|
ASSERT(pvarargIn != NULL && pvarargIn->vt == VT_I4);
|
|
if (pvarargIn->vt == VT_I4 && pvarargIn->lVal == DTRF_QUERY) {
|
|
ASSERT(pvarargOut != NULL);
|
|
pvarargOut->vt = VT_I4;
|
|
pvarargOut->lVal = _fRaised ? DTRF_RAISE : DTRF_LOWER;
|
|
return S_OK;
|
|
}
|
|
// o.w. let parent handle it
|
|
break;
|
|
|
|
case SHDVID_UPDATEOFFLINEDESKTOP:
|
|
UpdateAllDesktopSubscriptions();
|
|
return S_OK;
|
|
}
|
|
} else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) {
|
|
switch (nCmdID)
|
|
{
|
|
case SBCMDID_OPTIONS:
|
|
case SBCMDID_ADDTOFAVORITES:
|
|
return _pctInner->Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
|
|
}
|
|
}
|
|
|
|
// do *not* forward up to SUPERCLASS::Exec (see QI's cryptic commment
|
|
// about "don't let these get thru to our base class")
|
|
return OLECMDERR_E_NOTSUPPORTED;
|
|
}
|
|
|
|
// }
|
|
|
|
STDMETHODIMP CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
|
|
{
|
|
// REVIEW: do we need this at all? does navigate come through here?
|
|
|
|
// Force SBSP_NEWBROWSER and SBSP_ABSOLUTE;
|
|
wFlags &= ~(SBSP_DEFBROWSER | SBSP_SAMEBROWSER | SBSP_RELATIVE | SBSP_PARENT);
|
|
wFlags |= (SBSP_NEWBROWSER | SBSP_ABSOLUTE);
|
|
return _psbInner->BrowseObject(pidl, wFlags);
|
|
}
|
|
|
|
IStream *GetDesktopViewStream(DWORD grfMode, LPCTSTR pszName)
|
|
{
|
|
HKEY hkStreams;
|
|
|
|
if (RegCreateKey(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\Streams"), &hkStreams) == ERROR_SUCCESS)
|
|
{
|
|
IStream *pstm = OpenRegStream(hkStreams, TEXT("Desktop"), pszName, grfMode);
|
|
RegCloseKey(hkStreams);
|
|
return pstm;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void DeleteDesktopViewStream(LPCTSTR pszName)
|
|
{
|
|
SHDeleteValue(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\Streams\\Desktop"), pszName);
|
|
}
|
|
|
|
#ifndef BUGBUG // export SHGetViewStream from BROWSEUI and make shdocvw,shell32 delay load it!
|
|
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;
|
|
}
|
|
|
|
IStream* GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCTSTR pszName, LPCTSTR pszStreamMRU, LPCTSTR pszStreams)
|
|
{
|
|
IStream *pstm = NULL;
|
|
HANDLE hmru;
|
|
int iFoundSlot = -1;
|
|
UINT cbPidl;
|
|
static DWORD s_dwMRUSize = 0;
|
|
DWORD dwSize = sizeof(s_dwMRUSize);
|
|
|
|
if ((0 == s_dwMRUSize) &&
|
|
(ERROR_SUCCESS != SHGetValue(HKEY_CURRENT_USER, pszStreamMRU, TEXT("MRU Size"), NULL, (LPVOID) &s_dwMRUSize, &dwSize)))
|
|
{
|
|
s_dwMRUSize = 200; // The default.
|
|
}
|
|
|
|
MRUINFO mi = {
|
|
SIZEOF(MRUINFO),
|
|
s_dwMRUSize, // we store this many view streams
|
|
MRU_BINARY,
|
|
HKEY_CURRENT_USER,
|
|
pszStreamMRU,
|
|
(MRUCMPPROC)MRUILIsEqual,
|
|
};
|
|
|
|
ASSERT(pidl);
|
|
|
|
// should be checked by caller - if this is not true we'll flush the
|
|
// MRU cache with internet pidls! FTP and other URL Shell Extension PIDLs
|
|
// that act like a folder and need similar persistence and fine. This
|
|
// is especially true because recently the cache size was increased from
|
|
// 30 or so to 200.
|
|
//ASSERT(pidl==c_pidlURLRoot || !IsURLChild(pidl, TRUE) || IsPidlFromURLShellExt(pidl));
|
|
|
|
cbPidl = ILGetSize(pidl);
|
|
|
|
// Now lets try to save away the other information associated with view.
|
|
hmru = CreateMRUListLazyEx(&mi, pidl, cbPidl, &iFoundSlot);
|
|
if (!hmru)
|
|
return NULL;
|
|
|
|
// 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;
|
|
|
|
|
|
// 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
|
|
|
|
hkCabStreams = SHGetExplorerSubHkey( HKEY_CURRENT_USER, pszStreams, TRUE );
|
|
if ( hkCabStreams )
|
|
{
|
|
HKEY hkValues;
|
|
TCHAR szValue[32], szSubVal[64];
|
|
|
|
wsprintf(szValue, TEXT("%d"), AddMRUDataEx(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
|
|
// BUGBUG NOTE: Why can't we use SHDeleteKey?
|
|
DWORD dwType;
|
|
|
|
while (dwSize = ARRAYSIZE(szSubVal),
|
|
ERROR_SUCCESS == RegEnumValue(hkValues, 0, szSubVal, &dwSize, NULL, &dwType, NULL, NULL))
|
|
{
|
|
if (RegDeleteValue(hkValues, szSubVal) != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkValues);
|
|
}
|
|
pstm = SHOpenRegStream(hkCabStreams, szValue, pszName, grfMode);
|
|
RegCloseKey(hkCabStreams);
|
|
}
|
|
}
|
|
|
|
FreeMRUListEx(hmru);
|
|
|
|
return pstm;
|
|
}
|
|
#endif // !BUGBUG
|
|
|
|
IStream *CDesktopBrowser::v_GetViewStream(LPCITEMIDLIST pidl, DWORD grfMode, LPCWSTR pwszName)
|
|
{
|
|
IStream *pstm;
|
|
TCHAR szName[MAX_PATH];
|
|
|
|
SHUnicodeToTChar(pwszName, szName, ARRAYSIZE(szName));
|
|
pstm = GetDesktopViewStream(grfMode, szName);
|
|
|
|
|
|
// Detect the very first boot and migrate the icon positoins from where
|
|
// Win95 has stored (OK to execute this code for NT as well).
|
|
|
|
if (grfMode == STGM_READ && !lstrcmpi(szName, TEXT("ViewView")) &&
|
|
(!pstm || SHIsEmptyStream(pstm)))
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_DESKTOPDIRECTORY, TRUE))
|
|
{
|
|
LPITEMIDLIST pidl=ILCreateFromPath(szPath);
|
|
if (pidl) {
|
|
LPCTSTR lpstrMRU;
|
|
LPCTSTR lpstrStream;
|
|
|
|
if ( pstm )
|
|
pstm->Release();
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
lpstrMRU = REGSTR_PATH_EXPLORER TEXT("\\DesktopStreamMRU");
|
|
lpstrStream = TEXT("DesktopStreams");
|
|
}
|
|
else
|
|
{
|
|
lpstrMRU = REGSTR_PATH_EXPLORER TEXT("\\StreamMRU");
|
|
lpstrStream = TEXT("Streams");
|
|
}
|
|
pstm = ::GetViewStream(pidl, grfMode, szName, lpstrMRU, lpstrStream);
|
|
|
|
if(!pstm && g_fRunningOnNT)
|
|
{
|
|
LPITEMIDLIST pidlWin95Desktop;
|
|
TCHAR szWin95DesktopPath[MAX_PATH];
|
|
LPTSTR pszDirName;
|
|
|
|
// This path is hit when we upgrade from Win95 (with NO IE4.X).
|
|
// The path to desktop in NT5 is "c:\<win>\Profiles\<username>\Desktop";
|
|
// but, under win95, the path is "c:\<win>\Desktop". So, we need to
|
|
// generate the pidl corresponding to what we have in Win95.
|
|
pszDirName = PathFindFileName(szPath); //Finds pointer to "Desktop"
|
|
GetWindowsDirectory(szWin95DesktopPath, ARRAYSIZE(szWin95DesktopPath));
|
|
PathAppend(szWin95DesktopPath, pszDirName);
|
|
|
|
pidlWin95Desktop = ILCreateFromPath(szWin95DesktopPath);
|
|
if (pidlWin95Desktop)
|
|
{
|
|
// When we upgrade from Win95 to NT5 directly, "DesktopStreamMRU" won't be present.
|
|
// So, we need to read from the old location in this case.
|
|
pstm = ::GetViewStream(pidlWin95Desktop, grfMode, szName,
|
|
REGSTR_PATH_EXPLORER TEXT("\\StreamMRU"),
|
|
TEXT("Streams"));
|
|
ILFree(pidlWin95Desktop);
|
|
}
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
}
|
|
}
|
|
|
|
return pstm;
|
|
}
|
|
|
|
LRESULT CDesktopBrowser::OnCommand(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case FCIDM_FINDFILES:
|
|
SHFindFiles(_pbbd->_pidlCur, NULL);
|
|
break;
|
|
|
|
case FCIDM_REFRESH:
|
|
{
|
|
// Invalidate the enum cache to force a reenumeration
|
|
LPITEMIDLIST pidl;
|
|
if (S_OK == SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 0, &pidl))
|
|
{
|
|
Desktop_InvalidateEnumCache(pidl, SHCNE_DISKEVENTS);
|
|
ILFree(pidl);
|
|
}
|
|
|
|
VARIANT v = {0};
|
|
v.vt = VT_I4;
|
|
v.lVal = OLECMDIDF_REFRESH_NO_CACHE|OLECMDIDF_REFRESH_PROMPTIFOFFLINE;
|
|
// Our Exec is neutered (on purpose), so call our parent
|
|
_pctInner->Exec(NULL, OLECMDID_REFRESH, OLECMDEXECOPT_DONTPROMPTUSER, &v, NULL);
|
|
break;
|
|
}
|
|
|
|
case IDC_KBSTART:
|
|
case FCIDM_NEXTCTL:
|
|
if (_hwndTray)
|
|
{
|
|
// n.b. VK_TAB handled this way (among other things)
|
|
SendMessage(_hwndTray, WM_COMMAND, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
|
|
case IDM_CLOSE:
|
|
SendMessage(_hwndTray, TM_DOEXITWINDOWS, 0, 0);
|
|
break;
|
|
|
|
default:
|
|
_pbsInner->OnCommand(wParam, lParam);
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
// Create desktop IShellView instance
|
|
|
|
HRESULT CDesktopBrowser::_CreateDesktopView()
|
|
{
|
|
LPCITEMIDLIST pidl = SHCloneSpecialIDList(NULL, CSIDL_DESKTOP, TRUE);
|
|
if (pidl)
|
|
{
|
|
FOLDERSETTINGS fs;
|
|
DWORD cb = SIZEOF(fs);
|
|
|
|
if (SHGetValueGoodBoot(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\DeskView"),
|
|
TEXT("Settings"), NULL, (BYTE *)&fs, &cb) == ERROR_SUCCESS &&
|
|
cb >= SIZEOF(fs))
|
|
{
|
|
_fsd._fs.fFlags = fs.fFlags | FWF_DESKTOP | FWF_NOCLIENTEDGE; // make it transparent, etc.
|
|
}
|
|
else
|
|
{
|
|
_fsd._fs.fFlags = FWF_DESKTOP | FWF_NOCLIENTEDGE; // default
|
|
}
|
|
|
|
_fsd._fs.ViewMode = FVM_ICON; // can't change this, sorry
|
|
|
|
SHELLSTATE ss = {0};
|
|
SHGetSetSettings(&ss, SSF_HIDEICONS, FALSE);
|
|
if (ss.fHideIcons)
|
|
_fsd._fs.fFlags |= FWF_NOICONS;
|
|
else
|
|
_fsd._fs.fFlags &= ~FWF_NOICONS;
|
|
|
|
// We keep the active desktop in offline mode!
|
|
ASSERT(_pbbd->_pautoWB2);
|
|
_pbbd->_pautoWB2->put_Offline(TRUE);
|
|
|
|
return _psbInner->BrowseObject(pidl, 0);
|
|
}
|
|
else
|
|
{
|
|
TCHAR szYouLoose[256];
|
|
|
|
// BUGBUG (beta-only): deal with the inability to create the desktop
|
|
LoadString(HINST_THISDLL, IDS_YOULOSE, szYouLoose, ARRAYSIZE(szYouLoose));
|
|
MessageBox(NULL, szYouLoose, NULL, MB_ICONSTOP);
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::ActivatePendingView(void)
|
|
{
|
|
HRESULT hres = _pbsInner->ActivatePendingView();
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
if (g_fRunningOnNT)
|
|
{
|
|
// On NT, simply calling SetShellWindow will cause the desktop
|
|
// to initially paint white, then the background window.
|
|
// This causes an ugly white trail when you move windows
|
|
// around until the desktop finally paints.
|
|
|
|
// Calling SetShellWindowEx resolves this problem.
|
|
|
|
SHSetShellWindowEx(_pbbd->_hwnd, _GetDesktopListview());
|
|
}
|
|
else
|
|
{
|
|
SetShellWindow(_pbbd->_hwnd);
|
|
}
|
|
|
|
// Tell fsnotiy that our window is ready to handle PnP notifications
|
|
// Must wait until we've done the SetShellWindow because
|
|
SHChangeNotify_DesktopInit();
|
|
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
#ifdef DEBUG // {
|
|
|
|
void CDesktopBrowser::_CreateDeskbars()
|
|
{
|
|
HRESULT hres;
|
|
BOOL fCreate = FALSE;
|
|
HKEY hkey;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\DeskBar\\Bands"), &hkey)) {
|
|
fCreate = TRUE;
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if (fCreate) {
|
|
IPersistStreamInit *ppstm;
|
|
|
|
hres = CoCreateInstance(CLSID_DeskBarApp, NULL, CLSCTX_INPROC_SERVER, IID_IPersistStreamInit, (void **)&ppstm);
|
|
if (SUCCEEDED(hres)) {
|
|
hres = ppstm->InitNew();
|
|
AddToolbar(ppstm, L"test", NULL); // BUGBUG "Microsoft.DeskBarApp"
|
|
ppstm->Release();
|
|
}
|
|
}
|
|
}
|
|
#endif // }
|
|
|
|
void CDesktopBrowser::_InitDeskbars()
|
|
{
|
|
|
|
// Load toolbars
|
|
|
|
|
|
// 1st, try persisted state
|
|
IStream* pstm = GetDesktopViewStream(STGM_READ, TEXT("Toolbars"));
|
|
HRESULT hres = E_FAIL;
|
|
if (pstm) {
|
|
hres = _pbsInner->_LoadToolbars(pstm);
|
|
pstm->Release();
|
|
}
|
|
|
|
// 2nd, if there is none (or if version mismatch or other failure),
|
|
// try settings from setup
|
|
// BUGBUG n.b. this works fine for ie4 where we have no old toolbars,
|
|
// but for future releases we'll need some kind of merging scheme,
|
|
// so we probably want to change this after ie4-beta-1.
|
|
if (FAILED(hres)) {
|
|
// n.b. HKLM not HKCU
|
|
// like GetDesktopViewStream but for HKLM
|
|
pstm = OpenRegStream(g_hklmExplorer,
|
|
TEXT("Streams\\Desktop"),
|
|
TEXT("Default Toolbars"), STGM_READ);
|
|
if (pstm) {
|
|
hres = _pbsInner->_LoadToolbars(pstm);
|
|
pstm->Release();
|
|
}
|
|
}
|
|
|
|
// o.w., throw up our hands
|
|
if (FAILED(hres)) {
|
|
ASSERT(0);
|
|
#ifdef DEBUG
|
|
// but for debug, need a way to bootstrap the entire process
|
|
_CreateDeskbars();
|
|
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
// Handle creation of a new Desktop folder window. Creates everything except
|
|
// the viewer part.
|
|
// Returns -1 if something goes wrong.
|
|
HWND g_hwndTray = NULL;
|
|
|
|
HRESULT CDesktopBrowser::OnCreate(CREATESTRUCT *pcs)
|
|
{
|
|
LRESULT lr;
|
|
|
|
g_pdtray->GetTrayWindow(&_hwndTray);
|
|
g_hwndTray = _hwndTray;
|
|
g_pdtray->SetDesktopWindow(_pbbd->_hwnd);
|
|
|
|
|
|
// Notify IEDDE that the automation services are now available.
|
|
|
|
IEOnFirstBrowserCreation(NULL);
|
|
|
|
ASSERT(_hwndTray);
|
|
|
|
// BUGBUG TODO: we need to split out "ie registry settings" into a
|
|
// browser component and a shell component.
|
|
|
|
//EnsureWebViewRegSettings();
|
|
|
|
if (SUCCEEDED(_CreateDesktopView()))
|
|
{
|
|
SHChangeNotifyEntry fsne;
|
|
|
|
lr = _pbsInner->OnCreate(pcs); // success
|
|
|
|
fsne.fRecursive = TRUE;
|
|
fsne.pidl = NULL;
|
|
_uNotifyID = SHChangeNotifyRegister(_pbbd->_hwnd, SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_NewDelivery, SHCNE_DRIVEADDGUI, WM_CHANGENOTIFY, 1, &fsne);
|
|
|
|
PostMessage(_pbbd->_hwnd, DTM_CREATESAVEDWINDOWS, 0, 0);
|
|
|
|
return (HRESULT) lr;
|
|
}
|
|
|
|
return (LRESULT)-1; // failure
|
|
}
|
|
|
|
UINT GetDDEExecMsg()
|
|
{
|
|
static UINT uDDEExec = 0;
|
|
|
|
if (!uDDEExec)
|
|
uDDEExec = RegisterWindowMessage(TEXT("DDEEXECUTESHORTCIRCUIT"));
|
|
|
|
return uDDEExec;
|
|
}
|
|
|
|
LRESULT CDesktopBrowser::OnNotify(NMHDR * pnm)
|
|
{
|
|
switch (pnm->code)
|
|
{
|
|
case SEN_DDEEXECUTE:
|
|
if (pnm->idFrom == 0)
|
|
{
|
|
// short cut notifier around the dde conv.
|
|
|
|
LPNMVIEWFOLDER pnmPost = DDECreatePostNotify((LPNMVIEWFOLDER)pnm);
|
|
|
|
if (pnmPost)
|
|
{
|
|
PostMessage(_pbbd->_hwnd, GetDDEExecMsg(), 0, (LPARAM)pnmPost);
|
|
return TRUE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case NM_STARTWAIT:
|
|
case NM_ENDWAIT:
|
|
_iWaitCount += (pnm->code == NM_STARTWAIT ? 1 :-1);
|
|
|
|
ASSERT(_iWaitCount >= 0);
|
|
|
|
// Don't let it go negative or we'll never get rid of it.
|
|
if (_iWaitCount < 0)
|
|
_iWaitCount = 0;
|
|
|
|
// what we really want is for user to simulate a mouse move/setcursor
|
|
SetCursor(LoadCursor(NULL, _iWaitCount ? IDC_APPSTARTING : IDC_ARROW));
|
|
break;
|
|
|
|
default:
|
|
return _pbsInner->OnNotify(pnm);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// HACKHACK: this hard codes in that we know a listview is the child
|
|
// of the view.
|
|
HWND CDesktopBrowser::_GetDesktopListview()
|
|
{
|
|
HWND hwndView = _pbbd->_hwndView ? _pbbd->_hwndView : _pbbd->_hwndViewPending;
|
|
|
|
if (!hwndView)
|
|
return NULL;
|
|
|
|
return FindWindowEx(hwndView, NULL, WC_LISTVIEW, NULL);
|
|
}
|
|
|
|
#ifndef ENUM_REGISTRY_SETTINGS
|
|
#define ENUM_REGISTRY_SETTINGS ((DWORD)-2)
|
|
#endif
|
|
|
|
|
|
BOOL IsTempDisplayMode()
|
|
{
|
|
BOOL fTempMode = FALSE;
|
|
|
|
// BUGBUG (scotth): the original code in explorer was #ifdef WINNT or MEMPHIS.
|
|
// We're just checking for NT right now.
|
|
if (g_fRunningOnNT)
|
|
{
|
|
DEVMODE dm;
|
|
|
|
ZeroMemory(&dm, sizeof(dm));
|
|
dm.dmSize = sizeof(dm);
|
|
|
|
if (EnumDisplaySettings(NULL, ENUM_REGISTRY_SETTINGS, &dm) &&
|
|
dm.dmPelsWidth > 0 && dm.dmPelsHeight > 0)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
int xres = GetDeviceCaps(hdc, HORZRES);
|
|
int yres = GetDeviceCaps(hdc, VERTRES);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
if (xres != (int)dm.dmPelsWidth || yres != (int)dm.dmPelsHeight)
|
|
fTempMode = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TCHAR ach[80];
|
|
DWORD cb = SIZEOF(ach);
|
|
|
|
if (SHGetValueGoodBoot(HKEY_CURRENT_CONFIG, REGSTR_PATH_DISPLAYSETTINGS,
|
|
REGSTR_VAL_RESOLUTION, NULL, (BYTE *)ach, &cb) == ERROR_SUCCESS)
|
|
{
|
|
int xres = StrToInt(ach);
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
if ((GetDeviceCaps(hdc, CAPS1) & C1_REINIT_ABLE) &&
|
|
(xres > 0) && (xres != GetDeviceCaps(hdc, HORZRES)))
|
|
{
|
|
fTempMode = TRUE;
|
|
}
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
|
|
}
|
|
return fTempMode;
|
|
}
|
|
|
|
// BUGBUG: this is the hack andyp put in
|
|
// (dli) Currently, bottommost Tray is really wierd, it is not treated as toolbars.
|
|
// In a sense, it has higher priority than those toolbars. So they should be taken
|
|
// off the EffectiveClientArea
|
|
|
|
void CDesktopBrowser::_SubtractBottommostTray(LPRECT prc)
|
|
{
|
|
LRESULT lTmp;
|
|
APPBARDATA abd;
|
|
|
|
abd.cbSize = sizeof(APPBARDATA);
|
|
abd.hWnd = _hwndTray;
|
|
|
|
// lTmp = SHAppBarMessage(ABM_GETSTATE, &abd);
|
|
lTmp = g_pdtray->AppBarGetState();
|
|
|
|
if ((lTmp & (ABS_ALWAYSONTOP|ABS_AUTOHIDE)) == 0) {
|
|
// tray is on bottom and takes 'real' space
|
|
RECT rcTray = {0};
|
|
|
|
GetWindowRect(_hwndTray, &rcTray);
|
|
IntersectRect(&rcTray, prc, &rcTray);
|
|
SubtractRect(prc, prc, &rcTray);
|
|
}
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::_GetEffectiveClientArea(LPRECT lprectBorder, HMONITOR hmon)
|
|
{
|
|
|
|
// Cache the work area if
|
|
// (1) this is the very first call
|
|
// (2) cached value is blew off by WM_SIZE (in _OnSize)
|
|
|
|
if (hmon) {
|
|
GetMonitorWorkArea(hmon, lprectBorder);
|
|
}
|
|
else {
|
|
if (::IsRectEmpty(&_rcWorkArea)) {
|
|
::SystemParametersInfo(SPI_GETWORKAREA, 0, &_rcWorkArea, 0);
|
|
}
|
|
*lprectBorder = _rcWorkArea;
|
|
}
|
|
|
|
_SubtractBottommostTray(lprectBorder);
|
|
MapWindowPoints(NULL, _pbbd->_hwnd, (LPPOINT)lprectBorder, 2);
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
BOOL EqualRects(LPRECT prcNew, LPRECT prcOld, int nRects)
|
|
{
|
|
int i;
|
|
for (i = 0; i < nRects; i++)
|
|
if (!EqualRect(&prcNew[i], &prcOld[i]))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
void CDesktopBrowser::_SetWorkAreas(int nWorkAreas, LPRECT prcWork)
|
|
{
|
|
RECT rcListViewWork[LV_MAX_WORKAREAS];
|
|
RECT rcNewWork[LV_MAX_WORKAREAS];
|
|
int nListViewWork = 0;
|
|
HWND hwndList;
|
|
int i;
|
|
|
|
ASSERT(prcWork);
|
|
ASSERT(nWorkAreas <= LV_MAX_WORKAREAS);
|
|
ASSERT(nWorkAreas > 0);
|
|
|
|
if (nWorkAreas <= 0)
|
|
return;
|
|
|
|
if (IsTempDisplayMode())
|
|
return;
|
|
|
|
hwndList = _GetDesktopListview();
|
|
ASSERT(IsWindow(hwndList));
|
|
|
|
ListView_GetNumberOfWorkAreas(hwndList, &nListViewWork);
|
|
|
|
if (nListViewWork > 0)
|
|
{
|
|
ListView_GetWorkAreas(hwndList, nListViewWork, rcListViewWork);
|
|
// Map these rects back to DESKTOP coordinate
|
|
// We need to convert the following only if WorkAreas > 1
|
|
if (nListViewWork > 1)
|
|
{
|
|
// [msadek]; MapWindowPoints() is mirroring-aware only if you pass two points
|
|
for(i = 0; i < nListViewWork; i++)
|
|
{
|
|
MapWindowPoints(hwndList, HWND_DESKTOP, (LPPOINT)(&rcListViewWork[i]), 2);
|
|
}
|
|
}
|
|
if(nListViewWork == nWorkAreas && EqualRects(prcWork, rcListViewWork, nWorkAreas))
|
|
return;
|
|
}
|
|
else if (_nOldWork > 1)
|
|
// In single monitor case, listview workares always starts from (0,0)
|
|
// It will be wrong to set the persisted workarea.
|
|
{
|
|
for (nListViewWork = 0; nListViewWork < (int)_nOldWork && nListViewWork < LV_MAX_WORKAREAS; nListViewWork++)
|
|
CopyRect(&rcListViewWork[nListViewWork], &_rcOldWorkAreas[nListViewWork]);
|
|
|
|
// This may not be needed, because at this point, ListView is in Desktop coordinate
|
|
// [msadek]; MapWindowPoints() is mirroring-aware only if you pass two points
|
|
for(i = 0; i < nListViewWork; i++)
|
|
{
|
|
MapWindowPoints(HWND_DESKTOP, hwndList, (LPPOINT)(&rcListViewWork[i]), 2);
|
|
}
|
|
// This call to SetWorkAreas sets the old work areas in the listview, which is not persisted there.
|
|
ListView_SetWorkAreas(hwndList, nListViewWork, rcListViewWork);
|
|
}
|
|
|
|
//Make a copy of the new work area array because it gets modified by
|
|
// the MapWindowPoints below.
|
|
for(i = 0; i < nWorkAreas; i++)
|
|
rcNewWork[i] = *(prcWork + i);
|
|
|
|
// It's already in ListView coordinate if we just have one monitor
|
|
if (nWorkAreas > 1)
|
|
{
|
|
for(i = 0; i < nWorkAreas; i++)
|
|
{
|
|
MapWindowPoints(HWND_DESKTOP, hwndList, (LPPOINT)(&prcWork[i]), 2);
|
|
}
|
|
}
|
|
|
|
// We need to set the new work area before we call AdjustDesktopComponents below
|
|
// because that function results in a refresh and that ends up setting
|
|
// the work areas again to the same values.
|
|
ListView_SetWorkAreas(hwndList, nWorkAreas, prcWork);
|
|
|
|
if (nWorkAreas == 1)
|
|
MapWindowPoints(hwndList, HWND_DESKTOP, (LPPOINT)rcNewWork, 2 * nWorkAreas);
|
|
|
|
//Move and size desktop components based on the new work areas.
|
|
AdjustDesktopComponents((LPCRECT)rcNewWork, nWorkAreas, (LPCRECT)_rcOldMonitors, (LPCRECT)_rcOldWorkAreas, _nOldWork);
|
|
|
|
// Backup the new Monitor rect's in _rcOldMonitors
|
|
for (i = 0; i < _nMonitors; i++)
|
|
{
|
|
GetMonitorRect(_hMonitors[i], &_rcOldMonitors[i]);
|
|
}
|
|
// Backup the new workareas in _rcOldWorkAreas
|
|
for (i = 0; i < nWorkAreas; i++)
|
|
{
|
|
_rcOldWorkAreas[i] = rcNewWork[i];
|
|
}
|
|
_nOldWork = nWorkAreas;
|
|
}
|
|
|
|
// Get all the view border rectangles (not including toolbars) for the monitors
|
|
// this is used for multi-monitor case only.
|
|
void CDesktopBrowser::_GetViewBorderRects(int nRects, LPRECT prcBorders)
|
|
{
|
|
int iMon;
|
|
HMONITOR hmonTray;
|
|
Tray_GetHMonitor(_hwndTray, &hmonTray);
|
|
for (iMon = 0; iMon < min(_nMonitors, nRects); iMon++)
|
|
{
|
|
GetMonitorWorkArea(_hMonitors[iMon], &prcBorders[iMon]);
|
|
if (hmonTray == _hMonitors[iMon])
|
|
_SubtractBottommostTray(&prcBorders[iMon]);
|
|
|
|
// Extract the border taken by all "frame" toolbars
|
|
for (int itb=0; itb < _pbsInner->_GetToolbarCount(); itb++)
|
|
{
|
|
LPTOOLBARITEM ptbi = _pbsInner->_GetToolbarItem(itb);
|
|
if (ptbi && ptbi->hMon == _hMonitors[iMon])
|
|
{
|
|
prcBorders[iMon].left += ptbi->rcBorderTool.left;
|
|
prcBorders[iMon].top += ptbi->rcBorderTool.top;
|
|
prcBorders[iMon].right -= ptbi->rcBorderTool.right;
|
|
prcBorders[iMon].bottom -= ptbi->rcBorderTool.bottom;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
HRESULT CDesktopBrowser::_UpdateViewRectSize()
|
|
{
|
|
HWND hwndView = _pbbd->_hwndView;
|
|
if (!hwndView && ((hwndView = _pbbd->_hwndViewPending) == NULL))
|
|
return S_FALSE;
|
|
|
|
_pbsInner->_UpdateViewRectSize();
|
|
|
|
if (_nMonitors <= 1)
|
|
{
|
|
RECT rcView, rcWork;
|
|
GetViewRect(&rcView);
|
|
rcWork.top = rcWork.left = 0;
|
|
rcWork.right = RECTWIDTH(rcView);
|
|
rcWork.bottom = RECTHEIGHT(rcView);
|
|
_SetWorkAreas(1, &rcWork);
|
|
}
|
|
else
|
|
{
|
|
RECT rcWorks[LV_MAX_WORKAREAS];
|
|
_GetViewBorderRects(_nMonitors, rcWorks);
|
|
_SetWorkAreas(_nMonitors, rcWorks);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CDesktopBrowser::_PositionViewWindow(HWND hwnd, LPRECT prc)
|
|
{
|
|
RECT rcWindow;
|
|
UINT uSWPFlags;
|
|
int iWidth, iHeight;
|
|
GetWindowRect(hwnd, &rcWindow);
|
|
MapWindowPoints(NULL, GetParent(hwnd), (LPPOINT)&rcWindow, 2);
|
|
|
|
|
|
// Erase it all so the wallpaper is repainted correctly.
|
|
|
|
if (rcWindow.left != prc->left ||
|
|
rcWindow.top != prc->top)
|
|
{
|
|
// optimize, if the top left didn't change, the wallpaper doesn't move
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
uSWPFlags = SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE;
|
|
}
|
|
else
|
|
{
|
|
uSWPFlags = SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE;
|
|
}
|
|
iWidth = RECTWIDTH(*prc);
|
|
iHeight = RECTHEIGHT(*prc);
|
|
SetWindowPos(hwnd, NULL, prc->left, prc->top, iWidth, iHeight, uSWPFlags);
|
|
}
|
|
|
|
void CDesktopBrowser::_SetViewArea()
|
|
{
|
|
|
|
// Invalidate the cached work area size
|
|
|
|
::SetRectEmpty(&_rcWorkArea);
|
|
|
|
v_ShowHideChildWindows(FALSE);
|
|
}
|
|
|
|
// we get called here when new drives come and go;
|
|
// things like net connections, hot insertions, etc.
|
|
|
|
void _OnDeviceBroadcast(HWND hwnd, ULONG_PTR code, DEV_BROADCAST_HDR *pbh)
|
|
{
|
|
// do a bunch of this stuff here in desktop so it only happens
|
|
// once...
|
|
|
|
switch (code)
|
|
{
|
|
case DBT_LOW_DISK_SPACE:
|
|
case DBT_NO_DISK_SPACE:
|
|
SetTimer(hwnd, IDT_DISKFULL + PtrToUlong(pbh), DISKFULL_TIMEOUT, NULL);
|
|
break;
|
|
case DBT_DEVICEREMOVECOMPLETE: // drive or media went away
|
|
case DBT_DEVICEARRIVAL: // new drive or media (or UNC) has arrived
|
|
case DBT_DEVICEQUERYREMOVE: // drive or media about to go away
|
|
case DBT_DEVICEQUERYREMOVEFAILED: // drive or media didn't go away
|
|
|
|
// Don't process if we are being shutdown...
|
|
if (!IsWindowVisible(hwnd))
|
|
break;
|
|
|
|
CMountPoint::HandleWMDeviceChange(code, pbh);
|
|
SHChangeNotify_OnDeviceChange(code, pbh);
|
|
break;
|
|
case DBT_CONFIGCHANGED:
|
|
Desktop_UpdateBriefcaseOnEvent(hwnd, UOE_CONFIGCHANGED);
|
|
break;
|
|
case DBT_QUERYCHANGECONFIG:
|
|
Desktop_UpdateBriefcaseOnEvent(hwnd, UOE_QUERYCHANGECONFIG);
|
|
break;
|
|
}
|
|
}
|
|
|
|
BOOL AppAllowsAutoRun(HWND hwndApp)
|
|
{
|
|
static UINT uMessage = 0;
|
|
ULONG_PTR dwCancel = 0;
|
|
|
|
if (!uMessage)
|
|
uMessage = RegisterWindowMessage(TEXT("QueryCancelAutoPlay"));
|
|
|
|
SendMessageTimeout(hwndApp, uMessage, 0, 0, SMTO_NORMAL | SMTO_ABORTIFHUNG,
|
|
1000, &dwCancel);
|
|
|
|
return (dwCancel != 1); // check for exactly 1 (future expansion)
|
|
}
|
|
|
|
// Note: this overrides the one in CBaseBrowser
|
|
HRESULT CDesktopBrowser::GetViewRect(RECT* prc)
|
|
{
|
|
|
|
// Check if we are on a multiple-monitor system. In multiple monitors the
|
|
// view needs to cover all displays (ie the size of _pbbd->_hwnd) while on
|
|
// single-monitor systems the view just needs to cover the work area (like
|
|
// in Win95).
|
|
|
|
if (_nMonitors <= 1)
|
|
_pbsInner->GetViewRect(prc);
|
|
else
|
|
GetClientRect(_pbbd->_hwnd, prc);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
// BUGBUG LATER: This is only a temporary solution for NT. We can have a much more
|
|
// efficient implementation inside USER on both NT and Win9x. Then we could have
|
|
// common NT/Win9x code that says "if OnActiveDesktop() ..." below in Desktop_OnFSNotify
|
|
|
|
BOOL IsMyDesktopActive()
|
|
{
|
|
BOOL bResult = FALSE;
|
|
DWORD cb;
|
|
|
|
if (!g_fRunningOnNT) // Win95 does not support this stuff, assume it is OK
|
|
return TRUE;
|
|
|
|
HDESK hdeskInput = OpenInputDesktop(0, FALSE, STANDARD_RIGHTS_REQUIRED | DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
|
|
if (hdeskInput)
|
|
{
|
|
TCHAR szInput[256];
|
|
if (GetUserObjectInformation(hdeskInput, UOI_NAME, (PVOID)szInput, sizeof(szInput), &cb))
|
|
{
|
|
HDESK hdeskMyDesktop = GetThreadDesktop(GetCurrentThreadId());
|
|
if (hdeskMyDesktop)
|
|
{
|
|
TCHAR szMyDesktop[256];
|
|
if (GetUserObjectInformation(hdeskMyDesktop, UOI_NAME, (PVOID)szMyDesktop, sizeof(szMyDesktop), &cb))
|
|
{
|
|
bResult = lstrcmpi(szInput, szMyDesktop) == 0;
|
|
}
|
|
}
|
|
}
|
|
CloseDesktop(hdeskInput);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
void CDesktopBrowser::_OnChangeNotify(LONG lNotification, LPITEMIDLIST *ppidl)
|
|
{
|
|
// Currently only handle SHCNE_DRIVEADDGUI...
|
|
if (lNotification == SHCNE_DRIVEADDGUI)
|
|
{
|
|
HWND hwnd = GetForegroundWindow();
|
|
BOOL fShellForeground;
|
|
TCHAR szDrive[MAX_PATH];
|
|
int iDrive;
|
|
DWORD dwRestricted;
|
|
|
|
// dont run anything if the SHIFT key is down
|
|
if (GetAsyncKeyState(VK_SHIFT) < 0)
|
|
{
|
|
TraceMsg(DM_TRACE, "Cabinet: SHIFT key is down skipping AutoOpen");
|
|
return;
|
|
}
|
|
|
|
SHGetPathFromIDList(*ppidl, szDrive);
|
|
ASSERT(szDrive[1] == TEXT(':'));
|
|
|
|
if ((0 == *(szDrive + 2) || 0 == *(szDrive + 3)))
|
|
{
|
|
iDrive = DRIVEID(szDrive);
|
|
|
|
// Now make sure that this drive is not restricted!
|
|
// Handles cases where drives are mapped in under the covers
|
|
// like when a drivespace floppy is discovered.
|
|
|
|
dwRestricted = SHRestricted(REST_NODRIVES);
|
|
if (dwRestricted & (1 << iDrive))
|
|
{
|
|
// Restricted drive...
|
|
TraceMsg(DM_TRACE, "_OnChangeNotify: Restricted Drive(%c)", szDrive[0]);
|
|
return;
|
|
}
|
|
|
|
// On NT, bail out now if we're on the secure desktop (locked
|
|
// workstation or password-protected screensaver)
|
|
if (!IsMyDesktopActive())
|
|
return;
|
|
|
|
fShellForeground = hwnd && (hwnd == _hwndTray || hwnd == _pbbd->_hwnd || IsFolderWindow(hwnd));
|
|
|
|
// Always shlexec if its a net drive being added - gives feedback to user
|
|
|
|
BOOL fShellExec = FALSE;
|
|
|
|
if (IsNetDrive(iDrive))
|
|
{
|
|
fShellExec = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (CMountPoint::IsAutoOpen(iDrive))
|
|
{
|
|
fShellExec = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (fShellForeground && CMountPoint::IsShellOpen(iDrive))
|
|
{
|
|
fShellExec = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fShellExec)
|
|
{
|
|
if (CMountPoint::IsAutoRun(iDrive) && !AppAllowsAutoRun(hwnd))
|
|
{
|
|
fShellExec = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Do we have a fixed disk?
|
|
if (DRIVE_FIXED == GetDriveType(szDrive))
|
|
{
|
|
// Yes.
|
|
// Are we running on server?
|
|
if (IsOS(OS_WIN2000SERVER) || IsOS(OS_WIN2000ADVSERVER) || IsOS(OS_WIN2000DATACENTER))
|
|
{
|
|
// Yes. On server having cluster service, when one disk goes down and another one
|
|
// replace it, we used to autoopen an explorer on the drive. This was very annoying
|
|
// and a lot of explorer ended up opening. BUG# 376481 (stephstm, 08/20/99)
|
|
fShellExec = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// Is this a docked laptop?
|
|
if (SHGetMachineInfo(GMID_DOCKED))
|
|
{
|
|
// Yes. On docking station having a hard disk (not in the laptop, but in the
|
|
// docking station), each time the laptop is docked, we receive a WM_DEVICECHANGE
|
|
// and used to popup an Explorer on the drive. BUG# 358361 (stephstm, 08/20/99)
|
|
fShellExec = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fShellExec)
|
|
{
|
|
|
|
// use ShellExecuteEx() so the default verb gets invoked
|
|
// (may not be open or even explore)
|
|
|
|
SHELLEXECUTEINFO ei = {
|
|
SIZEOF(ei), // size
|
|
SEE_MASK_INVOKEIDLIST, // flags
|
|
_pbbd->_hwnd, // parent window
|
|
NULL, // verb
|
|
NULL, // file
|
|
szDrive, // params
|
|
szDrive, // directory
|
|
SW_NORMAL, // show.
|
|
NULL, // hinstance
|
|
*ppidl, // IDLIST
|
|
NULL, // class name
|
|
NULL, // class key
|
|
0, // hot key
|
|
NULL, // icon
|
|
NULL, // hProcess
|
|
};
|
|
|
|
#ifdef BUGBUG // IMPLEMENT LATER
|
|
// BUGBUG: aahhh.. look how we force a new window!
|
|
BOOL fPrevMode = g_CabState.fNewWindowMode;
|
|
g_CabState.fNewWindowMode = TRUE;
|
|
#endif //!BUGBUG
|
|
|
|
if (!ShellExecuteEx(&ei))
|
|
{
|
|
TraceMsg(DM_TRACE, "Cabinet: ShellExecuteEx() failed on drive notify");
|
|
}
|
|
#ifdef BUGBUG
|
|
g_CabState.fNewWindowMode = fPrevMode;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::ReleaseShellView()
|
|
{
|
|
_SaveState();
|
|
|
|
return _pbsInner->ReleaseShellView();
|
|
}
|
|
|
|
void CDesktopBrowser::_ViewChange(DWORD dwAspect, LONG lindex)
|
|
{
|
|
// do nothing here...
|
|
}
|
|
|
|
void CDesktopBrowser::_SaveDesktopToolbars()
|
|
{
|
|
IStream * pstm = GetDesktopViewStream(STGM_WRITE, TEXT("Toolbars"));
|
|
if (pstm)
|
|
{
|
|
_pbsInner->_SaveToolbars(pstm);
|
|
pstm->Release();
|
|
}
|
|
}
|
|
|
|
void CDesktopBrowser::_SaveState()
|
|
{
|
|
// save off the Recycle Bin information to the registry
|
|
SaveRecycleBinInfo();
|
|
|
|
if (!SHRestricted(REST_NOSAVESET) && _pbbd->_psv)
|
|
{
|
|
if (!GetSystemMetrics(SM_CLEANBOOT))
|
|
{
|
|
FOLDERSETTINGS fs;
|
|
_pbbd->_psv->GetCurrentInfo(&fs);
|
|
|
|
SHSetValue(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER TEXT("\\DeskView"), TEXT("Settings"), REG_BINARY, &fs, SIZEOF(fs));
|
|
}
|
|
|
|
_pbbd->_psv->SaveViewState();
|
|
|
|
_SaveDesktopToolbars();
|
|
}
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::OnSize(WPARAM wParam)
|
|
{
|
|
if (wParam == SIZE_MINIMIZED)
|
|
{
|
|
TraceMsg(DM_TRACE, "c.dwp: Desktop minimized by somebody!");
|
|
// Put it back.
|
|
ShowWindow(_pbbd->_hwnd, SW_RESTORE);
|
|
}
|
|
_SetViewArea();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
HRESULT CDesktopBrowser::OnDestroy()
|
|
{
|
|
TraceMsg(DM_SHUTDOWN, "cdtb._od (WM_DESTROY)");
|
|
|
|
// Tell fsnotiy that he ain't got our window to kick around any mo'
|
|
SHChangeNotify_DesktopTerm();
|
|
|
|
if (_uNotifyID)
|
|
{
|
|
SHChangeNotifyDeregister(_uNotifyID);
|
|
_uNotifyID = 0;
|
|
}
|
|
|
|
if (_hwndRaised)
|
|
DestroyWindow(_hwndRaised);
|
|
|
|
// get rid of the scheduler and the desktop tasks
|
|
if (_psched)
|
|
{
|
|
_psched->RemoveTasks(TOID_Desktop, 0, TRUE);
|
|
ATOMICRELEASE(_psched);
|
|
}
|
|
|
|
_pbsInner->OnDestroy();
|
|
|
|
// BUGBUG: call this (q: what happens if we don't terminate this?)
|
|
//OneTree_Terminate();
|
|
|
|
_pbsInner->_CloseAndReleaseToolbars(TRUE);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
#define DM_SWAP DM_TRACE
|
|
|
|
void CDesktopBrowser::_SwapParents(HWND hwndOldParent, HWND hwndNewParent)
|
|
{
|
|
HWND hwnd = ::GetWindow(hwndOldParent, GW_CHILD);
|
|
while (hwnd)
|
|
{
|
|
|
|
// Note that we must get the next sibling BEFORE we set the new
|
|
// parent.
|
|
|
|
HWND hwndNext = ::GetWindow(hwnd, GW_HWNDNEXT);
|
|
::SetParent(hwnd, hwndNewParent);
|
|
hwnd = hwndNext;
|
|
}
|
|
}
|
|
|
|
LRESULT CDesktopBrowser::RaisedWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CDesktopBrowser *psb = (CDesktopBrowser*)GetWindowLongPtr(hwnd, 0);
|
|
|
|
return psb->_RaisedWndProc(uMsg, wParam, lParam);
|
|
}
|
|
|
|
LRESULT CDesktopBrowser::_RaisedWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg) {
|
|
case WM_ACTIVATE:
|
|
|
|
#if 0
|
|
if (_fRaised) {
|
|
|
|
if (LOWORD(wParam) == WA_ACTIVE) {
|
|
// always put the tray on top
|
|
SetWindowPos(_hwndTray, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
|
|
}
|
|
if (LOWORD(wParam) == WA_INACTIVE) {
|
|
DWORD dwProcID;
|
|
HWND hwndForeground = GetForegroundWindow();
|
|
|
|
if (!hwndForeground ||
|
|
!(GetWindowLongPtr(hwndForeground, GWL_EXSTYLE) & WS_EX_TOPMOST) ||
|
|
GetWindowThreadProcessId(hwndForeground, &dwProcID), dwProcID != GetCurrentProcessId())
|
|
{
|
|
_OnRaise((WPARAM)_hwndTray, DTRF_LOWER);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
if (wParam == SIZE_MINIMIZED)
|
|
ShowWindow(_hwndRaised, SW_RESTORE);
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
case WM_ERASEBKGND:
|
|
goto SendToDesktop;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (uMsg >= WM_USER)
|
|
{
|
|
SendToDesktop:
|
|
return SendMessage(_pbbd->_hwnd, uMsg, wParam, lParam);
|
|
}
|
|
else
|
|
{
|
|
return ::SHDefWindowProc(_hwndRaised, uMsg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void CDesktopBrowser::_Raise()
|
|
{
|
|
RECT rc;
|
|
HWND hwndDesktop = GetDesktopWindow();
|
|
BOOL fLocked;
|
|
HWND hwndLastActive = GetLastActivePopup(_pbbd->_hwnd);
|
|
|
|
if (SHIsRestricted(NULL, REST_NODESKTOP))
|
|
return;
|
|
|
|
if (hwndLastActive != _pbbd->_hwnd)
|
|
{
|
|
SetForegroundWindow(hwndLastActive);
|
|
return;
|
|
}
|
|
|
|
if (!_hwndRaised)
|
|
_hwndRaised = SHCreateWorkerWindow(RaisedWndProc, NULL, WS_EX_TOOLWINDOW, WS_POPUP | WS_CLIPCHILDREN, NULL, this);
|
|
|
|
//SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
|
//rc.left = 0; // need to always start from 0, 0 to get the wallpaper centered right
|
|
//rc.top = 0;
|
|
fLocked = LockWindowUpdate(hwndDesktop);
|
|
_SwapParents(_pbbd->_hwnd, _hwndRaised);
|
|
|
|
// set the view window to the bottom of the z order
|
|
SetWindowPos(_pbbd->_hwndView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
GetWindowRect(_pbbd->_hwnd, &rc);
|
|
SetWindowPos(_hwndRaised, HWND_TOP, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), SWP_SHOWWINDOW);
|
|
SetForegroundWindow(_hwndRaised);
|
|
|
|
if (fLocked)
|
|
LockWindowUpdate(NULL);
|
|
|
|
THR(RegisterDragDrop(_hwndRaised, (IDropTarget *)this));
|
|
|
|
SetFocus(_pbbd->_hwndView);
|
|
//SetWindowPos(_hwndTray, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE);
|
|
_fRaised = TRUE;
|
|
}
|
|
|
|
void CDesktopBrowser::_Lower()
|
|
{
|
|
BOOL fLocked;
|
|
|
|
fLocked = LockWindowUpdate(_hwndRaised);
|
|
_SwapParents(_hwndRaised, _pbbd->_hwnd);
|
|
|
|
// set the view window to the bottom of the z order
|
|
SetWindowPos(_pbbd->_hwndView, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
|
|
|
ShowWindow(_hwndRaised, SW_HIDE);
|
|
if (fLocked)
|
|
LockWindowUpdate(NULL);
|
|
RevokeDragDrop(_hwndRaised);
|
|
_fRaised = FALSE;
|
|
}
|
|
|
|
void CDesktopBrowser::_OnRaise(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
VARIANTARG vaIn;
|
|
|
|
VariantInit(&vaIn);
|
|
vaIn.vt = VT_I4;
|
|
vaIn.lVal = (DWORD) lParam;
|
|
|
|
switch (lParam) {
|
|
|
|
case DTRF_RAISE:
|
|
_Raise();
|
|
_ExecChildren(NULL, TRUE, &CGID_ShellDocView, SHDVID_RAISE, 0, &vaIn, NULL);
|
|
break;
|
|
|
|
case DTRF_LOWER:
|
|
_ExecChildren(NULL, TRUE, &CGID_ShellDocView, SHDVID_RAISE, 0, &vaIn, NULL);
|
|
_Lower();
|
|
break;
|
|
}
|
|
|
|
VariantClear(&vaIn);
|
|
|
|
if (!wParam) {
|
|
wParam = (WPARAM)_hwndTray;
|
|
}
|
|
|
|
PostMessage((HWND)wParam, TM_DESKTOPSTATE, 0, _fRaised ? DTRF_RAISE : DTRF_LOWER);
|
|
}
|
|
|
|
#ifdef WINNT
|
|
BOOL CDesktopBrowser::_QueryHKCRChanged(HWND hwnd, DWORD *pdwCookie)
|
|
{
|
|
// we assume that the key has changed if
|
|
// we were unable to init correctly
|
|
BOOL fRet = TRUE;
|
|
|
|
ASSERT(pdwCookie);
|
|
|
|
if (_cChangeEvents)
|
|
{
|
|
DWORD dw = WaitForMultipleObjects(_cChangeEvents, _rghChangeEvents, FALSE, 0);
|
|
|
|
dw -= WAIT_OBJECT_0;
|
|
|
|
if (dw >= 0 && dw < _cChangeEvents)
|
|
{
|
|
|
|
// this means the key changed...
|
|
ResetEvent(_rghChangeEvents[dw]);
|
|
_dwChangeCookie = GetTickCount();
|
|
|
|
PostMessage(hwnd, DTM_SETUPAPPRAN, 0, NULL);
|
|
}
|
|
|
|
|
|
// if nothing has changed yet, or if nothing has changed
|
|
// since the client last checked,
|
|
// than this client doesnt need to update its cache
|
|
|
|
if (!_dwChangeCookie || (*pdwCookie && *pdwCookie == _dwChangeCookie))
|
|
fRet = FALSE;
|
|
|
|
// update the cookie
|
|
*pdwCookie = _dwChangeCookie;
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
#endif //WINNT
|
|
|
|
// This msg gets posted to us after a setup application runs so that we can
|
|
// fix things up.
|
|
|
|
void CDesktopBrowser::_SetupAppRan(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// Lotus 123R5 sometimes gets confused when installing over IE4 and
|
|
// they leave their country setting blank. Detect this case and put
|
|
// in USA so that they at least boot.
|
|
{
|
|
TCHAR szPath[MAX_PATH];
|
|
GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
|
|
if (PathAppend(szPath, TEXT("123r5.ini")) && PathFileExistsAndAttributes(szPath, NULL))
|
|
{
|
|
TCHAR szData[100];
|
|
|
|
GetPrivateProfileString(TEXT("Country"), TEXT("driver"), TEXT(""), szData, ARRAYSIZE(szData), TEXT("123r5.ini"));
|
|
if (!szData[0])
|
|
{
|
|
WritePrivateProfileString(TEXT("Country"), TEXT("driver"), TEXT("L1WUSF"), TEXT("123r5.ini"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Win95 post setup app processing wacks in SoundRec for .wav associations.
|
|
// We want to fix this up to be wavfile for active movie wav file handling.
|
|
{
|
|
TCHAR szName[MAX_PATH];
|
|
DWORD cbData = ARRAYSIZE(szName);
|
|
SHGetValue(HKEY_CLASSES_ROOT, TEXT(".WAV"), NULL, NULL, &szName, &cbData);
|
|
if (!lstrcmp(szName, TEXT("SoundRec")))
|
|
{
|
|
SHSetValue(HKEY_CLASSES_ROOT, TEXT(".WAV"), NULL, REG_SZ, TEXT("wavfile"), sizeof(TEXT("wavfile")));
|
|
}
|
|
}
|
|
|
|
// this location in the registry is a good place to cache info
|
|
// that needs to be invalided once
|
|
SHDeleteKey(HKEY_CURRENT_USER, STRREG_DISCARDABLE STRREG_POSTSETUP) ;
|
|
|
|
// Take this opportunity to freshen our component categories cache:
|
|
IShellTaskScheduler* pScheduler ;
|
|
if( SUCCEEDED( CoCreateInstance( CLSID_SharedTaskScheduler, NULL, CLSCTX_INPROC_SERVER, IID_IShellTaskScheduler, (LPVOID*)&pScheduler ) ) )
|
|
{
|
|
IRunnableTask* pTask ;
|
|
if( SUCCEEDED( CoCreateInstance( CLSID_ComCatCacheTask, NULL, CLSCTX_INPROC_SERVER, IID_IRunnableTask, (void**)&pTask ) ) )
|
|
{
|
|
pScheduler->AddTask( pTask, CLSID_ComCatCacheTask, 0L, ITSAT_DEFAULT_PRIORITY ) ;
|
|
pTask->Release() ; // Scheduler has AddRef'd him
|
|
}
|
|
pScheduler->Release() ; // OK to release global task scheduler.
|
|
}
|
|
|
|
|
|
// We get this notification from the OS that a setup app ran.
|
|
// Legacy app support for freshly written entries under [extensions] section;
|
|
// Scoop these up and shove into registry. (re: bug 140986)
|
|
CheckWinIniForAssocs() ;
|
|
}
|
|
|
|
|
|
|
|
struct propagatemsg
|
|
{
|
|
UINT uMsg;
|
|
WPARAM wParam;
|
|
LPARAM lParam;
|
|
BOOL fSend;
|
|
};
|
|
|
|
BOOL PropagateCallback(HWND hwndChild, struct propagatemsg *pmsg)
|
|
{
|
|
if (pmsg->fSend)
|
|
SendMessage(hwndChild, pmsg->uMsg, pmsg->wParam, pmsg->lParam);
|
|
else
|
|
PostMessage(hwndChild, pmsg->uMsg, pmsg->wParam, pmsg->lParam);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void PropagateMessage(HWND hwndParent, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fSend)
|
|
{
|
|
if (!hwndParent)
|
|
return;
|
|
|
|
struct propagatemsg msg = { uMsg, wParam, lParam, fSend };
|
|
|
|
EnumChildWindows(hwndParent, (WNDENUMPROC)PropagateCallback, (LPARAM)&msg);
|
|
}
|
|
|
|
void CDesktopBrowser::v_PropagateMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL fSend)
|
|
{
|
|
// WARNING: We can't propagate the message to a NULL hwnd because it will
|
|
// turn into a broadcast. This will come back to us and we will re-send it
|
|
// causing an infinite loop. BryanSt.
|
|
|
|
if (_fRaised && EVAL(_hwndRaised))
|
|
PropagateMessage(_hwndRaised, uMsg, wParam, lParam, fSend);
|
|
else if (EVAL(_pbbd->_hwnd))
|
|
PropagateMessage(_pbbd->_hwnd, uMsg, wParam, lParam, fSend);
|
|
}
|
|
|
|
|
|
// NOTES
|
|
// in the tray case, we actually do SetFocus etc.
|
|
HRESULT CDesktopBrowser::v_MayGetNextToolbarFocus(LPMSG lpMsg,
|
|
UINT itbCur, int citb,
|
|
LPTOOLBARITEM * pptbi, HWND * phwnd)
|
|
{
|
|
HRESULT hr;
|
|
|
|
// _fTrayHack?
|
|
|
|
if (itbCur == ITB_VIEW) {
|
|
if (citb == -1) {
|
|
TraceMsg(DM_FOCUS, "cdtb.v_mgntf: ITB_VIEW,-1 => tray");
|
|
goto Ltray;
|
|
}
|
|
}
|
|
|
|
hr = _pbsInner->v_MayGetNextToolbarFocus(lpMsg, itbCur, citb, pptbi, phwnd);
|
|
TraceMsg(DM_FOCUS, "cdtb.v_mgntf: SUPER hr=%x", hr);
|
|
if (SUCCEEDED(hr)) {
|
|
// S_OK: we got and handled a candidate
|
|
// S_FALSE: we got a candidate and our parent will finish up
|
|
ASSERT(hr != S_OK); // currently never happens (but should work)
|
|
return hr;
|
|
}
|
|
|
|
// E_xxx: no candidate
|
|
ASSERT(citb == 1 || citb == -1);
|
|
*pptbi = NULL;
|
|
if (citb == 1) {
|
|
Ltray:
|
|
*phwnd = _hwndTray;
|
|
// AndyP REVIEW: why do we do this here instead of overriding
|
|
// _SetFocus and letting commonsb call that function? Sure, this
|
|
// is one less override, but why have different code paths?
|
|
SendMessage(_hwndTray, TM_UIACTIVATEIO, TRUE, citb);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
//Lview:
|
|
*phwnd = _pbbd->_hwndView;
|
|
return S_FALSE;
|
|
}
|
|
/*NOTREACHED*/
|
|
ASSERT(0);
|
|
}
|
|
|
|
|
|
// NOTE: Please think before calling this function, in a multi-monitor system this function
|
|
// returns TRUE if you are within a certain edge for any monitor, so puEdge means puEdge
|
|
// of a certain monitor instead of the whole desktop. -- dli
|
|
|
|
BOOL CDesktopBrowser::_PtOnDesktopEdge(POINTL* ppt, LPUINT puEdge)
|
|
{
|
|
RECT rcMonitor;
|
|
POINT pt = {ppt->x, ppt->y};
|
|
HMONITOR hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
|
|
// We got this point from drop, so it definitely should belong to a valid monitor -- dli
|
|
ASSERT(hMon);
|
|
GetMonitorRect(hMon, &rcMonitor);
|
|
|
|
// if it's near/on the edge on this monitor
|
|
if (ppt->x < rcMonitor.left + g_cxEdge) {
|
|
*puEdge = ABE_LEFT;
|
|
} else if (ppt->x > rcMonitor.right - g_cxEdge) {
|
|
*puEdge = ABE_RIGHT;
|
|
} else if (ppt->y < rcMonitor.top + g_cyEdge) {
|
|
*puEdge = ABE_TOP;
|
|
} else if (ppt->y > rcMonitor.bottom - g_cyEdge) {
|
|
*puEdge = ABE_BOTTOM;
|
|
} else {
|
|
*puEdge = (UINT)-1;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
UINT g_cfDeskBand = 0;
|
|
|
|
HRESULT CDesktopBrowser::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
|
|
{
|
|
ASSERT(pdtobj);
|
|
if (!g_cfDeskBand)
|
|
g_cfDeskBand = RegisterClipboardFormat(TEXT("DeskBand"));
|
|
|
|
FORMATETC fmte = { (CLIPFORMAT) g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
|
|
if (pdtobj->QueryGetData(&fmte) == S_OK) {
|
|
_dwEffectOnEdge = DROPEFFECT_COPY | DROPEFFECT_MOVE;
|
|
} else {
|
|
_dwEffectOnEdge = DROPEFFECT_NONE;
|
|
}
|
|
|
|
_grfKeyState = grfKeyState;
|
|
|
|
HRESULT hr;
|
|
|
|
if (_pdtInner)
|
|
hr = _pdtInner->DragEnter(pdtobj, grfKeyState, ptl, pdwEffect);
|
|
else
|
|
{
|
|
_DragEnter(_pbbd->_hwndView, ptl, pdtobj);
|
|
hr = S_OK;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
_DragMove(_pbbd->_hwndView, ptl);
|
|
_grfKeyState = grfKeyState;
|
|
|
|
if (_dwEffectOnEdge != DROPEFFECT_NONE) {
|
|
*pdwEffect &= _dwEffectOnEdge;
|
|
return S_OK;
|
|
}
|
|
|
|
if (_pdtInner)
|
|
hr = _pdtInner->DragOver(grfKeyState, ptl, pdwEffect);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT DeskBarApp_Create(IUnknown** ppunkBar, IUnknown** ppunkBandSite)
|
|
{
|
|
IDeskBar* pdb;
|
|
HRESULT hres = CoCreateInstance(CLSID_DeskBarApp, NULL, CLSCTX_INPROC_SERVER, IID_IDeskBar, (void **)&pdb);
|
|
*ppunkBar = pdb;
|
|
if (SUCCEEDED(hres)) {
|
|
pdb->GetClient(ppunkBandSite);
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
// ENTRY/EXIT
|
|
// hres AddBand result on success; o.w. failure code
|
|
// NOTES
|
|
// n.b. on success we *must* return AddBand's hres (which is a dwBandID)
|
|
HRESULT CDesktopBrowser::_CreateDeskBarForBand(UINT uEdge, IUnknown *punk, POINTL *pptl, IBandSite **ppbsOut)
|
|
{
|
|
IBandSite *pbs;
|
|
IUnknown *punkBar;
|
|
IUnknown *punkBandSite;
|
|
HRESULT hres;
|
|
#ifdef DEBUG
|
|
HRESULT hresRet = -1;
|
|
#endif
|
|
|
|
if (ppbsOut)
|
|
*ppbsOut = NULL;
|
|
|
|
hres = DeskBarApp_Create(&punkBar, &punkBandSite);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
IDockingBarPropertyBagInit* ppbi;
|
|
|
|
if (SUCCEEDED(CoCreateInstance(CLSID_CDockingBarPropertyBag, NULL, CLSCTX_INPROC_SERVER, IID_IDockingBarPropertyBagInit, (void **)&ppbi)))
|
|
{
|
|
if ((UINT)uEdge != -1) {
|
|
ppbi->SetDataDWORD(PROPDATA_MODE, WBM_BOTTOMMOST);
|
|
ppbi->SetDataDWORD(PROPDATA_SIDE, uEdge);
|
|
} else {
|
|
ppbi->SetDataDWORD(PROPDATA_MODE, WBM_FLOATING);
|
|
}
|
|
|
|
ppbi->SetDataDWORD(PROPDATA_X, pptl->x);
|
|
ppbi->SetDataDWORD(PROPDATA_Y, pptl->y);
|
|
|
|
|
|
IPropertyBag * ppb;
|
|
if (SUCCEEDED(ppbi->QueryInterface(IID_IPropertyBag, (void **)&ppb)))
|
|
{
|
|
SHLoadFromPropertyBag(punkBar, ppb);
|
|
|
|
punkBandSite->QueryInterface(IID_IBandSite, (void **)&pbs);
|
|
|
|
if (pbs) {
|
|
hres = pbs->AddBand(punk);
|
|
#ifdef DEBUG
|
|
hresRet = hres;
|
|
#endif
|
|
|
|
AddToolbar(punkBar, L"", NULL);
|
|
|
|
if (ppbsOut) {
|
|
// IUnknown_Set (sort of...)
|
|
*ppbsOut = pbs;
|
|
(*ppbsOut)->AddRef();
|
|
}
|
|
|
|
pbs->Release();
|
|
|
|
if (_fRaised) {
|
|
VARIANTARG vaIn = { 0 };
|
|
|
|
//VariantInit(&vaIn);
|
|
vaIn.vt = VT_I4;
|
|
vaIn.lVal = DTRF_RAISE;
|
|
|
|
ASSERT(punkBar != NULL); // o.w. we'd do a broadcast
|
|
_ExecChildren(punkBar, FALSE, &CGID_ShellDocView, SHDVID_RAISE, 0, &vaIn, NULL);
|
|
//VariantClear(&vaIn);
|
|
}
|
|
}
|
|
|
|
ppb->Release();
|
|
}
|
|
|
|
ppbi->Release();
|
|
}
|
|
|
|
punkBandSite->Release();
|
|
punkBar->Release();
|
|
}
|
|
|
|
ASSERT(hres == hresRet || FAILED(hres));
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
|
|
{
|
|
UINT uEdge;
|
|
HRESULT hres = E_FAIL;
|
|
|
|
if (((_PtOnDesktopEdge(&pt, &uEdge) && (_grfKeyState & MK_LBUTTON)) ||
|
|
(_dwEffectOnEdge != DROPEFFECT_NONE)) && !SHRestricted(REST_NOCLOSE_DRAGDROPBAND)) {
|
|
|
|
|
|
// if the point is on the edge of the desktop and the item dropped was
|
|
// a single url object, then create a webbar
|
|
// TODO: (reuse) w/ a little restructuring we might share this code
|
|
// w/ CBandSite::Drop etc.
|
|
|
|
FORMATETC fmte = {(CLIPFORMAT)g_cfDeskBand, NULL, 0, -1, TYMED_ISTREAM};
|
|
STGMEDIUM stg;
|
|
LPITEMIDLIST pidl;
|
|
IUnknown* punk = NULL;
|
|
|
|
// we can move a band from bar to bar, but we can only copy or link a folder
|
|
// because the creation of a band relies on the source still abeing there
|
|
if ((*pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_MOVE)) &&
|
|
SUCCEEDED(pdtobj->GetData(&fmte, &stg))) {
|
|
|
|
// this is a drag of a band from another bar, create it!
|
|
hres = OleLoadFromStream(stg.pstm, IID_IUnknown, (void **)&punk);
|
|
if (SUCCEEDED(hres)) {
|
|
if (*pdwEffect & DROPEFFECT_COPY)
|
|
*pdwEffect = DROPEFFECT_COPY;
|
|
else
|
|
*pdwEffect = DROPEFFECT_MOVE;
|
|
}
|
|
ReleaseStgMedium(&stg);
|
|
|
|
} else if ((*pdwEffect & (DROPEFFECT_COPY | DROPEFFECT_LINK)) &&
|
|
SUCCEEDED(SHPidlFromDataObject(pdtobj, &pidl, NULL, 0))) {
|
|
|
|
hres = SHCreateBandForPidl(pidl, &punk, (grfKeyState & (MK_CONTROL | MK_SHIFT)) == (MK_CONTROL | MK_SHIFT));
|
|
|
|
ILFree(pidl);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
if (*pdwEffect & DROPEFFECT_LINK)
|
|
*pdwEffect = DROPEFFECT_LINK;
|
|
else
|
|
*pdwEffect = DROPEFFECT_COPY;
|
|
}
|
|
|
|
}
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
|
|
if (punk) {
|
|
IBandSite *pbs;
|
|
hres = _CreateDeskBarForBand(uEdge, punk, &pt, &pbs);
|
|
|
|
if (SUCCEEDED(hres)) {
|
|
DWORD dwState;
|
|
|
|
dwState = IDataObject_GetDeskBandState(pdtobj);
|
|
pbs->SetBandState(ShortFromResult(hres), BSSF_NOTITLE, dwState & BSSF_NOTITLE);
|
|
pbs->Release();
|
|
}
|
|
|
|
punk->Release();
|
|
}
|
|
|
|
IDropTarget *pdtView;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
//Get the view's drop target
|
|
if (_pbbd->_psv)
|
|
{
|
|
hr = _pbbd->_psv->QueryInterface(IID_IDropTarget, (void **)&pdtView);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pdtView->DragLeave();
|
|
pdtView->Release();
|
|
}
|
|
}
|
|
return hres;
|
|
}
|
|
|
|
|
|
// if we failed, pass this on to our child.
|
|
// this allows things like d/d of wallpaper to the edge to do
|
|
// right thing
|
|
}
|
|
|
|
if (_pdtInner)
|
|
hres = _pdtInner->Drop(pdtobj, grfKeyState, pt, pdwEffect);
|
|
|
|
return hres;
|
|
}
|
|
|
|
BOOL _GetToken(LPCTSTR *ppszCmdLine, LPTSTR szToken, UINT cchMax)
|
|
{
|
|
LPCTSTR pszCmdLine = *ppszCmdLine;
|
|
|
|
TCHAR chTerm = ' ';
|
|
if (*pszCmdLine == TEXT('"')) {
|
|
chTerm = TEXT('"');
|
|
pszCmdLine++;
|
|
}
|
|
|
|
UINT ichToken = 0;
|
|
TCHAR ch;
|
|
while((ch=*pszCmdLine) && (ch != chTerm)) {
|
|
if (ichToken < cchMax-1) {
|
|
szToken[ichToken++] = ch;
|
|
}
|
|
pszCmdLine++;
|
|
}
|
|
|
|
szToken[ichToken] = TEXT('\0');
|
|
|
|
if (chTerm == TEXT('"') && ch == TEXT('"')) {
|
|
pszCmdLine++;
|
|
}
|
|
|
|
// skip trailing spaces
|
|
while(*pszCmdLine == TEXT(' '))
|
|
pszCmdLine++;
|
|
|
|
*ppszCmdLine = pszCmdLine;
|
|
|
|
TraceMsg(TF_SHDAUTO, "_GetToken returning %s (+%s)", szToken, pszCmdLine);
|
|
|
|
return szToken[0];
|
|
}
|
|
|
|
|
|
BOOL CDesktopBrowser::_OnCopyData(PCOPYDATASTRUCT pcds)
|
|
{
|
|
IETHREADPARAM *piei = SHCreateIETHREADPARAM(NULL, (ULONG)pcds->dwData, NULL, NULL);
|
|
if (piei)
|
|
{
|
|
LPCWSTR pwszSrc = (LPCWSTR)pcds->lpData;
|
|
LPCWSTR pwszDdeRegEvent = NULL;
|
|
LPCWSTR pwszCloseEvent = NULL;
|
|
DWORD cchSrc = pcds->cbData / SIZEOF(WCHAR);
|
|
|
|
piei->uFlags = COF_NORMAL | COF_WAITFORPENDING | COF_IEXPLORE;
|
|
|
|
|
|
// Remember where the command line parameters are.
|
|
|
|
LPCWSTR pszCmd = pwszSrc;
|
|
int cch = lstrlenW(pwszSrc) + 1;
|
|
pwszSrc += cch;
|
|
cchSrc -= cch;
|
|
|
|
TraceMsg(TF_SHDAUTO, "CDB::_OnCopyData got %hs", pszCmd);
|
|
|
|
|
|
// Get the dde reg event name into piei->szDdeRegEvent.
|
|
|
|
|
|
// NOTE: this is now conditional because we now launch the channel band from the desktop
|
|
// NOTE: as a fake WM_COPYDATA command
|
|
if (cchSrc)
|
|
{
|
|
ASSERT(cchSrc);
|
|
pwszDdeRegEvent = pwszSrc;
|
|
StrCpyNW(piei->szDdeRegEvent, pwszSrc, ARRAYSIZE(piei->szDdeRegEvent));
|
|
cch = lstrlenW(pwszSrc) + 1;
|
|
pwszSrc += cch;
|
|
cchSrc -= cch;
|
|
piei->uFlags |= COF_FIREEVENTONDDEREG;
|
|
|
|
|
|
// Get the name of the event to fire on close, if any.
|
|
|
|
if (cchSrc)
|
|
{
|
|
pwszCloseEvent = pwszSrc;
|
|
StrCpyNW(piei->szCloseEvent, pwszSrc, ARRAYSIZE(piei->szCloseEvent));
|
|
cch = lstrlenW(pwszSrc) + 1;
|
|
pwszSrc += cch;
|
|
cchSrc -= cch;
|
|
piei->uFlags |= COF_FIREEVENTONCLOSE;
|
|
|
|
}
|
|
}
|
|
|
|
ASSERT(cchSrc == 0);
|
|
|
|
if (pszCmd && pszCmd[0])
|
|
{
|
|
// for compatibility with apps that spawn the browser with a command line
|
|
// tell wininet to refresh its proxy settings. (this is particularly needed
|
|
// for TravelSoft WebEx)
|
|
MyInternetSetOption(NULL, INTERNET_OPTION_SETTINGS_CHANGED, NULL, 0);
|
|
|
|
if (SHParseIECommandLine(&pszCmd, piei))
|
|
piei->uFlags |= COF_NOFINDWINDOW;
|
|
|
|
if (pszCmd[0] && FAILED(_ConvertPathToPidlW(_pbsInner, _pbbd->_hwnd, pszCmd, &piei->pidl)))
|
|
piei->pidl = NULL;
|
|
}
|
|
else
|
|
{
|
|
piei->fCheckFirstOpen = TRUE;
|
|
}
|
|
|
|
// SHOpenFolderWindow takes ownership of piei
|
|
BOOL fRes = SHOpenFolderWindow(piei);
|
|
if (!fRes)
|
|
{
|
|
|
|
// Something went wrong creating the browser,
|
|
// let's fire all the events ourselves.
|
|
|
|
if (pwszDdeRegEvent) FireEventW(pwszDdeRegEvent);
|
|
if (pwszCloseEvent) FireEventW(pwszCloseEvent);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "OnCopyData unable to create IETHREADPARAM");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CDesktopBrowser::_InitScheduler(void)
|
|
{
|
|
if (!_psched)
|
|
{
|
|
// get the system background scheduler thread
|
|
CoCreateInstance(CLSID_SharedTaskScheduler, NULL, CLSCTX_INPROC, IID_IShellTaskScheduler, (void **) &_psched);
|
|
}
|
|
|
|
return (_psched != NULL);
|
|
}
|
|
|
|
|
|
HRESULT CDesktopBrowser::_AddDesktopTask(IRunnableTask *ptask, DWORD dwPriority)
|
|
{
|
|
if (_InitScheduler())
|
|
return _psched->AddTask(ptask, TOID_Desktop, 0, dwPriority);
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
void CDesktopBrowser::_OnAddToRecent( HANDLE hMem, DWORD dwProcId )
|
|
{
|
|
IRunnableTask *ptask;
|
|
if (SUCCEEDED(CTaskAddDoc_Create(hMem, dwProcId, &ptask)))
|
|
{
|
|
_AddDesktopTask(ptask, ITSAT_DEFAULT_PRIORITY);
|
|
ptask->Release();
|
|
}
|
|
}
|
|
|
|
LRESULT CDesktopBrowser::WndProcBS(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
INSTRUMENT_WNDPROC(SHCNFI_DESKTOP_WNDPROC, _pbbd->_hwnd, uMsg, wParam, lParam);
|
|
ASSERT(IsWindowTchar(hwnd));
|
|
|
|
switch (uMsg)
|
|
{
|
|
#ifdef DEBUG
|
|
case WM_QUERYENDSESSION:
|
|
TraceMsg(DM_SHUTDOWN, "cdtb.wp: WM_QUERYENDSESSION");
|
|
goto DoDefault;
|
|
#endif
|
|
|
|
case WM_ENDSESSION:
|
|
TraceMsg(DM_SHUTDOWN, "cdtb.wp: WM_ENDSESSION wP=%d lP=%d", wParam, lParam);
|
|
if (wParam)
|
|
{
|
|
SHELLSTATE ss = {0};
|
|
|
|
// When we shut down, if the desktop is in WebView, we leave some temp
|
|
// files undeleted because we never get the WM_DESTROY message below.
|
|
// So, I just destroy the shellview which in turn destroys the temp
|
|
// file here. Note: This is done only if we are in web view.
|
|
|
|
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE); //Get the desktop_html flag
|
|
if (ss.fDesktopHTML)
|
|
{
|
|
ReleaseShellView();
|
|
}
|
|
|
|
g_pdtray->SetVar(SVTRAY_EXITEXPLORER, FALSE); // don't exit process
|
|
|
|
// flush log before we exit
|
|
if (StopWatchMode())
|
|
{
|
|
StopWatchFlush();
|
|
}
|
|
|
|
// Kill this window so that we free active desktop threads properly
|
|
DestroyWindow(hwnd);
|
|
}
|
|
TraceMsg(DM_SHUTDOWN, "cdtb.wp: WM_ENDSESSION return 0");
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
PaintDesktop((HDC)wParam);
|
|
return 1;
|
|
|
|
case WM_TIMER:
|
|
switch (wParam)
|
|
{
|
|
case IDT_DDETIMEOUT:
|
|
DDEHandleTimeout(_pbbd->_hwnd);
|
|
break;
|
|
|
|
default:
|
|
|
|
if (wParam >= IDT_DISKFULL && (wParam <= IDT_DISKFULLLAST))
|
|
{
|
|
int idDrive = (int) (wParam - IDT_DISKFULL - 1);
|
|
KillTimer(_pbbd->_hwnd, (UINT) wParam);
|
|
TraceMsg(DM_TRACE, "Disk %c: is full", TEXT('a') + idDrive);
|
|
|
|
// are we already handling it?
|
|
if (!((1 << idDrive) & _dwDiskFullDrives))
|
|
{
|
|
_dwDiskFullDrives |= (1 << idDrive);
|
|
SHHandleDiskFull(_pbbd->_hwnd, idDrive);
|
|
_dwDiskFullDrives &= ~(1 << idDrive);
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(DM_TRACE, "Punting because we're already dealing");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_SHELLNOTIFY:
|
|
switch(wParam)
|
|
{
|
|
case SHELLNOTIFY_DISKFULL:
|
|
SetTimer(_pbbd->_hwnd, IDT_DISKFULL + (UINT) lParam, DISKFULL_TIMEOUT, NULL);
|
|
break;
|
|
|
|
case SHELLNOTIFY_WALLPAPERCHANGED:
|
|
// Changing the wallpaper through theme switcher and some other apps, do not
|
|
// result in WININICHANGE message. So, we handle this notification. However,
|
|
// under NT, we do not get this notification. So, we do this under WinIniChange
|
|
// processing too!
|
|
if(!g_fRunningOnNT)
|
|
{
|
|
SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
|
|
}
|
|
// this is done only to the shell window when someone sets
|
|
// the wall paper but doesn't specify to broadcast
|
|
_pbsInner->ForwardViewMsg(uMsg, wParam, lParam);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_PALETTECHANGED:
|
|
case WM_QUERYNEWPALETTE:
|
|
|
|
// in Win95 the desktop wndproc will invalidate the shell window when
|
|
// a palette change occurs so we didn't have to do anything here before
|
|
|
|
// in Nashville the desktop can be HTML and needs the palette messages
|
|
|
|
// so now we fall through and propagate...
|
|
|
|
case WM_ACTIVATEAPP:
|
|
if (!_pbbd->_hwndView)
|
|
goto DoDefault;
|
|
|
|
return _pbsInner->ForwardViewMsg(uMsg, wParam, lParam);
|
|
|
|
case WM_DEVICECHANGE:
|
|
_pbsInner->ForwardViewMsg(uMsg, wParam, lParam);
|
|
_OnDeviceBroadcast(_pbbd->_hwnd, wParam, (DEV_BROADCAST_HDR *)lParam);
|
|
goto DoDefault;
|
|
|
|
case WM_WINDOWPOSCHANGING:
|
|
#define ppos ((LPWINDOWPOS)lParam)
|
|
ppos->x = g_xVirtualScreen;
|
|
ppos->y = g_yVirtualScreen;
|
|
ppos->cx = g_cxVirtualScreen;
|
|
ppos->cy = g_cyVirtualScreen;
|
|
break;
|
|
|
|
case WM_CHANGENOTIFY:
|
|
{
|
|
LPITEMIDLIST *ppidl;
|
|
LONG lEvent;
|
|
LPSHChangeNotificationLock pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
|
|
if (pshcnl)
|
|
{
|
|
_OnChangeNotify(lEvent, ppidl);
|
|
SHChangeNotification_Unlock(pshcnl);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_HOTKEY:
|
|
// NOTE: forward hotkeys to the tray. This fixes the logitech mouseman who sends
|
|
// NOTE: hotkeys directly to the desktop.
|
|
// SPECIAL NOTE: the offset for GHID_FIRST is added because hotkeys that are sent to the
|
|
// SPECIAL NOTE: desktop are not proper hotkeys generated from the keyboard, they are
|
|
// SPECIAL NOTE: sent by an app, and the IDs have changed since win95....
|
|
ASSERT( g_hwndTray );
|
|
ASSERT( wParam < GHID_FIRST );
|
|
PostMessage( g_hwndTray, uMsg, wParam + GHID_FIRST, lParam );
|
|
return 0;
|
|
|
|
case WM_SYSCOMMAND:
|
|
switch (wParam & 0xFFF0) {
|
|
// NB Dashboard 1.0 sends a WM_SYSCOMMAND SC_CLOSE to the desktop when it starts up.
|
|
// What it was trying to do was to close down any non-shell versions of Progman. The
|
|
// proper shell version would just ignore the close. Under Chicago, they think that
|
|
// the desktop is Progman and send it the close, so we put up the exit windows dialog!
|
|
// Dashboard 2.0 has been fixed to avoid this bogisity.
|
|
case SC_CLOSE:
|
|
break;
|
|
|
|
// America alive tries to minimise Progman after installing - they end up minimising
|
|
// the desktop on Chicago!
|
|
case SC_MINIMIZE:
|
|
break;
|
|
|
|
default:
|
|
goto DoDefault;
|
|
}
|
|
break;
|
|
|
|
case WM_SETCURSOR:
|
|
// REVIEW: is this really needed?
|
|
if (_iWaitCount)
|
|
{
|
|
SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
|
|
return TRUE;
|
|
}
|
|
else
|
|
goto DoDefault;
|
|
|
|
case WM_CLOSE:
|
|
SendMessage(_hwndTray, TM_DOEXITWINDOWS, 0, 0);
|
|
return 0;
|
|
|
|
// REVIEW: do we need this, BUGBUG: can all of these cases be the same?
|
|
case WM_DRAWITEM:
|
|
case WM_MEASUREITEM:
|
|
if (!_pbsInner->ForwardViewMsg(uMsg, wParam, lParam))
|
|
goto DoDefault;
|
|
break;
|
|
|
|
case WM_INITMENUPOPUP:
|
|
case WM_ENTERMENULOOP:
|
|
case WM_EXITMENULOOP:
|
|
// let the fsview deal with any popup menus it created
|
|
_pbsInner->ForwardViewMsg(uMsg, wParam, lParam);
|
|
break;
|
|
|
|
// Looking at messages to try to capture when the workarea may
|
|
// have changed...
|
|
case WM_DISPLAYCHANGE:
|
|
lParam = 0;
|
|
if (GetNumberOfMonitors() != _nMonitors)
|
|
_InitMonitors();
|
|
|
|
// fall through
|
|
|
|
case WM_WININICHANGE:
|
|
_InitDesktopMetrics(wParam, (LPCTSTR)lParam);
|
|
|
|
if (wParam == SPI_SETNONCLIENTMETRICS)
|
|
{
|
|
VARIANTARG varIn;
|
|
VARIANTARG varOut = {0};
|
|
varIn.vt = VT_BOOL;
|
|
varIn.boolVal = VARIANT_TRUE;
|
|
|
|
_pctInner->Exec(&CGID_Explorer, SBCMDID_CACHEINETZONEICON, OLECMDEXECOPT_DODEFAULT , &varIn, &varOut);
|
|
}
|
|
|
|
if (lParam)
|
|
{
|
|
if (lstrcmpi((LPCTSTR)lParam, TEXT("Extensions")) == 0)
|
|
{
|
|
// Post a message to our selves so we can do more stuff
|
|
// slightly delayed.
|
|
PostMessage(hwnd, DTM_SETUPAPPRAN, 0, 0);
|
|
}
|
|
else if (lstrcmpi((LPCTSTR)lParam, TEXT("ShellState")) == 0)
|
|
{
|
|
// this should cover external apps changing
|
|
// our settings.
|
|
SHRefreshSettings();
|
|
}
|
|
else
|
|
{
|
|
// SPI_GETICONTITLELONGFONT is broadcast from IE when the home page is changed. We look for that so
|
|
// we can be sure to update the MyCurrentHomePage component.
|
|
if((wParam == SPI_SETDESKWALLPAPER) || (wParam == SPI_SETDESKPATTERN) || (wParam == SPI_GETICONTITLELOGFONT))
|
|
{
|
|
// Some desktop attribute has changed. So, regenerate desktop.
|
|
if(lstrcmpi((LPCTSTR)lParam, TEXT("ToggleDesktop")) &&
|
|
lstrcmpi((LPCTSTR)lParam, TEXT("RefreshDesktop")) &&
|
|
lstrcmpi((LPCTSTR)lParam, TEXT("BufferedRefresh")))
|
|
{
|
|
DWORD dwFlags = AD_APPLY_HTMLGEN | AD_APPLY_REFRESH;
|
|
|
|
switch (wParam)
|
|
{
|
|
case SPI_SETDESKPATTERN:
|
|
dwFlags |= (AD_APPLY_FORCE | AD_APPLY_DYNAMICREFRESH);
|
|
break;
|
|
case SPI_SETDESKWALLPAPER:
|
|
dwFlags |= AD_APPLY_SAVE;
|
|
break;
|
|
case SPI_GETICONTITLELOGFONT:
|
|
dwFlags |= AD_APPLY_FORCE;
|
|
break;
|
|
}
|
|
|
|
PokeWebViewDesktop(dwFlags);
|
|
|
|
// If we are not currently in ActiveDesktop Mode, then we need to set the dirty bit
|
|
// sothat a new HTML file will be generated showing the new wallpaper,
|
|
// the next time the active desktop is turned ON!
|
|
if(g_fRunningOnNT && (wParam == SPI_SETDESKWALLPAPER))
|
|
{
|
|
SHELLSTATE ss = {0};
|
|
SHGetSetSettings(&ss, SSF_DESKTOPHTML, FALSE); //Get the desktop_html flag
|
|
if (!ss.fDesktopHTML)
|
|
SetDesktopFlags(COMPONENTS_DIRTY, COMPONENTS_DIRTY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (g_fRunningOnNT)
|
|
{
|
|
// NT has a control panel applet that allows users to change the
|
|
// environment with-which to spawn new applications. On NT, we need
|
|
// to pick up that environment change so that anything we spawn in
|
|
// the future will pick up those updated environment values.
|
|
|
|
if (lParam && (lstrcmpi((LPTSTR)lParam, TEXT("Environment")) == 0))
|
|
{
|
|
void *pv;
|
|
RegenerateUserEnvironment(&pv, TRUE);
|
|
}
|
|
}
|
|
|
|
v_PropagateMessage(uMsg, wParam, lParam, TRUE);
|
|
SetWindowPos(_pbbd->_hwnd, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER);
|
|
if ((uMsg == WM_DISPLAYCHANGE) || (wParam == SPI_SETWORKAREA))
|
|
_SetViewArea();
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
|
|
// In memphis, when apps go into low-res mode, we get this message. We should not re-generate
|
|
// desktop.htt in this scenario, or else the centered wallpaper gets screwed up because we do not
|
|
// get the message when the app exists and the resoultion goes up. So, we make the following check.
|
|
|
|
if(!IsTempDisplayMode())
|
|
OnDesktopSysColorChange();
|
|
//This is done sothat the defview can set the listview in proper
|
|
//colors.
|
|
_pbsInner->ForwardViewMsg(uMsg, wParam, lParam);
|
|
break;
|
|
|
|
// Don't go to default wnd proc for this one...
|
|
case WM_INPUTLANGCHANGEREQUEST:
|
|
if (wParam)
|
|
goto DoDefault;
|
|
else
|
|
return 0;
|
|
|
|
case WM_COPYDATA:
|
|
return _OnCopyData((PCOPYDATASTRUCT)lParam);
|
|
|
|
case CWM_COMMANDLINE:
|
|
SHOnCWMCommandLine(lParam);
|
|
break;
|
|
|
|
case CWM_FSNOTIFY:
|
|
return SHChangeNotify_OnNotify(wParam, lParam);
|
|
|
|
case CWM_CHANGEREGISTRATION:
|
|
return (LRESULT)SHChangeRegistrationReceive((HANDLE)wParam, (DWORD)lParam);
|
|
|
|
case CWM_FSNOTIFYSUSPENDRESUME:
|
|
return (LRESULT)SHChangeNotifySuspendResumeReceive(wParam, lParam);
|
|
|
|
case CWM_ADDTORECENT:
|
|
_OnAddToRecent((HANDLE)wParam, (DWORD) lParam);
|
|
return 0;
|
|
|
|
case CWM_WAITOP:
|
|
SHWaitOp_Operate((HANDLE)wParam, (DWORD)lParam);
|
|
return 0;
|
|
|
|
case CWM_SHOWFOLDEROPT:
|
|
// appwiz.cpl sends this message to us
|
|
DoGlobalFolderOptions();
|
|
return 0;
|
|
|
|
case DTM_CREATESAVEDWINDOWS:
|
|
_InitDeskbars();
|
|
SHCreateSavedWindows();
|
|
#ifdef ENABLE_CHANNELS
|
|
_MaybeLaunchChannelBand();
|
|
#endif
|
|
// we need to update the recycle bin icon because the recycle bin
|
|
// is per user on NTFS, and thus the state could change w/ each new user
|
|
// who logs in.
|
|
SHUpdateRecycleBinIcon();
|
|
break;
|
|
|
|
case DTM_SAVESTATE:
|
|
TraceMsg(DM_SHUTDOWN, "cdtb.wp: DTM_SAVESTATE");
|
|
_SaveState();
|
|
break;
|
|
|
|
case DTM_RAISE:
|
|
_OnRaise(wParam, lParam);
|
|
break;
|
|
|
|
#ifdef DEBUG
|
|
case DTM_NEXTCTL:
|
|
#endif
|
|
case DTM_UIACTIVATEIO:
|
|
case DTM_ONFOCUSCHANGEIS:
|
|
_OnFocusMsg(uMsg, wParam, lParam);
|
|
break;
|
|
|
|
case DTM_SETUPAPPRAN:
|
|
_SetupAppRan(wParam, lParam);
|
|
break;
|
|
|
|
case DTM_QUERYHKCRCHANGED:
|
|
#ifdef WINNT
|
|
// some clients are out of process, so we
|
|
// can cache their cookies for them.
|
|
if (!lParam && wParam > QHKCRID_NONE && wParam < QHKCRID_MAX)
|
|
lParam = (LPARAM)&_rgdwQHKCRCookies[wParam - QHKCRID_MIN];
|
|
|
|
return _QueryHKCRChanged(hwnd, (LPDWORD)lParam);
|
|
#else
|
|
// on win95 we assume it is the same
|
|
return FALSE;
|
|
#endif //WINNNT
|
|
|
|
case DTM_UPDATENOW:
|
|
UpdateWindow(hwnd);
|
|
break;
|
|
|
|
case DTM_GETVIEWAREAS:
|
|
{
|
|
// wParam is an in/out param. in - the max. # of areas, out - the actual # of areas.
|
|
// if "in" value < "out" value, lParam is not set.
|
|
// The ViewAreas are already stored in the desktop Listview.
|
|
int* pnViewAreas = (int*) wParam;
|
|
LPRECT lprcViewAreas = (LPRECT) lParam;
|
|
|
|
if (pnViewAreas)
|
|
{
|
|
int nMaxAreas = *pnViewAreas;
|
|
HWND hwndList = _GetDesktopListview();
|
|
|
|
ASSERT(IsWindow(hwndList));
|
|
ListView_GetNumberOfWorkAreas(hwndList, pnViewAreas);
|
|
if (*pnViewAreas >= 0 && *pnViewAreas <= nMaxAreas && lprcViewAreas)
|
|
{
|
|
ListView_GetWorkAreas(hwndList, *pnViewAreas, lprcViewAreas);
|
|
// These are in Listview co-ordinates. We have to map them to screen co-ordinates.
|
|
// [msadek]; MapWindowPoints() is mirroring-aware only if you pass two points
|
|
for (int i = 0; i < *pnViewAreas; i++)
|
|
{
|
|
MapWindowPoints(hwndList, HWND_DESKTOP, (LPPOINT)(&lprcViewAreas[i]), 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DTM_DESKTOPCONTEXTMENU:
|
|
if (!SHRestricted(REST_NOACTIVEDESKTOP))
|
|
{
|
|
SetForegroundWindow(hwnd);
|
|
SendMessage(_pbbd->_hwndView, WM_DSV_DESKTOPCONTEXTMENU, (WPARAM)_hwndTray, lParam);
|
|
}
|
|
break;
|
|
|
|
case DTM_MAKEHTMLCHANGES:
|
|
//Make changes to desktop's HTML using Dynamic HTML
|
|
SendMessage(_pbbd->_hwndView, WM_DSV_DESKHTML_CHANGES, wParam, lParam);
|
|
break;
|
|
|
|
// Handle DDE messages for badly written apps (that assume the shell's
|
|
// window is of class Progman and called Program Manager.
|
|
case WM_DDE_INITIATE:
|
|
case WM_DDE_TERMINATE:
|
|
case WM_DDE_ADVISE:
|
|
case WM_DDE_UNADVISE:
|
|
case WM_DDE_ACK:
|
|
case WM_DDE_DATA:
|
|
case WM_DDE_REQUEST:
|
|
case WM_DDE_POKE:
|
|
case WM_DDE_EXECUTE:
|
|
return DDEHandleMsgs(_pbbd->_hwnd, uMsg, wParam, lParam);
|
|
break;
|
|
|
|
default:
|
|
// Handle the MSWheel message - send it to the focus window if it isn't us
|
|
extern UINT g_msgMSWheel;
|
|
|
|
if (uMsg == g_msgMSWheel)
|
|
{
|
|
HWND hwndT = GetFocus();
|
|
if (_pbbd->_hwnd != hwndT)
|
|
{
|
|
PostMessage(hwndT, uMsg, wParam, lParam);
|
|
return 1;
|
|
}
|
|
}
|
|
else if (uMsg == GetDDEExecMsg())
|
|
{
|
|
ASSERT(lParam && 0 == ((LPNMHDR)lParam)->idFrom);
|
|
|
|
DDEHandleViewFolderNotify(NULL, _pbbd->_hwnd, (LPNMVIEWFOLDER)lParam);
|
|
LocalFree((LPNMVIEWFOLDER)lParam);
|
|
return TRUE;
|
|
}
|
|
|
|
DoDefault:
|
|
|
|
return _pbsInner->WndProcBS(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
#ifdef ENABLE_CHANNELS
|
|
// launch the channelbar, this is called when the desktop has finished starting up.
|
|
const WCHAR c_szwChannelBand[] = L"-channelband";
|
|
|
|
void CDesktopBrowser::_MaybeLaunchChannelBand( )
|
|
{
|
|
DWORD dwType = REG_SZ;
|
|
TCHAR szYesOrNo[20];
|
|
DWORD cbSize = sizeof(szYesOrNo);
|
|
|
|
BOOL bLaunchChannelBar = FALSE;
|
|
|
|
if(SHRegGetUSValue(TEXT("Software\\Microsoft\\Internet Explorer\\Main"), TEXT("Show_ChannelBand"),
|
|
&dwType, (LPVOID)szYesOrNo, &cbSize, FALSE, NULL, 0) == ERROR_SUCCESS)
|
|
{
|
|
bLaunchChannelBar = !lstrcmpi(szYesOrNo, TEXT("yes"));
|
|
}
|
|
// Don't launch by default post IE4
|
|
//else if ( IsOS( OS_WINDOWS ))
|
|
//{
|
|
// bLaunchChannelBar = TRUE; // launch channel bar by default on Memphis and win95
|
|
//}
|
|
|
|
if ( bLaunchChannelBar )
|
|
{
|
|
// fake up a WM_COPYDATA struct
|
|
COPYDATASTRUCT cds;
|
|
cds.dwData = SW_NORMAL;
|
|
cds.cbData = sizeof( c_szwChannelBand );
|
|
cds.lpData = (LPVOID) c_szwChannelBand;
|
|
|
|
// fake it as if we had launched iexplore.exe, it saves us a whole process doing it this way....
|
|
_OnCopyData( &cds );
|
|
}
|
|
}
|
|
#endif // ENABLE_CHANNELS
|
|
|
|
|
|
// NOTES
|
|
// BUGBUG should this be CBaseBrowser::IInputObject::UIActIO etc.?
|
|
HRESULT CDesktopBrowser::_OnFocusMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
BOOL fActivate = (BOOL) wParam;
|
|
|
|
switch (uMsg) {
|
|
case DTM_UIACTIVATEIO:
|
|
fActivate = (BOOL) wParam;
|
|
TraceMsg(DM_FOCUS, "cdtb.oxiois: DTM_UIActIO fAct=%d dtb=%d", fActivate, (int) lParam);
|
|
|
|
if (fActivate) {
|
|
MSG msg = {_pbbd->_hwnd, WM_KEYDOWN, VK_TAB, 0xf0001};
|
|
BOOL bShift = (GetAsyncKeyState(VK_SHIFT) < 0);
|
|
if (bShift) {
|
|
int cToolbars = _pbsInner->_GetToolbarCount();
|
|
while (--cToolbars >= 0) {
|
|
// activate last toolbar in tab order
|
|
LPTOOLBARITEM ptbi = _pbsInner->_GetToolbarItem(cToolbars);
|
|
if (ptbi && ptbi->ptbar) {
|
|
IInputObject* pio;
|
|
if (SUCCEEDED(ptbi->ptbar->QueryInterface(IID_IInputObject, (LPVOID*)&pio))) {
|
|
pio->UIActivateIO(TRUE, &msg);
|
|
pio->Release();
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef KEYBOARDCUES
|
|
// Since we are Tab or Shift Tab we should turn the focus rect on.
|
|
SendMessage(_pbbd->_hwnd, WM_UPDATEUISTATE, MAKEWPARAM(UIS_CLEAR,
|
|
UISF_HIDEFOCUS), 0);
|
|
#endif
|
|
|
|
// activate view
|
|
if (bShift && _pbbd->_psv)
|
|
{
|
|
_pbbd->_psv->TranslateAccelerator(&msg);
|
|
}
|
|
else
|
|
{
|
|
_pbsInner->_SetFocus(NULL, _pbbd->_hwndView, NULL);
|
|
}
|
|
}
|
|
else {
|
|
Ldeact:
|
|
// if we don't have focus, we're fine;
|
|
// if we do have focus, there's nothing we can do about it...
|
|
/*NOTHING*/
|
|
;
|
|
#ifdef DEBUG
|
|
TraceMsg(DM_FOCUS, "cdtb.oxiois: GetFocus()=%x _pbbd->_hwnd=%x _pbbd->_hwndView=%x", GetFocus(), _pbbd->_hwnd, _pbbd->_hwndView);
|
|
#endif
|
|
}
|
|
|
|
break;
|
|
|
|
case DTM_ONFOCUSCHANGEIS:
|
|
TraceMsg(DM_FOCUS, "cdtb.oxiois: DTM_OnFocChgIS hwnd=%x fAct=%d", (HWND) lParam, fActivate);
|
|
|
|
if (fActivate) {
|
|
// someone else is activating, so we need to deactivate
|
|
goto Ldeact;
|
|
}
|
|
// BUGBUG forward up? (to whom?)
|
|
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
LRESULT CALLBACK CDesktopBrowser::DesktopWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CDesktopBrowser *psb = (CDesktopBrowser*)GetWindowLongPtr(hwnd, 0);
|
|
|
|
switch(uMsg)
|
|
{
|
|
#ifdef KEYBOARDCUES
|
|
case WM_CREATE:
|
|
// Initialize our keyboard cues bits
|
|
SendMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_INITIALIZE, 0), 0);
|
|
|
|
// Set the localized name of the Desktop so it can be used in Error messages
|
|
// that have the desktop window as the title.
|
|
if (EVAL(LoadStringW(HINST_THISDLL, IDS_DESKTOP, psb->_wzDesktopTitle, ARRAYSIZE(psb->_wzDesktopTitle))))
|
|
{
|
|
EVAL(SetProp(hwnd, TEXT("pszDesktopTitleW"), (HANDLE)psb->_wzDesktopTitle));
|
|
}
|
|
|
|
if (psb)
|
|
return psb->WndProcBS(hwnd, uMsg, wParam, lParam);
|
|
else
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam); // known charset
|
|
|
|
case WM_ACTIVATE:
|
|
if (WA_INACTIVE == LOWORD(wParam))
|
|
SendMessage(hwnd, WM_CHANGEUISTATE,
|
|
MAKEWPARAM(UIS_SET, UISF_HIDEFOCUS | UISF_HIDEACCEL), 0);
|
|
|
|
goto DoDefault;
|
|
break;
|
|
#endif
|
|
|
|
case WM_NCCREATE:
|
|
|
|
ASSERT(psb == NULL);
|
|
|
|
CDesktopBrowser_CreateInstance(hwnd, (void **)&psb);
|
|
|
|
SetWindowLongPtr(hwnd, 0, (LONG_PTR)psb);
|
|
|
|
// BUGBUG needed?
|
|
// DdeNewWindow(hwnd);
|
|
if (psb)
|
|
goto DoDefault;
|
|
return 0;
|
|
|
|
case WM_NCDESTROY:
|
|
|
|
if (psb)
|
|
{
|
|
RemoveProp(hwnd, TEXT("pszDesktopTitleW"));
|
|
// In case someone does a get shell window and post a WM_QUIT, we need to
|
|
// make sure that we also close down our other thread.
|
|
TraceMsg(DM_SHUTDOWN, "cdtb.wp(WM_NCDESTROY): ?post WM_QUIT hwndTray=%x(IsWnd=%d)", psb->_hwndTray, IsWindow(psb->_hwndTray));
|
|
if (psb->_hwndTray && IsWindow(psb->_hwndTray))
|
|
PostMessage(psb->_hwndTray, WM_QUIT, 0, 0);
|
|
psb->ReleaseShellView();
|
|
psb->Release();
|
|
}
|
|
|
|
PostQuitMessage(0); // exit out message loop
|
|
break;
|
|
|
|
default:
|
|
if (psb)
|
|
return psb->WndProcBS(hwnd, uMsg, wParam, lParam);
|
|
else {
|
|
DoDefault:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam); // known charset
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void RegisterDesktopClass()
|
|
{
|
|
WNDCLASS wc = {0};
|
|
|
|
wc.style = CS_DBLCLKS;
|
|
wc.lpfnWndProc = CDesktopBrowser::DesktopWndProc;
|
|
//wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = SIZEOF(void *);
|
|
wc.hInstance = HINST_THISDLL;
|
|
//wc.hIcon = NULL;
|
|
wc.hCursor = GetClassCursor(GetDesktopWindow());
|
|
wc.hbrBackground = (HBRUSH)(COLOR_DESKTOP + 1);
|
|
//wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = DESKTOPCLASS;
|
|
|
|
RegisterClass(&wc);
|
|
}
|
|
|
|
#ifdef BETA_WARNING // {
|
|
#pragma message("buidling with time bomb enabled")
|
|
void DoTimebomb(HWND hwnd)
|
|
{
|
|
SYSTEMTIME st;
|
|
GetSystemTime(&st);
|
|
|
|
// BUGBUG: Remove after the beta-release!!!
|
|
|
|
// Revision History:
|
|
// End of October, 1996
|
|
// April, 1997
|
|
// September, 1997 (for beta-1)
|
|
// November 15th, 1997 (for beta-2)
|
|
|
|
if (st.wYear > 1997 || (st.wYear==1997 && st.wMonth > 11) ||
|
|
(st.wYear==1997 && st.wMonth == 11 && st.wDay > 15))
|
|
{
|
|
TCHAR szTitle[128];
|
|
TCHAR szBeta[512];
|
|
|
|
LoadString(HINST_THISDLL, IDS_CABINET, szTitle, ARRAYSIZE(szTitle));
|
|
LoadString(HINST_THISDLL, IDS_BETAEXPIRED, szBeta, ARRAYSIZE(szBeta));
|
|
|
|
MessageBox(hwnd, szBeta, szTitle, MB_OK);
|
|
}
|
|
}
|
|
#endif // BETA_WARNING // }
|
|
|
|
|
|
#define PEEK_NORMAL 0
|
|
#define PEEK_QUIT 1
|
|
#define PEEK_CONTINUE 2
|
|
#define PEEK_CLOSE 3
|
|
|
|
|
|
// RETURNS BOOL whehter to continue the search or not.
|
|
// so FALSE means we've found one.
|
|
// TRUE means we haven't.
|
|
BOOL CALLBACK FindBrowserWindow_Callback(HWND hwnd, LPARAM lParam)
|
|
{
|
|
if (IsExplorerWindow(hwnd) || IsFolderWindow(hwnd) || IsTrayWindow(hwnd)) {
|
|
DWORD dwProcID;
|
|
GetWindowThreadProcessId(hwnd, &dwProcID);
|
|
if (dwProcID == GetCurrentProcessId()) {
|
|
if (lParam)
|
|
*((BOOL*)lParam) = TRUE; // found one!
|
|
return FALSE; // stop search
|
|
}
|
|
}
|
|
return TRUE; // continue search
|
|
}
|
|
|
|
#define IsBrowserWindow(hwnd) !FindBrowserWindow_Callback(hwnd, NULL)
|
|
|
|
BOOL CALLBACK CloseWindow_Callback(HWND hwnd, LPARAM lParam)
|
|
{
|
|
if (IsBrowserWindow(hwnd)) {
|
|
TraceMsg(DM_SHUTDOWN, "s.cw_cb: post WM_CLOSE hwnd=%x", hwnd);
|
|
PostMessage(hwnd, WM_CLOSE, 0, 0);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
UINT CDesktopBrowser::_PeekForAMessage()
|
|
{
|
|
MSG msg;
|
|
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
|
{
|
|
if (msg.message == WM_QUIT)
|
|
{
|
|
TraceMsg(DM_SHUTDOWN, "cdtb.pfam: WM_QUIT wP=%d [lP=%d]", msg.wParam, msg.lParam);
|
|
if (msg.lParam == 1) {
|
|
return PEEK_CLOSE;
|
|
}
|
|
TraceMsg(DM_TRACE, "c.ml: Got quit message for %#08x", GetCurrentThreadId());
|
|
return PEEK_QUIT; // break all the way out of the main loop
|
|
}
|
|
|
|
if (_pbbd->_hwnd)
|
|
{
|
|
if (S_OK == _pbsInner->v_MayTranslateAccelerator(&msg))
|
|
return PEEK_CONTINUE;
|
|
}
|
|
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
|
|
return PEEK_CONTINUE; // Go back and get the next message
|
|
}
|
|
return PEEK_NORMAL;
|
|
}
|
|
|
|
void CDesktopBrowser::_MessageLoop()
|
|
{
|
|
for ( ; ; )
|
|
{
|
|
switch (_PeekForAMessage())
|
|
{
|
|
case PEEK_QUIT:
|
|
return;
|
|
|
|
case PEEK_NORMAL:
|
|
WaitMessage();
|
|
break;
|
|
|
|
case PEEK_CONTINUE:
|
|
break;
|
|
|
|
case PEEK_CLOSE:
|
|
// we need to close all the shell windows too
|
|
TraceMsg(DM_SHUTDOWN, "cdtb._ml: PEEK_CLOSE, close/wait all");
|
|
EnumWindows(CloseWindow_Callback, 0);
|
|
{
|
|
#define MAXIMUM_DESKTOP_WAIT 15000
|
|
DWORD iStartTime = GetTickCount();
|
|
// block until all other browser windows are closed
|
|
for (;;) {
|
|
BOOL f = FALSE;
|
|
EnumWindows(FindBrowserWindow_Callback, (LPARAM)&f);
|
|
if (!f || (GetTickCount() - iStartTime > MAXIMUM_DESKTOP_WAIT))
|
|
return;
|
|
|
|
switch (_PeekForAMessage()) {
|
|
case PEEK_NORMAL:
|
|
// don't do a waitmessage because we want to exit when thelast other window is gone
|
|
// and we don't get a message to signal that
|
|
Sleep(100);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT CDesktopBrowser::QueryService(REFGUID guidService,
|
|
REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualGUID(guidService, SID_SShellDesktop))
|
|
return QueryInterface(riid, ppvObj);
|
|
|
|
return _pspInner->QueryService(guidService, riid, ppvObj);
|
|
}
|
|
|
|
void CDesktopBrowser::StartBackgroundShellTasks(void)
|
|
{
|
|
TCHAR szClass[GUIDSTR_MAX];
|
|
DWORD cchClass;
|
|
DWORD dwType;
|
|
int i = 0;
|
|
|
|
HKEY hkey;
|
|
if (ERROR_SUCCESS == RegOpenKey(g_hklmExplorer, TEXT("SharedTaskScheduler"), &hkey))
|
|
{
|
|
while (cchClass = ARRAYSIZE(szClass),
|
|
ERROR_SUCCESS == RegEnumValue(hkey, i++, szClass, &cchClass, NULL, &dwType, NULL, NULL))
|
|
{
|
|
CLSID clsid;
|
|
if (SUCCEEDED(SHCLSIDFromString(szClass, &clsid)))
|
|
{
|
|
IRunnableTask* ptask;
|
|
if (SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC, IID_IRunnableTask, (void **) &ptask)))
|
|
{
|
|
// Personally I think the start menu should have priority
|
|
// over itbar icon extraction, so set this priority list
|
|
// a tad lower than the default priority (which start menu is at)
|
|
_AddDesktopTask(ptask, ITSAT_DEFAULT_PRIORITY-1);
|
|
ptask->Release();
|
|
}
|
|
else
|
|
{
|
|
TraceMsg(TF_WARNING, "startup background task %s not registered correctly!", szClass);
|
|
}
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// create the desktop window and its shell view
|
|
DWORD_PTR DesktopWindowCreate(CDesktopBrowser ** ppBrowser)
|
|
{
|
|
*ppBrowser = NULL;
|
|
DWORD dwExStyle = WS_EX_TOOLWINDOW;
|
|
|
|
OleInitialize(NULL);
|
|
RegisterDesktopClass();
|
|
|
|
_InitDesktopMetrics(0, NULL);
|
|
|
|
dwExStyle |= IS_BIDI_LOCALIZED_SYSTEM() ? dwExStyleRTLMirrorWnd : 0L;
|
|
|
|
|
|
// NB This windows class is Progman and it's title is Program Manager. This makes
|
|
// sure apps (like ATM) think that program is running and don't fail their install.
|
|
|
|
HWND hwnd = CreateWindowEx(dwExStyle, DESKTOPCLASS, PROGMAN,
|
|
WS_POPUP | WS_CLIPCHILDREN,
|
|
g_xVirtualScreen, g_yVirtualScreen,
|
|
g_cxVirtualScreen, g_cyVirtualScreen,
|
|
NULL, NULL, HINST_THISDLL, (void *)NULL);
|
|
if (hwnd)
|
|
{
|
|
CDesktopBrowser *psb = (CDesktopBrowser*)GetWindowLongPtr(hwnd, 0);
|
|
ASSERT(psb);
|
|
|
|
if (!SHRestricted(REST_NODESKTOP))
|
|
{
|
|
// do this here to avoid painting the desktop, then repainting
|
|
// when the tray appears and causes everything to move
|
|
|
|
ShowWindow(hwnd, SW_SHOW);
|
|
UpdateWindow(hwnd);
|
|
}
|
|
|
|
DoTimebomb(hwnd);
|
|
|
|
// Cause Shell Service Objects to load, open.
|
|
// This also causes the tray thread to resume other threads
|
|
// it created during boot time, including the FS_NOTIFY thread
|
|
// and the start menu building thread. We do this here after
|
|
// the desktop thread has initialized to speed up the boot process.
|
|
// Otherwise the secondary threads created starve out the desktop
|
|
// thread and cause extra paging, thus causing the desktop to display
|
|
// much later. --MikeSch
|
|
ASSERT(psb->GetTrayWindow());
|
|
|
|
psb->StartBackgroundShellTasks();
|
|
|
|
PostMessage(psb->GetTrayWindow(), TM_HANDLEDELAYBOOTSTUFF, 0, 0);
|
|
|
|
*ppBrowser = (CDesktopBrowser*)GetWindowLongPtr(hwnd, 0);
|
|
}
|
|
|
|
return (DWORD_PTR)hwnd;
|
|
}
|
|
|
|
STDAPI_(HANDLE) SHCreateDesktop(IDeskTray* pdtray)
|
|
{
|
|
if (g_dwProfileCAP & 0x00000010)
|
|
StartCAP();
|
|
|
|
ASSERT(pdtray);
|
|
ASSERT(g_pdtray==NULL);
|
|
g_pdtray = pdtray;
|
|
pdtray->AddRef(); // this is no-op, but we want to follow the COM rule.
|
|
|
|
// put the desktop on the main thread (this is needed for win95 so that
|
|
// the DDeExecuteHack() in user.exe works, it needs the desktop and the
|
|
// DDE window on the mainthread
|
|
CDesktopBrowser *pBrowser;
|
|
if (DesktopWindowCreate(&pBrowser))
|
|
{
|
|
if (g_dwProfileCAP & 0x00040000)
|
|
StopCAP();
|
|
|
|
// hack, cast the object to a handle (otherwise we have to export the class
|
|
// declaration so that explorer.exe can use it)
|
|
return (HANDLE) pBrowser;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// nash:49485 (IME focus) and nash:nobug (win95 compat)
|
|
// make sure keyboard input goes to the desktop. this is
|
|
// a) win95 compat: where focus was on win95 and
|
|
// b) nash:49485: focus was in the empty taskband on login so
|
|
// the keys went into the bitbucket
|
|
|
|
// If some other process has stolen the foreground window,
|
|
// don't be rude and grab it back.
|
|
|
|
void FriendlySetForegroundWindow(HWND hwnd)
|
|
{
|
|
HWND hwndOld = GetForegroundWindow();
|
|
if (hwndOld)
|
|
{
|
|
DWORD dwProcessId;
|
|
|
|
GetWindowThreadProcessId(hwndOld, &dwProcessId);
|
|
if (dwProcessId == GetCurrentProcessId())
|
|
hwndOld = NULL;
|
|
}
|
|
if (!hwndOld)
|
|
SetForegroundWindow(hwnd);
|
|
}
|
|
|
|
STDAPI_(BOOL) SHDesktopMessageLoop(HANDLE hDesktop)
|
|
{
|
|
CDesktopBrowser *pBrowser = (CDesktopBrowser *) hDesktop;
|
|
if (pBrowser)
|
|
{
|
|
// We must AddRef the pBrowser because _MessageLoop() will
|
|
// Release() it if another app initiated a system shutdown.
|
|
// We will do our own Release() when we don't need the pointer
|
|
// any more.
|
|
|
|
pBrowser->AddRef();
|
|
|
|
FriendlySetForegroundWindow(pBrowser->GetDesktopWindow());
|
|
|
|
pBrowser->_MessageLoop();
|
|
|
|
// In case someone posted us a WM_QUIT message, before terminating
|
|
// the thread, make sure it is properly destroyed so that trident etc
|
|
// gets properly freed up.
|
|
HWND hwnd;
|
|
if (hwnd = pBrowser->GetDesktopWindow())
|
|
{
|
|
DestroyWindow(hwnd);
|
|
}
|
|
pBrowser->Release();
|
|
OleUninitialize();
|
|
|
|
}
|
|
return BOOLFROMPTR(pBrowser);
|
|
}
|
|
|
|
void EscapeAccelerators(LPTSTR psz)
|
|
{
|
|
LPTSTR pszEscape;
|
|
|
|
while (pszEscape = StrChr(psz, TEXT('&'))) {
|
|
|
|
int iLen = lstrlen(pszEscape)+1;
|
|
MoveMemory(pszEscape+1, pszEscape, iLen * SIZEOF(TCHAR));
|
|
pszEscape[0] = TEXT('&');
|
|
psz = pszEscape + 2;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Whenever we remove the toolbar from the desktop, we persist it.
|
|
|
|
HRESULT CDesktopBrowser::RemoveToolbar(IUnknown* punkSrc, DWORD dwRemoveFlags)
|
|
{
|
|
HRESULT hres = E_FAIL;
|
|
UINT itb = _pbsInner->_FindTBar(punkSrc);
|
|
if (itb==(UINT)-1) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
LPTOOLBARITEM ptbi = _pbsInner->_GetToolbarItem(itb);
|
|
if (ptbi && ptbi->pwszItem) {
|
|
#ifdef UNICODE
|
|
LPCWSTR szItem = ptbi->pwszItem;
|
|
#else
|
|
TCHAR szItem[256];
|
|
SHUnicodeToTChar(ptbi->pwszItem, szItem, ARRAYSIZE(szItem));
|
|
#endif
|
|
|
|
if (dwRemoveFlags & STFRF_DELETECONFIGDATA) {
|
|
|
|
DeleteDesktopViewStream(szItem);
|
|
|
|
} else {
|
|
IStream* pstm = GetDesktopViewStream(STGM_WRITE, szItem);
|
|
if (pstm) {
|
|
IPersistStreamInit* ppstm;
|
|
HRESULT hresT = punkSrc->QueryInterface(IID_IPersistStreamInit, (void **)&ppstm);
|
|
if (SUCCEEDED(hresT)) {
|
|
ppstm->Save(pstm, TRUE);
|
|
ppstm->Release();
|
|
}
|
|
pstm->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
hres = _pdwfInner->RemoveToolbar(punkSrc, dwRemoveFlags);
|
|
_UpdateViewRectSize();
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::GetBorderDW(IUnknown* punkSrc, LPRECT lprectBorder)
|
|
{
|
|
BOOL bUseHmonitor = (GetNumberOfMonitors() > 1);
|
|
return _pbsInner->_GetBorderDWHelper(punkSrc, lprectBorder, bUseHmonitor);
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::_ResizeNextBorder(UINT itb)
|
|
{
|
|
_ResizeNextBorderHelper(itb, TRUE);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::GetMonitor(IUnknown* punkSrc, HMONITOR * phMon)
|
|
{
|
|
ASSERT(phMon);
|
|
*phMon = NULL; // just in case
|
|
|
|
UINT itb = _pbsInner->_FindTBar(punkSrc);
|
|
if (itb==(UINT)-1) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
LPTOOLBARITEM ptbi = _pbsInner->_GetToolbarItem(itb);
|
|
if (ptbi) {
|
|
*phMon = ptbi->hMon;
|
|
return S_OK;
|
|
} else {
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::RequestMonitor(IUnknown* punkSrc, HMONITOR * phMonitor)
|
|
{
|
|
UINT itb = _pbsInner->_FindTBar(punkSrc);
|
|
if (itb==(UINT)-1) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
ASSERT(phMonitor);
|
|
if (IsMonitorValid(*phMonitor))
|
|
return S_OK;
|
|
else
|
|
{
|
|
*phMonitor = GetPrimaryMonitor();
|
|
return S_FALSE;
|
|
}
|
|
}
|
|
|
|
HRESULT CDesktopBrowser::SetMonitor(IUnknown* punkSrc, HMONITOR hMonNew, HMONITOR * phMonOld)
|
|
{
|
|
ASSERT(phMonOld);
|
|
*phMonOld = NULL; // just in case
|
|
|
|
UINT itb = _pbsInner->_FindTBar(punkSrc);
|
|
if (itb==(UINT)-1) {
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
LPTOOLBARITEM ptbThis = _pbsInner->_GetToolbarItem(itb);
|
|
if (ptbThis) {
|
|
*phMonOld = ptbThis->hMon;
|
|
ptbThis->hMon = hMonNew;
|
|
return S_OK;
|
|
} else {
|
|
// BUGBUG -- browseui doesn't check the error code!
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// CDesktopBrowser FORWARDERS to commonsb
|
|
|
|
|
|
// {
|
|
#define CALL_INNER(_result, _function, _arglist, _args) \
|
|
_result CDesktopBrowser:: _function _arglist { return _psbInner-> _function _args ; }
|
|
|
|
#define CALL_INNER_HRESULT(_function, _arglist, _args) CALL_INNER(HRESULT, _function, _arglist, _args)
|
|
|
|
// IShellBrowser (same as IOleInPlaceFrame)
|
|
CALL_INNER_HRESULT(GetWindow, (HWND * lphwnd), (lphwnd));
|
|
CALL_INNER_HRESULT(ContextSensitiveHelp, (BOOL fEnterMode), (fEnterMode));
|
|
CALL_INNER_HRESULT(InsertMenusSB, (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths), (hmenuShared, lpMenuWidths));
|
|
CALL_INNER_HRESULT(SetMenuSB, (HMENU hmenuShared, HOLEMENU holemenu, HWND hwnd), (hmenuShared, holemenu, hwnd));
|
|
CALL_INNER_HRESULT(RemoveMenusSB, (HMENU hmenuShared), (hmenuShared));
|
|
CALL_INNER_HRESULT(SetStatusTextSB, (LPCOLESTR lpszStatusText), (lpszStatusText));
|
|
CALL_INNER_HRESULT(EnableModelessSB, (BOOL fEnable), (fEnable));
|
|
CALL_INNER_HRESULT(TranslateAcceleratorSB, (LPMSG lpmsg, WORD wID), (lpmsg, wID) );
|
|
CALL_INNER_HRESULT(GetViewStateStream, (DWORD grfMode, LPSTREAM *ppStrm), (grfMode, ppStrm) );
|
|
CALL_INNER_HRESULT(GetControlWindow, (UINT id, HWND * lphwnd), (id, lphwnd));
|
|
CALL_INNER_HRESULT(SendControlMsg, (UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret), (id, uMsg, wParam, lParam, pret));
|
|
CALL_INNER_HRESULT(QueryActiveShellView, (struct IShellView ** ppshv), (ppshv));
|
|
CALL_INNER_HRESULT(OnViewWindowActive, (struct IShellView * ppshv), (ppshv));
|
|
CALL_INNER_HRESULT(SetToolbarItems, (LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags), (lpButtons, nButtons, uFlags));
|
|
|
|
#undef CALL_INNER
|
|
#undef CALL_INNER_HRESULT
|
|
// }
|
|
|
|
// {
|
|
#define CALL_INNER(_result, _function, _arglist, _args) \
|
|
_result CDesktopBrowser:: _function _arglist { return _pdwsInner-> _function _args ; }
|
|
|
|
#define CALL_INNER_HRESULT(_function, _arglist, _args) CALL_INNER(HRESULT, _function, _arglist, _args)
|
|
|
|
// IDockingWindowSite
|
|
// TODO: move these up from basesb to commonsb - requires toolbars
|
|
CALL_INNER_HRESULT(RequestBorderSpaceDW, (IUnknown* punkSrc, LPCBORDERWIDTHS pborderwidths), (punkSrc, pborderwidths) );
|
|
CALL_INNER_HRESULT(SetBorderSpaceDW, (IUnknown* punkSrc, LPCBORDERWIDTHS pborderwidths), (punkSrc, pborderwidths) );
|
|
|
|
#undef CALL_INNER
|
|
#undef CALL_INNER_HRESULT
|
|
// }
|
|
|
|
|
|
// {
|
|
#define CALL_INNER(_result, _function, _arglist, _args) \
|
|
_result CDesktopBrowser:: _function _arglist { return _pdwfInner-> _function _args ; }
|
|
|
|
#define CALL_INNER_HRESULT(_function, _arglist, _args) CALL_INNER(HRESULT, _function, _arglist, _args)
|
|
|
|
// IDockingWindowFrame
|
|
CALL_INNER_HRESULT(AddToolbar, (IUnknown* punkSrc, LPCWSTR pwszItem, DWORD dwReserved), (punkSrc, pwszItem, dwReserved) );
|
|
CALL_INNER_HRESULT(FindToolbar, (LPCWSTR pwszItem, REFIID riid, void **ppvObj), (pwszItem, riid, ppvObj) );
|
|
|
|
#undef CALL_INNER
|
|
#undef CALL_INNER_HRESULT
|
|
// }
|
|
|
|
// {
|
|
#define CALL_INNER(_result, _function, _arglist, _args) \
|
|
_result CDesktopBrowser:: _function _arglist { return _piosInner-> _function _args ; }
|
|
|
|
#define CALL_INNER_HRESULT(_function, _arglist, _args) CALL_INNER(HRESULT, _function, _arglist, _args)
|
|
|
|
// IInputObjectSite
|
|
CALL_INNER_HRESULT(OnFocusChangeIS, (IUnknown* punkSrc, BOOL fSetFocus), (punkSrc, fSetFocus) );
|
|
|
|
#undef CALL_INNER
|
|
#undef CALL_INNER_HRESULT
|
|
// }
|
|
|
|
// {
|
|
#define CALL_INNER(_result, _function, _arglist, _args) \
|
|
_result CDesktopBrowser:: _function _arglist { return _pdtInner-> _function _args ; }
|
|
|
|
#define CALL_INNER_HRESULT(_function, _arglist, _args) CALL_INNER(HRESULT, _function, _arglist, _args)
|
|
|
|
// *** IDropTarget ***
|
|
CALL_INNER_HRESULT(DragLeave, (void), ());
|
|
|
|
#undef CALL_INNER
|
|
#undef CALL_INNER_HRESULT
|
|
// }
|
|
|
|
// {
|
|
#define CALL_INNER(_result, _function, _arglist, _args) \
|
|
_result CDesktopBrowser:: _function _arglist { return _pbsInner-> _function _args ; }
|
|
|
|
#define CALL_INNER_HRESULT(_function, _arglist, _args) CALL_INNER(HRESULT, _function, _arglist, _args)
|
|
|
|
|
|
// *** IBrowserService2 specific methods ***
|
|
CALL_INNER_HRESULT(GetParentSite, ( IOleInPlaceSite** ppipsite), ( ppipsite) );
|
|
CALL_INNER_HRESULT(SetTitle, ( IShellView* psv, LPCWSTR pszName), ( psv, pszName) );
|
|
CALL_INNER_HRESULT(GetTitle, ( IShellView* psv, LPWSTR pszName, DWORD cchName), ( psv, pszName, cchName) );
|
|
CALL_INNER_HRESULT(GetOleObject, ( IOleObject** ppobjv), ( ppobjv) );
|
|
|
|
// think about this one.. I'm not sure we want to expose this -- Chee
|
|
// BUGBUG:: Yep soon we should have interface instead.
|
|
// My impression is that we won't document this whole interface???
|
|
CALL_INNER_HRESULT(GetTravelLog, ( ITravelLog** pptl), ( pptl) );
|
|
|
|
CALL_INNER_HRESULT(ShowControlWindow, ( UINT id, BOOL fShow), ( id, fShow) );
|
|
CALL_INNER_HRESULT(IsControlWindowShown, ( UINT id, BOOL *pfShown), ( id, pfShown) );
|
|
CALL_INNER_HRESULT(IEGetDisplayName, ( LPCITEMIDLIST pidl, LPWSTR pwszName, UINT uFlags), ( pidl, pwszName, uFlags) );
|
|
CALL_INNER_HRESULT(IEParseDisplayName, ( UINT uiCP, LPCWSTR pwszPath, LPITEMIDLIST * ppidlOut), ( uiCP, pwszPath, ppidlOut) );
|
|
CALL_INNER_HRESULT(DisplayParseError, ( HRESULT hres, LPCWSTR pwszPath), ( hres, pwszPath) );
|
|
CALL_INNER_HRESULT(NavigateToPidl, ( LPCITEMIDLIST pidl, DWORD grfHLNF), ( pidl, grfHLNF) );
|
|
|
|
CALL_INNER_HRESULT(SetNavigateState, ( BNSTATE bnstate), ( bnstate) );
|
|
CALL_INNER_HRESULT(GetNavigateState, ( BNSTATE *pbnstate), ( pbnstate) );
|
|
|
|
CALL_INNER_HRESULT(NotifyRedirect, ( IShellView* psv, LPCITEMIDLIST pidl, BOOL *pfDidBrowse), ( psv, pidl, pfDidBrowse) );
|
|
CALL_INNER_HRESULT(UpdateWindowList, (), () );
|
|
|
|
CALL_INNER_HRESULT(UpdateBackForwardState, (), () );
|
|
|
|
CALL_INNER_HRESULT(SetFlags, ( DWORD dwFlags, DWORD dwFlagMask), ( dwFlags, dwFlagMask) );
|
|
CALL_INNER_HRESULT(GetFlags, ( DWORD *pdwFlags), ( pdwFlags) );
|
|
|
|
// Tells if it can navigate now or not.
|
|
CALL_INNER_HRESULT(CanNavigateNow, (), () );
|
|
|
|
CALL_INNER_HRESULT(GetPidl, ( LPITEMIDLIST *ppidl), ( ppidl) );
|
|
CALL_INNER_HRESULT(SetReferrer, ( LPITEMIDLIST pidl), ( pidl) );
|
|
CALL_INNER(DWORD, GetBrowserIndex ,(), () );
|
|
CALL_INNER_HRESULT(GetBrowserByIndex, ( DWORD dwID, IUnknown **ppunk), ( dwID, ppunk) );
|
|
CALL_INNER_HRESULT(GetHistoryObject, ( IOleObject **ppole, IStream **pstm, IBindCtx **ppbc), ( ppole, pstm, ppbc) );
|
|
CALL_INNER_HRESULT(SetHistoryObject, ( IOleObject *pole, BOOL fIsLocalAnchor), ( pole, fIsLocalAnchor) );
|
|
|
|
CALL_INNER_HRESULT(CacheOLEServer, ( IOleObject *pole), ( pole) );
|
|
|
|
CALL_INNER_HRESULT(GetSetCodePage, ( VARIANT* pvarIn, VARIANT* pvarOut), ( pvarIn, pvarOut) );
|
|
CALL_INNER_HRESULT(OnHttpEquiv, ( IShellView* psv, BOOL fDone, VARIANT* pvarargIn, VARIANT* pvarargOut), ( psv, fDone, pvarargIn, pvarargOut) );
|
|
|
|
CALL_INNER_HRESULT(GetPalette, ( HPALETTE * hpal ), ( hpal ) );
|
|
|
|
CALL_INNER_HRESULT(OnSetFocus, (), () );
|
|
CALL_INNER_HRESULT(OnFrameWindowActivateBS, (BOOL fActive), (fActive) );
|
|
|
|
CALL_INNER_HRESULT(RegisterWindow, ( BOOL fUnregister, int swc), ( fUnregister, swc) );
|
|
CALL_INNER_HRESULT(GetBaseBrowserData,( LPCBASEBROWSERDATA* ppbd ), ( ppbd ));
|
|
CALL_INNER(LPBASEBROWSERDATA, PutBaseBrowserData,(), ());
|
|
CALL_INNER_HRESULT(CreateViewWindow, (IShellView* psvNew, IShellView* psvOld, LPRECT prcView, HWND* phwnd), (psvNew, psvOld, prcView, phwnd));;
|
|
CALL_INNER_HRESULT(SetTopBrowser, (), ());
|
|
CALL_INNER_HRESULT(InitializeDownloadManager, (), ());
|
|
CALL_INNER_HRESULT(InitializeTransitionSite, (), ());
|
|
CALL_INNER_HRESULT(Offline, (int iCmd), (iCmd));
|
|
CALL_INNER_HRESULT(AllowViewResize, (BOOL f), (f));
|
|
CALL_INNER_HRESULT(SetActivateState, (UINT u), (u));
|
|
CALL_INNER_HRESULT(UpdateSecureLockIcon, (int eSecureLock), (eSecureLock));
|
|
CALL_INNER_HRESULT(CreateBrowserPropSheetExt, (REFIID riid, void **ppvObj), (riid, ppvObj));
|
|
|
|
CALL_INNER_HRESULT(GetViewWindow,( HWND * phwnd ), ( phwnd ));
|
|
CALL_INNER_HRESULT(InitializeTravelLog,( ITravelLog* ptl, DWORD dw ), ( ptl, dw ));
|
|
|
|
CALL_INNER_HRESULT(_UIActivateView, (UINT uState), (uState) );
|
|
|
|
CALL_INNER_HRESULT(_ResizeView,(), ());
|
|
|
|
CALL_INNER_HRESULT(_ExecChildren, (IUnknown *punkBar, BOOL fBroadcast, const GUID *pguidCmdGroup,
|
|
DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut),
|
|
(punkBar, fBroadcast, pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut) );
|
|
CALL_INNER_HRESULT(_SendChildren,
|
|
(HWND hwndBar, BOOL fBroadcast, UINT uMsg, WPARAM wParam, LPARAM lParam),
|
|
(hwndBar, fBroadcast, uMsg, wParam, lParam) );
|
|
|
|
CALL_INNER_HRESULT(_OnFocusChange, (UINT itb), (itb) );
|
|
CALL_INNER_HRESULT(v_ShowHideChildWindows, (BOOL fChildOnly), (fChildOnly) );
|
|
|
|
CALL_INNER_HRESULT(_GetViewBorderRect, (RECT* prc), (prc) );
|
|
|
|
|
|
// BEGIN REVIEW: review names and need of each.
|
|
|
|
// this first set could be basebrowser only members. no one overrides
|
|
CALL_INNER_HRESULT(_CancelPendingNavigationAsync, (), () );
|
|
CALL_INNER_HRESULT(_MaySaveChanges, (), () );
|
|
CALL_INNER_HRESULT(_PauseOrResumeView, ( BOOL fPaused), ( fPaused) );
|
|
CALL_INNER_HRESULT(_DisableModeless, (), () );
|
|
|
|
// rethink these... are all of these necessary?
|
|
CALL_INNER_HRESULT(_NavigateToPidl, ( LPCITEMIDLIST pidl, DWORD grfHLNF, DWORD dwFlags), ( pidl, grfHLNF, dwFlags));
|
|
CALL_INNER_HRESULT(_TryShell2Rename, ( IShellView* psv, LPCITEMIDLIST pidlNew), ( psv, pidlNew));
|
|
CALL_INNER_HRESULT(_SwitchActivationNow, () , ( ));
|
|
CALL_INNER_HRESULT(_CancelPendingView, (), () );
|
|
|
|
//END REVIEW:
|
|
|
|
CALL_INNER(UINT, _get_itbLastFocus, (), () );
|
|
CALL_INNER_HRESULT(_put_itbLastFocus, (UINT itbLastFocus), (itbLastFocus) );
|
|
|
|
CALL_INNER_HRESULT(_ResizeNextBorderHelper, (UINT itb, BOOL bUseHmonitor), (itb, bUseHmonitor));
|
|
|
|
#undef CALL_INNER
|
|
#undef CALL_INNER_HRESULT
|
|
// }
|