Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Getting the default printer in 64-bit Vista

27 views
Skip to first unread message

Mark Rae

unread,
Jun 8, 2007, 6:36:17 PM6/8/07
to
Hi,

I have used the code below to return the default printer in 32-bit WinXP
Pro, but now that I am running 64-bit Vista Business I'm getting an error:

using System.Drawing.Printing;

using (PrintDocument objPrintDocument = new PrintDocument())
{
string strDefaultPrinter =
objPrintDocument.PrinterSettings.PrinterName;
}

The error message is: "No printers are installed." and which seems to come
from a method called HdevmodeInternal

However, I have several printers installed, and the default printer is an
old HP LaserJet 5.

Does the above code not work on 64-bit Vista? The app in question is
compiled for x86...

Would I be better off using WMI to return the name of the default printer?

I've tried to find a solution in Google and MSDN, but haven't had much
luck...

Any assistance gratefully received.


--
http://www.markrae.net

Willy Denoyette [MVP]

unread,
Jun 9, 2007, 6:04:01 AM6/9/07
to
"Mark Rae" <ma...@markNOSPAMrae.net> wrote in message
news:u5ow81hq...@TK2MSFTNGP04.phx.gbl...

Works for me on Vista 64 and 32 bit. What happens if you make "Microsoft XPS
Document Writer" the default printer?

Willy.


Mark Rae

unread,
Jun 9, 2007, 7:32:31 AM6/9/07
to
"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
news:%23cKPz1n...@TK2MSFTNGP06.phx.gbl...

Same thing... Incidentally, it works for me on 32-bit Vista... Did you try
it with a 32-bit app running on 64-bit Vista...?

Also, when I try to query objPrintDocument.PrinterSettings.PrinterName, it
returns "Default printer is not set.", though it definitely is...

The Exception generated still doesn't have any value for InnerException, and
the <Exception>.TargetSite.Name is "HdevmodeInternal" - I can't even find
that anywhere in Google!


--
http://www.markrae.net

Willy Denoyette [MVP]

unread,
Jun 9, 2007, 8:29:25 AM6/9/07
to
"Mark Rae" <ma...@markNOSPAMrae.net> wrote in message
news:u4XRsnoq...@TK2MSFTNGP04.phx.gbl...

Yep, both X86 and X64 flavors work on 64-bit Vista Ultimate.

Note that I'm allways adding an application manifest to my executable
assemblies. If you don't add a manifest to an application that runs under
wow64, this application will get a virtualized view of the registry (part
off) and the file system (part off).

To prevent virtualization you have to add a manifest like this:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0"
name="MyApplication.app"></assemblyIdentity>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel
level="asInvoker"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

save above contents in a file named "MyApplication.manifest", where
"MyApplication" is the name of the assembly (not absolutely required any
name will do as manifest filename).
When done, run the following command:
mt -manifest MyApplication.manifest -outputresource:MyApplication.exe;#1

mt.exe is part of VS2005.

I'm not sure this will be of any help, but it's worth a try.

Willy.


Mark Rae

unread,
Jun 9, 2007, 8:42:35 AM6/9/07
to
"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
news:uKrwfHpq...@TK2MSFTNGP04.phx.gbl...

> I'm not sure this will be of any help, but it's worth a try.

Didn't help, unfortunately...

However, I'm wondering if there's something more fundamental going on
here...

When I run e.g. Word 2007, it "sees" the collection of printers installed,
and selects the default one.

However, when I open a PDF in Acrobat Reader 8.0 and try to print it, I get
a MessageBox saying:

"Before you can perform print-related tasks such as page setup or printing a
document, you need to install a printer."

Maybe Word and Acrobat Reader are using different methods to interrogate the
collection if installed printers...?


--
http://www.markrae.net

Mark Rae

unread,
Jun 9, 2007, 8:46:39 AM6/9/07
to
"Mark Rae" <ma...@markNOSPAMrae.net> wrote in message
news:unb$1OpqHH...@TK2MSFTNGP04.phx.gbl...

