2

This is similar to A copy of Excel Addin is created in My Documents after saving, except that I'm working with Perl instead of VBA, and xls files instead of xlsm, and the negative impact of the behavior is different.

I've inherited a Perl script (Perl 5.8.8) that is running on Windows 2003 Server as SYSTEM. After copying an Excel 2003 template file to a unique, fully defined path location, it opens the unique file in Excel using OLE, edits the file, saves the file, and closes the file. What results is the edited file being saved both in the correct, fully-defined path location, and also in the Default User profile's Documents folder.

This causes thousands of these files to accumulate on the C: drive, as every new admin to be hired gets a copy in his Documents folder.

Adding the code that sets the value of $OUT:

if (!$db->Sql("EXEC GetDetails 'name'"))
{
    while ($db->FetchRow()>0)
    {
        @DataIn = $db->Data();
        $name = $DataIn[0];
        $IN = $DataIn[1];
        $OUT = $DataIn[2];
        opendir(DIR,"$OUT") || die "$OUT directory does not exist $!\n";

        #... loop of proprietary code
            #...
            @Completed = $db1->Data();
            #...

            &formatExcelReport  #The code that I previously posted

            #...
            # more proprietary code
        # end of loop

    } #end of while
}#end of if

The code I originally posted:

# Initialize Excel object
eval {Win32::OLE->new('Excel.Application', 'Quit')};
eval {$Excel = Win32::OLE->GetActiveObject('Excel.Application')};
unless (defined $Excel)
{
    $Excel = Win32::OLE->GetActiveObject('Excel.Application')
             || Win32::OLE->new('Excel.Application', 'Quit');
}
$infiles = "Report_Template.xls";
$infiles = $OUT."/".$infiles;
$db6->Sql("EXEC FormatResults '".$Completed[0]."','".$Completed[1]."'");
$row = 2;
$fileName = $Completed[0]."_".$Completed[1];
$uniquefile = $fileName.$printdate.".xls";

# $OUT is a fully defined path on the E: drive
$reportfile = "$OUT"."\\".$uniquefile;
copy($infiles,$reportfile);
$Book = $Excel->Workbooks->Open("$reportfile");
$sheetnum = 1;
my $Sheet = $Book->Worksheets($sheetnum);

# Set Headers
$Header = $Sheet->PageSetup->{'CenterHeader'};
$Header = $Header." Results Test Code: ".$Completed[0]." Worksheet: ".$Completed[1]." Date: ".$headerdate;
$Sheet->PageSetup->{'CenterHeader'}= $Header;

# More file editing
# ...

$Book->Save();
$Book->Close(0);
Win32::OLE->new('Excel.Application', 'Quit');

Is the root of this problem the Save() command? Should I be using SaveAs() instead?

Any other feedback about how Excel is being used welcome, as well.

Thanks!

Community
  • 1
  • 1
Rebeccah
  • 327
  • 1
  • 13

2 Answers2

3

I don't see what causes this behavior, but here are a few things to try.

  • The template and the file it is copied to have names

      $infiles = $OUT."/".$infiles;
      $reportfile = "$OUT"."\\".$uniquefile;
    

Use the same separator.

  • Try to suppress some possible setting dictating that another copy be made. Perhaphs

      $Excel->Application->{CreateBackup} = 0;
    

