The issue here is that printing an X++ report to file (pdf) via a business connector call within a web service, the paper size is defaulting to "letter" instead of the usual A4 size we use in Europe, but we'll also explain first how AX finds the default printer and then we'll talk about how that applies in our problem situation.

How the AX kernel finds the default printer:

What is happening in the background here is that the AX kernel calls into the Windows function GetDefaultPrinter() (http://msdn.microsoft.com/en-us/library/dd144876(VS.85).aspx) this looks to the registry key:

.. Software\Microsoft\Windows NT\CurrentVersion\Windows\Device

To find the default printer, whether this is HKCU, HKU\UserSid, or HKU\Default depends on the context it is running in and whether the particular user profile actually exists or not. Once the function finds the device from here it will move to the registry key:

..Software\Microsoft\Windows NT\CurrentVersion\Devices\<printer name>

Later in the kernel we'll use the Windows function OpenPrinter() (http://msdn.microsoft.com/en-us/library/dd162751(VS.85).aspx) to access the printer's properties - this is where the papersize would be populated. If this function fails, and if not printing direct to that device (e.g. print to file/screen etc..) then we'll set a pseudo-printer with some standard defaults to allow printing to continue even though we cannot access the printer. This pseudo-printer uses "letter" page size, so this is where that is coming from.

The reason that we have this pseudo-printer mechanism is that when running BC under w3wp it is not always possible to access printer information - we created it during the development of AX4 as part of the new .NET business connector and Enterprise portal framework, without this mechanism, with certain configuration it is possible that we would fail in low level printer functions which the reporting engine relies upon.

 

Why in some situations we fail to find the default printer:

Now if I apply this to a specific situation, for example we may be running the business connector within a web service, which runs as the ApplicationPoolIdentity. So when we call GetDefaultPrinter() - we find there is no user profile for that identity (it is not access denied - it simply does not exist) this can be seen with a procmon trace from a line like this:

12:34:23.5536848 PM  w3wp.exe      2676   RegOpenKey    HKU\S-1-5-82-2257762870-3033483361-1282393911-956591122-915368935  NAME NOT FOUND       Desired Access: Read

Next we jump to the default user profile, which does exist, but the key that we need does not exist, which basically tell us there is no default printer for the default user profile:

12:34:23.5537105 PM  w3wp.exe      2676   RegOpenKey    HKU\.DEFAULT\Software\Microsoft\Windows NT\CurrentVersion\Windows  NAME NOT FOUND       Desired Access: Read

From this point onwards - as we found no printer in the steps above, we fail to return a default printer, and therefore when we call openPrinter we also fail and the pseudo-printer is selected instead - and the pseudo printer has "letter" papers size instead of A4.

To move past this you need to run the application pool as a domain account, and ensure that it has access to pick up a real printer - you can test with procmon as I described above to see where it's looking for the printer so that you can prove where it's failing.

--author:  Tariq Bell
--editor: Tariq Bell
--date: 27/04/2011