Printing Issue

A

Alex Clark

Hi,

I'm having an unusual printing problem in my .NET app which I think may be a
permissions issue. If I log on to my network as an Administrator, my
application will print without any problem at all. If I log in as a
restricted user, I get an InvalidPrinterException stating that there are no
printers installed - there are, I installed them myself!

The really strange issue is that if I try printing from MS Word when logged
in under the restricted account, that works perfectly. If I grant the
"Manage Documents" priv to my restricted account, my application prints
perfectly. What is the framework doing printer-wise that requires the
"Manage Documents" priv? My client understandably doesn't want to grant
that privilege to all their users. What gives?

Thanks,
Alex Clark
 
A

Alex Clark

Hi,

Sample code below. Please note that the exception is thrown when attempting
to show the print preview dialog in its CreateHandle method.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click

Try

If dlgPreview.ShowDialog = DialogResult.OK Then

pdocTest.Print()

End If

Catch ex As Exception

MessageBox.Show(ex.ToString)

End Try



End Sub

Private Sub pdocTest_PrintPage(ByVal sender As System.Object, ByVal e As
System.Drawing.Printing.PrintPageEventArgs) Handles pdocTest.PrintPage

With e.Graphics

..DrawRectangle(Pens.Black, New Rectangle(25, 25, 40, 40))

..DrawString("This is a test document", Me.Font, Brushes.Black, 30, 30)

..DrawEllipse(Pens.Black, 40, 80, 20, 20)

e.HasMorePages = False

End With

End Sub
 
J

Jeffrey Tan[MSFT]

Hi Alex ,

Thanks for your feedback.

I have created a test Power Users account on my machine, then test your
sample code in this account. Yes, I can reproduce out this problem on my
side. This exception occurs in PrintPreviewDialog.CreateHandle.

If we use Reflector to view the source code, we will see that:
protected override void CreateHandle()
{
if ((this.Document != null) && !this.Document.PrinterSettings.IsValid)
{
throw new
InvalidPrinterException(this.Document.PrinterSettings);
}
base.CreateHandle();
}

Then I added the test code:
bool f=this.printDocument1.PrinterSettings.IsValid;

For the test account, the result is false, which caused out the
InvalidPrinterException exception.

Further invest in System.Drawing.Printing.PrinterSettings.IsValid in
Reflector, I got the following code:
public bool IsValid
{
get
{
return (this.DeviceCapabilities(0x12, IntPtr.Zero, -1) != -1);
}
}

private int DeviceCapabilities(short capability, IntPtr pointerToBuffer,
int defaultValue)
{
IntSecurity.AllPrinting.Assert();
string text1 = this.PrinterName;
CodeAccessPermission.RevertAssert();
IntSecurity.UnmanagedCode.Assert();
return this.FastDeviceCapabilities(capability, pointerToBuffer,
defaultValue, text1);
}

private int FastDeviceCapabilities(short capability, IntPtr
pointerToBuffer, int defaultValue, string printerName)
{
int num1 = SafeNativeMethods.DeviceCapabilities(printerName,
this.OutputPort, capability, pointerToBuffer, IntPtr.Zero);
if (num1 == -1)
{
return defaultValue;
}
return num1;
}

After setting breakpoing in these methods one-by-one(you should setup the
debug symbols correctly, also, I used Win2003 RunAs function to run VS.net
under the test accout, so that I can do debugging under this test account),
I find that DeviceCapabilities Win32 API failed and returns -1. Calling
System.Runtime.InteropServices.Marshal.GetLastWin32Error(), I got the error
message below: "The printer name is invalid".

It seems that PrinterSettings.PrinterName property returns the incorrect
printer name. Then I checked into the PrinterName property, I get these:

public string get_PrinterName()
{
IntSecurity.AllPrinting.Demand();
return this.PrinterNameInternal;
}

private string get_PrinterNameInternal()
{
if (this.printerName == null)
{
return PrinterSettings.GetDefaultPrinterName();
}
return this.printerName;
}