However, this may not be the correct property -- search the VB or Excel documentation for properties that may result in Excel saving an extra copy. (It needn't be "backup".)

  • Try to create a new file and use SaveAs, as a test to see whether you get two files again. The template copying may be setting it off to Save an extra copy (even though I don't see how). I'd say it's either that, or some general setting that need be turned off.

The rest is the original post, about using SaveAs, whereby I thought that a new file is created

You would use SaveAs to write a new file. See saveas in MSDN library

Saves changes to the workbook in a different file.

Using the save method may result in saving two files fro some reason, as noted in the answer by Borodin. This page also advises to use SaveAs for a new file

The first time you save a workbook, use the SaveAs method to specify a name for the file.

Once you change to using SaveAs there should be a confirmation dialog to deal with. If you want to suppress that you can set a property, with one (or either?) of

$Excel->Application->{DisplayAlerts} = 0;
# or
$Excel->{DisplayAlerts} = 0;

For a number of options, including backups for example, see the Chapter on OLE automation in PERL in a Nutshell.


A note on some other resources. There is a cookbook of sorts in this post on perlmonks. A listing of various operations is given in this SO post.

Finally, I don't know how deep the reasons for using OLE are but if it is only about writing some Excel files there are other modules. For example the very well regarded Spreadsheet::WriteExcel and Excel-Writer-XLSX.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • @Rebeccah I updated the answer substantially, after realizing that your posted code opens an existing file, not create a new one. Please let me know how it goes. – zdim Jun 15 '16 at 08:25
  • Thank you, @zdim. The template file has all of the formatting in it. I'm going to be doing a test deployment today, so I'll have the opportunity to try some of these things. The new version will be using Spreadsheet::WriteExcel or possibly SpreadSheet::ParseExcel::SaveParser (I've got two versions to try out), but this current behavior has been bugging me, so I do hope I get to the bottom of it. – Rebeccah Jun 15 '16 at 16:47
  • I've updated my question to correct the mistaken impression that Excel is creating a new file, when in fact, it is opening an existing one. – Rebeccah Jun 15 '16 at 16:57
  • @Rebeccah Right, of course. So you need that. I changed my post accordingly. It's still worth trying with a new file, just to see whether you get the same behavior. Other than that, I'd guess that it is some Excel setting. I think that all bullets are worth trying, but if you merely write Excel files use other modules, in particular the first recommended one. OLE is needed for other pursposes, you don't need it to just write a file or a few (unless there are very fancy elements). – zdim Jun 15 '16 at 17:32
  • right. I think the script was originally written this way because at the time, the author was not aware of those other modules - I'm not sure if they even existed for Perl 5.8. ....Why is this interface erasing @ zdim from my comment to you? – Rebeccah Jun 15 '16 at 21:04
  • @Rebeccah Alright, then you are probably better off using the other modules. OLE is great since it offers a uniform API for a range of tasks but for simple Excel reading/writing other modules are simpler to use. I'll leave this answer as it is then, I hope that it was/is still useful. – zdim Jun 15 '16 at 21:07
  • @Rebeccah When you post a comment beneath a question or an answer, the 'owner' of the question/answer gets notified. So there is no need for at-owner-name, and the interface removes it if you actually type it in. You can tag other people (up to one other than the owner, I think) by starting with at-username and they will get notified of the comment. I would suggest that we now tidy up this thread, please remove what is not relevant any more and then I will do so, too. – zdim Jun 15 '16 at 21:27
0

That's very strange Perl code. eval without checking $@ afterwards is just wrong -- you need to know if a step of your code has failed for the following steps to make sense

It looks like the problem is in your call to copy($infiles, $reportfile). That will save one copy of the file, while $Book->Save and $Book->Close will save another

Borodin
  • 126,100
  • 9
  • 70
  • 144
  • One thing I'm still not following, though -- which copy is ending up in the Documents folder of the default user? $reportfile should be a full pathname to an .xls file on the E: drive at the time of the copy and at the time of opening the file in Excel. – Rebeccah Jun 14 '16 at 21:28
  • Regarding the use of eval, I think this was some trick that was found on the Internet to prevent the script from exiting if Excel was already open - and instead, causing the existing Excel instance to be used. I think this has turned out to be a bad idea for other reasons. Our next version of this script will not be using OLE and Excel at all. But for now, I just want to understand why this has been behaving the way it has. – Rebeccah Jun 14 '16 at 21:36
  • @Rebeccah: What is `$OUT` in your code? You don't show its definition. – Borodin Jun 15 '16 at 11:23
  • 1
    @Rebeccah: Please just add any relevant information to your original question, without deleting what is already there. We will probably pick up the change,but you can leave a comment to alert us that you have made a change – Borodin Jun 15 '16 at 21:18
  • 1
    @Rebeccah: Please also delete any comments that are no longer relevant – Borodin Jun 15 '16 at 21:19
  • 1
    @Rebeccah: The edit link is beneath your question, just below the tags. [Here's a copy](http://stackoverflow.com/posts/37819913/edit) – Borodin Jun 15 '16 at 21:20
  • OK, I've added the code that sets $OUT to the original question. Not sure why the help says I can format code in comments, unless it's an advanced feature that I'm not eligible to use. – Rebeccah Jun 15 '16 at 21:28