406 lines
10 KiB
C++
406 lines
10 KiB
C++
|
/**************************************************************\
|
||
|
FILE: bandprxy.cpp
|
||
|
|
||
|
DESCRIPTION:
|
||
|
The CBandProxy class will allow bands to navigate a
|
||
|
generic browser window. This will work correctly if the
|
||
|
band is tied to the Browser Window because it's a ToolBar.
|
||
|
Or if it's a toolband, each time a navigation happens,
|
||
|
the top most browser window needs to be found or a new window
|
||
|
created.
|
||
|
\**************************************************************/
|
||
|
|
||
|
#include "priv.h"
|
||
|
#include "sccls.h"
|
||
|
#include "itbar.h"
|
||
|
#include "itbdrop.h"
|
||
|
#include "util.h"
|
||
|
#include <varutil.h>
|
||
|
#include "bandprxy.h"
|
||
|
|
||
|
#define DM_PERSIST DM_TRACE // trace IPS::Load, ::Save, etc.
|
||
|
|
||
|
|
||
|
//=================================================================
|
||
|
// Implementation of CBandProxy
|
||
|
//=================================================================
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: CBandProxy_CreateInstance
|
||
|
|
||
|
DESCRIPTION:
|
||
|
This function will create an instance of the
|
||
|
CBandProxy COM object.
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
|
||
|
{
|
||
|
// aggregation checking is handled in class factory
|
||
|
|
||
|
CBandProxy * p = new CBandProxy();
|
||
|
if (p)
|
||
|
{
|
||
|
*ppunk = SAFECAST(p, IBandProxy *);
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: Address Band Constructor
|
||
|
\****************************************************/
|
||
|
CBandProxy::CBandProxy() : _cRef(1)
|
||
|
{
|
||
|
DllAddRef();
|
||
|
TraceMsg(TF_SHDLIFE, "ctor CBandProxy %x", this);
|
||
|
|
||
|
// This needs to be allocated in Zero Inited Memory.
|
||
|
// Assert that all Member Variables are inited to Zero.
|
||
|
ASSERT(!_pwb);
|
||
|
ASSERT(!_punkSite);
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: Address Band destructor
|
||
|
\****************************************************/
|
||
|
CBandProxy::~CBandProxy()
|
||
|
{
|
||
|
ATOMICRELEASE(_pwb);
|
||
|
ATOMICRELEASE(_punkSite);
|
||
|
|
||
|
TraceMsg(TF_SHDLIFE, "dtor CBandProxy %x", this);
|
||
|
DllRelease();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//===========================
|
||
|
// *** IUnknown Interface ***
|
||
|
/****************************************************\
|
||
|
FUNCTION: AddRef
|
||
|
\****************************************************/
|
||
|
ULONG CBandProxy::AddRef()
|
||
|
{
|
||
|
_cRef++;
|
||
|
return _cRef;
|
||
|
}
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: Release
|
||
|
\****************************************************/
|
||
|
ULONG CBandProxy::Release()
|
||
|
{
|
||
|
ASSERT(_cRef > 0);
|
||
|
_cRef--;
|
||
|
|
||
|
if (_cRef > 0)
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: QueryInterface
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::QueryInterface(REFIID riid, void **ppvObj)
|
||
|
{
|
||
|
if (IsEqualIID(riid, IID_IUnknown) ||
|
||
|
IsEqualIID(riid, IID_IBandProxy))
|
||
|
{
|
||
|
*ppvObj = SAFECAST(this, IBandProxy*);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppvObj = NULL;
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
//================================
|
||
|
// ** IBandProxy Interface ***
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: SetSite
|
||
|
|
||
|
DESCRIPTION:
|
||
|
This function will be called to have this
|
||
|
Toolband try to obtain enough information about it's
|
||
|
parent Toolbar to create the Band window and maybe
|
||
|
connect to a Browser Window.
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::SetSite(IUnknown * punk)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// On UNIX, we always have a browser.
|
||
|
// Note, that there's no memory leak happened,
|
||
|
// because we get the browser only once
|
||
|
// and release it once too (in destructor).
|
||
|
#ifndef DISABLE_ACTIVEDESKTOP_FOR_UNIX
|
||
|
_fHaveBrowser = FALSE;
|
||
|
ATOMICRELEASE(_pwb);
|
||
|
#endif
|
||
|
|
||
|
IUnknown_Set(&_punkSite, punk);
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: CreateNewWindow
|
||
|
|
||
|
DESCRIPTION:
|
||
|
If this function succeeds, the caller must
|
||
|
use and release the returned interface quickly. The
|
||
|
caller cannot hold on to the Interface because
|
||
|
the user may close the window and make releasing
|
||
|
it impossible.
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::CreateNewWindow(IUnknown** ppunk)
|
||
|
{
|
||
|
return CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_INPROC_SERVER,
|
||
|
IID_PPV_ARG(IUnknown, ppunk));
|
||
|
// ZekeL: Add code to prep new Browser here.
|
||
|
}
|
||
|
|
||
|
|
||
|
IWebBrowser2* CBandProxy::_GetBrowser()
|
||
|
{
|
||
|
if (!_fHaveBrowser)
|
||
|
{
|
||
|
IUnknown * punkHack;
|
||
|
|
||
|
_fHaveBrowser = TRUE;
|
||
|
|
||
|
// HACK: Bands docked on the side of the screen besides the Taskbar will be
|
||
|
// able to get a IWebBrowser2 interface pointer. But we expect this
|
||
|
// to be pointing to a valid browser that we are attached to. Navigating
|
||
|
// this interface appears to create new windows, which is not what we
|
||
|
// want, because we will try to recycle windows and do special behavior
|
||
|
// if the shift key is down. This QS will detect this case and prevent
|
||
|
// it from confusing us.
|
||
|
if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SShellDesktop, IID_PPV_ARG(IUnknown, &punkHack))))
|
||
|
punkHack->Release();
|
||
|
else
|
||
|
IUnknown_QueryService(_punkSite, SID_SWebBrowserApp, IID_PPV_ARG(IWebBrowser2, &_pwb));
|
||
|
}
|
||
|
|
||
|
return _pwb;
|
||
|
}
|
||
|
|
||
|
|
||
|
// this does the default UI work of opening a new window if the shift
|
||
|
// key is down
|
||
|
// or creating a browser if one isn't available already
|
||
|
IWebBrowser2* CBandProxy::_GetBrowserWindow()
|
||
|
{
|
||
|
IUnknown* punk = NULL;
|
||
|
IWebBrowser2* pwb = NULL;
|
||
|
|
||
|
GetBrowserWindow(&punk);
|
||
|
|
||
|
if (punk)
|
||
|
{
|
||
|
punk->QueryInterface(IID_PPV_ARG(IWebBrowser2, &pwb));
|
||
|
|
||
|
// Always make browser visible.
|
||
|
MakeBrowserVisible(punk);
|
||
|
punk->Release();
|
||
|
}
|
||
|
|
||
|
return pwb;
|
||
|
}
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: GetBrowserWindow
|
||
|
|
||
|
DESCRIPTION:
|
||
|
this is to just *GET* the browser. It does not
|
||
|
do any auto-creating work.
|
||
|
If this function succseeds, the caller must
|
||
|
use and release the returned interface quickly. The
|
||
|
caller cannot hold on to the Interface because
|
||
|
the user may close the window and make releasing
|
||
|
it impossible.
|
||
|
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::GetBrowserWindow(IUnknown** ppunk)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
*ppunk = _GetBrowser();
|
||
|
if (*ppunk)
|
||
|
{
|
||
|
(*ppunk)->AddRef();
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: IsConnected
|
||
|
|
||
|
DESCRIPTION:
|
||
|
Indicate if we have a direct connection to the
|
||
|
browser window.
|
||
|
S_FALSE == no
|
||
|
S_OK == yes.
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::IsConnected()
|
||
|
{
|
||
|
return _GetBrowser() ? S_OK : S_FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: MakeBrowserVisible
|
||
|
|
||
|
DESCRIPTION:
|
||
|
Make browser visible.
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::MakeBrowserVisible(IUnknown* punk)
|
||
|
{
|
||
|
IWebBrowserApp * pdie;
|
||
|
|
||
|
if (SUCCEEDED(punk->QueryInterface(IID_PPV_ARG(IWebBrowserApp, &pdie))))
|
||
|
{
|
||
|
pdie->put_Visible(TRUE);
|
||
|
|
||
|
HWND hwnd;
|
||
|
if (SUCCEEDED(SHGetTopBrowserWindow(punk, &hwnd)))
|
||
|
{
|
||
|
if (IsIconic(hwnd))
|
||
|
ShowWindow(hwnd, SW_RESTORE);
|
||
|
}
|
||
|
|
||
|
pdie->Release();
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: NavigateToPIDL
|
||
|
|
||
|
DESCRIPTION:
|
||
|
The caller needs to free the PIDL parameter and
|
||
|
it can be done at any time. (No need to worry
|
||
|
about async navigation)
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::NavigateToPIDL(LPCITEMIDLIST pidl)
|
||
|
{
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
IWebBrowser2* pwb = _GetBrowserWindow();
|
||
|
if (pwb)
|
||
|
{
|
||
|
VARIANT varThePidl;
|
||
|
|
||
|
hr = InitVariantFromIDList(&varThePidl, pidl);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = pwb->Navigate2(&varThePidl, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY);
|
||
|
VariantClear(&varThePidl);
|
||
|
}
|
||
|
pwb->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPCITEMIDLIST pidlTemp;
|
||
|
IShellFolder* psf;
|
||
|
|
||
|
if (SUCCEEDED(IEBindToParentFolder(pidl, &psf, &pidlTemp)))
|
||
|
{
|
||
|
IContextMenu* pcm;
|
||
|
|
||
|
hr = psf->GetUIObjectOf(NULL, 1, &pidlTemp, IID_PPV_ARG_NULL(IContextMenu, &pcm));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = IContextMenu_Invoke(pcm, NULL, NULL, 0);
|
||
|
pcm->Release();
|
||
|
}
|
||
|
psf->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: NavigateToUrlOLE
|
||
|
|
||
|
DESCRIPTION:
|
||
|
Navigate to the Specified URL.
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::_NavigateToUrlOLE(BSTR bstrURL, VARIANT * pvFlags)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
ASSERT(bstrURL); // must have valid URL to browse to
|
||
|
|
||
|
IWebBrowser2* pwb = _GetBrowserWindow();
|
||
|
// This will assert if someone was hanging around in the debugger
|
||
|
// too long. While will cause the call to timing out.
|
||
|
if (pwb)
|
||
|
{
|
||
|
VARIANT varURL;
|
||
|
varURL.vt = VT_BSTR;
|
||
|
varURL.bstrVal = bstrURL;
|
||
|
|
||
|
hr = pwb->Navigate2(&varURL, pvFlags, PVAREMPTY, PVAREMPTY, PVAREMPTY);
|
||
|
// VariantClear() not called because caller will free the allocated string.
|
||
|
pwb->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SHELLEXECUTEINFO sei;
|
||
|
|
||
|
FillExecInfo(sei, NULL, NULL, bstrURL, NULL, NULL, SW_SHOWNORMAL);
|
||
|
// this navigate code path gets hit only from the edit address bar -- since the user
|
||
|
// would have to interactively put in a weird failure case path to get here, its not an issue.
|
||
|
if (ShellExecuteEx(&sei))
|
||
|
hr = S_OK;
|
||
|
else
|
||
|
hr = E_FAIL;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************\
|
||
|
FUNCTION: NavigateToURLW
|
||
|
|
||
|
DESCRIPTION:
|
||
|
Navigate to the Specified URL.
|
||
|
\****************************************************/
|
||
|
HRESULT CBandProxy::NavigateToURL(LPCWSTR lpwzURL, VARIANT * Flags)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
LBSTR::CString strPath( lpwzURL );
|
||
|
|
||
|
hr = _NavigateToUrlOLE( strPath, Flags );
|
||
|
|
||
|
return hr;
|
||
|
}
|