How to run macro from specific workbook w/ Win32::OLE - perl

(Using Win32:OLE w/ Perl)
Is there a way to specify which workbook an Excel macro is run from if multiple workbooks are already open?
I am using the following code, but it sometimes fails if more than one Excel workbook is open. I know there is an obvious solution to just close the other workbooks, but my work often involves using another Excel workbook (which is a hassle to keep closing and reopening). So I am hoping there is a way to specify which workbook to run the macro from (perhaps similar to how one specifies an additional parameter such as the title for Win32::GUI).
Here is an example of what currently just works with one workbook open:
use Win32::OLE;
my $excel = Win32::OLE->GetActiveObject('Excel.Application');
$excel->Run("macroName");
The macro I am running exports all the sheets of the current workbook, so it is important that it is run from the correct workbook. I checked out this question (How do I use Perl to run a macro in an **already open** Excel workbook) but it doesn't seem to address how to select which macro the workbook is run from.
I was also reading through this article (http://docs.activestate.com/activeperl/5.6/faq/Windows/ActivePerl-Winfaq12.html), but it didn't seem to show a way how to run a macro from a specific workbook. Thinking a bit more, I could see not being able to specify which workbook to run from being an issue if two workbooks have the same macro name, but for some reason, these do different things.
Any suggestions?

You need to select the worksheet you want within the workbook. e.g. open a file, select the second workbook (by name) and activate it:
#!/usr/bin/perl
use strict;
use warnings;
use Win32::OLE;
use Win32::OLE::Const 'Microsoft Excel';
my $excelfile = 'd:\\Book1.xls';
my $Excel = Win32::OLE->GetActiveObject('Excel.Application')
|| Win32::OLE->new('Excel.Application');
$Excel->{'Visible'} = 1;
my $Book = $Excel->Workbooks->Open("$excelfile") or die "$!";
my $Sheet = $Book->Worksheets("Sheet2");
$Sheet->Activate();
This is a great reference for working with Win32::OLE – perl Win32::OLE cheat sheet

Related

Reading Xlsx from another Xlsx file

I have few Xlsx files say X.xlsx,Y.xlsx,Z.XLSX and I kept those three Xlsx files in another xlsx file say A.xlsx. Now I want to ready the content in the three xlsx files(x,y,z) at a time through A.xlsx.
Can any one help me on this.
Thanks in advance
This is easy on Windows if your target machine also has Microsoft Excel installed.
Use the Win32::OLE module to create an instance of Excel, open your master file A.xlsx and then iterate over its ->{OLEObjects} property:
#!perl
use strict;
use warnings;
use Win32::OLE 'in';
$ex = Win32::OLE->new('Excel.Application') or die "oops\n";
my $Axlsx = $ex->Open('C:\\Path\\To\\A.xlsx');
my $i=0;
for my $embedded (in $Axlsx->OLEObjects) {
$embedded->Object->Activate();
$embedded->Object->SaveAs("test$i++.xlsx");
$embedded->Object->Close;
}
After saving them, you can treat them as normal Excel files. Alternatively, you can work directly with $embedded->Object, but as you haven't told us what exactly you need to do, it's hard to give specific advice.
See also Save as an Excel file embedded in another Excel file

perl script to read an excel file using cpan modules

I am writing a perl script to read data from an excel file. The script is being written in an unix environment and run on the server, whereas the excel file is available on my Desktop in Windows.
#!/usr/bin/perl
use strict;
use warnings;
use feature 'say';
use Spreadsheet::Read;
my $workbook = ReadData ("C:/Users/tej/Desktop/Work.xlsx");
say $workbook->[1]{A1};
The output gives out a warning saying
Use of uninitialized value in say at..... line 10
And there is no other output being printed. I just wrote a sample code to read the A1 cell value from sheet 1. Later, I need to write a logic to read particular values. For right now, need to fix the error to read and print the excel cell values. Appreciate any help. :)
I fixed the issue. It was about file was not being accessed. I used samba to Map unix disk to Windows Network Drive. But now, I get a different error which says : Parser for XLSX is not installed at.. Can someone help me to resolve it.

Rewrite existing xls files using Perl