> However, I'm wondering if there's something more fundamental going on
> here...

Also, when debugging the app in VS.NET 2005 and I force it to quit as soon
as the Exception is thrown, the Output window shows:

"A first chance exception of type
'System.Drawing.Printing.InvalidPrinterException' occurred in
System.Drawing.dll"


--
http://www.markrae.net

Willy Denoyette [MVP]

unread,
Jun 9, 2007, 10:09:01 AM6/9/07
to
"Mark Rae" <ma...@markNOSPAMrae.net> wrote in message
news:unb$1OpqHH...@TK2MSFTNGP04.phx.gbl...

> "Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
> news:uKrwfHpq...@TK2MSFTNGP04.phx.gbl...
>
>> I'm not sure this will be of any help, but it's worth a try.
>
> Didn't help, unfortunately...
>
> However, I'm wondering if there's something more fundamental going on
> here...
>
> When I run e.g. Word 2007, it "sees" the collection of printers installed,
> and selects the default one.
>
> However, when I open a PDF in Acrobat Reader 8.0 and try to print it, I
> get a MessageBox saying:
>
> "Before you can perform print-related tasks such as page setup or printing
> a
> document, you need to install a printer."
>

This is basically the same error as yours.
I'm running AR 8.1.0 and everything works as expected.

> Maybe Word and Acrobat Reader are using different methods to interrogate
> the collection if installed printers...?
>

Probably they do.
Note that .NET uses PrintDlg from comdlg32.dll (SysWow64), probably Adobe
uses the same.

Could you try this?

// start of code X86 only!
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace Willys
{
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto, Pack=0x1)]
public class PRINTDLG
{
public int lStructSize;
public IntPtr hwndOwner;
public IntPtr hDevMode;
public IntPtr hDevNames;
public IntPtr hDC;
public int Flags;
public short nFromPage;
public short nToPage;
public short nMinPage;
public short nMaxPage;
public short nCopies;
public IntPtr hInstance;
public IntPtr lCustData;
public IntPtr lpfnPrintHook;
public IntPtr lpfnSetupHook;
public string lpPrintTemplateName;
public string lpSetupTemplateName;
public IntPtr hPrintTemplate;
public IntPtr hSetupTemplate;
}

class Program
{
[DllImport("comdlg32.dll", CharSet=CharSet.Auto, SetLastError=true)]
static extern int PrintDlg([In, Out] PRINTDLG lppd);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true,
ExactSpelling=true)]
public static extern IntPtr GlobalLock(HandleRef handle);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true,
ExactSpelling=true)]
public static extern bool GlobalUnlock(HandleRef handle);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true,
ExactSpelling=true)]
public static extern IntPtr GlobalFree(HandleRef handle);

static void Main()
{
Console.WriteLine(GetDefaultPrinterName());
}
private static PRINTDLG CreatePRINTDLG()
{
PRINTDLG printdlg = new PRINTDLG();
printdlg.lStructSize = Marshal.SizeOf(typeof(PRINTDLG));
printdlg.hwndOwner = IntPtr.Zero;
printdlg.hDevMode = IntPtr.Zero;
printdlg.hDevNames = IntPtr.Zero;
printdlg.Flags = 0x0;
printdlg.hwndOwner = IntPtr.Zero;
printdlg.hDC = IntPtr.Zero;
printdlg.nFromPage = 0x1;
printdlg.nToPage = 0x1;
printdlg.nMinPage = 0x0;
printdlg.nMaxPage = 0x270f;
printdlg.nCopies = 0x1;
printdlg.hInstance = IntPtr.Zero;
printdlg.lCustData = IntPtr.Zero;
printdlg.lpfnPrintHook = IntPtr.Zero;
printdlg.lpfnSetupHook = IntPtr.Zero;
printdlg.lpPrintTemplateName = null;
printdlg.lpSetupTemplateName = null;
printdlg.hPrintTemplate = IntPtr.Zero;
printdlg.hSetupTemplate = IntPtr.Zero;
return printdlg;
}
static string GetDefaultPrinterName()
{
PRINTDLG printdlg = CreatePRINTDLG();
printdlg.Flags = 0x400; //PD_RETURNDEFAULT
if (PrintDlg(printdlg) == 0)
return "No Default Printer Set";
IntPtr hDevNames = printdlg.hDevNames;
IntPtr handle = GlobalLock(new HandleRef(printdlg, hDevNames));
if (handle == IntPtr.Zero)
throw new Win32Exception();
// calculate offset of dev names in DEVNAMES struct allocated by
PrintDlg
// X86 platforms only!!!!!!!!
int devOffset = Marshal.SystemDefaultCharSize *
Marshal.ReadInt16((IntPtr) (((int) handle) + 2));
string name = Marshal.PtrToStringAuto((IntPtr) (((int) handle) +
devOffset));
GlobalUnlock(new HandleRef(printdlg, hDevNames));
GlobalFree(new HandleRef(printdlg, printdlg.hDevNames));
GlobalFree(new HandleRef(printdlg, printdlg.hDevMode));
return name;
}
}
}
// end of code

