Problem with TSRVPrint when no default printer is assigned
Posted: Tue Jul 03, 2012 7:04 pm
When TSRVPrint is on a form and the user's profile has no default printer assigned, a couple of nasty things occur.
TSRVPrint.Create creates a TSRVPrtInfo, but always "Gets Printer Data Immediately".
TSRVPrtInfo.UpdateCurPrinterData sets Printer.PrinterIndex := Printer.PrinterIndex, I assume to refresh the current printer. However, when there is not a default printer, this throws the exception "EPrinter: There is no default printer currently selected"
This alone prevents the form from loading. However, it gets uglier. TSRVPrint is automatically destroyed by Delphi since an exception occurred in its constructor. TSRVPrint's destructor assumes SRVPrtInfo was created and always tries to destroy it. In this scenario, that causes an Access Violation, which prevents the original exception from being seen by the developer.That second issue can be fixed by ensuring SRVPrtInfo is assigned before destroying it:
I can make sure a default printer is available, notify the user if there isn't one and avoid calling TSRVPrint.Print in that scenario. Unfortunately, I can't prevent the exception upon form creation.
I'm going to investigate the impact of changing TSRVPrint.Create from doingto
If the component will create without blowing up, I can have it get printer information before printing, and only print if a default printer is available.
I have a function that I created from code in Printers.pas that determines if a default printer is available, if that would be helpful to you.
TSRVPrint.Create creates a TSRVPrtInfo, but always "Gets Printer Data Immediately".
TSRVPrtInfo.UpdateCurPrinterData sets Printer.PrinterIndex := Printer.PrinterIndex, I assume to refresh the current printer. However, when there is not a default printer, this throws the exception "EPrinter: There is no default printer currently selected"
This alone prevents the form from loading. However, it gets uglier. TSRVPrint is automatically destroyed by Delphi since an exception occurred in its constructor. TSRVPrint's destructor assumes SRVPrtInfo was created and always tries to destroy it. In this scenario, that causes an Access Violation, which prevents the original exception from being seen by the developer.
Code: Select all
destructor TSRVPrint.Destroy;
begin
SRVPrtInfo.Destroy;
inherited;
end;
Code: Select all
destructor TSRVPrint.Destroy;
begin
if Assigned(SRVPrtInfo) then
SRVPrtInfo.Destroy;
// or simply call Free, which will not free a nil reference:
// SRVPrtInfo.Free;
inherited;
end;
I'm going to investigate the impact of changing TSRVPrint.Create from doing
Code: Select all
SRVPrtInfo := TSRVPrtInfo.Create(True);
Code: Select all
SRVPrtInfo := TSRVPrtInfo.Create(False);
I have a function that I created from code in Printers.pas that determines if a default printer is available, if that would be helpful to you.