|
|
#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; }
|