dynamically link c# dll (COM) into a c++ rpogram

I have a c++ program, in which I am trying to load a c# dll.   I have got as far as being able to statically load it, by compiling with the "Register for COM Interop" setting, and generating it .tlb file.

From what I could see from other examples, it looks like normally, I should use LoadLibrary and  GetProcAddress to get the function address... sometihng like:

m_hHandle = ::LoadLibrary(m_strName);
P=GetProcAddress(m_hHandle,_T("ICalculator"));
(see below for c# code)

but I cannot seem to get a valid address, no matter how I play with it....
Am I on the right track at all?  I'm trying to get this to work like a plugin...
Thanks.

//------- C# dll being call
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace WoodEngineLink
{
	public class Class1
	{
		public interface ICalculator
		{
			int Add(int Number1, int Number2);
		};
		// Interface implementation.
		public class ManagedClass : ICalculator
		{
			public int Add(int Number1, int Number2)
			{
				return Number1 + Number2;
			}
		}
	}
}
 
//------------  c++ code

Open in new window

gp02874Asked:
Who is Participating?
 
jkrCommented:
Such as you would need to know the names of the DLLs, yes. But, you could store the CLSIDs of available managed COM servers in the registry, for example...
0
 
Todd GerbertIT ConsultantCommented:
I don't think you can LoadLibrary() a .Net library from C++ code (although the opposite direction is possible) - since your C# .dll is actually intermediate code that's compiled at run-time by the Common Language Runtime.
0
 
jkrCommented:
You cannot do that this way at all - If you want to call managed code from unmanaged code, you should consider COM Interop. For your particular setup, see http://msdn.microsoft.com/en-us/library/aa645738(VS.71).aspx ("COM Interop Part 2: C# Server Tutorial")
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

 
gp02874Author Commented:
let me clarify...
My understanding is I am creating a COM Interop of the c# dll, through the visual studio function.. which works similar to using regasm.exe.
I am able to get a (hopefully) valid address through the LoadLibrary() function.
0
 
jkrCommented:
You cannot get a valid address because there is no such thing as an address in managed code, sorry. That only works for unmanaged binaries.
0
 
gp02874Author Commented:
again to clarify.. I am able to sucessfully see access my c# functions (through  the COM created).  My problem is that I need to do it by dynamical loading, and not static loading.
0
 
gp02874Author Commented:
so is the answer .. I can only load it staticly, I cannot load it dynamically?
0
 
jkrCommented:
You can dynamically instantiate an object using 'CoCreateInstance()', but not via 'LoadLibrary()' as in the example above:
// COMClient.cpp
// Build with "cl COMClient.cpp"
// arguments: friend
 
#include <windows.h>
#include <stdio.h>
 
#pragma warning (disable: 4278)
 
// To use managed-code servers like the C# server, 
// we have to import the common language runtime:
#import <mscorlib.tlb> raw_interfaces_only
 
// For simplicity, we ignore the server namespace and use named guids:
#if defined (USINGPROJECTSYSTEM)
#import "..\RegisterCSharpServerAndExportTLB\CSharpServer.tlb" no_namespace named_guids
#else  // Compiling from the command line, all files in the same directory
#import "CSharpServer.tlb" no_namespace named_guids
#endif
int main(int argc, char* argv[])
{
   IManagedInterface *cpi = NULL;
   int retval = 1;
 
   // Initialize COM and create an instance of the InterfaceImplementation class:
   CoInitialize(NULL);
   HRESULT hr = CoCreateInstance(CLSID_InterfaceImplementation,
               NULL, CLSCTX_INPROC_SERVER,
               IID_IManagedInterface, reinterpret_cast<void**>(&cpi));
 
   if (FAILED(hr))
   {
      printf("Couldn't create the instance!... 0x%x\n", hr);
   }
   else
   {
      if (argc > 1)
      {
         printf("Calling function.\n");
         fflush(stdout);
         // The variable cpi now holds an interface pointer 
         // to the managed interface.
         // If you are on an OS that uses ASCII characters at the 
         // command prompt, notice that the ASCII characters are 
         // automatically marshaled to Unicode for the C# code.
         if (cpi->PrintHi(argv[1]) == 33)
            retval = 0;
         printf("Returned from function.\n");
      }
      else
         printf ("Usage:  COMClient <name>\n");
      cpi->Release();
      cpi = NULL;
   }
 
   // Be a good citizen and clean up COM:
   CoUninitialize();
   return retval;
}

Open in new window

0
 
jkrCommented:
Well, to sum it up - 'LoadLibrary()' won't work at all in this context, but using 'CoCreateInstance()' should do the job for you.
0
 
gp02874Author Commented:
but isn't this statically loading it as well?  If the file CSharpServer.tlb above is not present, than the code will not compile? no?
Remember, I'm trying to set this up like a Plug-in, so the file might be there or not (or even chosen through a dialog box).
0
 
jkrCommented:
No, that isn't static at all. And compiling is different from running. Such as you need the .tlb file for compiling here, you'd need a valid function prototype to use with 'LoadLibrary()'/'GetProcAddress()', there is not much of a difference here.
0
 
gp02874Author Commented:
sorry for being dense...

My vision of what I'm trying to to get to work is like the following:
   ...I have two different c# dll(converted to COM)... Eval-methodA.dll and Eval-methodB.dll
   ... The user of the main c++ program will be able to choose the method (dll) to use on start up..
   ... At some point in the future, there will be a Eval-methodC.dll, which I would like to not have to recompile the c++ program.
(Please don't figure out why I'm doing this, or if there's a better way, just take it on faith).

So the "Load Library" method would work for this, in so far as I don't need to know the name of the dll (or tlb) before I compile, and if I don't know the name.
With the "CoCreateInstance" example above, it might not load it untill I need it, but it looks like I have to have it available when I compile.

Hopefully this make sense.
I'm thinking I might have to have some sort of plain function  "wrapper" around my class, or something...
I'm also thinking..eh.. it just might not be possible to do what I want..


0
 
jkrCommented:
Well, in this case you'd distinguish between these two DLLs not by using their names, but via their respective CLSIDs, e.g.
   HRESULT hr;
 
   if(bUseEvalMethodA)
           hr = CoCreateInstance(CLSID_EvalMethodA,
               NULL, CLSCTX_INPROC_SERVER,
               IID_IManagedInterface, reinterpret_cast<void**>(&cpi));
    else
           hr = CoCreateInstance(CLSID_EvalMethodB,
               NULL, CLSCTX_INPROC_SERVER,
               IID_IManagedInterface, reinterpret_cast<void**>(&cpi));

Open in new window

0
 
gp02874Author Commented:
but I need to know these when I compile, both at the CoCreateInstance() and in the #Import statements.  I need to compile again when I have a method "C" .. (or method "ZZ"), right?

I'm not so much worred about dynamically creating an instance of the object class, than if the COM is available both at compile and run time.
0
 
Todd GerbertIT ConsultantCommented:
Not sure if this would work for you (or at all, for that matter)...is a mixed managed/unmanaged C++ app possible?  If so you might be able to make use of System::Reflection::Assembly::LoadFrom to get a managed pointer to your C# assembly.

Or perhaps a mixed C++ DLL as a wrapper...
0
 
gp02874Author Commented:
tgerbert.. thats is more along the lines of what I'm after.  Unfortunately, the C++ is unmanaged, and to messy to convert.  I think Reflection will only work with managed...
I was hoping that when I converted my c# dll to a COM object, I would be going from unmanaged to unmanaged, and it would be as bad.
0
 
williamcampbellCommented:
FACADE PATTERN

I think what you need to do it this:

 Create your COM Interop C# DLL *AND* Create a C++ DLL that calls it.
The C++ DLL does a CoCreateInstance on The C# DLL and builds a FACADE to the functions inside it.
The C++ DLL hides the registry and .tld info as that is compiled into the C# DLL

Then You can scan the folder for the C++ DLL's the C# Implementation is hidden

The Drawback is you would now have to DLL's and have to do some work to expose the functions. But since the functions are minimal (at least now) I think is a worthwhile trade off.

The alternative is .. it can't be done.

wc

0
 
Todd GerbertIT ConsultantCommented:
Granted, my knowledge of C++ is fuzzy at best, however it's my understanding that it is possible to compile an assembly that contains both .Net managed code and native unmanaged code.  Therefore, it *might* be possible to add such a mixed C++ .dll to your project, whose sole function is to act as proxy between your native C++ application and the managed C# assemblies; exposing itself to the C++ code using __declspec(dllexport) and to managed code using the System::Reflection namespace.

Just a thought...
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.