Perl 与 MS Office 2013(32 位)的 Win32::OLE 问题

Issue in Win32::OLE of Perl with MS Office 2013 (32bits)

我有一个使用 Win32::OLE 访问 MS Word 文件的 Perl 脚本。它在 MS Office 2010 上运行良好,但在我更新到 MS Office 2013 32 位后就不行了。

然后我尝试使用最新版本的 ActivePerl,包括 32 位和 64 位。我正在使用 Windows 7 SP1 64 位。

关闭 MS Word 并调用 Win32::OLE->new('Word.Application', 'Quit') 时,错误出现在以下行中:

my $Word =  Win32::OLE->GetActiveObject('Word.Application') || Win32::OLE->new('Word.Application', 'Quit');

[2015 年 8 月 13 日更新] 在命令行中添加 Win32::OLE->GetActiveObject('Word.Application') || 以强调问题与 new 函数

返回的错误如下:

Win32::OLE(0.1709) error 0x800700c1: "%1 is not a valid Win32 application" at C:\script.pl line 52
eval {...} called at C:\script.pl line 52

有趣的是,第52行对应的是注释行

这是整个脚本(出于调试目的注释行之后):

#!perl
#line 15

#======================================================================
# This script takes a Word document as input and generates out of it
# The Rev_x and the proper .pdf, and add the PDF to SVN
#======================================================================

use Win32::OLE qw(in with valof OVERLOAD);
use Win32::OLE::Const 'Microsoft.Word';    # wd  constants
use Win32::OLE::Variant;
$Win32::OLE::Warn = 3;

my $true  = Variant(VT_BOOL, 1);
my $false  = Variant(VT_BOOL, 0);

use Getopt::Long;
use File::Spec;
use File::Basename;

my $NoChanges = undef;

exit 1 unless &GetOptions('no-changes',  $NoChanges);

$DocFile = $ARGV[0];
$DocFile = "E:/SVN/project-docs/6.7/Common Data/03-Standards/SC-ST-019_STST-SDY.docx";
# $DocFile = "E:/SVN/project-docs/6.7/Common Data/SC-TS-048_TS-TOR-DF.docx";
[ -e $DocFile ] || die "*** Cannot open '$DocFile'\n";

if ( ! File::Spec->file_name_is_absolute($DocFile) ) {
  warn "File name is not absolute, trying to fix it\n";
  my $abs = File::Spec->rel2abs($DocFile);
  warn "Finding: $abs\n";
  $DocFile = $abs;
}

## Autoflush
$| = 1;
### opening file: try with "new" function, otherwise use "GetActiveObject"
my $Word =  Win32::OLE->GetActiveObject('Word.Application') || Win32::OLE->new('Word.Application', 'Quit');

# print "--- Opening $DocFile\n";
# my $document = $Word->Documents->Open({FileName =>$DocFile, ReadOnly =>$true, ConfirmConversions => 0});
# die "Cannot open '$DocFile'\n" unless defined $document;
# $document->Activate();

# ### Extract revision, increment and date from fields
# my $major = $document->Bookmarks->{Doc_Rev}->Range->{Text};
# $major =~ s/ *FORMTEXT *//;
# my $minor = $document->Bookmarks->{Doc_Incr}->Range->{Text};
# $minor =~ s/ *FORMTEXT *//;
# my $date = $document->Bookmarks->{Doc_Date}->Range->{Text};
# $date =~ s/ *FORMTEXT *//;
# my ($id) = (basename($DocFile) =~ /^([A-Z0-9-]+)/);
# print "--- DocID=$id\n";

### Accept all changes
# if ($NoChanges = 1) {
  # $Word->ActiveDocument->{TrackRevisions} = $false;
  # $Word->WordBasic->AcceptAllChangesInDoc();
# }

# ### Setting normal view to update fields
# $Word->ActiveWindow->ActivePane->View->{Type} = wdNormalView;
# my $selection = $Word->Selection();
# $selection->WholeStory();
# $selection->Fields->Update();

# ### Back to print view & print
# $Word->ActiveWindow->ActivePane->View->{Type} = wdPrintView;

# ### Build PDF filepath
# my $pdf = $DocFile;
# $pdf =~ s/[.]docx?$/.pdf/;
# $pdf =~ s/[.]rtf$/.pdf/;
# $pdf =~ s/$id/$id-$major-$minor/;
# print "PDF = $pdf\n";

# print "--- Printing ";
# $Word->ActiveDocument->ExportAsFixedFormat({ OutputFileName  => $pdf,
                           # ExportFormat    => wdExportFormatPDF,
                           # OpenAfterExport => $false,
                           # IncludeDocProps => $true,
                           # OptimizeFor => wdExportOptimizeForPrint,
                           # CreateBookmarks => wdExportCreateHeadingBookmarks});

# while ( $Word->BackgroundPrintingStatus() > 0 ) {
  # print ".";
  # sleep 1;
# }
# print "\n";
# $document->Close(wdDoNotSaveChanges);

我在 Whosebug、Perlmonks 等中搜索了信息,但没有找到任何相关信息。

我应该如何修改我的代码才能使其工作。

谢谢

显然,问题出在我的机器上。

Win32::OLE->new 功能在我的电脑上似乎不起作用(但在 Windows 8 下的另一台装有相同版本 MS Office 的计算机上可以使用)。

解决方法是在使用函数 GetActiveObject 之前强制手动打开 MS Word。

我更新的代码如下所示:

### opening file: try with "GetActiveObject" function, otherwise try with "new" function 
my $Word;
eval {
    $Word = Win32::OLE->GetActiveObject('Word.Application') 
         || Win32::OLE->new('Word.Application', 'Quit');
};
if ($@) {
    #MS Word shall be opened manually
    print "Please open MS Word manually before continuing\n";
    print "...Press ENTER to continue...\n";
    <STDIN>;
    $Word = Win32::OLE->GetActiveObject('Word.Application','Quit');
}

希望对您有所帮助。