Handling Arrays Between ASP and COM

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情
Handling Arrays Between ASP and COM
By Adam B. Richman
Rating: 3.4 out of 5
Rate this article


print this article

email this article to a colleague

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抰 believe that I have made a database call from within ASP since summer ?998, so understand that I am coming from a component-driven Web perspective. Furthermore, I can抰 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 = 慡mith?and First Name like 慗o%?

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 揺ase 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抎 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抰 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抰 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抯 a catch.** It wouldn抰 matter much if these weren抰 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抯 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抯 are faster than For抯 or parsing strings is faster than calling ReDim and Preserve methods. This sample is simple. It doesn抰 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抰 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抰 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抰 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抰 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.

ASP中一个字符串处理类(VBScript 这个类是用于处理字符串的,是老外写的,我把里面的功能和参数加了说明使用方法:=============== test.asp================dim strset str = New StringOperations test = str.toCharArray("check this out") response.write "str.toCharArray: " fo 阅读详情

相关推荐

Vbscript获取数据库结构类(修正版)

ADOX操作类,用ADOX获取数据库结构 制作人: 刘晓逸

兔子专栏 2874

VBScript之Eval函数与Execute语句(Array.ForEach的实现)

每当使用C#中的Array.ForEach时,感觉很爽。最近在做QTP自动化测试时,偶然在QTP自带示例中看到一段代码可以动态调用方法,于是先喜若狂,着手改编了一下,写了一个VBScript版的Array.ForEach功能,使用起来确实不错。其实关键的一个地方就在于使用了VBScript中的Eval函数。首先我们来看看Eval函数的作用。 1. Eval函数 Eval函数主要是计算一个表达式...

weixin_30585437的博客 242

QTP自动化测试之VBScript基础

要想使用QTP进行自动化测试,必须了解VBScript这门语言,对于使用过ASP或VB开发的人来说,VBScript已经再熟悉不过了,但是没有接触过VBScript的同学也不要灰心,因为这门语言简单易学。 1. VBScript利器 2. Hello World 3. 数据类型 4. 变量 5. 常数 6. 运算符 1. VBScript利器 子曰:工欲善其事,必先利其器

pdn2000的专栏 2861

QTP自动化测试之VBScript对象

VBScript作为脚本语言不仅能够编写简单的脚本,而且还能够创建及使用对象编写复杂的脚本,如Class对象,数据字典,操作文件夹及文件,错误处理,正则表达式等等。 1. Class对象2. Dictionary对象3. FileSystemObject对象4. Err对象5. RegExp对象 1. Class对象 使用Class语句可以创建一个对象,可以为它编写字段、属性及方法,它只有两...

weixin_30730053的博客 259

【转】WinCC VBscript常用标准函数总结

在WinCC软件中使用VBS进行编程的时候常常使用的标准函数整理如下: 数值型函数:abs(num): 返回绝对值sgn(num): num&gt;0 1; num=0 0; num&lt;0 -1;判断数值正负hex(num): 返回十六进制值 直接表示:&amp;Hxx 最大8位oct(num): 返回八进制值 直接表示:&amp;Oxx 最大8位sqr(num): 返回平方根 num&gt...

SmallBox00的博客 4426

XML 简单接口 (SAX2)用Visual Basic 实现的示例

Martin Naughton2000年6月 下载本文的示例代码 (351 KB)摘要:本文概述用 Microsoft Visual Basic 编制 SAX2 接口的方法。简介 May 2000 MSXML Technology Preview 的关键功能之一是实现了 SAX2 (Simple API for XML, version 2)。MSDN XML 开发人员中

coolstar的调侃 1829

格式化时间日期函数

Function DateTimeToString(oDate, sFormatInfo) Dim wkDayShort, wkDayLong Dim mtNameShort,mtNameLong wkDayShort = Array("Sun","Mon","Tue","Wed","Thu","Fri","Sat") wkDayLong = Array("Sunday","Monday","Tu

卡农的魔笛 1268

VBScript基于WSH编程

大学时期也用过VBScript,不过都是基于ASP的,近期因工作需要,尝试在WSH(windows script host)下编程,实现列示oracle client下tnsnames.ora文件的主要信息(TNSname、HOST、SID),大体思路是:判断当前系统下oracle路径,从系统变量中读取具体path,通过Wscript下的文件对象读取文件,分隔path,截取o...

weixin_33753845的博客 318

vb学习

 使用静态变量放置控件: Form1:Label1,Command1 属性设置: cLabel1.Autosize= true代码:Private Sub Command1_Click() Static stflag As Boolean 使用静态变量来保存变量值 If stflag = False Then    Label1.Font.Size = 14 

dzlove的专栏 8041

vb6的一些自己写的函数 用于类型转换,十六进制输出,字节转换

基本的函数 '用于将 一个变量 的类型打印出来。 Public Function getVarTypeToString(ByVal m_value As VbVarType) As String 'varType typename 'information: IsArray IsDate IsEmpty IsError IsMissing IsNULL isNumric IsO...

weixin_34357887的博客 445

使用客户端脚本

使用客户端脚本发布日期: 9/20/2004 | 更新日期: 9/20/2004Scott Mitchell4GuysFromRolla.com摘要:尽管 ASP.NET 在服务器上执行其大多数操作,但是某些操作在客户端进行处理可能会更好。Scott Mitchell 说明了 ASP.NET 页面和控件如何添加客户端代码。下载本文的源代码。本页内容

水丝游云 1285

ASP中一个字符串处理类(加强)(VBScript

相关文章参见:http://www.csdn.net/Develop/read_article.asp?id=22695本文在此基础上进行了一些添加,加了几个适合中文网站的FUNCTION进去,可能还有些没有补充进去,有感兴趣的朋友可以再在此基础上加一点FUNCTION进去,不过可别忘记分享一下!class StringOperations *******************

871

关于javascript数组与VB DLL中中数组的传递问题

  各位:我现在在JavaScript中定义一个一维数组,然后调用VB编写的DLL对象,在DLL对象给此数组赋值,然后在JavaScript读出已经赋值的数组。请问如何操作。   DLL对象:  TestPrj.Test  PublicSubTest(strName()AsVariant)   strName(0)="MR"   strName(1)="zhang"  EndSub

0_net的专栏 959

php服务不可用,ThinkPHP/Library/Vendor/Tcpdf/fonts/uni2cid_ak12.php · 白俊遥/thinkphp-bjyadmin - Gitee.com...

// unicode to cid conversion table is from// ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/// cid2code.txt in ak12.tar.Z$cidinfo['uni2cid'] = array(32=>1,33=>2,34=>3,35=>4,36=>...

weixin_39630441的博客 125万+

CSS 学习

转载常来网免费空间CSS 教程 http://school.99081.com/css_tutorials/040_css_diff_border_margin_padding.html   margin 边距 border 边框 padding 间隙 (也有人称做补丁) content (内容,比如文本,图片等) CSS 边距属性 (margin) 是用来设置一个元素所占空间的边缘到相邻元...

Hyvi的专栏 133

node-pre-gyp WARN Tried to download(404): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.2.

出现以下错误的原因是 :node-pre-gyp WARN Tried to download(404): https://fsevents-binaries.s3-us-west-2.amazonaws.com/v1.2.7/fse-v1.2.7-node-v83-darwin-x64.tar.gz 请参考文章【重磅推荐】关于npm之代码升级顺利成功的完美攻略【package.json和package-lock.json的作用】:https://blog.csdn.net/weixin_4334..

weixin_43343144的博客 3435

Windows XP 的外观风格

使用 Windows XP 的外观风格 Windows 用户体验组Microsoft Corporation 2001年5月 本文只是初步的文档,如有更改,恕不另行通知。概要:本文档说明了如何使用 Microsoft Windows XP 来完成将外观风格应用于应用程序时必需执行的常见任务。 目录简介 ComCtl32.dll 版本 6 外观风格任务 在未使用第

sonicdater的专栏 2128

Managing Windows with WMI

Managing Windows with WMIMichael MastonMicrosoft Corporation November 1999 Summary: Introduces Microsoft® Windows® Management Instrumentation, part of Windows 2000 (but available for Win

sonicdater的专栏 1480

Creating a Server Component with VB - Redesigned - Part 1

Creating a Server Component with VB - Redesigned - Part 1By Doug DeanRating: 4.6 out of 5Rate this article document.write("print this article")print this article email this arti

sonicdater的专栏 1455
上一篇: Creating a Server Component with VB - Redesigned - Part 2
下一篇: Creating a Server Component with VB - Redesigned - Part 1
sonicdater
博客等级 码龄26年 6粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值