Professional Excel Development The Definitive Guide 9780321262509, 0321262506

Microsoft Excel can be much more than just a spreadsheet. It has become adevelopment platform in it own right. Applicati

1,081 36 9MB

English Pages 949 Year 2005

Report DMCA / Copyright

DOWNLOAD PDF FILE

Recommend Papers

Professional Excel Development The Definitive Guide
 9780321262509, 0321262506

  • 0 0 0
  • Like this paper and download? You can publish your own PDF file online for free in a few minutes! Sign Up
File loading please wait...
Citation preview

Professional Excel Development: The Definitive Guide to Developing Applications Using Microsoft® Excel and VBA® By Stephen Bullen, Rob Bovey, John Green Publisher: Addison Wesley Professional Pub Date: February 01, 2005 ISBN: 0-321-26250-6 Table of Contents • Index •

Pages: 936

• Examples

Finally, t here's a book t hat t reat s Excel as t he powerful developm ent plat form it really is, and covers every facet of developing com m ercialqualit y Excel applicat ions. This is not a book for beginners. Writ ing for professional developers and t rue Excel expert s, t he aut hors share insider's knowledge t hey've acquired building Excel applicat ions for m any of t he world's largest com paniesincluding Microsoft . Professional Excel Developm ent dem onst rat es how t o get t he ut m ost from Excel, addressing everyt hing from applicat ion archit ect ures t hrough worksheet and userform design, chart ing, debugging, error handling and opt im izing perform ance. Along t he way, t he aut hors offer best pract ices for every t ype of Excel developm ent , from building add- ins t hrough int eract ing wit h XML Web services. Coverage includes Building add- ins t o provide new Excel funct ions Designing effect ive worksheet s, userform s and ot her user int erface elem ent s Leveraging Excel's powerful dat a analysis feat ures Creat ing sophist icat ed cust om chart s Handling errors, debugging applicat ions and opt im izing per for m ance Using class m odules and int erfaces t o creat e cust om obj ect s Underst anding Windows API calls: when t o use t hem , and how t o m odify t hem Adding worksheet funct ions wit h C- based XLLs Program m ing wit h dat abases Cont rolling ext ernal applicat ions from Excel

I nt egrat ing wit h Visual Basic 6, VB.NET and Visual St udio Tools for Office Using XML t o im port and export dat a and com m unicat e wit h Web services Providing help, securing, packaging and dist ribut ing The accom panying CD- ROM cont ains t he book's sam ple t im esheet applicat ion at every st age of const ruct ion, wit h det ailed code com m ent s. I t also includes m any exam ples of t he concept s int roduced in each chapt er and a collect ion of t he aut hors' Excel developm ent ut ilit ies.

Professional Excel Development: The Definitive Guide to Developing Applications Using Microsoft® Excel and VBA® By Stephen Bullen, Rob Bovey, John Green Publisher: Addison Wesley Professional Pub Date: February 01, 2005 ISBN: 0-321-26250-6 Table of Contents • Index •

Pages: 936

• Examples

Copyright Praise for Professional Excel Development Acknowledgments About the Authors Stephen Bullen Rob Bovey John Green Chapter 1. Introduction About This Book The Excel Developer Excel as an Application Development Platform Structure Examples Supported Versions Typefaces On the CD Help and Support Feedback Chapter 2. Application Architectures Concepts Conclusion Chapter 3. Excel and VBA Development Best Practices Naming Conventions Best Practices for Application Structure and Organization General Application Development Best Practices Conclusion Chapter 4. Worksheet Design Principles of Good Worksheet UI Design Program Rows and Columns: The Fundamental UI Design Technique Defined Names Styles

User Interface Drawing Techniques Data Validation Conditional Formatting Using Controls on Worksheets Practical Example Conclusion Chapter 5. Function, General and Application-Specific Add-ins The Four Stages of an Application Function Library Add-ins General Add-ins Application-Specific Add-ins Practical Example Conclusion Chapter 6. Dictator Applications Structure of a Dictator Application Practical Example Conclusion Chapter 7. Using Class Modules to Create Objects Creating Objects Creating a Collection Trapping Events Raising Events Practical Example Conclusion Chapter 8. Advanced Command Bar Handling Command Bar Design Table-Driven Command Bars Putting It All Together Loading Custom Icons from Files Hooking Command Bar Control Events Practical Example Conclusion Chapter 9. Understanding and Using Windows API Calls Overview Working with the Screen Working with Windows Working with the Keyboard Working with the File System and Network Practical Examples Conclusion Chapter 10. Userform Design and Best Practices Principles Control Fundamentals Visual Effects Userform Positioning and Sizing Wizards

Dynamic Userforms Modeless Userforms Control Specifics Practical Examples Conclusion Chapter 11. Interfaces What Is an Interface? Code Reuse Defining a Custom Interface Implementing a Custom Interface Using a Custom Interface Polymorphic Classes Improving Robustness Simplifying Development A Plug-in Architecture Practical Example Conclusion Chapter 12. VBA Error Handling Error-Handling Concepts The Single Exit Point Principle Simple Error Handling Complex Project Error Handler Organization The Central Error Handler Error Handling in Classes and Userforms Putting It All Together Practical Example Conclusion Chapter 13. Programming with Databases An Introduction to Databases Designing the Data Access Tier Data Access with SQL and ADO Further Reading Practical Example Conclusion Chapter 14. Data Manipulation Techniques Excel's Data Structures Data Processing Features Advanced Functions Conclusion Chapter 15. Advanced Charting Techniques Fundamental Techniques VBA Techniques Conclusion Chapter 16. VBA Debugging Basic VBA Debugging Techniques The Immediate Window (Ctrl+G)

The Call Stack (Ctrl+L) The Watch Window The Locals Window The Object Browser (F2) Creating and Running a Test Harness Using Assertions Debugging Shortcut Keys that Every Developer Should Know Conclusion Chapter 17. Optimizing VBA Performance Measuring Performance The PerfMon Utility Creative Thinking Macro-Optimization Micro-Optimization Conclusion Chapter 18. Controlling Other Office Applications Fundamentals The Primary Office Application Object Models Practical Example Conclusion Chapter 19. XLLs and the C API Why Create an XLL-Based Worksheet Function Creating an XLL Project in Visual Studio The Structure of an XLL The XLOPER and OPER Data Types The Excel4 Function Commonly Used C API Functions XLOPERs and Memory Management Registering and Unregistering Custom Worksheet Functions Sample Application Function Debugging the Worksheet Functions Miscellaneous Topics Additional Resources Conclusion Chapter 20. Combining Excel and Visual Basic 6 A Hello World ActiveX DLL Why Use VB6 ActiveX DLLs in Excel VBA Projects In-Process versus Out-of-Process Automating Excel From a VB6 EXE Practical Examples Conclusion Chapter 21. Writing Add-ins with Visual Basic 6 A Hello World Add-in The Add-in Designer Installation Considerations The AddinInstance Events

Command Bar Handling Why Use a COM Add-in? Automation Add-ins Practical Example Conclusion Chapter 22. Using VB.NET and the Visual Studio Tools for Office Overview How to Leverage the .NET Framework Managed Workbooks Managed Excel Add-ins Hybrid VBA/VSTO Solutions The VSTO Security Model The Big Issues Further Reading Practical Example Conclusion Chapter 23. Excel, XML and Web Services XML Web Services Practical Example Conclusion Chapter 24. Providing Help, Securing, Packaging and Distributing Providing Help Securing Packaging Distributing Conclusion Index

Copyright Many of t he designat ions used by m anufact urers and sellers t o dist inguish t heir product s are claim ed as t radem arks. Where t hose designat ions appear in t his book, and t he publisher was aware of a t radem ark claim , t he designat ions have been print ed wit h init ial capit al let t ers or in all capit als. The aut hors and publisher have t aken care in t he preparat ion of t his book, but m ake no expressed or im plied warrant y of any kind and assum e no responsibilit y for errors or om issions. No liabilit y is assum ed for incident al or consequent ial dam ages in connect ion wit h or arising out of t he use of t he inform at ion or program s cont ained herein. The publisher offers excellent discount s on t his book when ordered in quant it y for bulk purchases or special sales, which m ay include elect ronic versions and/ or cust om covers and cont ent part icular t o your business, t raining goals, m arket ing focus, and branding int erest s. For m ore inform at ion, please cont act : U. S. Corporate and Governm ent Sales (800) 382-3419 cor psales@pear sont echgr oup.com For sales out side t he U. S., please cont act : I nternational Sales int er nat ional@pear soned.com Visit us on t he Web: w w w .aw pr ofessional.com Library of Congress Cat alog Num ber: 2004114575 Copyright © 2005 Pearson Educat ion, I nc. All right s reserved. Print ed in t he Unit ed St at es of Am erica. This publicat ion is prot ect ed by copyright , and perm ission m ust be obt ained from t he publisher prior t o any prohibit ed reproduct ion, st orage in a ret rieval syst em , or t ransm ission in any form or by any m eans, elect ronic, m echanical, phot ocopying, recording, or likewise. For inform at ion regarding perm issions, writ e t o: Pearson Education, I nc. Rights and Contracts Departm ent One Lake Street Upper Saddle River, NJ 07458 Text print ed in t he Unit ed St at es on recycled paper at Phoenix BookTech in Hagerst own, Maryland. First print ing, February, 2005

Praise for Professional Excel Development " Think you know Microsoft Excel? Think again. This book covers int erm ediat e ( class m odules, dict at or applicat ions, et c.) t o advanced t opics like XLLs, C API s and Web Services. I t offers plent y of easy t o underst and code list ings t hat show exact ly what t he aut hors are t rying t o convey wit hout forcing t he readers t o follow st ep- by- st ep." D e e pa k Sh a r m a , Sr . Syst e m s Spe cia list , Ta t a I n fot e ch Lt d. " This book t akes off where ot her Excel books st op. I t covers Excel program m ing beyond VBA and looks at t he professional issuessecurit y, dist ribut ion, working wit h dat abasesusing VB, VBA.NET and Windows API calls. The aut hors' dept h and pract ical experience shows in t he det ails. They explain com plex issues clearly, describe best pract ices and point out t raps t o av oid." Sh a u n a Ke lly, M icr osoft Office M VP, w w w .Sh a u n a Ke lly.com " The approach of following an applicat ion's developm ent is very effect ive in developing t he concept s as t he chapt ers unfold. The pract ical, working exam ples used are relevant t o m any professional program m ers." Ja n Ka r e l Pie t e r se , JKP Applica t ion D e ve lopm e n t Se r vice s, w w w .j k p- a ds.com " This book st ands out . While t here are plent y of Excel books, I am not aware of any organized in t his way. I nform at ion on .NET, and C, as well as ot her unique and useful chapt ers m akes t his a great offering." Ke n Blu t t m a n , Au t h or of D e ve lopin g M icr osoft Office Solu t ion s " This book explains difficult concept s in det ail. The aut hors provide m ore t han one m et hod for com plex developm ent t opics, along wit h t he advant ages and disadvant ages of using t he various m et hods described. They have m y applause for t he incorporat ion of developm ent best pr act ices." Be t h M e lt on , M icr osoft Office M VP

Acknowledgments First and forem ost , t his book would never have been writ t en wit hout t he support of our part ners and fam ilies, who have graciously put up wit h our insat iable com put er habit s and m any lat e night s over t he past year. Neit her would it have been done wit hout our dogs, who kept our feet warm while we worked and forced us t o get out of t he house at least once each day. We all owe a debt of grat it ude t o t he Excel group at Microsoft , past and present , for m aking Excel t he am azing developm ent plat form it is t oday. I t is t heir dedicat ion and com m it m ent t o us t hat m akes Excel applicat ion developm ent possible and enj oyable. They have repeat edly dem onst rat ed t heir willingness t o list en t o and im plem ent our suggest ions over t he years. There are m any people we want t o t hank at Addison- Wesley Professional, part icularly Am y Fleischer for bringing us t oget her, St ephane Thom as, Ebony Haight and Joan Murray for t heir support while writ ing t he book, Krist y Hart for st eering us t hrough t he product ion process and Curt Johnson for get t ing it on t he shelves. The qualit y of a t echnical book depends as m uch on t he reviewers as t he aut hors, so we want t o t hank all our t echnical reviewers. Most of your suggest ions were im plem ent ed. At t he risk of offending t he ot hers, we would part icularly like t o t hank Dick Kusleika and John Pelt ier for t he qualit y and rigor of t heir reviews and Bet h Melt on for finding num erous errors nobody else spot t ed. Last ly, we want t o t hank you for buying t his book. Please t ell us what you t hink about it , eit her by e- m ail or by writ ing a review at Am azon.com . Thank you, St ephen Bullen Rob Bovey John Green

About the Authors St ephen Bullen Rob Bovey John Green

Stephen Bullen st ephen@oalt d.co.uk St ephen Bullen lives in Woodford Green, London, England, wit h his part ner Clare, daught er Becky and t heir dog, Fluffy. A graduat e of Oxford Universit y, St ephen has an MA in Engineering, Econom ics and Managem ent , providing a unique blend of bot h business and t echnical skills. He has been providing Excel consult ing and applicat ion developm ent services since 1994, originally as an em ployee of Price Wat erhouse Managem ent Consult ant s and since 1997 as an independent consult ant t rading under t he nam e of Business Modelling Solut ions Lim it ed. I n Sept em ber 2004, BMS changed it s nam e t o Office Aut om at ion Lim it ed. I f you would like t o m ake use of St ephen's services, please cont act him at st ephen@oalt d.co.uk. The Office Aut om at ion Web sit e, w w w .oalt d.co.uk, provides a num ber of helpful and int erest ing ut ilit ies, exam ples, t ips and t echniques t o help in your use of Excel and developm ent of Excel applicat ions. St ephen cont ribut ed chapt ers t o John Green's Excel 2000 VBA Program m er's Reference and coaut hored t he sequel, Excel 2002 VBA Program m er's Reference ( bot h published by Wrox Press) . I n addit ion t o his consult ing and writ ing assignm ent s, St ephen act ively support s t he Excel user com m unit y in Microsoft 's peer- t o- peer support newsgroups. I n recognit ion of his knowledge, skills and cont ribut ions, Microsoft has awarded him t he t it le of Most Valuable Professional each year since 1996.

Rob Bovey r obbov ey @appspr o.com Rob Bovey is president of Applicat ion Professionals, a soft ware developm ent com pany specializing in Microsoft Office, Visual Basic, and SQL Server applicat ions. He brings m any years' experience creat ing financial, account ing and execut ive inform at ion syst em s for corporat e users t o Applicat ion Professionals. You can visit t he Applicat ion Professionals Web sit e at w w w .appspr o.com . Rob developed several add- ins shipped by Microsoft for Microsoft Excel, co- aut hored t he Micr osoft Excel 97 Developers Kit and cont ribut ed t o t he Excel 2002 VBA Program m er's Reference. He earned his Bachelor of Science degree from The Rochest er I nst it ut e of Technology and his MBA from t he Universit y of Nort h Carolina at Chapel Hill. He is a Microsoft Cert ified Syst em s Engineer ( MCSE) and a Microsoft Cert ified Solut ion Developer ( MCSD) . Microsoft has awarded him t he t it le of Most Valuable Professional each year since 1995. He current ly resides in Edm onds, Washingt on, wit h his wife Michelle, and t heir t wo black labs, Jasper and Jade.

John Green gr eenj @bigpond.net .au John Green lives and works in Sydney, Aust ralia, as an independent com put er consult ant , specializing in int egrat ing Excel, Access, Word and Out look using VBA. He has m ore t han 30 years of com put ing experience, a Chem ical Engineering degree and an MBA. He wrot e his first program s in FORTRAN, t ook a part in t he evolut ion of specialized planning languages on m ainfram es and, in t he early 1980s, becam e int erest ed in spreadsheet syst em s, including 1- 2- 3 and Excel. John est ablished his com pany, Execuplan Consult ing, in 1980, developing com put er- based planning applicat ions and t raining users and developers. John has had regular colum ns in a num ber of Aust ralian m agazines and has cont ribut ed chapt ers t o a num ber of books, including Excel Expert Solut ions and Using Visual Basic for Applicat ions 5, published by Que. He is t he principal aut hor of Excel 2000 VBA Program m er's Reference and it s subsequent edit ions, published by Wrox Press. Since 1995 he has been accorded t he st at us of Most Valuable Professional by Microsoft for his cont ribut ions t o t he Com puServe Excel forum and MS I nt ernet newsgroups.

Chapter 1. Introduction About This Book The Excel Developer Excel as an Applicat ion Developm ent Plat form St r uct ur e Exam ples Support ed Versions Typefaces On t he CD Help and Support Feedback

About This Book Microsoft Excel is m uch, m uch m ore t han j ust a spreadsheet . Since t he int roduct ion of t he Visual Basic Edit or in Excel 97 and t he im proved st abilit y of Excel 2000, it has becom e a respect ed developm ent plat form in it s own right . Applicat ions writ t en using Excel are now oft en found alongside t hose writ t en using Visual Basic, C+ + , Java, .NET and so on, as part of m any corporat ions' core suit e of business- crit ical applicat ions. I ndeed, Excel is oft en used for t he client end of Web- based applicat ions, m ade part icularly easy wit h Excel 2003's XML im port / export feat ur es. Unfort unat ely, Excel is st ill all t oo oft en t hought of as a hobbyist plat form t hat people develop spreadsheet - based applicat ions in t heir spare t im e t o help out wit h t heir day j ob. A brief look at t he shelves of any bookst ore seem s t o confirm t hat opinion. Alt hough t here are m yriad t it les explaining how t o use Excel and num erous t it les about Excel and VBA, none provide an overall explanat ion of how t o develop professional- qualit y Excel- based applicat ions. This is t hat book. Whereas all t he ot her m aj or languages seem t o have a de fact o st andard t ext t hat explains t he com m only agreed best pract ices for archit ect ing, designing and developing applicat ions in t hat language, Excel does not . This book aim s t o fill t hat gap. All t hree aut hors are professional Excel developers who run our own com panies developing Excelbased applicat ions for client s ranging from individuals t o t he largest m ult inat ional corporat ions. This book det ails t he approaches we use when designing, developing, dist ribut ing and support ing t he applicat ions we writ e for our client s. This is not a beginner- level book. We assum e t hat t he reader will have read and ( m ost ly) underst ood our Excel 2000/ 2002 VBA Program m er's Reference, John Walkenbach's Excel Power Pr ogr am m ing, or sim ilar t it les.

The Excel Developer Excel developers can be divided int o five general cat egories, based on t heir experience and knowledge of Excel and VBA. To varying degrees, t his book has som et hing t o offer each of t hem , but wit h a focus on t he m ore advanced t opics. Put t ing yourself int o one of t hese cat egories m ight help you decide whet her t his is t he right book for you. The basic Ex ce l u se r probably doesn't t hink of him self as a developer at all. To basic users, Excel is no m ore t han a t ool t o help t hem get on wit h t heir j ob. They st art off using Excel worksheet s as a handy place t o st ore list s or perform sim ple repet it ive calculat ions. As t hey discover m ore of Excel's funct ionalit y, t heir workbooks becom e m ore com plex and st art t o include lot s of worksheet funct ions, pivot t ables and chart s. There is lit t le in t his book for t hese people; alt hough Chapt er 4 Worksheet Design det ails t he best pract ices t o use when designing and laying out a worksheet for dat a ent ry, Chapt er 14 Dat a Manipulat ion Techniques explains how t o st ruct ure a worksheet and which funct ions and feat ures t o use t o m anipulat e t heir list s, and Chapt er 15 Advanced Chart ing Techniques, explains how t o get t he m ost from Excel's chart engine. The t echniques suggest ed in t hese chapt ers should help t he basic Excel user avoid som e of t he pit falls oft en encount ered as t heir experience and t he com plexit y of t heir spreadsheet s increases. The Ex ce l pow e r u se r has a wide underst anding of Excel's funct ionalit y, knows which t ool or funct ion is best t o use in a given sit uat ion, creat es com plex spreadsheet s for his own use and is oft en called on t o help develop colleagues' spreadsheet s or t o ident ify why colleagues' spreadsheet s do not work as int ended. Occasionally power users include sm all snippet s of VBA t hey found on t he I nt ernet or creat ed using t he m acro recorder, but st ruggle t o adapt t he code t o t heir needs. As a result , t hey produce code t hat is unt idy, slow and hard t o m aint ain. Alt hough t his book is not a VBA t ut orial, t he power user has m uch t o gain from following t he best pract ices we suggest for bot h worksheet s and code m odules. Most of t he chapt ers in t he book are relevant t o power users who have an int erest in im proving t heir Excel and VBA developm ent skills. The VBA de ve lope r m akes ext ensive use of VBA code in his workbooks ( oft en t oo m uch) . VBA developers are t ypically eit her power users who have st art ed t o learn VBA t oo early or Visual Basic 6 developers who have swit ched t o Excel VBA developm ent . Alt hough t hey m ight be very proficient at VBA, t hey believe every problem m ust have a VBA solut ion and lack sufficient knowledge of Excel t o m ake t he best use of it s feat ures. Their solut ions are oft en cum bersom e, slow and m ake poor use of Excel's obj ect m odel. This book has m uch t o offer VBA developers t o im prove t heir use of Excel it self, including explaining how t o archit ect Excel- based applicat ions, t he best pract ices for designing worksheet s and how t o use Excel's feat ures for t heir dat a ent ry, analysis and present at ion. This book also seeks t o im prove t heir Excel VBA developm ent skills by int roducing advanced coding t echniques, det ailing VBA best pract ices and explaining how t o im prove t heir code's perform ance. The Ex ce l de ve lope r has realized t he m ost efficient and m aint ainable applicat ions are t hose t hat m ake t he m ost of Excel's own funct ionalit y, augm ent ed by VBA when appropriat e. Excel developers are confident developing Excel- based applicat ions for t heir colleagues t o use or as part of an inhouse developm ent t eam . Their undoubt ed knowledge of Excel is put t o good use in t heir applicat ions, but it also const rains t heir designs, and t hey are reluct ant t o use ot her languages and applicat ions t o augm ent t heir Excel solut ions. They have probably read John Walkenbach's Excel

Power Program m ing and/ or our own Excel 2000/ 2002 VBA Program m er's Reference and need a book t o t ake t hem t o t he highest level of Excel applicat ion developm ent t hat of t he professional developer. This is t hat book. The pr ofe ssion a l Ex ce l de ve lope r designs and develops Excel- based applicat ions and ut ilit ies for client s or em ployers t hat are robust , fast , easy t o use, m aint ainable and secure. Excel form s t he core of t heir solut ions, but t hey include any ot her applicat ions and languages t hat are appropriat e. For exam ple, t hey m ight use t hird- part y Act iveX cont rols; aut om at e ot her applicat ions; use Windows API calls; use ADO t o connect t o ext ernal dat abases, C/ C+ + for fast cust om worksheet funct ions, VB6 or VB.Net for creat ing t heir own obj ect m odels and securing t heir code; and XML for sharing dat a over t he I nt ernet . This book t eaches all t hose skills. I f you are already a professional Excel developer, you know t hat learning never st ops and will appreciat e t he knowledge and best pract ices present ed in t his book by t hree of your peers.

Excel as an Application Development Platform I f we look at Excel as a developm ent plat form and not j ust a spreadsheet , we can break it down int o five fundam ent al com ponent s we can use for our applicat ions: The worksheet , chart s and so on, used as a user int erface and present at ion layer for dat a ent ry and report ing The worksheet , used as a sim ple dat a st ore for list s, t ables and ot her inform at ion used by our applicat ion VBA, Excel's program m ing language and form s engine The worksheet , used as a declarat ive program m ing language for high- perform ance num eric pr ocessing The Excel obj ect m odel, allowing program m at ic cont rol of ( nearly) all of Excel's funct ionalit y, from bot h wit hin Excel and from out side it

The Worksheet as a Presentation Layer for Data Entry and Reporting When m ost people t hink about Excel, t hey t hink in t erm s of t yping num bers int o cells, having som e calculat ions updat e and seeing a result displayed in a different cell or on a chart . Wit hout necessarily t hinking in such t erm s, t hey are using t he worksheet as a user int erface for t heir dat a ent ry and report ing and are generally com fort able wit h t hese t asks. The in- cell edit ing, validat ion and form at t ing feat ures built in t o Excel provide an ext rem ely rich and com pelling dat a- ent ry experience, while t he chart ing, cell form at t ing and drawing t ools provide a present at ion- qualit y report ing m echanism . I t is hard t o im agine t he code t hat would be required if we t ried t o reproduce t he experience using t he form design t ools available in m ost ot her developm ent environm ent s, yet it 's t here wait ing for us t o use in our Excel- based applicat ions. The biggest problem we face is how t o add som e st ruct ure t o t he free- form grid of t he worksheet , t o present a sim ple and easy- t o- use int erface, while leveraging t he rich funct ionalit y Excel provides. Chapt er 4 Worksheet Design int roduces som e t echniques and best pract ices for developing worksheet - based dat a- ent ry form s, and Chapt er 15 Advanced Chart ing Techniques discusses using Excel's chart ing capabilit ies.

The Worksheet as a Simple Data Store What is a worksheet when it is never int ended t o be shown t o t he end user? At it s sim plest , it is no m ore t han a large grid of cells in which we can st ore j ust about anyt hing we want t onum bers, t ext , list s, t ables or pict ures. Most applicat ions use som e am ount of st at ic dat a or t ext ual or graphical resources; st oring t hat inform at ion in a worksheet m akes it bot h ext rem ely easy t o access using VBA and sim ple t o m aint ain. List s and t ables in worksheet s can direct ly feed Excel's dat a validat ion ( as shown in Chapt er 4 Worksheet Design) , great ly sim plify t he creat ion and m aint enance of

com m and bars (Chapt er 8 Advanced Com m and Bar Handling) , and enable us t o const ruct dynam ic userform s ( Chapt er 10 Userform Design and Best Pract ices) .

VBA: Excel's Programming Language We expect m ost readers of t his book t o have at least som e fam iliarit y wit h VBA. I f not , we suggest you read eit her our Excel 2000/ 2002 VBA Program m er's Reference or John Walkenbach's Excel Power Program m ing before cont inuing m uch furt her. Many people see t he A in VBA as m eaning t he language is som ehow less t han Visual Basic it self. I n fact , bot h VB6 and Office 2000 and above use exact ly t he sam e DLL t o provide t he keywords, synt ax and st at em ent s we program wit h. The only differences are t he obj ect s provided by t he runt im es ( t he VB runt im e vs. t he Excel obj ect s) , t he form s packages ( VB's " Ruby" form s vs. Office UserForm s) and t hat VB6 includes a com piler t o creat e EXEs and DLLs, whereas VBA is always int erpret ed at runt im e. I ndeed, t he Office Developer Edit ion ( pre- Excel 2003) includes t he sam e com piler VB6 uses, enabling us t o com pile ( sim ple) DLLs from wit hin t he Office Visual Basic Edit or. Most beginner and int erm ediat e VBA developers use VBA as a p u r e ly procedural language, wit h nearly all t heir code residing in st andard m odules. VBA also enables us t o creat e applicat ions using an obj ect - orient ed program m ing ( OOP) approach, in which class m odules are used t o creat e our own obj ect s. Chapt er 7 Using Class Modules t o Creat e Obj ect s and Chapt er 11 I nt erfaces explain how t o use VBA in t his m anner, while basic OOP concept s ( such as encapsulat ion) are used t hroughout t he book. Most of t his book is dedicat ed t o explaining advanced VBA t echniques and a professional approach t o applicat ion design and developm ent t hat can put using VBA in Excel on a par wit h, and som et im es in front of, using VB6 or VB.Net for applicat ion developm ent . We also show in Chapt er 20 Com bining Excel and Visual Basic 6 and Chapt er 22 Using VB.NET and t he Visual St udio Tools for Office t hat t he Excel developer can use t he best of bot h worlds, by com bining Excel, VB6 and/ or VB.Net in a seam less applicat ion.

The Worksheet as a Declarative Programming Language Consider t he following code:

dSales = 1000 dPrice = 10.99 dRevenue = dSales * dPrice

This code could quit e easily be a few lines of VBA. We give t he variable dSales a value of 1000, t he v ar iable dPrice a value of 10.99 and t hen calculat e t he revenue as sales t im es price. I f we change t he nam es of t he variables and adj ust t he spacing, t he sam e code could also be writ t en as follows:

D1 D2 D3

=1000 =10.99 =D1*D2

This preceding code looks m uch m ore like worksheet cell addresses and form ulas t han lines of VBA code, showing t hat a worksheet is in fact a program m ing language of it s own, if we choose t o t hink of it in t hose t erm s. The I F( ) worksheet funct ion is direct ly equivalent t o t he If...Then...Else VBA st at em ent , and t he j udicious use of circular references and it erat ion can be equivalent t o eit her t he For...Next or Do...Loop st ruct ures. I nst ead of st at ing a set of ope r a t ion s t hat are execut ed line by line, we " program " in t his language by st at ing a set of de cla r a t ion s ( by t yping form ulas and values int o worksheet cells) , in any order we want t o:

"D3 is the product of D1 and D2" "D1 has the value 1000" "D2 has the value 10.99"

To " run" t his program , Excel first exam ines all t he declarat ions and builds a " precedence t ree" t o ident ify which cells depend on t he result s of which ot her cells and t hereby det erm ine t he m ost efficient order in which t he cells m ust be calculat ed. The sam e precedence t ree is also used t o ident ify t he m inim um set of calculat ions t hat m ust be perform ed whenever t he value in a cell is changed. The result is a calculat ion engine t hat is vast ly m ore efficient t han an equivalent VBA program , and one t hat should be used whenever com plex num eric com put at ions are required in our applicat ions. Microsoft Excel ( and ot her spreadsheet program s) is unique am ong applicat ion developm ent plat form s in providing bot h a procedural ( VBA) and a declarat ive ( t he worksheet ) program m ing language. The m ost efficient Excel applicat ion is one t hat m akes appropriat e use of bot h t hese languages. I t is assum ed t he reader of t his book has som e knowledge of Excel and worksheet funct ions, so Chapt er 14 Dat a Manipulat ion Techniques focuses on using advanced worksheet funct ions ( including best - pract ice suggest ions for handling circular references) and Excel's ot her dat aanalysis feat ures.

The Excel Object Model Alt hough t he ot her four com ponent s of t he Excel plat form are invaluable in t he developm ent of applicat ions, it is probably t he richness of t he Excel obj ect m odel t hat provides t he m ost com pelling reason t o base our applicat ion developm ent on Excel. Alm ost everyt hing t hat can be done t hrough t he user int erface can also be done program m at ically by using t he obj ect s in t he Excel obj ect m odelaccessing t he list of num ber form at s and applying a digit al signat ure t o a workbook are perhaps t he m ost not able except ions. The vast array of funct ionalit y exposed by t hese obj ect s m akes highly com plex applicat ions fairly sim ple t o developit becom es m ore an issue of when and how t o efficient ly plug t he funct ionalit y t oget her t han t o develop t he funct ionalit y from scrat ch. This book does not at t em pt t o explore and docum ent all t he backwat ers of t he obj ect m odel, but inst ead m akes cont inual use of t he obj ect s in our applicat ion developm ent .

Structure Through t he course of t his book, we cover bot h t he concept s and det ails of each t opic and apply t hose concept s t o a t im esheet report ing and analysis applicat ion we build. The chapt ers are t herefore arranged approxim at ely in t he order in which we would design and develop an Excel applicat ion: Chapt er 2 discusses t he different st yles of applicat ion we m ight choose t o creat e. Chapt er 3 ident ifies som e general best pract ices for working wit h Excel and VBA, which are followed t hroughout t his book. Chapt er 4 explains how t o design and st ruct ure a worksheet for dat a ent ry. Chapt ers 5 and 6 int roduce t wo specific t ypes of applicat ion, t he add- in and t he dict at or applicat ion, which form t he basis of our t im esheet report ing and analysis suit e. Chapt ers 7 t hrough 13 discuss advanced t echniques for a range of VBA t opics. Chapt ers 14 and 15 explain how t o efficient ly ut ilize Excel's feat ures wit hin an applicat ion t o analyze dat a and present result s. Chapt ers 16 and 17 discuss t echniques for debugging and opt im izing VBA code. Chapt ers 18 t hrough 22 look out side of Excel, first by explaining how t o aut om at e ot her applicat ions, and t hen by explaining how t o int eract wit h Excel using C, Visual Basic and VB.Net . Chapt er 23 focuses on how Excel applicat ions can m ake use of t he I nt ernet and XML. Chapt er 24 com plet es t he developm ent by explaining how t o provide help and how t o secure, package and dist ribut e t he applicat ion.

Examples Throughout t he book, we illust rat e t he concept s and t echniques we int roduce by building a t im esheet dat a- ent ry, consolidat ion, analysis and report ing applicat ion. This applicat ion com prises a dat a- ent ry t em plat e t o be com plet ed by each em ployee, wit h t he dat a sent t o a cent ral locat ion for consolidat ion, analysis and report ing. The end of each chapt er present s a fully working exam ple of bot h part s of t he applicat ion included on t he CD, which grows st eadily m ore com plex as t he book progresses and t herefore will be relevant t o different t ypes of com panies. I n Chapt er 4 Worksheet Design, we st art wit h a very sim ple dat a- ent ry workbook and t he assum pt ion t hat each em ployee would e- m ail t he com plet ed file t o a m anager, who would analyze t he result s m anuallya t ypical sit uat ion for a com pany wit h perhaps 10 t o 20 em ployees. By t he end of t he book, t he dat a- ent ry workbook uses XML t o upload t he dat a t o a Web service, where it is st ored in a cent ral dat abase. The report ing applicat ion ext ract s t he dat a from t he dat abase, perform s various analyses and present s t he result s as report s in Excel worksheet s and chart s. Along t he way, we rewrit e som e of t he part s of t he applicat ion in a num ber of different ways, t o show how easy it can be t o include ot her languages and delivery m echanism s in our Excel- based applicat ions. Each chapt er m ay also include specific exam ples t o illust rat e key point s t hat it would be t oo art ificial t o include in our m ain applicat ion.

Supported Versions When developing an Excel applicat ion for a client , t heir upgrade policy will usually det erm ine which version of Excel we m ust use; very few client s will agree t o upgrade t heir deskt ops j ust so we can develop using t he lat est version, unless t here is a com pelling business requirem ent t hat can only be sat isfied by using feat ures t hat t he lat est version int roduces. There is so lit t le difference bet ween Excel 2000 and Excel 2003 t hat it is hard t o im agine such a business requirem ent . An ext rem ely unscient ific poll ( based on post ings t o t he Microsoft support newsgroups) seem s t o indicat e t he following approxim at e usage for each version: Excel 97

10%

Excel 2000

45%

Excel 2002

40%

Excel 2003

5%

There were a num ber of significant changes bet ween Excel 97 and Excel 2000 for t he applicat ion developer, including t he swit ch from VBA5 t o VBA6 and t he int roduct ion of m odeless userform s, int erfaces, COM Add- ins and support for ADO. We have t herefore decided t o use Excel 2000 as our lowest support ed version and developm ent plat form , wit h our applicat ions t est ed in t he lat er versions. Most of t he concept s det ailed in t his book apply equally t o Excel 97, but our exam ple t im esheet applicat ion uses feat ures Excel 97 does not support . Whenever we discuss a feat ure

Typefaces The following t ext st yles are used in t his book: Menu it em s and dialog t ext will be shown as Tools > Opt ions > Calculat ion > Manual, where t he > indicat es navigat ion t o a subm enu or dialog t ab.

Sub SomeCode() 'Code listings are shown like this 'With new or changed lines highlighted like this End Sub

Code wit hin a paragraph is shown as Application.Calculation = xlManual. Pat hs on t he CD are shown as \ Concept s\ Ch11 - I nt erfaces. URLs are shown as ht t p: / / w w w .oalt d.co.uk. I m port ant point s or em phasized words are shown bold and it alic, lik e t h is.

On the CD Most of t he code list ings shown in t his book are also included in exam ple workbooks on t he accom panying CD. For clarit y, t he code shown in t he book uses short er line lengt hs, a reduced indent set t ing, fewer in- code com m ent s and less error handling t han t he corresponding code in t he w or k book s. The CD has t hree m ain direct ories, cont aining t he following files: \ Tools cont ains a num ber of t ools and ut ilit ies developed by t he aut hors t hat we have found t o be invaluable during our applicat ion developm ent . The Must HaveTools.ht m file cont ains det ails about each of t hese t ools and links t o ot her t hird- part y ut ilit ies. \ Concept s has separat e subdirect ories for each chapt er, each one cont aining exam ple files t o support t he t ext of t he chapt er. For best result s, we suggest you have t hese workbooks open while reading t hrough t he corresponding chapt er. \ Applicat ion has separat e subdirect ories for each chapt er, each one cont aining a version of our t im esheet exam ple applicat ion suit e. Beginning wit h Chapt er 4 Worksheet Design, m ost chapt ers end wit h a Pract ical Exam ple sect ion, explaining t he changes t hat have been m ade t o t he t im esheet applicat ion t o im plem ent som e of t he concept s int roduced in t he chapt er.

Help and Support Quest ions about t he book it self ( such as m issing CDs, t ypos, errat a and so on) should be direct ed t o Addison- Wesley, at ht t p: / / w w w .aw pr ofessional.com / cont act us. Any errat a and correct ions will be post ed t o t he Addison- Wesley Web sit e at ht t p: / / w w w .aw pr ofessional.com / t it le/ 0321262506. By far t he best place t o go for help wit h any of your Excel developm ent quest ions, whet her relat ed t o t his book or not , are t he Microsoft support newsgroups' archives m aint ained by Google at ht t p: / / gr oups.google.com . A quick search of t he archives is alm ost cert ain t o find a quest ion sim ilar t o yours, already answered by one of t he m any professional developers who volunt eer t heir t im e helping out in t he newsgroups, including all t hree of t his book's aut hors. On t he rare occasions t hat t he archives fail t o answer your quest ion, you are welcom e t o ask it direct ly in t he newsgroups by connect ing a news reader ( such as Out look Express) t o m snew s.m icr osoft .com and select ing an appropriat e newsgroup, such as t hese: microsoft.public.excel.programming for VBA- relat ed quest ions microsoft.public.excel.worksheet.functions for help wit h worksheet funct ions microsoft.public.vsnet.vstools.office for help wit h Excel/ VB.Net int egrat ion issues microsoft.public.excel.misc for general Excel queries A num ber of Web sit es provide a great deal of inform at ion and free downloadable exam ples and ut ilit ies t arget ed t oward t he Excel developer, including t he following: ht t p: / / w w w .oalt d.co.uk ht t p: / / w w w .appspr o.com ht t p: / / w w w .j - w alk .com ht t p: / / w w w .cpear son.com ht t p: / / m sdn.m icrosoft .com / office

Feedback We have t ried very hard t o present t he inform at ion in t his book in a clear and concise m anner, explaining bot h t he concept s and det ails needed t o get t hings working and providing working exam ples of everyt hing we cover. We have t ried t o provide sufficient inform at ion t o enable you t o apply t hese t echniques in your own applicat ions, but wit hout get t ing bogged down in line- by- line explanat ions of ent ire code list ings. We would like t o t hink we have been successful in our at t em pt , but encourage you t o let us know what you t hink. Const ruct ive crit icism is always welcom e, as are suggest ions for t opics you t hink we m ay have overlooked. Please send an e- m ail t o one ( or all) of t he following: St ephen Bullen: st ephen@oalt d.co.uk Rob Bovey: r obbov ey @appspr o.com John Green: gr eenj @bigpond.net .au

Chapter 2. Application Architectures One of t he first decisions t o be m ade when st art ing a new proj ect is how t o st ruct ure t he applicat ion. This chapt er explains t he alt ernat ive archit ect ures we can use, t he sit uat ions where each is m ost applicable, and t he pros and cons of each choice.

Concepts The choice of where t o put t he code for an Excel applicat ion is rarely st raight forward. I n anyt hing but t he sim plest of sit uat ions, it is a considered t rade- off bet ween num erous fact ors, including t he follow ing: Com ple x it y How easy will t he chosen archit ect ure be t o creat e? Cla r it y How easy will it be for som eone ot her t han t he aut hor t o underst and t he applicat ion? D e ve lopm e n t How easy will it be t o m odify t he code, part icularly in a t eam environm ent ? Fle x ibilit y How easy is it t o add new feat ures? Re lia bilit y Can t he result s be relied upon? How easily can calculat ion errors be int roduced int o t he applicat ion? Robu st n e ss How well will t he applicat ion be able t o handle applicat ion errors, invalid dat a, and so fort h? Se cu r it y How easy will it be t o prevent unaut horized changes t o t he applicat ion? D e ploy m e n t How easy will it be t o dist ribut e t he applicat ion t o t he end user? Upda t e s How easy will it be t o updat e t he applicat ion aft er it has been dist ribut ed and st art ed t o be used? One of t he m ost fundam ent al t enet s of applicat ion design is t hat t he " program " elem ent s of t he applicat ion m ust be physically separat e from t he " dat a" it works on.

Codeless Applications The m ost basic applicat ion is one t hat only uses Excel's built - in funct ionalit y. Everybody creat es t his t ype of applicat ion wit hout knowing it , sim ply by using Excel. They are t ypically creat ed by beginning t o int erm ediat e Excel users who have not yet learned t o use VBA. All t he special form at t ing, validat ion, form ulas and so on are placed direct ly on t he sam e worksheet where dat a ent ry will be perform ed. There are som e m aj or issues wit h t his approach, which t oget her m ean t ot ally codeless applicat ions are rarely a good choice. Those who avoid using VBA m ay find t hat som e of t heir worksheet funct ions and dat a- validat ion crit eria get ext rem ely com plex and alm ost incom prehensible t o anyone ot her t han t he aut hor. The equivalent VBA will oft en be easier t o underst and. The sam e worksheet is usually used for dat a ent ry, analysis, and present at ion, oft en result ing in a clut t ered appearance ( usually wit h m ult it udes of different ly colored cells t o t ry t o ident ify t heir purpose) t hat is difficult t o underst and, is unint uit ive t o use and is alm ost im possible for anyone except t he aut hor t o m odify reliably.

Such applicat ions have t o rely on Excel's cell prot ect ion and password- prot ect ing t he worksheet t o prevent t he users m aking unaut horized changes t o t he form ulas, validat ion, form at t ing and so on. Worksheet passwords are not oriously easy t o break, and a sim ple copy and past e will wipe out any dat a validat ion t hat has been set up. These applicat ions are t herefore neit her secure nor robust . Wit hout any code, we are unable t o provide m uch assist ance t o t he user; we have t o rely on t hem t o do everyt hing t hem selvesand do it correct lyinst ead of providing reliable helper rout ines t hat aut om at e som e of t heir t asks. The m ore com plex t he applicat ion, t he less likely it is t hat all t he t asks will be perform ed correct ly. I f we consider a definit ion of what const it ut es a " program " t o be " anyt hing t hat isn't t he dat a," we see t hat all t he condit ional form at t ing, dat a validat ion, worksheet funct ions and so fort h are really part of t he " program ," so t hese applicat ions break t he basic t enet of keeping t he program and dat a physically separat e. Aft er t he end users have st art ed t o ent er dat a int o t heir worksheet , it is very difficult t o dist ribut e an updat ed worksheet t o t hem , wit hout losing t he dat a t hey have already ent ered. I n addit ion t o t he new version of t he worksheet , you would have t o eit her provide clear inst ruct ions explaining how t o copy t heir dat a across or writ e a conversion program t hat will copy t heir dat a from t he old t o t he new workbook. Codeless applicat ions are ideal for sim ple sit uat ions where m ost of t he following condit ions apply: There will only be one copy of t he workbook ( so any changes can be done direct ly t o t hat workbook) , or each copy of t he workbook will have a short lifet im e, such as a survey or dat acollect ion form t hat can be forgot t en about aft er it has been com plet ed and ret urned. I n each case, t he assum pt ion is t hat t he workbooks will not need up dat ing aft er t hey have been deploy ed. The end users will be m aint aining t he workbook t hem selves ( and don't know VBA) , or t he workbook will not require any m aint enance at all. The workbook m ight be copied and updat ed on different m achines ( alt hough only one at a t im e) , such as when t he workbook is t aken hom e for t he weekendbecause it is self- cont ained, it can easily be copied t o a floppy disk or e- m ailed. There are relat ively few rout ine or com plex t asks t o be perform ed t o m aint ain or analyze t he dat a. There are only a sm all num ber of end users, who can be well t rained t o ensure t he applicat ion is used correct ly and is not inadvert ent ly broken. A good exam ple of a codeless applicat ion is a sim ple survey or dat a- collect ion form t hat requires t he end user t o fill in t he det ails and e- m ail t he com plet ed workbook t o a cent ral address for consolidat ion and analysis. The m ain benefit of a codeless applicat ion in such a sit uat ion is t he avoidance of Excel's m acro securit y warnings and t he corresponding assurance t hat t here is not hing m alicious in t he file.

Self-Automated Workbooks A self- aut om at ed workbook is one in which t he VBA code is physically cont ained wit hin t he workbook it act s upon. Probably t he m ost com m on t ype of applicat ion, t he aut om at ion code can be

as sim ple as ensuring t he workbook always opens wit h Sheet 1 act ive or be as com plex as an ent ire applicat ion. This is usually t he first t ype of applicat ion a beginning VBA developer produces, built by adding num erous helper rout ines t o t he workbook t hat get progressively m ore com plex ( and usually cum bersom e) over t im e. Aft er VBA is int roduced t o t he workbook, we have m uch m ore flexibilit y in providing t he required funct ionalit y and can m ake a considered choice whet her t o use Excel's built - in funct ions or writ e our own equivalent s t o avoid som e of Excel's pit falls. For exam ple, Excel's dat a validat ion m ight not fire correct ly when ent ries are m ade in m ult iple cells at t he sam e t im e and is usually cleared when dat a is past ed ont o t he range. We can work around bot h t hese lim it at ions by t rapping t he Worksheet _Change event and perform ing our own validat ion in code, m aking t he worksheet m ore robust , reliable, and secure. The workbook and worksheet code m odules are provided for us by Excel t o hook whichever event s we want t o use, and any Act iveX cont rols we add t o t he worksheet are aut om at ically exposed in t he sam e code m odule. This is t he sim plest archit ect ure t o creat e and probably t he sim plest t o underst andm ost VBA developers will have writ t en an applicat ion of t his t ype and will t herefore underst and, for exam ple, how t he code wit hin t he worksheet code m odule is t riggered. The clearest advant age t his st yle of applicat ion has over all t he ot hers is in t he ease of deploym ent . There is only one filet he workbookt o dist ribut e; t here is no need t o inst all or configure anyt hing; and because t he code is physically st ored wit hin t he workbook, it is im m ediat ely available and working as soon as t he workbook is opened. Unfort unat ely, t he self- aut om at ed workbook's clearest advant age is also it s biggest problem . Because t he code is physically inside t he workbook, how do you issue updat es t o t he code wit hout affect ing t he dat a t hat has been ent ered on t he worksheet s? Alt hough it is possible t o writ e VBA t hat m odifies t he code wit hin anot her workbook, t he user has t o specifically allow t hat t o happen ( in Excel 2002 and above) , and it is only possible t o unprot ect and reprot ect t he VBA proj ect using SendKeys, which cannot be relied on t o work in foreign- language versions of Excel or if Excel does not have t he focus. Even if t he proj ect could be unprot ect ed and reprot ect ed, saving t he updat ed proj ect would rem ove any digit al signat ure t hat had been applied, result ing in m acro virus warnings every t im e t he workbook was subsequent ly opened. The only reliable way self- aut om at ed workbooks can be updat ed is t o provide a com plet ely new workbook wit h a rout ine ( or inst ruct ions) t o copy t he dat a from t he old workbook. Self- aut om at ed workbooks are an ideal choice if t he following condit ions apply: The rout ines cont ained wit hin t he workbook provide specific funct ionalit y for t hat workbook ( as opposed t o general- purpose ut ilit ies) . There will only be one copy of t he workbook ( so any changes can be done direct ly t o t hat workbook) , or The workbook will have a short lifet im e and/ or will be dist ribut ed t o a large ( and m aybe unknown) audience, in which case t he ease of deploym ent becom es a significant considerat ion, and t here is no int ent ion t o dist ribut e any updat es, or The workbook does not cont ain any dat a t hat will need t o be ret ained during an updat e, such as one t hat obt ains it s dat a from an ext ernal dat a source. Codeless and self- aut om at ed workbooks are discussed in m ore det ail in Chapt er 4 Worksheet

Design.

Function and General-Purpose Add-ins An a dd- in is a specific t ype of applicat ion, usually used t o add feat ures t o Excel. The worksheet s in an add- in are hidden from t he user, so t hey never int eract direct ly wit h t he workbook. I nst ead, t he add- in exposes it s rout ines by adding it em s t o Excel's m enus and t oolbars, hooking key com binat ions and/ or exposing funct ions t o be used wit hin a worksheet . The rout ines in an add- in can also be execut ed by t yping t heir fully qualified nam e ( for exam ple, MyAddin.xla! MyRout ine) in t he Tools > Macro > Macros dialog, alt hough t hey do not appear in t he list of available m acros. The rout ines in a general- purpose add- in will always be available t o t he Excel user, so t hey are m ost appropriat e when used for ut ilit y funct ions t hat are designed t o work wit h any file, t ypically using t he ActiveWorkbook, ActiveSheet or Selection obj ect s t o ident ify t he it em s t o operat e on. Care should be t aken t o t idily handle " user error" issues, where t he add- in's rout ines m ay be called from a cont ext in which t hey will not work. For exam ple, if your add- in changes t he case of t he t ext in t he select ed cell, you m ust check t hat t here is a cell select ed ( and not a drawing obj ect , for exam ple) , it isn't locked and it isn't t he result of a form ula. Sim ilarly, if your code applies som e cust om form at t ing t o t he act ive worksheet , you m ust check t hat t here is an act ive sheet ( because t here m ay be no workbooks open) , it is a worksheet ( and not a chart or m acro sheet ) and it is not pr ot ect ed. An add- in is j ust a very hidden workbook, so it doesn't appear in t he list of workbooks or t he VBA Workbooks collect ion, and it s m acros are not list ed in t he Tools > Macro > Macros dialog. I t is, however, j ust like any ot her workbook in alm ost every ot her way and should t herefore be very easy for an int erm ediat e Excel/ VBA developer t o underst and and m aint ain. I ndeed, you can t oggle bet ween having t he workbook behave like an add- in or not by j ust changing t he I sAddin propert y of t he ThisWorkbook obj ect in t he VBE's Propert ies window. Because add- ins never expose t heir worksheet s t o t he user, all t he user int eract ion is done t hrough userform s ( alt hough VBA's InputBox and MsgBox funct ions can be used in sim ple sit uat ions) . This gives us a high level of cont rol over t he user's ent ries, enabling us t o creat e applicat ions t hat are t ot ally robust and reliableassum ing we include dat a- validat ion code and good error handling. I f t he add- in needs t o st ore any inform at ion, such as rem em bering a user's choices, t hat inform at ion should be kept separat e from t he add- in file, by st oring it eit her in t he regist ry ( using SaveSetting/ GetSetting) or in a separat e file ( such as an I NI file) . I f t hat is done, t he add- in will never need t o be saved by t he end user and can be sim ply replaced by a new version if an updat e is required. I f you are willing t o t rust t he end user t o inst all t he add- in correct ly, it is also very easy t o deployj ust send t he XLA file wit h inst ruct ions t o eit her copy it t o t heir Library folder or t o use t he Browse but t on in t he Tools > Add- ins dialog t o locat e t he file. The alt ernat ive is t o use an inst allat ion rout ine t o writ e t he required regist ry ent ries Excel uses t o m aint ain it s add- ins list , such t hat t he add- in is aut om at ically opened and inst alled when t he client next st art s Excel. These regist ry ent ries are covered in det ail in Chapt er 24 Proving Help, Securing, Packaging and Dist ribut ing.

Structure of a Function or General-Purpose Add-in

Most general- purpose add- ins use t he sam e st ruct ure: Code in an Aut o_Open or Workbook_Open rout ine t hat adds t he add- in's m enu it em s and set s up t he keyboard hooks. Each m enu it em has it s OnAct ion propert y set t o call t he appropriat e rout ine in t he add- in file. Separat e rout ines for each m enu it em , locat ed in a st andard m odule. Public funct ions, locat ed in a st andard m odule, exposed for use in worksheet form ulas. Dedicat ed funct ion add- ins oft en cont ain only funct ions and do not add m enu it em s. Code in an Aut o_Close or Workbook_Close rout ine t hat rem oves t he add- in's m enu it em s and clears t he keyboard hooks.

Application-Specific Add-ins As m ent ioned previously, t he m ain problem wit h bot h codeless and self- aut om at ed workbooks is t hat t he " program " is physically st ored in t he sam e file as t he dat a t he end user t ypes in or ot herwise works wit h. I t is very difficult t o reliably updat e t he program part of t hose workbooks wit hout affect ing or in m ost cases dest roying t he end- user's work. The alt ernat ive is t o st ruct ure t he applicat ion such t hat all t he code is cont ained wit hin one workbook, wit h a separat e workbook for t he end user t o use for dat a ent ry, analysis, and so fort h. One such archit ect ure is t hat of an applicat ion- specific add- in. These are very sim ilar t o norm al add- ins, but inst ead of im m ediat ely set t ing up t heir m enu it em s, keyboard hooks, and so on, t hey st ay invisible unt il t he user opens a workbook t he add- in can ident ify as one for which it should m ake it self available. Typically, t he user would be supplied wit h at least t wo workbookst he XLA add- in workbook and a t em plat e workbook t o use for dat a ent ry. The t em plat e workbook( s) will cont ain som e kind of indicat or t he add- in can use t o ident ify it , usually eit her a hidden defined nam e or a cust om docum ent propert y. The key benefit of using an applicat ion- specific add- in is t hat we can safely dist ribut e updat es t o t he code, knowing we will not be dest roying t he user's dat a. There is, however, a sm all price t o pay for t his convenience: Split t ing t he applicat ion int o t wo ( or m ore) workbooks m akes it slight ly harder t o m anage, because we have t o keep t he correct versions of bot h workbooks synchronized during t he developm ent process. Sim ple version cont rol is discussed in m ore det ail in Chapt er 3 Excel and VBA Developm ent Best Pract ices. The applicat ion is slight ly harder for ot her developers t o underst andpart icularly if t hey are used t o single- workbook applicat ions or do not underst and t he t echnique of using class m odules t o hook applicat ion- level event s, as explained in Chapt er 7 Using Class Modules t o Creat e Obj ect s. Deploym ent is m ore com plicat ed because we need t o dist ribut e m ult iple files. Deploym ent st rat egies are discussed in Chapt er 24 Providing Help, Securing, Packaging, and Dist ribut ing.

Structure of an Application-Specific Add-in Applicat ion- specific add- ins are very sim ilar in st ruct ure t o general- purpose add- ins, but wit h ext ra code t o ident ify when t o enable or disable t he m enu it em s: A class m odule used t o t rap t he applicat ion- level event s. Code in an Aut o_Open or Workbook_Open rout ine adds t he add- in's m enu it em s. Each m enu it em has it s OnAct ion propert y set t o call t he appropriat e rout ine in t he add- in file, but t hey are all init ially eit her disabled or hidden. I t t hen creat es an inst ance of t he class m odule and init ializes applicat ion event hooks. Separat e rout ines for each m enu it em , locat ed in a st andard m odule. ( Opt ionally) Public funct ions, locat ed in a st andard m odule, exposed for use in worksheet funct ions. Code in t he class m odule hooks t he applicat ion- level Workbook Act ivat e event , checks whet her t he new workbook has t he correct cust om docum ent propert y, and if so enables t he m enu it em s and set s up t he keyboard hooks. Code in t he class m odule hooks t he applicat ion- level Workbook Deact ivat e event , disables t he m enu it em s, and rem oves t he keyboard hooks. Code in an Aut o_Close or Workbook_Close rout ine rem oves t he add- in's m enu it em s. General- purpose and Applicat ion- specific add- ins are discussed in m ore det ail in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins.

Dictator Applications All of t he archit ect ures we have considered so far have sought t o enhance Excel in som e way t o im prove t he end user's experience when using our applicat ion. I n cont rast , dict a t or a pplica t ion s seek t o com plet ely t ake over t he Excel user int erface, replacing Excel's m enus wit h t heir own and exercising a very high level of cont rol over t he user. I n t he ideal dict at or applicat ion, users cannot t ell t hey are inside Excel. These applicat ions are creat ed in Excel t o use t he feat ures Excel provides, but t hose feat ures are ent irely cont rolled by t he applicat ion and rarely ( if ever) exposed t o t he user. I nst ead, t he user int erface is m ade up of t ight ly cont rolled dat a- ent ry worksheet s and/ or userform s, designed t o appear like any ot her Windows applicat ion. These applicat ions t ypically require large am ount s of code t o be able t o have t hat level of cont rol, but t hat degree of cont rol enables us t o writ e fullscale, fully funct ional Windows applicat ions, on a par wit h any t hat can be writ t en in Visual Basic or ot her " m ainst ream " applicat ion- developm ent plat form s. I ndeed, by building our applicat ion wit hin Excel, we are im m ediat ely able t o ut ilize t he incredible am ount of funct ionalit y Excel provides. I f t here is a requirem ent for our dict at or applicat ions t o work in Excel 97, we are not able t o have userform s and m enu it em s available at t he sam e t im e, because userform s are always m odal. We t herefore have t he choice t o base our user int erface on using worksheet s and m enus, using userform s wit h but t ons t o navigat e bet ween t he form s or by building m odeless form s using VB6.

Excel 2000 int roduced m odeless userform s, enabling us t o m ake bot h userform s and m enus available and allowing us m uch m ore flexibilit y when deciding whet her t o use a form or worksheet for t he user int erface. For t his reason, we recom m end t hat , if possible, Excel 2000 should be set as t he lowest - level version dict at or applicat ions are designed t o work wit hin. As dict at or applicat ions get m ore and m ore com plex, t hey will oft en st art t o use funct ionalit y t hat only exist s in t he m ost recent versions of Excel ( such as t he XML im port / export int roduced in Excel 2003) , so youas t he designer of t he applicat ionneed t o decide what should happen if t he applicat ion is opened in an older version. I f t he funct ionalit y being used is a core part of t he applicat ion, it is unlikely t he applicat ion will be usable at all in older versions. I f t he use of t he new feat ures can be lim it ed t o a sm all part of t he applicat ion, it m ight m ake m ore sense t o j ust disable t hat m enu it em , or provide separat e rout ines for older versions t o use. Making use of new Excel feat ures will oft en result in com pile errors if t he workbook were t o be opened in an older version, so m any dict at or applicat ions use a " front - loader" workbook t o do an init ial version check, check whet her all ext ernal dependencies ( such as Out look) are available, and t hen open and run t he m ain applicat ion workbook if all t he checks are okay. I f t he checks fail, we can provide m eaningful error m essages t o t he end user ( such as " This applicat ion requires Excel 2000 or above and will not work in Excel 97" ) . There's no escaping t he fact t hat dict at or applicat ions are m uch m ore com plicat ed t han eit her selfaut om at ed workbooks or applicat ion- specific add- ins and will require an int erm ediat e t o advancedlevel Excel/ VBA developer t o creat e and m aint ain t hem . Alt hough t his t ype of archit ect ure can get very com plicat ed, t he com plexit y can be m it igat ed by following t he best - pract ices advice discussed in Chapt er 3 Excel and VBA Developm ent Best Pract ices ( general advice) and Chapt er 6 Dict at or Applicat ions ( specific advice for dict at or applicat ions) . Aft er t he decision t o build a dict at or applicat ion has been m ade, we have an incredible am ount of flexibilit y in t erm s of physically creat ing t he applicat ion. The dat a could be st ored in one or m ore separat e workbooks, local dat abases ( for exam ple, Access dat abases) , or a cent ral dat abase ( for exam ple, SQL Server) . We could decide t o include all t he code in a single workbook or have a sm all " core" add- in, wit h num erous lit t le applet s t hat plug in t o t he core t o provide t he funct ionalit y, where each applet perform s a single, specific t ask. The decision will probably be a t rade- off bet ween ( at least ) t he following considerat ions: A single- workbook st ruct ure is easier for a single developer t o m aint ain, because everyt hing is in t he one place. A m ult iple- workbook st ruct ure is easier for a t eam of developers t o creat e, because each developer can work on his own applet wit hout conflict ing wit h anot her t eam m em ber. I f a m ult iple- workbook st ruct ure is built so each plug- in applet is not loaded unt il it is first used, t he init ial opening of t he core add- in will be quicker t han loading t he full applicat ion of t he single- workbook st ruct urealt hough m odern PCs m ight m ake t hat difference appear im m at er ial. A single- workbook st ruct ure m ust be updat ed in it s ent iret y, but t he applet s of a m ult ipleworkbook st ruct ure can be updat ed and deployed independent ly. The code required t o im plem ent a m ult iple- workbook plug- in archit ect ure is quit e com plex, and m ight be t oo com plex for t he int erm ediat e VBA developer t o fully underst andalt hough we explain it in Chapt er 11 I nt erfaces.

Requirements of a Dictator Application To look and operat e like a st andalone Windows applicat ion, a dict at or applicat ion needs t o m odify m any Application propert ies, from t urning on IgnoreOtherApplications ( so double- clicking an XLS file in Explorer will not use our inst ance of Excel) t o t urning off ShowWindowsInTaskBar in Excel 2000 and above ( because we m ay have m ult iple workbooks t o be m anaged under program cont rol) , as well as hiding all t he com m and bars. Unfort unat ely, Excel will rem em ber m any of t hose set t ings, t o reuse t hem t he next t im e Excel is st art ed, so every dict at or applicat ion m ust st art by recording t he exist ing st at e of all t he set t ings t hat will be changed and rest ore t hem all when it closes. I f t he code t o do t his is writ t en as t wo separat e rout ines and assigned short cut keys, t hey also provide an easy way t o swit ch bet ween t he applicat ion's display and Excel's during developm ent . Aft er a snapshot of t he user's set t ings has been t aken, t he dict at or applicat ion can set t he applicat ion propert ies it requires; it t hen needs t o lock down Excel t o prevent users from doing t hings we do not want t hem t o do, including t he following: Hiding and disabling all t he com m and bars ( including t he short cut com m and bars) , t hen set t ing up our own. Prot ect ing our com m and bars and disabling access t o t he com m and bar cust om izat ion dialog. Disabling all t he short cut key com binat ions t hat Excel provides, and t hen opt ionally reenabling t he few we want t o be exposed t o t he user. Set t ing Application.EnableCancelKey t o xlDisabled at t he st art of every ent ry point , t o prevent users st opping t he code. When using worksheet s as dat a- ent ry form s, we don't want t he user t o be able t o copy and past e ent ire cells, because t hat includes t he form at t ing, dat a validat ion, and so on. Therefore we need t o t urn off drag and drop ( which does a cut and past e) ; t rap bot h Ct rl+ X and Shift + Delet e t o do a copy rat her t han a cut ; and t rap Ct rl+ V, Shift + I nsert , and t he Ent er keys t o ensure we only ever past e values. Having locked down t he Excel environm ent while our applicat ion is running, we need t o provide a m echanism for t he developers t o access t he code, t o enable t hem t o debug t he applicat ion. One m et hod is t o set a global I sDevMode Boolean variable t o True if a part icular file exist s in t he applicat ion direct ory or ( m ore securely) depending on t he Windows usernam e. This Boolean can t hen be used t hroughout t he applicat ion t o provide access point s, such as enabling t he Alt + F11 short cut t o swit ch t o t he VBE, adding a Reset m enu it em and/ or short cut key t o swit ch back t o t he Excel environm ent and not set t ing t he EnableCancelKey propert y, t o allow t he developer t o break int o t he code. The Boolean can also be used wit hin error handlers, t o cont rol whet her t o display a user- or developer- orient ed error m essage.

Structure of a Dictator Application A t ypical dict at or applicat ion uses t he following logical st ruct ure: A front - loader/ st art up rout ine t o perform version and dependency checks and so on

A m ain " core" set of rout ines, t o do t he following: Take a snapshot of t he Excel environm ent set t ings and t o rest ore t hose set t ings Configure and lock down t he Excel applicat ion Creat e and rem ove t he applicat ion's com m and bars Handle copying and past ing dat a wit hin t he worksheet t em plat es Provide a library of com m on helper rout ines and classes ( Opt ionally) I m plem ent a plug- in archit ect ure using class m odules, as described in Chapt er 11 I nt erfaces A backdrop worksheet , t o display wit hin t he Excel window while userform s are being shown, usually wit h som e form of applicat ion- specific logo ( if we are prim arily using form s for t he user int erface) Mult iple independent applet s t hat provide t he applicat ion's funct ionalit y Mult iple t em plat e worksheet s used by t he applet s, such as dat a- ent ry form s or preform at t ed report t em plat es Physically, all t he elem ent s t hat m ake up a t ypical dict at or applicat ion can reside in a single workbook or can be dist ribut ed across m ult iple workbooks. Dict at or applicat ions are discussed in m ore det ail in Chapt er 6 Dict at or Applicat ions.

Technical Implementations I n our discussion of t he m ain t ypes of applicat ion archit ect ure, an underlying assum pt ion is t hat t he applicat ion will be writ t en using VBA. That need not be t he case, however, as we discuss in Chapt ers 19 t hrough 22 , where we exam ine how we can use t he C API t o creat e XLL add- ins and use Visual Basic 6 and/ or VB.Net t o support our VBA rout ines and creat e COM Add- ins. Addit ionally, any of t hese archit ect ures can be im plem ent ed using a t radit ional procedural design ( where m ost of t he funct ionalit y is im plem ent ed using helper rout ines in st andard code m odules) or an obj ect - orient ed approach ( where t he funct ionalit y is im plem ent ed as propert ies and m et hods of class m odules) , as discussed in Chapt er 7 Using Class Modules t o Creat e Obj ect s.

Conclusion The five m ain t ypes of applicat ion archit ect ure have t heir pros and cons, and each is t he m ost applicable for cert ain sit uat ions. The choice of archit ect ure should be t aken carefully, wit h appropriat e considerat ion given t o t he ongoing m aint enance ( probably by a different person t han t he original aut hor) as well as j ust t he ease wit h which t he applicat ion can be creat ed init ially. St yle

Pr os

Co n s

Applica ble For

Codeless

No VBA requirem ent .

Usually clut t ered and hard t o use.

Sim ple dat a- ent ry form s, surveys and so on.

No m acro securit y issues. Easy t o deploy.

Neit her robust nor r eliable. Unable t o provide m uch assist ance t o t he user. Difficult t o updat e.

Selfaut om at ed

Sim ple applicat ion, easy for a beginner VBA developer t o underst and.

I f t he VBA needs t o be updat ed, it will be difficult or im possible t o do so once deployed.

VBA can be used t o im prove robust ness and r eliabilit y .

More com plex dat a- ent ry form s, where t he VBA can be used t o im prove t he qualit y of t he dat a being ent ered, but t here is lit t le dat a st ored in t he workbook long t erm .

Able t o provide lot s of ext ra funct ionalit y for t he user. Easy t o deploy. General addin

Designed t o ext end Excel's Must include robust funct ionalit y. cont ext checks and error handling. Sim ple applicat ion, only Harder t o deploy if it slight ly m ore com plex t han an aut om at ed should be aut om at ically w or k book . ready for use.

I deal for adding ext ra funct ionalit y t o Excel, for use in any workbook.

Easy t o deploy ( alt hough not as sim ple as a w or k book ) . App- specific add- in

Separat es t he code from t he dat a, so t he code can be updat ed wit hout

Slight ly m ore t echnically com plex t han t he general add- in, requires an

This is t he recom m ended st ruct ure t o use for an applicat ion t hat adds t o

St yle

Pr be os updat ed wit hout affect ing t he user's work. Rem oving t he code from t he dat a workbooks m akes t hem sm aller and avoids t he m acro securit y w ar ning.

Dict at or applicat ion

Able t o writ e fully funct ional applicat ions t hat appear t o be applicat ions in t heir own r ight . High degree of cont rol over t he user int eract ion enables us t o writ e very robust and reliable applicat ions. Funct ionalit y can be split over m ult iple workbooks, m aking t hem easier for a t eam t o develop and easier t o deploy updat es.

Co n sin, requires an addint erm ediat e- level VBA dev eloper .

Applica ble t For applicat ion hat adds t o Excel's m enus.

Slight ly harder t o deploy, because it requires at least t wo workbooks t o be inst alled, som et im es t o separat e locat ions. Much m ore com plex t han ot her archit ect ures. Care m ust be t aken t o rest ore t he user's Excel envir onm ent Harder t o deploy, t ypically requiring an inst allat ion r out ine.

The ideal m et hod for a Windows applicat ion t hat m akes heavy use of t he funct ionalit y t hat Excel pr ov ides.

Chapter 3. Excel and VBA Development Best Practices This chapt er appears early in t he book because we want you t o underst and why we are doing cert ain t hings t he way we are in lat er chapt ers. Unfort unat ely, t his also m eans we m ust cover a few t opics in t his chapt er t hat do not get full coverage unt il lat er. For best result s, you m ight want t o review t his chapt er aft er you have read t he rest of t he book. As you read t his chapt er, keep in m ind t hat even t hough t he pract ices described here are generally accept ed best pract ices, t here will always be cert ain cases where t he best t hing t o do is not follow t he best pract ice. We t ry t o point out t he m ost com m on exam ples of t his here and in t he best pract ices discussions in t he chapt ers t hat follow.

Naming Conventions What Is a Naming Convention and Why Is It Important The t erm n a m in g con ve n t ion refers t o t he syst em you use t o nam e t he various part s of your applicat ion. Whenever you declare a variable or creat e a userform , you give it a nam e. You im plicit ly nam e obj ect s even when you do not give t hem a nam e direct ly by accept ing t he default nam e provided when you creat e a userform , for exam ple. One of t he hallm arks of good program m ing pract ice is t he consist ent use of a clearly defined nam ing convent ion for all part s of your VBA applicat ion. Let 's look at an exam ple t hat m ay help dem onst rat e why nam ing convent ions m at t er. I n t he following line of code, what do you know about x?

x = wksDataSheet.Range("A1").Value

From it s usage you can reasonably assum e it is a variable. But what dat a t ype is it designed t o hold? I s it s scope public, m odule level, or privat e? What is it s purpose in t he program ? As it st ands, you cannot answer any of t hese quest ions wit hout spending som e t im e searching t hrough t he rest of t he code. A good nam ing convent ion conveys t he answers t o t hese quest ions wit h a sim ple visual inspect ion of t he variable nam e. Here's a revised exam ple. ( We cover t he specifics in det ail in t he next sect ion.)

glListCount = wksDataSheet.Range("A1").Value

Now you know t he scope of t he variable ( g st ands for global or public scope) , what dat a t ype it was designed t o hold ( l st ands for t he Long dat a t ype) and have a rough idea of t he purpose of t he variable ( it holds t he num ber of it em s in a list ) . A nam ing convent ion helps you t o im m ediat ely recognize t he t ype and purpose of t he building blocks used in an applicat ion. This enables you t o concent rat e on what t he code is doing rat her t han having t o figure out how t he code is st ruct ured. Nam ing convent ions also help m ake your code self- docum ent ing, reducing t he num ber of com m ent s required t o m ake t he purpose of your code clear . We present an exam ple of a well- st ruct ured nam ing convent ion in t he following sect ion. However, t he m ost im port ant t hing about nam ing convent ions is t hat you pick one and use it consist ent ly. As long as everyone involved in a proj ect underst ands t he nam ing convent ion, it doesn't really m at t er exact ly what prefixes you use or how your nam es are capit alized. When it com es t o nam ing

convent ions, consist ency rules, bot h across proj ect s and over t im e.

A Sample Naming Convention A good nam ing convent ion applies not j ust t o variables, but t o all t he elem ent s of your applicat ion. The sam ple nam ing convent ion we present here covers all t he elem ent s in a t ypical Excel applicat ion. We begin wit h a discussion of variables, const ant s and relat ed elem ent s, because t hese are t he m ost com m on elem ent s in any applicat ion. Table 3- 1 shows t he general form at of t he nam ing convent ion. The specific elem ent s of t he nam ing convent ion and t heir purposes are described aft erward.

Ta ble 3 - 1 . A N a m in g Con ve n t ion for Va r ia ble s, Con st a n t s, Use r - D e fin e d Type s a n d En u m e r a t ion s Ele m e n t

N a m in g Con ve n t ion

Var iables

DESCRIPTIVE_NAME

User- defined t ypes Type DESCRIPTIVE_NAME DescriptiveName End Type

Enum er at ions Enum GeneralDescr GeneralDescrSpecificName1 GeneralDescrSpecificName2 End Enum

The Scope Specifier () g Public m Module level ( not hing) Procedure level

The Array Specifier ()

a Array ( not hing) Not an array

The Data Type Specifier () There are so m any dat a t ypes t hat it 's difficult t o provide a com prehensive list of prefixes t o represent t hem . The built - in t ypes are easy. The m ost frequent ly used built - in t ypes get t he short est prefixes. Problem s arise when nam ing obj ect variables t hat refer t o obj ect s from various applicat ions. Som e program m ers use t he prefix obj for all obj ect nam es. This is not accept able. However, devising consist ent , unique and reasonably short prefixes for every obj ect t ype you will ever use is also probably t oo m uch t o ask. Try t o find reasonably m eaningful one- t o t hree- let t er prefixes for t he obj ect variables you use m ost frequent ly and reserve t he obj prefix for obj ect s t hat appear infrequent ly in your code. Make your code clear, and above all, be consist ent . Keep dat a t ype prefixes t o t hree charact ers or fewer. Longer prefixes, in com binat ion wit h scope and array specifiers, m ake for unwieldy variable nam es. Table 3- 2 shows som e suggest ed prefixes for t he m ost com m only used dat a t ypes.

Ta ble 3 - 2 . Su gge st e d N a m in g Con ve n t ion Pr e fix e s Pr e fix

D a t a Type

Pr e fix

D a t a Type

Pr e fix

D a t a Type

b

Boolean

cm

ADODB.Com m and

cbo

MSFor m s.Com boBox [ * ]

byt

Byt e

cn

ADODB.Connect ion

chk

MSForm s.CheckBox

cur

Cur r ency

rs

ADODB.Recordset

cm d

MSFor m s.Com m andBut t on

dt e

Dat e

ddn

MSFor m s.Com boBox [ * * ]

dec

Decim al

cht

Excel.Char t

fra

MSFor m s.Fr am e

d

Double

rng

Excel.Range

lb l

MSFor m s.Label

i

I nt eger

wkb

Ex cel.Wor k book

lst

MSFor m s.List Box

l

Lon g

wks

Excel.Worksheet

m pg

MSFor m s.Mult iPage

ob j

Obj ect

opt

MSFor m s.Opt ionBut t on

sng

Single

cb r

Office.Com m andBar

spn

MSFor m s.SpinBut t on

s

St r ing

ct l

Office.Com m andBar Cont r ol t xt

u

User defined t ype

MSForm s.Text Box

Pr e fix

D a t a Type

Pr e fix

D a t a Type

v

Var iant

cls

User- defined

frm

Pr e fix

D a t a Type

class variable

ref

RefEdit Cont rol

Userform variable

col

VBA.Collect ion

[*] Used for ComboBox controls with a DropDownCombo Style setting. [**] Used for ComboBox controls with a DropDownList Style setting.

Using Descriptive Names VBA gives you up t o 255 charact ers for each of your variable nam es. Use a few of t hem . Don't t ry t o save yourself a lit t le effort by m aking your variable nam es very short . Doing so will m ake your code difficult t o underst and in t he long run, bot h for you and for anyone else who has t o work on it . The Visual Basic I DE provides an aut o- com plet e feat ure for ident ifiers ( all t he nam es used in your applicat ion) . You t ypically need t o t ype only t he first few charact ers t o get t he nam e you want . Ent er t he first few charact ers of t he nam e and press Ct rl+ Spacebar t o act ivat e an aut o- com plet e list of all nam es t hat begin wit h t hose charact ers. As you t ype addit ional charact ers, t he list will cont inue t o narrow down. I n Figure 3- 1 , t he Ct rl+ Spacebar short cut has been used t o display a list of m essage st ring const ant s available t o add t o a m essage box.

Figu r e 3 - 1 . Usin g t h e Ct r l+ Spa ce ba r Sh or t cu t t o Au t o- Com ple t e Lon g Nam es [View full size image]

A Few Words About Enumerations

Enum erat ions are a special t ype of const ant available in Excel 2000 and higher. They enable you t o t ake a list of relat ed values and package t hem up wit h sim ilar, logical friendly nam es. VBA and t he Excel obj ect m odel m ake ext ensive use of enum erat ions. You can see t hese in t he aut o- com plet e list t hat VBA provides for t he values of m any propert ies. For exam ple if you t ype:

Sheet1.PageSetup.PaperSize

=

int o a VBA m odule, you'll be prom pt ed wit h a long list of XlPaperSize enum erat ion m em bers t hat represent t he paper sizes available t o print on. Figure 3- 2 shows t his in act ion.

Figu r e 3 - 2 . Th e Ex ce l Pa pe r Size En u m e r a t ion M e m be r List [View full size image]

These nam es act ually represent num eric const ant s whose values you can exam ine if you look t hem up in t he Obj ect Browser, discussed in Chapt er 16 VBA Debugging. Not ice t he st ruct ure of t hese enum erat ion nam es. First , t hey all begin wit h a prefix ident ifying t he applicat ion t hey are associat ed wit h, in t his case xl, which obviously st ands for Excel. Second, t he first part of t heir nam e is a descript ive t erm t hat t ies t hem t oget her visually as belonging t o t he sam e enum erat ed t ype, in t his case Paper. The last part of each enum erat ion nam e is a unique st ring describing t he specific value. For exam ple, xlPaper11x17 represent s 11x17 paper and xlPaperA4 represent s A4 paper. This syst em for nam ing enum erat ed const ant s is very com m on and is t he one we use in t his book .

Naming Convention Examples Nam ing convent ion descript ions in t he abst ract are difficult t o connect t o real- world nam es, so we show som e real- world exam ples of our nam ing convent ion in t his sect ion. All of t hese exam ples are t aken direct ly from com m ercial- qualit y applicat ions writ t en by t he aut hors.

Variables gsErrMsg A public variable wit h t he dat a t ype St ring used t o st ore an error m essage mauSettings() A m odule- level array of user- defined t ype t hat holds a list of set t ings cbrMenu A local variable wit h t he dat a t ype Com m andBar t hat holds a reference t o a m enu b ar

Constants gbDEBUG_MODE A public const ant of t ype Boolean t hat indicat es whet her t he proj ect is in debug m ode msCAPTION_FILE_OPEN A m odule- level const ant of dat a t ype St ring t hat holds t he capt ion for a user- defined file open dialog (Application.GetOpenFilename in t his inst ance) lOFFSET_START A local const ant of dat a t ype Long holding t he point at which we begin offset t ing from som e Range obj ect

User-Defined Types The following is a public user- defined t ype t hat is used t o st ore t he dim ensions and locat ion of an obj ect . I t consist s of four variables of dat a t ype Double t hat st ore t he t op, left , widt h and height of t he obj ect and a variable of dat a t ype Boolean used t o indicat e whet her t he set t ings have been saved.

Public Type DIMENSION_SETTINGS bSettingsSaved As Boolean dValTop As Double dValLeft As Double dValHeight As Double dValWidth As Double End Type

The variables wit hin a user- defined t ype definit ion are called m e m be r va r ia ble s. These can be declared in any order. However, our nam ing convent ion suggest s you sort t hem alphabet ically by dat a t ype unless t here is a st rong reason t o group t hem in som e ot her fashion.

Enumerations

The following is a m odule- level enum erat ion used t o describe various t ypes of days. The sch prefix in t he nam e of t he enum erat ion st ands for t he applicat ion nam e. This enum erat ion happens t o com e from an applicat ion called Scheduler. DayType in t he enum erat ion nam e indicat es t he purpose of t he enum erat ion and each of t he individual enum erat ion m em bers has a unique suffix t hat describes what it m eans.

Private Enum schDayType schDayTypeUnscheduled schDayTypeProduction schDayTypeDownTime schDayTypeHoliday End Enum

I f you don't indicat e what values you want t o give your enum erat ion m em bers, VBA aut om at ically assigns a value of zero t o t he first m em ber in t he list and increm ent s t hat value by one for each addit ional m em ber. You can easily override t his behavior and assign a different st art ing point from which VBA will begin increm ent ing. For exam ple, t o m ake t he enum erat ion above begin wit h one inst ead of zero, you would do t he following:

Private Enum schDayType schDayTypeUnscheduled = 1 schDayTypeProduction schDayTypeDownTime schDayTypeHoliday End Enum

VBA will cont inue t o increm ent by one for each m em ber aft er t he last m em ber for which you've specified a value. You can override aut om at ic assignm ent of values t o all of your enum erat ion m em bers by sim ply specifying values for all of t hem . Figure 3- 3 shows one of t he prim ary advant ages of using enum erat ions. VBA provides you wit h an aut o- com plet e list of pot ent ial values for any variable declared as a specific enum erat ion.

Figu r e 3 - 3 . Eve n Cu st om En u m e r a t ion s Ge t a VBA Au t o- Com ple t e List in g

Procedures Subrout ines and funct ions are grouped under t he m ore general t erm pr ocedur e. Always give your procedures very descript ive nam es. Once again, you are allowed up t o 255 charact ers for your procedure nam es, and procedure nam es appear in t he Ct rl+ Spacebar aut o- com plet e list , so don't sacrifice a nam e t hat m akes t he purpose of a procedure obvious for one t hat 's sim ply short . I t is not a com m on pract ice t o do so, but we find t hat giving funct ions a prefix indicat ing t he dat a t ype of t heir ret urn value t o be very helpful in underst anding code. When calling a funct ion, always place open and closed parent hesis aft er t he funct ion nam e t o dist inguish it from a variable or subrout ine nam e, even if t he funct ion t akes no argum ent s. List ing 3- 1 shows a well- nam ed Boolean funct ion being used as t he t est for an If...Then st at em ent .

List in g 3 - 1 . An Ex a m ple of N a m in g Con ve n t ion s for Fu n ct ion N a m e s If bValidatePath("C:\Files") Then ' The If...Then block is executed ' if the specified path exists. End If

Subrout ines should be given a nam e t hat describes t he t ask t hey perform . For exam ple, a subrout ine nam ed Shut downApplicat ion leaves lit t le doubt as t o what it does. Funct ions should be given a nam e t hat describes t he value t hey ret urn. A funct ion nam ed sGet UnusedFilenam e( ) can reasonably be expect ed t o ret urn a filenam e.

The nam ing convent ion applied t o procedure argum ent s is exact ly t he sam e as t he nam ing convent ion for procedure- level variables. For exam ple, t he bValidat ePat h funct ion shown in List ing 3 - 1 would be declared in t he following m anner:

Function bValidatePath(ByVal sPath As String) As Boolean

Modules, Classes and Userforms I n our sam ple nam ing convent ion, t he nam es of st andard code m odules should be prefixed wit h an uppercase M, class m odules wit h an uppercase C and userform s wit h an upper case F. This has t he advant age of neat ly sort ing t hese obj ect s in t he VBE Proj ect window if you don't care for t he folder view, as shown in Figure 3- 4 .

Figu r e 3 - 4 . Cla ss M odu le s, Use r for m s a n d St a n da r d M odu le s Sor t e d in t h e Pr oj e ct W in dow

This convent ion also m akes code t hat uses classes and userform obj ect s m uch clearer. I n t he following code sam ple, for exam ple, t his nam ing convent ion m akes it very clear t hat you are

declaring an obj ect variable of a cert ain class t ype and t hen creat ing a new inst ance of t hat class:

Dim clsMyClass As CMyClass Set clsMyClass = New CMyClass

I n each case, t he nam e on t he left is a class va r ia ble , and t he obj ect on t he right is a cla ss.

Worksheets and Chart Sheets Because t he CodeNam es of worksheet s and chart sheet s in your proj ect are t reat ed by VBA as int rinsic obj ect variables t hat reference t hose sheet s, t he CodeNam es given t o worksheet s and chart sheet s should follow variable nam ing convent ions. Worksheet CodeNam es are prefixed wit h wks t o ident ify t hem in code as references t o Worksheet obj ect s. Sim ilarly, chart sheet s are prefixed wit h cht t o ident ify t hem as references t o Excel Chart obj ect s. For bot h t ypes of sheet s, t he prefix should be followed by a descript ive t erm indicat ing t he sheet 's purpose in t he applicat ion. Figure 3- 4 , for exam ple, shows a wksCom m andBars worksheet t hat cont ains a t able defining t he com m and bars creat ed by t he applicat ion. For sheet s cont ained wit hin an add- in or hidden in a workbook and not designed t o be seen by t he user, t he sheet t ab nam e should be ident ical t o t he CodeNam e. For sheet s t hat are visible t o t he user, t he sheet t ab nam e should be a friendly nam e, and one t hat you should be prepared for t he user t o change. As discussed lat er, you should always rely on sheet CodeNam es rat her t han sheet t ab nam es wit hin your VBA code.

The Visual Basic Project Not ice in Figure 3- 4 t hat t he Visual Basic Proj ect has been given t he sam e nam e as t he workbook it 's associat ed wit h. You should always give your VBProj ect a nam e t hat clearly ident ifies t he applicat ion it belongs t o. There's not hing worse t han having a group of workbooks open in t he VBE wit h all of t hem having t he sam e default nam e VBAProj ect . I f you plan on creat ing references bet ween proj ect s, you will be required t o give t hem unique nam es.

Excel UI Naming Conventions Excel user int erface elem ent s used in t he creat ion of an applicat ion should also be nam ed using a consist ent and well- defined nam ing convent ion. We covered worksheet s and chart sheet s in a previous sect ion. The t hree ot her m aj or cat egories of Excel UI elem ent s t hat can be nam ed are shapes, em bedded obj ect s and defined nam es.

Shapes The t erm Sh a pe s refers t o t he generic collect ion t hat can cont ain t he wide variet y of obj ect s you

can place on t op of a worksheet or chart sheet . Shapes can be broadly divided int o t hree cat egories: cont rols, drawing obj ect s and em bedded obj ect s. Shapes should be nam ed sim ilarly t o obj ect variables, which is t o say t hey should be given a prefix t hat ident ifies what t ype of obj ect t hey are followed by a descript ive nam e indicat ing what purpose t hey serve in t he applicat ion. Many cont rols t hat can be placed on userform s can be placed on worksheet s as well. Worksheet s can also host t he old Form s t oolbar cont rols, which are sim ilar t o t he Act iveX MSForm s cont rols but wit h t heir own unique advant ages and disadvant ages. Chapt er 4 Worksheet Design discusses t hese in m ore det ail. Cont rols placed on worksheet s should be nam ed using exact ly t he sam e convent ions you would use for cont rols placed on userform s. Worksheet s can also host a wide variet y of drawing obj ect s ( t echnically known as Shapes) t hat are not st rict ly cont rols, alt hough you can assign m acros t o all of t hem . These fall int o t he sam e nam ing convent ion cat egory as t he wide variet y of obj ect s t hat you can use in VBA. I t would be very difficult t o devise unique prefixes for all of t hem , so use well- defined prefixes for t he m ost com m on drawing obj ect s and use a generic prefix for t he rest . Here are som e sam ple prefixes for t hree of t he m ost com m only used drawing obj ect s: p ic

Pict ure

rec

Rect angle

t xt

Text Box ( not t he Act iveX cont r ol)

Embedded Objects The t erm e m be dde d obj e ct is used here t o refer t o Excel obj ect s such as Pivot Tables, QueryTables and Chart Obj ect s, as well as obj ect s creat ed by applicat ions ot her t han Excel. Worksheet s can host a variet y of em bedded obj ect s. Com m on exam ples of non- Excel em bedded obj ect s would include equat ions creat ed wit h t he Equat ion Edit or and WordArt drawings. Sam ple prefixes for em bedded obj ect s are shown here: cht

Char t Obj ect

eqn Equat ion q r y Quer y Table pvt

Piv ot Table

ar t

Wor dAr t

Defined Names Our nam ing convent ion for defined nam es is a bit different t han for ot her program elem ent s. I n t he case of defined nam es, t he prefix should indicat e t he broad purpose of t he defined nam e, as opposed t o t he dat a t ype it 's expect ed t o hold. This is because nont rivial Excel applicat ions t ypically have m any defined nam es t hat are m uch easier t o work wit h if t hey are grouped t oget her by purpose wit hin t he Define Nam e dialog. When a worksheet cont ains dozens or hundreds of defined

nam es, t here are significant efficiencies t o be gained by having nam es wit h relat ed funct ions grouped t oget her by prefix in t he defined nam e list . The descript ive nam e port ion of a defined nam e is used t o specify exact ly what purpose t he nam e serves wit hin it s broader cat egory. The following list shows som e exam ples of purpose prefixes for defined nam es: cht

Chart dat a r ange

con

Nam ed const ant

err

Error check

for

Nam ed for m ula

inp

I nput range

out

Out put range

pt r

Specific cell locat ion

rgn

Region

set

UI set t ing

t bl

Table

ExceptionsWhen Not to Apply the Naming Convention You want t o break t he general rule and not apply your nam ing convent ion in t wo specific sit uat ions. The first is when you are dealing wit h elem ent s relat ed t o Windows API calls. These elem ent s have been nam ed by Microsoft , and t he nam es are well known wit hin t he program m ing com m unit y. The Windows API const ant s, user- defined t ypes, procedure declarat ions and procedure argum ent s should appear in your code exact ly as t hey appear in t he Microsoft Plat form SDK, which can be viewed on t he MSDN Web sit e at : ht t p: / / m sdn.m icr osoft .com / libr ar y / en- us/ w inpr og/ w inpr og/ w indow s_api_st ar t _page.asp Not e t hat t his reference is provided in C/ C+ + form at only. The second sit uat ion where you want t o avoid applying your own nam ing convent ions is when you

Best Practices for Application Structure and Organization Application Structure The One-Workbook vs. the N-Workbook Application The num ber of workbooks used in an Excel applicat ion is driven prim arily by t wo fact ors: t he com plexit y of t he applicat ion it self and t he lim it at ions im posed by applicat ion dist ribut ion issues. Sim ple applicat ions and t hose for which you cannot im pose a form al inst allat ion sequence dem and t he fewest num ber of workbooks. Com plex applicat ions and t hose over which you have com plet e cont rol of t he inst allat ion process allow division int o m ult iple workbooks or ot her file t ypes such as DLLs. Chapt er 2 Applicat ion Archit ect ures discusses t he various t ypes of Excel applicat ions and t he st ruct ure suit ed t o each. When you have t he libert y t o divide your applicat ion across m ult iple files, t here are a num ber of good reasons t o do so. These include separat ion of t he logical t iers in your applicat ion, separat ion of code from dat a, separat ion of user- int erface elem ent s from code elem ent s, encapsulat ing funct ional elem ent s of t he applicat ion and m anaging change conflict s in a t eam developm ent envir onm ent .

Separation of Logical Tiers Alm ost every nont rivial Excel applicat ion has t hree dist inct logical t iers or sect ions: Th e u se r - in t e r fa ce t ie r The user- int erface t ier consist s of all t he code and visible elem ent s required for your applicat ion t o int eract wit h t he user. I n an Excel applicat ion, t he userint erface t ier consist s of visible elem ent s such as worksheet s, chart s, com m and bars, userform s and t he code required t o direct ly m anage t hose visible elem ent s. The user- int erface t ier is t he only logical t ier t hat cont ains elem ent s visible t o t he user. Th e bu sin e ss logic or a pplica t ion t ie r The business logic t ier is com plet ely code based. I t s code perform s t he core operat ions t he applicat ion was designed t o accom plish. The business logic t ier accept s input from t he user- int erface t ier and ret urns out put t o t he user- int erface t ier. For long- running operat ions, t he business logic t ier m ay t ransm it periodic updat es t o t he user- int erface t ier in t he form of st at us bar m essages or progress bar updat es. Th e da t a a cce ss a n d st or a ge t ie r The dat a access and st orage t ier is responsible for t he st orage and ret rieval of dat a required by t he applicat ion. This can be as sim ple as reading from and writ ing dat a t o cells on a local, hidden worksheet or as com plex as execut ing st ored procedures in a SQL Server dat abase across a net work. The dat a access and st orage t ier com m unicat es direct ly only wit h t he business logic t ier.

As Figure 3- 5 shows, all t hree t iers are necessary for a com plet e applicat ion, but t hey m ust not be inext ricably linked. The t hree t iers of your applicat ion should be loosely coupled, such t hat a significant change in one t ier does not require significant changes t o t he ot her t wo. St rongly coupled applicat ion t iers inevit ably lead t o m aint enance and upgrade difficult ies.

Figu r e 3 - 5 . Th e Re la t ion sh ips Am on g t h e Th r e e Tie r s of a n Ex ce l Applica t ion

For exam ple, if your dat a access and st orage t ier needs t o m ove from using an Access dat abase for st orage t o using a SQL Server dat abase for st orage, you want t he changes required t o be isolat ed wit hin t he dat a access and st orage t ier. I n a well- designed applicat ion, neit her of t he ot her t wo t iers would be affect ed in any way by such a change. I deally, dat a should be t ransferred bet ween t he business logic t ier and t he dat a access and st orage t ier in t he form of user- defined t ypes. These provide t he best t rade- off bet ween efficiency and loose coupling. Alt ernat ively, ADO Recordset obj ect s can be used, but t hese int roduce subt le linkage issues t hat it would be bet t er if t he business logic layer didn't rely on, such as t he order of fields ret urned from t he dat abase. Sim ilarly, if you need t o provide an alt ernat e Web- based present at ion int erface for your applicat ion, loose coupling bet ween t he user- int erface t ier and t he business logic t ier will m ake it m uch easier t o accom plish. This is because t here will be no im plicit assum pt ions built in t o t he business logic t ier regarding how t he user int erface is const ruct ed. Elem ent s t hat accept dat a input from t he user should be com plet ely self- cont ained. The business logic t ier should pass t he userint erface t ier t he dat a it requires for init ializat ion as sim ple dat a t ype propert ies. The user- int erface t ier should collect t he user input and pass it back t o t he business logic t ier as sim ple dat a t ype propert ies or as a UDT for m ore com plex int erfaces. Because t he business logic t ier should have no int rinsic knowledge of how t he user- int erface is const ruct ed, referencing cont rols on a userform direct ly from a business logic t ier procedure is expressly forbidden.

Separation of Data/UI from Code Wit hin t he user- int erface t ier of m any Excel applicat ions lie t wo unique subt iers. These consist of t he workbook and sheet elem ent s used t o const ruct t he user- int erface and t he code support ing t hose elem ent s. The concept of separat ion should be applied rigorously t o t hese subt iers. A workbook- based int erface should cont ain no code, and t he UI code t hat cont rols a workbook- based int erface should reside in an add- in com plet ely separat ed from t he workbook it cont rols. The reasoning for t his separat ion is t he sam e as t he reasoning described above for separat ing t he m ain applicat ion t iers, isolat ing t he effect s of change. Of all t he applicat ion t iers, t he user- int erface t ier undergoes t he m ost frequent changes. Therefore it 's not sufficient j ust t o isolat e user int erface

changes t o t he user int erface t ier; you should also isolat e changes t o t he visible elem ent s of t he user int erface from t he code t hat cont rols t he user int erface. We provide real- world exam ples of applicat ion t ier separat ion in t he chapt ers t hat follow, so don't be concerned if what is discussed here is not t ot ally obvious t o you at t his point .

Application Organization for Procedural Programming Procedural program m ing is t he program m ing m et hodology m ost developers are fam iliar wit h. I t involves dividing an applicat ion int o m ult iple procedures, each of which is designed t o perform a specific t ask wit hin t he applicat ion. An ent ire applicat ion can be writ t en in procedural fashion, procedural elem ent s can be com bined wit h obj ect - orient ed elem ent s or an ent ire applicat ion can be writ t en in obj ect - orient ed fashion. This sect ion focuses on best pract ices for procedural program m ing. We discuss obj ect - orient ed program m ing t echniques in Chapt er 7 Using Class Modules t o Creat e Obj ect s.

Organizing Code into Modules by Function/Category The prim ary purpose of separat ing code int o m odules is t o im prove t he com prehensibilit y and m aint ainabilit y of t he applicat ion. I n a procedural applicat ion, procedures should be organized int o separat e code m odules in a logical fashion. The best way t o do t his is t o group procedures t hat perform sim ilar funct ions int o t he sam e code m odule.

TI P VBA has an undocum ent ed " soft lim it " on t he m axim um size of any single st andard code m odule. A st andard code m odule should not exceed 64KB as m easured by it s t ext file size when export ed from t he proj ect . ( The VBETools ut ilit y included on t he CD will report m odule sizes for you aut om at ically.) Your proj ect will not crash im m ediat ely upon a single m odule exceeding t his 64KB lim it , but consist ent ly exceeding t his lim it will alm ost invariably lead t o an unst able applicat ion.

Functional Decomposition Funct ional decom posit ion refers t o t he process of breaking your applicat ion int o separat e procedures such t hat each procedure is responsible for a single t ask. I n t heory, you could writ e m any applicat ions as one huge, m onolit hic procedure. However, doing so would m ake your applicat ion ext rem ely difficult t o debug and m aint ain. By using funct ional decom posit ion, you design your applicat ion such t hat it consist s of m ult iple procedures t hat are each responsible for a well- defined t ask t hat is easy t o underst and, validat e, docum ent and m aint ain.

Best Practices for Creating Procedures

A com prehensive set of guidelines for creat ing good procedures could easily fill a chapt er of it s own. We cover t he m ost im port ant guidelines in t he following list : En ca psu la t ion Whenever possible, a procedure should be designed t o com plet ely encapsulat e t he logical operat ion it perform s. I deally, your procedures should have no linkages t o anyt hing out side of t hem . This m eans, for exam ple, t hat a properly encapsulat ed procedure can be copied int o a com plet ely different proj ect and work j ust as well t here as it did in t he proj ect where it originat ed. Encapsulat ion prom ot es code reuse and sim plifies debugging by isolat ing different logical operat ions from each ot her. Elim in a t ion of du plica t e code When writ ing a nont rivial Excel applicat ion, you will frequent ly discover you are writ ing code t o perform t he sam e operat ion in m ult iple places. When t his occurs, you should fact or t his duplicat ed code out int o a separat e procedure. Doing so reduces t he num ber of places where t hat part icular operat ion needs t o be validat ed or m odified t o one. The com m on procedure can also be opt im ized in one place, and t he benefit s will be felt t hroughout your applicat ion. All of t his leads t o a significant im provem ent in code qualit y. I t also serves a second im port ant purpose, m aking your code m ore reusable. As you fact or com m on operat ions int o dedicat ed procedures, you will discover t hat you can oft en reuse t hese procedures in ot her applicat ions. This t ype of code form s t he basis of a code library t hat you can use t o increase your product ivit y when writ ing new applicat ions. The m ore logical operat ions you have available as com plet e, fully t est ed library procedures, t he less t im e it will t ake for you t o develop a new applicat ion. I sola t ion of com ple x ope r a t ion s I n m any real- world applicat ions, you will find t hat som e sect ions of t he business logic are bot h com plex and very specific t o t he applicat ion for which t hey were designed ( t hat is, not reusable) . These sect ions of business logic should be isolat ed int o separat e procedures for ease of debugging and m aint enance. Pr oce du r e size r e du ct ion Procedures t hat are overly long are difficult t o underst and, debug and m aint ain, even for t he program m er who wrot e t hem . I f you discover a procedure cont aining m ore t han 150 t o 200 lines of code, it is probably t rying t o accom plish m ult iple goals and t herefore should be fact ored int o m ult iple single- purpose procedures. Lim it in g t h e n u m be r of pr oce du r e a r gu m e n t s The m ore argum ent s a procedure accept s, t he m ore difficult it will be t o underst and and t he less efficient it will be t o execut e. I n general, you should lim it t he num ber of procedure argum ent s t o five or fewer. And don't sim ply replace procedure argum ent s wit h public or m odule- level variables. I f you find yourself requiring m ore t han five procedure argum ent s, it 's probably a good sign t hat your procedure, or your applicat ion logic, needs t o be redesigned.

General Application Development Best Practices This sect ion covers best developm ent pract ices com m on t o all applicat ion developm ent areas. Most of t he ot her chapt ers in t his book recom m end furt her best pract ices relat ed specifically t o t he subj ect of t hat chapt er.

Code Commenting Good code com m ent ing is one of t he m ost im port ant pract ices in Excel applicat ion developm ent . Your code com m ent s should provide a clear and com plet e descript ion of how your code is organized, how each obj ect and procedure should be used and what you are t rying t o accom plish wit h your code. Com m ent s also provide a m eans of t racking changes t o your code over t im e, a subj ect we cover lat er in t his chapt er. Code com m ent s are im port ant t o bot h you and t o ot her developers who m ay need t o work on your code. The ut ilit y of code com m ent s t o ot her developers should be self- evident . What you m ight not realize unt il t he cruel fist of experience has pounded it int o you is t hat your com m ent s are very im port ant t o you as well. I t is very com m on for a developer t o writ e an init ial version of an applicat ion and t hen be asked t o revise it subst ant ially aft er a long period of t im e has passed. You would be surprised at how foreign even your own code looks t o you aft er it has been out of sight and out of m ind for a long period of t im e. Code com m ent s help solve t his problem . Com m ent s should be applied at all t hree m aj or levels of your applicat ion's code: t he m odule level, t he procedure level and t o individual sect ions or lines of code. We discuss t he t ypes of com m ent ing appropriat e t o each of t hese levels below.

Module-Level Comments I f you have used t he m odule nam ing convent ions described previously in t his chapt er, t hen anyone exam ining your code will have a rough idea of t he purpose of t he code cont ained wit hin each m odule. You should supplem ent t his wit h a brief com m ent at t he t op of each m odule t hat provides a m ore det ailed descript ion of t he purpose of t he m odule.

N OTE For t he purposes of code com m ent ing, when we use t he t erm m odule, we m ean it t o include st andard m odules, class m odules and t he code m odules behind userform s.

A good m odule- level com m ent should be locat ed at t he very t op of t he m odule and look som et hing

like t he exam ple shown in List ing 3- 2 .

List in g 3 - 2 . A Sa m ple M odu le - Le ve l Com m e n t ' ' Description: ' ' Option Explicit

A brief description of the purpose of the code in this module.

Procedure-Level Comments Procedure- level com m ent s are t ypically t he m ost det ailed com m ent s in your applicat ion. I n a procedure- level com m ent block, you describe t he purpose of t he procedure, usage not es, a det ailed list of argum ent s and t heir purposes and a descript ion of expect ed ret urn values in t he case of funct ions. Procedure- level com m ent s can also serve a rudim ent ary change- t racking purpose by providing a place t o add dat es and descript ions of changes m ade t o t he procedure. A good procedure- level com m ent such as t he one shown in List ing 3- 3 would be placed direct ly above t he first line of t he procedure. The procedure- level com m ent in List ing 3- 3 is designed for a funct ion. The only difference bet ween a com m ent block for a funct ion and a com m ent block for a subrout ine is t he subrout ine com m ent block does not cont ain a Ret urns sect ion, obviously because subrout ines do not ret urn a value.

List in g 3 - 3 . A Sa m ple Pr oce du r e - Le ve l Com m e n t '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Comments: Locates the chart to be operated on or asks ' the user to select a chart if multiple charts ' are located. ' ' Arguments: chtChart Returned by this function. An ' object reference to the chart to ' be operated on, or Nothing on user ' cancel. ' ' Returns: Boolean True on success, False on error ' or user cancel. ' ' Date Developer Action ' ------------------------------------------------------------' 07/04/02 Rob Bovey Created ' 10/14/03 Rob Bovey Error trap for charts with no

' 11/18/03 '

Rob Bovey

series Error trap for no active workbook

Internal Comments I nt ernal com m ent s are com m ent s t hat appear wit hin t he body of t he code it self. These com m ent s should be used t o describe t he purpose of any code where t he purpose is not self- evident . I nt ernal com m ent s should describe t he in t e n t of t he code rat her t han t he ope r a t ion of t he code. The dist inct ion bet ween int ent and operat ion is not always clear, so List ing 3- 4 and List ing 3- 5 show t wo exam ples of t he sam e code, one wit h a bad com m ent and t he ot her wit h a good com m ent .

List in g 3 - 4 . Ex a m ple of a Ba d I n t e r n a l Code Com m e n t ' Loop the asInputFiles array. For lIndex = LBound(asInputFiles) To UBound(asInputFiles) '... Next lIndex

The com m ent in List ing 3- 4 is m onum ent ally unhelpful. First of all, it describes only t he line of code direct ly below it , giving you no clue about t he purpose of t he loop st ruct ure as a whole. Second, t he com m ent is sim ply an exact writ t en descript ion of t hat line of code. This inform at ion is easy enough t o det erm ine by j ust looking at t he line of code. I f you rem oved t he com m ent shown in List ing 3- 4 , you would not lose any inform at ion at all.

List in g 3 - 5 . Ex a m ple of a Good I n t e r n a l Code Com m e n t ' Import the specified list of input files into the working area ' of our data sheet. For lIndex = LBound(asInputFiles) To UBound(asInputFiles) '... Next lIndex

I n List ing 3- 5 , we have a com m ent t hat adds value t o t he code. Not only does it describe t he int ent , rat her t han t he operat ion of t he code, it also explains t he ent ire loop st ruct ure. Aft er reading t his com m ent , you know what you're looking at as you delve int o t he code wit hin t he loop. As wit h m ost rules, t here are except ions t o t he int ernal com m ent guidelines specified above. The m ost im port ant except ion concerns com m ent s used t o clarify cont rol st ruct ures. If...Then st at em ent s and Do... Loops can m ake code difficult t o underst and as t hey becom e wider, because

you can no longer see t he ent ire cont rol st ruct ure in a single code window. At t hat point , it becom es difficult t o rem em ber what t he applicable cont rol expression was. For exam ple, when evaluat ing a lengt hy procedure we have oft en found ourselves looking at som et hing like t he code snippet shown in List ing 3- 6 .

List in g 3 - 6 . I n scr u t a ble Con t r ol St r u ct u r e s End If lNumInputFiles = lNumInputFiles - 1 Loop End If

I n List ing 3- 6 , what are t he logical t est s being m ade by t he t wo If...Then st at em ent s, and what expression cont rols t he Do...While loop? Aft er t hese st ruct ures have been filled wit h a subst ant ial am ount of code, you sim ply cannot t ell wit hout scrolling back and fort h wit hin t he procedure, because t he ent ire block is no longer visible wit hin a single code window. You can alleviat e t his problem very easily by using t he end- of- cont rol- block com m ent ing st yle shown in List ing 3- 7 .

List in g 3 - 7 . Un de r st a n da ble Con t r ol St r u ct u r e s End If

' If bContentsValid Then

lNumInputFiles = lNumInputFiles - 1 Loop End If

' Do While lNumInputFiles > 0 ' If bInputFilesFound Then

The com m ent s in List ing 3- 7 , alt hough t hey j ust rest at e t he code at t he t op of each cont rol st ruct ure, m ake it com plet ely obvious what you are looking at . These t ypes of com m ent s should be used anywhere you have a cont rol st ruct ure wit hin your code t hat is t oo large t o fit com plet ely int o one code window.

Avoiding the Worst Code-Commenting Mistake I t m ight seem obvious, but t he m ost frequent and dam aging m ist ake relat ed t o code com m ent ing is not keeping t he com m ent s updat ed as you m odify t he code. We have frequent ly seen proj ect s t hat appeared at first glance t o im plem ent good code- com m ent ing pract ices, but upon closer

exam inat ion discovered t he com m ent s were creat ed for som e ancient version of t he proj ect and now bore alm ost no relat ionship t o t he current code. When at t em pt ing t o underst and a proj ect , bad com m ent s are worse t han no com m ent s at all. Bad com m ent s are act ively m isleading. Always keep your com m ent s current . Old com m ent s can eit her be delet ed or ret ained as a series of change- t racking records. We recom m end rem oving obsolet e in- line com m ent s or t hey will quickly clut t er your code, m aking it difficult t o underst and sim ply due t o t he num ber of lines of inapplicable com m ent s t hat accum ulat e. Use procedure- level com m ent s as a change- t racking m echanism where necessary.

Code Readability Code readabilit y is a funct ion of how your code is physically arranged. Good visual layout of code enables you t o infer a significant am ount of inform at ion about t he logical st ruct ure of t he program . This is a key point . Code layout m akes not one bit of difference t o t he com put er. I t s sole purpose is t o assist hum ans in underst anding t he code. Like nam ing convent ions, t he consist ent use of good code layout convent ions m akes your code self- docum ent ing. The prim ary t ool of code layout is whit e space. Whit e space includes space charact ers, t abs and blank lines. The following paragraphs discuss t he m ost im port ant ways t o use whit e space t o produce a well- designed code layout . Group relat ed code elem ent s t oget her and separat e unrelat ed code elem ent s wit h blank lines. Sect ions of code separat ed by blank lines wit hin a procedure can be t hought of as serving a sim ilar funct ion t o paragraphs wit hin t he chapt ers of a book. They help you det erm ine what t hings belong t oget her. List ing 3- 8 shows an exam ple of how blank lines can im prove code readabilit y. Even wit hout t he code com m ent s, it would be obvious which lines of code are relat ed.

List in g 3 - 8 . Usin g Bla n k Lin e s t o Gr ou p Re la t e d Se ct ion s of Code ' Reset Application properties. Application.ScreenUpdating = True Application.DisplayAlerts = True Application.EnableEvents = True Application.StatusBar = False Application.Caption = Empty Application.EnableCancelKey = xlInterrupt Application.Cursor = xlDefault ' Delete all custom CommandBars For Each cbrBar In Application.CommandBars If Not cbrBar.BuiltIn Then cbrBar.Delete Else cbrBar.Enabled = True End If Next cbrBar ' Reset the Worksheet Menu bar. With Application.CommandBars(1)

.Reset .Enabled = True .Visible = True End With

Wit hin a relat ed sect ion of code, alignm ent is used t o indicat e which lines of code belong t oget her. I ndent at ion is used t o show t he logical st ruct ure of t he code. List ing 3- 9 shows a single sect ion fr om List ing 3- 8 where alignm ent and indent at ion have been used t o good effect . You can look at t his sect ion of code and underst and im m ediat ely which elem ent s go t oget her as well as deduce t he logical flow of t he code's execut ion.

List in g 3 - 9 . Pr ope r Use of Align m e n t a n d I n de n t a t ion ' Delete all custom CommandBars For Each cbrBar In Application.CommandBars If Not cbrBar.BuiltIn Then cbrBar.Delete Else cbrBar.Enabled = True End If Next cbrBar

Line cont inuat ion can be used t o m ake com plex expressions and long declarat ions m ore readable. Keep in m ind t hat breaking code int o cont inued lines solely for t he purpose of m aking t he ent ire line visible wit hout scrolling is not necessarily a good pract ice and can oft en m ake code m ore confusing. List ing 3- 10 shows exam ples of j udicious use of line cont inuat ion.

List in g 3 - 1 0 . Ju diciou s Use of Lin e Con t in u a t ion ' Complex expressions are easier to understand ' when properly continued If (uData.lMaxLocationLevel > 1) Or _ uData.bHasClientSubsets Or _ (uData.uDemandType = bcDemandTypeCalculate) Then End If ' Line continuations make long API declarations easier to read. Declare Function SHGetSpecialFolderPath Lib "Shell32.dll" _ (ByVal hwndOwner As Long, _ ByRef szBuffer As String, _ ByVal lFolder As Long, _ ByVal bCreate As Long) As Long

VBA Programming Best Practices General VBA Best Practices

Use of Module Directives Option Explicit Always use t he Option Explicit st at em ent in every m odule. The im port ance of t his pract ice cannot be overst at ed. Wit hout Option Explicit, any t ypographical error you m ake result s in VBA aut om at ically creat ing a new Variant variable. This t ype of error is very insidious because it m ay not even cause an im m ediat e runt im e error. However, it will cert ainly cause your applicat ion t o event ually ret urn incorrect result s. This t ype of bug m ay very well pass wit hout not ice unt il your applicat ion is dist ribut ed, and it will be difficult t o debug under any circum st ances. The Option Explicit st at em ent forces you t o explicit ly declare all t he variables you use. Option Explicit causes VBA t o t hrow a com pile- t im e error ( init iat ed by select ing Debug > Com pile from t he VBE m enu) whenever an unrecognized ident ifier nam e is encount ered. This m akes it very easy t o discover and correct t ypographical errors. You can ensure t hat Option Explicit is aut om at ically placed at t he t op of every m odule you creat e by choosing Tools > Opt ions > Edit or from t he VBE m enu and checking t he Require Variable Declarat ion check box. This set t ing is st rongly recom m ended. Option Private Module The Option Private Module st at em ent m akes all procedures wit hin t he m odule where it is used unavailable from t he Excel user- int erface or from ot her Excel proj ect s. Use t his st at em ent t o hide procedures t hat should not be called from out side your applicat ion.

TI P The Application.Run m et hod can circum vent t he Option Private Module st at em ent and run privat e procedures in m odules where t his st at em ent has been used.

Option Base 1 The Option Base 1 st at em ent causes all array variables whose lower bound has not been specified t o have a lower bound of 1. Do not use t he Option Base 1 st at em ent . I nst ead, always specify bot h t he upper and lower bounds of every array variable you use. A procedure creat ed in a m odule t hat uses Option Base 1 m ay m alfunct ion if copied t o a m odule in which t his st at em ent isn't used. This behavior inhibit s one of t he m ost im port ant procedure design goals, t hat of reusabilit y. Option Compare Text The Option Compare Text st at em ent forces all st ring com parisons

wit hin t he m odule where it is used t o be t ext based rat her t han binary. I n a t ext - based st ring com parison, upper- and lowercase versions of t he sam e charact er are t reat ed as ident ical, whereas in a binary com parison t hey are different . The Option Compare Text st at em ent should be avoided for t he sam e reason Option Base 1 should be avoided. I t m akes procedures behave different ly when placed in m odules wit h t he st at em ent versus m odules wit hout it . Text - based com parisons are also m uch m ore com put at ionally expensive t han binary com parisons, so Option Compare Text slows down all st ring com parison operat ions in t he m odule where it 's locat ed. Most Excel and VBA st ring com parison funct ions provide an argum ent you can use t o specify binary or t ext - based com parison. I t 's m uch bet t er t o use t hese argum ent s t o provide t ext - based com parisons only where you need t hem . There are som e rare cases where Option Compare Text is required. The m ost frequent case occurs when you need t o do non- case- sensit ive st ring com parisons wit h t he VBA Like operat or. The only way t o get t he Like operat or t o perform in a non- case- sensit ive m anner is t o use t he Option Compare Text st at em ent . I n t his case, you should isolat e t he procedures t hat require t his st at em ent in a separat e code m odule so ot her procedures t hat don't require t his opt ion aren't adversely affect ed. Be sure t o docum ent why you have done t his in a m odule- level com m ent .

Variables and Constants

Avoid Reusing Variables Each variable declared in your program should serve one purpose only. Using t he sam e variable for m ult iple purposes saves you only one variable declarat ion line but int roduces m assive pot ent ial for confusion wit hin your program . I f you are t rying t o det erm ine how a procedure works and you have figured out what a cert ain variable does in a cert ain place, you will nat urally assum e t he variable serves t he sam e purpose t he next t im e you see it . I f t his is not t he case, t he code logic will becom e very difficult t o underst and.

Avoid the Variant Data Type Avoid t he use of t he Variant dat a t ype whenever possible. Unfort unat ely, VBA is not a st rongly t yped program m ing language. Therefore, you can sim ply declare variables wit hout specifying t heir dat a t ype and VBA will creat e t hese variables as Variant s. The m ain reasons not t o use Variant s are as follows: Va r ia n t s a r e ve r y in e fficie n t This is because int ernally, a Variant is a very com plex st ruct ure designed t o hold any dat a t ype in t he VBA program m ing language. Variant values cannot be accessed and m odified direct ly as can fundam ent al dat a t ypes such as Long and Double. I nst ead, VBA m ust use a series of com plex Windows API calls behind t he scenes whenever it needs t o perform any operat ion on a Variant . D a t a st or e d in a va r ia n t ca n be h a ve u n e x pe ct e dly Because Variant s are designed t o hold any t ype of dat a, t he dat a t ype t hat goes int o a Variant is not necessarily t he dat a t ype t hat will com e out of it . When accessing t he dat a in a Variant , VBA will at t em pt t o coerce t he dat a int o what ever dat a t ype it t hinks m akes t he m ost sense in t he cont ext of t he operat ion. I f you

m ust use Variant s, always explicit ly cast t hem t o t he dat a t ype you want when using t heir values.

Beware of Evil Type Coercion Evil Type Coercion ( ETC) is anot her sym pt om t hat result s from VBA not being a st rongly t yped program m ing language. ETC occurs when VBA aut om at ically convert s one dat a t ype t o anot her com plet ely unrelat ed dat a t ype. The m ost frequent exam ples are St rings t hat hold num bers being convert ed t o I nt egers and Booleans being convert ed t o t heir St ring equivalent s. Don't m ix variables of different dat a t ypes in your code wit hout using t he explicit cast ing funct ions ( CStr, CLng, CDbl and so on) t o t ell VBA exact ly how you want t hose variables t o be t reat ed.

Avoid the As New Declaration Syntax Never declare obj ect variables using t he As New synt ax. For exam ple, t he following form of an obj ect variable declarat ion should never be used:

Dim rsData As New ADODB.Recordset

I f VBA encount ers a line of code t hat uses t his variable and t he variable has not been init ialized, VBA will aut om at ically creat e a new inst ance of t he variable. This is n e v e r t he behavior you want . Good program m ing pract ice im plies t hat t he program m er should m aint ain com plet e cont rol over t he creat ion of all t he obj ect s used in t he program . I f VBA encount ers an uninit ialized obj ect variable in your code, it is alm ost cert ainly t he result of a bug, and you want t o be not ified about it im m ediat ely. Therefore, t he proper way t o declare and init ialize t he obj ect variable shown above is as follows:

Dim rsData As ADODB.Recordset Set rsData = New ADODB.Recordset

Using t his st yle of declarat ion and init ializat ion, if t he obj ect variable is dest royed som ewhere in your procedure and you inadvert ent ly reference it again aft er t hat point , VBA will im m ediat ely t hrow t he runt im e error " Obj ect variable or Wit h block variable not set ," not ifying you of t he pr oblem .

Always Fully Qualify Object Names Always use fully qualified obj ect nam es in variable declarat ions and code wit h t heir class nam e prefix. The reason for t his is because m any obj ect libraries share t he sam e obj ect nam es. I f you j ust declare a variable wit h an obj ect nam e alone and t here are m ult iple obj ect libraries wit h t hat obj ect nam e being referenced by your applicat ion, VBA will creat e a variable from t he first library in

t he Tools > References list where it finds t he obj ect nam e you used. This is oft en not what you want . UserForm cont rols present t he m ost com m on sit uat ion where problem s result from obj ect variable declarat ions t hat aren't fully qualified. For exam ple, if you want ed t o declare an obj ect variable t o reference a Text Box cont rol on your userform , you m ight be inclined t o do t he following:

Dim txtBox As TextBox Set txtBox = Me.TextBox1

Unfort unat ely, as soon as VBA at t em pt s t o execut e t he second line of code, a " Type m ism at ch" error would be generat ed. This is because t he Excel obj ect library cont ains a Text Box obj ect and t he Excel obj ect library com es before t he MSForm s obj ect library in t he Tools > References list . The correct way t o writ e t his code is shown here:

Dim txtBox As MSForms.TextBox Set txtBox = Me.TextBox1

Never Hard Code Array Bounds When you are looping t he cont ent s of an array variable, never hard- code t he array bounds in loop. Use t he LBound and UBound funct ions inst ead, as shown in List ing 3- 11.

List in g 3 - 1 1 . Th e Cor r e ct W a y t o Loop a n Ar r a y Dim lIndex As Long Dim alListItems(1 To 10) As Long ' Load the array here. For lIndex = LBound(alListItems) To UBound(alListItems) ' Do something with each value. Next lIndex

The reason for t his is because array bounds frequent ly change over t he course of creat ing and m aint aining an applicat ion. I f you hard- code t he array bounds 1 and 10 in t he loop shown above, you will have t o rem em ber t o updat e t he loop any t im e t he bounds of t he alListItems array change. Failure t o do so is a frequent source of errors. By using LBound and Ubound, you m ake t he loop self- adj ust ing.

Always Specify the Loop Counter After a Next Statement List ing 3- 11 dem onst rat es anot her good coding pract ice. You should always specify t he loop count er variable aft er a Next st at em ent . Even t hough t his is not st rict ly required by VBA, doing so m akes your code m uch easier t o underst and, especially if t he dist ance bet ween t he For and Next st at em ent s is long.

Make Use of Constants Const ant s are very useful program m ing elem ent s. They serve t he following purposes in your code, am ong ot hers: Const ant s elim inat e " m agic num bers," replacing t hem wit h recognizable nam es. For exam ple, in t he following line of code, what does t he num ber 50 m ean? If lIndex < 50 Then

There is no way of knowing unless you wrot e t he code and you st ill rem em ber what 50 represent s. I f inst ead you saw t he following, you would have a very good idea of what t he If...Then t est was looking for:

Const lMAX_NUM_INPUT_FILES As Long = 50 ' More code here. If lIndex < lMAX_NUM_INPUT_FILES Then

I f you need t o know t he value of a const ant at design t im e, you can j ust right - click over t he const ant nam e in t he VBE and choose Definit ion from t he short cut m enu. You will be brought direct ly t o t he line where t he const ant is defined. I n break m ode at runt im e it 's even easier. Just hover your m ouse over t he const ant and a t oolt ip window cont aining it s value will appear . Const ant s im prove coding efficiency and avoid errors by elim inat ing duplicat e dat a. I n t he preceding exam ple, assum e you reference t he m axim um num ber of input files in several places t hroughout your program . At som e point you m ay need t o upgrade your program t o handle m ore files. I f you have hard- coded t he m axim um num ber of input files everywhere you've needed t o use it , you will have t o locat e all of t hese places and change t he num ber in each one. I f you've used a const ant , all you need t o do is m odify t he value of t he single const ant declarat ion and t he new value will aut om at ically be used wherever t he const ant has been used in your code. This sit uat ion is a very frequent source of errors t hat can be elim inat ed by sim ply using const ant s inst ead of hard- coded num bers.

Variable Scope Public variables are dangerous. They can be m odified anywhere in your applicat ion wit hout warning, m aking t heir values unpredict able. They also work against one of t he m ost im port ant program m ing precept s: encapsulat ion. Always creat e variables wit h t he m inim um scope possible. Begin by creat ing all of your variables wit h local ( procedure- level) scope and only widen t he scope of a variable when it is absolut ely necessary. As wit h m ost of our ot her rules, t here are a few cases where t he use of public variables is useful and/ or necessary. When dat a m ust be passed deep int o t he st ack before it is used. For exam ple, if procedure A reads som e dat a, t hen passes t hat dat a t o procedure B, which passes it t o procedure C, which passes it t o procedure D where t he dat a is finally used, a good case can be m ade t hat t he dat a should be passed direct ly from procedure A t o procedure D by way of a public variable. Cert ain inherent ly public classes, such as an applicat ion- level event handling class, require a public obj ect variable so t hey never go out of scope while your applicat ion is running.

Early Binding vs. Late Binding The dist inct ion bet ween early binding and lat e binding is widely m isunderst ood and oft en confused wit h how an obj ect is creat ed. The on ly t hing t hat affect s whet her an obj ect is early bound or lat e bound is how t he obj ect variable holding t he reference t o t he obj ect was declared. Variables declared as a specific obj ect dat a t ype are always early bound. Variables declared wit h t he Obj ect or Variant dat a t ype are always lat e bound. List ing 3- 12 shows an exam ple of a lat e bound reference, and List ing 3- 13 shows an exam ple of an early bound reference.

List in g 3 - 1 2 . A La t e Bou n d Re fe r e n ce t o a n AD O Con n e ct ion Obj e ct Dim objConnection As Object ' It doesn't matter ' late bound due to Set objConnection = Set objConnection =

how you create the object, it's still the As Object variable declaration. New ADODB.Connection CreateObject("ADODB.Connection")

List in g 3 - 1 3 . An Ea r ly Bou n d Re fe r e n ce t o a n AD O Con n e ct ion Obj e ct Dim cnConnection As ADODB.Connection ' It doesn't matter how you create the object, it's still early ' bound due to the data type used in the variable declaration.

Set cnConnection = New ADODB.Connection Set cnConnection = CreateObject("ADODB.Connection")

Not e t hat t o use early binding wit h obj ect s t hat are out side t he Excel obj ect m odel you m ust set a reference t o t he appropriat e obj ect library using t he Tools > References m enu in t he Visual Basic Edit or. For exam ple, t o creat e early bound variables referencing ADO obj ect s, you m ust set a reference t o t he Microsoft Act iveX Dat a Obj ect s 2.x Library, where x is t he version of ADO you int end t o use. You should use early bound obj ect variables wherever possible. Early bound obj ect variables provide t he following advant ages over lat e bound variables: I m pr ove d pe r for m a n ce When you use an obj ect variable whose dat a t ype is known t o VBA at com pile t im e, VBA can look up t he m em ory locat ions of all propert y and m et hod calls you use wit h t his obj ect and st ore t hem wit h your code. At runt im e, when VBA encount ers one of t hese early bound propert y or m et hod calls, it sim ply execut es t he code locat ed at t he st ored locat ion. ( This is a bit of an oversim plificat ion. What VBA act ually st ores is a num eric offset t o t he code t o be execut ed from a known st art ing point in m em ory, which is t he beginning of a st ruct ure called t he obj ect 's VTable.) When you use a lat e bound obj ect variable, VBA has no way of knowing in advance what t ype of obj ect t he variable will cont ain. Therefore, it cannot opt im ize any propert y or m et hod calls at com pile t im e. This m eans t hat each t im e VBA encount ers a lat e bound propert y or m et hod call at runt im e, it m ust query t he variable t o det erm ine what kind of obj ect it holds, look up t he nam e of t he propert y or m et hod being execut ed t o det erm ine where in m em ory it is locat ed and t hen execut e t he code locat ed at t hat m em ory address. This process is significant ly slower t han an early bound call. St r ict t ype ch e ck in g I n t he lat e bound exam ple in List ing 3- 12, if you accident ally set your obj ect variable t o reference an ADO Com m and obj ect inst ead of a Connect ion obj ect , VBA would not com plain. You would only discover you had a problem downst ream in your code when you t ried t o use a m et hod or propert y not support ed by t he Com m and obj ect . Wit h early binding, VBA will im m ediat ely det ect t hat you are t rying t o assign t he wrong t ype of obj ect reference t o your obj ect variable and not ify you wit h a " Type m ism at ch" error. I ncorrect propert y and m et hod calls can be det ect ed even earlier, before t he code is ever run. VBA will at t em pt t o look up t he nam e of t he propert y or m et hod being called from wit hin t he appropriat e obj ect library at com pile t im e and t hrow an error if t he nam e cannot be locat ed. I n t e lliSe n se a va ila bilit y Early bound obj ect variables m ake for m uch easier program m ing as well. Because VBA knows exact ly what t ype of obj ect a variable represent s, it can parse t he appropriat e obj ect library and provide a drop- down list of all available propert ies and m et hods for t he obj ect as soon as you t ype a dot operat or aft er t he variable's nam e. As you m ight expect , in som e cases you need t o use lat e binding rat her t han early binding. The t wo m ost com m on reasons for using lat e binding rat her t han early binding are as follows:

1 . When a newer version of an applicat ion's obj ect library has broken com pat ibilit y wit h an earlier version.

This is an all t oo com m on sit uat ion. I f you set a reference t o t he lat er version of t he applicat ion's obj ect library in your applicat ion and t hen at t em pt t o run it on a com put er t hat has t he earlier version, you will get an im m ediat e com pile t im e error " Can't find proj ect or library," and t he reference on t he t arget m achine will be prefixed wit h MI SSI NG. The m ost insidious t hing about t his error is t hat t he line of code flagged as being t he source of t he error will oft en have not hing t o do wit h t he obj ect library act ually causing t he problem . I f you need t o use obj ect s from an applicat ion t hat exhibit s t his problem and you want t o support users wit h any version of t he applicat ion, you need t o use lat e binding for all variables referencing obj ect s from t he applicat ion. I f you are creat ing new obj ect s, you also need t o use t he Creat eObj ect funct ion wit h t he version- independent ProgI D of t he obj ect you want t o creat e, rat her t han t he = New ObjectName synt ax. 2 . When you want t o use an applicat ion t hat you cannot be sure will exist on t he user's com put er and t hat you cannot inst all yourself. I n t his case, you need t o use lat e binding t o avoid t he com pile t im e error t hat would im m ediat ely result from at t em pt ing t o run an applicat ion t hat referenced an obj ect library t hat did not exist on t he user's com put er. Your applicat ion can t hen check for t he exist ence of t he obj ect library in quest ion and exit gracefully if t hat library is not inst alled on t he user's com put er .

TI P Even if you will event ually use lat e binding in your code, early binding offers such a great increase in product ivit y while coding t hat you should writ e and t est t he applicat ion using early binding. Convert your code t o lat e binding only for t he final round of t est ing and dist r ibut ion.

Defensive Coding Defensive coding refers t o various program m ing pract ices designed t o help you prevent errors rat her t han having t o correct t hem aft er t hey occur.

Write Your Application in the Earliest Version of Excel That You Expect It to Run In Alt hough t he Microsoft Excel t eam has done a bet t er j ob t han m ost of m aint aining backward com pat ibilit y wit h earlier versions of Excel, t here are m any subt le differences bet ween t he versions. I f you are very fam iliar wit h a lat er version of Excel, you can easily writ e an applicat ion t hat will not run on an earlier version because som e feat ure you used did not exist in t hat version. The solut ion t o t his problem is t o always develop your applicat ions in t he earliest version of Excel t hat you expect t hem t o run in. This m ay force you t o m aint ain m ult iple versions of Excel on one com put er, or bet t er yet , separat e com put ers for each version of Excel. Eit her way, t his is an essent ial pract ice. I f you develop an applicat ion in Excel 2000, give it t o a user in Excel 97 and find

out it doesn't run, you will need t o debug and rem ove any code t hat doesn't work in Excel 97. You will save m uch t im e and st ress by sim ply developing t he applicat ion using Excel 97 t o begin wit h.

Explicitly Use ByRef or ByVal I f a procedure t akes argum ent s, t here are t wo ways t o declare t hose argum ent s: ByRef or ByVal. ByRef This convent ion m eans you are passing t he m em ory address of t he variable rat her t han t he value of t he variable. I f t he called procedure m odifies a ByRef argum ent , t he m odificat ion will be visible in t he calling procedure. ByVal This convent ion m eans you are passing a value t o t he procedure. A procedure can m ake changes t o a ByVal argum ent , but t hese changes will not be visible t o t he calling procedure. I n fact , a procedure can use ByVal argum ent s exact ly as if t hey were locally declared variables. Always explicit ly declare your procedure argum ent s as ByRef or ByVal. I f you do not specify t his, all argum ent s are creat ed ByRef by default . You should declare procedure argum ent s ByVal unless you have a specific need for t he calling procedure t o see changes m ade t o t he argum ent s. Declaring ar gum ent s ByVal will prevent changes m ade t o t hose argum ent s from being propagat ed back t o t he calling procedure. The only except ions are when you are passing large st rings ( very large st rings) , which are far m ore efficient ly passed ByRef, or when your procedure argum ent is of a t ype, such as an array, t hat cannot be passed ByVal. Be aware t hat declaring procedure argum ent s ByVal does leave you m ore exposed t o Evil Type Coercion. A ByRef procedure argum ent m u st be passed t he sam e dat a t ype as it is declared t o accept ; ot herwise a com pile t im e error will result . By cont rast , VBA will at t em pt t o coerce a value passed t o a ByVal procedure argum ent int o a com pat ible dat a t ype.

Explicitly Call the Default Property of an Object Wit h t he possible except ion of t he I t em propert y of a Collect ion obj ect , it 's never a good idea t o im plicit ly invoke t he default propert y of an obj ect j ust by using t he obj ect 's nam e in an expression. List ing 3- 14 shows t he right way and t he wrong way of accessing t he default propert y of an obj ect using an MSForms.TextBox cont rol for dem onst rat ion purposes ( t he Text propert y is t he default propert y of an MSForms.TextBox cont rol) .

List in g 3 - 1 4 . D e fa u lt Pr ope r t ie s ' The right way. txtUsername.Text = "My Name" ' The wrong way txtUsername = "My Name"

By avoiding t he im plicit use of default propert ies, you m ake your code m uch m ore readable and prot ect yourself from errors if t he default behavior of t he obj ect changes in som e fut ure version of Excel or VBA.

Validate Arguments Before Using Them in Procedures I f your procedure accept s input argum ent s t hat m ust have cert ain propert ies in order t o be validfor exam ple, if t hey m ust be wit hin a specific range of valuesverify t hat t he values passed t o t hose argum ent s are valid before at t em pt ing t o use t hem in your procedure. The idea is t o cat ch erroneous input as soon as possible so t hat you can generat e a m eaningful error m essage and sim plify your debugging. Wherever possible, creat e t est harnesses t o validat e t he behavior of your procedures. A t est harness is a wrapper procedure t hat can call t he procedure being t est ed m ult iple t im es, passing it a wide range of argum ent s, and t est t he result t o be sure it is correct . Chapt er 16 VBA Debugging discusses t est harnesses in det ail.

Use Guard Counters to Protect Against Infinite Loops Program your loops t o aut om at ically handle infinit e loop condit ions. One of t he m ost com m on m ist akes m ade when using Do...While or While...Wend loops is t o creat e a sit uat ion where t he loop cont rol condit ion is never sat isfied. This causes t he loop t o run forever ( or unt il you can force your code t o break by pressing Ct rl+ Break if you are lucky, or by using t he Windows Task Manager t o shut down your applicat ion if you are not ) . Always add a count er t hat aut om at ically bails out when t he num ber of loops execut ed is known t o be m ore t han t he highest num ber t hat should ever occur in pract ice. List ing 3- 15 shows a Do...While loop wit h an infinit e loop guard st ruct ure.

List in g 3 - 1 5 . Gu a r d Aga in st I n fin it e Loops Dim bContinueLoop As Boolean Dim lCount As Long bContinueLoop = True lCount = 1 Do ' The code that goes here should set the ' bContinueLoop variable to False once the ' loop has achieved its purpose. ' This infinite loop guard exits the loop ' unconditionally after 10000 iterations. lCount = lCount + 1 If lCount > 10000 Then Exit Do

Loop While bContinueLoop

The only purpose of t he lCount variable wit hin t he loop is t o force t he loop t o exit if t he code wit hin t he loop fails t o set t he cont rol variable t o exit wit hin 10,000 it erat ions. ( The appropriat e num ber would depend on t he part icular sit uat ion.) This t ype of const ruct adds very lit t le overhead t o your loop; if perform ance is a significant concern, however, use t he infinit e loop guard unt il you are sure all t he code wit hin t he loop is funct ioning properly, and t hen delet e it or com m ent it out .

Use Debug > Compile Early and Often Never let your code st ray m ore t han a few changes away from being able t o run a flawless Debug > Com pile. Failing t o adhere t o t his pract ice will lead t o long, inefficient debugging sessions.

Use CodeNames to Reference Sheet Objects Always reference worksheet s and chart sheet s in your applicat ion by t heir CodeNam e. Depending on sheet t ab nam es t o ident ify sheet s is risky because you or your users m ay change t hese t ab nam es, breaking any code t hat uses t hem .

Validate the Data Types of Selections I f you writ e a procedure designed t o operat e on a specific t ype of obj ect t he user has select ed, always check t he obj ect t ype of t he select ion using eit her t he TypeName funct ion or t he If TypeOf...Is const ruct . For exam ple, if you need t o operat e on a range select ed by t he user, ensure t hat t he select ion really is a Range obj ect before cont inuing, as shown in List ing 3- 16.

List in g 3 - 1 6 . Ve r ify Th a t t h e Se le ct ion I s t h e Cor r e ct Obj e ct Type ' Code designed to operate on a range. If TypeOf Selection Is Excel.Range Then ' OK, it's a Range object. ' Continue code execution. Else ' Error, it's not a Range object. MsgBox "Please select a range.", vbCritical, "Error!" End If

Change Control Change cont rol, also known as version cont rol, at t he m ost basic level involves t wo pract ices:

m aint aining a set of prior versions of your applicat ion t hat you can use t o recover from various program m ing or t echnical errors and docum ent ing changes m ade t o your applicat ion over t im e.

Saving Versions When m ost professional program m ers t alk about version cont rol, t hey m ean t he use of dedicat ed version cont rol soft ware, such as Microsoft Visual Source Safe. However, t his t ype of soft ware is expensive, has a st eep learning curve and doesn't int egrat e well wit h applicat ions built in Excel. This is because Excel doesn't st ore it s m odules nat ively as separat e t ext files. The version cont rol m et hod we will suggest here is quick, sim ple, requires no special soft ware and delivers t he m ost crucial benefit s of a t radit ional version cont rol syst em . The m ost im port ant obj ect ive of a version cont rol syst em is t o enable you t o recover an earlier version of your proj ect if you have encount ered som e significant problem wit h t he version you are current ly working on. I f a significant code m odificat ion has gone t erribly wrong or you suddenly find yourself wit h a corrupt file, you will be in a very difficult posit ion if you do not have a recent backup t o help you recover. A sim ple version cont rol syst em t hat can save you from t hese problem s would be im plem ent ed in a fashion sim ilar t o t he following. First creat e a folder nam ed Backup as a subfolder t o t he folder in which your proj ect is st ored. Each t im e you prepare t o m ake a significant addit ion or m odificat ion t o your proj ect , or at m inim um once a day, use a file- com pression ut ilit y such as WinZip t o zip all t he files in your proj ect folder int o a file wit h t he following nam e form at : Backup_YYYYMMDDHH.zip, where Y st ands for year, M st ands for m ont h, D st ands for day and H st ands for hour. This nam ing form at will give your backup file a unique nam e t hat will sort in correct sequent ial order when viewed in Windows Explorer. Move t his file int o your Backup folder and cont inue working. I f you encount er a problem , you can recover your proj ect from t he m ost recent backup. You will obviously lose som e work, but if you save backup versions diligent ly you can m inim ize t he loss. Each t im e you are sure you have a fully t est ed build of your proj ect , you can delet e m ost of t he int erm ediat e files from your Backup folder. I t is advisable t o ret ain at least weekly backups t hroughout t he life of a proj ect .

Documenting Changes with Comments When you are m aint aining code, if you m ake a significant change t o t he logic of a procedure you should also m ake a not e wit h a brief descript ion of t he change, t he dat e it was m ade and your nam e in t he procedure- level com m ent block ( see List ing 3- 3 ) . All nont rivial m odificat ions t o your code should be not ed wit h an int ernal com m ent t hat includes t he dat e t he change was m ade and t he nam e of t he developer who m ade t he change if t here are m ult iple developers working on t he applicat ion.

Conclusion Whet her you use t he nam ing convent ion proposed here or creat e your own, use a nam ing convent ion consist ent ly across all your applicat ions and over t im e. I t will m ake your code selfdocum ent ing and easy t o follow. Code t he separat e logical t iers of your applicat ion as independent ent it ies. This will prevent changes in one logical t ier from forcing you t o rebuild m uch of your applicat ion. Com m ent your code liberally at all levels. When t rying t o underst and t he purpose of a sect ion of code, it 's a lot easier if t hat purpose is explained by a code com m ent t han if you have t o figure it out yourself. Following t hese and all t he ot her best pract ices present ed in t his chapt er will result in robust , underst andable and m aint ainable applicat ions.

Chapter 4. Worksheet Design There is a t rem endous am ount of Excel user int erface design t hat can and should be accom plished using t he built - in feat ures of Excel alone, wit h no VBA required. One of t he guiding principles of Excel developm ent is " let Excel be Excel." Don't t ry t o reinvent t he wheel. Excel provides a wide variet y of prepackaged, perform ance- opt im ized feat ures you can use t o build your applicat ion's user int erface. This chapt er exam ines how you can produce a fully funct ional user int erface wit h j ust t he feat ures Excel provides for t his purpose. There are t wo fundam ent al sect ions of an Excel worksheet user int erface: t hose designed t o be visible t o t he user and t hrough which t he user operat es your applicat ion, and t hose designed t o be hidden from t he user and used only by your applicat ion t o perform t he t asks required of it . We cover each of t hese sect ions in m ore det ail in t his chapt er.

Principles of Good Worksheet UI Design The following list provides som e design guidelines t hat apply t o all worksheet user int erfaces:

1 . Use form at t ing t o creat e visual cont rast bet ween cells designed t o serve different purposesinput cells versus form ula cells, for exam pleas well as visual separat ion bet ween different sect ions of your user int erface. 2 . Use consist ent form at t ing based on t he purpose of each cell. For exam ple, don't form at input cells wit h a whit e background in one area and a green background in anot her. 3 . Don't use garish colors. Your choice of form at t ing should not dist ract from t he t ask at hand. 4 . Creat e a logical, well- st ruct ured flow t hrough your user int erface. Your user int erface should flow from left t o right t hen t op t o bot t om wit hin a worksheet and from left t o right am ong m ult iple worksheet s. 5 . Make it obvious t o users what t hey are supposed t o do each t im e t hey are required t o perform som e act ion. Techniques for doing t his include t he use of cell com m ent s, validat ion list s, default values, good descript ive field nam es and so on. 6 . Use dynam ic input - verificat ion t echniques t o provide feedback as quickly as possible if t he user has done som et hing wrong. Wait ing unt il t he user has com plet ed t he ent ire form t o point out dat a- ent ry errors should be viewed as a last resort , t o be used only when t here are no good alt ernat ives. 7 . Don't creat e an environm ent t hat pot ent ially allows t he user t o m ake cat ast rophic m ist akes. Prot ect all of your user int erface worksheet s, leaving only cells t hat require dat a ent ry unlocked. This prevent s crit ical form ulas from being accident ally overwrit t en. 8 . Don't allow t he user t o get lost . Rest rict t he area of t he worksheet wit hin which t he user can navigat e t o t he working area of your user int erface.

Program Rows and Columns: The Fundamental UI Design Technique When you design a user int erface on an Excel worksheet , one of t he first t hings you should do is leave row 1 and colum n A em pt y. This sect ion of t he worksheet will be hidden from t he user and will allow your applicat ion t o perform m any t asks associat ed wit h an advanced Excel UI , including error checking, st oring validat ion list s and calculat ing int erm ediat e values. I n very com plex worksheet user int erfaces, it is not uncom m on t o have several init ial rows and/ or colum ns used as hidden work areas. These are called pr ogr a m r ow s and pr ogr a m colu m n s. An Excel worksheet user int erface is t ypically laid out in a t able form at , left t o right , t op t o bot t om . I m plem ent ing design principle 6 described above is m ost easily accom plished if you have a hidden area you can use t o aut om at ically exam ine each of t he user's ent ries and det erm ine whet her t hey m eet all t he crit eria t hat are enforceable using worksheet - based const ruct s. The result of t hese t est s can t hen be used by condit ional form at t ing and/ or VBA- based validat ion t o signal users when t hey have ent ered dat a incorrect ly. I n t he sim ple t im esheet exam ple shown in Figure 4- 1 , t he user com plet es t he first t hree colum ns of t he t able. The last colum n of t he t able is calculat ed by t he worksheet . The first colum n of t he worksheet it self is designed t o be a hidden colum n. I t perform s a sim ple validat ion check on each row of t he t im esheet t able. I t count s t he num ber of ent ries m ade by t he user in each row and ret urns True if t he num ber of ent ries is incorrect ( which is t o say t he user has not com plet ed all of t he required ent ries for t hat row) .

Figu r e 4 - 1 . An Ex a m ple of H idde n Colu m n D a t a Va lida t ion [View full size image]

Here t here are only t wo possible valid condit ions. Eit her a row has not yet been used and t herefore has zero ent ries, or a row has been com plet ely filled out , in which case t here will be t hree ent ries. Any ot her condit ion is an error. Not ice t hat t he error- checking form ula for row 6 indicat es t here is a

dat a- ent ry error in t hat row. This is because t he user has not yet ent ered a St op Tim e. The user m ay very well elim inat e t his error by ent ering a St op Tim e aft er he com plet es t his t ask. I f he doesn't , it is a sim ple m at t er for your applicat ion t o exam ine t he validat ion range in colum n A and det erm ine t here is an error.

Defined Names Defined nam es are an int egral part of worksheet user int erface design. Defined nam es are a superset of t he m ore com m only underst ood nam ed range feat ure. Defined nam es include nam ed const ant s, nam ed ranges and nam ed form ulas. Each t ype of defined nam e serves an im port ant purpose and all nont rivial Excel worksheet user int erfaces use som e or all of t he defined nam e t ypes. The nam ing convent ions used for t he defined nam es dem onst rat ed in t his chapt er are described in Chapt er 3 Excel and VBA Developm ent Best Pract ices.

Named Constants A defined nam e can refer t o a const ant value. For exam ple, t he set HiddenCols defined const ant shown in Figure 4- 2 refers t o t he value 1.

Figu r e 4 - 2 . A Sa m ple N a m e d Con st a n t

This nam e illust rat es a t ypical use of defined const ant s: st oring set t ings t hat will be m ade t o a user int erface worksheet . I n t his case it indicat es t he num ber of init ial colum ns t hat will be hidden. Nam ed const ant s can also serve all of t he sam e purposes on a worksheet t hat VBA const ant s serve in a VBA program , as discussed in Chapt er 3 Excel and VBA Developm ent Best Pract ices.

Two part icularly im port ant uses of nam ed const ant s are workbook ident ificat ion and version ident ificat ion. Each UI workbook you creat e should have a unique nam ed const ant t hat ident ifies it as belonging t o your applicat ion. The add- in for your applicat ion can t hen use t his const ant t o det erm ine whet her t he current ly act ive workbook belongs t o it . You should also include a version const ant so you can pinpoint exact ly what version of your applicat ion a given workbook belongs t o. This becom es very im port ant when you upgrade t he applicat ion such t hat prior version user int erface workbooks m ust be updat ed in som e way.

Named Ranges Nam ed ranges enable you t o reference a locat ion on a worksheet wit h a friendly nam e t hat conveys inform at ion about t hat locat ion, rat her t han using a range address t hat cannot be int erpret ed wit hout following it back t o t he cell or cells it refers t o. As t he exam ple below shows, nam ed ranges also enable you t o accom plish t hings you cannot accom plish wit h direct ly ent ered cell addresses. Everyone reading t his book should be fam iliar wit h fixed nam ed ranges, t hose referring t o a fixed cell or group of cells on a worksheet . This sect ion concent rat es on t he less well- underst ood t opic of relat ive nam ed ranges. A r e la t ive nam ed range is called relat ive because t he locat ion it references is det erm ined relat ive t o t he cell in which t he nam e is used. Relat ive nam ed ranges are defined in such a way t hat t he cell or cells t hey refer t o change depending on where t he nam e is used. There are t hree t ypes of relat ive nam ed ranges:

1 . Colu m n r e la t ive The referenced colum n changes, but t he referenced row rem ains fixed. These can be ident ified because t he absolut e reference sym bol ( $) appears only before t he row num ber. The address A$1 is an exam ple of a colum n- relat ive address. 2 . Row r e la t ive The referenced row changes, but t he referenced colum n rem ains fixed. These can be ident ified because t he absolut e reference sym bol ( $) appears only before t he colum n let t er. The address $A1 is an exam ple of a row- relat ive address. 3 . Fu lly r e la t ive Bot h t he referenced row and t he referenced colum n change. I n fully relat ive nam ed ranges, neit her t he row nor t he colum n is prefixed wit h t he absolut e reference sym bol ( $) . The address A1 is an exam ple of a fully relat ive address. To creat e a relat ive nam ed range, you m ust first select a cell whose posit ion you will define t he nam e relat ive t o. This cell is your st a r t in g poin t . This cell is not t he only cell where t he nam e can be used; it sim ply gives you a point from which t o define t he relat ive nam e. I n t he next exam ple, we dem onst rat e how t o define and use a fully relat ive nam ed range t hat enables you t o creat e form ulas t hat aut om at ically adj ust t he range t hey refer t o when a row is insert ed direct ly above t hem . First let 's see why t his is im port ant . Figure 4- 3 shows a sim ple t able showing t he sales for t hree hypot het ical regions. The t ot al sales for all t hree regions are calculat ed using t he built - in SUM worksheet funct ion, which you can see displayed in t he form ula bar.

Figu r e 4 - 3 . Tot a l Sa le s Usin g a St a n da r d For m u la

Now assum e we need t o add a fourt h region t o our list . We will insert a new row direct ly above t he Tot al Sales row and add Region D. Figure 4- 4 shows t he result .

Figu r e 4 - 4 . I n se r t a n Addit ion a l Re gion t o t h e List

Because t he new region was insert ed at t he bot t om of t he list , t he SUM funct ion range did not adj ust and t he Tot al Sales num ber report ed by t he funct ion is now wrong. This exam ple was designed t o m ake t he problem blindingly obvious. I n real- world worksheet s, t his t ype of m ist ake is frequent and rarely so obvious. I n fact , it is one of t he m ost com m on errors we discover when audit ing m alfunct ioning worksheet s. This error is easy t o avoid by defining a fully relat ive nam ed range t hat always refers t o t he cell direct ly above t he cell where t he nam e is used. To do t his, choose I nsert > Nam e > Define t o display t he Define Nam e dialog ( or bet t er yet , use t he Ct rl+ F3 keyboard short cut ) . As you can see in Figure 4- 5 , our st art ing point is cell B6 and we have defined a fully relat ive, sheet - level nam ed range called pt rCellAbove t hat refers t o cell B5.

Figu r e 4 - 5 . Cr e a t in g a Fu lly Re la t ive N a m e d Ra n ge [View full size image]

Next we m odify our SUM funct ion so it references t he pt rCellAbove nam ed range rat her t han a specific ending cell address, as shown in Figure 4- 6 .

Figu r e 4 - 6 . Usin g a Fu lly Re la t ive N a m e d Ra n ge in a W or k sh e e t Fu n ct ion

Not only does our SUM funct ion now display t he correct answer, you can insert as m any rows direct ly above it as you like and it will always sum t he correct area. This feat can only be accom plished t hrough t he use of a fully relat ive nam ed range. We use relat ive nam ed ranges ext ensively in our sam ple applicat ion.

Named Formulas The least underst ood and m ost powerful defined nam e t ype is t he nam ed form ula. Nam ed form ulas are built from t he sam e Excel funct ions as regular worksheet form ulas and like worksheet form ulas t hey can ret urn sim ple values, arrays and range references. Nam ed form ulas enable you t o package up com plex but frequent ly used form ulas int o a single defined nam e. This m akes t he form ula m uch easier t o use, because all you need t o do is ent er t he defined nam e you've assigned t o it rat her t han t he ent ire form ula. I t also m akes t he form ula easier t o m aint ain because you can m odify it in one place ( t he Define Nam e dialog) and t he changes will aut om at ically propagat e t o every cell where t he defined nam e is used. I n t he Pract ical Exam ple sect ion of t his chapt er, we show an exam ple of how t o use a nam ed form ula t o package a com plex worksheet form ula int o a defined nam e t o m ake it m ore m aint ainable and easier t o use. Nam ed form ulas can also be used t o creat e dyn a m ic list s. A dynam ic list form ula is used t o ret urn a reference t o a list of ent ries on a worksheet when t he num ber of ent ries in t he list is variable. Worksheet user int erface developm ent m akes ext ensive use of dynam ic list s for dat a- validat ion purposes, a t opic we cover in dept h in t he Dat a Validat ion sect ion lat er in t he chapt er, but let 's revisit t he t im esheet from Figure 4- 1 t o show a quick exam ple. I n t his t ype of user int erface, we wouldn't want users t o ent er what ever act ivit y nam e t hey want in t he Act ivit y colum n. To m ake our dat a consist ent from user t o user, we would define a dat avalidat ion list of accept able act ivit y nam es and users would pick t he act ivit y t hat m ost closely described what t hey were doing from our predefined dat a- validat ion list . We'll put our act ivit y list on a background worksheet ( one not designed t o be seen by t he user) and creat e a dynam ic list nam ed form ula t hat refers t o it . Figure 4- 7 shows t his nam ed form ula.

Figu r e 4 - 7 . A D yn a m ic N a m e d For m u la [View full size image]

The valAct ivit iesList nam ed form ula can now be used as t he dat a- validat ion list for t he t im esheet Act ivit y colum n. A dynam ic list nam ed form ula consist s of t he following part s: St a r t in g poin t The point at which t he list begins. I n t his case, our st art ing point is cell w ksDat a! $A$1. D a t a a r e a The full range in which it em s of our list m ight be locat ed. This includes not only cells t hat are current ly being used, but also cells t hat m ight be used in t he fut ure. I n t his case, our dat a area is t he ent ire colum n A, or wksDat a! $A: $A. List for m u la A form ula t hat det erm ines t he num ber of it em s current ly in t he list and ret urns a range reference t o j ust t hose it em s. This is a com binat ion of t he OFFSET and COUNTA worksheet funct ions.

Scope of Defined Names Defined nam es can have one of t wo scopes: worksheet level or workbook level. These are roughly analogous t o privat e and public variables. Like variables, defined nam es should be given t he m ost lim it ed scope possible. Always use worksheet - level defined nam es unless you m ust m ake a nam e workbook level. When your workbook cont ains a large num ber of defined nam es, using worksheet - level defined nam es helps reduce t he num ber of nam es you have t o look t hrough in t he Define Nam e dialog all at once. Worksheet - level defined nam es can be used from ot her worksheet s in m ost cases. When t hey are used from anot her worksheet , t hey are j ust prefixed wit h t he nam e of t he worksheet from which t hey originat ed. This m akes audit ing worksheet s t hat use defined nam es m uch sim pler because you don't have t o look up every defined nam e you com e across in t he Define Nam es dialog in order t o det erm ine which worksheet it references. I t is also oft en useful t o have t he sam e defined nam e on m ult iple worksheet s in your user int erface workbook. Two good exam ples of t his are general- purpose, fully relat ive range nam es such as t he pt rCellAbove range we discussed earlier and nam es t hat hold t he values of set t ings you want t o m ake t o each worksheet using VBA code. We cover t he lat t er in m ore det ail in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins. Som e circum st ances require you t o use workbook- level defined nam es. Figure 4- 7 dem onst rat es t he m ost com m on case. A defined nam e t hat refers t o a range locat ed on a different worksheet t hat you want t o use in a dat a- validat ion list m ust be a workbook- level defined nam e. This is a lim it at ion inherent in Excel's dat a- validat ion feat ure. I n som e cases, a workbook- level defined nam e is sim ply appropriat e, such as when t he nam e t ruly refers t o t he ent ire workbook rat her t han t o any individual worksheet . This would be t he case wit h a nam ed const ant used t o ident ify t he version num ber of a workbook. I n t he pract ical exam ple sect ion of Chapt er 7 Using Class Modules t o Creat e Obj ect s, we dem onst rat e t he use of a workbooklevel defined const ant t o ident ify workbooks t hat belong t o our applicat ion.

Styles Advantages of Styles St yles provide a num ber of advant ages t hat m ake t hem an int egral part of any worksheet user int erface. They provide a sim ple, flexible way t o apply sim ilar form at t ing t o all t he cells in your worksheet user int erface t hat serve a sim ilar purpose. The consist ent use of st yles also gives t he user clear visual clues about how your user int erface works. Using our t im esheet exam ple from Figure 4- 1 , Figure 4- 8 shows how different st yles define different areas of t he worksheet user int erface.

Figu r e 4 - 8 . Usin g St yle s a s Visu a l I n dica t or s of t h e St r u ct u r e of You r Use r I n t e r fa ce [View full size image]

St yles enable you t o apply t he m ult iple form at t ing charact erist ics required for each user int erface range all at once. Form at t ing charact erist ics com m only applied t hrough t he use of st yles include num ber form at , font t ype, background shading and cell prot ect ion. Ot her st yle propert ies, such as t ext alignm ent and cell borders, are less com m only used because t hey t end t o be different , even wit hin cells of t he sam e st yle. Cust om st yles, which we discuss in t he next sect ion, can be configured t o ignore t he form at t ing charact erist ics you don't want t o include in t hem .

I f you need t o change t he form at of a cert ain area of your user int erface, you can j ust m odify t he appropriat e st yle and all of t he cells using t hat st yle will updat e aut om at ically. Here's an all- t oocom m on real- world exam ple of where t his is very useful. You've creat ed a com plex, m ult isheet dat a- ent ry workbook using whit e as t he background color for dat a- ent ry cells. When you show t his t o your client or boss, t hey decide t hey want t he dat a- ent ry cells t o be shaded light yellow inst ead of whit e. I f you didn't use st yles t o const ruct your user int erface, you would have t o laboriously reform at every dat a- ent ry cell in your workbook. I f you did use st yles, all t hat 's required is t o change t he pat t ern color of your dat a- ent ry st yle from whit e t o light yellow and every dat a- ent ry cell in your workbook will updat e aut om at ically. Given t he frequency wit h which people change t heir m inds about how t heir applicat ions should look, using st yles t hroughout an applicat ion can save you a significant am ount of t im e and effort .

Creating and Using Styles Adding cust om st yles is not t he m ost int uit ive process in Excel, but aft er you've seen t he st eps required, you'll be creat ing st yles like an expert in no t im e. Cust om st yles are creat ed using t he Form at > St yle m enu. This opens t he St yle dialog, shown in Figure 4- 9 , from which all st yle confusions originat e.

Figu r e 4 - 9 . Th e Ex ce l St yle D ia log

When t he St yle dialog first opens, it aut om at ically displays t he form at t ing charact erist ics of t he cell t hat was select ed when t he dialog was invoked. I n Figure 4- 9 , t he St yle dialog was invoked while t he select ed cell was in t he St art Tim e colum n shown in Figure 4- 8 . As you can see, t his cell was form at t ed wit h t he I nput st yle, so t his is t he st yle displayed by t he St yle dialog.

To creat e a new st yle, ent er t he nam e of t he st yle you want t o creat e in t he St yle nam e com bo box, as shown in Figure 4- 10.

Figu r e 4 - 1 0 . A N e w St yle I s Alw a ys Ba se d on t h e St yle of t h e Ce ll Se le ct e d W h e n t h e St yle D ia log I s D ispla ye d

Aft er you do t his, you will encount er one of t he m ore confusing aspect s of t he St yle dialog. All t he St yle I ncludes check boxes will be checked and t heir values will be set t o t he form at of t he cell t hat was select ed when t he St yle dialog was invoked. This occurs even if t hose form at charact erist ics are not part of t he st yle current ly applied t o t hat cell. For exam ple, Num ber, Alignm ent and Border at t ribut es were excluded from t he I nput st yle t hat was displayed in t he St yle dialog im m ediat ely before we creat ed our new st yle. All t hree of t hose at t ribut es are included in our new st yle, however, and t heir specific values are drawn from t he form at t hat was applied t o t he cell t hat was select ed when t he St yle dialog was first invoked. This is what t he By Exam ple in parent hesis aft er t he St yle I ncludes t it le m eans. Don't worry; all of t hese at t ribut es can easily be changed. First , rem ove t he checkm ark from beside any form at opt ion t hat you don't want t o include in your st yle. When a st yle is applied t o a range, only t he form at opt ions you checked will be applied. Next , click t he Modify but t on t o define t he propert ies of your new st yle. This will display t he Form at Cells dialog, shown in Figure 4- 11.

Figu r e 4 - 1 1 . Th e For m a t Ce lls D ia log a s I n vok e d fr om t h e St yle D ia log M odify Bu t t on

Not ice t hat t he six t abs on t he Form at Cells dialog correspond exact ly t o t he six St yle I ncludes opt ions shown in Figure 4- 10. This is no accident . St yles are j ust a way of grouping m ult iple cell form at charact erist ics under a single nam e so t hat t hey can be applied and m aint ained sim ult aneously t hrough t hat nam e.

N OTE I f you rem ove t he checkm ark from a St yle I ncludes opt ion but t hen change any of t he charact erist ics of t hat opt ion in t he Form at Cells dialog, t he opt ion will aut om at ically becom e checked again in t he St yle dialog.

Modifying Styles Modifying an exist ing st yle is exact ly like creat ing a new st yle except t hat aft er select ing t he Form at > St yle m enu, you pick t he st yle you want t o m odify from t he St yle nam e com bo box rat her t han ent ering a new st yle nam e. Each t im e you select a st yle in t he St yle nam e com bo box, t hat st yle will have it s set t ings sum m arized and displayed for you in t he St yle I ncludes sect ion of t he dialog. Click t he Modify but t on t o display t he Form at Cells dialog and change any of t he form at opt ions for

t he current ly select ed st yle. There is one m inor caut ion t o keep in m ind when creat ing new st yles or m odifying exist ing st yles. Aft er you have configured t he st yle using t he Form at Cells dialog, be sure t o click t he Add but t on on t he St yle dialog t o save your changes. I f you click t he OK but t on, your changes will be saved, but t he st yle you have creat ed or m odified will also be applied t o t he current ly select ed cell. This is oft en not t he result you want . Get t ing int o t he habit of using t he Add but t on t o add and updat e st yles will save you from having t o undo changes t o a cell you didn't int end t o change. Aft er you have used t he Add but t on t o creat e or m odify a St yle, you can safely use t he Cancel but t on t o dism iss t he St yle dialog wit hout losing your work or form at t ing t he current ly select ed cell.

Adding the Style Drop-Down to the Toolbar I f you're fam iliar wit h Word, you'll not ice st yles in Word are considered so im port ant t hat a special st yle drop- down is aut om at ically present on t he Form at t ing t oolbar. This not only enables you t o quickly apply a st yle t o a select ion, but also displays t he st yle associat ed wit h t he sect ion of t he docum ent where your cursor is locat ed. Excel has t he sam e t oolbar cont rol, but for som e reason, st yles in Excel were not deem ed im port ant enough by Microsoft t o have t his cont rol appear by default . You can add t his cont rol t o one of your Excel t oolbars m anually, however, and if you plan on m aking full use of st yles in Excel you should do so. Here's how. St art by select ing View > Toolbars > Cust om ize from t he Excel m enu. I n t he Cust om ize dialog, select t he Com m ands t ab. I n t he Com m ands t ab, select t he Form at it em from t he Cat egor ies list . As shown in Figure 4- 12, t he St yle drop- down will be t he fift h it em in t he Com m ands list box.

Figu r e 4 - 1 2 . Se le ct in g t h e St yle D r op- D ow n fr om t h e List of For m a t Con t r ols

Drag t his cont rol from t he Com m ands list box and drop in ont o one of your exist ing t oolbars. You will now have a St yle cont rol t hat provides t he sam e benefit s as t he St yle cont rol in Word. You can select a group of cells and apply a st yle t o all of t hose cells by sim ply select ing t he st yle nam e from t he St yle drop- down. And when you select a cell, t he nam e of t he st yle applied t o t hat cell will aut om at ically be displayed in t he St yle drop- down. This feat ure proves very helpful when creat ing com plex worksheet user int erfaces t hat ut ilize m any different st yles.

User Interface Drawing Techniques Using Borders to Create Special Effects To keep t he user focused on t he elem ent s of your worksheet user int erface, it is oft en helpful t o m odify t he norm al st yle so all unused areas of t he worksheet have a consist ent , light gray background color. This pract ice has been dem onst rat ed in m ost of t he user int erface exam ples shown so far and will be used in our sam ple applicat ion. On t op of t his light gray background, you can use cell borders t o creat e som e int erest ing special effect s. One of t he m ost com m only used border- based special effect s gives a range of cells a 3D appearance, eit her raised or sunken. Figur e 4- 13 shows exam ples of bot h effect s.

Figu r e 4 - 1 3 . Usin g Bor de r s t o Cr e a t e 3 D Visu a l Effe ct s

To creat e a raised effect , you j ust add a whit e border t o t he t op and right sides of your range and add a 50 percent gray border t o t he left and bot t om sides of your range. To creat e a sunken effect , you do exact ly t he opposit e. The widt h of t he borders can be used t o cont rol t he degree of t he effect . When you've applied a background color t o a worksheet , as we've done in t he exam ple above, Excel's st andard gridlines are obscured. I n m any cases gridlines are a useful visual guide for t he user, so you want t o put t hem back. Alt hough t here is no way t o force Excel's st andard gridlines t o display over a background color, you can easily sim ulat e gridlines by adding 25 percent gray borders wit h t he light est widt h t o t he area where you want t he gridlines t o appear. Figure 4- 14 shows t his effect .

Figu r e 4 - 1 4 . Usin g Bor de r s t o Sim u la t e Gr idlin e s

Creating Well-Formatted Tables Tables used wit hin an Excel worksheet user int erface t ypically have one or m ore of t he following elem ent s: Table descript ion Row and colum n descript ions Dat a- ent ry area Form ula result area Each sect ion of your t able should be form at t ed wit h a unique st yle t hat you use consist ent ly t hroughout your user int erface. Figure 4- 15 shows a sam ple t able wit h all four of t he elem ent s described above.

Figu r e 4 - 1 5 . A Ba sic W or k sh e e t Use r I n t e r fa ce Ta ble La you t

As you can see, in it s sim plest form t he t able is not very at t ract ive. You can give your t ables a m uch m ore professional appearance by using borders t o provide a 3D effect and sim ulat ed gridlines and by increasing t he row height s and colum n widt hs t o provide m ore visual separat ion. Turning off t he row and colum n headers and t he form ula bar com plet es t he effect . The t able now looks like a com plet ely cust om user int erface. Figure 4- 16 shows t he t able wit h t hese added effect s.

Figu r e 4 - 1 6 . A Fu lly For m a t t e d W or k sh e e t Use r I n t e r fa ce Ta ble

Cell Comments for Help Text Cell com m ent s are one of t he m ost im port ant user int erface feat ures provided by Excel. Their ut ilit y st em s from t he fact t hat in m any cases t hey can serve t he sam e purpose as a help file wit hout

requiring users t o do anyt hing m ore com plicat ed t han hover t heir m ouse cursor over t he com m ent ed cell. Not e t hat cell com m ent s have several lim it at ions t hat m ay m ake t hem inappropriat e in cert ain sit uat ions: I f you are using t he freeze panes feat ure on a worksheet and t he worksheet is scrolled beyond t he freeze point , if t he com m ent window overlaps t he frozen row and/ or colum n it will be cut off at t he point where t he window is frozen. Each cell com m ent is also associat ed wit h a specific st at us bar m essage whose st ruct ure cannot be m odified. The st at us bar m essage displayed when users hover t heir m ouse over a com m ent has t he following st ruct ure, which is shown graphically in Figure 4- 17:

Figu r e 4 - 1 7 . Th e For m a t of a n Ex ce l Com m e n t St a t u s Ba r M e ssa ge

Cell a d d r e ss com m ent ed by u se r n a m e a t t h e t im e t h e com m e n t w a s cr e a t e d The only part of t his m essage you can m odify is t he user nam e at t he t im e t he com m ent was creat ed sect ion, which displays t he cont ent s of t he User nam e ent ry locat ed under t he Tools > Opt ions > General t ab of t he Excel m enu. I f you are a consult ant creat ing a worksheet user int erface for a client , it 's unlikely your client will want t o see your nam e in t he st at us bar each t im e t hey view a cell com m ent . I n t hat case, one of t he best workarounds is t o change t he User nam e set t ing on your m achine t o your client 's com pany nam e while you creat e t he com m ent s for t heir user int erface. Aft er t he com m ent s have been creat ed, t he user nam e displayed in t he st at us bar is fixed and will not be affect ed when you change your User nam e set t ing back t o your own nam e. Rem em ber t hat cell com m ent s can be rich- t ext form at t ed. This m eans you can use form at t ing such as bold and it alic font s wit hin t he com m ent t ext as well as m ult iple font s. Rich- t ext form at t ing enables you t o creat e som e very sophist icat ed help m essages. Figure 4- 18 shows a rich- t ext form at t ed cell com m ent from a real- world worksheet user int erface.

Figu r e 4 - 1 8 . A Rich - Te x t - For m a t t e d Ce ll Com m e n t

Using Shapes The abilit y t o use shapes ( obj ect s drawn using t he various opt ions on t he Drawing or Form s t oolbars) on an Excel worksheet is a very powerful user int erface t echnique. Shapes are locat ed in a special drawing layer t hat exist s above t he cells on a worksheet , so shapes cover ( and obscure) worksheet cells. Shapes are also connect ed t o t he underlying worksheet t hrough t heir propert ies, which allow t hem t o do t he following: Move and size wit h t he worksheet cells t hey cover Move but don't size wit h t he worksheet cells t hey cover Don't m ove or size wit h t he worksheet cells t hey cover Alm ost all shapes can cont ain t ext . A shape's t ext can eit her be m anually ent ered or it can be linked dynam ically t o a specific cell on a worksheet by select ing t he shape and ent ering t he address of t hat cell as a form ula in t he form ula bar. As you can im agine, t he abilit y t o assign form ulas t o shapes opens up a wide array of opt ions for creat ing dynam ic user int erfaces. Shapes can also be given a m acro assignm ent t hat will cause t hem t o execut e t he specified m acro whenever t he user clicks t hem . Just right - click over t he shape and choose Assign Macro from t he short cut m enu. Figure 4- 19 shows an excellent exam ple of how shapes can be used t o creat e a cust om t oolbar- like area across t he t op of a worksheet user int erface.

Figu r e 4 - 1 9 . A Cu st om On - Sh e e t Toolba r Cr e a t e d w it h Sh a pe s [View full size image]

Data Validation Dat a validat ion is one of t he m ost useful yet underut ilized feat ures for worksheet user int erface design. I t enables you t o ensure t hat m ost , if not all, of t he input s m ade in your user int erface are correct by disallowing input t hat does not m at ch t he rules you specify. Dat a validat ion can be as sim ple as rest rict ing cell ent ries t o whole num bers or as com plex as rest rict ing cell ent ries t o it em s on a list whose cont ent s are condit ionally det erm ined based on an ent ry m ade in a previous cell. We assum e you underst and t he basic use of dat a validat ion and inst ead dem onst rat e t wo of t he m ore com plex validat ion scenarios t hat can be creat ed wit h t his feat ure. Most com plex dat a validat ion scenarios involve dat a validat ed list s or cust om dat a validat ion form ulas.

Unique Entries I f you need t he user t o ent er only unique it em nam es in a dat a- ent ry list , you can use a cust om dat a- validat ion form ula t o enforce uniqueness. First select t he ent ire dat a- ent ry area you need t o validat e. Then choose Dat a > Validat ion from t he m enu and select t he Cust om opt ion from t he Allow list . The basic synt ax of t he form ula you need t o ent er is t he following:

=COUNTIF(,)=1

The first argum ent t o t he COUNTI F funct ion is a fixed reference t o t he ent ire dat a- ent ry area t hat m ust cont ain unique ent ries. The second argum ent t o t he COUNTI F funct ion is a relat ive reference t o t he current ly select ed cell in t he dat a- input range. I f each ent ry is unique, t he COUNTI F funct ion evaluat es t o 1 and t he ent ire form ula evaluat es t o True, m eaning t he dat a is valid. I f t he COUNTI F funct ion locat es m ore t han one inst ance of an ent ry in t he dat a- ent ry area t he ent ire form ula will evaluat e t o False and dat a validat ion will prevent t hat ent ry from being m ade. Figure 4- 20 shows an exam ple of t his validat ion set up and Figure 4- 21 shows it in act ion.

Figu r e 4 - 2 0 . D a t a Va lida t ion Con figu r a t ion t o For ce Un iqu e En t r ie s in a List [View full size image]

Figu r e 4 - 2 1 . Un iqu e En t r ie s D a t a Va lida t ion in Act ion

Cascading Lists I n t his t ype of validat ion, t he specific dat a validat ion list t hat is displayed for a cell is det erm ined by t he ent ry select ed in a previous cell. I n Figure 4- 22, t he dat a validat ion list for t he I t em colum n is det erm ined by t he select ion in t he Cat egory colum n. All of t he dat a validat ion list s are locat ed in t he hidden colum n A. The Cat egories list is t he dat a validat ion list for t he Cat egory colum n. The Fruit s list is t he dat a validat ion list for t he I t em colum n when t he Cat egory select ed is Fruit s. The

Veget ables list is t he dat a validat ion list for t he I t em colum n when t he Cat egory select ed is Veget ables.

Figu r e 4 - 2 2 . I n it ia l Se t u p for Ca sca din g D a t a - Va lida t ion List s

The dat a validat ion list form ula for t he Cat egory colum n is sim ple: =$A$3:$A$4. The dat a validat ion list form ula for t he I t em colum n is a bit m ore com plicat ed. I t has t o check t he value of t he corresponding Cat egory ent ry and do one of t hree t hings: display no list if t he Cat egory ent ry has not been select ed, display t he list of fruit s if Fruit s has been select ed or display t he list of veget ables if Veget ables has been select ed. The form ula t hat does all t his is shown below:

=IF(C3=$A$3,$A$7:$A$10,IF(C3=$A$4,$A$13:$A$16,$A$1)))

Not e t he t railing reference t o cell $A$1 in t his form ula. The purpose t his serves is t o creat e an em pt y validat ion list in t he I t em colum n if not hing has been select ed in t he Cat egory colum n. I t wouldn't m ake sense t o allow t he user t o select an I t em prior t o select ing a Cat egory. As Figure 423 shows, t his form ula successfully displays t wo com plet ely different dat a validat ion list s depending on t he cat egory select ion.

Figu r e 4 - 2 3 . Ca sca din g List Va lida t ion in Act ion

This logic can be ext ended t o as m any cat egories as t he m axim um form ula lengt h of 1024

charact ers will allow. However, for cases wit h large num bers of cat egories, a t able- driven approach t hat you'll see used in our sam ple t im esheet applicat ion is m uch easier t o set up and m aint ain. Not e t hat one drawback of t his t ype of validat ion is t hat it doesn't work in bot h direct ions. I n t he scenario described above, t here is not hing t o st op a user from accident ally changing t he cat egory ent ry in a row where a specific it em has already been select ed. I n t he next sect ion we show how t o use condit ional form at t ing t o provide a visual indicat ion t hat t his kind of error has been m ade.

N OTE I n Excel 97 t here is a bug such t hat in m ost circum st ances, dat a- validat ion list s will not funct ion when t he freeze panes feat ure has been applied t o a worksheet .

Conditional Formatting Condit ional form at t ing is one of t he m ost powerful feat ures available for Excel user int erface const ruct ion. I t enables you t o subst it ut e sim ple form ulas for what would ot herwise be ream s of VBA code. Condit ional form at t ing works by m odifying t he appearance of t he cells it has been applied t o only if one or m ore condit ions t hat you specify have been m et . Condit ional form at t ing overrides any st yle set t ing when t he condit ion is t riggered. When t he condit ion t hat t riggered t he condit ional form at t ing is no longer t rue, t he affect ed cell regains it s original form at . The t wo m ost com m on uses for condit ional form at t ing in Excel user int erface developm ent are t he creat ion of dynam ic t ables and calling out error condit ions.

Creating Dynamic Tables When building nont rivial worksheet - based user int erfaces, you will oft en be faced wit h t he problem of providing a t able t hat in ext rem e cases will allow t he ent ry of som e large num ber of rows but for t he m ost com m on scenarios will only require a few. Rat her t han hard- coding a visible t able wit h t he m axim um possible num ber of rows, you can use condit ional form at t ing t o creat e a t able t hat expands dynam ically as dat a is ent ered int o it . We dem onst rat e how t his is done beginning wit h t he sam ple t able shown in Figure 4- 24.

Figu r e 4 - 2 4 . D a t a - En t r y Ta ble Pr ior t o t h e Addit ion of D yn a m ic For m a t t in g

Let 's assum e t his t able really requires 200 rows for t he largest proj ect s but t hat m ost users only need a few rows of input . Therefore, you want t o hide t he unused area of t he t able. As you can see, t he first st ep in creat ing a dynam ic t able is t o draw t he ent ire t able on t he worksheet . You t hen use condit ional form at t ing t o hide t he unused area of t he t able and reveal rows dynam ically as needed. The t rigger for displaying a dat a- ent ry row will be t he user ent ering a new nam e int o t he I t em Nam e colum n. For t hat reason, we always need t o leave an em pt y I t em Nam e ent ry cell at t he bot t om of t he t able. When creat ing a dynam ic t able, it 's a good idea t o also creat e an out line showing t he ext ent of t he t able in one of your hidden colum ns. Aft er we've added t he condit ional form at t ing, t he t able will disappear. This m akes t he t able difficult t o m aint ain if you haven't provided yourself wit h a visual m arker indicat ing it s ext ent . The em pt y bordered area in colum n A serves t his purpose in our exam ple. This area doesn't need t o be em pt y. I t could include error- checking form ulas, for exam ple. As long as it gives you a visual indicat ion of t he ext ent of t he hidden area of t he t able, it serves it s purpose. Our dynam ic t able requires t hree different condit ionally form at t ed sect ions. Referencing Figure 425 , t he first sect ion will encom pass range C3:C12, t he second sect ion will encom pass range D3:F12 and t he t hird range will encom pass range G3:G12. We'll add t he condit ional form at s one st ep at a t im e so you can see t he result s as t hey occur. To m ake t he operat ion of t he condit ional form at s m ore obvious we'll add dat a t o t he first row of t he t able. Keep in m ind t hat t he purpose of all t hree condit ional form at t ing sect ions is t he sam e: t o sim ulat e t he appearance of a t able t hat is j ust large enough t o hold t he dat a t hat has been ent ered int o it . Figure 4- 25 shows t he t able wit h t he first sect ion of condit ional form at t ing com plet ed.

Figu r e 4 - 2 5 . Con dit ion a l For m a t t in g for t h e Fir st Colu m n [View full size image]

I n addit ion t o t he purpose described above, t he first condit ional form at serves t o leave a blank cell in front of t he first unused t able row in order t o help prom pt t he user t o ent er t he next it em . The second condit ional form at is shown in Figure 4- 26. I t clears all unused rows in colum ns D t hrough F and draws a bot t om border below t he first unused row in t he t able, t hereby helping t o com plet e t he t able out line.

Figu r e 4 - 2 6 . Con dit ion a l For m a t t in g for t h e Re m a in in g Colu m n s W it h in t h e Ta ble [View full size image]

You can see t he whit e border on t he far right side of t he t able is m issing in Figure 4- 27. The purpose of t he t hird condit ional form at is t o com plet e t he sim ulat ed t able by drawing t his border. Figure 4- 27 shows t he t hird condit ional form at .

Figu r e 4 - 2 7 . Con dit ion a l For m a t t in g Ou t side t h e Ta ble t o Cr e a t e t h e Righ t - H a n d Bor de r [View full size image]

Figure 4- 28 shows t he fully form at t ed t able wit h som e addit ional ent ries. Each t im e a new ent ry is m ade, t he condit ional form at reveals t he row in which t he ent ry was placed and adds a new prom pt row below it .

Figu r e 4 - 2 8 . Th e Com ple t e D yn a m ica lly For m a t t e d Ta ble

The one m aj or caveat when considering t he use of condit ional form at t ing t o creat e dynam ic t ables is t hat calculat ion m ust be set t o aut om at ic in order for it t o work. I f your user int erface is so calculat ion int ensive t hat you need t o set calculat ion t o m anual, t hen you cannot creat e dynam ic t ables using t his m et hod ( or use any ot her t ype of form ula- based condit ional form at t ing for t hat m at t er) .

Calling Out Error Conditions Condit ional form at t ing can also work alone or in concert wit h form ulas in hidden rows and colum ns t o highlight invalid ent ries as soon as t hey are m ade. This should not be your m et hod of first choice for point ing out dat a- ent ry errors. Always t ry t o use dat a validat ion t o prevent dat a- ent ry errors from being m ade in t he first place. The m ost com m on sit uat ion in which errors cannot be prevent ed by dat a validat ion is when you have t wo dat a- ent ry colum ns such t hat t he ent ry in t he first colum n det erm ines t he allowable ent ries in t he second colum n. I n Figure 4- 29 we revisit our cascading dat a- validat ion list exam ple fr om Figure 4- 22.

Figu r e 4 - 2 9 . Th e Er r or Ch e ck For m u la Colu m n for t h e Con dit ion a l For m a t

Even t hough bot h colum ns' list s are dat a validat ed, an error can creep in if t he user init ially select s a valid cat egory and it em com binat ion but t hen accident ally changes t he cat egory nam e at som e lat er point in t im e. This t ype of m ist ake cannot be prevent ed by dat a validat ion, so we need t o provide som e visual indicat ion t hat t here is a m ism at ch bet ween t he cat egory and it em select ions if t his error occurs. This is a t ask for condit ional form at t ing. As you can see in Figure 4- 29, we've insert ed a second hidden colum n. I n t his colum n we've creat ed an error check for each row t hat verifies t he ent ry select ed in t he I t em colum n is valid for t he select ion in t he Cat egory colum n.

The error check form ula is a bit com plicat ed, so we break it down in List ing 4- 1 . Keep in m ind t hat t he purpose of t he error check form ula is t o ret urn True if t he corresponding row in t he t able has a dat a- ent ry error and False ot herwise.

List in g 4 - 1 . Th e Er r or Ch e ck For m u la Ou t lin e d =IF(ISBLANK(E3),FALSE, IF(D3=$A$3, ISERROR(MATCH(E3,$A$7:$A$10,0)), ISERROR(MATCH(E3,$A$13:$A$16,0)) ) )

The only t ype of error t hat can occur in t his sit uat ion is t he I t em colum n ent ry not m at ching t he Cat egory colum n ent ry. I f t here is no I t em colum n ent ry, t he row is not com plet e and we cannot det erm ine t he validit y of t he Cat egory colum n ent ry. The out er I F funct ion checks for t his condit ion and ret urns FALSE if t his is t he case. When t here is an ent ry in t he I t em colum n, t he inner I F funct ion det erm ines t he correct list from which t o t ry and locat e t he Cat egory ent ry. The form ula t hen uses t he MATCH funct ion wrapped in t he I SERROR funct ion t o ret urn TRUE if t he Cat egory ent ry is locat ed in t he correct list or FALSE if it isn't . The next t hing we do is add a condit ional form at t o t he t able t hat checks t he value of t he HasError colum n. I f t he HasError colum n indicat es t here is an error in one of t he t able rows, our condit ional form at will give t hat row a bright red shade. Error condit ion highlight ing is one except ion t o t he rule of not using garish colors in your user int erface. We do recom m end using red, however, because t his is alm ost universally recognized as a warning color. Figure 4- 30 shows t he condit ional form at required t o accom plish t his.

Figu r e 4 - 3 0 . Se t t in g Up Con dit ion a l For m a t t in g t o Fla g a n Er r or Con dit ion [View full size image]

The result of t he condit ional form at in response t o an error condit ion is shown in Figure 4- 31, where we've changed t he Cat egory colum n ent ry in t he second t able row from Veget ables t o Fruit s so it no longer m at ches t he ent ry in t he I t em colum n.

Figu r e 4 - 3 1 . Con dit ion a l For m a t t in g Fla ggin g a Ba d En t r y in t h e Ta ble

Using Controls on Worksheets Using cont rols placed direct ly on worksheet s is t ypically not t he best user int erface design. For m ost Excel applicat ion developm ent , we recom m end you use cust om com m and bars as ent ry point s int o your code and subst it ut e dat a- validat ion list s for com bo box cont rols. ( Com m and bars are given a full- chapt er t reat m ent in Chapt er 8 Advanced Com m and Bar Handling.) I n som e circum st ances, placing cont rols direct ly on your worksheet user int erface is t he best opt ion, so here we cover som e of t he t hings you need t o wat ch out for when you do t his. When you do need t o use cont rols on a worksheet , you m ust choose bet ween Act iveX cont rols and cont rols from t he Form s t oolbar. As a general rule, we recom m end you use Form s cont rols unless you absolut ely need Act iveX cont rols. Form s cont rols are very light weight and don't exhibit t he m any quirks you'll run int o when using Act iveX cont rols on worksheet s. Figure 4- 32 shows a worksheet in which Form s cont rols have been used t o great effect .

Figu r e 4 - 3 2 . Good Use of For m s Con t r ols on a W or k sh e e t [View full size image]

Because everyone reading t his chapt er should be fam iliar wit h how cont rols work, we j ust cover t he det ails crit ical t o deciding whet her you can use Form s cont rols in your worksheet user int erface or whet her you need Act iveX cont rols.

Advantages of Forms Controls Form s cont rols can be used on Chart sheet s, Act iveX cont rols cannot . Form s cont rols are m ore t ight ly linked t o Excel. You can select a Label or But t on cont rol and ent er a form ula in t he form ula bar t hat will dynam ically set t he capt ions of t hose cont rols. And unlike it s Act iveX count erpart , a Form s cont rol List box will updat e it s cont ent s in response t o changes t o a dynam ic nam ed range t hat has been assigned t o it s I nput range propert y. I t is a sim ple m at t er t o assign m ult iple Form s cont rols t o run t he sam e VBA procedure. Doing t he sam e wit h Act iveX cont rols requires a m ore com plicat ed class- based approach. I f you use m ult iple windows or t he split - panes feat ure in your applicat ion t o show t wo different views of t he sam e worksheet , Act iveX cont rols will only work in t he original window. Form s cont rols will work in any window.

Advantages of ActiveX Controls You can m odify t he appearance of Act iveX cont rols t o a m uch great er degree t han Form s cont rols. There are m ore variet ies of Act iveX cont rols t han t here are Form s cont rols. Act iveX cont rols have a wide variet y of event procedures t hat you can respond t o, whereas Form s cont rols can only run a single m acro.

N OTE I f you use Act iveX cont rols on worksheet s in Excel 97, you will frequent ly run int o problem s wit h VBA code t hat will not run in response t o a cont rol being select ed. This is because t he select ed cont rol has " st olen" t he focus from t he worksheet . Wit h t he except ion of t he Com m andBut t on cont rol, which has a TakeFocusOnClick propert y t hat can be set t o False t o elim inat e t his problem , t he first line of code associat ed wit h an Act iveX cont rol on a worksheet under Excel 97 should select a cell on t he worksheet t o ret urn t he focus t o it .

Practical Example I n t his sect ion we begin building a real- world Excel applicat ion t hat illust rat es t he point s m ade in t he chapt er t ext . Our applicat ion will be a t im e- t racking syst em t hat will st art as a sim ple, no- frills t im esheet and work it s way up t o being a full- feat ured Excel applicat ion as we progress t hrough t he book. Due t o space const raint s, we do not show every det ail involved in creat ing t his applicat ion. We dem onst rat e t he m aj or feat ures and allow you t o exam ine t he rest by perusing t he finished sam ple of t he applicat ion t hat is available on t he accom panying CD. This t im esheet applicat ion will hencefort h be referred t o by it s acronym PETRAS, which st ands for Professional Excel Tim esheet Report ing and Analysis Syst em . The first version of PETRAS will be a sim ple workbook cont aining a t im e- ent ry t able on one worksheet and dat a- validat ion list s on a second hidden worksheet . The user will be expect ed t o com plet e t he t im e- ent ry t able each week and m anually copy t he workbook t o a cent ral locat ion for consolidat ion. You can find t his version of PETRAS on t he accom panying CD in t he \ Applicat ion\ Ch04- Worksheet Design\ folder. I t is displayed in Figure 4- 33.

Figu r e 4 - 3 3 . Th e Fir st Ve r sion of t h e PETRAS Applica t ion [View full size image]

Most of t he user int erface design t echniques t hat have been discussed in t his chapt er have been used in t he PETRAS applicat ion, including all variat ions of defined nam es, st yles t o different iat e

areas by purpose, t able form at t ing t echniques, use of com m ent s for help t ext , dat a validat ion and condit ional form at t ing. Let 's quickly cover exam ples of how each of t hese t echniques is used in pr act ice.

Hidden Rows and Columns We've t aken advant age of hidden rows and colum ns in t he PETRAS applicat ion for t wo purposes: error checking and background dat a processing. Figure 4- 34 shows an open version of t he PETRAS user int erface workbook.

Figu r e 4 - 3 4 . Th e PETRAS Applica t ion w it h a ll Row s a n d Colu m n s Visible [View full size image]

This worksheet has t wo t ypes of hidden colum ns. The t wo init ial hidden colum ns are what we called program colum ns early in t he chapt er. We also have t wo hidden colum ns in t he m iddle of t he user int erface. These t wo colum ns are used t o creat e a dat a t able t hat m akes t he process of aut om at ically consolidat ing dat a sim pler, while not requiring t he user t o ent er duplicat e dat a for each row. As you'll see in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins, we will have special- purpose code t hat uses t he set HideCols nam ed range, shown in t he first row, t o ensure t hese colum ns are hidden.

Defined Names The Tot al Hours colum n in Figure 4- 33 is calculat ed using a nam ed form ula called forTimeDiff.

We used a defined form ula for t his purpose because t he logic required is com plex and t herefore it m akes sense t o encapsulat e it . The forTimeDiff nam ed form ula m akes use of relat ive defined nam es t o reference each part of t he row from which it needs t o gat her t he dat a required t o perform it s calculat ion. List ing 4- 2 shows t his defined form ula.

List in g 4 - 2 . Th e forTimeDiff N a m e d For m u la =IF(COUNTA(inpEntryRow)inpStart, inpStop-inpStart, (1+inpStop)-inpStart ) )

The input - t ype defined nam es ( t hose wit h t he inp prefix) are all row- relat ive defined nam es t hat refer t o fixed colum ns on t he Tim eEnt ry worksheet , as follows: inpEnt ryRow = Tim eEnt ry! $F3: $K3 inpSt art = Tim eEnt ry! $J3 inpSt op = Tim eEnt ry! $K3 I f t here are fewer t han six ent ries in t he current row, t he form ula sim ply ret urns an em pt y st ring. We cannot allow t ot al hours t o be calculat ed for a row t hat has not been com plet ed. Aft er all of t he ent ries in a row have been com plet ed, we m ust com pare t he st art and st op t im es. These t im es are ent ered as Excel dat e serial t im e values; t herefore t hey are decim al values less t han or equal t o 1 t hat have no indicat ion of t he dat e worked. We set up t he t im esheet in t his m anner as a convenience t o t he user. I t allows t he user t o sim ply ent er a st art t im e and a st op t im e wit hout also having t o ent er a specific dat e for each t im e. I f t he st op t im e is great er t han t he st art t im e we know bot h ent ries refer t o t he sam e day. We can t hen j ust subt ract t he st art t im e from t he st op t im e t o calculat e t he num ber of hours worked. I f t he st op t im e is less t han or equal t o t he st art t im e, we know t he user began working prior t o m idnight on one day and finished working aft er m idnight on t he next day. I n t his case, we add 1 t o t he st op t im e, which is equivalent t o adding one day in t he Excel dat e serial form at , t o force it t o be great er t han t he st art t im e. We t hen subt ract t he st art t im e from t he result . This enables us t o account for sit uat ions in which users work past m idnight .

Styles Not e t hat PETRAS uses t he sam e st yles we int roduced in Figure 4- 8 . We use separat e st yles t o ident ify row and colum n headers, input areas, form ula result s and areas t hat are out side t he user int erface. The Tim eEnt ry worksheet in Figure 4- 33 is designed t o be prot ect ed, and once prot ect ed, t he only cells t hat can be m odified by t he user are cells having t he I nput st yle ( t he st yle wit h t he whit e background) .

User Interface Drawing Techniques The PETRAS applicat ion dem onst rat es t wo of our recom m ended user int erface drawing t echniques. As shown in Figure 4- 33, we've used borders t o give t he t im e- ent ry t able a 3D appearance and a sim ulat ed grid t o help guide t he user. We've also provided cell com m ent s t o answer t he m ost com m on quest ions t he user m ay have about t he user int erface. Figure 4- 35 shows t he cell com m ent describing t he Day colum n.

Figu r e 4 - 3 5 . A Ce ll Com m e n t Use d a s H e lp Te x t

Data Validation Dat a validat ion has been used in every input cell in t he PETRAS user int erface. Most of t he dat a validat ion derives from dynam ic list s st ored on t he hidden wksProgram Dat a worksheet , part of which is shown in Figure 4- 36.

Figu r e 4 - 3 6 . Th e H idde n w k sPr ogr a m D a t a W or k sh e e t [View full size image]

The Consult ant s colum n on t he wksProgram Dat a worksheet provides t he dat a- validat ion list for t he Consult ant ent ry on t he Tim eEnt ry worksheet . Sim ilarly, t he Act ivit ies colum n on t he wksProgram Dat a worksheet provides t he dat a- validat ion list for t he Act ivit y colum n on t he Tim eEnt ry worksheet and so on. A com plet e pict ure of t he various dat a validat ion t echniques used on t he Tim eEnt ry worksheet can be gained by exam ining t he sam ple applicat ion. Not e t hat a m ore com plex exam ple of t he cascading list s dat a- validat ion t echnique described earlier in t his chapt er is used t o connect t he Client and Proj ect colum ns on t he Tim eEnt ry worksheet .

Conditional Formatting I n Figure 4- 33, you can see t hat condit ional form at t ing has been used t o provide a clear visual indicat ion of t im e ent ries t hat were m ade on a weekend. This is because work done on weekend days t ypically cost s a higher hourly rat e t han work done on a weekday. Condit ional form at t ing is also used t o call out t he error condit ion creat ed when t he user changes t he first colum n ent ry of a cascading validat ion list pair if t he second ent ry has already been m ade. I n Figure 4- 37 below, t he user has m ist akenly changed a Client ent ry t o a client t hat does not m at ch t he Proj ect ent ry previously m ade. Not e how condit ional form at t ing m akes it inst ant ly recognizable t hat changing t he client ent ry was t he wrong t hing t o do in t his case.

Figu r e 4 - 3 7 . Con dit ion a l For m a t t in g N ot ifie s t h e Use r of a D a t a - En t r y Er r or [View full size image]

Conclusion We've discussed m any user- int erface building t echniques in t his chapt er; all of t hem im plem ent ed using Excel's built - in feat ures. However, don't lose sight of t he fact t hat t he m ost im port ant t hing about an Excel user int erface is not how m any cool t echniques you've used. Users don't care about cool t echniques. They want an int uit ive user int erface t hat m akes it easy for t hem t o get t heir j ob done. I deally your user int erface should not draw at t ent ion t o it self at all. I t should j ust be so well designed and const ruct ed t hat users can dive right in and st art working wit hout having t o spend any significant t im e figuring t hings out . Adhering t o t he eight principles described at t he beginning of t his chapt er can help you design user int erfaces t hat do t heir j ob so well no one not ices t hem . This is t he best user int erface design of all.

Chapter 5. Function, General and Application-Specific Add-ins Add- ins are t he prim ary const it uent s of m ost nont rivial Excel applicat ions. This chapt er discusses t he m ost im port ant dut ies add- ins perform wit hin an Excel applicat ion, as well as det ails about t he act ivit ies various t ypes of add- in m ust perform . This chapt er does not cover dict at or applicat ions, as t hat is t he subj ect of t he next chapt er.

The Four Stages of an Application Every applicat ion has four dist inct st ages, regardless of t he t ype of add- in used t o im plem ent it . These st ages are developm ent / m aint enance, st art up, runt im e and shut down. This sect ion briefly discusses all four st ages and ident ifies t he act ivit ies and services t hat m ust be provided by t he applicat ion during each st age. Som e of t he t opics covered do not apply t o all t ypes of applicat ions, but we cover t hem all t o give you a com plet e high- level overview of what an applicat ion m ust accom plish. We do not go int o great det ail on t he t opics covered in t his sect ion. Som e will be obvious t o readers of t his book and ot hers are covered ext ensively eit her lat er in t his chapt er or in lat er chapt ers of t he book.

Development/Maintenance During t his st age you are eit her writ ing t he applicat ion's code for t he first t im e or updat ing exist ing code in t he applicat ion. Eit her way, t he purpose of t his st age is t o build or fix t he applicat ion rat her t han t o run it . You can m ake your life easier during t his st age by using VBA code t o help build and m aint ain t he applicat ion you are writ ing. There are t wo m aj or cat egories of code t hat helps t o build code: Code t e m pla t e s These can be as sim ple as basic subrout ine and funct ion fram eworks m anually copied from a st ored m odule, or as com plex as t hird- part y code- generat ion t ools. The Excel Visual Basic Edit or ( VBE) provides a very rudim ent ary t ool for creat ing t em plat e subrout ines, funct ions and propert y procedures t hrough t he I nsert > Procedure m enu. D e ve lopm e n t u t ilit ie s You should st rive t o aut om at e as m any rout ine developm ent processes as possible. Your applicat ion should cont ain a dedicat ed code m odule, or even a separat e ut ilit y applicat ion, for VBA ut ilit ies t hat assist you in creat ing and m aint aining t he applicat ion. I n t he A Table- Driven Approach t o UI Worksheet Managem ent sect ion lat er in t he chapt er, we dem onst rat e a ut ilit y for aut om at ically m anaging t he set t ings on your user int erface worksheet s.

Startup When your applicat ion is st art ing up, it m ust perform a num ber of t asks depending on what t ype of applicat ion it is and t he condit ions it finds during t he st art up process. Ch e ck t h e e n vir on m e n t Check any environm ent al condit ions t hat m ust be sat isfied in order for your applicat ion t o run. This m ight include verifying t hat t he appropriat e version of Windows and Excel are inst alled as well as verifying t he exist ence of any addit ional program s and files your applicat ion depends on. I f t he st art up check fails, you can exit gracefully wit h a clear error m essage t o t he user rat her t han allowing your applicat ion t o cont inue unt il it encount ers a runt im e error.

Sa ve a ll se t t in gs t h a t m u st be r e st or e d on e x it I f your applicat ion m odifies t he user's Excel environm ent , it m ust save t he original set t ings so t hey can be rest ored prior t o exit ing. This t opic is covered ext ensively in Chapt er 6 Dict at or Applicat ions. Bu ild a n y dyn a m ic u se r in t e r fa ce e le m e n t s These include applicat ion- specific com m and bars, Excel Applicat ion- level set t ings, workbook t em plat es and so fort h. Re gist e r a n y u se r - de fin e d fu n ct ion s I f your add- in cont ains user- defined funct ions ( UDFs) you want t o expose t o t he user, you need t o add som e basic inform at ion about t hem t o t he Excel Funct ion Wizard. We cover t his t opic in t he Funct ion Library Add- ins sect ion lat er in t he chapt er . Se t t h e in it ia l u se r in t e r fa ce con figu r a t ion The specific set t ings m ade will depend on t he t ype of add- in and t he condit ions discovered at st art up. For exam ple, if t here were an applicat ion workbook open t hat belonged t o your applicat ion when t he add- in was opened, you would enable all of your applicat ion's m enu bars and t oolbars. Ot herwise you would probably disable m ost of t hem . This t ype of dynam ic com m and bar m odificat ion is covered in t he Pract ical Exam ple sect ion of Chapt er 7 Using Class Modules t o Creat e Obj ect s.

Runtime Runt im e is t he st age during which your applicat ion is perform ing t he operat ions t hat const it ut e it s prim ary purpose. H a n dle r e qu e st s fr om t h e u se r These include calls generat ed by com m and bar cont rols, Form s cont rols on worksheet s, Act iveX cont rols on userform s and worksheet s and any keyboard short cut s your applicat ion has provided for t he user. H a n dle Ex ce l a pplica t ion e ve n t s During runt im e your applicat ion m ust also be prepared t o respond t o ( and in som e cases suppress) event s generat ed by Excel it self. Excel applicat ion event handling is covered ext ensively in Chapt er 7 Using Class Modules t o Creat e Obj ect s. H a n dle r u n t im e e r r or s Alt hough we would like our applicat ions t o run flawlessly all t he t im e, every applicat ion event ually encount ers a runt im e error. These errors cannot be allowed t o st op your applicat ion dead in it s t racks. I nst ead, t hey m ust be handled gracefully and in such a way t hat t he user has som e idea of what went wrong. Error handling is covered ext ensively in Chapt er 12 VBA Error Handling . Ca ll code loca t e d in ot h e r a dd- in s I f you have set a reference t o anot her add- in using t he Tools > References m enu in t he VBE during developm ent , you can call public procedures locat ed in st andard m odules in t he referenced add- in direct ly by nam e. Wit hout references, you can accom plish t he sam e t hing by using t he Application.Run funct ion. Pr ovide ot h e r se r vice s Add- ins also provide ot her services at runt im e, t he m ost com m on being UDFs. We cover UDFs in det ail in t he Funct ion Library Add- ins sect ion lat er in t his chapt er .

Shutdown

The shut down st age is when your applicat ion is exit ing, eit her norm ally at t he request of t he user or abnorm ally as t he result of an error condit ion. Eit her way t here are act ivit ies t hat m ust be perform ed at t his st age. Un r e gist e r a n y u se r - de fin e d fu n ct ion s I f your add- in regist ered any UDFs wit h t he Excel Funct ion Wizard on st art up, it should unregist er t hese funct ions on shut down. Re m ove a ll a pplica t ion - spe cific u se r in t e r fa ce com pon e n t s This m eans rem oving all t he applicat ion- specific it em s creat ed during t he st art up phase ( com m and bars, applicat ionspecific workbooks and so fort h) . Re st or e t h e or igin a l e n vir on m e n t I f your applicat ion m ade any persist ent changes t o t he Excel environm ent , it m ust save t he original set t ings on st art up and rest ore t hem on shut down. This process is generically known as saving and rest oring t he user's workspace. This t opic is covered ext ensively in Chapt er 6 Dict at or Applicat ions.

Function Library Add-ins I t is quit e com m on t o encount er VBA add- ins t hat serve no ot her purpose t han t o provide a library of UDFs. These add- ins are called funct ion library add- ins. Add- ins are t he best cont ainer for host ing VBA user- defined funct ions because as long as t he user has t he add- in cont aining t he funct ions open, t hose funct ions will be available t o all current ly open workbooks. UDFs locat ed in a specific workbook are only available t o worksheet s in t hat workbook. Funct ion library add- ins are t he sim plest t ype of add- in from t he perspect ive of t he operat ional t asks t hey m ust accom plish. Alt hough t he funct ions it cont ains m ay be quit e com plex, t he funct ion library add- in it self has only t wo responsibilit ies: regist ering it s UDFs wit h t he Excel Funct ion Wizard on st art up and unregist ering t hem on shut down. I n t his sect ion, we first creat e a sam ple UDF and t hen show t he opt ions available t o t he add- in for handling it s regist rat ion dut ies.

An Example UDF A com m on sit uat ion encount ered when creat ing worksheet m odels is t he need t o use a com binat ion of t he I F and I SERROR worksheet funct ions t o t est t he result of anot her funct ion for an error condit ion. I f t he funct ion being t est ed evaluat es t o an error value, you const ruct t he I F funct ion t o ret urn som e default value in it s place. I f t he funct ion being t est ed does not evaluat e t o an error value, you const ruct t he I F funct ion t o execut e t he funct ion being evaluat ed a second t im e and ret urn it s result . When t he funct ion being t est ed is very long and/ or com plex, t he result ing form ula is doubly long and/ or com plex because you m ust evaluat e t he funct ion being t est ed t wice. This sit uat ion can be generalized by t he following pseudo- form ula:

=IF(ISERROR(),,)

I n t his sect ion, we writ e a UDF t hat perform s t his operat ion wit h j ust one pass of t he funct ion being evaluat ed. We'll call our UDF I FERROR and it s synt ax will be t he following:

=IFERROR(,)

List ing 5- 1 shows t he VBA code required t o im plem ent our I FERROR funct ion.

List in g 5 - 1 . Th e I FERROR Use r - D e fin e d Fu n ct ion

Public Function IFERROR(ByRef ToEvaluate As Variant, _ ByRef Default As Variant) As Variant If IsError(ToEvaluate) Then IFERROR = Default Else IFERROR = ToEvaluate End If End Function

The ToEvaluate argum ent is a value, cell reference or direct ly ent ered funct ion expression t o be evaluat ed. I f ToEvaluate cont ains an error value, t he Default argum ent is ret urned, ot herwise ToEvaluate is ret urned. The Default argum ent can also be a value, cell reference or direct ly ent ered expression. Bot h argum ent s and t he funct ion ret urn value of t he I FERROR funct ion are specified as Variant dat a t ypes in order t o provide t he m axim um flexibilit y in t he t ypes of argum ent s t he funct ion can accept and ret urn. As discussed in Chapt er 3 Excel and VBA Developm ent Best Pract ices, t he Variant dat a t ype can have a negat ive im pact on perform ance. I f you know, for exam ple, t hat you will always be passing cell references t o bot h I FERROR argum ent s, you can significant ly im prove t he perform ance of t he funct ion by changing t he dat a t ype of it s argum ent s and ret urn value t o t he Range dat a t ype.

UDF Naming Conventions Cust om worksheet funct ions and t heir argum ent s ( if any) should be given reasonably short descript ive nam es. You should do your best t o m ake your UDFs look and feel like built - in Excel worksheet funct ions. Therefore, you should not apply t he nam ing convent ions described in Chapt er 3 Excel and VBA Developm ent Best Pract ices t o UDFs.

Making Your UDF Appear Native You can m ake your UDFs appear m ore like nat ive Excel funct ions by regist ering t hem wit h t he Excel Funct ion Wizard. This involves giving t hem descript ions and assigning t hem t o cat egories t hat will assist t he user in figuring out how t o use t hem . There are t wo ways t o do t his; t he first is sim ple but lim it ed, t he second com plex but com plet e. The first way is t o use t he Application.MacroOptions m et hod. The m aj or advant ages of t he Application.MacroOptions m et hod are t he relat ively lengt hy funct ion descript ion allowed and t he fact t hat it rem oves your UDF from t he default User Defined cat egory when it places it under t he cat egory you specify. The disadvant ages of t his m et hod are t hat t he funct ion descript ion and cat egory are t he only opt ions you can specify and you cannot creat e cat egories t hat don't already exist in t he Funct ion Wizard. List ing 5- 2 shows an Aut o_Open procedure t hat uses t he Application.MacroOptions m et hod t o regist er our I FERROR funct ion.

List in g 5 - 2 . Re gist e r in g a UD F w it h Applica t ion .M a cr oOpt ion s

Sub Auto_Open() Dim sDescription As String sDescription = "Provides a short-cut replacement " & _ "for the common worksheet function construct:" & _ vbLf & "=IF(ISERROR(),,)" Application.MacroOptions Macro:="IFERROR", _ Description:=sDescription, _ Category:=9 End Sub

Excel's funct ion cat egories are specified by num eric values t hat correspond t o t he posit ion of t he cat egory in t he Excel Funct ion Wizard cat egory list , where All = 0, Financial = 1 and so on. I f you do not specify a cat egory num ber, your UDF will be assigned t o cat egory 14, User Defined, by default . I f you specify a cat egory num ber t hat does not exist , a runt im e error will occur. Table 5- 1 shows t he full set of available cat egory num bers, along wit h t heir corresponding cat egory nam es. Not all of t hese cat egories are com m only used.

Ta ble 5 - 1 . UD F Fu n ct ion Ca t e gor y N u m be r s a n d N a m e s Ca t e gor y N um ber

Ca t e gor y N a m e

0

All

1

Financial

2

Dat e & Tim e

3

Mat h & Trig

4

St at ist ical

5

Lookup & Reference

6

Dat abase

7

Text

8

Logical

9

I nfor m at ion

10

Com m ands

11

Cust om izing

12

Macro Cont rol

Ca t e gor y N um ber

Ca t e gor y N a m e

13

DDE/ Ex t er nal

14

User Defined

List ing 5- 3 shows an Aut o_Close procedure t hat uses t he Application.MacroOptions m et hod t o unregist er our I FERROR funct ion. The only drawback t o t his m et hod is it leaves your funct ion nam e list ed in t he All cat egory wit h no descript ion.

List in g 5 - 3 . Un r e gist e r in g a UD F w it h Applica t ion .M a cr oOpt ion s Private Sub Auto_Close() Application.MacroOptions Macro:="IFERROR", _ Description:=Empty, _ Category:=Empty End Sub

Keep in m ind t hat t he Application.MacroOption exam ples shown above regist er and unregist er a single funct ion. I f your add- in cont ains m ult iple UDFs, you will need t o add one call t o t he Application.MacroOptions m et hod for each UDF in bot h t he Aut o_Open and t he Aut o_Close pr ocedur e. The second way t o provide descript ions for your UDFs requires you t o execut e an XLM m acro funct ion t o bot h regist er and unregist er t hem . XLM is t he nat ive Excel program m ing language t hat predat es VBA but is st ill support ed in Excel. More t han t en years aft er it supposedly becam e obsolet e, t here are st ill t hings t hat XLM does bet t er t han VBA, and t his is a good exam ple. The advant age of t his m et hod is it gives you com plet e cont rol over all aspect s of t he descript ion and cat egorizat ion of your funct ion. The disadvant age of t his m et hod is t he XLM m acro st ring, which m ust cont ain all nam es, descript ions and ot her inform at ion, is lim it ed t o 255 charact ers in lengt h. This m eans your descript ions m ust be kept short . Your UDF will also cont inue t o appear in t he default User Defined cat egory even t hough it also appears in any new cat egory t hat you specify. Credit for originally devising t his t echnique goes t o worksheet funct ion expert Laurent Longre. The code required t o dem onst rat e t his m et hod will not fit wit hin t he lim it ed confines of a print ed page, so you will need t o exam ine t he MRegist er m odule in t he Funct ion.xls workbook locat ed on t he CD in t he Concept s folder for t his chapt er t o see how it works. The code in t his m odule is com m ent ed ext ensively t o help you underst and it and is designed so t he ent ire m odule can be copied int o anot her proj ect and work correct ly. You will j ust need t o m odify t he funct ion descript ions and add room for addit ional funct ions t o suit your needs. One procedure call placed in your add- in's Aut o_Open procedure will regist er all of your UDFs and one procedure call placed in your add- in's Aut o_Close procedure will unregist er all of your UDFs.

N OTE I f you do not do anyt hing t o prevent it , any public funct ion in your add- in will aut om at ically be list ed in t he User Defined cat egory in t he Excel Funct ion Wizard. This will occur even if your funct ion isn't designed t o be used as a worksheet funct ion at all. The solut ion t o t his problem is t o add t he Option Private Module direct ive t o t he t op of any m odule t hat cont ains public funct ions. This will not prevent public worksheet funct ions from being used as such, but it will prevent t hem from being aut om at ically added t o t he User Defined funct ions cat egory.

Creating a Friendly Name and Description for Your Function Library Addin Funct ion library add- ins are t ypically placed in t he add- ins list of t he Excel Add- ins dialog accessed t hrough t he Tools > Add- ins m enu. This enables t he user t o easily load and unload t hem as t he need arises. We discuss t he various ways of m aking your add- in appear in t he Tools > Add- ins dialog in Chapt er 24 Providing Help, Securing, Packaging and Dist ribut ing. You should provide a friendly nam e and a short descript ion for any add- in t hat appears in t he Add- ins dialog. These can be m ade t o appear when t he add- in's ent ry is select ed by set t ing t wo specific file propert ies of t he add- in workbook. First , set t he I sAddin propert y of t he add- in's ThisWorkbook obj ect t o False so you can access t he add- in workbook from t he Excel user int erface. Then choose File > Propert ies from t he Excel m enu. On t he Sum m ar y t ab of t he result ing Propert ies dialog, you provide a friendly nam e for your add- in using t he Tit le ent ry. The descript ion for your add- in is ent ered in t he Com m ent s field. Figure 5- 1 shows t he nam e and descript ion for our sam ple funct ion library add- in.

Figu r e 5 - 1 . Addin g a N a m e a n d D e scr ipt ion t o a n Add- in

Figure 5- 2 shows how t he nam e and descript ion added in t he Propert ies dialog appear in t he Addins dialog.

Figu r e 5 - 2 . Th e Add- in N a m e a n d D e scr ipt ion in t h e Add- in s D ia log

Critical UDF Details The following are som e crit ical det ails you need t o underst and in order t o develop VBA user- defined funct ions. One of t he m ost com m on m ist aken beliefs about UDFs is t hat t hey can change t he value of cells ot her t han t he one t hey've been ent ered int o. This is not t he case. Whet her a UDF is program m ed in a VBA add- in ( described in t his chapt er) a VB6 aut om at ion add- in ( described in Chapt er 21 Writ ing Add- ins wit h Visual Basic 6) or a C/ C+ + XLL ( described in Chapt er 19 XLLs and t he C API ) , a user- defined funct ion can only m odify t he value of t he cell int o which it has been ent ered. A UDF cannot change any propert ies of t he cell it has been ent ered int o ot her t han t he value of t hat cell. At t em pt ing t o set t he pat t ern or borders of a cell from wit hin a UDF, for exam ple, will not work, alt hough neit her does it cause a VBA or funct ion ret urn value error. UDFs m ust be locat ed in st andard code m odules. They cannot be placed in class m odules, userform s or t he code m odules behind workbooks or worksheet s. Do not at t em pt t o change t he values of UDF argum ent s t hat are declared ByRef. As we discuss in a m om ent , UDFs can only change t he value of t he cell int o which t hey have been ent ered. At t em pt ing t o m odify t he value of a ByRef argum ent violat es t his principle and will cause your UDF t o ret urn a # VALUE! error if you at t em pt t o m odify a ByRef argum ent t hat has been declared as a Range obj ect . Put all range references used by your funct ion in t he funct ion's argum ent list . I f you refer t o ranges not in t he argum ent list from wit hin your UDF, changes t o t hose ranges will not cause your UDF t o recalculat e, possibly leading t o incorrect result s being displayed. You can use t he

Application.Volatile m et hod t o force your UDF t o recalculat e whenever calculat ion is t riggered anywhere in Excel, but t his can cause serious degradat ion of calculat ion perform ance and som e t ypes of worksheet event handling and should be used only as a last r esor t .

VBA UDF Problems The biggest problem wit h m ost VBA UDFs is t hat using t hem creat es hard- coded links from t he workbooks where t hey are used t o t he add- in t hat cont ains t hem . I f you physically m ove t he source add- in, workbooks t hat use t he funct ions it cont ains will not be able t o locat e it , even if t he add- in is opened prior t o opening any workbooks t hat use it s funct ions. I f you use t he XLM UDF regist rat ion m et hod described in t he sect ion on Creat ing a Friendly Nam e and Descript ion for Your Funct ion Library Add- in, you can avoid t his problem . VBA funct ions also do not aut om at ically capit alize correct ly when you ent er t hem int o a worksheet cell. Capit alizat ion does not affect t he operat ion of t he funct ion, but it gives t he funct ion a st range appearance. And aft er you have ent ered a UDF in all lowercase charact ers, you will find it alm ost im possible t o get it t o convert t o uppercase charact ers even when it is defined t hat way in t he source code in t he add- in.

TI P When writ ing any worksheet funct ion for Excel 97, always use an error handler. An unhandled error t hat occurs inside a UDF in Excel 97 for any reason will cause m any different problem s depending on how t he funct ion calculat ion was t riggered. The worst of t hese problem s will halt your VBA program in it s t racks if t he calculat ion was t riggered by VBA code.

General Add-ins General add- ins, also known as ut ilit y add- ins, are designed t o enhance Excel by ext ending it s feat ure set or providing connect ions bet ween it and ot her program s. All Excel ut ilit y add- ins fall int o t his cat egory, including m ost of t he add- ins you will find in t he Tools folder of t he CD t hat accom panies t his book. Like funct ion library add- ins, general add- ins are designed t o work wit h any arbit rary workbook t he user opens. General add- ins are t ypically cont ained wit hin a single .xla workbook, alt hough larger exam ples m ay be dist ribut ed across m ult iple files. General add- ins are t ypically placed in t he add- ins list of t he Excel Add- ins dialog so t he user can easily load and unload t hem as t he need arises. They are provided wit h a friendly nam e and descript ion in exact ly t he sam e way as described for a funct ion library add- in in t he previous sect ion. The m ost com m on m et hod for providing t he user access t o feat ures in a general add- in is t hrough a m enu and/ or t oolbar. Event handling is also frequent ly used t o respond t o user act ions, while keyboard short cut s can be provided t o run com m only used feat ures. Because general add- ins m ust operat e correct ly no m at t er what st at e Excel is current ly in, any event handling class you use m ust respond t o changes in t he Excel environm ent t hat would prevent your add- in from operat ing correct ly. An exam ple would be t he user closing t he last open workbook. I n response t o t his sit uat ion, your event handler should disable access t o t he feat ures of your add- in t hat require an open workbook t o funct ion correct ly. Event handling is covered in m ore det ail in Chapt er 7 Using Class Modules t o Creat e Obj ect s. The individual ent ry- point procedures of your add- in m ust also verify t hat t he current st at e of Excel is valid for t hem t o run. For exam ple, if a procedure is designed t o operat e on a chart , but t here is no chart current ly act ive, your procedure m ust det ect t his and provide t he user wit h an explanat ory error m essage rat her t han falling over wit h a runt im e error caused by an at t em pt t o reference a nonexist ent chart .

Application-Specific Add-ins Applicat ion- specific add- ins differ from t he previous t wo add- in t ypes in t hat t hey are designed t o im plem ent self- cont ained Excel applicat ions. They m ay int egrat e wit h t he st andard Excel user int erface, as does t he add- in shown in t he Pract ical Exam ple sect ion lat er in t he chapt er, or t hey m ay t ake over t he Excel user int erface ent irely, as dem onst rat ed in Chapt er 6 Dict at or Applicat ions. I n eit her case, an applicat ion- specific add- in is designed t o operat e only on workbooks t hat have been specifically designed for it . St ill, m ost of t he sam e operat ions and requirem ent s apply t o applicat ion- specific add- ins as apply t o funct ion libraries and general add- ins. Applicat ion specific add- ins sim ply add an addit ional elem ent , t he worksheet user int erface.

A Table-Driven Approach to UI Worksheet Management A significant part of t he responsibilit y of an applicat ion- specific add- in is t o m anage t he user int erface workbook and worksheet set t ings. I t 's possible t o st ore, apply and rem ove t hese set t ings on an ad hoc basis, but when dealing wit h large and/ or com plex user int erfaces it is m uch bet t er t o let VBA do t he work for you. I n t his sect ion, we dem onst rat e a t able- driven approach t o m anaging worksheet user int erface set t ings. Typically, a num ber of set t ings m ust be m ade prior t o your applicat ion being run by t he end user. However, t hese set t ings will get in your way during developm ent . The solut ion is t o creat e an aut om at ed syst em for defining, applying and rem oving t hese set t ings. This is j ust one of m any areas in Excel developm ent t hat lends it self t o a t able- driven m et hodology.

Table-Driven Methodology Defined I n a nut shell, t able- driven m et hods use a worksheet t able t o st ore dat a t hat describes t he t ask you are t rying t o accom plish. One or m ore VBA procedures read t he dat a from t he t able and aut om at ically perform t hat t ask. The biggest advant age of a t able- driven m et hod for accom plishing a specific t ask is it t ends t o be easily reusable from proj ect t o proj ect . Com m on t asks t hat lend t hem selves t o t able- driven solut ions are m anaging workbook and worksheet user int erface set up, building com m and bars and saving and rest oring t he user's workspace. We even dem onst rat e a t able- driven m et hod for creat ing userform s in Chapt er 10 Userform Design and Best Pract ices.

Typical Worksheet User Interface Settings A num ber of set t ings or configurat ion det ails t end t o be com m on t o all worksheet user int erfaces, including t he following

H idde n r ow s a n d colu m n s As discussed in Chapt er 4 Worksheet Design, having hidden rows and colum ns at your disposal is a valuable user int erface const ruct ion t echnique. However, you don't want t hese rows and colum ns t o be hidden when you are perform ing developm ent or m aint enance work on t he user int erface. Pr ot e ct ion Workbook and worksheet prot ect ion are fundam ent al t o good user int erface design. Prot ect ing t he user int erface prevent s users from m odifying areas of t he user int erface t hat should not be m odified. Scr oll a r e a Set t ing a scroll area for each user int erface worksheet prevent s users from get t ing lost by prevent ing t hem from scrolling beyond t he area used by your applicat ion. En a ble se le ct ion This propert y works wit h t he scroll area propert y t o keep t he user focused on your user int erface. I t prevent s t he user from even select ing cells t hat are out side t he boundaries of your UI . Row a n d colu m n h e a de r s Alt hough t here are som e except ions, you t ypically do not want t o display Excel's row and colum n headers on your user int erface worksheet s. Row and colum n headers serve as guidelines for const ruct ing and m aint aining a user int erface, so t hey should be visible during t hat process. I n m ost well- designed user int erfaces, however, t hey will j ust be a dist ract ion t o t he user. Therefore, you want t hem visible during developm ent and hidden at runt im e. Sh e e t visibilit y I n m ost nont rivial workbook- based user int erfaces, you will have one or m ore worksheet s t hat are designed t o perform background t asks t hat should not be seen or m odified by t he user. Once again, however, you want t hese sheet s t o be visible during developm ent and m aint enance.

The Settings Table Let 's see how a t able- driven m et hodology can help us creat e and m anipulat e t he user int erface set t ings described above. The first t hing we need is a set t ings t able. This t able will list t he nam es of t he user int erface worksheet s in t he first colum n and t he nam es of t he set t ings in t he first row. At t he int ersect ion of each row and colum n is t he value t hat will be applied t o a specific worksheet for t hat set t ing. Figure 5- 3 shows an exam ple of a user int erface set t ings t able.

Figu r e 5 - 3 . A Use r I n t e r fa ce Se t t in gs Ta ble [View full size image]

This t able would t ypically be locat ed on a worksheet in your add- in. The VBA code used t o m anage t hese set t ings would be locat ed in a ut ilit y m odule in t he add- in. A ut ilit y m odule is a st andard code m odule t hat holds code designed t o assist t he program m er during developm ent and not used by t he applicat ion it self. I n sit uat ions where add- in size needs t o be m inim ized, t his t able and it s associat ed code could be locat ed in a separat e ut ilit y workbook t hat is only used during developm ent and m aint enance. However, you will st ill need t o have som e user int erface m anagem ent code locat ed in t he add- in t o set t he propert ies of your user int erface when your applicat ion is run. There are t wo t hings t o not e about t his t able. First , you can see t hat all of t he worksheet nam es in t he first colum n follow our worksheet nam ing convent ion. This is because t hey are t he CodeNam es of t he worksheet s, not t heir sheet t ab nam es. As m ent ioned in Chapt er 3 Excel and VBA Developm ent Best Pract ices, you should never rely on sheet t ab nam es because t hey m ay change frequent ly or unexpect edly. A worksheet 's CodeNam e provides a perm anent , unique nam e by which you can ident ify t he worksheet . Second, beginning in colum n B you can see t hat t he colum n headers are defined nam es ( rem em ber t hat t he set prefix ident ifies a defined nam e t hat represent s a set t ing) . This is because all of t hese set t ings will be st ored as sheet - level defined nam es on t he worksheet s t o which t hey apply. This allows all of t he inform at ion required t o m anage a worksheet t o be encapsulat ed wit hin t hat w or k sheet . Also not ice t hat som e of t he set t ings in t he body of t he t able are blank. This indicat es t he set t ing does not apply t o t hat worksheet and t he set t ing nam e will not be defined on t hat worksheet . Lat er you will see t hat t he VBA code t hat im plem ent s t hese set t ings ignores set t ings whose defined nam es are m issing.

The Utility Code The VBA code t hat im plem ent s t he t able- driven set t ings needs t o accom plish t wo obj ect ives:

1 . I t needs t o read t he set t ings t able and add t he specified defined nam es wit h t he specified values t o each worksheet list ed in t he t able.

2 . I t needs t o loop each worksheet in t he user int erface workbook, read t he value of each defined nam e list ed in t he set t ings t able and record t he value of t hat set t ing in t he appropriat e cell of t he set t ings t able. These t asks will be im plem ent ed as t wo separat e procedures. I f we have code t o creat e t he set t ings defined in t he set t ings t able, you m ay be asking yourself, why do we also need code t o read t hese set t ings back int o t he t able? Good quest ion. The answer is t hat when you are working direct ly on t he user int erface workbook you will oft en find it easier t o m anually updat e t he value of a defined nam e for a set t ing you've j ust alt ered. For exam ple, if you need t o add addit ional hidden program colum ns t o several sheet s, it 's very easy t o updat e t heir respect ive set ProgCols defined nam es as you go along. Aft er you've m ade t hese adj ust m ent s, you can quickly synchronize t he set t ings t able and t he user int erface workbook by reading t he values of all t he defined nam es from t he workbook back int o t he set t ings t able. As you can see in List ing 5- 4 , t he code required t o apply t he set t ings in t he set t ings t able t o t he worksheet s in t he user int erface workbook is relat ively sim ple. The defined nam es t hat reference t he list of worksheet s in t he first colum n and t he list of set t ings in t he first row are bot h dynam ic. I f you add worksheet s or set t ings, t hese nam es aut om at ically expand t o include t hem . Keep in m ind t hat t his code does not act ually a pply any set t ings in t he user int erface workbook. I t sim ply records t he set t ings we want t o apply on each worksheet using worksheet - level defined nam es. A procedure in t he applicat ion t hat runs as part of t he st art up code will read t hese defined nam es and apply t he set t ings t hey specify.

List in g 5 - 4 . Code t o W r it e Se t t in gs t o t h e Use r I n t e r fa ce W or k sh e e t s Private Const msFILE_TEMPLATE As String = "PetrasTemplate.xlt" Private Const msRNG_NAME_LIST As String = "tblRangeNames" Private Const msRNG_SHEET_LIST As String = "tblSheetNames" Public Sub WriteSettings() Dim rngSheet As Range Dim rngSheetList As Range Dim rngName As Range Dim rngNameList As Range Dim rngSetting As Range Dim sSheetTab As String Dim wkbTemplate As Workbook Dim wksSheet As Worksheet ' Turning off screen updating and calculation ' will speed the process significantly. Application.ScreenUpdating = False Application.Calculation = xlCalculationManual ' The time entry workbook. Set wkbTemplate = Application.Workbooks(msFILE_TEMPLATE) ' The list of worksheets in the first column. Set rngSheetList = wksUISettings.Range(msRNG_SHEET_LIST)

' The list of setting names in the first row. Set rngNameList = wksUISettings.Range(msRNG_NAME_LIST) ' The outer loop processes all the worksheets in the ' first column of the table. For Each rngSheet In rngSheetList ' We need an object reference to the worksheet so we ' can easily add a sheet-level defined name to it. ' The sSheetTabName() function converts a CodeName ' into its corresponding sheet tab name. sSheetTab = sSheetTabName(wkbTemplate, rngSheet.Value) Set wksSheet = wkbTemplate.Worksheets(sSheetTab) ' The inner loop adds each setting to the current sheet. ' If the setting already exists it will be replaced. For Each rngName In rngNameList ' The value of the setting is contained in the cell ' where the worksheet row and range name column ' intersect. Set rngSetting = Intersect(rngSheet.EntireRow, _ rngName.EntireColumn) ' We only create defined names for settings that ' have been given a non-zero-length value. If Len(rngSetting.Value) > 0 Then wksSheet.Names.Add rngName.Value, _ "=" & rngSetting.Value End If Next rngName Next rngSheet Application.ScreenUpdating = True Application.Calculation = xlCalculationAutomatic End Sub

The sam ple add- in discussed in t he Pract ical Exam ple sect ion lat er in t his chapt er cont ains code t hat aut om at ically applies t hese set t ings t o t he user int erface workbook when it is first opened. The MUt ilit y m odule of t he applicat ion also cont ains a procedure t hat aut om at ically rem oves all t hese set t ings from t he user int erface workbook t o m ake it easier t o m aint ain.

Using VBA to Dynamically Modify Your Worksheet User Interface You can leverage t he power of VBA t o im prove your user int erface in m any ways. Many of t hem , including t echniques such as cont ext - specific com m and bar enabling and dynam ic hiding and

unhiding of rows and colum ns, require t he use of Excel event t rapping, which we cover in Chapt er 7 Using Class Modules t o Creat e Obj ect s. A sim ple exam ple t hat we'll add t o our sam ple applicat ion is a feat ure t hat clears t he dat a- ent ry cells on a worksheet . A one- click m et hod for clearing all input cells on t he current user int erface worksheet is oft en very helpful t o users. To do t his, j ust creat e a nam ed range t hat includes all t he dat a- input cells on each dat a- ent ry worksheet and give it an obvious nam e such as rgnClearI nput s. This m ust be a sheet - level defined nam e creat ed on all dat a- ent ry worksheet s in your workbook. List ing 5- 5 shows t he VBA im plem ent at ion of our clear dat a- ent ry area feat ure.

List in g 5 - 5 . VBA I m ple m e n t a t ion of a Cle a r D a t a - En t r y Ar e a Fe a t u r e Public Sub ClearDataEntryAreas() Dim rngToClear As Range ' Make sure the active worksheet has the rgnClearInputs ' defined name (i.e. it's an input worksheet). On Error Resume Next Set rngToClear = ActiveSheet.Range("rgnClearInputs") On Error GoTo 0 ' If the worksheet is an input worksheet, clear the ' contents of the input area. If Not rngToClear Is Nothing Then rngToClear.ClearContents End Sub

Practical Example Features The add- in for our PETRAS t im esheet applicat ion will perform t he following operat ions: Open and init ialize t he applicat ion Build a t oolbar t hat gives t he user access t o each feat ure of t he applicat ion Open and init ialize t he t im e- ent ry workbook Enable t he user t o save a copy of t he t im e ent ry workbook t o a predefined consolidat ion locat ion Enable t he user t o add m ore dat a- ent ry rows t o t he t im e- ent ry worksheet Enable t he user t o clear t he dat a- ent ry area so t he t im esheet can easily be reused Enable t he user t o close t he PETRAS applicat ion Add a cust om propert y t hat will allow t he consolidat ion applicat ion t o locat e all inst ances of our t im e- ent ry workbook Let 's look at how t he add- in accom plishes t hese t asks. We'll assum e t he Writ eSet t ings ut ilit y procedure shown in List ing 5- 4 has been run on t he t im e- ent ry workbook and t he set t ings saved prior t o running t he add- in.

Open and Initialize the Application The first operat ion t he add- in perform s when it is opened is t o init ialize t he applicat ion and t hen open and init ialize t he user int erface workbook. This is accom plished by t he Aut o_Open procedure, shown in List ing 5- 6 .

List in g 5 - 6 . Th e PETRAS Add- in Au t o_ Ope n Pr oce du r e Public Sub Auto_Open() Dim wkbBook As Workbook ' The very first thing your application should do upon

' startup is attempt to delete any copies of its ' command bars that may have been left hanging around ' by an Excel crash or other incomplete exit. On Error Resume Next Application.CommandBars(gsBAR_TOOLBAR).Delete On Error GoTo 0 ' Initialize global variables. InitGlobals ' Make sure we can locate our time entry workbook before ' we do anything else. If Len(Dir$(gsAppDir & gsFILE_TIME_ENTRY)) > 0 Then Application.ScreenUpdating = False Application.StatusBar = gsSTATUS_LOADING_APP ' Build the command bars. BuildCommandBars ' Determine if the time entry workbook is already ' open. If not, open it. If so, activate it. On Error Resume Next Set wkbBook = Application.Workbooks(gsFILE_TIME_ENTRY) On Error GoTo 0 If wkbBook Is Nothing Then Set wkbBook = Application.Workbooks.Open( _ gsAppDir & gsFILE_TIME_ENTRY) Else wkbBook.Activate End If ' Make the worksheet settings for the time entry ' workbook MakeWorksheetSettings wkbBook ' Reset critical application properties. ResetAppProperties Else MsgBox gsERR_FILE_NOT_FOUND, vbCritical, gsAPP_NAME ShutdownApplication End If End Sub

The first t hing t he add- in does is blindly at t em pt t o delet e any previous inst ance of it s t oolbar. This should be considered a best pract ice. Applicat ion t oolbars can be left behind due t o an incom plet e shut down, which will t hen cause an error when you t ry t o creat e t hem again t he next t im e your applicat ion is run. Then t he add- in init ializes any global variables. I n t his case we have t wo: a

variable t hat holds t he full pat h where t he add- in is locat ed and a variable t hat indicat es when t he add- in is in t he process of shut t ing down. As m ent ioned in Chapt er 3 Excel and VBA Developm ent Best Pract ices, you should use as few global variables as possible. When you do use t hem , you m ust m ake sure t hey are in a known st at e at t he beginning of every procedure where t hey m ight be accessed. Encapsulat ing t his logic in an I nit Globals procedure t hat can be called wherever it 's needed is a good way t o m anage t his pr ocess. Aft er t he add- in has perform ed t hese t wo basic t asks, it checks t o see whet her it can locat e t he user int erface workbook. I f t he user int erface workbook is locat ed, execut ion cont inues. Ot herwise, an error m essage displays and t he applicat ion exit s. This m akes sense because t here is not hing t he add- in can do wit hout t he user int erface workbook.

Build a Toolbar That Gives the User Access to Each Feature Next t he add- in builds it s t oolbar. The t echniques used t o do t his are basic, hard- coded VBA com m and bar building t echniques t hat should be fam iliar t o all readers of t his book. Therefore, we do not go int o any det ail on t his. An ent ire chapt er is devot ed t o advanced com m and bar building t echniques, Chapt er 8 Advanced Com m and Bar Handling. The add- in exposes four dist inct feat ures for t he user t hrough t he applicat ion t oolbar, as shown in Figure 5- 4 . Each of t hese feat ures is discussed in t he sect ions t hat follow.

Figu r e 5 - 4 . Th e PETRAS Applica t ion Toolba r

Open and Initialize the Time-Entry Workbook Aft er t he com m and bars have been const ruct ed, t he add- in checks t o see whet her t he user int erface workbook is already open. I f t his workbook is not open, t he Auto_Open procedure opens it . I f t his workbook is open, t he Aut o_Open procedure act ivat es it . The next st ep is t o init ialize t he user int erface workbook. During t his process, all t he set t ings t hat were saved t o t he user int erface workbook's worksheet s by t he Writ eSet t ings procedure in List ing 5- 4 are read and applied by t he MakeWorksheet Set t ings procedure. List ing 5- 7 shows t his procedure.

List in g 5 - 7 . Th e M a k e W or k sh e e t Se t t in gs Pr oce du r e Public Sub MakeWorksheetSettings(ByRef wkbBook As Workbook)

Dim Dim Dim Dim Dim Dim

rngCell As Range rngSettingList As Range rngHideCols As Range sTabName As String vSetting As Variant wksSheet As Worksheet

Set rngSettingList = wksUISettings.Range(gsRNG_NAME_LIST) For Each wksSheet In wkbBook.Worksheets ' The worksheet must be unprotected and visible in order ' to make many of the settings. It will be protected and ' hidden again automatically by the settings code if it ' needs to be protected and/or hidden. wksSheet.Unprotect wksSheet.Visible = xlSheetVisible ' Hide any non-standard columns that need hiding. Set rngHideCols = Nothing On Error Resume Next Set rngHideCols = wksSheet.Range(gsRNG_SET_HIDE_COLS) On Error GoTo 0 If Not rngHideCols Is Nothing Then rngHideCols.EntireColumn.Hidden = True End If For Each rngCell In rngSettingList ' Determine if the current worksheet requires the ' current setting. vSetting = Empty On Error Resume Next If rngCell.Value = "setScrollArea" Then ' The scroll area setting must be treated ' differently because it's a range object. Set vSetting = Application.Evaluate( _ "'" & wksSheet.Name & "'!" & rngCell.Value) Else vSetting = Application.Evaluate( _ "'" & wksSheet.Name & "'!" & rngCell.Value) End If On Error GoTo 0 If Not IsEmpty(vSetting) Then If rngCell.Value = "setProgRows" Then If vSetting > 0 Then wksSheet.Range("A1").Resize(vSetting) _ .EntireRow.Hidden = True End If ElseIf rngCell.Value = "setProgCols" Then If vSetting > 0 Then

wksSheet.Range("A1").Resize(, _ vSetting).EntireColumn.Hidden = True End If ElseIf rngCell.Value = "setScrollArea" Then wksSheet.ScrollArea = vSetting.Address ElseIf rngCell.Value = "setEnableSelect" Then wksSheet.EnableSelection = vSetting ElseIf rngCell.Value = "setRowColHeaders" Then wksSheet.Activate Application.ActiveWindow _ .DisplayHeadings = vSetting ElseIf rngCell.Value = "setVisible" Then wksSheet.Visible = vSetting ElseIf rngCell.Value = "setProtect" Then If vSetting Then wksSheet.Protect , True, True, True End If End If End If Next rngCell Next wksSheet ' Leave the Time Entry worksheet active. sTabName = sSheetTabName(wkbBook, gsSHEET_TIME_ENTRY) wkbBook.Worksheets(sTabName).Activate End Sub

The MakeWorksheet Set t ings procedure loops t hrough all t he worksheet s in t he specified workbook and applies all t he set t ings t hat we have defined for each worksheet . We have designed t his procedure t o accept a reference t o a specific workbook obj ect as an argum ent rat her t han having it assum ing it needs t o operat e on t he user int erface workbook because t his design will allow us t o generalize t he applicat ion t o handle m ult iple user int erface workbooks if we need t o at som e lat er t im e. The set t ings t able on which t his procedure is based can be seen on t he wksUI Set t ings worksheet of t he Pet rasAddin.xla workbook. Aft er t he user int erface workbook has been init ialized, t he last t hing we do is run a procedure t hat ensures all Excel applicat ion propert ies are set t o t heir default values. This is t he Reset AppPropert ies procedure shown in List ing 5- 8 .

List in g 5 - 8 . Th e Re se t AppPr ope r t ie s Pr oce du r e Public Sub ResetAppProperties() Application.StatusBar = False Application.ScreenUpdating = True Application.DisplayAlerts = True

Application.EnableEvents = True Application.EnableCancelKey = xlInterrupt Application.Cursor = xlDefault End Sub

This procedure is useful because we can m ake what ever applicat ion set t ings we like during t he code execut ion required for a feat ure, and as long as we call t his procedure before we exit we know t hat all crit ical applicat ion propert ies will be left in known good st at es. I f we didn't happen t o use one of t he propert ies reset by t his procedure, it doesn't m at t er. The values set by t he Reset AppPropert ies procedure are t he default values for each propert y. Therefore we aren't changing t hem if t hey weren't used.

Save a Copy of the Time-Entry Workbook to a Predefined Consolidation Location The first t oolbar but t on will save a copy of t he t im e- ent ry workbook t o a cent ralized consolidat ion locat ion. From here, a procedure in t he PETRAS report ing applicat ion will consolidat e t he t im eent ry workbooks from all t he consult ant s int o a single report . List ing 5- 9 shows t he procedure t hat im plem ent s t his feat ure.

List in g 5 - 9 . Th e Post Tim e En t r ie sToN e t w or k Pr oce du r e Public Sub PostTimeEntriesToNetwork() Dim Dim Dim Dim Dim Dim Dim Dim

sSheetTab As String sWeekEndDate As String sEmployee As String sSaveName As String sSavePath As String wksSheet As Worksheet wkbBook As Workbook vFullName As Variant

' Don't do anything unless our time entry workbook is active ' wkbBook will return a reference to it if it is. If bIsTimeEntryBookActive(wkbBook) Then ' Make sure the TimeEntry worksheet does not have any ' data entry errors. sSheetTab = sSheetTabName(wkbBook, gsSHEET_TIME_ENTRY) Set wksSheet = wkbBook.Worksheets(sSheetTab) If wksSheet.Range(gsRNG_HAS_ERRORS).Value Then MsgBox gsERR_DATA_ENTRY, vbCritical, gsAPP_NAME Exit Sub End If ' Create a unique name for the time entry workbook.

sWeekEndDate = Format$( _ wksSheet.Range(gsRNG_WEEK_END_DATE).Value, _ "YYYYMMDD") sEmployee = wksSheet.Range(gsRNG_EMPLOYEE_NAME).Value sSaveName = sWeekEndDate & " - " & sEmployee & ".xls" ' Check the registry to determine if we already have a ' consolidation path specified. If so, save the time ' entry workbook to that location. If not, prompt the ' user to identify a consolidation location, save that ' location to the registry and save the time entry ' workbook to that location. sSavePath = GetSetting(gsREG_APP, gsREG_SECTION, _ gsREG_KEY, "") If Len(sSavePath) = 0 Then ' No path was stored in the registry. Prompt the ' user for one. vFullName = Application.GetOpenFilename( _ Title:=gsCAPTION_SELECT_FOLDER) If vFullName False Then ' NOTE: The InStrRev function was not available ' in Excel 97. sSavePath = Left$(vFullName, _ InStrRev(vFullName, "\")) SaveSetting gsREG_APP, gsREG_SECTION, _ gsREG_KEY, sSavePath Else ' The user cancelled the dialog. MsgBox gsMSG_POST_FAIL, vbCritical, gsAPP_NAME Exit Sub End If End If wkbBook.SaveCopyAs sSavePath & sSaveName MsgBox gsMSG_POST_SUCCESS, vbInformation, gsAPP_NAME Else MsgBox gsMSG_BOOK_NOT_ACTIVE, vbExclamation, gsAPP_NAME End If End Sub

This procedure shows t he safet y m echanism we use t o prevent runt im e errors from occurring if t he user clicks one of our t oolbar but t ons wit hout t he user int erface workbook being act ive. Prior t o perform ing any act ion, we verify t hat t his workbook is act ive using t he bI sTim eEnt ryBookAct ive (wkbBook) funct ion call. This funct ion ret urns an obj ect reference t o t he t im e- ent ry workbook via it s ByRef Workbook argum ent if t he t im e- ent ry workbook is act ive. I f t he t im e- ent ry workbook is not act ive, we display an error m essage t o t he user and exit . Aft er we verify t he t im e- ent ry workbook is act ive, we check t he error flag in t he hidden colum n on

t he t im e- ent ry worksheet t o det erm ine whet her t he t im esheet has any dat a- ent ry errors. I f t he flag indicat es errors, we display a m essage t o t he user and exit . I f t here are no dat a- ent ry errors, t he next t ask is t o creat e a unique nam e for t he workbook and look for our consolidat ion pat h in t he regist ry. I f t he consolidat ion pat h has not yet been saved t o t he regist ry, we prom pt t he user t o specify t he pat h t hat should be used. Finally, we use t he SaveCopyAs m et hod of t he Workbook obj ect t o post a copy of t he workbook t o t he cent ral consolidat ion locat ion. We t hen display a m essage t o t he user indicat ing t hat t he process succeeded.

Allow the User to Add More Data-Entry Rows to the Time-Entry Worksheet I n t he version of t he t im e- ent ry workbook dem onst rat ed in Chapt er 4 Worksheet Design, t he num ber of dat a- ent ry rows was fixed. I n t his version, t he second t oolbar but t on will enable t he user t o add addit ional rows t o t he t im e- ent ry t able as needed. List ing 5- 10 shows t he procedure t hat im plem ent s t his feat ure.

List in g 5 - 1 0 . Th e AddM or e Row s Pr oce du r e Public Sub AddMoreRows() Const lOFFSET_COLS As Long = 5 Const lINPUT_COLS As Long = 6 Dim rngInsert As Range Dim wkbBook As Workbook Dim wksSheet As Worksheet ' Don't do anything unless our time entry workbook is active If bIsTimeEntryBookActive(wkbBook) Then ' Get a reference to the TimeEntry worksheet and the ' insert row range on it. All new rows will be inserted ' above this range. Set wksSheet = wkbBook.Worksheets(sSheetTabName( _ wkbBook, gsSHEET_TIME_ENTRY)) Set rngInsert = wksSheet.Range(gsRNG_INSERT_ROW) ' Add a new row to the time entry table. wksSheet.Unprotect rngInsert.EntireRow.Insert rngInsert.Offset(-2, 0).EntireRow.Copy _ Destination:=rngInsert.Offset(-1, 0) rngInsert.Offset(-1, lOFFSET_COLS) _ .Resize(1, lINPUT_COLS).ClearContents wksSheet.Protect , True, True, True Else

MsgBox gsMSG_BOOK_NOT_ACTIVE, vbExclamation, gsAPP_NAME End If End Sub

I n t he AddMoreRows procedure, we use t he sam e m et hod t o det erm ine whet her a t im e- ent ry workbook is act ive as we used in t he Post Tim eEnt riesToNet work procedure. Aft er we've det erm ined we have a valid workbook act ive, insert ing a new row is a t hree- st ep process: 1 . I nsert a new row direct ly above t he last row in t he t able. The last row in t he t able is m arked by t he gsRNG_I NSERT_ROW defined nam e. 2 . Copy t he row above t he newly insert ed row and past e it ont o t he newly insert ed row. This ensures all funct ions, form at t ing and validat ion required t o m ake t he t able operat e and appear correct ly are t ransferred t o t he newly insert ed row. 3 . The cont ent s of t he dat a- ent ry area of t he newly insert ed row is cleared of any dat a t hat m ay have been t ransferred t o t he new row by t he previous st ep. The new dat a- ent ry row is now clean and ready t o be used.

Allow the User to Clear the Data-Entry Area So the Timesheet Can Be Reused The t hird t oolbar but t on, Clear Dat a Ent ries, sim ply clears t he values from all t he dat a- ent ry areas on t he t im esheet . The code t o im plem ent t his feat ure was discussed in t he Using VBA t o Dynam ically Modify Your Worksheet User I nt erface sect ion above, so we don't repeat it here.

Allow the User to Close the PETRAS Application The fourt h and last t oolbar but t on sim ply closes t he PETRAS applicat ion workbooks and rem oves it s t oolbar. The Exit Applicat ion procedure t hat im plem ent s t his feat ure is shown in List ing 5- 11.

List in g 5 - 1 1 . Th e Ex it Applica t ion Pr oce du r e Public Sub ExitApplication() ShutdownApplication End Sub

This is a one- line st ub procedure t hat j ust calls t he Shut downApplicat ion procedure, which act ually perform s t he t asks required t o shut down t he applicat ion. We place t he shut down logic in a separat e procedure because it m ust be called from t he Exit Applicat ion procedure as well as from t he Aut o_Close procedure. These t wo procedures reflect t he t wo ways t he user could exit our

applicat ion: select ing t he Exit PETRAS t oolbar but t on or using one of Excel's built - in exit feat ures. List ing 5- 12 shows t he code for t he Shut downApplicat ion procedure.

List in g 5 - 1 2 . Th e Sh u t dow n Applica t ion Pr oce du r e Public Sub ShutdownApplication() ' Blow past any errors on application shutdown. On Error Resume Next ' This flag prevents this procedure from being called a ' second time by Auto_Close if it has already been called ' by the ExitApplication procedure. gbShutdownInProgress = True ' Delete command bar. Application.CommandBars(gsBAR_TOOLBAR).Delete ' Close the time entry workbook, allowing the user to ' save changes. Application.Workbooks(gsFILE_TIME_ENTRY).Close ' If there are no workbooks left open, quit Excel ' Otherwise just close this workbook. If lCountVisibleWorkbooks() = 0 Then ThisWorkbook.Saved = True Application.Quit Else ThisWorkbook.Close False End If End Sub

The Shut downApplicat ion procedure is an exam ple of a procedure where you want t o ignore any errors. The applicat ion is closing down, so t here isn't anyt hing useful t hat could be done about any errors t hat did occur. Therefore, we t ell VBA t o ignore any errors in t he procedure by using t he On Error Resume Next st at em ent . Chapt er 12 VBA Error Handling covers t his st at em ent in det ail. The first t hing t he Shut downApplicat ion procedure does is set a global flag variable t hat will prevent it from being called t wice if t he user init iat ed shut down by clicking t he Exit PETRAS t oolbar but t on. The process of closing t he add- in workbook will cause t he Aut o_Close procedure t o fire. The Aut o_Close procedure also calls Shut downApplicat ion, but it checks t he value of t he gbShut downI nProgress variable first and sim ply exit s if shut down is already in progress. Then t he Shut downApplicat ion procedure delet es t he applicat ion t oolbar. I t t hen closes t he user's t im e- ent ry workbook. I f t his workbook has not been saved, we allow Excel t o prom pt t he user t o save t he workbook. Aft er t he t im e- ent ry workbook has been closed, we check t o see whet her any ot her v isib le workbooks are open. I f no visible workbooks are open, we can assum e t he user

st art ed Excel j ust t o run our applicat ion and t herefore we can close Excel. I f t here are st ill visible workbooks open, we assum e t he user was working wit h Excel before our applicat ion was opened and t herefore we j ust close our add- in and leave Excel open for t he user t o cont inue working wit h. The v isib le workbooks dist inct ion is an im port ant one because m any users have a hidden Personal.xls workbook or ot her ut ilit y workbook always open. We want t o ignore t hese hidden workbooks when t rying t o det erm ine whet her we should close Excel or leave Excel open on exit . List ing 5- 13 shows t he procedure t hat count s t he num ber of visible workbooks.

List in g 5 - 1 3 . Th e lCou n t Visible W or k book s Pr oce du r e Public Function lCountVisibleWorkbooks() As Long Dim lCount As Long Dim wkbBook As Workbook For Each wkbBook In Application.Workbooks If wkbBook.Windows(1).Visible Then lCount = lCount + 1 End If Next wkbBook lCountVisibleWorkbooks = lCount End Function

Add a Custom Property to Allow the Consolidation Application to Locate All Instances of Our Time-Entry Workbook Aft er all em ployees have saved t heir t im e- ent ry workbooks t o t he cent ralized consolidat ion locat ion, t he consolidat ion applicat ion needs t o be able t o definit ively locat e t hese workbooks. There m ay be ot her files locat ed in t he consolidat ion direct ory t hat t he consolidat ion applicat ion needs t o ignore. We solve t his problem by adding a cust om docum ent propert y called Pet rasTim esheet t o our t im e- ent ry workbook. This allows t he consolidat ion applicat ion t o uniquely ident ify any t im e- ent ry workbooks creat ed by our applicat ion. To add a cust om docum ent propert y, act ivat e t he Pet rasTem plat e.xls workbook and choose File > Pr oper t ies from t he Excel m enu. I n t he Propert ies dialog, select t he Cust om t ab. Ent er Pet rasTim esheet in t he Nam e box and ent er Yes in t he Value box. Click t he Ad d but t on t o add t his propert y t o t he workbook. Figure 5- 5 shows t he result .

Figu r e 5 - 5 . Addin g t h e Cu st om D ocu m e n t Pr ope r t y

Application Organization We briefly cover t he way in which t he PETRAS add- in has been organized int o code m odules. The Pet rasAddin.xla workbook is a very sim ple, ent irely procedural based applicat ion at t his point . I t consist s of six st andard code m odules whose nam es provide a reasonable indicat ion of t he t ype of code t hey cont ain. These m odules are t he following: M En t r y Poin t s This m odule cont ains t he procedures called from t he t oolbar but t ons of our t oolbar. These procedures are ent ry point s in t he sense t hat t hey are t he only way for t he user t o execut e code in t he applicat ion. The ClearDat aEnt ryAreas procedure shown in List ing 5- 5 , t he Post Tim eEnt riesToNet work procedure shown in List ing 5- 9 , t he AddMoreRows procedure shown in List ing 5- 10 and t he Exit Applicat ion procedure shown in List ing 5- 11 are all locat ed in t his m odule.

M Globa ls This m odule cont ains t he definit ions of all public const ant s and variables used by our applicat ion as well as an I nit Globals procedure used t o ensure our global variables are always properly init ialized. M Ope n Close This m odule cont ains t he code required t o st art up and shut down t he applicat ion. The Aut o_Open procedure shown in List ing 5- 6 is locat ed in t his m odule. M St a n da r dCode This m odule cont ains st andard code library procedures t hat are reused wit hout m odificat ion in m any different proj ect s. The Reset AppPropert ies procedure shown in List ing 5- 8 is one exam ple. M Sy st e m Code This m odule cont ains core procedures writ t en specifically for t his applicat ion. I n a larger applicat ion, you would have m any m odules of t his t ype, each of which would have a m ore det ailed descript ive nam e ( for exam ple, MPrint ing, MCalculat ion or MExport ) . M Ut ilit ie s This m odule cont ains procedures designed solely for use by t he program m er during const ruct ion and m aint enance of t he applicat ion. Procedures in t his m odule will never be run by t he end user and in fact are hidden from t he user by t he Option Private Module direct ive. The Writ eSet t ings procedure shown in List ing 5- 4 is locat ed in t his m odule.

Conclusion This chapt er has covered a com plet e list of st ages all Excel applicat ions go t hrough. I t has described t he various t ypes of add- ins and t he t ypes of operat ions t hat each is required t o perform . I t has dem onst rat ed a t able- driven m et hod for m aint aining and applying crit ical set t ings in a user int erface workbook and dem onst rat ed a sim ple exam ple of an applicat ion- specific add- in applicat ion.

Chapter 6. Dictator Applications Dict at or applicat ions t ake cont rol of t he ent ire Excel session, m odifying t he user int erface t o m ake it appear and behave like a norm al Windows program . By doing t his, t he applicat ions can leverage Excel's rich user int erface feat ures and/ or m ake ext ensive use of Excel's calculat ion engine and analysis feat ures, while m aint aining a high degree of cont rol over t he user. This chapt er explains how t o creat e a sim ple dict at or applicat ion, providing a basic t em plat e from which you can build your own. Lat er chapt ers in t his book add m ore feat ures t o t he basic applicat ion we present here.

Structure of a Dictator Application As m ent ioned in Chapt er 2 Applicat ion Archit ect ures, m ost dict at or applicat ions have t he following logical st ruct ure: A st art up rout ine t o perform version and dependency checks and so fort h A core set of rout ines, t o: Take a snapshot of t he Excel environm ent set t ings and t o rest ore t hose set t ings Configure and lock down t he Excel applicat ion Creat e and rem ove t he dict at or applicat ion's com m and bars Handle copying and past ing dat a wit hin t he worksheet t em plat es ( if using worksheet based dat a- ent ry form s) Provide a library of com m on helper rout ines and classes A backdrop worksheet , t o display wit hin t he Excel window while userform s are being shown, usually wit h som e form of applicat ion- specific logo ( if we're prim arily using form s for t he user int er face) Mult iple independent applet s, which provide t he applicat ion's funct ionalit y Mult iple t em plat e worksheet s used by t he applet s, such as dat a- ent ry form s or preform at t ed report t em plat es Each of t hese point s is discussed in m ore det ail below in t he order in which t hey occur wit hin a t ypical dict at or applicat ion. I n t he sim plest dict at or applicat ions, t hese elem ent s are all cont ained wit hin a single workbook, alt hough spreading t hem over m ult iple workbooks can m ake m aint enance easier when a t eam of developers works on a large applicat ion.

Startup and Shutdown Version and Dependency Checks All versions of Excel from 97 t o 2003 share t he sam e file form at , so if our applicat ion requires a m inim um version level ( for exam ple, Excel 2000 in our case) , we need t o check t hat our user hasn't j ust opened t he applicat ion in Excel 97. The easiest way t o do t his is t o check t he value of t he Application.Version propert y. The original version of Excel 97 was version 8.0, which increm ent ed t o 8.0e wit h t he various service packs. Each m aj or release of Excel increm ent s t he

version num ber, so Excel 2000 is version 9.0, Excel 2002 is version 10.0 and Excel 2003 is version 11.0. I n List ing 6- 1 , we check t hat t he user is running Excel 2000 or lat er.

List in g 6 - 1 . Ch e ck in g t h e Ex ce l Ve r sion 'Check that the version is at least Excel 2000 If Val(Application.Version) < 9 Then MsgBox "The PETRAS Reporting application " & _ "requires Excel 2000 or later.", _ vbOKOnly, gsAPP_TITLE ThisWorkbook.Close False Exit Sub End If

Aft er we know we're running in an appropriat e version of Excel, we have t o check t hat t he user has inst alled any ext ra com ponent s we require, such as t he Analysis Toolpak or Solver add- ins, or ot her applicat ions t hat we're aut om at ing, such as Word or Out look. For add- ins, we can eit her check t he Application.Addins collect ion, or check t hat t he file exist s based on t he Application.LibraryPath. To check t hat ot her applicat ions are inst alled, we can eit her look direct ly in t he regist ry ( using API calls) or use CreateObject t o t ry t o creat e a new inst ance of t he applicat ion and t est for failure. This is covered in m ore det ail in Chapt er 18 Cont rolling Ot her Office Applicat ions.

Storing and Restoring Excel Settings To t ake full cont rol of t he Excel session, dict at or applicat ions t ypically cust om ize t he int erface t o a high degree, such as hiding t he t oolbars and form ula bar and changing num erous applicat ion set t ings. Unfort unat ely ( and despit e repeat ed request s t o Microsoft ) , Excel assum es t hese changes are t he user's choice of set t ings and should be preserved for t he next session; t here's no way t o t ell Excel t hese are t em porary set t ings, for t his session only. To solve t his problem , we have t o t ake a snapshot of t he Excel set t ings when our applicat ion st art s, st ore t hem away som ewhere and reset t hem as part of our applicat ion's shut down processing. The easiest place t o st ore t he set t ings is in a worksheet in t he add- in, alt hough our preference is t o st ore t hem in t he regist ry, so t hey can be recovered if t he applicat ion crashes ( see below) . The biggest issue wit h using t he regist ry is if t he com pany's securit y policy is such t hat regist ry access is blocked. I n t hat case, Excel won't be able t o st ore any user set t ings, so it doesn't m at t er t hat we won't be able t o st ore/ rest ore t hem eit her. List ing 6- 2 shows a t ypical rout ine t o st ore t he Excel set t ings.

List in g 6 - 2 . St or in g Ex ce l Se t t in gs in t h e Re gist r y Public Const gsREG_APP As String = "Company\Application" Public Const gsREG_XL_ENV As String = "Excel Settings"

Sub StoreExcelSettings() Dim Dim Dim Dim

cbBar As CommandBar sBarNames As String objTemp As Object wkbTemp As Workbook

'Skip errors in case we can't use the registry On Error Resume Next 'Check if we've already stored the settings '(so don't want to overwrite them) If GetSetting(gsREG_APP, gsREG_XL_ENV, "Stored", "No") _ = "No" Then 'Some properties require a workbook open, so create one If ActiveWorkbook Is Nothing Then Set wkbTemp = Workbooks.Add End If 'Indicate that the settings have been stored. 'This key will be deleted in RestoreSettings. SaveSetting gsREG_APP, gsREG_XL_ENV, "Stored", "Yes" 'Store the current Excel settings in the registry With Application SaveSetting gsREG_APP, gsREG_XL_ENV, _ "DisplayStatusBar", CStr(.DisplayStatusBar) SaveSetting gsREG_APP, gsREG_XL_ENV, _ "DisplayFormulaBar", CStr(.DisplayFormulaBar) 'etc. 'Which commandbars are visible For Each cbBar In .CommandBars If cbBar.Visible Then sBarNames = sBarNames & "," & cbBar.Name End If Next SaveSetting gsREG_APP, gsREG_XL_ENV, _ "VisibleCommandBars", sBarNames 'Special items for Excel 2000 and up If Val(.Version) >= 9 Then SaveSetting gsREG_APP, gsREG_XL_ENV, _ "ShowWindowsInTaskbar", _ CStr(.ShowWindowsInTaskbar) End If 'Special items for Excel 2002 and up If Val(.Version) >= 10 Then Set objTemp = .CommandBars

SaveSetting gsREG_APP, gsREG_XL_ENV, _ "DisableAskAQuestion", _ CStr(objTemp.DisableAskAQuestionDropdown) SaveSetting gsREG_APP, gsREG_XL_ENV, _ "AutoRecover", CStr(.AutoRecover.Enabled) End If End With 'Close up the temporary workbook If Not wkbTemp Is Nothing Then wkbTemp.Close False End If End Sub

List ing 6- 3 shows t he corresponding rout ine t o rest ore t he set t ings, which should be called during t he applicat ion's shut down processing.

List in g 6 - 3 . Re st or in g Ex ce l Se t t in gs D u r in g Sh u t dow n Sub RestoreExcelSettings() Dim vBarName As Variant Dim objTemp As Object 'Restore the original Excel settings from the registry With Application 'Check that we have some settings to restore If GetSetting(gsREG_APP, gsREG_XL_ENV, "Stored", "No") _ = "Yes" Then .DisplayStatusBar = CBool(GetSetting(gsREG_APP, _ gsREG_XL_ENV, "DisplayStatusBar", _ CStr(.DisplayStatusBar))) .DisplayFormulaBar = CBool(GetSetting(gsREG_APP, _ gsREG_XL_ENV, "DisplayFormulaBar", _ CStr(.DisplayFormulaBar))) 'etc. 'Show the correct toolbars On Error Resume Next For Each vBarName In Split(GetSetting(gsREG_APP, _ gsREG_XL_ENV, "VisibleCommandBars"), ",")

Application.CommandBars(vBarName).Visible = True Next On Error GoTo 0 'Specific stuff for Excel 2000 and up If Val(.Version) >= 9 Then .ShowWindowsInTaskbar = CBool(GetSetting(gsREG_APP, _ gsREG_XL_ENV, "ShowWindowsInTaskbar", _ CStr(.ShowWindowsInTaskbar))) End If 'Specific stuff for Excel 2002 and up If Val(.Version) >= 10 Then Set objTemp = .CommandBars objTemp.DisableAskAQuestionDropdown = _ CBool(GetSetting(gsREG_APP, gsREG_XL_ENV, _ "DisableAskAQuestion", _ CStr(objTemp.DisableAskAQuestionDropdown))) .AutoRecover.Enabled = CBool(GetSetting(gsREG_APP, _ gsREG_XL_ENV, "AutoRecover", _ CStr(.AutoRecover.Enabled))) End If 'Once restored, delete all the registry entries DeleteSetting gsREG_APP, gsREG_XL_ENV End If End With 'Restore the Excel menus RestoreMenus

End Sub

Toolbar cust om izat ions are st ored in a file wit h an .xlb ext ension, where t he filenam e differs wit h each version of Excel. Each t im e a perm anent change is m ade t o t he t oolbars, inform at ion about t he change is added t o t he file. By t heir very nat ure, dict at or applicat ions usually m ake lot s of changes t o t he t oolbars, result ing in t he XLB file growing quit e rapidly ( alt hough it can be reduced by creat ing t he t oolbars wit h t he temporary param et er set t o True) . This result s in slowing Excel's st art up processing and event ually causes Excel t o crash at st art up. To avoid t his, t he best way t o rest ore t he user's t oolbar configurat ion is t o find and open t he XLB file j ust before t he applicat ion closes. By doing so, Excel doesn't see any changes, so t he XLB file isn't m odified. The Rest oreMenus rout ine t o do t his is shown in List ing 6- 4 .

List in g 6 - 4 . Re st or in g Ex ce l Toolba r s D u r in g Sh u t dow n

Public Const gsMENU_BAR As String = "PETRAS Menu Bar" Sub RestoreMenus() Dim Dim Dim Dim

cbCommandBar As CommandBar sPath As String sToolbarFile As String vBarName As Variant

On Error Resume Next 'Reopen the xlb toolbar customization file '(if it exists), to avoid it growing in size sPath = Application.StartupPath 'Work out the name of the correct toolbar file to open, 'depending on the version of Excel If Val(Application.Version) = 9 Then sToolbarFile = Left$(sPath, InStrRev(sPath, "\")) & _ "Excel.xlb" Else sToolbarFile = Left$(sPath, InStrRev(sPath, "\")) & _ "Excel" & Val(Application.Version) & ".xlb" End If 'If there is one, reopen the toolbar file If Dir(sToolbarFile) "" Then Workbooks.Open sToolbarFile, ReadOnly:=True Else 'If not, we have to tidy up ourselves 'Re-enable all the toolbars For Each cbCommandBar In Application.CommandBars cbCommandBar.Enabled = True Next 'Delete our Application's toolbar Application.CommandBars(gsMENU_BAR).Delete End If End Sub

Handling Crashes I t is an unfort unat e fact of Excel applicat ion developm ent t hat at som e point , Excel m ight crash while our applicat ion is being used. I f/ when t hat happens, our norm al shut down processing will not have t he chance t o run, so Excel will rest art wit h our applicat ion's set t ings inst ead of t he user's. I f we want , we can handle t his by copying t he Rest oreExcelSet t ings rout ine int o a new workbook, calling it from t he Workbook_Open procedure and saving it as anot her add- in t hat we dist ribut e

wit h our applicat ion. Our St oreExcelSet t ings rout ine can be m odified t o copy t he add- in t o t he Application.StartupPath and our Rest oreExcelSet t ings rout ine can be m odified t o delet e it . I n doing so, t he add- in will be left behind if Excel crashes and will be opened and run by Excel when it rest art s, reset t ing t he environm ent t o t he way t he user had it .

Configuring the Excel Environment Aft er we've t aken t he snapshot of t he user's environm ent set t ings, we can configure Excel t o suit our applicat ion, such as: Set t ing t he applicat ion capt ion and icon Hiding t he form ula bar and st at us bar Set t ing calculat ion t o m anual ( because recalcs will be under program cont rol) Set t ing Application.IgnoreRemoteRequests = True, so double- clicking a workbook in Explorer opens a new inst ance of Excel inst ead of reusing our inst ance Swit ching off Windows in TaskBar, because we're likely t o have m ult iple processing workbooks open t hat we don't want t he user t o be able t o swit ch t o Swit ching off t he Ask a Quest ion drop- down from t he com m and bars Prevent ing t he abilit y t o cust om ize t he com m and bars Swit ching off aut o- recover ( in Excel 2002 and lat er)

Supporting a Debug Mode When developing and debugging our dict at or applicat ion, we will need a m echanism t o enable us t o access t he VBE, hidden sheet s and so on and allow quick and easy swit ching bet ween Excel's int erface and our applicat ion's, yet prevent our users from doing t he sam e. A sim ple m et hod is t o check for t he exist ence of a specific file in a specific direct ory at st art up and set a global gbDebugMode Boolean variable accordingly. We can t hen configure t he Excel environm ent different ly for debug and product ion m odes. I n debug m ode, we'll keep all Excel's short cut keys act ive and set up an ext ra short cut t o swit ch back t o Excel's m enus ( by calling t he Rest oreExcelSet t ings rout ine from List ing 6- 4 ) . I n product ion m ode, we'll disable all Excel's short cut keys and ensure t he VBE window is hidden. List ing 6- 5 shows a t ypical rout ine t o configure t he Excel environm ent for a dict at or applicat ion. I f t est ing t his rout ine, we recom m end you do so wit h t he debug.ini file creat ed.

List in g 6 - 5 . Con figu r in g t h e Ex ce l En vir on m e n t for a D ict a t or Applica t ion Public gvaKeysToDisable As Variant Public gbDebugMode As Boolean

Sub InitGlobals() gvaKeysToDisable = Array("^{F6}", "+^{F6}", "^{TAB}", _ "+^{TAB}", "%{F11}", "%{F8}", "^W", "^{F4}", _ "{F11}", "%{F1}", "+{F11}", "+%{F1}", "^{F5}", _ "^{F9}", "^{F10}") 'Use the existence of a debug file to set whether we're 'in debug mode gbDebugMode = Dir(ThisWorkbook.Path & "\debug.ini") "" End Sub

Sub

ConfigureExcelEnvironment()

Dim objTemp As Object Dim vKey As Variant With Application 'Set the Application properties we want .Caption = gsAPP_TITLE .DisplayStatusBar = True .DisplayFormulaBar = False .Calculation = xlManual .DisplayAlerts = False .IgnoreRemoteRequests = True .DisplayAlerts = True .Iteration = True .MaxIterations = 100 'Specific items for Excel 2000 and up If Val(.Version) >= 9 Then .ShowWindowsInTaskbar = False End If 'Specific items for Excel 2002 and up If Val(.Version) >= 10 Then Set objTemp = .CommandBars objTemp.DisableAskAQuestionDropdown = True objTemp.DisableCustomize = True .AutoRecover.Enabled = False End If 'We'll have slightly different environment states, _ 'depending on whether we're debugging or not If gbDebugMode Then 'Since we have blitzed the environment, we should 'set a hot key combination to restore it. 'That key combination is Shift+Ctrl+R .OnKey "+^R", "RestoreExcelSettings"

Else 'Make sure the VBE isn't visible .VBE.MainWindow.Visible = False 'Disable a whole host of shortcut keys For Each vKey In gvaKeysToDisable .OnKey vKey, "" Next End If End With End Sub

Not e t hat t he init ial value of e ve r y persist ent environm ent propert y changed in t he configurat ion rout ine should be st ored at st art up and rest ored at shut down, so any ext ra propert ies you need t o change m ust be added t o all t hree rout ines. We're assum ing t he dict at or applicat ion shut s down Excel when it closes, so t here's no need t o st ore such t hings as t he applicat ion t it le and so fort h.

Customizing the User Interface Preparing a Backdrop Graphic At t his point , we have a locked- down em pt y screen, ready for us t o add our applicat ion's user int erface. The first UI elem ent t o add will t ypically be som e sort of background graphic t o display as our applicat ion's " deskt op." The sim plest version of t his is t o have a single worksheet cont ained in our applicat ion workbook t hat is copied t o a new, visible workbook. The workbook is t hen m axim ized, has t he appropriat e worksheet display at t ribut es set and t he display range is zoom ed t o fill t he Excel window, as shown in List ing 6- 6 . The workbook windows can t hen be prot ect ed t o rem ove t he cont rol box and m axim ize/ m inim ize but t ons:

List in g 6 - 6 . Code t o Pr e pa r e a Ba ck gr ou n d Gr a ph ic W or k book Public gwbkBackDrop As Workbook Public Const gsBACKDROP_TITLE As String = "BackdropWkbk" Sub PrepareBackDrop() Dim wkbBook As Workbook If Not WorkbookAlive(gwbkBackDrop) Then 'See if there's already a backdrop workbook out there Set gwbkBackDrop = Nothing For Each wkbBook In Workbooks

If wkbBook.BuiltinDocumentProperties("Title") = _ gsBACKDROP_TITLE Then Set gwbkBackDrop = wkbBook Exit For End If Next If gwbkBackDrop Is Nothing Then 'Copy the backdrop sheet out of this workbook 'into a new one for display wksBackdrop.Copy Set gwbkBackDrop = ActiveWorkbook gwbkBackDrop.BuiltinDocumentProperties("Title") = _ gsBACKDROP_TITLE End If End If With gwbkBackDrop .Activate 'Select the full region that encompasses the backdrop 'graphic, so we can use Zoom = True to size it to fit .Worksheets(1).Range("rgnBackDrop").Select 'Set the Window View options to hide everything With .Windows(1) .WindowState = xlMaximized .Caption = "" .DisplayHorizontalScrollBar = False .DisplayVerticalScrollBar = False .DisplayHeadings = False .DisplayWorkbookTabs = False 'Zoom the selected area to fit the screen .Zoom = True End With 'Prevent selection or editing of any cells With .Worksheets(1) .Range("ptrCursor").Select .ScrollArea = .Range("ptrCursor").Address .EnableSelection = xlNoSelection .Protect DrawingObjects:=True, _ UserInterfaceOnly:=True End With 'Protect 'control .Protect .Saved = End With

the backdrop workbook, to remove the menu Windows:=True True

End Sub

'Function to test if a given workbook object variable 'points to a valid workbook Function WorkbookAlive(wbkTest As Workbook) As Boolean On Error Resume Next If Not wbkTest Is Nothing Then WorkbookAlive = wbkTest.Sheets(1).Name "" End If End Function

A m ore com plex version will cont ain m ult iple pot ent ial backdrop sheet s, each designed for a specific screen resolut ion or window size. At runt im e, t he appropriat e sheet is select ed, based on t he window's height or widt h.

Sheet-Based vs. Form-Based User Interfaces There are t wo prim ary st yles of user int erface for dict at or applicat ions: t hose t hat use worksheet s for t he m ain dat a- ent ry form s and t hose t hat use userform s. Bot h st yles can be com bined wit h a cust om m enu st ruct ure, alt hough it is slight ly harder wit h a form - based user int erface. Worksheet - based user int erfaces are very sim ilar t o t he applicat ion- specific add- ins discussed in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins and are designed t o m ake m axim um use of Excel's rich cell- edit ing feat ures, such as aut o- com plet e, dat a validat ion and condit ional form at t ing. Alt hough t he use of Excel's rich funct ionalit y is a com pelling choice, care m ust be t aken t o ensure t he users do not accident ally dest roy t he dat a- ent ry form . I f you decide on a worksheet based user int erface, use worksheet s for all your m aj or dat a- ent ry form s and report s; dialogs should only be used for m inor t asks and wizards. Form - based user int erfaces are t ypically found in applicat ions t hat use Excel prim arily for it s calculat ion and analysis feat ures, rat her t han t he rich edit ing experience. The dat a- ent ry form s t end t o be m uch sim pler t han t hose where a worksheet is used, which is oft en perceived as a benefit for bot h t he user and t he developer; t he reduced funct ionalit y and t ight er cont rol t hat userform s provide can result in less chance for your users t o m ake m ist akes and hence a m ore robust solut ion. I f you decide t o use a form - based user int erface, worksheet s should only be used for report ing. Designing a form - based user int erface is covered in det ail in Chapt er 10 Userform Design and Best Pract ices. Trying t o m ix t he t wo user int erface st yles rarely works well; it is j ust t oo cum bersom e t o m ake worksheet s behave like dialogs ( such as t abbing bet ween cont rols) and vice versa ( such as aut ocom plet e) , part icularly if t he worksheet also includes som e form s cont rols ( such as but t ons, check boxes and so on) . When deciding which st yle t o use, base t he decision on where users are likely t o spend t he m aj orit y of t heir t im e. Will it be bet t er ( for t he user) t o provide t he rich edit ing feat ures of a worksheet , or t he t ight er cont rol of a userform ?

Handling Cut, Copy and Paste The biggest issue wit h sheet - based user int erfaces is having t o override Excel's default handling of cut , copy, past e and drag/ drop. As discussed in Chapt er 4 Worksheet Design, m ost of t he edit able cells in a dat a- ent ry worksheet will be given specific st yles, dat a validat ion and condit ional form at s. Unfort unat ely, Excel's default copy/ past e behavior will overwrit e t he form at t ing of t he cell being past ed t o and Excel's default cut behavior is t o form at t he cell being cut wit h t he Norm al st yle ( which is usually used for t he sheet background) . Excel's drag/ drop feat ure is t he sam e as cut and past e and will also dest roy t he dat a- ent ry sheet if used. The only way t o avoid t his is t o swit ch off drag/ drop and code our own cut , copy and past e rout ines, such as t hose shown in List ing 6- 7 .

List in g 6 - 7 . Code t o H a n dle Cu t , Copy a n d Pa st e for D a t a - En t r y W or k sh e e t s Dim mbCut As Boolean Dim mrngSource As Range 'Initialise cell copy-paste Public Sub InitCutCopyPaste() 'Hook all the cut, copy and paste keystrokes Application.OnKey "^X", "DoCut" Application.OnKey "^x", "DoCut" Application.OnKey "+{DEL}", "DoCut" Application.OnKey "^C", "DoCopy" Application.OnKey "^c", "DoCopy" Application.OnKey "^{INSERT}", "DoCopy" Application.OnKey "^V", "DoPaste" Application.OnKey "^v", "DoPaste" Application.OnKey "+{INSERT}", "DoPaste" Application.OnKey "{ENTER}", "DoPaste" Application.OnKey "~", "DoPaste" 'Switch off drag/drop Application.CellDragAndDrop = False End Sub 'Handle Cutting cells Public Sub DoCut() If TypeOf Selection Is Range Then mbCut = True Set mrngSource = Selection Selection.Copy

Else Set mrngSource = Nothing Selection.Cut End If End Sub 'Handle Copying cells Public Sub DoCopy() If TypeOf Selection Is Range Then mbCut = False Set mrngSource = Selection Else Set mrngSource = Nothing End If Selection.Copy End Sub 'Handle pasting cells Public Sub DoPaste() If Application.CutCopyMode And Not mrngSource Is Nothing Then Selection.PasteSpecial xlValues If mbCut Then mrngSource.ClearContents End If Application.CutCopyMode = False Else ActiveSheet.Paste End If End Sub

Custom Command Bars Most dict at or applicat ions will include a set of m enus and t oolbars t o provide access t o t he applicat ion's funct ionalit y. Dict at or applicat ions usually have quit e com plex m enu st ruct ures, m ixing bot h Excel's m enu it em s ( such as Print and Print Preview) and cust om it em s. The m aint enance of t hese m enu it em s can be great ly eased by using a t able- driven approach t o building t he com m and bars, as discussed in Chapt er 8 Advanced Com m and Bar Handling.

Processing and Analysis Many dict at or applicat ions use Excel for it s dat a processing, calculat ion and analysis feat ures, rat her t han it s rich UI . All t he processing should be perform ed using hidden sheet s, under program cont rol, wit h only t he result s being shown t o t he users. This enables us t o design our processing sheet s for m axim um calculat ion efficiency, wit hout having t o worry whet her t hey would be readable

by our users. This t opic is covered in det ail in Chapt er 14 Dat a Manipulat ion Techniques.

Presenting Results Excel worksheet s are ext rem ely good present at ion vehicles for det ailed report s and chart s; indeed, t he requirem ent t o use Excel for t he applicat ion's report ing m echanism is oft en t he m ain fact or for choosing t o creat e t he applicat ion ent irely in Excel. I n pract ice, report st yles and layout s are usually dict at ed by t he client ( t o conform t o a house st yle) , but we explain how t o get t he m ost out of Excel's chart ing engine in Chapt er 15 Advanced Chart ing Techniques.

Practical Example PETRAS Timesheet The PETRAS t im esheet add- in has not been updat ed for t his chapt er.

PETRAS Reporting I n Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins, we int roduced t he client side of t he PETRAS applicat ion, wit h which our users ent er t heir weekly t im ekeeping inform at ion and save t he result ing workbook t o a cent ral locat ion on t he net work. This chapt er int roduces t he cent ral consolidat ion, analysis and report ing applicat ion, writ t en as a sim ple, single- workbook dict at or applicat ion. I n t his version of t he applicat ion, we're assum ing t he consolidat ion will be done weekly, as soon as all t he source t im esheet s have been received. The dat a will be ext ract ed from each t im esheet workbook and copied t o a single t able in a result s workbook, from which we'll generat e a single pivot t able t o provide a rudim ent ary analysis capabilit y. The result s workbook can t hen be saved. We also allow previous result s workbooks t o be opened, so t he consolidat ion can be repeat ed ( for inst ance, if a t im esheet arrives lat e) . Lat er chapt ers add m any m ore feat ures t o t he applicat ion. The applicat ion can be found on t he CD in t he folder \ Applicat ion\ Ch06Dict at or Applicat ions and includes t he following files: Pe t r a sTe m pla t e .x ls The client dat a- ent ry t em plat e, unchanged from Chapt er 5 Pe t r a sAddin .x la The client dat a- ent ry support add- in, un changed from Chapt er 5 Pe t r a sRe por t in g.x la The m ain report ing applicat ion Pe t r a sCon solida t ion .x lt A t em plat e t o use for new result s workbooks, cont aining an area for im port ing t im esheet dat a t o and a preform at t ed pivot t able, which references t he consolidat ion area D e bu g.in i A dum m y file t hat t ells t he applicat ion t o run in debug m ode The m ain report ing workbook, Pet rasReport ing.xla, cont ains t he following it em s: M Globa ls This m odule cont ains t he declarat ions of our global const ant s and variables. M Ope n Close This m odule cont ains t he st art up and shut down code, including code sim ilar t o List ing 6- 1 t o check t he Excel version.

M W or k spa ce This m odule cont ains t he code t o st ore, configure and rest ore t he Excel environm ent , very sim ilar t o List ing 6- 2 , List ing 6- 3 , List ing 6- 5 and List ing 6- 6 . M Com m a n dba r s This m odule cont ains code t o creat e and dest roy our m enus, including code lik e List ing 6- 4 t o rest ore t hem . M En t r y Poin t s This m odule cont ains t he rout ines called by our m enus. M St a n da r dCode This m odule cont ains t he WorkbookAlive funct ion shown in List ing 6- 6 , a funct ion t o check whet her a given file has a specific cust om docum ent propert y ( see below) and will cont ain m ore com m on ut ilit y rout ines as t hey're added t hroughout t he book. M Sy st e m Code This m odule cont ains code specific t o t his applicat ion, including a rout ine t o enable/ disable som e of our m enu it em s and t he m ain rout ine t o perform t he dat a consolidat ion. w k sBa ck D r op This is t he worksheet used for t he backdrop graphic. The exam ple applicat ion uses t he code shown in List ing 6- 8 t o set up t he m enu st ruct ure it em by it em . I t is quit e a lengt hy rout ine, for only eight m enu it em s. Fort unat ely, it will be replaced in Chapt er 8 Advanced Com m and Bar Handling, t o use a t able- driven com m and bar builder, enabling us t o im plem ent a m uch m ore com prehensive m enu st ruct ure wit hout adding new code for every it em .

List in g 6 - 8 . Code t o Se t Up t h e M e n u St r u ct u r e Sub SetUpMenus() Dim cbCommandBar As CommandBar Dim oPopup As CommandBarPopup Dim oButton As CommandBarButton ' Hide all the toolbars On Error Resume Next For Each cbCommandBar In Application.CommandBars cbCommandBar.Visible = False cbCommandBar.Enabled = False Next Application.CommandBars(gsMENU_BAR).Delete On Error GoTo 0 'Create our menu bar Set cbCommandBar = Application.CommandBars.Add( _ gsMENU_BAR, , True, True) 'The File menu Set oPopup = cbCommandBar.Controls.Add(msoControlPopup) With oPopup .Caption = "&File"

'File > New Set oButton = .Controls.Add(msoControlButton) With oButton .Caption = "&New Consolidation..." .BeginGroup = True .FaceId = 18 .ShortcutText = "Ctrl+N" .OnAction = "MenuFileNew" Application.OnKey "^N", "MenuFileNew" Application.OnKey "^n", "MenuFileNew" End With 'File > Open Set oButton = .Controls.Add(msoControlButton) With oButton .Caption = "&Open..." .BeginGroup = False .FaceId = 23 .ShortcutText = "Ctrl+O" .OnAction = "MenuFileOpen" Application.OnKey "^O", "MenuFileOpen" Application.OnKey "^o", "MenuFileOpen" End With 'File > Close Set oButton = .Controls.Add(msoControlButton) With oButton .Caption = "&Close" .BeginGroup = False .FaceId = 106 .OnAction = "MenuFileClose" .Enabled = False End With 'File > Save 'Use the standard Save button Set oButton = .Controls.Add(msoControlButton, 3) With oButton .BeginGroup = True .Enabled = False End With 'File > Save As 'Use the standard Save As button Set oButton = .Controls.Add(msoControlButton, 748) With oButton .BeginGroup = False .Enabled = False End With 'File > Exit Set oButton = .Controls.Add(msoControlButton)

With oButton .Caption = "&Exit" .BeginGroup = True .OnAction = "MenuFileExit" End With End With 'The Processing menu Set oPopup = cbCommandBar.Controls.Add(msoControlPopup) With oPopup .Caption = "&Processing" 'Processing > Consolidate Set oButton = .Controls.Add(msoControlButton) With oButton .Caption = "&Consolidate Timesheets" .BeginGroup = True .OnAction = "MenuConsolidate" .Enabled = False End With End With 'The Help menu Set oPopup = cbCommandBar.Controls.Add(msoControlPopup) With oPopup .Caption = "&Help" 'Help > About Set oButton = .Controls.Add(msoControlButton) With oButton .Caption = "&About PETRAS Reporting" .BeginGroup = True .OnAction = "MenuHelpAbout" End With End With cbCommandBar.Visible = True 'Protect the command bars, to prevent customization Application.CommandBars("Toolbar List").Enabled = False End Sub

Identifying Workbooks Dict at or applicat ions oft en need t o ident ify whet her a part icular workbook was creat ed from a part icular t em plat e, or ot herwise " belongs" t o t he applicat ion. One way t o do t his wit hout needing t o open t he workbook is t o add a cust om docum ent propert y t o t he t em plat e file, as shown in Figure 6- 1 .

Figu r e 6 - 1 . Addin g a n I de n t ifyin g Cu st om D ocu m e n t Pr ope r t y t o a Te m pla t e

The dict at or applicat ion can t hen use Excel's FileSearch obj ect t o t est whet her t he file has t hat propert y, using t he funct ion shown in List ing 6- 9 . I n our exam ple applicat ion, we've added t he Pet rasTim esheet propert y t o t he dat a- ent ry t em plat e and t he Pet rasResult s propert y t o t he consolidat ion result s t em plat e.

List in g 6 - 9 . Usin g t h e File Se a r ch Obj e ct t o Ch e ck for a Cu st om D ocu m e n t Pr ope r t y 'Function to test whether a file has the given 'Yes/No property set to Yes

Function FileHasYesProperty(ByVal sFile As String, _ ByVal sProperty As String) As Boolean Dim lSeparator As Long 'Using the FileSearch object With Application.FileSearch 'Start a new search .NewSearch 'For all file types .FileType = msoFileTypeAllFiles 'For the given file in the given directory lSeparator = InStrRev(sFile, "\") .Filename = Mid$(sFile, lSeparator + 1) .LookIn = Left$(sFile, lSeparator) 'Having the given Yes/No property set to Yes .PropertyTests.Add sProperty, msoConditionIsYes, _ Connector:=msoConnectorAnd 'Look for the file .Execute 'If we found it, that file has that property! FileHasYesProperty = .FoundFiles.Count > 0 End With End Function

Using the PETRAS Reporting Application I n Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins, we explained how t o use t he PETRAS t im esheet add- in and t em plat e t o creat e weekly t im esheet workbooks and st ore t hem in a cent ral locat ion. The following st eps can be used t o consolidat e and analyze your t im esheet s using t he PETRAS report ing dict at or applicat ion:

1 . St art Excel and use File > Open t o open t he Pet rasReport ing.xla workbook. 2 . Select t he File > New Consolidat ion m enu, as shown in Figure 6- 2 . This will creat e a new, em pt y consolidat ion workbook and t hen display a st andard file open dialog.

Figu r e 6 - 2 . Th e PETRAS Re por t in g Applica t ion M e n u St r u ct u r e

3 . Select t he t im esheet workbooks t o include in t he consolidat ion by m ult iselect ing t he individual files ( or using Ct rl+ A t o select all t he files in a folder) and click OK t o begin t he consolidat ion. The applicat ion will ext ract t he t im esheet dat a from all t he select ed files, im port ing it int o t he consolidat ion workbook. 4 . Review t he consolidat ed dat a in t he SourceDat a worksheet and analyze t he dat a in t he Pivot Table worksheet .

Conclusion Dict at or applicat ions enable us t o leverage Excel's rich user int erface, calculat ion engine, analysis and/ or present at ion feat ures, while sim ulat ing t he look and behavior of a norm al Windows pr ogr am . The Excel workspace will usually require a significant am ount of configurat ion and cust om izat ion for t he dict at or applicat ion. Unfort unat ely, Excel will rem em ber m ost of t hese configurat ions and t ry t o reuse t hem for t he next ( user) session. To work around Excel's behavior, we m ust st ore t he init ial st at e of t he user's set t ings when our applicat ion st art s and rest ore t hem when we close down. When using a worksheet - based user int erface, ext rem e care m ust be t aken t o prevent accident al corrupt ion of t he sheet , oft en as a result of a cut , copy or past e operat ion. The pract ical exam ple for t his chapt er is a com plet e, but sim ple, dict at or applicat ion t em plat e for you t o use as a st art ing point for your own applicat ions. Lat er chapt ers in t his book add m any m ore feat ures t o t he applicat ion.

Chapter 7. Using Class Modules to Create Objects Class m odules are used t o creat e obj ect s. There are m any reasons for you as a developer t o creat e your own obj ect s, including t he following: To encapsulat e VBA and Windows API code t o m ake it t ransport able and easy t o use and reuse, as shown in Chapt er 9 Underst anding and Using Windows API Calls To t rap event s To raise event s To creat e your own obj ect s and obj ect m odels I n t his chapt er we assum e you are already fam iliar wit h writ ing VBA code t o m anipulat e t he obj ect s in Excel and are fam iliar wit h t he Excel obj ect m odel t hat defines t he relat ionships am ong t hose obj ect s. We also assum e you are fam iliar wit h obj ect propert ies, m et hods and event s. I f you have writ t en code in t he ThisWorkbook m odule, any of t he m odules behind worksheet s or chart s or t he m odule associat ed wit h a userform , you have already worked wit h class m odules. One of t he key feat ures of t hese m odules, like all class m odules, is t he abilit y t o t rap and respond t o event s. The goal of t his chapt er is t o show you how t o creat e your own obj ect s. We begin by explaining how t o creat e a single cust om obj ect and t hen show how you can creat e a collect ion cont aining m ult iple inst ances of t he obj ect . We cont inue wit h a dem onst rat ion of how t o t rap and raise event s wit hin your classes.

Creating Objects Suppose we want t o develop code t o analyze a single cell in a worksheet and cat egorize t he ent ry in t hat cell as one of t he following: Em pt y Cont aining a label Cont aining a const ant num eric value Cont aining a form ula We can readily accom plish t his by creat ing a new obj ect wit h t he appropriat e propert ies and m et hods. Our new obj ect will be a Cell obj ect . I t will have an Analyze m et hod t hat det erm ines t he cell t ype and set s t he CellType propert y t o a num eric value t hat can be used in our code. We will also have a Descript iveCellType propert y so we can display t he cell t ype as t ext . List ing 7- 1 shows t he CCell class m odule code. This class m odule is used t o creat e a cust om Cell obj ect represent ing t he specified cell, analyze t he cont ent s of t he cell and ret urn t he t ype of t he cell as a user- friendly t ext st ring.

List in g 7 - 1 . Th e CCe ll Cla ss M odu le Option Explicit Public Enum anlCellType anlCellTypeEmpty anlCellTypeLabel anlCellTypeConstant anlCellTypeFormula End Enum Private muCellType As anlCellType Private mrngCell As Excel.Range Property Set Cell(ByRef rngCell As Excel.Range) Set mrngCell = rngCell End Property Property Get Cell() As Excel.Range Set Cell = mrngCell End Property

Property Get CellType() As anlCellType CellType = muCellType End Property Property Get DescriptiveCellType() As String Select Case muCellType Case anlCellTypeEmpty DescriptiveCellType = "Empty" Case anlCellTypeFormula DescriptiveCellType = "Formula" Case anlCellTypeConstant DescriptiveCellType = "Constant" Case anlCellTypeLabel DescriptiveCellType = "Label" End Select End Property Public Sub Analyze() If IsEmpty(mrngCell) Then muCellType = anlCellTypeEmpty ElseIf mrngCell.HasFormula Then muCellType = anlCellTypeFormula ElseIf IsNumeric(mrngCell.Formula) Then muCellType = anlCellTypeConstant Else muCellType = anlCellTypeLabel End If End Sub

The CCell class m odule cont ains a public enum erat ion wit h four m em bers, each of which represent s a cell t ype. By default , t he enum erat ion m em bers will be assigned values from zero t o t hree. The enum erat ion m em ber nam es help m ake our code m ore readable and easier t o m aint ain. The enum erat ion m em ber values are t ranslat ed int o user- friendly t ext by t he Descript iveCellType pr oper t y . List ing 7- 2 shows t he AnalyzeAct iveCell procedure. This procedure is cont ained in t he st andard m odule MEnt ryPoint s.

List in g 7 - 2 . Th e An a lyze Act ive Ce ll Pr oce du r e Public Sub AnalyzeActiveCell() Dim clsCell As CCell ' Create new instance of Cell object Set clsCell = New CCell ' Determine cell type and display it

Set clsCell.Cell = Application.ActiveCell clsCell.Analyze MsgBox clsCell.DescriptiveCellType End Sub

I f you select a cell on a worksheet and run t he AnalyzeAct iveCell procedure, it creat es a new inst ance of t he CCell class t hat it st ores in t he clsCell obj ect variable. The procedure t hen assigns t he act ive cell t o t he Cell propert y of t his Cell obj ect , execut es it s Analyze m et hod and displays t he result of it s Descript iveCellType propert y. This code is cont ained in t he Analysis1.xls workbook in t he \ Concept s\ Ch07Using Class Modules t o Creat e Obj ect s folder on t he CD t hat accom panies t his book .

Class Module Structure A class m odule cont ains t he blueprint for an obj ect . You can use it t o creat e as m any inst ances of t he obj ect as you require. I t defines t he m et hods and propert ies of t he obj ect . Any public subrout ines or funct ions in t he class m odule becom e m et hods of t he obj ect . Any public variables or propert y procedures becom e propert ies of t he obj ect .

Property Procedures Rat her t han rely on public variables t o define propert ies, it is bet t er pract ice t o use propert y procedures. These give you m ore cont rol over how propert ies are assigned values and how t hey ret urn values. Propert y procedures enable you t o validat e t he dat a t hat is passed t o t he obj ect and t o perform relat ed act ions where appropriat e. They also enable you t o m ake propert ies read only or writ e only if you want . The CCell class uses t wo privat e m odule level variables t o st ore it s propert ies int ernally. m uCellType holds t he cell t ype in t he form of an anlCellType enum erat ion m em ber value. m rngCell holds a reference t o t he single- cell Range t hat an obj ect creat ed from t he CCell class will r epr esent . Propert y procedures cont rol t he int erface bet ween t hese variables and t he out side world. Propert y procedures com e in t hree form s: Pr ope r t y Le t Used t o assign a value t o a propert y Pr ope r t y Se t Used t o assign an obj ect t o a propert y Pr ope r t y Ge t Used t o ret urn t he value or t he obj ect reference in a propert y t o t he out side w or ld The propert y nam e present ed t o t he out side world is t he sam e as t he nam e of t he propert y procedure. The CCell class uses Propert y Set Cell t o enable you t o assign a Range reference t o t he Cell propert y of t he Cell obj ect . The propert y procedure st ores t he reference in t he m rngCell

variable. This procedure could have a validat ion check t o ensure t hat only single- cell ranges can be specified. There is a corresponding Propert y Get Cell procedure t hat allows t his propert y t o be read. The CCell class uses t wo Propert y Get procedures t o ret urn t he cell t ype as an enum erat ion m em ber value or as descript ive t ext . These propert ies are read- only because t hey have no corresponding Propert y Let procedures.

Methods The CCell class has one m et hod defined by t he Analyze subrout ine. I t det erm ines t he t ype of dat a in t he cell referred t o by t he m rngCell variable and assigns t he corresponding enum erat ion m em ber t o t he m uCellType variable. Because it is a subrout ine, t he Analyze m et hod doesn't ret urn a value t o t he out side world. I f a m et hod is creat ed using a funct ion, it can ret urn a value. The Analyze m et hod could be convert ed t o a funct ion t hat ret urned t he t ext value associat ed wit h t he cell t ype, as shown in List ing 7- 3 .

List in g 7 - 3 . Th e An a lyze M e t h od of t h e Ce ll Obj e ct Public Function Analyze() As String If IsEmpty(mrngCell) Then muCellType = anlCellTypeEmpty ElseIf mrngCell.HasFormula Then muCellType = anlCellTypeFormula ElseIf IsNumeric(mrngCell.Formula) Then muCellType = anlCellTypeConstant Else muCellType = anlCellTypeLabel End If Analyze = Me.DescriptiveCellType End Function

We could t hen analyze t he cell and display t he ret urn value wit h t he following single line of code inst ead of t he original t wo lines:

MsgBox clsCell.Analyze()

Creating a Collection Now t hat we have a Cell obj ect , we will want t o creat e m any inst ances of t he obj ect so we can analyze a worksheet or ranges of cells wit hin a worksheet . The easiest way t o m anage t hese new obj ect s is t o st ore t hem in a collect ion. VBA provides a Collect ion obj ect t hat we can use t o st ore obj ect s and dat a. The Collect ion obj ect has four m et hods: Ad d Count I t em Rem ove There is no rest rict ion on t he t ype of dat a t hat can be st ored wit hin a Collect ion obj ect , and it em s wit h different dat a t ypes can be st ored in t he sam e Collect ion obj ect . I n our case, we want t o be consist ent and st ore j ust Cell obj ect s in our collect ion. To creat e a new Collect ion, t he first st ep is t o add a new st andard m odule t o cont ain global variables. This m odule will be called MGlobals. Next , add t he following variable declarat ion t o t he MGlobals m odule t o declare a global Collect ion obj ect variable t o hold t he collect ion, as follows:

Public gcolCells As Collection

Now add t he Creat eCellsCollect ion procedure shown in List ing 7- 4 t o t he MEnt ryPoint s m odule. The m odified code is cont ained in t he Analysis2.xls workbook in t he \ Concept s\ Ch07Using Class Modules t o Creat e Obj ect s folder on t he CD t hat accom panies t his book.

List in g 7 - 4 . Cr e a t in g a Colle ct ion of Ce ll Obj e ct s Public Sub CreateCellsCollection() Dim clsCell As CCell Dim rngCell As Range ' Create new Cells collection Set gcolCells = New Collection ' Create Cell objects for each cell in Selection For Each rngCell In Application.Selection

Set clsCell = New CCell Set clsCell.Cell = rngCell clsCell.Analyze 'Add the Cell to the collection gcolCells.Add Item:=clsCell, Key:=rngCell.Address Next rngCell ' Display the number of Cell objects stored MsgBox "Number of cells stored: " & CStr(gcolCells.Count) End Sub

We declare gcolCells as a public obj ect variable so t hat it persist s while t he workbook is open and is visible t o all procedures in t he VBA proj ect . The Creat eCellsCollect ion procedure creat es a new inst ance of t he collect ion and loops t hrough t he current ly select ed cells, creat ing a new inst ance of t he Cell obj ect for each cell and adding it t o t he collect ion. The address of each cell, in $A$1 reference st yle, is used as a key t o uniquely ident ify it and t o provide a way of accessing t he Cell obj ect lat er. We can loop t hrough t he obj ect s in t he collect ion using a For... Each loop or we can access individual Cell obj ect s by t heir posit ion in t he collect ion or by using t he key value. Because t he I t em m et hod is t he default m et hod for t he collect ion, we can use code like t he following t o access a specific Cell obj ect :

Set rngCell = gcolCells(3) Set rngCell = gcolCells("$A$3")

Creating a Collection Object The collect ion we have est ablished is easy t o use but it lacks som e feat ures we would like t o have. As it st ands, t here is no cont rol over t he t ype of obj ect s t hat can be added t o t he collect ion. We would also like t o add a m et hod t o t he collect ion t hat enables us t o highlight cells of t he sam e t ype and anot her m et hod t o rem ove t he highlight s. We will first add t wo new m et hods t o t he CCell class m odule. The Highlight m et hod adds color t o t he Cell obj ect according t o t he CellType. The UnHighlight m et hod rem oves t he color. List ing 7- 5 shows t he new code. Not e t hat we are applying t he principle of encapsulat ion. All t he code t hat relat es t o t he Cell obj ect is cont ained in t he CCell class m odule, not in any ot her m odule. Doing t his ensures t hat t he code can be easily found and m aint ained and m eans t hat it can be easily t ransport ed from one proj ect t o anot her .

List in g 7 - 5 . N e w Code for t h e CCe ll Cla ss M odu le

Public Sub Highlight() Cell.Interior.ColorIndex = Choose(muCellType + 1, 5, 6, 7, 8) End Sub Public Sub UnHighlight() Cell.Interior.ColorIndex = xlNone End Sub

We can now creat e a new class m odule nam ed CCells t o cont ain t he Cells collect ion, as shown in List ing 7- 6 . The com plet e code is cont ained in t he Analysis3.xls workbook in t he \ Concept s\ Ch07Using Class Modules t o Creat e Obj ect s folder on t he CD t hat accom panies t his book.

List in g 7 - 6 . Th e CCe lls Cla ssM odu le Option Explicit Private mcolCells As Collection Property Get Count() As Long Count = mcolCells.Count End Property Property Get Item(ByVal vID As Variant) As CCell Set Item = mcolCells(vID) End Property Private Sub Class_Initialize() Set mcolCells = New Collection End Sub Public Sub Add(ByRef rngCell As Range) Dim clsCell As CCell Set clsCell = New CCell Set clsCell.Cell = rngCell clsCell.Analyze mcolCells.Add Item:=clsCell, Key:=rngCell.Address End Sub Public Function NewEnum() As IUnknown Set NewEnum = mcolCells.[_NewEnum] End Function Public Sub Highlight(ByVal uCellType As anlCellType) Dim clsCell As CCell For Each clsCell In mcolCells If clsCell.CellType = uCellType Then clsCell.Highlight End If

Next clsCell End Sub Public Sub UnHighlight(ByVal uCellType As anlCellType) Dim clsCell As CCell For Each clsCell In mcolCells If clsCell.CellType = uCellType Then clsCell.UnHighlight End If Next clsCell End Sub

The m colCells Collect ion obj ect variable is declared as a privat e, m odule- level variable and is inst ant iat ed in t he I nit ialize procedure of t he class m odule. Because t he Collect ion obj ect is now hidden from t he out side world, we need t o writ e our own Add m et hod for it . We also have creat ed I t em and Count propert y procedures t o em ulat e t he corresponding propert ies of t he collect ion. The input argum ent for t he I t em propert y is declared as a Variant dat a t ype because it can be eit her a num eric index or t he st ring key t hat ident ifies t he collect ion m em ber. The Highlight m et hod loops t hrough each m em ber of t he collect ion. I f t he CellType propert y of t he Cell obj ect is t he sam e as t he t ype specified by t he uCellType argum ent , we execut e t he Cell obj ect 's Highlight m et hod. The UnHighlight m et hod loops t hrough t he collect ion and execut es t he UnHighlight m et hod of all Cell obj ect s whose t ype is t he sam e as t he t ype specified by t he uCellType argum ent . We've m odified t he public Collect ion variable declarat ion in MGlobals t o refer t o our new cust om collect ion class, as shown here:

Public gclsCells As CCells

We've also m odified t he Creat eCellsCollect ion procedure in t he MEnt ryPoint s m odule t o inst ant iat e and populat e our cust om collect ion, as shown in List ing 7- 7 .

List in g 7 - 7 . M En t r yPoin t s Code t o Cr e a t e a Ce lls Obj e ct Colle ct ion Public Sub CreateCellsCollection() Dim Dim Dim Dim

clsCell As CCell lIndex As Long lCount As Long rngCell As Range

Set gclsCells = New CCells For Each rngCell In Application.ActiveSheet.UsedRange

gclsCells.Add rngCell Next rngCell ' Count the number of formula cells in the collection. For lIndex = 1 To gclsCells.Count If gclsCells.Item(lIndex).CellType = anlCellTypeFormula Then lCount = lCount + 1 End If Next lIndex MsgBox "Number of Formulas = " & CStr(lCount) End Sub

We declare gclsCells as a public obj ect variable t o cont ain our cust om Cells collect ion obj ect . The Creat eCellsCollect ion procedure inst ant iat es gclsCells and uses a For...Each loop t o add all t he cells in t he act ive worksheet 's used range t o t he collect ion. Aft er loading t he collect ion, t he procedure count s t he num ber of cells t hat cont ain form ulas and displays t he result . The MEnt ryPoint s m odule cont ains a ShowForm ulas procedure t hat can be execut ed t o highlight and unhighlight t he form ula cells in t he worksheet . Several addit ional variat ions are provided for ot her cell t ypes. This code illust rat es t wo short com ings of our cust om collect ion class. You can't process t he m em bers of t he collect ion in a For...Each loop. You m ust use an index and t he I t em propert y inst ead. Also, our collect ion has no default propert y, so you can't short cut t he I t em propert y using t he st andard collect ion synt ax gclsCells( 1) t o access a m em ber of t he collect ion. You m ust specify t he I t em propert y explicit ly in your code. We explain how t o solve t hese problem s using Visual Basic or j ust a t ext edit or in t he next sect ion.

Addressing Class Collection Shortcomings I t is possible t o m ake your cust om collect ion class behave like a built - in collect ion. I t requires not hing m ore t han a t ext edit or t o m ake t he adj ust m ent s, but first we explain how t o do it by set t ing procedure at t ribut es using Visual Basic 6 ( VB6) t o bet t er illust rat e t he nat ure of t he changes r equir ed.

Using Visual Basic I n VB6, unlike Visual Basic for Applicat ions used in Excel, you can specify a propert y t o be t he default propert y of t he class. I f you declare t he I t em propert y t o be t he default propert y, you can om it .I t em when referencing a m em ber of t he collect ion and use a short cut such as gclsCells( 1) inst ead. I f you have VB6 inst alled you can export t he code m odule CCells t o a file and open t hat file in VB6. Place your cursor anywhere wit hin t he I t em propert y procedure and select Tools > Procedure At t r ibut es from t he m enu t o display t he Procedure At t ribut es dialog. Then click t he Advanced > >

but t on and under t he Advanced opt ions select ( Default ) from t he Procedure I D com bo box. This will m ake t he I t em propert y t he default propert y for t he class. When you save your changes and im port t his file back int o your Excel VBA proj ect , t he at t ribut e will be recognized even t hough t here is no way t o set at t ribut e opt ions wit hin t he Excel Visual Basic edit or. VB6 also enables you t o set up t he special procedure in List ing 7- 8 .

List in g 7 - 8 . Code t o Allow t h e Colle ct ion t o be Re fe r e n ce d in a For ... Each Loop Public Function NewEnum() As IUnknown Set NewEnum = mcolCells.[_NewEnum] End Function

This procedure m ust be given an at t ribut e value of 4, which you ent er direct ly int o t he Procedure I D com bo box in t he Procedure At t ribut es dialog. Giving t he NewEnum procedure t his at t ribut e value enables a For... Each loop t o process t he m em bers of t he collect ion. Aft er you have m ade t his addit ion t o your class m odule in VB6 and saved your changes, you can load t he m odule back int o your Excel VBA proj ect , and once again t he changes will be recognized.

Using a Text Editor Even wit hout VB6, you can easily creat e t hese procedures and t heir at t ribut es using a t ext edit or such as Not epad. Export t he CCells class m odule t o a file and open it using t he t ext edit or. Modify your code t o look like t he exam ple shown in List ing 7- 9 .

List in g 7 - 9 . Vie w in g t h e Code in a Te x t Edit or Property Get Item(ByVal vID As Variant) As CCell Attribute Item.VB_UserMemId = 0 Set Item = mcolCells(vID) End Property Public Function NewEnum() As IUnknown Attribute NewEnum.VB_UserMemId = -4 Set NewEnum = mcolCells.[_NewEnum] End Function

When t he m odified class m odule is im port ed back int o your proj ect , t he At t ribut e lines will not be visible, but t he procedures will work as expect ed. You can now refer t o a m em ber of t he collect ion as gclsCells( 1) and use your cust om collect ion class in a For ... Each loop as shown in List ing 7-

10 .

List in g 7 - 1 0 . Re fe r e n cin g t h e Ce lls Colle ct ion in a For ... Each Loop For Each clsCell In gclsCells If clsCell.CellType = anlCellTypeFormula Then lCount = lCount + 1 End If Next clsCell

Trapping Events A powerful capabilit y built in t o class m odules is t he abilit y t o respond t o event s. We want t o ext end our Analysis applicat ion so t hat when you double- click a cell t hat has been analyzed, all t he cells of t he sam e t ype will be highlight ed. When you right - click t he cell, t he highlight will be rem oved. We also want t o ensure t hat cells are reanalyzed when t hey are changed so t hat our corresponding Cell obj ect s are kept up t o dat e. The code shown in t his sect ion is cont ained in t he Analysis4.xls workbook in t he \ Concept s\ Ch07Using Class Modules t o Creat e Obj ect s folder on t he CD t hat accom panies t his book. To t rap t he event s associat ed wit h an obj ect you need t o do t wo t hings: Declare a W it h Ev e n t s variable of t he correct obj ect t ype in a class m odule. Assign an obj ect reference t o t he variable. The event s we want t o t rap are associat ed wit h t he Worksheet obj ect . Therefore, we need t o creat e a Wit hEvent s obj ect variable in t he CCells class m odule t hat references t he worksheet cont aining t he Cell obj ect s. The appropriat e Wit hEvent s variable declarat ion is m ade at t he m odule- level wit hin t he CCells class and looks like t he following:

Private WithEvents mwksWorkSheet As Excel.Worksheet

As soon as you add t his variable declarat ion t o t he CCells class m odule, you can select t he Wit hEvent s variable nam e from t he drop- down m enu at t he t op left of t he m odule and use t he drop- down m enu at t he t op right of t he m odule t o see t he event s t hat can be t rapped, as shown in Figure 7- 1 . Event nam es list ed in bold are current ly being t rapped wit hin t he class, as you will see in a m om ent .

Figu r e 7 - 1 . Th e W or k sh e e t Eve n t Pr oce du r e s Ava ila ble in CCe lls [View full size image]

Select ing an event from t he drop- down creat es a shell for t he event procedure in t he m odule. You need t o add t he procedures shown in List ing 7- 11 t o t he CCells class m odule. They include a new propert y nam ed Worksheet t hat refers t o t he Worksheet obj ect cont aining t he Cell obj ect s held by t he collect ion, as well as t he code for t he BeforeDoubleClick, BeforeRight Click and Change event s.

List in g 7 - 1 1 . Addit ion s t o t h e CCe lls Cla ss M odu le Property Set Worksheet(wks As Excel.Worksheet) Set mwksWorkSheet = wks End Property

Private Sub mwksWorkSheet_BeforeDoubleClick( _ ByVal Target As Range, Cancel As Boolean) If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then Highlight mcolCells(Target.Address).CellType Cancel = True End If End Sub Private Sub mwksWorkSheet_BeforeRightClick( _ ByVal Target As Range, Cancel As Boolean) If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then UnHighlight mcolCells(Target.Address).CellType Cancel = True End If End Sub Private Sub mwksWorkSheet_Change(ByVal Target As Range) Dim rngCell As Range

If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then For Each rngCell In Target.Cells mcolCells(rngCell.Address).Analyze Next rngCell End If End Sub

The Creat eCellsCollect ion procedure in t he MEnt ryPoint s m odule needs t o be changed as shown in List ing 7- 12. The new code assigns a reference t o t he act ive worksheet t o t he Worksheet propert y of t he Cells obj ect so t he worksheet 's event s can be t rapped.

List in g 7 - 1 2 . Th e Upda t e d Cr e a t e Ce llsColle ct ion Pr oce du r e in t h e M En t r yPoin t s M odu le Public Sub CreateCellsCollection() Dim clsCell As CCell Dim rngCell As Range Set gclsCells = New CCells Set gclsCells.Worksheet = ActiveSheet For Each rngCell In ActiveSheet.UsedRange gclsCells.Add rngCell Next rngCell End Sub

You can now execut e t he Creat eCellsCollect ion procedure in MEnt ryPoint s t o creat e a new collect ion wit h all t he links in place t o t rap t he double- click and right - click event s for t he cells in t he worksheet . Double- clicking a cell changes t he cell's background of all sim ilar cells t o a color t hat depends on t he cell's t ype. Right - clicking a cell rem oves t he background color.

Raising Events Anot her powerful capabilit y of class m odules is t he abilit y t o raise event s. You can define your own event s and t rigger t hem in your code. Ot her class m odules can t rap t hose event s and respond t o t hem . To illust rat e t his, we will change t he way our Cells collect ion t ells t he Cell obj ect s it cont ains t o execut e t he Highlight and UnHighlight m et hods. The Cells obj ect will raise an event t hat will be t rapped by t he Cell obj ect s. The code shown in t his sect ion is cont ained in t he Analysis5.xls workbook in t he \ Concept s\ Ch07Using Class Modules t o Creat e Obj ect s folder on t he CD t hat accom panies t his book. To raise an event in a class m odule you need t wo t hings: An Ev e n t declarat ion at t he t op of t he class m odule. A line of code t hat uses Ra ise Eve n t t o cause t he event t o t ake place. The code changes shown in List ing 7- 13 should be m ade in t he CCells class m odule.

List in g 7 - 1 3 . Ch a n ge s t o t h e CCe lls Cla ss M odu le t o Ra ise a n Eve n t Option Explicit Public Enum anlCellType anlCellTypeEmpty anlCellTypeLabel anlCellTypeConstant anlCellTypeFormula End Enum Private mcolCells As Collection Private WithEvents mwksWorkSheet As Excel.Worksheet Event ChangeColor(uCellType As anlCellType, bColorOn As Boolean) Public Sub Add(ByRef rngCell As Range) Dim clsCell As CCell Set clsCell = New CCell Set clsCell.Cell = rngCell Set clsCell.Parent = Me clsCell.Analyze mcolCells.Add Item:=clsCell, Key:=rngCell.Address End Sub Private Sub mwksWorkSheet_BeforeDoubleClick( _

ByVal Target As Range, Cancel As Boolean) If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then RaiseEvent ChangeColor( _ mcolCells(Target.Address).CellType, True) Cancel = True End If End Sub Private Sub mwksWorkSheet_BeforeRightClick( _ ByVal Target As Range, Cancel As Boolean) If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then RaiseEvent ChangeColor( _ mcolCells(Target.Address).CellType, False) Cancel = True End If End Sub

Not e t hat we m oved t he anlCellType Enum declarat ion int o t he parent collect ion class m odule. Now t hat we have creat ed an explicit parent - child relat ionship bet ween t he CCell and CCells class, any public t ypes used by bot h classes m ust reside in t he parent class m odule; ot herwise, circular dependencies bet ween t he classes t hat cannot be handled by VBA will be creat ed. I n t he declarat ions sect ion of CCells we declare an event nam ed ChangeColor t hat has t wo argum ent s. The first argum ent defines t he cell t ype t o be changed and t he second argum ent is a Boolean value t o indicat e whet her we are t urning color on or off. The BeforeDoubleClick and BeforeRight Click event procedures have been changed t o raise t he new event and pass t he cell t ype of t he t arget cell and t he on or off value. The Add m et hod has been updat ed t o set a new Parent propert y of t he Cell obj ect . This propert y holds a reference t o t he Cells obj ect . The nam e reflect s t he relat ionship bet ween t he Cells obj ect as t he parent obj ect and t he Cell obj ect as t he child obj ect . Trapping t he event raised by t he Cells obj ect in anot her class m odule is carried out in exact ly t he sam e way we have t rapped ot her event s. We creat e a Wit hEvent s obj ect variable and set it t o reference an inst ance of t he class t hat defines and raises t he event . The changes shown in List ing 7- 14 should be m ade t o t he CCell class m odule.

List in g 7 - 1 4 . Ch a n ge s t o t h e CCe ll Cla ss M odu le t o Tr a p t h e Ch a n ge Color Eve n t Option Explicit Private muCellType As anlCellType Private mrngCell As Excel.Range Private WithEvents mclsParent As CCells Property Set Parent(ByRef clsCells As CCells)

Set mclsParent = clsCells End Property Private Sub mclsParent_ChangeColor(uCellType As anlCellType, _ bColorOn As Boolean) If Me.CellType uCellType Then Exit Sub If bColorOn Then Highlight Else UnHighlight End If End Sub

A new m odule- level obj ect variable m clsParent is declared Wit hEvent s as an inst ance of t he CCells class. A reference t o a Cells obj ect is assigned t o m clsParent in t he Parent Propert y Set procedure. When t he Cells obj ect raises t he ChangeColor event , it will be t rapped by all t he Cell obj ect s. The Cell obj ect s will t ake act ion in response t o t he event if t hey are of t he correct cell t ype.

A Family Relationship Problem Unfort unat ely, we have int roduced a problem in our applicat ion. Running t he Creat eCellsCollect ion procedure m ult iple t im es creat es a m em ory leak. Norm ally when you overwrit e an obj ect in VBA, VBA cleans up t he old version of t he obj ect and reclaim s t he m em ory t hat was used t o hold it . You can also set an obj ect equal t o Not hing t o reclaim t he m em ory used by it . I t is good pract ice t o do t his explicit ly when you no longer need an obj ect , rat her t han relying on VBA t o do it .

Set gclsCells = Nothing

When you creat e t wo obj ect s t hat st ore references t o each ot her, t he syst em will no longer reclaim t he m em ory t hey used when t hey are set t o new versions or when t hey are set t o Not hing. When analyzing t he worksheet in Analysis5.xls wit h 574 cells in t he used range, t here is a loss of about 250KB of RAM each t im e Creat eCellsCollect ion is execut ed during an Excel session.

N OTE: I f you are running Windows NT, 2000 or XP, you can check t he am ount of RAM current ly used by Excel by pressing Ct rl+ Shift + Esc t o display t he Processes window in Task Manager and exam ining t he Mem Usage colum n for t he row where t he I m age Nam e colum n is EXCEL.EXE.

One way t o avoid t his problem is t o m ake sure you rem ove t he cross- references from t he linked obj ect s before t he obj ect s are rem oved. You can do t his by adding a m et hod such as t he Term inat e m et hod shown in List ing 7- 15 t o t he problem classes, in our case t he CCell class.

List in g 7 - 1 5 . Th e Te r m in a t e M e t h od in t h e CCe ll Cla ss M odu le Public Sub Terminate() Set mclsParent = Nothing End Sub

The code in List ing 7- 16 is added t o t he CCells class m odule. I t calls t he Term inat e m et hod of each Cell class cont ained in t he collect ion t o dest roy t he cross- reference bet ween t he classes.

List in g 7 - 1 6 . Th e Te r m in a t e M e t h od in t h e CCe lls Cla ss M odu le Public Sub Terminate() Dim clsCell As CCell For Each clsCell In mcolCells clsCell.Terminate Set clsCell = Nothing Next clsCell Set mcolCells = Nothing End Sub

The code in List ing 7- 17 is added t o t he Creat eCellsCollect ion procedure in t he MEnt ryPoint s m odule.

List in g 7 - 1 7 . Th e Cr e a t e Ce llsColle ct ion Pr oce du r e in t h e M En t r yPoin t s M odu le Public Sub CreateCellsCollection() Dim clsCell As CCell Dim rngCell As Range ' Remove any existing instance of the Cells collection If Not gclsCells Is Nothing Then gclsCells.Terminate Set gclsCells = Nothing End If

Set gclsCells = New CCells Set gclsCells.Worksheet = ActiveSheet For Each rngCell In ActiveSheet.UsedRange gclsCells.Add rngCell Next rngCell End Sub

I f Creat eCellsCollect ion finds an exist ing inst ance of gclsCells, it execut es t he obj ect 's Term inat e m et hod before set t ing t he obj ect t o Not hing. The gclsCells Term inat e m et hod it erat es t hrough all t he obj ect s in t he collect ion and execut es t heir Term inat e m et hods. I n a m ore com plex obj ect m odel wit h m ore levels, you could have obj ect s in t he m iddle of t he st ruct ure t hat cont ain bot h child and parent references. The Term inat e m et hod in t hese obj ect s would need t o run t he Term inat e m et hod of each of it s children and t hen set it s own Parent propert y t o Not hing.

Creating a Trigger Class I nst ead of raising t he ChangeColor event in t he CCells class m odule, we can set up a new class m odule t o t rigger t his event . Creat ing a t rigger class gives us t he opport unit y t o int roduce a m ore efficient way t o highlight our Cell obj ect s. We can creat e four inst ances of t he t rigger class, one for each cell t ype, and assign t he appropriat e inst ance t o each Cell obj ect . That m eans each Cell obj ect is only sent a m essage t hat is m eant for it , rat her t han hearing all m essages sent t o all Cell obj ect s. The t rigger class also enables us t o elim inat e t he parent / child relat ionship bet ween our CCells and CCell classes, t hus rem oving t he requirem ent t o m anage cross- references. Not e t hat it will not always be possible or desirable t o do t his. The code shown in t his sect ion is cont ained in t he Analysis6.xls workbook in t he \ Concept s\ Ch07Using Class Modules t o Creat e Obj ect s folder on t he CD t hat accom panies t his book. List ing 7- 18 shows t he code in a new CTypeTrigger class m odule. The code declares t he ChangeColor event , which now only needs one argum ent t o specify whet her color is t urned on or off. The class has Highlight and UnHighlight m et hods t o raise t he event .

List in g 7 - 1 8 . Th e CType Tr igge r Cla ss M odu le Option Explicit Public Event ChangeColor(bColorOn As Boolean) Public Sub Highlight() RaiseEvent ChangeColor(True) End Sub

Public Sub UnHighlight() RaiseEvent ChangeColor(False) End Sub

List ing 7- 19 cont ains t he changes t o t he CCell class m odule t o t rap t he ChangeColor event raised in CTypeTrigger. Depending on t he value of bColorOn, t he event procedure runs t he Highlight or UnHighlight m et hods.

List in g 7 - 1 9 . Ch a n ge s t o t h e CCe ll Cla ss M odu le t o Tr a p t h e Ch a n ge Color Eve n t of CType Tr igge r Option Explicit Private muCellType As anlCellType Private mrngCell As Excel.Range Private WithEvents mclsTypeTrigger As CTypeTrigger Property Set TypeTrigger(clsTrigger As CTypeTrigger) Set mclsTypeTrigger = clsTrigger End Property Private Sub mclsTypeTrigger_ChangeColor(bColorOn As Boolean) If bColorOn Then Highlight Else UnHighlight End If End Sub

List ing 7- 20 cont ains t he changes t o t he CCells m odule. An array variable m aclsTriggers is declared t o hold t he inst ances of CTypeTrigger. The I nit ialize event redim ensions m aclsTriggers t o m at ch t he num ber of cell t ypes and t he For ... Next loop assigns inst ances of CTypeTrigger t o t he array elem ent s. The Add m et hod assigns t he correct elem ent of m aclsTriggers t o each Cell obj ect according t o it s cell t ype. The result is t hat each Cell obj ect only list ens for m essages t hat apply t o it s own cell t ype.

List in g 7 - 2 0 . Ch a n ge s t o t h e CCe lls Cla ss M odu le t o Assign Re fe r e n ce s t o CType Tr igge r t o Ce ll Obj e ct s Option Explicit Public Enum anlCellType anlCellTypeEmpty

anlCellTypeLabel anlCellTypeConstant anlCellTypeFormula End Enum Private mcolCells As Collection Private WithEvents mwksWorkSheet As Excel.Worksheet Private maclsTriggers() As CTypeTrigger Private Sub Class_Initialize() Dim uCellType As anlCellType Set mcolCells = New Collection ' Initialize the array of cell type triggers, ' one element for each of our cell types. ReDim maclsTriggers(anlCellTypeEmpty To anlCellTypeFormula) For uCellType = anlCellTypeEmpty To anlCellTypeFormula Set maclsTriggers(uCellType) = New CTypeTrigger Next uCellType End Sub Public Sub Add(ByRef rngCell As Range) Dim clsCell As CCell Set clsCell = New CCell Set clsCell.Cell = rngCell clsCell.Analyze Set clsCell.TypeTrigger = maclsTriggers(clsCell.CellType) mcolCells.Add Item:=clsCell, Key:=rngCell.Address End Sub Public Sub Highlight(ByVal uCellType As anlCellType) maclsTriggers(uCellType).Highlight End Sub Public Sub UnHighlight(ByVal uCellType As anlCellType) maclsTriggers(uCellType).UnHighlight End Sub Private Sub mwksWorkSheet_BeforeDoubleClick( _ ByVal Target As Range, Cancel As Boolean) If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then Highlight mcolCells(Target.Address).CellType Cancel = True End If End Sub Private Sub mwksWorkSheet_BeforeRightClick( _ ByVal Target As Range, Cancel As Boolean) If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then UnHighlight mcolCells(Target.Address).CellType Cancel = True End If

End Sub Private Sub mwksWorkSheet_Change(ByVal Target As Range) Dim rngCell As Range Dim clsCell As CCell If Not Application.Intersect(Target, _ mwksWorkSheet.UsedRange) Is Nothing Then For Each rngCell In Target.Cells Set clsCell = mcolCells(rngCell.Address) clsCell.Analyze Set clsCell.TypeTrigger = _ maclsTriggers(clsCell.CellType) Next rngCell End If End Sub

Practical Example PETRAS Timesheet I n our pract ical exam ple for t his chapt er, we add an applicat ion- level event handling class t o our PETRAS t im esheet applicat ion t hat will m ake t wo significant changes. First , it will enable us t o convert t he t im e- ent ry workbook int o an Excel t em plat e. This will sim plify creat ion of new t im eent ry workbooks for new purposes as well as allow m ult iple t im e ent ry workbooks t o be open at t he sam e t im e. Second, t he event handler will aut om at ically det ect whet her a t im e ent ry workbook is act ive and enable or disable our t oolbar but t ons accordingly. Table 7- 1 sum m arizes t he changes m ade t o t he PETRAS t im esheet applicat ion for t his chapt er.

Ta ble 7 - 1 . Ch a n ge s t o PETRAS Tim e sh e e t Applica t ion for Ch a pt e r 7 M odu le

Pr oce du r e

Ch a n g e

Pet rasTem plat e.xlt

Changed t he norm al workbook int o a t em plat e w or k book

CAppEv ent Handler

Added an applicat ion- level event handling class t o t he add- in

MEnt r yPoint s

New Tim eSheet

New procedure t o creat e t im esheet s from t he t em plat e workbook

MOpenClose

Aut o_Open

Rem oved t im esheet init ializat ion logic and delegat ed it t o t he event handling class

MSyst em Code

Moved all t im e- ent ry workbook m anagem ent code int o t he event handling class

The Template A t em plat e workbook react s different ly t han a norm al workbook when opened using t he Excel Workbooks.Open m et hod. A norm al workbook will sim ply be opened. When a t em plat e workbook is opened a new, unsaved copy of t he t em plat e workbook will be creat ed. To creat e a t em plat e workbook from a norm al workbook, choose File > Save As from t he Excel m enu and select t he Tem plat e ent ry from t he Save as t ype drop- down. As soon as you select t he Tem plat e opt ion, Excel will unhelpfully m odify t he direct ory where you are saving your workbook t o t he Office Tem plat es direct ory, so don't forget t o change t his t o t he locat ion where you are st oring your applicat ion files.

Aft er we begin using a t em plat e workbook, t he user has com plet e cont rol over t he workbook filenam e. We will det erm ine whet her a given workbook belongs t o us by checking for t he unique nam ed const ant set I sTim eSheet t hat we have added t o our t em plat e workbook for t his purpose. A t em plat e workbook com bined wit h an applicat ion- level event handler enables us t o support m ult iple inst ances of t he t im e ent ry workbook being open sim ult aneously. This m ight be needed, for exam ple, if t here is a requirem ent t o have a separat e t im e sheet for each client or proj ect . Moving t o a t em plat e user int erface workbook also requires t hat we give t he user a way t o creat e new t im e sheet workbooks, because it is no longer a sim ple m at t er of opening and reusing t he sam e fixed t im esheet workbook over and over. I n Figure 7- 2 , not e t he new t oolbar but t on labeled New Tim e Sheet . This but t on enables t he user t o creat e new inst ances of our t em plat e.

Figu r e 7 - 2 . Th e PETRAS Toolba r w it h t h e N e w Tim e Sh e e t Bu t t on [View full size image]

As shown in List ing 7- 21, t he code run by t his new but t on is very sim ple.

List in g 7 - 2 1 . Th e N e w Tim e Sh e e t Pr oce du r e Public Sub NewTimeSheet() Application.ScreenUpdating = False InitGlobals Application.Workbooks.Add gsAppDir & gsFILE_TIME_ENTRY Application.ScreenUpdating = True End Sub

We t urn off screen updat ing and call I nit Globals t o ensure t hat our global variables are properly init ialized. We t hen sim ply open t he t em plat e workbook and t urn screen updat ing back on. When you open a t em plat e workbook from VBA, it is t reat ed different ly t han a norm al workbook. Rat her t han opening Pet rasTem plat e.xlt , a new copy of Pet rasTem plat e.xlt , called Pet rasTem plat e1, is creat ed. Each t im e t he user clicks t he New Tim e Sheet but t on, he get s a com plet ely new, independent copy of Pet rasTem plat e.xlt . The act of opening t he t em plat e t riggers t he NewWorkbook event in our event handing class. This event perform s all t he necessary act ions required t o init ialize t he t em plat e. This event procedure is shown in t he next sect ion.

The Application-Level Event Handler Wit hin our applicat ion- level event handling class, we encapsulat e m any of t he t asks t hat were previously accom plished by procedures in st andard m odules. For exam ple, t he MakeWorksheet Set t ings procedure and t he bI sTim eEnt ryBookAct ive funct ion t hat we encount ered in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins are now bot h privat e procedures of t he class. We will describe t he layout of t he class m odule in List ing 7- 22, t hen explain what t he pieces do, inst ead of showing all of t he code here. You can exam ine t he code yourself in t he Pet rasAddin.xla workbook of t he sam ple applicat ion for t his chapt er on t he CD, and are st rongly encouraged t o do so.

List in g 7 - 2 2 . Cla ss M odu le La you t of t h e CAppEve n t H a n dle r Cla ss M odu le - Le ve l Va r ia ble s

Private WithEvents mxlApp As Excel.Application

Cla ss Eve n t Pr oce du r e s

Class_Initialize Class_Terminate mxlApp_NewWorkbook mxlApp_WorkbookOpen mxlApp_WindowActivate mxlApp_WindowDeactivate

Cla ss M e t h od Pr oce du r e s

SetInitialStatus

Cla ss Pr iva t e Pr oce du r e s

EnableDisableToolbar MakeWorksheetSettings bIsTimeEntryBookActive bIsTimeEntryWorkbook

Because t he variable t hat holds a reference t o t he inst ance of t he CAppEvent Handler class t hat we use in our applicat ion is a public variable, we use t he I nit Globals procedure t o m anage it . The code required t o do t his is shown below. I n t he declarat ions sect ion of t he MGlobals m odule:

Public gclsEventHandler As CAppEventHandler

I n t he I nit Globals procedure:

' Instantiate the Application event handler If gclsEventHandler Is Nothing Then Set gclsEventHandler = New CAppEventHandler End If

The I nit Globals code checks t o see whet her t he public gclsEvent Handler variable is init ialized and init ializes it if it isn't . I nit Globals is called at t he beginning of every nont rivial ent ry- point procedure in our applicat ion, so if anyt hing causes our class variable t o lose st at e, it will be inst ant iat ed again as soon as t he next ent ry- point procedure is called. This is a good safet y m echanism . When t he public gclsEvent Handler variable is init ialized, it causes t he Class_I nit ialize event procedure t o execut e. I nside t his event procedure, we init ialize t he event handling m echanism by set t ing t he class m odule- level Wit hEvent s variable t o refer t o t he current inst ance of t he Excel Applicat ion, as follows:

Set mxlApp = Excel.Application

Sim ilarly, when our applicat ion is exit ing and we dest roy our gclsEvent Handler variable, it causes t he Class_Term inat e event procedure t o execut e. Wit hin t his event procedure we dest roy t he class reference t o t he Excel Applicat ion obj ect by set t ing t he m xlApp variable t o Not hing. All t he rest of t he class event procedures, which are t hose belonging t o t he m xlApp Wit hEvent s variable, serve t he sam e purpose. They " wat ch" t he Excel environm ent and enable or disable our t oolbar but t ons as appropriat e when condit ions change. Disabling t oolbar but t ons when t hey can't be used is a m uch bet t er user int erface t echnique t han displaying an error m essage when t he user clicks one in t he wrong circum st ances. You don't want t o punish t he user ( t hat is, display an error m essage in response t o an act ion) when he can't be expect ed t o know he has done som et hing wrong. Not e t hat we always leave t he New Tim e Sheet and Exit PETRAS t oolbar but t ons enabled. The user should always be able t o creat e a new t im esheet or exit t he applicat ion.

I n addit ion t o enabling and disabling t he t oolbar but t ons, t he m xlApp_NewWorkbook and m xlApp_WorkbookOpen event procedures det ect when a t im e ent ry workbook is being creat ed or opened for t he first t im e, respect ively. At t his point t hey run t he privat e MakeWorksheet Set t ings procedure t o init ialize t hat t im e ent ry workbook. All of t he m xlApp event procedures are shown in List ing 7- 23. As you can see, t he individual procedures are very sim ple, but t he cum ulat ive effect is very powerful.

List in g 7 - 2 3 . Th e m x lApp Eve n t Pr oce du r e s Private Sub mxlApp_NewWorkbook(ByVal Wb As Workbook) If bIsTimeEntryWorkbook(Wb) Then EnableDisableToolbar True MakeWorksheetSettings Wb Else EnableDisableToolbar False End If End Sub Private Sub mxlApp_WorkbookOpen(ByVal Wb As Excel.Workbook) If bIsTimeEntryWorkbook(Wb) Then EnableDisableToolbar True MakeWorksheetSettings Wb Else EnableDisableToolbar False End If End Sub Private Sub mxlApp_WindowActivate(ByVal Wb As Workbook, _ ByVal Wn As Window) ' When a window is activated, check to see if it belongs ' to one of our workbooks. Enable all our toolbar controls ' if it does. EnableDisableToolbar bIsTimeEntryBookActive() End Sub Private Sub mxlApp_WindowDeactivate(ByVal Wb As Workbook, _ ByVal Wn As Window) ' When a window is deactivated, disable our toolbar ' controls by default. They will be re-enables by the ' WindowActivate event procedure if required. EnableDisableToolbar False End Sub

The full power of having an event handling class in your applicat ion is difficult t o convey on paper. We urge you t o experim ent wit h t he sam ple applicat ion for t his chapt er t o see for yourself how it works in a live set t ing. Double- click t he Pet rasAddin.xla file t o open Excel and see how t he applicat ion t oolbar behaves. Creat e new t im esheet workbooks, open non- t im esheet workbooks and

swit ch back and fort h bet ween t hem . The st at e of t he t oolbar will follow your every act ion. I t is also educat ional t o see exact ly how m uch preparat ion t he applicat ion does when you creat e a new inst ance of t he t im esheet workbook. Wit hout t he Pet rasAddin.xla running, open t he Pet rasTem plat e.xlt workbook and com pare how it looks and behaves in it s raw st at e wit h t he way it looks and behaves as an inst ance of t he t im esheet wit hin t he running applicat ion.

PETRAS Reporting The PETRAS report ing applicat ion has been m odified in m uch t he sam e way, and for t he sam e reasons, as t he PETRAS t im esheet add- in. By adding a class m odule t o handle applicat ion- level event s, we can enable t he user t o have m ult iple consolidat ion workbooks open at t he sam e t im e and swit ch bet ween t hem using t he new Window m enu, as shown in Figure 7- 3 .

Figu r e 7 - 3 . Th e PETRAS Re por t in g M e n u Ba r w it h t h e N e w W in dow M e n u

Table 7- 2 sum m arizes t he changes m ade t o t he PETRAS report ing applicat ion for t his chapt er. Rat her t han repeat m uch of t he previous few pages, we suggest you review t he Pet rasReport ing.xla workbook t o see exact ly how t he m ult iple- docum ent int erface has been im plem ent ed.

Ta ble 7 - 2 . Ch a n ge s t o t h e PETRAS Re por t in g Applica t ion for Ch a pt e r 7 M odu le

Pr oce du r e

CAppEv ent Handler

MCom m andBar s

Ch a n g e Added an applicat ion- level event handling class t o t he applicat ion t o m anage m ult iple consolidat ion workbooks.

Set UpMenus

Added code t o creat e t he Window m enu.

M odu le

Pr oce du r e

MSyst em Code

MEnt r yPoint s

Ch a n g e Added procedures t o add, rem ove and place a checkm ark against an it em in t he Window m enu.

MenuWindow Select

New procedure t o handle select ing an it em wit hin t he Window m enu. All Window m enu it em s call t his rout ine.

Conclusion You use class m odules t o creat e obj ect s and t heir associat ed m et hods, propert ies and event s. You can collect child obj ect s in a parent obj ect so t hat you can creat e a hierarchy of obj ect s t o form an obj ect m odel. You can use class m odules t o t rap t he event s raised by ot her obj ect s including t he Excel applicat ion. You can raise your own event s in a class m odule. When you set up cross- references bet ween parent and child obj ect s so t hat each is aware of t he ot her, you will creat e a st ruct ure t hat is not sim ple t o rem ove from m em ory when it is no longer useful. You need t o add ext ra code t o rem ove t hese cross- references. Class m odules are a powerful addit ion t o a developer's t oolkit . The obj ect s creat ed lead t o code t hat is easier t o writ e, develop, m aint ain and share t han t radit ional code. Obj ect s are easy t o use because t hey encapsulat e com plex code in a form t hat is very accessible. All you need t o know t o use an obj ect are it s m et hods, propert ies and event s. Obj ect s can be shared because t he class m odules t hat define t hem are encapsulat ed ( self- cont ained) and t herefore very t ransport able from one proj ect t o anot her. All you need t o do is copy t he class m odule t o m ake t he obj ect available in anot her proj ect . As a developer, you can easily add new m et hods, propert ies and event s t o an obj ect wit hout changing t he exist ing int erface. Your obj ect s can evolve wit hout harm ing older syst em s t hat use t hem . Most developers find class m odules very addict ive. The m ore you use t hem , t he m ore you like t hem and t he m ore uses you find for t hem . They will be used ext ensively t hroughout t he rest of t his book.

Chapter 8. Advanced Command Bar Handling This chapt er st art s off by covering som e best pract ices for com m and bar design. Then we int roduce our t able- driven com m and bar building m et hodology. This feat ure, which you can easily add t o your own applicat ions, rem oves m ost of t he difficult ies associat ed wit h building and m aint aining nont rivial cust om com m and bars. We show you how t o creat e and use cust om icon/ m ask file com binat ions in Excel 2002 and higher ( a feat ure also support ed by t he com m and bar builder) . We t hen finish up by explaining how t o hook Com m andBarCont rol event s in order t o int ercept clicks from Com m andBarCont rols in ways t hat are not possible using a sim ple OnAct ion m acro assignm ent .

N OTE Whenever we use t he noun con t r ol in t his chapt er, we are referring t o t he generic Com m andBarCont rol obj ect . This noun is used whenever t he t opic we are current ly discussing applies equally t o any of t he specific cont rol obj ect s t hat can be represent ed by a generic Com m andBarCont rol.

Command Bar Design Before we get int o com m and bar creat ion, let 's cover a few best pract ices for com m and bar design. Try t o follow all of t hese pract ices when designing your cust om com m and bars and cont rols: Em ulat e Excel's m enu bar. Users are already fam iliar wit h t he Excel m enu st ruct ure, so if your applicat ion em ulat es it users will have som e im m ediat e fam iliarit y wit h your applicat ion. This is especially t rue for dict at or applicat ions, whose m enus m ay include a large num ber of t he sam e feat ures t hat would norm ally appear on Excel's m enu bar. Don't use m ore t han t hree m enu sublevels. Alt hough t he t able- driven com m and bar builder t hat we will describe in t he next sect ion provides a m eans t o creat e m enus deeper t han t hree levels, t his is not som et hing you should do unless absolut ely necessary. Users t end t o get lost when your m enu st ruct ure exceeds t hree sublevels. I f you are adding one or m ore t op- level m enus t o t he built - in m enu bar, t hose m enus should be locat ed direct ly t o t he left of t he Window m enu. This is a longst anding user int erface convent ion t hat m ost users are fam iliar wit h. Unless you have a very good reason for not doing so, always dock your cust om t oolbars at t he t op of t he Excel window. There are a reasonable num ber of sit uat ions where it is appropriat e t o creat e float ing t oolbars, but rem em ber t hat your users can always undock your t oolbar if t hey want . Even less frequent ly, but st ill on occasion, it is useful t o dock a t oolbar at t he bot t om of t he Excel window. Right and left docking, even t hough t he com m and bar builder support s t hem , are never recom m ended. We have never seen a sit uat ion where t hese posit ions are appropriat e. The vast m aj orit y of users have never encount ered a t oolbar docked on t he right or left sides, and t he necessit y of doing so is alm ost always an indicat ion of poor user int erface design. Physically group cont rols t hat perform relat ed funct ions. Your applicat ion will be m uch easier t o use if sim ilar cont rols are locat ed near each ot her. Separat e relat ed groups of cont rols from each ot her using separat or bars, but t ry not t o have m ore t han four our five m enus or t oolbar but t ons in a row wit hout a separat or. Separat or bars are creat ed using t he BeginGroup propert y, which we cover in t he next sect ion. Select or creat e icons whose appearance visually im plies t he act ion perform ed by t heir cont rol. This seem s obvious, but it 's very difficult in a cust om applicat ion wit h a large num ber of feat ures. Put as m uch t hought and creat ivit y int o t he appearance of your icons as possible. Feat ures whose icons bear no visual resem blance t o t heir funct ion will be m uch harder for users t o rem em ber t han t hose whose icons clearly im ply t heir funct ion. Think, for exam ple, how easy it is t o det erm ine which t oolbar but t on you need t o click t o print a docum ent . Do your best t o em ulat e t his close associat ion bet ween funct ion and appearance.

Table-Driven Command Bars For sm all- scale Excel applicat ions wit h a few t oolbar but t ons and/ or m enu it em s, it is perfect ly accept able t o hard- code t he creat ion of t he com m and bars and cont rols your applicat ion requires using a cust om VBA procedure. ( We do recom m end t hat you isolat e com m and bar building code in a separat e procedure for ease of m aint enance.) When you begin building large- scale applicat ions wit h m ult iple dedicat ed t oolbars and m enus, hard- coded com m and bars becom e very t im econsum ing t o creat e and difficult t o m aint ain. The solut ion t o t his problem is a widely used t echnique wit hin t he Excel developm ent com m unit y known as t a ble - dr ive n com m and bar building. As we discussed in Chapt er 4 Worksheet Design, t able- driven is a generic t erm referring t o any process t hat perform s som e operat ion guided by inform at ion st ored in a dedicat ed t able on a worksheet . Table- driven com m and bar building is one of t he m ore com plex t able- driven m et hodologies. I m plem ent ed correct ly, however, it is easy t o use and far superior t o anyt hing t hat can be accom plished using VBA alone. Even when we resort t o using Visual Basic Act iveX DLLs, a t echnique we cover ext ensively in Chapt er 20 Com bining Excel and Visual Basic 6, we use an Excel add- in workbook wit h a t hree- line st ub procedure assigned t o each of t he com m and bar cont rols t hat calls t he Act iveX DLL. This add- in workbook allows us t o use worksheet s, which would ot herwise be unavailable, t o im plem ent t able- driven com m and bars and ot her t able- driven m et hodologies. I n t his sect ion we describe t he m ost sophist icat ed t able- driven com m and bar builder available. As wit h all ot her applicat ions described in t he book, t his com m and bar builder is included on t he CD t hat accom panies t his book and can be int egrat ed int o any of your applicat ions.

Introducing the Table-Driven Command Bar Builder The t able- driven com m and bar builder consist s of t hree part s t hat form a self- cont ained unit you can plug direct ly int o any applicat ion: a worksheet t able t hat defines t he com m and bars and cont rols t o be built and t wo code m odules t hat read t his t able and build t he com m and bars and cont rols it specifies. To use t he com m and bar builder in your applicat ion, you need t o copy t he wksCom m andBars worksheet and t he MCom m andBars and MPast ePict ure m odules int o your proj ect . I n t he Put t ing I t All Toget her sect ion lat er in t he chapt er we dem onst rat e t he workbook cont aining t he version of t he com m and bar builder t hat you should use in your proj ect s. Aft er you have added definit ions of t he com m and bars and cont rols you want t o build t o t he wksCom m andBars worksheet , your applicat ion j ust needs t o call one procedure on st art up and all of t hose com m and bars and cont rols will be built t o your specificat ions. A second procedure can be called on shut down t o dism ant le t he com m and bars and cont rols specified in t he t able. We cover t his in m ore det ail in t he Pract ical Exam ple sect ion at t he end of t he chapt er. We spend m ost of t his sect ion explaining how t o writ e com m and bar definit ions in t he com m and

bar definit ion t able. I t 's best t o t hink of t he code t hat reads and im plem ent s t he com m and bars and cont rols defined by t he t able as a black box. This code is t oo lengt hy and com plex t o cover in any det ail in t his chapt er, but you are st rongly encouraged t o exam ine t he code if you want t o underst and how it works. The code is open and heavily com m ent ed, so it should be reasonably approachable t o t he seasoned program m er.

The Command Bar Definition Table The reason we are spending so m uch t im e describing t he com m and bar definit ion t able is because you will spend 99 percent of your com m and bar building t im e working wit h it . The only t hing you need t o do wit h t he code, aft er adding it t o your proj ect , is call t he build com m and bars procedure on st art up and t he reset com m and bars procedure on shut down. The com m and bar definit ion t able is t oo wide t o display ent irely in a screen shot on t he print ed page, but we will give you t he flavor for what it looks like wit h t he part ial exam ple shown in Figur e 8 - 1.

Figu r e 8 - 1 . A Pa r t ia l Com m a n d Ba r D e fin it ion Ta ble [View full size image]

The cust om m enu bar creat ed by t his com m and bar definit ion t able ent ry is shown in Figure 8- 2 .

Figu r e 8 - 2 . A Cu st om M e n u Ba r Cr e a t e d by t h e Com m a n d Ba r Bu ilde r

Keep in m ind t his is only a sm all sect ion from t he upper- left corner of t he com m and bar definit ion t able. The act ual t able cont ains at least 25 colum ns of set t ings and as m any rows as required t o define all of t he com m and bars and cont rols required for t he applicat ion. One of t he feat ures m aking t he com m and bar definit ion t able so easy for experienced program m ers t o use is t hat it cont ains sheet - level defined const ant s corresponding t o every enum erat ion m em ber used when building com m and bars and cont rols wit h VBA. Therefore, wherever t he t able calls for an enum erat ion m em ber such as msoBarTop or msoButtonIconAndCaption, you can use t hose nam es exact ly as you would in VBA by j ust preceding t hem wit h an equal sign when you ent er t hem int o a cell. Their num eric values will appear in t he cell, but if you select t he cell and check t he form ula bar you will see t he enum erat ion m em ber nam e. Figure 8- 3 shows an exam ple of t his.

Figu r e 8 - 3 . D e fin e d Con st a n t s in t h e Com m a n d Ba r D e fin it ion Ta ble

I n t he sect ions t hat follow, we will provide com plet e descript ions of t he purpose and usage of each of t he set t ings in t he com m and bar definit ion t able. I n t he act ual t able t here are cell com m ent s at t he t op of each colum n t hat give brief but reasonably com plet e explanat ions of t he purpose of t he colum n. This will enable you t o use t he t able wit hout having t o cont inually refer back t o t his chapt er. The set t ing nam es in t he colum n headers of t he com m and bar definit ion t able are ident ical or very sim ilar t o t he nam es of t he VBA propert ies t hey represent on t he com m and bar or cont rol being defined. This allows you t o leverage all of your exist ing knowledge of how t o build com m and bars and cont rols in VBA when using t he t able- driven com m and bar builder. Most set t ings in t he com m and bar definit ion t able are not required. I n addit ion, som e set t ings apply t o Com m andBar obj ect s, som e t o Com m andBarCont rol obj ect s and som e t o bot h. Table 8- 1 cont ains a sum m ary of t he com m and bar definit ion t able set t ings, showing which obj ect s each set t ing applies t o, which set t ings are required and what t he default value is for each opt ional set t ing, if any.

Ta ble 8 - 1 . Com m a n d Ba r D e fin it ion Ta ble Se t t in gs Su m m a r y

Se t t in g

Com m a n dBa r

Com m a n d Ba r Con t r ol

Re qu ir e d

D e fa u lt

Com m and Bar Nam e

Yes

None

Cont rol Capt ion

Yes

None

Posit ion

No

m soBar Top

I sMenubar

No

False

Visible

No

False

Widt h

No

None

Pr ot ect ion

No

m soBar NoCust om ize

I sTem por ar y

No

True

I sEnabled

No

True

OnAct ion

No

None

Cont rol I D

No

1 ( Cust om )

Cont rol Type

No

m soCont r olBut t on

Cont rol St yle

No

m soBut t onAut om at ic

Face I D

No

None

Begin Group

No

False

Se t t in g

Com m a n dBa r

Com m a n d Ba r Con t r ol

Re qu ir e d

D e fa u lt

Befor e

No

Syst em Default

Toolt ip

No

Syst em Default

Short cut Text

No

None

Tag

No

None

Par am et er

No

None

St at e

No

m soBut t onUp

List Range

No

None

List s

No

None

Beginning wit h t he Posit ion colum n and cont inuing t hrough t he last colum n in t he t able, t he colum n values apply t o t he com m and bar or cont rol whose nam e or capt ion is specified in t he sam e row in one of t he first four colum ns of t he t able. I f a set t ing does not apply t o t he t ype of obj ect specified in t he init ial colum ns, it will be ignored. Sim ilarly, if t he ent ry in t he init ial colum ns specifies an exist ing com m and bar or cont rol obj ect , m ost set t ings in subsequent colum ns are ignored.

Command Bar Name The com m and bar builder has t he flexibilit y t o creat e new com m and bars as well as add cont rols t o exist ing com m and bars. Regardless of whet her you are creat ing a new com m and bar or adding cont rols t o an exist ing com m and bar, you ent er t he nam e of t he com m and bar in t his colum n. The com m and bar builder checks each com m and bar nam e specified in t his colum n t o see whet her it already exist s. I f t he specified com m and bar already exist s, t he com m and bar builder assum es you are adding cont rols t o t hat com m and bar. I f no com m and bar wit h t he specified nam e exist s, t he com m and bar builder creat es a new com m and bar wit h t he specified nam e using t he set t ings specified in lat er colum ns. There m ust be t wo ent ries in t he Com m and Bar Nam e colum n for every com m and bar you build or m odify. The first ent ry m ust be t he nam e or index num ber of t he com m and bar being creat ed or m odified. The second ent ry is sim ply t he word St op. The St op ent ry m ust be placed in t he row direct ly below t he last row of t he com m and bar definit ion specified by t he first ent ry. These t wo ent ries in t he first colum n work t oget her t o bracket t he com m and bar definit ion so t he com m and bar building code knows where t he definit ion st art s and ends. I n Figure 8- 1 , not ice how t he com m and bar nam e Cust om Menu Bar is placed at t he t op of t he Com m and Bar Nam e colum n in cell A2 and t he word St op is placed at t he bot t om in cell A27. As shown in t his exam ple, t h e r e ca n n ot be a n y e n t r ie s be t w e e n t h e com m a n d ba r n a m e va lu e a n d t h e St op k e yw or d. You can st ack as m any com m and bar definit ions in t he t able as you like. The only rule is t hat each subsequent definit ion m ust be separat ed from t he previous definit ion by at least one blank row.

Control Caption There are t hree Cont rol Capt ion colum ns by default . This is because good user int erface design suggest s you should not use m ore t han t hree cascading m enu levels. I f you really m ust have addit ional levels, you can sim ply insert addit ional Cont rol Capt ion colum ns t o t he right of t he exist ing t hree. Sim ilar t o t he Com m and Bar Nam e colum n, t he Cont rol Capt ion colum ns can be used t o creat e new cont rols or add subcont rols t o exist ing cont rols. I f t he com m and bar builder code det ect s t hat t he capt ion in t he Cont rol Capt ion colum n refers t o an exist ing cont rol on t he current com m and bar, it will assum e you want t o add subcont rols t o it . Ot herwise it will creat e a new cont rol wit h t he specified capt ion using t he set t ings specified in lat er colum ns. Regardless of whet her you are creat ing a single cont rol or a cascading series of m enus, each cont rol m ust occupy it s own row. The posit ion of a cont rol's capt ion wit hin t he series of Cont rol Capt ion colum ns det erm ines t he level at which t he cont rol will be added. Look again at Figure 8- 1 . Not ice t hat even t hough all t hree Cont rol Capt ion colum ns have ent ries, no row has a Cont rol Capt ion ent ry in m ore t han one of t he t hree colum ns. Th is is a n a bsolu t e r e qu ir e m e n t. You can provide an accelerat or key for your cont rol by placing an am persand direct ly t o t he left of t he charact er t hat you want t o use as t he accelerat or key charact er. The cont rol can t hen be act ivat ed from t he keyboard by pressing t he Alt key and t he specified charact er sim ult aneously. This feat ure only applies t o cont rols t hat display t heir capt ion and are current ly visible.

N OTE When a cont rol displays a dialog, st andard user int erface convent ions dict at e t hat t he capt ion of t he cont rol, if it displays one, should be followed by an ellipsis. See t he Excel File > Print …m enu for an exam ple of t his convent ion.

Position The Posit ion set t ing applies only t o Com m andBar obj ect s. I t specifies t he posit ion on t he screen where t he Com m andBar will appear when it is displayed. This set t ing m ust be one of t he following msoBarPosition enum erat ion m em bers: msoBarBottom The com m and bar will be docked at t he bot t om of t he screen. msoBarFloating The com m and bar will not be docked but inst ead will float over t he screen. msoBarLeft The com m and bar will be docked on t he left side of t he screen. msoBarPopup This set t ing is used t o specify com m and bars t hat will be displayed when t he user right - clicks wit h t he m ouse. The com m and bar will be displayed at t he posit ion where t he user right - clicked. Com m and bars wit h t his posit ion set t ing m ust be displayed in response t o

one of t he BeforeRight Click event procedures using t he synt ax: Application.CommandBars("Name").ShowPopup

msoBarRight The com m and bar will be docked on t he right side of t he screen. msoBarTop The com m and bar will be docked at t he t op of t he screen. This is t he default value if no posit ion is specified.

IsMenubar The I sMenubar set t ing applies only t o Com m andBar obj ect s. I f set t o True, t he specified com m and bar will be t he m enu bar when it is visible. You can define m ult iple com m and bars as m enu bars for different purposes, but only one m enu bar can be visible at a t im e. I f t he I sMenubar set t ing is False, t he com m and bar will be a t oolbar or popup depending on t he Posit ion set t ing. The I sMenubar propert y m ust be False for com m and bars wit h t he Posit ion propert y value msoBarPopup or a runt im e error will occur. Therefore, t he com m and bar builder code will enforce t his value for msoBarPopup com m and bars regardless of t he value act ually ent ered in t he t able. The default value for t he I sMenubar set t ing is False.

Visible The Visible set t ing applies only t o Com m andBar obj ect s. I f set t o True, t he specified Com m andBar will be visible, subj ect t o t he following lim it at ions: I f m ore t han one com m and bar has bot h t he I sMenubar and Visible set t ings set t o True, t he last such com m and bar in t he t able will be t he m enu bar t hat is act ually displayed. All ot her m enu bars will be hidden. The Visible propert y does not apply t o and has no effect on com m and bars wit h t he Posit ion value msoBarPopup. The default value of t he Visible set t ing is False. This enables you t o creat e a large num ber of com m and bars when your applicat ion st art s up and t hen display t hem on dem and as needed.

Width The Widt h set t ing applies t o Com m andBar and Com m andBarCont rol obj ect s. The Widt h set t ing m ust be a posit ive whole num ber great er t han zero. This set t ing is not required and t here is no default value. I f t he Widt h set t ing is not specified, t he widt h of t he com m and bar or cont rol will be det erm ined aut om at ically by VBA. I f t he Widt h set t ing is not specified for a com m and bar, VBA will m ake t he com m and bar wide enough t o display all of t he cont rols it cont ains on a single row. I f t he Widt h set t ing is not specified for a cont rol, VBA will m ake t he cont rol wide enough t o display it s icon and/ or capt ion.

For Com m andBar obj ect s, t he Widt h set t ing applies only when t he Posit ion set t ing is msoBarFloating. The Widt h set t ing is ignored for all ot her com m and bar Posit ion set t ings. You cannot m ake a com m and bar wider t han it s aut om at ically calculat ed widt h. Set t ing t he widt h of a float ing com m and bar t o a value narrower t han it s aut om at ically calculat ed widt h enables you t o st ack cont rols in m ult iple rows rat her t han displaying a long, single- row com m and bar. For Com m andBarCont rol obj ect s, t he Widt h set t ing always applies and you can set it t o any posit ive whole num ber great er t han zero. I f t he specified widt h is t oo narrow t o display t he capt ion and/ or icon of t he cont rol, however, it will be ignored. Not e t hat all cont rols on t he sam e popup m enu list will have t he widt h of t he widest cont rol in t he list regardless of t heir individual Widt h set t ings. There are no hard- and- fast rules for deciding exact ly what t he Widt h set t ing should be. The best approach is t o first build your com m and bars and cont rols wit hout specifying t he Widt h set t ing. Then use t he I m m ediat e window t o exam ine t he widt h propert y t hat has been aut om at ically assigned by VBA. You can use t hat as a st art ing point from which t o increase or decrease t he widt h of your com m and bars and/ or cont rols.

Protection The Prot ect ion set t ing applies only t o Com m andBar obj ect s. This set t ing specifies what t ype of m odificat ions t he user will be allowed t o m ake t o t he com m and bar. This set t ing m ust be one or m ore of t he following msoBarProtection enum erat ion m em bers. To apply m ult iple Prot ect ion values, j ust add t he values t oget her in t he Prot ect ion cell for t he com m and bar in quest ion. msoBarNoChangeDock The user cannot change t he posit ion at which t he com m and bar is dock ed. msoBarNoChangeVisible The user cannot change t he visibilit y st at us of t he com m and bar. I f t he com m and bar is visible, t he user cannot hide it ; if t he com m and bar is hidden, t he user cannot display it . msoBarNoCustomize The user cannot add or rem ove cont rols on t he com m and bar. msoBarNoHorizontalDock The user cannot dock t he com m and bar in any horizont al posit ion, eit her t op or bot t om . Wit hout any addit ional prot ect ion values, t he com m and bar can st ill be docked vert ically. To prevent a com m and bar from being docked anywhere, j ust add t he msoBarNoHorizontalDock and t he msoBarNoVerticalDock enum erat ion m em ber values t oget her in t he Prot ect ion cell. msoBarNoMove The com m and bar cannot be m oved. Be careful wit h t his opt ion because it will prevent t he user from m oving t he com m and bar under any circum st ances. For exam ple, if you creat e a float ing com m and bar whose widt h causes it t o appear part ially off- screen, t he user will not be able t o m ove t he com m and bar int o a posit ion where t hey can access all of it s cont rols. msoBarNoProtection The user can m ake any changes t o t he com m and bar t hat he want s. msoBarNoResize The user cannot m odify t he widt h or height of t he com m and bar. msoBarNoVerticalDock The user cannot dock t he com m and bar in any vert ical posit ion,

eit her left or right . There are t wo ways a user can delet e your com m and bar regardless of it s Prot ect ion set t ing, even if you have disabled t he View > Toolbars > Cust om ize m enu. Bot h of t hese m et hods provide " back doors" t o display t he Cust om ize dialog. I t is part icularly im port ant t o disable t hese opt ions in dict at or applicat ions where delet ing a cust om com m and bar m ay leave t he user wit h no way t o properly exit t he applicat ion. First , if t he Toolbar List com m and bar is enabled, t he user will be able t o delet e your cust om com m and bar by right - clicking anywhere over t he com m and bar area and select ing Cust om ize from t he short cut m enu. To disable t he Toolbar List com m and bar, execut e t he following line of code:

Application.CommandBars("Toolbar List").Enabled = False

Second, if any em pt y t oolbar docking surface is exposed on screen ( t ypically beyond t he right side of a t oolbar) , t he user can double- click anywhere wit hin t his area and t he Cust om ize dialog will display. There is no way t o direct ly disable t his feat ure, so you m ust indirect ly disable it by ensuring t hat no uncovered t oolbar docking area is left exposed by your applicat ion. The easiest way t o do t his is t o add a nonfunct ional Com m andBarBut t on cont rol ( one wit h no Capt ion or OnAct ion assignm ent ) at t he end of each of your t oolbars and set it t o be wide enough so it will cover t he ent ire t oolbar docking area regardless of t he user's screen resolut ion.

IsTemporary The I sTem porary set t ing applies t o Com m andBar and Com m and BarCont rol obj ect s. I f set t o False, t he specified com m and bar or cont rol will be persist ed bet ween Excel sessions. Set t ing t his propert y t o True causes t he com m and bar or cont rol t o be discarded when t he current session of Excel exit s. The default value for t his set t ing is True. The com m and bar builder will rebuild all com m and bars and cont rols defined in t he t able each t im e your applicat ion runs, so t he occasions when you want your cust om com m and bars or cont rols t o be persist ed bet ween Excel sessions are very rare. Leave t his set t ing blank so t he default value is used unless you have a very good reason t o do ot herwise.

IsEnabled The I sEnabled set t ing applies t o Com m andBar and Com m andBarCont rol obj ect s. This set t ing det erm ines whet her t he com m and bar or cont rol is enabled on st art up. A value of True causes t he com m and bar or cont rol t o be enabled. A value of False causes t he com m and bar or cont rol t o be disabled. Disabled com m and bars will not be visible t o t he user. The I sEnabled propert y overrides t he Visible propert y for com m and bars in t his respect . Disabled cont rols will be visible but will appear grayed out . The default value for t his propert y is True.

OnAction

This set t ing applies t o Com m andBarCont rol obj ect s. I t holds t he nam e of t he procedure t hat will be run by t he cont rol. This procedure m ust be a public procedure locat ed in a st andard code m odule. I f you want t o t rap t he Click or Change event rat her t han assigning a procedure t o t he OnAct ion propert y, you can leave t his set t ing blank. We cover cont rol event t rapping in t he Hooking Com m and Bar Cont rol Event s sect ion lat er in t his chapt er. I f t he Cont rol I D set t ing is anyt hing ot her t han 1, t he OnAct ion set t ing is ignored. You will underst and why t his is t he case when we describe t he Cont rol I D set t ing next .

Control ID This set t ing applies t o Com m andBarCont rol obj ect s. Giving t his set t ing a value of 1 m eans t hat you are creat ing a cust om cont rol whose propert ies are specified by t he rest of t he colum ns in t he t able. Any value ot her t han 1 is int erpret ed as t he I D of a built - in Excel cont rol. I n t hat case, t he built - in cont rol specified by t he Cont rol I D value will be added t o your com m and bar, along wit h it s funct ion and appearance. I f you specify a built - in cont rol using t he Cont rol I D set t ing, t he following com m and bar definit ion t able set t ings will be ignored: OnAct ion Cont rol Type Cont rol St yle Short cut Text St at e List Range List s You can det erm ine t he I D you need t o use in order t o add a built - in cont rol t o your com m and bar in t he following m anner. Assum e you want t o add t he Pr int m enu it em from t he File m enu on t he Worksheet Menu Bar t o your cust om com m and bar. Ent er t he following int o t he VBE I m m ediat e w indow :

?

CommandBars("File").Controls("Print...").ID 4

The I m m ediat e window is covered in m ore det ail in Chapt er 16 VBA Debugging, but for now not e t hat t he ? charact er t ells t he I m m ediat e window t o print t he result of t he expression t hat follows it . I n t his case, t he result is t he num ber 4, shown direct ly below t he expression. This is t he I D of t he Pr int cont rol. To add t his cont rol t o your cust om com m and bar, you j ust place 4 in t he Cont rol I D colum n of t he appropriat e row in t he com m and bar definit ion t able.

N OTE A quirk in t he Office Com m andBars obj ect m odel enables you t o access t he t op- level m enus of t he Excel m enu bar as Com m andBar obj ect s in t heir own right . I f you loop t he cont ent s of t he Com m andBars collect ion, you won't find t hese m enus cont ained in it , but you can access t hem using t he synt ax shown above j ust t he sam e.

Control Type This set t ing applies t o Com m andBarCont rol obj ect s. I t is used t o specify what t ype of cont rol you want . This set t ing m ust be one of t he following msoControlType enum erat ion m em bers: msoControlButton This is a m enu or t oolbar but t on t hat sim ply execut es t he specified OnAct ion procedure when it is clicked. The m aj orit y of Com m andBarCont rols t hat you see on Excel's m enus and t oolbars are t his t ype of cont rol. msoControlComboBox This is a com bo box cont rol t hat enables users t o eit her select an ent ry from a predefined list or ent er a new value of t heir choosing. An exam ple of t his t ype of cont rol is t he Zoom com bo box on t he St andard t oolbar. You can select from a predefined list of zoom values or supply your own. msoControlDropdown This cont rol looks exact ly like t he msoControlComboBox cont rol but t he only opt ion allowed is t o select an it em from t he predefined list . msoControlEdit This is an edit box cont rol t hat allows t he user t o ent er an arbit rary t ext value. msoControlPopup This t ype of cont rol is used t o creat e a subm enu cont aining a list of one or m ore m enu it em s. All of t he t op- level m enus on t he Excel m enu bar are of t ype msoControlPopup. Rat her t han doing anyt hing direct ly, t hey j ust display t heir associat ed subm enu. This is t he on ly cont rol t ype t hat can display a subm enu. For cust om cont rols, t he default value for t his set t ing is msoControlButton. We exam ine how you use each of t hese cont rol t ypes in m ore det ail in t he Put t ing I t All Toget her sect ion lat er in t his chapt er .

N OTE I f you look in t he VBE Obj ect Browser, you will discover t hat t here are anywhere from 21 t o 27 different msoControlType enum erat ion m em bers depending on t he version of Excel you are using. Unfort unat ely, you are lim it ed t o one of t he five m em bers list ed above when building cust om Com m andBarCont rols. Cont rols wit h som e of t he ot her enum erat ion m em ber t ypes can be added t o a cust om com m and bar by adding a built - in cont rol of t hose t ypes ( by adding t he Borders but t on from t he Form at t ing t oolbar, for exam ple, whose t ype is msoControlSplitButtonPopup) .

Som e of t he msoControlType enum erat ion m em bers sim ply haven't been im plem ent ed. msoControlOCXDropdown is one exam ple.

Control Style This set t ing applies t o Com m andBarCont rol obj ect s. I t specifies t he visual layout of t he cont rol. This set t ing does not apply t o t he Cont rol Types msoControlEdit or msoControlPopup. I t applies t o t he ot her cont rol t ypes in t he following m anner: msoControlButton Must be one of t he following msoButtonStyle enum erat ion m em bers: msoButtonAutomatic This is t he default value for cont rols of t ype msoControlButton. For a m enu it em , t his is equivalent t o msoButtonIconAndCaption. For a t oolbar but t on, t his is equivalent t o msoButtonIcon. msoButtonCaption This st yle displays only t he capt ion assigned t o t he cont rol. Any icon assigned t o t he cont rol is ignored. msoButtonIcon This st yle is a bit confusing. I t displays only t he icon for t oolbar but t ons and only t he ca pt ion for m enu it em s. I f no icon is specified for a t oolbar but t on wit h t his st yle, a blank but t on will be creat ed. msoButtonIconAndCaption This st yle displays t he icon and places t he capt ion t o t he right of t he icon for bot h m enu it em s and t oolbar but t ons. msoButtonIconAndCaptionBelow This st yle has exact ly t he sam e effect as msoButtonIconAndCaption for m enu it em s. For t oolbar but t ons it displays t he capt ion cent ered below t he icon. msoButtonIconAndWrapCaption This st yle is sim ilar t o t he msoButtonIconAndCaption st yle, but it wraps long capt ions t o t he right of t he icon inst ead of displaying t hem on a single line. This st yle gives very poor visual result s when used wit h m enu it em s, so we recom m end against using it for t hat t ype of cont rol. msoButtonIconAndWrapCaptionBelow For t oolbar but t ons t his st yle is sim ilar t o t he msoButtonIconAndCaptionBelow st yle except t hat long capt ions are wrapped beneat h t he but t on icon. For m enu it em s t his st yle gives exact ly t he sam e poor result s as t he msoButtonIconAndWrapCaption st yle, so we recom m end against using it for t hat t ype of cont r ol. msoButtonWrapCaption This st yle is sim ilar t o t he msoButtonCaption st yle in t hat it ignores any icon assigned t o t he cont rol. The difference is t hat it wraps long capt ions rat her t han displaying t hem on a single line. msoControlComboBox an d msoControlDropdown Must be one of t he following msoComboStyle enum erat ion m em bers: msoComboNormal This is t he default value for cont rols of t ype msoControlComboBox and

msoControlDropdown. I t sim ply displays t he cont rol wit h no capt ion. msoComboLabel This st yle displays t he capt ion direct ly t o t he left of t he com bo box or drop- down cont rol. Because t he Cont rol St yle set t ing does not apply t o cont rols of t ype msoControlPopup, you cannot m odify t he default appearance of t his t ype of cont rol. There is no workaround for t his lim it at ion. Because t he Cont rol St yle set t ing does not apply t o cont rols of t ype msoControlEdit, you cannot provide a capt ion for t hese cont rols. I f your edit box cont rol is locat ed on a t oolbar, you can work around t his lim it at ion by adding a nonfunct ional msoControlButton wit h t he msoButtonCaption st yle t hat displays t he capt ion you desire direct ly t o t he left of t he edit box cont rol. We dem onst rat e t his workaround in t he Put t ing I t All Toget her sect ion lat er in t his chapt er.

Face ID This set t ing applies t o Com m andBarCont rol obj ect s. I t specifies t he icon t hat will be associat ed wit h t he cont rol. The Face I D set t ing can be specified in one of t hree ways:

1 . You can use t he icon from a built - in cont rol by specifying it s I D as t he value for t he Face I D set t ing. 2 . You can use a cust om icon by specifying it s nam e. This icon m ust be a 16x16 pixel graphic t hat has been placed on t he wksCom m andBars worksheet . We will dem onst rat e t his in t he Put t ing I t All Toget her sect ion lat er in t he chapt er. 3 . When operat ing under Excel 2002 or higher, you have t he opt ion of specifying an icon and a m ask. This m et hod provides significant ly superior visual result s for t hese versions of Excel. Bot h t he icon and t he m ask m ust be 16x16 pixel graphics t hat are locat ed on t he wksCom m andBars worksheet . The icon and m ask pict ure nam es m ust be ent ered t oget her int o t he Face I D cell separat ed by a forward slash ( / ) charact er. We discuss t his m et hod in m ore det ail in t he Loading Cust om I cons from Files and Hooking Com m and Bar Cont rol Event s sect ions lat er in t he chapt er. Not e t hat t he icon pict ure from t he icon/ m ask pair will aut om at ically be used in versions of Excel earlier t han Excel 2002, m aking m et hod t hree equivalent t o m et hod t wo when running on down- level versions of Excel. The m ost im port ant charact erist ic of a cust om icon is t hat it s background appear t ransparent when applied t o a cont rol. To use cust om icons under Excel 97/ 2000, you m ust use t he Set Transparent Color cont rol from t he Pict ure t oolbar t o specify a t ransparent background color for t he single pict ure t hat will becom e t he cust om icon for your cont rol. This m et hod is illust rat ed by t he before and aft er pict ures shown in Figure 8- 4 and Figure 8- 5 .

Figu r e 8 - 4 . An I con Pict u r e Be for e Se t t in g t h e Tr a n spa r e n t Ba ck gr ou n d

Figu r e 8 - 5 . An I con Pict u r e Aft e r Se t t in g t h e Tr a n spa r e n t Ba ck gr ou n d

Just place t he Set Transparent Color cont rol cursor over t he color in your pict ure t hat you want t o becom e t ransparent and click. That color will disappear and t he background will show t hrough it . We have dem onst rat ed t his exam ple wit h a pict ure t hat has been enlarged enough so t hat you can see what is happening. This is t ypically t he way you would perform t his operat ion in t he real world as well. A 16x16 pict ure is t oo sm all t o accurat ely point at t he desired background color when you are dealing wit h a com plex icon. Just st ret ch t he pict ure out t o a size large enough so t hat you can see what you are doing, set t he t ransparent background color, t hen revert t he pict ure t o it s original size in t he following m anner:

1 . Right - click over t he pict ure and choose Form at Pict ure from t he short cut m enu. 2 . I n t he Form at Pict ure dialog, select t he Size t ab. 3 . Click t he Reset but t on in t he lower- right corner of t he Size t ab.

Excel 97/ 2000, Excel 2002 and Excel 2003 all use different UI drawing t echniques, so pict ure backgrounds set t o be t ransparent in one version of Excel will not appear t ransparent in ot her versions. As you will see in t he sect ion on Loading Cust om I cons from Files lat er in t he chapt er, t wo new m et hods were added t o t he Com m andBarBut t on obj ect in Excel 2002 t hat enable you t o load pict ures direct ly int o t he cont rol in a m anner t hat is independent of t heir appearance on t he w or k sheet . For t his reason we recom m end t hat you use t he icon/ m ask m et hod described in point 3 above for creat ing cust om icons in Excel 2002 and higher, while set t ing t he t ransparent background color of t he icon pict ure using Excel 97/ 2000. This gives t he com m and bar builder an appropriat ely form at t ed icon for use in Excel 97/ 2000. I t will aut om at ically use m et hod t wo under t hese versions of Excel. You do not have t o do anyt hing special t o t he m ask pict ure, because t he m ask is not used under Excel 97/ 2000.

Begin Group This set t ing applies t o Com m andBarCont rol obj ect s. I t is a True/ False set t ing t hat specifies whet her a separat or bar will be placed above or t o t he left of t he specified cont rol depending on cont ext . A value of True adds a separat or bar. False is t he default value for t his set t ing; so if False is specified or t his set t ing is left blank, no separat or bar will be creat ed.

Before This set t ing applies t o Com m andBarCont rol obj ect s. I t is used t o posit ion a new cont rol before an exist ing cont rol. I f t he cont rols are arranged horizont ally, t he Before set t ing will place your cont rol t o t he left of t he cont rol specified. I f t he cont rols are arranged vert ically, t he Before set t ing will place your cont rol above t he cont rol specified. The exist ing cont rol can be specified eit her by it s nam e or I D num ber. This set t ing is not required and t here is no default value. I f t his set t ing is left blank or if t he cont rol specified by t his set t ing cannot be locat ed, t his set t ing will be ignored. I n t his case, t he cont rol will be added at t he syst em default posit ion, which is at t he end of t he current set of cont rols on t he sam e level. The Before set t ing is t ypically used t o posit ion cont rols t hat are being added t o built - in Excel com m and bars.

Tooltip This set t ing applies t o Com m andBarCont rol obj ect s. I t specifies t he t ext t hat will be cont ained in t he yellow t oolt ip m essage t hat displays when t he user hovers t he m ouse point er over t he cont rol. This set t ing does not apply t o cont rols of t ype msoControlPopup or t o any child cont rol of an

msoControlPopup cont rol. I f t he Toolt ip set t ing is not specified, t he syst em default value displayed in t he t oolt ip is t he capt ion of t he cont rol.

Shortcut Text This set t ing applies t o Com m andBarCont rol obj ect s. I t displays t he keyboard short cut t hat will be assigned t o t he cont rol direct ly t o t he right of t he capt ion for t he cont rol. This set t ing applies only t o cont rols of t ype msoControlButton t hat are child cont rols of an msoControlPopup cont rol ( t hat is, m enu it em s on a subm enu) . Specifying t his set t ing does not act ually assign t he specified keyboard short cut t o t he m acro assigned t o t he OnAct ion set t ing of t he cont rol. You m ust do t his separat ely in your own code. The Short cut Text set t ing is not required and t here is no default value.

Tag This set t ing applies t o Com m andBarCont rol obj ect s. I t enables you t o st ore St ring dat a for your own use. The Tag set t ing does not m odify t he appearance or funct ion of t he cont rol in any way. One com m on use of t his set t ing is t o different iat e am ong cont rols t hat have been assigned t he sam e OnAct ion procedure. Assum e you have assigned t he OnAct ion set t ings of t hree cont rols t o t he sam e procedure. You t hen assign t he values 1, 2 and 3 t o t he Tag set t ings of t he first , second and t hird cont rols, respect ively. When t he specified OnAct ion procedure is called by one of t hese cont rols, you can ident ify t he cont rol t hat called it in t he m anner shown in List ing 8- 1 and condit ionally redirect program execut ion based on t he result .

List in g 8 - 1 . D ist in gu ish in g Con t r ols Usin g t h e Ta g Se t t in g Public Sub MyProcedure() Dim lControl As Long ' Retrieve the Tag value of the control that ' called this procedure. lControl = CLng(CommandBars.ActionControl.Tag) Select Case lControl Case 1 ' Perform the action for control 1. Case 2 ' Perform the action for control 2. Case 3 ' Perform the action for control 3. End Select End Sub

As you will see in t he Hooking Com m and Bar Cont rol Event s sect ion lat er in t he chapt er, t he Tag set t ing is also used t o specify t he cust om cont rols whose event s you want t o hook as a group.

Parameter This set t ing applies t o Com m andBarCont rol obj ect s. I t is funct ionally ident ical t o t he Tag set t ing. I t is a place for t he program m er t o st ore St ring dat a t hat will not have any effect on t he appearance or funct ion of t he cont rol.

State This set t ing applies t o Com m andBarCont rol obj ect s. I t enables you t o creat e checked m enu it em s or depressed t oolbar but t ons. The value for t his set t ing m ust be one of t he following msoButtonState enum erat ion m em bers: msoButtonDown For t oolbar but t ons t his creat es t he visual effect of t he but t on being depressed. For m enu it em s, t he effect depends on whet her t here is an icon displayed wit h t he m enu it em . For m enu it em s wit h icons, t he icon will appear depressed in a fashion very sim ilar t o t he effect on t oolbar but t ons. For m enu it em s wit hout an icon, a depressed check m ark will be added t o t he left of t he m enu capt ion. msoButtonMixed For all current versions of Excel, t his value is indist inguishable from msoButtonDown. I t is included in t he com m and bar builder in case it becom es support ed for som e different purpose in a fut ure version of Excel. msoButtonUp This is t he default value for t his set t ing. A St at e value of msoButtonUp has no effect on t he appearance of newly creat ed cont rols. This value only com es int o play as a way t o rem ove t he effect of t he msoButtonDown or msoButtonMixed values. The St at e set t ing applies only t o cust om cont rols of t ype msoControlButton. Keep in m ind t hat t he St at e propert y is a dynam ic propert y of t he cont rol. The com m and bar builder will creat e t he cont rol wit h what ever init ial St at e value you specify, but aft er t he cont rol has been creat ed you will need t o writ e cust om code t o m odify t he St at e propert y appropriat ely in response t o user act ions. We dem onst rat e t his in t he Put t ing I t All Toget her sect ion lat er in t he chapt er.

ListRange and Lists These set t ings apply t o Com m andBarCont rol obj ect s of t ype msoControlComboBox or msoControlDropdown. We discuss t hese set t ings t oget her because t hey are, in effect , a single set t ing t hat specifies t he list t o be loaded int o a com bo box or drop- down cont rol. The purpose of t hese set t ings is as follows: List Ra n ge This value specifies t he address of t he range on t he wksCom m andBars worksheet t hat holds t he list t o be loaded int o t he cont rol. The specified range m ust be locat ed in t he

List s colum n. Like all ot her set t ings described so far, t he List Range set t ing m ust be locat ed on t he sam e row as t he cont rol t o which it applies. List s This set t ing is a list of values t hat will be loaded int o t he cont rol. This is t he only set t ing t hat does not have t o be locat ed on t he sam e row as t he cont rol it applies t o, and as we discuss below, it should not be locat ed in rows t hat are part of any com m and bar or cont rol definit ion. You should always place your list s below t he last com m and bar definit ion in t he t able. By doing t his, if you need t o insert or delet e rows in a com m and bar definit ion, you will not inadvert ent ly alt er one of your list s. For sim ilar reasons, use a dynam ic form ula t o creat e t he list address value for t he List Range set t ing. I f you hard- code t he list address and t hen insert or delet e rows in t he com m and bar definit ion t able, t he list address will no longer be valid. Use of a dynam ically adj ust ing form ula t o specify t he list locat ion solves t his problem . An exam ple of a dynam ically adj ust ing List address form ula is shown here:

=ADDRESS(ROW(Y48),COLUMN(Y48))&":"&ADDRESS(ROW(Y53),COLUMN(Y53))

This form ula indicat es t hat t he List s set t ing is locat ed in colum n Y of t he com m and bar definit ion worksheet . The list current ly st art s in row 48 of t hat colum n and ends in row 53 of t hat colum n. Not ice, however, t hat t his form ula uses relat ive addresses. I f you insert or delet e rows above t he list , t he addresses specified in t he form ula will aut om at ically adj ust t o t he new locat ion of t he list . The result of t his form ula, as displayed in t he List Range cell and as read by t he com m and bar builder code, is shown here:

$Y$48:$Y$53

The com m and bar builder will use t he range specified by t his address as t he list t o be loaded int o t he cont rol defined in t he row in which t he List Range set t ing is locat ed. Not e t hat t he last com m and bar definit ion in t his exam ple ends at row 47. Therefore, placing t he list below row 47 ensures t hat any subsequent insert ions or delet ions wit hin t he com m and bar definit ion t able will not have any effect on t he cont ent s of t he list . We dem onst rat e t his t echnique in t he Put t ing I t All Toget her sect ion lat er in t he chapt er.

Post Mortem Alt hough it seem s as if every com m and bar and cont rol propert y under t he sun has been covered here, we're not even close. Only t he m ost frequent ly used propert ies have been included in t he com m and bar builder. Ot her propert ies t hat you m ay find an occasional need for can always be m anually coded int o your applicat ion. Exam ples of propert ies t hat are not included in t he com m and bar builder are t he Height and RowI ndex propert ies of t he Com m andBar obj ect , because in our experience t hese propert ies are rarely used when building com m and bars. Propert ies of t he Com m andBarCont rol obj ect t hat are not support ed include t he Descript ionText propert y, because it sim ply duplicat es t he purpose of t he

Tag and/ or Param et er propert ies and t he HyperLinkType propert y, because it is so rarely used. There are also dynam ic propert ies such as I sEnabled and St at e whose init ial values are set by t he com m and bar builder, but whose subsequent values m ust be m anaged by cust om code in your applicat ion as t he need t o change t hem arises.

Putting It All Together I n t his sect ion we creat e several com m on variat ions of com m and bars t hat are not associat ed wit h any applicat ion. We use t hese exam ples t o dem onst rat e m any of t he set t ings described in t he previous sect ion. I n t his exam ple we use t he version of t he com m and bar builder code t hat has been int egrat ed wit h t he error handling syst em t o be described in Chapt er 12 VBA Error Handling . Because t he prim ary focus of t his sect ion is creat ing a valid com m and bar definit ion t able, t his should not cause any problem s. All of t he error handling t echniques you'll see in t he code for t his exam ple are fully explained in Chapt er 12 VBA Error Handling . The error handled com m and bar builder is t he one we st rongly recom m end you use in your own proj ect s, so bear wit h us if you're looking at t he code and it isn't clear what all of it does. I f you do use t his version of t he com m and bar builder, you will need t o im port one addit ional m odule besides t he t hree list ed at t he beginning of t he chapt er. This is t he MErrorHandler m odule cont aining all t he error handling code referenced by t he com m and bar builder. The code for t his exam ple is locat ed in t he Com m andBarDem o.xls workbook t hat can be found on t he CD in t he \ Concept s\ Ch08Advanced Com m and Bar Handling folder. We st rongly recom m end t hat you open t his workbook and follow along while you read t his sect ion. The com m and bar definit ion t able is physically t oo large t o enable us t o use screen shot s t o display all of t he im port ant inform at ion we'll be discussing. The com m and bars in t he Com m andBarDem o.xls workbook will be built aut om at ically whenever t he workbook is opened. Three t ypes of cust om com m and bar are dem onst rat ed:

1 . A cust om m enu cont aining subm enus added t o t he exist ing worksheet m enu bar 2 . A cust om t oolbar 3 . A cust om right - click com m and bar Figure 8- 6 shows t he com plet e set of cust om com m and bars creat ed by t he Com m andBarDem o.xls workbook. To rem ove t he cust om com m and bars and close t he workbook, select Cust om > Exit from t he Excel m enu.

Figu r e 8 - 6 . Th e Cu st om Com m a n d Ba r s Ex a m ple [View full size image]

Adding a Custom Menu with Submenus to the Worksheet Menu Bar Figure 8- 7 shows t he com m and bar definit ion t able layout required t o add a new t op- level m enu t o t he Worksheet Menu Bar.

Figu r e 8 - 7 . Addin g a Cu st om M e n u t o t h e W or k sh e e t M e n u Ba r

Not ice t hat Worksheet Menu Bar has been ent ered for t he Com m and Bar Nam e set t ing value. The com m and bar building code will recognize t hat t his com m and bar already exist s and will add all subsequent ly defined cont rols t o t he exist ing com m and bar. As explained in t he sect ion on t he Com m and Bar Nam e set t ing above, t here can be no ent ries bet ween t he nam e of t he com m and bar and t he St op keyword.

The new t op- level m enu we are adding t o t he Worksheet Menu Bar is locat ed in t he first of t he t hree Cont rol Capt ion colum ns. I t s nam e is Cust om . The am persand charact er in front of t he first let t er of t he cont rol capt ion indicat es t he let t er C will be t he short cut key for t his m enu. We have also used t he Before set t ing ( not shown here) in t he com m and bar definit ion t able t o specify t hat t he Cust om m enu will be added direct ly t o t he left of t he Window m enu. This is t he st andard posit ion for cust om m enus added t o t he Worksheet Menu Bar. All subsequent cont rols will be const ruct ed as child m enus at som e level below t he Cust om m enu. You can verify t his is t he case because t he Cont rol Capt ion colum n ent ries visually display t he m enu hierarchy. I n t his case, no Cont rol Capt ion ent ries exist below t he Cust om ent ry, so all subsequent cont rols m ust be children of t his m enu. The full Cust om m enu is shown in Figure 8- 8 .

Figu r e 8 - 8 . Th e Cu st om M e n u

Unless specified ot herwise, all t he cust om cont rols in t his exam ple have t heir OnAct ion set t ings assigned t o t he GeneralDem o procedure shown in List ing 8- 2 . When a m enu or t oolbar but t on wit h t his OnAct ion assignm ent is clicked, a m essage box cont aining t he capt ion of t he cont rol t hat called t he procedure will display. This is a very sim ple exam ple of how you can use a single procedure t o handle m ult iple cont rols.

List in g 8 - 2 . Th e Ge n e r a lD e m o Pr oce du r e Public Sub GeneralDemo() Dim sCaller As String sCaller = CommandBars.ActionControl.Caption MsgBox sCaller & " was clicked.", vbInformation, gsAPP_TITLE End Sub

The Cust om m enu has t hree subm enus:

1 . Su bm e n u 1 We use t his cont rol t o dem onst rat e t he use of t he St at e set t ing. This cont rol is init ially creat ed wit h it s St at e set t o msoButtonDown, as dem onst rat ed by t he depressed checkm ark displayed t o t he left of t he cont rol in Figure 8- 8 . Subm enu 1 is assigned t o a

special procedure called St at eDem o t hat t oggles t he St at e of t he cont rol bet ween msoButtonDown and msoButtonUp each t im e it is clicked. The St at eDem o procedure is shown in List ing 8- 3 .

List in g 8 - 3 . Th e St a t e D e m o Pr oce du r e Public Sub StateDemo() Dim ctlCaller As CommandBarButton Dim sMsg As String Set ctlCaller = CommandBars.ActionControl If ctlCaller.State = msoButtonDown Then ' Switch to msoButtonUp. ctlCaller.State = msoButtonUp sMsg = "The state has been switched to up." Else ' Switch to msoButtonDown. ctlCaller.State = msoButtonDown sMsg = "The state has been switched to down." End If MsgBox sMsg, vbInformation, gsAPP_TITLE End Sub

2 . Su bm e n u 2 We use t his cont rol t o dem onst rat e t hird- level subm enus ( oft en referred t o as subm enu it em s) . Subm enu 2 is a cont rol of t ype msoControlPopup. As shown in Figure 8- 7 , it cont ains t hree subm enu it em s. Each of t hese subm enu it em s has had it s FaceI D set t ing assigned t o t he I D num ber of a built - in cont rol. As explained in t he sect ion on t he FaceI D set t ing above, assigning t he I D num ber of a built - in cont rol t o t he FaceI D set t ing of a cust om cont rol enables you t o give your cont rol t he appearance of t he built - in cont rol wit hout t aking on any of it s ot her charact erist ics. 3 . Ex it This is j ust a plain vanilla subm enu cont rol t hat is used t o exit t he dem o applicat ion. I t s OnAct ion set t ing is assigned t o t he AppExit procedure, which init iat es shut down of t he applicat ion.

Adding a Custom Toolbar Figure 8- 9 shows t he com m and bar definit ion t able layout required t o creat e our cust om t oolbar. Because t he t oolbar requires only a single level of Cont rol Capt ion set t ings, we've used t he freeze panes feat ure t o scroll t he t able over t o show som e of t he addit ional set t ings used t o creat e t he cont rols on t he t oolbar.

Figu r e 8 - 9 . Addin g a Cu st om Toolba r

[View full size image]

I f you're following along wit h t he act ual workbook exam ple, you'll see t hat t he row in t he com m and bar definit ion t able used t o specify t he t oolbar required only a single set t ing: Visible = TRUE. This lack of a requirem ent for explicit set t ings in m ost of t he com m and bar definit ion t able colum ns is pervasive and it represent s one of t he prim ary st rengt hs of t his syst em . The default values for all set t ings are designed t o be t he values you will use m ost frequent ly when building com m and bars and cont rols. Therefore, t he com m and bar definit ion t able requires very few ent ries for t he m aj orit y of com m and bars and cont rols you will build wit h it . Just be sure you underst and what t he default ent ries are. I f you're ever unsure, read t he cell com m ent at t he t op of t he colum n. Any default s will be list ed t here as well as any ot her crit ical inform at ion required t o use t he set t ing cont rolled by t hat colum n correct ly. The t oolbar built by t he com m and bar definit ion in Figure 8- 9 is shown in Figure 8- 10.

Figu r e 8 - 1 0 . Th e Cu st om Toolba r [View full size image]

The cont rols on t he Cust om Toolbar are used t o dem onst rat e a num ber a feat ures of t he com m and bar builder: N e w a n d Ope n As you can see in Figure 8- 9 , t here is no Cont rol I D value specified for t he New or Open but t ons. This m eans t hey will be creat ed as cust om cont rols. Bot h OnAct ion set t ings use t he GeneralDem o procedure shown in List ing 8- 2 and t heir FaceI D set t ings ( not shown) are t he I D num bers of t he built - in New and Open cont rols, respect ively. What m akes t hese cont rols different from your average t oolbar but t ons are t heir Cont rol St yle set t ings. As shown in Figure 8- 9 , t hese cont rols have a Cont rol St yle of msoButton IconAndCaption. Rat her t han sim ply displaying an icon alone, t his st yle displays t he cont rols

wit h t heir capt ions t o t he right of t heir icons. This is a som ewhat unusual but oft en very useful display t echnique when you have room on your t oolbar t o use it . The m eanings of t oolbar but t ons oft en t end t o be obscure based on t he icon alone. Adding a capt ion t o a t oolbar but t on can m ake it s purpose m uch m ore obvious. Sa ve a n d Pr in t As you can see in Figure 8- 9 , t hese but t ons have Cont rol I D values ot her t han 1. I n t his case t he Cont rol I D values are t he I D values for t he built - in Save and Print cont rols, respect ively. This m eans t he built - in Save and Print cont rols have been added t o our cust om t oolbar wit h all of t heir appearance and funct ion int act . These cont rols have no OnAct ion set t ing because t hey would ignore it . Clicking eit her one of t hese cont rols causes t hem t o perform t he sam e act ion t hey would perform as built - in cont rols. Te x t Box La be l a n d Te x t Box This set of cont rols is used t o dem onst rat e how you can add a t ext box cont rol t o your t oolbar and fake a capt ion for it by placing a nonfunct ional Com m andBarBut t on cont rol wit h t he desired capt ion t o t he left of t he t ext box cont rol. I n Figure 8- 9 you can see t hat t he OnAct ion set t ings of t he t ext box cont rol is assigned t o a special- purpose procedure called HandleText Box, shown in List ing 8- 4 .

List in g 8 - 4 . Th e H a n dle Te x t Box Pr oce du r e Public Sub HandleTextBox() Dim ctlCaller As CommandBarControl Set ctlCaller = CommandBars.ActionControl MsgBox "You entered: '" & ctlCaller.Text & "'." End Sub

This procedure perform s exact ly t he sam e funct ion as t he GeneralDem o procedure except it displays t he value ent ered in t he t ext box cont rol. D r opdow n This cont rol dem onst rat es how t o add a cont rol of t ype msoControlComboBox or msoControlDropdown t o your t oolbar. This specific exam ple dem onst rat es an msoControlDropdown cont rol, but t he t wo t ypes of cont rols are alm ost ident ical. Everyt hing you see in t his exam ple can be applied t o a cont rol of t ype msoControlComboBox. I n Figure 8- 9 , not e t hat t he Cont rol St yle set t ing for t he drop- down cont rol has a value of 1. This is t he value of t he msoComboLabel st yle. I t causes t he capt ion of t he drop- down t o display t o t he left of t he cont rol it self. The OnAct ion set t ing of t he drop- down cont rol is assigned t o t he cust om HandleDropDown procedure shown in List ing 8- 5 .

List in g 8 - 5 . Th e H a n dle D r opD ow n Pr oce du r e Public Sub HandleDropDown() Dim ctlCaller As CommandBarComboBox Set ctlCaller = CommandBars.ActionControl MsgBox "You selected: '" & ctlCaller.Text & "'."

End Sub

Aft er you select an ent ry from t he drop- down list , t his procedure displays t he list it em you select ed. Pr e viou s a n d N e x t These cont rols dem onst rat e how t o apply cust om icons t o your cont rols. I n Figure 8- 11, you can see t he Previous and Next Cont rol Capt ion set t ings, t heir Face I D set t ings t hat specify nam ed pict ures and t he t wo pict ures nam ed by t he Face I D set t ings, which happen t o be locat ed in t he Begin Group colum n. ( They can be locat ed anywhere on t he wksCom m andBars worksheet .)

Figu r e 8 - 1 1 . Cu st om I con s on t h e Toolba r

I n Figure 8- 11 t he pict ure for t he Previous but t on is select ed and you can see t hat it s nam e, as shown in t he nam e box direct ly t o t he left of t he form ula bar, is exact ly t he sam e as t he nam e specified for t he Previous cont rol in it s Face I D set t ing ( cell P20) . For sim plicit y's sake we have not dem onst rat ed t he icon/ m ask com binat ion in t his Face I D exam ple. The Face I D set t ings shown above will work in any version of Excel, alt hough not necessarily wit h opt im al appearance. We cover t he m ore com plex icon/ m ask m et hod of set t ing t he Face I D propert y in t he sect ions t hat follow.

Adding a Custom Right-Click Command Bar Figure 8- 12 shows t he com m and bar definit ion t able layout required t o creat e our cust om right click com m and bar. I f you exam ine t he Posit ion set t ing for t his com m and bar, you will see t hat it s value has been set t o msoBarPopup.

Figu r e 8 - 1 2 . Addin g a Cu st om Righ t - Click Com m a n d Ba r

The only cont rol set t ing on t his com m and bar wit h values assigned t o it is t he Cont rol I D set t ing. This is because all of t he cont rols on our cust om right - click m enu are built - in cont rols. Not j ust built - in cont rols by appearance, but t he act ual built - in cont rols specified by t he I D num bers in t he Cont rol I D colum n, including all of t heir feat ures and at t ribut es. The right - click com m and bar built by t his com m and bar t able definit ion is shown in Figure 8- 13.

Figu r e 8 - 1 3 . Th e Cu st om Righ t - Click Com m a n d Ba r

We have replaced t he built - in com m and bar norm ally invoked by right - clicking over a worksheet cell wit h our cust om right - click com m and bar. This was accom plished using t he workbook- level Sheet BeforeRight Click event , as shown in List ing 8- 6 .

List in g 8 - 6 . Th e W or k book _ Sh e e t Be for e Righ t Click Eve n t H a n dle r Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, _ ByVal Target As Range, Cancel As Boolean)

Dim cbrBar As CommandBar ' Only attempt to display the custom right-click ' command bar if it exists. On Error Resume Next Set cbrBar = Nothing Set cbrBar = Application.CommandBars("Custom Popup") On Error GoTo 0 If Not cbrBar Is Nothing Then ' Show our custom right-click command bar. cbrBar.ShowPopup ' Cancel the default action of the right-click. Cancel = True End If End Sub

As Figure 8- 13 shows, t he cont rols on our cust om right - click m enu are behaving exact ly like t heir corresponding Excel cont rols. Because we have not yet copied anyt hing, bot h t he Past e and Past e Special m enus are disabled. The Copy m enu is enabled, allowing us t o copy a range. The Zoom cont rol is enabled because we can m odify t he zoom at any t im e. We do not need t o t ake any act ion t o m ake t hese cont rols behave in t his m anner because we are using t he built - in cont rols t hem selves. Excel ensures t hey behave appropriat ely. I n t he Hooking Com m and Bar Cont rol Event s sect ion, you will see how we can have t he best of bot h worlds. By hooking com m and bar cont rol event s, we can ut ilize t he appearance of built - in cont rols provided by Excel while also having t hem run t he cust om code of our choice rat her t han perform t heir norm al act ions.

Loading Custom Icons from Files As explained in t he sect ion on t he FaceI D set t ing above, each version of Excel from 2000 onward uses a slight ly different UI drawing t echnique. This m eans cust om icons st ored as pict ures on a worksheet will only appear correct ly in t he version of Excel in which t hey were opt im ized. For applicat ions running under Excel 2002 or higher, t here is a second way t o apply cust om icons t o com m and bar cont rols t hat elim inat es t he problem s associat ed wit h t he different drawing t echniques used by different versions of Excel. The com m and bar builder support s t his m et hod aut om at ically, but in t his sect ion we will explain how t o use it m anually so you can t ake advant age of it in an applicat ion t hat does not use t he com m and bar builder. Beginning wit h Office XP, t wo new propert ies were added t o t he Com m andBarBut t on obj ect . These t wo propert ies enable you t o load icons direct ly int o t he cont rol. The Pict ure propert y specifies t he bit m ap t o be used as t he foreground of t he icon and t he Mask propert y specifies t he bit m ap t hat indicat es which areas of t he icon should be rendered as t ransparent background. I n t he next sect ion, we show you how t o creat e t hese bit m aps. Because t his m et hod requires t wo bit m ap files for each icon, if you have a large num ber of cust om icons it can becom e unwieldy due t o t he num ber of files you m ust dist ribut e. I n Chapt er 20 Com bining Excel and Visual Basic 6 we show how you can package up all of your cust om icons int o a single DLL resource file. Alt ernat ively, if you are using t he com m and bar builder, you can host bot h t he icon and m ask pict ure files on t he wksCom m andBars worksheet .

Creating Bitmap Files for Icons and Masks I f you plan t o creat e cust om icons on a regular basis, it probably m akes sense t o purchase a special- purpose icon creat ion program . For t he occasional cust om icon, however, every version of Windows com es wit h a perfect ly serviceable icon creat ion t ool: Microsoft Paint . The t ype of file you will need t o creat e for use as a Com m andBarBut t on icon is a 16x16 pixel 16color bit m ap. The icon file will cont ain t he art ist ic foreground pict ure you t hink of as your icon. The m ask file is an overlay for t he icon file in which everyt hing foreground is colored black and everyt hing you want t o be t ransparent background is colored whit e. To creat e a cust om icon, open Microsoft Paint . Paint will open wit h a blank default im age canvas. Select I m age > At t ribut es from t he Paint m enu. I n t he At t ribut es dialog, set Widt h and Height t o 16, Unit s t o Pixels and Colors t o Color. These set t ings are shown in Figure 8- 14.

Figu r e 8 - 1 4 . Th e I con At t r ibu t e s Se t t in gs

Click t he OK but t on on t he At t ribut es dialog and select View > Zoom > Cust om from t he Paint m enu. Select 800% as your Zoom t o set t ing. The result ing im age canvas is shown in Figure 8- 15.

Figu r e 8 - 1 5 . Th e Bla n k I con Ca n va s in Pa in t

You are now ready t o draw your icon. Drawing icons well requires m uch pract ice. The appearance of a 16x16 pixel im age at 800 percent m agnificat ion is oft en not hing like it s appearance at norm al size. We've provided a sim ple cust om icon im age you can use for t est ing purposes. This icon is called Arrows.bm p and is locat ed on t he CD in t he \ Concept s\ Ch08Advanced Com m and Bar Handling folder. This icon is shown loaded int o Paint in Figure 8- 16.

Figu r e 8 - 1 6 . Th e Ar r ow s I con

The m ask file for t he arrows icon is called ArrowsMask.bm p and is locat ed in t he sam e CD folder as t he Arrows.bm p file. As you can see in Figure 8- 17, t his file sim ply replaces t he blue foreground color of t he original icon wit h black. When loaded int o t he Com m andBarBut t on, t he areas of t he icon corresponding t o t he black areas of t he m ask will display, while t he areas of t he icon corresponding t o t he whit e areas of t he m ask will be t ransparent .

Figu r e 8 - 1 7 . Th e M a sk File for t h e Ar r ow s I con

Using Bitmap Files as CommandBarButton Icons Now t hat we have our icon and m ask bit m aps, it 's a sim ple m at t er t o apply t hem t o a Com m andBarBut t on. The procedures shown in List ing 8- 7 build a com m and bar wit h a single but t on t hat uses our cust om arrow icon and m ask. You can find t his code in t he LoadPict ureAndMask.xls workbook locat ed on t he CD in t he \ Concept s\ Ch08Advanced Com m and Bar Handling folder. Not e t hat t his exam ple only works in Excel 2002 or lat er.

List in g 8 - 7 . Addin g a Cu st om I con t o a Com m a n dBa r Bu t t on Public Sub CreateBar() Dim cbrBar As CommandBar Dim ctlControl As CommandBarButton Dim sPath As String ' Make sure any previously created version of our demo ' command bar is deleted.

RemoveBar ' We're assuming that the bitmap files used to create the ' custom icon are located in the same path as this workbook. sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Create a toolbar-type command bar. Set cbrBar = CommandBars.Add("Demo", msoBarTop, False, True) cbrBar.Visible = True ' Add the command bar button control. Set ctlControl = cbrBar.Controls.Add(msoControlButton) ' Load the foreground bitmap file. ctlControl.Picture = LoadPicture(sPath & "Arrows.bmp") ' Load the mask bitmap file. ctlControl.Mask = LoadPicture(sPath & "ArrowsMask.bmp") End Sub Public Sub RemoveBar() On Error Resume Next CommandBars("Demo").Delete End Sub

To creat e t he com m and bar but t on wit h t he cust om icon, run t he Creat eBar procedure. To rem ove t he dem o com m and bar and it s but t on, run t he Rem oveBar procedure. The result ing cust om icon appears as shown in Figure 8- 18.

Figu r e 8 - 1 8 . Th e Ar r ow s Cu st om I con

Hooking Command Bar Control Events I n Office 2000, Microsoft added t he Click event t o t he Com m and BarBut t on obj ect and t he Change event t o t he Com m andBarCom boBox obj ect t o provide an event - based m echanism for working wit h com m and bar cont rols in addit ion t o t he OnAct ion propert y. The prim ary reason for t his was t o allow cont rols t o be used by non- VBA code, such as COM Add- ins, which were int roduced at t he sam e t im e. There are, however, subt le differences in t he behavior of a cont rol when using an event hook com pared t o using t he OnAct ion propert y. We can exploit t his behavior t o our advant age in VBA.

Why Use an Event Hook Set t ing t he OnAct ion propert y is usually t he easiest opt ion for cust om com m and bar cont rols; when t he cont rol is clicked, t he procedure specified by t he OnAct ion propert y is called. Using an event hook enables us t o int eract wit h cont rols in t hree addit ional ways t hat cannot be accom plished using t he OnAct ion propert y: 1 . Hook t he Click event s of t he built - in cont rols, giving us a Before_xxx event for any cont rol t hat we hook. 2 . Hook t he Click event s of bot h built - in and cust om cont rols in ot her Office applicat ions, including t he VBE. For exam ple, if we're using Excel t o aut om at e Word, our Excel code can respond t o t he user clicking a cont rol in Wordeit her a built - in Word cont rol or one we have creat ed. 3 . Hook t he Click event s of bot h built - in and cust om cont rols from out side VBA, such as when aut om at ing Excel from Visual Basic ( Chapt er 20 Com bining Excel and Visual Basic 6) , wit hin COM Add- ins ( Chapt er 21 Writ ing Add- ins wit h Visual Basic 6) or in VSTO solut ions ( Chapt er 22 Using VB.NET and t he Visual St udio Tools for Office) .

What Can an Event Hook Do When hooking cust om cont rols, event hooks behave exact ly like OnAct ion procedures. They run when t he cont rol is clicked. When hooking built - in cont rols, however, t he event hook is called be for e t h e bu ilt - in pr oce ss, effect ively giving us a Before_xxx event in which t o run any code we want and/ or cancel t he built - in processing. For exam ple, in Chapt er 6 Dict at or Applicat ions we used an OnKey assignm ent t o ensure t hat t he Ct rl+ V keyboard short cut past ed only values int o our dat a- ent ry form s. I f we also hook t he Edit > Past e m enu, we could check t o see whet her t he cell being past ed int o was wit hin our dat a- ent ry form . I f so, we would replace it wit h a Past e Special > Values and cancel Excel's default past e behavior using t he CancelDefault argum ent supplied by t he Click event procedure. Ot herwise we

would let Excel perform a norm al past e operat ion. Wit hin t he Click event procedure we could also use t he Application.OnTime m et hod t o run a rout ine im m ediat ely aft er Excel has done it s norm al process, effect ively giving us an Aft er_xxx event . This m et hod will only work wit hin an Excel- based add- in. We can also use event hooks t o im plem ent cust om cont rols t hat are enabled and disabled aut om at ically as t he environm ent changes. For exam ple, t he built - in Past e Values cont rol is only enabled when t here is som et hing on t he clipboard t o past e and a cell select ed t o past e int o. We can use event hooks t o creat e our own cust om but t ons t hat are enabled and disabled in t he sam e way. All we need t o do is creat e a copy of t he Past e Values cont rol, give it a different icon, add our own code t o t he click event and cancel t he default behavior. Because our cust om cont rols are based on a built - in cont rol, Excel handles t heir enable/ disable behavior for us. We will dem onst rat e t his in The Past e Special Com m and Bar exam ple below.

The Importance of the Tag Property When you use a Wit hEvent s obj ect declarat ion t o hook a Com m andBarBut t on or Com m andBarCom boBox, you're not act ually hooking t hat specific inst ance of t he cont rol, but rat her t hat cont rol I D for built - in cont rols or t hat I D/ Tag propert y com binat ion for cust om cont rols. This m eans when you hook one of t he built - in cont rols, your event will be fired whenever a n y inst ance of t hat cont rol is clicked, a big advant age over having t o search for every inst ance of t he cont rol and hook each one ( including having t o det erm ine whet her t he user has dragged a new one on t o t heir t oolbar at som e point during your applicat ion's operat ion) . Cust om cont rols wit h an I D of 1 and no Tag assignm ent are t reat ed as unique, individual cont rols for t he purposes of a Wit hEvent s assignm ent . This is a safet y m echanism built in t o t he event hooking syst em . I f hooking any cust om cont rol wit h an I D/ Tag com binat ion of 1/ < blank> m eant hooking all cust om cont rols wit h t hat I D/ Tag com binat ion you m ight be hooking a very large num ber of cont rols indeed, including m any t hat didn't even belong t o your applicat ion. To t ake advant age of m ult iple sim ult aneous event hooks for our cust om cont rols, we need t o assign t he sam e Tag value t o all of t he cust om cont rols we want t o hook t oget her. We can t hen use t he Param et er value of t he Ct rl argum ent passed t o t he event t o ident ify which cont rol was clicked and decide what t o do wit h it . We can also have a cust om cont rol em ulat e t he enabled/ disabled behavior of a built - in cont rol aut om at ically. We do t his by assigning t he I D value of t he built - in cont rol whose behavior we want t o em ulat e t o t he Cont rol I D value of our cust om cont rol. We t hen give t hat cont rol a unique Tag value and set up t he event hook. Excel will m anage t he enabled/ disabled behavior of our cust om cont rol but t he cont rol will run t he code we assign t o it in t he event handler. This is act ually j ust a special case of hooking a built - in cont rol. And because we are hooking t he I D of a built - in cont rol, t hat built - in cont rol will also act ivat e our event handler. We can use t he Tag value of t he Ct rl argum ent passed t o t he event procedure t o det erm ine whet her t he event was fired by our cust om cont rol or t he built - in cont rol whose behavior our cust om cont rol em ulat es. I f t here is no Tag, we know t he built - in cont rol called t he event . I n t his case we sim ply do not hing and allow Excel t o perform it s default process for t he cont rol. I f t he Tag propert y is set , we know our cust om cont rol called t he event . I n t his case we cancel Excel's default act ion and run our own code in it s place.

I f we want t o have m ult iple cust om cont rols, all wit h t he sam e enabled/ disabled behavior but each wit h different act ions, we can give t hese cont rols t he sam e Cont rol I D and Tag values so t hey all fire t he sam e event hook, t hen use t he Param et er value t o uniquely ident ify each cont rol in order t o condit ionally execut e t he correct code for it in t he event handler. This is all very confusing, but it will becom e clear once you see t he exam ple in t he next sect ion.

The Paste Special Command Bar Aft er you have copied a range, Excel provides a num ber of very useful past e special opt ions t hat are buried under t he Edit > Past e Special m enu. Built - in t oolbar but t ons are provided for t wo com m only used past e special opt ions: Past e Values and Past e Form at t ing. What we want , however, is a t oolbar t hat exposes a ll of t he m ost com m only used past e special opt ions. All of t he but t ons on t his t oolbar should have t he sam e enabled/ disabled behavior exhibit ed by t he built - in Past e Values but t on, but t hey should run t he operat ion- specific code t hat we assign t o t hem . I n t his sect ion we t ake advant age of com m and bar cont rol event hooking t o creat e t his t oolbar. The workbook t hat im plem ent s t his exam ple is called Past eSpecialBar.xls and is locat ed on t he CD in t he \ Concept s\ Ch08Advanced Com m and Bar Handling folder. We st rongly recom m end t hat you open t his workbook and exam ine it while you read t his sect ion.

The Paste Special Toolbar Definition The first st ep in creat ing our Past e Special t oolbar is t o writ e t he correct definit ion for it in t he com m and bar definit ion t able. The com plet e com m and bar definit ion t able for t his t oolbar is t oo wide t o fit wit hin a single screen shot , so we show a series of screen shot s t hat ut ilize t he Excel freeze panes feat ure t o display several of t he m ost im port ant sect ions of t he definit ion t able. Showing t he ent ire com m and bar definit ion t able for our Past e Special t oolbar would require m ore screen shot s t han we have room for, so please follow along wit h t he exam ple workbook provided on t he CD. I n Figure 8- 19 we show t he basic st ruct ure and definit ion of t he Past e Special t oolbar and it s cont rols.

Figu r e 8 - 1 9 . Th e Ba sic Pa st e Spe cia l Toolba r D e fin it ion

Our Past e Special t oolbar will be const ruct ed as an msoBarFloating Com m andBar wit h seven cont rols of t ype msoControlButton. Not e t hat all of t he cont rols on t he t oolbar have been assigned t he sam e built - in Cont rol I D value 370. This num ber is t he I D of t he built - in Past e Values Com m andBarBut t on. What we are doing is creat ing seven ident ical copies of t he built - in Past e Values cont rol t hat we will lat er m odify t o perform different act ions. We do t his because even aft er our m odificat ions, Excel will t reat t hese cont rols as if t hey were copies of t he Past e Values cont rol for t he purpose of enabling and disabling t hem . This is exact ly what we want . I n Figure 8- 20 we dem onst rat e how we are set t ing t he appearance of our seven cont rols.

Figu r e 8 - 2 0 . Th e Pa st e Spe cia l Toolba r Fa ce I D Assign m e n t s [View full size image]

Let 's st art wit h t he Values but t on. Because all of t he cont rols on our t oolbar are copies of t he built in Past e Values cont rol, and t his cont rol is act ually included on our t oolbar, we don't have t o specify anyt hing for it s Face I D set t ing. I t will t ake on t he appearance of t he Past e Values cont rol by default . Next , look at t he Face I D set t ing for t he Form at t ing cont rol. Because Excel provides a built in Past e Form at t ing cont rol, we can j ust use it s Face I D rat her t han having t o creat e a cust om icon for our Form at t ing cont rol. For all t he ot her cont rols on our t oolbar, we have provided cust om icons and m asks. The purpose and usage of icons and m asks has been covered ext ensively in t he Face I D t opic and t he Loading Cust om I cons From Files sect ion above, so we do not repeat t hat inform at ion here. What we do is describe how t his feat ure has been im plem ent ed on t he com m and bar definit ion t able shown in Figure 8- 20. The pict ures for t he icons and m asks have been placed in t he unused Cont rol St yle colum n. This colum n is unused because t he default value msoButtonIcon is exact ly what we want for our cont rols. These pict ures could t heoret ically be locat ed anywhere on t he wksCom m andBars worksheet , but for ease of m aint enance we recom m end you place your icon and m ask pict ures on t he sam e row as t he cont rol t o which t hey apply and as close as possible t o t he Face I D colum n in which t hey are nam ed. Alt hough it is som ewhat difficult t o different iat e when looking at a blackand- whit e screen shot , in all cases t he icon is t he pict ure on t he left and t he m ask is t he pict ure on t he right .

I f you exam ine t he value of t he Face I D set t ing for each of t he cont rols ut ilizing an icon and m ask you will see t hat it consist s of t he icon pict ure nam e and t he m ask pict ure nam e separat ed by a forward slash ( / ) charact er. For Excel versions 2002 and higher, bot h of t hese pict ures will be used t o creat e t he icon for t he cont rol. For Excel versions 2000 and lower, only t he icon pict ure will be used and it s appearance on t he cont rol will be exact ly t he sam e as it s appearance on t he worksheet . Therefore, if your applicat ion will be run on Excel 97 or Excel 2000, you should set t he t ransparent background color of t he icon pict ure in Excel 2000 and save t he workbook in t hat version of Excel, as we have done here. Figure 8- 21 shows t he Tag and Param et er set t ings for our cont rols.

Figu r e 8 - 2 1 . Th e Pa st e Spe cia l Toolba r Ta g a n d Pa r a m e t e r Assign m e n t s

Except for t he Values cont rol, all t he cont rols have been assigned t he sam e Tag set t ing value. This is what allows all of t hese cont rols' event s t o be t rapped by t he sam e event handler. The Tag value is not required for t he Values cont rol because it is a built - in copy of t he Excel Past e Values cont rol. Because all of our cont rols are copies of t his cont rol, our event handler will t rap it s event aut om at ically. I n t he event code t hat we show in a m om ent , event calls from t he built - in Past e Values cont rol are ignored and Excel is allowed t o handle t hem as if t hey had not been t rapped at all. When t he Past e Special t oolbar is first creat ed, t here is not hing on t he clipboard and t herefore all of t he cont rols are in t he disabled st at e, as shown in Figure 8- 22.

Figu r e 8 - 2 2 . Th e Pa st e Spe cia l Toolba r w it h All Con t r ols D isa ble d

Achieving t his effect requires absolut ely no work on our part . By using t he Past e Values cont rol as t he basis for all t he cust om cont rols on t he Past e Special t oolbar, Excel m anages enabling and disabling t he cont rols appropriat ely for us. Aft er a range has been copied, Excel aut om at ically enables all of our cont rols, as shown in Figure 8- 23.

Figu r e 8 - 2 3 . Th e Pa st e Spe cia l Toolba r w it h All Con t r ols En a ble d

Now let 's look at t he code required t o m anage t hese cont rols. A Wit hEvent s class m odule called CCont rolEvent s is used t o t rap t he event s for our cont rols. A reference t o t his class m ust be creat ed in and held by a global variable so t hat event t rapping cont inues t hroughout t he life of our applicat ion. Therefore, we m ust add t he following obj ect variable declarat ion t o t he MGlobals m odule of our exam ple workbook:

Public gclsControlEvents As CControlEvents

I t seem s obvious, but bears m ent ioning, t hat t he global class variable cannot be inst ant iat ed unt il aft er we have built t he com m and bars specified in t he com m and bar definit ion t able. Ot herwise, t here would be no cont rols t o hook. Bot h of t hese t asks are accom plished in t he Aut o_Open procedure, a fragm ent of which is shown in List ing 8- 8 . As in our Put t ing I t All Toget her exam ple, t he version of t he com m and bar builder code used here has been int egrat ed wit h t he error handling syst em t o be described in Chapt er 12 VBA Error Handling .

List in g 8 - 8 . I n st a n t ia t in g t h e Eve n t H a n dle r in t h e Au t o_ Ope n Pr oce du r e ' Initialize global variables. InitGlobals ' Build the custom command bars specified in the ' wksCommandBars table. If Not bBuildCommandBars() Then Err.Raise glHANDLED_ERROR ' Instantiate the control event handler class variable. Set gclsControlEvents = New CControlEvents

The com plet e code from t he CCont rolEvent s class m odule t hat act ually t raps and handles t he cont rol event s is shown in List ing 8- 9 .

List in g 8 - 9 . Th e CCon t r olEve n t s Cla ss M odu le Private WithEvents mctlPasteSpecial As Office.CommandBarButton Private Sub Class_Initialize() ' Find and hook one of our custom buttons. ' The Click event will fire when *any* of the controls with ' the same ID and Tag are clicked, as well as when the ' built-in control whose ID we're using is clicked. ' We've given all our controls the same ID and Tag, so ' we're handling the click events for all our controls ' using a single hook and event handler. Set mctlPasteSpecial = _ CommandBars.FindControl(Tag:=gsMENU_TAG) End Sub Private Sub Class_Terminate() Set mctlPasteSpecial = Nothing End Sub Private Sub mctlPasteSpecial_Click( _ ByVal Ctrl As Office.CommandBarButton, _ CancelDefault As Boolean) Dim uPasteType As XlPasteType ' This is called for all instances of the built-in ' Paste Special > Values button as well as our custom ' Paste Special buttons, so check if it's one of ours. ' If the button is not one of ours, we'll do nothing ' and Excel will perform its normal action for that ' button. If Ctrl.Tag = gsMENU_TAG Then ' It is one of ours, so set the appropriate paste type. Select Case Ctrl.Parameter Case gsMENU_PS_ALL uPasteType = xlPasteAll Case gsMENU_PS_FORMULAS uPasteType = xlPasteFormulas Case gsMENU_PS_VALUES uPasteType = xlPasteValues Case gsMENU_PS_FORMATS uPasteType = xlPasteFormats Case gsMENU_PS_COMMENTS uPasteType = xlPasteComments

Case gsMENU_PS_VALIDATION uPasteType = 6 ' xlPasteValidation in 2002+ Case gsMENU_PS_COLWIDTHS uPasteType = 8 ' xlPasteColumnWidths in 2002+ End Select ' If the paste special doesn't succeed, fail silently. On Error Resume Next Selection.PasteSpecial uPasteType On Error GoTo 0 ' We handled the event, so cancel its default behavior. CancelDefault = True End If End Sub

When t he global gclsCont rolEvent s class variable is inst ant iat ed by t he Aut o_Open procedure, t he first t hing t hat happens is t he Class_I nit ialize event fires. This event locat es a single inst ance of a cont rol on our Past e Special t oolbar and assigns it t o t he int ernal Wit hEvent s class variable. As we have explained previously, t his is enough t o cause a ll t he cont rols on our t oolbar t o be hooked by our event handler ( as well as any built - in Past e Values cont rols on which our cust om cont rols are based) . Because Excel is m anaging whet her our cont rols are enabled or disabled, when our m ct lPast eSpecial_Click event does fire, we know t he user has clicked one of our cont rols a n d t here is som et hing on t he clipboard t hat can pot ent ially be past ed. The first it em of business is t hen t o det erm ine whet her t he cont rol t hat fired t he click event is one of our cust om cont rols. We do t his by com paring t he Tag propert y exposed by t he Ct rl argum ent t o t he Tag value t hat we have assigned t o each of our cust om cont rols. I f t he Tag propert y of t he Ct rl argum ent doesn't m at ch t he Tag value we have assigned t o our cust om cont rols, we know t hat a built - in Excel cont rol fired t he event procedure. I n t his case we j ust exit t he procedure wit hout doing anyt hing. This allows Excel t o perform t he default act ion for t hat built - in cont rol, which is t he behavior we want . I f t he Tag propert y of t he cont rol t hat fired t he event m at ches t he Tag value we assigned t o our cust om cont rols, we know we're dealing wit h one of our cust om cont rols. I n t his case we cont inue processing. The act ion we t ake depends on t he value of t he Param et er propert y of t he cont rol t hat fired t he event . The Param et er propert y is used t o dist inguish am ong our cust om cont rols because t he Cont rol I D and Tag propert ies are ident ical for all of t hem . This is what allows t hem all t o fire t he sam e event procedure. I n t his case, t he Param et er value is used t o specify t he t ype of past e special operat ion t hat should be perform ed. Wit hin t he event procedure we convert t he Param et er value int o one of t he xlPasteType enum erat ion values. Aft er we have t he correct past e special enum erat ion value, we at t em pt t o perform t he specified operat ion. This past e special operat ion is wrapped in On Error Resume Next/On Error GoTo 0 so no error will be generat ed if t he past e special operat ion being at t em pt ed is not valid for t he current version of Excel or t he cont ent s of t he clipboard. We explain t he use of t he various perm ut at ions of t he On Error st at em ent in m ore det ail in Chapt er 12 VBA Error Handling.

Practical Example Because we have not yet int roduced t he t opic of error handling, t he com m and bar builder t hat we int egrat e int o t he sam ple applicat ion at t his point does not m ake use of any error handling t echniques. This is not t he preferred m et hod, but we are using it t o avoid confusing t he addit ion of an aut om at ed com m and bar builder, discussed in t his chapt er, wit h t he addit ion of error handling, covered in Chapt er 12 VBA Error Handling . The t oolbar for our PETRAS add- in is a very sim ple one com pared t o t he exam ples t hat we've seen already. We show it again in Figure 8- 24 t o refresh your m em ory.

Figu r e 8 - 2 4 . Th e PETRAS Add- in Toolba r [View full size image]

PETRAS Timesheet As Figure 8- 24 shows, all five but t ons on t he t oolbar are cust om but t ons and all of t hem use built in Excel com m and bar cont rol Face I D values, so t here is no need t o at t ach ext ernal pict ures t o t hem . A part ial view of t he com m and bar definit ion t able is shown in Figure 8- 25. We've frozen panes at colum n B and scrolled t he right pane t o colum n O t o show som e of t he m ore int erest ing cont rol set t ings. To see t he ent ire t able, j ust set t he I sAddin propert y of t he Pet rasAddin.xla workbook t o False so t he wksCom m andBars worksheet is visible in t he Excel user int erface.

Figu r e 8 - 2 5 . Th e PETRAS Add- in Com m a n d Ba r D e fin it ion Ta ble

The code wit hin t he add- in looks exact ly like it did when we last saw it except for t he addit ion of t wo code m odules: MCom m andBars and MPast ePict ure. These hold t he code t hat reads t he com m and bar definit ion t able and builds t he com m and bars it specifies. The procedure call used t o creat e t he com m and bar in t he Aut o_Open procedure is exact ly t he sam e as before. The difference is now it calls t he BuildCom m andBars procedure in t he MCom m andBars m odule inst ead of our previous, hard- coded com m and bar building procedure of t he sam e nam e t hat was locat ed in t he MSyst em Code m odule. There has been one sim ple change in t he Aut o_Close procedure. Rat her t han rem oving our cust om t oolbar wit h t he line:

Application.CommandBars(gsBAR_TOOLBAR).Delete

we are now calling t he MCom m andBars procedure designed t o work backward t hrough t he com m and bars t able and rem ove t he com m and bars and cont rols it specifies:

ResetCommandBars

We've done t his for illust rat ion purposes only. I n t he sim ple case of a single, fully cust om t oolbar, t he first line of code is t he m ore efficient m et hod for rem oval. When you begin building com plex applicat ions t hat use a com binat ion of m odified built - in and fully cust om ized com m and bars, however, you will find it m uch easier t o let t he com m and bar builder rem ove your applicat ion's com m and bars based on t he com m and bar definit ion t able t hat defined t hem in t he first place. A sum m ary of t he changes m ade t o t he PETRAS t im esheet applicat ion t o im plem ent t he t abledriven com m and bar builder is shown in Table 8- 2.

Ta ble 8 - 2 . Ch a n ge s t o t h e PETRAS Tim e sh e e t Applica t ion for Ch a pt e r 8 M odu le

Pr oce du r e

Ch a n g e

MCom m andBars ( new m odule)

New m odule cont aining t he com m and bar building code.

MPast ePict ure ( new m odule)

New m odule t o support t he com m and bar builder. Used t o add a pict ure t o and ret rieve a pict ure from t he clipboard.

M odu le

Pr oce du r e

Ch a n g e

MOpenClose

Aut o_Open

The BuildCom m andbars procedure is now called from t he new MCom m andBars m odule inst ead of MSyst em Code.

MSyst em Code

BuildCom m andBar s

This procedure was rem oved because t he t ask of building t he com m and bars is now handled by t he t able- driven com m and bar builder.

PETRAS Reporting Previous versions of t he PETRAS report ing applicat ion have had a very sim ple m enu st ruct ure, lit t le m ore t han t he usual File > New, Open, Close, Save and Exit m enus and a Window m enu t o swit ch bet ween result s workbooks. When we're displaying a result s workbook, however, we would really like t o provide m ost ( but not all) of Excel's built - in m enus, t o enable our users t o work direct ly wit h t he workbook. Adding t he com m and bar builder t o t he applicat ion m akes t his a t rivial t ask of including t he appropriat e built - in m enu I Ds. I n t he definit ion t able shown in Figure 8- 26, for exam ple, we've been able t o include Excel's ent ire Edit m enu ( and all it s subm enus) j ust by specifying it s cont rol I D of 30003.

Figu r e 8 - 2 6 . Th e PETRAS Re por t in g Com m a n d Ba r D e fin it ion Ta ble [View full size image]

I f you look at t he OnAct ion and Cont rol I D colum ns of t he t able, you'll see t hat we have been able t o add lot s of very rich funct ionalit y t o our applicat ion j ust by borrowing Excel's st andard m enus. I n fact , all of t hese feat ures have been added wit hout us having t o writ e a n y code t o im plem ent t hem !

Application Contexts As dict at or applicat ions becom e m ore and m ore com plex, we need an easier way t o handle t he enabling and disabling of t he m enu it em s t han coding t hem individually. One approach is t o int roduce t he concept of an applicat ion cont ext , which is an ident ifier t o specify what part of t he applicat ion is being displayed. Typical cont ext s in Excel dict at or applicat ions include t he following: Ba ck dr op The st at ic backdrop sheet is being displayed, so alm ost all m enus not relat ed t o beginning work or exit ing t he applicat ion are disabled. D a t a En t r y We're in a dat a- ent ry worksheet , so a lim it ed set of edit ing m enus are enabled Re su lt s We're in a result s workbook, so all t he edit ing and form at t ing m enus are enabled. We can specify t he cont ext s in which each m enu it em ( or an ent ire popup t oolbar) should be enabled by list ing t he applicable cont ext s in t he Param et er colum n of t he definit ion t able. I n t he PETRAS report ing applicat ion, we're only using t he Backdrop and Result s cont ext s. Because t he cont ext is usually det erm ined by t he worksheet current ly being displayed, we can use t he applicat ion WindowAct ivat e event t o t rigger t he enabling/ disabling by using code like t hat shown in List ing 8- 10.

List in g 8 - 1 0 . Th e Code t o I m ple m e n t Applica t ion Con t e x t s Private Sub mxlApp_WindowActivate(ByVal Wb As Workbook, _ ByVal Wn As Window) 'Set the correct context, depending if we have a results 'workbook or not. If IsResultsWorkbook(Wb) Then EnableDisableMenus gsCONTEXT_RESULTS Else EnableDisableMenus gsCONTEXT_BACKDROP End If End Sub 'Enable/disable menu items, depending on the 'application context. Sub EnableDisableMenus(ByVal sContext As String) Dim cbCommandbar As CommandBar

On Error Resume Next 'Enable/disable key menu items, by calling the 'EnableDisableMenuBar procedure, which recursively operates 'on all Menu items in the structure EnableDisableMenuBar Application.CommandBars(gsMENU_BAR), _ sContext, "" 'Enable/disable all the toolbars For Each cbCommandbar In Application.CommandBars If cbCommandbar.Type msoBarTypeMenuBar Then cbCommandbar.Enabled = (sContext = gsCONTEXT_RESULTS) End If Next 'Enable/disable the associated shortcut keys If sContext = gsCONTEXT_RESULTS Then Application.OnKey "^s" Application.OnKey "^S" Else Application.OnKey "^s", "" Application.OnKey "^S", "" End If End Sub 'Recursive routine to process the menu bar hierarchy, 'enabling/disabling items based on their context. Private Sub EnableDisableMenuBar(cbBar As CommandBar, _ sContext As String, sBarContext As String) Dim ctlControl As CommandBarControl On Error Resume Next 'Loop through all the controls on this bar For Each ctlControl In cbBar.Controls If TypeOf ctlControl Is CommandBarPopup Then 'If it's a popup, recurse down to process its menus EnableDisableMenuBar ctlControl.CommandBar, _ sContext, ctlControl.Parameter ElseIf ctlControl.Parameter = "" Then 'If the control doesn't have a parameter, use the 'commandbar's parameter. This allows us to add entire 'Excel built-in commandbars to our app, without 'specifying every menu item on them ctlControl.Enabled = InStr(1, sBarContext, _ sContext) > 0 Else 'Otherwise enable/disable the bar

ctlControl.Enabled = InStr(1, ctlControl.Parameter, _ sContext) > 0 End If Next End Sub

Adding t he t able- driven com m and bar builder required a num ber of relat ively m inor changes t hroughout t he PETRAS report ing applicat ion, det ailed in Table 8- 3.

Ta ble 8 - 3 . Ch a n ge s t o t h e PETRAS Re por t in g Applica t ion for Ch a pt e r 8 M odu le

Pr oce du r e

Ch a n g e

MOpenClose

Aut o_Open

Set init ial applicat ion cont ext at end of rout ine.

MCom m andBar s

Replaced t he ent ire m odule wit h t he t able- driven com m and bar builder.

MPast ePict ure ( new m odule)

New m odule t o support t he com m and bar builder. Used t o add a pict ure t o and ret rieve a pict ure from t he clipboard.

MGlobals

Added const ant s for applicat ion cont ext s.

MEnt r yPoint s

MenuWindow Select

We were using t he Param et er t o t est for t he PETRAS Backdrop m enu it em . Changed t o use t he capt ion inst ead, as t he Param et er is now used for t he applicat ion cont ext .

CAppEv ent Handler

m x lApp_Window Act iv at e

I dent ify t he applicat ion cont ext and pass it t o EnableDisableMenus, as shown in List ing 8- 10.

MSyst em Code

EnableDisableMenus

I m plem ent ed List ing 8- 10, t o enable/ disable t he m enus based on applicat ion cont ext inst ead of hard- coding each m enu it em .

M odu le

Pr oce du r e

Ch a n g e

MSyst em Code

AddToWindow Menu

Set t he Param et er value t o Backdrop,Result s when adding t he workbook window m enu it em s.

MWor k space

Rest or eEx celSet t ings

Moved t he code t o re- enable t he t oolbars t o here, from t he old Rest oreMenus rout ine ( which has been replaced by t he com m and bar builder) .

wksCom m andBars ( new w or k sheet )

New worksheet t o hold t he com m and bar definit ion t able.

Conclusion The purpose of t his chapt er is t o sim plify com m and bar building in your applicat ions t o save t im e and allow you t o focus m ore effort on good design. To assist in t hat effort , we've covered a num ber of best pract ice design principles t hat you should follow. Com m and bars are t he user's ent ry point int o your applicat ion. Make t hem easy t o discover, use and rem em ber. We've int roduced you t o a t able- driven com m and bar building m et hodology t hat will rem ove m ost of t he work associat ed wit h building and m aint aining com m and bars for your applicat ion. We've shown you how t o creat e cust om icon and m ask pict ures t hat enable you t o avoid t he problem s associat ed wit h divergent appearance of cust om com m and bar but t on icons am ong various current versions of Excel. We've also explained how t o hook t he event s generat ed when t he user clicks com m and bar cont rols so t hat you can cont rol t he behavior of t hose cont rols in a m ore granular fashion.

Chapter 9. Understanding and Using Windows API Calls I n t he Program m ing wit h t he Windows API chapt er of our Excel 2002 VBA Program m ers Reference, we approached t he subj ect of using Windows API calls by explaining how t o locat e t he definit ions for various funct ions on t he MSDN Web sit e and t ranslat e t hose funct ions for use in VBA. The idea was t o enable readers t o browse t hrough t he API docum ent at ion and use anyt hing of int erest t hey found. I n realit y, ext rem ely few people use Windows API calls in t hat m anner; indeed, t rying t o include previously unexplored API calls in our Excel applicat ions is very likely t o result in a m aint enance problem , because it 's doubt ful t hat anot her developer will underst and what we were t rying t o do. I nst ead, m ost of us go t o Google and search t he Web or t he newsgroups for t he answer t o a problem and find t hat t he solut ion requires t he use of API calls. ( Searching Google for " Excel Windows API " result s in m ore t han 200,000 Web pages and 19,000 newsgroup post s.) We copy t he solut ion int o our applicat ion and hope it works, usually wit hout really underst anding what it does. This chapt er shines a light on m any of t hose solut ions, explaining how t hey work, what t hey use t he API calls for, and how t hey can be m odified t o bet t er fit our applicat ions. Along t he way, we fill in som e of t he concept ual fram ework of com m on Windows API t echniques and t erm inology. By t he end of t he chapt er, you will be com fort able about including API calls in your applicat ions, underst and how t hey work, accept t heir use in t he exam ple applicat ions we develop in t his book and be able t o m odify t hem t o suit your needs.

Overview When developing Excel- based applicat ions, we can get m ost t hings done by using t he Excel obj ect m odel. Occasionally, t hough, we need som e inform at ion or feat ure t hat Excel doesn't provide. I n t hose cases, we can usually go direct ly t o t he files t hat com prise t he Windows operat ing syst em t o find what we're looking for. The first st ep in doing t hat is t o t ell VBA t he funct ion exist s, where t o find it , what argum ent s it t akes and what dat a t ype it ret urns. This is done using t he Declare st at em ent , such as t hat for Get Syst em Met rics:

Declare Function GetSystemMetrics Lib "user32" _ (ByVal nIndex As Long) As Long

This st at em ent t ells t he VBA int erpret er t hat t here is a funct ion called Get Syst em Met rics locat ed in t he file user32.exe ( or user32.dll, it 'll check bot h) t hat t akes one argum ent of a Long value and ret urns a Long value. Once defined, we can call Get Syst em Met rics in exact ly t he sam e way as if it is t he VBA funct ion:

Function GetSystemMetrics(ByVal nIndex As Long) As Long End Function

The Declare st at em ent s can be used in any t ype of code m odule, can be Public or Privat e ( j ust like st andard procedures) , but m ust always be placed in t he Declarat ions sect ion at t he t op of t he m odule.

Finding Documentation All of t he funct ions in t he Windows API are fully docum ent ed in t he Windows Developm ent / Plat form SDK sect ion of t he MSDN library on t he Microsoft Web sit e, at ht t p: / / m sdn.m icr osoft .com / libr ar y, alt hough t he t erm inology used and t he code sam ples t end t o be t arget ed at t he C+ + developer. A Google search will usually locat e docum ent at ion m ore appropriat e for t he Visual Basic and VBA developer, but is unlikely t o be as com plet e as MSDN. I f you're using API calls found on a Web sit e, t he Web page will hopefully explain what t hey do, but it is a good idea t o always check t he official docum ent at ion for t he funct ions t o see whet her any lim it at ions or ot her rem arks m ay affect your usage. Unfort unat ely, t he MSDN library's search engine is significant ly worse t han using Google t o search t he MSDN sit e. We find t hat Google always gives us m ore relevant pages t han MSDN's search engine. To use Google t o search MSDN, browse t o ht t p: / / w w w .google.com and click t he Advanced Search link. Type in t he search crit eria and t hen in t he Dom ain edit box t ype m sdn.m icrosoft .com

t o rest rict t he search t o MSDN.

Finding Declarations I t is not uncom m on t o encount er code snippet s on t he I nt ernet t hat include incorrect declarat ions for API funct ionssuch as declaring an argum ent 's dat a t ype as I nt eger or Boolean when it should be Long. Alt hough using t he declarat ion included in t he snippet will probably work ( hopefully t he aut hor t est ed it ) , it m ight not work for t he full range of possible argum ent s t hat t he funct ion accept s and in rare cases m ay cause m em ory corrupt ion and dat a loss. The official VBA- friendly declarat ions for m any of t he m ore com m only used API funct ions can be found in t he win32api.t xt file, which is included wit h a viewer in t he Developer Edit ions of Office 972002, Visual Basic 6 and is available for download from ht t p: / / suppor t .m icr osoft .com / ?kbid= 178020. You'll not ice from t he download page t hat t he file hasn't been updat ed for som e t im e. I t t herefore doesn't include t he declarat ions and const ant s added in recent versions of Windows. I f you're using one of t hose newer declarat ions, you'll have t o t rust t he Web page aut hor, exam ine a num ber of Web pages t o check t hat t hey all use t he sam e declarat ion or creat e your own VBA- friendly declarat ion by following t he st eps we described in t he Excel 2002 VBA Program m ers Reference.

Finding the Values of Constants Most API funct ions are passed const ant s t o m odify t heir behavior or specify t he t ype of value t o ret urn. For exam ple, t he Get Syst em Met rics funct ion shown previously accept s a param et er t o specify which m et ric we want , such as SM_CXSCREEN t o get t he widt h of t he screen in pixels or SM_CYSCREEN t o get t he height . All of t he appropriat e const ant s are shown on t he MSDN page for t hat declarat ion. For exam ple, t he Get Syst em Met rics funct ion is docum ent ed at ht t p: / / m sdn.m icr osoft .com / libr ar y/ en- us/ sysinfo/ base/ get syst em m et r ics.asp and shows m ore t han 70 valid const ant s. Alt hough m any of t he const ant s are included in t he win32api.t xt file m ent ioned earlier, it does not include const ant s added for recent versions of Windows. The best way t o find t hese values is by downloading and inst alling t he core Plat form SDK from ht t p: / / w w w .m icr osoft .com / m sdow nload/ plat for m sdk / sdk updat e/ . This includes all t he C+ + header files t hat were used t o build t he DLLs, in a subdirect ory called \ include. The files in t his direct ory can be searched using norm al Windows file searching t o find t he file t hat cont ains t he const ant we're int erest ed in. For exam ple, searching for SM_CXSCREEN gives t he file winuser.h. Opening t hat file and searching wit hin it gives t he following lines:

#define SM_CXSCREEN #define SM_CYSCREEN

0 1

These const ant s can t hen be included in your VBA m odule by declaring t hem as Long variables wit h t he values shown:

Const SM_CXSCREEN As Long = 0 Const SM_CYSCREEN As Long = 1

Som et im es, t he values will be shown in hexadecim al form , such as 0x8000, which can be convert ed t o VBA by replacing t he 0x wit h &h and adding a furt her & on t he end, such t hat

#define KF_UP

0x8000

becom es

Const KF_UP As Long = &h8000&

Understanding Handles Wit hin VBA, we're used t o set t ing a variable t o reference an obj ect using code like

Set wkbBackDrop = Workbooks("Backdrop.xls")

and releasing t hat reference by set t ing t he variable t o Not hing ( or let t ing VBA do t hat for us when it goes out of scope at t he end of t he procedure) . Under t he covers, t he t hing t hat we see as t he Backdrop.xls workbook is j ust an area of m em ory cont aining dat a st ruct ured in a specific way t hat only Excel underst ands. When we set t he variable equal t o t hat obj ect , it is j ust given t he m em ory locat ion of t hat dat a st ruct ure. The Windows operat ing syst em works in a very sim ilar way, but at a m uch m ore granular level; alm ost everyt hing wit hin Windows is m aint ained as a sm all dat a st ruct ure som ewhere. I f we want t o work wit h t he it em t hat is represent ed by t hat st ruct ure ( such as a window) , we need t o get a reference t o it and pass t hat reference t o t he appropriat e API funct ion. These references are known as h a n dle s and are j ust I D num bers t hat Windows uses t o ident ify t he dat a st ruct ure. Variables used t o st ore handles are usually given t he prefix h and are declared As Long. When we ask for t he handle t o an it em , som e funct ionssuch as FindWindowgive us t he handle t o a shared dat a st ruct ure; t here is only one dat a st ruct ure for each window, so every call t o FindWindow wit h t he sam e param et ers will ret urn t he sam e handle. I n t hese cases, we can j ust discard t he handle when we're finished wit h it . I n m ost sit uat ions, however, Windows allocat es an area of m em ory, creat es a new dat a st ruct ure for us t o use and ret urns t he handle t o t hat st ruct ure. I n t hese cases, we m u st t idy up aft er ourselves, by explicit ly t elling Windows t hat we've finished using t he handle ( and by im plicat ion, t he m em ory used t o st ore t he dat a st ruct ure t hat t he handle point s t o) . I f we fail t o t idy up correct ly, each call t o our rout ine will use anot her bit of m em ory unt il Windows crashest his is known as a m e m or y le a k . The m ost com m on cause of m em ory leaks is forget t ing t o include t idy- up code wit hin a rout ine's error handler. The MSDN docum ent at ion will t ell you whet her you need t o release t he handle and which funct ion t o call t o do it .

Encapsulating API Calls Get Syst em Met rics is one of t he few API calls t hat can easily be used in isolat ionit has a m eaningful nam e, t akes a single param et er, ret urns a sim ple result and doesn't require any preparat ion or cleanup. So long as you can rem em ber what SM_CXSCREEN is asking for, it 's ext rem ely easy t o call t his funct ion; GetSystemMetrics(SM_CXSCREEN) gives us t he widt h of t he screen in pixels. I n general pract ice, however, it is a very good idea t o wrap your API calls inside t heir own VBA funct ions and t o place t hose funct ions in m odules dedicat ed t o specific areas of t he Windows API , for t he following reasons: The VBA rout ine can include som e validit y checks before t rying t o call t he API funct ion. Passing invalid dat a t o API funct ions will oft en result in a crash. Most of t he t ext ual API funct ions require st ring variables t o be defined and passed in, which are t hen populat ed by t he API funct ion. Using a VBA rout ine hides t hat com plexit y. Many API funct ions accept param et ers t hat we don't need t o use. A VBA rout ine can expose only t he param et ers t hat are applicable t o our applicat ion. Few API funct ions can be used in isolat ion; m ost require ext ra preparat ory and clean up calls. Using a VBA rout ine hides t hat com plexit y. The API declarat ions t hem selves can be declared Privat e t o t he m odule in which t hey're cont ained, so t hey can be hidden from use by ot her developers who m ay not underst and how t o use t hem ; t heir funct ionalit y can t hen be exposed t hrough m ore friendly VBA rout ines. Som e API funct ions, such as t he encrypt ion or I nt ernet funct ions, require an init ial set of preparat ory calls t o open resources, a num ber of rout ines t hat use t hose resources and a final set of rout ines t o close t he resources and t idy up. Such rout ines are ideally encapsulat ed in a class m odule, wit h t he Class_I nit ialize and Class_Term inat e procedures used t o ensure t he resources are opened and closed correct ly. By using dedicat ed m odules for specific areas of t he Windows API , we can easily copy t he rout ines bet ween applicat ions, in t he knowledge t hat t hey are self- cont ained. When you st art t o include lot s of API calls in your applicat ion, it quickly becom es difficult t o keep t rack of which const ant s belong t o which funct ions. We can m ake t he const ant s m uch easier t o m anage if we encapsulat e t hem in an enum erat ion and use t hat enum erat ion for our VBA funct ion's param et er, as shown in List ing 9- 1 . By doing t his, t he applicable const ant s are shown in t he I nt ellisense list when t he VBA funct ion is used, as shown in Figure 9- 1 . The abilit y t o define enum erat ions was added in Excel 2000.

List in g 9 - 1 . En ca psu la t in g t h e Ge t Syst e m M e t r ics API Fu n ct ion a n d Re la t e d Con st a n t s 'Declare all the API-specific items Private to the module Private Declare Function GetSystemMetrics Lib "user32" _

(ByVal nIndex As Long) As Long Private Const SM_CXSCREEN As Long = 0 Private Const SM_CYSCREEN As Long = 1 'Wrap the API constants in a public enumeration, 'so they appear in the Intellisense dropdown Public Enum SystemMetricsConstants smScreenWidth = SM_CXSCREEN smScreenHeight = SM_CYSCREEN End Enum 'Wrapper for the GetSystemMetrics API function, 'using the SystemMetricsConstants enumeration Public Function SystemMetrics( _ ByVal uIndex As SystemMetricsConstants) As Long SystemMetrics = GetSystemMetrics(uIndex) End Function

Figu r e 9 - 1 . By Usin g t h e En u m e r a t ion , t h e Re le va n t Con st a n t s Appe a r in t h e I n t e llise n se D r op- D ow n

Working with the Screen The procedures included in t his sect ion all relat e t o t he Windows screen and can be found in t he MScreen m odule of t he API Exam ples.xls workbook.

Reading the Screen Resolution The Get Syst em Met rics API funct ion has been used t o illust rat e t he general concept s above. I t can be used t o discover m any of t he sim pler aspect s of t he operat ing syst em , from whet her a m ouse or net work is present t o t he height of t he st andard window t it le bar. By far it s m ost com m on use in Excel is t o find t he screen resolut ion, t o check t hat it is at least a m inim um size ( for exam ple, 800x600) or t o work out which userform t o display if you have different layout s opt im ized for different resolut ions. The code in List ing 9- 2 wraps t he Get Syst em Met rics API funct ion, exposing it as separat e ScreenWidt h and ScreenHeight funct ions.

List in g 9 - 2 . Re a din g t h e Scr e e n Re solu t ion 'Declare all the API-specific items Private to the module Private Declare Function GetSystemMetrics Lib "user32" _ (ByVal nIndex As Long) As Long Private Const SM_CXSCREEN = 0 'Screen width Private Const SM_CYSCREEN = 1 'Screen height 'The width of the screen, in pixels Public Function ScreenWidth() As Long ScreenWidth = GetSystemMetrics(SM_CXSCREEN) End Function 'The height of the screen, in pixels Public Function ScreenHeight() As Long ScreenHeight = GetSystemMetrics(SM_CYSCREEN) End Function

Finding the Size of a Pixel I n general, Excel m easures dist ances in point s, whereas m ost API funct ions use pixels and m any Act iveX cont rols ( such as t he Microsoft Flexgrid) use t wips. A point is defined as being 1/ 72 ( logical) inches, and a t wip is defined as 1/ 20t h of a point . To convert bet ween pixels and point s, we need t o know how m any pixels Windows is displaying for each logical inch. This is t he DPI ( dot s per inch) set by t he user in Cont rol Panel > Display > Set t ings > Advanced > General > Display ,

which is usually set at eit her Norm al size ( 96 DPI ) or Large size ( 120 DPI ) . I n versions of Windows prior t o XP, t his was known as Sm all Font s and Large Font s. The value of t his set t ing can be found using t he Get DeviceCaps API funct ion, which is used t o exam ine t he det ailed capabilit ies of a specific graphical device, such as a screen or print er.

Device Contexts One of t he fundam ent al feat ures of Windows is t hat applicat ions can int eract wit h all graphical devices ( screens, print ers, or even individual pict ure files) in a st andard way. This is achieved by operat ing t hrough a layer of indirect ion called a device cont ext , which represent s a drawing layer. An applicat ion obt ains a reference ( handle) t o t he drawing layer for a specific device ( for exam ple, t he screen) , exam ines it s capabilit ies ( such as t he size of a dot , whet her it can draw curves and how m any colors it support s) , draws ont o t he drawing layer and t hen releases t he reference. Windows t akes care of exact ly how t he drawing layer is represent ed on t he graphical device. I n t his exam ple, we're only exam ining t he screen's capabilit ies. The code t o ret rieve t he size of a pixel is shown in List ing 9- 3 . Rem em ber t hat when adding t his code t o an exist ing m odule, t he declarat ions m ust always be placed at t he t op of t he m odule.

List in g 9 - 3 . Fin din g t h e Size of a Pix e l Private Declare Function GetDC Lib "user32" _ (ByVal hwnd As Long) As Long Private Declare Function GetDeviceCaps Lib "gdi32" _ (ByVal hDC As Long, ByVal nIndex As Long) As Long Private Declare Function ReleaseDC Lib "user32" _ (ByVal hwnd As Long, ByVal hDC As Long) As Long Private Const LOGPIXELSX = 88

'Pixels/inch in X

'A point is defined as 1/72 inches Private Const POINTS_PER_INCH As Long = 72 'The size of a pixel, in points Public Function PointsPerPixel() As Double Dim hDC As Long Dim lDotsPerInch As Long hDC = GetDC(0) lDotsPerInch = GetDeviceCaps(hDC, LOGPIXELSX) PointsPerPixel = POINTS_PER_INCH / lDotsPerInch ReleaseDC 0, hDC End Function

The first t hing t o not ice about t his rout ine is t hat we cannot j ust call Get DeviceCaps direct ly; we need t o give it a handle t o t he screen's device cont ext . This handle is obt ained by calling t he Get DC funct ion, where t he zero param et er convenient ly gives us t he device cont ext for t he screen. We t hen call Get DeviceCaps, passing t he const ant LOGPI XELSX, which asks for t he num ber of pixels per logical inch horizont ally. ( For screens, t he horizont al and vert ical DPI is t he sam e, but it m ight not be for print ers, which is why circles on screen oft en print out as ovals.) Wit h Norm al size chosen, we get 96 dot s per inch. We divide t he 72 point s per inch by t he 96 DPI , t elling us t hat a dot ( t hat is, pixel) is 0.75 point s; so if we want t o m ove som et hing in Excel by one pixel, we need t o change it s Top or Left by 0.75. Wit h Large Size select ed, a pixel is 0.6 point s. Every t im e we use Get DC t o obt ain a handle t o a device cont ext , we use up a sm all am ount of Window's graphical resources. I f we didn't release t he handle aft er using it , we would event ually use up all of Window's graphical resources and crash. To avoid t hat , we have t o be sure t o release any resources we obt ain, in t his case by calling ReleaseDC.

Working with Windows Everyt hing t hat we see on t he screen is eit her a window or is cont ained wit hin a window, from t he Windows deskt op t o t he sm allest popup t oolt ip. Consequent ly, if we want t o m odify som et hing on t he screen, we always st art by locat ing it s window. The windows are organized int o a hierarchy, wit h t he deskt op at t he root . The next level down includes t he m ain windows for all open applicat ions and num erous syst em - relat ed windows. Each applicat ion t hen owns and m aint ains it s own hierarchy of windows. Every window is ident ified by it s window handle, com m only referred t o as h W n d. By far t he best t ool for locat ing and exam ining windows is t he Spy+ + ut ilit y t hat is included wit h Visual St udio. Figure 9- 2 shows t he Spy+ + display for t he window hierarchy of a t ypical Excel session.

Figu r e 9 - 2 . Th e Spy+ + D ispla y of t h e Ex ce l W in dow H ie r a r ch y

Window Classes As well as showing t he hierarchy, t he Spy+ + display shows t hree key at t ribut es for each window: t he handle ( in hexadecim al) , t he capt ion and t he class. Just like class m odules, a window class defines a t ype of window. Som e classes, such as t he Com boBox class, are provided by t he Windows operat ing syst em , but m ost are defined as part of an applicat ion. Each window class is usually associat ed wit h a specific part of an applicat ion, such as XLMAI N being Excel's m ain applicat ion w indow . Table 9- 1 list s t he window classes shown in t he Spy+ + hierarchy and t heir uses, plus som e ot her window classes com m only encount ered during Excel applicat ion developm ent .

Ta ble 9 - 1 . Ex ce l W in dow Cla sse s a n d Th e ir Use s W in dow Cla ss

Usa ge

XLMAI N

The m ain Excel applicat ion window.

EXCEL;

The left half of t he form ula bar, including t he Nam e drop- down.

Com boBox

A st andard Windows com bo box ( in t his case, it 's t he Nam e drop- down) .

EXCEL
0 Then 'Return the login id, stripping off the final vbNullChar UserName = Left$(sBuffer, lStringLength - 1) End If End Function

Buffers Every API funct ion t hat ret urns t ext ual inform at ion, such as t he user nam e, does so by using a buffer t hat we provide. A buffer com prises a St ring variable init ialized t o a fixed size and a Long variable t o t ell t he funct ion how big t he buffer is. When t he funct ion is called, it writ es t he t ext t o t he buffer ( including a final Null charact er) and ( usually) updat es t he lengt h variable wit h t he num ber of charact ers writ t en. ( Som e funct ions ret urn t he t ext lengt h as t he funct ion's result inst ead of updat ing t he variable.) We can t hen look in t he buffer for t he required t ext . Not e t hat VBA st ores st rings in a very different way t han t he API funct ions expect , so whenever we pass st rings t o API funct ions, VBA does som e conversion for us behind t he scenes. For t his t o work properly, we a lw a ys pass st rings by value ( ByVal) t o API funct ions, even when t he funct ion updat es t he st ring. Som e people prefer t o ignore t he buffer lengt h inform at ion, looking inst ead for t he first vbNullChar charact er in t he buffer and assum ing t hat 's t he end of t he ret rieved st ring, so you m ay encount er usage like t hat shown in List ing 9- 11.

List in g 9 - 1 1 . Usin g a Bu ffe r , I gn or in g t h e Bu ffe r Le n gt h Va r ia ble 'Get the user's login ID, without using the buffer length Function UserName2() As String Dim sBuffer As String * 255 GetUserName sBuffer, 255 UserName2 = Left$(sBuffer, InStr(sBuffer, vbNullChar) - 1) End Function

Changing to a UNC Path VBA's int rinsic ChDrive and ChDir st at em ent s can be used t o change t he act ive pat h prior t o using Application.GetOpenFilename, such t hat t he dialog opens wit h t he correct pat h preselect ed. Unfort unat ely, t hat can only be used t o change t he act ive pat h t o local folders or net work folders t hat have been m apped t o a drive let t er. Not e t hat once set , t he VBA CurDir funct ion will ret urn a UNC pat h. We need t o use API funct ions t o change t he folder t o a net work pat h of t he form \ \ server\ share\ pat h, as shown in List ing 9- 12. I n pract ice, t he Set CurDir API funct ion is one of t he few t hat can be called direct ly from your code.

List in g 9 - 1 2 . Ch a n gin g t o a UN C Pa t h Private Declare Function SetCurDir Lib "kernel32" _ Alias "SetCurrentDirectoryA" _ (ByVal lpPathName As String) As Long 'Change to a UNC Directory

Sub ChDirUNC(ByVal sPath As String) Dim lReturn As Long 'Call the API function to set the current directory lReturn = SetCurDir(sPath) 'A zero return value means an error If lReturn = 0 Then Err.Raise vbObjectError + 1, "Error setting path." End If End Sub

Locating Special Folders Windows m aint ains a large num ber of special folders t hat relat e t o eit her t he current user or t he syst em configurat ion. When a user is logged in t o Windows wit h relat ively low privileges, such as t he basic User account , it is highly likely t hat t he user will only have full access t o his personal folders, such as his My Docum ent s folder. These folders can usually be found under C: \ Docum ent s and Set t ings\ UserNam e, but could be locat ed anywhere. We can use an API funct ion t o give us t he correct pat hs t o t hese special folders, using t he code shown in List ing 9- 13. Not e t hat t his list ing cont ains a subset of all t he possible folder const ant s. The full list can be found by searching MSDN for " CSI DL Values." The not able except ion from t his list is t he user's Tem p folder, which can be found by using t he Get Tem pPat h funct ion. List ing 9- 13 includes a special case for t his folder, so t hat it can be obt ained t hrough t he sam e funct ion.

List in g 9 - 1 3 . Loca t in g a W in dow s Spe cia l Folde r Private Declare Function SHGetFolderPath Lib "shell32" _ Alias "SHGetFolderPathA" _ (ByVal hwndOwner As Long, ByVal nFolder As Long, _ ByVal hToken As Long, ByVal dwFlags As Long, _ ByVal pszPath As String) As Long Private Declare Function GetTempPath Lib "kernel32" _ Alias "GetTempPathA" _ (ByVal nBufferLength As Long, _ ByVal lpBuffer As String) As Long 'More Commonly used CSIDL values. 'For the full list, search MSDN for "CSIDL Values" Private Const CSIDL_PROGRAMS As Long = &H2 Private Const CSIDL_PERSONAL As Long = &H5 Private Const CSIDL_FAVORITES As Long = &H6 Private Const CSIDL_STARTMENU As Long = &HB

Private Private Private Private Private Private Private Private Private Private Private

Const Const Const Const Const Const Const Const Const Const Const

CSIDL_MYDOCUMENTS As Long = &HC CSIDL_MYMUSIC As Long = &HD CSIDL_MYVIDEO As Long = &HE CSIDL_DESKTOPDIRECTORY As Long = &H10 CSIDL_APPDATA As Long = &H1A CSIDL_LOCAL_APPDATA As Long = &H1C CSIDL_INTERNET_CACHE As Long = &H20 CSIDL_WINDOWS As Long = &H24 CSIDL_SYSTEM As Long = &H25 CSIDL_PROGRAM_FILES As Long = &H26 CSIDL_MYPICTURES As Long = &H27

'Constants used in the SHGetFolderPath call Private Const CSIDL_FLAG_CREATE As Long = &H8000& Private Const SHGFP_TYPE_CURRENT = 0 Private Const SHGFP_TYPE_DEFAULT = 1 Private Const MAX_PATH = 260 'Public enumeration to give friendly names for the CSIDL values Public Enum SpecialFolderIDs sfAppDataRoaming = CSIDL_APPDATA sfAppDataNonRoaming = CSIDL_LOCAL_APPDATA sfStartMenu = CSIDL_STARTMENU sfStartMenuPrograms = CSIDL_PROGRAMS sfMyDocuments = CSIDL_PERSONAL sfMyMusic = CSIDL_MYMUSIC sfMyPictures = CSIDL_MYPICTURES sfMyVideo = CSIDL_MYVIDEO sfFavorites = CSIDL_FAVORITES sfDesktopDir = CSIDL_DESKTOPDIRECTORY sfInternetCache = CSIDL_INTERNET_CACHE sfWindows = CSIDL_WINDOWS sfWindowsSystem = CSIDL_SYSTEM sfProgramFiles = CSIDL_PROGRAM_FILES 'There is no CSIDL for the temp path, 'so we need to give it a dummy value 'and treat it differently in the function sfTemporary = &HFF End Enum 'Get the path for a Windows special folder Public Function SpecialFolderPath( _ ByVal uFolderID As SpecialFolderIDs) As String 'Create a buffer of the correct size Dim sBuffer As String * MAX_PATH Dim lResult As Long If uFolderID = sfTemporary Then 'Use GetTempPath for the temporary path lResult = GetTempPath(MAX_PATH, sBuffer)

'The GetTempPath call returns the length and a 'trailing \ which we remove for consistency SpecialFolderPath = Left$(sBuffer, lResult - 1) Else 'Call the function, passing the buffer lResult = SHGetFolderPath(0, _ uFolderID + CSIDL_FLAG_CREATE, 0, _ SHGFP_TYPE_CURRENT, sBuffer) 'The SHGetFolderPath function doesn't give us a 'length, so look for the first vbNullChar SpecialFolderPath = Left$(sBuffer, _ InStr(sBuffer, vbNullChar) - 1) End If End Function

The observant am ong you m ight have not iced t hat we've now com e across all t hree ways in which buffers are filled by API funct ions: Get UserNam e ret urns t he lengt h of t he t ext by m odifying t he input param et er. Get Tem pPat h ret urns t he lengt h of t he t ext as t he funct ion's ret urn value. SHGet FolderPat h doesn't ret urn t he lengt h at all, so we search for t he first vbNullChar.

Deleting a File to the Recycle Bin The VBA Kill st at em ent is used t o delet e a file, but does not send it t o t he recycle bin for pot ent ial recovery by t he user. To send a file t o t he recycle bin, we need t o use t he SHFileOperat ion funct ion, as shown in List ing 9- 14:

List in g 9 - 1 4 . D e le t in g a File t o t h e Re cycle Bin 'Structure to tell the SHFileOperation function what to do Private Type SHFILEOPSTRUCT hwnd As Long wFunc As Long pFrom As String pTo As String fFlags As Integer fAnyOperationsAborted As Boolean hNameMappings As Long lpszProgressTitle As String End Type

Private Declare Function SHFileOperation Lib "shell32.dll" _ Alias "SHFileOperationA" _ (ByRef lpFileOp As SHFILEOPSTRUCT) As Long Private Private Private Private

Const Const Const Const

FO_DELETE = &H3 FOF_SILENT = &H4 FOF_NOCONFIRMATION = &H10 FOF_ALLOWUNDO = &H40

'Delete a file, sending it to the recycle bin Sub DeleteToRecycleBin(ByVal sFile As String) Dim uFileOperation As SHFILEOPSTRUCT Dim lReturn As Long 'Fill the UDT with information about what to do With FileOperation .wFunc = FO_DELETE .pFrom = sFile .pTo = vbNullChar .fFlags = FOF_SILENT + FOF_NOCONFIRMATION + _ FOF_ALLOWUNDO End With 'Pass the UDT to the function lReturn = SHFileOperation(FileOperation) If lReturn 0 Then Err.Raise vbObjectError + 1, "Error deleting file." End If End Sub

There are t wo t hings t o not e about t his funct ion. First , t he funct ion uses a user- defined t ype t o t ell it what t o do, inst ead of t he m ore com m on m et hod of having m ult iple input param et ers. Second, t he funct ion ret urns a value of zero t o indicat e success. I f you recall t he Set CurDir funct ion in List ing 9- 12, it ret urns a value of zero t o indicat e failure! The only way t o know which t o expect is t o check t he Ret urn Values sect ion of t he funct ion's inform at ion page on MSDN.

Browsing for a Folder All versions of Excel have included t he Get OpenFilenam e and Get SaveAsFilenam e funct ions t o allow t he user t o select a filenam e t o open or save. Excel 2002 int roduced t he com m on Office FileDialog obj ect , which can be used t o browse for a folder, using t he code shown in List ing 9- 15, which result s in t he dialog shown in Figure 9- 3 .

List in g 9 - 1 5 . Usin g Ex ce l 2 0 0 2 's File D ia log t o Br ow se for a Folde r 'Browse for a folder, using the Excel 2002 FileDialog Sub BrowseForFolder() Dim fdBrowser As FileDialog 'Get the File Dialog object Set fdBrowser = Application.FileDialog(msoFileDialogFolderPicker) With fdBrowser 'Initialize it .Title = "Select Folder" .InitialFileName = "c:\" 'Display the dialog If .Show Then MsgBox "You selected " & .SelectedItems(1) End If End With End Sub

Figu r e 9 - 3 . Th e St a n da r d Office 2 0 0 2 Folde r Pick e r D ia log [View full size image]

We consider t his layout far t oo com plicat ed, when all we need is a sim ple t ree view of t he folders on t he com put er. We can use API funct ions t o show t he st andard Windows Browse for folder dialog shown in Figure 9- 4 , which our users t end t o find m uch easier t o use. The Windows dialog also gives us t he opt ion t o display som e descript ive t ext t o t ell our users what t hey should be select ing.

Figu r e 9 - 4 . Th e St a n da r d W in dow s Folde r Pick e r D ia log

Callbacks So far, every funct ion we've encount ered j ust does it s t hing and ret urns it s result . However, a range of API funct ions ( including t he SHBrowseForFolder funct ion t hat we're about t o use) int eract wit h t he calling program while t hey're working. This m echanism is known as a ca llba ck. Excel 2000 added a VBA funct ion called AddressOf, which provides t he address in m em ory where a given procedure can be found. This address is passed t o t he API funct ion, which calls back t o t he procedure found at t hat address as required. For exam ple, t he Enum Windows funct ion it erat es t hrough all t he t op- level windows, calling back t o t he procedure wit h t he det ails of each window it finds. Obviously, t he procedure being called m ust be defined exact ly as Windows expect s it t o be so t he API funct ion can pass it t he correct num ber and t ype of param et ers. The SHBrowseForFolder funct ion uses a callback t o t ell us when t he dialog is init ially shown, enabling us t o set it s capt ion and init ial select ion, and each t im e t he user select s a folder, enabling us t o check t he select ion and enable/ disable t he OK but t on. The full t ext for t he funct ion is cont ained in t he MBrowseForFolder m odule of t he API Exam ples.xls workbook and a slight ly sim plified version is shown in List ing 9- 16.

List in g 9 - 1 6 . Usin g Ca llba ck s t o I n t e r a ct w it h t h e W in dow s File Pick e r D ia log 'UDT to pass information to the SHBrowseForFolder function Private Type BROWSEINFO hOwner As Long pidlRoot As Long pszDisplayName As String lpszTitle As String ulFlags As Long lpfn As Long lParam As Long iImage As Long End Type 'Commonly used ulFlags constants 'Only return file system directories. 'If the user selects folders that are not 'part of the file system (such as 'My Computer'), 'the OK button is grayed. Private Const BIF_RETURNONLYFSDIRS As Long = &H1 'Use a newer dialog style, which gives a richer experience Private Const BIF_NEWDIALOGSTYLE As Long = &H40 'Hide the default 'Make New Folder' button Private Const BIF_NONEWFOLDERBUTTON As Long = &H200

'Messages sent from dialog to callback function Private Const BFFM_INITIALIZED = 1 Private Const BFFM_SELCHANGED = 2

'Messages sent to browser from callback function Private Const WM_USER = &H400 'Set the selected path Private Const BFFM_SETSELECTIONA = WM_USER + 102 'Enable/disable the OK button Private Const BFFM_ENABLEOK = WM_USER + 101

'The maximum allowed path Private Const MAX_PATH = 260 'Main Browse for directory function

Declare Function SHBrowseForFolder Lib "shell32.dll" _ Alias "SHBrowseForFolderA" _ (ByRef lpBrowseInfo As BROWSEINFO) As Long 'Gets a path from a pidl Declare Function SHGetPathFromIDList Lib "shell32.dll" _ Alias "SHGetPathFromIDListA" _ (ByVal pidl As Long, _ ByVal pszPath As String) As Long 'Used to set the browse dialog's title Declare Function SetWindowText Lib "user32" _ Alias "SetWindowTextA" _ (ByVal hwnd As Long, _ ByVal lpString As String) As Long 'A versions of SendMessage, to send strings to the browser Private Declare Function SendMessageString Lib "user32" _ Alias "SendMessageA" (ByVal hwnd As Long, _ ByVal wMsg As Long, ByVal wParam As Long, _ ByVal lParam As String) As Long 'Variables to hold the initial options, 'set in the callback function Dim msInitialPath As String Dim msTitleBarText As String 'The main function to initialize and show the dialog Function GetDirectory(Optional ByVal sInitDir As String, _ Optional ByVal sTitle As String, _ Optional ByVal sMessage As String, _ Optional ByVal hwndOwner As Long, _ Optional ByVal bAllowCreateFolder As Boolean) _ As String 'A variable to hold the UDT Dim uInfo As BROWSEINFO Dim sPath As String Dim lResult As Long 'Check that the initial directory exists On Error Resume Next sPath = Dir(sInitDir & "\*.*", vbNormal + vbDirectory) If Len(sPath) = 0 Or Err.Number 0 Then sInitDir = "" On Error GoTo 0 'Store the initials setting in module-level variables, 'for use in the callback function msInitialPath = sInitDir msTitleBarText = sTitle

'If no owner window given, use the Excel window 'N.B. Uses the ApphWnd function in MWindows If hwndOwner = 0 Then hwndOwner = ApphWnd 'Initialise the structure to pass to the API function With uInfo .hOwner = hwndOwner .pszDisplayName = String$(MAX_PATH, vbNullChar) .lpszTitle = sMessage .ulFlags = BIF_RETURNONLYFSDIRS + BIF_NEWDIALOGSTYLE _ + IIf(bAllowCreateFolder, 0, BIF_NONEWFOLDERBUTTON) 'Pass the address of the callback function in the UDT .lpfn = LongToLong(AddressOf BrowseCallBack) End With 'Display the dialog, returning the ID of the selection lResult = SHBrowseForFolder(uInfo) 'Get the path string from the ID GetDirectory = GetPathFromID(lResult) End Function

'Windows calls this function when the dialog events occur Private Function BrowseCallBack (ByVal hwnd As Long, _ ByVal Msg As Long, ByVal lParam As Long, _ ByVal pData As Long) As Long Dim sPath As String 'This is called by Windows, so don't allow any errors! On Error Resume Next Select Case Msg Case BFFM_INITIALIZED 'Dialog is being initialized, 'so set the initial parameters 'The dialog caption If msTitleBarText "" Then SetWindowText hwnd, msTitleBarText End If 'The initial path to display If msInitialPath "" Then SendMessageString hwnd, BFFM_SETSELECTIONA, 1, _ msInitialPath End If Case BFFM_SELCHANGED

'User selected a folder 'lParam contains the pidl of the folder, which can be 'converted to the path using GetPathFromID 'sPath = GetPathFromID(lParam) 'We could put extra checks in here, 'e.g. to check if the folder contains any workbooks, 'and send the BFFM_ENABLEOK message to enable/disable 'the OK button: 'SendMessage hwnd, BFFM_ENABLEOK, 0, True/False End Select End Function

'Converts a PIDL to a path string Private Function GetPathFromID(ByVal lID As Long) As String Dim lResult As Long Dim sPath As String * MAX_PATH lResult = SHGetPathFromIDList(lID, sPath) If lResult 0 Then GetPathFromID = Left$(sPath, InStr(sPath, Chr$(0)) - 1) End If End Function 'VBA doesn't let us assign the result of AddressOf 'to a variable, but does allow us to pass it to a function. 'This 'do nothing' function works around that problem Private Function LongToLong(ByVal lAddr As Long) As Long LongToLong = lAddr End Function

Let 's t ake a closer look at how t his all works. First , m ost of t he shell funct ions use t hings called PI DLs t o uniquely ident ify folders and files. For sim plicit y's sake, you can t hink of a PI DL as a handle t o a file or folder, and t here are API funct ions t o convert bet ween t he PI DL and t he norm al file or folder nam e. The Get Direct ory funct ion is t he m ain funct ion in t he m odule and is t he funct ion t hat should be called t o display t he dialog. I t st art s by validat ing t he ( opt ional) input param et ers, t hen populat es t he BROWSEI NFO user- defined t ype t hat is used t o pass all t he required inform at ion t o t he SHBrowseForFolder funct ion. The h Ow n e r elem ent of t he UDT is used t o provide t he parent window for t he dialog, which should be t he handle of t he m ain Excel window, or t he handle of t he userform window if showing t his dialog from a userform . The u lFla gs elem ent is used t o specify det ailed behavior for t he dialog, such as whet her t o show a Make Folder but t on. The full list of possible flags and t heir purpose can be found on MSDN by searching for t he SHBrowseForFolder funct ion. The lpfn elem ent is where we pass t he address of t he callback funct ion, BrowseCallBack.

We have t o wrap t he AddressOf value in a sim ple LongToLong funct ion, because VB doesn't let us assign t he value direct ly t o an elem ent of a UDT. Aft er t he UDT has been init ialized, we pass it t o t he SHBrowseForFolder API funct ion. That funct ion displays t he dialog and Windows calls back t o our BrowseCallBack funct ion, passing t he BFFM_I NI TI ALI ZED m essage. We respond t o t hat m essage by set t ing t he dialog's capt ion ( using t he Set WindowText API funct ion) and t he init ial folder select ion ( by sending t he BFFM_SETSELECTI ONA m essage back t o t he dialog wit h t he pat h st ring) . Every t im e t he user clicks a folder, it t riggers a Windows callback t o our BrowseCallBack funct ion, passing t he BFFM_SELCHANGED m essage and t he I D of t he select ed folder. All t he code t o respond t o t hat m essage is com m ent ed out in t his exam ple, but we could add code t o check whet her t he folder is a valid select ion for our applicat ion ( such as whet her it cont ains any workbooks) and enable/ disable t he OK but t on appropriat ely ( by sending t he BFFM_ENABLEOK m essage back t o t he dialog) . When t he user clicks t he OK or Cancel but t on, t he funct ion ret urns t he I D of t he select ed folder and execut ion cont inues back in t he Get Direct ory funct ion. We get t he t ext ual pat h from t he ret urned I D and ret urn it t o t he calling code.

Practical Examples All t he rout ines included in t his chapt er have been t aken out of act ual Excel applicat ions, so are t hem selves pract ical exam ples of API calls. The PETRAS applicat ion files for t his chapt er can be found on t he CD in t he folder \ Applicat ion\ Ch09Underst anding and Using Windows API Calls and now includes t he following files: Pe t r a sTe m pla t e .x lt The t im esheet t em plat e Pe t r a sAddin .x la The t im esheet dat a- ent ry support add- in Pe t r a sRe por t in g.x la The m ain report ing applicat ion Pe t r a sCon solida t ion .x lt A t em plat e t o use for new result s workbooks D e bu g.in i A dum m y file t hat t ells t he applicat ion t o run in debug m ode Pe t r a sI con .ico A new icon file, t o use for Excel's m ain window

PETRAS Timesheet Unt il t his chapt er, t he locat ion used by t he Post t o Net work rout ine has used Applicat ion.Get OpenFilenam e t o allow t he user t o select t he direct ory t o save t he t im esheet workbook t o. The problem wit h t hat call is t hat t he direct ory m ust already cont ain at least one file. I n t his chapt er, we add t he BrowseForFolder dialog and use t hat inst ead of Get OpenFilenam e, which allows em pt y folders t o be select ed. We've also added a new feat ure t o t he t im esheet add- in. I n previous versions you were prom pt ed t o specify t he consolidat ion locat ion t he first t im e you post ed a t im esheet workbook t o t he net work. When you select ed a locat ion, t hat locat ion was st ored in t he regist ry and from t here on out t he applicat ion sim ply read t he locat ion from t he regist ry whenever you post ed a new t im esheet . What t his didn't t ake int o account is t he possibilit y t hat t he consolidat ion locat ion m ight change. I f it did, you would have no way, short of edit ing t he applicat ion's regist ry ent ries direct ly, of swit ching t o t he new locat ion. Our new Specify Consolidat ion Folder feat ure enables you t o click a but t on on t he t oolbar and use t he Windows browse for folders dialog t o m odify t he consolidat ion folder. The SpecifyConsolidat ionFolder procedure is shown in List ing 9- 17 and t he updat ed t oolbar is shown in Figure 9- 5 .

List in g 9 - 1 7 . Th e N e w Spe cifyCon solida t ion Folde r Pr oce du r e Public Sub SpecifyConsolidationFolder()

Dim sSavePath As String InitGlobals ' Get the current consolidation path. sSavePath = GetSetting(gsREG_APP, gsREG_SECTION, _ gsREG_KEY, "") ' Display the browse for folders dialog with the initial ' path display set to the current consolidation folder. sSavePath = GetDirectory(sSavePath, _ gsCAPTION_SELECT_FOLDER, gsMSG_SELECT_FOLDER) If Len(sSavePath) > 0 Then ' Save the selected path to the registry. If Right$(sSavePath, 1) "\" Then _ sSavePath = sSavePath & "\" SaveSetting gsREG_APP, gsREG_SECTION, _ gsREG_KEY, sSavePath End If End Sub

Figu r e 9 - 5 . Th e Upda t e d PETRAS Tim e sh e e t Toolba r [View full size image]

Table 9- 2 sum m arizes t he changes t hat have been m ade t o t he t im esheet add- in for t his chapt er.

Ta ble 9 - 2 . Ch a n ge s t o t h e PETRAS Tim e sh e e t Add- in t o Use t h e Br ow se For Folde r Rou t in e M odu le

Pr oce du r e

MBrowseForFolder ( new m odule) MEnt r yPoint s

Ch a n g e I ncluded t he ent ire MBrowseForFolder m odule shown in List ing 9- 16

Post Tim eEnt r iesToNet w or k

Added call t o t he Get Direct ory funct ion in MBr ow seFor Folder

M odu le

Pr oce du r e

Ch a n g e

Specify Consolidat ionFolder

New feat ure t o updat e t he consolidat ion folder locat ion

PETRAS Reporting The changes m ade t o t he cent ral report ing applicat ion for t his chapt er are t o display a cust om icon for t he applicat ion and t o enable t he user t o close all t he result s workbooks sim ult aneously, by holding down t he Shift key while clicking t he File > Close m enu. The det ailed changes are shown in Table 9- 3, and List ing 9- 18 shows t he new MenuFileClose rout ine t hat includes t he check for t he Shift key.

List in g 9 - 1 8 . Th e N e w M e n u File Close Rou t in e , Ch e ck in g for a Sh ift + Close 'Handle the File > Close menu Sub MenuFileClose() Dim wkbWorkbook As Workbook 'Ch09+ 'Check for a Shift+Close If IsKeyPressed(gksKeyboardShift) Then 'Close all results workbooks For Each wkbWorkbook In Workbooks If IsResultsWorkbook(wkbWorkbook) Then CloseWorkbook wkbWorkbook End If Next Else 'Ch09'Close only the active workbook If IsResultsWorkbook(ActiveWorkbook) Then CloseWorkbook ActiveWorkbook End If End If End Sub

Ta ble 9 - 3 . Ch a n ge s t o t h e PETRAS Re por t in g Applica t ion for Ch a pt e r 9

M odu le

Pr oce du r e

Ch a n g e

MAPI Wr apper s ( new m odule)

ApphWnd

I ncluded List ing 9- 4 t o obt ain t he handle of Excel's m ain window

MAPI Wr apper s ( new m odule)

Set I con

I ncluded List ing 9- 7 t o display a cust om icon, read from t he new Pet rasI con.ico file.

MAPI Wr apper s

I sKeyPr essed

I ncluded List ing 9- 8 t o check for t he Shift key held down when clicking File > Close

MGlobals

Added a const ant for t he icon filenam e

MWor k space

Configur eExcelEnvir onm ent

Added a call t o Set I con

MEnt r yPoint s

MenuFileClose

Added check for Shift key being held down, shown in List ing 9- 17, doing a Close All if so

Lat er chapt ers, part icularly Chapt er 10 Userform Design and Best Pract ices, use m ore of t he rout ines and concept s int roduced in t his chapt er.

Conclusion The Excel obj ect m odel provides an ext rem ely rich set of t ools for us t o use when creat ing our applicat ions. By including calls t o Windows API funct ions, we can enhance our applicat ions t o give t hem a t ruly professional look and feel. This chapt er has explained m ost of t he uses of API funct ions t hat are com m only encount ered in Excel applicat ion developm ent . All t he fundam ent al concept s have been explained and you should now be able t o int erpret and underst and new uses of API funct ions as you encount er t hem . All of t he exam ple rout ines included in t his chapt er have been t aken from act ual Excel applicat ions and are ready for you t o use in your own workbooks.

Chapter 10. Userform Design and Best Practices Userform s are a fundam ent al part of m ost applicat ions' user int erfaces, ranging from cust om m essage and input boxes t o very com plex dat a- ent ry form s. This chapt er explains how t o get t he m ost out of Excel's userform s.

Principles When we design and code userform s, we st rive t o adhere t o a sm all set of basic principles whenever possible, explained below. We have found t hat following t hese principles has result ed in userform s t hat are easy t o use, easy t o code and easy t o m aint ain. Alt hough som e of t hese principles m ay seem a lit t le art ificial at first , experience has shown t hat st icking t o t hem gives longt erm rewards.

Keep It Simple A userform should not need a help file t o explain how t o fill it in. When present ed wit h a userform , our users should int uit ively be able t o use it . I n pract ice, t his m eans having a relat ively sm all num ber of cont rols on a userform t hat are well posit ioned, clearly labeled and in appropriat e groupings and orders t o m at ch t he t ask for which t he userform will be used. When designing a userform t o help wit h a com plex t ask, a wizard st yle should be used, breaking t he userform down int o m ult iple st eps, each of which adheres t o t he Keep I t Sim ple, St upid ( KI SS) principle. There are, of course, sit uat ions t hat require com plex userform s. I n t hese cases, ext ra effort should be invest ed t o m ake t he userform as sim ple t o use as possible. Making a com plex userform as easy as possible for t he user usually requires t he m ost effort on t he part of t he program m er and oft en result s in quit e com plex code!

Display Canvas, Not Business Rules A userform is a user int erface elem ent , not a place t o im plem ent business logic. The user int eract ion should always be separat ed from t he business response t o t hat int eract ion, at least logically if not physically. I n pract ice, t his m eans t hat t he only code t hat should be included in cont rols' event procedures is eit her ( a) changing anot her cont rol's propert ies, or ( b) calling funct ions in t he business logic layer. Conversely, t he code in t he business logic layer should never refer direct ly t o cont rols on t he userform and ideally should not assum e t hat a specific display m echanism is being used ( such as a set of opt ion but t ons vs. a list box) . So what is business logic in t his cont ext ? Figure 10- 1 shows a sim ple userform wit h a com bo box t o select a region and a t wo- colum n list t o show sales by product .

Figu r e 1 0 - 1 . A Sim ple Use r for m

I f t he code in t he com bobox_change event procedure ident ifies t he region, ret rieves t he product s for t he region, ret rieves t he t ot al sales for each product and adds t hem t o t he list box, it 's im plem ent ing business logic and is doing t oo m uch. When t he user select s a new region, t here are t wo t hings we need t o specify: ( 1) t he appropriat e response, and ( 2) t he dat a required t o sat isfy t hat response. I n our exam ple, t he appropriat e response is t o populat e t he list of product s and t he dat a required t o sat isfy t he response is t he list of product s and t he t ot al sales for each. At a m inim um , t he dat a required t o sat isfy t he response should be obt ained from t he business logic layer. I n t his case, we would have a funct ion in t he business logic layer t hat t akes a region as a param et er and ret urns an array of product s and t ot al sales. I t does t his by ret rieving t he underlying dat a from t he dat a access layer and populat ing t he array. Code in t he com bobox_change event would read t he select ed region from t he com bo box, call t he business logic layer funct ion t o get t he array of product s and sales and writ e t hat array t o t he list box. List ing 10- 1 shows an exam ple of t his m echanism .

List in g 1 0 - 1 . Th e Use r I n t e r fa ce La ye r D e t e r m in e s t h e Re spon se '*********************************** '* User Interface Layer, FSimpleForm '*********************************** 'Handle selecting a different region Private Sub cboRegion_Change() Dim vaProductSales As Variant 'Get the Product/Sales array for the selected region 'from the business logic layer

vaProductSales = GetProductSalesForRegion(cboRegion.Value) 'Populate the list box lstProducts.List = vaProductSales End Sub

At t he ext rem e, we int roduce a new user int erface support ( UI S) layer t hat cont ains t he code t o det erm ine t he appropriat e response for each user act ion. The event procedure would t hen cont ain a single line t hat calls a procedure in t he UI S layer, passing t he select ed region. The UI S layer calls t he funct ion in t he business logic layer t o ret rieve t he array of product s and t ot al sales, t hen t ells t he userform t o populat e t he list wit h t he array. This m echanism t reat s t he userform as not hing m ore t han a drawing and int eract ion layer and is an ext rem ely useful way t o handle com plex form s. An exam ple of t his t echnique can be found in t he UI SLayer.xls workbook on t he CD. I n List ing 10- 2, t he UI S layer is physically locat ed in a separat e class m odule t hat t ells t he userform what t o do by raising cust om event s. For m ore det ails about class m odules and cust om event s, see Chapt er 7Using Class Modules t o Creat e Obj ect s.

List in g 1 0 - 2 . Th e Use r I n t e r fa ce Su ppor t La ye r D e t e r m in e s t h e Re spon se '************************************* '* User Interface Layer in '* userform FComplexForm '************************************* 'UIS Event handler Dim WithEvents mclsUISComplexForm As CUISComplexForm

'Initialize our UIS class Private Sub UserForm_Initialize() Set mclsUISComplexForm = New CUISComplexForm End Sub ' ' Control events, to handle the user telling us ' to do something. In most cases, we just pass it ' on to the UIS class. ' 'Handle selecting a different region Private Sub cboRegion_Change() 'Tell the UIS layer that the user 'just selected a different region mclsUISComplexForm.RegionSelected cboRegion.Value

End Sub

' ' UIS class events, to handle the UIS layer ' telling us to do something ' 'Populate the Product Sales List Private Sub mclsUISComplex_PopulateProductList( _ vaProductSales As Variant) lstProducts.List = vaProductSales End Sub

'************************************************ '* User Interface Support Layer '* in class CUISComplexForm '************************************************ 'Events to tell the userform what to do Public Event PopulateProductList(vaProductSales As Variant)

'The user selected a different region. Public Sub RegionSelected(ByVal sRegion As String) Dim vaProductSales As Variant 'Get the Product/Sales array from the business logic layer vaProductSales = GetProductSalesForRegion(sRegion) 'Tell the userform to populate the products list RaiseEvent PopulateProductList(vaProductSales) End Sub

There is obviously m ore overhead in using an int erm ediat e UI S layer, but it reduces m ost of t he userform event procedures t o one- line calls int o t he UI S layer, enabling us t o concent rat e on t he det ail of t he user experience wit hin t he userform m odule. This m akes t he userform it self m uch easier t o m aint ain. Not ice also t hat t he UI S class has no knowledge of how t he inform at ion is obt ained or displayedall it knows is t hat when it 's given a region, it should t ell t he userform t hat t here's a new list of product s. The UI S class could be used by m ult iple versions of t he sam e userform perhaps wit h each one opt im ized for different screen resolut ions.

Use Classes, Not the Default Instance

Whenever we add a userform t o a proj ect , we aut om at ically get a default inst ance of t he userform creat ed for us. This is effect ively a global variable t hat has t he sam e nam e as t he userform 's class nam e, declared As New. This m eans t hat as soon as we refer t o t he userform , Excel creat es t he default inst ance for us ( t his is known as a u t o- in st a n t ia t ion ) . When we unload t he userform , t he default inst ance is dest royed and when we refer t o it again, t he default inst ance is re- creat ed. Consider a userform , FMyForm , cont aining a single t ext box, t xt Nam e. The code in List ing 10- 3 shows t he userform and displays t he nam e.

List in g 1 0 - 3 . Usin g t h e Use r for m 's D e fa u lt I n st a n ce Sub TestDefaultInstance() 'Show the userform FMyForm.Show 'Show the contents of the text box MsgBox "The name is: " & FMyForm.txtName.Text End Sub

Run t he procedure, t ype a nam e int o t he t ext box and close t he userform using t he [ x] in t he t opright corner. The procedure runs wit hout any errors, but t he m essage box doesn't show us t he nam e we t yped in! This is because when t he [ x] was clicked, t he userform was unloaded and anyt hing ent ered int o it was lost . Wit hin t he MsgBox line, t he reference t o FMyForm caused Excel t o creat e a new inst ance of t he userform , in which t he nam e is blank. D o n ot u se de fa u lt in st a n ce s. Userform s are j ust a special t ype of class m odule and t hey should be t reat ed like class m odules. By doing so, we gain cont rol over when t he userform is creat ed and dest royed, prevent ing t he t ype of bug dem onst rat ed in List ing 10- 3. List ing 10- 4 shows t he sam e rout ine, t reat ing t he userform as a class. This t im e, t he nam e is displayed correct ly.

List in g 1 0 - 4 . Usin g t h e Use r for m Lik e a Cla ss Sub TestClassInstance() 'Define our object variable Dim frmMyForm As FMyForm 'Set our object variable to be a new instance of the userform Set frmMyForm = New FMyForm 'Show the userform frmMyForm.Show 'Show the contents of the text box

MsgBox "The name is: " & frmMyForm.txtName.Text 'If showing the userform modeless, we have to unload it Unload frmMyForm End Sub

Unfort unat ely, using a userform like t his gives us a m inor problem t hat we need t o be aware of and workaround: I f t he userform is unloaded while our obj ect variable is referring t o it , we will oft en get an aut om at ion error. This is easily avoided by ensuring our userform is only ever hidden inst ead of being unloaded. The code in List ing 10- 5 can be added t o any userform s t hat have t he st andard OK and Cancel but t ons.

List in g 1 0 - 5 . H idin g I n st e a d of Un loa din g a For m 'Store whether the user OK'd or Cancel'd Dim mbOK As Boolean 'Handle the OK button Private Sub cmdOK_Click() mbOK = True Me.Hide End Sub 'Handle the Cancel button Private Sub cmdCancel_Click() mbOK = False Me.Hide End Sub 'Make the [x] behave the same as Cancel Private Sub UserForm_QueryClose(Cancel As Integer, _ CloseMode As Integer) If CloseMode = vbFormControlMenu Then cmdCancel_Click Cancel = True End If End Sub 'Return whether the OK or Cancel button was clicked Public Property Get OK() As Boolean OK = mbOK End Property

Expose Properties and Methods, Not Controls Following t he philosophy of t reat ing a userform like a class, we should only int eract wit h t he userform via propert ies and m et hods t hat we add t o t he userform 's class m odule; we should never refer t o individual cont rols from out side t he userform 's m odule, nor should we set any propert ies of t he userform it self. Proper encapsulat ion dict at es t hat everyt hing t o do wit h a userform should be cont ained wit hin t he userform . By adding propert ies and m et hods t o isolat e a userform 's cont rols from ext ernal code, we gain t he abilit y t o renam e or change t he st yle of any of t he cont rols, knowing t hat we won't be breaking any code t hat uses t he userform . I m agine a userform wit h a set of t hree opt ion but t ons t o select a level of det ail for a report . I f we were t o allow ext ernal code t o direct ly access t he cont rols, we m ight be t em pt ed t o writ e code like List ing 10- 6 ( where we've assum ed t he form includes t he code from List ing 10- 5) .

List in g 1 0 - 6 . Usin g a Use r for m 's Con t r ols D ir e ct ly Sub UseTheControls() Dim frmOptions As FOptions Set frmOptions = New FOptions 'Show the userform frmOptions.Show If frmOptions.OK Then 'Which option was selected? If frmOptions.optDetailed.Value Then RunDetailedReport ElseIf frmOptions.optNormal.Value Then RunNormalReport ElseIf frmOptions.optSummary.Value Then RunSummaryReport End If End If End Sub

The result of doing t his is t hat t he calling code is very t ight ly bound t o t he physical layout of t he userform , so if we want t o change t he userform 's layout such as t o use a com bo box inst ead of t he t hree opt ion but t onswe have t o check wherever t he userform is used and change t hat code as well as t he code wit hin t he userform 's m odule. I nst ead, we should expose everyt hing using propert y procedures, so t he calling code does not need t o know how t he propert y is physically represent ed on t he userform . List ing 10- 7 adds a Det ailLevel propert y t o t he userform , ret urning t he level of det ail as an enum erat ion, which t he

calling code uses t o decide which report t o run.

List in g 1 0 - 7 . Usin g Pr ope r t y Pr oce du r e s ' 'Within the userform FOptions ' 'Enum for the levels of detail Public Enum odlOptionDetailLevel odlDetailLevelDetailed odlDetailLevelNormal odlDetailLevelSummary End Enum 'Property to return the level of detail Public Property Get DetailLevel() As odlOptionDetailLevel 'Which option was selected? If optDetailed.Value Then DetailLevel = odlDetailLevelDetailed ElseIf optNormal.Value Then DetailLevel = odlDetailLevelNormal ElseIf optSummary.Value Then DetailLevel = odlDetailLevelSummary End If End Property ' 'The calling code ' Sub UseAProperty() Dim frmOptions As FOptions Set frmOptions = New FOptions 'Show the userform frmOptions.Show If frmOptions.OK Then 'Which option was selected? If frmOptions.DetailLevel = odlDetailLevelDetailed Then RunDetailedReport ElseIf frmOptions.DetailLevel = odlDetailLevelNormal Then RunNormalReport

ElseIf frmOptions.DetailLevel = odlDetailLevelSummary Then RunSummaryReport End If End if End Sub

Now if we want t o change t he opt ion but t ons t o a com bo box, all of t he changes are cont ained wit hin t he userform and it s code m odule, m aking m aint enance m uch easier and m uch less prone t o int roducing new bugs. Unfort unat ely, all t he cont rols on a userform and all t he userform 's propert ies are always exposed t o ext ernal code, so any propert ies and m et hods we add get lost in t he I nt elliSense list . I n Chapt er 11 I nt erfaces, we explain how t o define and use our own int erfaces, which allow us t o expose only t he propert ies and m et hods t hat we want t o be called.

Control Fundamentals There are a few fundam ent al det ails t hat we sim ply have t o get right when working wit h cont rols on user for m s.

Naming As we discussed in Chapt er 3 Excel and VBA Developm ent Best Pract ices, all our cont rols should be given m eaningful nam es and include a t wo- or t hree- charact er prefix t o ident ify t he cont rol t ype. This enables us t o easily ident ify t he cont rol in code and when set t ing t he t ab order. For exam ple, we have no idea which but t on Com m andBut t on1 is, but we can easily ident ify cm dOK and so on.

Layering I f we include t he background, userform s have t hree drawing layers. When we add a cont rol t o a userform , it get s added t o one of t he t op t wo layers, depending on t he t ype of cont rol. The t hree layers are ident ified as follows:

1 . The userform background and it s scrollbar 2 . The Label, CheckBox, Com boBox, Com m andBut t on, I m age, Opt ionBut t on, RefEdit , ScrollBar, SpinBut t on, TabSt rip, ToggleBut t on and Text Box cont rols 3 . The Fram e, List Box, Mult iPage and ot her Act iveX cont rols Cont rols in layer 2 can overlap each ot her, but will always be drawn behind cont rols in layer 3, whereas all t he cont rols in layer 3 can overlap each ot her. Fort unat ely, layer 3 includes t he Fram e cont rol, so if we want t o draw any of t he ot her cont rols on t op of a layer 3 cont rol, we can put it inside a fram e. Wit hin a layer, we can arrange our cont rols' z- order using t he Form at > Order m enu it em s.

Positioning All cont rols on a userform should be aligned bot h horizont ally and vert ically wit h a consist ent am ount of space bet ween t hem . When people read form s, t hey read t he t ext of each cont rol, so it is t he t ext t hat we should align and not t he edges of t he cont rols. I f we have Snap t o Grid swit ched on and add a t ext box and a label t o a userform , t he label will need t o be m oved down ( usually by four pixels) t o ensure t he t ext of t he label aligns wit h t he t ext ent ered int o t he t ext box. This can be done by edit ing t he label's Top propert y, t o add four pixels, but how big is a pixel? I n Chapt er 9 Underst anding and Using Windows API Calls, we explained t hat t he pixel size depends on t he user's

choice of dot s per inch, but is usually 0.75 point s for t he Norm al set t ing of 96 DPI and 0.6 point s for t he Large set t ing of 120 DPI . So t o m ove a cont rol by one pixel, we have t o add 0.75 or 0.6. Moving and sizing cont rols pixel by pixel is m ade m uch easier by using t he VBE Tools Cont rol Nudger t oolbar, shown in Figure 10- 2. This t oolbar is part of t he VBE Tools add- in, included on t he CD in t he \ Tools\ folder .

Figu r e 1 0 - 2 . Th e VBE Tools Con t r ol N u dge r Toolba r

Tab Orders and Accelerator Keys As designers of userform s, we t end t o be " m ousers" and oft en forget t hat m any people prefer t o use t he keyboard t o navigat e around userform s. We m ust rem em ber t o facilit at e keyboard usage by ensuring we give our cont rols t he correct t ab order and/ or accelerat or keys. The t ab order should m at ch t he nat ural reading orderleft t o right and t op t o bot t om and should include labels as well as cont rols. I f t he userform includes som e cont ainer cont rols, such as t he Fram e and Mult iPage cont rols, we m ust rem em ber t o set t he t ab order for t he cont rols t hey cont ain as well as for t hose direct ly on t he userform . We do t his by ensuring t he cont ainer cont rol is select ed before clicking View > Tab Order. Accelerat or keys enable us t o use t he Alt + key com binat ion t o j um p direct ly t o t he cont rol. The accelerat or key for a cont rol is ident ified by an underscore under t he appropriat e let t er of t he cont rol's capt ion. I f we set t he accelerat or key for a label and use t hat accelerat or key, t he focus will j um p t o t he next cont rol in t he userform 's t ab order. This behavior allows us t o provide keyboard access t o cont rols t hat do not have a capt ion, such as list boxes, edit boxes and so fort h.

Data Binding Many userform cont rols have propert ies t hat allow t hem t o be bound t o worksheet cells t o specify t heir cont ent s and/ or ret urn t heir value/ t ext . Don't use t hem . They are t here for beginners t o creat e sim ple, quick- and- dirt y form s, but t hey very quickly becom e m ore t rouble t han t hey're wort h. Using VBA t o set t he cont rols' cont ent s and handle t he dat a ent ry gives us m uch m ore flexibilit y and enables us t o validat e t he dat a before updat ing cells.

Event Handling

The MSForm s cont rols used on userform s have a fairly rich event m odel. Deciding which event t o use for a given purpose can be quit e daunt ing. Our recom m endat ion is t o follow t he principle of keeping it sim ple and use t he basic Change or Click event s for m ost sit uat ions. I n part icular, don't t ry t o int ercept t he KeyDown or KeyPress event s in an at t em pt t o force num eric ent ry int o a cont rol. I f your code prevent s let t ers, it also prevent s t he valid use of exponent ial not at ion, such as 1E3 for 1000. I f you t ry t o prevent m ult iple decim al separat ors, you have t o m ake sure you're allowing t he decim al separat or set in t he Regional Set t ings applet ; and if t he user put t he decim al in t he wrong place, you're forcing t hem t o delet e t he wrong one before t yping t he new one. I t is m uch bet t er ( and easier for us) t o allow t he user t o t ype in what ever he chooses, t hen validat e t he ent ry using VBA's I sNum eric( ) funct ion. Cont rol event s are fired bot h by user act ion and when t he cont rol is changed in code. We can use Applicat ion.EnableEvent s t o t urn event s on and off for Excel's obj ect s, but t hat has no effect on t he MSForm s obj ect m odel. We can get t he sam e level of cont rol over when event s are handled by using a m odule- level variable t hat is checked at t he st art of all our event procedures, as shown in List ing 10- 8.

List in g 1 0 - 8 . H a n dlin g Con t r ols' Eve n t s 'Module-level variable to control events firing Dim mbStopEvents As Boolean

'Handle clicking a 'Get Data' button Private Sub btnGetNames_Click() Dim vaNames As Variant 'Get a list of names from somewhere vaNames = Array("Rob", "Stephen", "John", "Robert") 'Turn off events while populating the controls mbStopEvents = True 'Populate controls. 'The Clear method triggers the Change event. lstNames.Clear lstNames.List = vaNames 'Turn events on again mbStopEvents = False 'Select the first name, allowing the Change event to fire If lstNames.ListCount > 0 Then lstNames.ListIndex = 0 End If End Sub

'Handle selecting a name Private Sub lstNames_Change() 'Don't do anything if we've stopped events If mbStopEvents Then Exit Sub 'Process selecting a name from the list MsgBox "You selected " & lstNames.Text End Sub

Validation Most userform s have cont rols for dat a ent ry and a pair of OK and Cancel but t ons. When t he OK but t on is clicked, t he dat a is writ t en t o t he sheet / dat abase/ obj ect m odel. When t he Cancel but t on is clicked, t he dat a is ignored. At som e point bet ween t he user ent ering dat a and t hat dat a being st ored, it m ust be validat ed. Many people are t em pt ed t o use t he BeforeUpdat e event for t heir validat ion code, because it has a Cancel propert y t hat can be used t o force t he user t o ent er valid dat a. Don't use it . Our userform s should never get in t he way of users, or int errupt t heir work, yet should also provide feedback as soon as possible, t o give t hem t he opport unit y ( but not force t hem ) t o correct t heir m ist akes. Our recom m endat ion is t o use an unobt rusive form of validat ion in each cont rol's Aft erUpdat e event and an int rusive form of validat ion in t he OK but t on's Click event . By int rusive, we m ean som et hing t hat st ops t he user from cont inuing, such as displaying a m essage box. By unobt rusive, we m ean som et hing t hat alert s t he user t o an error sit uat ion, but allows t hem t o cont inue, such as t urning t he background red and set t ing t he t oolt ip t o show t he error m essage. List ing 10- 9 shows t he code t o validat e a sim ple userform t hat cont ains t wo sales figures, and Figure 10- 3 shows t he userform wit h an error in t he first edit box.

List in g 1 0 - 9 . Va lida t in g Con t r ols Option Explicit 'When exiting the controls, we perform some 'nonintrusve validation, by calling the 'CheckNumeric function Private Sub txtSalesNorth_AfterUpdate() CheckNumeric txtSalesNorth End Sub Private Sub txtSalesSouth_AfterUpdate() CheckNumeric txtSalesSouth End Sub

'In the OK button, we use the same CheckNumeric

'function to show some intrusive validation 'messages. Private Sub btnOK_Click() Dim Dim Dim Dim Dim

dNorth As Double dSouth As Double sError As String sAllErrors As String bFocusSet As Boolean

'Validate the North Sales text box, 'returning the value or some error text If Not CheckNumeric(txtSalesNorth, dNorth, sError) Then 'Set the focus to the first control with an error If Not bFocusSet Then txtSalesNorth.SetFocus bFocusSet = True End If 'Build an error string, so we display all errors on the 'userform in one error message sAllErrors = sAllErrors & "North Sales:" & sError & vbLf End If 'Validate the South Sales text box, 'returning the value or some error text If Not CheckNumeric(txtSalesSouth, dSouth, sError) Then 'Set the focus to the first control with an error If Not bFocusSet Then txtSalesSouth.SetFocus bFocusSet = True End If 'Build an error string, so we display all errors on the 'userform in one error message sAllErrors = sAllErrors & "South Sales:" & sError & vbLf End If 'Display any errors we got If Len(sAllErrors) > 0 Then MsgBox "Please correct the following error(s):" & _ vbLf & sAllErrors, vbOKOnly Else 'No errors, so store the result ActiveSheet.Range("rngNorthSales").Value = dNorth ActiveSheet.Range("rngSouthSales").Value = dSouth 'And unload the userform Unload Me End If

End Sub

'The Cancel button just unloads the userform. 'This assumes the form is self-contained, so the 'calling routine doesn't need to know if the user 'OK'd or Cancelled the form. Private Sub btnCancel_Click() Unload Me End Sub

'Function to check a control (textbox or combobox) for 'numeric entry ' 'Parameters: txtData [in] The textbox or combobox ' dResult [out] The numeric value from the box ' sError [out] The text of the error message ' Function CheckNumeric(ByRef txtData As MSForms.Control, _ Optional ByRef dResult As Double, _ Optional ByRef sError As String) As Boolean Const sERR As String = ". Error: " Dim lErrPos As Long 'Remove any existing tooltip error text lErrPos = InStr(1, txtData.ControlTipText, sERR) If lErrPos > 0 Then txtData.ControlTipText = Left$(txtData.ControlTipText, _ lErrPos - 1) End If 'Check for valid entry If txtData.Text = "" Then 'Allow empty dResult = 0 sError = "" CheckNumeric = True 'And give the text box its usual background txtData.BackColor = vbWindowBackground ElseIf IsNumeric(txtData.Text) Then 'Numeric, so set the return values dResult = CDbl(txtData.Text) sError = "" CheckNumeric = True 'And give the text box its usual background txtData.BackColor = vbWindowBackground

Else 'Not numeric, so set the return values dResult = 0 sError = "Entry is not a number." CheckNumeric = False 'Give the text box a red background txtData.BackColor = vbRed 'And add the error message to the tooltip txtData.ControlTipText = txtData.ControlTipText & _ sERR & sError End If End Function

Figu r e 1 0 - 3 . An Un obt r u sive Er r or I n dica t or

Visual Effects Userform Window Styles We m ent ioned briefly in Chapt er 9 Underst anding and Using Windows API Calls t hat we can use a few API funct ions t o m odify t he appearance of a window's border and/ or t it le bar. List ing 10- 10 shows t he Set Userform Appearance procedure t o do j ust t hat for userform s, enabling us t o independent ly set t he following at t ribut es: Whet her t he userform has a t it le bar Whet her t he t it le bar is t he norm al size or t he sm all size used for float ing t oolbars Whet her t he userform is resizable Whet her t he userform has a m axim ize but t on Whet her t he userform has a m inim ize but t on Whet her t he userform has a close but t on Whet her t he userform has an icon and t he icon t o use To set t he appearance for a userform we call t he Set Userform Appearance procedure from t he Userform _I nit ialize event , passing in t he required set of values from t he Userform WindowSt yles enum erat ion, added t oget her. This code is included on t he CD in t he MForm St yles m odule in t he Userform St yles.xls workbook and uses t he FindOurWindow and Set I con procedures shown in Chapt er 9 Underst anding and Using Windows API Calls.

List in g 1 0 - 1 0 . M odifyin g a Use r for m 's W in dow St yle s 'Windows API calls to do all the dirty work Private Declare Function GetWindowLong Lib "user32" Alias _ "GetWindowLongA" (ByVal hWnd As Long, _ ByVal nIndex As Long) As Long Private Declare Function SetWindowLong Lib "user32" Alias _ "SetWindowLongA" (ByVal hWnd As Long, _ ByVal nIndex As Long, ByVal dwNewLong As Long) As Long Private Declare Function GetSystemMenu Lib "user32" _ (ByVal hWnd As Long, ByVal bRevert As Long) As Long

Private Declare Function DeleteMenu Lib "user32" _ (ByVal hMenu As Long, ByVal nPosition As Long, _ ByVal wFlags As Long) As Long Private Declare Function DrawMenuBar Lib "user32" _ (ByVal hWnd As Long) As Long 'Window Private Private Private Private Private Private Private Private Private Private

API constants Const GWL_STYLE As Long = (-16) Const GWL_EXSTYLE As Long = (-20) Const WS_CAPTION As Long = &HC00000 Const WS_SYSMENU As Long = &H80000 Const WS_THICKFRAME As Long = &H40000 Const WS_MINIMIZEBOX As Long = &H20000 Const WS_MAXIMIZEBOX As Long = &H10000 Const WS_EX_DLGMODALFRAME As Long = &H1 Const WS_EX_TOOLWINDOW As Long = &H80 Const SC_CLOSE As Long = &HF060

'Public enum of our userform styles Public Enum UserformWindowStyles uwsNoTitleBar = 0 uwsHasTitleBar = 1 uwsHasSmallTitleBar = 2 uwsHasMaxButton = 4 uwsHasMinButton = 8 uwsHasCloseButton = 16 uwsHasIcon = 32 uwsCanResize = 64 uwsDefault = uwsHasTitleBar Or uwsHasCloseButton End Enum

'Routine to set a userform's window style, 'called from Userform_Initialize event Sub SetUserformAppearance(ByRef frmForm As Object, _ ByVal lStyles As UserformWindowStyles, _ Optional ByVal sIconPath As String) Dim Dim Dim Dim

sCaption As String hWnd As Long lStyle As Long hMenu As Long

'Find the window handle of the form sCaption = frmForm.Caption frmForm.Caption = "FindThis" & Rnd hWnd = FindOurWindow("ThunderDFrame", frmForm.Caption) frmForm.Caption = sCaption 'If we want a small title bar, we can't have an icon, 'max or min buttons as well

If lStyles And uwsHasSmallTitleBar Then lStyles = lStyles And Not (uwsHasMaxButton Or _ uwsHasMinButton Or uwsHasIcon) End If 'Get the normal windows style bits lStyle = GetWindowLong(hWnd, GWL_STYLE) 'Update the normal style bits appropriately 'If we want and icon or Max, Min or Close buttons, 'we have to have a system menu ModifyStyles lStyle, lStyles, uwsHasIcon Or _ uwsHasMaxButton Or uwsHasMinButton Or _ uwsHasCloseButton, WS_SYSMENU 'Most things need a title bar! ModifyStyles lStyle, lStyles, uwsHasIcon Or _ uwsHasMaxButton Or uwsHasMinButton Or _ uwsHasCloseButton Or uwsHasTitleBar Or _ uwsHasSmallTitleBar, WS_CAPTION ModifyStyles lStyle, lStyles, uwsHasMaxButton, WS_MAXIMIZEBOX ModifyStyles lStyle, lStyles, uwsHasMinButton, WS_MINIMIZEBOX ModifyStyles lStyle, lStyles, uwsCanResize, WS_THICKFRAME 'Update the window with the normal style bits SetWindowLong hWnd, GWL_STYLE, lStyle 'Get the extended style bits lStyle = GetWindowLong(hWnd, GWL_EXSTYLE) 'Modify them appropriately ModifyStyles lStyle, lStyles, uwsHasSmallTitleBar, _ WS_EX_TOOLWINDOW 'The icon is different to the rest-'we set a bit to turn it off, not on! If lStyles And uwsHasIcon Then lStyle = lStyle And Not WS_EX_DLGMODALFRAME 'Set the icon, if given If Len(sIconPath) > 0 Then SetIcon hWnd, sIconPath End If Else lStyle = lStyle Or WS_EX_DLGMODALFRAME End If 'Update the window with the extended style bits SetWindowLong hWnd, GWL_EXSTYLE, lStyle

'The Close button is handled by removing it from the 'control menu, not through a window style bit If lStyles And uwsHasCloseButton Then 'We want it, so reset the control menu hMenu = GetSystemMenu(hWnd, 1) Else 'We don't want it, so delete it from the control menu hMenu = GetSystemMenu(hWnd, 0) DeleteMenu hMenu, SC_CLOSE, 0& End If 'Refresh the window with the changes DrawMenuBar hWnd End Sub

'Helper routine to check if one of our style bits is set 'and set/clear the corresponding Windows style bit Private Sub ModifyStyles(ByRef lFormStyle As Long, _ ByVal lStyleSet As Long, _ ByVal lChoice As UserformWindowStyles, _ ByVal lWS_Style As Long) If lStyleSet And lChoice Then lFormStyle = lFormStyle Or lWS_Style Else lFormStyle = lFormStyle And Not lWS_Style End If End Sub

Disabling the Close Button Even t hough t he procedure shown in List ing 10- 10 can be used t o rem ove t he close m enu from a userform , t he st andard Windows keyst roke of Alt + F4 t o close a window can st ill be used t o close t he form . We handle t his by hooking t he UserForm _QueryClose event , as shown in List ing 10- 11. The QueryClose event can be used wit hout rem oving t he Close but t on, but t hat gives conflict ing m essages t o t he user; you're showing an enabled Close but t on, but it doesn't do anyt hing.

List in g 1 0 - 1 1 . Pr e ve n t in g t h e Use r Closin g t h e Use r for m 'Set the form to have a (small) title bar, but no Close button Private Sub UserForm_Initialize() SetUserformAppearance Me, uwsHasSmallTitleBar

End Sub 'Prevent the form being closed using Alt+F4 Private Sub UserForm_QueryClose(Cancel As Integer, _ CloseMode As Integer) Cancel = (CloseMode = vbFormControlMenu) End Sub

Displaying Graphics, Charts, WordArt and So Forth on Userforms Userform s have very lim it ed graphics capabilit ies; alt hough we can set t he colors and font s of t he cont rols and use em pt y labels t o draw rect angles, we can't draw diagonal lines, arrows, ovals and so on. Neit her can we em bed ot her obj ect s on t o t he userform t o display chart s, WordArt and so fort h. We can, however, draw our graphics on a worksheet , copy t hem t o t he clipboard and past e t hem as pict ures t o use for t he background of m any of t he MSForm s cont rols. To set t he pict ure, select t he cont rol ( or t he userform it self) , click in t he Pict ure propert y box in t he Propert ies window and eit her click t he ellipsis t o select an im age file or j ust press Ct rl+ V t o past e a pict ure from t he clipboard. Most of t he cont rols st ret ch t he pict ure t o fill t he cont rol, but wit h t he I m age, Fram e and Page cont rols and t he userform background, we can cont rol t he pict ure sizing ( zoom , st ret ch or crop) , alignm ent ( wit hin t he cont rol) and whet her t he pict ure is t iled t o fill t he cont rol. At runt im e, we can use Excel's CopyPict ure m et hod t o copy a range, chart or ot her drawing obj ect t o t he clipboard and our Past ePict ure funct ion t o ret rieve t he im age from t he clipboard as a st andard Pict ure obj ect t hat can be assigned t o t he Pict ure propert y of t he MSForm s cont rols. The funct ion uses lot s of com plex Windows API calls t o ext ract t he pict ure from t he clipboard, so it 's best t o t reat it as a " black box" by j ust copying t he ent ire MPast ePict ure m odule int o your proj ect . We did t his in Chapt er 8 Advanced Com m and Bar Handling t o set a com m and bar but t on's Pict ure and Mask propert ies. The MPast ePict ure m odule can be found in t he Past ePict ure.xls exam ple workbook, which dem onst rat es how t o display a chart on a userform , shown in Figure 10- 4. The relevant part of t he code t o updat e t he chart is shown in List ing 10- 12.

List in g 1 0 - 1 2 . D ispla yin g a Ch a r t on a Use r for m 'Update the chart image on the form Private Sub UpdateChart() Dim chtChart As Chart Dim lPicType As Long 'Find the chart object on the sheet Set chtChart = Sheet1.ChartObjects(1).Chart 'Do we want a metafile or a bitmap? 'If scaling the image, xlPicture will give better results 'If not scaling, xlBitmap will give a 'truer' rendition.

'obMetafile is the 'Metafile' option button on the form lPicType = IIf(obMetafile, xlPicture, xlBitmap) 'Copy the chart to the clipboard, as seen on screen chtChart.CopyPicture xlScreen, lPicType, xlScreen 'Paste the picture from the clipboard into our image control Set imgChtPic.Picture = PastePicture(lPicType) End Sub

Figu r e 1 0 - 4 . D ispla yin g a Ch a r t on a Use r for m [View full size image]

Locking vs. Disabling Controls When t ext boxes and com bo boxes are disabled, Excel displays t he t ext in gray, but keeps t he whit e background. I f t here is no t ext in t he box, t here is no way for t he user t o t ell whet her it is disabled or not . An alt ernat ive is t o keep t he cont rol enabled, but locked and wit h a gray background. Locking a t ext box or com bo box allows t he user t o select any t ext in it , but not change t he t ext . This can be very useful when displaying inform at ion t o t he user t hat t hey m ay want t o copy t o t he clipboard, such as an error m essage. Figure 10- 5 shows a sect ion of a userform cont aining t hree t ext boxesone disabled, one locked wit h a gray background and t he t hird used as a label. I n our opinion, t he m iddle t ext box gives t he best visual indicat or t hat it is disabled, while keeping t he t ext readable. List ing 10- 13 shows t he st andard rout ine t hat we use t o " disable" our cont rols by locking t hem . Unfort unat ely, we cannot use t he sam e t echnique for a list box, because it doesn't redraw t he select ion indicat or when t he background color is changed!

List in g 1 0 - 1 3 . St a n da r d Pr oce du r e t o " D isa ble " a Con t r ol by Lock in g I t 'Enable/Disable a control by locking it and 'changing the background color Public Sub EnableControl(ByRef ctlControl As MSForms.Control, _ ByVal bEnable As Boolean) ctlControl.Locked = Not bEnable ctlControl.BackColor = IIf(bEnable, vbWindowBackground, _ vbButtonFace) End Sub

Figu r e 1 0 - 5 . Th r e e Te x t Box e s

Popup Menus When designing com plex userform s, we have a cont inual t rade- off bet ween adding feat ures t o m ake t he userform easier t o use versus confusing t he user by m aking t he userform t oo clut t ered. For exam ple, if we have a list box wit h a long list of nam es, we could m ake it easier t o find a nam e by adding opt ions t o sort by forenam e or surnam e, in ascending or descending order. We could add t hese cont rols as set s of opt ion but t ons or com bo boxes, but t hose t ake up valuable space on t he form and m ake it appear t oo clut t ered. An alt ernat ive m echanism is t o put t hose opt ions in a com m and bar creat ed wit h t he m soBarPopup st yle, t hen show t hat popup when t he user right clicks t he list box. Figure 10- 6 shows a list box wit h t he popup, and List ing 10- 14 shows t he code t o handle t he right - click and show t he popup. This code assum es t he com m and bar has already been creat ed and ot her rout ines handle t he m enu it em select ions.

List in g 1 0 - 1 4 . Sh ow in g a Popu p for a List Box

'Show a Sort Method popup when the list box is right-clicked Private Sub lstNames_MouseDown(ByVal Button As Integer, _ ByVal Shift As Integer, ByVal X As Single, _ ByVal Y As Single) '2=Right Button If Button = 2 Then Application.CommandBars("NameSortPopup").ShowPopup End If End Sub

Figu r e 1 0 - 6 . A List Box w it h Popu p Sor t M e n u

Userform Positioning and Sizing Positioning Next to a Cell I f we're displaying a userform in response t o t he user select ing a m enu it em from t he cell's popup m enu, it is a nice t ouch t o display t he userform direct ly alongside t he cell ( assum ing t here's space for it on t he screen) . Trying t o work out t he exact posit ion of a cell on t he screen using t he Range's posit ion is ext rem ely difficult , because we would have t o account for t he zoom fact or, scroll set t ings, which t oolbars were displayed and whet her t he Excel applicat ion window is m axim ized. Fort unat ely t here is an easier workaround, which is t o m ake use of t he window t hat Excel uses for edit ing em bedded chart s. I f we creat e a chart obj ect over t he cell and act ivat e it , Excel m oves a window wit h t he class nam e EXCELE t o t hat posit ion. We can im m ediat ely delet e t he chart obj ect , use API funct ions t o read t he posit ion of t he EXCELE window and display our userform in t he sam e place. List ing 10- 15 shows a procedure t o m ove a userform over a cell and an exam ple of it being used t o display a userform alongside of t he act ive cell. You can find t his rout ine on t he CD in t he MForm Pos m odule of Userform Posit ioning.xls. Not e t hat t he rout ine uses funct ions in t he MScreen and MWindows m odules from t he API Exam ples.xls workbook docum ent ed in Chapt er 9 Underst anding and Using Windows API Calls.

List in g 1 0 - 1 5 . Sh ow in g a Use r for m N e x t t o t h e Act ive Ce ll 'API Functions to find a window and read its position Private Declare Function FindWindowEx Lib "user32" _ Alias "FindWindowExA" (ByVal hWnd1 As Long, _ ByVal hWnd2 As Long, ByVal lpsz1 As String, _ ByVal lpsz2 As String) As Long Private Declare Function GetWindowRect Lib "user32" _ (ByVal hWnd As Long, lpRect As RECT) As Long Private Type RECT Left As Long Top As Long Right As Long Bottom As Long End Type

'Routine to move a form to a given cell Public Sub MoveFormToCell(frmForm As Object, _ rngCell As Range)

Dim hWndDesk As Long Dim hWndChart As Long Dim uChartPos As RECT 'Create a chart object at the cell, activate it and 'immediately delete it. That puts the EXCELE chart 'editing window in the correct place With rngCell.Parent.ChartObjects.Add(rngCell.Left, _ rngCell.Top, 1, 1) .Activate .Delete End With 'Find the EXCELE window hWndDesk = FindWindowEx(ApphWnd, 0, "XLDESK", vbNullString) hWndChart = FindWindowEx(hWndDesk, 0, "EXCELE", vbNullString) 'Read its position GetWindowRect hWndChart, uChartPos 'Move the form to the same position, 'converting pixels to points frmForm.Left = uChartPos.Left * PointsPerPixel frmForm.Top = uChartPos.Top * PointsPerPixel End Sub

'Test procedure to show a form next to the active cell Sub ShowMyForm() Dim frmForm As FMyForm Set frmForm = New FMyForm 'Set the form to show in a custom position frmForm.StartUpPosition = 0 'Move the form over the cell MoveFormToCell frmForm, ActiveCell.Offset(0, 1) 'Show the form frmForm.Show End Sub

Responding to Different Resolutions

We regularly see quest ions in t he Microsoft support newsgroups from people who have designed a userform t o fill t heir screen, only t o find t hat it 's t oo big for t heir users' lower resolut ions. The quest ion usually ends " How do I change t he user's resolut ion t o display m y userform ?" The answer is always " You don't ." I nst ead, we have t o design our userform s so t hey are usable on t he lowest resolut ion our users have. Typically, t hat m eans a resolut ion of 800x600 pixels, alt hough people wit h poor sight or very sm all screens m ay use 640x480 pixels. Designing our userform s t o fit on a 640x480 display gives us t wo m ain issues t o solve:

1 . We can't fit m any cont rols on a 640x480 userform . 2 . Userform s t hat fit on a 640x480 screen oft en m ake very poor use of t he space available wit h larger resolut ions. I n pract ice, m ost of t he userform s we creat e are quit e sim ple and can usually fit wit hin t he bounds of a 640x480 screen. For com plex form s, we usually use popup m enus, drop- down panes ( see lat er) and/ or a wizard st yle t o m ake t he m ost of t he available space and m ay design m ult iple versions of t he sam e form , for use wit h different screen resolut ions. The form s for lower resolut ions will use m ore com pact cont rols, such as com bo boxes inst ead of set s of opt ion but t ons or list boxes and have less blank space around each cont rol, whereas t he form s for higher resolut ions will have m ore cont rols direct ly visible, wit h each cont rol using m ore space. I f we correct ly split our code bet ween t he form layer and business logic layer, bot h form s can use t he sam e class for t heir business logic.

Resizable Userforms Part of t he KI SS principle is avoiding overwhelm ing t he user. Experience has shown us t hat if a userform won't fit on an 800x600 resolut ion screen, it alm ost cert ainly cont ains t oo m any cont rols. For t hat reason, we design our form s t o fit on an 800x600 screen, but m ake t hem resizable so t he user can choose t o m ake bet t er use of t he space available if t hey have a higher- resolut ion screen. For exam ple, if our userform includes a list box, we allow t he list box t o change size wit h t he form , t hereby allowing t he user t o see m ore it em s in t he list . The Form Resizer.xls exam ple workbook cont ains a class m odule, CForm Resizer, which can be included in a proj ect t o handle t he resizing of any form . The class changes t he form 's window st yles t o m ake it resizable and handles t he resizing and reposit ioning of all t he cont rols on t he form . We define t he resize behavior of each cont rol by set t ing it s Tag propert y t o indicat e by how m uch each of it s t op, left , height and/ or widt h should change in proport ion t o t he change in size of t he form . To m ake one of t he propert ies change as t he form is sized, we include t he let t er T, L, H, or W followed by a num ber giving t he percent age change ( or om it t ed for 100 percent ) . For exam ple, if we have an OK but t on in t he m iddle bot t om of t he form , we would want it t o m ove up/ down t he sam e am ount as t he change in t he form 's height and m ove left / right by half t he change in t he form 's widt h; it s Tag would be TL0.5. I f we have a form wit h a pair of list boxes side by side, we would want t he left list box t o keep it s t op and left const ant , but grow by t he full change in t he form 's height and half t he change in t he form 's widt h; it s Tag would be HW0.5. The right - hand list box would resize t he sam e way, but should also m ove across by half t he change in form 's widt h ( so it s right edge st ays const ant relat ive t o t he right edge of t he form ) ; it s Tag would be L0.5HW0.5. To st art including resizable userform s in your applicat ions, copy t he CForm Resizer class int o t he proj ect , hook it up t o a form using t he code shown in List ing 10- 16 and set t he cont rols' Tag

propert ies appropriat ely. I t will probably t ake som e t rial and error t o get t he t ags correct at first , but will becom e m uch easier wit h pract ice. For best result s, list boxes should have t heir I nt egralHeight propert y set t o False, and due t o an Excel bug, t hey m ay need an ext ra blank it em added t o t he bot t om of t he list for all t he it em s t o display correct ly.

List in g 1 0 - 1 6 . M a k in g a Use r for m Re siza ble Usin g t h e CFor m Re size r Cla ss 'Declare an object of our CFormResizer class to handle 'resizing for this form Dim mclsResizer As CFormResizer 'The Resizer class is set up in UserForm_Initialize Private Sub UserForm_Initialize() 'Create the instance of the class Set mclsResizer = New CFormResizer 'Tell it which form it's handling Set mclsResizer.Form = Me End Sub 'When the form is resized, the UserForm_Resize event is 'raised, which we just pass on to the Resizer class Private Sub UserForm_Resize() mclsResizer.FormResize End Sub 'The QueryClose event is called whenever the form is closed. 'We call the FormResize method one last time, to store the 'form's final size and position in the registry Private Sub UserForm_QueryClose(Cancel As Integer, _ CloseMode As Integer) mclsResizer.FormResize End Sub

Splitter Bars I f our resizable userform s cont ain t wo or m ore list boxes, it m ay not be always desirable t o let t hem bot h grow or shrink at t he sam e rat e. We can allow our users t o decide how m uch space t o give each form by adding a split t er bar bet ween t hem . We don't act ually have a split t er bar cont rol, but we can fake one using a norm al Label. The userform shown in Figure 10- 7 has t wo list boxes t hat are bot h configured for t heir widt h t o change at half t he rat e of t he form 's change in widt h, keeping t he gap bet ween t hem cent ral t o t he form . We've also added a label t o fill t he gap bet ween

t he list boxes. For clarit y, it is shown here wit h it s nam e, but would norm ally be t ransparent and blank. The label's MousePoint er propert y has been changed t o fm MousePoint erSizeWE, so we get t he st andard left / right sizing arrows when t he m ouse m oves over t he label. The code in List ing 1017 uses t he label's m ouse event s t o sim ulat e a split t er bar.

List in g 1 0 - 1 7 . Th e Code t o Tu r n a La be l in t o a Split t e r Ba r 'Module variables to handle the splitter bar Dim mbSplitterMoving As Boolean Dim mdSplitterOrigin As Double 'When pressing down the left mouse button, 'initiate the dragging and remember where we started Private Sub lblSplitterBar_MouseDown( _ ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single) If Button = 1 Then mbSplitterMoving = True mdSplitterOrigin = X End If End Sub 'When releasing the left mouse button, 'stop the dragging Private Sub lblSplitterBar_MouseUp( _ ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single) If Button = 1 Then mbSplitterMoving = False End Sub 'When moving the mouse over the label 'and we're in 'drag' mode (i.e. dragging the splitter), 'move all the controls appropriately Private Sub lblSplitterBar_MouseMove( _ ByVal Button As Integer, ByVal Shift As Integer, _ ByVal X As Single, ByVal Y As Single) Dim dChange As Double 'Are we doing a drag? If mbSplitterMoving Then 'Find where we moved to dChange = (X - mdSplitterOrigin) / PointsPerPixel 'Adjust the control sizes and positions If (lstLeft.Width + dChange > 0) And _

(lstRight.Width - dChange > 0) Then 'The left list changes size lstLeft.Width = lstLeft.Width + dChange 'The splitter bar in the middle moves lblSplitterBar.Left = lblSplitterBar.Left + dChange 'The right list moves and changes size lstRight.Left = lstRight.Left + dChange lstRight.Width = lstRight.Width - dChange End If End If End Sub

Figu r e 1 0 - 7 . A Split t e r Ba r Be t w e e n Tw o List Box e s

Wizards Wizard dialogs are norm ally used when we need t o collect a reasonably large am ount of dat a from t he user. The only absolut e requirem ent t his dat a m ust fulfill in order t o be a candidat e for a wizard dialog is t hat t he bit s of dat a being collect ed m ust be logically relat ed t o each ot her in som e way. Wizard dialogs are part icularly useful where t he dat a being collect ed has t he following charact erist ics in addit ion t o being logically relat ed: The inform at ion is com plex and varied. The inform at ion m ust be supplied in a defined order because earlier select ions alt er t he allowable param et ers of lat er select ions. The user does not need t o underst and t he relat ionship bet ween earlier and lat er choices. The wizard dialog can t hen abst ract t his decision- m aking process away from t he user. The prim ary purpose of a wizard dialog is t o reduce t he num ber of choices t he user m ust m ake at any one t im e t o a m anageable level. An im port ant secondary purpose of a wizard dialog is t o allow us t o alt er t he part s of t he user int erface t hat depend on t he select ions t he user is current ly m aking wit hout having t o do so in a way t hat is visible t o t he user and t hereby pot ent ially dist ract t hem from t he t ask at hand ( see Dynam ic Userform s lat er for an exam ple) .

Design Rules for Wizard Dialogs

1 . The first page of a wizard dialog should explain t he purpose of t he wizard and t he st eps involved, but always have a " Don't show m e t his again" check box t o aut om at ically skip t he first page if t he user want s. 2 . The last page of a wizard dialog should confirm everyt hing t he user has ent ered and all t he choices m ade, and no act ions are perform ed unt il t he user clicks t he Finish but t on. 3 . Always display t he st ep num ber wit hin t he wizard t hat t he user is current ly working on as well as t he t ot al num ber of st eps left t o com plet e. This inform at ion is t ypically displayed in t he t it le bar, alt hough we've seen perfect ly accept able designs t hat display it elsewhere. 4 . Navigat ion t hrough t he wizard is t ypically cont rolled by a series of four but t ons: Cancel, Back, Next and Finish. The enabled st at e of t hese but t ons should be used t o provide visual clues t o t he user about how t hey're doing. Track t he user's progress t hrough t he wizard and wat ch t heir input during each st ep of t he wizard. Based on where t he user is and what dat a he has ent ered, enable only t he navigat ion but t ons t hat m akes sense, such as t he following: First st ep wit h no dat a ent eredThe Cancel but t on should be t he only but t on enabled.

( Cancel is always enabled.) The Next but t on is only enabled when t he page passes all validat ion checks, as long as t he user can det erm ine which are t he invalid ent ries and why ( see Validat ion earlier) . Last st ep wit h all dat a ent ered and validat edCancel enabled, Back enabled, Next disabled and Finish enabled. The user has com plet ed all wizard st eps correct ly but t hen used t he Back but t on t o revisit an earlier st epAll but t ons enabled unt il t he user m akes an ent ry t hat invalidat es t he abilit y of t he wizard t o finish or m ove forward. I n, say, a five- st ep wizard, if st eps four and five allow t he user t o ent er opt ional inform at ion, t he Finish but t on can be enabled aft er st ep t hree. Excel's Chart Wizard is a good exam ple of t his.

5 . The user can m ove back and fort h t hrough wizards t o his heart 's cont ent . Therefore, you m ust always keep t rack of t he st at us of all st eps in t he wizard in order t o properly set t he st at us of t he navigat ion but t ons. I t is perfect ly appropriat e for t he user t o click Finish from st ep t wo of a five- st ep wizard as long as he has com plet ed all five st eps and has j ust m oved back t o st ep t wo in order t o m ake a m inor change. 6 . I n som e wizard designs, select ions m ade on a st ep affect ot her select ions on t hat sam e st ep. I f a select ion on a st ep m akes anot her select ion on t hat sam e st ep unnecessary, do not h id e t he cont rols for t he unnecessary select ion. Just disable t hem . Cont rols t hat pop in and out of exist ence in front of t he user's face t end t o be a confusing dist ract ion.

Creating a Wizard Dialog The easiest way t o creat e a wizard dialog is t o use a Mult iPage cont rol, wit h each page of t he cont rol being used for a separat e st ep of t he wizard and a com m on set of but t ons at t he bot t om . Figure 10- 8 shows t he wizard userform t em plat e included on t he CD in t he WizardDem o.xls workbook, wit h t he Mult iPage t abs showing on t he right side. Prior t o dist ribut ing t he wizard, t he Mult iPage should be form at t ed t o not have any t abs showing by set t ing it s St yle propert y t o fm TabSt yleNone, and reducing bot h t he Mult iPage's and userform 's widt h accordingly.

Figu r e 1 0 - 8 . An Em pt y W iza r d Use r for m Usin g a M u lt iPa ge Con t r ol for t h e St e ps

Unfort unat ely, t he Mult iPage cont rol is not wit hout it s problem s, part icularly when using nonMSForm s cont rols wit hin a page. I f you int end t o use t he RefEdit cont rol or any of t he Windows Com m on Cont rols ( such as t he TreeView and List View cont rol) , you should use a separat e Fram e cont rol for each st ep of t he wizard inst ead of a Mult iPage cont rol. I f using a Fram e cont rol, it 's easiest t o develop t he wizard wit h all t he fram es visible at t he sam e t im e, on a userform m uch larger t han t he final version. When t he wizard is com plet e, change t he fram es' left and t op so t hey all overlap and reduce t he userform t o it s correct size. List ing 10- 18 shows t he code for t he four navigat ion but t ons, which each call furt her procedures t o init ialize and validat e t he cont rols in each st ep. The cont ent of t he I nit ializeSt ep and bValidat eSt ep procedures will obviously depend on t he cont ent s of t he st ep, so have not been shown here. As well as init ializing t he cont rols on each page, t he I nit ializeSt ep procedure should updat e t he userform 's capt ion t o show t he st ep num ber and enable/ disable t he navigat ion but t ons.

List in g 1 0 - 1 8 . Th e N a viga t ion Code for a W iza r d D ia log Private Sub cmdCancel_Click() mbUserCancel = True Me.Hide End Sub Private Sub cmdBack_Click() ' Can't go back from step 1. If mlStep > 1 Then ' No validation is required when moving back. mlStep = mlStep - 1

mpgWizard.Value = mlStep - 1 InitializeStep mlStep End If End Sub Private Sub cmdNext_Click() ' Can't go forward from the last step. If mlStep 5 Then lBoxes = 5 'Initialize the collection of event handler classes Set mcolEvents = New Collection 'Create the required number of boxes

For lBox = 1 To lBoxes 'Add a label to the form Set lblLabel = Me.Controls.Add("Forms.Label.1", _ "lbl" & lBox) With lblLabel .Top = (lBox - 1) * 21.75 + 9 .Left = 6 .Width = 50 .Height = 9.75 .WordWrap = False .Caption = "Text Box " & lBox End With 'Add the text box to the form Set txtBox = Me.Controls.Add("Forms.TextBox.1", _ "txt" & lBox) With txtBox .Top = (lBox - 1) * 21.75 + 6 .Left = 56 .Width = 50 .Height = 15.75 End With 'Create a new instance of the event handler class Set clsEvents = New CTextBoxEvents 'Tell it to handle the events for the text box Set clsEvents.Control = txtBox 'Add the event handler instance to our collection, 'so it stays alive during the life of the form mcolEvents.Add clsEvents Next End Sub

We can use t he sam e t echnique t o handle t he event s of cont rols in nondynam ic userform s as well. I m agine a form wit h 50 t ext boxes, all requiring num eric validat ion. We could include all 50 Change event procedures in our code and accept t he m aint enance overhead t hat brings, or we could use t he class m odule from List ing 10- 20 t o handle t he validat ion for all our t ext boxes. The code in List ing 10- 22 it erat es t hrough all t he cont rols on t he form , hooking up new inst ances of t he event handler class for every t ext box it finds.

List in g 1 0 - 2 2 . Cla ss t o H a n dle a Te x t Box 's Eve n t s

'Collection to store instances of our event handler class Dim mcolEvents As Collection 'Hook the events for all the Text Boxes Private Sub UserForm_Initialize() Dim ctlControl As MSForms.Control Dim clsEvents As CTextBoxEvents 'Initialize the collection of event handler classes Set mcolEvents = New Collection 'Loop through all the controls For Each ctlControl In Me.Controls 'Check if it's a text box If TypeOf ctlControl Is MSForms.TextBox Then 'Create a new instance of the event handler class Set clsEvents = New CTextBoxEvents 'Tell it to handle the events for the text box Set clsEvents.Control = ctlControl 'Add the event handler instance to our collection, 'so it stays alive during the life of the form mcolEvents.Add clsEvents End If Next End Sub

Modeless Userforms Most of t he dialogs t hat we norm ally com e int o cont act wit h are m odal, which is t o say t hat neit her t he applicat ion nor t he user can do anyt hing unt il t he form is dism issed. When t he Show st at em ent is processed, by default t he applicat ion window is disabled ( so none of t he m enus are available) , t he form is displayed and t he code st ops. Snippet s of code can run in response t o cont rol event s, but it 's not unt il t he user closes t he form t hat execut ion cont inues on t he line aft er t he Show st at em ent . When a userform is shown m odeless, however, code execut ion cont inues im m ediat ely aft er t he Userform _I nit ialize and Userform _Act ivat e event procedures have finished, wit h t he userform rem aining displayed. I f t he code com es t o an end while a m odeless userform is displayed, t he form rem ains open and bot h t he userform and t he applicat ion window can be used.

N OTE Excel 97 does not support m odeless userform s.

Splash Screens The sim plest use for a m odeless userform is as an int roduct ory splash screen. The userform is shown m odeless at t he st art of t he Aut o_Open or Workbook_Open procedure and unloaded at t he end of t he procedure. List ing 10- 23 shows a sim ple exam ple, where t he form uses t he Set Userform Appearance procedure from earlier t o rem ove t he t it le bar.

List in g 1 0 - 2 3 . Sh ow in g a Spla sh Scr e e n a t St a r t u p Sub Auto_Open() Dim frmSplash As FSplashScreen 'Show the form modelessly Set frmSplash = New FSplashScreen frmSplash.Show vbModeless 'Process the startup code Application.Wait Now + TimeValue("00:00:5") 'Unload the splash screen

Unload frmSplash Set frmSplash = Nothing End Sub 'The FSplashScreen Userform's Code Module Option Explicit 'Set the form to have no title bar Private Sub UserForm_Initialize() 'Adjust the height for the missing caption Me.Height = Me.InsideHeight SetUserformAppearance Me, uwsNoTitleBar End Sub 'Prevent the form being closed using Alt+F4 Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) Cancel = (CloseMode = vbFormControlMenu) End Sub

Progress Bars A rat her m ore int erest ing use of m odeless form s is t o display progress inform at ion t o t he user during lengt hy looping operat ions. Figure 10- 11 shows a sim ple progress bar userform , where t he progress indicat or is m ade up of t wo overlapping Fram e cont rols, each cont aining a label. The back fram e has a whit e background and a label wit h blue t ext , and t he front fram e has a blue background and a label wit h whit e t ext . As t he progress is updat ed, t he widt h of t he front fram e is adj ust ed, allowing us t o see m ore of t he blue background. This m akes t he bar appear t o fill up as t he progress increases.

Figu r e 1 0 - 1 1 . A M ode le ss Pr ogr e ss Ba r

The code for t he progress bar form is t oo lengt hy t o show here, but is included on t he CD in t he ModelessForm s.xls exam ple workbook. The FProgressBar form can be copied from t he exam ple workbook int o your proj ect and cont rolled using code such as t hat shown in List ing 10- 24.

List in g 1 0 - 2 4 . Usin g t h e Pr ogr e ss Ba r Use r for m Sub ShowProgress() Dim lLoop As Long Dim lIterations As Long Dim frmProgress As FProgressBar lIterations = 2000 'Initialize the progress bar Set frmProgress = New FProgressBar frmProgress.Title = "Professional Excel Development" frmProgress.Text = "Preparing reports, please wait..." frmProgress.Min = 1 frmProgress.Max = lIterations 'Show the progress bar frmProgress.ShowForm For lLoop = 1 To lIterations 'Check if the user cancelled If frmProgress.Cancelled Then Exit For 'Update the progress frmProgress.Progress = lLoop 'Do Stuff Next lLoop 'Unload the progress bar form Unload frmProgress End Sub

Combining with Menu Items I f we display a m odeless userform and t hen allow our code t o finish, t he form is left act ive on t he screen, and bot h t he form and t he applicat ion can be used. This behavior can be used t o very good effect in form - based dict at or applicat ions. I n t his design, t he worksheet is only ever used for a

backdrop graphic display; all t he int eract ion wit h t he user is done t hrough userform s. Most form based applicat ions have a cent ral " swit chboard" form , wit h a set of but t ons t o show subform s for each funct ional area. Those form s have t heir own but t ons t o show ot her form s and so on. I t is usually very difficult t o navigat e around t he applicat ion. I f we use m odeless userform s, however, t he m enus are available, so we can im plem ent a m enu st ruct ure t hat enables t he user t o quickly swit ch bet ween part s of t he applicat ion. To im plem ent t his design, we need t o be able t o com m unicat e wit h all t he form s, so t hey can be not ified when t he user clicks a m enu it em t o j um p t o anot her form , or when t he applicat ion is about t o exit , or if t he Save m enu it em is clicked. All t he form s will have t o include t he sam e set of st andard funct ions, shown in List ing 10- 25, t hat can be called from a cent ral " form - handler" r out ine.

List in g 1 0 - 2 5 . St a n da r d Rou t in e s t o Be I n clu de d in All M ode le ss For m s ' Called prior to navigating to another form. ' Allows the form to validate and store its data, then unload ' If validation fails, the navigation can be cancelled Public Sub BeforeNavigate(ByRef Cancel As Boolean) End Sub ' Called prior to saving the data workbook ' Allows the form to validate and store its data ' If validation fails, the navigation can be cancelled Public Sub BeforeSave(ByRef Cancel As Boolean) End Sub ' Called after to saving the data workbook ' Allows the form to update its display ' (e.g. if showing the file name) Public Sub AfterSave() End Sub ' Called when the application is about to be closed ' The form should unload itself, but could cancel the close Public Sub AppExit(ByRef Cancel As Boolean) End Sub

Wit h all t he userform s having t he sam e set of st andard rout ines, we can writ e a sim ple cent ralized rout ine t o m anage t hem all, shown in List ing 10- 26.

List in g 1 0 - 2 6 . Th e Ce n t r a l Con t r ol Rou t in e t o H a n dle N a viga t ion Be t w e e n For m s ' Global variable to hold the form currently being displayed

Dim gfrmActiveForm As Object ' A single OnAction procedure for most menu items, where the ' form name is obtained from the menu item's Parameter Sub FormMenuClick() ShowForm Application.CommandBars.ActionControl.Parameter End Sub 'Common routine to switch between forms Sub ShowForm(ByVal sForm As String) Dim bCancel As Boolean 'If there's an active form, tell it to save and unload If Not gfrmActiveForm Is Nothing Then gfrmActiveForm.BeforeNavigate bCancel End If 'If the save/close wasn't cancelled, If Not bCancel Then 'Show the next form, assuming it is in the same workbook Set gfrmActiveForm = VBA.Userforms.Add(sForm) gfrmActiveForm.Show vbModeless End If End Sub 'The OnAction routine for the File > Save menu item Sub MenuFileSave() Dim bCancel As Boolean 'If there's an active form, tell it to save its data If Not gfrmActiveForm Is Nothing Then gfrmActiveForm.BeforeSave bCancel End If If Not bCancel Then 'Save the data workbook if not cancelled gwkbDataWorkbook.Save 'If there's an active form, tell it to do its post-save 'processing (if any) If Not gfrmActiveForm Is Nothing Then gfrmActiveForm.AfterSave End If End If End Sub

Using t his m echanism , we can add m ore userform s t o t he applicat ion wit hout having t o add any

ext ra code t o cont rol t heir display; as long as t hey include t he st andard set of procedures shown in List ing 10- 25, t hey will plug in t o t he cent ral cont rol procedure. All we need t o do is add t he form m odule t o t he workbook and add som e ext ra lines t o t he t able used by t he com m and bar builder, t o include t he new form in our applicat ion's m enu st ruct ure.

Control Specifics Most of t he cont rols t hat we use in our form s are well docum ent ed and well underst ood, so docum ent ing t hem here would be of lit t le benefit t o t he reader. I nst ead, t his sect ion of t he chapt er explains how t o use som e of t he lesser- known cont rols, or how t o use t hem in innovat ive ways.

ComboBox The Com boBox is t he unsung hero of t he MSForm s t oolbox. By changing t he st yle of t he drop- down but t on, we can use a com bo box as a norm al drop- down list , as a t ext box, as a filenam e ent ry box or as a t ot ally cust om ized drop- down cont rol. Figure 10- 12 shows four com bo boxes, wit h t he bot t om one shown in it s dropped st at e, revealing a cust om drop- down pane for specifying a filt er.

Figu r e 1 0 - 1 2 . Com bo Box St yle s

Drop-Down List/Combo The default behavior for a com bo box is t o allow t he user t o select an it em from a list or t ype in ent ries t hat do not exist in t he supplied list ; when t he arrow is clicked, t he list is shown below t he com bo box. When t he user clicks on an it em from t he list , t he select ed it em is shown in t he cont rol and t he list is hidden.

Text Box I f we set t he ShowDropBut t onWhen propert y t o fm ShowDrop- But t onNever and t he St yle propert y t o fm St yleDropDownCom bo, t he result is a cont rol t hat looks and behaves exact ly like a t ext box. This allows us t o have a single cont rol t hat can be used t o select an it em from a list , or allow direct ent ry. For exam ple, in t he userform in Figure 10- 12, t he t op drop- down m ay be a list of at t ribut es about a person, such as age, sex and so on, whereas t he second drop- down would be used t o fill in t he value for t he select ed at t ribut e. When Age is select ed from t he drop- down, we would want t o be able t o t ype a num ber direct ly int o t he cont rol, but when Sex is select ed, we would want t o show a drop- down t o choose bet ween Male and Fem ale.

Filename Box By changing t he DropBut t onSt yle t o fm DropBut t onSt yleEllipsis, we creat e a cont rol t hat looks like a filenam e box. The user would expect a File Open dialog t o appear when he clicks t he but t on. We can do exact ly t hat by hooking t he DropBut t onClick event , as shown in List ing 10- 27.

List in g 1 0 - 2 7 . H a n dle t h e Ellipsis in t h e File n a m e Com bo 'Handle clicking the ellipsis in the Filename combo Private Sub cboFileName_DropButtonClick() Dim vFile As Variant 'Get the filename vFile = Application.GetOpenFilename() 'Write it to the control If TypeName(vFile) = "String" Then cboFileName.Text = vFile End If 'Toggle the Enabled property to move the focus 'to the next control cboFileName.Enabled = False cboFileName.Enabled = True End Sub

One annoying aspect of hooking t he DropBut t onClick event is t hat we can't cancel it , so t he cont rol shows an em pt y list aft er we've obt ained t he filenam e. One workaround for t his is t o t oggle t he Enabled propert y of t he cont rol, which forces t he focus t o m ove t o t he next cont rol in t he t ab order.

Drop-Down Panes The fourt h com bo box shown in Figure 10- 12 is used t o im plem ent a t ot ally cust om ized drop- down pane, t o display a sim ple filt er select ion. This would t ypically be used above a list box, t o filt er t he it em s in t he list . The code t o handle t he filt er pane is shown in List ing 10- 28.

List in g 1 0 - 2 8 . Code t o M a n a ge a Cu st om D r op- D ow n Pa n e 'Boolean to identify if the filter has changed Dim mbFilterChanged As Boolean 'Set up the form Private Sub UserForm_Initialize() cboFilter.AddItem "All Clients" cboFilter.ListIndex = 0 cboConsultant.List = Array("Stephen Bullen", "Rob Bovey", _ "John Green") cboConsultant.ListIndex = 0 End Sub 'When clicking the drop-down, show the filter frame Private Sub cboFilter_DropButtonClick() mbFilterChanged = False fraFilter.Visible = True fraFilter.SetFocus End Sub 'Changing any of the filter options 'sets the 'Filter Changed' Boolean Private Sub optAllClients_Click() mbFilterChanged = True cboConsultant.Enabled = optClientsForConsultant.Value End Sub Private Sub optClientsForConsultant_Click() mbFilterChanged = True cboConsultant.Enabled = optClientsForConsultant.Value End Sub Private Sub cboConsultant_Change() mbFilterChanged = True End Sub 'When exiting the frame, check for updates to the filter Private Sub fraFilter_Exit(ByVal Cancel As _ MSForms.ReturnBoolean)

CheckFilterFrame End Sub 'When clicking outside the frame, 'check and close the filter panel Private Sub UserForm_MouseDown(ByVal Button As Integer, _ ByVal Shift As Integer, ByVal X As Single, _ ByVal Y As Single) CheckFilterFrame End Sub 'Handle clicking outside the frame, 'to check for updates and close the panel Private Sub CheckFilterFrame() 'If it's visible, update the list If fraFilter.Visible Then If mbFilterChanged Then ApplyFilter End If fraFilter.Visible = False End Sub 'Apply the changed filter options Private Sub ApplyFilter() 'Update the text of the filter dropdown If optAllClients Then cboFilter.List(0) = "All Clients" Else cboFilter.List(0) = "Clients for " & cboConsultant.Text End If 'Update the contents of the list box End Sub

The cust om drop- down pane is a st andard Fram e cont rol, init ially set t o be invisible and wit h a slight ly light er background color, cont aining t he cont rols used for our filt er. When t he user clicks t he com bo box's drop- down but t on, we use t he DropBut t onClick event t o init ialize a Boolean variable m bFilt erChanged ( used t o ident ify whet her changes are m ade wit hin t he fram e) , t hen m ake t he fram e visible and give it t he focus; t his m akes t he fram e appear t o " drop down" from t he com bo box. We include code in t he change event for all t he cont rols in t he fram e t o set t he Boolean variable t o True, indicat ing t hat t he fram e's cont ent has changed. The user can exit t he fram e by t abbing t o or clicking anot her cont rol ( causing t he Exit event t o fire) , or by clicking som ewhere else on t he userform ( which we det ect wit h t he Userform _MouseDown event ) . I n bot h cases, we call t he CheckFilt erFram e procedure t o hide t he fram e, check whet her any of t he cont rols were changed and apply t he new filt er. I n t his case, we're j ust updat ing t he t ext shown in t he com bo box t o show t he filt er set t ings. The com bo box st yle is set t o fm St yleDropDownList , so t hat clicking anywhere in t he com bo box will cause t he DropBut t onClick event t o fire. We have a single it em in t he com bo

box's list , wit h t he List I ndex t o zero t o show it in t he cont rol. To updat e t he t ext shown in t he com bo box, we change t he t ext of t hat it em .

Windows Common Controls There is an OCX file available on m ost com put ers called m scom ct l.ocx, usually found in t he C: \ w indow s\ syst em 32 folder t hat cont ains a set of cont rols collect ively known as t he Microsoft Windows Com m on Cont rols 6.0. Alt hough it t heoret ically m ight not exist , we have yet t o see a com put er wit h Office inst alled t hat doesn't have t his fileit is so widely used t hat anyt hing ot her t han a plain vanilla Windows inst allat ion will include t he file. I t cont ains t he following cont rols t hat can be used in our userform s. To access t hese cont rols, right - click t he cont rol t oolbox, select t he Addit ional Cont rols, m enu and put a t ick m ark beside each of t he cont rols you int end t o use: Microsoft I m ageCom boBox Cont rol 6.0 Microsoft I m ageList Cont rol 6.0 Microsoft List View Cont rol 6.0 Microsoft ProgressBar Cont rol 6.0 Microsoft Slider Cont rol 6.0 Microsoft St at usBar Cont rol 6.0 Microsoft TabSt rip Cont rol 6.0 Microsoft ToolBar Cont rol 6.0 Microsoft TreeView Cont rol 6.0 Microsoft UpDown Cont rol 6.0 Som e of t hese cont rols, such as t he TabSt rip and UpDown cont rols, are very sim ilar t o t he st andard MSForm s cont rols, but t he ot hers can be used t o im prove t he usabilit y of our form s. For exam ple, t he List View is sim ilar t o t he File pane of Windows Explorer, and enables us t o display a list of it em s wit h icons, giving us m any form at t ing possibilit ies for each it em in t he list . The List View's " report " st yle is very sim ilar in appearance t o t he norm al List cont rol, but enables us t o display each it em using a different font , color and so fort h. The TreeView cont rol is an excellent way t o display hierarchical dat a, and t he I m ageList and I m ageCom bo cont rols can be used where displaying t hum bnails m ay be m ore appropriat e t han t ext . To fully docum ent each of t he Windows Com m on Cont rols is beyond t he scope of t his book, but t he Com m onCont rols.xls exam ple workbook cont ains t he userform shown in Figure 10- 13, wit h fully com m ent ed code t o explain it s operat ion.

Figu r e 1 0 - 1 3 . Usin g t h e W in dow s Com m on Con t r ols

[View full size image]

The official docum ent at ion for t he Windows Com m on Cont rols can be found in t he MSDN library wit hin t he Visual Basic 6.0 sect ion. For exam ple, t he docum ent at ion for t he TreeView st art s at ht t p: / / m sdn.m icr osoft .com / libr ar y/ en- us/ cm ct l198/ ht m l/ vbobj Tr eeView .asp. The only issue t o be aware of when using t he Windows Com m on Cont rols on userform s is t hat t hey do not like t o be placed inside t he Mult iPage cont rol. Trying t o m odify a cont rol t hat is not on t he act ive page usually fails.

Drag and Drop The norm al MSForm s cont rols do not support drag- and- drop operat ions bet ween cont rols. I f we want t o im plem ent drag and drop bet ween cont rols on our form s ( such as being able t o drag an it em from one list box and drop it on anot her) , we have t o eit her use t he Windows Com m on Cont rols or use a Visual Basic form . The Com m onCont rols.xls workbook cont ains fully com m ent ed code t hat im plem ent s drag and drop bet ween t he List View and TreeView cont rols as well as wit hin t he TreeView cont rol t o change it s st ruct ure.

Practical Examples PETRAS Timesheet The PETRAS t im esheet add- in has not been changed for t his chapt er.

PETRAS Reporting At t his st age of t he PETRAS report ing applicat ion, it would be art ificial t o add a suit e of userform s j ust t o dem onst rat e t he t echniques discussed in t his chapt er. Therefore, t he only change m ade t o t he report ing applicat ion for t his chapt er is t o display a progress bar while consolidat ing all t he t im esheet workbooks. When we m odify t he applicat ion t o use a dat abase back end in Chapt er 13 Program m ing wit h Dat abases, we will add a set of userform s t o t he report ing applicat ion for t he user t o m aint ain t he st at ic list s of consult ant s, client s, proj ect s and so on. The code changes required t o add t he progress bar are det ailed in Table 10- 1 .

Ta ble 1 0 - 1 . Ch a n ge s t o t h e PETRAS Re por t in g Applica t ion for Ch a pt e r 1 0 M odu le FProgressBar ( new form ) MSyst em Code

Pr oce du r e

Ch a n g e Added t he FProgressBar form shown in Figure 1011

Consolidat eWor k book s Modified t o use t he FProgressBar form inst ead of writ ing t he progress t o t he st at us bar

Conclusion As program m ers, we t end t o t hink t hat our code is t he m ost im port ant part of an applicat ion and dism iss t he userform s as m ere eye candy. Our users, on t he ot her hand, don't see t he code, only t he int erface t hat we provide t hem . The userform s are t he m ost im port ant part of our applicat ion t o t he users, and t hey will like or dislike our applicat ions based prim arily on how well t he userform s are designed. For t his reason and m ore, userform design should be as m uch a priorit y as any ot her part of our applicat ion developm ent . Taking t he t im e t o design userform s t hat are easy t o use, easy t o m aint ain and t hat adapt t o t he user's environm ent can give our workbook t he polished appearance expect ed of a professionally developed applicat ion.

Chapter 11. Interfaces The previous few chapt ers have explained class m odules in som e dept h and t he various part s t hey can play in our applicat ionshandling event s, encapsulat ing funct ionalit y and creat ing our own obj ect m odels. We've seen t hat userform s and t he workbook and worksheet code m odules are j ust special t ypes of class m odule. This chapt er t akes a st ep furt her int o obj ect - orient ed design by explaining how one class can appear t o be m any different t ypes of obj ect and how m any different classes can appear t o be t he sam e t ype of obj ect . We show t hat by using t he t echniques explained in t his chapt er, we can im prove t he robust ness of our solut ion, sim plify t he developm ent experience and reduce t he am ount of code we need t o writ e. As an exam ple, we convert our cent ral consolidat ion and report ing applicat ion t o use a plug- in archit ect ure for it s userform s, enabling us t o ext end t he applicat ion wit hout having t o add any m ore code t o t he core rout ines.

What Is an Interface? An int erface is a list of public propert ies, m et hods, event s, user- defined- t ypes, const ant s and/ or enum erat ions t hat we can use t o int eract wit h an obj ect . When we dim ension a variable t o be a cert ain obj ect t ype, we're act ually specifying t he in t e r fa ce t hat t he variable will use t o t alk t o an obj ect . When we lat er m ake t he variable refer t o an obj ect , we're specifying which ob j e ct we want t o t alk t o, t hrough t hat int erface. When t he code is run, t he com piler checks t o see whet her t he obj ect has t he int erface we specified, and t hrows a Type Mism at ch error if it doesn't , as shown in List ing 11- 1.

List in g 1 1 - 1 . A Type M ism a t ch Er r or 'Declare a variable that will talk to objects through the 'Worksheet interface Dim wksInput As Worksheet 'Sheet1 in our workbook has the Worksheet interface, 'so we can talk to it Set wksInput = Sheet1 'The ThisWorkbook object doesn't have the Worksheet interface, 'so we get a Type Mismatch error. Set wksInput = ThisWorkbook

Whenever we creat e a class m odule, t he VBA com piler also creat es a default int erface for t hat class. The default int erface is given t he sam e nam e as t he class and cont ains a list of all t he public propert ies, m et hods et c. t hat we add t o t he class. When we dim ension a variable using Dim clsTheClass As CClassName, we're saying t hat t he variable will use t he in t e r fa ce CClassNam e. When we use code like Set clsTheClass = New CClassName, we're creat ing an obj ect t hat is a new inst ance of t he cla ss CClassNam e, t hen set t ing t he variable t o refer t o t he obj ect , as in List ing 11- 2 .

List in g 1 1 - 2 . Va r ia ble s, I n t e r fa ce s a n d Cla sse s 'Declare a variable to use the CClassName interface Dim clsTheClass As CClassName 'Create a new instance of the CClassName class 'and set our variable to refer to it Set clsTheClass = New CClassName

Th e code in t h e cla ss de fin e s h ow t h e obj e ct be h a ve s, w h e r e a s t h e in t e r fa ce de fin e s h ow w e a cce ss t h e code . By hiding t his im plem ent at ion det ail from us, VBA m akes it m uch easier for us t o work wit h class m oduleswe don't need t o care whet her we're dealing wit h a class or an int erface. Unfort unat ely, it also hides t he useful fact t hat we can define our own cust om int erfaces and m ix and m at ch classes and int erfaces if we want t o! The rest of t his chapt er exam ines a few ways t hat we can im prove our applicat ions by doing j ust t hat .

Code Reuse One of t he basic t enet s of good program m ing is t o writ e rout ines t hat can be reused as m uch as possible. For exam ple, a generic sort ing rout ine, such as t he sim ple bubble sort shown in List ing 11- 3 , can be used t o sort an array of any sim ple dat a t ype.

List in g 1 1 - 3 . A Ge n e r ic Bu bble Sor t 'A simple, generic, slow bubble sort, to sort a 1D array Sub Generic1DBubbleSort(ByRef vaArray As Variant) Dim bDoAgain As Boolean Dim vTemp As Variant Dim iIndex As Integer Do 'Assume we're done bDoAgain = False 'Loop through the array, comparing the names For iIndex = LBound(vaArray) To UBound(vaArray) - 1 'If we found some in the wrong order, ... If vaArray(iIndex) > vaArray(iIndex + 1) Then '... swap them ... vTemp = vaArray(iIndex) vaArray(iIndex) = vaArray(iIndex + 1) vaArray(iIndex + 1) = vTemp '... and remember to loop again. bDoAgain = True End If Next Loop While bDoAgain End Sub

Unfort unat ely, we can't use t his rout ine t o sort obj ect s, because t here is not hing in t he code t o say which propert y t o sort on; every t ype of obj ect would need a specific version of t he rout ine. Let 's assum e t hat we're writ ing an applicat ion for a publishing com pany t o m anage t he product ion of a book, we're using an obj ect - orient ed design and we have a CAut hor class and a CReviewer class

( am ong ot hers) . The CAut hor class m ight look som et hing like List ing 11- 4 ( but wit h m ore propert ies t han j ust t he nam e! ) .

List in g 1 1 - 4 . A CAu t h or Cla ss 'Name: 'Description:

CAuthor Class to represent a book's author

Option Explicit Dim msAuthName As String Public Property Let AuthorName(sNew As String) msAuthName = sNew End Property Public Property Get AuthorName() As String AuthorName = msAuthName End Property

At som e point in t he applicat ion, we have t he requirem ent t o produce a list of Aut hors, sort ed by t he aut hor's nam e. Because t his is a collect ion of obj ect s we're sort ing, we cannot j ust pass t hem t o a generic rout ine; we have t o use a specific rout ine for each obj ect t ype such as t hat shown in List ing 11- 5 t o sort a collect ion of Aut hors using t he Aut horNam e propert y.

List in g 1 1 - 5 . A Bu bble Sor t for t h e CAu t h or Cla ss 'A simple bubble sort, to sort a collection of CAuthor objects Sub BubbleSortAuthors(ByRef colAuthors As Collection) Dim Dim Dim Dim

bDoAgain As Boolean iIndex As Integer clsAuthorLow As CAuthor clsAuthorHigh As CAuthor

Do 'Assume we're done bDoAgain = False 'Loop through the collection, comparing the names For iIndex = 1 To colAuthors.Count - 1 'Get the Author objects from the collection at this point Set clsAuthorLow = colAuthors(iIndex) Set clsAuthorHigh = colAuthors(iIndex + 1)

'If we found some in the wrong order, ... If clsAuthorLow.AuthorName > clsAuthorHigh.AuthorName Then '... swap them ... colAuthors.Remove iIndex + 1 colAuthors.Add clsAuthorHigh, , iIndex '... and remember to loop again. bDoAgain = True End If Next Loop While bDoAgain End Sub

Sim ilarly, we m ight need specific rout ines t o sort collect ions of CReviewer, CEdit or, CDist ribut or and so fort h obj ect s. Wouldn't it be m uch bet t er if we could have a single rout ine t hat could sort collect ions of any of t hose obj ect s? I f we use a cust om int erface, we can!

Defining a Custom Interface I f we want t o creat e a generic sort rout ine t hat will work wit h any of our classes, we need t o be able t o t alk t o each class in t he sam e wayt hat is, t hrough t he sam e int erfaceby saying t o each one " I don't care what class you are, j ust give m e som et hing t o sort you by." To achieve t hat , we need t o give each of our classes a cust om int erface, t hrough which we can ask for t he it em t o sort wit h. Our cust om int erface will be called I Sort ableObj ect ( by convent ion, int erfaces st art wit h a capit al I ) and will have a single propert y called Sort Key. The generic obj ect sort ing rout ine can t hen use t hat int erface t o ask each obj ect for it s key, wit hout caring what t ype of class it is. As m ent ioned previously, whenever we creat e a class m odule, t he VBA com piler also creat es an int erface of t he sam e nam e, cont aining all t he public propert ies, m et hods and event s t hat we add t o t he class. All we need t o do t o define a cust om int erface, t hen, is t o creat e a new class m odule t hat cont ains t he propert ies and m et hods we want t o use, but doesn't have any code in t he rout ines. VBA will creat e t he int erface for us behind t he scenes, which we can t hen add t o our ot her classes. So we can define our I Sort ableObj ect int erface by adding a new class m odule, giving it t he nam e I Sort ableObj ect and a public Sort Key propert y, as shown in List ing 11- 6.

List in g 1 1 - 6 . A I Sor t a ble Obj e ct I n t e r fa ce Cla ss 'Name: 'Description: 'Author:

ISortableObject Class to define the ISortableObject interface Stephen Bullen

'Get the key to use in the generic sorting routine Public Property Get SortKey() As Variant End Property

That 's all t here is t o it . Not e t hat we've defined t he Sort Key propert y t o ret urn a Variant dat a t ype, so we can use t he sam e generic rout ine for ot her obj ect s t hat it m ay be m ore appropriat e t o sort by a num ber or dat e.

Implementing a Custom Interface Aft er we've defined our int erface, we have t o add it t o all t he classes t hat we want t o use it wit h. We do t his by adding t he I m plem ent s keyword at t he t op of t he class m odule:

Implements IsortableObject

Figure 11- 1 shows t hat as soon as we add t hat line t o t he class, t he int erface nam e appears in t he obj ect dropdown at t he t op- left of t he code pane, j ust like an obj ect on a userform .

Figu r e 1 1 - 1 . Th e I n t e r fa ce Appe a r s in t h e Obj e ct D r op- D ow n

When t he int erface nam e is select ed in t hat drop- down, t he right - hand drop- down list s t he m et hods and propert ies defined for t hat int erface, as shown in Figure 11- 2.

Figu r e 1 1 - 2 . W it h t h e I n t e r fa ce Se le ct e d, t h e Pr ope r t ie s a n d M e t h ods Appe a r in t h e Righ t - H a n d D r op- D ow n

Clicking one of t he m et hods adds an out line procedure t o t he code m odule, j ust as it does for a userform obj ect 's event . We j ust need t o add code t o t hat rout ine t o ret urn t he value t o use when sort ing t his t ype of obj ect . The com plet e, sort able CAut hor class is shown in List ing 11- 7, where t he code t o im plem ent t he I Sort ableObj ect int erface has been highlight ed.

List in g 1 1 - 7 . Th e Sor t a ble CAu t h or Cla ss 'Name: 'Description:

CAuthor Class to represent a book's author

'Allow this type of object to be sortable 'by the generic routine Implements ISortableObject Dim msAuthName As String Public Property Let AuthorName(sNew As String) msAuthName = sNew End Property Public Property Get AuthorName() As String AuthorName = msAuthName End Property 'Return the value to be used when sorting this object Private Property Get ISortableObject_SortKey() As Variant ISortableObject_SortKey = AuthorName End Property

Not e t hat t he nam e of t he I Sort ableObj ect _Sort Key rout ine is t he concat enat ion of t he int erface nam e and t he propert y nam e and t hat it is a Privat e propert y of t he CAut hor class, so won't appear on t he CAut hor int erface.

Using a Custom Interface Wit h t he cust om I Sort ableObj ect int erface defined and im plem ent ed in our CAut hor class, we can m odify our BubbleSort Aut hors rout ine t o be able t o sort collect ions of any class t hat im plem ent s our I Sort ableObj ect int erface, shown in List ing 11- 8. All we need t o do is t o define our dat a t ypes As I Sort ableObj ect inst ead of As CAut hor, use t he Sort Key propert y inst ead of Aut horNam e and change t he variable nam es t o be m ore generic.

List in g 1 1 - 8 . A Bu bble Sor t for Cla sse s Th a t I m ple m e n t I Sor t a ble Obj e ct 'A simple bubble sort, to sort a collection of objects 'that implement ISortableObject Sub BubbleSortSortableObjects(ByRef colSortable As Collection) Dim Dim Dim Dim

bDoAgain As Boolean iIndex As Integer clsSortable1 As ISortableObject clsSortable2 As ISortableObject

Do 'Assume we're done bDoAgain = False 'Loop through the collection, comparing the names For iIndex = 1 To colSortable.Count - 1 'Get the objects from the collection at this point Set clsSortable1 = colSortable(iIndex) Set clsSortable2 = colSortable(iIndex + 1) 'If we found some in the wrong order, ... If clsSortable1.SortKey > clsSortable2.SortKey Then '... swap them ... colSortable.Remove iIndex + 1 colSortable.Add clsSortable2, , iIndex '... and remember to loop again. bDoAgain = True End If Next Loop While bDoAgain End Sub

We can t hen use t his rout ine wit h any t ype of obj ect t hat im plem ent s t he I Sort ableObj ect int erface, as shown in List ing 11- 9. This t echnique assum es t hat t he values provided by each obj ect 's I Sort ableObj ect _Sort Key propert y can be used wit hin a " great er t han" com parison.

List in g 1 1 - 9 . Usin g t h e Ge n e r ic Sor t in g Rou t in e for a Colle ct ion of CAu t h or s Sub AuthorSortExample() Dim vItem As Variant Dim colAuthors As Collection Dim clsAuthor As CAuthor Set colAuthors = New Collection 'Populate the Authors collection For Each vItem In Array("Stephen Bullen", "Rob Bovey", _ "John Green") Set clsAuthor = New CAuthor clsAuthor.AuthorName = CStr(vItem) colAuthors.Add clsAuthor Next 'Sort the Authors using the generic routine BubbleSortSortableObjects colAuthors 'Show the sorted list For Each clsAuthor In colAuthors Debug.Print clsAuthor.AuthorName Next End Sub

That was a very quick int roduct ion t o cust om int erfaces, so let 's recap what we've achieved and why we're doing it . When we creat e nont rivial obj ect m odels, we oft en end up wit h m ult iple obj ect t ypes ( t hat is, classes) t hat have a lot of propert ies in com m on, but som e significant differences. We also oft en need t o process m any of t hose obj ect t ypes in sim ilar ways ( such as sort ing t hem ) . We could do t his using a variable declared As Obj ect and hope t hat all our classes use t he sam e nam es for t heir com m on propert ies, but t hat is neit her robust nor efficient . I nst ead, we can define a cust om int erface which cont ains t he propert ies and m et hods t hat are com m on t o our obj ect s and add code t o each class t o im plem ent t he int erface. Our processes can t hen com m unicat e wit h any of t hose obj ect t ypes t hrough t he cust om int erface, m aking our code m uch m ore robust , efficient , m aint ainable and reusable.

Polymorphic Classes The abilit y of a class t o appear t o be m any different t ypes of obj ect is called poly m or ph ism and is som et hing t hat m any of t he classes in Excel's obj ect m odel use. For exam ple, we can access t he different aspect s of t he various m enu it em t ypes using t heir det ailed int erfacesCom m andBarPopUp, Com m andBarBut t on, Com m andBarCom boBox and so onor it erat e t hrough t hem all using t he m ore generic set of propert ies t hat t hey expose t hrough t he Com m andBarCont rol int erface. We can m ake our own classes polym orphic by sim ply defining and im plem ent ing m ult iple cust om int erfaces, in t he sam e way t hat we added t he I Sort ableObj ect int erface. For exam ple, anot her requirem ent for our fict ional book- publishing applicat ion m ight be t o generat e a let t er for everyone involved in t he book's product ion. I deally we would like t o be able t o put all t he CAut hor, CReviewer, CEdit or and CDist ribut or obj ect s int o a single collect ion, sort t he collect ion and t hen loop t hrough it t o generat e t he let t ers. Adding all t he obj ect s int o one collect ion is not a problem t he Collect ion obj ect can handle m ixed obj ect t ypes. Assum ing all t hose classes have im plem ent ed our I Sort ableObj ect int erface, sort ing t he collect ion is not an issue eit herour generic sort ing rout ine doesn't care what t ype of obj ect it 's looking at , so long as it im plem ent s t he int erface. The problem com es when we want t o generat e t he let t ershow do we it erat e t hrough t he collect ion of m ixed obj ect t ypes t o get t he cont act det ails? The answer, of course, is t o add anot her cust om int erface t o t hose classes, t hrough which we can access t he cont act det ails and ot her propert ies t hat are com m on t o all t he obj ect s ( assum ing we've ext ended t he earlier CAut hor class t o include t hose det ails) . We m ight choose t o call it t he I Cont act Det ails int erface, shown in List ing 11- 10, and include t he nam e, post al address and so fort h.

List in g 1 1 - 1 0 . Th e I Con t a ct D e t a ils I n t e r fa ce Cla ss 'Name: 'Description: 'Author:

IContactDetails Class to define the IContactDetails interface Stephen Bullen

'Get/set the name Public Property Get Name() As String End Property Public Property Let Name(sNew As String) End Property 'Get/set the postal address Public Property Get Address() As String End Property Public Property Let Address(sNew As String) End Property

The ext ended CAut hor, CReviewer, CEdit or and CDist ribut or classes can im plem ent t hat int erface, result ing in t he CAut hor class looking like List ing 11- 11, where t he ext ra code t o im plem ent t he I Cont act Det ails int erface has been highlight ed.

List in g 1 1 - 1 1 . Th e CAu t h or Cla ss I m ple m e n t in g t h e I Con t a ct D e t a ils I n t e r fa ce 'Name: 'Description:

CAuthor Class to represent a book's author

'Allow this type of object to be sortable 'by the generic routine Implements ISortableObject 'Provide access through the IContactDetails interface Implements IContactDetails Dim msAuthName As String Dim msAddress As String 'Set/get the Author name Public Property Let AuthorName(sNew As String) msAuthName = sNew End Property Public Property Get AuthorName() As String AuthorName = msAuthName End Property 'Set/Get the address Public Property Let Address(sNew As String) msAddress = sNew End Property Public Property Get Address() As String Address = msAddress End Property 'Implement the ISortableObject class Private Property Get ISortableObject_SortKey() As Variant ISortableObject_SortKey = AuthorName End Property 'Implement the IContactDetails interface, 'by calling through to the default interface's properties Private Property Let IContactDetails_Name(RHS As String) Me.AuthorName = RHS

End Property Private Property Get IContactDetails_Name() As String IContactDetails_Name = Me.AuthorName End Property Private Property Let IContactDetails_Address(RHS As String) Me.Address = RHS End Property Private Property Get IContactDetails_Address() As String IContactDetails_Address = Me.Address End Property

When using t he int erface and procedure nam e drop- downs t o add t he Propert y Let procedures, t he VB edit or always uses RHS as t he variable nam e for t he new propert y value ( because t hat represent s t he " right - hand side" of t he propert y assignm ent expression) . I f t he code will be doing anyt hing ot her t han j ust passing t he value on t o anot her procedure, it is a very good idea t o give t he variable a m ore m eaningful nam e, in line wit h t he best pract ices on nam ing convent ions explained in Chapt er 3 Excel and VBA Developm ent Best Pract ices. Aft er we've added t he int erface t o all our classes, we can add t he classes t o a single collect ion, sort t he collect ion using t he I Sort ableObj ect int erface and it erat e t hrough it using t he I Cont act Det ails int erface, shown in List ing 11- 12. The ShowDet ails procedure processes t he cont act det ails for each obj ect in t he collect ion, again using t he I Cont act Det ails int erface, and is explained lat er.

List in g 1 1 - 1 2 . Sor t in g a n d List in g M ix e d Cla sse s Th a t I m ple m e n t I Sor t a ble Obj e ct a n d I Con t a ct D e t a ils Sub

CombinedIterateExample()

Dim Dim Dim Dim Dim

vItem As Variant colMailList As Collection clsAuthor As CAuthor clsReviewer As CReviewer clsDetails As IContactDetails

Set colMailList = New Collection 'Add the Authors to the collection For Each vItem In Array("Stephen Bullen", "Rob Bovey", _ "John Green") Set clsAuthor = New CAuthor clsAuthor.AuthorName = CStr(vItem) colMailList.Add clsAuthor Next

'Add some Reviewers to the collection For Each vItem In Array("Dick Kusleika", _ "Beth Melton", "Shauna Kelly", "Jon Peltier") Set clsReviewer = New CReviewer clsReviewer.ReviewerName = CStr(vItem) colMailList.Add clsReviewer Next 'Sort the Mailing list using the generic routine BubbleSortSortableObjects colMailList 'Although colMailList is a collection of mixed object types, 'they all implement the IContactDetails interface, so we can 'process them all by using an object variable declared 'As IContactDetails For Each clsDetails In colMailList ShowDetails clsDetails Next End Sub

We can use t he TypeOf funct ion t o t est whet her a class im plem ent s a cert ain int erface and swit ch bet ween int erfaces by declaring a variable as t he t ype of int erface we want t o look t hrough, t hen set t ing it t o refer t o t he obj ect , as shown in List ing 11- 13. Regardless of which int erface we're looking t hrough, t he VB TypeNam e( ) funct ion will always ret urn t he obj ect 's class nam e.

List in g 1 1 - 1 3 . Ch e ck in g a n Obj e ct 's I n t e r fa ce s 'Show the details of any given object Sub ShowDetails(objUnknown As Object) 'Two variables that we can use to look at the object 'through two different interfaces Dim clsAuthor As CAuthor Dim clsDetails As IContactDetails 'Check if this object has the full CAuthor interface If TypeOf objUnknown Is CAuthor Then 'Yes, so look at the object through the CAuthor interface Set clsAuthor = objUnknown 'Write a special message for the authors Debug.Print clsAuthor.AuthorName & " wrote the book" 'Does the object implement the IContactDetails interface?

ElseIf TypeOf objUnknown Is IContactDetails Then 'Yes, so look at it through that interface Set clsDetails = objUnknown 'And write a message for everyone that helped Debug.Print clsDetails.Name & " helped with the book" Else 'An object we can't use, so write the class name Debug.Print "Unknown Object: " & TypeName(objUnknown) End If End Sub

Improving Robustness The abilit y t o it erat e t hrough a collect ion of different obj ect t ypes could be achieved wit hout using a cust om int erface, by declaring t he variable As Obj ect and ensuring t hat all t he classes we want t o access have t he sam e propert ies and m et hods. However, t hat m akes t he obj ect lat e bound, so it 's slower, doesn't show any I nt elliSense, coding errors aren't caught unt il runt im e and it relies on all t he classes using t he sam e nam es for t heir propert ies. Had we t ried t o im plem ent t he preceding funct ionalit y using a generic Obj ect t ype, we would have had a few issues t o resolve: Having st art ed wit h CAut hor.Aut horNam e and CReviewer. ReviewerNam e, we would have had t o add a com m on .Nam e propert y t o bot h, result ing in t wo propert ies t hat do t he sam e t hing. Alt ernat ively, we could have checked t he rest of t he applicat ion and changed Aut horNam e and ReviewerNam e t o Nam e wherever it was used. We would have t o expose a ll t he propert ies of t he class on it s ( single) default int erface, including t hose such as t he Sort Key propert y t hat are only used for specific " int ernal" funct ionalit y. I f we design our applicat ion t o use t he generic Obj ect t ype inst ead of cust om int erfaces t o it erat e t hrough m ixed obj ect t ypes, we rely on an im plicit agreem ent t hat our obj ect s will have t he correct propert y nam es and any errors due t o m issing, renam ed or sim ply m ist yped propert ies won't be found unt il run t im e. Taking t he ext ra st ep t o define and use a cust om int erface gives us all t he benefit s of early binding ( speed, I nt elliSense and com pile- t im e t ype checking) as well as e x plicit ly st at ing how t he classes and t heir consum ers int eract , which can only help t o im prove t he robust ness of our applicat ions.

Simplifying Development One of t he m ost used t im e- saving t ools in t he Visual Basic Edit or is t he I nt elliSense popup t hat appears aft er t yping a period ( .) aft er an obj ect . This popup list s all t he m et hods and propert ies t hat are defined in t he int erface for t hat t ype of obj ect . Unfort unat ely, when we t ry t o set propert ies or call m et hods in a worksheet or userform class, t he I nt elliSense list cont ains so m any it em s t hat it 's hard t o find t he propert ies and m et hods t hat we need t o use. I f we follow t he recom m endat ions for encapsulat ing our code, for exam ple, we shouldn't be set t ing any of a userform 's propert ies from out side t he form ; we should inst ead be exposing t he form 's funct ionalit y t hrough our own propert ies and m et hods. When viewing t he I nt elliSense popup for a userform , it shows our propert ies and m et hods m ixed in wit h t hose of t he form . Defining and using our own int erface for t he form enables us t o rest rict t he list of propert ies and m et hods t o only t hose t hat we choose t o expose.

A Progress Bar Many applicat ions include som e form of progress indicat ion t o show t he st at us of lengt hy rout ines. I t 's likely t hat such an indicat ion will be used in m ult iple places in our applicat ion and it m akes sense t o im plem ent it as a com m on funct ion t hat can be called from all our rout ines. I f we have an obj ect - orient ed design, we would ideally like t o t reat it j ust like any ot her obj ect , using som et hing like t he code in List ing 11- 14.

List in g 1 1 - 1 4 . Usin g a Pr ogr e ssBa r Cla ss Sub LongRoutine() Dim pbProgBar As ProgressBar Dim iCounter As Integer Set pbProgBar = New ProgressBar pbProgBar.Title = "Professional Excel Development" pbProgBar.Text = "Preparing report, please wait..." pbProgBar.Min = 0 pbProgBar.Max = 1000 pbProgBar.Progress = 0 pbProgBar.Show For iCounter = 0 To 1000 pbProgBar.Progress = iCounter Next pbProgBar.Hide

End Sub

There is not hing in t his code t o suggest t hat t he progress indicat ion is a userform . The code is only saying t hat we want t o display som e t ype of progress indicat ion t o t he user; t he way in which it 's present ed is ent irely encapsulat ed wit hin t he ProgressBar class and could j ust as easily be a userform , a m essage in t he st at us bar or an audible prom pt . To help ot her developers t hat m ight use t he ProgressBar class, it would be ideal if t he I nt elliSense list only showed t he seven propert ies and m et hods ( Tit le, Text , Min, Max, Progress, Show and Hide) t hat we should be using t o cont rol t he progress bar. Unfort unat ely, if t he ProgressBar was a userform class, t he I nt elliSense list would show our 7 it em s lost am ong t he ot her 57 propert ies and m et hods of userform s. As well as m aking it harder t o pick out t he correct propert ies and m et hods t o use, exposing t he norm al userform propert ies m akes it t em pt ing for t he consum er of t he progress bar class t o set som e of t he ot her propert ies of t he form . At worst , t hat could break t he way in which t he progress bar works, or m ake t he progress bar appear different ly in different part s of t he applicat ion. At best , it would m ake it m uch harder for us t o m odify t he im plem ent at ion of t he progress bar it self; our new im plem ent at ion m ay break t he nonst andard way in which t he progress bar class has been used, so we would have t o check ( and t est ) everywhere t hat it 's referred t o. By using a cust om int erface, we can gu a r a n t e e t hat all users of t he progress bar class are only able t o use t he propert ies and m et hods t hat we define in t hat int erface. Doing so rem oves t he t em pt at ion t o use t he norm al userform propert ies and m akes it im possible for consum ers of t he class t o use t he progress bar form in non- st andard ways. This enables us t o t ot ally separat e t he im ple m e n t a t ion of t he progress indicat ion from t he u se of t he progress indicat ion; as long as we keep t he sam e int erface, we can im plem ent it as a userform or as a sim ple class m odule t hat j ust updat es t he st at us bar.

The IProgressBar Interface As before, we define t he int erface t o use for our progress bar form by creat ing a new class m odule, giving it t he nam e I ProgressBar and adding em pt y rout ines for each of t he elem ent s on t he int erface, as shown in List ing 11- 15.

List in g 1 1 - 1 5 . Th e I Pr ogr e ssBa r I n t e r fa ce Cla ss 'Set and get the title Public Property Let Title(sNew As String) End Property Public Property Get Title() As String End Property 'Set and get the descriptive text

Public Property Let Text(sNew As String) End Property Public Property Get Text() As String End Property 'Set and get the minimum value for the bar Public Property Let Min(dNew As Double) End Property Public Property Get Min() As Double End Property 'Set and get the maximum value for the bar Public Property Let Max(dNew As Double) End Property Public Property Get Max() As Double End Property 'Set and get the progress point Public Property Let Progress(dNew As Double) End Property Public Property Get Progress() As Double End Property 'Show the progress bar Public Sub Show() End Sub 'Hide the progress bar Public Sub Hide() End Sub

The FProgressBar Form The FProgressBar form im plem ent s t he I ProgressBar int erface by displaying t he progress indicat ion on a userform . The progress bar is m ade up of t wo superim posed fram es, each cont aining a label. The back fram e and label is blue- on- whit e, and t he front fram e and label is whit e- on- blue. The progress m easure cont rols t he widt h of t he front fram e, t o give t he appearance of t he progress bar shown in Figure 11- 3.

Figu r e 1 1 - 3 . A Sim ple Pr ogr e ss Ba r For m

The com plet e FProgressBar form can be found on t he CD, in t he workbook \ Concept s\ Ch11I nt erfaces\ Progress Bars.xls, but is reproduced in a sim ple form in List ing 11- 16.

List in g 1 1 - 1 6 . Th e FPr ogr e ssBa r For m M odu le I m ple m e n t in g t h e I Pr ogr e ssBa r I n t e r fa ce ' ' Name: ' Description: ' Author:

FProgressBar Displays a modeless progress bar on the screen Stephen Bullen

Option Explicit ' Implement the IProgressBar interface Implements IProgressBar ' Store the Min, Max and Progress values in module variables Dim mdMin As Double Dim mdMax As Double Dim mdProgress As Double Dim mdLastPerc As Double ' Initialize the form to show blank text Private Sub UserForm_Initialize() lblMessage.Caption = "" Me.Caption = "" End Sub 'Ignore clicking the [x] on the dialog Private Sub UserForm_QueryClose(Cancel As Integer, _ CloseMode As Integer) If CloseMode = vbFormControlMenu Then Cancel = True End Sub ' Let the calling routine set/get the caption of the form Private Property Let IProgressBar_Title(RHS As String) Me.Caption = RHS End Property

Private Property Get IProgressBar_Title() As String IProgressBar_Title = Me.Caption End Property ' Let the calling routine set/get the descriptive text Private Property Let IProgressBar_Text(RHS As String) If RHS lblMessage.Caption Then lblMessage.Caption = RHS End If End Property Private Property Get IProgressBar_Text() As String IProgressBar_Text = lblMessage.Caption End Property ' Let the calling routine set/get the Minimum scale Private Property Let IProgressBar_Min(RHS As Double) mdMin = RHS End Property Private Property Get IProgressBar_Min() As Double IProgressBar_Min = mdMin End Property ' Let the calling routine set the Maximum scale Private Property Let IProgressBar_Max(RHS As Double) mdMax = RHS End Property Private Property Get IProgressBar_Max() As Double IProgressBar_Max = mdMax End Property

' Let the calling routine set the progress amount. ' Update the form to show the progress. Private Property Let IProgressBar_Progress(RHS As Double) Dim dPerc As Double mdProgress = RHS 'Calculate the progress percentage If mdMax = mdMin Then dPerc = 0 Else dPerc = Abs((RHS - mdMin) / (mdMax - mdMin)) End If 'Only update the form every 0.5% change

If Abs(dPerc - mdLastPerc) > 0.005 Then mdLastPerc = dPerc 'Set the width of the inside frame, 'rounding to the pixel fraInside.Width = Int(lblBack.Width * dPerc / _ 0.75 + 1) * 0.75 'Set the captions for the blue-on-white and 'white-on-blue text lblBack.Caption = Format(dPerc, "0%") lblFront.Caption = Format(dPerc, "0%") 'Refresh the form if it's being shown If Me.Visible Then Me.Repaint End If End If End Property Private Property Get IProgressBar_Progress() As Double IProgressBar_Progress = mdProgress End Property

'Show the form modelessly Private Sub IProgressBar_Show() Me.Show vbModeless End Sub 'Hide the form Private Sub IProgressBar_Hide() Me.Hide End Sub

The only differences bet ween t his code and t he " plain" Progress Bar form we saw in Chapt er 10 Userform Design and Best Pract ices are t hat t he Tit le, Text , Min, Max and Progress propert ies have been exposed via t he I ProgressBar int erface and we've added our own Show and Hide m et hods t o show and hide t he form using t hat int erface. The difference bet ween t he I nt elliSense displays when using our cust om I ProgressBar int erface inst ead of t he form 's default int erface can be seen in Figure 11- 4 and Figure 11- 5. By im plem ent ing t he int erface, t he consum er of our progress bar form has a m uch clearer display of t he propert ies and m et hods t hat should be used t o cont rol t he progress bar. Figure 11- 4 shows t he I nt elliSense popup we get if we add t he progress bar propert ies direct ly t o t he form , and Figure 11- 5 shows t he m uch sim pler I nt elliSense list we get when using t he cust om int erface.

Figu r e 1 1 - 4 . Usin g t h e For m 's D e fa u lt I n t e r fa ce Sh ow s All t h e Use r for m 's

Pr ope r t ie s in t h e I n t e lliSe n se List , Obscu r in g t h e On e s for t h e Pr ogr e ss Ba r I t se lf

Figu r e 1 1 - 5 . Usin g t h e Cu st om I Pr ogr e ssBa r I n t e r fa ce Lim it s t h e I n t e lli Se n se List t o On ly t h e I t e m s W e W a n t t o Ex pose , Sim plifyin g t h e Use of t h e For m

The CProgressBar Class Aft er we know t hat t he consum er of our progress bar is accessing it t hrough our cust om int erface, we are free t o m odify t he im plem ent at ion of t he progress indicat ion in any way we like. As long as we keep t he int erface t he sam e, we k n ow t he code t hat uses t he class will cont inue t o work. The opposit e is also t rue; as consum ers of t he class, we k n ow as long as t he int erface is kept t he sam e, t he creat or of t he class cannot change t he nam e of any of t he propert ies or m et hods and in doing so break our code. By way of exam ple, t he code in List ing 11- 17 im plem ent s t he int erface using a class m odule inst ead of a userform and displays t he progress on Excel's st at us bar.

List in g 1 1 - 1 7 . Th e CPr ogr e ssBa r Cla ss I m ple m e n t in g t h e I Pr ogr e ssBa r I n t e r fa ce ' ' ' '

Class to show a progress indication in the status bar. Implements to IProgressBar interface to allow easy switching between showing the progress on the status bar (this class) or on a userform (the FProgressBar form).

Option Explicit 'Implement the IProgressBar interface

Implements IProgressBar 'Module-level variables to store the property values Dim msTitle As String Dim msText As String Dim mdMin As Double Dim mdMax As Double Dim mdProgress As Double Dim mbShowing As Boolean Dim msLastCaption As String

'Assume Private mdMin mdMax End Sub

an initial progress of 0-100 Sub Class_Initialize() = 0 = 100

'Set and get the title Private Property Let IProgressBar_Title(RHS As String) msTitle = RHS If mbShowing Then UpdateStatusBar End Property Private Property Get IProgressBar_Title() As String IProgressBar_Title = msTitle End Property

'Set and get the descriptive text Private Property Let IProgressBar_Text(RHS As String) msText = RHS If mbShowing Then UpdateStatusBar End Property Private Property Get IProgressBar_Text() As String IProgressBar_Text = msText End Property

'Set and get the minimum value for the bar Private Property Let IProgressBar_Min(RHS As Double) mdMin = RHS If mbShowing Then UpdateStatusBar End Property Private Property Get IProgressBar_Min() As Double IProgressBar_Min = mdMin End Property

'Set and get the maximum value for the bar Private Property Let IProgressBar_Max(RHS As Double) mdMax = RHS If mbShowing Then UpdateStatusBar End Property Private Property Get IProgressBar_Max() As Double IProgressBar_Max = mdMax End Property

'Set and get the progress point Private Property Let IProgressBar_Progress(RHS As Double) mdProgress = RHS If mbShowing Then UpdateStatusBar End Property Private Property Get IProgressBar_Progress() As Double IProgressBar_Progress = msprogress End Property

'Show the progress bar Private Sub IProgressBar_Show() mbShowing = True mdLastProgress = 0 UpdateStatusBar End Sub

'Hide the progress bar Private Sub IProgressBar_Hide() Application.StatusBar = False mbShowing = False End Sub

'Private routine to show the progress indication 'on the status bar Private Sub UpdateStatusBar() Dim dPerc As Double Dim sCaption As String 'Calculate the progress percentage If mdMax = mdMin Then dPerc = 0 Else dPerc = Abs((mdProgress - mdMin) / (mdMax - mdMin)) End If 'Create the caption

If Len(msTitle) > 0 Then sCaption = msTitle If Len(msTitle) > 0 And Len(msText) > 0 Then sCaption = sCaption & ": " End If If Len(msText) > 0 Then sCaption = sCaption & msText 'Calculate and add the formatted percentage sCaption = sCaption & " (" & Format$(dPerc, "0%") & ")" 'Update the status bar if it's changed If sCaption msLastCaption Then msLastCaption = sCaption Application.StatusBar = sCaption End If End Sub

The calling code can very easily swit ch bet ween using eit her t he form or t he st at us bar for t he progress display ( perhaps according t o a user's preference) , as shown in List ing 11- 18.

List in g 1 1 - 1 8 . Usin g t h e I Pr ogr e ssBa r I n t e r fa ce Allow s t h e Ch oice Be t w e e n t h e For m a n d t h e Cla ss Sub LongRoutine(bProgressInForm As Boolean) 'Always use the IProgressBar interface Dim pbProgBar As IProgressBar Dim iCounter As Integer If bProgressInForm Then 'Use the progress bar form Set pbProgBar = New FProgressBar Else 'Use the status bar class Set pbProgBar = New CProgressBar End If 'The rest of the code is unchanged pbProgBar.Title = "Professional Excel Development" pbProgBar.Text = "Preparing report, please wait..." pbProgBar.Min = 0 pbProgBar.Max = 1000 pbProgBar.Progress = 0 pbProgBar.Show

For iCounter = 0 To 1000 pbProgBar.Progress = iCounter Next pbProgBar.Hide End Sub

A Plug-in Architecture You saw in Chapt er 10 Userform Design and Best Pract ices how it was possible t o creat e a user int erface consist ing of m odeless userform s, in which t he int eract ion wit h t he user occurs wit hin userform s ( as opposed t o worksheet s) , yet wit h t he com m and bars st ill usable. To allow t he form s t o respond t o m enu bar clicks ( such as saving, m oving t o anot her form or closing t he applicat ion) , we had t o ensure t hat all our form s had t he sam e basic set of rout ines, t hat could be called by our com m on m enu handler. Those rout ines were called BeforeNavigat e, BeforeSave, Aft erSave and AppExit . We had in fact creat ed our own im plicit int erface, wit hout knowing it . By m aking t hat int erface explicit , we can im prove robust ness and reliabilit y and sim plify t he developm ent of t he applicat ion. We'll call t his int erface I PlugI nForm and define it as shown in List ing 11- 19, where we've also added a Show m et hod, t o be able t o show t he form t hrough t his int erface.

List in g 1 1 - 1 9 . Th e I Plu gI n For m I n t e r fa ce Cla ss 'Name: 'Description: 'Author:

IPlugInForm Interface to be implemented by each form Stephen Bullen

'The form's name Public Property Get Name() As String End Property 'Show the form Public Sub Show(Optional ByVal Style As _ FormShowConstants = vbModal) End Sub 'The user clicked a menu item to navigate to a different form 'Save any changes on the form and unload Public Sub BeforeNavigate(ByRef bCancel As Boolean) End Sub 'The user clicked the Save button 'Save any changes on the form and unload Public Sub BeforeSave(ByVal bSaveAs As Boolean, _ ByRef bCancel As Boolean) End Sub 'After the save completed 'Update the form with any new information Public Sub AfterSave(ByVal bSaveAs As Boolean) End Sub

'The user clicked the Close button to exit the application 'Tidy up and unload the form Public Sub AppExit() End Sub

I f all of our form s im plem ent t his int erface, t he cent ral cont rol rout ine shown in List ing 10- 26 in Chapt er 10 Userform Design and Best Pract ices can declare t he gfrm Act iveForm variable As I PlugI nForm inst ead of As Obj ect and call t he sam e m et hods as before. Using t he int erface enables us t o be explicit about what t he code is doing, prevent s t yping errors, ensures none of our com m on rout ines are " accident ally" delet ed from t he form s and helps enforce a com m on st ruct ure t hroughout t he applicat ion.

Practical Example The PETRAS applicat ion files for t his chapt er can be found on t he CD in t he folder \ Applicat ion\ Ch11I nt erfaces and include t he following files: Pe t r a sTe m pla t e .x lt The t im esheet t em plat e Pe t r a sAddin .x la The t im esheet dat a- ent ry support add- in Pe t r a sRe por t in g.x la The m ain report ing applicat ion Pe t r a sCon solida t ion .x lt A t em plat e t o use for new result s workbooks D e bu g.in i A dum m y file t hat t ells t he applicat ion t o run in debug m ode Pe t r a sI con .ico An icon file, t o use for Excel's m ain window

PETRAS Timesheet The PETRAS t im esheet add- in has not been updat ed for t his chapt er.

PETRAS Reporting At t his st age in t he developm ent of t he applicat ion, it would be art ificial t o add a suit e of userform s, j ust so we could dem onst rat e t he im plem ent at ion of a plug- in archit ect ure. However, such a suit e of form s will be added t o t he applicat ion in Chapt er 13 Program m ing wit h Dat abases for m aint enance of t he st at ic list s of Consult ant s, Client s, Proj ect s and so fort h. For t his chapt er, we will m odify t he progress bar handling t o display t he consolidat ion progress unobt rusively in t he st at us bar if we're consolidat ing fewer t han t en t im esheet workbooks, but pop up a cancelable progress bar userform if consolidat ing t en or m ore t im esheet s. As such, we'll be including t he I ProgressBar int erface from List ing 11- 15, t he FProgressBar form from List ing 11- 16 and t he CProgressBar class from List ing 11- 17. I n t his exam ple, t he form has an ext ra Cancel but t on and t he int erface has been enhanced t o add a Cancelled propert y, set t o True when t he Cancel but t on is clicked. The code changes required for t his enhancem ent are det ailed in Table 111.

Ta ble 1 1 - 1 . Ch a n ge s t o t h e PETRAS Re por t in g Applica t ion for Ch a pt e r 1 1

M odu le

Pr oce du r e

Ch a n g e

I ProgressBar ( new class)

Added class t o define t he I ProgressBar int erface, copied from List ing 11- 15, adding Cancelable propert y.

CProgressBar ( new class)

Added class t o show t he progress in t he st at us bar, copied from List ing 11- 17.

FPr ogr essBar

Moved various m et hods t o be exposed t hrough t he I ProgressBar int erface inst ead of t he default int erface. The result ing code is sim ilar t o List ing 11- 16.

MSyst em Code

Consolidat eWor k book s Modified t o use t he I ProgressBar int erface and t est whet her t o use t he CProgressBar class or FProgressBar form .

Conclusion Whenever we creat e a class m odule in VBA, t he com piler creat es bot h t he class and a default int erface for it . The code in t he class defines how t he obj ect behaves, and t he int erface defines how we access t he code. Wit h a sm all am ount of effort , we can define our own cust om int erfaces and im plem ent t hem in our classes, enabling us t o t reat different classes as if t hey were t he sam e t ype of obj ect . When developing userform s, we can use a cust om int erface t o expose only t he propert ies and m et hods t hat apply t o t he funct ionalit y we're providing, wit hout clut t ering t he I nt elliSense list wit h all t he basic userform 's propert ies. By doing t his, we can m ake our code m ore generic, m ore robust , m ore reliable, easier t o writ e and easier t o m aint ain. By im plem ent ing a st andard cust om int erface in all our form s, report s and processes, we can design an applicat ion archit ect ure t hat is t ot ally ext ensible, wit hout requiring any changes t o t he core applicat ion. I f working in a m ult ideveloper t eam , t his int erface can be ext ended across workbooks, allowing each developer t o work independent ly on t he applicat ion's funct ions, safe in t he knowledge t hat his work will not direct ly im pede any of t he ot her developers.

Chapter 12. VBA Error Handling Error handling is one of t he m ost com m only om it t ed feat ures in Excel applicat ions. This is not an accept able st at e of affairs. The last t hing you want your users t o see is an unvarnished Excel or VBA runt im e error. They will m ost surely not underst and what t hey are seeing and t hey will oft en panic, lose fait h in your applicat ion, or bot h. A good error handling syst em will not prevent errors from occurring, but it will m ake t he process m uch less dist ressing for your users and m uch easier for you t o diagnose and correct . All t he errors discussed in t his chapt er are runt im e errors. These are errors t hat occur while your code is execut ing. The ot her t ype of error, t he com pile- t im e error, should not be a fact or at t his point . A good developer will have ensured his proj ect cleanly passes a Debug > Com pile in t he VBE before at t em pt ing t o execut e it .

Error-Handling Concepts Unhandled vs. Handled Errors Runt im e errors fall int o t wo broad cat egories: u n h a n dle d e r r or s and h a n dle d e r r or s. Sim ply put , an unhandled error is one t hat is not caught by an error handling m echanism in t he procedure where it occurs, whereas a handled error is caught by such an error handler. This is not t o im ply t hat all unhandled errors are bad. I n som e sit uat ions, you can reasonably choose not t o handle errors in a cert ain procedure, inst ead deferring t hem t o an error handler furt her up t he call st ack. The error is convert ed from an unhandled error int o a handled error at t he point where it reaches an error handling m echanism . What is unaccept able is an error t hat rem ains unhandled all t he way unt il it reaches t he user. Figure 12- 1 shows t he result of an unhandled error.

Figu r e 1 2 - 1 . An Un h a n dle d Er r or M e ssa ge

The Err Object When any kind of runt im e error occurs, t he affect ed code is said t o be in error m ode. An int rinsic, global VBA obj ect called t he Err obj ect is populat ed wit h inform at ion about t he error. Alm ost every error handling m echanism m akes use of t he Err obj ect , so it is helpful t o underst and it s m ost com m only used propert ies and m et hods. Err.Clear This m et hod clears all t he propert ies of t he Err obj ect , canceling t he current error.

Err.Description This propert y cont ains a short st ring t hat describes t he error. Err.HelpFile This propert y cont ains t he full pat h and filenam e of t he help file cont aining a descript ion of t he error. Err.HelpContext This propert y cont ains t he help cont ext I D wit hin t he help file of t he t opic t hat describes t he error. Err.LastDLLError Theoret ically, t his propert y ret urns any error code generat ed by calls t o a DLL, such as a Windows API call. I n pract ice, t his value is very unreliable because Windows m ay execut e DLL funct ions aut om at ically t hat overwrit e t he inform at ion in t his propert y before your code get s a chance t o look at it . I t 's best never t o rely on t he LastDLLError propert y. Err.Number This propert y ret urns t he num ber associat ed wit h t he m ost recent runt im e error. When your error handler needs t o t ake different act ions based on t he t ype of error t hat occurred, you should use t his propert y t o dist inguish am ong different t ypes of errors. Err.Raise This m et hod enables you t o int ent ionally raise errors wit hin your applicat ion. We discuss t his t opic in det ail lat er in t he chapt er. Err.Source This propert y ident ifies t he source of t he error. I t is not very useful for providing inform at ion about VBA runt im e errors because it sim ply ret urns t he nam e of t he proj ect in which t he error occurred. However, as we discuss lat er in t his chapt er, you can populat e t his propert y yourself wit h m ore det ailed inform at ion when raising cust om errors.

N OTE All cont ent s of t he Err obj ect are cleared aut om at ically when code execut ion encount ers a Resum e st at em ent , an On Error st at em ent , Exit Sub, Exit Funct ion, Exit Propert y, End Sub, End Funct ion, or End Propert y.

What Is an Error Handler An error handler is a labeled sect ion of a procedure t hat you designat e as t he place where code will resum e execut ing whenever a runt im e error occurs. An On Error GoTo st at em ent , discussed in t he next sect ion, is used t o m ake t his designat ion. The error handler m ust be a separat e block of code wit hin t he procedure, wit h t he only way int o it being an error and t he only way out being a Resum e, Exit Sub, or Exit Funct ion. List ing 12- 1 shows an exam ple of a procedure wit h a very sim ple error handler.

List in g 1 2 - 1 . A Pr oce du r e w it h a Sim ple Er r or H a n dle r Public Sub MyProcedure() On Error GoTo ErrorHandler

' Lots of code here. Exit Sub ErrorHandler: MsgBox Err.Description, vbCritical, "Error!" End Sub

I n t his procedure, t he sect ion of code ident ified by t he ErrorHandler label has been designat ed as t he error handler for t he procedure by t he On Error GoTo ErrorHandler st at em ent . Not e t he Exit Sub st at em ent prior t o t he ErrorHandler sect ion. This prevent s t he procedure from execut ing t he code in t he ErrorHandler sect ion if no error has occurred. Designat ing a sect ion of code as an error handler e n a b le s it . When a runt im e error occurs and code execut ion branches t o t he error handler, it is said t o be a ct ive . This difference is not academ ic. I f an error handler is act ive ( current ly in t he process of handling an error) and anot her error occurs as a result of som et hing t he code in t hat error handler does, t he new error cannot be handled by t he sam e error handler. I f t his occurs, cont rol will be passed t o t he error handler of t he next highest procedure in t he call st ack. Why is t his im port ant ? There are som e circum st ances in which you need t o perform an operat ion t hat m ay generat e anot her error inside an error handler. I f t his is t he case, put t his code int o a separat e procedure wit h it s own error handler and call t hat procedure from t he act ive error handler. Mult iple error handlers can be act ive at t he sam e t im e, so an error t hat occurs in and is handled by t his separat e procedure will not affect t he error handler t hat called it .

N OTE There is only a single global Err obj ect . I t s propert ies are set by t he error t hat occurred m ost recent ly. I f you t hink you will run int o an error wit hin an error sit uat ion, as described above, save any inform at ion about t he original error in your own variables so you don't lose it .

Error Handler Scope The scope of an error handler, which is t he body of code t hat will act ivat e it if a runt im e error occurs, includes t he procedure t hat t he error handler is defined in as well as any called procedures t hat do not have t heir own error handlers. I f a calling procedure has a designat ed error handler but t he procedures it calls do not , t he error handler of t he calling procedure will be act ivat ed by any errors t hat occur. The sim ple code exam ple in List ing 12- 2 will illust rat e t his m ore clearly.

List in g 1 2 - 2 . Th e Scope of a n Er r or H a n dle r

Public Sub EntryPointProcedure() On Error GoTo ErrorHandler SubProcedure1 Exit Sub ErrorHandler: MsgBox Err.Description, vbCritical, "Error!" End Sub Private Sub SubProcedure1() SubProcedure2 End Sub Private Sub SubProcedure2() Dim lTest As Long ' This error will activate the error handler ' in the entry point procedure. lTest = 1 / 0 End Sub

I n t his exam ple, only Ent ryPoint Procedure has defined an error handler. Ent ryPoint Procedure calls SubProcedure1 and SubProcedure1 calls SubProcedure2. I f a runt im e error occurs in a n y of t hese t hree procedures, code execut ion will im m ediat ely branch t o t he error handler defined in Ent r y Point Pr ocedur e. There are som e cases where t his is a valid and reasonable error handling t echnique, but usually it 's not t he best choice. First , you lose any inform at ion about where t he error act ually occurred. Second, if any of t he called procedures need t o perform cleanup prior t o exit ing ( dest roy obj ect , close connect ions, reset public variables and so on) , t his cleanup code will be skipped. Code execut ion branches uncondit ionally t o t he t op- level procedure's error handler and it cannot be m ade t o ret urn t o t he procedure where t he error occurred ( even wit h t he use of t he Resum e st at em ent , which we will discuss lat er in t he chapt er) . For t hese reasons, it is usually best if each procedure in your applicat ion handles it s own errors.

The On Error Statement The t hree variant s of t he On Error st at em ent provide t he foundat ion of VBA's error handling capabilit y.

On Error GoTo This st at em ent is used t o specify an error handler for a procedure. Lit erally, what it t ells VBA t o do

is branch code execut ion t o t he line in t he procedure ident ified by < Label> when a runt im e error occurs. The code below t his line is considered t he error handler for t he procedure.

On Error Resume Next This st at em ent is bot h very dangerous and very useful at t he sam e t im e. I t t ells VBA t o ignore any errors t hat occur and cont inue wit h t he next line of code unt il you t ell it t o do ot herwise. First let 's m ake it very clear what you should not do wit h t his st at em ent . All t oo oft en I receive code from a client where t he first line in several very large procedures is On Error Resume Next. Don't do t his! On Error Resume Next is not a subst it ut e for writ ing code correct ly in t he first place. I f you have a large procedure t hat will not run unless you place On Error Resume Next at t he t op of it , t hen t hat procedure is alm ost cert ainly poorly writ t en. Wit h t hat out of t he way, let 's t alk about t he circum st ances in which On Error Resume Next is useful and necessary. You will som et im es encount er sit uat ions where you expect an error t o occur during norm al program execut ion at least som e of t he t im e. I n cases such as t his you do not want t he error t o act ivat e your error handler. I nst ead you want code execut ion t o cont inue in som e condit ional fashion based on whet her or not an error occurred. For exam ple, assum e a procedure needs t o use an exist ing workbook t hat m ay or m ay not be open when t he procedure is execut ed. I n t his case, you would use On Error Resume Next t o t em porarily bypass error handling while you t est t o det erm ine whet her t he workbook is open. The m om ent you finish t his t est you would re- enable t he error handler using t he On Error Goto st at em ent . List ing 12- 3 shows an exam ple of t his.

List in g 1 2 - 3 . W h e n t o Use On Er r or Re su m e N e x t Public Sub OnErrorResumeNextDemo() Dim wkbCalcs As Workbook On Error GoTo ErrorHandler ' Lots of code here. ' Test if the Calcs.xls workbook is open. Set wkbCalcs = Nothing On Error Resume Next Set wkbCalcs = Application.Workbooks("Calcs.xls") On Error GoTo ErrorHandler ' If the workbook wasn't open we need to open it. If wkbCalcs Is Nothing Then Set wkbCalcs = Application.Workbooks.Open( _ ThisWorkbook.Path & "\Calcs.xls") End If ' Lots more code here.

Exit Sub ErrorHandler: MsgBox Err.Description, vbCritical, "Error!" End Sub

Not ice t hat On Error Resume Next is used t o disable error handling for j ust t he single line of code t hat det erm ines if t he Calcs.xls workbook is already open. This should be t he norm . Always keep t he num ber of lines of code affect ed by On Error Resume Next t o an absolut e m inim um . I f you do not t urn it off im m ediat ely when you no longer need it , you will very likely suppress errors you did not int end t o suppress. As wit h alm ost all rules, t here are a few except ions t o t he ban on ent ire procedures being " wrapped" in On Error Resume Next. The first sit uat ion concerns a special t ype of procedure in which an error is an int egral part of t he logic of t he procedure. I n t he code in List ing 12- 3, for exam ple, we could subst it ut e t he in- place t est for t he Calcs.xls workbook being open wit h a general- purpose funct ion t hat could be used anywhere t his t ype of t est was required. The result would look like t he funct ion in List ing 12- 4, which is wrapped ent irely in On Error Resume Next by design.

List in g 1 2 - 4 . An En t ir e Fu n ct ion W r a ppe d in On Er r or Re su m e N e x t Private Function bIsBookOpen(ByVal sBookName As String, _ ByRef wkbBook As Workbook) As Boolean ' Checks to see if the specified workbook is open. If it is, ' a reference to it is returned in the wkbBook argument. On Error Resume Next Set wkbBook = Application.Workbooks(sBookName) bIsBookOpen = (Len(wkbBook.Name) > 0) End Function

The second sit uat ion t hat requires wrapping an ent ire procedure in On Error Resume Next involves applicat ion shut down code. When your applicat ion is closing, you t ypically at t em pt t o perform som e cleanup. I f an error occurs during t his process, t here really isn't anyt hing useful an error handler can accom plish. I t 's t ypically bet t er t o use On Error Resume Next t o bypass any errors and cont inue perform ing what ever cleanup t he applicat ion can accom plish before it closes. You can see an exam ple of t his in t he shut down code for our sam ple add- in. The t hird sit uat ion t hat requires wrapping an ent ire procedure in On Error Resume Next involves

applicat ion shut down code and class Term inat e event s. When your applicat ion or class is going away, t here's not m uch point in act ivat ing an error handler. The best choice for when an error occurs in t hese t ypes of procedure is usually t o skip t he line t hat caused t he error and cont inue t o execut e as m uch of t he code as possible. We cover t hese cases lat er in t he chapt er.

On Error GoTo 0 This st at em ent disables any previously enabled error handler in t he current procedure. I t has no effect in procedures t hat do not cont ain error handling, even if t hey have been called by a higherlevel procedure t hat does cont ain error handling. I n List ing 12- 2, for exam ple, placing On Error GoTo 0 in SubProcedure1 would not prevent errors t hat occurred in t hat procedure from being handled by t he st ill enabled error handler in Ent ryPoint Procedure.

The Resume Statement The Resume st at em ent is used t o deact ivat e an error handler and cause code execut ion t o resum e at a specific locat ion t hat depends on which variat ion of t he st at em ent is used. The Resume st at em ent can only be used inside an act ive error handler. Using it under any ot her circum st ances will cause a runt im e error t o occur. No variet y of t he Resume st at em ent can cause code execut ion t o resum e in any procedure ot her t han t he one where t he current error handler is locat ed. This m eans if t he current error handler has t rapped an error from a lower- level procedure, Resume cannot cause code execut ion t o ret urn t o t hat procedure. You m ust be very careful wit h t he Resume st at em ent because you can very easily creat e an infinit e loop in your code wit h it . There are t hree variat ions of t he Resume st at em ent .

Resume This is t he m ost dangerous Resume st at em ent of t hem all. I t causes code execut ion t o ret urn t o t he line of code t hat caused t he error ( or t he call t o a subprocedure where t he error originat ed if t he error did not originat e in t he current procedure) . The im plicit assum pt ion is t hat your error handler has done som et hing t o correct t he error condit ion. I f t his is not t he case, t he error will j ust occur again, t riggering t he error handler, which resum es execut ion on t he line of code t hat caused t he error and so on. This is t he dreaded infinit e loop condit ion and in m any sit uat ions t he only way t o st op it is t o use Ct rl+ Alt + Del t o shut down Excel. Wit h t his warning very clear, t hough, t he Resume st at em ent can be quit e useful. I f you are at t em pt ing t o m ake a connect ion t o a rem ot e dat abase over a slow or congest ed net work, for exam ple, it is not uncom m on t o fail one or m ore t im es. When a connect ion failure occurs, an error is t hrown and your error handler is act ivat ed. You can increm ent a count er in your error handler and use Resume t o t ry connect ing again. I f you are unable t o connect successfully aft er a cert ain num ber of at t em pt s, you can have your error handler bail out wit h an error m essage t o t he user. We dem onst rat e t his use of resum e in Chapt er 13 Program m ing wit h Dat abases. The Resume st at em ent is also very useful wit hin t he cont ext of built - in debugging aides. When your code has a special flag set t hat indicat es it is in debug m ode, your error handler can direct code

execut ion t o a branch t hat aut om at ically places t he code int o break m ode and allows you t o resum e code execut ion on t he line of code t hat generat ed t he error in order t o debug t he problem . You will see t he error handling const ruct s t hat assist debug m ode in t his chapt er, but we do not cover debugging in det ail unt il Chapt er 16 VBA Debugging.

Resume Next The Resume Next st at em ent causes code execut ion t o cont inue on t he first execut able line of code aft er t he one t hat generat ed t he error. The Resume Next st at em ent will not ret urn t o a lower- level procedure if t hat 's where t he error was generat ed. I nst ead, it will resum e execut ion in t he procedure t hat handled t he error on t he line of code im m ediat ely following t he call t o t he procedure branch where t he error was generat ed.

Resume The Resume st at em ent causes code execut ion t o cont inue on t he line of code following t he specified label. The label m ust be locat ed in t he sam e procedure as t he error handler. Like t he Resume st at em ent , t he Resume st at em ent can cause an infinit e loop in your code if t he error is locat ed below t he specified label.

Raising Custom Errors Alt hough it m ay seem count erint uit ive, deliberat ely generat ing runt im e errors in your code can be a very useful t echnique and it is fully support ed by VBA. The reasons for using t hese cust om errors are bet t er dealt wit h in t he cont ext of procedure error handling as a whole, so we defer a det ailed discussion of t his t opic unt il lat er in t he chapt er. I n t his sect ion we cover t he m echanics of raising cust om errors. Cust om errors are raised using t he Raise m et hod of t he Err obj ect . The synt ax of t his m et hod is as follow s:

Err.Raise Number, Source, Description, HelpFile, HelpContextID

The argum ent s t o t he Err.Raise m et hod correspond t o t he propert ies of t he Err obj ect , which we described above. When you raise a cust om error, you can set t hese argum ent s however you like. All of t hem except t he Num ber argum ent are opt ional. One caveat is you cannot use an error num ber for a cust om error t hat is already used by an Excel or VBA error. ( You can raise predefined errors using t heir error num bers.) The num bers 513 t hrough 65535 are reserved for cust om errors. VBA also provides t he special const ant vbObj ect Error for creat ing cust om error num bers t hat are t ypically used wit h classes. Any num ber added t o t he vbObj ect Error const ant is guarant eed t o be an error num ber t hat is not used by any Windows process. An exam ple of a cust om error num ber creat ed using t he vbObj ect Error const ant is shown here:

Err.Raise vbObjectError + 1024

The Source argum ent of t he error should be set t o t he nam e of t he procedure in which t he error was raised. The Descript ion of a cust om error should be a reasonably brief but clear descript ion of t he reason t he error was raised. The HelpFile and HelpCont ext I D argum ent s enable you t o provide t he user wit h addit ional inform at ion about t he error if your proj ect uses a help file. Ot herwise, t hese argum ent s can be ignored. Help files are covered in m ore det ail in Chapt er 24 Providing Help, Securing, Packaging and Dist ribut ing.

The Single Exit Point Principle One of t he fundam ent al good archit ect ural pract ices in any procedure is t o have a single exit point . This m eans t hat aft er your error handler has finished handling an error, it should redirect code execut ion back int o t he body of t he procedure so t he procedure will be exit ed at t he sam e point under all circum st ances. The pract ical reason for t his is t hat it 's very com m on for som e t ype of cleanup t o be required before a procedure exit s. Even if a procedure current ly requires no cleanup, t his m ay very well change as a result of som e fut ure code m odificat ion. I f your error handlers are already st ruct ured t o use a single exit point , you have one less m odificat ion t o m ake. The m echanism for im plem ent ing a single exit point is t he Resum e < Label> st at em ent discussed previously. I n t his case < Label> ident ifies t he point in each procedure at which code execut ion resum es aft er an error has occurred and been handled. We will give t his label t he nam e ErrorExit . The ErrorExit label has no effect on code execut ion when t he procedure com plet es wit hout error. Norm al code execut ion j ust passes t his label and cont inues on t o t he end of t he procedure. When an error occurs, however, t his label ident ifies t he point at which t he error handler should resum e code execut ion once an error has been handled in order t o guarant ee t hat code execut ion com plet es at t he sam e point in t he procedure wit h or wit hout an error. You will see ex am ples of single exit point procedures in t he sect ions t hat follow.

Simple Error Handling I n t he sim plest form of error handling, error handlers are placed only in e n t r y poin t pr oce du r e s. Ent ry point procedures are t hose procedures from which code execut ion can be init iat ed. They are t ypically t he procedures assigned t o m enu it em s, t oolbar but t ons, or cont rols placed on worksheet s, but m ost event procedures are also ent ry point s, because t hey init iat e execut ion based on som e act ion m ade by t he user. I f t he error handler in an ent ry point procedure is t he only error handler in it s call st ack, t his error handler will t rap all errors t hat occur in all lower- level procedures. A sim ple error handler will display an error m essage t o t he user and exit t he procedure. An exam ple of t his is shown in List ing 12- 5 .

List in g 1 2 - 5 . An Ex a m ple of a Sim ple Er r or H a n dle r Public Sub MyEntryPoint() On Error GoTo ErrorHandler ' Your code here. ErrorExit: Exit Sub ErrorHandler: MsgBox Err.Description, vbCritical, "Application Name" Resume ErrorExit End Sub

Sim ple error handlers are appropriat e only for t he m ost t rivial applicat ions. An exam ple m ight be a ut ilit y add- in t hat provides a num ber of sim ple feat ures t hat require a sm all am ount of code and do not require any significant cleanup. The prim ary purpose of a sim ple error handler is t o shield users from raw runt im e errors such as t he one shown in Figure 12- 1.

Complex Project Error Handler Organization There are t wo or t hree com plex error handling syst em designs com m only used in Excel VBA applicat ions and several m inor variat ions on each of t hose. I f designed correct ly, all of t hem will accom plish t he sam e purpose; gracefully handling runt im e errors encount ered by your applicat ion. The com plex error handling syst em we int roduce in t his sect ion has t he following charact erist ics: All nont rivial procedures cont ain error handlers. All procedure error handlers call a cent ral error handling funct ion. This funct ion t racks and logs each error, decides whet her or not t o display an error m essage t o t he user and t ells t he calling procedure how t o proceed by way of it s ret urn value. All ent ry point procedures are subrout ines. An ent ry point procedure is any procedure in which code execut ion begins. This includes subrout ines in st andard m odules called by t oolbar but t ons and event procedures execut ed in response t o som e user act ion. All nont rivial lower- level procedures ( all procedures t hat are called by ent ry point procedures) are Boolean funct ions whose ret urn value indicat es whet her t he funct ion succeeded or failed. We cover all of t hese point s in det ail as t his sect ion progresses, but we want ed t o give you a highlevel overview of how our error handling syst em works. An im port ant point t o keep in m ind as you read t his sect ion is t hat ent ry point procedures m ust only be t riggered direct ly by som e user act ion. One ent ry point procedure m ust never call anot her ent ry point procedure or t he error handling syst em described here will break down. I f t wo ent ry point procedures need t o run t he sam e code, t he com m on code should be fact ored out int o a lowerlevel funct ion t hat can be called by bot h ent ry point procedures.

Procedure Error Handlers List ing 12- 6 shows t wo error handler procedure skelet ons. The first is an exam ple of an ent ry point subrout ine, t he second an exam ple of a lower- level, Boolean funct ion. We have placed a call from t he ent ry point subrout ine t o t he lower- level funct ion t o dem onst rat e how t he error handling syst em would work. We explain t he purpose of t he various const ant s shown in List ing 12- 6 as well as t he funct ion call inside t he error handlers in The Cent ral Error Handler sect ion lat er in t he chapt er .

List in g 1 2 - 6 . Su br ou t in e a n d Fu n ct ion Er r or H a n dle r s Private Const msMODULE As String = "MMyModule"

Public Sub MyEntryPointSubroutine() Const sSOURCE As String = "MyEntryPointSubroutine()" On Error GoTo ErrorHandler ' Call the lower level function. If Not bMyLowerLevelFunction() Then Err.Raise glHANDLED_ERROR End If ErrorExit: ' Cleanup code here. Exit Sub ErrorHandler: If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then Stop Resume Else Resume ErrorExit End If End Sub Private Function bMyLowerLevelFunction() As Boolean Const sSOURCE As String = "bMyLowerLevelFunction()" Dim bReturn As Boolean

' The function return value

On Error GoTo ErrorHandler ' Assume success until an error is encountered. bReturn = True ' Operational code here. ErrorExit: ' Cleanup code here. bMyLowerLevelFunction = bReturn Exit Function ErrorHandler: bReturn = False If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else

Resume ErrorExit End If End Function

The general layout of t he error handlers is very sim ilar in bot h cases. The only significant difference is t he funct ion m ust ret urn a value indicat ing success or failure wit hout violat ing t he single exit point principle, so we have added t he st ruct ure required t o accom plish t hat t o t he funct ion's error handler . List ing 12- 6 shows exam ples of very sim ple error handlers. They don't t ry t o respond t o errors ot her t han by invoking t he cent ral error handler and exit ing. I n m any sit uat ions, you will be aware of errors t hat m ight occur but can be correct ed in t he error handler and allow code execut ion t o cont inue. A m ore com plex error handler, such as t he one shown in List ing 12- 7, enables you t o accom plish t his.

List in g 1 2 - 7 . A M or e Com ple x Er r or H a n dle r ErrorHandler: Select Case Err.Number Case 58 ' File already exists. Resolve the problem and resume. Resume Case 71 ' Disk not ready. Resolve the problem and resume. Resume Case Else ' The error can't be resolved here. Invoke the central ' error handling procedure. If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then ' If the program is in debug mode, execution ' continues here. Stop Resume Else Resume ErrorExit End If End Select End Function

A Select Case st at em ent is used t o ident ify error num bers t hat can be handled wit hin t he error handler. I f t he num ber of t he error t rapped is not one of t hose handled by a specific Case clause, it falls t hrough t o t he Case Else clause, which invokes t he cent ral error handler.

N OTE I n t he cont ext of error handling, t he word t rap refers t o an error handler being act ivat ed by an error. I t is synonym ous wit h t he word cat ch, which is com m only used in it s place.

A t ypical error handling scenario based on t he exam ples shown in List ing 12- 6 and List ing 12- 7 would play out som et hing like t his. MyEnt ryPoint Subrout ine calls bMyLowerLevelFunct ion t o perform som e operat ion. An error occurs in bMyLowerLevelFunct ion t hat cannot be handled by it s error handler. The error handler in bMyLower LevelFunct ion calls t he cent ral error handler. The cent ral error handler logs t he error and passes a value back t o bMyLowerLevelFunct ion t hat t ells it t o exit . bMyLowerLevelFunct ion exit s and ret urns False t o t he MyEnt ryPoint Subrout ine calling procedure. I n MyEnt ryPoint Subrout ine, a cust om error is raised ( because bMyLowerLevelFunct ion ret urned False) , which t hen calls t he cent ral error handler again. Because an ent ry point subrout ine called t he cent ral error handler, an error m essage is displayed t o t he user. Aft er t he cent ral error handler has com plet ed it s dut ies, code execut ion resum es in MyEnt ryPoint Subrout ine, which t hen exit s. I n The Cent ral Error Handler sect ion below, we describe how t he cent ral error handler det erm ines when an error m essage should be displayed and how it influences program execut ion aft er t he error is handled.

Trivial Procedures At t he beginning of t his sect ion we st at ed t hat all n on t r iv ia l procedures cont ain error handlers. That begs t he quest ion of what is a t rivial procedure t hat wouldn't require an error handler. A t rivial procedure is eit her so sim ple t hat an error cannot occur wit hin it or is st ruct ured such t hat any errors t hat do occur are ignored. List ing 12- 8 shows exam ples of bot h t ypes.

List in g 1 2 - 8 . Tr ivia l Pr oce du r e s D on 't Re qu ir e Er r or H a n dle r s ' This subroutine is so simple that no errors ' will ever be generated within it. Public Sub ResetAppProperties() Application.StatusBar = False Application.ScreenUpdating = True Application.DisplayAlerts = True Application.EnableEvents = True Application.EnableCancelKey = xlInterrupt Application.Cursor = xlDefault End Sub ' Any errors that occur in this function are ignored. Private Function bIsBookOpen(ByVal sBookName As String, _

ByRef wkbBook As Workbook) As Boolean On Error Resume Next Set wkbBook = Application.Workbooks(sBookName) bIsBookOpen = (Len(wkbBook.Name) > 0) End Function

The Central Error Handler The cent ral error handler is t he heart of any com plex error handling syst em . I t consist s of a procedure designed t o log errors t o an error log file or ot her persist ent locat ion and display error m essages t o t he user, as well as provide facilit ies t hat allow t he program m er t o debug errors during developm ent . ( We cover debugging in det ail in Chapt er 16 VBA Debugging.) The m odule cont aining t he cent ral error handler also cont ains all error handling- relat ed const ant s, m aking t he error handling syst em fully encapsulat ed. List ing 12- 9 shows an exam ple of a com plet e cent ral error handler.

List in g 1 2 - 9 . A Ce n t r a l Er r or H a n dle r Public Const gbDEBUG_MODE As Boolean = False Public Const glHANDLED_ERROR As Long = 9999 Public Const glUSER_CANCEL As Long = 18 Private Const msSILENT_ERROR As String = "UserCancel" Private Const msFILE_ERROR_LOG As String = "Error.log" Public Function bCentralErrorHandler( _ ByVal sModule As String, _ ByVal sProc As String, _ Optional ByVal sFile As String, _ Optional ByVal bEntryPoint As Boolean) As Boolean Static sErrMsg As String Dim Dim Dim Dim Dim

iFile As Integer lErrNum As Long sFullSource As String sPath As String sLogText As String

' Grab the error info before it's cleared by ' On Error Resume Next below. lErrNum = Err.Number ' If this is a user cancel, set the silent error flag ' message. This will cause the error to be ignored. If lErrNum = glUSER_CANCEL Then sErrMsg = msSILENT_ERROR ' If this is the originating error, the static error ' message variable will be empty. In that case, store ' the originating error message in the static variable. If Len(sErrMsg) = 0 Then sErrMsg = Err.Description

' We cannot allow errors in the central error handler. On Error Resume Next ' Load the default filename if required. If Len(sFile) = 0 Then sFile = ThisWorkbook.Name ' Get the application directory. sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Construct the fully-qualified error source name. sFullSource = "[" & sFile & "]" & sModule & "." & sProc ' Create the error text to be logged. sLogText = " " & sFullSource & ", Error " & _ CStr(lErrNum) & ": " & sErrMsg ' Open the log file, write out the error information and ' close the log file. iFile = FreeFile() Open sPath & msFILE_ERROR_LOG For Append As #iFile Print #iFile, Format$(Now(), "mm/dd/yy hh:mm:ss"); sLogText If bEntryPoint Then Print #iFile, Close #iFile ' Do not display silent errors. If sErrMsg msSILENT_ERROR Then ' Show the error message when we reach the entry point ' procedure or immediately if we are in debug mode. If bEntryPoint Or gbDEBUG_MODE Then Application.ScreenUpdating = True MsgBox sErrMsg, vbCritical, gsAPP_TITLE ' Clear the static error message variable once ' we've reached the entry point so that we're ready ' to handle the next error. sErrMsg = vbNullString End If ' The return value is the debug mode status. bCentralErrorHandler = gbDEBUG_MODE Else ' If this is a silent error, clear the static error ' message variable when we reach the entry point. If bEntryPoint Then sErrMsg = vbNullString bCentralErrorHandler = False End If End Function

This is a lot t o digest , so let 's dissect it piece by piece. First t he const ant declarat ions: gbDEBUG_MODE This public Boolean const ant is used by t he developer t o set t he debug m ode st at us of t he applicat ion. When you are t est ing your applicat ion or at t em pt ing t o locat e errors in your code, you want your error handlers t o behave different ly t han t hey do when your applicat ion is deployed t o end users. Set t ing t he gbDEBUG_MODE const ant t o True causes t he cent ral error handler funct ion t o display an error m essage im m ediat ely aft er an error occurs and t hen ret urn True. As shown in List ing 12- 6 and List ing 12- 7, when t he cent ral error handler funct ion ret urns True, t he procedure error handler drops int o a VBA St op st at em ent followed by a Resum e st at em ent . The St op st at em ent put s t he proj ect int o Break m ode and t he Resum e st at em ent enables you t o single st ep back t o t he line of code in t he procedure where t he error occurred. You can t hen debug t he error. Again, we discuss debugging in det ail in Chapt er 16 VBA Debugging. glHANDLED_ERROR This public Long const ant is an error num ber you can use t o raise cust om errors. As we discussed in t he sect ion on raising cust om errors, when you raise a cust om error you m ust supply an error num ber not already used by Excel or VBA. The glHANDLED_ERROR const ant has a value of 9999, which is not wit hin t he range of error num ber values used by VBA. I t also has t he advant age of being easily recognizable as a cust om error num ber for debugging purposes. I n all but t he m ost com plex error handling scenarios, a single cust om error num ber can be used for all of your cust om errors. glUSER_CANCEL This public Long const ant is set t o t he VBA error value 18. This error value occurs when t he user cancels program execut ion by pressing t he Esc or Ct rl+ Break keys. Unless it is absolut ely crit ical t hat your program not be int errupt ed, such as during st art up and shut down, you should always allow t he user t o halt program execut ion. The best way t o do t his is t o add t he following st at em ent at t he beginning of each ent ry point procedure: Application.EnableCancelKey = xlErrorHandler

This will cause VBA t o t reat a user cancel as a runt im e error wit h an Err.Number = 18 t hat is rout ed t hrough your error handler. When t he cent ral error handler sees t his error num ber, it convert s it int o a special error m essage st ring, which we cover next , t hat causes t he error t o be ignored. m sSI LENT_ERROR This privat e St ring const ant is assigned t o t he st at ic error m essage variable in t he cent ral error handling funct ion whenever a user cancel error ( Err.Number = glUSER_ CANCEL) is det ect ed. Because t his error m essage variable is st at ic, it holds it s value bet ween calls t o t he cent ral error handler. This m eans no m at t er how deep in t he call st ack t he program was when t he user cancelled execut ion, t he error handler will pass t he error up t he st ack and out t he ent ry point procedure wit hout displaying an error m essage t o t he user. Silent errors also will not t rigger t he procedure debugging m echanism , even if t he applicat ion is in debug m ode. m sFI LE_ERROR_LOG This privat e St ring const ant specifies t he nam e of t he t ext file t o which all error m essages will be writ t en. The error log file will always be locat ed in t he sam e

direct ory as t he workbook cont aining t he cent ral error handler. The inform at ion st ored in t he error log file is designed t o help you debug errors t hat have occurred on a user's com put er t hat you m ay not necessarily have access t o. The error log file will show you t he exact error m essage, t he procedure where t he error originat ed and t he call st ack t hat led t o t he error. Com bined wit h a brief verbal report from t he user about exact ly what t hey were doing when t he error occurred, t his inform at ion is usually sufficient t o enable you t o debug t he problem . Now we exam ine t he code in t he cent ral error handler funct ion line by line t o see how an error is t reat ed under various condit ions. First let 's look at t he argum ent s t o t he funct ion. The first t hree argum ent s t o t he bCent ralErrorHandler funct ion ident ify t he code m odule, procedure and filenam e from which t he funct ion was called. This inform at ion is writ t en t o t he error log file for use in debugging runt im e errors. The fourt h argum ent t o t he bCent ralErrorHandler funct ion indicat es whet her or not it was called from an ent ry point procedure. I f t he applicat ion is not in debug m ode, an error m essage is displayed t o t he user only when t he error reaches t he originat ing ent ry point procedure. I f t he applicat ion is in debug m ode, t he fourt h argum ent is ignored, an error m essage is displayed im m ediat ely and t he cent ral error handler ret urns False so t hat you can begin debugging t he error. Not ice t hat wit hin t he bCent ralErrorHandler funct ion we have declared a st at ic St ring variable. This variable is used t o st ore t he original error m essage so we can display it t o t he user when we reach t he ent ry point , regardless of how m any procedures deep in t he st ack we are when t he error occurs. This st at ic variable will hold it s value unt il we explicit ly change it . As soon as code execut ion has ent ered t he bCent ralErrorHandler funct ion, we m ust read and st ore any inform at ion we need from t he VBA Err obj ect . The reason for t his will becom e apparent very short ly.

lErrNum = Err.Number ' If this is a user cancel, set the silent error flag ' message. This will cause the error to be ignored. If lErrNum = glUSER_CANCEL Then sErrMsg = msSILENT_ERROR ' If this is the originating error, the static error ' message variable will be empty. In that case, store ' the originating error message in the static variable. If Len(sErrMsg) = 0 Then sErrMsg = Err.Description

First we read and st ore t he error num ber. Then, if t he error num ber indicat es t hat t he user has cancelled program execut ion, we st ore t he gsSI LENT_ERROR flag m essage in our st at ic error m essage variable. I f t he error num ber does not indicat e a user cancel and t he st at ic error m essage variable does not already cont ain a value, we st ore t he error descript ion in t he st at ic error m essage variable. I n t his way, we st ore only t he original error m essage and persist it t hrough any addit ional calls t o t he cent ral error handler funct ion. The st at ic variable is cleared only aft er t he ent ry point procedure has been reached and t he error m essage displayed t o t he user. The reason we m ust persist any necessary Err obj ect values im m ediat ely upon ent ering t he cent ral error handler funct ion is because we cannot allow any errors t o occur in t his funct ion. Therefore t he ent ire funct ion is wrapped in On Error Resume Next:

' We cannot allow errors in the central error handler.

On Error Resume Next

As soon as code execut ion passes t he On Error Resume Next st at em ent , all propert ies of t he Err obj ect are aut om at ically cleared. I f you have not st ored t he original values from t he Err obj ect 's propert ies at t his point , t hey are lost forever. I n t he next sect ion of code we const ruct several St ring values t hat t he error handler requires.

' Load the default filename if required. If Len(sFile) = 0 Then sFile = ThisWorkbook.Name ' Get the application directory. sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Construct the fully-qualified error source name. sFullSource = "[" & sFile & "]" & sModule & "." & sProc ' Create the error text to be logged. sLogText = " " & sFullSource & ", Error " & _ CStr(lErrNum) & ": " & sErrMsg

You will not ice from List ing 12- 9 t hat t he sFile argum ent is opt ional. I f no value for t his argum ent is passed, t he cent ral error handler assum es it is being called from wit hin t he current workbook and it loads t his argum ent 's value wit h ThisWorkbook.Name. The next t ask is t o get t he pat h t o t he current workbook. This is where t he error log file will be creat ed ( or updat ed if it has already been creat ed) . I n t he next line of code we const ruct a fully qualified locat ion t hat ident ifies where t he call t o t he bCent ralErrorHandler funct ion originat ed. This locat ion ident ifier has t he following form at :

[FileName]CodeModuleName.ProcedureName

The last st ring we const ruct in t his sect ion is t he com plet e error log file ent ry. This consist s of t he fully qualified locat ion st ring creat ed above, prefixed wit h t he dat e and t im e t he error occurred and suffixed wit h t he error num ber and t he error m essage. We will see ex am ples of error log file ent ries lat er in t his chapt er. Our next t ask is t o writ e t he ent ry in t he applicat ion error log file. As shown below, we use st andard VBA file I / O t echniques t o creat e or append t o t he error log file:

' Open the log file, write out the error information and ' close the log file. iFile = FreeFile() Open sPath & msFILE_ERROR_LOG For Append As #iFile Print #iFile, Format$(Now(), "mm/dd/yy hh:mm:ss"); sLogText

If bEntryPoint Then Print #iFile, Close #iFile

We first acquire an available file num ber and use it t o creat e or open t he error log file specified by t he m sFI LE_ERROR_LOG const ant and locat ed in t he pat h creat ed in t he previous sect ion. We t hen writ e t he log file ent ry st ring creat ed above t o t he log file. I f t he bCent ralErrorHandler funct ion has been called by an ent ry point procedure, we writ e an addit ional blank line t o t he error log file t o provide visual separat ion bet ween t his and subsequent errors. Aft er t hat we close t he error log file. The last sect ion of t he cent ral error handler det erm ines whet her and when an error m essage is displayed and whet her t he cent ral error handler t riggers debug m ode behavior in t he procedure t hat called it .

' Do not display or debug silent errors. If sErrMsg msSILENT_ERROR Then ' Show the error message when we reach the entry point ' procedure or immediately if we are in debug mode. If bEntryPoint Or gbDEBUG_MODE Then Application.ScreenUpdating = True MsgBox sErrMsg, vbCritical, gsAPP_TITLE ' Clear the static error message variable once ' we've reached the entry point so that we're ready ' to handle the next error. sErrMsg = vbNullString End If ' The return vale is the debug mode status. bCentralErrorHandler = gbDEBUG_MODE Else ' If this is a silent error, clear the static error ' message variable when we reach the entry point. If bEntryPoint Then sErrMsg = vbNullString bCentralErrorHandler = False End If

The prim ary deciding fact or on when t o display an error m essage and when t o ignore it is t he value of t he st at ic sErrMsg variable. Rem em ber t hat t his variable holds t he value of t he original error m essage t hat t riggered t he cent ral error handler. I f t he value of t his variable indicat es t hat t he original error was t he result of t he user canceling program execut ion, t hen no error m essage is displayed, t he st at ic error m essage variable is cleared t o prepare t he cent ral error handler for t he next error, and t he ret urn value of t he cent ral error handler is False, so as not t o t rigger any debug act ions. I f t he st at ic error m essage variable indicat es any error ot her t han a user cancel error, t hen an error m essage is displayed. I f t he applicat ion is in debug m ode ( gbDEBUG_MODE = True) , an error

m essage displays as soon as t he error occurs and t he cent ral error handler ret urns True so t he calling procedure can begin execut ing debug code. I f t he applicat ion is not in debug m ode, an error m essage displays only when t he error handling code reaches t he ent ry point procedure. I n t his case, t he cent ral error handler funct ion ret urns False t hroughout so as not t o t rigger any procedure- level debug code.

Error Handling in Classes and Userforms Classes and userform s present som e unique error handling challenges t hat we cover in t his sect ion. As explained previously, event procedures in classes and userform s should alm ost always be considered ent ry point procedures. The I nit ialize, Act ivat e and Term inat e event s are except ions t o t his rule. The user does not direct ly t rigger t hese event s. I nst ead, t hey are fired as a side effect of a class being creat ed or dest royed or a userform being creat ed, shown or dest royed. Error handling for t hese event s is a lit t le t ricky, so we discuss t hem in det ail.

Initialize and Activate Events Errors t hat occur in I nit ialize or Act ivat e event s are t ypically cat ast rophic errors t hat render t he class or userform in which t hey occur unusable. Therefore, t hey norm ally cannot be handled in any way t hat would m it igat e t hem . I f you are going t o place code in eit her of t hese event procedures, t he best opt ion is not t o give t hem an error handler at all. This will delegat e t he handling of any errors t hat occur inside t hese event procedures t o t he error handler of t he procedure t hat at t em pt ed t o creat e t he obj ect . An opt ion t hat gives you m uch m ore cont rol over t he init ializat ion process, and any errors t hat arise as a result of it , is t o creat e your own cust om I nit ialize m et hod. This Boolean funct ion would replace t he I nit ialize and Act ivat e event procedures, so t hose event s would no longer need t o be t rapped in your code. I n t he Put t ing I t All Toget her sect ion below, we show an exam ple of a cust om I nit ialize m et hod in a userform .

Terminate Events Errors t hat occur in Term inat e event s are unusual in t hat , assum ing proper program m ing t echniques have been used, neit her are t hey cat ast rophic nor can t hey be m it igat ed. When t he Term inat e event is fired, t he class or userform has perform ed it s funct ion and is being dest royed. I f you need t o place code in t he Term inat e event of a class or userform , it is best t o sim ply ignore any errors t hat occur by using t he On Error Resume Next st at em ent at t he beginning of t he procedure.

Putting It All Together Alt hough we've described all t he pieces of an error handling syst em , it m ay not be clear how all t hose pieces fit t oget her. I n t his sect ion we show a sm all but com plet e program t hat dem onst rat es t he basic error handling t echniques. This program is adm it t edly cont rived, but t he idea behind it is t o have a com plet e program wit h as lit t le dist ract ion from non- error- handling- relat ed code as possible. The com plet e program can be found in t he Concept s folder of t he CD in t he workbook nam ed ErrorHandlingDem o.xls. The error handling dem o program consist s of a single ent ry point procedure t hat displays a userform and t hen calls a funct ion t hat int ent ionally generat es an error depending on whet her t he user clicks t he OK or Cancel but t on on t he userform . Figure 12- 2 shows t he userform for our error handling dem o and List ing 12- 10 shows t he code behind t his userform .

List in g 1 2 - 1 0 . Th e Code Be h in d t h e Er r or H a n dlin g D e m o Use r for m Private Const msMODULE As String = "FDemo" Private bUserCancel As Boolean Public Property Get UserCancel() As Boolean UserCancel = bUserCancel End Property Private Sub cmdOK_Click() bUserCancel = False Me.Hide End Sub Private Sub cmdCancel_Click() bUserCancel = True Me.Hide End Sub Private Sub UserForm_QueryClose(Cancel As Integer, _ CloseMode As Integer) ' Route any X-close button calls through ' the cmdCancel_Click procedure. If CloseMode = vbFormControlMenu Then Cancel = True cmdCancel_Click End If End Sub

Public Function Initialize() As Boolean Const sSOURCE As String = "Initialize()" Dim bReturn As Boolean

' The function return value

On Error GoTo ErrorHandler ' Assume success until an error is encountered. bReturn = True ' Set the UserForm caption. Me.Caption = gsAPP_TITLE ErrorExit: Initialize = bReturn Exit Function ErrorHandler: bReturn = False If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else Resume ErrorExit End If End Function

Figu r e 1 2 - 2 . Th e Er r or H a n dlin g D e m o Use r for m

The first t hing t o not ice is t he userform has a read- only UserCancel propert y. The value of t his propert y is det erm ined by which but t on t he user clicks. I f t he OK but t on is clicked, t he UserCancel propert y will ret urn False ( m eaning t he user did not cancel t he userform ) . I f t he Cancel but t on is clicked, t he UserCancel propert y will ret urn True. I n t he code for t he calling procedure we will dem onst rat e how t o raise a cust om user cancel error in response t o t he UserCancel m et hod ret urning True t hat will cause t he error handler t o exit silent ly rat her t han displaying an error. The second t hing t o not ice is we are t rapping clicks t o t he X- close but t on on t he userform wit h t he UserForm _QueryClose event procedure and rerout ing t hem t o t he cm dCancel_Click event procedure. This m akes a click on t he X- close but t on behave exact ly like a click on t he Cancel but t on. The last t hing t o not ice is t he userform cont ains a cust om I nit ialize m et hod. This m et hod is a Boolean funct ion t hat ret urns True if init ializat ion succeeds and False if an error occurred during init ializat ion. This m et hod is called prior t o showing t he userform . The calling funct ion t hen exam ines t he ret urn value of t he m et hod and does not at t em pt t o show t he userform if init ializat ion failed. List ing 12- 11 shows t he funct ion t hat will purposely cause an error.

List in g 1 2 - 1 1 . Th e bCa u se An Er r or Fu n ct ion Public Function bCauseAnError() As Boolean Const sSOURCE As String = "bCauseAnError()" Dim bReturn As Boolean Dim lTest As Long

' The function return value

On Error GoTo ErrorHandler ' Assume success until an error is encountered. bReturn = True ' Cause a divide by zero error. lTest = 1 / 0 ErrorExit: bCauseAnError = bReturn Exit Function ErrorHandler: bReturn = False If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else Resume ErrorExit End If

End Function

This funct ion is exact ly t he sam e as t he one we showed in List ing 12- 6 wit h som e code added t hat causes it t o t hrow a divide by zero error. Now we can t ie t hings t oget her wit h t he ent ry point procedure t hat runs t he applicat ion. The code for t his procedure is shown in List ing 12- 12.

List in g 1 2 - 1 2 . Th e En t r yPoin t Su br ou t in e Public Sub EntryPoint() Const sSOURCE As String = "EntryPoint" Dim bUserCancel As Boolean Dim frmDemo As FDemo On Error GoTo ErrorHandler Set frmDemo = New FDemo Load frmDemo ' If UserForm initialization failed, raise a custom error. If Not frmDemo.Initialize() Then Err.Raise glHANDLED_ERROR frmDemo.Show ' If the user pressed the Cancel button, raise a custom ' user cancel error. This will cause the central error ' handler to exit the program without displaying an ' error message. If frmDemo.UserCancel Then Err.Raise glUSER_CANCEL ' If the user pressed the OK button, run the function that ' is designed to cause an error. If Not bCauseAnError() Then Err.Raise glHANDLED_ERROR ErrorExit: ' Clean up the UserForm Unload frmDemo Set frmDemo = Nothing Exit Sub ErrorHandler: If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then Stop Resume Else Resume ErrorExit End If

End Sub

The Ent ryPoint subrout ine is run from a but t on locat ed on Sheet 1 of t he ErrorHandlingDem o.xls workbook. This applicat ion has only t wo possible execut ion pat hs. Clicking t he OK but t on on t he userform t riggers t he first and clicking t he Cancel but t on on t he userform t riggers t he second. Let 's exam ine what happens in each case and see t he result ing error log ent ries. The Ent ryPoint subrout ine first creat es a new inst ance of t he FDem o UserForm , loads it and calls t he userform 's cust om I nit ialize m et hod. I n t his sam ple applicat ion t he userform will never fail t o init ialize. We have provided t his cust om I nit ialize m et hod t o dem onst rat e how you would init ialize a userform in a way t hat is linked int o t he error handling syst em . Next , t he Ent ryPoint subrout ine shows t he FDem o userform . As you can see in Figure 12- 2, t he only act ions available t o t he user are clicking t he OK or Cancel but t ons. Clicking t he OK but t on set s t he FDem o userform 's UserCancel propert y t o False, m eaning t he user did not cancel. Clicking t he Cancel but t on set s t he UserCancel propert y t o True, m eaning t he user did cancel. Clicking eit her but t on also hides t he userform , allowing t he Ent ryPoint subrout ine t o cont inue execut ing. Because t he FDem o userform is hidden rat her t han unloaded, when code execut ion ret urns t o t he Ent ryPoint subrout ine t he userform is st ill in m em ory. This allows t he Ent ryPoint subrout ine t o check t he value of t he FDem o UserCancel propert y t o det erm ine what t he user has asked it t o do. I f t he UserCancel propert y is True, t he Ent ryPoint subrout ine needs t o exit wit hout displaying an error m essage but st ill running it s cleanup code. I t accom plishes t his by raising a cust om user cancel error. I f you recall from t he discussion of t he cent ral error handler, VBA uses t he error num ber 18 t o indicat e t he user has cancelled program execut ion, we have defined a public const ant t hat holds t his value, and when t he cent ral error handler sees a user cancel error it exit s silent ly. Therefore, t o exit as a result of t he user clicking Cancel in t he FDem o userform , t he Ent ryPoint subrout ine raises a cust om error wit h t he error num ber glUSER_ CANCEL. The line of code used t o accom plish t his is shown here:

If frmDemo.UserCancel Then Err.Raise glUSER_CANCEL

This not ifies t he cent ral error handler of t he error. The cent ral error handler logs t he error and ret urns cont rol t o t he Ent ryPoint procedure so it can com plet e it s cleanup act ivit ies prior t o exit ing. The cent ral error handler records all errors, including user cancel errors, in t he error log. The error.log file will be locat ed in t he sam e direct ory as t he ErrorHandlingDem o.xls workbook. The ent ry m ade in response t o t he user clicking t he FDem o Cancel but t on will be sim ilar t o t he ent ry shown below except it will be writ t en t o a single line in t he error log file:

03/30/04 20:23:37 [ErrorHandlingDemo.xls] MEntryPoints.EntryPoint, Error 18: UserCancel

I f t he user did not cancel program execut ion, t he Ent ryPoint subrout ine cont inues wit h t he next line

of code. This line is a call t o t he funct ion t hat is designed t o int ent ionally t hrow a divide by zero error. As you can see in List ing 12- 11, t his funct ion's error handler will first call t he cent ral error handler t o not ify it of t he error, t hen cause t he funct ion t o ret urn False in order t o not ify t he calling procedure t hat an error has occurred. I n t his case, t he error is cat ast rophic, so t he calling procedure m ust t erm inat e t he program . I t does t his by raising a cust om handled error, as shown below :

If Not bCauseAnError() Then Err.Raise glHANDLED_ERROR

Because t his error was raised from an ent ry point procedure, t he original error m essage st ored by t he cent ral error handler will be displayed t o t he user, as shown in Figure 12- 3.

Figu r e 1 2 - 3 . Th e Er r or M e ssa ge D ispla ye d t o t h e Use r

I n t his case t he cent ral error handler will log t wo ent ries: one from t he funct ion where t he error originat ed and one from t he ent ry point procedure.

03/30/04 20:44:20 [ErrorHandlingDemo.xls] MSystemCode.bCauseAnError(), Error 11: Division by zero 03/30/04 20:44:20 [ErrorHandlingDemo.xls] MEntryPoints.EntryPoint, Error 9999: Division by zero

Not e t hat t he first error num ber recorded is t he original VBA error num ber, while t he second error num ber ( and any subsequent error num bers) is t he value of our predefined glHANDLED_ERROR const ant . I f t here are m ult iple procedures in t he call st ack when an error occurs, t he cent ral error handler will creat e a log ent ry for each one. This provides helpful inform at ion when debugging an error because it provides a record of t he call st ack at t he t im e t he error occurred. Aft er t he error has been logged and t he error m essage displayed, t he cent ral error handler ret urns cont rol t o t he Ent ryPoint subrout ine so it can com plet e it s cleanup prior t o exit ing.

Practical Example PETRAS Timesheet I n t he Pract ical Exam ple sect ion of t his chapt er, we ret rofit our t im e- ent ry add- in wit h a com plet e cent ralized error handling syst em . This is t he best exam ple t o exam ine if you want t o see how a real- world error handling syst em is const ruct ed. The process of ret rofit t ing our add- in wit h error handling is t edious but uncom plicat ed. All ent ry point procedures are out fit t ed wit h t he ent ry point version of t he error handling code and all subprocedures are convert ed int o Boolean funct ions and out fit t ed wit h t he funct ion version of t he error handling code. The only code exam ple from t he new version of t he PETRAS add- in t hat we show here is t he Aut o_Open procedure, in List ing 12- 13. This is t he ent ry point procedure t hat m akes t he m ost calls t o lower- level procedures. I t also has t he unique requirem ent t o shut down t he applicat ion if an error occurs. This m akes it t he m ost int erest ing exam ple of error handling in t he add- in. You are encouraged t o exam ine t he com plet e revised code for t he PETRAS add- in, locat ed on t he CD in t he Applicat ion folder for t his chapt er, for a com plet e view of t he error handling syst em .

List in g 1 2 - 1 3 . Th e PETRAS Add- in Au t o_ Ope n Pr oce du r e w it h Er r or H a n dlin g Public Sub Auto_Open() Const sSOURCE As String = "Auto_Open" Dim bErrorOut As Boolean Dim wkbBook As Workbook ' The very first thing your application should do upon ' startup is attempt to delete any copies of its ' command bars that may have been left hanging around ' by an Excel crash or other incomplete exit. On Error Resume Next Application.CommandBars(gsBAR_TOOLBAR).Delete On Error GoTo ErrorHandler ' Initialize global variables. If Not bInitGlobals() Then Err.Raise glHANDLED_ERROR ' Assume False until an error is encountered. bErrorOut = False

' Make sure we can locate our time entry workbook before we ' do anything else. If Len(Dir$(gsAppDir & gsFILE_TIME_ENTRY)) = 0 Then _ Err.Raise glHANDLED_ERROR, sSOURCE, gsERR_FILE_NOT_FOUND Application.ScreenUpdating = False Application.EnableEvents = False Application.StatusBar = gsSTATUS_LOADING_APP ' Build the command bars. If Not bBuildCommandBars() Then Err.Raise glHANDLED_ERROR ' Set the initial state of the application. If Not gclsEventHandler.SetInitialStatus() Then _ Err.Raise glHANDLED_ERROR ErrorExit: ' Reset critical application properties. ResetAppProperties ' If an error occurred during the Auto_Open procedure, ' the only option is to exit the application. If bErrorOut Then ShutdownApplication Exit Sub ErrorHandler: ' This variable informs the clean up section when an error ' has occurred. bErrorOut = True If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then Stop Resume Else Resume ErrorExit End If End Sub

This version of t he Aut o_Open procedure is very different from t he version we last saw in Chapt er 8 Advanced Com m and Bar Handling. You will not ice t hat wit h t he except ion of t he Reset AppPropert ies procedure and t he Shut downApplicat ion procedure, every procedure called by Aut o_Open is now a Boolean funct ion whose ret urn value indicat es success or failure. The Reset AppPropert ies procedure is an except ion because it is t he rare case of a procedure in which not hing can go wrong. This t ype of procedure was described in t he Trivial Procedures sect ion above and t he Reset AppPropert ies procedure it self was shown in List ing 12- 8. The Shut downApplicat ion procedure is an except ion because it is t he last procedure run before t he applicat ion closes. Sim ilar t o t he bCent ralErrorHandler funct ion we exam ined in List ing 12- 9, it doesn't m ake any sense t o t ry and handle errors t hat occur in t his procedure, so t he ent ire

Shut downApplicat ion procedure is wrapped in On Error Resume Next. We've also added a new bErrorOut flag variable. This is because t he cleanup sect ion for t he Aut o_Open procedure ( t he sect ion of code bet ween t he ErrorExit label and t he Exit Sub st at em ent ) needs t o know whet her an error has occurred when it is execut ed. The error handler for t he Aut o_Open procedure set s t he bErrorOut variable t o True when an error occurs. I t t hen calls t he cent ral error handler and, aft er t he cent ral error handler ret urns, it redirect s code execut ion t o t he cleanup sect ion, st art ing direct ly below t he ErrorExit label. I f t he bErrorOut variable indicat es t o t he cleanup sect ion t hat an error has occurred, t he cleanup sect ion init iat es applicat ion shut down by calling t he Shut downApplicat ion procedure.

PETRAS Reporting As m ent ioned in t he sect ion Com plex Proj ect Error Handler Organizat ion earlier in t his chapt er, t here are t wo or t hree com plex error handling syst em designs com m only used in Excel VBA applicat ions and several m inor variat ions on each of t hose. Throughout t his chapt er, we've dem onst rat ed t he concept s of error handling using a syst em known as t he fu n ct ion r e t u r n va lu e m et hod. I n t his syst em , every subprocedure is writ t en as a Boolean funct ion whose ret urn value indicat es success or failure. I f an error occurs, it is t rapped in t he funct ion's error handler, which logs t he error and t hen set s t he funct ion's ret urn value t o False. The calling procedure t est s t he ret urn value and ( usually) raises anot her error t o t rigger it s own error handler, and so t he error bubbles up t he call st ack. List ing 12- 14 shows t he order in which lines are execut ed in a nest ed set of procedures.

List in g 1 2 - 1 4 . Th e Or de r of Ex e cu t ion W h e n Usin g t h e Fu n ct ion Re t u r n Va lu e Syst e m Sub EntryPoint() Const sSOURCE As String = "EntryPoint" 1

On Error GoTo ErrorHandler

2 20

If Not bSubProc1() Then Err.Raise glHANDLED_ERROR End If

ErrorExit: 'Run some cleanup code 23 Exit Sub ErrorHandler: 21 If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then Stop Resume Else 22 Resume ErrorExit End If End Sub

Function bSubProc1() As Boolean Const sSOURCE As String = "bSubProc1" Dim bReturn As Boolean 3 4

On Error GoTo ErrorHandler bReturn = True

5 14

If Not bSubProc2() Then Err.Raise glHANDLED_ERROR End If

ErrorExit: 'Run some cleanup code 18 bSubProc1 = bReturn 19 Exit Function ErrorHandler: 15 bReturn = False 16 If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else 17 Resume ErrorExit End If End Function Function bSubProc2() As Boolean Const sSOURCE As String = "bSubProc2" Dim bReturn As Boolean 6 7

On Error GoTo ErrorHandler bReturn = True

8

'Cause an error Debug.Print 1 / 0

ErrorExit: 'Run some cleanup code 12 bSubProc2 = bReturn 13 Exit Function ErrorHandler: 9 bReturn = False 10 If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else 11 Resume ErrorExit End If

End Function

You'll not ice t hat in t he vast m aj orit y of cases, t he calling procedure handles a False ret urn value j ust by raising anot her error t o t rigger it s own error handler. Error handling in VBA is designed such t hat any unhandled errors and any errors raised wit hin an error handler aut om at ically fire t he error handler of t he calling procedure. So if we raise an error wit hin t he subprocedure's error handler, it will aut om at ically t rigger t he calling procedure's error handler, wit hout t he calling procedure having t o t est for a False ret urn value and t rigger t he error handler it self. The sam e will happen if we raise an error at t he end of t he cent ral error handler. This is known as t he r e - t h r ow syst em of error handling and has been im plem ent ed in t he PETRAS report ing applicat ion. The m ain advant ages of t he re- t hrow syst em are t hat we can use it wit hin Sub, Propert y and Funct ion procedures, and our funct ions' ret urn values can be used for t heir result s inst ead of success/ failure indicat ors. The m ain disadvant age is t hat it becom es slight ly harder for us t o include com plex cleanup code if an error occurs. List ing 12- 15 is t aken from t he MErrorHandler m odule of t he PETRASReport ing.xla workbook and shows a m odified cent ral error handler t hat im plem ent s t he re- t hrow syst em by default , but enables us t o override t he re- t hrow behavior in t he except ional cases when we need t o run com plex post - error cleanup code. This is very sim ilar t o List ing 12- 9, wit h t he ext ra code t o im plem ent t he re- t hrow m et hod highlight ed.

List in g 1 2 - 1 5 . A Ce n t r a l Er r or H a n dle r I m ple m e n t in g t h e Re - Th r ow Sy st e m Public Function bCentralErrorHandler( _ ByVal sModule As String, _ ByVal sProc As String, _ Optional ByVal sFile As String, _ Optional ByVal bEntryPoint As Boolean = False, _ Optional ByVal bReThrow As Boolean = True) As Boolean Static sErrMsg As String Dim Dim Dim Dim Dim

iFile As Integer lErrNum As Long sFullSource As String sPath As String sLogText As String

' Grab the error info before it's cleared by ' On Error Resume Next below. lErrNum = Err.Number ' If this is a user cancel, set the silent error flag ' message. This will cause the error to be ignored. If lErrNum = glUSER_CANCEL Then sErrMsg = msSILENT_ERROR

' If this is the originating error, the static error ' message variable will be empty. In that case, store ' the originating error message in the static variable. If Len(sErrMsg) = 0 Then sErrMsg = Err.Description ' We cannot allow errors in the central error handler. On Error Resume Next ' Load the default filename if required. If Len(sFile) = 0 Then sFile = ThisWorkbook.Name ' Get the application directory. sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Construct the fully qualified error source name. sFullSource = "[" & sFile & "]" & sModule & "." & sProc ' Create the error text to be logged. sLogText = " " & sFullSource & ", Error " & _ CStr(lErrNum) & ": " & sErrMsg ' Open the log file, write out the error information and ' close the log file. iFile = FreeFile() Open sPath & msFILE_ERROR_LOG For Append As #iFile Print #iFile, Format$(Now(), "dd mmm yy hh:mm:ss"); sLogText If bEntryPoint Or Not bReThrow Then Print #iFile, Close #iFile ' Do not display or debug silent errors. If sErrMsg msSILENT_ERROR Then ' Show the error message when we reach the entry point ' procedure or immediately if we are in debug mode. If bEntryPoint Or gbDEBUG_MODE Then Application.ScreenUpdating = True MsgBox sErrMsg, vbCritical, gsAPP_TITLE ' Clear the static error message variable once ' we've reached the entry point so that we're ready ' to handle the next error. sErrMsg = vbNullString End If ' The return vale is the debug mode status. bCentralErrorHandler = gbDEBUG_MODE Else ' If this is a silent error, clear the static error ' message variable when we reach the entry point. If bEntryPoint Then sErrMsg = vbNullString bCentralErrorHandler = False

End If 'If we're using re-throw error handling, 'this is not the entry point and we're not debugging, 're-raise the error, to be caught in the next procedure 'up the call stack. 'Procedures that handle their own errors can call the 'central error handler with bReThrow:=False to log the 'error, but not re-raise it. If bReThrow Then If Not bEntryPoint And Not gbDEBUG_MODE Then On Error GoTo 0 Err.Raise lErrNum, sFullSource, sErrMsg End If Else 'Error is being logged and handled, 'so clear the static error message variable sErrMsg = vbNullString End If End Function

List ing 12- 16 shows t he order in which lines are execut ed in a nest ed set of procedures when t he re- t hrow syst em is im plem ent ed.

List in g 1 2 - 1 6 . Th e Or de r of Ex e cu t ion W h e n Usin g t h e Re - Th r ow Syst e m Sub EntryPoint() Const sSOURCE As String = "EntryPoint" 1

On Error GoTo ErrorHandler

2

SubProc1

ErrorExit: 11 Exit Sub ErrorHandler: 'Run simple cleanup code here 9

10

If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then Stop Resume Else Resume ErrorExit End If

End Sub Sub SubProc1() Const sSOURCE As String = "SubProc1" 3

On Error GoTo ErrorHandler

4

SubProc2 Exit Sub

ErrorHandler: 'Run simple cleanup code here 8

If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume End If End Sub Sub SubProc2() Const sSOURCE As String = "bSubProc2" 5

On Error GoTo ErrorHandler

6

'Cause an error Debug.Print 1 / 0 Exit Sub

ErrorHandler: 'Run simple cleanup code here 7

If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume End If End Sub

Using t he re- t hrow m et hod, we can only include cleanup code at t he st art of our error handlers ( before t he call t o t he cent ral error handler) , so we have t o be ext rem ely careful t o ensure t hat t he cleanup code does not cause any m ore errors t o occur and does not reset t he Err obj ect . I n pract ice, t his m eans t he re- t hrow m et hod is best used when t here is no cleanup required, or when t he cleanup is t rivial and could not cause an error. I n List ing 12- 15, we added an opt ional param et er t o t he cent ral error handler t hat enables us t o st op t he error being re- raised. This result s in exact ly t he sam e behavior as t he funct ion ret urn value syst em , t hereby allowing us t o use t hat m et hod in t he except ional cases t hat require com plex

cleanup code. This param et er is used in t he Consolidat eWorkbooks procedure t o handle errors t hat occur while ext ract ing t he dat a from a t im esheet workbook. I n t hat case, we call t he cent ral error handler t o log t he error, t hen close t he problem t im esheet workbook and cont inue wit h t he next one. Whet her t o use t he funct ion ret urn value or re- t hrow syst em of error handling is largely a philosophical decision. Bot h have t heir advant ages and disadvant ages and will be m ore or less appropriat e for different sit uat ions. Eit her syst em is bet t er t han having no error handling at all.

Conclusion I n t his chapt er we've covered a lot of ground t hat m ay be unfam iliar t o m any readers. Look closely at t he sam ple applicat ions for t his chapt er and read t he chapt er again if error handling concept s cont inue t o be unclear. One of t he best ways t o discover how an error handler works is t o use debugging t echniques t o single st ep t hrough an applicat ion as it handles an error. We cover debugging t echniques in det ail in Chapt er 16 VBA Debugging. Aft er reading t hat chapt er, you m ight want t o revisit t his chapt er and exam ine t he sam ple applicat ions in m ore det ail using VBA debugging t echniques.

Chapter 13. Programming with Databases A large percent age of nont rivial Excel applicat ions require som e sort of dat a st ore t hat is separat e from t he rest of t he applicat ion, usually in t he form of a dat abase. I n t his chapt er we cover t he basics of dat abase design and dat a access using SQL and ADO. We do not go int o great det ail on any of t hese t opics. All of t hem are book- lengt h subj ect s in t heir own right . Aft er som e brief int roduct ory m at erial, we dem onst rat e t hese t echnologies by showing how t o use t hem for t heir m ost com m on purposes. At t he end of t he chapt er, we suggest addit ional books t hat you can use for in- dept h st udy of t he t opics we int roduce here.

An Introduction to Databases The biggest problem for Excel- cent ric developers m aking t he j um p t o applicat ions based on a backend dat abase is underst anding t he fundam ent al differences bet ween how dat a is t reat ed in Excel and how dat a is t reat ed in a dat abase. A dat abase requires a significant am ount of rigor from t he dat a when com pared t o an Excel worksheet . You can ent er alm ost anyt hing you want on a worksheet , but dat abase t ables are m uch m ore picky. Even som e of t he t hings you ca n ent er in dat abase t ables you shouldn't . Dat abase t ables have a concept of being form ally relat ed t o each ot her, a concept t hat doesn't exist at all in Excel. Modificat ions m ade t o dat abases t ake effect im m ediat ely. There's no need t o " save" t he dat a. Unfort unat ely, t here's also no way t o undo a change m ade t o dat a in a dat abase once t hat change has been com m it t ed. As you can see, working wit h dat abases is significant ly different from working wit h Excel worksheet t ables. This sect ion covers t he m ost im port ant t hings you need t o know about how dat abases work and why you would want t o use one.

N OTE Those of you who are very fam iliar wit h dat abases and t he t erm inology surrounding t hem will not ice t hat we use som e nonst andard t erm s t o describe dat abase concept s in t his sect ion. This is int ent ional and is designed t o explain t hese concept s in t erm s t hat Excel program m ers wit h lim it ed dat abase experience will find easier t o underst and.

Why Use a Database For m any purposes Excel is a perfect ly adequat e dat a cont ainer. However, cert ain com m on circum st ances will force you t o confront a dat abase. These circum st ances include t he following: An e x ist in g da t a ba se The dat a your Excel applicat ion requires m ay already be st ored in a dat abase. I n t hat case, you'll need t o use t he exist ing dat abase, if for no ot her purpose t han t o ext ract t he dat a your applicat ion requires. Ca pa cit y con st r a in t s An Excel worksheet can hold only a lim it ed am ount of dat a, 65,536 rows t o be exact . I t is not uncom m on for a large applicat ion t o be required t o deal wit h m illion s of rows of dat a. You cannot hope t o st ore t his m uch dat a in Excel, so you are forced t o use a dat abase, which can easily m anage t his volum e of dat a. Ope r a t ion a l r e qu ir e m e n t s Excel is not a m ult iuser applicat ion. I t does have som e very unreliable sharing capabilit ies, but as a general rule, if one person is using an Excel workbook

t hat cont ains dat a, anyone else who want s t o use it m ust wait for t hat person t o finish. Dat abases, by cont rast , are inherent ly m ult iuser applicat ions. They are designed from t he ground up t o allow m any people t o access t he sam e dat a at t he sam e t im e. I f your applicat ion requires m ult iple users t o access t he sam e dat a at t he sam e t im e, t hen you probably need a dat abase.

Relational Databases A relat ional dat abase is a set of t ables cont aining dat a organized int o specific cat egories. Each t able cont ains dat a cat egories in colum ns. Each row cont ains a unique inst ance of dat a for t he cat egories defined by t he colum ns. A relat ional dat abase is st ruct ured such t hat dat a can be accessed in m any different ways wit hout having t o reorganize t he t ables. A relat ional dat abase also has t he im port ant advant age of being easy t o ext end. Aft er t he original dat abase has been creat ed, new t ables can be added wit hout requiring all exist ing applicat ions t hat use t he dat abase t o be m odified. The st andard m et hod used t o access relat ional dat a is St ruct ured Query Language ( SQL) , which we describe in t he Dat a Access Techniques sect ion lat er in t he chapt er.

File-Based Databases vs. Client-Server Databases There are t wo broad cat egories of relat ional dat abases: file- based dat abases and client - server dat abases. The fundam ent al difference bet ween t hem has t o do wit h where t he dat a access logic is execut ed. I n a file- based dat abase, t he dat abase consist s of one or m ore files t hat sim ply cont ain t he dat a. When an applicat ion accesses a file- based dat abase, all of t he dat a access logic is execut ed on t he client com put er where t he applicat ion resides. The advant ages of file- based dat abases are t hat t hey are inexpensive, relat ively sim ple and require lit t le ongoing m aint enance. The disadvant ages of file- based dat abases are t hat t hey can creat e significant net work t raffic, t hey are lim it ed in t he am ount of dat a t hey can st ore and lim it ed in t he num ber of sim ult aneous users who can access t hem . Microsoft Access and Microsoft Visual FoxPro are t wo exam ples of file- based dat abases. I n a client - server dat abase, dat abases are cont ained wit hin a larger server applicat ion. This dat abase server is responsible for execut ing t he dat a access request s from client applicat ions. The advant ages and disadvant ages of client server dat abases are m ore or less t he m irror im age of t hose for file- based dat abases. Client server dat abases reduce net work t raffic by handling t he dat a access logic on t he server. They can st ore very large am ount s of dat a and handle very large num bers of sim ult aneous users. However, client - server dat abases are expensive, com plex and require rout ine m aint enance t o keep t hem operat ing efficient ly. Microsoft SQL Server and Oracle are t wo exam ples of client - server dat abases.

Normalization Norm alizat ion is t he process of opt im izing t he dat a in your dat abase t ables. I t s goal is t o elim inat e redundant dat a and ensure t hat only relat ed dat a is st ored in each t able. Norm alizat ion can be t aken t o ext rem e lengt hs. But for m ost developers m ost of t he t im e, underst anding t he first t hree rules of norm alizat ion and ensuring t hat your dat abase is in t hird norm al form is all you'll ever need t o do. ( We cover t he first t hree norm al form s in det ail in t he sect ions t hat follow.)

N OTE Prior t o norm alizing your dat a, you m ust be sure all of t he rows in every t able are unique. A dat abase t able should not cont ain duplicat e rows of dat a and norm alizat ion will not correct t his problem .

Before we can t alk about norm alizat ion, we need t o cover t he concept of a pr im a r y k e y . A prim ary key consist s of one or m ore colum ns in a dat a t able whose value( s) uniquely ident ify each row in t he t able. Let 's t ake a look at a sim ple exam ple. Figure 13- 1 shows a dat abase t able cont aining a list of aut hor inform at ion.

Figu r e 1 3 - 1 . Th e Au t h or s Ta ble

Not ice t hat t here are t wo inst ances of t he nam e Robert in t he First Nam e colum n. These nam es refer t o t wo different people, but if you were t rying t o use only t his colum n t o ident ify rows t here would be no way t o dist inguish t hese from duplicat e ent ries. To uniquely ident ify rows in t his t able, we m ust designat e t he First Nam e a n d Last Nam e colum ns as t he prim ary key. I f you com bine t he values of t hese t wo colum ns t here is no longer any duplicat ion, so all rows are uniquely ident ified. I n t he t ext t hat follows, prim ary key colum ns are oft en referred t o sim ply as k e y colu m n s, whereas any colum ns t hat do not belong t o t he prim ary key are referred t o as n on k e y colu m n s. For our discussion of norm alizat ion, we use t he BillableHours t able shown in Figure 13- 2. This t able cont ains dat a t hat m ight have been ext ract ed from one of our PETRAS t im e- ent ry workbooks. As it st ands, t his dat a is very denorm alized and not suit able for use in a relat ional dat abase. The prim ary key for t his t able consist s of t he com binat ion of t he Consult ant , Dat e, Proj ect and Act ivit y colum ns.

Figu r e 1 3 - 2 . Th e I n it ia l Billa ble H ou r s Ta ble [View full size image]

First Normal Form There are t wo requirem ent s a dat a t able m ust m eet t o sat isfy t he first norm al form :

1 . All colum n values are a t om ic. This m eans t here are no values t hat can be split int o sm aller m eaningful part s. We have one colum n t hat obviously violat es t his requirem ent . The Consult ant colum n consist s of bot h t he first nam e and t he last nam e of each consult ant . This dat a m ust be separat ed int o t wo dist inct colum ns, First Nam e and Last Nam e, t o sat isfy t he first norm al form . 2 . Repeat ing groups of dat a should be elim inat ed by m oving t hem int o new t ables. The Consult ant colum n, even aft er separat ing it int o first nam e and last nam e, violat es t his requirem ent . The solut ion is t o creat e a separat e Consult ant s t able t o hold t his dat a. Each consult ant will be assigned a unique consult ant I D num ber t hat will be used in t he BillableHours t able t o ident ify t he consult ant . The result of t ransform ing our BillableHours t able int o first norm al form is t wo t ablest he m odified BillableHours t able shown in Figure 13- 3 and t he new Consult ant s t able shown in Figure 13- 4. The first colum n in t he BillableHours t able, which previously held each consult ant 's nam e, has been replaced wit h a unique Consult ant I D num ber creat ed in t he new Consult ant s t able.

Figu r e 1 3 - 3 . Th e Billa ble H ou r s Ta ble in Fir st N or m a l For m [View full size image]

Figu r e 1 3 - 4 . Th e N e w Con su lt a n t s Ta ble

This not only allows us t o sat isfy first norm al form , but also allows us t o handle t he sit uat ion in which t wo consult ant s have t he sam e first and last nam es. I n t he original t able t here would have been no way t o dist inguish bet ween t wo consult ant s wit h t he sam e nam e. Before we go any furt her we m ust explain t he concept of a for e ign k e y . A foreign key is a colum n in one t able t hat uniquely ident ifies records in som e ot her t able. I n t he case above, t he Consult ant I D colum n in t he BillableHours t able is a foreign key colum n, each of whose values ident ify a single, unique consult ant in t he new Consult ant s t able. The use of foreign keys is ubiquit ous in relat ional dat abases. As we will see in t he upcom ing sect ion on Relat ionships and Referent ial I nt egrit y , foreign keys are used t o creat e connect ions bet ween relat ed t ables in a dat abase.

Second Normal Form

There are t wo requirem ent s a dat a t able m ust m eet t o sat isfy t he second norm al form :

1 . The t able m ust be in first norm al form . Each successive norm al form builds upon t he previous norm al form . Because our BillableHours t able is already in first norm al form , t his requirem ent has been sat isfied. 2 . Each colum n in t he t able m ust depend on t he whole prim ary key. This m eans if any colum n in t he prim ary key were rem oved, you could no longer uniquely ident ify t he rows in any nonkey colum n in t he t able. The prim ary key in our BillableHours t able consist s of a com binat ion of t he Consult ant I D, Dat e, Proj ect and Act ivit y colum ns. Do we have any colum ns t hat are not dependent on all four of t hese key colum ns? Yes. The Client colum n depends only on t he Proj ect colum n, because a proj ect nam e uniquely ident ifies t he client for whom t he proj ect is com plet ed. To solve t his problem we will rem ove t he client colum n from t he BillableHours t able and creat e a new Client s t able. We will also creat e a new Proj ect s t able t hat provides each proj ect wit h a unique I D num ber, and use t his proj ect I D rat her t han t he proj ect nam e in t he BillableHours t able. This will serve t wo purposes. The new Proj ect s t able will provide a link from t he BillableHours t able t o t he Client s t able ( which we discuss in m ore det ail lat er in t he chapt er) . I t will also enable us t o handle t he sit uat ion in which t wo client s have t he sam e proj ect nam e. The result of t ransform ing our BillableHours t able int o second norm al form is t hree t ables. The m odified BillableHours t able, shown in Figure 13- 5, t he new Client s t able, shown in Figure 13- 6, and t he new Proj ect s t able, shown in Figure 13- 7 ( t his is in addit ion t o t he Consult ant s t able we creat ed in t he previous sect ion) .

Figu r e 1 3 - 5 . Th e Billa ble H ou r s Ta ble in Se con d N or m a l For m [View full size image]

Figu r e 1 3 - 6 . Th e N e w Clie n t s Ta ble

Figu r e 1 3 - 7 . Th e N e w Pr oj e ct s Ta ble

N OTE The sharp- eyed am ong you m ay have not iced t hat t he Rat e colum n in t he BillableHours t able also violat es second norm al form . This is absolut ely correct , so give yourself a gold st ar if you caught t his. However, t his colum n is part of such a good exam ple for dem onst rat ing t hird norm al form t hat we've decided t o post pone it for t hat t opic.

Third Normal Form There are t hree requirem ent s a dat a t able m ust m eet t o sat isfy t hird norm al form :

1 . The t able m ust be in second norm al form . This requirem ent has been m et by t he m odificat ions we m ade in t he previous sect ion.

2 . Nonkey colum ns cannot describe ot her nonkey colum ns. This requirem ent can be m em orably expressed as " Nonkey colum ns m ust represent t he key, t he whole key and not hing but t he key." I n our BillableHours t able, t he Rat e colum n depends only on t he Act ivit y key colum n. All t he ot her key colum ns could be rem oved from t he t able and t he values in t he Rat e colum n could st ill be uniquely associat ed wit h t he rem aining Act ivit y colum n. We can solve t his problem by creat ing a new t able t o hold t he list of Act ivit ies and t heir associat ed rat es. The BillableHours t able will ret ain only an act ivit y I D num ber in place of t he previous Act ivit y and Rat e colum ns. 3 . The t able cannot cont ain de r ive d da t a . Derived dat a refers t o a colum n in a dat a t able whose values have been creat ed by applying a form ula or t ransform at ion t o t he values in one or m ore ot her colum ns in t he t able. I n our BillableHours t able, t he Charge colum n is a derived colum n t hat is t he result of m ult iplying t he Rat e colum n by t he Hours colum n. Colum ns cont aining derived dat a should sim ply be rem oved from t he t able and calculat ed " on t he fly" whenever t heir values are required. The result of t ransform ing our BillableHours t able int o t hird norm al form is t wo t ables: t he m odified BillableHours t able, shown in Figure 13- 8 and t he new Act ivit ies t able shown in Figure 13- 9.

Figu r e 1 3 - 8 . Th e Billa ble H ou r s Ta ble in Th ir d N or m a l For m

Figu r e 1 3 - 9 . Th e N e w Act ivit ie s Ta ble

Not e t hat our t hird norm al form BillableHours t able consist s of a set of prim ary key colum ns, t he Consult ant I D, Dat e, Proj ect I D and Act ivit yI D colum ns, and a nonkey Hours colum n t hat depends on t he ent ire prim ary key and not hing but t he prim ary key. I f any prim ary key colum n were rem oved from t he t able, it would no longer be possible t o uniquely ident ify any of t he ent ries in t he Hours colum n. Because t here are no ot her nonkey colum ns in t he t able, t he Hours colum n cannot possibly depend on any nonkey colum ns. Our dat a is now ready t o be used in a relat ional dat abase.

When Not to Normalize I n t he vast m aj orit y of cases, you will always want t o follow t he norm alizat ion rules out lined above when preparing your dat a for st orage in a relat ional dat abase. As wit h alm ost every ot her rule, however, t here are except ions. The m ost com m on except ion has t o do wit h derived colum ns. When we t ransform ed our BillableHours t able int o t hird norm al form we elim inat ed t he derived colum n t hat showed t he t ot al charge for each line it em . This is generally a good pract ice because if you have derived colum ns you m ust also creat e logic t o ensure t hose colum ns are updat ed correct ly if t he values of any of t he colum ns t hey depend on change. This creat es overhead t hat is best deferred unt il you act ually need t o query t he derived value. I n som e cases, however, it m akes sense t o st ore derived dat a. This is usually t he case when t he dat a is derived from colum ns t hat are very unlikely t o change. I f t he colum ns t hat t he derived dat a depends on are unlikely t o change, t he derived dat a is also unlikely t o change. I n t his case you can im prove t he perform ance of queries t hat access t he derived dat a by calculat ing it in advance and st oring t he result so t he query can sim ply ret rieve it s value rat her t han having t o calculat e it on t he fly.

Relationships and Referential Integrity The abilit y t o t ake advant age of r e la t ion sh ips and r e fe r e n t ia l in t e gr it y are t wo of t he prim ary advant ages t hat relat ional dat abases provide over Excel for dat a st orage. The abilit y t o creat e form al relat ionships bet ween t ables enables you t o avoid m assive repet it ion of dat a and it s associat ed frequency of dat a- ent ry errors t hat lead t o bad or " dirt y" dat a. Referent ial int egrit y enables you t o ensure t hat dat a ent ered in one t able is consist ent wit h dat a ent ered in ot her relat ed t ables. Neit her one of t hese capabilit ies is available t o dat a st ored in Excel.

Foreign Keys Before we can discuss relat ionships and referent ial int egrit y, we need t o have a firm underst anding of foreign keys. A foreign key is a colum n in one t able ( t he r e fe r e n cin g t able) cont aining dat a t hat uniquely ident ifies records from anot her t able ( t he r e fe r e n ce d t able) . The foreign key serves t o connect t he t wo t ables and ensures t hat only valid dat a from t he referenced t able can be ent ered in t he referencing t able. The Act ivit yI D colum n in t he BillableHours t able shown in Figure 13- 8 is a foreign key t hat refers t o t he Act ivit yI D colum n in t he Act ivit ies t able in Figure 13- 9.

For a colum n t o serve as a foreign key, it m ust eit her be t he prim ary key of t he referenced t able or a colum n on which a unique index has been defined. We cover unique indexes lat er in t he chapt er. A foreign key can also consist of m ult iple colum ns, as long as t he const raint s above are followed. Foreign keys provide t he basis of creat ing relat ionships bet ween t ables. I n t his sect ion we will be using t he Microsoft Access Relat ionships window t o visually display t he effect of relat ionships and referent ial int egrit y. Figure 13- 10 shows t he relat ionship described above bet ween t he BillableHours t able and t he Act ivit ies t able. Each t able's prim ary key colum ns are shown in bold.

Figu r e 1 3 - 1 0 . Th e Re la t ion sh ip Be t w e e n t h e Billa ble H ou r s a n d Act ivit ie s Ta ble s

Types of Relationships The vast m aj orit y of relat ionships bet ween dat abase t ables fall int o one of t hree cat egories: one t o one, one t o m any, and m any t o m any.

One to One I n t his t ype of relat ionship, each row in one t able is associat ed wit h a single row in anot her t able. One- t o- one relat ionships are not frequent ly encount ered. The m ost com m on reason for creat ing a one- t o- one relat ionship is t o divide a single t able int o it s m ost frequent ly accessed sect ions and least frequent ly accessed sect ions. This can im prove perform ance by m aking t he m ost frequent ly accessed t able sm aller. All t hings being equal, t he rows in a sm all t able can be accessed m ore quickly t han t he rows in a large t able. A sm aller t able is also m ore likely t o rem ain in m em ory or require less bandwidt h t o t ransfer t o t he client depending on t he t ype of dat abase being used. Consider t he hypot het ical Part s t able shown in Figure 13- 11.

Figu r e 1 3 - 1 1 . Th e Pa r t s Ta ble

Assum e t his t able has a very large num ber of rows, and t he only colum ns you want t o access in m ost cases are t he Part Num ber, Part Nam e, Unit Price and Weight colum ns. You can im prove t he perform ance of queries against your Part s t able by dividing it int o t wo t ables, wit h t he m ost frequent ly accessed colum ns in one t able and t he rest in a second t able. Each row in t hese t wo new t ables will be relat ed t o exact ly one row in t he ot her t able and t he t wo t ables will share a prim ary key. The result of t his part it ioning is shown in Figure 13- 12.

Figu r e 1 3 - 1 2 . Th e Pa r t s Ta ble D ivide d in t o Tw o Ta ble s w it h a On e - t o- On e Re la t ion sh ip

The Access Relat ionship window indicat es a one- t o- one relat ionship by placing t he num ber 1 on each side of t he relat ionship line connect ing t he t wo t ables.

One to Many This is by far t he m ost com m on t ype of relat ionship. I n a one- t o- m any relat ionship, a single row in one t able can be relat ed t o zero, one or m any rows in anot her t able. As Figure 13- 13 shows, every relat ionship creat ed in t he process of norm alizing our BillableHours t able is a one- t o- m any r elat ionship.

Figu r e 1 3 - 1 3 . On e - t o- M a n y Re la t ion sh ips

The Access Relat ionship window indicat es a one- t o- m any relat ionship by placing t he num ber 1 on t he one side of t he relat ionship line and t he infinit y sym bol on t he m any side of t he relat ionship line. Each row in t he Consult ant s, Proj ect s and Act ivit ies t able can be relat ed t o zero, one or m any rows in t he BillableHours t able. The one or m any part of t he relat ionship should be obvious; t he zero part m ay require som e addit ional explanat ion. I f a new consult ant has j oined t he com pany but not yet logged any billable hours, t hat consult ant would be represent ed by a row in t he Consult ant s t able. However, t he row represent ing t he new consult ant would not be associat ed wit h any rows in t he BillableHours t able. The Consult ant s t able would have a one- t o- m any relat ionship wit h t he BillableHours t able, and t he row represent ing t he new consult ant in t he Consult ant s t able would be associat ed wit h zero rows in t he BillableHours t able.

N OTE Som e of you m ay be t hinking t hat Excel's dat a- validat ion list feat ure provides t he sam e benefit as a one- t o- m any dat abase relat ionship. Unfort unat ely, t his is not t rue. Alt hough it 's a very useful feat ure, a dat a- validat ion list only enforces a one- t im e relat ionship

check, at t he t im e an ent ry is select ed from t he list . Unlike a dat abase relat ionship, aft er an ent ry has been select ed from a dat a- validat ion list it does not m aint ain any connect ion t o t he list from which it was select ed.

Many to Many I n t his t ype of relat ionship, each row in one t able can be relat ed t o m ult iple rows in t he ot her t able. This concept can be a bit difficult t o visualize. We dem onst rat e it by ext ending t he exam ple we used in t he Nor m alizat ion sect ion t o include t he role each consult ant plays on each proj ect . Our list of roles m ight look like t he Roles t able shown in Figure 13- 14.

Figu r e 1 3 - 1 4 . Th e Role s Ta ble

Each proj ect will require m ult iple roles in order t o com plet e it , and consult ant s will serve in different roles on different proj ect s. A consult ant m ight be a program m er on one proj ect and a t est er on anot her. On a sm all proj ect , in fact , one consult ant could very well serve m ult iple roles. This m eans t hat role inform at ion cannot be at t ached t o eit her t he Proj ect s t able or t he Consult ant s t able because t here are m any- t o- m any relat ionships bet ween proj ect s and roles as well as consult ant s and roles. Each proj ect requires m ult iple roles and each role applies t o m ult iple proj ect s. Likewise, each consult ant can serve m ult iple roles and each role can be served by m ult iple consult ant s. Most relat ional dat abases cannot direct ly represent a m any- t o- m any relat ionship. When t his t ype of relat ionship is encount ered, however, it can always be broken up int o m ult iple one- t o- m any relat ionships linked by an int erm ediat e t able. I n our Proj ect s, Consult ant s and Roles exam ple, t he m any- t o- m any relat ionships would be represent ed in t he dat abase as shown in Figure 13- 15.

Figu r e 1 3 - 1 5 . M a n y- t o- M a n y Re la t ion sh ips Re solve d in t o On e - t o- M a n y Re la t ion sh ips [View full size image]

The Proj ect Consult ant Role t able serves as t he int erm ediat e t able t hat enables us t o convert t he m any- t o- m any relat ionships bet ween t he Proj ect s and Roles t ables and t he Consult ant s and Roles t ables int o one- t o- m any relat ionships wit h t he Proj ect Consult ant Role t able in t he m iddle. The Proj ect s, Consult ant s and Roles t ables now have one- t o- m any relat ionships wit h t he Proj ect Consult ant Role t able, allowing t he m any- t o- m any relat ionships bet ween t he Proj ect s and Roles t ables and t he Consult ant s and Roles t ables t o be im plem ent ed.

Referential Integrity Aft er your dat abase has been fully norm alized and you have est ablished relat ionships am ong your t ables, referent ial int egrit y ensures t hat t he dat a in t hose t ables rem ains valid when dat a is added, m odified or delet ed. I n Figure 13- 13, for exam ple, referent ial int egrit y ensures t hat invalid rows cannot be added t o t he BillableHours t able by enforcing t he fact t hat t he Consult ant I D, Proj ect I D and Act ivit yI D foreign key colum ns all refer t o valid rows in t heir respect ive source t ables. ( The validit y of t he Dat e and Hours colum ns is ensured by dom ain const raint s t hat can be added t o t hose colum ns. The t opic of dom ain const raint s is beyond t he scope of t his chapt er.)

N OTE All m odern relat ional dat abases support t he concept of referent ial int egrit y, but t he st eps required t o im plem ent it are com plet ely different from one dat abase t o t he next . Consult t he docum ent at ion for your dat abase t o det erm ine how t o im plem ent referent ial int egrit y.

Natural vs. Artificial Primary Keys

There is an ongoing debat e wit hin t he dat abase com m unit y over whet her t he prim ary key for a t able should be nat ural, which is t o say it should consist of one or m ore colum ns t hat nat urally occur in t he t able, or whet her it should be art ificial. An art ificial key is a unique but ot herwise m eaningless num ber t hat is aut om at ically added t o each row in a t able. Most m odern relat ional dat abases provide a special colum n t ype t hat will aut om at ically generat e a unique num ber for every row added t o a t able. To oversim plify t he debat e, nat ural keys t end t o be advocat ed by people who prim arily design dat abases, whereas art ificial keys t end t o be advocat ed by people who m ust live and work wit h dat abases. The argum ent really com es down t o t wo point s: providing easily usable foreign keys and ensuring t he t rue uniqueness of records in a t able. The form al t ask of a prim ary key can be divided int o t wo very sim ilar but subt ly different t asks: uniquely ident ifying each row in a t able and ensuring every row in a t able is unique. The first t ask provides a foreign key t hat can be used by ot her t ables t o uniquely ident ify a specific row in a t able while t he second t ask enforces dat a int egrit y by ensuring t hat you cannot creat e duplicat e records in a t able. When you have a t able wit h a prim ary key t hat is perform ing bot h t asks sim ult aneously, problem s begin t o arise when you need t o reference t hat t able from anot her t able t hrough t he use of a foreign key. Take, for exam ple, our BillableHours t able. This t able requires t he use of four colum ns t o const ruct a nat ural prim ary key. I f you need t o reference t he BillableHours t able from anot her t able in your dat abase, you will need t o add a foreign key t o t hat t able consist ing of all four of t hese colum ns. This is because all four colum ns are required t o uniquely ident ify a record in t he BillableHours t able. As you can im agine, t his can becom e very unwieldy. Assum e we have an I nvoices t able t hat needs t o reference t he BillableHours t able. An exam ple of how t his would be accom plished using a nat ural key is shown in Figure 13- 16.

Figu r e 1 3 - 1 6 . Usin g a N a t u r a l Ke y for t h e Billa ble H ou r s Ta ble

The alt ernat ive is t o separat e t he t wo t asks of t he prim ary key bet ween t wo different const ruct s. The t ask of uniquely ident ifying a row in t he t able can be accom plished wit h a single colum n t hat provides a unique num ber for each row. This colum n becom es t he prim ary key for t he t able. When

you need t o reference t his t able from anot her t able, t he only colum n you will need t o im port as t he foreign key is t he single num eric prim ary key colum n. I n Figure 13- 17 we have added an art ificial prim ary key t o t he BillableHours t able. This is j ust a num ber t hat uniquely ident ifies each row in t he t able. See how m uch sim pler t his m akes t he t ask of referencing a record in t he BillableHours t able from t he I nvoices t able.

Figu r e 1 3 - 1 7 . Usin g a n Ar t ificia l Ke y for t h e Billa ble H ou r s Ta ble

I f all we did was creat e an art ificial prim ary key consist ing of an aut om at ically generat ed unique value t hat had no real m eaning, you could easily ent er t wo com plet ely ident ical rows in t he BillableHours t able and t he dat abase would m ake t hem art ificially unique by creat ing a unique value in t he art ificial prim ary key colum n. The t ask of ensuring dat a uniqueness can be accom plished wit h a unique index. A unique index is a special const ruct you can creat e t hat includes one or m ore colum ns in a t able. The values in t he colum n( s) on which t he unique index is defined m ust be unique. The index will not allow duplicat e values t o be ent ered. I n t he case of our BillableHours t able, a unique index would include t he Consult ant I D, Dat e, Proj ect I D and Act ivit yI D colum ns. Not e t hat t hese colum ns are t he colum ns t hat originally form ed t he nat ural prim ary key. At t he risk of ant agonizing t hose on t he opposit e side of t his debat e, we recom m end t he use of art ificial prim ary keys. Art ificial prim ary keys m ake dat abase const ruct ion and use m uch sim pler in pract ice, and you can easily enforce t rue uniqueness in every t able by creat ing a unique index on t he colum ns t hat would ot herwise form t he nat ural prim ary key.

N OTE All m odern relat ional dat abases support t he creat ion of unique indexes, but t he m et hod used t o creat e t hem is com plet ely different from one dat abase t o t he next . Consult t he docum ent at ion for your dat abase t o det erm ine how t o creat e unique indexes on a t able.

Designing the Data Access Tier As you saw in Chapt er 3 Excel and VBA Developm ent Best Pract ices, t he dat a access code in an applicat ion form s a unique logical t ier t hat should be separat ed from t he ot her applicat ion t iers. The m ain reason for t his is over t he lifet im e of a nont rivial Excel applicat ion, t he dat a- st orage m echanism is very likely t o change. For exam ple, when dat a- st orage requirem ent s are sim ple, dat a can be st ored in an Excel workbook. As t he am ount of dat a and t he num ber of users who need t o access it grows, a file- based dat abase m ay be required. Som e applicat ions will grow so large and at t ract so m any users t hat t heir dat a access needs can only be m et by a client - server dat abase. Your applicat ion should be designed so changes in t he dat a access t ier have a m inim al im pact on t he rest of t he applicat ion when m oving from one dat a st orage m echanism t o anot her. Applicat ion t iers ot her t han t he dat a access t ier should have no knowledge or im plicit reliance on any part icular dat a st orage m echanism . I t is t he j ob of t he dat a access t ier t o abst ract away t he part icular dat a st orage m echanism used and present all dat a t o t he business logic t ier in t he sam e form at , regardless of whet her t he dat a com es from a local Excel workbook or a rem ot e SQL Server dat abase. I n an ideal design, t he public m et hods of t he dat a access t ier will be driven by t he needs of t he business logic t ier. The business logic t ier should be able t o call t he dat a access t ier t o ret rieve, input , updat e or delet e dat a in a m anner t hat reflect s t he applicat ion logic. The applicat ion logic will be t ranslat ed int o t he specific act ions required t o accom plish t he physical t ask on what ever dat a st orage m echanism is in use. I f possible, all dat a should be t ransferred bet ween t he business logic t ier and t he dat a access t ier by way of user- defined t ypes. Use ADO recordset s if absolut ely necessary, but be aware t hat t he use of recordset s int roduces som e undesired linkages bet ween business logic and dat a access t iers, in t he form of t he physical ordering of t he dat a in t he recordset , for exam ple. ADO will be described in m ore det ail in t he next sect ion.

Data Access with SQL and ADO An Introduction to ActiveX Data Objects (ADO) ADO is t he dat a access t echnology designed by Microsoft t o m ake dat a access as sim ple and t ransparent as possible, regardless of how or where t he dat a is st ored. Previous dat a access t echnologies, m ost not ably DAO and ODBC, are st ill in use. However, t hese t echnologies have been officially deprecat ed, m eaning t hat Microsoft will no longer enhance t hem and m ay drop support for t hem at any t im e. For several years, as of t his writ ing, ADO has been t he sole designat ed dat a access t echnology for now and t he fut ure.

Data Access Technology Defined A dat a access t echnology such as ADO can be t hought of as a connect or bet ween your applicat ion and t he dat a- st orage m echanism it uses. ADO allows your applicat ion t o " t alk" t o dat abases in t he VBA program m ing language. You do st ill need t o underst and t he use of SQL, which will be discussed t hroughout t he rest of t his chapt er, but you do not need t o underst and t he low- level API s required t o t ranslat e SQL- based request s bet ween VBA and t he t arget dat a- st orage applicat ion. ADO abst ract s t hese low- level requirem ent s int o a set of com m on obj ect s, propert ies and m et hods t hat are used in t he sam e way no m at t er what dat a- st orage applicat ion you're working wit h.

N OTE For sim ple applicat ions where t he dat a is st ored ent irely wit hin open Excel workbooks, you will rarely need t o use a separat e dat a access t echnology such as ADO. VBA will do t he j ob quit e nicely. However, your dat a access code should st ill be separat ed int o it s own logical t ier in order t o m inim ize t he num ber of problem s you'll encount er if you need t o m ove t o a dat a st orage m echanism t hat does require t he use of ADO.

How does ADO accom plish t his? I t operat es t hrough a lower- level t echnology called OLE DB. You can t hink of OLE DB as ADO for C+ + program m ers. OLE DB cannot be used direct ly from VBA, but ADO t ranslat es t he OLE DB dat a access m echanism s int o a form VBA underst ands. The root of OLE DB's abilit y t o m ake all dat a st orage applicat ions look t he sam e is a com ponent called a pr ovide r . There is an OLE DB provider for each dat a- st orage applicat ion. This provider t ranslat es t he unique, low- level API s of t hat applicat ion int o a com m on OLE DB int erface. ( The concept of int erfaces is covered ext ensively in Chapt er 11 I nt erfaces.) Providers for t he m ost com m only used dat abases are packaged wit h ADO.

I f you need t o use ADO t o access a dat abase for which a provider has not been supplied, t here are t wo pot ent ial opt ions. You can obt ain a nat ive OLE DB provider for t hat dat abase from a t hird- part y vendor if one is available. I f no t hird- part y provider is available you can fall back on t he OLE DB provider for ODBC. ODBC was an early indust ry st andard low- level dat a access t echnology pioneered by Microsoft . Any dat abase applicat ion t hat support s ODBC can be accessed by ADO using t he OLE DB provider for ODBC. We discuss t he t opic of providers from an ADO point of view in m ore det ail lat er in t his sect ion.

ADO Objects ADO is built on a very sim ple yet ext rem ely flexible obj ect m odel. For t he vast m aj orit y of purposes you will require only t hree t op- level obj ect s: Connect ion, Com m and and Recordset , and t hree collect ions t hat belong t o t hese t op- level obj ect s: Errors, Param et ers and Fields. The t op- level obj ect s are not organized hierarchically. Rat her t hey can each be creat ed and used along wit h or independent ly of t he ot hers. As shown in Figure 13- 18, t he core ADO obj ect m odel can be visualized as a t riangle am ong t he t hree t op- level obj ect s wit h t he collect ions at t ached t o t he t oplevel obj ect t hey belong t o.

Figu r e 1 3 - 1 8 . Th e Cor e AD O Obj e ct M ode l

A brief descript ion of t he general purpose of each obj ect and collect ion is provided below. We show specific code exam ples t hat use each of t hese obj ect s and collect ions lat er in t he chapt er.

Top-Level Objects Con n e ct ion The prim ary purpose of t he Connect ion obj ect is exact ly what it s nam e im plies:

connect ing t o a dat abase. I n keeping wit h t he flexibilit y of ADO, however, a Connect ion obj ect can be used t o execut e SQL st at em ent s or st ored procedures direct ly. Com m a n d The Com m and obj ect is t ypically used t o execut e SQL st at em ent s or st ored procedures t hat do not ret urn dat a and/ or require param et ers. Re cor dse t The Recordset obj ect is used t o execut e SQL st at em ent s or st ored procedures t hat will ret urn dat a t o your applicat ion.

Collections Er r or s The Errors collect ion is used by ADO t o ret urn any errors generat ed by t he provider used t o connect t o t he dat a source. These errors are not ADO errors. ADO obj ect s generat e runt im e errors. Pa r a m e t e r s The Param et ers collect ion is used t o st ore t he variable argum ent s t hat will be passed t o a SQL st at em ent or st ored procedure. This allows you t o const ruct a reusable Com m and obj ect cont aining all t he st at ic inform at ion t o which you sim ply pass different param et ers for each call. Fie lds The Fields collect ion is used t o access t he dat a cont ained in a Recordset obj ect . A recordset can be t hought of as cont aining a t able in which only one row is act ive at a t im e. The Fields collect ion exposes t he values in t he colum ns corresponding t o t he act ive row.

Connecting to Data Sources Before you can do anyt hing wit h t he dat a in a dat a source you m ust est ablish a connect ion t o t he dat a source. As wit h m ost t asks involving ADO, t here is m ore t han one way t o do t his. A connect ion can be specified by set t ing individual propert ies of an ADO Connect ion obj ect or by grouping all t he required propert ies int o a con n e ct ion st r in g. We will dem onst rat e how t o est ablish connect ions using connect ion st rings. A connect ion st ring t ells ADO what provider t o use, what dat a source t o connect t o and any ot her det ails required t o est ablish t he connect ion ( a user nam e and password, for exam ple) . A connect ion st ring consist s of a series of propert y- value pairs, each followed by a sem icolon. The first propert y specified in your connect ion st ring should be t he Pr ovide r propert y. This t ells ADO what provider you want t o use. The provider det erm ines t he st ruct ure of t he rest of t he connect ion st ring. Each provider has a unique set of addit ional propert ies, som e of which are required and som e of which are opt ional. I f no provider is specified, t he default provider is t he OLE DB provider for ODBC. This is for backward com pat ibilit y wit h old- st yle ODBC connect ion st rings. This is rarely t he provider you want t o use, so always specify t he provider in your connect ion st rings. Sam ple connect ion st rings for several com m on dat a sources are shown below.

Access

The OLE DB Provider for Microsoft Jet is used t o connect t o Access dat abases. The synt ax for a t ypical connect ion st ring t o an Access dat abase is shown in List ing 13- 1.

List in g 1 3 - 1 . An Acce ss D a t a ba se Con n e ct ion St r in g Dim sConnect As String sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=C:\Files\MyDatabase.mdb;" & _ "User ID=UserName;" & _ "Password=Password;"

As you can see, t he first argum ent specifies t he provider you want t o use. Aft er you have specified t he OLE DB Provider for Microsoft Jet , t he only ot her propert y t hat is always required is t he Dat a Source propert y. This t ells OLE DB where t he Access dat abase you want t o connect t o is locat ed. I f your Access dat abase is password- prot ect ed, you can pass it t he user nam e and password required t o open it using t he User I D and Password propert ies.

N OTE Microsoft has deprecat ed t he OLE DB Provider for Microsoft Jet . This m eans t hat it st ill works but is no longer act ively dist ribut ed and t hat support for it will end at som e point in t he fut ure. ADO version 2.5 was t he last version of ADO wit h which t his provider was dist ribut ed. I f you or your users do not have t his version of ADO inst alled, you can download it from t he Microsoft Web sit e at ht t p: / / m sdn.m icr osoft .com / dow nloads/ .

SQL Server The OLE DB Provider for SQL Server is used t o connect t o SQL Server dat abases. The base connect ion st ring synt ax for t his provider is shown in List ing 13- 2.

List in g 1 3 - 2 . Ba se Con n e ct ion St r in g Syn t a x for SQL Se r ve r Dim sConnect As String sConnect = "Provider=SQLOLEDB;" & _ "Data Source=Server\Instance;" & _ "Initial Catalog=DatabaseName;"

The D a t a Sou r ce propert y specifies t he server and inst ance you want t o connect t o. SQL Server 2000 and lat er can have m ult iple server inst ances, each cont aining m ult iple dat abases. I n prior versions of SQL Server, you would j ust specify t he server nam e. I n eit her case, t he server nam e is t ypically t he sam e as t he nam e of t he com put er on which SQL Server is inst alled. The I n it ia l Ca t a log propert y is used t o specify t he dat abase you want t o connect t o. There are t wo com m on synt ax variat ions used when connect ing t o a SQL Server dat abase. The variat ion you need t o use depends on how t he login securit y has been configured on t he SQL Server you are connect ing t o. Unlike Access, SQL Server always requires som e sort of login credent ials. The t wo t ypes of SQL Server securit y are st a n da r d se cu r it y and W in dow s in t e gr a t e d se cu r it y. St andard securit y m eans t hat you log in t o SQL Server wit h a user nam e and password specific t o SQL Server. I nt egrat ed securit y m eans your Windows net work login credent ials are used t o validat e your connect ion t o SQL Server. The connect ion st ring used for st andard securit y is shown in List ing 13- 3 . The connect ion st ring used for int egrat ed securit y is shown in List ing 13- 4.

List in g 1 3 - 3 . Con n e ct ion St r in g for SQL Se r ve r w it h St a n da r d Se cu r it y Dim sConnect As String sConnect = "Provider=SQLOLEDB;" & _ "Data Source=ServerName\InstanceName;" & _ "Initial Catalog=DatabaseName;" & _ "User ID=UserName;" & _ "Password=Password;"

List in g 1 3 - 4 . Con n e ct ion St r in g for SQL Se r ve r w it h I n t e gr a t e d Se cu r it y Dim sConnect As String sConnect = "Provider=SQLOLEDB;" & _ "Data Source=ServerName\InstanceName;" & _ "Initial Catalog=DatabaseName;" & _ "Integrated Security=SSPI"

Excel You can connect t o an Excel workbook using eit her t he OLE DB Provider for ODBC or t he OLE DB Provider for Microsoft Jet . We dem onst rat e t he use of t he lat t er. The synt ax for t his is shown in List ing 13- 5.

List in g 1 3 - 5 . Con n e ct ion St r in g for a n Ex ce l W or k book Dim sConnect As String sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=C:\Files\MyWorkbook.xls;" & _ "Extended Properties=""Excel 8.0;HDR=YES"";"

Not e t he Ex t e n de d Pr ope r t ie s propert y. This propert y consist s of t wo values. The first t ells t he Jet provider you are connect ing t o an Excel workbook. The second t ells t he provider how t o int erpret t he dat a in t he sheet or range you specify in your SQL st at em ent s. A value of HDR=YES indicat es t he first row of dat a cont ains t he colum n nam es. I f t his value is om it t ed or if it is specified as HDR=NO, t he provider will assum e all values in t he t able are dat a and t here are no colum n nam es.

Using the Connection String Aft er you have built your connect ion st ring, you can assign it t o t he Connect ionSt ring propert y of t he ADO Connect ion obj ect or pass it direct ly t o various propert ies and m et hods of ot her t op- level ADO obj ect s. List ing 13- 6 dem onst rat es how t o open a connect ion t o an Access dat abase using t he Connect ion obj ect .

N OTE To use ADO from your Excel VBA proj ect , you m ust set a reference t o t he Microsoft Act iveX Dat a Obj ect s 2.x library, where x represent s t he highest num bered library available on your syst em .

List in g 1 3 - 6 . Ope n in g a Con n e ct ion t o a n Acce ss D a t a ba se Public gcnAccess As ADODB.Connection Sub OpenAccessConnection() Dim sConnect As String sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=E:\MyDatabase.mdb;" Set gcnAccess = New ADODB.Connection gcnAccess.ConnectionString = sConnect gcnAccess.Open

' Code to use the connection goes here. gcnAccess.Close End Sub

Connect ing t o ot her dat a sources works exact ly t he sam e way. We show ot her ways t hat t he connect ion st ring can be used in lat er sect ions. Not e t hat our ADO Connect ion obj ect was declared as a global variable. This is required t o enable a very im port ant ADO feat ure called con n e ct ion poolin g . Creat ing and t earing down a connect ion t o a dat abase is a resource- int ensive process. I f your applicat ion will be perform ing a large num ber of dat abase operat ions, you do not want ADO t o have t o creat e and dest roy a connect ion for each one of t hem . To enable connect ion pooling, you m ust do t he following: Declare your ADO Connect ion obj ect as a global or m odule- level variable. Creat e your ADO connect ion on applicat ion st art up and t hen close it . Each t im e a procedure needs t o use t he connect ion it should open t he connect ion, use it and t hen close it . Do not set t he Connect ion obj ect t o Not hing unt il your applicat ion is shut t ing down. By following t hese procedures you will allow ADO ( or m ore accurat ely, t he underlying OLE DB provider) t o hold t he dat abase connect ion open behind t he scenes and provide your procedures wit h an exist ing connect ion on request rat her t han forcing it t o creat e a new connect ion each t im e one is needed.

Error Handling Connections When t alking t heoret ically about m aking dat abase connect ions, t he connect ion at t em pt s always succeed and you cont inue along your m erry way. I n t he real world, t his is not always t he case. When you are at t em pt ing t o access a dat abase t hat is not locat ed on t he sam e com put er as your code, any num ber of t hings can cause t he connect ion at t em pt t o fail. The solut ion t o t his problem is t o use your error handler t o look for t he error t hat is generat ed when a connect ion at t em pt fails and t hen handle it appropriat ely. Because congest ed net work condit ions or very busy dat abases can bot h cause t ransient connect ion problem s, t he best st rat egy is t o ret ry t he connect ion at t em pt a few t im es before giving up and inform ing t he user t hat a connect ion t o t he dat abase could not be est ablished. The code required t o accom plish t his for an at t em pt ed connect ion t o a SQL Server dat abase is shown in List ing 13- 7. For general det ails on t he error handling t echnique used here, refer back t o Chapt er 12 VBA Error Handling .

List in g 1 3 - 7 . Er r or H a n dlin g a Con n e ct ion At t e m pt Public gcnConnect As ADODB.Connection Public Sub ConnectToDatabase() Const sSOURCE As String = "ConnectToDatabase" Dim lAttempt As Long Dim sConnect As String On Error GoTo ErrorHandler ' Create the connection string. sConnect = "Provider=SQLOLEDB;" & _ "Data Source=ServerName\InstanceName;" & _ "Initial Catalog=DatabaseName;" & _ "Integrated Security=SSPI" ' Attempt to open the connection. Application.StatusBar = "Attempting to connect..." Set gcnConnect = New ADODB.Connection gcnConnect.ConnectionString = sConnect gcnConnect.Open ' Close connection to enable connection pooling. gcnConnect.Close ErrorExit: Application.StatusBar = False Exit Sub ErrorHandler: ' We will try to make the connection three times before ' bailing out. If lAttempt < 3 And gcnConnect.Errors.Count > 0 Then If gcnConnect.Errors(0).NativeError = 17 Then Application.StatusBar = "Retrying connection..." lAttempt = lAttempt + 1 Resume End If End If If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then Stop Resume Else Resume ErrorExit End If

End Sub

The error indicat ing a connect ion failure is a provider error, so we m ust exam ine t he Connect ion obj ect 's Errors collect ion in order t o det erm ine whet her a connect ion at t em pt failed. The Errors collect ion m ay cont ain m ult iple errors, but t he first it em in t he collect ion is alm ost always t he one t hat describes t he root cause of t he error. Unlike m ost collect ions t hat you'll encount er in VBA, t he Connect ion obj ect Errors collect ion is indexed beginning wit h zero. The process of ret rying connect ion at t em pt s can be lengt hy. Therefore we've added st at us bar m essages t o keep our users updat ed. Ot herwise t hey m ay t hink t he applicat ion is frozen and at t em pt t o end it wit h Ct rl+ Alt + Del.

Data Access Techniques There are four fundam ent al da t a m a n ipu la t ion operat ions you can perform on t he dat a in a dat a source. You can ret rieve exist ing dat a, you can add new dat a, you can m odify exist ing dat a and you can delet e exist ing dat a. I n t his sect ion we dem onst rat e how t o perform t hese operat ions using SQL and ADO. Any dat a- m anipulat ion operat ion can be perform ed on any dat a source by passing plain- t ext SQL st at em ent s direct ly t o t he dat a source using ADO. Relat ional dat abases also allow you t o st ore prefabricat ed SQL st at em ent s, known as st ored queries or st ored procedures. When working wit h client - server dat abases especially, if you have t he opt ion you should always prefer st ored procedures. They are far m ore efficient t han plain- t ext SQL st at em ent s and you can creat e far m ore com plex dat a access logic wit hin t hem . For t he plain- t ext SQL st at em ent s we dem onst rat e below we will show only t he m ost com m on synt ax elem ent s. Act ual SQL st at em ent s can be m uch m ore com plex and will have dat abasespecific ext ensions available t hat are only valid when you are working wit h t hat dat abase. To keep t his sect ion focused, all t he exam ples shown use Access as t he dat a source. The nice t hing about ADO is t hat it s usage is alm ost ident ical regardless of t he dat a source you are working wit h. However, please see our previous book, t he Excel 2002 VBA Program m er's Reference, for det ailed exam ples of dat a access using SQL Server, Excel and even t ext files.

Retrieving Data I n t his sect ion we dem onst rat e how t o ret rieve dat a using SQL and ADO. Excel also provides a num ber of aut om at ed feat ures for ret rieving and analyzing dat a. These will be covered in Chapt er 14 Dat a Manipulat ion Techniques. The SQL SELECT st at em ent is used t o accom plish dat a ret rieval. The basic synt ax of t he SELECT st at em ent is shown in List ing 13- 8.

List in g 1 3 - 8 . Th e SQL SELECT St a t e m e n t SELECT

FROM

WHERE

ORDER BY

We've placed each clause of t he SELECT st at em ent on a separat e line for readabilit y purposes. I n realit y, whit e space has no effect on a SQL st at em ent and you can arrange it on a single line or m ult iple lines as you see fit . Just m ake sure t hat at least one space separat es each elem ent in t he st at em ent from t he next and t he clauses appear in t he order shown above. The m eaning of each clause is t he following: SELECT This clause is a com m a- delim it ed list of colum ns you want t o ret rieve. FROM This clause cont ains t he nam es of one or m ore t ables t hat cont ain t he dat a you want t o ret rieve. I f m ult iple t ables are specified, you will need t o perform a j oin . There are various t ypes of j oins available in SQL and a discussion of t hem all is beyond t he scope of t his chapt er. However, t he m ost com m on j oin t ype is t he I NNER JOI N, which uses t he following sy nt ax : FROM table1 INNER JOIN table2 ON table1.IDCol = table2.IDCol

We dem onst rat e an I NNER JOI N in t he exam ple below. W H ERE This clause cont ains any crit eria t hat rest rict what dat a should be ret urned. I t is t ypically expressed as a Boolean condit ion in t he form of column_name = value. The WHERE clause is opt ional and can be om it t ed if you j ust want t o ret rieve all t he dat a in a t able. ORD ER BY This clause indicat es which colum ns you want t he dat a sort ed by. The ORDER BY clause is opt ional if you are not concerned about t he order in which t he dat a is ret urned t o you. For our SELECT exam ple, we will use our norm alized BillableHours t able shown in Figure 13- 8 and t he relat ed Consult ant s t able shown in Figure 13- 4. We will assum e t he dat abase is locat ed in t he sam e direct ory as t he workbook t hat is calling it . List ing 13- 9 shows a plain- t ext SQL query t hat ret rieves all of t he billable hours records for consult ant Rob Bovey.

List in g 1 3 - 9 . Re t r ie vin g D a t a fr om Acce ss Public Sub SelectFromAccess() Dim Dim Dim Dim

rsData As ADODB.Recordset sPath As String sConnect As String sSQL As String

' Clear the destination worksheet. Sheet1.UsedRange.Clear ' Get the database path (same as this workbook). sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Create the connection string. sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & sPath & "Figures3.mdb;" ' Build the SQL query. sSQL = "SELECT FirstName + ' ' + LastName, Date, Hours " & _ "FROM BillableHours AS b " & _ "INNER JOIN Consultants AS c " & _ "ON b.ConsultantID = c.ConsultantID " & _ "WHERE FirstName = 'Rob' AND LastName = 'Bovey';" ' Retrieve the data using ADO. Set rsData = New ADODB.Recordset rsData.Open sSQL, sConnect, _ adOpenForwardOnly, adLockReadOnly, adCmdText If Not rsData.EOF Then Sheet1.Range("A1").CopyFromRecordset rsData Else MsgBox "No data located.", vbCritical, "Error!" End If rsData.Close Set rsData = Nothing End Sub

There are several int erest ing t echniques t o point out in List ing 13- 9. First exam ine t he SQL used t o specify t he dat a we want t o ret rieve. This shows a lit t le bit of t he flexibilit y available in t he SQL SELECT st at em ent . I n t he SELECT clause, we show how you can concat enat e t he values of m ult iple dat abase colum ns int o a single result colum n. We have also j oined t wo t ables in t he FROM clause. We need t o do t his because even t hough t he dat a we want is locat ed in t he BillableHours t able, t he consult ant 's nam e t hat we want t o rest rict our dat a t o is locat ed in t he Consult ant s t able. I n t he FROM clause, we link t he t wo t ables on t heir com m on colum n, t he Consult ant I D colum n. Recall from our previous discussion on relat ionships t hat t he Consult ant I D colum n is t he prim ary key of t he Consult ant s t able and a foreign key in t he BillableHours t able. Next , not ice we have used m ult iple rest rict ion condit ions in t he WHERE clause. We need t o specify bot h t he value of t he First Nam e and Last Nam e colum ns t o uniquely ident ify t he consult ant whose dat a we want t o ret rieve. To do t his, we j ust link t he t wo Boolean condit ions wit h t he SQL AND oper at or .

Last , not ice how we m ake use of t he connect ion st ring in t his exam ple. Rat her t han creat ing an ADO Connect ion obj ect , we sim ply pass t he connect ion st ring direct ly t o t he ADO Recordset obj ect 's Open m et hod. This is a very useful t echnique when you will only be perform ing a single query and you don't need advanced feat ures of t he ADO Connect ion obj ect such as connect ion pooling. Aft er we've opened t he recordset , we check t o see whet her we got any dat a. This is accom plished by exam ining t he recordset 's EOF propert y. EOF st ands for e n d of file. I f no dat a was ret urned, t he recordset 's row point er will be point ing t o t he end of t he recordset and t he EOF propert y will be True, ot herwise t he row point er will be point ing t o t he first record in t he recordset and t he value of EOF will be False. I f we successfully ret rieved t he dat a we asked for, we dum p it ont o Sheet 1 using t he CopyFrom Recordset m et hod of t he Excel Range obj ect . The CopyFrom Recordset m et hod provides an ext rem ely fast m et hod for ext ract ing t he dat a from a recordset ont o a worksheet . The CopyFrom Recordset m et hod ret urns only t he dat a, not t he colum n nam es. An alt ernat ive m et hod t hat adds t he colum n nam es and t hen adds t he dat a by looping t he recordset one row at a t im e is shown in t he code fragm ent in List ing 13- 10.

List in g 1 3 - 1 0 . Loopin g a Re cor dse t by Row s If Not rsData.EOF Then ' Add the column headers. For lColumn = 0 To rsData.Fields.Count - 1 With Sheet1.Range("A1") .Offset(0, lColumn).Value = _ rsData.Fields(lColumn).Name End With Next lColumn ' Add the data. lRow = 1 Do While Not rsData.EOF For lColumn = 0 To rsData.Fields.Count - 1 With Sheet1.Range("A1") .Offset(lRow, lColumn).Value = _ rsData.Fields(lColumn).Value End With Next lColumn lRow = lRow + 1 rsData.MoveNext Loop Else MsgBox "No data located.", vbCritical, "Error!" End If

Inserting Data

I nsert ing new dat a int o a dat abase is accom plished using t he SQL I NSERT st at em ent . The basic synt ax of t he I NSERT st at em ent is shown in List ing 13- 11. An explanat ion of each clause of t he st at em ent follows.

List in g 1 3 - 1 1 . Th e SQL I N SERT St a t e m e n t INSERT INTO
() VALUES ()

I N SERT I N TO This clause includes t he nam e of t he t able int o which you are insert ing t he dat a and a com m a- delim it ed list of colum ns t hat will be receiving dat a enclosed in parent hesis. You are not required t o list t he colum ns if you will be supplying dat a in t he VALUES clause for every required colum n in t he t able in t he sam e order in which t hey appear in t he t able. Cert ain t ypes of colum ns cannot be included in t he I NSERT clause. These include any Aut oNum ber colum n in an Access dat abase t able. VALUES This clause includes a com m a- delim it ed list of values t o be insert ed int o t he t able enclosed in parent hesis. When a list of colum ns is provided in t he I NSERT I NTO clause, t here m ust be a corresponding value for each of t hese colum ns in t he VALUES clause. To illust rat e t he I NSERT st at em ent , we'll add a new consult ant t o our Consult ant s t able. The code t o accom plish t his is shown in List ing 13- 12.

List in g 1 3 - 1 2 . I n se r t in g D a t a in t o Acce ss Public Sub InsertIntoAccess() Dim Dim Dim Dim

cnAccess As ADODB.Connection sPath As String sConnect As String sSQL As String

' Get the database path (same as this workbook). sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Create the connection string. sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & sPath & "Figures3.mdb;" ' Build the SQL query. sSQL = "INSERT INTO Consultants (FirstName, LastName)" & _ "VALUES ('John', 'Smith');"

' Use the Connection object to execute the SQL statement. Set cnAccess = New ADODB.Connection cnAccess.ConnectionString = sConnect cnAccess.Open cnAccess.Execute sSQL, , adCmdText + adExecuteNoRecords cnAccess.Close Set cnAccess = Nothing End Sub

I n t his exam ple we've dem onst rat ed how you can execut e SQL st at em ent s using t he ADO Connect ion obj ect alone. The Connect ion obj ect has an Execut e m et hod t hat we've used t o insert our new record int o t he Consult ant s t able. The first argum ent t o t he Execut e m et hod is t he SQL st at em ent we want t o execut e. The second argum ent is a ret urn value t hat t ells us t he num ber of records affect ed aft er t he m et hod has com plet ed. We don't need t his because we know our I NSERT st at em ent only insert s a single record. I f t he insert fails for som e reason a runt im e error will be generat ed by ADO. The last argum ent t ells t he Execut e m et hod what we are giving it in t he first argum ent as well as how t o process t he call. adCm dText is an enum erat ion m em ber t hat t ells t he Execut e m et hod we are passing it a SQL t ext st ring. This is t he sam e value we passed t o t he last argum ent of t he Recordset .Open m et hod in List ing 13- 9 above. I f t his value is not specified, ADO will det erm ine for it self what is being passed in t he first argum ent , but t elling it t o begin wit h saves t im e. adExecut eNoRecords is an enum erat ion m em ber t hat t ells t he Execut e m et hod how t o process t he call. I n t his case, it m eans t he Execut e m et hod should not ret urn a recordset . The Execut e m et hod will always ret urn a recordset unless t old t o do ot herwise, even if a recordset it not logically required and is t herefore em pt y. Telling t he Execut e m et hod we don't need a recordset ret urned saves t he t im e and resources required t o creat e and ret urn t he unnecessary em pt y recordset .

Updating Data Updat ing dat a in a dat abase is accom plished using t he SQL UPDATE st at em ent . The basic synt ax of t he UPDATE st at em ent is shown in List ing 13- 13. An explanat ion of each clause of t he st at em ent follow s.

List in g 1 3 - 1 3 . Th e SQL UPD ATE St a t e m e n t UPDATE SET WHERE

=

UPD ATE This clause cont ains t he nam e of t he t able t hat holds t he dat a t o be updat ed.

SET This clause provides t he colum n nam e t o be updat ed and t he value it will be updat ed w it h. W H ERE This clause cont ains t he crit erion t hat ident ifies t he row t o be updat ed. I t is expressed as a Boolean condit ion in t he form of column_name = value. The WHERE clause is t echnically opt ional, but beware. I f you do not supply a WHERE clause in t he UPDATE st at em ent t hen every row in t he t able will be updat ed wit h t he specified value. This is rarely what you want t o do and it is im possible t o reverse. To illust rat e t he UPDATE st at em ent , we'll use an Access st ored param et er query t o m odify t he nam e of one of t he client s in our Client s t able from Figure 13- 6. The Access st ored query is called qryUpdat eClient and it s cont ent s are shown in List ing 13- 14.

List in g 1 3 - 1 4 . Th e qr yUpda t e Clie n t Pa r a m e t e r Qu e r y UPDATE SET WHERE

Clients ClientName = [CName] ClientID = [ID];

As you can see, t his query t akes t wo param et ers. The CNam e param et er is used t o m odify t he client nam e and t he I D param et er is used t o uniquely ident ify t he client whose nam e we want t o updat e. The code t o execut e t his query is shown in List ing 13- 15.

List in g 1 3 - 1 5 . Upda t in g Acce ss D a t a Public Sub UpdateAccess() Dim Dim Dim Dim Dim

cmAccess As ADODB.Command objParams As ADODB.Parameters lAffected As Long sPath As String sConnect As String

' Get the database path (same as this workbook). sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Create the connection string. sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & sPath & "Figures3.mdb;" ' Create the Command object. Set cmAccess = New ADODB.Command cmAccess.ActiveConnection = sConnect cmAccess.CommandText = "qryUpdateClient"

cmAccess.CommandType = adCmdStoredProc ' Create and append the parameters. Set objParams = cmAccess.Parameters objParams.Append cmAccess.CreateParameter("CName", _ adVarChar, adParamInput, 50) objParams.Append cmAccess.CreateParameter("ID", _ adInteger, adParamInput, 0) Set objParams = Nothing ' Load the parameters and execute the query. cmAccess.Parameters("CName").Value = "Hardware House" cmAccess.Parameters("ID").Value = 2 cmAccess.Execute lAffected, , adExecuteNoRecords ' Verify the correct number of records updated. If lAffected 1 Then MsgBox "Error updating record.", vbCritical, "Error!" End If Set cmAccess = Nothing End Sub

We are again bypassing t he ADO Connect ion obj ect , t his t im e assigning t he connect ion st ring direct ly t o t he Com m and obj ect 's Act iveConnect ion propert y. Also not ice t hat inst ead of a plain- t ext SQL st at em ent we are now using t he nam e of t he Access st ored query. Where t he t ype of t he plaint ext queries we used previously was adCm dText , t he t ype of a st ored query is adCm dSt oredProc. This exam ple illust rat es t he use of t he ADO Com m and obj ect 's Param et ers collect ion. For each param et er in t he Access param et er query, we m ust creat e a Param et er obj ect and add it t o t he Param et ers collect ion. These param et ers m ust be creat ed and added t o t he collect ion in exact ly t he sam e order as t hey appear in t he SQL of t he Access param et er query. We creat e and st ore t he param et ers in a single line of code by passing t he result of t he Com m and obj ect 's Creat eParam et er m et hod t o t he Param et ers collect ion Append m et hod. We use four argum ent s of t he Creat eParam et er m et hod: N a m e This is t he nam e of t he param et er. I t m ust be t he sam e nam e t hat appears in t he Access param et er query for t he param et er. Ty p e This is an enum erat ion m em ber specifying t he dat a t ype of t he param et er. adVarChar m eans a Text param et er and adI nt eger m eans a Long I nt eger param et er. D ir e ct ion This is an enum erat ion m em ber indicat ing which direct ion t he param et er is used t o pass dat a. adParam I nput indicat es t he param et er will be used t o pass dat a from our code t o t he dat abase. Size This value indicat es t he size of t he param et er. I t is only required for Text dat a t ypes. I n t he case of our CNam e param et er, t he colum n being updat ed has a m axim um widt h of 50 charact ers. For num eric dat a t ypes like t he I D param et er, you can sim ply pass zero t o t his

ar gum ent . Aft er we have creat ed t he param et ers and added t hem t o our Com m and obj ect 's Param et ers collect ion, we load t hem wit h t he values we want t o send t o t he dat abase and t hen execut e t he st ored query. The first argum ent t o t he Com m and obj ect 's Execut e m et hod is a ret urn value indicat ing t he num ber of records affect ed. We are using t he lAffect ed variable t o ret rieve t his value and checking it t o ensure t hat exact ly one record was updat ed. As in our insert exam ple, we do not require a recordset t o be ret urned, so we're using t he t hird argum ent of t he Com m and obj ect t o prevent t his from happening.

Deleting Data Delet ing dat a in a dat abase is accom plished using t he SQL DELETE st at em ent . The basic synt ax of t he DELETE st at em ent is shown in List ing 13- 16. An explanat ion of each clause of t he st at em ent follow s.

List in g 1 3 - 1 6 . Th e SQL D ELETE St a t e m e n t DELETE FROM
WHERE

D ELETE FROM This clause cont ains t he nam e of t he t able t hat holds t he dat a t o be delet ed. W H ERE This clause cont ains t he crit erion t hat ident ifies t he row t o be delet ed. I t is expressed as a Boolean condit ion in t he form of column_name = value. The WHERE clause is t echnically opt ional, but beware. I f you do not supply a WHERE clause in t he DELETE st at em ent , t hen every row in t he t able will be delet ed. This is rarely what you want t o do and it is im possible t o reverse. To illust rat e t he DELETE st at em ent , we'll rem ove t he consult ant we added t o t he Consult ant s t able wit h our insert exam ple in List ing 13- 12. The code t o accom plish t his is shown in List ing 13- 17.

List in g 1 3 - 1 7 . D e le t in g Acce ss D a t a Public Sub DeleteFromAccess() Dim Dim Dim Dim Dim

cmAccess As ADODB.Command lAffected As Long sPath As String sConnect As String sSQL As String

' Get the database path (same as this workbook).

sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" ' Create the connection string. sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & sPath & "Figures3.mdb;" ' Build the SQL query. sSQL = "DELETE FROM Consultants " & _ "WHERE FirstName = 'John' AND LastName = 'Smith';" ' Create and execute the Command object. Set cmAccess = New ADODB.Command cmAccess.ActiveConnection = sConnect cmAccess.CommandText = sSQL cmAccess.CommandType = adCmdText cmAccess.Execute lAffected, , adExecuteNoRecords ' Verify the correct number of records deleted. If lAffected 1 Then MsgBox "Error deleting record.", vbCritical, "Error!" End If Set cmAccess = Nothing End Sub

All of t he t echniques used here should be fam iliar from previous exam ples so we will not cover t hem in any det ail.

Further Reading As we st at ed at t he beginning of t he chapt er, t he subj ect s covered here are all book- lengt h t opics in t heir own right . Therefore, we would be rem iss if we didn't recom m end som e good books you could use t o pursue t he full breadt h of t hese t opics. The books recom m ended below have been found very useful by t he aut hors of t his book. We have no financial st ake in any of t hem . These recom m endat ions are based purely on qualit y.

Professional SQL Server 2000 Database Design Aut hored by Louis Davidson I SBN 1861004761 - Wrox Alt hough t he t it le cont ains " SQL Server 2000," t he first half of t his book provides very det ailed coverage of dat a norm alizat ion and relat ional dat abase design in a soft ware- agnost ic m anner. I f t he first sect ion of t his chapt er was unclear or left you want ing m ore inform at ion, t his is t he book for you. Sadly, t his book is now out of print , but used copies can be readily obt ained t hrough Am azon.com .

ADO 2.6 Programmer's Reference Aut hored by David Sussm an I SBN 186100463X - Wrox

Professional ADO 2.5 Programming Aut hored by David Sussm an et al. I SBN 1861002750 - Wrox Unfort unat ely, t here were not very m any excellent books on " classic ADO" t o begin wit h. Now t hat Microsoft has m oved on t o ADO.NET ( a com plet ely different t echnology regardless of t he sim ilar acronym ) what few good books t here were are going out of print very quickly. That applies t o bot h of t hese t it les, alt hough again, you can readily find used copies t hrough Am azon.com . The ADO 2.6 Program m er's Reference is exact ly what it s t it le would suggest : a very com prehensive reference t o t he ADO obj ect m odel. I t is essent ially a high- qualit y ADO dict ionary. Pr ofessional ADO2.5 Program m ing assum es t hat you underst and all t he basic concept s of ADO and goes on t o show you how t o apply t hem in a series of advanced applicat ion scenarios.

Professional SQL Server 2000 Programming Aut hored by Robert Vieira I SBN 0764543792 - Wrox I f you want t o learn about SQL Server, t here is no bet t er place t o st art t han here. The best way t o describe t he scope of t his book is t hat it st art s where ADO ends. I t is t ight ly focused on pure SQL Server t opics. I t provides excellent SQL Server- specific coverage of SQL, st ored procedures, views, indexes, t ransact ions, and t he t ools used t o m anage and program SQL Server, am ong m any ot her t opics.

Access 2002 Developer's Handbook Set Aut hored by Paul Lit win, Ken Get z and Mike Gunderloy I SBN 0782140114 - Sybex This is t he lat est updat e of an ongoing series of first - class Access developm ent books t hat began wit h Access 95. This book t ouches on all aspect s of Access developm ent , from running Access SQL direct ly against an Access dat abase t o developing report s in t he Access user int erface. I f you want a com prehensive reference t o Access developm ent , t his should be your first choice.

Practical Example I n t his sect ion we will m ove our dat a int o an Access dat abase. We've provided a ready- m ade Access dat abase for t his proj ect . Creat ing an Access dat abase is easy and aft er you've creat ed t he dat abase you no longer need Access t o use it .

PETRAS Timesheet All of t he dat a access logic in our applicat ion has been isolat ed in a single m odule called MDat aAccess. This will m ake it easy for us t o change our back- end dat a st ore, t o SQL Server for exam ple, as our dat a access needs becom e m ore significant . We are also using t he connect ion pooling feat ure of ADO t o im prove perform ance. List ing 13- 18 shows t he funct ion t hat is called from t he Aut o_Open procedure t o init ialize our Connect ion obj ect .

List in g 1 3 - 1 8 . I n it ia lizin g t h e Con n e ct ion Obj e ct Private mcnConnection As ADODB.Connection Public Function bCreateDBConnection() As Boolean Const sSOURCE As String = "bCreateDBConnection()" Dim bReturn As Boolean Dim sPath As String Dim sConnect As String On Error GoTo ErrorHandler ' Assume success until an error is encountered. bReturn = True ' First look for the database path in the registry. sPath = GetSetting(gsREG_APP, gsREG_SECTION, gsREG_KEY, "") ' If we didn't find a database location entry in the ' registry, assume it is located in the same folder ' as this workbook. If Len(sPath) = 0 Then sPath = ThisWorkbook.Path If Right$(sPath, 1) "\" Then sPath = sPath & "\" End If ' Make sure we can locate the database file.

If Len(Dir$(sPath & msFILE_DATABASE)) = 0 Then _ Err.Raise glHANDLED_ERROR, sSOURCE, gsERR_NO_DATABASE ' Create the connection string. sConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & sPath & msFILE_DATABASE & ";" Set mcnConnection = New ADODB.Connection mcnConnection.ConnectionString = sConnect mcnConnection.Open mcnConnection.Close ErrorExit: bCreateDBConnection = bReturn Exit Function ErrorHandler: bReturn = False If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else Resume ErrorExit End If End Function

This funct ion first ensures we can locat e our dat abase file. I t t hen inst ant iat es t he m odule- level Connect ion obj ect , t hen opens and closes t he connect ion t o our dat abase. This enables t he ADO connect ion pooling feat ure. The Connect ion obj ect rem ains act ive as long as t he applicat ion is running, being opened and closed as it is used. When t he applicat ion shut s down we dest roy t he connect ion obj ect by calling t he procedure shown in List ing 13- 19.

List in g 1 3 - 1 9 . D e st r oyin g t h e Con n e ct ion Obj e ct Public Sub DestroyConnection() Set mcnConnection = Nothing End Sub

Modifying the Application to Load Data-Validation Lists from the Database I n previous versions of our t im e- ent ry workbook t em plat e, t he dat a- validat ion list s in t he wksProgram Dat a worksheet were hard- coded. I f t hese list s changed, you would need t o dist ribut e a new copy of t he t em plat e t o all of your users. I n t his sect ion we will m odify t he applicat ion so it aut om at ically loads t he lat est versions of t hese list s from our new dat abase whenever a t im e- ent ry

workbook is opened. The procedure t hat accom plishes t his t ask is locat ed in our MDat aAccess m odule and called by our applicat ion event handler whenever a t im e- ent ry workbook is creat ed, opened or det ect ed on applicat ion st art up. The ent ire procedure is long and very repet it ive, so we will only show a represent at ive sam ple of it in List ing 13- 20.

List in g 1 3 - 2 0 . Loa din g t h e Applica t ion D a t a Public Function bLoadInitialData( _ ByRef wkbTemplate As Workbook) As Boolean Const sSOURCE As String = "bLoadInitialData()" Dim Dim Dim Dim Dim Dim Dim Dim Dim

rsData As ADODB.Recordset bReturn As Boolean lColOffset As Long rngCell As Range rngClients As Range rngProjects As Range sSQL As String sSQLBase As String wksProgData As Worksheet

On Error GoTo ErrorHandler ' Assume success until an error is encountered. bReturn = True Application.StatusBar = gsSTATUS_LOADING_DATA ' Clear any existing data from the wksProgramData worksheet. Set wksProgData = wkbTemplate.Worksheets(gsSHEET_PROG_DATA) wksProgData.UsedRange.Offset(1, 0).ClearContents ' Create the Recordset object we'll use for all the queries. Set rsData = New ADODB.Recordset ' Get a connection from the pool. mcnConnection.Open ' Load each of the program data lists. ' Consultants sSQL = "SELECT FirstName + ' ' + LastName, ConsultantID" & _ " FROM Consultants;" rsData.Open sSQL, mcnConnection, adOpenForwardOnly, _ adLockReadOnly, adCmdText If Not rsData.EOF Then wksProgData.Range(gsRNG_CONSULT_TOP).Offset(1, 0) _ .CopyFromRecordset rsData

Else Err.Raise glHANDLED_ERROR, sSOURCE, _ "Error retrieving consultant data." End If rsData.Close ' Load the rest of the lists here... ErrorExit: Set rsData = Nothing ' Close the connection to return it to the pool. mcnConnection.Close Application.StatusBar = False bLoadInitialData = bReturn Exit Function ErrorHandler: bReturn = False If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else Resume ErrorExit End If End Function

The select operat ion using t he recordset should look very fam iliar. I t is essent ially ident ical t o t he operat ion we dem onst rat ed in t he Ret rieving Dat a sect ion above. Not ice how we open our m odulelevel Connect ion obj ect at t he beginning of t he procedure and close it at t he end. This is t he proper way t o m ake use of a pooled connect ion.

Modifying the Application to Save Time Entries to the Database I n previous versions of our applicat ion, t he ent ire com plet ed t im e- ent ry workbook was saved t o a cent ral consolidat ion locat ion. I n t his sect ion we m odify t he applicat ion t o save j ust t he billable hours dat a t o our new dat abase. We've added a new hidden sect ion t o our t im e- ent ry worksheet t hat convert s t he dat a ent ered by t he user int o a form at t hat can be loaded int o t he dat abase. The dat a from t he visible UI is rearranged int o a form at t hat is ident ical t o t he BillableHours t able in t he dat abase. All t ext colum n select ions are convert ed t o t heir I D num bers by looking t hem up in t he appropriat e wksProgram Dat a worksheet t able, and t he t ot al hours num ber is convert ed from Excel's dat e serial form at int o num eric form at by m ult iplying by 24. The conversion sect ion of t he t im e- ent ry worksheet is shown in Figure 13- 19.

Figu r e 1 3 - 1 9 . Tim e - En t r y D a t a - Con ve r sion Se ct ion [View full size image]

For perform ing t he insert operat ion on t he t im e- ent ry dat a, we've creat ed a user- defined t ype st ruct ure t hat is used t o pass dat a bet ween t he business logic t ier and t he dat a access t ier. The definit ion of t his t ype st ruct ure is shown in List ing 13- 21.

List in g 1 3 - 2 1 . Th e BI LLABLE_ H OUR Type St r u ct u r e Public Type BILLABLE_HOUR lConsultantID As Long dteDateWorked As Date lProjectID As Long lActivityID As Long dHours As Double End Type

The dat a access t ier procedure t hat consum es t his t ype st ruct ure and insert s it s dat a int o t he dat abase is shown in List ing 13- 22.

List in g 1 3 - 2 2 . Th e bI n se r t Tim e En t r y Fu n ct ion

Public Function bInsertTimeEntry( _ ByRef uData As BILLABLE_HOUR) As Boolean Const sSOURCE As String = "bInsertTimeEntry()" Dim cmInsert As ADODB.Command Dim bReturn As Boolean Dim sSQL As String On Error GoTo ErrorHandler ' Assume success until an error is encountered. bReturn = True ' Create the SQL statement to insert the data. sSQL = "INSERT INTO BillableHours (ConsultantID, " & _ "DateWorked, ProjectID, ActivityID, Hours) " & _ "VALUES (" & CStr(uData.lConsultantID) & ", " & _ "#" & uData.dteDateWorked & "#, " & _ CStr(uData.lProjectID) & ", " & _ CStr(uData.lActivityID) & ", " & _ CStr(uData.dHours) & ");" ' Open the connection so we can use it. mcnConnection.Open Set cmInsert = New ADODB.Command Set cmInsert.ActiveConnection = mcnConnection mcnConnection.Execute sSQL, , adCmdText + adExecuteNoRecords ErrorExit: Set cmInsert = Nothing ' Close the connection to return it to the pool. mcnConnection.Close bInsertTimeEntry = bReturn Exit Function ErrorHandler: bReturn = False If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else Resume ErrorExit End If End Function

Our new Post Tim eEnt riesToDat abase procedure, shown in List ing 13- 23, sim ply loops t he processed ent ries in t he hidden sect ion of t he t im e ent ry worksheet , loads each of t hem int o t he BI LLABLE_HOUR t ype st ruct ure one at a t im e and passes t hem t o t he bI nsert Tim eEnt ry funct ion t o be insert ed int o t he dat abase.

List in g 1 3 - 2 3 . Th e Post Tim e En t r ie sToD a t a ba se Pr oce du r e Public Sub PostTimeEntriesToDatabase() Const sSOURCE As String = "PostTimeEntriesToDatabase" Dim Dim Dim Dim Dim Dim

uData As BILLABLE_HOUR rngCell As Range rngTable As Range sSheetTab As String wksSheet As Worksheet wkbBook As Workbook

On Error GoTo ErrorHandler If Not bInitGlobals() Then Err.Raise glHANDLED_ERROR ' We know the active workbook is a time-entry workbook ' because our application event handling class would have ' disabled the menu that runs this procedure if it wasn't. Set wkbBook = Application.ActiveWorkbook ' Make sure the TimeEntry worksheet does not have any ' data entry errors. sSheetTab = sSheetTabName(wkbBook, gsSHEET_TIME_ENTRY) Set wksSheet = wkbBook.Worksheets(sSheetTab) If wksSheet.Range(gsRNG_HAS_ERRORS).Value Then Err.Raise glHANDLED_ERROR, sSOURCE, gsERR_DATA_ENTRY End If ' Warn the user that this action cannot be reversed ' and give them a chance to bail out. If MsgBox(gsMSG_WARN_POST, vbExclamation + vbYesNo, _ gsAPP_TITLE) = vbYes Then ' Loop each entry in the time sheet and save it to ' the database. Set rngTable = wksSheet.Range(gsRNG_BILLABLE_HOURS) For Each rngCell In rngTable uData.lConsultantID = rngCell.Value uData.dteDateWorked = rngCell.Offset(0, 1).Value uData.lProjectID = rngCell.Offset(0, 2).Value uData.lActivityID = rngCell.Offset(0, 3).Value

uData.dHours = rngCell.Offset(0, 4).Value If Not bInsertTimeEntry(uData) Then Err.Raise glHANDLED_ERROR End If Next rngCell ' Clear the time entry worksheet and display a success ' message to the user. wksSheet.Range(gsRNG_CLEAR_INPUTS).ClearContents MsgBox gsMSG_POST_SUCCESS, vbInformation, gsAPP_TITLE End If ErrorExit: Exit Sub ErrorHandler: If bCentralErrorHandler(msMODULE, sSOURCE, , True) Then Stop Resume Else Resume ErrorExit End If End Sub

Table 13- 1 shows a sum m ary of t he changes m ade t o t he PETRAS t im esheet applicat ion for t his chapt er .

Ta ble 1 3 - 1 . Ch a n ge s t o t h e PETRAS Tim e sh e e t Applica t ion for Ch a pt e r 1 3 M odu le

Pr oce du r e

Ch a n g e

CAppEv ent Handler

bI nit ializeWor k book

Cent ralized workbook init ializat ion code here

bLoadI nit ialDat a

Call t his procedure t o load init ial t im esheet dat a

MDat aAccess MEnt r yPoint s

New m odule t o handle all t he dat abase connect ivit y Post Tim eEnt r iesToNet w or k

Convert ed t o Post Tim eEnt r iesToDat abase

M odu le

Aut o_Open

Pr oce du r e

Ch a n g e

Specify Consolidat ionFolder

Convert ed t o SpecifyDat abaseLocat ion

bCr eat eDBConnect ion

Call t his procedure t o creat e pooled Connect ion obj ect

Shut dow nApplicat ion

Dest roy pooled Connect ion obj ect on close

PETRAS Reporting The PETRAS report ing applicat ion has had a num ber of changes and addit ions, part ly t o dem onst rat e t he dat abase handling concept s int roduced in t his chapt er, but also t o dem onst rat e som e of t he m ore int erest ing concept s int roduced in Chapt er 10 Userform Design and Best Pract ices and Chapt er 11 I nt erfaces. The im m ediat e result of using a dat abase inst ead of workbooks t o st ore our t im esheet dat a is t hat we no longer need a ( pot ent ially t im e- consum ing) procedure t o consolidat e t he dat a. I nst ead of select ing t he files t o consolidat e, t he user now provides a st art and end dat e, which t he applicat ion uses t o ext ract t he required records from t he dat abase. The dat a ext ract ion is done using code very sim ilar t o List ing 13- 20. Using a cent ral dat abase also m akes it m uch easier for us t o m aint ain t he st at ic list s of consult ant s, act ivit ies, client s and proj ect s. The PETRAS t im esheet add- in has been m odified t o read t hese list s from t he dat abase whenever a new t im esheet is creat ed, inst ead of us being required t o dist ribut e new t im esheet t em plat es aft er each updat e. A set of form s t o m aint ain t he list s has been added t o t he PETRAS report ing applicat ion, dem onst rat ing m any of t he concept s from Chapt ers 10 Userform Design and Best Pract ices and 11 I nt erfaces, including t he following: All t he form s follow t he KI SS principle of being sim ple for t he user. All t he form s have t heir code separat ed bet ween a user int erface layer ( t he form 's m odule) and a separat e user int erface support ( UI S) layer, im plem ent ed as a class m odule specific t o each form . All t he form s are resizable, im plem ent ed using t he CForm Resizer class from Chapt er 10. The m aint enance of t he client and proj ect list s has been im plem ent ed using a TreeView cont rol t o show t he client / proj ect hierarchy. All t he form s have been im plem ent ed using t he plug- in archit ect ure from Chapt er 11, enabling us t o add new form s wit hout changing any exist ing code. Wit hin t his chapt er, we've barely been able t o scrat ch t he surface of dat abase program m ing in general and ADO in part icular. To show som e real- world exam ples of t hese t echnologies, we have used som e of t he m ore advanced t echniques covered in t he Furt her Reading t ext s. Specifically, we have used discon n e ct e d r e cor dse t s t o handle t he underlying dat a for our userform s. Wit h t hese recordset s, we creat e a connect ion t o t he dat abase, populat e t he recordset , t hen set t he recordset 's Act iveConnect ion propert y t o Not hing. That disconnect s t he recordset from t he physical dat abase

file, allowing us t o change t he dat a cont ained in t he recordset w it h ou t t h e da t a ba se be in g u pda t e d . So when our user adds, delet es or renam es t he dat a, we can apply t hose changes direct ly t o t he recordset . I f t hey subsequent ly cancel t he form , we can j ust discard t he recordset and none of t heir changes will have reached t he dat abase. I f t hey click t he OK but t on, we set t he recordset 's Act iveConnect ion t o a valid dat abase connect ion and t ell t he recordset t o apply it s changes t o t he dat abase. This m akes it ext rem ely easy for us t o m odify sim ple list s of dat a, while allowing t he user t o cancel t heir changes. The code changes required for all t hese enhancem ent s are det ailed in Table 13- 2 .

Ta ble 1 3 - 2 . Ch a n ge s t o t h e PETRAS Re por t in g Applica t ion for Ch a pt e r 1 3 M odu le

Pr oce du r e

Ch a n g e

General changes for dat abase handling MDat aAccess MEnt r yPoint s

New m odule t o handle all t he dat abase connect ivit y. MenuSpecify Dat abaseLocat ion

MBr ow seFor Folder

New procedure for t he user t o select t he locat ion of t he cent ral PETRAS dat abase file. New m odule t o show t he st andard Browse for Folder dialog.

Ext ract ing dat a inst ead of consolidat ing workbooks MSyst em Code

I m por t Dat a

FI m por t Dat a

MDat aAccess

Renam ed from Consolidat eWorkbooks. Ext ract s dat a from t he dat abase inst ead of looping t hrough workbooks. New userform t o provide a range of dat es for ext ract ing t im esheet r ecor ds.

Get Tim esheet Dat a

FPr ogr essBar , CPr ogr essBar , I Pr ogr essBar

Ret rieve t he t im esheet records for t he given dat e range, writ ing t he records t o t he result s workbook. The t hree progress bar m odules have been rem oved, because t hey are no longer required t o show t he progress of t he consolidat ion process.

Userform s t o m aint ain t he st at ic list s w ksCom m andBars

New m enu st ruct ure creat ed for t he dat abase int eract ion.

M odu le

Pr oce du r e

Ch a n g e

MEnt r yPoint s

Added procedures called by t he new m enu it em s, one for each new form .

FAct ivit ies

New form t o m aint ain t he list of Act ivit ies. The code in t he form concent rat es on handling t he user int er act ion.

CUI SAct ivit ies

New class t o support t he FAct ivit ies form . The code in t he class concent rat es on m anaging t he disconnect ed recordset , in response t o t he user act ions.

FConsult ant s

New form t o m aint ain t he list of Consult ant s.

CUI SConsult ant s

New class t o support t he FConsult ant s for m .

FClient s

New form t o m aint ain t he list s of Client s and Proj ect s.

CUI SClient s

New class t o support t he FClient s for m .

MDat aAccess

New procedures t o creat e t he disconnect ed recordset s for t he Act ivit ies, Consult ant s and Client s/ Proj ect s form s and t o updat e t he dat abase wit h t he changes t o t he recordset s.

CFor m Resizer

New class t o handle t he resizing of t he new form s.

I m plem ent ing t he plug- in userform archit ect ure I Plu gI n For m

New class t o define t he I PlugI nForm int erface.

FAct ivit ies, FConsult ant s, FClient s

The t hree new dat a- m aint enance form s im plem ent t he I PlugI nForm int erface.

MSyst em Code

Show For m

A generic procedure t o show any of t he plug- in form s.

Conclusion We've covered a lot of ground in a very short space in t his chapt er. We've explained what dat abases are and under what circum st ances you should use t hem . We've explained how t o st ruct ure your dat a properly for st orage in a relat ional dat abase. We've provided a brief int roduct ion t o SQL and ADO and dem onst rat ed how you can use t hem t o ret rieve and m anipulat e dat a in a relat ional dat abase from your Excel VBA applicat ion. Because we cannot possibly do j ust ice t o any of t hese t opics in a single chapt er, we've also provided you wit h point ers t o som e excellent resources for addit ional inform at ion. The abilit y t o work wit h dat abases m ay have been an opt ional skill for t he professional Excel developer five or six years ago. Today it is an absolut e requirem ent . As different t ypes of applicat ions converge, t here are fewer and fewer nont rivial Excel applicat ions t hat do not require int eract ion wit h a back- end dat abase of som e kind. I f you need t o be a t rue professional Excel developer, you will need t o underst and how t o work wit h dat abases.

Chapter 14. Data Manipulation Techniques I n t his chapt er, we t urn away slight ly from VBA t o exam ine how we can m ake t he m ost of Excel's advanced dat a- m anipulat ion feat ures. Alt hough t he user int erface is usually t he only part of our applicat ions t hat our users will know ( or care) about , it is t he qualit y and efficiency of our dat a processing t hat provides t he solid foundat ion on which a great user int erface can be built . Excel provides som e ext rem ely powerful dat a- m anipulat ion feat ures, if used in t he correct way. The m ost difficult aspect of organizing our dat a processing is oft en deciding which feat ures t o use in each sit uat ion, and how t hey can be efficient ly com bined.

Excel's Data Structures Excel's dat a- handling feat ures fall int o t wo dist inct groups. Most worksheet funct ions are designed t o operat e on individual it em s of dat a ( usually st ored in single cells) , whereas feat ures such as pivot t ables, filt ering and so on operat e on large set s of dat a, usually arranged in t ables. There are com parat ively few worksheet funct ions, such as VLOOKUP, MATCH and t he Dxxx funct ions t hat fill t he gap bet ween t he t wo paradigm s, operat ing on t ables of dat a but ret urning single- value result s. The way in which we arrange our dat a on t he sheet can have a significant im pact on t he ease wit h which Excel's feat ures can be used. Most workbooks t hat we see are organized in what can only be described as a haphazard nat ure. They oft en t ry t o com bine dat a ent ry, analysis and report ing wit hin t he sam e area of t he worksheet and are t herefore a com prom ise bet ween form at and funct ion. To design t he best user int erfaces, we have t o organize t he sheet t o appeal t o t he user ( such as including blank rows and/ or colum ns around t he dat a) , ignoring t he arrangem ent required by Excel's feat ures ( such as having t o be in a single t able) . Conversely, t o m ake t he m ost efficient use of m any of Excel's feat ures, we have t o organize our dat a in specific ways, which will probably not be t he nicest t o look at ( such as having t o leave lot s of whit e space around pivot t ables t o allow for t heir changing shape, or include art ificial colum n and row labels) .

Unstructured Ranges Unst ruct ured ranges are usually encount ered in t he part s of t he workbook designed for dat a ent ry. The spat ial arrangem ent of t he dat a will probably have som e m eaning t o t he user, wit h labels and form at t ing used t o ident ify t he dat a t o be t yped int o each cell. When dat a is arranged in t his unst ruct ured m anner, we can only use worksheet funct ions for our analysis. We cannot direct ly creat e pivot t ables or chart s from t his dat a, nor consolidat e, filt er or sort t he it em s. I n pract ice, we probably wouldn't want t o operat e on t his dat a as a whole anyway. They're likely t o be single, unrelat ed it em s of dat a, where t he lack of a st ruct ure is not a problem . I deally, each dat a- ent ry cell should be given an unam biguous nam e, so we can t ell at a glance where it 's used by ot her funct ions. The m ain problem wit h an unst ruct ured arrangem ent of dat a is t hat every cell has t o be t reat ed individuallybot h by t he user and t hrough codem aking it hard t o copy and past e or im port and export t he dat a. The inabilit y t o im port / export unst ruct ured ranges can be overcom e in Excel 2003 Professional by using XML t o apply som e st ruct ure t o t he cells, as we dem onst rat e in Chapt er 23 Excel, XML and Web Services.

Structured Ranges Most of t he feat ures in Excel t hat are designed t o operat e on or wit h large set s of dat a require t he dat a t o be organized in a t abular arrangem ent , usually wit h a header row cont aining unique labels which Excel can use t o ident ify each colum n. The m ost not able except ions t o t his are t he LOOKUP( )

funct ion and array form ulas ( see lat er) , which bot h work bet t er wit hout including a header row. The Dat a > Consolidat e feat ure works best wit h an even st rict er st ruct ure, where t he cont ent s of t he first colum n in t he dat a range can be used t o ident ify each row, as you'll see lat er. The easiest way for us t o set up our dat a t o be m ost useful t o Excel, t hen, is t o put it in a worksheet as a single t able, wit h a header row and consist ent dat a in each colum n, such as t he list of cust om ers shown in Figure 14- 1. This dat a is from t he sam ple Nort hWind Access dat abase supplied wit h Office, usually found at C: \ Program Files\ Microsoft Office\ Office\ Sam ples\ Nort hwind.m db.

Figu r e 1 4 - 1 . A St r u ct u r e d Ra n ge of D a t a [View full size image]

Using t he t echniques shown in Chapt er 13 Program m ing wit h Dat abases t o ret rieve dat a from a dat abase, we can easily creat e a st ruct ured range by populat ing t he sheet from an ADO recordset . Typical code t o do t hat is shown in List ing 14- 1, where rsDat a is an obj ect variable which refers t o an ADO recordset .

List in g 1 4 - 1 . Cr e a t in g a St r u ct u r e d Ra n ge fr om a n AD O Re cor dse t If Not rsData.EOF Then ' Clear the destination worksheet. Sheet1.UsedRange.Clear ' Add the column headers. For lField = 0 To rsData.Fields.Count - 1 Sheet1.Cells(1, lField + 1).Value = _ rsData.Fields(lField).Name Next lField ' Make the column headers bold, for clarity Sheet1.Rows(1).Font.Bold = True ' Copy the data from the recordset

Sheet1.Range("A2").CopyFromRecordset rsData ' Give the retrieved data range a name for later use Sheet1.Range("A1").CurrentRegion.Name = "Sheet1!MyData" Else MsgBox "No data located.", vbCritical, "Error!" End If

Excel 2003's Lists Working wit h a list of dat a is such a com m on use of Excel t hat Microsoft added t he List feat ure in Excel 2003 t o ease m any of t he t asks associat ed wit h t hem , such as sort ing, filt ering and adding and rem oving rows. A range can be convert ed t o a List using t he Dat a > List > Creat e List m enu it em . Figure 14- 2 shows t he sam e t able of cust om ers convert ed t o a List ( wit h rows 8 t o 90 hidden t o save space) . Not ice t he t hick ( blue) border, t he aut om at ic appearance of t he aut ofilt er drop downs in t he t op row and t he New Dat a row in row 93. The List can also be set t o aut om at ically show a t ot al row, using t he sam e t ot aling opt ions t hat are provided by t he SUBTOTAL( ) funct ion. Showing t he t ot al row only m akes sense if t he list cont ains num eric dat a, as t he only opt ion for t ext ual dat a is t o count t he rows. I t would have been m ore helpful t o have a " count dist inct " opt ion, but perhaps t hat will be added in a fut ure version of Excel.

Figu r e 1 4 - 2 . An Ex ce l 2 0 0 3 List Ra n ge [View full size image]

The biggest benefit of using List s is t hat any references t o an ent ire colum n of t he list are aut om at ically updat ed as dat a is added or delet ed, so we no longer need t o worry about whet her funct ions, chart s or defined nam es are referring t o t he full set of dat a. The List obj ect also provides som e rudim ent ary consist ency checking, such as ensuring t he dat a in a row st ays in sync, but is m ainly used by Excel under t he covers t o handle int eract ion wit h SharePoint and t o enable t he im port and export of XML. Unfort unat ely, SharePoint int eract ion is beyond t he scope of t his book, but using List s for XML im port / export is covered in Chapt er 23 Excel, XML and Web Services.

Query Tables Whenever we use one of t he Dat a > I m port Ext ernal Dat a m enu it em s t o im port a t ext file, a t able from a Web page or a dat abase query, t he result is a qu e r y t a ble. This is j ust a defined area of t he worksheet t hat encom passes t he ret rieved dat a and ( opt ionally) st ores t he connect ion inform at ion used t o obt ain t he dat a. I f t he connect ion inform at ion is st ored, t he query t able can be configured t o refresh t he dat a when t he file is opened or at regular int ervals. We can also t ell t he query t able how t o handle different am ount s of dat a, and whet her t o copy/ delet e any form ulas in adj acent colum ns. For anyt hing ot her t han t he m ost basic of dat abase queries, Excel uses t he MSQuery applicat ion t o provide an int erface for creat ing t he SQL SELECT st at em ent . I f you've used a UI for creat ing SQL st at em ent s before ( such as MS Access) , t he MSQuery int erface is easy t o underst and. Figure 14- 3 shows t he MSQuery screen, wit h a query t hat ret rieves som e exam ple dat a from t he Nort hWind OrderDet ails and associat ed t ables.

Figu r e 1 4 - 3 . Th e M SQu e r y UI for Cr e a t in g SQL Se le ct St a t e m e n t s [View full size image]

The biggest problem wit h creat ing query t ables is t hat t he SQL produced by MSQuery is such poor qualit y and includes t he full pat h t o t he dat abase file being queried. This m akes it alm ost im possible t o creat e a worksheet using a query t able t o ret rieve dat a from an Access dat abase and expect it t o work when inst alled at a client sit e. To creat e a robust solut ion, we always have t o include som e VBA code t o set t he query t able's Connect ion and SQL propert ies. For exam ple, we would rarely be able t o use t he built - in abilit y t o refresh t he query when t he file was opened, because it would fail if t he dat abase was m oved. I nst ead, we can use code sim ilar t o t hat shown in List ing 14- 2, which set s t he dat abase locat ion t o t he sam e direct ory as t he workbook and updat es t he query t able's propert ies before doing t he refresh. Not e t hat for t his exam ple t o work correct ly, you will need t o copy t he Nort hWind dat abase t o t he folder cont aining your workbook. I n pract ice, we would prom pt t he user t o select t he dat abase locat ion t he first t im e t he workbook was opened and st ore t hat choice in t he regist ry for subsequent use.

List in g 1 4 - 2 . Re fr e sh in g a Qu e r y Ta ble W h e n Ope n in g a W or k book Private Sub Workbook_Open() Dim sDatabase As String Dim sConnect As String Dim sSQL As String 'Where is the database to connect to? 'This is the usual location of the Northwind database. 'In practice, this should be a user-configurable option, 'probably read from the registry. sDatabase = Application.Path & "\Samples\Northwind.mdb" If Len(Dir(sDatabase)) > 0 Then 'Create the connection string using ADO sConnect = "OLEDB;Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & sDatabase & ";" 'Create a tidy sSQL = "SELECT " " " " FROM " " WHERE " " "

SQL statement, without the file paths O.OrderID, O.OrderDate, CUS.CustomerID, " & _ CUS.CompanyName, CUS.Country, CUS.City, " & _ CAT.CategoryName, P.ProductName, " & _ OD.Quantity, OD.UnitPrice, OD.Discount " & _ Categories CAT, Customers CUS, " & _ `Order Details` OD, Orders O, Products P " & _ CUS.CustomerID = O.CustomerID And " & _ OD.OrderID = O.OrderID And " & _ P.ProductID = OD.ProductID And " & _ CAT.CategoryID = P.CategoryID"

'Update and refresh the query table With wksData.QueryTables(1) .Connection = sConnect .CommandText = sSQL .Refresh End With End If End Sub

As well as rem oving t he hard- coded pat hs t o t he dat abase file, handling t he refresh t hrough VBA also provides t he abilit y t o include param et ers in t he query, such as only ret rieving t he dat a for a specific count ry where t he count ry nam e could be obt ained from worksheet cells. When creat ing a query t able using Excel's UI , t he result is a t able t hat uses ODBC t o connect t o t he dat abase, rat her t han t he ADO connect ions t hat we covered in Chapt er 13 Program m ing wit h

Dat abases. We can easily swit ch t o using an ADO connect ion if we prefer, by adding t he OLEDB; prefix t o t he ADO connect ion st ring. Even t hough we end up wit h very sim ilar code t o connect t o t he dat abase and run t he query, using query t ables is preferable t o populat ing t he worksheet from an ADO recordset , as t he query t able aut om at ically handles whet her t o insert new rows for ext ra dat a and whet her t o copy any form ulas from adj acent colum ns. Query t ables are very useful feat ures, but are lim it ed in t he am ount of dat a t hey can efficient ly handle. As t he end result of a query t able is a worksheet cont aining t he dat a, we are lim it ed by Excel's abilit y t o display t he dat a in a worksheet ( t hat is, a m axim um of 65,535 rows) and have t o devot e a significant am ount of resources ( bot h display resource and drawing t im e) t o show t he dat a on t he worksheet .

Data Processing Features Aft er we've arranged our dat a and/ or calculat ions in a t abular form , we can use Excel's dat a processing feat ures t o m anipulat e it . Obviously, t he act ual m anipulat ion t hat needs t o be done will depend t ot ally on t he problem being solved, so t his sect ion describes som e of t he t echniques available and how t hey can be linked t oget her. I t is up t o t he reader t o decide which t echniques are m ost appropriat e for t heir sit uat ion!

It Doesn't Have to Be Data Even t hough we've only considered dat a so far, Excel is not a dat abase; it 's designed t o m anipulat e num bers. We are not forced t o only include raw dat a in our st ruct ured ranges. Som e of t he m ost powerful num ber crunching com es from organizing our for m u la s in a st ruct ured, t abular form , t hen using Excel's dat a processing feat ures on t he result s of t hose calculat ions. The only caveat wit h using form ulas in our dat a t ables is t hat t he dat a processing ( consolidat ion, pivot t able, filt er and so on) will not be updat ed or refreshed when t he source form ulas are recalculat ed. We can easily work around t his by including som e VBA code t o t rigger t he processing from wit hin t he Worksheet _Calculat e event ( which convenient ly occurs aft er t he sheet has been calculat ed) .

Pivot Caches When Microsoft int roduced pivot t ables in Excel 95, t hey realized t hat it would be m uch m ore efficient t o st ore t he source dat a for t he pivot t ables in a hidden form wit hin t he workbook file t han wit hin worksheet cells. The hidden dat a st ores are called pivot ca ch e s and are j ust like query t ables, but wit hout t he visual represent at ion and can only be used by pivot t ables. They suffer from t he sam e problem of including hard- coded pat hs t o t he dat abase wit hin t heir connect ion and SQL query inform at ion, and t he sam e solut ion of using VBA t o define t he connect ion st ring and query t ext applies.

Pivot Tables Pivot t ables are Excel's prem ier dat a processing feat ure. Using eit her a t able in a worksheet as t he dat a source or a pivot cache for direct connect ion t o a dat abase, pivot t ables enable us t o filt er, group, sort , t ot al, count and drill down int o our dat a. Most books about using Excel include a sect ion explaining how t o set up and m anipulat e pivot t ables, so we're assum ing you already know t he basics. Wit h pivot t ables, t here is only one level of difficult y, so once t he basics are underst ood, t he skill is in knowing how t o m ost efficient ly use pivot t ables t o analyze our dat a and int egrat e t hem wit h t he rest of our dat a processing. The best way t o use pivot t ables for dat a processing in m ost applicat ions is t o creat e all t he pivot t ables beforehand, on individual worksheet s. I f t he pivot t ables are set up t o connect direct ly t o a dat abase, it is usually m ore efficient t o have a single, large pivot cache t hat feeds m ult iple pivot

t ables, t han having separat e queries for each pivot t able. The easiest way t o do t his is t o creat e t he first pivot t able norm ally, t hen base subsequent pivot t ables on t he first ( in st ep one of t he Pivot Table Wizard) . By using t he sam e pivot cache, Excel will only need t o st ore one copy of t he dat a wit hin t he workbook and all t he pivot t ables will be updat ed when t he cache is refreshed. Alt hough it is possible t o use t he Excel obj ect m odel t o creat e and m odify pivot t ables, t his should be kept t o a m inim um , because Excel refreshes and redraws t he t able wit h every m odificat ion. Wit h anyt hing ot her t han a t rivial am ount of dat a, t his quickly becom es ext rem ely slow. I n t he NWindOrders.xls exam ple workbook, found on t he CD in t he \ Concept s\ Ch14Dat a Manipulat ion Techniques folder, t he OrderDat a worksheet cont ains a query t able which ret rieves inform at ion about each order from t he Nort hWind sam ple Access dat abase, shown in Figure 14- 4.

Figu r e 1 4 - 4 . Th e Qu e r y Ta ble for N or t h W in d Or de r D e t a ils [View full size image]

As well as ret rieving t he specific dat a for t he order inform at ion, we've included ext ra inform at ion such as t he com pany nam e, count ry and product cat egory. Adding t his ext ra inform at ion will usually have negligible im pact on t he query execut ion t im e or ext ra dat a st orage requirem ent s, but enables us t o perform m ore diverse analysis using t he sam e raw dat a. For exam ple, Figure 14- 5 shows t he Pivot Table worksheet from t he exam ple workbook, which includes bot h a breakdown of order quant it ies by count ry and product cat egory and a list of our UK cust om ers.

Figu r e 1 4 - 5 . Tw o D ive r se Pivot Ta ble s, D e r ive d fr om t h e Sa m e Pivot Cache [View full size image]

Unfort unat ely, t his t echnique is lim it ed by t he lack of a " dist inct count " funct ion t o t ot al t he dat a. The " count " funct ion gives t he num ber of records, which in our case is t he t ot al num ber of order det ail line it em s. I f we had a " dist inct count " funct ion, we would be able t o ident ify t he num ber of orders placed by each cust om er ( by count ing t he num ber of dist inct order I Ds) or t he num ber of cust om ers in each count ry ( by count ing t he num ber of dist inct cust om er I Ds) .

Calculated Pivot Fields Excel enables us t o add ext ra fields and dat a t o our pivot caches, in t he form of ca lcu la t e d fie lds and ca lcu la t e d it e m s. A calculat ed field is an ext ra colum n, derived from one or m ore ot her fields, such as defining a calculat ed Profit field as Revenue Cost , where Revenue and Cost are fields in t he dat a set . These are of very lim it ed use, because Excel always does t he Sum of t he individual fields before perform ing t he calculat ion, so we get t he following: Sum of Profit = Sum of Revenue Sum of Cost This is okay and m arginally useful for t he sim ple cases, but is useless and dangerous if a m ore com plex form ula is required. Looking at t he Nort hWind dat a in Figure 14- 4, we have fields for t he Quant it y, Unit Price and Discount , so we m ight be t em pt ed t o add a calculat ed Revenue field as Quant it y x ( Unit Price Discount ) . Unfort unat ely, as Excel sum s t he individual fields before doing t he calculat ion, we end up m ult iplying t he t ot al quant it y sold by t he sum of all t he prices m inus t he sum of all t he discount s! Unless t hat is what you really require, it is far bet t er and m uch safer t o add t he addit ional fields at t he raw dat a level, eit her by including calculat ed fields in t he SQL query, or by adding ext ra colum ns alongside t he query t able, as shown in Figure 14- 6.

Figu r e 1 4 - 6 . Addin g a Ca lcu la t e d Fie ld Alon gside a Qu e r y Ta ble

When using colum ns alongside t he query t able, be sure t o t ick t he Fill down form ulas in colum ns adj acent t o dat a check box in t he query t able Propert ies dialog t o m ake sure t he form ulas are copied t o new rows. We should also use a defined nam e t o link t he pivot t able t o t he query t able, which can be adj ust ed t o ensure t he pivot t ables always refer t o t he correct dat a range, including t he addit ional form ulas. We creat e t he nam e t o refer t o t he full range of dat a and form ulas and use t hat nam e inst ead of a direct range reference in St ep 2 of t he Pivot Table Wizard. The defined nam e can be updat ed using t he QueryTable_Aft erRefresh event shown in List ing 14- 3, which also refreshes any pivot caches t hat use it .

List in g 1 4 - 3 . Upda t in g D e fin e d N a m e s a n d Re fr e sh in g Pivot Ca ch e s W h e n a Qu e r y Ta ble I s Re fr e sh e d 'Code contained within the OrderData worksheet code module 'Variable to hook the Query Table events Private WithEvents mqtData As QueryTable 'Called from the start of Workbook_Open() Public Sub Initialise() 'Set up the event hook for the query table Set mqtData = Me.QueryTables(1) End Sub 'Update dependent data when the QueryTable is refreshed Private Sub mqtData_AfterRefresh(ByVal Success As Boolean) Dim sRangeName As String Dim pcCache As PivotCache If Success Then 'Update the defined name sRangeName = Me.Name & "!pdPivotDataRange" mqtData.ResultRange.CurrentRegion.Name = sRangeName 'Refresh any dependent pivot caches

For Each pcCache In ThisWorkbook.PivotCaches If pcCache.SourceData = sRangeName Then pcCache.Refresh End If Next End If End Sub

Data Consolidation Probably t he m ost lit t le- known of Excel's dat a processing feat ures is it s abilit y t o consolidat e num eric dat a from m ult iple ranges int o a single t able, m at ching t he dat a using t he labels in bot h t he first row and first colum n of each range. I f a single cell is select ed, Excel first creat es a unique list of all t he colum n headers and a unique list of all t he row headers ( t hat is, t he labels in t he first colum n) t o creat e t he result t able. I f a range is already select ed, Excel uses t he row and colum n headers t hat are already t here. I t t hen adds ( or count s, averages, m ax, m in and so on) all t he it em s of dat a t hat share t he sam e row and colum n header. This proves ext rem ely useful when consolidat ing dat a and calculat ions t hat occur over a t im e series. For exam ple, im agine a proj ect t o analyze whet her t o build and run a new t hem e park. You m ight have a workbook for t he const ruct ion planning, anot her for t he ongoing operat ions, anot her for concessions and ret ail planning and so fort h. Each workbook cont ains a sum m ary t able showing t he cost s, revenue and cash flow for each year. A great ly sim plified version is shown in Figure 14- 7, but im agine t he Const ruct ion Planning and Operat ions t ables act ually exist in different workbooks and each has been given a defined nam e.

Figu r e 1 4 - 7 . Sim plifie d Pr oj e ct Pla n n in g

To consolidat e t hese ranges int o a single t able, select t he t op- left cell in t he t arget consolidat ion area, A15 in t his exam ple, and click t he Dat a > Consolidat e m enu t o access t he Consolidat e dialog shown in Figure 14- 8.

Figu r e 1 4 - 8 . Th e D a t a Con solida t ion D ia log

The All references list shows all t he source dat a ranges t hat will be consolidat ed. The ranges can be from t he sam e worksheet , a different worksheet , different workbook or even a closed workbook! Yes, t his is one of t he few Excel feat ures t hat works as well wit h closed workbooks as wit h open ones. To add a source dat a range, t ype t he reference in t he Reference: refedit and click t he Ad d but t on. Make sure t he t wo Use labels in check boxes are bot h t icked, t o ensure Excel m at ches bot h row and colum n headers. I f t hey're not t icked, Excel m at ches by posit ion, which is rarely what is r equir ed. When we click t he OK but t on, Excel m at ches all t he labels, adds up all t he sim ilar dat a and gives us t he t able shown in Figure 14- 9.

Figu r e 1 4 - 9 . Th e Con solida t e d Re su lt s

Advanced Filtering

The abilit y t o ext ract specific records from a large dat a set is oft en t he key t o successful and efficient dat a processing. Pivot t ables provide som e rudim ent ary filt ering capabilit y, but only by hiding individual it em s of dat a. Excel's Advanced Filt er feat ure enables us t o filt er t he dat a using m uch m ore com plex expressions, eit her j ust by hiding records in t he original t able, or m ore com m only by copying t he result ing records t o a new locat ion for furt her processing. The Advanced Filt er dialog is accessed by clicking t he Dat a > Filt er > Advanced Filt er m enu and is shown in Figur e 14- 10.

Figu r e 1 4 - 1 0 . Th e Adva n ce d Filt e r D ia log

As can be seen from Figure 14- 10, when copying t he filt ered dat a t o a new locat ion, an advanced filt er requires t hree ranges: List range is t he range cont aining t he original dat a t o be filt ered. Crit eria range is a worksheet range used t o define t he crit eria t o use when filt ering t he dat a. Underst anding how t o get t he m ost from t he crit eria range is t he key t o using advanced filt ering and is t he focus of t he rest of t his sect ion. Copy t o is t he dest inat ion range for t he filt ered dat a t o be copied t o. When t he OK but t on is clicked, Excel scans t hrough t he source dat a range, checks each record against t he crit eria specified in t he crit eria range and copies t he m at ching records t o t he next row in t he Copy t o range. The result is a subset of t he original dat a, arranged as a sim ple st ruct ured dat a areat hat is, not as a list or query t able. Unfort unat ely, every t im e t he Advanced Filt er dialog is shown, t he List range is eit her blanked out or guessed and t he Act ion default s t o Filt er in place. I t would be m uch m ore helpful if Excel

rem em bered t he source range and act ion, which would be possible if only Excel creat ed t he filt er as a query t able. I f t hat were t he case, we would also have a one- click Refresh opt ion and be able t o t ell Excel t o aut om at ically copy down adj acent form ulas. The best we can do in current versions is t o give our ranges som e specific nam es. I f t he workbook cont ains t he defined nam es Dat abase, Crit eria and/ or Ext ract , Excel will populat e t he dialog using t he ranges point ed t o by t hose nam es. To save you som e frust rat ion if you're working t hrough t hese exam ples, we've included t he rout ine shown in List ing 14- 14 in t he exam ple workbook t o refresh t he filt er wit hout showing t he Advanced Filt er dialog. Not e t hat in VBA, we use t he AdvancedFilt er m et hod on t he sou r ce dat a range and specify t he range t o copy t he filt ered dat a t o.

List in g 1 4 - 4 . Adva n ce d Filt e r in g w it h VBA Private Sub cmdRefresh_Click() Static rngCriteria As Range Dim rngNewCriteria As Range 'Provide a default initial selection If rngCriteria Is Nothing Then Set rngCriteria = Me.Range("A1") End If 'Use error trapping to handle a cancel On Error GoTo ErrNoRangeSelected 'Allow the user to select the criteria range to use 'Type:=8 allows for selection of ranges. Set rngNewCriteria = Application.InputBox( _ "Select the criteria range to use and click OK.", _ "Refresh Advanced Filter Extract", _ rngCriteria.Address, Type:=8) 'Remember the criteria range for next time Set rngCriteria = rngNewCriteria 'Perform the autofilter wksData.Range("pdPivotDataRange").AdvancedFilter _ xlFilterCopy, rngCriteria, _ Me.Range("rngAFExtract"), False ErrNoRangeSelected: Exit Sub End Sub

Criteria Ranges

The crit eria range is used t o specify t he equivalent of a SQL WHERE clause, t elling Excel which records t o ret urn. Figure 14- 11 shows an exam ple of a crit eria range, in A1: B3.

Figu r e 1 4 - 1 1 . An Adva n ce d Filt e r Cr it e r ia Ra n ge

The first row of t he crit eria range cont ains field nam es t hat m ust m at ch t he field nam es used in t he source dat a t able, but can be in any order. Subsequent rows cont ain t he dat a t o m at ch for each field. All t he it em s in a row are j oined wit h an AND operat ion, while separat e rows are j oined wit h an OR operat ion. Blank cells in t he crit eria range m at ch t o anyt hing. The crit eria range shown in Figure 14- 11 should be read as " ( Count ry= " UK" ) OR ( Count ry= " USA" AND Cat egoryNam e= " Beverages" ) ," so t hat will ret urn all orders from t he UK and all orders from t he USA for Beverages. I f we only want t he Beverage orders from t he UK or USA, we have t o include t he Beverages filt er in bot h lines, as shown in Figure 14- 12, which reads as " ( Count ry= " UK" AND Cat egoryNam e= " Beverages" ) OR ( Count ry= " USA" AND Cat egoryNam e= " Beverages" ) ."

Figu r e 1 4 - 1 2 . Be ve r a ge s fr om t h e UK or USA

By com bining t he AND and OR logic in t his way, Excel enables us t o creat e ext rem ely com plex cr it er ia. We're not lim it ed t o filt ering using " equals" relat ionships. I n fact , t he default filt er for t ext it em s is " st art s wit h" so t he crit eria range shown in Figure 14- 12 will also ret urn Beverages orders from t he Ukraine! To specify an exact ( case insensit ive) m at ch, we use an = sign, as shown in Figure 14- 13. When t yping t hese in, it 's a good idea t o st art wit h a quot e m ark, '= UK, t o t ell Excel t his is t ext and not a form ula, or t o form at t he crit eria cells as t ext before t yping t he values.

Figu r e 1 4 - 1 3 . Be ve r a ge s fr om On ly t h e UK or USA, a n d N ot Uk r a in e

As well as using t he = sign t o specify an exact m at ch, we can include t he ? and x wildcard charact ers t o m at ch any one charact er or any range of charact ers respect ively and use t he > and < sym bols t o m at ch ranges. To specify bot h a lower and upper lim it , we can include t he field nam e m ult iple t im es in t he crit eria range, such as t he crit eria shown in Figure 14- 14 t o select t he orders from UK cust om ers whose nam es st art wit h G t o N.

Figu r e 1 4 - 1 4 . Spe cifyin g a Ra n ge of M a t ch e s by Re pe a t in g t h e Fie ld Nam e

We can also, of course, filt er on num eric and dat e fields in exact ly t he sam e way, alt hough we have t o be careful if our workbooks will be used in m ult iple count ries wit h different dat e orders. For exam ple, if you're Am erican, you m ight expect t he crit eria range in Figure 14- 15 t o ret urn all t he records for 2004.

Figu r e 1 4 - 1 5 . Filt e r in g Be t w e e n t o D a t e s in t h e USA

When t he filt er is applied in t he UK, it doesn't ret urn any records, as 12/ 31/ 2004 is not recognized as a dat eit should be 31/ 12/ 2004 inst ead. To avoid t hese issues, it is a very good idea t o use form ulas t o const ruct t he dat e crit eria. I n t his exam ple we should replace t he hard- coded dat e in B2 wit h t he form ula ="="&1.23, t hereby allowing Excel t o use t he correct decim al separat ors for t he locat ion. As well as specifying t hat individual fields m ust have cert ain values, we can also filt er on

relat ionships bet ween t he dat a in m ult iple fields. To do t his, we use a dum m y field nam e t hat doesn't exist in t he source dat a, such as Calc1, Calc2 and so fort h and creat e a form ula using t he cells from t he first dat a row of t he t able ( t hat is, not t he header row) . The form ula m ust evaluat e t o TRUE or FALSE and m ust use relat ive referencing when referring t o t he dat a in t he t able. As Excel scans t hrough t he source t able, it increm ent s all t he relat ive row references in t he form ula, evaluat es t he form ula for t hat row and m at ches on a TRUE result . For exam ple, t he form ula shown in Figure 14- 16 will ret urn any orders where t he discount is m ore t han 5 percent of t he unit price. Not e t hat t his is ent ered as an Excel form ula, not as a t ext st ring, so you should see t he result of t he form ula ( TRUE or FALSE) displayed in t he cell.

Figu r e 1 4 - 1 6 . Filt e r in g Usin g a For m u la

I nst ead of using cell references, which can be hard t o read when t he referenced range is on a separat e sheet ( as in t his case) , Excel enables us t o use t he field nam es in t he form ula, such as = Discount / Unit Price> = 0.05 in t his case. Doing so usually result s in t he cell displaying a # NAME! error, but t hat can be safely ignored.

Advanced Functions The Database Functions We oft en see advanced filt ering used t o select a subset of dat a, wit h t he result of t he filt er being used by a few sim ple worksheet funct ions, such as SUM, AVERAGE and so on. Depending on t he com plexit y and num ber of t he worksheet funct ions t hat refer t o t he filt ered dat a, it can oft en be quicker and easier t o use Excel's da t a ba se fu n ct ion s. These are equivalent t o t he norm al SUM, AVERAGE, MI N, MAX, COUNT, COUNTA and so fort h, but inst ead of providing a sim ple range t o operat e over, we provide a source dat abase, a crit eria range t o filt er t he dat abase by and t he field in t he dat abase t o operat e on. For exam ple, while AVERAGE( K2: K2156) would give us t he overall average discount in our sam ple workbook, we could use t he DAVERAGE( ) funct ion t o calculat e t he average discount of our UK and USA Beverage sales, ignoring t hose wit h zero discount . The crit eria range for t he dat abase funct ions follows exact ly t he sam e st ruct ure and rules as for advanced filt ering, so we could use t he range shown in Figure 14- 17 in t his case.

Figu r e 1 4 - 1 7 . Cr it e r ia Ra n ge for D iscou n t e d UK a n d USA Be ve r a ge Sa le s

The average nonzero discount for our UK and USA Beverage sales could t hen be calculat ed using t he worksheet form ula:

=DAVERAGE(OrderData!pdPivotDataRange,"Discount",$A$1:$C$3)

I f we use t hese funct ions wit hin t he advanced filt er crit eria range, we can perform som e ext rem ely powerful filt ering. For exam ple, t he crit eria range shown in form ula view in Figure 14- 18 will ext ract all t he UK or USA Beverages sales t hat have a discount great er t han t he average discount for UK or USA Beverage sales, ignoring t hose sales where no discount was applied.

Figu r e 1 4 - 1 8 . Usin g a D a t a ba se Fu n ct ion W it h in a n Adva n ce d Filt e r

Cr it e r ia Ra n ge [View full size image]

Here, t he first t hree colum ns of t he crit eria range are being used by t he DAVERAGE( ) funct ion t o calculat e t he average discount . The average discount figure is t hen used t o populat e t he fourt h colum n in t he crit eria range, which is used by t he Advanced Filt er.

Array Formulas The st andard worksheet funct ions t hat we use every day t ypically accept one or m ore param et ers and ret urn a result . A few, such as SUM( ) and AVERAGE( ) , accept ranges or arrays in t heir param et ers and will ret urn t he sum , average and so on of all t he dat a t hey're given. Most worksheet funct ions and m at hem at ical operat ors, however, are given a single num ber for each of t heir param et ers and ret urn a single num ber as t he result . Even t hough a funct ion norm ally accept s single- figure param et ers, we can usually give it a m ult icell range reference and ent er t he funct ion using Ct rl+ Shift + Ent er inst ead of j ust pressing t he Ent er key. Doing t his t ells Excel t o calculat e t he funct ion as an a r r a y for m u la, whereby t he funct ion perform s it s calculat ion m ult iple t im es, it erat ing over each cell in t he range. The result is an array of num bers, wit h each elem ent in t he array corresponding t o one of t he cells in t he original reference. These result s can in t urn be fed int o t he param et ers of ot her funct ions and so on unt il t hey are event ually aggregat ed ( usually sum m ed) t o give a final answer. All of t he array calculat ion is done inside Excel and does not usually appear on t he worksheet . The m ost com m on use of array form ulas is t o count and sum list s, using m ult iple crit eria. Excel provides t he COUNTI F( ) and SUMI F( ) funct ions t hat accept a single filt er crit eria, so we could sum our UK orders using t he following funct ion:

=SUMIF($E$1:$E$2156,"=UK",$I$1:$I$2156)

where colum n E cont ains t he count ry nam es and colum n I cont ains t he order quant it ies. I f we want t he t ot al of our UK Beverages sales, we can no longer use SUMI F, because we need t wo crit eria. We could creat e a pivot t able for it , or use DSUM wit h a crit eria range, but bot h of t hose can be overkill if we only have a relat ively sm all list and sim ple crit eria, and cannot be used if we don't have colum n headers. Array form ulas occupy t he m iddle ground bet ween t he sim plicit y of a worksheet funct ion and t he com plexit y of crit eria ranges. I f we only have a series of condit ions AND'ed t oget her, we can use an array form ula of t he form :

=SUM(ValueRange*(Criteria1)*(Criteria2)*(Criteria...))

To get t he t ot al orders of UK Beverages from our exam ple dat a, we could use t he following for m ula:

=SUM($I$2:$I$2156*N($E$2:$E$2156="UK") *N($G$2:$G$2156="Beverages"))

Rem em ber t o ent er it using Ct rl+ Shift + Ent er. Let 's look at t he sam ple dat a shown in Figure 14- 19 ( on t he following page) t o see how it works.

Figu r e 1 4 - 1 9 . Sa m ple D a t a for a n Ar r a y For m u la [View full size image]

To explain how t he array form ula works, we need t o break it up and explain each part of t he form ula, st art ing from t he m iddle and working out ward: $E$2:$E$2156="UK" Excel scans t hrough each of t he cells in t he range E2: E2156 in t urn, checking whet her each one is equal t o UK. The result is an array of True or False values. I n our case, it is t he array { F, F, T, T, T, T, T, T, F, F} . N($E$2:$E$2156="UK") The N( ) funct ion convert s it s param et er t o a num ber. When given an array of True and False values, it convert s each True t o 1 and each False t o 0. I n our case, t his is t he array { 0, 0, 1, 1, 1, 1, 1, 1, 0, 0} . You m ight see a double- m inus being used inst ead of t he N( ) funct ion, such as --($E$2:$E$2156="UK"), which has t he sam e effect and is preferred by som e people. You m ight also see t he N( ) funct ion om it t ed from com plex array form ulas, as Excel will oft en ( but not always) do t he conversion wit hout being t old. $G$2:$G$2156="Beverages" Like t he t est for UK, Excel scans each cell in t he range G2: G2156, checking whet her each one is equal t o Beverages. I n our case, t he result is t he

array { T, F, T, F, F, F, F, T, F, F} . N($G$2:$G$2156="Beverages") Convert s t he Beverages True/ False array t o 1s and 0s, giving t he array { 1, 0, 1, 0, 0, 0, 0, 1, 0, 0} . $I$2:$I$2156 A st andard range reference, which is direct ly t ranslat ed int o t he array { 21, 15, 25, 25, 15, 20, 20, 25, 2, 20} . SUM($I$2:$I$2156*N($E$2:$E$2156="UK")*N($G$2:$G$2156="Beverages")) Mult iplies t he m at ching elem ent s from each of t he int erm ediat e arrays and t ot als t he result , as shown in Figure 14- 20.

Figu r e 1 4 - 2 0 . Th e I n n e r W or k in gs of a n Ar r a y For m u la [View full size image]

For t hese sit uat ions, t he decision t o use an array form ula inst ead of a pivot t able, advanced filt er or dat abase funct ion is largely dependent on t he size of t he dat a set and t he num ber of such form ulas required. For one or t wo t ot als, array form ulas are oft en t he m ost efficient , but as t he num ber of t ot als increases, it becom es m ore efficient t o perform t he filt ering before calculat ing t hem . Aft er you've grasped t he concept of array form ulas, you will probably ident ify m ore and m ore sit uat ions where t hey can be used. A com m on requirem ent for m any array form ulas is t o be able t o generat e a num ber sequence such as t he array { 1, 2, 3, 4, 5} . This can be achieved using t he awkward- looking form ula =ROW(INDIRECT("A1:A5")). The INDIRECT("A1:A5") part ret urns t he range reference A1: A5, and is insensit ive t o rows being m oved, added or delet ed. The ROW() part ret urns an array of t he row num ber of each row in t he range, being t he array of rows 1 t o 5, { 1, 2, 3, 4, 5} . The classic use of such a sequence is in t he " sum of digit s" calculat ion oft en used in credit card checksum form ulas. Given an arbit rary num ber, 672435, what is t he sum of each of t he digit s in t he num ber. I n t his case it 's 6+ 7+ 2+ 4+ 3+ 5= 27. To calculat e it using a form ula, we st art off wit h a sequence from 1 t o t he num ber of digit s, use t he sequence in t he MI D( ) funct ion t o ext ract each digit in t urn ( as t ext ) , convert it t o a num ber and t hen sum t he result ant array. The com plet e funct ion is as follows:

=SUM(VALUE(MID(B7,ROW(INDIRECT("A1:A"&LEN(B7))),1)))

Where B7 cont ains t he num ber for which we want t o calculat e t he sum of t he digit s. To underst and how it works, let 's break it down again: LEN(B7) gives t he lengt h of t he num ber ( t hat is, t he count of it s digit s; 6 in our case) . INDIRECT("A1:A"&LEN(B7)) ret urns t he range A1: A6 in our case. ROW(INDIRECT("A1:A"&LEN(B7))) ret urns t he row of each cell in t he range, giving t he array { 1, 2, 3, 4, 5, 6} . MID(B7,ROW(INDIRECT("A1:A"&LEN(B7))),1) applies t he sequence t o t he st art num param et er of t he MI D( ) funct ion, which ret urns t he nt h digit from t he num ber as t ext . I n t his case, it 's t he array { " 6" , " 7" , " 2" , " 4" , " 3" , " 5" } . VALUE(MID(B7,ROW(INDIRECT("A1:A"&LEN(B7))),1)) convert s t he array of t ext it em s t o num bers, giving t he array { 6, 7, 2, 4, 3, 5} . SUM(VALUE(MID(B7,ROW(INDIRECT("A1:A"&LEN(B7))),1))) sum s t he num bers in t he array, giving 6+ 7+ 2+ 4+ 3+ 5= 27. Despit e t heir definit e power, array form ulas have t hree m ain problem s: They're relat ively slow t o calculat e, part icularly when operat ing on large dat a set s; t hey're relat ively difficult t o underst and, when com pared t o norm al worksheet funct ions; and t hey're difficult t o t est , debug and m aint ain. I f you're using Excel 2002 or lat er, t he Tools > Audit ing > Evaluat e Form ula feat ure can be very useful for analyzing and debugging array form ulas. Our advice is t o use array form ulas when absolut ely necessary, but don't use t hem j ust t o save a few cells. I t is oft en quicker t o creat e and m uch easier t o underst and if int erm ediat e cells are used for ext ra calculat ions, inst ead of t rying t o perform everyt hing in a single array form ula.

Circular References Excel's online help file and m ost books m ent ion circular references in t erm s of " circular reference errors," where you've accident ally creat ed a circular reference by m ist yping a range reference. This is, indeed, one of m any pot ent ial sym pt om s of spreadsheet errors, which can be quit e difficult t o t rack down. I f you find yourself in t hat sit uat ion, t he findcirc.xla add- in, available for download fr om w w w .oalt d.co.uk/ Excel, m ight com e in useful. This add- in scans a workbook, t rying t o locat e a circular reference chain and provides t he full list of cells involved in t he circle. Wit h any luck, you should be able t o ident ify t he erroneous references and break t he chain. Much m ore int erest ing, t hough, is t he in t e n t ion a l use of circular references t o t idily solve business problem s. A great m any problem s in t he world of finance are circular in nat ure. A t ypical exam ple is t o det erm ine t he repaym ent s of a long- t erm loan. A com pany m ay have decided t o devot e 40 percent of t heir aft er- t ax profit s t o repay a loan. The problem is t hat bot h t he loan repaym ent and t he int erest charge can usually be offset against t he t ax liabilit y, t hereby increasing t he aft er- t ax

profit s and allowing t he com pany t o repay m ore of t he loan. The problem can be expressed using t he following equat ion: R = ( P R ( B R ) x I ) x ( 1 T ) x 0.4 where R is t he am ount of t he loan t o repay, P is t he profit before financing and t ax, B is t he balance of t he loan, I is t he int erest rat e and T is t he t ax rat e. I n t his ext rem ely sim ple exam ple, it is possible t o solve for R algebraically, giving t he following: R = ( P I x B) / ( 1 I + 1 / 0.4 / ( 1 T ) ) I n m ost real- life exam ples, however, t he int erest rat e m ay be st epped depending on t he out st anding balance, and t he t ax calculat ion is unlikely t o be as sim ple as j ust m ult iplying by t he t ax rat e. I n t hese sit uat ions, we can int ent ionally use circular references t o it erat e t o a solut ion. Figure 14- 21 shows a worksheet t o solve t his sim ple problem using circular references.

Figu r e 1 4 - 2 1 . Usin g Cir cu la r Re fe r e n ce s t o Ca lcu la t e Loa n Re pa ym e n t s

When we creat ed t he sheet , we init ially put a guessed value in cell B12. Aft er ent ering t he rem aining form ulas, we added t he forward reference in B12, t o refer t o B17. By default , Excel disables t he calculat ion of circular references. To enable t hem , put a t ick in t he Tools > Opt ions > Calculat ion > I t erat ion box. The Max I t erat ions and Max Change set t ings can be left as t heir default s; t hey have lit t le im pact on m ost circular- reference problem s. They com e int o

play if t he calculat ions are part icularly slow at converging t o a result . The Max Change det erm ines when Excel considers a circular reference t o have converged correct ly ( t he new result m ust be wit hin t he given value of t he previous it erat ion) , whereas t he Max I t erat ions provides a cut - off point t o t ell Excel t o st op t rying. I n slowly converging calculat ions, t he Max I t erat ions m ay need t o be increased t o allow t he it erat ions t o run unt il com plet ion. Such sit uat ions should be exam ined t o see whet her t he calculat ions can be reworked t o give a solut ion t hat converges wit hin fewer it er at ions. The worksheet shown in Figure 14- 21 adopt s a num ber of best pract ices when designing worksheet s in general, and specifically when using circular references: The t it le of t he worksheet m akes it clear t hat int ent ional circular references exist on t he sheet . The input ranges are clearly ident ified, wit h a light - colored background. Each form ula is clearly ident ified wit h a label st at ing what is being calculat ed. All t he form ulas except t he circular reference refer t o cells above t hem ; t he cell cont aining t he circular reference is t he only one wit h a reference t o a cell below it . The circular reference is clearly ident ified by including ( circ) in t he cell label. Bot h ends of t he circular reference have t he sam e label. The circular reference in cell B12 refers t o t he single cell holding t he value t o be fed back int o t he circular calculat ion, and only t hat cell. Aft er you've used circular references for a while, you'll not ice t wo com m on issues. First , if any of t he funct ions wit hin t he circle result s in an error value, it will propagat e t o every funct ion in t he circle. Second, t he abilit y of t he form ulas t o it erat e t o a solut ion can be quit e sensit ive t o t he init ial guess for t he feedback value. Bot h of t hese issues can be resolved by including a k ill sw it ch t o cont rol whet her t he circular reference is calculat ed and an ext ra cell t o provide a seed value for t he init ial guess. When t he kill swit ch is FALSE, t he feedback cell( s) t ake on t he seed value, which should also clear out any residual error values. When t he kill swit ch is TRUE, t he feedback cell( s) com plet e t he circle. Figure 14- 22 shows t he sam e loan repaym ent problem wit h t he addit ion of a kill swit ch in cell B4 and all ot her changes highlight ed in bold.

Figu r e 1 4 - 2 2 . Usin g a Kill Sw it ch t o Con t r ol t h e Cir cu la r Re fe r e n ce Fe e dba ck

Unfort unat ely, including circular references in our worksheet s prevent s us from using som e of Excel's feat ures. Specifically, t he Goal Seek, Dat a Table and Solver feat ures will only calculat e a single it erat ion of t he sheet for each st ep in t heir processing, so will never ret urn correct result s.

Conclusion I n t his chapt er, we have explained how t o organize bot h our dat a and calculat ions such t hat Excel can readily use t hem and how t o use query t ables t o access dat a in ext ernal dat abases, and efficient ly link t hem t o pivot t ables. We've also explained how t o ident ify and perform calculat ions on subset s of our dat a, using advanced filt ers, dat abase funct ions and array form ulas. We have also lift ed t he lid on t he int ent ional use of circular references in our applicat ions and explained how t o rem ain in cont rol when doing t hat . Arm ed wit h t hese t echniques, we can include efficient , robust and scalable dat a processing in our Excel applicat ions and can easily cope wit h t he m ost com plex dat a- handling requirem ent s.

Chapter 15. Advanced Charting Techniques Only a few m inut es are required t o learn t he basics of Excel's chart ing m odule, but m any frust rat ing hours are required t o get a chart looking " j ust right ." Most people creat e chart s using one of t he built - in chart t ypes, but are unable t o m odify t hem t o m eet t heir exact requirem ent s. This chapt er int roduces and explains t he fundam ent al t echniques we can use t o im pose our will on Excel's chart ing engine t o produce chart s t hat look exact ly how we want t hem t o. The chapt er focuses solely on t he t echnical aspect s of working wit h t he chart engine. We do not invest igat e which chart t ype should be used in any given sit uat ion, nor t he pros and cons of whet her 3D chart s can be used t o present dat a accurat ely, nor whet her you should use as few or as m any of t he colorful form at t ing opt ions t hat Excel support s.

Fundamental Techniques Combining Chart Types When m ost people creat e chart s, t hey st art t he Chart Wizard and browse t hrough all t he st andard and cust om chart t ypes shown in St ep 1, t rying t o find one t hat m ost closely resem bles t he look t hey're t rying t o achieve. More oft en t han not , t here isn't a close enough m at ch and t hey end up t hinking t hat Excel doesn't support t he chart t hey're t rying t o creat e. I n fact , we can include any num ber of colum n, bar, line, XY and/ or area series wit hin t he sam e chart . All of t he choices on t he Cust om Types t ab of St ep 1 of t he Chart Wizard are no m ore t han preform at t ed com binat ions of t hese basic st yles, wit h a bit of form at t ing t hrown in. I nst ead of relying on t hese cust om t ypes, we can usually get bet t er result s ( and a great er underst anding of t he chart engine) by creat ing t hese com binat ion chart s ourselves. Unfort unat ely, we can't com bine t he different 3D st yles, pie chart s or bubble chart s wit h ot her t ypes. Let 's st art by creat ing a sim ple colum n/ line com binat ion chart for t he dat a shown in Figure 15- 1, where we want t he 2004 sales t o be shown as colum ns, wit h t he forecast shown as lines.

Figu r e 1 5 - 1 . Th e Sa m ple D a t a t o Plot a s a Com bin a t ion Colu m n / Lin e Ch a r t

The easiest way t o st art is by select ing t he dat a region, A3:C8 and creat e a sim ple colum n chart from it , as shown in Figure 15- 2. We usually find it easiest t o st art wit h a colum n chart , but perhaps t hat 's because it 's t he default select ion in t he Chart Wizard, so we can creat e t he chart by select ing t he source dat a, clicking t he Chart Wizard t oolbar but t on and t hen t he Finish but t on on t he Chart Wizard.

Figu r e 1 5 - 2 . Th e Ch a r t W iza r d Cr e a t e d a St a n da r d Colu m n Ch a r t [View full size image]

To change t he Forecast values from a colum n t o a line, select t he series, click t he Chart > Chart Type m enu it em and select one of t he 2D Line chart t ypes, choosing t o apply t he chart t ype t o t he select ed series, as shown in Figure 15- 3.

Figu r e 1 5 - 3 . Se le ct in g t h e N e w Type for t h e Se le ct e d Se r ie s

When you click OK, t he Forecast series will display as a line, while t he Sales series rem ains as t he original colum n, as shown in Figure 15- 4. ( We've also m odified t he form at of t he Forecast line t o m ake it st and out in t he book.)

Figu r e 1 5 - 4 . Th e Re su lt in g Com bin a t ion Colu m n / Lin e Ch a r t [View full size image]

That 's j ust about all t here is t o it . St art wit h a sim ple colum n chart wit h m ult iple series, select each series in t urn, use t he Chart > Chart Type m enu t o change it s t ype and t hen apply t he required form at t ing. The possible com binat ions are lim it ed only by our im aginat ion and t he legibilit y of t he final chart !

Using Multiple Axes When we creat e one of t he st andard 2D chart s, t he plot area can have t wo set s of axes. The prim ary axes are usually displayed on t he bot t om and left , whereas t he secondary axes are usually displayed on t he t op and right . I f we have m ore t han one series on t he chart , we can choose which set of axes t o use for each series by double- clicking t he series and m aking our choice on t he Axis t ab of t he Form at Dat a Series dialog. When inst ruct ed t o place a series on t he secondary axis, Excel usually only displays a secondary Y axis on t he chart . This can be changed using t he Chart > Chart Opt ions m enu com m and, clicking t he Axes t ab and choosing what ever com binat ion of prim ary and secondary axes are desired. When t wo series are plot t ed on different axes, t he axes are scaled independent ly. Care m ust be t aken t o ensure t hat it is obvious t o t he viewer which series is plot t ed on which axis, by adding relevant axis labels and m at ching t hem t o t he series labels, as shown in Figure 15- 5.

Figu r e 1 5 - 5 . Usin g La be ls a n d Ax is Tit le s t o Cle a r ly I de n t ify W h ich Se r ie s Applie s t o W h ich Ax is

Using Defined Names to Link Charts to Data A key point t o underst and is t hat our chart s do not have t o refer direct ly t o t he cells cont aining t heir dat a. The source dat a for a chart series is provided by t he = SERI ES( ) funct ion, which can be seen in t he form ula bar when a series is select ed. The SERI ES( ) funct ion has t he following form at :

=SERIES(Name, XValues, YValues, PlotOrder)

Each of t he four param et ers can be a const ant or array of const ant s, a direct range reference or a reference t o a defined nam e. All t he lines in List ing 15- 1 are exam ples of valid funct ions.

List in g 1 5 - 1 . Ex a m ple s of Va lid SERI ES( ) Fu n ct ion s =SERIES(Sheet1!$B$1,Sheet1$A$2:$A$20,Sheet1!$B2:$B20,1) =SERIES("Sales",Sheet1$A$2:$A$20,Sheet1!$B2:$B20,1) =SERIES("Horizontal Line",{0,1},{123,123},1) =SERIES("Book Names",Book1.xls!chtXName,Book1.xls!chtYName,1) =SERIES("Sheet Names",Sheet1!chtXName,Sheet1!chtYName,1)

The last t wo versions of t he SERI ES( ) form ula use workbook- level and sheet - level defined nam es respect ively inst ead of direct cell references. This indirect ion enables us t o use t he defined nam es' definit ions t o m odify t he ranges or arrays passed t o t he chart , as shown in t he following exam ples.

Setting Up the Defined Name Links When you use a defined nam e in a SERI ES form ula, for best result s you should begin wit h a nam e t hat references a worksheet range direct ly. Aft er you have t his working correct ly, you can m odify t he nam e t o perform m ore com plex operat ions. Som et im es, if t he form ula for t he defined nam e is part icularly com plex, or if we m ake an error in it s definit ion, t he chart ing m odule will refuse t o accept t he nam e in t he SERI ES( ) funct ion. By st art ing wit h a very sim ple definit ion for t he nam es, we are able t o add t hem t o t he SERI ES( ) funct ion wit hout problem . Figure 15- 6 shows a sim ple line chart , wit h t he series select ed and t he SERI ES( ) funct ion displayed in t he form ula bar.

Figu r e 1 5 - 6 . A Sim ple Lin e Ch a r t [View full size image]

To change t he chart t o use defined nam es, we first creat e t wo defined nam es, for t he Dat e and Value ranges. Select I nsert > Nam e > Define from t he m enu and creat e t he following t wo nam es: Nam e:

Sheet1!chtDates

Refers t o: =Sheet1!$A$2:$A$9

Nam e:

Sheet1!chtValues

Refers t o: =Sheet1!$B$2:$B$9

Now select t he chart series and edit t he SERI ES( ) form ula t o read as follows:

=SERIES("Value",Sheet1!chtDates,Sheet1!chtValues,1)

That 's it ! The chart series is now linked t o t he defined nam es and t he defined nam es refer t o t he source dat a ranges. Obviously, if we had m ore series in our chart , we would have t o creat e ext ra nam es for t he values for each addit ional series. Now t hat we've set up t he linkage, we can m odify t he Refers To: form ulas for t he nam es ( t heir de fin it ion s) t o creat e som e int erest ing and t im esaving effect s.

Auto-Expanding Charts One of t he m ost frequent ly asked quest ions in t he m icrosoft .public. excel.chart ing newsgroup is how t o get a chart t o aut om at ically include new dat a as it 's t yped in. I n Excel 2003, if we creat e a List from t he dat a range and set eit her t he chart or t he defined nam es t o refer t o an ent ire colum n of t he List , t he reference will aut om at ically be adj ust ed t o include any new dat a. I n previous versions, or if we prefer not t o convert t he range t o a List in Excel 2003, we can use defined nam es t o do t he aut om at ic updat ing. The t rick is t o use a com binat ion of t he OFFSET( ) and COUNTA( ) funct ions in t he definit ion of t he nam e used for t he X values, t hen define t he nam e used for t he Y values as an offset from t he X values range. Select a cell in t he worksheet , t hen choose I nsert > Nam e > Define. Change t he definit ion of t he cht Dat es range t o be t he following by select ing t he exist ing cht Dat es ent ry, t yping t he new definit ion and clicking t he Add but t on: Nam e:

Sheet1!chtDates

Refers t o:

=OFFSET(Sheet1!$A$2,0,0,COUNTA(Sheet1!$A:$A)1,1)

The OFFSET( ) funct ion has t he following param et ers:

=OFFSET(SourceRange, RowsToMoveDown, ColumnsToMoveAcross, NumberOfRowsToInclude, NumberOfColumnsToInclude)

The COUNTA( ) funct ion ret urns t he num ber of non- blank cells in t he range, which in our case includes t he header row. We t herefore subt ract one t o get t he num ber of dat a it em s. Put t ing t he t wo t oget her gives us a reference t hat st art s in A2, m oves down zero rows and across zero colum ns

( so rem ains in A2) , has a num ber of rows equal t o t he count of our dat a it em s and is one colum n wide. While in t he Define Nam e dialog wit h t he cht Dat es nam e select ed, if we t ab int o t he Refers t o: box, Excel will highlight t he result ing range wit h it s " dancing ant s," as shown in Figure 15- 7.

Figu r e 1 5 - 7 . Ex ce l's D a n cin g An t s Sh ow in g t h e Ra n ge Re fe r r e d t o by t h e D e fin e d N a m e [View full size image]

While we're in t he Define Nam e dialog, we need t o m odify t he definit ion of t he cht Values nam e. The easiest way t o do t hat is t o again use t he OFFSET( ) funct ion, but t his t im e t o st art at t he range referred t o by t he cht Dat es nam e and m ove one colum n across, keeping t he sam e height and w idt h: Nam e:

Sheet1!chtValues

Refers t o: =OFFSET(Sheet1!chtDates,0,1)

Aft er clicking OK t o apply t hose changes and ret urn t o t he worksheet , t he chart should be showing exact ly t he sam e as beforet he new definit ions resolve t o t he sam e ranges we st art ed off wit h. The difference now is t hat if we t ype a new dat a point in row 10, it will aut om at ically appear on t he chart ( assum ing calculat ion is set t o Aut om at ic) ! To recap, it works because t he COUNTA( ) funct ion cont ained wit hin t he definit ion of t he cht Dat es range ret urns t he num ber of it em s in colum n A, which now includes t he new ent ry. That feeds int o t he OFFSET( ) funct ion, m aking it include t he new ent ry in it s result ing reference ( now A2:A10) . The cht Values range is updat ed t o refer t o one colum n across from t he expanded cht Dat es range, so becom es B2:B10 and bot h t hose nam es feed int o t he chart series = SERI ES( ) funct ion, m aking t he chart redraw t o include t he new dat a. The funct ions used in t he defined nam e assum e t hat t he source dat a is cont iguous, st art ing in cell A2. Blank cells will result in an incorrect ly calculat ed range. More precise form ulas are out side t he scope of t his book, but can easily be found by searching t he Google newsgroup archives.

I t is fundam ent al t o t he rest of t his sect ion t hat you fully underst and t he m echanism we're using. I f anyt hing is unclear, t ake som e t im e t o go t hrough t he exam ple, perhaps t rying t o creat e an aut oexpanding chart wit h t wo or t hree dat a series.

Scrolling and Zooming a Time Series I n t he aut o- expanding chart , we were only updat ing one of t he OFFSET( ) funct ion's param et ers. I f we m odify bot h t he row offset and num ber of rows, we can provide a sim ple, codeless m echanism for our users t o scroll and zoom t hrough a t im e series. I n t he worksheet shown in Figure 15- 8, we've added t wo scrollbars from t he Form s t oolbar below t he chart , set t heir Min and Max values t o correspond t o t he num ber of dat a point s and linked t heir values t o t he cells in colum n D, using t wo defined nam es Zoom Val and ScrollVal t o refer t o cells D24 and D25 respect ively.

Figu r e 1 5 - 8 . Allow in g t h e Use r t o Zoom a n d Scr oll Th r ou gh Tim e - Se r ie s Data [View full size image]

I n t he definit ion for t he cht Dat es nam e for t his exam ple, t he ScrollVal figure is used for t he row offset and t he Zoom Val figure provides t he num ber of dat a point s t o include in t he range:

Nam e:

Sheet1!chtDates

Refers t o: =OFFSET(Sheet1!$A$1,Sheet1!ScrollVal,0,Sheet1!ZoomVal,1)

The cht Values definit ion is t he sam e as before, =OFFSET(chtDates,0,1).

Transforming Coordinate Systems I n t he previous t wo exam ples, we've used t he OFFSET( ) funct ion in t he defined nam e t o change t he range of values drawn on t he chart , but keeping t he act ual dat a int act . We can also use defined nam es t o m odify t he dat a it self prior t o plot t ing it , such as t ransform ing bet ween polar and x, y coordinat e syst em s. I n polar coordinat es, a point 's locat ion is defined by it s angle and dist ance from t he origin, rat her t han t he dist ance- along and dist ance- up of t he st andard XY chart . Excel does not have a built - in chart t ype t hat will plot dat a in polar coordinat es, but we can use defined nam es t o convert t he ( angle, lengt h) polar coordinat e t o ( x, y) , which can t hen be drawn on a st andard XY chart . We're going t o show you how t o creat e t he chart shown in Figure 15- 9 from t he dat a shown beside it by using defined nam es. I n t his exam ple, t he lengt h figures are calculat ed from t he angle using t he form ula a*sin(a).

Figu r e 1 5 - 9 . Plot t in g Pola r Coor din a t e s on a n XY Sca t t e r Ch a r t

To dem onst rat e how t he various uses of defined nam es can be com bined, we'll im plem ent t wo levels of indirect ion. The first level will use t he t echnique from t he Aut o- Expanding Chart s sect ion

above t o aut om at ically handle changing dat a set s, while a second level will perform t he coordinat e t ransform at ion. The nam es t o handle t he aut om at ic updat es are defined as follows: Nam e:

Sheet1!datAngle

Refers t o:

=OFFSET(Sheet1!$A$3,1,0,COUNTA(Sheet1!$A$3:$A$5000)1,1)

Nam e: Sheet1!datLength Refer s =OFFSET(Sheet1!datAngle,0,1) t o:

The observant reader m ight have not iced t hat we're using a slight different version of t he OFFSET( ) funct ion in t he definit ion for t he dat Angle nam e. The version shown here is slight ly m ore robust , as it count s wit hin a specific range of 5,000 cells, st art ing wit h t he dat a header cell. You m ay have seen a variat ion on t his t echnique in which t he ent ire colum n address was used in t he COUNTA funct ion. By lim it ing t he range in t he way we do here, it doesn't m at t er whet her t he user changes t he cont ent s of t he cells above t he dat a range, such as adding ext ra t it les t o t he sheet . Wit h t he dat Angle and dat Lengt h nam es referring t o our source dat a, we can define t wo m ore nam es t o convert from t he polar t o x, y coordinat es: Nam e:

Sheet1!chtX

Refers t o: =Sheet1!datLength*COS(Sheet1!datAngle*PI()/180)

Nam e:

Sheet1!chtY

Refers t o: =Sheet1!datLength*SIN(Sheet1!datAngle*PI()/180)

The chart series can t hen use t he cht X and cht Y nam es for t he X and Y dat a:

=SERIES("Polar

Plot",Sheet1!chtX,Sheet1!chtY,1)

Charting a Function So we've used defined nam es t o change t he range of cells t o plot and t o m anipulat e t he dat a in t hat range before we plot it . I n Chapt er 14 Dat a Manipulat ion Techniques, we int roduced array form ulas and explained how t hey can be used t o perform calculat ions on arrays of dat a. We also showed a specific array form ula t hat is oft en used t o generat e a num ber sequence for use in ot her array

form ulas. What we didn't m ent ion was t hat we can also use array form ulas in our defined nam es and refer t o t hem from chart s! Figure 15- 10 shows a worksheet t hat uses array form ulas in defined nam es t o plot a m at hem at ical funct ion over a range of x values, wit hout needing t o read any dat a from t he worksheet .

Figu r e 1 5 - 1 0 . Usin g Ar r a y For m u la s in D e fin e d N a m e s t o Ge n e r a t e a n d Plot D a t a [View full size image]

This worksheet com bines a num ber of Excel t ricks t o generat e t he x axis values and use t hem t o calculat e t he y axis result s. We creat e a defined nam ed t o generat e t he values for t he x axis and give it t he nam e x, for reasons explained below: Nam e:

Sheet1!x

Refers t o:

=$C$6+(ROW(OFFSET($A$1,0,0,$C$8,1))-1)*($C$7$C$6)/($C$8-1)

Working t hrough t he part s of t his array form ula: OFFSET($A$1,0,0, $C$8,1) gives t he range A1: A51. ROW(OFFSET($A$1,0,0, (ROW(OFFSET($A$1,0,0, 2, …, 49, 50} .

$C$8,1)) convert s t he range t o t he array { 1, 2, 3, …, 50, 51} . $C$8,1))-1) subt ract s 1 from each it em in t he array, giving { 0, 1,

($C$7-$C$6)/($C$8-1) calculat es t he x axis increm ent for each point , giving 0.1 in our ex am ple. (ROW(OFFSET($A$1,0,0,$C$8,1))-1)*($C$7-$C$6)/($C$8-1) m ult iplies each it em in t he array by t he x axis increm ent , giving t he array { 0, 0.1, 0.2, …, 4.9, 5.0} . $C$6+(ROW(OFFSET($A$1,0,0,$C$8,1))-1)*($C$7-$C$6)/($C$8-1) adds t he array t o t he required x value st art point , result ing in t he range of x values t o use in t he chart { 4.5, 4.4, 4.3, …0.49, 0.50} . Unfort unat ely, if we t ry t o include Sheet 1! x in t he chart SERI ES( ) funct ion, we get an error about an incorrect range reference. To creat e t he chart , we use t he workaround described at t he st art of t his sect ion, by creat ing t wo nam es cht X and cht Y t hat point t o worksheet cells, use t hem t o creat e t he chart and t hen change t hem t o t heir real definit ions: Nam e:

Sheet1!chtX

Refers t o: =Sheet1!x

Nam e:

Sheet1!chtY

Refers t o: =EVALUATE(Sheet1!$B$3&"+x*0")

The definit ion for cht X is j ust a workaround for Excel not allowing us t o use t he x nam e in t he chart it self. The definit ion for cht Y needs som e explaining! Cell B3 cont ains t he equat ion t o be plot t ed, exp(x)*sin(x^2), as t ext . The EVALUATE funct ion is an XLM m acro funct ion, equivalent t o t he VBA Applicat ion.Evaluat e m et hod, but which can be called from wit hin a defined nam e. XLM funct ions were t he program m ing language for Excel 4, replaced by VBA in Excel 5, but st ill support ed in Excel 2003. The docum ent at ion for t he XLM funct ions can be downloaded from t he Microsoft Web sit e, by searching for " m acrofun.exe" or " xlm acro.exe." At t he t im e of writ ing, one version of t he file is available from ht t p: / / suppor t .m icr osoft .com / ?kbid= 128175. EVALUATE( ) evaluat es t he expression it 's given, ret urning a num eric result . I n our case, when t he expression is evaluat ed, Excel replaces t he x's in t he form ula wit h t he array of values produced by our Sheet 1! x defined nam e ( which is exact ly why we called it x) and ret urns an array cont aining t he result of t he funct ion for each of our x axis values. These arrays are plot t ed on t he chart , t o give t he line for t he equat ion. The &"+x*0" part of t he cht Y definit ion works around an error in Excel t hat som et im es causes t rig funct ions t o not evaluat e as array form ulas, by forcing t he ent ire form ula t o be evaluat ed as an array.

Faking It A chart is a visual art ifact , designed t o im part inform at ion t o t he viewer in a graphical m anner. As such, we should m ainly be int erest ed in whet her t he final chart looks correct and perform s it s purpose of providing clear inform at ion. We should not be t oo bot hered about whet her t he chart has been const ruct ed according t o a not ional set of generally approved guidelines. I n ot her words, we oft en need t o cheat by using som e of t he chart engine's feat ures in " creat ive and im aginat ive" ways. This sect ion explains a few ways in which we can get creat ive wit h Excel's chart engine, by

using som e of it s feat ures in ways t hey were probably not designed t o be used.

Error Bars When is a line not a line? When it 's an error bar! From a purely visual perspect ive, an error bar is a horizont al or vert ical line em anat ing from a dat a point , so if we ever have t he need t o draw horizont al or vert ical lines around our dat a point s, we m ight consider using error bars for t hose lines. A great exam ple is t he st ep chart shown in Figure 15- 11, where t he vert ical lines show t he change in an it em 's price during a day and t he horizont al lines connect t he end price from one day t o t he st art price for t he next day.

Figu r e 1 5 - 1 1 . A St e p Ch a r t

Because Excel doesn't include a built - in St ep Chart t ype, m any people believe t hat Excel can't creat e t hem . There are quit e a few ways in which it can be done, but t he easiest is probably t o use an XY chart wit h bot h vert ical and horizont al error bars. The basic dat a for t he chart consist s of a list of dat es and end- of- day prices, wit h a calculat ed field for t he change in price from t he end of t he previous day. From t his basic dat a, we st art wit h a norm al XY chart t o plot t he price against t he dat e, as shown in Figure 15- 12.

Figu r e 1 5 - 1 2 . St a r t w it h a N or m a l XY ( Sca t t e r ) Ch a r t of Pr ice vs. D a t e

[View full size image]

Below each dat a point , we want t o display a vert ical line equal t o t he change in price for t hat day, which we do by specifying a cust om m inus error value in t he Y Error Bars t ab of t he Form at Dat a Series Dialog, as shown in Figure 15- 13.

Figu r e 1 5 - 1 3 . Add a Cu st om M in u s Y Er r or Ba r for t h e D a y's Ch a n ge in Pr ice

The horizont al lines need t o j oin each dat a point t o t he bot t om of t he subsequent point 's error bar. That sounds difficult , but because t hese are daily prices all you need t o do is add Plus m arkers t o t he X error bars wit h a fixed value set t ing of 1. Wit h t he error bars configured, you should be seeing a chart som et hing like t hat shown in Figure 15- 14.

Figu r e 1 5 - 1 4 . Th e Ch a r t w it h t h e Addit ion a l Er r or Ba r s

All t hat rem ains is t o double- click t he error bar lines and use t he Pat t erns t ab t o change t heir color, t hickness and m arker st yle, and t hen double- click t he original XY line and form at t hat t o have no line and no m arker. The result appears t o be t he st ep chart from Figure 15- 11, even t hough it 's act ually only error bars being drawn.

Dummy XY Series When is an axis not an axis? When it 's an XY series wit h dat a labels! Excel's value axes are eit her boringly linear or logarit hm ic. They do not support breaks in t he axis, nor scales t hat vary along t he axis nor m any ot her com plex- axis effect s. Figure 15- 15 shows a chart wit h a variable Y axis, where t he bot t om half of t he chart plot s values from 0 t o 100 in st eps of 20, but t he t op half plot s 100 t o 1,000 in st eps of 200:

Figu r e 1 5 - 1 5 . Ch a r t w it h a Com ple x Ax is Sca le [View full size image]

I n t his chart , t he real Y axis goes from zero t o 200, but we've added a dum m y XY series using t he dat a from B10:C20, added dat a labels t o t he XY series, set t hem t o display t o t he left of t he point and cust om ized t heir t ext t o t hat shown in t he figure. The result appears t o be a com plex axis scale t hat varies up t he chart . The final st ep is t o t ransform t he real sales dat a in B3:B7 int o t he correct values for Excel t o plot on it s linear 0 t o 200 scale, which is done using a sim ple m apping form ula in C3:C7 of =IF(B3 0 Then dMax = dMax + (dMax - dMin) * 0.01 Else dMax = dMax - (dMax - dMin) * 0.01 End If If dMin > 0 Then dMin = dMin - (dMax - dMin) * 0.01 Else dMin = dMin + (dMax - dMin) * 0.01 End If 'What if they are both 0? If (dMax = 0) And (dMin = 0) Then dMax = 1

'This bit rounds the maximum and minimum values to 'reasonable values to chart. 'Find the range of values covered dPower = Log(dMax - dMin) / Log(10) dScale = 10 ^ (dPower - Int(dPower)) 'Find the scaling factor Select Case dScale Case 0 To 2.5 dScale = 0.2 Case 2.5 To 5 dScale = 0.5 Case 5 To 7.5 dScale = 1 Case Else dScale = 2 End Select 'Calculate the scaling factor (major unit) dScale = dScale * 10 ^ Int(dPower) 'Round the axis values to the nearest scaling factor ChartScale.dMin = dScale * Int(dMin / dScale) ChartScale.dMax = dScale * (Int(dMax / dScale) + 1) ChartScale.dScale = dScale End Function

Conclusion Alt hough Excel's chart ing engine has a relat ively poor reput at ion am ong users, m ost of t hat is due t o a lack of knowledge about how t o exploit t he engine, rat her t han a lack of feat ures. Yes, we would like t o see significant im provem ent s in t he qualit y of t he graphics, proper support for t rue 3D cont our and XYZ scat t er plot s and a general overhaul of t he user int erface t o m ake t he advanced t echniques shown in t his chapt er m uch m ore discoverable for t he average user. However, aft er we've spent t he t im e t o explore t he chart ing engine and fully underst and t he t echniques int roduced here, we realize t hat t he lim it s of Excel's chart ing capabilit ies are t o be found in our im aginat ion and creat ivit y, rat her t han wit h Excel.

Chapter 16. VBA Debugging Debugging is t he m ost im port ant and probably t he least underst ood aspect of program m ing. No one writ es perfect code on t he first t ry. Being able t o efficient ly locat e and correct t he m ist akes you've m ade is a significant part of what separat es a great program m er from a skilled am at eur. I n t his chapt er we dem onst rat e how t o use t he built - in debugging feat ures of t he Visual Basic Edit or ( VBE) t o locat e and correct bugs in your code as well as provide t ips and t echniques t hat will help you becom e a bet t er debugger.

Basic VBA Debugging Techniques Run Mode vs. Break Mode A running applicat ion can exist in one of t wo st at es. Run m ode is exact ly what it s nam e would suggest . The applicat ion is running norm ally. I n break m ode an applicat ion is st ill t echnically running, but execut ion has been int errupt ed. Break m ode can be t riggered by an unhandled runt im e error, a St op st at em ent , or a break point placed wit hin t he code. I n t he first group of t opics in t his sect ion we discuss how t he global VBE Error Trapping set t ing affect s how an applicat ion will ent er break m ode. The global error t rapping set t ings are locat ed under t he VBE Tools > Opt ions > General > Error Trapping m enu.

Break on All Errors This set t ing is reasonably self- explanat ory. When you have select ed t he Break on All Errors set t ing, all error handlers will be ignored. The m om ent any runt im e error occurs, an error m essage will display and you will have t he opt ion t o end t he program or ent er break m ode on t he line of code t hat caused t he error.

Break in Class Module I f an error occurs wit hin a class m odule procedure t hat cont ains an error handler, t his set t ing is equivalent t o t he Break on Unhandled Errors set t ing t hat we cover next . This is t o say it will not cause code execut ion t o halt in response t o t he error. I f an error occurs wit hin a class m odule procedure t hat doe s n ot cont ain an error handler, code execut ion will be int errupt ed on t he line of code in t he class m odule procedure t hat generat ed t he error. I f you've ever experienced a runt im e error on a line of code such as Userform1.Show, using t his set t ing will bring you t o t he line of code wit hin t he UserForm class m odule t hat act ually caused t he error.

Break on Unhandled Errors This set t ing causes code t o break on errors only where t here are no error handlers anywhere in t he call st ack above t he procedure in which t he error occurred. This is an im port ant dist inct ion. Even if an error occurs in a procedure wit hout an error handler, if t hat procedure was called by anot her procedure t hat does cont ain an error handler t he calling procedure's error handler will handle t he error. Code execut ion will only break when t here are no error handlers anywhere in t he call st ack above t he procedure where t he error occurred. We cover t he call st ack in m ore det ail in The Call St ack sect ion lat er in t his chapt er. Keep in m ind t hat t he error t rapping set t ing is an applicat ion- level set t ing t hat is persist ent in all

versions of Excel higher t han Excel 97. There is no way t o det ect or change t his set t ing wit hin your VBA code. Therefore, when you are having st range problem s wit h t he error handling behavior on a specific user's com put er, t he first t hing you should do is det erm ine what error t rapping set t ing is current ly specified for t hat inst ance of Excel.

Debug Mode Debug m ode refers t o t he st at e in an applicat ion in which error handling has been int ent ionally bypassed in som e fashion. Debug m ode is usually built in t o t he error handling syst em used by t he applicat ion. We covered debug m ode as a design feat ure of an error handling syst em in Chapt er 12 VBA Error Handling. Placing an applicat ion int o debug m ode can also be as sim ple as changing t he VBE Error Trapping set t ing t o Break on All Errors. This is not a robust solut ion for im plem ent ing debug m ode, however, because m any nont rivial applicat ions deliberat ely generat e runt im e errors t hat are designed t o be ignored as a norm al part of program execut ion. The Break on All Errors set t ing doesn't dist inguish bet ween errors t hat are a norm al part of code execut ion and t hose t hat represent bugs, it j ust breaks on any of t hem . I f you need t o get past a " norm al" error t o reach an error caused by a bug, you will need a m ore sophist icat ed debug m ode im plem ent at ion, such as t he one described next .

User-Defined Debug Mode A user- defined debug m ode t ypically involves a public const ant t hat can be used t o disable or m odify t he behavior of error handling on an applicat ion- wide basis. I n t he error handling syst em we dem onst rat ed in Chapt er 12 VBA Error Handling , debug m ode was im plem ent ed wit h t he following public const ant defined in t he MErrorHandler m odule:

Public Const gbDEBUG_MODE As Boolean = False

When set t o False, t he gbDEBUG_MODE const ant has no effect and applicat ion error handling proceeds norm ally. When set t o True, t he gbDEBUG_MODE const ant causes t he error handler wit hin t he procedure where t he error occurred t o drop int o a St op st at em ent . As we will see in t he next sect ion, t his init iat es break m ode and enables us t o debug t he error. The gbDEBUG_MODE const ant is also used t o disable error handling in ot her cont ext s. For exam ple, som e procedures m ay not have form al error handling. Procedures t hat are wrapped ent irely in On Error Resume Next are t he m ost com m on exam ple. When a procedure is const ruct ed in t his m anner, it im plies t hat any errors t hat m ight occur wit hin it are expect ed and should be ignored. This is not always a valid assum pt ion, so we need som e way of condit ionally disabling On Error Resume Next. The st andard way t o accom plish t his is shown in List ing 16- 1.

List in g 1 6 - 1 . Con dit ion a lly D isa blin g On Er r or Re su m e N e x t If Not gbDEBUG_MODE Then

On Error Resume Next End If

The code shown in List ing 16- 1 would appear at t he t op of t he procedure in quest ion. I f our gbDEBUG_MODE const ant has been set t o True, all error bypassing is disabled. When t he gbDEBUG_MODE const ant is set t o False, t he procedure funct ions norm ally, ignoring any errors t hat occur in t he course of it s execut ion.

The Stop Statement When VBA encount ers a St op st at em ent in your program , code execut ion is halt ed at t he st at em ent and break m ode is init iat ed. You can t hen use any of t he st andard debugging t echniques t hat will be discussed t hroughout t his chapt er t o st ep over t he St op st at em ent and debug your program . The St op st at em ent can be used as part of a larger debug m ode infrast ruct ure, as described in Chapt er 12 VBA Error Handling , or it can be added t o your code on an ad hoc basis when you are at t em pt ing t o debug errors in very specific locat ions. Just rem em ber t o rem ove any ad hoc St op st at em ent s from your code and disable debug m ode prior t o shipping your applicat ion. Failing t o do t his is one of t he m ost com m on debugging m ist akes we have seen. I f VBA encount ers a St op st at em ent in an unprot ect ed VBA applicat ion, t he user will be uncerem oniously dum ped int o break m ode. The vast m aj orit y of users will have no idea what has happened or what t hey should do about it . Proj ect prot ect ion disables t he effect of St op st at em ent s, but t his can cause even worse problem s if debug m ode has not been disabled. I f a program uses an error handling syst em sim ilar t o t he one we present ed in Chapt er 12 VBA Error Handling , it s proj ect is prot ect ed and it has been left in debug m ode, t he program will ent er an infinit e loop any t im e a runt im e error occurs. As shown in List ing 16- 2, t his is because t he St op st at em ent is skipped. Rat her t han halt ing at t he St op st at em ent , t he Resum e st at em ent t hat im m ediat ely follows t he St op st at em ent is execut ed. This causes VBA t o re- execut e t he line of code t hat generat ed t he error. This t riggers t he error handler again and causes t he Resum e st at em ent t o be execut ed again, ad infinit um .

List in g 1 6 - 2 . Th e Pe r ils of Le a vin g D e bu g M ode Act ive ErrorHandler: bReturn = False If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop ' This will be ignored in a protected project. Resume Else Resume ErrorExit End If End Function

I f you are very lucky, t he user will underst and how t o press Ct rl+ Break t o halt t he loop. I n m ost cases, however, t he only opt ion t hey will underst and is Ct rl+ Alt + Del or worse, t he Off but t on. Alw a ys rem em ber t o disable debug m ode prior t o shipping your code.

Conditional Compilation Constants We m ent ion condit ional com pilat ion const ant s very briefly in t his sect ion for t he sake of com plet eness. Condit ional com pilat ion const ant s are designed t o enable you t o com pile different versions of your code for different plat form s t hat it will run on. Because VBA is an int erpret ed rat her t han a com piled program m ing language, however, t he usefulness of condit ional com pilat ion const ant s is lim it ed. A condit ional com pilat ion const ant could be subst it ut ed for t he norm al const ant used t o cont rol debug m ode, but t here are no significant benefit s t o doing so. The single sit uat ion in which condit ional com pilat ion const ant s are t ruly useful in Excel VBA is when you need t o writ e an applicat ion t hat can be run on bot h t he PC and Mac plat form s using t he sam e code base. This sit uat ion is beyond t he scope of t his book. Condit ional com pilat ion const ant s are defined in t he VBE using t he Tools > VBAProj ect Propert ies m enu ( where VBAProj ect is t he act ual nam e of your proj ect ) . I n Figure 16- 1 we have creat ed a condit ional com pilat ion const ant nam ed DEBUG_MODE t hat could act as a subst it ut e for our gbDEBUG_MODE VBA const ant .

Figu r e 1 6 - 1 . Cr e a t in g Con dit ion a l Com pila t ion Con st a n t s

The cont rol where condit ional com pilat ion const ant s are defined is locat ed at t he bot t om of t he General t ab of t he Proj ect Propert ies dialog. Condit ional com pilat ion const ant s defined in t he Proj ect Propert ies dialog have public scope. These const ant s can only be assigned int eger values. They can funct ion as Boolean values using t he rule t hat zero = False and nonzero = True. You can define m ult iple condit ional com pilat ion const ant s by separat ing each const ant definit ion in t he Proj ect Propert ies dialog wit h a colon charact er. Condit ional com pilat ion const ant s cannot be t reat ed like st andard VBA const ant s. They have t heir own special set of st at em ent s wit h which t hey m ust be used. The DEBUG_MODE condit ional com pilat ion const ant would be used in a procedure as shown in List ing 16- 3.

List in g 1 6 - 3 . Usin g Con dit ion a l Com pila t ion Con st a n t s #If DEBUG_MODE Then On Error GoTo 0 #Else On Error Resume Next #End If

The # charact er before t he program m ing st at em ent s used wit h t he condit ional com pilat ion const ant is required. There are only a few such VBA program m ing language const ruct s designed t o work wit h condit ional com pilat ion const ant s. As you can see, for debugging purposes, condit ional com pilat ion const ant s are no different t han norm al VBA const ant s. For t his reason we suggest t hat you use condit ional com pilat ion const ant s only for sit uat ions where you t ruly need condit ional com pilat ion. Debugging in VBA is not one of t hem .

Using Break Points (F9) Break point s are select ed posit ions wit hin your code at which program execut ion will aut om at ically st op and ent er break m ode. Break point s are concept ually very sim ilar t o t he St op st at em ent . The difference is t hat break point s can be added and rem oved wit h t he click of a m ouse or a keyboard short cut , and t hey are not saved wit h your code. I f you set break point s in your code and t hen save your proj ect , you will find t hat t hey disappear if you close and re- open t he proj ect . St op st at em ent s will rem ain. As im plied above, break point s can be set in one of t wo ways: using your m ouse, or using keyboard short cut s. Figure 16- 2 shows a break point being set using t he m ouse.

Figu r e 1 6 - 2 . Se t t in g a Br e a k Poin t w it h You r M ou se [View full size image]

Each code m odule has a gray bar running down t he left side. This is called t he m a r gin in dica t or ba r. Clicking t he m argin indicat or bar adds a break point t o your code at t he point where you clicked. Clicking an exist ing break point in t he m argin indicat or bar rem oves t hat break point . Set t ing break point s using keyboard short cut s is j ust as easy. To set a break point , place t he cursor anywhere on t he line of code where you want t he break point t o be locat ed and press t he F9 key. A break point will be added t o t hat line of code. Pressing F9 while t he cursor is locat ed on an exist ing break point will rem ove t hat break point . Break point s can only be set on execut able lines of code. Code com m ent s, blank lines and variable declarat ions are exam ples of places where you cannot set a break point . Aft er you have set a break point , run your applicat ion as you would norm ally. When code execut ion reaches t he break point , it will st op and ent er break m ode. You can t hen use t he debugging t echniques discussed in t he following sect ions t o st ep over t he break point and debug t he problem you are having wit h your code.

Stepping Through Code The fundam ent al skill you m ust m ast er t o becom e proficient at debugging is st epping t hrough your code. The t erm " st epping t hrough your code" im plies a one- way, det erm inist ic process. This is not t he case. St epping t hrough code can involve m oving backward or forward t hrough your code as well as skipping sect ions of code or allowing sect ions of code t o run but t hen halt ing when t hey have com plet ed. We discuss t he various t echniques used t o st ep t hrough code in det ail in t his sect ion. Keep in m ind t hat t he whole point of st epping t hrough code is t o see what t he code is doing. When you st ep t hrough code you are duplicat ing exact ly what your program does when it is running norm ally, but you are doing it one line of code at a t im e. I n lat er sect ions we explain in det ail how you det erm ine what your code is doing once you are st epping t hrough it . Every code st epping feat ure in VBA has bot h a keyboard short cut and a t oolbar but t on equivalent . To becom e t ruly efficient at code debugging you m u st learn t he keyboard short cut s. For t his reason we cover only t he keyboard short cut s required t o init iat e each t echnique. I t is a sim ple m at t er t o exam ine t he VBE Debug t oolbar and discover t he equivalent t oolbar but t ons for each keyboard short cut we discuss. You can display t he VBE Debug t oolbar by choosing View > Toolbars > Debug from t he VBE m enu. We provide a com prehensive list of debugging- relat ed keyboard short cut s at t he end of t he chapt er.

Step Into (F8) St epping int o code can be init iat ed in one of t wo ways. I f you need t o exam ine code execut ion from t he beginning of an ent ry point procedure, you can place your cursor anywhere inside t hat procedure and press F8 t o begin st epping t hrough it s code. Alt ernat ively, if you want t o st art your debugging session deeper in t he procedure, or even deeper in t he call st ack, you can place a break point on t he first line of code you want t o debug and press F5. VBA will run your code unt il it reaches t he break point . You can t hen use F8 t o begin execut ing your code one line at a t im e from t hat point .

As you are st epping t hrough your code, you will not ice a yellow line t hat m oves each t im e you execut e one of t he st ep com m ands. This line is called t he e x e cu t ion poin t. To m ake it easier t o follow, t he execut ion point displays an arrow in t he m argin indicat or bar of t he code m odule, as shown in Figure 16- 3.

Figu r e 1 6 - 3 . Th e Ex e cu t ion Poin t I n dica t or [View full size image]

The execut ion point indicat or can be a bit confusing unt il you get used t o it . I t does not represent t he line of code you have j ust execut ed; rat her it shows t he line of code t hat will be execut ed next . The line of code you j ust execut ed is t he first execut able line of code above t he execut ion point indicat or . The reason VBA debugging works t his way will becom e apparent as you gain experience debugging. Having a clear m arker on t he line of code t hat will be execut ed next t ends t o be m uch m ore valuable t han having a m arker on t he line of code you j ust execut ed. The lat t er is easily det erm ined from t he form er, but not necessarily vice versa. Wit h each press of t he F8 key t he line of code current ly highlight ed by t he execut ion point indicat or will be execut ed and t he execut ion point indicat or will m ove t o t he line of code t hat logically follows based on t he result s of execut ing t he previous line. This m ay or m ay not be t he next physical line of code depending on how your program is st ruct ured.

Step Over (Shift+F8) While single st epping t hrough code you will oft en reach calls t o subprocedure t hat you are sure do not cont ain any errors. I f you cont inue t o press F8, code execut ion will st ep int o t he subprocedure and begin execut ing it s code. What you would rat her do in t his case is have VBA execut e all code

associat ed wit h t he subprocedure call and break again on t he line of code t hat im m ediat ely follows it . This is accom plished using t he St ep Over com m and, whose keyboard short cut is Shift + F8. The St ep Over com m and will execut e all code required t o pass over t he line current ly highlight ed by t he execut ion point indicat or and t hen break on t he next execut able line of code t hat logically follows t he result of t hat execut ion. I f t he line of code current ly highlight ed by t he execut ion point indicat or is not a call t o an out side procedure, t he St ep Over com m and is logically equivalent t o t he St ep I nt o com m and.

Step Out (Ctrl+Shift+F8) I f you st ep int o a subprocedure call by accident or if you st ep int o it on purpose and t hen realize you don't need t o cont inue st epping t hrough it , t he St ep Out com m and is your savior. Rat her t han having t o t ediously st ep t hrough t he rest of t he subprocedure code or physically locat e t he calling procedure and use t he St ep To Cursor com m and described in t he next sect ion, you can j ust press Ct rl+ Shift + F8. VBA will run t he rest of t he subprocedure aut om at ically and break again on t he next execut able line of code in t he calling procedure t hat logically follows t he result of t he subprocedure call.

Step to Cursor (Ctrl+F8) This opt ion would be m ore accurat ely called " run t o cursor." Whet her you are already in break m ode or you are j ust init iat ing a debugging session, you can sim ply place your cursor on t he line of code where you want execut ion t o break and press t he Ct rl+ F8 keyboard short cut . VBA will run your code from t he beginning unt il it reaches t he locat ion of your cursor, at which point it will ent er break m ode. This opt ion works alm ost exact ly like placing a break point on t he line. The only difference is t hat St ep t o Cursor is t ransient . As soon as you m ove t he cursor, t he st ep t o cursor point changes. This opt ion is m ost useful when you are single st epping t hrough your code and you encount er a sect ion of code you are sure does not cont ain any errors. Just use t he arrow keys t o m ove t he cursor down t o t he first execut able line of code beyond t his sect ion and press Ct rl+ F8. VBA will run all t he code bet ween t he current execut ion point and t he line m arked by t he cursor, ent ering break m ode again at t he line m arked by t he cursor. This enables you t o avoid t ediously single st epping t hrough sect ions of code where it is not necessary.

Changing the Execution Point, or Set Next Statement (Ctrl+F9) There are t im es when you want t o eit her skip lines of code t hat are about t o be execut ed or ret race t he execut ion st eps t hat got you t o where you are. One of t he m ost am azing t hings about t he VBA debugger is t hat it enables you t o do bot h of t hese t hings. You can m ove t he execut ion point backward and forward as you please using t he Set Next St at em ent com m and. The execut ion point can also be dragged t o different posit ions using your m ouse. Aft er you have reposit ioned t he execut ion point you can resum e st epping t hrough your code from t hat point using t he com m ands covered in t he previous sect ion. The difference bet ween changing t he execut ion point using t he Set Next St at em ent com m and and t he st ep com m ands t hat we have previously covered is t he following:

I f you reposit ion t he execut ion point such t hat it skips lines of code t hat have not yet been execut ed, t he lines you skipped w ill n ot be e x e cu t e d . I f you reposit ion t he execut ion point such t hat it resum es execut ion above t he point where it is current ly posit ioned, all of t he lines of code bet ween t he new posit ion of t he execut ion point and t he line of code direct ly above t he previous posit ion of t he execut ion point will be execut ed a se con d t im e . As you can im agine, you m ust have a very firm underst anding of what your code does and where it m akes sense t o change t he execut ion point t o avoid spurious errors or garbage result s. For exam ple, if you skip a line of code t hat set s an obj ect variable and t hen at t em pt t o execut e a line of code t hat uses t he obj ect variable, you will obviously get an " Obj ect variable or wit h block variable not set " error. Sim ilarly, if you m ove t he execut ion point backward such t hat you rerun a block of code t hat increm ent s a variable, t he value of t hat variable will be increm ent ed beyond t he value it would norm ally reach, result ing in pot ent ially garbage dat a. The abilit y t o change t he execut ion point is a very valuable t ool. I t enables you t o safely skip a sect ion of code t hat you know would ot herwise cause an error, or rerun a sect ion of code t hat you would like t o exam ine a second t im e wit hout having t o rest art debugging. Just be sure you are fully aware of what you are doing before you use it .

The Immediate Window (Ctrl+G) The I m m ediat e window is an int eract ive debugging t ool t hat is always available for you t o use. To display t he I m m ediat e window in t he VBE, press t he Ct rl+ G short cut key, or choose View > I m m ediat e Window from t he VBE m enu. You can do alm ost anyt hing in t he I m m ediat e window t hat you can do in your VBA proj ect , eit her at design t im e or while in break m ode, including t he follow ing: Calling procedures Checking or changing t he value of variables I nst ant iat ing and t est ing classes Running single- line loops The I m m ediat e window is t he m ore powerful cousin of t he m ost basic debugging t echnique of all; m essage box debugging. Message box debugging is t ypically t he first debugging m et hod you learn as a VBA program m er. I t involves placing m essage boxes at various locat ions wit hin your code, each of which display t he values of one or m ore variables and/ or locat ion inform at ion. The I m m ediat e window enables you t o do everyt hing you can do wit h m essage box debugging and m uch m ore, wit hout t he int rusive m essage boxes.

Debug.Print The Debug.Print st at em ent is t he I m m ediat e window's direct equivalent of m essage box debugging. The Debug.Print st at em ent print s t he value of t he expression t hat follows it t o t he I m m ediat e window. Two sam ple Debug.Print st at em ent s are shown in List ing 16- 4.

List in g 1 6 - 4 . Sa m ple D e bu g.Pr in t St a t e m e n t s Dim sSheetTab As String Dim wkbBook As Workbook Set wkbBook = Application.ActiveWorkbook sSheetTab = sSheetTabName(wkbBook, gsSHEET_TIME_ENTRY) Debug.Print wkbBook.Name Debug.Print sSheetTab

The result s of t hese Debug.Print st at em ent s are shown in Figure 16- 4.

Figu r e 1 6 - 4 . Ou t pu t Fr om t h e D e bu g.Pr in t St a t e m e n t s

As you can see, t he out put from each Debug.Print st at em ent begins on a new line in t he I m m ediat e window. I f you are fam iliar wit h VBA t ext I / O funct ions, not e t hat t he Debug.Print st at em ent support s m ost of t he sam e form at t ing feat ures support ed by t he t ext I / O Print # st at em ent . I t is uncom m on t o use ext ensively form at t ed out put from t he Debug.Print st at em ent in t he I m m ediat e window, so we do not cover t hese feat ures in any det ail ot her t han t o say t hat you can include m ult iple expressions in a Debug.Print st at em ent separat ed by com m as and t hey will all be print ed on t he sam e line in t he I m m ediat e window separat ed by t abs.

Making the Best Use of the Immediate Window There are t wo prim ary ways in which t he I m m ediat e window is used. I t can be used as a sim ple collect ion point for t he out put of Debug.Print st at em ent s t hat post result s as your code is running norm ally, or it can be used as an int eract ive t ool while you are st epping t hrough your code. There are t wo ways t o use t he im m ediat e window int eract ively: To e va lu a t e a va r ia ble or e x pr e ssion This is accom plished by ent ering a quest ion m ark charact er ( ?) followed by t he variable or expression t hat you want t o evaluat e. The I m m ediat e window is t ypically used for one- t im e evaluat ions. I f you want t o evaluat e t he variable or expression m ult iple t im es you should add a wat ch inst ead. We'll explain how t o do t his in The Wat ch Window sect ion lat er in t he chapt er. Figure 16- 5 shows t he I m m ediat e window being used t o evaluat e t he value in a worksheet cell t hat is used in t he next line of code t o be execut ed in t he m odule below it .

Figu r e 1 6 - 5 . Usin g t h e I m m e dia t e W in dow t o Eva lu a t e a n Ex pr e ssion [View full size image]

To e x e cu t e code This can include changing t he value of variables t hat are current ly being used in your applicat ion, m odifying applicat ion set t ings, calling procedures in your code and alm ost anyt hing else you could norm ally do in VBA. The only difference bet ween evaluat ing expressions and execut ing code using t he I m m ediat e window is t hat you leave out t he quest ion m ark when execut ing code. Placing your cursor anywhere wit hin t he line of code and pressing ent er causes t he line of code t o be execut ed. One com m on t ask involving code execut ion in t he im m ediat e window is m odifying t he value of t he Application.Cursor propert y. During long- running VBA procedures, t he Excel cursor will oft en flicker back and fort h bet ween an hourglass and t he default point er. This can be confusing t o t he user, so you force t he cursor t o display an hourglass at t he beginning of t he ent ry point procedure and reset it t o it s default at t he end of t he ent ry point procedure. The problem arises when you want t o debug som et hing wit hin t his procedure. Even in break m ode t he cursor set t ing you m ake is persist ent , and it applies t o t he VBE as well as t he Excel int erface. The solut ion is t o use t he I m m ediat e window t o change t he Application.Cursor propert y back t o it s default value, as shown in Figure 16- 6.

Figu r e 1 6 - 6 . Ex e cu t in g a Lin e of Code in t h e I m m e dia t e W in dow [View full size image]

Anot her excellent exam ple of t he abilit y t o execut e code in t he I m m ediat e window is running loops t hat print out inform at ion. Anyt hing you can fit on a single line can be run in t he I m m ediat e window and you can st ring m ult iple lines of VBA code t oget her by separat ing t hem wit h t he colon charact er ( : ) . Figure 16- 7 shows an exam ple of running a loop t hat print s out t he nam es of all open workbooks in t he I m m ediat e window.

Figu r e 1 6 - 7 . Ex e cu t in g a Loop in t h e I m m e dia t e W in dow

Keep in m ind t hat t he I m m ediat e window is fully funct ional even during design t im e. I t 's t he perfect environm ent for t est ing specific lines of code you are unsure about . The I m m ediat e window should becom e t he m ost com m only used debugging t ool in your arsenal.

The Call Stack (Ctrl+L) The call st ack refers t o t he list of procedures t hat were execut ed t o get you t o t he procedure you're current ly execut ing in break m ode. The call st ack is im port ant for t wo reasons:

1 . I t shows you t he execut ion pat h t hat got you t o where you are now. This is especially im port ant when debugging procedures t hat are called from m ult iple places wit hin your code. I t also enables you t o " walk" back up t he procedure st ack by sim ply select ing t he specific procedure you are int erest ed in. 2 . I f you want t o know exact ly which st at em ent s in each procedure in t he call st ack got you int o t he m ess t hat you are current ly debugging, press Ct rl+ L t o display t he Call St ack window. Double- click t he procedure nam e locat ed direct ly below t he nam e of t he procedure you are current ly in. The Call St ack window will bring you t o t he line of code in t he procedure you double- clicked t hat called t he procedure in which t he error occurred. This process will enable you t o cont inue walking back up t he call st ack unt il you reach t he line of code in t he ent ry point procedure where t he problem call originat ed. The Call St ack window is only available while execut ing code in break m ode. A t ypical exam ple of a Call St ack window you would encount er during break m ode is shown in Figure 16- 8.

Figu r e 1 6 - 8 . Th e Ca ll St a ck W in dow

Not ice t he procedure deepest in t he st ack is t he first procedure list ed and t he ent ry point procedure is at t he bot t om of t he list . When debugging procedures t hat display userform s you will see som et hing a bit st range in t he Call St ack window. An exam ple is shown in Figure 16- 9.

Figu r e 1 6 - 9 . N on - Ba sic Code En t r y in t h e Ca ll St a ck W in dow

The second ent ry, [], is an indicat ion t hat VBA had t o perform an operat ion " under t he covers," in t his case showing t he userform . You can st ep back and fort h t o procedures above and below t his ent ry, but you cannot st ep int o t his ent ry because it represent s a procedure t hat is not running wit hin VBA.

The Watch Window The Wat ch window is anot her am azingly m ult ifunct ional debugging t ool provided by t he VBE. I nexplicably, t here is no direct keyboard short cut available t o display t he Wat ch window. You can, however, use t he st andard Windows m enu hot key sequence Alt + V followed by an h charact er. The Wat ch window is t ypically used t o display t he value of variables or expressions t hat you have specified while you are st epping t hrough your code in break m ode. But t he Wat ch window cont ains t wo feat ures t hat m ake it invaluable as a run- t im e debugging t ool as well: Break When Value I s True and Break When Value Changes. Bot h of t hese feat ures are discussed at lengt h lat er in t his sect ion. Unlike t he I m m ediat e window, t he Wat ch window does not operat e at design t im e.

Setting a Basic Watch The m ost fundam ent al feat ure of t he Wat ch window is it s capabilit y t o show you t he value of a variable or expression t hat you specify in real t im e while you are st epping t hrough your code. Adding a wat ch is very easy, but inexplicably, it is anot her fundam ent ally im port ant operat ion involving t he Wat ch window t hat has no keyboard short cut . Therefore, t he easiest way t o add a wat ch is t o highlight t he variable or expression t hat you want t o wat ch, right - click t he highlight ed area and choose Add Wat ch from t he short cut m enu. The process of adding a wat ch is shown in Figure 16- 10, Figure 16- 11 and Figure 16- 12.

Figu r e 1 6 - 1 0 . Spe cifyin g t h e W a t ch Ex pr e ssion [View full size image]

Figu r e 1 6 - 1 1 . Con figu r in g t h e W a t ch Ex pr e ssion

Figu r e 1 6 - 1 2 . Th e Com ple t e d W a t ch Ex pr e ssion [View full size image]

The wat ch expression added is shown in Figure 16- 12. This sequence assum es t hat you sim ply accept ed all t he default values in t he Add Wat ch dialog shown in Figure 16- 11. We discuss why and when you m ight want t o change t hese default s lat er in t his sect ion. As you can see, t he Wat ch window displays t he expression being wat ched, t he value of t he expression, t he dat a t ype of t he expression and t he code m odule and procedure nam e wit hin which t he wat ch was defined. You can add as m any sim ult aneous wat ches as you like. Each wat ch will be shown on a separat e line in t he Wat ch window.

Using a Basic Watch As you st ep t hrough your code in break m ode, t he Wat ch window will cont inually updat e t he values of all of t he wat ches you've added. This is t he prim ary purpose of t he Wat ch window. There are t ypically a large num ber of t hings going on in your code and t he Wat ch window provides you wit h a m et hod t o m onit or exact ly what 's happening t o all of t he crit ical variables and expressions in t he code you're debugging. The Wat ch window enables you t o m odify t he value of any variable or expression t hat is an lva lu e . An lvalue is j ust a fancy com put er science t erm t hat says t he variable or expression can appear on t he left side of an assignm ent . I n t he following line of code, for exam ple, t he expression Sheet1.Range("A1").Value is an lvalue because it is valid for t his expression t o appear on t he left side of t he assignm ent operat ion, which in t his case assigns it t he value of 25:

Sheet1.Range("A1").Value = 25

By cont rast , t he expression ThisWorkbook.Worksheets.Count is not an lvalue because you cannot sim ply assign it a new value. I t can only be changed by physically adding or rem oving worksheet s in t he workbook.

To m odify t he value of an lvalue expression in t he Wat ch window, j ust click t he Wat ch window Value colum n in t he row cont aining t he value you want t o m odify. The Value colum n ent ry will t urn int o an edit able field and you can t ype in a new value. The new value m ust be a dat a t ype t hat is valid for t he expression you are alt ering. Figure 16- 13 shows us changing t he value of t he expression Sheet1.Range("A1").Value t o 99.

Figu r e 1 6 - 1 3 . M odifyin g t h e Va lu e of a W a t ch Ex pr e ssion [View full size image]

You can also edit t he Expression colum n of t he wat ch. I n t he case of Figure 16- 13, for exam ple, you could change t he wat ch t o point at Range("B1") inst ead of Range("A1"). Don't be t oo concerned about t rying t o det erm ine what you're allowed t o change. I f you m ake a m ist ake, t he VBE will display an error m essage and t he Wat ch window will revert t o it s previous st at e. No harm done.

Watch Types When you creat e a wat ch expression, you don't have t o accept t he default values of all t he opt ions in t he Wat ch window. By m odifying t hese default s you can creat e wat ches t hat are m uch m ore powerful t han t hose t hat sim ply use t he default values. There are t wo opt ion cat egories t hat you can m odify when you add a wat ch: Wat ch Cont ext and Wat ch Type. We cover t hem bot h in following sect ions. Don't worry if you don't get t he values of t hese opt ions correct when you first add t he wat ch. You can edit any exist ing wat ch, which allows you t o m odify t hese opt ions. The st eps required t o edit a wat ch are shown in Figure 16- 14 and Figure 16- 15.

Figu r e 1 6 - 1 4 . Righ t - Click ove r a W a t ch Ex pr e ssion t o Edit I t [View full size image]

Figu r e 1 6 - 1 5 . Ch a n ge t h e W a t ch Type t o Br e a k W h e n Va lu e Ch a n ge s

Watch Context

The Wat ch Cont ext opt ions cont rol t he scope of t he wat ch expression. Wat ches can be confined t o code execut ing wit hin a single procedure in a single m odule ( t he t ypical default ) or t hey can apply t o code execut ing anywhere wit hin t he proj ect . Suppose, for exam ple, you want t o place a wat ch on a global variable or expression. I f you sim ply add a wat ch on t hat variable or expression from wit hin t he first procedure where you com e across it , t he wat ch will only be valid when code is execut ing wit hin t he procedure where t he wat ch was added. To change t his, you change t he select ions in t he t wo Wat ch Cont ext drop- downs.

Module We are going t o discuss t he Wat ch Cont ext opt ions in reverse order of t heir appearance on t he Wat ch dialog because t he Module set t ing drives t he Pr ocedur e set t ing. You have t wo opt ions when select ing a Module set t ing: 1 . Se le ct a Spe cific M odu le All st andard m odules, class m odules, userform m odules and docum ent obj ect m odules in t he current proj ect are available t o be select ed. When you select a specific m odule, t he values available in t he Pr ocedur e set t ing will be narrowed down t o only t he procedures t hat exist wit hin t he m odule you select ed. The scope of t he wat ch will t hen be det erm ined by t he value you select in t he Pr ocedur e drop- down. 2 . Se le ct t h e ( All M odu le s) Va lu e This is t he first value in t he Module drop- down. When you select t his value, t he value of t he Pr ocedur e drop- down will aut om at ically change t o t he corresponding ( All Procedures) value. When you m ake t his select ion, t he scope of t he wat ch will be global. The Wat ch window will at t em pt t o evaluat e it no m at t er where code is current ly execut ing wit hin t he proj ect .

Procedure The Pr ocedur e set t ing det erm ines what procedure t he wat ch expression will be valid for wit hin t he m odule specified by t he Module set t ing. As described above, if t he Module set t ing value is ( All Modules) , t hen you have no choice over t he Pr ocedur e set t ing. I n t his case, it s only possible value will be ( All Procedures) . I f a specific code m odule has been select ed in t he Module set t ing, t here are t wo opt ions for t he Pr ocedur e set t ing:

1 . Se le ct t h e N a m e of a Spe cific Pr oce du r e I n t his case, t he wat ch expression will only be evaluat ed when code is execut ing wit hin t he specified procedure or one of t he subprocedures called from t hat procedure. I f code is execut ing in som e unrelat ed procedure, even if it is cont ained wit hin t he sam e m odule, t he value displayed by t he Wat ch window for t he wat ch expression will be " < Out of cont ext > " . 2 . Se le ct t h e ( All Pr oce du r e s) Va lu e Select ing t his value m eans t he scope of t he wat ch will be all procedures wit hin t he m odule specified by t he Module set t ing. Whenever code is execut ing wit hin t hat m odule, t he Wat ch window will at t em pt t o evaluat e t he wat ch. When code is execut ing wit hin a different m odule t he wat ch value will display " < Out of cont ext > " . The only except ion is if code execut ion reached a different m odule as t he result of a call t o a subprocedure originat ing in t he m odule where t he wat ch was creat ed. I n t hat case t he wat ch will cont inue t o evaluat e norm ally.

Watch Type The Wat ch Type set t ing will det erm ine how t he Wat ch window handles t he wat ch. The first opt ion is passive, used only while st epping t hrough code in break m ode. The second t wo opt ions are act ive and are used t o init iat e break m ode.

Watch Expression This is t he default value for t he Wat ch Type set t ing. I t j ust adds t he specified variable or expression as a wat ch and displays it s value while you are st epping t hrough your code in break m ode.

Break When Value Is True This Wat ch Type set t ing has m uch in com m on wit h t he Excel condit ional form at t ing expressions we discussed in Chapt er 3 Excel and VBA Developm ent Best Pract ices. When you specify t his wat ch t ype, your wat ch is t reat ed as a Boolean expression and code execut ion will st op and ent er break m ode whenever t he value of t he expression changes from False t o True or < out of cont ext > t o Tr ue. This t ype of wat ch can be const ruct ed as eit her a Boolean expression or a sim ple wat ch expression whose only possible values are True or False. Regardless of t he way in which you const ruct t he wat ch, code execut ion will st op and ent er break m ode whenever t he value of t he wat ch evaluat es t o Tr ue. One very com m on use for t his Wat ch Type set t ing is som ewhat count erint uit ive but very valuable in pract ice. The Application. EnableEvents propert y is persist ent from t he t im e it is set t o False unt il it is explicit ly set t o True or Excel is closed, which ever com es first . While t his propert y is False, all Excel event s are disabled. One of t he m ost frequent Excel program m ing bugs is t o set Application.EnableEvents t o False and t hen forget t o set it back t o True when you no longer need t o disable event s. This will obviously cause havoc in any applicat ion t hat depends on t rapping Excel event s for it s operat ion. We can very easily debug t his problem by t elling t he Wat ch window t o break code execut ion

whenever t he Application.EnableEvents propert y doe s n ot equal True. I f t he Application.EnableEvents propert y does not equal True, by definit ion it has been set t o False. Aft er you have set t his wat ch, each t im e code execut ion breaks you know you have t urned off Excel event s. You can t hen exam ine t he code t hat follows and ensure t hat Application.EnableEvents has been properly reset . We dem onst rat e set t ing t his wat ch expression in Figure 16- 16.

Figu r e 1 6 - 1 6 . Se t t in g a Br e a k W h e n Va lu e I s Tr u e W a t ch

Not e t hat t he wat ch expression we have defined is Application. EnableEvents True. When t his expression evaluat es t o True, it m eans t hat Application.EnableEvents has been set t o False. ( I f Application.EnableEvents does not equal True, it m ust be False.) Also not e t hat we have set t he Cont ext of t his wat ch t o ( All Procedures) and ( All Modules) . This is because t he Application.EnableEvents propert y is global t o t he current inst ance of Excel, regardless of where it has been set .

Break When Value Changes Anot her com m on sit uat ion you want t o wat ch for is when t he value of an expression or variable in your code changes. I n t his case you are t ypically not concerned about t he specific value t o which your variable or expression changed, rat her you want code execut ion t o break whenever t hat value changes t o anyt hing ot her t han it s current value. This t ype of wat ch can be const ruct ed as eit her a Boolean expression or a sim ple wat ch expression. Regardless of how you const ruct t he wat ch, code execut ion will st op and ent er break m ode whenever t he value of t he expression changes. I n Figure 16- 17 we set a wat ch t hat will cause code

execut ion t o st op and ent er break m ode whenever t he value of t he expression Sheet1.Range("A1").Value changes.

Figu r e 1 6 - 1 7 . Se t t in g a Br e a k W h e n Va lu e Ch a n ge s Ex pr e ssion

Not e t hat we have set t he Cont ext set t ings for t his wat ch t o a specific m odule and procedure. This m eans code execut ion will only break when t he value of t he wat ch expression is changed by t he specified procedure or one of it s subprocedures.

Arrays, UDTs and Classes in the Watch Window Sim ple variables and expressions added t o t he Wat ch window are easy t o underst and on sight . But t he Wat ch window is m uch m ore powerful t han t his. I t can easily handle com plex dat a t ypes such as arrays, UDTs and classes. Wat ches for t hese dat a t ypes are added in exact ly t he sam e way t hat wat ches for sim ple variables are added, but t he result s are quit e different . Recall t hat in Chapt er 13 Program m ing wit h Dat abases we creat ed a BI LLABLE_HOURS UDT t o hold inform at ion about a billable hour ent ry from our t im esheet applicat ion. List ing 16- 5 shows a sect ion of code from t he Post Tim eEnt riesToDat abase procedure t hat uses t his UDT.

List in g 1 6 - 5 . Code Th a t Use s t h e BI LLABLE_ H OURS UD T

Dim uData As BILLABLE_HOUR For Each rngCell In rngTable uData.lConsultantID = rngCell.Value uData.dteDateWorked = rngCell.Offset(0, 1).Value uData.lProjectID = rngCell.Offset(0, 2).Value uData.lActivityID = rngCell.Offset(0, 3).Value uData.dHours = rngCell.Offset(0, 4).Value If Not bInsertTimeEntry(uData) Then Err.Raise glHANDLED_ERROR End If Next rngCell

Let 's assum e t hat we are debugging t his code and we want t o wat ch t he cont ent s of t he BI LLABLE_HOURS UDT. There's no need t o add each individual elem ent of t he UDT t o t he Wat ch window. Just add a wat ch on t he uDat a UDT variable as shown in Figure 16- 18.

Figu r e 1 6 - 1 8 . Addin g a W a t ch on a UD T Va r ia ble

Figure 16- 19 shows how t he Wat ch window displays a UDT wat ch expression when you are st epping t hrough code.

Figu r e 1 6 - 1 9 . Usin g a W a t ch on a UD T Va r ia ble [View full size image]

Even t hough we only added a wat ch t o t he uDat a variable, t he Wat ch window underst ands t his is a UDT and it displays t he m em ber variables of t he UDT in a hierarchical list below t he variable t he wat ch was defined on. Array variables and obj ect s variables are t reat ed t he sam e way. The Wat ch window recognizes t heir dat a t ypes and displays t he current values of all t heir m em bers in a hierarchical list sim ilar t o t hat shown in Figure 16- 19. This is a great way t o learn t he obj ect m odel of t he applicat ion you're working wit h. Set a wat ch on an obj ect variable, t rigger break m ode once t hat variable has been set and t hen use t he Wat ch window t o drill down t hrough t hat obj ect 's propert ies and child collect ions.

Quick Watch (Shift+F9) The Quick Wat ch window is t he lit t le brot her of t he Wat ch window. By highlight ing a variable or expression while in break m ode and pressing Shift + F9, t he Quick Wat ch window allows you t o exam ine all t he sam e det ails t hat would be displayed by t he Wat ch window except for t he dat a t ype. The Quick Wat ch window also allows you t o quickly add t he select ed variable or expression t o

t he Wat ch window by invoking t he Add but t on ( Alt + A) . Figure 16- 20 shows an exam ple of t he Quick Wat ch window being used t o display t he cont ent s of a st ring variable.

Figu r e 1 6 - 2 0 . Th e Qu ick W a t ch W in dow

The Quick Wat ch window is designed for hands- on- t he- keyboard debugging. I f you're using t he m ouse, in m ost cases t he Quick Wat ch window will be unnecessary. This is because t he VBE will dynam ically display t he value of m ost expressions in a t oolt ip when you hover your m ouse cursor over t hem . This behavior is shown in Figure 16- 21.

Figu r e 1 6 - 2 1 . Toolt ip Ex pr e ssion Eva lu a t ion [View full size image]

Even if you do m ake use of t he t oolt ip expression evaluat ion feat ure, rem em ber how t o use t he

Quick Wat ch window. You will com e across m any expressions t hat j ust won't be evaluat ed by t he t oolt ip feat ure. To see t he value of t hese expressions, you'll need t o use t he Quick Wat ch window.

The Locals Window The Locals window is anot her valuable debugging t ool closely relat ed t o t he Wat ch window t hat also inexplicably has no built - in keyboard short cut t hat can be used t o display it . I n place of t hat you can use t he st andard m enu hot key sequence Alt + V followed by an s charact er. The Locals window can be t hought of as a specialized version of t he Wat ch window t hat aut om at ically displays t he nam es, values and dat a t ypes of all variables and const ant s t hat are local t o t he procedure current ly being execut ed. The Locals window for our debugging session in t he Post Tim eEnt riesToDat abase procedure is shown in Figure 16- 22.

Figu r e 1 6 - 2 2 . Th e Loca ls W in dow in Act ion [View full size image]

Like t he Wat ch window, you can use t he Locals window t o change t he value of any variable in t he wat ch list . There are also t wo unique feat ures provided by t he Locals window:

1 . Qu ick a cce ss t o t h e ca ll st a ck The but t on in t he upper- right corner of t he Locals window direct ly below t he X- close but t on will display t he call st ack window and allow you t o change t he scope of t he variables being displayed in t he Locals window t o any ot her procedure in t he call st ack. 2 . Th e M odu le Va r ia ble s e n t r y I f you look closely at t he first line in t he Locals window, you'll see t hat it has t he sam e nam e as t he m odule wit hin which t he current procedure is execut ing. I f you expand t his ent ry it will display a list of values for all m odule- level variables and const ant s.

The Object Browser (F2) Probably t he m ost overlooked and underused t ool in t he VBA program m er's arsenal is t he Obj ect Browser. This is unfort unat e, because it is also one of t he m ost im port ant . The Obj ect Browser is your window int o t he cont ent s of t he obj ect libraries you're working wit h. For every obj ect library m arked under t he VBE Tools > References m enu, t he Obj ect Browser displays all of t he obj ect s, m et hods, propert ies, const ant s and enum erat ions support ed by t hat obj ect library. I n addit ion t o sim ply displaying t hese it em s, t he Obj ect Browser displays a brief descript ion of t he synt ax required t o use each it em wit h hyperlinks t o ot her it em s where applicable. For const ant s and enum erat ions, t he Obj ect Browser displays t he act ual num eric value of t he const ant or enum er at ion. The VBA help syst em is also direct ly linked t o t he obj ect browser. I f you need furt her explanat ion of som e obj ect , propert y or m et hod you're looking at , you can j ust select t he nam e of t he it em in t he Obj ect Browser and press F1 t o bring up it s help t opic. ( Specific const ant s and enum erat ions are rarely associat ed wit h help t opics.) The Obj ect Browser is packed wit h so m any useful feat ures t hat it could alm ost warrant a chapt er in it s own right . We cover t he m ost com m only used feat ures of t he Obj ect Browser in t his sect ion. An exam ple of t he Obj ect Browser being used t o display inform at ion about t he ADO obj ect library is shown in Figure 16- 23.

Figu r e 1 6 - 2 3 . Th e VBE Obj e ct Br ow se r

Basic Features The m ost com m only used feat ures of t he Obj ect Browser window it self are t he following: Th e Obj e ct Libr a r y Box This is t he drop- down in t he upper- left corner of t he Obj ect Library window. I t det erm ines which obj ect library will be displayed in t he Obj ect Browser. The Obj ect Library Box cont ains one ent ry for every referenced obj ect library in t he current ly act ive proj ect , one ent ry for t he current ly act ive proj ect it self and a default < All Libraries> ent ry t hat causes t he Obj ect Browser t o display all of t he cont ent s of all of t he referenced libraries as well as t he current proj ect in one big heap. We recom m end t rying t o narrow down t he obj ect library you want t o exam ine by select ing it in t his drop- down. Having everyt hing displayed all at once m akes any one t hing difficult t o locat e. Th e Cla sse s List This is t he list t hat runs down t he left side of t he Obj ect Browser window. I t s nam e is a bit of a m isnom er because it displays m odules, const ant s and enum erat ions in addit ion t o classes. This is t he second level of det ail you will look t hrough aft er you've select ed t he obj ect library you want t o look in.

Th e M e m be r s List This is t he list t hat runs down t he right side of t he Obj ect Browser window. I t displays a com plet e list of m em bers for what ever it em is select ed in t he Classes List . For exam ple, in Figure 16- 23 t he Com m and obj ect has been select ed in t he Classes List , so t he Mem bers List displays all t he m em bers of t he Com m and obj ect . Th e D e t a ils W in dow This is t he window t hat occupies t he bot t om of t he Obj ect Browser. I t provides a descript ion of t he it em t hat is current ly select ed in t he Mem bers List . For exam ple, in Figure 16- 23 t he Execut e m et hod of t he Com m and obj ect has been select ed in t he Mem bers List . The Det ails window provides a brief descript ion of t he synt ax of t his m et hod wit h hyperlinks t o relat ed it em s in t he obj ect library.

Advanced Features Th e Se a r ch Com bo Box This is t he com bo box locat ed direct ly below t he Obj ect Library drop- down. Using t he Search com bo box you can look for all occurrences of a given t erm wit hin t he obj ect library or libraries current ly select ed in t he Obj ect Library Box. Just t ype t he t erm you want t o search for in t he search com bo box and click t he Search but t on ( t he t oolbar but t on t hat looks like a pair of binoculars) . I n Figure 16- 24, for exam ple, we've searched for all occurrences of t he t erm Act iveConnect ion wit hin t he ADO obj ect library.

Figu r e 1 6 - 2 4 . Usin g t h e Se a r ch Fe a t u r e of t h e Obj e ct Br ow se r

Sh ow H idde n M e m be r s I t m ay com e as a surprise, but m any elem ent s of every obj ect library are hidden from t he default Obj ect Browser view. There can be several reasons for t his: t he hidden feat ures m ight not be usable from VBA, t he hidden feat ures m ight not be im plem ent ed at all, or t he hidden feat ures m ight be older feat ures t hat Microsoft would like t o discourage you from using. This last reason is why we can t hank t he Microsoft developm ent t eam for providing us a way t o m ake t hese hidden feat ures visible. Som e t im es t hese older feat ures are useful, even necessary, for t op- qualit y Excel developm ent . Just don't expect t o find any help t opics linked t o t hese hidden feat ures. Figure 16- 25 shows an excellent exam ple of t he value of t he Show Hidden Mem bers feat ure.

Figu r e 1 6 - 2 5 . Tu r n in g On Sh ow H idde n M e m be r s

Not ice t hat som e of t he it em s in t he list are colored in very light gray. These are t he hidden m em bers t hat are revealed when you select t he Show Hidden Mem bers opt ion. As discussed in Chapt er 4 Worksheet Design, t he cont rols from t he Form s t oolbar are oft en t he best choice for use of cont rols on worksheet s. Unfort unat ely, t hese cont rols dat e back prior t o t he Excel 97 era and even t hough t hey are fully support ed by VBA it is not obvious how t o find inform at ion on t hem unless you have a copy of Excel 5 or 95 running on a spare com put er. As shown in Figure 16- 25, by using t he Obj ect Browser's short cut m enu you can display t hese hidden obj ect s t o learn m ore about t hem .

Creating and Running a Test Harness As discussed in t he Funct ional Decom posit ion sect ion of Chapt er 3 Excel and VBA Developm ent Best Pract ices, you should st rive t o break your applicat ion int o as m any single- purpose, reusable procedures as possible. Aft er you've done t his, however, you need t o verify t hat t hese procedures work under all circum st ances. Test ing t hem m anually wit hin your applicat ion is t edious, t im econsum ing and not very t horough. The proper way t o t est a procedure is t o writ e a wrapper procedure t hat calls t he procedure t o be t est ed in a loop, passing it all possible com binat ions of argum ent s and verifying t he result s t o ensure t hat t hey are correct . This wrapper procedure is called a t e st h a r n e ss and we show you how t o build one in t his sect ion. The workbook cont aining t he procedures we're about t o dem onst rat e is called Test HarnessDem o.xls and is locat ed on t he CD in t he \ Concept s\ Ch16VBA Debugging folder. One frequent ly useful single- purpose procedure t akes a full pat h and filenam e st ring and breaks it int o it s pat h and filenam e com ponent s, opt ionally ret urning one or bot h t o t he calling procedure. The Ret urnPat hAndFilenam e procedure shown in List ing 16- 6 does t his.

N OTE Because of it s use of t he VBA I nSt rRev funct ion, which was first int roduced in Excel 2000, t he Ret urnPat hAndFilenam e procedure will not work in Excel 97.

List in g 1 6 - 6 . Th e Re t u r n Pa t h An dFile n a m e Pr oce du r e Public Sub ReturnPathAndFilename(ByRef sFullName As String, _ Optional ByRef sPath As String, _ Optional ByRef sFile As String) Dim lPosition As Long lPosition = InStrRev(sFullName, "\") sPath = Left$(sFullName, lPosition) sFile = Mid$(sFullName, lPosition + 1) End Sub

To verify t hat t his procedure works as expect ed we need t o creat e a t est harness t hat feeds it large num bers of full pat h and filenam e st rings and t hen concat enat es t he ret urned split pat h and filenam e values and verifies t hat t he specified file exist s. I f t he split is perform ed incorrect ly on any

t est st ring, we know t here is a bug in t he procedure t hat needs t o be fixed. The t est harness t hat perform s t his operat ion is shown in List ing 16- 7.

List in g 1 6 - 7 . Th e Te st H a r n e ss for t h e Re t u r n Pa t h An dFile n a m e Pr oce du r e Public Sub TestHarness() Dim Dim Dim Dim Dim Dim

bSuccess As Boolean objSearch As FileSearch lCount As Long sFullName As String sPath As String sFilename As String

' Use the FileSearch object to get a large number of full ' path and filename strings to use as test data. Application.StatusBar = "Retrieving test data..." Set objSearch = Application.FileSearch objSearch.NewSearch objSearch.LookIn = "E:\" objSearch.SearchSubFolders = True objSearch.FileType = msoFileTypeExcelWorkbooks If objSearch.Execute() > 0 Then ' Assume the test succeeded until something goes wrong. bSuccess = True ' Run each path and filename returned by the FileSearch ' object through our ReturnPathAndFilename. ' Then concatenate the results and verify that they ' refer to a valid file. For lCount = 1 To objSearch.FoundFiles.Count sFullName = objSearch.FoundFiles(lCount) Application.StatusBar = "Checking: " & sFullName ReturnPathAndFilename sFullName, sPath, sFilename If Len(Dir$(sPath & sFilename)) = 0 Then ' Combining the path and filename returned by ' the ReturnPathAndFilename procedure resulted ' in an invalid file specification. Debug.Print "Bad split: ", sPath, sFilename bSuccess = False End If Next lCount Application.StatusBar = False If bSuccess Then MsgBox "All tests succeeded."

Else MsgBox "Failures encountered. " & _ "See list in the Immediate window." End If Else MsgBox "No matching files found." End If End Sub

I n t he Test Harness procedure we use t he FileSearch obj ect t o creat e a large array of full pat h and filenam e st rings. We loop t his array and feed each of t hese st rings t o t he Ret urnPat hAndFilenam e procedure. We t hen concat enat e t he pat h and filenam e ret urned by t he procedure and verify t hat it refers t o a valid file. I f any full pat h and filenam e st rings are split incorrect ly, we print t he result s t o t he I m m ediat e window and display an error m essage upon com plet ion. Ot herwise we display a success m essage. Using t his t echnique, you can run t housands of full pat h and filenam e st rings t hrough t he funct ion and verify t hat it handles t hem correct ly in a very short period of t im e. Verifying as m any procedures as possible using t he t est harness approach should be considered a best program m ing pr act ice.

Using Assertions Assert ions are a way t o guarant ee t hat one or m ore specific condit ions hold t rue. They can be used t o t est t he validit y of variables or expressions at specific point s wit hin your program . I n VBA program m ing, assert ions are im plem ent ed wit h t he Debug.Assert m et hod. The Debug.Assert m et hod t akes a Boolean expression as it s single argum ent . I f t he value of t he expression is False, Debug.Assert causes code execut ion t o halt and ent er break m ode on t he line of code where t he assert ion failed. Assert ions creat ed using Debug.Assert ignore t he global error t rapping set t ing defined under t he VBE Tools > Opt ions > General > Error Trapping m enu. A Debug.Assert st at em ent will cause code execut ion t o ent er break m ode regardless of t he global error t rapping set t ing. List ing 16- 8 shows an exam ple of Debug.Assert in use.

List in g 1 6 - 8 . D e bu g.Asse r t Ex a m ple Sub DebugAssertExample() Dim lRow As Long Dim lColumn As Long ' Some code here that sets lRow and lColumn. Debug.Assert (lRow > 0) And (lColumn > 0) Sheet1.Cells(lRow, lColumn).Value = True End Sub

I n t his exam ple, we are using t wo variables t o st ore t he row and colum n num ber t hat specifies t he Range we access using t he Cells m et hod in t he last line of code. Because bot h t he row and colum n num ber m ust be great er t han zero, we use t he Debug.Assert st at em ent t o halt program execut ion if eit her one of t hem fails t his t est . Not e t hat we are able t o st ring t wo relat ed Boolean t est s int o a single Debug.Assert expression. You can link as m any relat ed t est s int o t he sam e assert ion as you want . We recom m end, however, t hat unrelat ed assert ions get separat e lines of code. This sim plifies t he logic of debugging, especially in cases where you m ay be experiencing m ult iple errors. Assert ions are especially valuable when debugging int erm it t ent errors or errors t hat are difficult t o reproduce. I f you can narrow down t he sect ion of code where t he error is occurring, you can sim ply place assert ions on all of t he im port ant variables and expressions used in t hat sect ion of code. You t hen run t he program norm ally, t rying various com binat ions of t hings unt il one of your assert ions

fails and halt s your program . Keep in m ind t hat Debug.Assert is purely a debugging t ool. I t should not be used t o t est condit ions t hat require validat ion each t im e your program runs. For exam ple, if your applicat ion needs a specific file t o funct ion correct ly, you should code a check for t hat file in your Aut o_Open procedure. This is called a pe r m a n e n t a sse r t ion , because it is always perform ed. A perm anent assert ion is different from t he kind creat ed using t he Debug.Assert st at em ent because it t hrows a runt im e error t hat can be handled by your proj ect error handling syst em . An exam ple of t his is shown in t he excerpt from our Pet rasAddin.xla workbook's Aut o_Open procedure in List ing 16- 9.

List in g 1 6 - 9 . A Pe r m a n e n t Asse r t ion ' Make sure we can locate our time entry workbook before we ' do anything else. If Len(Dir$(gsAppDir & gsFILE_TIME_ENTRY)) = 0 Then _ Err.Raise glHANDLED_ERROR, sSOURCE, gsERR_FILE_NOT_FOUND

This perm anent assert ion verifies t hat we can locat e our t im e ent ry t em plat e workbook and t hrows a cust om error if we can't . Our program can never run properly wit hout it s accom panying t im eent ry t em plat e, so t his check should be perform ed whenever t he applicat ion is run.

Debugging Shortcut Keys that Every Developer Should Know As wit h m ost program m ing t asks, t he fewer t im es you t ake your hands off t he keyboard during debugging t he fast er and m ore product ive you will be in t he long t erm . Wit h t hat in m ind, what follows is a list of t he m ost useful debugging- relat ed keyboard short cut s.

General F5 Ru n : Runs t he procedure wit hin which t he cursor is current ly locat ed. I f t he cursor is not current ly locat ed wit hin a procedure t hat can be run direct ly, or if t he cursor is not locat ed wit hin any procedure, t he VBE will prom pt you wit h t he Macros dialog, which displays a list of procedures t hat can be run. I f you are already in break m ode, F5 will run your code t o t he next break point or t o com plet ion, whichever com es first . F9 Toggle br e a k poin t : Toggles bet ween set t ing and rem oving a break point on t he line of code occupied by t he cursor. See t he sect ion on Using Break Point s above for m ore det ails on how t o effect ively use break point s. Ct r l+ Sh ift + F9 Cle a r a ll br e a k poin t s: I f you have set a num ber of break point s in your code and t hen correct ed t he error you were looking for, you m ay sim ply want t o rem ove all break point s from your code so t hat you can run it norm ally and verify your fix. You can quickly rem ove all break point s from your code by pressing Ct rl+ Shift + F9. Ct r l+ GD ispla y t h e I m m e dia t e w in dow : What would be really helpful would be t o have a short cut key, or any sim ple m et hod for t hat m at t er, for clearing t he cont ent s of t he I m m ediat e window. Unfort unat ely, no such feat ure is provided in VBA. I n t he Tools folder of t he accom panying CD we provide a link t o a freeware add- in called MZTools t hat offers t his feat ure along wit h a host of ot her useful VBE ut ilit ies.

Debug Mode Code Execution F8 St e p in t o: When in break m ode, t his key enables you t o st ep t hrough your code one line at a t im e. I f you are not in break m ode but your cursor is wit hin a valid ent ry point procedure, code execut ion will begin and break m ode will st art on t he first line of t hat procedure. Sh ift + F8 St e p ove r : When in break m ode, t his will st ep com plet ely over t he next line of code t o be execut ed. Whet her t hat line is a sim ple st at em ent or a com plex nest ed funct ion call, Shift + F8 will execut e all t he code required t o st ep over t he line and resum e break m ode at t he next breakable posit ion. Ct r l+ Sh ift + F8 St e p ou t of: I f you have st epped int o a called procedure and det erm ined t hat what you are looking for is not t here, you don't have t o cont inue single st epping t hrough t he rest of t he

procedure t o get back out of it . Ct rl+ Shift + F8 will t ell VBA t o finish execut ing t he procedure you are in and will resum e break m ode on t he first breakable line im m ediat ely following t he call t hat brought you int o t he procedure. Ct r l+ F8 St e p t o cu r sor : During debugging, you will oft en encount er a group of st at em ent s t hat you do not need t o exam ine carefully. Rat her t han single st epping t hrough t hem , you can place your cursor at t he beginning of t he next line of code you would like t o st ep t hrough and press Ct rl+ F8. VBA will run all t he lines of code bet ween your current posit ion and t he point where you placed t he cursor, t hen st op and resum e break m ode at t he line where you placed t he cursor. Ct r l+ F9 Se t n e x t st a t e m e n t : When you are single- st ep debugging your code, you m ay see a sect ion t hat you would like t o skip alt oget her. To do so, j ust m ove t he cursor down t o t he next line you want execut ed and press Ct rl+ F9. VBA will skip all t he lines of code bet ween t he current execut ion point and resum e break m ode on t he line specified by your cursor posit ion.

Navigation Sh ift + F2 Pr oce du r e de fin it ion : When you place your cursor wit hin t he nam e of a procedure and press t his short cut , you will be t aken t o t he definit ion of t hat procedure. Ct r l+ Sh ift + F2 La st posit ion : This short cut is t he reverse of Shift + F2. I t brings you back t o t he posit ion wit hin your code where you were when you pressed Shift + F2.

Information Ct r l+ LCa ll St a ck : This short cut displays t he Call St ack window so you can see how you got t o t he procedure where you're current ly locat ed in a deeply nest ed sect ion of code. Sh ift + F9 Qu ick W a t ch : This displays t he Quick Wat ch dialog, which displays t he cont ext ( scope) of t he expression you select ed, t he expression it self and t he value of t he expression. F2 Obj e ct Br ow se r : This displays t he Obj ect Browser.

Conclusion Excellent debugging skills are one of t he prim ary at t ribut es t hat separat e t he professional program m er from t he skilled am at eur. I n t his chapt er we have covered t he vast array of debugging t ools and t echniques t hat you have at your disposal in t he VBA environm ent . I f ever t here were an aspect of program m ing t o which t he old adage " pract ice m akes perfect " applies, it is surely debugging. All t he dedicat ed debugging t ools described here not wit hst anding, t he pract ice of debugging is j ust as m uch art as science. Learning t hese t ools is a st art ing point , but you m ust debug a significant am ount of real- world code, ideally not all of it your own, before you becom e t ruly proficient . Many people have rem arked t o us, and we believe it t o be t rue, t hat you learn m ore from debugging m ist akes t han you do from get t ing it right t he first t im e. So go fort h and debug!

Chapter 17. Optimizing VBA Performance A com m on com plaint about VBA in general, and part icularly rout ines t hat aut om at e Excel, is poor perform ance. Alt hough t here is som e t rut h in t hat , say when com pared t o C+ + , it is very oft en due t o poorly st ruct ured or poorly writ t en code. This is probably because VBA m akes it very easy t o writ e code t hat works, but quit e difficult t o writ e code t hat works fast . As a general rule, t he speed of a well- opt im ized rout ine can oft en be an order of m agnit ude fast er t han t he original code, and im provem ent s of t wo orders of m agnit ude are not uncom m on. This chapt er explains how t o achieve t hose savings.

Measuring Performance The end users of your applicat ion are t he final arbit ers of perform ance, and t hey rarely use st opwat ches t o t im e how long som et hing t akes. I nst ead, t hey form an im pression based on t heir expect at ions, past experiences, visual cues and t he act ivit y t hey're perform ing. As a general guideline, we aim t o keep wit hin t he t im es shown in Table 17- 1 .

Ta ble 1 7 - 1 . Ta r ge t Re spon se Tim e s Act ion

Re spon se Tim e

Displaying a sim ple form

< 2 seconds

Displaying a com plex form

< 20 seconds

Select ing it em s wit hin a form

< 1 second

Typing wit hin a form

Unnot iceable

Preparing a sim ple r epor t

< 10 seconds

Preparing a com plex r epor t

< 30 seconds

All t hese t arget s relat e t o t he user experience, so m ust be checked using a PC sim ilar t o t he average users' specificat ion. Not e also t he difference bet ween a " sim ple" form or report and a " com plex" one is purely t he users' percept ion and need not have any relat ionship t o t he t echnical com plexit y. Hopefully, you'll find m ost of t he rout ines you writ e perform well wit hin t hese t arget s, even wit h t he largest dat a set s t hey're likely t o encount er, so t here is lit t le point t rying t o opt im ize t hem . Undoubt edly, t hough, t here will be som e t hat t ake m uch, m uch longer, and t hey're t he ones t hat will give your applicat ion a poor reput at ion. Radically im proving t he slowest rout ines will oft en give t he im pression t he applicat ion is m ore responsive overall. The rest of t his chapt er explains t he st eps t hat can be t aken t o achieve m assive im provem ent s in t he perform ance of your slowest r out ines. Aft er you've opt im ized t he applicat ion as m uch as you can, t here are a few t ricks you can use t o m ake it seem t o perform bet t ereven t hough it m ight not be doing so:

I f a rout ine t akes m ore t han about a second, change t he cursor t o an hourglass at t he st art of it and back t o norm al at t he end. This t ricks users int o expect ing a delay and t hey're pleasant ly surprised when it finishes quickly. I f a rout ine is t riggered by t he user t yping int o a t ext box, never show an hourglass. Showing an hourglass t ells t he user you expect t he rout ine t o be lengt hy and no rout ines t riggered by t ext box Change event s should have a not iceable delay. I f a rout ine t akes m ore t han about five seconds, display a progress bar ( such as t he ones shown in Chapt er 10 Userform Design and Best Pract ices and Chapt er 11 I nt erfaces)

The PerfMon Utility The PerfMon ut ilit y is a set of t hree DLLs t hat enable us t o m onit or and record t he perform ance of a VBA applicat ion as it is execut ing. I t achieves t his by adding a line of code t o t he t op and bot t om of every procedure t o not ify t he m onit oring DLL when t he procedure st art s and finishes. The DLL records t he num ber of t im es each procedure is called and t he m axim um , t ot al and average t im e spent in each. The result is a com plet e list of all t he procedures called and t he det ailed t im ings for each, eit her copied t o t he clipboard or saved t o a t ext file. Once im port ed int o an Excel worksheet and sort ed by t ot al t im e, t he result looks som et hing like Figure 17- 1.

Figu r e 1 7 - 1 . An Ex a m ple of t h e Pe r fM on Re su lt s

We can im m ediat ely see t he first procedure account s for nearly t he ent ire processing t im e and is t herefore where we should focus our opt im izat ion effort s. The set up program for t he PerfMon ut ilit y can be found in t he \ Tools\ Perform ance Monit or direct ory on t he CD and inst alls t he following DLLs: Pe r fM on it or .dll An Act iveX DLL t hat uses t he Windows high- perform ance count er t o t rack t he perform ance of each rout ine. I t is list ed in t he Proj ect > References dialog as Per fMon: VB/ VBA Perform ance Monit or. Pe r fM on Office .dll An add- in for t he Office VBE t o add and rem ove t he calls t o t he PerfMonit or DLL. Pe r fM on V B6 .dll An add- in for t he VB6 I DE t o add and rem ove t he calls t o t he PerfMonit or DLL. The set up program also inst alls t he CPerfMon.cls file, which is a class m odule t hat can be included in a VB6 proj ect t o enable cross- process perform ance m onit oring for use during developm ent of com bined Excel/ VB6 solut ions ( see Chapt er 20 Com bining Excel and Visual Basic 6) . To st art using t he ut ilit y, click on Addins > PerfMon > Add PerfMon Calls and select which

procedures t o add t he calls t o, as shown in Figure 17- 2.

Figu r e 1 7 - 2 . Th e Add Pe r fM on Ca lls D ia log

When you click OK, t he ut ilit y will add a reference t o t he PerfMonit or DLL and add calling code t o t he t op and bot t om of t he select ed rout ine( s) , as shown in List ing 17- 1.

List in g 1 7 - 1 . A Pr oce du r e w it h t h e Au t om a t ic Pe r fM on Ca lls Adde d Sub ALengthyRoutine() PerfMonProcStart "PrjChapter17.MPerfMon.AlengthyRoutine" 'Do something lengthy PerfMonProcEnd End Sub

"PrjChapter17.MPerfMon.AlengthyRoutine"

Not e t hat every procedure is given a unique I D, being t he concat enat ion of t he proj ect nam e, m odule nam e, procedure nam e and propert y t ype ( if it is a propert y procedure) . I f you have a part icularly long procedure t hat would be bet t er m onit ored in separat e blocks, ext ra PerfMon calls can be added m anually, t aking care t o m at ch t he ProcSt art and ProcEnd calls, as shown in List ing 17- 2 .

List in g 1 7 - 2 . A Pr oce du r e w it h M a n u a l Pe r fM on Ca lls Adde d

Sub ALengthyRoutine() PerfMonProcStart "PrjChapter17.MPerfMon.AlengthyRoutine" PerfMonProcStart "PrjChapter17.MPerfMon.AlengthyRoutine1" 'Do something lengthy PerfMonProcEnd "PrjChapter17.MPerfMon.AlengthyRoutine1" PerfMonProcStart "PrjChapter17.MPerfMon.AlengthyRoutine2" 'Do something else lengthy PerfMonProcEnd "PrjChapter17.MPerfMon.AlengthyRoutine2" PerfMonProcEnd "PrjChapter17.MPerfMon.AlengthyRoutine" End Sub

The last t hing t o do is t o add a line t o t ell t he ut ilit y when t o st art and st op m onit oring, as shown in List ing 17- 3.

List in g 1 7 - 3 . I n clu de t h e Ca lls t o St a r t a n d St op t h e M on it or in g Sub ALengthyRoutine() 'Start monitoring all procedures from here PerfMonStartMonitoring PerfMonProcStart "PrjChapter17.MPerfMon.AlengthyRoutine" PerfMonProcStart "PrjChapter17.MPerfMon.AlengthyRoutine1" 'Do something lengthy PerfMonProcEnd "PrjChapter17.MPerfMon.AlengthyRoutine1" PerfMonProcStart "PrjChapter17.MPerfMon.AlengthyRoutine2" 'Do something else lengthy PerfMonProcEnd "PrjChapter17.MPerfMon.AlengthyRoutine2" PerfMonProcEnd "PrjChapter17.MPerfMon.AlengthyRoutine" 'Stop monitoring and write the results to a file 'If no file name given, the results will be put on the clipboard PerfMonStopMonitoring "c:\MyRoutineTiming.txt" End Sub

The easiest way t o analyze t he result s is t o st art a new Excel session, click Dat a > Get Ext ernal Dat a > I m port Text File ( Excel 2000) or Dat a > I m port Ext ernal Dat a > I m port Dat a ( Excel XP/ 2003) , select t he t ext file t hat you gave in t he PerfMonSt opMonit oring call and click t hrough t he

Text I m port Wizard. I t is bet t er t o im port t he dat a inst ead of j ust opening t he file, because t he lat t er locks t he file and t he PerfMon m onit or will not t hen be able t o overwrit e it wit h new result s for each subsequent run. We can also set t he im port t o use t he sam e filenam e each t im e, allowing us t o re- im port t he new result s by clicking t he Refresh but t on, shown in Figure 17- 3.

Figu r e 1 7 - 3 . I m por t in g t h e File Allow s Us t o Qu ick ly Re fr e sh t h e D a t a t o Ge t t h e N e w Re su lt s [View full size image]

All t he t im ings shown in t he result s t able are in seconds, wit h an accuracy of at least t he m illisecond. Not e, t hough, t he m onit oring calls t hem selves t ake a sm all am ount of t im e, so t he result s shown will t ypically be slight ly slower t han t he unm onit ored code. Sort t he t able by t he Tot al Tim e colum n t o quickly ident ify t he slowest procedures. I n t his exam ple, we can clearly see t he second half of our rout ine is t aking nearly all t he t im e. For best result s, t he t est s should be run wit hout any ot her applicat ions open, and cert ainly wit hout swit ching t o t hem , so Windows can dedicat e all it s resources t o your applicat ion. As t hese t im ings will probably be done on a developer- spec m achine, we need t o calculat e a t arget durat ion for us t o work t owards, by com paring t he t ot al durat ion shown in t he t op- left corner t o t hat experienced by t he user and pro- rat ing it t o t he users' t arget t im e. Obviously, t his can only be done when you are t im ing " end- t o- end" processest hat is, from t he t im e t he user clicked a but t on t o when t he form or report is displayed. All we t hen need t o do is t o t hink of ways in which t he speed of t he rout ines can be im proved.

Creative Thinking The key t o im proving your applicat ion's perform ance is t o rem ove t he bot t lenecks by t rying t o find a different ( fast er) way t o do t he sam e t ask. Eit her by ret hinking t he ent ire approachso t he t ask t hat t ook so long is no longer neededor by t hinking how t o do t he t ask quicker. The t rick is t o t ap in t o t he creat ive side of your brain, so inst ead of " analyzing" t he problem and " ident ifying" a solut ion, use your im aginat ion t o conj ure up sent ences t hat st art wit h " I wonder what would happen if I …." Alt hough t his m ay seem like an alien concept t o t hose of us who are norm ally analyt ical inst ead of art ist ic, t here are a few exercises t hat can help.

Do a Jigsaw On t he rare occasions t hat we t each a class on perform ance opt im izat ion, we split t he class int o pairs and give each pair a child's six- piece j igsaw t o build and t im e how long t hey t ake t o com plet e it . The rules of t he gam e are as follows: All t he pieces m ust st art face down, arranged random ly on t he t able. The j igsaw m ust be com plet ed and finish face up. You are not allowed t o be t ouching any piece when t he t im er st art s. The first at t em pt usually t akes about 30 seconds. Applying t he rule t hat an opt im ized rout ine should be an order of m agnit ude fast er t han t he first at t em pt gives us a t arget of t hree seconds t o do t he six- piece j igsaw.

Identify the Steps The bigger t he t ask, t he harder it is t o invent a com plet ely new way of perform ing t he t ask so it will st ill work. So break it down int o sm aller st eps and t ry t o t hink how each st ep could be ( a) avoided ent irely or ( b) speeded up. I n VBA t erm s, t he t em pt at ion is t o focus on each exist ing procedure, but doing so j ust locks in t he exist ing design. I nst ead, look at t he process as a whole and ident ify t he t ransform at ions, checks and processing t hat occur. Looking at our j igsaw exam ple, t he processing could be broken down int o t he following st eps for each piece: Pick it up

Turn it over

I dent ify it

Put it down

Join it up

Wit h six pieces and five t hings t o do for each piece, 30 seconds is a reasonable t im e, but can any of t hose st eps be rem oved?

Think Outside the Box

" Think out side t he box" is probably t he m ost - used consult ant - speak phrase of all t im e, urging us t o com e up wit h som e new ideas. But what does it really m ean? The origin we m ost like com es from being asked t o j oin up nine dot s, drawing as few connect ed st raight lines as possibleanalogous t o m aking a procedure run as fast as possible:

Using five lines is easy ( as is our first at t em pt at coding t he VBA rout ine) :

But can you connect all t he dot s using four st raight lines? Visually, t he nine dot s appear t o our brains as a box, which is a visual m et aphor for t he m any rules, regulat ions and norm s t hat we work ( and code) wit hin, usually as a result of our upbringing and educat ion. Connect ing t he dot s using four lines requires us t o break t hrough t he boundaries of t he box and st art t o consider t he area out side it lit erally t hinking out side t he box ( but only a lit t le bit ! ) :

Now you're t hinking out side t he box, can you do it using t hree st raight lines? You'll have t o t hink furt her out side t he box and also sm ash t hrough a const raint t hat was never st at ed, but has been assum edyou don't have t o go t hrough t he cent re of each dot :

So what ot her unst at ed assum pt ions can we break in order t o j oin t he dot s using even fewer lines?

Just one line, perhaps? I f we t ake t he t hree- line solut ion t o it s ext rem e, we could have one line t hat spirals around t he globe. ( I t doesn't have t o be physically pract ical.) Or we could break anot her assum pt ion and use a t hicker pena paint brush could cover all t he dot s in one line! But our t hinking is st ill boxed inlit erally. To t ruly t hink out side t he box requires us t o rem ove t he box it self! Was it ever st at ed we can't cut t he paper? Doing so m akes a one- line solut ion t rivial:

The final opt im izat ion is t o realize we can com plet e t he t ask of j oining t he dot s wit hout drawing any lines at all! I f we cut t he paper carefully, we can have all t he dot s t ouching t o begin wit h. Even bet t er is t o break a last assum pt ion and t hink in t erm s of a 3D, not 2D, space and st ack t he dot s on t op of each ot her. We've opt im ized t he t ask of j oining t he dot s t o doing not hing!

The next t im e you're asked t o " Think out side t he box," st ep out of your cubicle and ask " What box?"

Break the Rules! A large part of creat ive t hinking, t hen, is t o break t he ( oft en unst at ed) rules t hat norm ally govern our behavior. These rules ( usually) exist for som e very good reasons, but perform ance is rarely one of t hem . For exam ple, passing a variable t o a procedure by value ( ByVal) is t he m et hod recom m ended in Chapt er 3 Excel and VBA Developm ent Best Pract ices. This is m ainly due t o defensive program m ingknowing t he rout ine being called can't change t he value of t he variable passed inbut is oft en ( slight ly) slower t han passing t he variable by reference ( ByRef) , part icularly when passing large st rings or Variant arrays. The one t hing we m u st do when breaking rules it t o fully docum ent t he rules we're breaking and why we're breaking t hem ( by com m ent ing t he code) . I t 's not uncom m on for a m aint enance developer t o t hink " We're not allowed t o do t hat " and unwit t ingly undo your opt im izat ions. Ret urning t o our j igsaw puzzle, what rules can we break in order t o speed up t he t ask? The five st eps t o com plet ing a piece of t he puzzle are as follows: Pick it up

Turn it over

I dent ify it

Put it down

Join it up

One t hing we can do is draw on t he t able! By t racing around t he com plet ed j igsaw pieces ( on som e flipchart paper) , we can t ell exact ly where each piece goes, enabling us t o put it down in it s final posit ion. We've com bined t he " Put it down" and " Join it up" t asks and reduced t he t im e accordingly. I n VBA t erm s, a rout ine t hat processes a set of dat a oft en has a final st ep which organizes t he result s for t he next process ( such as rem oving duplicat es/ blanks, sort ing and so on) . Try t o com bine t hat organizat ion int o t he processing of t he dat a, so t he nat ural out put of t he dat a processing can be passed direct ly t o t he next rout ine. We can also deface t he j igsaw pieces! By num bering t he back of each piece and it s final posit ion on t he flipchart paper, we know before we've even t ouched a piece exact ly where it has t o go, and we no longer need t he " I dent ify it " st ep. The VBA equivalent is t o ensure t he incom ing dat a is in a st ruct ured, known and predict able form at before we have t o process it . I f t he incom ing dat a can't be obt ained in such a form at ( by m odifying t he previous rout ine) , it is oft en quicker t o get it t hat way at t he st art of a rout ine t han t o have t o deal wit h t he lack of st ruct ure during t he processing. For exam ple, if t he rout ine does a lot of searching t hrough list s, it is m uch quicker t o sort t he list

first and use a binary search inside t he loop t han it is t o search t hrough an unsort ed list each t im e. By ensuring we have st ruct ured our incom ing dat a ( by num bering t he j igsaw pieces) and com bined t he final reorganizat ion int o t he m ain processing ( by drawing and num bering an out line of each piece of t he com plet ed j igsaw) , we no longer need t o t urn t he piece over t o ident ify it and so have reduced t he processing required for each piece t o a sim ple " Move it ." One t ask for each of our six pieces gives us a processing t im e of roughly six seconds, which is well on t he way t o our t arget of t hree. So far we've concent rat ed on opt im izing a rout ine by changing t he way in which t hings are done, t o reduce t he am ount of processing required. By doing t hese m acro- scale opt im izat ions we've achieved 80 percent of our t arget 90 percent saving, which is t ypical for m any sit uat ions. The last 10 percent com es from m aking t he rem aining m inim um processing as fast as it can be.

Know the Data When doing a j igsaw puzzle, wit h everyt hing else being equal, t he second and t hird at t em pt s are likely t o be som ewhat quicker t han t he first . This is sim ply because t he people building t he j igsaw will st art t o recognize which piece is which and where it goes, wit hout needing t o check t he num bers writ t en on each, shaving anot her few seconds off t he processing t im e. The last second can be shaved by choosing t o do t he pieces in a specific ordereach person does one of t he m iddle t wo pieces first , t hen t he t wo pieces at opposit e ends. The equivalent VBA is in knowing t he am ount , form at , t ype and so on of t he incom ing dat a and hence t he m ost efficient way t o process m ost of it . Oft en, rout ines are required t o handle slight ly different t ypes of dat a in slight ly different ways, but where t he differences are rarely sufficient t o j ust ify dedicat ed procedures. I t is alm ost im possible for a rout ine t o be equally efficient at handling all t he expect ed dat a t ypes. I n m any cases, t he rout ines we writ e are fast est when operat ing wit hin cert ain lim it s, such as t he t ypical sizes of list s. The m ost efficient code t o handle list s wit h up t o t en it em s is unlikely t o be t he m ost efficient at handling list s wit h t housands of it em s. I f we know t he dat a we'll be given and can ident ify which are t he m ost com m on sit uat ions, we can opt im ize our rout ines t o handle t hose sit uat ions as efficient ly as possible, t o m axim ize overall perform ance. I f t his result s in part icularly poor perform ance for t he rarer cases, we m ay be forced t o include alt ernat ive procedures opt im ized for t hose. I n t hat case, t here would be a t rade- off bet ween perform ance and m aint ainabilit y.

Ask Questions What if it was an elephant ? What if it was a m ouse? The corollary t o knowing t he dat a is t o consider how you would approach t he problem if you had t o process incredibly m ore or incredibly less dat a. By forcing yourself t o consider solut ions t o out - of- bounds sit uat ions, you m ay t hink of new ways t o st ream line t he processing t hat you had previously discount ed ( m aybe subconsciously) . What if I st ood on m y head? I nst ead of looking at t he code from t op t o bot t om and accept ing t hat B follows A, look at it from bot t om t o t op and keep asking " Does B h a ve t o follow A? What can I change in B t o break t hat dependency? I f I do t hat , can I get rid of A ent irely? I s t hat any quicker?"

Know the Tool Aft er we've reduced t he processing st eps t o a m inim um and organized t he rest t o be m ost efficient when handling t he m ost com m on sit uat ions, t he last few percent age point s can be saved by ensuring we writ e t he m ost efficient code. Bot h in pure VBA and when aut om at ing Excel, t here are usually a num ber of alt ernat ive ways of doing t he sam e t hing, som e fast er t han ot hers. These m icro- level opt im izat ions require a very good underst anding of t he t ool being used ( t hat is, VBA and/ or Excel) , are oft en count erint uit ive and are oft en different for different dat a t ypes ( Longs vs. St rings vs. Variant s) . Many of t hese alt ernat ives are explained in t he Micr o- Opt im izat ion sect ion lat er in t his chapt er.

Macro-Optimization The vast m aj orit y of t he perform ance im provem ent will com e from rest ruct uring t he code t o use a m ore efficient algorit hm . This part of t he chapt er highlight s som e of t he t hings t o look for and provides alt ernat ive suggest ions for doing t he sam e t hing. Whet her t he suggest ions shown here are bet t er or worse t han your exist ing code will depend very m uch on t he sit uat ion, part icularly on t he am ount and t ype of dat a being processed. The slowest part s of a procedure will invariably involve eit her ext ernal dat a ret rieval or repeat edly looping t hrough set s of dat a. Large loops are an opport unit y for opt im izat ion; any im provem ent ( however m inor) t hat can be m ade inside a loop is a gain m any t im es over. The perform ance of ext ernal dat a ret rieval is usually dependant on t he server and net work perform ance and is som et hing we have lit t le cont rol over. One t hing we ca n do t o m inim ize t he effect of poor dat abase perform ance is t o load dat a ( such as st at ic lookup list s and so fort h) when t he applicat ion st art s inst ead of when it is required. Users oft en find it m ore accept able t o have a longer st art up t im e t han sluggish perform ance aft er t he applicat ion is loaded.

Preprocess Before reading t he rest of t his paragraph, st art Excel and writ e t he fast est possible VBA rout ine you can t o calculat e how m any 1s t here are in t he binary represent at ion of t he num bers 0 t o 255. How did you do it ? Did you use t he Dec2Bin funct ion from t he Analysis Toolpak? Did you use a recursive rout ine? Did you repeat edly divide by 2 and check whet her t he result was odd or even? Or did you work out t he num bers yourself, hard- code t he result s in a VBA array and j ust read t hem at runt im e, as shown in List ing 17- 4?

List in g 1 7 - 4 . H ow M a n y 1 s Ar e Th e r e in a Bin a r y N u m be r ? Function CountTheOnes(ByVal iValue As Integer) As Integer Static vaOneCount As Variant 'Initialize the array If IsEmpty(vaOneCount) Then vaOneCount = Array(0, 1, 1, 2, 1, ... , 7, 8) End If 'Read the result CountTheOnes = vaOneCount(iValue) End Function

By doing as m uch processing as possible when developing t he applicat ion, our applicat ions don't need t o do t he processing at runt im e.

Check the Order The best rout ines are t hose whose perform ance doesn't vary significant ly wit h t he volum e of dat a being processed. For exam ple, a rout ine t hat copied a set of dat a from a Variant array int o a worksheet range, calculat ed t he worksheet and ret urned a result would t ake approxim at ely t he sam e t im e whet her t here were t en or a t housand elem ent s in t he array. Such rout ines are said t o have an order of 1 and are very hard t o achieve in pract ice. The next best are t hose t hat vary linearly wit h t he volum e of dat a, such as one or m ore sequent ial For...Next loops t hrough t he dat a. These rout ines have an order of n, so if we have t en t im es as m uch dat a, t he rout ine is likely t o t ake approxim at ely t en t im es as long. Wit h a lit t le t hought and work, m ost rout ines can be reduced t o order n. Nest ed loops result in rout ines t hat are very sensit ive t o t he volum e of dat a being processed. A rout ine wit h t wo nest ed loops has an order n 2 and each ext ra level of nest ing adds an ext ra order t o t he rout ine. I f t hese rout ines are given t en t im es as m uch dat a t o process, t hey're likely t o t ake 100 or 1,000 t im es as long. I f such a rout ine norm ally t akes 1 second t o com plet e, it m ight t ake 15 m inut es t o process 10 t im es as m uch dat a. I n m ost cases, nest ed loops are j ust a quick and easy way t o code an algorit hm t hat could be redesigned as m ult iple sequent ial loops t hrough t he dat a. Not e t hat nest ed loops will oft en be spread over m any different procedures, for exam ple where ProcedureA loops t hrough an array and calls ProcedureB for each elem ent , which it self loops t hrough anot her array t o process t he elem ent . As an exam ple, consider t he rout ine in List ing 17- 5, which com pares t wo arrays and processes any it em s t hat are in bot h.

List in g 1 7 - 5 . Com pa r e Tw o Ar r a ys Sub ProcessLists(asArray1() As String, asArray2() As String) Dim lIndex1 As Long Dim lIndex2 As Long 'Loop through the first array For lIndex1 = LBound(asArray1) To UBound(asArray1) 'Loop through the second array For lIndex2 = LBound(asArray2) To UBound(asArray2) 'Do they match? If asArray1(lIndex1) = asArray2(lIndex2) Then 'Yes, so process it End If

Next Next End Sub

Wit hout t hinking t oo hard about how t o im prove t his rout ine, we m ight be t em pt ed t o j ust add an Exit For t o j um p out of t he inner loop aft er we've found a m at ch, but t hat st ill leaves t he rout ine essent ially of order n 2 . I f t he t wo arrays are sort ed, we can reduce t his t o order n by looping t hrough bot h arrays wit hin t he sam e loop, as shown in List ing 17- 6.

List in g 1 7 - 6 . Pr oce ss Bot h Ar r a ys W it h in On e Loop Sub ProcessLists(asArray1() As String, asArray2() As String) Dim lIndex1 As Long Dim lIndex2 As Long Dim iComp As Integer lIndex1 = LBound(asArray1) lIndex2 = LBound(asArray2) 'Loop through both arrays together Do 'Compare the elements from both arrays iComp = StrComp(asArray1(lIndex1), asArray2(lIndex2)) If iComp = 0 Then 'A match, so process it Debug.Print asArray1(lIndex1) 'And advance in both arrays lIndex1 = lIndex1 + 1 lIndex2 = lIndex2 + 1 ElseIf iComp = -1 Then 'Item in array1 is before item in array2, 'so move down array1 and check again lIndex1 = lIndex1 + 1 ElseIf iComp = 1 Then 'Item in array1 is after item in array2, 'so move down array2 and check again lIndex2 = lIndex2 + 1 End If 'Stop when we reach the end of one of the arrays Loop Until lIndex1 > UBound(asArray1) Or _

lIndex2 > UBound(asArray2) End Sub

I f t he arrays are not sort ed, it will probably be quicker t o sort t hem bot h beforehand, t hen use t he above rout ine. I f t he out put has t o be in a specific order ( prevent ing us from sort ing bot h arrays) , we could sort asArray2 and use a binary search rout ine t o see whet her t he st ring exist s, or use a Dict ionary obj ect ( see lat er for an exam ple of each) .

Tighten the Loop Having replaced t he nest ed loops wit h m ore efficient algorit hm s, t he next t ask is t o m ake t he code wit hin t he rem aining loop as t ight as possible. As well as im plem ent ing all t he m icro- opt im izat ions shown lat er in t his chapt er, t he prim ary goal is t o ensure t hat in each it erat ion, we only execut e t he m inim um am ount of code possible. Ret urning t o t he quest ion above " Does B have t o follow A?" it is com m on t o see loops t hat cont ain code t o calculat e int erm ediat e result s, followed by som e t est s t o check whet her t he int erm ediat e result should be used ( because t his reflect s t he order in which we originally t hought about t he rout ine) . I f we t urn t he rout ine on it s head, we can do t he t est s first and only calculat e t he int erm ediat e result s for t hose elem ent s we know we'll be using.

Fast VBA Algorithms QuickSort The QuickSort rout ine is one of t he fast est sort ing algorit hm s and should be used whenever you want t o sort an array. I t works by doing t he following:

1 . Select one elem ent from t he array, t ypically t aken from t he m iddle 2 . Scan t hrough t he array m oving everyt hing t hat should com e before t he select ed elem ent t o t he bot t om of t he array and everyt hing t hat should com e aft er t he select ed elem ent t o t he t op of t he array 3 . Call it self t o sort t he bot t om half 4 . Call it self t o sort t he t op half For best perform ance, you should have a num ber of QuickSort rout ines for specific dat a t ypes, such as t hat shown in List ing 17- 7 for one- dim ensional st ring arrays.

List in g 1 7 - 7 . A Qu ick Sor t Rou t in e for On e - D im e n sion a l St r in g Ar r a ys

'************************************************************** '* '* FUNCTION NAME: QUICKSORT STRING ARRAY - 1D '* '* DESCRIPTION: Sorts the passed array into required order. '* The array must be a 1D string array. '* '* PARAMETERS: '* asArray A 1D string array of values to sort '* bSortAscending True = ascending order. '* iLow1 The first item to sort between '* iHigh1 The last item to sort between '* '************************************************************** Sub QuickSortString1D(asArray() As String, _ Optional bSortAscending As Boolean = True, _ Optional iLow1, Optional iHigh1) 'Dimension variables Dim iLow2 As Long, iHigh2 As Long Dim sKey As String Dim sSwap As String On Error GoTo PtrExit 'If not provided, sort the entire array If IsMissing(iLow1) Then iLow1 = LBound(asArray) If IsMissing(iHigh1) Then iHigh1 = UBound(asArray) 'Set new extremes to old extremes iLow2 = iLow1 iHigh2 = iHigh1 'Get value of array item in middle of new extremes sKey = asArray((iLow1 + iHigh1) \ 2) 'Loop for all the items in the array between the extremes Do While iLow2 < iHigh2 If bSortAscending Then 'Find the first item that is greater than the mid-point Do While asArray(iLow2) < sKey And iLow2 < iHigh1 iLow2 = iLow2 + 1 Loop 'Find the last item that is less than the mid-point Do While asArray(iHigh2) > sKey And iHigh2 > iLow1 iHigh2 = iHigh2 - 1 Loop Else 'Find the first item that is less than the mid-point

Do While asArray(iLow2) > sKey And iLow2 < iHigh1 iLow2 = iLow2 + 1 Loop 'Find the last item that is greater than the mid-point Do While asArray(iHigh2) < sKey And iHigh2 > iLow1 iHigh2 = iHigh2 - 1 Loop End If 'If the two items are in the wrong order, swap them If iLow2 < iHigh2 Then sSwap = asArray(iLow2) asArray(iLow2) = asArray(iHigh2) asArray(iHigh2) = sSwap End If 'If the pointers are not together, do the next item If iLow2 lHigh PTR_Exit: End Function

Sort and Scan The com binat ion of a QuickSort and BinarySearch gives us a very efficient way of com paring t wo arrays, t o process t he elem ent s in com m on, as shown in List ing 17- 9.

List in g 1 7 - 9 . Com bin in g a Sor t a n d Bin a r y Se a r ch Sub ProcessLists(asArray1() As String, asArray2() As String) Dim lIndex As Long 'Sort the second array QuickSortString1D asArray2 'Loop through the first array For lIndex = LBound(asArray1) To UBound(asArray1) 'Use the binary search routine to 'check if the element is in the second array If BinarySearchString(asArray1(lIndex), asArray2) -1 Then

'A match, so process it Debug.Print asArray1(lIndex) End If Next End Sub

This is not quit e as efficient as t he exam ple shown previously t hat relied on bot h list s being sort ed, but is a very efficient and easy t o underst and alt ernat ive for use when t he init ial array m ust be left in it s original order.

The SORTSEARCH_INDEX udt When dealing wit h large 2D arrays, arrays of obj ect s or m ult iple keys, it is usually m ore efficient t o creat e a new indexing array and sort and search t hat t han t o t ry t o sort and search t he original array. An index array is an array of t he SORTSEARCH_I NDEX udt , which is defined as follows:

Public Type SORTSEARCH_INDEX Key As String Index As Long End Type

The key is t he st ring used for sort ing and searching, which is t ypically t he value from t he first colum n in a large 2D array, t he nam e of an obj ect or a concat enat ion of t he values t o sort an array by m ult iple colum ns. The index is t he row num ber in t he original array. When t he udt array is sort ed, we can loop t hrough t he elem ent s in t he sort ed order, using t he I ndex propert y t o ident ify t he appropriat e row from t he original array, as in List ing 17- 10.

List in g 1 7 - 1 0 . Usin g t h e SORTSEARCH _ I N D EX u dt Sub UseIndexSort() Dim vaArray As Variant Dim lRow As Long Dim auIndex() As SORTSEARCH_INDEX 'Assume vaArray is a multicolumn, multirow Variant array 'e.g. as read from the worksheet vaArray = Selection.Value 'Create an index array of the same size ReDim auIndex(LBound(vaArray) To UBound(vaArray))

'Populate the index array with the original row number 'and sort key For lRow = LBound(vaArray) To UBound(vaArray) auIndex(lRow).Index = lRow auIndex(lRow).Key = vaArray(lRow, 1) Next 'Sort the index array QuickSortIndex auIndex 'Loop through the sorted array For lRow = LBound(auIndex) To UBound(auIndex) 'The .Index element of the sorted udt is the row 'in the original array Debug.Print vaArray(auIndex(lRow).Index, 2) Next End Sub

QuickSort I ndex is a version of t he QuickSort algorit hm for arrays of t he SORTSEARCH_I NDEX user defined t ype and can be found on t he CD in t he workbook \ Concept s\ Ch17Opt im izing VBA Per for m ance\ Algor it hm s.xls. The workbook also cont ains a version of t he binary search algorit hm , BinarySearchI ndex, which searches for a st ring in t he index array and ret urns t he row num ber in t he original array.

Micro-Optimization Bot h VBA and Excel oft en provide m any ways t o do t he sam e t hing, som e of which are always fast er t han t he ot hers, but som e of which are som et im es fast er and som et im es slower depending on t he dat a being processed. This sect ion ident ifies m any of t he com m on alt ernat ives. Before blindly using t he recom m ended alt ernat ive, you should always confirm t he behavior using your own dat a. This can usually be done in a quick- and- dirt y m anner, using t he code shown in List ing 17- 11.

List in g 1 7 - 1 1 . A Sim ple Rou t in e t o Com pa r e Tw o Alt e r n a t ive s Sub CompareThem() Dim dStart As Double Dim lCounter As Long 'We often need lots of loops to get a measurable result Const 1LOOP_COUNT As Long = 10000 dStart = Timer For lCounter = 1 To 1LOOP_COUNT 'The code for one alternative Next Debug.Print "Version 1 took " & (Timer - dStart) & " seconds" dStart = Timer For lCounter = 1 To 1LOOP_COUNT 'the code for the second alternative Next Debug.Print "Version 2 took " & (Timer - dStart) & " seconds" End Sub

VBA's built - in Tim er call is fairly slow and not very accurat e, so we usually have t o do each version m any, m any t im es t o get a m easurable result , proving t hese m icro- opt im izat ions will only have a not iceable effect if t hey're execut ed m any t im es over.

VBA

Use Matching Data Types VBA is very forgiving when we m ix dat a t ypessuch as passing a Double t o a procedure t hat expect s a St ring or vice versa. However, t here is som e overhead associat ed wit h t he conversion and it can int roduce subt le bugs, so it should be avoided. Whenever passing a variable t o a procedure, or set t ing one variable equal t o anot her, always ensure t he variables have t he sam e dat a t ype.

Perform Explicit Conversions Instead of Implicit Ones When you are unable t o m at ch dat a t ypes, always t ell VBA which conversion t o perform , such as CSt r( ) , CDbl( ) and so on. By being explicit about t he conversion you want t o perform , you allow wast ing t he t im e required by VBA t o m ake t he decision it self.

Use Len(string)=0 Instead of string="" VBA st ores st rings in m em ory by st oring t he lengt h of t he st ring, followed by t he charact ers it cont ains. As t he lengt h of t he st ring is readily available, it is m uch quicker t o check whet her it is zero t han t o ask VBA t o perform st ring com parisons ( wit h all t he m em ory allocat ions t hat involves) .

Use Left$, Right$, Mid$ and So Forth Instead of Left, Right and Mid Most of VBA's st ring- handling funct ions have bot h a variant ( for exam ple, Left , Right , Mid) and a st ring ( Left $, Right $, Mid$) version. I f you use t he variant versions wit h st ring variables, VBA has t o convert t he inside st ring t o a variant , pass it t o t he funct ion, get t he result ( as a variant ) and convert t he result back t o a st ring. By using t he st ring version, VBA doesn't need t o do t he t wo variant - t o- st ring conversions, which can be relat ively slow, part icularly wit h large st rings.

Pass Strings and Variant Arrays ByRef Instead of ByVal Whenever st rings and arrays are passed t o a procedure by value ( ByVal) , VBA has t o t ake a copy of t he ent ire st ring or array and pass t he copy t o t he procedure. I f t he st ring or array is passed by reference ( ByRef) , VBA only has t o pass a point er t o t he procedure, which is m uch quicker.

Don't Use Option Compare Text Adding Option Compare Text t o t he t op of a m odule forces VBA t o perform all st ring com parisons in a case- insensit ive way. I n t he m aj orit y of cases, t his will not be required and only wast es t im e. I nst ead, every m odule should have Option Compare Binary set and you should use t he Com pareMet hod param et er of St rCom p, I nst r and so on t o specify when case- insensit ive com parisons are required. I f you need t o use a funct ion t hat doesn't have a Com pareMet hod ( such as Like) , you should eit her force bot h st rings t o upper- or lowercase and do a norm al binary com pare, or have a specific rout ine t o do t he com parison and place it in it s own m odule wit h

Option Compare Text set .

Use Early Binding Wherever Possible Whenever you declare a variable As Obj ect , VBA doesn't know anyt hing about it unt il runt im e. Every t im e you call a propert y or m et hod of t he obj ect , VBA has t o check whet her t he m et hod exist s, check it s param et ers and confirm your code can call it . All of t hat t akes t im e and should be avoided by giving all your variables specific t ypes. I f you are using As Obj ect t o be able t o call t he sam e propert y ( for exam ple, Nam e) on a num ber of your own classes, you should im plem ent a cust om int erface in t hose classes inst ead ( see Chapt er 11 I nt erfaces) .

Use Integer Arithmetic Where Possible VBA can perform int eger arit hm et icpart icularly divisionm uch fast er t han float ing- point arit hm et ic. You can t ell VBA t o use int eger arit hm et ic by declaring your variables As Long, or by using t he int eger division operat or, \ :

'Slower-uses floating-point operations dMid = (dLow + dHigh) / 2 'Faster-uses integer operations lMid = (lLow + lHigh) \ 2

Use For Each to Iterate Collections (Not by Index) VBA's Collect ion obj ect is designed t o be it erat ed m ost efficient ly using t he For Each const ruct , inst ead of For Next .

Use For …Next to Iterate Arrays (Not For Each) VBA's arrays, however, are fast er t o it erat e by index inst ead of using For Each.

Use Dictionaries Instead of Collections (If Order Isn't Important) The Microsoft Script ing Runt im e library, scrrun.dll, cont ains a very fast and light weight Dict ionary obj ect , which can be used j ust like a VBA Collect ion. As well as being fast er, it exposes bot h t he it em s and t he keys used t o st ore t hem and support s t he Exist s propert y t o check whet her a key exist s in t he collect ion. I t s biggest drawback is it does not allow it em s be insert ed int o t he m iddle of t he list , so can't be used when re- ordering is required.

Don't Use If bVariable = True Then, Just Use If bVariable Then

I f you have a Boolean variable, adding t he ext ra st ep of com paring it t o True in an I f st at em ent is j ust wast ing processing cycles. The redundant com parison t o True should be rem oved.

Don't Use IIf() VBA's I I f( ) funct ion is a very convenient way t o choose bet ween t wo alt ernat ives. However, it is also ext rem ely slow, com pared t o t he longer m ult iline I f st at em ent and always evaluat es bot h t he True and False expressions.

Use Multiple If…ElseIf…End If Instead of Select Case Sim ilarly, Select Case is a convenient , clear and easy- t o- read const ruct for choosing bet ween m ult iple alt ernat ives, but is also slower t han t he equivalent I f…ElseI f const ruct .

Use With blocks and Object Variables to Reduce the Dots VBA enables us t o navigat e t hrough obj ect m odel hierarchies using t he dot ( . ) operat or t o access an obj ect 's propert ies or m et hods. Think of every dot as a sm all pause in your applicat ion and reduce t hem by using Wit h blocks or an obj ect variable.

Excel Turn Off ScreenUpdating and Automatic Calculation The biggest gains when aut om at ing Excel are t o set Application.ScreenUpdating = False and Application.Calculation = xlManual. That will st op Excel cont inually refreshing it s display or recalculat ing everyt hing when dat a is writ t en t o t he sheet .

Don't Select Things The m acro recorder produces ext rem ely inefficient code, peppered wit h code such as t his:

Range("A1").Select Selection.Font.Bold = True

I t is ext rem ely rare t o ever need t o select anyt hing when cont rolling Excel from VBA. I n m ost cases, t hese t wo lines can be com bined by rem oving t he Select / Select ion:

Range("A1").Font.Bold = True

You will occasionally need t o insert an ext ra obj ect bet ween t he Select and Select ion, part icularly when chart s or drawing obj ect s are involved, such as changing a chart 's t it le:

ActiveSheet.ChartObjects("Chart 1").Activate ActiveChart.ChartTitle.Select Selection.Characters.Text = "Hello"

Becom es:

ActiveSheet.ChartObjects("Chart .Characters.Text = "Hello"

1").Chart.ChartTitle _

Use Variant Arrays I nst ead of reading and writ ing cells one by one, it is m uch quicker t o read a range of cells int o a Variant variable, t hen process t he variable as a 2D array, or populat e a Variant array t hen writ e it t o a range of cells, as shown in List ing 17- 12.

List in g 1 7 - 1 2 . Re a din g a n d W r it in g Va r ia n t Ar r a ys Sub ReadWriteVariants() Dim vaData As Variant Dim lRow As Long Dim lCol As Long 'Read the data from the sheet in one go vaData = ActiveSheet.Range("A1:B10").Value 'Process the data within VBA For lRow = 1 To UBound(vaData) For lCol = 1 To UBound(vaData, 2) If IsNumeric(vaData(lRow, lCol)) And _ Not IsEmpty(vaData(lRow, lCol)) Then vaData(lRow, lCol) = vaData(lRow, lCol) * 2 End If Next Next

'Write the data to the sheet in one go ActiveSheet.Range("D1:E10").Value = vaData End Sub

Don't Use ActiveSheet, Selection or Worksheets() Repeatedly Som e of t he m ore com m only used propert ies in t he Excel obj ect m odelsuch as Act iveSheet , Select ion or Worksheet sret urn t he generic Obj ect t ype, so all calls t hat use t hese obj ect s will be lat e- bound and slow. For best perform ance, you should declare a variable of t he specific dat a t ype and set it t o be t he Act iveSheet , Select ion and so fort h.

Test a Property Before Setting It I t is oft en m uch fast er t o read a propert y t han t o writ e it . I t can save t im e t o only updat e a propert y when it needs t o change, by checking whet her it is t he required value first . This cont radict s t he general rule of reducing t he am ount of code you writ e, but it can be readily observed t hat reading t he value of an Excel obj ect 's propert y ( such as Range.Font.Bold) m akes it m uch quicker t o subsequent ly set t he sam e propert y.

Use Doubles to Talk to Excel When passing num bers t o Exceleit her t o populat e a worksheet cell or as param et ers t o Excel funct ionsit is usually m ost efficient t o pass variables declared As Double. This is because Excel generally uses t he Double dat a t ype int ernally and so avoids t ype conversions. When populat ing a cell, Excel will also t ry t o apply cell form at t ing if ot her dat a t ypes ( such as Dat e or Currency) are used. Using Double's t hroughout avoids Excel's aut oform at t ing and so im proves perform ance.

Use the PAGE.SETUP XLM Function Instead of the PageSetup Object Whenever you change any of t he propert ies of t he PageSet up obj ect , Excel repaginat es t he page, t o check whet her t he aut om at ic zoom ing or aut om at ic page breaks need t o change. To do t his, Excel has t o com m unicat e wit h t he print er drivers, which is ext rem ely slow. This can be avoided by using t he PAGE.SETUP XLM funct ion, which is fully docum ent ed in t he m acrofun.hlp file available from ht t p: / / suppor t .m icr osoft .com / ?kbid= 128175, as shown in List ing 17- 13. Not e t hat t he PAGE.SETUP funct ion always applies t he set t ings t o t he act ive sheet .

List in g 1 7 - 1 3 . Usin g PAGE.SETUP t o Se t a Pa ge H e a de r Sub SetHeaders()

'Set the header using the slow PageSetup object With ActiveSheet.PageSetup .LeftHeader = "Hello" .RightHeader = "World" End With 'Set the header using the faster PAGE.SETUP XLM function ExecuteExcel4Macro "PAGE.SETUP(""&LHello &RWorld"")" End Sub

Conclusion A highly opt im ized VBA rout ine will oft en execut e in 1/ 10t h or 1/ 100t h t he t im e t aken by t he first version of t he rout ine. I n m ost cases, VBA's perform ance is " good enough," in t hat t he rout ine execut es wit hin an accept able t im e, such as 2 seconds t o show a form , 0.5 seconds for elem ent s wit hin t he form ( for exam ple, when t yping int o a t ext box) or 10 seconds t o produce a report . Rout ines which t ake significant ly longer t han t his are good candidat es for opt im izat ion. The CD included wit h t his book cont ains an add- in for bot h t he Office VBE and VB6 I DE t o m onit or an applicat ion's perform ance as it runs, which can be used t o assess t he perform ance im pact of changes t o t he code. Macro- opt im izat ion looks at t he st ruct ure of t he rout ine, t o use t he m ost efficient algorit hm s and m inim ize t he am ount of code t hat needs t o be execut ed. This is where m ost of t he savings are usually found. Micro- opt im izat ion ensures t he m ost efficient VBA st at em ent s and dat a t ypes are used wit hin t he code. These account for t he final few percent age point s and usually only have an im pact where loops are execut ing t housands of t im es. The t rade- off is com plexit y. A QuickSort is m uch fast er t han a bubble sort and a binary search in a sort ed array is m uch fast er t han looping t hrough a collect ion, but t hey are also m ore com plex and t herefore slight ly harder t o debug and m aint ain. By using t he t echniques suggest ed in t his chapt er when writ ing new rout ines, t he knowledgeable VBA developer can writ e rout ines t hat are already well opt im ized and are likely t o operat e wit hin accept able t im e lim it s.

Chapter 18. Controlling Other Office Applications Excel's prim ary purpose is t o perform calculat ions. I t has som e dat abase- like feat ures, but it 's not a relat ional dat abase. I t has som e t ext edit ing and form at t ing feat ures, but it 's not a word processor. I t has present at ion- qualit y graphics, but it 's not a present at ion applicat ion. I t can save worksheet s as Web pages, but it 's not a Web aut horing t ool. I t can send a workbook t hrough e- m ail, but it 's neit her an e- m ail program nor personal inform at ion m anager. Excel's built - in dat abase, word processing, present at ion, e- m ail and Web feat ures are sufficient for m ost applicat ions, but t here com es a t im e when we need t o use a feat ure t hat is only provided by t he dedicat ed Office applicat ionAccess, Word, PowerPoint , Out look or Front Page. This chapt er explains how t o cont rol t hose ot her Office applicat ions from wit hin Excel, suggest s som e best pract ices t o use when cont rolling ot her applicat ions and provides an int roduct ory overview of t he m aj or obj ect s in each applicat ion's obj ect m odel.

Fundamentals Cont rolling anot her applicat ion is only a m at t er of knowing how t o connect t o t he t arget applicat ion and efficient ly use it s obj ect m odel. This part of t he chapt er discusses t he fundam ent als of connect ing t o ot her applicat ions and best pract ices for using t hird- part y obj ect m odels.

Automation Aut om at ion is Microsoft 's generic t erm for t echnology t hat allows one applicat ion t o m anipulat e anot her applicat ion's obj ect s, including allowing VBA t o m anipulat e Excel. Aut om at ion began wit h a t echnology called OLE ( Obj ect Linking and Em bedding) and has since evolved int o ot her form s such as COM ( Com ponent Obj ect Model) , also known as Act iveX, and DCOM ( Dist ribut ed Com ponent Obj ect Model) . The applicat ion t hat m anipulat es t he obj ect s is called t he a u t om a t ion clie n t or h ost a pplica t ion . Applicat ions whose obj ect s are m anipulat ed are called a u t om a t ion se r ve r s or t a r ge t a pplica t ion s. All of t he Office applicat ions can be used as aut om at ion servers so long as t hey've been properly inst alled ( regist ered) on t he com put er. Microsoft Office applicat ions are aut om at ically regist ered during inst allat ion, but can be re- regist ered using t he / regserver com m and- line swit ch.

Referencing The easiest way t o get st art ed is t o creat e a reference t o t he obj ect library for t he applicat ion t hat we want t o aut om at e using t he Tools > References m enu in t he VBE. I n Figure 18- 1, we've added a reference t o t he Word 2000 obj ect library, as indicat ed by t he 9.0 version num ber in t he reference descr ipt ion.

Figu r e 1 8 - 1 . Addin g a Re fe r e n ce t o t h e W or d Obj e ct Libr a r y

Wit h t he reference set , we can use t he obj ect s in t he Word obj ect m odel as if t hey were classes in our proj ect , as shown in List ing 18- 1, which uses t he New keyword t o creat e a new inst ance of t he Word applicat ion.

List in g 1 8 - 1 . A Sim ple Pr oce du r e t o Con t r ol W or d Sub ControlWord() 'Declare an object variable to reference 'the Word application Dim wrdApp As Word.Application 'Start a new instance of Word Set wrdApp = New Word.Application 'Do something 'Close Word and tidy up wrdApp.Quit savechanges:=False Set wrdApp = Nothing End Sub

Development Best Practices I n addit ion t o t he advice given in Chapt er 3 Excel and VBA Developm ent Best Pract ices, som e addit ional t echniques should always be used when aut om at ing ot her applicat ions.

Always Include the Object Library in Variable Declarations Whenever we declare a variable as a specific obj ect t ype, such as Dim rngData As Range, t he VBA int erpret er scans t hrough t he obj ect libraries referenced in t he Tools > References list ( in t he order shown in t hat list ) unt il it finds an obj ect wit h t he sam e nam e as specified in t he variable declarat ion. I n t his case, t he first obj ect library t o cont ain an obj ect called Range is t he Excel obj ect library, so our variable is t yped as an Excel Range obj ect . I n m ost cases, t hat 's exact ly what we want t o happen. Problem s arise, t hough, if we're referencing m ult iple obj ect libraries t hat use t he sam e nam e for t heir own obj ect s. For exam ple, Excel and Word bot h have Range obj ect s, but t hey're very different . To m ake sure t he int erpret er uses t he Range obj ect from t he correct library, we should always include t he library nam e in t he variable declarat ion, as shown in List ing 18- 2.

List in g 1 8 - 2 . D e cla r in g Obj e ct s w it h t h e Cor r e ct Obj e ct Libr a r y Sub GetRanges() 'An Excel Range Dim rngData As Excel.Range 'A Word Range Dim wrngTitle As Word.Range End Sub

I n addit ion t o explicit ly t elling VBA which Range obj ect we want a reference t o, fully qualifying our obj ect declarat ions also m akes our code m uch easier t o underst and; when we see As Word.Range, we have t he m ent al prom pt t hat t he Word obj ect library is being used. This prom pt is carried t hrough t o t he variable nam e, where we've included a w prefix t o indicat e an obj ect from t he Word obj ect library.

Always Fully Qualify Property and Method Calls All of t he Office obj ect libraries include som e global propert ies t hat we oft en use as short cut s int o t he obj ect m odel, such as Excel's Act iveSheet , Act iveCell, Select ion and Word's Act iveDocum ent , Select ion and so on. Whenever we use any such propert y in cross- applicat ion developm ent , we m ust always provide a fully qualified obj ect reference t hat can be t raced back t o t he original

variable we used t o reference t he applicat ion. List ing 18- 3 shows t he correct way t o get a reference t o t he Act iveDocum ent in a Word inst ance t hat we're cont rolling.

List in g 1 8 - 3 . Re fe r r in g t o t h e Act ive D ocu m e n t Sub GetActiveDoc() 'Declare an object variable to reference 'the Word application Dim wrdApp As Word.Application Dim wrdDoc As Word.Document 'Start a new instance of Word with a blank document Set wrdApp = New Word.Application 'Do something that opens or creates a document 'Get a reference to the active document Set wrdDoc = wrdApp.ActiveDocument 'Close Word and tidy up wrdApp.Quit savechanges:=False Set wrdDoc = Nothing Set wrdApp = Nothing End Sub

I f we om it t ed t he wrdApp. in t he highlight ed line, t he VBA int erpret er will t ry t o find a Word docum ent in any inst ance of Word t he user m ight have open, which m ay not be t he inst ance we're cont rolling. By providing t he wrdApp. reference, we're explicit ly t elling t he int erpret er t o ret urn t he act ive docum ent in t he inst ance of Word we've creat ed.

Develop Using the Earliest Version You'll Support For reasons explained lat er, references t hat we declare t o Office obj ect libraries are forward com pat ible but not backward com pat ible. This m eans t hat if we save our workbook wit h a reference t o t he Word 2003 obj ect library, anyone opening t he workbook on a PC wit h only Office 2000 inst alled will receive a com pile error " Can't find proj ect or library" as soon as t he code is run. I f we save our workbook wit h a reference t o t he Word 2000 obj ect library, it will work correct ly on any m achine wit h Office 2000 or any lat er version. Every version of Office adds m ore feat ures t o each applicat ion and correspondingly m ore obj ect s, m et hods, propert ies and opt ional param et ers t o t he applicat ion's obj ect library. By developing using t he earliest version t hat we int end t o support , we st op ourselves from accident ally using any of t he m ore recent obj ect s, m et hods, propert ies or param et ers. I f we were t o develop using t he lat est version of t he applicat ion, we would not discover our accident al use of t he newer obj ect s unt il we were well int o our t est ing, or even aft er deploym ent .

Group Routines in Application-Specific Modules The VBA int erpret er/ com piler com piles our code on a m odule- by- m odule basis. A m odule is com piled when code cont ained in t hat m odule is first run. I f we have a reference t o an obj ect library t hat isn't regist ered correct ly, t he com piler will not be able t o com pile t he m odule t hat cont ains code t hat uses obj ect s in t hat library and we'll get a com pile error. This issue can be part ially m it igat ed by ensuring t hat all t he code t hat cont rols anot her applicat ion is cont ained in a single m odule dedicat ed t o t hat purpose. The m odule should not cont ain any procedures used by ot her part s of t he applicat ion. I f we're aut om at ing m ult iple applicat ions, t he rout ines for each applicat ion should be in t heir own m odulesone for Word, one for Access, one for PowerPoint and so onwit h each m odule having a descript ive nam e such as MWordCode. Wit h all t he applicat ionspecific code cont ained in a single m odule, we can check whet her t he applicat ion is inst alled correct ly and safely use or avoid t hat m odule, as shown lat er.

The vTable and Early vs. Late Binding Every COM obj ect has a st ruct ure called a v Ta b le, or virt ual funct ion t able, which list s all it s propert ies and m et hods along wit h t he m em ory addresses where t heir ent ry point s are locat ed and t he param et ers t hey t ake. When we declare a variable as a specific obj ect dat a t ype, t he com piler can look up t he addresses of all t he propert y and m et hod calls for t hat obj ect in it s vTable at com pile t im e. I t can t hen st ore j u m p t o inst ruct ions t hat ident ify t he ent ry point s of t hose propert y and m et hod calls direct ly in our code. When t he code is execut ed and VBA encount ers one of t hese propert y or m et hod calls, it j ust runs t he code at t he m em ory locat ion specified by t he st ored j um p t o inst ruct ion. This is known as e a r ly bin din g . Early binding requires us t o set a reference t o t he obj ect library t hrough t he Tools > References m enu, so VBA can include t hat obj ect library's GUI Ds and ot her t ype inform at ion in our proj ect . ( A GUI D is a unique 128- bit num ber used t o ident ify all COM obj ect s.) When our proj ect is run on a different com put er, VBA verifies t hat an obj ect wit h t he sam e GUI D as t he one we originally referenced is available t here. I f so, it m eans t his is t he sa m e obj ect as t he one we originally referenced so it will have t he sam e vTable. Therefore, all t he direct m em ory j um p inst ruct ions t hat were com piled int o our applicat ion for t hat obj ect can be t rust ed. I f t he GUI D is not found on t he client com put er, VBA knows t hat t he obj ect we want t o use is not available and so gives us a com pile error ( and m arks t he reference as MI SSI NG in t he Tools > References list ) . This is why MI SSI NG obj ect library references caused by referenced COM com ponent s not being inst alled on a user's com put er will st op a VBA applicat ion dead in it s t racks. When we declare a variable as t he generic Obj ect dat a t ype, t he com piler doesn't know which vTable t o use. Therefore, it cannot det erm ine t he m em ory locat ion of t hat obj ect 's propert ies and m et hods and it cannot com pile j um p t o inst ruct ions for t hem int o our code. I nst ead, aft er t he generic obj ect variable has been set t o reference a specific obj ect at run- t im e, VBA checks t he vTable of t hat obj ect every t im e it encount ers one of t he obj ect 's propert y or m et hod calls in order t o locat e t he m em ory address t o j um p t o. This is known as la t e bin din g . The cont inual vTable lookups can have a significant im pact on perform ance, but t hey don't require us t o set a reference t o t he obj ect library we're cont rolling. This result s in any referencing problem s ( such as a m issing obj ect library) appearing as runt im e errors ( which we can handle gracefully) rat her t han com pile errors. The vTable also explains why Office obj ect libraries are forward com pat ible, but not backward

com pat ible. I n each new version of an Office applicat ion t he vTable is e x t e n de d wit h new propert y and m et hod ent ries, but t he exist ing sect ions are not changed. This m akes it safe t o use an earlier version vTable ent ry t o call int o a lat er version of t he sam e applicat ion, but not vice versa. The first sect ion of t he lat er version's vTable is ident ical t o t he earlier version's vTable, but it also cont ains addit ional ent ries t hat do not appear in t he earlier version. I f VBA at t em pt ed t o execut e a propert y or m et hod call ident ified by an ent ry lat e in t he Word 2003 vTable while running under Word 2000, for exam ple, t hat ent ry wouldn't exist in t he Word 2000 execut able and our applicat ion would crash. As well as cont rolling whet her we can use early binding, adding a reference t o an obj ect library also cont rols whet her we can use t he const ant s and param et er nam es defined in t he library, as shown in List ing 18- 4.

List in g 1 8 - 4 . Ea r ly vs. La t e Bin din g 'Early-Bound 'Requires a reference to the Word object library, 'but allows us to use specific object types, 'named parameters and defined constants 'and gives us IntelliSense information Sub EarlyBound(wrdApp As Word.Application) 'Open a text file wrdApp.Documents.Open FileName:="c:\myfile.txt", _ Format:=wdOpenFormatText End Sub 'Late-Bound 'Have to use the generic Object type, 'can't use named parameters or defined constants, 'don't get IntelliSense information, 'but doesn't require a reference either. Sub LateBound(wrdApp As Object) 'Open a text file wrdApp.Documents.Open "c:\myfile.txt", , , , , , , , , 4 End Sub

The key fact or in choosing bet ween early or lat e binding is t he likelihood t hat t he applicat ions we're cont rolling are available and inst alled correct ly on t he users' com put ers. We can ensure t he applicat ions are inst alled correct ly on our com put ers, so we should always use early binding during developm ent . That allows us t o use t he I nt elliSense inform at ion, obj ect t ypes, const ant s and nam ed param et ers which t oget her m ake early- bound code m uch easier t o develop, read, debug and m aint ain. Before dist ribut ing our applicat ion t o our users, we need t o decide whet her t o swit ch t o using lat e

binding. This will usually depend on bot h t he likelihood t hat t he applicat ions are available and t he am ount of code t hat calls t he applicat ion. The fundam ent al advant age of using lat e binding is t hat we can easily handle a failure t o link t o t he obj ect we want t o cont rol ( see lat er for an exam ple) . I n t he case of Excel aut om at ing Word wit hin a com pany environm ent , it 's highly likely t hat anyone wit h Excel inst alled will have Word inst alled as well, so it 's probably safe t o st ay wit h early binding. The sam e can't be said when aut om at ing, say, Front Page, so it would probably be best t o swit ch t o lat e binding for t hat . I f we only have a few lines of code, it 's safest t o always use lat e binding. Wit h lot s of code, t he inabilit y t o use nam ed param et ers and defined const ant s when lat e binding can m ake our applicat ions m uch harder t o m aint ain.

Handling Instances Before we can use an applicat ion's feat ures, we need t o connect t o an inst ance of t he applicat ion. We can eit her hij ack an inst ance t he user m ight already have open or creat e a new inst ance for our dedicat ed use. Unless t here is a specific need t o link t o t he inst ance t hat t he user is working wit h, we should always creat e our own inst ances, use t hem and close t hem when we're finished. This is m ainly because t he user m ay have left t he inst ance t hey're using in a st at e t hat would cause errors in our applicat ion if we t ried t o use it , such as having a m odal dialog displayed. This could eit her prevent our applicat ion working correct ly, or worse, result in our applicat ion int erfering wit h t he work t he user is doing in t hat inst ance.

Create a New Instance We can use eit her t he New keyword or Creat eObj ect funct ion t o creat e a new inst ance of an applicat ion, as shown in List ing 18- 5. The New keyword can only be used if we have set a reference t o t he t ype libr a r y ( synonym ous wit h obj ect library) , while t he Creat eObj ect funct ion can be used eit her wit h or wit hout a reference. The m anner in which an applicat ion is st art ed does not det erm ine whet her we're using early or lat e binding. Rat her, t he opposit e is t rue; our choice of binding det erm ines whet her we can use New or Creat eObj ect . Alt hough using t he New keyword is slight ly fast er t han Creat eObj ect , it is our opinion t hat Creat eObj ect should always be used, as it is one less t hing t o change if we choose t o swit ch bet ween early and lat e binding.

List in g 1 8 - 5 . Cr e a t in g a N e w I n st a n ce of W or d Sub StartWord() 'Early bound Dim wrdApp1 As Word.Application Set wrdApp1 = New Word.Application 'Early bound Dim wrdApp2 As Word.Application Set wrdApp2 = CreateObject("Word.Application") 'Late bound Dim wrdApp3 As Object

Set wrdApp3 = CreateObject("Word.Application") End Sub

Table 18- 1 list s som e of t he Office applicat ion class nam es used by t he Creat eObj ect funct ion.

Ta ble 1 8 - 1 . Cla ss List for Cr e a t e Obj e ct Applica t ion

Cla ss

Access

Access.Applicat ion

Excel

Ex cel.Applicat ion

Front Page

Fr ont Page.Applicat ion

I nt ernet Explorer

I nt er net Ex plor er .Applicat ion

MapPoint

MapPoint .Applicat ion

Out look

Out look .Applicat ion

Pow er Point

Pow er Point .Applicat ion

Pr oj ect

MSPr oj ect .Applicat ion

Publisher

Publisher .Applicat ion

Visio

Visio.Applicat ion

Wor d

Wor d.Applicat ion

Properly Tidying Up Whenever we creat e a new inst ance of an applicat ion, we m ust ensure t hat we close it correct ly. I n m ost cases, t his is j ust a m at t er of calling t he applicat ion's Quit m et hod and t hen dest roying any variables t hat we m ay be using t o reference it . We m ust be part icularly careful wit h error handling, t o ensure t hat t he applicat ion we're cont rolling is correct ly shut down in t he case of an error, as shown in List ing 18- 6, which uses t he error handling st ruct ure explained in Chapt er 12 VBA Error Handling.

List in g 1 8 - 6 . St a r t in g a n d Closin g W or d, w it h Er r or H a n dlin g Sub ControlWord()

Const sSOURCE As String = "ControlWord" Dim wrdApp As Word.Application On Error GoTo ErrorHandler 'Start Word Set wrdApp = CreateObject("Word.Application") 'Do something here ErrorExit: 'The tidy-up code is performed 'whether or not we get an error If Not wrdApp Is Nothing Then 'Close Word, ignoring any errors 'Without On Error Resume Next, an error would 'cause an endless loop in the error handler. On Error Resume Next wrdApp.Quit savechanges:=False On Error GoTo ErrorHandler 'Tidy up Set wrdApp = Nothing End If Exit Sub ErrorHandler: If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else Resume ErrorExit End If End Sub

Reference an Existing Instance I t is nearly always best t o creat e a new inst ance of an applicat ion for our program t o use. A not able except ion is when cont rolling Out look, because it only allows a single inst ance t o be running at any one t im e; using eit her t he New keyword or Creat eObj ect funct ion t o creat e an inst ance of Out look only creat es an inst ance if Out look is not already running. I f Out look is already open, a reference t o t hat inst ance is ret urned. This behavior can cause us problem s when we've finished using t he inst ance we asked for, as we won't know whet her or not we should shut Out look down. I f Out look was already running when we asked for our inst ance, we should leave it running. I f it wasn't already running, we should close it . We can use t he Get Obj ect funct ion t o obt ain a reference t o an

exist ing inst ance of an applicat ion, t hen use Creat eObj ect if t he Get Obj ect call fails, as shown in List ing 18- 7. I n eit her case, we set a Boolean variable t hat we use t o see whet her we should close Out look when t idying up.

List in g 1 8 - 7 . Ch e ck in g for , St a r t in g a n d Closin g Ou t look , w it h Er r or H a n dlin g Sub ControlOutlook() Const sSOURCE As String = "ControlOutlook" Const sOUTLOOK_APP As String = "Outlook.Application" Dim olkApp As Outlook.Application Dim bOutlookCreated As Boolean 'Try to get a reference to Outlook On Error Resume Next Set olkApp = GetObject(, sOUTLOOK_APP) On Error GoTo ErrorHandler If olkApp Is Nothing Then 'Start Outlook Set olkApp = CreateObject(sOUTLOOK_APP) bOutlookCreated = True End If 'Do something here ErrorExit: 'The tidy-up code is performed 'whether or not we get an error If Not olkApp Is Nothing Then If bOutlookCreated Then 'Close Outlook, ignoring any errors On Error Resume Next olkApp.Quit On Error GoTo ErrorHandler End If 'Tidy up Set olkApp = Nothing End If Exit Sub ErrorHandler:

If bCentralErrorHandler(msMODULE, sSOURCE) Then Stop Resume Else Resume ErrorExit End If End Sub

When we use Creat eObj ect t o st art a new inst ance of PowerPoint , we act ually get a reference t o an exist ing inst ance if t here is one already running. The Present at ions collect ion includes all t he open present at ions from all t he " inst ances" t hat have been creat ed. This is sim ilar t o Out look's behavior, but PowerPoint also t idily handles calls t o Applicat ion.Quit by closing only t he present at ion and not t he ent ire applicat ion. We can t herefore safely use Creat eObj ect t o st art PowerPoint and Applicat ion.Quit t o close it .

Multiversion Support I t is a fact of Excel applicat ion developm ent t hat we can expect our users t o have a variet y of Office versions, t ypically going back as far as Office 2000. We explained previously how t he vTable allows obj ect libraries t o be forward com pat ible but not backward com pat ible. This m eans if we save our workbook cont aining a reference t o Word 2003, it will give a com pile error when run on a m achine wit h only Office 2000 inst alled. One solut ion t o t his problem is t o save our workbook wit h a reference t o t he earliest version of t he obj ect library we int end t o support . When a workbook saved wit h a reference t o Word 2000 is run on a m achine wit h Office 2003, t he reference will aut om at ically be updat ed t o Word 2003. Unfort unat ely, if t hat workbook is t hen saved, t he reference t o Word 2003 will rem ain. I f t he workbook is forwarded t o our Office 2000 user, we'll get t he com pile error again. This t echnique is t herefore only suit able for workbooks t hat our users won't need t o save, such as add- ins and t he code workbooks of dict at or applicat ions. I f we put our code and UI in separat e workbooks, it is probably only t he UI workbook t hat will need t o be saved by our users, t hereby avoiding t his problem . The safest solut ion, t hough, is t o use lat e binding and save our workbooks wit hout any reference t o Word. When run, we can check t he availabilit y and version of Word and run t he code appropriat ely.

Determining the Availability of an Application The funct ion shown in List ing 18- 8 checks whet her an applicat ion is inst alled by sim ply t rying t o st art it . I f t he applicat ion st art s successfully, t he funct ion ret urns a reference t o it via t he obj App param et er. Not e t hat t his funct ion can ( and should) be used regardless of whet her we're lat e binding or early binding. Even if an obj ect library exist s and is regist ered, t here is no guarant ee t hat t he applicat ion will st art correct ly.

List in g 1 8 - 8 . Ch e ck in g for a n I n st a lle d Applica t ion

Function bIsAppAvailable(ByVal sClass As String, _ ByRef objApp As Object) As Boolean On Error Resume Next Set objApp = CreateObject(sClass) bIsAppAvailable = (Not objApp Is Nothing) End Function

Performance VBA calls bet ween applicat ions, such as Excel cont rolling Word, are ext rem ely slow, even if we're using early binding. To im prove perform ance, we need t o keep such calls t o a m inim um , using Wit h blocks and obj ect variables t o refer t o it em s deep in t he obj ect m odel. For best perform ance, we should m ove t he code int o t he t arget applicat ion. For exam ple, List ing 18- 9 uses Excel t o populat e a num ber of Word bookm arks, wit h all t he code cont ained in Excel. I n List ing 18- 10, we have m oved t he code t hat populat es t he docum ent int o a Word t em plat e, which is opened and called from our Excel code. Alt hough t his is a t rivial exam ple, t he t echnique can result in a significant perform ance im provem ent in m ore com plex sit uat ions. These exam ples can be found on t he CD in t he \ Concept s\ Ch18Cont rolling Ot her Office Applicat ions folder and com prise t he following: Popu la t e W or d.x ls An Excel workbook cont aining bot h Populat eWordDoc procedures Book m a r k s.dot A sim ple Word t em plat e wit h som e bookm arked t ext t o updat e FillD ocu m e n t .dot A Word t em plat e cont aining t he code from List ing 18- 10

List in g 1 8 - 9 . Popu la t in g a W or d D ocu m e n t En t ir e ly fr om Ex ce l 'In an Excel module, with a reference to Word Sub PopulateWordDoc1() Dim Dim Dim Dim Dim

wrdApp As Word.Application wrdDoc As Word.Document sPath As String vaBookmarks As Variant lBookmark As Long

'Fill the Bookmarks array from the sheet vaBookmarks = wksBookmarks.Range("rngBookmarkList").Value 'Start Word Set wrdApp = CreateObject("Word.Application") 'Open the template to populate

sPath = ThisWorkbook.Path & "\" Set wrdDoc = wrdApp.Documents.Add(Template:=sPath & _ "Bookmarks.dot") 'Populate the bookmarks in the template from the array For lBookmark = LBound(vaBookmarks, 1) To _ UBound(vaBookmarks, 1) wrdDoc.Bookmarks(vaBookmarks(lBookmark, _ LBound(vaBookmarks, 2))).Range.Text = _ vaBookmarks(lBookmark, UBound(vaBookmarks, 2)) Next lBookmark 'Save the filled document and close it wrdDoc.SaveAs sPath & "Filled1.doc" wrdDoc.Close Set wrdDoc = Nothing 'Close Word wrdApp.Quit False Set wrdApp = Nothing End Sub

List in g 1 8 - 1 0 . Popu la t in g a W or d D ocu m e n t Usin g Code in W or d 'In a module in the Word template FillDocument.dot Public Sub FillDocument(ByVal sTemplateName As String, _ ByVal sSaveName As String, _ ByVal vaBookmarks As Variant) Dim docToFill As Document Dim lBookmark As Long Set docToFill = Documents.Add(Template:=sTemplateName) For lBookmark = LBound(vaBookmarks, 1) To _ UBound(vaBookmarks, 1) docToFill.Bookmarks(vaBookmarks(lBookmark, _ LBound(vaBookmarks, 2))).Range.Text = _ vaBookmarks(lBookmark, UBound(vaBookmarks, 2)) Next lBookmark docToFill.SaveAs sSaveName docToFill.Close End Sub 'In an Excel module, with a reference to Word

Sub PopulateWordDoc2() Dim Dim Dim Dim

wrdApp As Word.Application wrdDoc As Word.Document sPath As String vaBookmarks As Variant

'Fill the Bookmarks array from the sheet vaBookmarks = wksBookmarks.Range("rngBookmarkList").Value 'Start Word Set wrdApp = CreateObject("Word.Application") 'Open the template containing our controlling code sPath = ThisWorkbook.Path & "\" Set wrdDoc = wrdApp.Documents.Open(sPath & _ "FillDocument.dot") 'Run the code within Word, passing all required information wrdApp.Run "FillDocument", sPath & "Bookmarks.dot", _ sPath & "Filled2.doc", vaBookmarks wrdDoc.Close Set wrdDoc = Nothing wrdApp.Quit False Set wrdApp = Nothing End Sub

The Primary Office Application Object Models Now t hat we can reliably det ect , st art , cont rol and shut down ot her Office applicat ions, t he final piece of t he puzzle is t o learn each applicat ion's obj ect m odel. This part of t he chapt er provides an int roduct ion t o t he m ain obj ect s wit hin each obj ect m odel, dem onst rat ing som e t ypical uses wit hin Excel- based applicat ions. All t he Office applicat ions have a t op- level Applicat ion obj ect , which is t he obj ect we get a reference t o when creat ing new inst ances of t he applicat ion. From t he Applicat ion obj ect , we drill down t o t he ot her obj ect s t hat provide t he applicat ion's funct ionalit y. All t he exam ples in t his sect ion can be found on t he CD in t he \ Concept s\ Ch18Cont rolling Ot her Office Applicat ions folder. The workbook Ch18Exam ples.xls cont ains all t he exam ple code and a dat a sheet t o represent t he result s of som e analysis.

Access and Data Access Objects I t 's act ually quit e rare t o aut om at e Access it self from an Excel applicat ion. We can easily m anipulat e t he dat a in an Access ( Jet ) dat abase out side of Access using Act iveX Dat a Obj ect s, as described in Chapt er 13 Program m ing wit h Dat abases, and t here's lit t le reason t o use Access form s inst ead of VBA userform s. However, Access is m uch bet t er t han Excel for creat ing cont inuous dat adriven report s, wit h it s sort ing and grouping and separat e group, page and report headers and foot er s.

Application Each inst ance of Access has a single dat abase, which we open using Application.OpenCurrentDatabase and close using Application.CloseCurrentDatabase. The Current Db obj ect exposes a Dat a Access Obj ect s ( DAO) Dat abase obj ect , which we can use t o m anipulat e t he st ruct ure of t he t ables and queries in t he dat abase. Most of t he ot her propert ies of t he Applicat ion obj ect provide inform at ion about t he st at e of t he applicat ion, such as which t ables t he user has open, and are very rarely relevant when cont rolling Access from Excel.

DAO.Database The DAO Dat abase obj ect t hat we get from Application.CurrentDb provides program m at ic access t o t he st ruct ure of t he dat abase, via t he TableDefs, QueryDefs and Relat ions collect ions. The m ost com m only used of t hese is t he TableDefs collect ion, t hrough which we can access t he propert ies of t he dat abase t ables. I n m any sit uat ions, we m ay have an access t able linked t o a separat e dat a source, such as an Excel workbook or SQL Server t able and will need t o change t he t able's link inform at ion prior t o running a report .

DoCmd Most aut om at ion of Access is done t hrough t he DoCm d obj ect , which provides program m at ic access t o m ost of Access' m enus, including delet ing t ables, im port ing dat a and running report s.

Example The procedure in List ing 18- 11 runs an Access report based on dat a in an Excel workbook. The Access dat abase Report OnExcelDat a.m db cont ains a single t able, t blExcelDat a, t o link t o t he Excel workbook, a query t o sort t he dat a and a report , rpt ExcelDat a, t o run. The procedure creat es an inst ance of Access, opens t he dat abase, updat es t he t able's connect ion inform at ion and runs t he report , leaving it displayed onscreen. This code can be found in t he MAccess m odule of t he Ch18Exam ples.xls workbook and t he dat abase cont aining t he linked t able and report is called Report OnExcelDat a.m db.

List in g 1 8 - 1 1 . Ru n n in g a n Acce ss Re por t Usin g Ex ce l D a t a Sub AccessRunReport() 'Requires references to the Microsoft Access and 'Microsoft DAO object libraries Dim objApp As Object Dim accApp As Access.Application Dim dbData As DAO.Database Dim tdExcelData As DAO.TableDef 'Update the export range wksAccess.Range("tblExcelDataStart").CurrentRegion _ .Name = "tblExcelData" 'Save any changes to the workbook, so Access can read 'the latest version from disk ThisWorkbook.Save 'Attempt to create a new instance of Access Set accApp = Nothing Set accApp = CreateObject("Access.Application") With accApp 'Set the access automation security, 'so the database opens without prompts. 'Use late binding and On Error Resume Next 'to ignore version issues On Error Resume Next Set objApp = accApp objApp.AutomationSecurity = 2 'msoAutomationSecurityLow

On Error GoTo 0 'Open the database .OpenCurrentDatabase FilePath:=ThisWorkbook.Path & _ "\ReportOnExcelData.mdb" 'Get a reference to the DAO TableDef for the 'tblExcelData linked table Set dbData = .CurrentDb Set tdExcelData = dbData.TableDefs("tblExcelData") 'Update the table link to point to this workbook tdExcelData.Connect = "Excel 8.0;HDR=YES;IMEX=2;" & _ "DATABASE=" & ThisWorkbook.FullName Set tdExcelData = Nothing Set dbData = Nothing 'Open and preview the report .DoCmd.OpenReport ReportName:="rptExcelData", _ View:=acViewPreview 'Make the App visible .Visible = True End With 'Clear the variable from memory Set accApp = Nothing End Sub

Word Word is oft en aut om at ed from Excel when we need t o populat e a Word docum ent from dat a in Excelsuch as a m ont hly report t hat cont ains som e dat a analyzed in Excel.

Application As well as t he usual propert ies t o cont rol t he applicat ion it self, t he Word Applicat ion obj ect has a Docum ent s collect ion t hat we use t o creat e, open and access Word docum ent s.

Document The Docum ent obj ect provides all t he inform at ion about a Word docum ent , akin t o Excel's Workbook obj ect .

Bookmark Each bookm ark wit hin a docum ent is included in t he Document.Bookmarks collect ion and exposed as a Bookm ark obj ect . Bookm arks enable us t o easily ident ify elem ent s of t ext wit hin a docum ent .

Range A Range is a cont iguous area in a docum ent , ident ified by it s st art and end point s. Many Word obj ect s ( such as Paragraph and Bookm ark) have a Range propert y t hat ret urns t he area enclosed by t he obj ect . We can populat e a bookm ark by set t ing t he t ext of it s Range. One issue wit h doing t his is t hat set t ing t he t ext in a bookm ark delet es t he bookm ark. To set a bookm ark's t ext , we have t o st ore t he bookm ark's range, set t he t ext of t he range, t hen re- creat e t he bookm ark, as shown in List ing 18- 12.

Example Survey result s are very oft en analyzed in Excel and published as a Word docum ent . This is usually achieved by creat ing a Word t em plat e for t he survey result s, ident ifying each insert ion point as a bookm ark, t hen copying t he dat a from t he Excel workbook t o t he Word docum ent using VBA. I t is quit e com m on in corporat e surveys t o creat e a docum ent specific t o each of t he respondent s, where each report is essent ially t he sam e, but wit h t hat respondent 's result s and rankings. List ing 18- 12 shows a very sim ple exam ple of t his, where we loop t hrough all t he divisions in a com pany, analyzing t he dat a and producing a docum ent for each. This code can be found in t he MWord m odule of t he Ch18Exam ples.xls workbook and t he docum ent t em plat e is called SalaryReport .dot .

List in g 1 8 - 1 2 . Popu la t in g a W or d Te m pla t e fr om Ex ce l D a t a Sub

GenerateDivisionSummaries() Dim Dim Dim Dim Dim Dim Dim

wrdApp As Word.Application wrdDoc As Word.Document wrdrngBM As Word.Range piDiv As Excel.PivotItem rngBookmark As Excel.Range sPath As String sBookmarkName As String

'Start Word Set wrdApp = CreateObject("Word.Application") sPath = ThisWorkbook.Path & "\" 'Create a new document based on the template

Set wrdDoc = wrdApp.Documents.Add(Template:= _ sPath & "SalaryReport.dot") 'Loop through each division in the pivot table For Each piDiv In wksData.PivotTables(1) _ .PivotFields("Division").PivotItems 'Populate the Division Name cell wksData.Range("ptrDivName") = piDiv.Value 'Recalc the sheet to update the results 'for the division wksData.Calculate 'Populate the bookmarks from the sheet For Each rngBookmark In _ wksData.Range("rngBookmarks").Rows 'Get the name of the bookmark sBookmarkName = rngBookmark.Cells(1, 1).Value 'Get the Word Range that the bookmark spans Set wrdrngBM = wrdDoc.Bookmarks(sBookmarkName) _ .Range 'Set the text of the range '(which deletes the bookmark) wrdrngBM.Text = rngBookmark.Cells(1, 2).Text 'Re-create the bookmark for the next iteration wrdDoc.Bookmarks.Add sBookmarkName, wrdrngBM Next rngBookmark 'Update any fields linked to these bookmarks wrdDoc.Fields.Update 'Save the filled document wrdDoc.SaveAs sPath & "Salary Results - " & _ piDiv.Value & ".doc" Next piDiv 'Close the Word document wrdDoc.Close Set wrdDoc = Nothing 'Close Word wrdApp.Quit False Set wrdApp = Nothing End Sub

PowerPoint and MSGraph PowerPoint is usually used in a sim ilar way t o Wordpopulat ing pre- prepared present at ions wit h dat a from Excel.

Application As well as t he usual propert ies t o cont rol t he applicat ion it self, t he PowerPoint Applicat ion obj ect has a Present at ions collect ion t hat we use t o creat e, open and access PowerPoint present at ions.

Presentation The Present at ion obj ect provides all t he inform at ion about a PowerPoint present at ion, akin t o Excel's Workbook obj ect .

Slide The Slide obj ect provides t he inform at ion about a slide wit hin a present at ion, akin t o Excel's Worksheet obj ect . When aut om at ing PowerPoint , it helps t o give each slide a m eaningful nam e, which can be done by select ing t he slide and running t he following st at em ent from t he PowerPoint VBE's I m m ediat e window:

ActiveWindow.Selection.SlideRange(1).Name

=

"NewSlideName"

Shape The Shape obj ect is t he sam e as Excel's Shape obj ect and is a drawing obj ect on a Slide, which can be a cont ainer for t ext boxes, lines, pict ures or em bedded obj ect s such as chart s. A shape can be given a m eaningful nam e by select ing it and running t he following st at em ent from t he PowerPoint VBE's I m m ediat e window:

ActiveWindow.Selection.ShapeRange(1).Name

=

"NewShapeName"

Charts PowerPoint chart s are provided by t he MSGraph obj ect m odel, which is a version of Excel's chart ing engine, m odified t o rem ove t he worksheet links. As such, m ost Excel chart ing code will work on a PowerPoint chart . However, it is quit e com m on t o prepare t he chart s wit hin Excel, copy t hem t o t he clipboard and past e t hem as pict ures in PowerPoint .

Example The procedure in List ing 18- 13 updat es a PowerPoint present at ion wit h dat a from an Excel spreadsheet . I t updat es bot h t ext in a bullet ed list and t he source dat a for an em bedded chart . This code can be found in t he MPowerPoint m odule of t he Ch18Exam ples.xls workbook and t he present at ion we're updat ing is called Salary Present at ion.ppt .

List in g 1 8 - 1 3 . Popu la t in g a Pow e r Poin t Pr e se n t a t ion fr om Ex ce l D a t a Sub

PPTGenerateSalarySummary() 'Powerpoint objects Dim pptApp As PowerPoint.Application Dim pptPres As PowerPoint.Presentation Dim pptSlide As PowerPoint.Slide Dim pptBullets As PowerPoint.Shape 'MSGraph objects Dim gphChart As Graph.Chart Dim gphData As Graph.DataSheet 'Excel objects Dim pfDiv As Excel.PivotField Dim rngDiv As Excel.Range 'Other variables Dim sBulletText As String Dim lDiv As Long 'Start PowerPoint Set pptApp = CreateObject("PowerPoint.Application") 'Switch back to Excel AppActivate Application.Caption 'Open the presentation Set pptPres = pptApp.Presentations.Open(Filename:= _ ThisWorkbook.Path & "\Salary Presentation.ppt", _ withwindow:=False) 'Get the 'Detail' slide Set pptSlide = pptPres.Slides("sldDetail") 'Get the shape containing the bulleted list Set pptBullets = pptSlide.Shapes("shpBullets") 'Get the text of the first bullet in the list

sBulletText = pptBullets.TextFrame.TextRange _ .Paragraphs(1).Text 'Update the text with the calculated total 'from the worksheet sBulletText = Replace(sBulletText, "#SalaryTotal#", _ wksData.Range("ptrSalaryTotal").Text) 'Update the presentation with the correct text pptBullets.TextFrame.TextRange.Paragraphs(1) _ .Text = sBulletText 'Get the MSGraph Chart object embedded in the slide Set gphChart = pptSlide.Shapes("shpChart").OLEFormat _ .Object 'Get the graph's data sheet Set gphData = gphChart.Application.DataSheet 'Get the 'Division' pivot field in the Data worksheet Set pfDiv = wksData.PivotTables(1).PivotFields("Division") 'Loop through the range of Divisions in the pivot table For Each rngDiv In pfDiv.DataRange lDiv = lDiv + 1 'Write the division name and total salary to the 'graph data sheet gphData.Cells(1, lDiv + 1).Value = rngDiv.Text gphData.Cells(2, lDiv + 1).Value = rngDiv _ .Offset(0, 1).Value Next rngDiv 'Apply the datasheet changes gphChart.Application.Update 'Redraw the chart object gphChart.Refresh 'Save the presentation with a new name pptPres.SaveAs ThisWorkbook.Path & "\Salaries 2003.ppt" 'Tidy up object variables Set pptSlide = Nothing Set pptBullets = Nothing Set gphChart = Nothing Set gphData = Nothing 'Close the presentation pptPres.Close Set pptPres = Nothing

'Close PowerPoint pptApp.Quit Set pptApp = Nothing 'Display confirmation message MsgBox "Salary Summary Presentation Generated OK." End Sub

Outlook Out look behaves quit e different ly t o t he rest of t he Office applicat ions. I t only allows one inst ance t o be open at any t im e and doesn't use t he 'docum ent ' concept . I nst ead, it st ores all it s dat a in a single dat a file, represent ed by a Nam espace obj ect . The dat a file is int ernally st ruct ured as m ult iple folders t hat each cont ain a specific cat egory of inform at ion, such as e- m ails, cont act s, appoint m ent s and so on.

Application The Out look Applicat ion obj ect provides access t o t he dat a st ore t hrough t he Get Nam espace propert y and allows us t o easily creat e new dat a it em s ( e- m ails, cont act s, appoint m ent s and so on) using t he Creat eI t em m et hod.

Namespace The Nam espace obj ect represent s an Out look dat a st ore. Out look was originally designed t o support m ult iple t ypes of dat a st ore, but only one was ever im plem ent ed. That is called t he MAPI dat a st ore and is ret rieved using Application.GetNamespace("MAPI"). The Nam espace obj ect act s as a cont ainer for all t he Out look folders, enabling us t o navigat e t he ent ire folder hierarchy. I t also provides t he Get Default Folder( ) propert y t o access each of t he t op- level folders.

MAPIFolder The MAPI Folder obj ect represent s a single Out look folder, such as t he I nbox, Cont act s or Calendar folder. I t has a Folders propert y t hat ret urns a collect ion of child folders, enabling us t o drill down and an I t em s propert y t hat ret urns a collect ion of all t he individual it em s ( e- m ails, cont act s and so on) cont ained in t he folder.

AppointmentItem, ContactItem, DistributionListItem, JournalItem, MailItem, NoteItem, PostItItem and TaskItem These obj ect s represent t he individual it em s wit hin an Out look folder. We can access t hem t hrough t he I t em s collect ion of a MAPI Folder and creat e t hem by using eit her t he Add m et hod of an I t em s

collect ion or t he Creat eI t em m et hod of t he Applicat ion obj ect . I n eit her case, we get an em pt y obj ect of t he appropriat e t ype which we populat e and save t o t he dat a st ore.

Example The procedure shown in List ing 18- 14 ret rieves all t he holidays for a specified year from t he default Out look Calendar, displaying t hem in an Excel worksheet .

List in g 1 8 - 1 4 . Re t r ie vin g H olida y D a t e s fr om t h e Ou t look Ca le n da r Sub

OutlookRetrieveHolidays() 'Outlook objects Dim olApp As Outlook.Application Dim olNS As Outlook.Namespace Dim olItems As Outlook.Items Dim olAppt As Outlook.AppointmentItem Dim bCreated As Boolean Dim lYear As Long Dim lRow As Long 'Obtain a reference to Outlook On Error Resume Next Set olApp = GetObject(, "Outlook.Application") On Error GoTo 0 'If Outlook isn't running, start it and remember If olApp Is Nothing Then Set olApp = CreateObject("Outlook.Application") bCreated = True End If 'Get the MAPI namespace Set olNS = olApp.GetNamespace("MAPI") 'Get the items in the Calendar Set olItems = olNS.GetDefaultFolder(olFolderCalendar) _ .Items 'Clear the destination range if previously used wksOutlook.Range("tblStart").CurrentRegion.ClearContents 'Get the year criteria lYear = wksOutlook.Range("Year").Value 'Set the default row counter lRow = 1

'Loop through the calendar entries For Each olAppt In olItems 'We only want holidays... If olAppt.Categories = "Holiday" Then '... with a title ... If Len(olAppt.Subject) > 0 Then '... that start in the given year ... If Year(olAppt.Start) = lYear Then wksOutlook.Range("tblStart") _ .Cells(lRow, 1).Value = olAppt.Subject wksOutlook.Range("tblStart") _ .Cells(lRow, 2).Value = olAppt.Start lRow = lRow + 1 End If End If End If Next olAppt 'Sort the holidays by date With wksOutlook.Range("tblStart").CurrentRegion .Sort key1:=.Cells(1, 2), order1:=xlAscending, _ Header:=xlNo End With 'Clear intermediate Outlook object variables Set olAppt = Nothing Set olItems = Nothing Set olNS = Nothing 'Close Outlook if we started it If bCreated Then olApp.Quit 'Clear the Outlook application variable Set olApp = Nothing End Sub

Further Reading The Office Developer Cent er on t he MSDN Web sit e should be your first point of call t o learn about program m ing t he Office applicat ions. St art at ht t p: / / m sdn.m icr osoft .com / office/ under st anding/ and click t hrough t o t he applicat ion you're int erest ed in. There have also been num erous books writ t en for each applicat ion, of which t he following are usually considered am ong t he best . All have a 5- st ar rat ing at Am azon.com :

Tit le: Aut hor : Publisher : I SBN:

Access 2002 Deskt op Developer's Handbook Paul Lit win, Ken Get z, Mike Gunderloy Sybex Books 0782140092

Tit le: Aut hor : Publisher : I SBN:

Powerful PowerPoint for Educat ors David M. Marcovit z Libraries Unlim it ed 1591580951

Tit le: Aut hor : Publisher : I SBN:

Microsoft Out look Program m ing Sue Mosher Digit al Press 1555582869

I t seem s t hat t he publishing com m unit y has decided t hat books about program m ing Word do not sell enough t o be profit ablet he lat est edit ions are for Word 2000. The best way t o learn m ore about program m ing Word is t o st art at t he Word MVP Web sit e at ht t p: / / w w w .m v ps.or g/ w or d and follow t he links from t here.

Practical Example I t would be t oo art ificial t o ext end eit her t he PETRAS t im esheet add- in or t he PETRAS report ing applicat ion t o cont rol one or m ore of t he ot her Office applicat ions. Excel's feat ures are sufficient for our analysis and report ing requirem ent s. I f we were t o do so, however, we would use t he procedures shown in List ing 18- 11 t o List ing 18- 14, which should be considered t o be t he pract ical exam ples for t his chapt er.

Conclusion Excel is only one part of t he Office suit e of applicat ions. Alt hough it s dat a handling, word processing and present at ion feat ures are usually sufficient for m any applicat ions, we can oft en add a great deal of value t o our applicat ions by cont rolling som e of t he ot her com ponent s of t he Office suit e. The easiest way t o cont rol t he ot her Office applicat ions is t o have a pre- prepared t em plat e dat abase, docum ent or present at ion t hat we open, m odify and save; all t he exam ples in t his chapt er do exact ly t hat . This chapt er has barely scrat ched t he surface of each applicat ion's obj ect m odel, only describing t he obj ect m odels in sufficient det ail for you t o underst and t he sam ple code and get st art ed using t hem . We can achieve som e im pressive result s wit h only a lit t le knowledge of t he obj ect s, so learning t o aut om at e t he ot her Office applicat ions is not as daunt ing a prospect as it first appears.

Chapter 19. XLLs and the C API This chapt er in no way at t em pt s t o provide a com plet e guide t o program m ing Excel using t he C API . That would be a book- lengt h t opic in it s own right . A skilled C+ + program m er wit h an indept h knowledge of t he Excel C API can creat e add- ins t hat can do anyt hing a VBA add- in can do. I nst ead, t his chapt er focuses on t he core st rengt h of t he C API and what is arguably t he m ost com m on use for it in Excel developm ent : program m ing cust om worksheet funct ions. Even t his t opic is t oo large t o be covered in a single chapt er, so we get you st art ed wit h solid fundam ent als and t hen point you t o addit ional resources at t he end of t he chapt er. All t he exam ples discussed in t his chapt er assum e t hat you are running Microsoft Visual C+ + .NET 2003. The accom panying CD cont ains com plet e versions of t he sam ple proj ect discussed below for bot h VC+ + 6.0 and VC+ + .NET 2003 in t he \ Concept s\ Chapt er 19XLLs and t he C API folder. I f you are unfam iliar wit h C program m ing, you are st rongly advised t o open t he sam ple files and follow along as you read. C is a very verbose program m ing language com pared t o VB/ VBA, so we only have room t o show t he m ost im port ant code cont ained in t he sam ple.

Why Create an XLL-Based Worksheet Function An XLL is a Windows DLL t hat is st ruct ured so Excel can recognize and open it direct ly. Because worksheet funct ions built int o XLLs are com piled t o m achine code and t reat ed by Excel as if t hey were nat ive worksheet funct ions, t hey are ext rem ely fast . You can creat e cust om versions of worksheet funct ions t hat Excel doesn't get quit e right as well as creat ing worksheet funct ions t hat Excel doesn't provide at all. Also, Excel doesn't st ore hard- coded pat hs t o XLL- based worksheet funct ions, so t hey don't suffer from broken links when files are relocat ed like VBA add- in based funct ions do.

Creating an XLL Project in Visual Studio An XLL is j ust a Windows DLL wit h a .xll file ext ension and an int ernal st ruct ure t hat Excel recognizes. Prior t o creat ing your XLL proj ect , you need t o copy t he x lca ll.h and x lca ll3 2 .lib from t he Microsoft Excel 97 SDK int o your Visual St udio include and lib direct ories, respect ively. We're using t he SDK for Excel 97 because t hat was t he last version of Excel for which Microsoft released an SDK. There have been no fundam ent al changes t o t he underlying Excel C API since t he Excel 97 SDK was writ t en, so t his is not a problem . The Excel 97 SDK can be downloaded from ht t p: / / dow nload.m icr osoft .com / dow nload/ ex cel97w in/ I nst all/ 1.0/ W9XNT4XP/ ENUS/ excel97sdk.exe. To creat e your XLL proj ect , choose File > New > Proj ect from t he Visual St udio m enu. I n t he New Proj ect dialog, expand t he Visual C+ + Proj ect s folder on t he left side and select t he Win32 folder. From t he Tem plat es list , select Win32 Console Proj ect . Ent er t he nam e for your XLL in t he Nam e t ext box and select t he locat ion where you want t he proj ect t o be saved. This is shown in Figure 191.

Figu r e 1 9 - 1 . Cr e a t in g t h e I n it ia l XLL Pr oj e ct [View full size image]

Click t he OK but t on and Visual St udio will display t he Applicat ion Wizard dialog box shown in Figure 19- 2. Select Applicat ion Set t ings on t he left side and choose DLL as your Applicat ion t ype. Place a check m ark in t he Em pt y proj ect check box under Addit ional opt ions and click t he Finish but t on. You will now have an em pt y Win32 DLL proj ect .

Figu r e 1 9 - 2 . Ch oosin g t h e Cor r e ct Applica t ion W iza r d Se t t in gs [View full size image]

Next you will add t wo files t o your proj ect . Select File > Add New I t em from t he Visual St udio m enu. I n t he Add New I t em dialog, select C+ + File ( .cpp) from t he Tem plat es list . This will be t he file t hat cont ains your code. Because we are creat ing a C proj ect , you need t o explicit ly give your file a .c ext ension, as shown in Figure 19- 3. The Locat ion set t ing should already be point ing t o your proj ect folder. Leave t his as is.

Figu r e 1 9 - 3 . Addin g a Code File t o You r XLL Pr oj e ct [View full size image]

The next file you need t o add t o your proj ect is a m odule definit ion file. This will enable you t o export funct ion nam es from your XLL t hat Excel can recognize. Select File > Add New I t em from t he Visual St udio m enu again, but t his t im e choose Module- Definit ion File ( .def) from t he list of t em plat es. Give your m odule definit ion file t he sam e nam e as t he .c code file you added above, but wit h a .def file ext ension, as shown in Figure 19- 4.

Figu r e 1 9 - 4 . Addin g a M odu le D e fin it ion File t o You r XLL Pr oj e ct [View full size image]

You need t o m ake several proj ect - level set t ings before you're ready t o st art writ ing code. Choose Proj ect > Sam ple Propert ies from t he Visual St udio m enu ( where Sam ple is t he act ual nam e you select ed for your proj ect ) . I n t he Sam ple Propert y Pages dialog shown in Figure 19- 5, select t he Debugging folder from t he t ree view. Then select t he Com m an d opt ion from t he list of set t ings on t he right side and browse t o t he locat ion of Excel.exe on your com put er. This t ells Visual St udio what program t o use when debugging your XLL.

Figu r e 1 9 - 5 . Spe cifyin g Ex ce l.e x e a s t h e D e bu ggin g Pr ogr a m for You r XLL Pr oj e ct [View full size image]

Then select t he C/ C+ + folder, followed by t he General subfolder from t he t ree view. The first set t ing you need t o change is t he Debug I nform at ion Form at set t ing. The default value for t his set t ing is Program Dat abase for Edit and Cont inue. This value will add debug sym bols t o t he XLL t hat will cause Excel not t o recognize it . Change t his set t ing t o Program Dat abase inst ead. This set t ing is dem onst rat ed in Figure 19- 6.

Figu r e 1 9 - 6 . Spe cifyin g t h e Cor r e ct D e bu g I n for m a t ion For m a t Se t t in g [View full size image]

Then select t he Linker folder, followed by t he General subfolder from t he t ree view. I n t he Out put File set t ing, m anually change t he file ext ension of t he out put filenam e from .dll t o .xll, as shown in Figure 19- 7.

Figu r e 1 9 - 7 . Ch a n gin g t h e Ou t pu t File n a m e Ex t e n sion [View full size image]

Select t he Release ent ry from t he Configurat ions drop- down and repeat t he file ext ension change for t he release build. Finally, choose t he I nput folder from t he Linker sect ion of t he t ree view. Choose t he All Configurat ions ent ry from t he Configurat ions drop- down. Type t he filenam e xlcall32.lib int o t he Addit ional Dependencies set t ing as shown in Figure 19- 8.

Figu r e 1 9 - 8 . Addin g x lca ll3 2 .lib t o t h e Addit ion a l D e pe n de n cie s for You r Pr oj e ct [View full size image]

We've m ade all t he necessary set t ings now, so click t he OK but t on and we'll st art writ ing t he code for our XLL.

The Structure of an XLL We'll st art our discussion by creat ing an XLL t hat cont ains t wo t rivial cust om worksheet funct ions. This will allow us t o concent rat e on t he st ruct ure required t o creat e an XLL independent of what ever worksheet funct ions it happens t o cont ain. We look at an exam ple of a real- world funct ion lat er in t he chapt er. List ing 19- 1 shows t he t wo cust om worksheet funct ions our first XLL will provide.

List in g 1 9 - 1 . Sa m ple Cu st om W or k sh e e t Fu n ct ion s double WINAPI AddTwo(double d1, double d2) { return d1 + d2; } double WINAPI MultiplyTwo(double d1, double d2) { return d1 * d2; }

The Function Table The first t hing you need t o do when creat ing your XLL is build a funct ion t able. This is a t hreedim ensional st ring array holding det ailed descript ions of each of t he cust om worksheet funct ions t hat your XLL cont ains. The funct ion t able will be used t o regist er each cust om worksheet funct ion wit h Excel when t he XLL is opened. The first dim ension of t he t able holds an ent ry for each cust om worksheet funct ion in t he XLL. The second dim ension of t he t able holds all of t he argum ent s t hat will be passed t o t he Regist er funct ion for a given cust om worksheet funct ion. The t hird dim ension of t he t able holds t he st ring values for each argum ent The m axim um allowable lengt h of a Regist er funct ion argum ent st ring is 255 charact ers. You m ust leave a blank space at t he first charact er posit ion of each st ring in t he t able ( even unused st rings) . This is because Excel does not use null- t erm inat ed C st rings but rat her byt e- count ed Pascal st rings. Lat er we will insert a byt e count for each st ring in it s first charact er posit ion. List ing 19- 2 shows t he funct ion t able t hat describes our t wo cust om worksheet funct ions. Not e t hat t he NUM_REGI STER_ARGS const ant m ust be large enough so t he funct ion t able can hold all t he descript ions required for t he cust om worksheet funct ion in t he XLL t hat cont ains t he m ost argum ent s. For cust om worksheet funct ions wit h fewer t han t he m axim um num ber of argum ent s, t he unused argum ent help t opic ent ries at t he end of t he t able can be left em pt y and Excel will ignore t hem . Adj ust m ent s t o t he NUM_REGI STER_ARGS const ant m ust also be reflect ed in t he HandleRegist rat ion funct ion described in t he Regist ering and Unregist ering Cust om Worksheet

Funct ions sect ion lat er in t he chapt er.

List in g 1 9 - 2 . Th e Sa m ple XLL Fu n ct ion Ta ble #define NUM_FUNCTIONS #define NUM_REGISTER_ARGS #define MAX_LENGTH static { {" " " " " " " " " " " }, {" " " " " " " " " " " } };

2 11 255

char gszWorksheetFuncs[NUM_FUNCTIONS][NUM_REGISTER_ARGS][MAX_LENGTH] = AddTwo", BBB", AddTwo", d1, d2", 1", Sample Add-in", ", ", Adds the two arguments.", The first number to add.", The second number to add."

// // // // // // // // // // //

procedure type_text function_text argument_text macro_type category shortcut_text help_topic function_help argument_help1 argument_help2

MultiplyTwo", BBB", MultiplyTwo", d1, d2", 1", Sample Add-in", ", ", Multiplies the two arguments.", The first number to multiply.", The second number to multiply."

The following are brief descript ions of t he purpose and usage of each ent ry in t he funct ion t able in t he order in which t hey appear. We describe how t o act ually regist er your funct ions wit h Excel based on t his inform at ion in t he Regist ering and Unregist ering Cust om Worksheet Funct ions sect ion. procedure This is t he nam e of your cust om worksheet funct ion. I t should be exact ly t he sam e as t he nam e t hat appears in your funct ion definit ion. type_text This is a coded st ring t hat specifies t he dat a t ypes of all t he funct ion's argum ent s as well as it s ret urn value. The first let t er specifies t he ret urn t ype of t he funct ion and all following let t ers specify t he dat a t ypes expect ed by each of t he funct ions argum ent s, from left

t o right . Table 19- 1 list s t he codes for t he m ost com m only used dat a t ypes. For a com plet e list of dat a t ypes, see t he Microsoft Excel 97 SDK, referenced in t he Addit ional Resources sect ion at t he end of t he chapt er.

Ta ble 1 9 - 1 . Th e M ost Com m on ly Use d t ype _ t e x t D a t a Type s Code

D e scr ipt ion

D a t a Type

A

Boolean ( TRUE = 1, FALSE = 0)

short int

B

Float ing point num ber

double

D

Byt e- count ed st ring ( m ax lengt h = 255 char act er s)

unsigned char *

I

Signed 2- byt e int eger

short int

J

Signed 4- byt e int eger

int

K

Array

FP * ( see below)

P

Excel OPER st ruct

OPER *

R

Excel XLOPER st ruct

XLOPER *

Excel norm ally recalculat es worksheet funct ions only when t hey are first ent ered int o a worksheet cell or when one of t heir dependencies changes. You can m ake a cust om worksheet funct ion volat ile by appending an exclam at ion point charact er ( ! ) t o t he end of t hat funct ion's t ype_t ext st ring. Volat ile funct ions are recalculat ed whenever any worksheet cell is recalculat ed. Therefore, you m ust be very careful wit h t hem , because t hey can cause ext rem e degradat ion in recalculat ion perform ance. function_text This is t he nam e of t he funct ion as it will appear in t he Excel Funct ion Wizard. argument_text This t ext st ring enables you t o display a list of argum ent s t hat your funct ion accept s in t he Excel Funct ion Wizard. macro_type This is a num eric value indicat ing t he t ype of t he funct ion. Excel worksheet funct ions always have a m acro t ype of 1. We will m ake use of t he hidden funct ion m acro t ype 0 t o overcom e a bug in unregist ering cust om worksheet funct ions. The last m acro t ype is 2, which defines a funct ion t hat can only be called from an XLM m acro sheet . This funct ion t ype is beyond t he scope of t his chapt er. category Enables you t o specify t he cat egory t hat your funct ion will appear in when viewed in t he Funct ion Wizard. You should always creat e a separat e cat egory for cust om worksheet funct ions so you do not confuse t he user about which funct ions are built - in and which funct ions require your XLL t o be loaded in order t o be used. shortcut_text This is used t o assign a short cut key t o com m and- t ype funct ions. This funct ion

t ype will not be covered here, so t his ent ry can be left em pt y. help_topic I f you have a cust om help file associat ed wit h your XLL, t his will be t he help t opic I D for t his worksheet funct ion. function_help This is a short descript ive help t ext st ring t hat will appear in t he Excel Funct ion Wizard when t he user select s your funct ion. argument_help1 ... 20 This is a short descript ive help t ext st ring t hat will appear in t he Funct ion Wizard when t he user is ent ering dat a for each of your argum ent s. An Excel worksheet funct ion can t ake up t o 29 argum ent s. Unfort unat ely, t he Regist er funct ion, which we discuss lat er, uses t he first nine of it s argum ent s for ot her purposes. Therefore, you can only docum ent t he first 20 argum ent s of any cust om worksheet funct ion. All argum ent s beyond t he 20t h will have an argum ent help st ring t hat is a duplicat e of t hat used for t he 20t h ar gum ent . Not e again t hat every funct ion m ust have exact ly t he sam e num ber of ent ries in t he funct ion t able, so t he funct ion wit h t he m axim um num ber of argum ent s det erm ines t he num ber of funct ion t able ent ries for all t he funct ions in your XLL. I f an argum ent _helpX st ring is not used by a funct ion, leave it em pt y and Excel will ignore it . The K dat a t ype is m ost frequent ly used as a cust om worksheet funct ion argum ent t ype because it is t he nearest t hing in t he Excel C API t o a st rongly t yped array dat a t ype. To use K dat a t ype argum ent s in your XLL, you need t o add t he definit ion for t he FP st ruct shown in List ing 19- 3 t o your code.

List in g 1 9 - 3 . Th e FP St r u ct typedef struct _FP { unsigned short int rows; unsigned short int columns; double array[1]; } FP;

When received as an argum ent , t he array[] m em ber of t he FP st ruct will be sized such t hat it cont ains rows*columns elem ent s.

The DLLMain Function Because an XLL is j ust a variat ion on a st andard Windows DLL, Windows will be expect ing t o find a DLLMain funct ion t o call when it loads t he XLL. I n m ost XLLs, t his funct ion doesn't have t o do anyt hing ot her t han ret urn TRUE. You m ay use t he DLLMain funct ion for any norm al init ializat ion operat ions if you want , but in an XLL it is m ore cust om ary t o use t he xlAut oOpen callback funct ion for t his purpose.

There is one sit uat ion where use of t he DLLMain funct ion m akes m ore sense t han xlAut oOpen. This is when your XLL requires som e crit ical int ernal init ializat ion t o succeed, and if t hat init ializat ion fails you want t o prevent Excel from loading t he XLL. By ret urning FALSE from DLLMain, you can prevent Excel from loading your XLL. I n our sam ple XLL, DLLMain will be em pt y except for a return TRUE; st at em ent , as shown in List ing 19- 4.

List in g 1 9 - 4 . Th e D llM a in Fu n ct ion BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { return TRUE; }

Standard XLL Callback Functions Excel calls t he following t hree funct ions at various t im es during it s use of an XLL. Only t he xlAut oOpen funct ion is st rict ly required, but m ost XLLs will m ake use of all t hree of t hese callback funct ions.

xlAutoOpen The xlAut oOpen funct ion is t he st art up funct ion of your XLL. xlAut oOpen is called whenever: You open t he XLL file from t he Excel File > Open m enu. You load t he XLL as an add- in using t he Tools > Add- ins m enu. The XLL is in t he XLSTART direct ory and is aut om at ically opened when Excel st art s. Excel opens t he XLL for any ot her reason. A m acro calls t he XLM REGI STER( ) funct ion wit h only one argum ent , which is t he nam e of t he XLL. Not e t hat t he xlAut oOpen funct ion will not be called if your XLL is opened from a VBA m acro using t he Workbooks.Open m et hod. This is consist ent wit h t he behavior of VBA add- ins. I f you want t o load your XLL from VBA, use t he Application.RegisterXLL m et hod inst ead. xlAut oOpen should regist er all t he cust om worksheet funct ions in t he XLL and perform any ot her init ializat ion your XLL requires. List ing 19- 5 shows t he xlAut oOpen code for our sam ple XLL. We defer discussion of how t he HandleRegist rat ion funct ion works unt il we've covered t he XLOPER dat a t ype and t he Excel4 funct ion.

List in g 1 9 - 5 . Th e x lAu t oOpe n Fu n ct ion

EXPORT int WINAPI xlAutoOpen(void) { static XLOPER xDLL; int i, j; // In the following loop, the strings in // gszFunctionTable are byte-counted. for (i = 0; i < NUM_FUNCTIONS; ++i) for (j = 0; j < NUM_REGISTER_ARGS; ++j) gszFunctionTable[i][j][0] = (BYTE) lstrlen(gszFunctionTable[i][j] + 1); // Register the functions using our custom procedure. HandleRegistration(TRUE); return 1; }

xlAutoClose The xlAut oClose funct ion is t he shut down funct ion of your XLL. xlAut oClose is called whenever: You quit Excel. You unselect t he XLL from t he add- ins list under t he Tools > Add- ins m enu. xlAut oClose should perform any cleanup operat ions required by your XLL as well as unregist er t he worksheet funct ions it cont ains so t hey no longer appear in t he Funct ion Wizard or t he Past e Funct ions list . Not e t hat if t he user at t em pt s t o exit Excel when t here is an unsaved workbook open, Excel will call t he xlAut oClose funct ion of any open XLLs before prom pt ing t he user t o save changes t o t he unsaved workbook. I f t he user cancels t he save prom pt , Excel and your XLL will rem ain open. This m ay const rain t he am ount of cleanup you can safely do in t he xlAut oClose funct ion in som e circum st ances. List ing 19- 6 shows t he xlAut oClose funct ion for our sam ple XLL. Again, we defer discussion of how t he HandleRegist rat ion funct ion works unt il lat er in t he chapt er.

List in g 1 9 - 6 . Th e x lAu t oClose Fu n ct ion EXPORT int WINAPI xlAutoClose(void) { // Unregister the worksheet functions // using our custom procedure. HandleRegistration(FALSE); return 1;

}

xlAddInManagerInfo The Excel Add- in Manager calls t he xlAddinManagerI nfo funct ion when it loads your XLL in order t o det erm ine t he descript ive st ring t hat it should display for your XLL in t he list of add- ins. This funct ion is not st rict ly required. I f you don't provide it , t he Add- in Manager will use t he filenam e of t he XLL as t he descript ive t ext . However, providing a descript ive nam e for your XLL m akes it m uch easier for users t o locat e. List ing 19- 7 shows t he xlAddinManagerI nfo code for our sam ple XLL. We describe what m ost of t his code is doing in t he sect ions on t he XLOPER dat a t ype and t he Excel4 funct ion.

List in g 1 9 - 7 . Th e x lAddI n M a n a ge r I n fo Fu n ct ion EXPORT LPXLOPER WINAPI xlAddInManagerInfo(LPXLOPER xlAction) { static XLOPER xlReturn, xlLongName, xlTemp; // Coerce the argument XLOPER to an integer. xlTemp.xltype = xltypeInt; xlTemp.val.w = xltypeInt; Excel4(xlCoerce, &xlReturn, 2, xlAction, &xlTemp); // The only valid argument value is 1. In this case we // return the long name for the XLL. Any other value should // result in the return of a #VALUE! error. if(1 == xlReturn.val.w) { xlLongName.xltype = xltypeStr; xlLongName.val.str = "\021Sample XLL Add-in"; } else { xlLongName.xltype = xltypeErr; xlLongName.val.err = xlerrValue; } return &xlLongName; }

Not e how we've m anually byt e- count ed t he descript ive t ext st ring for our XLL using an oct al lengt h prefix, \ 021. This is t he form at in which Excel expect s t o receive all st ring values. Rat her t han using t he C convent ion of relying on t he posit ion of a null charact er wit hin a st ring t o det erm ine it s lengt h, Excel uses t he Pascal convent ion of a num eric prefix specifying t he lengt h of a st ring.

Additional XLL Callback Functions The following funct ions are opt ional and will not be covered in det ail in t his chapt er.

xlAutoRegister Excel will call t he xlAut oRegist er funct ion if an XLM m acro t ries t o regist er one of t he cust om worksheet funct ions cont ained in t he XLL wit hout specifying t he t ype_t ext argum ent . I n t hat case, Excel passes t he nam e of t he funct ion t he XLM m acro t ried t o regist er t o t he xlAut oRegist er funct ion and t he xlAut oRegist er funct ion should fully regist er t he funct ion it was passed. I f t he funct ion nam e passed by Excel is not recognized, xlAut oRegist er should ret urn a # VALUE! error. The prot ot ype for t he xlAut oRegist er funct ion is as follows:

LPXLOPER WINAPI xlAutoRegister(LPXLOPER);

xlAutoAdd The xlAut oAdd funct ion works exact ly like t he xlAut oOpen funct ion except Excel only calls xlAut oAdd when t he Excel Add- in Manager loads t he XLL. The prot ot ype for t he xlAut oAdd funct ion is as follows:

int WINAPI xlAutoAdd(void);

xlAutoRemove The xlAut oRem ove funct ion works exact ly like t he xlAut oClose funct ion except Excel only calls xlAut oRem ove when t he Excel Add- in Manager unloads t he XLL. The prot ot ype for t he xlAut oRem ove funct ion is as follows:

int WINAPI xlAutoRemove(void);

xlAutoFree We discuss t his funct ion in a bit m ore det ail in t he sect ion on t he XLOPER dat a t ype below. Briefly, when your XLL passes an XLOPER cont aining a point er t o a large am ount of m em ory t hat is m anaged by t he XLL, you can t ell Excel t o call t he xlAut oFree funct ion as soon as it is finished wit h t hat XLOPER so t he m em ory it uses can be freed as soon as possible. The prot ot ype for t he xlAut oFree funct ion is as follows:

void WINAPI xlAutoFree(LPXLOPER xlToFree);

The XLOPER and OPER Data Types As you can see from t he definit ions of our t wo sam ple funct ions in List ing 19- 1, you can writ e a cust om Excel worksheet funct ion using not hing but fundam ent al C dat a t ypes. However, any t im e you need t o com m unicat e wit h Excel t hrough it s C API or creat e cust om worksheet funct ions t hat support m ult iple ret urn dat a t ypes or use opt ional argum ent s, you'll need t o m ake use of t he special Excel XLOPER dat a t ype and it s subset OPER. An XLOPER is a st ruct t hat provides all t he st orage perm ut at ions required t o im plem ent t he polym orphic behavior you experience when working wit h cells on an Excel worksheet . The definit ion of t he XLOPER dat a t ype is locat ed in t he xlcall.h file and is reproduced in List ing 19- 8.

List in g 1 9 - 8 . Th e XLOPER D a t a Type typedef struct xloper { union { double num; LPSTR str; WORD bool; WORD err; short int w; struct { WORD count; XLREF ref; } sref; struct { XLMREF far *lpmref; DWORD idSheet; } mref; struct { struct xloper far *lparray; WORD rows; WORD columns; } array; struct { union { short int level; short int tbctrl;

/* /* /* /* /*

xltypeNum */ xltypeStr */ xltypeBool */ xltypeErr */ xltypeInt */

/* always = 1 */ /* xltypeSRef */

/* xltypeRef */

/* xltypeMulti */

/* xlflowRestart */ /* xlflowPause */

DWORD idSheet; } valflow; WORD rw; BYTE col; BYTE xlflow; } flow; struct { union { BYTE far *lpbData; HANDLE hdata; } h; long cbData; } bigdata; } val; WORD xltype; } XLOPER, FAR *LPXLOPER;

/* xlflowGoto */ /* xlflowGoto */ /* xlflowGoto */ /* xltypeFlow */

/* data passed to XL */ /* data returned from XL */

/* xltypeBigData */

// The following additional structs are used to implement // the SRef and Ref XLOPER subtypes. // Describes a single rectangular reference typedef struct xlref { WORD rwFirst; WORD rwLast; BYTE colFirst; BYTE colLast; } XLREF, FAR *LPXLREF; // Describes multiple rectangular references. // This is a variable size structure. // Its default size is 1 reference. typedef struct xlmref { WORD count; XLREF reftbl[1]; // actually reftbl[count] } XLMREF, FAR *LPXLMREF;

At it s sim plest level an XLOPER cont ains t wo pieces of inform at ion: som e kind of dat a and a flag indicat ing what t ype of dat a t hat is. There are 12 possible dat a t ypes an XLOPER can hold. These are represent ed by t he following const ant s defined in t he xlcall.h header file: xltypeNum Used for bot h int eger and float ing point num eric dat a. xltypeStr A byt e- count ed st ring. xltypeBool A boolean value.

xltypeRef An ext ernal cell reference or m ult iple area reference. xltypeErr An error value. xltypeFlow An XLM m acro flow cont rol com m and. xltypeMulti An array of values. xltypeMissing A m issing worksheet funct ion argum ent . xltypeNil An em pt y XLOPER. xltypeSRef A single rect angular cell reference on t he current sheet . xltypeInt A short int . Not com m only used. xltypeBigData Used for persist ent dat a st orage. Due t o space lim it at ions, we only discuss t he m ost frequent ly used XLOPER t ypes. When you receive an XLOPER from Excel, eit her as an argum ent t o a cust om worksheet funct ion or as t he ret urn value from an Excel4 funct ion call ( discussed lat er) , you query t he xlt ype m em ber of t he XLOPER st ruct t o det erm ine what t ype of dat a you are receiving. When you creat e an XLOPER, you set t he xlt ype m em ber t o indicat e what t ype of dat a your XLOPER holds. The following are som e exam ples of XLOPERs you m ight creat e: N u m e r ic da t a : Alt hough t he XLOPER dat a t ype has t wo fields t hat could pot ent ially cont ain num eric dat a, only one is com m only used: xlt ypeNum . This is equivalent t o t he double dat a t ype in C. Because xlt ypeI nt is a short int dat a t ype, it s size const raint s rule it out for m any purposes.

XLOPER xlNum; xlNum.xltype = xltypeNum; xlNum.val.num = 5.5;

St r in g da t a : The key t hing t o rem em ber when using st ring dat a wit h Excel is t hat Excel does not use null- t erm inat ed C st rings. I nst ead, it uses byt e- count ed Pascal st rings. Therefore, you m u st byt e- count any st ring you pass t o Excel and be sure not t o t reat any st ring ret urned from Excel as if it were a C st ring. For st ring lit erals, t he byt e count m ust be provided in oct al form at , as shown in t he following exam ple.

XLOPER xlString; xlString.xltype = xltypeStr; xlString.val.str = "\035This is a byte-counted string";

Er r or va lu e s: One im port ant use of XLOPERs is t o provide your funct ion wit h t he abilit y t o ret urn a norm al value when t he funct ion is used correct ly and an error value when t he funct ion has been used out side of it s expect ed param et ers. An error value is indicat ed by t he t ype xlt ypeErr and t he err field is set t o one of t he following error value const ant s supplied in xlcall.h:

xlerrNull ( # NULL! ) Refers t o t he int ersect ion of t wo ranges t hat don't int ersect . xlerrDiv0 ( # DI V/ 0! ) I ndicat es an at t em pt t o divide by zero or by a blank cell. xlerrValue ( # VALUE! ) I ndicat es an argum ent of t he wrong t ype. xlerrRef ( # REF! ) I ndicat es an invalid cell reference. xlerrName ( # NAME?) I ndicat es a st ring value t hat cannot be recognized as a funct ion or defined nam e. xlerrNum ( # NUM! ) I ndicat es t hat an argum ent value is out of bounds. xlerrNA ( # N/ A) I ndicat es t hat t he funct ion cannot calculat e a valid ret urn value based on t he argum ent s passed t o it . I n t he following exam ple we creat e an XLOPER cont aining a # VALUE! error:

XLOPER xlError; xlError.xltype = xltypeErr; xlError.val.err = xlerrValue;

Ar r a ys: These are som ewhat m ore com plex XLOPERs t hat enable you t o ret urn arrays from your cust om worksheet funct ions, t hereby creat ing cust om array form ulas. I n List ing 19- 9, we creat e an XLOPER cont aining t he array { 1, 2, 3, 4} .

List in g 1 9 - 9 . An XLOPER Con t a in in g a n Ar r a y XLOPER xlArray, xlValues[4]; int i; for (i = 0; i < 4; ++i) { xlValues[i].xltype = xltypeNum; xlValues[i].val.num = i + 1; } xlArray.xltype = xltypeMulti; xlArray.val.array.lparray = &xlValues[0]; xlArray.val.array.rows = 1; xlArray.val.array.columns = 4;

The m ost difficult part of using XLOPERs is deciding whet her t he XLL or Excel is responsible for t he m em ory allocat ed t o t he XLOPER and any dat a it point s t o, as well as det erm ining when and how t his m em ory should be freed. The OPER dat a t ype is a st ruct t hat is a subset of an XLOPER cont aining only value dat a t ypes, not reference dat a t ypes. This m akes it m uch sim pler t o work

wit h because t here is never any m em ory allocat ed t o an OPER t hat needs t o be freed by eit her t he XLL or Excel. As a general rule, if your worksheet funct ion accept s OPER dat a t ypes as argum ent s and uses XLOPER dat a t ypes as ret urn values, your m em ory m anagem ent chores will be m uch sim plified. The definit ion of t he OPER st ruct is not included in t he xlcall.h file and you are not required t o define it in your applicat ion in order t o accept OPER argum ent s t o or ret urn an OPER dat a t ype from your cust om worksheet funct ions. You can sim ply declare your argum ent s and ret urn values as LPXLOPER ( an alias for XLOPER * ) and t hen regist er your funct ion wit h t he code P at t he appropriat e posit ions wit hin t he t ype_t ext argum ent in your funct ion t able. Excel will t hen pass and accept OPER st ruct s even t hough XLOPER st ruct s were specified in your funct ion definit ion. I f you want t o declare and use OPER variables in your XLL, you will need t o add t he OPER st ruct definit ion shown in List ing 19- 10 t o your proj ect .

List in g 1 9 - 1 0 . Th e OPER D a t a Type typedef struct _oper { union { double num; unsigned char *str; unsigned short int bool; unsigned short int err; struct { struct _oper *lparray; unsigned short int rows; unsigned short int columns; } array; } val; unsigned short int type; } OPER;

The Excel4 Function The ent ire breadt h of t he Excel C API is accessed t hrough a single funct ion called Excel4. This funct ion is declared in xlcall.h as follows:

int far _cdecl Excel4(int xlfn, LPXLOPER operRes, int count,... );

As you can see, t he Excel4 funct ion has t hree required param et ers followed by a variable argum ent list . The required param et ers and t heir m eanings are as follows: xlfn This is a const ant t hat ident ifies t he Excel funct ion you are t rying t o call. The values for t his param et er are defined in xlcall.h. There are t hree t ypes of funct ions t hat can be called by t he Excel4 funct ion. C API - only funct ions are ident ified by a const ant wit h a prefix of xl. These will be discussed in t he next sect ion. Excel4 can also call all valid Excel worksheet funct ions. These are ident ified by a const ant wit h an xlf prefix. Finally, all valid XLM m acro com m ands can be called from Excel4. These com m and- equivalent funct ions are ident ified by a const ant wit h t he prefix xlc. We do not cover com m and- equivalent funct ions in t his chapt er. operRes This argum ent t akes eit her t he address of an XLOPER variable in which t he Excel4 funct ion will place t he result of t he funct ion being called, or zero if t he funct ion being called does not have a ret urn value. We address m em ory m anagem ent issues relat ed t o Excel4 XLOPER ret urn values in t he XLOPERs and Mem ory Managem ent sect ion lat er in t he chapt er. count This argum ent is used t o t ell Excel4 how m any opt ional argum ent s follow. The num ber of opt ional argum ent s varies depending on t he specific funct ion being called and can vary from 0 t o 30. All opt ional argum ent s passed t o Excel4 m ust be eit her XLOPER or OPER dat a t ypes. You m ust always rem em ber t o m ake a dist inct ion bet ween t he result of t he funct ion being called by Excel4 and t he result of t he Excel4 funct ion call it self. The form er is cont ained in t he operRes param et er of t he Excel4 funct ion, whereas t he lat t er is t he int ret urn value of t he Excel4 funct ion. All possible ret urn values from Excel4 are represent ed by const ant s defined in xlcall.h. Most of t hese ret urn values will not be encount ered aft er you've debugged your XLL. Som e of t hem are out side t he scope of t his chapt er. A brief descript ion of t he Excel4 funct ion ret urn value const ant s follow s: xlretSuccess The Excel4 funct ion call succeeded. This does not m ean t he funct ion being called by Excel4 succeeded. You det erm ine t hat by checking t he operRes argum ent for an error dat a t ype. xlretAbort An int ernal abort occurred. A discussion of t his ret urn value is out side t he scope of t his chapt er.

xlretInvXlfn The funct ion num ber supplied as an argum ent t o t he XLFN param et er was an invalid funct ion num ber. I f you use only t he predefined funct ion const ant s supplied by xlcall.h, you should not encount er t his error. xlretInvCount Your Excel4 funct ion call did not supply t he correct num ber of argum ent s for t he funct ion it specified in t he xlfn argum ent . xlretInvXloper An invalid XLOPER was passed t o one of t he Excel4 funct ion argum ent s or a valid XLOPER cont aining an incorrect dat a t ype was passed. xlretStackOvfl A st ack overflow occurred. A discussion of t his ret urn value is out side t he scope of t his chapt er. xlretFailed An XLM com m and- equivalent funct ion call failed. A discussion of t his ret urn value is out side t he scope of t his chapt er. xlretUncalced An at t em pt was m ade t o dereference a cell t hat has not been calculat ed yet . I f you ever encount er t his error, your funct ion m ust exit im m ediat ely. Excel will call your funct ion again when t he cell in quest ion has been calculat ed.

Commonly Used C API Functions The funct ions list ed below can only be called from wit hin an XLL using t he Excel4 funct ion. They are not available from wit hin Excel. This is not a com plet e list of t hese funct ions, only t hose t hat apply m ost com m only t o cust om worksheet funct ion proj ect s.

xlFree The xlFree funct ion is used t o t ell Excel you are finished wit h t he cont ent s of an XLOPER variable Excel has allocat ed t he m em ory for and t hat Excel is now free t o reclaim t hat m em ory. The xlFree funct ion t akes one or m ore XLOPER variables as param et ers t o be freed and does not ret urn a value t o t he operRes param et er of t he Excel4 funct ion. We discuss XLOPER m em ory m anagem ent in t he next sect ion, but for now, here's t he basic synt ax of an xlFree funct ion call:

XLOPER xlToBeFreed; // Do something here that causes Excel to allocate // the xlToBeFreed variable. Excel4(xlFree, 0, 1, xlToBeFreed);

xlCoerce The xlCoerce funct ion is used t o convert XLOPER st ruct s from one dat a t ype t o anot her. For exam ple, you can m ake a cust om worksheet funct ion m ore robust by using xlCoerce t o explicit ly convert t o a num eric value what ever is passed t o an XLOPER param et er t hat expect s a num eric value. The need for t his would arise if t he user ent ered som et hing sim ilar t o t he following for a funct ion whose param et er expect ed a num eric dat a t ype:

=MYFUNC("100")

The default behavior of xlCoerce is t o convert a cell reference t o any nonreference t ype, in effect looking up t he value of a cell t hat an XLOPER point s t o. The synt ax of an xlCoerce call looks like t he follow ing:

XLOPER xlResult, xlType; xlType.xltype = xltypeInt; xlType.val.w = xltypeNum; Excel4(xlCoerce, &xlResult, 2, pxlInput, &xlType);

The xlCoerce funct ion t akes t wo argum ent s: pxlInput A point er t o an XLOPER ( LPXLOPER) t hat cont ains t he value or reference t o be convert ed. xlType A point er t o an XLOPER of t ype xlt ypeI nt whose val.w m em ber cont ains a bit m ask of t ypes you are willing t o accept . This argum ent is opt ional. I f it is not provided, xlCoerce will convert t he pxlI nput reference argum ent int o t he closest possible dat a t ype associat ed wit h t he value in t he referenced cell.

xlGetName The xlGet Nam e funct ion ret urns t he full pat h nam e and filenam e of your XLL. As you will see in t he Regist ering and Unregist ering Cust om Worksheet Funct ions sect ion, t his inform at ion is required t o regist er and unregist er t he cust om worksheet funct ions in an XLL.

XLOPERs and Memory Management Excel allocat es and frees any argum ent s passed t o a cust om worksheet funct ion. For m ost XLOPER ret urn values, you pass Excel a st at ic XLOPER variable. Your XLL m ust allocat e any argum ent s passed t o t he Excel4 funct ion. When a call t o t he Excel4 funct ion ret urns an XLOPER cont aining a point er, t hat m em ory is allocat ed and m anaged by Excel. You m ust call t he xlFree funct ion on t hat XLOPER so Excel can free it s m em ory. You can safely call xlFree on every ret urn value from t he Excel4 funct ion. Calling xlFree on an XLOPER t hat does not cont ain a point er does not hing, and if xlFree is called t wice on t he sam e XLOPER Excel ignores t he second call. Excel support s t wo special m em ory m anagem ent bit s in t he xlt ype field of t he XLOPER dat a t ype. I f you need t o use an XLOPER as t he ret urn value of a worksheet funct ion, but t hat XLOPER it self was ret urned from Excel via t he Excel4 funct ion, you set t he xlbit XLFree bit in t he xlt ype field of t he XLOPER. When you do t his, Excel copies out t he dat a it needs and t hen frees t he XLOPER for you, relieving you of t he requirem ent t o call xlFree on t he XLOPER. Sim ilarly, if you set t he xlbit DLLFree bit in t he xlt ype field of an XLOPER, Excel copies t he dat a it requires out of t he XLOPER and t hen calls t he xlAut oFree funct ion in your XLL, passing it a point er t o t he XLOPER. Your XLL can t hen free any m em ory it allocat ed for t his XLOPER. This is useful for ret urning large am ount s of dat a t o Excel wit hout being required t o have t he m em ory for it rem ain allocat ed indefinit ely.

N OTE Do not m odify any XLOPER m anaged by Excel. This includes worksheet funct ion argum ent s and ret urn values from t he Excel4 funct ion. Copy t he dat a int o your own m em ory area if you need t o work wit h it . Rem em ber t hat Excel does not use nullt erm inat ed C st rings, so if you copy a st ring value from an XLOPER ret urned by Excel you m ust copy it charact er by charact er int o a new char array for t he num ber of charact ers specified in t he first byt e of t he XLOPER st ring.

Registering and Unregistering Custom Worksheet Functions For Excel t o recognize t he cust om worksheet funct ions in your XLL, you m ust regist er t hem . This is accom plished by using t he apt ly nam ed Regist er funct ion. Conversely, when your XLL is unloaded it m ust rem ove it s funct ion regist rat ions so t hat Excel will no longer display t hem in t he list of available funct ions. As you saw in t he xlAut oOpen and xlAut oClose funct ions, we've creat ed a special- purpose funct ion called HandleRegist rat ion t o m anage t he regist ering and unregist ering of our cust om worksheet funct ions. Pass TRUE t o t he funct ion and it will regist er all of t he cust om worksheet funct ions specified in t he funct ion t able wit h Excel. Pass FALSE t o t he funct ion and it will unregist er all t he cust om worksheet funct ions. The definit ion of t he HandleRegist rat ion funct ion is shown in List ing 19- 11.

List in g 1 9 - 1 1 . Th e H a n dle Re gist r a t ion Fu n ct ion //////////////////////////////////////////////////////////////// // Comments: This function handles registering and // unregistering all of the custom worksheet // functions specified in our function table. // // Parameters: bRegister [in] Pass TRUE to register all the // custom worksheet functions or FALSE // to unregister them. // // Returns: No return. // static void HandleRegistration(BOOL bRegister) { XLOPER xlXLLName, xlRegID, xlRegArgs[NUM_REGISTER_ARGS]; int i, j; // Get the filename of the XLL by calling xlGetName. Excel4(xlGetName, &xlXLLName, 0); // All of the XLOPER arguments passed to the Register // function will have the type xltypeStr. for (i = 0; i < NUM_REGISTER_ARGS; ++i) xlRegArgs[i].xltype = xltypeStr; for (i = 0; i < NUM_FUNCTIONS; ++i) {

// Load the XLOPER arguments to the Register function. for(j = 0; j < NUM_REGISTER_ARGS; ++j) xlRegArgs[j].val.str = gszFunctionTable[i][j]; if (TRUE == bRegister) { // Register each function. // NOTE: The number of xlRegArgs[] arguments passed // here must be equal to NUM_REGISTER_ARGS - 1. Excel4(xlfRegister, 0, NUM_REGISTER_ARGS + 1, &xlXLLName, &xlRegArgs[0], &xlRegArgs[1], &xlRegArgs[2], &xlRegArgs[3], &xlRegArgs[4], &xlRegArgs[5], &xlRegArgs[6], &xlRegArgs[7], &xlRegArgs[8], &xlRegArgs[9], &xlRegArgs[10]); } else { // Unregister each function. // Due to a bug in Excel's C API this is a 3-step // process. Thanks to Laurent Longre for discovering // the workaround described here. // Step 1: Redefine each custom worksheet function // as a hidden function (change the macro_type // argument to 0). xlRegArgs[4].val.str = "\0010"; // Step 2: Re-register each function as a hidden // function. // NOTE: The number of xlRegArgs[] arguments passed // here must be equal to NUM_REGISTER_ARGS - 1. Excel4(xlfRegister, 0, NUM_REGISTER_ARGS + 1, &xlXLLName, &xlRegArgs[0], &xlRegArgs[1], &xlRegArgs[2], &xlRegArgs[3], &xlRegArgs[4], &xlRegArgs[5], &xlRegArgs[6], &xlRegArgs[7], &xlRegArgs[8], &xlRegArgs[9], &xlRegArgs[10]); // Step 3: Unregister the now hidden function. // Get the Register ID for the function. // Since xlfRegisterId will return a non-pointer // type to the xlRegID XLOPER, we do not need to // call xlFree on it. Excel4(xlfRegisterId, &xlRegID, 2, &xlXLLName, &xlRegArgs[0]); // Unregister the function using its Register ID. Excel4(xlfUnregister, 0, 1, &xlRegID); } } // Since xlXLLName holds a pointer that is managed by Excel, // we must call xlFree on it. Excel4(xlFree, 0, 1, &xlXLLName); }

Regist ering a cust om worksheet funct ion wit h Excel is very st raight forward. You j ust get t he nam e of your XLL by calling t he xlGet Nam e funct ion, and t hen loop t he funct ions in t he funct ion t able and call t he xlfRegist er funct ion for each one, passing t he XLL nam e as t he first argum ent and all t he funct ion t able ent ries as successive argum ent s. Unregist ering your funct ions requires a bit m ore work. Theoret ically, you should sim ply be able t o call t he xlfUnregist er funct ion, passing it t he Regist er I D of each worksheet funct ion you want t o unregist er. Due t o a bug in t he xlfUnregist er funct ion, however, t his will not rem ove t he nam es of your funct ions from t he Excel funct ion t able. They will cont inue t o display in t he Funct ion Wizard even t hough t hey are no longer available. XLL guru Laurent Longre ( see Web sit e reference at t he end of t his chapt er) discovered a workaround for t his bug. I t involves changing t he m acro_t ype of each funct ion t o 0, or hidden, reregist ering each funct ion as a hidden funct ion, t hen unregist ering t he hidden funct ions. Because hidden funct ions are not displayed in t he Excel UI , t his has t he effect of correct ly rem oving t hem when your XLL exit s.

Sample Application Function For our real- world exam ple funct ion, we'll creat e a new worksheet funct ion called I FERROR. As not ed in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins, we oft en encount er t he following worksheet funct ion const ruct :

=IF(ISERROR(),

0,

)

This is t edious and unwieldy, so we creat ed a user- defined funct ion in VBA t hat enabled us t o accom plish exact ly t he sam e t hing wit h t he following:

=IFERROR(,

0)

I n t his sect ion we rewrit e our I FERROR funct ion in C. This will dram at ically im prove it s perform ance because it will be com piled t o nat ive code and be able t o com m unicat e direct ly wit h Excel t hrough t he Excel C API . Our C I FERROR funct ion has t he definit ion shown in List ing 19- 12.

List in g 1 9 - 1 2 . Th e I FERROR Fu n ct ion //////////////////////////////////////////////////////////////// // Comments: This function provides a short-cut replacement // for the common worksheet function construct: // =IF(ISERROR(),0,) // // Arguments: ToEvaluate [in] A value, expression or cell // reference to be evaluated. // Default [in] A value, expression or cell // reference to be returned if the // ToEvaluate argument evaluates to an // error condition. // // Returns: ToEvaluate if not an error, Default otherwise. // EXPORT LPXLOPER IFERROR(LPXLOPER ToEvaluate, LPXLOPER Default) { int IsError = 0; XLOPER xlResult; static XLOPER xlBadArgErr;

// This is the return value for bad or missing arguments. xlBadArgErr.xltype = xltypeErr; xlBadArgErr.val.err = xlerrValue; // Check for missing arguments. if ((xltypeMissing == ToEvaluate->xltype) || (xltypeMissing == Default->xltype)) return &xlBadArgErr; switch (ToEvaluate->xltype) { // The first four all indicate valid ToEvaluate types. // Drop out and use ToEvaluate as the return value. case xltypeNum: case xltypeStr: case xltypeBool: case xltypeInt: break; // A cell reference must be dereferenced to see what it // contains. case xltypeSRef: case xltypeRef: if (xlretUncalced == Excel4(xlCoerce, &xlResult, 1, ToEvaluate)) // If we're looking at an uncalculateded cell, // return immediately. Excel will call this // function again once the dependency has been // calculated. return 0; else { if (xltypeMulti == xlResult.xltype) // Multi-cell arguments are not permitted. return &xlBadArgErr; else if (xltypeErr == xlResult.xltype) // ToEvaluate is a single cell containing an // error. Return Default instead. IsError = 1; } // ToEvaluate is returned for all other types. // Always call xlFree on the return value from // Excel4. Excel4(xlFree, 0, 1, &xlResult); break; case xltypeMulti: // This function does not accept array arguments. return &xlBadArgErr; break; case xltypeErr: // ToEvaluate is an error. Return Default instead. IsError = 1; break;

default: return &xlBadArgErr; break; } if (IsError) return Default; else return ToEvaluate; }

The addit ional funct ion t able ent ry required t o regist er t his funct ion wit h Excel is shown in List ing 19- 13.

List in g 1 9 - 1 3 . Fu n ct ion Ta ble En t r y for t h e I FERROR Fu n ct ion {" " " " " " " " "

IFERROR", RRR", IFERROR", ToEvaluate, Default", 1", Sample Add-in", ", ", If the first argument is an error value, the second " "argument is returned. Otherwise the first argument " "is returned.", " The argument to be checked for an error condition.", " The value to return if the first argument is an error."

}

Debugging the Worksheet Functions I n t he course of writ ing cust om worksheet funct ions, you will need t o do som e debugging in order t o fix errors and prove t hat your funct ion is operat ing as int ended. This is very easy t o do. Because we have already specified Excel.exe as our debug execut able, all t hat 's required is t o com pile your XLL using t he Build > Build Solut ion m enu, put a break point som ewhere in your funct ion and press F5 t o st art debugging. Visual St udio will st art Excel for you. The first t im e you do t his you'll be prom pt ed wit h t he warning dialog shown in Figure 19- 9.

Figu r e 1 9 - 9 . Th e Fir st - Tim e Ex ce l.e x e D e bu g W a r n in g D ia log

This is j ust t elling you t hat you won't be able t o debug Excel it self because t here's no debugging inform at ion available. Because t hat 's not what we're t rying t o do here, you can safely check t he Do not prom pt in t he fut ure check box and click OK t o cont inue. When Excel is open, you will have t o m ake sure your XLL is also open inside Excel. This does not happen aut om at ically. You can open your XLL in one of t wo ways. Eit her use t he File > Open m enu t o open t he XLL direct ly, or add t he XLL t o t he list of add- ins t hat Excel loads aut om at ically on st art up. The second m et hod is t he preferred m et hod for use over m ult iple debugging sessions. To do t his, choose Tools > Add- ins from t he Excel m enu t o display t he Add- ins dialog. Click t he Browse but t on on t he Add- ins dialog and use t he Browse window t o point Excel at your XLL. I f you have bot h debug and release versions of your XLL, be sure t o point Excel at t he debug version. Click OK t wice and your XLL will be loaded. Now all you need t o do is ent er your cust om worksheet funct ion int o a worksheet cell. As soon as code execut ion reaches your break point it will st op and you can begin debugging your code.

Miscellaneous Topics A Caution for Users of COM Automation A funct ion t hat is defined in an XLL can be called in t hree sit uat ions:

1 . During t he recalculat ion of a workbook 2 . As a result of Excel's Funct ion Wizard being called t o help wit h t he XLL funct ion 3 . As a result of a VBA m acro calling Excel's Application.Run m et hod Under t he first t wo circum st ances, Excel's obj ect m odel does not expect and is not prepared for incom ing Aut om at ion calls. Unexpect ed result s or crashes m ay occur if you use COM Aut om at ion under t hese circum st ances.

C++ Keyword Clash with the XLOPER Definition To com pile xlcall.h in a C+ + proj ect ( as opposed t o t he C proj ect dem onst rat ed here) using a st andards- com pliant C+ + com piler ( such as VC.NET) , you m ust add t he following wrapper around t he xlcall.h include. This is because t he bool variable nam e used in t he XLOPER st ruct definit ion is now a C+ + keyword.

#define bool boolean #include "xlcall.h" #undef bool

Additional Resources The Excel 97 SDK on MSDN An ext ensive resource on creat ing XLLs using plain C code, t he Excel 97 SDK covers a m uch wider variet y of t opics t han t his chapt er. I n addit ion, t he source files t hat go wit h it include a handy fram ework for easing som e of t he repet it ive chores involved in building an XLL. Just not e t hat in a num ber of places, t his fram ework at t em pt s t o direct ly m odify st ring lit eral values. This is undefined behavior in C+ + and t herefore you m ust m odify t hese inst ances t o use char arrays inst ead. The t ext of t he Excel 97 SDK can be found in t he MSDN library at ht t p: / / m sdn.m icr osoft .com / libr ar y / . Under : Office Solut ions Developm ent Microsoft Office Microsoft Office 97 Product Docum ent at ion Excel Microsoft Excel 97 Developer's Kit You can find t he files t hat go wit h t he SDK at ht t p: / / dow nload.m icr osoft .com / dow nload/ ex cel97w in/ I nst all/ 1.0/ W9XNT4XP/ ENUS/ excel97sdk.exe.

Excel Add-in Development in C/C++: Applications in Finance Aut hored by St eve Dalt on I SBN 0470024690Wiley An excellent book- lengt h discussion on creat ing XLLs in C and C+ + , t his t it le is highly recom m ended for anyone who want s t o pursue t his t opic furt her.

William Hooper's Web Site ht t p: / / w w w .w hooper .co.uk / ex celst uff.ht m Excellent discussion and exam ples on various advanced XLL t opics.

Laurent Longre's Web Site (French Only) ht t p: / / longr e.fr ee.fr / More excellent discussion of XLL creat ion for t hose who can read French.

The Microsoft Excel Public Newsgroups Point your newsreader t o m snew s.m icr osoft .com . You'll find expert s in a wide array of t opics willing t o answer your quest ions for no charge. Most discussions relat ed t o XLL developm ent will be found in t he microsoft.public.excel.programming and microsoft.public.excel.sdk newsgroups. The microsoft.public.vc.language newsgroup is t he best choice for C/ C+ + specific quest ions.

Planatech XLL+ ht t p: / / w w w .as- lt d.co.uk / m ain/ I f you develop any significant num ber of XLLs, you owe it t o yourself t o buy a copy of XLL+ . This is absolut ely t he best obj ect - orient ed XLL developm ent fram ework available. I t elim inat es all t he grunt work involved in creat ing XLLs and provides m any advanced feat ures in an easily accessible form at . I n addit ion, t he help file for XLL+ , alt hough specific t o t he XLL+ developm ent fram ework, is probably t he best basic XLL developm ent t ut orial available. ( Not e: The aut hors have no financial incent ive for t his recom m endat ion, it is based purely on t he m erit s of t he product .)

Keith Lewis' Freeware Object-Oriented C++ Wrapper for the Excel C API ht t p: / / sour cefor ge.net / pr oj ect s/ xll An open source im plem ent at ion of an obj ect - orient ed wrapper for t he Excel C API .

ManagedXLL ht t p: / / m anagedx ll.net Sim ilar t o Planat ech XLL+ but designed t o work specifically wit h t he .NET program m ing languages.

Conclusion Aft er you've writ t en a few user- defined funct ions in VBA, you cannot help but not ice t hat t hey do awful t hings t o your calculat ion perform ance. Convert ing your VBA user- defined funct ions int o C or C+ + based XLLs will solve t his perform ance problem . Well- writ t en XLL funct ions exhibit calculat ion perform ance t hat is indist inguishable from nat ive Excel worksheet funct ions. I f you need userdefined funct ions and calculat ion speed is im port ant , t ake t he t im e t o learn how t o program XLLs. The result s will be well wort h t he effort .

Chapter 20. Combining Excel and Visual Basic 6 Before we begin t his chapt er, we m ust not e t hat Visual Basic 6 is no longer sold by Microsoft . I t s place has been t aken by VB.NET, which is a very different program m ing language despit e t he sim ilarit y of it s nam e t o VB6. However, VB6 is st ill widely used by working program m ers all over t he world. VBA is t he prim ary program m ing language for all current versions of Excel and it will cont inue t o be so for som e t im e t o com e. VBA and VB6 are very closely relat ed and work very well t oget her, so t he case for using VB6 t o ext end t he powers of VBA is st ill a st rong one. I f you do not already have a copy of VB6, it m ay be difficult t o locat e one. Check online auct ion sit es such as E- bay. Many used bookst ores also sell used soft ware, so t hose m ay be anot her good place t o find a copy of VB6. You can t hink of VB6 as t he m ore powerful big brot her t o VBA. I t has a num ber of capabilit ies t hat VBA does not , including t he abilit y t o generat e t ruly com piled code in t he form of DLLs or st andalone execut able files, a m ore powerful form s package, superior obj ect - orient ed program m ing capabilit ies, support for resource libraries, and Clipboard, Print er and Screen obj ect s am ong ot hers. All of t hese feat ures can be easily and t ight ly int egrat ed wit h your VBA proj ect s wit h no loss of perform ance. I n fact you will see a gain in perform ance in som e cases due t o t he fact t hat VB6 code is t ruly com piled, rat her t han being int erpret ed like VBA. I n t his chapt er we show you how t o get st art ed com bining VB6 and Excel and cover t he m ost com m on reasons why you would want t o ext end your VBA proj ect s wit h VB6. Keep in m ind t hat VB6 is yet anot her t opic t hat would require an ent ire book t o cover properly, so we focus very narrowly on j ust t he VB6 feat ures you would be m ost likely t o use in conj unct ion wit h your Excel applicat ions.

A Hello World ActiveX DLL VB6 can be used t o creat e m ore t han half a dozen different t ypes of applicat ion, but t he only t wo t hat are t ypically used in conj unct ion wit h Excel are Act iveX DLLs and St andard EXEs. I n t his sect ion we int roduce you t o using VB6 Act iveX DLLs from Excel wit h a sim ple Hello World applicat ion. We cover t he basics of com bining Excel and VB6 EXEs in t he Aut om at ing Excel from a VB6 EXE sect ion lat er in t he chapt er. The first it erat ion of our Hello World Act iveX DLL dem onst rat es one- way com m unicat ion only, from Excel t o t he DLL. We t hen ext end t he exam ple in t he second it erat ion t o dem onst rat e t wo- way com m unicat ion. Excel will com m unicat e wit h t he DLL and t he DLL will com m unicat e back t o Excel. I n t he t hird it erat ion we dem onst rat e how t o show a VB6 form in Excel as if it were a nat ive userform . I n t his way, wit hout com plicat ing t he exam ple wit h any advanced feat ures, you will see j ust how easy it is t o creat e and use all t he basic feat ures of a VB6 Act iveX DLL from Excel. Lat er sect ions of t he chapt er show how t o add nont rivial VB6 feat ures t o t he base t hat we build in our Hello World applicat ion. The com plet e set of files for t his exam ple is locat ed on t he CD in t he \ Concept s\ Ch20Com bining Excel and Visual Basic 6\ HelloWorld folder.

Creating an ActiveX DLL Project When you first open VB6 you are present ed wit h t he New Proj ect dialog shown in Figure 20- 1. I f you have used VB6 in t he past and configured it not t o display t his dialog on st art up, you can access it from t he File > New Proj ect m enu.

Figu r e 2 0 - 1 . Th e VB6 N e w Pr oj e ct D ia log

As shown in Figure 20- 1, we will be select ing t he Act iveX DLL proj ect t ype. Aft er you have select ed t his proj ect t ype, click t he Open but t on and VB6 will creat e a new Act iveX DLL proj ect for you. I n it s sim plest form , which is t he form we will be using in t he first it erat ion of our Hello World applicat ion, an Act iveX DLL consist s of only t wo part s: a proj ect and a class m odule. The proj ect det erm ines t he applicat ion nam e of your DLL, and t he class m odule exposes t he feat ures of your DLL t o ot her program s. Figure 20- 2 shows t he st ruct ure of a newly creat ed Act iveX DLL proj ect as seen in t he Proj ect window.

Figu r e 2 0 - 2 . A N e w ly Cr e a t e d Act ive X D LL Pr oj e ct

I f t his Proj ect window appears fam iliar, it 's no accident . You will find t hat t he VB6 developm ent environm ent and t he VBA developm ent environm ent are so sim ilar t hat it 's easy t o confuse t hem . This also m akes it very easy t o work wit h VB6 if you already have experience wit h VBA. We'll use t he Propert ies window in VB6 t o provide friendly nam es for our proj ect and class m odule in exact ly t he sam e way we would do it in VBA. I nst ead of Proj ect 1, we'll give our proj ect t he nam e AFirst Proj ect . I nst ead of Class1, we'll give our class m odule t he nam e CHelloWorld. We t hen save t he proj ect . The result is shown in Figure 20- 3.

Figu r e 2 0 - 3 . Th e Com pon e n t N a m e s for t h e H e llo W or ld Pr oj e ct

Not ice t hat aft er we have saved t he VB6 proj ect , a filenam e appears in parent hesis beside each of t he friendly nam es of our com ponent s. This is one exam ple of t he difference bet ween VBA and VB6. I n VBA, all com ponent s of a proj ect are st ored wit hin a single file. I n t he case of an Excel applicat ion t hey are st ored wit hin t he file st ruct ure of t he workbook in which t hey're locat ed. I n

VB6, all com ponent s are st ored as separat e t ext files in t he direct ory in which you saved t he proj ect . ( Cert ain obj ect s such as form s and resource files have binary files associat ed wit h t hem , but t his det ail isn't im port ant for t he purposes of our discussion.)

The Simplest CaseOne-Way Communication Now t hat we have t he skelet on of an Act iveX DLL proj ect com plet ed, let 's add som e code t o m ake it do som et hing. For t he first it erat ion of our Hello World proj ect t he DLL will do not hing m ore t han display a m essage box wit h t he capt ion " Hello World! " when prom pt ed. This is accom plished by adding a m et hod t o our class m odule t hat displays t he m essage box when called. Adding a m et hod t o a VB6 class m odule is done in exact ly t he sam e way as adding a m et hod t o a VBA class m odule. Just open t he class m odule and add t he code shown in List ing 20- 1.

List in g 2 0 - 1 . Th e Sh ow M e ssa ge M e t h od Public Sub ShowMessage() MsgBox "Hello World!" End Sub

That 's it ! Wasn't t hat easy? Now all we need t o do is com pile our Act iveX DLL and call it from an Excel applicat ion t o display it s m essage. Before you can use a VB6 proj ect you m ust com pile it . This is accom plished t hrough t he use of t he File > Make AFirst Proj ect .dll m enu, as shown in Figure 20- 4. The AFirst Proj ect .dll port ion of t his m enu nam e will differ depending on t he nam e and t ype of t he proj ect you are com piling.

Figu r e 2 0 - 4 . Usin g t h e File > M a k e M e n u t o Com pile t h e D LL

Aft er you have com piled your DLL you will find a file nam ed AFirst Proj ect .dll in t he direct ory in which you saved your proj ect . This is t he com piled, execut able form of all t he files in t he proj ect com bined. So how do we use t his from Excel? I t 's so easy t hat if you have never done it before you will be am azed. The first st ep is t o creat e a new workbook and save it as Book1.xls t o t he sam e direct ory as your VB6 proj ect . Saving t he workbook t o t his locat ion is not a requirem ent ; it j ust m akes t hings

sim pler by keeping all t he files for t he exam ple in one place. I n realit y, t he DLL could be used by any Excel applicat ion anywhere on your com put er. Next , open t he VBE from Excel and insert one st andard code m odule. Before we can st art adding code t o call our DLL we need t o t ell VBA where t o find it . This is done using t he Tools > References m enu in t he VBE. As m ent ioned previously, t he nam e of your proj ect serves as it s applicat ion nam e. Therefore, t he nam e of t he reference you need t o add is t he sam e as t he nam e of your VB6 proj ect , in t his case, AFirst Proj ect . Figure 20- 5 shows t he VBA References dialog wit h t he AFirst Proj ect DLL reference select ed. Not e t hat t he pat h shown in t he Locat ion list ing at t he bot t om of t he References dialog will reflect t he locat ion where t he DLL was com piled on your com put er, so it will be different from t he pat h shown in t he figure.

Figu r e 2 0 - 5 . Re fe r e n cin g t h e AFir st Pr oj e ct D LL fr om Ex ce l

Aft er you have set a reference t o t he DLL, you can use it exact ly like you would use any ot her out side obj ect referenced from Excel. To dem onst rat e our DLL, we creat e a sim ple ShowDLLMessage procedure in t he st andard m odule of our Excel workbook. The com plet e code for t his procedure is shown in List ing 20- 2.

List in g 2 0 - 2 . Th e Sh ow D LLM e ssa ge Pr oce du r e Public Sub ShowDLLMessage() Dim clsHelloWorld As AFirstProject.CHelloWorld Set clsHelloWorld = New AFirstProject.CHelloWorld clsHelloWorld.ShowMessage Set clsHelloWorld = Nothing End Sub

That 's all t here is t o it ! Not ice t hat like we have done in several previous chapt ers, we referenced our DLL class here using a t wo- part not at ion: Applicat ionNam e.ClassNam e. This uniquely ident ifies t he class we want t o use and prevent s any confusion t hat m ight arise from t wo referenced applicat ions sharing t he sam e class nam e. When you run t he ShowDLLMessage procedure, t he m essage box in Figure 20- 6 will display.

Figu r e 2 0 - 6 . Th e H e llo W or ld! M e ssa ge fr om Ou r Act ive X D LL

An int erest ing side not e dem onst rat ed by Figure 20- 6 is t he t ext displayed in t he t it le bar of t he m essage box. I f you don't supply a t it le of your own, t he t ext displayed in t he t it le bar of a m essage box by default will be t he nam e of t he applicat ion t hat displayed it . For exam ple, if you displayed a m essage box from Excel wit hout specifying a t it le, t he t it le t ext would be set t o " Microsoft Excel" by default . Sim ilarly, because we didn't specify a t it le for t he m essage box shown by our Act iveX DLL it s t it le default s t o t he applicat ion nam e of t he DLL, which is AFirst Proj ect . This proves t hat t he m essage box indeed originat ed from wit hin t he DLL and not from wit hin t he Excel proj ect t hat called it .

The More Complex CaseTwo-Way Communication The first it erat ion of our Hello World applicat ion dem onst rat ed in an uncom plicat ed fashion how t o creat e an Act iveX DLL and a corresponding Excel proj ect t hat could com m unicat e wit h t he DLL. But t he exam ple was significant ly lim it ed by t he fact t hat all com m unicat ion was one- way, Excel calling t he DLL. To t ake advant age of t he full power afforded by com bining Excel wit h a VB6 Act iveX DLL, we m ust

creat e a st ruct ure t hat allows com m unicat ion t o flow in bot h direct ions. I n t he second it erat ion of our Hello World applicat ion, we ext end t he previous exam ple t o allow t wo- way com m unicat ion. A DLL is fundam ent ally a dependent com ponent . A DLL cannot t ake any act ion by it self, it can only respond t o request s from applicat ions t hat are m aking use of it s code. Aft er a request is m ade, however, a DLL can com m unicat e direct ly wit h t he applicat ion t hat called it . The first t hing we m ust do t o enable t wo- way com m unicat ion bet ween Excel and t he DLL is provide t he DLL wit h a way of knowing who called it . The first st ep required t o accom plish t his is t o set a reference from t he DLL t o t he Excel obj ect library, which provides t he DLL wit h t he all inform at ion about Excel t hat it needs in order t o com m unicat e direct ly wit h Excel. The process of set t ing a reference in VB6 is virt ually ident ical t o t he process of set t ing a reference in VBA. The only difference is t he locat ion of t he m enu it em . To set a reference t o Excel from our VB6 Act iveX DLL we select Proj ect > References from t he VB6 m enu. Figure 20- 7 shows a reference creat ed from our VB6 proj ect t o t he Microsoft Excel 9.0 Obj ect Library. This is t he obj ect library for Excel 2000 and it will work correct ly for all versions of Excel from 2000 forward.

Figu r e 2 0 - 7 . Se t t in g a Re fe r e n ce t o Ex ce l Fr om VB6

As discussed in Chapt er 18 Cont rolling Ot her Office Applicat ions, because of pot ent ial backwardcom pat ibilit y problem s you should always set a reference t o t he earliest version of t he applicat ion

you expect t o be using. I n t his case, t he earliest version of Excel t hat we expect t o use is Excel 2000. Now t hat our DLL has a reference t o t he Excel obj ect library, we add t he code t o allow t he DLL t o com m unicat e wit h t he inst ance of t he Excel applicat ion t hat loaded it . Because, as m ent ioned earlier, a DLL is a fundam ent ally dependent com ponent , it is up t o t he VBA code running in t he Excel applicat ion t o est ablish t wo- way com m unicat ion by providing t he DLL wit h a reference t o t he Excel Applicat ion obj ect . The DLL m ust sim ply be prepared t o accept and st ore t his reference. To dem onst rat e t his process in our Hello World applicat ion, we will creat e a second m et hod t hat when called by Excel will ent er t he st ring " Hello World! " int o t he current ly select ed cell on t he act ive worksheet . As we im plied earlier, t he first t hing our DLL needs in order t o accom plish t his is a reference t o t he Excel applicat ion t hat called it . We will creat e a m odule- level variable t o st ore t he reference t o t he calling Excel Applicat ion obj ect and a new Propert y procedure t hat Excel can use t o pass a reference t o it self int o t he DLL. Because our DLL is now holding a reference t o an out side applicat ion we m ust also be sure t his reference is dest royed when t he DLL is unloaded from m em ory. We use t he Class_Term inat e event procedure t o accom plish t his. The com plet e code for t he new version of our CHelloWorld class m odule is shown in List ing 20- 3. Not e t hat we have used good code com m ent ing t echniques t o visually separat e t he various sect ions of t his new, m ore com plex class m odule code.

List in g 2 0 - 3 . Th e Com ple t e Upda t e d CH e lloW or ld Code M odu le Option Explicit ' ************************************************************ ' Class Variable Declarations Follow ' ************************************************************ ' Object reference to the calling Excel Application. Private mxlApp As Excel.Application ' ************************************************************ ' Class Property Procedures Follow ' ************************************************************ Public Property Set ExcelApp(ByRef xlApp As Excel.Application) Set mxlApp = xlApp End Property ' ************************************************************ ' Class Event Procedures Follow ' ************************************************************ Private Sub Class_Terminate() Set mxlApp = Nothing End Sub ' ************************************************************ ' Class Method Procedures Follow ' ************************************************************ Public Sub ShowMessage()

MsgBox "Hello World!" End Sub Public Sub WriteMessage() mxlApp.ActiveCell.Value = "Hello World!" End Sub

We have added t he following addit ional code t o our DLL class m odule: An m xlApp m odule- level variable t hat will hold a reference t o t he Excel Applicat ion obj ect t hat called t he DLL. The DLL will com m unicat e wit h Excel t hrough t his obj ect reference. An ExcelApp propert y procedure t hat will be used by t he Excel Applicat ion calling t he DLL t o provide a reference t o it self. A Class_Term inat e event procedure t hat ensures t he m odule- level reference t o t he Excel Applicat ion obj ect is dest royed when t he class is dest royed. A Writ eMessage m et hod t hat will place t he t ext st ring " Hello World! " int o t he current ly select ed cell in t he current ly act ive worksheet in t he current ly act ive workbook in t he Excel Applicat ion t hat called t he m et hod. I t is now t im e t o recom pile our DLL. I f you are following along on your own com put er and you st ill have Excel open from t est ing t he previous version of t he DLL, you will not ice t hat VB6 will not allow you t o recom pile t he DLL unt il you have closed Excel. The sym pt om s of t his are a " Perm ission denied: " error m essage when you at t em pt t o com pile. Aft er an Excel applicat ion has loaded a DLL, t he DLL will not be released from m em ory unt il Excel is closed. Closing t he workbook t hat references t he DLL will not do t he t rick. You m ust close Excel com plet ely. Aft er you have closed Excel you j ust select t he File > Make AFirst Proj ect .dll m enu, as in t he previous exam ple, t o recom pile your DLL so t hat it includes t he feat ures we have added in t his sect ion. Because you already have a previous version of AFirst Proj ect .dll locat ed in your proj ect direct ory, VB6 will warn you and ask if you want t o replace it wit h a new version. Select Yes and t he new version of your DLL will be com piled. Now t hat you have a newly com piled version of your DLL, you need t o add a procedure t o your Excel workbook t hat t akes advant age of t he new Writ eMessage m et hod. Open t he Book1.xls workbook t hat you saved t o t he VB6 proj ect direct ory and add t he procedure shown in List ing 20- 4 t o it s code m odule:

List in g 2 0 - 4 . Th e W r it e D LLM e ssa ge Pr oce du r e Public Sub WriteDLLMessage() Dim clsHelloWorld As AFirstProject.CHelloWorld Set clsHelloWorld = New AFirstProject.CHelloWorld Set clsHelloWorld.ExcelApp = Application clsHelloWorld.WriteMessage

Set clsHelloWorld = Nothing End Sub

The only fundam ent al difference bet ween t he Writ eDLLMessage procedure and t he previous ShowDLLMessage procedure is t hat we use t he new ExcelApp propert y of our CHelloWorld class t o pass a reference t o t he Excel Applicat ion obj ect int o t he class. This t ells t he class what applicat ion called it and t herefore what applicat ion it s com m unicat ions should be direct ed back t o. Because t he new Writ eMessage m et hod operat es on a cell on t he act ive worksheet , we have added t wo Form s t oolbar But t on cont rols t o t he first ( and only) worksheet in Book1.xls and assigned t heir OnAct ion propert ies t o each of t he t wo procedures in Book1.xls. I f you select a cell on t he worksheet and click t he Writ e DLL Message but t on, t he Writ eDLLMessage procedure assigned t o t hat but t on will be run. This procedure asks t he DLL t o ent er a m essage st ring int o t he current ly select ed cell of t hat Excel Applicat ion obj ect . The DLL uses it s reference t o t he Excel Applicat ion obj ect t o ent er t he st ring " Hello World! " int o t he current ly select ed cell. The result of t his call is shown in our newly const ruct ed Excel user int erface in Figure 20- 8.

Figu r e 2 0 - 8 . Tw o- W a y Com m u n ica t ion Be t w e e n Ex ce l a n d a n Act ive X D LL

Displaying a VB6 Form in Excel For t he next it erat ion of our VB6 Hello World applicat ion we perform an even m ore com plex t ask: displaying a VB6 form in Excel exact ly as if it were a VBA userform . There are a num ber of reasons you m ight want t o do t his, and we discuss t hem at lengt h in t he Taking Advant age of VB6 Form s sect ion lat er in t he chapt er. For now let 's leave t he com plicat ions aside and look at t he bare m inim um requirem ent s for displaying a VB6 form in Excel. The first st ep is t o add a form t o our Hello World proj ect by choosing Proj ect > Add Form from t he VB6 m enu. This displays t he Add Form dialog shown in Figure 20- 9.

Figu r e 2 0 - 9 . Th e Add For m D ia log

Select t he Form icon in t he upper- left corner and click t he Open but t on. A new form obj ect will be added t o your proj ect . Before we save our proj ect wit h t he new form obj ect in it , we need t o change a few propert ies of t he form . The propert ies t o be changed and t he values t hey should be changed t o are shown in Table 20- 1 .

Ta ble 2 0 - 1 . Th e Pr ope r t y Se t t in gs for Ou r N e w For m Pr ope r t y N a m e

Pr ope r t y Se t t in g

( Nam e)

FHelloWor ld

Bor der St yle

3 Fixed Dialog

Capt ion

Hello From VB6

I con

( None) Select and delet e t he default v alue

St art upPosit ion

1 Cent er Owner

Aft er you have m ade t hese propert y changes, save your proj ect . Because t he form has never been saved before, VB6 will prom pt you wit h a Save File As dialog asking you where t o save t he form . Make sure you save it in t he sam e direct ory where t he rest of t he proj ect is saved. Your proj ect should now look like t he one shown in t he Proj ect window in Figure 20- 10.

Figu r e 2 0 - 1 0 . Th e Pr oj e ct w it h a For m Adde d

Next we add a Com m andBut t on and a Label cont rol t o our new form . Nam e t he Com m andBut t on cm dOK and give it t he capt ion OK. Give t he Label t he capt ion " Hello World! " , change t he Alignm ent propert y t o 1Cent er and increase t he Font size t o 24 point s. Your com plet ed form should resem ble t he one shown in Figure 20- 11, but don't worry if yours looks a lit t le different .

Figu r e 2 0 - 1 1 . Th e VB6 H e llo W or ld! For m

The only code t hat we'll need t o put behind t he form is a line in t he cm dOK_Click event procedure t hat hides t he form when t he OK but t on is clicked. This event procedure is shown in List ing 20- 5.

List in g 2 0 - 5 . Th e cm dOK_ Click Eve n t Pr oce du r e Private Sub cmdOK_Click() Me.Hide End Sub

A form obj ect in a VB6 Act iveX DLL is not direct ly accessible t o out side applicat ions. Therefore we need t o add code t o our class m odule t hat will allow our Excel applicat ion t o display t he form . We also need t o m ake one addit ional t weak t o t he form so t hat it behaves like a nat ive Excel userform . The com plet e code for t he new version of our CHelloWorld class is shown in List ing 20- 6 wit h t he new code for t his version shaded.

List in g 2 0 - 6 . Th e CH e lloW or ld Code M odu le Upda t e d t o Su ppor t t h e For m Option Explicit ' ************************************************************ ' Class Constant Declarations Follow ' ************************************************************ ' SetWindowLongA API constant. Private Const GWL_HWNDPARENT As Long = -8 ' ************************************************************ ' Class Variable Declarations Follow ' ************************************************************ ' Object reference to the calling Excel Application. Private mxlApp As Excel.Application ' Window handle of the calling Excel Application. Private mlXLhWnd As Long ' ************************************************************ ' Class DLL Declaractions Follow ' ************************************************************ Private Declare Function FindWindowA Lib "user32" _ (ByVal lpClassName As String, _ ByVal lpWindowName As String) As Long Private Declare Function SetWindowLongA Lib "user32" _ (ByVal hWnd As Long, _ ByVal nIndex As Long, _ ByVal dwNewLong As Long) As Long ' ************************************************************ ' Class Property Procedures Follow ' ************************************************************ Public Property Set ExcelApp(ByRef xlApp As Excel.Application)

Set mxlApp = xlApp ' Get the window handle of the Excel Application object ' as soon as it is passed to us. mlXLhWnd = FindWindowA(vbNullString, mxlApp.Caption) End Property ' ************************************************************ ' Class Event Procedures Follow ' ************************************************************ Private Sub Class_Terminate() Set mxlApp = Nothing End Sub ' ************************************************************ ' Class Method Procedures Follow ' ************************************************************ Public Sub ShowMessage() MsgBox "Hello World!" End Sub Public Sub WriteMessage() mxlApp.ActiveCell.Value = "Hello World!" End Sub Public Sub ShowVB6Form() Dim frmHelloWorld As FHelloWorld Set frmHelloWorld = New FHelloWorld Load frmHelloWorld ' Parent the Form window to the Excel Application window. SetWindowLongA frmHelloWorld.hWnd, GWL_HWNDPARENT, mlXLhWnd frmHelloWorld.Show vbModal Unload frmHelloWorld Set frmHelloWorld = Nothing End Sub

A VB6 form is a t op- level window by default . That is t o say it is a child window only of t he deskt op. To m ake a VB6 form behave like a nat ive userform in Excel, we need t o use t he Windows API t o change t he parent window of t he VB6 form from t he deskt op t o t he window of t he Excel Applicat ion obj ect t hat called it . Changing t he parent window of a form involves t wo st eps: 1 . Ret rieving t he window handle of t he window we want t o use as t he form 's parent window. 2 . Changing t he form 's parent window by put t ing t he window handle we ret rieved int o t he st orage area of t he form 's window st ruct ure t hat is used t o specify t he parent window of t he for m .

I m plem ent ing t his in our code requires us t o m ake a num ber of addit ions, all of which are highlight ed in List ing 20- 6 above. We have declared a new m odule- level variable, m lXLhWnd, t o

hold t he window handle of t he Excel Applicat ion obj ect t hat called our class. We have added t wo Windows API funct ion declarat ions: FindWindowA t o locat e t he window handle of t he Excel Applicat ion window and Set WindowLongA t o change t he parent window of our form . The new GWL_HWNDPARENT const ant ident ifies t he locat ion in our form 's window st ruct ure where t he window handle of t he new parent window will be placed. We have added a line of code t o t he ExcelApp propert y procedure t o ext ract t he Excel Applicat ion obj ect 's window handle as soon as t he propert y is set . We have also creat ed a new ShowVB6Form m et hod t hat is responsible for displaying t he form in Excel in response t o a call from t he Excel applicat ion. This m et hod uses t he following st eps t o accom plish it s t ask: I t creat es a new inst ance of t he FHelloWorld form . I t loads t hat inst ance of t he FHelloWorld form int o m em ory. I t changes t he form 's parent window from t he deskt op window t o t he Excel Applicat ion window using t he Set WindowLongA API . I t shows t he form using t he vbModal flag. Unlike userform s, VB6 form s will show m odeless by default . Because t his is not what we want for t his exam ple we add t he vbModal flag t o t he form 's Show m et hod t o force t he form t o be m odal. When t he user has closed t he form t he m et hod unloads it from m em ory and dest roys t he obj ect variable t hat refers t o it .

Aft er you have added t he new code t o your VB6 proj ect , close Excel and recom pile your DLL using t he File > Make AFirst Proj ect m enu. On t he Excel applicat ion side you j ust need t o add a new procedure in t he code m odule t o call t he DLL and have it display t he VB6 form and add a new but t on on t he worksheet assigned t o t his procedure. The code for t he new DisplayDLLForm procedure is shown in List ing 20- 7.

List in g 2 0 - 7 . Th e D ispla yD LLFor m Pr oce du r e Public Sub DisplayDLLForm() Dim clsHelloWorld As AFirstProject.CHelloWorld Set clsHelloWorld = New AFirstProject.CHelloWorld Set clsHelloWorld.ExcelApp = Application clsHelloWorld.ShowVB6Form Set clsHelloWorld = Nothing End Sub

As you can see, t he code for t he DisplayDLLForm procedure is virt ually ident ical t o t he code for t he Writ eDLLMessage procedure shown back in List ing 20- 4. The only difference is t hat one calls t he ShowVB6Form m et hod of our CHelloWorld class while t he ot her calls t he Writ eMessage m et hod of our CHelloWorld class. The Excel user int erface wit h t he VB6 form displayed over it is shown in

Figure 20- 12.

Figu r e 2 0 - 1 2 . Th e VB6 For m D ispla ye d in Ex ce l

Not ice how our VB6 form looks and behaves exact ly like a userform in Excel. You m ay be asking yourself why we would go t hrough all t his t rouble when we could have spent five m inut es creat ing an ident ical userform in VBA. I n t he Taking Advant age of VB6 Form s sect ion lat er in t his chapt er you will see t hat VB6 form s have a num ber of feat ures t hat userform s don't , and t he sim ple st ruct ure for displaying a VB6 form in Excel t hat we have developed here is t he first st ep in

Why Use VB6 ActiveX DLLs in Excel VBA Projects Alt hough t he core VBA language cont ained in VB6 is exact ly t he sam e as t hat used by Excel, VB6 support s a num ber of addit ional feat ures t hat are not available in a pure Excel applicat ion. These feat ures include very st rong code prot ect ion due t o it s fully com piled nat ure and a m ore powerful form s package wit h t he abilit y t o use t hird- part y Act iveX cont rols, cont rol arrays and wit h enhanced dat a- binding capabilit ies. VB6 also provides bet t er support for obj ect - orient ed program m ing, t he abilit y t o creat e resource files and ot her useful feat ures, including t he Clipboard, Print er and Screen obj ect s.

Code Protection A frequent problem t hat com es up in t he cont ext of Excel applicat ions is t he com plet e inabilit y of VBA t o prot ect your code from prying eyes. Sure you can prot ect your VBA proj ect wit h a password. But VBA proj ect password breaking program s t hat can rem ove t his password inst ant aneously are widely available. Because VBA code is never t ruly com piled, it will never be possible t o prevent ot her people from gaining access t o it . For run- of- t he- m ill applicat ions t his is not a very significant problem . There are a num ber of applicat ions, however, t hat rely on valuable propriet ary algorit hm s. The only way t o prot ect t his propriet ary code is t o st ore it in a t ruly com piled st at e like t hat provided by a VB6 DLL. Not e t hat t he com piled m achine code produced by VB6 can be decom piled t o a very lim it ed ext ent . The result of decom piling a VB6 DLL, however, is lit t le m ore t han assem bly language, which so few people underst and t hat code com piled in VB6 is effect ively invulnerable.

Taking Advantage of VB6 Forms The form s package used by VB6 is very different from t he one used by VBA. As m ent ioned in Chapt er 10 Userform Design and Best Pract ices, t he form s package used t o creat e userform obj ect s in Excel applicat ions is called MSForm s. The form s package used t o creat e form obj ect s in VB6 is known as Ruby Form s. There are superficial sim ilarit ies bet ween t he t wo. Bot h provide a blank canvas ont o which you can drag and drop cont rols t o visually const ruct your form . Bot h t ypes of form have event m odels and bot h allow you t o program cont rols by responding t o event s raised by t hose cont rols. There are also differences bet ween t he t wo form s packages and t hose differences range from t he subt le t o t he significant . For exam ple, t here are m inor differences in t he set of propert ies, m et hods and event s exposed by t he t wo t ypes of form s and t heir built - in cont rols. There are also significant differences in t he capabilit ies of t he t wo. For exam ple, in Chapt er 10 Userform Design and Best Pract ices we showed in det ail how t o m odify t he window st yles of userform s using API calls t o achieve effect s t hat were not direct ly support ed by userform s. All of t hese window st yles are direct ly support ed by VB6 form s and it requires

not hing m ore t han set t ing t he appropriat e form propert ies in t he Propert ies window t o im plem ent t hem . VB6 form s also provide a wide variet y of built - in shapes and drawing m et hods t hat allow you t o creat e sophist icat ed form designs wit hout ever having t o resort t o t he Windows API . Where API t echniques are st ill required t o achieve a cert ain effect , t hey are m uch easier t o im plem ent in VB6 form s because VB6 form s expose t heir window handles and device cont ext s as nat ive propert ies, obviat ing t he need for API calls t o obt ain t hem . And in cont rast t o t he light weight , windowless cont rols provided wit h VBA userform s, VB6 form cont rols all have windows and t hey all expose t heir window handles as nat ive propert ies. This allows t hem t o be m anipulat ed in ways t hat are sim ply im possible wit h windowless userform cont rols. We discuss addit ional differences bet ween VBA userform s and VB6 form s t hat are of part icular int erest t o t he Excel program m er in t he sect ions t hat follow.

Better ActiveX Control Support Not only do VB6 form s provide bet t er support t han userform s for a wide variet y of built - in Windows cont rols, t hey can also host hundreds of t hird- part y Act iveX cont rols t hat are com plet ely unavailable t o userform s. The reason for t his is t hat alm ost all t hird- part y Act iveX cont rols com e in t wo versions. When building your proj ect t he version you use is called t he de sign - t im e ve r sion of t he cont rol. When your proj ect is dist ribut ed and running in a com piled st at e it uses t he r u n t im e ve r sion of t he cont rol. When you purchase a t hird- part y Act iveX cont rol, what you are really buying is a license t o build your VB6 form s using t he design- t im e version of t he cont rol. The runt im e version of t he cont rol, required by your VB6 form aft er it is com piled, can be redist ribut ed wit hout rest rict ions in m ost cases. This is because it cannot be used in t he design- t im e environm ent and t herefore cannot be used t o build new proj ect s. By cont rast , VBA userform s a lw a ys operat e in design m ode, so runt im e versions of Act iveX cont rols will not work wit h t hem . I f you were t o dist ribut e t he design- t im e version of a cont rol t o get it t o run on an uncom piled VBA userform , you would essent ially be giving t hat cont rol away t o ot her users for free. Anyone who has t he design- t im e version of a cont rol inst alled on t heir com put er can use it in t heir own proj ect s, whet her t hey purchased it or not . As you can im agine, t here are very few Act iveX cont rol vendors who will allow you t o redist ribut e t he design- t im e versions of t heir cont rols. This m akes t he use of t hose cont rols effect ively off- lim it s t o all VBA userform - based proj ect s.

N OTE I t is possible t o wrap a t hird- part y Act iveX cont rol inside a cust om VB6 Act iveX cont rol proj ect . The wrapper proj ect would need t o duplicat e all t he required propert ies, m et hods and event s of t he cont rol it wraps. Once com piled, however, it uses t he runt im e version of t he t hird- part y cont rol. Userform s can host cust om VB6 Act iveX cont rols, so t his is a way t o get around t he lim it at ion described above. However, t his is difficult and t im econsum ing t o im plem ent , probably a violat ion of t he license agreem ent s of m ost t hirdpart y cont rols and, anyway, beyond t he scope of t his chapt er.

Control Arrays Cont rol arrays are one of t he m ost useful feat ures provided by VB6 form s. There is sim ply not hing like t hem support ed by VBA userform s. Using cont rol arrays, you can declare a set of cont rols t o be an array. Each cont rol in t he array is given t he sam e nam e but a unique I ndex propert y value. VB6 t hen t reat s all t he cont rols in t he array alm ost as if t hey were a single cont rol. For exam ple, a single event procedure of each t ype is fired in response t o act ivit y from any of t he cont rols wit hin t he array. This event procedure passes t he I ndex value of t he specific cont rol t hat fired t he event , allowing you t o respond appropriat ely. Not only are all cont rols in a cont rol array t reat ed as a single cont rol, but you can easily add or rem ove cont rols dynam ically from t he array as required at runt im e. Adding or rem oving cont rols from t he array physically adds or rem oves act ual cont rols on t he form , a capabilit y t hat great ly sim plifies t he creat ion of dynam ically configured form s. We dem onst rat e a very sim ple exam ple of a cont rol array below. This exam ple is available on t he CD in t he \ Concept s\ Ch20Com bining Excel and Visual Basic 6\ Cont rolArrays folder. The plum bing required t o display t he VB6 form in Excel is ident ical t o t hat shown in t he t hird it erat ion of our Hello World exam ple above, so we do not rehash any of t hat m at erial. I nst ead we concent rat e on how t o creat e and program a cont rol array on a VB6 form . Our cont rol array dem o will consist of a VB6 form t hat will event ually cont ain six Opt ionBut t on cont rols along wit h a List Box cont rol. The opt ion but t on select ed by t he user will det erm ine t he cont ent s of t he List Box cont rol. Rat her t han having t o respond t o a separat e Click event from each opt ion but t on, we creat e t he six opt ion but t ons as a cont rol array so t hat we can m anage t hem from a single Click event . The init ial form cont aining a list box and a single nonarray opt ion but t on is displayed side by side wit h t he Propert ies window showing t he propert ies for t he opt ion but t on in Figure 20- 13. The Propert ies window is shown wit h it s Cat egorized t ab act ive and all cat egories except Misc collapsed. The Misc propert ies are t he ones we want t o focus on when it com es t o creat ing cont rol arrays.

Figu r e 2 0 - 1 3 . Th e I n it ia l Con t r ol Ar r a y D e m o For m [View full size image]

Not e t hat we have given our opt ion but t on t he nam e opt Type and t hat t he I ndex propert y select ed in t he Propert ies window is em pt y. This ident ifies opt Type as a st andard cont rol. The next st ep is t o add t he five addit ional opt ion but t ons t o our form . Because we have already drawn one Opt ionBut t on cont rol on our form t hat we want t o duplicat e, t here's no reason t o add five m ore opt ion but t ons from scrat ch. I nst ead we'll j ust copy our first opt ion but t on and past e new copies of it back on t o t he form . To do t his, we j ust select our exist ing opt ion but t on, right - click over it and choose Copy from t he short cut m enu. We t hen select an em pt y area on our form , right - click over it and choose Past e from t he short cut m enu. As soon as we at t em pt t o past e a copy of our exist ing opt ion but t on ont o t he sam e form where it originat ed, VB6 displays t he m essage shown in Figure 20- 14.

Figu r e 2 0 - 1 4 . VB6 H e lps u s Cr e a t e a Con t r ol Ar r a y [View full size image]

When you at t em pt t o past e a cont rol t hat has t he sam e nam e as an exist ing cont rol ont o a form , VB6 assum es you want t o creat e a cont rol array and it offers t o help you do so. Click t he Yes but t on in t he m essage box and let 's see what happens. We have reselect ed our original opt ion but t on and displayed t he result in Figure 20- 15.

Figu r e 2 0 - 1 5 . A Con t r ol Ar r a y Cr e a t e d by t h e Copy/ Pa st e M e t h od [View full size image]

The copy of t he opt ion but t on t hat we past ed appears in t he upper left corner of t he form . What is int riguing is t o com pare t he previous propert y values for our first opt ion but t on from Figure 20- 13 wit h it s new propert y values shown in Figure 20- 15. The first t hing t o not e is t hat t he nam e of our original opt ion but t on is now opt Type( 0) inst ead of opt Type. We allowed VBA t o creat e a cont rol array for us when we past ed t he copy of t his opt ion but t on ont o our form , and t he original opt ion but t on is now t he first elem ent in t he array. Cont rol arrays begin at zero by default . The second t hing t o not ice is t hat t he form erly em pt y I ndex propert y now also has a value of zero. This propert y is what really det erm ines whet her a cont rol is part of an array or not . I f t he I ndex propert y is blank, t he cont rol is not part of an array. I f t he I ndex propert y cont ains a num ber, t he cont rol is part of an array and t he I ndex propert y value is it s posit ion wit hin t he array. We now posit ion t he copied opt ion but t on cont rol ( which has an I ndex of 1) below t he original opt ion but t on and set it s capt ion. Then we'll past e four m ore copies of t he original opt ion but t on ont o t he form and do t he sam e. The result s are shown in Figure 20- 16.

Figu r e 2 0 - 1 6 . Th e Com ple t e d Con t r ol Ar r a y D e m o For m

Even t hough t he opt ion but t ons have com plet ely different capt ions, t hey have exact ly t he sam e nam e wit h a unique I ndex value t o ident ify t hem . Therefore we now have opt ion but t ons opt Type( 0) t hrough opt Type( 5) . Not e t hat when you past e a cont rol t hat is already part of a cont rol array ont o a form , VB no longer prom pt s you wit h t he quest ion shown in Figure 20- 16. I t j ust adds t he cont rol t o t he next available index posit ion wit hin t he exist ing cont rol array. Now t hat we have com plet ed t he visible part of our Cont rol Array Dem o form , let 's have a look at t he code required t o m anage it . Our form requires only t wo propert ies and t hree event procedures t o perform all of it s operat ions: One propert y t o expose t he opt ion select ed and anot her t o expose t he list it em select ed for t hat opt ion. A Click event procedure t hat handles all t he opt ion but t ons in t he cont rol array. A Click event procedure for t he cm dOK but t on t hat validat es t he user's select ions. A QueryUnload event for t he form t hat rerout es clicks on t he X- Close but t on t o t he cm dOK_Click event procedure.

The code behind our Cont rol Array Dem o form is shown in List ing 20- 8.

List in g 2 0 - 8 . Th e Con t r ol Ar r a y D e m o For m - Spe cific Code

Option Explicit ' ************************************************************ ' Form Property Procedures Follow ' ************************************************************ Public Property Get OptionSelected() As Long Dim lIndex As Long Dim sOption As String For lIndex = optType.LBound To optType.UBound If optType(lIndex).Value Then Exit For Next lIndex Select Case lIndex Case 0 sOption = "Population" Case 1 sOption = "Demand" Case 2 sOption = "Price" Case 3 sOption = "Turnover" Case 4 sOption = "Additional Capital" Case 5 sOption = "Additional Expense" End Select OptionSelected = sOption End Property Public Property Get ListSelection() As Double ListSelection = CDbl(lstValue.Text) End Property ' ************************************************************ ' Form Event Procedures Follow ' ************************************************************ Private Sub optType_Click(Index As Integer) Dim vItem As Variant Dim vaList As Variant lstValue.Clear Select Case Index Case 0 ' Population vaList = Array(500, 1000, 100000, 100000) Case 1 ' Demand vaList = Array(50, 100, 1000, 10000) Case 2 ' Price vaList = Array(9.99, 19.99, 29.99, 39.99) Case 3 ' Turnover vaList = Array(0.01, 0.015, 0.02, 0.025, 0.03) Case 4 ' Additional Capital vaList = Array(1000, 2000, 3000, 4000) Case 5 ' Additional Expense

vaList = Array(500, 1000, 1500, 2000) End Select For Each vItem In vaList lstValue.AddItem vItem Next vItem lstValue.ListIndex = -1 End Sub Private Sub cmdOK_Click() Dim bOptionSelected As Boolean Dim lIndex As Long ' Do not allow the user to continue unless an option button ' has been selected and a list item has been selected For lIndex = optType.LBound To optType.UBound If optType(lIndex).Value Then bOptionSelected = True Exit For End If Next lIndex If Not bOptionSelected Or lstValue.ListIndex = -1 Then MsgBox "You must select an option and a list item." Else Me.Hide End If End Sub Private Sub Form_QueryUnload(Cancel As Integer, _ UnloadMode As Integer) ' Route the x-close button through the ' cmdOK_Click event procedure. If UnloadMode = vbFormControlMenu Then Cancel = True cmdOK_Click End If End Sub

The Opt ionSelect ed propert y procedure ret urns a st ring ident ifying t he opt ion but t on wit hin t he cont rol array t hat t he user select ed. I t does t his by j ust looping t he cont rol array unt il a cont rol wit h a value of True is locat ed. Aft er t his cont rol is locat ed, t he loop is exit ed and t he index value convert ed int o it s corresponding st ring descript ion. The List Select ion propert y does not hing m ore t han ret urn t he Text propert y of t he list box ( whose values are const rained by t he opt ion but t on select ion) . The opt Type_Click event procedure is som et hing t hat we have never seen before. This event procedure behaves exact ly like t he Click event for any opt ion but t on except t hat it fires when any opt ion but t on in t he cont rol array is clicked. This is why it has an I ndex argum ent . The I ndex argum ent will cont ain t he value of t he I ndex propert y of t he opt ion but t on t hat fired t he event . We use t his event procedure t o load t he list box wit h values t hat correspond t o t he opt ions select ed. Look at t he st ruct ure of t his procedure and im agine how easy it would be t o add or rem ove opt ions.

The cm dOK_Click event dem onst rat es som e very sim ple validat ion code. When t he form is first displayed, no opt ion but t on is select ed and t here is not hing in t he list . I f t his were a real applicat ion we would writ e code t o disable t he cm dOK but t on unt il all t he appropriat e select ions had been m ade. For t he purposes of t his dem o, however, we j ust check t he st at us of t he opt ion but t on array and t he list when t he cm dOK but t on is clicked. I f everyt hing is in order, we hide t he form and cont inue. Ot herwise we display a m essage t o t he user indicat ing what t hey need t o do. The Form _QueryUnload event is used t o t rap cases where t he user t ries t o close t he form wit h t he X- Close but t on rat her t han t he OK but t on. I n a real applicat ion, we would have cancel logic coded int o t he form t hat would be act ivat ed by t his but t on, but because t he only rout e out of t he form t hat we have provided for t his exam ple is t hrough t he cm dOK but t on, we cancel any clicks on t he X- Close but t on and rerout e t hem t hrough t he cm dOK_Click event procedure. As m ent ioned in t he final sect ion of our Hello World exam ple, VB6 form s cannot be accessed direct ly by out side applicat ions. Therefore we have creat ed a public CDialogHandler class m odule t o expose t he Cont rol Array Dem o form and t he select ions t he user has m ade in it t o our Excel applicat ion. The m et hod used t o expose t he form is shown in List ing 20- 9.

List in g 2 0 - 9 . Th e CD ia logH a n dle r Sh ow VB6 For m M e t h od Public Sub ShowVB6Form(ByRef sOption As String, _ ByRef dValue As Double) Dim frmCtrlArrays As FControlArrays Set frmCtrlArrays = New FControlArrays Load frmCtrlArrays ' Parent the Form window to the Excel Application window. SetWindowLongA frmCtrlArrays.hWnd, GWL_HWNDPARENT, mlXLhWnd frmCtrlArrays.Show vbModal sOption = frmCtrlArrays.OptionSelected dValue = frmCtrlArrays.ListSelection Unload frmCtrlArrays Set frmCtrlArrays = Nothing End Sub

This ShowVB6Form m et hod procedure is alm ost ident ical t o t he m et hod we used t o display t he form in our Hello World applicat ion. The only difference is t hat in t he Hello World applicat ion t he form did not ret urn any value t o t he calling procedure, while in t his exam ple t he form ret urns t he opt ion select ed by t he user and t he it em t hey select ed in t he list box. The addit ional code you see in t his procedure is used t o ret rieve t hese t wo values and pass t hem back t o t he calling Excel applicat ion. This is accom plished by t he t wo ByRef argum ent s t o t he ShowVB6Form m et hod I n a real- world applicat ion, we would t ypically have m uch m ore dat a t o t ransfer back t o Excel and t herefore we would design a m uch m ore efficient m et hod for doing so, creat ing a global userdefined t ype t o hold all t he inform at ion t ransferred out of t he form and passing t his UDT direct ly from t he DLL t o t he Excel applicat ion for exam ple. We have not done so here so as not t o draw at t ent ion away from t he m ain point , which is t o dem onst rat e t he use of cont rol arrays.

Better Support for Object-Oriented Programming More Class Instancing Types The I nst ancing propert y of a class det erm ines it s visibilit y wit h respect t o t he applicat ion wit hin which it is locat ed. Excel VBA classes are lim it ed t o t he I nst ancing t ypes Privat e and PublicNot Creat able. A class wit h it s I nst ancing propert y set t o Privat e is invisible t o all out side applicat ions. A class wit h it s I nst ancing propert y set t o PublicNot Creat able can be seen by out side applicat ions but it can only be used by an out side applicat ion if your proj ect creat es and exposes an inst ance of t he class t hrough a publicly accessible propert y, m et hod or procedure first . What t his m eans for Excel VBA proj ect s is t hat no out side applicat ions ( or even ot her VBA proj ect s wit hin t he sam e inst ance of Excel) can creat e inst ances of classes t hat exist wit hin an Excel VBA proj ect . As shown in Figure 20- 17, however, a VB6 Act iveX DLL has t wo addit ional I nst ancing t ypes, bot h of which allow classes of t hose t ypes t o be creat ed and used direct ly by ot her applicat ions.

Figu r e 2 0 - 1 7 . VB6 Act ive X D LL Cla ss Type s

MultiUse

Mult iUse is t he default inst ancing t ype for class m odules added t o a VB6 Act iveX DLL proj ect . This is t he inst ancing t ype t hat has been used by all t he class m odules t hat we have used in t his chapt er so far. Aft er you have creat ed a class wit h t he Mult iUse inst ancing t ype, any applicat ion t hat references your DLL can creat e and use new inst ances of t hat class. The Mult iUse inst ancing t ype is t he one you want t o use in cases where it is im port ant for you t o require t hat your public classes are explicit ly creat ed before t heir feat ures are used. This is m ost frequent ly t he case when your VB6 Act iveX DLL cont ains an obj ect m odel t hat im plem ent s t he business logic layer of an applicat ion, for exam ple.

GlobalMultiUse Class m odules wit h t he inst ancing t ype GlobalMult iUse don't need t o be explicit ly creat ed. Som et im es referred t o as aut o- inst ancing classes, t his t ype of class m odule will be inst ant iat ed aut om at ically as soon as any reference is m ade t o one of it s publicly exposed com ponent s. This t ype of class is m ost frequent ly used for creat ing libraries of user- defined t ypes, enum erat ion const ant s and funct ions t hat will be used by m ult iple files in an applicat ion. They are also a good place t o define int erfaces t hat you will be im plem ent ing in m ult iple files. For exam ple, if t he code for your dat a access t ier resides in a VB6 Act iveX DLL and t he code for your business logic t ier resides in an Excel workbook but t hey bot h need t o share t he sam e userdefined t ype in order t o pass dat a bet ween t hem , you can define t hat UDT in a GlobalMult iUse class in a separat e Act iveX DLL t hat bot h proj ect s reference. Bot h proj ect s will t hen be able t o " see" t he declarat ion of t he UDT and t hey can pass variables of t hat t ype bet ween t hem selves even t hough t he UDT is not declared in eit her one of t hem . This sam e t echnique can be used t o expose com m on enum erat ions as well. GlobalMult iUse classes also provide an excellent cont ainer for library procedures. Library procedures are generically designed cust om subrout ines and funct ions t hat you find yourself using in m ost of your proj ect s. I f you st ore t hese procedures in a GlobalMult iUse class com piled int o an Act iveX DLL, all of t hem can be m ade available t o any proj ect by j ust referencing t hat DLL. There is no need t o creat e any obj ect in order t o use t hese library procedures, because public procedures of GlobalMult iUse classes effect ively becom e part of t he global nam espace in any proj ect t hat references t heir DLL. This m eans you can use your cust om bSheet Exist s( ) funct ion exact ly t he sam e way you use t he built - in VBA Replace( ) funct ion. A working exam ple of a VB6 Act iveX DLL cont aining a GlobalMult iUseClass can be found on t he CD in t he \ Concept s\ Ch20Com bining Excel and Visual Basic 6\ GlobalMult iUse folder.

Better Support for Custom Collections through Direct Support of NewEnum As explained in Chapt er 7 Using Class Modules t o Creat e Obj ect s, VB6 has t wo significant advant ages over VBA when it com es t o creat ing cust om Collect ion obj ect s. I t support s default procedures and it has a user int erface t hat can give t he required NewEnum m et hod t he " m agic num ber" procedure at t ribut e of 4. For exam ple, t he I t em propert y and NewEnum m et hod from t he CCells collect ion int roduced in Chapt er 7 are shown in List ing 20- 10.

List in g 2 0 - 1 0 . Th e I t e m Pr ope r t y a n d N e w En u m M e t h od fr om t h e CCe lls Colle ct ion Property Get Item(ByVal vID As Variant) As CCell Set Item = mcolCells(vID) End Property Public Function NewEnum() As IUnknown Set NewEnum = mcolCells.[_NewEnum] End Function

I f t his code were locat ed in a cust om collect ion class in VB6, you would m ake t he I t em propert y t he default procedure of t he class by placing your m ouse cursor anywhere wit hin t he procedure and select ing t he Tools > Procedure At t ribut es m enu. This would display t he Procedure At t ribut es dialog. I n t he Procedure At t ribut es dialog you would click t he Advanced but t on and select ( Default ) from t he Procedure I D dropdown. The result of t his is shown in Figure 20- 18.

Figu r e 2 0 - 1 8 . Cr e a t in g a D e fa u lt Pr oce du r e in VB6

Sim ilarly, t o give t he NewEnum procedure t he m agic num ber procedure at t ribut e of 4, you would place your cursor anywhere inside t he NewEnum procedure and select Tools > Procedure At t ribut es from t he VB6 m enu. You would again click t he Advanced but t on, but inst ead of select ing a preexist ing it em from t he Procedure I D dropdown you would t ype in t he num ber 4. The result of t his is shown in Figure 20- 19.

Figu r e 2 0 - 1 9 . Addin g t h e M a gic N u m be r t o t h e N e w En u m M e t h od

Wit h VB6 it requires very lit t le effort t o creat e a cust om collect ion obj ect t hat behaves exact ly like a built - in collect ion obj ect . As we described in Chapt er 7 Using Class Modules t o Creat e Obj ect s, you can accom plish t his in VBA but it is a m uch m ore laborious process. Because cust om collect ion obj ect s are a fundam ent al building block in creat ing cust om obj ect m odels, t he ease of creat ing t hem in VB6 is a very significant advant age.

Resource Files Resource files are a t ype of cont ainer provided by VB6 t o st ore st ring t ables and a wide variet y of binary obj ect s. These resources, as t hey are called, are com piled int o your VB6 DLL and m ade

available t hrough t he use of specialized VB6 funct ions. I n t radit ional VB6 proj ect s, t he m ost com m on use of a resource file is t o hold a st ring t able t hat is used t o t ranslat e t he applicat ion int o m ult iple languages. A separat e st ring t able is provided for each language under which t he applicat ion needs t o run, and all t ext displayed by t he applicat ion is loaded dynam ically from t he st ring t able t hat corresponds t o t he language set t ing on t he user's com put er. Excel applicat ions have t he advant age of being able t o use worksheet s for t his t ype of dat a st orage. What Excel applicat ions lack is an easy way t o st ore binary resources such as icons and bit m aps. You can st ore t hese t ypes of resources on worksheet s eit her direct ly as shapes or as pict ure obj ect s wit hin a large num ber of I m age cont rols, or you can dist ribut e t hem as separat e files wit h t he rest of t he applicat ion. All of t hese m et hods have significant problem s associat ed wit h t hem t hat VB6 resource files do not . We show an exam ple of how t o use a resource file t o st ore com m and bar cont rol icons in t he Pract ical Exam ples sect ion lat er in t he chapt er.

Other VB6 Features Th e Clipboa r d obj e ct The MSForm s obj ect library provides t ext - only access t o t he clipboard t hrough t he Dat aObj ect . VB6 has a clipboard obj ect t hat support s a com plet e range of operat ions for bot h t ext and graphics. Th e Pr in t e r obj e ct The VB6 Print er obj ect enables you t o com m unicat e direct ly wit h t he print er inst alled on t he user's com put er. This in no way replaces t he built - in print ing capabilit ies of an applicat ion like Excel, but it opens up a wide variet y of addit ional print ing opt ions t hat are not available from VBA. Th e Scr e e n obj e ct The VB6 Screen obj ect , am ong ot her useful feat ures, has t wo m et hods t hat allow you t o convert from pixels t o t wips in bot h t he horizont al and vert ical direct ions, obviat ing t he need for a series of API calls required t o det erm ine t hat inform at ion wit h VBA alone.

In-Process versus Out-of-Process When you connect t wo different applicat ions, in t his case an Excel VBA applicat ion and an applicat ion writ t en in VB6, t here are t wo different m et hods by which t he t wo applicat ions can com m unicat e. These t wo m et hods are known as in- process and out - of- process com m unicat ion.

In-Process Communication I n- process com m unicat ion occurs when t wo applicat ions run in t he sam e virt ual m em ory area allocat ed by Windows. Act iveX DLLs are t he t ype of VB6 applicat ion t hat will run in process wit h Excel VBA applicat ions. When an Excel VBA applicat ion calls a VB6 Act iveX DLL, Windows loads t he DLL int o t he sam e m em ory area it has allocat ed for t he Excel VBA applicat ion. ( All Excel VBA applicat ions running wit hin a given inst ance of Excel always run in t he sam e m em ory area as each ot her and Excel.) This has im port ant pract ical im plicat ions. When t wo applicat ions share t he sam e m em ory area, com m unicat ion bet ween t hem is very fast . I n fact com m unicat ion bet ween an Excel VBA applicat ion and a VB6 Act iveX DLL operat es at m ore or less exact ly t he sam e speed as com m unicat ion wit hin an Excel VBA applicat ion. Therefore, you do not sacrifice any perform ance due t o com m unicat ion overhead when using VB6 DLLs wit h Excel VBA applicat ions and you pot ent ially gain perform ance due t o t he fact t hat unlike VBA, a VB6 DLL is t ruly com piled and runs m ore efficient ly as a result .

Out-of-Process Communication Out - of- process com m unicat ion occurs when t wo applicat ions run in different m em ory areas allocat ed by Windows. This is always t he case for com m unicat ions bet ween t wo EXE applicat ions. Windows loads all EXE applicat ions int o separat e m em ory areas. I t is not possible for t wo EXE applicat ions t o share t he sam e m em ory area. Therefore, when you use a VB6 EXE t oget her wit h an Excel VBA applicat ion, t he VB6 EXE and t he Excel VBA applicat ion will run in separat e m em ory areas. This result s in a significant perform ance degradat ion caused by t he overhead of com m unicat ing bet ween t he t wo m em ory areas ( t echnically t erm ed int er- process com m unicat ion) . Out - of- process com m unicat ion runs several orders of m agnit ude m ore slowly t han in- process com m unicat ion. One of t he obvious im plicat ions of t his is t hat you should not choose an out - of- process archit ect ure for highly perform ance- int ensive applicat ions. I f, for som e reason, you m ust use an out - of- process archit ect ure for a perform anceint ensive applicat ion, put as m uch code as possible in t he Excel workbook so t hat it is run inprocess by VBA.

Automating Excel From a VB6 EXE I n t he m ost com m on t ypes of applicat ion t hat com bine a VB6 EXE wit h Excel, t he VB6 EXE is t he init iat ing applicat ion. The VB6 EXE m ay eit her be t he prim ary applicat ion aut om at ing Excel, or j ust a front loader for an Excel applicat ion yet t o be st art ed. I n t his sect ion, we dem onst rat e a st rippeddown exam ple of a VB6 EXE applicat ion aut om at ing Excel. We t hen describe one of t he m ost com m on real- world exam ples of a VB6 EXE com bined wit h an Excel applicat ion, t he front loader.

An Excel Automation Primer Aut om at ing Excel from a VB6 EXE applicat ion is m uch sim pler t han using a VB6 Act iveX DLL from an Excel applicat ion. I n fact we have already covered all of t he point s required t o aut om at e one applicat ion from anot her in Chapt er 18 Cont rolling Ot her Office Applicat ions. The process of cont rolling Excel from VB6 is no different from cont rolling an out side applicat ion from Excel. We now dem onst rat e a very basic exam ple of a VB6 EXE t hat aut om at es Excel. The files for t his exam ple can be found on t he CD in t he \ Concept s\ Ch20Com bining Excel and Visual Basic 6\ Aut om at ingExcel folder. Creat ing an elaborat e exam ple using Excel would be t im e consum ing and would t end t o obscure t he fundam ent als. I nst ead we creat e a som ewhat light heart ed exam ple t hat uses an obscure funct ion provided by Excel t o convert whole num bers int o Rom an num erals. This is not as far from realit y as it m ay seem at first . One of t he prim ary reasons for aut om at ing Excel from VB6 is t o ut ilize t he powerful capabilit ies of Excel's calculat ion engine in a VB6 applicat ion. To begin t he proj ect , st art VB6 and select St andard EXE as t he proj ect t ype in t he New Proj ect dialog. I n addit ion t o t he proj ect it self, you will get a single VB6 form by default . This is all we need for t his exam ple. Renam e your proj ect Convert ToRom an, renam e your form FRom an and t hen save your proj ect . I n t he VB6 Proj ect window, your proj ect should now look like Figure 20- 20.

Figu r e 2 0 - 2 0 . Th e Con ve r t ToRom a n Pr oj e ct

The first st ep required in any proj ect t hat int ends t o aut om at e Excel is t o set a reference t o t he Excel obj ect library. Choose Proj ect > References from t he VB6 m enu and select t he Microsoft Excel X.0 Obj ect Library, as shown in Figure 20- 21, where X is t he version num ber of t he earliest version of Excel t hat you expect t o aut om at e wit h your VB6 applicat ion.

Figu r e 2 0 - 2 1 . Re fe r e n cin g t h e Ex ce l Obj e ct Libr a r y

The default form will be t he only VB6 class we use in t his exam ple. Add t hree cont rols t o t he form : a Text Box cont rol in which t o ent er t he num ber t o be convert ed t o Rom an num eral form at , a Com m andBut t on cont rol t o run t he code t hat perform s t he conversion and a Label cont rol in which t o display t he result s. Our com plet ed form is shown in Figure 20- 22.

Figu r e 2 0 - 2 2 . Th e I n it ia l FRom a n For m

We have not changed any of t he default propert ies of our form or it s cont rols. For a change of pace, we show how easy t his is t o do in code when t he form loads. We do need t o give our cont rols reasonable nam es, however, so we nam e t he Com m andBut t on cm dConvert , t he Text Box t xt Convert and t he Label lblResult . Now let 's look at t he code behind our form . All of t his code will consist of event procedures for t he form obj ect and it s cont rols. The first event procedure we'll exam ine is t he Form _Load event shown in List ing 20- 11.

List in g 2 0 - 1 1 . Th e For m _ Loa d Eve n t Pr oce du r e Private Sub Form_Load() ' Form properties Me.BorderStyle = vbFixedDouble Me.Caption = "Convert to Roman Numerals" ' CommandButton properties cmdConvert.Caption = "Convert To Roman" ' TextBox properties txtConvert.Alignment = vbRightJustify txtConvert.MaxLength = 4 txtConvert.Text = "" ' Label properties lblResult.Alignment = vbCenter lblResult.BackColor = &HE0E0E0 lblResult.BorderStyle = vbFixedSingle lblResult.Caption = ""

lblResult.Font.Name = "Courier" End Sub

I n t his procedure we set all t he propert ies of t he form and it s cont rols t hat are required t o m ake t he form user friendly. The result of displaying t he form wit h only t his procedure in place is shown in Figure 20- 23. Com pare t his pict ure wit h t he design- t im e version of t he form shown in Figure 20- 22.

Figu r e 2 0 - 2 3 . Th e D ispla y Appe a r a n ce of t h e For m

The next t hing we need t o account for is t he fact we can only convert whole num bers t o Rom an num erals. This m eans we need t o prevent t he user from ent ering anyt hing int o t he t xt Convert Text Box cont rol ot her t han t he num erals 0 t hrough 9. We accom plish t his using t he t xt Convert _KeyPress event . The KeyPress event allows you t o exam ine each charact er t he user t ries t o ent er int o a cont rol before it act ually get s t here. This enables you t o alt er t he charact er, for exam ple by convert ing lowercase charact ers t o uppercase charact ers, or cancel t he charact er ent irely, as we do for any charact er ot her t han 0 t hrough 9 in our exam ple. The code for our t xt Convert _KeyPress event is shown in List ing 20- 12.

List in g 2 0 - 1 2 . Th e t x t Con ve r t _ Ke yPr e ss Eve n t Pr oce du r e

Private Sub txtConvert_KeyPress(KeyAscii As Integer) Select Case KeyAscii Case 8, 48 To 57 ' Backspace and numerals 0 through 9 ' these are all OK. Take no action. Case Else ' No other characters are permitted. KeyAscii = 0 End Select End Sub

The KeyPress event passes us a KeyAscii argum ent t hat is t he ASCI I value of t he charact er t he user is t rying t o ent er. You can m odify t hat charact er by changing t he value of t he KeyAscii argum ent wit h t he KeyPress event . To cancel a charact er you j ust change t he KeyAscii argum ent t o zero, which is t he equivalent of Chr$( 0) or vbNullChar, and t herefore has t he effect of ent ering not hing. I n our t xt Convert _KeyPress event we use a Select Case st at em ent t o handle t he incom ing charact ers. This const ruct m akes it easier t o enable one whole series of charact ers and disable all ot hers. We enable t he Backspace charact er ( t o allow edit ing) and t he num erals 0 t hrough 9 by including t heir ASCI I values in a Case expression t hat t akes no act ion. All ot her charact ers are caught by t he Case Else clause, which cancels t hem by set t ing t he KeyAscii argum ent t o 0. I n t his m anner t he KeyPress event ensures t he value in t he t xt Convert Text Box will always be wit hin t he dom ain of values convert ible t o a Rom an num eral. Speaking of Excel, didn't we say t he point of t his exercise was t o dem onst rat e how t o aut om at e Excel? Well now we have creat ed everyt hing required by our Com m andBut t on's Click event procedure t o use Excel t o convert t he cont ent s of t he t xt Convert Text Box int o an equivalent Rom an num eral. The cm dConvert _Click event t hat accom plishes t his feat is shown in List ing 20- 13.

List in g 2 0 - 1 3 . Th e cm dCon ve r t _ Click Eve n t Pr oce du r e Private Sub cmdConvert_Click() Dim Dim Dim Dim

bError As Boolean xlApp As Excel.Application lConvert As Long sErrMsg As String

' Coerce the text box value into a long. ' Val is required in case it is empty. lConvert = CLng(Val(txtConvert.Text)) ' Don't do anything unless txtConvert contains ' a number greater than zero. If lConvert > 0 Then ' The maximum number that can be converted ' to Roman numeral is 3999.

If lConvert Make Convert ToRom an.exe m enu you will generat e a st andalone execut able file t hat can be run by j ust double- clicking it from Windows Explorer.

Figu r e 2 0 - 2 4 . Th e Com ple t e d Con ve r t t o Rom a n N u m e r a ls D ia log

One of t he first t hings you'll not ice about t he cm dConvert _Click event procedure is t he vast m aj orit y of it has not hing t o do wit h aut om at ing Excel. This is a very im port ant point . I t oft en requires a significant am ount of preparat ion on t he part of t he aut om at ing applicat ion t o ensure Excel will run wit hout error when it is finally st art ed. The first t hing t he cm dConvert _Click event procedure does is t o verify t hat t he input from t he t xt Convert Text Box is wit hin t he bounds t hat can be handled by t he Excel Rom an funct ion. The num ber t o be convert ed t o a Rom an num eral m ust be great er t han 0 and less t han or equal t o 3999. I f t he num ber t hat has been ent ered is out of bounds, an error m essage is displayed t o t he user and t hey are sent back t o t he t xt Convert Text Box t o t ry again. I f t he num ber t o be convert ed is wit hin bounds, t he event procedure creat es an inst ance of Excel and goes t o work. Using Excel t o convert a whole num ber int o a Rom an num eral requires m erely four lines of code ( not count ing variable declarat ions) , but it illust rat es several of t he m ost im port ant point s t o follow when aut om at ing Excel from VB6:

1 . Wherever possible, st art your own inst ance of Excel using t he Set xlApp = New Excel.Application synt ax. Hij acking an exist ing inst ance of Excel using Get Obj ect should be avoided at all cost s. You have no idea what t he user is doing in any exist ing inst ance of Excel and t herefore you cannot be sure you won't cause t hem t o lose dat a. Excel will allow you t o run m ult iple inst ances of it self on t he sam e m achine wit hout any t rouble at all, so design your applicat ions t o creat e and use t heir own privat e inst ance of Excel. 2 . Always fully qualify all references t o Excel obj ect s you use, ult im at ely t ying all of t hem back t o t he Excel Applicat ion obj ect you creat ed. I f you don't do t his you will oft en creat e separat e im plicit global references t o obj ect s wit hin t he inst ance of Excel you are aut om at ing. This will m ake it difficult or im possible t o close your inst ance of Excel when you are finished wit h it . 3 . When you are finished wit h your inst ance of Excel be sure t o explicit ly call t he xlApp.Quit m et hod on t he Excel Applicat ion obj ect . Set t ing t he Excel Applicat ion obj ect variable t o Not hing is not good enough. I f you do not explicit ly quit t he inst ance of Excel you st art ed, you cannot be sure it is not st ill running, even aft er your VB6 applicat ion has exit ed.

I n addit ion, you cannot help but not ice t hat you never saw Excel when running t his exam ple. This is because when an inst ance of Excel is creat ed via aut om at ion it is invisible by default . I n t he St andard EXECreat ing a Front Loader for Your Excel Applicat ion sect ion below, we dem onst rat e not only how t o m ake an aut om at ed inst ance of Excel visible, but how t o t urn it over t o t he user and exit t he VB6 applicat ion t hat st art ed it com plet ely, leaving t he creat ed inst ance of Excel running for t he user. Last ly, if you are expect ing any add- ins or ot her aut o- loaded files t o be open when you creat e an inst ance of Excel via aut om at ion you will be disappoint ed. An inst ance of Excel creat ed via aut om at ion does not load any add- ins t hat are select ed in t he Tools > Add- ins list nor does it load any files locat ed in aut o- st art direct ories like XLSt art . I f your applicat ion depends on t hese files being loaded you will need t o writ e t he code t o open t hem yourself.

Using a VB6 EXE Front Loader for Your Excel Application A VB6 EXE front loader has t he unique abilit y t o exam ine t he configurat ion of a user's com put er wit hout com m it t ing it self t o any specific version of Excel or any ot her applicat ion. I f your Excel applicat ion will be dist ribut ed widely and/ or run on hardware and soft ware over which you have no cont rol, t he front loader can verify t hat everyt hing required t o run your applicat ion is in place prior t o st art ing Excel, running your applicat ion and exit ing. A VB6 EXE front loader can also creat e an inst ance of Excel and st art your applicat ion in it wit hout t riggering any of Excel's m acro securit y feat ures. Wit h a VB6 EXE front loader, you never need t o be concerned about t he user disabling your applicat ion by set t ing m acro securit y t o high. A VB6 EXE front loader can also be used as a securit y m echanism for your applicat ion. The Excel File > Open password is t he only t ruly st rong password Excel has t o offer. But you need t o allow your users t o open your Excel applicat ion in order t o use it . A VB6 EXE front loader neat ly solves t his problem by allowing you t o com pile all of t he File > Open passwords required t o run your applicat ion int o a VB6 EXE. This VB6 EXE can t hen open t he Excel files required by your applicat ion wit hout ever exposing t heir passwords t o VBA's weak proj ect prot ect ion.

N OTE Any password st ored as a lit eral st ring in any applicat ion is vulnerable t o an experienced program m er wit h a good hex edit or. Therefore, if you want your passwords t o be t ruly secure you m ust st ore t hem in an encrypt ed form at and use a procedure t o decrypt t hem j ust before t hey are required by your code. But keep in m ind t hat j ust com piling your passwords int o a VB6 EXE front loader will elim inat e t he abilit y of at least 99 percent of hackers t o break int o your applicat ion. Adding an encrypt ion layer m ight increase t his t o 99.9 percent . For t he vast m aj orit y of real- world applicat ions, adding an encrypt ion layer is sim ply not wort h t he effort .

Practical Examples ActiveX DLLUsing a Resource File to Load Icons Adding a Resource File to Your Project To use resource files in VB6, you m ust have t he VB6 Re sou r ce Edit or add- in loaded in t he VB6 I DE. I f t his add- in is loaded you will see a Proj ect > Add New Resource File m enu it em on t he VB6 m enu bar. I f you do not see t his m enu, choose Add- ins > Add- in Manager from t he VB6 m enu. This will display t he Add- in Manager dialog shown in Figure 20- 25.

Figu r e 2 0 - 2 5 . Th e Add- in M a n a ge r D ia log

The list of available add- ins will likely be different on your syst em , but locat e t he VB6 Resource

Edit or add- in as shown and under t he Load Behavior sect ion of t he Add- in Manager dialog check t he Loaded/ Unloaded and Load on St art up check boxes. Aft er t he Resource Edit or add- in is inst alled, m ake sure your proj ect has been saved and t hen choose Proj ect > Add New Resource File from t he VB6 m enu t o add a resource file t o your proj ect . You will be prom pt ed wit h t he rat her confusingly nam ed Open a Resource File dialog shown in Figure 20- 26.

Figu r e 2 0 - 2 6 . Th e Ope n a Re sou r ce File D ia log

This dialog can be used t o eit her add an exist ing resource file t o your applicat ion or creat e a new resource file. We'll creat e a new resource file. Navigat e t o t he folder where your proj ect is saved and t ype t he nam e you want t o give your resource file, wit hout t he .RES ext ension, int o t he File n am e box. When you click t he Open but t on, t he Resource Edit or will prom pt you wit h t he m essage shown in Figure 20- 27. ( We have chosen t he filenam e I cons because t hat is what we will be st oring in t his resource file.) Click t he Yes but t on and an em pt y resource file will be creat ed and added t o your proj ect .

Figu r e 2 0 - 2 7 . Cr e a t in g a N e w Re sou r ce File

The Proj ect window view of our Act iveX DLL proj ect cont aining t he I cons.res resource file is shown in Figure 20- 28. As you will see lat er in t his exam ple, t he CResourceProvider class will be used t o expose t he bit m aps cont ained in t he resource file t o out side callers as St dPict ure obj ect s. This is t he obj ect t ype required t o set t he Pict ure and Mask propert ies for Excel 2002 and lat er com m and bar cont rols.

Figu r e 2 0 - 2 8 . Th e Re sou r ce s Act ive X D LL Pr oj e ct

Adding Bitmaps to the Resource File You can add icons, bit m aps or cust om binary resources t o your resource file. Because t he ult im at e t arget for our resources are com m and bar cont rol icons, we load t hem as bit m aps. Bit m aps have t he advant age of being very sim ple. They can be creat ed using not hing m ore t han t he Paint program t hat ships wit h every copy of Windows. The only rest rict ion is t hat bit m aps designed t o be com m and bar but t on icons m ust be 16 pixels by 16 pixels in size in order t o provide t he opt im al appear ance. I n t his sect ion, we load t wo bit m aps int o our resource file: a com m and bar but t on icon and it s

corresponding m ask. We use t he cust om arrow icon and m ask we saw in Chapt er 8 Adv anced Com m and Bar Handing for dem onst rat ion purposes. To begin t he process, double- click t he resource file in t he VB6 Proj ect window in order t o open it in t he Resource Edit or. The current ly em pt y resource file will open in t he Resource Edit or as shown in Figure 20- 29. The t op line in t he Resource Edit or displays t he full pat h and filenam e of t he resource file being edit ed.

Figu r e 2 0 - 2 9 . Th e Em pt y I con s.r e s File Ope n e d in t h e Re sou r ce Edit or

To add a bit m ap t o t he resource file, click t he Add Bit m ap t oolbar but t on on t he Resource Edit or t oolbar. This is t he t hird but t on from t he right in Figure 20- 29. The Resource Edit or will display t he Open a Bit m ap File dialog shown in Figure 20- 30.

Figu r e 2 0 - 3 0 . Th e Ope n a Bit m a p File D ia log

We have already navigat ed t o t he folder cont aining t he t wo bit m aps we want t o load and select ed t he first one. As you can see, t he Open a Bit m ap File dialog displays a preview of t he select ed bit m ap in it s right pane. Click t he Open but t on t o add t he select ed Arrows.bm p bit m ap t o t he resource file. The result is shown in Figure 20- 31.

Figu r e 2 0 - 3 1 . Th e I con s.r e s Re sou r ce File Con t a in in g On e Bit m a p

The Resource Edit or has given our bit m ap t he default I D propert y value 101. You can m odify t his value by select ing t he bit m ap resource and clicking t he Edit Propert ies t oolbar but t on. I n t he next sect ion we'll use an enum erat ion t o m ap t hese num eric I Ds ont o som et hing m ore recognizable. Repeat t he st eps above t o load t he ArrowsMask.bm p resource int o t he resource file. This will be given t he default I D propert y value 102. Click t he Save icon t o save t he resource file and t hen close t he Resource Edit or using t he X- Close but t on in t he upper right corner. An im port ant point t o not e is t hat adding bit m aps t o your resource file copies t hem int o it . The original bit m ap files you select ed are st ill in t heir original locat ion and t hey are not connect ed t o t he copies cont ained in t he resource file in any way.

Using Bitmaps Located in the Resource File A sim ple, one- line propert y procedure in t he CResourceProvider class m odule will ret urn any of t he bit m ap resources st ored in our resource file. All t hat will be required is t o pass t his propert y procedure t he enum erat ion value ( discussed below) ident ifying t he resource you want t o ret rieve. The propert y procedure will ret urn a reference t o t he specified resource as an St dPict ure obj ect . The ent ire cont ent s of t he CResourceProvider class m odule are shown in List ing 20- 14.

List in g 2 0 - 1 4 . Th e I con Pr ope r t y Pr oce du r e Public Enum resIcon resIconArrows = 101

resIconArrowsMask = 102 End Enum Public Property Get Icon(ByVal uName As resIcon) As StdPicture Set Icon = LoadResPicture(uName, vbResBitmap) End Property

As you can see, we have used an enum erat ion t o provide readable nam es for t he num eric I D propert y values t hat ident ify t he bit m ap resources in our resource file. I nside t he propert y procedure t he VB LoadResPict ure funct ion is used t o ret rieve t he specified resource from t he resource file. The first argum ent t o t his funct ion specifies which resource should be ret urned. The second argum ent specifies t he t ype of t he resource t o be ret urned using a built - in VB const ant , in t his case vbResBit m ap. Aft er you have com piled t he Resources Act iveX DLL, any program capable of consum ing a St dPict ure obj ect can use t he resources it cont ains. To dem onst rat e t he use of t his DLL, we rework t he Load Pict ure and Mask exam ple from Chapt er 8 Advanced Com m and Bar Handling t o ret rieve it s icons from t he Resource DLL rat her t han loading t hem from individual bit m ap files on disk. The procedures shown in List ing 20- 15 build a com m and bar wit h a single but t on t hat uses our cust om arrow icon and m ask loaded from t he Resources DLL.

List in g 2 0 - 1 5 . Loa din g a Cu st om I con fr om a Re sou r ce File in t o a Com m a n d Ba r Bu t t on Public Sub CreateBar() Dim cbrBar As CommandBar Dim ctlControl As CommandBarButton Dim objRes As Resources.CResourceProvider ' Make sure any previously created version of our demo ' command bar is deleted. RemoveBar ' Create an instance of the resource provider. Set objRes = New Resources.CResourceProvider ' Create a toolbar-type command bar. Set cbrBar = CommandBars.Add("Demo", msoBarTop, False, True) cbrBar.Visible = True ' Add the command bar button control. Set ctlControl = cbrBar.Controls.Add(msoControlButton) ' Load the foreground bitmap file. ctlControl.Picture = objRes.Icon(resIconArrows) ' Load the mask bitmap file. ctlControl.Mask = objRes.Icon(resIconArrowsMask)

End Sub Public Sub RemoveBar() On Error Resume Next CommandBars("Demo").Delete End Sub

The com plet e code for t his exam ple can be found in t he LoadPict ureAndMask.xls workbook locat ed on t he CD in t he \ Concept s\ Ch20Com bining Excel and Visual Basic 6 folder. Not e t hat t his exam ple will only work in Excel 2002 or lat er and you m ust have regist ered t he Resources Act iveX DLL on your com put er. Not ice how t he Pict ure and Mask propert ies of our com m and bar but t on in t his exam ple are now ret rieving t heir cont ent s from t he cust om resource file in our DLL rat her t han from bit m ap files st ored on disk.

Standard EXECreating a Front Loader for Your Excel Application An applicat ion ut ilizing a VB6 front loader begins wit h t he execut ion of a VB6 applicat ion rat her t han an Excel applicat ion. The corresponding Excel applicat ion is only execut ed if t he condit ions being verified by t he front - loader applicat ion are m et by t he syst em on which t he applicat ion is execut ing. We covered t he reasons for using a VB6 EXE front loader in your Excel applicat ion in t he Using a VB6 EXE Front Loader for Your Excel Applicat ion sect ion above. I n t his sect ion we focus on how t o build a VB6 EXE front loader. I n t his exam ple, we assum e t hat t he t ask of our front loader is t o verify Word and Out look are correct ly inst alled on t he user's com put er before running our PETRAS t im esheet applicat ion. St art by opening VB6 and choosing St andard EXE as t he proj ect t ype in t he New Proj ect dialog. I n addit ion t o t he default form obj ect t hat VB6 provides wit h t his proj ect t ype add one st andard code m odule t o your proj ect using t he Proj ect > Add Module m enu. Renam e your default obj ect s t o t he nam es shown in Table 20- 2 .

Ta ble 2 0 - 2 . Fr on t Loa de r Applica t ion Obj e ct N a m e s D e fa u lt Obj e ct Nam e

N e w Obj e ct N a m e

Proj ect 1

Fr ont Loader

For m 1

FWar ning

Module1

MEnt r yPoint s

Next , set a reference t o t he Microsoft Excel Obj ect Library using t he Proj ect > References m enu.

Finally, save your proj ect 's files t o a com m on folder. The end result as displayed in t he Proj ect window should look like Figure 20- 32.

Figu r e 2 0 - 3 2 . Th e St r u ct u r e of t h e Fr on t Loa de r Applica t ion

When you creat e a St andard EXE proj ect , t he default st art up obj ect is t he form obj ect t hat is added by default when t he proj ect is first creat ed. This is not how we want our front loader applicat ion t o work. I nst ead, we add a special procedure t o t he MEnt ryPoint s m odule called Sub Main. We t hen m odify our proj ect 's propert ies so t hat Sub Main is run on st art up rat her t han t he default form . Open t he MEnt ryPoint s m odule and creat e t he Sub Main st ub procedure shown in List ing 20- 16.

List in g 2 0 - 1 6 . Th e Su b M a in St u b Pr oce du r e Public Sub Main() ' Code goes here later. End Sub

We m ust now t ell t he proj ect t hat we want our Sub Main procedure t o be execut ed when our VB6 EXE is first run. This is accom plished using t he Proj ect > Front Loader Propert ies…m enu. As shown in Figure 20- 33, we have changed t he St art up Obj ect set t ing in t he upper right corner of t he Proj ect Propert ies dialog General t ab from FWarning ( t he default ) t o Sub Main.

Figu r e 2 0 - 3 3 . Ch a n gin g t h e St a r t u p Obj e ct t o Su b M a in

Next we build t he FWarning form . This form is relat ively uncom plicat ed. I t s only purpose is t o not ify t he user t hat t he validat ion check failed prior t o t he front loader exit ing wit hout st art ing t he Excel applicat ion. First we'll set t he propert ies of t he form obj ect it self as shown in Table 20- 3 .

Ta ble 2 0 - 3 . FW a r n in g Pr ope r t y Se t t in gs Pr ope r t y N a m e

Se t t in g

Bor der St yle

3 Fixed Dialog

Capt ion

St art up Validat ion Failed

I con

Pet rasI con.ico ( supplied on t he CD)

St art upPosit ion

2 Cent er Screen

Rat her t han displaying t he bland, default VB6 icon for our final Front Loader.exe applicat ion, we

want t o use t he sam e branded PETRAS icon t hat we used in our FWarning form . To accom plish t his, select t he Proj ect > Front Loader Propert ies m enu and t hen select t he Mak e t ab in t he Proj ect Propert ies dialog. As shown in Figure 20- 34, select FWarning from t he I con dropdown in t he upperright corner. This will m ake t he icon defined for t he FWarning dialog be t he icon displayed for our Front Loader.exe file in Windows Explorer and by any short cut s we creat e t o it .

Figu r e 2 0 - 3 4 . M odifyin g t h e I con D ispla ye d by Ou r Fr on t Loa de r .e x e File

The FWarning form it self will cont ain only t wo cont rols: a cm dOK Com m andBut t on t o dism iss t he form and a st at ic Label cont rol t o display t he validat ion failure m essage t o t he user. The form should look sim ilar t o t he one displayed in Figure 20- 35.

Figu r e 2 0 - 3 5 . Th e La you t of t h e FW a r n in g D ia log

The click event of t he cm dOK but t on is displayed in List ing 20- 17. I t j ust unloads t he form aft er t he user has read t he m essage.

List in g 2 0 - 1 7 . Th e cm dOK_ Click Eve n t Pr oce du r e Private Sub cmdOK_Click() Unload Me End Sub

The decision whet her t o run t he Excel applicat ion or display t he FWarning m essage will be m ade by t he code logic cont rolled by t he Sub Main procedure. Our Word and Out look validat ion logic will be encapsulat ed in t wo separat e funct ions. One will det erm ine whet her Word is inst alled and operat ing correct ly and t he ot her will do t he sam e for Out look. Two funct ions are required because t he t wo applicat ions behave different ly when aut om at ed. When your applicat ion creat es an inst ance of Word via aut om at ion you always get a brand new hidden inst ance of Word, regardless of whet her t he user is current ly running Word. Wit h Out look, t he result of creat ing an inst ance via aut om at ion depends on whet her t he user already has Out look open. I f Out look is already open, you get a reference t o t he current ly open inst ance. I f Out look is not open, you get a new hidden inst ance. For our validat ion logic we use t he m ost rigorous t est possible, whet her or not we can act ually get a reference t o running inst ances of Word and Out look. The funct ions t hat will perform t he validat ion for t he st at us of Word and Out look are shown in List ing 20- 18.

List in g 2 0 - 1 8 . Th e bW or dAva ila ble a n d bOu t look Ava ila ble Fu n ct ion s

Private Function bWordAvailable() As Boolean Dim wdApp As Object ' Attempt to start an instance of Word. On Error Resume Next Set wdApp = CreateObject("Word.Application") On Error GoTo 0 ' Return the result of the test. If Not wdApp Is Nothing Then ' If we started Word we need to close it. wdApp.Quit Set wdApp = Nothing bWordAvailable = True Else bWordAvailable = False End If End Function Private Function bOutlookAvailable() As Boolean Dim bWasRunning As Boolean Dim olApp As Object On Error Resume Next ' Attempt to get a reference to a currently open ' instance of Outlook. Set olApp = GetObject(, "Outlook.Application") If olApp Is Nothing Then ' If this fails, attempt to start a new instance. Set olApp = CreateObject("Outlook.Application") Else ' Otherwise flag that Outlook was already running ' so that we don't try to close it. bWasRunning = True End If On Error GoTo 0 ' Return the result of the test. If Not olApp Is Nothing Then ' If we started Outlook we need to close it. If Not bWasRunning Then olApp.Quit Set olApp = Nothing bOutlookAvailable = True Else bOutlookAvailable = False End If End Function

The first t hing t o not ice is t hat we're using lat e binding in bot h of t hese validat ion funct ions. I f we didn't use lat e binding and t ried t o run our front loader on a com put er t hat didn't have Word or Out look inst alled, t he front loader would fail before it ever got t he chance t o run t he validat ion funct ions. This is t he result of using a com piled vs. an int erpret ed program m ing language. When you run an

Excel VBA applicat ion, it s code is validat ed by t he VBA runt im e on a m odule- by- m odule basis. The code in any given m odule is only validat ed when som e code in t hat m odule is called or referenced by t he applicat ion. This m eans, for exam ple, t hat if you had a reference t o an invalid com ponent in your Excel VBA proj ect , but t he code m aking use of t his reference was confined t o one m odule and no code in t hat m odule was ever called or referenced by your applicat ion, t hat m odule would never be loaded by t he VBA runt im e, it s code would never be validat ed and your applicat ion would not experience a runt im e error. I n a fully com piled applicat ion, all references are validat ed on st art up. Therefore, if you reference a com ponent t hat doesn't exist on t he m achine where your fully com piled applicat ion is run, t he applicat ion fails im m ediat ely. The second t hing t o not ice is t he difference bet ween t he bWordAvailable and bOut lookAvailable funct ions. Because aut om at ing Word is very st raight forward, we j ust at t em pt t o creat e a new inst ance of Word and t he result of t he funct ion is det erm ined by whet her we succeed or fail. The logic of t he Out look validat ion funct ion is exact ly t he sam e, but due t o t he different behavior of Out look t he im plem ent at ion is different . Rat her t han j ust at t em pt ing t o creat e a new inst ance of Out look we first need t o t ry t he Get Obj ect funct ion. This will ret urn a reference t o any inst ance of Out look t he user is current ly running. I f t his succeeds, it sat isfies our validat ion t est . I f t he user can successfully run Out look we can be reasonably sure t hat our applicat ion can as well. I f we are not able t o locat e a current ly running inst ance of Out look, we t hen t ry t o creat e a new one using t he Creat eObj ect funct ion. I f t his succeeds we have validat ed t he availabilit y of Out look, but we have also st art ed a new inst ance of Out look t hat needs t o be closed before our funct ion exit s. This is t he point where t he logic of t he bWordAvailable and bOut lookAvailable funct ions diverge. I f t he bWordAvailable funct ion succeeds t hen we know we have st art ed a new inst ance of Word t hat we m ust close before t he funct ion exit s. I f t he bOut lookAvailable funct ion succeeds, whet her or not we need t o close Out look on exit depends on whet her or not our funct ion act ually st art ed t he inst ance of Out look t hat validat ed it s availabilit y or whet her we sim ply at t ached t o an inst ance of Out look t he user was already running. I f t he Get Obj ect funct ion ret rieved our reference t o Out look t hen we leave it alone. I f Creat eObj ect ret rieved our reference t o Out look t hen we m ust close t hat inst ance of Out look before we exit . This is t he purpose of t he bWasRunning variable in t he bOut lookAvailable funct ion. I t t ells us whet her we need t o close Out look at t he end of t he funct ion. Now t hat we have seen all t he pieces of t he front - loader applicat ion, let 's look at t he procedure t hat brings t hem all t oget her. As we st at ed earlier, t he Sub Main procedure is t he cont rolling procedure in our front - loader applicat ion. I t calls t he validat ion funct ions, exam ines t heir result s, and based on t hose result s it det erm ines whet her t o run our Excel applicat ion or display a warning m essage and exit . The Sub Main procedure is shown in List ing 20- 19.

List in g 2 0 - 1 9 . Th e Su b M a in Pr oce du r e Public Sub Main() Dim Dim Dim Dim

bHasWord As Boolean bHasOutlook As Boolean xlApp As Excel.Application wkbPetras As Excel.Workbook

Dim frmWarning As FWarning ' Verify that we can automate both Word and Outlook on ' this computer. bHasWord = bWordAvailable() bHasOutlook = bOutlookAvailable() If bHasWord And bHasOutlook Then ' If we successfully automated both Word and Outlook, ' load our Excel app and turn it over to the user. Set xlApp = New Excel.Application xlApp.Visible = True xlApp.UserControl = True Set wkbPetras = xlApp.Workbooks.Open(App.Path & _ "\PetrasAddin.xla") wkbPetras.RunAutoMacros xlAutoOpen Set wkbPetras = Nothing Set xlApp = Nothing Else ' If we failed to get a reference to either Word or ' Outlook, display a warning message to the user and ' exit without taking further action. Set frmWarning = New FWarning frmWarning.Show Set frmWarning = Nothing End If End Sub

There are t wo t hings in part icular t o not e about t he way t he Sub Main procedure handles Excel. First , aft er creat ing an inst ance of Excel and m aking it Visible, it set s t he Excel Applicat ion obj ect 's UserCont rol propert y t o True. This m akes t he Excel Applicat ion behave as if it had been st art ed direct ly by t he user rat her t han via aut om at ion. Second, aft er opening t he PETRAS applicat ion workbook, it runs t he RunAut oMacros m et hod of t he Workbook obj ect . This is because t he Aut o_Open procedure will not run aut om at ically when an Excel workbook is opened via aut om at ion. Therefore, we need t o run it ourselves. As m ent ioned previously in t he An Excel Aut om at ion Prim er sect ion, an Excel Applicat ion obj ect creat ed via aut om at ion will also not open any add- ins specified in t he Tools > Add- ins list nor any workbooks locat ed in st art up folders like XLSt art . I f your applicat ion relies on any secondary

Conclusion There are m any good reasons t o t ake advant age of t he addit ional power afforded by VB6 in your Excel VBA applicat ions. VB6 Act iveX DLLs provide code prot ect ion, t he abilit y t o use t he m ore powerful VB6 form s in your Excel proj ect s, excellent support for obj ect - orient ed program m ing, support for resource files and a num ber of m iscellaneous feat ures not available in VBA, including t he Clipboard, Print er and Screen obj ect s. VB6 EXE applicat ions enable you t o aut om at e Excel, init iat ing your applicat ion from VB6 rat her t han Excel. This allows you t o creat e com ponent s such as front loaders. These can scan t he operat ing environm ent for you prior t o st art up t o ensure t hat your applicat ion has t he required resources available, allow you an ext ra level of VBA code prot ect ion by com piling your File > Open passwords in an EXE file, and let you st art Excel and run your VBA applicat ion wit hout t riggering any VBA m acro securit y feat ures.

Chapter 21. Writing Add-ins with Visual Basic 6 Ever since VBA was added t o Excel 5.0, we've been able t o add feat ures t o Excel by creat ing add- in workbooks, as discussed in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins. Word, Access and PowerPoint had t heir own applicat ion- specific add- in archit ect ures. I n Office 2000, Microsoft creat ed a new add- in archit ect ure, called a COM Add- in, which was com m on t o all t he Office applicat ions and t he VBI DE. This chapt er explains how t o creat e COM Add- ins using Visual Basic 6. Chapt er 22 Using VB.NET and t he Visual St udio Tools for Office explains how t o achieve sim ilar result s using Visual Basic.NET.

A Hello World Add-in At it s m ost fundam ent al level, an add- in archit ect ure has four basic requirem ent s: A m echanism for t elling t he host applicat ion t hat t he add- in exist s. A m echanism for t he host applicat ion t o call a procedure in t he add- in when t he add- in is loaded, usually during t he applicat ion's st art up processing. At t his point , t he add- in set s up it s m enu it em s, t oolbar but t ons and/ or short cut keys A m echanism for raising event s t hat t he add- in can respond t o. A m echanism for t he host applicat ion t o call a procedure in t he add- in when t he add- in is unloaded, usually during t he applicat ion's shut down processing. For Excel add- ins, we can eit her put t he add- in file in t he XLSt art folder ( so it 's always inst alled for all users) or use t he Tools > Add- ins dialog t o select t he add- in file and m ark it as inst alled ( on a per- user basis) . When Excel st art s up, it sees t he add- in, opens t he file and runs t he st art up procedure. When Excel 5 had loaded t he add- in, it called t he special Aut o_Open procedure and prior t o shut t ing down, it called t he special Aut o_Close procedure. Bot h procedures were placed in a st andard VBA m odule ( t he only m odule t ype t hat exist ed at t he t im e! ) . A Hello World add- in looked like List ing 21- 1.

List in g 2 1 - 1 . A H e llo W or ld Add- in Usin g Au t o_ Ope n in a St a n da r d M odu le 'Run when the add-in is loaded Sub Auto_Open() MsgBox "Hello World" End Sub 'Run when the add-in is closed Sub Auto_Close() MsgBox "Goodbye World" End Sub

When t he VBI DE was int roduced in Excel 97, every workbook was given a ThisWorkbook class m odule, wit hin which we could writ e code t o respond t o a num ber of workbook- relat ed event s, including Workbook_Open and Workbook_BeforeClose. These procedures were also called when Excel 97 opened and closed an add- in workbook. List ing 21- 2 shows a Hello World add- in t hat uses workbook event s.

List in g 2 1 - 2 . A H e llo W or ld Add- in Usin g W or k book Eve n t s in t h e Th isW or k book M odu le 'Run when the add-in is loaded Private Sub Workbook_Open() MsgBox "Hello World" End Sub 'Run when the add-in is closed Private Sub Workbook_BeforeClose(Cancel As Boolean) MsgBox "Goodbye World" End Sub

Bot h t he Aut o_Open and Workbook_Open m et hods cont inue t o work in all recent versions of Excel and which one t o use is a m at t er of personal preference. So let 's do t he sam e wit h Visual Basic 6. St art VB and select t he Addin proj ect t ype from t he New Proj ect dialog. This creat es a new COM Add- in proj ect called MyAddin, wit h a default form and Designer class called Connect . We prefer t o always st art wit h a clean proj ect , so change t he proj ect nam e t o HelloWorld, rem ove t he default form and delet e all t he exist ing code from t he Connect class. The Add- in Designer is t he COM Add- in equivalent of Excel's ThisWorkbook class and handles all t he com m unicat ion bet ween Excel and t he COM Add- in. I t has a sim ple UI for us t o set t he addin's propert ies, such as it s t it le, descript ion and which Office applicat ion it t arget s, as shown in Figure 21- 1, where we've com plet ed it for our Hello World exam ple. We cover t he dialog's opt ions in m ore det ail lat er.

Figu r e 2 1 - 1 . Th e Com ple t e d Add- in D e sign e r D ia log

Excel's ThisWorkbook class gives us a Workbook obj ect t hat has t he Open and BeforeClose event s t hat we use for our st art up and shut down code. The equivalent in t he Add- in Designer class is t he AddinI nst ance obj ect and OnConnect ion and OnDisconnect ion event s, shown in Figure 21- 2.

Figu r e 2 1 - 2 . Th e Addin I n st a n ce Obj e ct a n d Eve n t s

List ing 21- 3 uses t hese t wo event s for our Hello World COM Add- in.

List in g 2 1 - 3 . A H e llo W or ld COM Add- in 'Run when the add-in is loaded Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As _ AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, _ custom() As Variant) MsgBox "Hello World" End Sub 'Run when the add-in is unloaded Private Sub AddinInstance_OnDisconnection( _ ByVal RemoveMode As _ AddInDesignerObjects.ext_DisconnectMode, _ custom() As Variant) MsgBox "Goodbye World" End Sub

The only difference bet ween t his code and t he workbook add- in is t hat t he t wo event s have m any m ore param et ers ( described lat er) . To build t he add- in, save all t he proj ect files and click File > Make HelloWorld.DLL. Now st art Excel 2000 or above and you should see t he Hello World m essage box appear. Close Excel and t he Goodbye World m essage box pops up. Congrat ulat ions, you've creat ed a COM Add- in! The first t hing you'll want t o do now is swit ch it off! All t he Office applicat ions have a COM Add- ins dialog t o enable or disable COM Add- ins, but it is not included on t he default set of m enus. To add it , right - click a t oolbar, choose Cust om ize, select t he Com m ands t ab and find COM Add- ins…

halfway down t he list for t he Tools cat egory. Drag it t o Excel's Tools m enu. Figure 21- 3 shows t he COM Add- ins dialog wit h our add- in select ed. The add- in can be disabled by unt icking it or rem oved from t he list by clicking t he Rem ove but t on.

Figu r e 2 1 - 3 . Th e COM Add- in s D ia log

The Add-in Designer Excel's Tools > Add- ins dialog is act ually a sim ple UI t hat handles t he following t wo regist ry keys ( where t he 10.0 indicat es t he version of Office) : HKEY_CURRENT_USER\ Soft ware\ Microsoft \ Office\ 10.0\ Excel\ Add- in Manager HKEY_CURRENT_USER\ Soft w ar e\ Micr osoft \ Office\ 10.0\ Excel\ Opt ions The first key list s t he full pat h of any add- in workbooks t hat are not in Excel's Library folder ( t hat is, where we've used t he Browse but t on t o locat e t he add- in) and are not inst alledt hey j ust appear unt icked in t he Tools > Add- ins list . The second key cont ains a num ber of OPENx values, list ing t he full pat h for all add- in workbooks t hat are inst alledt hat is, t icked in t he Tools > Add- ins list . These regist ry ent ries are covered in m ore det ail in Chapt er 24 Providing Help, Securing, Packaging and Dist ribut ing. To check for inst alled add- ins when Excel st art s up, it looks for t he OPENx ent ries in t he Excel\ Opt ions key, opens t hose workbooks and calls t he Aut o_Open and/ or Workbook_Open procedures t herein. To check for inst alled COM Add- ins, Excel looks in t he regist ry t o see whet her t here are any keys below HKEY_CURRENT_USER\ Soft ware\ Microsoft \ Office\ Excel\ Addins. Each COM Add- in adds a key below t hat wit h t he ProgI D of it s Add- in Designer class, having t he form < Proj ect Nam e> .< Designer Nam e> . I n our case, t he key is called HelloWorld.Connect . Wit hin t hat key are a num ber of regist ry ent ries t hat direct ly correspond t o t he opt ions on t he Designer form , shown in Figure 21- 1 earlier. When t he proj ect is built and t he DLL is regist ered, t he Designer writ es t he regist ry values int o t he HKEY_CURRENT_USER key ( com m only referred t o using it s acronym HKCU) t o inst all t he add- in for t he current user. These values and opt ions are det ailed below.

General Tab For convenience, t he General t ab of t he Add- in Designer is repeat ed in Figure 21- 4.

Figu r e 2 1 - 4 . Th e Ge n e r a l Ta b of t h e D e sign e r D ia log

Add-in Display Name This is t he nam e displayed in Excel's Tools > COMAdd- ins dialog box. I t is st ored in t he regist ry in t he Fr iendlyNam e value.

Add-in Description Excel does not display t he descript ion anywhere. I f writ ing a COM Add- in t hat t arget s t he VBI DE, t he descript ion is shown in t he VBE's Add- in Manager dialog when t he add- in is select ed. I t is st ored in t he regist ry in t he Descr ipt ion value.

Application A drop- down list of all t he inst alled applicat ions t hat can be ext ended using COM Add- ins. Select ing t his list det erm ines which key is used for t he regist ry ent ries, such as: Excel:

HKCU\ Soft w ar e\ Micr osoft \ Office\ Excel\ Addins

Wor d:

HKCU \ Soft w ar e\ Micr osoft \ Office\ Wor d\ Addins

VBI DE:

HKCU \ Soft w ar e\ Micr osoft \ VBA\ VBE\ 6.0\ Addins

Application Version A drop- down list of all t he inst alled versions of t he select ed applicat ion. The observant reader m ight have not iced t hat when we built our Hello World COM Add- in above, it was im m ediat ely working in Excel 2000, 2002 and 2003. This is because t he Applicat ion Version is ignored for Excel COM Addins; t he det ails always get writ t en t o t he sam e regist ry key of HKCU\ Soft ware\ Microsoft \ Office\ Excel\ Addins. When writ ing COM Add- ins t hat t arget t he VBI DE, t he version ( 6.0) is included in t he regist ry key. Of course, we've yet t o see anyt hing ot her t han version 6.0 of t he VBI DE!

Initial Load Behavior A set of four choices t hat cont rol whet her and how Excel loads our add- in. The choice is st ored in t he LoadBehav ior value and can be one of t he following: St ar t up, value = 3: The add- in is loaded every t im e Excel st art s. This is t he m ost com m on load behavior set t ing. None, value = 0: The add- in is not loaded and does not appear in t he Tools > COMAdd- ins dialog. This opt ion would be select ed if t he COM Add- in is t o be inst alled for all users. See I nst allat ion Considerat ions lat er for m ore det ails. Load on Dem and, value = 9: The add- in is loaded t he first t im e one of it s m enu it em s is clicked. I t is highly unusual for t his value t o be set wit hin t he Designer. Load at Next St art up Only, value = 16: The add- in is loaded t he first t im e Excel is st art ed aft er t he add- in is inst alled, so it can add it s m enu it em s perm anent ly t o Excel's com m and bars. Once loaded, Excel changes t his value t o 9 ( Load on Dem and) , so it is loaded t he first t im e one of it s m enu it em s is clicked. See Com m and Bar Handling lat er for m ore det ails.

Advanced Tab

The Advanced t ab of t he Add- in Designer is shown in Figure 21- 5.

Figu r e 2 1 - 5 . Th e Adva n ce d Ta b of t h e D e sign e r D ia log

Satellite DLL Name The COM Add- in archit ect ure has been designed t o allow easy localizat ion. This m eans t hat inst ead of st oring t he t ext of t he add- in's nam e and descript ion in t he regist ry, we can st ore t hose st rings in a resource t able in a separat e DLL. We can t hen use a st andard Windows resource edit or t o

t ranslat e t he t ext int o localized versions of t he DLL. I n t he Designer form , we t ype in t he resource I Ds inst ead of t he nam e and descript ion and provide t he nam e of t he DLL cont aining t he resource t able in t his field ( st ored as Sat ellit eDLLNam e in t he regist ry) . When Excel needs t o show t he Display Nam e in t he Tools > COMAdd- ins dialog, it should recognize t hat a resource DLL is being used and ext ract t he display nam e from t he resource t able. Unfort unat ely, however, Excel doesn't check for t he resource DLL and always displays t he m eaningless resource I D inst ead! The use of a sat ellit e DLL in t his way works correct ly for add- ins t arget ing t he VBI DE.

Registry Key for Additional Add-in Data and Add-in-Specific Data When t he COM Add- in is inst alled, we have t he opt ion of writ ing addit ional ent ries in t he regist ry. These fields specify t he ent ries t o writ e and t he regist ry key where t hose ent ries will be writ t en. They are m ost oft en used if t he COM Add- in is t o be inst alled for all users. See I nst allat ion

Installation Considerations A COM Add- in is an Act iveX DLL t hat needs t o be regist ered on t he com put er before it can be used. The regist rat ion is done by a program called regsvr32.exe, usually found in t he C: \ Window s\ Syst em 32 direct ory. The easiest way t o do it m anually is t o right - click t he DLL, choose Open Wit h…and browse t o t he regsvr32.exe file. You can also use t he A d d …but t on on Excel's COM Add- ins dialog and browse t o t he DLL. A final alt ernat ive is t o use a set up program , which should aut om at ically regist er any Act iveX DLLs it inst alls. All of t hese m et hods call a special funct ion wit hin t he DLL, t elling it t o writ e what ever regist ry ent ries it requires t o work. For COM Add- ins, t he Designer ensures t his includes t he regist ry ent ries required t o get it working wit h Excel. The Designer, however, only writ es t he ent ries required t o inst all t he add- in for t he current user ( t hat is, under t he HKEY_CURRENT_USER sect ion of t he r egist r y ) . Excel also allows add- ins t o be inst alled for all users of t he m achine. As well as looking wit hin t he HKCU sect ion, it also looks in t he sam e pat h of t he HKEY_LOCAL_MACHI NE sect ion ( oft en referred t o as HKLM) . I f we want our add- in t o be inst alled for all users, we have t o set t he Designer's I nit ial Load Behavior t o None and use t he Advanced t ab t o add our own regist ry ent ries, as shown in Figure 21- 6. Not e t hat t he LoadBehav ior value is a DWORD t ype, whereas t he ot her t wo are st r ings.

Figu r e 2 1 - 6 . Th e Adva n ce d Ta b of t h e D e sign e r D ia log, Sh ow in g t h e En t r ie s for a n All- Use r I n st a lla t ion

COM Add- ins t hat are inst alled in t his way do not show up in t he COM Add- ins dialog and can only be uninst alled by delet ing t he regist ry ent ries using regedit ( which you m ight want t o do right now! ) . They will also obviously require access t o t he HKLM sect ion of t he regist ry, which is usually only grant ed t o people in t he Power Users or Adm inist rat ors net work groups. Mem bers of t he basic Users group will not be able t o inst all ( or uninst all) t he add- in.

The AddinInstance Events Now t hat we've creat ed, inst alled and t est ed a sim ple Hello World COM Add- in, it 's t im e t o t ake a m ore det ailed look at how Excel int eract s wit h t he COM Add- in, using t he Designer's code m odule. During t he life of a session, Excel t ells us what 's going on by raising event s t hrough t he Designer's AddinI nst ance obj ect , in exact ly t he sam e way t hat it raises event s t hrough t he Workbook obj ect of a workbook's ThisWorkbook code m odule. These event s are list ed below, in t he order in which t hey're fired during a t ypical Excel session.

Initialize Private Sub AddinInstance_Initialize()

The I nit ialize event is fired when t he class is first inst ant iat ed and is exact ly t he sam e as t he Class_I nit ialize event of a class m odule. I t 's rare t o see t his event used.

OnConnection Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As _ AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, _ custom() As Variant)

Every COM Add- in uses t he OnConnect ion event , which is raised by Excel during it s st art up processing, when a dem and- loaded add- in is loaded ( see t he Com m and Bar Handling sect ion lat er) or when t he add- in is enabled in t he COM Add- ins dialog. This is t he equivalent of t he VBA Aut o_Open or Workbook_Open procedures and should be used t o init ialize t he proj ect , set up m enu it em s and so on. This procedure should not display any form s or show any m essage boxes. The Application param et er is a reference t o t he host 's Applicat ion obj ect ( Excel.Applicat ion in our case) . Most add- ins will assign t his t o a global variable, t o provide access t o t he applicat ion's propert ies, m et hods and event s. The ConnectMode t ells us when t he add- in was st art ed, eit her ext _cm _St art up ( as Excel st art ed) or ext _cm _Aft erSt art up ( when a dem and- loaded add- in is loaded, or from t he COM Add- in dialog) .

The AddInInst param et er is Excel's COMAddin obj ect t hat refers t o t his COM Add- in. We use t his obj ect t o get t he add- in's ProgI D t o use when set t ing up our m enu it em s ( see t he Com m and Bar Handling sect ion lat er) . The AddI nI nst obj ect also enables us t o expose t he funct ions in our add- in t o VBA, by including t he following line:

AddInInst.Object = Me

in t he OnConnect ion procedure. Any Public propert ies and m et hods we include in t he Designer class can t hen be called from VBA using code like t his:

'Run the SomeSub() procedure in the Hello World COM Addin Application.COMAddins("HelloWorld.Connect").Object.SomeSub

The custom() param et er allows t he COM Add- in host applicat ion t o send ext ra inform at ion t o a COM Add- in. For Excel, t he first elem ent of t he cust om ( ) array is used t o t ell us how Excel was st art ed: 1 = Opened from t he user int erface, 2 = Opened as an em bedded obj ect , 3 = Opened t hrough aut om at ion.

OnStartupComplete Private Sub AddinInstance_OnStartupComplete( _ custom() As Variant)

Excel raises t he OnConnect ion event wit hin it s st art up processing, as it encount ers a COM Add- in t o open. The OnSt art upCom plet e event is raised aft er Excel has com plet ed it s st art up processing, j ust before ret urning cont rol t o t he user. This is t he place t o display any form s you want t o show on st art up, such as " Thanks for I nst alling" or " Did You Know?" dialogs. I n pract ice, it is rarely used.

OnAddInsUpdate Private Sub AddinInstance_OnAddInsUpdate( _ custom() As Variant)

The OnAddI nsUpdat e event is raised whenever anot her COM Add- in is loaded or unloaded ( alt hough we're not t old which, or whet her it 's j ust been loaded or unloaded) . We've never seen it used.

OnBeginShutdown Private Sub AddinInstance_OnBeginShutdown( _ custom() As Variant)

The OnBeginShut down event is raised when Excel st art s it s shut down processing, if t he add- in is loaded at t he t im e. I t is not called if t he add- in is unloaded using t he COM Add- ins dialog. We've never seen it used.

OnDisconnection Private Sub AddinInstance_OnDisconnection( _ ByVal RemoveMode As _ AddInDesignerObjects.ext_DisconnectMode, _ custom() As Variant)

The OnDisconnect ion event is raised when Excel shut s down or when t he add- in is unloaded using t he COM Add- ins dialog. This procedure is where you should put your add- in's shut down code, such as t idying up m enus and so fort h. The RemoveMode param et er t ells us why t he add- in is being unloaded, eit her ext _dm _UserClosed ( unloaded using t he COM Add- ins dialog) or ext _dm _Host Shut down ( Excel is shut t ing down) . We would use t his t o decide whet her or not t o delet e our m enu it em s, if using a perm anent - m enu design ( see t he Com m and Bar Handling sect ion lat er) .

Terminate Private Sub AddinInstance_Terminate()

The Term inat e event is fired when t he class is dest royed and is exact ly t he sam e as t he Class_Term inat e event of a class m odule. I t 's rare t o see t his event used.

Command Bar Handling Using Command Bar Event Hooks Toward t he end of Chapt er 8 Advanced Com m and Bar Handling, we explained t he difference bet ween using t he Com m andBarCont rol's OnAct ion propert y t o call our procedures and using class m odules t o hook t he Com m andBarBut t on's Click event or t he Com m andBarCom boBox's Change event . When creat ing COM Add- ins, we have t o use t he event - hook m et hod for all our cont rols. I t would be a good idea t o reread t hat sect ion of Chapt er 8, but t o sum m arize it we need t o do t he follow ing: Give all our m enu it em s t he sam e Tag propert y, t o uniquely ident ify t hem as belonging t o our add- in . Give each m enu it em a unique Param et er propert y, t o ident ify t hem in code. Have a class m odule cont aining a Wit h Event s declarat ion for a Com m andBarBut t on ( and/ or Com m andBar Com boBox ) . I n t he class's Com m andBarBut t on_Click event procedure, confirm t hat t he Tag is set t o ours t hen call t he procedure appropriat e t o t he Param et er value. When set t ing up our m enus, creat e a new inst ance of t he class for each com binat ion of I D and Tag t hat we use. I f we're not using any built - in m enu it em s, we would only need a single inst ance of t he class.

Permanent vs. Temporary Menu Items I n an Excel add- in, we can respond t o t he AddI nI nst all event t o perm anent ly add our m enu it em s t o Excel ( by set t ing t he temporary param et er t o False when adding t hem ) and respond t o t he AddI nUninst all event t o rem ove t hem . I n t he m eant im e, t hey will always be available t o t he user, will feat ure in t heir usage count ing ( if t hey've elect ed t o show part ial m enus) and can be m oved around, copied t o ot her t oolbars and so on. This is t he preferred m et hod for general- purpose addins t hat m ight be expect ed t o always be inst alled. Alt ernat ively, we could choose t o add our m enu it em s on a t em porary basis, in which case we would add t hem in t he Workbook_Open event and rem ove t hem in t he Workbook_BeforeClose event . This is t he preferred m et hod for applicat ion- specific add- ins, where t he m enu it em s would t ypically be cont ained in t heir own com m and bar and we wouldn't want t he user t o m ove t hem ar ound. COM Add- ins differ from norm al Excel add- ins in t hat we aren't t old when t he add- in is inst alled or uninst alled ( part icularly uninst alled) ; we can only infer it from t he value we gave t he I nit ial Load

Behavior set t ing and t he param et ers passed t o t he OnConnect ion and OnDisconnect ion event s.

A Permanent-Menu Architecture When using perm anent m enus wit h COM Add- ins, we set t he I nit ial Load Behavior in t he Designer t o Load at next st art up only. This m eans Excel will load t he add- in t he next t im e it st art s, run t he OnConnect ion procedure, t hen set t he load behavior t o Load on dem and. I n t he OnConnect ion procedure, we need t o check t he Connect Mode param et er. I f it is ext _cm _St art up, we creat e our com m and bars and m enu it em s t hen set up t he event hooks for t hem . I f t he Connect Mode is ext _cm _Aft erSt art up, our m enu it em s should already be t here, so we only need t o set up t he event hooks. We should include som e code t o check whet her any of our m enu it em s have been rem oved and add t hem back. I n t he OnDisconnect ion procedure, we need t o check t he Rem oveMode param et er. I f it is ext _dm _UserClosed, t he user has unt icked t he add- in in t he COM Add- ins dialog, so we should delet e our m enu it em s. I f t he Rem oveMode is ext _dm _Host Shut down, we don't need t o do any t hing. When creat ing our m enu it em s, we need t o t ell Excel t hat t he m enu belongs t o our COM Add- in. We do t hat by set t ing t he com m and bar cont rol's OnAct ion propert y t o ! < ProgI D> , where t he ProgI D can be obt ained from t he AddI nI nst obj ect passed t o t he event . This t ells Excel which add- in owns t he cont rol so it loads t he add- in and calls t he OnConnect ion event ( if necessary) , allowing t he addin t o set up t he event hooks, t hen raises t he Click or Change event . The code for a perm anent - m enu archit ect ure is shown in List ing 21- 4.

List in g 2 1 - 4 . A Pe r m a n e n t - M e n u Ar ch it e ct u r e 'Run when the add-in is loaded Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As _ AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, _ custom() As Variant) Dim sOnAction As String 'Store a reference to the application object Set gxlApp = Application 'If we're starting up, it must be the first time, 'so create our menu items permanently If ConnectMode = ext_cm_Startup Then 'Get the ProgID from the AddInInst object sOnAction = "!"

'Create our menus, passing the OnAction string CreateMenus sOnAction End If 'Whether at startup or after startup, 'we have to set up our event hooks HookMenus End Sub 'Run when the add-in is unloaded Private Sub AddinInstance_OnDisconnection( _ ByVal RemoveMode As _ AddInDesignerObjects.ext_DisconnectMode, _ custom() As Variant) 'If the user chose to uninstall the add-in, 'remove our menus If RemoveMode = ext_dm_UserClosed Then RemoveMenus End If 'Tidy up our application reference Set gxlApp = Nothing End Sub

The problem wit h using a perm anent - m enu design wit h COM Add- ins is t hat it is quit e likely t he add- in would be uninst alled while Excel is closed. As COM Add- in DLLs need t o be regist ered on t he user's com put er, it is com m on pract ice t o dist ribut e t hem using a proper set up file. The set up file will usually include an Uninst all opt ion and/ or include t he add- in in t he user's Add/ Rem ove Program s list . I f our users were t o use t his opt ion t o uninst all t he add- in, t he add- in's m enu it em s would rem ain, orphaned. This risk has t o be weighed against t he benefit of allowing t he user t o m ove t he m enus around, creat e copies and so on. I n pract ice, t em porary m enu archit ect ures are t he m ost com m on.

A Temporary-Menu Architecture A t em porary- m enu archit ect ure is m uch sim pler. We set t he I nit ial Load Behavior in t he Designer t o St ar t Up, so t he add- in is loaded every t im e Excel st art s. I n t he OnConnect ion event , we always recreat e our m enus and set up t he event hooks. I n t he OnDisconnect ion event , we always rem ove t hem . I f we're creat ing our own com m and bars, we need t o st ore t heir visibilit y, docked st at e and posit ion before rem oving t hem and m ake sure t hey're added back in t he sam e st at e. Because t he add- in will always be open, we do not need t o set t he OnAct ion propert y. Even t hough we're rem oving our m enu it em s in t he OnDisconnect ion event , it is good pract ice t o add t hem wit h t he temporary param et er set t o True. The code for a t em porary- m enu archit ect ure is shown in List ing 21- 5 .

List in g 2 1 - 5 . A Te m por a r y- M e n u Ar ch it e ct u r e 'Run when the add-in is loaded Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As _ AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, _ custom() As Variant) 'Store a reference to the application object Set gxlApp = Application 'Always create our menu items CreateMenus 'Set up our event hooks HookMenus End Sub 'Run when the add-in is unloaded Private Sub AddinInstance_OnDisconnection( _ ByVal RemoveMode As _ AddInDesignerObjects.ext_DisconnectMode, _ custom() As Variant) 'Always remove our menus RemoveMenus 'Tidy up our application reference Set gxlApp = Nothing End Sub

Custom Toolbar Faces A COM Add- in does not have a worksheet handy t o st ore t he pict ures and m asks t hat we need for cust om t oolbar faces. I nst ead, we st ore t he bit m aps in a resource file wit hin t he COM Add- in proj ect and use LoadResPict ure t o ret rieve t he im age when needed. For m ore inform at ion about t he use of resource files in VB6, see Chapt er 20 Com bining Excel and Visual Basic 6. For Excel 2002 and 2003, we set t he Pict ure and Mask direct ly, but Excel 2000 gives us m ore of a problem . When st ored in resource files, t he bit m aps lose t he t ransparency t hat we could give t hem when t hey were st ored in a worksheet . When we Copy/ Past eFace t he pict ure ont o an Excel 2000 t oolbar and disable t he but t on, t he im age usually t urns int o an unident ifiable gray blob. This can be worked around by using API calls t o creat e a t ransparent bit m ap during t he Copy/ Past e procedure and is docum ent ed in Microsoft KB art icle 288771 at ht t p: / / suppor t .m icr osoft .com / ?kbid= 288771.

The Paste Special Bar COM Add-in I n Chapt er 8 Advanced Com m and Bar Handling, we used a Past e Special com m and bar t o dem onst rat e t he concept of hooking com m and bar but t on event s. The workbook is called Past eSpecialBar.xls and is locat ed on t he CD in t he \ Concept s\ Ch08Advanced Com m and Bar Handling folder. To dem onst rat e a working t em porary- m enu archit ect ure in a COM Add- in and t he use of cust om t oolbar faces, we have convert ed t he workbook t o a COM Add- in. The code for it can found in t he \ Concept s\ Ch21Writ ing Add- ins wit h Visual Basic 6\ Past eSpecialBarVB6 folder. The READ_ME m odule list s t he changes t hat were m ade t o convert t he Excel add- in t o a COM Add- in, while each m odule list s t he changes t hat were required in t he m odule header. The changes are sum m arized below: Use t he Designer and OnConnect ion / OnDisconnect ion inst ead of Aut o_Open / Aut o_Close. Add a global variable t o st ore a reference t o t he Excel.Applicat ion obj ect and use t hat variable whenever referring t o any of Excel's global obj ect s. Rem ove all t he code for t he t able- driven com m and bar builder, replacing it wit h a sim pler procedure t o add t he t oolbar but t ons individually. Copy t he cust om t oolbar im ages t o a resource file and use t hem inst ead of t he Past ePict ure m odule. Add t he MCopyTransparent m odule, t o handle copying t ransparent bit m aps for Excel 2000. Change t he values of a few of t he global variables, so t he Excel add- in and COM Add- in can coexist in Excel. Tidy up a few m inor references t o ThisWorkbook. I t is int erest ing t o not e t hat t he only change required t o t he add- in's payload of perform ing t he Past e Special was t o prefix Com m andBars and Select ion by our global Applicat ion obj ect variable. I f you're st ill unsure of t he differences and sim ilarit ies bet ween Excel and COM Add- ins, open bot h versions of t he Past e Special Bar and com pare t hem . Bot h add- ins do exact ly t he sam e t hings in exact ly t he sam e ways, using t he sam e m odule and procedure nam es, except where not ed in t he com m ent s. Fam iliarizing yourself wit h bot h versions of t he add- in will also prepare you for t he next chapt er, in which we convert it t o a Visual St udio Tools for Office ( VSTO) solut ion, using Visual Basic.NET.

Why Use a COM Add-in? By now, you've hopefully realized t hat while t he det ails are slight ly different bet ween COM Add- ins and Excel add- ins, t he concept s are t he sam e and t he code in t hem can be alm ost ident ical. That begs t he quest ion " Why bot her?"

Improved Code Security The code cont ained in Excel workbooks is not oriously easy t o break int o; t ools are readily available on t he I nt ernet t hat can crack ( or sim ply rem ove) t he VBProj ect prot ect ion password. I f your addin cont ains sensit ive inform at ion or int ellect ual propert y t hat you would prefer rem ained hidden, you should consider creat ing it as a COM Add- in. COM Add- ins are dist ribut ed as DLLs com piled t o m achine code; t he source code is never included. Alt hough it is t heoret ically possible t o decom pile an add- in, it is ext rem ely difficult and im pract ical t o do.

Multi-Application Add-ins A COM Add- in can cont ain m ult iple Designer classes, each handling t he connect ion t o a different Office applicat ion. I m agine an I nsert Cust om er Det ails add- in, which displayed a form enabling you t o select a cust om er from a cent ral dat abase and t hen insert ed t heir nam e, address and/ or t elephone num ber in t he current place in t he docum ent . By including m ult iple Designer classes in t he add- in, we could easily m ake t he add- in available t o all t he Office applicat ions. Each class's OnConnect ion event would be used t o add a st andard m enu it em t o t he host applicat ion's com m and bars, wit h t he Click event handled by a single class. When clicked, it would display t he form and would only branch int o applicat ion- specific code when t he I nsert but t on was clicked t o insert t he select ed det ails int o t he cell, paragraph, field, present at ion or Web page.

Exploiting Separate Threading One of t he m ore int erest ing t hings about COM Add- ins is t hat each one is given it s own execut ion t hread. The vast m aj orit y of Excel and VBA is single- t hreaded, m eaning t hat VBA code st ops when Excel is working ( such as showing one of it s dialogs) and vice versa. COM Add- ins don't have t his lim it at ion. A COM Add- in can init ialize a Windows t im er callback, t ell Excel t o display a dialog ( or Print Preview or what ever) , t hen cont inue processing ( in t he callback funct ion) while Excel is st ill displaying t he dialog. This enables us t o ( a) prepopulat e t he dialog, ( b) wat ch what t he user is doing wit hin t he dialog ( and respond t o it ) and even ( c) change t he layout of t he dialog it self! I t should be not ed t hat Excel is not designed t o be used like t his and t hese t echniques are in no way support ed by Microsoft . At t em pt ing t o call int o Excel's obj ect m odel while it is displaying a form m ay or m ay not work ( but if it works in one case, it will always work in t hat case) , oft en depending on whet her we're sim ply reading propert ies ( usually reliable) or t rying t o get Excel t o do som et hing ( which usually fails) .

As an exam ple, t he \ Concept s\ Ch21Writ ing Add- ins wit h Visual Basic 6\ ToolsRefSize folder on t he CD cont ains a COM Add- in which uses t his t echnique t o m odify t he labels at t he bot t om of t he VBE's Tools > References dialog, t o display t he filenam e of t he referenced proj ect using t wo lines wit h word wrap. Figure 21- 7 shows t he m odificat ions m ade by t he COM Add- in, enabling us t o see t he full pat h of t he referenced proj ect .

Figu r e 2 1 - 7 . Th e VBE's Tools > Re fe r e n ce s D ia log, M odifie d by t h e ToolsRe fSize COM Add- in t o Sh ow t h e Fu ll Loca t ion of t h e Se le ct e d Pr oj e ct

Automation Add-ins When init ially int roduced in Excel 2000, t he funct ions cont ained in COM Add- ins could not be called direct ly from a worksheet . I n Excel 2002, Microsoft added Au t om a t ion Add- in s t o solve t hat problem . An aut om at ion add- in is not hing m ore t han an Act iveX DLL t hat cont ains a public funct ion.

Creating the IfError Automation Add-in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins int roduced t he I FERROR( ) funct ion, writ t en as a VBA user- defined funct ion. I n Chapt er 19 XLLs and t he C API , it was rewrit t en in C, for best perform ance. We can re- creat e t his as an aut om at ion add- in t o im prove on t he perform ance of t he VBA version, alt hough not as m uch as t he C version. This can be t hought of as a com prom ise, im proving t he perform ance but keeping t he sim plicit y of t he Visual Basic code. To creat e t he addin, st art a new em pt y Act iveX DLL proj ect in VB6, change t he proj ect nam e t o ProExcel and t he class nam e t o Funct ions, t hen copy in t he code shown in List ing 21- 6.

List in g 2 1 - 6 . Th e I FERROR Use r - D e fin e d Fu n ct ion Public Function IFERROR(ByRef ToEvaluate As Variant, _ ByRef Default As Variant) As Variant If IsError(ToEvaluate) Then IFERROR = Default Else IFERROR = ToEvaluate End If End Function

Not e t hat t his is e x a ct ly t he sam e code as List ing 5- 3 in Chapt er 5 Funct ion, General and Applicat ion- Specific Add- ins. Click File > Make ProExcel.DLL t o build t he DLL.

Using the IfError Automation Add-in Open Excel 2002, click t he Tools > Add- ins m enu and click t he Aut om at ion but t on. The Aut om at ion Servers dialog list s every regist ered Act iveX DLL on t he PC, including t he one we j ust creat ed. Select t he ent ry for ProExcel.Funct ions and click OK. I t should now be list ed in t he norm al Tools > Add- ins dialog. Click OK t o ret urn t o t he worksheet . The funct ion can now be called direct ly from t he worksheet j ust like any ot her funct ion:

=IFERROR(A1/B1,0)

Accessing the Excel Application Object from an Automation Add-in When creat ing anyt hing m ore t han a t rivial funct ion, we will usually want t o use som e of Excel's worksheet funct ions wit hin t he procedure. Alt ernat ively, we m ay need t o m ark our funct ion as volat ile, so it is called every t im e t he sheet is recalculat ed. Bot h of t hese sit uat ions require us t o int eract wit h t he Excel Applicat ion obj ect . I f we add one of t he sam e Add- in Designer classes t o our proj ect t hat we used for COM Add- ins, Excel will call t he OnConnect ion event when t he DLL is first loaded, giving us t he opport unit y t o st ore a reference t o t he Applicat ion obj ect . We can t hen use t hat obj ect wit hin our funct ions. The following st eps explain how t o set it up: 1 . Wit hin t he ProExcel proj ect , click Proj ect > Add Add- in Class t o add a new Add- in Designer t o t he proj ect . I f t hat m enu isn't available, click Proj ect > Com ponent s and put a t ick next t o t he Add- in Class it em on t he Designers t ab t o m ake it available. 2 . I n t he Designer dialog, set t he Applicat ion t o Microsoft Excel and t he I nit ial Load Behavior t o None. 3 . We don't need t o provide a nam e or descript ion, but change t he Designer's class nam e in t he Propert ies window from AddI nDesigner1 t o AppFunct ions and set Public t o True ( ignoring t he w ar ning) . 4 . Click Proj ect > References, select Microsoft Excel from t he list t o creat e a reference t o t he Excel obj ect library, t hen copy in t he code shown in List ing 21- 7.

List in g 2 1 - 7 . Th e AppFu n ct ion s Code , Usin g t h e Ex ce l Applica t ion W it h in Au t om a t ion Add- in s Option Explicit 'Reference to the Excel application Dim mxlApp As Excel.Application 'Called when the automation add-in is loaded Private Sub AddinInstance_OnConnection( _ ByVal Application As Object, _ ByVal ConnectMode As _ AddInDesignerObjects.ext_ConnectMode, _ ByVal AddInInst As Object, _ custom() As Variant) 'Store away a reference to the Application object

Set mxlApp = Application End Sub 'Volatile function to return VB's Timer value Public Function VBTimer() As Double mxlApp.Volatile True VBTimer = Timer End Function 'Function to count how many items in Source lie between 'Min and Max Public Function CountBetween(ByRef Source As Range, _ ByVal Min As Double, ByVal Max As Double) As Double 'If we get an error, return zero On Error GoTo ErrHandler 'Count the items bigger than Min CountBetween = mxlApp.WorksheetFunction _ .CountIf(Source, ">" & Min) 'Subtract the items bigger than Max, giving the number 'of items in between CountBetween = CountBetween - mxlApp.WorksheetFunction _ .CountIf(Source, ">=" & Max) Exit Function ErrHandler: CountBetween = 0 End Function

5 . Close Excel, com pile t he DLL and inst all t he ProExcel.AppFunct ions add- in by select ing it from t he Tools > Add- ins > Aut om at ion list .

The first t im e any of t he funct ions in t he add- in is used, Excel loads t he add- in, calls t he OnConnect ion procedure, t hen calls t he funct ion. I n t he OnConnect ion procedure, we st ore a reference t o t he Excel Applicat ion obj ect , which we use wit hin t he funct ions cont ained in t he class.

Practical Example COM Add- ins are m ost applicable t o creat ing general- purpose add- ins, oft en working across m any of t he Office applicat ions. There is very lit t le benefit t o be gained from using t hem for applicat ionspecific add- ins, such as t he PETRAS t im esheet add- in we've been developing t hrough t he book. Therefore, neit her t he PETRAS t im esheet add- in nor t he PETRAS report ing applicat ion have been m odified for t his chapt er. However, t he Past e Special Bar add- in dem onst rat es a pract ical exam ple of a COM Add- in, and t he I fError add- in dem onst rat es a pract ical exam ple of an aut om at ion add- in.

Conclusion The COM Add- in archit ect ure enables us t o creat e a single add- in t hat can t arget any ( or m any, or all) of t he applicat ions in t he Office suit e and any t hird- part y applicat ions t hat license t he VBA6 developm ent environm ent . The code cont ained wit hin a COM Add- in is virt ually im possible t o decom pile, m aking it a m uch m ore secure m edium t han st andard Excel add- ins, in t erm s of prot ect ing int ellect ual propert y. There is very lit t le difference bet ween t he code cont ained in a COM Add- in and an Excel add- in; in m any cases, t he code can be copied from Excel and run virt ually unchanged in t he COM Add- in. Because COM Add- ins are t ypically writ t en using Visual Basic 6, all t he best pract ices described in Chapt er 20 Com bining Excel and Visual Basic 6 apply. Bot h t he Past e Special Bar and t he I FERROR funct ion exam ples have dem onst rat ed t hat an Excel add- in can be convert ed t o a COM Add- in relat ively easily.

Chapter 22. Using VB.NET and the Visual Studio Tools for Office Relat ively lat e in t he planning process for Office 2003, t he irresist ible force of .NET crashed int o t he im m ovable obj ect of Office. The Visual St udio Tools for Office was craft ed from t he debris. This chapt er explains t he concept s behind VSTO, how it works, what it can do ( and cannot do) and discusses ot her ways of leveraging t he .NET fram ework wit hin Excel solut ions. Not e t hat t his chapt er applies t o Visual St udio 2003, Office 2003 and VSTO 1.0, and all code sam ples are in Visual Basic.NET. You need t o have t hese applicat ions inst alled t o be able t o run t he exam ples for t his chapt er . The sam ple files for t his chapt er need som e m odificat ion t o adj ust t heir securit y configurat ion before you will be able t o run t hem . We suggest you read t hrough t he ent ire chapt er t o underst and how t o do t his, before t rying out t he sam ples.

Overview Target Audience Visual St udio.NET and t he .NET languages are t he responsibilit y of t he Visual Tools division of Microsoft . The Office applicat ions and t heir obj ect m odels are t he responsibilit y of t he Office division. Office program m abilit y lives in t he no m an's land bet ween t he t wo. At t he t im e of t his writ ing, t he VBA language and t he int egrat ed VBI DE are owned by t he Visual Tools division, but it s ownership has flipped back and fort h a few t im es since Excel 5. I t 's possible t hat ownership of VBA and t he VBI DE m ay swit ch back t o t he Office division, t o allow t he Visual Tools division t o concent rat e on .NET t echnologies, which includes t he Visual St udio Tools for Office ( VSTO) added for Office 2003. The dist inct ion is very im port ant because t he t wo divisions have radically different t ypes of cust om ers, and it 's t he cust om ers' requirem ent s t hat drive t he developm ent of new t ools and t echnologies. The prim ary focus in t he Office division is t hat of end- user product ivit y, providing t ools t hat enable end users t o creat e, access, m anipulat e and share t heir docum ent s and dat a quickly, easily and reliably. For t his group, Office program m abilit y ranges from using VBA t o aut om at e repet it ive t asks ( at t he low end of t he scale) t o creat ing st andalone line- of- business applicat ions using one or m ore of t he Office applicat ions t o provide t he core feat ures ( at t he t op end of t he scale) . The prim ary focus of t he Visual Tools division is t he professional developer who creat es ent erprisewide and/ or Web- based applicat ions using t he m ost up- t o- dat e t ools available. I t is for t his group t hat t he .NET t echnologies were developed and cont inue t o be enhanced. For t hem , Office program m abilit y has t ypically been an aft ert hought , m aybe adding a final feat ure t o t heir applicat ion t o export t heir dat a or report s as an Excel spreadsheet or Word docum ent . The Visual St udio Tools for Office has been creat ed t o allow t his group t o apply t heir skills t o Office developm ent .

What Is VSTO? The Visual St udio Tools for Office is a set of Visual St udio.NET proj ect t em plat es t hat bring Officebased applicat ion developm ent t o t he .NET developer, allowing t hem t o consider Excel and Word as first - class cit izens of t he .NET fram ework, alongside Windows Form s, Web Form s, ASP.NET and t he rest . VSTO allows t hose developers who have em braced t he .NET init iat ive t o link code t o Excel workbooks and Word docum ent s t hat will be execut ed when t he workbook or docum ent is opened ( in m uch t he sam e way we do wit h VBA) , subj ect t o securit y const raint s. A key dist inct ion is t hat t he code does not form part of t he workbook file. I nst ead, t he code is cont ained in an assem bly ( t he .NET t erm for a DLL) placed in a cent ral locat ion, such as a net work share, and a link t o t he assem bly is added t o t he workbook as a cust om docum ent propert y. When Excel 2003 opens a

workbook, it checks whet her t he cust om docum ent propert y exist s, reads where t o download t he assem bly from , downloads t he assem bly, checks t he securit y configurat ion and calls som e st andard ent ry point s t o run t he code. This new process is referred t o as t he VSTO Loader and is t he on ly change t hat has been m ade t o Excel 2003 for it t o support .NET.

How Does .NET Interact with Office? At t he risk of st at ing t he obvious, VBA int eract s wit h t he Office applicat ions t hrough t heir obj ect m odels. The obj ect m odels are exposed as COM int erfaces which VBA can call t o access t he underlying applicat ion code. To enable t he .NET languages t o int eract wit h Office, Microsoft has creat ed a Prim ary I nt erop Assem bly ( PI A) for each applicat ion. The PI A is an ext ra layer on t op of t he COM int erfaces t hat exposes ( alm ost ) t he sam e obj ect s wit h t he sam e propert ies, m et hods and event s t hat we know from VBA, allowing t hem t o be used by .NET code.

Is This the End for VBA? No, no, no, no and no. VSTO is a t oolset t o allow .NET developers t o link VB.NET or C# code t o Office docum ent s, t ypically t o add feat ures t o t he workbooks and docum ent s produced by t heir ent erprise- wide applicat ions. I t does lit t le t o address t he needs of t he t ypical VBA user com m unit y. VBA and t he VBA I DE will cont inue t o be included wit hin Office for t he foreseeable fut ure, and all new feat ures added t o Office will be exposed via t he obj ect m odels t o bot h VBA and .NET. To do ot herwise would be financial suicide for Microsoft , because all t heir corporat e cust om ers t hat have significant invest m ent s in VBA solut ions would sim ply refuse t o upgrade t o a version of Office t hat does not support VBA and allow it t o be m aint ained. The sit uat ion is very sim ilar t o t he XLM funct ions used t o program Excel 4. Alt hough VBA was int roduced in Excel 5, som e t en years ago, XLM m acros are st ill support ed and can be m aint ained in Excel 2003; indeed t here are st ill som e t hings t hat can only be done using XLM funct ion calls, such as finding t he coordinat es of chart elem ent s as discussed in Chapt er 15 Advanced Chart ing Techniques. At t he t im e of writ ing, VSTO is j ust anot her t ool for creat ing Excel applicat ions.

Terminology .NET int roduced som e new t erm inology t hat we use t hroughout t his chapt er: Asse m bly is t he .NET t erm for a DLL or EXE, being a file cont aining .NET code. Code be h in d is t he t erm given t o a linked VSTO assem bly; t hat is, t he assem bly t hat is point ed t o by t he cust om docum ent propert y, downloaded and run when t he docum ent is opened. Don't be confused by t his t erm ; it does not im ply t hat t he code is cont ained wit hin t he docum ent in t he sam e m anner as VBA. M a n a ge d m eans som et hing writ t en using a .NET language, usually VB.NET or C# , and execut ed by t he .NET runt im e, so m a n a ge d code m eans code writ t en using VB.NET, C# or one of t he ot her .NET languages, and a m a n a ge d w or k book is a workbook which has

m anaged code behind it .

How to Leverage the .NET Framework We can use five different m echanism s ( at least ) t o include som e m anaged code in our Excel- based applicat ions, all of which have t heir pros and cons. They are sum m arized below, and t he last t hree are explored in great er det ail lat er in t he chapt er: M a n a ge d COM D LLs are assem blies t hat include special at t ribut es t o expose t he classes, m et hods and propert ies as st andard COM obj ect s. To creat e a Managed COM DLL, we st art wit h a proj ect of t ype Class Library and add a class of t ype COM Class. That class will be exposed as a COM obj ect and any public procedures we add t o t he class will be exposed as t he obj ect 's m et hods and propert ies, in exact ly t he sam e way t hat we explain in Chapt er 20 Com bining Excel and Visual Basic 6. M a n a ge d COM a dd- in s are COM DLLs t hat im plem ent t he I DTExt ensibilit y2 int erface. To creat e a Managed COM Add- in, we st art wit h a Managed COM DLL and add a reference t o t he Microsoft Add- in Designer library. We t hen im plem ent t he int erface by adding Implements

AddInDesignerObjects.IDTExtensibility2

at t he t op of t he class m odule and adding our code for all t he int erface procedures. I n Chapt er 21 Writ ing Add- ins wit h Visual Basic 6, we used t he Add- in Designer class inst ead, which is a wrapper for t he I DTExt enxibilit y2 int erface. When writ ing m anaged COM Add- ins, we have t o im plem ent t he int erface direct ly and also writ e t he regist ry ent ries t o inst all t he add- in. As we explain in Chapt er 24 Providing Help, Securing, Packaging and Dist ribut ing, if t he user doesn't have t he Trust all I nst alled Add- ins and Tem plat es set t ing t icked in t he Tools > Macro > Securit y dialog, Excel will only aut om at ically load a COM Add- in if it is digit ally signed wit h a t rust ed digit al signat ure. Unfort unat ely, Excel ignores any digit al signat ures we apply t o m anaged assem blies, so will not aut om at ically load m anaged COM Add- ins. The workaround for t his issue is explained at ht t p: / / m sdn.m icr osoft .com / libr ar y / enus/ dnox pt a/ ht m l/ odc_shim .asp and involves using C+ + t o creat e an unm anaged shim t hat can sat isfy Excel's securit y checks. M a n a ge d w or k book s are t he pure docum ent - cent ric VSTO design philosophy. Wit h t his m echanism , a workbook is linked t o an assem bly creat ed using t he VSTO t ools. The assem bly cont ains a st andard Office Code Be h in d class t hat Excel calls and provides ThisWorkbook and ThisApplicat ion obj ect s. The ThisWorkbook obj ect is a reference t o t he workbook t he assem bly is linked t o, and ThisApplicat ion is a reference t o t he Excel Applicat ion obj ect . The code cont ained in t he assem bly is used t o aut om at e t he single docum ent it is linked t o. I f you have m ult iple copies of t he sam e workbook open, each one get s it s own inst ance of t he linked assem bly, so t he code cont ained in t he assem bly has t o t ake t hat int o account . We explain som e ways of doing t his lat er in t he chapt er. A M a n a ge d Ex ce l a dd- in is a m anaged workbook t hat has been saved as an Excel add- in,

but does not cont ain any VBA code. When Excel st art s, it loads t he add- in as norm al, but inst ead of running t he Aut o_Open or Workbook_Open rout ine, it uses t he VSTO Loader t o run t he linked assem bly. The code in t he assem bly can act as eit her a general- purpose or applicat ion- specific add- in, as described in Chapt er 5 Funct ion, General and Applicat ionSpecific Add- ins. H ybr id VBA/ VSTOSolu t ion s are workbooks t hat bot h cont ain VBA and have linked VSTO assem blies int eroperat ing wit h each ot her. This usage is officially unt est ed and unsupport ed by Microsoft but in our opinion provides by far t he best m echanism for a gradual m igrat ion from VBA t o a m anaged ( VSTO) solut ion, should we want t o do so.

Managed Workbooks Concept Managed workbooks are at t he core of t he VSTO design. The basic principle is t o com plet ely separat e code from dat aa principle t hat has been st ressed m any t im es in t his book. I n VBA, our code is always em bedded wit hin a workbook and we achieve code/ dat a separat ion by using m ult iple workbooksone for t he code and one for t he dat a. I n a VSTO solut ion, our VB.NET or C# code is com piled int o a .NET assem bly and t he workbook is linked t o t he code by t he t wo cust om docum ent propert ies _ Asse m blyLoca t ion 0 and _ Asse m bly N a m e 0 , giving t he direct ory and filenam e of t he assem bly respect ively. To deploy t he applicat ion, t he assem bly is copied t o a net work share ( wit h t he appropriat e securit y perm issions set see lat er) and t he _Assem blyLocat ion0 propert y is updat ed wit h t he URL of t he share, in \ \ server\ share form . The workbook is t hen dist ribut ed t o t he end users. When t hey open it , Excel checks t he cust om propert ies, downloads t he assem bly, checks t he user's securit y set t ings and runs it ( via t he .NET runt im e) if t he securit y set t ings are configured t o allow it t o run. This concept brings a num ber of benefit s: We can updat e everyone's code by copying a new version of t he assem bly t o t he net work sharewe no longer need t o t rack who t he docum ent has been sent t o in order t o dist ribut e updat es. As t he assem bly is always downloaded before being run, it doesn't m at t er whet her som eone has t he workbook open when we updat e t he assem blyt hey'll aut om at ically st art using t he new assem bly t he next t im e t hey open t he workbook. We never have t o dist ribut e t he source code, so t here is bet t er prot ect ion for our int ellect ual pr oper t y . I f each user has his .NET securit y set t ings configured t o allow VSTO solut ions t o run only if t hey have com e from a specific URL, opening m anaged workbooks from ot her ( unt rust ed) sources will not run t he code, t hereby prevent ing viruses and im proving securit y. Unfort unat ely, it also int roduces a few issues: I t 's m uch harder t o have different groups of people running different versions of t he applicat ion, such as during a phased rollout or region- specific updat eswe would have t o dist ribut e new versions of t he docum ent t hat point t o different assem blies, negat ing t he benefit of t he " aut om at ic" updat es. Everyone m ust be able t o access t he net work share in order t o download and run t he assem bly, which m akes it m u ch harder t o use t he docum ent out side t he corporat e net work,

such as t aking it hom e t o work on, or sharing it wit h part ner com panies. Every com put er has t o have it s .NET securit y perm issions set t o allow VSTO solut ions t o run from t he net work share. I n a corporat e environm ent , t his could be adm inist ered cent rally by including t he configurat ion wit h a login script . A sm all com pany or hom e user would have t o configure t he set t ings m anually, requiring det ailed knowledge of t he .NET and VSTO securit y m odel ( see lat er) .

A Hello World Managed Workbook Let 's st art by creat ing a sim ple Hello World VSTO solut ion. Fire up Visual St udio.NET 2003, select New Proj ect and choose a new Excel workbook, as shown in Figure 22- 1.

Figu r e 2 2 - 1 . Th e Visu a l St u dio.N ET N e w Pr oj e ct D ia log

Aft er clicking OK t hrough t he dialogs, we end up wit h a VSTO OfficeCodeBehind class t em plat e, including a collapsed region called Generat ed init ializat ion code and som e st ubs for t he Workbook_Open and Workbook_BeforeClose event s. Adding a MsgBox call t o each st ub gives us our Hello World VSTO solut ion, shown in List ing 22- 1, where t he code we've added has been highlight ed and t he collapsed sect ion expanded t o show it s cont ent s.

List in g 2 2 - 1 . VSTO Solu t ion Imports System.Windows.Forms Imports Office = Microsoft.Office.Core Imports Excel = Microsoft.Office.Interop.Excel Imports MSForms = Microsoft.Vbe.Interop.Forms ' Office integration attribute. Identifies the startup ' class for the workbook. Do not modify.

Public Class OfficeCodeBehind Friend WithEvents ThisWorkbook As Excel.Workbook Friend WithEvents ThisApplication As Excel.Application #Region "Generated initialization code" ' Default constructor. Public Sub New() End Sub ' Required procedure. Do not modify. Public Sub _Startup(ByVal application As Object, _ ByVal workbook As Object) ThisApplication = CType(application, Excel.Application) ThisWorkbook = CType(workbook, Excel.Workbook)

End Sub ' Required procedure. Do not modify. Public Sub _Shutdown() ThisApplication = Nothing ThisWorkbook = Nothing End Sub ' Returns the control with the specified name on ' ThisWorkbook's active worksheet. Overloads Function FindControl(ByVal name As String) _ As Object Return FindControl(name, CType(ThisWorkbook.ActiveSheet, _ Excel.Worksheet)) End Function ' Returns the control with the specified name on the _ ' specified worksheet. Overloads Function FindControl(ByVal name As String, _

ByVal sheet As Excel.Worksheet) As Object Dim theObject As Excel.OLEObject Try theObject = CType(sheet.OLEObjects(name), _ Excel.OLEObject) Return theObject.Object Catch Ex As Exception ' Returns Nothing if the control is not found. End Try Return Nothing End Function #End Region ' Called when the workbook is opened. Private Sub ThisWorkbook_Open() Handles ThisWorkbook.Open MsgBox("Hello World") End Sub ' Called before the workbook is closed. Note that this ' method might be called multiple times and the value ' assigned to Cancel might be ignored if other code or ' the user intervenes. Cancel is False when the event ' occurs. If the event procedure sets this to True, the ' document does not close when the procedure is finished. Private Sub ThisWorkbook_BeforeClose( _ ByRef Cancel As Boolean) _ Handles ThisWorkbook.BeforeClose MsgBox("Goodbye World") Cancel = False End Sub End Class

When you press F5 t o run t he proj ect , Visual St udio builds t he assem bly and st art s Excel, passing in t he workbook t o open. Excel opens t he workbook, checks t he _Assem blyLocat ion0 and _Assem blyNam e0 cust om propert ies, loads t he assem bly, reads t he OfficeSt art upClass assem bly at t ribut e t o find t he class t o st art and calls t he _St art up procedure in t hat class. Excel passes in a reference t o it self and a reference t o t he workbook it opened, which t he _St art up procedure assigns t o t wo m odule- level Wit hEvent variables, ThisApplicat ion and ThisWorkbook. That gives us bot h applicat ion- level and workbook- level event s by default . Excel t hen raises t he workbook's Open event , which we handle in t he ThisWorkbook_Open procedure t o show our " Hello World" m essage.

The Default VSTO Template The default Excel workbook VSTO class shown in List ing 22- 1 includes procedure and variable

nam es t hat have been chosen t o m im ic t hose found in Excelsuch as ThisWorkbookt o m ake it a lit t le easier for t hose wit h som e experience of VBA t o get st art ed. Not e t hat t hese are not hing m ore t han norm al variable and procedure nam es and do not have t he int rinsic m eaning t hey do in VBA. For som e reason, t he t em plat e also includes t wo versions of a FindCont rol funct ion, used t o locat e MSForm s cont rols on worksheet s. Presum ably, t his is because t he designers t hought m ost VSTO solut ions would include MSForm s cont rols in t he worksheet , which would need t o have event hooks configur ed. I n pract ice, t he default t em plat e really doesn't work well for people used t o working in VBA. We're used t o having global obj ect s such as Applicat ion and ThisWorkbook and being able t o refer t o worksheet s by t he code nam e. I t also m ixes up t he procedures required for t he com m unicat ion wit h Excel, t he event handling code for t he workbook and som e st andard funct ions. Our best pract ice recom m endat ion would be t o separat e out t hese funct ional areas int o t heir own m odules.

The ProExcel VSTO Template When we creat e VSTO proj ect s, t he first t hing we do is rem ove t he default ThisWorkbook m odule and use our own t em plat e inst ead. The t em plat e files are locat ed on t he CD in t he \ Concept s\ Ch22Using VB.NET and t he Visual St udio Tools for Office\ ProExcelTem plat e folder and com prise t he following: VSTOHooks.vb cont ains t he procedures t hat Excel calls t o st art up and shut down t he VSTO pr oj ect . CExcelApp.vb cont ains procedures t o set up and handle t he Excel Applicat ion's event s CThisWorkbook.vb cont ains procedures t o set up and handle t he workbook's event s. CSheet 1.vb, CSheet 2.vb and CSheet 3.vb cont ain procedures t o set up and handle t he worksheet event s for each worksheet in a default t hree- sheet workbook. MGlobals cont ains global variable definit ions t o refer t o t he applicat ion class, t he workbook class and each of t he t hree sheet classes. MSt andardCode cont ains st andard funct ions t o ident ify a worksheet from it s CodeNam e propert y and t he FindCont rol funct ion t o find an Act iveX cont rol on a worksheet .

MGlobals List ing 22- 2 shows t he code cont ained in t he MGlobals.vb file, which j ust defines som e global variables t o refer t o t he Excel Applicat ion obj ect , t he workbook event handler class and t he worksheet event handler classes.

List in g 2 2 - 2 . Th e M Globa ls Code

Option Explicit On Module MGlobals 'The Excel Application event-handler class Friend ExcelApp As CExcelApp 'The workbook event-handler class Friend ThisWorkbook As CThisWorkbook 'The worksheet event-handler classes Friend Sheet1 As CSheet1 Friend Sheet2 As CSheet2 Friend Sheet3 As CSheet3 End Module

VSTOHooks List ing 22- 3 shows t he code cont ained in t he VSTOHooks.vb file.

List in g 2 2 - 3 . Th e VSTOH ook s Code Option Explicit On 'Define aliases for commonly-used libraries Imports Excel = Microsoft.Office.Interop.Excel Imports Forms = System.Windows.Forms ' Office integration attribute. Identifies the startup class ' for the workbook. Do not modify.

Public Class VSTOHooks 'TODO: Change this to be the name of the Assembly Friend Const msAssemblyName As String = "ProExcelTemplate" ' Default constructor. Do not remove Public Sub New() End Sub ' Required procedure. Do not remove. ' Called by Excel when it loads the workbook. ' Used to check the environment and set up event hooks.

' DO NOT DO ANYTHING WITH THE EXCEL OBJECT MODEL IN HERE! Public Sub _Startup(ByVal application As Object, _ ByVal workbook As Object) 'Initialise global variables to refer to classes that 'handle the events for the Excel application class... ExcelApp = New CExcelApp(CType(application, _ Excel.Application)) '... and the workbook that this assembly is linked to ThisWorkbook = New CThisWorkbook(CType(workbook, _ Excel.Workbook)) End Sub ' Required procedure. Do not remove. ' Called when Excel closes the workbook '(after any prompts/confirmation etc.) Public Sub _Shutdown() 'Tell the CThisWorkbook class to shut down ThisWorkbook.ShutDown 'Tear down the global variables ExcelApp = Nothing ThisWorkbook = Nothing Sheet1 = Nothing Sheet2 = Nothing Sheet3 = Nothing End Sub End Class

The line t hat st art s but t on.

5. Choose St rong Nam e from t he Condit ion Type drop- down, t o creat e a t rust condit ion based on a st rong nam e key, t hen click t he I m port but t on and select any assem bly t hat has been st am ped wit h t he key. Click t he Next > but t on. 6. Choose t he Full Trust perm ission set , which t ells t he .NET fram ework t hat assem blies st am ped wit h t hat st rong nam e can do anyt hing. Click t he Next > but t on and t hen t he Finish but t on on t he confirm at ion dialog.

The .NET fram ework has now been configured t o allow any assem bly st am ped wit h t he sam e st rong nam e key t o run from t hat m achine. Adding t he code group t o t he User level m eans t hat .NET will only run assem blies t hat are physically locat ed on t he local m achine and only for t hat user. I n m ost cases when working on docum ent s at hom e or sending t hem t o people out side t he net work, t hat is exact ly what we'd like t o happen, as it 's an ext ra layer of securit y t hat won't im pede our abilit y t o use t he docum ent . We could allow t he assem bly t o be run for all users from t hat com put er and/ or from t he local net work by adding t he code group at t he m achine level, wit hin t he My_Com put er_Zone and/ or t he LocalI nt ranet _Zone, as shown in Figure 22- 4 .

Figu r e 2 2 - 4 . Se le ct in g t h e M a ch in e 's Loca lI n t r a n e t _ Zon e Gr ou p in t h e Se cu r it y Policy Edit or

Adding code groups at t he Machine level requires Adm in right s, but is a good place for net work adm inist rat ors t o add groups t hat allow specific st rong nam es t o run. I f we do t hat , we m u st ( from a securit y point of view) add ext ra condit ions t hat rest rict t he assem bly t o only run from specific net work shares, t o prevent t he at t ack described in St rong Nam e Risks ear lier . We have walked you t hrough t he st eps t hat need t o be t aken t o t rust a st rong nam e using t he Securit y Policy Edit or m ainly so you underst and what is going on, and can m odify it t o suit your requirem ent s. The .NET Trust an Assem bly Wizard ( found under Cont rol Panel > Adm inist rat ive Tools > Microsoft .NET Fram ework 1.1 Wizards ) can also be used t o t rust a st rong nam e and provides a m uch sim pler end- user experience. I t m ust not , however, be used t o t rust a st rong nam e at t he m achine level, because doing so explicit ly enables t he t ype of at t ack we've described.

Caspol Providing inst ruct ions for t he end user t o form ally est ablish a t rust relat ionship is a good way t o ensure t hey underst and what t hey're allowing, but is very dangerous if t hey do it wrong. I t is quit e easy for t hem t o inadvert ent ly open up t heir securit y and allow any .NET code t o run on t heir m achine! An alt ernat ive is t o provide a bat ch file or ot her inst allat ion script t o set t he .NET policy for t hem ; t he t rust decision is t hen whet her or not t o run t he script . The fram ework securit y policy can be set using t he caspol com m and line ut ilit y, usually found at C: \ WI NDOWS\ Micr osoft .NET\ Fr am ew or k\ v1.1.4322 . The com m and line t o do t he sam e as t he

previous m anual st eps is shown below, where t he CD is drive E: [View full width] caspol -q -u -ag All_Code -strong -file "E:\Concepts\Ch22 - Using VB.NET and the Visual Studio Tools for Office\SharedMenus\SharedMenus\bin\ SharedMenus.DLL" -noname -noversion FullTrust -n "ProExcel VSTO Projects" -d "VSTO Projects stamped with the ProExcel strong name key."

The caspol com m and line swit ches we've used are as follows: -q Quiet m ode, doesn't ask for confirm at ion. -u Add t his t o t he User node. - ag All_Code Add a code group below t he All_Code group. - st rong - file " E: \ ...\ SharedMenus.DLL" Using a st rong nam e key as evidence, ext ract ed from t hat file. - nonam e Don't use t he assem bly nam e as evidence. - nov er sion Don't use t he assem bly version as evidence. FullTr ust Give Full Trust t o any assem blies wit h a m at ching set of evidence ( t hat is, st am ped wit h t he sam e st rong nam e) . - n " ProExcel VSTO Proj ect " Creat e t he code group wit h t his nam e. - d " VSTO Proj ect s…" Creat e t he code group wit h t his descript ion. Sw it ch

D e scr ipt ion

To add t he st rong nam e t o t he m achine's LocalI nt ranet _Zone, but only allowing assem blies st ored on t he net work at \ \ Ser v er \ Shar e\ Folder or below, t he caspol com m and line would st art :

caspol -q -m -ag LocalIntranet_Zone -url \\Server\Share\Folder\* -strong file ...

The Big Issues The Visual St udio Tools for Office is a v1.0 product , so we don't expect perfect ion. This sect ion ident ifies what we consider t o be t he m aj or issues wit h v1.0, in t he hope t hey will be addressed in fut ure releases. We im agine t hat m ost of t hese issues are a result of t he Office t eam not having sufficient t im e t o m odify t heir applicat ions t o fully support VSTO solut ions. Som e of t he issues m ay be im proved by t he use of creat ive workarounds in VSTO 2005, but we expect m ost of t hem t o rem ain unt il changes can be m ade t o t he Office applicat ions, in Office 12 or lat er.

Functional Gaps A few t hings t hat can be done wit h VBA cannot be achieved using VSTO workbooks, t he m ain ones being t hese: User- defined funct ions callable from a worksheet Calling VSTO code from OnKey, OnTim e, OnDat a and so on Calling VSTO code from t he OnAct ion propert y of drawing obj ect s Uniquely ident ifying worksheet s ( wit hout relying on t he sheet t ab)

Application Links The only change m ade t o Excel 2003 t o support VSTO was t o add t he VSTO Loader, used t o open and st art VSTO assem blies. There are num erous links bet ween Excel and VBA t hat we t ake for grant ed, but are m issing in VSTO, including t he following: Aut om at ically having classes in VBA t o handle t he event s for t he workbook and each w or k sheet . Adding a worksheet t o a workbook doesn't add an event handler class t o t he VSTO proj ect . Adding a cont rol t o a worksheet doesn't add an event handler t o t he VSTO worksheet class. Wit h VBA, as soon as we add a cont rol t o t he worksheet , we can add code t o it s event s. Wit h VSTO, we have t o st op and rest art t he proj ect . I n VBA, t he worksheet 's propert ies and m et hods and any propert ies and m et hods we add t o it s class m odule are exposed t hrough t he sam e obj ect ; in VSTO solut ions we have t o use separat e obj ect s, result ing in t he awkward ExcelApp.Application and ThisWorkbook.Workbook synt ax.

I n VBA, t he code for m ult iple workbooks is handled by t he sam e I DE, enabling us t o easily copy code bet ween t hem ( such as being able t o drag/ drop a form or class bet ween proj ect s) . VSTO solut ions have one solut ion per inst ance of t he Visual St udio I DE.

Global Solutions Consider t he following line of code, placed in t he ThisWorkbook_Open procedure of a st andard VSTO workbook ( t hat is, creat ed wit h t he norm al VSTO t em plat e, not our ProExcelTem plat e classes) :

ThisWorkbook.ActiveSheet.Range("A1").Value = 2000

Assum ing t hat t he act ive sheet is a worksheet ( and not a chart ) , t hat code can be relied upon t o always put t he value 2000 in cell A1, right ? Wrong! Assum ing you have a st andard U.S. English inst allat ion of Office 2003 and Windows, use t he Cont rol Panel > Regional Set t ings applet t o swit ch t o French ( France) num ber form at s and st art t he VSTO workbook. I nst ead of put t ing 2000 in A1, we get a runt im e error wit h t he helpful m essage of " Except ion from HRESULT," which roughly t ranslat es as " Som et hing went wrong in Excel." But what ? Wit hin t he low- level com m unicat ion t hat occurs when we call int o an obj ect m odel, t here is a field called t he Locale I dent ifier ( lcid for short ) . The lcid specifies which locale ( t hat is, regional set t ings) t o use if t he program needs t o int erpret t he dat a being passed t o it . For exam ple, if we pass t he st ring " 2,000" t o Excel, is t hat t wo t housand ( U.S. locale) or t wo point zero ( m ost European locales) ? The VBA runt im e a lw a ys set s t he lcid field t o U.S. English, which is why we always have t o use U.S. form at s when sending st rings cont aining dat es or num bers t o Excel. Alt hough it t akes a lit t le get t ing used t o, t hat has t he clear advant age of predict abilit y; as long as we ensure our com m unicat ion wit h Excel is done using U.S. form at s, our VBA applicat ions will work worldwide. The I nt ernat ional I ssues chapt er of our Excel 2002 VBA Program m ers Reference explains t his in det ail and can be read online at w w w .oalt d.co.uk/ ExcelPr ogRef/ Ch22 . The .NET runt im e, however, passes t he lcid of t he t hread t he assem bly is running on, which by default is t he locale t hat Windows is set t oFrench in our exam ple. The first t hing m any of Excel's propert ies and m et hods do is check t he lcid and raise an error if it isn't recognized. Unfort unat ely, t he default inst allat ion of Office 2003 only recognizes English lcids, which is why we got t he error. All ot her lcids require t he Mulit lingual User I nt erface ( MUI ) Pack t o be inst alled, which is only available t o cust om ers on Microsoft 's volum e licensing program s. I n our experience, it is ext rem ely rare for cust om ers t o inst all t he language packs t hroughout an organizat ion. The usual sit uat ion is t o inst all t he U.S. English version, but allow t he end users t o set t heir own regional set t ingsexact ly t he sit uat ion t hat breaks our code. Anot her nast y issue arises from .NET passing t he lcid t o Excel. There are m any propert ies in t he Excel obj ect m odel t hat have bot h a U.S. and local version, such as t he Form ula and Form ulaLocal propert ies of a Range. Bot h propert ies call t he sam e underlying rout ine and t he only difference bet ween t hem is t he lcid passed t o t hat rout ine. Using t he Form ula propert y t ells VBA t o pass an lcid of U.S. English, while using Form ulaLocal t ells VBA t o pass t he lcid used by Windows. From .NET, however, t he lcid of t he t hread is passed t o t hem bot h, so t hey bot h behave like For m ulaLocal!

Even if t he MUI Pack is inst alled, we can st ill get rat her m ore subt le bugs in our code if t he user has cust om ized his Windows regional set t ings and is not using t he default for t he locale. Consider t he code in List ing 22- 10.

List in g 2 2 - 1 0 . D e m on st r a t in g Bu gs w it h Cu st om ize d Loca le s Private Sub ThisWorkbook_Open() Handles ThisWorkbook.Open Dim sValue As String sValue = InputBox("Enter a number according to your " & _ "regional settings.") With CType(ThisWorkbook.ActiveSheet, Excel.Worksheet) 'Allow Excel to do the conversion, using the lcid .Range("A1").Value = sValue 'Get .NET to do the conversion, using the full set of 'regional settings .Range("A2").Value = CType(sValue, Double) End With End Sub

Now set t he Windows regional set t ings back t o English, but cust om ize it t o use a com m a for t he decim al sym bol and a period for t he t housand separat orwhich is a num ber form at used widely in Europe. This sort of cust om izat ion is oft en done by people in t he UK who want t o print report s using English dat e form at s, m ont h nam es and so on, but European num ber form at s. Run t he code and t ype 2,000 in t he input box. You will discover t hat A1 has t he ( wrong) value 2000, but A2 has t he ( correct ) value 2. This happens because Excel is only using t he lcidEnglishand assum ing t hat t he st andard num ber form at s are being used ( where com m a is t he t housand separat or) , but .NET is using t he full set of regional set t ings, including t he cust om izat ion of using a com m a for t he decim al separ at or . So we cannot rely on t he users having t he MUI Pack inst alled, and even wit h it inst alled, we have t o handle t he problem of Form ula behaving like Form ulaLocal and so on, and we cannot rely on t hem not cust om izing t he Windows regional set t ings. The only t hing we can do is force .NET t o com m unicat e wit h Excel in U.S. English. To do t his, we have t o change t he cu lt u r e ( .NET's t erm for regional set t ings) t hat .NET is using t o U.S. before every call int o t he Excel obj ect m odel and change it back t o t he Windows default before every int eract ion wit h t he user, as shown in List ing 22- 11.

List in g 2 2 - 1 1 . Togglin g t h e .N ET Cu lt u r e 'Global variables used to handling culture switching

'This thread Public gThread As System.Threading.Thread = _ System.Threading.Thread.CurrentThread 'The Windows culture information Public gCultureWin As System.Globalization.CultureInfo = _ gThread.CurrentCulture 'The US culture information Public gCultureUS As System.Globalization.CultureInfo = _ New System.Globalization.CultureInfo("en-US")

' Called when the workbook is opened. Private Sub ThisWorkbook_Open() Handles ThisWorkbook.Open Dim sValue As String Dim dValue As Double Dim dResult As Double 'Interacting with user, so switch to Windows culture gThread.CurrentCulture = gCultureWin 'Get the value and convert to a double, using Windows 'culture sValue = InputBox("Enter a number according to your " & _ "regional settings.") dValue = CType(sValue, Double) 'Always use exception handling, so the culture gets 'switched back in case of a run-time error Try 'About to talk to Excel, so switch to US gThread.CurrentCulture = gCultureUS 'Do the Excel stuff... With CType(ThisWorkbook.ActiveSheet, Excel.Worksheet) 'Send the data to Excel .Range("A1").Value = dValue 'Enter a formula .Range("A2").Formula = "=A1*A1" 'Read the result. We can't display it until we 'switched the culture back dResult = .Range("A2").Value End With Finally

'Finished with Excel, so switch back to Windows gThread.CurrentCulture = gCultureWin End Try 'Show the result to the user MsgBox("Your value squared is " & dResult.ToString) End Sub

Ot her t han being a t on of ext ra code, we have t o be ext rem ely careful t hat we have t he correct cult ure set for every line, which becom es increasingly unwieldy as we call funct ions and subprocedures which also have t o swit ch cult ures. I n t he exam ple in List ing 22- 11, we had t o use t he dResult variable t o t em porarily hold t he result while we swit ched cult ures back t o t he Windows default , prior t o displaying it t o t he user. The problem doesn't st op t here. Excel runs all VSTO assem blies on t he sam e t hread, so when we swit ch cult ures, t hat affect s every loaded VSTO assem bly. I f a separat e VSTO assem bly is responding t o applicat ion event s, t hat assem bly could easily swit ch t he cult ure back, causing our assem bly t o fail. Correct ing t his issue will require changes t o bot h Excel and t he VSTO t em plat e, so it 's ext rem ely unlikely t o be fixed before Office 12. One solut ion would be t o have a new Office- specific assem bly at t ribut e ( such as t he ones t hat VSTO int roduced) for t he ExcelAut om at ionCult ure. I f om it t ed or set t o Default , t he behavior would be t he sam e as now, but if set t o a specific lcid, such as en- US, Excel would use t hat cult ure I D regardless of t he lcid sent wit h t he obj ect m odel calls. By m aking it an assem bly at t ribut e ( inst ead of, say, a propert y of t he Excel Applicat ion obj ect ) , different VSTO workbooks would be able t o work side by side wit h different set t ings. We would be able t o set t he ExcelAut om at ionCult ure t o en- US and from t hen on rely on t he predict abilit y t hat we are accust om ed t o wit h VBA.

Security and Sharing Managed Workbooks Office users share t heir files; oft en by e- m ailing t he files t o each ot her, but also by copying t hem t o disk or m em ory st icks. The linked nat ure and st ringent securit y requirem ent s of VSTO solut ions m ake t his m uch m ore difficult t han at present , part icularly when sending t he workbook out side of t he corporat e net work. As well as copying t he docum ent file, we now need t o copy t he assem bly t oo, m odify t he _Assem blyLocat ion0 cust om docum ent propert y ( so Excel finds t he assem bly on t he t arget m achine) and configure t he .NET securit y policy t o t rust t he assem bly ( so Excel will run it ) . And when we get it back t o t he office, we have t o m odify t he _Assem blyLocat ion0 again t o point back t o t he server. Do we really t hink t he average low- end Excel users will be able t o do all t hat wit hout error every t im e t hey want t o share a docum ent ?

Migrating from VBA At t he st art of t his chapt er, we explained t hat t he Visual St udio Tools for Office was prim arily creat ed t o bring Office developm ent int o t he realm of professional .NET developers. Consequent ly, t he em phasis has been on m aking Office behave in a sim ilar way t o t he ot her .NET t echnologies,

rat her t han m aking VSTO behave in a sim ilar way t o VBA. The result is t hat t hose of us wit h VBA experience have a long uphill st ruggle t o m igrat e bot h our knowledge and our applicat ions t o m anaged code; we have neit her t he conversion wizard nor t he support ed I nt erop opt ion enj oyed ( if t hat 's t he right word) by our VB6 colleagues. I f Microsoft want s t o see significant num bers of Office developers m oving t o m anaged code, Office 12 m u st m ake it m uch m ore approachable for t hose wit h a VBA background.

Office Versions VSTO workbooks are only support ed in t he Professional version of Office 2003 and t he st andalone version of Excel 2003. They are not support ed in eit her t he St andard or St udent versions of Office, nor in any previous version. As applicat ion developers, t hat m eans we sim ply can't predict whet her our applicat ions will run when we send t hem t o our users. That uncert aint y alone m ight be sufficient reason t o st ay wit h VBA. We can only hope t hat Office 12 will enable VSTO workbooks in all it s versions and provide sufficient incent ive for t he m aj orit y of users t o upgrade.

Further Reading At t he t im e of writ ing, no books have been writ t en about t he Visual St udio Tools for Office. To find out m ore about VSTO, we suggest you st art wit h t he following: For general inform at ion about VSTO, st art at t he Microsoft Web sit e, at ht t p: / / m sdn.m icr osoft .com / office/ under st anding/ vst o For inform at ion about t he VSTO securit y m odel, we recom m end Pet er Torr's blog, at ht t p: / / w eblogs.asp.net / pt or r / cat egor y / 2391.aspx ?Show = All I f you encount er any problem s while developing VSTO proj ect s, ask for help in t he Microsoft support newsgroup, microsoft.public.vsnet.vstools.offfice

Practical Example The PETRAS applicat ion files for t his chapt er can be found on t he CD in t he folder \ Applicat ion\ Ch22Using VB.NET and t he Visual St udio Tools for Office and includes t he following files: Pe t r a sTe m pla t e .x lt The t im esheet t em plat e Pe t r a sAddin .dll The t im esheet dat a- ent ry support add- in, rewrit t en as a VSTO assem bly and linked t o from t he Pet rasTem plat e.xlt t em plat e Pe t r a sRe por t in g.x la The m ain report ing applicat ion Pe t r a sCon solida t ion .x lt A t em plat e t o use for new result s workbooks Pe t r a s.m db A dat abase file t o st ore t im esheet dat a D e bu g.in i A dum m y file t hat t ells t he applicat ion t o run in debug m ode Pe t r a sI con .ico An icon file, t o use for Excel's m ain window

PETRAS Timesheet Add-in The PETRAS t im esheet is an ideal exam ple of t he t ype of workbook for which t he Visual St udio Tools for Office was designed. I nst ead of creat ing an Excel add- in and dist ribut ing it t o all our users, t he VSTO solut ion uses a single assem bly deployed t o a net work share and a linked Excel t em plat e. The Pet rasTem plat e.xlt links t o t he assem bly using t he cust om docum ent propert ies. To t est t his exam ple, you will need t o copy t he Pet rasAddin.DLL t o a folder of your choice, go t hrough t he st eps described in Trust ing a St rong Nam e earlier in t his chapt er and change t he t em plat e's cust om docum ent propert y t o point t o t he folder cont aining t he Pet rasAddin.dll ( using t he full folder nam e) . The Pet rasTem plat e.xlt file should be saved t o your Tem plat es folder, usually locat ed at C: \ Docum ent s and Set t ings\ < Usernam e> \ Applicat ion Dat a\ Microsoft \ Tem plat es. The Pet rasAddin VSTO proj ect cont ains t he following m odules: Asse m bly I n fo.vb The .NET at t ribut es for t his assem bly. M Globa ls.v b Global const ant s and variables. V STOH ook s.v b Procedures t o handle t he com m unicat ion bet ween Excel and t he assem bly. CTh isW or k book Class t o handle workbook event s, m ost of which were handled at t he applicat ion level in previous versions of t he add- in. M Com m a n dBa r s.vb Module t o creat e and rem ove our com m and bar but t ons. Rewrit t en t o creat e and dest roy t hem individually inst ead of using t he t able- driven com m and bar builder.

CCon t r olEve n t s.vb Class t o hook t he event s for our com m and bar but t ons. M En t r y Poin t s.v b Module cont aining t he procedures called by t he com m and bar but t ons. M Br ow se For Folde r .vb Module t o display a Browse for Folder dialog, rewrit t en t o use t he st andard .NET dialog. M D a t a Acce ss.vb Module cont aining t he ADO dat a layer. M Er r or H a n dle r .vb The com m on error handler rout ine. M St a n da r dCode .v b St andard rout ines, copied bet ween proj ect s. I n t his version of t he add- in, we've m oved from an applicat ion- cent ric add- in t o a docum ent - cent ric one, so each t im esheet workbook get s it s own inst ance of t he VSTO code. The m ost not iceable change wit h t his is t hat new t im esheet s are creat ed using Excel's norm al File > New m enu inst ead of a New Tim e sheet but t on on our com m and bar. The code is unloaded when t he t im esheet docum ent is closed, so we no longer need an Exit PETRAS but t on eit her. The m aj or changes required t o convert t he Pet rasAddin from an Excel add- in t o a m anaged VTSO t em plat e workbook are list ed in Table 22- 1 .

Ta ble 2 2 - 1 . Ch a n ge s t o t h e PETRAS Tim e sh e e t Add- in for Ch a pt e r 2 2 M odu le

Pr oce du r e

Ch a n g e

All

All

Convert ed synt ax, obj ect references et c. t o VB.NET st yle.

Mult iple

Mult iple

Where t he Excel add- in code used t he Act iveWorkbook in previous chapt ers, we're now only int erest ed in t he workbook linked t o t he assem bly, given by ThisWorkbook.Workbook.

CAppEv ent Handler

Rem oved t he class, as each workbook has it s own inst ance of t he code, so can handle it s own event s at workbook level. Moved m uch of t he code t o t he ThisWorkbook class.

MGlobals

Added global variables from st andard ProExcel VSTO t em plat e. Changed ThisWorkbook.Pat h t o use t he assem bly's pat h.

MEnt r yPoint s

Rem oved t he procedures for New Tim esheet and Exit PETRAS. As t his is now an aut om at ed t im esheet , we'll use Excel's File > New t o creat e new ones and t he code is aut om at ically unloaded when t he t im esheet is closed. Rem oved calls t o bI nit Globals as t hey can now be t rust ed t o rem ain set .

M odu le

Pr oce du r e

Ch a n g e

MBr ow seFor Folder

Rewrit t en t o use t he .NET Browse for Folder dialog.

MCom m andBar s

Rewrit t en t o creat e our com m and bar but t ons individually, inst ead of using t he t able- driven com m and bar builder.

CCont rolEvent s ( new class)

New class t o handle t he com m and bar but t on Click event s.

MEr r or Handler

bCent r alEr r or Handler

CThisWor k book

bMakeWor ksheet Set t ings Rewrit t en t o configure our worksheet s individually inst ead of using a t able- driven approach.

Pet rasTem plat e.xlt

Changed ThisWorkbook.Pat h t o use t he assem bly's pat h.

Added set HideRows and set HideCols nam ed ranges t o allow t he rows and colum ns t o be hidden direct ly. Added t he _Assem blyLocat ion0 and _Assem blyNam e0 cust om docum ent propert ies, t o launch t he VSTO assem bly. Saved t he t em plat e in it s ready- t o- edit st at e.

PETRAS Reporting Application The PETRAS report ing applicat ion has not been updat ed for t his chapt er.

Conclusion Office 2003 and t he Visual St udio Tools for Office should be t hought of as a t ypical Microsoft " version 1.0" product ; it does exact ly what it has been designed t o do, but you m ight not be t he kind of person it was designed for and t he design m ay be t oo lim it ed for pract ical use in m ost com m on sit uat ions. I t also lacks m any of t he ease- of- use feat ures t hat we t ake for grant ed in our VBA proj ect s, such as aut om at ically having class m odules for each of our worksheet s and aut om at ically having event s for any cont rols we add t o t hem . You m ight consider a VSTO solut ion if a ll of t he following apply: This is a new applicat ion which won't m ake m uch use of any VBA code libraries you m ight have, and You already have som e experience wit h VB.NET or C# and t he .NET fram ework, and The .NET fram ework 1.1 is inst alled for all users, and You can adm inist er .NET securit y policy cent rally and roll it out t o all users, and All users have Office 2003 Professional inst alled, running wit h U.S. English regional set t ings, an d You don't need t o use any of t he feat ures t hat VSTO doesn't support , such as user- defined funct ions, OnKey, OnTim e and so on, and You have a cent ral server t o host t he VSTO assem blies, and All users will be connect ed t o t he cent ral server when using t he docum ent ; it will not be used out side t he com pany or offline, such as t aken hom e or being shared wit h a t hird part y. I f you can't t ick all t hose boxes, but st ill want t o use t he facilit ies provided by t he .NET fram ework, consider exposing t he m anaged code as a COM DLL and calling it from VBA. VSTO 1.0 was designed t o bring Office developm ent int o t he realm of t he professional Visual St udio.NET developer. I t was not designed t o bring m anaged code developm ent int o t he realm of t he Office power user or VBA developer and doesn't at t em pt t o do so. I t is in no way a replacem ent for VBA, which will cont inue t o be support ed for m any years t o com e. VSTO 2.0 ( a.k.a. VSTO 2005) t akes a furt her st ep away from t he average Office user by host ing t he Excel window inside Visual St udio.NET and m aking it behave j ust like t he Windows Form s drawing surface, allowing t he .NET developer t o drag and drop Windows Form s cont rols ont o worksheet s. By forcing Excel t o behave in t he sam e m anner as ot her Visual St udio.NET elem ent s, such as Windows Form s and ASP.NET, VSTO 2.0 m akes it m uch easier for t he VS.NET developer t o em brace Office developm ent , but at t he cost of m any of t he ease- of- use feat ures t hat Excel end users have com e t o expect . On t he plus side, VSTO 2.0 includes m any of t he aut om at ic feat ures we t ake for grant ed in VBA, such as aut om at ically get t ing a new event handler class m odule when we add a

worksheet and so fort h. I t also includes a num ber of new program m ing elem ent s, in which t he exist ing Excel event s have been wrapped and com bined in innovat ive ways. This chapt er st art ed wit h t he st at em ent t hat t he collision bet ween .NET and Office cam e relat ively lat e in t he Office 2003 planning processfar t oo lat e for m aj or changes t o be considered. Wit h t he planning for Office 12 well under way, it is incum bent upon bot h t he Visual Tools and Office divisions at Microsoft t o work hand in hand t o bring m anaged code developm ent wit hin t he realm of t he t radit ional Office power user and VBA developer. This m ust include t he abilit y for t he owners of exist ing VBA applicat ions t o m igrat e t heir code, t heir skills and t heir knowledge t o .NET in a gradual m anner at t heir own pace, which only a seam less hybrid VBA/ VB.NET environm ent would allow .

Chapter 23. Excel, XML and Web Services Wit h every version of Excel since Office 97, Microsoft has gradually added feat ures t hat enable Excel applicat ions t o work wit h I nt ernet - based solut ions. St art ing wit h t he abilit y t o open and save HTML pages and perform rudim ent ary Web queries in Excel 97, t his has progressed t hrough m uch im proved Web queries in Excel 2000, saving a workbook as XML in Excel 2002 and culm inat ing wit h Excel 2003's abilit y t o read and writ e arbit rary XML schem as. Along t he way, Microsoft released t he Web Services Toolkit , which allows our VBA code t o com m unicat e wit h Web services. This chapt er explains why we m ight want t o use XML and Web services wit hin our Excel applicat ions, how t o use t hem effect ively in Excel 2003 and how t hey can be used in versions prior t o Excel 2003.

XML Unless you've been living in a vacuum for t he past few years, you will have heard t he acronym XM L t hrown around wit h increasing regularit y. I f you're prim arily an Excel developer, you're probably also wondering what all t he fuss is about . XML is a form at used for t he t ext ual expression of dat a. I n t hat respect , it 's no different from t he fixed- widt h, com m a- separat ed or t ab- delim it ed t ext form at s we've been using for years. There are, however, a num ber of key fact ors t hat different iat e XML from all t he ot her t ext form at s t hat have com e before it and m ake it m uch m ore appealing t o developer s: XML is a st r u ct u r e d form at , which m eans t hat we can define exact ly how t he dat a is t o be arranged, organized and expressed wit hin t he file. When we are given a file, we can validat e t hat it conform s t o a specific st ruct ure, prior t o im port ing t he dat a. As we know t he st ruct ure of t he file in advance, we know what it cont ains and how t o process each it em . Prior t o XML, t he only st ruct ure in a t ext file was posit ionalwe knew t he bit of t ext aft er t he fourt h com m a should be a dat e of birt hand we had no way t o validat e whet her it was a dat e of birt h, or even a dat e, or whet her it was in day/ m ont h/ year or m ont h/ day/ year order. XML is a de scr ibe d form at , which m eans t hat wit hin t he t ext file, every it em of dat a has a nam e t hat is bot h hum an- and m achine- readable as well as being uniquely ident ifiable. We can open t hese files, read t heir cont ent s and underst and t he dat a t hey cont ain, wit hout having t o refer back t o anot her docum ent t o find out what t he t ext aft er t he fourt h com m a represent s ( and was t hat com m a a separat or, or part of t he t ext of t he second it em ?) . Sim ilarly, we can edit t hese docum ent s wit h a fairly high level of confidence t hat we're m aking t he correct changes. XML can easily describe h ie r a r ch ica l dat a and t he r e la t ion sh ips bet ween dat a. I f we want t o im port and export a list of aut hors, wit h t heir nam es, addresses and t he books t hey've writ t en, deciding on a reasonable form at for a CSV file is by no m eans st raight forward. Using XML, we can define what an Aut hor it em is and t hat it has a nam e, address and m ult iple Book it em s. We can also define what a Book it em is and t hat it has a t it le, a publisher and an I SBN. The hierarchy and relat ionships are a nat ural consequence of t he definit ion. XML can be v a lida t e d, which m eans we can provide a second XML filean XML schem a definit ion filet hat describes exact ly how t he XML dat a file should be st ruct ured. Before processing an XML file, we can com pare it wit h t he schem a t o ensure it conform s t o t he st ruct ure we expect t o receive. XML is a discove r a ble form at , which m eans program s ( including Excel 2003) can parse an XML dat a file and infer t he st ruct ure and relat ionships bet ween t he it em s. This m eans we can read an XML file, infer it s st ruct ure and generat e new XML dat a files t hat conform t o t he sam e st ruct ure, wit h a high degree of confidence t he new XML dat a files will pass validat ion. XML is a st r on gly t ype d form at , which m eans t he schem a definit ion file specifies t he dat a t ype of each elem ent . When im port ing t he dat a, t he applicat ion can check t he schem a definit ion t o ident ify t he dat a t ype t o im port it as. We no longer run t he risk of t he product

code 01- 03 being im port ed as a dat e. XML is a globa l form at . There is only one way t o express a num ber in an XML file ( wit h U.S. num ber form at s) and only one way t o express a dat e. We no longer have t o check whet her a CSV file was creat ed wit h U.S. or French set t ings and adj ust our processing of it accordingly. XML is a st a n da r d form at . The way in which t he cont ent of an XML file is defined has been specified by t he World Wide Web Consort ium ( W3C) . This allows applicat ions ( including Excel 2003) t o read, underst and and validat e t he st ruct ure of an XML file and creat e files t hat conform t o t he specified st ruct ure. I t also allows diffe r e n t applicat ions t o read, writ e, underst and and validat e t he sa m e XML files, enabling us t o share dat a bet ween applicat ions in an ext rem ely robust m anner. So is t here anyt hing we can do wit h XML we couldn't do using t echnologies we already know? No, not really. But t hen, t here's not hing we can do wit h a spreadsheet we couldn't also do wit h a pen and paper ( and m aybe a basic calculat or! ) . Since t he earliest com put ers, we've been st oring dat a and sharing it bet ween applicat ions. I f we cont rol bot h ends of t he dialogue, it doesn't m at t er what 's passed bet ween t hem , so long as each end knows what t o supply and what t o expect and not hing goes wrong. I f t he form at of a file is docum ent ed, any applicat ion could ( in t heory) be program m ed t o read and writ e t he sam e dat a files. Wit h XML files, an applicat ion can read ( or infer) t he st ruct ure definit ion and j oin in any conversat ion wit hout ext ra program m ing. Using XML j ust m akes som e t hings a whole lot easier and m ore reliable.

An Example XML File List ing 23- 1 shows an exam ple XML file for an aut hor, including his nam e, e- m ail address and som e of t he books he has been involved wit h.

List in g 2 3 - 1 . An Ex a m ple XM L File

Stephen Bullen [email protected]

Professional Excel Development Addison Wesley 0321262506

Excel 2002 VBA Programmer's Reference Wrox Press 1861005709

I f XML lives up t o it s hype, you should have been able t o read and underst and all t he it em s of dat a in t hat file and underst and t he relat ionships bet ween t he elem ent s. Just in case, we'll highlight t he m ain it em s: The first line ident ifies t he cont ent s of t he file as XML. Every XML file st art s wit h t his line. The file consist s of bot h dat a and pairs of t ags surrounding t he dat a, which are t oget her called an e le m e n t . Our file consist s of Aut hor, Nam e, Em ail, Book, Tit le, Publisher and I SBN elem ent s. A t ag is ident ified by t ext enclosed wit hin angle bracket s, like < Tag> . All t he t ags com e in pairs, wit h an opening t ag like < Tag> and a closing t ag like < / Tag> ; all t he t ext bet ween t he opening and closing t ags in som e way " belongs" t o t he t ag. However, if t here is not hing cont ained wit hin t he opening and closing t ags, t hey can be com bined so t hat < Tag> < / Tag> can be shown as < Tag/ > . This is oft en used when t he dat a for an elem ent is provided as an a t t r ibu t e of t he elem ent , using a synt ax like < Publisher nam e= " Addison Wesley" / > . There is lit t le difference bet ween using elem ent s or at t ribut es, t hough our preference is t o use elem ent s. Not e t hat t ags and at t ribut es are case- sensit ive, so < Aut hor> will not m at ch wit h < / aut hor> . The second line ident ifies a r oot e le m e n t , which in t his file represent s an Aut hor. Every XML file m ust have one and only one root elem ent ; all ot her elem ent s in t he file belong t o t he root elem ent . The t hird and fourt h lines ident ify t he aut hor's nam e and e- m ail address; we know it 's t he aut hor's nam e and e- m ail address because t hey're bot h wit hin t he sam e < Aut hor> elem ent . The fift h line is t he st art of a Book elem ent , wit h t he next t hree lines giving t he book's det ails ( because t hey're cont ained wit hin t he Book elem ent ) . The nint h line closes t he Book elem ent , t elling us we've finished wit h t hat book. Lines 10 t o 14 show a second Book elem ent , wit h t he book's det ails. Line 15 closes t he Aut hor elem ent , t elling us we've finished wit h t hat aut hor. That exam ple hopefully dem onst rat es t he m ain at t ribut es of an XML file. I t is st ruct ured, described, hierarchical and relat ional, but how is it validat ed?

An Example XSD file The st ruct ure of an XML file is specified using an XML schem a definit ion file, which usually has t he ext ension .xsd and cont ains set s of XML t ags t hat have been defined by t he W3C. The XSD file for t he Aut hor XML dat a is shown in List ing 23- 2.

List in g 2 3 - 2 . An Ex a m ple XSD File















This is slight ly less readable XML! We explain how t o creat e an XSD file lat er in t he chapt er, but it 's helpful t o underst and how t his file describes t he st ruct ure of t he XML dat a file shown in List ing 231: Like all XML files, t he first line ident ifies t he cont ent s as XML. The second line ident ifies t he nam espace ht t p: / / w w w .w 3.or g/ 2001/ XMLSchem a and gives it t he alias, xs. This is t he nam espace defined by t he W3C t hat cont ains all t he XML t ags used in XML schem a definit ion files. When we need t o use a t ag from t hat nam espace, we precede it wit h t he xs: alias ident ifier so t he XML processor can correct ly ident ify it . This m echanism of using nam espace aliases is oft en encount ered in XML files t hat cont ain elem ent s from m ult iple nam espaces ( such as Excel workbook files, which cont ain t ags from bot h t he Excel and Office nam espaces) . The t hird line defines an Aut hor elem ent which m ust occur once and only once in t he file ( unless ot herwise specified, t he default occurrence of a t ag is 'm ust occur once and only once') , so our XML dat a file can only be for one aut hor. The fourt h line st at es t hat t he Aut hor elem ent is a com plexType, which m eans it cont ains ot her elem ent s. The fift h line st at es t hat all t he it em s wit hin t he Aut hor elem ent m ust be list ed in t he sequence shown in t he XSD file ( t hat is, Nam e, t hen Em ail, t hen Book) . The sixt h line defines an elem ent wit hin Aut hor called Nam e, of t ype st ring and t here m ust be one and only one of t hem . The use of t he /> at t he end of t he elem ent t ag is a short hand for creat ing a self- closing t ag, so is equivalent t o . The sevent h and eight h lines define an elem ent wit hin Aut hor called Em ail, of t ype st ring, which doesn't have t o occur (minOccurs="0") or t here can be any num ber of t hem ( maxOccurs="unbounded") .

Lines 915 define an elem ent wit hin Aut hor called Book, of which t here can be any num ber. I f provided, each Book elem ent m ust cont ain a single Tit le, Publisher and I SBN st ring elem ent in t hat order. Lines 1622 close out t he t ags. Before we im port any dat a files, we can check t hat t hey conform t o t hese rules ( assum ing we have t he XSD file t o check t hem against ) and rej ect any files t hat can't be validat ed.

Overview of Excel 2003's XML Features

N OTE The XML feat ures added t o Excel 2003 are only available in t he Professional version of Office and St andalone version of Excel; t hey have been disabled in t he St andard and St udent versions of Office. I n pract ice, t his m eans t hat if we want t o ut ilize t he new XML feat ures, we and all our users m ust be running Office 2003 Professional.

Throughout t his book, we've been st ressing t he im port ance of physically separat ing our dat a from our code, so we can easily updat e our code wit hout affect ing t he dat a; our PETRAS t im esheet addin has undergone som e m aj or changes, but our t im esheet t em plat e file has st ayed ( pret t y m uch) t he sam e t hroughout . We've been a lit t le quiet , t hough, about what we should consider our " code" t o be, and hence where t o put t he break bet ween applicat ion and dat a. That is because t he only real choice we've had is t o put t he break at t he boundary bet ween VBA and our Excel workbooks and t em plat es. Whenever we've had a new set of dat a t o st ore, we've st ored it inside a copy of our t em plat e. That leaves us a lit t le concerned and hopeful t hat we don't have t o change anyt hing in t he t em plat e. I f we discovered a bug in t he dat a validat ion set t ings, we would have t o open and updat e every copy of every t im esheet subm it t ed using t hat t em plat e ( or j ust ignore it for archived files! ) . We haven't really separat ed our dat a from our logic. Wit hin each of our dat a files, we're st oring lot s of form at t ing, validat ion and ancillary inform at ion as well as t he dat a ent ered int o t he t im esheet . What we would really like t o do is t o com plet ely separat e t he raw dat a from t he form at t ing and dat a validat ion, so we would only need one copy of t he dat a- ent ry workbook on each m achine which could im port and export t he raw dat a. That 's exact ly what Excel 2003's XML feat ures enable us t o do! Using Excel 2003's new XML Source t ask pane, we can im port an XML schem a definit ion file int o a workbook and link t he elem ent s defined in t hat file t o cells ( for t he single elem ent s) or List s ( for t he m ult iple- occurring elem ent s) in t he workbook. We can t hen im port any XML dat a file t hat conform s t o t he schem a int o our workbook. Excel will parse t he XML dat a file, check t hat it conform s t o t he schem a, read t he dat a from all t he elem ent s and populat e t he linked cells and list s. Figure 23- 1 shows an Excel 2003 workbook cont aining t he

XSD from List ing 23- 2 and having im port ed t he XML dat a from List ing 23- 1.

Figu r e 2 3 - 1 . An Ex ce l W or k book Lin k e d t o a n XM L Sch e m a [View full size image]

We can also t ype dat a int o t he linked cells and list s and export t he dat a as an XML file. Excel will creat e an XML dat a file t hat conform s t o t he schem a and cont ains t he dat a from t he linked cells and list s. Excel's XML feat ures can great ly help wit h t he m aint enance of our financial m odels as well. Unt il Excel 2003, if we want ed t o use our m odel t o analyze different dat a set s, we would have t o use a separat e copy of t he m odel workbook for each set . I f we subsequent ly found an error in our m odel, we would have t o open and updat e all t he copies. I n Excel 2003, we can creat e a schem a for our m odel's input variables and anot her schem a for it s result s, include t hem bot h in t he workbook and link t hem t o t he relevant cells or List s. We can t hen use a single copy of t he m odel workbook t o im port t he input variables, calculat e t he m odel and export t he result s. The new XML feat ures are, of course, all exposed t o VBA, so we can easily ident ify which cells are linked t o which elem ent s of which schem as ( and vice versa) , read and writ e t he XML t o/ from st rings as well as ( or inst ead of) im port ing and export ing files and respond t o event s raised bot h before and aft er XML dat a is im port ed or export ed.

A Simple Financial Model To dem onst rat e how Excel 2003 uses XML, we'll creat e a sim ple financial m odel t hat calculat es t he net present value of a list of cash flows, giving us t he num ber of flows, t he t ot al cash flow and t he net present value. We'll also record t he m odel's version num ber and t he dat e and t im e t he m odel was calculat ed. Figure 23- 2 shows t he spreadsheet for t he m odel, which can also be found in t he Model1.xls workbook on t he CD in t he \ Concept s\ Ch23Excel, XML and Web Services folder.

Figu r e 2 3 - 2 . Th e N e t Pr e se n t Va lu e Ca lcu la t ion M ode l

Not e t hat t he Flows dat a in B9: B13 is in an Excel 2003 List , so as dat a is t yped int o it , t he references used in t he funct ions in cells E9: E11 are aut om at ically updat ed. This is obviously a very sim ple financial m odel t o dem onst rat e t he principles. I n pract ice, t here m ay be m any set s of input dat a, m any worksheet s of calculat ions, pivot t ables and so fort h, and a large set of result s. Let 's assum e for now we want t o analyze m any set s of dat ain t his case, different com binat ions of rat es and cash flows, and we want t o st ore each set of dat a som ewhere, so we can com e back t o it at a lat er dat e. Let 's also im agine t his is a large and com plex m odel, so we would prefer not t o have m ult iple copies of it t o keep in sync. What we'd really like t o do is t ell Excel what bit s of t he file are t he raw dat a and be able t o im port and export j ust t hat dat a in a form we could edit and m aybe even creat e offline. Wit h Excel 2003, we can do exact ly t hat .

Creating an XML Schema Definition The first st ep is t o creat e an XML schem a definit ion ( XSD) file t o define our raw dat a. I f we already have an XML file cont aining som e dat a we want t o im port , Excel can infer an XSD from it . Excel generally does quit e a good j ob at inferring t he st ruct ure, but we have m ore cont rol over t he det ails if we define it ourselves. For exam ple, in t he Aut hors XML file in List ing 23- 1, t he dat a file included a single e- m ail address. Excel will infer t he schem a only allows one address, but t he real schem a allows m ult iples. Excel also always assum es dat a is opt ional, while we've m ade t he aut hor nam e m andat or y . All t he input dat a is shown wit h a light shading in Figure 23- 2, from which we can see t he st ruct ure we would like t o em ulat e:

There is a single block of cont rol inform at ion, which m ust exist . Wit hin t he cont rol inform at ion, we have a nam e, e- m ail address and com m ent . For t his exam ple, we'll m ake t he nam e and e- m ail required, but t he com m ent opt ional. Each it em can only occur once ( if at all) and t hey're all st rings. We t hen have a single block of dat a inform at ion, which m ust exist . The dat a inform at ion cont ains a single Rat e figure and m ult iple Flows figures, all of which are Doubles. Alt hough not required by t he NPV funct ion, we'll require a m inim um of t wo cash flow am ount s. The XSD for t his dat a is shown in List ing 23- 3, which includes a root NPVModelDat a elem ent t o cont ain our dat a t ypes.

List in g 2 3 - 3 . Th e XSD File for t h e N PV M ode l D a t a

















As t his is XML, you should be able t o read List ing 23- 3 and see t he direct correlat ion t o t he dat a in

our worksheet and t he previous st at em ent s about t he st ruct ure we want t o em ulat e. A few not ewort hy point s are as follows: We always st art an XSD file wit h t he sam e first t wo lines. Every elem ent t hat is a cont ainer of ot her elem ent s m ust be followed by t he t ag and a t ag t o ident ify how t he elem ent s are cont ained. I n t his exam ple ( and in m ost cases) , we use t he t ag t o say t hat t he elem ent s are cont ained in t he sequence shown. The Com m ent elem ent includes t he at t ribut es minOccurs="0" maxOccurs="1", which is how we specify an opt ional it em ; it doesn't have t o occur ( minOccurs="0") , but if it does occur, t here can only be one of t hem (maxOccurs="1") . The Flows elem ent includes t he at t ribut es minOccurs="2" maxOccurs="unbounded", which is how we specify t hat t here m ust be at least t wo cash flows, but t here can be any num ber. Theoret ically, we should put maxOccurs="65527", as t hat is t he m axim um num ber of flows t hat will fit on our m odel worksheet .

XML Maps Now t hat we have an XSD file describing our dat a, we need t o t ell Excel t o use it and t o link each elem ent in t he XSD file t o a worksheet cell or range. I m port ing t he schem a and linking it t o cells is known as m a p p in g and Excel refers t o t hese as XM L M a ps ( which is Excel's t erm inology, not an indust ry- wide one) . So let 's m ap our XSD t o our m odel. Open t he Model1.xls file, click View > Task Pane and select t he XML Source t ask pane from t he drop- down in t he t ask pane t it le bar, shown in Figure 23- 3.

Figu r e 2 3 - 3 . Se le ct in g t h e XM L Sou r ce Ta sk Pa n e [View full size image]

Click t he XML Maps…but t on at t he bot t om of t he XML Source t ask pane t o bring up t he XML Maps dialog, click t he Add but t on on t he dialog and browse t o t he XSD file. I f t he XSD is valid, Excel will im port t he schem a and creat e an XML m ap using it , as shown in Figure 23- 4. I f t here is an error in t he XSD, Excel will show you where it t hinks t he error is. Not e t hat if we select ed an XML dat a file inst ead of t he XSD, Excel would infer a schem a from t he XML dat a. I t is definit ely best pract ice, t hough, t o creat e and use an XSD file.

Figu r e 2 3 - 4 . Th e XM L M a p D ia log Aft e r Addin g t h e N PVM ode lD a t a Sch e m a

When we click OK on t he XML Map dialog, Excel exam ines t he schem a and displays it in t he XML

Source t ask pane, as shown in Figure 23- 5.

Figu r e 2 3 - 5 . Th e XM L Sou r ce Ta sk Pa n e , Sh ow in g t h e N PVM ode lD a t a Sch e m a

Not e t hat Excel has ident ified t he hierarchical st ruct ure of t he schem a, t he elem ent s t hat are required ( shown wit h an ast erisk in t he icon) and t he elem ent s t hat are repeat ing ( shown by t he arrow at t he bot t om of t he Flows icon) . The final st ep is t o associat e t he elem ent s in t he schem a wit h t he dat a- ent ry cells in our m odel worksheet . We do t his by select ing each elem ent from t he t ree in t he t ask pane, dragging it t o t he worksheet and dropping it on t he cell t hat we want t o link it t o. I n Figure 23- 6, we're dragging t he Subm it t edBy elem ent and dropping it on cell B4.

Figu r e 2 3 - 6 . D r a g a n d D r op t h e Ele m e n t s fr om t h e Ta sk Pa n e t o t h e W or k sh e e t

[View full size image]

Sim ilarly, we'll m ap t he rest of t he schem a t o our worksheet by dropping t he Em ail elem ent t o B5, t he Com m ent elem ent t o B6, t he Rat e elem ent t o A10 and t he Flows elem ent t o B10 ( or anywhere inside t he Flows list ) . As we do t hat , Excel annoyingly adj ust s t he colum n widt hs of each cell t o fit t he dat a it cont ains. We would m uch prefer t he default behavior t o not do t hat , but we can swit ch it off by right - clicking one of t he m apped cells and choosing XML > XML Map Propert ies from t he popup m enu t o display t he XML Map Propert ies dialog shown in Figure 23- 7, in which we've set t he propert ies t hat we recom m end using. We should be able t o access t his dialog from t he XML Maps dialog we used t o select a m ap, but for som e reason, we can't !

Figu r e 2 3 - 7 . Th e Re com m e n de d Se t t in gs for XM L M a p Pr ope r t ie s

The first check box Validat e dat a against schem a for im port and export default s t o off, but in our opinion is t he m ost im port ant set t ing in t he whole of Excel's XML support . Wit h it t urned on, Excel will verify t hat t he XML dat a files we im port conform t o t he form at defined in t he schem a and t hat t he dat a we t ype int o cells conform s t o t he schem a before allowing us t o export it . Turning off t hose checks seem s t o us t o invalidat e t he whole point of using XML in t he first placet hat of reliable and robust dat a t ransfer. That 's it ! We've defined t he raw dat a our financial m odel uses, creat ed an XSD file t o form ally specify it , added t he schem a t o t he m odel and linked t he elem ent s in t he schem a t o t he m odel's dat a ent ry cells. The com plet ed workbook can be found in t he Model2.xls workbook.

Exporting and Importing XML Data The m enu it em s t o im port and export our XML dat a can be found on t he Dat a > XML m enu, wit h t oolbar but t ons also locat ed on t he List t oolbar. Using t he Export XML m enu result s in t he XML dat a

file for our m odel shown in List ing 23- 4.

List in g 2 3 - 4 . Th e XM L D a t a File Pr odu ce d fr om Ou r M ode l

Stephen Bullen [email protected] Fee Fi Fo Fum

0.05 10 20 30 40

Hopefully, everyt hing in t he file m akes sense by now, part icularly t he m ult iple elem ent s. I f we delet e t he elem ent , add a few m ore elem ent s t o t he bot t om , save it wit h a different nam e and use t he I m port XML m enu t o im port it int o our m odel, we get t he worksheet shown in Figure 23- 8. Rem em ber t hat our XSD file specified t he t ag as opt ional, so our file passes t he schem a validat ion even t hough t he com m ent dat a is m issing. The ext ra elem ent s have been included in t he List , which has aut om at ically ext ended t o accom m odat e t hem , and t he form ulas in cells E9:E11 have also aut om at ically been adj ust ed t o suit !

Figu r e 2 3 - 8 . I m por t in g a n XM L D a t a File Adj u st s t h e Ra n ge s

We have achieved our goal of being able t o t ot ally separat e our dat a from our m odel, im port ing and export ing t he dat a as we choose, wit h t he m odel aut om at ically updat ing t o use t he new dat a as we im port it .

The XML Object Model and Events Now t hat we can im port and export t he raw dat a for t he m odel, we'll probably want t o im port t he dat a and t hen export t he result s, wit h t he export file cont aining a copy of t he input dat a, det ails about t he m odel it self, such as t he version num ber and when t he calculat ion was done, and t he m odel's result s. List ing 23- 5 shows t he XSD file for t he full set of our NPVModel dat a, which can be found on t he CD in t he NPVModel.XSD file. The definit ion for t he NPVModelDat a schem a from List ing 23- 5 has been included inside t he new root NPVModel t ag and we've added elem ent s for t he m odel det ails and result s. I t looks com plicat ed, but isn't reallyj ust rem em ber t hat when we want t o nest one elem ent inside anot her, we have t o include a pair of and t ags bet ween t hem .

List in g 2 3 - 5 . Th e Fu ll XSD File for Ou r M ode l



































We can add t his schem a t o our m odel as a second XML m ap and m ap t he NPVModelDet ails and NPVModelResult s elem ent s t o t he appropriat e cells in colum n E. When we t ry t o m ap t he Cont rolI nform at ion elem ent s t o t he cells in colum n B, however, Excel displays an error m essage

" The operat ion cannot be com plet ed because t he result would overlap an exist ing XML m apping" and prevent s us from doing t he m apping. This is because Excel lim it s us t o a one- t o- one relat ionship bet ween cells and XML elem ent s; any one cell can only m ap t o one elem ent from one XML m ap and vice versa. We want all our input dat a t o m ap t o bot h t he NVPModelDat a m ap ( so we can im port it ) and t he NVPModel m ap ( so we can include it in t he export ) . The only way we can achieve our obj ect ive is t o have a copy of t he input dat a t hat we include in our NPVModel m ap, as shown in Figure 23- 9. All t he single it em s, such as t he e- m ail address and rat e, can be linked using st andard worksheet form ulae, but t he list s will have t o be synchronized t hrough VBA.

Figu r e 2 3 - 9 . M a ppin g t h e N PVM ode l Ele m e n t s t o a Copy of t h e I n pu t D a t a

Fort unat ely, Excel 2003 includes a rich obj ect m odel and event m odel for working wit h XML m aps. We can use t he Workbook_BeforeXMLExport event t o copy t he Flow dat a from t he input range ( B9

and below) t o t he export range ( G8 and below) , using t he m apping t o ident ify t he ranges in each case, as shown in List ing 23- 6.

List in g 2 3 - 6 . Copyin g t h e I n pu t Flow s List t o t h e Ex por t Copy 'Run before any XML is exported Private Sub Workbook_BeforeXMLExport(ByVal Map As XMLMap, _ ByVal Url As String, Cancel As Boolean) Dim rngSource As Range Dim rngTarget As Range 'Are we exporting the full Model data? If Map.RootElementName = "NPVModel" Then 'Find the data part of the target list Set rngTarget = Sheet1.XMLDataQuery( _ "/NPVModel/NPVModelData/InputData/Flows") 'If there is any existing data in the target list, 'remove it. If Not rngTarget Is Nothing Then rngTarget.Delete 'Find the data part of the source list Set rngSource = Sheet1.XMLDataQuery( _ "/NPVModelData/InputData/Flows") 'Is there any source data to copy? If Not rngSource Is Nothing Then 'Find the header part of the target list Set rngTarget = Sheet1.XMLMapQuery( _ "/NPVModel/NPVModelData/InputData/Flows") 'Copy the data to the cell below the target list header rngSource.Copy rngTarget.Cells(1).Offset(1, 0).PasteSpecial xlValues End If End If End Sub

Wit hin t he obj ect m odel, t he linking bet ween ranges and XML schem a elem ent s is done using XPat hs. The XPat h is a concat enat ed st ring of all t he elem ent nam es in an elem ent 's hierarchy, so t o get t o t he Flows elem ent in t he NPVModelDat a m ap, we st art at t he root NPVModelDat a, go down t o t he I nput Dat a elem ent and t hen t o t he Flows elem ent , so t he XPat h for t he Flows elem ent in t hat m ap is /NPVModelData/InputData/Flows. This is st ored in t he XPat h propert y of t he Range

obj ect , so we can direct ly find out which elem ent a range is m apped t o. To find t he range m apped t o a given elem ent , we use t he XMLMapQuery and XMLDat aQuery m et hods, passing t he XPat h of t he elem ent . I t 's a curiosit y of t he obj ect m odel t hat while XML m aps are workbook- level it em s and an elem ent can be m apped t o any range in any sheet in t he workbook, t he XMLMapQuery and XMLDat aQuery m et hods are worksheet - level m et hods. I f we didn't know which sheet t he range was on, we would have t o scan t hrough t hem all, repeat ing t he XMLMapQuery for each. Bot h XMLMapQuery and XMLDat aQuery ret urn t he range t hat is m apped t o a given XPat h st ring. The only difference bet ween t hem is when t he m apped range is a List ; t he XMLMapQuery ret urns t he full range of t he List , including t he header row, whereas t he XMLDat aQuery ret urns only t he dat a in t he List , or Not hing if t he List is em pt y. Wit h j ust a few m ouse clicks, we can now im port som e raw dat a for our financial m odel, recalculat e it and export t he result s, giving an XML dat a file like t he one shown in List ing 23- 7.

List in g 2 3 - 7 . Th e XM L D a t a File fr om Ou r N PV M ode l



Stephen Bullen [email protected] Fee Fi Fo Fum

0.05 10 20 30 40

1.0 2004-07-01T13:44:04.430

4 100 86.49

I t 's not hard t o envisage our financial m odel being used as a " black box" service, whereby individuals ( or ot her applicat ions) subm it XML files cont aining t he raw dat a for t he m odel, we im port it , calculat e and export t he result s and send t hem back.

Not ice t he very specific form at used for t he dat e and t im e in t he CalcDat e elem ent , which is how XML avoids t he issues of ident ifying different dat e form at s. I t doesn't , however, account for different t im e zones! By adding t he abilit y t o export result s direct ly from our m odel, we've also creat ed a vulnerabilit y. Users could im port dat a int o t hat m ap as well, which would overwrit e our form ulas! We can prevent t his using t he Workbook_BeforeXMLI m port event , as shown in List ing 23- 8.

List in g 2 3 - 8 . Pr e ve n t I m por t in g of t h e Re su lt s XM L 'Run before any XML is imported Private Sub Workbook_BeforeXMLImport(ByVal Map As XMLMap, _ ByVal Url As String, ByVal IsRefresh As Boolean, _ Cancel As Boolean) 'Are we importing to the full Model data? If Map.RootElementName = "NPVModel" Then 'Yes, so disallow it MsgBox "The XML file you selected contains the " & _ "results for this model, and can not be imported." 'Cancel the import Cancel = True End If End Sub

XML Support in Earlier Versions Excel 2003 has m ade t he handling of arbit rary XML files ext rem ely easy, but we don't h a ve t o upgrade t o Excel 2003 t o use XML. As m ent ioned at t he st art of t he chapt er, XML is j ust anot her t ext file form at , so in t heory we can read and writ e XML files using st andard VBA t ext handling and file I / O code. When Excel 2003 im port s an XML dat a file, it uses t he MSXML library t o do t he validat ion and parsing of t he file, and t here's not hing st opping us referencing t he sam e library from VBA. Of course, we also have t o writ e our own rout ines t o im port t he dat a from t he MSXML st ruct ure t o t he worksheet and export t he dat a from t he sheet t o an XML file. Mult iple- version com pat ibilit y is one of t he key design goals for our PETRAS t im esheet applicat ion, so we show t he VBA t echnique in t he Pract ical Exam ple sect ion at t he end of t his chapt er. The VBA t echnique is also required in Excel 2003 if t he st ruct ure of t he XML dat a is t oo com plex t o be handled by Excel's fairly sim plist ic m apping abilit ies. For exam ple, our PETRAS t im esheet workbook includes a t able of client s and proj ect s, wit h t he client nam es across t he t op and t he proj ect s list ed below each client ( t o feed t he dat a validat ion drop- downs) . I t is not possible t o m ap an XML schem a t o t hat layout , so t he im port of t hat sect ion of t he XML dat a file has t o be done wit h VBA in all versions of Excel.

Using Namespaces All of t he exam ples shown so far in t his chapt er have ignored t he use of nam espaces. This m eans t he XML files we use and produce are only ident ified by t he root elem ent s of NPVModel and NPVModelDat a. There is not hing in t he file t o ident ify t hem as t he dat a for ou r NPV m odel. This m eans t hat , in t heory, som eone else could creat e an XML file t hat uses a very sim ilar st ruct ure t o ours and we could im port it wit hout knowing it was not int ended for our applicat ion. To avoid t his, we can include a nam espace ident ifier bot h in t he XSD and XML files, which is used t o uniquely ident ify all t he t ags in t he file, and hence t he dat a t hey cont ain. When t he file is processed, t he nam espace is prepended t o all t he t ags, allowing t he parser t o dist inguish bet ween, say, t he Nam e elem ent in t his file denot ing t he aut hor's nam e and t he Nam e elem ent in a workbook file denot ing an Excel Defined Nam e. The t ext of t he nam espace can be any st ring, but should be globally unique. I t is general pract ice t o use a URL, which has t he advant age t hat t he viewer of t he file could browse t o t he URL in t he hope of finding a descript ion of t he nam espace. We t ell Excel t he nam espace t o use by including it wit hin t he t ag at t he t op of our XSD file, as shown in List ing 23- 9 and included on t he CD in t he file NPVModelDat a - NS.xsd.

List in g 2 3 - 9 . Pr ovidin g Ex ce l w it h a N a m e spa ce

...

When t hat schem a is added t o a workbook, Excel will rem em ber t he nam espace, creat e an alias for it , such as ns0, ns1, ns2 and so on, and add t hat alias t o t he front of all t he elem ent s in t he file, as shown in Figure 23- 10.

Figu r e 2 3 - 1 0 . All t h e XM L Ele m e n t s a r e Pr e fix e d w it h t h e N a m e spa ce Alia s

When t he XML is export ed, Excel includes t he nam espace in t he file and qualifies all t he elem ent s wit h t he nam espace alias, as shown in List ing 23- 10.

List in g 2 3 - 1 0 . Pr ovidin g Ex ce l w it h a N a m e spa ce

Stephen Bullen [email protected] Fee Fi Fo Fum

0.05 10 20 30 40

I t is definit ely a good pract ice t o use nam espaces in our XML files, t o avoid any chance of Excel im port ing erroneous dat a int o our applicat ions. The only reason we haven't used t hem so far in t his chapt er is t o avoid overcom plicat ing our explanat ion of Excel's XML feat ures.

Web Services Like XML, W e b se r vice s is anot her t erm you've probably heard about wit h m ild curiosit y, but ult im at ely rej ect ed as being irrelevant t o Excel. This sect ion aim s t o explain what Web services are, how t o creat e t hem ( using Visual Basic.NET) and how t hey can play an im port ant role in our applicat ions. What we will n ot do is explain how t hey work, because t hat is largely irrelevant t o us as Excel developers. A Web service is a piece of code running on a com put er som ewhere t hat we can find, connect t o and use from anywhere in t he world ( as long as we have an I nt ernet connect ion) . The com put er on which t he Web service is running can be very t ight ly cont rolled, m onit ored and secured, forcing t he client s t o t reat t he code as a " black box" t he user of t he Web service can only see it s input and out put s and cannot access t he program it self. This m akes Web services ideal for providing inform at ion in a very cont rolled and regulat ed m anner by running applicat ions on t he server inst ead of dist ribut ing applicat ions which m ight include sensit ive inform at ion ( such as dat abase I Ds and passwords) and/ or int ellect ual propert y ( such as a propriet ary financial m odel) and run t he risk of t hem being hacked. Addit ionally, we only need t o m anage one copy of t he code, running on t he server, so as soon as we m odify t he code and copy it t o t he server, all users im m ediat ely st art using t he new version. Any applicat ion t hat exposes it s funct ionalit y t o such a wide audience is going t o have t he problem of how t o specify and validat e t he dat a it accept s and t he result s it produces, which is where XML com es int o t he pict ure. All t he com m unicat ion bet ween t he Web service and it s client is done using XML. But haven't we j ust been discussing how Excel 2003 can read and writ e arbit rary XML dat a files? So shouldn't we be able t o point t he XML export / im port t o a Web service som ewhere and be able t o call t he propriet ary financial m odel direct ly from t he worksheet ? I n t heory, yes we should, but t he final st ep is m issing from Excel 2003; we have t o glue t he ends t oget her using VBA. And haven't we j ust been dem onst rat ing how t o creat e a propriet ary financial m odel in Excel 2003 t hat accept s XML for it s input s and writ es it s result s as XML t oo? So we could put t hat on t he server and, hey prest o, we have a Web service? Again, in t heory, yes. Unfort unat ely, Excel is not designed t o run on a server, doesn't scale at all and Microsoft st rongly discourages us from using Excel in t hat way. Nor does Excel 2003 include t he glue t o expose an Excel workbook as a Web service. So we can't connect direct ly t o a Web service from Excel and we can't use Excel as a Web service, but we can use VBA t o connect t o a Web service, eit her t o m ake use of propriet ary calculat ions or t o access dat a from and send dat a t o a cent ral dat abase, over t he I nt ernet . Being able t o do t his m eans we can t ake our Excel applicat ions out of t he office, but st ill allow t hem t o connect t o t he corporat e dat a. I n t his part of t he chapt er, we explain how t o creat e a sim ple Web service for a financial m odel and connect t o it from VBA, so we can call it direct ly from t he worksheet . I n t he Pract ical Exam ple sect ion, we m odify t he PETRAS t im esheet add- in t o ret rieve dat a from and send dat a t o a Web service. I nst ead of t he t im esheet add- in connect ing direct ly t o a dat abase on t he net work, t he Web service will handle t he dat abase connect ion. I n bot h cases, we focus on using t he Web service,

rat her t han creat ing one wit h all t he scalabilit y and securit y considerat ions. For t his exam ple we use a local Web server ( http://localhost) t o run t he Web service. To run t he exam ples in t his sect ion, you will need a com put er running I nt ernet I nform at ion Services and have Visual St udio.NET 2003 t o creat e t he Web service. The Excel part of t he exam ple works in any version from Excel 2000 forward.

Creating a Web Service with VB.NET To dem onst rat e how t o connect t o and use a Web service from Excel, we'll creat e a very sim ple one t o reproduce t he AddTwo and Mult iplyTwo funct ions seen in Chapt er 19 XLLs and t he C API . St art Visual St udio.NET 2003, st art a new proj ect , choose t he ASP.NET Web Service Visual Basic proj ect and renam e t he locat ion t o ht t p: / / localhost / ProExcelDev, as shown in Figure 23- 11.

Figu r e 2 3 - 1 1 . Cr e a t in g a N e w Visu a l Ba sic W e b Se r vice [View full size image]

Click OK t o let Visual St udio creat e a new Web service proj ect . This proj ect includes a class called Service1 t hat we want t o renam e t o be Mat hs. The nam e needs t o be changed in bot h t he filenam e ( by edit ing t he filenam e in t he Solut ion Explorer t ree) and t he class nam e ( by edit ing t he code m odule) . I n List ing 23- 11 we've changed t he class nam e in bot h lines t hree and four and added t he t wo funct ions we want t o m ake available t o users of our Web service.

List in g 2 3 - 1 1 . Th e Pr oEx ce lD e v M a t h s W e b Se r vice 'The Professional Excel Development Maths Web Service Imports System.Web.Services _ Public Class Maths Inherits System.Web.Services.WebService [Web Services Designer Generated Code] 'Add two numbers _ Public Function AddTwo(ByVal d1 As Double, _ ByVal d2 As Double) As Double Return d1 + d2 End Function 'Multiply two numbers _ Public Function MultiplyTwo(ByVal d1 As Double, _ ByVal d2 As Double) As Double Return d1 * d2 End Function End Class

That 's all t here is t o it ; we've creat ed a Web service! The key bit is t he at t ribut e t hat we add t o any funct ions we want t o expose. I n t his exam ple, we're only passing sim ple dat a t ypesdoublesbut in t he PETRAS Web service, we'll be passing and ret urning m ore com plex dat a set s, using XML. Build t he solut ion, close Visual St udio and let 's get on wit h t he int erest ing bit using t he Web service from Excel.

Using a Web Service Excel's Web Service connect ivit y is provided by t he Microsoft Office Soap Type Library, m ssoap30.dll, included in t he Office Web Services Toolkit . The t oolkit is an opt ional inst all in Office 2003 Professional and can be down loaded by following t he Office 2003: Web Services Toolkit 2.01 link from ht t p: / / m sdn.m icr osoft .com / office/ dow nloads/ t oolsut ils/ default .aspx. When deploying applicat ions t hat use Web services, our users will also need t o have t he Web Services Toolkit inst alled, t o provide t hem wit h t he m ssoap30 DLL and it s dependencies. As well as cont aining t he t ype library, t he t oolkit includes an add- in t o t he VBI DE t hat enables us t o find and select Web services, t hen adds classes t o our VBProj ect s t o wrap t he calls int o t he Soap Type Library and

expose t he Web service as a st andard VBA class ( or set of classes) . Despit e it s nam e, t he Web Services Toolkit is not dependent on Excel 2003 and works fine in all versions from Excel 2000 for w ar d. Download and inst all t he t oolkit , swit ch t o t he Excel VBE and click on Tools > Web Service Ref er en ces…t o bring up t he Microsoft Office Web Services Toolkit dialog. This dialog provides t he capabilit y t o search for a Web service by keyword ( by linking t o a Microsoft Web sit e for t hat inform at ion) , but we'll provide it wit h t he locat ion of t he ProExcelDev Mat hs Web service we creat ed above. When we built t he Web service, Visual St udio com piled our source code int o a file called Mat hs.asm x, which is t he Web service equivalent of an EXE or DLL. Because we know which file t o connect t o, we can t ell t he Web Services Toolkit t o connect direct ly t o it and search for t he Web services it cont ains, as shown in Figure 23- 12.

Figu r e 2 3 - 1 2 . Con n e ct in g t o t h e Pr oEx ce lD e v M a t h s W e b Se r vice [View full size image]

When we click t he Add but t on, t he t oolkit will creat e class m odules for each of t he Web services we've t icked in t he t op- right box. So t ick t he Mat hs Web service, click Add and look at t he generat ed code in t he new clsws_Mat hs class t he t oolkit j ust creat ed. An ext ract of t he generat ed code is shown in List ing 23- 12 ( where we've rem oved t he error handling and changed a few com m ent s for clarit y) .

List in g 2 3 - 1 2 . Th e Ge n e r a t e d Cla ss t o Con n e ct t o t h e M a t h s W e b Se r vice 'Dimensioning private class variables. 'The sc_Maths object handles all the communication Private sc_Maths As SoapClient30 'These constants reflect the selections in the dialog, 'and tell the class where to connect to Private Const c_WSDL_URL As String = _ "http://localhost/ProExcelDev/Maths.asmx?wsdl" Private Const c_SERVICE As String = "Maths" Private Const c_PORT As String = "MathsSoap" Private Const c_SERVICE_NAMESPACE As String = _ "http://tempuri.org/ProExcelDev/Maths" Private Sub Class_Initialize() Dim str_WSML As String str_WSML = "" Set sc_Maths = New SoapClient30 'Initialize the connection to the Web service sc_Maths.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE, _ c_PORT, c_SERVICE_NAMESPACE sc_Maths.ConnectorProperty("ProxyServer") = "" sc_Maths.ConnectorProperty("EnableAutoProxy") = True End Sub Private Sub Class_Terminate() Set sc_Maths = Nothing End Sub 'Wrapper for the AddTwo function in our Web service Public Function wsm_AddTwo(ByVal dbl_d1 As Double, _ ByVal dbl_d2 As Double) As Double wsm_AddTwo = sc_Maths.AddTwo(dbl_d1, dbl_d2) End Function 'Wrapper for the MultipleTwo function in our Web service Public Function wsm_MultiplyTwo(ByVal dbl_d1 As Double, _ ByVal dbl_d2 As Double) As Double wsm_MultiplyTwo = sc_Maths.MultiplyTwo(dbl_d1, dbl_d2)

End Function

The class m odule is generat ed from t he select ions we m ade in t he Web Services Toolkit dialog. The class uses a m odule- level variable called sc_Mat hs t o hold a reference t o a SoapClient 30 obj ect , which does all t he com m unicat ion wit h t he Web service for us. The const ant s at t he t op of t he m odule specify t he locat ion of t he Web service, it s nam e and so on, which are used in t he Class_I nit ialize event t o connect t o t he service. The rest of t he class cont ains wrappers for each funct ion exposed by our Web service, each of t hem having t he prefix wsm _, for Web service m et hod. As t his is j ust a norm al class m odule, we can, of course, change t he nam es t o anyt hing we want , add m ore propert ies, and so fort h. To use t he Web service from our VB code, we creat e an inst ance of t he class and call t he wrapper funct ions, as shown in List ing 23- 13.

List in g 2 3 - 1 3 . Usin g t h e M a t h s W e b Se r vice Sub Add1And2() Dim clsMaths As clsws_Maths Set clsMaths = New clsws_Maths MsgBox "1 + 2 = " & clsMaths.wsm_AddTwo(1, 2) End Sub

We could, of course, put t he sam e code in a st andard VBA user- defined funct ion and call it from t he worksheet , so if, say, a propriet ary pricing funct ion has been exposed as a Web service, we can now use it wit hin our worksheet s!

Practical Example The exam ples used t o explain XML and Web services were obviously very sim ple so we could focus on t he t echnology and how t o use it , part icularly wit h t he explanat ion of Web services. I n t he pract ical exam ple for t his chapt er, we creat e a rat her m ore com plex Web service t o act as an int erface bet ween our PETRAS t im esheet add- in and t he cent ral dat abase used t o st ore t he st at ic inform at ion of consult ant s, client s and proj ect s and subm it t ed t im esheet dat a. By using t he Web service, our consult ant s can now access t he t im e sheet inform at ion over t he I nt ernet , enabling t hem t o subm it t heir t im esheet s from anywhere in t he world. The dat a sent bet ween t he Web service and t he add- in will be done using XML, which m akes it ext rem ely easy t o connect t o t he dat abase and enables us t o validat e t he dat a st ruct ure at each end of t he com m unicat ion. Specifically, t he following dat a will be passed bet ween t he Web service and t he add- in: At st art up, t he add- in will ret rieve som e XML cont aining t he st at ic list s of consult ant s, client s, proj ect s and act ivit ies, by calling t he Web service's Get St at icDat a funct ion. When t he user clicks t he Post Tim esheet Dat a but t on, t he add- in will generat e som e XML t o cont ain t he t im esheet dat a and send it t o t he Web service, which will st ore it in t he cent ral dat abase.

PETRAS Web Service The new PETRAS Web service has been writ t en using Visual Basic.NET, connect ing t o t he sam e Access dat abase we int roduced in Chapt er 13 Program m ing wit h Dat abases, but t his t im e using ADO.NET. Visual St udio.NET creat es num erous files for a Web service. The int erest ing files are: St a t icD a t a . XSD , cont aining t he XSD file for t he XML ret urned by t he Get St at icDat a funct ion Tim e Sh e e t .XSD , cont aining t he XSD file for t he XML passed t o t he St oreTim eSheet funct ion PETRAS.a sm x, cont aining t he code for t he Web service The Web service provides t he following t wo funct ions: Ge t St a t icD a t a , which ret urns an XML dat a set cont aining all t he list s of consult ant s, act ivit ies, client s and proj ect s. An exam ple of t he XML ret urned is shown in List ing 23- 14. Not ice t hat t he Proj ect elem ent s for a client are nest ed inside t he Client elem ent . St or e Tim e Sh e e t , which is passed an XML dat a set cont aining t he t im esheet dat a ent ered int o t he Excel sheet , writ es t he dat a t o t he BillableHours t able of t he Access dat abase and ret urns a confirm at ion m essage t hat includes t he num ber of rows insert ed. An exam ple of t he XML

passed is shown in List ing 23- 15.

List in g 2 3 - 1 4 . Ex a m ple XM L Ou t pu t fr om t h e Ge t St a t icD a t a Fu n ct ion

1 Rob Bovey

2 Stephen Bullen

1 General Programming

2 Phone Conference

1 Big Auto Corp.

1 BAC 1

2 BAC 2



List in g 2 3 - 1 5 . Ex a m ple XM L Pa sse d t o t h e St or e Tim e Sh e e t Fu n ct ion

2 Stephen Bullen

2004-07-04

2004-07-01 2

1 6.75

2004-07-02 2 1 7.5

All of t he dat a connect ivit y for t he Web service is set up using Visual St udio's wizards, result ing in t he following obj ect s t hat can be seen on t he Web service's " Design" page: con PETRASD bCon n e ct ion An OleDbConnect ion used t o define t he connect ion t o t he Access dat abase. da Con su lt a n t s, da Act ivit ie s, da Clie n t s a n d da Pr oj e ct s OleDbDat aAdapt ers, used t o ret rieve t he list of consult ant s, act ivit ies, client s and proj ect s from t he dat abase. cm D e le t e Tim e An OleDbCom m and t o delet e t im esheet records from t he dat abase. When a t im esheet is subm it t ed, any previous records for t he sam e consult ant and period are delet ed. cm I n se r t Tim e An OleDbCom m and t o insert t im esheet records int o t he dat abase. When we include an XSD file in a Visual St udio.NET proj ect , we have t he opt ion of aut om at ically creat ing a Dat aSet from t he schem a. Aft er we've done t hat , we can m ap t he elem ent s in our schem a t o fields in a Dat aAdapt er, in m uch t he sam e way t hat Excel 2003 enables us t o m ap elem ent s t o worksheet cells. I n our Web service, each sect ion of t he schem a is m apped t o it s own Dat aAdapt er. ( For exam ple, t he < I D> and < Nam e> in t he < Consult ant > elem ent s in t he XSD are m apped t o t he Consult ant I D and Nam e fields in t he daConsult ant s Dat aAdapt er.) Having m apped everyt hing in our St at icDat a schem a t o t he Dat aAdapt ers, we can ret rieve t he XML for all our st at ic list s by t elling each of t he Dat aAdapt ers t o fill t heir part of t he schem a, t hen reading t he XML from t he dat a set , as shown in t he code for t he Get St at icDat a funct ion in List ing 23- 16.

List in g 2 3 - 1 6 . Th e Ge t St a t icTe x t Fu n ct ion