-1

I have a number of C# Assemblies which have been built and registered as COM components. They work perfectly fine when invoked from unmanaged code (Fujitsu NetCOBOL for Windows) and I also have no difficulty when invoking COBOL COM components from C#. The unmanaged COM component appears in the VS 2017 Reference Manager COM tab, VS 2017 generates the Interop and it is all excellent.

But if I try to use one of the managed COM components with managed code (a C# .exe), the VS 2017 Reference Manager doesn't show an entry for the .DLL. Instead, it presents the DESCRIPTION of the component instead of the NAME, and it is pointing to the .TLB which was generated when I built the original component. If I select that reference, this happens:

enter image description here

If I go and Browse for the .DLL the reference is added OK, but it forces me to "Copy Local" and I get a copy of the .DLL deployed with my executable.

Screenshot of referenced component properties

If I try and make it false, and embed the types, it fails to build and I get a message about some obscure attributes not being set...

If I build it as shown, it deploys and works perfectly, but I am adding a copy of the COM component .dll to every executable I deploy. That kind of defeats the object of COM components where one copy of the code is shared between users. I used COM for years with unmanaged code and never had any problems. Is a different understanding required for use with managed code?

I have spent a number of hours reading the docs on COM and interOP (although InterOP is not applicable here I think, as both the client and the server are managed code.)

Is there something I need to set when I build the component? (I use "Make COM Visible" and it certainly seems to register it OK. However, I noticed that if I unregister it with Regasm it does not clear the registry entries...

Is there a VS 2017 setting I am missing or something in the build? Any help would be gratefully received.

Pete.

Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
Morepork
  • 11
  • 5
  • Try testing it from Microsoft _Ole Viewer_ first just to ensure the COM component is registered correctly. It needs to work there first –  Jul 20 '20 at 07:00
  • 1
    .NET will not wrap a COM callable wrapper (CCW) in a Runtime callable wrapper (RCW). Managed code consumes managed code using managed references, not COM. (Which is what the end of that dialog is telling you too) – Damien_The_Unbeliever Jul 20 '20 at 07:39
  • MickyD: Thanks, that was a good suggestion. I installed the software and ran it. It showed that there were 2 versions of the component registered: one 32 bit and one 64 bit. However the registrations were correct. I changed the component version and rebuilt for Version 4+ of .NET. It is all working fine but I still have to deploy a copy with every app that uses it... – Morepork Jul 21 '20 at 02:21
  • Damien: I don't really understand what you are saying so it didn't really help. I did what it required and browsed to the actual .DLL in the Reference Manager. It loaded the reference fine but I still get a local copy and that was what prompted my original request for help. – Morepork Jul 21 '20 at 02:24
  • General: perhaps I should re-word this question. My problem is that managed components registered as COM, are treated just like any .DLL that you might add to a project. I am forced to use "COPY Local" (if I don't it won't build because it says some flags I never heard of, and can't seem to locate, are not set.). UNmanaged components registered as COM work without problem because they use InterOP. I really want the same functionality for a managed COM component. There should be a single codebase (as supplied to Regasm) and I should not have copies of the .DLL deployed with managed code. – Morepork Jul 21 '20 at 02:32

2 Answers2

0

After some intensive reading and experimentation I finally solved the problem.

SUMMARY: To be able to used managed COM components in the same way as we used unmanaged ones (one copy, registered and shared by all users), you SHOULD NOT try and add the .DLL as a reference to your project. Instead, you late bind the component and use reflection to implement its interfaces, methods, and properties.

This means doing the following:

  1. Getting an instance of the component dynamically at run time.

  2. using reflection on that instance to access properties and methods in the normal way.

DETAILS and CODE SAMPLES (to hopefully save someone else from having to do the background I did...):

First thing: DON'T add a reference to the .DLL to your Project.

I set up some global variables as follows:

code sample 1

Now I needed to consider what actions I wanted. I wanted a general solution so that I could use it on ANY COM reference and what I'm posting here is close, but things like specific error messages have not been replaced with variables yet.

The COM object supports Getting and Setting Properties and invoking Methods. I also need to be able to instantiate it easily.

The methods I have written here return a dynamic value in retVal.

They have been tested and all work very well, so I can continue to use the managed COM components just as I did the unmanaged ones, by simply adding the code samples here to any project that deals with them, and invoking these methods to deal with a given managed COM component. I do not claim to be an expert in C# and I'm sure that more experienced people will find better ways to code than I have, but it does work and that is always a good thing... :-)

I was a little concerned that using reflection might slow everything down, but in practice it is no "slower" than late binding any COM object is.

Here are the methods: (Sorry for code misalignment; I'm new to this...)

The method to instantiate the COM object. The example uses something called "RAVDesktop.dll"

code sample 2 code sample 3

Now the "Action" methods for properties and methods in the COM object...

code sample 4 code sample 5 code sample 6

Here's an example of instantiating the component, then setting a Property in it called "WebServiceURL", and, if the setting succeeded, retrieving it so it can be checked:

code sample 7

Grateful thanks to all who contributed. Stack Overflow rocks!

Pete.

Morepork
  • 11
  • 5
-1

ActiveX controls or COM components written in .NET languages cannot be referenced by .NET applications in the form of interop assemblies.

If you "add reference" to such a TLB, or drag & drop such an ActiveX control to your .NET application, you will get an error "The ActiveX type library 'XXXXX.tlb' was exported from a .NET assembly and cannot be added as a reference."Support: Can not add reference a COM in COM client?

The correct way to solve this problem is to add the reference.As follows:Right-click Reference->Add Reference->Browse.

Jack J Jun
  • 5,633
  • 1
  • 9
  • 27
  • Further to Jack: The reference you gave correctly identifies the scenario I gave screenshots for above. But I noticed that they talk about registering the COM server with regsvr32. I understood that was only for unmanaged code and have been using Regasm to register my COM assembly. (Like the person there, I tried it manually as well as from VS2017.) It registers fine with Regasm. – Morepork Jul 21 '20 at 22:52
  • Jack J Jun: Yes, I found that out. And I DID browse through Reference Manager and find the COM server .DLL. It is added correctly as a reference, and the application runs correctly. The problem is that when I do that, I get a copy of the COM server included with my application.(Just as I would expect for ANY referenced .DLL) I want the component to be shared, just like an unmanaged COM server is. Is it just not possible to do this with managed code or am I missing something? – Morepork Jul 21 '20 at 22:58
  • Marking as answer: I never marked jack's response as an answer because it isn't, for the reasons I have commented. I don't know how to unmark it and do appreciate ALL the responses, but so far, my problem is not solved. – Morepork Jul 21 '20 at 23:12
  • After my many attempts, it is not feasible to call the managed com component in VS through the com tab. I found the following link, and his fourth explanation explains your problem in detail. Link: [How to make C# COM DLL equivalent to ATL COM C++](https://stackoverflow.com/questions/6540171/how-to-make-c-sharp-com-dll-equivalent-to-atl-com-c) – Jack J Jun Jul 22 '20 at 09:23
  • Jack: Thanks for your response and your attempts. I read the link several times and it didn't really tell me anything I don't already know. I know about the strong name requirement, I know about needing to register the COM server on clients I deploy it to... (I do this with a script that runs the correct version of Regasm on the client, using INNO)... none of that is problematic. My problem is still the same as it was when I originally posted this question: How can I share a managed COM component so that a COPY of it is NOT distributed embedded in my application? (Copy Local). – Morepork Jul 23 '20 at 00:51
  • Jack: I want to separately deploy my COM components, register them on the target machine, and have them shared by the applications that use them, exactly as is normal practice for unmanaged COM. I think what has come out of this is that a wrapper of SOME kind may be required. I did think about writing an unmanaged harness to invoke my managed COM (like the guy in the link considered) but it is too unwieldy. I'm going to look in depth into RCWs and see if I can solve it that way. Will post back here when done. – Morepork Jul 23 '20 at 00:54