Visual Interdev Overwriting Type Libraries (Bug) 08 January 2001 at 00:00

Interdev likes to take control of the global.asa file. If possible, always add references to type libraries in your global.asa using the Project/Project References menu route.

However, if this is not possible, adding the following two lines around your type library declaration will prevent Visual Interdev from writing over portions of your file:

  <!--==Visual InterDev Generated - startspan==-->
  <!--==Visual InterDev Generated - endspan==-->
Internet Explorer 4 BUG: Session Status 08 January 2001 at 00:00
I experienced a major problem with IE4 users mysteriously losing their session status. In the end, it turned out to be the Browse in New Process attribute of their browsers turning off whenever they switched off their machines. The following is the solution recommended by Microsoft:

  • Start
  • Run
  • Type 'regedit'
  • Maximize 'HKEY_CURRENT_USER'
  • Maximize 'Software'
  • Maximize 'Microsoft'
  • Maximize 'Windows'
  • Maximize 'CurrentVersion'
  • Select 'Internet Settings'
  • Delete 'Internet Settings'
  • Restart Machine
This will then reload all the defaults into the registery.
Sending Email in HTML format with ASP 08 January 2001 at 00:00
IIS5 has the functionality with it's CDO object to send email in both text and HTML formats. However, if you want to send in HTML format with an earlier webserver, you need to add headers to the email:

  Dim mailMessage
  Dim oMail
  
  Set oMail = Server.CreateObject("CDONTS.NewMail")

  mailMessage = "<!DOCTYPE HTML PUBLIC ""-//IETF//DTD HTML//EN"">" 
  & chr(13) _
  & chr(10) _
  & "<html> " _
  & "<head>" _
  & "<meta http-equiv=""Content-Type"" content=""text/html; charset=iso-8859-1"">" _
  & "<title>Questionnaire</title>" _
  & "<style>" _
  & "td { font-family: verdana; font-size: 8pt; color: navy; } " _
  & "input { font-family: verdana; font-size: 8pt; color: navy; } " _
  & "</style>" _
  & "</head>" _
  & "<body bgcolor=""orange"">" _
  & "Body information here (i.e. your actual message)" _
  & "</form>" _
  & "</body>" _
  & "</html>" 

  oMail.BodyFormat = 0
  oMail.MailFormat = 0

  oMail.To = "matt@somewhere.com"
  oMail.From = "matt@somewhere.com"
  oMail.Subject = "Beautifully coloured questionnaire"
  oMail.Body = mailMessage

  oMail.Send

  Set oMail = Nothing  

SQL Server : Using Parameters 08 January 2001 at 00:00

You can use parameters to pass a value into a stored procedure, or to return a value from a stored procedure to a calling program. You can have up to 1024 parameters in a stored procedure.

Parameters can be given default values. The default value can be a constant value or NULL. You do not need to pass a parameter a value if a default is specified.

Example:

  CREATE PROCEDURE MyProcedure
    (
    @Name varchar(200),
    @Age int,
    @Year int = 2000,     /* default of 2000 specified */
    @ParticipantID int OUTPUT
    )
  AS
    SELECT @retval = 0
    INSERT INTO Participants
      (
      Name,
      Age,
      Year,
      DateEntered
      )
    VALUES
      (
      @Name,
      @Age,
      @Year,
      GetDate()
      )
  /* Give return variable value of error */
  SELECT @retval = @@ERROR    
  /* Return the new identity value */
  SELECT @ParticipantID = @@IDENTITY
  return
Checking for a file with ASP (VBScript) 08 January 2001 at 00:00
This is very useful for sites that allow users to upload, for example, images. You can check to see if a file exists before attempting to show their uploaded image on a page, or check to see if it exists before uploading a file of the same name and overwriting an old version.
  '------------------------------------------------------------------------------
  ' Pass the file name and the directory path into the function to determine
  ' if the file exists
  ' @param myFile    the name of the file
  ' @param directory the directory the file should be in
  ' @return True     if the file does exist, false if not
  '------------------------------------------------------------------------------
  Function FileExists(myFile)  
    Dim fs, outVal
    ' create file system object and see if file exists  
    Set fs = CreateObject("Scripting.FileSystemObject")  
    If fs.FileExists(myFile) Then    
      outVal = True  
    Else    
      outVal = False  
    End If
    Set fs = Nothing    
    FileExists = outVal
  End Function
