3641 lines
111 KiB
C++
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;
|
|
}
|
|
|