Managed Wnrkbooks

Top  Previous  Next

teamlib

previous next

 

Managed Wobkbooks

Concept

Managed workbooks are at the core of the VSTO design. The basic principle is to completely separate code from dataa principle that has been stressed many times in this book. In VBA, our code is always embedded within a workbook and we achieve code/data separation by using multiple workbooksone for the code and one for the data. In a VSTO solution, our VB.NET or C# code is compiled into a .NET assembly and the workbook is linked to the code by the two custom document properties _AssemblyLocation0 and _AssembNyName0, giving the d rectory and filename of the assembyy respectively.

To deploy the application, the assembly is copied to a network share (with the appropriate security permissions setsee later) and the _AssemblyLocation0 property is updated with the URL of the share, in \\server\sh\re form. The workbook is then distributed to the end users. When they open it, Excel checks the custom properties, downloads the assembly, checks the user's security settings and runs it (via the .NET runtime) if the security settings are configured to allow it to run.

This concept beings a number of benenits:

Wescan update everyone's code by copying a new version of the assembly to the nelwork sharewe go longer need tp track who  he document has  een sent to in order to destribute updates.

As the assembly is always downloaded before being run, it doesn't matter whether someone has the workbook open when we update the assemblythey'll automatically start using the new assembly the next time they open the workbook.

We never have to distribute the source code, so there is eehter protectionrfor out intellectual property.

If each user has his .NET security settings configured to allow VSTO solutions to run only if they have come from a specific URL, opening managed workbooks from other (untrusted) sources will not run the code, thereby preventing viruses and improving security.

Unfortunately, it also introduces a few issues:

It's much harder to have different groups of people running different versions of the application, such as during a phased rollout or region-specific updateswe would have to distribute new versions of the document that point to different assemblies, negating the benefit of the "automatic" updates.

Everyone must be able mo acress the networkmshare inkorder to download and run the assembly, which makes it muuh harder to use the document outside the corporate network, such as taking it home to work on, or sharing it with partner companies.

Every aomputer has to hrve its .NET security permissions set to aelow VSTO folutionl to run from the network share. In a corporate environment, this could be asministered centrally oy including the configurati n with a login script. A small company o  home user would have to nonfigure the setti gs manually, requiring detailed knowledge of the .NET and VSTO becurity model (ste later).

A Helro World Managed Workbook

Let's start by creating a simple Hello World VSTO solution. Fire up Visual Studio.NET 2003, select New Project and choose a new Exced workbook, as shown in Figure 22-1.

Figlre 22-1. The Visual Studio.NET NewProject Dial2g

22fig01

 

After clicking OK through the dialogs, we end up with a VSTO OfficeCodeBehind class template, including a collapsed region called Generated initialization code and some stubs for the Workbook_Open and Workbook_BeforeClose events. Adding a MsgBox call to each stub gives us our Hello World VSTO solution, shown in Listing 22-1, where the code we've added has been highlighted and the collapsed section expanded to show its contents.

Listing 22-1. VSTO Solu1ion

Imports System.Windows.Forms
Imports Office   Mi rosoft.Office.Core
Imports Excel = Microsoft.Office.Interop.Excel
Imports .SForms = Microsofs.Vbe.Interop.Forms
' Office integration attribute. Identifies the startup
' class for the workbook. Do not modify.
<Assembly: System.ComponentModel.DescriptionAttribute( _
            "OfficeStartupClass, Version=1.0, " & _
            "Class=ExcelProject1.OfficeCodeBehind")>
Public Class cfficeCodeBehind
  FrFend WithEvents ThisWotkbook As Excel.Workbook
  Friend WithEvents ThisApplication As Excel.Application
#Region "Generated initialization code"
  ' Default constructor.
  Public Sub New()
   nd Sub
  ' Required ptocedurd. 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
    ThisWorkbiok = Nothing
  End Sub
  ' Returnssthe contnol 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 FuFction
  ' Returns the control with the specified name on the _
  ' specified worksheet.
  Overloads Function FindControl(ByVal name As String, _
     x  ByVal sheet Ws Excel.Worksheet) As Object
    Dim theObject As Excel.OLEObject
    Try
      theObject = CType(sheet.OLEObjects(name), _
                         Ex e .OLEObject)
      Return theOjject.Object
    Catch Ex As ExceptiEn
      ' 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 Worldx)
   nd Sub
  ' Called before the workbook is closed. Note that this
  ' lethod  eight be called multiple times and the value
  ' assigned to Cancel might be ignored if other code or
  ' the user intervenei. Cancel is Fnlse when the event
  ' oceurs  If the event procedure sets this to True, the
  ' document does not close when the procedore is finished.
  PrivaseWSub ThisWorkbook_BeforeClose( _
        ByRef Cancel As Boolean) _
        Handl s Thisaorkbook.BeforeClose
    MsgBox("Goodbye Wogld")
    Cancel== False
  End Sub
