Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

WIN32, OLE, Excel, and Printing

by boblawblah (Scribe)
on Aug 20, 2008 at 18:40 UTC ( [id://705581]=perlquestion: print w/replies, xml ) Need Help??

boblawblah has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks, What I have is a program that prints reports using Win32::OLE and MS Excel. The user can select any number of reports that they want to run. The reports are created and printed using Excel. However I can't quite get the print options/behavior that I am looking for.

Once the user presses the <PRINT> button the following code is executed for each report.
my $rpt = GTIMs::Report->new('Schedule::Daily', $args); $rpt->create; # populate the workbook with data $rpt->print; # print the workbook $rpt->destroy; # destroy the workbook ######################## # the report print function simply looks like this sub print { my ($self, $copies) = @_; $copies = 1 unless $copies; $self->{WorkBook}->PrintOut(Copies => 1); }
Now the issue is, as that printing like this, I can't select the printer to print to and advanced options like double sided printing, resolution, layout type, etc.

Things like paper type and orientation can be set using PageSetup (an example is provided below)
with ($Sheet->PageSetup, LeftHeader => '', CenterHeader => '&"Arial,Bold"&16' . $self->{Schedule}{$schedu +le}{Title} . chr(10) . "&12 $day $self->{Period}{Start}" . chr(10) . "$start - $end", RightHeader => '', LeftFooter => 'Printed &D &T', CenterFooter => '', RightFooter => 'Page &P of &N', LeftMargin => $Sheet->Application->InchesToPoints(0.15), RightMargin => $Sheet->Application->InchesToPoints(0.15), TopMargin => $Sheet->Application->InchesToPoints(1.0), BottomMargin => $Sheet->Application->InchesToPoints(0.5), HeaderMargin => $Sheet->Application->InchesToPoints(0.25), FooterMargin => $Sheet->Application->InchesToPoints(0.25), PrintHeadings => 0, PrintGridlines => 0, PrintComments => xlPrintNoComments, PrintQuality => 600, CenterHorizontally => 1, CenterVertically => 0, Orientation => xlPortrait, Draft => 0, PaperSize => xlPaperLetter, FirstPageNumber => xlAutomatic, Order => xlDownThenOver, BlackAndWhite => 0, Zoom => Variant(VT_BOOL, 0), FitToPagesWide => 1, FitToPagesTall => 1, PrintErrors => xlPrintErrorsDisplayed, PrintTitleRows => '$1:$2', PrintTitleColumns => '$A:$D', );
After some searching (I hope the below examples help others in a similar situation) I was able come up with the following code to display the print dialog.
use constant xlDialogPrint => 8; sub print { my $self = shift; my $dlg = $self->{Excel}->Dialogs(xlDialogPrint); my $response = $dlg->Show; }
This displays the print dialog, and you can change these settings. Exactly what I want to do. The problem is that it is going to display the print dialog for EVERY report the user wants to print. Which could be potentially be a pretty large number. I want to display the dialog once, and then use the same print settings for each document that I am printing. Does anyone have any insight into this?

Replies are listed 'Best First'.
Re: WIN32, OLE, Excel, and Printing
by Corion (Patriarch) on Aug 20, 2008 at 18:58 UTC

    Can't you just display the xlDialogPrint once and use it to set the defaults, or copy the values set from it? If the dialog doesn't set the defaults, you have to make up the list of default values, invoke the print dialog for the first file, copy the values set through the print dialog, and then feed the printing values from your program instead of the dialog every time.

    But as you don't show the loop in which you actually ask the user and then print the things, and as I don't have Excel (or the time to play with it) on this machine, it's hard to know for sure unless you provide more information or try it yourself.

      Thank you for your response Corion. And I wish it were (is it?) that simple. The dialog doesn't set the defaults for each workbook (report). If I call the dialog for only the first workbook/report, the settings are applied to only that workbook. The remaining workbooks are not affected. I would love to be able to get the values from the print dialog if anyone knows how to do this. The other issue would be *when/if* i get these values, is passing them to the next workbook/report. I see no functions/properties that allow me to change things like single/double sided, layout type, resolution, etc. The OLE function PrintOut only allows you to set the following properties (Taken from MS Object Browser):
      Sub PrintOut([From], [To], [Copies], [Preview], [ActivePrinter], [Prin +tToFile], [Collate], [PrToFileName])
      As for the actual loop that prints the reports, see below.
      # Print the report sub on_winReports_btnPrint_clicked { my ($btn, $win) = @_; my $self = $win->{GUI}; my $tree = $self->get_widget('winReports_treeView'); my $model = $tree->get_model; my $period = $self->get_period; return unless $period; my $criteria = $self->get_criteria; my $dialog = 1; $model->foreach ( sub { my ($model, $path, $iter) = @_; my $class = $model->get($iter, CLASS_COL); my $active = $model->get($iter, ACTIVE_COL); my $header = $model->get($iter, HEADER_COL); if ($active && !$header) { my $options = $self->get_options($class); my $report = GTIMs::Report->new($class, {Period => $period +, Criteria => $criteria, Options => $options}); $report->create; $report->print($dialog); $report->destroy; $dialog = 0; } } ); } #### HERE IS THE NEW PRINT FUNCTION IN GTIMs::Report ##### sub print { my ($self, $dialog) = @_; if ($dialog) { my $dlg = $self->{Excel}->Dialogs(xlDialogPrint); my $result = $dlg->show; } else { $self->{Document}->PrintOut(); } }
      As you can see the dialog variable determines whether or not the print dialog will be displayed. Another note that may be important, is that the excel xlDialogPrint object actually prints the active workbook (or doesn't, depending on the user's response) so no call to PrintOut is required. A subsequent call to PrintOut on the same workbook keeps the setting set by xlDialogPrint.

      A workaround to my problem (which is a path I would rather not go down) is that each report could use the same workbook. So the program would create a workbook, create the first report, prompt the use for the print settings, then delete each worksheet in the book, create the next report, and issue the PrintOut command, and then delete each worksheet, etx.. for all subsequent reports. Reasons I do not want to do this is

      1) It exposes the underlying interface to the report modules

      2) It relies on the user to interact with underlying interface. The user would have to create the Excel and Workbook objects, and pass them to each report. Besides wanting this to be transparent to the user, if I decide that I don't want to use Excel anymore, and instead write my reports in HTML, old code would break (or would be throwing around OLE objects for no good reason).

      3) The seems as though this should be trivial - and *hopefully* the only reason it is not is due to my ignorance of programming Microsoft applications compounded by the idiosyncrasies programming Microsoft applications.

        From a cursory browsing of the various Excel dialogs, maybe dialog 9, xlDialogPrinterSetup can help. I think there is/was a way to clone the printer settings from one document to the next, but I don't find the code I think I had to do that, and the Googles fail me as well.