private static string GetDefaultPrinterName()
{
IntSecurity.UnmanagedCode.Assert();
SafeNativeMethods.PRINTDLG printdlg1 =
PrinterSettings.CreatePRINTDLG();
printdlg1.Flags = 0x400;
if (!SafeNativeMethods.PrintDlg(printdlg1))
{
return SR.GetString("NoDefaultPrinter");
}
IntPtr ptr1 = printdlg1.hDevNames;
IntPtr ptr2 = SafeNativeMethods.GlobalLock(new HandleRef(printdlg1,
ptr1));
if (ptr2 == IntPtr.Zero)
{
throw new Win32Exception();
}
string text1 = PrinterSettings.ReadOneDEVNAME(ptr2, 1);
SafeNativeMethods.GlobalUnlock(new HandleRef(printdlg1, ptr1));
ptr2 = IntPtr.Zero;
SafeNativeMethods.GlobalFree(new HandleRef(printdlg1,
printdlg1.hDevNames));
SafeNativeMethods.GlobalFree(new HandleRef(printdlg1,
printdlg1.hDevMode));
return text1;
}

I finally get that the SafeNativeMethods.PrintDlg return false, so no
default printer name is returned(returned by
SR.GetString("NoDefaultPrinter"); statement).

SafeNativeMethods.PrintDlg is a Win32 API, which .Net p/invoked it. Then I
write a MFC application to test this API in Win32 world:

void CMFCPrintDlgTestDlg::OnBnClickedButton1()
{
PRINTDLG printdlg1;
HWND hwnd;

// Initialize PRINTDLG
ZeroMemory(&printdlg1, sizeof(printdlg1));

printdlg1.lStructSize = 0x42;
printdlg1.hwndOwner = 0;
printdlg1.hDevMode = 0;
printdlg1.hDevNames = 0;
printdlg1.Flags = 0;
printdlg1.hwndOwner = 0;
printdlg1.hDC = 0;
printdlg1.nFromPage = 1;
printdlg1.nToPage = 1;
printdlg1.nMinPage = 0;
printdlg1.nMaxPage = 0x270f;
printdlg1.nCopies = 1;
printdlg1.hInstance = 0;
printdlg1.lCustData = 0;
printdlg1.lpfnPrintHook = NULL;
printdlg1.lpfnSetupHook = NULL;
printdlg1.lpPrintTemplateName = NULL;
printdlg1.lpSetupTemplateName = NULL;
printdlg1.hPrintTemplate = 0;
printdlg1.hSetupTemplate = 0;
printdlg1.Flags = 0x400;

if (PrintDlg(&printdlg1)==TRUE)
{
MessageBox("Succeeded!");
DeleteDC(printdlg1.hDC);
}
else
{
char buf[50];
wsprintf(buf, "error: %d",GetLastError());
MessageBox(buf, buf);
}
}
Testing with the test account, I also can reproduce out the problem. Also,
the key point is for setting PRINTDLG.Flags to 0x400, which is
PD_RETURNDEFAULT const.

Yes, after enabling "Manage Documents" permission on the printer for test
account, the problem will go away. But I am not sure why PrintDlg with
PD_RETURNDEFAULT require "Manage Documents" permission.

Currently, I do not think there is any good solution for this issue, maybe
we have to setup "Manage Documents" permission for all the non-admin
accounts.(Yes, you can documented this in your application)

Finally, if you want to submit a bug for microsoft, I suggest you contact
Microsoft PSS for it.

You can contact Microsoft Product Support by contacting us at
1-(800)936-5800 or by choosing one of the options listed at
http://www.microsoft.com/services/microsoftservices/supp.mspx

Hope this information helps

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
C

Collin Bennett

Great debugging information. You have to show me how you do that. :)

Hi Alex ,

Thanks for your feedback.

I have created a test Power Users account on my machine, then test your
sample code in this account. Yes, I can reproduce out this problem on my
side. This exception occurs in PrintPreviewDialog.CreateHandle.

If we use Reflector to view the source code, we will see that:
protected override void CreateHandle()
{
if ((this.Document != null) && !this.Document.PrinterSettings.IsValid)
{
throw new
InvalidPrinterException(this.Document.PrinterSettings);
}
base.CreateHandle();
}

