Atlanta Custom Software Development 

 
   Search        Code/Page
 

User Login
Email

Password

 

Forgot the Password?
Services
» Web Development
» Maintenance
» Data Integration/BI
» Information Management
Programming
  Database
Automation
OS/Networking
Graphics
Links
Tools
» Regular Expr Tester
» Free Tools

Understanding interface marshaling

Total Hit ( 3587)

Rate this article:     Poor     Excellent 

 Submit Your Question/Comment about this article

Rating


 


There is quite a lot of misunderstanding among COM newbies about what really happens when a COM interface is passed as a method parameter. As in most of the cases, VB programmers are protected from a lot of details on the COM run-time, but you do have to know such details if you want to assemble something that perform decently in a distributed environment.

1) Basic automation types (Double, Long, String) are passed by value if the method signature is declared ByVal. They are passed by reference if the method signature is declared ByRef. The behavior you experience is the same if the method call takes place in-Apartment or cross-Apartment.
2) COM Interfaces: The first thing to emphasize here is that in VB (or in any COM-aware language) you never get in touch with a Class (the client doesn't have to know the class binary layout!); instead, you get in touch with interfaces. So when you think you're passing an object you are actually passing an interface. The state of underlying COM object that is behind the interface is not copied, e.g. as a struct (a VB type) is.

Now, coming to the point: COM Interfaces are passed

a) by reference if the method signature is declared ByVal;
b) by a reference to a reference if the method signature is declared ByRef.

For example, the following VB procedure signature:

Click here to copy the following block
Public Sub test(ByVal a1 As IMyInterface1, ByRef a2 As IMyinterface2)

maps to the following IDL code:

Click here to copy the following block
HRESULT test([in] IMyInterface* a1,[in,out] IMyInterface2** a2);

This means that even if you pass an interface ByVal, you shouldn't to be surprised that, on returning from the method call, one of its properties have been changed.
You might wonder when ByRef makes the difference: Passing an interface ByRef lets the callee replace the object behind the interface with another object that implements the same interface. Here an example: Say that CFastAnimal and CSlowAnimal both implement the interface IRun. CSomething implements IPrepareToRun, which has two methods : PrepareByRef and PrepareByVal:

Click here to copy the following block
Public Sub PrepareByRef(ByRef a1 As IRun)
  Set a1 = CreateObject("CSlowAnimal")
  a1.name = "AAA"
End Sub

Public Sub PrepareByVal(ByVal a1 As IRun)
  Set a1 = Createobject("CSlowAnimal")
  a1.name = "AAA"
End Sub

Here is the client code:

Click here to copy the following block
Sub a()
  Dim x As IRun
  Set x = CreateObject("CFastAnimal")
  x.name ="BBB"
  Dim y As IPrepareToRun
  Set y = CreateObject("CSomething")
  y.PrepareByRef(x)
  x.run         'runs slow
  Debug.Print x.name   'prints "AA"
End Sub

Sub b()
  Dim x As IRun
  Set x = CreateObject("CFastAnimal")
  x.name ="BBB"
  Dim y As IPrepareToRun
  Set y = CreateObject("CSomething")
  y.PrepareByVal(x)
  x.run         'runs fast
  Debug.Print x.name   'prints "AA"
End Sub

You see the same behavior described above if you pass Interfaces in-Apartment or cross-Apartment (Cross Process / Cross Host) if such interface are standard marshaled (Type-Library marshaling).
I should stress, however, that passing interfaces across apartment boundaries is considered bad design (especially across hosts): reading or setting a property involves a roundtrip. There are some cases where you may need to pass an interface for a callback, but NEVER use an interface as a method to pass/return data among two objects if you are not sure the two objects and the interface in question will always be in the same apartment.

There is an exception, though: you can do it if the interface implements MBV (Marshaling by value), and , yes, ADO disconnected Recordsets do implement marshaling by value. This means that when the _Recordset interface crosses apartment boundaries the data behind the recordset are copied in the new apartment. If the parameter is declared ByRef, then the data are copied back. But remember: this happens only if the recordset cross apartment boundaries, if it's not the case you get the standard COM behavior.

The conclusions are:

1) you have to know what standard marshaling is to develop distributed application;
2) you have to know when an interface is MBV and be aware that, in such case, your object behaves differently when is passed in-Apartment or inter-Apartment.



Submitted By : Nayan Patel  (Member Since : 5/26/2004 12:23:06 PM)

Job Description : He is the moderator of this site and currently working as an independent consultant. He works with VB.net/ASP.net, SQL Server and other MS technologies. He is MCSD.net, MCDBA and MCSE. In his free time he likes to watch funny movies and doing oil painting.
View all (893) submissions by this author  (Birth Date : 7/14/1981 )


Home   |  Comment   |  Contact Us   |  Privacy Policy   |  Terms & Conditions   |  BlogsZappySys

© 2008 BinaryWorld LLC. All rights reserved.