PRB: Implements Keyword Fails In VB DLL Called From ASP
ID: Q188716
|
The information in this article applies to:
-
Active Server Pages
-
Microsoft Visual Basic Standard, Professional, and Enterprise Editions, 32-bit only, for Windows, versions 5.0, 5.0 SP1, 5.0 SP2, 5.0 SP3, 6.0
-
Microsoft Transaction Server 2.0
-
Microsoft Internet Information Server versions 4.0, 5.0
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.
- 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
- 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.
- Save and Close the People.dll project.
- From the File menu, click New Project and select Standard EXE.
-
Add a reference to the People.dll by going to the Project menu and select References.
- 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:
- Create an ASP page.
- 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
%>
- 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
- Add the following public method to the People.dll in the CEmployee class:
Public Property Get Person() As CPerson
Set Person = Me
End Property
- Remake the People.dll if you get errors (see the note below).
- 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
%>
- 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:
- Recycle the web server first. From a command prompt type:
net stop iisadmin /y
net start w3svc
- In the Visual Basic project add the following reference by selecting References from the Project menu:
Microsoft Transaction Server Type Library
- 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
- 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.
- Build your project by selecting Make Project Group from the File menu.
- 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.
- 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 : kberrmsg kbASP kbCOMt kbCtrl kbMTS200 kbVBp500 kbVBp600 kbVisID kbGrpASP kbCodeSnippet kbiis400 kbiis500
Version : WINDOWS:5.0,5.0 SP1,5.0 SP2,5.0 SP3,6.0; winnt:2.0,4.0,5.0
Platform : WINDOWS winnt
Issue type : kbprb