Then I added the test code:
bool f=this.printDocument1.PrinterSettings.IsValid;

For the test account, the result is false, which caused out the
InvalidPrinterException exception.

Further invest in System.Drawing.Printing.PrinterSettings.IsValid in
Reflector, I got the following code:
public bool IsValid
{
get
{
return (this.DeviceCapabilities(0x12, IntPtr.Zero, -1) != -1);
}
}

private int DeviceCapabilities(short capability, IntPtr pointerToBuffer,
int defaultValue)
{
IntSecurity.AllPrinting.Assert();
string text1 = this.PrinterName;
CodeAccessPermission.RevertAssert();
IntSecurity.UnmanagedCode.Assert();
return this.FastDeviceCapabilities(capability, pointerToBuffer,
defaultValue, text1);
}

private int FastDeviceCapabilities(short capability, IntPtr
pointerToBuffer, int defaultValue, string printerName)
{
int num1 = SafeNativeMethods.DeviceCapabilities(printerName,
this.OutputPort, capability, pointerToBuffer, IntPtr.Zero);
if (num1 == -1)
{
return defaultValue;
}
return num1;
}

After setting breakpoing in these methods one-by-one(you should setup the
debug symbols correctly, also, I used Win2003 RunAs function to run VS.net
under the test accout, so that I can do debugging under this test account),
I find that DeviceCapabilities Win32 API failed and returns -1. Calling
System.Runtime.InteropServices.Marshal.GetLastWin32Error(), I got the error
message below: "The printer name is invalid".

It seems that PrinterSettings.PrinterName property returns the incorrect
printer name. Then I checked into the PrinterName property, I get these:

public string get_PrinterName()
{
IntSecurity.AllPrinting.Demand();
return this.PrinterNameInternal;
}

private string get_PrinterNameInternal()
{
if (this.printerName == null)
{
return PrinterSettings.GetDefaultPrinterName();
}
return this.printerName;
}

private static string GetDefaultPrinterName()
{
IntSecurity.UnmanagedCode.Assert();
SafeNativeMethods.PRINTDLG printdlg1 =
PrinterSettings.CreatePRINTDLG();
printdlg1.Flags = 0x400;
if (!SafeNativeMethods.PrintDlg(printdlg1))
{
return SR.GetString("NoDefaultPrinter");
}
IntPtr ptr1 = printdlg1.hDevNames;
IntPtr ptr2 = SafeNativeMethods.GlobalLock(new HandleRef(printdlg1,
ptr1));
if (ptr2 == IntPtr.Zero)
{
throw new Win32Exception();
}
string text1 = PrinterSettings.ReadOneDEVNAME(ptr2, 1);
SafeNativeMethods.GlobalUnlock(new HandleRef(printdlg1, ptr1));
ptr2 = IntPtr.Zero;
SafeNativeMethods.GlobalFree(new HandleRef(printdlg1,
printdlg1.hDevNames));
SafeNativeMethods.GlobalFree(new HandleRef(printdlg1,
printdlg1.hDevMode));
return text1;
}

I finally get that the SafeNativeMethods.PrintDlg return false, so no
default printer name is returned(returned by
SR.GetString("NoDefaultPrinter"); statement).

SafeNativeMethods.PrintDlg is a Win32 API, which .Net p/invoked it. Then I
write a MFC application to test this API in Win32 world:

