Microsoft Access
  Home arrow Microsoft Access arrow Page 2 - VBA Details
ASP Free Forums 
.NET  
ASP  
ASP Code  
ASP.NET  
ASP.NET Code  
BrainDump  
C#  
Code Examples  
Database  
Database Code  
IIS  
Microsoft Access  
MS SQL Server  
Visual Basic.NET  
Windows Scripting  
Windows Security  
XML  
ASP Web Hosting  
ASP.NET Web Hosting 
Dedicated Servers 
Actuate Whitepapers 
VeriSign Whitepapers 
Windows Web Hosting
 
IBM® developerWorks 
Sun Developer Network 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid 
Request Media Kit
Contact Us 
Site Map 
Privacy Policy 
Support 
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
MICROSOFT ACCESS

VBA Details
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: 5 stars5 stars5 stars5 stars5 stars / 11
    2006-12-28

    Table of Contents:
  • VBA Details
  • 7.2 Create a Global Procedure Stack
  • 7.3 Create an Execution Time Pro?ler
  • 7.4 Multitask Your VBA Code
  • 7.5 Programmatically Add Items to a List or Combo Box

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      Del.ici.ous Digg
      Blink Simpy
      Google Spurl
      Y! MyWeb Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article
     
     
    ADVERTISEMENT

    Stay one step ahead of the competition. Evaluate and give feedback on some of the hottest web development tools on the market today. Make your opinion heard! Click Here

    VBA Details - 7.2 Create a Global Procedure Stack


    (Page 2 of 5 )

    Problem

    When you're writing an application, you often need to know the name of the current procedure from within your code. For example, if an error occurs, you'd like to be able to have a generic function handle the error and display the name of the procedure in which the error occurred (and all the procedures that have been called on the way to get there). VBA doesn't include a way to retrieve this information. How can you accomplish this?

    Solution

    By maintaining a list of active procedures, adding the current name to the list on the way into the procedure and removing it on the way out, you can always keep track of the current procedure and the procedure calls that got you there. There are many other uses for this functionality (see the next solution, for example), but one simple use is to retrieve the name of the current procedure in a global error-handling procedure.

    The kind of data structure you'll need for maintaining your list is called a stack. As you enter a new procedure, you "push" its name onto the top of the stack. When you leave the procedure, you "pop" the name off the stack. Figure 7-2 shows a graphical representation of a procedure stack in action. The arrows indicate the direction in which the stack grows and shrinks as you add and remove items.


    Figure 7-2.  The call stack and the sample routines to fill it

    To see the procedure stack in action, load 07-02.MDB. Open the module basTestStack in design mode. Open the Immediate window (choose View Immediate Window). In the Immediate window, type:

      ? A( )

    to execute the function named A. Figure 7-2 shows A and the procedures it calls. At each step, the current procedure pushes its name onto the procedure stack and then calls some other procedure. Once the calling procedure regains control, it pops its name off of the stack. In addition, each procedure prints the name of the current procedure (using the acbCurrentProc function, discussed later in this solution) to the Immediate window. Once all execution has finished, you should see in the Immediate window output like that shown in Figure 7-3.


    Figure 7-3.  The output from running the sample procedure

    Follow these steps to incorporate this functionality into your own applications:

    1. Import the module basStack into your application. This includes the procedures that initialize and maintain the procedure stack.
    2. Insert a call to the acbInitStack subroutine into code that's executed when your application starts up. Consider adding this procedure call to the code in your main form's Load event procedure. You'll want to call acbInitStack any time you restart your program during development, so you probably don't want to call it from the Autoexec macro, which is executed only when you first load the database. To call acbInitStack, either place its name alone on a line of code, like this:

      acbInitStack

      or use the Call construct, as follows:

      Call acbInitStack
    1. For each procedure in your application, place a call to acbPushStack as the first statement. This procedure will place the value it's passed on the top of the stack. As the single argument for each call, pass the name of the current procedure.

      Our example places a pair of parentheses after function names and nothing after subroutine names, as a matter of style. As the last line in each procedure add a call to acbPopStack, which will remove the current name from the top of the stack.

    2. You can retrieve the name of the currently executing procedure at any time by calling the acbCurrentProc function. This function looks at the top of the stack and returns the string it finds there. You can use this as part of an error handler or, as in the next solution, to help track procedure performance.

    Discussion

    The module you imported from 07-02.MDB, basStack, includes code for maintaining the procedure stack and a module-local variable that is the stack itself. There are just six entry points (nonprivate procedures) in the module. Table 7-1 lists those procedures. Since all the code for the stack is encapsulated in that one module, you never really have to know how it all works. However, it's quite simple.

    Table 7-1. The six entry points into basStack

    Procedure name

    Purpose

    Parameters

    acbInitStack

    Initialize the stack.

    acbPushStack

    Add an item to the stack.

    A string to push

    acbPopStack

    Remove an item from the stack.

    acbCurrentProc

    Retrieve the name of the current procedure.

     

     

    acbGetStack

    Retrieve a specific item from the stack.

    The item number to retrieve

    acbGetStackItems

    Retrieve the number of items on the stack.

     

     

    basStack includes two module-level variables: mastrStack , the array of strings that is the stack itself; and mintStackTop , an integer that holds the array slot into which the next stack item will be placed. When you begin your work with the stack, mintStackTop  must be 0, so the first item will go in the slot numbered 0. The acbInitStack procedure does nothing other than initialize mintStackTop :

      Public Sub acbInitStack( )
         
    ' Resets the stack top to 0.
         
    mintStackTop = 0
     
    End Sub

    You can add an item to the stack at any time by calling acbPushStack. Pass to this subroutine the item you want pushed. To push the item, the code places the item in the array at the location stored in mintStackTop  and then increments the value of mintStackTop . Its code is:

      Public Sub acbPushStack(strToPush As String)

           ' Push a string onto the call stack.
           ' If the stack is full, display an error.
           ' Otherwise, add the new item to the call stack.

           ' Handle the error case first.
           If mintStackTop > acbcMaxStack Then
               MsgBox acbcMsgStackOverflow
           
    Else
              ' Store away the string.
              mastrStack(mintStackTop) = strToPush

              ' Set mintStackTop to point to the NEXT
              ' item to be filled.
              mintStackTop = mintStackTop + 1
          
    End If
      End Sub

    The only problem that might occur is that the stack might be full. The constant acbcMaxStack is originally set to 20, which should be enough levels. (Remember that mintStackTop  goes up one only when a procedure calls another procedure. If you have 20 levels of procedure calling, you might consider rethinking your application, instead of worrying about procedure stacks!) If the stack is full, acbPushStack will pop up an alert and will not add the item to the stack.

    When leaving a procedure, you'll want to remove an item from the stack. To do so, call the acbPopStack procedure:

      Public Sub acbPopStack( )

          ' Pop a string from the call stack.
          ' If the stack is empty, display an error.
          ' Otherwise, set the current item to be the
          ' next one to be filled in. If you're logging,
          ' send the information out to the log file.

          ' Handle the error case first.
          If mintStackTop = 0 Then
              MsgBox acbcMsgStackUnderflow
          Else
             ' Because you're removing an item, not adding one,
             ' set the stack top back to the previous row. Next time
             ' you add an item, it'll go right here.
             mintStackTop = mintStackTop - 1

         End If
      End Sub

    Just as in acbPushStack, this code first checks to make sure that the stack integrity hasn't been violated; you can't remove an item from the stack if there's nothing to remove! If you try, acbPopStack will pop up an alert and exit. If the stack is intact, the procedure will decrement the value of mintStackTop . Decrementing that value sets up the next call to acbPushStack so that it will place the new value where the old one used to be.

    To retrieve the value at the top of the stack without pushing or popping anything, call the acbCurrentProc function:

      Public Function acbCurrentProc( ) As String
          ' Since mintStackTop always points to the next item to
          ' be filled in, retrieve the item from mintStackTop - 1.
          If mintStackTop > 0 Then

             acbCurrentProc = mastrStack(mintStackTop - 1)
          Else
              acbCurrentProc = ""
          End If
      End Function

    This function retrieves the value most recently placed on the stack (at the location one less than mintStackTop , because mintStackTop always points to the next location to be filled). You can't look at mastrStack yourself, because it's local to basStack--and that's the way it ought to be. Since the details of how the stack works are kept private, you can replace basStack, using a different architecture for the stack data structure, and the rest of your code won't have to change at all.

    To retrieve more information about what's in the stack, you can call acbGetStackItems, to find out how many items there are in the stack, and acbGetStack, which retrieves a specific item from the stack. For example, write code like this to dump out the entire stack (see subroutine D, which does just this, in the basTestStack module):

      Debug.Print "Stack items currently:"
      For intI = 0 To acbGetStackItems( ) - 1
         Debug.Print , acbGetStack(intI)
      Next intI

    The acbGetStackItems function is simple: it returns the value of mintStackTop , because that value always contains the number of items in the stack:

      Public Function acbGetStackItems( ) As Integer
          ' Retrieve the number of items in the stack.
          acbGetStackItems = mintStackTop
     
    End Function

    The acbGetStack function is a little more complex. It accepts an item number (requesting item 0 returns the item at the top of the stack) and calculates the
    posi tion of the item to retrieve. Its source code is:

      Public Function acbGetStack(mintItem As Integer) As Strin g
          ' Retrieve the item that's mintItems from the top of the
          ' stack. That is,
          ' ? acbGetStack(0)
          ' would return the same value as acbCurrentProc.
          ' ? acbGetStack(3) would return the third value from the top.
          If mintStackTop >= mintItem Then
              acbGetStack = mastrStack(mintStackTop - mintItem - 1)
          Else
              acbGetStack = ""
          End If
      End Function

    For the procedure stack to work, you have to place calls to acbPushStack and acbPopStack on entry and exit from every procedure call. Good coding practice
    supports the concept of only one exit point from each procedure, but even the best programmer sometimes breaks this rule. To use the call stack, however, you must catch every exit point with a call to acbPopStack. Keep this in mind as you retrofit old code to use this mechanism and when you devise new code to use it. You can always code for a single exit point, and you will find code maintenance much easier if you do.

    More Microsoft Access Articles
    More By O'Reilly Media


       · This article is an excerpt from the book "Access Cookbook, Second Edition,"...
     

    Buy this book now. This article is excerpted from chapter seven of the Access Cookbook, Second Edition, written by Ken Getz, Paul Litwin, and Andy Baron (O'Reilly, 2005; ISBN: 0596006780). Check it out today at your favorite bookstore. Buy this book now.

    MICROSOFT ACCESS ARTICLES

    - Linking SQL Express 2005 Tables to MS Access...
    - Working with Access Projects in Access 2007
    - Exploring Access 2007
    - Working with Stored Procedures in an MS Acce...
    - Creating and Using Action Queries
    - Creating Data Access Pages with Charts using...
    - Advanced Ideas using VBA
    - VBA Details
    - Updating Records in MS Access
    - Using ADO`s Record Object with URLs
    - Exporting XML from MS Access 2003
    - Importing XML into MS Access 2003
    - On Using Pass-through Queries in MS Access
    - Distributed Queries in MS Access
    - Configuring a Linked Microsoft Access Server...





    © 2003-2008 by Developer Shed. All rights reserved. DS Cluster 4 hosted by Hostway