PRB: Implements Keyword Fails In VB DLL Called From ASP

ID: Q188716


The information in this article applies to:


SYMPTOMS

When calling a server side ActiveX component from an Active Server Pages (ASP) page that was written in Visual Basic 6.0 and uses the "Implements" keyword to get implementation inheritance between classes, the object does not expose the implemented methods as part of the interface. When you assign the derived object back to a base object, ASP will report the following error:

Microsoft VBScript runtime error '800a01b6' Object doesn't support this property or method.


CAUSE

VBScript is late-bound and can only QueryInterface for IDispatch, which simply returns the default IDispatch interface for the object. To get to an implemented interface you must QueryInterface for a specific interface. This is possible in Visual Basic for Applications, Visual Basic 4.0, and Visual Basic 5.0 because you can early-bind to type information and dimension object variables that expect a specific interface. When this is done Visual Basic will QueryInterface for an interface pointer of only this type in the variable. You will have the same problem in Visual Basic if you dimension the variables as Variants because Visual Basic will not save a specific interface and will QueryInterface for IDispatch, just like VBScript.


RESOLUTION

Visual Basic does not support inheritance, but there are workarounds for the problem. Look in the MORE INFORMATION section for details.


STATUS

This behavior is by design.


MORE INFORMATION

The following sample demonstrates the differences between how Visual Basic 6.0 and Active Server Pages (ASP) handle inheritance. Following are two workarounds showing how to simulate inheritance for ASP without the use of Microsoft Transaction Server (MTS). Finally, there is a workaround to simulate inheritance for MTS.

This example creates two classes. The first class, CPerson, supports the FirstName and the LastName method. The second class, CEmployee, implements CPerson and has a method GetName. From Visual Basic 6.0 the code sample works with all methods available, but from an Active Server Page, the FirstName and LastName methods are not available.

  1. Using Visual Basic 6.0, create a new ActiveX DLL.


  2. This DLL will have two classes, CPerson, and CEmployee.


  3. Name one class CPerson and copy and paste in the following code:
    
         ' Person class
          Option Explicit
    
          Public Property Get FirstName() As String
          End Property
    
          Public Property Get LastName() As String
          End Property
    
          Public Property Let LastName(sLastName As String)
          End Property
    
          Public Property Let FirstName(sFirstName As String)
          End Property 


  4. On the Project menu, click Add Class Module. On the New tab, select Class Module and click Open.


  5. Name the other class CEmployee, and cut and paste in the following code:
    
          ' Employee class
          Option Explicit
          Implements CPerson
          Private m_sFirstName As String
          Private m_sLastName As String
    
          Public Function GetEmployeeName() As String
             GetEmployeeName = m_sFirstName & " " & m_sLastName
          End Function
    
          Private Property Let CPerson_FirstName(RHS As String)
             m_sFirstName = RHS
          End Property
    
          Private Property Get CPerson_FirstName() As String
             CPerson_FirstName = m_sFirstName
          End Property
    
          Private Property Let CPerson_LastName(RHS As String)
             m_sLastName = RHS
          End Property
    
          Private Property Get CPerson_LastName() As String
             CPerson_LastName = m_sLastName
          End Property 


  6. Name the project People. On the File menu, click Make DLL. This will create the DLL and Register it for use.


You can test this DLL from a standard executable only if you do not wish to use MTS. Now you need to create a new standard executable using Visual Basic 6 to test the DLL you just created.

  1. Save and Close the People.dll project.


  2. From the File menu, click New Project and select Standard EXE.


  3. Add a reference to the People.dll by going to the Project menu and select References.


  4. Select the People check box, and click OK.




Add the following code to the project:

      Private Sub Form_Load()
         Dim oPerson  As People.CPerson
         Dim oEmp      As People.CEmployee
         Set oEmp = CreateObject("People.CEmployee")
         Set oPerson = oEmp
         oPerson.FirstName = "Some"
         oPerson.LastName = "Body"
         Form1.Hide
         MsgBox oEmp.GetEmployeeName
      End Sub 
Run the code. You should see a Message Box that displays the following:

   Some Body 
This is the behavior you would like to get from ASP but cannot. Use the following steps to see how ASP handles the People.dll:

  1. Create an ASP page.


  2. Copy and paste the code listed below into it, and save it as a new ASP page.
    
        <%
             Dim oPerson
             Dim oEmp
             Set oEmp = Server.CreateObject("People.CEmployee")
             Set oPerson = oEmp
             oPerson.FirstName = "Some"
             oPerson.LastName = "Body"
             Response.Write oEmp.GetEmployeeName
         %> 


  3. Place it on a running web server, and then open the ASP page using your Web browser.


