PRB: CallByName Fails to Return the Correct Error Information
ID: Q194418
|
The information in this article applies to:
-
Microsoft Visual Basic Learning, Professional, and Enterprise Editions for Windows, version 6.0
SYMPTOMS
When an error is raised in a procedure of an ActiveX server and the
procedure is called with the CallByName() function from a client, the
client always gets error 440 regardless of the original error number being
raised.
RESOLUTION
See the MORE INFORMATION section of this article for a workaround.
STATUS
This behavior is by design.
MORE INFORMATION
The following sample projects demonstrate the problem and a workaround:
Create a Test Server
- Start Visual Basic and create a new ActiveX DLL project. Class1 is
created by default.
- Rename the project TestSvr.
- Add the following code to Class1:
Option Explicit
Private strObjName As String
Private Sub Class_Initialize()
strObjName = "Default Name"
End Sub
Public Property Get ObjectName() As String
ObjectName = strObjName
End Property
Public Property Let ObjectName(s As String)
strObjName = s
End Property
Public Property Get ObjectNameWithErr() As String
ObjectNameWithErr = strObjName
' User-defined error numbers should be between 513 and 65535
' plus vbObjectError Numbers below 513 are reserved.
' The vbObjectError is equivalent to FACILITY_ITF (&H80040000).
' You need to add this constant because everything made public
' in VB is on an interface.
' We are arbitrarily choosing 1000 below.
Err.Raise vbObjectError + 1000, _
"Error in " & App.EXEName & ".ObjectNameWithErr", _
"User defined error"
End Property
Public Property Let ObjectNameWithErr(s As String)
strObjName = s
Err.Raise vbObjectError + 1000, _
"Error in " & App.EXEName & ".ObjectNameWithErr", _
"User defined error"
End Property
Public Function ConcatString _
(s1 As String, s2 As String) As String
ConcatString = s1 & s2
End Function
Public Function ConcatStringWithErr _
(s1 As String, s2 As String) As String
ConcatStringWithErr = s1 & s2
Err.Raise vbObjectError + 1000, _
"Error in " & App.EXEName & ".ConcatStringWithErr", _
"User defined error"
End Function
- Compile the project. If you want to run the server in the IDE, select
Options from the Tools menu, and select "Break on Unhandled Errors"
under "Error Trapping" on the General Tab.
Create a Test Client
- Create a new Standard EXE project in Microsoft Visual Basic. Form1 is
created by default.
- Select References from the Project menu, and add "TypeLib Information"
(TLBINF32.DLL) to the reference list.
- Add a ComboBox, two CommandButtons, a Frame, and two OptionButtons
inside the frame to Form1.
- Add the following code to Form1's code window:
Option Explicit
Private objServer As Object
Private IFaceInfo As TLI.InterfaceInfo
Private Sub Command1_Click()
' This subroutine demonstrates the problem with returned errors
' when CallByName() is used.
On Error GoTo Command1Handler
Select Case Combo1.ListIndex
Case 0, 2
If Option1.Value Then
Call CallByName(objServer, _
Combo1.Text, _
VbLet, _
App.EXEName)
Else
MsgBox CallByName(objServer, _
Combo1.Text, _
VbGet)
End If
Case 1, 3
MsgBox CallByName(objServer, _
Combo1.Text, _
VbMethod, _
"Parameter1", _
"Parameter2")
End Select
Exit Sub
Command1Handler:
MsgBox Err.Number & vbCrLf & Err.Source & vbCrLf & Err.Description
End Sub
Private Sub Command2_Click()
' This subroutine demonstrates a workaround for the problem
' shown in the Command1_Click subroutine.
Dim sResults As TLI.SearchResults
Dim sItem As TLI.SearchItem
On Error GoTo Command2Handler
Set IFaceInfo = TLI.InterfaceInfoFromObject(objServer)
Set sResults = IFaceInfo.Members.GetFilteredMembers
With sResults
For Each sItem In sResults
If sItem.Name = Combo1.Text Then
Select Case Combo1.ListIndex
Case 0, 2
If Option1.Value = True Then
Call TLI.InvokeHook(objServer, _
sItem.MemberId, _
INVOKE_PROPERTYPUT, _
App.EXEName)
Else
MsgBox TLI.InvokeHook(objServer, _
sItem.MemberId, _
INVOKE_PROPERTYGET)
End If
Case 1, 3
Dim vArg(1) As Variant
vArg(0) = "Parameter2": vArg(1) = "Parameter1"
' The variant array elements are passed in reverse
' order, that is the 0th element first
MsgBox TLI.InvokeHookArray(objServer, _
sItem.MemberId, _
INVOKE_FUNC, _
vArg)
End Select
End If
Next
End With
Exit Sub
Command2Handler:
' Please note that the error number will be the raw error number
' raised in the server.
' To get the equivalent error number of VB, subtract vbObjectError
' from Err.Number.
MsgBox (Err.Number - vbObjectError) & vbCrLf & Err.Source & _
vbCrLf & Err.Description
End Sub
Private Sub Form_Load()
Command1.Caption = "&CallByName"
Command2.Caption = "&InvokeHook"
Option1.Caption = "Property &Let"
Option2.Value = True
Option2.Caption = "Property &Get"
With Combo1
.AddItem "ObjectName"
.AddItem "ConcatString"
.AddItem "ObjectNameWithErr"
.AddItem "ConcatStringWithErr"
.ListIndex = 0
End With
Set objServer = CreateObject("TestSvr.Class1")
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set objServer = Nothing
End Sub
- Run the project.
When you access the ObjectNameWithErr property or call the
ConcatStringWithErr function using CallByName(), the error object you
received has the following error information regardless of the error
raised in the server:
Number: 440
Source: Name of the application
Description: Automation error
To get the correct error object, use the InvokeHook set of functions as
shown in the Click event of Command2.
REFERENCES
Additional information on TLBINF32.DLL can be found in the article "Inspect
Dynamic Objects" by Matthew Curland in the November 1998 issue of Visual
Basic Programmer's Journal, pages 120-124
For additional information, please see the following article in the
Microsoft Knowledge Base:
Q172988
: FILE: Programmatically Retrieve the Members of a DLL Class
Additional query words:
kbDSupport kbVBp kbdss kbNoKeyWord
Keywords : kbGrpVB
Version : WINDOWS:6.0
Platform : WINDOWS
Issue type : kbprb
|