3

I am having some performance problems when calling a COM TLB methods from C# using the dynamic keyword (more information here). Scince I have not had any luck trying to optimise such call I am now looking at a way to convert my TLB library to a native wrapper DLL which I can use directly in my C# project (at this stage I am not even sure that this will help, but instead abstract the performance problems down a layer).

I have used tlbimp.exe to create a .dll from my COM .tlb file (which is registered) using the VS2013 command prompt and the command

tlbimp F:\SomeDir\GrpSvr.tlb /out:F\SomeDir\GrpSvr.dll 

This has produced a managed wrapper C# .dll that I can inspect this using dotPeek. It contains the expected namespace

namespace GRPSVR
{
    [TypeLibType(TypeLibTypeFlags.FCanCreate)]
    [Guid("FFB54BC4-B15E-11D1-99BC-0000E803C444")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComImport]
    public class GrpCallClass : IGrpCall, GrpCall { /*Expected Methods et al.*/ }
}

and the two interfaces IGrpCall containing the full template for the generated class and and empty interface GrpCall. I register this .dll using regasm.exe and

regasm F:\SomeDir\GrpSvr.dll 

Now, I include a reference to this .dll in my project and attempt to instantiate the GrpCallClass class via

private GRPSVR.GrpCallClass grpSvr = new GRPSVR.GrpCallClass();

But this give the compile time error:

Interop type 'GRPSVR.GrpCallClass' cannot be embedded. Use the applicable interface instead.

So then I try

private GRPSVR.IGrpCall grpSvr = new GRPSVR.GrpCall();

and this works at compile time but at run time I get a

Additional information: Retrieving the COM class factory for component with CLSID {FFB54BC4-B15E-11D1-99BC-0000E803C444} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

But I have registered the .dll.

  1. Will this approach help increase the performance of calling method in the initial COM TLB assembly?

  2. Can someone explain what I am doing wrong and how I can convert my COM .tlb library into a native wrapper .dll?

Thanks for your time.

Community
  • 1
  • 1
MoonKnight
  • 23,214
  • 40
  • 145
  • 277
  • Looks like you are going in the right direction. Look in the registry for your class and see if it is present, just as you would for any other COM object. Also, be aware that many COM components are 32-bit only, so your calling application should be 32-bit as well. Be aware that there are 32 and 64 bit versions of the registration utilities as well. – tcarvin Mar 28 '14 at 12:00

1 Answers1

5

I register this .dll using regasm.exe

That was a fatal mistake. That overwrote the registry keys for the native COM server. Regasm should only ever be used when the server was written in a .NET language. You will have to re-install the server to repair the damage. Be sure to run Regasm /unregister first to clean up the registry.

and empty interface GrpCall

That you see an empty interface is the reason you have to use the dynamic keyword in your C# code. The author of the COM server only permits you to use it late-bound. The equivalent of [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] in .NET. This is not uncommon, it avoids a lot of DLL Hell misery. But sure, late-binding isn't very fast since an extra call is needed at runtime to find the dispid of the method you are calling. Setting up the stack frame to make the call is slow as well, every argument has to be converted to a VARIANT. A x10 slowdown compared to a early-bound call is pretty normal, could be several orders of magnitude for a simple property.

There isn't anything you can do to avoid this, you'll have to work with the server author to get ahead. A pretty-please-with-cheese-on-top is the way to go about it, ask for a dual interface. Expect a "no", you may get a "yes".

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Hans, thank you for your time yet again. It is, as always, very much appreciated... All the best. – MoonKnight Mar 28 '14 at 13:36
  • Just to clarify, you are saying that even if I get the C# wrapper from `tlbimp` I will still have this performance hit? I thought that using this wrapper dll I could get away from late-binding? I have only just realised as well that I can add a reference to the COM library in my VS2013 project allowing me access to the classes/interfaces above directly - it this again a round about way of doing late-binding behind the scenes/what would happen to my calls in this case? – MoonKnight Mar 28 '14 at 13:40
  • Ps. I have deleted the generated DLL without unregistering. I am an idiot. What can I do about unregistering that DLL now? I have tried re-installing the application that uses the TLB/COM library but this now does not register properly! Fool I am. – MoonKnight Mar 28 '14 at 13:44
  • 1
    You can just rerun tlbimp.exe and use Regasm /uninstall on the dll to clean up the registry. Using the interop library will not make any difference, you still have to make late-bound calls. The server author doesn't want you to use it so you shouldn't. It is risky because he might change the [Guid] of the GrpCallClass (like he should when he makes any changes) and that will bomb your code with "Class not registered". Also the reason you'd expect a "no". – Hans Passant Mar 28 '14 at 13:52
  • Sorry for all the questions Hans. The server author I know, however this is old code. Dispite this, he should be able to make any changes required to get this to work nativity without late-bound calls. I am confused now over how he can compile his old code to enable compile-time resolution of types? – MoonKnight Mar 28 '14 at 13:56
  • It entirely depends on the tooling he used to create the server. It can be trivial, it can be a massive headache for him. He'll know. Nobody likes to dig up ancient code and make changes to it, do make sure to do this formally when you get a "maybe". – Hans Passant Mar 28 '14 at 14:01
  • This is honestly a nightmare and the reason I sometimes hate development. I have been asked to create a temporary UI to 'wrap around' and old (but very powerful) COM library. Mostly it is working great with `dynamic` but in the only section of the code I have to loop thousands of times, using `dynamic` [expected] is causing the code to lock up and run like treacle. Basically, what I gather, is that there is no way around this using this old COM library... – MoonKnight Mar 28 '14 at 14:24
  • My issue was that I ran TlbImp.exe on my developer machine and the GUIDs for the COM library were different on my server. Running the importer utility on the server resolved my issue. Hope someone else finds this useful. – SteveB Feb 21 '20 at 21:40