void CMFCPrintDlgTestDlg::OnBnClickedButton1()
{
PRINTDLG printdlg1;
HWND hwnd;

// Initialize PRINTDLG
ZeroMemory(&printdlg1, sizeof(printdlg1));

printdlg1.lStructSize = 0x42;
printdlg1.hwndOwner = 0;
printdlg1.hDevMode = 0;
printdlg1.hDevNames = 0;
printdlg1.Flags = 0;
printdlg1.hwndOwner = 0;
printdlg1.hDC = 0;
printdlg1.nFromPage = 1;
printdlg1.nToPage = 1;
printdlg1.nMinPage = 0;
printdlg1.nMaxPage = 0x270f;
printdlg1.nCopies = 1;
printdlg1.hInstance = 0;
printdlg1.lCustData = 0;
printdlg1.lpfnPrintHook = NULL;
printdlg1.lpfnSetupHook = NULL;
printdlg1.lpPrintTemplateName = NULL;
printdlg1.lpSetupTemplateName = NULL;
printdlg1.hPrintTemplate = 0;
printdlg1.hSetupTemplate = 0;
printdlg1.Flags = 0x400;

if (PrintDlg(&printdlg1)==TRUE)
{
MessageBox("Succeeded!");
DeleteDC(printdlg1.hDC);
}
else
{
char buf[50];
wsprintf(buf, "error: %d",GetLastError());
MessageBox(buf, buf);
}
}
Testing with the test account, I also can reproduce out the problem. Also,
the key point is for setting PRINTDLG.Flags to 0x400, which is
PD_RETURNDEFAULT const.

Yes, after enabling "Manage Documents" permission on the printer for test
account, the problem will go away. But I am not sure why PrintDlg with
PD_RETURNDEFAULT require "Manage Documents" permission.

Currently, I do not think there is any good solution for this issue, maybe
we have to setup "Manage Documents" permission for all the non-admin
accounts.(Yes, you can documented this in your application)

Finally, if you want to submit a bug for microsoft, I suggest you contact
Microsoft PSS for it.

You can contact Microsoft Product Support by contacting us at
1-(800)936-5800 or by choosing one of the options listed at
http://www.microsoft.com/services/microsoftservices/supp.mspx

Hope this information helps

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
A

Alex Clark

Hi Jeffrey,

I've submitted it as a bug report to MSDN Online Feedback with all necessary
information. After some more testing in my office I've deduced it may be
something to do with account impersonation, ie using the "Run As" command
rather than logging in directly as the test account and running it from
that.

My customer's been having this problem with their users running the app
through Citrix/Remote Desktop, which I assume is essentially impersonating
the user that logs in via it. Maybe it's not finding a default printer in
the user's profile settings until they've physically logged in on the
console?

Thanks,
Alex Clark





"Jeffrey Tan[MSFT]" said:
Hi Alex ,

Thanks for your feedback.

I have created a test Power Users account on my machine, then test your
sample code in this account. Yes, I can reproduce out this problem on my
side. This exception occurs in PrintPreviewDialog.CreateHandle.

If we use Reflector to view the source code, we will see that:
protected override void CreateHandle()
{
if ((this.Document != null) &&
!this.Document.PrinterSettings.IsValid)
{
throw new
InvalidPrinterException(this.Document.PrinterSettings);
}
base.CreateHandle();
}

Then I added the test code:
bool f=this.printDocument1.PrinterSettings.IsValid;

For the test account, the result is false, which caused out the
InvalidPrinterException exception.

Further invest in System.Drawing.Printing.PrinterSettings.IsValid in
Reflector, I got the following code:
public bool IsValid
{
get
{
return (this.DeviceCapabilities(0x12, IntPtr.Zero, -1) != -1);
}
}

private int DeviceCapabilities(short capability, IntPtr pointerToBuffer,
int defaultValue)
{
IntSecurity.AllPrinting.Assert();
string text1 = this.PrinterName;
CodeAccessPermission.RevertAssert();
IntSecurity.UnmanagedCode.Assert();
return this.FastDeviceCapabilities(capability, pointerToBuffer,
defaultValue, text1);
}

private int FastDeviceCapabilities(short capability, IntPtr
pointerToBuffer, int defaultValue, string printerName)
{
int num1 = SafeNativeMethods.DeviceCapabilities(printerName,
this.OutputPort, capability, pointerToBuffer, IntPtr.Zero);
if (num1 == -1)
{
return defaultValue;
}
return num1;
}

After setting breakpoing in these methods one-by-one(you should setup the
debug symbols correctly, also, I used Win2003 RunAs function to run VS.net
under the test accout, so that I can do debugging under this test
account),
I find that DeviceCapabilities Win32 API failed and returns -1. Calling
System.Runtime.InteropServices.Marshal.GetLastWin32Error(), I got the
error
message below: "The printer name is invalid".