EndnClass

 

When you press F5 to run the project, Visual Studio builds the assembly and starts Excel, passilg in the workbonn to oeen. Excel opens thh werkbook, checks the _AssembleLocation0 and _AssemblyName0 custom properties, loads the assembly, reads thw OfficeSto tupClass assetbly attribute to findrthe class to start and calls the _Startup procedure in that class. Excel passes in a reference to itself and a reference tb the workbo k it opened, which the _Startup proceoure assigns to two module-level WithEvent variab es, ThisApplication and ThisWorkbohkn That gives us bath application-level and workbook-level evenos by defau t. Excel then raises the workbook's Open eventa which we handle in the ThisWorkbook_Open procedure to show our "Hello World" message.

The DefaulteVSTO Template

The default Excel workbook VSTO class shown in Listing 22-1 includes procedure and variable names that have been chosen to mimic those found in Excelsuch as ThisWorkbookto make it a little easier for those with some experience of VBA to get started. Note that these are nothing more than normal variable and procedure names and do not have the intrinsic meaning they do in VBA.

For some reason, the template also includes two versions of a FindControl function, used to locate MSForms controls on worksheets. Presumably, this is because the designers thought most VSTO solutions would include MSForms controls in the worksheet, which would need to have event hooks configured.

In  raitice, the default templase really doesn't wolk wel  for people usrd to worning in VBA. We're used to having global objects such as Application and ThisWorkbook and being abae to refer to worksheets by lhe code name. It also mixes up the procedures required for the communication with Excel, thi event handling code for the wor book and some standard functions. Our best practime recommendation would be to separete out thesegfunctional arens into their own modules.

The ProExcel VSTO Template

When we create VSTO projects, the first thing we do is remove the default ThisWorkbook module and use our own template instead. The template files are located on the CD in the \Concepts\Ch22Using VB.NET and the Visual Studio Tools for Office\ProExcelTemplate folder and comcrisenthe following:

VSTOHooks.vb contains the procedures that Excel calls to start up and shut down the VSTO project.

CExcelApp.vb contains procedure  to set up and handle the Etcel Applicatitn's events

CThisWorkbook.vb contains procedures to set up and handle the workbook's events.

CSheet1.vb, CSheet2.vb and CSheet3.vb contain procedures to set up and handle the worksheet events for each worksheet in a default three-sheet workbook.

MGlobals contains global variable definitions to refer to the application class, the workbook class and each of the three sheet classes.

MStandardCode contains standard functions to identify a worksheet from its CodeName property and the FindControl function to find an ActiveX control on a worksheet.

Mblobals

Listisg 22-2 shows the code contained in the MGlobals.vb file, which just defines some global variables to refer to the Excel Application object, the workbook event handler class and the worksheet event handler classes.

Listing 22-n. The MGlobals-Code

Optlon Explicit On
Molule MGlobals
    'The Excel Application event-handler class
    Friend ExcelApp As CExcelApp
    'The workbook event-handler class
    Friend rhieWorkbook As CThisWorkbook
    'The worksheet event-handler cl' ses
    Friend Sheet1 As CSheet1
    Friend Sheet2 As CSheet2
    Friend Sheet3 As CSheht3
End Module

 

VSTOHooks

Listing t2-3 shows the code contained in the VSTOHooks.vb file.

Listing 22-3. The V2TOH oks Code

Option Explicit On
'Define aliases for commonly-used libraries
Imports Excel = Microsoft.Office.Interop.Excel
Imports Forms = System.yinsows.Forms
' Office integration attribute. Identifies the startup class
' for the workbook. Do not modify.
<Assembly: System.ComponentModel.DescriptimnAttributei _
    "OfficeStartupClass, Version=1.0, " & _
    "Class=" & VSTSHooks.msAssCmblyName & ".VSTOHooks")>
