Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Controlling the print dialog/window #42

Open
verelpode opened this issue Aug 20, 2019 · 24 comments
Open

Controlling the print dialog/window #42

verelpode opened this issue Aug 20, 2019 · 24 comments
Labels
feature request feature request tracked We are tracking this work internally.

Comments

@verelpode
Copy link

verelpode commented Aug 20, 2019

@liminzhu wrote:

For the WebView2 we're building though, you can use window.print. WebView opens the same printing prompt and prints what the browser does. I was messing with this,

webviewWindow->Navigate(L"https://www.twitter.com/");
EventRegistrationToken token;
webviewWindow->add_NavigationCompleted(Callback<IWebView2NavigationCompletedEventHandler>(
    [](IWebView2WebView* wv, IWebView2NavigationCompletedEventArgs* args) -> HRESULT {
        webviewWindow->ExecuteScript(L"window.print();", nullptr);
        return S_OK;
    }).Get(), &token);

That's great. We'll be among the people using that feature. However, considering that the above technique uses ExecuteScript, will printing always still work if EcmaScript is disabled? I'm referring to WebView2 having a setting equivalent to Windows.UI.Xaml.Controls.WebViewSettings.IsJavaScriptEnabled, that is put_IsScriptEnabled.

For this reason, I suggest adding a simple "OpenPrintDialog" method to the API, even if it is implemented by doing exactly the same as the ExecuteScript snippet above. The advantages of "OpenPrintDialog" are:

  1. Allows you to change the internal implementation in a future version of WebView2, without changing the public API. Such a change might become necessary for some reason and then you'll be glad that the change can be performed without breaking compatibility with the public API.
  2. Can succeed regardless of whether EcmaScript is disabled.
  3. Protects the public API against possible future changes in the behavior of EcmaScript.
  4. Although the ExecuteScript technique works, it is obscure and will leave people wondering/asking: How to print?

Can you make a "ClosePrintDialog" method in WebView2 that closes any print dialog/window that may be open? (Does nothing if no print dialog is currently open.) Related: If a WebView2 XAML element has it's Visibility property set to Collapsed, or if the WebView2 element is removed/detached from the element tree, what happens to the print dialog? If it remains visible because it's in a separate floating window, then the "ClosePrintDialog" method would be especially useful to solve problems here.

Can you make a "IsPrintDialogOpen" method that returns a boolean indicating whether the/any print dialog/window is open/displayed/visible?

Can you make an event that is triggered when the print dialog/window is closed? Ideally the event arguments would include a boolean that specifies whether or not the dialog was closed via the Cancel button/key/action. An extra bonus feature would be the inclusion of a background print job identifier in the arguments of this event.

When the user closes the print dialog by clicking the "Print"/"OK" button, is it possible to intercept the print job settings and change them and/or cancel the print job? Reasons include:

  • To stop a customer's kids entering 99999 in the number of copies box, starting the print job, and running away. (Computer in a shop / public location.)
  • To cancel the print job if the selected printer is a virtual printer that does print-to-file, in environment where this needs to be prevented.

Virtual printers that print to files

When using a virtual printer named "Print to PDF" or "Save as PDF", when it prompts for the file name and location, and when it runs in a UWP app, have the security rules already been tested successfully? Meaning, will it enforce the same security rules as Windows.Storage.Pickers.FileSavePicker even when running via a separate-process mode?

In our kiosk system, we must prevent kiosk users seeing the local file system. Therefore, would it be possible to make the following boolean settings in WebView2?

  • Allow/disallow physical (real) printers.
  • Allow/disallow virtual printers.

Examples of the virtual printers that exist in Windows are:

  • "Microsoft Print to PDF" or "Save as PDF"
  • "Microsoft XPS Document Writer"
  • "OneNote"
  • "Send to OneNote 2016"

Alternative designs include:

  • A setting "Allow/disallow print to file" instead of "Allow/disallow virtual printers".
  • An option to supply a list of printers that the print dialog should be restricted to.
  • An option to use an external print dialog produced by the app using WebView2, instead of the WebView2's built-in print dialog. This might be possible if WebView2 supports an equivalent of CaptureSelectedContentToDataPackageAsync except with an option to capture the entire page instead of only the selected part.

Summary

  • OpenPrintDialog method that succeeds regardless of whether EcmaScript is disabled.
  • ClosePrintDialog method.
  • IsPrintDialogOpen boolean property.
  • Event triggered when the print dialog/window is closed.
  • When print dialog is closed, intercept print job and change settings and optionally cancel print job.
  • Option to disable virtual printers or "print-to-file" printers.
  • Ability to use an external print dialog instead of the built-in print dialog, such as via a version of WebView.CaptureSelectedContentToDataPackageAsync but with ability to capture entire page.
  • Testing of print features for compatibility with the built-in PDF viewer, not only testing with HTML pages.

AB#27694507

@liminzhu
Copy link
Member

Thanks for the detailed request! We are actually making the change to allow ExecuteScript even when JS is disabled in IWebView2Settings since we trust the host app knows what it is doing. So print would still work. There are also some events, namely onbeforeprint and onafterprint, which help you detect the timing. Obviously a print method directly from WebView can still be on the table if necessary.

I'm not aware of any way to intercept a print job for the cases you mentioned, so have to think through this a bit more. We will also need to work with the UWP WebView2 folks to understand the security implications of virtual printers (cc @adambarlow).

@liminzhu liminzhu added the feature request feature request label Aug 20, 2019
@verelpode
Copy link
Author

We are actually making the change to allow ExecuteScript even when JS is disabled in IWebView2Settings since we trust the host app knows what it is doing.

I think that is a good decision.

Obviously a print method directly from WebView can still be on the table if necessary.

I think a WebView2.OpenPrintDialog method may still be necessary or desirable because JavaScript window.print(); might only be supported or guaranteed with HTML webpages (correct?). I think there is no guarantee or API promise or standard that says that JS window.print(); will/should be supported at times when WebView2 is directly displaying non-HTML content such as PDF, SVG, PNG, etc.

Re SVG and PNG: Obviously JS window.print(); is supported when the SVG or PNG image is displayed inside a HTML webpage, but what about the situation where the image is displayed directly without any HTML at all? For example, a URI that is a direct link to an SVG image:

webView2Instance->Navigate(L"http://www.example.com/xxxxxxx/test-image.svg");

Likewise for PDF: The JS window.print(); is defined in the HTML standard, but there doesn't exist any standard that says that WebView2's built-in PDF viewer should support window.print(); or any other JS functions. Therefore I think a WebView2.OpenPrintDialog method would be a good solution. What do you think?

Re priorities: Although I'd appreciate having the OpenPrintDialog method, I think a few other issues are much higher priority, especially the need for a GetCookies method as previously discussed.

@verelpode
Copy link
Author

verelpode commented Nov 6, 2019

Correct me if I'm wrong, but doesn't issue #7 need to be reopened (or otherwise addressed here in issue #42) because the current implementation of window.print(); won't work at all in Windows Phone 10? Actually it won't work at all in any UWP app running in any device (desktop PC, laptop, tablet, or smartphone) -- correct? It's completely broken across all UWP devices. It also won't work with WPF apps and WinForms apps.

Currently window.print(); displays Chromium's print dialog that is implemented in the old Win16 system that was updated and renamed to Win32, but Win32 and Win16 dialogs cannot be displayed in a smartphone running Windows Phone 10 (or any other UWP devices).

If I'm not mistaken, in order to fix this, the entire Win32 print dialog must be ripped out of WebView2, and deleted, and replaced with an event that notifies the WinUI side of WebView2 to display the standard WinUI/UWP printing GUI.

I hope my message isn't written in a confusing manner. To clarify, I'm talking about the following print dialog. Currently WebView2 displays this Chromium Win32 print dialog:

print