It seems that PrinterSettings.PrinterName property returns the incorrect
printer name. Then I checked into the PrinterName property, I get these:

public string get_PrinterName()
{
IntSecurity.AllPrinting.Demand();
return this.PrinterNameInternal;
}

private string get_PrinterNameInternal()
{
if (this.printerName == null)
{
return PrinterSettings.GetDefaultPrinterName();
}
return this.printerName;
}

private static string GetDefaultPrinterName()
{
IntSecurity.UnmanagedCode.Assert();
SafeNativeMethods.PRINTDLG printdlg1 =
PrinterSettings.CreatePRINTDLG();
printdlg1.Flags = 0x400;
if (!SafeNativeMethods.PrintDlg(printdlg1))
{
return SR.GetString("NoDefaultPrinter");
}
IntPtr ptr1 = printdlg1.hDevNames;
IntPtr ptr2 = SafeNativeMethods.GlobalLock(new HandleRef(printdlg1,
ptr1));
if (ptr2 == IntPtr.Zero)
{
throw new Win32Exception();
}
string text1 = PrinterSettings.ReadOneDEVNAME(ptr2, 1);
SafeNativeMethods.GlobalUnlock(new HandleRef(printdlg1, ptr1));
ptr2 = IntPtr.Zero;
SafeNativeMethods.GlobalFree(new HandleRef(printdlg1,
printdlg1.hDevNames));
SafeNativeMethods.GlobalFree(new HandleRef(printdlg1,
printdlg1.hDevMode));
return text1;
}

I finally get that the SafeNativeMethods.PrintDlg return false, so no
default printer name is returned(returned by
SR.GetString("NoDefaultPrinter"); statement).

SafeNativeMethods.PrintDlg is a Win32 API, which .Net p/invoked it. Then I
write a MFC application to test this API in Win32 world:

void CMFCPrintDlgTestDlg::OnBnClickedButton1()
{
PRINTDLG printdlg1;
HWND hwnd;

// Initialize PRINTDLG
ZeroMemory(&printdlg1, sizeof(printdlg1));

printdlg1.lStructSize = 0x42;
printdlg1.hwndOwner = 0;
printdlg1.hDevMode = 0;
printdlg1.hDevNames = 0;
printdlg1.Flags = 0;
printdlg1.hwndOwner = 0;
printdlg1.hDC = 0;
printdlg1.nFromPage = 1;
printdlg1.nToPage = 1;
printdlg1.nMinPage = 0;
printdlg1.nMaxPage = 0x270f;
printdlg1.nCopies = 1;
printdlg1.hInstance = 0;
printdlg1.lCustData = 0;
printdlg1.lpfnPrintHook = NULL;
printdlg1.lpfnSetupHook = NULL;
printdlg1.lpPrintTemplateName = NULL;
printdlg1.lpSetupTemplateName = NULL;
printdlg1.hPrintTemplate = 0;
printdlg1.hSetupTemplate = 0;
printdlg1.Flags = 0x400;

if (PrintDlg(&printdlg1)==TRUE)
{
MessageBox("Succeeded!");
DeleteDC(printdlg1.hDC);
}
else
{
char buf[50];
wsprintf(buf, "error: %d",GetLastError());
MessageBox(buf, buf);
}
}
Testing with the test account, I also can reproduce out the problem. Also,
the key point is for setting PRINTDLG.Flags to 0x400, which is
PD_RETURNDEFAULT const.

Yes, after enabling "Manage Documents" permission on the printer for test
account, the problem will go away. But I am not sure why PrintDlg with
PD_RETURNDEFAULT require "Manage Documents" permission.

Currently, I do not think there is any good solution for this issue, maybe
we have to setup "Manage Documents" permission for all the non-admin
accounts.(Yes, you can documented this in your application)

Finally, if you want to submit a bug for microsoft, I suggest you contact
Microsoft PSS for it.

You can contact Microsoft Product Support by contacting us at
1-(800)936-5800 or by choosing one of the options listed at
http://www.microsoft.com/services/microsoftservices/supp.mspx

Hope this information helps

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Alex,

