Late Binding Return Value Weirdness

T

Tim Roberts

I've been doing COM a long time, but I've just come across a behavior
with late binding that surprises me. VB and VBS are not my normal
milieux, so I'm hoping someone can point me to a document that
describes this.

Here's the setup. We have a COM server, written in Python. For
completeness, here is the script:

----- testserver.py -----
import pythoncom

class TestSrv(object):

_reg_clsid_ = '{C7B89AAC-99B7-48A1-8088-D77A867CBB0C}'
_reg_desc_ = 'TestSrv COM+ Server'
_reg_progid_ = 'TestSrv.Application'
_reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER
_public_methods_ = ['SetValue', 'GetValue']

def __init__(self):
self.ABC = ''

def SetValue(self, what, newval):
if what == 'ABC':
self.ABC = newval

def GetValue(self, what):
if what == 'ABC':
return self.ABC

if __name__=='__main__':
import win32com.server.register
win32com.server.register.UseCommandLine(TestSrv, debug=0)
----- end -----

This server has two methods. Even without knowing Python, you can see
that neither method alters its parameters. They touch internal state
only.

We call this from a VB module:

----- Module1.vb -----
Module Module1
Sub Main()
Dim testSrvObj As Object
Dim what As String, value As String, retvalue As String
testSrvObj = CreateObject("TestSrv.Application")

value = "ABCValue"
what = "ABC"

Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
testSrvObj.SetValue(what, value)
Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
testSrvObj.SetValue("ABC", value)
Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
retvalue = testSrvObj.GetValue("ABC")
Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
Console.ReadKey()
End Sub

End Module
----- end -----

The following VBScript exhibits the exact same behavior:

----- testClient.vbs -----
Dim testSrvObj, what, value, retvalue
Set testSrvObj = CreateObject("TestSrv.Application")

value = "ABCValue"
what = "ABC"

WScript.Echo "What", what
WScript.Echo "Value", value
testSrvObj.SetValue what, value
WScript.Echo "What", what
WScript.Echo "Value", value
testSrvObj.SetValue "ABC", value
WScript.Echo "What", what
WScript.Echo "Value", value
retvalue = testSrvObj.GetValue("ABC")
WScript.Echo "What", what
WScript.Echo "Value", value
WScript.Echo "Return", retvalue
----- end -----

The surprise here is that, after the first call to SetValue, the value
of "what" is changed. After the second call to SetValue, the value of
"value" is changed. After some experimentation, we discover that
these variables are getting set to whatever SetValue returns. In the
example I posted, we return the Python "None" value, which translates
to VB's Nothing. If I change the server to return a string, the VB
variables receive that string.

This question was originally posted to a Python mailing list with the
VBScript client. I assumed this was a bug in the Python COM handling,
which is why I tried it in VB2005. However, I dumped the IL from the
VB code above, and discovered to my great surprise that the IL has
code to do this! In the first case, it takes the return value, casts
it to string, and stores it in "what". In the second case, it stuffs
the return value into "value".

I can't duplicate this in C++ or C#, because they do not have
automatic support for late binding. The method calls return a value,
and it's up to me to handle it. Python does have support for late
binding, but calling this from a Python client does not exhibit this
behavior.

I have searched through two dozen documents on late binding in VB, and
I have found nothing to describe this. It turns out to be easy to
work around; if I turn the method call into a function call, it works:

retvalue = testSrvObj.SetValue( what, value )

Or, if I turn the parameters into ByVal parameters, it works:

testSrvObj.SetValue (what), (value)

However, I am stunned that I should have to do that. The semantics
boggle me.

Any clues greatly appreciated.
 
J

Jared Parsons [MSFT]

Hello Tim,
I've been doing COM a long time, but I've just come across a behavior
with late binding that surprises me. VB and VBS are not my normal
milieux, so I'm hoping someone can point me to a document that
describes this.

I'm not very familiar with late binding but I also am a bit surprised by
this behavior. Let's try and get python out of the picture here. Can you
post the IDL file for the Python server?
 
C

Cor Ligthert [MVP]

Tim,

I would set first Option Strict On in top of your program, than you can edit
the most obvious late binding errors which are not needed. If you can than
not resolve one or two, than you can set it again off.

At this moment there are in my opinion more changes on late binding errors
than are needed.

Be aware that you use very much VBScript code in VBNet which can give
errors. What is something the same as using C in C#.

By instance instancing an non global Object in VBNet is

\\\
Dim myOjbect as New TheClass
///

Cor


Tim Roberts said:
I've been doing COM a long time, but I've just come across a behavior
with late binding that surprises me. VB and VBS are not my normal
milieux, so I'm hoping someone can point me to a document that
describes this.

Here's the setup. We have a COM server, written in Python. For
completeness, here is the script:

----- testserver.py -----
import pythoncom

class TestSrv(object):

_reg_clsid_ = '{C7B89AAC-99B7-48A1-8088-D77A867CBB0C}'
_reg_desc_ = 'TestSrv COM+ Server'
_reg_progid_ = 'TestSrv.Application'
_reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER
_public_methods_ = ['SetValue', 'GetValue']