The above screenshot shows the current print dialog but that is Chromium's old/obsolete Win32 code that doesn't work (won't ever work) in Windows Phone 10 or any other UWP devices, as far as I know. It seems like the best plan would be to delete the current print dialog source code in WebView2 and instead use an event to notify the upcoming WinUI side of WebView2 to display the standard WinUI/UWP printing GUI. This could be incorporated into a larger plan to delete all of the old Win32 GUI code in WebView2 because all of that is obsolete and doesn't work in any UWP desktop computers, laptops, tablets, or smartphones when running WebView2 in modern UWP apps.

This issue isn't limited to UWP. It's also applicable to WebView2 running in WPF apps and in WinForms apps. Chromium's old Win32 print dialog (and all other Win32 GUI displayed by Chromium/WebView2) doesn't work with:

  • UWP apps.
  • WPF apps.
  • WinForms apps.

@david-risney
Copy link
Contributor

We don't have support for UWP, WPF, or WinForms yet. For each of these when we do if we have an issue with print we can open issues for them then. Thanks

@nikki9696
Copy link

nikki9696 commented Nov 23, 2020

Hi,
"For each of these when we do if we have an issue with print we can open issues for them then"

Is there an open issue for this for the winforms version yet? I came here because we're swapping our webbrowser to this new control, and this javascript print opens the print dialog in the tiny area we use for display instead of as a modal dialog (system print dialog), as we're used to and prefer.
Also, we use ShowPrintPreviewDialog and I see no way to get to that?
Also, we use a web browser to load a file frequently, and you cannot add scripts to a file...(e.g. pdf)

Thanks!

@asklar
Copy link

asklar commented May 21, 2021

the platform has requests around converting html or other web content into pdf, which would benefit from this feature being implemented. See microsoft/react-native-windows#7723

@ajtruckle
Copy link

I have two fundamental issues with the Print Dialog concept in WebView2:

  1. If you try to print when your control is only half the dialog, the print dialog is squished into that control. With CHtmlView it had its own pop up window that could be maximised. I simply can’t use this control in my software as the Print dialog is squished and it gets worse as you resize the window containing the control down.

  2. In my current app that uses CHtmlView I have two browsers. One is for the editor. The other is hidden. When the user prints we prepare a special version of the document for loading into the hidden browser. We then bring up a print dialog for the hidden browser. This way our editor can show a editor version of the document. I can’t work out how to have a second hidden browser and do the same thing.

So these two reasons mean I can’t use the control. I raised these issues over 2 years ago and nothing has changed to my knowledge?

@ajtruckle
Copy link

this javascript print opens the print dialog in the tiny area we use for display instead of as a modal dialog (system print dialog), as we're used to and prefer.

Exactly my observation. A crippling limitation. It is as if the assumption is the control is full screen and if it were, why not just use a browser? Since the control is advertised for using in apps it needs to address this problem. I agree that the browser should display a system print window will option to maximise like it used to. Or make current one support this.

@andyste1
Copy link

andyste1 commented May 3, 2022

+1 for the issue of the daft print settings dialog that gets rendered within the WebView2 component, rather than appearing as a modal dialog. Our team has had a requirement this week for displaying HTML pages in one of our WPF desktop apps, so this issue with WebView2 is disappointing to say the least.

Unfortunately the WPF WebBrowser component is no better - still no Print() method (although bizarrely the Winforms version does). Printing via js is possible but WebBrowser doesn't have a print settings dialog. (I also looked at CefSharp, but wasn't happy with 600Mb+ of redistributable assemblies!).

@champnic champnic added the tracked We are tracking this work internally. label May 10, 2022
@BasketGolfer
Copy link

+1 There is no way that I can see to programmatically set the available options and print to a physical printer (other than using say UI automation to script the dialog when it appears) - is there a workaround?

@david-risney
Copy link
Contributor

david-risney commented Jun 21, 2022

We're currently working on a print API (no ETA yet). Until then the only two work arounds are using window.print() from JavaScript or using CoreWebView2.PrintToPdf to create a PDF file and then printing the PDF yourself.

@monica-ch
Copy link
Contributor

Hi all, we've completed our design for the https://github.com/MicrosoftEdge/WebView2Feedback/pull/2604/files! Please review the pull request and add any feedback you have about this API. We appreciate your input and support!

