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!

Handling Arrays Between ASP and COM
By Adam B. Richman
Rating: 3.2 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

    Introduction

    As Visual Basic (VB) components become more and more pervasive on the Web application development landscape, we are forced to code with more structure in this environment than ever before. No longer is the slick code for our webs restricted to our webs; business objects have made short work of distributing these solutions. We have to plan for this use.

    Realizing all shops and projects are different, I don’t believe that I have made a database call from within ASP since summer –1998, so understand that I am coming from a component-driven Web perspective. Furthermore, I can’t remember the last time a client has asked me to create a static HTML page. The majority of what we do is dynamic. Sometimes, I find myself calling 411 and asking for Number where Last Name = ‘Smith’ and First Name like ‘Jo%’.

    One strategy for improving the structure of our Web development involves the way we pass data between ASP and components. I will usually try to group items (such as rights) together with the user they apply to and pass them in a variant array between components and/or back to ASP. In this way I can pass data from record sets (using the getRows method of ADODB.Recordset) and database updates to COM as well as my grouped rights all in the same type (structure) of variable. This is a question of “ease of use.” You may prefer to return record sets to ASP as themselves. My rationale is that I will definitely use arrays to pass and manipulate data within ASP and VB, so I’d rather pass my record sets that way as well. Chalk it up to personal preference.

    The Problem

    My recent discovery of a bug or a design limitation between VB and ASP relates to how VB and ASP interpret arrays. I rely heavily on arrays, therefore a utility component is one of the first I create. One of the most essential functions in that component is my ConvertToArray function. This is an asset when writing Web apps using ActiveX components.

    To quickly build components and save myself from breaking interfaces*, I like to use arrays to pass data back and forth between components. At times I also use this technique to pass data from ASP to COM. Below are two code snippets. Looking at Snippet 1, I am constructing a simple two-dimensional array (in this case it didn’t need to be two-dimensional).

    Snippet 1: Create an ASP called testCase.asp, and run it.

    
    
    
    <% @Language="VBScript" %>
    <% Option Explicit %>
    <%
    Dim tcs
    Dim rc
    Dim vntInput(0,4)
    Dim i
    
    vntInput(0,0) = Request.QueryString("strUser")
    vntInput(0,1) = Request.QueryString("intCreate")
    vntInput(0,2) = Request.QueryString("intDelete")
    vntInput(0,3) = Request.QueryString("intModify")
    vntInput(0,4) = Request.QueryString("intView")
    
    If Len(vntInput(0,0)) = 0 Then
    	Response.Redirect("testCase.asp?strUser=myDomain\arichman&intCreate=1&intDelete=1&intModify=0&intView=1")
    End If
    
    vntInputString = "String Input Value"
    
    ' First make sure we have a valid array
    For i = 0 to UBound(vntInput,2)
    	Response.write "Loop Count " & i & " " & vntInput(0,i) & "<BR>"
    Next
    Response.Write "<HR>"
    
    
    Set tcs = Server.CreateObject("TestCases.ArrayFailure")
         rc = tcs.AcceptArray(vntInput)
    
    
    ' Now see what we have left
    For i = 0 to UBound(vntInput,2)
    	Response.write "Loop Count " & i & " " & vntInput(0,i) & "<BR>"
    Next
    
    %>
    
    
    
    If you construct and parse this variant array in VB Script, it will work as intended. If you construct and parse this variant array in VB, it will work as intended as well. However, if you wish to pass your array "by value" (ByVal) from ASP to VB, you will see some messy results. Whether by design or mistake, when you pass a Variant array from ASP to COM ByVal, VB will throw an Automation Exception, and that is the problem. Also, don’t run Snippet 2 (below) in any VB component you have created before saving your data or you will have to kill it via the Task Manager.

    Create an ActiveX component called TestCases.dll and a class called ArrayFailure.

    Snippet 2:

    
    
    Public Function AcceptArray(ByVal vntArray As Variant) as Integer
    
        DoEvents
    
    End Function
    
    
    
    Now, of course, you could pass the variant array "by reference" (ByRef), but there’s a catch.** It wouldn’t matter much if these weren’t shared business objects. Yes, I could take the responsibility of always preserving the data in an object passed ByRef which was intended to be passed and not manipulated, but this seems overly involved and it is not my preference.

    The Solution

    There’s a COM solution for a COM problem. Create a function that will parse a string and return an array from VB. ASP preserves the returned variant array and it will not cause an Automation Exception when sent into a component ByVal. To do this, replace the ASP-built array in Snippet 1 with the sample code in Snippet 3.

    Add this snippet to the above ASP sample in place of the ASP-built array.

    Snippet 3

    
    
    <% @Language="VBScript" %>
    <% Option Explicit %>
    <%
    Dim tcs
    Dim rc
    Dim vntInput
    Dim vntInputString
    Dim i
    
    dim cta 
    
    set cta = Server.CreateObject("TestCases.ArrayFailure")
    rc = cta.ConvertToArray("a,b,c,d,e,f,g,h,i,j,k,l", ",", 3, vntInput)
    
    
    
    Note: You will not need to dimension the bounds of this array (see above code appearing in bold) in ASP. VB will do that inside your ConvertToArray function.

    Create an ActiveX component and class to house useful utilities.

    Snippet 4:

    
     
    Option Explicit
    Private Const vectorSize As Integer = 10
    
    Public Function ConvertToArray(ByVal strParse As String, _
                                              ByVal strDelimiter As String, _
                                              ByVal intDimensions As Integer, _
                                              ByRef vntArray As Variant) As Integer
                                              
        Dim intColumns As Integer, intCnt As Integer, intPos As Integer
        Dim i As Integer, j As Integer, n As Integer
        Dim vntTemp As Variant
        Dim strTemp As String, chrTemp As String
        
        ' loop for number of instances of the delimiter and store it in an array for later use.
        ReDim vntTemp(vectorSize)
        n = 0
        For intPos = 1 To Len(strParse)
            chrTemp = Mid$(strParse, intPos, 1)
            If Mid$(strParse, intPos, 1) = strDelimiter Then
                intCnt = intCnt + 1
                FillAndSize n, strTemp, vntTemp
                strTemp = ""
                n = n + 1
            Else
                strTemp = strTemp & chrTemp
            End If
        Next
        FillAndSize n, strTemp, vntTemp
        ReDim Preserve vntTemp(n)
        
        ' redim the array (deprecating by 1 for base zero array) by row and column
        intColumns = (intCnt + 1) / intDimensions
        intDimensions = intDimensions - 1
        intColumns = intColumns - 1
        ReDim vntArray(intDimensions, intColumns)
        
        ' populate the newly redimensioned array
        n = 0
        For j = 0 To intColumns
            For i = 0 To intDimensions
                vntArray(i, j) = vntTemp(n)
                n = n + 1
            Next
        Next
                           
    End Function
    
    Private Sub FillAndSize(ByVal intCount As Integer, ByVal strTemp As String, ByRef vntInput As Variant)
        
        Dim i As Integer
        i = intCount Mod vectorSize
        If i = 0 And intCount >= vectorSize Then
            ReDim Preserve vntInput(intCount + vectorSize)
        End If
        vntInput(intCount) = strTemp
    
    End Sub
    
    
    
    Snippet 4 contains a function and sub to take a string and parse it out, then throw it into an array. This is not the best way to do this. You will find various opinions that say Do’s are faster than For’s or parsing strings is faster than calling ReDim and Preserve methods. This sample is simple. It doesn’t take up much space and it was quick to write You probably have your own techniques for doing this, and they will work fine or better.

    The main point is that you have your data in an array that will work for your needs in both ASP and VB. There are a couple of things to remember when you are creating this sort of array builder. If you are going to use a .getRows method for data retrieval in COM, you will notice that it populates arrays by indexing on the outer element. Also remember that if you plan on resizing arrays in VB sent in as a parameter by ASP, you will need to ReDim Preserve the array. VB will only allow you to resize the outer element of your array (e.g., vntArray(1,10) can only be resized by (1,n). The 1 in this example is fixed).

    Additional Ideas

    There are various ways to profit from using arrays in building COM/ASP solutions. One of the most valuable is the ability to change the ways your functions behave without touching the functions’ parameters. From my vantage point, everywhere there is a database update, I can use a variant array as a parameter and never break binary compatibility***, while continually cramming more and more updates in the function as the scope or requirements change. Example of a Modify function that implements a variant array. Snippet 5

    
    
    
    Public Function Modify(ByVal lngItemNum As Long, _
                                  ByVal strTableName As String, _
                                  ByVal vntModifications As Variant) As Integer
                                  
        Dim intCols As Integer, intRecs As Integer
        Dim strUpdate As String, strQuery As String
        Dim cn As ADODB.Connection
        Dim rs As ADODB.Recordset
        
        ' for each modification add a new name/value pair to the update statement
        For intCols = 0 To UBound(vntModifications, 2)
            strUpdate = "," & strUpdate & vntmods(0, intCols) & "=" & vntmods(1, intCols)
        Next
        ' trim off the leading comma in the update string
        strUpdate = Mid$(strUpdate, 2)
        strQuery = "UPDATE " & strTableName _
                    & " SET " & strUpdate _
                    & " WHERE Item_Num = " & lngItemNum
        
        Set cn = CreateObject("ADODB.Connection")
        cn.Open "OLEDB PROVIDER CONNECTION STRING"
        rs = cn.Execute(strUpdate, intRecs)
        
    End Function
    
    
    
    Snippet 5 is an example of a very generic function called "Modify" that I can use to change anywhere from one to 10 (or more) columns in a table passed in by strTableName. For this to be a truly effective COM object, it would contain the business logic, instead of the ASP that calls it. Look at this function as being incomplete. A more complete version would take in parameters that we would perform business operations upon and then some (potentially a growing number) additional parameters would be sent in by vntModifications.

    Keeping in mind generic nature of the example, if the case demanded that I need more criteria (the where statement in this snippet) to make my update, I would need to define that in the design stage and include that in my parameter list. For the sake of simplicity, consider the above example to be updating a table with a unique index Item_Num. We could construct myriad different arrays containing a name/value pair with which we wish to update the record. Of course, we could use a string for input. We could continue to grow the string and never break the interface as well. If we know that the input will never need massaging, this will work fine. On the other hand, if we may need to massage data, it is far simpler to test elements of an array than parse a string (see Snippet 6). This is an example of the ease of testing a condition in an array vs. parsing a string. Snippet 6

    
     
    . . .
    ' for each modification add a new name/value pair to the update statement
        For intCols = 0 To UBound(vntModifications, 2)
            If UCase(CStr(vntmods(0, intCols))) = "FIRST_NM" Or UCase(CStr(vntmods(0, intCols))) = "LAST_NM" Then
                strUpdate = "," & strUpdate & vntmods(0, intCols) & "=" & UCase(CStr(vntmods(1, intCols)))
            Else
                strUpdate = "," & strUpdate & vntmods(0, intCols) & "=" & vntmods(1, intCols)
            End If
        Next
    . . .
    
    
    
    Whether you are using strings or arrays, adding some structure to your code will greatly benefit future modifications. We are forced to code with more structure than ever before, and seeing the potential pitfalls should allow us to create a more pliant and robust application.

    Notes

    * Use arrays for input parameters wherever logical. Arrays can greatly reduce the number of interface changes made. By constructing functions with arrays as parameters, components can service many more component calls without interface changes.

    ** Declare all function parameters explicitly ByVal ("A way of passing the value, rather than the address, of an argument to a procedure. This allows the procedure to access a copy of the variable. As a result, the variable's actual value can't be changed by the procedure to which it is passed." MSDN Visual Studio 6.0) except those intended to return a value ByRef. This will prevent changing the values of data that may be used later in code, be that ASP or other components.

    *** Always compile components using binary compatibility (see Design Note below). This will enable others calling these objects to declare their components using vTable Binding (Early Binding) and to not need to recompile every time internal code is changed. According to MSDN; "For in-process components, vtable binding reduces call overhead to a tiny fraction of that required for DispID binding." VB generates a GUID for components in the Windows Registry. When you compile with binary compatibility, VB will use the previous GUID for its registry entry, provided the interface has not changed. Consequently, customers will never need to recompile their objects when we recompile our component., (This is only pertinent to "component-to-component" design. This will have no effect on ASP because all ASP is late bound.) Although it would be very convenient to create one giant ActiveX component with all of your classes, I wouldn’t advise it. By doing this you greatly increase the number of times you will have to change interfaces, thus breaking binary compatibility. Creating this large ActiveX component is fine if you are creating specific classes that will not be shared business objects – others aren’t relying on your GUID. I try to group my classes in their functionality (relationships), but any type of grouping will work. Note: Be mindful of cross dependencies that can make build time a nightmare.

    Design Note on Planning the Use of Binary Compatibility

    * Use arrays for input parameters wherever logical. Arrays can greatly reduce the number of interface changes made. By constructing functions with arrays as parameters, components can service many more component calls without interface changes.

    ** Declare all function parameters explicitly ByVal ("A way of passing the value, rather than the address, of an argument to a procedure. This allows the procedure to access a copy of the variable. As a result, the variable's actual value can't be changed by the procedure to which it is passed." MSDN Visual Studio 6.0) except those intended to return a value ByRef. This will prevent changing the values of data that may be used later in code, be that ASP or other components.

    *** Always compile components using binary compatibility (see Design Note below). This will enable others calling these objects to declare their components using vTable Binding (Early Binding) and to not need to recompile every time internal code is changed. According to MSDN; "For in-process components, vtable binding reduces call overhead to a tiny fraction of that required for DispID binding." VB generates a GUID for components in the Windows Registry. When you compile with binary compatibility, VB will use the previous GUID for its registry entry, provided the interface has not changed. Consequently, customers will never need to recompile their objects when we recompile our component., (This is only pertinent to "component-to-component" design. This will have no effect on ASP because all ASP is late bound.) Although it would be very convenient to create one giant ActiveX component with all of your classes, I wouldn’t advise it. By doing this you greatly increase the number of times you will have to change interfaces, thus breaking binary compatibility. Creating this large ActiveX component is fine if you are creating specific classes that will not be shared business objects – others aren’t relying on your GUID. I try to group my classes in their functionality (relationships), but any type of grouping will work. Note: Be mindful of cross dependencies that can make build time a nightmare.

    Download the Code

    You can download the complete source for the sample contained in this article:

    http://15seconds.com/files/990826.zip

    About the Author

    A Russian interpreter by education, Adam Richman has been a web developer since 1995. He is currently a consultant on a 3-tier development project at a pharmaceutical firm in Research Triangle Park, North Carolina. Adam is also working to establish a project-oriented web development business implementing COM, Java, VB and ASP solutions. He can be contacted at arichman@ipsolve.com.

  • 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]
    Oct 2, 2002 - Function Pointers and COM
    Using callbacks and function pointers in VB can be risky and complicated. Ben Garcia explains his work-around for the function pointer issue he encountered while creating the VB version of his SNMP component.
    [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]
    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

    Solutions
    Whitepapers and eBooks
    Microsoft Article: HyperV-The Killer Feature in WinServer ‘08
    Avaya Article: How to Feed Data into the Avaya Event Processor
    Microsoft Article: Install What You Need with Win Server ‘08
    HP eBook: Putting the Green into IT
    Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
    Avaya Article: Setting Up a SIP A/S Development Environment
    IBM Article: How Cool Is Your Data Center?
    Microsoft Article: Managing Virtual Machines with Microsoft System Center
    HP eBook: Storage Networking , Part 1
    Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
    MORE WHITEPAPERS, EBOOKS, AND ARTICLES
    Webcasts
    Intel Video: Are Multi-core Processors Here to Stay?
    On-Demand Webcast: Five Virtualization Trends to Watch
    HP Video: Page Cost Calculator
    Intel Video: APIs for Parallel Programming
    HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
    Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
    MORE WEBCASTS, PODCASTS, AND VIDEOS
    Downloads and eKits
    Sun Download: Solaris 8 Migration Assistant
    Sybase Download: SQL Anywhere Developer Edition
    Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
    Red Gate Download: SQL Compare Pro 6
    Iron Speed Designer Application Generator
    MORE DOWNLOADS, EKITS, AND FREE TRIALS
    Tutorials and Demos
    How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
    eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
    IBM Article: Collaborating in the High-Performance Workplace
    HP Demo: StorageWorks EVA4400
    Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
    Microsoft How-to Article: Get Going with Silverlight and Windows Live
    MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES