1
votes

Q: Can I make a native client that consumes a .NET COM component, using reg free COM?

I.e. Can I make a C++ application with COM info in its manifest, instead of registering the component (COM 'stuff') in the registry?


Note: I started looking at reg free COM with this question in mind, and didn't find a quick answer via web search. When I found the answer, thought'd I'd post on SO in case helps anyone else searching...

2
An easy way of doing this: stackoverflow.com/a/23073183/1768303noseratio

2 Answers

2
votes

Yes.

And here's an MSDN has an article (from 2005) that walks through a working example of:

...the registration-free activation of a .NET Framework-based component by native clients via COM interop. (11 printed pages)
https://msdn.microsoft.com/en-us/library/ms973915.aspx (accessed Jan 2015)

2
votes

Daryn,

This blog entry explain you how to do it: http://blogs.msdn.com/b/rodneyviana/archive/2015/08/24/pure-native-c-consuming-net-classes-without-com-registration.aspx

Basically you use a entry point to return the pointer to the interface (using DllExport Nuget for "export"):

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using RGiesecke.DllExport;

namespace ContosoCom
{

 public static class Exports
 {
     [DllExport(CallingConvention = CallingConvention.Cdecl)]
     public static void GetClass([Out] [MarshalAs((UnmanagedType.Interface))] out IMyClass pInterface)
     {
         pInterface = new MyClass();
     }
 }


 [ComVisible(true)]
 [System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
 public interface IMyClass
 {
     void DisplayMessageBox([MarshalAs(UnmanagedType.BStr)] string Text);
     void GetTicksAndDate([Out] out MyStruct Structure);
 }

 [ComVisible(true)]
 [StructLayout(LayoutKind.Sequential, Pack = 8)]
 public struct MyStruct
 {
     public long TicksOfNow;
     public int Day;
     public int Month;
     public int Year;
 }

 [ComVisible(true)]
 [ClassInterface(ClassInterfaceType.None)]
 [ComDefaultInterface(typeof(IMyClass))]
 public class MyClass : IMyClass
 {

     public void DisplayMessageBox(string Text)
     {
         MessageBox.Show(Text);
     }

     public void GetTicksAndDate(out MyStruct Structure)
     {
         Structure.TicksOfNow = DateTime.Now.Ticks;
         Structure.Day = DateTime.Now.Day;
         Structure.Month = DateTime.Now.Month;
         Structure.Year = DateTime.Now.Year;
     }
 }

}

And this is how the C++ code looks like:

#include "stdafx.h"
#import "..\..\bin\Debug\ContosoCom.tlb" auto_rename


using namespace ContosoCom;
typedef void(*pGetClass)(IMyClass **iMyClass);


int _tmain(int argc, _TCHAR* argv[])
{
 pGetClass getClass = NULL;
 IMyClass *mc = NULL;

 HINSTANCE hDLL = 0;
 // load the DLL

 hDLL = ::LoadLibrary(L"ContosoCom.dll");

 ::CoInitialize(NULL);

 if(!hDLL)
 {
     printf("ERROR: Unable to load library ContosoCom.dll\n");
     return -1;
 }


 //
 // TO DO: Add code here to get an instance of MyClass
 //
 getClass = (pGetClass)GetProcAddress(hDLL, "GetClass");

 if(!getClass)
 {
     printf("ERROR: Unable to find entry for GetClass()\n");
     return -1;

 }

 getClass(&mc);

 // At this point we do not have how to get a pointer even with the libray loaded

 // End of TO DO

 if(!mc)
 {
     printf("ERROR: Unable to get a pointer for MyClass\n");
     return -1;
 }

 mc->DisplayMessageBox("Hello World from native to .NET without registration");
 MyStruct st;
 ZeroMemory(&st, sizeof(MyStruct));
 mc->GetTicksAndDate(&st);
 printf("Ticks %I64i\n",st.TicksOfNow);
 printf("Today is %i/%i/%i\n",st.Month,st.Day,st.Year);


 printf("SUCCESS: Leaving gracefully\n");
 return 0;
}