Two Visual Basic Printing Problems With Redirected Printers

Background

Applications written in Visual Basic 6, print using a standard printer object included with Visual Basic. This object includes methods to access a list of available printers or the default printer. The information that these Visual Basic methods access, ultimately comes from registry keys in the users’ registry hives. It is the duty of the Windows operating system to look after these registry keys. However Visual Basic 6 and other legacy applications that use this older source of information, have fallen out of support. This means that later versions of the Windows operating system have paid less attention to maintaining backwards compatibility. Windows provides information via these registry keys which might not match what Windows Settings or the Control Panel is showing. When we use “redirected printers” in particular, we can see a variety of Visual Basic printing problems.

Visual Basic Printer List

These legacy Visual Basic applications obtain the list of available printers from the “Devices” registry key at:

 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Devices
Visual Basic Printing Problem 1 Legacy VB6 applications obtain the printer list from a registry key
Legacy VB6 applications obtain the printer list from a registry key

and each device listed in there should have a matching record in

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts

Visual Basic Printing Problem 1: Printer List Builds Up Many Copies Of Redirected Printers

Users with printers available to their local PC or laptop can use those printers from inside a Remote Desktop Session. We call these “redirected printers”. When a user logs on to a Remote Desktop Server, it creates a remote session. If we have enabled “redirected printers” in this session then Windows adds or updates values in the registry keys discussed above.

Unfortunately later versions of Windows are not removing these legacy registry entries when the user logs out. Since the name of a redirected printer changes with each connection, we can see multiple copies of the same printer. For example Fax (redirected 1), Fax (redirected 2), Fax (redirected 3) etc.

When users look in Windows settings or control panel they see a different list where everything works as expected. However any legacy application that depends on these registry keys may see problems with redirected printers. This legacy list can contain many hundreds of printers. Only some of which will be functional. Some Visual Basic printing problems include print dialogue boxes that take minutes just to show a list hundreds of out of date redirected printers.

Workaround 1 – Delete the entries from the registry

Whilst it would be nice to see Microsoft fix this, there is no hint that they’re interested in doing so. Instead we can delete the registry values ourselves. First from:

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Devices 

and then

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts

The next time a user logs on valid values will be created .

Unfortunately this is only a stop gap. Windows will still add any new printers or redirected printers to the list but will not remove them.

Note also that this will only fix the issue for one user at a time. Each user has their own copy of HKEY_CURRENT_USER. So we must be carry out the fix for each user separately.

Workaround 2 – Disable Redirected Printers

We often leave redirected printers switched by default but they’re not always necessary. If the user’s PC and the server are connected to the same network, they can print directly from the server. We can then switch off redirected printers by editing the user’s connection settings as below. Or they can use policy settings to switch them off from the server side.

Used alongside the first workaround, this may prevent these faulty registry entries from returning.

Visual Basic Printing Solution - Printer redirection is enabled by default but is not always needed
Printer redirection is enabled by default but is not always needed

Workaround 3- Logout Script

If redirected printers are required, then it is possible to use group policy to set a logout script. We can use this to apply the first workaround (delete entries from the registry) each time the user logs out. Below is one example of such a logout script, using vbscript:

Const HKEY_CURRENT_USER = &H80000001
on error resume next
strComputer = "."
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\" & strComputer & "\root\default:StdRegProv")
strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\Devices"
oReg.EnumValues HKEY_CURRENT_USER, strKeyPath, arrDevices
For Each device In arrDevices
if (inStr(device,"redirected")) then
oReg.DeleteValue HKEY_CURRENT_USER,strKeyPath,device
end if
Next
strKeyPath = "Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"
oReg.EnumValues HKEY_CURRENT_USER, strKeyPath, arrPrinterPorts
For Each printerport In arrPrinterPorts
if (inStr(printerport,"redirected")) then
oReg.DeleteValue HKEY_CURRENT_USER,strKeyPath,printerport
end if
Next

Or in powershell

$pathlist  = 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Devices', 'HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PrinterPorts'
foreach ($p in $pathlist) {
    $devices = get-itemproperty -path $p
    $redirecteddevices = $devices | get-member | where-object -FilterScript {$_.name -match 'redirected'} 
    $redirecteddevices | Remove-ItemProperty -path $p
}

Visual Basic Default Printer

Legacy Visual Basic applications obtain the default printer from the registry at:

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows\Device  
Visual Basic Printing Problem 2 - Legacy VB6 applications obtain the default printer from a registry value
Legacy VB6 applications obtain the default printer from a registry value

Visual Basic Printing Problem 1: Session Default Printers

Starting with Windows Server 2012, Microsoft introduced a new key where the system may look for a default printer. When a user logs on to a remote desktop session and has a redirected, default printer then the new key is used. We then find the default printer in the “Device” value in a subkey of :

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows\SessionDefaultDevices
Visual Basic Printing Problem 2 The default printer in a remote desktop session using redirected printers may be found in within a unique key for each session
The default printer in a remote desktop session using redirected printers may be found in within a unique key for each session

The purpose of this seems to allow for more than one session existing for the same user account. Previously this would have meant that when a default printer was set for a user’s second session, it would replace the default printer in the user’s first session.

The hope appears to be that the application would check for a default printer under the appropriate subkey of SessionDefaultDevices. If no such subkey is found then it would fall back to using the “Device” value from the “Windows” key :

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows\Device

Many legacy applications do not know to use the SessionDefaultDevices subkey. They can only look in at the device value from the Windows Key. Windows 2012 maintained backwards compatibility by updating both locations. However Windows 2016 and Windows 2019 do not do so which leads to problems printing from Visual Basic applications using redirected printers. It means that when redirected printers are in use, legacy visual basic applications may be looking for a value that is either missing or does not represent the true default printer.

Workaround – copy default printer from Session Default Printer

Sometimes we can reprogram applications to be aware of these changes and so maintain the “Device” value from the “Windows” key by copying it from the appropriate SessionDefaultDevices subkey.
Alternatively we can carry this out with a script:

$a = Get-ItemProperty "HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\SessionDefaultDevices*\"
if ($a.Device) {
Set-ItemProperty -path "HKCU:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows" -name Device -Value $a.Device
write-output "Legacy Default Printer set to $($a.Device)"
}
else
{
write-output "Default Printer is not Redirected"
} 

Summary

We’ve seen two problems where using redirected printer causes Visual Basic printing problems and discussed workarounds for these issues. If you’ve seen similar issues or have your own workarounds then comments are open.


Posted

in

by