You will receive an error similar to this:

Microsoft VBScript runtime error '800a01b6' Object doesn't support this property or method: 'FirstName' /xxx.asp, line 6


Following are possible workarounds for this problem.

Workaround #1

  1. Add the following public method to the People.dll in the CEmployee class:
    
          Public Property Get Person() As CPerson
           Set Person = Me
          End Property 


  2. Remake the People.dll if you get errors (see the note below).


  3. Modify the ASP sample as in the following:
    
          <%
             Dim oEmp
             Dim oPerson
             Set oEmp = Server.CreateObject("People.CEmployee")
             Set oPerson = oEmp.Person
             Response.Write TypeName (oPerson) & "<BR>"
             oPerson.FirstName = "Some"
             oPerson.LastName = "Body"
             Response.write oEmp.GetEmployeeName
          %> 


  4. Execute the modified ASP sample, and you should see the following:
    
       CEmployee
       Some Body 
    Where CEmployee is the typename returned from the oPerson object.


Workaround #2

You can simulate inheritance on your own objects by adding the following paired public methods to the sample code in the CEmployee class. This will treat your object as both an Employee and a Person:


   Public Property Get FirstName() As String
      FirstName = CPerson_FirstName
   End Property
   
   Public Property Let FirstName(RHS As String)
      m_sFirstName = RHS
   End Property
   
   Public Property Get LastName() As String
      LastName = CPerson_LastName
   End Property
   
   Public Property Let LastName(RHS As String)
      m_sLastName = RHS
   End Property 


NOTE: When you remake the People.dll, you will be denied access until you stop and start the Web service so the existing DLL can be unloaded from memory. To completely stop the Web service, go to the Control Panel and double-click Settings. Click the IISADMIN service and select Stop.

A dialog box appears showing services dependent on the IISADMIN service that will be also stopped as a result of stopping the IISADMIN service. The dependencies should include the World Wide Web publishing service. Allow all the dependent services to be stopped. To Restart the Web service, select the World Wide Web publishing service, and click the Start button. This will cause the IISADMIN service to be restarted, but none of the IISADMIN service dependencies. You can restart any stopped services using the services applet.

You will also need to modify the Active Server Page sample to look like this:

   <%
      Dim oEmp
      Set oEmp = Server.CreateObject("People.CEmployee")
      oEmp.FirstName = "Some"
      oEmp.LastName = "Body"
      Response.write oEmp.GetEmployeeName
   %> 
Open the modified ASP page in your Web browser. You should see the following:

Some Body

MTS Solution for Workaround #1

In order to make use of workaround #1 under MTS, make the following changes:
  1. Recycle the web server first. From a command prompt type:
    
       net stop iisadmin /y
       net start w3svc 


  2. In the Visual Basic project add the following reference by selecting References from the Project menu:
    
       Microsoft Transaction Server Type Library 


  3. Modify the CEmployee class to reflect the following changes in the public Property Get Person:
    
       Public Property Get Person() As CPerson
         Set Person = SafeRef(Me)
       End Property 


  4. For both classes set the MTSTransactionMode property to:
    
       '1 - NoTransactions' 
    NOTE: This samples uses '1 - NoTransactions', but it should work similarly for the other MTSTransactionMode properties.


  5. Build your project by selecting Make Project Group from the File menu.


  6. Create a new empty MTS Library Package and add the newly built DLL.

    NOTE: Make sure you've set the Package Activation Type to Library Package. It will not work if the Package Activation Type is set to Server Package because of the marshalling that will take place between the Web application and the MTS Server Package.


  7. Request the ASP page (see Workaround #1, Step 3) from a browser, and you should see the following:
    
       CEmployee
       Some Body 
    where CEmployee is the typename returned from the oPerson object.



REFERENCES

For more information on using the Implements feature of Visual Basic, use the Visual Basic Help, and search on the keyword "Implements."

For additional information, click the article number below to view the article in the Microsoft Knowledge Base:

Q223406 HOWTO: Create an Empty MTS Package to Add Components for ASP

Additional query words: kbnokeyword


Keywords          : kbASP kbCOMt kbCtrl kbMTS200 kbVBp500 kbVBp600 kbVisID kbGrpASP 
Version           : winnt:2.0
Platform          : winnt 
Issue type        : kbprb 

Last Reviewed: July 28, 1999