Thanks for your feedback.

Based on my knowledge, adding the printer should not be a profile related
operation, it should be system wide operation. I have tried logging with
the test account using remote desktop, in this remote desktop, I can see
the printers without any problem.

Also, as we can see normal notepad, word and other applications do not have
printing issue under test account, so it should be winform implementation
issue.

Anyway, I think your bug submi should get some useful comment from our
product team. You can wait for it. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
A

Alex Clark

Hi Jeffrey,

MS Product Feedback have responded saying that it's not a bug, but that
there's no default printer assigned to the user profile in question. I'm
not sure that this is consistent with our findings - would it make sense
that although the printer has been added to the machine globally, it's not
set as the default for users who haven't yet logged in? I'm fairly certain
that it's not a default printer issue, as I've experienced this running over
an RDP session to a W2003 Server and I *know* I have a default printer set
up. Also, it wouldn't explain why granting the manage-documents privilege
would solve the problem. Any ideas?

Kind Regards,
Alex Clark
 
A

Alex Clark

Hi Jeffrey,

I've just confirmed that this is not due to a lack of a default printer. I
logged into my customer's W2003 Server via RDP as a local administrator,
confirmed that I do have a default printer installed, and still I got the
same error. Product Feedback have closed my bug report as being "By
Design", saying that it's a default printer issue. Is there any way you can
get in touch with them directly, as I'd hate to see this bug get included in
Whidbey :-(

Thanks,
Alex Clark



Alex Clark said:
Hi Jeffrey,

MS Product Feedback have responded saying that it's not a bug, but that
there's no default printer assigned to the user profile in question. I'm
not sure that this is consistent with our findings - would it make sense
that although the printer has been added to the machine globally, it's not
set as the default for users who haven't yet logged in? I'm fairly
certain that it's not a default printer issue, as I've experienced this
running over an RDP session to a W2003 Server and I *know* I have a
default printer set up. Also, it wouldn't explain why granting the
manage-documents privilege would solve the problem. Any ideas?

Kind Regards,
Alex Clark




"Jeffrey Tan[MSFT]" said:
Hi Alex,

Thanks for your feedback.

Based on my knowledge, adding the printer should not be a profile related
operation, it should be system wide operation. I have tried logging with
the test account using remote desktop, in this remote desktop, I can see
the printers without any problem.

Also, as we can see normal notepad, word and other applications do not
have
printing issue under test account, so it should be winform implementation
issue.

Anyway, I think your bug submi should get some useful comment from our
product team. You can wait for it. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no
rights.
 
A

Alex Clark

Hi Jeffrey,

Sorry for the bombardment but I think I've narrowed down the precise issue.
While testing on the W2003 Server box, I found that despite there being over
a dozen printers installed (and me being logged in as a local admin), I got
the same error. This happened even though I'd set one of the printers as my
default. However, if I tried to view the properties of any of the printers
in Control Panel, I only had read-only access to view the security
permissions associated with them.

If, however, I manually added a new printer by searching the Active
Directory and then set that as the default, my test application worked fine.
I believe there is a flaw in the printing subsystem of .NET whereby it's
instantly trying to do something with the default printer the moment you try
to do anything so much as a print-preview, and it fails if the current user
account either doesn't have sufficient privs or isn't the owner/creator of
the printer object - it is assuming it will have elevated privileges on the
default printer object, which must by definition be a security related bug
in the framework.


Kind Regards,
Alex Clark
 
J

Jeffrey Tan[MSFT]

Hi Alex,

Just as I replied in last reply, I can see the printers with test account
through RDP, so I have the same findings as you.

Currently, I have found the bug you submited in our internal database. I
will contact the bug owner directly for this issue. However, as we can see
it is resolved as "Postponed" due to their product cycle limit, I am not
sure if they have time to resolve this issue ASAP.

Anyway, I will feedback any further progress here. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Alex,

Sorry for letting you wait for so long.

I have contacted the bug owner for this issue. Yes, they have confirmed
that my troubleshooting way is correct, it is PrintDlg API fails with Flags
0x400 that caused Winform PrintPreviewControl throw the exception.

However, the root cause for the problem is still that there is no default
printer for the test account. We can do the test like this:
1. Do your repro logged in as "A" and using Run-As "B"
2. Now log out of the machine and re-log in as "B"
3. Add a new printer and set it as the default (there should be no current
printers other than possibly a fax "printer")
4. Now log off and back onto "a"
5. Redo your repro and you will see that it works.

This shows that once another account has the printer installed, no
exception will generate.

In the test on my side, if we enable ManageDocument permission on the
printer, even more, if we unchecked this permission, for "test account" the
problem will not arise anymore, it seems that turning on this permission
triggered certain flag in the system.(I am not sure if you notice this, but
this is the test result in more thatn 3 machines on my side)
From our product team, they say that this implies that its not really a
security issue. Whats most likely happening is that by enabling
ManageDocument permission on a certain printer -- you are exposing that
printer to the other accounts -- thereby creating a default printer. Then
when you disable the permission, it doesn't actually matter since you
created the printer.

So, we suggest the following KB, which shows how to add default printer for
all new users:
"How to Add a Default Printer for All New Users"
http://support.microsoft.com/default.aspx?scid=kb;en-us;252388

Hope this makes sense to you. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
A

Alex Clark

Hi Jeffrey,

No problem about the delay, thankyou for following it up :)