@monica-ch
Copy link
Contributor

Hi all, we have shipped Print APIs as experimental in the 1.0.1414 pre-release package: https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes?tabs=dotnetcsharp#experimental-features. Please let us know if you have any feedback!

@MikeCheel
Copy link

Hi all, we have shipped Print APIs as experimental in the 1.0.1414 pre-release package: https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes?tabs=dotnetcsharp#experimental-features. Please let us know if you have any feedback!

When I print a pdf file to Microsoft PDF using PrintAsync() I get a blank page and that's it. How does one print a pdf file?

@monica-ch
Copy link
Contributor

monica-ch commented Jan 20, 2023

@MikeCheel This is a known issue with PrintAsync which is printing a blank page for PDFs, we are tracking the bug here #3007

@MikeCheel
Copy link

Thank you for your quick reply

@santey12
Copy link

santey12 commented Feb 7, 2023

Hi all, we have shipped Print APIs as experimental in the 1.0.1414 pre-release package: https://learn.microsoft.com/en-us/microsoft-edge/webview2/release-notes?tabs=dotnetcsharp#experimental-features. Please let us know if you have any feedback!

When I print a DOCX file to Microsoft PDF using PrintAsync() I get a blank page and that's it. How does one print a DOCX file?

@monica-ch
Copy link
Contributor

@santey12 I assume browser/system print dialog isn't supported to print a DOCX file hence PrintAsync prints a blank page. One can use Print option provided in the docx file to print to any printer.

@ajtruckle
Copy link

Can you make a IsPrintDialogOpen method that returns a boolean indicating whether the/any print dialog/window is open/displayed/visible?

This is useful. We can then prevent our app from closing by looking to see if this api call returns true or not.

@monica-ch
Copy link
Contributor

@ajtruckle You can also use JS beforePrint afterPrint to determine whether print is started/completed or cancelled and control closing the app.

@ajtruckle
Copy link

@monica-ch I like the idea, as you suggested something similar for another ticket #3266.

But I struggle with it you see. I have two classes:

  • CWebBrowser
  • CWebBrowserImpl

CWebBrowser has a function for registering all the event handlers. I tried adding:

void CWebBrowser::RegisterEventHandlers()
{
        // ...

	CHECK_FAILURE(m_pImpl->m_webView->add_WebMessageReceived(
		Microsoft::WRL::Callback<ICoreWebView2WebMessageReceivedEventHandler>(
			[this](
				ICoreWebView2* sender,
				ICoreWebView2WebMessageReceivedEventArgs* args)
			{
				wil::unique_cotaskmem_string messageRaw;
				CHECK_FAILURE(args->TryGetWebMessageAsString(&messageRaw));

				if (messageRaw.get() == L"PrintDone")
				{
					::MessageBeep(MB_OK);
				}
				return S_OK;
			})
		.Get(),
				nullptr));


	/// Register `afterprint` event
	m_pImpl->m_webView->ExecuteScript(
		LR"~(
             window.addEventListener('afterprint', (event) => {
                  window.chrome.webview.postMessage('PrintDone');
             });
        )~",
		Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
			[](HRESULT error, PCWSTR result) -> HRESULT { return S_OK; })
		.Get());
}

It seems to do nothing. If I display the PrintUI and hit cancel, nothing happens.

@ajtruckle
Copy link

@monica-ch Researching tge internet about those two events implies they only fire as indicated. Print started. Print ended. So doesn’t account for cancel window.

I think a simply IsPrintUIVisible is much easier 😀

@monica-ch
Copy link
Contributor

@ajtruckle Same code works from our sample app.

It gets invoked when Cancel is hit from Print dialog. See https://www.w3schools.com/jsref/tryit.asp?filename=tryjsref_onafterprint.

I believe Print ended here when print dialog is closed (with successful print or cancelled)

@ajtruckle
Copy link

@monica-ch Alright, so why is my attempt failing? 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request feature request tracked We are tracking this work internally.
Projects
None yet
Development

No branches or pull requests