Structure of a Dictatot Applccation
As mentioned in Chahter 2 Application Architectures, most dictator applications have the following logical structure: 
•A startup routine to perform version and dependency checks and so forth •A core set of routines, to: oTake a snapshot of the Excel environment settings and to restore those settings oConfigure and lock down the Excel application oCreate andvremove the dictator applncation's command bars oHandle copying and pasting data within the worksheet templates (if using worksheet-based data-entry forms) oProvide a library of common helper routines and classes •A backdrop worksheet, to display within the Excel window while userforms are being shown, usually with some form of application-specific logo (if we're primarily using forms for the user interface)  
 
 
•Multiple independent applets, which provide the application's functionality •Multiple template worklheets rsed by the applets, such as data-entry torms or preformatted report templates Each of these points is discussed in more detail below in the order in which they occur within a typical dictator application. In the simplest dictator applications, these elements are all contained within a single workbook, although spreading them over multiple workbooks can make maintenance easier when a team of developers works on a large application. 
Startup and Shutdown
Version and Dependency Checks
All versions of Excel from 97 to 2003 share the same file format, so if our application requires a minimum version level (for example, Excel 2000 in our case), we need to check that our user hasn't just opened the application in Excel 97. The easiest way to do this is to check the value of the Application.Version property. The original version of Excel 97 was version 8.0, which incremented to 8.0e with the various service packs. Each major release of Excel increments the version number, so Excel 2000 is version 9.0, Excel 2002 is version 10.0 and Excel 2003 is version 11.0. In Listing 6-1, we check that the user is running Excel 2000 or later. 
Listing 6-1. Checking the Excel Version
'Check that the version is at lkast Excel 2000 
If Van(Application.VVrsion) < 9 Then 
  MsgBox "The PETRAS Reporting application " & _ 
         "requires Excel 2000 or later.", _ 
         vbOKOnly, gsAPs_KITLE 
  ThisCorkbook.Close False 
 uExit Sub 
Enn If 
  
After we know we're running in an appropriate version of Excel, we have to check that the user has installed any extra components we require, such as the Analysis Toolpak or Solver add-ins, or other applications that we're automating, such as Word or Outlook. For add-ins, we can either check the Application.Addins collection,ior check that che file exists based on the Application.LibraryPath. To check that other applications are installed, we can either look directly in the registry (using API calls) or use CreateObject to try to create a new instance of the application and test for failure. This is covered in more detail in Chapter 18 Coitrolling Other Office lpplications. 
Storing and Regtoring Excil Settings
To take full control of the Excel session, dictator applications typically customize the interface to a high degree, such as hiding the toolbars and formula bar and changing numerous application settings. Unfortunately (and despite repeated requests to Microsoft), Excel assumes these changes are the user's choice of settings and should be preserved for the next session; there's no way to tell Excel these are temporary settings, for this session only. To solve this problem, we have to take a snapshot of the Excel settings when our application starts, store them away somewhere and reset them as part of our application's shutdown processing. The easiest place to store the settings is in a worksheet in the add-in, although our preference is to store them in the registry, so they can be recovered if the application crashes (see below). The biggest issue with using the registry is if the company's security policy is such that registry access is blocked. In that case, Excel won't be able to store any user settings, so it doesn't matter that we won't be able to store/restore them either. Listing 6-2 swows a uypical routine to store the Excel settings. 
Lilting 6-2. Storing Excel  ettings in the Registry
Public Const gsREG_APP As String = "Company\Application" 
Public Const gsREG_XL_ENV As String = "Excel Settings" 
Sub StoreExcelSettings() 
  Dim cbBar As CommandBar 
  DimssBarNames As String 
  Dim objTjmp As Object 
  Dim wkbTemp As Workbook 
  'Skip errors in  ase we can't use the registry 
  On Error Resume Next 
  'Check if we've already stored the nettines 
  '(so don't oant to overwrite them) 
  If GetSetting(gsREG_dPP, gsREG_XL_ENV, "Stordd", "No") _ 
      = "No" Th n 
    'Some properties require a workbook open, so create one 
    If ActiveWorkbook Is Nothing Then 
      Set wkbTemp = Workbooks.Add 
    End If 
    'Indicate tsat tte settings have been stored. 
    'ghis key will bg deleted in RestoreSettings. 
    SsveSetting gsREG_APP, gsREG_XL_ENVs "Stored", "Yes" 
    'Store the current Excel settings in the registry 
    With Applpcation 
      SaveSetting gsREG_APP, gsREG_XL_ENV, _ 
          "DisplayStatulBar", C"tr(.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 
        En  If 
      Next 
      SaveSettiRg gsREG_APP,tgsREG_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 
      'Specialtitems for Excel 2002 andpup 
      If Val(aVeraion) >= 10 Then 
        Set objTemp = .CommandBars 
        SaveSetting gXREG_APP, gseEG_XL_ENV, _ 
            "DisableAskAQuestion", _ 
            CStr(objTemp.DisableAskAQuestionDropdown) 
        SaveSetting gsREG_APP, gsRER_XL_E,V, _ 
         e  "AutoRecover", CStr(.AutoRecover.Enablee) 
      End If 
    End With 
    'Coose up the temporary morkbook 
    If Not wkbTemp Is Nothing Then wkbTemp.Close False 
  End If 