I'm still not convinced that this is exclusively a default printer issue.
As stated in one of my previous posts, I was able to log in as user "B"
after adding printers as user "A", and set one of the printers that were
already there to be my default - however, the test application still
crashed. It was only when I added my own printer in while logged in as user
"B" and setting that as the default that I could actually print.

From my tests it seems that even if you have a default printer, unless you
have ownership of some form over it you will still get the same problem.

Also, I assume MS are still treating this as a bug? I'd hate to see my app
crash simply because there is no default printer available! I'm already
testing for the presence of printers beforehand, but of course the Printers
Collection always returns the number of printers installed on the system -
not the number of printers *available* for use. Surely the framework should
at least be reporting a meaningful error message and giving you the option
to test for a default accessible printer beforehand? And surely it
shouldn't crash when displaying the Print Preview - before anything is even
sent to the printer!

Kind Regards,
Alex Clark





"Jeffrey Tan[MSFT]" said:
Hi Alex,

Sorry for letting you wait for so long.

I have contacted the bug owner for this issue. Yes, they have confirmed
that my troubleshooting way is correct, it is PrintDlg API fails with
Flags
0x400 that caused Winform PrintPreviewControl throw the exception.

However, the root cause for the problem is still that there is no default
printer for the test account. We can do the test like this:
1. Do your repro logged in as "A" and using Run-As "B"
2. Now log out of the machine and re-log in as "B"
3. Add a new printer and set it as the default (there should be no
current
printers other than possibly a fax "printer")
4. Now log off and back onto "a"
5. Redo your repro and you will see that it works.

This shows that once another account has the printer installed, no
exception will generate.

In the test on my side, if we enable ManageDocument permission on the
printer, even more, if we unchecked this permission, for "test account"
the
problem will not arise anymore, it seems that turning on this permission
triggered certain flag in the system.(I am not sure if you notice this,
but
this is the test result in more thatn 3 machines on my side)
From our product team, they say that this implies that its not really a
security issue. Whats most likely happening is that by enabling
ManageDocument permission on a certain printer -- you are exposing that
printer to the other accounts -- thereby creating a default printer. Then
when you disable the permission, it doesn't actually matter since you
created the printer.

So, we suggest the following KB, which shows how to add default printer
for
all new users:
"How to Add a Default Printer for All New Users"
http://support.microsoft.com/default.aspx?scid=kb;en-us;252388

Hope this makes sense to you. Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Alex,

Thanks for your feedback.

This is my test result:
1. I create an account "test1", Runas "test1" will result in
InvalidPrinterException.
2. If I add "test1" to "Remote Desktop Users" group, Runas "test1" will
still generate InvalidPrinterException
3. If I remote login "test1" from another machine, then I still Runas
"test1", the InvalidPrinterException will go away.

