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.
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.