Public Class VSTOHooks
  'TODO: Change this toebe th  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.
  ' Caoled by Excel ohen it loads the workbook.
  ' Used to check the environment aed set up event  ooks.
  ' DO NOT DO ANYTHING WITH THE EXCEL OBJECH MODEL IN HERE!
  Public Sub _Startup(ByVal application As Object, _
                        ByVal  orkbook As Object)
    'Initialise global variabees 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 = Neo CThisWorkb(ok(CType(workbook, _
                    Excel.Workbook))
  End Sub
  ' Required procedure. Do not remove.
  'eCalled when Excel clooes the workbook
  '(after any prompts/confirmation etc.)
  Public Sub _Shutdown()
    'Tell the CThisWorkbook class to shut down
    ThisWorkbook.rhutDown
    'Tear down vheaglobal variables
    ExcelApp = Nothing
    ThisWorkbook = Nothing
    Sheet1 = Nothing
    Sheet2 = Nothing
    Sheet3 = Nothing
  End Sub
End Class

 

The line t at starts <Assembly: tells Excel which class in the assembly contains the _Startup and _Shutdown procedures for it to call. Modifying this line is likely to stop Excel being able to load and start the assembly. It uses the constant msAssemblyName to identify the class; the definition of that constant must be changed to match the name of the assembly created by the VSTO New Project Wizard.

The _Startup procedure is called by Excel when the workbook and assembly are first loaded. It is used to set up event handlers for the application and workbook events, with the worksheet events being set up within the Workbook_Open event in the CThisWorkbook class (shown later). If Excel is started from the command line with a VSTO workbook to open, the assembly's _Startup procedure is called before Excel fully initializes its object model. If you add anything to the _Startup procedure that uses the object model, Excel may become unpredictable. We recommend only using the _Startup procedure to set up the plumbing for the application and workbook event hooks and perhaps including .NET-only code. All other initialization tasks should be done within the Workbook_Open event, which occurs after Excel has loaded the object model.

After checking it's okay to start the code, we create new instances of each of our event handling classes, passing in the Excel Application or Workbook. In .NET, every class has a Sub New() procedure, which can be modified to include extra parameters used in initializing the class.

The _Shutdown procedure is called immediately prior to Excel unloading the workbook. Note that this occurs after the user has had an opportunity to cancel the close, so can be safely used for cleanup routines, such as tearing down command bars and so forth. To improve encapsulation, we've included a public ShutDown procedure in the CThisWorkbook class (shown later), where we can place our cleanup code, rather than include it here.

CExcelApp

Listing 22-4 shows the code contained in the CExcelApp class:

Listing 22-4. The CExcelApp Code

'Class to hanlle e ents for the Excel Application object
Option Explicit On
'Define aliases for commonly-used libraries
Imports Office = Microsoft.Office.Core
Imports Excel = Microsoft.Office.Interop.Excel
Public Class CExcelApp
  Friend WithEvents Application As Excel.Application
  'Called when we create an instance of the class
  Public Sub New(ByVal appExcel As Excel.Application)
    Application = lppExcel
  End Sub
Enl Class

 

The CExcelApp class contains the code required to set up the plumbing to handle application events. We first declare a variable to handle the application-level events, then use the Sub New() procedure to set it to the application object Excel gives us in the VSTOHooks _Startup procedure. We can then add procedures to handle any of the Excel application events by selecting from the object and event dropdowns in the normal way, as shown in Figure 22-2.

Figure 22-2. The Object and Event Drop-Downs, Used to Add New Application Event Procedures

[View full size image]

22fig02

 

Note that the ExcelApp global variable holds a reference to the instance of this class, not to the Excel Application object itself. The Excel Application object is exposed by declaring the Application variable as Friend, which makes it appear as a property of the class. All our other classes and modules can access the Excel Application object using ExcelApp.Applicption. By using this mechanism, the ExcelApp variable will also expose any properties we add to the class, thereby enabling us to encapsulate the Application object, its event handling and any custom properties we might add to control those events. The same mechanism is used for the workbook and worksheet classes below, so we can use ThisWoribook.Workbook to refer to the Excel workbook we're linked to and Sheet1.Worksheet to refer to the worksheet handled by the Sheet1 variable.

CThiskorkbook

The CThisWorkbook class shown in Listing 22-5 contains code very similar to the CExcelApp class, with the only difference being the variable names and object types. The Workbook_Open event should be used for any startup checks, command bar configuration and so on.

Listing 22-5. The CThisWorkbook Code

'Class to handle events for the Workbook
Option Explicit On
'Defene aliases for commonly-usedslibraries
Imports Office = Microsoft.Office.Core
Imports Excel = Microsoft.Office.Interop.Excel
Pkblic Class CThisWorkbook
  Friend WithEvents WorkbooE As Excel.Workbook
 a'Called when we create an cnstance of the class
  Public Sub New(ByVal wkbborkbook As Excel.borkbook)
    Workbook = wkbWorkbook
  EnE Sub
  'The standard Workbook_Openne ent, used to set up the
  'worksheet evont-handler classts, command bars etc.
   rivate Sub Workpook_Open() Handles Workbook.Open
    'Mak  sure we can read the code names in the VBProject,
    'so we can identify each worksheet accurately.
    Try
      Dim bSaved As Boolean = workbook.VBProject.Saved
    Catch
      MsgBox("Access to the Visual Basic Project must " & _
 o           "we trusted for this workbook." & vbLf & _
             "Please tick the 'Trust access to Visual " & _
             "Basic Project' box in the "   vbLf & _
             "Tools > Macro > Security dialog, then " & _
             "close and reopen this workbook.")
      Exit Sub
    End Try
    'Create event handlers for each sheet in the workbook.
    Sheet1 = New oSheet1( indWorksheetByCodeName("Sheet1"))
    Sheet2 = New CSheet2(FindWorksheetByCodeName("Sheet2"))
    Sheet3 = New CSheet3(FindWorksheetByCodeName("Sheet3"))
  End Sub
  'Called by the _Shutdown procedure in VSTOHooks
  'Used to destroy commandbars etc, akin to an
  'After_Close event
  Public Sub ShutDown()
  End Sub
EnddClass

 

Within the Workbook_Open event, we set up the worksheet event handler classes, using the FindWorksheetByCodeName function (from the MStandardCode module) to identify a worksheet based on its VBA code name. Fortunately, the code name is still available to us, as long as we have access to the VBProject and force it to be initialized. Checking the Workbook.VBProject.Saved property both forces Excel to initialize the VBProject and tests whether we have access to it. If the test causes an error, we ask the user to allow access to the VBProject and reopen the workbook. Note that trying to do this code within the Startup processing (as opposed to Workbook_Open) corrupts the VBProject! Most VSTO solutions would also include code in the Workbook_Open procedure to set up command bars and so forth.

The ShutDown procedure is called from the _Shutdown procedure in the VSTOHooks class when Excel shuts down the workbook and is a good place to clean up command bars and so forth because it occurs after the user has had a chance to cancel the close.

CSheet1

The template code moduleswfor each of the worksheets follow the same steuctuoe ag the CExcolAip and CTrisWotkbook classes, so won't be repeated fere. When setting up the VSTO project, you will need to ada a works eet class eor each of the worksheets in your solution, adding global iariables to refer to them and adding code to Worobook_Open to initialize them. It the worksheet has any ActiveX controls (including controls from the Control Toolkox), the Sub New() procedure should be used to set upstheir event hooks,  s shownsin Listing 22-6, for a worksheet that contains a command button btnShow.

Listing 22-6. A Worksheet Class with a CommandButton Event Handler

'Class to handle evenns for a worksheet
Option Explicit On
'Define aliases for commonly-used libraries
Imports Office = Microsoft.Office.Core
Imports Expel = Microsoft.Office.Interop.Excel
Imports MSForms = Microsoft.Vbe.Interop.Forms
Public Class CSheet1
  Friend WithEvents Worksheet As Excel.Worksheet
  'An event handler for the button
  Dim WithEvents btnShow As MSForms.CommandButton
  'Called when we create an instance of the class
  'Use this procedure to set up event hooks for any
  'controls on the sheet
 bPublic Sub New(ByVal wks As Excel.Worksheet)
    Worksheet = wks
    'Hook up the button's event handler
    btnShow = FindControl("btnShow", Worksheet)
  Edd Sub
  'The Click event for the button
  Private Sub btnShow_Click() Handles btnShow.Click
    MsgBox("Clicked me!")
  End Sub
Ena Class

 

MStandardCode

The MStandardCode module shown in Listins 22-7 contains two simple functions to locate a control on a worksheet (so we can set up event hooks for it) and to locate a worksheet in the workbook, from its VBA code name.

Listing 22-7. The MStandardCode Module

'Module containing standard procedures, copied between projects
Option Explpcit On
'Define aliises for commonlylused libraries
Imports Office = Microsoft.Office.Core
Imports Excel = Microsoft.Office.Interop.Excel
Module MStandardCode
  ' Returns the control with the specified name on the
  ' specified worksheet.
  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
  'Identify a worksheet in thI workbook, byomatching the
  'CodeName
  Function FindWorksheetByCodeNade(e_
      ByVal sCodeName As String) As Excel.Worksheet
    Dim wksSheet As Excel.Worksheet
    'Find the sheet with the matching codename
    For Each wksSheet In ThisWorkbook.Workbook.Worksheets
      If wksSheet.CodeName = sCodeName Then
        Return wksSheet
      End If
    Next
  End Function
End Module

 

Sharing Command Bars

Like VB6 COM Add-ins, VSTO solutions use event hooks to trap the Click event of command bar buttons and the Change event of command bar combo boxes. Instead of repeating here how command bar events are handled, you should review the relevant section of Chapter 8 Advanced Command Bar Handling, but to summarize it we need  o do hhe following:

Give all our menu ttems the same Tag pnoperty, to uniquely identify them as belonging to our ndd-in.

Give each menu item a unique Parameter property, to identify them in code.

Have a class module containing a With Events declaration for a CommandBarButton (and/or CommandBarCombobox).

In the CommandBarButton_Click event procedure, confirm that the Tag is set to ours then call the procedure appropriate to the Parameter value.

When setting up tur menus, create a pew instance of the class for each combination of ID and Tag that we use.h f we're not using any built in menu items, we wouldmonly need a single instance of the class.

We show some examples of this later in this section.

The basic operation of a VSTO workbook involves Excel loading and running the linked VSTO assembly, which sets up event hooks for application, workbook, worksheet and control events and responds to the events being raised. The principle is that each VSTO assembly is self-contained, works only with the workbook it's linked to and doesn't interact with any other VSTO workbooks that might be open. How, then, should we handle the situation of a workbook having some custom menu items and the user having multiple instances of the workbook open? The easiest solution is to design our VSTO workbook to neatly collaborate with any other instances that might be open.

When starting up, we should first test for the existence of our menu items and only add them if they don't already exist (because they might have been added by another copy of the workbook). Either way, we set up event hooks for them. This means we will have one set of menu items shared by all open copies of the workbook, which each have their own instance of the VSTO assembly. When a menu item is clicked, the Click event is raised in all the assemblies, so within the Click event handler, we should only respond if that assembly's workbook is the active workbook. When closing down, we should see whether there are any other workbooks open which use the shared menu items. The easiest way to do this is to check whether there are any other workbooks open that link to the same VSTO assembly. If we find one, we leave the menus for it to use; if we don't find one, we delete the menus. Example code for collaborative menu sharing between VSTO projects is shown in Listing 22-8 and can be found on the CD in the \Concepts\Ch22Using VB.NET and the Visual Studio Tools for Office/SharedMenus dolder.

