www.pudn.com > STBIHOST.rar > mainwnd.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name: mainwnd.cpp
Abstract: Implements the main window, the container for the webbrowser
Functions:
Notes: Most of the code resides here. The container and its interaction with the webbrowser control,
commandbar, statusbar etc.
--*/
#include
#include "stdafx.h"
#include "stbihost.h"
#include "mainwnd.h"
#include "mshtmcid.h"
#include "resource.h"
#include "external.h"
#include "rctlkeys.h"
#define INITGUID
#include "initguid.h"
#include
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY_NON_CREATEABLE(CHostExternal)
END_OBJECT_MAP()
#define WINCLS_UUID TEXT("55efda90-063f-419c-9ce4-18c3d26c2ae2") // window class
#define REG_ROOTKEY TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\Main")
#define REG_WMPVALUE TEXT("Windows Media Page")
#define SAFEAREA_MARGIN 0.82 // SHDOCVW will display within this area of the container window
DEFINE_GUID(CLSID_WebBrowser, 0x8856F961L, 0x340A, 0x11D0, 0xA9, 0x6B, 0x00, 0xC0, 0x4F, 0xD7, 0x05, 0xA2);
DEFINE_GUID(IID_IWebBrowser, 0xEAB22AC1L, 0x30C1, 0x11CF, 0xA7, 0xEB, 0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B);
DEFINE_GUID(IID_IWebBrowser2, 0xD30C1661L, 0xCDAF, 0x11D0, 0x8A, 0x3E, 0x00, 0xC0, 0x4F, 0xC9, 0xE2, 0x6E);
DEFINE_GUID(DIID_DWebBrowserEvents, 0xEAB22AC2L, 0x30C1, 0x11CF, 0xA7, 0xEB, 0x00, 0x00, 0xC0, 0x5B, 0xAE, 0x0B);
DEFINE_GUID(DIID_DWebBrowserEvents2, 0x34A715A0L, 0x6587, 0x11D0, 0x92, 0x4A, 0x00, 0x20, 0xAF, 0xC7, 0xAC, 0x4D);
DEFINE_GUID(IID_IWebBrowserApp, 0x0002DF05L, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
const GUID SID_SDocHost = { 0xc6504990, 0xd43e, 0x11cf, { 0x89, 0x3b, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x1a}};
LONG glThreadCount = 0;
HWND ghWndAddressEdit= NULL;
HANDLE ghExitEvent = NULL;
HINSTANCE g_hInstance = NULL;
DWORD g_dwMainWindowStackSize = 0x20000;
void GetProxyOption();
static HRESULT FindString();
HRESULT HandleNewWindow2(LPTSTR lpszUrl, DISPPARAMS FAR* pdparams);
BOOL RegisterMainWnd();
DWORD WINAPI NewWindow(LPVOID pParam)
{
CMainWnd *pWnd = (CMainWnd *)pParam;
MSG msg;
BOOL fRet;
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
fRet = pWnd->Create();
SetEvent(pWnd->hEvent);
if (!fRet)
{
pWnd->_pBrowser = NULL;
return 0;
}
while (GetMessage( &msg, NULL, 0, 0 ) )
{
if(msg.message == WM_QUIT)
break;
if (!pWnd->PreTranslateMessage(&msg) && !(msg.message == WM_CHAR && msg.wParam == VK_TAB))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
pWnd->Release();
CoUninitialize();
InterlockedDecrement(&glThreadCount);
SetEvent(ghExitEvent);
return msg.wParam;
}
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpCmdLine, int nCmdShow)
{
DEBUGMSG (1, (TEXT("\r\n\r\n### New instance of StbIHost ###\r\n")
TEXT("### Command line is: %s"), lpCmdLine));
// allow only one instance
HWND hWnd = FindWindow(WINCLS_UUID, NULL);
if (hWnd)
{
SetForegroundWindow((HWND)(((DWORD)hWnd) | 0x01));
if (*lpCmdLine)
{
COPYDATASTRUCT cds = { 1,
sizeof(TCHAR)*(_tcslen(lpCmdLine) + 1),
lpCmdLine };
SendMessage(hWnd, WM_COPYDATA, NULL, (LPARAM)&cds);
}
return 0;
}
INITCOMMONCONTROLSEX iccsex;
HKEY hKey;
DWORD dwSize = sizeof(DWORD);
MSG msg;
// HKCU is where IE\Main settings are
if(ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REG_ROOTKEY, 0, 0, &hKey))
{
RegQueryValueEx(hKey, TEXT("StackRes"), NULL, NULL, (LPBYTE)&g_dwMainWindowStackSize, &dwSize);
RegCloseKey(hKey);
}
// provide a default stack size if the one given is too small or too large.
if(g_dwMainWindowStackSize < 0x10000 || g_dwMainWindowStackSize > 0x80000)
{
// default to 128k
g_dwMainWindowStackSize = 0x20000;
}
RETAILMSG(1,(L"STBIHOST Using stack size: %x", g_dwMainWindowStackSize));
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (FAILED(hr))
{
return FALSE;
}
hr = _Module.Init(ObjectMap, hInst, &LIBID_STBIHOSTLib);
ASSERT(SUCCEEDED(hr));
hr = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
ASSERT(SUCCEEDED(hr));
hr = _Module.RegisterTypeLib();
ASSERT(SUCCEEDED(hr));
if (!RegisterMainWnd())
return FALSE;
ghExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!ghExitEvent)
{
return FALSE;
}
iccsex.dwSize = sizeof(INITCOMMONCONTROLSEX);
iccsex.dwICC = ICC_COOL_CLASSES;
InitCommonControlsEx(&iccsex);
g_hInstance = hInst;
// Create a message queue on this thread
PeekMessage(&msg, NULL, 0,0,PM_NOREMOVE);
if(HandleNewWindow2(lpCmdLine, NULL))
{
goto Cleanup;
}
while (glThreadCount > 0)
{
WaitForSingleObject(ghExitEvent, INFINITE);
}
Cleanup:
_Module.UnRegisterTypeLib();
_Module.RevokeClassObjects();
_Module.Term();
CoUninitialize();
RETAILMSG(1, (L"STBIHOST exited. Cmdline was: %s\r\n",lpCmdLine ? lpCmdLine : L""));
return TRUE;
}
CMainWnd::CMainWnd()
{
_ulRefs = 1;
_hWnd = NULL;
_pBrowser = NULL;
_pObject = NULL;
_pCP = NULL;
_lpszUrl = NULL;
_fEmpty = FALSE;
_szTitle[0] = 0;
_fSafeArea = FALSE;
_lSafeWidth = 0;
_lSafeHeight = 0;
_ptSafe.x = 0;
_ptSafe.y = 0;
_wZoom = 2; // default zoom
_wDLCCounter = 0; // counter for Download Completes
_pUnkExternal = NULL;
_hAccelTblNew = NULL;
_cNewAccels = 0;
_rgNewAccels = NULL;
_fUseNewAccels = NULL;
}
CMainWnd::~CMainWnd()
{
RETAILMSG(1,(L"STBIHOST Exiting ~CMainWnd\r\n"));
if (_pBrowser)
_pBrowser->Release();
if (_pUnkExternal)
_pUnkExternal->Release();
if (_rgNewAccels)
delete [] _rgNewAccels;
if (_hAccelTblNew)
DestroyAcceleratorTable(_hAccelTblNew);
}
BOOL RegisterMainWnd()
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)CMainWnd::MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInstance;
wc.hIcon = NULL; // LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_IE));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = CreateSolidBrush(RGB(50,50,50));
wc.lpszMenuName = NULL;
wc.lpszClassName = WINCLS_UUID;
if (!(RegisterClass(&wc)))
return FALSE;
return TRUE;
}
BOOL CMainWnd::Create()
{
RECT rcArea;
DWORD dwStyle = WS_VISIBLE;
DWORD dwExStyle = 0;
HMENU hMenu = NULL;
SystemParametersInfo(SPI_GETWORKAREA, 0, &rcArea, 0);
_hWnd = ::CreateWindowEx(dwExStyle,
WINCLS_UUID,
(WCHAR *)LoadString(g_hInstance, IDS_STBIHOST, NULL, 0),
dwStyle,
rcArea.left,
rcArea.top,
rcArea.right - rcArea.left,
rcArea.bottom - rcArea.top,
NULL, hMenu, g_hInstance, 0);
if (!_hWnd)
return FALSE;
SetWindowLong(_hWnd, GWL_USERDATA, (DWORD)this);
GetWindowRect(_hWnd, &_rcWnd);
// create a "safe area" to prevent the browser
// control (and the progress bar) from displaying
// graphics that bleed off the edges of the TV screen
_lSafeWidth = (LONG)((_rcWnd.right - _rcWnd.left) * SAFEAREA_MARGIN);
_lSafeHeight = (LONG)((_rcWnd.bottom - _rcWnd.top) * SAFEAREA_MARGIN);
_ptSafe.x = (LONG)((_rcWnd.right - _rcWnd.left - _lSafeWidth)/2);
_ptSafe.y = (LONG)((_rcWnd.bottom - _rcWnd.top - _lSafeHeight)/2);
// create a progress bar
_rcProgress.left = _ptSafe.x + 5;
_rcProgress.top = _ptSafe.y + 5;
_rcProgress.right = _rcProgress.left + _lSafeWidth/3;
_rcProgress.bottom = _rcProgress.top + 15;
_hwndProgress = CreateWindowEx(WS_EX_NOACTIVATE, PROGRESS_CLASS,
_T(""), WS_CHILD|PBS_SMOOTH|WS_BORDER,
_rcProgress.left, _rcProgress.top,
_rcProgress.right-_rcProgress.left,
_rcProgress.bottom-_rcProgress.top,
_hWnd, NULL, g_hInstance, NULL);
if (_hwndProgress)
SendMessage(_hwndProgress, PBM_SETRANGE32, 0, 1000);
if (!(_hWndBrowser = CreateBrowser()))
return FALSE;
// LONG lStyle = GetWindowLong(_hWndBrowser, GWL_STYLE);
// SetWindowLong(_hWndBrowser, GWL_STYLE, lStyle|WS_BORDER);
// use the safe area to resize the web control
EnableSafeArea(TRUE);
SetFocus(_hWnd);
_hAccelTblDef = LoadAccelerators(g_hInstance,
MAKEINTRESOURCE(IDR_ACCELERATOR));
return TRUE;
}
void GetProxyOption()
{
INTERNET_PER_CONN_OPTION_LIST iOptionList;
INTERNET_PER_CONN_OPTION iOptions[3];
ULONG uSize = sizeof(iOptionList);
iOptionList.dwSize = uSize;
iOptionList.pszConnection = NULL;
iOptionList.dwOptionCount = 3;
iOptionList.pOptions = iOptions;
// set proxy type direct or proxy server
iOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
iOptions[1].dwOption = INTERNET_PER_CONN_PROXY_SERVER;
iOptions[2].dwOption = INTERNET_PER_CONN_PROXY_BYPASS;
if(InternetQueryOption(NULL,INTERNET_OPTION_PER_CONNECTION_OPTION ,(LPVOID)(&iOptionList),&uSize))
{
GlobalFree(iOptionList.pOptions[1].Value.pszValue);
GlobalFree(iOptionList.pOptions[2].Value.pszValue);
}
}
HWND CMainWnd::CreateBrowser()
{
HRESULT hr;
IUnknown *pUnk = NULL;
IOleObject *pObject = NULL;
if (!_pBrowser)
{
GetProxyOption();
hr = CoCreateInstance(CLSID_WebBrowser, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
IID_IUnknown, (LPVOID *)(&pUnk));
if (hr)
return FALSE;
hr = pUnk->QueryInterface(IID_IOleObject, (LPVOID *)(&pObject));
if (hr)
goto Cleanup;
DWORD dwFlags;
hr = pObject->GetMiscStatus(DVASPECT_CONTENT, &dwFlags);
if (hr)
goto Cleanup;
if (dwFlags & OLEMISC_SETCLIENTSITEFIRST)
{
IOleClientSite *pClientSite;
hr = QueryInterface(IID_IOleClientSite, (LPVOID *)(&pClientSite));
if (hr)
goto Cleanup;
hr = pObject->SetClientSite(pClientSite);
pClientSite->Release();
if (hr)
goto Cleanup;
}
hr = Activate(pObject);
if (hr)
goto Cleanup;
hr = _pObject->QueryInterface(IID_IWebBrowser2, (void **)&_pBrowser);
if (hr)
goto Cleanup;
// See if there might be a url in lpszUrl
hr = pUnk->QueryInterface(IID_IOleInPlaceActiveObject, (LPVOID *)(&_pIPActiveObj));
if (S_OK!=hr)
_pIPActiveObj = NULL;
hr = S_FALSE;
if (_fEmpty)
{
if (_lpszUrl)
{
LPTSTR lpszUrlAlpha = _lpszUrl;
while (hr == S_FALSE && *lpszUrlAlpha != _T('\0'))
{
if (_istalpha(*lpszUrlAlpha))
hr = S_OK;
lpszUrlAlpha++;
}
}
if (hr == S_OK)
_pBrowser->Navigate(_lpszUrl, NULL, NULL, NULL, NULL);
else
_pBrowser->GoHome();
}
hr = InitEvents();
}
Cleanup:
if (pUnk)
pUnk->Release();
if (pObject)
pObject->Release();
IOleWindow *pWnd = NULL;
HWND hwndBrowser = NULL;
if (_pBrowser)
{
hr = _pBrowser->QueryInterface(IID_IOleWindow, (LPVOID *)(&pWnd));
if (hr)
return NULL;
}
if (pWnd)
{
hr = pWnd->GetWindow(&hwndBrowser);
pWnd->Release();
}
return hwndBrowser;
}
HRESULT CMainWnd::Activate(IOleObject *pObject)
{
_pObject = pObject;
_pObject->AddRef();
RECT rc;
::GetClientRect(_hWnd, &rc);
HRESULT hr;
hr = _pObject->DoVerb( OLEIVERB_UIACTIVATE, NULL, this, 0, _hWnd, &rc);
if (hr)
goto Cleanup;
Cleanup:
return hr;
}
HRESULT CMainWnd::InitEvents()
{
HRESULT hr;
IConnectionPointContainer *pCPCont = NULL;
DWebBrowserEvents *pEvents = NULL;
if (!_pBrowser)
return S_FALSE;
hr = _pBrowser->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPCont);
if (hr)
return S_FALSE;
hr = pCPCont->FindConnectionPoint(DIID_DWebBrowserEvents2, &_pCP);
if (hr)
{
_pCP = NULL;
goto Cleanup;
}
hr = QueryInterface(DIID_DWebBrowserEvents2, (LPVOID *)(&pEvents));
if (hr)
goto Cleanup;
hr = _pCP->Advise(pEvents, &(_dwEventCookie));
if (hr)
goto Cleanup;
Cleanup:
if (pCPCont)
pCPCont->Release();
if (pEvents)
pEvents->Release();
return hr;
}
HRESULT HandleNewWindow2(LPTSTR lpszUrl, DISPPARAMS FAR* pdparams)
{
HANDLE hThread;
CMainWnd *pNewWnd;
IDispatch *pDispatch;
HRESULT hr = S_OK;
pNewWnd = new CMainWnd;
if (!pNewWnd)
{
return E_OUTOFMEMORY;
}
pNewWnd->_lpszUrl = lpszUrl;
if(!pdparams)
pNewWnd->_fEmpty = TRUE;
pNewWnd->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!pNewWnd->hEvent)
{
}
InterlockedIncrement(&glThreadCount);
hThread = CreateThread(NULL, g_dwMainWindowStackSize, NewWindow, (LPVOID)pNewWnd, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
if (!hThread)
{
delete pNewWnd;
InterlockedDecrement(&glThreadCount);
return E_OUTOFMEMORY;
}
WaitForSingleObject(pNewWnd->hEvent, INFINITE);
CloseHandle(hThread);
if(pdparams)
{
if (pNewWnd->_pBrowser)
{
hr = pNewWnd->_pBrowser->QueryInterface(IID_IDispatch, (LPVOID *)(&pDispatch));
}
else
{
hr = E_FAIL;
pDispatch = NULL;
}
*(pdparams->rgvarg[0].pboolVal) = 0;
*(pdparams->rgvarg[1].ppdispVal) = pDispatch;
}
return hr;
}
STDMETHODIMP CMainWnd::GetExternal(IDispatch **ppDispatch)
{
HRESULT hr = S_OK;
if (!ppDispatch) return E_POINTER;
if (*ppDispatch)
*ppDispatch = NULL;
if (!_pUnkExternal)
{
_pUnkExternal = new CComObject();
if (!_pUnkExternal) return E_OUTOFMEMORY;
_pUnkExternal->AddRef();
(reinterpret_cast(_pUnkExternal))->SetInst(this);
}
return _pUnkExternal->QueryInterface(IID_IDispatch, (PVOID*)(ppDispatch));
}
STDMETHODIMP CMainWnd::GetHostInfo(DOCHOSTUIINFO *pInfo)
{
pInfo->cbSize = sizeof(DOCHOSTUIINFO);
//pInfo->dwFlags = DOCHOSTUIFLAG_NO3DBORDER|DOCHOSTUIFLAG_FLAT_SCROLLBAR;
//pInfo->dwFlags |= DOCHOSTUIFLAG_SCROLL_NO;
return S_OK;
}
STDMETHODIMP CMainWnd::Invoke (
DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS FAR* pdparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo,
UINT FAR* puArgErr
)
{
switch (dispidMember)
{
case DISPID_AMBIENT_DLCONTROL:
if(pvarResult)
{
V_VT(pvarResult) = VT_I4;
// always set these three unless they should be disabled
pvarResult->lVal = DLCTL_DLIMAGES|DLCTL_VIDEOS|DLCTL_BGSOUNDS;
// put the browser in download only mode
// pvarResult->lVal |= DLCTL_DOWNLOADONLY;
}
break;
case DISPID_STATUSTEXTCHANGE:
{
}
break;
case DISPID_SETSECURELOCKICON:
{
}
break;
case DISPID_PROGRESSCHANGE:
{
LONG lProgMax = pdparams->rgvarg[0].lVal;
LONG lProg = pdparams->rgvarg[1].lVal;
UINT nPos = (lProg == -1) ? 999 : ((lProg-1)%1000);
SendMessage(_hwndProgress, PBM_SETPOS, nPos, 0);
}
break;
// notification for file download
case DISPID_FILEDOWNLOAD:
break;
case DISPID_NAVIGATECOMPLETE2:
break;
case DISPID_COMMANDSTATECHANGE:
break;
case DISPID_TITLECHANGE:
if (pdparams && pdparams->rgvarg[0].vt == VT_BSTR)
{
TCHAR szTitle[85];
int len = wcslen(pdparams->rgvarg[0].bstrVal);
_tcsncpy(_szTitle, pdparams->rgvarg[0].bstrVal, MAX_URL-1);
_tcsncpy(szTitle, pdparams->rgvarg[0].bstrVal, 80);
if(len > 80)
_tcscat(szTitle, L"...");
SetWindowText(_hWnd, szTitle);
}
break;
case DISPID_ONQUIT:
PostMessage(_hWnd, WM_CLOSE, 0, 0L);
break;
case DISPID_DOWNLOADBEGIN:
_wDLCCounter++;
SetWindowPos(_hwndProgress, HWND_TOP, 0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_SHOWWINDOW);
break;
case DISPID_DOWNLOADCOMPLETE:
case DISPID_DOCUMENTCOMPLETE:
_wDLCCounter--;
if(_wDLCCounter <= 0)
{
SetWindowPos(_hwndProgress,NULL, 0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_HIDEWINDOW);
ChangeFontSize(TRUE);
_wDLCCounter = 0;
}
break;
case DISPID_NEWWINDOW2:
//pdparams->rgvarg[1].boolVal = VARIANT_TRUE;
//break;
return HandleNewWindow2(NULL, pdparams);
break;
case DISPID_PROPERTYCHANGE:
case DISPID_BEFORENAVIGATE2:
break;
default:
return DISP_E_MEMBERNOTFOUND;
}
return S_OK;
}
STDMETHODIMP CMainWnd::moveTo( LONG x, LONG y)
{
SetWindowPos(_hWnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
return S_OK;
}
STDMETHODIMP CMainWnd::moveBy( LONG x, LONG y)
{
RECT rcWindow;
GetWindowRect(_hWnd, &rcWindow);
SetWindowPos(_hWnd, NULL, rcWindow.left + x, rcWindow.top + y, 0, 0,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
return S_OK;
}
STDMETHODIMP CMainWnd::resizeTo( LONG x, LONG y)
{
// We do not want the size to be less then 100 for top level windows in browser
if (x < 100)
x = 100;
if (y < 100)
y = 100;
SetWindowPos(_hWnd, NULL, 0, 0, x, y, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
return S_OK;
}
STDMETHODIMP CMainWnd::resizeBy( LONG x, LONG y)
{
RECT rcWindow;
long w, h;
GetWindowRect(_hWnd, &rcWindow);
w = rcWindow.right - rcWindow.left + x;
h = rcWindow.bottom - rcWindow.top + y;
if (w < 100)
w = 100;
if (h < 100)
h = 100;
SetWindowPos(_hWnd, NULL, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
return S_OK;
}
EXTERN_C const GUID CGID_MSHTML;
extern "C" BOOL APIENTRY OpenURLDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam);
LRESULT CMainWnd::HandleCommand(WPARAM wParam, LPARAM lParam)
{
UINT nID = LOWORD(wParam);
switch (nID)
{
case ID_INTERNET_OPTIONS:
{
SHELLEXECUTEINFO sei;
sei.cbSize = sizeof(sei);
sei.fMask = SEE_MASK_FLAG_NO_UI;
sei.hwnd = _hWnd;
sei.lpVerb = NULL;
sei.lpFile = L"ctlpnl";
sei.lpParameters = L"inetcpl.cpl";
sei.lpDirectory = NULL;
sei.nShow = SW_SHOWNORMAL;
ShellExecuteEx(&sei);
}
break;
case ID_FIND:
FindString();
break;
case ID_GO_BACK:
_pBrowser->GoBack();
return 0;
case ID_GO_FORWARD:
_pBrowser->GoForward();
return 0;
case ID_GO_HOME:
_pBrowser->GoHome();
return 0;
case ID_GO_SEARCH:
_pBrowser->GoSearch();
return 0;
case ID_VIEW_REFRESH:
_pBrowser->Refresh();
return 0;
case ID_VIEW_STOP:
_pBrowser->Stop();
return 0;
case ID_SCROLL_PAGEUP:
case ID_SCROLL_PAGEDOWN:
{ // TODO: this isn't working...
ASSERT(_pBrowser);
LPDISPATCH pDisp = NULL;
LPOLECOMMANDTARGET pCmdTarg = NULL;
VARIANTARG var;
HRESULT hr;
UINT nCmdId = (ID_SCROLL_PAGEUP == nID
? IDM_SCROLL_PAGEUP
: IDM_SCROLL_PAGEDOWN);
hr = _pBrowser->get_Document(&pDisp);
if (FAILED(hr) || !pDisp) break;
hr = pDisp->QueryInterface(IID_IOleCommandTarget,
(LPVOID*)&pCmdTarg);
if (FAILED(hr) || !pCmdTarg)
{
pDisp->Release();
break;
}
var.vt = VT_I4;
var.lVal = 0;
hr = pCmdTarg->Exec(&CGID_MSHTML, nCmdId, 0, 0, 0);
if (pCmdTarg) pCmdTarg->Release();
if (pDisp) pDisp->Release();
}
break;
case ID_ZOOMUP:
_wZoom++;
if(_wZoom > 4)
_wZoom = 4;
ChangeFontSize(FALSE);
return 0;
case ID_ZOOMDOWN:
_wZoom--;
if(_wZoom < 0)
_wZoom = 0;
ChangeFontSize(FALSE);
return 0;
case ID_CLOSE:
_pBrowser->ExecWB(OLECMDID_CLOSE, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
return 0;
case ID_FOCUS_URL:
case ID_OPEN:
{
WCHAR *szURL = new TCHAR[MAX_URL];
if (szURL)
{
int nRet = 0;
BSTR bstrUrl = NULL;
_pBrowser->get_LocationURL(&bstrUrl);
StringCchCopy(szURL, MAX_URL, (LPCTSTR)bstrUrl);
SysFreeString(bstrUrl);
nRet = DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_OPEN_DIALOG), _hWnd, OpenURLDlgProc, (long)szURL);
if(nRet == 1)
{
_pBrowser->Navigate(szURL, NULL, NULL, NULL, NULL);
}
else if(nRet == 2)
{
HandleNewWindow2(szURL, NULL);
}
delete[] szURL;
}
}
return 0;
}
return 0;
}
EXTERN_C const GUID CGID_ShellDocView;
LRESULT CALLBACK CMainWnd::MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CMainWnd *pMainWnd = (CMainWnd*)GetWindowLong(hwnd, GWL_USERDATA);
if (pMainWnd)
{
switch (message)
{
case WM_CLOSE:
case WM_DESTROY:
if(pMainWnd)
pMainWnd->Close();
SetWindowLong(hwnd, GWL_USERDATA, (DWORD)0);
::PostQuitMessage(0);
break;
case WM_SETFOCUS:
if (pMainWnd->_pIPActiveObj)
{
pMainWnd->_pIPActiveObj->OnFrameWindowActivate(LOWORD(wParam) != WA_INACTIVE);
}
return 0;
case WM_SIZE:
{
RECT rcWnd;
GetClientRect(hwnd, &rcWnd);
SetWindowPos(pMainWnd->_hWndBrowser,
NULL, 0, 0,
rcWnd.right-rcWnd.left,
rcWnd.bottom - rcWnd.top,
SWP_NOZORDER);
}
// FALL THROUGH
case WM_MOVE:
break;
case WM_COMMAND:
return pMainWnd->HandleCommand(wParam, lParam);
case WM_NOTIFY:
break;
case WM_INITMENUPOPUP:
break;
case WM_SETTINGCHANGE:
if(wParam == SPI_SETWORKAREA)
{
ASSERT(FALSE);
}
break;
// TODO: We currently only use WM_COPYDATA for the WMP page.
// TODO: If we load other types of pages as well, we'll need to develop
// TODO: a protocol to determine who sent the WM_COPYDATA message.
// TODO: e.g. - "type=stbihostwmp&url="
case WM_COPYDATA:
// navigate to the WMP webpage, passing it the copied link
if( lParam )
{
HKEY hKey;
DWORD cbData, dwType, cbDummy;
LONG lRet;
LPTSTR szNavURL;
lRet = RegOpenKeyEx(HKEY_CURRENT_USER, REG_ROOTKEY, 0, 0, &hKey);
ASSERT(ERROR_SUCCESS == lRet);
if (ERROR_SUCCESS != lRet)
{
DEBUGMSG(1, (TEXT("Error (%u) getting registry key: ")
REG_ROOTKEY TEXT("\r\n"), GetLastError()));
break;
}
// just get the size first
lRet = RegQueryValueEx(hKey, REG_WMPVALUE, NULL,
&dwType, NULL, &cbData);
ASSERT(ERROR_SUCCESS == lRet);
if (ERROR_SUCCESS != lRet)
{
DEBUGMSG(1, (TEXT("Error (%u) getting registry value: ")
REG_ROOTKEY REG_WMPVALUE, GetLastError()));
RegCloseKey(hKey);
break;
}
ASSERT(REG_SZ == dwType);
cbData += _tcslen(TEXT("#")) * sizeof(TCHAR);
PCOPYDATASTRUCT lpCDS = (PCOPYDATASTRUCT)lParam;
ASSERT(lpCDS->cbData ==
(_tcslen((LPTSTR)lpCDS->lpData) + 1) * sizeof(TCHAR));
cbData += lpCDS->cbData + sizeof(TCHAR); // extra TCHAR for null term
// now that we know the size, create the URL
szNavURL = new TCHAR[cbData/sizeof(TCHAR)];
ASSERT(szNavURL);
if (!szNavURL)
{
DEBUGMSG(1, (TEXT("Error creating Windows Media ")
TEXT("Navigation URL string!\r\n")));
break;
}
cbDummy = cbData;
lRet = RegQueryValueEx(hKey, REG_WMPVALUE, NULL, NULL,
(LPBYTE)szNavURL, &cbDummy);
ASSERT(ERROR_SUCCESS == lRet);
RegCloseKey(hKey);
if (ERROR_SUCCESS != lRet)
{
DEBUGMSG(1, (TEXT("Error (%u) getting registry value: ")
REG_ROOTKEY REG_WMPVALUE, GetLastError()));
break;
}
_tcscat(szNavURL, TEXT("#"));
_tcscat(szNavURL, (LPTSTR)lpCDS->lpData);
szNavURL[cbData/sizeof(TCHAR) - 1] = 0;
HRESULT hr = pMainWnd->_pBrowser->Navigate(szNavURL,
NULL, NULL, NULL, NULL);
ASSERT(S_OK == hr);
if (FAILED(hr))
{
DEBUGMSG(1, (TEXT("IWebBrowser2::Navigate(\"%s\") failed!\r\n"),
szNavURL));
}
return 1;
}
break;
default:
break;
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
BOOL CMainWnd::PreTranslateMessage(LPMSG pMsg)
{
// main frame gets first shot
if (_fUseNewAccels)
{
if (::TranslateAccelerator(_hWnd, _hAccelTblNew, pMsg))
return TRUE;
}
else
{
if (::TranslateAccelerator(_hWnd, _hAccelTblDef, pMsg))
return TRUE;
}
// then to mshtml
if (_pIPActiveObj && pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
{
HRESULT hr = _pIPActiveObj->TranslateAccelerator(pMsg);
return (hr != S_FALSE);
}
return FALSE;
}
VOID CMainWnd::ChangeFontSize(BOOL fInit)
{
VARIANT vaSize;
vaSize.vt = VT_I4;
if (fInit) {
// Setting initial value
vaSize.vt = 0;
HRESULT hr = _pBrowser->ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER,
NULL, &vaSize);
_wZoom = vaSize.lVal;
} else {
vaSize.lVal = _wZoom;
HRESULT hr = _pBrowser->ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER,
&vaSize, NULL);
}
}
VOID CMainWnd::Close()
{
RETAILMSG(1,(L"STBIHOST CMainWnd::Close"));
// Tell the shell to die off
SendMessage(_hWndBrowser, WM_CLOSE, 0,0);
if(_pIPActiveObj)
{
_pIPActiveObj->Release();
}
_pIPActiveObj = NULL;
if(_pCP)
{
_pCP->Unadvise(_dwEventCookie);
_pCP->Release();
}
_pCP = NULL;
if(_pObject)
{
_pObject->Close(FALSE);
_pObject->Release();
}
_pObject = NULL;
if(_pBrowser)
_pBrowser->Release();
_pBrowser = NULL;
}
HRESULT CMainWnd::FindString()
{
LPDISPATCH pDisp = NULL;
LPOLECOMMANDTARGET pCmdTarg = NULL;
HRESULT sts = S_OK;
VARIANTARG var;
#define GOERROR_S(bNotCond) {if (!(bNotCond)) goto errorS; }
if (!_pBrowser)
return S_OK;
sts = _pBrowser->get_Document(&pDisp);
GOERROR_S(pDisp);
sts = pDisp->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmdTarg);
GOERROR_S(pCmdTarg);
var.vt = VT_I4;
var.lVal = 0;
sts = pCmdTarg->Exec(
NULL,
OLECMDID_FIND,
MSOCMDEXECOPT_PROMPTUSER,
NULL,
&var);
errorS:
if (pCmdTarg)
pCmdTarg->Release(); // release document's command target
if (pDisp)
pDisp->Release(); // release document's dispatch interface
return sts;
}
BOOL CMainWnd::EnableSafeArea(BOOL fEnable)
{
BOOL fRet;
if (fEnable)
{
fRet = SetWindowPos(_hWndBrowser, NULL, _ptSafe.x, _ptSafe.y,
_lSafeWidth, _lSafeHeight, SWP_NOZORDER);
if (!fRet)
{
ASSERT(FALSE);
RETAILMSG(1, (TEXT("SetWindowPos(x=%i, y=%i, cx=%i, cy=%i) ")
TEXT("failed in CMainWnd::EnableSafeArea()"),
_ptSafe.x, _ptSafe.y, _lSafeWidth, _lSafeHeight));
}
}
else
{
fRet = SetWindowPos(_hWndBrowser, NULL,
_rcWnd.left, _rcWnd.top,
_rcWnd.right - _rcWnd.left,
_rcWnd.bottom - _rcWnd.top,
SWP_NOZORDER);
if (!fRet)
{
ASSERT(FALSE);
RETAILMSG(1, (TEXT("SetWindowPos(x=%i, y=%i, cx=%i, cy=%i) ")
TEXT("failed in CMainWnd::EnableSafeArea()"),
_rcWnd.left, _rcWnd.top,
_rcWnd.right - _rcWnd.left,
_rcWnd.bottom - _rcWnd.top));
}
}
if (fRet)
{
_fSafeArea = fEnable;
}
return fRet;
}
BOOL CMainWnd::AssignAccelerator(ACCEL accel, SHORT nKey)
{
accel.fVirt = FNOINVERT | FVIRTKEY;
switch (nKey)
{
case RCTL_STOP:
accel.key = VK_MEDIA_STOP;
accel.cmd = ID_VIEW_STOP;
break;
case RCTL_PLAY:
accel.key = VK_PLAY;
accel.cmd = ID_VIEW_REFRESH;
break;
case RCTL_PREV:
accel.key = VK_MEDIA_PREV_TRACK;
accel.cmd = ID_GO_HOME;
break;
case RCTL_NEXT:
accel.key = VK_MEDIA_NEXT_TRACK;
accel.cmd = ID_GO_SEARCH;
break;
case RCTL_BACK:
accel.key = VK_PRIOR;
accel.cmd = ID_GO_BACK;
break;
case RCTL_FWD:
accel.key = VK_NEXT;
accel.cmd = ID_GO_FORWARD;
case RCTL_VOLUP:
accel.key = VK_VOLUME_UP;
accel.cmd = ID_SCROLL_PAGEUP;
break;
case RCTL_VOLDN:
accel.key = VK_VOLUME_DOWN;
accel.cmd = ID_SCROLL_PAGEDOWN;
break;
default:
ASSERT(FALSE);
return FALSE;
}
return TRUE;
}
// This bitmask defines the keys that StbIHost doesn't
// have in its default accelerator table). We need this
// to insure that StbIHost doesn't suddenly start
// handling these keys when a new table overrides the
// default.
//
// We simply have no use for pause, mute, or menu, and
// SHDOCVW uses left, right, up, down, and select for
// TVLENS tab navigation.
#define RCTLKEYS_BM_DONTCARE ( RCTL_BM_PAUSE | RCTL_BM_MUTE | RCTL_BM_MENU \
| RCTL_BM_LEFT | RCTL_BM_RIGHT | RCTL_BM_UP \
| RCTL_BM_DOWN | RCTL_BM_SELECT )
BOOL CMainWnd::CreateAccelTbl(ULONG bmKeys)
{
// if this ASSERT fails, then the datatype
// for bmKeys needs to be larger
ASSERT(RCTL_NUMKEYS < sizeof(bmKeys) * 8);
_fUseNewAccels = TRUE;
// all the bit fields in bmKeys with value=1 are
// the ones the current web page wants to use, so
// we care about the left-overs--the bitfields with
// value=0
bmKeys = (~bmKeys & ~RCTLKEYS_BM_DONTCARE & ((1 << RCTL_NUMKEYS) - 1));
if (!bmKeys)
return TRUE;
ULONG bmKeysTmp = bmKeys;
// determine length of new accelerator table
_cNewAccels = 0;
while (0 != bmKeysTmp)
{
if (bmKeysTmp & 1)
_cNewAccels++;
bmKeysTmp >>= 1;
}
// create table
if (_rgNewAccels)
delete [] _rgNewAccels;
_rgNewAccels = new ACCEL[_cNewAccels];
if (!_rgNewAccels)
{
_cNewAccels = 0;
_fUseNewAccels = FALSE;
return FALSE;
}
SHORT nKeys = 0, nBit = 0;
while (0 != bmKeys)
{
if (bmKeys & 1)
{
if (!AssignAccelerator(_rgNewAccels[nKeys], nBit))
{
_cNewAccels = 0;
delete [] _rgNewAccels;
_fUseNewAccels = FALSE;
return FALSE;
}
nKeys++;
}
bmKeys >>= 1;
nBit++;
}
// finally, register new table
if (_hAccelTblNew)
DestroyAcceleratorTable(_hAccelTblNew);
_hAccelTblNew = CreateAcceleratorTable(_rgNewAccels, _cNewAccels);
if (!_hAccelTblNew)
{
ASSERT(FALSE);
_cNewAccels = 0;
delete [] _rgNewAccels;
_fUseNewAccels = FALSE;
return FALSE;
}
return TRUE;
}
BOOL CMainWnd::DestroyAccelTbl()
{
if (_rgNewAccels)
{
delete [] _rgNewAccels;
_rgNewAccels = NULL;
}
if (_hAccelTblNew)
{
DestroyAcceleratorTable(_hAccelTblNew);
_hAccelTblNew = NULL;
}
_cNewAccels = 0;
_fUseNewAccels = FALSE;
return TRUE;
}
BOOL HandleBrowse(HWND hwndOwner, WCHAR *szURL);
extern "C" BOOL APIENTRY OpenURLDlgProc (HWND hDlg, UINT message, UINT wParam, LONG lParam)
{
WCHAR *szURL = (WCHAR *)GetWindowLong(hDlg,DWL_USER);
int nRet = 4;
switch(message)
{
case WM_INITDIALOG:
{
if(!lParam)
{
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
EnableWindow(GetDlgItem(hDlg, IDC_BROWSE), FALSE);
}
else
{
szURL = (WCHAR *)lParam;
SetWindowLong(hDlg, DWL_USER, (LONG)szURL);
SendMessage(GetDlgItem(hDlg, IDC_URL_EDIT), EM_LIMITTEXT, MAX_URL-1, 0);
if(szURL[0])
{
SetDlgItemText(hDlg, IDC_URL_EDIT, szURL);
}
}
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
{
GetDlgItemText(hDlg, IDC_URL_EDIT, szURL, MAX_URL-1);
BOOL bNewWnd = SendMessage(GetDlgItem(hDlg, IDC_NEWWINDOW), BM_GETCHECK, 0L, 0L);
nRet = (bNewWnd) ? 2 : 1;
}
case IDCANCEL:
EndDialog(hDlg, nRet);
return TRUE;
case IDC_BROWSE:
if(HandleBrowse(hDlg, szURL))
{
SetDlgItemText(hDlg, IDC_URL_EDIT, szURL);
}
default:
return (TRUE);
}
break;
case WM_DESTROY:
SetWindowLong(hDlg, DWL_USER, 0);
break;
}
return (FALSE);
}
extern HINSTANCE g_hInstance;
BOOL HandleBrowse(HWND hwndOwner, WCHAR *szURL)
{
OPENFILENAME ofn;
WCHAR wchFilter[MAX_PATH];
WCHAR wchFile[MAX_PATH+8];
int cbLen;
// Initialize ofn struct
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwndOwner;
ofn.Flags = OFN_FILEMUSTEXIST
| OFN_PATHMUSTEXIST
| OFN_OVERWRITEPROMPT
| OFN_HIDEREADONLY;
cbLen = LoadString(g_hInstance, IDS_BROWSEFILTER,
wchFilter, MAX_PATH-2);
if (cbLen>0)
{
for (; cbLen >= 0; cbLen--)
{
if (wchFilter[cbLen]== L'@')
{
wchFilter[cbLen] = 0;
}
}
}
else
{
return FALSE;
}
ofn.lpstrFilter = wchFilter;
ofn.nFilterIndex = 1;
wcscpy(wchFile, L"file://");
ofn.lpstrFile = wchFile+wcslen(wchFile); // prefix the string with "file://"
ofn.nMaxFile = MAX_PATH;
if (GetOpenFileName(&ofn))
{
wcsncpy(szURL, wchFile, MAX_URL-1);
return TRUE;
}
return FALSE;
}