Files
Mozilla/mozilla/embedding/browser/activex/src/control/MozillaBrowser.cpp
bsmedberg%covad.net 0b5159006b From bug 320988, remove references to nsCRT::strcmp
git-svn-id: svn://10.0.0.236/trunk@186528 18797224-902f-48f8-a5cc-f745e15eee43
2005-12-23 14:16:20 +00:00

2161 lines
60 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "stdafx.h"
#include <string.h>
#include <string>
#include <objidl.h>
//#include <comdef.h>
#include <shlobj.h>
// commdlg.h is needed to build with WIN32_LEAN_AND_MEAN
#include <commdlg.h>
#include "MozillaControl.h"
#include "MozillaBrowser.h"
#include "IEHtmlDocument.h"
#include "PropertyDlg.h"
#include "PageSetupDlg.h"
#include "PromptService.h"
#include "HelperAppDlg.h"
#include "WindowCreator.h"
#include "nsNetUtil.h"
#include "nsCWebBrowser.h"
#include "nsIAtom.h"
#include "nsILocalFile.h"
#include "nsIWebBrowserPersist.h"
#include "nsIClipboardCommands.h"
#include "nsIProfile.h"
#include "nsIWidget.h"
#include "nsIWebBrowserFocus.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsIComponentRegistrar.h"
#ifdef NS_PRINTING
#include "nsIPrintOptions.h"
#include "nsIWebBrowserPrint.h"
#endif
#include "nsIDOMWindow.h"
#include "nsIDOMHTMLAnchorElement.h"
#include "nsIDOMNSDocument.h"
#include "nsEmbedAPI.h"
#include "nsEmbedCID.h"
#define HACK_NON_REENTRANCY
#ifdef HACK_NON_REENTRANCY
static HANDLE s_hHackedNonReentrancy = NULL;
#endif
#define NS_PROMPTSERVICE_CID \
{0xa2112d6a, 0x0e28, 0x421f, {0xb4, 0x6a, 0x25, 0xc0, 0xb3, 0x8, 0xcb, 0xd0}}
#define NS_HELPERAPPLAUNCHERDIALOG_CID \
{0xf68578eb, 0x6ec2, 0x4169, {0xae, 0x19, 0x8c, 0x62, 0x43, 0xf0, 0xab, 0xe1}}
static NS_DEFINE_CID(kPromptServiceCID, NS_PROMPTSERVICE_CID);
static NS_DEFINE_CID(kHelperAppLauncherDialogCID, NS_HELPERAPPLAUNCHERDIALOG_CID);
#ifdef NS_PRINTING
class PrintListener : public nsIWebProgressListener
{
PRBool mComplete;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
PrintListener();
virtual ~PrintListener();
void WaitForComplete();
};
#endif
class SimpleDirectoryProvider :
public nsIDirectoryServiceProvider
{
public:
SimpleDirectoryProvider();
BOOL IsValid() const;
NS_DECL_ISUPPORTS
NS_DECL_NSIDIRECTORYSERVICEPROVIDER
protected:
virtual ~SimpleDirectoryProvider();
nsCOMPtr<nsILocalFile> mApplicationRegistryDir;
nsCOMPtr<nsILocalFile> mApplicationRegistryFile;
nsCOMPtr<nsILocalFile> mUserProfileDir;
};
// Default page in design mode. The data protocol may or may not be supported
// so the scheme is checked before the page is loaded.
static const char kDesignModeScheme[] = "data";
static const OLECHAR kDesignModeURL[] =
L"data:text/html,<html><body bgcolor=\"#00FF00\"><p>Mozilla Control</p></body></html>";
// Registry keys and values
static const TCHAR kBrowserHelperObjectRegKey[] =
_T("Software\\Mozilla\\ActiveX Control\\Browser Helper Objects");
// Some recent SDKs define these IOleCommandTarget groups, so they're
// postfixed with _Moz to prevent linker errors.
GUID CGID_IWebBrowser_Moz =
{ 0xED016940L, 0xBD5B, 0x11cf, {0xBA, 0x4E, 0x00, 0xC0, 0x4F, 0xD7, 0x08, 0x16} };
GUID CGID_MSHTML_Moz =
{ 0xED016940L, 0xBD5B, 0x11cf, {0xBA, 0x4E, 0x00, 0xC0, 0x4F, 0xD7, 0x08, 0x16} };
/////////////////////////////////////////////////////////////////////////////
// CMozillaBrowser
nsVoidArray CMozillaBrowser::sBrowserList;
//
// Constructor
//
CMozillaBrowser::CMozillaBrowser()
{
NG_TRACE_METHOD(CMozillaBrowser::CMozillaBrowser);
// ATL flags ensures the control opens with a window
m_bWindowOnly = TRUE;
m_bWndLess = FALSE;
// Initialize layout interfaces
mWebBrowserAsWin = nsnull;
mValidBrowserFlag = FALSE;
// Create the container that handles some things for us
mWebBrowserContainer = NULL;
// Control starts off in non-edit mode
mEditModeFlag = FALSE;
// Control starts off without being a drop target
mHaveDropTargetFlag = FALSE;
// the IHTMLDocument, lazy allocation.
mIERootDocument = NULL;
// Browser helpers
mBrowserHelperList = NULL;
mBrowserHelperListCount = 0;
// Name of the default profile to use
mProfileName.Assign(NS_LITERAL_STRING("MozillaControl"));
// Initialise the web browser
Initialize();
}
//
// Destructor
//
CMozillaBrowser::~CMozillaBrowser()
{
NG_TRACE_METHOD(CMozillaBrowser::~CMozillaBrowser);
// Close the web browser
Terminate();
}
// See bug 127982:
//
// Microsoft's InlineIsEqualGUID global function is multiply defined
// in ATL and/or SDKs with varying namespace requirements. To save the control
// from future grief, this method is used instead.
static inline BOOL _IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
return (
((PLONG) &rguid1)[0] == ((PLONG) &rguid2)[0] &&
((PLONG) &rguid1)[1] == ((PLONG) &rguid2)[1] &&
((PLONG) &rguid1)[2] == ((PLONG) &rguid2)[2] &&
((PLONG) &rguid1)[3] == ((PLONG) &rguid2)[3]);
}
STDMETHODIMP CMozillaBrowser::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IWebBrowser,
&IID_IWebBrowser2,
&IID_IWebBrowserApp
};
for (int i = 0; i < (sizeof(arr) / sizeof(arr[0])); i++)
{
if (_IsEqualGUID(*arr[i], riid))
return S_OK;
}
return S_FALSE;
}
//
// ShowContextMenu
//
void CMozillaBrowser::ShowContextMenu(PRUint32 aContextFlags, nsIDOMEvent *aEvent, nsIDOMNode *aNode)
{
POINT pt;
GetCursorPos(&pt);
// Give the client application the chance to show its own menu
// in place of the one the control is about to show.
CIPtr(IDocHostUIHandler) spIDocHostUIHandler = m_spClientSite;
if (spIDocHostUIHandler)
{
enum IE4MenuContexts
{
ctxMenuDefault = 0,
ctxMenuImage,
ctxMenuControl,
ctxMenuTable,
ctxMenuDebug,
ctxMenu1DSelect,
ctxMenuAnchor,
ctxMenuImgDynSrc
};
DWORD dwID = ctxMenuDefault;
if (aContextFlags & nsIContextMenuListener::CONTEXT_DOCUMENT)
{
dwID = ctxMenuDefault;
}
else if (aContextFlags & nsIContextMenuListener::CONTEXT_LINK)
{
dwID = ctxMenuAnchor;
}
else if (aContextFlags & nsIContextMenuListener::CONTEXT_IMAGE)
{
dwID = ctxMenuImage;
}
else if (aContextFlags & nsIContextMenuListener::CONTEXT_TEXT)
{
dwID = ctxMenu1DSelect;
}
else
{
dwID = ctxMenuDefault;
}
HRESULT hr = spIDocHostUIHandler->ShowContextMenu(dwID, &pt, NULL, NULL);
if (hr == S_OK)
{
// Client handled menu
return;
}
}
LPTSTR pszMenuResource = NULL;
if (aContextFlags & nsIContextMenuListener::CONTEXT_DOCUMENT)
{
pszMenuResource = MAKEINTRESOURCE(IDR_POPUP_DOCUMENT);
}
else if (aContextFlags & nsIContextMenuListener::CONTEXT_LINK)
{
pszMenuResource = MAKEINTRESOURCE(IDR_POPUP_LINK);
}
else if (aContextFlags & nsIContextMenuListener::CONTEXT_IMAGE)
{
pszMenuResource = MAKEINTRESOURCE(IDR_POPUP_IMAGE);
}
else if (aContextFlags & nsIContextMenuListener::CONTEXT_TEXT)
{
pszMenuResource = MAKEINTRESOURCE(IDR_POPUP_TEXT);
}
else
{
pszMenuResource = MAKEINTRESOURCE(IDR_POPUP_DOCUMENT);
}
if (pszMenuResource)
{
HMENU hMenu = LoadMenu(_Module.m_hInstResource, pszMenuResource);
HMENU hPopupMenu = GetSubMenu(hMenu, 0);
mContextNode = do_QueryInterface(aNode);
UINT nCmd = TrackPopupMenu(hPopupMenu, TPM_NONOTIFY | TPM_RETURNCMD, pt.x, pt.y, 0, m_hWnd, NULL);
DestroyMenu(hMenu);
if (nCmd != 0)
{
SendMessage(WM_COMMAND, nCmd);
}
mContextNode = nsnull;
}
}
//
// ShowURIPropertyDlg
//
void CMozillaBrowser::ShowURIPropertyDlg(const nsAString &aURI, const nsAString &aContentType)
{
CPropertyDlg dlg;
CPPageDlg linkDlg;
dlg.AddPage(&linkDlg);
if (!aURI.IsEmpty())
{
linkDlg.mType = aContentType;
linkDlg.mURL = aURI;
}
dlg.DoModal();
}
//
// Displays a message box to the user. If the container provides
// a IDocHostShowUI interface we use that to display messages, otherwise
// a simple message box is shown.
//
int CMozillaBrowser::MessageBox(LPCTSTR lpszText, LPCTSTR lpszCaption, UINT nType)
{
// Let the doc host display it's own message box if it can
CIPtr(IDocHostShowUI) spIDocHostShowUI = m_spClientSite;
if (spIDocHostShowUI)
{
USES_CONVERSION;
LRESULT lResult = 0;
HRESULT hr = spIDocHostShowUI->ShowMessage(m_hWnd,
T2OLE(lpszText), T2OLE(lpszCaption), nType, NULL, 0, &lResult);
if (hr == S_OK)
{
return lResult;
}
}
// Do the default message box
return CWindow::MessageBox(lpszText, lpszCaption, nType);
}
//
// Sets the startup error message from a resource string
//
HRESULT CMozillaBrowser::SetStartupErrorMessage(UINT nStringID)
{
TCHAR szMsg[1024];
::LoadString(_Module.m_hInstResource, nStringID, szMsg, sizeof(szMsg) / sizeof(szMsg[0]));
mStartupErrorMessage = szMsg;
return S_OK;
}
//
// Tells the container to change focus to the next control in the dialog.
//
void CMozillaBrowser::NextDlgControl()
{
HWND hwndParent = GetParent();
if (::IsWindow(hwndParent))
{
::PostMessage(hwndParent, WM_NEXTDLGCTL, 0, 0);
}
}
//
// Tells the container to change focus to the previous control in the dialog.
//
void CMozillaBrowser::PrevDlgControl()
{
HWND hwndParent = GetParent();
if (::IsWindow(hwndParent))
{
::PostMessage(hwndParent, WM_NEXTDLGCTL, 1, 0);
}
}
///////////////////////////////////////////////////////////////////////////////
// Message handlers
// Handle WM_CREATE windows message
LRESULT CMozillaBrowser::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnCreate);
// Create the web browser
CreateBrowser();
// TODO create and register a drop target
// Control is ready
mBrowserReadyState = READYSTATE_COMPLETE;
FireOnChanged(DISPID_READYSTATE);
// Load browser helpers
LoadBrowserHelpers();
// Browse to a default page - if in design mode
BOOL bUserMode = FALSE;
if (SUCCEEDED(GetAmbientUserMode(bUserMode)))
{
if (!bUserMode)
{
// Load a page in design mode if the specified page is supported
nsCOMPtr<nsIIOService> ios = do_GetIOService();
if (ios)
{
// Ensure design page can be loaded by checking for a
// registered protocol handler that supports the scheme
nsCOMPtr<nsIProtocolHandler> ph;
nsCAutoString phScheme;
ios->GetProtocolHandler(kDesignModeScheme, getter_AddRefs(ph));
if (ph &&
NS_SUCCEEDED(ph->GetScheme(phScheme)) &&
phScheme.Equals(NS_LITERAL_CSTRING(kDesignModeScheme)))
{
Navigate(const_cast<BSTR>(kDesignModeURL), NULL, NULL, NULL, NULL);
}
}
}
}
// Clip the child windows out of paint operations
SetWindowLong(GWL_STYLE, GetWindowLong(GWL_STYLE) | WS_CLIPCHILDREN | WS_TABSTOP);
return 0;
}
// Handle WM_DESTROY window message
LRESULT CMozillaBrowser::OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnDestroy);
// Unload browser helpers
UnloadBrowserHelpers();
// Clean up the browser
DestroyBrowser();
return 0;
}
// Handle WM_SIZE windows message
LRESULT CMozillaBrowser::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnSize);
RECT rc;
rc.top = 0;
rc.left = 0;
rc.right = LOWORD(lParam);
rc.bottom = HIWORD(lParam);
AdjustWindowRectEx(&rc, GetWindowLong(GWL_STYLE), FALSE, GetWindowLong(GWL_EXSTYLE));
rc.right -= rc.left;
rc.bottom -= rc.top;
rc.left = 0;
rc.top = 0;
// Pass resize information down to the browser...
if (mWebBrowserAsWin)
{
mWebBrowserAsWin->SetPosition(rc.left, rc.top);
mWebBrowserAsWin->SetSize(rc.right - rc.left, rc.bottom - rc.top, PR_TRUE);
}
return 0;
}
// Handle WM_SETFOCUS
LRESULT CMozillaBrowser::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
ATLTRACE(_T("CMozillaBrowser::OnSetFocus()\n"));
nsCOMPtr<nsIWebBrowserFocus> browserAsFocus = do_QueryInterface(mWebBrowser);
if (browserAsFocus)
{
browserAsFocus->Activate();
}
CComQIPtr<IOleControlSite> controlSite = m_spClientSite;
if (controlSite)
{
controlSite->OnFocus(TRUE);
}
return 0;
}
// Handle WM_KILLFOCUS
LRESULT CMozillaBrowser::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
ATLTRACE(_T("CMozillaBrowser::OnKillFocus()\n"));
nsCOMPtr<nsIWebBrowserFocus> browserAsFocus = do_QueryInterface(mWebBrowser);
if (browserAsFocus)
{
browserAsFocus->Deactivate();
}
CComQIPtr<IOleControlSite> controlSite = m_spClientSite;
if (controlSite)
{
controlSite->OnFocus(FALSE);
}
return 0;
}
// Handle WM_MOUSEACTIVATE messages
LRESULT CMozillaBrowser::OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return MA_ACTIVATE;
}
// Handle WM_GETDLGCODE to receive keyboard presses
LRESULT CMozillaBrowser::OnGetDlgCode(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
return DLGC_WANTALLKEYS;
}
// Handle WM_PAINT windows message (and IViewObject::Draw)
HRESULT CMozillaBrowser::OnDraw(ATL_DRAWINFO& di)
{
NG_TRACE_METHOD(CMozillaBrowser::OnDraw);
if (!BrowserIsValid())
{
RECT& rc = *(RECT*)di.prcBounds;
DrawText(di.hdcDraw, mStartupErrorMessage.c_str(), -1, &rc, DT_TOP | DT_LEFT | DT_WORDBREAK);
}
return S_OK;
}
// Handle ID_PAGESETUP command
LRESULT CMozillaBrowser::OnPageSetup(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnPageSetup);
#ifdef NS_PRINTING
nsCOMPtr<nsIWebBrowserPrint> print(do_GetInterface(mWebBrowser));
nsCOMPtr<nsIPrintSettings> printSettings;
if(!print ||
NS_FAILED(print->GetGlobalPrintSettings(getter_AddRefs(printSettings))))
{
return 0;
}
// show the page setup dialog
CPageSetupDlg dlg(printSettings);
dlg.DoModal();
#endif
return 0;
}
// Handle ID_PRINT command
LRESULT CMozillaBrowser::OnPrint(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnPrint);
if (!BrowserIsValid())
{
return 0;
}
PrintDocument(TRUE);
return 0;
}
LRESULT CMozillaBrowser::OnSaveAs(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnSaveAs);
OPENFILENAME SaveFileName;
char szFile[_MAX_PATH];
char szFileTitle[256];
//TODO: The IE control allows you to also save as "Web Page, complete"
// where all of the page's images are saved in the same directory.
// For the moment, we're not allowing this option.
memset(&SaveFileName, 0, sizeof(SaveFileName));
SaveFileName.lStructSize = sizeof(SaveFileName);
SaveFileName.hwndOwner = m_hWnd;
SaveFileName.lpstrFilter = "Web Page, HTML Only (*.htm;*.html)\0*.htm;*.html\0Text File (*.txt)\0*.txt\0";
SaveFileName.nFilterIndex = 1;
SaveFileName.lpstrFile = szFile;
SaveFileName.nMaxFile = sizeof(szFile);
SaveFileName.lpstrFileTitle = szFileTitle;
SaveFileName.nMaxFileTitle = sizeof(szFileTitle);
SaveFileName.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
SaveFileName.lpstrDefExt = "htm";
//Get the title of the current web page to set as the default filename.
char szTmp[_MAX_FNAME] = "untitled";
BSTR pageName = NULL;
get_LocationName(&pageName); // Page title
if (pageName)
{
USES_CONVERSION;
strncpy(szTmp, OLE2A(pageName), sizeof(szTmp) - 1);
SysFreeString(pageName);
szTmp[sizeof(szTmp) - 1] = '\0';
}
// The SaveAs dialog will fail if szFile contains any "bad" characters.
// This hunk of code attempts to mimick the IE way of replacing "bad"
// characters with "good" characters.
int j = 0;
for (int i=0; szTmp[i]!='\0'; i++)
{
switch(szTmp[i])
{
case '\\':
case '*':
case '|':
case ':':
case '"':
case '>':
case '<':
case '?':
break;
case '.':
if (szTmp[i+1] != '\0')
{
szFile[j] = '_';
j++;
}
break;
case '/':
szFile[j] = '-';
j++;
break;
default:
szFile[j] = szTmp[i];
j++;
}
}
szFile[j] = '\0';
HRESULT hr = S_OK;
if (GetSaveFileName(&SaveFileName))
{
nsCOMPtr<nsIWebBrowserPersist> persist(do_QueryInterface(mWebBrowser));
USES_CONVERSION;
char szDataFile[_MAX_PATH];
char szDataPath[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath(szFile, drive, dir, fname, ext);
sprintf(szDataFile, "%s_files", fname);
_makepath(szDataPath, drive, dir, szDataFile, "");
nsCOMPtr<nsILocalFile> file;
NS_NewNativeLocalFile(nsDependentCString(T2A(szFile)), TRUE, getter_AddRefs(file));
nsCOMPtr<nsILocalFile> dataPath;
NS_NewNativeLocalFile(nsDependentCString(szDataPath), TRUE, getter_AddRefs(dataPath));
persist->SaveDocument(nsnull, file, dataPath, nsnull, 0, 0);
}
return hr;
}
LRESULT CMozillaBrowser::OnProperties(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnProperties);
MessageBox(_T("No Properties Yet!"), _T("Control Message"), MB_OK);
// TODO show the properties dialog
return 0;
}
LRESULT CMozillaBrowser::OnCut(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnCut);
nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
if (clipboard)
{
clipboard->CutSelection();
}
return 0;
}
LRESULT CMozillaBrowser::OnCopy(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnCopy);
nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
if (clipboard)
{
clipboard->CopySelection();
}
return 0;
}
LRESULT CMozillaBrowser::OnPaste(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnPaste);
nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
if (clipboard)
{
clipboard->Paste();
}
return 0;
}
LRESULT CMozillaBrowser::OnSelectAll(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnSelectAll);
nsCOMPtr<nsIClipboardCommands> clipboard(do_GetInterface(mWebBrowser));
if (clipboard)
{
clipboard->SelectAll();
}
return 0;
}
// Handle ID_VIEWSOURCE command
LRESULT CMozillaBrowser::OnViewSource(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
NG_TRACE_METHOD(CMozillaBrowser::OnViewSource);
if (!mWebBrowser)
{
// No webbrowser to view!
NG_ASSERT(0);
return 0;
}
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(mWebBrowser);
if (!webNav)
{
// No webnav!
NG_ASSERT(0);
return 0;
}
nsCOMPtr<nsIURI> uri;
webNav->GetCurrentURI(getter_AddRefs(uri));
if (!uri)
{
// No URI to view!
NG_ASSERT(0);
return 0;
}
// Get the current URI
nsCAutoString aURI;
uri->GetSpec(aURI);
NS_ConvertUTF8toUTF16 strURI(aURI);
strURI.Insert(NS_LITERAL_STRING("view-source:"), 0);
// Ask the client to create a window to view the source in
CIPtr(IDispatch) spDispNew;
VARIANT_BOOL bCancel = VARIANT_FALSE;
Fire_NewWindow2(&spDispNew, &bCancel);
// Load the view-source into a new url
if ((bCancel == VARIANT_FALSE) && spDispNew)
{
CIPtr(IWebBrowser2) spOther = spDispNew;;
if (spOther)
{
// tack in the viewsource command
CComBSTR bstrURL(strURI.get());
CComVariant vURL(bstrURL);
VARIANT vNull;
vNull.vt = VT_NULL;
spOther->Navigate2(&vURL, &vNull, &vNull, &vNull, &vNull);
}
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Document handlers
LRESULT CMozillaBrowser::OnDocumentBack(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
GoBack();
return 0;
}
LRESULT CMozillaBrowser::OnDocumentForward(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
GoForward();
return 0;
}
LRESULT CMozillaBrowser::OnDocumentPrint(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
return OnPrint(wNotifyCode, wID, hWndCtl, bHandled);
}
LRESULT CMozillaBrowser::OnDocumentRefresh(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
Refresh();
return 0;
}
LRESULT CMozillaBrowser::OnDocumentProperties(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
nsCOMPtr<nsIDOMDocument> ownerDoc;
if (mContextNode)
{
mContextNode->GetOwnerDocument(getter_AddRefs(ownerDoc));
}
// Get the document URL
nsAutoString uri;
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(ownerDoc);
if (htmlDoc)
{
htmlDoc->GetURL(uri);
}
nsAutoString contentType;
nsCOMPtr<nsIDOMNSDocument> doc = do_QueryInterface(ownerDoc);
if (doc)
{
doc->GetContentType(contentType);
}
ShowURIPropertyDlg(uri, contentType);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Link handlers
LRESULT CMozillaBrowser::OnLinkOpen(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
nsAutoString uri;
nsCOMPtr<nsIDOMHTMLAnchorElement> anchorElement = do_QueryInterface(mContextNode);
if (anchorElement)
{
anchorElement->GetHref(uri);
}
if (!uri.IsEmpty())
{
CComBSTR bstrURI(uri.get());
CComVariant vFlags(0);
Navigate(bstrURI, &vFlags, NULL, NULL, NULL);
}
return 0;
}
LRESULT CMozillaBrowser::OnLinkOpenInNewWindow(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
nsAutoString uri;
nsCOMPtr<nsIDOMHTMLAnchorElement> anchorElement = do_QueryInterface(mContextNode);
if (anchorElement)
{
anchorElement->GetHref(uri);
}
if (!uri.IsEmpty())
{
CComBSTR bstrURI(uri.get());
CComVariant vFlags(navOpenInNewWindow);
Navigate(bstrURI, &vFlags, NULL, NULL, NULL);
}
return 0;
}
LRESULT CMozillaBrowser::OnLinkCopyShortcut(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
nsAutoString uri;
nsCOMPtr<nsIDOMHTMLAnchorElement> anchorElement = do_QueryInterface(mContextNode);
if (anchorElement)
{
anchorElement->GetHref(uri);
}
if (!uri.IsEmpty() && OpenClipboard())
{
EmptyClipboard();
NS_ConvertUTF16toUTF8 curi(uri);
const char *stringText;
PRUint32 stringLen = NS_CStringGetData(curi,
&stringText);
// CF_TEXT
HGLOBAL hmemText = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
stringLen + 1);
char *pszText = (char *) GlobalLock(hmemText);
strncpy(pszText, stringText, stringLen);
pszText[stringLen] = '\0';
GlobalUnlock(hmemText);
SetClipboardData(CF_TEXT, hmemText);
// UniformResourceLocator - CFSTR_SHELLURL
const UINT cfShellURL = RegisterClipboardFormat(CFSTR_SHELLURL);
HGLOBAL hmemURL = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
stringLen + 1);
char *pszURL = (char *) GlobalLock(hmemURL);
strncpy(pszText, stringText, stringLen);
pszText[stringLen] = '\0';
GlobalUnlock(hmemURL);
SetClipboardData(cfShellURL, hmemURL);
// TODO
// FileContents - CFSTR_FILECONTENTS
// FileGroupDescriptor - CFSTR_FILEDESCRIPTORA
// FileGroupDescriptorW - CFSTR_FILEDESCRIPTORW
CloseClipboard();
}
return 0;
}
LRESULT CMozillaBrowser::OnLinkProperties(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
nsAutoString uri;
nsAutoString type;
nsCOMPtr<nsIDOMHTMLAnchorElement> anchorElement = do_QueryInterface(mContextNode);
if (anchorElement)
{
anchorElement->GetHref(uri);
anchorElement->GetType(type); // How many anchors implement this I wonder
}
ShowURIPropertyDlg(uri, type);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Initialises the web browser engine
HRESULT CMozillaBrowser::Initialize()
{
#ifdef HACK_NON_REENTRANCY
// Attempt to open a named event for this process. If it's not there we
// know this is the first time the control has run in this process, so create
// the named event and do the initialisation. Otherwise do nothing.
TCHAR szHackEvent[255];
_stprintf(szHackEvent, _T("MozCtlEvent%d"), (int) GetCurrentProcessId());
s_hHackedNonReentrancy = OpenEvent(EVENT_ALL_ACCESS, FALSE, szHackEvent);
if (s_hHackedNonReentrancy == NULL)
{
s_hHackedNonReentrancy = CreateEvent(NULL, FALSE, FALSE, szHackEvent);
#endif
// Extract the bin directory path from the control's filename
TCHAR szMozCtlPath[MAX_PATH];
memset(szMozCtlPath, 0, sizeof(szMozCtlPath));
GetModuleFileName(_Module.m_hInst, szMozCtlPath, sizeof(szMozCtlPath) / sizeof(szMozCtlPath[0]));
TCHAR szTmpDrive[_MAX_DRIVE];
TCHAR szTmpDir[_MAX_DIR];
TCHAR szTmpFname[_MAX_FNAME];
TCHAR szTmpExt[_MAX_EXT];
TCHAR szBinDirPath[MAX_PATH];
_tsplitpath(szMozCtlPath, szTmpDrive, szTmpDir, szTmpFname, szTmpExt);
memset(szBinDirPath, 0, sizeof(szBinDirPath));
_tmakepath(szBinDirPath, szTmpDrive, szTmpDir, NULL, NULL);
if (_tcslen(szBinDirPath) == 0)
{
return E_FAIL;
}
// Create a simple directory provider. If this fails because the directories are
// invalid or whatever then the control will fallback on the default directory
// provider.
nsCOMPtr<nsIDirectoryServiceProvider> directoryProvider;
SimpleDirectoryProvider *pDirectoryProvider = new SimpleDirectoryProvider;
if (pDirectoryProvider->IsValid())
directoryProvider = do_QueryInterface(pDirectoryProvider);
// Create an object to represent the path
nsresult rv;
nsCOMPtr<nsILocalFile> binDir;
USES_CONVERSION;
NS_NewNativeLocalFile(nsDependentCString(T2A(szBinDirPath)), TRUE, getter_AddRefs(binDir));
rv = NS_InitEmbedding(binDir, directoryProvider);
// Load preferences service
mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
NG_ASSERT(0);
NG_TRACE_ALWAYS(_T("Could not create preference object rv=%08x\n"), (int) rv);
SetStartupErrorMessage(IDS_CANNOTCREATEPREFS);
return E_FAIL;
}
// Stuff in here only needs to be done once
static BOOL bRegisterComponents = FALSE;
if (!bRegisterComponents)
{
// Register our own native prompting service for message boxes, login
// prompts etc.
nsCOMPtr<nsIFactory> promptFactory;
rv = NS_NewPromptServiceFactory(getter_AddRefs(promptFactory));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIComponentRegistrar> registrar;
rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
if (NS_FAILED(rv)) return rv;
rv = registrar->RegisterFactory(kPromptServiceCID,
"Prompt Service",
NS_PROMPTSERVICE_CONTRACTID,
promptFactory);
if (NS_FAILED(rv)) return rv;
// Helper app launcher dialog
nsCOMPtr<nsIFactory> helperAppDlgFactory;
rv = NS_NewHelperAppLauncherDlgFactory(getter_AddRefs(helperAppDlgFactory));
if (NS_FAILED(rv)) return rv;
rv = registrar->RegisterFactory(kHelperAppLauncherDialogCID,
"Helper App Launcher Dialog",
"@mozilla.org/helperapplauncherdialog;1",
helperAppDlgFactory);
if (NS_FAILED(rv)) return rv;
// create our local object
CWindowCreator *creator = new CWindowCreator();
nsCOMPtr<nsIWindowCreator> windowCreator;
windowCreator = NS_STATIC_CAST(nsIWindowCreator *, creator);
// Attach it via the watcher service
nsCOMPtr<nsIWindowWatcher> watcher =
do_GetService(NS_WINDOWWATCHER_CONTRACTID);
if (watcher)
watcher->SetWindowCreator(windowCreator);
}
// Set the profile which the control will use
nsCOMPtr<nsIProfile> profileService =
do_GetService(NS_PROFILE_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
return E_FAIL;
}
// Make a new default profile
PRBool profileExists = PR_FALSE;
rv = profileService->ProfileExists(mProfileName.get(), &profileExists);
if (NS_FAILED(rv))
{
return E_FAIL;
}
else if (!profileExists)
{
rv = profileService->CreateNewProfile(mProfileName.get(), nsnull, nsnull, PR_FALSE);
if (NS_FAILED(rv))
{
return E_FAIL;
}
}
rv = profileService->SetCurrentProfile(mProfileName.get());
if (NS_FAILED(rv))
{
return E_FAIL;
}
#ifdef HACK_NON_REENTRANCY
}
#endif
return S_OK;
}
// Terminates the web browser engine
HRESULT CMozillaBrowser::Terminate()
{
#ifdef HACK_NON_REENTRANCY
if (0)
{
#endif
mPrefBranch = nsnull;
NS_TermEmbedding();
#ifdef HACK_NON_REENTRANCY
}
#endif
return S_OK;
}
// Create and initialise the web browser
HRESULT CMozillaBrowser::CreateBrowser()
{
NG_TRACE_METHOD(CMozillaBrowser::CreateBrowser);
if (mWebBrowser != nsnull)
{
NG_ASSERT(0);
NG_TRACE_ALWAYS(_T("CreateBrowser() called more than once!"));
return SetErrorInfo(E_UNEXPECTED);
}
RECT rcLocation;
GetClientRect(&rcLocation);
if (IsRectEmpty(&rcLocation))
{
rcLocation.bottom++;
rcLocation.top++;
}
nsresult rv;
// Create the web browser
mWebBrowser = do_CreateInstance(NS_WEBBROWSER_CONTRACTID, &rv);
if (NS_FAILED(rv))
{
NG_ASSERT(0);
NG_TRACE_ALWAYS(_T("Could not create webbrowser object rv=%08x\n"), (int) rv);
SetStartupErrorMessage(IDS_CANNOTCREATEPREFS);
return rv;
}
// Configure what the web browser can and cannot do
nsCOMPtr<nsIWebBrowserSetup> webBrowserAsSetup(do_QueryInterface(mWebBrowser));
// Allow plugins?
const PRBool kAllowPlugins = PR_TRUE;
webBrowserAsSetup->SetProperty(nsIWebBrowserSetup::SETUP_ALLOW_PLUGINS, kAllowPlugins);
// Host chrome or content?
const PRBool kHostChrome = PR_FALSE; // Hardcoded for now
webBrowserAsSetup->SetProperty(nsIWebBrowserSetup::SETUP_IS_CHROME_WRAPPER, PR_FALSE);
// Create the webbrowser window
mWebBrowserAsWin = do_QueryInterface(mWebBrowser);
rv = mWebBrowserAsWin->InitWindow(nsNativeWidget(m_hWnd), nsnull,
0, 0, rcLocation.right - rcLocation.left, rcLocation.bottom - rcLocation.top);
rv = mWebBrowserAsWin->Create();
// Create the container object
mWebBrowserContainer = new CWebBrowserContainer(this);
if (mWebBrowserContainer == NULL)
{
NG_ASSERT(0);
NG_TRACE_ALWAYS(_T("Could not create webbrowsercontainer - out of memory\n"));
return NS_ERROR_OUT_OF_MEMORY;
}
mWebBrowserContainer->AddRef();
// Set up the browser with its chrome
mWebBrowser->SetContainerWindow(NS_STATIC_CAST(nsIWebBrowserChrome*, mWebBrowserContainer));
mWebBrowser->SetParentURIContentListener(mWebBrowserContainer);
// Subscribe for progress notifications
nsCOMPtr<nsIWeakReference> listener(
do_GetWeakReference(NS_STATIC_CAST(nsIWebProgressListener*, mWebBrowserContainer)));
mWebBrowser->AddWebBrowserListener(listener, NS_GET_IID(nsIWebProgressListener));
// Visible
mWebBrowserAsWin->SetVisibility(PR_TRUE);
// Activated
nsCOMPtr<nsIWebBrowserFocus> browserAsFocus = do_QueryInterface(mWebBrowser);
browserAsFocus->Activate();
// Get an editor session
mEditingSession = do_GetInterface(mWebBrowser);
mCommandManager = do_GetInterface(mWebBrowser);
// Append browser to browser list
sBrowserList.AppendElement(this);
mValidBrowserFlag = TRUE;
return S_OK;
}
// Clean up the browser
HRESULT CMozillaBrowser::DestroyBrowser()
{
// TODO unregister drop target
mValidBrowserFlag = FALSE;
// Remove browser from browser list
sBrowserList.RemoveElement(this);
// Destroy the htmldoc
if (mIERootDocument != NULL)
{
mIERootDocument->Release();
mIERootDocument = NULL;
}
// Destroy layout...
if (mWebBrowserAsWin)
{
mWebBrowserAsWin->Destroy();
mWebBrowserAsWin = nsnull;
}
if (mWebBrowserContainer)
{
mWebBrowserContainer->Release();
mWebBrowserContainer = NULL;
}
mEditingSession = nsnull;
mCommandManager = nsnull;
mWebBrowser = nsnull;
return S_OK;
}
// Turns the editor mode on or off
HRESULT CMozillaBrowser::SetEditorMode(BOOL bEnabled)
{
NG_TRACE_METHOD(CMozillaBrowser::SetEditorMode);
if (!mEditingSession || !mCommandManager)
return E_FAIL;
nsCOMPtr<nsIDOMWindow> domWindow;
nsresult rv = GetDOMWindow(getter_AddRefs(domWindow));
if (NS_FAILED(rv))
return E_FAIL;
rv = mEditingSession->MakeWindowEditable(domWindow, "html", PR_FALSE);
return S_OK;
}
HRESULT CMozillaBrowser::OnEditorCommand(DWORD nCmdID)
{
NG_TRACE_METHOD(CMozillaBrowser::OnEditorCommand);
nsCOMPtr<nsIDOMWindow> domWindow;
GetDOMWindow(getter_AddRefs(domWindow));
const char *styleCommand = nsnull;
nsICommandParams *commandParams = nsnull;
switch (nCmdID)
{
case IDM_BOLD:
styleCommand = "cmd_bold";
break;
case IDM_ITALIC:
styleCommand = "cmd_italic";
break;
case IDM_UNDERLINE:
styleCommand = "cmd_underline";
break;
// TODO add the rest!
default:
// DO NOTHING
break;
}
return mCommandManager ?
mCommandManager->DoCommand(styleCommand, commandParams, domWindow) :
NS_ERROR_FAILURE;
}
// Return the root DOM document
HRESULT CMozillaBrowser::GetDOMDocument(nsIDOMDocument **pDocument)
{
NG_TRACE_METHOD(CMozillaBrowser::GetDOMDocument);
HRESULT hr = E_FAIL;
// Test for stupid args
if (pDocument == NULL)
{
NG_ASSERT(0);
return E_INVALIDARG;
}
*pDocument = nsnull;
if (!BrowserIsValid())
{
NG_ASSERT(0);
return E_UNEXPECTED;
}
// Get the DOM window from the webbrowser
nsCOMPtr<nsIDOMWindow> window;
mWebBrowser->GetContentDOMWindow(getter_AddRefs(window));
if (window)
{
if (NS_SUCCEEDED(window->GetDocument(pDocument)) && *pDocument)
{
hr = S_OK;
}
}
return hr;
}
// Load any browser helpers
HRESULT CMozillaBrowser::LoadBrowserHelpers()
{
NG_TRACE_METHOD(CMozillaBrowser::LoadBrowserHelpers);
UnloadBrowserHelpers();
// IE loads browser helper objects from a branch of the registry
// Search the branch looking for objects to load with the control.
CRegKey cKey;
if (cKey.Open(HKEY_LOCAL_MACHINE, kBrowserHelperObjectRegKey, KEY_ENUMERATE_SUB_KEYS) != ERROR_SUCCESS)
{
NG_TRACE(_T("No browser helper key found\n"));
return S_FALSE;
}
// Count the number of browser helper object keys
ULONG nHelperKeys = 0;
LONG nResult = ERROR_SUCCESS;
while (nResult == ERROR_SUCCESS)
{
TCHAR szCLSID[50];
DWORD dwCLSID = sizeof(szCLSID) / sizeof(TCHAR);
FILETIME cLastWrite;
// Read next subkey
nResult = RegEnumKeyEx(cKey, nHelperKeys, szCLSID, &dwCLSID, NULL, NULL, NULL, &cLastWrite);
if (nResult != ERROR_SUCCESS)
{
break;
}
nHelperKeys++;
}
if (nHelperKeys == 0)
{
NG_TRACE(_T("No browser helper objects found\n"));
return S_FALSE;
}
// Get the CLSID for each browser helper object
CLSID *pClassList = new CLSID[nHelperKeys];
DWORD nHelpers = 0;
DWORD nKey = 0;
nResult = ERROR_SUCCESS;
while (nResult == ERROR_SUCCESS)
{
TCHAR szCLSID[50];
DWORD dwCLSID = sizeof(szCLSID) / sizeof(TCHAR);
FILETIME cLastWrite;
// Read next subkey
nResult = RegEnumKeyEx(cKey, nKey++, szCLSID, &dwCLSID, NULL, NULL, NULL, &cLastWrite);
if (nResult != ERROR_SUCCESS)
{
break;
}
NG_TRACE(_T("Reading helper object entry \"%s\"\n"), szCLSID);
// Turn the key into a CLSID
USES_CONVERSION;
CLSID clsid;
if (CLSIDFromString(T2OLE(szCLSID), &clsid) != NOERROR)
{
continue;
}
pClassList[nHelpers++] = clsid;
}
mBrowserHelperList = new CComUnkPtr[nHelpers];
// Create each object in turn
for (ULONG i = 0; i < nHelpers; i++)
{
CLSID clsid = pClassList[i];
HRESULT hr;
CComQIPtr<IObjectWithSite, &IID_IObjectWithSite> cpObjectWithSite;
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IObjectWithSite, (LPVOID *) &cpObjectWithSite);
if (FAILED(hr))
{
NG_TRACE(_T("Registered browser helper object cannot be created\n"));;
}
else
{
// Set the object to point at the browser
cpObjectWithSite->SetSite((IWebBrowser2 *) this);
// Store in the list
CComUnkPtr cpUnk = cpObjectWithSite;
mBrowserHelperList[mBrowserHelperListCount++] = cpUnk;
}
}
delete []pClassList;
return S_OK;
}
// Release browser helpers
HRESULT CMozillaBrowser::UnloadBrowserHelpers()
{
NG_TRACE_METHOD(CMozillaBrowser::UnloadBrowserHelpers);
if (mBrowserHelperList == NULL)
{
return S_OK;
}
// Destroy each helper
for (ULONG i = 0; i < mBrowserHelperListCount; i++)
{
CComUnkPtr cpUnk = mBrowserHelperList[i];
if (cpUnk)
{
CComQIPtr<IObjectWithSite, &IID_IObjectWithSite> cpObjectWithSite = cpUnk;
if (cpObjectWithSite)
{
cpObjectWithSite->SetSite(NULL);
}
}
}
// Cleanup the array
mBrowserHelperListCount = 0;
delete []mBrowserHelperList;
mBrowserHelperList = NULL;
return S_OK;
}
// Print document
HRESULT CMozillaBrowser::PrintDocument(BOOL promptUser)
{
#ifdef NS_PRINTING
// Print the contents
nsCOMPtr<nsIWebBrowserPrint> browserAsPrint = do_GetInterface(mWebBrowser);
NS_ASSERTION(browserAsPrint, "No nsIWebBrowserPrint!");
PRBool oldPrintSilent = PR_FALSE;
nsCOMPtr<nsIPrintSettings> printSettings;
browserAsPrint->GetGlobalPrintSettings(getter_AddRefs(printSettings));
if (printSettings)
{
printSettings->GetPrintSilent(&oldPrintSilent);
printSettings->SetPrintSilent(promptUser ? PR_FALSE : PR_TRUE);
}
// Disable print progress dialog (XUL)
PRBool oldShowPrintProgress = FALSE;
const char *kShowPrintProgressPref = "print.show_print_progress";
mPrefBranch->GetBoolPref(kShowPrintProgressPref, &oldShowPrintProgress);
mPrefBranch->SetBoolPref(kShowPrintProgressPref, PR_FALSE);
// Print
PrintListener *listener = new PrintListener;
nsCOMPtr<nsIWebProgressListener> printListener = do_QueryInterface(listener);
nsresult rv = browserAsPrint->Print(printSettings, printListener);
if (NS_SUCCEEDED(rv))
{
listener->WaitForComplete();
}
// Cleanup
if (printSettings)
{
printSettings->SetPrintSilent(oldPrintSilent);
}
mPrefBranch->SetBoolPref(kShowPrintProgressPref, oldShowPrintProgress);
#endif
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IOleObject overrides
// This is an almost verbatim copy of the standard ATL implementation of
// IOleObject::InPlaceActivate but with a few lines commented out.
HRESULT CMozillaBrowser::InPlaceActivate(LONG iVerb, const RECT* prcPosRect)
{
NG_TRACE_METHOD(CMozillaBrowser::InPlaceActivate);
HRESULT hr;
if (m_spClientSite == NULL)
return S_OK;
CComPtr<IOleInPlaceObject> pIPO;
ControlQueryInterface(IID_IOleInPlaceObject, (void**)&pIPO);
_ASSERTE(pIPO != NULL);
if (prcPosRect != NULL)
pIPO->SetObjectRects(prcPosRect, prcPosRect);
if (!m_bNegotiatedWnd)
{
if (!m_bWindowOnly)
// Try for windowless site
hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSiteWindowless, (void **)&m_spInPlaceSite);
if (m_spInPlaceSite)
{
m_bInPlaceSiteEx = TRUE;
m_bWndLess = SUCCEEDED(m_spInPlaceSite->CanWindowlessActivate());
m_bWasOnceWindowless = TRUE;
}
else
{
m_spClientSite->QueryInterface(IID_IOleInPlaceSiteEx, (void **)&m_spInPlaceSite);
if (m_spInPlaceSite)
m_bInPlaceSiteEx = TRUE;
else
hr = m_spClientSite->QueryInterface(IID_IOleInPlaceSite, (void **)&m_spInPlaceSite);
}
}
_ASSERTE(m_spInPlaceSite);
if (!m_spInPlaceSite)
return E_FAIL;
m_bNegotiatedWnd = TRUE;
if (!m_bInPlaceActive)
{
BOOL bNoRedraw = FALSE;
if (m_bWndLess)
m_spInPlaceSite->OnInPlaceActivateEx(&bNoRedraw, ACTIVATE_WINDOWLESS);
else
{
if (m_bInPlaceSiteEx)
m_spInPlaceSite->OnInPlaceActivateEx(&bNoRedraw, 0);
else
{
HRESULT hr = m_spInPlaceSite->CanInPlaceActivate();
if (FAILED(hr))
return hr;
m_spInPlaceSite->OnInPlaceActivate();
}
}
}
m_bInPlaceActive = TRUE;
// get location in the parent window,
// as well as some information about the parent
//
OLEINPLACEFRAMEINFO frameInfo;
RECT rcPos, rcClip;
CComPtr<IOleInPlaceFrame> spInPlaceFrame;
CComPtr<IOleInPlaceUIWindow> spInPlaceUIWindow;
frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
HWND hwndParent;
if (m_spInPlaceSite->GetWindow(&hwndParent) == S_OK)
{
m_spInPlaceSite->GetWindowContext(&spInPlaceFrame,
&spInPlaceUIWindow, &rcPos, &rcClip, &frameInfo);
if (!m_bWndLess)
{
if (m_hWndCD)
{
::ShowWindow(m_hWndCD, SW_SHOW);
::SetFocus(m_hWndCD);
}
else
{
HWND h = CreateControlWindow(hwndParent, rcPos);
_ASSERTE(h == m_hWndCD);
}
}
pIPO->SetObjectRects(&rcPos, &rcClip);
}
CComPtr<IOleInPlaceActiveObject> spActiveObject;
ControlQueryInterface(IID_IOleInPlaceActiveObject, (void**)&spActiveObject);
// Gone active by now, take care of UIACTIVATE
if (DoesVerbUIActivate(iVerb))
{
if (!m_bUIActive)
{
m_bUIActive = TRUE;
hr = m_spInPlaceSite->OnUIActivate();
if (FAILED(hr))
return hr;
SetControlFocus(TRUE);
// set ourselves up in the host.
//
if (spActiveObject)
{
if (spInPlaceFrame)
spInPlaceFrame->SetActiveObject(spActiveObject, NULL);
if (spInPlaceUIWindow)
spInPlaceUIWindow->SetActiveObject(spActiveObject, NULL);
}
// These lines are deliberately commented out to demonstrate what breaks certain
// control containers.
// if (spInPlaceFrame)
// spInPlaceFrame->SetBorderSpace(NULL);
// if (spInPlaceUIWindow)
// spInPlaceUIWindow->SetBorderSpace(NULL);
}
}
m_spClientSite->ShowObject();
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMozillaBrowser::GetClientSite(IOleClientSite **ppClientSite)
{
NG_TRACE_METHOD(CMozillaBrowser::GetClientSite);
NG_ASSERT(ppClientSite);
// This fixes a problem in the base class which asserts if the client
// site has not been set when this method is called.
HRESULT hRes = E_POINTER;
if (ppClientSite != NULL)
{
*ppClientSite = NULL;
if (m_spClientSite == NULL)
{
return S_OK;
}
}
return IOleObjectImpl<CMozillaBrowser>::GetClientSite(ppClientSite);
}
/////////////////////////////////////////////////////////////////////////////
// IMozControlBridge
HRESULT STDMETHODCALLTYPE CMozillaBrowser::GetWebBrowser(/* [out] */ void __RPC_FAR *__RPC_FAR *aBrowser)
{
if (!NgIsValidAddress(aBrowser, sizeof(void *)))
{
NG_ASSERT(0);
return SetErrorInfo(E_INVALIDARG);
}
*aBrowser = NULL;
if (mWebBrowser)
{
nsIWebBrowser *browser = mWebBrowser.get();
NS_ADDREF(browser);
*aBrowser = (void *) browser;
}
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IWebBrowserImpl
nsresult CMozillaBrowser::GetWebNavigation(nsIWebNavigation **aWebNav)
{
NS_ENSURE_ARG_POINTER(aWebNav);
if (!mWebBrowser) return NS_ERROR_FAILURE;
return mWebBrowser->QueryInterface(NS_GET_IID(nsIWebNavigation), (void **) aWebNav);
}
nsresult CMozillaBrowser::GetDOMWindow(nsIDOMWindow **aDOMWindow)
{
NS_ENSURE_ARG_POINTER(aDOMWindow);
if (!mWebBrowser) return NS_ERROR_FAILURE;
return mWebBrowser->GetContentDOMWindow(aDOMWindow);
}
nsresult CMozillaBrowser::GetPrefs(nsIPrefBranch **aPrefBranch)
{
if (mPrefBranch)
*aPrefBranch = mPrefBranch;
NS_IF_ADDREF(*aPrefBranch);
return (*aPrefBranch) ? NS_OK : NS_ERROR_FAILURE;
}
PRBool CMozillaBrowser::BrowserIsValid()
{
NG_TRACE_METHOD(CMozillaBrowser::BrowserIsValid);
return mValidBrowserFlag ? PR_TRUE : PR_FALSE;
}
// Overrides of IWebBrowser / IWebBrowserApp / IWebBrowser2 methods
HRESULT STDMETHODCALLTYPE CMozillaBrowser::get_Parent(IDispatch __RPC_FAR *__RPC_FAR *ppDisp)
{
NG_TRACE_METHOD(CMozillaBrowser::get_Parent);
ENSURE_BROWSER_IS_VALID();
if (!NgIsValidAddress(ppDisp, sizeof(IDispatch *)))
{
NG_ASSERT(0);
return SetErrorInfo(E_INVALIDARG);
}
// Attempt to get the parent object of this control
HRESULT hr = E_FAIL;
if (m_spClientSite)
{
hr = m_spClientSite->QueryInterface(IID_IDispatch, (void **) ppDisp);
}
return (SUCCEEDED(hr)) ? S_OK : E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE CMozillaBrowser::get_Document(IDispatch __RPC_FAR *__RPC_FAR *ppDisp)
{
NG_TRACE_METHOD(CMozillaBrowser::get_Document);
ENSURE_BROWSER_IS_VALID();
if (!NgIsValidAddress(ppDisp, sizeof(IDispatch *)))
{
NG_ASSERT(0);
return SetErrorInfo(E_UNEXPECTED);
}
*ppDisp = NULL;
// Get hold of the DOM document
nsIDOMDocument *pIDOMDocument = nsnull;
if (FAILED(GetDOMDocument(&pIDOMDocument)) || pIDOMDocument == nsnull)
{
return S_OK; // return NULL pointer
}
if (mIERootDocument == NULL)
{
nsCOMPtr <nsIDOMHTMLDocument> pIDOMHTMLDocument =
do_QueryInterface(pIDOMDocument);
if (!pIDOMDocument)
{
return SetErrorInfo(E_FAIL, L"get_Document: not HTML");
}
CIEHtmlDocumentInstance::CreateInstance(&mIERootDocument);
if (mIERootDocument == NULL)
{
return SetErrorInfo(E_OUTOFMEMORY, L"get_Document: can't create IERootDocument");
}
// addref it so it doesn't go away on us.
mIERootDocument->AddRef();
// give it a pointer to us. note that we shouldn't be addref'd by this call, or it would be
// a circular reference.
mIERootDocument->SetParent(this);
mIERootDocument->SetDOMNode(pIDOMDocument);
mIERootDocument->SetNative(pIDOMHTMLDocument);
}
mIERootDocument->QueryInterface(IID_IDispatch, (void **) ppDisp);
pIDOMDocument->Release();
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMozillaBrowser::get_RegisterAsDropTarget(VARIANT_BOOL __RPC_FAR *pbRegister)
{
NG_TRACE_METHOD(CMozillaBrowser::get_RegisterAsDropTarget);
ENSURE_BROWSER_IS_VALID();
if (pbRegister == NULL)
{
NG_ASSERT(0);
return SetErrorInfo(E_INVALIDARG);
}
*pbRegister = mHaveDropTargetFlag ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
static BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
{
::RevokeDragDrop(hwnd);
return TRUE;
}
HRESULT STDMETHODCALLTYPE CMozillaBrowser::put_RegisterAsDropTarget(VARIANT_BOOL bRegister)
{
NG_TRACE_METHOD(CMozillaBrowser::put_RegisterAsDropTarget);
ENSURE_BROWSER_IS_VALID();
// Register the window as a drop target
if (bRegister == VARIANT_TRUE)
{
if (!mHaveDropTargetFlag)
{
CDropTargetInstance *pDropTarget = NULL;
CDropTargetInstance::CreateInstance(&pDropTarget);
if (pDropTarget)
{
pDropTarget->AddRef();
pDropTarget->SetOwner(this);
// Ask the site if it wants to replace this drop target for another one
CIPtr(IDropTarget) spDropTarget;
CIPtr(IDocHostUIHandler) spDocHostUIHandler = m_spClientSite;
if (spDocHostUIHandler)
{
//if (spDocHostUIHandler->GetDropTarget(pDropTarget, &spDropTarget) != S_OK)
if (spDocHostUIHandler->GetDropTarget(pDropTarget, &spDropTarget) == S_OK)
{
mHaveDropTargetFlag = TRUE;
::RegisterDragDrop(m_hWnd, spDropTarget);
//spDropTarget = pDropTarget;
}
}
else
//if (spDropTarget)
{
mHaveDropTargetFlag = TRUE;
::RegisterDragDrop(m_hWnd, pDropTarget);
//::RegisterDragDrop(m_hWnd, spDropTarget);
}
pDropTarget->Release();
}
// Now revoke any child window drop targets and pray they aren't
// reset by the layout engine.
::EnumChildWindows(m_hWnd, EnumChildProc, (LPARAM) this);
}
}
else
{
if (mHaveDropTargetFlag)
{
mHaveDropTargetFlag = FALSE;
::RevokeDragDrop(m_hWnd);
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// Ole Command Handlers
HRESULT _stdcall CMozillaBrowser::PrintHandler(CMozillaBrowser *pThis, const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
{
BOOL promptUser = (nCmdexecopt & OLECMDEXECOPT_DONTPROMPTUSER) ? FALSE : TRUE;
pThis->PrintDocument(promptUser);
return S_OK;
}
HRESULT _stdcall CMozillaBrowser::EditModeHandler(CMozillaBrowser *pThis, const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
{
BOOL bEditorMode = (nCmdID == IDM_EDITMODE) ? TRUE : FALSE;
pThis->SetEditorMode(bEditorMode);
return S_OK;
}
HRESULT _stdcall CMozillaBrowser::EditCommandHandler(CMozillaBrowser *pThis, const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
{
pThis->OnEditorCommand(nCmdID);
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
// SimpleDirectoryProvider implementation
SimpleDirectoryProvider::SimpleDirectoryProvider()
{
nsCOMPtr<nsILocalFile> appDataDir;
// Attempt to fill appDataDir with a meaningful value. Any error in the process
// will cause the constructor to return and IsValid() to return FALSE,
CComPtr<IMalloc> shellMalloc;
SHGetMalloc(&shellMalloc);
if (shellMalloc)
{
LPITEMIDLIST pitemidList = NULL;
SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pitemidList);
if (pitemidList)
{
TCHAR szBuffer[MAX_PATH + 1];
if (SUCCEEDED(SHGetPathFromIDList(pitemidList, szBuffer)))
{
szBuffer[MAX_PATH] = TCHAR('\0');
USES_CONVERSION;
NS_NewNativeLocalFile(nsDependentCString(T2A(szBuffer)), TRUE, getter_AddRefs(appDataDir));
}
shellMalloc->Free(pitemidList);
}
}
if (!appDataDir)
{
return;
}
// Mozilla control paths are
// App data - {Application Data}/MozillaControl
// App registry - {Application Data}/MozillaControl/registry.dat
// Profiles - {Application Data}/MozillaControl/profiles
nsresult rv;
// Create the root directory
PRBool exists;
rv = appDataDir->Exists(&exists);
if (NS_FAILED(rv) || !exists) return;
// MozillaControl application data
rv = appDataDir->AppendRelativePath(NS_LITERAL_STRING("MozillaControl"));
if (NS_FAILED(rv)) return;
rv = appDataDir->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = appDataDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return;
// Registry.dat file
nsCOMPtr<nsIFile> appDataRegAsFile;
rv = appDataDir->Clone(getter_AddRefs(appDataRegAsFile));
if (NS_FAILED(rv)) return;
nsCOMPtr<nsILocalFile> appDataRegistry = do_QueryInterface(appDataRegAsFile, &rv);
if (NS_FAILED(rv)) return;
appDataRegistry->AppendRelativePath(NS_LITERAL_STRING("registry.dat"));
// Profiles directory
nsCOMPtr<nsIFile> profileDirAsFile;
rv = appDataDir->Clone(getter_AddRefs(profileDirAsFile));
if (NS_FAILED(rv)) return;
nsCOMPtr<nsILocalFile> profileDir = do_QueryInterface(profileDirAsFile, &rv);
if (NS_FAILED(rv)) return;
profileDir->AppendRelativePath(NS_LITERAL_STRING("profiles"));
rv = profileDir->Exists(&exists);
if (NS_SUCCEEDED(rv) && !exists)
rv = profileDir->Create(nsIFile::DIRECTORY_TYPE, 0775);
if (NS_FAILED(rv)) return;
// Store the member values
mApplicationRegistryDir = appDataDir;
mApplicationRegistryFile = appDataRegistry;
mUserProfileDir = profileDir;
}
SimpleDirectoryProvider::~SimpleDirectoryProvider()
{
}
BOOL
SimpleDirectoryProvider::IsValid() const
{
return (mApplicationRegistryDir && mApplicationRegistryFile && mUserProfileDir) ?
TRUE : FALSE;
}
NS_IMPL_ISUPPORTS1(SimpleDirectoryProvider, nsIDirectoryServiceProvider)
///////////////////////////////////////////////////////////////////////////////
// nsIDirectoryServiceProvider
/* nsIFile getFile (in string prop, out PRBool persistent); */
NS_IMETHODIMP SimpleDirectoryProvider::GetFile(const char *prop, PRBool *persistent, nsIFile **_retval)
{
NS_ENSURE_ARG_POINTER(prop);
NS_ENSURE_ARG_POINTER(persistent);
NS_ENSURE_ARG_POINTER(_retval);
*_retval = nsnull;
*persistent = PR_TRUE;
// Only need to support NS_APP_APPLICATION_REGISTRY_DIR, NS_APP_APPLICATION_REGISTRY_FILE, and
// NS_APP_USER_PROFILES_ROOT_DIR. Unsupported keys fallback to the default service provider
nsCOMPtr<nsILocalFile> localFile;
nsresult rv = NS_ERROR_FAILURE;
if (strcmp(prop, NS_APP_APPLICATION_REGISTRY_DIR) == 0)
{
localFile = mApplicationRegistryDir;
}
else if (strcmp(prop, NS_APP_APPLICATION_REGISTRY_FILE) == 0)
{
localFile = mApplicationRegistryFile;
}
else if (strcmp(prop, NS_APP_USER_PROFILES_ROOT_DIR) == 0)
{
localFile = mUserProfileDir;
}
if (localFile)
return CallQueryInterface(localFile, _retval);
return rv;
}
///////////////////////////////////////////////////////////////////////////////
// PrintListener implementation
#ifdef NS_PRINTING
NS_IMPL_ISUPPORTS1(PrintListener, nsIWebProgressListener)
PrintListener::PrintListener() : mComplete(PR_FALSE)
{
/* member initializers and constructor code */
}
PrintListener::~PrintListener()
{
/* destructor code */
}
void PrintListener::WaitForComplete()
{
MSG msg;
HANDLE hFakeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
while (!mComplete)
{
// Process pending messages
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!::GetMessage(&msg, NULL, 0, 0))
{
::CloseHandle(hFakeEvent);
return;
}
PRBool wasHandled = PR_FALSE;
::NS_HandleEmbeddingEvent(msg, wasHandled);
if (wasHandled)
continue;
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if (mComplete)
break;
// Do idle stuff
::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 500, QS_ALLEVENTS);
}
::CloseHandle(hFakeEvent);
}
/* void onStateChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long aStateFlags, in nsresult aStatus); */
NS_IMETHODIMP PrintListener::OnStateChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 aStateFlags, nsresult aStatus)
{
if (aStateFlags & nsIWebProgressListener::STATE_STOP &&
aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT)
{
mComplete = PR_TRUE;
}
return NS_OK;
}
/* void onProgressChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in long aCurSelfProgress, in long aMaxSelfProgress, in long aCurTotalProgress, in long aMaxTotalProgress); */
NS_IMETHODIMP PrintListener::OnProgressChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress)
{
return NS_OK;
}
/* void onLocationChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsIURI location); */
NS_IMETHODIMP PrintListener::OnLocationChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsIURI *location)
{
return NS_OK;
}
/* void onStatusChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in nsresult aStatus, in wstring aMessage); */
NS_IMETHODIMP PrintListener::OnStatusChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, nsresult aStatus, const PRUnichar *aMessage)
{
return NS_OK;
}
/* void onSecurityChange (in nsIWebProgress aWebProgress, in nsIRequest aRequest, in unsigned long state); */
NS_IMETHODIMP PrintListener::OnSecurityChange(nsIWebProgress *aWebProgress, nsIRequest *aRequest, PRUint32 state)
{
return NS_OK;
}
#endif