views:

734

answers:

1

EDIT: If you have an example in VBA, I'll take it. I'm just trying to understand how to use the Range object with the Tables collection to copy and paste multiple tables without looping. Put another way, how can I specify a range of 1..lastTable using the Tables collection? If I can see a working VBA example of this, I'll work on the VBA --> Perl conversion.

I'm trying to use Perl's Win32::OLE module (via Dave Roth's excellent book) to automate a couple tasks I need to repeatedly perform on some Word documents. However, the book (and most web examples) tends to use Excel for examples, so I am not sure how to copy and paste effectively with the Tables collection object.

Here is a snippet of my code:

my $originalDoc = $MSWord->Documents->Open('C:\Perl\testDocument.doc');
my $newDoc = $MSWord->Documents->Add;
my $selection = $MSWord->Selection(); # this may be spurious

my $Count = int( $originalDoc->Tables()->{Count} );
my $range = $originalDoc->Tables()->Range( { Start => $originalDoc->Tables(1)->{Range}->{Start},
                                             End   => $originalDoc->Tables($Count)->{Range}->{End}
                                           } );
$range->Copy();
$newDoc->Range()->Paste();

The original code used Paragraphs, not Tables, so I assume some of the bugs are artifacts from that code (or more likely my non-understanding of that code).

+2  A: 

Copying and pasting tables one at a time might be preferable:

#!/usr/bin/perl

use strict;
use warnings;

use File::Spec::Functions qw( catfile );

use Win32::OLE;
use Win32::OLE::Const 'Microsoft Word';
$Win32::OLE::Warn = 3;

my $word = get_word();
$word->{Visible} = 1;

my $doc = $word->{Documents}->Open(catfile $ENV{TEMP}, 'test.doc');
my $newdoc = $word->Documents->Add;

my $n_tables = $doc->Tables->Count;

for my $table_i ( 1 .. $n_tables ) {

    my $table = $doc->Tables->Item($table_i);
    $table->Select;
    $word->Selection->Copy;

    my $end = $newdoc->GoTo(wdGoToLine, wdGoToLast);
    $end->InsertBefore("\n");
    $end = $newdoc->GoTo(wdGoToLine, wdGoToLast);
    $end->Select;

    $word->Selection->Paste;
}

$doc->Close(0);
$newdoc->SaveAs('test-output.doc');

sub get_word {
    my $word;
    eval {
        $word = Win32::OLE->GetActiveObject('Word.Application');
    };

    die "$@\n" if $@;

    unless(defined $word) {
        $word = Win32::OLE->new('Word.Application', sub { $_[0]->Quit })
            or die "Oops, cannot start Word: ",
                   Win32::OLE->LastError, "\n";
    }
    return $word;
}
Sinan Ünür
Great! One question though.. is there no way to select a range of objects from a collection object? Say, all the table objects, without any other text in one operation? I'm just asking about whether this is possible -- I'm getting the impression it isn't, or at least it doesn't work the way I think it could.
romandas
@romandas I do not think so. The `Tables` collection does not have a `Range` method.
Sinan Ünür
Thanks! +1 and accepted.
romandas