PrintPreviewDialog and Win32Exception "The RPC server is unavailab

G

Guest

Hello.

I've got an issue with PrintPreviewDialog with an unhandled Win32Exception
when pressing the Print button. As far as I can tell the exception is raised
in a background thread that the framework is spawning. The exception is
raised if I preview to a network printer where either the password is
incorrect or the network printer is not online (more or less the same thing
really).

I would like to be able to just display a message like "printer unavailable"
to the user; but, I can't do that by catching the exception from another
thread. I.e. my entry into the PrintPreviewDialog is via the ShowDialog
method; catching the exception at that level means the dialog is abruptly
closed without warning and without printing anything.

If this problem has been encountered before, is there a recommended
workaround?

Thanks,
 
L

Linda Liu [MSFT]

Hi,

From your post, my understanding on this issue is that you have opened a
print preview dialog in your program. If the default printer is unavailable
and if you press the Print button in the print preview dialog, an unhandled
Win32Exception "The RPC server is unavailable" is raised. You want to catch
the exception. If I'm off base, please feel free to tell me.

You should handle the ThreadException event of Application object to catch
the untrapped thread exception. The following is a sample.

public Form1()
{
Application.ThreadException += new
System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
}

void Application_ThreadException(object sender,
System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message);
}

Hope this helps.

Sincerely,
Linda Liu
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Hi Karen. Thank you for your reply.

Your example does not include a call to
Application.SetUnhandledExceptionMode; which would be required in order to
reliably catch exceptions with this method. The fact that the default
behaviour does not catch this exception and that the application config can
override the unhandled exception handling logic of the application suggests
this method is not safe.

Using the ThreadException event to "ignore" exceptions basically cancels the
current windows message (i.e. the current WndProc call). The
ThreadExcepttion handler is not provided any context in which to distinguish
whether this particular raised Win32Exception (in this case,
Win32Exception.NativeErrorCode == 1722) is the exception in question. Also,
as far as I can tell, this doesn't cause following messages in the queue to
stop being processed, this Win32Exception could be a symptom of, or result
in, corrupt data that will be used by upcoming messages--leading to a larger
problem.

Further, not handling this Win32Exception with a ThreadException exception
handler simply causes the print preview dialog to close, it's not an
unhandled exception in that the application is terminated. So, the exception
is "handled" somewhere, and I'm assuming it's handled in a safe way--it just
doesn't provide useful feedback to the user. Using ThreadException would
circumvent this default exception handler, which I believe is far from safe.

With Application.ThreadException documentation like "Where possible,
exceptions should be handled by a structured exception handling block.", I'm
surprised this method is even suggested. ThreadException should be reserved
for use as a last-change exception handler, due to its potential to hide bugs.

--
Browse http://connect.microsoft.com/VisualStudio/feedback/ and vote.
http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#
 
L

Linda Liu [MSFT]

Hi,

Yes, you're right that we should call Application.SetUnhandledExceptionMode
method in order to ensure routing all unhandled exceptions to the
ThreadException handler. In addition, to handle the unhandled exceptions in
the ThreadException handler, we should pass a parameter with the value of
UnhandledExceptionMode.Automatic or UnhandledExceptionMode.CatchException
when calling the SetUnhandledExceptionMode method.

The default behaviour is to route all unhandled exceptions to the
ThreadException handler. And I am sorry that I don't think that fact that
the application config can override the unhandled exception handling logic
of the application means this method is unsafe. It's just a kind of
configuration that .Net provides to us.

The ThreadException handler isn't provided with any context in which to
distinguish which line of code or operation causes the exception. But we
could make use of the System.Threading.ThreadExceptionEventArgs parameter
to know the detailed information of the exception. I think this is enough.

When an exception rises, the code behind the line of code which causes this
exception won't be executed. I don't think the following messages in the
queue should stop being processed. But it's better to validate data before
using it.

Generally speaking, it is recommended to handle an exception using
try..catch..finally structured block. This method applies to the scenario
that a line of code contained within the try block causes an exception.
However, in our scenario, the exception is raise in the print preview
dialog, so we couldn't catch it using try..catch..finally structured block.

Hope this helps.
If you have any concerns, please feel free to let me know.

Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Hi Linda. I should have made myself more clear. The ThreadException method
does not solve the issue of closing the print preview form. I can intercept
the Win32Exception; but the print preview form will still be closed.

The ThreadExceptionEventArgs will really only give me the exception type
that was raised. There are many reasons that a Win32Exception with error
code 1722 can be raised. I don't want to handle EVERY case while the print
preview dialog is active, just the one in question. Plus, there's the case
of handling this exception when not print previewing. The only way I could
limit the scope of the exception being handled would to be to parse the
Exception's StackTrace property--not something I would ever be willing to do.

I was hoping this problem was known and that a recommended workaround
creating a new class deriving from PrintController or
PrintControllerWithStatusDialog showing where to add a try/catch block would
be provided. Similar to the workaround presented for the thread "Unhandled
Exception when cancelling print from PrintPreviewDialog" by Jeffery Tan.

Using ThreadException is not acceptable.

--
Browse http://connect.microsoft.com/VisualStudio/feedback/ and vote.
http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#
 
L

Linda Liu [MSFT]

Hi,

Sorry for my delayed reply. I have spent a lot of time doing more research
on this issue and found a better workaround finally.

The reason that we couldn't catch the exception when we contain the line of
code to show the PrintPreviewDialog in a try..catch structure block is that
where the exception is ocurring isn't part of calls you're making. It is a
response to the messages on the messge loop.

When we press the Print button in the PrintPreviewDialog, the
PrintController code doesn't check to see if there're errors occuring in
OnStartPrint method and instead goes ahead and calls PrintLoop, which print
each page. This calls into OnStartPage, which leads to the error.

However, before PrintLoop proceeds, the first thing it does is to raise the
QueryPageSettings event on the print document, which offers a chance to
cancel the printing. The steps of the workaround are like blow.

1. Create a new class derived from PrintDocument. Add a flag in the new
class and override the OnQueryPrintSettings method.

2. Create a new class derived from StandardPrintController and override
the OnStartPrint method.

3. When an error is raised in the overridden OnStartPrint method, set the
flag in the print document to true.

The following is a sample.

using System.Drawing.Printing;
using System.Windows.Forms;

class MyPrintDocument:printDocument
{
public bool Cancelled = false;
protected override void
OnQueryPageSettings(QueryPageSettingsEventArgs e)
{
e.Cancel = Cancelled;
base.OnQueryPageSettings(e);
}
}

class MyPrintController : StandardPrintController
{
public override void OnStartPrint(PrintDocument document,
PrintEventArgs e)
{
try
{
base.OnStartPrint(document, e);
}
catch (Exception exp)
{
((MyPrintDocument)document).Cancelled = true;
MessageBox.Show(exp.Message);
}
}
}

We should use the MyPrintDocument instead of PrintDocument in the form and
set the PrintController property of the print document to an instance of
MyPrinterController. A sample code is as follow.

MyPrintDocument printDocument1 = new MyPrintDocument();
PrintController controller = new MyPrintController();
this.printDocument1.PrintController = controller;

Hope this helps.
If you have anything unclear, please feel freel to let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support
 
G

Guest

Hi Linda. Thank you for your response. I hope to have the time to analyse
the details sometime this weekend and will get back to you.
 

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