def __init__(self):
self.ABC = ''

def SetValue(self, what, newval):
if what == 'ABC':
self.ABC = newval

def GetValue(self, what):
if what == 'ABC':
return self.ABC

if __name__=='__main__':
import win32com.server.register
win32com.server.register.UseCommandLine(TestSrv, debug=0)
----- end -----

This server has two methods. Even without knowing Python, you can see
that neither method alters its parameters. They touch internal state
only.

We call this from a VB module:

----- Module1.vb -----
Module Module1
Sub Main()
Dim testSrvObj As Object
Dim what As String, value As String, retvalue As String
testSrvObj = CreateObject("TestSrv.Application")

value = "ABCValue"
what = "ABC"

Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
testSrvObj.SetValue(what, value)
Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
testSrvObj.SetValue("ABC", value)
Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
retvalue = testSrvObj.GetValue("ABC")
Console.WriteLine("What " & what)
Console.WriteLine("Value " & value)
Console.ReadKey()
End Sub

End Module
----- end -----

The following VBScript exhibits the exact same behavior:

----- testClient.vbs -----
Dim testSrvObj, what, value, retvalue
Set testSrvObj = CreateObject("TestSrv.Application")

value = "ABCValue"
what = "ABC"

WScript.Echo "What", what
WScript.Echo "Value", value
testSrvObj.SetValue what, value
WScript.Echo "What", what
WScript.Echo "Value", value
testSrvObj.SetValue "ABC", value
WScript.Echo "What", what
WScript.Echo "Value", value
retvalue = testSrvObj.GetValue("ABC")
WScript.Echo "What", what
WScript.Echo "Value", value
WScript.Echo "Return", retvalue
----- end -----

The surprise here is that, after the first call to SetValue, the value
of "what" is changed. After the second call to SetValue, the value of
"value" is changed. After some experimentation, we discover that
these variables are getting set to whatever SetValue returns. In the
example I posted, we return the Python "None" value, which translates
to VB's Nothing. If I change the server to return a string, the VB
variables receive that string.

This question was originally posted to a Python mailing list with the
VBScript client. I assumed this was a bug in the Python COM handling,
which is why I tried it in VB2005. However, I dumped the IL from the
VB code above, and discovered to my great surprise that the IL has
code to do this! In the first case, it takes the return value, casts
it to string, and stores it in "what". In the second case, it stuffs
the return value into "value".

I can't duplicate this in C++ or C#, because they do not have
automatic support for late binding. The method calls return a value,
and it's up to me to handle it. Python does have support for late
binding, but calling this from a Python client does not exhibit this
behavior.

I have searched through two dozen documents on late binding in VB, and
I have found nothing to describe this. It turns out to be easy to
work around; if I turn the method call into a function call, it works:

retvalue = testSrvObj.SetValue( what, value )

Or, if I turn the parameters into ByVal parameters, it works:

testSrvObj.SetValue (what), (value)

However, I am stunned that I should have to do that. The semantics
boggle me.

Any clues greatly appreciated.
 
T

Tim Roberts

Jared Parsons said:
Hello Tim,


I'm not very familiar with late binding but I also am a bit surprised by
this behavior. Let's try and get python out of the picture here. Can you
post the IDL file for the Python server?

There is no IDL. What you saw in my post is all that there is. The Python
COM services use reflection to synthesize IDispatch handlers for the class.
That's why we have to use late binding.

By the way, I keep saying "we", but in fact this code belongs to someone on
one of the Python mailing lists. The question intrigued me, because I
thought I was a pretty studly COM guy, and now I MUST find the answer.

The Cameron Beccario posting was useful; I'm going to try to concoct a C#
test case using Microsoft.VisualBasic.CompilerServices.LateCall and see if
I can duplicate it there.

In the end, however, I suspect the answer is "because that's how it works".
 
T

Tim Roberts

Cor Ligthert said:
I would set first Option Strict On in top of your program, than you can edit
the most obvious late binding errors which are not needed. If you can than
not resolve one or two, than you can set it again off.

"Late binding errors"? I'm not sure I understand. Late binding is not
allowed under Option Strict On, and this problem is entirely related to
late binding.
At this moment there are in my opinion more changes on late binding errors
than are needed.

Again, I'm not sure what you are saying. To use a Python COM server, we
have to use late binding.
Be aware that you use very much VBScript code in VBNet which can give
errors. What is something the same as using C in C#.

I don't think you read my post closely enough. I had a VB example, and a
separate VBScript example. Both happen to exhibit the same behavior.
 
C

Cor Ligthert [MVP]

Tim,

Thanks for the lesson,

Cor

Tim Roberts said:
"Late binding errors"? I'm not sure I understand. Late binding is not
allowed under Option Strict On, and this problem is entirely related to
late binding.


Again, I'm not sure what you are saying. To use a Python COM server, we
have to use late binding.


I don't think you read my post closely enough. I had a VB example, and a
separate VBScript example. Both happen to exhibit the same behavior.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top