UWP – Print PDF Files Silently (Without Print Dialog)

At the moment I’m working on one of the UWP business apps. This app will run on a kiosk mode (Assigned Access) and will be placed in a public place for customers to use. The customer should be able to fill forms, and print them out.

The easiest and the most straightforward way to do that is to use the PrintManager and call ShowPrintUIAsync

 

The issue with this method, it will show the user the print dialog. This is not acceptable in a controlled environment

So what we want is to print silently without showing a  preview dialog, which leaves us with the following methods:

  1. Sending the print order to a server, and from the server to the printer
  2. Sending the print order directly from the UWP app to the printer

In this post we gonna discuss the second approach.

The high level look at this solution is as simple as this:

  1. We create our Win32 application that will do the printing for us (a Console project)
  2. That Win32 application is added to our UWP application as an executable (We also add any other required executables)
  3. We launch that Win32 application from our UWP app and pass any parameters if required

 

So let’s start by creating a new Console application. Start Visual Studio, create a new solution and make sure the project selected is Console App (.NET Framework):

In this tutorial I’m using Foxit PDF Reader to print my PDF files, so go ahead and install it.

Once installed, in your console’s Program class, create a process and execute the print command:

static void Main(string[] args)
{
var pdfProcess = new System.Diagnostics.Process();
pdfProcess.StartInfo.FileName = @"C:\Program Files (x86)\Foxit Software\Foxit Reader\FoxitReader.exe";
pdfProcess.StartInfo.Arguments = string.Format("-t \"{0}\" \"{1}\"", @"c:\temp\sample.pdf", "Microsoft Print to PDF");
pdfProcess.Start();
}

All we had to do above is to create a process, provide the process name “FoxitReader.exe“, and provide the argument “-t “c:\temp\sample.pdf” “Microsoft Print to PDF”“.

Now that our console application is ready to be called from UWP, create a new Blank App (Universal Windows):

To call the Win32 process, we will need to add the Windows Desktop Extensions for the UWP , right click on the References and then Add Reference:

From the left pane select Universal Windows -> Extensions, then select Windows Desktop Extensions for the UWP and press Ok.

Open MainPage.xaml, and add a button (which will initiate the printing task):

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Print" HorizontalAlignment="Center" VerticalAlignment="Center" Click="print_Click" />
</Grid>

In your MainPage.xaml.cs file, add the following method:

private async void print_Click(object sender, RoutedEventArgs e)
{
if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
await Windows.ApplicationModel.FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
}
}

The previous code is checking if we have access to the FullTrustAppContract api, if so we’re launching the process.

Before launching the process we need to tell the UWP application where to find the Win32 console application to start.

What we need to do here is make sure that the console project is creating the executable inside the UWP project’s folder. So first lets go back to the Console project and open the properties:

Then change the Output Path to “..\UWPPrintSilently“:

Build the console project once, if you try to open the UWP project’s folder, the executable wont be there yet, as we didnt add it to the project. Click on the UWP project and then on the Show All Files icon:

You will see the “Win32Printer.exe” file grayed out. Right click on that file and then Include In Project

Now we need to include this file into the PackageManifest. At the time of writing this post, there’s no UI to edit the Package.appxmanifest to add the trusted win32 application, so we will need to do it through xml editor. Right click on the Package.appxmanifest and click on Open With

From the Open With window, select “XML (Text) Editor” and press Ok

At the end of this file, in the capabilities section, we will need to add the “runFullTrust” capability <Capabilities>

<Capability Name="internetClient" />
<rescap:Capability xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" Name="runFullTrust" />
</Capabilities>

Finally we will assign which excecutable we want to run, from the Applications->Application xml element (below the </uap:VisualElement>), add the following:

<Extensions xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10">
<desktop:Extension Category="windows.fullTrustProcess" Executable="Win32Printer.exe" />
</Extensions>

Don’t forget to set the UWP as a startup project. Run the app and press the button “Print” you should get the print order.

 

Tweaks/Fixes

Hide the console

You will notice when you start the print process a console application shows up. We can easily fix that by changing the output type. Right click on the console project, then click Properties. Then from the left pane click on Application and change the Output Type to Windows Application.

Pick the files to be printed

Unlike what we have now where the pdf to be printed is hard coded, you would want to pick what file to be printed. So we need to send the pdf file to the console application.

We can do that by passing the values through the ApplicationData.Current.LocalSettings. Because this class is part of the UWP APIs, we will need to enable our console application to call these APIs. All we need to do here is to add the Windows.winmd file which can be located in the path “C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.16299.0\Windows.winmd” (Note that the version number “10.0.16299.0” might change). From the Solution Explorer window, right click on the console project then Add Reference

From the Reference Manager window, click on Browse, and add the file “C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.16299.0\Windows.winmd

Once added, change the implementation of the Main method in the console project to the following:

var pdfProcess = new System.Diagnostics.Process();
pdfProcess.StartInfo.FileName = @"C:\Program Files (x86)\Foxit Software\Foxit Reader\FoxitReader.exe";
var fileToPrint = ApplicationData.Current.LocalSettings.Values["FileToPrint"];
pdfProcess.StartInfo.Arguments = string.Format("-t \"{0}\" \"{1}\"", fileToPrint, "Microsoft Print to PDF");
pdfProcess.Start();

The only change here is that we read the path of the file to be printed form the ApplicationData instead of the hard coded value.

Going back to the UWP project, we need to pass the path using the ApplicationData using the same key:

var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".pdf");
var pdfFile = await picker.PickSingleFileAsync();

if (pdfFile != null)
{
ApplicationData.Current.LocalSettings.Values["FileToPrint"] = pdfFile.Path;
if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
{
await Windows.ApplicationModel.FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
}
}

So this time we let the user pick the file, and we pass the path of that file through the ApplicationData, and start the process.

 

Add FoxitPdfReader to the UWP package

One of the prerequisites for printing pdf used in this tutorial is to install Foxit Reader. This might be not possible for some scenarios (Not allowed to install other apps, or maybe you have Windows 10s which doesn’t allow running unverified apps)

So to fix this, we will add the Foxit Pdf Reader executable to our UWP project.

Navigate to the path “C:\Program Files (x86)\Foxit Software\Foxit Reader“, and add the FoxitReader.exe to your UWP project.

Then in your console application, change the path of the process:

pdfProcess.StartInfo.FileName = @"FoxitReader.exe";

Now you can uninstall FoxitReader and start your uwp application, we dont need Foxit PDF reader to be installed anymore.

 

Notes
  • I’ve used FoxitPDFReader as an example here, Please read the usage agreement as this method might violate the terms.
  • You can replace FoxitReader with any available readers you like (Adobe, Word ..etc)
  • In the above example the printer name is hard coded in the console project. You can pass the printer name through ApplicationData form the UWP project
  • If you want to print directly to the default printer, you can set the printer name as an empty string
You can get the complete source code from this github repository:
https://github.com/TareqAteik/SampleUWPPrintSilently
If you have any question, please reach me out on twitter @tareqateik

Leave a Reply

Your email address will not be published. Required fields are marked *