department at 800-762-2974. Fo r reseller info rmatio n, inc luding disc o unts and premium sales, please c all o ur Reseller Custo mer Servic e department at 800-434-3422. Fo r info rmatio n o n where to purc hase IDG Bo o ks Wo rldwide’s bo o ks o utside the U.S., please c o ntac t o ur Internatio nal Sales department at 317-596-5530 o r fax 317-572-4002. Fo r c o nsumer info rmatio n o n fo reign language translatio ns, please c o ntac t o ur Custo mer Servic e department at 800-434-3422, fax 317-572-4002, o r e-mail rights@idgbo o ks.c o m. Fo r info rmatio n o n lic ensing fo reign o r do mestic rights, please pho ne +1-650-653-7098. Fo r sales inquiries and spec ial pric es fo r bulk quantities, please c o ntac t o ur Order Servic es department at 800-434-3422 o r write to the address abo ve. Fo r info rmatio n o n using IDG Bo o ks Wo rldwide’s bo o ks in the c lassro o m o r fo r o rdering examinatio n c o pies, please c o ntac t o ur Educ atio nal Sales department at 800-434-2086 o r fax 317-572-4005. Fo r press review c o pies, autho r interviews, o r o ther public ity info rmatio n, please c o ntac t o ur Public Relatio ns department at 650-653-7000 o r fax 650-653-7500. Fo r autho rizatio n to pho to c o py items fo r c o rpo rate, perso nal, o r educ atio nal use, please c o ntac t Co pyright Clearanc e Center, 222 Ro sewo o d Drive, Danvers, MA 01923, o r fax 978-750-4470.
Library of Congress Cataloging-in-Publication Data
Fo r general info rmatio n o n IDG Bo o ks Wo rldwide’s bo o ks in the U.S., please c all o ur Co nsumer Custo mer Servic e
LIMIT OF LIABILITY/DISCLAIMER OF WARRANTY: THE PUBLISHER AND AUTHOR HAVE USED THEIR BEST EFFORTS IN PREPARING THIS BOOK. THE PUBLISHER AND AUTHOR MAKE NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE ACCURACY OR COMPLETENESS OF THE CONTENTS OF THIS BOOK AND SPECIFICALLY DISCLAIM ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. THERE ARE NO WARRANTIES WHICH EXTEND BEYOND THE DESCRIPTIONS CONTAINED IN THIS PARAGRAPH. NO WARRANTY MAY BE CREATED OR EXTENDED BY SALES REPRESENTATIVES OR WRITTEN SALES MATERIALS. THE ACCURACY AND COMPLETENESS OF THE INFORMATION PROVIDED HEREIN AND THE OPINIONS STATED HEREIN ARE NOT GUARANTEED OR WARRANTED TO PRODUCE ANY PARTICULAR RESULTS, AND THE ADVICE AND STRATEGIES CONTAINED HEREIN MAY NOT BE SUITABLE FOR EVERY INDIVIDUAL. NEITHER THE PUBLISHER NOR AUTHOR SHALL BE LIABLE FOR ANY LOSS OF PROFIT OR ANY OTHER COMMERCIAL DAMAGES, INCLUDING BUT NOT LIMITED TO SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR OTHER DAMAGES. Trademarks: All brand names and pro duc t names used in this bo o k are trade names, servic e marks, trademarks, o r registered trademarks o f their respec tive o wners. IDG Bo o ks Wo rldwide is no t asso c iated with any pro duc t o r vendo r mentio ned in this bo o k.
is a registered trademark o r trademark under exc lusive lic ense to IDG Bo o ks Wo rldwide, Inc . fro m Internatio nal Data Gro up, Inc . in the United States and/ o r o ther c o untries.
Welcome to the world of IDG Books Worldwide. IDG Books Worldwide, Inc., is a subsidiary of International Data Group, the world’s largest publisher of computer-related information and the leading global provider of information services on information technology. IDG was founded more than 30 years ago by Patrick J. McGovern and now employs more than 9,000 people worldwide. IDG publishes more than 290 computer publications in over 75 countries. More than 90 million people read one or more IDG publications each month. Launched in 1990, IDG Books Worldwide is today the #1 publisher of best-selling computer books in the United States. We are proud to have received eight awards from the Computer Press Association in recognition of editorial excellence and three from Computer Currents’ First Annual Readers’ Choice Awards. Our bestselling ...For Dummies® series has more than 50 million copies in print with translations in 31 languages. IDG Books Worldwide, through a joint venture with IDG’s Hi-Tech Beijing, became the first U.S. publisher to publish a computer book in the People’s Republic of China. In record time, IDG Books Worldwide has become the first choice for millions of readers around the world who want to learn how to better manage their businesses. Our mission is simple: Every one of our books is designed to bring extra value and skill-building instructions to the reader. Our books are written by experts who understand and care about our readers. The knowledge base of our editorial staff comes from years of experience in publishing, education, and journalism — experience we use to produce books to carry us into the new millennium. In short, we care about books, so we attract the best people. We devote special attention to details such as audience, interior design, use of icons, and illustrations. And because we use an efficient process of authoring, editing, and desktop publishing our books electronically, we can spend more time ensuring superior content and less time on the technicalities of making books. You can count on our commitment to deliver high-quality books at competitive prices on topics you want to read about. At IDG Books Worldwide, we continue in the IDG tradition of delivering quality for more than 30 years. You’ll find no better book on a subject than one from IDG Books Worldwide.
John Kilcullen Chairman and CEO IDG Books Worldwide, Inc.
Eighth Annual Computer Press Awards 1992
Ninth Annual Computer Press Awards 1993
Tenth Annual Computer Press Awards 1994
Eleventh Annual Computer Press Awards 1995
IDG is the world’s leading IT media, research and exposition company. Founded in 1964, IDG had 1997 revenues of $2.05 billion and has more than 9,000 employees worldwide. IDG offers the widest range of media options that reach IT buyers in 75 countries representing 95% of worldwide IT spending. IDG’s diverse product and services portfolio spans six key areas including print publishing, online publishing, expositions and conferences, market research, education and training, and global marketing services. More than 90 million people read one or more of IDG’s 290 magazines and newspapers, including IDG’s leading global brands — Computerworld, PC World, Network World, Macworld and the Channel World family of publications. IDG Books Worldwide is one of the fastest-growing computer book publishers in the world, with more than 700 titles in 36 languages. The “...For Dummies® ” series alone has more than 50 million copies in print. IDG offers online users the largest network of technology-specific Web sites around the world through IDG.net (http://www.idg.net), which comprises more than 225 targeted Web sites in 55 countries worldwide. International Data Corporation (IDC) is the world’s largest provider of information technology data, analysis and consulting, with research centers in over 41 countries and more than 400 research analysts worldwide. IDG World Expo is a leading producer of more than 168 globally branded conferences and expositions in 35 countries including E3 (Electronic Entertainment Expo), Macworld Expo, ComNet, Windows World Expo, ICE (Internet Commerce Expo), Agenda, DEMO, and Spotlight. IDG’s training subsidiary, ExecuTrain, is the world’s largest computer training company, with more than 230 locations worldwide and 785 training courses. IDG Marketing Services helps industry-leading IT companies build international brand recognition by developing global integrated marketing programs via IDG’s print, online and exposition products worldwide. Further information about the company can be found at www.idg.com. 1/26/00
Credits Acquisitions Editors Sherri Mo rningstar Jo hn Osbo rn
Project Editors Kurt Stephan Luann Ro uff
Technical Editor Chris Sto ne
Copy Editor Julie M. Smith
Media Development Specialist Jake Maso n
Permissions Editor Leno ra Chin Sell
Media Development Manager
Graphics and Production Specialists Ro bert Bihlmayer Jude Levinso n Mic hael Lewis Ramses Ramirez Vic to r Pérez-Varela Dina F Quan
Quality Control Specialist Laura Taflinger
Book Designer Murder By Design
Illustrator Mary Jo Ric hards
Proofreading and Indexing Yo rk Pro duc tio n Servic es
Stephen No etzel
Project Coordinator Linda Maro usek Jo e Shines
About the Author Dr. Tobias Weltner is a best-selling c o mputer bo o k autho r who has published mo re than 30 bo o ks o n Windo ws o perating systems, Ac tive Server Pages Internet tec hno lo gy, and to pic s suc h as Unix and Po stSc ript. He regularly c o ntributes to a number o f Euro pean c o mputer magazines and wo rks as senio r develo per c o nsultant fo r Mic ro so ft Germany. Ho wever, To bias do esn’t limit himself to c o mputer sc ienc e. In 1996, he earned his medic al degree and did so me researc h o n multi-o rgan failure in trauma patients befo re returning to the c o mputer arena. To bias prefers an easy-to -understand writing style and c o nc entrates o n the prac tic al aspec ts o f his wo rk. When time allo ws, To bias enjo ys c rew ro wing and his friendship with his fo rmer ho st family in Arizo na as well as his many friends in the West Co ast regio n. Yo u may c o ntac t him at [email protected].
To Claudia, my wife! Yo u suppo rted me in any way imaginable. And to Caro l and Dave Mansfield, who welc o med me to the States mo re than a dec ade ago , made me apprec iate the Americ an way o f life, and still are c aring friends.
Preface Windo ws Sc ripting is exc iting! To day, mo st pro fessio nal so ftware suites o ffer extensive sc ript suppo rt, enabling yo u to tailo r so ftware func tio ns exac tly to yo ur needs. The mo st impo rtant piec e o f so ftware, ho wever, the o perating system itself, do esn’t even bo ther supplying a similar useful way o f auto mating ro utine tasks. Instead, Windo ws left yo u with the o ld-fashio ned and ugly DOS batc h files. No t anymo re! Mic ro so ft has released Windo ws Sc ripting Ho st, and altho ugh its name do esn’t so und hero ic , it may well be o ne o f the mo st impo rtant inno vatio ns Mic ro so ft has released in the past years. And it’s o ne o f the mo st unkno wn and undo c umented tec hniques, to o . This is why yo u are reading Windo ws Scripting Se cre ts.
The Windo ws Sc ripting Ho st gives yo u the ability, fo r the first time, to talk direc tly to Windo ws — witho ut having to reso rt to so phistic ated pro gramming enviro nments. Yo u do n’t need to kno c k yo urself o ut just to get a list o f bro ken links o r find all files that yo u didn’t use within the last two mo nths. In fac t, yo u do n’t even need to kno w muc h abo ut pro gramming at all. Sc ript languages are easy, fault-to lerant, and fun to use.
Why Should You Use Windows Scripting? So what c an Windo ws Scripting Se cre ts do fo r yo u? A lo t! This bo o k is like an exc iting adventure game and hundreds o f sc ripts pro vide yo u with ready-to run examples. Get live demo nstratio ns o f what is po ssible rather than just reading abo ut it, and use the so urc e c o des as so lid fo undatio n fo r yo ur very o wn sc ripts and pro grams. Yo u will see results in a matter o f minutes rather than having to study theo retic al bac kgro und fo r weeks. This bo o k wo n’t just sc ratc h the surfac e, either. It go es deep into subjec ts suc h as DLLs, COM o bjec ts, the Windo ws API, TypeLibraries, IDispatc h Interfac es, and mo re. And unlike so me o ther bo o ks, yo u’ll learn these details almo st c asually. There’s no need to dig yo ur way thro ugh theo retic al o verhead. Instead, go ahead and do things: lo o k into real DLL files, retrieve sec ret type library info rmatio n, c all API func tio ns fro m yo ur o wn sc ripts, and see what happens. Have a lo o k:
■
Writing little time savers: As a warm up and c o mfo rtable start, yo u c an stic k entirely to o ne o f the Sc ript languages like VBSc ript and build little time savers that c alc ulate mo rtgages o r find o ut the day o f the week o f yo ur next birthday party. This is an exc ellent and fun way to get ac c usto med to the sc ript language itself. Kno wledge yo u gain here c an be used fo r the mo re so phistic ated sc ripting pro jec ts yo u find in this bo o k. It’s also a perfec t fo undatio n fo r yo ur perso nal c areer sinc e many o ther Mic ro so ft tec hno lo gies are based o n exac tly the same sc ripting language. Whether yo u plan to get into Internet pro gramming and e-c o mmerc e using Ac tive Server Pages, o r wo uld like to mo ve o n to pro fessio nal applic atio n develo pment and Visual Basic — feeling at ho me with the sc ript language VBSc ript is an exc ellent starting po int.
■
Extending the scope of your scripts: So ftware c o mpanies develo p applic atio ns filled with zillio ns o f func tio ns, desperately trying to please virtually any c usto mer need. The results are huge applic atio ns that so metimes o verwhelm users with c ho ic es they never need. On the o ther hand, even the best so ftware engineers will never be able to guess all o f yo ur needs and wishes, so many times there’s just no applic atio n available that do es exac tly what yo u want it to do . Sc ripting c an help o ut bec ause the Windo ws Sc ripting Ho st has the ability to “bo rro w” func tio ns fro m o ther applic atio ns so yo u c an pic k o ut tho se yo u really need. Even better, yo ur sc ripts c an ac t like so ftware glue and tie to gether so ftware func tio ns fro m different applic atio ns. In Chapter 21, fo r example, yo u will see ho w to glue to gether a TWAIN-sc anner driver with yo ur printer. This way, yo u get a po werful Xero x c o py mac hine — abso lutely free!
■
Developing your own Script extensions: Yo u are no t a pro grammer? Why no t? To o c o mplic ated? No develo pment enviro nment available? Do n’t limit yo urself! Instead o f spending a great deal o f mo ney o n shareware and c o mmerc ial so ftware, yo u c an do it yo urself. Yo u’ll be amazed o n ho w many ready-to -use c o mpo nents are already installed o n yo ur system — just waiting fo r yo u to take advantage o f them. It’s o nly a very small (and very undo c umented) step to develo p yo ur o wn Sc ripting Ho st extensio ns. And best o f all it’s free, and very easy to master. Mic ro so ft gives away the Mic ro so ft Co ntro l Creatio n Editio n. This so ftware is a full-fledged Visual Basic 5 develo pment enviro nment. Altho ugh Mic ro so ft has stripped o ut the ability to develo p “real pro grams,” the Sc ripting Ho st sec retly brings bac k everything yo u need to develo p yo ur o wn Sc ripting Ho st Extensio ns — whic h yo u c an even sell to o thers. Inside o f the MS CCE, yo u do n’t use muc h mo re than what yo u already kno w: VBSc ript, yo ur sc ripting language, is a subset o f the full-flavo red Visual Basic language. So there’s very little to learn to transfo rm yo u into a versatile and po werful so ftware develo per.
■
Untapping the real Windows power: Using the MS CCE, yo u blast away the last sc ripting limitatio ns. The MS CCE c an ac c ess any o f the basic Windo ws API func tio ns, even tho se that are heavily undo c umented. With so me spec ial tric ks, yo u c an also use func tio ns that were o riginally designed fo r the “elite” C pro grammers. So no matter whether yo u already have pro gramming experienc e o r whether all o f this still so unds
Pre fac e
xi
■ ■
like blac k magic , by the end o f this bo o k yo u will kno w ho w to bo ss aro und Windo ws in any way yo u please — kno wledge that also c o mes in handy fo r any Visual Basic pro grammer. ■ Administering Windows and the Network: Are yo u respo nsible fo r
so ftware updates o r wo rk as a system administrato r? Then c hanc es are great that sc ripting will get yo u a c o uple o f extra weeks o f vac atio n. The Sc ripting Ho st has full ac c ess to all impo rtant info rmatio n sto res: sc ripts c an ac c ess the entire file system and netwo rk. Sc ripts c an also lo o k inside o f the magic Windo ws Registry, the c entral info rmatio n database. And with the advent o f Windo ws 2000, sc ripts have full ac c ess to the Ac tive Direc to ry and c an c hange tho usands o f user ac c o unts and pro files in a c o uple o f minutes. The interfac e ADSI (Ac tive Direc to ry Servic e Interfac e) is even available fo r Windo ws NT and 9x and is disc ussed in great detail in Chapter 24. If this is no t eno ugh, the MS CCE allo ws yo u to add o n any additio nal windo ws func tio nality yo u need to administer yo ur system: shutting do wn mac hines remo tely, c hec king available disk spac es, and sending messages ac ro ss the netwo rk.
Who Can Use Windows Scripting? Everyo ne c an use sc ripting. Yo u. Yo ur neighbo r. Yo ur entire c o mpany. Sc ripting is everywhere, and c hanc es are it will bec o me very po pular. So far, Mic ro so ft has c o nc entrated effo rts o n making sc ripting available o n all 32-bit Windo ws platfo rms. Windo ws 98 and Windo ws 2000 already c o me with it. Windo ws 95 and Windo ws NT c an be easily updated to inc lude it. On all o f these Windo ws platfo rms, yo u c an run the same Sc ripting Ho st and the same sc ripts — witho ut c hanges, tweaks, o r adjustments. It’s a brave new wo rld!
This Book’s Structure Windo ws Scripting Se cre ts is lo aded with po werful and undo c umented info rmatio n, divided into five parts:
Part I: Scripting Kickstart Start yo ur jo urney with a VBScript “guerilla sessio n” that sho ws yo u all the highlights and pro fessio nal tweaks yo u need to kno w to write great scripts. Yo u will learn ho w to use the undo cumented Script Debugger to find erro rs quickly and step thro ugh yo ur co de. Learn ho w to use Visual Basic o r the free Visual Basic Co ntro l Creatio n Editio n to write yo ur o wn script extensio ns. Disco ver ho w to use undo cumented Windo ws API functio ns to display any o f the standard dialo g windo ws, and find o ut ho w DLL files are internally o rganized. As a special highlight, yo u will learn ho w to use scripts to untap the secret TypeLibraries and list all the metho ds and pro perties undo cumented co mpo nents pro vide.
xii
Windo ws Sc ripting Se c re ts
■
■
Part II: Conquering the File System Emplo y numero us sample sc ripts to c o ntro l files and fo lders, c reate yo ur o wn inc remental bac kup utility, find bro ken links, and c reate new text files fro m sc ratc h. Disc o ver ho w to use the Windo ws API to get ac c ess to c o mpletely undo c umented c o py func tio ns.
Part III: Starting and Controlling Other Software Learn ho w to launc h any so ftware, enumerate all the running pro grams, and send key stro kes to spec ific windo ws to remo te-c o ntro l dialo g bo xes and entire pro grams. Find o ut ho w to switc h between pro gram windo ws and c lo se pro grams at will.
Part IV: Accessing the Operating System Disc o ver ho w to read and write to the Windo ws Registry, c o ntro l numero us undo c umented Windo ws settings, and c hange sc reen reso lutio n o r refresh rate. Learn all abo ut events and ho w to use them to c o mmunic ate between pro grams and sc ripts.
Part V: Accessing Hidden Components Take advantage o f the many COM o bjec ts already installed o n yo ur system. Ac c ess TWAIN sc anners, sync hro nize yo ur lo c al hard drive with Web servers using FTP, ac c ess databases and design yo ur o wn HTML-based c usto m dialo g windo ws. As a spec ial highlight, use ADSI and the windo ws API to c o mpletely administer Windo ws NT and 2000 by sc ript.
Scripting: A Detailed View of Its Architecture There has been a lo t o f c o nfusio n abo ut what sc ripting really is — and in whic h sc enario s yo u c an use it. So let’s take a quic k lo o k at the general c o nc ept. There are o nly two parts required fo r sc ripting and they inc lude the sc ript language itself and a ho st in whic h the sc ripts are exec uted.
Script languages: Your options Mic ro so ft pro vides two sc ripting languages: VBSc ript and JSc ript (the Mic ro so ft versio n o f JavaSc ript). It is c o mpletely up to yo u whic h o ne yo u
Pre fac e ■
xiii ■
prefer, and sinc e the entire sc ripting arc hitec ture is highly mo dular, yo u c an also plug in o ther sc ripting languages like PERLSc ript o r REXX.
Scripting Hosts: There’s more than one! Sc ripting languages themselves c an’t do muc h. They are designed as “inpro c ess” DLLs, so they require a ho st applic atio n that lo ads and exec utes the DLL. Just c o nsider sc ripting languages to be plug-ins. Where do yo u plug them in? Yo u need a ho st applic atio n! Mic ro so ft has develo ped the Windo ws Sc ripting Ho st, whic h resides in WSCRIPT.EXE and CSCRIPT.EXE.
WSCRIPT.EXE is the “default” sc ript ho st and runs as a Windo ws pro gram. CSCRIPT.EXE, in c o ntrast, exec utes sc ripts within a DOS windo w. Yo ur sc ripts c an then ac t like DOS- o r UNIX-c o mmands and use the DOS windo ws fo r input and o utput. Whenever yo u sto re a VBSc ript in a file with the extensio n VBS, it will be exec uted by WSCRIPT.EXE using the VBSc ript engine. If yo u sto re a sc ript in a file with the extensio n .JS, it will be interpreted using the JSc ript engine. And if yo u use the file extensio n .WS, yo u c an mix different sc ript languages and use XML-tags fo r advanc ed o ptio ns. The Windo ws Sc ripting Ho st isn’t the o nly suitable ho st, tho ugh. Originally, sc ripting languages like VBSc ript and JSc ript were develo ped fo r Web designers. They c an use bo th sc ript languages inside o f HTML pages to add dynamic func tio nality. So Internet Explo rer may be c o nsidered just ano ther sc ripting ho st. Altho ugh it is perfec tly po ssible to embed any o f the example sc ripts yo u find in this bo o k into a HTML page, it’s no t always a go o d idea. Sc ripts are extremely po werful, and a malic io us sc ript c an easily trash the entire system, so yo u do n’t want to have yo ur bro wser exec ute just any sc ript fro m any Web site. This is why Mic ro so ft implemented sec urity settings into Internet Explo rer. As a default in mo st versio ns, advanc ed sc ripts wo n’t be exec uted o r will po p up a warning message first. Therefo re, the Windo ws Sc ripting Ho st is a muc h better alternative to run sc ripts lo c ally.
Applications that act as Scripting Host Even regular applic atio ns like a wo rd pro c esso r o r spreadsheet pro gram c an ac t as sc ript ho sts. Here, the intentio n is to use o ne o f the sc ript languages to c o ntro l the so ftware and design mac ro s. Ac tually, many pro fessio nal so ftware pac kages use ano ther sc ripting language c alled Visual Basic fo r Applic atio ns (VBA). This language is mo re po werful than VBSc ript and JSc ript, and VBA also inc ludes a so phistic ated develo pment enviro nment. Ho wever, VBA is no t free.
xiv
Windo ws Sc ripting Se c re ts
■
■
The sc ripting ho st and its sc ript languages are free o f c harge, and yo u c an easily integrate sc ript c apabilities into yo ur o wn so ftware by using the sc ript c o ntro l. By plac ing the free sc ript c o ntro l into yo ur o wn so ftware pro jec ts, yo u essentially transfo rm them into sc ripting ho sts. They no w c an ho st sc ript languages and use them to c o ntro l so ftware func tio nality. The impo rtant thing to remember is that yo u need a Sc ripting Ho st to exec ute sc ript languages. The Windo ws Sc ripting Ho st is the mo st versatile sc ript ho st bec ause it’s an independent applic atio n that c an c o ntro l an unlimited number o f o ther applic atio ns simultaneo usly. The Windo ws Sc ripting Ho st c an, fo r example, c o ntro l the Ko dak Imaging To o ls to sc an in an image and then feed it to WinWo rd. Also , the Windo ws Sc ripting Ho st requires very little memo ry, making it the perfec t c ho ic e fo r administrative sc ripts and sc ript to o ls.
A special Scripting Host: Active Server Pages Whether yo u exec ute a sc ript with WSCRIPT.EXE o r o ne o f the o ther sc ripting ho sts, the sc ript will always run lo c ally. Yo u c an’t start a sc ript remo tely o n ano ther mac hine. Ho wever, there is ano ther Mic ro so ft tec hno lo gy c alled Ac tive Server Pages (ASP). It’s part o f the Internet Info rmatio n Server and enables yo u to embed server-side sc ripts into yo ur HTML pages. Server side sc ripts will be exec uted o n the Web server, and o nly the result is transferred to the perso n who c alls the Web site. ASP is just ano ther ho st applic atio n, and uses the exac t same sc ripting engine. So yo u c an plac e any o f the example sc ripts in this bo o k into an ASP Web page and have them exec uted remo tely just by c alling the ASP page fro m so me remo te bro wser. Fo r example, yo u c an use the c o mmand extensio n fro m Chapter 16 to find o ut the available physic al memo ry, then use it as an ASP page to easily find o ut the memo ry statistic s o f yo ur Web server.
Scripting Host from the inside The Sc ripting Ho st is no thing mo re than a shell in whic h COM o bjec ts c an be exec uted. The kind and number o f c o mmands yo u c an use in yo ur sc ripts depends o nly o n the COM o bjec ts yo u “plugged in.” As a safe start, the Windo ws Sc ript Ho st always plugs in o ne o f the sc ripting languages. If yo u sto re yo ur sc ript in a VBS file, it will be VBSc ript, and if yo u use a JS file extensio n, it will be JSc ript. This sc ripting language pro vides yo u with the basic set o f c o mmands. Yo u do n’t need to stic k to this c o mmand set, tho ugh! Sc ripting is mo dular, and to be able to do mo re, yo u just need to plug in mo re COM o bjec ts. Plug in as many additio nal o bjec ts as yo u need! Fo r example, to use the WinWo rd spelling c hec ker, just plug in the Winwo rd COM o bjec t. Yo ur sc ripting c o mmand set will no w no t o nly inc lude the sc ripting language c o mmands but also all o f the WinWo rd c o mmands, inc luding the spelling c hec ker. In Chapter
Pre fac e ■
xv ■
4, yo u will get detailed info rmatio n abo ut all the COM o bjec ts available o n yo ur system and ho w to retrieve the c o mmands sto red inside o f them. Even if a partic ular so ftware pro gram do es no t c o me with a COM interfac e, yo u c an still c o ntro l its func tio ns. Either use SendKeys to send key stro kes to the pro gram windo w, o r develo p yo ur o wn COM o bjec t that “translates” between sc ripts and the so ftware. This is a very po werful c o nc ept, and it’s far less c o mplic ated than it seems. Chapter 11 sho ws yo u ho w to do this.
Get your system “scripting-ready” Mic ro so ft gives away the Sc ripting Ho st fo r free. Yo u just need to install it o n yo ur system. In additio n, there are many o ther free so ftware pro duc ts that help yo u develo p sc ripts.
What’s the story about the “new” Scripting Host? Windo ws Sc ripting Ho st was intro duc ed with Windo ws 98. Yo u c an find it either o n the Windo ws 98 CD-ROM o r o n the Windo ws NT Optio n Pac k. Ho wever, bo th so urc es o nly deliver the o ld WSH versio n 1.0. There are many go o d reaso ns no t to use this versio n. Mo st impo rtantly, the latest versio n (2.0) c o mes with many new and impo rtant features. There’s an easy rule — if yo u are in do ubt whether o r no t the latest versio n o f WSH is installed o n yo ur system: just go ahead and install the latest versio n anyway. It will update yo ur system if nec essary, and at the end yo u c an be sure yo u’re using the new WSH 2.0 with all o f its impro ved po wer and speed. To do wnlo ad the latest versio n o f WSH, go to : http://www.microsoft.com/msdownload/vbscript/scripting.asp?id=01
On Windo ws 95 and Windo ws NT, make sure yo u install Internet Explo rer 4 o r abo ve first. If yo u want to take advantage o f the sec ret Shell.Application o bjec t c o vered in Chapter 8, yo u do need Internet Explo rer 4. IE5 wo n’t install this o bjec t.
Updating Windows 2000 Windo ws 2000 is already up-to -date! Yo u do n’t need to do anything spec ial. Do n’t install any updates. Just happily mo ve o n to the first c hapter!
Obtaining the Visual Basic Control Creation Edition If yo u want to o pen the so urc e c o des fo r all o f the sc ript extensio ns, use internal Windo ws API func tio ns, o r c hange the sc ript extensio ns pro vided o n the c o mpanio n CD, yo u need the Visual Basic develo pment enviro nment. Yo u do n’t need to purc hase Visual Basic , tho ugh. Just do wnlo ad the free Visual Basic Co ntro l Creatio n Editio n: http://msdn.microsoft.com/vbasic/
xvi
Windo ws Sc ripting Se c re ts
■
■
downloads/cce/. All the samples in this bo o k have been c reated and c o mpiled with the VB CCE.
The security hole — and how to fix it Will sc ripts endanger yo ur system? There’s c urrently a lo t o f disc ussio n abo ut this impo rtant to pic , and even Mic ro so ft rec o mmends turning o ff Ac tiveX c o mpo nents inside o f IE4.
Why you need to protect your system Sc ripting is no t evil at all. And it’s no t dangero us, either. Installing the Sc ripting Ho st will do yo ur system no harm. It might, ho wever, make it mo re sensitive to o ther related sec urity issues. In o rder to wreak havo c , evil sc ripts need to be able to talk to yo ur c o mputer. It’s the o nly way a sc ript c an do so mething bad (suc h as c o nvinc e the CPU that it wo uld be better to erase the entire hard disk first thing in the mo rning). An e-mail that c o ntains fo ul c o ntent c an sit o n yo ur system fo r years and no t bo ther anyo ne. Ho wever, there are two majo r gro ups o f po tentially evil (i.e., dangero us) o bjec ts: pro grams and Ac tiveX c o ntro ls. They are equally dangero us bec ause they are equally po werful. Obvio usly, yo u sho uld never do wnlo ad so ftware fro m an unkno wn so urc e and run it right away. It’s c o mmo n prac tic e to first c hec k the so ftware using a virus sc anner. But even if the so ftware do es no t c o ntain a virus, it c an still c rash yo ur system. Any pro gram c an do this if it c o ntains erro rs o r do es things differently than yo u tho ught it wo uld. Ac tiveX c o ntro ls are just as po werful as regular pro grams. The o nly differenc e is that Ac tiveX c o ntro ls need to be ho sted by so me o ther pro gram, mo st c o mmo nly a Web bro wser. This makes them c o mparably small, so they c an be easily embedded into Web pages. Therefo re, o pening a Web page and allo wing any Ac tiveX c o ntro l to be exec uted witho ut c hec king it wo uld be just as irrespo nsible as starting unkno wn so ftware witho ut a virus c hec k. This is the who le sto ry. All that peo ple c urrently talk abo ut is the advic e no t to run Ac tiveX c o mpo nents witho ut a c hec k, and sinc e the built-in c hec k inside o f IE4 has pro ven to be weak, so me rec o mmend to no t allo w Ac tiveX c o mpo nents to run at all — inside o f IE4 bro wser, that is! The go o d news is that yo ur sc ripts — that is, all the sc ripts c o vered in this bo o k — do n’t run inside o f IE4, so they are no t subjec t to this c aveat abo ut Ac tiveX. They are no t limited by anything yo u turn o n o r o ff inside o f IE4. They have no thing to do with the Internet and are no t subjec t to any dangers that might arise fro m using it.
Pre fac e
xvii
■
■
A safe solution I do think yo u sho uld c hec k yo ur Internet Explo rer sec urity settings befo re yo u get started. Yo u sho uld make sure no Web page has the po tential to ac tivate COM o bjec ts o n yo ur c o mputer. To do this:
1. Open the Co ntro l Panel, and o pen the Internet mo dule. Then, c lic k o n the Sec urity tab.
2. In the Zo nes List, selec t Internet Zo ne. 3. Cho o se Custo m to c usto mize the Sec urity settings. Yo u no w have the c ho ic e whic h things c an be run by yo ur bro wser. One o f the entries applies to Ac tiveX c o mpo nents that might be unsafe.
4. Next, c ho o se Disable. Po tentially unsafe Ac tiveX c o mpo nents sho uld never be allo wed to run o n a Web page. They c an do virtually anything o n yo ur system, and allo wing them to run wo uld, in essenc e, allo w the Web autho r to take o ver yo ur entire mac hine.
Conventions Used in This Book Seven ic o ns appear thro ugho ut this bo o k. Yo u sho uld kno w their meanings befo re pro c eeding: Sec rets are the very c o re o f this bo o k; the Sec ret ic o n indic ates valuable extra info rmatio n no t c o mmo nly fo und elsewhere. Sec rets tell yo u mo re abo ut extra func tio nality, hidden c o mmands, po werful wo rkaro unds, and little-kno wn pro duc tivity gainers. The Undo c umented ic o n marks tec hnic al info rmatio n and bac kgro und yo u sho uld kno w abo ut, but wo n’t find in the o ffic ial do c umentatio n.
No tes highlight info rmatio n yo u sho uldn’t o verlo o k, so yo ur sc ripts run smo o thly and as intended. Tips are my perso nal rec o mmendatio ns. They may no t be as valuable as Sec rets, but still to ss in ideas what to do next and ho w to further explo it what yo u have just read abo ut. Cautio n indic ates info rmatio n yo u sho uld definitely take into c o nsideratio n. Mo st o f the sc ripting samples in this bo o k are friendly and benign. If yo u see a Cautio n ic o n, tho ugh, ho ld o n fo r a sec o nd, have a sip o f c o ffee, and make sure yo u understand the side effec ts and c o nsequenc es the Cautio n info rmatio n o utlines fo r yo u.
xviii
Windo ws Sc ripting Se c re ts
■
■
A Cro ss-Referenc e helps to tie to gether related to pic s o f this bo o k. A Cro ssReferenc e ic o n makes it easy to jump to a to pic that further enhanc es what yo u have just read abo ut.
This ic o n indic ates material fo und o n the c o mpanio n CD.
Tell Us What You Think Sinc e sc ripting is a lo t abo ut c o mmunic atio n between COM o bjec ts and rec yc ling c o de that’s already installed o n yo ur system, expec t to disc o ver even mo re sec rets and o ppo rtunities than tho se revealed by this bo o k. At the same time, also expec t to run into little pro blems every no w and then. Wo rking with sc ripting is no t always like wo rking a majo r applianc e -- yo u c an’t expec t to push a butto n and have it wo rk all the time. By that, I mean yo u will mo st likely have to develo p yo ur o wn so lutio ns and wo rk-aro unds fo r kno wn issues. Likewise, as yo u read and refer to this bo o k, yo u’ll undo ubtedly think o f ways in whic h this bo o k c an be impro ved. That said, I want to hear fro m yo u. If yo u are interested in c o mmunic ating with me direc tly to ask questio ns, share tips, and so o n, send e-mail to [email protected]. Be patient, and I’ll try to answer yo ur e-mails within a few business days.
Acknowledgments This bo o k wo uld never exist witho ut the c aring help o f a number o f very spec ial peo ple. Writing a bo o k like this requires lo ts o f suppo rt, bo th fro m the family fo r the many mo nths o f testing and explo ring, as well as fro m the IDG team o f edito rs. First and fo remo st I’d like to thank Claudia Wo lters fo r her patienc e, and fo r supplying me with lo ve, fo o d, and c heer even during the mo st stressful parts o f o ur lives. I’d also like to thank Jo hn Osbo rn fro m IDG Bo o ks Wo rldwide fo r his tremendo us wo rk in getting the pro jec t started. To gether, Jo hn and I c arefully planned this bo o k and bro ught to gether everything needed to make it po ssible. Thanks also to pro jec t edito r Kurt Stephan, c o py edito r Julie Smith, ac quisitio ns edito r Sherri Mo rningstar, and freelanc e develo pment edito r Luann Ro uff. I wo rked c lo sely with them during the develo pment and pro duc tio n o f this bo o k, and their c o mments and suggestio ns were always welc o me. I apprec iate their great skills and o utstanding c o mmitment. Finally, many thanks to tec h edito r Chris Sto ne, who spent numero us ho urs testing the c o de and do uble-c hec king that everything ran smo o thly.
Contents at a Glance Prefac e ix Ac kno wledgments
xix
P a r t I: S c r ip t in g Kic k s t a r t
1
Chapter 1: Sc ript Develo pment with Ease 3 Chapter 2: VBSc ript Guerilla Sessio n 31 Chapter 3: Kidnapping Objec ts 85 Chapter 4: Develo ping Yo ur Own Sc ript Co mpo nents 117 Chapter 5: Using Internet Explo rer as the Output Windo w Chapter 6: Using System Dialo g Bo xes 185
155
P a r t II: Co n q u e r in g t h e F ile S ys t e m 2 1 7 Chapter 7: Ac c essing the File System Chapter 8: Advanc ed File System Tric ks Chapter 9: Mastering Links 289
219 249
P a r t III: S t a r t in g a n d Co n t ro llin g Ot h e r S o ft w a re Chapter 10: Launc hing Any Pro gram By Sc ript Chapter 11: Co ntro lling Running So ftware 355 Chapter 12: Gaining Full Co ntro l Over Any Windo w Chapter 13: Starting Sc ripts Auto matic ally 393
323 367
P a r t IV: Ac c e s s in g t h e Op e r a t in g S ys t e m 4 0 5 Chapter 14: Getting Ac c ess to the Registry 407 Chapter 15: Registry Tweaks 423 Chapter 16: Getting System Info rmatio n 483 Chapter 17: Wo rking with Events 509 Chapter 18: Develo ping Unix-like Co mmands
529
P a r t V: Ac c e s s in g Hid d e n Co m p o n e n t s Chapter 19: Using the WebBro wser Co ntro l 539 Chapter 20: Internet and Co mmunic atio ns 559 Chapter 21: Fax, Printer, Sc anner, and Graphic s Chapter 22: Fun, Tric ks, and Multimedia 607 Chapter 23: Using Databases 645 Chapter 24: Managing Windo ws NT/ 2000 Server
581
669
537
321
xxii
Co nte nts at a Glanc e
■
■
Ap p e n d ix A 6 9 7 Ap p e n d ix B 7 0 1 In d e x 7 0 7 En d -Us e r Lic e n s e Ag re e m e n t 7 2 8 CD-R o m In s t a lla t io n In s t r u c t io n s
732
Contents P re fa c e
ix
Ac k n o w le d g m e n t s
x ix
P a r t I: S c r ip t in g Kic k s t a r t
1
Ch a p t e r 1 : S c r ip t De ve lo p m e n t w it h Ea s e 3 Writing Yo ur First Sc ript 3 Editing the c o ntents o f a sc ript 5 Co nveniently starting new sc ripts 6 Auto matic ally renaming and o pening new sc ripts 8 Getting Help When Sc ripts Misbehave 11 Finding the right parts o f yo ur sc ripts 11 Canc eling run-away sc ripts 15 Invo king the Sc ript Debugger 15 Exec uting Sc ripts Line by Line 19 Repairing sc ript erro rs 20 When the Debugger sto ps answering 21 Setting breakpo ints 21 Lo gging Yo ur Sc ript’s Ac tivity 21 Lo gging events o n NT24 Cho o sing the kind o f lo g entry 25 Handling Erro rs Yo urself 26 Preventing erro rs fro m happening 26 Dealing with unpredic table erro rs 28 Turning o ff erro r handling the smart way 29
Ch a p t e r 2 : VB S c r ip t Gu e r illa S e s s io n Getting Input and Sho wing Results Asking questio ns 32 Chec king info rmatio n type 34 Asking simple yes-o r-no questio ns Asking questio ns with a time-o ut Passing Arguments to Sc ripts 40 Dragging files o nto yo ur sc ript ic o n Using DOS input and o utput streams The Truth Abo ut VBSc ript Variables Finding o ut the variable subtype Co nverting variables 48 Using variable arrays 51
32
36 38 40 42 46 46
31
xxiv
Co nte nts
■
■
Dissec ting strings 56 Co nverting text fo rmats 59 Using Rando m Numbers 61 Enc rypting files using rando m numbers 62 Dec rypting files 62 Have Yo ur Sc ripts Make Dec isio ns 65 If...then...else 65 Selec t c ase 67 Lo o ping: Do ing So mething Many Times 67 Fo r...next 68 Fo r eac h...next 68 Do ...lo o p 70 Exiting lo o ps prematurely 71 The Beauty o f Func tio ns and Pro c edures 72 Defining a pro c edure 72 Returning values with the help o f func tio ns Co mmo n pitfalls with pro c edures and func tio ns Passing results using arguments 76 Using Dic tio naries 80 Using c ase-insensitive dic tio naries 81 Overview: pro perties and metho ds 82 Dec laring Variables Explic itly 83 Playing safe: dec laring variables 83 Dec laring o r no t dec laring: a c ase example
Ch a p t e r 3 : Kid n a p p in g Ob je c t s
73 74
83
85
What Objec ts Really Are 85 Ho w Can I Talk To COM Objec ts? 86 Co nnec ting to an Objec t 86 Kno wing Whic h Objec ts Are Available 88 Finding Out Where Objec ts Are Sto red 91 Finding Out Undo c umented Objec t Info rmatio n Listing All Auto matio n Objec ts 98 Determining Whether an Objec t is Sc riptable Auto -Do c umenting Undo c umented Objec ts Getting Mo re Help On Spec ific Co mmands Finding Mo re Info rmatio n Abo ut Co mmands
94 100 105 108 115
Ch a p t e r 4 : De ve lo p in g Yo u r Ow n S c r ip t Co m p o n e n t s Getting Ac c usto med to VB CCE 118 To o lbo x 118 Main windo w 119 Pro jec t Explo rer 119 Pro perties windo w 120 Fo rm Layo ut windo w 120 Develo ping Yo ur Own Sc ript Extensio n Assigning a name to yo ur c o ntro l Co mpiling the COM o bjec t 123 Testing yo ur new o bjec t 123 Advantages o f COM o bjec ts 124
121 122
117
Co nte nts ■
xxv ■
Calling Windo ws API Func tio ns 124 Opening and c lo sing the CD-ROM tray 125 Ho w API func tio ns really wo rk 127 Lo o king Inside DLL Files 129 Dec rypting the c o ntents o f a DLL file 129 Develo ping Dialo g Bo xes 131 Designing a fo rm 132 Cho o sing the right element o rder 133 Co mpiling yo ur COM o bjec t 134 Adding c o de to make yo ur windo w appear 134 Adding c o de to make yo ur windo w do so mething 136 Using Pro perties to Change Yo ur Windo w’s Behavio r 139 Ac c essing yo ur element’s pro perties 140 Making pro perties ac c essible fro m the o utside 140 Using Optio nal Parameters 141 Spec ifying default values 142 Detec ting missing arguments 142 Unc o vering Spec ial Windo w Pro perties 142 Changing the c o lo rs 143 No n-resizable windo ws 143 Spec ial dialo g windo ws 143 Po sitio ning windo ws in the c enter o f the sc reen 144 Implementing Spec ial Windo w Behavio r 144 Resizing the c o ntents o f yo ur windo w 144 Preselec ting windo w elements 147 Respo nding to the [Enter] key 147 Displaying OLE Erro r Messages as Clear Text 147 Creating yo ur new OLE erro r spy to o l 148 Finding o ut mo re abo ut OLE erro rs 149 Distributing Yo ur Self-Made COM Objec ts 150 Manually registering a COM o bjec t 150 Preparing a setup pac kage 152 Impo rtant c aveats yo u must kno w abo ut 153
Ch a p t e r 5 : Us in g In t e r n e t Ex p lo re r a s t h e Ou t p u t Win d o w Finding Out the Sec ret Func tio ns Inside IE 156 Determining a pro gram’s real name 156 Reading o ut sec ret TypeLibrary info rmatio n 157 Opening Internet Explo rer with Style 157 Writing so mething into the IE windo w 158 Dynamic ally c hanging the IE c o ntents 159 Respo nding to Events 161 Finding o ut whic h events the o bjec t suppo rts 163 The perfec t o utput windo w example 165 Sizing the IE windo w 167 Respo nding to Events Inside Yo ur Do c uments 168 Setting up dialo g elements and butto ns 168 Sto pping the sc ript until events are fired170 Creating yo ur o wn HTML dialo g bo xes 171 Getting Info rmatio n Abo ut Internet Explo rer DHTML Objec t Mo del
174
155
xxvi
Co nte nts
■
■
Generating HTML-fo rmatted do c umentatio n manuals 176 Retrieving undo c umented info rmatio n abo ut the sc reen o bjec t
Ch a p t e r 6 : Us in g S ys t e m Dia lo g B o x e s
185
Where Do System Dialo g Bo xes Co me Fro m? 185 Opening system dialo g bo xes 186 Finding o ut mo re info rmatio n abo ut system dialo g bo xes 187 Using Other System Dialo g Bo xes 188 Managing flags and spec ial behavio r 189 Pic king a c o lo r 192 Wrapping System Dialo g Bo xes 193 Creating yo ur o wn system dialo g bo xes 193 Getting ac c ess to the system dialo g bo xes 194 Using the Fo lder Pic ker 197 Ac c essing Fo lder Pic ker thro ugh API func tio ns 198 Auto matic ally do c umenting all sec ret Fo lder Pic ker o ptio ns Getting Ac c ess to the Hidden Ic o n Pic ker 203 Ho w to c all undo c umented shell func tio ns 203 Displaying ic o ns hidden in the system files 205 Displaying and So rting Lists 207 Getting Aac ess to the ListView 207 Designing and so rting lists 207 So rting lists witho ut dialo g bo xes 211 Diving into do c umentatio n and so urc e c o de 212 Suc c essfully Dealing with API Func tio ns 213 String handling — undo c umented Visual Basic c o mmands 213 Dealing with ANSI and UNICODE 214 Cutting exc ess string spac e 215 Experimenting and getting so urc e c o de fo r free 215
P a r t II: Co n q u e r in g t h e F ile S ys t e m 2 1 7 Ch a p t e r 7 : Ac c e s s in g t h e F ile S ys t e m
182
219
Finding the Sec ret Bac kdo o r to the File System 219 Ac c essing a drive 220 Finding info rmatio n abo ut pro perties and metho ds Getting Details Abo ut Yo ur Drives 221 Clo sely examining the Drive o bjec t 222 Is the drive ready fo r ac tio n? 223 Changing a drive’s vo lume name 224 Using a drive’s serial number 224 Determining drive type and file system 224 Finding o ut available spac e o n drives 225 Ac c essing Fo lders 230 Examining the Fo lder o bjec t 231 Determining a fo lder’s to tal size 232 Finding and deleting empty fo lders 234 Creating new fo lders 236
221
201
Co nte nts ■
xxvii ■
Organizing Files 237 Ac c essing files 238 Mastering File Attributes238 Reading file and fo lder attributes Changing a file’s attribute 240 Changing File Co ntent 241 Peeking into files 241 Creating Files 246 Renaming files 247
239
Ch a p t e r 8 : Ad va n c e d F ile S ys t e m Tr ic k s
249
Using Advanc ed File System Metho ds 249 Kidnapping the shell’s c o py statio n 250 Getting ac c ess to the Windo ws file servic es 250 Understanding SHFileOperatio n 250 Deleting Files to the Rec yc le Bin 253 Emptying the rec yc ler 255 Co pying and Mo ving Files 256 Bac king up valuable data 256 Co pying files to multiple fo lders 259 Fo rmatting Drives 259 Unc o vering Extended File Versio n Info rmatio n 262 Ac c essing file versio n info rmatio n 262 Finding o ut file versio ns and c o pyright info rmatio n Searc hing fo r 16-Bit Windo ws files 265 Searc hing fo r DOS files 266 Explo ring Windo ws system files 266 Co mpressing (and dec o mpressing) files 269 Getting ac c ess to c o mpressio n func tio ns 269 Squeezing files o nto a disk 269 Dec o mpressing c o mpressed files 271 So me sec o nd tho ughts abo ut c o mpressio n 272 The Sec ret Shell View o n the File System 273 An inside view o f the shell.Applic atio n o bjec t 273 Ac c essing fo lders the shell way 274 Finding o ut a fo lder’s name 276 Reading fo lder c o ntents 276 Retrieving sec ret file info rmatio n 278 Ac c essing spec ial virtual Windo ws fo lders 279 Translating between namespac es 281 Calling a file’s Pro perty page 282 Opening Pro perties windo ws as mo dal windo ws 284 Ac c essing c o ntext menu Co mmands the smart way Calling Pro perties pages using API c alls 286
Ch a p t e r 9 : M a s t e r in g Lin k s 2 8 9 Why Do I Need Links Anyway? 289 Creating a new link file 290 Examining the sho rtc ut o bjec t 290
263
284
xxviii
Co nte nts
■
■
Ac c essing Existing Link Files 291 Searc hing fo r invalid links 291 Finding (and eliminating) duplic ate keybo ard sho rtc uts Changing a Sho rtc ut Ic o n 295 Bo rro wing system ic o ns 295 Changing yo ur pro gram menu’s ic o ns 299 Creating yo ur o wn ic o ns 300 Inserting Sc ripts into Spec ial Plac es 300 Starting sc ripts auto matic ally 301 Using sc ripts as a Send To extensio n 302 Advanc ed Sho rtc ut Tric ks 305 Pro viding o ptio nal arguments 305 Selec ting a new windo w size 306 Ac c essing the shell link o bjec t 307 Examining the shell’s link o bjec t 308 Reso lving links 309 Bac kgro und: Ho w Windo ws reso lves links 312 Using the o ffic ial link reso lving dialo g bo x 313 Designing Co ntext menu extensio ns 315 Selec ting a link target 318
293
P a r t III: S t a r t in g a n d Co n t ro llin g Ot h e r S o ft w a re Ch a p t e r 1 0 : La u n c h in g An y P ro g r a m B y S c r ip t Launc hing Pro grams 323 Launc hing pro grams direc tly 324 Determining windo w size 327 Waiting fo r a pro gram to finish 328 Remo te Co ntro lling Running Pro grams 329 Getting to kno w SendKeys 329 Direc ting keys to the right windo w 332 Telling windo ws to switc h fo c us no matter what 333 Finding o ut whether a windo w exists 335 Safely direc ting keystro kes to the windo w o f yo ur c ho ic e Remo te c o ntro lling menus and the Start menu 338 Shutting do wn all running pro grams 339 Exec uting DOS Co mmands 344 Feeding DOS c o mmands to the interpreter 344 Reading in the DOS c o mmand results 345 Feeding answer files to DOS c o mmands 346 Launc hing Co ntro l Panel Items 347 Where do Co ntro l Panel items live? 347 Exec uting Co ntro l Panel items 348 Ac c essing So ftware Thro ugh CreateObjec t 349 Remo te c o ntro lling Mic ro so ft Wo rd 349 Ac c essing the Wo rd spell-c hec ker 351 A who le new universe . . . 353
323
335
321
Co nte nts ■
xxix ■
Ch a p t e r 1 1 : Co n t ro llin g R u n n in g S o ft w a re 3 5 5 Co ntro lling So ftware Thro ugh Pro c essIDs 355 Ac c essing Pro c essIDs direc tly 355 Clo sing applic atio ns under all c irc umstanc es Clo sely mo nito ring a pro gram 357 Running pro grams sync hro no usly 358 Co ntro lling windo w style 359 Clo sing external pro grams 360 Splitting Pro grams into Mo dules 360 Whic h Windo ws versio n is running? 361 Enumerating running pro c esses 362 Listing pro gram mo dules 363
356
Ch a p t e r 1 2 : Ga in in g F u ll Co n t ro l Ove r An y Win d o w Full Co ntro l Over Any Windo w 367 Ac c essing any windo w 368 Bringing a windo w to the fo regro und 371 Clo sing a windo w 372 Making Windo ws Invisible 372 Finding o ut the c urrent windo w style 372 Changing windo w style dynamic ally 374 Changing Windo w Size and Mo ving Windo ws Finding o ut c urrent windo w dimensio ns 375 Changing windo w size 376 Mo ving windo ws aro und 376 Resizing windo ws 377 Flashing a Windo w Title Bar 378 Flashing title bars manually 378 Flashing title bars auto matic ally 378 Manipulating Windo w Butto ns 379 Disabling minimize and maximize 380 Disabling the windo w system menu 380 Disabling windo w resizing 381 Hiding and Casc ading All Windo ws 381 Minimizing all o pen windo ws 381 Casc ading and tiling windo ws 382 Explo ring Windo w Internals and Child Windo ws Ac c essing system windo ws 383 Finding windo w parents 384 Finding c hild windo ws 385 Hiding the Start menu butto n 386 Enumerating c hild windo ws 386 Bro wsing thro ugh system windo ws 387 Hiding the deskto p 389 Changing deskto p View mo de 389 Capturing Windo w Co ntent 390 Capturing the entire sc reen 390 Capturing the ac tive windo w 391 Capturing any windo w 391 Displaying a windo w preview 391
375
382
367
xxx
Co nte nts
■
■
Ch a p t e r 1 3 : S t a r t in g S c r ip t s Au t o m a t ic a lly 3 9 3 Starting Sc ripts the Smart Way 393 Launc hing sc ripts at lo go n 393 Hiding sc ript launc h 394 Launc hing sc ripts befo re lo go n396 Launc hing sc ripts in intervals 396 Inserting Sc ripts into Co ntext Menus 397 Inserting new c o mmands into the fo lder c o ntext menu Inserting new c o mmands into any file’s c o ntext menu Co pying the filename to the c lipbo ard 403
398 401
P a r t IV: Ac c e s s in g t h e Op e r a t in g S ys t e m 4 0 5 Ch a p t e r 1 4 : Ge t t in g Ac c e s s t o t h e R e g is t r y Getting to Kno w the Registry 407 Where do es the Registry live? 407 Ac c essing Registry c o ntent 408 Bac king up the Registry 409 Reading and Writing to the Registry 411 Reading the Registered Owner 411 Changing Registry info rmatio n 412 Tric ks and tips aro und Registry edits 413 Deleting Registry values 414 Creating Advanc ed Registry To o ls 415 Enumerating subkeys 415 Listing subkey entries 416 Versio n-independent Windo ws settings 417 Writing Registry sc ripts fo r spec ific Windo ws versio ns Finding o ut the variable type 418 Reading binary data 419 Writing binary data 419 Deleting Registry keys and values 420 Finding o ut if a key exists 420 Additio nal things to remember . . . 421
Ch a p t e r 1 5 : R e g is t r y Tw e a k s
423
The Registry: Zillio ns o f Undo c umented Features 423 Co mparing Registry snapsho ts 424 Spying: Watc hing the Registry wo rk 426 Writing a sc ript to ac c ess undo c umented features428 Fo rc ing Windo ws to rec o gnize yo ur new settings 430 Max Cac hed Ic o ns key 431 Searc hing fo r interesting Registry keys 431 Co ntro lling pro gram settings 434 Managing System Ic o ns o n the Deskto p 434 Changing the name o f the Rec yc le Bin 435 Mo re sec rets abo ut deskto p items 436 Hiding the Rec yc le Bin 438
407
418
Co nte nts ■
xxxi ■
Refreshing the deskto p auto matic ally 439 Finding and resto ring system ic o ns 440 Adding c o mmands to system c o ntext menus Inserting ic o ns into yo ur Explo rer 446 Co ntro lling Windo ws Settings Thro ugh API 447 Retrieving Windo ws settings 448 Gaining full ac c ess to all Windo ws settings Changing Windo ws settings 452 Changing ic o n spac ing 453 Managing Ac tive Windo w Trac king 454 Changing windo w bo rders 456 Co ntro lling the system beep 457 Using Ic o n Title Wrap 458 Co ntro lling Sc reen Savers 458 Launc hing sc reen savers 458 Tempo rarily disabling sc reen savers 459 Setting sc reen saver timeo ut 460 Finding o ut if a sc reen saver runs 461 Changing sc reen saver settings461 Installing new sc reen savers 463 Co ntro lling lo w-po wer sc reen saver features Animatio ns and Visual Effec ts 465 Turning o ff visual effec ts alto gether 465 Overview: Visual effec ts built into Windo ws Co mbo bo x animatio n 466 Curso r shado w 467 Gradient c aptio ns 467 List bo x animatio n 468 Menu animatio n 468 Menu underlines 469 Menu sho w delay 470 Selec tio n fade 471 To o ltip animatio n 471 Full windo w drag 474 Fo nt smo o thing 474 Setting blinking text c urso r width 475 Spec ifying a new deskto p wallpaper 475 Enabling “Snap-To -Butto n” 478 Mo re Undo c umented Registry Tweaks 478 Getting rid o f sho rtc ut arro ws 478 Changing the sho rtc ut arro w 480 New ic o ns fo r all system ic o ns 481 Sizing the Co o l Switc h windo w 481
Ch a p t e r 1 6 : Ge t t in g S ys t e m In fo r m a t io n Finding Out Impo rtant Path Info rmatio n Retrieving spec ial fo lder path names Cleaning up yo ur Do c uments menu Finding the Windo ws fo lder 488 Reading Netwo rk Info rmatio n 489
483 484 485
443
450
463
465
483
xxxii
Co nte nts
■
■
Inside view: WSc ript.Netwo rk 489 Listing c urrent username 490 Managing Memo ry Co nsumptio n 491 Retrieving memo ry statistic s 491 Running in physic al memo ry o nly 492 Chec king memo ry installed and memo ry c o nsumed Getting Misc ellaneo us Windo ws Settings 493 Querying system metric s 494 Identifying slo w c o mputers 496 Detec ting mo use/ wheel info rmatio n 497 Is a netwo rk present? 497 Co ntro lling bo o t mo de 498 Managing Sc reen Reso lutio n and Refresh Rate 498 Finding o ut all available sc reen reso lutio ns 498 Determining the c urrent video settings 499 Finding o ut the best frequenc y setting 500 Changing display frequenc y 500 Changing sc reen reso lutio n 500 Enumerating System Fo nts 501 Creating a fo nt sample page 501 Analyzing yo ur pro c esso r 503 Determining yo ur pro c esso r type 503 Determining ho w many pro c esso rs are o nbo ard 504 Dealing with Windo ws Versio ns 504 Getting an o verview: Windo ws versio n details 505 Determining Windo ws versio n 505 Extrac ting individual versio n info rmatio n 506 Determining system suppo rt fo r spec ific func tio ns
Ch a p t e r 1 7 : Wo r k in g w it h Eve n t s
492
506
509
What’s So Thrilling Abo ut Events? 509 Rec eiving events 510 Implementing an event sink 511 Using events 511 Defining Yo ur Own Events 513 Creating a timer c o ntro l 513 Creating a debugging timer 514 Sho wing ic o ns in the tray area 516 Tray ic o ns under the ho o d 517 Changing fo rm ic o ns dynamic ally 520 Respo nding to tray ic o n events 521 Creating Mo deless Windo ws 522 Output status info rmatio n to a mo dal windo w Using pro gress bars to spic e up dialo g bo xes
522 526
Ch a p t e r 1 8 : De ve lo p in g Un ix -lik e Co m m a n d s Develo ping Yo ur Own Co mmand-Line Mac ro s Creating a new c o mmand 529 Calling sc ripts like DOS c o mmands 531 Detec ting whether a sc ript runs in a DOS bo x
529
531
529
Co nte nts ■
xxxiii ■
Using piping: Feeding results to yo ur c o mmands Develo ping pipe c o mmands 534 Writing filters thro ugh piping 535
534
P a r t V: Ac c e s s in g Hid d e n Co m p o n e n t s
537
Ch a p t e r 1 9 : Us in g t h e We b B ro w s e r Co n t ro l
539
The WebBro wser Co ntro l: Mastering Real-Wo rld Tasks 539 Creating c usto m dialo g bo xes 540 Getting ac c ess to template elements 542 Revealing implementatio n details 545 Advanc ed WebBro wser Tric ks 545 Calling sc ript pro c edures thro ugh yo ur HTML template 546 Co mmunic atio n between the HTML template and the COM o bjec t Auto matic ally c lo sing the fo rm o n RETURN 550 Ho o king COM pro c edures to individual elements 551 Chec king fo r valid fo rm entries 553 Respo nding to WebBro wser c o ntro l events 555 Reading Gro ups o f Radio Butto ns 555 Creating a gro up o f radio butto ns 555
Ch a p t e r 2 0 : In t e r n e t a n d Co m m u n ic a t io n s 5 5 9 Ac c essing the Internet 559 Creating a universal Internet sc ript extensio n 560 Co nnec ting to the Internet 560 Clo sing the c o nnec tio n o nc e the Web page is lo aded Using FTP to do wnlo ad and uplo ad files 562 General rules fo r ac c essing FTP 562 Ac c essing an FTP server 562 Retrieving an FTP direc to ry listing 562 Do wnlo ading FTP files 567 Uplo ading FTP files 568 Sync hro nizing lo c al fo lders and Web fo lders 569 Misc ellaneo us Internet Metho ds 575 Determining Internet c o nnec tio n type 575 Determining ho st names 575 Determining IP address 576 Sc ript Extensio n Internet Metho ds 577
561
Ch a p t e r 2 1 : F a x , P r in t e r, S c a n n e r, a n d Gr a p h ic s 5 8 1 Say “Hi” to Ko dak Imaging 581 A c lo ser lo o k 582 Getting ac c ess to the c o ntro l 583 Finding o ut if TWAIN suppo rt is available Sc anning Pic tures 585 Saving sc anned pic tures to disk 585 Auto mated sc anning 586 Sc anning large numbers o f pic tures 588
584
547
xxxiv
Co nte nts
■
■
Sc anning pic tures with the preview func tio n Printing Sc anned Images 590 Yo ur perso nal pho to c o py mac hine 590 A pho to c o py mac hine with editing func tio ns Managing Pic tures 593 Lo ading and printing pic tures 593 Printing pic tures witho ut a dialo g bo x 594 Co nverting Graphic s Files 594 Ro tating pic tures 594 Sc aling pic tures 595 Creating butto ns and ic o ns 596 Generating thumbnails and preview pages Co nverting pic ture quality and c o lo r fo rmats Saving sc anned pic tures with c o mpressio n Cho o sing the right c o mpressio n o ptio ns 602 Repairing pic tures with damaged file type info 604
Ch a p t e r 2 2 : F u n , Tr ic k s , a n d M u lt im e d ia
589
592
597 599 601
607
Extrac ting Ic o ns fro m Files 607 Creating a list o f available ic o ns 608 Selec ting a file fro m yo ur ic o n list 611 Changing Fo lder Ic o ns 614 Hiding fo lders 619 Changing system ic o ns 619 Extrac ting ic o ns to files 622 Searc hing fo r c usto mized DESKTOP.INI fo lders 623 Ac c essing Multimedia Devic es 626 Opening and c lo sing CD trays 628 Finding o ut if an audio CD is inserted 631 Querying audio CD parameters632 Remo te Co ntro lling Audio Playbac k 634 Co ntro lling po sitio n 634 Changing time fo rmat fro m trac ks to millisec o nds 635 Dealing with Wave Audio , MIDI Files, and Misc ellaneo us Multimedia Types Playing bac k MIDI files 638 Playing bac k WAV audio files 640 Sho wing AVI mo vie files 640 Auto matic ally rec o rding CD trac ks to WAV audio 642
Ch a p t e r 2 3 : Us in g Da t a b a s e s
645
Ac c essing Databases 645 Chec king ADO versio n 646 Do I need to upgrade o r install anything? Getting Ac c ess to a Database 648 Opening and querying a database 648 Reading database c o ntents 650 Finding o ut design info rmatio n 651 Adding new data to yo ur database table 653 Co unting the number o f rec o rds 655
647
636
Co nte nts ■
xxxv ■
Deleting rec o rds 655 Creating new database tables 656 Deleting tables 657 Co ntro lling the Index Server 658 Ac tivating lo c al file system indexing 658 Adding and remo ving fo lders fro m the index Adding a new c atalo g 660 Querying the Index Server 661 Explo ring info rmatio n c atego ries 662 Limiting searc hes to spec ific fo lders 664 Creating yo ur o wn searc h dialo g bo x 665 Fine-tuning Index Server 666
660
Ch a p t e r 2 4 : M a n a g in g Win d o w s NT/2 0 0 0 S e r ve r 6 6 9 Managing Windo ws NT/ 2000 Sec urity 669 Creating sc ripting extensio ns to manage user ac c o unts Getting ready fo r ADSI 670 Managing User Ac c o unts (the API Way) 671 Enumerating users 671 Adding users 672 Deleting user ac c o unts 673 Changing passwo rds 673 Listing glo bal gro ups 674 Managing gro up membership 675 Finding the primary do main c o ntro ller 675 Explo ring the ADSI Wo rld 675 Is it a c o ntainer? 677 Enumerating gro up memberships 678 Testing whether a user belo ngs to the gro up 679 Creating a new user ac c o unt 679 Finding o ut all gro ups a user belo ngs to 680 Adding a user to the gro up 680 Remo ving a user fro m a gro up 681 Finding o ut sec ret gro up pro perties 681 Setting user passwo rds 684 Changing user ac c o unt info rmatio n 684 Fo rc ing passwo rd c hanges 686 Pro hibiting passwo rd c hanges 686 Disabling ac c o unts 687 Managing Windo ws Servic es 688 Co ntro lling servic es thro ugh the API 688 Managing servic es thro ugh ADSI 688 Managing individual servic es 689 Co ntro lling Netwo rk Shares 690 Adding netwo rk shares 691 Ac c essing shared fo lder pro perties 691 Auto matic ally Restarting and Shutting Do wn 692 Shutting do wn a lo c al mac hine 692 Remo tely shutting do wn a mac hine 693 Auto matic lo go n 694
670
xxxvi
Co nte nts ®
■
■
Ap p e n d ix A 6 9 7 Ap p e n d ix B 7 0 1 In d e x 7 0 7 En d -Us e r Lic e n s e Ag re e m e n t 7 2 8 CD-R o m In s t a lla t io n In s t r u c t io n s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3 2
Chapte r 1
Script Development with Ease In This Chapter 䊳 Write and edit sc ript files 䊳 Create blank sc ript files with a mo use c lic k 䊳 Selec t sc ript lines auto matic ally 䊳 Get help when sc ripts misbehave 䊳 Exec ute sc ripts line by line 䊳 Lo g yo ur sc ripts’ ac tivity 䊳 Catc h erro rs and handle them yo urself
S
c ripts are plain text files (see Figure 1-1), so yo u c an use any text edito r to develo p them. Ho wever, mo st text edito rs are no t designed to meet develo pers’ needs. Fo r example, they o ften lac k the ability to mark spec ific lines yo u’d like to take a c lo ser lo o k at. This is unfo rtunate bec ause when the Sc ripting Ho st enc o unters a pro blem, it tells yo u the line number that c aused the hic c up — and it’s nic e to have a c o nvenient way o f jumping to that partic ular line. In this chapter, you’ll learn how easy it is to use hidden script techniques to enhance any text editor that has line-marking capabilities. You will also discover convenient ways of starting new script files with a mere right-click of the mouse button. In addition, you’ll discover how scripts are executed line by line and learn about the Script Debugger, which allows you to step through your script code while it is executed. This “slow motion” execution helps you understand the script mechanics and is also perfect for finding (and resolving) script errors easily.
Writing Your First Script Writing sc ripts is as easy as launc hing yo ur favo rite text edito r. Even the simple Windo ws edito r will suffic e — Just selec t Run fro m yo ur Start menu and enter NOTEPAD. If yo u like, yo u c an even use yo ur favo rite wo rd-pro c essing so ftware fo r writing sc ripts, by using line-numbering o r o ther advanc ed features. Remember tho ugh, wo rd pro c esso rs do n’t save plain text files as a default — they use their o wn pro prietary binary fo rmat. The Sc ripting Ho st c an’t
4
Part I: Sc ripting Kic ks tart
■
■
dec ipher this fo rmat, so yo u’ll need to be sure to save yo ur sc ripts as file type plain text. In mo st c ases, a plain text edito r is the better c ho ic e. No w yo u’ll see yo ur blank text edito r windo w. This is yo ur playgro und, the plac e where yo u c an start develo ping yo ur sc ripts. The traditio nal first step in pro gramming bo o ks is to greet the wo rld. Let’s do it!
Figure 1-1: Scripts are jus t plain text files . At this po int, yo ur sc ript is a plain text file. In o rder to have Windo ws interpret it as a VBSc ript file and feed its c o ntents to the Sc ripting Ho st, yo u’ll need to save it with the file extensio n .vbs (see Figure 1-2). Cho o se Save As fro m the File Menu, c hange the Save in the listbo x to Deskto p, and enter the filename welcome.vbs.
Figure 1-2: Save s cripts w ith a .vbs file extens ion. Yo ur sc ript will be plac ed right o n yo ur deskto p (see Figure 1-3). If yo u have c o rrec tly set up the Sc ripting Ho st as o utlined previo usly, it will have the typic al sc ript ic o n.
Chapte r 1 : Sc ript De ve lo pme nt with Eas e ■
5 ■
Figure 1-3: A .vbs s cript To see yo ur sc ript, just o pen up the file. It will po p up a small dialo g bo x and say hello to the wo rld (see Figure 1-4).
Figure 1-4: It w orks ! Your s cript s ays hello to the w orld.
Editing the contents of a script During sc ript develo pment, yo u will pro bably edit a sc ript many times, in o rder to fix erro rs and ado pt new features (see Figure 1-5). To keep things simple, it’s a go o d idea to break larger pro jec ts into small piec es and run the sc ript after eac h step is c o mpleted. This way, it is muc h easier to identify and c o rrec t sc ript erro rs.
Figure 1-5: Choos e Edit to change a s cript anytime you feel like it To c hange a sc ript, right-c lic k its ic o n and c ho o se Edit. Make whatever c hanges yo u like, and then save it again. Editing a sc ript is like editing a letter, exc ept that yo u c an’t o pen the sc ript file to c hange it, bec ause o pening the file always runs the sc ript. Use the Edit c o mmand instead, o r drag the sc ript file o nto the pro gram ic o n yo u want to use fo r displaying the file c o ntents.
6
Part I: Sc ripting Kic ks tart
■
■
Conveniently starting new scripts Yo u do n’t have to go thro ugh all this c lic king and renaming o f file extensio ns just to start a new sc ripting pro jec t. Instead, use the sc ripting c apabilities to plac e a new c o mmand into the New menu. This way, it’s easy to get new sc ript files, o f the right file type, anytime yo u want. To insert a new do c ument type into yo ur New menu, just exec ute the fo llo wing sc ript: ‘ 1-1.VBS ‘ this is the file extension the new command ‘ should generate: filetype = “.vbs” ‘ connect to WScript.Shell for registry access: set WSHShell = CreateObject(“WScript.Shell”) ‘ read in the name of the vbs-section: prg = ReadReg(“HKCR\” & filetype & “\”) ‘ read in the official name for vbs-files: prgname = ReadReg(“HKCR\” & prg & “\”) ‘ ask for a new name ask = “What should be the name for new VBScript scripts?” title = “New menu entry” prgname = InputBox(ask, title, prgname) ‘ save the new program description: WSHShell.RegWrite “HKCR\” & prg & “\”, prgname ‘ add a New menu entry asking for an empty new file: WSHShell.RegWrite “HKCR\” & filetype & “\ShellNew\NullFile”, “” ‘ reads a registry key ‘ should the key be invalid, complain and stop: function ReadReg(key) on error resume next ReadReg = WSHShell.RegRead(key) if err.Number>0 then ‘ key could not be read: complain! error = “Error: Registry-Key “”” & key _ & “”” could not be found!” MsgBox error, vbCritical WScript.Quit end if end function
This sc ript is a great example o f ho w po werful the Sc ripting Ho st c an be. With it, yo u c an c hange the o ffic ial name o f .vbs files and write info rmatio n into the windo ws registry to make the .vbs files available in the New menu. Just enter a name under whic h VBSc ript files will appear in yo ur New menu (see Figure 1-6).
Chapte r 1 : Sc ript De ve lo pme nt with Eas e ■
7 ■
It may take a few sec o nds befo re the new c o mmand bec o mes visible. To fo rc e Explo rer to rec o gnize the c hange, c lic k an empty spo t o n the deskto p and press [F5].
Figure 1-6: Choos e a name for your .vbs s cript files To start a new sc ript (see Figure 1-7), right-c lic k the mo use, c ho o se New, and then c lic k the name yo u spec ified fo r .vbs files. That’s all there is to it. Windo ws will generate a new and empty .vbs file fo r yo u.
Figure 1-7: Start new s cript files w ith the help of New. All that is left to do is to rename the file and then right-c lic k the file: Edit will o pen the empty file in yo ur text edito r, and yo u’ll be ready to bring yo ur sc ript to life. Fo r mo re info rmatio n abo ut ho w the sc ript ac c o mplishes all o f this, see Chapter 13. Fo r no w, it’s just a c o nvenient to o l. Getting rid o f a new entry is even easier: ‘ 1-2.VBS set WSHShell = CreateObject(“WScript.Shell”) filetype = “.vbs”
Automatically renaming and opening new scripts Sc ripts c an help yo u to auto mate ro utine tasks — it’s their jo b. Let’s start with a c o nvenient way to c reate new sc ripts fro m sc ratc h! Plac ing file templates into the New menu is c o mmo n prac tic e fo r many file types, and yo u have just seen ho w to do this with .vbs files. The New menu c an do muc h mo re, tho ugh. Yo u c an also plac e c o mmands into this menu, launc hing sc ripts that take o ver muc h o f the wo rk invo lved in getting new files. The next sc ript plac es a new c o mmand into the New menu. This c o mmand itself launc hes ano ther sc ript, and then the subsequent sc ript takes o ver the respo nsibility o f generating a new sc ript file. ‘ 1-3.VBS ‘ Name of your new command: commandname = “Get New VBScript file” ‘ connect to Wscript.Shell for registry access: set WSHShell = CreateObject(“WScript.Shell”) ‘ get path to windows folder: windir = WSHShell.ExpandEnvironmentStrings(“%WINDIR%”) ‘ name of the script to be executed by the new ‘ command: script = “\newvbsfile.vbs” command = “WSCRIPT.EXE “ + windir + script + “ “”%2””” ‘ the dummy file extension name this commands registers with: prgextension = “vbscustom” extension1 = “HKCR\.vbsneu\” extension2 = “HKCR\” & prgextension & “\” ‘ save the command to be executed: WSHShell.RegWrite extension1, prgextension WSHShell.RegWrite extension1 + “ShellNew\command”, command ‘ Name of the editor you want to open scripts with: WSHShell.RegWrite extension2 + “Shell\open\command\”, “NOTEPAD.EXE” WSHShell.RegWrite extension2, commandname WSHShell.RegWrite extension2 + “DefaultIcon\”, “SHELL32.DLL,44” MsgBox “Command installed.”,_ vbInformation + vbSystemModal
Onc e yo u run this sc ript (see Figure 1-8), yo u’ll disc o ver a new entry in the New menu c alled Get New VBScript File.
Chapte r 1 : Sc ript De ve lo pme nt with Eas e ■
9 ■
In o rder to have Explo rer update its menus, yo u may need to c lic k an empty spac e o n yo ur deskto p and press [F5].
Figure 1-8: Your new command launches a s cript, but it ’s mis s ing. Cho o sing this entry will raise an erro r — and that’s go o d! No w yo u kno w yo ur sc ript is wo rking well, bec ause instead o f plac ing an empty file so mewhere, yo ur c o mmand tries to exec ute ano ther sc ript, c alled newvbsfile.vbs. Yo ur c o mmand lo o ks fo r this sc ript inside yo ur Windo ws fo lder, but bec ause yo u haven’t plac ed it there yet, the c o mmand fails. It wo n’t fail fo r lo ng. Just plac e the fo llo wing sc ript into yo ur Windo ws fo lder and c all it newvbsfile.vbs: ‘ NEWVBSFILE.VBS ‘ look for the arguments the New menu ‘ supplied to this script: set args = WScript.Arguments ‘ no arguments? Then someone called this script directly: if args.Count=0 then MsgBox “This script cannot be run directly” WScript.Quit else ‘ access Scripting.FileSystemObject to get a hold ‘ of all the file system commands necessary to ‘ generate a new and empty script file: set fs = CreateObject(“Scripting.FileSystemObject”) ‘ where does the user wants the script file to be ‘ placed? Read the arguments: path = args(0) ‘ strip off the preliminary file name ‘ we just want the path name: path = left(path, InstrRev(path, “\”)) ‘ ask for the name: do ask = “I am going to place a new vbs file here: “”” & _ path & “””.” + vbCr + vbCr ask = ask + “What’s the name of the new script file?” name = InputBox(ask) if name = “” then ‘ oh, no file name specified! ‘ Quit!
10
Part I: Sc ripting Kic ks tart
■
■
status = 3 else ‘ a name was specified: ‘ generate new fully qualified path name ‘ for script file: filename = path + name + “.vbs” ‘ does this file exist already? if fs.FileExists(filename) then ‘ yes, overwrite it? ask = “Script “”” + name _ + “”” already exists! Replace?” answer = MsgBox(ask, vbQuestion + vbYesNo) if answer = vbYes then ‘ delete old file status = 2 else ‘ ask for another name: status = 0 end if else ‘ generate new file: status=1 end if end if ‘ ask until a valid file name was entered loop while status=0 if status = 3 then ‘ no file name was entered: MsgBox “Exit!”, vbInformation else ‘ Create new text file and overwrite any ‘ existing file: set handle = fs.CreateTextFile(filename, true) handle.close ‘ open new script file automatically ‘ for editing: ‘ connect to WScript.Shell for Run-command: set WSHShell = CreateObject(“WScript.Shell”) WSHShell.Run “NOTEPAD.EXE “ + filename end if end if
It’s easy to save this file to the Windo ws fo lder: Open the file in yo ur edito r, c ho o se Save As fro m yo ur File menu, and use %WINDIR% [Enter] as yo ur filename. The Save As dialo g bo x will immediately switc h to yo ur Windo ws fo lder, and yo u c an save yo ur file using newvbsfile.vbs as the filename. Enviro nment variables like %WINDIR% are rec o gnized o nly with the new set o f dialo g bo xes intro duc ed with Windo ws 98. On Windo ws 95 systems, this sho rtc ut do esn’t wo rk.
Chapte r 1 : Sc ript De ve lo pme nt with Eas e ■
11 ■
No w try yo ur new c o mmand again! This time, it will find the target sc ript and exec ute it. Yo ur new sc ript, newvbsfile.vbs, will po litely ask fo r a filename, and will then auto matic ally o pen a new file fo r editing (see Figure 1-9).
Figure 1-9: Enter the name of your new s cript file.
Getting Help When Scripts Misbehave The mo re yo u experiment with sc ripts, the mo re yo u will enc o unter erro rs. This is abso lutely no rmal. Erro rs are a great way o f learning, and even the mo st experienc ed sc ript develo per will have to c o pe with erro rs every no w and then. Finding (and c o rrec ting) erro rs c an be frustrating if yo u do n’t have the right to o ls and strategies to assist yo u. This c hapter pro vides yo u with all the debugging info rmatio n yo u need to kno w. Co me bac k to this c hapter whenever yo ur sc ripts do n’t do what yo u expec t them to !
Finding the right parts of your scripts Whenever the Sc ripting Ho st enc o unters a pro blem, it po ps up an erro r message (see Figure 1-10). It may lo o k a little ugly, but it pro vides all the info rmatio n yo u need, inc luding a sho rt desc riptio n o f the mo st pro bable c ause and a line number. This line number indic ates the sc ript line where the erro r was disc o vered.
Figure 1-10: This mes s age tells you on w hich line number an error occurred. The next step is to take a lo o k at the line. Open up the sc ript in yo ur edito r, right-c lic k the sc ript ic o n, and c ho o se Edit.
12
Part I: Sc ripting Kic ks tart
■
■
If yo ur sc ript is relatively sho rt, it’s easy to identify the line number. There’s o nly o ne c aveat — turn o ff wo rd wrapping! Wo rd wrapping breaks lo ng lines into mo re than o ne line so yo u c an view the entire line witho ut the need fo r ho rizo ntal sc ro lling. Wo rd wrapping, ho wever, interferes with an edito r’s ability to c o unt line numbers. Using the No tepad edito r, o pen the Edit menu and turn o ff Wo rd Wrap befo re yo u start c o unting line numbers! Onc e yo ur sc ript gro ws, c o unting line numbers bec o mes tedio us. It’s just no t prac tic al to c o unt a hundred o r so lines. Unfo rtunately, as I’ve mentio ned previo usly, mo st edito rs do n’t feature Go To c o mmands that let yo u jump to spec ific lines. Again, this is a great example o f ho w sc ripts c an help o ut. Yo u c an develo p a sc ript that c o ntro ls yo ur favo rite edito r and have it jump right to the line yo u spec ify. Use the fo llo wing sc ript: ‘ 1-4.VBS ‘ mark a line ‘ Connect to WScript.Shell-Object which provides ‘ the SendKeys-Command set wshshell = CreateObject(“WScript.Shell”) ‘ Ask which line number to highlight: line = inputBox(“Which line do you want to mark?”) ‘ Check whether entry is a number: if not isNumeric(line) then MsgBox “You did not specify a number!” WScript.Quit else ‘ convert number to Integer: line = Fix(line) ‘ is line number valid? if line “ end if loop sub ExecuteIt(command) ‘ Execute is a separate procedure because it turns off ‘ build-in error handling ‘ This is necessary to keep the script running even if ‘ invalid commands are entered: on error resume next ‘ execute statement: ExecuteGlobal command ‘ did an error occur? if not err.Number=0 then ‘ yes, report cause: output.WriteLine “Error: “ & err.description err.clear end if end sub
Yo u’ll pro bably launc h this sc ript frequently to try o ut the examples pro vided o n the fo llo wing pages, so try this handy sho rtc ut:
1. Right-c lic k yo ur sc ript ic o n and c ho o se Create Sho rtc ut. A new sho rtc ut appears.
2. Right-c lic k the new sho rtc ut and c ho o se Pro perties. Next, c lic k the target field and mo ve to the first c harac ter. The target field c o ntains the full path name o f yo ur sc ript.
3. To make yo ur link use CSCRIPT.EXE as a ho st, enter CSCRIPT.EXE and a spac e, and leave the sc ript path name as an argument. Then c lic k OK. Clic k Change Ic o n if yo u want to assign an eye-c atc hing ic o n to yo ur link. Leave the Filename field empty and press [Enter] to get the default Windo ws ic o n selec tio n.
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
45 ■
In the future, whenever yo u want to try o ut a little VBSc ript magic , just launc h yo ur link. Yo u c an also pro vide it with a handy key sho rtc ut as o utlined in Chapter 1. The sc ripting ho st starts inside a DOS windo w. No w, yo u c an enter any valid VBSc ript statement, as sho wn in Figure 2-7. Use ? to print o ut messages. Fo r example, yo u c o uld assign a value to a variable: > a=”Test” [Enter] >
Next, yo u c o uld print o ut this variable: > ? a [Enter] test >
Wo ndering what kind o f variable type VBSc ript used to sto re yo ur text? Find o ut: > ? TypeName(a) [Enter] String >
Yo u c an even tie c o mmands to gether using the c o lo n. To find o ut all o f the c harac ter c o des between 32 and 255, use this line: > for x=32 to 255:list = list & x & “=” & chr(x) & “ “:next [Enter]
No w it’s easy to o utput the key c o des: > MsgBox list [Enter] > ? list [Enter]
Figure 2-7: Experiment us ing your homemade VBScript command line interpreter.
46
Part I: Sc ripting Kic ks tart
■
■
The sc ript will even interc ept erro r messages, so c ausing an erro r will just display the erro r message: > MsgBo “Hello!” Error: Type mismatch >
Onc e finished, just type in exit [Enter]. This time, the DOS windo w disappears auto matic ally. If yo u launc h a sc ript in a DOS windo w and the sc ript ends, the DOS windo w will still be there. It was there in the first plac e, so why sho uld it disappear? In c o ntrast, if yo u launc h CSCRIPT.EXE direc tly, yo u o mit the DOS c o mmand line interpreter. This time, when yo ur sc ript ends, CSCRIPT ends, and bec ause CSCRIPT o pened the DOS windo w, it will c lo se the windo w auto matic ally.
The Truth About VBScript Variables Variables are plac eho lders fo r yo ur data. While mo st pro gramming languages require yo u to define spec ific variable types, VBSc ript is very liberal. It uses o nly o ne variable type c alled Variant. This type c an sto re any kind o f data — numbers, text, o bjec ts, yo u name it. There’s no need to define the variable befo rehand. Just use it, and VBSc ript takes c are o f the rest. This liberal c o nc ept is very easy to use. Still, there’s no single perfec t so lutio n, and bec ause VBSc ript do esn’t c o mplain muc h, it do esn’t help muc h either when trying to find a sc ript erro r o r typo . Fo r example, if yo u ac c identally misspell a variable name, VBSc ript just initializes a new variable. It do esn’t c o mplain, and yo u might never get a c lue why yo ur sc ript is misbehaving. In the same way, if yo u assign values to the wro ng variable, VBSc ript wo n’t suspec t an erro r. It just assigns the value. If there were the need to dec lare variable types, yo u’d get an erro r message if the assigned variable type wo uldn’t matc h the dec lared variable type. Yo u c an fo rc e VBSc ript to ac c ept o nly dec lared variables by plac ing the c o mmand o ptio n explic itly o n to p o f yo ur sc ript c o de. No w, variables need to be dec lared using Dim befo re they c an be used. Yo u will find mo re info rmatio n abo ut this at the end o f this c hapter. Therefo re, VBSc ript variables are perfec t fo r small and simple sc ripts. Sc ripts that go beyo nd a c o uple o f lines o f c o de, ho wever, need c areful planning. The fo llo wing part will sho w yo u ho w to play it safe.
Finding out the variable subtype Altho ugh Variant variables c an sto re any kind o f data, VBSc ript c o ntains two impo rtant func tio ns that help identify what type o f data is ac tually sto red inside o f a variable. These are TypeName and VarType.
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
47 ■
The best way to get ac c usto med to Variant variables is by playing with them. Playing aro und is easy eno ugh; just launc h yo ur VBSc ript c o mmand line interpreter as desc ribed, then assign a value to a variable. Fo r help, see Table 2-1. > a=”Hello!” [Enter] > ? TypeName(a) String > ? VarType(a) 8 >
TypeName returns a text desc riptio n o f the variable type.
TypeName will reveal the internal name o f the o bjec t. In Chapter 3, TypeName helps yo u to understand the struc ture o f unkno wn o bjec ts. VarType, in c o ntrast, returns a c o de that c o rrespo nds to o ne o f the Variant subtypes.
Table 2-1
Variable Types and Constant Names
Value
Constant
Description
0
vbEmpty
Uninitialized variable
1
vbNull
No valid data
2
vbInteger
Integer (0-32767)
3
vbLong
Long integer
4
vbSingle
Single -precis ion floating point number
5
vbDouble
Double -precis ion floating point number
6
vbCurrency
Currency
7
vbDate
Date
8
vbString
String
9
vbObject
Automation object
10
vbError
Error
11
vbBoolean
Boolean
12
vbVariant
Array of variants
13
vbDataObject
Data-acces s object
17
vbByte
Byte
8192
vbArray
Array
48
Part I: Sc ripting Kic ks tart
■
■
Try it o ut! Assign a who le number belo w 32,768 to a variable and c hec k its type: > a=567 [Enter] > ? TypeName(a) [Enter] Integer >
Repeat this example, using a larger number this time: > a=668543 [Enter] > ? TypeName(a) [Enter] Long >
Witho ut any dec laratio n, VBSc ript always auto matic ally c ho o ses the mo st effic ient sto rage type. Yo u do n’t need to be aware o f the differenc e between Integer and Lo ng. This is the c o nc ept o f Variants.
Converting variables So metimes, it is nec essary to c hange the type o f a variable. Fo r example, if yo ur sc ript finds o ut ho w many files are sto red in so me fo lder, yo u might want to o utput this info rmatio n to the user. Therefo re, yo u need to transfo rm the numeric value into a text value that yo u c an display. Again, VBSc ript do es mo st o f the jo b auto matic ally. The fo llo wing example repo rts the number o f files in the ro o t fo lder o f drive C:\: ‘ 2-9.VBS set fs = CreateObject(“Scripting.FileSystemObject”) files = fs.GetFolder(“C:\”).files.count MsgBox MsgBox ‘ this MsgBox
“Variable type: “ + TypeName(files) files line will cause an error: “C:\ contains “ + files + “ files.”
Launc hing this sc ript reveals many interesting details: ■ First, the sc ript finds o ut the number o f files in the ro o t fo lder o f C:\. It
uses GetFolder to get ac c ess to the fo lder, asks fo r a files c o llec tio n, and c alls Count. By the way, all o f the file system func tio ns are c o vered in detail in Chapter 7. ■ The result is a variable o f subtype Long. Yo u may be thinking, sho uldn’t
this be Integer? No . To be able to handle a virtually unlimited number o f files, Count always uses Long variables. VBSc ript will c ho o se the mo st effic ient variable subtype o nly when it assigns variables. In this c ase, Count assigned the variable, so Count c o ntro ls the variable subtype. ■ MsgBox then o utputs the number o f files. Altho ugh files are o f subtype
Long, this wo rks perfec tly well bec ause MsgBox auto matic ally c o nverts the number to a text.
49
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
■
■ The third MsgBox c o mmand fails ho wever. WSH repo rts a type mismatc h
erro r (see Figure 2-8), and this is the first time yo u run into variable type c o nflic ts. Yo ur sc ript tried to c o mbine text with a number. This do esn’t wo rk. Yo u first have to manually c o nvert the number to text.
Figure 2-8: Sometimes it ’s neces s ary to change variable type manually. To repair the line, yo u have two o ptio ns: One, yo u manually c o nvert the number to text using the appro priate c o nversio n func tio n: MsgBox “C:\ containts “ + CStr(files) + “ files.”
CStr transfo rms the variable to text: MsgBox TypeName(CStr(files))
Or two , yo u use ano ther nic e VBSc ript tric k: &. Many autho rs use + and & syno nymo usly. Do n’t do that! + and & are very different. Use + if yo u want to add to gether variables o f the same o r c o mpatible type. Yo u c an add texts, o r yo u c an add numbers, but yo u c an’t mix variable types. In c o ntrast, & adds text and o ther variable types by auto matic ally c o nverting them to text. The result is always a string variable. The & o perato r c o nc atenates variables and pro duc es a text string. It auto matic ally c o nverts variables to subtype String as needed: MsgBox “C:\ contains “ & files & “ files.”
Using variable conversion functions Almo st all o f the c o nversio n func tio ns start with a “C.” These are yo ur helper func tio ns to explic itly switc h to ano ther variable type:
Table 2-2
VBScript Conversion Functions
Conversion function
Resulting variable type
CBool
Boolean
CByte
Byte
CCur
Currency Co ntinue d
50
Part I: Sc ripting Kic ks tart
■
■
Table 2-2
( co ntinue d)
Conversion function
Resulting variable type
CDate
Date
CDbl
Double
CInt
Integer
Int
Integer
Fix
Integer
CLng
Long
CSng
Single
CStr
String
There are three different func tio ns to c o nvert a variable to Integer: CInt, Int and Fix. Altho ugh in mo st do c umentatio ns, CInt is used, this is dangero us. All three func tio ns behave differently when c o nverting negative numbers. Only Fix limits itself to stripping the dec imal plac es o f a number. CInt and Int bo th auto matic ally ro und negative numbers to the next lo wer o r next higher integer. This c an c ause a lo t o f c o nfusio n and erro rs. Therefo re, always use Fix to c o nvert numbers to Integer. In additio n, yo u c an use func tio ns to fo rmat a variable:
Table 2-3
M anipulate Variable Content
Function
Description
Abs
Returns abs olute number; alw ays pos itive
Asc
Returns character code of a text character
Chr
Returns character repres ented by a character code
Hex
Returns hexadecimal format of a number
Oct
Returns octal format of a number
Round
Returns a number that is rounded to a s pecified number of decimal places
Sgn
Returns a number indicating the s ign of a number
FormatNumber
Formats a number dis playing a s pecified number of decimal places
FormatPercent
Formats a number as percentage
FormatCurrency
Formats a number according to the currency s ettings of the control panel
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
51 ■
Using variable arrays Variable arrays are just gro ups o f variables that c an be ac c essed using an index number. This is espec ially useful if yo ur sc ript needs to lo o k up info rmatio n sto red in variables. Variable arrays always need to be dec lared so that VBSc ript kno ws ho w muc h sto rage spac e it sho uld reserve. Yo u c an dec lare variable arrays using Dim o r ReDim. VBSc ript variable arrays always start with index number 0. In c o ntrast to Visual Basic and o ther pro gramming languages, there is no way to c hange the “base” o f an array. The func tio n Lbound, whic h repo rts the first index number o f an array, is therefo re useless bec ause it always repo rts 0.
Dim initializes a variable array o f fixed size. Yo u need to spec ify the number o f elements the array sho uld ho ld, and yo u c anno t expand o r shrink the array afterwards. Using Dim, yo u need to spec ify the number o f entries as a c o nstant o r abso lute number. Yo u are no t allo wed to use a variable to feed the size o f the array to Dim. ReDim will also ac c ept variables. ‘ 2-10.VBS dim myarray(5) myarray(0)=”Unknown” myarray(1)=”Removable” myarray(2)=”Fixed” myarray(3)=”Remote” myarray(4)=”CD-ROM” myarray(5)=”RAM-Drive”
‘ find out the type of drives set fs = CreateObject(“Scripting.FileSystemObject”) ‘ get all drives: set drives = fs.Drives for each drive in drives letter = drive.DriveLetter kind = myarray(drive.DriveType) list = list & “Drive “ & letter & “ is of type “ & kind & vbCr next MsgBox list
This sc ript displays a list o f all drives available o n yo ur c o mputer (see Figure 2-9). It uses the Drives c o llec tio n and queries the DriveType pro perty to find o ut the type o f drive. Bec ause this pro perty just returns a number, a
52
Part I: Sc ripting Kic ks tart
■
■
variable array is used to sto re the meaning o f tho se numbers. The sc ript then c an use the type number to index the variable array and return a userfriendly desc riptio n.
Figure 2-9: Your s cript reports all drives and their drive types . There are two hidden func tio ns that c an make life a lo t easier — Join and Split. Join c o nverts a text variable into an array using a delimiter yo u spec ify. Split do es exac tly the o ppo site and c o nverts an array into a text variable, allo wing yo u to display entire array c o ntents at o nc e. Using Split, yo u c an greatly simplify the previo us sc ript. Split is perfec t to fill variable arrays with text variables: ‘ 2-11.VBS myarray = “Unknown;Removable;Fixed;Remote;CD-ROM;RAM-Drive” myarray = Split(myarray, “;”)
‘ find out the type of drives set fs = CreateObject(“Scripting.FileSystemObject”) ‘ get all drives: set drives = fs.Drives for each drive in drives letter = drive.DriveLetter kind = myarray(drive.DriveType) list = list & “Drive “ & letter & “ is of type “ & kind & vbCr next MsgBox list
In this example, yo u do no t need Dim. Split auto matic ally generates an array. There is no need fo r a dec laratio n anymo re. Use Dim o nly to generate a new array fro m sc ratc h.
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
53 ■
Using dynamic variable arrays Dim and Split always generate fixed-size arrays. A muc h mo re versatile appro ac h is ReDim. ReDim behaves just like Dim exc ept that the resulting array is dynamic and c an be expanded o r shrunk at a later time. Even if yo u do no t plan to take advantage o f dynamic array features, ReDim might be a better alternative. Often, it makes sense to first c alc ulate the size o f an array based o n what yo ur sc ript wants to sto re in it. ReDim ac c epts a dynamic ally c alc ulated size that yo u pass as a variable, so yo u c an spec ify the size o f the array at run-time. Dim do es no t ac c ept variables, so yo u need to kno w the size o f the array at design-time. The fo llo wing sc ript reads in all the .exe files in the Windo ws fo lder and sto res them inside an array. Bec ause the sc ript c an determine the number o f files o nly at run-time, it uses a dynamic array: ‘ 2-12.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) ‘ find out location of windows folder windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) ‘ get access to windows folder: set winfolder = fs.GetFolder(windir) ‘ find out how many EXE-files there are: counter = 0 for each file in winfolder.files ‘ find out extension name: ext = lcase(fs.GetExtensionName(file.name)) ‘ is it an EXE file? if ext = “exe” then ‘ count it! counter = counter + 1 end if next ‘ get appropriately sized array ‘ since base of array is 0, substract 1: Redim filenames(counter-1) ‘ store names of EXE files in array: for each file in winfolder.files ‘ find out extension name: ext = lcase(fs.GetExtensionName(file.name)) ‘ is it an EXE file? if ext = “exe” then ‘ store it! counter = counter - 1 filenames(counter) = ucase(file.name)
54
Part I: Sc ripting Kic ks tart
■
■
end if next ‘ now your array contains all the EXE files. How many? MsgBox “I found “ & UBound(filenames)+1 & “ executable files!” ‘ Show list of files: ‘ transform array to text variable: text = Join(filenames, vbCr) MsgBox text
UBound repo rts the highest index number o f an array. Bec ause arrays start with index 0 and are c o nsec utive, the number o f array elements is repo rted by UBound(array)+1. If yo u need to deal with text variables suc h as filenames, yo u c an also use Split to c reate a dynamic array at run-time: ‘ 2-13.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) ‘ find out location of windows folder windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) ‘ get access to windows folder: set winfolder = fs.GetFolder(windir) ‘ list all EXE-files: for each file in winfolder.files ‘ find out extension name: ext = lcase(fs.GetExtensionName(file.name)) ‘ is it an EXE file? if ext = “exe” then ‘ add it! list = list & ucase(file.name) & vbCr end if next ‘ strip off the last delimiter: if len(list)>0 then list = left(list, len(list)-1) end if MsgBox list ‘ if needed, convert list to dynamic array: filenames = Split(list, vbCr) MsgBox “There are “ & UBound(filenames)+1 & “ executables!”
This sc ript is muc h simpler (and faster) bec ause there is no lo nger a need to find o ut the number o f .exe files befo rehand.
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
55 ■
Dynamically shrinking or expanding arrays Arrays defined by ReDim c an be shrunk o r expanded. The fo llo wing sc ript intro duc es a self-defined pro c edure c alled CompressIt that eliminates all empty fields: ‘ 2-14.VBS ‘ define an array dynamically: redim myarray(100) ‘ only use part of the space: myarray(1) = “Hello!” myarray(3) = 3.1415926 myarray(18) = 2000 ‘ a lot of space is wasted. Compress array by ‘ eliminating all empty fields: MsgBox “Before compression: array contains “ & UBound(myarray)+1 & “ fields.” CompressIt myarray MsgBox “After compression: array contains “ & UBound(myarray)+1 & “ fields.” for each entry in myarray list = list & TypeName(entry) & “:” & vbTab & entry & vbCr next MsgBox list
sub CompressIt(array) ‘ field used to store data: counter = 0 ‘ loop through all fields: for each entry in array if not isEmpty(entry) then ‘ store this entry array(counter)=entry counter = counter + 1 end if next ‘ counter now contains the number of ‘ fields that contain data. Resize the ‘ array: ReDim Preserve array(counter-1) end sub
56
Part I: Sc ripting Kic ks tart
■
■
CompressIt c an o nly wo rk bec ause the array was initially defined dynamic ally by ReDim. Trying to c o mpress a static array will c ause an erro r. This example reveals many interesting details: ■ Co mpressio n is do ne by lo o ping thro ugh the array elements. A c o unter
is inc remented eac h time a valid entry is fo und, and the valid entry is c o pied into the array at the po sitio n o f the c o unter. This way, all valid entries are mo ved to the beginning o f the array. ■ Onc e all valid entries are c o nc entrated at the beginning o f the array,
ReDim c uts o ff the remainder. By using Preserve, the c o ntents in the remaining fields o f the array are preserved. No te that the resulting array still c o ntains the same data and data type as befo re. VBSc ript arrays c o nsist o f Variants, so the array elements c an c o ntain all kinds o f data types. Array c o ntents need no t be o f the same type.
Using multiple dimensions Arrays c an use mo re than o ne index. If yo u need to , yo u c an dec lare arrays o f up to 60 dimensio ns. Using multiple dimensio ns requires a lo t mo re memo ry, tho ugh. Multiply all dimensio ns (plus o ne fo r the 0-based field) to get the true number o f array fields: dim multi(60,5,12)
This line dec lares a static three-dimensio nal array. Yo u no w need to use three index numbers to ac c ess eac h array element. The to tal number o f array fields c an be c alc ulated as (60+1) × (5+1) × (12+1) = 4758. Multidimensio nal arrays are really no different fro m regular arrays. VBSc ript just c hanges the way yo u spec ify the array elements. In the prec eding example, VBSc ript wo uld just multiply the index numbers yo u spec ified and c alc ulate the true (o ne-dimensio nal) index number o f the field.
Dissecting strings A lo t o f info rmatio n is handed to yo ur sc ript as plain text. It’s impo rtant to be able to lo c ate and extrac t spec ific parts o r to make sure text is fo rmatted the right way. Fo rtunately, VBSc ript c o ntains many very useful func tio ns to handle texts. Yo u c an auto matic ally replac e text o r pic k o ut valuable info rmatio n.
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
57 ■
The basic text manipulatio n func tio ns are listed in Table 2-4:
Table 2-4
Text String M anipulation Functions
Function
Description
Len
Length of a s tring
Left
Returns characters from the beginning of the text
Mid
Returns characters from ins ide the text
Right
Returns characters from the end of the text
Instr
Finds the firs t occurrence of a text template
InstrRev
Finds the las t occurrence of a text template
Replace
Replaces part of the text w ith another text or eliminates characters
Trim
Removes s paces from either end of the text
LTrim
Removes s paces from the beginning of the text
RTrim
Removes s paces from the end of the text
LCase
Converts text to low ercas e
UCase
Converts text to uppercas e
Text c o mmands c an help yo u deal with two impo rtant tasks: ■ Extrac ting info rmatio n ■ Co nverting text fo rmats
Extracting information Yo ur sc ripts need to deal with filenames and paths all the time. So ho w c an yo u extrac t the path name fro m a filename? Suppo se yo u want to o pen the fo lder a sc ript resides in: ‘ 2-15.VBS fullname = WScript.ScriptFullName ‘ get the path ‘ first, find the last “\” pos = InstrRev(fullname, “\”) ‘ next, extract the part with the path: path = left(fullname, pos-1) MsgBox “This script is stored in: “ & path ‘ you now got the path! Now let’s get the filename:
58
Part I: Sc ripting Kic ks tart
■
■
filename = mid(fullname, pos+1) MsgBox “This script: “ & filename ‘ open an explorer window set wshshell = CreateObject(“WScript.Shell”) command = “EXPLORER.EXE “ & path wshshell.run command
ScriptFullName returns the fully qualified path name o f yo ur sc ript. InstrRev finds the po sitio n o f the last “\” that divides the path and filename (see Figure 2-10).
Figure 2-10: Find out your s cript ’s name and s torage location. Naming implies that Left and Right are c o usins. This is no t true. Left and Mid are the real c o usins and return at the beginning o r the end o f the text. Right also returns the end o f the text but c o unts text po sitio n bac kwards. With Right, po sitio n 1 represents the last c harac ter o f the text.
Left c an then extrac t the path, and Mid c an extrac t the filename. To o pen up the sc ript fo lder, yo u no w just need to c all the Explo rer and supply the path name. Ano ther way o f o pening a fo lder witho ut first needing to find o ut the path name is / selec t,. This hidden Explo rer o ptio n o pens a fo lder and marks a file at the same time. No te the c o mma. Unfo rtunately, the selec tio n feature do es no t always wo rk. Yo u c an at least use the o ptio n to o pen fo lders that c o ntain a spec ific file. ‘ 2-16.VBS set wshshell = CreateObject(“WScript.Shell”) command = “EXPLORER.EXE /SELECT,” & WScript.ScriptFullName wshshell.run command
Mid, Left, and Right are friendly func tio ns — sho uld yo u spec ify a text po sitio n that is greater than the text length, they return whatever text is left in the range. Ho wever, all three func tio ns raise erro rs if yo u spec ify a zero o r negative po sitio n. Therefo re, if yo u c alc ulate po sitio ns, always make sure the result is valid. This is espec ially true when using Instr o r InstrRev: Bo th func tio ns return zero if the spec ified searc h string is no t fo und.
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
59 ■
Converting text formats Yo ur sc ripts c an pic k o ut any c harac ter and c o nvert it into any o ther c harac ter. This is the basis o f c o nversio n to o ls. Whether yo u want to c o nvert DOS-ASCII to Windo ws-ANSI o r just enc rypt/ dec rypt files, the string manipulatio n func tio ns are the right to o ls. DOS c o mmands, fo r example, use the ASCII c harac ter c o de. It is very similar to the Windo ws ANSI c o de but no t identic al. Spec ial c harac ters are mapped to different c harac ter c o des. The same is true fo r plain text and HTML: To display text files as HTML pages, it’s nec essary to c o nvert spac es and any c harac ters that c o uld be c o nfused with HTML tags. The fo llo wing sc ript sho ws the basic arc hitec ture o f a c o nversio n to o l: It generates a DOS fo lder listing using the DIR c o mmand and then c o nverts the result to HTML (see Figure 2-11): ‘ 2-17.VBS ‘ connect to these objects: set WSHShell = CreateObject(“WScript.Shell”) set fs = CreateObject (“Scripting.FileSystemObject”) ‘ files to store information in: raw = “c:\temp.tmp” html = “c:\temp.html” ‘ DOS command used to get directory listing: command = “%COMSPEC% /C DIR “”C:\”” > “”” & raw & “””” ‘ execute DOS-command result = WSHShell.Run(command,0,true) ‘ in case of trouble, use this line instead to see what ‘ is happening with DOS command: ‘ result = WSHShell.Run(command,,true) ‘ read in DOS result and convert to HTML ConvertFile raw, html ‘ open HTML file in browser cmd = “iexplore.exe “”” & html & “””” wshshell.Run cmd
‘ converts a DOS-text into HTML sub ConvertFile(dir, output) ‘ does the input file exist? if fs.FileExists(dir) then ‘ open source file for reading: set source = fs.OpenTextFile(dir) ‘ create output file from scratch: set dest = fs.CreateTextFile(output)
60
Part I: Sc ripting Kic ks tart
■
■
‘ write HTML body tags: dest.WriteLine “
” ‘ read one character at a time and convert as appropriate: do until source.atEndOfStream char = asc(source.Read(1)) select case char case 132: ‘ä charnew = chr(228) case 129: ‘ü charnew = chr(252) case 142: ‘Ä charnew = chr(196) case 154: ‘Ü charnew = chr(220) case 153: ‘Ö charnew = chr(214) case 148: ‘ö charnew = chr(246) case 225: ‘ß charnew = chr(223) case 60: ‘< charnew = “[“ case 62: ‘> charnew = “]” case 13: ‘CR charnew = “ ” case 32: ‘Space charnew = “ ” case else: charnew = chr(char) end select ‘ write converted character into output file: dest.Write charnew loop ‘ close DOS input: source.close ‘ finalize HTML: dest.WriteLine “
” ‘ close output file dest.close ‘ delete temporary DOS file fs.DeleteFile dir, true end if end sub
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
61 ■
Figure 2-11: Convert DOS -ASCII to Window s -ANSI and dis play DOS command res ults .
Using Random Numbers VBSc ript c o ntains a rando m number generato r that c an supply rando m numbers in any range. The next sc ript sho ws the rando m number generato r in ac tio n (see Figure 2-12): ‘ 2-18.VBS ‘ get a series of 10 random numbers between 1 and 6 do for x=1 to 6 list = list & GetRandomNumber(1, 6) & “ “ next list = list & vbCr response = MsgBox(list & “More?”, vbYesNo + vbQuestion) loop until response=vbNo function GetRandomNumber(fromnr, tonr) ‘ initialize random number generator to get ‘ new random numbers: randomize ‘ calculate the random number GetRandomNumber = Fix(rnd*(tonr-fromnr))+fromnr end function
The rando m number generato r is c o ntro lled by randomize and rnd.
62
Part I: Sc ripting Kic ks tart
■
■
Always c all randomize at least o nc e befo re using rnd. This way, the base o f the rando m number generato r is set to the system time, a “rando m” number itself. This will guarantee that yo u get different rando m numbers eac h time yo u run yo ur sc ript. Yo u c an also supply yo ur o wn rando m number seed, whic h is useful if yo u need the same set o f rando m numbers again.
Randomize sets the base o f the generato r. This base number influenc es all subsequent c alls to rnd. Rnd returns a flo ating-po int value between 0 and 1, the rando m number.
Figure 2-12: Generate arbitrary s ets of random numbers . To get a rando m integer o f a c ertain range, yo u just need to transfo rm the flo ating-po int value. Multiply it by the desired range (max-min), then add the minimum rando m number. Cut o ff any dec imal plac es using Fix.
Encrypting files using random numbers Rando m numbers no t o nly serve as elec tro nic dic e. They c an also be used to effec tively enc rypt a file, to o ! The strategy is simple and ado pts the princ iple o f file c o nversio n disc ussed abo ve: Yo ur sc ript reads in a file c harac ter by c harac ter and then adds a rando m number to the c harac ter c o de. Bec ause c harac ter c o des need to be values between 0 and 255, the sc ript then subtrac ts 256 until the c o de is o f valid range.
Decrypting files In o rder to be able to dec rypt the file at a later time, it’s nec essary to repro duc e the exac t same set o f rando m numbers. Therefo re, bo th fo r enc ryptio n and dec ryptio n, yo u need to set the base o f the rando m number generato r to the same value. This is yo ur dec ryptio n key. To get the exac t same set o f rando m numbers o ver and o ver again, yo u need to c all rnd with a negative number just befo re yo u initialize the rando m base using randomize.
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
63 ■
Yo u c an also determine the enc ryptio n strength by spec ifying ho w many rando m numbers sho uld be used fo r enc ryptio n. The mo re numbers yo u use, the harder it will be to dec rypt the file. The fo llo wing sc ript sho ws the basic princ iple and enc rypts a file. Spec ify the filename, the enc ryptio n key, and the enc ryptio n strength. The file c o ntent will be enc rypted as sho wn in Figure 2-13. ‘ 2-19.VBS set fs = CreateObject(“Scripting.FileSystemObject”) name = InputBox(“Which file do you want to encrypt?”) if not fs.FileExists(name) then MsgBox name & “ does not exist!” WScript.Quit end if key = InputBox(“Enter your encryption key!”,,”12345”) if not isNumeric(key) then MsgBox “Your key needs to be a number!” WScript.Quit end if key = Fix(key) sec = InputBox(“Enter encryption strength!”,,”500”) if not isNumeric(sec) then MsgBox “This needs to be a number!” WScript.Quit end if sec = Abs(Fix(sec)) rnd -1 randomize key set readIt = fs.OpenTextFile(name, 1,,-2) set writeIt = fs.CreateTextFile(“C:\coded.txt”, true) do until readIt.atEndOfStream writeIt.write Encrypt(readIt.Read(1)) loop readIt.close writeIt.close MsgBox “Result stored in C:\CODED.TXT” & vbCr & _ “Your key is “”” & key & “””, your strength is “”” & sec & “””” function Encrypt(char) code = asc(char) randomnr = Fix(rnd*sec)+1 code = code + randomnr do while code>255
64
Part I: Sc ripting Kic ks tart
■
■
code=code-256 loop Encrypt = Chr(code) end function
Figure 2-13: Example of an encrypted file’s contents Dec ryptio n wo rks just the same way. All yo u need is the o riginal enc ryptio n key and the enc ryptio n strength: ‘ 2-20.VBS set fs = CreateObject(“Scripting.FileSystemObject”) name = InputBox(“Which file do you want to decrypt?”) if not fs.FileExists(name) then MsgBox name & “ does not exist!” WScript.Quit end if key = InputBox(“Enter your encryption key!”,,”12345”) if not isNumeric(key) then MsgBox “Your key needs to be a number!” WScript.Quit end if key = Fix(key) sec = InputBox(“Enter encryption strength!”,,”500”) if not isNumeric(sec) then MsgBox “This needs to be a number!” WScript.Quit end if sec = Abs(Fix(sec)) rnd -1 randomize key set readIt = fs.OpenTextFile(name, 1,,-2) set writeIt = fs.CreateTextFile(“C:\decoded.txt”, true)
Chapte r 2 : VBSc ript Gue rilla Se s s io n ■
65 ■
do until readIt.atEndOfStream writeIt.write Decrypt(readIt.Read(1)) loop readIt.close writeIt.close MsgBox “Result stored in C:\DECODED.TXT” function Decrypt(char) code = asc(char) randomnr = Fix(rnd*sec)+1 code = code - randomnr do while codelen(key) then if left(element, len(key)+1)=key & “.” then ‘ yes, return name vdpid = element exit for end if end if next ‘ any version dependent progID found? if vdpid=”” then ‘ no, add to store dict.add key, 0 else ‘ yes, replace dict.Remove vdpid dict.add key, 0 end if end if end if next MsgBox dict.Count & “ Objects found!” for each key in dict list = list & key & vbCr next MsgBox list
Try it o ut! Be patient, the sc ript takes so me sec o nds to exec ute. Then it repo rts the number o f o bjec ts it fo und and lists their names (see Figure 3-6).
Figure 3-6: Automatically build a lis t of all ins talled COM objects .
100
Part I: Sc ripting Kic ks tart
■
■
The sc ript auto matic ally takes c are o f multiple-versio n o bjec ts. It repo rts the versio n-independent ProgID, if available; o therwise, it repo rts the versio nspec ific ProgID. Mo st likely, there will be hundreds o f o bjec ts, and they wo n’t all fit into the dialo g bo x. That’s o kay, tho ugh. So far, the list o f o bjec ts is interesting but still no t refined eno ugh. Mo st o f the o bjec ts serve internal purpo ses and c anno t be used as sc ript c o mpo nents. The ProgID c o nsists o f two parts. The first part represents the “server” o bjec t. The sec o nd part is the name o f a sec tio n inside this server o bjec t. ProgIDs that share the first part are related and live inside the same o bjec t file.
Determining Whether an Object is Scriptable To get a real useful list o f o bjec ts that c an serve as Sc ript extensio ns, yo u need to further test the o bjec ts. It’s easy — just c all CreateObject o n eac h o f the o bjec ts and see what happens. Sho uld there be an erro r, then yo u kno w fo r sure that this o bjec t is unsuitable fo r sc ripting. Calling CreateObject o n an o bjec t usually o nly establishes a c o nnec tio n to this o bjec t. So metimes, ho wever, the o bjec t will respo nd with so me ac tio n. Yo u then kno w that these o bjec ts have defined c o de in the Initialize c o de segment. This c o de is exec uted immediately upo n o bjec t initializatio n. Ho wever, c alling CreateObject o n an unkno wn o bjec t is a brute-fo rc e appro ac h. If the o bjec t is generally unsuitable fo r sc ripting, CreateObject will simply fail. This is o kay bec ause the sc ript uses the on error resume next safety net. If the o bjec t is generally suitable fo r sc ripting, CreateObject will launc h the c o de inside the o bjec t. Usually, no thing exc iting happens — mo st o bjec ts just get initialized and patiently await yo ur c o mmands. There are so me o bjec ts, tho ugh, whic h start right away and do n’t wait fo r any metho d c alls. Calling CreateObject is eno ugh fo r them to jump o ut in the o pen. Sho uld this happen to yo u, then yo u’ll see so me windo ws po p up o r messages appear. Just c lic k them away. In very rare c irc umstanc es, c alling CreateObject c an even c rash yo ur sc ript (o r yo ur entire mac hine). This is o bvio usly neither no rmal behavio r no r by design. It indic ates so me malfunc tio n inside the o bjec t o r inside so me o ther c o mpo nent the o bjec t relates to . COM o bjec ts are exec utables. They c an fail just as any regular so ftware pro gram c an c rash. So , befo re starting the spysc ript, save any valuable info rmatio n and c lo se all yo ur pro grams! It’s very useful to kno w mo re abo ut why an o bjec t c rashes yo ur system. To find o ut, install Dr. Watso n, a little utility that c o mes with Windo ws. It will tell yo u mo re abo ut the c ause o f a c rash. Fo r example, o n o ne o f the test systems, three o bjec ts c rashed the sc ript. All three o bjec ts were inno c ent,
Chapte r 3 : Kidnapping Obje c ts
101
■
■
tho ugh! It turned o ut that in all three c ases, the Ado be Type Manager c aused the fault by c hanging system files it wasn’t suppo sed to . On systems witho ut this so ftware, no c rashes o c c urred. The test sc ript c hec ks all o bjec ts and rec o rds a lo g file. If so mething go es wro ng and yo ur sc ript breaks, then just start it o ver again. It’ll skip the last o bjec t and start where it left o ff. So even if so me exc eptio n erro rs do o c c ur, yo u will eventually get a list o f all suitable sc ripting o bjec ts — and warnings abo ut the o nes that aren’t stable. On Windo ws NT/ 2000, there may be numero us COM o bjec ts respo nsible fo r business lo gic o r advanc ed server features. It’s c o mmo n fo r them to raise erro rs when c alled direc tly. Try generating the list o nly o n systems that are no t c ruc ial to yo ur business. They might sto p respo nding and need a restart. Yo u must be sure yo ur system c an safely c rash. If in do ubt, use the files o n the c o mpanio n CD I’ve prepared fo r yo u instead o f generating yo ur o wn. I have prepared sample files fo r bo th Windo ws 98 and Windo ws 2000. They represent o bjec ts available o n my test systems and may no t be c o mpletely identic al to what’s available o n yo urs. Ho wever, sho uld yo u have tro uble generating the list o n yo ur system, they pro vide info rmatio n abo ut mo st standard COM o bjec ts. Yo u c an find bo th samples here — \info\win98.txt and \info.win2000.txt. ‘3-5.VBS ‘ get advanced registry functions: ‘ make sure the book toolkit is installed! set registry = CreateObject(“regtool.tob”) ‘ get a dictionary object to store key names in set dict = CreateObject(“Scripting.Dictionary”) set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) ‘ enumerate all keys in HKEY_CLASSES_ROOT set allkeys = registry.RegEnum(“HKCR\”) ‘ sort out all key names that have a dot in the name: for each key in allkeys ‘ where’s the first dot (skipping initial dots)? pos = Instr(2, key, “.”) if pos>0 then ‘ there’s a dot. Is there another one? pos2 = Instr(pos+1, key, “.”) if pos2>0 then ‘ yes, so this name is version specific ‘check whether we already have a ‘ version-independent progid! independent = left(key, pos2-1)
102
Part I: Sc ripting Kic ks tart
■
■
if not dict.Exists(independent) then ‘ no, store it dict.Add key, 0 end if else ‘ this one is version-independent. ‘ do we already have a version-dependent ‘ progID in store? vdpid = “” for each element in dict if len(element)>len(key) then if left(element, len(key)+1)=key & “.” then ‘ yes, return name vdpid = element exit for end if end if next ‘ any version dependent progID found? if vdpid=”” then ‘ no, add to store dict.add key, 0 else ‘ yes, replace dict.Remove vdpid dict.add key, 0 end if end if end if next MsgBox dict.Count & “ Objects found! Now checking if suitable” _ & “ for scripting!” ‘ open log file logfile = “C:\SCRIPTOBJECTS.TXT” ‘ open crash recovery file crash = “C:\CRASH.TXT” if fs.FileExists(crash) then set input = fs.OpenTextFile(crash) crashedAt = Fix(input.ReadLine) input.close MsgBox “Crash detected: skipping Object!” ‘ open for append! set output = fs.OpenTextFile(logfile, 8) else crashedAt = 0 set output = fs.CreateTextFile(logfile, true) end if ‘ check every object for each key in dict
Chapte r 3 : Kidnapping Obje c ts ■
103 ■
crashcount = crashcount + 1 LogCall crashcount if crashCount = crashedAt then MsgBox “This Object caused a crash: “ & key Print “WARNING” & vbTab & key & “ caused a crash!” elseif crashcount>crashedAt then if CheckObject(key) then Print key end if end if next ‘ delete crash log fs.DeleteFile crash, true ‘ open file wshshell.run logfile sub Print(text) output.WriteLine text end sub function CheckObject(name) ‘ turn off error handling on error resume next ‘ try to access object set dummy = CreateObject(name) ‘ check whether error was raised: if not err.Number=0 then ‘ object unsuitable err.clear CheckObject=false else ‘ add Object Information: name = name & vbTab & TypeName(dummy) & vbTab _ & ProcessInfo(name) ‘ Object ok for scripting CheckObject=true end if ‘ release Object WScript.DisconnectObject dummy end function sub LogCall(crashcount) set recovery = fs.CreateTextFile(crash, true) recovery.WriteLine crashcount recovery.close end sub function ProcessInfo(name)
104
Part I: Sc ripting Kic ks tart
■
■
clsid = ReadKey(“HKCR\” & name & “\CLSID\”, ok) keyA = “HKCR\CLSID\” & clsid & “\” physicalname = ReadKey(keyA & “InprocServer32\”, ok) if physicalname = “” then physicalname = ReadKey(keyA & “LocalServer32\”, ok) end if if physicalname=”” then physicalname = “unknown object file location” end if typelib = ReadKey(keyA & “TypeLib\”, ok) if typelib”” then set typelibs = registry.RegEnum(“HKCR\TypeLib\” _ & typelib & “\”) for each typelibid in typelibs if typelibid”” then lib = lib _ & ReadKey(“HKCR\TypeLib\” & typelib _ & “\” & typelibid & “\0\win32\”, ok) & vbTab next else lib = “no typelib” & vbTab end if ProcessInfo = physicalname & vbTab & lib end function function KeyExists(key) on error resume next check = wshshell.RegRead(key) if not err.Number=0 then KeyExists = false else KeyExists = true end if end function function ReadKey(key, status) on error resume next ReadKey = wshshell.RegRead(key) if not err.Number=0 then value=”” err.clear status=false else status=true end if end function
Go ahead and sip yo ur c o ffee. The sc ript takes many minutes to c hec k all the available o bjec ts. Even tho ugh it wo rks behind the sc enes, it’s still alive. Yo u’ll either get the final list o f o bjec t names o r so me so rt o f reac tio n to the test c all. Clo se all pro gram windo ws that might appear, and restart the sc ript if Windo ws repo rts an exc eptio n fault. Onc e the list is generated, restart yo ur system — just to make sure. The list will still be there. It’s sto red in C:\SCRIPTOBJECTS.TXT.
Chapte r 3 : Kidnapping Obje c ts
105
■
■
This list inc ludes the ProgID (the o bjec t name tag yo u pass to CreateObject to get a ho ld o f the o bjec t) and the o bjec t Type. Mo st o f the time, the o bjec t Type will o nly be “Objec t”, but so me o bjec ts reveal their true names. This is valuable info rmatio n bec ause it helps to identify the o bjec t’s inner struc ture o nc e yo u tap into the TypeLibrary. In additio n, the list reveals the physic al name o f the o bjec t and the names o f any type libraries asso c iated with this o bjec t. This info rmatio n will c o me in handy thro ugho ut the rest o f this bo o k. Reading Sec ret TypeLibrary Info rmatio n No w that yo u kno w ho w many po tentially useful o bjec ts reside o n yo ur mac hine, yo u just need a way to ac c ess the func tio ns sto red inside. This is where the fun c o mes to an abrupt end bec ause mo st o bjec ts are undo c umented. Ho wever, there are ways to auto -do c ument hidden o bjec t func tio ns yo urself. Mo st o bjec ts c o me with a TypeLibrary, and inside this TypeLibrary, yo u find detailed info rmatio n abo ut all func tio ns, events, and c o nstants defined in the o bjec t. Type Libraries are used by pro gram develo pment enviro nments like Visual Basic to c hec k the syntax and give c lues to the pro grammer. This is why many o bjec ts “invo luntarily” c o ntain very detailed do c umentatio n, even if they did no t intend to supply this info rmatio n to yo u. It’s all a matter o f ac c essing the info rmatio n sto red in the TypeLibrary. Under no rmal c o nditio ns, a TypeLibrary is o f no great use. The Sc ripting Ho st has o nly limited abilities to “lo o k inside” and repo rt the hidden info rmatio n. This is why I have develo ped a little add-o n. It unc o vers any useful info rmatio n fo und in any TypeLibrary and helps to get very detailed do c umentatio n abo ut any o bjec t yo u might be interested in. Just make sure yo u install the bo o k to o lkit.
Auto-Documenting Undocumented Objects Abo ve, yo u c o nstruc ted a list o f all the po tentially useful o bjec ts installed o n yo ur system. All the info rmatio n is sto red in C:\SCRIPTOBJECTS.TXT. Next, extrac t the “o wners manual” fo r any o f these o bjec ts with the help o f the TypeLibrary. To be able to do so , yo ur sc ripts again need a c o mmand extensio n. Make sure yo u install \install\typelib\setup.exe, fo und o n the o n the c o mpanio n CD, befo re trying to launc h the fo llo wing sc ript. Pic k o ut an o bjec t yo u wo uld like to kno w mo re abo ut. Let’s start with WScript.Shell. The list states that the real name is WSHOM.OCX. This file resides in the Windo ws system fo lder.
106
Part I: Sc ripting Kic ks tart
■
■
Let’s c hec k o ut whic h o bjec ts really live inside this file (see Figure 3-7): ‘ 3-6.VBS obj = InputBox(“Object?”,,”wshom.ocx”) set wshshell = CreateObject(“WScript.Shell”) set tl = CreateObject(“typelib.decoder”) set erg = tl.GetInterfaces(obj) for each interface in erg list = list & interface & vbCr next MsgBox list
Figure 3-7: Peek into COM objects and find out names of internal objects . It wo rks! The sc ript repo rts a number o f o bjec t names, and yo u c an see two things immediately. First, yo u’ll no tic e that wshom.ocx c o ntains the IWshShell2 o bjec t, whic h belo ngs to WScript.Shell. It also c o ntains IWshNetwork2, whic h belo ngs to WScript.Network. In additio n, wshom. ocx c o ntains a number o f o ther o bjec ts. Objec t files c o ntain many different o bjec ts. So me o f them refer to o bjec ts that sc ripts c an instantiate using CreateObject. These are “Start-Objec ts.” Other o bjec ts c anno t be c reated direc tly. Fo r example, a CreateObject o n WScript.Shell returns an IWshShell2-Object. One o f the hidden func tio ns inside IWshShell2 is c alled CreateShortcut, and this func tio n returns either IWshShortcut- o r IWshURLShortcut-Object. Bo th o bjec ts c anno t be c reated direc tly using CreateObject. If yo u use WSH 2.0, then WScript.Shell returns IWshShell2-Object. If yo u use WSH 1.0, then yo u get the o riginal o bjec t c alled IWshShell. Take a lo o k at yo ur SCRIPTOBJECTS.TXT list: It tells yo u exac tly whic h o bjec t type yo ur system returns. No w that yo u kno w the internal name o f the o bjec t, yo u c an take a lo o k inside and retrieve the internal “o wner’s manual.” Just supply the filename o f the
Chapte r 3 : Kidnapping Obje c ts
107
■
■
TypeLibrary and the name o f the o bjec t yo u are interested in: fo r example, wshom.ocx and IWshShell2 (see Figure 3-8). ‘ 3-7.VBS ‘ make sure you installed the custom object ‘ as shown in the book. set tl = CreateObject(“typelib.decoder”) set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) typelib = InputBox(“Please enter the name of the” _ & “ type library!”,,”wshom.ocx”) object = InputBox(“Please enter the name of the” _ & “ object!”,,”IWshShell2”) docu = “C:\docu.txt” set output = fs.CreateTextFile(docu, true) set ifc = tl.EnumInterface(typelib, object) for each info in ifc infos = split(info, vbTab) output.WriteLine infos(0) if len(infos(1))>0 then output.WriteLine infos(1) else output.WriteLine “no description available” end if next output.close wshshell.Run “IEXPLORE.EXE “ & docu
Wo w! The sc ript lists all the func tio ns and pro c edures sto red in IWshShell2, and yo u no w kno w the exac t syntax o f any c o mmand available thro ugh WScript.Shell. That is, yo u kno w the names o f the c o mmands, the number and kind o f arguments to supply, and the type o f return value, if any. If yo u are using the “o ld” WSH 1.0, there is no IWshShell2 o bjec t. Use IWshShell instead. What yo u do no t get is bac kgro und info rmatio n o n the c o mmands. wshom.ocx do es no t supply this kind o f info rmatio n. Instead, the list just states “no desc riptio n available.” Chec k o ut what happens if yo u list the c o mmands sto red in Scripting.FileSystemObject. To do this, take a lo o k in yo ur C:\SCRIPTOBJECTS.TXT list and searc h fo r Scripting.FileSystemObject. Immediately, yo u kno w that this o bjec t is sto red in sc rrun.dll and that the TypeLibrary is sto red in the same file. Yo u also kno w that yo u need to lo o k fo r an o bjec t c alled FileSystemObject. Supply this info rmatio n to yo ur sc ript abo ve.
108
Part I: Sc ripting Kic ks tart
■
■
Figure 3-8: Often, the TypeLibrary even includes documentation about the us e of functions . This time, the list inc ludes a sho rt desc riptio n o f eac h c o mmand that tells yo u what the c o mmand is suppo sed to do . There’s no law that requires an o bjec t to supply additio nal desc riptive info rmatio n, but many o bjec ts deliver suc h info rmatio n vo luntarily.
Getting More Help On Specific Commands In everyday life, yo u need so me so rt o f info rmatio n so urc e that tells yo u mo re abo ut available c o mmands and their purpo ses. There are numero us ways to get this info rmatio n. Maybe yo u need to quic kly lo o k up the syntax o f so me c o mmand. To do so with the help o f the TypeLibrary, yo u wo uld need to kno w a lo t o f info rmatio n: Yo u wo uld need to kno w the o bjec t file and the o bjec t name. In additio n, yo u wo uld o bvio usly need to kno w the exac t name o f the c o mmand yo u are lo o king fo r. This is to o muc h wo rk — let yo ur sc ripts do the dirty stuff. The fo llo wing sc ript returns any c o mmand that c o ntains yo ur searc h wo rd anywhere in its name, and the sc ript auto matic ally searc hes the mo st c o mmo n o bjec t files and all o bjec ts inside them. ‘ 3-8.VBS ‘ make sure you installed the custom object ‘ as shown in the book. set ti = CreateObject(“typelib.decoder”)
Chapte r 3 : Kidnapping Obje c ts
109
■
■
list = Split(“wshom.ocx;vbscript.dll;scrrun.dll;” _ & “shdocvw.dll;wscript.exe”, “;”) searchword = InputBox(“Please enter the command name you are looking for!”) for each library in list result = ti.Search(searchword, library) if not result=”” then endresult = endresult & “(“ & library & “)” & vbCrLf & result end if next MsgBox endresult
Test this sc ript! Just enter so me c o mmand name: GetDrive, fo r example. Immediately, the sc ript o pens a dialo g windo w and displays the c alling syntax. It also tells yo u whic h o bjec t file c o ntains the c o mmand: fo r example, sc rrun.dll. Even the name o f the internal o bjec t that supplies this c o mmand is pro vided: in this c ase, FileSystemObject (see Figure 3-9). This sc ript is no t limited to external o bjec ts. It also queries the files vbsc ript.dll and wsc ript.exe, so yo u c an also searc h fo r intrinsic VBSc ript c o mmands like MsgBox and InputBox o r c o mmands pro vided by the sc ripting ho st like Sleep (WSH 2.0 o nly).
Figure 3-9: Search for function s yntax us ing key w ords . The sc ript auto matic ally searc hes the mo st c o mmo n o bjec ts. Yo u c an always append the list o f filenames to inc lude mo re o bjec ts. If o bjec ts are sto red o utside the system fo lders c o vered by the PATH enviro nment variable, then yo u need to pro vide the full path name. Interesting, do n’t yo u agree? The InputBox c o mmand features so me undo c umented arguments to spec ify the po sitio n. Chec k this line o ut: answer = InputBox(“Question”,,,10,10)
This line o pens an InputBo x dialo g windo w, but this time, yo u c an spec ify its upper-left c o rner po sitio n o n yo ur sc reen. No te that o ptio nal arguments are enc lo sed by square brac kets. Yo u immediately see that the pro mpt is the o nly argument InputBox requires.
110
Part I: Sc ripting Kic ks tart
■
■
Even mo re interesting: The searc h func tio n returns any c o mmand that inc ludes yo ur searc h wo rd anywhere in its name. So , if yo u do n’t kno w the exac t c o mmand name, just type in part o f it. Fo r example, type in Drive ! No w yo u get a list o f all kinds o f c o mmands that relate to drives (see Figure 3-10). No te also that so me func tio ns are pro vided by mo re than o ne o bjec t, so there may be duplic ate entries. This is no rmal behavio r.
Figure 3-10: Find any function related to “Drives .” If yo u want to limit the searc h result to o nly tho se c o mmands that start with yo ur searc h text, then just replac e o ne line o f c o de: result = ti.Search(searchword, library, false)
To be able to use a spec ific c o mmand, yo u sho uld c arefully lo o k at the o bjec t name that pro vides this func tio nality. Let’s suppo se yo u have searc hed fo r the key wo rd Drive. The dialo g bo x sho ws all c o mmands with “drive” in its name. Maybe yo u are interested in EnumNetworkDrives. As yo u see, this c o mmand is pro vided by IWshNetwork, so take a lo o k in yo ur C:\scriptobjects.txt file and searc h fo r IWshNetwork. As yo u see, WScript.Network pro vides this o bjec t. Next, take a lo o k at the c o mmand syntax. The func tio n EnumNetworkDrives returns IWshCollection. This name is no standard variable type, so yo u c an safely assume it’s ano ther o bjec t; therefo re, yo u need to sto re the func tio n result using Set. This is all yo u need to kno w: ‘ 3-9.VBS ‘ get access to IWshNetwork-Object set iwshnetwork = CreateObject(“WScript.Network”) ‘ call unknown command: set iwshcollection = iwshnetwork.EnumNetworkDrives MsgBox TypeName(iwshcollection)
The sc ript wo rks and no erro r is raised. No thing exc iting happens either, tho ugh. EnumNetworkDrives has retrieved an iwshcollection o bjec t, and yo u need to kno w mo re abo ut this o bjec t befo re yo u c an do so mething with it.
Chapte r 3 : Kidnapping Obje c ts
111
■
■
The previo us sc ript c an’t help yo u muc h. IWshCollection is an o bjec t, no t a c o mmand, so yo u c an’t searc h fo r it. Try the next sc ript! It searc hes bo th fo r c o mmands and fo r o bjec ts, and bec ause the result c an be a lo t o f info rmatio n, it displays the info rmatio n as a text file: ‘ 3-10.VBS ‘ make sure you installed the custom object ‘ as shown in the book. set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) set ti = CreateObject(“typelib.decoder”) list = Split(“wshom.ocx;vbscript.dll;scrrun.dll;” _ & “shdocvw.dll;wscript.exe”, “;”) searchword = InputBox(“Please enter the command name you are looking for!”) for each library in list result = ti.Search(searchword, library) if not result=”” then endresult = endresult & “(“ & library & “)” _ & vbCrLf & result end if next for each library in list set iflist = ti.GetTypeInfos(library) for each interfacename in iflist if Instr(lcase(interfacename), lcase(searchword))>0 then set result = ti.EnumInterface(library, interfacename) if result.Count>0 then endresult = endresult & “(“ & library & “)(“ _ & interfacename & “)” & vbCrLf for each infoset in result info = Split(infoset, vbTab) endresult = endresult & info(0) & vbCrLf if not info(1)=”” then endresult = endresult & info(1) _ & vbCrLf end if next end if end if next next file = “C:\doku_” & searchword & “.txt” set output = fs.CreateTextFile(file, true) output.WriteLine endresult output.close wshshell.run file
112
Part I: Sc ripting Kic ks tart
■
■
No w searc h fo r IWshCollection! Yo u will get a c o mplete referenc e o f all its metho ds and pro perties (see Figure 3-11).
Figure 3-11: Build complete function lis ts for future reference and res earch. As it turns o ut, the IWshCollection o bjec t is a generic o bjec t used to sto re any kind o f info rmatio n. This is all yo u need to kno w in o rder to c o mplete yo ur sc ript: ‘ 3-11.VBS ‘ get access to IWshNetwork-Object set iwshnetwork = CreateObject(“WScript.Network”) ‘ call unknown command: set iwshcollection = iwshnetwork.EnumNetworkDrives ‘ get detail information if iwshcollection.Count>0 then ‘ how many network connections exist? MsgBox “Network connections: “ & (iwshcollection.Count/2) for x = 0 to iwshcollection.Count - 1 step 2 connect = “Connection Name: “”” & iwshcollection.Item(x) connect = connect & “”” UNC: “ & iwshcollection.Item(x+1) MsgBox connect next end if
Count tells yo u ho w many piec es o f info rmatio n are sto red inside the c o llec tio n. Yo u c an retrieve the ac tual info rmatio n with for...next using Item(x) and using index number 0 fo r the first c o llec tio n element, o r yo u c an use for each...next. The helper to o ls c an pro vide info rmatio n abo ut the struc ture o f c o mmands and o bjec ts. They c anno t tell yo u all the details, tho ugh. So , it’s up to yo u to find o ut whic h info rmatio n EnumNetworkDrives ac tually returns. This is part o f the adventure game. Fo rtunately, yo u just need to lo o k at the returned data to find o ut what it stands fo r.
EnumNetworkDrives happens to sto re two piec es o f info rmatio n per netwo rk c o nnec tio n: the name o f the c o nnec tio n (if any) and its UNC path name. This is why the sc ript divides Count by 2 to retrieve the number o f ac tual netwo rk
Chapte r 3 : Kidnapping Obje c ts
113
■
■
c o nnec tio ns, and this is also the reaso n why the sc ript uses for...next with step 2. It wants to retrieve two piec es o f info rmatio n at a time.
EnumNetworkDrives lists all c urrently ac tive netwo rk c o nnec tio ns. This inc ludes permanent c o nnec tio ns as well as tempo rary c o nnec tio ns. Fo r example, yo u c o uld use Run fro m the Start menu and type in a valid UNC path like \\10.10.1.5 [Enter]. This wo uld establish a tempo rary c o nnec tio n to the server 10.10.1.5, and EnumNetworkDrives wo uld repo rt this c o nnec tio n. Bec ause it’s a tempo rary c o nnec tio n, it do es no t c arry a name tag.
Getting access to hidden help files It’s amazing: Many o bjec t func tio ns are extremely well-do c umented, but the do c umentatio n is sto red away in so me help file deep do wn o n yo ur hard drive. Again, here c o mes the TypeLibrary to the resc ue. It c o ntains help c o ntext info rmatio n that spec ifies no t o nly the name o f the help file but also the “page” that c o ntains the info rmatio n abo ut the spec ific func tio n yo u wo nder abo ut. The help info rmatio n pro vided by the TypeLibrary isn’t suppo sed to help yo u o ut. Instead, it’s pro vided fo r pro gramming enviro nments: They c an po p up the right help file whenever the pro grammer hits [F1]. Luc kily, this help info rmatio n is available to yo ur sc ripts, to o ! Chec k o ut the fo llo wing sc ript. It wants yo u to type in the exac t name o f so me c o mmand. This time, it wo n’t be eno ugh to just spec ify part o f the name. Yo ur input do esn’t need to be c ase-sensitive, tho ugh. See what happens if yo u type in MsgBox! ‘ 3-12.VBS ‘ make sure you installed the custom object ‘ as shown in the book. set ti = CreateObject(“typelib.decoder”) set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) list = Split(“wshom.ocx;vbscript.dll;scrrun.dll” _ & “;shdocvw.dll;wscript.exe”, “;”) searchword = InputBox(“Please enter the command name you are looking for!”) helpfile = “” for each library in list result = ti.SearchHelp(searchword, library) if not result=”” then helpfile = result end if next if not helpfile=”” then filename = mid(helpfile, InstrRev(helpfile, “ “)+1) if fs.FileExists(filename) then
114
Part I: Sc ripting Kic ks tart
■
■
msg = searchword & “ is covered in “ & filename & vbCr _ & “Do you want to open help file?” if MsgBox(msg, vbYesNo)=vbYes then wshshell.Run helpfile end if else msg = searchword & “ is covered in “ & filename & vbCr _ & “The file does not exist on your computer.” MsgBox msg end if else MsgBox “No help file associated with this item.” end if
Darn. There isn’t a help file asso c iated with this c o mmand. Try a different c o mmand: fo r example, GetDrive. Hey, this time a help file is spec ified! Yo u c an o pen the help file right away if it’s installed o n yo ur c o mputer. This way, yo u get immediate help and so me example c o de. In my c ase, the do c umentatio n is in German bec ause o n my system, the German versio n o f the MSDN library was installed (see Figure 3-12).
Figure 3-12: Many functions are as s ociated w ith s pecific help files . Sho uld the sc ript repo rt that the help file is missing o n yo ur c o mputer, then manually searc h yo ur hard drive using Searc h fro m the Start menu. So metimes, help files do exist but are misplac ed. Always searc h fo r the filename witho ut extensio n, so if the file VBENLR98.CHM is missing, searc h fo r VBENLR98 o nly. Help files c an c o nsist o f mo re than a single file, and yo u want to find all parts o f it. Then, c o py all fo und files into the appro priate fo lder. Sho uld the file be missing, then surf to o ne o f the internet searc h pages like www.altavista.com and lo o k fo r the file so meplac e else. Maybe yo u c an do wnlo ad it so mewhere. Why are help files so metimes missing? It’s by design. Remember that help c o ntext info rmatio n is pro vided mainly fo r pro gramming enviro nments like Visual Basic . So , so metimes the help files are also part o f these so ftware pac kages and are o nly available if yo u install them. Still, yo u are no t required to buy expensive pro gramming so ftware just to get help info rmatio n. Bo th WScript- and Scripting-Objects are welldo c umented. The help files are pro vided o n the bo o k CD. They will no t matc h
Chapte r 3 : Kidnapping Obje c ts
115
■
■
the internal help c o ntext IDs, but it’s easy to lo o k up the info rmatio n manually using the index page. Mo st o f what yo u have disc o vered in this c hapter is useful primarily to ac c ess undo c umented o bjec ts. These o bjec ts bring their o wn help files (if available), so there’s no need fo r any pro gramming enviro nment anyway. Just install the Ko dak Imaging to o ls o n yo ur system to see ho w this c o nc ept wo rks! They are free, and they are part o f any Windo ws versio n (see Chapter 22 fo r details). Then, extend yo ur searc h sc ripts by adding the new o bjec t filenames: Split(“wshom.ocx;vbscript.DLL;scrrun.DLL;shdocvw.DLL;wscript.exe;imgad min.ocx;imgedit.ocx;imgscan.ocx;imgthumb.ocx”, “;”)
No w try it o ut! Searc h fo r the c o mmand ScannerAvailable. The c o mmand is fo und in no time, and yo u get a referenc e to its help file. Open it. Auto matic ally, the sc ript jumps to the right page o f the file, and yo u get all the o ffic ial do c umentatio n available fo r ScannerAvailable. In Windo ws 2000, fo r so me reaso n, Mic ro so ft dec ided to take o ut bo th the help info rmatio n and the help file fo r the imaging c o ntro ls. Still, yo u c an use the free versio n. This c hapter pro vides the to o ls to reveal the internal metho ds, and Chapter 21 pro vides a lo t o f sample sc ripts! There are two types o f help files: Old Windo ws help files c arry the extensio n .hlp. Yo u c an o pen tho se files using WINHELP.EXE and jump to a spec ific page using o ptio n –n. Current help files c o me in a different flavo r — they c arry the extensio n .chm and c o nsist o f HTML pages. Yo u c an o pen tho se help files with HH.EXE and jump to individual pages using the hidden o ptio n –mapid.
Finding More Information About Commands If yo u need additio nal info rmatio n abo ut a spec ific c o mmand, searc h this bo o k’s index. It c o ntains hundreds o f examples. If yo u are still hungry fo r mo re, then surf to o ne o f the Internet searc h sites like www.altavista.com and enter the c o mmand name as a searc h phrase. Yo u will be amazed ho w muc h useful info rmatio n will po p up in yo ur bro wser.
Summary Hundreds o f po tentially useful auto matio n o bjec ts are installed o n yo ur system, and mo st o f them are valuable add-o ns to yo ur sc ripts. It o nly takes so me hidden to o ls and tec hniques to unc o ver the impo rtant hidden info rmatio n inside these o bjec ts. To o ls pro vide yo u with the detailed “o wner’s manual” o f any auto matio n o bjec t yo u find interesting. With the help o f this info rmatio n, yo u c an immediately start ac c essing the internal func tio ns.
Chapte r 4
Developing Your Own Script Components In This Chapter 䊳 Get ac c usto med to the free Visual Basic Co ntro l Creatio n Editio n 䊳 Develo p yo ur o wn sc ript extensio ns using Windo ws API func tio ns 䊳 Open and c lo se the CD-ROM tray by sc ript 䊳 Lo o k at Windo ws API func tio ns and DECLARE in-depth 䊳 Examine func tio ns sto red in DLL files 䊳 Develo p yo ur o wn dialo g bo xes 䊳 Disc o ver pro perties and design yo ur o wn 䊳 Create o ptio nal parameters and default values 䊳 Change windo w style 䊳 Make windo ws resizable 䊳 Distribute self-made COM o bjec ts to o thers
C
OM o bjec ts wo rk like c o mmand extensio ns and pro vide all the func tio ns missing in VBScript. In the previo us c hapter, yo u saw ho w useful it is to ac c ess COM o bjec ts. Yo u are no t limited to the COM o bjec ts o ther peo ple have develo ped. Yo u c an design yo ur o wn. It’’s very easy, and it’s free, to o . Mic ro so ft pro vides all the nec essary develo pment to o ls, and yo u c an find them o n the c o mpanio n CD. Develo ping yo ur o wn COM o bjec ts allo ws yo u to ac c ess even the mo st basic Windo ws Applic atio n Pro gramming Interfac e (API) func tio ns. COM o bjec ts c an do anything a “C” o r Visual Basic pro grammer c an do . In this c hapter, I’ll sho w yo u ho w to develo p yo ur o wn COM o bjec ts. It’s easy, bec ause yo u c an use Visual Basic to develo p COM o bjec ts. Visual Basic is very similar to VBScript. In fac t, VBScript is just a subset o f Visual Basic , so yo u already kno w mo st o f what is needed.
118
Part I: Sc ripting Kic ks tart
■
■
COM develo pment is the sec o nd step, no t the first. Befo re yo u start develo ping yo ur o wn COM o bjec ts, bro wse thro ugh Part II and get familiar with VBScript and the sc ript examples. Onc e yo u feel c o mfo rtable with VBScript, it’s o nly a small step to COM develo pment. Yo u do n’t need to buy Visual Basic in o rder to develo p COM c o mpo nents. Mic ro so ft has c reated a spec ial versio n o f Visual Basic c alled Visual Basic Co ntro l Creatio n Editio n. It’s a full Visual Basic develo pment enviro nment. Mic ro so ft has just disabled so me o ptio ns so yo u c an’t c reate “regular” pro grams. Yo u c an, ho wever, easily c reate COM o bjec ts, and that’s all yo u need. The VB CCE is inc luded o n the c o mpanio n CD. Yo u just need to install it. Mic ro so ft has released the VB CCE primarily to pro mo te the use o f Ac tiveX Internet c o ntro ls. So , the primary target gro up is Web develo pers. Ho wever, Ac tiveX c o ntro ls are no t a go o d c ho ic e to spic e up Web pages, primarily bec ause o f sec urity c o nc erns o utlined in the Prefac e. Fo rtunately, Ac tiveX c o ntro ls are no t limited to Web pages. They c an ac t as COM o bjec ts, to o .
Getting Accustomed to VB CCE After installatio n, yo u’ll find a new pro gram gro up c alled Visual Basic 5.0 CCE. Inside, yo u’ll find the VB CCE pro gram and an Applic atio n Wizard. The Applic atio n Wizard helps yo u to pro duc e setup files so yo u c an distribute yo ur COM o bjec ts to o thers. Onc e yo u start VB CCE, the New Pro jec t windo w o pens. Pic k Ac tiveX Co ntro l to start a new Ac tiveX c o ntro l pro jec t. Other pro jec t types are available, to o . Ho wever, VB CCE c an’t c o mpile a Standard .exe, so the o nly useful o ptio n is Ac tiveX Co ntro l. Yo u get a new pro jec t. At first, the menu bars and windo w panes are a little o verwhelming, but no t fo r lo ng. Take a lo o k at Figure 4-1.
Toolbox On the left side, yo u’ll see the to o lbo x. It c o ntains c o ntro ls that yo u c an plac e inside yo ur pro jec t. Yo u need the to o lbo x o nly if yo u plan to design a windo w. Fo r no w, yo u wo n’t need c o ntro ls, so yo u c an safely turn the to o lbo x o ff. To get it bac k later, o pen the View c o mmand and c ho o se To o lbo x. All To o lbars (this inc ludes To o lbo x windo w as well as all the o ther to o lbars) are do c kable. It’s up to yo u whether yo u want to use them do c ked o r as flo ating windo ws. Yo u c an even stac k a c o uple o f to o lbars o n to p o f eac h o ther o r do c k them at ano ther side o f the main windo w.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
119
■
■
Toolbox
Properties W indow
M ain W indow
Project W indow
Form Layout
Figure 4-1: Dis cover the anatomy of Vis ual Bas ic Control Creation Edition.
Main window The main windo w sho ws the o bjec t yo u are develo ping. There are two different views, and Objec t View is enabled by default. In Objec t View, yo u see the user interfac e. It’s just a gray square, but yo u c an easily plac e c o ntro ls o n it — just do uble-c lic k a c o ntro l in the to o lbo x windo w. In Co de view, yo u will see the “inside” o f yo ur o bjec t. Co de view is muc h mo re impo rtant than Objec t view bec ause in Co de view yo u c an develo p the internal mec hanic s o f yo ur o bjec t. To switc h between bo th view mo des, just right-c lic k so mewhere inside the main windo w and c ho o se View Co de (see Figure 4-2). Yo u c an also o pen the View menu and c ho o se Co de to switc h to Co de view.
Project Explorer On the right side, yo u’ll see three individual helper windo ws. One o f them is the Pro jec t Explo rer. It wo rks like a table o f c o ntents and lists all the c o mpo nents yo ur o bjec t c o nsists o f. At the beginning, there is o nly o ne o bjec t — UserControl1. It’s sto red in the virtual User Co ntro ls fo lder, whic h is part o f yo ur pro jec t, mo st likely c alled Project1 (see Figure 4-3).
120
Part I: Sc ripting Kic ks tart
■
■
Figure 4-2: Sw itch to Code view to enter Vis ual Bas ic code.
Figure 4-3: Project w indow lis ts your projects ’ elements . Yo u c an always turn this windo w o ff if it’s in the way. Yo u c an get it bac k later by o pening the View menu and c ho o sing Pro jec t Explo rer. Leave this windo w o pen, tho ugh, bec ause yo u need it to assign a name to yo ur pro jec t.
Properties window The Pro perties windo w displays all the pro perties o f a c o ntro l. Bec ause there is o nly o ne c o ntro l c alled UserControl1, it sho ws the pro perties o f yo ur c o ntro l fo rm. Yo u c an always c lo se this windo w and get it bac k later by o pening the View menu: Cho o se Pro perties Windo w. Leave the windo w o pen, tho ugh, bec ause yo u will need it in a sec o nd to c hange yo ur c o ntro l’s name.
Form Layout window The last helper windo w displays any fo rms yo u may have develo ped — it’s a c hanc e fo r yo u to judge their lo o ks. But, yo u’re no t go ing to design any fo rms no w, so just turn the windo w o ff. Yo u c an always get it bac k by o pening the View menu and c ho o sing Fo rm Layo ut Windo w.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
121
■
■
Developing Your Own Script Extension Onc e yo u have c lo sed all unnec essary windo ws and switc hed to Co de view, yo ur VB CCE windo w lo o ks a lo t friendlier. In fac t, it almo st lo o ks like the text edito r yo u used to develo p sc ripts. And it wo rks muc h the same, to o . Befo re yo u start, rethink what yo u are go ing to do . Yo u are go ing to develo p a sc ript add-o n. Yo u aren’t go ing to develo p a stand-alo ne pro gram. So , at this stage, all yo u want to do is define func tio ns and pro c edures, whic h c an then be c alled by yo ur sc ripts. Do n’t write a main sc ript bo dy. Fo r example, write so mething like this: Sub SayHello(text) MsgBox “This is my message: “ & text end sub
This c o de is just plain sc ript c o de, so yo u c an just as easily use it inside o f a VBSc ript file. This time, ho wever, yo u are designing a COM c o mpo nent. One o f the first differenc es yo u’ll no tic e is the pro fessio nal develo pment enviro nment. VB CCE auto matic ally adds the End Sub statement, and o nc e yo u type in MsgBox, an info bo x o pens and assists yo u by pro viding the syntax info rmatio n (see Figure 4-4).
Figure 4-4: You can des ign your ow n COM objects us ing plain VBScript.
122
Part I: Sc ripting Kic ks tart
■
■
Yo u c an’t exec ute yo ur c o de, tho ugh. If yo u c lic k the Play butto n, yo u’ll just get an erro r message stating that c o ntro ls c an’t run independently. Always remember that c o ntro ls are designed to be add-o ns to sc ript ho sts like the Windo ws Sc ripting Ho st o r the Internet Explo rer. They c an’t run independently.
Assigning a name to your control The next impo rtant step is to assign a name to yo ur c o ntro l. This name is very impo rtant bec ause it will be used as ProgID inside yo ur sc ripts to ac c ess yo ur new c o mpo nent. First, assign a name to yo ur pro jec t. Switc h to the Pro jec t Explo rer and c lic k the Project1-entry. In the Pro perties windo w, yo u no w see the o nly pro perty available — Name (see Figure 4-5). Clic k in this field and assign a new name. Be c areful c ho o sing a name. Never use a name already taken by so me o ther o bjec t installed o n yo ur system. In this example, use test.
Figure 4-5: Mark your project and as s ign a name in the Property w indow. Next, yo u need to assign a name to yo ur c o ntro l. Switc h to the Pro jec t Explo rer windo w and c lic k UserControl1. No w the Pro perties windo w sho ws the pro perties o f yo ur c o ntro l. Clic k the Name field and c ho o se a name (see Figure 4-6). Yo u c anno t use the same name yo u already used fo r yo ur pro jec t. In this example, use module.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts ■
123 ■
Figure 4-6: Mark your us er control and as s ign a name in the Property w indow. Yo ur c o ntro l is no w named test.module.
Compiling the COM object Yo u are almo st finished. Yo u just need to c o mpile yo ur c o de, transfo rming it into a real COM o bjec t. Open the file menu and c ho o se Make test.ocx. Write do wn the name o f the OCX file so mewhere so yo u kno w where yo ur c o mpo nent will be sto red.
Testing your new object Onc e yo u have c o mpiled yo ur o bjec t, it’s ready fo r use by yo ur sc ripts. Yo u c an ac c ess it just like any o ther COM o bjec t. Try the fo llo wing sc ript c o de. Enter it into a text edito r and save it with the .vbs file extensio n: ‘ 4-1.VBS set myobj = CreateObject(“test.module”) myobj.SayHello “Hi World!” MsgBox TypeName(myobj)
It wo rks. Yo ur sc ript ac c esses yo ur new COM o bjec t using CreateObject and the name yo u assigned to bo th yo ur pro jec t and yo ur user c o ntro l. Then it c alls the SayHello pro c edure.
TypeName reveals the name o f the o bjec t yo u ac c essed. It’s “mo dule,” just as expec ted.
124
Part I: Sc ripting Kic ks tart
■
■
Advantages of COM objects Why go thro ugh the hassle o f develo ping a COM o bjec t if yo u c an just as easily implement the same func tio nality direc tly into yo ur sc ript? There are a number o f so und reaso ns: ■ Hide yo ur c o de: If yo u want, yo u c an plac e it inside a COM o bjec t to hide
it. COM o bjec ts always wo rk like blac k bo xes. Yo u c an use them, but yo u c an’t lo o k inside them o nc e they are c o mpiled. ■ Reuse c o de: Yo u c an easily design c o mprehensive sc ript extensio ns
and inc lude them in any sc ript file yo u feel like. Bec ause the c o mplex mec hanic s are sto red inside the COM o bjec t, yo u do n’t need to c lutter yo ur sc ript c o de. It will o nly use o ne CreateObject c o mmand to ac c ess all the func tio nality inside yo ur COM o bjec t. ■ Language independenc e: COM o bjec ts are language-independent bec ause
the COM interfac e uses a c o mmo n standard. Any sc ript language c an use COM o bjec ts. So if yo u prefer to so lve a pro blem using Visual Basic , but yo u like JavaSc ript as a sc ript language, then develo p a COM o bjec t using MS CCE and plug it into yo ur JavaSc ript sc ript. Yo u c an even use yo ur COM o bjec ts inside Visual Basic fo r Applic atio ns sc ripts, so yo u c an add func tio nality to WinWo rd mac ro s. ■ Advanc ed func tio ns: VB CCE uses Visual Basic , no t VBSc ript. So far, yo ur
COM o bjec t is limited to the VBSc ript subset o f c o mmands. But no t fo r muc h lo nger. Visual Basic is able to ac c ess any o f the basic Windo ws API func tio ns, so yo u c an write sc ript enhanc ements that o ffer c o mpletely new func tio nality no t available to VBSc ript. ■ Fo rms and dialo g windo ws: COM o bjec ts c an neither run independently
no r o pen multiple windo ws. COM o bjec ts c an, ho wever, display o ne single windo w, so yo u c an design a graphic al user interfac e fo r yo ur sc ripts. Fo r example, yo u c an develo p an enhanc ed InputBox func tio n that hides what a user enters — perfec tly suited fo r passwo rd c hec ks. Yo u c an even develo p stand-alo ne disk to o ls that just need to be c alled by a sc ript.
Calling Windows API Functions Mo st o f the time, so ftware pac kages are no t mo no lithic blo c ks o f c o de. Instead, they c o ntain many different mo dules, and eac h mo dule serves a spec ific purpo se. In real life, whenever yo u start suc h an applic atio n, the individual c o mpo nents start to c o mmunic ate with o ne ano ther, sending c o mmands and requests bac k and fo rth. This is go o d news. No thing prevents yo u fro m talking to the mo dules as well. Yo u c an ac c ess a c o mpo nent and c all its func tio ns, and the c o mpo nent wo n’t realize that yo u’re an o utsider. It will do whatever it’s suppo sed to do .
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
125
■
■
In fac t, to make Windo ws so ftware develo pment easier, Mic ro so ft pro vides hundreds o f DLL files stuffed with internal Windo ws func tio ns that yo u wo uld never be able to invo ke fro m any dialo g bo x. They’re there fo r internal purpo ses, and almo st any so ftware yo u buy makes heavy use o f them. This set o f basic Windo ws c o mmands is c alled the applic atio n pro gramming interfac e (API). Originally, this API was develo ped fo r “serio us pro grammers” using a c o mplic ated pro gramming language like C. Ho wever, Visual Basic c an ac c ess tho se API func tio ns as well. And this is where COM o bjec ts c o me into play. VBSc ript has no way o f ac c essing API func tio ns bec ause it do esn’t have a built-in c o mmand to spec ify DLL files and c all c ertain func tio ns within it. Visual Basic , in c o ntrast, spo rts the dec lare c o mmand, and bec ause VB CCE uses the full language set o f Visual Basic , yo u c an easily ac c ess API func tio ns fro m inside yo ur COM o bjec t and then repac kage them so yo ur sc ripts c an ac c ess the func tio ns.
Opening and closing the CD-ROM tray Take a lo o k at yo ur CD-ROM drive, fo r example. Right-c lic k the CD-ROM drive ic o n in the Explo rer windo w, and yo u see the Ejec t c o mmand (see Figure 4-7). Using it, yo u c an o pen and c lo se the CD-ROM tray witho ut having to c limb under yo ur desk and searc h fo r the butto n o n the drive.
Figure 4-7: The Explorer s upports an Eject command for CD-ROMs and ZIP drives . Yo ur sc ripts c an’t remo te c o ntro l the CD-ROM tray yet, tho ugh. Obvio usly, there needs to be so me built-in Windo ws func tio nality that o pens and c lo ses the CD-ROM tray. But ho w c an yo u ac c ess it?
126
Part I: Sc ripting Kic ks tart
■
■
The fo llo wing pro jec t is available o n the c o mpanio n CD: \components\ cdtray. Pro vided yo u have installed the VB CCE o r yo ur o wn Visual Basic , yo u just need to c o py this fo lder to yo ur hard drive and o pen the vbp-Project file. Start a new VB CCE pro jec t. Then enter the fo llo wing c o de (see Figure 4-8): Private Declare Function mciSendString Lib “winmm.DLL” Alias _ “mciSendStringA” (ByVal lpstrCommand As String, ByVal _ lpstrReturnString As String, ByVal wReturnLength As Integer, ByVal _ hCallback As Integer) As Long Sub closeTray() call mciSendString(“Set CDAudio Door Closed Wait”, 0&, 0, 0) End Sub Sub openTray() call mciSendString(“Set CDAudio Door Open Wait”, 0&, 0, 0) End Sub
This is all yo u need to remo te c o ntro l the CD-ROM tray. Befo re yo u c an c o mpile yo ur COM o bjec t, assign a new name to it. In the pro jec t windo w, c lic k the uppermo st entry (Pro jec t1). Then, assign a name to yo ur pro jec t using the name pro perty in the Pro perty windo w. Next, in the pro jec t windo w, c lic k yo ur user c o ntro l. It’s the lo west entry. Then, assign it a name using the name pro perty in the Pro perty windo w.
Figure 4-8: Wrap CD-ROM tray API functions as COM objects . Yo u do no t have to assign a name to yo ur pro jec t and yo ur user c o ntro l if yo u do n’t feel like it. Ho wever, the standard name Project1.UserControl1 is no t very thrilling. Yo u might want to c ho o se so mething yo u’ll remember. Even mo re impo rtant, using the default name fo r mo re than o ne pro jec t wo uld register o nly the last pro jec t. All the o ther pro jec ts yo u have c o mpiled previo usly wo uld no lo nger be ac c essible.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
127
■
■
Onc e yo u have assigned a name like cd.tools to yo ur pro jec t and c o ntro l, yo u c an c o mpile it. Open the file menu and c ho o se Make. Done. To remo te c o ntro l yo ur CD-ROM tray, just write a little sc ript: ‘ 4-2.VBS set tool = CreateObject(“cd.tools”) tool.openTray MsgBox “CD-ROM Tray is open!” tool.closeTray MsgBox “CD ROM Tray is closed!”
Make sure yo ur sc ript uses the c o rrec t COM o bjec t name. If yo u have c alled yo ur new COM o bjec t so mething else, c hange the ProgID that CreateObject uses. The sc ript c an no w o pen and c lo se the CD-ROM tray. Yo u c an c all the metho ds openTray and closeTray. If there is a CD-ROM in the drive, o nc e yo u o pen and c lo se the tray, an AutoPlay pro gram may start. Every time yo u insert an AutoPlayenabled CD-ROM, it auto matic ally launc hes the pro gram spec ified in the file AUTORUN.INF.
How API functions really work Ho w did yo ur COM o bjec t get ac c ess to the CD-ROM tray? It used a Windo ws API func tio n c alled mciSendString. This func tio n sends c o mmands to multimedia devic es. Yo u c an do many things with this c o mmand. Fo r example, yo u c an remo te c o ntro l VCRs o r play bac k so und files. CD-ROMs are multimedia devic es, so they are also c o ntro lled by mci. In Chapter 23, yo u will find many mo re examples and learn ho w to ac c ess multiple CD-ROM drives. To be able to use mciSendString, yo ur COM o bjec t needs to dec lare this func tio n. Dec laring a func tio n is just like teac hing Visual Basic all it needs to kno w to c all the func tio n. First, it needs to kno w ho w yo u want to refer to the c o mmand. Just pic k a name. In this example, the COM o bjec t wants to refer to the func tio n as mciSendString. Yo u c an pic k a different name if yo u like, as lo ng as yo u use this different name thro ugho ut the rest o f yo ur c o de to ac c ess the func tio n. Ho wever, when c alling API func tio ns, it’s a go o d idea to use the standard names so o thers will rec o gnize the standard API func tio ns. Next, it needs to kno w where it c an find the func tio n. The lib statement dec lares the name o f the DLL file that c o ntains the func tio n. In this example, it’s winmm.dll, and bec ause this file is sto red in o ne o f the Windo ws system fo lders, yo u do no t need to spec ify the full path name.
128
Part I: Sc ripting Kic ks tart
■
■
Then, it needs to kno w the internal name o f the func tio n. This info rmatio n is prec eded by Alias. This info rmatio n is c ruc ial, and it’s c ase-sensitive. The o ffic ial name o f the multimedia func tio n is mciSendStringA. Yo u do n’t need an Alias statement if yo u have c alled yo ur func tio n by the o ffic ial name in the first plac e. In the prec eding example, if yo u c all yo ur func tio n mciSendStringA instead o f mciSendString, then yo u c an skip the Alias statement. Be c areful, tho ugh, and remember that the o ffic ial func tio n names are c ase-sensitive. Windo ws o perating systems have two different ways o f sto ring strings. On Win9.x, strings are sto red as ANSI, using o ne byte per c harac ter. On Windo ws NT/ 2000, strings are sto red as Unic o de, using two bytes per c harac ter. To make life easy fo r yo u, mo st API func tio ns are available bo th as ANSI (“A”) and as Unic o de (“W” fo r “wide”). This example uses mciSendStringA bec ause altho ugh Visual Basic sto res strings as unic o de internally, it always c o nverts them to ANSI. Ho wever, yo u c an just as well use mciSendStringW. Then yo u wo uld have to c o nvert the c o mmand string to Unic o de, tho ugh. Take a lo o k at the fo llo wing c o de example. The impo rtant thing to keep in mind is that the “A” API func tio ns are muc h easier to handle than the “W” API func tio ns. Private Declare Function mciSendString Lib “winmm.DLL” Alias _ “mciSendStringW” (ByVal lpstrCommand As String, ByVal _ lpstrReturnString As String, ByVal wReturnLength As Integer, ByVal _ hCallback As Integer) As Long Sub closeTray() Call mciSendString(StrConv(“Set CDAudio Door Closed Wait”, _ vbUnicode), 0&, 0, 0) End Sub Sub openTray() Call mciSendString(StrConv(“Set CDAudio Door Open Wait”, _ vbUnicode), 0&, 0, 0) End Sub
In additio n, declare states whic h arguments the API func tio n expec ts to rec eive and whic h info rmatio n it returns. The declare statement is extremely po werful bec ause it impo ses virtually no restric tio ns o n yo u. It’s entirely up to yo u to define the c o mmunic atio n between Visual Basic and the API func tio n, and there is o ften mo re than o ne way yo u c an “talk” to an API func tio n. On the o ther hand, dec laring an API func tio n c o rrec tly is fundamentally impo rtant. While Visual Basic and VBSc ript safeguard eac h o f yo ur steps, this safety net do es no t apply to declare — it o pens a do o r to the ho stile “C” pro gramming wo rld, and if yo u dec lare the wro ng variable types, yo u c an easily c rash yo ur entire mac hine. So why risk brain damage trying to understand all this strange stuff at o nc e? Yo u do n’t need to . All that yo u need to ac c ess c o re Windo ws func tio nality are declare statements, and I have prepared them fo r yo u. Onc e yo u feel
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
129
■
■
c o mfo rtable with the hundreds o f examples in this bo o k, there’s still plenty o f time to dive into variable types, po inters, and all the o ther details Visual Basic usually takes c are o f fo r yo u. If yo u’re still hungry fo r mo re at the end o f this bo o k, I’ll sho w yo u ho w to ac c ess just abo ut any API func tio n by develo ping yo ur o wn dec lare statements.
Looking Inside DLL Files To fully understand the c o nc ept o f .dll files and the func tio ns sto red inside, just take a lo o k at what’s sto red inside .dll files. Mo st use a fixed struc ture c alled Mic ro so ft Po rtable Exec utable and Co mmo n Objec t File Fo rmat. Part o f this struc ture is an expo rt table. This table reveals all the names o f the sto red func tio ns. DLL stands fo r “dynamic link library”, and .dll is also the extensio n name. To find .dll files, just searc h fo r *.dll. There are hundreds o f them sto red o n yo ur c o mputer. Eac h file is ac tually a library o f predefined func tio ns. And eac h pro gram (o r sc ript) c an dynamic ally link to the library it needs fo r a spec ific purpo se. This is what makes the c o nc ept o f .dll files so po werful.
Decrypting the contents of a DLL file To peek inside .dll files, yo u just need to kno w the exac t struc ture they use to o rganize their c o ntent. The fo llo wing sc ript reveals all the hidden info rmatio n sto red in a PE-c o mpliant .dll file. It uses a COM o bjec t I develo ped to dec ipher the PE-DLL-file fo rmat (see Figure 4-9). Yo u’ll find full so urc e c o de o n the c o mpanio n CD. Just make sure yo u install the COM o bjec t o n the c o mpanio n CD befo re yo u launc h the sc ript: \install\ dll\setup.exe. ‘ 4-3.VBS
set wshshell= CreateObject(“WScript.Shell”) set dll = CreateObject(“dll.tobtools”) windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) dllname = windir & “\system\winmm.dll” set coll = dll.GetDLLFunctions(dllname) for each member in coll list = list & member & vbCr next MsgBox list
As yo u see, winmm.dll c o ntains hundreds o f func tio ns, mciSendStringA being o nly o ne o f them. Also , yo u no w see all the “A” and “W” versio ns mentio ned abo ve.
130
Part I: Sc ripting Kic ks tart
■
■
Unfo rtunately, the PE file fo rmat is no type library. It o nly c o ntains the func tio n names so the dec lare statement c an referenc e a func tio n. The .dll file do es no t c o ntain syntax info rmatio n. Yo u c an’t find o ut the arguments o r return types. If yo u find a spec ific func tio n interesting, just surf to o ne o f the Internet searc h sites like www.altavista.com and searc h fo r the func tio n name. Chanc es are yo u will find a lo t o f examples sho wing the func tio n in ac tio n. Mo st o f these examples will be written in “C” tho ugh. In o rder to use tho se examples fo r o wn COM o bjec ts, yo u will need to translate “C” into Visual Basic , whic h is no t a trivial task. Replac e “system” with “system32” if yo u are wo rking o n an NT/ 2000 system.
Figure 4-9: Uncover all the hidden functions s tored in a .dll file. To get a nic ely fo rmatted list o f expo rted func tio ns, yo u c an easily spic e up this sc ript and have it o utput the info rmatio n as an HTML file: ‘ 4-4.VBS set wshshell = CreateObject(“WScript.Shell”) windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) dllfile = windir & “\system\winmm.dll” outputfile = “C:\dll.htm” GetDLLInfo dllfile, outputfile wshshell.run “IEXPLORE.EXE “ & outputfile sub GetDllInfo(dllname, outputname) set dll = CreateObject(“dll.tobtools”) set coll = dll.GetDLLFunctions(dllname)
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
131
■
■
set fs = CreateObject(“Scripting.FileSystemObject”) set output = fs.CreateTextFile(outputname, true) dim colors(1) colors(0)=” bgcolor=””#EEEEEE””” colors(1)=” bgcolor=””#DDDDDD””” output.WriteLine “” output.WriteLine “
” _ & fs.GetBaseName(dllname) & “
” & coll.Count _ & “ functions
” for each name in coll counter = counter + 1 output.WriteLine “
” _ & name & “
” & coll(name) & “
” next output.WriteLine “
” output.close end sub
The list c o ntains the name and the o rdinal number o f eac h .dll func tio n that is ac c essible. Ac tually, the o rdinal number is the impo rtant part. The o rdinal number is the real name o f a func tio n. Whenever yo u c all a .dll func tio n by name, Windo ws lo o ks up the name in the expo rt list and translates it to the o rdinal number. Then it lo o ks up the base o ffset and kno ws at whic h byte po sitio n in the .dll file the func tio n c o de starts. Yo u c an c all a .dll func tio n direc tly by o rdinal number, to o . Instead o f the name, just use a # and then the o rdinal number. Instead o f mciSendStringA, yo u c o uld just as well write #52. If yo u did, yo ur COM o bjec t wo uldn’t wo rk o n Windo ws 2000 systems anymo re, tho ugh. Here, mciSendStringA has a different o rdinal number. By using the func tio n names, yo u leave it to the o perating system to determine the c o rrec t o rdinal number. Ho wever, there are times when yo u must use the o rdinal number. Undo c umented Windo ws func tio ns have no text entry so yo u c an’t c all tho se func tio ns by name. Yo u c an o nly ac c ess these func tio ns thro ugh the o rdinal number. Bec ause o rdinal numbers are c o nsec utive, just take a lo o k at yo ur .dll func tio n list. If there are any o rdinal numbers missing, yo u c an safely assume that these o rdinal numbers represent undo c umented hidden Windo ws features. So me .dlls do n’t c o ntain any, while o thers c o ntain mo stly undo c umented func tio ns.
Developing Dialog Boxes So far, yo ur COM o bjec ts have c o ntained c o mmands o nly. COM o bjec ts c an do a lo t mo re, tho ugh. If yo u want to , they c an also po p up dialo g windo ws fo r yo u. And bec ause yo u are free to design the windo w c o ntent, yo u c an easily c reate all the dialo g bo xes yo u might need fo r a spec ial pro jec t.
132
Part I: Sc ripting Kic ks tart
■
■
Many autho rs are c o nvinc ed that an Ac tiveX c o ntro l c an’t o pen a windo w. Instead, they believe Ac tiveX c o ntro ls c an o nly bec o me visible as an embedded o bjec t o n a Web page. This is definitely wro ng. Altho ugh Ac tiveX c o ntro ls were o riginally designed as Web page add-o ns, they c an also po p up regular windo ws. There are o nly two things yo u need to kno w to make this wo rk. One, the user c o ntro l itself c an o nly be embedded o n Web pages, but if yo u add fo rms to yo ur pro jec t, yo u c an view tho se as windo ws. And two , bec ause Ac tiveX c o ntro ls are no t independent pro grams, they c an’t o pen mo deless windo ws. This means they c an’t o pen mo re than o ne windo w at a time, and while the windo w is displayed, yo ur sc ript sto ps. Ho wever, even this limitatio n c an be o verc o me. In Chapter 17, I’ll sho w yo u ho w to use events to turn mo dal windo ws into mo deless windo ws. Start the VB CCE and c reate a new pro jec t. Next, assign a name to bo th yo ur pro jec t and yo ur UserControl as o utlined abo ve. Call it dialog.test. No w yo u c an start develo ping yo ur dialo g bo x.
Designing a form Visual Basic c alls dialo g windo ws fo rms. In o rder to develo p a COM func tio n that po ps up a windo w, yo u just design a fo rm. In the main windo w, yo u see yo ur user c o ntro l. Mo st likely, it lo o ks like a gray square. Ho wever, this user c o ntro l c an never ac t as a dialo g windo w. User c o ntro ls are always invisible and c an o nly appear as part o f a Web page. To c reate a real windo w, yo u need to add a fo rm to yo ur pro jec t. In the Pro jec t windo w, right-c lic k o n yo ur pro jec t, then c ho o se Add and Fo rm. The Add Fo rm windo w appears. Clic k Open. Yo u no w get a new fo rm. It appears in yo ur pro jec t windo w and lo o ks like a gray, empty windo w. This is yo ur dialo g windo w. In o rder to design it, yo u just o pen the To o lbo x windo w — o pen the View menu and selec t To o lbo x. Always make sure yo u are wo rking with the fo rm. The user c o ntro l lo o ks just the same. If in do ubt, take a lo o k at yo ur Pro jec t windo w and c lic k yo ur fo rm. The To o lbo x windo w c o ntains the design elements. To plac e a design element o n yo ur windo w, just do uble-c lic k it in the To o lbo x windo w. It appears o n yo ur fo rm. No w yo u c an drag it to the c o rrec t po sitio n and adjust its size. The c o mplete InputBox pro jec t is also available o n the CD-ROM. Just o pen \components\inputbox\dialog.vbp. Yo u c an also install the pre-c o mpiled pro jec t: \install\inputbox\setup.exe. Let’s assume yo u want to design a new input bo x. Yo u need a label and a text field. Do uble-c lic k o n bo th elements, then po sitio n the elements. If yo u feel like it, yo u c an also add a frame. In additio n, yo u need a butto n element so the user c an c lo se the dialo g bo x.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
133
■
■
Selecting the right elements Putting to gether the elements is easy o nc e yo u kno w so me tric ks: ■ Do uble-c lic k elements in the To o lbo x windo w to plac e a c o py o n yo ur
fo rm. Yo u c an’t drag elements o nto yo ur fo rm. Onc e the elements are plac ed o n yo ur fo rm, yo u c an drag them into po sitio n and c hange sizes. ■ Having tro uble selec ting an element? Take a lo o k at the Pro perties
windo w. It spo rts a dro p-do wn list. Just selec t the element in this list, and it will be selec ted o n the fo rm as well. ■ So me elements ac t like c o ntainers. The frame element is a c o ntainer. Yo u
need to plac e elements into the frame; o therwise, the frame will c o ver them. To plac e elements into the frame, selec t the element and then c ut it to the c lipbo ard using [Ctrl]+[X]. Next, selec t the frame and insert the element using [Ctrl]+[V]. Next, explo re the pro perties o f yo ur elements. Selec t the element o n the fo rm and see whic h pro perties the Pro perties windo w has to o ffer. Fo r example, c hange the label o f the frame. Mo st elements o ffer the c aptio n pro perty. To c hange the c aptio n o f yo ur butto n, c lic k the butto n o n the fo rm, then switc h to the Pro perties windo w and c hange the c aptio n pro perty. Yo u c an even assign keybo ard sho rtc uts to yo ur elements. Just insert the & c harac ter into yo ur c aptio n. Windo ws auto matic ally underlines the fo llo wing c harac ter and uses it as a keybo ard sho rtc ut. To use “ O” as a sho rtc ut fo r OK, write &OK. Every element yo u plac e o n yo ur fo rm has a name pro perty. This pro perty is very impo rtant bec ause yo u need it to ac c ess the element fro m yo ur pro gram c o de. Either write do wn the standard element names fo r referenc e o nc e yo u develo p the lo gic behind yo ur dialo g windo w o r assign yo ur o wn names to the elements. Yo u sho uld play aro und with the elements and pro perties available. One o f the first “serio us” things yo u need to do , tho ugh, is assign a name to yo ur fo rm. To do so , in the Pro jec t windo w, c lic k yo ur fo rm and then switc h to t he Pro perties windo w. In the dro p-do wn list o f elements, c ho o se the fo rm. Then assign it a name using the name pro perty. In this example, c all yo ur fo rm windo w1.
Choosing the right element order Yo u c an plac e as many elements o n yo ur fo rm as yo u want. As so o n as elements start to o verlap, tho ugh, things bec o me tric ky. Yo u no w need to spec ify the element in o rder to make sure that elements do n’t bury o ther elements under them. To c hange the o rder o f elements and determine whic h o nes are o n to p o f o thers, yo u first selec t the element yo u want to mo ve up o r do wn in the pile.
134
Part I: Sc ripting Kic ks tart
■
■
If yo u c an’t c lic k the element, then use the dro p-do wn list in the Pro perties windo w. Next, yo u o pen the Fo rmat menu and c ho o se Order. No w yo u c an mo ve the selec ted element up o r do wn.
Compiling your COM object Yo u have designed yo ur fo rm? Great! Just assign a name to bo th yo ur pro jec t and yo ur UserControl, as sho wn abo ve. Call yo ur pro jec t dialo g and yo ur UserControl test. Next, c o mpile yo ur COM o bjec t — o pen the File menu and c ho o se Make dialog.ocx. Sho uld yo ur Make c o mmand repo rt a name o ther than dialog.ocx, then yo u pro bably did no t assign names to yo ur pro jec t and yo ur UserControl yet. It’s easy; just fo llo w the rules abo ve. Using names o ther than tho se I rec o mmended will c ause tro uble bec ause the sample sc ripts expec t yo ur COM o bjec t to be named dialog.test. No w it’s time to test yo ur COM o bjec t. Open the text edito r and save the fo llo wing file with the .vbs extensio n: ‘ 4-5.VBS set dialog = CreateObject(“dialog.test”) MsgBox “Done.”
Pro vided yo u have c alled yo ur COM o bjec t dialog.test, yo ur sc ript will run perfec tly well, and no erro r will be raised. Ho wever, yo u sho uld no te that yo ur windo w did no t appear either. Initially, all fo rms are invisible. To sho w yo ur dialo g windo w, yo u need to explic itly c all it. So , switc h bac k to yo ur pro jec t and add so me c o de.
Adding code to make your window appear Yo ur COM o bjec t needs an additio nal metho d that yo u c an c all to sho w yo ur windo w. All the public metho ds that are visible fro m the o utside live inside yo ur user c o ntro l. So take a lo o k at yo ur Pro jec t windo w and right-c lic k o n yo ur user c o ntro l. It’s lo c ated inside the User Co ntro ls fo lder. In the c o ntext menu, c ho o se View Co de. Yo ur user c o ntro l is c o mpletely empty (see Figure 4-10). Add the fo llo wing pro c edure: sub ShowWindow() window1.Show vbModal end sub
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
135
■
■
Figure 4-10: “In-proces s ” COM objects can only dis play modal dialog w indow s . Yo ur new pro c edure c alls the Show metho d that’s built into any fo rm. Bec ause Show is supplied by yo ur fo rm, yo u need to also supply the name o f the fo rm. This is no thing new — in o rder to c all a metho d, always spec ify the name o f the o bjec t first. Fo r the pro c edure to wo rk c o rrec tly, yo u have to name yo ur fo rm windo w1. If yo u have named yo ur fo rm differently, then use that name instead. If yo u haven’t named yo ur fo rm at all, then yo ur fo rm’s default name is Fo rm1. Next, rec o mpile yo ur COM o bjec t — o pen the File menu and c ho o se Make dialog.ocx. Yo u c an’t rec o mpile yo ur COM o bjec t while it is in use. Always make sure yo u have sto pped any sc ript that ac c esses yo ur o bjec t. Right no w, this is pro bably o f no c o nc ern. Onc e yo ur sc ript is able to o pen yo ur dialo g windo w, ho wever, yo u need to make sure that yo ur dialo g windo w is c lo sed befo re yo u rec o mpile yo ur o bjec t. Bec ause yo ur dialo g windo w c an be hidden behind o ther windo ws, press [Win]+[M] to see all o pen dialo g windo ws. Also , while yo ur sc ript is exec uted in the Sc ript Debugger, yo ur o bjec t is c o nsidered to be in use. Clo se the Sc ript Debugger befo re yo u rec o mpile yo ur o bjec t. No w yo u just need to c all the new metho d to o pen yo ur windo w. Change yo ur sc ript ac c o rdingly: ‘ 4-6.VBS set dialog = CreateObject(“dialog.test”) dialog.ShowWindow MsgBox “Done.”
It wo rks. Yo ur windo w appears exac tly the way yo u designed it.
136
Part I: Sc ripting Kic ks tart
■
■
The elements yo u plac ed o n yo ur fo rm may wo rk, but they are no t really func tio nal. Fo r example, if yo u c lic k the butto n, no thing exc iting happens. No wo nder — so far, yo u have o nly designed the windo w layo ut. Yo u haven’t yet defined any lo gic . Onc e yo u c lo se the windo w, yo ur sc ript c o ntinues and displays the MsgBox message. Yo ur COM o bjec t c an’t sho w mo deless windo ws. Onc e yo u c all a fo rm’s Show metho d, yo u rec eive an erro r message. This is why many peo ple believe Ac tiveX c o ntro ls c an’t sho w windo ws. They c an. Ho wever, they’re limited to mo dal windo ws, so yo u need to supply the vbModal parameter. Mo dal windo ws halt sc ript exec utio n fo r as lo ng as the windo w is displayed, and this is also the reaso n why yo u c an o nly o pen o ne windo w at a time.
Adding code to make your window do something So far, yo u c an make yo ur dialo g windo w appear, but the windo w isn’t really useful. Just add so me c o de to yo ur fo rm to educ ate it. Switc h bac k to yo ur VB CCE pro jec t. Bec ause yo u want to add func tio nality to yo ur fo rm, take a lo o k at yo ur Pro jec t windo w and right-c lic k o n yo ur fo rm. It’s lo c ated in the Fo rms fo lder. In the c o ntext menu, c ho o se View Objec t. No w yo u see yo ur windo w in design mo de. First, yo u want to add c o de to the OK butto n so the windo w is c lo sed o nc e so meo ne c lic ks this butto n. Do uble-c lic k o n the butto n. The windo w c hanges its appearanc e, and no w yo u see the fo rms’ Co de view. Yo u c o uld have switc hed to this view by right-c lic king o n the fo rm and c ho o sing View Co de, but by do uble-c lic king the butto n element, Visual Basic auto matic ally adds the appro priate pro c edure framewo rk (see Figure 4-11). Visual Basic adds a sub pro c edure. This new pro c edure is spec ial. Yo u do n’t need to c all it. It will be auto matic ally c alled whenever so meo ne c lic ks the butto n. And what makes it spec ial? Its name. The name starts with the name o f the element it will be respo nsible fo r. In the c ase o f the butto n, the pro c edure name will start with Co mmand1, the default name o f the butto n. If yo u have c hanged the butto n’s name, the pro c edure name will start with the name yo u c ho se fo r the butto n element. Next, there is an undersc o re. After the undersc o re, yo u will see Click. Command1_Click() translates into “exec ute this pro c edure whenever the element Command1 raises the Click-event.” There are many events an element c an respo nd to . Abo ve yo ur Co de view, yo u will see two dro p-do wn lists. The left list c o ntains all available elements o n yo ur fo rm, while the right list reveals all the events this element c an po ssibly respo nd to . Press [Esc ] to c lo se the list. If yo u want to insert c o de that exec utes o nc e so meo ne presses a butto n, yo u simply c ho o se the MouseDown event. The Click event, in c o ntrast, is raised o nly after so meo ne has released the mo use butto n while the mo use po inter is lo c ated o ver the element.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
137
■
■
Figure 4-11: Add event handlers to your dialog box to res pond to button clicks . In o rder to c lo se the dialo g windo w, yo ur pro c edure needs to c all the appro priate metho d o f the fo rm. Yo u c an either unlo ad the fo rm fro m memo ry o r hide the fo rm. Unlo ading the fo rm fro m memo ry is the better alternative fo r dialo g windo ws. Hide windo ws o nly if yo u plan to make the windo w invisible tempo rarily. If yo u hide a windo w and c all Show vbModal at a later time, the exac t same windo w will reappear. Anything yo u have typed into the windo w previo usly will still be there. If yo u unlo ad a windo w and then c all Show vbModal later, yo u get a new instanc e o f the windo w. It will no t c o ntain o ld data. Hiding a windo w will keep it in memo ry until yo ur sc ript ends o r until yo u explic itly c lo se the c o nnec tio n to yo ur COM o bjec t by assigning Nothing to yo ur o bjec t referenc e. To c lo se the windo w, add this pro c edure to yo ur fo rm: Private Sub Command1_Click() Unload me end sub
To hide the windo w, add this pro c edure: Private Sub Command1_Click() me.Hide end sub
me is a spec ial referenc e to the c urrent o bjec t. Bec ause yo ur pro c edure is lo c ated inside the fo rm, me represents the fo rm. Yo u c an no w either use the Unload func tio n o r pro vide me as an argument. Bec ause Unload is a func tio n pro vided by yo ur COM o bjec t, yo u c an use it direc tly. Alternatively, yo u c an c all the Hide metho d, whic h is built into yo ur fo rm. Here, yo u use me as an o bjec t referenc e. Instead o f me, yo u c an also use the o ffic ial name o f the fo rm.
138
Part I: Sc ripting Kic ks tart
■
■
Rec o mpile yo ur COM o bjec t and then run yo ur sc ript c o de. This time, yo u c an c lo se the dialo g windo w by c lic king the butto n. This is go o d, but no t go o d eno ugh. Ho w c an yo u read what the user has typed into the dialo g windo w? It’s easy. Everything the user types in will be sto red in the element Text1. (It c an have a different name if yo u renamed it.) To return the input to yo ur sc ript, yo u need to sto re this text into a glo bal variable just befo re yo u c lo se the windo w. So , switc h to the Pro jec t windo w and do uble-c lic k o n yo ur fo rm. Yo u see yo ur dialo g windo w. Do uble-c lic k o n the OK butto n. No w yo u see the pro c edure that gets exec uted o nc e so meo ne c lic ks the butto n. Befo re yo u allo w yo ur pro c edure to unlo ad the windo w, yo u read the c o ntents o f the Text1 element into a glo bal variable. This way, the user input is still aro und when the windo w is c lo sed: Public enteredText as String Private Sub Command1_Click() enteredText = Me.Text1 Unload Me End Sub
No w, when so meo ne c lic ks the butto n, yo ur pro c edure first sto res the c o ntents o f Text1 into the string variable enteredText. Then the windo w is c lo sed. To be able to read the variable enteredText fro m o ther pro c edures, yo u just dec lare the variable as glo bal using the Public key wo rd (see Figure 4-12).
Figure 4-12: To automatically clos e the w indow, hide it or unload it from memory.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
139
■
■
Next, yo u return the variable to yo ur sc ript. In the Pro jec t windo w, right-c lic k o n yo ur user c o ntro l and c ho o se View c o de. Then c hange yo ur ShowWindow pro c edure to a func tio n bec ause yo u want to return so mething — replac e sub with func tio n. No w yo u just need to define the return value. Assign a value to the variable ShowWindow, then use the variable enteredText, whic h is part o f the fo rm. In do ing so , spec ify the name o f yo ur fo rm and then the name o f the variable. That’s all, and altho ugh it seems a little c o mplex, it is very straightfo rward. Again, there is o nly o ne thing yo u need to remember — always spec ify the o bjec t yo u want to talk to . Bec ause it’s the fo rm that sto res the enteredText variable, talk to the fo rm when retrieving the variable. To use yo ur new func tio nality, c hange yo ur sc ript ac c o rdingly: ‘ 4-7.VBS set dialog = CreateObject(“dialog.test”) MsgBox dialog.ShowWindow MsgBox “Done.”
This time, dialog.ShowWindow o pens the windo w and returns whatever the user has typed in (see Figure 4-13).
Figure 4-13: Your w indow reports entered text back to your s cript. Maybe there’s default text in the text bo x Text1. To start with an empty text bo x, just selec t yo ur fo rm in the Pro jec t windo w and selec t yo ur text-bo x element in the Pro perties’ windo w dro p-do wn bo x. Then lo o k fo r the text pro perty and delete its default text.
Using Properties to Change Your Window’s Behavior So far, yo u have wo rked with func tio ns and pro c edures. Bo th make yo ur COM o bjec t do so mething, and func tio ns c an return values. There’s a third element yo u c an use — pro perties. Pro perties do n’t start ac tio n. They just c o ntro l parameters.
140
Part I: Sc ripting Kic ks tart
■
■
Take a lo o k at yo ur dialo g windo w. There are many aspec ts yo u pro bably wo uld like to c o ntro l. First o f all, it wo uld definitely be go o d to be able to set the label text fo r bo th the frame and the label so yo u c an ask questio ns. Yo u c an set this label text using the c aptio n pro perty o f the elements fro m within the COM o bjec t, but hard-c o ding tho se pro perties do esn’t make muc h sense. Yo u want yo ur sc ript to be able to ask any questio n. If yo u want to be able to do that, just define so me pro perties. In the VB CCE pro jec t, switc h to the Pro jec t windo w and right-c lic k yo ur user c o ntro l. In the c o ntext menu, c ho o se View c o de.
Accessing your element’s properties The Pro perties windo w lists all the pro perties a spec ific o bjec t o ffers. Just selec t the element in the dro p-do wn list, and yo u c an see all the pro perties available. The Pro perties windo w is a c o nvenient to o l fo r setting pro perties during design-time. Ho wever, yo u need ano ther way o f ac c essing the pro perties if yo u c ho o se to c hange pro perties during run-time. Yo u c an ac c ess any o bjec t pro perty by c o de. Let’s assume yo u have plac ed a frame element o n yo ur fo rm and this element’s name pro perty is Frame1. To c hange the label, yo u need to c hange the c aptio n pro perty o f the Frame1 o bjec t: Frame1.Caption = “New Label”
Bec ause the Frame1 o bjec t is lo c ated o n yo ur fo rm, and assuming yo ur fo rm is c alled window1, yo u wo uld write: window1.Frame1.Caption = “New Label”
Making properties accessible from the outside Yo u no w kno w ho w to c hange pro perties during run-time. Ho wever, yo u c an o nly ac c ess yo ur elements’ pro perties fro m within yo ur COM o bjec t. Yo ur sc ript c an’t ac c ess the internal pro perties. No t yet. To be able to c hange pro perties fro m the o utside, yo u just need to “publish” the pro perty in exac tly the same way yo u already used to “publish” func tio ns and pro c edures. Instead o f func tio n and sub, this time yo u use the keywo rd Property. Add the fo llo wing lines to yo ur user c o ntro l c o de: Property Let Label(ByVal text As String) window1.Label1.Caption = text End Property Property Let Frame(ByVal text As String) window1.Frame1.Caption = text End Property
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
141
■
■
Property Let Default(ByVal text As String) window1.Text1.text = text End Property
No w yo ur sc ript c an c o ntro l label text, frame text, and the default text in the text bo x: ‘ 4-8.VBS set dialog = CreateObject(“dialog.test”) dialog.Frame = “Question” dialog.Label = “Enter something!” dialog.Default = “This is the default!” MsgBox dialog.ShowWindow MsgBox “Done.”
Property Let defines a write-o nly pro perty. Yo u c an assign values to this pro perty, but yo u c an’t read the c urrent c o ntent. Property Get defines a read-o nly pro perty. Yo u c an’t set its value, but yo u c an read it. To implement a read/ write pro perty, yo u use bo th Property Let and Property Get.
Using Optional Parameters Pro perties are great, but they require additio nal lines o f c o de. Take a lo o k at the o ffic ial InputBox func tio n. This func tio n do esn’t expo se pro perties. Still, yo u are able to supply additio nal arguments if yo u want to . Yo u do n’t need to . Mo st arguments are o ptio nal: ‘ 4-9.VBS text = InputBox(“Enter something!”) text = InputBox(“Enter something!”, “Titlebar Text”) text = InputBox(“Enter something!”, “Titlebar Text”, “The Default”)
Can yo ur dialo g bo x use o ptio nal arguments, to o ? Yes. Just c hange yo ur ShowWindow func tio n to inc lude the o ptio nal parameters: Function ShowWindow(ByVal question As String, _ Optional ByVal frametext As String = “Question”, _ Optional ByVal titletext As String, _ Optional ByVal defaulttext As String = “”) As String window1.Label1.Caption = question window1.Frame1.Caption = frametext window1.Text1.text = defaulttext If Not IsMissing(titletext) Then window1.Caption = titletext End If window1.Show vbModal ShowWindow = window1.enteredText End Function
142
Part I: Sc ripting Kic ks tart
■
■
Onc e yo u c o mpile yo ur COM o bjec t, yo u c an c all yo ur dialo g windo w using a number o f alternatives: ‘ 4-10.VBS set dialog = CreateObject(“dialog.test”) MsgBox dialog.ShowWindow(“Enter something!”) MsgBox dialog.ShowWindow(“Enter something!”, “May I ask?”) MsgBox dialog.ShowWindow(“Enter something!”, “May I ask?”,,”Default!”) MsgBox dialog.ShowWindow(“Enter something!”, “May I ask?”, _ “Titlebar under control”, “Default!”) MsgBox “Done.”
Only the first argument is mandato ry. The fo llo wing three arguments are o ptio nal. Yo u c an o mit them, but yo u c an’t c hange their o rder. If yo u do n’t want to spec ify an argument, just leave it blank.
Specifying default values To make an argument o ptio nal, yo u use the o ptio nal key wo rd. Onc e yo u dec lare an argument as o ptio nal, yo u c an’t add mandato ry arguments. Mandato ry arguments must be dec lared befo re yo u start dec laring yo ur o ptio nal arguments. Take a lo o k at the arguments frametext and defaulttext. Bo th are o ptio nal, and bo th rec eive a default value sho uld they be o mitted.
Detecting missing arguments titletext wo rks differently. There is no default value defined, and if the user o mits this argument, titletext is undefined. To c hec k whether an argument was spec ified o r no t, just ask isMissing. This func tio n returns true if the argument was o mitted. In the example, isMissing determines whether the user spec ified an argument fo r titletext. If an argument was spec ified, it c hanges the fo rm’s title bar text. If the argument is missing, it do esn’t c hange the title bar text.
Uncovering Special Window Properties Yo u no w kno w muc h abo ut the inside mec hanic s o f dialo g windo ws. All o f what yo u have do ne so far happens inside the windo w, tho ugh. The windo w is just the c o ntainer fo r all yo ur elements and yo ur c o de. It’s a go o d idea to also take a lo o k at the windo w c o ntainer itself. This c o ntainer o ffers many useful pro perties yo u may want to use fo r yo ur dialo g windo w pro jec t.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
143
■
■
To ac c ess these pro perties, c lic k o n yo ur fo rm in the Pro jec t windo w. Then take a lo o k at the Pro perties windo w. Selec t yo ur Fo rm in the dro p-do wn list.
Changing the colors BackColor sets the bac kgro und c o lo r o f yo ur fo rm. Yo u do n’t need to use gray dialo g windo ws. Yo u c an even make them blue o r yello w if yo u like. Ho wever, yo u will also need to set the BackColor pro perty o f elements yo u plac ed o n yo ur fo rm.
Non-resizable windows BorderStyle presents a ric h set o f windo w bo rder settings. By default, Visual Basic uses the sizable windo w bo rder. The user c an resize yo ur dialo g windo w, and if yo u didn’t pro vide the appro priate sizing mec hanisms, the windo w will bec o me larger but yo ur elements will stay where they were. I’ll sho w yo u mo re abo ut sizing in a mo ment, but in mo st c ases, it do esn’t make sense to resize dialo g bo xes anyway. Selec t Fixed Dialo g to get a no nresizable dialo g windo w frame. MaxButton c o ntro ls whether yo ur windo w displays a maximize butto n in its title bar. This setting has an effec t o nly if the windo w is resizable. MinButton c o ntro ls the minimize butto n. If yo u set Movable to false, then yo ur dialo g windo w c an no lo nger be dragged. Yo u c an ac hieve the same effec t by hiding the title bar (see the fo llo wing sec tio n).
Special dialog windows As a default, yo ur windo ws lo o k like regular windo ws. They have a title bar and share the same 3D lo o k yo u are used to fro m o ther so ftware. If yo u want to , yo u c an c o mpletely c hange this lo o k and feel. Just c hange ControlBox to false. No w yo ur windo w has no title bar anymo re (see Figure 4-14), and if yo u selec t Fixed To o lWindo w as Bo rderStyle, yo u will even lo se the 3D effec t.
Figure 4-14: Strip off your dialog box title bar.
144
Part I: Sc ripting Kic ks tart
■
■
If yo u spec ify c aptio n text fo r the fo rm, yo u will get a title bar even if yo u turned o ff ControlBox.
Positioning windows in the center of the screen Many pro grammers plac e a lo t o f c usto m c o de into their COM o bjec ts just to make a windo w appear c entered o n the sc reen. It’s a go o d idea to c enter dialo g windo ws so they c atc h attentio n. Ho wever, yo u do n’t need extra c o de fo r this. Just set StartUpPosition to CenterScreen. This will take c are o f everything. As a default, Visual Basic uses Windo ws Default. With this setting, eac h new windo w is plac ed o n the sc reen using a small o ffset fro m the po sitio n o f the previo usly o pened windo w. Windo ws Default is best when yo u plan to o pen a number o f windo ws, so the windo ws do n’t c o mpletely o verlap. Bec ause yo u c an’t o pen multiple windo ws anyway fro m within an Ac tiveX c o ntro l, yo u are better o ff using CenterScreen.
Implementing Special Window Behavior Yo u c an no w c o ntro l bo th the inside and the o utside o f yo ur windo w. So metimes, ho wever, it may bec o me nec essary to c o ntro l the way Windo ws treats yo ur windo w. Fo r example, if yo ur sc ript has launc hed ano ther pro gram o r used ano ther COM o bjec t, then this pro gram gets the fo c us and yo ur sc ript lo o ses the fo c us. Any c usto m windo w yo u o pen afterwards may no t appear o n the sc reen. Instead, it may appear hidden underneath o ther windo ws. This is bad. But luc kily, there are ways yo u c an c hange this — and a lo t o f o ther things that may ruin yo ur day at first.
Resizing the contents of your window Default windo ws are resizable. Unfo rtunately, Windo ws o nly resizes the windo w, no t its c o ntents. If yo u resize yo ur dialo g windo w, it will bec o me larger, but yo ur elements inside o f the windo w stay where they are. The easiest way to deal with this is to turn o ff the resize c apability alto gether. This way, yo u do n’t have to deal with it. Just set the BorderStyle pro perty to a fixed bo rder, as o utlined abo ve. While this may wo rk perfec tly well fo r c ertain dialo g windo ws, it may limit the fun in o ther c ases. The InputBox func tio n, fo r example, takes the easy ro ute and do esn’t allo w resizing. That’s to o bad bec ause it wo uld be nic e to enlarge the dialo g windo w fo r additio nal spac e.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
145
■
■
To make yo ur windo w c o ntent resizable, yo u need to reac t to the fo rm’s resize event. This event is triggered anytime the size o f the windo w is c hanged. The fo rm’s resize event will be triggered at least o nc e — the mo ment yo u display yo ur fo rm. So if yo u pro vide a resize pro c edure, yo u no lo nger need to spec ify the height and width o f yo ur fo rm’s elements. Do n’t spend ho urs trying to align fo rm elements during design-time. The elements will be straightened o ut by yo ur resize pro c edure anyway. The tric ky part is to respo nd to this event. Yo u will have to manually resize all the elements o n yo ur fo rm. This is no t a trivial thing. Take a lo o k at the fo llo wing pro c edure. It will resize all the elements o f yo ur new InputBox dialo g windo w: Private Sub Form_Resize() Const OFFSET = 100 Dim frmRealWidth As Integer Dim frmRealHeight As Integer On Error Resume Next frmRealWidth = Me.ScaleWidth frmRealHeight = Me.ScaleHeight Me.Frame1.Move OFFSET, OFFSET, frmRealWidth - 2 * OFFSET, _ frmRealHeight - 3 * OFFSET - Me.Command1.Height Me.Label1.Move OFFSET, 2 * OFFSET, _ Me.Frame1.Width - 2 * OFFSET, 300 Me.Text1.Move OFFSET, 3 * OFFSET + Me.Label1.Height, _ Me.Frame1.Width - 2 * OFFSET, _ Me.Frame1.Height - Me.Label1.Height - 4 * OFFSET Me.Command1.Move frmRealWidth - OFFSET - Me.Command1.Width, _ 2 * OFFSET + Me.Frame1.Height End Sub
Fo r this to wo rk, yo u need to plac e this pro c edure into yo ur fo rm. Right-c lic k yo ur fo rm in the Pro jec t windo w, then c ho o se View Co de. Next, c ho o se Fo rm in the left dro p-do wn list and c ho o se Resize in the right dro p-do wn list. To be able to resize the windo w c o ntents, yo ur pro c edure needs to kno w the new size o f the windo w. ScaleWidth and ScaleHeight pro vide this info rmatio n. Next, the pro c edure mo ves the fo ur elements o n the fo rm. This is the rather abstrac t part. The c o nstant OFFSET determines the spac e between the elements.
146
Part I: Sc ripting Kic ks tart
■
■
Mo ving the elements in respo nse to the resize event is a dynamic pro c ess. Yo u do n’t want to use fixed sizes. Instead, always refer to the new windo w dimensio ns sto red in frmRealWidth and frmRealHeight. In additio n, yo u c an use the height and width info rmatio n o f tho se elements yo u already resized. Use fixed sizes o nly fo r tho se elements yo u do no t want to sc ale. In the example, the Label1 element rec eives a fixed height o f 300 bec ause it do esn’t make sense to dynamic ally sc ale the label text. Also , use me rather than the real name o f yo ur fo rm. This way, yo u c an c ut and paste yo ur resize pro c edure and reuse it in o ther fo rms with o nly mino r adjustments. Yo ur key to resizing maneuvers is the Move metho d. Move c an be c alled fo r any fo rm element. It ac c epts fo ur parameters — left, to p, width, and height. Yo u o nly need to spec ify two if yo u do n’t want to c hange the size o f the element. In the example, the Co mmand1 c o mmand butto n is mo ved this way, but it is no t resized. Elements c an be parts o f o ther elements. In this example, bo th Label1 and Text1 are embedded in the Frame1 element. When using Move o n Label1 and Text1, yo u need to spec ify the dimensio ns relative to the Frame1 dimensio ns. Take a lo o k at the Command1 element. Yo u want to mo ve it so it aligns at the right side o f the windo w. Lo o k at the first parameter c alc ulatio n. The entire width o f the windo w ( frmRealWidth) minus the windo w margin ( offset), minus the width o f the c o mmand butto n itself, results in the left ( starting) po sitio n o f the c o mmand butto n. If yo u wanted to align the butto n o n the left side, then yo u wo uld replac e all o f this with offset. Auto mating the po sitio ning o f all yo ur fo rm elements is rather abstrac t. Do n’t feel bad if yo ur resize algo rithm do esn’t wo rk at first. It’s almo st no rmal if yo ur resizing pro c edure plac es the fo rm elements all o ver the plac e at first. Start with a simple fo rm and o nly a few elements. Trial-and-erro r is so metimes the best way to go . Ho wever, always try to keep yo ur algo rithm as simple as po ssible. Use c o nstants like offset fo r windo w margins and to define the distanc e between the elements. Yo u may be wo ndering why the pro c edure turns o ff erro r handling. This is just a simplific atio n. A windo w c an be shrunk as well as enlarged, and whenever yo ur windo w bec o mes to o small to display all the elements inside, Visual Basic raises an erro r. To prevent this erro r, yo u have to do uble-c hec k whether yo ur windo w size is to o small fo r additio nal resizing. Turning o ff erro r handling do esn’t so lve the c ause, but it prevents the erro r. If yo ur windo w bec o mes to o small, then yo ur fo rm elements will start to o verlap, and users will get immediate feedbac k, fo rc ing them to re-enlarge the windo w. If yo u plan to o pen yo ur windo w mo re than o nc e, yo u sho uld hide it instead o f unlo ading it fro m memo ry. Hiding a windo w preserves its c urrent size. If yo u unlo ad the windo w, it will always po p up with the predefined size, and yo ur users may no t like to resize it again and again. Ho wever, when hiding a windo w, always make sure yo u initialize all the impo rtant variables eac h time yo u sho w the windo w. The example in this c hapter always resets the label texts and text bo x values as part o f the ShowWindow pro c edure. This way, yo u always get an empty text bo x even if yo u have used the windo w befo re.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
147
■
■
Preselecting window elements The main purpo se o f yo ur COM o bjec t is to present a windo w fo r input. So , it makes a lo t o f sense to preselec t the text bo x element. This way, yo u c an start typing in text right away. Yo u do n’t need to grab the mo use first and c lic k into the text bo x element. To preselec t the text bo x, just plac e o ne mo re line into yo ur resize pro c edure: me.text1.SetFocus
Responding to the [Enter] key The o ffic ial InputBox c an do so mething yo ur COM o bjec t c an’t — o nc e the user has finished his input and presses [Enter], the windo w auto matic ally c lo ses. There is no need to grab the mo use and c lic k OK. Yo u c an implement the same servic e, to o . All yo u need to do is sc an the key c o des entered into the text bo x. This is easy bec ause every key pressed raises the KeyPress event. Sho uld yo u detec t c o de 13, then yo u kno w that the [Enter] key was pressed: Sub Text1_KeyPress(KeyAscii As Integer) If KeyAscii = 13 Then DoEvents enteredText = Me.Text1 Me.Hide End If End Sub
Just plac e this pro c edure o n yo ur fo rm. Anytime the user presses [Enter] inside the text bo x element, KeyAscii repo rts c o de 13. DoEvents c o mpletes the event pro c essing, and then the pro c edure exec utes the same steps as the c lic k-pro c edure o f yo ur OK butto n. In fac t, instead o f repeating the c o mmands bo th in this pro c edure and in the Click pro c edure respo nsible fo r yo ur OK butto n, it wo uld be mo re mo dular to plac e the exit c o mmands into a separate sub and c all this sub fro m bo th the Click and the KeyPress pro c edures. Try to avo id redundant c o de.
Displaying OLE Error Messages as Clear Text No w that yo u kno w ho w to develo p yo ur o wn COM o bjec ts, let’s mo ve o n to a sho rt but very useful add-o n fo r yo ur sc ripts. Let’s develo p a c o mpo nent that returns the c lear text erro r message o f any OLE erro r number yo u o r yo ur sc ript might run into . OLE erro r messages are very impo rtant — they are raised by the c o mpo nents that handle c o mmunic atio n between yo ur sc ripting c o mpo nents.
148
Part I: Sc ripting Kic ks tart
■
■
As a rule o f thumb, OLE erro rs indic ate slo ppy erro r handling. The c o mpo nent that c aused the OLE erro r sho uld have taken c are o f it in the first plac e, so in a perfec t wo rld, yo u wo uld never enc o unter any OLE erro rs. In reality, ho wever, OLE erro rs do happen. In the WSH 2.0 beta versio n, fo r example, GetFileVersion raised an OLE erro r whenever yo u tried to retrieve the file versio n o f a file that did no t c o ntain versio n info rmatio n. Mic ro so ft has fixed this pro blem in the Windo ws 2000 versio n and will pro bably fix it in the o ther WSH versio ns, as well. Take a lo o k at the fo llo wing example sc ript — it uses GetFileVersion to retrieve a file’s versio n info rmatio n. Depending o n the WSH versio n yo u use, GetFileVersion may o r may no t raise an erro r whenever yo u try to retrieve versio n info rmatio n o f a file that do es no t c o ntain suc h info rmatio n: ‘ 4-11.VBS set fs = CreateObject(“Scripting.FileSystemObject”) on error resume next version = fs.GetFileVersion(“C:\AUTOEXEC.BAT”) if not err.Number=0 then MsgBox “Error Message: “ & err.description MsgBox “Error Code: “ & err.Number else MsgBox “No error occured.” MsgBox “File Version Information: “ & version end if
Older versio ns o f GetFileVersion repo rt an unhandled OLE erro r. OLE erro rs are easy to rec o gnize — erro r numbers are huge and negative (see Figure 4-15). Ano ther indic ato r is err.Description — it do esn’t return a c lear text desc riptio n.
Figure 4-15: OLE errors dis play huge negative error codes .
Creating your new OLE error spy tool To find o ut mo re abo ut the reaso n fo r a spec ific OLE erro r, just write a little sc ript extensio n. As always, yo u find the c o mplete so urc e c o de o n the c o mpanio n CD — just o pen \components\oleerror\oleerror.vbp. If yo u wish, yo u c an also install the prec o mpiled c o mpo nent, o r \install\ oleerr\setup.exe.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
149
■
■
Launc h the VB CCE, c all yo ur pro jec t ole.err, switc h to Co de view, and enter the fo llo wing c o de. Option Explicit Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000 Private Declare Function FormatMessage Lib “kernel32” Alias _ “FormatMessageA” (ByVal dwFlags As Long, _ lpSource As Long, ByVal dwMessageId As Long, _ ByVal dwLanguageId As Long, ByVal lpBuffer As String, _ ByVal nSize As Long, Arguments As Any) As Long Public Function OLEError(ByVal number As Long) As String Dim returnmessage As String Dim returnedchars As Long returnmessage = Space$(256) returnedchars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0&, _ number, 0&, returnmessage, Len(returnmessage), 0&) If returnedchars > 0 Then OLEError = Left$(returnmessage, returnedchars) Else OLEError = “Error not found.” End If End Function
Next, c o mpile the pro jec t — o pen the File menu and c ho o se Make ole.ocx. Do ne.
Finding out more about OLE errors No w yo u are ready to ask Windo ws what the hec k erro r c o de –2147024885 ac tually means. Use the fo llo wing sc ript and enter the erro r number yo u need info rmatio n abo ut: ‘ 4-12.VBS set ole = CreateObject(“ole.err”) number = InputBox(“Enter Error Number!”,,”-2147024885”) reason = ole.OLEError(number) MsgBox number & “ = “ & reason
No w yo u kno w — GetFileVersion failed bec ause an attempt was made to lo ad a file that did no t c o ntain versio n info rmatio n (see Figure 4-16).
150
Part I: Sc ripting Kic ks tart
■
■
Figure 4-16: Retrieve hidden OLE error des criptions us ing API functions .
Distributing Your Self-Made COM Objects Anytime yo u c o mpile a COM o bjec t using the Make c o mmand, Windo ws auto matic ally registers the c o mpo nent in the Registry. This is fundamentally impo rtant. In Chapter 3, yo u saw the keys nec essary fo r yo ur sc ripts’ CreateObject c o mmand to find and ac c ess the c o mpo nent. Witho ut tho se, yo u c an’t ac c ess yo ur COM o bjec t. Registering a c o mpo nent auto matic ally builds all Registry keys nec essary to ac c ess the c o mpo nent. Registratio n servic e is built direc tly into yo ur COM o bjec t and just needs to be c alled.
Manually registering a COM object Eac h COM o bjec t c o ntains built-in func tio ns to register itself. Yo u c an see tho se hidden registratio n func tio ns with the help o f the fo llo wing sc ript: ‘ 4-13.VBS
set wshshell= CreateObject(“WScript.Shell”) set dll = CreateObject(“dll.tobtools”) dllname = InputBox(“Please enter full path to COM object!”) set coll = dll.GetDLLFunctions(dllname) for each member in coll list = list & member & vbCr next MsgBox list
No matter whether yo u view a system .dll file o r a c usto m-made .ocx c o ntro l, there will always be a standard set o f func tio ns available to register and unregister yo ur c o mpo nent.
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
151
■
■
Let’s assume fo r a sec o nd yo u have develo ped a COM o bjec t and c o mpiled it as cd.ocx. To be able to use its func tio nality o n ano ther c o mputer, c o py the .ocx file to the c o mputer’s system fo lder. Next, yo u need to register the c o mpo nent. Yo u do no t have to plac e the .ocx file in o ne o f the o ffic ial system fo lders. If yo u do n’t, tho ugh, yo u need to spec ify the full path name. Also , yo u need to make sure that the .ocx file will stay where yo u put it. Sho uld yo u plac e it o n yo ur deskto p and delete it later o n, yo u will no lo nger be able to use its func tio ns. Therefo re, it’s a go o d idea to plac e it so mewhere safe. Open the Start menu and c ho o se Run. Then enter this c o mmand — regsvr32 cd.ocx (see Figure 4-17).
Figure 4-17: Manually regis tering COM objects us ing REGSVR32 Regsvr32.exe ac tually do esn’t do muc h. It just c alls the DLLRegisterServer func tio n inside the file yo u spec ify. Regsvr32.exe c o mplains if the file wasn’t fo und o r if it do esn’t o ffer the DLLRegisterServer func tio nality. That’s all. DLLRegisterServer internally takes all steps nec essary to intro duc e the COM o bjec t to the lo c al Registry, and o nc e it’s registered, yo u c an ac c ess yo ur c o mpo nent. COM o bjec ts are also smart eno ugh to remo ve their Registry keys o nc e they are no t needed anymo re, so they auto matic ally c o ntain a deinstallatio n feature. This is invo ked by DLLUnregisterServer. Just use /U in c o njunc tio n with Regsvr32.exe to c all DLLUnregisterServer instead o f DLLRegisterServer. To be able to remo ve a c o mpo nent, c all its DLLUnregisterServer func tio n befo re yo u physic ally delete the .ocx file. Onc e yo u’ve deleted the file, yo u will have no way to auto matic ally remo ve the c o mpo nent’s Registry entries anymo re. This is a c o mmo n reaso n fo r garbage and malfunc tio ns in general, bec ause what applies to yo ur COM o bjec ts also applies to the many COM o bjec ts that c o mmerc ial so ftware brings alo ng. Never delete a pro gram befo re c alling its uninstall func tio ns. To view all c o mmand lines available, just c ho o se Run fro m the Start menu and c all Regsvr32 witho ut arguments.
152
Part I: Sc ripting Kic ks tart
■
■
Preparing a setup package Manually registering a c o mpo nent is straightfo rward, but it requires so me tec hnic al po king aro und. It’s no t the best idea if yo u plan to distribute yo ur COM o bjec ts c o mmerc ially o r to beginners. In additio n, registering a COM o bjec t may no t be eno ugh. Onc e yo u start develo ping c o mplex COM o bjec ts, they may require additio nal o bjec ts, and then it bec o mes hard to keep trac k o f whic h c o mpo nents need to be distributed. Even wo rse, COM o bjec ts designed with the Visual Basic CCE require the Visual Basic run-time o bjec ts to be available. Installing a naked COM o bjec t o n a mac hine witho ut tho se run-time files wo n’t wo rk. Fo rtunately, there is an easy way o ut. The Visual Basic Co ntro l Creatio n Editio n c o mes with the Setup Wizard. This wizard helps yo u to prepare a setup pac kage. It features a graphic al user interfac e and do es all the tec hnic al registratio n pro c edures safely hidden in the bac kgro und. In additio n, the wizard takes c are o f all o bjec ts yo ur COM o bjec t needs to have aro und and integrates them into the Setup pac kage @em inc luding the Visual Basic runtime files. In essenc e, yo u c an then distribute the entire pac kage, and the rec ipient just needs to c all SETUP.EXE. Yo u c an even c reate a setup file fo r interac tively installing the pac kage o ver the Internet. The setup pac kage also takes c are o f uninstalling yo ur c o mpo nent(s). It plac es an entry in the Windo ws so ftware list and pro vides an uninstall c o mpo nent that c alls DLLUnregisterServer fo r eac h o f yo ur c o mpo nents. It also remo ves the files. The user c an deinstall yo ur pac kage just like any o ther so ftware using the Add/ Remo ve Pro grams mo dule in the Co ntro l Panel. Nic e. Start the Setup Wizard, then c ho o se the pro jec t file. Next, selec t the way yo u want to distribute the pac kage. If needed, the wizard c an split up the c o ntent o n many flo ppy disks o r sto re everything in o ne direc to ry (see Figure 4-18).
Chapte r 4 : De ve lo ping Yo ur Own Sc ript Co mpo ne nts
153
■
■
The wizard may ask whether yo u want to inc lude enviro nment files. If in do ubt, just c lic k Yes. Then the wizard prepares a list o f files needed to be integrated into yo ur pac kage and builds the pac kage (see Figure 4-19).
Figure 4-19: Setup Wizard automatically includes all neces s ary files and objects . To make yo ur COM o bjec t as c o mpatible as po ssible, c o mpile the COM o bjec ts o n the latest Windo ws versio n available. Fo r example, it may be nec essary to c o mpile yo ur COM o bjec ts o n a Windo ws 2000 mac hine fo r it to run o n all Windo ws versio ns. Co mpiling o n a Windo ws 98 mac hine may pro duc e COM o bjec ts that do no t run o n Windo ws 2000. Onc e yo ur so ftware pac kage is c reated, yo u sho uld o pen the file setup.lst in yo ur text edito r. It c o ntains the list o f files the pac kage will install. Yo u c an manually fine-tune the list and take o ut files yo u do n’t want to distribute (the run-time files, fo r example). Yo u c an also c o mbine mo re than o ne distributio n pac kage — prepare so ftware pac kages fo r all o f yo ur COM o bjec ts, then c o mbine the setup.lst entries o f all pac kages and c o py all distributio n files in o ne fo lder. No w, yo ur setup pac kage installs all COM o bjec ts in o ne step. Be c areful no t to inc lude a file referenc e mo re than o nc e. Make sure any file that needs DLLRegisterServer registratio n is marked as DLLSelfRegister.
Important caveats you must know about The Setup Wizard is a nic e thing to have, but it will no t always c ause pure jo y. One o f the mo st impo rtant limitatio ns o f the setup pac kage that it c reates is its inability to o verwrite files. Let’s assume fo r a mo ment yo u have previo usly c reated a COM o bjec t and saved it as test.ocx. Whenever yo u try to install a newer versio n (o r a c o mpletely different COM o bjec t) that also uses this file name, yo u must deinstall the o ld file first. Yo u c an’t go ahead and install the new c o mpo nent o n to p o f the o ld o ne. If yo u did, everything wo uld seem to install smo o thly and the setup pac kage wo uld even repo rt suc c ess. The bitter truth, ho wever, is that the new COM o bjec t isn’t c o pied to yo ur hard drive and isn’t registered at all.
154
Part I: Sc ripting Kic ks tart
■
■
So , whenever yo u suspec t this issue, find o ut the .ocx filename yo u are abo ut to install and do a searc h fo r it. If yo u find it is already installed o n yo ur system, make sure it c an be safely replac ed and then delete the file. No w yo u are ready to install the new c o mpo nent. No te also that the Setup pac kage the Setup Wizard c reates c an always be deinstalled using the Add/ Remo ve Pro grams mo dule in yo ur Co ntro l Panel. There’s ano ther issue, tho ugh. The Setup Wizard do es take c are that any file yo ur COM pro jec t referenc es is inc luded with yo ur pac kage. It c an’t c hec k, ho wever, whether this is legal. Maybe yo u referenc ed so me third-party to o l that c an’t be supplied to o thers. Even wo rse, yo ur pac kage may c o ntain system files unsuitable fo r o ther Windo ws systems. This definitely is a bug, bec ause under no rmal c o nditio ns, Windo ws wo uld so rt o ut any system file with a lo wer versio n number than tho se already in use, and it do es. Unfo rtunately, the Mic ro so ft “DLL hell” — the mixture o f different system c o mpo nents and versio ns — o ften leads to instabilities even if yo u o nly replac e system files with newer versio ns. The pro blem o utlined is by far no t limited to yo ur COM o bjec t pac kages. It applies to any so ftware installatio n. In c o ntrast to mo st o ther so ftware, yo u do have an o ptio n, tho ugh. First o f all, yo u c an always edit the SETUP.LST file and determine fo r yo urself whic h files are ac tually installed by yo ur pac kage. Sec o nd, yo u c an always c ho o se the purist way and o nly distribute yo ur .ocx file — it’s small and handy. Just make sure that o n the target system, the Visual Basic 5 Runtime Files are installed, and that yo u register yo ur .ocx file using regvr32.ocx as o utlined abo ve.
Summary The freely available Visual Basic CCE allo ws yo u to easily c reate sc ript extensio ns. Sc ript extensio ns are fully distributable COM o bjec ts that c an be c alled fro m any pro gram. Use hidden Windo ws API func tio ns and fo rm elements to c reate c o mpletely new sc ripting c o mmands o r to display c usto m-made dialo g bo xes.
Chapte r 5
Using Internet Explorer as the Output Window In This Chapter 䊳 Find o ut the sec ret Internet Explo rer sc ripting c o mmands 䊳 Open and size the IE windo w by sc ript 䊳 Write text into the IE windo w 䊳 Change Internet Explo rer c o ntent dynamic ally 䊳 Respo nd to IE events suc h as onQuit 䊳 Design yo ur o wn HTML dialo g bo xes 䊳 Halt sc ripts and enable event pro c essing 䊳 Get detailed info rmatio n abo ut the IE DHTML o bjec t mo del 䊳 Generate c o lo r-c o ded do c umentatio n manuals auto matic ally 䊳 Learn to “walk” the Objec t hierarc hies and retrieve hidden info rmatio n 䊳 Print Web pages using hidden IE sc ript c o mmands
H
o w c an yo u display results to the user? Yo ur Sc ripting Ho st has no windo w, so the built-in c o mmunic atio n paths use the MsgBox and Popup func tio ns.
Bo th func tio ns may be suffic ient fo r o utputting simple messages, but they do n’t allo w muc h ro o m fo r yo ur o wn designs. Even wo rse, they are part o f the sc ript engine. They c an’t run independently and o utput results while yo ur sc ript runs. Bo th MsgBox and Popup are func tio ns defined in COM o bjec ts that serve “in-pro c ess.” MsgBox lives inside vbscript.dll, and Popup resides in wshom.ocx. In-pro c ess means the COM o bjec t is lo aded into yo ur ho st’s address spac e. To yo u, this means yo ur sc ript needs to wait fo r tho se func tio ns. In o rder to o utput results while yo ur sc ript runs, yo u need “o ut-o f-pro c ess” COM o bjec ts. Tho se o bjec ts are .exe files that c an run o utside yo ur ho st.
156
Part I: Sc ripting Kic ks tart
■
■
There’s an easy way o ut, tho ugh. Just use an independent .exe file to display results. On any WSH-enabled Windo ws system, yo u sho uld find at least Internet Explo rer Versio n 4.0. Internet Explo rer has two fac es — it c an run independently as a regular pro gram to surf the Internet, and it also ac ts as a COM o bjec t. Yo u c an c o mpletely c o ntro l all its features by sc ript.
Finding Out the Secret Functions Inside IE Befo re yo u c an ac c ess a fo reign pro gram like Internet Explo rer by sc ript, yo u need a lo t o f info rmatio n. Fo rtunately, yo u have already prepared all the to o ls nec essary. So o n, yo u’ll retrieve full do c umentatio n o f the hidden safely metho ds and pro perties available inside Internet Explo rer. Even better, the strategies o utlined wo rk with any pro gram. So , if yo u are hungry fo r mo re, apply them to any o ther pro gram yo u find interesting and see if and ho w it makes its internal func tio ns available to yo ur sc ripts.
Determining a program’s real name The first step in ac c essing any pro gram is to find o ut its real name. That’s easy, b y the way; just lo o k fo r the pro gram’s ic o n, right-c lic k it, and c ho o se Pro perties. In the Pro perties windo w, c lic k the Sho rtc ut tab . The Target field reveals the tec hnic al name ( see Figure 5-1) . Internet Explo rer hides in iexplore.exe, fo r example.
Figure 5-1: Find out a program’s real name.
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
157
■
■
Next, yo u need to find o ut whether it’s a COM o bjec t and whether yo u c an ac c ess it remo tely. This is also easy — just o pen the scriptobjects.exe file yo u generated in Chapter 4 and searc h fo r iexplore.exe. Immediately, yo u find that iexplore.exe is indeed a COM o b jec t and c an b e c alled b y sc ript, referred to as InternetExplorer.Application and returning an IWebBrowser2 o b jec t. Yo u also see that its TypeLib rary is sto red in shdocvw.dll. That’s all yo u need to kno w.
Reading out secret TypeLibrary information Next, yo u generate the undo c umented o wner’s manual. Launc h sc ript 3-7.VBS and pro vide it with the info rmatio n yo u just fo und o ut. A c o uple sec o nds later, yo u rec eive the auto matic ally generated o wner’s manual as a handy HTML file (see Figure 5-2). The TypeLibrary pro vides yo u no t o nly with the syntax o f all the hidden metho ds and pro perties, it also inc ludes sho rt desc riptio ns. Print o ut this file fo r future referenc e.
Figure 5-2: Scripts generate detailed lis ts of internal functions for printout and res earch.
Opening Internet Explorer with Style No w yo u c an get ac c ess to Internet Explo rer easily, bec ause yo u no w kno w its ProgID ( InternetExplorer.Application); yo u just need to c all CreateObject. Yo u rec eive a IWebBrowser2 Object and c an start c alling all its metho ds and pro perties listed in yo ur freshly generated “o wner’s manual.”
158
Part I: Sc ripting Kic ks tart
■
■
The fo llo wing sc ript o pens Internet Explo rer remo tely: ‘ 5-1.VBS set ie = CreateObject(“InternetExplorer.Application”) MsgBox “Object Type: “ & TypeName(ie) ie.visible = true MsgBox “Internet Explorer is visible now!” ie.visible = false MsgBox “Now it’s hidden!” ie.Quit
The sc ript gets a referenc e to Internet Explo rer and repo rts the o bjec t name — IWebBrowser2, just as expec ted. If yo u use an o lder versio n o f Internet Explo rer, the o bjec t name may also be IWebBrowser. This versio n o f Internet Explo rer lac ks so me metho ds and pro perties, but yo u c an use it as well. Just replac e IWebBrowser with IWebBrowser2 in all the examples. No w the sc ripts will start to use so me o f the pro perties and metho ds listed in the “o wner’s manual” yo u just c reated. The visible pro perty c o ntro ls whether o r no t the windo w is visible. No te that the windo w butto n appears in the task bar o nly when visible is set to true. visible is false by default. Onc e the sc ript is do ne, it c alls the Quit metho d to c lo se Internet Explo rer alto gether. Clo sing an o bjec t is no t really mandato ry. The Sc ripting Ho st c lo ses o bjec ts anyway o nc e the sc ript is do ne. Ho wever, “o ut-o f-pro c ess” COM o bjec ts like Internet Explo rer run as independent pro grams. They may no t reac t to the WSH’s c lo se request bec ause they are no t lo c ated inside the WSH’s address spac e. In c o ntrast to “in-pro c ess” COM o bjec ts, the WSH c an o nly kindly ask the o bjec t to go away. It c an’t use fo rc e. Therefo re, it’s safer to c lo se suc h o bjec ts explic itly.
Writing something into the IE window So far, Internet Explo rer is c o mpletely empty. Ho w c an yo u ac c ess (and c hange) its c o ntents? Again, this is surprisingly easy o nc e yo u find the hidden do o r. Under no rmal c o nditio ns, Internet Explo rer displays HTML pages, so the inside is just an HTML enviro nment that c an ho st and display HTML. To display an HTML page, use the navigate metho d. ‘ 5-2.VBS set ie = CreateObject(“InternetExplorer.Application”) scriptname = WScript.ScriptFullName path = left(scriptname, InstrRev(scriptname, “\”)) filename = path & “showme.htm”
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
159
■
■
MsgBox “Now loading “ & filename ie.navigate filename ie.visible = true MsgBox “Internet Explorer is visible now!”, vbSystemModal MsgBox “Type of document: “ & TypeName(ie.document) ie.Quit
Just make sure yo u prepared an HTML file the sc ript c an lo ad. This sc ript lo o ks fo r a file named showme.htm. It needs to be lo c ated in the same fo lder the sc ript is sto red in. Launc h yo ur text edito r and type in the fo llo wing simple HTML tags:
Hello World!
Next, save it as SHOWME.HTM.
WScript.ScriptFullName always returns the full path name o f yo ur sc ript. With this info rmatio n, it’s easy to retrieve the fo lder name. Yo u c an append the fo lder name to any reso urc e filename. This way, the reso urc e file just needs to be lo c ated in the same fo lder the sc ript is sto red in. Yo u do n’t need to spec ify any fixed path names anymo re. No w Internet Explo rer will display yo ur HTML file. This isn’t to o exc iting, tho ugh. Yo u c o uld have just as easily o pened yo ur HTML page with the Run c o mmand in the Start menu: IEXPLORE.EXE SHOWME.HTM [Enter]
The real firewo rks start o nc e the page is lo aded and o nc e yo ur sc ript q ueries Internet Explo rer’s pro perty do c ument. It returns an o b jec t. This o b jec t ac tually represents yo ur HTML file. This simple o b jec t referenc e is all yo u need to dynamic ally c hange the appearanc e o f the HTML page. If yo u start Internet Explo rer fo r the first time, the Internet Wizard might po p up, asking yo u to set up the Internet c o nnec tio n. Yo u do n’t need a c o nnec tio n fo r these examples, but yo u do need to get rid o f the wizard befo re yo u c an c o ntro l the IE c o ntents by sc ript. So , just set up a c o nnec tio n first o r spec ify a LAN c o nnec tio n.
Dynamically changing the IE contents Using Internet Explo rer as o utput windo w sho uldn’t require yo u to pro vide an external HTML file. After all, yo ur sc ript sho uld supply all the info rmatio n yo u want to display. But ho w c an yo u initialize Internet Explo rer c o ntents?
160
Part I: Sc ripting Kic ks tart
■
■
Just use this little tric k: Call navigate, but do n’t supply an HTML filename. Instead, use the undo c umented JavaSc ript: keywo rd. This way, yo u c an synthetic ally o pen a Web page. The fo llo wing sc ript sho ws ho w this wo rks, and it also inc ludes ano ther impo rtant feature. A lo o p delays the sc ript until the HTML page is ac tually displayed. This is extremely impo rtant. Sho uld yo u try to ac c ess the do c ument pro perty befo re the do c ument is pro perly initialized, yo u will get an erro r. Yo u c an’t c hange Internet Explo rer c o ntent dynamic ally befo re it is fully lo aded. ‘ 5-3.VBS set ie = CreateObject(“InternetExplorer.Application”) title = “My Output Window” page = “JavaScript:’” & title _ & “’” ie.navigate page ‘ wait for the page to be fully initialized: do loop while ie.ReadyState4 ‘ show page: ie.visible = true ‘ now you can dynamically change content: content = InputBox(“Please enter some text!”) ie.document.body.innerHTML = “” & content & “” MsgBox “I will now list all files on drive C:\!” ‘ list all files set fs = CreateObject(“Scripting.FileSystemObject”) set folder = fs.GetFolder(“C:\”) for each file in folder.files ie.document.body.insertAdjacentHTML “beforeEnd”, _ file.name & “ ” next
The sc ript pro mpts yo u fo r text and displays it in the IE windo w. Next, it enumerates all files o n drive C:\ and displays them dynamic ally (see Figure 5-3). Yo u c an even set the title bar text o f yo ur windo w. Just add a sec tio n in yo ur HTML c o de and pro vide a sec tio n. This is po ssible o nly bec ause yo ur sc ript o wns a referenc e to the embedded Web page. It c an replac e the bo dy o f the page with innerHTML, and it c an add text to the bo dy tag using insertAdjacentHTML. In fac t, yo ur sc ript c an no w use any DHTML c o mmand suppo rted by Internet Explo rer.
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
161
■
■
Figure 5-3: Change text in the w indow dynamically.
Responding to Events As many advantages as independent “o ut-o f-pro c ess” COM o bjec ts o ffer, pro blems c an still arise. What if so meo ne c lo ses the IE windo w while yo ur sc ript is still trying to ac c ess it? Yo u will rec eive an auto matio n erro r. No fun. Therefo re, it’s nec essary to info rm yo ur sc ript abo ut any impo rtant c o nditio ns inside the IE windo w. Yo ur sc ript needs a way to respo nd to events fired by the IE windo w. Events are messages a COM o bjec t sends as so o n as so mething impo rtant happens, so yo ur sc ript needs so me kind o f rec eiver to listen to tho se events. Fo rtunately, the Sc ripting Ho st c o ntains suc h a rec eiver. It’s c alled event sink, and it auto matic ally c alls a c usto m pro c edure the mo ment the event that the event sink listens to is fired. The fo llo wing sc ript ac tivates its event rec eiver and respo nds to the onQuit event. This event is fired just befo re the IE windo w is c lo sed. ‘ 5-4.VBS ‘ this statement invokes the event sink feature: set ie = WScript.CreateObject(“InternetExplorer.Application”, _ “event_”) title = “My Output Window” page = “JavaScript:’” & title _ & “’” ie.navigate page ‘ wait for the page to be fully initialized: do
162
Part I: Sc ripting Kic ks tart
■
■
loop while ie.ReadyState4 ‘ show page: ie.visible = true ‘ now you can dynamically change content: content = InputBox(“Please enter some text!”) ie.document.body.innerHTML = “” & content & “” MsgBox “I will now list all files on drive C:\!” ‘ list all files set fs = CreateObject(“Scripting.FileSystemObject”) set folder = fs.GetFolder(“C:\”) for each file in folder.files ie.document.body.insertAdjacentHTML “beforeEnd”, _ file.name & “ ” next ‘ this procedure executes once the IE Quit event is fired: sub event_onQuit MsgBox “Hey! You closed my output window!”, vbExclamation WScript.Quit end sub
The sc ript wo rks almo st like its predec esso r. Again, yo u c an insert text dynamic ally into the IE windo w, but this time, the mo ment yo u c lo se the IE windo w, yo ur sc ript po ps up a warning message and quits. If yo u tried the same thing with 5-3.VBS, yo u wo uld have raised an auto matio n erro r. Ho w do es the magic wo rk? This time, the sc ript uses CreateObject no t o nly to get a referenc e to InternetExplorer.Application, but to also establish an event sink. It’s the sec o nd argument, “ event_.” Yo u c an c all yo ur event sink so mething else as lo ng as the name ends with an undersc o re. There are ac tually two different CreateObject metho ds. One is part o f VBSc ript and c an be c alled direc tly. This metho d do es no t suppo rt event sinks. Instead, it allo ws ac c ess to remo te COM o bjec ts o n o ther mac hines. The Sc ripting Ho st o ffers its o wn CreateObject metho d. This metho d c an’t c all COM o bjec ts remo tely, but it suppo rts event sinks. To c all this metho d, yo u need to spec ify the Sc ripting Ho st explic itly, using WScript.CreateObject. To be able to establish an event sink, yo u must use the Sc ripting Ho sts’ versio n o f CreateObject. Yo u c an’t use the VBSc ript c o mmand. This is why the sc ript uses WScript.CreateObject instead o f CreateObject. The event sink listens to all events fired by the o bjec t. Onc e an event is fired, the event sink lo o ks fo r a pro c edure that starts with the name o f the event sink and ends with the name o f the event. Bec ause the sc ript has c alled its event sink “ event_,” the pro c edure event_onQuit is exec uted eac h time the onQuit event is fired.
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
163
■
■
IE fires onQuit anytime its windo w is c lo sed. This c an happen bec ause so meo ne c lo sed it with the mo use, o r if yo ur sc ript c alls the IE Quit metho d. So if yo u want to c lo se the IE windo w by sc ript, yo u sho uld disable the event pro c edure first. Just c all WScript.DisconnectObject ie. Yo u c an also build a c o ntro l variable into yo ur event pro c edure and set the variable appro priately. Fo r example, display the warning message o nly if yo ur c o ntro l variable is set to true, and set it to false anytime yo u do n’t want event pro c essing.
Finding out which events the object supports Ho w did I kno w Internet Explo rer suppo rts the onQuit event? I just lo o ked it up in the IE TypeLibrary. Yo u c o uld, to o . The IWebBrowser2 o bjec t really is just a mo dule. It c o ntains o nly the metho ds and pro perties, but no events. Events are handled by ano ther mo dule, so the first thing yo u need to do is get a c lear pic ture o f whic h mo dules there really are: ‘ 5-5.VBS set typelib = CreateObject(“typelib3.decoder”) ‘ use a dictionary to keep track of duplicate entries: set dict = CreateObject(“scripting.dictionary”) ‘ check interfaces defined in this file: typelibfile = “shdocvw.dll” ‘ enumerate available interfaces: set interfaces = typelib.GetInterfaces(typelibfile) list = “Interfaces in “ & typelibfile & “:” & vbCr & vbCr ‘ read all interfaces and put into list: for each interface in interfaces ‘ check whether entry is a duplicate entry: if not dict.Exists(interface) then ‘ add to list only if new entry dict.Add interface, 0 list = list & interface & vbCr end if next MsgBox list
The sc ript lists all the mo dules mentio ned in the TypeLibray (see Figure 5-4). There are mo re than just IWebBrowser2.
164
Part I: Sc ripting Kic ks tart
■
■
Figure 5-4: Retrieve objects s tored in IE TypeLibrary to find out about events . As a go o d investigato r, yo u no tic e that so me o f the mo dule names c o ntain “events” in their names. One might assume that DWebBrowserEvents2 c o ntains the IE event list. To make sure, and to find o ut abo ut the events, take a lo o k inside DWebBrowserEvents2: ‘ 5-6.VBS set typelib = CreateObject(“typelib.decoder”) set wshshell = CreateObject(“WScript.Shell”) ‘ This is the Type Library responsible for IE: module = “shdocvw.dll” ‘ This is the module we are interested in: interface = “DWebBrowserEvents2” ‘ list content: set result = typelib.EnumInterface(module, interface) for each entry in result entry = Split(entry, vbTab) list = list & entry(0) & vbCr & “[“ & entry(1) & “]” & vbCr next wshshell.Popup list
Bec ause there are a lo t o f events, the sc ript uses the Popup metho d. MsgBox wo uldn’t be able to sho w all the results. If yo u’d rather save the o utput to a file fo r future referenc e, take a lo o k at Chapter 8 and the file system metho ds. Yo u c an also use sc ript 5-13.VBS. Right again — DWebBrowserEvents2 c o ntains the onQuit pro c edure, and its sec ret c o mment states Fired when the applic atio n is quitting. In additio n, yo u no w have a c o mplete list o f all the o ther events the IE suppo rts.
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w ■
165 ■
Yo u c o uld also go the o ppo site direc tio n. Just use yo ur handy lo o kup to o l 3-8.VBS and enter onQuit. Immediately, yo u kno w whic h o bjec ts suppo rt onQuit (see Figure 5-5).
Figure 5-5: Search for key w ord onQuit.
The perfect output window example By no w, yo u have all the building blo c ks nec essary to prepare a generic o utput windo w. Just bundle the c o de and put it into an easy-to -use func tio n. In additio n, the fo llo wing sc ript also disables all the IE to o lbars so the windo w do esn’t lo o k like an IE windo w anymo re: ‘ 5-7.VBS ‘ Open IE Window without scroll bar set window = OpenWindow(“My Output Window”, false) ‘ use window: content = InputBox(“Please enter some text!”) PrintNew window, “” & content & “” MsgBox “I will now list all files on drive C:\!” ‘ list all files set fs = CreateObject(“Scripting.FileSystemObject”) set folder = fs.GetFolder(“C:\”) for each file in folder.files Print window, file.name & “ ” next sub event_onQuit MsgBox “Hey! You closed my output window!”, vbExclamation WScript.Quit end sub function OpenWindow(title, scrolling) set ie = WScript.CreateObject(“InternetExplorer.Application”, _
166
Part I: Sc ripting Kic ks tart
■
■
“event_”) ‘ add attribute to body-tag to hide scroll bar if appropriate: if scrolling then scroller = “scroll = no” end if page = “JavaScript:’” & title _ & “’” ie.navigate page ‘ turn off toolbars ie.Toolbar = false ‘ turn off status bar ie.Statusbar = false do loop while ie.ReadyState4 ie.visible = true ‘ return reference to IE object: Set OpenWindow = ie end function sub PrintNew(obj, text) obj.document.body.innerHTML = text end sub sub Print(obj, text) obj.document.body.insertAdjacentHTML “beforeEnd”, text end sub
The func tio n OpenWindow handles all the IE o pening and returns the o bjec t referenc e. As always with referenc es, remember to use Set whenever yo u assign the referenc e to ano ther variable. No te also the use o f scroll=no. The sc ript inserts this statement into the tag to disable the vertic al sc ro ll bar whenever yo u supply false as a sec o nd argument. In this example, bec ause o f the missing sc ro ll bar, yo u c an’t see the end o f the file listing. So , in this c ase, it wo uld be a go o d idea to enable the sc ro ll bar. In o ther c ases where yo u just want to design a dialo g bo x, it’s better to turn the bar o ff — the c ho ic e is yo urs. Finally, Mic ro so ft has fixed the sc ro ll b ar issue. Beginning with Internet Explo rer 5, yo u c an spec ify scroll=auto. No w, the IE will display the vertic al sc ro ll b ar o nly when needed.
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
167
■
■
Sizing the IE window Yo u c an even size and c enter yo ur IE windo w. The windo w size is determined by the IE pro perties Width and Height. The c urrent po sitio n is determined by Left and To p. In o rder to c enter the windo w o nsc reen, yo u also need info rmatio n abo ut the c urrent sc reen reso lutio n so yo u c an c alc ulate the o ffsets. This info rmatio n is pro vided by the screen o bjec t — part o f any HTMLDocument o bjec t. ‘ 5-8.VBS set window = OpenWindow(“My Output Window”, 400, 200) content = InputBox(“Please enter some text!”) PrintNew window, “” & content & “” MsgBox “I will now list all files on drive C:\!” ‘ list all files set fs = CreateObject(“Scripting.FileSystemObject”) set folder = fs.GetFolder(“C:\”) for each file in folder.files Print window, file.name & “ ” next sub event_onQuit MsgBox “Hey! You closed my output window!”, vbExclamation WScript.Quit end sub function OpenWindow(title, width, height) set ie = WScript.CreateObject(“InternetExplorer.Application”, _ “event_”) page = “JavaScript:’” & title _ & “’” ie.navigate page ie.Toolbar = false ie.Statusbar = false do loop while ie.ReadyState4 screenWidth = ie.document.parentWindow.screen.availWidth screenHeight = ie.document.parentWindow.screen.availHeight ‘ limit size to max avail space if width>screenWidth then width=screenWidth if height>screenHeight then height=screenHeight ie.Width = width ie.Height = height
168
Part I: Sc ripting Kic ks tart
■
■
ie.left = Fix((screenWidth - width)/2) ie.top = Fix((screenHeight - height)/2) ie.visible = true ‘ return reference to IE object: Set OpenWindow = ie end function sub PrintNew(obj, text) obj.document.body.innerHTML = text end sub sub Print(obj, text) obj.document.body.insertAdjacentHTML “beforeEnd”, text end sub
Responding to Events Inside Your Documents So far, IE c an o nly display info rmatio n. What if yo u want to c reate a real dialo g windo w? Ho w c an yo u send keystro kes, inputs, and butto n c lic ks fro m inside yo ur HTML do c ument bac k to yo ur sc ript? Easy. Yo u already disc o vered events. Whenever so mething exc iting happens inside yo ur HTML do c ument, it also raises events. Respo nding to tho se events is just a matter o f setting up the right rec eiver. Then yo ur sc ript c an listen to these events. In c o ntrast to CreateObject, this time yo u are no t go ing to c reate a new o bjec t. The HTMLDocument o bjec t is already there so yo u c an’t use CreateObject to set up an event sink the way yo u did fo r the Internet Explo rer windo w. Yo u do n’t have to set up event sinks. It’s muc h easier, bec ause yo ur HTML do c ument already c o ntains event-handling func tio ns. Mo dern DHTML Web pages use events every day.
Setting up dialog elements and buttons Befo re yo u c an start listening to events fired by yo ur HTML page, yo u first need to set up a page that c o ntains fo rm elements. Otherwise, there wo n’t be any events yo ur sc ript c an respo nd to . So , start yo ur text edito r and hac k in the fo llo wing simple page:
My Dialog!
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w ■
169 ■
Save it as dialog.htm, and o pen the file to c hec k whether it will display c o rrec tly. Next, use the fo llo wing sc ript to display the dialo g bo x: ‘ 5-9.VBS ‘ global variable will report entered text: enteredText = “” ‘ open window: set window = OpenWindow(“dialog.htm”, 400, 300) ‘ hook up event handler: window.document.all.myButton.onClick = GetRef(“buttonclick”) ‘ display MsgBox to halt the script and wait for input WScript.Sleep 2000 MsgBox “Press OK to read dialog box...”, vbSystemModal ‘ see what the user has typed in: MsgBox “This is what you entered: “ & enteredText ‘ event procedure responds to button click: sub buttonclick ‘ someone clicked the button! ‘ read entered text enteredText = window.document.all.myInput.value ‘ close window window.Quit end sub function OpenWindow(filename, width, height) set ie = CreateObject(“InternetExplorer.Application”) scriptname = WScript.ScriptFullName path = left(scriptname, InstrRev(scriptname, “\”)) filepath = path & filename ie.navigate filepath ie.Toolbar = false ie.Statusbar = false do loop while ie.ReadyState4 screenWidth = ie.document.parentWindow.screen.availWidth screenHeight = ie.document.parentWindow.screen.availHeight
170
Part I: Sc ripting Kic ks tart
■
■
‘ limit size to max avail space if width>screenWidth then width=screenWidth if height>screenHeight then height=screenHeight ie.Width = width ie.Height = height ie.left = Fix((screenWidth - width)/2) ie.top = Fix((screenHeight - height)/2) ie.visible = true ‘ return reference to IE object: Set OpenWindow = ie end function
Unfo rtunately, this sc ript wo n’t wo rk yet. It do es display yo ur dialo g bo x, but it do esn’t wait fo r yo ur respo nse. Instead, right after the dialo g bo x is sho wn, yo ur sc ript reads o ut the text field and finds — no thing.
Stopping the script until events are fired So , yo u need a way to halt yo ur sc ript until either the IE windo w is c lo sed o r the b utto n inside yo ur page is c lic ked. Yo u c o uld use a do...loop and c o nstantly c hec k fo r either c o nditio n. Ho wever, this lo o p wo uld c o nsume so muc h c o mputing po wer that it wo uld slo w do wn yo ur entire mac hine. The events wo uld have no c hanc e to ever fire. Visual Basic has a better so lutio n — and it’s c alled DoEvents.
DoEvents allo ws any pending events to fire, and this keeps yo ur system respo nsive even if yo u are exec uting a lo o p. In essenc e, yo u are no t o nly pausing yo ur sc ript fo r so me millisec o nds, but also fo rc ing Windo ws to ac tively pro c ess any pending events. WScript.Sleep, in c o ntrast, just pauses. Events still c an’t get thro ugh. Unfo rtunately, VBSc ript do esn’t suppo rt DoEvents. This is a typic al example where the Visual Basic CCE c o mes to the resc ue. Sho uld yo u need a little refresher, go bac k to Chapter 5. To use DoEvents fro m inside yo ur sc ripts, just start the VB CCE, c reate a new pro jec t and name it iehelper.tools. Next, in Co de view, enter this simple wrapper pro c edure (see Figure 5-6): sub HandleEvents DoEvents end sub
Co mpile yo ur pro jec t using Make iehelper.ocx in the File menu. Do ne.
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w ■
171 ■
Yo u c an find the pro jec t o n the c o mpanio n CD: open \components\ iehelper\iehelper.vbp. Or install the prec o mpiled pac kage: \install\ iehelper\setup.exe.
Figure 5-6: Wrap DoEvents for us e in s cripts to allow events to be handled. Unfo rtunately, yo u c an’t c all yo ur pro c edure DoEvents. Bec ause Visual Basic c o mmands are reserved key wo rds, yo u need to find a similar name fo r yo ur wrapper func tio n.
Creating your own HTML dialog boxes No w that yo u c an lo o p and pro c ess events at the same time, yo u c an finally c reate useful dialo g bo xes: ‘ 5-10.VBS ‘ get access to your wrapped DoEvents command set helper = CreateObject(“iehelper.tools”) ‘ global variable will report entered text: enteredText = “” ‘ open window: set window = OpenWindow(“dialog.htm”, 400, 300) ‘ hook up event handler: window.document.all.myButton.onClick = GetRef(“buttonclick”)
172
Part I: Sc ripting Kic ks tart
■
■
‘ go to bed until either button is clicked or window is closed: wakeup = false do ‘ allow events to fire: helper.HandleEvents loop until wakeup MsgBox “This is what you entered: “ & enteredText ‘ event procedures: sub buttonclick ‘ someone clicked the button! ‘ read entered text enteredText = window.document.all.myInput.value ‘ close window window.Quit end sub sub event_onQuit wakeup = true end sub
function OpenWindow(filename, width, height) set ie = WScript.CreateObject(“InternetExplorer.Application”, _ “event_”) scriptname = WScript.ScriptFullName path = left(scriptname, InstrRev(scriptname, “\”)) filepath = path & filename ie.navigate filepath ie.Toolbar = false ie.Statusbar = false do loop while ie.ReadyState4 screenWidth = ie.document.parentWindow.screen.availWidth screenHeight = ie.document.parentWindow.screen.availHeight ‘ limit size to max avail space if width>screenWidth then width=screenWidth if height>screenHeight then height=screenHeight ie.Width = width ie.Height = height ie.left = Fix((screenWidth - width)/2) ie.top = Fix((screenHeight - height)/2) ie.visible = true ‘ return reference to IE object: Set OpenWindow = ie end function
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
173
■
■
It wo rks perfec tly well. Yo ur sc ript waits patiently until either the butto n is c lic ked o r the windo w is c lo sed. It then reads o ut whatever yo u have typed into yo ur HTML page and displays the results (see Figure 5-7).
Figure 5-7: Des ign your ow n HTML dialog boxes and w ait for entered text. Ho w do es it wo rk? There are ac tually two events yo ur sc ript listens to . First, event_onClick c hec ks whether so meo ne c lo sed the IE windo w. If so , the pro c edure c hanges wakeup to true. This c auses the lo o p to exit, and yo ur sc ript c o mes bac k to life.
buttonclick is ano ther event rec eiver. This pro c edure is exec uted when so meo ne c lic ks the butto n o n yo ur Web page. Yo ur sc ript has ho o ked up the butto ns’ event pro c edure to its o wn pro c edure. First, yo ur sc ript ac c esses the butto n element o n the HTML page. window.document.all.myButton represents the butto n. Always make sure yo u assign a name= to yo ur HTML elements. Only with this name c an yo ur sc ript ac c ess the element. Elements witho ut names c an’t be c o ntro lled by yo ur sc ript. Next, it assigns a value to the butto n’s onClick pro perty using GetRef. GetRef is a new WSH 2.0 func tio n. It returns the internal address o f any sc ript pro c edure. This way, yo u c an link yo ur sc ript pro c edures to o ther o bjec ts. Whenever so meo ne c lic ks o n the butto n, Internet Explo rer no w ac tively c alls the address it rec eived fro m GetRef.
buttonclick first sto res the text field value in so me glo bal variable. Again, yo ur sc ript ac c esses the text field using the same syntax as with the butto n. Next, the pro c edure c lo ses the IE windo w using its Quit metho d. Bec ause this auto matic ally fires the onQuit event, immediately thereafter event_onQuit is c alled and exits the do...loop delay.
174
Part I: Sc ripting Kic ks tart
■
■
This tec hno lo gy is extremely po werful! It allo ws yo u to design just abo ut any dialo g bo x, even if yo ur dialo g bo xes c o nsist o f many different fo rm elements o r dynamic HTML. Yo ur sc ript c an easily respo nd to different butto ns and read o ut mo re than just a text field. This way, yo u c an design input fo rms fo r databases as well as c o mplex windo ws fo r disk to o ls yo u c reate. If yo u do n’t feel c o mfo rtable writing HTML c o de, just use an HTML edito r suc h as Fro ntPage. HTML edito rs allo w yo u to design yo ur windo w interac tively and with a graphic al user interfac e. Yo u do n’t need to kno w HTML, altho ugh it sure helps to o ptimize yo ur c o de.
Getting Information About Internet Explorer DHTML Object Model Every HTML page is internally represented as an HTMLDocument o bjec t. Yo u have already seen ho w useful it is to kno w mo re abo ut the internal struc ture o f this o bjec t. This kno wledge helps to remo te c o ntro l an HTML page by sc ript, and it also reveals muc h abo ut ho w DHTML wo rks. If yo u’re a Web designer, the fo llo wing pages will pro bably pro vide useful info rmatio n yo u haven’t seen elsewhere. A sec ret TypeLibrary c o ntains the entire do c umentatio n abo ut the IE DHTML o bjec t mo del. Yo u c an lo o k up any o bjec t and explo re the entire struc ture o f DHTML pages. To be able to read the sec ret TypeLibrary info rmatio n, yo u need a sc ript extensio n. Make sure yo u have installed \install\typelib\setup.exe o n the c o mpanio n CD. The sec ret DHTML TypeLibrary is c alled mshtml.tlb. Ho wever, it wasn’t intended fo r yo u to see. Instead, mshtml.tlb was designed to assist in pro fessio nal develo pment enviro nments like Visual Basic . It may o r may no t be available o n yo ur system. Take a lo o k at all the o bjec ts defined in mshtml.tlb: ‘ 5-11.VBS ‘ make sure you have installed the custom COM object ‘ as outlined in the book outputfile = “C:\Interface.txt” set typelib = CreateObject(“typelib.decoder”) set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) set output = fs.CreateTextFile(outputfile, true) ‘ use a dictionary to keep track of duplicate entries: set dict = CreateObject(“scripting.dictionary”) ‘ check interfaces defined in this file: typelibfile = InputBox(“Type lib name”,,”mshtml.tlb”)
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
175
■
■
‘ enumerate available interfaces: set interfaces = typelib.GetInterfaces(typelibfile) output.WriteLine “Interfaces in “ & typelibfile & “:” & vbCrLf & vbCrLf ‘ read all interfaces and put into list: for each interface in interfaces ‘ check whether entry is a duplicate entry: if not dict.Exists(interface) then ‘ add to list only if new entry dict.Add interface, 0 output.WriteLine interface end if next output.close wshshell.Run outputfile
This sc ript c an list the available o bjec t names o f any TypeLibrary. Just enter the name to rec eive a list o f the o bjec ts do c umented in the TypeLibrary. If the TypeLibrary file is no t lo c ated in any o f the system fo lders, yo u need to spec ify the full path name. To find o ut mo re abo ut individual o bjec ts, just use sc ript 3-7.VBS. Enter the name o f the TypeLibrary ( mshtml.tlb) and the name o f the o bjec t yo u are interested in. Try HTMLDocument. Yo ur sc ript no w reveals every detail — mo re than yo u c o uld po ssib ly find in even the mo st so phistic ated referenc e b o o ks ( see Figure 5-8) . Bec ause this info rmatio n is auto matic ally generated o n the b asis o f yo ur c urrent TypeLib rary, yo u will get the mo st up-to -date info rmatio n availab le.
Figure 5-8: Retrieve all hidden IE functions and properties .
176
Part I: Sc ripting Kic ks tart
■
■
Generating HTML-formatted documentation manuals But there’s mo re. Yo ur sc ript c an easily query all info rmatio n sec tio ns and auto matic ally build nic ely fo rmatted HTML do c umentatio n files fo r c o nvenient referenc e. The fo llo wing sc ript generates yo ur perso nal info rmatio n library, and yo u c an add any TypeLibrary info rmatio n yo u find interesting: To o lazy to generate the do c umentatio n yo urself? Take a lo o k at the c o mpanio n CD: \info\documentation\. I have put so me sample do c umentatio ns o n it. Still, it’s muc h better to generate the do c umentatio n yo urself so it adequately reflec ts the c urrent pro gram versio ns o f yo ur COM o bjec ts. ‘ 5-12.VBS ‘ make sure you have installed the custom COM object ‘ as outlined in the book ‘ change this path to the folder you want to store ‘ your documentation in: docu = “C:\documentation” ‘ change this to false if you don’t want a shortcut ‘ to your documentation folder on your desktop: link = true ‘ we need access to a couple of COM objects: set typelib = CreateObject(“typelib.decoder”) set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) set dict = CreateObject(“scripting.dictionary”) ‘ ask which type library to decode: lib = InputBox(“Which Type Library do you want to decode?”, _ , “mshtml.tlb”) ‘ do some checks: ‘ does the folder name end with “\”? if not right(docu,1)=”\” then docu = docu & “\” ‘ does the typelib file exist and is it a valid typelib? if not isTypeLib(lib) then MsgBox “Error: “ & err.description WScript.Quit end if ‘ does the documentation folder exist? if not fs.FolderExists(docu) then result = MsgBox(docu & “ does not exist. Create?”, vbYesNo _ + vbQuestion) if result=vbYes then
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w ■
177 ■
fs.CreateFolder docu else MsgBox “Can’t continue.”, vbCritical WScript.Quit end if end if ‘ open status window: set window = OpenWindow(“Querying TypeLib”, 600, 400) windowavailable = true PrintNew window, “Decoding “ & lib & “ Type Library ” ‘ enumerate typelib interfaces set interfaces = typelib.GetInterfaces(lib) ‘ enumerate other information contained in typelib set modules = typelib.GetTypeInfos(lib) ‘ find out number of information blocks to show progress allelements = interfaces.Count + modules.Count allcounter = 0 ‘ create auto-documentation files autodocument interfaces autodocument modules ‘ close status window: closeisok=true window.Quit result = MsgBox(“Do you want to open documentation folder?”, _ vbYesNo + VbQuestion) command = “EXPLORER.EXE /e,/root,” & docu if result = vbYes then wshshell.Run command end if ‘ place a link to documentation on desktop ‘ where’s the desktop? if link then desktop = wshshell.SpecialFolders(“desktop”) set scut = wshshell.CreateShortcut(desktop & “\script host docu.lnk”) scut.TargetPath = “explorer.exe” scut.Arguments = “/e,/root,” & docu scut.IconLocation = “wscript.exe,0” scut.save end if sub autodocument(collection) ‘ create subfolder for this type library: foldername = docu & fs.GetBaseName(lib) & “\” if not fs.FolderExists(foldername) then
178
Part I: Sc ripting Kic ks tart
■
■
fs.CreateFolder foldername end if ‘ decode entire collection: for each section in collection ‘ update status window:
‘ generate safe file name safename = Replace(section, “\”, “”) safename = Replace(section, “.”, “”) ‘ create file: set output = fs.CreateTextFile( _ foldername & safename & “.htm”) ‘ insert html framework like style sheets: output.WriteLine “” _ & “TypeLib-Information “ & module output.WriteLine “” output.WriteLine “” & lib & “” ‘ check whether duplicate entry: if not dict.Exists(section) then ‘ add to list only if new entry dict.Add section, 0 allcounter = allcounter + 1 percent = Fix(allcounter * 100/allelements) Print window, “[“ & percent & “%] Querying “ _ & section & “... ” ‘ retrieve section information, preformatted as HTML html = typelib.EnumInterfaceHTML(lib, section, 255)
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w ■
179 ■
output.WriteLine “
” output.WriteLine “
” _ & section & “
Description
” output.WriteLine html output.WriteLine “
” end if ‘ close this file output.WriteLine “” output.close next end sub sub event_onQuit windowavailable = false if not closeisok then MsgBox “Hey! You closed my output window!”, vbExclamation WScript.Quit end if end sub function OpenWindow(title, width, height) set ie = WScript.CreateObject(“InternetExplorer.Application”, _ “event_”) page = “JavaScript:’” & title _ & “’” ie.navigate page ie.Toolbar = false ie.Statusbar = false do loop while ie.ReadyState4 screenWidth = ie.document.parentWindow.screen.availWidth screenHeight = ie.document.parentWindow.screen.availHeight if width>screenWidth then width=screenWidth if height>screenHeight then height=screenHeight ie.Width = width ie.Height = height ie.left = Fix((screenWidth - width)/2) ie.top = Fix((screenHeight - height)/2) ie.visible = true Set OpenWindow = ie end function
180
Part I: Sc ripting Kic ks tart
■
■
sub PrintNew(obj, text) if windowavailable then obj.document.body.innerHTML = text end sub sub Print(obj, text) if windowavailable then obj.document.body.insertAdjacentHTML “beforeEnd”, text set textrange = obj.document.body.createTextRange textrange.scrollIntoView false end if end sub function isTypeLib(lib) on error resume next set interfaces = typelib.GetInterfaces(lib) if err.Number=0 then isTypeLib=true else isTypeLib=false end if end function
By default, the sc ript sto res the do c umentatio n in C:\documentation. Change the sc ript if yo u want to sto re it elsewhere. mshtml.tlb is an exc eptio nally large TypeLibrary. It c an take so me minutes fo r the sc ript to dec o de all the info rmatio n. Yo u c an ac tually watc h the sc ript retrieve the info rmatio n: It uses an IE windo w to repo rt pro gress info rmatio n (see Figure 5-9). This gives yo u a ro ugh estimate o f ho w muc h info rmatio n is already pro c essed. Ho wever, it’s very likely that the sc ript will be finished befo re 100 perc ent is reac hed. There are many duplic ate entries, and the sc ript eliminates tho se.
Figure 5-9: Script automatically s cans all TypeLibrary objects .
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
181
■
■
The sc ript uses the textrange o bjec t to auto matic ally sc ro ll to the last line inside the IE windo w. This way, yo u always see the latest pro gress info rmatio n. Onc e all info rmatio n is retrieved, the sc ript o ffers to o pen yo ur do c umentatio n library. In additio n, it plac es a sho rtc ut o n yo ur deskto p. Bo th no t o nly o pen yo ur do c umentatio n fo lder but also use hidden Explo rer o ptio ns to set it as ro o t. In the left Explo rer pane, yo u no w c an o nly see yo ur do c umentatio n subfo lders — and no thing else (see Figure 5-11). Call yo ur sc ript a c o uple o f times and have it generate do c umentatio ns fo r all the o ther impo rtant TypeLib raries to o . These inc lude vbscript. dll, scrrun.dll, wshom.ocx, shdocvw.dll, and comdlg32.ocx. Eac h TypeLib rary gets its o wn sub fo lder in yo ur do c umentatio n view. It’s no w easy to searc h fo r info rmatio n. Yo u c an even give this do c umentatio n to friends and c o lleagues o r put it o n yo ur Web site: The do c umentatio n files are plain DHTML, ideally suited fo r Internet pub lishing. Mayb e yo u want to restruc ture the info rmatio n, to o . Go ahead; it’s all c o ntained in individual files, and yo u c an easily c reate ano ther fo lder named FileSystemObject and feed it any file that relates to the FileSystemObject o b jec t. No w lean b ac k and see what yo u c an do with this wealth o f info rmatio n. TypeName has revealed that HTML do c uments are o f type HTMLDocument. So , in yo ur do c umentatio n fo lder, o pen sub fo lder mshtml and lo o k fo r HTMLDocument. Open the file.
Figure 5-10: Create your pers onal information library of undocumented COM object functions .
It c o ntains all the pro perties and metho ds suppo rted by HTML do c uments displayed in the IE windo w. Obvio usly, this do c umentatio n is no tuto rial, just tec hnic al data. Ho wever, it’s a great starting po int fo r yo ur o wn researc h.
182
Part I: Sc ripting Kic ks tart
■
■
Retrieving undocumented information about the screen object Fo r example, the sc ripts abo ve have used this line to determine the ho rizo ntal sc reen reso lutio n: screenWidth = ie.document.parentWindow.screen.availWidth
ie.document represents yo ur HTMLDocument o bjec t. Lo o k up parentWindow in yo ur do c umentatio n — what yo u see will lo o k like the windo w sho wn in Figure 5-11.
Figure 5-11: Script generates color-coded HTML references of any COM object. Yo u no w kno w that parentWindow is a pro perty and returns the referenc e to ano ther o bjec t: IHTMLWindow2. Yo u do n’t kno w this o bjec t? Let’s lo o k it up. In yo ur do c umentatio n fo lder mshtml, lo o k fo r IHTMLWindow2.htm. Open it. Open the View menu and switc h to Details view. No w yo u c an so rt the filenames with a c lic k o n the c o lumn header. [Ctrl] + [+] (o n the numeric keypad) resizes the c o lumn widths so everything is nic ely in view. Unfo rtunately, it’s empty. IHTMLWindow2 just refers to the interfac e. This is why it starts with “I.” To see the real desc riptio n, lo o k fo r HTMLWindow2 and o pen this file instead. As yo u see, pio neering in Windo ws sec rets is a lo t like an adventure game. Fro m no w o n, whenever yo u lo o k fo r an o bjec t name starting with “I,” also lo o k fo r it witho ut the “I.” Whenever yo u lo o k fo r an o bjec t name no t starting with an “I,” also lo o k fo r the “I” versio n.
Chapte r 5 : Us ing Inte rne t Explo re r as the Output Windo w
183
■
■
Lo o k up the sc reen pro perty used in the sc ripts abo ve:
Figure 5-12: Screen property returns a reference to IHTMLScreen object. Interesting: Sc reen o pens yet ano ther do o r, this time referring to an o bjec t named IHTMLScreen. Searc h fo r HTMLScreen in yo ur do c umentatio n fo lder, and yo u finally see all the sc reen info rmatio n available (see Figure 5-13).
Figure 5-13: HTMLScreen object contains us eful information about s creen. There it is: availWidth, a lo ng integer. And it’s no t the o nly info rmatio n. The sc reen o bjec t has a lo t mo re to o ffer, and yo u no w kno w ho w to “walk” the o bjec t hierarc hy until yo u reac h the info rmatio n yo u need. The sc reen o bjec t ac tually uses two different pro perties fo r the sc reen reso lutio n. availWidth and availHeight repo rt the available spac e (minus any do c ked bars like the taskbar). width and height, in c o ntrast, return the physic al sc reen reso lutio n. It may take so me time befo re yo u fully apprec iate the sc o pe o f what yo u have just disc o vered. The info rmatio n yo u just retrieved and the strategies yo u learned apply to any COM o bjec t yo u may stumble into . In additio n, yo u c an use all the HTMLDocument features in regular Web pages, to o . Just wrap yo ur sc ript c o de into blo c ks (see the example belo w). Pro vided yo ur c usto mers use the IE to view yo ur page, yo u c an no w determine their c urrent sc reen reso lutio ns and sc ale yo ur Web page ac c o rdingly. Ho wever, always remember that different bro wsers use their o wn o bjec t mo dels. I’d lo ve to dive into mo re DHTML, but will leave this to yo u instead. Yo u no w kno w all the nec essary to o ls and strategies to c o ntinue disc o vering sec rets o n yo ur o wn, so feel free to experiment. As a final treat, take a lo o k at the fo llo wing sc ripts. They take advantage o f the undo c umented print feature that Internet Explo rer 5 and abo ve bro ught alo ng. While it will remain undo c umented to mo st o thers, yo u no w have auto matic ally generated do c umentatio n fo r even the mo st hidden away func tio n. ‘ 5-13.VBS url = InputBox(“Enter name of web page!”,,”http://www.microsoft.com”)
184
Part I: Sc ripting Kic ks tart
■
■
‘ surf to website: set ie = CreateObject(“InternetExplorer.Application”) ie.navigate url ‘ wait for page to be loaded do loop while ie.ReadyState4 ie.visible = true answer = MsgBox(“Do you want to print this page?”, vbYesNo) if answer=vbYes then ie.document.parentWindow.print end if
Even mo re valuable: the exac t same tec hnique wo rks in plain HTML files, to o :
Hello World!
So , yo u finally c an add a c o nvenient Print butto n to yo ur Web pages. It will o nly wo rk when viewed with Internet Explo rer 5 and abo ve, so yo u may want to generate the print butto n dynamic ally inside a sc ript pro c edure to make sure it will o nly appear when printing is suppo rted.
Summary Internet Explo rer is a perfec t sc ript c o mpanio n and c an serve as the Sc ripting Ho st o utput windo w. It’s easy to o pen an IE windo w and o utput text into it while the sc ript runs. HTML elements c an also be tied to sc ript pro c edures so a butto n c lic k invo kes so me sc ript func tio nality. All this is po ssible o nly with a deep understanding o f the IE DHTML o bjec t mo del. This c hapter sho wed yo u ho w to auto matic ally extrac t all details fro m the TypeLibrary and searc h fo r mo re undo c umented c o mmands. Yo u c an, fo r example, print Web pages by pro viding the appro priate print butto n.
Chapte r 6
Using System Dialog Boxes In This Chapter 䊳 Take advantage o f the built-in system dialo g bo xes to ask fo r file names,
c o lo rs, and fo nts 䊳 Get ac c ess to the hidden Fo lder Pic ker dialo g bo x and use it to ask fo r
fo lders and files 䊳 Get ac c ess to the hidden Ic o n Pic ker and display ic o ns sto red in any file 䊳 Create yo ur o wn dialo g bo xes and display c usto m lists fo r selec tio n 䊳 Use the internal ListView element to quic kly so rt lists 䊳 Learn ho w to c all undo c umented API func tio ns 䊳 Co nvert strings between ANSI and UNICODE 䊳 Write c o de that runs o n all Windo ws versio ns
W
indo ws already c o ntains a ric h set o f system dialo g bo xes to ask fo r file names, c o lo rs, fo nts, and mo re. To spic e up yo ur arsenal o f dialo g bo xes, all yo u need is a way to ac c ess tho se dialo g bo xes. In additio n, Visual Basic c o ntains very versatile dialo g bo x elements. The ListView element, fo r example, allo ws yo u to display lists and so rt them in a matter o f sec o nds. The ProgressBar element graphic ally indic ates the pro gress. All yo u need to do is wrap tho se func tio ns to make them ac c essible by sc ript. In this c hapter, yo u’ll build yo ur o wn COM o bjec ts that pro vide ac c ess to all o f these c o o l features whenever yo ur sc ripts need them.
Where Do System Dialog Boxes Come From? Did yo u ever wo nder why standard dialo g bo xes always lo o k almo st the same, no matter whic h so ftware yo u use? They are pro vided by Windo ws to give all so ftware the same lo o k and feel.
186
Part I: Sc ripting Kic ks tart
■
■
It’s c o mpletely up to yo u — yo u c an happily ac c ept the o ffer and use the built-in system dialo g bo xes, o r yo u c an be an individualist and design yo ur dialo g bo xes fro m sc ratc h (as o utlined in Chapter 4). It may be a go o d idea to stic k to the system dialo g bo xes whenever po ssible, tho ugh. Yo ur users apprec iate the pro fessio nal lo o k, and yo ur sc ripts also auto matic ally use the mo st up-to -date dialo g bo xes. This means that if users run yo ur sc ript o n a Windo ws 2000 mac hine, they’ll get the new Windo ws 2000 lo o k and feel witho ut a single c hange in yo ur sc ript c o de. Even the mo st so phistic ated selfdefined dialo g bo xes start lo o king dull and ugly after a c o uple o f years, and they lac k impo rtant features added to later system dialo g bo xes. Mic ro so ft has pro vided a COM o bjec t to easily ac c ess the standard dialo g bo xes. It’s c alled MSComDlg.CommonDialog. Unfo rtunately, this o bjec t is no t part o f Windo ws. Instead, so ftware pac kages like Mic ro so ft Offic e o r Visual Basic Co ntro l Creatio n Editio n bring it alo ng. Just take a lo o k in the sc ripto bjec ts.txt file yo u generated in Chapter 3 to see whether this o bjec t is installed o n yo ur system. Yo u c an also use the fo llo wing sc ript to find o ut: ‘ 6-1.VBS ‘ turn off error handling: on error resume next ‘ try to access common dialogs: set comdlg = CreateObject(“MSComDlg.CommonDialog”) ‘ check whether error was raised: if err.number=0 then MsgBox “Common Dialog COM object available!” else MsgBox “Common Dialog COM object missing!” end if
MSComDlg.CommonDialog is no t abso lutely nec essary to display the system dialo g bo xes. It’s just a wrapper that takes c are o f all the dirty API handling usually invo lved when c alling system dialo g bo xes direc tly. Yo u c an display system dialo g bo xes witho ut MSComDlg.CommonDialog when yo u pro vide yo ur o wn wrapper. Belo w, yo u’ll find examples fo r c usto m wrappers that pro vide ac c ess to o ther system dialo g bo xes.
Opening system dialog boxes Is the Common Dialog COM o bjec t available o n yo ur system? Great! Then yo u c an o pen any system dialo g bo x entirely by sc ript. Even if MSComDlg.CommonDialog isn’t registered o n yo ur system, it might still be there. Visual Basic CCE brings it alo ng and redistributes it with all yo ur COM o bjec ts. A little later in this c hapter, I’ll sho w yo u ho w to o pen system dialo g bo xes using yo ur o wn COM o bjec ts. Ho wever, the fo llo wing sc ripts do require MSComDlg.CommonDialog to be registered o n yo ur system.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
187
■
■
To ask fo r a filename, use the fo llo wing sc ript: ‘ 6-2.VBS whichone = OpenFile(“Choose a File!”, “C:\”, _ “Everything|*.*|Text Files|*.TXT|Word-Documents|*.DOC”, 2, 0) MsgBox “Your choice: “ & whichone function OpenFile(title, dir, filter, index, flags) set comdlg = CreateObject(“MSComDlg.CommonDialog”) if filter = “” then filter = “All Files|*.*” end if ‘ initialize all dialog properties: comdlg.filter = filter comdlg.FilterIndex = index comdlg.Flags = flags comdlg.MaxFileSize = 260 comdlg.CancelError = false comdlg.DialogTitle = title comdlg.InitDir = dir ‘ open dialog box comdlg.ShowOpen ‘ return selection OpenFile = comdlg.filename end function
Windo ws will po p up its o ffic ial Open dialo g bo x and allo w yo u to selec t a file. Yo u’ll see that the Files o f type list c o ntains the file types yo ur sc ript spec ified. This way, yo ur sc ript c an easily limit the selec tio n o f available files to any file type yo u want. Yo u c an even c o mbine file types. If yo u want the dialo g bo x to sho w bo th WinWo rd do c uments and plain text files, use *.doc;*.txt as the selec to r. The dialo g bo x may lo o k different o n yo ur system. Windo ws always uses its standard dialo g bo xes, and their appearanc e varies with the Windo ws versio n.
Finding out more information about system dialog boxes System dialo g bo xes suppo rt many hidden flags and features. This means it’s a go o d idea to dec o de all the hidden info rmatio n nec essary to c o ntro l the dialo g bo xes. Just take a lo o k in the scriptobjects.txt file yo u generated in Chapter 4 and searc h fo r MSComDlg.CommonDialog. It reveals where the c o mmo n c o ntro ls are sto red — in this c ase, comdlg32.ocx. Yo u c an no w easily generate the hidden “o wner’s manual” using sc ript 5-12.VBS (see Figure 6-1). Just supply comdlg32.ocx as the name o f the TypeLibrary.
188
Part I: Sc ripting Kic ks tart
■
■
Yo u’ll find sample do c umentatio n o n the CD-ROM, at \info\documentation\ comdlg32. Use it if yo u c an’t generate the do c umentatio n yo urself.
Figure 6-1: Scripts generate full CommonDialog documentation for you.
Using Other System Dialog Boxes The Open dialo g bo x is just o ne o f many system dialo g bo xes. To find o ut abo ut the o thers, searc h fo r c o mmands that start with Show, as sho wn in Table 6-1:
Table 6-1
Common Dialog Box Scripting Commands
Command
Dialog Box
ShowOpen
Open File
ShowSave
Save File
ShowFont
Select Font
ShowColor
Select Color
ShowPrinter
Select Printer
ShowHelp
Show Help File
Eac h dialo g bo x has its o wn set o f flags yo u c an use to fine-tune its behavio r. The do c umentatio n file yo u just c reated lists different c o nstant sec tio ns and pro vides all the do c umentatio n.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
189
■
■
Managing flags and special behavior The sec tio n FileOpenConstants, fo r example, applies to bo th the ShowOpen and ShowSave dialo g bo xes. To get rid o f the Read Only c hec k bo x, use HideReadOnly alias 4 as a flag. To switc h to Multiselect mo de, use flag AllowMultiselect alias 512 o r &H200. Figure 6-2 lists all available c o nstants.
Figure 6-2: Find out all about the hidden dialog box flags . Yo u c an’t use the c o nstant names in yo ur sc ripts. Yo ur sc ripts have no way o f lo o king inside the TypeLibrary. Instead, use the numeric values. It’s up to yo u whether yo u prefer dec imal o r hexadec imal (&h...) no tatio n. Add all the flags’ values yo u want to use — 4 + &h200 o pens a multiselec t dialo g bo x witho ut the Read Only c hec k bo x. Flags wo rk in bo th ways. Yo u c an spec ify values to fine-tune the dialo g bo x befo re yo u display it and read flag values after display to find o ut abo ut selec tio ns the user has made. Fo r example, to find o ut whether the user c hec ked the Read Only c hec k bo x, yo u c an query the flags value. It will o nly c o ntain interesting info rmatio n if the user has selec ted a file. No t all o f the flags in the FileOpenConstants sec tio n apply to bo th Open and Save As dialo g bo xes.
190
Part I: Sc ripting Kic ks tart
■
■
This sc ript o pens a multiselec t dialo g bo x and returns all the selec ted files. It also repo rts whether o r no t the user has selec ted the Read Only c hec k bo x: ‘ 6-3.VBS flag = &h200 whichone = OpenFile(“Choose a File!”, “C:\”, “Everything|*.*|Text Files|*.TXT|Word-Documents|*.DOC”, 2, flag) MsgBox “Raw data returned: “ & whichone ‘ Split up multi selection result: ‘ space is used as separator: whichone = Split(whichone, “ “) ‘ field index 0 contains path information: path = whichone(0) ‘ list all the files: ‘ how many files were selected? filecount = UBound(whichone) if filecount=0 then ‘ just one file selected! MsgBox “You selected one file: “ & whichone(0) ‘ check status of Read Only checkbox ‘ is bit 1 set or cleared? ‘ works only if just one file was selected! MsgBox “Returned flag: “ & flag if (flag and 1) then ‘ (flag and 1)0, transforms to true ‘ bit is set! MsgBox “ReadOnly selected!” else MsgBox “ReadOnly not selected!” end if ‘ check whether selected file is of default type (txt) if (flag and 1024) then MsgBox “selected file is no txt file!” else MsgBox “selected file is of default type!” end if else ‘ more than one file selected! MsgBox “You selected “ & filecount & “ files!” for x = 1 to UBound(whichone) list = list & path & whichone(x) & vbCr next MsgBox list end if
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
191
■
■
function OpenFile(title, dir, filter, index, flags) set comdlg = CreateObject(“MSComDlg.CommonDialog”) comdlg.filter = filter comdlg.FilterIndex = index comdlg.Flags = flags comdlg.MaxFileSize = 260 comdlg.CancelError = false comdlg.DialogTitle = title comdlg.InitDir = dir ‘ set txt as default comdlg.DefaultExt = “txt” comdlg.ShowOpen OpenFile = comdlg.filename ‘ important: return flag status so your main script can ‘ check it: flags = comdlg.Flags end function
This sc ript demo nstrates many things at o nc e. Mo st impo rtant, it uses the returned flag value to c hec k whether c ertain c o nditio ns are met. Fo r example, the sc ript c hec ks whether o r no t the user has selec ted the ReadOnly c hec k bo x. This c hec k bo x is handled by value 1 ( ReadOnly). Ho wever, yo u c an’t go ahead and c hec k whether flag equals 1. After all, flag c o ntains a sum o f many po ssible values. Therefo re, yo u need to c hec k the bits. Chec king bits is muc h easier than it so unds. To find o ut whether 1 is set in flag, c hec k (flag and 1). If 1 isn’t set (and the ReadOnly c hec kbo x wasn’t selec ted), the result is 0. 0 always equals false, and any o ther number always equals true, so yo u c an write: if (flag and 1) then MsgBox “1 is set, ReadOnly is checked!” end if
Bo th the ReadOnly and the ExtensionDifferent flags are o nly used when exac tly o ne file is selec ted. If mo re than o ne file is selec ted, the flags are useless. In additio n, the sc ript demo nstrates ho w to reac t to multiple file selec tio ns. Flag AllowMultiselect (512/ &h200) allo ws yo u to selec t mo re than o ne file. Windo ws no w uses a spec ial versio n o f the dialo g bo x. In Multiselect mo de, spac es are used as separato rs between file names. Bec ause lo ng filenames c an c o ntain spac es, to o , the dialo g bo x c o nverts any file name with spac es to sho rt (DOS) file names. Windo ws 2000 wo rks very differently — filenames are enc lo sed in quo tes, and the multiselect Open dialo g bo x lo o ks just like the regular Open dialo g bo x. Yo u need to c hange yo ur sc ript c o de to c o rrec tly interpret the Windo ws 2000 results returned in multiselect mo de.
192
Part I: Sc ripting Kic ks tart
■
■
Picking a color The Co lo r dialo g bo x uses a c o mpletely different set o f flags. They are spec ified in the ColorConstants sec tio n. The flags no w c o ntro l whether the detailed c o lo r pic ker is visible and whether yo u c an spec ify an initial c o lo r (see Figure 6-3).
Figure 6-3: Take advantage of s pecial color flags to adjus t the Color dialog box. The easiest way to pro vide a c o lo r is by using hexadec imal no tatio n. Just use &h. This way, yo u c an easily spec ify the c o lo r values fo r red, green, and blue separately. Use 00 to FF fo r eac h c o lo r c o mpo nent, and add the values in the fo llo wing o rder: red, green, and blue. To use CC as red and 8C as green and 35 as blue, write &hCC8C35. The higher the values, the brighter the c o lo r. This is all yo u need to pic k a c o lo r: ‘ 6-4.VBS flag = 1+2 initialColor = &hff32ea color = OpenColor(initialColor, flag) MsgBox “Selected color: “ & hex(color) function OpenColor(initColor, flags) set comdlg = CreateObject(“MSComDlg.CommonDialog”) comdlg.Color = initColor comdlg.Flags = flags comdlg.ShowColor OpenColor = comdlg.Color end function
Flag 1 allo ws yo u to predefine the c o lo r, and flag 2 instruc ts the dialo g bo x to o pen the detail c o lo r pic ker (see Figure 6-4).
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
193
■
■
Figure 6-4: Control the color picker from your s cripts . If yo u do n’t spec ify an initial c o lo r, the brightness slider o n the right side is set to dark blac k by default. Bec ause all c o lo rs are no w blac k, it appears as if yo u c o uldn’t selec t a c o lo r. In truth, yo u just need to inc rease the brightness. It’s a lo t mo re elegant to set an initial brightness o f abo ve 0. To c hange brightness, use gray values as initial c o lo r. Gray values always use the same numbers fo r red, green, and blue. So , c ho o se &h888888 o r &hCCCCCC o r &h3D3D3D as the initial c o lo r.
Wrapping System Dialog Boxes There are a number o f go o d reaso ns why yo u sho uld wrap system dialo g bo xes in self-defined COM o bjec ts instead o f using MSComDlg.CommonDialog direc tly. Fo r o ne, wrapping dialo g bo xes will make them wo rk even o n systems where MSComDlg.CommonDialog is no t yet installed. Sec o nd, yo u no w c an define o ptio nal parameters. This way, yo u c an c all yo ur dialo g bo xes with defaults o r spec ify as many details as yo u want. Wrapping dialo g bo xes makes them muc h easier to use and mo re dependable, to o . Wrapping system dialo g bo xes has two mo re advantages. First, yo ur sc ript isn’t c luttered with dialo g bo x-related c o de. It lo o ks a lo t c leaner. Sec o nd, yo u do n’t need to wo rry anymo re abo ut variables yo u used inside yo ur dialo g bo x pro c edures. Rec all fro m Chapter 3 the disc ussio n abo ut private and public variables and ho w they c an interfere with eac h o ther.
Creating your own system dialog boxes To wrap system dialo g bo xes, just start the Visual Basic CCE (refer to Chapter 4 if this so unds unfamiliar to yo u). Yo u’ll find the entire pro jec t o n the c o mpanio n CD. Just o pen \components\ comdlg\comdlg.vbp. To o lazy to c reate the COM o bjec t yo urself? Kic k bac k and c all \install\comdlg\setup.exe.
194
Part I: Sc ripting Kic ks tart
■
■
Create a new Ac tiveX Pro jec t. Next, yo u need to insert a referenc e to the c o mmo n dialo g bo xes befo re yo u c an start using them. Open the View menu and c ho o se To o lbar to o pen the to o lbar windo w. Right-c lic k the to o lbar, and c ho o se Co mpo nents (see Figure 6-5).
Figure 6-5: Include additional control elements in your VB CCE toolbox. Yo u no w see a list o f o ptio nal c o mpo nents. Lo o k fo r Mic ro so ft Co mmo n Dialo g Co ntro l and c lic k the c hec k bo x. Then c lic k OK. Is Mic ro so ft Co mmo n Dialo g Co ntro l missing in yo ur list? Clic k Bro wse and searc h fo r comdlg32.ocx manually. The CCE inserts a new c o ntro l into the to o lbo x windo w: the c o mmo n c o ntro ls. Do uble-c lic k the new ic o n to plac e a c o py o n yo ur UserControl (see Figure 6-6). No w it’s time to assign a name to yo ur pro jec t and yo ur UserControl. Yo u might c all them dlg.tools. (Fo r tips o n ho w to name yo ur pro jec t, refer to Chapter 4.)
Getting access to the system dialog boxes Yo u’re all set. Just start to develo p the func tio ns yo u want to make available thro ugh yo ur COM o bjec t. Yo u do n’t need CreateObject anymo re. The c o mmo n c o ntro ls are already plac ed o n yo ur UserControl, and yo u c an ac c ess them by name. It’s CommonControls1 by default.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s ■
195 ■
Figure 6-6: Place a copy of the CommonControl w rapper on your us er control. Ac tually, yo ur wrapper uses the same COM o bjec t that MSComDlg. CommonDialog used, to o . Ho wever, bec ause its func tio ns are no w integrated into yo ur COM o bjec t by “early binding” (this is what yo u did when yo u inserted the c o mpo nent into yo ur to o lbar windo w), there need no t be any MSComDlg.CommonDialog Registry entries anymo re. Yo u still need comdlg32.dll, tho ugh. If yo u plan to distribute yo ur dialo g bo x wrapper c o ntro l, make sure yo u also distribute comdlg. The best way is to use the Applic atio n Wizard as o utlined in Chapter 4. First, let’s develo p an easy func tio n wrapper fo r ShowOpen: Option Explicit Function Optional Optional Optional
ShowOpen(Optional ByVal initdir As String, _ ByVal title As String, Optional flags As Variant, _ ByVal filter As String = “all files|*.*”, _ ByVal index As Long = 1) As String
If Not IsMissing(flags) Then CommonDialog1.flags = flags End If If Not IsMissing(initdir) Then CommonDialog1.initdir = initdir End If If Not IsMissing(title) Then CommonDialog1.DialogTitle = title End If CommonDialog1.filter = filter CommonDialog1.FilterIndex = index CommonDialog1.ShowOpen ShowOpen = CommonDialog1.filename
196
Part I: Sc ripting Kic ks tart
■
■
If Not IsMissing(flags) Then flags = CommonDialog1.flags End If End Function
Yo ur COM o bjec t makes heavy use o f o ptio nal arguments. A little later in the c hapter, yo u’ll see ho w muc h easier they make yo ur life. No te that so me o ptio nal arguments have default values; o thers do no t. Always use isMissing when dealing with arguments witho ut default value. Also no te ho w the func tio n returns flag values. Changed flag values will o nly be returned if the user has supplied a flag variable in the first plac e. To be able to return the c hanged flags thro ugh the flag arguments, they need to be dec lared as ByRef. This way, sc ript and COM o bjec t bo th share the same variable. Whenever yo u use ByRef, use Variant as variable type. If yo u do n’t, yo u will need to c o nvert variable types befo re yo u c an c all yo ur COM func tio ns. Remember, VBSc ript always uses variants if no t to ld o therwise. To use an argument ByRef, either spec ify ByRef instead o f ByVal, o r do n’t spec ify either o ne. ByRef is the default. Co mpile yo ur pro jec t: Open the File menu and c ho o se Make dlg.ocx (see Figure 6-7). Next, enjo y yo ur new c o mmand: ‘ 6-5.VBS set dlg = CreateObject(“dlg.tools”) MsgBox dlg.ShowOpen
Figure 6-7: Des ign your dialog box w rapper and then compile, us ing Make.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
197
■
■
Just fo r the fun o f it, c o mpare this sc ript to the previo us o nes. Ho w muc h c leaner and mo re straightfo rward things are no w. And thanks to the o ptio nal arguments, yo u are still able to do all the tweaking yo u disc o vered abo ve: ‘ 6-6.VBS set dlg = CreateObject(“dlg.tools”) flag = 0 whichone = dlg.ShowOpen(“C:\”, “Choose a File!”, _ flag, “Everything|*.*|Text Files|*.TXT|Word-Documents|*.DOC”, 2) MsgBox “Selected file: “ & whichone MsgBox “Returned flags: “ & flag
Using the Folder Picker Did yo u no tic e that no ne o f the system dialo g bo xes managed by the c o mmo n c o ntro ls allo ws yo u to selec t a fo lder? This is bad, but fo rtunately Mic ro so ft has added ano ther dialo g bo x just fo r this purpo se. It’s part o f Windo ws 98 and Windo ws 2000. On o lder Windo ws versio ns, just install Internet Explo rer 4 . It brings alo ng the Shell.Application COM o bjec t. This o bjec t c o ntains the Fo lder Pic ker. Ho wever, fo r so me strange reaso n, Internet Explo rer 5 do esn’t bring alo ng the Shell.Application-Object. Chec k o ut the new dialo g bo x: ‘ 6-7.VBS set shell = CreateObject(“Shell.Application”) set result = shell.BrowseForFolder(0, “Select a folder!”, 0, “C:\”) MsgBox TypeName(result) MsgBox “You selected: “ & result.Title
The sc ript c alls the hidden BrowseForFolder metho d to o pen the dialo g bo x (see Figure 6-8). In return, it rec eives an o bjec t referenc e to a Folder2 o bjec t (it’s c alled Fo lder o n o lder Windo ws versio ns). Yo u c an retrieve the name o f the selec ted fo lder using the Title pro perty. This all lo o ks a bit strange. Even wo rse, there is no way to retrieve the full path name. So , this dialo g bo x seems pretty useless. The mo re c o mmo n system dialo g bo xes are managed by a COM o bjec t c alled comdlg32.ocx, o r the c o mmo n dialo gs. This o bjec t wraps a lo t o f the internal tec hniques nec essary to handle the dialo g bo xes. Shell.Application o ffers a wrapper fo r the Fo lder Pic ker dialo g: BrowseForFolder. Ho wever, this wrapper was never intended fo r public use. It’s targeted to wards the internal Web view requirements o f the Windo ws shell, and it’s no t suited fo r general path inquiries. Therefo re, yo u need to write yo ur o wn Fo lder Pic ker wrapper and ac c ess the dialo g bo x direc tly using very basic API func tio ns.
198
Part I: Sc ripting Kic ks tart
■
■
Figure 6-8: BrowseForFolder is a s pecial dialog box w rapper us ed by the s hell.
Accessing Folder Picker through API functions To fully explo it all the fasc inating func tio ns hidden in the Fo lder Pic ker, yo u just need to wrap it as a COM o bjec t. So , start yo ur VB CCE and c reate a new Ac tiveX Pro jec t (refer to Chapter 4 if this so unds unfamiliar to yo u). As always, yo u c an find the c o mplete pro jec t o n CD by lo o king at \components\folderpicker\pickfolder.vbp. If yo u are no t interested in the internal mec hanic s and just want to use the Fo lder Pic ker, install the prepared so ftware pac kage — \install\folderpicker\setup.exe. This is the “wrapper” c o de: Option Explicit ‘ define a custom structure Private Type BrowseInfo hwndOwner As Long pIDLRoot As Long pszDisplayName As Long lpszTitle As Long ulFlags As Long lpfnCallback As Long lParam As Long iImage As Long End Type ‘ declare API functions we need: Private Declare Function GetDesktopWindow Lib “User32” () As Long Private Declare Function SHBrowseForFolder Lib “shell32” _ (lpbi As BrowseInfo) As Long Private Declare Function SHGetPathFromIDList Lib “shell32” _ (ByVal pidList As Long, ByVal lpBuffer As String) As Long
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
199
■
■
Private Declare Function SHGetSpecialFolderLocation Lib _ “shell32” (ByVal hwndOwner As Long, ByVal nFolder As Long, _ ListId As Long) As Long Private Declare Function SHSimpleIDListFromPath Lib “shell32” _ Alias “#162” (ByVal szPath As String) As Long Private Declare Sub CoTaskMemFree Lib “ole32.dll” (ByVal hMem As Long) Public Function BrowseForFolder(ByVal initdir As Variant, _ Optional ByVal message As String = “Choose!”, _ Optional ByVal flags As Long) As String Dim rootID As Long Dim PIDL As Long Dim Path As String Dim nullPos As Integer Dim BInfo As BrowseInfo Dim myMessage As String ‘ convert the message string to ANSI code: myMessage = StrConv(message, vbFromUnicode) ‘ check whether user specified a path or a code If VarType(initdir) = vbString Then ‘ it’s a path! ‘ use undocumented function to create IDList ‘ convert path string to Unicode: rootID = SHSimpleIDListFromPath(StrConv(initdir, vbUnicode)) Else ‘ it’s a virtual system folder code ‘ get “real” path SHGetSpecialFolderLocation GetDesktopWindow, initdir, rootID End If ‘ fill out the BrowseInfo structure: BInfo.hwndOwner = GetDesktopWindow BInfo.ulFlags = flags ‘ fill in the address of your ANSI message string: BInfo.lpszTitle = StrPtr(myMessage) ‘ is there a valid rootID? Fill it in! If rootID 0 Then BInfo.pIDLRoot = rootID ‘ open the dialog box, retrieve a PIDL ‘ PIDL is internal identifier for selected folder: PIDL = SHBrowseForFolder(BInfo) ‘ was there a PIDL returned? Transform to path: If PIDL 0 Then ‘ reserve space for path name Path = String(260, 0) ‘ return path name from PIDL: SHGetPathFromIDList PIDL, Path ‘ manually release the memory: Call CoTaskMemFree(PIDL) Call CoTaskMemFree(rootID)
200
Part I: Sc ripting Kic ks tart
■
■
‘ cut off string at char 0: nullPos = InStr(Path, vbNullChar) If nullPos 0 Then Path = Left(Path, nullPos - 1) End If End If ‘ return path: BrowseForFolder = Path End Function
Next, assign a name to yo ur pro jec t. Call it folder.tools. No w yo u c an c o mpile it: Open the File menu and c ho o se Make folder.ocx. I’ll sho w yo u in a minute ho w all o f this wo rks. This wrapper emplo ys all the hidden tec hniques nec essary to c all internal system func tio ns. Let’s first c o nc entrate o n the prac tic al aspec ts, so yo u c an safely steal yo urself away to the next c hapter anytime yo u feel like it. No w, it’s extremely simple to ac c ess the Fo lder Pic ker. Lo o k fo r yo urself: ‘ 6-8.VBS set picker = CreateObject(“folder.tools”) result = picker.BrowseForFolder(“C:\”, “Hey, select a folder!”) MsgBox “You selected: “ & result
This time, yo u rec eive the full path name (see Figure 6-9).
Figure 6-9: Your ow n BrowseForFolder w rapper finally returns the correct filename.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
201
■
■
There’s a lo t mo re yo u c an do with yo ur new func tio n. Instead o f spec ifying a path name, try using a number. BrowseForFolder c an also o pen any virtual system fo lder, and BrowseForFolder(2) wo uld o pen yo ur pro gram gro ups. The next sc ript lets yo u play aro und. Yo ur wrapper o nly puts a thin layer aro und the ho stile API wo rld. Fo r example, the wrapper do es no t c hec k whether the path yo u spec ify really exists. Spec ifying illegal path names may pro duc e strange results — to say the least. ‘ 6-9.VBS set picker = CreateObject(“folder.tools”) do showwhat = InputBox(“Enter number or path!”,,2) if not showwhat = vbEmpty then if isNumeric(showwhat) then idnr = Fix(showwhat) result = picker.BrowseForFolder(idnr, “ID-Number: “ _ & idnr) answer = MsgBox(result & vbCr & “Again?”, vbYesNo) else result = picker.BrowseForFolder(showwhat, _ “Showing Path”) answer = MsgBox(result & vbCr & “Again?”, vbYesNo) end if else answer = vbNo end if loop until answer = vbNo
Yo u’ll so o n disc o ver that BrowseForFolder c an ac c ess just abo ut any virtual Windo ws fo lder. Ho wever, bec ause the dialo g bo x c an o nly display fo lders, yo u c an’t see files o r individual c o ntent. No t yet. Yo u need two things to fully explo it BrowseForFolder. First, yo u need a list o f all the c o des and available virtual fo lders. Next, yo u need a list o f all the spec ial flags BrowseForFolder suppo rts. But where do yo u get them?
Automatically documenting all secret Folder Picker options Just ask the appro priate TypeLibrary. The API func tio ns that yo ur wrapper uses do esn’t have a TypeLibrary, but the Shell.Application o bjec t uses the same fundamental API func tio ns, so yo u c an find a lo t o f the info rmatio n in the Shell.Application TypeLibrary. Take a lo o k into the scriptobjects.txt file yo u generated in Chapter 3. Yo u’ll quic kly disc o ver that Shell.Application sto res type info rmatio n in either shdocvw.dll o r shell32.dll.
202
Part I: Sc ripting Kic ks tart
■
■
No t to o lo ng ago , Shell.Application and the Web view were just c ute add-o ns to Windo ws. Web view wasn’t really integrated into Windo ws at this stage — instead, it was left to Internet Explo rer to handle it. Windo ws 98 featured the integrated Internet Explo rer, but it was still up to the integrated Internet Explo rer to take c are o f Web view. Bac k then, Web view was handled internally by shdocvw.dll. Beginning with Windo ws 2000, Mic ro so ft has inc o rpo rated Web view into the c o re system func tio nality. Fo r this reaso n, o n Windo ws 2000, Web view (and its TypeLibrary) is integrated into shell32.dll. No bo dy wo uld dare kic k this .dll o ut o f the system. It’s the c o re o f the Windo ws user interfac e. If yo u haven’t do ne so already in Chapter 5, launc h sc ript 5-12.VBS and let it c reate the do c umentatio n fo r yo u. On Windo ws 2000, enter shell32.dll. On all o ther Windo ws versio ns, enter shdocvw.dll. Next, in yo ur do c umentatio n fo lder, lo o k fo r ShellSpecialFolderConstants. htm. There yo u’ll find yo ur list o f available virtual fo lders. No w yo u just need the Fo lder Pic ker flag values. Unfo rtunately, Shell. Application do esn’t make use o f the spec ial flags, so it do esn’t mentio n them. Here’s a table o f them fo r yo u.
Table 6-2
Folder Picker Special Flags
Flag
Description
1
Accept only file s ys tem folders
2
No netw ork folders
8
Accept only file s ys tem objects
&h10
Show text field for direct entry
&h1000
Show only computers
&h2000
Show only printers
&h4000
Show files or individual entries
This is all yo u need to also display individual files o r o ther elements. The fo llo wing sc ript displays yo ur Deskto p and then yo ur Co ntro l Panel c o ntent: ‘ 6-10.VBS set picker = CreateObject(“folder.tools”) result = picker.BrowseForFolder(0, “Desktop”, &h4000) MsgBox “You selected: “ & result result = picker.BrowseForFolder(3, “Control Panel”, &h4000) MsgBox “You selected: “ & result
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
203
■
■
Everything seems to wo rk fine. Onc e yo u selec t a c o ntro l panel item, tho ugh, yo ur BrowseForFolder func tio n wo n’t return a value. After so me rethinking, this is no surprise — yo ur wrapper func tio n explic itly uses the BrowseForFolder dialo g bo x to retrieve file names. Sinc e Co ntro l Panel items are no t files, BrowseForFolder c o rrec tly returns an empty value. Yo ur new BrowseForFolder func tio n is smart eno ugh, tho ugh, to translate virtual o bjec ts to their path names if it’s po ssible. Fo r example, c ho o se the Deskto p entry in the first dialo g bo x. Altho ugh Deskto p is a virtual fo lder, yo ur BrowseForFolder c o rrec tly identifies the fo lder yo ur deskto p c o ntent is sto red in.
Getting Access to the Hidden Icon Picker There’s o ne mo re system dialo g bo x, and it’s an impo rtant o ne: The Ic o n Pic ker c an display ic o ns sto red in files. It’s yo ur o nly way to present ic o n selec tio ns to yo ur users. To see the dialo g bo x in ac tio n, just fo llo w these steps:
1. Searc h fo r any link, then right-c lic k it and c ho o se Pro perties. 2. Next, c lic k the Change Ic o n butto n. There it is: yo ur Ic o n Pic ker dialo g bo x (see Figure 6-10). It may lo o k a little different depending o n yo ur Windo ws versio n.
Figure 6-10: Getting to know the hidden Icon Picker dialog box.
How to call undocumented shell functions Windo ws desperately tries to keep its Ic o n Pic ker dialo g bo x to itself. It’s no t do c umented anywhere, and there’s no t even a named API func tio n to c all the dialo g bo x. But, with a c o uple o f tric ks, yo u c an make it wo rk. After all, it must exist o r else Windo ws wo uldn’t be able to use it either.
204
Part I: Sc ripting Kic ks tart
■
■
After so me researc h, it turns o ut that the Ic o n Pic ker dialo g bo x is c o ntained in shell32.dll. Its func tio n uses o rdinal #62 thro ugho ut all the 32-bit Windo ws versio ns, so it’s fairly easy to design an appro priate dec lare statement to c all the Ic o n Pic ker. Ho wever, bec ause this func tio n is undo c umented, Mic ro so ft do esn’t take any effo rt to keep things c o nsistent. On Windo ws 9.x and Windo ws NT, the Ic o n Pic ker ac c epts ANSI strings as arguments. With the advent o f Windo ws 2000, many o f the undo c umented func tio ns switc h to Unic o de strings witho ut warning. So , it’s up to yo ur wrapper to determine the Windo ws versio n and c o nvert the string arguments appro priately. I’ve do ne all o f this fo r yo u. The so urc e c o de is a vivid example o f develo ping c ro ss-Windo ws-versio n COM o bjec ts, and the isWin2000 func tio n c an be useful fo r o ther pro jec ts, as well. Just install iconpicker.tool fro m the CD at \install\iconpick\setup.exe. Yo u c an also lo ad the c o mplete pro jec t and c o mpile it yo urself by using \components\iconpick\iconpick.vbp. Option Explicit ‘ structure needed to retrieve OS version: Private Type OSVERSIONINFO size As Long majorver As Long minorver As Long build As Long platformid As Long CSDVersion As String * 128 End Type ‘ declare undocumented icon dialog function: Private Declare Function IconDialog Lib “shell32.dll” _ Alias “#62” (ByVal hwnd As Long, ByVal lpStrFile As Long, _ ByVal maxfilelen As Long, IconIndex As Long) As Boolean Private Declare Function ExtractIconEx Lib “shell32.dll” _ Alias “ExtractIconExA” (ByVal lpszFile As String, _ ByVal nIconIndex As Long, phIconLarge As Long, _ phIconSmall As Long, ByVal nIcons As Long) As Long Private Declare Function GetVersionEx Lib “kernel32.dll” _ Alias “GetVersionExA” (lpVersionInfo As OSVERSIONINFO) As Long
Public Function PickIcon(ByVal path As String, _ Optional ByVal index As Long = 0) As String Dim ok As Boolean Dim filestr As String Dim convert As Boolean ‘ build a string of 260 characters (max path len) ‘ that contains the path of the icon library ‘ you want to display filestr = path & Chr(0) & String(260 - Len(path) - 1, 0) ‘ if not Win2000, string needs to be ANSI:
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s ■
205 ■
If Not isWin2000 Then filestr = StrConv(filestr, vbFromUnicode) End If ‘ call undocumented dialog box: ok = IconDialog(0&, StrPtr(filestr), 260&, index) ‘ did user select an icon? If ok Then ‘ if not Win2000, ANSI-string needs to be reconverted ‘ back to Unicode If Not isWin2000 Then filestr = StrConv(filestr, vbUnicode) End If ‘ resize string - cut off anything beyond terminating ‘ chr(0) character: filestr = Left(filestr, InStr(filestr, Chr(0)) - 1) ‘ add index of selected icon: PickIcon = filestr & “,” & index Else PickIcon = “” End If End Function Public Function CountIcons(ByVal path As String) As Long ‘ counts number of icons in given file: CountIcons = ExtractIconEx(path, -1, 0, 0, 0) End Function Public Function isWin2000() As Boolean ‘ checks whether OS is Win2000: Dim osinfo As OSVERSIONINFO osinfo.size = Len(osinfo) GetVersionEx osinfo If (osinfo.platformid >= 2 And osinfo.majorver >= 5) Then isWin2000 = True Else isWin2000 = False End If End Function
Displaying icons hidden in the system files The new Ic o n Pic ker is extremely versatile, and yo u’ll find many useful examples in Chapter 23. Fo r no w, the fo llo wing sc ript examines all yo ur system files and displays the ic o ns in the Ic o n Pic ker dialo g bo x (see Figure 6-12). No w selec t an ic o n. The sc ript tells yo u the exac t syntax o f ho w to ac c ess the ic o n yo u selec ted. This syntax bec o mes impo rtant o nc e yo u assign ic o ns via Registry keys o r sc ript c o mmands.
206
Part I: Sc ripting Kic ks tart
■
■
‘ 6-11.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set icon = CreateObject(“iconpicker.tool”) ‘ get access to system folder set sysfolder = fs.GetSpecialFolder(1) ‘ enumerate all files for each file in sysfolder.files ‘ how many icons are stored in file? icons = icon.CountIcons(file.path) ‘ more than 2 files? Show them! if icons>2 then selection = icon.PickIcon(file.path) ‘ did the user select an icon? if selection=”” then msg = “You did not select an icon.” else msg = “This is how you access the icon: “ & vbCr msg = msg & selection end if msg = msg & vbCr & “Continue?” answer = MsgBox(msg, vbQuestion + vbOkCancel) if answer = vbCancel then exit for end if next MsgBox “Done!”
Figure 6-11: Dis play icon res ources s tored in s ys tem files .
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
207
■
■
Displaying and Sorting Lists VBSc ript is unable to display lists, no t to mentio n so rt them. Altho ugh so rting is an impo rtant func tio nality, yo u are left alo ne and need to reso rt to slo w c usto m VBSc ript pro c edures. Do yo u really have to live with these limits? No way. A lo o k at the Windo ws Explo rer pro ves that there must be so me kind o f List view and so rting c apability built into Windo ws. Ho w else wo uld the Explo rer be able to display fo lder c o ntents as Details view and allo w yo u to so rt tho se lists in any way yo u please? The answer is c o ntained in the ListView dialo g bo x c o mpo nent. This c o mpo nent c an easily display huge lists and so rt them by any c atego ry yo u spec ify. All yo u need is a way to ac c ess the ListView element. The ListView element was o riginally designed to display lists. Yo u do n’t need to , tho ugh. It’s up to yo u — if yo u prefer, yo u c an use the hide the ListView element entirely. In this c ase, it will o nly serve to so rt lists.
Getting Aacess to the ListView VBSc ript has no way o f ac c essing the ListView element direc tly. Yo u c an, ho wever, wrap the ListView element as a COM o bjec t. I have do ne it fo r yo u. The full so urc e c o de is pro vided o n the c o mpanio n CD. Just o pen \components\listview\listview.vbp. Either o pen the pro jec t and c o mpile it yo urself, o r run \install\listview\setup.ocx. Bo th ways will register the listview.tool c o mpo nent.
Designing and sorting lists Chec k o ut ho w po werful the new ListView element really is. The fo llo wing sc ript reads in all files sto red in the ro o t fo lder o f drive C:\. Then, the files are displayed in the ListView element. Yo u c an so rt eac h c o lumn by c lic king o n the c o lumn heads. Ano ther c lic k so rts in the o ppo site direc tio n. Yo u c an even find o ut whic h file(s) the user has selec ted. Just selec t o ne o r mo re files in the ListView and then c lic k OK. Yo ur sc ript will repo rt the file details. ‘ 6-12.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set lview = CreateObject(“listview.tool”) ‘ open sample folder: set folder = fs.GetFolder(“C:\”)
design some column headers AddHeader name, size in percent, alignment 0 = left (default) 1 = right 2 = center
lview.AddHeader “File name”, 50 lview.AddHeader “Size”, 20, 1 lview.AddHeader “Type”, 30 ‘ read files into ListView: for each file in folder.files lview.AddItem file.name lview.AddSubitem 1, AlignNumber(file.size) lview.AddSubitem 2, file.type next ‘ sort result ‘ 0 = first column ‘ 1 = second column... lview.Sort 0 ‘ enable multiselect lview.MultiSelect = true ‘ show ListView Form set result = lview.Show(“Files on Drive C:\”) list = “Selected items: “ & result.Count for each entry in result list = list & entry & vbCr next MsgBox list function AlignNumber(number) size = len(CStr(number)) AlignNumber = Space(20-size) & number end function
The new ListView dialo g bo x allo ws fo r bo th single- and multiselec tio n. Use the MultiSelect pro perty to determine whether the user will be able to selec t mo re than o ne file. The ListView sto res String values. To be able to so rt numeric c o ntent, the sc ript uses the func tio n AlignNumber to pad the numeric strings with spac es. This way, numbers will be so rted c o rrec tly. It’s easy to get rid o f the padding spac es: Onc e a number is returned, just use LTrim to eliminate the leading spac es.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
209
■
■
Figure 6-12: Us ing your ow n dialog boxes to dis play lis ts and s elect entries . Yo ur new listview.tool c o mpo nent o ffers a ric h set o f o ptio ns. Use the labelOK and labelCancel pro perties to c hange the labels o n the butto ns. Yo u c an manually so rt c o lumns befo re yo u display the dialo g bo x by using So rt. With the help o f the MultiEdit pro perty, yo u c an even display the same dialo g bo x mo re than o nc e and delete entries. When defining c o lumn headers using AddHeader, yo u c an spec ify up to three arguments: the name o f the c o lumn header, its size in perc ent, and the alignment type as do c umented in the sc ript. The first c o lumn always has to be left-aligned, whic h is also the default. The next sc ript demo nstrates the advanc ed o ptio ns. It will delete the selec ted entry fro m the list and c o ntinue to display the list until the user hits Canc el. Whenever yo u selec t an entry and either c lic k OK o r press [Enter], the sc ript displays detailed info rmatio n abo ut this file and remo ves it fro m its list. Then it redisplays the list. The selec ted items are no lo nger available. This is po ssible bec ause the sc ript enables the MultiEdit pro perty. In MultiEdit mo de, the dialo g bo x isn’t destro yed, but hidden, and it c an reappear anytime yo u use Show. In additio n, in MultiEdit mo de, the dialo g bo x returns additio nal info rmatio n: The internal key name o f the selec ted items is appended to the list info rmatio n and returned. With this key, yo u c an remo ve list entries using RemoveItem. ‘ 6-13.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set lview = CreateObject(“listview.tool”)
210
Part I: Sc ripting Kic ks tart
■
■
set folder = fs.GetFolder(“C:\”) lview.width = 600 lview.height = 400 lview.AddHeader “File name”, 50 lview.AddHeader “Size”, 20, 1 lview.AddHeader “Type”, 30 ‘ read files into ListView: for each file in folder.files lview.AddItem file.name lview.AddSubitem 1, AlignNumber(file.size) lview.AddSubitem 2, file.type next ‘ enable MultiEdit feature lview.MultiEdit = true ‘ show ListView Form until user hits Cancel: do set result = lview.Show(“Files on Drive C:\”) ‘ did the user select something? if result.Count=0 then ‘ no, exit exit do end if ‘ split result: details = Split(result.Item(1), vbCrLf) ‘ now msg = msg = & vbCr msg = msg =
the information is contained in an array “You selected: “ & details(0) & vbCr msg & “File Size is “ & ltrim(details(1)) & “ Bytes.” _ msg & “File Type is “ & details(2) & vbCr msg & “Internal ListView item key is: “ & details(3)
MsgBox msg, vbInformation lview.removeItem details(3) loop MsgBox “Done!” function AlignNumber(number) size = len(CStr(number)) AlignNumber = Space(20-size) & number end function
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
211
■
■
Sorting lists without dialog boxes The great so rting c apabilities that the ListView o ffers c an be used separately, to o . This way, yo u c an easily so rt any kind o f list (see Figure 6-13). Yo u do n’t need to display the ListView dialo g bo x. Whenever yo u query the files in a fo lder, Windo ws returns them in the o rder they were o riginally saved. They are no t so rted. The fo llo wing sc ript demo nstrates ho w to build a file list and then have it so rted in the bac kgro und by yo ur ListView: ‘ 6-14.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set lview = CreateObject(“listview.tool”) ‘ open sample folder: set folder = fs.GetFolder(“C:\”) ‘ design some column headers lview.AddHeader “File name”, 50 lview.AddHeader “Type”, 30 ‘ read files into ListView: for each file in folder.files lview.AddItem file.name lview.AddSubitem 1, file.type next ‘ Sorting: ‘ sort for type, then for name ‘ use reverse order in script: lview.Sort 0 ‘ sort column 0 (name) lview.Sort 1 ‘ sort column 1 (type) ‘ read sorted result without displaying any dialog box: set result = lview.ReadResult ‘ convert collection to strings: list = “” for each entry in result entry = Split(entry, vbCrLf) list = list & entry(0) & vbTab & entry(1) & vbCr next MsgBox list
The so rting c apabilities are so po werful yo u c an even so rt fo r multiple c o lumns: In the example, the sc ript first so rts c o lumn 0 (file name), then c o lumn 1 (file type). The result is a so rted list that lists the files so rted by type and within the types so rted by name.
212
Part I: Sc ripting Kic ks tart
■
■
Figure 6-13: Us ing ListView to s ort arbitrary lis ts . Yo u need c o mmands to spec ify the number o f list c atego ries and ano ther o ne to ac tually sto re values in yo ur list.
Diving into documentation and source code To get yo ur perso nal c o py o f the ListView.tool o wner’s manual, launc h sc ript 5-12.VBS and have it auto -do c ument listview.ocx. Searc h fo r listview.ocx first to find o ut its exac t path name. The do c umentatio n file is c o ntained o n the c o mpanio n CD: info\documentation\listview\. The so urc e c o de is so mewhat lengthy, but well-do c umented. It’s no t so muc h the c o de but rather the ListView o bjec t mo del that makes it a little hard to understand. In additio n, I was fo rc ed to inc lude so me API c alls. Visual Basic 5 (and VBCCE, to o ) are buggy when it c o mes to sizing c o lumn headers. Fo r so me unkno wn reaso n, VB always adds so me extra spac e to yo ur width values, so it’s almo st impo ssible to size the c o lumns neatly this way. The so urc e c o de sho ws a wo rkaro und: It uses the internal SendMessage func tio n o f Windo ws to send resizing messages direc tly to the ListView elements.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s
213
■
■
Figure 6-14: Eas ily auto-document any COM object — even your ow n!
Successfully Dealing with API Functions Yo u no w kno w ho w to suc c essfully deal with API func tio ns. It’s a go o d time to review so me o f the basic tec hno lo gies the previo us examples have emplo yed. Yo u do n’t have to go thro ugh this, but yo u might find it helpful o nc e yo u start c hanging the example c o de to suit yo ur o wn needs. On the fo llo wing pages, I’ll sho w yo u ho w to feed text strings to API func tio ns and get results bac k safely. I’ll also c larify the ANSI/ UNICODE issue, whic h will help with writing c o de that runs bo th o n Windo ws 95/ 98 and o n Windo ws NT/ 2000.
String handling — undocumented Visual Basic commands Chapter 4 already revealed the basic s abo ut API c alls. There’s o ne mo re issue to so lve, tho ugh, and it frequently drives Visual Basic pro grammers nuts. Yo u guessed it — it’s string handling. Many API func tio ns expec t strings as arguments. The func tio ns then sto re so me value into the string so yo u c an retrieve it afterwards. The Ic o n Pic ker, fo r example, expec ts the address o f a string in whic h yo u have sto red the path to the ic o n library file. In return, the func tio n writes the new ic o n file into the string if the user c hanges the file. So , all yo u need to do is pro vide a string to the func tio n and read its c o ntents afterwards.
214
Part I: Sc ripting Kic ks tart
■
■
In theo ry, at least. In everyday life, there are a lo t mo re details to think abo ut. First o f all, many API func tio ns do n’t expec t a string but rather a referenc e to a string: its memo ry address. Therefo re, yo u need to dec lare this argument as ByVal and as Long. It’s an address po inter, no t a string. Next, yo u need to make sure yo u reserve eno ugh spac e fo r the data the func tio n might want to sto re in yo ur string. So , fill yo ur string with empty data using String. No w yo u are ready to pass the string’s memo ry address to the API func tio n. But wait a minute! There’s no Visual Basic c o mmand that wo uld tell yo u this address. Right? But there is. Yo u c an always use StrPtr. StrPtr is an undo c umented Visual Basic c o mmand. It wo rks perfec tly well, but it remains hidden bec ause in the wro ng hands, this func tio n c an c ause tro uble. There’s a lo t o f c o nfusio n abo ut address po inters, and many pro grammers invest a lo t o f time and energy using c o mplic ated API func tio ns o r Byte arrays to c o py string values into memo ry addresses. It’s mo stly unnec essary, and very slo w to o . Starting with Visual Basic 5, c o nvenient (yet hidden) func tio ns are built right into VB to handle mo st o f these tasks fo r yo u. And bec ause the VB CCE yo u’re using is based o n VB5, yo u c an use these func tio ns as well. Whenever yo u deal with po inters yo urself, yo u are no lo nger pro tec ted by the internal Visual Basic safety net. So , yo u need to make sure yo u are passing valid po inters to the plac es yo u intend to po int to .
Dealing with ANSI and UNICODE As if things weren’t tric ky eno ugh, Mic ro so ft is c urrently transfo rming its internal string mec hanic s fro m ANSI to UNICODE. ANSI strings sto re o ne c harac ter per byte. That’s eno ugh fo r so me o f us, but no t eno ugh fo r all the Chinese c harac ters — let alo ne all the glo bally available c harac ters. Therefo re, as Mic ro so ft expands wo rldwide, it migrates its Windo ws versio ns to UNICODE. Here, eac h c harac ter is represented by two bytes, allo wing fo r 65,536 different c harac ters. What do es this mean fo r us? Windo ws 9.x (and partially Windo ws NT) uses ANSI strings. Windo ws 2000 is all UNICODE, yet it still c o ntains so me ANSI suppo rt fo r bac kwards-c o mpatibility. The Ic o n Pic ker is again a go o d example. This func tio n expec ts the file name to be ANSI o n Windo ws 9.x/NT and UNICODE o n Windo ws 2000. Bec ause Visual Basic sto res its strings in UNICODE anyway, yo ur c o de will wo rk perfec tly well o n Windo ws 2000 witho ut any c o nversio n. On all o ther Windo ws versio ns, ho wever, yo u’ll get strange results. The dialo g bo x wo n’t be able to find yo ur ic o n files bec ause it will misinterpret the UNICODE filename where it expec ts an ANSI string.
Chapte r 6 : Us ing Sys te m Dialo g Bo xe s ■
215 ■
Fo rtunately, Visual Basic c o ntains the appro priate c o nversio n to o ls. Just use StrConv. It o ffers a ric h set o f c o nversio n sc hemes and allo ws fo r easy UNICODE-ANSI-UNICODE ro undtrips. In the Ic o n Pic ker example, the c o de first c hec ks whether it’s being run o n a no n-Windo ws 2000 system. If so , it c o nverts the Visual Basic UNICODE strings to ANSI, feeds them to the APIfunc tio n, and rec o nverts the result bac k to UNICODE so Visual Basic c an handle it.
Cutting excess string space Whenever yo u pro vide string spac e to an API func tio n, yo u mo st likely reserve mo re spac e than yo u ac tually need — just in c ase. Befo re yo u c an use the resulting strings in Visual Basic , yo u need to adjust string size, ho wever. API func tio ns are c lo sely related to C. They determine the size o f a string by a terminating null c harac ter ( vbNullChar). Visual Basic , in c o ntrast, do esn’t c are abo ut nulls. It sto res the string length in two bytes right befo re the string data starts. So , yo u definitely need to c ut o ff exc ess spac e befo re yo u c an use the string c o ntent in Visual Basic . This is easy — just have Visual Basic lo o k fo r the first null c harac ter and c ut o ff the rest: stringvar = left(stringvar, Instr(stringvar, vbNullChar)-1)
Experimenting and getting source code for free Always remember: Yo ur Visual Basic Co ntro l Creatio n Editio n is a full Visual Basic develo pment enviro nment! I stro ngly enc o urage yo u to searc h the Internet fo r so urc e c o de examples. There are many great Web sites o ut there with tuto rials and samples o f vario us API tec hniques. Just launc h yo ur VBCCE and c ho o se Open Pro jec t fro m the File menu. Then lo ad the sample pro jec t yo u do wnlo aded fro m the Internet and experiment with it! Yo ur VBCCE is based o n Visual Basic 5.0. Many examples already use Visual Basic 6.0, and yo u may get erro r messages when trying to o pen tho se pro jec ts. Ho wever, in mo st c ases, yo u just need to o pen the .vbp file in yo ur edito r and remo ve the attributes that c aused the erro r. A c o mmo n pro blem is the line retained =. Co mpletely remo ve this line, save the .vbp file, and reo pen it. This way, yo u c an o pen and use mo st Visual Basic 6 pro jec ts.
216
Part I: Sc ripting Kic ks tart
■
■
Summary Yo u have disc o vered ho w to wrap system dialo g bo xes in COM o bjec ts and c all them fro m sc ript. Using the ListView element, yo u c reated yo ur o wn list bo x dialo g bo x and fo und ways to have it so rt arbitrary lists quic kly and safely. Calling API func tio ns leaves it to yo u to handle string po inters and string fo rmats. Yo u no w kno w ho w to pass string address po inters and ho w to deal with ANSI/ UNICODE c o nversio n to write c o de that runs equally well o n all Windo ws versio ns. As a result, yo u no w have a who le armo ry o f new c o mmands that display virtually any dialo g bo x yo u may ever need.
Chapte r 7
Accessing the File System In This Chapter 䊳 Ac c ess drives, fo lders, and individual files 䊳 Peek into any file, and c hanging file c o ntents at will 䊳 Determine free spac e o n drives, and o verc o me the 2GB bug 䊳 Searc h the entire hard drive fo r o utdated files o r empty fo lders rec ursively
T
he Windo ws Sc ripting Ho st c o mes with a sec ret sc ript extensio n, c alled Scripting.FileSystemObject. This o bjec t grants full ac c ess to the entire file system. In this c hapter, yo u’ll disc o ver ho w to peek into files, c o py, mo ve, delete and c reate new files fro m sc ratc h. In additio n, I’ll sho w yo u so me wo rkaro unds to c o rrec tly deal with drive sizes greater than 2GB
Finding the Secret Backdoor to the File System The file system is o ne o f the mo st interesting areas o f yo ur c o mputer. It’s where all o f yo ur data is sto red, and there are numero us tasks that sc ripts c an handle fo r yo u, inc luding reo rganizing data, finding o rphan files, do ing bac kups, and mo re. Ho w do yo u get ac c ess to yo ur files? Bo th the WSH and VBSc ript lac k file system c o mmands. There’s no way to o pen files, delete data, o r c o py fo lders. Ho wever, this makes perfec t sense bec ause bo th WSH and VBSc ript are designed as platfo rm-independent tec hno lo gies. The file system, in c o ntrast, is very spec ial, and its tec hno lo gy c an vary fro m o perating system to o perating system. Still, yo ur sc ripts have full ac c ess to yo ur file system. Mic ro so ft has plac ed all the nec essary c o mmands into a separate mo dule. scrrun.dll is auto matic ally registered as a Scripting.FileSystemObject COM c o mpo nent, and whenever yo u need file system suppo rt, just inc lude a referenc e to this o bjec t in yo ur sc ripts.
220
Part II: Co nque ring the File Sys te m
■
■
Accessing a drive Where’s the sec ret bac k do o r to yo ur file system? Ac tually, there are many do o rs. One is to get ac c ess to any o ne o f yo ur drives using GetDrive: ‘ 7-1.VBS ‘ get access to file system commands: set fs = CreateObject(“Scripting.FileSystemObject”) set drivec = fs.GetDrive(“C:\”) MsgBox TypeName(drivec) emptyspace = drivec.AvailableSpace MsgBox “Avaialable on C:\: “ & _ FormatNumber(emptyspace/1024^2,1) & “ MB”
This simple sc ript ac c esses drive C:\ and returns a Drive o bjec t. The Drive o bjec t c o ntains many useful pro perties and metho ds. The AvailableSpace pro perty, fo r example, repo rts the available spac e o n this drive (see Figure 7-1).
Figure 7-1: Acces s ing a drive and retrieving Volume information. Ac tually, there are two very similar pro perties: AvailableSpace and FreeSpace. Whereas FreeSpace repo rts the physic ally uno c c upied spac e o n the partic ular drive, AvailableSpace repo rts the spac e available to a user. It takes into ac c o unt o ther limitatio ns, suc h as disk quo tas. Bo th c o mmands repo rt a maximum o f 2GB o f spac e. This is an intrinsic limitatio n, and yo u will hear mo re abo ut it a little later in the c hapter. Yo u will also disc o ver metho ds to so lve this limitatio n and repo rt available spac e even o n drives larger than 2GB. It o nly takes a c o uple o f additio nal lines to enumerate all files in the ro o t fo lder o f yo ur drive: ‘ 7-2.VBS ‘ get access to file system commands: set fs = CreateObject(“Scripting.FileSystemObject”) set drivec = fs.GetDrive(“C:\”) set root = drivec.RootFolder for each file in root.files list = list & file.name & vbCr next MsgBox list
Chapte r 7 : Ac c e s s ing the File Sys te m
221
■
■
When dealing with the file system, yo u wo rk with many different o bjec ts. In the example, the drive, the fo lder, and eac h individual file are represented by an individual o bjec t. Always remember to use Set whenever yo u retrieve an o bjec t referenc e and want to assign it to a variable.
Finding information about properties and methods Ho w did I kno w abo ut all the metho ds and pro perties I used in the previo us examples? I didn’t. I lo o ked them up, and yo u c an, to o . In fac t, it’s a go o d idea to first get to gether all the do c umentatio n yo u need to fully explo it the FileSystemObject. It’s easy — yo u’ve already prepared the nec essary to o ls in the previo us c hapters. Have a lo o k at Table 7-1:
Table 7-1 Script 3-12.VBS
Scripts You Can Use To Auto-Document COM Objects Description Find out the particular s yntax of a command. For example, enter
GetDrive. 3-7.VBS
Auto-document all properties and methods of FileSystemObject: Enter the name of the object: scrrun.dll. Then enter the object you w ant to document: FileSystemObject.
3-10.VBS
Auto-document the Drive object or any other object: J us t enter the name of the object: for example, Drive
5-12.VBS
Generate a fully color-coded reference to all the commands and objects . Enter the name of the COM object you w ant to document: scrrun.dll. Then open your documentation folder C:\documentation\s crrun and brow s e through the automatically generated documentation files . Open Drive.htm to dis cover the internal s tructure of the Drive object you jus t us ed.
Getting Details About Your Drives All yo ur drives are represented by the Drive o bjec t. Ho w do yo u get o ne? Yo u ask fo r it! One way is the GetDrive metho d, but there are o thers, to o . The drives metho d enumerates all drives available o n yo ur system: ‘ 7-3.VBS ‘ get access to file system commands: set fs = CreateObject(“Scripting.FileSystemObject”) ‘ retrieve list of all available drives: set drivecollection = fs.Drives
222
Part II: Co nque ring the File Sys te m
■
■
‘ enumerate drives for each drive in drivecollection list = list & drive.path & vbCr next MsgBox list
Ano ther “do o r” to the Drive o bjec t go es the o ppo site direc tio n: Get a fo lder o bjec t and retrieve the Drive o bjec t o f the drive the fo lder is sto red in: ‘ 7-4.VBS ‘ get access to file system commands: set fs = CreateObject(“Scripting.FileSystemObject”) ‘ get access to a folder ‘ get windows folder set winfolder = fs.GetSpecialFolder(0) MsgBox “Windows folder: “ & winfolder.name ‘ get drive object: set drive = winfolder.Drive MsgBox “Windows is installed on Drive “ & drive.DriveLetter
Closely examining the Drive object There are many ways to retrieve a Drive o bjec t. What c an yo u do o nc e yo u have a referenc e to a Drive o bjec t, tho ugh? Take a lo o k at its internal struc ture (see Table 7-2):
Table 7-2
The Drive Object
Property/M ethod
Description
Property AvailableSpace
Get available s pace
Property DriveLetter As String
Drive letter
Property DriveType As DriveTypeConst
Drive type
Property FileSystem As String
Files ys tem type
Property FreeSpace
Get drive free s pace
Property IsReady As Boolean
Check if dis k is available
Property Path As String
Path
Property RootFolder As IFolder
Root folder
Property SerialNumber As Long
Serial number
Property ShareName As String
Share name
Property TotalSize
Get total drive s ize
Property VolumeName As String
Name of volume
Chapte r 7 : Ac c e s s ing the File Sys te m
223
■
■
Is the drive ready for action? It’s always a go o d idea to prevent erro rs whenever po ssible (see Figure 7-2). Drives c an have remo vable media suc h as a ZIP drive o r disk drive. Use isReady to find o ut whether a media is inserted befo re yo u start querying fo r any additio nal info rmatio n: ‘ 7-5.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ let’s check drive A: set drivea = fs.GetDrive(“A:\”) ‘ loop until drive is ready or user cancels: do until drivea.isReady response = MsgBox(“Please insert disk in drive A:!”, vbOKCancel) if response = vbCancel then ‘ user wants to quit, maybe no disk at hand: MsgBox “Cancel accepted”, vbExclamation WScript.Quit end if loop ‘ let’s label the drive: volname = drivea.VolumeName newname = InputBox(“Assign a new Volume label to the disk:”, _ ,volname) if newname = vbEmpty then ‘ user cancelled: MsgBox “Volume name remains unchanged.” else drivea.VolumeName = newname MsgBox “New Volume name assigned: “ & newname end if
Figure 7-2: Script checks w hether a dis k is ins erted. isReady no t o nly prevents ac c ess to drives with no media inserted. Yo u c an also , fo r example, write a shutdo wn sc ript that c lo ses Windo ws and uses isReady to make sure no media is left in the drives. With the help o f the CD-ROM tray API c o mmands in Chapter 4, yo u c an even auto matic ally o pen CD ROM trays if media is left in the drive befo re shutting do wn the c o mputer. All the metho ds and pro perties yo u disc o ver thro ugho ut this bo o k are just building blo c ks, and the beauty o f sc ripting is yo ur freedo m to use these building blo c ks in any way yo u want.
224
Part II: Co nque ring the File Sys te m
■
■
Changing a drive’s volume name VolumeName is a read/ write pro perty: Yo u c an bo th read the c urrent vo lume label and assign new names. This is po ssible fo r all write-enabled drives, and yo u even get to see yo ur new label fo r hard drives in the Explo rer windo w. The Vo lume label traditio nally plays an impo rtant ro le with installatio n disks. By assigning vo lume labels to disks, yo ur sc ript c an c hec k whether the user inserted the c o rrec t disk.
Using a drive’s serial number Ano ther impo rtant means o f identific atio n is the serial number. Eac h drive has an individual serial number, and yo u c an ask fo r it by querying the SerialNumber pro perty. The serial number is assigned during media fo rmatting. Bec ause the serial number will also be c o pied whenever yo u duplic ate disks, it’s no go o d fo r c o py pro tec tio n sc hemes. Ho wever, a serial number o f 0 indic ates that the media wasn’t fully fo rmatted. “Pre-fo rmatted” disks, fo r example, display a serial number o f 0. Bec ause it’s dangero us to sto re valuable data o n suc h disks witho ut fully fo rmatting them befo rehand, yo u c an use the Serial Number pro perty to build additio nal sec urity into yo ur sc ripts. See the fo llo wing example. ‘ 7-6.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set drivea = fs.GetDrive(“A:\”) ‘ loop until drive is ready or user cancels: do until drivea.isReady response = MsgBox(“Please insert disk in drive A:!”, vbOKCancel) if response = vbCancel then ‘ user wants to quit, maybe no disk at hand: MsgBox “Cancel accepted”, vbExclamation WScript.Quit end if loop serno = drivea.SerialNumber if serno = 0 then MsgBox “This disk was never fully formatted!” else MsgBox “Disk serial number: “ & serno end if
Determining drive type and file system There are many different drive types o ut there, and maybe yo u need to so rt o ut read-o nly drives. Ho w c an yo u determine whether a drive is a CD-ROM drive?
Chapte r 7 : Ac c e s s ing the File Sys te m ■
225 ■
Easy. DriveType tells yo u the type o f drive, and FileSystem repo rts the type o f file system used o n this drive (see Figure 7-3).
Figure 7-3: Retrieve Volume Label and file s ys tem information. ‘ 7-7.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ define array with clear text description dt = Split(“unknown;removable;fixed;remote;CD-ROM;RAM-Drive”, “;”) ‘ get list of drives set drivecoll = fs.Drives ‘ enumerate all drives for each drive in drivecoll ‘ check whether drive is ready: if drive.isReady then drivetype = drive.DriveType filesystem = drive.FileSystem label = drive.VolumeName letter = drive.DriveLetter msg = msg & “Drive “ & letter & “: (“ & label _ & “) “ & dt(drivetype) & “ (“ & filesystem & “)” & vbCr else msg = msg & “Drive “ & letter & “: is not ready.” & vbCr end if next MsgBox msg, vbInformation
Finding out available space on drives Data sto rage is always a sc arc e reso urc e. Yo ur sc ripts will need to c hec k whether there is eno ugh sto rage spac e available befo re starting a lengthy c o py o peratio n, and it’s a go o d idea to let sc ripts warn yo u o nc e available spac e dro ps belo w a c ertain thresho ld.
226
Part II: Co nque ring the File Sys te m
■
■
The Drive o bjec t o ffers three pro perties, inc luding AvailableSpace, FreeSpace, and TotalSize. Ho wever, all three pro perties impo se a serio us limitatio n: They c an o nly deal with drives up to a maximum size o f 2GB. Or, in o ther wo rds: Neither o ne will ever repo rt mo re than 2GB. The FileSystemObject uses o ld API func tio ns to retrieve drive sizes. These o ld func tio ns c an’t deal with drive sizes abo ve 2GB. ‘ 7-8.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set drive = fs.GetDrive(“C:\”) avail = drive.AvailableSpace free = drive.FreeSpace total = drive.TotalSize msg msg msg msg
MsgBox msg function fn(bytes) fn = FormatNumber(bytes/1024^2,2) & “ MB” end function
AvailableSpace and FreeSpace will o nly differ if yo u have set up disk quo tas. Disk quo tas limit the amo unt o f spac e an individual user c an use. This feature is implemented in Windo ws 2000.
Fixing the 2GB bug There’s really no reaso n why yo ur sc ripts sho uldn’t repo rt the true spac e even o n to day’s larger disks. To o verc o me the 2GB limitatio n, all yo u need to do is use the c o rrec t and up-to -date API func tio ns. Just wrap them in a COM o bjec t as o utlined in Chapter 4. I have prepared a COM o bjec t fo r yo u that c o rrec tly repo rts drive sizes, demo nstrating the use o f API func tio ns (see Figure 7-4). To view the internal mec hanic s, o pen \components\filesys\filesys.vbp in yo ur Visual Basic CCE and c o mpile the pro jec t. To just use the new metho ds, install the so ftware pac kage — \install\filesys\setup.exe. ‘ 7-9.VBS set tool = CreateObject(“filesystem.tool”) free = tool.FreeSpace(“C:\”) total = tool.TotalSize(“C:\”) msg = “Statistics Drive C:\” & vbCr msg = msg & “Free Space: “ & fn(free) & vbCr msg = msg & “Total Size: “ & fn(total)
Chapte r 7 : Ac c e s s ing the File Sys te m ■
227 ■
MsgBox msg function fn(bytes) fn = FormatNumber(bytes/1024^2,2) & “ MB” end function
Figure 7-4: Your new COM object can deal w ith drives larger than 2GB.
Calling file system APIs directly The filesystem.tool COM o bjec t demo nstrates so me very impo rtant new tec hniques. Have a lo o k: Option Explicit ‘ old version Private Declare Function GetDiskFreeSpace Lib “kernel32” _ Alias “GetDiskFreeSpaceA” (ByVal lpRootPathName As String, _ lpSectorsPerCluster As Long, lpBytesPerSector As Long, _ lpNumberOfFreeClusters As Long, lpTotalNumberOfClusters As _ Long) As Long ‘ new version without 2 GB limitation ‘ use Currency var type as “long integer” Private Declare Function GetDiskFreeSpaceEx Lib “kernel32” _ Alias “GetDiskFreeSpaceExA” (ByVal lpRootPathName As String, _ lpFreeBytesAvailableToCaller As Currency, lpTotalNumberOfBytes _ As Currency, lpTotalNumberOfFreeBytes As Currency) As Long ‘ error code for undefined API functions: Private Const errNoSuchFunction = 453 Private Double, Dim Dim Dim Dim Dim Dim Dim Dim Dim
Sub GetSizes(ByVal DriveLetter As String, TotalBytes As FreeBytes As Double) drvLetter As String free As Currency total As Currency allfree As Currency ok As Integer lngSPC As Long ‘ sectors per cluster lngBPS As Long ‘ bytes per sector lngTC As Long ‘ total number of clusters lngFC As Long ‘ free clusters
TotalBytes = 0 FreeBytes = 0
228
Part II: Co nque ring the File Sys te m
■
■
‘ was a valid drive letter specified? If Len(DriveLetter) = 0 Then Err.Raise vbObjectError + 512 + 20, _ “FileSystem Tool: Drive Size”, _ “You did not specify a drive letter!” Exit Sub End If ‘ transform letter in drive specs: drvLetter = UCase(Left(DriveLetter, 1)) & “:\” ‘ valid drive letter? If Left(drvLetter, 1) < “A” Or Left(drvLetter, 1) > “Z” Then Err.Raise vbObjectError + 512 + 21, _ “FileSystem Tool: Drive Size”, _ “The specified drive letter “”” & DriveLetter _ & “”” was invalid!” Exit Sub End If ‘ API call is undefined on older systems with 2 GB limitation ‘ so catch errors! On Error Resume Next ok = GetDiskFreeSpaceEx(drvLetter, free, total, allfree) ‘ is new API call supported? If Err.Number = errNoSuchFunction Then ‘ no. This system can only use 2 GB max drives anyway, ‘ so use older version ‘ first turn back on error handling: Err.Clear On Error GoTo 0 ‘ find out space info ok = GetDiskFreeSpace(drvLetter, lngSPC, lngBPS, lngFC, lngTC) If ok Then ‘ calculate actual bytes: TotalBytes = CDbl(lngTC) * lngSPC * lngBPS FreeBytes = CDbl(lngFC) * lngSPC * lngBPS End If ElseIf Err.Number = 0 And ok Then ‘ reset error handling Err.Clear On Error GoTo 0 ‘ adjust for Currency var type: TotalBytes = CDbl(total) * 10000 FreeBytes = CDbl(free) * 10000 Else Err.Raise vbObjectError + 512 + 22, “FileSystem Tool”, “Failed to retrieve drive size information” End If End Sub
Chapte r 7 : Ac c e s s ing the File Sys te m
229
■
■
Public Function TotalSize(ByVal drive As String) As Double Dim total As Double Dim free As Double GetSizes drive, total, free TotalSize = total End Function Public Function FreeSpace(ByVal drive As String) As Double Dim total As Double Dim free As Double GetSizes drive, total, free FreeSpace = free End Function
There are ac tually two c o mpletely different API func tio ns that c an retrieve spac e o n a drive — the o lder GetDiskFreeSpace func tio n and the new GetDiskFreeSpaceEx func tio n. Bo th func tio ns lo o k at drives in c o mpletely different ways, but while GetDiskFreeSpace uses the o lder and mo re “mec hanic ally” o riented c luster sizes to repo rt free spac e, the new func tio n returns the byte c o unt already summed up. The c luster-o riented appro ac h o f the o lder func tio n is the true reaso n why it c an’t deal with drives larger than 2GB. There is a maximum o f c lusters and a maximum o f bytes per c luster. Mo dern file systems have c hanged this way o f o rganizing data. There are two drawbac ks when using GetDiskFreeSpaceEx. First, it’s no t available o n all Windo ws systems. Older Windo ws versio ns still exc lusively use the FAT file system with its 2GB limit. And bec ause GetDiskFreeSpaceEx needs to repo rt po tentially large numbers, it uses the Lo ng Integer variable type. This variable type isn’t suppo rted in Visual Basic . To o verc o me bo th drawbac ks, the c o de uses so me handy tric ks that c an help with o ther API func tio ns, to o . First, it uses on error resume next to take erro r handling in its o wn hands. Then, it just c hec ks whether c alling GetDiskFreeSpaceEx raised the errNoSuchFunction erro r. If so , it falls bac k and uses the o ld GetDiskFreeSpace func tio n, whic h is available o n any Windo ws system. There are numero us ways to deal with Lo ng Integer variable types. Mo st pro grammers define user types and do a lo t o f c alc ulatio n switc hing bits bac k and fo rth. In mo st c ases, this is c o mpletely unnec essary. Visual Basic suppo rts a variable type c alled Currenc y. Even tho ugh this variable type, as its name implies, o riginally was designed to deal with c urrenc ies, it sto res its values internally as Lo ng Integer. The Currency variable type really is the missing Long Integer variable type. The o nly differenc e is the dec imal po int, whic h yo u c an adjust by multiplying the variable appro priately. Yo ur c o de c an therefo re use Currenc y in API dec laratio ns whenever an API func tio n expec ts a Lo ng Integer. To retrieve the value, just multiply the variable by 10, 000 to adjust fo r the dec imals. There’s definitely no need fo r brain-mangling bit o peratio ns.
230
Part II: Co nque ring the File Sys te m
■
■
Accessing Folders Fo lders are the c o ntainers yo ur files are o rganized in. Similar to drives, there are many ways to get a ho ld o f a fo lder o bjec t: ‘ 7-10.VBS ‘ accessing a folder directly: set fs = CreateObject(“Scripting.FileSystemObject”) set folder = fs.GetFolder(“C:\”) MsgBox TypeName(folder)
It’s easy to enumerate the subfo lder o f any given fo lder using a c o llec tio n and subfo lders: ‘ 7-11.VBS set set set for
fs = CreateObject(“Scripting.FileSystemObject”) folder = fs.GetFolder(“C:\”) foldercollection = folder.subfolders each subfolder in foldercollection list = list & subfolder.name & vbCr next MsgBox list
Yo u c an even get direc t ac c ess to any o f the spec ial fo lders: ‘ 7-12.VBS set fs = CreateObject(“Scripting.FileSystemObject”) for x=0 to 2 set specialfolder = fs.GetSpecialFolder(x) MsgBox x & “ = “ & specialfolder.path next
And there’s also the o ld relatio nship between Drive o bjec t and Folder o bjec t: ‘ 7-13.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ get Drive: set drive = fs.GetDrive(“C:\”) set rootfolder = drive.RootFolder ‘ get folder directly set rootfolder2 = fs.GetFolder(“C:\”) if rootfolder is rootfolder2 then MsgBox “both objects are identical” else MsgBox “objects are different” end if
Chapte r 7 : Ac c e s s ing the File Sys te m
231
■
■
As it turns o ut, it do esn’t matter whic h ro ute yo u take: In bo th c ases, yo u end up with the same Folder o bjec t representing fo lder “C:\”.
Examining the Folder object Take a lo o k at the Folder o bjec t (see Table 7-3). What c an it do fo r yo u?
Table 7-3
The Folder Object
Property/M ethod
Description
Property Attributes As FileAttribute
Folder attributes
Sub Copy(ByVal Destination As String, [ByVal OverWriteFiles As BooleanTrue])
Copy this folder
Function CreateTextFile(ByVal FileName As String, [ByVal Overwrite As BooleanTrue], [ByVal Unicode As BooleanFalse]) As ITextStream
Create a file as a
TextStream
Property DateCreated As Date
Date folder w as created
Property DateLastAccessed As Date
Date folder w as las t acces s ed
Property DateLastModified As Date
Date folder w as las t modified
Sub Delete([ByVal Force As BooleanFalse])
Delete this folder
Property Drive As IDrive
Get drive that contains folder
Property Files As IFileCollection
Get files collection
Property IsRootFolder As Boolean
True if folder is root
Sub Move(ByVal Destination As String)
Move this folder
Property Name As String
Get name of folder
Property ParentFolder As IFolder
Get parent folder
Property Path As String
Path to folder
Property ShortName As String
Short name
Property ShortPath As String
Short path
Property Size
Sum of files and s ubfolders
Property SubFolders As IFolderCollection
Get folders collection
Property Type As String
Type des cription
232
Part II: Co nque ring the File Sys te m
■
■
Determining a folder’s total size The Folder o bjec t c o ntains a very po werful (and so mewhat slo w) metho d c alled Size. It c alc ulates the to tal size this fo lder o c c upies and inc ludes any files and subfo lders. This metho d c an be extremely useful. The fo llo wing sc ript generates a handy list with all fo lders and their sizes. This list helps to identify where all yo ur prec io us hard disk spac e went, and it c an be the basis o f so me serio us c leaning up: ‘ 7-14.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ space to store information dim folderspecs(10000,1) ‘ reset counter and define as global variable counter = 0 ‘ check all drives set drivecollection = fs.Drives for each drive in drivecollection ‘ is it a hard drive? if drive.DriveType = 2 then ‘ is it ready? It should... if drive.isReady then ‘ start recursive reporting response = MsgBox(“Checking Drive “ _ & drive.DriveLetter _ & vbCr & counter _ & “ folders checked so far...”, vbOkCancel) ‘ leave an exit to cancel prematurely so ‘ no user is trapped in length operations: if response = vbCancel then exit for CheckFolder(drive.RootFolder) end if end if next ‘ sort result, larger folders first MsgBox “Sorting results...” SortInfo ‘ generate list output = “C:\list.txt” set outputfile = fs.CreateTextFile(output, true) for x=0 to counter-1 size = FormatNumber(folderspecs(x, 0)/1024^2,1) size = right(space(30) & size, 10) & “ MB”& space(5) outputfile.WriteLine size & folderspecs(x,1) next outputfile.close
Chapte r 7 : Ac c e s s ing the File Sys te m ■
233 ■
‘ launch report file: set wshshell = CreateObject(“WScript.Shell”) wshshell.run output
sub CheckFolder(folderobj) ‘ determine folder size ‘ important: always turn off error handling! on error resume next size = folderobj.size ‘ check for access violation errors if not err.Number=0 then size=-1 err.clear end if ‘ turn error handling back on: on error goto 0 ‘ add entry: folderspecs(counter,0) = size folderspecs(counter,1) = folderobj.path ‘ increment counter: counter = counter + 1 ‘ check all subfolders ‘ this is the basis of recursive calling ‘ important! Always turn off error handling ‘ to handle access violation errors: on error resume next for each subfolder in folderobj.subfolders ‘ check each subfolder individually ‘ by calling myself CheckFolder subfolder next ‘ turn error handling back on: err.clear on error goto 0 end sub Sub SortInfo for x = 0 to counter-1 for y = x+1 to counter-2 if folderspecs(x,0)=30 then ReportEmptyFolder folderobj end if end if end if end sub
There are ac tually two ways o f deleting fo lders. Yo u c an use the Delete metho d built into any fo lder o bjec t. This is ho w the sc ript gets rid o f empty fo lders. In additio n, the FileSystemObject o ffers the DeleteFolder metho d. Here, yo u spec ify the path name o f the fo lder yo u want to delete.
Creating new folders Yo ur sc ript c an easily add fo lders. The fo llo wing sc ript sho ws ho w to auto matic ally c reate all fo lders in a given path: ‘ 7-16.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ generate folders for this path: generated = CreateFolders(“C:\DOCU\TEST\SUBFOLDER\TEST.TXT”) MsgBox “I’ve created “ & generated & “ folders for you!” function CreateFolders(path) count = 0 ‘ number of created folders start = 1 ‘ scan path beginning at pos 1 ‘ search for “\” pos = Instr(start, path, “\”) ‘ loop until no more “\” do until pos=0 ‘ extract subpath to current “\” folderpath = left(path, pos-1) ‘ does this folder already exist? if not fs.FolderExists(folderpath) then ‘ no, increment counter: count = count + 1 ‘ create folder: fs.CreateFolder folderpath end if ‘ move to next “\” and scan for more: start = pos+1 pos = Instr(start, path, “\”) loop
Chapte r 7 : Ac c e s s ing the File Sys te m ■
237 ■
‘ return # of newly created folders CreateFolders = count end function
This sc ript auto matic ally generates all nec essary fo lders in the given path and repo rts bac k the number o f fo lders it ac tually generated.
Organizing Files Fo lders and files are handled very similarly. Eac h file is represented by a File o bjec t. Let’s first lo o k at the info rmatio n pro vided by the File o bjec t (see Table 7-4):
Table 7-4
The File Object
Property/M ethod
Description
Property Attributes As FileAttribute
File attributes
Sub Copy(ByVal Destination As String, [ByVal OverWriteFiles As BooleanTrue])
Copy this file
Property DateCreated As Date
Date file w as created
Property DateLastAccessed As Date
Date file w as las t acces s ed
Property DateLastModified As Date
Date file w as las t modified
Sub Delete([ByVal Force As BooleanFalse])
Delete this file
Property Drive As IDrive
Get drive that contains file
Sub Move(ByVal Destination As String)
Move this file
Property Name As String
Get name of file
Function OpenAsTextStream([ByVal IOMode As IOModeForReading], [ByVal Format As TristateTristateFalse]) As ITextStream
Open a file as a TextStream
Property ParentFolder As IFolder
Get folder that contains file
Property Path As String
Path to the file
Property ShortName As String
Short name
Property ShortPath As String
Short path
Property Size
File s ize
Property Type As String
Type des cription
238
Part II: Co nque ring the File Sys te m
■
■
Accessing files Ac c essing individual files is very similar to ac c essing fo lders. Yo u c an ask fo r a spec ific file: ‘ 7-17.VBS set fs = CreateObject(“Scripting.FileSystemObject”) filename = “C:\AUTOEXEC.BAT” if fs.FileExists(filename) then set file = fs.GetFile(filename) MsgBox filename & “ is “ & file.size & “ bytes.” else MsgBox filename & “ does not exist.” end if
Or yo u c an enumerate all files in a fo lder using files: ‘ 7-18.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ access folder: set folder = fs.GetFolder(“C:\”) for each file in folder.files list = list & file.name & “: “ & file.Type & vbCr next MsgBox list
Keep in mind that ac c ess to a file may be restric ted o r impo ssible: If the file is already o pen and o wned by ano ther pro gram, yo u may no t be able to ac c ess it. Likewise, if yo u spec ify the wro ng path, the file c anno t be fo und. So it’s a go o d idea to use FileExists to c hec k whether the file really exists, and to turn o ff erro r handling fo r tho se parts o f yo ur sc ript where yo u try to ac c ess pro perties o f the File o bjec t. Never fo rget to turn erro r handling bac k o n using on error goto 0!
Mastering File Attributes File Attributes are just plain bits. They aren’t really po werful by themselves. What makes them po werful is the fac t that Windo ws reads the attributes befo re it starts file o peratio ns o n the file — and ac ts ac c o rdingly! Fo r example, if the read-o nly file attribute is set, yo u c an’t save the file. Instead, whenever yo u c ho o se Save fro m the File menu, the Save As dialo g po ps up and asks yo u to save yo ur c hanges as a different file. This is great news bec ause yo u c an take advantage o f the file attributes to pro tec t template files and keep trac k o f file c hanges using the Arc hive attribute. All yo u need to do is find a way to read and c hange the file attributes. Here’s a list (Table 7-5):
Chapte r 7 : Ac c e s s ing the File Sys te m ■
239 ■
Table 7-5
File Attributes
Bit value
Description
1
Read Only
2
Hidden
4
Sys tem
8
Volume (Drive)
16
Directory (Folder)
32
Archive
64
Alias (Link)
128
Compres s ed (NT only)
2048
Compres s ed (Win2000 only)
Reading file and folder attributes Unfo rtunately, these attributes are c runc hed into two bytes, and to retrieve the ac tual meaning, yo u need to do so me bit c hec king: ‘ 7-19.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ check attributes of file set file = fs.GetFile(“C:\MSDOS.SYS”) MsgBox CheckAttribs(file) ‘ check attributes of folder set folder = fs.GetFolder(“C:\”) MsgBox CheckAttribs(folder)
function CheckAttribs(obj) description = Split(“read-only;hidden;System;Drive;” _ & “Folder;Archive;Link;128;256;512;1024;compressed” _ & “;4096;8192”, “;”) attribs = obj.Attributes for x=0 to 13 if (attribs and 2^x) then msg = ucase(description(x) & “: set”) else msg = description(x) & “: not set” end if CheckAttribs = CheckAttribs & msg & vbCr next end function
240
Part II: Co nque ring the File Sys te m
■
■
Bit-c hec king is fairly simple: Use and c o mpare the bit value with the number. If the result is larger than 0 (whic h is always interpreted as true), then yo u kno w the bit is set (see Figure 7-6).
Figure 7-6: Convert Attribute bits into real text. To c hec k whether a file is write-pro tec ted, yo u c an write: ‘ 7-20.VBS set fs = CreateObject(“Scripting.FileSystemObject”) filepath = “C:\MSDOS.SYS” MsgBox “Is “ & filepath & “ write protected? “ _ & isWriteProtect(filepath) function isWriteProtect(path) set fs = CreateObject(“Scripting.FileSystemObject”) if fs.FileExists(path) then isWriteProtect = CBool(fs.GetFile(path).Attributes and 1) else MsgBox path & “doesn’t exist!”, vbInformation end if end function
Changing a file’s attribute The Attributes pro perty is read/ write, but it’s a little tric ky to c hange a file’s attribute. So me o f the attribute bits are read-o nly. Obvio usly, it wo uld make no sense and c ause immense c o nfusio n to set the Vo lume bit o n a file. Therefo re, always set read/ write bits o nly, and leave the rest alo ne. The fo llo wing example remo ves the read-o nly bit fro m MSDOS.SYS, o pens the file in the edito r, and allo ws yo u to c hange Windo ws 9.x Start o ptio ns. Onc e yo u c lo se the edito r, the read-o nly bit is resto red:
Chapte r 7 : Ac c e s s ing the File Sys te m
241
■
■
‘ 7-21.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) filename = “C:\MSDOS.SYS” set file = fs.GetFile(filename) ‘ remove read only bit: file.Attributes = file.Attributes and not 14000 and not 1 ‘ open file in editor: wait = wshshell.run(“notepad.exe “ & filename,,true) ‘ restore write protect file.Attributes = file.Attributes and not 14000 or 1
and not 14000 remo ves all write-pro tec ted bits. and not 1 deletes the write pro tec tio n bit. or 1 sets this bit. The Arc hive bit is a very spec ial Attribute. It’s managed by Windo ws. Whenever yo u save a file, Windo ws sets the files’ Arc hive bit. Yo u just need to c lear this bit to c hec k whether a file has c hanged o ver time. The Arc hive bit is used by Bac kup pro grams, and yo u’ll see a little later in the c hapter ho w sc ripts c an also use the Arc hive bit to bac k up o nly tho se files that have c hanged sinc e yo ur last bac kup.
Changing File Content Yo u are no t limited to o rganizing files and fo lders. Yo u c an also peek into files, c reate new files, and ac tually write data to files.
Peeking into files The FileSystemObject o ffers a ric h set o f func tio ns to manipulate text files. Yo u are no t limited to text files, tho ugh. Pro vided yo u kno w ho w to interpret the data, yo u c an also o pen binaries o r write binaries. The fo llo wing sc ript o pens a text file and displays its c o ntents as a dialo g bo x (see Figure 7-7): ‘ 7-22.VBS set fs = CreateObject(“Scripting.FileSystemObject”) filename = “C:\AUTOEXEC.BAT” if fs.FileExists(filename) then set handle = fs.OpenTextFile(filename) content = handle.ReadAll
242
Part II: Co nque ring the File Sys te m
■
■
handle.close MsgBox content else MsgBox filename & “ doesn’t exist!” end if
Figure 7-7: Read in a text file and dis play contents as a dialog box.
Reading Registry entries Using ReadAll will o nly wo rk o n rather small files. It just takes to o muc h memo ry to read large files c o mpletely into a single variable. A better appro ac h is reading line by line. No w, ho wever, yo u’ll need to find ways to detec t the end o f the file. The next example sho ws a c o uple o f new tec hniques. First, the sc ript launc hes regedit remo tely using hidden o ptio ns to c reate a text dump o f the entire Registry. Then the sc ript o pens the text dump and retrieves info rmatio n abo ut all installed fo nts. As a result, yo u rec eive a list o f installed fo nts, their true file names, and a status repo rt as to whether o r no t the file c urrently exists (see Figure 7-8).
Figure 7-8: Finding out ins talled s ys tem fonts and checking for integrity.
Chapte r 7 : Ac c e s s ing the File Sys te m
243
■
■
regedit is the well-kno wn Registry edito r. This to o l no t o nly displays the c o ntent o f yo ur Windo ws Registry. It also c an dump the entire Registry c o ntent to a file using the /E o ptio n. Sinc e the WSH has o nly limited abilities to searc h the Registry, dumping the c o ntent and then searc hing it c an be o ne way o f retrieving info rmatio n o therwise unreac hable. The /S o ptio n prevents any dialo g bo xes fro m appearing. /S is sho rt fo r “silent.” Chapter 14 intro duc es metho ds to manage the Registry c o ntent direc tly. ‘ 7-23.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) dump = “C:\dump.txt” wait = wshshell.run(“REGEDIT.EXE /S /E “”” & dump & “”””,,true) ‘ re-enable error handling on error goto 0 ‘ font key: key1 = “[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft” _ & “\Windows NT\CurrentVersion\Fonts]” key2 = “[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft” _ & “\Windows\CurrentVersion\Fonts]” ‘ open dump file for reading Const forReading = 1 Const useDefault = -2 set handle = fs.OpenTextFile(dump, forReading, false, useDefault) ‘ search entire dump until font section is reached do until handle.atEndOfStream line = handle.ReadLine if found then ‘ end of font section reached? if not left(line,1)=”””” then exit do else ‘ remove quotes: line = Replace(line, “”””, “”) fontinfo = Split(line, “=”) fontname = fontinfo(0) fontpath = fontinfo(1) msg = msg & fontname & “ is stored in “ & fontpath ‘ full path name available? if Instr(fontpath, “\”)=0 then ‘ no, font stored in system folder: fontpath = “%windir%\fonts\” & fontpath fontpath = _ wshshell.ExpandEnvironmentStrings(fontpath) end if
244
Part II: Co nque ring the File Sys te m
■
■
if fs.FileExists(fontpath) then msg = msg & “ OK.” & vbCr else msg = msg & “ FILE MISSING!” & vbCr end if end if ‘ font section reached? elseif Trim(ucase(line)) = Trim(ucase(key1)) or _ Trim(ucase(line)) = Trim(ucase(key2))then ‘ yes! found = true end if loop handle.close MsgBox msg
Take a c lo se lo o k at ho w this sc ript gets ac c ess to the dump file! It uses OpenTextFile in c o njunc tio n with the o ptio n useDefault. This o ptio n is o f utmo st impo rtanc e. System files are o ften sto red either in UNICODE o r in ANSI, depending o n the Windo ws versio n yo u use. OpenTextFile by default interprets text files as ANSI. On Windo ws 2000 systems, the Registry dump wo uld be unreadable this way. By using useDefault, OpenTextFile interprets the text file c o ntent ac c o rding to the system defaults. Always use useDefault when dealing with system files. No te also ho w this sc ript c hec ks fo r two different Registry keys in o rder to run o n bo th Windo ws 9.x and Windo ws NT/ 2000.
Reading script files Altho ugh it might seem o dd, yo ur sc ript file c an read itself into memo ry, to o . This is useful to embed additio nal info rmatio n into yo ur sc ript file. Take a lo o k at the next example: It uses Internet Explo rer to display an HTML message and reads the HTML c o ntent as part o f the sc ript file (see Figure 7-9): ‘ 7-24.VBS set window1 = OpenMessageWindow(“DISPLAY1”, 300, 100) set window2 = OpenMessageWindow(“DISPLAY2”, 400, 200) sub event_onQuit MsgBox “Hey! You closed my output window!”, vbExclamation WScript.Quit end sub function OpenMessageWindow(title, width, height) set ie = WScript.CreateObject(“InternetExplorer.Application”, _ “event_”) ‘ read in script file line by line
Chapte r 7 : Ac c e s s ing the File Sys te m ■
245 ■
set fs = CreateObject(“Scripting.FileSystemObject”) set handle = fs.OpenTextFile(WScript.ScriptFullName) do until handle.atEndOfStream line = handle.ReadLine if line = “REM HTML START “ & title then start = true elseif line = “REM HTML END” then start = false elseif start then html = html & mid(line,2) & vbCrLf end if loop page = “JavaScript:’” & html & “‘“ ie.navigate page ie.width = width ie.height = height ‘ turn off toolbars ie.Toolbar = false ‘ turn off status bar ie.Statusbar = false do loop while ie.ReadyState4 ie.visible = true ‘ return reference to IE object: Set OpenMessageWindow = ie end function sub PrintNew(obj, text) obj.document.body.innerHTML = text end sub sub Print(obj, text) obj.document.body.insertAdjacentHTML “beforeEnd”, text end sub REM HTML START DISPLAY1 ‘ ‘Welcome! ‘ ‘ ‘ ‘
This is my HTML message!
‘ REM HTML END
246
Part II: Co nque ring the File Sys te m
■
■
REM HTML START DISPLAY2 ‘ ‘Another message! ‘ ‘ ‘ ‘
This is my second HTML message!
‘ REM HTML END
Internet Explo rer and its metho ds are desc ribed in detail in Chapters 5 and 19.
Figure 7-9: Embedding HTML in s cript files and dis playing it as a dialog box.
Creating Files There are two ways to c reate new files: ■ New file fro m sc ratc h: use CreateTextFile ■ Create new file o nly if file do esn’t exist yet: use OpenTextFile
In additio n, yo u c an use OpenTextFile to o pen an existing file fo r reading o r appending.
Logging the use of your computer Fo r example, plac e a link to the fo llo wing sc ript into yo ur StartUp pro gram gro up. Every time the user lo gs o n, the sc ript adds an entry to a lo g file: ‘ 7-25.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set network = CreateObject(“WScript.Network”) logfile = “C:\user.txt” ‘ append to file and create file if it does not exist: Const forAppending = 8 set handle = fs.OpenTextFile(logfile, forAppending, true) handle.WriteLine now & vbTab & network.UserName handle.close
Chapte r 7 : Ac c e s s ing the File Sys te m
247
■
■
Traditio nally, it has been diffic ult to exec ute sc ripts when the user lo gs o ff. Even if yo u use Sc heduled Tasks fro m yo ur Co ntro l Panel, yo u wo n’t find suc h an event. Windo ws 2000’s Lo c al Co mputer Po lic y snap-in, ho wever, features bo th lo go n and lo go ff sc ripts, so it’s easy to also lo g info rmatio n o nc e a user c lo ses Windo ws. Yo ur sc ript c an even auto matic ally c alc ulate ho w many ho urs the perso n was wo rking if this is what yo u want to find o ut.
Renaming files Auto matic ally renaming files c an be o f tremendo us use. Suppo se yo u maintain a fo lder with graphic s yo u like to use. Over time, hundreds and hundreds o f files ac c umulate, and they all use their o wn naming sc heme. It wo uld be tremendo us wo rk to manually rename all these files. A sc ript do es the same thing in no time. Plac e the sc ript in the same fo lder yo u use to sto re the graphic s files, then launc h the sc ript. All .bmp graphic s files will be renamed using a template yo u spec ify. Yo u c an even c all this sc ript repeatedly whenever yo u have c hanged the fo lder c o ntent. The sc ript will auto matic ally fill in “ho les” in the numbering sc heme c aused by deletio ns, and it will leave unto uc hed file names that already use the naming template. Do n’t rename files if yo u already made referenc es to this file. Fo r example, if yo u c reated link files that po int to yo ur files, renaming the files will o bvio usly c ause the links to break. ‘ 7-26.VBS set fs = CreateObject(“Scripting.FileSystemObject”)
‘ naming template template = “pix###” ‘ find out the folder this script is stored in mename = WScript.ScriptFullName mepath = left(mename, InstrRev(mename, “\”)) ‘ access folder set folder = fs.GetFolder(mepath)
‘ reduce template to fixed part template1 = left(template, Instr(template, “#”)-1) ‘ length of numbering scheme template2 = len(template) - len(template1) ‘ start counter counter = 0 ‘ scan through files in folder for each file in folder.files
248
Part II: Co nque ring the File Sys te m
■
■
‘ find out extension ext = lcase(fs.GetExtensionName(file.name)) ‘ is it a bmp graphics file? if ext=”bmp” then ‘ yes, already renamed? if not lcase(left(file.name, len(template1)))=lcase(template1) then ‘ no, rename! do newfilename = template1 & right(“000000” & counter, template2) & “.bmp” counter = counter + 1 loop while fs.FileExists(mepath & newfilename) file.name = newfilename end if end if next MsgBox “Renaming complete!”
Summary In this c hapter, yo u first learned ho w to auto -do c ument the o bjec ts and struc tures o f the Scripting.FileSystemObject o bjec t, and then yo u put tho se metho ds and pro perties to wo rk. By ac c essing drives, fo lders, and files, yo u easily retrieved all the info rmatio n needed fo r daily maintenanc e sc ripts and fo r auto matic ally reo rganizing yo ur data. Yo u develo ped many useful to o ls to auto matic ally rename graphic s arc hives as well as to read (and c hange) file attributes. With the help o f yo ur o wn COM o bjec t, yo u c an even o verc o me the 2GB bug, allo wing yo ur sc ripts to deal with drives o f any size.
Chapte r 8
Advanced File System Tricks In This Chapter 䊳 Use built-in Copy metho ds to c o py files with the pro gress indic ato r
and Undo func tio ns 䊳 Create yo ur o wn Backup to o l to quic kly bac k up tho usands o f files 䊳 Delete files to the Rec yc le Bin, emptying the Rec yc le Bin, and fo rmatting
drives 䊳 Retrieve extended file versio n info rmatio n and returning self-defined
o bjec ts to yo ur sc ripts 䊳 Disc o ver the sec ret shell view o n the file system, c alling c o ntext menu
c o mmands remo tely, and displaying pro perty pages 䊳 Call undo c umented Windo ws API func tio ns and auto matic ally reso lve
the UNICODE/ ANSI c o nflic t
Y
o u are no t limited to the Sc ripting Ho st way o f ac c essing the file system. In this c hapter, yo u learn ho w to write yo ur o wn file system sc ript extensio ns and use the build-in Windo ws metho ds to c o py and mo ve files. Yo u’ll be able to delete files to the rec yc le bin, and disc o ver the Windo ws shell o bjec ts whic h grant additio nal file management func tio ns to yo ur sc ripts.
Using Advanced File System Methods In the previo us c hapter, yo u gained a go o d understanding o f the file system and ho w to c o ntro l fo lders and files by sc ript. There’s a lo t mo re to it, tho ugh. Do n’t limit yo urself to the metho ds the Scripting.FileSystemObject brings alo ng. Find ways to ac c ess impo rtant API func tio ns direc tly so yo u c an use the Rec yc le Bin and file c o py dialo gs. Retrieve interesting advanc ed info rmatio n abo ut exec utables and .dll files, and disc o ver the c o mpletely different appro ac h the new Web view takes to manage the file system.
250
Part II: Co nque ring the File Sys te m
■
■
Kidnapping the shell’s copy station Altho ugh the Scripting.FileSystemObject pro vides yo u with all the metho ds nec essary to to ss aro und files and fo lders, the Windo ws shell do esn’t use any o f these. Instead, Windo ws uses its o wn set o f c o mmands, and fo r go o d reaso n. The regular file transpo rt c o mmands are really very rudimentary. They are dependable, like a Vo lkswagen Beetle, but no t very fanc y. Fo r example, deleting files o r fo lders using Delete will immediately trash the data, witho ut any c hanc e o f rec o very (even if the o peratio n was just an ac c ident). There’s no way the Scripting.FileSystemObject c an delete files o r fo lders to the rec yc ler. There are no undo c apabilities, either, and if mo re than just a c o uple o f files are invo lved in yo ur file o peratio n, no dialo g bo x repo rts the pro gress, keeping the user uninfo rmed. In additio n, the Scripting.FileSystemObject c o py and mo ve c o mmands are very pic ky. They ac t very differently depending o n whether o r no t yo ur file names end with “\” and c an pro duc e strange results if yo u do n’t stic k exac tly to the spec ific atio ns. So ho w do es Windo ws do the tric k? It uses its o wn file transpo rtatio n metho ds, and yo u c an, to o .
Getting access to the Windows file services The Windo ws file transpo rtatio n department resides in shell32.dll. One single API func tio n c alled SHFileOperation handles all the file o peratio ns do ne by the Windo ws shell. Depending o n the flags yo u spec ify, this func tio n c an delete to the rec yc ler, as well as c o py o r mo ve large numbers o f files while displaying a pro gress dialo g bo x. To ac c ess this func tio nality, all yo u need to do is wrap the func tio n as a COM o bjec t. It’s easy. Launc h yo ur Visual Basic CCE and enter the fo llo wing c o de. Or even better — o pen the entire pro jec t file direc tly fro m the c o mpanio n CD, using \components\shellcopy\shellcopy.vbp. If yo u do n’t like to c o mpile the c o de yo urself, install the prepared pac kage — \install\shellcopy\ setup.exe.
Understanding SHFileOperation SHFileOperation is a rather easy API func tio n: The o nly argument required is a struc ture c alled shfileopstruct. This struc ture c o ntains the c o mmands yo u want the shell to exec ute. First o f all, yo u spec ify the kind o f file o peratio n: whether yo u want the shell to delete, c o py, o r mo ve so mething. Next, yo u spec ify the list o f files affec ted by yo ur file o peratio n. Finally, yo u are free to spec ify a set o f flags, effec tively fine-tuning yo ur file o peratio n. These flags determine whether dialo g bo xes will be sho wn and whether o r no t the user is able to undo the file o peratio n by pressing [Strg]+[Z]. Option Explicit
‘ command block Private Type shfileopstruct hwnd As Long wFunc As Long pFrom As String pTo As String fFlags As Integer fAborted As Boolean hNameMaps As Long sProgress As String End Type
‘ ‘ ‘ ‘ ‘
window handle kind of file op list of source files list of destination files flags
‘ API call for shell file operation Private Declare Function SHFileOperation Lib “shell32.dll” _ Alias “SHFileOperationA” (lpFileOp As shfileopstruct) As Long Public Function FileOP(ByVal source As String, Optional ByVal _ dest As String = vbNullChar & vbNullChar, Optional ByVal _ method As Long = FO_COPY, Optional ByVal flag As _ Long = (FOF_NOCONFIRMATION Or FOF_NOCONFIRMMKDIR Or _ FOF_MULTIDESTFILES Or FOF_NOERRORUI)) As Long Dim SHFileOP As shfileopstruct ‘ check whether source file list is valid If Len(source) = 0 Then Err.Raise vbObjectError + 1, “FileOP”, _ “You did not specify list of files” Exit Function End If ‘ make sure flags don’t contain “dangerous” bits: flag = flag And Not 32 ‘ tell file op struct what to do
252
Part II: Co nque ring the File Sys te m
■
■
With SHFileOP .wFunc = method .pFrom = source & vbNullChar & vbNullChar .pTo = dest & vbNullChar & vbNullChar .fFlags = flag End With ‘ execute: FileOP = SHFileOperation(SHFileOP) End Function
Yo u c o uld define a universal wrapper fo r SHFileOperation and leave it to yo ur sc ripters to figure o ut and supply the flags fo r spec ific file o peratio ns. A muc h better appro ac h is to define a c o uple o f func tio ns, eac h spec ializing in o ne o f the many kinds o f file o peratio ns available thro ugh SHFileOperation. This is ho w the sample COM o bjec t has do ne it. Recycle, fo r example, spec ific ally deletes files o r fo lders to the rec yc ler, so there’s no c o nfusio n abo ut the flags and mo des. Public Function Recycle(ByVal source As String, Optional _ ByVal safe As Boolean = True) As Long Dim SHFileOP As shfileopstruct With SHFileOP .wFunc = FO_DELETE .pFrom = source & vbNullChar & vbNullChar .pTo = vbNullChar & vbNullChar .fFlags = FOF_ALLOWUNDO Or FOF_NOCONFIRMATION If safe Then .fFlags = .fFlags Or fof_wantnukewarning End If End With ‘ execute: Recycle = SHFileOperation(SHFileOP) End Function Public Function Copy(ByVal source As String, ByVal dest As _ String, Optional ByVal safe As Boolean = False) As Long Dim SHFileOP As shfileopstruct With SHFileOP .wFunc = FO_COPY .pFrom = source & vbNullChar & vbNullChar .pTo = dest & vbNullChar & vbNullChar .fFlags = FOF_ALLOWUNDO Or FOF_NOCONFIRMATION _ Or FOF_NOCONFIRMMKDIR If safe Then .fFlags = .fFlags Or FOF_RENAMEONCOLLISION End If End With ‘ execute:
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
253 ■
Copy = SHFileOperation(SHFileOP) End Function Public Function CopyMultiDest(ByVal source As String, ByVal _ dest As String, Optional ByVal safe As Boolean = False) As Long Dim SHFileOP As shfileopstruct With SHFileOP .wFunc = FO_COPY .pFrom = source & vbNullChar & vbNullChar .pTo = dest & vbNullChar & vbNullChar .fFlags = FOF_ALLOWUNDO Or FOF_NOCONFIRMATION _ Or FOF_NOCONFIRMMKDIR Or FOF_MULTIDESTFILES If safe Then .fFlags = .fFlags Or FOF_RENAMEONCOLLISION End If End With ‘ execute: CopyMultiDest = SHFileOperation(SHFileOP) End Function Public Function Move(ByVal source As String, ByVal dest As _ String, Optional ByVal safe As Boolean = False) As Long Dim SHFileOP As shfileopstruct With SHFileOP .wFunc = FO_MOVE .pFrom = source & vbNullChar & vbNullChar .pTo = dest & vbNullChar & vbNullChar .fFlags = FOF_ALLOWUNDO Or FOF_NOCONFIRMATION _ Or FOF_NOCONFIRMMKDIR If safe Then .fFlags = .fFlags Or FOF_RENAMEONCOLLISION End If End With ‘ execute: Move = SHFileOperation(SHFileOP) End Function
Deleting Files to the Recycle Bin Deleting files and fo lders witho ut a safety net is risky. Windo ws o ffers suc h a safety net — the Rec yc le Bin sto res deleted data fo r a while so yo u c an easily retrieve ac c identally deleted data. With the help o f yo ur new COM o bjec t, yo ur sc ripts c an delete files to the Rec yc le Bin, to o . The fo llo wing sc ript gets ac c ess to yo ur temp fo lder and deletes any files that are o lder than two days: ‘ 8-1.VBS ‘ make sure you have installed the custom COM object
254
Part II: Co nque ring the File Sys te m
■
■
‘ as outlined in the book set tool = CreateObject(“shellcopy.tool”) ‘ select all files in TEMP folder older than 2 days set fs = CreateObject(“Scripting.FileSystemObject”) set temp = fs.GetSpecialFolder(2) for each file in temp.files if DateDiff(“d”,file.DateLastModified, date)>2 then list = list & file.path & chr(0) end if next ‘ delete in Recycler if len(list)>0 then MsgBox tool.Recycle(list) end if
GetSpecialFolder returns the fo lder o bjec t o f o ne o f the Windo ws spec ial fo lders. Index 2 represents the temp fo lder where Windo ws sto res tempo rary files. The temp fo lder o ften c o ntains a lo t o f o utdated files no lo nger in use. To make sure yo ur sc ript do esn’t delete files still in use, it determines ho w o ld the files are. DateDiff c alc ulates the differenc e between the c urrent date and the date the files were c reated. Recycle deletes files to the Rec yc le Bin. The impo rtant thing to no tic e is the delimiter — Recycle expec ts eac h file name to be separated by a null string: Chr(0). Figure 8-1 sho ws the pro gress dialo g bo x that appears auto matic ally whenever the shell needs mo re than just a sec o nd to c o mplete a file o peratio n.
Figure 8-1: Us e the s hell to delete files to the Recycle Bin. Always use fully qualified path names. If yo u do n’t, the files wo n’t be deleted to the Rec yc le Bin. Instead, Windo ws will delete them immediately. On Windo ws 2000 systems, SHFileOperation suppo rts additio nal flags. One o f them is fof_wantnukewarning, and Recycle uses this flag b y default. Whenever yo u try to delete a file fro m a drive witho ut a Rec yc le Bin ( like a disk drive, fo r example) , yo u rec eive a warning stating that the file yo u are deleting will b e permanently deleted. On o ther Windo ws versio ns, yo u do no t get suc h a warning.
Chapte r 8 : Advanc e d File Sys te m Tric ks
255
■
■
Emptying the recycler No w that yo u c an delete files to the Rec yc le Bin, yo u might wo nder ho w yo ur sc ripts c an ac tually flush the Rec yc le Bin and permanently delete its c o ntent. It’s easy: Just use ano ther API func tio n c alled SHEmptyRecycleBin. Or even easier: Use the metho d EmptyRecycler I have prepared fo r yo u: Option Explicit Private Const SHERB_NOCONFIRMATION = &H1 Private Const SHERB_NOPROGRESSUI = &H2 Private Const SHERB_NOSOUND = &H4 Private Declare Function SHEmptyRecycleBin Lib “shell32.dll” _ Alias “SHEmptyRecycleBinA” (ByVal hwnd As Long, _ ByVal root As Long, ByVal flags As Long) As Long Public Function EmptyRecycler(Optional ByVal _ flags As Long = SHERB_NOCONFIRMATION) As Long EmptyRecycler = SHEmptyRecycleBin(0, 0, flags) End Function
The next sc ript sho ws ho w to empty yo ur Rec yc le Bin: ‘ 8-2.VBS set tool = CreateObject(“shellcopy.tool”) tool.EmptyRecycler
By default, EmptyRecycler do esn’t sho w a c o nfirmatio n dialo g bo x. It do es, ho wever, sho w a pro gress indic ato r if yo ur Rec yc le Bin c o ntains mo re than just a handful o f files. To c o ntro l the pro c ess in mo re detail, yo u are free to spec ify additio nal flags, as sho wn in Table 8-1.
Table 8-1
Additional Flags for Emptying the Recycler
Flag
Description
1
Don’t s how a confirmation dialog box (default)
2
Don’t s how a progres s indicator
4
Don’t play the empty recycler s ound
Just pass the sum o f the desired flags as an argument to EmptyRecycler. Ac tually, SHEmptyRecycleBin allo ws yo u to empty individual Rec yc le Bins lo c ated o n individual drives. In this example, the COM o bjec t do esn’t use this feature, ho wever, bec ause o n so me Windo ws versio ns, deleting individual Rec yc le Bins messes up Registry values. This leads to strange behavio r, preventing yo u fro m emptying yo ur Rec yc le Bin.
256
Part II: Co nque ring the File Sys te m
■
■
Copying and Moving Files Co pying and mo ving files and fo lders is extremely easy — thanks to yo ur new c o mmands. They take c are o f mo st things. Fo r example, if the destinatio n fo lder do esn’t yet exist, Windo ws auto matic ally c reates it. Use flag NOCONFIRMMKDIR to determine whether windo ws sho uld ask fo r permissio n befo re auto matic ally generating new fo lders. Use RENAMEONCOLLISION to have Windo ws rename destinatio n files that already exist. With FILESONLY and NORECURSION, yo u c an safeguard rec ursive file o peratio ns. Rec ursive file o peratio ns take plac e when yo u use wildc ard c harac ters, suc h as C:\*.EXE, in yo ur so urc e file names. NOCOPYSECURITYATTRIBS is a new flag and o nly takes effec t o n Windo ws 2000 mac hines: It prevents Windo ws fro m c o pying the sec urity attributes asso c iated with a file.
Backing up valuable data The next sc ript demo nstrates ho w po werful file c o py c an be. It’s a full bac kup sc ript, and all yo u need to do is spec ify the so urc e fo lder and destinatio n fo lder. The sc ript determines whic h files need to be updated by c hec king whether the so urc e files already exist in the bac kup set, and if they do , whether their c o ntent has c hanged sinc e the last bac kup. This sc ript uses the Archive attribute to c hec k whether a file’s c o ntents have c hanged. It c lears the Arc hive attribute whenever it has c o pied a file. And it o nly c o pies files where the Arc hive attribute is set. Remember: Windo ws sets the Arc hive attribute auto matic ally the mo ment yo u save a file. If yo ur b ac kup inc ludes mo re than just a few files, the c o py metho d auto matic ally displays a pro gress indic ato r, as sho wn in Figure 8-2, telling yo u what’s go ing o n. No te, ho wever, that it may take so me sec o nds to c reate the file list, and during this part, yo u do n’t see any dialo g b o x. ‘ 8-3.VBS ‘ make sure you have installed the custom COM object ‘ as outlined in the book set tool = CreateObject(“shellcopy.tool”) set fs = CreateObject(“Scripting.FileSystemObject”) ‘ global variables: source = “D:\SOURCES\” dest = “C:\BACKUP\” ‘ list of files to be copied: sourcelist = “” ‘ list of destination files: destlist = “”
Chapte r 8 : Advanc e d File Sys te m Tric ks
257
■
■
‘ counts counter1 ‘ counts counter2
checked files = 0 copied files = 0
‘ check whether folder names are properly formatted: if not right(source,1)=”\” then source = source & “\” if not right(dest,1)=”\” then dest = dest & “\” ‘ select files to copy: BackupFolder fs.GetFolder(source) ‘ copy files if any: if counter2>0 then tool.CopyMultiDest sourcelist, destlist ‘ report MsgBox “Backup done:” & vbCr & counter1 & “ files checked.” & vbCr & counter2 & “ files copied.” & vbCr & counter1-counter2 & “ files upto-date.”
sub BackupFolder(folderobj) ‘ determine corresponding destination folder destfolder = dest & mid(folderobj.path, len(source)+1) ‘ create folder if missing ‘ this is not absolutely necessary as SHFileOperation creates ‘ folders automatically. Still, it’s needed if you want to create ‘ empty folders in your backup set if not fs.FolderExists(destfolder) then fs.CreateFolder destfolder end if ‘ check all files in current folder for each file in folderobj.files ‘ determine corresponding destination file name destfilename = dest & mid(file.path, len(source)+1) ‘ increment file counter counter1 = counter1 + 1 ‘ select file if it does not exist in backup or ‘ if original file has changed (archive attribute set): if (not fs.FileExists(destfilename)) or _ ((file.Attributes and 32)=32) then ‘ increment file copy counter counter2 = counter2 + 1 ‘ add file name to source list sourcelist = sourcelist & file.path & Chr(0) ‘ add destination file name to dest list destlist = destlist & destfilename & Chr(0) ‘ clear archive attribute file.Attributes = file.Attributes and not 14000 _ and not 32
258
Part II: Co nque ring the File Sys te m
■
■
end if next ‘ do the same for any subfolders ‘ clear this part if you do not want recursive backups for each subfolder in folderobj.subfolders BackupFolder subfolder next end sub
This sc ript really is versatile, and it eliminates the hassle no rmally invo lved in bac kups. This sc ript do esn’t c o mpress the bac ked up files. Ho wever, even c o mmerc ial bac kup so ftware do esn’t squeeze files well, and if yo u are using Windo ws NT/ 2000, yo u c an have the o perating system c o mpress yo ur bac kup fo lder. No t c o mpressing files is o f great advantage: This bac kup metho d do esn’t invo lve pro prietary bac kup file sets.
Figure 8-2: Back up entire folders (including s ubfolders ) to any des tination. Yo u c an always ac c ess yo ur bac kup files thro ugh the regular Explo rer bec ause yo ur bac ked up files and fo lders remain regular files and fo lders. Yo u do n’t need spec ial so ftware to retrieve bac ked up files. Even mo re impo rtant: Thro ugh the use o f the Arc hive bit, yo ur bac kup sc ript is extremely effic ient. It o nly c o pies true c hanges, so yo u do n’t need to wait fo rever fo r yo ur bac kup to c o mplete, and it returns a bac kup repo rt, as sho wn in Figure 8-3. If yo u wanted to use the same effic ient strategy with c o mmerc ial bac kup so ftware, yo u’d have to do inc remental bac kups. They’re no fun, espec ially bec ause yo u end up with vario us bac kup sets, and if yo u have so me kind o f emergenc y, yo u’ll need to extrac t files fro m many different bac kup sets. But this is yo ur so lutio n — it’s very basic , very easy, and very effic ient.
Figure 8-3: Your backup s cript only copies files that have changed s ince the las t backup.
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
259 ■
The sc ript c hec ks fo lders separately, and if a fo lder is missing in yo ur bac kup set, it will be auto matic ally c reated. This is so mewhat redundant. The SHFileOperation func tio n auto matic ally c reates any needed fo lders. Ho wever, it wo n’t c reate empty fo lders. To inc lude empty fo lders in yo ur bac kup, yo u need to c hec k fo r them yo urself.
Copying files to multiple folders The bac kup sc ript demo nstrates ano ther tec hnique, c alled MultiDest c o pying. The regular c o py c o mmand c o pies a list o f files to o ne c o mmo n fo lder. This wo uldn’t wo rk fo r yo ur bac kup so lutio n, bec ause, after all, yo u want to be able to c o py many different files fro m many different fo lders to many different destinatio n fo lders. Here c o mes CopyMultiDest to the resc ue! It’s ac tually just the Co py metho d using the spec ial MULTIDESTFILES flag. With this flag enab led, SHFileOperation expec ts to rec eive two file lists: o ne c o ntaining the o riginal ( so urc e) filenames and ano ther o ne c o ntaining the destinatio n filenames. So fo r eac h file, yo u define an entry in b o th lists. Always no te the differenc e. The regular c o py metho d ac c epts a list o f so urc e files and a destinatio n fo lder. The CopyMultiDest metho d ac c epts two filename lists.
Formatting Drives Maybe o ne o f these days yo u’ll find it nec essary to fo rmat a drive. But yo u’re o ut o f luc k — Visual Basic is inc apable o f do ing this. So ho w do es Windo ws po p up its Fo rmat Drive dialo g b o x? It uses the undo c umented SHFormatDrive API c all — and yo u c an, to o ! Either o pen the pro jec t fro m the c o mpanio n CD ( \components\format\format.vbp) o r install the prepared pac kage ( \install\format\setup.exe) . Option Explicit Private Declare Function SHFormatDrive Lib “shell32” _ (ByVal hwnd As Long, ByVal drive As Long, ByVal fmtID As _ Long, ByVal options As Long) As Long Private Declare Function GetDriveType Lib “kernel32” _ Alias “GetDriveTypeA” (ByVal nDrive As String) As Long Private Private Private Private Private
Public Function format(ByVal driveletter As String, _ Optional quick As Boolean = True, _ Optional ByVal safe As Boolean = True) Dim drive As String Dim driveindex As Long Dim mode As Long drive = Left(driveletter, 1) & “:\” driveindex = Asc(UCase(driveletter)) - Asc(“A”) If (Not safe) Or GetDriveType(drive) = 2 Then If quick Then mode = SHFMT_OPT_QUICK Else mode = SHFMT_OPT_FULL End If format = SHFormatDrive(0, driveindex, SHFMT_ID_DEFAULT, mode) Else Err.Raise vbObjectError + 1, “format()”, “Drive “ & drive _ & “ is a fixed disk and cannot be formatted.” End If End Function
Fo rmat is straightfo rward to use: Just spec ify the drive letter o f the drive yo u want to fo rmat. Windo ws po ps up the Fo rmat Drive dialo g bo x and pre-selec ts Quic k Fo rmat. To o verrun this default and pre-selec t a full fo rmat, use false as a sec o nd argument. Figure 8-4 sho ws the dialo g bo x that po ps up auto matic ally if no disk is inserted into yo ur drive.
Figure 8-4: The s cript invokes the official format dialog box and reports mis s ing dis ks . Format has a built-in safety guard. Whenever yo u spec ify a fixed drive, suc h as a hard drive, the metho d will raise an erro r, and yo u’ll rec eive a message similar to the o ne sho wn in Figure 8-5. Yo u do n’t need to fo rmat hard drives very o ften,
Chapte r 8 : Advanc e d File Sys te m Tric ks
261
■
■
and do ing so by ac c ident c an c o st yo u a fo rtune. If yo u must fo rmat a hard drive, o verrun the safety guard: Spec ify false as a third parameter. No te the use o f GetDriveType: This API func tio n reveals the type o f a drive. It’s analo go us to the Scripting.FileSystemObjects’ Drive o bjec t’s DriveType pro perty. ‘ 8-4.vbs set tool = CreateObject(“format.tool”) MsgBox tool.Format(“A:\”) MsgBox tool.Format(“D:\”)
SHFormatDrive c an o nly po p up the dialo g bo x. So there’s no way yo u c an auto matic ally launc h the fo rmatting pro c ess, right? Sure there is! Onc e the dialo g bo x is o pen, yo u c an use SendKeys to fill in the nec essary key stro kes. Ho wever, fo rmatting drives witho ut user interac tio n is po tentially dangero us.
Figure 8-5: The s cript w on’t format fixed drives unles s you explicitly as k for it. Fo rmat returns a status letting yo u kno w if everything went well, as sho wn in Table 8-2.
Table 8-2
Format’s Error Codes
Error Code
Description
0
All is OK.
-1
An Error occurred; drive may s till be formattable.
-2
A us er interrupted the las t format.
-3
Drive media is not formattable.
No te, ho wever, that yo ur new Format metho d do esn’t c hec k fo r erro rs. whether a drive really exists. It c o nc entrates o nly o n fo rmatting the drive yo u spec ify. Ho wever, with the metho ds o f the Scripting. FileSystemObject, yo u c an easily add erro r-c hec king. Fo r example, use GetDrive to see whether a drive exists, and use isReady to c hec k whether it c o ntains media. It’s c o mpletely up to yo u: Either do the erro rc hec king inside o f yo ur sc ripts, o r enhanc e the COM o bjec t c o de.
262
Part II: Co nque ring the File Sys te m
■
■
On Windo ws 9.x mac hines, yo u c an use rundll32.exe to launc h SHFormatDrive direc tly. Cho o se Run fro m yo ur Start menu and enter: rundll32.exe shell32.dll, SHFormatDrive [Enter]. Do n’t insert spac es befo re o r after the c o mma. Rundll32.exe is o nly available o n Win9.x. It c alls the entry po int o f any .dll func tio n and is used by the system. Ho wever, rundll32.exe do esn’t allo w yo u to spec ify any arguments. Calling .dll func tio ns this way may c rash the system if the .dll func tio ns c an’t handle this.
Uncovering Extended File Version Information The new Sc ripting Ho st has finally bro ught to yo u a way o f determining a file’s versio n number, c alled GetFileVersion. On o lder WSH 2.0 versio ns, GetFileVersion will raise an erro r, ho wever, if the examined file do esn’t c o ntain versio n info rmatio n. What’s even mo re anno ying is the fac t that many mo re useful piec es o f info rmatio n are buried in mo st exec utable files. Why c an yo u o nly retrieve the file versio n? Yo u c an get muc h mo re! Just c all the GetFileVersionInfo API func tio n direc tly, and yo u will be able to retrieve info rmatio n abo ut debug, preview, and patc hed flags, determine the o perating system a file was designed fo r (distinguishing DOS applic atio ns and true Windo ws applic atio ns), and mo re. While we are at it, yo u will also see ho w to define o b jec ts yo urself. The fo llo wing COM o b jec t returns all the file info rmatio n as an o b jec t. This o b jec t c o ntains the info rmatio n ab o ut a spec ific file and c an b e q ueried using vario us pro perties. It ac ts just like a File o r Drive o b jec t, making it easy fo r yo u to struc ture info rmatio n.
Accessing file version information Version.dll delivers all the func tio ns nec essary to extrac t file versio n info rmatio n. I’ve again prepared a wo rking example: Lo ad the pro jec t ( \components\version\version.vbp) o r install the so ftware pac kage ( \install\version\setup.exe). To be able to retrieve the info rmatio n hassle-free, this time the COM o bjec t returns an info rmatio n o bjec t to yo ur sc ript. Yo ur basic COM mo dule, therefo re, just c o nsists o f o ne metho d, c alled GetVersion. This metho d c reates a new o bjec t c alled version, initializes this o bjec t with the filename o f the file yo u are interested in, and returns the o bjec t to yo ur sc ript: Public Function GetVersion(ByVal filename As String) As version Set GetVersion = New version GetVersion.Init filename End Function
Chapte r 8 : Advanc e d File Sys te m Tric ks
263
■
■
All the mec hanic al parts are sto red in the versio n o bjec t. Where did it c o me fro m? Yo u pro vided it! Take a lo o k at yo ur Pro jec t windo w: In additio n to the User Co ntro l, yo ur pro jec t c o nsists o f a c lass mo dule. This mo dule defines yo ur versio n o bjec t. Class mo dules are really no thing new. They are just additio nal mo dules c o ntaining arbitrary c o de. In c o ntrast to yo ur User Co ntro l, c lass mo dules c an be instantiated using the New o perato r. They ac t as separate blac k bo xes, and mo st impo rtantly o f all, yo u c an return c lass mo dules to yo ur sc ript — c lass mo dules are separate COM o bjec ts. Take a lo o k at the c o ntent o f yo ur c lass mo dule. Here, yo u find all the API dec laratio ns invo lving version.dll. One very impo rtant metho d is c alled Init. It initializes the data struc tures o f yo ur o bjec t. After all, a plain vanilla versio n o bjec t wo n’t do muc h go o d. Befo re yo u c an use it, the versio n o bjec t needs to read in the versio n info rmatio n o f so me file. This is do ne by Init. The retrieved info rmatio n is made ac c essible thro ugh pro perties. Eac h pro perty first c hec ks whether infoavailable is true — in essenc e, it c hec ks whether o r no t yo u have initialized yo ur o bjec t yet. Ano ther very impo rtant design c o nc ept is the use o f glo bal variables. The info rmatio n Init retrieves must be glo bally available so the pro perty pro c edures c an ac c ess and return it. This is why the info rmatio n struc ture VS_FIXEDFILEINFO is dec lared as Private, o utside o f any metho d o r pro c edure. udtVerBufferG is therefo re glo bally ac c essible fro m inside the versio n o bjec t.
Finding out file versions and copyright information Thanks to yo ur COM o bjec t’s arc hitec ture, it’s no w extremely easy to retrieve all kinds o f interesting file info rmatio n (See Figure 8-6). Chec k o ut ho w easy it is to determine yo ur Explo rer’s file versio n, amo ng o ther info rmatio n: ‘ 8-5.VBS set version = CreateObject(“file.versioninfo”) set wshshell = CreateObject(“WScript.Shell”) windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) filename = “explorer.exe” set obj = version.GetVersion(windir & “\” & filename) if obj.isVer then msg = msg & “Version: “ & obj.FileVersion & vbCr msg = msg & “Designed for: “ & obj.OS & vbCr msg = msg & “Designed by: “ & obj.CompanyName & vbCr msg = msg & “Description: “ & obj.FileDescription & vbCr msg = msg & obj.LegalCopyright end if MsgBox “Information about “ & filename & vbCr & msg
264
Part II: Co nque ring the File Sys te m
■
■
Figure 8-6: Retrieve extended vers ion information for any file. Figure 8-6 sho ws o nly part o f the info rmatio n yo ur new to o l makes available. Table 8-3 sho ws the c o mplete list o f info rmatio n yo u are no w able to retrieve:
Table 8-3
Custom Properties Your Tool Retrieves
Property
Description
CompanyName
Name of company that des igned this file.
FileDescription
Des cription of w hat the file is s uppos ed to do.
FileType
Type of file, e.g. Application, DLL, Driver, Font.
FileVersion
File vers ion number..
InternalName
Name this file is referenced internally (independent of how you renamed the file).
isDebug
True: file contains debug code.
isPatch
True: file has been patched.
isPrerelease
True: file is a prereleas e vers ion.
isPrivate
True: file is for private us e only.
isSpecial
True: s ome indicator for “s pecial” build.
isVer
True: file contains vers ion information.
LegalCopyright
Copyright information.
OriginalFileName
Original file name (in cas e s omeone renamed the file).
OS
Operating s ys tem this file w as des igned for.
ProductName
Name of the product this file belongs to.
ProductVersion
Vers ion of the product this file is part of.
SubType
Additional file information, e.g. type of driver or type of font.
Chapte r 8 : Advanc e d File Sys te m Tric ks
265
■
■
Searching for 16-Bit Windows files Curio us to see ho w many 16-bit applic atio ns are still flo ating aro und o n yo ur system? It’s easy no w: ‘ 8-6.VBS set version = CreateObject(“file.versioninfo”) set fs = CreateObject(“Scripting.FileSystemObject”) ‘ start with windows folder set windir = fs.GetSpecialFolder(0) list = “” ‘ recursively check all folders ‘ may take some time... CheckFolder windir MsgBox list sub CheckFolder(folderobj) ‘ check any file with extension “com” or “exe” for each file in folderobj.files ext = lcase(fs.GetExtensionName(file.name)) if ext=”exe” or ext=”com” then set obj = version.GetVersion(file.path) if obj.isVer then ‘ if 16bit then add to list if obj.OS = “16Bit Windows” then list = list & file.path & vbCr end if end if end if next ‘ check all subfolders (recursive search) for each subfolder in folderobj.subfolders CheckFolder subfolder next end sub
Figure 8-7 lists all files lo c ated in yo ur Windo ws fo lder (o r any o f its subfo lders) marked as “16bit.”
266
Part II: Co nque ring the File Sys te m
■
■
Figure 8-7: Identify all 16-bit applications running on your s ys tem.
Searching for DOS files Ho w c an yo u retrieve a list o f pure DOS exec utables? Yo u c o uld c hec k the OS pro perty fo r MS-DOS, but this wo uldn’t get yo u very far. DOS exec utables aren’t team players mo st o f the time — they selfishly use the entire c o mputer fo r themselves, instead. They do n’t c are muc h abo ut o ther o perating systems, and this is why mo st DOS exec utables do n’t even c o ntain versio n info rmatio n. Just searc h fo r any file with a .com o r .exe extensio n that do esn’t c o ntain valid versio n info rmatio n: isVer returns false. Yo u c an safely assume that suc h exec utables are DOS exec utables.
Exploring Windows system files Of c o urse, yo u c an — and sho uld — c o mbine the func tio ns and metho ds yo u’ve c reated thro ugho ut this bo o k. Remember the ListView c o ntro l in Chapter 6? It allo wed yo u to list info rmatio n in c o lumns and so rt these c o lumns any way yo u wanted. The List view c o ntro l is the perfec t c o mpanio n fo r building a little to o l that lets yo u explo re c o re Windo ws files — with the help o f the extended versio n info rmatio n. Figure 8-8 demo nstrates ho w muc h better yo ur sc ript c an no w display the results.
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
267 ■
Figure 8-8: Window s tells you hidden details about its s ys tem files . Fo r this example to run, yo u need to install bo th the versio n COM and the ListView COM: \install\listview\setup.exe. ‘ 8-7.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set lview = CreateObject(“listview.tool”) set version = CreateObject(“file.versioninfo”) windir = fs.GetSpecialFolder(0).Path CheckFolder windir CheckFolder windir & “\system” CheckFolder windir & “\fonts”
sub CheckFolder(name) set folder = fs.GetFolder(name) ‘ scale dialog box lview.width = 600 lview.height = 400 ‘ design some column headers lview.AddHeader lview.AddHeader lview.AddHeader lview.AddHeader lview.AddHeader lview.AddHeader lview.AddHeader
‘ read files into ListView: for each file in folder.files lview.AddItem file.name set obj = version.GetVersion(file.path) if obj.isVer then lview.AddSubItem 1, obj.FileDescription lview.AddSubItem 2, obj.FileVersion lview.AddSubItem 3, obj.OS lview.AddSubItem 4, obj.FileType lview.AddSubItem 5, obj.SubType lview.AddSubItem 6, obj.CompanyName end if next ‘ sort result ‘ 0 = first column ‘ 1 = second column... lview.Sort 1, 1 set result = lview.Show(“Extended Information: “ & name) end sub
The sc ript o pens the Windo ws fo lder, the system fo lder, and the fo nts fo lder. It also displays extended file info rmatio n. File Desc riptio n turns o ut to be a mo st valuable info rmatio n so urc e: It reveals the deeper meaning o f many o f the hidden and undo c umented Windo ws exec utables and retrieves info rmatio n abo ut fo nts (see Figure 8-9). Just c lic k o n any o f the c o lumn headers to so rt the result. Clic k again to so rt the o ppo site way.
Figure 8-9: You can s ort columns and retrieve s ys tem information s uch as ins talled fonts .
Chapte r 8 : Advanc e d File Sys te m Tric ks
269
■
■
Compressing (and decompressing) files Mic ro so ft has inc luded a little hidden present fo r yo u. As part o f the Visual Basic CCE, it ships the vbskco32.dll file. This file c o ntains the func tio n to c o mpress files. The ability to dec o mpress files is inc luded with any Windo ws versio n — lz32.dll o ffers the nec essary func tio ns. Being able to c o mpress files is o f great help. Just imagine yo u need to hand o ver data that do esn’t fit o n a disk. Co mpress the data, and c hanc es are yo u will be able to squeeze yo ur data o n the disk. Dec o mpressing files is a standard Windo ws func tio nality. Many installatio n pac kages and fo nt files c o me in c o mpressed fo rmat. Yo u c an rec o gnize suc h files by lo o king fo r undersc o res in the files’ extensio ns. The c reatio n o f c o mpressed files is no t suppo rted by Windo ws by default. Ho wever, bec ause the VB CCE c o mes with the Applic atio n Wizard, and bec ause this wizard pro duc es c o mpressed setup pac kages, the VB CCE inc ludes the nec essary c o mpressio n func tio ns. By taking advantage o f vbskco32. dll, yo u are free to c o mpress yo ur o wn files and dec o mpress them later.
Getting access to compression functions I’ve prepared a c o mpressio n wrapper fo r yo u. Again, it’s a COM o bjec t. Either o pen the pro jec t and c o mpile it yo urself with \components \compress\compress.vbp, o r just install the prepac kaged setup file: \install\compress\setup.exe. If yo u dec ide to rec o mpile the pro jec t, make sure the file vbskco32.dll is sto red in yo ur Windo ws system fo lder. If it’s no t, yo u need to spec ify the full path name in the LcbCompressFile dec laratio n. The COM o bjec t’s name is compress.files. It pro vides yo u with the two metho ds — CompressIt and ExpandIt.
Squeezing files onto a disk Ho w do yo u sto re c o mpressed files o nto a disk? Just use the fo llo wing sc ript. Either drag files o nto the sc ript ic o n, o r o pen the sc ript direc tly. The sc ript will no w display a message similar to the o ne sho wn in Figure 8-10 and o ffer to plac e a referenc e to itself in yo ur SendTo menu. Fro m no w o n, yo u c an right-c lic k any file, c ho o se Send to , and then c ho o se Co mpress to Disk. The file will be c o mpressed and sto red o n yo ur drive A:\. Yo ur sc ript will keep yo u info rmed and po p up messages like the o ne sho wn in Figure 8-11.
270
Part II: Co nque ring the File Sys te m
■
■
Change the drive letter in the sc ript if yo u’d like to use a different drive instead. No te that this sc ript c an o nly wo rk if yo ur Sc ripting Ho st is c apable o f drag-anddro p o peratio ns. Make sure yo u have upgraded to at least WSH 2.0, as o utlined in the Prefac e.
Figure 8-10: If you launch the s cript directly, it w ill ins tall its elf into the SendTo menu. ‘ 8-8.VBS set args = WScript.Arguments destination = “A:\” if args.Count>0 then set tool = CreateObject(“compress.files”) counter = 0 for each file in args filename = mid(file, InstrRev(file, “\”)+1) destname = destination & filename & “.compress” MsgBox file & “->” & destname returnval = tool.CompressIt(file, destname) if returnval>=0 then counter = counter + 1 next MsgBox “Compressed “ & counter & “ files.” else answer = MsgBox(“This script is intended as SendTo Extension.” _ & “ Do you want to install it?”, vbYesNo) if answer = vbYes then set wshshell = CreateObject(“WScript.Shell”) sendto = wshshell.SpecialFolders(“SENDTO”) set scut = wshshell.CreateShortcut(sendto _ & “\Compress to Disk.lnk”) scut.TargetPath = WScript.ScriptFullName scut.IconLocation = “shell32.dll,1” scut.Save MsgBox “Installed.” end if end if
The sc ript adds the .compress extensio n to yo ur c o mpressed files to indic ate that they are no lo nger regular files and c an’t be o pened direc tly.
Chapte r 8 : Advanc e d File Sys te m Tric ks
271
■
■
Figure 8-11: Your new context menu command compres s es files to dis k.
Decompressing compressed files Dec o mpressing wo rks similarly. The next sc ript dec o mpresses any c o mpressed files sto red o n a disk. The sc ript pro mpts fo r a fo lder in whic h it sto res the revitalized files. ‘ 8-9.VBS set args = WScript.Arguments set fs = CreateObject(“Scripting.FileSystemObject”) set tool = CreateObject(“compress.files”) destination = “A:\” destfolder = InputBox(“Where do you want to store “ _ & “the files?”,,”C:\TEMP”) if not right(destfolder,1)=”\” then destfolder = destfolder & “\” if not fs.FolderExists(destfolder) then fs.CreateFolder destfolder end if set folder = fs.GetFolder(destination) for each file in folder.files if lcase(fs.GetExtensionName(file.name))=”compress” then newfilename = destfolder & _ Replace(mid(file.path, 4), “.compress”, “”)
272
Part II: Co nque ring the File Sys te m
■
■
tool.ExpandIt file.path, newfilename end if next MsgBox “Done.”
Yo u do n’t even need yo ur COM wrapper to dec o mpress files. Any Windo ws versio n c o mes with the DOS c o mmand-line to o l expand.exe. It will dec o mpress files and entire fo lder c o ntents, pro vided the files were c o mpressed using the c o mpressio n to o l yo u just c reated. Therefo re, yo ur new c o mpressio n c o mmand is perfec tly suited to c o mpress distributio n files. On yo ur destinatio n system, yo u do n’t need a Windo ws Sc ripting Ho st to dec o mpress the files. A simple DOS batc h file will do the jo b. Ho wever, expand.exe wo n’t run in pure DOS mo de. To see all o ptio ns, o pen the c o mmand windo w as sho wn in Figure 8-12 and enter expand.exe /?.
Figure 8-12: Window s already contains the tools to decompres s your files .
Some second thoughts about compression The c o mpressio n algo rithms the previo us func tio ns use are no t o ptimized. Yo u get muc h better c o mpressio n ratio s using WinZIP o r o ther c o mmerc ial c o mpressio n to o ls. Still, the built-in file c o mpressio n func tio ns c o me in handy, espec ially as yo u are no w able to ac c ess c o mpressed system files individually. The mo st impo rtant advantage is that c o mpressed files c an be dec o mpressed so lely with built-in Windo ws func tio ns o r with the help o f expand.exe. To find c o mpressed system files, searc h fo r *.??_. This will list all files with an undersc o re at the end o f their file extensio ns. The system uses the third letter o f a file’s extensio n to indic ate that it’s c o mpressed. In o rder to re-c reate the o riginal file, yo u’ll need to manually c hange the file extensio n and replac e the undersc o re with the missing letter. There’s no c lue to whic h letter this c o uld be — it’s all up to yo ur experienc e. Fro m what yo u have learned so far, tho ugh, it’s safe to assume that a .dl_ file extensio n expands to .dll, whereas a .tt_ extensio n expands to .ttf.
273
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
■
The Secret Shell View on the File System So far, the Scripting.FileSystemObject has been yo ur sec ret do o r into the Windo ws file system. It has pro vided yo u with all the metho ds and pro perties nec essary to ac c ess and manipulate files and fo lders. There’s ano ther sec ret do o r, tho ugh, and it’s almo st undo c umented.
An inside view of the shell.Application object This sec o nd sec ret do o r is used by the shell and hides behind the shell. Application o bjec t. Let’s c hec k o ut ho w yo ur sc ripts c an benefit fro m shell.Application. Table 8-4 takes a lo o k at all the internal metho ds and pro perties. Ho wever, the shell.Application o bjec t will o nly be ac c essible if yo u have installed Internet Explo rer 4 o r use Windo ws 98/ 2000. Fo r so me unkno wn reaso n, shell.Application isn’t ac c essible o n Internet Explo rer 5.
Table 8-4
Shell.Application Properties and M ethods
M ethod/Property
Description
Property Application As Object
Get Application object
Function BrowseForFolder (ByVal Hwnd As Long, ByVal Title As String, ByVal Options As Long, [ByVal RootFolder]) As Folder
Brow s e the name s pace for a Folder
Sub CascadeWindows
Cas cade Window s
Sub ControlPanelItem (ByVal szDir As String)
Run a controlpanelItem
Sub EjectPC
Undock a notebook PC
Sub Explore(ByVal vDir)
Explore a folder
Sub FileRun
Bring up the file run
Sub FindComputer
Find a computer
Sub FindFiles
Find files
Sub Help
Dis play s hell help
Sub MinimizeAll
Minimize all w indow s Co ntinue d
274
Part II: Co nque ring the File Sys te m
■
■
Table 8-4
( co ntinue d)
M ethod/Property
Description
Function namespace (ByVal vDir) As Folder
ShellSpecialFolderConstants
Sub Open(ByVal vDir)
Open a folder
Property Parent As Object
Get Parent object
Sub RefreshMenu
Refres h the menu
Sub SetTime
Bring up the Set time dialog box
Sub ShutdownWindows
Exit Window s
Sub Suspend
Sus pend the PC
Sub TileHorizontally
Tile w indow s horizontally
Sub TileVertically
Tile w indow s vertically
Sub TrayProperties
Handle Tray properties
Sub UndoMinimizeALL
Undo Minimize All
Function Windows As Object
Collect open folder w indow s
Get special folder from
Accessing folders the shell way Always remember: The Scripting.FileSystemObject was c reated fo r pro grammers o nly. It’s no t an internal part o f Windo ws, and so the shell must use its o wn set o f file system c o mmands. Yo u are abo ut to enter a c o mpletely new and different wo rld. Any o bjec ts yo u enc o unter here are c o mpletely different fro m the Scripting.FileSystemObject, even if they share so me names. This is ho w the shell ac c esses a fo lder: ‘ 8-10.VBS set shell = CreateObject(“Shell.Application”) set folder = shell.namespace(“C:\”) MsgBox “Object Type: “ & TypeName(folder)
Yo ur sc ript retrieves a folder o r Folder2object, depending o n yo ur system’s shell versio n. Table 8-5 sho ws the metho ds and pro perties o f this o bjec t.
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
275 ■
Table 8-5
Shell.Application Folder Object
M ethod/Property
Description
Property Application As Object
Get Application object
Sub CopyHere(ByVal vItem, [ByVal vOptions])
Copy items to this folder
Function GetDetailsOf
Get the details about an item
(ByVal vItem, ByVal iColumn As Long) As String Function Items As FolderItems
Collec items in a folder
Sub MoveHere(ByVal vItem, [ByVal vOptions])
Move items to this folder
Sub NewFolder(ByVal bName As String, [ByVal vOptions])
Create a new s ub-folder in this folder
Property OfflineStatus As Long
(new ) Offline s tatus of the s erver
Property Parent As Object
Get Parent object
Property ParentFolder As Folder
Get Parent object
Function ParseName (ByVal bName As String) As FolderItem
Pars e the name to get an item
Property Self As FolderItem
(new ) Folder’s FolderItem interface
Sub Synchronize
(new ) Synchronize all offline files
Property Title As String
Get the dis play name for the w indow
There are ac tually two o bjec ts — Folder and Folder2. The Folder o bjec t is used by Windo ws 98 and Internet Explo rer 4. Folder2 is a revised o bjec t intro duc ed by Windo ws 2000. It c o ntains additio nal metho ds and pro perties (marked as “new” in Table 8-3).
276
Part II: Co nque ring the File Sys te m
■
■
Finding out a folder’s name The shell.Application o bjec t really is the shell view o f the file system, and the fo llo wing sc ript pro ves it: ‘ 8-11.VBS set shell = CreateObject(“Shell.Application”) set folder = shell.namespace(“C:\”) MsgBox “Shell Name of folder C:\: “ & vbCr & folder.Title if TypeName(folder)=”Folder2” then MsgBox “Real Name of folder C:\: “ & vbCr & folder.self.Path end if
The Folder o bjec t’s Title pro perty returns the fo lder name fro m the shell’s view. Figure 8-13 pro ves that it’s no plain path name. Instead, it’s the name o f the drive as it appears in the Explo rer.
Figure 8-13: In the s hell, files and folders may have s pecial names . To retrieve the true path name, the sc ript uses the Folder2 o bjec t’s Self pro perty. This pro perty is new and no t available in Folder o bjec ts. Yo u c an use this pro perty o nly o n Windo ws 2000.
Reading folder contents Every element sto red in a fo lder is represented by a FolderItem o bjec t. In fac t, yo u’ve already used the FolderItem o bjec t. The Folder2 o bjec t’s Self pro perty returns the FolderItem o bjec t representing the fo lder, and its path pro perty reveals the fo lder’s o ffic ial path name. Table 8-6 sho ws ho w a FolderItem o bjec t is o rganized.
Table 8-6
The FolderItem Object
M ethod/Property
Description
Property Application As Object
Get Application object.
Function ExtendedProperty (ByVal bstrPropName As String)
(new ) Acces s an extended property.
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
277 ■
M ethod/Property
Description
Property GetFolder As Object
If the item is a folder, return folder object.
Property GetLink As Object
If the item is a link, return link object.
Sub InvokeVerb ([ByVal vVerb])
Execute a command on the item.
Sub InvokeVerbEx([ByVal vVerb], [ByVal vArgs])
(new ) Extended vers ion of InvokeVerb.
Property IsBrowsable As Boolean
Is the item brow s able?
Property IsFileSystem As Boolean
Is the item a file s ys tem object?
Property IsFolder As Boolean
Is the item a folder?
Property IsLink As Boolean
Is the item a link?
Property ModifyDate As Date
Modification date?
Property Name As String
Get the dis play name for the item.
Property Parent As Object
Get the Parent object.
Property Path As String
Get the path name to the item.
Property Size As Long
Size.
Property Type As String
Type.
Function Verbs As FolderItemVerbs
Get the lis t of verbs for the object.
As with the Folder o bjec t, there are again two o bjec ts representing a fo lder c o ntent — the o ld FolderItem o bjec t and the revised FolderItem2 o bjec t. With Windo ws 2000, yo u always get a FolderItem2 o bjec t and c an take advantage o f the additio nal metho ds marked as “new.” Yo u no w kno w all the details to o pen a fo lder and list its c o ntent the way the shell do es it: ‘ 8-12.VBS set shell = CreateObject(“Shell.Application”) set folder = shell.namespace(“C:\”) for each folderitem in folder.items list = list & folderitem.name & vbTab & folderitem.size _ & vbTab & folderitem.ModifyDate & vbCr next MsgBox list
278
Part II: Co nque ring the File Sys te m
■
■
Figure 8-14 sho ws a sample o utput. The c o lumns may appear disarranged, and this is due to the pro po rtio nal fo nt used in the dialo g bo x. Yo u c o uld easily o utput the info rmatio n as an HTML table and get perfec tly aligned c o lumns. This is all pretty neat, but where’s the real advantage o ver the Scripting. FileSystemObject metho ds? Hang o n.
Figure 8-14: The s hell can provide all kinds of detailed file information.
Retrieving secret file information One advantage is the GetDetailsOf metho d pro vided by the Folder o bjec t. It returns interesting info rmatio n abo ut the files — have a lo o k at the sample o utput sho wn in Figure 8-15. ‘ 8-13.VBS set shell = CreateObject(“Shell.Application”) set folder = shell.namespace(“C:\”) for each folderitem in folder.items for x=-1 to 28 description = folder.GetDetailsOf(0, x) if description”” then list = list & “(“ & x & “)”& description & “: “ _ & folder.GetDetailsOf(folderitem, x) & vbCr end if next list = list & vbCr next MsgBox list
On Windo ws 2000, getDetailsOf reveals muc h mo re info rmatio n. Windo ws 9.x and NT limit themselves to the usual piec es o f info rmatio n fo und in the Explo rer Details view. On Windo ws 2000, rightc lic k o n any o ne o f the c o lumn headers in Details view to see the advanc ed info rmatio n direc tly.
GetDetailsOf ac tually leads a do uble life. Call it with its first argument set to 0, and it returns the desc riptio n o f the pro perty. Call it with its first argument set to a FolderItem o bjec t, and it returns the ac tual info rmatio n abo ut this o bjec t. The sec o nd argument selec ts the kind o f info rmatio n yo u want to query.
Chapte r 8 : Advanc e d File Sys te m Tric ks
279
■
■
Figure 8-15: GetDetailsOf reveals all kinds of detail object information. On Windo ws 9.x and NT, use index –1 to retrieve additio nal info rmatio n, suc h as autho r name, abo ut Mic ro so ft Offic e files. Windo ws 2000 has integrated this info rmatio n in its standard set o f info rmatio n.
Accessing special virtual Windows folders Yo u pro bably have no tic ed that Windo ws Explo rer c an do muc h mo re than just present regular fo lders. The Windo ws Explo rer c an display any kind o f info rmatio n so urc e. The Co ntro l Panel, fo r example, is a c o mpletely virtual fo lder that do esn’t exist anywhere o n yo ur hard drive. Still, it c an be displayed as if it were a fo lder. Why? It’s all a matter o f “namespac e.” The regular file system uses path names as unambiguo us selec to rs. It’s a namespac e, and path names are the to o ls to selec t individual elements in this namespac e. Co ntro l Panel, the Printer fo lder, and any o f the o ther virtual fo lders use their o wn namespac es and their very o wn way o f identifying o bjec ts. Windo ws keeps trac k o f this with the use o f PIDLs. PIDLs are unique identifiers no t bo und to any spec ific namespac e. Fo rtunately, yo u very seldo m have to deal with PIDLs yo urself. Take a lo o k at the Fo lder Pic ker dialo g bo x intro duc ed in Chapter 6 if yo u must c o nvert PIDLs to file names. The shell.Application o bjec t hides the internal mec hanic s o f virtual fo lders fro m yo u. Just ac c ess a virtual fo lder using namespace, and supply the index number o f the virtual fo lder yo u want to see, as o utlined in Table 8-7.
280
Part II: Co nque ring the File Sys te m
■
■
Table 8-7
Code Numbers Of W indow s Special Folders
Constant
Description
0
Special Folder DESKTOP
2
Special Folder PROGRAMS
3
Special Folder CONTROLS
4
Special Folder PRINTERS
5
Special Folder PERSONAL
6
Special Folder FAVORITES
7
Special Folder STARTUP
8
Special Folder RECENT
9
Special Folder SENDTO
10
Special Folder BITBUCKET
11
Special Folder STARTMENU
16
Special Folder DESKTOPDIRECTORY
17
Special Folder DRIVES
18
Special Folder NETWORK
19
Special Folder NETHOOD
20
Special Folder FONTS
21
Special Folder TEMPLATES
22
Special Folder COMMON STARTMENU
23
Special Folder COMMON PROGRAMS
24
Special Folder COMMON STARTUP
25
Special Folder COMMON DESKTOPDIR
26
Special Folder APPDATA
27
Special Folder PRINTHOOD
28
Special Folder LOCAL APPDATA
29
Special Folder ALTSTARTUP
30
Special Folder COMMON ALTSTARTUP
31
Special Folder COMMON FAVORITES
32
Special Folder INTERNET CACHE
33
Special Folder COOKIES
34
Special Folder HISTORY
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
281 ■
Constant
Description
35
Special Folder COMMON APPDATA
36
Special Folder WINDOWS
37
Special Folder SYSTEM
38
Special Folder PROGRAM FILES
39
Special Folder MYPICTURES
40
Special Folder PROFILE
41
Special Folder SYSTEMx86
48
Special Folder PROGRAM FILESx86
The fo llo wing sc ript sho ws ho w to enumerate the c o ntent o f Co ntro l Panel: ‘ 8-14.VBS set shell = CreateObject(“Shell.Application”) ‘ open Control Panel set folder = shell.namespace(3) for each folderitem in folder.items subfolder = false for x=0 to 1 description = folder.GetDetailsOf(0, x) content = folder.GetDetailsOf(folderitem, x) if content=”” and not subfolder then list = list & folderitem.name & “ (Subfolder)” & vbCr subfolder = true elseif not subfolder then list = list & “(“ & x & “)”& description _ & “: “ & content & vbCr end if next list = list & vbCr next MsgBox list
Here’s an interesting po int: GetDetailsOf reveals a c o mpletely different set o f info rmatio n abo ut the fo lder items. It’s all a matter o f the namespac e yo ur fo lder lives in.
Translating between namespaces Let’s fo c us fo r a mo ment o n the c lassic file system. There are two ways to ac c ess files and fo lders: Scripting.FileSystemObject uses the regular path names to identify o bjec ts, and shell.Application uses the shell’s naming c o nventio ns to ac c ess o bjec ts.
282
Part II: Co nque ring the File Sys te m
■
■
The regular path names and the shell’s naming c o nventio n are slightly different. Yo u have seen that drive C in the shell is represented thro ugh the display name o f the drive. Similarly, filenames in the shell are represented exac tly the way the shell and the Explo rer display them. If, fo r example, yo u have c ho sen to make file extensio ns invisible, files are ac c essed just by plain filenames. This impo ses pro blems: Imagine two files o f different type but with the same name — there’s no lo nger any way to differentiate between them. Fo rtunately, the shell supplies yo u with the to o ls to uniquely identify o bjec ts and translate c lassic file paths to shell o bjec ts. To ac c ess any file o r fo lder, yo u use two metho ds — namespace and ParseName. namespace gives ac c ess to fo lders. It auto matic ally translates the path name into whatever the shell uses as a desc ripto r fo r the fo lder. Onc e yo u have ac c ess to the fo lder, ParseName translates any filename to the shell’s file-naming c o nventio n. The o nly thing yo u need to do is split up a file path into a fo lder and true filename. Have a lo o k: ‘ 8-15.VBS set shell = CreateObject(“Shell.Application”) filepath = “C:\MSDOS.SYS” folder = left(filepath, InstrRev(filepath, “\”)) file = mid(filepath, InstrRev(filepath, “\”)+1) ‘ get access to folder containing the file set folderobj = shell.namespace(folder) set folderitem = folderobj.ParseName(file) ‘ folderitem now represents your file MsgBox folderItem.Name
The sc ript gets ac c ess to the file and displays its name. No te that the name is displayed ac c o rding to yo ur shell settings: If yo ur shell c urrently hides file extensio ns, the file extensio n will no t be sho wn. Always no te the differenc e in the naming c o nventio n — ParseName translates a regular filename into the shell’s naming c o nventio n. It’s yo ur sec ret bac k do o r inside the shell namespace. Yo u c an’t supply ParseName with the name returned by the FolderItem o bjec t. If yo u do , ParseName might raise an erro r, bec ause it c an’t find a file witho ut its extensio n.
Calling a file’s Property page Why wo uld yo u benefit fro m ac c essing files and fo lders thro ugh the shell? Bec ause the shell c an do so me extra tric ks the Scripting.FileSystemObject is unable to do . Fo r example, yo u c an c all any c o ntext menu yo u like. To display the Pro perties page o f any file, use this appro ac h: ‘ 8-16.VBS set shell = CreateObject(“Shell.Application”)
Chapte r 8 : Advanc e d File Sys te m Tric ks
283
■
■
filepath = “C:\MSDOS.SYS” folder = left(filepath, InstrRev(filepath, “\”)) file = mid(filepath, InstrRev(filepath, “\”)+1) ‘ get access to folder containing the file set folderobj = shell.namespace(folder) set folderitem = folderobj.ParseName(file) ‘ folderitem now represents your file folderItem.InvokeVerb(“Properties”) MsgBox “Properties window open”
Yo u will o nly see the Pro perties windo w if yo u supply the exac t c o ntext menu c o mmand displayed in the file’s c o ntext menu. If the c o ntext menu c o mmand c o ntains an underlined sho rtc ut c harac ter, yo u need to plac e an ampersand ( &) befo re this c harac ter. To c all a c o ntext menu c o mmand c alled Pro perties, yo u wo uld c all P&roperties. Sinc e the dialo g bo x is bo und to yo ur sc ript pro c ess, it will disappear o nc e yo ur sc ript is do ne. This is why the sc ript displays a MsgBox dialo g bo x, as sho wn in Figure 8-16: It keeps yo ur sc ript alive so the Pro perties windo w remains visible.
Figure 8-16: Your s cript has full control over Properties pages . No te that o pening the Pro perties page is o nly o ne example. Yo u c an c all any c o ntext menu in any namespac e. Fo r example, yo u c o uld list the mo dules o f yo ur Co ntro l Panel and o ffer to o pen the selec ted c o mmand panel mo dule by c alling its Open c o ntext menu.
284
Part II: Co nque ring the File Sys te m
■
■
Opening Properties windows as modal windows Pro perties windo ws sho uld remain o pen no matter what yo ur sc ript do es. The o nly way to ac hieve this is to detac h the dialo g bo x fro m yo ur sc ript pro c ess. Altho ugh this may so und c o mplic ated, it’s ac tually very easy. All yo u need to do is mimic the regular Windo ws behavio r! The fo llo wing sc ript o pens an Internet Explo rer windo w and keeps it invisible. It fo rc es the windo w to navigate to the fo lder the file is c o ntained in. A lo o p waits fo r the Internet Explo rer to initialize itself. Then, the sc ript ac c esses the fo lder o bjec t invisibly displayed in the Internet Explo rer windo w o r do c ument.fo lder. It’s the same kind o f o bjec t yo ur previo us sc ript ac c essed thro ugh namespace, o nly this time the o bjec t is handled by Internet Explo rer, no t yo ur sc ript. ‘ 8-17.VBS ShowProperties “C:\MSDOS.SYS” ShowProperties “C:\AUTOEXEC.BAT” sub ShowProperties(filepath) set shell = CreateObject(“Shell.Application”) set ie = CreateObject(“InternetExplorer.Application”) folder = left(filepath, InstrRev(filepath, “\”)) file = mid(filepath, InstrRev(filepath, “\”)+1) ie.navigate folder do until ie.readyState=4 loop set folderobj = ie.document.folder set folderitem = folderobj.ParseName(file) ‘ folderitem now represents your file folderItem.InvokeVerb(“Properties”) end sub
The rest o f the sc ript is identic al to the previo us o ne, in that it gets ho ld o f the file using ParseName and c alls the Properties verb. The resulting dialo g bo x o pens and remains o pen. Do n’t wo rry abo ut invisible Internet Explo rer! Windo ws auto matic ally c lo ses its pro c ess the mo ment yo u c lo se the dialo g bo x.
Accessing context menu Commands the smart way InvokeVerb is a very po werful metho d o nc e yo u kno w the exac t name o f the Co ntext menu c o mmand yo u must c all. Unfo rtunately, there are no true naming standards, and keybo ard sho rtc ut &-c harac ters c an be plac ed anywhere inside a verb name — no t to mentio n lo c alized Windo ws versio ns.
Chapte r 8 : Advanc e d File Sys te m Tric ks
285
■
■
Do n’t wo rry abo ut naming c o nventio ns! The standard Co ntext menu c o mmands are always ac c essible using standard Windo ws names, regardless o f ho w tho se c o mmands are named in the Co ntext menu, as sho wn in Table 8-8.
Table 8-8
[Context M enu Commands]
Command
Description
Properties
Properties -Command
Open
Open-Command
OpenAs
Open As -Command
Print
Print-Command
To ac c ess o ther c o mmands, yo u c an retrieve the names o f suppo rted c o mmands using the Verbs pro perty, and rec eive the names as sho wn in Figure 8-17. ‘ 8-18.VBS set shell = CreateObject(“Shell.Application”) filepath = “C:\MSDOS.SYS” folder = left(filepath, InstrRev(filepath, “\”)) file = mid(filepath, InstrRev(filepath, “\”)+1) set folderobj = shell.namespace(folder) set folderitem = folderobj.ParseName(file) set folderitemverbs = folderitem.Verbs for each folderitemverb in folderitemverbs list = list & folderitemverb.name & vbCr next MsgBox list
Figure 8-17: Retrieve the available Context menu commands . The folderitemverbs c o llec tio n returns the ac tual names o f eac h Co ntext menu c o mmand. Eac h folderitemverb o bjec t is o rganized as o utlined in Table 8-9. No t o nly c an yo u retrieve the name, DoIt also exec utes the c o mmand.
286
Part II: Co nque ring the File Sys te m
■
■
On Windo ws 9.x, the Verbs metho d c o ntains a serio us bug. It do esn’t return a FolderItemVerbs o bjec t but rather a useless FolderItemVerb o bjec t. Yo u c an’t enumerate Co ntext menu c o mmands o n Windo ws 9.x.
Table 8-9
Properties and M ethods of FolderItemVerb Objects
M ethod/Property
Description
Property Application As Object
Get Application object
Sub DoIt
Execute the verb
Property Name As String
Get dis play name for item
Property Parent As Object
Get Parent object
Calling Properties pages using API calls The Shell.Application o bjec t o nly delegates yo ur requests to c o mmo n API func tio ns. To display pro perty pages, the direc t appro ac h has so me advantages. Yo u c an easily o pen drive o r printer Pro perty pages, no t just file Pro perty pages. Even mo re interesting, if the Pro perty page c o nsists o f mo re than o ne tab, yo u c an also selec t the Ac tive tab. As usual, yo u have the c ho ic e: Either o pen the so urc e c o de ( \components \property\property.vbs) and c o mpile the pro jec t yo urself, o r install the prepared pac kage ( \install\property\setup.exe). Opening Pro perty pages is straightfo rward: Create a COM o bjec t and use this c o de: ‘ open properties Private Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformID As Long szCSDVersion As String * 128 End Type Private Declare Function GetVersionEx Lib “kernel32” _ Alias “GetVersionExA” (ByRef lpVersionInformation _ As OSVERSIONINFO) As Long Private Declare Function SHObjectProperties Lib “shell32.dll” _ Alias “#178” (ByVal hwnd As Long, ByVal uflags As Long, _ ByVal lpstrname As Long, ByVal lpcstrparams As Long) As Boolean Public Function ShowProp(ByVal filename As String, _ Optional ByVal page As String) As Boolean Dim file As String
Chapte r 8 : Advanc e d File Sys te m Tric ks ■
287 ■
Dim pagenr As Long ‘ adjust to ANSI/UNICODE If Not isNT Then ‘ convert to ANSI filename = StrConv(filename, vbFromUnicode) page = StrConv(page, vbFromUnicode) End If If IsMissing(page) Then pagenr = 0 Else pagenr = StrPtr(page) End If ShowProp = SHObjectProperties(0, 2, StrPtr(filename), pagenr) If ShowProp = False Then ‘ try printer dialog ShowProp = SHObjectProperties(0, 1, StrPtr(filename), pagenr) End If End Function Public Function isNT() As Boolean Dim osinfo As OSVERSIONINFO osinfo.dwOSVersionInfoSize = Len(osinfo) GetVersionEx osinfo If osinfo.dwPlatformID = 2 Then isNT = True Else isNT = False End If End Function
SHObjectProperties is an undo c umented API func tio n — the declare statement must use an Alias and the direc t o rdinal ( #178) to ac c ess this feature. As always with undo c umented func tio ns, it expec ts string input to b e UNICODE o n NT and ANSI o n Win9.x. Yo ur COM o b jec t therefo re needs to find o ut whether it’s running o n NT o r no t. On no n-NT mac hines, it c o nverts the strings to ANSI using the undo c umented StrConv func tio n. ‘ 8-19.VBS set tool = CreateObject(“property.tool”) MsgBox tool.ShowProp(“C:\”) MsgBox tool.ShowProp(“C:\MSDOS.SYS”) ‘ adjust printer name to some installed printer: MsgBox tool.ShowProp(“HP Laserjet”)
SHObjectProperties c an display Pro perty pages fo r file system o bjec ts and fo r printers. Use 2 as the sec o nd argument fo r file system o bjec ts and 1 fo r printer o bjec ts. The COM o bjec t auto matic ally tries bo th metho ds, so yo u c an use it fo r bo th files/fo lders and printer names. It returns true if the Pro perty page was o pened; o therwise, it returns false, and Figure 8-18 sho ws the result.
288
Part II: Co nque ring the File Sys te m
■
■
Figure 8-18: Open Property pages for drives , files , and printers us ing the API directly. Ho wever, if yo u spec ify a file o r fo lder that do esn’t exist, yo u will always end up with a printer erro r message. If yo u do n’t like this, split the pro c edure in two and use individual metho ds fo r file system and printer o bjec ts. Yo ur new ShowProp metho d c an do a tric k no o ther metho d is c apab le o f: Yo u c an preselec t a tab o n the Pro perty page. Supply the name o f the tab as a sec o nd argument. Fo r example, to o pen the Shared tab fo r drive C:, use this c o mmand: tool.ShowProp “C:\”, “Sharing”
SHObjectProperties displays mo deless dialo g bo xes. They are visible o nly as lo ng as yo ur sc ript is running. Here, there’s no easy way to attac h the dialo g bo x to ano ther pro c ess. Ho wever, if yo u use 4 as the sec o nd argument, SHObjectProperties displays mo dal dialo g bo xes fo r drives o nly. They halt yo ur sc ript so yo u c an wait fo r the user to make so me selec tio n. Yo u c an use this tric k o nly fo r drives. It wo n’t wo rk fo r files, fo lders, o r printers.
Summary In this c hapter, yo u used many undo c umented Windo ws API func tio ns to c reate handy little sc ript extensio ns, to c o py and c o mpress files, and even to c reate entire bac kup sets. These func tio ns allo w yo u to delete items to the Rec yc le Bin, empty the Rec yc le Bin, o r fo rmat drives — all previo usly impo ssible fo r yo ur sc ripts. Yo u are no w also able to retrieve extended file versio n info rmatio n, finding o ut the purpo se o f internal Windo ws files. A new sec ret bac k do o r to the shell allo ws yo u to ac c ess fo lders and files the way the Windo ws Explo rer do es it, allo wing yo u to c all Co ntext menu c o mmands and display Pro perties windo ws. This c hapter c larifies many o f the advanc ed tec hniques and sho ws ho w COM o bjec ts c an return info rmatio n o bjec ts and ho w undo c umented API func tio ns c an be c alled by any Windo ws versio n, auto matic ally so lving the UNICODE/ANSI c o nflic t.
Chapte r 9
Mastering Links In This Chapter 䊳 Learn mo re abo ut the po wer o f sho rtc ut files 䊳 Createand mo dify sho rtc ut files by sc ript 䊳 Searc h fo r invalid links and duplic ating keybo ard sho rtc uts 䊳 Change sho rtc ut ic o ns dynamic ally 䊳 Preselec t a sho rtc ut’s windo w size 䊳 Use the hidden Shell Link o bjec t to reso lve bro ken links 䊳 Disc o ver the undo c umented link reso lving mec hanism and the new
Windo ws 2000 Distributed Link Trac king Servic e 䊳 Open a sho rtc ut target’s Pro perties page 䊳 Mark a sho rtc ut target file in the Explo rer
N
o w that yo u kno w ho w to handle yo ur file system, take a lo o k at link files. In this c hapter, yo u learn what link files are and ho w to use them to c usto mize menus. Yo u also learn ho w to c reate new link files fro m sc ratc h and ho w to c hec k existing link files fo r erro rs. Using sec ret API func tio ns, yo u c an even auto matic ally repair bro ken link files.
Why Do I Need Links Anyway? Links are small but extremely po werful files. They represent files, fo lders, and system o bjec ts lo c ated so mewhere else. Links build the fo undatio n o f c usto mizing Windo ws. Links make the Pro grams menu wo rk. To see ho w impo rtant links really are, start a searc h fo r *.LNK.
Sc ripts c an use links to plac e themselves in impo rtant plac es. Yo u c an add yo ur sc ript to the Start menu, plac e it into the Send To fo lder, o r insert a referenc e into the Startup fo lder. In additio n, sc ripts c an use their link func tio ns fo r maintenanc e. Sc ripts c an searc h fo r links, c hec k whether their destinatio ns are still valid, and so rt o ut any bro ken links.
290
Part II: Co nque ring the File Sys te m
■
■
Mo re impo rtantly, sc ripts c an c hec k the internal keybo ard sho rtc uts and make sure there are no duplic ate entries. Windo ws do esn’t c hec k fo r this, allo wing yo u to assign multiple keybo ard sho rtc uts to mo re than o ne link file, o r even to o verride impo rtant built-in Windo ws sho rtc uts — resulting in erro neo us behavio r. By using so me undo c umented Windo ws magic , yo u c an even reso lve bro ken links and mark files and fo lders.
Creating a new link file The WScript.Shell o bjec t c o ntains all the metho ds needed fo r managing links. The fo llo wing example asks fo r a name and plac es a sho rtc ut to the Windo ws edito r right o n yo ur deskto p: ‘ 9-1.VBS set wshshell = CreateObject(“WScript.Shell”) desktop = wshshell.SpecialFolders(“desktop”) linkname = InputBox(“What do you want to call your new link?”, _ ,”Windows Editor”) target = “notepad.exe” linkname = desktop & “\” & linkname & “.lnk” ‘ create new shortcut object set scut = wshshell.CreateShortcut(linkname) ‘ fill in information scut.TargetPath = target ‘ save shortcut object scut.Save MsgBox “Done - new shortcut on your desktop!”
Take a lo o k at yo ur deskto p. The sc ript adds a new sho rtc ut and, when yo u o pen it, launc hes the edito r.
Examining the shortcut object All this magic was do ne with the help o f a sho rtc ut o bjec t. A sho rtc ut o bjec t represents the internal pro perties o f a link file. CreateShortcut is yo ur sec ret key to the sho rtc ut o bjec t. It always returns a sho rtc ut o bjec t. If yo u spec ified a link file that do esn’t yet exist, the new sho rtc ut o bjec t is empty. Ho wever, yo u c an easily ac c ess the hidden pro perties o f existing sho rtc uts. Just spec ify an existing sho rtc ut file path.
Chapte r 9 : Mas te ring Links
291
■
■
CreateShortcut will fail if the spec ified file name do esn’t c arry the .link file extensio n. The resulting sho rtc ut o bjec t is no t the ac tual sho rtc ut. It’s just an info rmatio n o bjec t sto red so mewhere in memo ry. To write the pro perties o f the sho rtc ut o bjec t bac k to the ac tual sho rtc ut file, yo u must c all the o bjec t’s Save metho d. Table 9-1 sho ws ho w sho rtc ut o bjec ts are o rganized.
Table 9-1
The Shortcut Object
Property/M ethod
Description
Property Arguments As String
Additional command-line arguments you w ant to pas s to the target file
Property Description As String
Optional des criptive information about w hat this s hortcut is us ed for
Property FullName As String
Full path name of the link file (undocumented)
Property Hotkey As String
Keyboard s hortcut
Property IconLocation As String
Dis play icon of the s hortcut
Property RelativePath As String
Not fully s upported (undocumented)
Sub Save
Saves the information to the s hortcut
Property TargetPath As String
Path name of the s hortcut target file
Property WindowStyle As Long
Type of w indow the s hortcut s hould open
Property WorkingDirectory As String
Initial directory s etting
Accessing Existing Link Files CreateShortcut is so mewhat misleading, as it do esn’t c reate a sho rtc ut file. It c reates a sho rtc ut o bjec t. Yo u c an easily manage existing link files using CreateShortcut and reveal their internal pro perties.
Searching for invalid links The next sc ript c hec ks yo ur entire Pro grams menu and repo rts any invalid links. Figure 9-1 sho ws the result.
292
Part II: Co nque ring the File Sys te m
■
■
Fo r yo ur c o nvenienc e, the sc ript o ffers to delete invalid links. Befo re yo u delete so mething, always think twic e. Sho rtc ut targets o n netwo rk drives o r targets to disk drives may no t c urrently be available but may still be useful. Chec k the message dialo g bo x c arefully befo re yo u dec ide to c lean up yo ur Pro grams menu! ‘ 9-2.VBS set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”) ‘ global variables num_checked = 0 num_error = 0 num_deleted = 0 programs = wshshell.SpecialFolders(“programs”) set folderobj = fs.GetFolder(programs) CheckFolder folderobj msg = “I have checked “ & num_checked & “ links.” & vbCr msg = msg & “I found “ & num_error & “ invalid links.” & vbCr msg = msg & “You asked me to delete “ & num_deleted & “ links” MsgBox msg, vbInformation sub CheckFolder(folderobj) for each file in folderobj.files ext = lcase(fs.GetExtensionName(file.name)) if ext = “lnk” then num_checked = num_checked + 1 set scut = wshshell.CreateShortcut(file.path) target = scut.TargetPath if not fs.FileExists(target) then num_error = num_error + 1 msg = “Link “”” & file.path & “”” points to “”” _ & target & “””” & vbCr msg = msg & “The target no longer exists! Do “ _ & “you want to delete the link?” response = MsgBox(msg, vbQuestion + vbYesNo _ + vbDefaultButton2) if response = vbYes then num_deleted = num_deleted + 1 file.delete end if end if end if next for each subfolder in folderobj.subfolders CheckFolder subfolder next end sub
Chapte r 9 : Mas te ring Links
293
■
■
Figure 9-1: Check for invalid and outdated links in your Programs menu.
Finding (and eliminating) duplicate keyboard shortcuts Keybo ard sho rtc uts are extremely useful — after all, any sho rtc ut file with a keybo ard sho rtc ut c an be invo ked just by pressing the keys yo u spec ify. Just right-c lic k o n a link file and c ho o se Pro perties. Then enter yo ur keybo ard sho rtc ut in the sho rtc ut text field and c lic k OK. But, this do esn’t always wo rk! Keybo ard sho rtc uts c an launc h files o nly if the sho rtc ut is lo c ated either o n yo ur deskto p o r inside the Pro grams menu. These are the o nly plac es Windo ws lo o ks fo r keybo ard sho rtc uts. It wo uld just take muc h to o lo ng to c hec k all link files anywhere in the file system. One o f the mo st anno ying reaso ns fo r failure is duplicate sho rtcut keys. Windo ws do esn’t make any effo rt to prevent yo u fro m assigning new keybo ard sho rtcuts that are already in use by so me o ther link file. Once yo u have multiple link files using the same key co mbinatio n, it’s up to Windo ws which file will be launched. Even wo rse, it’s po ssible to o verride Windo ws’ internal sho rtc uts. If yo u assign [F1] to a link file, this key will no lo nger invo ke Windo ws help. It’s very hard to reso lve duplic ate keybo ard sho rtc uts bec ause Windo ws c an’t list the sho rtc uts in use. Yo u wo uld have to o pen the Pro perties page o f eac h and every link file manually to lo o k fo r sho rtc uts. That’s to o muc h wo rk. The fo llo wing sc ript c reates a sho rtc ut list auto matic ally and presents the result as an HTML file similar to the o ne sho wn in Figure 9-2. ‘ 9-3.VBS set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”) startmenu = wshshell.SpecialFolders(“startmenu”) desktop = wshshell.SpecialFolders(“desktop”) outputfile = “C:\LINKLIST.HTM” dim links(1000,1) counter = 0
294
Part II: Co nque ring the File Sys te m
■
■
CheckFolder fs.GetFolder(desktop), false CheckFolder fs.GetFolder(startmenu), true for x=0 to counter-1 for y=x+1 to counter-2 if links(x,1)>links(y,1) then temp = links(x,1) links(x,1) = links(y,1) links(y,1) = temp temp = links(x,0) links(x,0) = links(y,0) links(y,0) = temp end if next next set output = fs.CreateTextFile(outputfile, true) output.WriteLine “” output.WriteLine “List of Shortcut Hotkeys” output.WriteLine “
” & counter & “ hotkeys found.
” output.WriteLine “
” for x= 0 to counter-1 output.WriteLine “
” & links(x,1) & “
” _ & links(x,0) & “
” next output.WriteLine “
” output.close wshshell.run “iexplore.exe “ & outputfile sub CheckFolder(folderobj, subdirs) for each file in folderobj.files ext = lcase(fs.GetExtensionName(file.name)) if ext = “lnk” then set scut = wshshell.CreateShortcut(file.path) hotkey = scut.HotKey if not (hotkey=”” or hotkey=”!”) then links(counter,0) = file.path links(counter,1) = hotkey counter = counter + 1 end if end if next if subdirs then for each subfolder in folderobj.subfolders CheckFolder subfolder, subdirs next end if end sub
Chapte r 9 : Mas te ring Links
295
■
■
A bubble-like algo rithm so rts the keybo ard sho rtc uts, so duplic ate entries are easy to rec o gnize. No te that this sc ript searc hes fo r links o nly o n the deskto p and inside the Start menu, as these are the o nly plac es where keybo ard sho rtc uts wo rk.
Figure 9-2: Build a lis t of keyboard s hortcuts and find duplicate entries . The sc ript searc hes rec ursively o nly in the Start menu. Subfo lders o n the deskto p wo n’t be searc hed. Undefined Ho tKey entries return either an empty string o r “!”. So me spec ial c harac ters suc h as “ö ” will no t be sho wn by the Ho tKey pro perty. Instead, yo u o nly see the mo difier keys. Take a lo o k at the file’s Pro perties page to see the ac tual sho rtc ut key. To eliminate duplic ate sho rtc uts, just o pen the Pro perties page and delete the sho rtc ut entry.
Changing a Shortcut Icon By default, Windo ws uses the file that the TargetPath pro perty po ints to as an ic o n reso urc e. Yo u do n’t need to ac c ept this default. Just spec ify yo ur o wn ic o n file as IconLocation pro perty. This is espec ially useful if yo u plan to insert sc ripts into the Start menu o r the Send To fo lder. Where do yo u get ic o ns to c ho o se fro m? The Windo ws system fo lder is filled with ic o n reso urc es yo u c an use. Or, yo u c an c reate yo ur very o wn perso nal ic o ns! It’s all po ssible.
Borrowing system icons System ic o ns hide in files like shell32.dll o r moricons.dll. To spec ify an ic o n, supply IconLocation with the filename and ic o n index: fo r example, shell32.dll,2.
296
Part II: Co nque ring the File Sys te m
■
■
Ho w do yo u kno w whic h files to pic k, tho ugh? No t every file is a go o d ic o n reso urc e, but I’ve prepared many ic o n to o ls fo r yo u. Yo u c an get a head start by jumping to Chapter 22. Or use the fo llo wing sc ript — it uses the ListView c o ntro l alo ng with the Ic o n Pic ker dialo g bo x, bo th o f whic h yo u c reated in Chapter 6. Make sure yo u install bo th \install\listview\setup.exe and \install\iconpick\setup.exe fro m the c o mpanio n CD befo re yo u launc h script 9-4.vbs. This sc ript auto matic ally c hanges the ic o n o f any link file. Drag a link file o nto the sc ript ic o n. It may take so me seco nds fo r the script to search fo r available ico ns. Be patient, have cup o f co ffee, and relax. Yo ur reward is a huge list o f available ico ns. It will pro vide yo u with many mo re cho ices than the o fficial dialo g bo x co uld ever o ffer. First, the sc ript searc hes bo th yo ur Windo ws fo lder and the system fo lder fo r files that c o ntain at least three ic o ns. This c an take so me sec o nds. Next, it displays all ic o n files as sho wn in Figure 9-3 so yo u c an selec t o ne. The Ic o n Pic ker dialo g bo x then displays the ic o ns sto red in the selec ted file. Figure 9-4 sho ws the result. Cho o se an ic o n, o r c ho o se Canc el to selec t a different ic o n file.
Figure 9-3: A Lis tView lis ts all the icon files available on your s ys tem. ‘ 9-4.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ any arguments supplied? set args = WScript.Arguments if args.Count=0 then MsgBox “Drag a link file on my icon to see me at work!” WScript.Quit elseif lcase(fs.GetExtensionName(args(0)))”lnk” then
Chapte r 9 : Mas te ring Links ■
297 ■
MsgBox “I only accept link files (shortcuts)!” WScript.Quit end if ‘ access COM objects: set iconpick = CreateObject(“iconpicker.tool”) set lview = CreateObject(“listview.tool”) set wshshell = CreateObject(“WScript.Shell”) ‘ find out icon library folders: set windir = fs.GetSpecialFolder(0) set sysdir = fs.GetSpecialFolder(1) ‘ initialize list view: lview.width = 600 lview.height = 400 lview.AddHeader “Icons available”, 30 lview.AddHeader “Icon Library”, 70 lview.MultiEdit = true
‘ build list of available icons PopulateList windir PopulateList sysdir ‘ Sort by icon count: lview.Sort 1, 1 do ‘ Select Icon Lib: set result = lview.Show(“Extended Information: “ & name) if result.Count>0 then ‘ extract library file name lib = Split(result(1), vbCrLf) libname = lib(0) else libname = “” end if ‘ library selected? good: if not libname=”” then ‘ show icons in library: icon = iconpick.PickIcon(libname) end if ‘ loop until either icon is chosen or library ‘ selection was cancelled: loop until libname = “” or not icon=”” ‘ did user select an icon? if not icon=”” then ‘ yes: access selected shortcut: set scut = wshshell.CreateShortcut(args(0))
298
Part II: Co nque ring the File Sys te m
■
■
‘ change icon and save information scut.IconLocation = icon scut.Save MsgBox “Changed link file icon!” else MsgBox “You did not specify an icon...” end if sub PopulateList(folderobj) ‘ search for icon files in entire folder for each file in folderobj.files ‘ how many icons are stored in file? iconcount = iconpick.CountIcons(file.path) if iconcount>2 then ‘ pad icon count with spaces so ‘ sorting as string works iconcount = right(space(10) & iconcount, 10) lview.AddItem file.name lview.AddSubItem 1, iconcount end if next end sub
Figure 9-4: The Icon Picker dialog box lis ts the icons available. Onc e yo u have selec ted an ic o n, the sc ript c hanges the sho rtc ut’s IconLocation pro perty to the selec ted ic o n. Figure 9-5 sho ws the final result: Yo ur sho rtc ut file has c hanged its ic o n! This sc ript will o nly wo rk if yo u have pro perly registered bo th the Listview to o l and the ic o n pic ker to o l. Yo u c an find c o nvenient setup.exe pac kages fo r bo th to o ls o n the c o mpanio n CD. Sho uld yo u rec eive “Can’t c reate o bjec t” erro r messages, install bo th setup.exe files: \install\listview\setup. exe and \install\iconpick\setup.exe.
Chapte r 9 : Mas te ring Links
299
■
■
Depending o n the number o f files in yo ur Windo ws and system fo lders, it may take up to a minute fo r the sc ript to c o llec t all ic o n files. Be a little patient! In Chapter 22, I present a way to c o nserve the list o f ic o n files in a text file. This way, yo u c an o pen the ic o n library list muc h mo re rapidly.
Figure 9-5: Your s hortcut object has received a new icon. No te also that the ic o n index depends o n the Windo ws versio n yo u use. The Ic o n index is a simple c o unter that selec ts the ic o n based o n its po sitio n inside the ic o n file. Mic ro so ft c hanges the ic o n o rder frequently, so the same index number may selec t different ic o ns o n different Windo ws versio ns. Aside fro m the ic o n index, there are fixed ic o n reso urc e identifiers. They do n’t c hange with Windo ws versio ns, bec ause they uniquely identify a spec ific ic o n. Reso urc e identifiers are used just the way yo u use ic o n indic es but are negative numbers. Unfo rtunately, there’s no easy way to find o ut the reso urc e identifier o f an ic o n — yo u either kno w it o r yo u do n’t.
Changing your program menu’s icons Yo ur new link file ic o n-c hanger wo rks perfec tly well fo r any link file. Bec ause yo ur Pro gram menu c o ntains link files, it’s an exc ellent way to spic e up bo th yo ur Start menu and Pro gram menu. Just drag any c usto m Start menu o r Pro gram menu entry o nto yo ur sc ript. This is all yo u need to do to assign c o mpletely new ic o ns to any entry. Yo u c an o nly c hange link file ic o ns this way. If yo u want to c hange the ic o ns o f built-in Start menu c o mmands, suc h as Help o r Run o r fo lder ic o ns, take a lo o k at Chapter 22. Drag-and-dro p do esn’t wo rk o n Windo ws 95/NT systems witho ut IE4 deskto p update. But, yo u still c an right-c lic k o n the Start butto n and c ho o se Open. This way, yo u c an ac c ess the Start menu and Pro gram menu c o ntent direc tly. Just drag the link file o ut o f the Explo rer windo w o nto yo ur sc ript ic o n. Do n’t dro p the link file anywhere else o r yo u will mo ve the file o ut o f the menus. [Strg]+[Z] reverts any ac c idental mo ve.
300
Part II: Co nque ring the File Sys te m
■
■
Creating your own icons Yo u do n’t need to stic k to system ic o ns. A plain bitmap file c an ac t as an ic o n, to o . This is why yo u c an use the built-in Windo ws paint pro gram to c reate yo ur o wn ic o ns. Launc h Paint fro m the Ac c esso ries pro gram gro up. If it’s missing, install it fro m yo ur Windo ws CD using the Add/ Remo ve Pro grams mo dule in the Co ntro l Panel. First, yo u sho uld resize the paint area. Cho o se Attributes fro m the Image menu, then limit the paint area to 32×32 pixels. Use the magnifier to o l to magnify the drawing area. No w, paint yo ur ic o n! When yo u are finished, save yo ur new ic o n. Be c areful: To be rec o gnized as an ic o n, yo u must save the file with the .ic o file extensio n. Save yo ur graphic as C:\test.ic o ! On Windo ws 9.x, white auto matic ally is c o nverted to “transparent,” so yo ur ic o ns behave like “real” ic o ns. On Windo ws 2000, the white bac kgro und is c o nverted to blac k, so here yo ur ho memade ic o ns aren’t as useful. Next, yo u c an use yo ur self-made ic o n file fo r yo ur links: ‘ 9-5.VBS set wshshell = CreateObject(“WScript.Shell”) desktop = wshshell.SpecialFolders(“desktop”) linkfile = desktop & “\My own icon!.lnk” set scut = wshshell.CreateShortcut(linkfile) scut.TargetPath = “notepad.exe” scut.IconLocation = “C:\icon2.ico” scut.Save MsgBox “Link saved.”
Inserting Scripts into Special Places Links are a perfec t to o l to intro duc e yo ur sc ripts into spec ial plac es. Fo r example, if yo u want yo ur sc ript to auto matic ally c hange the Windo ws startup sc reen eac h time yo u launc h Windo ws, plac e a sho rtc ut to this sc ript into yo ur Startup fo lder. Windo ws will auto matic ally launc h yo ur sc ript o n startup. Read mo re abo ut auto starting yo ur sc ripts in Chapter 13.
Chapte r 9 : Mas te ring Links ■
301 ■
Starting scripts automatically Ho w do yo u plac e yo ur sc ript’s referenc e into the Startup pro gram gro up? Easy. The next sc ript demo nstrates the tec hnique: ‘ 9-6.VBS set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”) startup = wshshell.SpecialFolders(“startup”) linkname = startup & “\mywelcome.lnk” if not fs.FileExists(linkname) then set scut = wshshell.CreateShortcut(linkname) scut.Targetpath = WScript.ScriptFullName scut.Save MsgBox “I inserted myself into the Startup group!” else ‘ do the stuff you want to be done at windows launch MsgBox “Hey, I’m the Scripting Host! Use me!” end if
This sc ript c o mbines bo th the startup registratio n and the ac tual c o mmands yo u want to be exec uted at Windo ws startup. The sc ript c hec ks whether it is registered in the Startup pro gram gro up. If so , it exec utes its c o de. If no t, it plac es a sho rtc ut to itself into the startup gro up and displays a message similar to the o ne sho wn in Figure 9-6.
Figure 9-6: Ins ert s cripts into your Startup program group. SpecialFolders(“startup”) reveals the path name to yo ur Startup gro up, and WScript.ScriptFullName returns yo ur sc ript’s path name.
Autostarting any script Obvio usly, it’s a waste o f CPU po wer to c hec k whether o r no t the sc ript is already plac ed into the Startup gro up every time. Fo r this reaso n, it’s better to delegate the registratio n to a separate sc ript. If at all po ssible, do n’t plac e mo re than o ne sc ript into yo ur Startup gro up. Starting many sc ripts at the same time c an c ause tro uble. While a sc ript ac c esses a COM o bjec t, this COM o bjec t may no t be ac c essible to o ther sc ripts. If yo u must auto start mo re than o ne sc ript, plac e a “lo ader sc ript” into yo ur StartUp gro up and remo ve any o ther referenc e to sc ripts. This lo ader sc ript will then use the WSc ript.Shell’s Run metho d to subsequently c all any needed sc ripts. Use the Run’s third argument and pro vide true so that Run waits fo r eac h sc ript to end befo re it c alls the next.
302
Part II: Co nque ring the File Sys te m
■
■
Building your own installation scripts Use the techniques just o utlined to create yo ur o wn script-install pro cedures. After all, these techniques do mo re than allo w yo u to place script references into the Startup gro up. With the help o f Scripting.FileSystemObject, yo u can easily create new fo lders that act as new pro gram gro ups. Also , SpecialFolders (“pro grams”) returns the path o f yo ur Pro gram menu, so yo ur installatio n script can create entirely new pro gram gro ups and place yo ur script references inside them. With yo ur kno wledge abo ut link ico ns and the IconLocation pro perty, yo u can even assign new and exciting ico ns to yo ur pro gram gro up items.
Using scripts as a Send To extension Thanks to the built-in drag-and-dro p c apabilities, yo ur sc ripts c an ac t as extensio ns to the Send To Co ntext menu. To be able to rec o gnize the SendTo’s arguments, yo ur sc ript o nly needs to query the Arguments c o llec tio n. This allo ws yo u to c reate yo ur o wn “Send to anywhere” c o mmands. The sc ript c o pies the files themselves. The built-in SendTo targets fo llo w Windo ws’ pro c ess — they will c o py if the target is lo c ated o n a different drive and will mo ve if bo th so urc e and target drive are the same. The next sc ript sends any file yo u drag o nto it to any drive o r fo lder yo u selec t. Fo r this sc ript to wo rk, yo u need to register the BrowseForFolder extensio n first. Take a lo o k at Chapter 6, o r install the extensio n fro m the c o mpanio n CD, using \install\folderpicker\setup.exe. ‘ 9-7 set args = WScript.Arguments if args.Count=0 then MsgBox “You did not drag any file on me...” WScript.Quit end if ‘ get access to browse dialog set browse = CreateObject(“folder.tools”) set fs = CreateObject(“Scripting.FileSystemObject”) ‘ select destination ‘ open “My Computer” to select drive/folder destination = browse.BrowseForFolder(17, _ “Where do you want to copy the file(s)?”) ‘ check whether destination is valid
Chapte r 9 : Mas te ring Links ■
303 ■
if destination=”” then MsgBox “You did not choose a valid destination for this operation!” WScript.Quit end if ‘ add “\” if missing: if not right(destination,1)=”\” then destination = destination & “\” ‘ is selected destination a valid drive/folder? if not fs.FolderExists(destination) then MsgBox “””” & destination & “”” is no valid file system folder!” else ‘ try to copy all selected files: for each filename in args ‘ does file exist? if fs.FileExists(filename) then ‘ overwrite condition? nameonly = mid(filename, InstrRev(filename, “\”)+1) destname = destination & nameonly ‘ file already exist? Ask before overwriting anything: if fs.FileExists(destname) then result = MsgBox(“File “”” & destname _ & “”” already exists! Overwrite?”, _ vbYesNo + vbExclamation) else ‘ new file, always copy: result = vbYes end if if result = vbYes then ‘ copy file fs.CopyFile filename, destination msg = msg & filename & “ -> “ & destination _ & “ copied...” & vbCr else msg = msg & filename & _ “ already exists. Not copied...” & vbCr end if else msg = msg & filename & _ “ is no valid file name, not copied...” _ & vbCr end if next MsgBox msg, vbInformation end if
This sc ript wo rks nic ely, and with it, yo u c an drag any file o nto yo ur sc ript ic o n to c o py it. The bro wser dialo g bo x in Figure 9-7 makes it easy to selec t the destinatio n fo lder. But ho w do yo u get it inside the Send To menu?
304
Part II: Co nque ring the File Sys te m
■
■
Figure 9-7: Send files anyw here w ith your new SendTo command. Use the fo llo wing sc ript to drag the previo us sc ript o nto its ic o n. This c reates a link and saves it in the spec ial Send To fo lder. Fro m no w o n, to send a file anyplac e, right-c lic k it and c ho o se Send To , and then c ho o se Anywhere. Yo ur new c o mmand will appear in the Send To Co ntext menu. Figure 9-8 sho ws the result. ‘ 9-8.VBS set args = WScript.Arguments if args.Count=0 then MsgBox “You did not drag any file on me...” WScript.Quit end if set wshshell = CreateObject(“WScript.Shell”) name = InputBox(“How do you want to name your new command?”, _ , “Copy anywhere”) linkfile = wshshell.SpecialFolders(“sendto”) & “\” _ & name & “.lnk” set scut = wshshell.CreateShortcut(linkfile) scut.TargetPath = args(0) scut.IconLocation = “shell32.dll,13” scut.Save MsgBox “Placed command in Send To Folder!”
Chapte r 9 : Mas te ring Links
305
■
■
Figure 9-8: Send files anyw here us ing your new s cript command extens ion.
Advanced Shortcut Tricks There’s still mo re to disc o ver — passing arguments to link targets, using Internet links, and determining the windo w style a link will use, to mentio n just a few. Altho ugh no ne o f these tric ks are needed in everyday life, they may help yo u with so me spec ific pro blems.
Providing optional arguments So metimes it’s nec essary to pro vide arguments fo r yo ur link. Fo r example, yo u might want to o pen fo lders using hidden Internet Explo rer o ptio ns. Assign these o ptio ns to the sho rtc ut o bjec t Arguments pro perty. The fo llo wing sc ript plac es a link o n yo ur deskto p. This link o pens yo ur private My Do c uments fo lder in two -pane Explo rer view and limits the Explo rer to this fo lder. Figure 9-9 sho ws ho w muc h better this spec ial fo lder o rganizes yo ur perso nal files and fo lders.
Figure 9-9: Special Internet Explorer options allow you to limit the tree view to s pecial folders .
306
Part II: Co nque ring the File Sys te m
■
■
Never use additio nal arguments with the TargetPath pro perty. The Target Path sho uld po int to the target file path o nly. Older WSH versio ns o n Windo ws 9.x didn’t c are abo ut this and allo wed yo u to inc lude arguments with Target Path. On Windo ws 2000, ho wever, this will c ause serio us erro rs. Therefo re, always plac e additio nal arguments into the Arguments pro perty. ‘ 9-9.VBS set wshshell = CreateObject(“WScript.Shell”) desktop = wshshell.SpecialFolders(“desktop”) personal = wshshell.SpecialFolders(“MyDocuments”) set scut = wshshell.CreateShortcut(desktop & “\MyDocs.lnk”) scut.TargetPath = “explorer.exe” scut.Arguments = “/e,/root,” & personal scut.IconLocation = “shell32.dll,20” scut.Save MsgBox “New link created on your desktop.”
Selecting a new window size Links c an o pen the target file using different windo w styles. Yo u c an c o ntro l whether the target file is o pened in a minimized, no rmal, o r maximized windo w. This is espec ially useful if yo u plan to launc h sho rtc uts auto matic ally using the StartUp pro gram gro up. To prevent sc reen c luttering, it’s best to o pen tho se sho rtc uts in minimized windo ws. This way, when yo u start Windo ws, the auto start applic atio ns will nic ely align in the taskbar and leave yo ur deskto p unto uc hed. First, take a lo o k at yo ur o ptio ns in Table 9-2:
Table 9-2
W indow Styles Used W ith Shortcuts
Option
Description
1
Window is normal s ize.
3
Window is maximized.
7
Window is minimized — bes t for autos tarts .
The next sc ript sho ws ho w to c hange the windo w style. The sc ript ac c esses yo ur Startup pro gram gro up and c hanges all auto start links to minimized windo ws: ‘ 9-10.VBS set wshshell = CreateObject(“WScript.Shell”)
Chapte r 9 : Mas te ring Links ■
307 ■
set fs = CreateObject(“Scripting.FileSystemObject”) autostart = wshshell.SpecialFolders(“startup”) set folder = fs.GetFolder(autostart) for each file in folder.files ext = lcase(fs.GetExtensionName(file.name)) if ext=”lnk” then set scut = wshshell.CreateShortcut(file.path) scut.WindowStyle = 7 scut.Save counter = counter + 1 end if next MsgBox “Changed “ & counter & “ shortcuts to minimized style.”
This sc ript will o nly c hange sho rtc uts in yo ur perso nal StartUp fo lder. On Windo ws NT/ 2000, yo u might find additio nal sho rtc uts in the spec ial StartUp fo lder fo r all users. To ac c ess these sho rtc uts, use SpecialFolders(“AllUsersStartup”). The windo w styles o utlined in Table 9-2 are o nly a subset o f all available windo w styles. The sho rtc ut o bjec t limits yo u to three alternatives. If yo u pro vide different numbers, they will be c o nverted to 1.
Accessing the shell link object The shell again has its very o wn way o f handling link files. To ac c ess a link file, use the fo llo wing appro ac h: set wshshell = CreateObject(“WScript.Shell”) desktop = wshshell.SpecialFolders(“desktop”) ‘ create dummy link the conventional way linkfile = desktop & “\testlink.lnk” set scut = wshshell.CreateShortcut(linkfile) scut.TargetPath = “notepad.exe” scut.Save ‘ access link via Shell set linkobj = GetLink(linkfile) MsgBox “I received object: “ & TypeName(linkobj)
function GetLink(name) set shell = CreateObject(“Shell.Application”) folder = left(name, InstrRev(name, “\”)) file = mid(name, InstrRev(name, “\”)+1) set folderobj = shell.NameSpace(folder) set folderitem = folderobj.ParseName(file) if folderitem.isLink then set GetLink = folderitem.GetLink
308
Part II: Co nque ring the File Sys te m
■
■
else set GetLink = Nothing end if end function
Why wo uld yo u take the extra effo rt to ac c ess a link thro ugh the shell? One example is to reso lve links. The shell o ffers many extra tric ks that the WScript.Shell link metho ds c an’t pro vide. Let’s take a lo o k at the shell’s link o bjec t first.
Examining the shell’s link object Table 9-3 sho ws ho w a shell link o bjec t is o rganized. Its o ffic ial name is IshellLink:
Table 9-3
The Shell Link Object
Property/M ethod
Description
Property Arguments As String
Get the arguments for the link
Property Description As String
Get the des cription for the link
Function GetIconLocation (pbs As String) As Long
Get the IconLocation for the link
Property Hotkey As Long
Get the Hotkey for the link
Property Path As String
Get the target path of the link
Sub Resolve(ByVal fFlags As Long)
Tell the link to res olve its elf
Sub Save([ByVal vWhere])
Tell the link to s ave the changes
Sub SetIconLocation (ByVal bs As String, ByVal iIcon As Long)
Set the IconLocation for the link
Property ShowCommand As Long
Get the Show Command for the link (the kind of w indow the link opens )
Property WorkingDirectory As String
Get the w orking directory for the link
Many metho ds c o rrespo nd to the metho ds o f the WScript.Shell sho rtc ut o bjec t. But there’s mo re — what abo ut Resolve?
Chapte r 9 : Mas te ring Links
309
■
■
Resolving links Links are fragile. Onc e yo u mo ve the target file to ano ther plac e — o r yet wo rse, delete it — the link is helpless. In these situatio ns, the shell tries to reso lve the link. Reso lving means the shell tries to trac k where the target file has been mo ved and adjusts the link’s target appro priately. Yo u c an easily view this pro c ess by c reating a new text file o n yo ur deskto p and then rightc lic king the file and c ho o sing Create Sho rtc ut. Then, delete the text file. The sho rtc ut is still there, and o nc e yo u o pen it, the shell displays a dialo g bo x while it searc hes fo r the target. Windo ws 2000 do es a muc h better jo b in link reso lving. The built-in Distributed Link Trac king (DLT) servic e keeps trac k o f mo ved files and c an easily determine the c o rrec t new po sitio n as lo ng as the file still exists. In this c ase, yo u wo n’t see any dialo g bo xes. Windo ws c hanges the link target silently in the bac kgro und. In o rder to see the reso lve dialo g bo x, yo u must delete the target file. Abo ve, yo u saw ho w yo ur sc ripts c an bro wse thro ugh yo ur links and c hec k the target. So far, yo ur sc ripts haven’t been able to repair damaged links. They c o uld o nly o ffer to delete them. A little later in this c hapter, yo u learn additio nal metho ds that allo w yo ur sc ripts to reso lve links the way the shell do es. Reso lving is ac c o mplished thro ugh the Resolve metho d. This is ho w yo u reso lve a link: ‘ 9-12.VBS set wshshell = CreateObject(“WScript.Shell”) desktop = wshshell.SpecialFolders(“desktop”) ‘ change this line to the name of the link you want to resolve! linkfile = desktop & “\testlink.lnk” set linkobj = GetLink(linkfile) linkobj.Resolve(4) function GetLink(name) set shell = CreateObject(“Shell.Application”) folder = left(name, InstrRev(name, “\”)) file = mid(name, InstrRev(name, “\”)+1) set folderobj = shell.NameSpace(folder) set folderitem = folderobj.ParseName(file) if folderitem.isLink then set GetLink = folderitem.GetLink else set GetLink = Nothing end if end function
310
Part II: Co nque ring the File Sys te m
■
■
To test this sc ript, c hange the link name to a test link yo u plac e o n yo ur deskto p, and then remo ve the link’s target file. The sc ript expec ts a link named testlink to be o n yo ur deskto p. Unfo rtunately, the sc ript is no t very helpful, bec ause if the link’s target exists, it wo n’t do a thing. If the link’s target is missing, it wo n’t reso lve it. Instead, it c o mplains abo ut the missing link, as sho wn in Figure 9-10. The dialo g bo x sho wn during link reso lving needs a parent windo w. Yo ur sc ript do esn’t have a windo w, so the shell c an’t display its pro gress windo w; instead, it po ps up its c o mplaint. It wo n’t reso lve the link unless yo u either pro vide a windo w o r turn o ff the pro gress dialo g bo x.
Figure 9-10: So far, the Resolve method w on’t res olve your link. To make yo ur sc ript wo rk, yo u need to turn o ff the shell’s user interfac e. This is do ne thro ugh flags. Table 9-4 presents the c o mplete list o f flags.
Table 9-4
Flags for Link Resolving
Flag
Description
1
NO_UI: don’t s how progres s dialog box w hile res olving a link
2
ANY_MATCH: not us ed anymore
4
UPDATE: update the link’s target property w ith the found alternative target
8
NOUPDATE: don’t update the link
16
NOSEARCH: don’t us e the s earch heuris tics
32
NOTRACK: don’t us e Window s 2000 object tracking (Win2000 only)
64
NOLINKINFO: don’t us e the net and volume relative info
128
INVOKE_MSI: If the link is part of an application, invoke the Window s Ins taller to (re)ins tall the mis s ing application part (Win2000 only).
Bec ause yo u do n’t have a dialo g bo x info rming yo u abo ut the newly fo und target, yo ur sc ript will need to take c are o f it. This sc ript c hec ks a link’s target, reso lves the link if the target is missing, and asks fo r yo ur permissio n to c hange the target:
Chapte r 9 : Mas te ring Links ■
311 ■
‘ 9-13.VBS ‘ where’s my desktop? set wshshell = CreateObject(“WScript.Shell”) desktop = wshshell.SpecialFolders(“desktop”) ‘ change this line to the name of the link you want to resolve! linkfile = desktop & “\testlink.lnk” ‘ check target of this linkfile and resolve if necessary! ResolveLink linkfile sub ResolveLink(name) set shell = CreateObject(“Shell.Application”) set fs = CreateObject(“Scripting.FileSystemObject”) ‘ split path in folder and file folder = left(name, InstrRev(name, “\”)) file = mid(name, InstrRev(name, “\”)+1) ‘ access file through shell: set folderobj = shell.NameSpace(folder) set folderitem = folderobj.ParseName(file) ‘ check whether it really is a shortcut: if folderitem.isLink then ‘ get link object set linkobj = folderitem.GetLink ‘ remember old target: oldtarget = linkobj.Path ‘ old target still valid? if fs.FileExists(oldtarget) then ‘ yes, nothing else to do: exit exit sub end if ‘ target invalid? Resolve! ‘ use flag 1 to disable user interface ‘ don’t use update flag 4 yet! First ask if ok! linkobj.Resolve(1) ‘ read new target newtarget = linkobj.Path msg = “Link “”” & name & “”” points to “”” _ & oldtarget & “””” & vbCr msg = msg & “This target doesn’t exist any longer. “ & vbCr ‘ no new target found? Then get rid of this link! if oldtarget = newtarget then msg = msg & “Do you want to delete the link?” result = MsgBox(msg, vbYesNo + vbExclamation) if result = vbYes then fs.DeleteFile name
312
Part II: Co nque ring the File Sys te m
■
■
end if else ‘ new target found! msg = msg & “I’ve determined that “”” & newtarget _ & “”” resembles the lost target the best.” & vbCr msg = msg & “Do you want me to adjust the target?” result = MsgBox(msg, vbYesNo + vbQuestion) ‘ if user allowed update, call Save method to ‘ activate new settings in link: if result = vbYes then linkobj.Save end if end if end if end sub
No te ho w the sc ript makes use o f the Resolve flags. It uses flag 1 to turn o ff the dialo g bo x. This is the o nly way to start the reso lving pro c ess unless yo u pro vide a windo w fo r the dialo g bo x (see the fo llo wing sec tio n). Do n’t use flag 4 to update yo ur sho rtc ut. If yo u do so , Windo ws will auto matic ally c hange yo ur link’s target path and wo rking direc to ry. Bec ause yo ur sc ript first wants to ask fo r permissio n, it do esn’t use auto matic update. After the user has given his o r her o kay in the dialo g bo x, as sho wn in Figure 9-11, the sc ript c alls the link o bjec t Save metho d (if a new target was identified) o r remo ves the link.
Figure 9-11: Your s cript us es its ow n us er interface to pres ent the res ults .
Background: How Windows resolves links Ho w do es Windo ws reso lve a link anyway? Let’s have a lo o k: ■ On Windo ws 2000, it first asks the Distributed Link Trac king Servic e.
This servic e trac ks all file mo vements and is a very quic k and safe way o f updating links. If yo u do n’t want to use DLTS, use Resolve with the NOTRACK flag.
Chapte r 9 : Mas te ring Links
313
■
■
■ If DLTS do esn’t find the file, o r if yo u are using Windo ws 9.x o r NT, Windo ws
invo kes its searc h heuristic s. It lo o ks in the target’s last kno wn direc to ry to find a file with a different name but with the same attributes and filec reatio n time. If it isn’t suc c essful, it rec ursively searc hes subdirec to ries fo r a file with the target’s name and c reatio n date. If still no t suc c essful, it lo o ks o n the deskto p and o ther lo c al vo lumes. Searc h heuristic s take a lo ng time and are no t very dependable. Whenever yo u use searc h heuristic s to reso lve a link, yo u must do uble-c hec k the result manually. To avo id searc h heuristic s, use the NOSEARCH flag. ■ If bo th appro ac hes fail, the system o pens a dialo g bo x and asks fo r yo ur
help. Yo u no w c an manually c ho o se the new target file. Mo st o f the time, this is abso lutely useless bec ause the user wo n’t kno w the new target destinatio n either. The dialo g bo x is o nly sho wn if yo u did no t use the NO_UI flag. Yo u will never see this dialo g bo x with any o f the sc ripts abo ve. Thro ugh the Resolve flags, yo u have tight co ntro l o ver the reso lutio n pro cess. Fo r example, o n Windo ws 2000 systems, yo u might want to auto matically reso lve with DLTS o nly, as search heuristics are no t a dependable mechanism — specify NOSEARCH and NO_UI.
Using the of ficial link resolving dialog box The questio n still remains — why c an’t yo ur sc ripts use the o ffic ial Resolve dialo g bo x? Things wo uld bec o me so muc h easier, and while the system searc hed fo r a link target, the user wo uld see a pro gress indic ato r. Yo u c an! Just pro vide a windo w the dialo g bo x c an ac c ess. This windo w do esn’t need to be visible. The fo llo wing sc ript uses a hidden Internet Explo rer windo w and c an finally reso lve links exac tly the way the shell do es it — see Figure 9-12. ‘ 9-14.VBS set wshshell = CreateObject(“WScript.Shell”) desktop = wshshell.SpecialFolders(“desktop”) linkfile = desktop & “\testlink.lnk” ResolveLink linkfile, 4+32
sub ResolveLink(filepath, flag) set ie = CreateObject(“InternetExplorer.Application”) ‘ split path in folder and file: folder = left(filepath, InstrRev(filepath, “\”)) file = mid(filepath, InstrRev(filepath, “\”)+1) ‘ navigate to folder and wait until it is displayed: ie.navigate folder ‘ie.visible = true
314
Part II: Co nque ring the File Sys te m
■
■
do until ie.readyState=4 loop ‘ access file: set folderobj = ie.document.folder set folderitem = folderobj.ParseName(file) ‘ is it really a link? if folderitem.isLink then set linkobj = folderitem.GetLink ‘ resolve: linkobj.Resolve(flag) end if end sub
Figure 9-12: Your s cript can us e the official Res olve dialog box, too! This time, the shell displays its dialo g bo x. The script uses two flags — 4 fo r auto matic update and 32 to turn o ff link-tracking (o n Windo ws 2000). If yo u do n’t turn link-tracking o ff, o n Windo ws 2000, yo u will no t see the dialo g bo x. Link-tracking is highly efficient and wo rks in a matter o f milliseco nds. In additio n, if link-tracking identified the target, it wo n’t ask fo r yo ur permissio n to update the link. Link-tracking safely identifies the target. Search heuristics, in co ntrast, can o nly guess and always asks fo r co nfirmatio n. In real life, never turn o ff linktracking, as it’s the best way fo r reso lving links. Yo u’ll no te that the results are similar. If Windo ws c an’t determine a new target, it o ffers to delete the sho rtc ut as depic ted in Figure 9-13. This message lo o ks almo st like yo ur c usto m message sho wn in Figure 9-11.
Figure 9-13: If the link can’t be res olved, Window s offers to delete the link.
Chapte r 9 : Mas te ring Links
315
■
■
This sc ript uses the Internet Explo rer to ac c ess the link file. Bec ause Internet Explo rer has its o wn windo w, the dialo g bo x c an be made visible. The IE windo w, ho wever, is hidden. If yo u wanted to , yo u c o uld also make it visible using ie.visible=true. Ho wever, using a hidden IE windo w has so me drawbac ks yo u sho uld kno w abo ut. The system c lo sely mo nito rs the hidden IE applic atio n, and if yo u do n’t use it fo r a while, the system c lo ses it do wn. This is why yo u sho uld handle all IE requests within o ne pro c edure. Never split the ac tio n up. Otherwise, yo u might rec eive a “server applic atio n no lo nger available” erro r.
Designing Context menu extensions With this new kno wledge, yo u c an no w c reate many useful c o mmand extensio ns. Fo r example, links traditio nally have an anno ying drawbac k — right-c lic king a link and c ho o sing Pro perties will always invo ke the link’s Pro perties page — there’s no easy way to c all the real target’s Pro perties page. The next sc ript adds the missing c o mmand. It determines the link target and c alls the target’s Pro perties page: ‘ 9-15.VBS set args = WScript.Arguments if args.Count=0 then MsgBox “This script is intended as context menu command.” WScript.Quit end if set wshshell = CreateObject(“WScript.Shell”) if not lcase(right(args(0),3))=”lnk” then MsgBox “You did not specify a link!” WScript.Quit end if set scut = wshshell.CreateShortcut(args(0)) filepath = scut.TargetPath if filepath=”” then MsgBox “Link points to virtual object. Can’t display properties!” WScript.Quit end if ‘ split path in folder and file: folder = left(filepath, InstrRev(filepath, “\”)) file = mid(filepath, InstrRev(filepath, “\”)+1) set ie = CreateObject(“InternetExplorer.Application”) if file=”” then
316
Part II: Co nque ring the File Sys te m
■
■
file = folder folder = “::{20D04FE0-3AEA-1069-A2D8-08002B30309D}” end if
‘ navigate to folder and wait until it is displayed: ie.navigate folder ‘ie.visible = true do until ie.readyState=4 loop ‘ access file: set folderobj = ie.document.folder set folderitem = folderobj.ParseName(file) folderitem.InvokeVerb(“Properties”)
Exc hange “Pro perties” in the last sc ript line with whatever yo ur system c alls the Pro perties c o mmand. Remember: Only Windo ws 2000 allo ws the use o f generic c o mmand names. This sc ript wo n’t wo rk by itself. It expec ts the link file name as argument. Yo u c an drag a link file o nto the sc ript ic o n. Or better yet, yo u c an integrate yo ur new c o mmand into the link Co ntext menu. The next sc ript pro vides a quic k so lutio n. Sto re yo ur Pro perties sc ript in a safe plac e, then drag it o nto the fo llo wing sc ript’s ic o n. ‘ 9-16.VBS set args = WScript.Arguments if args.Count>0 then set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) ext = lcase(fs.GetExtensionName(args(0))) if ext”vbs” then MsgBox “You did not drag a VBS script!” WScript.Quit end if name = InputBox(“How do you want to call your command?”,, _ “True Properties”) key = “HKCR\lnkfile\shell\” & name & “\” wshshell.RegWrite key, name wshshell.RegWrite key & “command\”, _ “wscript.exe “”” & args(0) & “”” “”%L””” else MsgBox “Please drag a VBS script on my icon!” end if
Learn mo re. abo ut c o ntext menus and ho w to insert yo ur o wn c o mmands in Chapter 14
Chapte r 9 : Mas te ring Links
317
■
■
Understanding virtual folders Yo ur Pro perties sc ript uses the Internet Explo rer to get ac c ess to the target file and invo ke its Pro perties page. This is nec essary fo r the Pro perties dialo g bo x to bec o me attac hed to the system shell. To ac c ess a file in Internet Explo rer (o r thro ugh o ther shell metho ds), yo u first need to navigate to the fo lder that the target file o r fo lder resides in. Next, yo u c an use ParseName to get ac c ess to the target file o r fo lder. This impo ses a pro blem when trying to ac c ess a ro o t drive. Where’s the parent fo lder o f drive C:\, and ho w do yo u get Internet Explo rer to navigate to this parent fo lder? The parent fo lder o f all drives is My Co mputer. Bec ause this is a virtual fo lder, yo u c an’t ac c ess it thro ugh a path name. Instead, yo u need to spec ify its internal identifier. Explo rer (and Internet Explo rer) c an navigate to any virtual fo lder. Spec ify two c o lo ns as the path name, fo llo wed by the Class-ID o f the virtual fo lder yo u want to visit. The sc ript uses My Co mputer’s internal Class-ID to navigate to the ro o t o f all drives o nc e it detec ts that no filename was spec ified. This o nly happens if the target is a ro o t drive. No te also that so me links do n’t return a TargetPath pro perty value. Target Path is empty whenever a link po ints to so me internal system c o mpo nent suc h as a printer. In these c ases, yo ur sc ript c an’t display the Pro perties page and po ps up a message.
Secret Class-IDs of virtual folders Take a lo o k at Table 9-5! It lists all the hidden Class-IDs o f virtual fo lders yo ur Explo rer c an navigate to . To try them o ut, o pen yo ur Start menu and c ho o se Run. Next, enter explorer.exe, a spac e, and two c o lo ns. Then enter the Class-ID. Do n’t fo rget the c urly brac kets. The Explo rer pro mptly navigates to the virtual fo lder yo u spec ified. Fo r example, to o pen the Netwo rk Neighbo rho o d, enter this c o mmand: EXPLORER.EXE ::{208D2C60-3AEA-1069-A2D7-08002B30309D}, as sho wn in Figure 9-14.
Figure 9-14: Open virtual folders us ing s ecret Explorer options .
318
Part II: Co nque ring the File Sys te m
■
■
Explo rer c an o nly navigate to tho se virtual fo lders that are ac c essible fro m yo ur deskto p. If yo u have deleted the Rec yc le Bin fro m yo ur deskto p, fo r example, yo u wo n’t be able to use the Class-ID any mo re to navigate there.
Table 9-5
Class-IDs of Desktop Items
Class-ID
Virtual Folder
{208D2C60-3AEA-1069-A2D7-08002B30309D}
Netw ork Neighborhood
{20D04FE0-3AEA-1069-A2D8-08002B30309D}
My Computer
{3DC7A020-0ACD-11CF-A9BB-00AA004AE837}
Internet
{450D8FBA-AD25-11D0-98A8-0800361B1103}
My Documents
{645FF040-5081-101B-9F08-00AA002F954E}
Recycle Bin
Selecting a link target Here’s ano ther useful Co ntext menu extensio n. Ever wo ndered where the file o r fo lder to whic h a link po ints ac tually lives? The fo llo wing sc ript is the so lutio n: It o pens the c o ntaining fo lder and marks the drive, fo lder, o r file yo ur link po ints to . Just insert this sc ript into the link Co ntext menu using the same helper sc ript yo u used to insert the True Pro perties c o mmand: Save the fo llo wing sc ript in a safe plac e, drag it o nto the helper sc ript ic o n, and spec ify a name: fo r example, “Sho w Target.” ‘ 9-17.VBS set args = WScript.Arguments if args.Count=0 then MsgBox “This script is intended as context menu command.” WScript.Quit end if set wshshell = CreateObject(“WScript.Shell”) if not lcase(right(args(0),3))=”lnk” then MsgBox “You did not specify a link!” WScript.Quit end if set scut = wshshell.CreateShortcut(args(0)) filepath = scut.TargetPath if filepath=”” then MsgBox “Link points to virtual object. Can’t mark!” WScript.Quit end if
319
Chapte r 9 : Mas te ring Links ■
■
MarkFile filepath sub MarkFile(filepath) ‘ split path in folder and file: folder = left(filepath, InstrRev(filepath, “\”)) file = mid(filepath, InstrRev(filepath, “\”)+1) set ie = CreateObject(“InternetExplorer.Application”) if file=”” then file = folder folder = “::{20D04FE0-3AEA-1069-A2D8-08002B30309D}” end if ‘ navigate to folder and wait until it is displayed: ie.navigate folder do until ie.readyState=4 loop ‘ access file: set folderobj = ie.document.folder set folderitem = folderobj.ParseName(file) ‘ mark file: ie.document.selectItem folderitem, 1+4+8+16 ‘ show IE window ie.visible = true end sub
This sc ript uses yet ano ther undo c umented metho d: selectItem. This metho d is pro vided by the Internet Explo rer shell view, ac c essible thro ugh ie.document. Table 9-6 pro vides a c o mplete list o f all pro perties and metho ds.
Table 9-6
The Internet Explorer WebView Object
Property/M ethod
Description
Property Application As Object
Get Application object
Property FocusedItem As FolderItem
The currently focus ed item in the folder
Property Folder As Folder
Get the folder being view ed
Property Parent As Object
Get Parent object
Function PopupItemMenu (ByVal pfi As FolderItem, [ByVal vx], [ByVal vy]) As String
Show Items menu and return command s elected Co ntinue d
320
Part II: Co nque ring the File Sys te m
■
■
Table 9-6
( co ntinue d)
Property/M ethod
Description
Property Script As Object
Return the s cripting automation model
Function SelectedItems As FolderItems
The collection of Selected Items in folder
Sub SelectItem (pvfi, ByVal dwFlags As Long)
Select the item
Property ViewOptions As Long
Return the view options for s how ing a folder
SelectItem is by far the mo st useful metho d. The o ther metho ds c an be used to determine whic h items are c urrently selec ted in the IE windo w. SelectItem expec ts the FolderItem o bjec t that yo u want to mark. As sec o nd parameter, it asks fo r flags. Table 9-7 pro vides the list.
Table 9-7
WebView Item Selection Flags
Flag
Description
0
Remove s election
1
Select
3
Rename item
4
Remove all s elections except for the current object
8
Move s elected item into the vis ible part of the w indow
16
Give focus to s elected item
Summary Yo u have disc o vered two ways o f ac c essing sho rtc ut files: the o ffic ial WScript. Shell sho rtc ut o bjec t and the hidden shell mec hanism. The shell mec hanism pro vides additio nal metho ds fo r reso lving bro ken links. Many sample sc ripts have demo nstrated ho w to manage all o f yo ur sho rtc ut files and searc h fo r bro ken links o r duplic ate keybo ard sho rtc uts. Yo u’ve even seen ho w to add new Co ntext menu c o mmands to yo ur sho rtc ut file Co ntext menu fo r o pening a target’s Pro perties page o r fo r marking the target file in the Explo rer. As a side effec t, yo u’ve seen ho w to o pen the Explo rer with hidden o ptio ns and using Class-IDs.
Chapte r 1 0
Launching Any Program By Script In This Chapter 䊳 Learn ho w to launc h any pro gram by sc ript 䊳 Launc h entire pro gram gro ups 䊳 Use hidden windo ws and o ther windo w styles 䊳 Wait fo r pro grams and analyze their return values 䊳 Build spec ial maintenanc e sc ripts that c hec k yo ur hard drives 䊳 Remo te c o ntro l pro grams and dialo g bo xes by sending keystro kes via
SendKeys 䊳 Bring windo ws to the fo regro und use sec ret API magic 䊳 Direc ting keystro kes to the right windo w safely 䊳 Enumerate all o pen windo ws and c lo se do wn all running pro grams by sc ript 䊳 Exec ute DOS c o mmands and read in their results 䊳 Launc h Co ntro l Panel applets and preselec t their tabs 䊳 Ho o k into mo dern so ftware and bo rro w their internal metho ds fo r yo ur o wn
purpo ses
S
c ripts c an c o ntro l o ther pro grams. In this c hapter, yo u learn ho w to launc h external pro grams. Yo u also disc o ver ways to determine windo ws style, hide pro gram windo ws, remo te c o ntro l o ther pro grams, and thus use sc ripts as a po werful mac ro language to c o ntro l just abo ut any task.
Launching Programs Sc ripts replac e the c lassic al batc h files. They are muc h easier to develo p, yet are muc h mo re po werful. Batc h files were c o mmo nly used to launc h so ftware. Yo ur sc ripts c an do this, to o — and a lo t mo re o n to p o f it. In fac t, sc ripts c an ac t as so ftware glue. They tie to gether pro grams and individual pro gram func tio ns to c reate c o mpletely new pro blem so lvers.
324
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Sc ripts c an explo it o ther so ftware in three ways: ■ Launc hing direc tly: The WScript.Shell o bjec t spo rts the Run metho d.
This metho d launc hes any pro gram as if yo u had launc hed it manually. Run c an launc h pro grams bo th sync hro no usly and async hro no usly, so yo ur sc ript c an wait fo r the pro gram to c o mplete and read its return value, o r it c an launc h pro grams c o nsec utively. ■ Using DOS: Even DOS c o mmands c an be exec uted. Yo ur sc ript just needs
to launc h the c o mmand line interpreter and feed it the DOS c o mmands. ■ Ac c essing Spec ialties: Mo st mo dern so ftware pac kages c o ntain an interfac e
c alled IDispatch. Yo ur sc ript c an ac c ess tho se so ftware pac kages using CreateObject and bo rro w their internal func tio ns fo r its o wn purpo ses. Fo r example, if yo u have installed Mic ro so ft Offic e, yo ur sc ript c an bo rro w its spell-c hec ker and c hec k any file yo u want. In mo st respec ts, sc ripts are far superio r to c lassic al batc h files. Ho wever, sc ripts need the Sc ripting Ho st in the bac kgro und. Yo u c an’t run sc ripts o utside o f Windo ws. Beginning with Windo ws 2000, Mic ro so ft has c ho sen sc ripts to be the new o ffic ial “batc h” files. Here, yo u c an assign sc ripts to the lo go n o r lo go ff pro c ess, eliminating the need fo r batc h files alto gether.
Launching programs directly To launc h o ther so ftware, all yo u need are a few sc ripting lines. Have a lo o k: ‘ 10-1.VBS set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “notepad.exe”
This little sc ript launc hes yo ur edito r. Pretty straightfo rward, no ? Always supply the fully qualified path name whenever the file isn’t sto red in o ne o f the fo lders inc luded by the path enviro nment variable. No tepad is sto red inside the Windo ws fo lder, so yo u do n’t need a path. Other so ftware might reside in its o wn fo lder. In this c ase, a path name is mandato ry. There’s o ne little pec uliarity abo ut Run, and it’s that it c ho kes o n spac es. Whenever a path name yo u supply c o ntains spac es, Run wo n’t exec ute it. Instead, it interprets the spac e as delimiter and views the rest as argument. To wo rk aro und this “spac e” pro blem, always delimit yo ur path name in quo tes. Use do uble quo tes inside strings. To launc h the so ftware C:\my software\test.exe, use wshshell.Run “””C:\my software\ test.exe”””. Here are so me mo re neat tric ks: ■ Do es the file exist? To make sure yo ur Run c o mmand do esn’t raise
an erro r, first c hec k whether the file yo u want to launc h really exists. Use the FileExists metho d pro vided by the Scripting.File SystemObject.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
325
■
■
■ Run do esn’t o nly launc h exec utables. Yo u c an easily pro vide a regular
filename. In this c ase, Run will auto matic ally launc h the pro gram that is asso c iated with this file type and lo ad the do c ument. Ho wever, if no pro gram is asso c iated with the file type, yo u’ll get a nasty erro r message. ■ Open do c uments with yo ur pro gram o f c ho ic e — yo u c an spec ify arguments
and determine whic h pro gram sho uld o pen a spec ific file. Fo r example, to o pen an HTML file with a bro wser o ther than Internet Explo rer, use the bro wser exec utable path in quo tes, a spac e, and then the do c ument path in quo tes. ■ Fo r enviro nment variables, Run auto matic ally c o nverts enviro nment
variables yo u might have defined in yo ur Lo gin sc ript. To c all a pro gram inside yo ur Windo ws fo lder, use %WINDIR%: fo r example, wshshell.Run “%WINDIR%\explorer.exe”.
Launching an entire program group Co mputer users wo uld rather delegate wo rk to their c o mputers. Why do things manually if yo ur c o mputer c an take c are o f it? One appro ac h to make life easier is the Startup Gro up. Any pro gram sho rtc ut yo u c o py into this spec ial pro gram gro up is launc hed auto matic ally whenever yo u lo g o n to Windo ws. This so unds like a great idea, but unfo rtunately mo st o f us do a lo t o f different things with o ur c o mputers. Auto starting pro grams make sense o nly if yo u use these pro grams every day. Otherwise, they c an bec o me very anno ying. A c o mpletely different appro ac h is to use c usto m pro gram gro ups. Yo u c an c reate individual pro gram gro ups fo r any majo r task yo u do with yo ur c o mputer. Fo r example, yo u c an c reate a gro up c alled “grafx” and c o py all the pro gram sho rtc uts in it that yo u usually use to c reate and mo dify artwo rk. Do the same fo r all the o ther tasks, suc h as Internet, music , wo rd pro c essing, and whatever else yo u c an think o f. No w yo u o nly need a quic k way o f launc hing entire pro gram gro ups. The fo llo wing sc ript will do the jo b. This sc ript uses the BrowseForFolder dialo g bo x yo u c reated in Chapter 6. Make sure yo u c o mpiled o r installed the pro jec t: \install\fo lderpic ker\ setup.exe. The Bro wse dialo g bo x isn’t really nec essary, but it makes things a lo t mo re c o nvenient. ‘ 10-2.VBS set browse = CreateObject(“folder.tools”) set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) ‘ which prg group do you want to launch? entry = browse.BrowseForFolder(2, _ “Which group or program do you want to launch?”, &h4001)
326
Part III: Starting and Co ntro lling Othe r So ftware
■
■
‘ did user cancel dialog? if entry = “” then MsgBox “Cancel accepted.”, vbInformation WScript.Quit end if ‘ find out whether use has selected group or individual program if fs.FileExists(entry) then ‘ a single program Launch entry, 1 elseif fs.FolderExists(entry) then ‘ a group set folder = fs.GetFolder(entry) ‘ folder empty? if folder.files.count=0 then MsgBox “The group “”” & fs.GetBaseName(folder) _ & “”” is empty. This script won’t “ _ & “execute files in subfolders.” WScript.Quit end if list = “Do you really want to launch these programs?” _ & vbCr & vbCr for each file in folder.files list = list & fs.GetBaseName(file.name) & vbCr next if MsgBox(list, vbYesNo + vbQuestion)=vbYes then for each file in folder.files Launch file.path, 2 next end if else MsgBox “””” & entry & “”” is missing!” end if
sub Launch(path, flag) on error resume next wshshell.Run “””” & path & “”””, flag on error goto 0 end sub
Drag yo ur sc ript ic o n o nto the Start butto n to insert a referenc e into yo ur Start menu. Next, right-c lic k the new Start menu entry and c ho o se Pro perties. No w yo u c an assign a sho rtc ut key to quic kly invo ke yo ur new pro gram launc her. Yo ur sc ript c an launc h bo th individual files and entire gro ups. The sc ript allo ws yo u to selec t bo th pro gram gro ups and individual files. If yo u selec t a gro up, the sc ript lists all the pro grams it is go ing to start and asks fo r yo ur permissio n (see Figure 10-1). It launc hes the pro grams in minimized windo ws so multiple pro gram windo ws wo n’t c lutter yo ur deskto p. If yo u selec t an individual pro gram, the sc ript will launc h it direc tly and as a no rmal windo w.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
327
■
■
Figure 10-1: The s cript lis ts all programs you are about to launch and as ks for permis s ion.
Determining window size The Run metho d c an even determine the kind o f windo w the launc hed pro gram will get. Spec ify the windo w style as sec o nd argument. Table 10-1 summarizes yo ur o ptio ns.
Table 10-1
W indow Sizes Relevant to the Run M ethod
Code
Description
0
No w indow at all.
1
Normal w indow.
2
Minimized w indow.
3
Maximized w indow.
4
Same w indow as las t time the program w as called.
5
Same as 4, w indow gets focus .
6
Minimized w indow, next w indow gets focus .
7
Minimized w indow, active w indow remains active.
8
Normal w indow, active w indow remains active.
9
Normal w indow gets focus .
In everyday life, o ptio ns 1 thro ugh 3 c o ver all yo u need. Optio n 0 is spec ial: It launc hes the pro gram witho ut a windo w. The pro gram remains hidden. This c an be extremely useful when launc hing DOS c o mmands
328
Part III: Starting and Co ntro lling Othe r So ftware
■
■
o r servic e pro grams yo u want to hide fro m the user. Ho wever, c alling a pro gram witho ut a windo w may be dangero us: Yo u no lo nger rec eive erro r messages, and yo u have no way o f c lo sing the pro gram manually. Use Optio n 0 (hidden windo w) with c are: During develo pment, always use a different o ptio n so yo u c an see whether yo ur pro gram behaves the way yo u expec t. Use o ptio n 0 o nly with pro grams that c lo se themselves auto matic ally after they are do ne. Never use o ptio n 0 with pro grams that might require user interac tio n.
Waiting for a program to finish So far, the Run metho d will launc h the files and immediately return c o ntro l to yo ur sc ript. Yo u c an launc h a who le series o f pro grams, and they will all be exec uted at the same time. This appro ac h is no t always best. Yo u might want to kno w the result o f so me pro gram, o r c all pro grams c o nsec utively. Let’s do it! Just spec ify true as third parameter, and the Run metho d will wait fo r the pro gram to c o mplete. In additio n, it no w returns the pro gram’s return value so yo u c an c hec k whether the pro gram did its jo b o r enc o untered pro blems. This example demo nstrates the general c o nc ept: The edito r is launc hed, and the sc ript waits until yo u c lo se it. The sec o nd MsgBox statement exec utes after yo u c lo se the edito r windo w. ‘ 10-3.VBS set wshshell = CreateObject(“WScript.Shell”) MsgBox “Please enter something, then close the editor!” result = wshshell.Run(“notepad”,,true) MsgBox “Thank you!”
Run reads the return value and passes it to yo ur sc ript. Whether this return value makes any sense o r no t is c o mpletely up to the pro gram yo u launc hed. Eac h pro gram is free to return any value. The next sc ript demo nstrates ho w useful the return value c an be. It launc hes the Sc anDisk disk c hec ker utility. This utility is available o n Win9.x o nly: ‘ 10-4.VBS set wshshell = CreateObject(“WScript.Shell”) returncodes = Split(“ok;detected error and corrected it;” _ & “DSKMAINT.DLL missing;out of memory;couldn’t” _ & “ correct disk error;couldn’t check a drive;check “ _ & “interrupted;disk error prevented further checking”, “;”) result = wshshell.run( _ “scandskw.exe /allfixeddisks /silent /noninteractive”,, true)
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
329
■
■
‘ mask unused bits result = result and not 65528 MsgBox “Result: “ & result & “: “ & returncodes(result)
The sc ript uses a c o uple o f sec ret o ptio ns to start Sc anDisk auto matic ally and witho ut user interventio n. Yo u c an expand the sc ript to inc lude many o ther disk maintenanc e utilities, to o . Fo r example, after c hec king a drive using Sc anDisk, yo u c an defrag the drive using defrag.exe. Bec ause the sc ript exec utes o ne pro gram after the o ther, the maintenanc e to o ls wo n’t run into eac h o ther, and yo u c an c all yo ur maintenanc e sc ript at night to do the lengthy maintenanc e wo rk.
Calling disk tools silently Disk to o ls are useless fo r remo te ac tio n if they require user input — after all, yo u want yo ur sc ript to run unattended. This is why mo st disk to o ls c an be prec o nfigured. Bo th SCANDSKW.EXE and DEFRAG.EXE wo rk this way. To prec o nfigure a disk to o l, c ho o se Run fro m yo ur Start menu and c all the disk to o l with the o ptio n /sageset:number. Replac e “number” with any number: fo r example, SCANDSKW.EXE /SAGESET:1. The disk to o l wo n’t start. Instead, a c o nfiguratio n dialo g bo x appears, and yo u c an c ho o se exac tly whic h o ptio ns yo u want yo ur sc ript to use. To c all the disk to o l with tho se prec o nfigured details, have yo ur sc ript launc h the to o l with the /sagerun:number o ptio n: fo r example, SCANDSKW.EXE /SAGERUN:1. It’s the o nly o ptio n yo u need. Auto matic ally, the to o l starts and uses the c o nfiguratio n details yo u previo usly spec ified. SAGE stands fo r “System AGEnt,” the Windo ws 9.x servic e that c alls pro grams auto matic ally at intervals. So , the /sage... o ptio ns ac tually belo ng to the System Agent, allo wing it to c all to o ls witho ut user interventio n. Yo ur sc ripts c an take advantage o f this.
Remote Controlling Running Programs Many pro grams do their jo b witho ut any user interventio n, whic h is go o d. But what if yo u need to press so me keys to make the pro gram wo rk? What if the pro gram po ps up anno ying dialo g bo xes? Relax! The Sc ripting Ho st 2.0 has the answer: SendKeys. This handy metho d sends keystro kes to the ac tive windo w so yo u c an bo ss it aro und any way yo u please. SendKeys makes it easy to remo te c o ntro l any pro gram.
Getting to know SendKeys The WScript.Shell o bjec t pro vides SendKeys. It c an send individual keys as well as key c o mbinatio ns to any windo w.
330
Part III: Starting and Co ntro lling Othe r So ftware
■
■
SendKeys is new and will o nly wo rk with WSH 2.0. Make sure yo u have updated yo ur Sc ripting Ho st as o utlined in the Prefac e. Here’s a little taste: ‘ 10-5.VBS set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “notepad.exe” ‘ wait a second WScript.Sleep 1000 ‘ write something to the window: wshshell.SendKeys “It’s me!” ‘ wait another second WScript.Sleep 1000 ‘ close the window wshshell.SendKeys “%{F4}”
This sc ript o pens the edito r, waits a sec o nd, o utputs so me text, and c lo ses the windo w using the key c o mbinatio n [Alt]+[F4]. Bec ause yo u “entered” text into the edito r, it will ask whether yo u want to save yo ur c hanges, as sho wn in Figure 10-2. A little later in the c hapter, yo u see ho w easy it is to extend this sc ript to take c are o f this dialo g bo x as well. One disadvantage o f SendKeys is the fac t that it sends the keystro kes “blindly” to the fo regro und windo w. If the edito r do esn’t po p up quic kly eno ugh o r hides behind o ther windo ws, the example will fail. A little later in the c hapter, yo u disc o ver ways to wo rk aro und this pro blem.
Figure 10-2: The s cript remotely ins erts text and tries to clos e the w indow.
Sending keys and key combinations SendKeys uses the spec ial c o des o utlined in Table 10-2 to “press” any o f the spec ial keys.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
331
■
■
Table 10-2
SendKeys Key Codes
Key
Code
BACKSPACE
{BACKSPACE}, {BS}, or {BKSP}
BREAK
{BREAK}
CAPS LOCK
{CAPSLOCK}
DEL or DELETE
{DELETE} or {DEL}
DOWN ARROW
{DOWN}
END
{END}
ENTER
{ENTER} or ~
ESC
{ESC}
F1
{F1}
F10
{F10}
F11
{F11}
F12
{F12}
F13
{F13}
F14
{F14}
F15
{F15}
F16
{F16}
F2
{F2}
F3
{F3}
F4
{F4}
F5
{F5}
F6
{F6}
F7
{F7}
F8
{F8}
F9
{F9}
HELP
{HELP}
HOME
{HOME}
INS or INSERT
{INSERT} or {INS}
LEFT ARROW
{LEFT}
NUM LOCK
{NUMLOCK} Co ntinue d
332
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Table 10-2
( co ntinue d)
Key
Code
PAGE DOWN
{PGDN}
PAGE UP
{PGUP}
PRINT SCREEN
{PRTSC}
RIGHT ARROW
{RIGHT}
SCROLL LOCK
{SCROLLLOCK}
TAB
{TAB}
UP ARROW
{UP}
[Shift] (modifier key)
+
[Ctrl] (modifier key)
^
[Alt] (modifier key)
%
The SendKeys string “%{F4}” represents the key c o mbinatio n [Alt]+[F4]. It c lo ses the ac tive windo w. Yo u c an even send keys repeatedly. To send 30 spac es, use {SPACE 30}.
Directing keys to the right window Sending keystro kes to a windo w is extremely versatile but also dangero us. SendKeys “blindly” sends keystro kes to the c urrently ac tive windo w. If the user has c lic ked ano ther windo w, o r if the windo w yo u wanted to c o ntro l didn’t rec eive the fo c us in the first plac e, yo ur keys may be transmitted to the c o mpletely wro ng windo w, c ausing unexpec ted behavio r. To fight this, Mic ro so ft invented the AppActivate metho d. This metho d brings any windo w yo u wish to the fo regro und — at least in theo ry.
AppActivate is pro vided by the WScript.Shell o bjec t and expec ts the name o f the windo w yo u want to give the fo c us to . Spec ify the name exac tly as it appears in the windo w’s title bar. Yo u do n’t need to spec ify the full windo w name. Spec ifying o nly part o f it switc hes to the next windo w title that matc hes the c aptio n. As an example, the fo llo wing sc ript o pens two windo ws and switc hes bac k and fo rth five times. But what is this? After the first c yc le, windo w switc hing do esn’t wo rk anymo re! Instead, the windo ws just nervo usly flash their c o mmand butto ns in the task bar. They wo n’t jump to the fo regro und.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
333
■
■
‘ 10-6.VBS set wshshell = CreateObject(“WScript.Shell”) windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) wshshell.Run “ explorer exe “ & windir wshshell.Run “notepad.exe “ & windir & “\win.ini” for x = 1 to 5 ‘ wait a second WScript.Sleep 1000 ‘ activate window 1 wshshell.AppActivate windir ‘ wait another second WScript.Sleep 1000 ‘ activate window 2 wshshell.AppActivate “WIN” next
Beginning with Windo ws 98, Mic ro so ft has built new c o de into the windo w subsystem. A windo w c an o nly rec eive the fo c us if the c alling applic atio n c urrently o wns it. Yo ur sc ript o wns the fo c us when yo u c all it and c an therefo re c o ntro l the fo c us. Ho wever, o nc e yo ur sc ript has given away the fo c us, it c an’t do any fo c us switc hing anymo re. Instead, the windo ws will o nly flash their butto ns. This also explains why so metimes even the VBSc ript MsgBox dialo g bo x remains hidden behind o ther windo ws. This is extremely bad news. AppActivate is rendered useless, and yo ur sc ripts have no safe way o f determining whic h windo w c urrently gets the fo c us.
Telling windows to switch focus no matter what There’s an easy so lutio n to the pro blem, altho ugh this so lutio n is abso lutely undo c umented. Thro ugh sec ret Windo ws APIs, yo u c an disable the fo c us lo c k. If yo u do , yo ur sc ripts c an happily c hange fo c us to any windo w. No mo re flashing windo w butto ns! To be able to c rac k the fo c us lo c k, yo u’ll need so me mo re details. Ac tually, Windo ws uses a parameter c alled ForegroundLockTimeout. This parameter defines a time perio d that defaults to 200 sec o nds. If a pro gram rec eives the fo c us and is idle fo r this time perio d, Windo ws allo ws o ther pro grams to steal the fo c us. This mec hanism is intended to prevent pro grams fro m jumping in the fo regro und while yo u are wo rking with so me o ther windo w. Yo ur sc ripts have no simple way o f retrieving the fo c us o nc e they have given it away using AppActivate. Ho wever, yo ur sc ripts c an set the Foreground LockTimeout value to 0. This effec tively turns o ff the fo c us lo c k, and AppActivate wo rks no matter who c urrently o wns the fo c us.
334
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Ho w do yo u c hange the fo c us timeo ut value? Yo u need to define a c usto m COM o bjec t! This o ne do es the jo b. It also inc ludes a func tio n to find o ut the name o f the c urrently ac tive windo w. Option Explicit Private Const SPI_GETFOREGROUNDLOCKTIMEOUT = &H2000 Private Const SPI_SETFOREGROUNDLOCKTIMEOUT = &H2001 Private Declare Function SystemParametersInfo Lib “user32” _ Alias “SystemParametersInfoA” (ByVal uAction As Long, _ ByVal uParam As Long, ByVal lpvParam As Any, _ ByVal fuWinINI As Long) As Long Private Declare Function GetActiveWindow Lib “user32” () _ As Long Private Declare Function GetWindowText Lib “user32” _ Alias “GetWindowTextA” (ByVal hwnd As Long, ByVal _ lpString As String, ByVal cch As Long) As Long
Public Sub SetActivation(ByVal millisecs As Long) SystemParametersInfo SPI_SETFOREGROUNDLOCKTIMEOUT, 0, millisecs, 0 End Sub Public Function GetActivation() As Long SystemParametersInfo SPI_GETFOREGROUNDLOCKTIMEOUT, 0, VarPtr(GetActivation), 0 End Function Public Function GetActiveWindowName() As String Dim result As Long Dim windName As String windName = Space(260) result = GetWindowText(GetActiveWindow, windName, 260) GetActiveWindowName = Left(windName, result) End Function
Lo ad the c o mplete pro jec t into yo ur VB CCE and c o mpile it yo urself, using \components\appactivate\appactivate.vbp. Or just install the prepared so ftware pac kage: \install\appactivate\setup.exe. No w yo ur windo w switc hing wo rks perfec tly smo o thly: ‘ 10-7.VBS set wshshell = CreateObject(“WScript.Shell”) set apptool = CreateObject(“app.activate”) windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) wshshell.Run windir wshshell.Run “notepad.exe “ & windir & “\win.ini”
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
335
■
■
‘ turn off focus lock and remember timeout value timeout = apptool.GetActivation apptool.SetActivation 0 for x = 1 to 5 ‘ wait a second WScript.Sleep 1000 ‘ activate window 1 wshshell.AppActivate windir ‘ wait another second WScript.Sleep 1000 ‘ activate window 2 wshshell.AppActivate “WIN” next ‘ restore timeout value apptool.SetActivation timeout
This is the ultimate prerequisite to use SendKeys safely. Fro m no w o n, yo u c an c ho o se the windo w yo u want to o utput keystro kes to .
Finding out whether a window exists There might be ano ther c o nc ern: What if the windo w yo u want to switc h to do esn’t exist? Ho w do yo u kno w it o pened c o rrec tly? Ho w do yo u determine whether o r no t the user has c lo sed the windo w in the meantime? AppActivate tells yo u! If yo u use it as func tio n, it will return true o r false. A false means no suc h windo w was fo und! In additio n, the new GetActiveWindowName metho d repo rts the name o f the c urrently ac tive windo w. Ac tually, GetActiveWindowName do esn’t repo rt the name o f the “ac tive” windo w. Instead, it returns the name o f the fo regro und windo w. This windo w do esn’t nec essarily have to have the fo c us. SendKeys always sends to the windo w in the fo regro und windo w. Turning o ff fo c us timeo ut was needed o nly to put arbitrary windo ws to the fo regro und. SendKeys do esn’t c are abo ut the fo c us.
Safely directing keystrokes to the window of your choice So , this is what a safe SendKeys wrapper might lo o k like. It sends keys to the windo w yo u spec ify and wo n’t send them to any o ther windo w. It is o nly thro ugh this wrapper that yo u c an use SendKeys in real-life sc enario s. Witho ut it, it’s muc h to o dangero us to send o ut keystro kes witho ut kno wing who rec eives them.
336
Part III: Starting and Co ntro lling Othe r So ftware
■
■
‘ 10-8.VBS set wshshell = CreateObject(“WScript.Shell”) set apptool = CreateObject(“app.activate”) timeout = 0 EnableSwitching ‘ now you are all set to safely use SendKeys! ‘ launch Editor wshshell.run “notepad.exe” ‘ wait 1 second WScript.Sleep 1000 ‘ determine name of editor: editname = apptool.GetActiveWindowName if instr(editname, “Notepad”)=0 then ‘ didn’t start! MsgBox “I tried to start the Editor. Instead, “”” & editname _ & “”” is the active window. I quit.” WScript.Quit end if ‘ list drive C:\ to editor set fs = CreateObject(“Scripting.FileSystemObject”) set folder = fs.GetFolder(“C:\”) for each file in folder.files SendKeys file.name & “{ENTER}”, editname next DisableSwitching MsgBox “Done!” sub SendKeys(keys, windowname) ‘ check whether output window is active windname = lcase(apptool.GetActiveWindowName) ‘ wrong window, switch: if not lcase(windowname)=left(windname, len(windowname)) then ok = wshshell.AppActivate(windowname) if not ok then MsgBox “Window “”” & windowname & “”” is missing!” DisableSwitching WScript.Quit end if end if wshshell.SendKeys keys, true Wscript.Sleep 100 end sub
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
337
■
■
sub EnableSwitching timeout = apptool.GetActivation apptool.SetActivation 0 end sub sub DisableSwitching apptool.SetActivation timeout end sub
The sc ript reads the fo lder’s c o ntents and sends it to yo ur edito r windo w, as sho wn by Figure 10-3.
Figure 10-3: SendKeys now s afely ins erts a complete folder lis ting into your editor w indow.
This sc ript so lves many pro blems. EnableSwitching turns o ff the fo c us lo c k so yo ur sc ript c an switc h to any windo w. GetActiveWindowName auto matic ally retrieves the name o f the c urrently ac tive windo w. This has a do uble use: After launc hing the edito r, yo ur new o utput windo w, the sc ript c an safely determine the windo w title, so yo u do n’t have to guess any lo nger o r hard-c o de a name into yo ur sc ript. Sec o ndly, the new SendKeys pro c edure c an use GetActiveWindowName to find o ut whether o r no t the right windo w is in the fo regro und. If it’s no t, it uses AppActivate to switc h to the windo w, and listens to AppActivate’s return value. If it’s false, the sc ript kno ws that the user has c lo sed the windo w, and sto ps. Try it o ut! Try switc hing the windo w while the sc ript o utputs the file list — yo u’ll find it wo n’t wo rk! The sc ript switc hes bac k immediately. Try c lo sing the o utput windo w. The sc ript detec ts the missing windo w and quits. No mo re danger o f keystro kes getting into the wro ng hands! Yo ur self-defined SendKeys pro c edure internally c alls the o ffic ial SendKeys metho d. It do es two surprising things. First, it c alls SendKeys with a sec o nd parameter: true. This lets SendKeys wait until the destinatio n windo w rec eives the keystro kes. Next, it delays the sc ript fo r 100 millisec o nds. Why? Yo ur sc ript is to o fast fo r SendKeys, and witho ut delay, so me keystro kes wo uld get lo st.
338
Part III: Starting and Co ntro lling Othe r So ftware
■
■
When remo te c o ntro lling so ftware, yo u might have to send keystro kes to many different windo ws. Maybe yo u are c alling menu c o mmands that po p up dialo g bo xes yo u need to fill o ut. Always remember to supply the c o rrec t windo w name. Use the dialo g bo x title name to send keystro kes to this windo w instead o f the applic atio n windo w.
Remote controlling menus and the Start menu The mo st impo rtant use o f SendKeys is getting ac c ess to menus and kic king dialo g bo xes o ut o f the way. SendKeys c an do anything yo u c an do with the mo use. Fo r example, yo ur sc ripts c an easily o pen and ac c ess the Start menu, c alling any o f the o ffic ial c o mmands. And bec ause these sho rtc uts do n’t relate to any windo w, yo u c an use them safely witho ut the wrapper. ‘ 10-9.VBS set wshshell = CreateObject(“WScript.Shell”) ‘ open Start Menu wshshell.SendKeys “^{ESC}” ‘ call Shutdown wshshell.SendKeys “{UP}{ENTER}” ‘ you could continue and completely shutting down windows ‘ or use any other option offered by the Shutdown screen
Why did the sc ript use {UP}{ENTER} to invo ke the Shutdo wn c o mmand? Wo uldn’t it be easier to c all it thro ugh its key c o mbinatio n? No . Key c o mbinatio ns o nly wo rk if they are unique. If yo u had inserted a c usto m Start menu entry who se name started with the same letter as the system c o mmand, the key c o mbinatio n wo uld no lo nger wo rk. In the Start menu, it’s muc h safer to use {UP} to mo ve to the system c o mmand yo u require. Still, yo u might need to adjust the sc ript if yo u have disabled so me o f the o ffic ial Start menu c o mmands. There are many hidden, yet useful, system keybo ard c o mmands yo u may want to use: ■ [Alt]+[Tab] switc hes bac k and fo rth between two windo ws. ■ [F10] ac tivates the menu bar. ■ [Shift]+[F10] ac tivates the c o ntext menu o f the c urrently selec ted item. ■ [Alt]+[Spac e] o pens the Windo ws’ system menu. ■ [Alt]+[F4] c lo ses the ac tive windo w.
When c alling menu o r c o mmand sho rtc uts, always use lo werc ase letters. If yo u send [Alt]+[F] (“%F”), the pro gram might interpret yo ur keys as [Alt]+[Shift]+[F], invo king a c o mpletely different func tio n than yo u intended.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript ■
339 ■
Shutting down all running programs After so me wo rk, the deskto p is o ften c luttered with numero us o pen windo ws, and it takes several c lic ks to c lo se them all manually. Isn’t there a way to auto mate this? Ho w c o nvenient it wo uld be to define a keystro ke that c lo ses all o pen windo ws!
Listing all running programs Yo u c an do this. Ho wever, first yo u need to invent so me metho d to enumerate the names o f all o pen windo ws. Lo ad the c o mplete pro jec t fro m the CD: \components\windowlist\windowlist.vbp. Or install the prepared pac kage: \install\windowlist\setup.exe. Option Explicit Public WindowList As String Public Public Public Public
Declare Function EnumWindows Lib “user32” (ByVal lpEnumFunc As _ Long, ByVal lParam As Long) As Long Declare Function IsWindowVisible Lib “user32” (ByVal hwnd As Long) _ As Long Declare Function GetWindowText Lib “user32” Alias _ “GetWindowTextA” (ByVal hwnd As Long, ByVal lpString As _ String, ByVal cch As Long) As Long Declare Function GetParent Lib “user32” (ByVal hwnd As Long) As Long Declare Function GetWindow Lib “user32” (ByVal hwnd As Long, _ ByVal wCmd As Long) As Long Declare Function GetWindowLong Lib “user32” Alias _ “GetWindowLongA” (ByVal hwnd As Long, ByVal nIndex _ As Long) As Long Private Function EnumWindowsCallBack(ByVal hwnd As Long, _ ByVal lParam As Long) As Long Dim lReturn As Long Dim lExStyle As Long Dim bNoOwner As Boolean Dim sWindowText As String If IsWindowVisible(hwnd) Then If GetParent(hwnd) = 0 Then bNoOwner = (GetWindow(hwnd, GW_OWNER) = 0) lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE) If (((lExStyle And WS_EX_TOOLWINDOW) = 0) And bNoOwner) _ Or ((lExStyle And WS_EX_APPWINDOW) _
340
Part III: Starting and Co ntro lling Othe r So ftware
■
■
And Not bNoOwner) Then sWindowText = Space$(256) lReturn = GetWindowText(hwnd, sWindowText, _ Len(sWindowText)) If lReturn Then WindowList = WindowList & Left$(sWindowText, _ lReturn) & vbCrLf End If End If End If End If EnumWindowsCallBack = True End Function Public Function EnumWin() As String Dim hwnd As Long WindowList = “” Call EnumWindows(AddressOf EnumWindowsCallBack, hwnd) If Len(WindowList) > 1 Then WindowList = Left(WindowList, Len(WindowList) - 2) End If EnumWin = WindowList End Function
To ac hieve yo ur go al, yo u need to dive deeply into the Windo ws API mec hanic s. First o f all, yo u c an’t write this c o de in the c o de segment o f yo ur COM User Co ntro l. It wo uldn’t wo rk. Instead, yo u need to c reate a separate c o de mo dule: In the VB CCE Pro jec t windo w, right-c lic k yo ur pro jec t and c ho o se Add and Mo dule. This c o de uses c allbac k func tio ns. Callbac k func tio ns are self-defined func tio ns that are passed to so me Windo ws API func tio n. The API func tio n then c alls yo ur c allbac k func tio n many times, mo stly in c o njunc tio n with so me enumeratio n pro c ess. To be able to pass a VisualBasic func tio n suc h as Callback, yo u need to pass its memo ry address. Fo rtunately, VisualBasic spo rts the AddressOf o perato r. Ho wever, this o perato r wo n’t wo rk in User Co ntro ls. Yo u need to use it in separate c o de mo dules.
EnumWin is the main func tio n yo u need to c all to get a list o f all the running windo ws. The real wo rk is do ne by EnumWindows, a sec ret API func tio n. It asks fo r the name o f so me c allbac k func tio n and then c alls this func tio n fo r every windo w c urrently defined. Yo ur c allbac k func tio n EnumWindowsCallback has the jo b o f dealing with any windo w passed by EnumWindows. So , the Windo ws API func tio n just enumerates the windo ws but leaves it to yo ur c allbac k func tio n to figure o ut whether yo u find the partic ular windo w interesting o r no t. Chapter 12 reveals all the details abo ut the many system windo ws and ho w to trac k them do wn.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
341
■
■
This is hard wo rk. Windo ws c o nsists o f hundreds, if no t tho usands, o f windo ws, even if yo u c an see o nly a handful. Take a lo o k at yo ur task bar: A separate windo w displays eac h butto n, inc luding the start butto n, and yo u o bvio usly do n’t want to enumerate all o f these internal windo ws. This is why yo ur c allbac k func tio n do es a lo t o f filtering. First o f all, it so rts o ut invisible windo ws. Next, it so rts o ut any windo w that is part o f a parent windo w, eliminating c hild windo ws. Finally, it filters o ut any windo ws that are neither applic atio n no r to o lbo x windo ws, and it also rejec ts windo ws that are o wned by ano ther windo w. The results are the true main windo ws yo u see o n yo ur sc reen. Yo ur c o de wo rks all right, but ho w c an yo ur sc ripts ac c ess it? Define this little func tio n in the User Co ntro l part o f yo ur COM o bjec t: Public Function ListWindows() As String ListWindows = EnumWin End Function
No w yo u are all set. The next sc ript enumerates all c urrently running windo w titles, and Figure 10-4 sho ws a sample result: ‘ 10-10.VBS set tool = CreateObject(“Window.List”) MsgBox tool.ListWindows
Figure 10-4: Automatically find out names of all open w indow s .
Sending a “close” command to running programs No w it’s easy to AppActivate eac h windo w in the list and tell it to c lo se do wn: ‘ 10-11.VBS set wshshell = CreateObject(“WScript.Shell”) set apptool = CreateObject(“app.activate”) set tool = CreateObject(“Window.List”) timeout = 0
342
Part III: Starting and Co ntro lling Othe r So ftware
■
■
list = tool.ListWindows list = Split(list, vbCrLf) EnableSwitching for each window in list ok = wshshell.AppActivate(window) if ok then wshshell.SendKeys(“%{F4}”) else MsgBox “Can’t switch to “”” & window & “””!” end if next DisableSwitching wshshell.Popup “Done closing windows.”, 1 sub EnableSwitching timeout = apptool.GetActivation apptool.SetActivation 0 end sub sub DisableSwitching apptool.SetActivation timeout end sub
Yo u c o uld easily filter the windo w names returned by ListWindows to inc lude o nly spec ial windo ws. Fo r example, use Scripting.FileSystem Object FileExists and FolderExists to see whether a windo w title represents a file o r fo lder, and c lo se just the Explo rer windo ws.
Closing down specific applications Yo ur sc ript wo rks all right at this po int, but it’s no t very selec tive. It c lo ses do wn any windo w visible o n sc reen. Maybe yo u are a pro grammer and wo rk with a lo t o f edito r windo ws. Every o nc e in a while, yo u wo uld like to hit a key and c lo se all edito r windo ws. But, is it po ssible to just shut do wn the edito r windo ws and no thing else? Yes! Ho wever, it requires even mo re API artistry. Unfo rtunately, Windo ws 9.x and Windo ws NT/ 2000 use a c o mpletely different appro ac h in finding o ut the exec utable name behind a windo w. I have designed a little variatio n o f the COM o bjec t yo u c reated abo ve. It no t o nly returns the windo w names but also the path names o f the exec utables running the windo w. The COM o bjec t wo rks bo th o n NT and 9.x bec ause it inc o rpo rates bo th ways o f retrieving the .exe name. Bec ause spac e is sc arc e, I dec ided no t to print the listing. Yo u’ll find the c o mplete so urc e c o de o n the CD: \components\windowlist2\winlist2.vbp. To be able to use the o bjec t, either c o mpile the pro jec t yo urself o r install the prepared pac kage: \install\windowlist2\setup.exe.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
343
■
■
Take a lo o k what yo ur new o bjec t do es (Figure 10-5 gives a quic k preview): ‘ 10-12.VBS set tool = CreateObject(“window.list2”) MsgBox tool.ListWindows
Figure 10-5: Find out the executable names w orking ins ide the open w indow s . This time, the metho d lists bo th the windo w name and the exec utable path. It uses a vbTab as delimiter. No w it’s easy to c reate a mo re selec tive c lo se-do wn sc ript. The fo llo wing sc ript c lo ses do wn the edito r o nly — all o ther windo ws remain intac t. It’s just a slightly enhanc ed versio n o f the previo us sc ript and demo nstrates ho w to separate windo w name and exec utable path using Split. ‘ 10-13.VBS ‘ specify which program you want to close down: closedown = “notepad.exe” set wshshell = CreateObject(“WScript.Shell”) set apptool = CreateObject(“app.activate”) set tool = CreateObject(“Window.List2”) timeout = 0 list = tool.ListWIndows list = Split(list, vbCrLf) EnableSwitching for each windowinfo in list infofield = Split(windowinfo, vbTab) window = infofield(0) exec = lcase(infofield(1)) exec = mid(exec, InstrRev(exec,”\”)+1) if exec = closedown then ok = wshshell.AppActivate(window) if ok then wshshell.SendKeys(“%{F4}”) else
344
Part III: Starting and Co ntro lling Othe r So ftware
■
■
MsgBox “Can’t switch to “”” & window & “””!” end if end if next DisableSwitching wshshell.Popup “Done closing windows.”, 1 sub EnableSwitching timeout = apptool.GetActivation apptool.SetActivation 0 end sub sub DisableSwitching apptool.SetActivation timeout end sub
Executing DOS Commands DOS c o mmands may be o utdated, but they are still there. And fo r so me tasks, DOS c o mmands are still a reaso nable alternative. I’ll leave it up to yo u to c ho o se whic h DOS c o mmands may be useful. In this part, I fo c us o n ho w to c all DOS c o mmands, and ho w to retrieve their results.
Feeding DOS commands to the interpreter DOS c o mmands are no t separate pro gram files. Do n’t c o nfuse them with DOS pro grams. Yo u c an launc h DOS pro grams the same way yo u launc h Windo ws pro grams, using the Run metho d. But ho w do yo u launc h a DOS c o mmand like DIR? There’s no DIR.EXE o r DIR.COM yo ur sc ript c o uld c all. All the internal DOS c o mmands are part o f COMMAND.COM, the DOS c o mmand interpreter. Yo u just need to feed the c o mmands yo u want to exec ute to this interpreter, and they will be exec uted. Easy. Yo u do n’t even have to kno w the exac t lo c atio n o f COMMAND.COM. The enviro nment variable %COMSPEC% reveals its internal name. On Windo ws NT/ 2000, the DOS c o mmand interpreter is still there. Here, it’s c alled CMD.EXE. Yo u do n’t need to wo rry abo ut the name, bec ause %COMSPEC% always c o ntains the path name to the DOS interpreter no matter where it’s sto red and no matter what it’s c alled. So , to list the direc to ry o f drive C:\, use the fo llo wing sc ript: ‘ 10-14.VBS set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “%COMSPEC% /k dir c:\”
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
345
■
■
Maybe yo u wo nder what the /k o ptio n do es. It’s the flag that makes the interpreter exec ute the fo llo wing c o mmand. Witho ut this o ptio n, yo u’d just get an empty DOS bo x.
/k isn’t the o nly po ssible flag. It’s useful o nly if yo u want to o pen a DOS windo w and keep it o pen. Mo st o f the time, this is no t what yo u want. Yo ur sc ripts just want to launc h a DOS c o mmand witho ut any spec tac ular windo w, and mo st impo rtantly, witho ut user interventio n. To c lo se the DOS windo w o nc e yo ur c o mmand is finished, use /c instead o f /k.
Reading in the DOS command results If yo u used /c in the example abo ve, yo u wo n’t have muc h fun. The DOS interpreter wo uld o pen the DOS windo w, exec ute the DIR c o mmand, and c lo se the windo w within a matter o f sec o nds. Yo u need a way to transfer the result into yo ur sc ripts.Take a lo o k at the fo llo wing sc ript — it sho ws ho w to sto re the result and read it into yo ur sc ript (see Figure 10-6): ‘ 10-15.VBS set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”) outputfile = “C:\TEMP.TXT” command = “%COMSPEC% /c dir c:\ > “ & outputfile ‘ wait for the command to finish result = wshshell.Run(command,,true) ‘ read in result set file = fs.OpenTextFile(outputfile) text = file.ReadAll file.close wshshell.Popup text
During this pro c ess, the DOS windo w may flash up. This may be a little anno ying, and yo u c an keep it hidden by using 0 as windo w style (use 0 as sec o nd parameter fo r Run). It wo uldn’t be very wise, tho ugh. DOS may direc t questio ns o r erro r messages at yo u, and if yo u hide the DOS windo w, yo u’d never kno w and wo nder why yo ur sc ript appears to hang. Hide windo ws o nly if yo u must, and o nly o nc e yo u have tested yo ur DOS c o mmand many times and are c o nvinc ed that it do esn’t require user interac tio n. Ho w did yo ur sc ript get ac c ess to the DOS c o mmand’s o utput? Easy: Yo u redirec ted the o utput into a text file. This is what the > o perato r did. In additio n, the Run metho d used sync hro no us c alling (third parameter is set to true), so yo ur sc ript waits fo r the DOS c o mmand to c o mplete the o utput file. Next, it c an ac c ess the o utput file and read in whatever the DOS c o mmand has left behind.
346
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Figure 10-6: Read in the res ults of DOS commands . DOS and Windo ws are two c o mpletely different wo rlds. DOS uses the o ld ASCII text c o de, while Windo ws stic ks to its ANSI text c o de. Yo u wo n’t no tic e the differenc e until yo u read spec ial c harac ters. All c harac ter c o des abo ve 128 are handled differently by these two sc hemes, and when reading in DOS results, spec ial c harac ters may lo o k garbled. Yo u c an, ho wever, use Replace and replac e all spec ial c harac ters with the ANSI equivalent.
Feeding answer files to DOS commands So me DOS c o mmands wo n’t wo rk witho ut user interac tio n. They require the user to press Y o r so me o ther key befo re they take ac tio n. Ho w c an yo u auto mate that? Yo u already kno w the answer! Just pro vide an answer file. Answer files are plain text files, and eac h line represents the answer to o ne questio n. This means yo u c an redirec t input to DOS c o mmands in exac tly the same way yo u redirec ted o utput. Use < this time. Fo r example, to fo rmat the disk drive o n Windo ws 9.x, yo u c an use this sc ript: ‘ 10-16.VBS if FormatDisk(“Disk1”) then MsgBox “Done formatting!” else MsgBox “You interrupted the formatting process...” end if function FormatDisk(name) set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”)
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
347
■
■
‘ exchange with different drive letter if necessary: set drive = fs.GetDrive(“A:”) do until drive.isReady or result=vbCancel result = MsgBox(“Please insert disk to be formatted “ _ & “ in drive A:\. Caution: disk will be completely” _ & “ erased!”, vbOkCancel) loop if result = vbCancel then FormatDisk = false exit function end if ‘ prepare answers answerfile = “c:\answers.txt” set answers = fs.CreateTextFile(answerfile, true) answers.WriteLine ‘ ENTER answers.WriteLine left(name,11) ‘ Disk name answers.WriteLine “N” ‘ N: no more disks answers.close ‘ execute DOS command and feed answers ‘ replace 1 with 0 to hide DOS window result = wshshell.Run(“%COMSPEC% /C FORMAT A: < “ _ & answerfile,1,true) FormatDisk = true end function
Again, it’s a little risky to let the DOS c o mmand run in a hidden windo w. What if the disk c o ntains a media erro r, o r so meo ne takes it o ut o f the drive? Yo u’d never see any DOS erro r messages, so the safe appro ac h is to leave the DOS windo w visible.
Launching Control Panel Items Ever wo ndered where all the Co ntro l Panel items live? They are individual files, and yo u c an bring up any Co ntro l Panel item direc tly. A sc ript c an pro mpt the user to c hange so me setting and have the appro priate item po p up right away. Co ntro l Panel items have so mething in c o mmo n with DOS c o mmands. They are no t exec utables, so yo u c an’t launc h them direc tly. Instead, yo u have to feed them to a spec ial DLL func tio n.
Where do Control Panel items live? Co ntro l Panel items are individual files. Co mmo nly, they share the CPL file extensio n, but DLL files c an ac t as Co ntro l Panel items, to o . Let’s do a little searc h! Searc h fo r *.CPL and see what yo u get! Eac h o f the files the searc h func tio n finds c o ntains o ne o r mo re Co ntro l Panel items. Ho w do yo u c all them?
348
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Executing Control Panel items Windo ws c o ntains a spec ial API func tio n c alled Control_RunDLL. This func tio n exec utes CPL files. Fo rtunately, yo u do n’t need to ac c ess this API func tio n direc tly. There’s a sho rtc ut. It’s c alled CONTROL.EXE. This pro gram “wraps” the API func tio n fo r yo u and sends the CPL file to shell32.dll. Try it o ut! Cho o se Run fro m yo ur Start menu and enter this c o mmand: CONTROL main.cpl. It wo rks: The main Co ntro l Panel mo dule appears. Bec ause CONTROL.EXE is an exec utable, yo u no w kno w all that’s needed to c all any Co ntro l Panel applet via sc ript. But there’s mo re. Clo se the mo use dialo g bo x and enter this c o mmand: CONTROL main.cpl,@1. Do n’t insert spac es befo re o r after the c o mma. This time, the keybo ard dialo g bo x po ps up. Main.cpl c o ntains mo re than o ne Co ntro l Panel applet, and yo u c an c ho o se the o ne yo u need. Always c lo se Co ntro l Panel applets befo re yo u try to o pen ano ther o ne. Windo ws may no t be able to o pen the new o ne as lo ng as the o ld o ne is still visible. Yo u c an even preselec t individual tabs. CONTROL main.cpl,@1,1 o pens the keybo ard dialo g bo x and selec ts the sec o nd tab (tabs start with index 0). Next, c hec k o ut the o ther .cpl files yo ur searc h has listed. No te that no t every Co ntro l Panel applet suppo rts tab preselec tio n, tho ugh. Yo u’ll find many useful sho rtc uts to impo rtant system dialo g bo xes. Fo r example, try CONTROL sysdm.cpl,,2. The result may vary, depending o n yo ur Windo ws versio n (see Figure 10-7).
Figure 10-7: Open Control Panel applets and pres elect a tab.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
349
■
■
‘ 10-17.VBS set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “CONTROL.EXE sysdm.cpl,,2”
Yo u c an’t c all CONTROL.EXE sync hro no usly; in o ther wo rds, yo u c an’t make yo ur sc ript wait fo r the Co ntro l Panel dialo g bo x to be c lo sed again. Remember: CONTROL.EXE passes c o ntro l to shell32.dll o nly. It will exit immediately after it has fed the CPL file to the API func tio n.
Accessing Software Through CreateObject Ac tually, yo u have launc hed and c o ntro lled external so ftware thro ugho ut this bo o k. Eac h and every c all to CreateObject has ac c essed so me external so ftware and bo rro wed so me o f its func tio nality. So far, ho wever, yo u have wo rked with simple “in-pro c ess” COM o bjec ts mo st o f the time. Mo st mo dern so ftware pac kages use a mo dular design. They sto re their spec ial func tio nality in separate COM mo dules. This makes it muc h easier fo r the so ftware vendo r to design add-o ns and re-use func tio ns already pro vided by so me c o mpo nent. There are also pirates waiting to explo it this vast amo unt o f so ftware po wer, to o — yo ur sc ripts! Ac c identally, the mo dular design allo ws yo ur o wn sc ripts to also ac c ess any spec ial func tio n a so ftware pac kage may have to o ffer — even if the so ftware vendo r wo uld have muc h rather kept these func tio ns to its o wn c o mpo nents. The o nly way so ftware vendo rs c an prevent third-party users fro m explo iting their so ftware is to no t do c ument the metho ds and pro perties. Witho ut a name and arguments list, yo u wo n’t be able to c all any external func tio n. Ac tually, a so ftware vendo r wo uld just have to get rid o f the IDispatch interfac e to prevent sc ript ac c ess, and, in fac t, simple so ftware pac kages o ften lac k this interfac e. IDispatc h is the sec ret bac k do o r thro ugh whic h sc ripts c an ac c ess the internal components. Ho wever, mac ro languages bec o me inc reasingly impo rtant fo r any so ftware vendo r. Any so ftware that wants to be c o mpatible with VisualBasic fo r Applic atio ns o r any o ther latebo und sc ript language needs IDispatch and invo luntarily gives yo ur sc ripts ac c ess to all o f its func tio ns Fo rtunately, mo st so ftware pac kages c o me with a hidden TypeLibrary, and yo u have already fo und many ways to peek into these info rmatio n files. They pro vide yo u with all the info rmatio n needed.
Remote controlling Microsoft Word Take a lo o k at MS Wo rd (WinWo rd). It c o mes as part o f Mic ro so ft Offic e, and bec ause it’s o ne o f the leading o ffic e so ftware suites, yo u’ll find it installed o n many c o mputers.
350
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Ho w do yo u ac c ess its internal metho ds? First, yo u need to find o ut its TypeLibrary. Mo st likely, the TypeLibrary is sto red in the same fo lder as the exec utable. So searc h fo r Winwo rd.exe and write do wn the fo lder name. Next, use the fo llo wing helper sc ript. It c hec ks all files in the fo lder yo u spec ify and returns a list o f all files that c o ntain TypeLibrary info rmatio n. Yo u get a result similar to the o ne sho wn in Figure 10-8.
Figure 10-8: Automatically s earch a folder for TypeLibrary information. To use this and the subsequent sc ripts, yo u need to install the TypeLibrary helper to o ls if yo u haven’t do ne so already: \install\typelib\setup.exe. ‘ 10-18.VBS searchfolder = inputBox(“Enter folder path to search!”) set tool = CreateObject(“typelib.decoder”) set fs = CreateObject(“Scripting.FileSystemObject”) if not fs.FolderExists(searchfolder) then MsgBox “””” & searchfolder & “”” does not exist!” WScript.Quit end if set folder = fs.GetFolder(searchfolder) list = “Found TypeLibs in “ & searchfolder & “ :” & vbCr & vbCr for each file in folder.files
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript ■
351 ■
if tool.isTypeLib(file.path) then list = list & file.name & vbCr end if next MsgBox list
The list o f filenames gives a go o d c lue whic h file is respo nsible fo r yo ur exec utable. Mic ro so ft Wo rd 2000, fo r example, sto res its TypeLibrary in a file c alled MSWORD9.OLB. To view all the internal metho ds, launc h sc ript 5-12 and pro vide it with the full path name o f the file. It will extrac t all the TypeLibrary info rmatio n into yo ur do c umentatio n fo lder (see Chapter 5 fo r details) and will o ffer to o pen the fo lder fo r yo u. In the Wo rd subfo lder, yo u no w find a vast number o f info rmatio n files (see Figure 10-9). Yo u might even feel slightly o verwhelmed. In a minute, tho ugh, yo u kno w exac tly where to start yo ur searc h.
Figure 10-9: Add the WinWord documentation to your documentation folder.
Accessing the Word spell-checker To ac c ess so ftware thro ugh IDispatch, yo u need to kno w its Pro gID. In Chapter 3, yo u c reated a list o f all available Pro gIDs. To ac c ess MS Wo rd, fo r example, use Word.Application: ‘ 10-19.VBS set word = CreateObject(“Word.Application”) MsgBox TypeName(word)
352
Part III: Starting and Co ntro lling Othe r So ftware
■
■
These lines establish a c o nnec tio n to yo ur o bjec t and return the name o f the o bjec t yo u rec eived. It’s Applic atio n. Switc h bac k to yo ur do c umentatio n fo lder and searc h fo r a file c alled Applic atio n. There it is — o pen Applic atio n.htm. A searc h fo r “spelling” quic kly brings GetSpellingSuggestions to yo ur attentio n. All right! So ho w do yo u c hec k the spelling o f so me wo rds? Here’s an example: ‘ 10-20.VBS set word = CreateObject(“Word.Application”) word.documents.Add checkword = InputBox(“Enter a word, and I check the spelling!”) set suggestions = word.GetSpellingSuggestions(checkword) if suggestions.Count = 0 then MsgBox “I have no alternatives for you...” else list = “I’ve some suggestions for “”” & checkword & “””:” & vbCr for each suggestion in suggestions list = list & suggestion & vbCr next MsgBox list end if word.Quit
It really wo rks: Yo ur sc ript c hec ks the spelling with the help o f WinWo rd and gives spelling suggestio ns (see Figure 10-10).
Figure 10-10: Your s elf-made documentation contains all the method des criptions needed.
Chapte r 1 0 : Launc hing Any Pro gram By Sc ript
353
■
■
To be able to use the metho ds o f yo ur WinWo rd o bjec t, yo u need to initialize it. Word.documents.Add adds a blank new do c ument. Witho ut a do c ument, Wo rd wo n’t allo w yo u to use its metho ds bec ause it thinks yo u are a so ftware pirate. Fo o l WinWo rd in thinking yo ur requests c o me fro m so me do c ument mac ro . Do n’t fo rget to c lo se WinWo rd after use: Even if WinWo rd remains invisible, it’s still there and will o therwise c lutter yo ur memo ry spac e.
A whole new universe . . . At this po int, yo u pro bably have a go o d feeling fo r the millio ns o f new and exc iting func tio ns yo ur sc ripts c an use. Yo u c an even get detailed info rmatio n abo ut all the metho ds and pro perties yo ur do c umentatio n has revealed. Visit msdn.microsoft.com/library to take a lo o k into the huge MS tec hnic al library. It c o ntains the c o mplete MS Offic e referenc e fo r free. And searc h the entire Internet fo r metho d names yo u find interesting! Chanc es are great yo u will find many useful examples and c o mments o n tric ks and o ther undo c umented implic atio ns. Finally, do n’t fo rget that TypeLibraries and IDispatch are general c o nc epts. They no t o nly apply to MS Offic e. Chec k o ut yo ur favo rite drawing pro gram like Co rel Draw, and yo u will disc o ver all kinds o f handy graphic s func tio ns and c o nverting algo rithms. It’s a who le new universe, and with this kno wledge, yo ur sc ripts c an finally ac t as so ftware glue — pic king o ut the best and mo st po werful func tio ns fro m existing so ftware pac kages to c reate yo ur very o wn (and very free) perso nal so ftware so lutio ns.
Summary This c hapter is full o f po werful new metho ds and tric ks that yo u c an use to explo it the spec ial c apabilities o f external pro grams. First, yo u learned ho w to run external pro grams and safely send keystro kes to c o ntro l them. Yo u fo und a dependable way to switc h any windo w to the fo regro und, and yo u also fo und that running many pro grams c o nsec utively builds the basis fo r maintenanc e to o ls and true batc h file replac ements. New sc ript extensio ns allo w yo u to determine the names o f all o pen windo ws and c lo se them all do wn at o nc e. Yo u c an no w launc h DOS c o mmands and Co ntro l Panel applets. Mo st impo rtantly, yo u kno w ho w to ho o k into mo dern so ftware and use its internal func tio nality fo r yo ur o wn purpo ses.
Chapte r 1 1
Controlling Running Software In This Chapter 䊳 Learn ho w Pro c essIDs identify running tasks 䊳 Clo se any running pro gram entirely by sc ript 䊳 Find o ut the individual mo dule names within a pro gram 䊳 Find o ut the Windo ws versio n yo u are c urrently running 䊳 Enumerate all running pro c esses 䊳 Mo nito r running pro grams and find o ut when they are c lo sed
I
n this c hapter, yo u gain many new metho ds to c o ntro l running pro c esses. Amo ng the mo st impo rtant enhanc ements are yo ur new ability to determine whether a spec ific pro gram is running and metho ds to end pro grams anytime.
Controlling Software Through ProcessIDs Pro c essIDs are internal handles to all running pro c esses. Whenever yo u use the Run metho d intro duc ed in the last c hapter, yo u ac tually wo rk with Pro c essIDs. Ho wever, Run hides the Pro c essIDs fro m yo u. This may be c o nvenient at the beginning, but so o n it bec o mes a majo r o bstac le. Kno wing the Pro c essID is very useful. It allo ws yo u to detec t whether a pro gram is (still) running. It allo ws yo u to switc h to a spec ific pro gram windo w, and yo u c an remo tely shut do wn an applic atio n, to o .
Accessing ProcessIDs directly Bec ause the Run metho d wo n’t tell yo u the Pro c essID o f so ftware it launc hes, yo u are muc h better o ff designing yo ur o wn Run metho d. This way, yo u are free to return any info rmatio n yo u find valuable, inc luding the Pro c essID. I have designed a COM o bjec t fo r yo u that o ffers no t o nly an advanc ed Run metho d, but also a small armada o f helper func tio ns. They allo w yo u to examine the state o f an applic atio n and to c lo se it do wn any time.
356
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Full so urc e c o de is pro vided o n the c o mpanio n CD, at \components\ process\process.vbp. Make sure yo u either c o mpile it o r install the COM o bjec t using the prepared pac kage: install\process\setup.exe. This is all yo u need to launc h a pro gram, retrieve its Pro c essID, and c lo se it do wn any time yo u please: ‘ 11-1.VBS set tool = CreateObject(“process.id”) procID = tool.Run(“NOTEPAD.EXE”) MsgBox “I have started the editor and will close it in a second!” _ & “ This is possible because I know its ProcessID: “ _ & procID, vbSystemModal tool.EndProcess procID MsgBox “The editor is gone!”
The Run metho d launc hes the pro gram async hro no usly and returns the Pro c essID. With its help, yo u c an no w c lo sely mo nito r yo ur applic atio n. EndProcess shuts do wn the applic atio n.
Closing applications under all circumstances EndProcess is yo ur “nic e” way o f c lo sing do wn pro grams. EndProcess merely whispers “please shut do wn” to yo ur pro gram. It c an’t guarantee that the pro gram really c lo ses do wn. Yo ur pro gram may o pen a Save As dialo g bo x instead and wait indefinitely fo r yo u to answer it. So , no w that yo u kno w the ProcessID, it’s up to yo u what the pro gram do es. KillProcess is yo ur deadly weapo n. It kills the pro gram no matter what (see Figure 11-1). Use KillProcess with c are! Killing a pro c ess will guarantee that it c lo ses do wn. Ho wever, the pro gram has no time to save any unsaved c hanges. Even wo rse, if the pro gram has o pened external DLLs, killing a pro c ess wo n’t allo w the pro c ess to dec rement the DLL c o unter. The DLL may therefo re stay in memo ry altho ugh it’s no t in use anymo re. Use KillProcess o nly if yo u must. The next sc ript demo nstrates ho w to use KillProcess. The sc ript first tries to c lo se do wn the pro gram the “nic e” way. It uses a new sec o nd argument, spec ifying a time interval (in millisec o nds). If the pro gram do esn’t c lo se do wn within this time frame, EndProcess returns false, indic ating the failure.
Chapte r 1 1 : Co ntro lling Running So ftware ■
357 ■
Figure 11-1: Your s cript can clos e programs even if they refus e to quit. Yo ur sc ript info rms yo u and asks fo r permissio n to c lo se the pro gram the hard way, as sho wn by Figure 11-1. If yo u agree, KillProcess will terminate the pro gram fo r sure. ‘ 11-2.VBS set proc = CreateObject(“process.id”) pid = proc.Run(“NOTEPAD.EXE”) MsgBox “I started the editor and will close it down in a second”, _ vbSystemModal if not proc.EndProcess(pid, 5000) then answer = MsgBox(“The program refuses to quit. Kill it?”, _ vbYesNo + vbQuestion) if answer = vbYes then proc.KillProcess(pid) end if end if
To test this sc ript, o nc e the edito r appears, type in so me c harac ters. Then c lic k OK. The sc ript will leave yo u five sec o nds to answer the Save As dialo g bo x. If the windo w is still o pen after this time perio d, the sc ript gets nervo us and asks whether yo u want to kill the pro gram. If yo u agree, it c lo ses the edito r using KillProcess. The Save As dialo g bo x disappears, and all unsaved info rmatio n is lo st.
Closely monitoring a program The o ffic ial Run metho d allo ws yo u to launc h a pro gram and wait fo r it to finish. This c an be o f great help, but it halts yo ur sc ript while the external pro gram is exec uted. What if the external pro gram do esn’t respo nd? What if it takes a lo ng time to exec ute? Bec ause yo ur sc ript has passed all c o ntro l to the external pro gram, it’s helpless and c an’t interrupt the running pro gram. A muc h better appro ac h wo uld be so me message indic ating whether o r no t a pro gram is still running. This way, it wo uld be up to yo ur sc ript to dec ide whether o r no t the external pro gram sho uld be interrupted. In fac t, the fo llo wing sc ript illustrates the general c o nc ept o f running external so ftware with a timeo ut. In additio n, yo ur new metho ds c o uld also determine the amo unt o f time a pro gram o r to o l needs to c o mplete so me task.
358
Part III: Starting and Co ntro lling Othe r So ftware
■
■
The next sc ript launc hes the edito r and grants yo u 10 sec o nds to enter so mething. Onc e the time is up, the sc ript c lo ses the edito r (see Figure 11-2). ‘ 11-3.VBS set tool = CreateObject(“process.id”) MsgBox “You have 10 seconds to enter something...” pid = tool.Run(“NOTEPAD.EXE”) ‘ wait for program to exit - check every second do WScript.Sleep 1000 ‘ sleep 1 sec counter = counter + 1 ‘ exit after 10 secs or once program closed down loop while counter60 then response = MsgBox(“Program is still running. “ _ & “Do you want to close it down?”, vbYesNo) if response = vbNo then ‘ reset counter counter = 0 end if end if loop until counter>60 or tool.isTaskRunning(pid)=false ‘ still running? if tool.isTaskRunning(pid) then
360
Part III: Starting and Co ntro lling Othe r So ftware
■
■
tool.EndProcess(pid) end if MsgBox “Done!”
Closing external programs So far, yo ur EndProcess and KillProcess metho ds are o nly able to c lo se pro grams yo u launc h. Use EndProgram and KillProgram to end o r kill any windo w. Instead o f a ProcessID, this time yo u spec ify the exac t windo w name. The metho ds require yo u to spec ify the windo w title exac tly as it appears in the windo w title bar. Explo rer windo ws are different: They are run by a c entral Explo rer instanc e and c an’t be c lo sed do wn using yo ur new metho ds. To c lo se do wn Explo rer windo ws, use the SendKeys alternative desc ribed abo ve. ‘ 11-6.VBS ‘ closes down window “Document1 – Microsoft Word” set tool = CreateObject(“process.id”) tool.EndProgram(“Document1 - Microsoft Word”)
The metho d returns true if the windo w c an be c lo sed. Yo u c an even spec ify a timeo ut and leave the windo w so me time to display its Save As dialo g bo x. The next sc ript c lo ses do wn the same windo w and waits fo r a maximum o f 10 sec o nds. If the windo w isn’t c lo sed within this time frame, the metho d returns false. Yo ur sc ript c an then use KillProgram to kill the pro gram fo rc efully. ‘ 11-7.VBS ‘ closes down window “Document1 - Microsoft Word” set tool = CreateObject(“process.id”) windowname = “Document1 - Microsoft Word” closed = tool.EndProgram(windowname, 10000) if not closed then result = MsgBox(“Window didn’t close - use the force?”, vbYesNo) if result = vbYes then tool.KillProgram(windowname) end if else MsgBox “Window has been closed.” end if
Splitting Programs into Modules Pro grams are no t mo no lithic blo c ks. Instead, they c o nsist o f a number o f partic ipating mo dules. Maybe yo u have tried to c o py a pro gram file to ano ther c o mputer just to disc o ver that it wo n’t run. No wo nder: Mo st pro grams require a lo t o f c o llabo rating staff in the bac kgro und, and o nly installing a so ftware with its install utility will c o py tho se files to yo ur c o mputer.
Chapte r 1 1 : Co ntro lling Running So ftware
361
■
■
It’s easy to break up a running pro gram into all o f its mo dules. First, yo u need to get ac c ess to the pro gram’s ProcessID. Next, yo u c an find o ut whic h mo dules are c o nnec ted to this pro c ess. All o f the dirty wo rk is do ne by ano ther COM o bjec t I have designed fo r yo u. Either use it as is, o r take a lo o k at its design! It’s very interesting bec ause Windo ws NT uses a c o mpletely different set o f APIs inside psapi.dll. Windo ws 9.x uses a muc h mo re advanc ed tec hnique hidden in kernel32.dll, whic h is no t available to Windo ws NT. Windo ws 2000 inc ludes bo th tec hniques. It’s no t trivial to examine running tasks. After all, in a multitasking enviro nment, yo u never kno w when a task quits. So , during examinatio n, the running tasks may vary. With Windo ws 95, Mic ro so ft has intro duc ed a new “snapsho t” tec hnique: It takes a system snapsho t and allo ws yo u to examine this snapsho t no matter what yo ur tasks do in the meantime. This appro ac h wo rked so well that Mic ro so ft built it into Windo ws 2000, to o . On Windo ws NT, in c o ntrast, yo u need to bro wse thro ugh the ac tual running tasks. The COM o bjec t I designed inc ludes bo th tec hniques. It wo rks o n all Windo ws versio ns. Make sure yo u either c o mpile the COM o bjec t yo urself, using \components\ spy\spy.vbp, o r install the prepared so ftware pac kage: \install\spy\ setup.exe.
Which Windows version is running? As o utlined abo ve, it depends o n the Windo ws versio n yo u are running whic h appro ac h to take. So , the first task is to find o ut whic h versio n yo u are using. As a servic e, the COM o bjec t makes these metho ds public ly available, so yo u c an use them fo r all kinds o f purpo ses (see Figure 11-3): ‘ 11-8.VBS set tool = CreateObject(“module.spy”) if tool.isNTKernel then MsgBox “You are running on NT Kernel!” else MsgBox “You are running Windows 95/98!” end if if tool.isModernWin then MsgBox “You are running Win9x or Windows 2000!” else MsgBox “You are running Windows NT” end if
362
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Figure 11-3: Find out w hich Window s vers ion currently is running.
Enumerating running processes Ever wo ndered whic h pro c esses are c urrently running o n yo ur mac hine? The next sc ript has the answer, and yo u’ll get a result similar to the o ne sho wn in Figure 11-4: ‘ 11-9.VBS set tool = CreateObject(“module.spy”) list = tool.ListProcesses MsgBox “Currently running:” & vbCr & vbCr & list
Figure 11-4: Enumerate all running proces s es . No w it’s easy to find o ut whether o r no t a spec ific pro gram is c urrently running: ‘ 11-10.VBS set tool = CreateObject(“module.spy”) list = tool.ListProcesses if Instr(1, list, “\notepad.exe”, 1)=0 then
Chapte r 1 1 : Co ntro lling Running So ftware
363
■
■
MsgBox “Notepad editor is NOT running.” else MsgBox “Notepad editor IS running.” end if
No te the use o f Instr. The sc ript uses it with all po ssible o ptio ns and asks fo r a textual c o mpariso n (fo rth argument set to 1). This is nec essary in o rder to use c ase-independent c o mpariso n. Yo u c an even c hec k ho w many instanc es o f so me pro gram are c urrently running (see Figure 11-5): ‘ 11-11.VBS set tool = CreateObject(“module.spy”) list = tool.ListProcesses start = 1 do pos = Instr(start, list, “\notepad.exe”, 1) if pos>0 then prgcount = prgcount + 1 start = pos+1 end if loop until pos=0 MsgBox “Notepad editor currently runs “ & prgcount & “ times.”
Figure 11-5: Determine how many ins tances of a s pecific program are running at the s ame time.
Listing program modules To find o ut the internal mo dules a pro gram c o nsists o f, use ModuleList. The fo llo wing example o pens an edito r windo w and uses the resulting Pro c essID to enumerate its mo dules. Figure 11-6 sho ws a sample result. ‘ 11-12.VBS set proc = CreateObject(“process.id”) set spy = CreateObject(“module.spy”) ‘ start editor pid = proc.Run(“NOTEPAD.EXE”) ‘ wait for Program to be launched
364
Part III: Starting and Co ntro lling Othe r So ftware
■
■
WScript.Sleep 1000 ‘ let’s see all internal modules: modules = spy.ModuleList(pid) MsgBox modules ‘ close editor window proc.EndProcess pid
Yo u c an enumerate mo dules even if yo u haven’t started the pro gram yo urself. Use ModuleListFromName to spec ify any windo w name.
Figure 11-6: Lis ting the internal modules in us e by Notepad Editor To list the mo dules “behind” any windo w, use this tec hnique: ‘ 11-13.VBS set wshshell = CreateObject(“WScript.Shell”) set spy = CreateObject(“module.spy”) ‘ open window folder windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) wshshell.Run “explorer.exe “ & windir ‘ wait for window to initialize WScript.Sleep 1000 ‘ let’s see all internal modules: modules = spy.ModuleListFromName(windir) MsgBox “EXPLORER uses these modules:” & vbCr & vbCr & modules
Yo u c an examine any windo w this way. Fo r example, o pen a Co ntro l Panel applet and spec ify its name. The fo llo wing sc ript enumerates any windo w.
Chapte r 1 1 : Co ntro lling Running So ftware
365
■
■
‘ 11-14.VBS set spy = CreateObject(“module.spy”) ‘ let’s see all internal modules: winname = InputBox(“Please specify the window title!”) modules = spy.ModuleListFromName(winname) MsgBox winname & “ uses these modules:” & vbCr & vbCr & modules
Summary Yo ur new c usto m Run metho d pro vides yo u with the Pro c essIDs. The Pro c essID allo ws yo u all kinds o f neat tric ks. Yo u no w have c o mplete c o ntro l o ver any pro gram and c an c lo se it do wn, using fo rc e if nec essary. Yo u c an break do wn a pro gram into its basic mo dules and find o ut whic h pro grams are c urrently running. These new metho ds are yo ur prerequisite to fully remo te-c o ntro lling external pro grams.
Chapte r 1 2
Gaining Full Control Over Any Window In This Chapter 䊳 Ac c ess any windo w direc tly using its handle 䊳 Retrieve any windo w’s c lass name fo r safe identific atio n 䊳 Bring a windo w safely into the fo regro und 䊳 Make windo ws invisible and c hange windo w style dynamic ally 䊳 Flash a windo w’s title bar 䊳 Capture windo w c o ntent and save it to disk 䊳 Explo re windo w internals and walking windo w hierarc hies
W
indo w handles are the key to manipulating any windo w. In this c hapter, yo u learn many new metho ds fo r so lving c o mmo n pro blems. Amo ng the many new so lutio ns, yo ur sc ripts will be able to switc h windo ws to the fo regro und and c apture entire windo w c o ntents.
Full Control Over Any Window Windo ws are all o ver the plac e — they resemble universe c o ntainers fo r yo ur pro grams and play an impo rtant ro le in reserving spac e. Surprisingly eno ugh, the Sc ripting Ho st do esn’t o ffer any windo w suppo rt at all. Mic ro so ft didn’t inc lude any metho ds to c o ntro l the size o f windo ws, mo ve them aro und, o r bring them into the fo regro und. Fo rtunately, the Windo ws API c o ntains numero us func tio ns to remo te c o ntro l any windo w. To ac c ess these features, all yo u need to do is o pen the COM pro jec t I have designed fo r yo u: \components\winmanager\winmanager. vbp. Even easier, yo u c an install the prepared so ftware pac kage: \install\ winmanager\setup.exe.
368
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Accessing any window The first step into the windo w wo rld is ac c essing individual windo ws. Windo ws administers individual windo ws similar to pro c esses. Eac h windo w has its individual ID, the windo w handle. It’s just a number. Yo u have numero us ways to find o ut the windo w handle o f any windo w.
Accessing a window by name If yo u kno w the name o f the windo w yo u want to ac c ess, use GetWindowHandle. The fo llo wing example asks yo u fo r a windo w name. Type in any windo w name, but take c are to type in the windo w name exac tly as it appears in the windo w’s title bar. The sc ript returns the windo w c lass (see Figure 12-1). ‘ 12-1.VBS set tool = CreateObject(“window.manager”) winname = InputBox(“Please enter the window name as it appears in” _ & “ its title bar!”) handle = tool.GetWindowHandle(winname) if handle=0 then MsgBox “Couldn’t find a window named “”” & winname & “””” else classname = tool.GetWindowClassName(handle) msg = “Window “”” & winname & “”” ID “ & handle & vbCr msg = msg & “is of class “”” & classname & “””” MsgBox msg end if
Figure 12-1: Script returns w indow handle and clas s name. It wo rked. Yo ur sc ript will retrieve the windo w handle and the windo w c lass, as sho wn in Figure 12-1. In additio n to the windo w handle, Windo ws gro ups eac h windo w by kind. Eac h applic atio n c an assign a c lass name to its windo ws. On Windo ws 2000, fo r example, eac h Explo rer windo w c arries the “CabinetWClass” c lass tag. Yo ur sc ript c an find o ut the c lass o f any windo w. Yo u’ll see a little later in the c hapter ho w the c lass name c an help identify the right windo w.
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
369
■
■
Accessing window by class name Ac c essing a windo w by name is no t very safe. Fo r example, the applic atio n might display the do c ument name in its title bar, so the windo w name depends o n the kind o f do c ument o pened by the applic atio n. Class names c an help. Let’s assume yo u want to get ac c ess to a No tepad edito r windo w. Eac h No tepad windo w uses “no tepad” as c lass name. The c lass name never c hanges, no matter whic h do c ument the edito r has lo aded. The next sc ript finds o ut if an edito r windo w is o pen and displays its name: ‘ 12-2.VBS set tool = CreateObject(“window.manager”) handle = tool.GetWindowHandleFromClass(“notepad”) if handle = 0 then MsgBox “Currently, no editor window open!” else MsgBox “Notepad title: “ & tool.GetWindowName(handle) end if
Class is a reserved VBSc ript key wo rd. Do n’t use it as a variable name. I did, and I regretted it.
Accessing a window by class name and title To safely identify a windo w, yo u c an even pro vide bo th piec es o f info rmatio n. Retrieve the handle by windo w name and c lass name. This way, yo u wo n’t get a windo w o f unexpec ted type just bec ause it may share the same name. Use GetWindowHandle and supply the c lass name as sec o nd argument.
Accessing the foreground window The fo regro und windo w is espec ially impo rtant. It’s the windo w that rec eives the keybo ard and mo use events, and yo ur SendKeys metho d sends keystro kes to this windo w. Finding o ut the fo regro und windo w is espec ially useful. Fo r example, yo u c an auto matic ally “ho o k” to a pro gram windo w yo ur sc ript launc hed: ‘ 12-3.VBS set tool = CreateObject(“window.manager”) set wshshell = CreateObject(“WScript.Shell”) ‘ launch editor wshshell.Run “notepad.exe” ‘ wait until window really is in foreground do handle = tool.GetForegroundWindowHandle ‘ find out window class classname = lcase(tool.GetWindowClassName(handle)) ‘ is right window in foreground?
370
Part III: Starting and Co ntro lling Othe r So ftware
■
■
if not classname = “notepad” then ‘ wait 1 sec WScript.Sleep 1000 counter = counter + 1 ‘ waited 5 secs, ask what’s going on! if counter>5 then MsgBox classname response = MsgBox(“Please click notepad to” _ & “ foreground!”, vbOkCancel) if response = vbCancel then WScript.Quit counter=0 end if else ok = true end if loop until ok MsgBox “Notepad in foreground: Handle “ & handle
When c o mparing the c lass name, always use lcase to c o nvert it to lo werc ase letters and c o mpare it to lo werc ase names. This way, the c lass name bec o mes c ase-insensitive. Wo ndering whic h c lass name a spec ific windo w uses? Chec k o ut the sc ripts abo ve to retrieve the c lass name. Class names never c hange, and o nc e yo u kno w the c lass name o f yo ur applic atio n, yo u are set fo rever. The sc ript demo nstrates a so lutio n to a c o mmo n pro blem. So metimes, the windo w yo u launc h fro m yo ur sc ript do esn’t jump into the fo regro und. Instead, it just nervo usly flashes its butto n in the task bar. The reaso n fo r this o dd behavio r was already explained in Chapter 10. The sc ript wo rks aro und it by c hec king the fo regro und windo w c lass and asking the user to manually bring the windo w to the fo regro und. It’s no t very elegant, but sinc e yo u do n’t kno w the windo w handle o f yo ur launc hed windo w, yo u c an’t get aro und it. There are better ways, tho ugh — read o n!
Accessing a launched window There’s a better so lutio n! Just use the c usto m Run c o mmand yo u develo ped in the previo us c hapter! It returns the Pro c essID, and with the help o f the Pro c essID, yo u c an retrieve the asso c iated windo w handle. As a side effec t, yo u no w have a safe way to determine when the windo w has initialized itself. ‘ 12-4.VBS set proc = CreateObject(“process.id”) set win = CreateObject(“window.manager”) procID = proc.Run(“notepad.exe”) if procID=0 then MsgBox “Error launching the program...” WScript.Quit end if ‘ wait for the program to initialize do handle = win.GetWindowFromProcess(procID)
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
371
■
■
‘ wait if window isn’t on screen yet if handle=0 then counter = counter + 1 WScript.Sleep 200 ‘ wait 10 secs max if counter>50 then MsgBox “Your software didn’t launch!” WScript.Quit end if end if loop while handle=0 MsgBox “Editor launched: ID “ & handle, vbSystemModal MsgBox “Bury it under some window so I can bring it up-front!”, _ vbSystemModal ‘ bring window to front win.ActivateWindow handle
This sc ript do es a number o f surprising things. First, it uses yo ur c usto m Run metho d to retrieve the Pro c essID o f the pro gram yo u launc hed. Next, it lo o ps and waits fo r GetWindowFromProcess to return the windo w handle. The mo ment GetWindowFromProcess returns a valid handle (no n-zero ), yo ur sc ript kno ws the pro gram is visible o n-sc reen. It o utputs the windo w handle, as sho wn by Figure 12-2.
Figure 12-2: Check w hether or not a program launched, retrieve its w indow handle, and bring it to the front. GetWindowFromProcess is a c o mplic ated metho d. It must enumerate all running windo ws to find the o ne with the spec ified Pro c essID. This is why the lo o p uses a delay o f 200 millisec o nds between the c hec ks. Witho ut the delay, the lo o p wo uld eat up way to o muc h CPU po wer.
Bringing a window to the foreground The sc ript c an do even mo re. It also demo nstrates ho w to safely bring a windo w up-fro nt. Onc e the sc ript asks yo u to bury the edito r windo w, c lic k so me o ther windo w so that the edito r gets c o vered. The dialo g bo x will still be visible bec ause o f the vbSystemModal o ptio n. Clic k OK. The sc ript uses ActivateWindow in c o njunc tio n with the windo w handle to bring yo ur edito r windo w in fro nt. Fro m no w o n, yo u c an make sure a pro gram windo w really is visible.
372
Part III: Starting and Co ntro lling Othe r So ftware
■
■
ActivateWindow wo rks o n all Windo ws versio ns bec ause internally it tempo rarily turns o ff fo c us lo c k. Witho ut this step, yo ur sc ript wo uldn’t be able to send windo ws in fro nt. Read mo re abo ut fo c us lo c k in Chapter 10.
Closing a window Kno wing the windo w handle, yo u c an also c lo se the windo w. QuitWindow ac ts as if yo u sent [Alt]+[F4] to the windo w. It’s up to the windo w to dec ide whether it first wants to po p up so me dialo g bo x. QuitWindow expec ts the windo w name as argument. If yo u must c lo se do wn a windo w, do n’t tamper with it. Instead, use GetProcessIDFromWindow to retrieve the Pro c essID, then use EndProcess o r KillProcess as o utlined in the previo us c hapter. ‘ 12-5.VBS set tool = CreateObject(“window.manager”) MsgBox “I am going to close the foreground window!”, vbSystemModal handle = tool.GetForegroundWindowHandle name = tool.GetWindowName(handle) if MsgBox(“Do you want to quit “”” & name & “””?”, vbYesNo)=vbYes then tool.QuitWindow(name) end if
Yo u c an also spec ify the windo w handle direc tly: Use QuitWindowHandle.
Making Windows Invisible Windo w handling isn’t dynamic with the Sc ripting Ho st. Yo u c an c ho o se the windo w style when launc hing the windo w thro ugh the Run metho d. Yo u c an’t c hange the windo w style later o n, tho ugh. This is to o bad. It wo uld be very helpful to run a pro gram as hidden and po p up its windo w o nc e a c ertain timeo ut is reac hed — just to make sure the pro gram is still running smo o thly. But ho w? Yo ur sc ript lo ses c o ntro l o ver the windo w the mo ment it launc hes the external pro gram, but yo u still have its handle. This handle is the key to dynamic c hanges.
Finding out the current window style The windo w style is just a number. It represents the windo w size and mo de. Table 12-1 lists all available windo w styles:
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
373
■
■
Table 12-1
W indow Styles
W indow Style
Description
0
Hidden
1
Maximized
2
Minimized, next w indow in order activated
3
Normal s ize
4
Activates w indow
5
Activates as maximized
6
Activates as minimized
7
Minimized, not activated
8
Show s w indow in current mode, not activated
9
Show s w indow in mos t recent mode, not activated
10
Show s w indow as normal w indow
Many o f the o ptio ns so und similar. They aren’t. Fo r example, if yo u minimize a windo w using windo w style 2, the windo w will flo at aro und with its title bar still visible. To minimize a windo w to the task bar, use windo w style 7. It’s easy to find o ut the c urrent windo w style o f any windo w. The sc ript asks yo u to c lic k a windo w, then it repo rts the c urrent windo w style, as sho wn in Figure 12-3. ‘ 12-6.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal handle = tool.GetForegroundWindowHandle msg = “””” & tool.GetWindowName(handle) & “”” uses window mode “ msg = msg & tool.GetShowCommand(handle) MsgBox msg, vbSystemModal
Figure 12-3: Find out the current w indow s tyle of any w indow.
374
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Changing window style dynamically Yo u c an c hange windo w style any time. To c hec k o ut the vario us windo w styles available, use the next sc ript to enter a new windo w style. It then applies the new style to the fo regro und windo w. Clic k Canc el to sto p the experiment. ‘ 12-7.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal handle = tool.GetForegroundWindowHandle originalstyle = tool.GetShowCommand(handle) do oldstyle = tool.GetShowCommand(handle) style = InputBox(“Current window style: “ & oldstyle _ & vbCr & “Please enter new style (0-10):”) if style = vbEmpty then exit do elseif not isNumeric(style) then MsgBox “Please enter a number!” elseif Fix(style)10 then MsgBox “Please enter a number between 0 and 10!” else tool.SetShowCommand handle, style end if loop tool.SetShowCommand handle, originalstyle MsgBox “Done.”
No w it’s easy to hide a windo w. Here’s ho w: ‘ 12-8.VBS set win = CreateObject(“window.manager”) set proc = CreateObject(“process.id”) ‘ launch editor procID = proc.Run(“NOTEPAD.EXE”) ‘ make sure program launched do handle = win.GetWindowFromProcess(procID) if handle = 0 then WScript.Sleep 200 counter = counter + 1 if counter>10 then MsgBox “Program didn’t start” WScript.Quit end if end if loop while handle=0 win.SetShowCommand handle, 0
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
375
■
■
MsgBox “Notepad now is invisible.”, vbSystemModal win.SetShowCommand handle, 10 win.ActivateWindow handle MsgBox “Now it’s visible again!”
Use ActivateWindow to make sure the windo w really gets the fo c us. If yo u do n’t, the windo w may be buried behind o ther windo ws.
Changing Window Size and Moving Windows There’s no way fo r yo ur sc ript to determine the windo w size. No t yet. Thro ugh yo ur windo w handle, yo u c an no t o nly resize a windo w but also mo ve the windo w aro und o n-sc reen.
Finding out current window dimensions Wo ndering ho w big a windo w is? Find o ut! ‘ 12-9.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal handle = tool.GetForegroundWindowHandle MsgBox “Current Window Size:” & vbCr _ & tool.GetWindowCoordinates(handle)
The sc ript returns the windo w c o o rdinates as left, to p, right, and bo tto m (see Figure 12-4).
Figure 12-4: The s cript reports the w indow ’s s ize. Wait a minute! The c o o rdinates may be o ff. This is perfec tly no rmal, bec ause the windo w c o o rdinates apply to the resto red windo w mo de o nly. If yo ur windo w is minimized o r maximized, yo u’ll still get the windo w c o o rdinates fo r resto red (no rmal) mo de. This makes sense — a minimized o r maximized windo w has no real “size.” With the previo us metho ds, yo u c an find o ut whether the windo w is in no rmal mo de, and if no t, yo u c an easily switc h to no rmal mo de and use individual windo w sizes.
376
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Changing window size The o ppo site way wo rks well, to o : Yo u c an re-size any windo w any time. Here’s the so lutio n: ‘ 12-10.VBS set win = CreateObject(“window.manager”) set proc = CreateObject(“process.id”) ‘ launch editor procID = proc.Run(“NOTEPAD.EXE”) ‘ make sure program launched do handle = win.GetWindowFromProcess(procID) if handle = 0 then WScript.Sleep 200 counter = counter + 1 if counter>10 then MsgBox “Program didn’t start” WScript.Quit end if end if loop while handle=0 ‘ reset window to (100,150) - (500,400) win.SetWindowCoordinates handle, 100, 150, 500, 400 MsgBox “New coordinates: “ & vbCr & win.GetWindowCoordinates(handle) ‘ reset window to (-40,30), width 300, height 400 win.SetWindowCoordinates2 handle, -40, 30, 300, 400 MsgBox “New coordinates: “ & vbCr & win.GetWindowCoordinates(handle)
Use negative numbers to mo ve the windo w o ff-sc reen to the left. In turn, yo u c an use this sc ript to mo ve any “lo st” windo w into the visible deskto p area. SetWindowCoordinates2 auto matic ally c alc ulates the width and height into the appro priate sc reen c o o rdinates.
Moving windows around To make transitio ns smo o thly, yo u c an even mo ve windo ws aro und. Just make sure the windo w is in no rmal mo de. Obvio usly, a minimized o r maximized windo w c an’t mo ve. ‘ 12-11.VBS set win = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal handle = win.GetForegroundWindowHandle ‘ switch to normal mode style = win.GetShowCommand(handle) if style1 then win.SetShowCommand handle, 1
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w ■
377 ■
‘ find out current x and y (left upper corner) coordinates = Split(win.GetWindowCoordinates(handle), vbCr) startx = coordinates(0) starty = coordinates(1) ‘ move window diagonally for i = 1 to 100 call win.WindowMove(handle, startx + i, starty + i) next ‘ move back, one dimension only for i = 1 to 100 call win.WindowMove(handle, startx + 100 - i) next for i = 1 to 100 call win.WindowMove(handle, , starty + 100 - i) next
If yo u o mit either the x o r y c o o rdinate, WindowMove will replac e the missing value with the c urrent windo w po sitio n.
Resizing windows Changing the windo w size wo rks very similar: Use Windo wSize! ‘ 12-12.VBS set win = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal handle = win.GetForegroundWindowHandle ‘ switch to normal mode style = win.GetShowCommand(handle) if style1 then win.SetShowCommand handle, 1 ‘ find out current size coordinates = Split(win.GetWindowCoordinates(handle), vbCr) width = coordinates(2) - coordinates(0) height = coordinates(3) - coordinates(1) for x = 1 to 200 win.WindowSize handle, width+x, height+x next for x = 1 to 200 win.WindowSize handle, width+200-x next for x = 1 to 200 win.WindowSize handle, , height+200-x next
378
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Again, if yo u o mit either width o r height, Windo wSize will replac e the missing argument with the c urrent width o r height.
Flashing a Window Title Bar Whenever Windo ws wants to c atc h yo ur attentio n, it flashes the windo w title bar. Yo u c an do the same, to o ! There are ac tually two API func tio ns in c harge. FlashWindow “manually” c hanges the title bar state fro m “selec ted” to “no n-selec ted” and vic e versa. To flash a windo w using FlashWindow, yo u need to c all this func tio n repeatedly. Windo ws 98 and Windo ws 2000 o ffer a better so lutio n — FlashWindowEx flashes a windo ws title bar fo r as lo ng as yo u want.
Flashing title bars manually Use FlashWindowManually to flash a windo w title bar the o ld way. Yo u’ll so o n disc o ver that this appro ac h isn’t very handy. Yo ur sc ript needs to c all the func tio n, and, depending o n the pro c esso r lo ad, flashing wo n’t wo rk smo o thly: ‘ 12-13.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal ‘ flash foreground window handle = tool.GetForegroundWindowHandle for x=1 to 10 state = not tool.FlashWindowManually(handle, state) WScript.Sleep 500 next ‘ revert to normal tool.FlashWindowManually handle, false
Flashing title bars automatically A muc h better appro ac h is auto matic flashing. This time, Windo ws takes c are o f all the flashing. Yo u just tell Windo ws to start and sto p the flashing: ‘ 12-14.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal ‘ flash foreground window handle = tool.GetForegroundWindowHandle tool.StartFlash handle, 200
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
379
■
■
MsgBox “Click OK to stop flashing!”, vbSystemModal tool.StopFlash handle
This new and c o nvenient flashing metho d o nly wo rks o n Windo ws 98/ Windo ws 2000.
StartFlash even allo ws yo u to pro vide the flashing interval. The sc ript uses a flashing interval o f 200 millisec o nds, but yo u c an adjust flashing to any time interval yo u like. As a default, StartFlash flashes the windo w until yo u c all StopFlash. There are alternatives. Spec ify yo ur o wn flags as third argument (see Table 12-2):
Table 12-2
Flags Controlling Caption Flashing
Flag
Description
1
Flas h caption only
2
Flas h tray button only
1+ 2 = 3
Flas h caption and tray button (default)
4
Flas h continuous ly until StopFlas h is called or counter reaches 0
8
Interrupt timer once w indow becomes active w indow
4+ 8 = 12
Flas h until w indow becomes active w indow
There’s even a fo urth (o ptio nal) argument: a c o unter. It’s set to –1 by default: flash until StopFlash is c alled. By setting the c o unter to a po sitive number, Windo ws will flash the windo w o nly fo r as many times as spec ified. ‘ 12-15.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal ‘ flash foreground window handle = tool.GetForegroundWindowHandle ‘ flash tray button only, use 600 ms frequency, ‘ flash 10 times tool.StartFlash handle, 600, 2, 10
Manipulating Window Buttons Whenever a new windo w is c reated, the c reating pro c ess c an spec ify all kinds o f windo w details. It c an spec ify whether o r no t the windo w is go ing to be resizable and if there sho uld be Maximize butto ns in its title bar. Yo ur sc ripts do n’t have this freedo m. The Run metho d wo n’t allo w yo u to spec ify these details. Again, here c o mes the windo w handle to the resc ue.
380
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Disabling minimize and maximize Fro m no w o n, it’s up to yo ur sc ript whether a c ertain windo w c an be minimized o r maximized. Have a lo o k. Figure 12-5 sho ws a No tepad windo w witho ut Minimize and Maximize butto ns. ‘ 12-16.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal ‘ use foreground window as guinea pig handle = tool.GetForegroundWindowHandle call tool.MinimizeButton(handle, call tool.MaximizeButton(handle, MsgBox “I have disabled minimize call tool.MinimizeButton(handle, call tool.MaximizeButton(handle,
false) false) and maximize buttons!”, vbSystemModal true) true)
Figure 12-5: Notice how the s cript has dis abled Minimize and Maximize buttons in the title bar. It’s up to the applic atio n whether it will hide the butto ns c o mpletely o r just gray them o ut. Likewise, it’s up to the applic atio n whether o r no t the butto ns will re-appear. If they stay hidden, c lic k the windo w title bar. This c auses the title bar to refresh, and the butto ns are reverted to no rmal. Disabling the butto ns also disables the c o rrespo nding c o ntext menu c o mmands.
Disabling the window system menu Are yo u familiar with the windo w system menu? It hides behind the little ic o n at the far-left po sitio n in the title bar. Whenever yo u c lic k this ic o n, the main windo w menu po ps up. Yo u c an disable this menu if needed. As a side effec t, the ic o n will disappear, to o .
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
381
■
■
‘ 12-17.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal ‘ use foreground window as guinea pig handle = tool.GetForegroundWindowHandle call tool.SysMenu(handle, false) MsgBox “I have disabled the window system menu!”, vbSystemModal call tool.SysMenu(handle, true)
Disabling the windo w system menu also disables the windo w c o ntext menu. Right-c lic king a windo w butto n in the task bar will no lo nger o pen a menu. As with the previo us metho ds, to get bac k the system menu, yo u might have to manually c lic k the windo w title bar.
Disabling window resizing The windo w frame c o ntro ls windo w size. Change the windo w frame to disable windo w resizing. ‘ 12-18.VBS set tool = CreateObject(“window.manager”) MsgBox “Click the window of choice, then click OK!”, vbSystemModal ‘ use foreground window as guinea pig handle = tool.GetForegroundWindowHandle call tool.ThickFrame(handle, false) MsgBox “You can’t resize the window anymore!”, vbSystemModal call tool.ThickFrame(handle, true)
Hiding and Cascading All Windows So far, yo u have always needed to c all the API func tio ns yo urself. So me selec ted windo w func tio ns are generally ac c essible, tho ugh. The Shell.Application o bjec t c o ntains the nec essary metho ds. They help yo u to keep a c lean deskto p.
Minimizing all open windows Do yo u want to take a lo o k at yo ur deskto p, but as usual numero us windo ws c o ver it? Or do yo u want to start a pro gram and c atc h the user’s attentio n, but there are to o many o pen windo ws and things get c o nfusing?
382
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Do so mething abo ut it! MinimizeAll minimizes all windo ws, and UndoMinimizeAll resto res the windo ws after yo u are do ne: ‘ 12-19.VBS set shell = CreateObject(“Shell.Application”) shell.MinimizeAll MsgBox “I’ve minimized all windows!” shell.UndoMinimizeAll MsgBox “They are back...”, vbSystemModal
MinimizeAll is very impo rtant to c atc h the user’s attentio n. If yo ur sc ript is suppo sed to interac t with the user, then c all MinimizeAll first to get rid o f any o ther windo w. Resto re the windo ws using UndoMinimizeAll after yo u are do ne. There are so me hidden keybo ard sho rtc uts that do the same. Yo u c an invo ke MinimizeAll by pressing [Win]+[M]. UndoMinimizeAll is ac c essed thro ugh [Win]+[Shift]+[M]. MinimizeAll minimizes o nly regular windo ws. Dialo g bo xes remain visible, so it’s an exc ellent way o f finding “lo st” dialo g bo xes. On Windo ws 98/ 2000, there’s ano ther sho rtc ut: [Alt]+[D] minimizes all windo ws, inc luding dialo g bo xes. The same keybo ard sho rtc ut resto res the windo ws.
Cascading and tiling windows Right-c lic k the c lo c k at the right side o f yo ur task bar! A c o ntext menu po ps up, and, amo ng o ther things, yo u c an o rganize yo ur o pen windo ws: Tile them o r c asc ade them. Any o ne o f these c o mmands will resize yo ur windo ws! Do n’t use the tile o ptio n if mo re than just a few windo ws are o pen. Otherwise, the windo ws will bec o me very small. In general, all o f these metho ds have a tendenc y to mess up yo ur neatly arranged windo w sizes. The same is available to yo ur sc ript. Use the Shell.Application metho ds TileHorizontally, TileVertically, o r CascadeWindows.
Exploring Window Internals and Child Windows Yo u no w have a very go o d understanding o f windo w mec hanic s. It’s time to enter o ne o f the mo st undo c umented, yet mo st exc iting, parts o f Windo ws: Explo re system windo ws, find o ut ho w windo ws are interc o nnec ted, and turn the entire windo w arc hitec ture upside do wn!
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
383
■
■
This is no t just fun. It gives yo u an exc ellent understanding o f ho w c o re Windo ws parts like the Start menu and the task bar really wo rk.
Accessing system windows Befo re yo u c an enter the hidden wo rld o f Windo ws internal windo ws, yo u need to find the sec ret bac k do o r. Ho w c an yo u ac c ess a system windo w like the task bar’s Start butto n? Yo u do n’t kno w its name o r c lass, so yo u c an’t use any o f the previo us metho ds. Yo u do n’t need to ! Just use the po int-and-c lic k appro ac h! GetWindowHandleFromCursor auto matic ally retrieves the windo w handle fro m the windo w the c urso r is po inting to . In o rder fo r yo u to have eno ugh time to po int to the right windo w, the metho d has a built-in delay. The next sc ript lets yo u analyze any windo w. Po int at the Start menu butto n, fo r example: ‘ 12-20.VBS set tool = CreateObject(“window.manager”) MsgBox “Point at the window you are interested in!” _ & “ I’ll grab the window 5 seconds after you clicked OK!”, _ vbSystemModal handle = tool.GetWindowHandleFromCursor(5) coords = tool.GetWindowCoordinates(handle) msg msg msg msg
Figure 12-6 sho ws the c lass name o f the Start butto n. What c an yo u do with yo ur new kno wledge? Yo u are no w in c harge! Fo r example, mo ve the Start butto n. Po int to the Start butto n and see ho w the sc ript mo ves it to the right: ‘ 12-21.VBS set tool = CreateObject(“window.manager”) MsgBox “Point at your Start Menu Button!” _ & “ I’ll grab the window 5 seconds after you clicked OK!”, _ vbSystemModal handle = tool.GetWindowHandleFromCursor(5) coords = tool.GetWindowCoordinates(handle) msg = “Grabbed Window ID “ & handle & vbCr
384
Part III: Starting and Co ntro lling Othe r So ftware
■
■
msg = msg & “Window Name: “ & tool.GetWindowName(handle) & vbCr msg = msg & “Class Name: “ & tool.GetWindowClassName(handle) & vbCr msg = msg & “Coordinates: “ & vbCr & tool.GetWindowCoordinates(handle) info = Split(coords, vbCr) xpos = info(0) MsgBox msg MsgBox “Moving the Start Menu Button...” for x=1 to 400 tool.WindowMove handle, xpos + x next MsgBox “The button still works! Want to reset it?” tool.WindowMove handle, xpos
Figure 12-6: Analyzing any w indow by pointing at it Wo w — the system really is mo dular. Even the very c o re c o mpo nents are just regular windo ws and behave as any windo w yo u c reated. Think abo ut yo ur new po wer: Yo u c an hide the Start butto n o r mo ve it o ff-sc reen. Ho wever, ho w c an yo u ac c ess the butto n (o r any o ther system windo w) witho ut first having to po int at it? The Start butto n do es no t have a unique name, and its c lass is no t unique, either.
Finding window parents Windo ws are o rganized hierarc hic ally. After all, so meo ne must have c reated the windo w. The c reato r is the windo w parent. Use GetParentHandle to find the parent windo w! The next sc ript allo ws yo u to po int at so me windo w. This is the starting po int. Fro m here, yo u c an c limb the hierarc hy and disc o ver the entire windo w c hain. Start yo ur experiment by po inting at the Start menu butto n! ‘ 12-22.VBS set tool = CreateObject(“window.manager”)
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w ■
385 ■
MsgBox “Point at the window you are interested in!” _ & “ I’ll grab the window 5 seconds after you clicked OK!”, _ vbSystemModal handle = tool.GetWindowHandleFromCursor(5) do MsgBox CreateInfo(handle) handle = tool.GetParentHandle(handle) loop until handle = 0 MsgBox “You have reached the top of the window chain!”
As it turns o ut, the Start butto n is a direc t c hild o f the tray bar, and the tray bar has a unique c lass name: Shell_TrayWnd. Yo u use this inside kno wledge a little later in the c hapter to ac c ess the Start butto n direc tly.
Finding child windows The o ppo site way is po ssible, to o : Yo u c an bro wse the windo w c hain fro m to p to bo tto m. Let’s see ho w Shell_TrayWnd is o rganized: ‘ 12-23.VBS set tool = CreateObject(“window.manager”) handle = tool.GetWindowHandleFromClass(“Shell_TrayWnd”) do MsgBox CreateInfo(handle) handle = tool.GetChildHandle(handle) loop until handle = 0 MsgBox “You have reached the bottom of the window chain!”
Part III: Starting and Co ntro lling Othe r So ftware
■
■
msg = msg & “Coordinates: “ & vbCr _ & tool.GetWindowCoordinates(handle) CreateInfo = msg end function
Hiding the Start menu button The taskbar o nly has o ne c hild — the Start butto n. So , no w yo u kno w ho w to ac c ess the butto n direc tly, and yo u c an do different things with it. Like hide it, fo r example. Figure 12-7 sho ws the result. ‘ 12-24.VBS set tool = CreateObject(“window.manager”) handle = tool.GetWindowHandleFromClass(“Shell_TrayWnd”) buttonhandle = tool.GetChildHandle(handle) style = tool.GetShowCommand(buttonhandle) tool.SetShowCommand buttonhandle, 0 MsgBox “Start button is invisible!”, vbSystemModal tool.SetShowCommand buttonhandle, style
Figure 12-7: Your s cript can make the Start button invis ible.
Enumerating child windows Ac tually, GetChildHandle isn’t telling yo u the truth. Yo u pro bably have already assumed that the Start menu butto n isn’t the o nly windo w o wned by the task bar.
GetChildHandle uses the API func tio n GetWindow with GW_CHILD as argument. This func tio n returns o nly the c hild windo w at the to p o f the windo w staple. This happens to be the Start butto n. Mo ving it aro und in the previo us example has sho wn that it’s lo c ated abo ve all o ther tray windo ws. To find o ut all c hild windo ws, yo u need a different appro ac h. To see all c hild windo ws, yo u need to enumerate them using a c allbac k func tio n. I’ve do ne the wo rk fo r yo u, so have a lo o k at the windo w kindergarten hidden inside yo ur task bar (see Figure 12-8): ‘ 12-25.VBS
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w ■
387 ■
set tool = CreateObject(“window.manager”) handle = tool.GetWindowHandleFromClass(“Shell_TrayWnd”) list = tool.EnumChildWindows(handle) MsgBox list ‘ split up in individual handles info = Split(list, vbCr) for each window in info info2 = Split(window, vbTab) handle = info2(0) MsgBox CreateInfo(handle) next function CreateInfo(handle) coords = tool.GetWindowCoordinates(handle) msg = “Grabbed Window ID “ & handle & vbCr msg = msg & “Window Name: “ & tool.GetWindowName(handle) & vbCr msg = msg & “Class Name: “ & tool.GetWindowClassName(handle) _ & vbCr msg = msg & “Coordinates: “ & vbCr _ & tool.GetWindowCoordinates(handle) CreateInfo = msg end function
Figure 12-8: Enumerate all child w indow s in the tas k bar area.
Browsing through system windows Class names and windo w handles aren’t very intuitive. I’ve designed a little to o l fo r yo u to visually bro wse thro ugh the windo ws (see Figure 12-9). It makes explo ring a lo t mo re fun. Just make sure yo u installed the COM o bjec t first: \install\treeview\setup.exe. Full so urc e c o de is inc luded: \components\treeview\tvtool.vbp. Make sure yo u have also installed the window.manager COM o bjec t: \install\winmanager\setup.exe. An Explo rer-like tree view c o ntro l lists all o pen windo ws. Clic k a no de in the tree view to see a snapsho t o f this windo w regio n in the right pane. Yo u c an even c o py the selec ted windo w bitmap to the c lipbo ard: Clic k Co py. ‘ 12-26.VBS set tool = CreateObject(“window.manager”) set tree = CreateObject(“treeview.tool”) ‘ enumerate all windows: use 0 as window handle handle = 0
388
Part III: Starting and Co ntro lling Othe r So ftware
■
■
EnumerateWindow handle, “” ‘ show dialog MsgBox tree.ShowDialog
‘ recursively search all child windows sub EnumerateWindow(handle, root) ‘ don’t list minimized windows: sc = tool.GetShowCommand(handle) minimized = (sc=0) or (sc=2) or (sc=6) or (sc=7) ‘ don’t list invisible windows ‘ do list if handle is zero! if (tool.WindowVisible(handle) and not minimized) _ or handle=0 then name = tool.GetWindowName(handle) if name = “” then name = “(none)” classname = tool.GetWindowClassName(handle) if handle=0 then classname = “Root” name = “” end if ‘ add new node in TreeView newroot = tree.AddNode(classname & “: “ _ & name, handle, root) if handle = 0 then tree.ExpandNode newroot end if ‘ enumerate child windows... list = tool.EnumChildWindows(handle) ‘ split up in individual handles info = Split(list, vbCr) for each window in info info2 = Split(window, vbTab) handle = info2(0) ‘ ...and call procedure recursively! EnumerateWindow handle, newroot next end if end sub
Use 0 as handle to enumerate all available windo ws. EnumChildWindows will enumerate all to p-level windo ws when yo u spec ify 0 as handle. This to o l makes windo w explo ratio n easy! There are just a c o uple o f details to no te: ■ Is the windo w c o vered? The to o l lists all visible windo ws, but it c an’t
guarantee that the windo w regio n is really visible. If so me o ther windo w is c o vering part o r yo ur entire windo w, yo u’ll get garbled images. This is by design. Yo ur to o l c an o nly c o py the display memo ry bo und by the windo w yo u selec ted. It c an’t do anything abo ut o ther windo ws in the way.
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
389
■
■
■ The Tree View to o l has a built-in To o lTip c apability. Whenever the name
o f a no de is to o lo ng to fit entirely into the c o ntro l, the To o lTip appears. Just wait fo r it to go away o r use the c urso r keys to navigate thro ugh yo ur tree. The to o l returns the windo w handle o f the selec ted windo w.
Figure 12-9: Explore any w indow and get a thumbnail preview.
Hiding the desktop Maybe yo u have no tic ed an o dd entry in yo ur Window Explorer: Progman: Program Manager. Altho ugh yo u are running 32-bit Windo ws, the go o d o ld Pro gram Manager is still there! In c o ntrast to Windo ws 3.11, no w it represents the entire deskto p. Chec k it o ut: The fo llo wing sc ript hides yo ur entire deskto p: ‘ 12-27.VBS set tool = CreateObject(“window.manager”) handle = tool.GetWindowHandle(“Program Manager”, “Progman”) oldstyle = tool.GetShowCommand(handle) tool.SetShowCommand handle, 0 MsgBox “Hiding the desktop!” tool.SetShowCommand handle, oldstyle
Changing desktop View mode If yo u bro wse thro ugh its c hild windo ws, yo u’ll disc o ver the c hild o bjec t SysListView32. This o bjec t is really an Explo rer windo w. It represents all the ic o ns o n yo ur deskto p. No rmal Explo rer windo ws o ffer yo u many different view o ptio ns. The deskto p, ho wever, always displays its c o ntent as Large Ic o ns. Always? No t if yo u try the next sc ript. Sinc e yo u no w kno w the windo w handle, it’s easy to set the View mo de manually:
390
Part III: Starting and Co ntro lling Othe r So ftware
for x = 1 to 4 tool.ViewMode handle, x MsgBox “Desktop now in View mode “ & x next
Capturing Window Content Windo ws share o ne c o mmo n fac t — their c o ntent is sto red so mewhere in display memo ry. To c apture the c o ntent, yo u need to find the display memo ry and c o py it into yo ur o wn memo ry sto rage. This is no t eno ugh, tho ugh. To be able to display the c aptured memo ry, c o py it to the c lipbo ard, o r sto re it as a file, yo u need to wrap the memo ry into so me kind o f c o ntainer. Yo u need to c o nvert the raw memo ry snapsho t into an OLE pic ture. I have designed a COM o bjec t that do es all o f this fo r yo u. This o bjec t is the fo undatio n fo r c apturing any sc reen area o r windo w. To use the fo llo wing sc ripts, make sure yo u have installed the COM o bjec t: \install\capture\ setup.exe. Full so urc e c o de is pro vided o n yo ur CD: \components\capture\ capture.vbp.
Capturing the entire screen Capturing the sc reen is very easy: GetForegroundWindowHandle retrieves the windo w handle o f the windo w in the fo regro und, and CaptureWindow c o nverts the display memo ry into an OLE pic ture. Yo ur COM o bjec t no w c an easily c o py it to the c lipbo ard o r use SavePicture to save it as a file. ‘ 12-29.VBS set tool = CreateObject(“OLE.bitmap”) set wshshell = CreateObject(“WScript.Shell”) ‘ capture screen to file: filename = “C:\myshot.jpg” tool.CaptureScreenToFile filename ‘ display (works only if graphics software is available) MsgBox “I’ll now try to show the screenshot to you...”, vbSystemModal wshshell.Run filename
Chapte r 1 2 : Gaining Full Co ntro l Ove r Any Windo w
391
■
■
Yo u want to c o py the sc reen sho t to the c lipbo ard to insert it into o ther pro grams direc tly? Go ahead: CaptureScreenToClip do es the jo b.
Capturing the active window Capturing the ac tive windo w wo rks similarly. Use CaptureActiveWindowToClip and CaptureActiveWindowToFile. Internally, this time the metho d uses the GetForegroundWindow API func tio n to retrieve the ac tive windo w’s handle.
Capturing any window Using a windo w handle, yo u c an c apture any windo w o r any c hild windo w inside o f so me windo w. If yo u kno w the windo w handle already, use CaptureWindowToClip o r CaptureWindowToFile. If yo u do n’t kno w the windo w handle, yo u c an po int at the windo w yo u want to c apture: Use CaptureCursorToClip o r CaptureCursorToFile: ‘ 12-30.VBS set tool = CreateObject(“OLE.bitmap”) set wshshell = CreateObject(“WScript.Shell”) ‘ capture screen to file: filename = “C:\myshot.jpg” delay = 5 MsgBox delay & “ secs after you clicked OK, I’ll capture!” & vbCr _ & “Please point at the window!”, vbSystemModal tool.CaptureCursorToFile delay, filename
‘ display (works only if graphics software is available) MsgBox “I’ll now try to show the screenshot to you...”, vbSystemModal wshshell.Run filename
The sc ript displays a dialo g bo x. Clic k OK. No w yo u have five sec o nds to po int at the windo w yo u want to c apture. Fo r example, c lic k the Start menu butto n and po int at the Start menu. Pro vided yo u have installed graphic s so ftware that is c apable o f displaying .bmp files, the sc ript presents the c aptured sho t to yo u.
Displaying a window preview The COM o bjec t c o ntains a little to o l fo r yo u — ShowWindow po ps up a dialo g bo x and displays a preview o f any windo w, as sho wn in Figure 12-10.
392
Part III: Starting and Co ntro lling Othe r So ftware
■
■
Figure 12-10: Preview any w indow and capture the w indow to the clipboard. ‘ 12-31.VBS set tool = CreateObject(“OLE.bitmap”) set win = CreateObject(“window.manager”) ‘ get foreground window handle handle = win.GetForegroundWindowHandle ‘ display preview (and allow to capture) tool.ShowWindow handle, “This is the foreground window!”
Summary In this c hapter, yo u learn ho w to ac c ess windo ws direc tly using their handles. Self-defined COM o bjec ts pro vide numero us ways to find o ut windo w handles, and using the handles, it bec o mes po ssible to hide windo ws o r c hange windo w style dynamic ally. Yo ur sc ripts no w c an even resize and mo ve any windo w o nsc reen. Additio nal to o ls let yo u bro wse thro ugh windo w hierarc hies and dive into the many hidden and undo c umented system windo ws. Kno wing these, yo u c an hide the entire deskto p o r mo ve the Start butto n aro und. Even better, ano ther COM o bjec t lets yo u c apture any windo w handle and c o nvert the display memo ry into an OLE pic ture o bjec t that yo u c an save to file o r c o py to the c lipbo ard.
Chapte r 1 3
Starting Scripts Automatically In This Chapter 䊳 Launc h sc ripts auto matic ally when a user lo gs o n — o r even befo re anybo dy
lo gs o n 䊳 Start sc ripts invisibly fro m inside yo ur Registry 䊳 Use the system agent to launc h servic e sc ripts in intervals 䊳 Insert sc ripts as c o ntext menu extensio ns into any c o ntext menu 䊳 Find o ut abo ut the hidden system variables used inside c o ntext menus 䊳 Co py file names to the c lipbo ard
S
c ripts c an be launc hed in a variety o f ways. In this c hapter, yo u learn ho w to launc h sc ripts auto matic ally and ho w to intro duc e yo ur o wn sc ripts into any c o ntext menu and use it as a Windo ws c o mmand extensio n.
Starting Scripts the Smart Way What if yo u want yo ur sc ript to launc h auto matic ally — say, every Wednesday afterno o n — to searc h fo r o utdated files? What if yo u want to use sc ripts to find o ut details abo ut a drive? Launc hing sc ripts manually is no real alternative. Fo rtunately, Windo ws allo ws yo u to run sc ripts auto matic ally, launc h sc ripts with keystro kes, and even insert yo ur sc ripts into c o ntext menus o f any file type.
Launching scripts at logon The easiest way to launc h a sc ript is to plac e a sho rtc ut into the StartUp pro gram gro up. The fo llo wing sc ript helps yo u do this. ‘ 13-1.VBS set args = WScript.Arguments if args.Count=0 then MsgBox “Please drag a vbs script file on my icon.” _
394
Part III: Starting and Co ntro lling Othe r So ftware
■
■
& “ I’ll place it into the Startup group!” WScript.Quit end if set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) scriptfile = args(0) if not lcase(fs.GetExtensionName(scriptfile))=”vbs” then MsgBox “I only accept vbs script files!” WScript.Quit end if startup = wshshell.SpecialFolders(“Startup”) name = InputBox(“Under which name should I place the script “ _ & “””” & fs.GetBaseName(scriptfile) & “”” into the StartUp-” _ & “Group?”, “autostart script”) set scut = wshshell.CreateShortcut(startup & “\” & name & “.lnk”) scut.TargetPath = scriptfile scut.Save MsgBox “Script has been successfully linked to your StartUp group!”
Drag a sc ript file o nto this sc ript ic o n and spec ify a name, as sho wn in Figure 13-1. The sc ript auto matic ally inserts a sho rtc ut to yo ur sc ript into the StartUp pro gram gro up, and the next time yo u lo g o n to Windo ws, yo ur sc ript will be exec uted.
Figure 13-1: Ins ert s cripts into the StartUp group and s pecify a name. To launc h the sc ript, no matter whic h user lo gs o n, plac e the sho rtc ut into the c o mmo n StartUp gro up (instead o f yo ur perso nal StartUp gro up). Replac e Startup with AllUsersStartUp. The c o mmo n StartUp gro up is available o n Windo ws 98, NT, and 2000.
Hiding script launch The StartUp gro up is visible to the user. Maybe yo u’d rather launc h yo ur sc ript fro m a hidden plac e. The Registry pro vides suc h a plac e: It’s the Run key. To plac e yo ur sc ript into the Run key, use the fo llo wing sc ript:
Chapte r 1 3 : Starting Sc ripts Auto matic ally
395
■
■
‘ 13-2.VBS set args = WScript.Arguments if args.Count=0 then MsgBox “Please drag a vbs script file on my icon.” _ & “ I’ll place it into the Startup group!” WScript.Quit end if set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) scriptfile = args(0) if not lcase(fs.GetExtensionName(scriptfile))=”vbs” then MsgBox “I only accept vbs script files!” WScript.Quit end if key = “HKLM\Software\Microsoft\Windows\CurrentVersion\Run\” ‘ use this key on Windows NT/2000: ‘key = “HKLM\Software\Microsoft\Windows NT\CurrentVersion\Run\” wshshell.RegWrite key & “myscript”, scriptfile MsgBox “Script has been successfully added to the Run key!”
Windo ws 9.x and Windo ws NT/ 2000 use different keys. No te the c o mment in the sc ript file and use the appro priate key. The key used by the sc ript applies to all users. It’s part o f HKEY_LOCAL_ MACHINE, so it’s a user-independent setting. If yo u want to launc h yo ur sc ript fo r individual users o nly, replac e HKLM with HKCU (c urrently lo gged-o n user) o r HKU\username\. The sc ript c an o nly add o ne sc ript file to the Run key bec ause it always uses the subkey named myscript. Any time yo u add a new sc ript file, the o ld entry will be replac ed. Yo u c o uld wo rk aro und this behavio r and assign different subkey names, but this wo uldn’t make muc h sense. Altho ugh there is no limitatio n o n ho w many sc ript files yo u c an launc h auto matic ally, yo u sho uld always stic k to o ne file o nly. Running mo re than o ne sc ript at the same time c an c ause tro uble when bo th sc ripts try to ac c ess a COM o bjec t at the same time. If yo u must launc h mo re than o ne sc ript, use a “launc h” sc ript o nly and launc h yo ur sc ripts fro m inside this sc ript, using sync hro no us c alling as o utlined in Chapter 10. To get rid o f Registry-c o ntro lled sc ript launc hing, start the Registry Edito r, c ho o se Run fro m yo ur Start menu, and enter REGEDIT. Then, use the Edit menu to searc h fo r the key Run and delete the subkey yo ur sc ript added. Figure 13-2 sho ws the Registry Edito r. Or, let a sc ript do the wo rk: ‘ 13-3.VBS set wshshell = CreateObject(“WScript.Shell”) key = “HKLM\Software\Microsoft\Windows\CurrentVersion\Run\”
396
Part III: Starting and Co ntro lling Othe r So ftware
■
■
‘ use this key on Windows NT/2000: ‘key = “HKLM\Software\Microsoft\Windows NT\CurrentVersion\Run\” wshshell.RegDelete key & “myscript” MsgBox “Deleted script entry from Registry.”
Figure 13-2: Launch s cripts from ins ide the Regis try us ing the Run key.
Launching scripts before logon Yo u c an even launc h sc ripts befo re anybo dy lo gs o n. Fo r example, in a c o mpany setting, c o mputers may be switc hed o n auto matic ally in the mo rning. Yo ur sc ript c an ac c o mplish bo ring maintenanc e wo rk befo re peo ple ac tually start wo rking o n the mac hines. Ho wever, this o nly wo rks o n Windo ws 9.x. There isn’t any NT sec urity available fo r this, so even tho ugh no bo dy has lo gged o n, yo ur sc ript c an do whatever it pleases. On Windo ws NT/2000, yo u c an’t run sc ripts prio r to lo gging o n. To launc h sc ripts prio r to lo go n, use the previo us sc ripts but use a different key. Instead o f Run, use the RunServices key!
Launching scripts in intervals Mic ro so ft has develo ped a flexible system to launc h so ftware auto matic ally in intervals. This system is c alled System Agent o r Sc heduled Tasks. It may no t be available o n yo ur system. Fo r Windo ws 95, it c o mes separately with the Plus! pac k. On Windo ws 98 and 2000, it’s already inc luded. Open My Co mputer o n the deskto p, and yo u see the ic o n Sc heduled Tasks. On Windo ws 2000, o pen Sc heduled Tasks in the Co ntro l Panel.
Chapte r 1 3 : Starting Sc ripts Auto matic ally
397
■
■
The dialo g bo xes will lo o k similar to the o ne sho wn in Figure 13-3 (the wizard wo rks slightly different o n different Windo ws versio ns).
Figure 13-3: The Scheduled Tas k Wizard helps s chedule your s cripts for automatic launch. The task sc heduler c an launc h any pro gram, inc luding yo ur sc ripts. It’s the perfec t so lutio n fo r any maintenanc e o r bac kup sc ript. Just supply the sc ript name. Even witho ut the task sc heduler, yo u c an make yo ur sc ripts c hec k in regular intervals. Just use a lo o p and delay the lo o p fo r as lo ng as yo u want the interval to last. Fo r example, a WScript.Sleep 10*60*1000 delays the lo o p fo r 10 minutes, instruc ting the sc ript to c hec k every 10 minutes fo r disk spac e, Internet c o nnec tio ns, o r whatever yo u want to mo nito r. Ho wever, yo u have no way o f sto pping yo ur sc ript exc ept by o pening the task list and killing wscript.exe manually.
Inserting Scripts into Context Menus Windo ws is o bjec t-o riented: Whenever yo u right-c lic k an o bjec t, a c o ntext menu appears and o ffers the mo st fundamental c o mmands this o bjec t has to o ffer. Did yo u kno w that c o ntext menu entries are fully pro grammable? Yo u c an easily insert yo ur o wn c o mmands and use sc ripts as c o ntext menu extensio ns! Fo r example, let’s assume yo u want a c o mmand to find o ut the size o f so me fo lder o r drive. This is what yo ur c o mmand wo uld lo o k like: ‘ 13-4.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set args = WScript.Arguments if args.Count=0 then MsgBox “Please drag a file, folder or drive on my icon!”
398
Part III: Starting and Co ntro lling Othe r So ftware
■
■
WScript.Quit end if ‘ args(0) now contains the file/folder/drive name ‘ find out which type it is if fs.FileExists(args(0)) then set object = fs.GetFile(args(0)) elseif fs.FolderExists(args(0)) then set object = fs.GetFolder(args(0)) else MsgBox “You did not drag a file/folder/drive - can’t find out” _ & “ size!” WScript.Quit end if MsgBox “””” & args(0) & “”” size: “ & _ FormatSize(object.size), vbInformation function FormatSize(bytes) if bytes0 then list = list & key & subkey & “\” & vbCr end if next for each subkey in subkeys SearchBranch key & subkey & “\” next end sub
Fo r example, Figure 15-9 displays the results o f a searc h fo r “deskto p.”
Figure 15-9: Find all Regis try keys that contain the w ord “des ktop.”
Searching for value names With a slight variatio n, the sc ript c an searc h fo r value names. The fo llo wing example lists all value names that c o ntain vbs. ‘ 15-4.VBS set tool = CreateObject(“regtool.tob”)
Chapte r 1 5 : Re gis try Twe aks
433
■
■
searchfor = “vbs” list = “” SearchBranch “HKEY_LOCAL_MACHINE\” SearchBranch “HKEY_CURRENT_USER\” MsgBox list sub SearchBranch(key) on error resume next ‘ enumerate values set subvalues = tool.RegEnum(left(key, len(key)-1)) for each valuename in subvalues if Instr(lcase(valuename), lcase(searchfor))>0 then list = list & key & valuename & vbCr end if next set subkeys = tool.RegEnum(key) for each subkey in subkeys SearchBranch key & subkey & “\” next end sub
Searching for values Ano ther mo dific atio n allo ws yo ur sc ript to searc h fo r the ac tual Registry values that matc h yo ur searchfor searc h c riteria. This sc ript searc hes fo r Registry entries c o ntaining “.scr”. ‘ 15-5.VBS set tool = CreateObject(“regtool.tob”) searchfor = “.scr” list = “” SearchBranch “HKEY_LOCAL_MACHINE\” SearchBranch “HKEY_CURRENT_USER\” MsgBox list sub SearchBranch(key) on error resume next ‘ enumerate values set subvalues = tool.RegEnum(left(key, len(key)-1)) for each valuename in subvalues ‘ retrieve value valcontent = tool.RegRead(key & valuename) if Instr(lcase(valcontent), lcase(searchfor))>0 then list = list & key & valuename & “=” & valcontent & vbCr end if next set subkeys = tool.RegEnum(key)
434
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
for each subkey in subkeys SearchBranch key & subkey & “\” next end sub
Controlling program settings Mo st o f yo ur pro grams sto re their internal settings in the Registry, to o . Yo u’ll find tho se settings either in HKEY_CURRENT_USER\Software \CompanyName\Product (fo r individual users) o r HKEY_LOCAL_MACHINE \Software\CompanyName\Product (fo r mac hine-wide settings). Replac e CompanyName and Product with the appro priate values o f yo ur so ftware. It may be extremely useful to c o ntro l these settings. Fo r example, maybe yo u want to launc h yo ur favo rite game with different o ptio ns fo r the input devic e o r netwo rk. Identify the settings first, using the snapsho t tec hnique desc ribed previo usly. Then, write a sc ript that sets the appro priate settings and launc hes yo ur game. This way, yo u c an write a number o f launc her sc ripts that all launc h yo ur game, but also auto matic ally set the settings yo u like. And, bec ause yo ur pro gram will be launc hed after yo u made the c hanges, the pro gram will rec o gnize yo ur c hanges.
Protecting program settings Yo u c an do even mo re. Imagine yo urself in a teac hing enviro nment — yo ur students lo ve to play aro und with all the pro gram o ptio ns, but o nc e yo ur lesso n is o ver, yo u need to spend ano ther half an ho ur resetting all the pro gram o ptio ns to the default. Yo u do n’t have to ! Start the Registry Edito r REGEDIT.EXE and identify the branc h in the Registry that sto res yo ur pro gram settings. Expo rt this branc h: Registry – Export Registry File. The entire branc h is saved as a REG file. Yo u c an no w reset all pro gram settings to the default b y simply o pening the REG file and re-impo rting the values. Or leave this wo rk to a sc ript. Use the WScript.Shell Run metho d to read in yo ur REG file auto matic ally: fo r example, as part o f the StartUp gro up at eac h Windo ws lo go n: set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “REGEDIT.EXE /S “”” & regfile & “”””
The /S o ptio n gets rid o f the anno ying “Are yo u sure...” message. REGEDIT silently reads in the REG file, and no c urio us student will ever get a c lue why all the settings are reset to no rmal eac h time he o r she lo gs in.
Managing System Icons on the Desktop The deskto p is yo ur private sto rage area. Here, yo u c an put any files yo u need fo r quic k ac c ess. In additio n, Windo ws plac es so me o f its o wn ic o ns o n yo ur deskto p. These system ic o ns wo rk differently. Often, yo u c an’t rename these ic o ns, and there might be no way o f deleting them, either.
Chapte r 1 5 : Re gis try Twe aks
435
■
■
With the help o f the Registry, tho ugh, yo u will be able to c o ntro l yo ur entire deskto p. Yo u c an kic k o ff any system ic o ns yo u do n’t want, c hange their names, and even plac e new system ic o ns o n yo ur deskto p.
Changing the name of the Recycle Bin On every deskto p, yo u’ll find a Rec yc le Bin. Yo u c an’t disable it, and yo u c an’t rename it. Right? Sure yo u c an. The next sc ript allo ws yo u to rename the Rec yc le Bin to whatever yo u like ( see Figure 15-10) . ‘ 15-6.VBS set wshshell = CreateObject(“WScript.Shell”) machinekey = “HKLM\SOFTWARE\Classes\CLSID\{645FF040-5081-101B-” _ & “9F08-00AA002F954E}\” ‘ use this key for Windows 2000 ‘userkey = “HKCU\Software\Microsoft\Windows\CurrentVersion\” _ ‘ & “Explorer\CLSID\{645FF040-5081-101B-9F08-00AA002F954E}\” userkey = “HKCU\Software\Classes\CLSID\{645FF040-5081-101B-” _ & “9F08-00AA002F954E}\” on error resume next oldname2 = wshshell.RegRead(machinekey) oldname1 = wshshell.RegRead(userkey) if oldname1=”” then oldname1=”(undefined)” on error goto 0 msg = “Your Recycle Bin is named “”” & oldname2 & “””” & vbCr msg = msg & “It’s current user setting is “”” & oldname1 & “””” & vbCr msg = msg & “Do you want to change its name?” response = MsgBox(msg, vbYesNo + vbQuestion) if response = vbYes then name = InputBox(“Please enter the new name!”) if name = “” then if oldname1=”” then WScript.Quit else response = MsgBox(“Do you want to delete the “ _ & “user setting?”, vbYesNo + vbQuestion) if response = vbYes then wshshell.RegWrite userkey, “” end if end if else wshshell.RegWrite userkey, name MsgBox “Name has changed. Refresh your desktop!” end if end if
436
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Figure 15-10: Rename your Recycle Bin. Clic k yo ur deskto p and press [F5] to refresh the deskto p. Immediately, yo ur ic o n name c hanges. To delete yo ur user-defined name, c ho o se to rename the ic o n and then c lic k Canc el. System c o mpo nents c arry a unique name tag, the Class ID. On all Windo ws versio ns, the Rec yc le Bin uses the Class ID {645FF0405081-101B-9F08-00AA002F954E}. The basic info rmatio n applies to all users and is sto red in HKEY_LOCAL_ MACHINE\Software\Classes\CLSID\{645FF040-5081-101B-9F0800AA002F954E} o r its alias: HKEY_CLASSES_ROOT\CLSID\{645FF0405081-101B-9F08-00AA002F954E}. In additio n, there may be a user-spec ific setting sto red in the HKEY_ CURRENT_USER branc h. If there is, the Rec yc le Bin uses a different name o n a per-user basis. The sc ript reads bo th keys and reveals the standard name and a username if o ne is spec ified. Yo u then have the o ppo rtunity to spec ify a new username. There’s a lo t c o nfusio n abo ut where Windo ws sto res the user settings, and so me versio ns, suc h as Windo ws 95, do n’t rec o gnize user settings at all. In this c ase, c hange the sc ript and use machinekey as userkey, to o . On Windo ws 98, user settings are sto red in HKCU\Software\Classes, so it’s the exac t mirro r image o f the mac hine settings: HKLM\Software\Classes. On Windo ws 2000, in c o ntrast, user settings are sto red as part o f the Explo rer settings. The appro priate key is marked in the prec eding sc ript. Change the user key if yo u run Windo ws 2000. It is unc lear whether this new lo c atio n is a bug o r a feature.
More secrets about desktop items Maybe yo u wo nder where the system deskto p items c ame fro m in the first plac e. They are no t regular ic o ns, and even mo re surprising, o n so me systems, yo u c an delete system ic o ns fro m the deskto p, and o n o thers, yo u c an’t.
Chapte r 1 5 : Re gis try Twe aks
437
■
■
The sec ret is a key named NameSpace. It’s sto red here: HKEY_LOCAL _MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer \Desktop\NameSpace. In it, Windo ws defines all system ic o ns visible o n the deskto p (see Figure 15-11). The next sc ript takes advantage o f this insider kno wledge and lists all system deskto p items: ‘ 15-7.VBS set tool = CreateObject(“regtool.tob”) key1 = “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\” _ & “CurrentVersion\Explorer\Desktop\NameSpace\” key2 = “HKCR\CLSID\” set desktopitems = tool.RegEnum(key1) list = “System icons currently installed on desktop:” & vbCr & vbCr for each icon in desktopitems if not left(icon,1) = “{“ then icon = “{“ & icon & “}” end if name = tool.RegRead(key2 & icon & “\”) if name = “” then name = “(unknown name)” list = list & name & “ (Class ID: “ & icon & “)” & vbCr next MsgBox list, vbInformation
Figure 15-11: Lis t all s ys tem icons that are vis ible on your des ktop. The key do esn’t list all system ic o ns: My Co mputer and Netwo rk Neighbo rho o d are no t inc luded. Many o ther items are inc luded, tho ugh, and yo u also get their Class IDs. The NameSpace key lists o nly o ptio nal system ic o ns. My Co mputer and Netwo rk Neighbo rho o d are no t o ptio nal. They are always part o f the system and c an’t be disabled — at least no t thro ugh NameSpace.
438
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Hiding the Recycle Bin All o ptio nal system ic o ns c an be hidden — just delete the ic o n entry in the NameSpace key. The next sc ript hides the Rec yc le Bin and is also able to resto re it: ‘ 15-8.VBS set tool = CreateObject(“regtool.tob”) key1 = “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\” _ & “CurrentVersion\Explorer\Desktop\NameSpace\” recycler = “{645FF040-5081-101B-9F08-00AA002F954E}\” ‘ check whether recycle bin is already hidden if tool.KeyExists(key1 & recycler) then ‘ recycle bin is currently visible msg = “Do you want to hide the recycle bin?” response = MsgBox(msg, vbYesNo + vbQuestion) if response = vbYes then tool.RegDelete key1 & recycler end if else ‘ recycle bin is hidden msg = “Do you want to restore the recycle bin icon?” response = MsgBox(msg, vbYesNo + vbQuestion) if response = vbYes then tool.RegWrite key1 & recycler, “Recycle Bin” end if end if
No te that again yo u need to refresh yo ur deskto p by pressing [F5] to see the results. Read o n to find the missing sc ripting metho d to refresh the deskto p auto matic ally.
The Secret dual-store The main info rmatio n sto re fo r all deskto p o bjec ts is lo c ated in the HKEY_LOCAL_MACHINE branc h o f the Registry. This setting applies to all users. It’s used as default. In additio n, Windo ws may sto re different settings in the HKEY_CURRENT_USER branc h. These settings o verride the default system settings and apply to the c urrent user o nly. So , if yo u want to hide the Rec yc le Bin o nly fro m so me users, first delete it fro m the HKEY_LOCAL_MACHINE key, as sho wn in the previo us example. Then, c hange the prec eding sc ript and replac e HKEY_LOCAL_MACHINE with HKEY_CURRENT_USER. No w yo u c an c o ntro l the Rec yc le Bin individually fo r every user. This “dual wo rld” is a relatively new tec hnique intro duc ed by Windo ws 98. Here, o nly a limited number o f settings c an be spec ified in the user branc h. Windo ws 2000 fully explo its the feature and allo ws yo u to sto re any o bjec t setting o n a per-user basis.
Chapte r 1 5 : Re gis try Twe aks ■
439 ■
The registry key HKEY_CLASSES_ROOT used to be just a sho rtc ut to HKEY_ LOCAL_MACHINE\Software\Classes\CLSID. No t anymo re. In Windo ws 2000, HKEY_CLASSES_ROOT reads bo th the HKEY_LOCAL_MACHINE user-independent setting and the HKEY_CURRENT_USER user-spec ific setting. If it finds userspec ific settings, they o verride the mac hine-wide settings. As a rule o f thumb, use HKEY_CURRENT_ROOT if yo u want to get the c urrently ac tive settings, and read the HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER keys direc tly if yo u want to rec eive the mac hine-default o r user-spec ific settings.
Refreshing the desktop automatically Yo ur sc ripts c an manipulate the Registry in any way they want. They c an’t fo rc e Windo ws to rec o gnize the c hanges, tho ugh. This is why yo u had to refresh the deskto p manually in the previo us examples. Obvio usly, this is no t a perfec t so lutio n. This is why I have develo ped ano ther COM o bjec t. It pro vides vario us metho ds to fo rc e Windo ws to rec o gnize Registry c hanges. Make sure yo u install the new c o mpo nent ( \install\regupdate\setup.exe). Full so urc e c o de is pro vided at \components\regupdate\regupdate.vbp. To fo rc e Windo ws to read in the deskto p-related Registry keys, yo u need a way to refresh the deskto p thro ugh API c alls. Here’s ho w: Option Explicit Const SHCNF_IDLIST = &H0 Const SHCNE_ALLEVENTS = &H7FFFFFFF Private Declare Function SHGetSpecialFolderLocationD Lib _ “shell32.dll” Alias “SHGetSpecialFolderLocation” _ (ByVal hwndOwner As Long, ByVal nFolder As Long, _ ByRef ppidl As Long) As Long Private Declare Function SHChangeNotify Lib “shell32.dll” _ (ByVal wEventID As Long, ByVal uFlags As Long, ByVal _ dwItem1 As Long, ByVal dwItem2 As Long) As Long Private Declare Function GetDesktopWindow Lib “User32” () As Long Public Sub RefreshDesktop() Dim lpil As Long Call Call Call Call End Sub
The sc ript first retrieves the System ID fo r the deskto p. Next, it sends no tific atio n messages to the deskto p to info rm it abo ut c hanges. This is eno ugh to tric k the deskto p into refreshing itself.
440
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Yo u no w c an c o mplete the prec eding sc ripts. Inc lude o ne mo re line at the beginning: set refresh = CreateObject(“registry.update”)
And inc lude o ne line at the end o f yo ur sc ript: refresh.RefreshDesktop
This is all yo u need. Fro m no w o n, yo ur sc ripts c hange the Rec yc le Bin immediately, and there’s no need anymo re fo r manual refreshing.
Finding and restoring system icons Ho w do yo u find system ic o ns yo u c an use o n yo ur deskto p? It’s simple. Eac h system ic o n is really a COM o bjec t, so it’s listed in the HKCR\CLSID\ key. Unfo rtunately, hundreds o f COM o bjec ts are registered. So ho w do yo u find the o nes that are eligible as deskto p ic o ns? Use a little tric k. COM o bjec ts designed as deskto p ic o ns have a subkey c alled ShellFolder. No w it’s easy to retrieve a list o f all system ic o ns available (see Figure 15-12): Make sure yo u have installed the COM o bjec t: ( \install\registry\ setup.exe). ‘ 15-9.VBS set tool = CreateObject(“regtool.tob”) set wshshell = CreateObject(“WScript.Shell”) key = “HKCR\CLSID\” ‘ enumerate all registered COM objects set result = tool.RegEnum(key) list = “Desktop COM objects:” & vbCr & vbCr for each comobject in result ‘ find object with ShellFolder subkey subkey = key & comobject & “\ShellFolder\” if tool.KeyExists(subkey) then name = “” on error resume next name = tool.RegRead(key & comobject & “\”) on error goto 0 if name = “” then name = “(unknown)” list = list & comobject & “: “ & name & vbCr end if next wshshell.Popup list
Chapte r 1 5 : Re gis try Twe aks ■
441 ■
Figure 15-12: Find s ys tem objects that may be s uitable as des ktop icons . With o nly a slight mo dific atio n, yo u c an use this sc ript to resto re any o f the system deskto p ic o ns — and add system ic o ns no t available befo re (see Figure 15-13): ‘ 15-10.VBS set tool = CreateObject(“regtool.tob”) set refresh = CreateObject(“registry.update”) set wshshell = CreateObject(“WScript.Shell”) key = “HKCR\CLSID\” key1 = “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\” _ & “CurrentVersion\Explorer\Desktop\NameSpace\” ‘ enumerate all registered COM objects set result = tool.RegEnum(key) list = “Desktop COM objects:” & vbCr & vbCr for each comobject in result ‘ find object with ShellFolder subkey subkey = key & comobject & “\ShellFolder\” if tool.KeyExists(subkey) then on error resume next
442
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
name = “” tip = “” name = tool.RegRead(key & comobject & “\”) tip = tool.RegRead(key & comobject & “\InfoTip”) on error goto 0 if not (name = “” and tip = “”) then if name = “” then name = “unknown” msg = “Found system icon: “ & name & vbCr if not tip=”” then msg = msg & “Additional info: “ & tip & vbCr end if if tool.KeyExists(key1 & comobject & “\”) then ‘ icon already visible msg = msg & “The icon is already visible. Do” _ & “ you want to hide it?” answer = MsgBox(msg, vbYesNoCancel + vbQuestion) if answer = vbYes then tool.RegDelete key1 & comobject & “\” refresh.RefreshDesktop end if else ‘ icon is currently hidden msg = msg & “The icon is currently hidden.” _ & “ Do you want to make it visible?” answer = MsgBox(msg, vbYesNoCancel + vbQuestion) if answer = vbYes then tool.RegWrite key1 & comobject & “\”, name refresh.RefreshDesktop end if end if if answer = vbCancel then WScript.Quit end if end if next
No t all symbo ls really do wo rk o n yo ur deskto p. A small mino rity wo n’t o pen o r will display erro r messages. Just launc h yo ur sc ript again, and yo u c an kic k tho se system ic o ns bac k o ff-sc reen.
Figure 15-13: Add and remove s ys tem icons from your des ktop. On Windo ws 2000, the NameSpace key c o ntains so me system ic o ns with no o bvio us use. Search Results, fo r example, do esn’t sho w an ic o n. Still, this o bjec t is very impo rtant. It’s respo nsible fo r displaying searc h results inside Explo rer windo ws. Disabling this system “ic o n” will disable the built-in searc h c apabilities o f yo ur Explo rer. As a general rule, do n’t disable anything yo u c an’t see o n yo ur deskto p.
Chapte r 1 5 : Re gis try Twe aks ■
443 ■
Adding commands to system context menus Strangely, so me o f yo ur new deskto p ic o ns c an be easily remo ved by just dragging them o nto yo ur Rec yc le Bin o r c ho o sing delete fro m the c o ntext menu, whereas o thers just wo n’t go away. What’s go ing o n? And why do system ic o ns have a ShellFolder subkey, anyway? The ShellFolder subkey c o ntains o ne very impo rtant value, and that is Attributes. This value c o ntro ls the c o ntext menu, and it’s this setting that determines whether o r no t a system ic o n c an be deleted manually, amo ng o ther things. ‘ 15-11.VBS set tool = CreateObject(“regtool.tob”) set refresh = CreateObject(“registry.update”) key1 = “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\” _ & “CurrentVersion\Explorer\Desktop\NameSpace\” ‘ get all visible system desktop icons set result = tool.RegEnum(key1) for each icon in result name = “” on error resume next name = tool.RegRead(key1 & icon & “\”) if name = “” then name = “(unknown)” on error goto 0 msg = “Found System Icon: “ & name & vbCr msg = msg & “Do you want to change its context menu?” answer = MsgBox(msg, vBYesNo + vbQuestion) if answer = vbYes then on error resume next attrib = tool.RegRead(“HKCR\CLSID\” & icon _ & “\ShellFolder\Attributes”) if err.number=0 then attrib1 = CInt(“&H” & left(attrib,2)) else attrib1 = 0 end if if (attrib1 and 16)=0 then mode = “NOT “ else mode = “” end if msg = “RENAME is currently “ & mode & “enabled. “ _ & “Do you want to enable it?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then attrib1 = attrib1 or 16 else
444
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
attrib1 = attrib1 and not 16 end if
if (attrib1 and 32)=0 then mode = “NOT “ else mode = “” end if msg = “DELETE is currently “ & mode & “enabled. “ _ & “Do you want to enable it?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then attrib1 = attrib1 or 32 on error resume next removmsg = “” key2 = key1 & icon & “\Removal Message” removmsg = tool.RegRead(key2) on error goto 0 msg = “Please enter a removal message!” newmsg = InputBox(msg,,removmsg) tool.RegWrite key2, newmsg else attrib1 = attrib1 and not 32 end if if (attrib1 and 64)=0 then mode = “NOT “ else mode = “” end if msg = “PROPERTIES is currently “ & mode & “enabled. “ _ & “Do you want to enable it?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then attrib1 = attrib1 or 64 else attrib1 = attrib1 and not 64 end if newattrib = right(“00” & hex(attrib1), 2) & mid(attrib, 3) tool.RegWrite “HKCR\CLSID\” & icon _ & “\ShellFolder\Attributes”, newattrib, “REG_BINARY” refresh.RefreshDesktop end if next
No w, yo u c an supply any system deskto p ic o n with its o wn Delete o r Rename c o ntext menu c o mmand and leave it up to yo ur users whether o r no t they want to c usto mize their deskto ps (see Figure 15-14). Sc ript 15-10.VBS helps yo u to get bac k any system ic o n yo u might have deleted.
Chapte r 1 5 : Re gis try Twe aks
445
■
■
Figure 15-14: Add a Rename command to your Recycle Bin context menu.
Defining a removal message Deleting system ic o ns fro m the deskto p is a o ne-way street fo r mo st users, b ec ause they c an’t get system ic o ns b ac k o nc e they are deleted. The resto ratio n sc ript 15-9.VBS isn’t availab le to everyo ne. That’s why it’s a go o d idea to warn users befo re they permanently delete system ic o ns. Windo ws spo rts a built-in warning mec hanism exc lusively fo r system ic o ns (see Figure 15-15). If yo u have tried the prec eding sc ript and enabled the delete c o mmand, the sc ript has asked yo u fo r a remo val message. This message is embedded into the system ic o n warning message whenever the user c ho o ses the Delete c o mmand.
Figure 15-15: Define your ow n removal mes s age. The warning message o nly appears if yo ur rec yc le bin generally issues warning messages. Right-c lic k yo ur Rec yc le Bin and c ho o se Pro perties to enable the warning message. If the warning message is disabled, system ic o ns will be deleted immediately witho ut any further c o mments.
446
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Inserting icons into your Explorer System ic o ns no t o nly live o n yo ur deskto p. So me o f them also exist inside the My Co mputer virtual fo lder (see Figure 15-16).
Figure 15-16: Add additional s ys tem icons like the Recycle Bin into My Computer. Here, Windo ws uses the exac t same tec hnique: Again, a NameSpace key c o ntro ls whic h system ic o ns appear in My Co mputer. Use the next sc ript to c o ntro l whic h o nes are displayed: ‘ 15-12.VBS set tool = CreateObject(“regtool.tob”) set refresh = CreateObject(“registry.update”) set wshshell = CreateObject(“WScript.Shell”) key = “HKCR\CLSID\” key1 = “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\” _ & “CurrentVersion\Explorer\MyComputer\NameSpace\” ‘ enumerate all registered COM objects set result = tool.RegEnum(key) list = “Desktop COM objects:” & vbCr & vbCr for each comobject in result
Chapte r 1 5 : Re gis try Twe aks
447
■
■
‘ find object with ShellFolder subkey subkey = key & comobject & “\ShellFolder\” if tool.KeyExists(subkey) then on error resume next name = “” tip = “” name = tool.RegRead(key & comobject & “\”) tip = tool.RegRead(key & comobject & “\InfoTip”) on error goto 0 if not (name = “” and tip = “”) then if name = “” then name = “unknown” msg = “Found system icon: “ & name & vbCr if not tip=”” then msg = msg & “Additional info: “ & tip & vbCr end if if tool.KeyExists(key1 & comobject & “\”) then ‘ icon already visible msg = msg & “The icon is already visible. Do” _ & “ you want to hide it?” answer = MsgBox(msg, vbYesNoCancel + vbQuestion) if answer = vbYes then tool.RegDelete key1 & comobject & “\” refresh.RefreshDesktop end if else ‘ icon is currently hidden msg = msg & “The icon is currently hidden.” _ & “ Do you want to make it visible?” answer = MsgBox(msg, vbYesNoCancel + vbQuestion) if answer = vbYes then tool.RegWrite key1 & comobject & “\”, name refresh.RefreshDesktop end if end if if answer = vbCancel then WScript.Quit end if end if next
Why waste spac e o n yo ur deskto p? Delete the Rec yc le Bin fro m yo ur deskto p using sc ript 15-11.VBS and transfer it into yo ur MyComputer NameSpace. Here, it’s still aro und in c ase yo u need to ac c ess the Rec yc le Bin pro perties.
Controlling Windows Settings Through API Yo u do n’t need to ac c ess the Registry direc tly to find o ut ab o ut spec ific Windo ws settings o r to c hange their values. The Windo ws API c o ntains many useful func tio ns to c hange Windo ws settings direc tly, and amo ng them are a vast numb er o f func tio ns no t ac c essib le thro ugh any o ffic ial dialo g b o x.
448
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Retrieving Windows settings The SystemParametersInfo API func tio n c an bo th read and write Windo ws settings. I have designed a COM o bjec t that makes it easy fo r yo ur sc ripts to take advantage o f this and a number o f additio nal API func tio ns to c o ntro l Windo ws settings direc tly. Befo re yo u try to run any o f the sc ript examples, make sure yo u have installed the COM o bjec t ( \install\regupdate\setup.exe). Full so urc e c o de is pro vided at \components\regupdate\regupdate.vbp. Yo u c an use the fo llo wing sc ript framewo rk to ask fo r any o f the Windo ws pro perties listed in Table 15-1: ‘ 15-13.VBS set reghelper = CreateObject(“registry.update”) returntype = “boolean” retval = reghelper.GetASetting(settingID, returntype)
Full window drag: Retrieving Boolean values Fo r example, to find o ut whether o r no t Windo ws c urrently uses full windo w drag (mo ves windo ws as full windo ws instead o f gho sted o utline), lo o k up the appro priate Pro perty ID in Table 15-1. The table reveals that this pro perty c arries the ID 38. It’s a Bo o lean return value(see Figure 15-17). This is all yo u need to kno w to c usto mize the sc ript framewo rk fro m abo ve: ‘ 15-14.VBS set reghelper = CreateObject(“registry.update”) boolvar = reghelper.GetASetting(38, “boolean”) if boolvar then MsgBox “Full window drag is currently enabled.” else MsgBox “Full window drag is NOT enabled.” end if
Figure 15-17: Find out w hether full w indow drag is currently enabled on your s ys tem.
Chapte r 1 5 : Re gis try Twe aks
449
■
■
Flash count: Returning long-integer values Windo ws uses different ways o f returning the requested info rmatio n. In the previo us example, the answer was a Bo o lean variable — either true o r false. Other pro perties return lo ng-integer numbers. Fo r example, o n Windo ws 98 and 2000, yo u c an find o ut ho w many times the o perating system flashes a windo w butto n if it c an’t switc h the windo w to the fo regro und. This info rmatio n is a dword integer. Use the appro priate variable type to sto re the return value: ‘ 15-15.VBS set reghelper = CreateObject(“registry.update”) dwordvar = reghelper.GetASetting(&H2004, “long”) MsgBox “Flash count: “ & dwordvar
Desktop work area: Retrieving long-integer arrays So me info rmatio n is returned as an array. Fo r example, yo u c an find o ut the c urrent wo rk area o n-sc reen. The wo rk area is the c urrent reso lutio n minus any spac e o c c upied by the task bar(s). Windo ws returns this info rmatio n as an array o f fo ur lo ng-integer numbers: ‘ 15-16.VBS set reghelper = CreateObject(“registry.update”) coords = reghelper.GetASetting(48, “array4”) MsgBox “Work area result: “ & vbCr & coords ‘ Split up coordinates carray = Split(coords, vbCr) msg = “Work area (“ & carray(0) & “,” & carray(1) _ & “) x (“ & carray(2) & “,” & carray(3) & “)” MsgBox msg
GetASetting do esn’t return the array. Instead, it c o nverts the array members to strings and returns o ne string, using vbCr as delimiter. Yo u c an o utput the result direc tly, o r yo u c an re-c o nvert the result into an array using Split. The example sho ws bo th alternatives. Wo rking with dynamic arrays is no t trivial. The API func tio n used internally by GetASetting expec ts the array to be big eno ugh to sto re its return values. It’s c o mpletely up to yo u to spec ify the right array size. If yo u size the array to o small, c hanc es are yo ur sc ript will c rash bec ause the API func tio n will write results into memo ry that yo u do no t o wn. To play it safe, just stic k to the info rmatio n pro vided in Table 15-1. Yo u c an also always use an extra-large array that will ho ld the info rmatio n fo r sure: fo r example, “array100.”
450
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Desktop wallpaper: Reading text strings There’s o ne last variable type, and that’s text strings. On Windo ws 2000, yo u c an easily find o ut the c urrent deskto p wallpaper file. Here’s ho w to retrieve a string value: ‘ 15-17.VBS set reghelper = CreateObject(“registry.update”) wallpaper = reghelper.GetASetting(115, “string260”) MsgBox “Current wallpaper: “ & vbCr & wallpaper
In this c ase, yo ur sc ript grants the API func tio n a maximum o f 260 c harac ters o f sto rage spac e. The resulting string will be auto matic ally trunc ated to the real c harac ter c o unt. 260 is the maximum file path length, so it’s a go o d value to use as maximum.
Gaining full access to all Windows settings I’ve pro vided the fo ur pro to types o f sc ripts yo u will run into . Table 15-1 lists all info rmatio n yo ur sc ripts c an request. It also spec ifies pro perty ID and return value type, so yo u c an adjust the sample sc ripts to whic hever info rmatio n yo u need to request.
Table 15-1
Property-IDs to change W indow s Settings
Property ID
Return Type
Description
&H1000
Boolean
True: Active Window Tracking enabled. Window s activates the w indow the mous e is over. Applies to Win98/2000 only.
&H100C
Boolean
True: Window s activated through Active Window Tracking w ill be brought to the foreground.
&H2002
long
Time in millis econds s pecifying the Active Window Tracking delay.
&H1002
Boolean
True: Menus w ill be animated. Applies to Win98/2000 only.
&H1012
Boolean
True: Menus w ill us e fade effect. Fals e: Menus w ill us e s lide effect. Applies to Window s 2000 only. Valid only w hen menu animation is generally turned on.
&H1004
Boolean
True: Combo box content w ill s lide open. Applies to Window s 98/2000.
&H1006
Boolean
True: Scrolling effect for lis t boxes enabled. Applies to Win98/2000.
&H1008
Boolean
True: Window title bars us e color gradient. Applies to Win98/2000.
451
Chapte r 1 5 : Re gis try Twe aks ■
■
Property ID
Return Type
Description
&H100A
Boolean
True: Menu acces s keys are alw ays underlined. Applies to Win98/2000.
&H100E
Boolean
True: Hot tracking is enabled. The mous e s elects items it points to.
&H101A
Boolean
True: Curs or s hadow enabled.
&H2004
long
Number of times Window s flas hes a w indow button if it can’t s w itch the w indow to the foreground immediately.
&H2000
long
Amount of time, in millis econds , follow ing us er input during w hich the s ys tem does n’t allow other w indow s to s w itch in the foreground.
&H1016
Boolean
True: Tooltip animation is turned on.
&H1018
Boolean
True: Tooltips fade; fals e: Tooltips s lide in.
&H103E
Boolean
True: Animation effects for the UI are generally enabled.
1
Boolean
True: Sys tem beep enabled.
5
long
Border s ize of w indow s .
10
long
Keyboard s peed; determines how rapidly the keyboard repeats keys trokes . 0 (30 repetitions per s econd) to 31 (2.5 repetitions per s econd).
13
long
Horizontal s pacing of icons .
14
long
Number of idle s econds after w hich the s creen s aver is turned on.
16
Boolean
True: Screen s aver is generally enabled.
22
long
Keyboard delay: 0 (approx. 250 ms ) to 3 (approx. 1 s ec) keyboard delay before keys w ill be automatically repeated.
24
long
Vertical s pacing of icons .
25
Boolean
True: Icon titles w ill w rap.
27
Boolean
True: Menus are left-aligned; fals e: menus are right-aligned.
38
Boolean
True: Full w indow drag enabled.
48
array4
Returns the current w ork area as top x, y, bottom x, y.
68
Boolean
True: Us er relies on the keyboards . Softw are s how s keyboard s hortcuts w hich otherw is e may be hidden. Co ntinue d
452
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Table 15-1
( co ntinue d)
Property ID
Return Type
Description
74
Boolean
True: Font s moothing enabled. Available on Window s 95 only in conjunction w ith Plus !-Pack.
79
long
Timeout value after w hich s creen s aver enters low -pow er mode.
83
Boolean
True: Low -pow er mode of s creen s aver is enabled.
92
Boolean
True: Window s 95 + Plus !-Pack.
94
long
Enables mous e trails . 0 or 1: feature dis abled; pos itive value: number of trailing mous e images (max. 10).
95
Boolean
True: Mous e automatically is moved over the dialog default button.
98
long
Width in pixels of the mous e hover rectangle.
100
long
Height in pixels of the mous e hover rectangle.
102
long
Time in millis econds that the mous e mus t be over an object for Window s to s elect it.
104
long
Number of lines s crolled w ith each rotation of a mous e w heel.
106
long
Time, in millis econds , us ed as menu s how delay. This delay affects opening w indow s , s how ing tooltips , and s electing icons .
112
long
Speed of mous e: 1 (s low es t) to 20 (fas tes t).
114
Boolean
True: Screen s aver is currently running.
115
String
Name of current des ktop w allpaper.
&2006
long
Width of s election caret us ed as input curs or in text boxes .
Changing Windows settings Yo ur sc ripts c an also c hange Windo ws settings. Setting new values do esn’t nec essarily mean yo u see the results immediately. Whether yo u set values manually using the Registry Edito r o r thro ugh the use o f SystemParametersInfo, in either c ase the c hanges will o nly be reflec ted o nc e yo u fo rc e Windo ws to reread the Registry settings. I have pro vided the nec essary metho ds to make the c hanges happen, and they are do c umented where appro priate.
Chapte r 1 5 : Re gis try Twe aks ■
453 ■
To make c hanges easy, the registry.update c o mpo nent already inc ludes the appro priate metho d, whic h is ChangeSetting. Supply the setting ID yo u want to c hange and supply two parameters with the new values. Optio nally, yo u c an c o ntro l whether the setting sho uld be sto red permanently o r used tempo rarily. By default, ChangeSetting c hanges the values permanently. If yo u spec ify 0 as fo urth argument, the settings will no t be sto red in yo ur user pro file and will be used o nly tempo rarily.
ChangeSetting do esn’t use the same Setting IDs as GetASetting. As a rule o f thumb, add 1 to the GetASetting Setting ID pro vided in Table 15-1 to get the ID fo r c hanging the setting. Fo r example, to c o ntro l whether menus will align to the left o r right, lo o k up the Setting ID in Table 15-1. (In this c ase, it’s 27.) The ID fo r setting this value, therefo re, is 28, and belo w yo u’ll find an example o f ho w to c hange menu alignment using this ID. There are o nly very few exc eptio ns to this rule. Still, ChangeSetting ac c epts two values. Whic h o ne sho uld be used fo r the new value? Either. Try o ut bo th ways o r take a lo o k at the many examples pro vided belo w. ‘ 15-18.VBS set tool = CreateObject(“registry.update”) ‘ current menu alignment status = tool.GetASetting(27, “boolean”) if status then msg = “Menus are currently right aligned. Change?” else msg = “Menus are currently left aligned. Change?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(28, not status, 0) MsgBox “Done.” end if
Figure 15-18: Change menu alignment.
Changing icon spacing Yo u c an arrange ic o ns o n yo ur deskto p manually, o r yo u c an let Windo ws take c are o f ic o n arrangements. Yo u c o ntro l this feature by right-c lic king the deskto p: Cho o se Arrange Ic o ns and Enable Auto matic ally.
454
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
To c hange ic o n spac ing, use the fo llo wing sc ript: ‘ 15-19.VBS set tool = CreateObject(“registry.update”) ‘ read in old values: sx = tool.GetASetting(13, “long”) sy = tool.GetASetting(24, “long”) msg = “Your current icon spacing is “ & sx & “ x “ & sy & vbCr msg = msg & “Do you want to change this?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then newsx = Ask(“Your new horizontal icon spacing”, sx) newsy = Ask(“Your new vertical icon spacing”, sy) Call tool.ChangeSetting(13, newsx, 0, 1) Call tool.ChangeSetting(24, newsy, 0, 1) ‘ Make changes happen: tool.RefreshWindowMetrics MsgBox “Setting has changed!” end if function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CInt(Ask) end function
Yo ur sc ript no w c an c hange ic o n spac ing in a range muc h greater than usually allo wed by the o ffic ial dialo g bo x. To make yo ur c hanges happen, the sc ript uses the new metho d RefreshWindowMetrics. This metho d sends a message to all o pen windo ws (inc luding the deskto p), info rming it o f c hanges in the Windo w Metric s sec tio n o f the Registry. Bro adc ast messages like this o ne sho uld be sent using async hro no us messaging. SendMessageTimeout sends the message but do esn’t wait fo rever if a windo w do esn’t respo nd.
Managing Active Window Tracking Ac tive Windo w Trac king is a new feature, availab le fo r Windo ws 98 and 2000. Turned o n, it ac tivates windo ws b y merely po inting at them. Yo u c an c o mpletely c o ntro l this feature thro ugh sc ript. Aside fro m enab ling and disab ling the feature alto gether, yo u c an also determine whether o r no t the selec ted windo w jumps to the fo regro und, and ho w lo ng yo u need to po int at a windo w to selec t it ( see Figure 15-19) .
Chapte r 1 5 : Re gis try Twe aks ■
455 ■
The next sc ript sho ws ho w to implement user c o ntro ls to manage this feature. It demo nstrates bo th the use o f GetASetting (ac c o rding to the info rmatio n fo und in Table 15-1) and ChangeSetting. ‘ 15-20.VBS set tool = CreateObject(“registry.update”) ‘ current state state = tool.GetASetting(&H1000, “boolean”) if state then msg = “Active Window Tracking is currently enabled. Do you” _ & “ want to disable it?” response = MsgBox(msg, vbYesNo + vbQuestion) if response = vbYes then tool.ChangeSetting &H1001, 0, false, 1 else AskDetails end if else msg = “Active Window Tracking is currently disabled.” _ & “ Do you want to enable it?” response = MsgBox(msg, vbYesNo + vbQuestion) if response = vbYes then tool.ChangeSetting &H1001, 0, true, 1 AskDetails end if end if sub AskDetails msg = “Should the active window jump to the foreground?” response = MsgBox(msg, vbYesNo + vbQuestion) if response = vbYes then tool.ChangeSetting &H100D, 0, true, 1 else tool.ChangeSetting &H100D, 0, false, 1 end if oldtimeout = tool.GetASetting(&H2002, “long”) msg = “Specify time (in milliseconds) for activation timeout!” timeout = Ask(msg, oldtimeout) tool.ChangeSetting &H2003, 0, timeout, 1 end sub
function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CInt(Ask) end function
456
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Figure 15-19: Manage Active Window Tracking.
Changing window borders By default, Windo ws uses a 1-pixel windo w frame aro und eac h windo w. The windo w frame do esn’t have to be this size, tho ugh. It’s easy to enlarge it: ‘ 15-21.VBS set tool = CreateObject(“registry.update”) ‘ current status of beep status = tool.GetASetting(5, “long”) msg = “Current window border size: “ & status & vbCr msg = msg & “Do you want to change the setting?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then newsize = Ask(“New window border size”,status) call tool.ChangeSetting(6, newsize, 0) MsgBox “Done.” end if function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CInt(Ask) end function
Figure 15-20: Expand w indow frames and color-code the active w indow.
Chapte r 1 5 : Re gis try Twe aks
457
■
■
Changing window colors Why wo uld anybo dy c hange the windo w frame size? There are a c o uple o f go o d reaso ns. Fo r example, yo u may find it easier to hit the frame with yo ur mo use po inter. Ano ther go o d reaso n is to better mark the ac tive windo w. Spec ify different c o lo rs fo r ac tive and inac tive windo w frames. The next sc ript sho ws yo u ho w to c hange windo w frame c o lo rs: ‘ 15-22.VBS set tool = CreateObject(“registry.update”) oldactive = tool.GetSystemColor(10) oldinactive = tool.GetSystemColor(11) ‘ change colors tool.SetSystemColor 10, &H00FF00 tool.SetSystemColor 11, &HFF0000 msg = “Changed window frame colors. You can only see the colors if “ _ & “you have expanded the window frame to more than 1 pixel “ _ & “width. Do you want to keep the new colors?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbNo then tool.SetSystemColor 10, oldactive tool.SetSystemColor 11, oldinactive MsgBox “Old color values restored.” end if
Changing windo w c o lo rs is disc ussed in mo re depth later. I’ve pro vided this example o nly to demo nstrate ho w windo w bo rder enlargement c an be used to display c o lo red windo w frames. Changing windo w c o lo rs (and o ther system c o lo rs) uses a different tec hnique. It’s no t do ne by SystemParametersInfo.
Controlling the system beep On systems witho ut a so und c ard, Windo ws uses the internal speaker to beep whenever so mething exc iting happens. Systems with so und c ards installed use the so und sc hemes instead. To c o ntro l the internal speaker, use this sc ript: ‘ 15-23.VBS set tool = CreateObject(“registry.update”) ‘ current status of beep status = tool.GetASetting(1, “boolean”) if status then msg = “System Beep is enabled. Do you want to disable it?” else
458
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
msg = “System Beep is disabled. Do you want to enable it?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(2, not status, 0) MsgBox “Done.” end if
Using Icon Title Wrap Lo ng ic o n names are trunc ated auto matic ally so they wo n’t interfere with neighbo r ic o ns. Ho wever, yo u c an spec ify whether o r no t Windo ws uses a wrapping tec hnique to c o ntinue the ic o n title in the next line. ‘ 15-24.VBS set tool = CreateObject(“registry.update”) ‘ current status of beep status = tool.GetASetting(25, “boolean”) if status then msg = “Icon Title Wrap is enabled. Do you want to disable it?” else msg = “Icon Title Wrap is disabled. Do you want to enable it?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(26, not status, 0) MsgBox “Done.” end if
Controlling Screen Savers Sc reen savers are spec ial exec utables c arrying the *.scr file extensio n. They are sto red in the Windo ws system fo lder. Yo ur sc ripts c an c hange many internal sc reen saver settings and even launc h sc reen savers.
Launching screen savers Launc hing sc reen savers is easy — just use the WScript.Shell Run metho d and spec ify the sc reen saver name: ‘ 15-25.VBS set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “””%windir%\system32\sspipes.scr”””
Chapte r 1 5 : Re gis try Twe aks
459
■
■
Change the sc ript and supply a sc reen saver name that is c urrently installed o n yo ur system. Searc h fo r *.scr to see all c urrently installed sc reen savers. This way, yo u c an ac c ess any sc reen saver lo c ated anywhere o n yo ur system. Maybe yo u wo uld muc h rather ac tivate the c urrent sc reen saver. Just query the Registry: ‘ 15-26.VBS set wshshell = CreateObject(“WScript.Shell”) ‘ retrieve screen saver on error resume next exepath = “” exepath = wshshell.RegRead(“HKCU\Control Panel\Desktop\SCRNSAVE.EXE”) on error goto 0 if exepath=”” or lcase(exepath) = “(none)” then MsgBox “No screen saver specified.” else wshshell.Run “””” & exepath & “””” end if
This time, the sc ript auto matic ally starts the c urrently selec ted sc reen saver. All the o ther sc reen-saver-related info rmatio n is sto red at the same lo c atio n: HKCU\Control Panel\Desktop\. Either ac c ess this info rmatio n direc tly o r use the API func tio ns.
Temporarily disabling screen savers Maybe yo ur sc ript wants to make sure the sc reen saver is disabled. This may be nec essary fo r maintenanc e sc ripts that c hec k the hard disk’s integrity using to o ls like Sc anDisk. During Sc anDisk and Defrag o peratio ns, no o ther so ftware may c hange the hard disk’s c o ntents, but advanc ed sc reen savers do . Ho w c an yo u make sure no sc reen saver jumps in fro nt and messes up yo ur maintenanc e wo rk effo rts? Tell Windo ws: ‘ 15-27.VBS set tool = CreateObject(“registry.update”) ‘ current status of screen saver status = tool.GetASetting(16, “boolean”) if status then ‘ temporarily disable screen saver call tool.ChangeSetting(17, false, 0) end if MsgBox “Your screen saver is now disabled for sure. You could now” _ & “ safely run your disk tools. Check your screen saver “ _
460
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
& “property page to see that the screen saver really is “ _ & “disabled. Click OK to return to previous state.” ‘ restore previous state call tool.ChangeSetting(17, status, 0) MsgBox “Previous screen saver state restored.”
Setting screen saver timeout Yo u c an also c hange the sc reen saver timeo ut. Here’s an example: ‘ 15-28.VBS set tool = CreateObject(“registry.update”) ‘ current timeout timeout = tool.GetASetting(14, “long”) ‘ set new timeout newtimeout = Ask(“Specify new timeout in seconds!”, timeout) call tool.ChangeSetting(15, newtimeout, 0) ‘ activate screen saver active = tool.GetASetting(16, “boolean”) if not active then answer = MsgBox(“Do you want to enable your screen saver?”, _ vbYesNo + vbQuestion) if answer=vbYes then call tool.ChangeSetting(17, true, 0) end if function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CInt(Ask) end function
If no sc reen saver is c urrently selec ted, Windo ws returns an “ac tive” sc reensaver status. Yo ur o nly way to determine whether o r no t a sc reen saver is spec ified is querying the SCRRUN.EXE key as o utlined in the previo us sc ript. The o ffic ial dialo g bo x lets yo u spec ify a sc reen saver timeo ut in units o f minutes o nly. This is why the minimum is fixed to 60 sec o nds. Yo ur sc ript c an set a sc reen-saver timeo ut up to the sec o nd, altho ugh this rarely makes sense. Fo r example, spec ifying a timeo ut o f 1 wo uld start the sc reen saver all the time — useful o nly fo r sabo tage purpo ses. Spec ifying a timeo ut value belo w 1 disables the sc reen saver.
Chapte r 1 5 : Re gis try Twe aks ■
461 ■
Finding out if a screen saver runs Yo ur sc ript c an even find o ut whether a sc reen saver is c urrently running. Have a lo o k: ‘ 15-29.VBS set tool = CreateObject(“registry.update”) ‘ screen saver running? ‘ check for 2 minutes for x=1 to 60 scr = tool.GetASetting(114, “boolean”) if scr then MsgBox “Screen Saver kicked in!” exit for end if ‘ wait 2 sec WScript.Sleep 2000 next
Pro vided yo ur sc reen saver kic ks in within two minutes, the sc ript will display a message the mo ment the sc reen saver is ac tivated.
Fooling Windows and disabling CTRL+ALT+DEL What seemed like a funny c urio sity in the previo us example do es have real-wo rld signific anc e. Yo ur sc ript c an also set the state o f the sc reen saver. Setting the sc reen saver state do esn’t ac tually start the sc reen saver (see Figure 15-21). It just fo o ls Windo ws into thinking a sc reen saver is running. On Windo ws 9.x, this has many c o nsequenc es. Fo r example, while a sc reen saver is running, yo u c an’t use CTRL+ALT+DEL to get to the task list and c lo se do wn pro grams. So to disable this key c o mbinatio n, use the fo llo wing sc ript: ‘ 15-30.VBS set tool = CreateObject(“registry.update”) ‘ make windows think a screen saver was running call tool.ChangeSetting(97, true, 0) MsgBox “CTRL+ALT+DEL disabled on Windows 95/98!” ‘ revert to normal call tool.ChangeSetting(97, false, 0)
Changing screen saver settings Ho w c an yo u c o nfigure the ac tive sc reen saver? It’s fairly easy: Eac h sc reen saver exec utable c o ntains its o wn set o f dialo g bo xes to c o nfigure the internal sc reen saver settings. Ho wever, it’s no t easy to get to these dialo g bo xes.
462
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
If yo u run a sc reen saver direc tly, it will display its c o nfiguratio n settings. To ac tivate the sc reen saver, use the sec ret o ptio n /S. Unfo rtunately, in the Windo ws Registry, scr files are registered to use the /S o ptio n by default. This is why yo u c an’t supply o ptio ns to the sc reen saver using the WScript.Shell Run metho d. There is a sec ret way to supply o ptio ns to sc reen savers. Instead o f using the WScript.Shell Run metho d, use the Run metho d yo u develo ped in Chapter 11 instead. The differenc e is: The WScript.Shell Run metho d lo o ks up the file path and starts the asso c iated pro gram. This is why this metho d c an launc h do c uments, to o . Yo ur o wn Run metho d launc hes the so ftware direc tly. Make sure yo u have installed yo ur COM extensio n: (pro c ess). See Chapter 11 fo r mo re details. ‘ 15-31.VBS set proc = CreateObject(“process.id”) set wshshell = CreateObject(“WScript.Shell”) ‘ retrieve screen saver on error resume next exepath = “” exepath = wshshell.RegRead(“HKCU\Control Panel\Desktop\SCRNSAVE.EXE”) on error goto 0 if exepath=”” or lcase(exepath)=”(none)” then MsgBox “No screen saver specified.” else proc.Run “””” & exepath & “””” end if
Figure 15-21: Invoke the property dialog box of the current s creen s aver. This sc ript displays the sc reen saver settings if a sc reen saver was spec ified. To pro ve the o ptio n theo ry, yo u just need to replac e o ne line. Change proc.Run “””” & exepath & “”””
Chapte r 1 5 : Re gis try Twe aks
463
■
■
with proc.Run “””” & exepath & “”” /S”
No w, yo ur sc ript runs the sc reen saver. This is the default fo r scr files.
Installing new screen savers Yo u c an even c hange the c urrent sc reen saver o r install o ne if no ne is spec ified. Under no rmal c o nditio ns, yo u’d use the Co ntro l Panel to install new sc reen savers. But did yo u kno w that yo u c an ac c ess the Co ntro l Panel func tio ns direc tly, to o ? Here’s an example. It mimic s the sc reen saver Install c o ntext menu c o mmand: ‘ 15-32.VBS set wshshell = CreateObject(“WScript.Shell”) name = InputBox(“Please enter path of screen saver!”,,”logon.scr”) if name = vbEmpty then WScript.Quit command = “rundll32.exe desk.cpl,InstallScreenSaver “”” & name _ & “””” wshshell.Run command
The sc ript invo kes the sc reen saver dialo g bo x and preselec ts the sc reen saver yo u spec ified. If yo u did no t spec ify a valid scr file, no sc reen saver will be spec ified.
Controlling low-power screen saver features Windo ws allo ws the sc reen saver to enter a spec ial po wer-saving mo de when the sc reen saver runs fo r a spec ific time. Here’s ho w to c o ntro l the po wer-saving feature: ‘ 15-34.VBS set tool = CreateObject(“registry.update”) ‘ current status powersave = tool.GetASetting(83, “boolean”) if powersave then msg = “Power Save Mode currently enabled. Disable?” else msg = “Power Save Mode currently disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion)
464
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
if answer = vbYes then powersave = not powersave call tool.ChangeSetting(85, Abs(CInt(status)), 0) end if if powersave then timeout = tool.GetASetting(79, “long”) msg = “Current timeout is “ & timeout & “ seconds. Change?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then newtimeout = Ask(“Specify new timeout in seconds!”, timeout) call tool.ChangeSetting(81, newtimeout, 0) end if end if MsgBox “Done.” function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CInt(Ask) end function
Yo ur sc ript c an c hange the po wer-o ff timeo uts up to the sec o nd. The o ffic ial dialo g b o x, in c o ntrast, o ffers o nly selec ted timeo ut values. If yo u c ho o se a timeo ut value no t listed in the o ffic ial dro p-do wn list, the list will sho w a b lank entry. To ac tivate po wer-o ff features right away, set the po wer-o ff timeo ut tempo rarily to 1 sec o nd, wait 2 sec o nds using WScript.Sleep 2000, and reset the o riginal value.
Powering of f devices The po wer-saving features inc lude two phases o f po wer saving: a lo w-po wer phase and a po wer-o ff phase. The previo us sc ript c o ntro lled the lo w-po wer phase. To manage the po wer-o ff phase, use the values in Table 15-2 instead:
Table 15-2
Property IDs for Pow er-Saving Features
ID
Description
84
Determines if PowerOff is active
86
Sets PowerOff activation
80
Determines PowerOff timeout
82
Sets PowerOff timeout
465
Chapte r 1 5 : Re gis try Twe aks ■
■
Animations and Visual Ef fects Windo ws uses an ever-inc reasing number o f visual effec ts, and Windo ws 2000, as the latest Windo ws family member, to ps all o f this by fading menus and c urso r shado ws. Fo rtunately, it’s up to yo u whic h effec ts yo u find useful and whic h effec ts yo u prefer to turn o ff. After all, visual effec ts eat up CPU po wer, altho ugh no serio us impac t is no tic eable.
Turning of f visual ef fects altogether Windo ws 2000 uses so many visual effec ts that Mic ro so ft dec ided to implement a way to disable them alto gether. No te that the next example wo rks o nly o n Windo ws 2000. On all o ther Windo ws versio ns, yo u need to disable the visual effec ts individually, as sho wn later. ‘ 15-35.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H103E, “boolean”) if status then msg = “Visual effects enabled. Do you want to disable them?” else msg = “Visual effects disabled. Do you want to enable them?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H103F, 0, not status) MsgBox “Done.” end if
Overview: Visual ef fects built into Windows Table 15-3 lists all the visual effec ts built into Windo ws. The table also reveals whic h effec ts are available o n whic h Windo ws versio n.
Table 15-3
Visual Effects Used to Enhance the User Interface
Effect
Description
ComboBox
Win98/2000: Combo boxes s lide open.
Curs or Shadow
Win2000: Curs or drops a s hadow.
Gradient Captions
Win98/2000: Window captions us e a s mooth color gradient ins tead of s olid color. Co ntinue d
466
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Table 15-3
( co ntinue d)
Effect
Description
Hot Tracking
Win98/2000: Window is s elected merely by pointing at it. More about this feature has already been dis cus s ed above.
Lis t Box
Win98/2000: Lis t boxes us e a s liding animation.
Menu Animation
Win98/2000: Menus us e s liding or fading animation.
Menu Underlines
Win98/2000: Menus s how keyboard s hortcut underlines only if menu is s elected. Works only in s elected applications . Older applications s how menu underlines all the time.
Selection Fade
Win2000: Selected menu item remains on-s creen briefly w hile fading out after the menu is clos ed.
Tooltip Animation
Win2000: Enables tooltips to s lide in or fade in.
Full Window Drag
Win95Plus/98/2000: Window s are moved completely w ith content.
Font Smoothing
Win95Plus /98/2000: Text characters are s moothened by us ing anti-alias ing techniques . Works only if all graphics cards us e more than 256 colors .
Combo box animation Co mbo bo x animatio n lets c o mbo bo x c o ntents slide o ut smo o thly. Ho wever, yo u c an always enable rapidly appearing c o mbo bo xes using this sc ript: ‘ 15-36.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H1004, “boolean”) if status then msg = “Combo Box animation enabled. Disable?” else msg = “Combo Box animation disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H1005, 0, not status) MsgBox “Done.” end if
Chapte r 1 5 : Re gis try Twe aks ■
467 ■
Cursor shadow Windo ws 2000 uses a c urso r shado w by default. The c urso r appears to be abo ve the deskto p, and it’s easier to rec o gnize than the c urso r arro w. If yo u prefer the o ld-fashio ned c urso r style, disable the shado w: ‘ 15-37.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H101A, “boolean”) if status then msg = “Cursor shadow animation enabled. Disable?” else msg = “Cursor shadow animation disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H101B, 0, not status) MsgBox “Done.” end if
Gradient captions Windo ws 98 and 2000 use c o lo r-gradients in the windo w title bar so that c o lo rs are blended fro m o ne c o lo r to ano ther (see Figure 15-22). If yo u do n’t like this, yo u do n’t have to live with it. ‘ 15-38.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H1008, “boolean”) if status then msg = “Gradient captions enabled. Disable?” else msg = “Gradient captions disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H1009, 0, not status) MsgBox “Done.” end if
468
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Figure 15-22: Enable or dis able color gradient captions .
List box animation List bo x animatio n lets the c o ntent slide do wn while yo u sc ro ll. Again, this feature is o ptio nal, and the fo llo wing sc ript allo ws yo u to turn it o ff: ‘ 15-39.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H1006, “boolean”) if status then msg = “List Box animation enabled. Disable?” else msg = “List Box animation disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H1007, 0, not status) MsgBox “Done.” end if
Menu animation Menu animatio ns were first intro duc ed by Windo ws 98 and expanded by Windo ws 2000. While this feature is turned o n, menus elegantly slide into view. Beginning with Windo ws 2000, yo u have the c ho ic e between two animatio n styles — sliding animatio ns and fading animatio ns. The sc ript no t o nly c o ntro ls the animatio n but also lets yo u c ho o se between animatio n styles. Tho se styles will o nly sho w effec t if yo u are using Windo ws 2000, tho ugh. ‘ 15-40.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H1002, “boolean”) if status then msg = “Menu animation enabled. Disable?” else msg = “Menu animation disabled. Enable?” end if
Chapte r 1 5 : Re gis try Twe aks
469
■
■
answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then status = not status call tool.ChangeSetting(&H1003, 0, status) end if if status then anim = tool.GetASetting(&H1012, “boolean”) if anim then animtype = “fading” else animtype = “sliding” end if msg = “On Windows 2000, you may choose between animation styles.” msg = msg & vbCr & “Currently, your system uses “ _ & animtype & “ animation.” & vbCr msg = msg & “Do you want to switch?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H1013, 0, not anim) end if end if MsgBox “Done.”
Menu underlines Menus indic ate keybo ard sho rtc uts by underlining the key in the menu name. If yo u do n’t use keybo ard sho rtc uts o ften, yo u might find it better to disable suc h sho rtc uts. If yo u do use them o ften, keybo ard sho rtc uts will o nly appear o nc e the menu is selec ted: fo r example, by pressing [F10]. The menu underline feature depends o n the so ftware yo u are running. Older so ftware do esn’t c are abo ut this feature and sho ws keybo ard sho rtc uts no matter what. ‘ 15-41.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H100A, “boolean”) if status then msg = “Menu Underline always shown. Enable?” else msg = “Menu Underline only shown when menu active. Disable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H100B, 0, not status) MsgBox “Done.” end if
470
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Menu show delay Windo ws uses an internal c o unter to delay the o pening o f menus. This is impo rtant fo r menus to remain o pen even if yo u ac c identally po int to so me o ther o bjec t. Here’s ho w yo u c o ntro l the delay: ‘ 15-42.VBS set tool = CreateObject(“registry.update”) delay = tool.GetASetting(106, “long”) msg = “Enter new menu delay in milliseconds!” newdelay = Ask(msg, delay) call tool.ChangeSetting(107, newdelay, 0) MsgBox “Done.” function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CLng(Ask) end function
Cho o sing a delay o f 100 millisec o nds will pro duc e rapidly o pening menus, at the pric e o f rapidly c lo sing menus the mo ment yo ur mo use leaves the menu. On the o ther hand, a delay o f 65,500 millisec o nds turns o ff auto matic menu o pening. To o pen submenus, yo u no w have to c lic k the menu item. 400 millisec o nds is the default value. Menu sho w delay serves a dual purpo se o n Windo ws 98 mac hines. If yo u have c o nfigured Explo rer to selec t ic o ns by po inting at them (instead o f c lic king), the menu sho w delay determines ho w lo ng yo u have to po int at the o bjec t befo re it will be selec ted. Obvio usly, spec ifying a menu sho w delay o f mo re than 1,000 millisec o nds (o ne sec o nd) will generate a c o nflic t. On Windo ws 2000, this pro blem has been reso lved, and o bjec t selec tio n do esn’t interfere anymo re with menu sho w delay. Iro nic ally, o n Windo ws 98, c hanges are reflec ted fo r o bjec t selec tio n immediately, whereas yo u need to restart explorer.exe o r Windo ws to ac tivate the menu delay.
Specifying mouse hover timeout On Windo ws 2000, Mic ro so ft has finally divided menu sho w delay and mo use ho vering delay. Mo use ho vering delay determines ho w lo ng yo u have to po int at so me o b jec t to get it selec ted. Mo use ho vering c an b e enab led and disab led using the Explo rer settings. Here’s ho w to set and c hange the mo use ho vering delay: ‘ 15-43.VBS set tool = CreateObject(“registry.update”)
Chapte r 1 5 : Re gis try Twe aks
471
■
■
delay = tool.GetASetting(102, “long”) msg = “Enter new mouse hover delay in milliseconds!” newdelay = Ask(msg, delay) call tool.ChangeSetting(103, newdelay, 0) MsgBox “Done.” function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CLng(Ask) end function
Mo use ho vering wo rks o nly if the windo w the o bjec t is c o ntained in is the ac tive windo w. Fo r example, if yo u c an’t selec t deskto p ic o ns by po inting at them, c lic k the deskto p first. This way, it bec o mes the ac tive windo w, and mo use ho vering wo rks fine.
Selection fade With Windo ws 2000, whenever yo u selec t a menu c o mmand, it will remain visib le fo r a small perio d o f time after the menu has already c lo sed, and then it will fade o ut. This effec t is c alled Selection Fade and is suppo sed to underline whic h menu c o mmand yo u have c ho sen. Turn it o n o r o ff as yo u like: ‘ 15-44.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H1014, “boolean”) if status then msg = “Selection Fade enabled. Disable?” else msg = “Selection Fade disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H1015, 0, not status) MsgBox “Done.” end if
Tooltip animation To o ltips are little info rmatio n windo ws. If yo u po int yo ur mo use at so me o bjec t, c hanc es are a to o ltip will display additio nal info rmatio n abo ut this o bjec t. Whether o r no t to o ltips appear fo r deskto p items is c o ntro lled by yo ur fo lder o ptio ns. Clic k the View tab and selec t the To o ltip o ptio n to enable the deskto p item To o ltips.
472
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
To o ltips c an be animated (see sc ript 15-46.VBS). They suppo rt the same general animatio n tec hniques as menus. On Windo ws 98, to o ltip animatio n slides in the tip windo ws. On Windo ws 2000, yo u have the c ho ic e between sliding and fading animatio n: ‘ 15-46.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(&H1016, “boolean”) if status then msg = “Tooltip animation enabled. Disable?” else msg = “Tooltip animation disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then status = not status call tool.ChangeSetting(&H1017, 0, status) end if if status then anim = tool.GetASetting(&H1018, “boolean”) if anim then animtype = “fading” else animtype = “sliding” end if msg = “On Windows 2000, you may choose between animation styles.” msg = msg & vbCr & “Currently, your system uses “ _ & animtype & “ animation.” & vbCr msg = msg & “Do you want to switch?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(&H1019, 0, not anim) end if end if MsgBox “Done.”
Changing the text of tooltips Yo u c an c hange the to o ltip desc riptio n, to o . The desc riptio n is sto red in a value c alled Info Tip. The next sc ript searc hes all registered COM o bjec ts fo r this value and allo ws yo u to c hange the desc riptio n (see Figure 15-23). This sc ript c hanges the default mac hine-wide settings. Yo ur new to o ltip desc riptio ns apply to all users. Per-user settings are po ssible o nly o n Windo ws 2000. Here, sto re the new desc riptio n in the HKEY_CURRENT _USER branc h.
Chapte r 1 5 : Re gis try Twe aks ■
473 ■
‘ 15-47.VBS set tool = CreateObject(“regtool.tob”) set refresh = CreateObject(“registry.update”) ‘ get access to registered COM objects set comobjects = tool.RegEnum(“HKCR\CLSID\”) for each comobject in comobjects key = “HKCR\CLSID\” & comobject & “\” if tool.KeyExists(key & “InfoTip”) then name = “” tip = “” on error resume next name = tool.RegRead(key) tip = tool.RegRead(key & “InfoTip”) if name = “” then name = “(unknown)” on error goto 0 msg = “Found COM object: “ & name & vbCr msg = msg & “Tooltip Text: “ & tip & vbCr msg = msg & “Do you want to change the description?” answer = MsgBox(msg, vbYesNoCancel + vbQuestion) if answer = vbCancel then WScript.Quit elseif answer = vbYes then msg = “Please enter new description!” newname = InputBox(msg,,tip) if newname = vbEmpty then WScript.Quit else tool.RegWrite key & “InfoTip”, newname MsgBox “Changed description” refresh.RefreshDesktop end if end if end if next
Figure 15-23: Change tooltips and s pecify the text yours elf.
474
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Full window drag On slo w c o mputers, it takes to o muc h CPU po wer to refresh the windo w c o ntents while yo u mo ve them. This is why o lder Windo ws versio ns use gho sted windo w bo rders during drag o peratio ns. Beginning with Windo ws 95 Plus!, Windo ws also suppo rts full windo w drag. It’s enabled by default o n Windo ws 98 and 2000. Yo u c an manually c o ntro l this setting: ‘ 15-48.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(38, “boolean”) if status then msg = “Full Window Drag enabled. Disable?” else msg = “Full Window Drag disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(37, Abs(CInt(not status)), 0) MsgBox “Done.” end if
Font smoothing Fo nt smo o thing was intro duc ed with Windo ws 95 Plus! and is a standard feature in Windo ws 98 and 2000. Fo nt smo o thing uses an o ptic al tric k to pro duc e c rispy text, thro ugh a tec hnique c alled anti-aliasing. It smo o thes o ut jaggy c harac ters by inserting additio nal pixels o f different shades. Fo nt smo o thing needs a c o nsiderable amo unt o f extra c o lo rs to “fill in” the jaggy c harac ter o utlines. Therefo re, to use this feature, yo ur graphic s adapter needs to suppo rt mo re than 256 c o lo rs. On multi-display systems, fo nt smo o thing is disabled auto matic ally the mo ment o ne o f the graphic s adapters uses 256 c o lo rs o r less. This is bec ause fo nt smo o thing is a system-wide setting and c anno t be limited to individual displays. ‘ 15-49.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(74, “boolean”) if status then msg = “Font smoothing enabled. Disable?” else msg = “Font smoothing disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(75, Abs(CInt(not status)), 0) MsgBox “Done.” end if
Chapte r 1 5 : Re gis try Twe aks ■
475 ■
Setting blinking text cursor width On Windo ws 2000, yo u c an c hange the size o f the blinking text input c urso r. By default, this c urso r uses a 1-pixel width. If yo u prefer a blo c k c urso r, spec ify a width o f 10 (see Figure 15-24): ‘ 15-50.VBS set tool = CreateObject(“registry.update”) caret = tool.GetASetting(&H2006, “long”) newcaret = Ask(“Specify new caret width!”, caret) call tool.ChangeSetting(&H2007, 0, newcaret) MsgBox “New caret width enabled. This only applies to Win2000!” function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CInt(Ask) end function
Figure 15-24: Change the curs or w idth and get an old-s tyle block curs or.
Specifying a new desktop wallpaper Yo ur sc ript c an even c hange the deskto p wallpaper. Drag any .bmp file o nto the fo llo wing sc ript ic o n to install it as new deskto p wallpaper: ‘ 15-51.VBS set args = WScript.Arguments if args.Count=0 then MsgBox “Please drag bmp files on my icon!” WScript.Quit end if if not lcase(right(args(0),3))=”bmp” then
476
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
MsgBox “I only accept bmp files!” WScript.Quit end if set tool = CreateObject(“registry.update”) call tool.ChangeSetting(20, 0, args(0)) MsgBox “New wallpaper enabled!”
Changing the wallpaper mode There’s no direc t API func tio n to set the wallpaper mo de. Changing wallpaper with the help o f the previo us sc ript will c hange the wallpaper file o nly. It wo n’t c hange the wallpaper style, and so yo ur wallpaper may appear o nly as a small pic ture c entered o n-sc reen. Ho wever, yo u c an c o mbine yo ur new wallpaper c o mmand with yo ur Registry metho ds, by setting the wallpaper mo de direc tly inside o f the Registry and then c alling yo ur wallpaper metho d to update the setting. To make things a little mo re c o mplex, Windo ws sto res the wallpaper mo de in two different settings. TileWallpaper determines whether the wallpaper is tiled o r displayed as a single image. WallpaperMode determines whether the image is displayed in o riginal size o r stretc hed to fit the sc reen. The fo llo wing sc ript c o nverts the wallpaper settings to a single number between 0 and 2. Changing the wallpaper style direc tly wo n’t do a thing to yo ur display. In o rder to make the c hange happen, yo u need to reset the wallpaper using the API c all. Bec ause the sc ript wants to c hange the wallpaper style o nly, it first retrieves the c urrent wallpaper using GetWallpaper, c hanges wallpaper style, and then resets the wallpaper to the same wallpaper c urrently enabled. This way, o nly wallpaper style is c hanged. ‘ 15-52.VBS set tool = CreateObject(“registry.update”) set wshshell = CreateObject(“WScript.Shell”) ‘ get current wallpaper settings wallpaper = GetWallpaper mode = GetWallpaperMode if wallpaper = “” then MsgBox “Sorry, currently no wallpaper specified!” WScript.Quit end if ‘ cycle through modes for x= 0 to 2 SetWallpaperMode x SetWallpaper wallpaper MsgBox “Wallpaper Mode “ & x, vbSystemModal next
Chapte r 1 5 : Re gis try Twe aks ■
477 ■
‘ restore old settings: SetWallpaperMode mode SetWallpaper wallpaper function SetWallpaper(newpaper) call tool.ChangeSetting(20, 0, newpaper) end function function GetWallpaper key = “HKCU\Control Panel\Desktop\Wallpaper” on error resume next GetWallpaper = wshshell.RegRead(key) end function sub SetWallpaperMode(mode) key1 = “HKCU\Control Panel\Desktop\WallpaperStyle” key2 = “HKCU\Control Panel\Desktop\TileWallpaper” on error resume next select case mode case 0: ‘ original size, no tiling wshshell.RegWrite key1, 0 wshshell.RegWrite key2, 0 case 1: ‘ center on screen: wshshell.RegWrite key1, 0 wshshell.RegWrite key2, 1 case 2: ‘ stretch wshshell.RegWrite key1, 2 wshshell.RegWrite key2, 0 case else MsgBox “Specify wallpaper mode 0-2!” WScript.Quit end select end sub function GetWallpaperMode key1 = “HKCU\Control Panel\Desktop\WallpaperStyle” key2 = “HKCU\Control Panel\Desktop\TileWallpaper” on error resume next mode1 = wshshell.RegRead(key1) mode2 = wshshell.RegRead(key2) on error goto 0 if mode1=0 and mode2=0 then GetWallpaperMode = 0 elseif mode1=0 and mode2=1 then GetWallpaperMode = 1 elseif mode1=2 and mode2=0 then GetWallpaperMode = 2 else MsgBox “Unknown wallpaper mode: “ & mode1 & “/” & mode2 end if end function
478
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Enabling “Snap-To-Button” Did yo u kno w that Windo ws 2000 c an help yo u deal with dialo g bo xes? Instead o f navigating to the butto ns and dragging the mo use po inter o ver yo ur entire deskto p to get there, have Windo ws plac e the mo use c urso r o ver any dialo g bo x’s default butto n. This feature is c alled SnapToDefButton. The next sc ript c an enable (and disable) the feature. It’s disabled by default: ‘ 15-53.VBS set tool = CreateObject(“registry.update”) status = tool.GetASetting(95, “boolean”) if status then msg = “Snap-To-Default enabled. Disable?” else msg = “Snap-To-Default disabled. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then call tool.ChangeSetting(96, Abs(CInt(not status)), 0) MsgBox “Done.” end if
Mic ro so ft states that the snapping feature is available o n Windo ws 98, NT4, and Windo ws 2000. Ho wever, o n my test systems, it wo rked o nly with Windo ws 2000. Yo u c an c hec k it o ut o n yo ur system by using the previo us sc ript to enable the feature, and then run the sc ript again. If it still repo rts a disabled state, the feature isn’t suppo rted o n yo ur system. Internally, Windo ws sto res the setting in HKCU\Sontrol Panel\ Mouse\SnapToDefaultButton.
More Undocumented Registry Tweaks Of c o urse, this b o o k c an o nly c o ver a frac tio n o f the undo c umented Registry settings availab le. Therefo re, this c hapter fo c uses o n ho w to find o ut undo c umented settings fo r yo urself, and ho w to c reate sc ripts c o ntro lling these features. There are two mo re c o nc epts I’d like to share with yo u. First, yo u learn ho w the Registry manages the sho rtc ut arro w. Next, yo u disc o ver so me new Registry tweaks available o nly o n Windo ws 2000. Take them as templates fo r yo ur o wn experiments and findings.
Getting rid of shortcut arrows Sho rtc ut arro ws appear in the lo wer-left c o rner o f sho rtc ut ic o ns. Ac tually, the sho rtc ut arro w is an o verlay ic o n plac ed o n to p o f the regular ic o n. So , yo u c an bo th disable and c hange the o verlay ic o n.
Chapte r 1 5 : Re gis try Twe aks ■
479 ■
Sho rtc ut arro ws are c o ntro lled by a Registry value c alled isShortcut. Any file that c arries this internal tag displays the sho rtc ut arro w o verlay. To get rid o f it, yo u need to do two things. First, delete the isShortcut value. Next, have Windo ws update its internal ic o n c ac he. The next sc ript demo nstrates an easy so lutio n: It allo ws yo u to turn the sho rtc ut o verlay o n and o ff. The sc ript uses the Registry extensio n disc ussed in the previo us c hapter. Make sure yo u have installed the COM o bjec t — \install\registry\setup.exe. ‘ 15-54.VBS set reg = CreateObject(“regtool.tob”) key = “HKCR\lnkfile\isShortcut” if reg.KeyExists(key) then msg = “Shortcut arrows visible. Do you want to hide arrows?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then reg.RegDelete(key) call reg.FlushIconCache MsgBox “Done.” end if else msg = “Shortcut arrows invisible. Do you want to enable arrows?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then reg.RegWrite key, “” call reg.FlushIconCache MsgBox “Done.” end if end if
No te that the Registry extensio n already inc ludes the nec essary metho d, c alled FlushIconCache, fo r refreshing the ic o n c ac he. This metho d tempo rarily c hanges ic o n size, so there may be so me sc reen flic ker. This sc ript manages regular Windo ws sho rtc uts o nly. DOS sho rtc uts remain unto uc hed. If yo u want to manage DOS sho rtc uts, c hange the Registry key: Replac e lnkfile with piffile. That’s all.
Shortcut arrows for any files The sho rtc ut arro w o verlay is so versatile yo u c an use it fo r any file type. Altho ugh this rarely makes sense, it’s still an interesting feature. The next sc ript asks fo r the file extensio n yo u want to c o ntro l. Yo u then have the o ppo rtunity to turn the sho rtc ut o verlay o n o r o ff. ‘ 15-55.VBS set reg = CreateObject(“regtool.tob”) ext = InputBox(“Please enter the file extension you want “ _ & “to control!”,,”.doc”) if ext = vbEmpty then WScript.Quit
480
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
if not left(ext,1)=”.” then ext = “.” & ext key = “HKCR\” & ext & “\” if not reg.KeyExists(key) then MsgBox “the file type you specified is not registered.” WScript.Quit end if mainkey = “HKCR\” & reg.RegRead(key) & “\” if not reg.KeyExists(mainkey) then MsgBox “the file type you specified isn’t properly registered!” WScript.Quit end if scutkey = mainkey & “isShortcut” if reg.KeyExists(scutkey) then msg = “Shortcut arrows visible. Do you want to hide arrows?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then reg.RegDelete(scutkey) call reg.FlushIconCache MsgBox “Done.” end if else msg = “Shortcut arrows invisible. Do you want to enable arrows?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then reg.RegWrite scutkey, “” call reg.FlushIconCache MsgBox “Done.” end if end if
Changing the shortcut arrow Yo u do n’t need to disable sho rtc ut arro ws alto gether just bec ause yo u do n’t like their lo o ks. In fac t, disabling sho rtc ut arro ws generally isn’t a go o d idea: Sho rtc uts lo o k exac tly like o riginal files, and it bec o mes hard to distinguish between them. A better way is to replac e the sho rtc ut arro w with so me o ther o verlay ic o n. Obvio usly, yo u sho uld c ho o se an ic o n that is mo stly transparent so the file ic o n wo n’t be c o vered to o muc h. Have a lo o k at Chapter 22 fo r a selec tio n o f useful ic o ns. ‘ 15-56.VBS set reg = CreateObject(“regtool.tob”) ‘ changing the Shortcut arrow reg.RegWrite “HKLM\Software\Microsoft\Windows\CurrentVersion\” _ & “explorer\Shell Icons\29”, “shell32.dll,30”
Chapte r 1 5 : Re gis try Twe aks
481
■
■
‘ updating the Cache reg.FlushIconCache
Are yo u wo ndering why the sc ript do esn’t use the Windo ws versio nindependent setting WINMACHINE instead o f HKLM...? Yo u do n’t need to ! Custo m ic o n settings are sto red in the Windo ws branc h o f the Registry no matter whic h Windo ws versio n yo u are using. The example replac es the sho rtc ut arro w with ano ther o verlay ic o n pro vided by shell32.dll. Yo u c an use any o ther ic o n library instead. Chapter 22 has the details. Table 15-4 lists useful o verlay ic o ns yo u may find o n yo ur system:
Table 15-4 Icon
Icon Resources Suitable as Link Overlay
File cdfview.dll,0 cdfview.dll,1 mms ys .cpl,24 ms rating.dll,4 progman.exe,38
New icons for all system icons Ac tually, the prec eding sc ript c an c hange any system ic o n, no t just sho rtc ut arro ws. To ac c ess o ther ic o ns, replac e the index number (29 fo r sho rtc ut arro ws) with the index number o f the ic o n yo u want to c hange, and supply an alternate ic o n reso urc e. There’s an easy tric k to retrieve the ic o n index fo r any system ic o n: Just right-c lic k any sho rtc ut file, c lic k the Change Ic o n butto n, and delete the name o f the ic o n file. Then, press enter. No w, Windo ws sho ws its standard shell32.dll ic o n file. This file c o ntains all the system ic o ns, and yo u c an c o unt the ic o ns to get their index numbers. Fo r example, to c hange the fo lder ic o n, use index number 3.
Sizing the Cool Switch window Do yo u kno w ab o ut the Co o l Switc h windo w? Ho ld do wn [ Alt] and press [ Tab ] . As lo ng as there are at least two o pen windo ws, a small windo w appears in the c enter o f yo ur sc reen, and yo u c an q uic kly switc h to ano ther running applic atio n b y pressing [ Tab ] a c o uple o f times until the applic atio n is selec ted. This is no t to o exc iting. The real news is that Windo ws 2000 emplo ys so me sec ret Registry keys, and these keys c o ntro l the size o f the windo w. Yo u c an
482
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
spec ify c o lumn and ro w numbers. No te, ho wever, that this setting is suppo rted o nly by Windo ws 2000: ‘ 15-57.VBS set wshshell = CreateObject(“WScript.Shell”) key = “HKCU\Control Panel\Desktop\” on error resume next columns = wshshell.RegRead(key & “CoolSwitchColumns”) rows = wshshell.RegRead(key & “CoolSwitchRows”) on error goto 0 if columns=0 then columns = 7 if rows =0 then rows = 3 newcolumns = Ask(“Specify number of columns!”, columns) newrows = Ask(“Specify number of rows!”, rows) wshshell.RegWrite key & “CoolSwitchColumns”, newcolumns wshshell.RegWrite key & “CoolSwitchRows”, newrows MsgBox “Settings changed. You need to restart your system!” function Ask(question, default) Ask = InputBox(question,,default) if ask = vbEmpty then WScript.Quit if not isNumeric(ask) then MsgBox “You did not enter a number!”, vbCritical WScript.Quit end if Ask = CInt(Ask) end function
Summary There are c o untless undo c umented settings inside the Windo ws Registry, and yo u no w kno w ho w to identify them and c reate yo ur o wn dialo g bo xes to manage them. Yo u also saw that c hanges may no t take plac e immediately and that yo u need to fo rc e Windo ws to rec o gnize yo ur new settings. The example sc ripts pro vided numero us ways fo r yo u to update the Ic o n Cac he, refresh the Deskto p, and invo ke system settings thro ugh the API.
Chapte r 1 6
Getting System Information In This Chapter 䊳 Determine the lo c atio n o f Windo ws spec ial fo lders suc h as Deskto p and My
Do c uments 䊳 Delete yo ur Do c uments menu to ensure privac y 䊳 Delete referenc es to do c ument types yo u do n’t wo rk with anyway 䊳 Find o ut impo rtant netwo rking details suc h as username and c o mputer name 䊳 Retrieve memo ry statistic s and determine c urrent wo rk lo ad, physic al
memo ry, and virtual memo ry management details 䊳 Detec t wheel mo use, so und c ard, and bo o t mo de 䊳 Retrieve c urrent video reso lutio n and c hange reso lutio n and video refresh
rate o n-the-fly 䊳 List all installed fo nts and c reate yo ur perso nal fo nt sampler page 䊳 Analyze yo ur pro c esso r type and Windo ws versio n 䊳 Find o ut if spec ific DLL func tio ns are available o n yo ur system
S
c ript develo pers need info rmatio n. This c hapter pro vides metho ds to retrieve all kinds o f info rmatio n abo ut yo ur system, yo ur c o nfiguratio n, and yo ur installatio n fo lders.
Finding Out Important Path Information Where do es Windo ws live? The true name o f the Windo ws fo lder may vary fro m system to system, and so do the names o f all the o ther spec ial fo lders Windo ws uses. Fo r yo ur sc ripts, it’s extremely impo rtant to kno w the spec ial Windo ws fo lder lo c atio ns. Maybe yo u want to insert yo ur sc ript into the StartUp pro gram gro up to start it auto matic ally at lo go n. Or maybe yo u need ac c ess to the RecentDocs fo lder to delete referenc es yo u do n’t need. The fo llo wing sec tio ns demo nstrate ho w to retrieve the path names o f all yo ur spec ial Windo ws fo lders.
484
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Retrieving special folder path names The WScript.Shell o bjec t is yo ur so lutio n. It o ffers the SpecialFoders metho d. This metho d returns the ac tual path name o f any spec ial Windo ws fo lder (see Figure 16-1). Here’s ho w to retrieve the path to yo ur pro gram gro ups (the gro ups yo u see when yo u o pen Pro grams in the Start menu): ‘ 16-1.VBS set wshshell = CreateObject(“WScript.Shell”) path = wshshell.SpecialFolders(“Programs”) MsgBox “The path to your private Programs folder:” & vbCr & path
Figure 16-1: Retrieve path names of s pecial Window s folders . On Windo ws 98, NT, and 2000, there may be individual user pro files. This is why these Windo ws versio ns divide many user settings into private settings and c o mmo n settings that apply to all users. To retrieve the lo c atio n o f the pro gram gro ups fo r all users, just replac e “Programs” with “AllUsersPrograms”. See ho w yo u c an take advantage o f this: ‘ 16-2.VBS set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”) path = wshshell.SpecialFolders(“Programs”) for each folder in fs.GetFolder(path).subfolders list = list & folder.name & vbCr next MsgBox “List of your private program groups:” & vbCr & list
Table 16-1 lists all the spec ial fo lder names yo u c an use with SpecialFolders:
Chapte r 1 6 : Ge tting Sys te m Info rmatio n
485
■
■
Table 16-1
Key Names for W indow s Folders
Name
Description
AllUsersDesktop
Des ktop items for all us ers
AllUsersStartMenu
Start menu cus tom items for all us ers
AllUsersPrograms
Program groups for all us ers
AllUsersStartup
Auto-s tarting s hortcuts for all us ers
Desktop
Des ktop items for current us er
Favorites
Favorites items for current us er
Fonts
Ins talled s ys tem fonts
MyDocuments
Private document folder for current us er
NetHood
Cus tom items for Netw ork Neighborhood virtual folder
PrintHood
Cus tom items for Printers virtual folder
Programs
Program groups for current us er
Recent
Lis t of recently us ed documents for current us er
SendTo
SendTo items
StartMenu
Start menu cus tom items for current us er
Startup
Auto-s tarting s hortcuts for current us er
Templates
Template files for New menu items
The “AllUsers...” settings apply to c o mmo n o bjec ts o nly. On Windo ws 95, they are unavailable, and if yo u do n’t use multiple user pro files, c hanc es are these fo lders are empty.
Cleaning up your Documents menu The Do c uments menu inside yo ur Start menu sto res the mo st rec ently used 15 files fo r easy ac c ess. Unfo rtunately, Windo ws do esn’t c are abo ut the file types, so the Do c uments menu rec o rds just any file yo u happen to o pen. Therefo re, impo rtant files c an get kic ked o ut o f this menu easily by o ther no tso -impo rtant files. Furthermo re, the Do c uments menu bec o mes unwieldy and c o nfusing if it c o ntains a lo t o f unwanted files. Yo u c an do so mething abo ut it. Clean yo ur menu up! Have a sc ript go thro ugh all the sho rtc uts, determine their targets, and delete any referenc e that po ints to a file type yo u are no t interested in!
486
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
‘ 16-3.VBS set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”) ‘ find out location of special folder recent = wshshell.SpecialFolders(“Recent”) ‘ access folder set folder = fs.GetFolder(recent) ‘ go through all shortcuts for each file in folder.files ‘ get extension type ext = lcase(fs.GetExtensionName(file.name)) ‘ is it a shortcut? It should be! if ext=”lnk” then ‘ open shortcut set scut = wshshell.CreateShortcut(file.path) ‘ find target target = scut.TargetPath ‘ target still valid? if not fs.FileExists(target) then ‘ no, delete file.delete else ‘ does target reference “important” file type? ext = lcase(fs.GetExtensionName(target)) select case ext ‘ add extensions for all file references ‘ you want to keep: case “doc” case “bmp” case “vbp” case else ‘ points to something else, delete file.delete end select end if end if next wshshell.Popup “Cleaned Documents Menu!”, 2
Take a lo o k at yo ur Do c uments menu, then launc h the sc ript. When yo u rec hec k yo ur Do c uments menu, yo u’ll see that the sc ript has deleted all referenc es to file types yo u did no t spec ify in yo ur sc ript. No w, the Do c uments menu o nly c o ntains referenc es to files yo u really wo rk with. It lo o ks muc h c leaner and has gained ro o m fo r new referenc es.
Chapte r 1 6 : Ge tting Sys te m Info rmatio n
487
■
■
When yo u c all the sc ript fo r the first time, it may take so me sec o nds to c o mplete the c leaning pro c ess. This is due to a Windo ws bug — the Do c uments menu sto res o nly the mo st rec ent 15 do c uments. Internally, whenever the limit is reac hed, Windo ws deletes o ld entries to make ro o m fo r new entries. This wo rks perfec tly well and happens inside the Registry. Outside, in yo ur RECENT fo lder, Windo ws o ften leaves behind unused sho rtc uts. Over time, hundreds o f sho rtc uts may be left behind in yo ur RECENT fo lder, and it’s a go o d idea to c lean them up. Use yo ur new sc ript whenever yo u find yo ur Do c uments menu c rammed with entries. Even better, yo u c an launc h yo ur sc ript auto matic ally at Windo ws lo go n so that yo u always start with a c lean Do c uments menu. See Chapter 13 fo r details.
Cleaning the Documents menu automatically If yo u want yo ur sc ript to c lean up the Do c uments menu auto matic ally at given intervals, yo u c an use this sc ript instead: ‘ 16-4.VBS set wshshell = CreateObject(“WScript.Shell”) set fs = CreateObject(“Scripting.FileSystemObject”) recent = wshshell.SpecialFolders(“Recent”) set folder = fs.GetFolder(recent) do for each file in folder.files ext = lcase(fs.GetExtensionName(file.name)) if ext=”lnk” then set scut = wshshell.CreateShortcut(file.path) target = scut.TargetPath if not fs.FileExists(target) then file.delete else ext = lcase(fs.GetExtensionName(target)) select case ext case “doc” case “bmp” case “vbp” case else file.delete end select end if end if next ‘ sleep for a minute WScript.Sleep 1000*60 loop
488
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
This sc ript runs fo rever. It c leans yo ur Do c uments menu, and then it sleeps fo r a minute and c leans again. Yo u have no way o f sto pping this sc ript exc ept by c alling the Task List and c lo sing do wn WScript.exe manually. If yo u run sc ripts this way, always make sure yo u inc lude a “sleep phase” so yo ur sc ript wo n’t eat up all yo ur CPU po wer. In Chapter 17, yo u also get a new way o f inserting a “sc ript ic o n” into the tray area. With this tray ic o n, yo u c an sto p sc ripts anytime. Chec k it o ut: Open a file with a file type no t listed in yo ur sc ript. Then, c hec k yo ur Do c uments menu: It c o ntains a referenc e to this file. No w, wait a minute and c hec k again. The do c ument referenc e is go ne. Yo ur sc ript has silently do ne its jo b in the bac kgro und.
Finding the Windows folder SpecialFolders gives ac c ess to any spec ial fo lder, but it c an’t return the Windo ws fo lder name. What no w? Ac tually, yo u have two c ho ic es. Windo ws always sto res the Windo ws fo lder in an enviro nment variable c alled %WINDIR%. Use ExpandEnvironmentStrings to retrieve the path name. Or yo u c an use the Scripting.FileSystemObject metho d c alled GetSpecialFolder. This metho d returns a fo lder o bjec t yo u c an use to ac c ess the fo lder c o ntent direc tly.
Where does Windows live? Here’s ho w to retrieve the Windo ws fo lder path name (see Figure 16-2): ‘ 16-5.VBS set wshshell = CreateObject(“WScript.Shell”) windir = wshshell.ExpandEnvironmentStrings(“%WINDIR%”) MsgBox “Windows Folder: “ & windir
Figure 16-2: Find out your current Window s folder.
Chapte r 1 6 : Ge tting Sys te m Info rmatio n
489
■
■
ExpandEnvironmentStrings c an retrieve o ther enviro nment variables, to o . Fo r example, to find o ut the name o f yo ur DOS c o mmand interpreter, use this sc ript: ‘ 16-6.VBS set wshshell = CreateObject(“WScript.Shell”) compath = wshshell.ExpandEnvironmentStrings(“%COMSPEC%”) MsgBox “DOS Interpreter: “ & compath
Accessing the Windows folder directly If yo u need to get ac c ess to the Windo ws fo lder c o ntents anyway, get the fo lder handle direc tly: ‘ 16-7.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set windir = fs.GetSpecialFolder(0) MsgBox “Windows Folder: “ & windir.Path for each subfolder in windir.subfolders list = list & subfolder.name & vbCr next MsgBox “Windows folder subfolders: “ & vbCr & list
GetSpecialFolder c an retrieve o ther spec ial fo lders, to o , as sho wn in Table 16-2.
Table 16-2
Key Codes for W indow s Folders
Index
Description
0
Window s Folder
1
Sys tem Folder
2
Temp Folder
Reading Network Information The WScript.Network o bjec t pro vides a basic set o f netwo rking metho ds and pro perties. Yo u c an use them to find o ut the c urrent username, and to remo tely install netwo rk printers.
Inside view: WScript.Network Table 16-3 pro vides a c o mplete list o f all the pro perties and metho ds pro vided by WScript.Network.
490
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Table 16-3
W Script.Netw ork Properties and M ethods
Property/M ethod
Description
Sub AddPrinterConnection(ByVal bstrLocalName As String, ByVal bstrRemoteName As String, [pvarUpdateProfile], [pvarUserName], [pvarPassword])
Maps the remote printer to a local res ource name
Property ComputerName As String
Retrieves the computer netw ork name
Function EnumNetworkDrives As IWshCollection
Lis ts all current netw ork connections
Function EnumPrinterConnections As IWshCollection
Lis ts all current netw ork printer connections
Sub MapNetworkDrive(ByVal bstrLocalName As String, ByVal bstrRemoteName As String, [pvarUpdateProfile], [pvarUserName], [pvarPassword])
Maps the netw ork drive to a local res ource
Sub RemoveNetworkDrive(ByVal bstrName As String, [pvarForce], [pvarUpdateProfile])
Removes a mapped netw ork drive
Sub RemovePrinterConnection(ByVal bstrName As String, [pvarForce], [pvarUpdateProfile])
Removes a netw ork printer
Sub SetDefaultPrinter(ByVal bstrName As String)
Sets the default printer
Property UserDomain As String
Retrieves the current us er domain
Property UserName As String
Retrieves the current us ername
Property UserProfile As String
Retrieves the current us er profile
Listing current username To find o ut the name o f the c urrently lo gged o n user (see Figure 16-3), use the fo llo wing sc ript: ‘ 16-8.VBS set wshnet = CreateObject(“WScript.Network”) user = wshnet.UserName domain = wshnet.UserDomain computer = wshnet.ComputerName
Chapte r 1 6 : Ge tting Sys te m Info rmatio n ■
491 ■
msg = “This computer is called “”” & computer & “””” & vbCr msg = msg & “You are logged on as “”” & user & “””” & vbCr msg = msg & “Your domain is “”” & domain & “””” & vbCr MsgBox msg, vbInformation
Figure 16-3: Determine logon name and domain name.
Managing Memory Consumption Memo ry is valuable, so it’s a go o d idea to find o ut the c urrent memo ry situatio n befo re sc ripts start extensive tasks. Co ntro lling yo ur system’s memo ry statistic s, yo u c an also find o ut if yo ur system has eno ugh RAM installed o r if it wo uld benefit fro m so me additio nal RAM (see Figure 16-4). Unfo rtunately, the WSH has no ac c ess to the memo ry statistic s. Yo u do . Just install the memo ry COM o bjec t I have prepared ( \install\memory\ setup.exe). Full so urc e c o de is pro vided at \components\memory\ memory.vbp.
Retrieving memory statistics Table 16-4 desc ribes what yo u c an do with the new memo ry COM o bjec t:
Table 16-4
New M ethods to Check M emory Status
M ethod
Description
Function GetMemory As String
Current memory s tatus as Text s tring report
Function Mem_load As Long
Current memory load in percent
Function Mem_page_avail As Long
Memory available in current page file
Function Mem_page_total As Long
Memory res erved in current page file
Function Mem_phys_avail As Long
True RAM memory available
Function Mem_phys_total As Long
True total RAM memory ins talled
Function Mem_virt_avail As Long
Maximum virtual memory available
Function Mem_virt_total As Long
Total virtual memory available
492
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Figure 16-4: Check memory cons umption and w ork load. If yo u just need a general o verview, use the c o nvenient GetMemory metho d: ‘ 16-9.VBS set tool = CreateObject(“memory.stats”) MsgBox tool.GetMemory
Running in physical memory only If yo u do n’t want to start a sc ript under lo w memo ry c o nditio ns, c hec k fo r the c urrent memo ry lo ad. Fo r example, yo u c an start yo ur sc ript if memo ry lo ad is belo w 80 perc ent: ‘ 16-10.VBS set tool = CreateObject(“memory.stats”) if tool.Mem_load4 identifies Windo ws 98. The mino r versio n reveals additio nal info rmatio n. A Platfo rm ID o f 1 and a majo r versio n o f 4 applies to bo th Windo ws 95 and so me Windo ws 98 versio ns. To c hec k fo r Windo ws 95, make sure the mino r versio n equals 0. The Build identifies the versio n within a spec ific Windo ws versio n.
Determining Windows version Yo u do n’t need to c alc ulate the Windo ws versio n yo urself. Use the WinKind metho d instead: ‘ 16-27.VBS set tool = CreateObject(“os.version”) MsgBox tool.WinKind
This metho d returns the exac t Windo ws type (see Figure 16-13). If yo u are interested in finding o ut whether yo u are running o n an NT basis o r no t, use WinType. This metho d reveals the type o f platfo rm.
506
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Figure 16-13: WinType and WinKind finding out your current Window s type
Extracting individual version information Yo u c an also retrieve individual versio n info rmatio n. Here’s an example: ‘ 16-28.VBS set tool = CreateObject(“os.version”) MsgBox “Windows-Version: “ & tool.WinVer MsgBox “Platform ID: “ & tool.Platform MsgBox “Build: “ & tool.Build
Determining system support for specific functions Kno wing the Windo ws versio n do es no t nec essarily mean yo u kno w whether o r no t yo ur system suppo rts a spec ific feature. Mic ro so ft has published so many servic e pac ks and add-o ns that things have bec o me a little c o nfusing. If yo u kno w the versio n o f the system file the feature requires, yo u c an use the file versio n to o l intro duc ed in Chapter 7 to c hec k whether yo ur system meets the requirements. If yo u kno w the feature is c o ntained in so me DLL func tio n c all, yo u c an c hec k whether the DLL o n yo ur system suppo rts the func tio n. Have a lo o k: ‘ 16-29.VBS set tool = CreateObject(“os.version”) MsgBox tool.DLLExists(“kernel32”, “GetVersionExA”) MsgBox tool.DLLExists(“kernel32”, “GetVersionExW”)
This sc ript tests whether kernel32.dll c o ntains the DLL func tio ns GetVersionExA and GetVersionExW. Remember: GetVersionExA represents the ANSI versio n and is generally available o n any Windo ws versio n. GetVersionExW represents the (wide) UNICODE versio n and is available o nly o n Windo ws NT/ 2000. When c hec king fo r a func tio n name, make sure yo u use the c o rrec t o ne. DLL func tio n names are c ase-sensitive, and mo st func tio ns are available as “A” and “W” versio ns. Do n’t c hec k fo r GetVersionEx bec ause this func tio n do esn’t exist. Chec k fo r GetVersionExA o r GetVersionExW. See Chapter 5 fo r additio nal details and ways to list all func tio ns sto red in DLLs.
Chapte r 1 6 : Ge tting Sys te m Info rmatio n
507
■
■
Finding DLLs that contain specific functions As a pro grammer, yo u might have the o ppo site pro blem: Yo u might kno w the name o f so me DLL func tio n, but yo u do n’t kno w whic h DLL c o ntains this func tio n. There are numero us ways to searc h fo r DLL func tio ns and retrieve the ho sting DLL name (this to pic is c o vered extensively in Chapter 5). Ho wever, the appro ac h used by DLLExists c an be easily expanded to searc h fo r DLL func tio ns. I’ve inc luded it into the COM o bjec t, and to searc h fo r a DLL func tio n, yo u c an use the metho d FindFunction: ‘ 16-30.VBS set tool = CreateObject(“os.version”) MsgBox tool.FindFunction(“GetVersionExA”)
It may take so me sec o nds fo r the sc ript to exec ute. After all, it has to query numero us DLL files. Internally, the COM o bjec t uses LoadLibraryEx bo th fo r DLLExists and FindFunction. LoadLibraryEx has o ne impo rtant advantage o ver LoadLibrary, and that’s that it ac c epts additio nal o ptio ns that lo ad the DLL witho ut ac tually exec uting the DLLMain part. Bec ause yo u are querying the DLL o nly, yo u do n’t want the DLL mec hanic s to start. No te that LoadLibraryEx do esn’t suppo rt 16-bit DLLs, so if the func tio n in questio n is part o f a 16-bit DLL, yo u wo n’t find it. Use the alternate metho ds desc ribed in Chapter 5 instead.
Figure 16-14: Find out w hich DLL contains the “GetVersionExA” function — or any other you might require.
Summary In this c hapter, yo u disc o vered numero us ways to find o ut system info rmatio n. Yo u no w c an read memo ry statistic s, and yo u c an detec t devic e types and video reso lutio ns. The auto matic fo nt sampler generato r sho ws vividly ho w this info rmatio n c an be used in everyday tasks. Metho ds to find o ut the c urrent Windo ws versio n and suppo rt fo r spec ific DLL func tio ns are an impo rtant prerequisite to selec t systems with c ertain features o nly. Even mo re impo rtantly, yo ur new to o ls allo w yo u to c hange c ritic al system settings. Yo u c an o ptimize video refresh and dynamic ally c hange sc reen reso lutio n.
Chapte r 1 7
Working with Events In This Chapter 䊳 Learn abo ut events and ho w yo ur sc ripts c an rec eive them 䊳 Co ntro l Internet Explo rer thro ugh events 䊳 Create yo ur o wn COM o bjec ts and fire events yo urself 䊳 Use the VB timer c o ntro l to add timer c apabilities to yo ur sc ripts 䊳 Sto p sc ripts after a predetermined timeo ut kic ks in 䊳 Sho w ic o ns in the tray area as lo ng as yo ur sc ript runs, and c anc el sc ripts
with the tray ic o n 䊳 Create mo deless dialo g bo xes and indic ate pro gress while yo ur sc ript
is at wo rk
E
vents pro vide a way fo r pro grams to c o mmunic ate with eac h o ther. Yo ur sc ripts c an use events, to o . In this c hapter, learn ho w to listen to events and ho w to raise events yo urself. With this kno wledge, yo u c an plac e yo ur o wn ic o ns into the tray area o f the task bar and turn mo dal dialo g bo xes into mo deless dialo g bo xes.
What’s So Thrilling About Events? In a multi-tasking enviro nment, there’s an impo rtant c hallenge — ho w c an pro grams c o mmunic ate with o ne ano ther? The answer is events. Events wo rk like alarm bells. Whenever so mething spec ial happens, an event is raised. The event itself is just a message. Yo ur pro gram (o r sc ript) c an happily igno re the event, and mo st sc ripts do . Pro grams (and sc ripts) need a spec ial “event sink” to rec eive events. The event sink listens to events fired by so meo ne else. Onc e an event is rec eived, yo ur sc ript c an reac t to it. The spec ial aspec t o f events is the fac t that they wo rk async hro no usly. Yo ur sc ript c an rec eive the event any time, no matter what it is c urrently do ing fo r yo u. Events, therefo re, c an interrupt yo ur sc ript at any time.
510
Part IV: Ac c e s s ing the Ope rating Sys te m
Receiving events Where do events c o me fro m? And ho w c an yo ur sc ripts listen to events? First o f all, events always c o me fro m “the o utside.” Fo r example, Internet Explo rer uses a who le set o f events to indic ate spec ial states. Onc e so meo ne c lo ses an Internet Explo rer windo w, fo r example, it raises an onQuit event (see Figure 17-1). Yo ur sc ript c an rec eive suc h events o nly if it is c urrently using the pro gram that issued the event. Yo ur sc ript c an, fo r example, c reate an instanc e o f Internet Explo rer to display results and listen to its onQuit event to make sure it wo n’t send data to a windo w that do esn’t exist anymo re: ‘ 17-1.VBS set ie = WScript.CreateObject(“InternetExplorer.Application”, _ “event_”) ie.visible = true MsgBox “Close the IE window to see what happens!”, vbSystemModal MsgBox “Script ends now.” sub event_onQuit MsgBox “Hey! You are about to close the window!”, _ vbSystemModal end sub
Figure 17-1: Your s cript res ponds to an IE onQuit event. The sc ript o pens an Internet Explo rer windo w. But lo o k what happens when yo u c lo se the windo w. Clo sing the windo w raises an onQuit event. Bec ause yo ur sc ript has established an event sink, it’s able to listen to events that Internet Explo rer raises. The pro c edure event_onQuit is exec uted and then displays a message right befo re the windo w c lo ses do wn. Ho wever, yo ur sc ript c an respo nd to the event o nly as lo ng as it’s still running. If yo u c lic k the dialo g bo x’s OK butto n twic e, the sc ript ends. It no lo nger exists and c an no lo nger listen to events. If yo u c lo se the IE windo w, no message appears.
511
Chapte r 1 7 : Wo rking with Eve nts ■
■
Implementing an event sink Implementing an event sink is easy — just use the WScript.Shell metho d and CreateObject instead o f VBScript CreateObject. Supply an event sink name as sec o nd argument. Next, define a pro c edure and name it appro priately. In the prec eding example, the pro c edure is c alled event_onQuit. event_ is the name o f the event sink, and onQuit is the name o f the event this pro c edure is attac hed to .
Using events Ho w do yo u kno w the event names a given o bjec t suppo rts? Yo u ask fo r them! In Chapter 3, yo u learned metho ds to dec o de the TypeLibrary o f any o bjec t. The fo llo wing sc ript uses the metho ds develo ped in my typelib COM o bjec t to retrieve the events the o bjec t suppo rts. Make sure yo u have installed the typelib COM o bjec t \install\typelib\setup.exe. ‘ 17-2.VBS set tool = CreateObject(“typelib.decoder”) set wshshell = CreateObject(“WScript.Shell”) set result = tool.EnumInterface(“shdocvw.dll”, “InternetExplorer”, 2) for each eventname in result list = list & eventname & vbCr next wshshell.popup “Events supported by Internet Explorer:” & vbCr & _ vbCr & list
EnumInterface queries the TypeLibrary sto red in shdocvw.dll. In Chapter 3, yo u c reated a list revealing the TypeLibrary filenames o f any COM o bjec t fo und o n yo ur c o mputer. EnumInterfaces lists o nly the events. Yo u c an use this metho d to query any info rmatio n c atego ry, as sho wn in Table 17-1.
Table 17-1
Information Categories Stored in TypeLibraries
Code
Description
1
Clas s es
2
Events
4
Cons tants Co ntinue d
512
Part IV: Ac c e s s ing the Ope rating Sys te m
Table 17-1
( co ntinue d)
Code
Description
8
Declarations
16
AppObject
32
Records
64
Intrins ic Alias es
128
Unions
239
All (default)
Try it! Use the sc ript and replac e c o de 2 with c o de 1. No w, the sc ript returns the pro perties and metho ds suppo rted by Internet Explo rer. Co de 4lists a c o mbinatio n o f bo th pro perties/ metho ds and events — so yo u c an even add to gether c o de numbers to searc h fo r multiple c atego ries at o nc e. The InternetExplorer o bjec t suppo rts many different events. Yo ur sc ript c an take advantage o f any o ne o f them: ‘ 17-3.VBS set ie = WScript.CreateObject(“InternetExplorer.Application”, _ “event_”) ie.visible = true MsgBox “I am hiding the window!”, vbSystemModal ie.visible = false MsgBox “Closing IE...” ie.quit MsgBox “Script ends.” sub event_onQuit MsgBox “Hey! You are about to close the window!”, _ vbSystemModal end sub sub event_OnVisible(mode) MsgBox “Changed visibility to “ & mode end sub
All IE events are pro c edures (defined as sub). Internet Explo rer raises the event but do esn’t ask yo u fo r permissio n. Yo ur sc ript c an o nly respo nd to the message; it c an’t c anc el the pending o peratio n. This is no t always the c ase. So me o bjec ts define events as func tio ns, allo wing yo ur sc ript to return a value. In mo st c ases, returning false c anc els the pending o peratio n. No te also that the OnVisible event supplies an argument.
Chapte r 1 7 : Wo rking with Eve nts
513
■
■
Defining Your Own Events Altho ugh sc ripts c an’t raise events, yo ur COM o bjec ts c an. This is go o d news, bec ause this way yo ur o wn COM o bjec ts c an c atc h yo ur sc ript’s attentio n anytime.
Creating a timer control Visual Basic inc ludes a timer c o ntro l, whic h c an be pro grammed to so me interval. And, it raises timer events auto matic ally. Yo u c an easily add timer c apabilities to yo ur sc ripts. Just c reate a COM o bjec t that inc ludes a timer c o ntro l and translate the timer event to a public event yo ur sc ript c an rec eive. First, add a timer c o ntro l to yo ur COM o bjec t: In the To o lbar windo w, do ublec lic k the timer c o ntro l ic o n. Next, add so me c o de to make yo ur timer c o ntro l ac c essible fro m the o utside. Make sure yo u fo llo w the instruc tio ns and c o mpile the new COM o bjec t as timer.event. The best way is to o pen the c o mplete so urc e pro jec t fro m the CD at \components\timer\timer.vbp. To o lazy to c o mpile the o bjec t yo urself? Then install the prepared pac kage: \install\timer\setup.exe. Option Explicit Public Event TimerFired() Public Sub EnableTimer() Timer1.Enabled = True End Sub Public Sub DisableTimer() Timer1.Enabled = False End Sub Public Sub HandleEvents() DoEvents end sub Public Sub SetTimer(ByVal interval As Long) Timer1.interval = interval End Sub Private Sub Timer1_Timer() RaiseEvent TimerFired End Sub
EnableTimer, DisableTimer, and SetTimer all set pro perties fo r the timer c o ntro l (whic h by default is named Timer1). The interesting part is the eventhandling. Whenever the timer fires, it raises a timer event. This event is a private event. The event will happen o nly inside yo ur COM o bjec t. To rec eive the event, yo ur c o de uses the Timer1_Timer pro c edure.
514
Part IV: Ac c e s s ing the Ope rating Sys te m
Bec ause yo u want to pass the event o n to yo ur sc ript, yo u need to raise a public event yo urself. The c o de defines a public event c alled TimerFired. Whenever the internal timer event is rec eived by the Timer1_Timer pro c edure, it raises the public event TimerFired. No w, yo ur sc ripts c an use the new timer c apabilities. Here’s an easy test: ‘ 17-4.VBS set tool = WScript.CreateObject(“timer.event”, “timer_”)
‘ set timer to 2 sec interval tool.SetTimer 2000 ‘ enable timer tool.EnableTimer MsgBox “Timer is enabled!” sub timer_TimerFired MsgBox “Timer has fired!” end sub
This sc ript sets the timer interval to two sec o nds (2,000 millisec o nds). Then, the sc ript enables the timer and displays a message, as sho wn in Figure 17-2. Fro m no w o n, every two sec o nds, a timer event is generated. It launc hes the timer_TimerFired pro c edure. No te that while this pro c edure is busy displaying its message, no further events will be rec o gnized. Also , o nc e the sc ript ends, there will be no mo re timer messages.
Figure 17-2: Enhance your s cript w ith a timer control.
Creating a debugging timer Timer events c an be used fo r all kinds o f things. One o f them is implementing a sc ript timeo ut. The fo llo wing sc ript implements an emergenc y break — if the sc ript runs fo r mo re than 20 sec o nds, a dialo g bo x appears and asks whether yo u want to interrupt it (see Figure 17-3). ‘ 17-5.VBS set tool = WScript.CreateObject(“timer.event”, “timer_”) ‘ set script timeout to 20 seconds
Chapte r 1 7 : Wo rking with Eve nts
515
■
■
tool.SetTimer 20000 tool.EnableTimer ‘ simulate a script error do ‘ check for events tool.HandleEvents loop
‘ your timeout procedure sub timer_TimerFired msg = “Your script is still running. Do you want to quit?” response = MsgBox(msg, vbYesNo + vbQuestion + vbDefaultButton2) if response = vbYes then WScript.Quit end sub
So metimes, yo ur sc ript is to o busy to respo nd to events. Lo o ps are o ptimized internally, and while yo ur sc ript exec utes a lo o p, it wo n’t pay attentio n to events. This is why the sc ript plac es a c all to HandleEvents inside the lo o p. HandleEvents c alls the DoEvents c o mmand, allo wing events to be exec uted.
Figure 17-3: The timer event as ks for confirmation if a s cript runs for more than 20 s econds . Yo u may wo nder why I used a timer c o ntro l instead o f the //T o ptio n. It’s true that c alling a sc ript with WSCRIPT.EXE //T:secs establishes a timeo ut after whic h the sc ripting ho st disc ards the sc ript. If yo u c all a sc ript with the line belo w, it will end after 10 sec o nds no matter what: wscript.exe //T:10 myscript.vbs
Ho wever, the timer c o ntro l c an do muc h mo re. It allo ws yo ur sc ript to reac t to the pending timeo ut. Fo r o ne thing, yo u c an do c lean-up wo rk, whic h is impo ssible with the //T: appro ac h. In Chapter 20, yo u’ll learn a lo t abo ut Internet c o ntro ls. Imagine that yo u auto mate so me Internet do wnlo ad pro c ess and want to make sure it do esn’t lo o p fo rever. If yo u establish a timeo ut using //T:secs, the sc ript will be interrupted after the number o f sec o nds yo u spec ify. The Internet c o nnec tio n will remain ac tive, tho ugh, and if yo u dial into the Internet, yo ur pho ne line will remain busy. No t so with the timer c o ntro l. Onc e the timer event fires, yo u have all the time in the wo rld to respo nd to it and c lo se do wn the Internet c o nnec tio n pro perly.
516
Part IV: Ac c e s s ing the Ope rating Sys te m
Showing icons in the tray area Thanks to events, yo u c an no w so lve o ne o f the big limitatio ns o f sc ripts. Bec ause sc ripts do n’t have their o wn windo ws, they run invisibly. This is bad bec ause yo u have neither a c lue whether the sc ript is still running no r an easy way to interrupt a sc ript when yo u need to . This is why I have develo ped yet ano ther COM o bjec t. It allo ws yo u to plac e an ic o n into the taskbar tray area (see Figure 17-4). The ic o n is visible while the sc ript is running, and if yo u c lic k the ic o n, yo u c an interrupt the sc ript at any time. Plac ing the mo use po inter o ver the ic o n sho ws a to o l tip telling yo u when the sc ript was started. Make sure yo u have installed the COM o bjec t \install\tray\setup.exe. Full so urc e c o de is pro vided at \components\tray\tray.vbp. ‘ 17-6.VBS ‘ enable quit on demand: set tool = WScript.CreateObject(“tray.icon”, “event_”) call tool.QuitOnDemand ‘ do some dummy stuff... for x = 1 to 1000 for y = 1 to 10000000 tool.HandleEvents test = left(“teststring”,1) + mid(“testing”, 3, 2) next next ‘ disable icon in tray area call tool.Quit ‘ called whenever someone asks the script to quit sub event_QuitNow WScript.Quit end sub
The mo ment the sc ript is launc hed, a new ic o n appears in the tray area. The sc ript then exec utes so me extensive lo o ps so that yo u have a c hanc e to prematurely quit it. No w po int at the new ic o n. A to o ltip reveals when the sc ript was started. Clic king the ic o n invo kes a dialo g bo x, whic h asks whether yo u want to c anc el the sc ript. If yo u c ho o se Yes, the event_QuitNow pro c edure is exec uted. WScript.Quit quits the sc ript immediately. Make sure yo ur sc ript c alls the Quit metho d befo re it sto ps. If yo u do n’t, the sc ript ic o n will remain in the tray area.
Chapte r 1 7 : Wo rking with Eve nts ■
517 ■
Figure 17-4: Control your s cripts through icons in the tray area. QuitOnDemand c an do a lo t o f additio nal tric ks. It suppo rts up to fo ur o ptio nal parameters, as sho wn in Table 17-2. QuitOnDemand message, icon file, icon index, tooltip text
Table 17-2
Parameters Supplied to QuitOnDemand
Parameter
Description
message
Mes s age you w ant to dis play w hen the tray icon is clicked
icon file
File that contains the icon you w ant to dis play in the tray: for example, s hell32.dll
icon index
Index of icon in the icon file
tooltip text
Mes s age you w ant to dis play in the tray icon tooltip w indow
Replac e QuitOnDemand with the fo llo wing c o mmand to see the differenc es: call tool.QuitOnDemand(“Wanna quit?”, “shell32.dll”, 3, “Hey!”)
This time, the sc ript displays a fo lder ic o n and uses the messages yo u supplied.
Tray icons under the hood Let’s take a lo o k at ho w the magic wo rks: Option Explicit Public Event QuitNow() Private Type NOTIFYICONDATA cbSize As Long hwnd As Long uId As Long uFlags As Long
518
Part IV: Ac c e s s ing the Ope rating Sys te m
uCallBackMessage As Long hIcon As Long szTip As String * 64 End Type Private Private Private Private Private Private Private
Private Type PicBmp Size As Long Type As Long hBmp As Long hPal As Long Reserved As Long End Type Private Declare Function OleCreatePictureIndirect Lib _ “olepro32.dll” (PicDesc As PicBmp, RefIID As GUID, _ ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long Private Declare Function Shell_NotifyIcon Lib “shell32” _ Alias “Shell_NotifyIconA” (ByVal dwMessage As Long, _ pnid As NOTIFYICONDATA) As Boolean Private Declare Function ExtractIconEx Lib “shell32.dll” _ Alias “ExtractIconExA” (ByVal lpszFile As String, _ ByVal nIconIndex As Long, phiconLarge As Long, phiconSmall _ As Long, ByVal nIcons As Long) As Long Private Declare Function DrawIconEx Lib “User32” (ByVal hdc As _ Long, ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon _ As Long, ByVal cxWidth As Long, ByVal cyWidth As Long, _ ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As _ Long, ByVal diFlags As Long) As Long Private Declare Function DestroyIcon Lib “User32” (ByVal _ hIcon As Long) As Long Private Private Private Private
nid As NOTIFYICONDATA msg busy As Boolean init As Boolean
Public Sub FireEvent() If busy Then Exit Sub
Chapte r 1 7 : Wo rking with Eve nts ■
519 ■
busy = True If MsgBox(msg, vbDefaultButton2 + vbYesNo + vbQuestion _ + vbSystemModal, “Quit?”) = vbYes Then RaiseEvent QuitNow Quit End If busy = False End Sub Public Sub HandleEvents() DoEvents End Sub Public Sub QuitOnDemand(Optional ByVal message As String = _ “WSH Script still running - do you want to quit anyway?”, _ Optional ByVal name As String = “shell32.dll”, Optional _ ByVal index As Long = 21, Optional ByVal tooltip As _ String = “WSH Script running”) init = True msg = message SetIconInternal name, index Set Form1.parent = Me nid.cbSize = Len(nid) nid.hwnd = Form1.hwnd nid.uId = vbNull nid.uFlags = NIF_ICON Or NIF_TIP Or NIF_MESSAGE nid.uCallBackMessage = WM_MOUSEMOVE nid.hIcon = Form1.icon nid.szTip = tooltip & “ - started “ & Time & vbNullChar Shell_NotifyIcon NIM_ADD, nid End Sub Public Sub Quit() If init Then Shell_NotifyIcon NIM_DELETE, nid init = False End If End Sub Public Sub SetIconInternal(ByVal name As String, ByVal index As Long) Dim handle As Long Dim Size As Long Dim iconnumber As Long iconnumber = ExtractIconEx(name, -1, 0, 0, 0) If iconnumber >= index Then Call ExtractIconEx(name, index, 0, handle, 1) Size = 16 Form1.icon = CreateBitmapIcon(handle) Form1.Refresh
520
Part IV: Ac c e s s ing the Ope rating Sys te m
End If End Sub Public Function CreateBitmapIcon(ByVal hBmp As Long) As Picture Dim ok As Long Dim Pic As PicBmp Dim IPic As IPicture Dim IID_IDispatch As GUID With IID_IDispatch .Data1 = &H20400 .Data4(0) = &HC0 .Data4(7) = &H46 End With With Pic .Size .Type .hBmp .hPal End With
= = = =
Len(Pic) vbPicTypeIcon hBmp 0
ok = OleCreatePictureIndirect(Pic, IID_IDispatch, 1, IPic) Set CreateBitmapIcon = IPic End Function
Shell_NotifyIcon is the API func tio n respo nsible fo r tray ic o ns. It uses a NOTIFYICONDATA struc ture to pass the arguments nec essary to display the ic o n. Because yo ur COM o bject is invisible and do esn’t participate in windo w message exchange, the co de uses an additio nal fo rm as event receiver fo r the tray ico n. The NOTIFYICONDATA structure is filled with the fo rms windo w handle and the fo rm ico n. Instead o f using co mplicated event callback pro cedures, the co de asks NOTIFYICONDATA to use the o fficial MouseMove event in case so meo ne mo ves the mo use o ver the tray ico n.
Changing form icons dynamically One issue remains — ho w is it po ssible to display a c usto m ic o n in the tray area? Ho w c an yo u assign an ic o n to the fo rm? SetIconInternal uses ExtractIconEx to extrac t the bitmap handle o f any ic o n sto red in any ic o n reso urc e file. Ho wever, yo u’ll o nly get the raw handle. Yo u c an’t assign the ic o n handle to the fo rm direc tly.
Converting bitmap handles to OLE pictures First, yo u need to c o nvert the ic o n handle into an OLE pic ture o bjec t o f the subtype ic o n. This is do ne by CreateBitmapIcon. This metho d ac c epts any handle to bitmap data and returns a valid OLE pic ture o f type vbPicTypeIcon. No w it’s easy to assign this pic ture to the ic o n pro perty o f the fo rm.
Chapte r 1 7 : Wo rking with Eve nts
521
■
■
Responding to tray icon events Let’s take a lo o k at ho w the fo rm handles the mo use events: Public parent As Object Private Private Private Private Private Private
Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Y As Single) msg As Long = X / Screen.TwipsPerPixelX
Select Case msg Case WM_LBUTTONDOWN parent.FireEvent Case WM_LBUTTONUP Case WM_LBUTTONDBLCLK Case WM_RBUTTONDOWN Case WM_RBUTTONUP Case WM_RBUTTONDBLCLK End Select End Sub
Whenever the mo use mo ves o ver the tray ic o n, a MouseMove event is raised. The fo rm respo nds to WM_LBUTTONDOWN o nly and c alls the pro c edure Fire Event. Bec ause this pro c edure is defined in yo ur COM o bjec t, it uses the parent variable. Yo ur c o de has initialized this variable with a referenc e to itself: me. Public Sub FireEvent() If busy Then Exit Sub busy = True If MsgBox(msg, vbDefaultButton2 + vbYesNo + vbQuestion _ + vbSystemModal, “Quit?”) = vbYes Then RaiseEvent QuitNow Quit End If busy = False End Sub
FireEvents first c hec ks if it is c urrently pro c essing a quit request. If it is, the public busy variable is true, and the pro c edure exists. If no t, the pro c edure asks whether yo u want to quit yo ur sc ript. If yo u c ho o se Yes, it raises the public event QuitNow and remo ves the ic o n fro m the tray area. Yo ur sc ript do esn’t kno w abo ut any o f this. Ho wever, o nc e it rec eives the QuitNow event, it c alls the WScript.Quit metho d and quits.
522
Part IV: Ac c e s s ing the Ope rating Sys te m
In o rder fo r yo ur sc ript to quit, yo ur sc ript needs to listen to the QuitNow event and ac t ac c o rdingly. As o utlined abo ve, yo u sho uld c all HandleEvents regularly inside o f lo o ps. If yo u do n’t, the QuitNow event may no t be pro c essed until the lo o p has finished.
Creating Modeless Windows Mo deless windo ws are windo ws that wo rk independently fro m yo ur script. They are visible and serve as o utput area, but yo ur script can still do whatever it likes. In co ntrast, mo dal windo ws take o ver co ntro l. While a mo dal windo w is active, yo ur script sto ps and waits fo r the windo w to be clo sed. Unfo rtunately, the Ac tiveX COM o bjec ts that yo ur free Visual Basic CCE c reates c an o nly deal with mo dal windo ws. This is bec ause yo ur COM o bjec ts are single-threaded. Only o ne part o f yo ur sc ript-COM o bjec t-arc hitec ture c an be exec uted at o ne time. Events c hange this c o nc ept c o mpletely. Yo u have seen that events c an trigger ac tio n anytime anywhere. So even tho ugh a mo dal windo w has drawn all attentio n to itself, if yo u c an manage to raise an event and pass it to the c alling sc ript, it regains c o ntro l while the mo dal windo w is still visible.
Output status information to a modal window Let’s turn a bo ring mo dal windo w into an exc iting mo deless windo w yo ur sc ript c an use to o utput status info rmatio n (see Figure 17-5). I’ve prepared a little COM o bjec t that do es the tric k. Lo ad the c o mplete pro jec t fro m the CD ( \components\modeless\modeless. vbp). Or install the c o mpo nent fo r immediate ac tio n ( \install\modeless\ setup.exe). Option Explicit Public Event WakeUp() Public Event QuitNow() Public Sub WriteDialog(ByVal text As String) Form1.Label1.Caption = text End Sub Public Sub ShowDialog() Set Form1.parentobj = Me Form1.enableEvent = True Form1.Show vbModal End Sub Public Sub CloseDialog() Form1.Quit
Chapte r 1 7 : Wo rking with Eve nts
523
■
■
End Sub Public Sub FireEvent() RaiseEvent WakeUp End Sub Public Sub FireQuitEvent() RaiseEvent QuitNow End Sub Public Sub HandleEvent() DoEvents End Sub
There are two public events — WakeUp and QuitNow. They are fired by Fire Event and FireQuitEvent. ShowDialog displays the mo dal dialo g bo x. Here’s the inside o f the fo rm: Public enableEvent As Boolean Public parentobj As Object Private Sub Command1_Click() parentobj.FireQuitEvent End Sub Private Sub Form_Resize() If Me.Visible And enableEvent Then parentobj.FireEvent enableEvent = False End If End Sub Public Sub Quit() Me.Hide End Sub
Ho w do yo u get the fo rm to fire the WakeUp event the mo ment it is displayed? Use the fo rms Resize pro c edure. This pro c edure is c alled anytime a fo rm is resized, and the Show metho d also invo kes this pro c edure. To make sure the fo rm fires o nly o nc e, the Resize pro c edure blo c ks the event firing mec hanism using enableEvent: Onc e the event is fired the first time, it sets enableEvent to false and pro hibits any further event firing.
Figure 17-5: Output s tatus information to modeles s w indow s w hile your s cript is at w ork.
524
Part IV: Ac c e s s ing the Ope rating Sys te m
Yo ur User Co ntro l is the o nly plac e where yo u c an fire public events. This is why ShowDialog has sto red a referenc e to the UserObject (Me) in the public fo rm variable parentobj. The fo rm c an no w c all UserObject pro c edures. No w, let’s take a lo o k at ho w yo u c an c o ntro l yo ur mo deless windo w: ‘ 17-7.VBS set fs = CreateObject(“Scripting.FileSystemObject”) ‘ create COM reference and catch events: set tool = WScript.CreateObject(“modeless.dialog”, “event_”) list = “” quit = false tool.WriteDialog “Starting...” ‘ enter MODAL mode, window takes over tool.ShowDialog ‘ this part is continued after the window has been closed MsgBox list sub event_WakeUp ‘ this event is fired once the modal window becomes visible ‘ this event is the key and lets your script regain control ‘ while the modal window is still visible and thinks its in ‘ charge ‘ recursively search all folders ShowFiles fs.GetFolder(“C:\”) ‘ IMPORTANT: use a MsgBox statement! ‘ it reassigns the window handle to the correct thread MsgBox “Close Down” ‘ close the modal dialog window tool.CloseDialog end sub sub event_QuitNow ‘ this event is fired once someone clicks the Cancel button ‘ quit is set to true. Inside of ShowFiles, quit is queried ‘ and if it’s true, the procedure exits immediately quit = true end sub sub ShowFiles(dirobj) ‘ did someone hit Cancel? Then quit! if quit then exit sub ‘ search all files in current folder for each file in dirobj.files ‘ write status information to modal window
Chapte r 1 7 : Wo rking with Eve nts
525
■
■
tool.WriteDialog dirobj.path & vbCr & dirobj.files.count _ & “ files...” & vbCr & file.name ‘ add files to list list = list & file.path & vbCr ‘ IMPORTANT: call HandleEvent frequently to allow your COM ‘ object to get some CPU cycles to respond to mouse action ‘ If you don’t, you can’t click the Cancel button because ‘ the COM object is completely busy tool.HandleEvent ‘ again, did someone hit Cancel? Leave loop immediately! if quit then exit sub next ‘ recursively search all subfolders for each subfolder in dirobj.subfolders ShowFiles subfolder next end sub
Pretty impressive, huh? Yo u’ve just gained a new way o f letting peo ple kno w yo ur sc ript is still alive. Witho ut the new pseudo -mo deless windo w, listing all files wo uld leave the sc ript user wo ndering what’s go ing o n. Use the windo w whenever a sc ript takes a lo ng time to exec ute. No t o nly do yo u get a great way o f pro viding feedbac k, yo ur windo w also allo ws the user to c anc el ac tio n. There are vario us pro perties to set fo r the fo rm so it appears c o rrec tly. The easiest way is to lo ad the pro jec t \components\modeless\modeless.vbp. Make sure yo ur fo rm uses AutoRedraw. In my example, the fo rm do esn’t use a c aptio n and is auto matic ally c entered in the middle o f the sc reen.
Some words of caution Co nverting a mo dal windo w into a mo deless windo w is no t a trivial thing. Yo ur events kic k the threads aro und, and VisualBasic wo nders what’s go ing o n. Ho wever, the prec eding tec hnique is c o mpletely safe. If yo u c hange the c o de, tho ugh, always make sure no abando ned threads are left behind. Open yo ur task manager windo w and searc h fo r WSc ript.exe after yo ur sc ript is do ne. Abando ned threads o c c ur when yo ur sc ript do esn’t c lean up after itself. Suppo se yo u have displayed a mo dal windo w using ShowDialog. Fro m this po int o n, the mo dal windo w is o ffic ially in c harge. Yo ur COM o bjec t sec retly passes bac k c o ntro l to yo ur sc ript using the WakeUp event. No w yo ur sc ript is bac k in c harge, altho ugh the mo dal windo w still thinks it’s the o nly o ne there. If yo ur sc ript wo uld simply c lo se do wn no w using WScript.Quit, yo u wo uld leave an abando ned thread behind. WScript.Quit sho uld c lo se do wn the mo dal windo w, but bec ause yo ur sc ript sneaked bac k into c o ntro l, it is c lo sed, and the o riginal Wscript sessio n remains ac tive.
526
Part IV: Ac c e s s ing the Ope rating Sys te m
So , it’s impo rtant to pass bac k c o ntro l to the mo dal windo w o nc e yo ur sc ript is do ne and to let it c lo se grac efully. In the example abo ve, it’s impo rtant to issue a MsgBox statement just befo re yo u c lo se do wn the mo dal windo w. This way, yo ur WakeUp event pro c edure is bac k in c harge and c an be c lo sed no rmally. If yo u do n’t issue this statement, yo ur sc ript wo n’t find its way bac k to where it started. Use the WScript.Shell Popup metho d if yo u want to c lo se the mandato ry message bo x auto matic ally. Set wshshell = CreateObject(“WScript. Shell”). Replac e MsgBox “Close Down” with wshshell.Popup “Close Down”, 1.
Using progress bars to spice up dialog boxes Yo u are pro bably wo ndering what this new tec hnique c an do fo r yo u. There are tremendo us po ssibilities, and bec ause the file-searc h dialo g bo x fro m abo ve is a very useful example, I have spic ed it up a bit to demo nstrate ho w easy it no w is to c reate pro fessio nal dialo g bo xes.
Figure 17-6: Dis play modeles s progres s bars to indicate s cript progres s . My COM o bjec t ac tually c o ntains two fo rms, and the sec o nd fo rm features a pro gress bar. The pro gress bar is part o f COMCTL32.OCX, a user c o ntro l pro vided by Mic ro so ft. Make sure yo u inc lude this file in yo ur distributio n if yo u plan to give away yo ur o wn pro gress bar c o ntro ls. To use the pro gress bar display, use ShowProgressDialog instead o f ShowDialog. To set the pro gress bar, use SetProgress. Make sure yo u spec ify a value between 0 and 100: ‘ 17-8.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set tool = WScript.CreateObject(“modeless.dialog”, “event_”)
Chapte r 1 7 : Wo rking with Eve nts
527
■
■
list = “” quit = false tool.WriteDialog “Starting...” ‘ this time, use progress bar dialog tool.ShowProgressDialog MsgBox list sub event_WakeUp ShowFiles fs.GetFolder(“C:\”) MsgBox “Close Down” tool.CloseDialog end sub sub event_QuitNow quit = true end sub sub ShowFiles(dirobj) if quit then exit sub counter = 0 filecount = dirobj.files.count for each file in dirobj.files counter = counter + 1 tool.WriteDialog dirobj.path & vbCr & filecount _ & “ files...” & vbCr & file.name ‘ calculate percent done percent = Fix(counter * 100/filecount) ‘ set progress bar accordingly tool.SetProgress percent list = list & file.path & vbCr tool.HandleEvent if quit then exit sub next for each subfolder in dirobj.subfolders ShowFiles subfolder next end sub
The pro gress bar is perfec t fo r well-defined o peratio ns. Searc hing a fo lder is well-defined: Yo u kno w the number o f files in the fo lder, and yo u kno w the number o f files yo u have already fo und. Fro m here, it’s easy to c alc ulate the perc entage using a fo rmula suc h as actual value * 100 / end value. Yo u c an’t use the pro gress bar fo r o peratio ns witho ut a c learly defined sc o pe.
528
Part IV: Ac c e s s ing the Ope rating Sys te m
Summary Events are great. Altho ugh they are no t abso lutely nec essary and yo u c an c o mpletely igno re them, explo ring events pro vides yo u with a who le new wo rld o f o ppo rtunities. This c hapter pro vided so me highly unusual examples: fo r instanc e, the c o nc ept o f events allo wing yo ur sc ripts to c o ntinue exec utio n altho ugh a mo dal windo w is visible. Events so lve many o ther pro blems, to o : Fro m no w o n, yo u c an display ic o ns in the tray area to indic ate that yo ur sc ript is running (and still feeling well). Thro ugh the tray ic o n, yo u c an c o mmunic ate with yo ur sc ript and, fo r example, c anc el exec utio n. As a side effec t, the COM o bjec ts disc ussed in this c hapter sho w so me rather interesting tec hniques — yo u learned ho w to extrac t ic o ns fro m system reso urc es and ho w to c o nvert tho se extrac ted ic o ns into OLE pic tures. These OLE pic tures then c an be used freely with Visual Basic .
Chapte r 1 8
Developing Unix-like Commands In This Chapter 䊳 Use sc ripts in DOS bo xes and let them behave as if they were DOS c o mmands 䊳 Co ntro l the DOS Input and Output streams 䊳 Use piping and feeding with the results o f o ther c o mmands in yo ur sc ripts
to further pro c ess o r filter them 䊳 Make sure yo ur sc ripts are launc hed inside a DOS bo x
S
c ripts c an ac t like DOS o r UNIX c o mmands. In this c hapter, learn ho w to ho o k a sc ript into the DOS Input and Output streams. Also disc o ver ho w sc ripts read in arguments and suppo rt piping.
Developing Your Own Command-Line Macros DOS and UNIX have o ne thing in c o mmo n — they use a c o mmand bo x, and yo u must enter c o mmands instead o f c lic king fanc y ic o ns with the mo use. Vario us extensio ns pro vide a graphic al user interfac e to bo th UNIX and DOS, and Windo ws 9.x to so me extent “wraps” DOS c o mmands and o ffers easy-to use ic o ns and menus. Still, many c o mputer pro fessio nals prefer the c o mmand-line style fo r administering systems. The Sc ripting Ho st allo ws yo u to append the set o f c o mmands available and generate yo ur o wn.
Creating a new command Sc ripts need a way to read input and write o utput to the DOS bo x in o rder to bec o me “real” c o mmands. The new WSH 2.0 is able to do that. It c an link itself into the DOS Input and Output streams and ac c ess them as TextStream o bjec ts. In essenc e, sc ripts c o ntro l input and o utput to the DOS bo x the same way they c o ntro l input and o utput to files. Take a lo o k at the fo llo wing example. It ac c esses the DOS Input and Output streams and ec ho s bac k whatever yo u type in. Use exit to quit the sc ript. ‘ 18-1.VBS set inputstream = WScript.StdIn
530
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
set outputstream = WScript.StdOut do data = inputStream.ReadLine if data = “exit” then WScript.Quit else outputstream.WriteLine UCASE(data) end if loop
If yo u try to launc h this sc ript, yo u’ll rec eive an erro r message (see Figure 18-1). The sc ripting ho st c o mplains abo ut an invalid handle. What’s go ing o n?
Figure 18-1: You can’t acces s DOS s treams from outs ide a DOS box. Launc hing sc ripts, by default, exec utes the sc ripts in the Windo ws enviro nment. WSCRIPT.EXE takes c are o f the sc ript, and bec ause WSCRIPT.EXE is no t a DOS bo x, there are no Input and Output streams the sc ript c an link into . Fo r yo ur sc ript to wo rk, yo u must exec ute it inside a DOS bo x. Either launc h the sc ript manually via CSCRIPT.EXE o r right-c lic k the sc ript ic o n and c ho o se Open With Co mmand Pro mpt.
Figure 18-2: The s cript proces s es entered text. No w, the sc ript wo rks perfec tly well. Yo u c an type in c harac ters, and the sc ript will return them in upperc ase. Exit c lo ses the sc ript.
Chapte r 1 8 : De ve lo ping Unix-like Co mmands
531
■
■
Calling scripts like DOS commands On previo us Windo ws versio ns, c alling a sc ript fro m the c o mmand line isn’t fun. Yo u need to append CSCRIPT.EXE and spec ify the full path name to yo ur sc ript. Fo r example, if yo u have sto red yo ur previo us sc ript as C:\18-1.VBS, yo u’d have to c all it this way: CSCRIPT.EXE C:\18-1.VBS
Obvio usly, this isn’t prac tic al, and luc kily, Windo ws 2000 is muc h mo re advanc ed. Here, .vbs files are inc luded in the searc h path and wo rk like exec utables. Pro vided yo u have sto red yo ur sc ript in a fo lder that is part o f the searc h path (the Windo ws fo lder, fo r example), yo u c an c all yo ur sc ript direc tly. Yo u do n’t even need to spec ify the file extensio n: 18-1 [Enter]
Ho wever, again Windo ws defaults to WSCRIPT.EXE, and altho ugh the sc ript is launc hed, yo u will get the erro r message c o mplaining abo ut invalid handles. Yo u c an c ho o se whether WSCRIPT.EXE o r CSCRIPT.EXE will exec ute sc ripts by default. WSCRIPT.EXE //H:CScript c hanges the default to CSCRIPT.EXE, and WSCRIPT.EXE //H:WScript c hanges the setting bac k to WSCRIPT.EXE. So if yo u want to use sc ripts as c o mmands, yo u c an c hange the default sc ript engine to CSCRIPT.EXE and get away with it: WSCRIPT.EXE //H:CScript
No w, at least o n Windo ws 2000, yo u c an c all yo ur sc ripts exac tly the way yo u’d c all any DOS c o mmand o r exec utable file. Ho wever, no w all sc ripts are launc hed by CSCRIPT.EXE, even the o nes yo u launc h by c lic king the sc ript ic o n o n the Windo ws deskto p.
Detecting whether a script runs in a DOS box To so lve this pro blem, and to prevent erro r messages regarding invalid handles, yo ur sc ript will need a way to determine whether it’s ho sted by WSCRIPT.EXE o r CSCRIPT.EXE. Kno wing this, it c an relaunc h itself in the appro priate ho sting enviro nment. This way, yo ur sc ript always gains ac c ess to the DOS handles, and yo u aren’t fo rc ed to c hange the default sc ript ho st. It’s easy. The WSH pro vides two impo rtant pro perties. FullName returns the full name o f the c urrent sc ript ho st. Yo ur sc ript just needs to extrac t the filename to find o ut whether it’s CSCRIPT.EXE o r so me o ther ho st. If it’s no t CSCRIPT.EXE, yo ur sc ript c an use the WScript.Shell metho d Run to relaunc h itself using CSCRIPT.EXE. ScriptFullName reveals the sc ript’s o wn full path name.
532
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Here’s the so lutio n: ‘ 18-2.VBS ‘ which engine runs this script? engine = lcase(mid(WScript.FullName, InstrRev(WScript.FullName,”\”)+1)) if not engine=”cscript.exe” then ‘ re-launch script using cscript.exe set wshshell = CreateObject(“WScript.Shell”) wshshell.run “CSCRIPT.EXE “”” & WScript.ScriptFullName & “””” WScript.Quit end if MsgBox “I run as DOS-Box!”
The stub sho wn in Figure 18-3 is all yo u need to make sure the sc ript is run by CSCRIPT.EXE.
Figure 18-3: Automatically make s ure your s cript is executed by CSCRIPT.EXE. Ho wever, it’s o nly a partial vic to ry. Bec ause yo ur sc ript is no w launc hed by WSCRIPT.EXE first and relaunc hed by CSCRIPT.EXE, it will always use a new and private DOS windo w. This so lutio n wo rks great fo r individual sc ripts that run stand-alo ne, but it’s no so lutio n if yo u want to mix DOS c o mmands and yo ur o wn c o mmands. Here, yo ur o nly c ho ic e is to tempo rarily c hange the default ho st.
Changing the default host The next sc ript c o uld be yo ur first real c o mmand extensio n (see Figure 18-4). Save it as DOS.VBS in yo ur Windo ws fo lder. Fro m no w o n, it’s easy to switc h default ho sts. Call the sc ript DOS.VBS witho ut arguments. It switc hes ho sts and repo rts the ac tive ho st. Or use DOS “o n” o r DOS “o ff” as argument. DOS o n ac tivates CSCRIPT.EXE, and DOS o ff ac tivates WSCRIPT.EXE as default ho st. Fro m no w o n, right befo re yo u start wo rking with yo ur sc ript c o mmands, enter DOS o n. Onc e yo u are finished, enter DOS o ff.
Chapte r 1 8 : De ve lo ping Unix-like Co mmands ■
533 ■
Again, remember that o nly Windo ws 2000 allo ws yo u to c all yo ur sc ript direc tly. Plac e yo ur sc ript into the Windo ws fo lder so yo u do n’t need to spec ify its full path name. On all o ther Windo ws systems, yo u need to append CSCRIPT.EXE and pro vide the full path to yo ur sc ript. ‘ DOS.VBS set wshshell = CreateObject(“WScript.Shell”) ‘ which engine runs this script? engine = lcase(mid(WScript.FullName, InstrRev(WScript.FullName,”\”)+1)) set args = WScript.Arguments if args.Count = 0 then ‘ no arguments if engine = “wscript.exe” then wshshell.run “WSCRIPT.EXE else wshshell.run “WSCRIPT.EXE end if else if args(0) = “on” then wshshell.run “WSCRIPT.EXE else wshshell.run “WSCRIPT.EXE end if end if
//H:CScript” //H:WScript”
//H:CScript” //H:WScript”
Sc ripts wo n’t wo rk well as c o mmand extensio ns o n systems o ther than Windo ws 2000. On Windo ws 9.x and NT, yo u need to c all the sc ript using a sc ript engine and the full sc ript path name. That’s no t very prac tic al.
Figure 18-4: Your new “DOS” command controls w hich s cript engine executes your s cripts .
534
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
Automatically changing default hosts Here’s ano ther so lutio n. The next sc ript c hanges the default ho st to CSCRIPT. EXE, then launc hes a c o mmand bo x and waits. Onc e yo u are do ne with yo ur c o mmand-line wo rk and c lo se the bo x, the sc ript wakes up again and c hanges the default ho st bac k to WSCRIPT.EXE: ‘ 18-3.VBS set wshshell = CreateObject(“WScript.Shell”) ‘ set cscript.exe as standard wshshell.run “WSCRIPT.EXE //H:CScript” ‘ launch command window and wait ok = wshshell.run(“””%comspec%”””,,true) ‘ change back to default wshshell.run “WSCRIPT.EXE //H:WScript”
Whenever yo u need to do c o mmand-line wo rk, make sure to o pen the c o mmand bo x with this sc ript. This way, yo u c an always be sure that yo ur sc ripts are exec uted inside the bo x.
Using piping: Feeding results to your commands Sc ript c o mmands suppo rt piping. Piping is a simple means o f c asc ading c o mmands. Fo r example, the DIR DOS c o mmand lists fo lder c o ntents. Ho wever, mo st fo lders c o ntain many mo re files than fit o n o ne sc reen page. So in o rder to read the entire listing, yo u c an “feed” it to ano ther c o mmand c alled more. This c o mmand sto ps o utput o nc e a sc reen is full until yo u enter a key: DIR | MORE
Developing pipe commands Yo ur sc ripts c an easily partic ipate in piping. Fo r example, the next sc ript c reates yo ur o wn more c o mmand. Do n’t launc h this sc ript direc tly! If yo u do , yo ur keybo ard is interpreted as Input stream, and bec ause there’s no defined end to keybo ard input, yo u’ll stumble into an endless lo o p. Clo se the DOS windo w if this happens to yo u. ‘ NEWMORE.VBS engine = lcase(mid(WScript.FullName, _ InstrRev(WScript.FullName,”\”)+1)) if not engine = “cscript.exe” then MsgBox “Launch with CSCRIPT.EXE!”
Chapte r 1 8 : De ve lo ping Unix-like Co mmands
535
■
■
WScript.Quit end if set inputstream = WScript.StdIn set outputstream = WScript.StdOut do counter = counter + 1 if outputstream.atEndOfStream then exit do outputstream.WriteLine inputstream.ReadLine if counter > 20 then MsgBox “Click OK to continue!” counter = 0 end if loop outputstream.WriteLine “That’s it!”
And this is ho w yo u invo ke it: DIR | CSCRIPT.EXE %WINDIR%\NEWMORE.VBS
To play it safe, yo u sho uld issue the DIR c o mmand first witho ut piping it to yo ur sc ript. Make sure the DIR c o mmand exec utes witho ut asking questio ns. If DIRCMD is set to so me o ptio n, DIR may pause after 25 lines and ask yo u to press a key. Set DIRCMD to no thing: SET DIRCMD= [Enter]
If the DOS c o mmand feeds results to yo ur sc ript to o fast, the sc ript asks the DOS c o mmand to ho ld o n a sec o nd. To c o ntinue feeding, yo u need to press a key. So if the sc ript appears to hang, press a key. Usually, this behavio r is an indic atio n that yo ur system is to o slo w and c an’t pro c ess yo ur sc ript at the usual speed. If it happens to yo u, piping is pretty muc h useless. Every 20 lines, a dialo g bo x asks yo u to c lic k OK. Altho ugh Windo ws 2000 do es a go o d jo b launc hing sc ript files as exec utables, piping o nly wo rks if yo u spec ify CSCRIPT.EXE as sc ript ho st in yo ur c o mmand line. Yo u c an’t use DIR | NEWMORE o r else yo u’ll get an invalid handle erro r. The reaso n is bec ause the pipe gets lo st the way Windo ws launc hes sc ript files. By explic itly spec ifying CSCRIPT.EXE, the pipe is attac hed to CSCRIPT.EXE and passed o n to the sc ript. It’s bad news, but it’s the truth.
Writing filters through piping There are mo re useful examples o f ho w piping c an help yo u. Fo r example, the next sc ript is a piping extensio n that finds filenames fo r yo u: ‘ MYFILTER.VBS engine = lcase(mid(WScript.FullName, _ InstrRev(WScript.FullName,”\”)+1))
536
Part IV: Ac c e s s ing the Ope rating Sys te m
■
■
if not engine = “cscript.exe” then MsgBox “Launch with CSCRIPT.EXE!” WScript.Quit end if
search = lcase(InputBox(“Enter File name or part of it!”)) set inputstream = WScript.StdIn set outputstream = WScript.StdOut do until inputstream.atEndOfStream line = inputstream.ReadLine if Instr(lcase(line), search)>0 then outputstream.WriteLine “FOUND: “ & line end if loop outputstream.WriteLine “Done.”
Feed it with a rec ursive DOS DIR searc h, and it filters o ut anything yo u ask fo r: DIR C:\ /S | CSCRIPT.EXE %WINDIR%\MYFILTER.VBS
Yo u c an even redirec t the result into a file: DIR C:\ /S | CSCRIPT.EXE %WINDIR%\MYFILTER.VBS > C:\RESULT.TXT
Summary Sc ripts c an ac t as c o mmand-line c o mmands and partic ipate in bo th DOS streams and piping. Ho wever, the use is limited: Only Windo ws 2000 allo ws yo u to spec ify sc ript names direc tly. On all o ther systems, yo u must use CSCRIPT.EXE and pro vide the full sc ript path. Also , DOS Input and Output handles are valid o nly if yo u launc h yo ur sc ript fro m inside a DOS bo x. Yo u have disc o vered a number o f so lutio ns to make sure sc ripts are launc hed this way. Still, there are many useful sc enario s in whic h DOS sc ripts c o me in handy. Amo ng the mo st fasc inating uses are interpreter-like so lutio ns: Yo u c an use the DOS bo x as a platfo rm fo r yo ur sc ript and input c o mmands and o utput the results.
Chapte r 1 9
Using the WebBrowser Control In This Chapter 䊳 Disc o ver the versatile WebBrowser c o ntro l, and c reate yo ur o wn dialo g bo xes
using plain HTML templates 䊳 Enumerate and ac c ess DHTML elements 䊳 Link sc ript pro c edures to DHTML butto ns using GetRef, and bypass Internet
Explo rer sec urity dialo gs 䊳 Co ntro l yo ur WebBrowser fo rm windo w thro ugh HTML c o mmands 䊳 Validate HTML fo rm input, and c o lo r-c o de missing fo rm fields 䊳 Let yo ur COM o bjec t respo nd to events fired by the WebBrowser c o ntro l,
and disable the c o ntext menu this way 䊳 Use radio butto ns and determine whic h radio butto n was selec ted 䊳 Custo mize yo ur HTML dialo g c o ntainer, c hange c aptio n text, and disable
sizing
T
he WebBrowser c o ntro l is the heart o f Internet Explo rer. It c an display HTML do c uments and is a very versatile design element yo u c an inc o rpo rate into yo ur o wn dialo g bo xes. In this c hapter, learn ho w to use the WebBrowser c o ntro l to c reate fully c o nfigurable HTML-based c usto m dialo g bo xes and transfer the results bac k into yo ur sc ripts.
The WebBrowser Control: Mastering Real-World Tasks Mic ro so ft has stuffed all kinds o f c o ntro ls into Windo ws, and while mo st s o f them are busy wo rking fo r the o perating system, yo ur sc ripts c an ac c ess tho se c o mpo nents, to o . One o f the mo st versatile c o ntro ls is the WebBrowser c o ntro l. It wo rks inside o f any Internet Explo rer windo w, and bec ause Mic ro so ft keeps expanding the ro le HTML plays, yo u’ll see this c o ntro l in many Windo ws 2000 system dialo g bo xes, to o . The WebBrowser c o ntro l is ac tually a miniature Web bro wser. It c o ntains everything nec essary to lo ad and display HTML c o ntent.
540
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Ac tually, Internet Explo rer is just a wrapping aro und the WebBrowser c o ntro l. The Internet Explo rer applic atio n pro vides the to o lbars and o ther gadgets helpful to navigate the Web, but the true po wer c o mes fro m the WebBrowser c o ntro l embedded in Internet Explo rer. The WebBrowser c o ntro l is by no means limited to displaying Web pages. In Chapter 5, I sho wed yo u ho w to use Internet Explo rer as a versatile Sc ripting Ho st o utput windo w. No w it’s time to take a c lo se lo o k at the real heart o f Internet Explo rer. The WebBrowser c o ntro l is the perfec t fo undatio n fo r truly c usto mizable dialo g bo xes. It makes muc h mo re sense to use the WebBrowser c o ntro l direc tly instead o f ac c essing it thro ugh Internet Explo rer and paying the pric e fo r all o f the o verhead invo lved.
Creating custom dialog boxes There’s a definite need fo r c usto m dialo g bo xes. The built-in set o f dialo g bo xes ac c essible to the Sc ripting Ho st is very limited, and it’s imprac tic al to c reate COM o bjec ts fo r any c usto m dialo g bo x yo u may need. A muc h mo re versatile appro ac h are HTML dialo g bo xes. Yo u c an c reate them with yo ur favo rite HTML edito r in a matter o f minutes, and it’s easy to design these dialo g bo xes just as yo u c an design a Web page. All yo u need is a way to display yo ur HTML dialo g bo xes. Displaying is easy — just feed the HTML template to the WebBrowser c o ntro l. In additio n, yo u’ll need so me extra tric ks to be able to retrieve the results typed into yo ur dialo g bo x. I’ve designed a COM o bjec t that uses the WebBrowser c o ntro l and inc ludes many fasc inating tric ks fo r interac ting with the user. Install the COM o bjec t \install\webdialog\setup.exe. Full so urc e c o de is pro vided at \components\webdialog\webdialog.vbp.
Designing your form: Creating an HTML template The first thing needed is an HTML template. This template defines the elements o f yo ur dialo g bo x. Here’s a simple example. Type it into yo ur favo rite text edito r and save it as TEMPLATE.HTM in the same fo lder yo u are go ing to use fo r the sample sc ripts:
Your name:
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
541
■
■
Next, o pen the template file. Internet Explo rer displays the fo rm, and yo u c an c hec k whether everything lo o ks the way yo u planned.
Displaying the template dialog box No w yo u are ready to display the fo rm template with yo ur new c usto m dialo g COM o bjec t (see Figure 19-1). Make sure the fo llo wing sample sc ript is sto red in the same fo lder yo u sto red yo ur HTML template! ‘ 19-1.VBS set tool = CreateObject(“Web.dialog”) ‘ current path myname = WScript.ScriptFullName cp = left(myname, InstrRev(myname, “\”)) ‘ template template = cp & “template.htm” ‘ size dialog tool.Width = 400 tool.Height = 300 tool.Title = “My Form” tool.SetIcon “shell32.dll”, 3 tool.Resizable = true ‘ display dialog and return object reference set webcontrol = tool.ShowDialog(template) MsgBox TypeName(webcontrol)
Figure 19-1: Us e an HTML template to des ign your ow n dialog box. The sc ript c reates a dialo g bo x and displays yo ur HTML template. Onc e yo u c lic k OK, the COM o bjec t returns a referenc e to the element c o llec tio n. Yo u’ll need this referenc e in a minute. First, take a lo o k at yo ur o ptio ns in Table 19-1.
542
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Table 19-1
Properties and M ethods to Control the WebBrow ser Dialog Box
M ethod/Property
Description
Property CancelButton As String
Caption name of Cancel button.
Function DisplayDialog As Object
Show s dialog box and returns element collection.
Property Height As Long
Height of dialog box in pixels .
Function LoadDialog(ByVal template As String) As Object
Loads dialog template and returns element collection.
Property OKButton As String
Caption name of OK button.
Property Resizable As Boolean
True: Dialog box is res izable.
Sub SetIcon(ByVal iconlib As String, ByVal index As Long)
Sets the dialog box icon. Supply name of icon file and icon index.
Sub ShowButtons(ByVal mode As Boolean)
True: Dialog box dis plays OK and Cancel buttons .
Function ShowDialog(ByVal template As String) As Object
Combines LoadDialog and ShowDialog: Loads a template file, dis plays the dialog box, and returns element collection.
Property Title As String
Title of dialog box.
Property Width As Long
Width of dialog box in pixels .
Getting access to template elements Displaying your HTML template alone won’t be enough. You need a way to access the elements in your HTML template in order to query their values. After all, you want to know what the user has entered into your form (see Figure 19-2).
Figure 19-2: Examine the elements acces s ible in your HTML template.
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
543
■
■
The COM o bjec t returns a referenc e to the element c o llec tio n. This c o llec tio n c o ntains referenc es to all the elements yo u plac ed o nto yo ur HTML page. Let’s c hec k o ut ho w to read this c o llec tio n: ‘ 19-2.VBS set tool = CreateObject(“Web.dialog”) ‘ current path myname = WScript.ScriptFullName cp = left(myname, InstrRev(myname, “\”)) ‘ template template = cp & “template.htm” ‘ size dialog tool.Resizable = true tool.Width = 400 tool.Height = 300 tool.Title = “My Form” tool.SetIcon “shell32.dll”, 3 ‘ display dialog and return object reference set webcontrol = tool.ShowDialog(template) ‘ read all named elements for each element in webcontrol on error resume next elname = element.name if not err.number=0 then ‘ element has no name tag! elname = “no name property, type: “ & TypeName(element) end if on error goto 0 list = list & elname & vbCr next MsgBox list
This time, o nc e yo u c lic k OK, the sc ript returns a list o f all the elements inside yo ur HTML template. There are a lo t o f unnamed c o ntro l elements, but yo u also see all the named elements. Named elements are elements yo u assigned a NAME= tag. No w it’s easy to retrieve the results so meo ne has entered into yo ur fo rm: ‘ 19-3.VBS set tool = CreateObject(“Web.dialog”) ‘ current path myname = WScript.ScriptFullName cp = left(myname, InstrRev(myname, “\”))
544
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
‘ template template = cp & “template.htm” ‘ size dialog tool.Resizable = true tool.Width = 400 tool.Height = 300 tool.Title = “My Form” tool.SetIcon “shell32.dll”, 3 ‘ display dialog and return object reference set webcontrol = tool.ShowDialog(template) ‘ read input if TypeName(webcontrol)=”Nothing” then MsgBox “You cancelled!” else MsgBox “You entered: “ & webcontrol.namefield.value end if
Expand yo ur HTML template to ask fo r mo re than o ne piec e o f info rmatio n. It’s c o mpletely up to yo u ho w c o mplex yo u want yo ur dialo g windo w to get!
Figure 19-3: It w orks — your s cript retrieves the input.
Designing dialog box templates The mo st o bvio us advantage o f HTML dialo g bo xes is their versatility. Yo u c an c hange the design o f yo ur dialo g bo x templates witho ut having to c hange the COM o bjec t in any way, and yo u do n’t need any c o mplic ated subc lassing tec hniques to dynamic ally add o r remo ve fo rm elements. There’s o nly o ne thing yo u need to ensure, and that’s to supply a NAME= tag fo r eac h input element yo u want to query. Witho ut the NAME= property, yo ur sc ript c an’t ac c ess the element’s value. Also take a lo o k at the BODY tag. This tag defines the bac kgro und c o lo r and turns o ff the vertic al sc ro ll bar.
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
545
■
■
The STYLE sec tio n uses a style sheet to c hange the fo nt the P element uses. Style sheets are a great way to glo bally assign fo rmatting info rmatio n to yo ur fo rm elements.
Revealing implementation details Befo re I sho w yo u mo re tric ks yo u c an do with yo ur new HTML dialo g bo x to o l, here are so me implementatio n details. If yo u do n’t c are ho w the COM o bjec t do es its wo rk, skip this part! The Resizable pro perty is o ne o f the mo st remarkable features: This pro perty c o ntro ls whether o r no t yo ur fo rm windo w is resizable. This may no t seem to be a big deal, but ac tually it is. Yo u c an’t c hange pro perties like this o ne during run-time. The windo w frame — whic h determines whether the fo rm is resizable o r no t — needs to be defined at design-time. There are ways to o verc o me this limitatio n, but they are very c o mplex. The COM o bjec t uses a muc h simpler appro ac h. It ac tually uses two fo rms — o ne is resizable, and the o ther o ne isn’t. The Resizable pro perty sets a glo bal referenc e to o ne o f the two fo rms, and all o ther pro perties and metho ds use this referenc e. This is why yo u sho uld use the Resizable pro perty befo re yo u use any o f the o ther pro perties and metho ds. Generally, yo ur dialo g bo x is c entered o nsc reen. Again, there are many c o mplex ways to c enter a fo rm, but they are c o mpletely unnec essary. The fo rm c o ntains a pro perty c alled StartUpPosition, and this pro perty just needs to be set to CenterScreen. That’s all there is to it. The VBSc ript has so me interesting parts, to o ! It uses ScriptFullName to retrieve its o wn file path and extrac ts the pure path info rmatio n. This way, the sc ript “kno ws” the fo lder name it is sto red in. This fo lder is appended to the template filename, and as a result, yo u do n’t need to fiddle aro und with template file paths. Just make sure the template file is sto red in the same fo lder yo u sto red yo ur sc ript in.
Advanced WebBrowser Tricks Let’s take a quic k lo o k at the arc hitec ture o f yo ur HTML dialo g bo xes. Three c o mpo nents are invo lved. Yo ur sc ript is part o ne. It launc hes the COM o bjec t, whic h in turn displays the WebBrowser c o ntro l. This is part two . Part three is yo ur HTML template, sho wn inside the WebBrowser c o ntro l. To get the mo st o ut o f this arc hitec ture, yo u need ways to c o mmunic ate between these c o mpo nents. Co mmunic atio n requires handles to the partic ipating o bjec ts, and in the prec eding examples, yo u saw ho w this wo rks.
CreateObject returns a handle to the COM o bjec t so yo ur sc ript c an c all its internal metho ds. ShowDialog in turn again returns a handle. To be exac t, it returns an element c o llec tio n, and this element c o llec tio n c o ntains the
546
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
handles o f all the elements inside yo ur HTML template. Bo th yo ur sc ript and yo ur COM o bjec t c an ac c ess any single HTML element in yo ur template, and the example used this handle to retrieve the value entered into the text field.
Calling script procedures through your HTML template Maybe yo u no tic ed the Help butto n o n the sample fo rm. It was o f no use — c lic king the butto n didn’t do a thing. No t yet, anyway. Test yo ur new kno wledge abo ut inter-c o mpo nent c o mmunic atio ns and ho o k up a sc ript pro c edure to this butto n (see Figure 19-4). Yo ur sc ript needs to ac c ess the butto n. That’s easy, bec ause yo ur sc ript kno ws the element’s referenc e so it c an ac c ess all pro perties. Ho w c an yo ur sc ript ask the butto n to exec ute a sc ript pro c edure? Yo ur sc ript needs to get a referenc e to the sc ript pro c edure and pass it to the onclick event o f the butto n. So unds c o mplic ated, but it isn’t! ‘ 19-4.VBS set tool = CreateObject(“Web.dialog”) ‘ current path myname = WScript.ScriptFullName cp = left(myname, InstrRev(myname, “\”)) ‘ template template = cp & “template.htm” ‘ size dialog tool.Width = 400 tool.Height = 300 tool.Title = “My Form” ‘ load template first! This way, you get a handle ‘ to the HTML elements without displaying the form yet set webcontrol = tool.LoadDialog(template) ‘ configure the dialog ‘ hook up a script procedure to the help button webcontrol.help.onclick = GetRef(“showhelp”) ‘ now display the dialog. Note that the help button now ‘ invokes the showhelp procedure! set webcontrol = tool.DisplayDialog ‘ read input if TypeName(webcontrol)=”Nothing” then MsgBox “You cancelled!”
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
547
■
■
else MsgBox “You entered: “ & webcontrol.namefield.value end if sub ShowHelp MsgBox “Please enter your full name!” end sub
No w it wo rks! Every time yo u c lic k the Help butto n, a help message appears. This help message c o mes fro m yo ur sc ript. The help butto n remo tely invo kes the ShowHelp pro c edure defined in yo ur sc ript. Yo u no w c an c all any sc ript pro c edure while the dialo g bo x is still visible. Imagine the po ssibilities — no t o nly c an yo u supply Help butto ns fo r any input field, yo u c an also update fo rm elements thro ugh a database, o r yo u c an c hec k the fo rm c o ntents befo re yo u allo w the user to quit the fo rm.
Figure 19-4: The Help button invokes the help procedure of your ow n s cript. The magic behind this is GetRef. This metho d returns a referenc e to the sc ript pro c edure, whic h in turn c an be attac hed to the butto n onClick event.
Communication between the HTML template and the COM object So far, yo ur sc ript has c o mmunic ated with bo th the COM o bjec t and the HTML template elements. Is there a way yo ur HTML template c an c o mmunic ate with the COM o bjec t, to o ? The COM o bjec t ho sts yo ur HTML template, and it c an be nic e to inc lude butto ns in yo ur template that c o ntro l the COM o bjec t. Fo r example, yo u c an inc lude a butto n that c lo ses the dialo g bo x. But ho w? Yo ur HTML do c ument needs a referenc e to yo ur COM o bjec t. This is why the COM o bjec t tries to insert suc h a referenc e into yo ur HTML do c ument. hookquit tries to assign the referenc e to a variable c alled parentobj. Ho wever, this fails bec ause there is no suc h variable inside yo ur HTML do c ument.
548
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
But, yo u c an c hange yo ur HTML template. Open it inside a text edito r and add a sc ript blo c k. Then save it as TEMPLATE2.HTM: (see Figure 19-5)
Your name:
No w try yo ur sc ript again: Exc hange TEMPLATE.HTM inside the sc ript with TEMPLATE2.HTM, o r use sc ript 19-4-2.VBS. The fo rm has c hanged, and there are two mo re butto ns — Quit and Do ne. Quit do es exac tly what yo ur Fo rm windo w Canc el butto n do es, and Do ne mimic s the OK butto n.
Figure 19-5: You new template features a Quit button that clos es the form.
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
549
■
■
Take a lo o k at the new sc ript blo c k. It defines an o bjec t referenc e c alled parentobj and sets it to Nothing. Then, it defines two pro c edures — Quit and Leave. These c all the Quit metho d defined in the parentobj o bjec t. But what is the parentobj o bjec t anyway? To make things wo rk, yo ur COM o bjec t inserts a referenc e to its o wn Form o bjec t into the HTML do c ument parentobj variable. This happens inside hookquit.
Parentobj no w po ints to the fo rm o bjec t o f yo ur COM o bjec t, and inside the fo rm, there’s no w a Quit pro c edure. Yo ur HTML do c ument no w c an remo tely ac c ess yo ur fo rm o bjec t’s internal pro c edures (see Figure 19-6). Yo u c an expand this c o nc ept easily. Yo ur HTML do c ument no w c an ac c ess any internal metho d yo ur COM o bjec t pro vides. Bec ause no w that yo ur HTML do c ument c an handle the OK and Canc el o peratio ns remo tely, yo ur dialo g bo x no lo nger needs to pro vide its o wn butto ns. Remo ve them. ‘ 19-5.VBS set tool = CreateObject(“Web.dialog”) ‘ current path myname = WScript.ScriptFullName cp = left(myname, InstrRev(myname, “\”)) ‘ template template = cp & “template2.htm” ‘ size dialog tool.Width = 400 tool.Height = 300 tool.Title = “My Form” ‘ remove buttons tool.ShowButtons false ‘ load template first! This way, you get a handle ‘ to the HTML elements without displaying the form yet set webcontrol = tool.LoadDialog(template) ‘ configure the dialog ‘ hook up a script procedure to the help button webcontrol.help.onclick = GetRef(“showhelp”) ‘ now display the dialog. Note that the help button now ‘ invokes the showhelp procedure! set webcontrol = tool.DisplayDialog ‘ read input if TypeName(webcontrol)=”Nothing” then
550
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
MsgBox “You cancelled!” else MsgBox “You entered: “ & webcontrol.namefield.value end if sub ShowHelp MsgBox “Please enter your full name!” end sub
Figure 19-6: Get rid of the s tandard buttons and us e your ow n template to control the form. No w, yo u are abso lutely free in yo ur design. Yo ur input elements c an ac c ess the COM o bjec t metho ds and ho o k them to their o wn events. Yo ur o wn OK and Canc el butto ns c an use DHTML sc ript to c hec k the input befo re allo wing the fo rm to c lo se.
Automatically closing the form on RETURN Fo r example, the next HTML template ac c esses the do c ument’s onkeypress event. It c hec ks fo r the c harac ter c o des 13 (RETURN) and 27 (ESC) and c alls the COM o bjec t metho ds to either send the input o r c anc el the dialo g bo x. As a result, the keys [Esc ] and [Enter] no w are c o nnec ted to the Canc el and OK butto ns. Onc e yo u finish yo ur input with [Enter], the fo rm is auto matic ally c lo sed, and yo u do n’t need to grab the mo use and c lic k OK. Save this template as TEMPLATE3.HTM and c hange yo ur sc ripts ac c o rdingly. Yo u c an also use sc ript 19-5-2.VBS o n the CD.
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l ■
551 ■
Your name->:
Hooking COM procedures to individual elements The previo us template respo nds to [Esc ] and [Return] no matter whic h element is c urrently selec ted. Maybe yo u do n’t like this idea. Yo u c an also ho o k the keybo ard c hec ker to spec ific input elements. Save this template as TEMPLATE4.HTM and c hange yo ur sc ripts ac c o rdingly, o r use sc ript 19-53.VBS.
552
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Your name->:
This time, the [Esc ] and [Enter] keys are rec o gnized o nly inside yo ur text bo x element. The sc ript inside the template has plac ed the keybo ard c hec k into a regular pro c edure c alled checkkeyboard. This pro c edure is then ho o ked to the keypress event o f the text bo x. The sc ript demo nstrates ano ther nic e advantage — yo ur text bo x element rec eives the fo c us auto matic ally, and yo u no lo nger have to c lic k the element befo re entering text. No w, yo ur dialo g bo x is ready, and yo u c an type in text immediately. And [Enter] sends the input to yo ur sc ript. Yo ur HTML dialo g bo x is just as c o nvenient to use as the built-in InputBox metho d.
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
553
■
■
Assigning the input fo c us to an element in regular Web pages is easy. Just c all the focus metho d o f the element that yo u want to rec eive the fo c us. Ho wever, this wo n’t wo rk in the prec eding example. The focus() metho d c an switc h fo c us to the element o nly o nc e it is visible o nsc reen. This is why the sc ript c alls the focus metho d in the BODY tag onload pro perty. This still isn’t eno ugh. Even tho ugh the do c ument is lo aded when onload is exec uted, it takes so me extra time fo r the elements to be fully pro grammable. This is why the sc ript do esn’t c all the focusit pro c edure direc tly. Instead, it uses the timer built into the window o bjec t and c alls it with a 100-millisec o nd delay. No te also that the focusit pro c edure needs to be defined in the HEAD sec tio n. It needs to be defined befo re the WebBrowser c o ntro l parses the BODY tag. If yo u want ano ther element to rec eive the fo c us, just c hange the element name in the focusit pro c edure.
Checking for valid form entries Using yo ur o wn OK and Canc el butto ns instead o f the butto ns the COM o bjec t pro vides has many advantages. Fo r example, yo u c an do uble-c hec k the user input befo re yo u allo w the fo rm windo w to c lo se. Save this template as TEMPLATE5.HTM and c hange yo ur sc ripts ac c o rdingly, o r use sc ript 19-54.VBS (see Figure 19-7).
Your name->:
The Leave pro c edure no w c hec ks whether the user has entered text at all. If the text field is empty, the sc ript flashes the text bo x bac kgro und c o lo r and displays a message. As lo ng as the text bo x is empty, the Canc el butto n is the o nly way to c lo se the fo rm windo w.
Figure 19-7: Automatically focus and check the input. Use this as a fo undatio n fo r yo ur o wn c hec ks. Yo u c an c hec k mo re than o ne field. Yo u c an c hec k the c o ntent and make sure the user has entered the type o f data yo u expec t. Yo u c an even disable the OK butto n fo r as lo ng as the user input c o ntains erro rs.
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
555
■
■
Responding to WebBrowser control events So far, yo ur COM o bjec t displays any HTML file yo u pro vide. But ho w c an yo u ac c ess the events raised by the WebBrowser c o ntro l? Use the WithEvents statement. The COM o bjec t defines a variable c alled htmldoc o f type HTMLDocument as WithEvents. The deeper meaning behind this is that the variable htmldoc no w c an ho st a referenc e to an HTML do c ument and c an also handle any events the HTML page may raise. Then, the LoadDialog pro c edure assigns the handle to the WebBrowser c o ntro l do c ument to this variable. Fro m no w o n, yo ur COM o bjec t c an respo nd to events raised by the HTML do c ument. And it do es. The func tio n htmldoc_oncontextmenu is c alled anytime a user tries to o pen a c o ntext menu. Bec ause yo u do n’t want an Internet Explo rerstyle c o ntext menu to appear o n yo ur dialo g bo x, the func tio n always returns false, effec tively disabling c o ntext menus. The oncontextmenu event is suppo rted o nly o n IE5.
Reading Groups of Radio Buttons HTML fo rms c an c o nsist o f mo re than just text bo xes. Radio butto ns wo rk like the radio butto ns o n yo ur o ld c ar stereo — o nly o ne selec tio n in a gro up c an be c ho sen at any time. Radio butto ns are perfec t fo r o ffering mutually exc lusive o ptio ns. Ho wever, ho w do yo u c reate Radio butto n gro ups, and even mo re impo rtant, ho w c an yo ur sc ript read the selec ted o ptio n?
Creating a group of radio buttons Radio butto ns are plain INPUT elements o f type “radio .” Their name pro perty gro ups them to gether (see Figure 19-8). Radio butto ns wo rk mutually exc lusively o nly when yo u gro up them to gether. Gro uping takes plac e by assigning the same name to all radio butto n elements in this gro up. Here’s an example file. Save it as TEMPLATE6.HTM.
556
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Choose an Option!
Option 1 Option 2 Option 3
Figure 19-8: Us e fixed-s ized dialog boxes and dis play any kind of form element you like. To display this template, use the fo llo wing sc ript: ‘ 19-6.VBS set tool = CreateObject(“Web.dialog”) ‘ current path myname = WScript.ScriptFullName cp = left(myname, InstrRev(myname, “\”)) ‘ template template = cp & “template6.htm” ‘ size dialog tool.Resizable =false tool.Width = 400 tool.Height = 200 tool.Title = “Option Dialog” set webcontrol = tool.ShowDialog(template) ‘ read input MsgBox “Done!”
The dialo g bo x fo rm displays nic ely, but yo ur sc ript c an’t read the selec ted o ptio n. If yo u try to ac c ess the webcontrol.r1.value o ptio n, yo u get an erro r (see Figure 19-9).
Chapte r 1 9 : Us ing the We bBro ws e r Co ntro l
557
■
■
Whenever yo u gro up an input field by naming all elements the same, it’s treated as an array. Yo u c an’t ac c ess individual elements o f a gro up direc tly. Instead, yo u need to determine the size o f the array (the number o f elements in the gro up) and pic k the o ne yo u are interested in. Bec ause there are three elements c alled r1, yo u need to treat r1 as an o bjec t array. Ac tually, in yo ur template, there is no element c alled r1, but there are three elements c alled r1(0), r1(1), and r1(2). This is ho w yo u c an read any gro up o f input elements and determine the value o f the c hec ked o ne: ‘ read input if TypeName(webcontrol)=”Nothing” then MsgBox “You cancelled!” else for x=0 to (webcontrol.r1.length)-1 if webcontrol.r1(x).checked then optionval = webcontrol.r1(x).value end if next MsgBox “You chose: “ & optionval end if
Figure 19-9: Now you can read in the res ults from the options dialog box group. Append this c o de to yo ur sc ript, and yo u are all set. Here’s the c o mplete sc ript: ‘ 19-7.VBS set tool = CreateObject(“Web.dialog”) ‘ current path myname = WScript.ScriptFullName cp = left(myname, InstrRev(myname, “\”)) ‘ template template = cp & “template6.htm” ‘ size dialog tool.Resizable =false tool.Width = 400
558
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
tool.Height = 200 tool.Title = “Option Dialog” set webcontrol = tool.ShowDialog(template) ‘ read input if TypeName(webcontrol)=”Nothing” then MsgBox “You cancelled!” else for x=0 to (webcontrol.r1.length)-1 if webcontrol.r1(x).checked then optionval = webcontrol.r1(x).value end if next MsgBox “You chose: “ & optionval end if
Bec ause the Web is based mainly o n JavaSc ript, the HTML o bjec t mo del returns the number o f elements in the gro up using the length pro perty instead o f the VBSc ript Co unt pro perty. Still, yo ur VBSc ript c an use this pro perty even tho ugh it do esn’t fo llo w VBSc ript naming c o nventio ns. A lo o p c hec ks all elements in the gro up and returns the value o f the element marked as c hec ked. Yo u need to deal with element arrays o nly when yo u read fo rm c o ntent fro m within a Web page using sc ript statements. If yo u submit a fo rm to so me Web server, yo u do n’t need to c are muc h. Submitting a fo rm sends o nly the c hec ked elements, so there wo n’t be mo re than o ne r1 element, and yo u c an ac c ess its value direc tly.
Summary The WebBrowser c o ntro l is a real gem. This c hapter has sho wn yo u so me o f what it c an do fo r yo u. The COM o bjec t I develo ped serves as a general-purpo se dialo g bo x c o ntainer, and yo u have seen many examples o n ho w to c reate yo ur o wn dialo g bo xes using plain HTML templates. This is a great fo undatio n fo r teamwo rk. Yo u c an let a graphic designer c reate the dialo g bo x design while yo u pro vide the COM o bjec t to ho st it. Thro ugh advanc ed event handling, yo ur COM c o ntainer c an be c o ntro lled entirely by yo ur HTML template. Yo u c an even c lo se the fo rm windo w fro m inside yo ur HTML sc ript c o de.
Chapte r 2 0
Internet and Communications In This Chapter 䊳 Co nnec t and disc o nnec t to the Internet by sc ript auto matic ally 䊳 Establish FTP c o nnec tio ns and retrieve FTP direc to ry listings 䊳 Do wnlo ad Web pages and FTP files auto matic ally 䊳 Uplo ad FTP files fro m yo ur lo c al hard disk to yo ur Web server 䊳 Sync hro nize yo ur lo c al Web site with a remo te Web server auto matic ally 䊳 Reso lve IP addresses and ho st names using WinSo c k
I
n this c hapter, learn ho w to add new sc ripting features that allo w yo ur sc ripts to auto matic ally c o nnec t and disc o nnec t to the Internet. Yo ur sc ripts will even be able to reso lve ho st names and transfer files between yo ur lo c al c o mputer and Web servers using the built-in FTP c apabilities.
Accessing the Internet Wo uldn’t it be great to be able to c o nnec t to the Internet using sc ripts? This way, yo u c o uld auto matic ally retrieve info rmatio n in regular intervals o r uplo ad files to yo ur Web server. Unfo rtunately, the Sc ripting Ho st o ffers next to no Internet suppo rt. This is surprising bec ause Windo ws do es c o ntain all the func tio ns nec essary to c o nnec t, disc o nnec t, and do wnlo ad files. Windo ws even c o ntains all the func tio ns nec essary to do FTP file transfer. FTP file transfer is a metho d to send data ac ro ss a TCP/ IP netwo rk like the Internet. Yo u c an bo th do wnlo ad and uplo ad any file yo u want. In this c hapter, yo u get all the sc ripting extensio ns nec essary fo r full Internet ac c ess — a tremendo usly useful to o lbo x that yo u wo uld have to pay a lo t o f mo ney fo r if yo u bo ught it fro m third-party vendo rs.
560
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Creating a universal Internet script extension The sc ript extensio n is just a COM o bjec t, and again it’s c reated using the free Visual Basic CCE. Yo u find the c o mplete so urc e c o de here: \components\ internet\internet.vbp. Take a lo o k at it and c hange it any way yo u please. To use the sc ript extensio n, make sure yo u install the COM o bjec t \install\internet\setup.exe.
Connecting to the Internet Regular sc ripts c an c o nnec t to the Internet witho ut any sc ript extensio n (see Figure 20-1). All yo u need to do is supply a valid http address: ‘ 20-1.VBS set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “http://www.altavista.com/”
Ho wever, this simple appro ac h has a majo r limitatio n — the sc ript c an’t establish the Internet c o nnec tio n itself but relies o n yo ur settings instead. If yo u dial into the Internet using a mo dem c o nnec tio n, yo u’ll mo st likely end up with a dialo g bo x asking fo r permissio n to dial. Even wo rse: Yo ur sc ript has no way o f disc o nnec ting the Internet c o nnec tio n o nc e it is established. There’s way to o muc h manual wo rk left fo r yo u.
Figure 20-1: You need a w ay to bypas s the connect dialog box and connect automatically. So ho w c an yo u c o nnec t to the Internet auto matic ally, and ho w c an yo u disc o nnec t o nc e yo ur sc ript is do ne?
Chapte r 2 0 : Inte rne t and Co mmunic atio ns
561
■
■
Use yo ur new sc ript extensio n. The fo llo wing sc ript c o nnec ts auto matic ally and o ffers to disc o nnec t at any time: ‘ 20-2.VBS set tool = CreateObject(“internet.communication”) set wshshell = CreateObject(“WScript.Shell”) ‘ automatically connect if tool.ConnectInternet then wshshell.Run “http://www.altavista.com/” MsgBox “Click OK to close connection!”, vbSystemModal if tool.DisconnectInternet then MsgBox “Connection closed.” else MsgBox “Connection couldn’t be closed down! “ _ & “It may be closed already!” end if else MsgBox “Unable to connect to Internet. Is your modem turned on?” end if
Closing the connection once the Web page is loaded The previo us sc ript left it up to yo u to c lo se the c o nnec tio n. Yo u might want to c lo se the c o nnec tio n yo urself o nc e the Web page is c o mpletely lo aded. Try this: ‘ 20-3.VBS set tool = CreateObject(“internet.communication”) set ie = CreateObject(“InternetExplorer.Application”) url = “www.altavista.com/” ‘ automatically connect if tool.ConnectInternet then ie.navigate url do loop until ie.ReadyState=4 ie.visible = true if not tool.DisconnectInternet then MsgBox “Warning: Connection could not be closed!” end if else MsgBox “Unable to connect to Internet. Is your modem turned on?” end if
This sc ript c o nnec ts to the Internet, lo ads a page, and disc o nnec ts immediately. Use the InternetExplorer o bjec t to get muc h mo re granular c o ntro l o ver the Internet. In the previo us example, the sc ript queried the ReadyState pro perty. It returns 4 o nc e the do c ument is fully lo aded.
562
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Using FTP to download and upload files FTP is the file transfer pro to c o l. Yo u c an use it to do wnlo ad files fro m FTP servers and uplo ad files to yo ur o wn Web server. Ho wever, yo u need to o ls to get ac c ess to the FTP c o mmands. That’s bad bec ause mo st to o ls do n’t suppo rt sc ripts, and they are expensive. Fo rtunately, Windo ws already c o ntains all the func tio ns nec essary to do FTP. Yo ur sc ript extensio n has wrapped them and made them ac c essible to yo ur sc ripts. In this part, yo u gain c o mplete c o ntro l o ver Internet file handling.
General rules for accessing FTP To do FTP, yo ur sc ript always fo llo ws the same set o f steps:
1. Establish a c o nnec tio n to the Internet using ConnectInternet. 2. Establish a handle to the FTP server using ConnectFTP. 3. Call metho ds to manage the FTP server by supplying the handle to the FTP server yo u c o nnec ted to .
4. Clo se the FTP server handle using CloseHandle. 5. Disc o nnec t fro m the Internet using DisconnectInternet. Let’s take a lo o k at so me real-wo rld examples.
Accessing an FTP server Yo u c an ac c ess FTP servers ano nymo usly. If yo u do , yo u c an o nly c o nnec t to public servers, and mo st likely yo u are limited to do wnlo ading files o nly. On the o ther hand, yo u c an authentic ate yo urself using a username and passwo rd and lo g o n to the server as a spec ific user. Pro vided yo u have ac c ess to the server and the appro priate permissio ns, yo u’ll no w be able to do all kinds o f stuff: fo r example, uplo ad new files to yo ur Web server o r delete unnec essary files. Use ConnectFTP to get ac c ess to any FTP server. If yo u just spec ify the FTP server name, the COM to o l will c o nnec t yo u ano nymo usly. If yo u spec ify an additio nal username and passwo rd, the to o l tries to lo g o n using yo ur c redentials. The result is always a handle. This handle is 0 if the c o nnec tio n request fails, and it’s a number o ther than 0 if it suc c eeds. Use the handle to issue FTP c o mmands to yo ur server.
Retrieving an FTP directory listing The first step sho uld be a direc to ry listing. Whic h files and fo lders are available o n the FTP server yo u c o nnec ted to ? Have a lo o k! The next sc ript
Chapte r 2 0 : Inte rne t and Co mmunic atio ns ■
563 ■
c o nnec ts to the public server ftp.microsoft.com and retrieves the direc to ry listing (see Figure 20-2): ‘ 20-4.VBS set tool = CreateObject(“internet.communication”) ftpdir = “ftp.microsoft.com” ‘ automatically connect if tool.ConnectInternet then ‘ open FTP server handle = tool.ConnectFTP(ftpdir) dirlist = tool.Dir(handle) ‘ close connection tool.CloseHandle handle tool.DisconnectInternet ‘ display FTP directory MsgBox dirlist, vbInformation else MsgBox “Unable to connect to Internet. Is your modem turned on?” end if
Figure 20-2: Retrieve information about FTP directory contents .
Trapping connect errors Yo u c an further enhanc e yo ur sc ripts by trapping erro rs in c ase the FTP c o nnec tio n c an’t be established. Use a mec hanism like this: ‘ open FTP server
564
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
on error resume next handle = tool.ConnectFTP(ftpdir) if handle=0 then MsgBox “Connection failed!” WScript.Quit end if on error goto 0
Sc ript 20-4.VBS returns info rmatio n abo ut files and fo lders ac c o rding to the sc heme o utlined in Table 20-1.
Table 20-1
Information Retrieved from an FTP Server
Information Description File or Folder Name
Name of file or folder
File Date
Time s tamp: When w as the file w ritten to the s erver?
File Size
Size of file in bytes
Attributes
File or folder attributes
The attributes listed in Table 20-2 give yo u additio nal info rmatio n abo ut the file o r fo lder.
Table 20-2
File Attributes on FTP Servers
Attribute
Description
1
Write -protected
2
Hidden
4
Sys tem file
16
Folder
32
Shortcut
128
Compres s ed
Yo u c an either manually c o nvert the info rmatio n inside yo ur sc ript o r leave this wo rk to yo ur sc ript extensio n. Use FriendlyDir instead o f Dir to retrieve a pre-fo rmatted FTP direc to ry listing (see Figure 20-3).
Chapte r 2 0 : Inte rne t and Co mmunic atio ns
565
■
■
Figure 20-3: FriendlyDir formats the directory lis ting.
Listing subfolders The Dir metho d lists the current FTP directo ry by default. The current directo ry is the o ne yo u co nnected to . Yo u can list any FTP directo ry, tho ugh. Just specify the relative o r fully qualified fo lder name as seco nd argument. Relative filenames are relative to the c urrent fo lder. Fully qualified filenames always wo rk no matter whic h fo lder is selec ted as the c urrent fo lder. They start with the FTP ro o t fo lder and always begin with a “/” c harac ter. Ho wever, there’s a do wnside to this appro ac h: Dir c an’t deal with spac es, and if yo u spec ify an invalid fo lder path, Dir returns an erro r pro to c o l instead o f the fo lder listing. So do n’t use the sec o nd argument to selec t an FTP fo lder. Instead, c hange the c urrent fo lder to the fo lder yo u want to list using ChDir. Then, use Dir to list this c urrent fo lder. Still, the sec o nd argument isn’t wo rthless. Use it as a wildc ard to selec t files. First, c ho o se the fo lder yo u want to list using ChDir. Then, use Dir and spec ify the searc h filter using its sec o nd parameter. The fo llo wing sc ript lists a subfo lder c alled code and displays its c o ntent. Then, it uses *.VBS as filter to display VBS sc ript files o nly (see Figure 20-4). Instead o f Dir, it uses FriendlyDir to fo rmat the listing and make it mo re readable: ‘ 20-5.VBS set tool = CreateObject(“internet.communication”) ftpdir = “10.10.1.98”
566
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
‘ automatically connect if tool.ConnectInternet then ‘ open FTP server handle = tool.ConnectFTP(ftpdir) ok = tool.ChDir(handle, “/code”) if ok then MsgBox tool.Dir(handle) MsgBox tool.Dir(handle, “*.VBS”) else MsgBox “ChDir failed: no such folder!” end if ‘ close connection tool.CloseHandle handle tool.DisconnectInternet else MsgBox “Unable to connect to Internet. Is your modem turned on?” end if
The sc ript uses an IP address instead o f a do main name. Obvio usly, yo u need to c hange this info rmatio n to matc h a valid server. Using IP addresses instead o f do main names c an be useful in yo ur c o mpany’s intranet o r between lo c ally c o nnec ted develo pment enviro nments.
Figure 20-4: Filter FTP lis tings us ing w ildcards like *.
Receiving extended error information Bo th Dir and FriendlyDir return extended erro r info rmatio n if the FTP server is unable to pro vide the requested direc to ry listing. Mo st likely, yo u either spec ified a fo lder that do esn’t exist o r yo u do n’t have the nec essary permissio ns. The erro r message c larifies the issue and helps to identify the c ause (see Figure 20-5).
Chapte r 2 0 : Inte rne t and Co mmunic atio ns ■
567 ■
Figure 20-5: You’ll receive error information if the FTP lis ting is n’t acces s ible.
Downloading FTP files To do wnlo ad FTP files fro m a server, use GetFile and pro vide the handle to yo ur FTP server. The next example retrieves the file DISCLAIMER.TXT fro m the Mic ro so ft server. The c o nnec tio n will be c lo sed the mo ment the file is transferred to yo ur disk, and the sc ript o pens the file after a suc c essful do wnlo ad: ‘ 20-6.VBS set tool = CreateObject(“internet.communication”) ftpdir = “ftp.microsoft.com” ftpfile = “disclaimer.txt” newfile = “C:\msdisc.txt” ‘ automatically connect if tool.ConnectInternet then ‘ open FTP server handle = tool.ConnectFTP(ftpdir) ok = tool.GetFile(handle, ftpfile, newfile) ‘ close connection tool.CloseHandle handle tool.DisconnectInternet ‘ process results locally: if ok then MsgBox “File has been downloaded and saved as “”” _ & newfile & “””” ‘ open file: set wshshell = CreateObject(“WScript.Shell”) wshshell.Run “””” & newfile & “””” else MsgBox “Download error: “ & tool.GetLastError end if else MsgBox “Unable to connect to Internet. Is your modem turned on?” end if
568
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Altho ugh yo ur sc ript c lo ses do wn the Internet c o nnec tio n as so o n as no further data transfers are required, the sc ript still is no t fo o lpro o f. What if the server is so busy that the do wnlo ad takes ho urs to c o mplete? Use a timeo ut. Yo u c an’t use a general sc ript timeo ut, tho ugh, bec ause it wo uld shut do wn yo ur sc ript witho ut c lo sing the Internet c o nnec tio n. Instead, use the timer c o ntro l intro duc ed in Chapter 17.
Uploading FTP files Uplo ading files requires spec ial permissio ns, so in mo st c ases yo u need to lo g o n to the FTP server with spec ial c redentials. The fo llo wing sc ript uplo ads the file C:\MYFILE.HTM to a sample server c alled ftp.wininfo.de. Exc hange server names and uplo ad filenames and c redentials, with the appro priate names and c redentials yo u want to use. ‘ 20-7.VBS set tool = CreateObject(“internet.communication”) ftpdir = “ftp.wininfo.de” uploadfile = “C:\mypage.htm” ftpname = “mypage.htm” username = “itsme” password = “secret” ‘ automatically connect if tool.ConnectInternet then ‘ open FTP server handle = tool.ConnectFTP(ftpdir, username, password) ok = tool.PutFile(handle, uploadfile, ftpname) ‘ close connection tool.CloseHandle handle if MsgBox(“Close Internet Connection?”, vBYesNo) = vbYes then tool.DisconnectInternet end if ‘ process results locally: if ok then MsgBox “File has been uploaded and saved as “”” _ & ftpname & “””” else MsgBox “Upload error: “ & tool.GetLastError end if else MsgBox “Unable to connect to Internet. Is your modem turned on?” end if
Chapte r 2 0 : Inte rne t and Co mmunic atio ns
569
■
■
FTP is yo ur file transpo rt department. No t o nly c an yo u manage FTP servic es, yo u c an also uplo ad new HTML files to yo ur Web server. Just make sure that yo ur FTP base direc to ry equals yo ur Web server base direc to ry o r that yo ur Web server base direc to ry is ac c essible via FTP, and uplo ad HTML files to yo ur Web server. The mo ment tho se files are uplo aded, yo u c an view them as regular Web pages.
Synchronizing local folders and Web folders Mo st Web-site develo pers develo p o n their lo c al mac hines. Onc e a Web site is finished, it must be transferred to the real Web server. This is no big deal, bec ause c o untless FTP to o ls allo w yo u to uplo ad files and fo lders. Ho wever, mo st o f these to o ls c an o nly transpo rt data. It’s impo ssible to sync hro nize lo c al fo lders and Web fo lders. Sync hro nizing means yo u o nly transfer files that have c hanged. That’s impo rtant! Imagine yo u have uplo aded yo ur Web site and made mino r c hanges later o n to yo ur lo c al c o py. With the regular to o ls, yo u wo uld have to uplo ad yo ur entire site again. If yo u c an sync hro nize the fo lders, o nly the true c hanges have to be uplo aded — and this saves tremendo us time and c o sts. Yo ur sc ripts c an easily do the jo b. Yo u no w have metho ds to retrieve a Web fo lder direc to ry listing, and yo ur sc ript c an c o mpare this direc to ry listing to yo ur lo c al fo lder. By c o mparing file size and file time, the sc ript c an identify c hanges and selec tively uplo ad o nly the new o r c hanged files (see Figure 20-6). This script wo rks so well that I use it to co mpletely manage my o wn Web site. I maintain a lo cal co py o f my Web Site and make changes o nly to the lo cal co py. Whenever I have changed so mething, I launch my script. It auto matically takes care o f updating any necessary files and minimizes o nline time. I’ve “hard-co ded” all the necessary co nnectio n info rmatio n into my script so I do n’t have to enter anything to invo ke the update pro cess.
Figure 20-6: Automatically upload entire local Web s ites .
570
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
‘ 20-8.VBS set args = WScript.Arguments if args.Count=0 then dirname = InputBox(“Please enter local folder path”) else dirname = args(0) end if set fs = CreateObject(“Scripting.FileSystemObject”) set tool = CreateObject(“internet.communication”) ‘ does specified local folder exist? if not fs.FolderExists(dirname) then ‘ no, quit! MsgBox “Folder “”” & dirname & “”” not found!” WScript.Quit end if ‘ ask details about destination FTP server ftpdir = InputBox(“Please enter base FTP directory”) username = InputBox(“Please enter user name”) password = InputBox(“Please enter password”)
‘ find out subfolder if right(ftpdir,1)=”/” then ftpdir = left(ftpdir, len(ftpdir)-1) pos = Instr(ftpdir, “/”) if pos = 0 then subfolderpath = “” else subfolderpath = mid(ftpdir, pos) end if ‘ log results here: logfile = “C:\ftplog.txt” ‘ count transfer volume: transfer = 0 ‘ create log file: set reportfile = fs.CreateTextFile(logfile, true)
‘ ### now start synchronizing ### ‘ automatically connect if tool.ConnectInternet then ‘ log start starttime = time Report “CONNECT automatically to Internet”
Chapte r 2 0 : Inte rne t and Co mmunic atio ns ■
571 ■
‘ open FTP server on error resume next handle = tool.ConnectFTP(ftpdir, username, password) if not err.number=0 then Report “Error accessing server: “ & tool.GetLastError Reportfile.close Showreport WScript.Quit end if Report “ACCESS GRANTED to FTP Server “ & ftpdir ‘ synchronize folder Synchronize dirname, subfolderpath ‘ close connection tool.CloseHandle handle Report “CLOSED FTP connection” if MsgBox(“Close Internet Connection?”, vBYesNo) = vbYes then tool.DisconnectInternet Report “DISCONNECT Internet Connection” end if ‘ calculate statistics duration = DateDiff(“s”, starttime, time) transferKB = FormatNumber(transfer/1024,1) speed = FormatNumber((transfer/duration)/1024,2) Report duration & “ secs online, “ & transferKB _ & “ KB transferred, “ & speed & “ KB/s.” else MsgBox “Unable to connect to Internet. Is your modem turned on?” Report “Error: Unable to establish Internet connection” end if reportfile.close ShowReport sub Synchronize(local, web) ‘ access local folder set folder = fs.GetFolder(local) ‘ create dictionary to store the file names of web folder set dict = CreateObject(“Scripting.Dictionary”) ‘ compare case-insensitive dict.CompareMode = 1 ‘ get current web folder dir listing ‘ first, change current directory using absolute path name ‘ next, get current directory listing tool.ChDir handle, “/” & web dirraw = tool.Dir(handle)
572
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
‘ split into individual lines dirlist = Split(dirraw, vbCrLf) ‘ process each file for each entry in dirlist ‘ split info details per line entryinfo = Split(entry, vbTab) ‘ check whether entry is a file: if (Fix(entryinfo(3)) and 16)=0 then ‘ if so, add to dict filename, modifydate dict.Add entryinfo(0), entryinfo(1) end if next if web = “” then fill = “” else fill = “/” end if ‘ check each file in local folder for each file in folder.files ‘ exists on web server? if dict.Exists(file.name) then ‘ yes, check modify date timestamp = dict.Item(file.name) filetime = GetFileTime(file) if CDate(timestamp) maxrow then counter = 1 html.WriteLine “
” end if html.WriteLine “
” & filename & “
” end sub
This sc ript generates BMP preview thumbnails. They are dec o mpressed and take c o nsiderable spac e. Yo u c an easily expand the sc ript and let it delete all the thumbnails o nc e the preview page is printed. Obvio usly, yo u wo uldn’t want the sc ript to c o nvert yo ur o riginal files into thumbnails. So , yo ur sc ript needs a way to save the thumbnail as a new file. SaveAs do es the jo b, and mo re. SaveAs c an c o nvert pic ture fo rmats, to o .
Converting picture quality and color formats SaveAs no t o nly saves the c urrent pic ture to a new file, it c an also c o nvert files (see Table 21-3). Fo r example, yo u c an c hange a c o lo r pic ture to graysc ale.
BMP and AWD: alw ays 1 TIFF: 1: no compres s ion 2: Group3(1D) 3: Group3(Modified Huffman) 4: PackBits 5: Group4(2D) 6: J PEG 7: Res erved 8: not applicable 9: LZW
compressioninfo
0: no compres s ion/default compres s ion 1: EOL 2: Packed Lines 4: Prefixed EOL 8: Compres s ed LTR
Chapte r 2 1 : Fax, Printe r, Sc anne r, and Graphic s
601
■
■
Argument
Description 16: Expand LTR 32: Negate 64: J PEG high compres s ion/high quality 128: J PEG: high compres s ion/medium quality 256: J PEG: high compres s ion/low quality 512: J PEG: medium compres s ion/high quality 1024: J PEG: medium compres s ion/medium quality 2048: J PEG: medium compres s ion/low quality 4096: J PEG: low compres s ion/high quality 8192: J PEG: low compres s ion/medium quality 16384: J PEG: low compres s ion/low quality
safezoom
true: s ave image at current zoom level
Saving scanned pictures with compression Even if yo ur sc anner do esn’t allo w yo ur sc ript to set c o lo r o ptio ns, yo u c an always sc an in the highest quality available and determine the c o lo r depth when yo u save the pic ture. To be able to do that, yo u do n’t spec ify a filename to sc an in. Instead, use a ScanTo value o f 0: display o nly. Onc e the image is sc anned, yo u c an save it using the advanc ed SaveAs o ptio ns. Fo r example, the next sc ript sc ans in a pic ture and saves it as bo th a dec o mpressed BMP file and a c o mpressed TIFF file using JPEG c o mpressio n at highest c o mpressio n/highest quality. The sc ript then reveals the differenc e in file size. The c o mpressed image may very well take up o nly 10 perc ent o f the spac e required by the dec o mpressed file (see Figure 21-12). The exac t savings vary and depend o n the type o f pic ture yo u sc anned.
Figure 21-12: Saving images w ith compres s ion s aves a lot of room.
602
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Maybe yo u’re wo ndering abo ut the termino lo gy. Ho w c o me a TIFF file c an save images using JPEG c o mpressio n? What abo ut JPG files? TIFF files using JPEG c o mpressio n remain TIFF files. They are no t JPEG files. They just use the same type o f c o mpressio n, whic h is espec ially effec tive fo r pho to graphs. Unfo rtunately, yo u c an’t c hange a TIFF file to JPEG just by using JPEG c o mpressio n. ‘ 21-14.VBS set tool = CreateObject(“twain.manager”) ‘ check whether twain support is available if not tool.ScannerAvailable then MsgBox “No TWAIN support!”, vbCritical WScript.Quit end if ‘ tell control how to scan tool.ScanTo = 0 ‘ show scanner setup? tool.ShowSetup = false tool.ScanPageUI ‘ save as uncompressed bitmap tool.SaveAs “c:\testpic.jpg”, 3, 6, 1, 0 ‘ save as highest quality lowest size jpeg tool.SaveAs “c:\testpic.tif”, 1, 6, 6, 64 ‘ determine size differences set fs = CreateObject(“Scripting.FileSystemObject”) set file1 = fs.GetFile(“c:\testpic.jpg”) set file2 = fs.GetFile(“c:\testpic.tif”) msg = “Bitmap size: “ & FormatNumber(file1.size/1024,2) & “ KB” & vbCr msg = msg & “TIFF size: “ & FormatNumber(file2.size/1024,2) & “ KB” MsgBox msg, vbInformation
Choosing the right compression options Cho o sing valid c o mpressio n parameters isn’t always easy. Yo u are dealing with the mo st fundamental settings, and witho ut so me kno wledge abo ut graphic file fo rmats, yo u’ll quic kly run into “invalid c o mpressio n type” erro rs. Fo r example, a gray8 page type do esn’t suppo rt JPEG c o mpressio n, and a Palettized4 page type is valid o nly if the image already c o ntains a Palettized4 image. So what? Try it o ut. There’s o ne basic rule: Only TIFF files suppo rt c o mpressio n at all. So always c ho o se 1 as FileType. The rest is up to yo u and trial-and-erro r.
Chapte r 2 1 : Fax, Printe r, Sc anne r, and Graphic s ■
603 ■
There’s a smart way, to o . Use the metho d GetImageInfo to retrieve c o mpressio n settings o f TIFF files that already exist (see Figure 21-13). Here’s an example: ‘ 21-15.VBS filetype = Split(“,TIFF,AWD,BMP,PCX,DCX,JPG,XIF,GIF,WIFF”, “,”) pagetype = Split(“,BW,GRAY4,GRAY8,PALETTIZED4,” _ & “PALETTIZED8,RGB24,BGR24”, “,”) compressiontype = Split(“,NO COMPRESSION,GROUP3(1D),GROUP3” _ & “(MODIFIED HUFFMAN),PACKBITS,GROUP4(2D),JPEG,RESERVED,” _ & “GROUP3(2D),LZW”, “,”) compressioninfo = Split(“EOL,PACKED LINES,PREFIXED EOL,” _ & “COMPRESSED LTR,EXPAND LTR,NEGATE,JPEG “ _ & “HIGHCOMPRESS/HIGHQUAL,JPEG HIGHCOMPRESS/MEDIUMQUAL,” _ & “JPEG HIGHCOMPRESS/LOWQUAL,JPEG MEDIUMCOMPRESS/HIGHQUAL,” _ & “JPEG MEDIUMCOMPRESS/MEDIUMQUAL,JPEG “ _ & “MEDIUMCOMPRESS/LOWQUAL,JPEG LOWCOMPRESS/HIGHQUAL,” _ & “JPEG LOWCOMPRESS/MEDIUMQUAL,JPEG LOWCOMPRESS/LOWQUAL”, “,”) set tool = CreateObject(“twain.manager”) ‘ select file: filename = tool.OpenFile if filename = “” then MsgBox “You didn’t select a file!” WScript.Quit end if ‘ get image size: size = tool.ImageWidth & “ x “ & tool.ImageHeight & “ pixels” & vbCr ‘ get compression info: info = tool.GetImageInfo infodetail = Split(info, vbCr) ‘ create report: msg = filename & vbCr & size param = infodetail(0) msg = msg & “File type: “ & filetype(param) & “ (“ _ & param & “)” & vbCr param = infodetail(1) msg = msg & “Page type: “ & pagetype(param) & “ (“ _ & param & “)” & vbCr param = infodetail(2) msg = msg & “Compression: “ & compressiontype(param) _ & “ (“ & param & “)” & vbCr msg = msg & “Compression Details:” & vbCr if infodetail(3)=0 then msg = msg & “NO COMPRESSION (0)”
604
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
else for x= 0 to 14 if (infodetail(3) and 2^x)>0 then msg = msg & compressioninfo(x) _ & “ (“ & 2^x & “)” & vbCr end if next end if MsgBox msg, vbInformation
Figure 21-13: Determine detail information about images .
Repairing pictures with damaged file type info So metimes when yo u do wnlo ad pic tures o r rec eive them via e-mail, the file type extensio n gets lo st. This c an easily happen, bec ause the file type info rmatio n is just an add-o n to the filename. This has tremendo us c o nsequenc es: Yo u are unable to o pen the pic ture and have no way to c o rrec t the pro blem. Yo u c an mimic this disaster o n yo ur o wn system by entering the Explo rer o ptio ns (fo lder o ptio ns) and make the file extensio ns visible. Then, searc h fo r a pic ture file and rename it. Omit the file type extensio n and press [Enter]. Windo ws c o mplains and warns that this file may no t wo rk any lo nger. Go ahead and try to o pen the file: It wo n’t wo rk anymo re. Bec ause there’s no file type info rmatio n anymo re, Windo ws do esn’t kno w whic h pro gram to start. And bec ause pic ture files are binary data, yo u do n’t kno w the file type, either. The pic ture has bec o me useless. But it wo n’t be useless fo r lo ng. The Imaging to o l do esn’t c are abo ut file type extensio ns. Instead, it o pens the file and lo o ks at the kind o f data (see Figure 21-14). This is yo ur perfec t so lutio n to repair lo st file type extensio ns. Just drag any kind o f file o nto the sc ript ic o n, and the sc ript will tell yo u whether it’s a pic ture type it c an read and whether the file type extensio n needs repair.
Chapte r 2 1 : Fax, Printe r, Sc anne r, and Graphic s ■
605 ■
Figure 21-14: Correct w rong or mis s ing picture file type extens ions automatically. ‘ 21-16.VBS filetype = Split(“,TIFF,AWD,BMP,PCX,DCX,JPG,XIF,GIF,WIFF”, “,”) fileext = Split(“,tif,awd,bmp,pcx,dcx,jpg,xif,gif,wif”, “,”) set args = WScript.Arguments if args.Count=0 then MsgBox “Please drag a picture file on my icon!” WScript.Quit end if set tool = CreateObject(“twain.manager”) set fs = CreateObject(“Scripting.FileSystemObject”) ‘ load picture if possible on error resume next tool.Image = args(0) if not err.number=0 then MsgBox “Sorry! This is either no picture file, or I” _ & “ don’t recognize it!” WScript.Quit end if on error goto 0 ‘ get compression info: info = tool.GetImageInfo infodetail = Split(info, vbCr) pictype = infodetail(0) msg = “Picture is of type “ & filetype(pictype) & vbCr ‘ get files current extension: ext = lcase(fs.GetExtensionName(args(0))) ‘ is it correct? if not ext = fileext(pictype) then msg = msg & “I suspect a wrong file extension:” & vbCr msg = msg & “Current extension is “”” & ext & “””.” & vbCr msg = msg & “I believe it should much rather be “”” _ & fileext(pictype) & “””.” & vbCr
606
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
msg = msg & “Do you want me to correct the file type?” answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then set file = fs.GetFile(args(0)) name = fs.GetBaseName(args(0)) file.name = name & “.” & fileext(pictype) MsgBox “Corrected the issue...” else MsgBox “I’ll leave file untouched...” end if else msg = msg & “File extension is correct!” MsgBox msg, vbInformation end if
Summary Ko dak Imaging is unbelievable — this inno c ent little to o l c an pro vide many extra func tio ns fo r yo ur sc ripts. While the Image to o l itself is rather bo ring, yo ur sc ripts c an take the imaging func tio ns to the max. Print o r sc an huge numbers o f images as batc h auto matio n. Sc an images and c reate yo ur o wn c o lo r pho to c o py mac hine. Zo o m, ro tate, c hange fo rmat — yo u name it. Ano ther interesting aspec t o f Ko dak Imaging is that it c an ac tually read the internal fo rmat and size o f image files. This info rmatio n c o mes in handy when yo u want to c reate sc ripts that o rganize yo ur graphic s arc hive and delete pic tures o f lo w quality o r small size. The o nly serio us limitatio n to Ko dak Imaging is that it c an save images as TIF and BMP o nly. There are c o untless to o ls o ut there, tho ugh, that c o nvert fro m TIF to JPG o r GIF, so yo u’ll easily find a wo rk-aro und.
Chapte r 2 2
Fun, Tricks, and Multimedia In This Chapter 䊳 Extrac t ic o ns fro m files 䊳 Create a list o f all ic o ns available o n yo ur system 䊳 Change individual fo lder ic o ns and spic e up yo ur bo ring yello w fo lder
symbo ls 䊳 Open and c lo se the CD-ROM tray, ac c ess multiple CD-ROM drives, and query
the CD-ROM’s c apabilities 䊳 Play audio CDs, WAV so unds, MIDI files, and AVI mo vies 䊳 Rec o rd CD trac ks to WAV files and c o ntro l po sitio n and duratio n by the
millisec o nd auto matic ally
T
his c hapter is all abo ut fun. Yo u learn to find system ic o ns and c hange any fo lder, file, o r Windo ws ic o n to so mething yo u like better. Ac c ess multimedia devic es, play so unds, and even rec o rd yo ur favo rite audio CD as a WAV file. Truly amazing things happen inside the c usto m COM o bjec ts that pro vide the new func tio nality. In the so urc e c o de, yo u find valuable info rmatio n o therwise undo c umented.
Extracting Icons from Files Ic o ns are fun. They ac t as visual c lues, making it muc h easier to find impo rtant info rmatio n. Drive ic o ns indic ate drive type, and file ic o ns c harac terize file type. Ho wever, Windo ws keeps ic o ns to itself and do esn’t allo w fo r muc h c usto mizatio n. In this c hapter, yo u learn ho w ic o ns wo rk and ho w yo u c an extrac t ic o ns fro m any ic o n reso urc e. Yo u disc o ver ho w to save extrac ted ic o ns as new ic o n files and c hange them any way yo u want. Yo u also get numero us new metho ds to assign yo ur new ic o ns to any system ic o n yo u like.
608
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Here’s o ur task list:
1. Create a list o f all the hidden ic o ns available o n yo ur system. 2. Create a dialo g bo x that allo ws yo u to selec t ic o n files fro m the list. 3. Create a dialo g bo x that allo ws yo u to selec t ic o ns fro m an ic o n file. 4. Create vario us sc ripts that assign the selec ted ic o n to fo lders, system ic o ns, and links. To get ac c ess to ic o n files, make sure yo u have installed the iconhandler COM o bjec t \install\iconhandler\setup.exe. Full so urc e c o de c an be fo und at \components\iconhandler\iconhandler.vbp.
Creating a list of available icons In Chapter 9, yo u learned ho w to assign new ic o ns to sho rtc uts, but it to o k a lo ng time to sc an the system fo lder fo r available ic o ns. Bec ause yo u are go ing to deal with ic o ns a lo t in this c hapter, there’s a better appro ac h. Yo u sho uld c reate a list o f available ic o ns o nc e — and then reuse it as o ften as yo u like. Yo u c an always update this list manually o r by relaunc hing the fo llo wing sc ript. This sc ript may take a lo ng time to searc h fo r the ic o ns. Grab a c up o f c o ffee. While yo u relax , think abo ut the time yo u’re saving. Bec ause the sc ript c reates a reusable list o f available ic o n reso urc es, yo u’ll never wait this lo ng again. Instead, o nc e the list is generated, yo u c an lo ad it into a dialo g bo x and pic k yo ur ic o n immediately. The sc ript searc hes all lo c al hard drives and c reates a list o f files that c o ntain mo re than two ic o ns: ‘ 22-1.VBS set tool = CreateObject(“icon.handler”) set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) iconlist = “C:\iconlist.txt” ‘ open icon list file set list = fs.CreateTextFile(iconlist, true) ‘ search all local hard drives for each drive in fs.Drives if drive.isReady and drive.DriveType=2 then SearchFolder drive.RootFolder end if next ‘ close file
Chapte r 2 2 : Fun, Tric ks , and Multime dia
609
■
■
list.close wshshell.run “””” & iconlist & “”””
sub SearchFolder(folderobj) ‘ don’t search recycle bin if lcase(folderobj.name) = “recycled” then exit sub if lcase(folderobj.name) = “dllcache” then exit sub ‘ search for icons and create list for each file in folderobj.files ‘ number of icons stored in file: iconcount = tool.GetIconNumber(file.path) if iconcount>2 then list.WriteLine iconcount & vbTab & file.path end if next for each subfolder in folderobj.subfolders SearchFolder subfolder next end sub
Yo u c an interrupt the invisible sc ript at any time. On Windo ws 9.x, press [Ctrl]+[Alt]+[Del], selec t WSCRIPT.EXE in the task list, and c lic k End Task. On Windo ws NT/ 2000, selec t the Task Manager, selec t the Pro c esses tab, and selec t WSCRIPT.EXE. Then, c lic k End Pro c ess. Yo u do n’t want the sc ript to wo rk invisibly fo r to o lo ng? Perhaps yo u’d rather see what it do es and have a way to interrupt the searc h (see Figure 22-1). In Chapter 8, I pro vided a metho d to c reate a mo deless dialo g bo x.
Figure 22-1: Watch w hile your s cript s earches for icons on all hard drives . The next sc ript searc hes fo r system ic o ns and displays its pro gress. It also o ffers a Canc el butto n to interrupt the searc h at any time. Just make sure yo u have installed the mo deless dialo g COM o bjec t \install\modeless\ setup.exe. ‘ 22-2.VBS set tool = CreateObject(“icon.handler”)
610
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) set dlg = WScript.CreateObject(“modeless.dialog”, “event_”) ‘ define variables: iconlist = “C:\iconlist.txt” list = “” quit = false iconfilecount = 0 icons = 0 ‘ open icon list file set list = fs.CreateTextFile(iconlist, true) ‘ show modal window ‘ everything else is handled by event_WakeUp dlg.ShowProgressDialog ‘ close file list.close wshshell.run “””” & iconlist & “””” sub event_WakeUp ‘ will be executed the moment your modal dialog becomes visible ‘ search all local hard drives for each drive in fs.Drives if quit then ‘ make sure to display this message! ‘ otherwise your script won’t find back to the ‘ starting process! wshshell.Popup “Interrupted search...”, 1 dlg.CloseDialog exit sub end if if drive.isReady and drive.DriveType=2 then SearchFolder drive.RootFolder end if next ‘ make sure to display this message! ‘ otherwise your script won’t find back to the ‘ starting process! wshshell.Popup “Done!”, 1 dlg.CloseDialog end sub sub event_QuitNow quit = true end sub
Chapte r 2 2 : Fun, Tric ks , and Multime dia
611
■
■
sub SearchFolder(folderobj) ‘ don’t search recycle bin if lcase(folderobj.name) = “recycled” then exit sub if lcase(folderobj.name) = “dllcache” then exit sub ‘ search for icons and create list counter = 0 filecount = folderobj.files.count drv = folderobj.Drive.Driveletter for each file in folderobj.files if quit then exit sub counter = counter +1 percent = Fix(counter * 100/filecount) dlg.WriteDialog “Scanning Drive “ & drv & vbCr _ & vbCr & folderobj.path & vbCr & file.name _ & vbCr & “found “ & iconfilecount _ & “ icon files and “ & icons & “ icons.” dlg.SetProgress percent dlg.HandleEvent ‘ number of icons stored in file: iconcount = tool.GetIconNumber(file.path) if iconcount>2 then iconfilecount = iconfilecount + 1 icons = icons + iconcount list.WriteLine iconcount & vbTab & file.path end if next for each subfolder in folderobj.subfolders if quit then exit sub SearchFolder subfolder next end sub
Review Chapter 8 to understand ho w mo deless dialo g bo xes wo rk. It’s c ruc ial to fo llo w the design rules o utlined in this c hapter.
Selecting a file from your icon list Yo u no w have a c o mplete list o f all ic o ns available o n yo ur system. What c an yo u do with it? Display it as a ListView dialo g bo x. This way, yo u c an selec t ic o n files fro m yo ur list.
612
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Make sure yo u have installed the ListView COM o bjec t \install\listview\ setup.exe. ‘ 22-3.VBS set tool = CreateObject(“listview.tool”) set icontool = CreateObject(“icon.handler”) set fs = CreateObject(“Scripting.FileSystemObject”) tool.AddHeader “File name”, 80 tool.AddHeader “Icon #”, 30 tool.AddHeader “Path name”, 60 ‘ read in results from icon list iconlist = “C:\iconlist.txt” set list = fs.OpenTextFile(iconlist) do until list.atEndOfStream line = list.ReadLine infos = Split(line, vbTab) ‘ insert spaces so numbers are sorted correctly: pos = InstrRev(infos(1), “\”) tool.AddItem mid(infos(1), pos+1) tool.AddSubItem 1, right(space(10) & infos(0), 3) tool.AddSubItem 2, left(infos(1), pos-1) loop tool.Sort 1, 1 tool.MultiEdit = true ‘ repeat until icon selected or cancel do set result = tool.Show(“Select Icon File!”) if result.Count>0 then ‘ we have an icon file! fileinfo = Split(result(1), vbCrLf) iconfile = fileinfo(2) & “/” & fileinfo(0) selectedicon = icontool.PickIcon(iconfile) if not selectedicon = “” then done = true end if else done = true end if loop until done if selectedicon = “” then MsgBox “You didn’t select an icon!” else MsgBox “You selected this icon:” & vbCr & selectedicon end if
Chapte r 2 2 : Fun, Tric ks , and Multime dia
613
■
■
This sc ript o pens yo ur ic o n list and displays the c o ntent as ListView (see Figure 22-2). It so rts the ic o n files by ic o n number, sho wing the ic o n files with the mo st ic o ns at the to p. Yo u c an so rt the ListView by c lic king the c o lumn headers.
Figure 22-2: Select from hundreds of icon files . Onc e yo u selec t an ic o n file, the sc ript o pens the o ffic ial ic o n selec tio n dialo g bo x and presents the ic o ns sto red in the file (see Figure 22-3). If yo u like an ic o n, selec t it and c lic k OK. The sc ript repo rts the name and ic o n index o f the ic o n yo u selec ted. If yo u do n’t find any ic o n appealing, c lic k Canc el. The ic o n file list reappears, and yo u c an selec t ano ther file.
Figure 22-3: Us e the undocumented Change Icon dialog box to look into the icon files . Yo u no w have yo ur basic to o ls ready fo r ac tio n — yo u c an quic kly display a list o f all ic o ns available, and yo u c an also pro vide a way to pic k an ic o n. But what c an yo u do with the ic o n info rmatio n the sc ript delivers?
614
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Changing Folder Icons Windo ws 98 has silently intro duc ed a c o mpletely new feature — regular fo lders c an c hange their ic o ns o n an individual basis. Yo u c an assign new ic o ns to any o ne fo lder (see Figure 22-4). Ac tually, this new feature is part o f the Internet Explo rer 4 Deskto p Update. It’s available fo r free o n Windo ws 95 and NT — just install the update. On Windo ws 98 and 2000, the features are part o f the o perating system. All the new and fanc y fo lder enhanc ements, inc luding individual ic o ns, Web view, and fo lder sho rtc uts, rely o n two simple fac ts: ■ There must be a hidden DESKTOP.INI file inside the fo lder, whic h
spec ifies the Class IDs o f the COM c o mpo nents pro viding the new features. ■ The fo lder must have a system attribute. In additio n, so me o ther features
require it to have a read-o nly flag, to o . In essenc e, Mic ro so ft rec yc led the fo lder attributes to serve a c o mpletely new purpo se. Fiddling aro und with fo lder DESKTOP.INI files is no t the fo c us o f this bo o k, altho ugh it’s very interesting. Instead, the next sc ript fully auto mates the pro c ess o f assigning individual ic o ns to individual fo lders. It first lets yo u selec t a new ic o n and then inc o rpo rates it into the DESKTP.INI. It also manages the fo lder attributes and c an even refresh the deskto p auto matic ally, so the c hanges bec o me visible. Just drag a fo lder o nto yo ur new sc ript ic o n and see what happens. ‘ 22-4.VBS set tool = CreateObject(“listview.tool”) set icontool = CreateObject(“icon.handler”) set fs = CreateObject(“Scripting.FileSystemObject”)
‘ was a folder dragged on the script icon? set args = WScript.Arguments if args.Count=0 then ‘ no, ask for it folder = InputBox(“Please enter path of folder!”) else ‘ yes, use argument folder = args(0) end if ‘ valid folder? if not fs.FolderExists(folder) then MsgBox “Folder “”” & folder & “”” not found!” WScript.Quit end if
Chapte r 2 2 : Fun, Tric ks , and Multime dia ■
615 ■
‘ prepare ListView tool.AddHeader “File name”, 80 tool.AddHeader “Icon #”, 30 tool.AddHeader “Path name”, 60 ‘ read in results from icon list iconlist = “C:\iconlist.txt” set list = fs.OpenTextFile(iconlist) do until list.atEndOfStream line = list.ReadLine infos = Split(line, vbTab) ‘ insert spaces so numbers are sorted correctly: pos = InstrRev(infos(1), “\”) tool.AddItem mid(infos(1), pos+1) tool.AddSubItem 1, right(space(10) & infos(0), 3) tool.AddSubItem 2, left(infos(1), pos-1) loop ‘ sort by number of icons, descending order tool.Sort 1, 1 ‘ listview can be opened repeatedly tool.MultiEdit = true ‘ repeat until icon selected or cancel do set result = tool.Show(“Select Icon File!”) if result.Count>0 then ‘ we have an icon file! fileinfo = Split(result(1), vbCrLf) iconfile = fileinfo(2) & “/” & fileinfo(0) selectedicon = icontool.PickIcon(iconfile) if not selectedicon = “” then done = true end if else done = true end if loop until done if selectedicon = “” then ‘ check whether folder is already customized set tempfldr = fs.GetFolder(folder) ‘ is system attribut set? if (tempfldr.Attributes and 4)>0 then msg = “Do you want to get back default icon?” answer = MsgBox(msg, vbYesNo) if answer=vbYes then CleanUp tempfldr end if end if else
616
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
‘ set new folder icon NewFolderIcon folder, selectedicon end if
sub NewFolderIcon(pfad, icon) ‘ parts(0) stores existing desktop.ini content ‘ before icon definition, part(1) after icon ‘ definition dim parts(1) startpart = 0 desktopini = pfad & “\desktop.ini” ‘ is there a desktop.ini already? if fs.FileExists(desktopini) then ‘ read file set tempfile = fs.OpenTextFile(desktopini) do until tempfile.atEndOfStream line = tempfile.ReadLine if lcase(left(line, 8)) = _ “iconfile” then skip = true elseif lcase(left(line, 9)) = _ “iconindex” then skip=true elseif lcase(left(line, 17)) = _ “[.shellclassinfo]” then skip = true else skip = false end if if not skip then parts(startpart) = _ parts(startpart)+line & vbCrLf if lcase(left(line, _ 17))=”[.shellclassinfo]” then startpart=1 end if loop tempfile.close ‘ remove desktop.ini protection attributes set tempfile = fs.GetFile(desktopini) tempfile.Attributes = tempfile.Attributes and _ not 216 and not 7 end if ‘ create new desktop.ini set tempdat = fs.CreateTextFile(desktopini, true) iconinfo = Split(icon, “,”) icon1 = Trim(iconinfo(0)) icon2 = Fix(iconinfo(1)) ‘ write old desktop.ini part 1 tempdat.WriteLine parts(0)
Chapte r 2 2 : Fun, Tric ks , and Multime dia ■
617 ■
‘ write new icon info tempdat.WriteLine “[.ShellClassInfo]” tempdat.WriteLine “IconFile=” & icon1 tempdat.WriteLine “IconIndex=” & icon2 ‘ write old desktop.ini part 2 tempdat.WriteLine parts(1) tempdat.Close ‘ set system attribute set folderobj = fs.GetFolder(pfad) folderobj.Attributes = _ folderobj.Attributes and not 216 or 4 ‘ hide desktop.ini set tempdatei = fs.GetFile(desktopini) tempdatei.Attributes = _ tempdatei.Attributes and not 216 or 2 ‘ refresh desktop to show changes Refresh folderobj end sub sub CleanUp(obj) desktopini = obj.path & “\desktop.ini” if fs.FileExists(desktopini) then ‘ read in old desktop.ini and ‘ remove icon information set tempfile = fs.OpenTextFile(desktopini) do until tempfile.atEndOfStream line = tempfile.ReadLine & space(20) if lcase(left(line, 8)) = _ “iconfile” then skip = true elseif lcase(left(line, 9)) = _ “iconindex” then skip = true elseif trim(line)=”” then skip = true elseif lcase(left(line, 17)) = _ “[.shellclassinfo]” then flag = true else if flag=true and left(line, _ 1)=”[“ then gesamt = Replace(gesamt, _ “[.shellclassinfo]”, “”,,,1) end if flag = false gesamt = gesamt & trim(line) & vbCrLf content = true
618
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
end if loop tempfile.close set tempfile = fs.GetFile(desktopini) tempfile.Attributes = tempfile.Attributes and _ not 216 and not 7 if content then set tempfile = fs.CreateTextFile _ (desktopini, true) tempfile.Write gesamt tempfile.close set tempfile = fs.GetFile(desktopini) tempfile.Attributes = _ tempfile.Attributes and not 216 or 2 else fs.Deletefile desktopini, true tempfldr.Attributes = _ tempfldr.Attributes and not 4and _ not 216 end if end if Refresh tempfldr end sub sub Refresh(obj) ‘ delete system attribute atts = obj.Attributes and not 216 obj.Attributes = atts and not 4 ‘ refresh desktop icontool.RefreshDesktop ‘ set system attribut obj.Attributes = atts ‘ refresh again icontool.RefreshDesktop end sub
If yo u want to get rid o f c usto mized fo lder ic o ns, drag the fo lder o nto yo ur sc ript ic o n and c lic k Canc el. The sc ript asks whether yo u want to exc lude the ic o n info rmatio n fro m yo ur c urrent DESKTOP.INI. If yo u agree, the ic o n returns bac k to the default. This sc ript c an o nly c hange true fo lders. On yo ur deskto p, there may be additio nal ic o ns that lo o k like fo lders but are so mething different. My Do c uments, fo r example, is just a COM o bjec t defined in the Desktop NameSpace Registry key. Windo ws 2000 intro duc es fo lder sho rtc uts, to o . They lo o k exac tly like fo lders but are sho rtc uts. Right-c lic k a fo lder and c ho o se Pro perties to make sure it really is a fo lder.
Chapte r 2 2 : Fun, Tric ks , and Multime dia ■
619 ■
Figure 22-4: Change boring folder icons and replace them w ith icons you like.
Hiding folders Changing individual fo lder ic o ns no t o nly helps to o rganize yo ur data better. Yo u c an also use this tec hnique to hide fo lders with sensitive data. Just assign a misleading ic o n to the fo lder. Fo r example, c ho o se shell32.dll as ic o n file and selec t the generic DOS pro gram ic o n to yo ur fo lder. Then, rename yo ur fo lder to so mething like DOSCNFG.EXE. No w, yo ur fo lder lo o ks like so me tec hbit DOS exec utable. But yo u c an o pen the fo lder as usual.
Changing system icons Windo ws uses private ic o ns, to o . All the system ic o ns yo u see o n yo ur deskto p — Netwo rk Neighbo rho o d, My Co mputer, My Do c uments — and all the ic o ns in yo ur Start menu are ac tually private Windo w ic o ns. Yo u c an c hange them, to o . All Windo ws ic o ns are sto red inside shell32.dll. Yo u c an use this ic o n file to selec t the system ic o n yo u want to c hange. The next sc ript o pens shell32.dll and displays the ic o ns inside it. Selec t the system ic o n yo u want to c hange, then selec t a replac ement ic o n. The sc ript auto matic ally updates the system ic o n in the Registry and updates the ic o n c ac he. The new ic o n appears instantaneo usly. ‘ 22-5.VBS set set set set
‘ ask for system icon to change msg = “Please select the system icon you want to change!” MsgBox msg, vbInformation + vbSystemModal ‘ registry key for custom icons key = “HKLM\Software\Microsoft\Windows\CurrentVersion\explorer\Shell Icons\” iconfile = icontool.PickIcon(“shell32.dll”) if iconfile = “” then answer = MsgBox(“You did not select an icon! Do you “ _ & “want to restore ALL default icons?”, _ vbYesNo + vbQuestion) if answer = vbYes then on error resume next wshshell.RegDelete key icontool.FlushIconCache end if WScript.Quit else index = mid(iconfile, Instr(iconfile, “,”)+1) end if ‘ prepare ListView tool.AddHeader “File name”, 80 tool.AddHeader “Icon #”, 30 tool.AddHeader “Path name”, 60 ‘ read in results from icon list iconlist = “C:\iconlist.txt” set list = fs.OpenTextFile(iconlist) do until list.atEndOfStream line = list.ReadLine infos = Split(line, vbTab) ‘ insert spaces so numbers are sorted correctly: pos = InstrRev(infos(1), “\”) tool.AddItem mid(infos(1), pos+1) tool.AddSubItem 1, right(space(10) & infos(0), 3) tool.AddSubItem 2, left(infos(1), pos-1) loop ‘ sort by number of icons, descending order tool.Sort 1, 1 ‘ listview can be opened repeatedly tool.MultiEdit = true ‘ repeat until icon selected or cancel do set result = tool.Show(“Select Icon File!”) if result.Count>0 then ‘ we have an icon file!
Chapte r 2 2 : Fun, Tric ks , and Multime dia
621
■
■
fileinfo = Split(result(1), vbCrLf) iconfile = fileinfo(2) & “/” & fileinfo(0) selectedicon = icontool.PickIcon(iconfile) if not selectedicon = “” then done = true end if else done = true end if loop until done if selectedicon = “” then msg = “Do you want to restore the system icon you selected?” answer = MsgBox(msg, vbQuestion + vbYesNo + vbSystemModal) if answer = vbYes then wshshell.RegDelete key & index icontool.FlushIconCache end if else ‘ set new system icon wshshell.RegWrite key & index, selectedicon icontool.FlushIconCache end if
System ic o n c hanges no rmally require Windo ws to restart fo r them to bec o me visible. No t so with this sc ript. It makes c hanges visible immediately. FlushIconCache fo rc es Windo ws to re-c reate its internal ic o n c ac he.
Changing a system icon To c hange, fo r example, all fo lder ic o ns, launc h yo ur sc ript and then selec t the o ffic ial fo lder ic o n in shell32.dll. Next, c ho o se the ic o n file yo u want to use as a replac ement. Selec t an ic o n and c lic k OK. All the fo lder ic o ns will c hange.
Restoring a system icon To resto re a system ic o n, launc h yo ur sc ript and selec t the ic o n. To get bac k no rmal fo lder ic o ns, selec t the o ffic ial fo lder ic o n in shell32.dll. Then, do n’t selec t an ic o n file — c lic k Canc el. The sc ript asks if yo u want to revert to no rmal. Clic k Yes. The o riginal ic o n will be resto red.
Restoring all system icons If yo u want to get rid o f all c usto m ic o ns, launc h yo ur sc ript and c lic k Canc el. The sc ript asks whether yo u want to revert to no rmal. Clic k Yes. All system ic o ns will be resto red. Almo st all the ic o ns in shell32.dll serve a spec ial purpo se. Fo r example, many o f the ic o ns are used inside yo ur Start menu. Yo u c an c hange tho se ic o ns, to o .
622
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Extracting icons to files So far, yo u have taken advantage o f all the ic o ns available o n yo ur system. Yo u do n’t o wn these ic o ns, tho ugh. This means that yo u c an’t c hange ic o ns manually, o r even be sure that the ic o ns will be there fo rever. If yo ur favo rite ic o n is part o f so ftware that yo u dec ide to uninstall, yo ur ic o n referenc e will get lo st. This is why it makes sense to extrac t ic o ns to individual ic o n files. Yo ur ic o n to o lkit c an do this. Ho wever, it c an o nly extrac t ic o ns as .bmp pic tures. This is OK — o n Windo ws 9.x, yo u just need to rename the .bmp file and assign .ico as file type. No w yo u c an use the bitmap pic ture as an ic o n. Ho wever, o n Windo ws 2000, this do esn’t wo rk as well anymo re. Transparenc y info rmatio n gets lo st, and yo ur ic o ns always display a blac k bac kgro und. The pro fessio nal alternative is yo ur Ic o n edito rs. Yo u c an get them free o r as shareware fro m a number o f plac es. Yo u c an insert yo ur o wn ic o ns into yo ur ic o n list. Just o pen the text file and add yo ur ic o n info rmatio n. This way, yo u c an selec t yo ur ic o ns with all o f the prec eding sc ripts. The next sc ript sho ws the simple so lutio n. It allo ws yo u to selec t an ic o n file and pic k an ic o n. Then, the ic o n is extrac ted and saved as an .ico file. The sc ript tries to launc h the ic o n so yo u c an make c hanges to it. If no pro gram is asso c iated with .ico files, yo u get an erro r. In this c ase, o pen the new .ico file manually. The Open As dialo g bo x appears. Just c ho o se MS Paint as the new default pro gram. It c an display and edit yo ur extrac ted ic o ns. Make sure to save yo ur images with the .ico file extensio n. ‘ 22-6.VBS set set set set
filename = “c:\testicon.ico” ‘ prepare ListView tool.AddHeader “File name”, 80 tool.AddHeader “Icon #”, 30 tool.AddHeader “Path name”, 60 ‘ read in results from icon list iconlist = “C:\iconlist.txt” set list = fs.OpenTextFile(iconlist) do until list.atEndOfStream line = list.ReadLine infos = Split(line, vbTab) ‘ insert spaces so numbers are sorted correctly:
Chapte r 2 2 : Fun, Tric ks , and Multime dia ■
623 ■
pos = InstrRev(infos(1), “\”) tool.AddItem mid(infos(1), pos+1) tool.AddSubItem 1, right(space(10) & infos(0), 3) tool.AddSubItem 2, left(infos(1), pos-1) loop ‘ sort by number of icons, descending order tool.Sort 1, 1 ‘ listview can be opened repeatedly tool.MultiEdit = true ‘ repeat until icon selected or cancel do set result = tool.Show(“Select Icon File!”) if result.Count>0 then ‘ we have an icon file! fileinfo = Split(result(1), vbCrLf) iconfile = fileinfo(2) & “/” & fileinfo(0) selectedicon = icontool.PickIcon(iconfile) if not selectedicon = “” then done = true end if else done = true end if loop until done if selectedicon = “” then MsgBox “You did not select an icon!” else ‘ extract icon iconinfo = Split(selectedicon, “,”) icontool.LoadIcon iconinfo(0), iconinfo(1) icontool.IconToFile filename wshshell.Run “””” & filename & “””” end if
Searching for customized DESKTOP.INI folders No w that yo u c an extrac t ic o ns to files, it’s easy to write sc ripts to searc h fo r c usto mized DESKTOP.INI fo lders. The next sc ript searc hes yo ur hard drive fo r any fo lder that has a system attribute and a DESKTOP.INI file (see Figure 22-5).
624
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Figure 22-5: Find all cus tomized folders and peek into DESKTOP.INI. The sc ript retrieves the ic o n, whic h c an be spec ified either in the DESKTOP.INI file o r inside the Windo ws Registry. It c reates a list and displays ic o n and DESKTOP.INI c o ntent info rmatio n. ‘ 22-7.VBS set set set set
mydir = “C:\desktopini\” logbook = mydir & “desktopini.htm” counter = 0 on error resume next fs.CreateFolder mydir on error goto 0 set list = fs.CreateTextFile(logbook, true) list.WriteLine “
” set windir = fs.GetSpecialFolder(0) SearchFolder fs.GetFolder(“C:\”) list.WriteLine “
” wshshell.run “iexplore.exe “”” & logbook & “”””
sub SearchFolder(folderobj)
Chapte r 2 2 : Fun, Tric ks , and Multime dia ■
625 ■
for each subfolder in folderobj.subfolders CheckFolder subfolder next for each subfolder in folderobj.subfolders SearchFolder subfolder next end sub
sub CheckFolder(subfolder) if fs.FileExists(subfolder.path & “\desktop.ini”) _ and (subfolder.Attributes and 4)>0 then set tempfile = fs.OpenTextFile(subfolder.path _ & “\desktop.ini”) iconfile=”” iconindex=0 deskini=”” source=”” do until tempfile.atEndOfStream line = tempfile.ReadLine testline = lcase(Replace(line, “ “, “”)) if watchout then if left(testline, 9)=”iconfile=” then iconfile = mid(line, Instr(line, “=”)+1) source = “desktop.ini” elseif left(testline, 10)=”iconindex=” then iconindex = mid(line, Instr(line, “=”)+1) end if pos = instr(testline, “clsid=”) if pos>0 then pos = instr(testline, “{“) classid = mid(testline, pos) if iconfile = “” then on error resume next key = “HKCR\CLSID\” & classid _ & “\DefaultIcon\” iconfile=”” iconfile = wshshell.RegRead(key) on error goto 0 if not err.number=0 then err.clear else iconfile = _ wshshell.ExpandEnvironmentStrings(iconfile) pos = Instr(iconfile, “,”) if pos=0 then iconindex = 0 else iconindex = mid(iconfile, _ pos+1) iconfile = left(iconfile, _ pos-1)
626
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
end if source = key end if end if end if end if if testline = “[.shellclassinfo]” then watchout=true elseif left(testline, 1)=”[“ then watchout = false end if deskini = deskini & line & “ ” loop tempfile.close if not iconfile=”” then counter = counter + 1 icontool.LoadIcon iconfile, iconindex picname = mydir & “pic” & counter & “.jpg” icontool.IconToFile picname list.WriteLine “
10 then MsgBox “Can’t delete “ & name WScript.quit end if WScript.Sleep 1000 loop else
end MCI MCI MCI MCI
MsgBox “Can’t save.” WScript.Quit end if if “open cdaudio” “set cdaudio time format tmsf” “status cdaudio position track “ & track “set cdaudio time format milliseconds”
call tool.QueryMCIString(“status cdaudio length track “ _ & track & “ wait”, result) song = CLng(result) msg = “Selected track is “ & FormatNumber(song/1000,1) _ & “ sec.” & vbCr msg = msg & “Specify length of recording in milliseconds!” limit = Ask(msg,song) MCI “open new type waveaudio alias capture” MCI “set cdaudio time format tmsf” MCI “play cdaudio from “ & track & “ to “ & track+1 MCI “record capture” WScript.Sleep limit MCI “save capture “ & name MCI “stop cdaudio” MCI “close cdaudio” end sub sub MCI(command) if not tool.SendMCIString(command, errormsg) then msg = command & vbCr & errormsg & vbCr & “Continue?” response = MsgBox(msg, vbYesNo + vbCritical) if response = vbNo then WScript.Quit end if end sub function Ask(question, default) Ask = InputBox(question,,default) if Ask=vbEmpty or not isNumeric(Ask) then MsgBox “Invalid entry.” WScript.Quit end if Ask = Fix(Ask) end function
644
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
RecordToWave rec o rds a trac k o f yo ur audio CD and sto res it as a WAV file. Yo u c an even spec ify if it sho uld rec o rd the entire trac k o r just part o f it — up to the millisec o nd (see Figure 22-13). WAV audio pro duc es very large files in a very sho rt perio d o f time. Rec o rd o nly a c o uple o f sec o nds at first and c hec k the resulting file sizes to get ac c usto med to the demands. No te that the Save c o mmand c an o nly wo rk if the file spec ified do esn’t already exist. Save c anno t replac e files. Yo ur sc ript must therefo re delete the file if it exists befo re a new rec o rding c an take plac e. If in do ubt, delete the file manually befo re yo u launc h the sc ript. MCI uses yo ur system default values when sto ring WAV audio data. It also uses yo ur system default so und input levels. Do uble-c lic k the speaker symbo l in yo ur taskbar’s tray area and selec t the rec o rding panel to adjust the input levels and input so urc es.
Figure 22-13: The res ulting WAV file is exactly the length you s pecified.
Summary In the first part o f this c hapter, yo u learned ho w Windo ws o rganizes its ic o ns. Yo ur sc ripts are no w able to enumerate ic o n files, extrac t ic o ns, and assign ic o ns to system o bjec ts. In the sec o nd part, yo u learned abo ut the unifo rm multimedia interfac e MCI. Yo u have seen ho w easy it is to c o ntro l the mo st different multimedia devic es with the exac t same set o f c o mmands. Yo ur sc ripts c an no w play audio and video files and even rec o rd CD-ROM audio trac ks to yo ur hard drive.
Chapte r 2 3
Using Databases In This Chapter 䊳 Learn abo ut ADO and MDAC, the standard interfac es to any database 䊳 Chec k yo ur ADO and MDAC versio ns, and update yo ur system with the help
o f free do wnlo ads 䊳 Ac c ess the sample database using a DSN-free c o nnec tio n 䊳 Read and write to any database using sc ripts and SQL 䊳 Deal with rec o rdsets, c o unt rec o rds, delete rec o rds, and retrieve info rmatio n
abo ut table fields and variable types 䊳 Eliminate the “single quo te” pro blem and wo rk aro und reserved SQL
c harac ters 䊳 Create c o mpletely new database tables and delete o ld o nes 䊳 Learn all abo ut the Index Server, and use Bo o lean o perato rs to quic kly find
the do c uments yo u are lo o king fo r 䊳 Do full text searc hes and queries in natural language 䊳 Limit searc h sc o pe to spec ific fo lders using the hidden ixsso.Util o bjec t
M
ic ro so ft has made database ac c ess easy. By using MDAC (Mic ro so ft Database Ac c ess Co mpo nents), yo ur sc ripts c an c o nnec t themselves to any kind o f database and read info rmatio n using SQL statements. Yo ur sc ripts c an even sto re info rmatio n and c hange database struc tures. In this c hapter, yo u learn ho w to add po werful database c apabilities to yo ur sc ripts.
Accessing Databases Imagine what yo u c o uld do if yo ur sc ripts were able to “talk” to databases. Yo u c o uld c reate yo ur o wn little address bo o k, retrieve invo ic e info rmatio n, o r sto re user names. Fo rtunately, Mic ro so ft has c reated a standard interfac e to ac c ess any kind o f database, inc luding simple text databases as well as full-sc ale SQL servers o r Orac le database servers.
646
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Checking ADO version This interfac e is c alled Ac tiveX Data Objec ts (ADO). Many pro duc ts silently install ADO o n yo ur system, so let’s c hec k whether ADO is wo rking o n yo ur system and whether it’s up-to -date (see Figure 23-1). ‘ 23-1.VBS set fs = CreateObject(“Scripting.FileSystemObject”) set wshshell = CreateObject(“WScript.Shell”) msg = “ADO status:” & vbCr & vbCr ‘ check whether Connection is accessible on error resume next set dummy = CreateObject(“ADODB.Connection”) if not err.number = 0 then MsgBox msg & “ADODB.Connection isn’t working!” WScript.Quit else msg = msg & “ADODB.Connection is operational.” & vbCr end if on error goto 0 ‘ retrieve files on error resume next clsid = wshshell.RegRead(“HKCR\ADODB.Connection\CLSID\”) exec = wshshell.RegRead(“HKCR\CLSID\” & clsid & “\InProcServer32\”) path = Left(exec, InstrRev(exec, “\”)-1) path = Left(path, InstrRev(path, “\”)-1) & “\Ole DB\” if not err.number=0 then MsgBox msg & “Error retrieving file version information!” WScript.Quit end if on error goto 0 ‘ check for ADO components filename = “msdadc.dll” if fs.FileExists(path & filename) then filever = fs.GetFileVersion(path &filename) msg = msg & filename & “ exists: Version “ & filever & vbCr else msg = msg & filename & “ is missing.” & vbCr end if filename = “oledb32.dll” if fs.FileExists(path & filename) then filever = fs.GetFileVersion(path &filename) msg = msg & filename & “ exists: Version “ & filever & vbCr else msg = msg & filename & “ is missing.” & vbCr
Chapte r 2 3 : Us ing Databas e s
647
■
■
end if
MsgBox msg, vbInformation
This sc ript makes so me assumptio ns. If yo ur ADODB.Co nnec tio n is o peratio nal, but neither file is fo und, yo u sho uld searc h fo r the files manually.
Figure 23-1: Check w hether ADO is operational and w hich MDAC vers ion you have. Use Table 23-1 to c alc ulate the interfac e versio n yo ur system c urrently uses.
Table 23-1
Information to Determine ADO Version Installed
ADODB.Connection
M SDADC.DLL
OLEDB32.DLL
Version
not operational
mis s ing
mis s ing
no MDAC (Micros oft Data Acces s Components ) ins talled
operational
1.50.3506.0
mis s ing
MDAC 1.5c
operational
2.0.3002.4
2.0.1706.0
MDAC 2.0
operational
2.0.3002.23
2.0.1706.0
MDAC 2.0 SP1/SP2
operational
2.10.3513.0
2.10.3513.0
MDAC 2.1.0.3513.2 (SQL)
operational
2.10.3711.2
2.10.3711.2
MDAC 2.1.1.3711.6 (Internet Explorer 5)
operational
2.10.3711.2
2.10.3711.9
MDAC 2.1.1.3711.11
operational
2.50.4403.0
2.50.4403.3
MDAC 2.5 (Window s 2000)
Do I need to upgrade or install anything? Here’s the go o d news. If yo ur sc ript repo rts ADODB.Connection o peratio nal, yo u are ready fo r ac tio n. Out o f c urio sity, yo u c o uld c hec k yo ur MDAC versio n, but even if it’s MDAC 1.5, yo u are fine.
648
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
And here’s mo re go o d news. If MDAC is missing o n yo ur system, yo u c an install it fo r free. Mic ro so ft o ffers the c o mplete so ftware kit fo r do wnlo ading. But, yo u guessed it, there’s so me no t-so -go o d news, to o . Do wnlo ad addresses c hange frequently, and Mic ro so ft do wnlo ad addresses c hange even mo re frequently. Start yo ur searc h here: www.microsoft.com/data/ado/ default.htm. Do wnlo ads are also available at www.microsoft.com/data/ download.htm. Lo o k fo r MDAC versio n 2.1 o r later. The do wnlo ad is huge, tho ugh; mo re than 6MB are waiting fo r yo u. Never to uc h a running system. If yo ur system suppo rts ADODB.Connection, then think twic e befo re dec iding to upgrade. There are mino r inc o nsistenc ies between the MDAC versio ns, and installing a higher versio n o n a system with applic atio ns that use a lo wer versio n might very well c rash tho se applic atio ns. So , here’s an easy rule — install MDAC o nly if it’s no t yet installed o r if yo u spec ific ally need a new feature o nly available in the update. Remember: Onc e yo u have upgraded to a higher MDAC versio n, yo u c an’t go bac k. Yo u c an’t even uninstall MDAC. It’s a o ne-way street. Do install the MDAC update if any o f the fo llo wing example sc ripts raise a “Can’t c reate Objec t” erro r. It’s a rather c o mmo n pro blem: On so me systems, MDAC was installed at so me time but parts o f it bec ame damaged o r were uninstalled. Tho se systems c an ac c ess ADODB.Connection, but they fail the mo ment yo u try to o pen a database.
Getting Access to a Database First o f all, yo u need a database to ac c ess. ADO is able to sto re data as plain text files in c ase yo u have no database at hand. On the c o mpanio n CD, yo u find a sample MS Ac c ess database. Yo u sho uld use this database fo r all o f yo ur experiments if yo u do n’t have a database o f yo ur o wn. As it turns o ut, yo ur sc ripts c an c hange and even add tables to the sample database.
Opening and querying a database To use a database, yo ur sc ript needs to o pen it first. There are many ways to o pen a database. Mo st o ften yo u will see the DSN appro ac h: Using the Co ntro l Panel and its 32-bit ODBC Data So urc e mo dule, yo u define a System DSN and sto re all the details abo ut yo ur database in the DSN. Then, yo ur sc ripts just refer to the DSN name tag, and ADO reads the c o nnec tio n details fro m yo ur DSN definitio n (see Figure 23-2). Ho wever, the DSN appro ac h has so me majo r drawbac ks. It requires yo u to set up the DSN first. Yo u need to go thro ugh many dialo g bo xes. No t so go o d. A muc h easier way bypasses the DSN. Here, the sc ript pro vides the c o nnec tio n details manually. Using this appro ac h, yo u c an distribute yo ur database file and yo ur sc ripts, and yo ur users c an ac c ess the data base info rmatio n right away. No further setup is required.
Chapte r 2 3 : Us ing Databas e s
649
■
■
Figure 23-2: Don’t us e fixed DSNs , or you w ill los e a lot of flexibility. Try it o ut. Alo ng with the sc ripts o f this c hapter, yo u will find a sample database ( sample.mdb). Co py the entire fo lder o nto yo ur hard drive and get rid o f the write-pro tec tio n attributes. Yo u c an then immediately start wo rking with this database and even c reate yo ur very o wn table design. All files o n a CD have a write-pro tec tio n attribute. If yo u c o py CD-ROM files to yo ur lo c al hard drive, they keep this attribute, and yo u c an’t c hange the files. Therefo re, whenever yo u c o py data fro m a CD ROM, yo u must remo ve the attribute: Right-c lic k the files and c ho o se Pro perties. Then, c lear the writepro tec tio n attribute and c lic k OK. No w, witho ut any further hassle, launc h the sc ript 23-2.VBS. It will ac c ess the database and retrieve the sample info rmatio n: my name and my e-mail address (see Figure 23-3).
Figure 23-3: Retrieve databas e information w ithout even ow ning a databas e. Next, launc h the sc ript 23-5.VBS. No w yo u c an enter a name and an e-mail address and add them to the sample database. To do uble-c hec k, launc h 23-2.VBS again. It wo rked: The new entry appears (see Figure 23-4). Yo u c an’t add entries if yo u do n’t remo ve the write-pro tec tio n attribute o r if yo u launc h the sc ripts direc tly fro m the CD-ROM.
650
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Figure 23-4: Add new entries to the s ample databas e.
Reading database contents Take a lo o k at ho w 23-2.VBS retrieves the database info rmatio n: ‘ 23-2.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to select information sql = “select * from info” set rs = db.Execute(sql) ‘ read resulting record set do until rs.EOF list = list & rs(“id”) & vbTab & rs(“name”) _ & “ Email to: “ & rs(“email”) & vbCr rs.MoveNext loop ‘ output information MsgBox list
First, the sc ript determines the c urrent fo lder. Bec ause yo u are no t go ing to use a static DSN, yo ur sc ript must tell ADO the lo c atio n o f yo ur database. In this c ase, the database is sto red in the same fo lder with the sc ript. Therefo re, the sc ript needs to find o ut the fo lder name it is sto red in. Next, it o pens the database. It first gets a vanilla instanc e o f the ADODB. Connection o bjec t and c alls its o pen metho d to o pen the real database. Instead o f a DSN, it pro vides the c o nnec tio n details direc tly, and DRIVER= spec ifies the database driver. DBQ= spec ifies the lo c atio n o f the database file.
Chapte r 2 3 : Us ing Databas e s
651
■
■
Figure 23-5: Your s cripts can actually read and w rite the databas e. Ho w do yo u get info rmatio n fro m yo ur database? Yo u ask fo r it. Databases use the SQL database query language. To selec t all data in a spec ific table, use SELECT * FROM tablename. Bec ause there’s o nly o ne table sto red in the sample database and this table is named info , yo u use SELECT * FROM INFO. Execute exec utes yo ur SQL statement and returns the results as recordset. The sc ript no w lo o ps thro ugh the recordset until the end is reac hed and EOF is true. It c an read the c o ntents o f eac h recordset. RS(“name”) retrieves the info rmatio n o f the “name” field o f the c urrent rec o rd. Alternatively, yo u c an spec ify the field index. RS(1) wo uld also retrieve the name field value bec ause the name field happens to be the field number 1 (field c o unt starts at 0, and field 0 in the sample table is c alled “id”). Always make sure yo ur lo o p uses MoveNext to mo ve o n to the next table rec o rd. If yo u do n’t, yo ur lo o p will c o nstantly read the same rec o rd set, and yo u’ll never reac h the end o f the table.
Finding out design information So far, yo ur sc ript has had a great advantage in that it kno ws the names o f the table fields and c an ac c ess them direc tly. What if yo u do n’t kno w ho w many fields a table c o ntains o r what the table fields are c alled? Find o ut (see Figure 23-6). Here’s ho w: ‘ 23-3.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to select information sql = “select * from info” set rs = db.Execute(sql) ‘ find out number of fields fields = rs.fields.count
652
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
‘ find out field names redim fieldnames(fields-1) for x=0 to fields-1 fieldnames(x) = rs.fields(x).name next ‘ output information msg = “Table contains “ & fields & “ fields:” & vbCr for x = 0 to fields-1 msg = msg & fieldnames(x) & vbCr next ‘ output information MsgBox msg
Figure 23-6: Read the names of all the fields available in the s ample table. No w yo u c an c reate a sc ript that reads info rmatio n fro m any kind o f table: ‘ 23-4.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to select information sql = “select * from info” set rs = db.Execute(sql) do until rs.EOF for x = 0 to rs.fields.count-1 list = list & rs(x) & vbTab next list = list & vbCr rs.MoveNext loop ‘ output information MsgBox list
Chapte r 2 3 : Us ing Databas e s
653
■
■
Adding new data to your database table Next, let’s examine ho w write.vbs manages to insert new data sets into yo ur table: ‘ 23-5.VBS ‘ find out current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ ask for new data name = InputBox(“Enter name to add!”) email = InputBox(“Enter email address to add!”) ‘ access database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to insert new data sql = “insert into info (name, email) values (‘“ _ & name & “‘, ‘“ & email & “‘)” ‘ uncomment next line to see SQL statement! ‘ MsgBox sql ‘ execute sql statement set rs = db.Execute(sql) MsgBox “Added entry!”
It’s fairly easy: The sc ript uses the same basic arc hitec ture. Instead o f SELECT, it uses the INSERT INTO statement. SQL uses single quo tes to delimit text info rmatio n. If yo u enter single quo tes in yo ur data text, they interfere with the single quo tes the SQL statement uses. Try it o ut. Launc h write.vbs and inc lude single quo tes. Yo u’ll get an ODBC erro r.
Solving the single quote problem Obvio usly, yo u c an’t expec t yo ur users to avo id single quo tes. Yo u do n’t need to , either. Just c o nvert single quo tes to two single quo tes. Two single quo tes are rec o gnized as data single quo tes just as Visual Basic rec o gnizes two quo tes as a single quo te inside o f a text string. So , after yo u ask fo r the info rmatio n to save in yo ur database, use a c o mmand like this: datatext = Replace(datatext, “‘“, “‘’”)
To pinpo int the issue: Replac e a single quo te with two single quo tes.
654
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Autonumber fields Why didn’t the write.vbs sc ript add a number fo r the id c o lumn even tho ugh the new data set still rec eived an id number? When I designed the info table, I assigned the info field a variable type o f “Auto Number.” This value is an auto matic c o unter. It will issue a unique number to eac h new dataset. It’s a go o d idea to use AutoNumber fields bec ause they’re yo ur o nly way to uniquely identify data sets.
Retrieving variable fields Yo u c an retrieve the variable types o f yo ur table fields, to o (see Figure 23-7): ‘ 23-6.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to select information sql = “select * from info” set rs = db.Execute(sql) ‘ find out number of fields fields = rs.fields.count ‘ find out field names redim fieldnames(fields-1) for x=0 to fields-1 fieldnames(x) = rs.fields(x).name & “ Type: “ & rs.fields(x).type next ‘ output information msg = “Table contains “ & fields & “ fields:” & vbCr for x = 0 to fields-1 msg = msg & fieldnames(x) & vbCr next ‘ output information MsgBox msg
Figure 23-7: Determine the variable type of databas e fields .
Chapte r 2 3 : Us ing Databas e s
655
■
■
Table 23-2 sho ws whic h numeric values c o rrespo nd to the variable type that c an be sto red in the field.
Table 23-2
Database Variable Types
Variable Type
Description
8, 12, 129, 130, 200, 201, 202, 203
Text s trings
7, 133, 134, 135
Date
11
Boolean
9, 10, 13, 128, 132, 204, 205
Special
All els e
Numeric
Yo u need the variable type when trying to insert new data via INSERT INTO: String info rmatio n must be enc lo sed in single quo tes, date info rmatio n must be c o nverted via Cdate, and Bo o lean values must be c o nverted using CBool.
Counting the number of records SELECT no t o nly retrieves database data, it also suppo rts so me c o mmands to sum c o lumns and c o unt datasets. To c o unt all recordsets, use this appro ac h: ‘ 23-7.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to count records sql = “select count(*) as counter from info” set rs = db.Execute(sql) MsgBox “Table contains “ & rs(“counter”) & “ records.”
Deleting records SQL c an also delete rec o rds. To delete a rec o rd, yo u need a unique way o f identifying it. This is where the Auto Number ID c o lumn c o mes into play. Eac h
656
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
rec o rd gets a unique id number, and with this number yo u c an delete individual rec o rds: ‘ 23-8.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to select information sql = “select * from info” set rs = db.Execute(sql) do until rs.EOF for x = 0 to rs.fields.count-1 list = list & rs(x) & vbTab next list = list & vbCr rs.MoveNext loop ‘ output information delrec = InputBox(list & vbCr _ & “Enter ID of record you want to delete!”) if delrec = vbEmpty then WScript.Quit sql = “DELETE FROM info WHERE id = “ & delrec db.Execute sql MsgBox “Record deleted.”
The Auto Number c o unter is inc remented eac h time yo u add a new rec o rd. Deleting rec o rds wo n’t dec rement the c o unter. So , when yo u add yo ur next rec o rd, it wo n’t get the id previo usly assigned to the deleted rec o rd. It always gets a unique id number.
Creating new database tables SQL c an even add c o mpletely new tables to yo ur database. This way, yo u c an use the sample database as the fo undatio n fo r yo ur o wn pro jec ts. The next sc ript adds a table named newtable and defines the fo llo wing fields: id
Auto Number
Name
String 200
Street
String 200
City
String 200
Chapte r 2 3 : Us ing Databas e s
657
■
■
‘ 23-9.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to select information sql = “CREATE TABLE newtable (id COUNTER, Name TEXT(200), “ _ & “Street TEXT(200), City TEXT(200))” set rs = db.Execute(sql) MsgBox “Table added!”
Adjust the sample sc ripts to add data to this table as yo u like.
Deleting tables No w yo u just need a way to delete a table. The next sc ript uses the SQL DROP statement to delete the newly added table: ‘ 23-10.VBS ‘ determine current folder myname = WScript.ScriptFullName mypath = Left(myname, InstrRev(myname, “\”)) ‘ open database set db = CreateObject(“ADODB.Connection”) db.Open(“DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=” _ & mypath & “SAMPLE.MDB”) ‘ use SQL to delete table sql = “DROP TABLE newtable” set rs = db.Execute(sql) MsgBox “Table deleted!”
There’s a lo t mo re to databases than that. Yo u c an ac c ess recordsets direc tly, use different c urso r types to mo ve bac k and fo rth in yo ur rec o rd sets, and retrieve newly assigned AutoNumber values. Using SQL Server (o r any o ther database server), yo u c an c all sto red pro c edures and c reate SQL mac ro s. All o f this info rmatio n deserves its o wn bo o k, altho ugh I’ve pro vided all the sc ripting to o ls yo u need to ac c ess databases. If yo u find this interesting, I rec o mmend yo u get yo urself a SQL bo o k, suc h as Mic ro so ft SQL Server 7 Sec rets o r Mic ro so ft Ac c ess 2000 Develo per’s Guide, bo th fro m IDG Bo o ks Wo rldwide.
658
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Controlling the Index Server Info rmatio n management is a ho t to pic these days. There are millio ns o f do c uments flo ating aro und, and it’s no t easy to keep yo ur head straight in a wo rld o f info rmatio n o verkill. Fo rtunately, there are easy so lutio ns to this pro blem. Many years ago , Mic ro so ft develo ped a to o l c alled Index Server. The Index Server was targeted at the Internet, and its so le purpo se was to auto matic ally index a Web site so visito rs c o uld searc h fo r pages with partic ular c o ntent. Altho ugh the Index Server wo rked well, it was lo ng c o nsidered to be so me kind o f experimental pro duc t. Mic ro so ft wo uldn’t suppo rt it, and it was no t an o ffic ial part o f the MS Internet Info rmatio n Server. Finally, the Index Server has evo lved as a true c o mmerc ial pro duc t. Its internal design has c hanged c o nsiderably, and what’s even mo re impo rtant, the Index Server no w is a standard part o f Windo ws 2000. This has eno rmo us c o nsequenc es. The Index Server no lo nger is just ano ther Web servic e. It c an index any kind o f data sto re, and Windo ws 2000 uses the Index Server to index its entire lo c al file system. Windo ws 2000 hides the Index Server, tho ugh. Yo u c an do full text searc hes and be amazed at the speed, but there’s no o bvio us way to c o ntro l the Index Server. In fac t, the built-in searc h uses o nly a small frac tio n o f the Index Server’s c apabilities. Despite this, yo u c an ac c ess the Index Server thro ugh ADO direc tly and think o f it as a database. Muc h o f what yo u have just learned will fall right into plac e when applied to the Index Server. The fo llo wing applies to Windo ws 2000 o nly. Ho wever, if yo u use Windo ws NT 4 and the Internet Info rmatio n Server with Optio n Pac k >=4, yo u c an use all o f the fo llo wing sc ripts to index yo ur Web page. Just adjust the c atalo g names and embed the sc ripts in yo ur ASP Web pages.
Activating local file system indexing Let’s get so me termino lo gy straight first. The Index Server is a bac kgro und servic e. It c an auto matic ally and silently index entire drives (see Figure 23-8). It do esn’t have to , tho ugh. Yo u still have the o ptio n to do full text searc hes the o ld way and have Windo ws sno o p thro ugh the files as it exec utes the searc h. So , first yo u sho uld c hec k the state o f yo ur Index Server. This is easy: Just selec t Searc h fro m yo ur Start menu and searc h fo r files and fo lders. Explo rer launc hes and displays the searc h panel in the left part o f its windo w. If yo u take a c lo ser lo o k, yo u’ll find a remark abo ut the Index Server — c lic k Searc h Optio ns if the remark is missing. The remark reveals whether the Index Server is turned o n o r o ff, and whether the Index is up-to -date o r no t.
Chapte r 2 3 : Us ing Databas e s
659
■
■
Figure 23-8: Activate the Window s 2000 Index Server. Clic k Indexing Servic e to see mo re details. Yo u no w have the c ho ic e to turn indexing o n o r o ff (see Figure 23-9).
Figure 23-9: Turn on Indexing Service to index your entire local file s ys tem. Turning the Index Server o ff may be nec essary fo r spec ial full text searc hes. While the Index Server is turned o n, it o nly finds info rmatio n sto red in its index. If the index isn’t up-to -date yet, if the file type yo u want to searc h isn’t inc luded in the indexing sc heme, o r if the file isn’t sto red in a fo lder inc luded in the indexing sc heme, yo u must turn o ff the Index Server to find the searc h text. Clic k Advanc ed to gain even mo re c o ntro l. Yo u no w see the c atalo gs yo ur Index Server is wo rking with. The windo w pro vides all the details and reveals whether a c atalo g is up-to -date and what the Index Server is c urrently do ing (see Figure 23-10). The Index Server do esn’t update its c atalo gs immediately. Instead, it waits fo r the system to bec o me idle. While yo u are busy wo rking with yo ur applic atio ns, the Index Server patiently waits in the bac kgro und. This way, yo ur wo rk isn’t slo wed do wn.
660
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Mo st likely, yo u’ll see two c atalo gs: System and Web. System is the index o f yo ur lo c al file system. Web is the index o f yo ur Web server if yo u have installed the Internet Info rmatio n Server. If the Web c atalo g is missing, yo u did no t enable yo ur Web Publishing func tio ns. On Windo ws NT 4 with IIS, yo u find a Web c atalo g, but the lo c al System c atalo g is missing.
Figure 23-10: See w hat your Index Server is currently doing. Do uble-c lic k a c atalo g to see whic h fo lders it inc ludes. In the to o lbar, yo u find a butto n to make the hierarc hic al tree view visible.
Adding and removing folders from the index Index c atalo gs fo r yo ur lo c al system and fo r yo ur Web server are managed differently. The Web c atalo g sho uld be managed with the Internet Info rmatio n Server c o ntro ls o nly. Yo ur lo c al index is managed by the Explo rer. To add a path to yo ur c atalo g, o pen it as o utlined abo ve. Then po int at an empty spac e in the windo w and right-c lic k. Cho o se New and Fo lder. Yo u c an no w explic itly add a fo lder path and spec ify whether this fo lder sho uld be inc luded in yo ur index o r no t. The fo lder yo u spec ify inc ludes all o f its subfo lders. By default, the System c atalo g inc ludes the ro o t fo lders o f all o f yo ur drives. This means that all data o n yo ur drives is auto matic ally part o f the index. In additio n, there are so me fo lder exc lusio ns. The Index Server do esn’t index the fo lders with all the perso nal settings.
Adding a new catalog Yo u c an always add additio nal c atalo gs. This way, yo u c an spec ify a spec ific c atalo g and searc h o nly fo r areas o f yo ur system defined in this c atalo g. Ho wever, adding additio nal c atalo gs generally isn’t a go o d idea bec ause it c o sts a lo t o f reso urc es. The Index Server has to update eac h c atalo g
Chapte r 2 3 : Us ing Databas e s
661
■
■
individually, and there will be separate index files, taking many megabytes o f extra spac e. Yo u do n’t need additio nal c atalo gs just bec ause yo u wo uld like to limit yo ur searc h to spec ific fo lders. Instead, define the “sc o pe” o f yo ur searc h and use the general System c atalo g fo r all o f yo ur searc hes.
Querying the Index Server No w that yo u kno w the general arc hitec ture, let’s searc h fo r so me info rmatio n. Chec k o ut the next sc ript (see Figure 23-11): It lists the first 20 matc hes fo r do c uments that c o ntain bo th “Mic ro so ft” and “ADO:” ‘ 23-11.VBS ‘ Access Index Server set index = CreateObject(“ixsso.Query”) ‘ Define search criteria index.Query = “Microsoft and ADO” ‘ Define catalog to search index.Catalog = “system” ‘ Select information to include in result set index.Columns = “filename, size, hitcount, rank, path, characterization” ‘ limit result to 20 index.MaxRecords = 20 ‘ sort by rank (quality of result), descending order index.SortBy = “rank[d]” ‘ allow optimization index.AllowEnumeration = true ‘ Result is a record set set rs = index.CreateRecordset(“nonsequential”) ‘ display file names do until rs.EOF list = list & rs(“filename”) & vbCr rs.MoveNext loop MsgBox list
Query c o ntains yo ur searc h request. Here, yo u’ll disc o ver the first great differenc e fro m the o ld-fashio ned full-text searc h. In this c ase, yo u c an use Bo o lean o perato rs suc h as and, o r, and no t to searc h fo r multiple key wo rds.
MaxRecords limits the result set, and Columns spec ifies whic h c o lumns to inc lude in the result set.
662
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Figure 23-11: Quickly find the firs t 20 documents matching “Micros oft ” and “ADO.”
Exploring information categories Table 23-3 lists the info rmatio n c atego ries yo u c an query.
Table 23-3
Index Server Information Categories
Column
Description
filename
Name of file
path
Path name
vpath
Virtual path name (us ed for Web acces s )
hitcount
Number of matches
rank
Relative hit count (0 to 100)
create
Time of file creation
write
Time of las t file change
DocTitle
Title of document
DocSubject
Subject of document
DocPageCount
Number of pages
DocAuthor
Author name of document
DocKeywords
Keyw ords in document
DocComments
Comments in document
Characterization
Summary report of file content
Chapte r 2 3 : Us ing Databas e s
663
■
■
The next sc ript allo ws yo u to experiment with the advanc ed searc h c apabilities. First, the sc ript o pens an input dialo g bo x so yo u c an type in yo ur searc h c riteria. It then lists the path names o f the files in the result set: ‘ 23-12.VBS do set index = CreateObject(“ixsso.Query”) index.MaxRecords = 20 index.SortBy = “rank[d]” index.AllowEnumeration = true index.Catalog = “system” index.Columns = “filename, size, hitcount, rank, path,” _ & “characterization” criteria = InputBox(“Search for:”) if criteria=vbEmpty then exit do index.Query = criteria set rs = index.CreateRecordset(“nonsequential”) ‘ display file names list = “” do until rs.EOF list = list & rs(“path”) & vbCr rs.MoveNext loop MsgBox list if index.QueryTimedOut then MsgBox “Your query was too complex!” end if if index.QueryIncomplete then MsgBox “Search result is not complete!” end if if index.OutOfDate then MsgBox “Index is not up-to-date. Results may not “ _ & “be accurate.” end if loop MsgBox “Done!”
Use the QueryTimedOut, QueryInxcomplete, and OutOfDate pro perties to c hec k whether the index is c urrent and whether yo ur searc h has pro c essed witho ut erro rs. The ixsso.Query o bjec t is no n-rec yc lable. Yo u c an use it o nly fo r o ne query. Onc e yo u have issued yo ur query using CreateRecordset, yo u c an’t use it fo r new searc hes. Instead, get a new instanc e and c all CreateObject again.
664
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Using Boolean operators To c o mbine multiple keywo rds, use Bo o lean o perato rs. Fo r example, to searc h fo r do c uments c o ntaining the wo rds Mic ro so ft and ADO but no t MDAC, use this query: Microsoft and ADO and not MDAC
Searching for phrases Yo u c an even query in natural language. Use the $contents keywo rd: $contents “How do I change screen resolution?”
Querying file properties Use # in c o njunc tio n with o ne o f the info rmatio n c atego ries listed in Table 23-3 and inc lude file pro perties into yo ur searc h. Fo r example, to searc h fo r all WinWo rd do c uments starting with the letter “A,” use this query: #filename a*.doc
Or c o mbine a natural language query with the selec tio n o f spec ific do c ument types: ($contents “How do I change the screen resolution”) and (#filename *.htm or #filename *.hlp or #filename *.chm)
Use @ instead o f # to c o mpare file pro perties. Fo r example, to list o nly .doc files greater that 10,000 bytes, write #filename *.doc and @size>10000
Limiting searches to specific folders Let’s see ho w yo u c an make real use o f the Index Server. Let’s assume yo u want to searc h the fo lder My Do c uments fo r WinWo rd and HTML do c uments o nly. Yo u’d like to get a list o f all the do c uments that matc h yo ur key wo rds. Ho w do yo u limit the sc o pe o f yo ur searc h? Yo u need ano ther o bjec t, namely ixsso.Util. The fo llo wing sc ript do es the jo b. It auto matic ally limits the sc o pe o f the searc h to yo ur perso nal My Do c uments fo lder and all o f its subfo lders. ‘ 23-13.VBS set wshshell = CreateObject(“WScript.Shell”) do set index = CreateObject(“ixsso.Query”) index.MaxRecords = 20 index.SortBy = “rank[d]” index.AllowEnumeration = true index.Catalog = “system” index.Columns = “path, rank”
Chapte r 2 3 : Us ing Databas e s ■
665 ■
criteria = InputBox(“Search for:”) if criteria=vbEmpty then exit do index.Query = criteria ‘ limit the scope set util = CreateObject(“ixsso.Util”) util.AddScopeToQuery index, _ wshshell.SpecialFolders(“MyDocuments”), “deep” set rs = index.CreateRecordset(“nonsequential”) ‘ display file names list = “” do until rs.EOF list = list & rs(“path”) & vbCr rs.MoveNext loop MsgBox list if index.QueryTimedOut then MsgBox “Your query was too complex!” end if if index.QueryIncomplete then MsgBox “Search result is not complete!” end if if index.OutOfDate then MsgBox “Index is not up-to-date. Results may “ _ & “not be accurate.” end if loop MsgBox “Done!”
Creating your own search dialog box Maybe yo u are fed up with the new searc h panel Mic ro so ft has built into the Explo rer. I perso nally liked the o ld searc h dialo g bo x muc h better. What’s even wo rse, the new searc h dialo g bo x do esn’t even suppo rt many o f the advanc ed Index Server features. This is why I have c reated a little COM o bjec t. Use it as a searc h dialo g bo x o r as a fo undatio n fo r yo ur o wn pro jec ts (see Figure 23-12). Install the COM o bjec t first ( \install\index\setup.exe). Full so urc e c o de is pro vided at \components\index\index.vbp. ‘ 23-14.VBS set tool = CreateObject(“index.search”) set wshshell = CreateObject(“WScript.Shell”) selected = tool.ShowDialog MsgBox “You selected: “ & selected
666
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
MsgBox “You can re-open the search any time!” selected = tool.ShowDialog MsgBox “You can also clear the display!” tool.DeleteDialog selected = tool.ShowDialog MsgBox “I now add scope to your search and only allow searches on drive C: and your windows folder!” tool.AddScope “C:\”, “shallow” tool.AddScope wshshell.ExpandEnvironmentStrings(“%WINDIR%”), “shallow” selected = tool.ShowDialog MsgBox “Now I remove the scope again!” tool.ClearScope result = tool.ShowDialog
Figure 23-12: Create your ow n s earch dialog boxes and take advantage of pow erful s earch options .
Fine-tuning Index Server Yo ur dialo g bo x pro vides a summary c o lumn. In this c o lumn, the Index Server displays a sho rt summary o f the file. Ho wever, summaries are displayed o nly if the Index Server c reates a summary in the first plac e. Summary c reatio n is turned o ff by default fo r perfo rmanc e reaso ns. To turn summary c reatio n o n, c ho o se Searc h in the Start menu and searc h fo r Files and Fo lders. Then, c lic k Index Server in the left c o lumn and c ho o se Advanc ed. Clic k iconexpand.jpg to see the tree view. No w, right-c lic k the Indexing Servic e o n Lo c al Mac hine and c ho o se Pro perties. Cho o se the Generate abstrac ts o ptio n and c lic k OK (see Figure 23-13).
Chapte r 2 3 : Us ing Databas e s
667
■
■
Figure 23-13: Turn on abs tract generation if you w ant to us e the “characterization” info column.
It takes a while fo r the Index Server to c reate summary info rmatio n. Yo u c an always sto p the Index Server and right-c lic k the System c atalo g. Cho o se All Tasks and Empty Catalo g to re-c reate it fro m sc ratc h, and then restart the Index Server.
Summary In this c hapter, yo u saw ho w easy it is to use ADO to ac c ess any kind o f database. Best o f all, yo u c an use a sample database and manage it c o mpletely by sc ript — no additio nal so ftware is required. Yo u c an read and write data to the database, and even c reate entirely new tables. Yo ur sc ripts c an no w c alc ulate invo ic es, c reate mass e-mail, and maintain yo ur perso nal sc hedule. Windo ws 2000 go es a step further. The Index Server ac ts like a database, but in reality it is a dynamic info rmatio n sto re o f all the data sto red o n yo ur lo c al drives. Sc ripts c an easily take advantage o f this po werful mec hanism: Use Bo o lean searc h o perato rs and even natural language queries to quic kly find the info rmatio n yo u need.
Chapte r 2 4
Managing Windows NT/ 2000 Server In This Chapter 䊳 Manage Windo ws NT thro ugh the API— add/ delete users, c hange
permissio ns, and c hange gro up membership 䊳 Find o ut abo ut ADSI and ho w yo u get it 䊳 Disc o ver the ADSI o bjec t mo del, and c hange user ac c o unt pro perties 䊳 Manage servic es: start, sto p, and pause them, even o n remo te systems 䊳 Shut do wn yo ur lo c al mac hine o r any remo te c o mputer 䊳 Add sec ret Registry keys to auto matic ally lo g o nto Windo ws NT
S
c ripts are perfec t fo r administering Windo ws NT/ 2000. Thro ugh API c alls and the new ADSI (Ac tive Direc to ry Servic e Interfac e), yo ur sc ripts c an manage user ac c o unts, file shares, printers, and servic es. In c o njunc tio n with the file system metho ds, yo u c an easily transfer hundreds o f user pro files in a matter o f minutes. In this c hapter, yo u learn ho w to use bo th the API and ADSI to manage all kinds o f server-related tasks.
Managing Windows NT/ 2000 Security Managing Windo ws NT/ 2000 c an be anno ying at times — it’s just to o muc h wo rk to administer hundreds o f user ac c o unts manually. Isn’t there so me mac ro language that c an auto matic ally take c are o f ro utine wo rk? There is. VBSc ript and the Windo ws Sc ripting Ho st c an help yo u administer Windo ws NT/ 2000, and Mic ro so ft has made VBSc ript the o ffic ial new auto matio n language o f Windo ws 2000. This sho ws yo u the new emphasis Mic ro so ft puts o n VBSc ript.
670
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Ho wever, VBSc ript itself is o nly the framewo rk. It do esn’t pro vide any metho ds to ac c ess user ac c o unts and c hange sec urity settings. There are two ways to add these c apabilities: ■ Write yo ur o wn COM o bjec ts. Yo u’ve seen many COM o bjec ts thro ugho ut
this bo o k serve as sc ripting extensio ns, and Windo ws NT management func tio ns pro vided by the API c an easily “ wrap” inside COM o bjec ts. ■ Add ADSI to yo ur system. ADSI is the new management standard
intro duc ed with Windo ws 2000. It’s a general interfac e to standardize ho w sc ripts talk to different namespaces. Yo u do n’t need Windo ws 2000 to take advantage o f ADSI, tho ugh. ADSI is available separately, and it’s free. All yo u need is to do wnlo ad the ADSI update. The big ADSI advantage is its availability: Yo u c an find it o n any Windo ws 2000 mac hine, and yo u c an add it to o ther Windo ws versio ns. Also , ADSI is a general interfac e, and yo u c an ac c ess Exc hange mail ac c o unts o r the Ac tive Direc to ry. Ho wever, its drawbac k is speed: ADSI is muc h slo wer than direc t API c alls. Espec ially if yo u plan to batc h-update large numbers o f ac c o unts, yo u sho uld use the API appro ac h.
Creating scripting extensions to manage user accounts Table 24-1 lists so me sc ripting extensio ns I’ve c reated to help yo u manage Windo ws NT/ 2000. Ho wever, these extensio ns are pro vided as sample o nly. In a pro fessio nal pro duc tio n enviro nment, review the so urc e c o de to make sure it wo rks as intended. Be extremely c autio us if yo u dec ide to experiment with these extensio ns. I’ve pro vided full so urc e c o de so yo u c an understand and expand the COM o bjec ts as yo u like. Make sure yo u have installed the COM o bjec ts listset in Table 24-1. They are needed fo r the API-based sc ripts.
Table 24-1
COM Objects Provided W ith This Book
COM Object
Description
\install\ntuser\setup.exe
Manage us er accounts
\install\ntservice\setup.exe
Manage s ys tem s ervices
\install\ntshutdown\setup.exe
Shutdow n a s ys tem locally or remotely
Getting ready for ADSI ADSI is exc iting and muc h mo re suitable fo r sc ripting. It will be the new standard o nc e Windo ws 2000 takes o ver, so it’s a go o d idea to get
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r ■
671 ■
ac c usto med with it. ADSI is free, and yo u c an upgrade Windo ws NT 4 by go ing to www.microsoft.com/adsi. Lo o k fo r the suitable update fo r yo ur system and do wnlo ad the pac kage. It’s c o mparably lightweight. Onc e yo u have updated yo ur system to ADSI, yo u c an immediately take advantage o f all the ADSI sample sc ripts.
Managing User Accounts (the API Way) Fiddling aro und manually with user ac c o unts is very time-c o nsuming and erro r-pro ne, at least in larger c o mpanies. Do n’t do it. Yo u c an fo rget mo st o f the dialo g bo xes with yo ur new sc ripting extensio ns and manage user ac c o unts so lely by sc ript o nc e yo u have installed the COM sc ript extensio n as o utlined previo usly.
Enumerating users To find o ut whic h users are defined o n a spec ific c o mputer, use EnumUsers: ‘ 24-1.VBS set tool = CreateObject(“nt.user”) MsgBox tool.EnumUsers MsgBox tool.EnumUsers(“\\scenic”)
Yo u c an query lo c al users as well as user ac c o unts o n remo te mac hines as lo ng as yo u have the nec essary permissio ns.
EnumUsers returns the info rmatio n as name, comment, usercomment, and full name. Use Split to get to the individual info rmatio n: ‘ 24-2.VBS set tool = CreateObject(“nt.user”) users = Split(tool.EnumUsers, vbCr) for x=0 to UBound(users)-1 infos = Split(users(x), vbTab) list = list & “Username: “ & infos(0) & vbCr list = list & “Comment: “ & infos(1) & vbCr & vbCr next MsgBox list, vbInformation
672
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
EnumUsers suppo rts a sec o nd parameter that wo rks as a filter:
Table 24-2
Filter Codes for Enumerating User Accounts
Filter
Description
1
Local us er account data on a domain controller
2
Global us er account data on a computer
4
Combination of all
8
Domain trus t account data on a domain controller
16
Works tation or member s erver account data on a domain controller
32
Domain controller account data on a domain controller
The next sc ript sho ws the differenc es. Yo u c an c o mbine filter flags to inc lude mo re than o ne gro up: ‘ 24-3.VBS set tool = CreateObject(“nt.user”) for i = 0 to 5 users = Split(tool.EnumUsers(,2^i), vbCrLf) list = “Enumerating using filter “ & 2^i & vbCr for x=0 to UBound(users)-1 infos = Split(users(x), vbTab) list = list & “Username: “ & infos(0) & vbCr next MsgBox list, vbInformation next
Adding users Yo ur sc ripts c an add users, to o . Use AddUser: ‘ 24-4.VBS set tool = CreateObject(“nt.user”) if tool.AddUser(“”, “testaccount”, “secret”, _ 5, “c:\users\test”, “this is a test account”) then MsgBox “User account added!” else MsgBox “Couldn’t add user account: “ & tool.GetLastError end if
This is the c o mplete syntax: AddUser server, user, pwd, expires, homedir, comment, scriptdir
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
673
■
■
Table 24-3
AddUser Parameters
Argument
Description
server
Name of s erver or “” for local s erver
user
Name of us er account
pwd
Pas s w ord
expires
Days the pas s w ord is valid
homedir
Home directory
comment
Comment des cribing the account purpos e
scriptdir
Script directory
Deleting user accounts DelUser deletes a user ac c o unt. No te that deleting a user ac c o unt c an’t be undo ne. Even if yo u re-c reate the ac c o unt later, the new ac c o unt gets new Sec urity IDs and ac ts as a different ac c o unt. ‘ 24-5.VBS set tool = CreateObject(“nt.user”) if tool.DelUser(“”, “testaccount”) then MsgBox “User account deleted!” else MsgBox “Couldn’t delete user account: “ & tool.GetLastError end if
Changing passwords Yo ur sc ript c an c hange user passwo rds, to o . Yo u have two o ptio ns, o ne being to pro vide the o ld passwo rd as authentic atio n. Or, if yo u are an administrato r, yo u c an use administrative o verride and skip the o ld passwo rd. This is espec ially useful if so meo ne has fo rgo tten his o r her passwo rd o r has left the c o mpany. Exec ute sc ript 24-4.VBS first to add a test user ac c o unt, and then c hange the passwo rd: ‘ 24-6.VBS set tool = CreateObject(“nt.user”) if tool.ChangePassword(“”, “testaccount”, _ “newpassword”, “secret”) then MsgBox “Password has changed!” else
674
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
MsgBox “Couldn’t change password: “ & tool.GetLastError end if
To use administrative o verride, yo u need administrato r privilege. Skip the o ld passwo rd: ‘ 24-7.VBS set tool = CreateObject(“nt.user”) if tool.ChangePassword(“”, “testaccount”, _ “newpassword”) then MsgBox “Password has changed!” else MsgBox “Couldn’t change password: “ & tool.GetLastError end if
Listing global groups Yo ur COM o bjec t c an manage glo bal gro ups, to o . Lo c al gro ups c anno t be managed. Glo bal gro ups are a feature o f do mains. On yo ur lo c al c o mputer, yo u may no t have ac c ess to glo bal gro ups. Take a lo o k at yo ur glo bal gro ups: ‘ 24-8.VBS set tool = CreateObject(“nt.user”) MsgBox tool.EnumerateGroups
Yo u c an list the gro ups o f individual servers, to o : ‘ 24-9.VBS set tool = CreateObject(“nt.user”) MsgBox tool.EnumerateGroups(“\\SCENIC”)
Yo u c an even find o ut the gro ups a spec ific user belo ngs to : ‘ 24-10.VBS set tool = CreateObject(“nt.user”) MsgBox tool.EnumerateGroups(“”, “testaccount”)
Maybe yo u want to list the users in a spec ific gro up. Here’s ho w: ‘ 24-11.VBS set tool = CreateObject(“nt.user”) MsgBox tool.EnumGroupUsers(“”, “Power User”)
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r ■
675 ■
Managing group membership Yo ur sc ript c an add users to gro ups and remo ve them fro m gro ups, to o . This is ho w yo u make yo ur test ac c o unt a member o f the do main administrato rs: ‘ 24-12.VBS set tool = CreateObject(“nt.user”) if
tool.AddUserToGroup(“”, “Power User”, “testaccount”) then MsgBox “User added to group!”
else MsgBox “Couldn’t add user to group: “ & tool.GetLastError end if
To remo ve the ac c o unt fro m the gro up, use this appro ac h: ‘ 24-13.VBS set tool = CreateObject(“nt.user”) if
tool.DelUserFromGroup(“”, “Power User”, “testaccount”) then MsgBox “User removed from group!”
else MsgBox “Couldn’t remove user from group: “ & tool.GetLastError end if
Finding the primary domain controller Internally, the COM o bjec t uses a helper func tio n to find the primary do main c o ntro ller if yo u spec ify a do main name instead o f a server name. Yo u c an use this metho d separately, to o . Just replac e the do main name in the sample sc ript with a valid do main name: ‘ 24-14.VBS set tool = CreateObject(“nt.user”) MsgBox tool.GetPrimaryDCName(“ASP”)
Exploring the ADSI World ADSI c an ac c ess all kinds o f namespaces. Namespaces refer to the way an applic atio n o r servic e o rganizes its data. To ac c ess Windo ws NT sec urity, ADSI uses the identifier WinNT:. Let’s c hec k o ut what this namespace has to o ffer: ‘ 24-15.VBS ‘ get access to namespace set namespace = GetObject(“WinNT:”)
676
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
‘ see what we get for each object in namespace list = list & object.name & vbCr next MsgBox list
The namespace c o ntains the names o f all do mains and wo rkgro ups c urrently o nline. Yo u c an dive into the hierarc hy. Fo r example, pic k a listed do main and enumerate its c o ntent. Exc hange the do main name in this example with a valid do main name. Yo u c an also use a c o mputer name. ‘ 24-16.VBS ‘ get access to namespace set namespace = GetObject(“WinNT://ASP”) ‘ see what we get for each object in namespace list = list & object.name & vbCr next MsgBox list
Who a: This time the sc ript spits o ut all the user ac c o unts and gro ups. If yo u are interested in yo ur lo c al c o mputer o nly, yo u c an further enhanc e yo ur sc ripts and have them use yo ur c o mputer name by default. Just use the ComputerName metho d pro vided by WScript.Network: Set objNet = WScript.CreateObject(“WScript.Network”) MsgBox objNet.ComputerName
Let’s c hec k o ut who is a member in a spec ific gro up: ‘ 24-17.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to namespace set namespace = GetObject(“WinNT://” & local & “/Power Users”) ‘ see what we get for each object in namespace list = list & object.name & vbCr next MsgBox list
This time, yo u get an erro r. Yo u c an’t ask fo r user names this way.
Getting “real” error messages Whenever ADSI raises an erro r, yo u wo n’t get a c lue what is go ing o n. This is bec ause ADSI raises OLE erro rs and do esn’t suppo rt the VBSc ript-style
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
677
■
■
err.description pro perty. So , the first task is to find o ut why ADSI raises an erro r. Fo rtunately, yo u do n’t need to invest muc h time: Yo u’ve do ne it already. Remember? In Chapter 4, yo u develo ped a COM o bjec t that transfo rms OLE erro r numbers into c lear text erro r messages. Just make sure yo u have installed the COM o bjec t: \install\oleerr\setup.exe. No w, yo u c an find o ut the reaso n why ADSI c o mplains: ‘ 24-18.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to namespace set namespace = GetObject(“WinNT://” & local & “/Power Users”) ‘ see what we get on error resume next for each object in namespace list = list & object.name & vbCr next CheckError MsgBox list sub CheckError if not err.number=0 then ‘ an error occured set ole = CreateObject(“ole.err”) MsgBox ole.oleError(err.Number), vbCritical err.clear end if end sub
Yo u get an “Erro r no t fo und” erro r: ADSI was unable to find what yo u requested. While WinNT: and do mains are c o ntainers, gro ups are no t. Yo u c an’t enumerate their c o ntent and get away with it. Gro ups are single o bjec ts.
Is it a container? The next sc ript pro vides a metho d to c hec k whether an o bjec t is a c o ntainer o r no t: ‘ 24-19.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName list = WhatIsIt(“WinNT://” & local) list = list & WhatIsIt(“WinNT://” & local & “/Power Users”)
678
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
MsgBox list, vbInformation function WhatIsIt(objname) set obj = GetObject(objname) if isContainer(obj) then WhatIsIt = objname & obj.class & else WhatIsIt = objname & obj.class & end if end function
& “ is a container and of class “ _ vbCr & “ is NO container and of class “ _ vbCr
function isContainer(obj) set classobj = GetObject(obj.Schema) isContainer = classobj.Container end function
Enumerating group memberships Gro ups are o bjec ts with their o wn pro perties and metho ds. Here are the metho ds:
Table 24-4
ADSI Group M ethods
M ethod
Description
Description
Des cription of group
Members
Collection of members
IsMember
Tes ts w hether a us er is a member of this group
Add
Adds object to group
Remove
Removes object from group
So , this is ho w yo u enumerate the members o f a gro up: ‘ 24-20.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set group = GetObject(“WinNT://” & local & “/Power Users”) ‘ see what we get for each member in group.Members list = list & member.name & vbCr next MsgBox list
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
679
■
■
Testing whether a user belongs to the group Using IsMember, yo u c an no w ask the gro up whether a user is a member: ‘ 24-21.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to group set group = GetObject(“WinNT://” & local & “/Power Users”) ‘ ask if user is member if group.isMember(“WinNT://” & local & “/Administrator”) then MsgBox “User is group member!” else MsgBox “User is no group member!” end if
Creating a new user account If yo u want to c reate new things, yo u need to ho o k yo urself up to the parent c o ntainer. Fo r example, if yo u want to c reate a new user ac c o unt in a do main, c o nnec t to the do main. Then, c all the Create metho d and spec ify the c lass o f o bjec t yo u want to c reate. Likewise, yo u c an c o nnec t to a c o mputer and c reate lo c al ac c o unts. The fo llo wing sc ript adds a new ac c o unt c alled testaccount so yo u c an play aro und with gro up memberships and user rights: ‘ 24-22.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set server = GetObject(“WinNT://” & local) set user = server.Create(“User”, “testaccount”) on error resume next user.SetInfo if err.number=0 then MsgBox “Account added.” else CheckError end if sub CheckError if not err.number=0 then ‘ an error occured set ole = CreateObject(“ole.err”) MsgBox ole.oleError(err.Number), vbCritical err.clear end if end sub
680
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Yo u must c all SetInfo to write yo ur new o bjec t into the parent c o ntainer. Witho ut SetInfo, yo ur new o bjec t is lo st. No te that Windo ws 2000 wo n’t list new users in the user dialo g bo x until yo u add them to at least o ne gro up.
Finding out all groups a user belongs to Do yo u want to find o ut to whic h gro ups a spec ific user belo ngs? Use the Groups metho d. Mo st likely, ho wever, yo ur newly c reated ac c o unt do esn’t belo ng to any gro up yet, so the result will be an empty dialo g bo x. I’ll sho w yo u ho w to add and remo ve yo ur testaccount to gro ups a little later in this c hapter. ‘ 24-23.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get user set user = GetObject(“WinNT://” & local & “/testaccount”) list = “User is member of the following groups:” & vbCr for each group in user.Groups list = list & group.name & vbCr next MsgBox list, vbInformation
Adding a user to the group Use Add to add a user to a gro up: ‘ 24-24.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to group set group = GetObject(“WinNT://” & local & “/Power Users”) ‘ add member on error resume next group.Add “WinNT://” & local & “/testaccount” CheckError sub CheckError if not err.number=0 then ‘ an error occured
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
681
■
■
set ole = CreateObject(“ole.err”) MsgBox ole.oleError(err.Number), vbCritical err.clear else MsgBox “Done.” end if end sub
Use sc ript 24-23.VBS to c hec k the new gro up membership.
Removing a user from a group Use Remove to get rid o f a user in a gro up: ‘ 24-25.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to group set group = GetObject(“WinNT://” & local & “/Power Users”) ‘ remove member on error resume next group.Remove “WinNT://” & local & “/testaccount” CheckError sub CheckError if not err.number=0 then ‘ an error occured set ole = CreateObject(“ole.err”) MsgBox ole.oleError(err.Number), vbCritical err.clear else MsgBox “Done.” end if end sub
Finding out secret group properties Gro ups (and many o ther o bjec ts, to o ) suppo rt a ric h set o f pro perties. These pro perties c o ntro l every aspec t o f the gro up behavio r. Fo rtunately, yo u do n’t need huge referenc e wo rks to searc h fo r the o bjec t pro perties. Use a sc ript instead: ‘ 24-26.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to group
682
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
set group = GetObject(“WinNT://” & local & “/Power Users”) ‘ list properties ListProperties group sub ListProperties(obj) set ole = CreateObject(“ole.err”) on error resume next set classobj = GetObject(obj.Schema) for each prop in classobj.MandatoryProperties list = list & prop & “ (mandatory)” & vbCr next for each prop in classobj.OptionalProperties list = list & prop & “ (optional)” & vbCr next if err.number=0 then MsgBox list, vbInformation else MsgBox ole.OleError(err.number), vbExcamation err.clear end if end sub
Querying group properties No w that yo u kno w so me Group pro perties, let’s find o ut their values: ‘ 24-27.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to group set group = GetObject(“WinNT://” & local & “/Power Users”) on error resume next MsgBox “Description: “ & group.Description MsgBox “groupType: “ & group.groupType CheckError sub CheckError if not err.number=0 then ‘ an error occured set ole = CreateObject(“ole.err”) MsgBox ole.oleError(err.Number), vbCritical err.clear else MsgBox “Done.” end if end sub
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r ■
683 ■
Group type is an integer value. Table 24-5 pro vides the real meaning.
Table 24-5
ADSI Group Type
Group Type
Description
2
Global group
4
Local group
8
Univers al group
&H80000000
Security group (can be s et w ith either group type)
Let’s no w enumerate all gro ups and find o ut the gro up type: ‘ 24-28.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to namespace set groups = GetObject(“WinNT://” & local) groups.Filter = Array(“Group”) ‘ see what we get for each group in groups grouptype = group.groupType if (grouptype and 2)>0 then typ = “ (global group)” elseif (grouptype and 4)>0 then typ = “ (local group)” elseif (grouptype and 8)>0 then typ = “ (universal group)” end if if (grouptype and &H80000000)0 then sec = “ (security group)” else sec = “ (distribution group)” end if list = list & group.name & typ & sec & vbCr next MsgBox list
As a first step, the sc ript has c o nnec ted to a do main. Bec ause it is interested o nly in o bjec ts o f type “Gro up,” it uses the Filter pro perty to filter gro ups o nly. Filter always expec ts an array. Yo u c an filter fo r multiple o bjec t c lasses. Array(“Group”, “User”) lists gro ups and users.
684
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Setting user passwords Use SetPassword to c hange an ac c o unt passwo rd: ‘ 24-29.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set user = GetObject(“WinNT://” & local & “/testaccount”) set ole = CreateObject(“ole.err”) on error resume next user.SetPassword “secret” if err.number=0 then MsgBox “Password changed.” else MsgBox “Couldn’t change password: “ _ & ole.OleError(err.number) end if
SetPassword is yo ur administrative o verride — a brute fo rc e appro ac h, bec ause yo u do n’t need to kno w the o ld passwo rd. If yo u do n’t have administrato r privileges and wo uld like to c hange yo ur o wn passwo rd, yo u c an pro vide the o ld passwo rd as authentic atio n: ‘ 24-30.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set server = GetObject(“WinNT://” & local) set user = server.Create(“User”, “testaccount”) set ole = CreateObject(“ole.err”) on error resume next user.ChangePassword “secret”, “newpassword” if err.number=0 then MsgBox “Password changed.” else MsgBox “Couldn’t change password: “ _ & ole.OleError(err.number) end if
Changing user account information User ac c o unts c o ntain pro perties, and yo u c an c hange tho se pro perties: ‘ 24-31.VBS set ole = CreateObject(“ole.err”)
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
685
■
■
Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set user = GetObject(“WinNT://” & local & “/testaccount”) user.FullName = “My full name” on error resume next user.SetInfo if err.number=0 then MsgBox “Done.” else MsgBox “Errors: “ & ole.OleError(err.number) end if
Fo r a full list o f pro perties, use this sc ript: ‘ 24-32.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName ‘ get access to group set user = GetObject(“WinNT://” & local & “/testaccount”) ‘ list properties ListProperties user sub ListProperties(obj) set ole = CreateObject(“ole.err”) on error resume next set classobj = GetObject(obj.Schema) for each prop in classobj.MandatoryProperties list = list & prop & “ (mandatory)” & vbCr next for each prop in classobj.OptionalProperties list = list & prop & “ (optional)” & vbCr next if err.number=0 then MsgBox list, vbInformation else MsgBox ole.OleError(err.number), vbExcamation err.clear end if end sub
No t all o f the listed pro perties are really suppo rted. If yo u try to read o r write a pro perty that isn’t there, yo u get an “Erro r no t fo und” erro r.
686
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Forcing password changes Do yo u want to fo rc e users (o r an entire department, fo r that matter) to c hange their passwo rds? This is ho w yo u do it: ‘ 24-33.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set user = GetObject(“WinNT://” & local & “/testaccount”) user.Put “PasswordExpired”, CLng(1) user.SetInfo
That wasn’t bad, was it?
Prohibiting password changes Maybe it’s the o ppo site way aro und, and yo u want to make sure a user c an’t c hange the passwo rd yo u assigned. This is the so lutio n: ‘ 24-34.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set user = GetObject(“WinNT://” & local & “/testaccount”) flag = user.Get(“UserFlags”) flag = flag or &H40 user.Put “UserFlags”, flag user.SetInfo
Table 24-6 lists all the kinds o f flags yo u c an use.
Table 24-6
User Account Properties
Flag
Description
1
Execute logon s cript.
2
Account dis abled.
8
Home Directory required.
&H10
Lockout.
&H20
Pas s w ord not required.
&H40
Pas s w ord can’t change.
&H80
Encrypted text pas s w ord allow ed.
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
687
■
■
Flag
Description
&H100
Us er has acces s to domain but not to trus ted domains .
&H200
Normal account.
&H10000
Don’t expire pas s w ord.
&H40000
SmartCard required.
Disabling accounts Use AccountDisabled to c o ntro l whether an ac c o unt is o peratio nal o r no t: ‘ 24-35.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set user = GetObject(“WinNT://” & local & “/testaccount”) user.AccountDisabled = true user.SetInfo
Ano ther way is to let an ac c o unt expire. Use the fo llo wing tec hnique to c reate tempo rary ac c o unts: ‘ 24-36.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set user = GetObject(“WinNT://” & local & “/testaccount”) user.AccountExpirationDate = “03/18/2001” user.SetInfo
To enable an ac c o unt fo rever, use an expiratio n date o f “01/ 01/ 1970”.
Unlocking accounts The system c an lo c k ac c o unts — fo r example, if yo u try the wro ng passwo rd to o many times. To re-enable suc h an ac c o unt, yo u need to unlo c k it: ‘ 24-37.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set user = GetObject(“WinNT://” & local & “/testaccount”) user.isAccountLocked = false user.SetInfo
688
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Managing Windows Services Windo ws Servic es are pro grams that run silently in the bac kgro und and pro vide so me kind o f servic e to the system. Hundreds o f servic es are running at o nc e, and it’s c ritic al to stable netwo rk o peratio n that c o re servic es run smo o thly. Yo ur sc ripts c an manage servic es, query their status, and even start, sto p, and pause servic es as needed. Again, yo u have two ways to appro ac h this issue: Use the API o r use ADSI.
Controlling services through the API If yo u have installed the COM add-o n ( ntservice), yo u c an bro wse fo r servic es right away. Use GetServiceInfo: ‘ 24-38.VBS Const SERVICE_ACTIVE = 1 Const SERVICE_INACTIVE = 2 Const SERVICE_ACTIVEINACTIVE = 3 Const SERVICE_DRIVER = 15 Const SERVICE_WIN32 = 48 set tool = CreateObject(“nt.services”) text = “Active drivers” & vbCr MsgBox text & tool.GetServiceInfo(SERVICE_ACTIVE, SERVICE_DRIVER) text = “Inactive drivers” & vbCr MsgBox text & tool.GetServiceInfo(SERVICE_INACTIVE, SERVICE_DRIVER) text = “Active Win32” & vbCr MsgBox text & tool.GetServiceInfo(SERVICE_ACTIVE, SERVICE_WIN32) text = “Inactive Win32” & vbCr MsgBox text & tool.GetServiceInfo(SERVICE_INACTIVE, SERVICE_WIN32) ‘ Querying the status MsgBox tool.ServiceStatus(“Beep”) MsgBox tool.ServiceStatus(“Netman”) MsgBox tool.ServiceStatus(“Alerter”)
Starting and stopping services ServicePause, ServiceStart, and ServiceStop c o ntro l individual servic es. Spec ify the server name as o ptio nal sec o nd argument.
Managing services through ADSI ADSI manages servic es in the usual hierarc hic al way: Co nnec t to the c o mputer yo u want to mo nito r. Filter the o bjec t and list o nly o bjec ts o f c lass Service. The Status pro perty reveals the servic e state: ‘ 24-39.VBS
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
689
■
■
Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName if not EnumServices(local, result) then MsgBox result, vbCritical else MsgBox “Services:” & vbCr & result end if function EnumServices(server, result) states = Split(“,Started,,Stop pend.,Running,,,Paused,Error”, _ “,”) set winnt = GetObject(“WinNT://” & server) winnt.Filter = Array(“Service”) on error resume next result = “” for each service in winnt result = result & service.Name & vbTab _ & States(service.Status) & vbCr next status = err.number on error goto 0 if status=0 then EnumServices = true else set ole = CreateObject(“ole.err”) result = ole.OleError(status) EnumServices = false end if end function
Managing individual services Servic es are simple o bjec ts in the ADSI o bjec t mo del. Yo u c an c o nnec t direc tly if yo u kno w the name o f the servic e: ‘ 24-40.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set service = GetObject(“WinNT://” & local & “/W3SVC”) MsgBox service.Name MsgBox service.StartType
This sc ript c o nnec ts to the Web server servic e and determines the StartType (see Table 24-7). If there is no Web server servic e running o n yo ur system, the sc ript generates an erro r.
690
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Table 24-7
Service Start Types
StartType
Description
0
Service is s tarted automatically during boot.
1
Service is s tarted at OS initialization.
2
Service is s tarted by the Service Control Manager.
3
Service is s tarted on demand by the Service Control Manager.
4
Service is dis abled.
Yo u c an c hange auto matic servic e start: Assign a new value to the pro perty and c all SetInfo: ‘ 24-41.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName set service = GetObject(“WinNT://” & local & “/W3SVC”) service.StartType = 3 service.SetInfo
Yo u c an also manually start and sto p servic es. Use the Start, Stop, Pause, and Continue metho ds.
Controlling Network Shares ADSI c an even manage netwo rk shares. With yo ur new freedo m, yo u c an use the Scripting.FileSystemObject to c reate new fo lders and add a netwo rk share using ADSI. This way, the new fo lder is ac c essible thro ugho ut yo ur entire netwo rk.
Enumerating shared folders Take a lo o k at ho w ADSI enumerates shared fo lders. The key is to c o nnec t direc tly to the servic e respo nsible fo r sharing fo lders, in this c ase LanmanServer. The FileService servic e then pro vides a c o llec tio n o f all shared fo lders. It wo n’t list hidden shares, tho ugh. Hidden shares are marked with a $. ‘24-42.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r ■
691 ■
Set fs = GetObject(“WinNT://” & local & “/LanmanServer”) If (fs.class = “FileService”) then on error resume next For Each fish In fs desc = fish.Name if desc = “” then desc = “(no name)” list = list & desc & vbTab & fish.Path & vbCr next end if MsgBox list
Adding network shares It’s easy to add yo ur o wn shares by using the Create metho d to add an o bjec t o f type FileShare and by pro viding it with a unique name. The sample sc ript uses the share name Public. Replac e it with any name yo u wish, but make sure the name is unique. Yo u c an’t use names that already serve as a share name. ‘ 24-43.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName foldername = “C:\testfolder” set fs = CreateObject(“Scripting.FileSystemObject”) if not fs.FolderExists(foldername) then fs.CreateFolder foldername end if Set cont = GetObject(“WinNT://” & local & “/LanmanServer”) Set share = cont.Create(“FileShare”, “Public”) share.Path = foldername share.SetInfo MsgBox “folder is now shared”
Accessing shared folder properties Pro vided yo u have assigned a name to yo ur shared fo lder, yo u c an ac c ess it direc tly thro ugh ADSI. This pro vides yo u with all the sec ret pro perties abo ut the share. ‘ 24-44.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName Set share = GetObject(“WinNT://” & local & “/LanmanServer/Public”) MsgBox share.Path
692
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Use the fo llo wing pro perties to get advanc ed info rmatio n abo ut yo ur shares:
Table 24-8
Secret Properties
Property
Description
CurrentUs erCount
Number of us ers currently w orking w ith the s hare (R)
Des cription
Des cription of folder purpos e (R/W)
Hos tComputer
Path name of hos t (R/W)
Path
Path name of s hare (R/W)
MaxUs erCount
Maximum number of us ers allow ed to w ork w ith s hare concurrently (R/W)
All pro perties marked as R/ W c an bo th be read and c hanged. To set the maximum user c o unt to a limit o f five users, use c o de like this: ‘ 24-45.VBS Set net = WScript.CreateObject(“WScript.Network”) local = net.ComputerName Set share = GetObject(“WinNT://” & local & “/LanmanServer/Public”) share.MaxUserCount = 5 share.SetInfo MsgBox “Set max user to 5”
Automatically Restarting and Shutting Down Thro ugh the API, yo ur sc ripts c an shut do wn o r restart bo th yo ur lo c al mac hine and remo te c o mputers. Obvio usly, yo u need appro priate permissio ns to c lo se a mac hine do wn remo tely — it’s nec essary to be lo gged o n as administrato r. Shutdo wn c apabilities are pro vided by yet ano ther COM o bjec t, c alled ntshutdown. Make sure yo u have installed it.
Shutting down a local machine To shut do wn o r rebo o t yo ur lo c al mac hine, use the ExitWindows metho d. It expec ts o ne o ptio nal parameter, as indic ated in Table 24-9.
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
693
■
■
Table 24-9
Shutdow n Options
Parameter
Description
0
Logoff
1
Shutdow n
2
Reboot
In additio n, Table 24-10 sho ws two values that enhanc e the basic rebo o t o ptio ns.
Table 24-10
Shutdow n Enhancements
Parameter
Description
4
Force: don’t w ait for programs to clos e
8
Pow er-off machine if pos s ible
Remotely shutting down a machine Use RemoteShutdown to send a shutdo wn request to ano ther netwo rk mac hine. Remo te shutdo wn will o nly be initiated if yo u have the appro priate rights o n the remo te mac hine. While shutdo wn is initiated, a dialo g bo x warns the remo te user. As lo ng as the dialo g bo x is visible, AbortShutdown c an c anc el the shutdo wn request. ‘ 24-46.VBS set tool = CreateObject(“nt.shutdown”) set wshshell = CreateObject(“WScript.Shell”) server = InputBox(“Servername?”) result = tool.RemoteShutdown(server, “I’ll shutdown your system!”, _ 5, true, false) if result0 then wshshell.Popup “I am shutting down “ _ & server & “. Hit OK within 5 secs to abort!”, 5 tool.AbortShutdown server
694
Part V: Ac c e s s ing Hidde n Co mpo ne nts
■
■
Automatic logon Windo ws NT Server/ Windo ws 2000 Server require yo u to use a lo go n passwo rd. Ho wever, if yo ur mac hine wo rks in a safe enviro nment, yo u may use auto matic lo go n, to o . ‘ 24-47.VBS set wshshell = CreateObject(“WScript.Shell”) key = “HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\” state = ReadKey(key & “AutoAdminLogon”) if state=1 then msg = “AutoLogon activated. Disable?” else msg = “AutoLogon not activated. Enable?” end if answer = MsgBox(msg, vbYesNo + vbQuestion) if answer = vbYes then if state=1 then DeleteKey key & “AutoAdminLogon” DeleteKey key & “DefaultUserName” DeleteKey key & “DefaultPassword” DeleteKey key & “DefaultDomainName” MsgBox “Done.” else name = Ask(“Username?”) password = Ask(“Password?”) antwort = MsgBox(“Logon to domain?”, vbYesNo + vbQuestion) if antwort = vbYes then domain = Ask(“Domain name?”) wshshell.RegWrite key & “DefaultDomainName”, domain end if wshshell.RegWrite key & “DefaultUserName”, name wshshell.RegWrite key & “DefaultPassword”, password wshshell.RegWrite key & “AutoAdminLogon”, 1 MsgBox “Done.” end if end if
function ReadKey(key) on error resume next ReadKey = wshshell.RegRead(key) if not err.number=0 then err.clear ReadKey = vbEmpty end if end function function DeleteKey(key) on error resume next
Chapte r 2 4 : Managing Windo ws NT/ 2 0 0 0 Se rve r
695
■
■
dummy = wshshell.RegRead(key) if err.number=0 then wshshell.RegDelete key if not err.number=0 then MsgBox “Key “”” & key & “””: unable to delete!” err.clear end if end if end function function Ask(question) Ask = InputBox(question) if Ask=”” then WScript.Quit end function
Summary This c hapter pro vided so me exc ellent to o ls fo r Windo ws NT management. Yo u learned ho w to add and delete users, c hange gro up memberships, and do it all with fast API c alls. This o pens the do o r fo r timesaving batc h-auto matio n. Yo u also learned abo ut ano ther COM o bjec t, whic h pro vides the metho ds to remo tely o r lo c ally shut do wn o r restart yo ur system. Yo u also disc o vered ADSI, the new interfac e fo r all kinds o f namespaces. Yo u explo red the o bjec t hierarc hy and c reated to o ls to enumerate do mains, gro ups, users, servic es, and even pro perty sets. ADSI allo ws almo st anything. It’s yo ur c o mplete to o lbo x fo r pro fessio nal administratio n. This c hapter c o nc ludes the lo ng Windo ws sc ripting to ur we started 24 c hapters ago . Sc ripting has matured, and yo u no w have bo th the inside kno wledge and the to o ls to effic iently master any c hallenge — true sc ripting po wer at yo ur fingertips.
Appe ndix A
When Bad Things Happen
T
rue sc ripting fun almo st always requires additio nal COM o bjec ts to spic e up the basic sets o f c o mmands. Finding, o r even pro gramming, suc h sc ript extensio ns isn’t hard — yo u’ll find numero us examples and full so urc e c o de in this bo o k. Ho wever, befo re yo u c an use suc h extensio ns, yo u’ll need to install them. This is where things c an bec o me tric ky.
I Can’t Install Some of the Script Components! All sc ripts o n CD auto matic ally c hec k whether o r no t the required COM o bjec ts are c urrently installed o n yo ur system. If a COM o bjec t is missing, the sc ript wo n’t sit silently. Instead, it will tell yo u whic h c o mpo nent is missing, and all yo u need to do is install the c o mpo nent fro m the c o mpanio n CD. But what if yo u c an’t get a COM o bjec t installed? What if so me so urc e c o de wo n’t c o mpile? On the next c o uple o f pages, I’ll pro vide yo u with a lo t o f undo c umented bac kgro und details that will help yo u understand (and reso lve) tho se issues.
Details about COM Object installation The easiest way to get a COM o bjec t wo rking o bvio usly is the use o f the prepared install pac kages. All yo u need to do is c all SETUP.EXE, and the Visual Basic installer takes c are o f everything else. Unfo rtunately, the installer isn’t very c lever. It wo rks mo st o f the time, but no t always, and so metimes, it may even have bad side effec ts. The first step the installer needs to do is c o pying the OCX file to yo ur system. The OCX-file is the “heart” o f yo ur COM o bjec t. The installer wo n’t c o py this file, tho ugh, if there’s already a file o f the same name sto red in the Windo ws fo lder. It wo n’t warn yo u, either. It just wo n’t install the new OCX c o mpo nent but still repo rt “suc c ess”. So the first thing yo u sho uld do uble-c hec k is whether o r no t there are already OCX files o f the name yo u are abo ut to install. Onc e the installer has suc c essfully c o pied the OCX-file to yo ur system, it registers the file auto matic ally. Registering means that it will write all the
698
Appe ndixe s
■
■
impo rtant o bjec t info rmatio n into the Windo ws registry. Mo st o f the time, this wo rks smo o thly. Ho wever, o n a Windo ws NT/ 2000 system, yo u may be required to have the appro priate permissio ns. On Windo ws 9x-systems, a c o rrupt registry may refuse to ac c ept the new registratio n info rmatio n. On Windo ws 98, yo u c an always “refresh” yo ur registry by launc hing the DOS mo de and using SCANREG /FIX. Onc e the OCX file is c o pied and registered, the installer c o pies a lo t o f additio nal files to yo ur c o mputer. Amo ng these are the required Visual Basic run-time files. Ho wever, there c an be o ther files, to o . So me c o mpo nents require the servic es o f o ther c o mpo nents. Fo r example, so me COM o bjec ts need ac c ess to the Co mmo n Dialo g c o mpo nent, and o thers take advantage o f Internet FTP o r Ko dak Imaging TWAIN c o mpo nents. Whenever there are suc h “dependenc ies”, the installer c o pies these files to yo ur c o mputer, to o . It sho uld make sure that it c o pies files o nly if they are missing, and o nly if there are no newer versio ns already installed. Unfo rtunately, due to the many servic e pac ks and add-o ns Mic ro so ft has published, this c o nc ept so metimes do esn’t wo rk. In the wo rst c ase, the installer o verwrites newer files with o lder versio ns. This may c ause yo ur entire system to suffer.
Windows 2000 Installer problems On Windo ws 2000, yo u may enc o unter ano ther fasc inating flaw — here, yo u c an install o ne Visual Basic pac kage o nly. Onc e yo u try to install a sec o nd o ne, Windo ws will c o mplain abo ut files it was unable to rename. Restarting Windo ws 2000 will enable yo u to install exac tly o ne mo re pac kage until the same erro r hits yo u.
Finding easy ways out... The best appro ac h therefo re is to no t use the Visual Basic installer tec hnique at all. A muc h safer way is to lo ad the so urc e files and rec o mpile the COM o bjec ts o n yo ur system. This way, no files are o verwritten, and the resulting COM o bjec t is guaranteed to run o n yo ur system. If yo u must use the VB installer tec hnique, fo r example bec ause yo u want to distribute yo ur COM o bjec ts to so me c usto mers, always make sure yo u c o mpiled the setup files o n a system as similar as po ssible to the target systems. Do n’t c o mpile o n Windo ws NT when yo ur target c o mputers use Windo ws 98. Yo u c an also fine-tune the install pac kage. Just o pen the SETUP.LST file and remo ve any files yo u do n’t want the installer to distribute. This way, yo u c an also c o mbine mo re than o ne install pac kage so yo ur c usto mer do esn’t have to launc h the installer multiple times. Mo st o f the COM o bjec ts really o nly require the OCX file. So yo u c o uld distribute the OCX file with the VB 5 run-time files and register the OCX file
Appe ndix A: Whe n Bad Things Happe n
699
■
■
manually using REGSVR32.EXE. This is the safest way to install yo ur o wn COM o bjec ts bec ause this way yo u have full c o ntro l o ver whic h files are c o pied to the target system. If yo u kno w fo r sure that the VB 5 run-time files are already installed o n the target system, then distributing OCX files o nly is a very slic k metho d. OCX files are o nly a c o uple o f hundred bytes in size and c an easily be do wnlo aded o ver the Internet. If yo u want to get rid o f OCX files so me day, use REGSVR32 again and take advantage o f its o ptio ns. /u will unregister any OCX file, and / ? will po p up a dialo g with all the o ptio ns the c o mmand has to o ffer. Onc e an OCX file is unregistered, it c an no lo nger be used bec ause all the o bjec t info rmatio n is remo ved fro m the Windo ws registry. The OCX file itself is still there, so yo u sho uld delete it after unregistering it.
Using Commercial Installer Software There’s ano ther alternative — . Instead o f the free Visual Basic installer, yo u c an always reso rt to a c o mmerc ial installer suc h as InstallShield. If yo u need to distribute yo ur COM o bjec ts o n a c o mmerc ial basis, these installers may well be wo rth the effo rt (and c o sts). The VB installer is suitable fo r ho me use o nly.
I can’t compile the source code! But what if yo u c an’t c o mpile the so urc e c o de in the first plac e? I have c hec ked the so urc es numero us times o n numero us systems, so the reaso n fo r this behavio r is no t a design flaw. Mo st likely, the so urc e c o de referenc es external c o mpo nents that are missing o n yo ur system. Fo r example, if yo u use the Ko dak Imaging to o ls to c reate yo ur o wn little pho to c o py mac hine, yo ur system may use a different versio n o f the Imaging to o ls. The Visual Basic develo pment enviro nment wo n’t be able to find the to o ls I used when I c reated the pro jec t. Yo u’ll see erro rs c o mplaining abo ut illegal pro perties o r wro ng arguments. If this sho uld happen to yo u, just remo ve the c o mpo nents and then add them again. By adding the c o mpo nents, yo u make sure the referenc es are c o rrec t. To do this, yo u right-c lic k the to o lbar windo w and c ho o se Co mpo nents. No w yo u’ll see a list o f all the c o mpo nents the pro jec t uses — c o mpo nents in use are marked with a c hec kmark. Clic k a c o mpo nent to see the true filename o f the c o mpo nent. Next, yo u c an remo ve the c o mpo nents fro m the fo rm o r user c o ntro l, and then add them again using ano ther right-c lic k into the to o lbar windo w, c ho o sing Co mpo nents and Bro wse. Spec ify the filename yo u no ted earlier. Onc e the newly added c o mpo nents appear in yo ur to o lbo x, yo u c an plac e them o nto the fo rm o r user c o ntro l.
700
Appe ndixe s
■
■
If yo u c an’t so lve the pro blem, dro p me a line: [email protected]. I’ll be mo re than happy to assist yo u. Always bear in mind, sc ripting is like an adventure game. Do n’t expec t everything to wo rk as smo o thly as a majo r applianc e.
What’s the fuss about “Automation Errors”? Auto matio n erro rs o c c ur if the COM o bjec t yo ur sc ript uses isn’t c o mmunic ating right. Mo st o f the time, this is due to versio n inc o mpatibilities. Fo r example, if yo u c o mpile the Internet to o ls o n a Windo ws 98 mac hine and try to use them with Windo ws 2000, yo u’ll get an Auto matio n erro r. This is why the prepared so ftware pac kages were all c o mpiled o n Windo ws 2000. Sinc e Windo ws 2000 is the latest Windo ws versio n, COM o bjec ts c o mpiled o n this system will generally wo rk with all o lder Windo ws versio ns. If yo u do get auto matio n erro rs, then rec o mpile the c o de o n yo ur o wn mac hine.
Appe ndix B
About the CD-ROM
T
he CD-ROM inc luded with this bo o k c o ntains the fo llo wing materials:
■ All sc ripts and c o mpo nent so urc e c o de fro m the bo o k ■ Mic ro so ft Windo ws Sc ript Tec hno lo gies Trial ■ Ado be Ac ro bat Reader ■ An elec tro nic versio n o f this bo o k, Windo ws Scripting Se cre ts, in
.pdf fo rmat
Scripts and Component Source Code Do n’t type in all the sc ripts and so urc es! There’s a muc h easier way: o n this bo o k’s c o mpanio n CD-ROM, where yo u’ll find bo th the sc ripts and all the c o mpo nent so urc e c o de. To c o mpile and run the sc ripts and so urc e c o de fo r this bo o k, yo u will need the Visual Basic Co ntro l Creatio n Editio n (VB CCE), whic h yo u c an do wnlo ad fro m Mic ro so ft at http://msdn.microsoft.com/vbasic/downloads/cce/, and Windo ws Sc ripting Ho st 2.0, whic h yo u c an o btain at http://www. microsoft.com/msdownload/vbscript/scripting.asp?id=01.
Creating your own COM objects After yo u have installed the Visual Basic Co ntro l Creatio n Editio n (o r if yo u already o wn Visual Basic ), yo u c an ac c ess the COM o bjec t so urc e c o des in the Code\Components direc to ry. These are o rganized in subdirec to ries by pro jec t name: appactivate, capture, and so o n. Open the .vbp files to see all the internal mec hanic s. There are no sec ret parts; I have pro vided full so urc e c o de o f any COM o bjec t intro duc ed in this bo o k.
Installing COM objects the easy way If yo u do n’t like to c o mpile COM o bjec ts yo urself, take a lo o k into the Install subdirec to ry. Here, yo u find setup pac kages fo r all COM o bjec ts. Just c all setup.exe, and the Visual Basic installer will install all nec essary files o nto yo ur c o mputer.
702
Appe ndixe s
■
■
Ho wever, befo re yo u install anything using the Visual Basic installer, make sure yo u have read the installer limitatio ns o utlined in Appendix A. The pac kages have been c o mpiled with Windo ws 2000 to ensure they will wo rk with as many Windo ws versio ns as po ssible. Still, using the VB installer may no t install all c o mpo nents c o rrec tly o n yo ur system. There may even be c ases where the installer replac es newer files with o lder o nes, an intrinsic limitatio n o f the VB installer, whic h is why yo u sho uld pay attentio n to the fo llo wing c aveat. On production systems critical to your business, you
should avoid the VB installer packages and instead compile the COM objects yourself.
Using scripts All sc ripts are o rganized by c hapter, and sto red in the Code/Scripts subfo lder. In c o ntrast to the so urc e c o de printed in the bo o k, the sc ripts o n CD also inc lude a pro tec tio n ro utine. It c hec ks whether all o f the required COM o bjec ts are installed o n yo ur system. This ro utine c o nsists o f two c learly marked parts, and yo u c an remo ve tho se lines anytime if yo u do n’t need this kind o f pro tec tio n.
Changing and editing files No te also that all files o n CD by default have a write-pro tec tio n attribute. If yo u want to c hange a file, yo u must c o py it to yo ur hard drive and remo ve the write pro tec tio n attribute manually.
Overview: COM object list All COM o bjec ts disc ussed in this bo o k and used within the sc ripts are listed in the fo llo wing table. In the left c o lumn, yo u find the COM o bjec t names sc ipts use to ac c ess the c o mpo nent. In the right c o lumn, yo u find the name o f the c o mpo nent o n CD. Searc h fo r this name bo th in Code\Components (so urc e c o de) and Code\Install (setup pac kages).
Table A-1
COM Objects and Components
COM Object Name
Component Name on CD
App.activate
appactivate
Cd.tools
Cdtray
Clip.board
Clipboard
Compress.files
Compres s
Dialog.test
Inputbox
Appe ndix A: Abo ut the CD-ROM
703
■
■
COM Object Name
Component Name on CD
Dlg.tools
Comdlg
Dll.tobtools
Dll
File.versioninfo
Vers ion
Filesystem.tool
files ys
Folder.tools
folderpicker
Format.tool
Format
Icon.handler
iconhandler
Iconpicker.tool
Iconpick
Iehelper.tools
Iehelper
Internet.communication
Internet
Listview.tool
Lis tview
Mci.manager
Mci
Memory.stats
Memory
Misc.information
Mis cinfo
Modeless.dialog
Modeles s
Module.spy
Spy
Nt.services
Nts ervice
Nt.shutdown
Nts hutdow n
Nt.user
Ntus er
Ole.bitmap
Capture
Ole.err
Oleerror
Os.version
Os vers ion
Process.id
Proces s
Property.tool
Property
Registry.update
Regupdate
Regtool.tob
Regis try
Screen.tool
s creen
Shellcopy.tool
Shellcopy
Timer.event
Timer
Tray.icon
Tray
Treeview.tool
Treeview Co ntinue d
704
Appe ndixe s
■
■
Table A-1
( co ntinue d)
COM Object Name
Component Name on CD
Twain.manager
Scan
Typelib.decoder
Typelib
Web.dialog
Webdialog
Window.list
Window lis t
Window.list2
Window lis t2
Window.Manager
Winmanager
Microsoft Windows Script Technologies Trial The CD-ROM inc ludes the Windo ws Sc ript Tec hno lo gies Trial fro m Mic ro so ft, whic h inc ludes valuable add-o ns and do c umentatio n. Inc luded are: ■ SCE10EN.EXE, whic h allo ws enc ryptio n o f sc ript files ■ SCT10EN.EXE, whic h inc ludes sc ript c o mpo nents useful fo r develo pers
who wish to inc lude sc ripting c apabilities into their applic atio ns. ■ STE51EN.EXE, whic h helps install the latest versio n o f Windo ws
Sc ripting Ho st. ■ VBSDOC.EXE, whic h inc ludes VBSc ript help files. ■ JSDOC.EXE, whic h inc ludes JSc ript help files. ■ WSHDOC.EXE, whic h inc ludes Windo ws Sc ripting Ho st help files.
To install any o f these items, go to the Windows Script Technology direc to ry o n the CD and do uble-c lic k the appro priate exec utable file, then fo llo w the setup instruc tio ns.
Adobe Acrobat Reader Ado be Ac ro bat Reader is a helpful pro gram that will enable yo u to view the elec tro nic versio n o f this bo o k in the same page fo rmat as the ac tual bo o k. To install and run Ado be Ac ro bat Reader and view the elec tro nic versio n o f this bo o k, fo llo w these steps:
1. Start Windo ws Explo rer (if yo u’re using Windo ws 95/ 98) o r Windo ws NT/ 2000 Explo rer (if yo u’re using Windo ws NT/ 2000), and then o pen the Adobe Acrobat fo lder o n the CD-ROM.
Appe ndix A: Abo ut the CD-ROM ■
705 ■
2. In the Adobe Acrobat fo lder, do uble-c lic k rs40eng.exe and fo llo w the instruc tio ns presented o nsc reen fo r installing Ado be Ac ro bat Reader.
3. To view the elec tro nic versio n o f this bo o k after yo u have installed Ado be Ac ro bat Reader, start Windo ws Explo rer (if yo u’re using Windo ws 95/ 98) o r Windo ws NT/ 2000 Explo rer (if yo u’re using Windo ws NT/ 2000), and then o pen the Windows Scripting Secrets PDF fo lder o n the CD-ROM. In the Windows Scripting Secrets PDF fo lder, do uble-c lic k the c hapter o r appendix file yo u want to view. All do c uments in this fo lder end with a .pdf extensio n.