I am trying to write data in excel files which is already exists, but the code I tried is creating a new sheet and erasing the old sheet with the data. This the code I use
#!/usr/bin/perl –w
use strict;
use Spreadsheet::WriteExcel;
# Create a new Excel file
my $FileName = 'Report.xls';
my $workbook = Spreadsheet::WriteExcel->new($FileName);
# Add a worksheet
my $worksheet1 = $workbook->add_worksheet(); #<- My Doubt
# Change width for only first column
$worksheet1->set_column(0,0,20);
# Write a formatted and unformatted string, row and column
# notation.
$worksheet1->write(0,0, "Hello");
$worksheet1->write(1,0,"HI");
$worksheet1->write(2,0,"1");
$worksheet1->write(3,0,"2"); `
How can I assign the current sheet to $worksheet1. And one more thing is I need to read specific cell from which is already exist.
Please give me some guidance .Thank you
You cannot open an existing a spreadsheet with Spreadsheet::WriteExcel and update it like that. You first want to open it using Spreadsheet::ReadExcel along with an output sheet which you open with WriteExcel. Then, you read the input file, write out existing cells, sheets etc, and make whatever edits/updates/insertions you are going to make. Then, you can close both files, remove the previous, and rename the new one (optionally backing up the previous version).
You can only really edit/change a given Excel file without going through this process by opening it using Win32::OLE, but for that you are most certainly going to need to be on a Windows system (I am not sure about the state of Wine), and this is not something you want to do on a server.
You can think of creating a file with Spreadsheet::WriteExcel as similar to opening a file with open my $fh, '>', 'output.file' ... output.file will be clobbered.
Note the line:
my $fh = FileHandle->new('>'. $self->{_filename});
in Spreadsheet::WriteExcel::Workbook->new.

How can I run a macro in an Excel file I open with Perl?

How can I run a macro in an Excel file I open with Perl?
Here is a skeleton of what might work.
use strict;
use warnings;
use Win32::OLE;
my $excel= Win32::OLE->new('Excel.Application')
or die "Could not create Excel.Application!\n"
;
$excel->Workbooks->open( 'C:\Users\Me\Documents\Book1.xlsx' );
$excel->run( 'Book1!Macro1' );
$excel->quit;
One of the most sure ways that you can do this is to simply record a macro of opening a spreadsheet and running a macro. And then taking a look at the macro code that was generated and convert it into Perl. Keep in mind that the OLE object is the Application object.
9/22/2010 - I added quit to stop Excel from running.

How can I modify an existing Excel workbook with Perl?

With Spreadsheet::WriteExcel, I can create a new workbook, but what if I want to open an existing book and modify certain columns? How would I accomplish that?
I could parse all of the data out of the sheet using Spreadsheet::ParseExcel then write it back with new values in certain rows/columns using Spreadsheet::WriteExcel, however. Is there a module that already combines the two?
Mainly I just want to open a .xls, overwrite certain rows/columns, and save it.
Spreadsheet::ParseExcel will read in existing excel files:
my $parser = Spreadsheet::ParseExcel->new();
# $workbook is a Spreadsheet::ParseExcel::Workbook object
my $workbook = $parser->Parse('Book1.xls');
But what you really want is Spreadsheet::ParseExcel::SaveParser, which is a combination of Spreadsheet::ParseExcel and Spreadsheet::WriteExcel. There is an example near the bottom of the documentation.
If you have Excel installed, then it's almost trivial to do this with Win32::OLE. Here is the example from Win32::OLE's own documentation:
use Win32::OLE;
# use existing instance if Excel is already running
eval {$ex = Win32::OLE->GetActiveObject('Excel.Application')};
die "Excel not installed" if $#;
unless (defined $ex) {
$ex = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;})
or die "Oops, cannot start Excel";
}
# get a new workbook
$book = $ex->Workbooks->Add;
# write to a particular cell
$sheet = $book->Worksheets(1);
$sheet->Cells(1,1)->{Value} = "foo";
# write a 2 rows by 3 columns range
$sheet->Range("A8:C9")->{Value} = [[ undef, 'Xyzzy', 'Plugh' ],
[ 42, 'Perl', 3.1415 ]];
# print "XyzzyPerl"
$array = $sheet->Range("A8:C9")->{Value};
for (#$array) {
for (#$_) {
print defined($_) ? "$_|" : "<undef>|";
}
print "\n";
}
# save and exit
$book->SaveAs( 'test.xls' );
undef $book;
undef $ex;
Basically, Win32::OLE gives you everything that is available to a VBA or Visual Basic application, which includes a huge variety of things -- everything from Excel and Word automation to enumerating and mounting network drives via Windows Script Host. It has come standard with the last few editions of ActivePerl.
There's a section of the Spreadsheet::WriteExcel docs that covers Modifying and Rewriting Spreadsheets.
An Excel file is a binary file within a binary file. It contains several interlinked checksums and changing even one byte can cause it to become corrupted.
As such you cannot simply append or update an Excel file. The only way to achieve this is to read the entire file into memory, make the required changes or additions and then write the file out again.
You can read and rewrite an Excel file using the Spreadsheet::ParseExcel::SaveParser module which is a wrapper around Spreadsheet::ParseExcel and Spreadsheet::WriteExcel. It is part of the Spreadsheet::ParseExcel package.
There's an example as well.
The Spreadsheet::ParseExcel::SaveParser module is a wrapper around Spreadsheet::ParseExcel and Spreadsheet::WriteExcel.
I recently updated the documentation with, what I hope, is a clearer example of how to do this.