Windows-Server-2003/shell/shdocvw/dhuihand.cpp

3641 lines
111 KiB
C++

#include "priv.h"
#include "resource.h"
#include "mshtmcid.h"
#include <mluisupp.h>
#ifndef X_IEHELPID_H_
#define X_IEHELPID_H_
#include "iehelpid.h"
#endif
#include "dhuihand.h"
#define DM_DOCHOSTUIHANDLER 0
#define CX_CONTEXTMENUOFFSET 2
#define CY_CONTEXTMENUOFFSET 2
//+------------------------------------------------------------------------
//
// WARNING! (greglett)
//
// The following defines were stolen from commdlg.h. Since SHDOCVW is
// compiled with WINVER=0x0400 and these defines are WINVER=0x0500 they
// needed to be copied and included here. These must be kept in sync
// with the commdlg.h definitions.
//
// If shdocvw ever gets compiled with WINVER=0x0500 or above, then these
// can be removed.
//
//-------------------------------------------------------------------------
#define NEED_BECAUSE_COMPILED_AT_WINVER_4
#ifdef NEED_BECAUSE_COMPILED_AT_WINVER_4
//
// Define the start page for the print dialog when using PrintDlgEx.
//
#define START_PAGE_GENERAL 0xffffffff
//
// Page Range structure for PrintDlgEx.
//
typedef struct tagPRINTPAGERANGE {
DWORD nFromPage;
DWORD nToPage;
} PRINTPAGERANGE, *LPPRINTPAGERANGE;
//
// PrintDlgEx structure.
//
typedef struct tagPDEXA {
DWORD lStructSize; // size of structure in bytes
HWND hwndOwner; // caller's window handle
HGLOBAL hDevMode; // handle to DevMode
HGLOBAL hDevNames; // handle to DevNames
HDC hDC; // printer DC/IC or NULL
DWORD Flags; // PD_ flags
DWORD Flags2; // reserved
DWORD ExclusionFlags; // items to exclude from driver pages
DWORD nPageRanges; // number of page ranges
DWORD nMaxPageRanges; // max number of page ranges
LPPRINTPAGERANGE lpPageRanges; // array of page ranges
DWORD nMinPage; // min page number
DWORD nMaxPage; // max page number
DWORD nCopies; // number of copies
HINSTANCE hInstance; // instance handle
LPCSTR lpPrintTemplateName; // template name for app specific area
LPUNKNOWN lpCallback; // app callback interface
DWORD nPropertyPages; // number of app property pages in lphPropertyPages
HPROPSHEETPAGE *lphPropertyPages; // array of app property page handles
DWORD nStartPage; // start page id
DWORD dwResultAction; // result action if S_OK is returned
} PRINTDLGEXA, *LPPRINTDLGEXA;
//
// PrintDlgEx structure.
//
typedef struct tagPDEXW {
DWORD lStructSize; // size of structure in bytes
HWND hwndOwner; // caller's window handle
HGLOBAL hDevMode; // handle to DevMode
HGLOBAL hDevNames; // handle to DevNames
HDC hDC; // printer DC/IC or NULL
DWORD Flags; // PD_ flags
DWORD Flags2; // reserved
DWORD ExclusionFlags; // items to exclude from driver pages
DWORD nPageRanges; // number of page ranges
DWORD nMaxPageRanges; // max number of page ranges
LPPRINTPAGERANGE lpPageRanges; // array of page ranges
DWORD nMinPage; // min page number
DWORD nMaxPage; // max page number
DWORD nCopies; // number of copies
HINSTANCE hInstance; // instance handle
LPCWSTR lpPrintTemplateName; // template name for app specific area
LPUNKNOWN lpCallback; // app callback interface
DWORD nPropertyPages; // number of app property pages in lphPropertyPages
HPROPSHEETPAGE *lphPropertyPages; // array of app property page handles
DWORD nStartPage; // start page id
DWORD dwResultAction; // result action if S_OK is returned
} PRINTDLGEXW, *LPPRINTDLGEXW;
#ifdef UNICODE
typedef PRINTDLGEXW PRINTDLGEX;
typedef LPPRINTDLGEXW LPPRINTDLGEX;
#else
typedef PRINTDLGEXA PRINTDLGEX;
typedef LPPRINTDLGEXA LPPRINTDLGEX;
#endif // UNICODE
HRESULT APIENTRY PrintDlgExA(LPPRINTDLGEXA);
HRESULT APIENTRY PrintDlgExW(LPPRINTDLGEXW);
#ifdef UNICODE
#define PrintDlgEx PrintDlgExW
#else
#define PrintDlgEx PrintDlgExA
#endif // !UNICODE
//
// Result action ids for PrintDlgEx.
//
#define PD_RESULT_CANCEL 0
#define PD_RESULT_PRINT 1
#define PD_RESULT_APPLY 2
#define PD_CURRENTPAGE 0x00400000
#define PD_NOCURRENTPAGE 0x00800000
#endif // NEED_BECAUSE_COMPILED_AT_WINVER_4
//+------------------------------------------------------------------------
//
// Useful combinations of flags for IOleCommandTarget
//
//-------------------------------------------------------------------------
#define OLECMDSTATE_DISABLED OLECMDF_SUPPORTED
#define OLECMDSTATE_UP (OLECMDF_SUPPORTED | OLECMDF_ENABLED)
#define OLECMDSTATE_DOWN (OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_LATCHED)
#define OLECMDSTATE_NINCHED (OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_NINCHED)
struct SExpandoInfo
{
TCHAR * name;
VARTYPE type;
};
// Enumerations for custom expandos
enum MessageEnum
{
MessageText,
MessageCaption,
MessageStyle,
MessageHelpFile,
MessageHelpContext
};
enum PagesetupEnum
{
PagesetupHeader,
PagesetupFooter,
PagesetupStruct
};
enum PrintEnum
{
PrintfRootDocumentHasFrameset,
PrintfAreRatingsEnabled,
PrintfPrintActiveFrame,
PrintfPrintLinked,
PrintfPrintSelection,
PrintfPrintAsShown,
PrintfShortcutTable,
PrintiFontScaling,
PrintpBodyActiveTarget,
PrintStruct,
PrintToFileOk,
PrintToFileName,
PrintfPrintActiveFrameEnabled,
};
enum PropertysheetEnum
{
PropertysheetPunks
};
//----------------------------------------------------------------------------
//
// Arrays describing helpcontextids for PageSetup/Print
//
//----------------------------------------------------------------------------
static const DWORD aPrintDialogHelpIDs[] =
{
stc6, IDH_PRINT_CHOOSE_PRINTER,
cmb4, IDH_PRINT_CHOOSE_PRINTER,
psh2, IDH_PRINT_PROPERTIES,
stc7, IDH_PRINT_SETUP_DETAILS,
stc8, IDH_PRINT_SETUP_DETAILS,
stc9, IDH_PRINT_SETUP_DETAILS,
stc10, IDH_PRINT_SETUP_DETAILS,
stc12, IDH_PRINT_SETUP_DETAILS,
stc11, IDH_PRINT_SETUP_DETAILS,
stc14, IDH_PRINT_SETUP_DETAILS,
stc13, IDH_PRINT_SETUP_DETAILS,
stc5, IDH_PRINT_TO_FILE,
chx1, IDH_PRINT_TO_FILE,
ico3, IDH_PRINT_COLLATE,
chx2, IDH_PRINT_COLLATE,
grp1, IDH_PRINT_RANGE,
rad1, IDH_PRINT_RANGE, // all
rad2, IDH_PRINT_RANGE, // selection
rad3, IDH_PRINT_RANGE, // pages
stc2, IDH_PRINT_RANGE,
stc3, IDH_PRINT_RANGE,
edt1, IDH_PRINT_RANGE,
edt2, IDH_PRINT_RANGE,
edt3, IDH_PRINT_COPIES,
rad4, IDH_PRINT_SCREEN,
rad5, IDH_PRINT_SEL_FRAME,
rad6, IDH_PRINT_ALL_FRAME,
IDC_LINKED, IDH_PRINT_LINKS,
IDC_SHORTCUTS, IDH_PRINT_SHORTCUTS,
0, 0
};
static const DWORD aPageSetupDialogHelpIDs[] =
{
psh3, IDH_PRINT_PRINTER_SETUP,
stc2, IDH_PAGE_PAPER_SIZE,
cmb2, IDH_PAGE_PAPER_SIZE,
stc3, IDH_PAGE_PAPER_SOURCE,
cmb3, IDH_PAGE_PAPER_SOURCE,
rad1, IDH_PAGE_ORIENTATION,
rad2, IDH_PAGE_ORIENTATION,
stc15, IDH_PAGE_MARGINS,
edt4, IDH_PAGE_MARGINS,
stc16, IDH_PAGE_MARGINS,
edt5, IDH_PAGE_MARGINS,
stc17, IDH_PAGE_MARGINS,
edt6, IDH_PAGE_MARGINS,
stc18, IDH_PAGE_MARGINS,
edt7, IDH_PAGE_MARGINS,
IDC_EDITHEADER, IDH_PAGESETUP_HEADER_LEFT,
IDC_STATICHEADER, IDH_PAGESETUP_HEADER_LEFT,
IDC_EDITFOOTER, IDH_PAGESETUP_HEADER_LEFT,
IDC_STATICFOOTER, IDH_PAGESETUP_HEADER_LEFT,
IDC_HEADERFOOTER, IDH_PAGESETUP_HEADER_LEFT,
0, 0
};
//+---------------------------------------------------------------------------
//
// Function: GetControlID
//
// Synopsis:
//
// Arguments: HWND - passed window handle of WM_CONTEXTMENU
// lParam - passed coordinates (lParam) of WM_CONTEXTMENU
//
// Returns: int - ctrlid
//
//
//----------------------------------------------------------------------------
int GetControlID(HWND hwnd, LPARAM lParam)
{
int CtrlID;
CtrlID = GetDlgCtrlID(hwnd);
if (CtrlID==0)
{
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
if (ScreenToClient(hwnd, &pt))
{
HWND hwndChild = ChildWindowFromPointEx(hwnd, pt, CWP_ALL);
if (hwndChild)
{
CtrlID = GetDlgCtrlID(hwndChild);
}
}
}
return CtrlID;
}
//+---------------------------------------------------------------------------
//
// Function: GetHelpFile
//
// Synopsis:
//
// Arguments: iCtrlID - id of the control
// adw - array of DWORDS, consisting of controlid,helpid pairs
//
// Returns: A string with the name of the helpfile
//
// Notes: Help topics for the print dialogs can be either in iexplore.hlp
// or in windows.hlp. We key off the helpid to determine which
// file to go to.
//
//----------------------------------------------------------------------------
LPTSTR
GetHelpFile(int iCtrlID, DWORD * adw)
{
ASSERT (adw);
while (TRUE)
{
int ctrlid = int(*adw);
int helpid = int(*(adw + 1));
if (ctrlid == 0 && helpid == 0)
{
break;
}
if (ctrlid == iCtrlID)
{
//TraceTag((tagContextHelp, "for ctrl=%d, topic=%d", ctrlid, helpid));
return (helpid < 50000) ? TEXT("windows.hlp") : TEXT("iexplore.hlp");
}
adw += 2;
}
return TEXT("windows.hlp");
}
GetInterfaceFromClientSite(IUnknown *pUnk, REFIID riid, void ** ppv)
{
HRESULT hr;
IOleObject * pOleObject = NULL;
IOleClientSite * pOleClientSite = NULL;
if (!pUnk || !ppv)
{
hr = E_INVALIDARG;
goto Cleanup;
}
*ppv = NULL;
hr = pUnk->QueryInterface(IID_PPV_ARG(IOleObject, &pOleObject));
if (hr)
goto Cleanup;
hr = pOleObject->GetClientSite(&pOleClientSite);
if (pOleClientSite == NULL)
{
hr = E_FAIL;
}
if (hr)
goto Cleanup;
hr = pOleClientSite->QueryInterface(riid, ppv);
Cleanup:
ATOMICRELEASE(pOleClientSite);
ATOMICRELEASE(pOleObject);
return hr;
}
//
// Get the IOleInPlaceFrame if available. If this proves useful, move this somewhere interesting.
//
HRESULT GetInPlaceFrameFromUnknown(IUnknown * punk, IOleInPlaceFrame ** ppOleInPlaceFrame)
{
IOleInPlaceSite * pOleInPlaceSite = NULL;
IOleInPlaceUIWindow * pOleInPlaceUIWindow = NULL;
RECT rcPos, rcClip;
OLEINPLACEFRAMEINFO frameInfo = {0};
HRESULT hr = GetInterfaceFromClientSite(punk, IID_PPV_ARG(IOleInPlaceSite, &pOleInPlaceSite));
if (S_OK != hr)
goto Cleanup;
*ppOleInPlaceFrame = NULL;
frameInfo.cb = sizeof(OLEINPLACEFRAMEINFO);
hr = pOleInPlaceSite->GetWindowContext(ppOleInPlaceFrame,
&pOleInPlaceUIWindow,
&rcPos,
&rcClip,
&frameInfo);
Cleanup:
ATOMICRELEASE(pOleInPlaceUIWindow);
ATOMICRELEASE(pOleInPlaceSite);
return hr;
}
HRESULT
GetHwndFromUnknown(
IUnknown * punk,
HWND * phwnd)
{
HRESULT hr;
IOleInPlaceFrame * pOleInPlaceFrame = NULL;
ASSERT(punk);
ASSERT(phwnd);
if (phwnd)
{
*phwnd = NULL;
}
if (!punk || !phwnd)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hr = GetInPlaceFrameFromUnknown(punk, &pOleInPlaceFrame);
if (S_OK != hr)
goto Cleanup;
hr = pOleInPlaceFrame->GetWindow(phwnd);
if (S_OK != hr)
goto Cleanup;
Cleanup:
ATOMICRELEASE(pOleInPlaceFrame);
return hr;
}
HRESULT
GetEventFromUnknown(
IUnknown * punk,
IHTMLEventObj ** ppEventObj)
{
HRESULT hr;
IHTMLDocument2 * pOmDoc = NULL;
IHTMLWindow2 * pOmWindow = NULL;
ASSERT(punk);
ASSERT(ppEventObj);
if (ppEventObj)
*ppEventObj = NULL;
if (!punk || !ppEventObj)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hr = punk->QueryInterface(IID_PPV_ARG(IHTMLDocument2, &pOmDoc));
if (S_OK != hr)
goto Cleanup;
hr = pOmDoc->get_parentWindow(&pOmWindow);
if (S_OK != hr)
goto Cleanup;
hr = pOmWindow->get_event(ppEventObj);
if (S_OK != hr)
goto Cleanup;
Cleanup:
ATOMICRELEASE(pOmDoc);
ATOMICRELEASE(pOmWindow);
return hr;
}
//
// Gets the dispids/variants from the event.
//
HRESULT
GetParamsFromEvent(
IHTMLEventObj * pEventObj,
unsigned int cExpandos,
DISPID aDispid[],
VARIANT aVariant[],
const SExpandoInfo aExpandos[])
{
HRESULT hr;
IDispatchEx * pDispatchEx = NULL;
unsigned int i;
ASSERT(pEventObj);
ASSERT(aVariant);
ASSERT(aExpandos);
// ASSERT(cExpandos >= 0); // cExpandos is an unsigned int, so this is always true
// deleted "|| cExpandos < 0" from below test
// since unsigned ints are never negative
if (!pEventObj || !aVariant || !aExpandos)
{
hr = E_INVALIDARG;
goto Cleanup;
}
for (i=0; i<cExpandos; i++)
{
VariantInit(aVariant+i);
aDispid[i] = DISPID_UNKNOWN;
}
hr = pEventObj->QueryInterface(IID_PPV_ARG(IDispatchEx, &pDispatchEx));
if (S_OK != hr)
goto Cleanup;
for (i=0; i<cExpandos; i++)
{
hr = pDispatchEx->GetDispID(
aExpandos[i].name,
fdexNameCaseSensitive,
aDispid+i);
if (S_OK != hr)
goto Cleanup;
hr = pDispatchEx->InvokeEx(
aDispid[i],
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYGET,
(DISPPARAMS *)&g_dispparamsNoArgs,
aVariant+i,
NULL,
NULL);
// Check the variant types match
ASSERT( V_VT(aVariant+i) == aExpandos[i].type
|| V_VT(aVariant+i) == VT_EMPTY);
if (S_OK != hr)
goto Cleanup;
}
Cleanup:
ATOMICRELEASE(pDispatchEx);
return hr;
}
HRESULT
PutParamToEvent(DISPID dispid, VARIANT * var, IHTMLEventObj * pEventObj)
{
HRESULT hr;
IDispatchEx * pDispatchEx = NULL;
DISPPARAMS dispparams = {var, &dispid, 1, 1};
ASSERT(var);
ASSERT(pEventObj);
if (!var || !pEventObj)
{
hr = E_INVALIDARG;
goto Cleanup;
}
hr = pEventObj->QueryInterface(IID_PPV_ARG(IDispatchEx, &pDispatchEx));
if (S_OK != hr)
goto Cleanup;
hr = pDispatchEx->InvokeEx(
dispid,
LOCALE_USER_DEFAULT,
DISPATCH_PROPERTYPUT,
&dispparams,
NULL,
NULL,
NULL);
if (S_OK != hr)
goto Cleanup;
Cleanup:
ATOMICRELEASE(pDispatchEx);
return hr;
}
void PutFindText(IWebBrowser2* pwb, LPCWSTR pwszFindText)
{
BSTR bstrName = SysAllocString(STR_FIND_DIALOG_TEXT);
if (NULL != bstrName)
{
VARIANT var = {VT_EMPTY};
if (NULL != pwszFindText)
{
var.vt = VT_BSTR;
var.bstrVal = SysAllocString(pwszFindText);
}
if ((VT_EMPTY == var.vt) || (NULL != var.bstrVal))
{
pwb->PutProperty(bstrName, var);
}
SysFreeString(var.bstrVal);
SysFreeString(bstrName);
}
}
BSTR GetFindText(IWebBrowser2* pwb)
{
BSTR bstrName = SysAllocString(STR_FIND_DIALOG_TEXT);
VARIANT var = {0};
if (bstrName)
{
ASSERT(pwb);
pwb->GetProperty(bstrName, &var);
SysFreeString(bstrName);
}
BSTR bstrResult;
if (VT_BSTR == var.vt)
{
bstrResult = var.bstrVal;
}
else
{
bstrResult = NULL;
VariantClear(&var);
}
return bstrResult;
}
CDocHostUIHandler::CDocHostUIHandler(void) : m_cRef(1)
{
DllAddRef();
m_cPreviewIsUp = 0;
}
CDocHostUIHandler::~CDocHostUIHandler(void)
{
ATOMICRELEASE(_punkSite);
//
// We don't addref _pExternal to avoid an addref/release cycle. So, we can't release it.
//
// ATOMICRELEASE(_pExternal);
ATOMICRELEASE(_pOptionsHolder);
if (_hBrowseMenu)
DestroyMenu(_hBrowseMenu);
if (_hEditMenu)
DestroyMenu(_hEditMenu);
DllRelease();
}
STDMETHODIMP CDocHostUIHandler::QueryInterface(REFIID riid, PVOID *ppvObj)
{
static const QITAB qit[] = {
QITABENT(CDocHostUIHandler, IDocHostUIHandler),
QITABENT(CDocHostUIHandler, IObjectWithSite),
QITABENT(CDocHostUIHandler, IOleCommandTarget),
QITABENT(CDocHostUIHandler, IDispatch),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
STDMETHODIMP_(ULONG) CDocHostUIHandler::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CDocHostUIHandler::Release()
{
ASSERT(0 != m_cRef);
ULONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
}
return cRef;
}
HRESULT CDocHostUIHandler::SetSite(IUnknown *punkSite)
{
ATOMICRELEASE(_punkSite);
ASSERT(_punkSite == NULL); // don't lose a reference to this
_punkSite = punkSite;
if (_punkSite)
{
_punkSite->AddRef();
}
// Always return S_OK
//
return S_OK;
}
HRESULT CDocHostUIHandler::GetSite(REFIID riid, void **ppvSite)
{
if (_punkSite)
return _punkSite->QueryInterface(riid, ppvSite);
*ppvSite = NULL;
return E_FAIL;
}
//==========================================================================
// IDocHostUIHandler implementation
//==========================================================================
HRESULT CDocHostUIHandler::ShowContextMenu(DWORD dwID, POINT *ppt, IUnknown *pcmdtReserved, IDispatch *pdispReserved)
{
HRESULT hr = S_FALSE;
HCURSOR hcursor;
HMENU hMenu = NULL;
VARIANT var, var1, var2;
VARIANT * pvar = NULL;
int iSelection = 0;
HWND hwnd = NULL;
IOleCommandTarget * pOleCommandTarget = NULL;
IOleWindow * pOleWindow = NULL;
IOleInPlaceFrame * pOleInPlaceFrame = NULL;
IDocHostUIHandler * pUIHandler = NULL;
MENUITEMINFO mii = {0};
int i;
OLECMD olecmd;
UINT mf;
BOOL fDeletePrint = FALSE;
BOOL fDeleteSetDesktopItem = FALSE;
BOOL fDeleteViewSource = FALSE;
IHTMLImgElement * pImgEle = NULL;
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::ShowContextMenu called");
//If restriction is set, we lie to Mshtml that context menu has been set.
if (SHRestricted2W(REST_NoBrowserContextMenu, NULL, 0))
return S_OK;
// Do a proper QI for IOleCommandTarget
//
hr = pcmdtReserved->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOleCommandTarget));
if (S_OK != hr)
goto Cleanup;
// Check if we are in browse mode
//
olecmd.cmdID = IDM_BROWSEMODE;
hr = pOleCommandTarget->QueryStatus(&CGID_MSHTML, 1, &olecmd, NULL);
if (S_OK != hr)
goto Cleanup;
if (olecmd.cmdf == OLECMDSTATE_DOWN)
{
if (!_hBrowseMenu)
_hBrowseMenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(IDR_BROWSE_CONTEXT_MENU));
hMenu = _hBrowseMenu;
}
// Check if we are in edit mode
else
{
olecmd.cmdID = IDM_EDITMODE;
hr = pOleCommandTarget->QueryStatus(&CGID_MSHTML, 1, &olecmd, NULL);
if (S_OK != hr)
goto Cleanup;
if (olecmd.cmdf == OLECMDSTATE_DOWN)
{
if (!_hEditMenu)
_hEditMenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(IDR_FORM_CONTEXT_MENU));
hMenu = _hEditMenu;
}
// Neither Browse nor Edit flags were set
else
{
ASSERT(false);
goto Cleanup;
}
}
if (!hMenu)
goto Cleanup;
//
// check through all the submenus and remove any sets of items which
// need to be removed
//
fDeletePrint = SHRestricted2(REST_NoPrinting, NULL, 0);
fDeleteSetDesktopItem = (WhichPlatform() != PLATFORM_INTEGRATED);
fDeleteViewSource = SHRestricted2(REST_NoViewSource, NULL, 0);
if (fDeletePrint || fDeleteSetDesktopItem || fDeleteViewSource)
{
int iSubMenuIndex;
for (iSubMenuIndex = 0; iSubMenuIndex < GetMenuItemCount(hMenu); iSubMenuIndex++)
{
HMENU hSubMenu = GetSubMenu(hMenu, iSubMenuIndex);
if (hSubMenu)
{
if (fDeletePrint)
{
DeleteMenu(hSubMenu, IDM_PRINT, MF_BYCOMMAND);
}
if (fDeleteSetDesktopItem)
{
DeleteMenu(hSubMenu, IDM_SETDESKTOPITEM, MF_BYCOMMAND);
}
if (fDeleteViewSource)
{
DeleteMenu(hSubMenu, IDM_VIEWSOURCE, MF_BYCOMMAND);
}
}
}
}
// Make sure we are running mshtml debug build if we are loading debug window
if (dwID == CONTEXT_MENU_DEBUG)
{
olecmd.cmdID = IDM_DEBUG_TRACETAGS;
hr = pOleCommandTarget->QueryStatus(&CGID_MSHTML, 1, &olecmd, NULL);
if (olecmd.cmdf != OLECMDSTATE_UP)
goto Cleanup;
}
// Select the appropriate submenu based on the passed in ID
hMenu = GetSubMenu(hMenu, dwID);
if (!hMenu)
goto Cleanup;
// Loop through and QueryStatus the menu items.
//
for (i = 0; i < GetMenuItemCount(hMenu); i++)
{
olecmd.cmdID = GetMenuItemID(hMenu, i);
if (olecmd.cmdID > 0)
{
pOleCommandTarget->QueryStatus(
&CGID_MSHTML,
1,
&olecmd,
NULL);
switch (olecmd.cmdf)
{
case OLECMDSTATE_UP:
case OLECMDSTATE_NINCHED:
mf = MF_BYCOMMAND | MF_ENABLED | MF_UNCHECKED;
break;
case OLECMDSTATE_DOWN:
mf = MF_BYCOMMAND | MF_ENABLED | MF_CHECKED;
break;
case OLECMDSTATE_DISABLED:
default:
mf = MF_BYCOMMAND | MF_DISABLED | MF_GRAYED;
break;
}
CheckMenuItem(hMenu, olecmd.cmdID, mf);
EnableMenuItem(hMenu, olecmd.cmdID, mf);
}
}
// Get the language submenu
hr = pOleCommandTarget->Exec(&CGID_ShellDocView, SHDVID_GETMIMECSETMENU, 0, NULL, &var);
if (S_OK != hr)
goto Cleanup;
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_SUBMENU;
mii.hSubMenu = (HMENU) var.byref;
SetMenuItemInfo(hMenu, IDM_LANGUAGE, FALSE, &mii);
// Insert Context Menu
V_VT(&var1) = VT_INT_PTR;
V_BYREF(&var1) = hMenu;
V_VT(&var2) = VT_I4;
V_I4(&var2) = dwID;
hr = pOleCommandTarget->Exec(&CGID_ShellDocView, SHDVID_ADDMENUEXTENSIONS, 0, &var1, &var2);
if (S_OK != hr)
goto Cleanup;
// Get the window also.
//
if (SUCCEEDED(pcmdtReserved->QueryInterface(IID_PPV_ARG(IOleWindow, &pOleWindow))))
{
pOleWindow->GetWindow(&hwnd);
}
if (hwnd)
{
GetInterfaceFromClientSite(pcmdtReserved, IID_PPV_ARG(IDocHostUIHandler, &pUIHandler));
if (pUIHandler)
pUIHandler->EnableModeless(FALSE);
GetInPlaceFrameFromUnknown(pcmdtReserved, &pOleInPlaceFrame);
if (pOleInPlaceFrame)
pOleInPlaceFrame->EnableModeless(FALSE);
hcursor = SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW)));
// Display the menu. Pass in the HWND of our site object.
//
iSelection = ::TrackPopupMenu(
hMenu,
TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
ppt->x + CX_CONTEXTMENUOFFSET,
ppt->y + CY_CONTEXTMENUOFFSET,
0,
hwnd,
(RECT*)NULL);
if (pUIHandler)
pUIHandler->EnableModeless(TRUE);
if (pOleInPlaceFrame)
pOleInPlaceFrame->EnableModeless(TRUE);
SetCursor(hcursor);
}
if (iSelection)
{
switch (iSelection)
{
case IDM_FOLLOWLINKN:
// tell the top level browser to save its window size to the registry so
// that our new window can pick it up and cascade properly
IUnknown_Exec(_punkSite, &CGID_Explorer, SBCMDID_SUGGESTSAVEWINPOS, 0, NULL, NULL);
// fall through
case IDM_PROPERTIES:
case IDM_FOLLOWLINKC:
pvar = &var;
V_VT(pvar) = VT_I4;
V_I4(pvar) = MAKELONG(ppt->x, ppt->y);
break;
}
pOleCommandTarget->Exec(&CGID_MSHTML, iSelection, 0, pvar, NULL);
}
{
MENUITEMINFO mii2 = {0};
mii2.cbSize = sizeof(mii);
mii2.fMask = MIIM_SUBMENU;
mii2.hSubMenu = NULL;
SetMenuItemInfo(hMenu, IDM_LANGUAGE, FALSE, &mii2);
}
Cleanup:
DestroyMenu(mii.hSubMenu);
ATOMICRELEASE(pOleCommandTarget);
ATOMICRELEASE(pOleWindow);
ATOMICRELEASE(pOleInPlaceFrame);
ATOMICRELEASE(pUIHandler);
return hr;
}
HRESULT CDocHostUIHandler::GetHostInfo(DOCHOSTUIINFO *pInfo)
{
DWORD dwUrlEncodingDisableUTF8;
DWORD dwSize = SIZEOF(dwUrlEncodingDisableUTF8);
BOOL fDefault = FALSE;
DWORD dwLoadf = 0;
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::GetHostInfo called");
pInfo->cbSize = sizeof(DOCHOSTUIINFO);
pInfo->dwFlags = DOCHOSTUIFLAG_BROWSER | DOCHOSTUIFLAG_ENABLE_INPLACE_NAVIGATION | DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION;
pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT; // default
SHRegGetUSValue(REGSTR_PATH_INTERNET_SETTINGS,
TEXT("UrlEncoding"), NULL, (LPBYTE) &dwUrlEncodingDisableUTF8, &dwSize, FALSE, (LPVOID) &fDefault, SIZEOF(fDefault));
if (dwUrlEncodingDisableUTF8)
pInfo->dwFlags |= DOCHOSTUIFLAG_URL_ENCODING_DISABLE_UTF8;
else
pInfo->dwFlags |= DOCHOSTUIFLAG_URL_ENCODING_ENABLE_UTF8;
return S_OK;
}
HRESULT CDocHostUIHandler::ShowUI(
DWORD dwID, IOleInPlaceActiveObject *pActiveObject,
IOleCommandTarget *pCommandTarget, IOleInPlaceFrame *pFrame,
IOleInPlaceUIWindow *pDoc)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::ShowUI called");
// Host did not display its own UI. Trident will proceed to display its own.
return S_FALSE;
}
HRESULT CDocHostUIHandler::HideUI(void)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::HideUI called");
// This one is paired with ShowUI
return S_FALSE;
}
HRESULT CDocHostUIHandler::UpdateUI(void)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::UpdateUI called");
// LATER: Isn't this equivalent to OLECMDID_UPDATECOMMANDS?
return S_FALSE;
}
HRESULT CDocHostUIHandler::EnableModeless(BOOL fEnable)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::EnableModeless called");
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocHostUIHandler::OnDocWindowActivate(BOOL fActivate)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocHostUIHandler::OnFrameWindowActivate(BOOL fActivate)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocHostUIHandler::ResizeBorder(
LPCRECT prcBorder, IOleInPlaceUIWindow *pUIWindow, BOOL fRameWindow)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_OK;
}
HRESULT CDocHostUIHandler::TranslateAccelerator(
LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID)
{
// Called from the Trident when the equivalent member of its
// IOleInPlaceActiveObject is called by the frame. We don't care
// those cases.
return S_FALSE; // The message was not translated
}
HRESULT CDocHostUIHandler::GetOptionKeyPath(BSTR *pbstrKey, DWORD dw)
{
// Trident will default to its own user options.
if (!pbstrKey)
return E_POINTER;
*pbstrKey = NULL;
return S_FALSE;
}
HRESULT CDocHostUIHandler::GetDropTarget(IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::GetDropTarget called");
return E_NOTIMPL;
}
HRESULT CDocHostUIHandler::GetAltExternal(IDispatch **ppDisp)
{
HRESULT hr = E_FAIL;
IDocHostUIHandler *pDocHostUIHandler;
IOleObject *pOleObject;
IOleClientSite *pOleClientSite;
*ppDisp = NULL;
// * QI ourselves for a service provider
// * QS for the top level browser's service provider
// * Ask for an IOleObject
// * Ask the IOleObject for an IOleClientSite
// * QI the IOleClientSite for an IDocHostUIHandler
// * Call GetExternal on the IDocHostUIHandler to get the IDispatch
if (SUCCEEDED(IUnknown_QueryServiceForWebBrowserApp(_punkSite, IID_PPV_ARG(IOleObject, &pOleObject))))
{
if (SUCCEEDED(pOleObject->GetClientSite(&pOleClientSite)))
{
if (SUCCEEDED(pOleClientSite->QueryInterface(IID_PPV_ARG(IDocHostUIHandler, &pDocHostUIHandler))))
{
hr = pDocHostUIHandler->GetExternal(ppDisp);
pDocHostUIHandler->Release();
}
pOleClientSite->Release();
}
pOleObject->Release();
}
return hr;
}
HRESULT CDocHostUIHandler::GetExternal(IDispatch **ppDisp)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::GetExternal called");
HRESULT hr = S_OK;
if (!ppDisp)
{
hr = E_INVALIDARG;
goto Cleanup;
}
if (_pExternal)
{
*ppDisp = _pExternal;
(*ppDisp)->AddRef();
goto Cleanup;
}
IDispatch *psuihDisp;
IDispatch *pAltExternalDisp;
*ppDisp = NULL;
GetAltExternal(&pAltExternalDisp);
hr = CShellUIHelper_CreateInstance2((IUnknown **)&psuihDisp, IID_IDispatch, _punkSite, pAltExternalDisp);
if (SUCCEEDED(hr))
{
*ppDisp = psuihDisp;
_pExternal = *ppDisp;
if (pAltExternalDisp)
{
// Don't hold a ref - the ShellUIHelper will do it
pAltExternalDisp->Release();
}
}
else if (pAltExternalDisp)
{
// Couldn't create a ShellUIHelper but we got our host's
// external.
*ppDisp = pAltExternalDisp;
_pExternal = *ppDisp;
}
Cleanup:
ASSERT((SUCCEEDED(hr) && (*ppDisp)) || (FAILED(hr)));
return hr;
}
HRESULT CDocHostUIHandler::TranslateUrl(DWORD dwTranslate, OLECHAR *pchURLIn, OLECHAR **ppchURLOut)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::TranslateUrl called");
return S_FALSE;
}
HRESULT CDocHostUIHandler::FilterDataObject(IDataObject *pDO, IDataObject **ppDORet)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::FilterDataObject called");
return S_FALSE;
}
HRESULT CDocHostUIHandler::GetOverrideKeyPath(LPOLESTR *pchKey, DWORD dw)
{
TraceMsg(DM_DOCHOSTUIHANDLER, "CDOH::GetOverrideKeyPath called");
return S_FALSE;
}
STDAPI CDocHostUIHandler_CreateInstance(IUnknown * punkOuter, IUnknown ** ppunk, LPCOBJECTINFO poi)
{
HRESULT hres = E_OUTOFMEMORY;
CDocHostUIHandler *pis = new CDocHostUIHandler;
if (pis)
{
*ppunk = SAFECAST(pis, IDocHostUIHandler *);
hres = S_OK;
}
return hres;
}
//==========================================================================
// IOleCommandTarget implementation
//==========================================================================
HRESULT CDocHostUIHandler::QueryStatus(const GUID *pguidCmdGroup,
ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
{
HRESULT hres = OLECMDERR_E_UNKNOWNGROUP;
if (IsEqualGUID(CGID_DocHostCommandHandler, *pguidCmdGroup))
{
ULONG i;
if (rgCmds == NULL)
return E_INVALIDARG;
for (i = 0 ; i < cCmds ; i++)
{
// ONLY say that we support the stuff we support in ::Exec
switch (rgCmds[i].cmdID)
{
case OLECMDID_SHOWSCRIPTERROR:
case OLECMDID_SHOWMESSAGE:
case OLECMDID_SHOWFIND:
case OLECMDID_SHOWPAGESETUP:
case OLECMDID_SHOWPRINT:
case OLECMDID_PRINTPREVIEW:
case OLECMDID_PRINT:
case OLECMDID_PROPERTIES:
case SHDVID_CLSIDTOMONIKER:
rgCmds[i].cmdf = OLECMDF_ENABLED;
break;
default:
rgCmds[i].cmdf = 0;
break;
}
}
hres = S_OK;
}
return hres;
}
HRESULT CDocHostUIHandler::Exec(const GUID *pguidCmdGroup,
DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
if (IsEqualGUID(CGID_DocHostCommandHandler, *pguidCmdGroup))
{
switch (nCmdID)
{
case OLECMDID_SHOWSCRIPTERROR:
if (!pvarargIn || !pvarargOut)
return E_INVALIDARG;
ShowErrorDialog(pvarargIn, pvarargOut, nCmdexecopt);
return S_OK;
case OLECMDID_SHOWMESSAGE:
if (!pvarargIn || !pvarargOut)
return E_INVALIDARG;
else
return ShowMessage(pvarargIn, pvarargOut, nCmdexecopt);
case OLECMDID_SHOWFIND:
if (!pvarargIn)
return E_INVALIDARG;
ShowFindDialog(pvarargIn, pvarargOut, nCmdexecopt);
return S_OK;
case OLECMDID_SHOWPAGESETUP:
if (!pvarargIn)
return E_INVALIDARG;
else
return ShowPageSetupDialog(pvarargIn, pvarargOut, nCmdexecopt);
case IDM_TEMPLATE_PAGESETUP:
return DoTemplatePageSetup(pvarargIn);
case OLECMDID_SHOWPRINT:
if (!pvarargIn)
return E_INVALIDARG;
else
return ShowPrintDialog(pvarargIn, pvarargOut, nCmdexecopt);
case OLECMDID_PRINTPREVIEW:
if (!pvarargIn)
return E_INVALIDARG;
else
return DoTemplatePrinting(pvarargIn, pvarargOut, TRUE);
case OLECMDID_PRINT:
if (!pvarargIn)
return E_INVALIDARG;
else
return DoTemplatePrinting(pvarargIn, pvarargOut, FALSE);
case OLECMDID_REFRESH:
//if print preview is up, tell them we handled refresh
//to prevent Trident from refreshing.
if (m_cPreviewIsUp > 0)
return S_OK;
// else do default handling
break;
case OLECMDID_PROPERTIES:
if (!pvarargIn)
return E_INVALIDARG;
else
return ShowPropertysheetDialog(pvarargIn, pvarargOut, nCmdexecopt);
case SHDVID_CLSIDTOMONIKER:
if (!pvarargIn || !pvarargOut)
return E_INVALIDARG;
else
return ClsidToMoniker(pvarargIn, pvarargOut);
default:
return OLECMDERR_E_NOTSUPPORTED;
}
}
return OLECMDERR_E_UNKNOWNGROUP;
}
//+---------------------------------------------------------------------------
//
// Helper for OLECMDID_SHOWSCRIPTERROR
//
//+---------------------------------------------------------------------------
void CDocHostUIHandler::ShowErrorDialog(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, DWORD)
{
HRESULT hr;
HWND hwnd;
IHTMLEventObj * pEventObj = NULL;
IMoniker * pmk = NULL;
VARIANT varEventObj;
TCHAR szResURL[MAX_URL_STRING];
ASSERT(V_VT(pvarargIn) == VT_UNKNOWN);
hr = GetHwndFromUnknown(V_UNKNOWN(pvarargIn), &hwnd);
if (S_OK != hr)
goto Cleanup;
hr = GetEventFromUnknown(V_UNKNOWN(pvarargIn), &pEventObj);
if (S_OK != hr)
goto Cleanup;
hr = MLBuildResURLWrap(TEXT("shdoclc.dll"),
HINST_THISDLL,
ML_CROSSCODEPAGE,
TEXT("error.dlg"),
szResURL,
ARRAYSIZE(szResURL),
TEXT("shdocvw.dll"));
if (FAILED(hr))
{
goto Cleanup;
}
hr = CreateURLMoniker(NULL, szResURL, &pmk);
if (FAILED(hr))
goto Cleanup;
V_VT(&varEventObj) = VT_DISPATCH;
V_DISPATCH(&varEventObj) = pEventObj;
ShowHTMLDialog(hwnd, pmk, &varEventObj, NULL, pvarargOut);
Cleanup:
ATOMICRELEASE(pEventObj);
ATOMICRELEASE(pmk);
}
//+---------------------------------------------------------------------------
//
// Callback procedure for OLECMDID_SHOWMESSAGE dialog
//
//+---------------------------------------------------------------------------
struct MSGBOXCALLBACKINFO
{
DWORD dwHelpContext;
TCHAR * pstrHelpFile;
HWND hwnd;
};
static void CALLBACK
MessageBoxCallBack(HELPINFO *phi)
{
MSGBOXCALLBACKINFO *p = (MSGBOXCALLBACKINFO *)phi->dwContextId;
BOOL fRet;
fRet = WinHelp(
p->hwnd,
p->pstrHelpFile,
HELP_CONTEXT,
p->dwHelpContext);
THR(fRet ? S_OK : E_FAIL);
}
//+---------------------------------------------------------------------------
//
// Helper for OLECMDID_SHOWMESSAGE
//
//+---------------------------------------------------------------------------
HRESULT
CDocHostUIHandler::ShowMessage(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, DWORD)
{
// must match order of MessageEnum
static const SExpandoInfo s_aMessageExpandos[] =
{
{TEXT("messageText"), VT_BSTR},
{TEXT("messageCaption"), VT_BSTR},
{TEXT("messageStyle"), VT_UI4},
{TEXT("messageHelpFile"), VT_BSTR},
{TEXT("messageHelpContext"), VT_UI4}
};
HRESULT hr;
HWND hwnd = NULL;
MSGBOXCALLBACKINFO mcbi;
MSGBOXPARAMS mbp = {0};
LRESULT plResult = 0;
LPOLESTR lpstrText = NULL;
LPOLESTR lpstrCaption = NULL;
DWORD dwType = 0;
LPOLESTR lpstrHelpFile = NULL;
DWORD dwHelpContext = 0;
IHTMLEventObj * pEventObj = NULL;
const int cExpandos = ARRAYSIZE(s_aMessageExpandos);
DISPID aDispid[cExpandos];
VARIANT aVariant[cExpandos];
int i;
ULONG_PTR uCookie = 0;
ASSERT(pvarargIn && pvarargOut);
for (i=0; i<cExpandos; i++)
VariantInit(aVariant + i);
ASSERT(V_VT(pvarargIn) == VT_UNKNOWN);
if ((V_VT(pvarargIn) != VT_UNKNOWN) || !V_UNKNOWN(pvarargIn))
{
hr = E_INVALIDARG;
goto Cleanup;
}
GetHwndFromUnknown(V_UNKNOWN(pvarargIn), &hwnd); // hwnd can be NULL
hr = GetEventFromUnknown(V_UNKNOWN(pvarargIn), &pEventObj);
if (S_OK != hr)
goto Cleanup;
// Get parameters from event object
hr = GetParamsFromEvent(
pEventObj,
cExpandos,
aDispid,
aVariant,
s_aMessageExpandos);
if (S_OK != hr)
goto Cleanup;
// Copy values from variants
lpstrText = V_BSTR(&aVariant[MessageText]);
lpstrCaption = V_BSTR(&aVariant[MessageCaption]);
dwType = V_UI4(&aVariant[MessageStyle]);
lpstrHelpFile = V_BSTR(&aVariant[MessageHelpFile]);
dwHelpContext = V_UI4(&aVariant[MessageHelpContext]);
// Set message box callback info
mcbi.dwHelpContext = dwHelpContext;
mcbi.pstrHelpFile = lpstrHelpFile;
mcbi.hwnd = hwnd;
// Set message box params
mbp.cbSize = sizeof(mbp);
mbp.hwndOwner = hwnd; // It is okay if this is NULL
mbp.hInstance = MLGetHinst();
mbp.lpszText = lpstrText;
mbp.lpszCaption = lpstrCaption;
mbp.dwContextHelpId = (DWORD_PTR) &mcbi;
mbp.lpfnMsgBoxCallback = MessageBoxCallBack;
// mbp.dwLanguageID = ?
mbp.dwStyle = dwType;
if (dwHelpContext && lpstrHelpFile)
mbp.dwStyle |= MB_HELP;
if (mbp.hwndOwner == NULL)
mbp.dwStyle |= MB_TASKMODAL;
SHActivateContext(&uCookie);
plResult = MessageBoxIndirect(&mbp);
if (uCookie)
{
SHDeactivateContext(uCookie);
}
Cleanup:
V_VT(pvarargOut) = VT_I4;
V_I4(pvarargOut) = (LONG)plResult;
for (i=0; i<cExpandos; i++)
VariantClear(&aVariant[i]);
ATOMICRELEASE(pEventObj);
return hr;
}
BOOL CDocHostUIHandler::IsFindDialogUp(IWebBrowser2* pwb, IHTMLWindow2** ppWindow)
{
BOOL fRet = FALSE;
BSTR bstrName = SysAllocString(STR_FIND_DIALOG_NAME);
if (bstrName)
{
VARIANT var = {0};
pwb->GetProperty(bstrName, &var);
if ( (var.vt == VT_DISPATCH) && (var.pdispVal != NULL) )
{
if (ppWindow)
{
*ppWindow = (IHTMLWindow2*)var.pdispVal;
(*ppWindow)->AddRef();
}
fRet = TRUE;
}
VariantClear(&var);
SysFreeString(bstrName);
}
if (!fRet && ppWindow)
*ppWindow = NULL;
return fRet;
}
HRESULT SetFindDialogProperty(IWebBrowser2* pwb, VARIANT* pvar)
{
HRESULT hr;
BSTR bstrName = SysAllocString(STR_FIND_DIALOG_NAME);
if (bstrName)
{
hr = pwb->PutProperty(bstrName, *pvar);
SysFreeString(bstrName);
}
else
hr = E_OUTOFMEMORY;
return hr;
}
//if this fails, then we have no choice but to orphan the dialog
HRESULT SetFindDialogUp(IWebBrowser2* pwb, IHTMLWindow2* pWindow)
{
VARIANT var;
var.vt = VT_DISPATCH;
var.pdispVal = pWindow;
return SetFindDialogProperty(pwb, &var);
}
void ReleaseFindDialog(IWebBrowser2* pwb)
{
VARIANT var = {0};
SetFindDialogProperty(pwb, &var);
}
//+---------------------------------------------------------------------------
//
// Helper for OLECMDID_SHOWFIND
//
// pvarargIn - IDispatch Interface
// dwflags - bidi flag
//+---------------------------------------------------------------------------
void
CDocHostUIHandler::ShowFindDialog(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, DWORD dwflags)
{
IDispatch * pDispatch = NULL;
IHTMLOptionsHolder * pHTMLOptionsHolder = NULL;
IHTMLDocument2 * pHTMLDocument2 = NULL;
IHTMLWindow2 * pHTMLWindow2 = NULL;
IOleInPlaceFrame * pOleInPlaceFrame = NULL;
HWND hwnd = NULL;
IMoniker * pmk = NULL;
if (EVAL(V_VT(pvarargIn) == VT_DISPATCH))
{
pDispatch = V_DISPATCH(pvarargIn);
if (SUCCEEDED(pDispatch->QueryInterface(IID_PPV_ARG(IHTMLOptionsHolder, &pHTMLOptionsHolder))))
{
if (SUCCEEDED(pHTMLOptionsHolder->get_document(&pHTMLDocument2)) && pHTMLDocument2)
{
if (SUCCEEDED(pHTMLDocument2->get_parentWindow(&pHTMLWindow2)))
{
if (SUCCEEDED(GetInPlaceFrameFromUnknown(pHTMLDocument2, &pOleInPlaceFrame)))
{
if (SUCCEEDED(pOleInPlaceFrame->GetWindow(&hwnd)))
{
BOOL fInBrowser = FALSE;
IWebBrowser2 * pwb2 = NULL;
if (SUCCEEDED(IUnknown_QueryServiceForWebBrowserApp(_punkSite, IID_PPV_ARG(IWebBrowser2, &pwb2))))
{
fInBrowser = TRUE;
}
TCHAR szResURL[MAX_URL_STRING];
if (SUCCEEDED(MLBuildResURLWrap(TEXT("shdoclc.dll"),
HINST_THISDLL,
ML_CROSSCODEPAGE,
(dwflags ? TEXT("bidifind.dlg") : TEXT("find.dlg")),
szResURL,
ARRAYSIZE(szResURL),
TEXT("shdocvw.dll"))))
{
CreateURLMoniker(NULL, szResURL, &pmk);
if (fInBrowser)
{
IHTMLWindow2 *pWinOut;
if (!IsFindDialogUp(pwb2, &pWinOut))
{
ASSERT(NULL==pWinOut);
if ((NULL != pvarargIn) &&
(VT_DISPATCH == pvarargIn->vt) &&
(NULL != pvarargIn->pdispVal))
{
BSTR bstrFindText = GetFindText(pwb2);
if (bstrFindText)
{
// paranoia since we hang on to this object
// a while and there is always potential
// for mess ups below where we mean to
// release it.
ATOMICRELEASE(_pOptionsHolder);
pvarargIn->pdispVal->QueryInterface(
IID_PPV_ARG(IHTMLOptionsHolder,
&_pOptionsHolder));
if (_pOptionsHolder)
_pOptionsHolder->put_findText(bstrFindText);
SysFreeString(bstrFindText);
}
}
ShowModelessHTMLDialog(hwnd, pmk, pvarargIn, NULL, &pWinOut);
if (pWinOut)
{
//can't really handle failure here, because the dialog is already up.
BSTR bstrOnunload = SysAllocString(L"onunload");
if (bstrOnunload)
{
IHTMLWindow3 * pWin3;
if (SUCCEEDED(pWinOut->QueryInterface(IID_PPV_ARG(IHTMLWindow3, &pWin3))))
{
VARIANT_BOOL varBool;
if (SUCCEEDED(pWin3->attachEvent(bstrOnunload, (IDispatch*)this, &varBool)))
{
// on SetFindDialogUp success, the property holds the ref on pWinOut
if (FAILED(SetFindDialogUp(pwb2, pWinOut)))
{
// No way to handle the event, so detach
pWin3->detachEvent(bstrOnunload, (IDispatch*)this);
}
}
pWin3->Release();
}
SysFreeString(bstrOnunload);
}
// REVIEW: the old code leaked this ref if the property
// wasn't attached in SetFindDialogUp...
pWinOut->Release();
}
}
else
{
//since the find dialog is already up, send focus to it
pWinOut->focus();
pWinOut->Release();
}
}
else
{
//we're not in the browser, so just show it modal
ShowHTMLDialog(hwnd, pmk, pvarargIn, NULL, NULL);
}
if (pmk)
pmk->Release();
}
ATOMICRELEASE(pwb2);
}
pOleInPlaceFrame->Release();
}
pHTMLWindow2->Release();
}
pHTMLDocument2->Release();
}
pHTMLOptionsHolder->Release();
}
}
//pWinOut gets released in CDocHostUIHandler::Invoke() or CIEFrameAuto::COmWindow::ViewReleased(),
// in response to the onunload event.
if (pvarargOut)
VariantInit(pvarargOut);
}
//+---------------------------------------------------------------------------
//
// Callback procedure for OLECMDID_SHOWPAGESETUP dialog
//
//+---------------------------------------------------------------------------
struct PAGESETUPBOXCALLBACKINFO
{
TCHAR strHeader[1024];
TCHAR strFooter[1024];
};
UINT_PTR APIENTRY
PageSetupHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
HKEY keyPageSetup = NULL;
switch (uiMsg)
{
case WM_INITDIALOG:
PAGESETUPBOXCALLBACKINFO * ppscbi;
ppscbi = (PAGESETUPBOXCALLBACKINFO *) ((PAGESETUPDLG*)lParam)->lCustData;
SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR)ppscbi);
SendDlgItemMessage(hdlg,IDC_EDITHEADER, EM_LIMITTEXT, ARRAYSIZE(ppscbi->strHeader)-1, 0L);
SendDlgItemMessage(hdlg,IDC_EDITFOOTER, EM_LIMITTEXT, ARRAYSIZE(ppscbi->strFooter)-1, 0L);
SetDlgItemText(hdlg,IDC_EDITHEADER, ppscbi->strHeader);
SetDlgItemText(hdlg,IDC_EDITFOOTER, ppscbi->strFooter);
return TRUE;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDOK:
{
PAGESETUPBOXCALLBACKINFO * ppscbi;
ppscbi = (PAGESETUPBOXCALLBACKINFO *) GetWindowLongPtr(hdlg, DWLP_USER);
if (ppscbi)
{
GetDlgItemText(hdlg,IDC_EDITHEADER, ppscbi->strHeader, ARRAYSIZE(ppscbi->strHeader));
GetDlgItemText(hdlg,IDC_EDITFOOTER, ppscbi->strFooter, ARRAYSIZE(ppscbi->strFooter));
}
}
}
break;
case WM_HELP:
{
LPHELPINFO pHI = (LPHELPINFO)lParam;
if (pHI->iContextType == HELPINFO_WINDOW) // must be for a control
{
WinHelp(
(HWND)pHI->hItemHandle,
GetHelpFile(pHI->iCtrlId, (DWORD *)aPageSetupDialogHelpIDs),
HELP_WM_HELP,
(DWORD_PTR)(LPVOID) aPageSetupDialogHelpIDs);
}
break;
//return TRUE;
}
case WM_CONTEXTMENU:
{
int CtrlID = GetControlID((HWND)wParam, lParam);
WinHelp(
(HWND)wParam,
GetHelpFile(CtrlID, (DWORD *)aPageSetupDialogHelpIDs),
HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID) aPageSetupDialogHelpIDs);
break;
}
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Helper for OLECMDID_SHOWPAGESETUP
//
// pvarargIn - holds IHTMLEventObj * for the event
//
// Returns S_FALSE if the user clicked Cancel and S_TRUE if the user
// clicked OK.
//+---------------------------------------------------------------------------
HRESULT
CDocHostUIHandler::ShowPageSetupDialog(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, DWORD)
{
// must match order of PagesetupEnum
static const SExpandoInfo s_aPagesetupExpandos[] =
{
{OLESTR("pagesetupHeader"), VT_BSTR},
{OLESTR("pagesetupFooter"), VT_BSTR},
{OLESTR("pagesetupStruct"), VT_PTR}
};
HRESULT hr = E_FAIL;
PAGESETUPDLG * ppagesetupdlg = NULL;
PAGESETUPBOXCALLBACKINFO pagesetupcbi;
IHTMLEventObj * pEventObj = NULL;
const int cExpandos = ARRAYSIZE(s_aPagesetupExpandos);
DISPID aDispid[cExpandos];
VARIANT aVariant[cExpandos];
int i;
ULONG_PTR uCookie = 0;
for (i=0; i<cExpandos; i++)
VariantInit(aVariant+i);
ASSERT(pvarargIn && (V_VT(pvarargIn) == VT_UNKNOWN));
if ((V_VT(pvarargIn) != VT_UNKNOWN) || !V_UNKNOWN(pvarargIn))
goto Cleanup;
if (V_UNKNOWN(pvarargIn)->QueryInterface(IID_PPV_ARG(IHTMLEventObj, &pEventObj)))
goto Cleanup;
// Get parameters from event object
if (GetParamsFromEvent(
pEventObj,
cExpandos,
aDispid,
aVariant,
s_aPagesetupExpandos))
goto Cleanup;
// Copy values from variants
StrCpyN(pagesetupcbi.strHeader,
V_BSTR(&aVariant[PagesetupHeader]) ? V_BSTR(&aVariant[PagesetupHeader]) : TEXT(""),
ARRAYSIZE(pagesetupcbi.strHeader));
StrCpyN(pagesetupcbi.strFooter,
V_BSTR(&aVariant[PagesetupFooter]) ? V_BSTR(&aVariant[PagesetupFooter]) : TEXT(""),
ARRAYSIZE(pagesetupcbi.strHeader));
ppagesetupdlg = (PAGESETUPDLG *)V_BYREF(&aVariant[PagesetupStruct]);
if (!ppagesetupdlg)
goto Cleanup;
// Set up custom dialog resource fields in pagesetupdlg
ppagesetupdlg->Flags |= PSD_ENABLEPAGESETUPHOOK | PSD_ENABLEPAGESETUPTEMPLATE;
ppagesetupdlg->lCustData = (LPARAM) &pagesetupcbi;
ppagesetupdlg->lpfnPageSetupHook = PageSetupHookProc;
ppagesetupdlg->hInstance = MLLoadShellLangResources();
ppagesetupdlg->lpPageSetupTemplateName = MAKEINTRESOURCE(PAGESETUPDLGORD);
// Show dialog
SHActivateContext(&uCookie);
if (!PageSetupDlg(ppagesetupdlg))
{
// treat failure as canceling
hr = S_FALSE;
goto Cleanup;
}
hr = S_OK;
// Save header/footer in event object
VARIANT var;
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(pagesetupcbi.strHeader ? pagesetupcbi.strHeader : TEXT(""));
if (NULL != V_BSTR(&var))
{
PutParamToEvent(aDispid[PagesetupHeader], &var, pEventObj);
VariantClear(&var);
}
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(pagesetupcbi.strFooter ? pagesetupcbi.strFooter : TEXT(""));
if (NULL != V_BSTR(&var))
{
PutParamToEvent(aDispid[PagesetupFooter], &var, pEventObj);
VariantClear(&var);
}
Cleanup:
if (ppagesetupdlg)
MLFreeLibrary(ppagesetupdlg->hInstance);
if (uCookie)
{
SHDeactivateContext(uCookie);
}
for (i=0; i<cExpandos; i++)
VariantClear(&aVariant[i]);
if (pvarargOut)
VariantInit(pvarargOut);
ATOMICRELEASE(pEventObj);
return hr;
}
//+---------------------------------------------------------------------------
//
// Callback procedure for OLECMDID_SHOWPRINT dialog
//
//+---------------------------------------------------------------------------
static void SetPreviewBitmap(long bitmapID, HWND hdlg);
HRESULT GetPrintFileName(HWND hwnd, TCHAR achFilePath[], int cchFilePath);
struct PRINTBOXCALLBACKINFO
{
BOOL fRootDocumentHasFrameset;
BOOL fAreRatingsEnabled;
BOOL fPrintActiveFrameEnabled;
BOOL fPrintActiveFrame;
BOOL fPrintLinked;
BOOL fPrintSelection;
BOOL fPrintAsShown;
BOOL fShortcutTable;
int iFontScaling;
IOleCommandTarget * pBodyActive;
};
// Common handling functions for both NT 5 and legacy print dialogs
void OnInitDialog( HWND hdlg, PRINTBOXCALLBACKINFO * ppcbi )
{
if (ppcbi)
{
// Three scenarioes:
// 1. Base case: Not FRAMESET, no IFRAMES. No frameoptions should be available.
// 2. FRAMESET: Obey all frameoptions. Any may be available.
// 3. IFRAME: May have selected frame available. If so, make selecetd frame & as laid out avail.
// Should the active frame be disabled?
if (!ppcbi->fPrintActiveFrameEnabled)
{
// Disable "print selected frame" radiobutton.
HWND hwndPrintActiveFrame = GetDlgItem(hdlg, rad5);
EnableWindow(hwndPrintActiveFrame, FALSE);
}
// If there is no frameset, disable "print all frames" radiobutton.
if (!ppcbi->fRootDocumentHasFrameset)
{
HWND hwndPrintAllFrames = GetDlgItem(hdlg, rad6);
EnableWindow(hwndPrintAllFrames, FALSE);
if (!ppcbi->fPrintActiveFrameEnabled)
{
// We're not a FRAMESET and don't have IFRAMEs
// Disable "print as laid out on screen" radiobutton.
HWND hwndPrintAsLaidOutOnScreen = GetDlgItem(hdlg, rad4);
EnableWindow(hwndPrintAsLaidOutOnScreen, FALSE);
SetPreviewBitmap(IDR_PRINT_PREVIEWDISABLED, hdlg);
}
}
// Setup default radio button to be checked.
// NOTE: We currently allow the template to check options that are disabled.
if (ppcbi->fPrintActiveFrame)
{
// Check "print selected frame" radiobutton.
CheckRadioButton(hdlg, rad4, rad6, rad5);
SetPreviewBitmap(IDR_PRINT_PREVIEWONEDOC, hdlg);
}
else if (ppcbi->fPrintAsShown)
{
// Check "print frames as laid out" radiobutton.
CheckRadioButton(hdlg, rad4, rad6, rad4);
SetPreviewBitmap(IDR_PRINT_PREVIEW, hdlg);
}
else
{
// Check "print all frames" radiobutton.
CheckRadioButton(hdlg, rad4, rad6, rad6);
SetPreviewBitmap(IDR_PRINT_PREVIEWALLDOCS, hdlg);
}
HWND hwndSelection = GetDlgItem(hdlg, rad2);
if (hwndSelection) EnableWindow(hwndSelection, (ppcbi->fPrintSelection));
#ifdef FONTSIZE_BOX
int i=0, cbLen=0;
//bugwin16: need to fix this.
for (i = 0; i < IDS_PRINT_FONTMAX; i++)
{
TCHAR achBuffer[128];
cbLen = MLLoadShellLangString(IDS_PRINT_FONTSCALE+i,achBuffer,127);
if (cbLen)
{
SendDlgItemMessage(hdlg, IDC_SCALING, CB_ADDSTRING, 0, (long) achBuffer);
}
}
if (i>0)
{
SendDlgItemMessage(hdlg, IDC_SCALING, CB_SETCURSEL, IDS_PRINT_FONTMAX - 1 - ppcbi->iFontScaling, 0);
}
#endif // FONTSIZE_BOX
// If ratings are enabled, don't allow recursive printing.
if (ppcbi->fAreRatingsEnabled)
{
HWND hwndPrintLinkedDocuments = GetDlgItem(hdlg, IDC_LINKED);
CheckDlgButton(hdlg, IDC_LINKED, BST_UNCHECKED);
EnableWindow(hwndPrintLinkedDocuments, FALSE);
}
}
}
void OnCommand( HWND hdlg, WPARAM wParam, LPARAM lParam )
{
PRINTBOXCALLBACKINFO * ppcbi;
ppcbi = (PRINTBOXCALLBACKINFO *)GetWindowLongPtr(hdlg, DWLP_USER);
if (!ppcbi)
{
return;
}
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case rad1: // "Print all"
case rad3: // "Print range"
case rad2: // "Print selection" (text selection)
{
// If we are printing a text selection, and we have a selected frame,
// force a print selected frame.
if (ppcbi && ppcbi->fPrintActiveFrame && ppcbi->fPrintSelection)
{
HWND hwndPrintWhatGroup = GetDlgItem(hdlg, grp3);
HWND hwndPrintActiveFrame = GetDlgItem(hdlg, rad5);
HWND hwndPrintAllFrames = GetDlgItem(hdlg, rad6);
HWND hwndPrintSelectedFrame = GetDlgItem(hdlg, rad4);
if (hwndPrintWhatGroup) EnableWindow(hwndPrintWhatGroup, LOWORD(wParam) != rad2);
if (hwndPrintActiveFrame) EnableWindow(hwndPrintActiveFrame, LOWORD(wParam) != rad2);
if (hwndPrintAllFrames) EnableWindow(hwndPrintAllFrames, ppcbi->fRootDocumentHasFrameset && LOWORD(wParam) != rad2);
if (hwndPrintSelectedFrame) EnableWindow(hwndPrintSelectedFrame, LOWORD(wParam) != rad2);
}
break;
}
case rad4:
if (HIWORD(wParam) == BN_CLICKED)
{
// now change the icon...
SetPreviewBitmap(IDR_PRINT_PREVIEW, hdlg);
HWND hwnd = GetDlgItem(hdlg, rad2);
if (hwnd) EnableWindow(hwnd, FALSE);
hwnd = GetDlgItem(hdlg, IDC_SHORTCUTS);
if (hwnd) EnableWindow(hwnd, FALSE);
hwnd = GetDlgItem(hdlg, IDC_LINKED);
if (hwnd) EnableWindow(hwnd, FALSE);
// if (ppcbi->pBodyActive);
// ppcbi->pBodyActive->Layout()->LockFocusRect(FALSE);
}
break;
case rad5:
if (HIWORD(wParam) == BN_CLICKED)
{
// now change the icon
SetPreviewBitmap(IDR_PRINT_PREVIEWONEDOC, hdlg);
HWND hwnd = GetDlgItem(hdlg, rad2);
if (hwnd) EnableWindow(hwnd, (ppcbi->fPrintSelection));
hwnd = GetDlgItem(hdlg, IDC_SHORTCUTS);
if (hwnd) EnableWindow(hwnd, TRUE);
hwnd = GetDlgItem(hdlg, IDC_LINKED);
if (hwnd) EnableWindow(hwnd, TRUE);
// if (ppcbi->pBodyActive);
// ppcbi->pBodyActive->Layout()->LockFocusRect(TRUE);
}
break;
case rad6:
if (HIWORD(wParam) == BN_CLICKED)
{
// now change the icon
SetPreviewBitmap(IDR_PRINT_PREVIEWALLDOCS, hdlg);
HWND hwnd = GetDlgItem(hdlg, rad2);
if (hwnd) EnableWindow(hwnd, FALSE);
hwnd = GetDlgItem(hdlg, IDC_SHORTCUTS);
if (hwnd) EnableWindow(hwnd, TRUE);
hwnd = GetDlgItem(hdlg, IDC_LINKED);
if (hwnd) EnableWindow(hwnd, TRUE);
// if (ppcbi->pBodyActive);
// ppcbi->pBodyActive->Layout()->LockFocusRect(FALSE);
}
break;
}
}
void OnHelp( HWND hdlg, WPARAM wParam, LPARAM lParam )
{
LPHELPINFO pHI = (LPHELPINFO)lParam;
if (pHI->iContextType == HELPINFO_WINDOW) // must be for a control
{
WinHelp(
(HWND)pHI->hItemHandle,
GetHelpFile(pHI->iCtrlId, (DWORD *) aPrintDialogHelpIDs),
HELP_WM_HELP,
(DWORD_PTR)(LPVOID) aPrintDialogHelpIDs);
}
}
void OnContextMenu( HWND hdlg, WPARAM wParam, LPARAM lParam )
{
int CtrlID = GetControlID((HWND)wParam, lParam);
WinHelp(
(HWND)wParam,
GetHelpFile(CtrlID, (DWORD *) aPrintDialogHelpIDs),
HELP_CONTEXTMENU,
(DWORD_PTR)(LPVOID) aPrintDialogHelpIDs);
}
void OnApplyOrOK( HWND hdlg, WPARAM wParam, LPARAM lParam )
{
PRINTBOXCALLBACKINFO * ppcbi = (PRINTBOXCALLBACKINFO *)GetWindowLongPtr(hdlg, DWLP_USER);
if (ppcbi)
{
ppcbi->fPrintLinked = IsDlgButtonChecked(hdlg, IDC_LINKED);
ppcbi->fPrintSelection = IsDlgButtonChecked(hdlg, rad2);
ppcbi->fPrintActiveFrame = IsDlgButtonChecked(hdlg, rad5) ||
( ppcbi->fPrintSelection &&
ppcbi->fRootDocumentHasFrameset
);
ppcbi->fPrintAsShown = IsDlgButtonChecked(hdlg, rad4) ||
( ppcbi->fPrintSelection &&
ppcbi->fRootDocumentHasFrameset
);
ppcbi->fShortcutTable = IsDlgButtonChecked(hdlg, IDC_SHORTCUTS);
#ifdef FONTSIZE_BOX
ppcbi->iFontScaling = IDS_PRINT_FONTMAX - 1 - SendDlgItemMessage( hdlg, IDC_SCALING, CB_GETCURSEL, 0,0 );
#endif
}
}
// This is the callback routine (and dlgproc) for the options
// page in the NT 5 print dialog.
INT_PTR APIENTRY
OptionsPageProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg)
{
case WM_INITDIALOG:
{
PRINTBOXCALLBACKINFO * ppcbi;
ppcbi = (PRINTBOXCALLBACKINFO *) ((PROPSHEETPAGE *)lParam)->lParam;
SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR)ppcbi);
OnInitDialog( hdlg, ppcbi );
break;
}
case WM_NOTIFY:
switch (((NMHDR FAR *)lParam)->code)
{
case PSN_APPLY:
OnApplyOrOK( hdlg, wParam, lParam );
SetWindowLongPtr (hdlg, DWLP_MSGRESULT, PSNRET_NOERROR);
return TRUE;
break;
case PSN_KILLACTIVE:
SetWindowLongPtr (hdlg, DWLP_MSGRESULT, FALSE);
return 1;
break;
case PSN_RESET:
SetWindowLongPtr (hdlg, DWLP_MSGRESULT, FALSE);
break;
}
break;
case WM_COMMAND:
OnCommand( hdlg, wParam, lParam );
break;
case WM_HELP:
OnHelp( hdlg, wParam, lParam );
break;
case WM_CONTEXTMENU:
OnContextMenu( hdlg, wParam, lParam );
break;
}
return FALSE;
}
UINT_PTR CALLBACK
PrintHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg)
{
case WM_INITDIALOG:
if (lParam)
{
PRINTBOXCALLBACKINFO * ppcbi;
ppcbi = (PRINTBOXCALLBACKINFO *) ((PRINTDLG*)lParam)->lCustData;
SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR)ppcbi);
OnInitDialog( hdlg, ppcbi );
}
return TRUE;
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDOK:
OnApplyOrOK( hdlg, wParam, lParam );
break;
default:
OnCommand( hdlg, wParam, lParam );
break;
}
}
break;
case WM_HELP:
OnHelp( hdlg, wParam, lParam );
break;
//return TRUE;
case WM_CONTEXTMENU:
OnContextMenu( hdlg, wParam, lParam );
break;
case WM_DESTROY:
{
PRINTBOXCALLBACKINFO * ppcbi = (PRINTBOXCALLBACKINFO *)GetWindowLongPtr(hdlg, DWLP_USER);
ASSERT(ppcbi);
break;
}
}
return FALSE;
}
void SetPreviewBitmap(long bitmapID, HWND hdlg)
{
// now change the icon...(note these bitmaps are not localized)
HBITMAP hNewBitmap = (HBITMAP) LoadImage(HINST_THISDLL, MAKEINTRESOURCE(bitmapID),
IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADMAP3DCOLORS );
if (hNewBitmap)
{
HBITMAP hOldBitmap = (HBITMAP) SendDlgItemMessage(hdlg, IDC_PREVIEW, STM_SETIMAGE,
(WPARAM) IMAGE_BITMAP, (LPARAM) hNewBitmap);
if (hOldBitmap)
{
//VERIFY(DeleteObject(hOldBitmap)!=0);
int i;
i = DeleteObject(hOldBitmap);
ASSERT(i!=0);
}
}
}
//+---------------------------------------------------------------------------
//
// Helper for OLECMDID_SHOWPRINT
//
//+---------------------------------------------------------------------------
HRESULT
CDocHostUIHandler::ShowPrintDialog(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, DWORD)
{
// the following must match the order of PrintEnum
static const SExpandoInfo s_aPrintExpandos[] =
{
{OLESTR("printfRootDocumentHasFrameset"), VT_BOOL},
{OLESTR("printfAreRatingsEnabled"), VT_BOOL},
{OLESTR("printfActiveFrame"), VT_BOOL},
{OLESTR("printfLinked"), VT_BOOL},
{OLESTR("printfSelection"), VT_BOOL},
{OLESTR("printfAsShown"), VT_BOOL},
{OLESTR("printfShortcutTable"), VT_BOOL},
{OLESTR("printiFontScaling"), VT_INT},
{OLESTR("printpBodyActiveTarget"), VT_UNKNOWN},
{OLESTR("printStruct"), VT_PTR},
{OLESTR("printToFileOk"), VT_BOOL},
{OLESTR("printToFileName"), VT_BSTR},
{OLESTR("printfActiveFrameEnabled"), VT_BOOL},
};
HRESULT hr = E_FAIL;
PRINTDLG * pprintdlg = NULL;
PRINTBOXCALLBACKINFO printcbi;
IHTMLEventObj * pEventObj = NULL;
const int cExpandos = ARRAYSIZE(s_aPrintExpandos);
DISPID aDispid[cExpandos];
VARIANT aVariant[cExpandos];
int i;
DWORD dwErr = 0;
printcbi.pBodyActive = NULL;
if (!V_UNKNOWN(pvarargIn))
goto Cleanup;
if (V_UNKNOWN(pvarargIn)->QueryInterface(IID_PPV_ARG(IHTMLEventObj, &pEventObj)))
goto Cleanup;
// Get parameters from event object
if (GetParamsFromEvent(
pEventObj,
cExpandos,
aDispid,
aVariant,
s_aPrintExpandos))
goto Cleanup;
// Copy values from variants
printcbi.fRootDocumentHasFrameset = V_BOOL(&aVariant[PrintfRootDocumentHasFrameset]);
printcbi.fAreRatingsEnabled = V_BOOL(&aVariant[PrintfAreRatingsEnabled]);
printcbi.fPrintActiveFrame = V_BOOL(&aVariant[PrintfPrintActiveFrame]);
printcbi.fPrintActiveFrameEnabled = V_BOOL(&aVariant[PrintfPrintActiveFrameEnabled]);
printcbi.fPrintLinked = V_BOOL(&aVariant[PrintfPrintLinked]);
printcbi.fPrintSelection = V_BOOL(&aVariant[PrintfPrintSelection]);
printcbi.fPrintAsShown = V_BOOL(&aVariant[PrintfPrintAsShown]);
printcbi.fShortcutTable = V_BOOL(&aVariant[PrintfShortcutTable]);
printcbi.iFontScaling = V_INT(&aVariant[PrintiFontScaling]);
// If we ever get LockFocusRect, use this field to access it
// peterlee 8/7/98
/*
if (V_UNKNOWN(&aVariant[PrintpBodyActiveTarget]))
{
if (V_UNKNOWN(&aVariant[PrintpBodyActiveTarget])->QueryInterface(IID_IOleCommandTarget,
(void**)&printcbi.pBodyActive))
goto Cleanup;
}
*/
pprintdlg = (PRINTDLG *)V_BYREF(&aVariant[PrintStruct]);
if (!pprintdlg)
goto Cleanup;
// Fix up requested page range so it's within bounds. The dialog will
// fail to initialize under W95 if this isn't done.
if ( pprintdlg->nFromPage < pprintdlg->nMinPage )
pprintdlg->nFromPage = pprintdlg->nMinPage;
else if ( pprintdlg->nFromPage > pprintdlg->nMaxPage )
pprintdlg->nFromPage = pprintdlg->nMaxPage;
if ( pprintdlg->nToPage < pprintdlg->nMinPage )
pprintdlg->nToPage = pprintdlg->nMinPage;
else if ( pprintdlg->nToPage > pprintdlg->nMaxPage )
pprintdlg->nToPage = pprintdlg->nMaxPage;
// Set up custom dialog resource fields in pagesetupdlg
pprintdlg->hInstance = MLLoadShellLangResources();
pprintdlg->lCustData = (LPARAM) &printcbi;
pprintdlg->lpfnPrintHook = PrintHookProc;
pprintdlg->lpPrintTemplateName = MAKEINTRESOURCE(PRINTDLGORD);
if (g_bRunOnNT5)
{
// We want to use the new PrintDlgEx in NT 5, so map all the PrintDlg
// settings to the new PrintDlgEx, get a pointer to the new function
// and then call it.
// Load the function from comdlg32 directly...
typedef HRESULT (*PFNPRINTDLGEX)(LPPRINTDLGEX pdex);
PFNPRINTDLGEX pfnPrintDlgEx = NULL;
HMODULE hComDlg32 = LoadLibrary(TEXT("comdlg32.dll"));
if (hComDlg32)
{
pfnPrintDlgEx = (PFNPRINTDLGEX)GetProcAddress(hComDlg32, "PrintDlgExW");
}
// Make sure we can call the function...
if (!pfnPrintDlgEx)
{
if (hComDlg32)
{
FreeLibrary(hComDlg32);
}
hr = E_FAIL;
goto Cleanup;
}
HPROPSHEETPAGE pages[1];
PRINTPAGERANGE ppr;
PRINTDLGEX pdex = {0};
// Copy over existing settings
pdex.lStructSize = sizeof(pdex);
pdex.hwndOwner = pprintdlg->hwndOwner;
pdex.hDevMode = pprintdlg->hDevMode;
pdex.hDevNames = pprintdlg->hDevNames;
pdex.hDC = pprintdlg->hDC;
pdex.Flags = pprintdlg->Flags;
pdex.nMinPage = pprintdlg->nMinPage;
pdex.nMaxPage = pprintdlg->nMaxPage;
pdex.nCopies = pprintdlg->nCopies;
// New settings
pdex.nStartPage = START_PAGE_GENERAL;
ppr.nFromPage = pprintdlg->nFromPage;
ppr.nToPage = pprintdlg->nToPage;
pdex.nPageRanges = 1;
pdex.nMaxPageRanges = 1;
pdex.lpPageRanges = &ppr;
// Create options page
PROPSHEETPAGE psp = {0};
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT;
psp.hInstance = pprintdlg->hInstance;
psp.pszTemplate = MAKEINTRESOURCE(IDD_PRINTOPTIONS);
psp.pfnDlgProc = OptionsPageProc;
psp.lParam = (LPARAM)&printcbi;
pages[0] = SHNoFusionCreatePropertySheetPageW(&psp);
if (pages[0])
{
pdex.nPropertyPages = 1;
pdex.lphPropertyPages = pages;
// Show the dialog
ULONG_PTR uCookie = 0;
SHActivateContext(&uCookie);
hr = pfnPrintDlgEx(&pdex);
if (uCookie)
{
SHDeactivateContext(uCookie);
}
if (SUCCEEDED(hr))
{
hr = S_FALSE;
if ((pdex.dwResultAction == PD_RESULT_PRINT) || (pdex.Flags & PD_RETURNDEFAULT))
{
// copy back values which might have changed
// during the call to PrintDlgEx
pprintdlg->Flags = pdex.Flags;
pprintdlg->hDevMode = pdex.hDevMode;
pprintdlg->hDevNames = pdex.hDevNames;
pprintdlg->nCopies = (WORD)pdex.nCopies;
pprintdlg->nFromPage = (WORD)ppr.nFromPage;
pprintdlg->nToPage = (WORD)ppr.nToPage;
if (pprintdlg->Flags & PD_RETURNDC)
{
pprintdlg->hDC = pdex.hDC;
}
hr = S_OK;
}
else if ((pdex.Flags & (PD_RETURNDC | PD_RETURNIC)) && pdex.hDC)
{
DeleteDC(pdex.hDC);
pdex.hDC = NULL;
}
}
else
{
hr = S_FALSE;
}
FreeLibrary(hComDlg32);
}
else
{
FreeLibrary(hComDlg32);
hr = E_OUTOFMEMORY;
goto Cleanup;
}
}
else
{
pprintdlg->Flags |= PD_ENABLEPRINTTEMPLATE | PD_ENABLEPRINTHOOK;
pprintdlg->Flags &= (~(PD_CURRENTPAGE | PD_NOCURRENTPAGE)); // Just in case, mask out the W2K only.
// Show dialog
if (!PrintDlg(pprintdlg))
{
// treat failure as canceling
dwErr = CommDlgExtendedError();
hr = S_FALSE;
goto Cleanup;
}
hr = S_OK;
}
// Write changed values to event object
VARIANT var;
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = printcbi.fPrintLinked ? VARIANT_TRUE : VARIANT_FALSE;
PutParamToEvent(aDispid[PrintfPrintLinked], &var, pEventObj);
V_BOOL(&var) = printcbi.fPrintActiveFrame ? VARIANT_TRUE : VARIANT_FALSE;
PutParamToEvent(aDispid[PrintfPrintActiveFrame], &var, pEventObj);
V_BOOL(&var) = printcbi.fPrintAsShown ? VARIANT_TRUE : VARIANT_FALSE;
PutParamToEvent(aDispid[PrintfPrintAsShown], &var, pEventObj);
V_BOOL(&var) = printcbi.fShortcutTable ? VARIANT_TRUE : VARIANT_FALSE;
PutParamToEvent(aDispid[PrintfShortcutTable], &var, pEventObj);
// now pop up the fileselection dialog and save the filename...
// this is the only place where we can make this modal
BOOL fPrintToFileOk;
fPrintToFileOk = FALSE;
if ((pprintdlg->Flags & PD_PRINTTOFILE) != 0)
{
// Get the save file path from the event object
TCHAR achPrintToFileName[MAX_PATH];
StrCpyN(achPrintToFileName,
V_BSTR(&aVariant[PrintToFileName]) ? V_BSTR(&aVariant[PrintToFileName]) : TEXT(""),
ARRAYSIZE(achPrintToFileName));
if (SUCCEEDED(GetPrintFileName(pprintdlg->hwndOwner, achPrintToFileName, ARRAYSIZE(achPrintToFileName))) &&
achPrintToFileName[0])
{
fPrintToFileOk = TRUE;
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(achPrintToFileName);
if (NULL != V_BSTR(&var))
{
PutParamToEvent(aDispid[PrintToFileName], &var, pEventObj);
VariantClear(&var);
}
}
}
V_VT(&var) = VT_BOOL;
V_BOOL(&var) = fPrintToFileOk ? VARIANT_TRUE : VARIANT_FALSE;
PutParamToEvent(aDispid[PrintToFileOk], &var, pEventObj);
Cleanup:
if (pprintdlg)
MLFreeLibrary(pprintdlg->hInstance);
for (i=0; i<cExpandos; i++)
VariantClear(&aVariant[i]);
if (pvarargOut)
VariantInit(pvarargOut);
ATOMICRELEASE(pEventObj);
ATOMICRELEASE(printcbi.pBodyActive);
return hr;
}
//+---------------------------------------------------------------------------
//
// Callback procedure for PrintToFile Dialog
//
//+---------------------------------------------------------------------------
UINT_PTR APIENTRY PrintToFileHookProc(HWND hdlg,
UINT uiMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uiMsg)
{
case WM_INITDIALOG:
{
int cbLen;
TCHAR achOK[MAX_PATH];
// change "save" to "ok"
cbLen = MLLoadShellLangString(IDS_PRINTTOFILE_OK,achOK,ARRAYSIZE(achOK));
if (cbLen < 1)
StrCpyN(achOK, TEXT("OK"), ARRAYSIZE(achOK));
// SetDlgItemText(hdlg, IDOK, _T("OK"));
SetDlgItemText(hdlg, IDOK, achOK);
// ...and, finally force us into foreground (needed for Win95, Bug : 13368)
::SetForegroundWindow(hdlg);
break;
}
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Member: GetPrintFileName
//
// Synopsis: Opens up the customized save file dialog and gets
// a filename for the printoutput
// Returns:
//
//----------------------------------------------------------------------------
HRESULT GetPrintFileName(HWND hwnd, TCHAR achFilePath[], int cchFilePath)
{
int cbLen;
TCHAR achTitlePrintInto[MAX_PATH];
TCHAR achFilePrintInto[MAX_PATH];
TCHAR achPath[MAX_PATH];
HRESULT hr = E_FAIL;
OPENFILENAME openfilename = {0};
openfilename.lStructSize = sizeof(openfilename);
openfilename.hwndOwner = hwnd;
cbLen = MLLoadShellLangString(IDS_PRINTTOFILE_TITLE,achTitlePrintInto,ARRAYSIZE(achTitlePrintInto));
ASSERT (cbLen && "could not load the resource");
if (cbLen > 0)
openfilename.lpstrTitle = achTitlePrintInto;
// guarantee trailing 0 to terminate the filter string
TCHAR achFilter[MAX_PATH] = {0};
cbLen = MLLoadShellLangString(IDS_PRINTTOFILE_SPEC,achFilter,ARRAYSIZE(achFilter)-2);
ASSERT (cbLen && "could not load the resource");
if (cbLen>0)
{
for (; cbLen >= 0; cbLen--)
{
if (achFilter[cbLen]== L',')
{
achFilter[cbLen] = 0;
}
}
}
openfilename.nMaxFileTitle = openfilename.lpstrTitle ? lstrlen(openfilename.lpstrTitle) : 0;
StrCpyN(achFilePrintInto, TEXT(""), ARRAYSIZE(achFilePrintInto));
openfilename.lpstrFile = achFilePrintInto;
openfilename.nMaxFile = ARRAYSIZE(achFilePrintInto);
openfilename.Flags = OFN_NOREADONLYRETURN | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT |
OFN_ENABLEHOOK | OFN_NOCHANGEDIR;
openfilename.lpfnHook = PrintToFileHookProc;
openfilename.lpstrFilter = achFilter;
openfilename.nFilterIndex = 1;
StrCpyN(achPath, achFilePath, ARRAYSIZE(achPath));
openfilename.lpstrInitialDir = *achPath ? achPath : NULL;
if (GetSaveFileName(&openfilename))
{
StrCpyN(achFilePath, openfilename.lpstrFile, cchFilePath);
hr = S_OK;
}
if (FAILED(hr))
*achFilePath = NULL;
return hr;
}
//+---------------------------------------------------------------------------
//
// Helpers for OLECMDID_PROPERTIES
//
//+---------------------------------------------------------------------------
HRESULT
CDocHostUIHandler::ShowPropertysheetDialog(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, DWORD)
{
// must match order of PropertysheetEnum
static const SExpandoInfo s_aPropertysheetExpandos[] =
{
{OLESTR("propertysheetPunks"), VT_SAFEARRAY}
};
HRESULT hr;
HWND hwnd = NULL;
HWND hwndParent;
IUnknown * punk = NULL;
OLECMD olecmd = {0, 0};
int cUnk = 0;
IUnknown * HUGEP * apUnk = NULL;
OCPFIPARAMS ocpfiparams = {0};
CAUUID ca = { 0, 0 };
RECT rc = {0, 0, 0, 0};
RECT rcDesktop = {0, 0, 0, 0};
SIZE pixelOffset;
SIZE metricOffset = {0, 0};
IHTMLEventObj * pEventObj = NULL;
const int cExpandos = ARRAYSIZE(s_aPropertysheetExpandos);
VARIANT aVariant[cExpandos];
DISPID aDispid[cExpandos];
SAFEARRAY * psafearray = NULL;
for (int i=0; i<cExpandos; i++)
VariantInit(&aVariant[i]);
ASSERT(pvarargIn && V_VT(pvarargIn) == VT_UNKNOWN && V_UNKNOWN(pvarargIn));
if (!pvarargIn || (V_VT(pvarargIn) != VT_UNKNOWN) || !V_UNKNOWN(pvarargIn))
{
hr = E_INVALIDARG;
goto Cleanup;
}
// get the hwnd
punk = V_UNKNOWN(pvarargIn);
hr = GetHwndFromUnknown(punk, &hwnd);
if (S_OK != hr)
goto Cleanup;
// get the SafeArray expando from the event obj
hr = GetEventFromUnknown(punk, &pEventObj);
if (S_OK != hr)
goto Cleanup;
hr = GetParamsFromEvent(
pEventObj,
cExpandos,
aDispid,
aVariant,
s_aPropertysheetExpandos);
if (S_OK != hr)
goto Cleanup;
psafearray = V_ARRAY(&aVariant[PropertysheetPunks]);
// verify array dimensions
if (SafeArrayGetDim(psafearray) != 1)
{
hr = E_INVALIDARG;
goto Cleanup;
}
// get array size, adding one to 0-based size
hr = SafeArrayGetUBound(psafearray, 1, (long*)&cUnk);
if (S_OK != hr)
goto Cleanup;
cUnk++;
if (cUnk)
{
// get pointer to vector
hr = SafeArrayAccessData(psafearray, (void HUGEP* FAR*)&apUnk);
if (S_OK != hr)
goto Cleanup;
}
else
{
cUnk = 1;
apUnk = &punk;
}
// Compute pages to load
hr = THR(GetCommonPages(cUnk, apUnk, &ca));
if (S_OK != hr)
goto Cleanup;
// compute top-level parent
while (hwndParent = GetParent(hwnd))
hwnd = hwndParent;
// The dialog box is not centered on screen
// the ocpfi seems to be ignoring the x, y values in ocpfiparams
// Compute offset to center of screen
GetWindowRect(GetDesktopWindow(), &rcDesktop);
GetWindowRect(hwnd, &rc);
pixelOffset.cx = (rcDesktop.right - rcDesktop.left)/2 - rc.left;
pixelOffset.cy = (rcDesktop.bottom - rcDesktop.top)/2 - rc.top;
AtlPixelToHiMetric(&pixelOffset, &metricOffset);
ocpfiparams.cbStructSize = sizeof(ocpfiparams);
ocpfiparams.hWndOwner = hwnd;
ocpfiparams.x = metricOffset.cx;
ocpfiparams.y = metricOffset.cy;
ocpfiparams.lpszCaption = NULL;
ocpfiparams.cObjects = cUnk;
ocpfiparams.lplpUnk = apUnk;
ocpfiparams.cPages = ca.cElems;
ocpfiparams.lpPages = ca.pElems;
ocpfiparams.lcid = GetUserDefaultLCID();
ocpfiparams.dispidInitialProperty = DISPID_UNKNOWN;
// OleCreatePropertyFrameIndirect throws its own dialog on error,
// so we don't want to display that twice
ULONG_PTR uCookie = 0;
SHActivateContext(&uCookie);
THR(OleCreatePropertyFrameIndirect(&ocpfiparams));
hr = S_OK;
Cleanup:
if (uCookie)
{
SHDeactivateContext(uCookie);
}
if (ca.cElems)
CoTaskMemFree(ca.pElems);
if (psafearray && apUnk)
SafeArrayUnaccessData(psafearray);
if (pvarargOut)
VariantInit(pvarargOut);
for (i=0; i<cExpandos; i++)
VariantClear(&aVariant[i]);
ATOMICRELEASE(pEventObj);
return hr;
}
HRESULT
CDocHostUIHandler::GetCommonPages(int cUnk, IUnknown **apUnk, CAUUID *pca)
{
HRESULT hr = E_INVALIDARG;
int i;
UINT iScan, iFill, iCompare;
BOOL fFirst = TRUE;
CAUUID caCurrent;
IUnknown * pUnk;
ISpecifyPropertyPages *pSPP;
pca->cElems = 0;
pca->pElems = NULL;
for (i = 0; i < cUnk; i++)
{
pUnk = apUnk[i];
ASSERT(pUnk);
hr = THR(pUnk->QueryInterface(IID_PPV_ARG(ISpecifyPropertyPages, &pSPP)));
if (S_OK != hr)
goto Cleanup;
hr = THR(pSPP->GetPages(fFirst ? pca : &caCurrent));
ATOMICRELEASE(pSPP);
if (S_OK != hr)
goto Cleanup;
if (fFirst)
{
continue;
}
// keep only the common pages
else
{
for (iScan = 0, iFill = 0; iScan < pca->cElems; iScan++)
{
for (iCompare = 0; iCompare < caCurrent.cElems; iCompare++)
{
if (caCurrent.pElems[iCompare] == pca->pElems[iScan])
break;
}
if (iCompare != caCurrent.cElems)
{
pca->pElems[iFill++] = pca->pElems[iScan];
}
}
pca->cElems = iFill;
CoTaskMemFree(caCurrent.pElems);
}
}
Cleanup:
return hr;
}
//+---------------------------------------------------------------------------
//
// Helper for SHDVID_CLSIDTOMONIKER
//
//+---------------------------------------------------------------------------
struct HTMLPAGECACHE
{
const CLSID * pclsid;
TCHAR * ach;
};
HRESULT CDocHostUIHandler::ClsidToMoniker(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
static const HTMLPAGECACHE s_ahtmlpagecache[] =
{
&CLSID_CAnchorBrowsePropertyPage, _T("anchrppg.ppg"),
&CLSID_CImageBrowsePropertyPage, _T("imageppg.ppg"),
&CLSID_CDocBrowsePropertyPage, _T("docppg.ppg"),
};
HRESULT hr = E_FAIL;
IMoniker * pmk = NULL;
IUnknown * pUnk = NULL;
int i;
const HTMLPAGECACHE * phtmlentry;
const CLSID * pclsid;
ASSERT(pvarargIn);
ASSERT(pvarargOut);
ASSERT(V_VT(pvarargIn) == VT_UINT_PTR && V_BYREF(pvarargIn));
if (!pvarargIn || V_VT(pvarargIn) != VT_UINT_PTR || !V_BYREF(pvarargIn))
goto Cleanup;
pclsid = (CLSID *)V_BYREF(pvarargIn);
if (!pvarargOut)
goto Cleanup;
VariantInit(pvarargOut);
// lookup the resource from the CLSID
for (i = ARRAYSIZE(s_ahtmlpagecache) - 1, phtmlentry = s_ahtmlpagecache;
i >= 0;
i--, phtmlentry++)
{
ASSERT(phtmlentry->pclsid && phtmlentry->ach);
if (IsEqualCLSID(*pclsid, *phtmlentry->pclsid))
{
// create a moniker for the dialog resource
TCHAR szResURL[MAX_URL_STRING];
hr = MLBuildResURL(TEXT("shdoclc.dll"),
HINST_THISDLL,
ML_CROSSCODEPAGE,
phtmlentry->ach,
szResURL,
ARRAYSIZE(szResURL));
if (S_OK != hr)
goto Cleanup;
hr = CreateURLMoniker(NULL, szResURL, &pmk);
if (S_OK != hr)
goto Cleanup;
break;
}
}
if (!pmk)
goto Cleanup;
// return the moniker
hr = pmk->QueryInterface(IID_PPV_ARG(IUnknown, &pUnk));
if (S_OK != hr)
goto Cleanup;
else
{
V_VT(pvarargOut) = VT_UNKNOWN;
V_UNKNOWN(pvarargOut) = pUnk;
V_UNKNOWN(pvarargOut)->AddRef();
}
Cleanup:
ATOMICRELEASE(pUnk);
ATOMICRELEASE(pmk);
return hr;
}
STDMETHODIMP CDocHostUIHandler::Invoke(
DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
HRESULT hr = S_OK; // this function almost always succeeds! should return failure in some cases
if (pDispParams && pDispParams->cArgs>=1)
{
if (pDispParams->rgvarg[0].vt == VT_DISPATCH && pDispParams->rgvarg[0].pdispVal)
{
IHTMLEventObj *pObj=NULL;
if (SUCCEEDED(pDispParams->rgvarg[0].pdispVal->QueryInterface(IID_PPV_ARG(IHTMLEventObj, &pObj)) && pObj))
{
BSTR bstrEvent=NULL;
pObj->get_type(&bstrEvent);
if (bstrEvent)
{
ASSERT(!StrCmpCW(bstrEvent, L"unload"));
IWebBrowser2* pwb2;
hr = IUnknown_QueryServiceForWebBrowserApp(_punkSite, IID_PPV_ARG(IWebBrowser2, &pwb2));
if (SUCCEEDED(hr))
{
IHTMLWindow2* pWindow;
// we shouldn't be catching this event if the dialog is not up
if (IsFindDialogUp(pwb2, &pWindow))
{
ASSERT(pWindow);
if (_pOptionsHolder)
{
BSTR bstrFindText = NULL;
_pOptionsHolder->get_findText(&bstrFindText);
ATOMICRELEASE(_pOptionsHolder);
PutFindText(pwb2, bstrFindText);
SysFreeString(bstrFindText);
}
BSTR bstrOnunload = SysAllocString(L"onunload");
if (bstrOnunload)
{
IHTMLWindow3 * pWin3;
if (SUCCEEDED(pWindow->QueryInterface(IID_PPV_ARG(IHTMLWindow3, &pWin3))))
{
pWin3->detachEvent(bstrOnunload, (IDispatch*)this);
pWin3->Release();
}
SysFreeString(bstrOnunload);
}
pWindow->Release();
//this is the one that should release the dialog (the pWinOut from ShowFindDialog())
ReleaseFindDialog(pwb2);
}
pwb2->Release();
}
SysFreeString(bstrEvent);
}
pObj->Release();
}
}
}
return hr;
}
//------------------------------------------------------------------
//------------------------------------------------------------------
IMoniker * GetTemplateMoniker(VARIANT varUrl)
{
IMoniker * pMon = NULL;
HRESULT hr = S_OK;
if (V_VT(&varUrl) == VT_BSTR && SysStringLen(V_BSTR(&varUrl)) !=0)
{
// we have a template URL
hr = CreateURLMoniker(NULL, V_BSTR(&varUrl), &pMon);
}
else
{
TCHAR szResURL[MAX_URL_STRING];
hr = MLBuildResURLWrap(TEXT("shdoclc.dll"),
HINST_THISDLL,
ML_CROSSCODEPAGE,
TEXT("preview.dlg"),
szResURL,
ARRAYSIZE(szResURL),
TEXT("shdocvw.dll"));
if (S_OK != hr)
goto Cleanup;
hr = CreateURLMoniker(NULL, szResURL, &pMon);
}
Cleanup:
return pMon;
}
//============================================================================
//
// Printing support
//
//============================================================================
static enum {
eTemplate = 0,
eParentHWND = 1,
eHeader = 2, // keep this in ssync with the list below!
eFooter = 3,
eOutlookDoc = 4,
eFontScale = 5,
eFlags = 6,
eContent = 7,
ePrinter = 8,
eDevice = 9,
ePort = 10,
eSelectUrl = 11,
eBrowseDoc = 12,
eTempFiles = 13,
};
static const SExpandoInfo s_aPrintTemplateExpandos[] =
{
{TEXT("__IE_TemplateUrl"), VT_BSTR},
{TEXT("__IE_ParentHWND"), VT_UINT},
{TEXT("__IE_HeaderString"), VT_BSTR}, // from here down matches the
{TEXT("__IE_FooterString"), VT_BSTR}, // safeArray structure so
{TEXT("__IE_OutlookHeader"), VT_UNKNOWN}, // that we can just VariantCopy
{TEXT("__IE_BaseLineScale"), VT_INT}, // in a loop to transfer the
{TEXT("__IE_uPrintFlags"), VT_UINT}, // data.
{TEXT("__IE_ContentDocumentUrl"), VT_BSTR}, // See MSHTML: SetPrintCommandParameters()
{TEXT("__IE_PrinterCMD_Printer"), VT_BSTR},
{TEXT("__IE_PrinterCMD_Device"), VT_BSTR},
{TEXT("__IE_PrinterCMD_Port"), VT_BSTR},
{TEXT("__IE_ContentSelectionUrl"), VT_BSTR},
{TEXT("__IE_BrowseDocument"), VT_UNKNOWN},
{TEXT("__IE_TemporaryFiles"), VT_ARRAY|VT_BSTR},
};
//+--------------------------------------------------------------------------------------
//
// Helper class CPrintUnloadHandler. Used to delete tempfiles created for print[preview].
// Note that we don't delete files when we get onUnload event - at this moment
// files are still in use and can't be deleted. We use destructor - when template
// is being destructed and all files are already released, template releases
// all sinks and here we do our cleanup.
//---------------------------------------------------------------------------------------
class CPrintUnloadHandler: public IDispatch
{
CDocHostUIHandler *m_pUIHandler;
VARIANT m_vFileNameArray; //SAFEARRAY with filenames
LONG m_cRef;
IUnknown *m_punkFreeThreadedMarshaler;
bool m_fPreview;
public:
//IUnknown
STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID *ppv)
{
HRESULT hr = E_NOINTERFACE;
if (ppv == NULL)
{
return E_POINTER;
}
else if (IsEqualIID(IID_IUnknown, riid) || IsEqualIID(IID_IDispatch, riid))
{
*ppv = this;
AddRef();
hr = S_OK;
}
else if (IsEqualIID(IID_IMarshal, riid))
{
hr = m_punkFreeThreadedMarshaler->QueryInterface(riid,ppv);
}
return hr;
}
STDMETHOD_(ULONG,AddRef)(THIS)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHOD_(ULONG,Release)(THIS)
{
ASSERT(0 != m_cRef);
ULONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
}
return cRef;
}
//IDispatch
virtual STDMETHODIMP GetTypeInfoCount(UINT* pctinfo)
{ return E_NOTIMPL; };
virtual STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
{ return E_NOTIMPL; };
virtual STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames,
LCID lcid, DISPID *rgDispId)
{ return E_NOTIMPL; };
virtual STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO *pExcepInfo, UINT *puArgErr)
{ return S_OK; }
CPrintUnloadHandler(CDocHostUIHandler *pUIHandler, bool fPreview)
{
ASSERT(pUIHandler);
//make sure our handler doesn't go anywere..
m_pUIHandler = pUIHandler;
pUIHandler->AddRef();
m_cRef = 1;
VariantInit(&m_vFileNameArray);
//create threaded marshaler because we will be called from another thread
//which will be created for print(preview) window
CoCreateFreeThreadedMarshaler((IUnknown*)this, &m_punkFreeThreadedMarshaler);
//if preview, lock the preview gate so no more then one is possible
m_fPreview = fPreview;
if (m_fPreview)
pUIHandler->IncrementPreviewCnt();
}
~CPrintUnloadHandler()
{
//here we delete those temp files, finally.
DeleteFiles();
if (m_fPreview)
m_pUIHandler->DecrementPreviewCnt();
if (m_pUIHandler)
m_pUIHandler->Release();
if (m_punkFreeThreadedMarshaler)
m_punkFreeThreadedMarshaler->Release();
VariantClear(&m_vFileNameArray);
}
HRESULT SetFileList(VARIANT *pvFileList)
{
if (pvFileList && (V_VT(pvFileList) == (VT_ARRAY | VT_BSTR)))
return VariantCopy(&m_vFileNameArray, pvFileList);
else
return VariantClear(&m_vFileNameArray);
}
void DeleteFiles()
{
int arrayMin, arrayMax;
if (V_VT(&m_vFileNameArray) != (VT_ARRAY | VT_BSTR))
return;
SAFEARRAY *psa = V_ARRAY(&m_vFileNameArray);
if (FAILED(SafeArrayGetLBound(psa, 1, (LONG*)&arrayMin)))
return;
if (FAILED(SafeArrayGetUBound(psa, 1, (LONG*)&arrayMax)))
return;
for (int i = arrayMin; i <= arrayMax; i++)
{
BSTR bstrName = NULL;
if (SUCCEEDED(SafeArrayGetElement(psa, (LONG*)&i, &bstrName)) && bstrName)
{
TCHAR szFileName[MAX_PATH];
SHUnicodeToTChar(bstrName, szFileName, ARRAYSIZE(szFileName));
DeleteFile(szFileName);
SysFreeString(bstrName);
}
}
}
};
#define MAX_BUF_INT (1 + 10 + 1) // -2147483647
//+--------------------------------------------------------------------------------------
//
// Member DoTemplatePrinting
//
// Synopsis : this member function deals with instantiating a print template and enabling
// the printing of a document. It deals with the logic of whether to show or hide the
// template; determining whether/and-how to bring up the print/page-setup dialogs;
// kicking off the print process rather or waiting for the template
// UI (and thus the user) to do so.
//
// Arguments :
// pvarargIn : points to an event object with a number of expandoes that define
// how this print operation should progress.
// pvarargOut : not used
// fPreview : flag indicating whether or not to actually show the template. This is true
// for preview mode, and false for normal printing
//
//---------------------------------------------------------------------------------------
HRESULT
CDocHostUIHandler::DoTemplatePrinting(VARIANTARG *pvarargIn, VARIANTARG *pvarargOut, BOOL fPreview)
{
int i;
HRESULT hr = S_OK;
VARIANT varDLGOut = {0};
const int cExpandos = ARRAYSIZE(s_aPrintTemplateExpandos);
VARIANT aVariant[cExpandos] = {0};
DISPID aDispid[cExpandos];
BSTR bstrDlgOptions = NULL;
DWORD dwDlgFlags;
IHTMLEventObj * pEventObj = NULL;
IHTMLEventObj2 * pEventObj2 = NULL;
IMoniker * pmk = NULL;
IHTMLWindow2 * pWinOut = NULL;
TCHAR achInit[512];
RECT rcClient;
HWND hwndOverlay = NULL;
HWND hwndParent = NULL;
CPrintUnloadHandler * pFinalizer = NULL;
BOOL fBlock;
// in preview mode we do not want to bring up another instance of the template
if (fPreview && (IncrementPreviewCnt() > 1))
goto Cleanup;
if (SHRestricted2(REST_NoPrinting, NULL, 0))
{
// printing functionality disabled via IEAK restriction
MLShellMessageBox(NULL, MAKEINTRESOURCE(IDS_RESTRICTED), MAKEINTRESOURCE(IDS_TITLE), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
hr = S_FALSE;
goto Cleanup;
}
ASSERT(V_VT(pvarargIn) == VT_UNKNOWN);
if ((V_VT(pvarargIn) != VT_UNKNOWN) || !V_UNKNOWN(pvarargIn))
{
hr = E_INVALIDARG;
goto Cleanup;
}
//
// now get the expando properties that were passed in...
//
hr = V_UNKNOWN(pvarargIn)->QueryInterface(IID_PPV_ARG(IHTMLEventObj, &pEventObj));
if (S_OK != hr)
goto Cleanup;
hr = V_UNKNOWN(pvarargIn)->QueryInterface(IID_PPV_ARG(IHTMLEventObj2, &pEventObj2));
if (S_OK != hr)
goto Cleanup;
//
// Get expando parameters from event object
//
hr = GetParamsFromEvent(pEventObj,
cExpandos,
aDispid,
aVariant,
s_aPrintTemplateExpandos);
if (S_OK != hr)
goto Cleanup;
//
// Now that we have all the data, lets do the work of raising the template.
// First, Create the Moniker of the template document
//
pmk = GetTemplateMoniker(aVariant[eTemplate]);
//
// Set up the bstrDlgOptions to properly pass in the size and location
//
StrCpyN(achInit, TEXT("resizable:yes;status:no;help:no;"), ARRAYSIZE(achInit));
//
// get the top most hwnd to use as the parenting hwnd and
// to use to set the size of the preview window
//
hwndOverlay = (HWND)(void*)V_UNKNOWN(&aVariant[eParentHWND]);
while (hwndParent = GetParent(hwndOverlay))
{
hwndOverlay = hwndParent;
}
if (GetWindowRect(hwndOverlay, &rcClient))
{
TCHAR achBuf[32];
StrCatBuff(achInit, TEXT("dialogLeft:"), ARRAYSIZE(achInit));
_ltot(rcClient.left, achBuf, 10); // plenty of space in achBuf for the long value
StrCatBuff(achInit, achBuf, ARRAYSIZE(achInit));
StrCatBuff(achInit, TEXT("px;dialogTop:"), ARRAYSIZE(achInit));
_ltot(rcClient.top, achBuf, 10);
StrCatBuff(achInit, achBuf, ARRAYSIZE(achInit));
StrCatBuff(achInit, TEXT("px;dialogWidth:"), ARRAYSIZE(achInit));
_ltot(rcClient.right - rcClient.left, achBuf, 10);
StrCatBuff(achInit, achBuf, ARRAYSIZE(achInit));
StrCatBuff(achInit, TEXT("px;dialogHeight:"), ARRAYSIZE(achInit));
_ltot(rcClient.bottom - rcClient.top, achBuf, 10);
StrCatBuff(achInit, achBuf, ARRAYSIZE(achInit));
StrCatBuff(achInit, TEXT("px;"), ARRAYSIZE(achInit));
}
bstrDlgOptions = SysAllocString(achInit);
if (!bstrDlgOptions)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
//Create a finalizer
pFinalizer = new CPrintUnloadHandler(this, fPreview);
if (pFinalizer)
{
pFinalizer->SetFileList(&aVariant[eTempFiles]);
}
//
// Bring up a modeless dialog and get the window pointer so that
// we can properly initialize the template document.
//
V_VT(&varDLGOut) = VT_UNKNOWN;
V_UNKNOWN(&varDLGOut) = NULL;
// HTMLDLG_MODELESS really means "open dialog on its own thread", which
// we want to do for both actual printing and previewing.
// Note that if we're previewing, we also flip on HTMLDLG_MODAL; this
// is by design! (see comment below).
fBlock = ((V_UINT(&aVariant[eFlags]) & PRINT_WAITFORCOMPLETION) != 0);
dwDlgFlags = HTMLDLG_PRINT_TEMPLATE;
// VERIFY if we are going to display
if (fPreview)
dwDlgFlags |= HTMLDLG_VERIFY;
// otherwise, don't display with NOUI
else
dwDlgFlags |= HTMLDLG_NOUI;
// If we are not printing synchronously, create a thread for printing.
if (!fBlock)
dwDlgFlags |= HTMLDLG_MODELESS;
// Dlg should block UI on parent
if (fPreview || fBlock)
dwDlgFlags |= HTMLDLG_MODAL;
ShowHTMLDialogEx((HWND)(void*)V_UNKNOWN(&aVariant[eParentHWND]),
pmk,
dwDlgFlags,
pvarargIn,
bstrDlgOptions,
&varDLGOut);
if (V_UNKNOWN(&varDLGOut))
{
V_UNKNOWN(&varDLGOut)->QueryInterface(IID_PPV_ARG(IHTMLWindow2, &pWinOut));
}
if (pWinOut)
{
BSTR bstrOnunload = SysAllocString(L"onunload");
//
// can't really handle failure here, because the dialog is already up.
// .. but we need to set up an onunload handler to properly ref release
//
if (bstrOnunload)
{
IHTMLWindow3 * pWin3;
if (SUCCEEDED(pWinOut->QueryInterface(IID_PPV_ARG(IHTMLWindow3, &pWin3))))
{
VARIANT_BOOL varBool;
hr = pWin3->attachEvent(bstrOnunload, (IDispatch*)pFinalizer, &varBool);
// (greglett) If this fails, we're in trouble.
// We can either delete the temp files at the end of the function (where the ATOMICRELEASE
// calls the Finalizer's destructor), or we can leak the temp files.
// We choose to delete the temp files if we were not modeless (same thread means we're now done with the files).
// Otherwise, we'd rather leak the files than not work.
// Known case: 109200.
if (S_OK != hr && !fBlock)
{
//ASSERT(FALSE && "Temp files leaked while printing!");
pFinalizer->SetFileList(NULL);
}
pWin3->Release();
}
SysFreeString(bstrOnunload);
}
pWinOut->Release();
}
Cleanup:
DecrementPreviewCnt();
VariantClear(&varDLGOut);
if (bstrDlgOptions)
SysFreeString(bstrDlgOptions);
if (pvarargOut)
VariantClear(pvarargOut);
for (i=0; i<cExpandos; i++)
VariantClear(aVariant + i);
// This will also delete temp files stored in finalizer if we did non-modeless preview (!fBlock)
ATOMICRELEASE(pFinalizer);
ATOMICRELEASE(pEventObj);
ATOMICRELEASE(pEventObj2);
ATOMICRELEASE(pmk);
return hr;
}
//+--------------------------------------------------------------------------------------
//
// Member DoTemplatePageSetup
//
// Synopsis : In template printing architecture, the page setup dialog is still raised
// by the DHUIHandler, but it may be overriden. In order to pull ALL print knowledge
// out of trident it is necessary to have trident delegate the request for pagesetup
// up to here, then we instantiate a minimal template which brings up a CTemplatePrinter
// which delegates back to the DHUIHandler to bring up the dialog itself.
//
// Although this is slightly convoluted, it is necessary in order to give the host
// complete control over the pagesetup dialog (when not raised from print preview)
// while at the same time maintaining backcompat for the registry setting that is done
// independant of the UI handling itself
//
//---------------------------------------------------------------------------------------
HRESULT
CDocHostUIHandler::DoTemplatePageSetup(VARIANTARG *pvarargIn)
{
HRESULT hr = S_OK;
TCHAR szResURL[MAX_URL_STRING];
IHTMLEventObj * pEventObj = NULL;
IMoniker * pMon = NULL;
const int cExpandos = ARRAYSIZE(s_aPrintTemplateExpandos);
VARIANT aVariant[cExpandos] = {0};
DISPID aDispid[cExpandos];
int i;
if (SHRestricted2(REST_NoPrinting, NULL, 0))
{
// printing functionality disabled via IEAK restriction
MLShellMessageBox(NULL, MAKEINTRESOURCE(IDS_RESTRICTED), MAKEINTRESOURCE(IDS_TITLE), MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND);
hr = S_FALSE;
goto Cleanup;
}
ASSERT(V_VT(pvarargIn) == VT_UNKNOWN);
if ((V_VT(pvarargIn) != VT_UNKNOWN) || !V_UNKNOWN(pvarargIn))
{
hr = E_INVALIDARG;
goto Cleanup;
}
//
// now get the expando properties that were passed in...
//
hr = V_UNKNOWN(pvarargIn)->QueryInterface(IID_PPV_ARG(IHTMLEventObj, &pEventObj));
if (S_OK != hr)
goto Cleanup;
//
// Get expando parameters from event object
// do we care if this fails?
hr = GetParamsFromEvent(pEventObj,
cExpandos,
aDispid,
aVariant,
s_aPrintTemplateExpandos);
// get the resource URL
hr = MLBuildResURLWrap(TEXT("shdoclc.dll"),
HINST_THISDLL,
ML_CROSSCODEPAGE,
TEXT("pstemplate.dlg"),
szResURL,
ARRAYSIZE(szResURL),
TEXT("shdocvw.dll"));
if (S_OK != hr)
goto Cleanup;
// create the moniker
hr = CreateURLMoniker(NULL, szResURL, &pMon);
if (S_OK != hr)
goto Cleanup;
// raise the template
hr = ShowHTMLDialogEx((HWND)(void*)V_UNKNOWN(&aVariant[eParentHWND]),
pMon,
HTMLDLG_MODAL | HTMLDLG_NOUI | HTMLDLG_PRINT_TEMPLATE,
pvarargIn,
NULL,
NULL);
Cleanup:
for (i=0; i<cExpandos; i++)
VariantClear(aVariant + i);
ATOMICRELEASE(pMon);
ATOMICRELEASE(pEventObj);
return hr;
}