Using cookies with ASP 08 January 2001 at 00:00
To write a cookie to the user's hard drive:
(Note: Most browsers do give users the option to turn off cookies. Sites should not rely on the use of cookies to store critical data.
  ' Write your cookie and your value
  Response.Cookies("MyCookieName") = "ValueOfCookie"
  ' Make the cookie only expire in one year's time.
  ' Not writing this line will result in a session-level
  ' cookie i.e. hangs around until the user closes their
  ' browser.
  Response.Cookies("MyCookieName").Expires = Date + 365
To read the cookie:
  Request.Cookies("MyCookieName")
Listing Directory Contents with ASP 08 January 2001 at 00:00
  Dim objFSO    ' FileSystemObject variable
  Dim objFolder ' Folder variable
  Dim objItem   ' Variable used to loop through the contents of the folder

  ' Create the file system object
  Set objFSO = Server.CreateObject("Scripting.FileSystemObject")

  ' Get a handle on our folder
  Set objFolder = objFSO.GetFolder(Server.MapPath("."))

  ' first, loop through all the subdirectories
  For Each objItem In objFolder.SubFolders
    ' don't include Visual Interdev _vti folders
    If InStr(1, objItem, "_vti", 1) = 0 Then
      Response.Write("Name: " & objItem.Name)
      Response.Write("Size: " & objItem.Size)
      Response.Write("Date Created: " & objItem.DateCreated)
      Response.Write("Type: " & objItem.Type)
      Response.Write("<hr>")	
    End If
  Next

  ' loop through all the files in the directory
  For Each objItem In objFolder.Files
    Response.Write("Name: " & objItem.Name)
    Response.Write("Size: " & objItem.Size)
    Response.Write("Date Created: " & objItem.DateCreated)
    Response.Write("Type: " & objItem.Type)
    Response.Write("<hr>")	
  Next

  ' clean up
  Set objItem = Nothing
  Set objFolder = Nothing
  Set objFSO = Nothing
Editing Microsoft Excel Documents with ASP 08 January 2001 at 00:00
If you have Microsoft Excel installed on your web server, you can edit or create documents using ASP.
  Dim objApp, objWorkBook, objASheet

  ' create instance of Excel, Workbook and finally active sheet
  Set objApp = CreateObject("Excel.Application")
  Set objWorkBook = objApp.WorkBooks.Add
  Set objASheet = objApp.ActiveWorkBook.ActiveSheet

  ' set sheet name
  objASheet.Name = "Address Book"
  
  ' set title fields
  objASheet.Cells(1,1).Value = "Name"
  objASheet.Cells(1,1).Font.Bold = True
  objASheet.Cells(1,2).Value = "Telephone"
  objASheet.Cells(1,2).Font.Bold = True

  ' set info fields
  objASheet.Cells(3,1).Value = "Matthew Salmon"
  objASheet.Cells(3,2).Value = "3121878"
  objASheet.Cells(4,1).Value = "Fiona Morris"
  objASheet.Cells(4,2).Value = "2662687"

  ' save sheet to whereever
  objASheet.SaveAs Server.MapPath(".") & "TEST.XLS"
	
  ' quit the application - very important to prevent multiple instances of Excel
  ' running on the server - use On Error Resume Next to ensure this line gets 
  ' executed
  objASheet.Application.Quit

  ' clean up
  Set objASheet = Nothing
  Set objWorkBook = Nothing
  Set objApp = Nothing
Adding HTML Attributes in XSL 08 January 2001 at 00:00
e.g. you want to add an image using the PRODUCTIMAGE element from your stylesheet:
<IMG>
  <xsl:attribute name="SRC"><xsl:value-of select="PRODUCTIMAGE" /></xsl:attribute>
</IMG>
Generate dynamic file downloads with ASP 08 January 2001 at 00:00
Should you ever require to generate a download file from ASP, where the file doesn't actually exist, but is perhaps the results of a query, here is the code. Works in IE4+ and NN2+. Without the "content-disposition" header, the filename the browser prompts to save is the name of the ASP page (eg. download.asp) - you can replace "data.csv" with anything you like.
  Response.ContentType = "application/csv"
  Response.AddHeader "content-disposition", "inline; filename=data.csv"
  Response.Write("one,two,three" & chr(13) & chr(10))
  Response.Write("1,2,3" & chr(13) & chr(10))
  Response.Write("1,2,3" & chr(13) & chr(10))
File Uploads with Microsoft Post Acceptor 09 January 2001 at 00:00
The following code shows you how to allow users to upload files to your server using Microsoft's Post Acceptor software which (I think) ships with Option Pack 4.0. For a complete explanation on how to set this up on your server, you can visit the Microsoft site, but in brief, all you need is the following code in your ASP file, a SCRIPTS directory with execute access applied and the post acceptor DLL in it, and a directory to write your files to.

  <%
  ' set up all the variables used for the post acceptor to upload images
  strServerURL = "http://" & Request.ServerVariables("SERVER_NAME")
  strTargetURL = strServerURL & pathVar & "/TargetFolder"
  strRepostURL = strServerURL & pathVar & "/TargetPage.asp"
  strPathToPA =  strServerURL & "/Scripts/cpshost.dll"
  strPostingURL = strPathToPA + "?PUBLISH?" + strRepostURL
  
  ' the following variables will be populated AFTER an upload (assuming 
  ' this page is your target page (strRepostURL)
  target = Request.Form("TargetURL")
  fileName = Request.Form("FileName")
  fileExt = Request.Form("FileExtention")
  filePath = Request.Form("FilePath")
  fileSize = Request.Form("FileSize")
  %>
 
  ' in your actual HTML document:
  <body>
  <form name="frmUp" enctype="multipart/form-data" action="<%= strPostingURL %>" method="post" onSubmit="return validate()">
    <b>Step 1:</b> Please click the "Browse" button and select the file from your computer which you want displayed on your web page. 
    <br>
    <input name="my_file" type="file" size="<%=ins(50)%>"><p>
    <b>Step 2:</b> Please type a description of the image as you would like the information to appear on your webpage.
    <br>
    <textarea name="imageDesc" rows="3" cols="50"></textarea>
    <input name="TargetURL" type="hidden" value="<%=strTargetURL%>"><br>
    <input name="CentreID" type="hidden" value="<%=CentreID%>"><br>
    <b>Step 3:</b> When you have selected the file, click <input type="submit" value="Upload" class="button">
  </form>
  </body>
ASP's Global.asa 08 January 2001 at 00:00
Below is an example of the Global.asa file which can be used when writing ASP applications. If you put this file in the root of a virtual directory or a site on IIS (NOT in a subfolder of a virtual) then it is the first thing that is executed whenever your application starts up. An application starts up when someone accesses your site for the first time after the web site has been stopped and started or the global.asa has been overwritten.
  <SCRIPT LANGUAGE="VBScript" RUNAT="Server">
  </SCRIPT>

  <OBJECT RUNAT=Server SCOPE=Session ID=Conn PROGID="ADODB.Connection">
  </OBJECT>

  <SCRIPT LANGUAGE=VBScript RUNAT=Server>
  Sub Application_OnStart
    Application("DefaultColour") = "navy"
  End Sub

  Sub Application_OnEnd
    'do nothing
  End Sub

  Sub Session_OnStart
    On Error Resume Next
    ' open connection to database
    Conn.Open "MyDSN", "userName", "passWord"
    Set Session("Conn") = Conn
    ' get username from cookie and assign to session variable
    Session("UserName") = Request.Cookies("UserName")
  End Sub

  Sub Session_OnEnd
    On Error Resume Next
    Session("Conn").Close
    Conn.Close
  End Sub
  </SCRIPT>
Creating a Graphical Hit Counter with ASP 08 January 2001 at 00:00
All you need to make a graphical hit counter with ASP is ten (0 - 9) images saved on your server and the following code:
  <%
  Dim fileObj, hitsFile, I, inStream, newHits, oldHits, outStream
  
  Set fileObj = Server.CreateObject("Scripting.FileSystemObject")
  hitsFile = Server.MapPath ("/main/sample") & "hits.txt"
  
  On Error Resume Next
  Set inStream = FileObject.OpenTextFile (hitsFile, 1, False )
  oldHits = Trim(inStream.ReadLine)
  newHits = oldHits + 1

  Set outStream = FileObject.CreateTextFile (hitsFile, True)
  outStream.WriteLine(newHits)
  
  inStream.Close
  outStream.Close
  Set inStream = Nothing
  Set outStream = Nothing
  %>

  <html>
  <head>
  <title>Graphic Counter</title>
  </head>
  <body>
  <%
  For I = 1 to Len(NewHits)
    Dim display, num
    num = Mid(newHits, I, 1)
    display = display & "<img src='../sample/digits/" & num & ".gif'>"
  Next
  Response.Write display
  %>
  </body>
  </html>
ASP : Reading Text Files 08 January 2001 at 00:00
  Dim fileName, fileStream, thisFile, newLine
  
  ' establish file name
  fileName = Server.MapPath("temp.txt")
  ' create file stream object and open fileSet 
  fileStream = CreateObject("Scripting.FileSystemObject")
  Set thisFile = fileStream.OpenTextFile(fileName, 1, False)
  
  ' loop through file, writing to page as you go
  Do While NOT thisFile.AtEndOfStream  
    newLine = thisFile.ReadLine  
    Response.Write newLine & "<br>"
  Loop
  
  ' clean up
  thisFile.Close
  Set fileStream = Nothing
  Set thisFile = Nothing
SQL Server : Retrieving a list of tables 08 January 2001 at 00:00
SELECT name FROM sysobjects WHERE xType = 'U' ORDER BY name
VB6 : Opening the user's default browser 08 January 2001 at 00:00
In the General Declarations section insert the following code:
  Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
    (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
    ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Then, to call the function, use:
  ShellExecute Me.hwnd, "open", "http://www.yourpage.com", vbNullString, vbNullString, 0
DOS : Ports Being Used 08 January 2001 at 00:00
  netstat -ar|more
To find out more, Telnet to the port on that machine.
SQL : Adding fields 08 January 2001 at 00:00
To add a single column to a table

  ALTER TABLE <tablename> ADD <newfield> <fieldtype>[(<fieldsize>)]

To add multiple columns to a table

ALTER TABLE <tablename>
  ADD (
      <newfield1> <fieldtype> DEFAULT NULL,
      <newfield2> <fieldtype> DEFAULT NULL,
      <newfield3> <fieldtype> DEFAULT NULL
      )
VB6 COM Callbacks 08 January 2001 at 00:00
COM components using asynchronous callbacks must provide an interface through which the component will make the callback. The client program must then create an object using the interface and pass it into a method of the component. When the component completes its processing, it calls a method of the object that was passed in to perform the notification.

1. A notification interface for validating an employee number (called EG.Notify) :

  Option Explicit
  
  Public Sub ValidateReturned(validated as Boolean)
  End Sub
2. The component actually performing the validation (called EG.Employee):
  Option Explicit
  Public objNotify As EG.Notify

  Public Sub ValidateEmployee(empID As Long, objClient As EG.Notify)
    Set objNotify = objClient
    Call DoValidation
  End Sub

  Private Sub DoValidation()
    ' do validation of employee here
    
    ' finished - call the client
    objNotify.ValidateReturned True
  End Sub
3. class module to implement the callback (called EmpNotifier):
  Option Explicit
  Implements EG.Notify

  Private Sub Notify_ValidateReturned(validated as Boolean)
    ' the process is complete
    If NOT validated Then
      MsgBox "The employee number could not be successfully validated."
    End If
  End Sub
4. Using the interface requires creating two objects - one which actual does the validation and one to handle the notification of the validation:
  Option Explicit
  Private objEmployee As New EG.Employee
  Private objNotify As New EmpNotifier

  Private Sub Form_Load()
    objEmployee.ValidateEmployee 123456, objNotify
  End Sub
Java Servlets Quickstart 08 January 2001 at 00:00
Getting servlets running on your machine isn't too clearly defined on the Sun site. Here's how to do it (assuming you have the JDK and JRE installed already and working on your machine):

  1. Download the JSWDK from the Sun site and extract to your default hard drive.
  2. Find and add the servlet.jar (probably in the lib directory under the JSWDK folder) file to your classpath.
  3. Run the startserver batch file in the JSWDK folder. The Java WebServer will now be running and ready to deal with requests.
  4. Open your default browser, and go to http://localhost:8080. This will be the default page for your Java WebServer.
  5. If the version you have has examples, click through to these to establish where the servlets are run from (otherwise just search the folder for files ending with ".class"). You can then place compiled servlets into this folder and call them via http://localhost:8080/<dir>/servlet/YourServletName
Reading/Writing INI Files with Visual Basic 6 08 January 2001 at 00:00
Although most settings can be stored in the registry these days, it is sometimes more practical to store settings in an INI file (e.g. you want to be able to manually go and change those settings regularly).

There are predefined functions in the Windows API to allow you to read and write properties to/from INI files:

  ' to write values to an INI file.
  Declare Function WritePrivateProfileString _
    Lib "kernel32" Alias "WritePrivateProfileStringA" _
    (ByVal lpApplicationname As String, ByVal _
    lpKeyName As Any, ByVal lsString As Any, _
    ByVal lplFilename As String) As Long
  
  ' to read values from an INI file
  Declare Function GetPrivateProfileString Lib _
    "kernel32" Alias "GetPrivateProfileStringA" _
    (ByVal lpApplicationname As String, ByVal _
    lpKeyName As String, ByVal lpDefault As _
    String, ByVal lpReturnedString As String, _
    ByVal nSize As Long, ByVal lpFileName As _
    String) As Long
For example, if you have the following INI file:
  [MyHeading]
  MyKey1=myValue1
  Dir=c:mydir
  File=hello.txt
You could read the value of the "File" key in the following way:
  Dim lngResult As Long
  Dim strFileName
  Dim strResult As String * 50
  strFileName = "C:MyIniFile.ini"
	
  lngResult = GetPrivateProfileString("MyHeading", _
    "File", strFileName, strResult, Len(strResult), _
    strFileName)

  If lngResult = 0 Then
    'An error has occurred
    Call MsgBox("An error has occurred", vbExclamation)
    Exit Sub
  Else
    MsgBox "The value is " & strResult
  End If
You could change the value of the same key in the following way:
  Dim lngResult As Long
  Dim strFileName
  strFileName = "C:MyIniFile.ini"
  lngResult = WritePrivateProfileString("MyHeading", "File", "NewValue", strFileName)

  If lngResult = 0 Then
    'An error has occurred
    Call MsgBox("An error has occurred", vbExclamation)
  Else
    MsgBox "The value has been changed"
  End If
Using the return value

The return value (in the example lngResult) specifies the length of the string that is being returned. A value of 0 means an error occurred, but if you want to use the string that is returned you need to do some work due to the fact that the string is the length specified (in the example 50). For example if you want to tell the user what was returned, you would code:

MsgBox Left(strResult, lngResult) & " is the result."
which would effectively get the exact value returned rather than the padded version.
Desktop links to your web app with CDF Files 08 January 2001 at 00:00

To allow users to place your web application on their desktops is fairly straightforward. This assumes that the user is running on a Microsoft Platform and has IE4+ installed - so it is probably only suitable for Intranets.

All you need to do is place a link on your site to a .CDF file. If the .CDF file is correctly formatted, the installation will take care of itself once the user clicks on the link. A CDF file is an XML subset, e.g.:

  <?XML VERSION="1.0"?>
  <CHANNEL>
    <ITEM HREF="http://yoursite/yourpage.htm">
      <TITLE>Your Unique Title</TITLE>
      <USAGE VALUE="DesktopComponent">
        <OPENAS VALUE="HTML"/>
        <WIDTH VALUE="510"/>
        <HEIGHT VALUE="95"/>
        <CANRESIZE VALUE="NO"/>
      </USAGE>
    </ITEM>
  </CHANNEL>
Halting Program Execution with VB6 08 January 2001 at 00:00
Say for example you want to perform batch updates, but only want to do 100 records every minute. If you're using a DLL or ActiveX EXE to do the job, the easiest way to halt program execution is to use the Windows API Sleep method. Just add the following declaration to a module in your project, and specify the number of seconds times by 1000 (to get milliseconds) that you want your program to sleep for in between updates.

Note: This call stops ALL the threads in your application. If you only want to pause the processing of a single thread, use the Wait() API function.

  Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
Setting up Microsoft SOAP Listeners for ASP 08 January 2001 at 00:00
This page provides brief instruction son how to set up the ASP and ISAPI listeners on a Microsoft web server for making public Web Services available.

ASP Listener

  1. Create a virtual off your default web site or new web site from where you will be offering your web services.
  2. Install the DLL you are exposing on the web server and register it.
  3. Register the rope.dll on the web server.
  4. Run the SDL Wizard to create the necessary files.
  5. Copy the file listener.asp to the web server.
  6. Place the generated ASP file and XML file whereever you want them to be available from. Ensure that the include reference to listener.asp in the ASP file points to the correct path to that file.
  7. The XML file holds the schema data and the ASP file has the function calls in it. Make sure the the reference to the ASP file in the XML file is correct.
  8. Make sure Anonymous Access is allowed through IIS to the folder(s) where the Web Services are exposed.

ISAPI Listener

  1. Run through the same steps as for the ASP file, except that use specify an ISAPI listener in the SDL Wizard, place the SOD file in the correct place.
  2. Edit the SOD file so that the path to the XML file is correct.
  3. Copy the file soapisapi.dll to the webserver but do not register it.
  4. Set up the virtual to map to the soapisapi.dll:
    • In Internet Services Manager, view the Properties for the virtual site that you want to enable the SOAP ISAPI Listener on. Go to the "Home Directory" tab and click the "Configuration..." button.
    • In the "Application Configuration" dialog, on the "App Mappings" tab, click the "Add" button to add the SOAP application mapping.
    • In the "Add/Edit Application Extension Mapping" dialog box, enter the following information:
      • Enter the path to SoapIsapi.dll as the "Executable."
      • Enter "sod" as the "Extension"
      • In the "Verbs" box, select "Limit to:" and enter "POST".
      • Make sure the "Script engine" check box is checked
      • Make sure the "Check that file exists" check box is checked
    • NB: IIS 5.0 will have a problem locating SOAPISAPI.dll if the path includes white space. Make sure you put the SOAPISAPI.dll into a directory that does not have white space in its path name.
ASP : Returning Recordsets with SOAP 08 January 2001 at 00:00

This page provides my implementation of returning recordsets with SOAP messaging. A more complete article is Returning ADO Recordsets with SOAP Messaging by Chris Dengler.

Recordset to be retrieved

A DLL on the web server took certain parameters and returned a recordset containg employee information. My web service offered the facility to retrieve this information in the form of a simple XML representation.

Schema Generated by the Wizard

The SDL wizard generated the following schema for the response with the return type defaulted to string:

  <element name='GetEmployeeResponse'>
    <type>
      <element name='return' type='dt:string'/>
    </type>
  </element>

Edited Schema
I adjusted the schema to my own structure so that the SOAPPackager on the client end knew that it was receiving XML rather than the string:

  <element name='GetEmployeeResponse'>
    <type>
      <element name='return' type='GetEmployeeStruct'/>
      <element name='pvarResults' type='dt:string'/>
      <element name='pvarErrors' type='dt:string'/>
    </type>
  </element>
  <element name='GetEmployeeStruct'>
    <type>
      <element name='RECORD' type='GetEmployeeRecStruct'/>
    </type>
  </element>
  <element name='GetEmployeeRecStruct'>
    <type>
      <element name='intEmpID' type='dt:integer'/>
      <element name='strUserName' type='dt:integer'/>
      <element name='strFirstName' type='dt:string'/>
      <element name='strSurname' type='dt:string'/>
      <element name='strEmail' type='dt:string'/>
     </type>
  </element>

Adjusted ASP Function
The ASP function was then adjusted to pass an ADO recordset into the DLL call as opposed to a string, and a simple XML representation of that database is returned by the web service.

  '____________________________________________________________________
  ' function used by the listener
  Public Function GetEmployee (ByVal plngUserID)
    Dim objGetEmployee
    Set objGetEmployee = Server.CreateObject("MyPackage.MyClass")
    Dim objRS		' record set object to pass to function
    ' create disconnected recordset
    Set objRS = Server.CreateObject("ADODB.Recordset")
    ' call function - function will return objRS as a disconnected recordset
    Call objGetEmployee.GetEmployee(plngUserID, objRS)
    ' convert the recordset into XML format and send back to client
    GetEmployee = GetXMLFromRS(objRS)
    ' clean up objects
    Set objRS = Nothing
    Set objGetEmployee = NOTHING
  End Function
  '____________________________________________________________________
  ' function used to convert the recordset to XML
  Function GetXMLFromRS(ByVal objRS)
    ' declare variables
    Dim strXML					' output XML string
    Dim objField				' fields in the record set
    Dim strFieldName		' name of the field
    Dim strFieldValue		' value of the current field in the current record
    ' create outer element RECORDSET
    strXML = "<RECORDSET>" & vbCrLf
    ' loop through the recordset, adding each record and values to string
    Do While NOT objRS.EOF
      ' add new RECORD element for each record
      strXML = strXML & vbTab & "<RECORD>" & vbCrLf
      ' loop through the fields and add each with value to xml string
      For Each objField In objRS.Fields
        strFieldName = objField.Name
        strFieldValue = CDATAIt(objRS(strFieldName))
        strXML = strXML & vbTab & vbTab & "<" & strFieldName & ">" _
        & strFieldValue & "</" & strFieldName & ">" & vbCrLf
      Next
      ' close RECORD element
      strXML = strXML & vbTab & "</RECORD>" & vbCrLf
      objRS.MoveNext
    Loop
    ' close outer element RECORDSET and return XML string
    strXML = strXML & "</RECORDSET>" & vbCrLf
    GetXMLFromRS = strXML
    ' GetXMLFromRS = "Test"
  End Function

  '____________________________________________________________________
  ' function to add cdata tags to XML information
  Function CDATAIt(ByVal strXMLVal)
	  CDATAIt = "<![CDATA[" & strXMLVal & "]]>"
  End Function

Client-side
The result returned is straight-forward XML, for example:

  <return>
    <RECORDSET>
      <RECORD>
        <EmployeeID><![CDATA[4]]></EmployeeID>
        <UserName><![CDATA[msalmon]]></UserName>
        <FirstName><![CDATA[Matt]]></FirstName>
        <LastName><![CDATA[Salmon]]></LastName>
        <Email><![CDATA[matt_salmon@yahoo.com]]></Email>
      </RECORD>
      <RECORD>
        <EmployeeID><![CDATA[4]]></EmployeeID>
        <UserName><![CDATA[example]]></UserName>
        <FirstName><![CDATA[Example]]></FirstName>
        <LastName><![CDATA[Test]]></LastName>
        <Email><![CDATA[example@examples.com]]></Email>
      </RECORD>
    </RECORDSET>
  </return>
C# : Simple Data Queries with the ADODataReader 08 January 2001 at 00:00
In order to retrieve data quickly and easily, a good method with C# and ADO+ is to use the ADODataReader object. In this example I grab browser statistics from a statistics table and write the results to the console.
  using System;
  using System.Data;
  using System.Data.ADO;

  ...

  // attempt to open a connection to the database, if fail exit
  ADOConnection connADO = null;
  try {
    connADO = new ADOConnection(strConn);
    connADO.Open();
  }
  catch (System.ArgumentException) {
    Console.WriteLine("Could not open connection - exitting.");
    Environment.Exit(0);
  }
  // build the sql string
  String sql = "SELECT Browser, COUNT(Browser) As Cnt FROM Statistics GROUP BY Browser";
  // create ADO DataReader and command objects
  ADODataReader reader = null;
  // execute the sql query and populate the reader
  ADOCommand adoCmd = new ADOCommand(sql, connADO);
  adoCmd.Execute(out reader);

  // loop through the returned contents and write to the console
  while (reader.Read()) {
    Console.WriteLine(reader["Browser"].ToString() + "---" + reader["Cnt"].ToString());
  }

  // close the connection to the database
  connADO.Close();
VB6 : HTTP Transfers 08 January 2001 at 00:00
The MSXML2 Library contains the class ServerXMLHTTP30 which can be used to send HTTP requests and posts over the web.

Example 1: Executing an ASP page on a remote web server

  Dim objNetRequest As MSXML2.ServerXMLHTTP30
  Dim strURL As String
  strURL = "http://remote.com/YourPage.asp?param1=value1"
    
  Set objNetRequest = New MSXML2.ServerXMLHTTP30
  With objNetRequest
    .open "GET", strURL, False
    .send ("")
    MsgBox .responseText
  End With
  Set objNetRequest = Nothing

Example 2: Posting a form to a remote page
  Dim objNetRequest As MSXML2.ServerXMLHTTP30
  Dim strURL As String
  strURL = "http://remote.com/YourPage.asp?param1=value1"
    
  Set objNetRequest = New MSXML2.ServerXMLHTTP30
  With objNetRequest

    .open "POST", strURL, False
    .setRequestHeader "Content-Type", "text/xml"
    .send ("some text to be posted")
    MsgBox .responseText
  End With
  Set objNetRequest = Nothing
DOS : Mapping a Drive 08 January 2001 at 00:00
Syntax: net use * <ipaddress><drive>$ /USER:<username>

E.g.: net use * 10.83.106.157c$ /USER:msalmon
Storing data in INI files with VB6 08 January 2001 at 00:00
Although most settings can be stored in the registry these days, it is sometimes more practical to store settings in an INI file (e.g. you want to be able to manually go and change those settings regularly).

There are predefined functions in the Windows API to allow you to read and write properties to/from INI files:

  ' to write values to an INI file.
  Declare Function WritePrivateProfileString _
    Lib "kernel32" Alias "WritePrivateProfileStringA" _
    (ByVal lpApplicationname As String, ByVal _
    lpKeyName As Any, ByVal lsString As Any, _
    ByVal lplFilename As String) As Long
  
  ' to read values from an INI file
  Declare Function GetPrivateProfileString Lib _
    "kernel32" Alias "GetPrivateProfileStringA" _
    (ByVal lpApplicationname As String, ByVal _
    lpKeyName As String, ByVal lpDefault As _
    String, ByVal lpReturnedString As String, _
    ByVal nSize As Long, ByVal lpFileName As _
    String) As Long
For example, if you have the following INI file:
  [MyHeading]
  MyKey1=myValue1
  Dir=c:mydir
  File=hello.txt
You could read the value of the "File" key in the following way:
  Dim lngResult As Long
  Dim strFileName
  Dim strResult As String * 50
  strFileName = "C:MyIniFile.ini"
	
  lngResult = GetPrivateProfileString("MyHeading", _
    "File", strFileName, strResult, Len(strResult), _
    strFileName)

  If lngResult = 0 Then
    'An error has occurred
    Call MsgBox("An error has occurred", vbExclamation)
    Exit Sub
  Else
    MsgBox "The value is " & strResult
  End If
You could change the value of the same key in the following way:
  Dim lngResult As Long
  Dim strFileName
  strFileName = "C:MyIniFile.ini"
  lngResult = WritePrivateProfileString("MyHeading", "File", "NewValue", strFileName)

  If lngResult = 0 Then
    'An error has occurred
    Call MsgBox("An error has occurred", vbExclamation)
  Else
    MsgBox "The value has been changed"
  End If

Using the return value

The return value (in the example lngResult) specifies the length of the string that is being returned. A value of 0 means an error occurred, but if you want to use the string that is returned you need to do some work due to the fact that the string is the length specified (in the example 50). For example if you want to tell the user what was returned, you would code:
MsgBox Left(strResult, lngResult) & " is the result."
which would effectively get the exact value returned rather than the padded version.
Returning recordsets in XML format with SOAP 08 January 2001 at 00:00
This post provides my implementation of returning recordsets with SOAP messaging. A more complete article is Returning ADO Recordsets with SOAP Messaging by Chris Dengler.

Recordset to be retrieved

A DLL on the web server took certain parameters and returned a recordset containg employee information. My web service offered the facility to retrieve this information in the form of a simple XML representation.

Schema Generated by the Wizard
The SDL wizard generated the following schema for the response with the return type defaulted to string:

  <element name='GetEmployeeResponse'>
    <type>
      <element name='return' type='dt:string'/>
    </type>
  </element>

Edited Schema

I adjusted the schema to my own structure so that the SOAPPackager on the client end knew that it was receiving XML rather than the string:
  <element name='GetEmployeeResponse'>
    <type>
      <element name='return' type='GetEmployeeStruct'/>
      <element name='pvarResults' type='dt:string'/>
      <element name='pvarErrors' type='dt:string'/>
    </type>
  </element>
  <element name='GetEmployeeStruct'>
    <type>
      <element name='RECORD' type='GetEmployeeRecStruct'/>
    </type>
  </element>
  <element name='GetEmployeeRecStruct'>
    <type>
      <element name='intEmpID' type='dt:integer'/>
      <element name='strUserName' type='dt:integer'/>
      <element name='strFirstName' type='dt:string'/>
      <element name='strSurname' type='dt:string'/>
      <element name='strEmail' type='dt:string'/>
     </type>
  </element>

Adjusted ASP Function

The ASP function was then adjusted to pass an ADO recordset into the DLL call as opposed to a string, and a simple XML representation of that database is returned by the web service.
  '____________________________________________________________________
  ' function used by the listener
  Public Function GetEmployee (ByVal plngUserID)
    Dim objGetEmployee
    Set objGetEmployee = Server.CreateObject("MyPackage.MyClass")
    Dim objRS		' record set object to pass to function
    ' create disconnected recordset
    Set objRS = Server.CreateObject("ADODB.Recordset")
    ' call function - function will return objRS as a disconnected recordset
    Call objGetEmployee.GetEmployee(plngUserID, objRS)
    ' convert the recordset into XML format and send back to client
    GetEmployee = GetXMLFromRS(objRS)
    ' clean up objects
    Set objRS = Nothing
    Set objGetEmployee = NOTHING
  End Function
  '____________________________________________________________________
  ' function used to convert the recordset to XML
  Function GetXMLFromRS(ByVal objRS)
    ' declare variables
    Dim strXML					' output XML string
    Dim objField				' fields in the record set
    Dim strFieldName		' name of the field
    Dim strFieldValue		' value of the current field in the current record
    ' create outer element RECORDSET
    strXML = "<RECORDSET>" & vbCrLf
    ' loop through the recordset, adding each record and values to string
    Do While NOT objRS.EOF
      ' add new RECORD element for each record
      strXML = strXML & vbTab & "<RECORD>" & vbCrLf
      ' loop through the fields and add each with value to xml string
      For Each objField In objRS.Fields
        strFieldName = objField.Name
        strFieldValue = CDATAIt(objRS(strFieldName))
        strXML = strXML & vbTab & vbTab & "<" & strFieldName & ">" _
        & strFieldValue & "</" & strFieldName & ">" & vbCrLf
      Next
      ' close RECORD element
      strXML = strXML & vbTab & "</RECORD>" & vbCrLf
      objRS.MoveNext
    Loop
    ' close outer element RECORDSET and return XML string
    strXML = strXML & "</RECORDSET>" & vbCrLf
    GetXMLFromRS = strXML
    ' GetXMLFromRS = "Test"
  End Function

  '____________________________________________________________________
  ' function to add cdata tags to XML information
  Function CDATAIt(ByVal strXMLVal)
	  CDATAIt = "<![CDATA[" & strXMLVal & "]]>"
  End Function

Client-side

The result returned is straight-forward XML, for example:
  <return>
    <RECORDSET>
      <RECORD>
        <EmployeeID><![CDATA[4]]></EmployeeID>
        <UserName><![CDATA[msalmon]]></UserName>
        <FirstName><![CDATA[Matt]]></FirstName>
        <LastName><![CDATA[Salmon]]></LastName>
        <Email><![CDATA[matt_salmon@yahoo.com]]></Email>
      </RECORD>
      <RECORD>
        <EmployeeID><![CDATA[4]]></EmployeeID>
        <UserName><![CDATA[example]]></UserName>
        <FirstName><![CDATA[Example]]></FirstName>
        <LastName><![CDATA[Test]]></LastName>
        <Email><![CDATA[example@examples.com]]></Email>
      </RECORD>
    </RECORDSET>
  </return>
Setting up the ASP and ISAPI SOAP Listeners for Microsoft's ROPE implementation using the SDL Wizard 08 January 2001 at 00:00
This page provides brief instruction son how to set up the ASP and ISAPI listeners on a Microsoft web server for making public Web Services available.

ASP Listener

  1. Create a virtual off your default web site or new web site from where you will be offering your web services.
  2. Install the DLL you are exposing on the web server and register it.
  3. Register the rope.dll on the web server.
  4. Run the SDL Wizard to create the necessary files.
  5. Copy the file listener.asp to the web server.
  6. Place the generated ASP file and XML file whereever you want them to be available from. Ensure that the include reference to listener.asp in the ASP file points to the correct path to that file.
  7. The XML file holds the schema data and the ASP file has the function calls in it. Make sure the the reference to the ASP file in the XML file is correct.
  8. Make sure Anonymous Access is allowed through IIS to the folder(s) where the Web Services are exposed.

ISAPI Listener

  1. Run through the same steps as for the ASP file, except that use specify an ISAPI listener in the SDL Wizard, place the SOD file in the correct place.
  2. Edit the SOD file so that the path to the XML file is correct.
  3. Copy the file soapisapi.dll to the webserver but do not register it.
  4. Set up the virtual to map to the soapisapi.dll:
    • In Internet Services Manager, view the Properties for the virtual site that you want to enable the SOAP ISAPI Listener on. Go to the "Home Directory" tab and click the "Configuration..." button.
    • In the "Application Configuration" dialog, on the "App Mappings" tab, click the "Add" button to add the SOAP application mapping.
    • In the "Add/Edit Application Extension Mapping" dialog box, enter the following information:
      • Enter the path to SoapIsapi.dll as the "Executable."
      • Enter "sod" as the "Extension"
      • In the "Verbs" box, select "Limit to:" and enter "POST".
      • Make sure the "Script engine" check box is checked
      • Make sure the "Check that file exists" check box is checked
    • NB: IIS 5.0 will have a problem locating SOAPISAPI.dll if the path includes white space. Make sure you put the SOAPISAPI.dll into a directory that does not have white space in its path name.
Retrieving data with the ADODataReader 08 January 2001 at 00:00
In order to retrieve data quickly and easily, a good method with C# and ADO+ is to use the ADODataReader object. In this example I grab browser statistics from a statistics table and write the results to the console.
  using System;
  using System.Data;
  using System.Data.ADO;

  ...

  // attempt to open a connection to the database, if fail exit
  ADOConnection connADO = null;
  try {
    connADO = new ADOConnection(strConn);
    connADO.Open();
  }
  catch (System.ArgumentException) {
    Console.WriteLine("Could not open connection - exitting.");
    Environment.Exit(0);
  }
  // build the sql string
  String sql = "SELECT Browser, COUNT(Browser) As Cnt FROM Statistics GROUP BY Browser";
  // create ADO DataReader and command objects
  ADODataReader reader = null;
  // execute the sql query and populate the reader
  ADOCommand adoCmd = new ADOCommand(sql, connADO);
  adoCmd.Execute(out reader);

  // loop through the returned contents and write to the console
  while (reader.Read()) {
    Console.WriteLine(reader["Browser"].ToString() + "---" + reader["Cnt"].ToString());
  }

  // close the connection to the database
  connADO.Close();
Send and receive data over HTTP using the Microsoft Internet Transfer Control 08 January 2001 at 00:00
The following is an example of submitting credit card validation details:
  Dim inetTransfer As InetCtlsObjects.Inet
  Set inetTransfer = New InetCtlsObjects.Inet
  Dim strPostText As String
  Dim strPostHeader As String
  
' build up the text that will be posted to the authentication site
  strPostText = "VMSMerchantID=" & VMSMerchantID & _
    "&SSMerchantID=" & SSMerchantID & _
    "&VMMCMerchantID=" & VMMCMerchantID & _
    "&AttemptNum=" & AttemptNum & _
    "&CurrencyCode=" & CurrencyCode & _
    "&CountryCode=" & CountryCode & _
    "&RetOKAddress=" & objUtil.URLEncode(RetOKAddress, DEF_CODE_PAGE) & _
    "&RetNotOKAddress=" & objUtil.URLEncode(RetNotOKAddress, DEF_CODE_PAGE) & _
    "&MessageType=" & MessageType & _
    "&Amount=" & Amount & _
    "&CardType=" & CardType & _
    "&CardNumber=" & objUtil.URLEncode(CardNumber, DEF_CODE_PAGE) & _
    "&IssueNumber=" & IssueNumber & _
    "&ExpMonth=" & ExpMonth & _
    "&ExpYear=" & ExpYear & _
    "&StartMonth=" & StartMonth & _
    "&StartYear=" & StartYear
  ' add the form encoded header to the post so that the recipient sees the data as
  ' coming from a submitted form
  strPostHeader = "Content-Type: application/x-www-form-urlencoded" & vbCrLf
  ' use transfer object to execute the url
  inetTransfer.Execute AuthURL, "POST", strPostText, strPostHeader
  ' wait until the authorisation site returns an answer
  Do Until inetTransfer.StillExecuting = False
    DoEvents
  Loop
  ' return the code - this will be a zero-length string if the card is authorised
  Authenticate = inetTransfer.GetChunk(1024, icString)
  Set inetTransfer = Nothing
Sending HTTP Requests using the MSXML2 object 08 January 2001 at 00:00
The MSXML2 Library contains the class ServerXMLHTTP30 which can be used to send HTTP requests and posts over the web.

Example 1: Executing an ASP page on a remote web server

  Dim objNetRequest As MSXML2.ServerXMLHTTP30
  Dim strURL As String
  strURL = "http://remote.com/YourPage.asp?param1=value1"
    
  Set objNetRequest = New MSXML2.ServerXMLHTTP30
  With objNetRequest
    .open "GET", strURL, False
    .send ("")
    MsgBox .responseText
  End With
  Set objNetRequest = Nothing

Example 2: Posting a form to a remote page

  Dim objNetRequest As MSXML2.ServerXMLHTTP30
  Dim strURL As String
  strURL = "http://remote.com/YourPage.asp?param1=value1"
    
  Set objNetRequest = New MSXML2.ServerXMLHTTP30
  With objNetRequest

    .open "POST", strURL, False
    .setRequestHeader "Content-Type", "text/xml"
    .send ("some text to be posted")
    MsgBox .responseText
  End With
  Set objNetRequest = Nothing
Mapping a drive from the command line in DOS 08 January 2001 at 00:00
Syntax: net use * <ipaddress>\<drive>$ /USER:<username>

E.g.: net use * 10.83.106.157\c$ /USER:msalmon
Input and output parameters with SQL Server stored procedures 08 January 2001 at 00:00

You can use parameters to pass a value into a stored procedure, or to return a value from a stored procedure to a calling program. You can have up to 1024 parameters in a stored procedure.

Parameters can be given default values. The default value can be a constant value or NULL. You do not need to pass a parameter a value if a default is specified.

Example:

  CREATE PROCEDURE MyProcedure
    (
    @Name varchar(200),
    @Age int,
    @Year int = 2000,     /* default of 2000 specified */
    @ParticipantID int OUTPUT
    )
  AS
    SELECT @retval = 0

    INSERT INTO Participants
      (Name, Age, Year, DateEntered)
    VALUES
      (@Name, @Age, @Year, GetDate())

    // Give return variable value of error
    SELECT @retval = @@ERROR    

    // Return the new identity value
    SELECT @ParticipantID = @@IDENTITY
    return