asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Function Pointers and COM
By Ben Garcia
Rating: 3.2 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction

    While writing the second SNMP article, Creating an SNMP Component - Part 2, an issue had been encountered with the SnmpCreateSession API function. It forced the developer to pass a function pointer so that all responses could be routed to whatever function was passed. It is important to note that the use of function pointers in Visual Basic should be limited to instances when it is absolutely necessary. The method chosen to solve a problem should be well researched before deploying it into a production environment.

    The solution and methodology presented in this article is only meant to be a guide and offer alternate solutions to the aforementioned topic. This is by no means a "be all, end all" solution and should be used with proper caution. Again, any developer that utilizes these techniques should understand the impact and possible ramifications of implementation.

    AddressOf Operator

    Syntax: [lngVal] = AddressOf procName
    Example: lSession = SnmpCreateSession(0, 0, AddressOf SnmpAgentResponse, 0)

    The AddressOf operator in Visual Basic returns the reference of a procedure as a long data type. In the example above, SnmpAgentResponse is a procedure defined within a module in a Visual Basic project. It is passed as a pointer into SnmpCreateSession to allow the API to make a callback so that when a response is generated from the agent it can dynamically call SnmpAgentResponse, the function pointer.

    When callbacks are used, the API function being executed will expect a certain argument list. For example, in the case of SnmpCreateSession, the argument list that SnmpAgentResponse must adhere to is the parameter list of SNMPAPI_CALLBACK. This isn't a true function; it's more of a placeholder for the function pointer. Listed below is both the definition for SNMPAPI_CALLBACK and SnmpAgentResponse:

    
    // As outlined in the MSDN
    SNMPAPI_STATUS CALLBACK SNMPAPI_CALLBACK(
      HSNMP_SESSION hSession,  // handle to the WinSNMP session
      HWND hWnd,                           // handle to the notification window
      UINT wMsg,                             // window notification message number
      WPARAM wParam,                // type of notification
      LPARAM lParam,                   // request identifier of PDU
      LPVOID lpClientData             // optional application-defined data
    );
    
    ' As defined in the NetMgrVB component
    Private Function SnmpAgentResponse(
      ByVal lSession As Long,
      ByVal hWnd As Long, 
      ByVal wMsg As Long, 
      ByVal wParam As Long, 
      ByVal lParam As Long, 
      ByVal lpClientData As Long
    ) As Long
    
    
    As outlined, both functions are declared with the same argument list and data type definitions. The Visual Basic implementation has different variable type definitions, but the long data type will properly translate into the API function.

    It is possible to pass a function pointer between procedures within a Visual Basic project; however, there is no support for calling a function by this convention. Error handling within the callback function cannot be instituted because the caller is not in the application where the callback function resides. If an error is passed to the caller, more than likely a fatal error will occur causing your application to crash. In article Q198607 of the Microsoft Knowledge Base, they attribute this kind of behavior to the fact that "the callback function is called by a thread that was not created by Visual Basic."

    The same error can occur if other API calls are made from within the callback function. This issue, coupled with the necessity to use callbacks in a Visual Basic COM environment, gave way for an alternative method for implementing this functionality.

    Alternative Method

    Using a callback function within a COM object can be very dangerous because waiting for a response from the callback, as in the SnmpAgentResponse example, causes the necessity for a do...loop statement that checks a global variable for changes. So what happens when the API doesn't return anything for 60 seconds or anything at all? A virtual timeout value can be set where if a certain amount of iterations have occurred or the total seconds elapsed breach a specified timeframe, the do...loop statement can be exited and an error code can be returned.

    Below is a more detailed discussion on how to mesh callback functions and COM methods together without being volatile to the project. For the remainder of the article, source code from the Creating a SNMP Component -- Part 2 will be used, specifically the NetMgrVB component.

    The flow for a typical Get/Set action in the NetMgrVB component is as follows:

    Initiate ObjectSet snmpObj = CreateObject("NetMgrVB.SNMPv1")
    Assign Values to PropertiessnmpObj.Agent = "[agent address]"
    snmpObj.CommStr = "[community string]
    snmpObj.Timeout = [timeout in ms]
    snmpObj.Retry = [total number of retries]
    Open SessionstrRetVal = snmpObj.SnmpMgrOpen()
    Make a Get RequeststrRetVal = snmpObj.SnmpGet("[OID]")
    Close ConnectionstrRetVal = snmpObj.SnmpMgrClose()
    Destroy ObjectSet snmpObj = nothing

    The intention isn't to give a tutorial over the NetMgrVB component, this is simply provided to help correlate internal functions and processes to the flow of the component. For more information on the NetMgrVB component, please read Creating a SNMP Component - Part 2.

    Listed below are two functions and a snippet of code to begin with:

    
    ' Called in NetMgrVB.modSNMPAPI.SnmpOpenSession procedure
    ' SnmpOpenSession is called by NetMgrVB.SnmpV1.SnmpMgrOpen
    
    lSession = SnmpCreateSession(0, 0, AddressOf SnmpAgentResponse, 0)
    
    
    This is where the function pointer is first introduced to the API function. As pointed out in the AddressOf section, the procedure that follows the AddressOf operator must be defined in a module. If the procedure is located in another module, you can reference it by [moduleName].[procedureName]. Procedures defined in a form or class is not permitted.

    Next is the modSNMPAPI.InitAgentProc function which handles the actual coordination of callback function:

    
    Public Function initAgentProc(
      ByVal lSession As Long, 
      ByVal lngPDUType As Long, 
      ByVal strOID As String, 
      ByVal varOIDValue As Variant
    ) As String
        ' Local variable declarations
        ' --------------------------------
        Dim strRetVal As String
        Dim lngRetVal As String
        
        ' Make request to agent
        ' This passes the requests made from SnmpV1.Get/GetNext/Set to the agent for processing
        strRetVal = SnmpAgentRequest(lSession, lngPDUType, strOID, varOIDValue)
       
        ' Check to see if an error was returned
        If InStr(1, strRetVal, "[NetMgrVB.Mod.", 1) > 0 Then
            ' Return error message
            initAgentProc = strRetVal
        Else
            ' Wait for SnmpAgentResponse to be executed
            ' At this point the agent has been queried a Do...Loop 
            ' statement so that we can wait for a response from the 
            ' callback function
            Do
                DoEvents			    ' Allows other events to continue in the
        ' background
                Sleep APP_RESPONSE_TIME ' Sleep was put in so that in 100% of the
    					    ' CPU wasn't continuously being utilized
            Loop Until (boolResponse)	  ' boolResponse is the global variable that
    					    ' is set to true in SnmpAgentResponse 
        ' when it has completed it's execution
            
            ' Return response for request value
            ' The function that handles all of the actual processing
            initAgentProc = SnmpResponseProcess(lSession)
        End If
    End Function
    
    
    This function is responsible for handling all high-level communication with the agent. High-level means that the actual parsing isn't handled in this function, so instead it makes the calls to appropriate functions that handle parsing and waits for a response.

    Once the Get/GetNext/Set methods are called from NetMgrVB.SnmpV1, InitAgentProc is called and a request has been made. The next function is called as callback from the API function.

    
    Private Function SnmpAgentResponse(
      ByVal lSession As Long, 
      ByVal hWnd As Long, 
      ByVal wMsg As Long, 
      ByVal wParam As Long, 
      ByVal lParam As Long, 
      ByVal lpClientData As Long
    ) As Long
        ' Assign values to global variables
        lngWParam = wParam       ' If wParam = 0 then a SNMP message is available
        lngLParam = lParam          ' Specifies the request id for the pdu being processed
        boolResponse = True         ' Set global to recognize response has been received
        
        ' Return Success -- must be returned
        SnmpAgentResponse = SNMPAPI_SUCCESS
    End Function
    
    
    The only actions that occur are global variable assignment since no other processing/API calls can occur (as outlined in article Q198607 in the Microsoft Knowledge Base). However, once this has been executed, global variable boolResponse is set true and the processing can continue in procedure InitAgentProc.

    So what happens when the agent doesn't return a response, o itr takes a very long time to execute? This is where adding a timeout value will help out greatly. Take a look at the initAgentProc again:

    
    Public Function initAgentProc(...) As String
            Dim lngBeginTimer as long	' New local variable: Start Timer Value
         ...
    	    lngBeginTimer = Timer
         ...
            ' Wait for SnmpAgentResponse to be executed
            Do
                DoEvents
                Sleep APP_RESPONSE_TIME
    	If Round(Timer - lngBeginTimer,0) >= APP_AGENT_TIMEOUT then
    		InitAgentProc = "[NetMgrVB.Mod.InitAgentProc][TO1]=Response Timeout has occurred"
    		Exit function
    	End if
            Loop Until (boolResponse)
         ...
    End Function
    
    
    For the purpose of this article, APP_AGENT_TIMEOUT is a Constant that houses the internal time out value in seconds. If the threshold is breached, the procedure returns an error back to the calling function and request is stopped.

    Recap

    Here is a brief summary of the problem and solution presented:

    1. AddressOf Operator
      1. Syntax: AddressOf [procedurename]
      2. Returns the reference or address of a procedure as a long data type
      3. Procedures passed to AddressOf must be defined in a module
      4. Cannot actually call a function by it's function pointer
    2. Alternative Method
      1. Create four functions (or a similar implementation) that will handle:
        1. Passing the function pointer to an API call (SnmpOpenSession)
        2. The actual callback function, which will act as a placeholder (SnmpAgentResponse)
        3. Coordination of high-level procedure calls (initAgentProc)
        4. The actual processing of the response (SnmpResponseProcess)
      2. Additional processing might be required to trigger the mechanism that calls the callback function. The examples above show that a request must be made before the callback is triggered).

    The callback function was chosen to be a placeholder instead of handling the actual processing because any API call made within it would instantly crash the component. So, by segmenting functionality into different functions with one procedure that handles coordination, API calls can be made without encountering fatal errors.

    Conclusion

    The procedure might seem simplistic. But without understanding how callbacks and function pointers operate within Visual Basic, this task can become a challenge very quickly. The key in this process is that functionality is segmented into different procedures with one central location where those functions are brought together. The impression was given that the SnmpMgrRequest function, which is a part of the SNMP Management API (mgmtapi.lib) that was demonstrated in the original NetMgr SNMP component, acts in a very similar fashion. This methodology can be applied to other API calls that allow or force the use of callbacks. Please feel free to email bgarcia@adaptiveinnovations.net with any questions about this convention.

    All references provided dealt primarily with SNMP and the NetMgr components. This wasn't meant to be an additional tutorial on either of these items. The NetMgrVB component demonstrated the issue and a work-around for dealing with function pointers in a Visual Basic COM environment.

    References

    MSDN, AddressOf Operator
    Q198607 - PRB: Access Violation in VB Run-Time Using AddressOf, Microsoft Knowledge Base

    Creating a SNMP Component -- Part 2, by Benjamin Garcia

    About the Author

    Ben Garcia is the President and Co-founder of Adaptive Innovations, LLC, a solution provider specializing in integration and artificial intelligence. He has more than 13 years of software development experience in many different facets of the industry. Please feel free to contact Ben at bgarcia@adaptiveinnovations.net.

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Other Articles
    Apr 27, 2004 - Develop and Customize Web Parts with Custom Tool Parts
    Tool Parts provide an interface for Web Part properties well beyond the capabilities of the default property pane. In this article Gayan Peiris shows how to customize Web Parts with custom Tool Parts.
    [Read This Article]  [Top]
    Apr 7, 2004 - Reusable Components in ASP.NET 2.0, Object Binding and Precompilation
    This article demonstrates how to create a reusable component in ASP.NET 2.0 and then consume it from an ASP.NET page. Also learn how the ObjectDataSource control can be used to directly bind the output of an object to the controls in an ASP.NET page and how precompilation can be used to increase the performance of the Web application and catch compilation errors.
    [Read This Article]  [Top]
    Mar 31, 2004 - Build a Managed BHO and Plug into the Browser
    Browser Helper Objects (BHOs) are COM components that communicate with Internet Explorer to enrich the browsing experience. Michele Leroux Bustamante returns to the world of COM to show you how to build a managed BHO with the help of the .NET Framework's COM interoperability features.
    [Read This Article]  [Top]
    Feb 18, 2004 - Customizing SharePoint Web Parts with Custom Properties
    In addition to creating custom Web Parts for SharePoint Portal Server, developers can actually create their own custom properties to further enhance Web Part appearance and behavior. Gayan Peiris explains the process and provides all the necessary code.
    [Read This Article]  [Top]
    Sep 26, 2003 - Accessing Shared Resources Using ASP.NET
    Accessing shared resources is a challenge for many ASP.NET developers. Tony Arslan explains how a simple serviced component can solve this infamous problem.
    [Read This Article]  [Top]
    Sep 4, 2002 - Creating an SNMP Component - Part 2
    In part two of this intriguing article series, Ben Garcia shows how to build an updated and improved SNMP component in VC++ AND VB, and he briefly explains why limitations in VB make VC++ a better language for developing this type of application.
    [Read This Article]  [Top]
    Jul 23, 2002 - Creating an SNMP Component
    Ben Garcia sheds some light on the Simple Network Management Protocol (SNMP). First he provides a history of SNMP, then he dives right into its architecture. Finally, he shows how to build a COM component that communicates with SNMP-enabled devices.
    [Read This Article]  [Top]
    Jun 26, 2002 - Accessing Caller ID from the Web - Part 1
    Paul Apostolos begins his series on using Web services and the MSComm32.OCX component to access caller id information from a Web page. In part 1, learn how to write the Visual Basic program that runs on the server and updates a database with incoming callers.
    [Read This Article]  [Top]
    Nov 20, 2001 - Creating a Server Component with VB - Redesigned - Part 2
    Doug Dean explains different methods of retrieving and manipulating data from a database in a VB DLL so that it is ready to be rendered in a browser.
    [Read This Article]  [Top]
    Aug 28, 2001 - Create Your Own Visual Basic Add-Ins
    In this article, S.S. Ahmed shows you how to create VB add-ins. Programmers always feel that they are short of several features while working with development tools. Since Microsoft made Visual Basic an extensible product, VB developers can create their own features in VB.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers