Reeks 1 | TIWI Intranet
Page 1 of 16
TIWI Intranet Reeks 1 COM programmatie in de praktijk Installeer thuis: 1. Perl: Download perl (Windows versie) [ActivePerl-5.12.1.1201-MSWin32-x86-292674.msi] inclusief perlscript en ActivePerl documentatie. Controleer in het register of er een tak HKEY_LOCAL_MACHINE\SOFTWARE\Activestate\PerlScript\1.0 is. In deze tak moet je de EnabledZones parameter aanpassen op 1, om in de volgende labo's met Internet Explorer als host zonder securityproblemen te kunnen werken. 2. De MSDN Library van Visual Studio 2008 : beschikbaar op WWW [http://www.microsoft.com/downloads/en/details.aspx?FamilyID=7bbe5eda-5062-4ebb-83c7d3c5ff92a373&displaylang=en] of CD .
De ActivePerl documentatie en MSDN Library zijn lokaal beschikbaar op de labocomputers en kan je raadplegen tijdens de testen. COM programmatie in de praktijk We bespreken in deze reeks de basisprincipes van COM programmatie aan de hand van twee eenvoudige COM hiërarchiëen. Een Windows script is een tekstfile, geschreven in een scripttaal (Script Engine). Een Windows script wordt niet gecompileerd in .exe vorm, maar is volledig aangewezen op een Scripting Host om zijn code at runtime uit te voeren. Elke scripting host biedt een omgeving aan die zorgt voor de correcte uitvoering van elk script, geschreven in een taal waarvoor de ActiveX script engine geïnstalleerd is. De meeste scripting hosts zijn toepassingen (zoals Internet Explorer). Deze laatste wordt in hoofdstuk 5 uitgebreid besproken. We bespreken nu een aantal mogelijkheden/verschillen van twee belangrijke hosts die vanuit een Command Prompt console worden opgestart. Hierbij geef je eerst de naam van de host, gevolgd door minstens één argument: de naam van het uit te voeren script. Scripting Host vanuit Command Prompt De volgende hosts zijn uitermate geschikt voor operating systeem verwante taken: • Perl : enkel in combinatie met engine PerlScript • WSH : Window Scripting Host
Perl als host Documentatie over Perl (en PerlScript) vind je in de ActivePerl documentatie, standaard geïnstalleerd op de labo-toestellen. Indien je voor deze host kiest, kan je niet automatisch COM-objecten gebruiken. Je moet WIN32::OLE de module inladen om COM-objecten te kunnen initialiseren (zie verder). In Emacs kan je heel gemakkelijk een script laten uitvoeren met Perl als host. Hiervoor beschik je,
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 2 of 16
indien je het .emacs configuratiebestand van de labocomputers gebruikt, over volgende snelle toetsencombinaties: F8 markeer alle tekst F5 of evalueer de gemarkeerde tekst als perl-programma Ctrl-Alt-p Ctrl-F5 laat de perl-tidy beautifyier de gemarkeerde tekst herformatteren
WSH : Windows Scripting Host WSH is standaard geïnstalleerd op Windows Server en XP/Vista/Windows 7, maar kan ook als optie geïnstalleerd worden op oudere 32-bit platformen, zoals Windows 98 of NT 4. De versie van WSH die we in de labo's gebruiken is 5.7 . Documentatie over WSH vind je in de MSDN Library onder Web Development / Scripting / Windows Script Technologies / Windows Script Host. WSH is geïmplementeerd als twee afhankelijke toepassingen: wscript en cscript. De wscript toepassing voert scripts uit in een GUI omgeving, terwijl cscript dezelfde scripts uitvoert in tekstmode. Beide toepassingen kan je opstarten in een Command Prompt console. Probeer alvast wscript /? respectievelijk cscript /?. De output van wscript verschijnt in dialoogboxen, waarin de gebruiker op OK moet klikken. De output van cscript komt direct in de console, zonder verdere gebruikersinteractie. We kiezen uiteraard voor de laatste toepassing. Met cscript uitgevoerde scripts zijn in zekere zin vergelijkbaar met DOS of NT batch opdrachten en met de shell scripts van Linux.
Script Host en Scripting Engine kiezen Als je kiest voor WSH, moet je ook de Scripting Engine opgeven bij het uitvoeren van een script. De optie //E:engine geeft aan welke engine gebruikt wordt. Ter illustratie: bewaar de onderstaande code (in PerlScript) in een bestand vb. print "print Hallo\n"; $WScript->Echo("echo Hallo\n");
Voer dit script uit op 3 manieren Host uitvoering opmerkingen Perl perl vb het WScript object is niet beschikbaar WSH met cscript cscript vb //E:Perlscript WSH met wscript wscript vb //E:Perlscript print lukt niet Je kan de optie //E:engine weglaten als de naam van je script een WSH-compatibele extensie heeft : .vbs (VbScript), .pls (PerlScript), .js (JScript), .... Nu wordt de juiste engine automatisch gekozen (voor Windows Server of XP/Vista/Windows 7). Probeer dit uit. Indien je problemen ondervindt vraag je, vanuit C:\Perl\bin, het commando regsvr32 PerlSE.dll. Dit kan enkel als administrator (gebruik runas /user:toestelnaam\administrator cmd) - gebruik het paswoord van de dag.... Deze instelling wordt onthouden op de computer, ook indien je geen administrator bent. Voor een script met extensie .pl kan je bovendien de host (perl) weglaten bij de uitvoering. Indien je WSH neemt als host is dit iets complexer. De extensie van het scriptbestand moet ingevuld zijn in de PATHEXT omgevingsvariabele (controleer met echo %PATHEXT%). Maar omdat wscript is ingesteld als default scripthost wordt de grafische versie gebruikt. Omdat scripts
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 3 of 16
niet ongevaarlijk zijn, kan het voorkomen dat deze mogelijkheid geblokkeerd wordt ( door een anti-virus programma ). Je kan, als administrator, de default host wijzigen naar cscript met het commando cscript //H:CScript. Hiermee deblokkeert ook de foutmelding bij de uitvoering van deze scripts. Ook deze instelling wordt onthouden op de computer. Indien je nu enkel de naam van je scriptfile opgeeft (met extensie) zal deze worden uitgevoerd met de default host en de automatisch gekozen script engine. Scripting engines : VBScript / PerlScript De meeste voorbeelden in de MSDN Library zijn geschreven in VBScript. Deze voorbeelden kan je enkel uittesten met WSH als host. Maak de volgende twee bestanden : Engine : VBScript PerlScript Naam bestand : hallo.vbs hallo.pls Inhoud bestand : WScript.echo "Hallo World" $WScript->echo ("Hallo World"); Als de instellingen die hiervoor beschreven werden correct zijn ingesteld, kan je beide scripts gewoon uitvoeren in een Command Prompt. Wijzig je de extensie van hallo.pls in .pl, dan wordt Perl gebruikt als host, en zal het niet lukken omdat je niet beschikt over het WSH object $WScript. Korte vergelijking tussen VBScript en PerlScript Uiteraard heeft elke taal zijn eigen functies, statements en bijzonderheden, waarvoor je best de documentatie raadpleegt. In herhaling Perl [perl_herhaling.html] vind je een kort overzicht van wat je vorig jaar geleerd hebt, raadpleeg ook de ActivePerl User Guide die op de Desktop gerefereerd wordt. De Web Development / Scripting / Windows Script Technologies - tak van MSDN Library bevat een aparte paragraaf VBScript met alle mogelijkheden van de scripttaal VBScript. De syntax van VBScript bestaat uit een subset van de syntax van Visual Basic. In een scripttaal heeft een variabele geen specifiek type en moet dus niet gedeclareerd worden. Het grote nadeel hiervan is dat domme typfouten in een variabelenaam niet gemakkelijk opgespoord worden. Je kan declaratie toch verplicht maken. Hieronder een kort overzicht met belangrijke verschillen: VBScript Case-sensitive ? Commentaar toevoegen : Afsluiten van een statement : Declaratie verplicht maken : Variabele declareren : Kan ook lokaal in functie/procedure Type van een variabele vragen : Com-object toekennen : Attribuut opvragen van een object :
file://C:\reeks1.html
PerlScript
nee ' comment nieuwe regel nemen Option Explicit
ja # comment ; toevoegen use strict;
Dim varnaam
my $varnaam; our $varnaam;
Typename() Vartype() Set varnaam = varnaam . attribuutnaam
/ $varnaam= $varnaam->{attribuutnaam}
3/11/2010
Reeks 1 | TIWI Intranet
Methode uitvoeren voor een object :
Page 4 of 16
varnaam . methodenaam (argumenten)
$varnaam->methodenaam (argumenten)
In VBScript moet je de Set instructie gebruiken om een COM-object toe te kennen aan een variabale. Indien je een gewone assignatie gebruikt, resulteert dit in een foutmelding (het script zal stoppen), en wordt de variabele opgevuld met Empty. In PerlScript wordt een referentie naar het object opgeslaan in de variabele, waardoor de attributen niet met de . worden opgevraagd. Om met beide scripttalen wat vertrouwd te geraken raden we aan om de oefeningen uit deze reeks afwisselend in VBScript en PerlScript op te lossen. Het ingebouwde WSH Object model WSH implementeert zelf een eenvoudig object model [../p0/sas_wsh_07c.gif] dat ondermeer toegang geeft tot het bestandssysteem en de omgevingsvariabelen: • Bovenaan staat WScript (zwart). Dit object heeft geen eigen ProgID en kan je enkel gebruiken met WSH als host (cscript of wscript). Het WScript object is dus niet beschikbaar als je met een andere host (vb. perl of Explorer) werkt !! • De objecten met een eigen ProgID (paars) worden onafhankelijk van het root-object toegekend en zijn wel vanuit elke Host bruikbaar. Deze objecten noemt men exposed, vb. WShNetwork • De andere objecten (geel/blauw) worden geïnitialiseerd met behulp van een attribuut van het bovenliggende object. Men noemt deze objecten non-exposed. De blauwe objecten zijn eigenlijk Collecties (zie verder) De beschrijving van alle objecten in de WSH - hiërarchie vind je in de MSDN Library in de tak Web Development / Scripting / Windows Script Technologies/Windows Script Host / Windows Script Host Basics / Windows Script Host Object Model
Het root-object WScript 1.
In het voorbeeld werd dit object reeds gebruikt. In PerlScript kan je met ref opvragen naar welk type object een variabele verwijst. voorbeeld bij sectie 1: print "\$WScript refereert naar ", ref $WScript, "\n";
2.
Elk object heeft attributen en methodes. Het WScript object heeft bijvoorbeeld een attribuut name en een methode echo. Onderstaand voorbeeld illustreert het voor de hand liggend gebruik. Let echter op de {} in PerlScript. Het is niet noodzakelijk om {} toe te voegen als je een attribuut ophaalt, maar het kan voor problemen zorgen als je dit niet doet !! Ook indien je een attribuut wijzigt (links van een assignatie) moet je de {} toevoegen. voorbeeld bij sectie 2: VBScript versie WScript.echo "Hallo World" waarde=WScript.name WScript.echo "name heeft waarde : " & waarde WScript.echo "name heeft waarde : " & WScript.name
file://C:\reeks1.html
' kan ook direct worden uitgeschreven
3/11/2010
Reeks 1 | TIWI Intranet
Page 5 of 16
PerlScript versie $WScript->echo("Hello World!"); $waarde=$WScript->name; #met of zonder {} geen enkel probleem print "name heeft waarde $waarde \n"; print "name heeft waarde $WScript->{name}\n"; print "name heeft waarde $WScript->name\n"; #geeft niet wat je had verwacht !!
3.
Bekijk in de on-line manual alle methodes van het root-object WScript. Naast methodes om andere objecten te binden vind je drie eenvoudige methodes echo, sleep, quit. Schrijf een script dat de cijfers 1,2,... 10 toont, met telkens 1 seconde tussentijd. Controleer ook dat de methode quit enkel in VBScript doet wat je verwacht. antwoord op vraag 3: VBScript versie Option Explicit Dim i For i=1 to 10 WScript.echo i WScript.sleep 1000 if i=3 Then WScript.quit Next PerlScript versie our $WScript = $WScript; use strict; foreach (1..10) { $WScript->echo($_); $WScript->sleep(1000); if ($_==3){ $WScript->quit(); #lukt niet om vroegtijdig te stoppen die ""; #zorgt dat het script direct stopt } } Opmerking: Indien je in perl met quit() het script probeert te stoppen, dan worden toch nog een aantal commando's uitgevoerd. Voeg je echter het perl-commando die toe dan stopt het script onmiddelijk. Je kan ook enkel het commando die gebruiken. Dit resulteert in een foutboodschap en laat het script onmiddelijk stoppen.
4.
Veel objecten hebben een default method of attribuut. Dit attribuut wordt aangesproken van zodra de object variabele gebruikt wordt zonder expliciete vermelding van een method of attribuut. Controleer in VBScript dat name het default attribuut is van WScript. Dit lukt niet in PerlScript. antwoord op vraag 4: WScript.echo "het default attribuut heeft als inhoud : ",WScript
5.
Het root-object WScript heeft 14 attributen [../p0/sas_wsh_60c.gif]. (De versie van Windows Script Host is afhankelijk van het operating system. De manual refereert naar de versie van Windows 2000 en je vindt er slechts 12 van de attributen terug.) Een aantal van die attributen bevatten eenvoudige informatie die je direct kan uitschrijven. Er zijn echter ook attributen die een ander object als return-waarde geven. In het onderstaand voorbeeld tonen we, voor alle attributen die kunnen uitgeschreven worden, de inhoud van deze attributen. Het toont ook voor de andere attributen welk soort object ze kunnen teruggeven.
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 6 of 16
Hierbij werd in de manual opgezocht welke informatie elk attribuut bevat. De attribuutnamen worden "hard-gecodeerd". voorbeeld bij sectie 5: VBScript versie WScript.echo "Volgende attributen kunnen worden uitgeschreven" WScript.echo WScript.echo "ScriptName : " & WScript.ScriptName WScript.echo "ScriptFullName : " & WScript.ScriptFullName WScript.echo "Version : " & WScript.Version WScript.echo "Interactive : " & WScript.Interactive WScript.echo "Name : " & WScript.Name WScript.echo "FullName : " & WScript.FullName WScript.echo "Path : " & WScript.Path WScript.echo WScript.echo "Extra argumenten die eenvoudig kunnen worden uitgeschreven:" WScript.echo WScript.echo "BuildVersion : " & WScript.BuildVersion WScript.echo "Timeout : " & WScript.Timeout WScript.echo WScript.echo "Volgende attributen van WScript kunnen niet worden uitgeschreven" WScript.echo WScript.echo "StdIn is " & TypeName(WScript.StdIn) WScript.echo "StdOut is " & TypeName(WScript.StdOut) WScript.echo "StdErr is " & TypeName(WScript.StdErr) WScript.echo "Arguments is " & TypeName(WScript.Arguments) WScript.echo WScript.echo "Application is " & TypeName(WScript.Arguments) WScript.echo " - > default waarde : " & WScript.Application & " = " & WScript.Application.name PerlScript versie $WScript->echo("Volgende attributen kunnen worden uitgeschreven"); $WScript->echo(); $WScript->echo("ScriptName : " . $WScript->{ScriptName}); $WScript->echo("ScriptFullName : " . $WScript->{ScriptFullName}); $WScript->echo("Version : " . $WScript->{Version}); $WScript->echo("Interactive : " . $WScript->{Interactive}); $WScript->echo("Name : " . $WScript->{Name}); $WScript->echo("FullName : " . $WScript->{FullName}); $WScript->echo("Path : " . $WScript->{Path}); $WScript->echo(); $WScript->echo("Extra argumenten die eenvoudig kunnen worden uitgeschreven:"); $WScript->echo(); $WScript->echo("BuildVersion : " . $WScript->{BuildVersion}); $WScript->echo("Timeout : " . $WScript->{Timeout}); $WScript->echo(); $WScript->echo("Volgende attributen van WScript kunnen niet worden uitgeschreven"); $WScript->echo(); $WScript->echo("StdIn is object van type : " . (ref $WScript->{StdIn})); $WScript->echo("StdOut is object van type : " . (ref $WScript->{StdOut})); $WScript->echo("StdErr is object van type : " . (ref $WScript->{StdErr})); $WScript->echo("Arguments is object van type : " . (ref $WScript->{Arguments})); $WScript->echo(); $WScript->echo("Application is een extra object van type : " . (ref $WScript->{Application}));
6.
Je kan dit iets meer automatiseren door in je script na te gaan wat de inhoud is van een bepaalde variabele. Schrijf een functie Inhoud (variabele) die voor een bepaalde variabele nagaat of het een object is. Indien het geen object is wordt de inhoud teruggegeven, anders wordt het type van het object teruggegeven. In VBScript kan je gebruik maken van de functies Vartype of TypeName. In PerlScript onderzoek je dit met ref . Controleer of je dezelfde uitvoer krijgt als in de vorige oefening. antwoord op vraag 6:
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 7 of 16
VBScript versie Function Inhoud(var) if VarType(var) = 9 or TypeName(var)="Object" Then Inhoud= "is object van type : "&Typename(var) else Inhoud=var
'In dit geval is dit voldoende
end if end function WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo WScript.echo
"Scriptname "ScriptFullname "Version "BuildVersion "Name "Fullname "Path "Timeout "Interactief "StdIn "StdOut "StdErr "Arguments "Application
: : : : : : : : : : : : : :
" " " " " " " " " " " " " "
& & & & & & & & & & & & & &
Inhoud(WScript.Scriptname) Inhoud(WScript.ScriptFullName) Inhoud(WScript.Version) Inhoud(WScript.BuildVersion) Inhoud(WScript.Name) Inhoud(WScript.FullName) Inhoud(WScript.Path) Inhoud(WScript.Timeout) Inhoud(WScript.Interactive) Inhoud(WScript.StdIn) Inhoud(WScript.StdOut) Inhoud(WScript.StdErr) Inhoud(WScript.Arguments) Inhoud(WScript.Application)
Het laatste object is het enige object met een default attribute name. Kijk naar het verschil in uitvoer bij de twee oplossingen. PerlScript versie sub Inhoud{ my $var = shift; my $ref = ref $var; return $ref ? "is object van type : " . $ref : $var; } print("\nScriptname print("\nScriptFullname print("\nVersion print("\nBuildVersion print("\nName print("\nFullname print("\nPath print("\nTimeout print("\nInteractief print("\nStdIn print("\nStdOut print("\nStdErr print("\nArguments print("\nApplication
: : : : : : : : : : : : : :
" " " " " " " " " " " " " "
, , , , , , , , , , , , , ,
Inhoud($WScript->{Scriptname})); Inhoud($WScript->{ScriptFullName})); Inhoud($WScript->{Version})); Inhoud($WScript->{BuildVersion})); Inhoud($WScript->{Name})); Inhoud($WScript->{FullName})); Inhoud($WScript->{Path})); Inhoud($WScript->{Timeout})); Inhoud($WScript->{Interactive})); Inhoud($WScript->{StdIn})); Inhoud($WScript->{StdOut})); Inhoud($WScript->{StdErr})); Inhoud($WScript->{Arguments})); Inhoud($WScript->{Application}));
De attributen StdIn, StdOut, StdErr initialiseren objecten die input, output en error - streams manipuleren. Merk op dat deze objecten niet voorkomen in de eigenlijke WSH-hiërarchie, je kan ze bovendien enkel gebruiken in cscript (niet in wscript). Ze maken een referentie naar een object van het type TextStreamObject [../p0/sas_wsh_80c.gif], dat telkens specifieke methods en attributen heeft om de stream te behandelen (zie on-line manual). De methods en attributen van de object worden aangesproken via de "." operator in VBScript, en met -> in PerlScript. Methods/attributen gedragen zich zoals reguliere procedures en functies en kunnen een returnwaarde hebben. 7.
Onderstaand voorbeeld vraagt een naam in te lezen. Zolang niets (= een lege string) wordt ingelezen moet de vraag herhaald worden. voorbeeld bij sectie 7:
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 8 of 16
VBScript versie set Uit=WScript.StdOut
'met expliciete toekenning van het non-exposed object
Do Uit.Write "Geef naam: " naam=WScript.StdIn.Readline Loop While naam=""
'zonder expliciete toekenning van het non-exposed object
WScript.echo vbCrLf & "Je gaf in: " & naam PerlScript versie my $Uit=$WScript->{StdOut}; my $naam; do { $Uit->Write("Geef naam: "); $naam=$WScript->{StdIn}->Readline(); } while $naam eq "";
#met expliciete toekenning van het non-exposed object
#zonder expliciete toekenning van het non-exposed object
$WScript->echo("Je gaf in: ".$naam); Je kan in perl ook inlezen zonder gebruik te maken van StdIn : Dit werkt enkel als je perl gebruikt als Host !! $naam=<>; chomp ($naam);
Initialiseren van COM-objecten met het ProgID 8.
In WSH gebruik je de methode CreateObject(ProgID) van WScript gebruiken om een exposed COM-object te initialiseren. De parameter is een string die de ProgID bevat van de klasse. De terugkeerwaarde is een referentie naar het object. Dit is niets anders dan een pointer naar de IDispatch interface van het object. In VBScript moet je de Set instructie gebruiken om een object referentie te kunnen toewijzen aan een variabele. Met de functie typename, resp. ref kan je controleren of het object inderdaad werd gevonden. In onderstaand voorbeeld wordt het WshShell object toegekend. Kijk wat er gebeurd als het ProgID een fout bevat, of als je Set weglaat. voorbeeld bij sectie 8: VBScript versie set win = WScript.CreateObject("WScript.Shell") WScript.echo typename(win) PerlScript versie $win = $WScript->CreateObject("WScript.Shell"); $WScript->echo(ref $win);
Als je niet over het $WScript object beschikt (Perl, Explorer als host), dan kan je bovenstaande methode niet gebruiken. De VBScript-engine beschikt over de functie Createobject(ProgID) met net dezelfde functionaliteit. set win = CreateObject("WScript.Shell") WScript.echo typename(win)
Perl(Script) stelt een enorme hoeveelheid extra functionaliteit ter beschikking met behulp van modules. Je kan een overzicht raadplegen en ook PerlScript modules downloaden op CPAN [http://www.cpan.org/], of met de ppm opdracht.
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 9 of 16
Modules gebruiken in PerlScript 9.
Informatie over de ingeladen modules vind je in de hash %INC, zoals in onderstaand voorbeeld wordt geïllustreerd. Je krijgt hierdoor toegang tot de geëxporteerde functies uit de module. Voer onderstaande code uit met host Perl en met host WSH. De module Win32::OLE::Lite wordt enkel ingeladen door PerlScript als je WSH gebruikt (met Perl als host dus niet). voorbeeld bij sectie 9: while (($key,$value)=each %INC) { print "\$INC{$key} = $value\n"; }
De module Win32::OLE::Lite is een deelmodule van Win32::OLE, die een aantal interessante/noodzakelijke functies en methodes bevat om COM objecten te gebruiken vanuit Perlscript. In de Perl-documentatie, de sectie Using OLE with Perl, staat beschreven dat je die module inlaadt met: use Win32::OLE qw(in with);
Onderzoek welke sub-modules nu worden ingeladen. In de inleiding werd ook de module strict ingeladen. Welke submodules worden dan ingeladen? (Je moet nu wel alle variabelen ook declareren.) De Win32::OLE module beschikt over de methode new(ProgID) waarmee je een COM-object kan initialiseren. $win = Win32::OLE->new("WScript.Shell"); print ref $win;
De beschrijving van alle beschikbare functies en methodes van deze module kan je opzoeken in dezelfde Perl-documentatie in de sectie Win32 / OLE. We bespreken kort de interessantste functies. 10.
Met QueryObjectType bekom je extra informatie over een COM object gelukt is. Vergelijk dit met de informatie die je met ref kon opvragen. voorbeeld bij sectie 10: use Win32::OLE; $win = Win32::OLE->new("WScript.Shell"); print "WScript.Shell : ", ref($win), " -- ",join(" / ",Win32::OLE->QueryObjectType($win));
11.
Met EnumAllObjects kan je een lijst maken van alle OLE-objecten die geladen zijn. Dit kan handig zijn bij debuggen. voorbeeld bij sectie 11: use Win32::OLE; $win = Win32::OLE->new("WScript.Shell"); $Count = Win32::OLE->EnumAllObjects( sub { my $Object = shift; printf "\n%-30s : %s",ref($Object),join(" / ",Win32::OLE->QueryObjectType ($Object));
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 10 of 16
} ); print "\n$Count OLE-objecten geladen\n"; Het aantal objecten dat ingeladen wordt hangt af van de Script Host die je gebruikt.
12.
Indien een fout optreedt zal het perlScript niet stoppen. Je kan echter met behulp van LastError() de foutmelding opvragen. Probeer dit zelf uit door een fout ProgId in te geven antwoord op vraag 12: use Win32::OLE; $foutobject = Win32::OLE->new("WScrfipt.Shell"); print "\nlast error= ",Win32::OLE->LastError() ;
13.
Een heel interessante mogelijkheid is de class variabele Warn instellen op 3. Hierdoor zal bij elke fout het script wel stoppen en ook de foutmelding uitschrijven. In de Perl documentatie vind je informatie over deze variabele en de betekenis van de waarden bij WIN32 / OLE. De foutmelding die je krijgt is afhankelijk van de Script Host. antwoord op vraag 13: use Win32::OLE; $Win32::OLE::Warn = 3; # of # Win32::OLE->Option(Warn => 3); $foutobject = Win32::OLE->new("WScrfipt.Shell");
De WSH-objecten verder bekeken Het WshShell object kan je met om het even elke host en engine inladen. We bekijken kort twee aspecten van dit COM object. 14.
Het attribuut CurrentDirectory van WshShell geeft de naam van de actieve directory : use Win32::OLE; $win = Win32::OLE->new("WScript.Shell"); print "\nCurrent dir : ", $win->{CurrentDirectory};
Een alternatief hiervoor die enkel in Perl(Script) beschikbaar is : use Cwd; print "\nCurrent dir : ",getcwd();
15.
Door het inladen van de module Cwd worden nog andere modules automatisch ingeladen. Welke? Het WshShell object geeft ook toegang tot de WshSpecialFolders collectie en de ingewikkelde collectie WshEnvironment. Als je Perl(Script) gebruikt is deze informatie veel eenvoudiger op te vragen met de hash %ENV. Vraag eerst met set een overzicht van de environment. Nu kan je zelf onderstaand voorbeeld naar believen uitbreiden: voorbeeld bij sectie 15: print print print print
"\nComputername: "\nAppdata : "\nHome : "\nPath :
file://C:\reeks1.html
",$ENV{COMPUTERNAME}; ",$ENV{APPDATA}; ",$ENV{HOME}; ",join("\n
",split (";",$ENV{PATH}));
3/11/2010
Reeks 1 | TIWI Intranet
Page 11 of 16
Collections Een Collection object bevat een verzameling van objecten die individueel kunnen aangesproken worden. De meeste collecties hebben een Count attribuut, dat weergeeft hoeveel objecten de collectie bevat. Individuele elementen worden meestal aangesproken met behulp van de Item (index) methode. Doorgaans is deze methode de default methode van het object, waardoor men de ->Item notatie kan weglaten, en men de indruk krijgt dat index een attribuut zou zijn. Hierdoor wordt de syntax om individuele elementen van collections aan te spreken identiek aan die om hashelementen aan te spreken. Meestal is de naam van een collectie object een meervoud (bijvoorbeeld Arguments). Gebruik voor de variabelen die refereren naar collecties ook altijd een naam in het meervoud, om duidelijk te maken dat deze objecten diverse data elementen bevatten. De indexering van collections moet niet altijd numeriek. Soms kan je voor dezelfde collectie, zowel numeriek als met een string indexeren. De methode van indexering wordt bepaald door de klasse van het object. Om onafhankelijk te zijn van de specifieke indexering, worden collections dikwijls afgelopen met behulp van de For Each ... IN ...; in VBScript en de foreach ... (in ...) instructie in PerlScript. Daarbij gebruik je de functie in, die door de module Win32::OLE wordt geïmplementeerd, om collections om te vormen in arrays van individuele objecten.
De collectie WshArguments 16.
Indien je perl gebruikt als host, kan je @ARGV gebruiken om de argumenten van een script te overlopen. Indien je WSH als host hebt, moet je (waarom ?) de collectie WshArguments gebruiken. Het onderscheid [../p0/sas_wsh_105c.gif] tussen Named en UnNamed Arguments is hierbij niet belangrijk. Onderstaande code illustreert hoe je deze collectie gebruikt. voorbeeld bij sectie 16: WshArguments is een non-exposed object, dat geïnitialiseerd wordt vanuit het WScript object, dus enkel met WSH als host beschikbaar. VBScript versie Option Explicit Dim argumenten,i Set argumenten = WScript.Arguments WScript.echo "Er zijn " & argumenten.Count & " argumenten : " For i=0 to argumenten.Count-1 WScript.echo argumenten(i) Next PerlScript versie $argumenten=$WScript->{Arguments}; foreach (0..$argumenten->{Count}-1){ #numeriek overlopen print "\n$_\t",$argumenten->Item($_); } Je kan ook het default attribuut Item weglaten: $argumenten=$WScript->{Arguments}; print "\n$_ \t $argumenten->{$_}" foreach (0..$argumenten->{Count}-1);
17.
Overloop de WshArguments collectie zonder de numerieke index. antwoord op vraag 17: VBScript versie Option Explicit Dim i WScript.echo "Er zijn " & WScript.Arguments.Count & " argumenten : "
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 12 of 16
For Each i IN WScript.Arguments WScript.echo i Next PerlScript versie use Win32::OLE in; print "$_\n" foreach in $WScript->{Arguments};
18.
Hoe kan je een tekst die bestaat uit meerdere woorden als 1 argument doorgeven? antwoord op vraag 18: Je plaatst de tekst tussen " "-tekens.
Type Library gebruiken Geïnterpreteerde omgevingen (zoals scripts) kunnen een beroep doen op type libraries, maar enkel om gebruik te maken van de erin gedefiniëerde symbolische constanten. In de documentatie worden constanten regelmatig gebruikt, maar het is niet altijd duidelijk wat hun waarde is. In plaats van de waarden op te zoeken in de documentatie of in de bijhorende Type Library (met Oleview) is het handiger om de bibliotheek zelf in te laden. Gebruik hiervoor de module Win32::OLE::Const Naam_bibliotheek. In de Perl documentatie vind je uitgebreide informatie over de mogelijkheden van deze module. Het argument Naam-bibliotheek wordt geïnterpreteerd als reguliere expressie. Enkel indien een "unieke" typelibrary aan de naamgeving voldoet zal ze ook worden ingeladen. Om het opzoeken van de bibliotheek in het register te versnellen wordt deze reguliere expressie vooraan impliciet uitgebreid met ^. Voeg daarom ook een .* toe indien de naam van de typelibrary niet begint met het opgegeven argument. Er treedt geen fout op indien er geen enkele bibliotheek aan de reguliere expressie voldoet !!. 19.
In de vorige reeks heb je de type libraries moeten opzoeken die horen bij de COM-klassen Excel.Sheet en CDO.Message. Laad nu beide libraries in, en schrijf een willekeurig gekozen constante uit (zoek de naam van een constante op met Oleview). Experimenteer met de reguliere expressie en kijk wat er gebeurt indien de bibliotheeknaam niet uniek is, of indien je een foute naam opgeeft. antwoord op vraag 19: use Win32::OLE::Const "Microsoft CDO for Windows 2000 Library"; #use Win32::OLE::Const ".*CDO"; #volstaat om de bibliotheek te vinden print "\ncdoSendUsingPort : ",cdoSendUsingPort; use Win32::OLE::Const "Microsoft Excel"; #use Win32::OLE::Const ".*Excel"; #volstaat om de bibliotheek te vinden print "\nxlHorizontaal : ",xlHorizontal; print "\nniet bestaand : ",xlHorizontaal; #geeft de naam zelf terug
20.
In de module Win32::OLE::Const beschik je over de interessante methode Load waarmee je alle constanten van een typelibrary in een hash kan inladen. Toon alle constanten van een bibliotheek, waarvan je de naam als argument meegeeft met je script. antwoord op vraag 20: Geef als argument bijvoorbeeld "Microsoft CDO for Windows 2000 Library" use Win32::OLE; use Win32::OLE::Const;
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
#met WSH $bibnaam=$WScript->Arguments(0); #met perl #$bibnaam=$ARGV[0];
Page 13 of 16
# beknopter dan $WScript->{Arguments}->Item(0)
$wd = Win32::OLE::Const->Load($bibnaam); while (($key,$value)=each %{$wd}){ print "$key :$value\n"; }
21.
De Load methode aanvaardt ook een OLE object als argument. In Perl(Script) beschik je dus heel eenvoudig over alle constanten van een typelibrary die hoort bij een specifiek COM-object. Gebruik deze methode om een overzicht te tonen van alle constanten van het basisobject $WScript van WSH. antwoord op vraag 21: Uiteraard lukt dit enkel met WSH als host : use Win32::OLE::Const; $wd = Win32::OLE::Const->Load($WScript); while (($key,$value)=each %{$wd}){ print "$key :$value\n"; } Indien perl als host gebruikt wordt dan moet je expliciet een OLE-object van het WScript object model inladen om daarmee de typelibrary in te laden: $win = Win32::OLE->new("WScript.Shell"); $wd = Win32::OLE::Const->Load($win);
Collaboration Data Objects (CDO) : mail versturen Het is de bedoeling om een script te schrijven dat een mail verstuurt. We beperken ons daarbij tot het versturen over het netwerk van een eenvoudige tekstboodschap naar één mail-adres, met behulp van het SMTP-protocol. De hoofdbedoeling van deze oefening is dat je leert werken met COM-objecten, leert opzoeken in de documentatie en de mogelijkheden van de module Win32::OLE begrijpt. Alle noodzakelijke informatie over de COM-objecten die we hiervoor nodig hebben, vind je in de MSDN Library terug in de tak WIN32 and COM Development / Messaging and Collaboration / Collaboration Data Objects (CDO) / CDO for Windows 2000. De subtak About CDO for Windows 2000 /CDO for Windows 2000 Object Model toont de volledige hiërarchie. De verdere beschrijving van alle klassen vind je terug in de subtak Reference / COM Classes . Voor onze eenvoudige mail gebruik je twee COM-klassen : COM klasse Message Configuration
ProgId CDO.Message CDO.Configuration
De beschikbare attributen/methodes staan beschreven in de Interface. Voor de "Message" klasse beperken we ons tot de interface IMessage . 22.
Een eerste stap is het initialiseren van een mail-object. Zoek de juiste attribuutnamen op in de interface IMessage. Vul gegevens in voor de afzender, de bestemmeling, het onderwerp
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 14 of 16
en de inhoud (in tekstformaat). In PerlScript moet je accollades {} gebruiken om een attribuut te kunnen initialiseren. voorbeeld bij sectie 22: use Win32::OLE; $mail = Win32::OLE->new("CDO.Message"); $mail->{TextBody} = 'Hallo'; $mail->{Subject} = 'COM' ; $mail->{From} = '
[email protected]'; #vul correct aan $mail->{To} = '
[email protected]'; #vul correct aan
23.
Als je nu de mail onmiddellijk verzendt met de methode Send(), dan zal de mail waarschijnlijk niet toekomen: je hebt immers niet opgegeven hoe dit moet gebeuren. (Indien Outlook Express correct geconfigureerd is, zal dit wel werken.) Hiervoor dient de Configuration klasse. Configuration settings worden ingesteld met behulp van de collectie Fields. Bepaal het aantal velden dat is ingesteld. antwoord op vraag 23: use Win32::OLE; $conf = Win32::OLE->new("CDO.Configuration"); print $conf->{Fields}->{Count};
24.
Elk element in de collectie is zelf een Field object. Een Field object is eigenlijk een basisobject, dat ook in andere toepassingen terugkomt. In de tak WIN32 and COM Development / Messaging and Collaboration / CDO 1.2.1 / CDO Library / CDO Reference vind je een uitgebreide beschrijving van o.a. dit Field object en bijhorende properties en methods. De belangrijkste attributen van dit Field object zijn : name, value. Geef een overzicht van de velden die standaard ingesteld zijn voor een configuration object. Bevat dit de waarden die je had verwacht ? antwoord op vraag 24: use Win32::OLE qw(in);
#inladen van de functie "in"
$conf = Win32::OLE->new("CDO.Configuration"); foreach (in $conf->{Fields}){ print "\n\nName : ",$_->{Name}; print "\n\tValue : ",$_->{Value}; }
Waarschijnlijk bevat dit configuratie object geen informatie over de uitgaande server. In de paragraaf CDO for Windows 2000 / Messaging / Messaging Programming Tasks / Configuring the Message Object / Sending or Posting Using the Network wordt beschreven welke instellingen noodzakelijk zijn om een mail te versturen over het netwerk met het SMTP-protocol : sendusing en smtpserver. Omdat dit object zijn informatie haalt bij het mail-programma Outlook Express, kan je dit heel eenvoudig oplossen door dit programma te initialiseren met een juiste account. Het belangrijkste is het instellen van de uitgaande server. Dit kan je thuis gemakkelijk uitproberen. Nu bevat het configuratie object veel meer velden, en zal het verzenden van de mail wel lukken.
Hoe stel je zelf het configuratie object in? Voeg de volgende initialisaties toe: $conf->Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "mail-out.hogent.be" #thuis a $conf->Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25; #niet n $conf->Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2; $conf->{Fields}->Update(); #is noodzakelijk
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
Page 15 of 16
Nu moet je nog deze configuratie instellen op het Message Object : $mail->{Configuration}=$conf;
#moet ingevuld worden
Nu zal het verzenden van de mail met send()wel lukken
Mag het iets meer zijn ? In deze laatste sectie leggen we uit hoe je meer informatie kan vinden in de type library om beter te begrijpen wat hiervoor is gebeurd. De namen van de velden die je moest instellen zijn eerder complex. 25.
Toon alle constanten van de type library die hoort bij de configuration class, zodat je bovenstaande namen terugvindt. antwoord op vraag 25: use Win32::OLE::Const; $conf = Win32::OLE->new("CDO.Configuration"); $wd = Win32::OLE::Const->Load($conf); while (($key,$value)=each %{$wd}){ print "$key :$value\n"; }
26.
Toon nu enkel de constanten uit de type library waarvoor de $key iets te maken heeft met sendusing of smtpserver. Je toont dus enkel die constanten waarvoor de naam een deelstring SendUsing of SMTPServer bevat. Je vindt de constanten cdoSMTPServer cdoSendUsingPort cdoSendUsingMethod die je nodig hebt voor de configuratie. De inhoud van deze constanten bevat de namen van de velden die je moest initialiseren in het Configuration object. antwoord op vraag 26: use Win32::OLE::Const; $conf = Win32::OLE->new("CDO.Configuration"); $wd = Win32::OLE::Const>Load($conf); while (($key,$value)=each %{$wd}){ print "$key :$value\n" if ($key=~/SendUsing/ ||$key=~/SMTPServer/); }
27.
Om het configuratie-object correct in te vullen, moet je enkel nog de identificatie van de smtp-server kennen (voor de Hogeschool is dit mail-out.hogent.be). Onderstaand voorbeeld gebruikt de constanten uit de type library om het configuration object juist in te stellen. Merk op dat je de namespace "http://schemas.microsoft.com/cdo/configuration" niet meer hard-codeert. voorbeeld bij sectie 27: use Win32::OLE qw(in); use Win32::OLE::Const; $conf=Win32::OLE->new("CDO.Configuration"); $wd =Win32::OLE::Const->Load($conf); $sendMethode=$wd->{cdoSendUsingMethod}; $sendPort =$wd->{cdoSendUsingPort}; $smtpServer =$wd->{cdoSMTPServer}; $conf->Fields($sendMethode)->{value}=$sendPort; $conf->Fields($smtpServer)->{value}="mail-out.hogent.be"; foreach (in $conf->{Fields}){ print "\n\nName : ",$_->{Name}; print "\n\tValue : ",$_->{Value}; }
file://C:\reeks1.html
3/11/2010
Reeks 1 | TIWI Intranet
28.
Page 16 of 16
Na een update van het configuratie-object, kan je voor het Message object de referentie naar dit configuratie-object instellen. Met send() wordt de mail nu effectief verstuurd. antwoord op vraag 28: use Win32::OLE qw(in); use Win32::OLE::Const; $mail = Win32::OLE->new("CDO.Message"); $mail->{TextBody} = 'Hallo uit perlScript'; $mail->{Subject} = 'COM' ; $mail->{From} = '
[email protected]' ; $mail->{To} = '
[email protected]'; $conf=Win32::OLE->new("CDO.Configuration"); $wd =Win32::OLE::Const->Load($conf);
#vul aan met je eigen mailadres
#instellen van de SPTMserver #volledige notatie $conf->{Fields}->Item($wd->{cdoSMTPServer})->{value} #thuis aanpassen
="mail-out.hogent.be"
;
#instellen van de poort #Item is weggelaten $conf->Fields($wd->{cdoSendUsingMethod})->{value} =$wd->{cdoSendUsingPort}; #instellen van timeout - niet noodzakelijk #superkorte notatie #$conf->{$wd->{cdoSMTPConnectionTimeout}}=25; #aanpassingen doorvoeren $conf->{Fields}->Update(); $mail->{Configuration}=$conf; $mail->Send();
29.
#is noodzakelijk #moet ingevuld worden
Je kan zelf een aantal andere mogelijkheden uitproberen, zoals een attachment toevoegen. Dit is echter niet zo gemakkelijk als het lijkt. Zoek de nodige attributen en methodes op in de documentatie.
Laatst gewijzigd op 05-10-2010 om 19:06 door Marleen Denert [mailto:
[email protected]]
file://C:\reeks1.html
3/11/2010