Perl语言高级编程专题Lesson 8周晓方courses@xfzhou.homedns.org注意: 本课内容仅适合Win32环境, 其中9X和NT系统也有细微差别并且Win32::OLE的实例和应用程序的版本有关1ActivePerl的Win32模块•使用ActivePerl,程序增加use Win32;•错误编号和错误字符串(Win32有时不用$!)–Win32::GetLastError()–Win32::FormatMessage(Win32::GetLastError())•操作系统的版本信息–($serive_pack, $major, $minor, $build, $platform_id)= Win32::GetOSVersion()–其中platform_id,0 = win32, 1=win9x, 2=winnt–判断Win类型Win32::IsWinNT(), Win32::IsWin95()–Perl的编号: $PerlBuild = Win32::BuildNumber();2实例version.pluse Win32;my ($service_pack, $major, $minor, $build, $platform_id) = Win32::GetOSVersion();my ($perlbuild) = Win32::BuildNumber();my ($is95, $isnt) = (Win32::IsWin95(), Win32::IsWinNT());print << \"Here\";(省略,详见version.pl)Here1;某XP上运行的结果Win32::GetOSVersion() returns:service_pack Service Pack 1major.minor 5.1build 2600platform_id 2Win32::BuildNumber() returns:635Win32::IsWin95() returns 0Win32::IsWinNT() returns 1某98上运行的结果(安装的ActivePerl版本不同)Win32::GetOSVersion() returns:service_pack Amajor.minor 4.10build 67766446platform_id 1Win32::BuildNumber() returns:805Win32::IsWin95() returns 1Win32::IsWinNT() returns 03另一些函数•用户名、计算机名、域名–Win32::LoginName(), Win32::NodeName(), Win32::DomainName()•设置和获取当前工作目录–Win32::SetCwd('路径'), Win32::SetCwd()•文件系统类型–(类型,标志,目录串长度)=Win32::FsType()•下一个可用驱动器–Win32::GetNextAvailDriver()•开机以来的时间(毫秒)–Win32::GetTickCount()4•Win32::Clipbrd;•目前支持3种格式,文本、图片和文件•清空和设置Empty(), Set('..')•例子程序监视剪贴板内容Windows的剪贴板use Win32::Clipboard;my $clip = Win32::Clipboard ();while (1) {if ($clip->WaitForChange(10000)) {print \"Clipboard changed. Format is \";if ($clip->IsText()) {print \"text. '\} elsif($clip->IsFiles()) {print \"files.\\n\} elsif($clip->IsBitmap()) {print \"bigmap.\\n\";open B, \">b.bmp\";binmodeB;print B $clip->GetBitmap;close B;} else {print \"not supported : \EnumFormats), \"\\n\";}} else {print \"Clipboard not changed, go on waiting...\\n\"}}5其他一些Win32模块••••••••••••Win32::Console控制Console窗口Win32::ChangeNotify监视目录文件改变Win32::File修改、获得文件属性Win32::FileSecurityNT文件权限控制Win32::Internetwininet.dll,http, ftp, 等Win32::NetResource共享文件和打印机Win32::ODBCODBC数据库接口Win32::ProcessWin32系统的进程管理函数Win32::Registry注册表Win32::Shortcut快捷方式Win32::IPC/Semaphore/Mutex多进程线程协调……6Win32::Pipe 命名管道named pipe•带名字的管道,可以让同一个域上的进程交换数据,其中管道源必须是NT/2K/XP,不能是9Xuse Win32;#管道主机端代码,先运行这段代码use Win32::Pipe;die \"Must be NT to create a named pipe.\\n\" if not Win32::IsWinNT();my $pipe = new Win32::Pipe(\"My Perl Pipe\");die \"Fail to create pipe\\n\" if not $pipe;die \"Fail to connect pipe\\n\" if not $pipe->Connect;my $msg= \"I'm \" . Win32::LoginName. \" on \" . Win32::NodeName. \"\\n\" .\"I'm running script $0.\";print \"Send to Client:\\n$msg\\n\";die \"Fail to send message\\n\" if not $pipe->Write($msg);print \"Read from Client:\\n\";print $pipe->Read();$pipe->Disconnect;$pipe->Close;use Win32; use Win32::Pipe;#管道客户端代码,后运行这段代码my $pipe = new Win32::Pipe(\"\\\\\\\\.\\\\pipe\\\\My Perl Pipe\");die \"Fail to create pipe\\n\" if not $pipe;my $msg= \"I'm \" . Win32::LoginName. \" on \" . Win32::NodeName. \"\\n\" .\"I'm running script $0.\";print \"Send to Server:\\n$msg\\n\";die \"Fail to send message\\n\" if not $pipe->Write($msg);print \"Read from Server:\\n\";print $pipe->Read();$pipe->Disconnect;$pipe->Close;7Win32::Sound播放声音•Volume(音量), Play(文件,标志), Stop()#!/usr/bin/perl -wuse strict;use Win32;use Win32::Sound;Win32::Sound::Volume ('100%'); #或Volumn(左,右)Win32::Sound::Play (\"CLEAR.WAV\SND_ASYNC );my($hz, $bits, $channels) = Win32::Sound::Format (\"CLEAR.WAV\");Win32::Sleep(500);print \"Clear.wav : ${hz}Hz, ${bits}B, ${channels}C\\n\";sleep(1);Win32::Sound::Stop ();1;8即时生成、播放波形•产生并播放一段正弦波形use Win32::Sound;$WAV = new Win32::Sound::WaveOut(44100, 8, 2);$data = \"\"; $counter = 0;$increment = 441/44100;# Generate 44100 samples ( = 1 second)for $i (1..44100) {# Calculate the pitch # (range 0..255 for 8 bits)$v = sin($counter/2*3.14) * 128 + 128;# \"pack\" it twice for left and right$data .= pack(\"cc\$counter += $increment;}$WAV->Load($data); # get it$WAV->Write(); # hear it1 until $WAV->Status(); # wait for completion$WAV->Save(\"sinus.wav\"); # write to disk$WAV->Unload(); # drop it9通过Win32::OLE打开IE•Perl是Controller,启动/控制各种OLE Server•创建、调用方法、访问属性:–––––$app = Win32::OLE->new('OLE ProgID/Class ID', 'Destructor');远程启动时采用Win32::OLE->new(['machine', '…ID'], 'Destructor');OLE的出错信息不在$!中,要用Win32::OLE->LastError()$result = $app->Method(arguments);$result = $app->{Property}; $app->{Property} = exp;use Win32::OLE;$ie= Win32::OLE->new ('InternetExplorer.Application.1', 'Quit') #或直接用CLSID new('{0002DF01-0000-0000-C000-000000000046}',…|| die \"CreateObject: \" . Win32::OLE->LastError;$ie->{Visible} = 1;$ie->Navigate(\"http://www.google.com/\");while ($ie->{Busy}) {print \"Busy\\";sleep(1);}print \"Done.\\n\";#打开浏览器,连接Google主页,连接过程sleep(2);#中显示busy,完成后等2秒,最后退出•参考ActivePerl帮助文档的OLE-Browser和VB手册10OLE-Browser和其他帮助•Active Perl 帮助文件自带,要用到Perlscript功能•更详细的帮助,参考各个应用程序的帮助•Office类应用程序有VB帮助和对象浏览器–例如: Excel->Tool->宏->Visual Basic编辑器->[F2]11控制Winword的例子•new()不指定Destructor,Perl结束后应用程序不退出•采用缺省参数时, 填写undef, 例如SaveAs的语法是:–expression.SaveAs(FileName,FileFormat,LockComments,Password,AddToRecentFiles,WritePassword,ReadOnlyRecommended,EmbedTrueTypeFonts,SaveNativePictureFormat,SaveFormsData,SaveAsAOCELetter) (参考Winword的VB帮助文件)–在下面例子中用的是$doc->SaveAs('ole.doc',undef,undef,\"111\")•要用好OLE, 就要熟悉各种OLEServer的编程接口, 以及COM/DCOM的知识, 仅仅学会Perl是远远不够的。use Win32::OLE;#本例用于Word2000my $line = \"Hello World!\";#不适合Word97my $wd = Win32::OLE->new('Word.Application') || die \"CreateObject: \" . Win32::OLE->LastError;$wd->{Visible} = 1;my $doc = $wd->Documents->Add();$wd->Selection->Font->{Size} = 100;$wd->Selection->Font->{SmallCaps} = 100;$wd->Selection->Font->{Animation} = 3;$wd->Selection->TypeText($line);$doc->SaveAs('ole.doc',undef,undef,\"111\");12将数据写入Excel文件•打开Excel的另一种办法$Excel = Win32::OLE->GetActiveObject('Excel.Application')•Excel对象层次–Workbooks对象$wbs= $Excel->Workbooks–Workbook对象$wb = $wbs->Add() 新建一个book一个Workbook包含多个Worksheet和Chart对象$wb->SaveAs($name, …)–Worksheet对象$sh = $wb->Worksheets(1)–Range对象$R = $Sh->Range(\"A1:D5\")$R->{Value} = [ [第一行], [第二行], [第三行],…]$R->Font->{Bold} = 1 #选定范围单元格的字体属性•参考Excel的VB文档,参见实例程序excel.pl13录制VBA宏àPerl OLE脚本•工具à宏à录制新宏à…各种操作…à停止工具à宏à宏à编辑•找到关键的VB语句,转换为Perl OLE语句Sub 宏1()Range(\"A3:A5\").SelectWith Selection.HorizontalAlignment= xlGeneral.VerticalAlignment= xlBottom.WrapText= False.Orientation = 90.AddIndent= False.ShrinkToFit= False.MergeCells= FalseEnd WithColumns(\"A:A\").EntireColumn.AutoFitEnd Sub$Range->{Orientation} = 90;$Sheet->Columns(\"A:A\")->{EntireColumn}->AutoFit();14从Excel文件读取数据•打开Excel的第三个方法:打开现有的文件$Book = Win32::OLE->GetObject(Win32::GetCwd. '\\OLE2.xls','Quit')直接获得WorkBook对象use Win32;use Win32::OLEqw(in with);use Win32::OLE::Const 'Microsoft Excel';$Win32::OLE::Warn = 3;# die on errors...my $Book = Win32::OLE->GetObject(Win32::GetCwd. '\\OLE2.xls','Quit')or die \"Can't open OLE2.xls\";my $Sheet = $Book->Worksheets('Perl_OLE');my $data = $Sheet->Range(\"B3:E5\")->{Value};my ($row, $cell);foreach$row (@$data) {D:>perl excel3.plforeach$cell (@$row) {'80' '80' '85' '80'print \"'$cell'\\";'90' '80' '70' '70'}'60' '70' '90' '100'print \"\\n\";D:>_}15用Excel产生图表•引入Excel VB程序的各种常数•Chart对象的常用方法、属性:–{Name}, {ChartType}, {HasTitle}–SetSourceData({Source=>$Range, PlotBy=>常数})这里用了传递参数给OLE方法的第二种形式.–ChartTitle->{Text}use Win32::OLE::Const 'Microsoft Excel';•将图表转换成图片–$Chart->Export(文件名, 图形过滤器, 交互)•参考excel4.pl16