Microsoft KB Archive/188716

= PRB: Implements Keyword Fails in Visual Basic DLL Called from ASP =

Article ID: 188716

Article Last Modified on 3/7/2005

-

APPLIES TO


 * Microsoft Active Server Pages 4.0
 * Microsoft Transaction Services 2.0
 * Microsoft Internet Information Server 4.0
 * Microsoft Internet Information Services 5.0

-



This article was previously published under Q188716



SYMPTOMS
When calling a server side ActiveX component written in Visual Basic 6.0 from an Active Server Pages (ASP) page, using the "Implements" keyword to get implementation inheritance between classes, ASP will report the following error:

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



CAUSE
The object does not expose implemented methods as part of the interface.

To get to an implemented interface you must QueryInterface for a specific interface. This is possible in Visual Basic for Applications and Visual Basic 4.0 or higher, 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.

VBScript is late-bound and can only QueryInterface for IDispatch, which simly returns the default IDispatch interface for the object.

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.

 Using Visual Basic 6.0, create a new ActiveX DLL. This DLL will have two classes, CPerson, and CEmployee.  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  On the Project menu, click Add Class Module. On the New tab, select Class Module and click Open.  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 </li> Name the project People. On the File menu, click Make DLL. This will create the DLL and Register it for use.</li></ol>

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: <pre class="fixed_text">  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:

<ol> Create an ASP page.</li>  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 %>                   </li> Place it on a running web server, and then open the ASP page using your Web browser.</li></ol>

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
<ol>  Add the following public method to the People.dll in the CEmployee class: Public Property Get Person As CPerson Set Person = Me     End Property </li> Remake the People.dll if you get errors (see the note below).</li>  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 %>

</li>  Execute the modified ASP sample, and you should see the following: <pre class="fixed_text">  CEmployee Some Body Where CEmployee is the typename returned from the oPerson object. </li></ol>

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: <ol>  Recycle the web server first. From a command prompt type: <pre class="fixed_text">  net stop iisadmin /y net start w3svc </li>  In the Visual Basic project, add the following reference by selecting References from the Project menu: <pre class="fixed_text">  Microsoft Transaction Server Type Library for IIS 4.0 or Com + Services Type Library for IIS 5.0 </li>  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 </li>  For both classes set the MTSTransactionMode property to: <pre class="fixed_text">  '1 - NoTransactions' NOTE: This samples uses '1 - NoTransactions', but it should work similarly for the other MTSTransactionMode properties. </li> Build your project by selecting Make Project Group from the File menu.</li> Create a new empty MTS Library Package in IIS 4.0 or a Com+ Application in IIS 5.0, 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.</li>  Request the ASP page (see Workaround #1, Step 3) from a browser, and you should see the following: <pre class="fixed_text">  CEmployee Some Body where CEmployee is the typename returned from the oPerson object. </li></ol>

<div class="references_section">