Re: WIN32, OLE, Excel, and Printing
by psini (Deacon) on Aug 20, 2008 at 21:25 UTC

    Have you considered the idea of writing a macro (or several macros) to change the printer settings?

    From Win32::OLE you should be able to execute it before printing.

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

Re: WIN32, OLE, Excel, and Printing
by ggvaidya (Pilgrim) on Aug 21, 2008 at 04:11 UTC
    Have you tried using PageSetupDlg in the Common Dialog Box library? That way you can get all the setting you want and store them where you need. I have no idea how easy it is to work this via Win32::*, though - I've coded in both Windows and Perl, but never at the same time!
Re: WIN32, OLE, Excel, and Printing
by Cefu (Beadle) on Aug 21, 2008 at 14:02 UTC

    I'm pretty familiar with Excel but I haven't done the sort of thing you're attempting with OLE so this answer is on a purely conceptual level.

    Once you have created the first workbook, popped up the printer dialog and collected the user's print preferences, they are then set for that workbook, correct? You then print, destroy the workbook and create a new one without the print settings you want.

    Why not clear out your data from the workbook rather than destroying it? You could then load up new data, set new title, etc. and print the "same" workbook again using the same print settings.

Re: WIN32, OLE, Excel, and Printing
by rpnoble419 (Pilgrim) on Aug 22, 2008 at 03:54 UTC
    Have you considered using Spreadsheet::WriteExcel to create all of the reports in one Excel file then using Excel via OLE to print it, thus needing to set your printer settings only once?
Re: WIN32, OLE, Excel, and Printing
by jrsimmon (Hermit) on Aug 21, 2008 at 15:54 UTC
    Have you considered printing from excel to a postscript file and then using a separate process to send the postscript file to the printer? Ghostscript comes to mind, though I'm not sure if it supports the options you need. Alternatively, if you aren't tied to the printer, would delivering the reports via email be acceptable? If the goal is perhaps to reduce paper usage, a pdf document via email would be an ever better solution (I realize this isn't the question you asked, just thought I'd throw it out there).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://705581]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (2)
As of 2024-04-20 05:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found