7

I am using COM Interop. I have a call in VB6 which returns a string of roughly 13000 chars. If I execute the call in pure VB6 it takes about 800ms to execute. If I execute it via c# and COM Interop it takes about 8 seconds. I'm assuming the delay is caused by marshaling.

If I am correct about marshaling, I'd be grateful if someone could suggest the fastest way I can get this into C#. e.g. Would it be better to a) expose it as a byte array b) provide a byref string param into the VB6 layer

I would appreciate some sample code as well. I tried the

Marshal.PtrToStringAuto(Marshal.ReadIntPtr(myCOMObject.GetString, 0)

to no avail.

--

Following on from Franci's comment. I am simply referencing the VB6 dll (so in process) from a C# dll. Here's an extract from OLEView

interface _MyCOMObect : IDispatch {
        ...
        [id(0x60030006)]
        HRESULT GetString(
                        [in] _IEventHistory* p_oEventHistory, 
                        [out, retval] _IXML** );
        ...
    };

    [
      uuid(09A06762-5322-4DC1-90DD-321D4EFC9C3E),
      version(1.0),
        custom({17093CC6-9BD2-11CF-AA4F-304BF89C0001}, "0")
    ]
    coclass MyCOMObject {
        [default] interface _CFactory;
    };

    [
      odl,
      uuid(C6E7413F-C63A-43E4-8B67-6AEAD132F5E5),
      version(1.0),
      hidden,
      dual,
      nonextensible,
      oleautomation
    ]

I should probably point out that the parameter (p_oEventHistory) is another COM object which I am instantiating in C# but that takes about 80ms

S

skaffman
  • 398,947
  • 96
  • 818
  • 769
Simon Woods
  • 2,223
  • 4
  • 27
  • 34
  • It might help if you give some details about your VB6 and C# code. Is the VB6 component an out-of-proc server or inproc? What's the actual TLB fragment for the object and the property you are accessing. Is the call going through IDispatch or a regular COM interface? Are you using standard OLE marshaller or a custom proxy/stub or even a custom marshaller? – Franci Penov Mar 30 '10 at 06:15
  • So I have managed to shave 1 sec off the time by not injecting a COM object into the COM call (via the parameter) but doing it all on the COM side of things. BUT 7 secs still seems excessive for transferring 13000 chars! – Simon Woods Mar 30 '10 at 09:19
  • 1
    There's something else going on. Marshaling a BSTR takes microseconds, not seconds. You should debug the VB6 code, set the C# exe as the startup program. – Hans Passant Mar 30 '10 at 13:00
  • So I did that, setting break points as the vb6 function is invokes and at the point of return in the C# code. The delay occurs as it leaves VB6 and before it returns to C#. The other factor which I have omitted to mention is that the VB6 dll resides in COM+, so I'm wondering if the problem lies somewhere around there. I'm not too sure how to begin to diagnose that though. Thx for the suggestion – Simon Woods Mar 30 '10 at 14:30
  • So I removed the COM+ layer and things worked much faster. So I guess I need to find out why COM+ slows things down so much in this scenario – Simon Woods Mar 30 '10 at 15:43
  • ... and the answer was that one of the objects I was loading into COM+ was too complicated. When I re-structured and made the objects in COM+ simple data types, the speed increased dramatically - thx to all – Simon Woods Mar 31 '10 at 13:37
  • Sounds like you've answered your own question, but you should confirm if the delay *is* dependent on the size of the string. I.e. try strings with size 100, 1000, 10000 and/or linear sizes and confirm the performance of each. – Mark Hurd Apr 01 '10 at 01:47
  • 1
    Here's a guess: COM+ probably made some of your objects hosted in a different process, and that made marshaling slow. – Fyodor Soikin Apr 04 '10 at 02:50

2 Answers2

2

A couple of things: -

  1. My VB6 is a little rusty, but your IDL excerpt suggests the GetString method actually returns an object that implements the IXML interface. I'm kind of surprised that Marshal.PtrToStringAuto can do anything useful with this. Could you change the VB6 so that it actually returns something of type String?

  2. The effect of COM+ is potentially enormous. Firstly I would suggest that you compare timings for the first invocation versus subsequent invocations. COM+ will need to spin up a host process for your VB6 component the first time it's invoked so the first call is always more painful. Note this happens on first invocation, not on object instantiation. Secondly, the way your component is configured in COM+ can make a big difference too; if you disable all the COM+ services that you don't actually need (e.g. transactions) you might be able to remove some of the interception logic that COM+ places around all method invocations. Ultimately, if you don't need the services that COM+ provides, don't use it.

Martin
  • 5,392
  • 30
  • 39
0

I would consider using memory mapped files or named pipes.

Community
  • 1
  • 1
kenny
  • 21,522
  • 8
  • 49
  • 87