4. I create an account "test2", Runas "test2" will result in
InvalidPrinterException.
5. If I add "test2" to "Power Users" group, then add "Manage Document"
permission to "Power Users" group in default printer, then Runas "test1".
InvalidPrinterException will go away
// This is our original test result

6. I create an account "test3", Runas "test3" will result in
InvalidPrinterException.
7. Note: in #6, "Power Users" group has been added "Manage Document"
permission.
8. If I add "test3" to "Power Users" group, Runas "test3" will still
generate InvalidPrinterException
9. First uncheck "Manage Document" permission to "Power Users" group, then
re-add "Manage Document" permission to "Power Users" group in default
printer. Runas "test3", the InvalidPrinterException will go away.

#1 to #3 shows that real login will add a default printer to test1 account
that, will eliminate InvalidPrinterException(Without runas service, this
problem should go away? Although I still did not test with a real login, I
just test it with remote desktop)

#6 to #9 shows that the problem is not really the "Manage Document"
permission, but that enabling "Manage Document" permission will add a
default printer to "test3" account.(Or why "test3" has "Manage Document"
permission, it will still generate InvalidPrinterException in #8?)

Hope these tests clarify the problem.
Surely the framework should
at least be reporting a meaningful error message and giving you the option
to test for a default accessible printer beforehand
The exception for this problem is: InvalidPrinterException --"there are no
printers installed" really gives us a good hint that there is no default
printer install for another account. We should think from this way.

If your concern is the exception crashed the application, I think you can
explicitly handle this exception in your winform application. Also, you can
add an application-wide Applcation.ThreadException handler, this will
handle all the unhandled exception in the application even display a
customized notification dialog to the user. And application will not crash
at all.

Hope this helps.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
J

Jeffrey Tan[MSFT]

Hi Alex,

Thanks for your defailed feedback.

Sorry, I also have tested with this issue on more than 2 windows2003
machines, all work well after setting a default printer, so I do not
understand why you have different behavior. Because I can not reproduce
this crash on my side, I can not give any useful comment to you. Also,
based on the feedback from our product team, they should have the test
result as me, that is: this is after logging with another account and
setting a default printer under that account, the printing will not fail at
all.

So unless we can find a way to reproduce out your problem, the help I can
provide is limited. Maybe, you may contact the Microsoft PSS for case
support, then they may remote logging on to your machine to do some test on
your problematic machines.

Thanks for your understanding.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 
A

Alex Clark

Hi Jeffrey,

I've told my client to reset all permissions on their printers and to try
again. I've also informed them about the default printer issue, which
they're taking steps to correct once they've reset the permissions. I found
that deleting and reinstalling the printer on *my* server actually sorted
out the issue, so long as it was made available as the default for any user
that logged on. As the client recently upgraded to W2K3 Server, I think
it's possible that some permissions haven't been "cascaded" through to the
existing users when logging on to the new server.

I'm hoping that this will fix the issue, and thankyou very much for your
time and patience on this.

However, is there any indication that MS will make this a bit easier to
diagnose in .NET 2.0? I'm still getting the regular question from my client
as to why they cannot at least do a print-preview, and I have to agree that
it shouldn't throw an exception at that stage. Surely a "No Default
Printer" exception would be more appropriate at the stage of actually trying
to print, along with some method in the printing namespace just to test "If
DefaultPrinter Is Nothing Then....(handle it)" ?

Thanks for all your help,
Alex Clark
 
J

Jeffrey Tan[MSFT]

Hi Alex,

Thanks for your feedback.

Yes, I think your concern makes sense. We should can do the print preview
without an actual printer installed. I will forward this comment to the
product team. Also, I have found that our product has received similiar
problem concern, please refer to the link below:
"Suggestion Details: Allow custom PrintControllers to function with no
installed printer"
http://lab.msdn.microsoft.com/ProductFeedback/viewFeedback.aspx?feedbackid=e
efebc3f-ac93-4a6d-b4a8-7a47fb90cfb8

Currently, we still have to workaround this problem with install a
ThreadException for "InvalidPrinterException: No printers installed", then
recover from this exception.

Thanks

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top