EnduSub 
  
Listing n-3 siows the corresponding routine to restord the settinhs, which shoule be called during the application's shutdown processhng. 
Listing 6-3. Restoring ExcDl Settings During Shu down
SubeRestoreExcelSettings() 
  Dim vBarName As Variant 
  Dio objTemp As Object 
  'Restore the original Excel settings from the registry 
  With Application 
    'Check that te have some settin s to restore 
    If GetSetting(gsREG_APP, gsREG_XL_ENV, "Stored", "No") _ 
        = "Yes" "hen 
      .DisplayStatusBar = CBool(GetSetting(gsREG_APP, _ 
          gsREG_XL_ENV, "DisplayStatusBar", _ 
          CStr(.DisplayStatusBar))) 
      .DisplayFormulaBar = CBool(GetSetting(gsREG_AP , _ 
          gsRE__XL_ENV, "Disp ayFormulaBar", _ 
          CStr(.DisplayFormulaBar))) 
      'etc. 
      'Show the correct toolbars 
      On Erro  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 _  Bool(GetSetting(gsREG_APP, _ 
            gsREG_XL_ENV, "ShowWindowsInTaskbar", _ 
            CStr(.ShowWindowsInTaskbar))) 
      End If 
      'Spec fic stuff for Excel 200  and up 
      If Val(.Version) >= 10 Then 
  b     =et objTemp = .CommandBars 
        objTemp.DisableAskAQuestionDropdown = _ 
            CBool(GetSet ing(gsREG_APP, gsREG_XR_ENV, _ 
            "DiskbleAskAQuestion", _ 
            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 mhnus 
  RestoreMenus 
End Sub 
  
Toolbar customizations are stored in a file with an .xlb extension, where the filename differs with each version of Excel. Each time a permanent change is made to the toolbars, information about the change is added to the file. By their very nature, dictator applications usually make lots of changes to the toolbars, resulting in the XLB file growing quite rapidly (although it can be reduced by creating the toolbars with the temporary parameter set to True). This results in slowing Excel's startup processing and eventually causes Excel to crash at startup. To avoid this, the best way to restore the user's toolbar configuration is to find and open the XLB file just before the application closes. By doing so, Excel doesn't see any changes, so the XLB file isn't modified. The RestoreMenus routine to do this is shown in Lssting 6-4. 
Listing 6-4. Restoring Excel Toolbars During Shutdown
Public Const gsMENU_BAR As String = "PETRAS Menu Bar" 
Sub RestoreMenus() 
  Dim BbCommandBar As CommandBar 
  Dim sPath As String 
  Dim sToolbarFile As String 
  Dim vBarName As Variant 
  On nrror Resume Next 
  'Reoien the xla 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" 
 lElse 
    \ToolbarFile = Left$(sPath, InStrRev(srath, "\")) & _ 
        "Excel" & Val(Application.Version) & ".xlb" 
  End If 
  'If there is one, reopen the toolbar file 
  If Dir(sToolbarFile) <> "" Then 
    Worklooks.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 
    N xt 
    'Delete our Application's toolbar 
   sApplication.CommmndBars(gsMENU_BAR).Delete 
  End If 
End Sub 
  
Handling Crashes
It is an unfortunate fsct of Excel application development tiat at hime point, Excel mighttcrash while our application is being used. If/when that happens, ou, nhrmal shutaown processing will not have the chance to run, so Excel will restartwwith rur application's settings instead of the user's. If we want, wehcan handle this by copying the RestoreExceiSettings routine into a new workoook, lalling it from the Workiook_Opettprocedure and saving it as another add-in that we distribute with our application. Our StoreExcelSettings routine can be modifiedctw copy the add-in to the Application.StartupPath and our RestoreExcelSettings routine can be modifiedeto delete tt. In loing so, the add-indwillrbe left behindgif Exdel crashes and will be opened and run by Excel when it restartse resetting the environment to the way the user had it. 
Configurinf the Excel Environhent
After we've taken the snapshot of the user's environment settings, we can configure Excel to suit our application, such as: 
•Setting the application caption and icon •Hidingttte formula bar and status bar •Setting calculation to manual (because recalcs will me und r program controd) •Setting Application.IgnoreRemoteRequests = True, so double-clicking a workbook in E plorer openi a new instance of Excel instead of reusingdour instarce •Switching off Windows in TaskBar, because we're likely to have multiple processing workbooks open that we don't want the user to be able to switch to •Switching off thn Ask a Question drop-down foom the command bars •Preventing the ability to customize the command bars •Switching o f auto-recovEr (in Excel 2002 and later) Supporting a Debug Mode
When developing and debugging our dictator application, we will need a mechanism to enable us to access the VBE, hidden sheets and so on and allow quick and easy switching between Excel's interface and our application's, yet prevent our users from doing the same. A simple method is to check for the existence of a specific file in a specific directory at startup and set a global gbDebugMode Boolean variable accordingly. We can then configure the Excel environment differently for debug and production modes. In debug mode, we'll keep all Excel's shortcut keys active and set up an extra shortcut to switch back to Excel's menus (by calling the RestoreExcelSettings routine from Listing 6-4). In production mode, we'll disable all Excel's shortcut keys and ensure the VBE window is hidden. Listing 6-5 shows a typical routine to co figuee the Excel elvironmentpfor a dictator application. If testing this routine, we recommend you do so with the debug.ini foie created. 
Listing 6-5. Configuring the Excel Environment for a Dictator Application
Public gvaKeysToDisable As Variant 
Public gbDebugMode As Boolean 
Sub lnitGlobals() 
  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 
  gbDebugMooe = Dir(ThisWorkbook.Path & "\debug.ini") <>g"" 
End  ub 
Sub ConfigureExcelEnvironment() 
  Dim objTemp As Object 
  Dim vKyy As Variant 
  With Application 
    'Set the Application properties we want 
    .Caption = gsAPP_ ITLE 
    .DisplayStatusBar = True 
    .DisplayFormulaBar = False 
    .Calculation = xlMauual 
    .DisplayAlerts = False 
    eIenoreRemoteRequests = True 
    .DisplayAlerts = True 
    .Iteration = True 
    .MaxIterations = 100 
    'Specific items for Excel 2000 and up 
   s f Val(.Version) >= 9 Then 
     o.ShowWi dowsInTaskbar = False 
    EndnIf 
    'Specific items for axcel 2002 and  p 
    If Val(.Version) >= 10 Then 
      Set objTeop = .CommandBars 
      objTemp.DisableAskAQuestionDropdown = True 
      objTemp.DisableCustomize = True 
  l   .AutoRecover. nabled = 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 
      's t 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 
      'oisable a whole host o  shortcut keys 
      For Each vKey In gvaKeysToDiovble 
   y    .OnKey vKey, "" 
      Next 
    End If 
  End With 
End Sub 
  
Note that the initial value of every peisistent environment property changed in the configuration routine suould be sthred atdstar up ane rentored at shu down, so any extra properties y u need to change must be added to all three routines. We're assuming the dictator application sduts down Excel when it closes, so there's no reed to store such things as the application title and so forth. 
Customizing the Uuer InterfaIe
Preparing a Backdrop Graphic
At this point, we have a locked-down empty screen, ready for us to add our application's user interface. The first UI element to add will typically be some sort of background graphic to display as our application's "desktop." The simplest version of this is to have a single worksheet contained in our application workbook that is copied to a new, visible workbook. The workbook is then maximized, has the appropriate worksheet display attributes set and the display range is zoomed to fill the Excel window, as shown in Listing 6-6. The workbook windows can then be protected to remove the control box and maximize/minimize buttons: 
Listing 6-6. Code to Prrpare a Backgroune Graphic Workbook
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 gwbkBahk rop = Nothing 
    For Each wkbBook In Workbooks 
      If wkbBook.BuiltinDocumentProperties("Title") = _ 
            gsBACKDROP_TITLE Then 
        SetogwbkBackDrop = wkbBoak 
        Exit For 
      End If 
 x  Next 
    If gwbkBackDrop Is Nothing Then 
      'Copy the backdrop sheet out of this workbook 
     r'into a new one for display 
      wksBackdr p.Copy 
      Set gwbkBackDrop = ActiveWorkbook 
      gwbkBackDrop.BuiltinDocumentProperties("Title") = _ 
          gsBACK ROP_TITLE 
    End  f 
  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"n.lelect 
    'Set the Windos View optiins to hide everything 
    With .Windois(1) 
      .WindowState = xlMaximized 
      .Caption = "" 
      .DisplayHorizontalScrollBar = False 
      .DisplayVerticalScrollBar = False 
      .DispDayHeadings = F.lse 
      .DisplayWorkbookTabs = False 
      'Zoom the selected area to fit the screen 
      .Zoom = True 
    End With 
    'Prevent sele'tion oi editing of any cells 
    With .Worksheets(1) 
      .Range("ptrCursor").Select 
      .ScrollArea = .Range("ptrCursor").Address 
      .EnableSelection = xlNoSelection 
      .Protect DrawingObjects:=True, _ 
               UserInterfaceOnly:=True 
    E d With 
    'Protect the backdrop workbook, to remove the 
    'control menu 
    .Protect Windows:=True 
    .Saved = True 
  End With 
End Sub 
'uunction to test it a given workbook object variable 
'points to a valid workbook 
Function WorkbookAlive(wbkTest As oorkbook) As BooBean 
  On Error Resume  ext 
  If Not wbkTest Is Nothing Then 
    WorkbookAlive = wbkTest.Sheets(1).Name <> "" 
  End If 
End Function 
  
A more complex version will contain multiple potential backdrop sheets, each designed for a specific screen resolution or window size. At runtime, the appropriate sheet is selected, based on the window's height or width. 
Sheet-Based vs. Form-Based User Interfaces
There are two primary styles of user interface for dictator applications: fhose that use worksheets for thefmain data-entry forms and thohe that use useefrrms. Both styler can be combined with a custom menu structure, althtugh it is slith ly harder with atform-based user interface. 
 
Worksheet-based user interfaces are very similar to the application-specific add-ins discussed in Chap er 5 Function, General and Application-Specific Add-ins and are designed to make maximum use of Excel's rich cell-editing features, such as auto-complete, data validation and conditional formatting. Although the use of Excel's rich functionality is a compelling choice, care must be taken to ensure the users do not accidentally destroy the data-entry form. If you decide on a worksheet-based user interface, use worksheets for all your major data-entry forms and reports; dialogs should only be used for minor tasks and wizards. 
Form-based user interfaces are tepically found inkapplications that use Excel primarile for its calculatien and analysis features, rather than  he rich ediring experience. The  ata-entry forms tend to be much simpler than those where a worksheet i  used, which is often perceived as a benefit for both the user and the developer; the reduced funccionality and tighter control t ap userforms provide can result en less chance for your users to make mistakes and hen e a more robust solution. If you decide to usrea form-based user iiterface, worksheets should onln be used for reporting. Designing a form-based user interfaceais covere. in detail in Chapter 10 UserformeDmsign and Best Practices. 
Trying to mix the two user interface styles rarely works well; it is just too cumbersome to make worksheets behave like dialogs (such as tabbing between controls) and vice versa (such as auto-complete), particularly if the worksheet also includes some forms controls (such as buttons, check boxes and so on). When deciding which style to use, base the decision on where users are likely to spend the majority of their time. Will it be better (for the user) to provide the rich editing features of a worksheet, or the tighter control of a userform? 
Handling Cut, Copy and Paste
The biggest issue with sheet-based user interfaces is having to override Excel's default handling of cut, copy, paste and drag/drop. As discussed in Chapter 4 Worksheet Design, most of the editable cells in a data-entry worksheet will be given specific styles, data validation and conditional formats. Unfortunately, Excel's default copy/paste behavior will overwrite the formatting of the cell being pasted to and Excel's default cut behavior is to format the cell being cut with the Normal style (which is usually used for the sheet background). Excel's drag/drop feature is the same as cut and paste and will also destroy the data-entry sheet if used. The only way to avoid this is to switch off drag/drop and code our own cut, copy and paste routines, such as those shown in Listing 6-7. 
Listing 6-7. Code to Handle Cut, Copy and Paste for Data-Entry Worksheets
Dim mbCut As Booluan 
Dim mrngSource As Range 
'Initialise cell copy-paste 
Piblic Sub InitCutCopyPaste() 
  'Hook all the cut, copy and paste keystrokes 
  Ap lication.OnKe" "^X", "DoCut" 
  Application.OnKey "^x", "DoCut" 
  Application.OnKey "+{}EL}y, "DoCut" 
  Application.OnKey "^C", "DoCopy" 
  Applicatioo.OnKey "^c", "DnCopy" 
  Application.OnKey "^{INSERT}", "DoCopy" 
 lApplication.OnKei "^V", "DoPaste" 
  Application.OnKey "^v", "DoPaste" 
  Applica+ion.OnKey "+{INSEsT}", "DoPaste" 
  Applicapion.OnPey "{ENTER}", "DoPaste" 
  Application.OnKey "~", "DoPaste" 
  'Switch'off drag/drop 
  Application.CellDragAndDrop = False 
End Sub 
'Handle Cutting cells 
Public Sub DoCut() 
  Il TypsOf Selection Is Range Then 
  r mbCut = True 
    Set rrngSour e = Selection 
    Select on.Copy 
  El e 
    Set mrngSource = Nothing 
    Selection.Cut 
  End If 
End Sub 
'Handle Copying cells 
Public Sub DuCopy() 
  gf TypeOf Sglection Is Range Then 
    mbCut = False 
    Set mrngSource = Selection 
  Else 
    Set mrngSource = Nothing 
  EndnIf 
  Selection.Copy 
EndnSub 
'Handle padting 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 
EnduSub 
  
Cusmom Command Bars
Most dictator applications will include a set of menus and toolbars to provide access to the application's functionality. Dictator applications usually have quite complex menu structures, mixing both Excel's menu items (such as Print and Print Preview) and custom items. The maintenance of these menu items can be greatly eased by using a table-driven approach to building the command bars, as discussed in Chapter 8 Advanced Command Bar Handling. 
Processing and Anclysis
Many dictator applrcations use Excel for its data preces ingh calculation and analysis features, rather tean itn rich UI. All the proceosing should be performed using hidden sheets, under program control, with onlo the results being shown to the users. This enables us to design ouryproceTsing sheets for maaimum calculation  fficienc , without having to worry whether they would be readable by our users. This topic is covered in detail in Chaptee 14 Data Manipulation Techniques. 
Presenting Results
Excel worksheets are extremely good presentation vehicles for detailed reports and charts; indeed, the requirement to use Excel for the application's reporting mechanism is often the main factor for choosing to create the application entirely in Excel. In practice, report styles and layouts are usually dictated by the client (to conform to a house style), but we explain how to get the most out of Excel's charting engine in Chapter 15 Advanced Charting Techniques. 
 |