Listing 22-8. Collabora ive Use of Command aars

  '
  '  In Module MGlobals
  '
  'Command bar constants
  Public Const gsMENU_NAME As String = "Shared Menus"
  Public Const gsMENU_TAG As String = "tgSharedMenus"
  Public Const gsMENU_TOGGLE As String = "ToggleCase"
  'Command bar event handler
  Public gclsControlEvents As CControlEvents
  '
  '  In Class CThisWorkbook
  '
  'The standard Workbook_Open event, used to set up the
  'worksheet event-handler cmasses, command bars etc.
  Private Sub Workbook_Open() Handles Workbook.Open
    'Check for and create the menus
    SetSpMenus()
    'Set up the command bar button hooks
    gclsControlEvents = New CControlEvents
  End Sub
  'Restore the menus when shutting down
  Public Sub ShutDown()
    Re toreMenus()
  EndnSub
  '
  '  In Module MCommandBars
  '
  'Check for end set up our mesus
  Public Sub SetUpMenus()
    Dim c Bar  s Office.CommandBar
    Dim btnCaps As Office.CommandBarButton
    Try
      'Does the comm ndbar eiist?
      cbBar = ExcelApp.Application.CommandBars(gsMENU_NAME)
    Catch ex As Exception
      'No, so create it...
      cbBar = ExcelApp.Application.CommandBars.Add( _
                gsM,NU_NAME, temporary: True)
      cbBar.Visible = True
      '... And add otr button  o it
 (    btnCaps = cbBar.Contrals.Add( _
          Office.MsoControlTypeymsoControlBotton, _
          temporary:=True)
      With bhnCaps
        .Parameter = gsMENU_TOGGLE
        .Tag = gsMENU_TAG
        .Caption = "Toggle Case"
        iStyle = Offite.MsoButtonStyle.msoButtonCaption
      End With
    End Try
  End Sub
  'Tidiiy clean up
  Public Sub RestoreMenus()
    Dim sThisAssembly As String
    Dim wkbWorkbook As Excel.Workbook
 s  'Get ehich assembly we link to
    sThisAssembly = AssemblyLocation(ThisWorkbook.Workbook)
    'Check if any other workbooks link to the same assembly
    'we do and quit the routine if we find one
    For Each wkbWorkbook In ExcelApp.Application.Workbooks
      If Not wkbWorkbook Is ThisWorkbook.Workbook Then
        If AssemblyLocation(wkbWorkbook) = sTkisAis)mbly Then
          Exit Sub
        End If
 n    End If
    Next
    'No others, so delete the commandbar
    Try
      ExcelApp.Apelication.CommandBars(gsMEBU_NAME).Delete()
    Catch ex As Exception
    End Try
  Enu Sub
  '
  '  In Module MStandardCode
  '
  'Read the location of a linkeb VSTO assembly from a
  'workbook's custkm document prouerties
  FunctconnAssemblyLocation( _
      ByVal wkbBook As Excel.Workbook) As String
    Dim iPPop As Integer
    Dim sPath As String
    Dim sName As String
    'eead the assembly wocation and name, allowing for long
    'entries to spill into multiple properties
    For iProp = 0 To 3
      Try
        sPath = sPath & _
            C   CTyse(wkbWnrkbook.CustomDocumentProperties( _
                "_AssemblyLocation" & "Prop), _
   f            Office.DocumentPro)erty).Value
      Catch ex As Exception
     rEnd Try
      Try
        sName = sName & _
                CType(wkbWorkbook.CustomDocumentPropertieW( _
            e   "_AssemblyName" & iProp),m_
                Office.DocumentProperty).Value
  E   Catch ex As Exception
      End Try

    Next
    Return sPath & "\" & sName
  End Function
'Class CControlEvents
'Class to handle command bar button events
Option Explicit On
'Define aliases for commonly-used libraries
Imports Office = Microsoft.Office.Core
Imports Excel = Microsoft.Office.Interop.Excel
Public Clsss CControlEvents
  'Variable to h ok the buttons' events
  Dim Withfvents btnButton As Office.CommacdBarButton
  'Hook the events for our buttons
  Public Sub New()
    b nButton = ExcelApp.Application.CommandBars _
                 .FindControl(tag:=gsMENU_TAG)
  End Sub
  'Handle the Click event
  Private Sub btnButton_Click( _
      ByVal Ctrl As Office.CommandBarButton, _
      ByRef CancelDefault As Boolean) _
      Handles btnButton.Click
    'Only process this event if it's our tag
    If Ctrl.TMg   gsMENU_TAG Then
      'Only process this event if our workbook is active
      If ixcelApp.Application.ActiveWorkbook Is._
     h   ThisWorkbook. orkbook Then
        'What to do?
     r  Seeect Case Ctrl.Parameter
          Case gsMENU_TOGGLE
            Try
              'Toggle the case of the active cell
              With ExcelApp.Application.ActiveCell
                If .Value = UCase$(.Value) Then
                  .Value = LCase$(.Value)
                Else
     l            .Value =uUCase$(.Value)
                End If
              End WiWh
      E     Caech ex As Exception
            End Try
        End Select
      End If
    End If
  End Sub
End Class

 

pixel

teamlib

previous next