If this doesn't work, you have a fundamental issue, not related to .NET.
Sure you can also give WMI a try.
Willy.

Mark Rae

unread,
Jun 9, 2007, 10:28:22 AM6/9/07
to
"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
news:e56cA$pqHHA...@TK2MSFTNGP05.phx.gbl...

> Could you try this?

That returns "No Default Printer Set"

> If this doesn't work, you have a fundamental issue, not related to .NET.

Hmm - that's a bit worrying... :-(

> Sure you can also give WMI a try.

WMI works perfectly, however...

using (ManagementObjectSearcher objMOS = new
ManagementObjectSearcher("SELECT * FROM Win32_Printer"))
{
Dictionary<string, bool> dicResults = new Dictionary<string, bool>();
using (ManagementObjectCollection objMOC = objMOS.Get())
{
foreach (ManagementObject objMO in objMOC)
{
dicResults.Add(objMO["Name"].ToString(),
Convert.ToBoolean(objMO["Default"]));
}
}
return dicResults;
}


--
http://www.markrae.net

Willy Denoyette [MVP]

unread,
Jun 9, 2007, 11:06:34 AM6/9/07
to
"Mark Rae" <ma...@markNOSPAMrae.net> wrote in message
news:OrLj9Jqq...@TK2MSFTNGP05.phx.gbl...

> "Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
> news:e56cA$pqHHA...@TK2MSFTNGP05.phx.gbl...
>
>> Could you try this?
>
> That returns "No Default Printer Set"
>

That means that the PrintDlg call returns 0, which means "failure" to get
the default printer..... which does not necessarily means there is no
default printer :-)


>> If this doesn't work, you have a fundamental issue, not related to .NET.
>
> Hmm - that's a bit worrying... :-(
>
>> Sure you can also give WMI a try.
>
> WMI works perfectly, however...
>
> using (ManagementObjectSearcher objMOS = new
> ManagementObjectSearcher("SELECT * FROM Win32_Printer"))
> {
> Dictionary<string, bool> dicResults = new Dictionary<string, bool>();
> using (ManagementObjectCollection objMOC = objMOS.Get())
> {
> foreach (ManagementObject objMO in objMOC)
> {
> dicResults.Add(objMO["Name"].ToString(),
> Convert.ToBoolean(objMO["Default"]));
> }
> }
> return dicResults;
> }
>
>
> --
> http://www.markrae.net


WMI does not use comdlg32.dll, anyway, it looks like there the issue is with
the 32bit version of the common dialog component or (more probably) one of
it's dependents. Mind to check the version installed in %windir%\SysWow64? I
have 6.0.6000.16386, however I can't believe yours would be different.

Willy.


Willy Denoyette [MVP]

unread,
Jun 9, 2007, 11:20:31 AM6/9/07
to
"Mark Rae" <ma...@markNOSPAMrae.net> wrote in message
news:OrLj9Jqq...@TK2MSFTNGP05.phx.gbl...

Note that you can simplify/optimize your query like this:

string DefaultPrinterName() {
string defaultPrinter = null;
SelectQuery q = new SelectQuery("select caption from win32_printer where
default = true");
using(ManagementObjectSearcher searcher = new
ManagementObjectSearcher(q))
{
foreach (ManagementObject printer in searcher.Get()) {
defaultPrinter = printer["Caption"].ToString();
}
}
return defaultPrinter;
}

Willy.

Mark Rae

unread,
Jun 9, 2007, 12:09:44 PM6/9/07
to
"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
news:u%23RpYeqq...@TK2MSFTNGP03.phx.gbl...

>> That returns "No Default Printer Set"
>
> That means that the PrintDlg call returns 0, which means "failure" to get
> the default printer..... which does not necessarily means there is no
> default printer :-)

OK... Do I need to be concerned about this, do you think...?

> WMI does not use comdlg32.dll, anyway, it looks like there the issue is
> with the 32bit version of the common dialog component or (more probably)
> one of it's dependents. Mind to check the version installed in
> %windir%\SysWow64? I have 6.0.6000.16386, however I can't believe yours
> would be different.

Yes - that's what I have...


--
http://www.markrae.net

Mark Rae

unread,
Jun 9, 2007, 12:13:35 PM6/9/07
to
"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
news:OHk4Kmqq...@TK2MSFTNGP03.phx.gbl...

> Note that you can simplify/optimize your query like this:
>
> string DefaultPrinterName() {
> string defaultPrinter = null;
> SelectQuery q = new SelectQuery("select caption from win32_printer
> where default = true");
> using(ManagementObjectSearcher searcher = new
> ManagementObjectSearcher(q))
> {
> foreach (ManagementObject printer in searcher.Get()) {
> defaultPrinter = printer["Caption"].ToString();
> }
> }
> return defaultPrinter;
> }

Yes indeed - my method is part of a WMI base class which returns several of
these collections (OperatingSystem, ComputerSystem, BIOS, Processor,
PhysicalMemory, Printer etc), so I don't really need an extra method to
return the default printer specifically. I do appreciate, however, that that
would represent a small performance boost, especially on a system with very
many printers installed...


--
http://www.markrae.net

Willy Denoyette [MVP]

unread,
Jun 9, 2007, 1:49:15 PM6/9/07
to
"Mark Rae" <ma...@markNOSPAMrae.net> wrote in message
news:%23CgZmCr...@TK2MSFTNGP06.phx.gbl...

> "Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
> news:u%23RpYeqq...@TK2MSFTNGP03.phx.gbl...
>
>>> That returns "No Default Printer Set"
>>
>> That means that the PrintDlg call returns 0, which means "failure" to get
>> the default printer..... which does not necessarily means there is no
>> default printer :-)
>
> OK... Do I need to be concerned about this, do you think...?
>

It's not that critical, but as it applies to all applications that use
PrintDlg, I would suggest you to post a bug request in the connect site,
especially because this was done for a 64-bit Vista beta (you do run an RTM
version I suppose), but was apparently closed with status "non
reproducible".

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=242908


Willy.

Mark Rae

unread,
Jun 9, 2007, 3:07:48 PM6/9/07
to
"Willy Denoyette [MVP]" <willy.d...@telenet.be> wrote in message
news:%23AdOS5r...@TK2MSFTNGP05.phx.gbl...

>> OK... Do I need to be concerned about this, do you think...?
>>
>
> It's not that critical, but as it applies to all applications that use
> PrintDlg, I would suggest you to post a bug request in the connect site,
> especially because this was done for a 64-bit Vista beta (you do run an
> RTM version I suppose), but was apparently closed with status "non
> reproducible".
>
> http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=242908

I have done so (I am running RTM).


--
http://www.markrae.net

0 new messages