Can a managed ref-class directly implement a COM interface? - visual-studio-2012

Is there a built-in way to allow a managed ref-class to implement and expose a COM inerface that is safely callable from native code?
Looking at the C# side, this is easily done by decorating the target interface with the proper COM-interop attributes, for example:
Native Interface
interface ISampleGrabberCB: public IUnknown
{
virtual STDMETHODIMP SampleCB( double SampleTime, IMediaSample *pSample ) = 0;
virtual STDMETHODIMP BufferCB( double SampleTime, BYTE *pBuffer, long BufferLen ) = 0;
};
static const IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994,
{ 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };
Managed Equivalent Interface
[Guid("0579154A-2B53-4994-B0D0-E773148EFF85")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[SuppressUnmanagedCodeSecurity]
public interface ISampleGrabberCB {
int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen);
int SampleCB(double SampleTime, IMediaSample pSample);
}
Once this declaration is done, through the magic of P-Invoke you can do something like this:
public class FooClass : ISampleGrabberCB {
int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen) {
Console.WriteLine("BufferCB called");
}
int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample) {
Console.WriteLine("SampleCB called");
}
public void SomeMethod(IBaseFilter aDirectShowFilter) {
ISampleGrabber sampleGrabber = (ISampleGrabber)aDirectShowFilter;
// By the magic of PInvoke, this is possible and works!
// ISampleGrabber->SetCallback() is expecting an ISampleGrabberCB* COM interface
// After the following line, native code is able to callback safely
// into our managed code
sampleGrabber.SetCallback(this, 0);
}
}
Is there a way to mimic this behavior on C++/CLI?
Evidently, the Interop plumbing to make this possible exists as it is used by C#. Furthermore, the compiler could generate the necessary managed interface from inspecting the available native interfaces (I still think we would need to provide the relevant Guids, as this is not an attribute within the native interface)

I just got curious about this topic and played around and I found out some minor differences:
I have IVI-COM class library on my PC, and always wanted to try to interface some of them, although the IVI also has .Net interfaces so it does not make too much sense...
I started with C#, where we get good IntelliSense support. I have added the necessary references and added a class to my project. With the object browser we can select an interface.
public class MyDmm : IIviDmmMultiPoint
{
}
After that just use IntelliSense (Ctrl-.) to add the ‘using’ statement and let them make the necessary properties and methods for us.
using Ivi.Dmm.Interop;
///...
public int Count
{
get
{
throw new NotImplementedException();
}
///...
So now we need the C++-CLI dialect :) Which is as follows:
using namespace IviDmmLib;
///...
public ref class Dmm : IIviDmmMultiPoint
{
Note that the name used by the using statement is different, we can obtain this by selecting the reference at the Solution Explorer and check the name shown at the ‘Properties’ below.
I did not fully complete the experiment but I saw that the COM library was x64 bit, so we may compile the project for the same.
Further interesting readings:
Windows Runtime C++ Template Library
Please, give me feedback if you find some more differences, so we can put them here too.

Related

How do I access a form's control from another thread?

Using VC++ 2010.
I want to access a form's control from a class in another thread.. and can't figure out the best (or any) way to do this. How can I pass a reference of my form instance? Im using createthread() as opposed to the managed version, wanting to make my app compatible with XP.
I've tried passing a reference and other values in a struct through the lpParameter, but I can't seem to figure out how to declare the reference properly.
ref class SZClass {
private:
FMain ^bound_form;
int server_port;
public:
void BindForm(FMain ^bf);
void Initialize(int sp)
}
struct param_data {
public:
FMain ^form_tobind;
int port_num;
}
are giving me errors:
error C2143: syntax error : missing ';' before '^'
FMain is the name of my form class, and I have a delegate method already set up to make it multithread safe:
public:
FMain(void)
{
InitializeComponent();
//
//TODO: Add the constructor code here
//
}
void FMain::PrintConsole(std::string mzg) {
String ^Smzg = marshal_as<String^>(mzg);
if (this->textBox1->InvokeRequired) {
SetTextDelegate^ d = gcnew SetTextDelegate(this, &FMain::PrintConsole);
this->Invoke(d, gcnew array<Object^> { Smzg });
} else {
textBox1->Text += Smzg;
textBox1->SelectionStart = textBox1->TextLength;
}
}
How do I declare a reference to my form?
Or is there an easier or better way to do this?
I don't know what forms library you're using, but the general rule of thumb for your question is, "Don't."
Unless you have a peculiar GUI library, Windows UI is thread-affinitized. All access to UI elements should be done via the ui's affinitized thread. Manipulating UI state from an unaffinitized execution context should be done by marshaling the update request to the affinitized context. It should not be done directly.

C++ how to change private members of managed object using a native one?

I'm working on a student project. It's a network card game. The solution contains 3 projects. Client's GUI using Windows Forms so it has managed classes. Static client's library in native C++. GUI's project has reference to it thus uses 'Mixed Rules'. Server is in native C++ as well. I use RPC middleware for communication. It works only with native C++. That is why I need the static library to hide there all the details of communication on client's side.
Since the server can at any moment change its state and that should be shown in client's GUI, I use callback approach to change Windows Forms' components. And here I found a problem because I need to change private members of managed class with the help of a native object.
There are probably different ways to do that. My idea is sending a pointer to instance of managed class into instance of native class and saving it there. So later I can call from that native object public member functions of that managed class to change components.
This is from my 'Mixed Rules' GUI project:
//Native class for changing window 'Lobby'
class LobbyI : public ClientLib::Lobby {
public:
LobbyI();
~LobbyI();
//Should change window due to current Server's state
void reDraw(const CommonLogic::ServerState&);
};
// Managed class implements GUI for window 'Lobby'
// generated by Visual Studio designer
public ref class LobbyGUI : public System::Windows::Forms::Form {
//My members
ClientLib::Mediator* mediatorPtr; // Is it correct?
LobbyI* lobbyPtr; // ?
public:
LobbyGUI(void) {
InitializeComponent();
mediatorPtr = new ClientLib::Mediator(); // Is it correct?
lobbyPtr = new LobbyI(); // ?
mediatorPtr->setCallback(lobbyPtr);
}
protected:
~LobbyGUI() {
if (components) { delete components; }
delete lobbyPtr; // Is it correct?
lobbyPtr = nullptr; // ?
delete mediatorPtr; // ?
mediatorPtr = nullptr; // ?
}
private: System::Windows::Forms::Button^ buttonLogIn;
//...
This is from native static library ClientLib:
class Lobby {
public:
virtual ~Lobby();
virtual void reDraw(const CommonLogic::ServerState&) = 0;
};
class Mediator {
CommonLogic::ServerState serverState;
Lobby* lobbyPtr;
public:
Mediator();
~Mediator();
void setCallback(Lobby* ptr) { lobbyPtr = ptr; }
void reDrawLobby() { lobbyPtr->reDraw(serverState); }
};
This code builds ok. The only thing I need now is that the member function reDraw() of native derived class LobbyI is able to change the window implemented by managed class LobbyGUI. Thus getting and keeping and using pointer to it. And then I think it all will work. How to do that?
Maybe it's not the nicest implementation in general. I would be happy to read other suggestion.
I'm also doubtful about the way I used pointers to native classes inside managed class. Is it correct? It didn't work correct until I inserted ptr=nullptr; after delete ptr; in destructor.
UPDATE: Now I see redundancy in my code. Abstract class Lobby is useless. I need only to implement reDraw() function in managed class which will have obviously access to components of the window. And then pass safe pointer to native class function which expects pointer to a function as a parameter.
Finally I've solved it!! Using this article. In the following code a native object stores provided pointer to a function of managed object. So this callback function can be invoked at any time. A delegate is used as a form of type-safe function pointer. Instance of GCHandle is used to prevent the delegate from being relocated by garbage collector.
Here is simple CLR Console Application which increments and prints some integer using callback function invoked from native object. Thus we can "change private members of managed object using a native one".
using namespace System;
using namespace System::Runtime::InteropServices;
typedef void(__stdcall *ANSWERCB)(); // define type of callback function
#pragma unmanaged
class NativeClass {
ANSWERCB cbFuncPtr = 0; // pointer to callback function
public:
void setCallback(ANSWERCB fptr) {
cbFuncPtr = fptr;
incAndPrint();
}
void incAndPrint() { cbFuncPtr(); } // invokes callback which increments and prints
};
#pragma managed
ref class ManagedClass {
public: delegate void Del();
private:
Int32 i;
NativeClass* nativePtr;
Del^ delHandle;
GCHandle gch;
public:
ManagedClass(Int32 ii) : i(ii) {
nativePtr = new NativeClass;
delHandle = gcnew Del(this, &ManagedClass::changeAndPrintInt);
gch = GCHandle::Alloc(delHandle);
IntPtr ip = Marshal::GetFunctionPointerForDelegate(delHandle);
ANSWERCB callbackPtr = static_cast<ANSWERCB>(ip.ToPointer());
nativePtr->setCallback(callbackPtr);
}
~ManagedClass() {
delete nativePtr;
nativePtr = __nullptr;
gch.Free();
}
private:
void changeAndPrintInt() // callback function
{
Console::WriteLine(++i);
}
};
int main(array<System::String ^> ^args)
{
ManagedClass mc(1);
return 0;
}

Expose types from embedded interop type to other assemblies

I have an ATL COM library that defines an enum and an interface in MIDL like:
[uuid(65785D49-574A-4B1B-95F1-B9C7F283364A)]
typedef enum Options
{
Option1,
Option2
} Options;
[
object,
uuid(2E3D1B1A-DF95-434F-836B-73FF1245B608),
oleautomation,
nonextensible,
pointer_default(unique)
]
interface IExample : IUnknown
{
HRESULT Test([in] Options option, [out, retval] BSTR* str);
};
I then create a managed assembly and reference the TLB, which creates a PIA and embeds the types (Embed Interop Types = true) into the managed assembly.
In the managed assembly, I now create a class that implements the interface:
public class Example : IExample
{
public string Test(Options option)
{
return option.ToString();
}
}
Now I would like to create a third assembly that references the managed assembly and creates the object and call into it, but it doesn't let me since Options is an unreferenced type (requires me to include the PIA generated from the typelib):
public class Equivalence
{
public void UseTest()
{
Example e = new Example();
e.Test(Options.Option1); // recognizes that it requires an ExampleLib.Options parameter, but that type isn't available
}
}
Using reflector, I can see it inside the managed assembly, but it isn't viewable by object browser:
namespace ExampleLib
{
[ComImport, CompilerGenerated, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("2E3D1B1A-DF95-434F-836B-73FF1245B608"), TypeIdentifier]
public interface IExample
[Guid("65785D49-574A-4B1B-95F1-B9C7F283364A"), CompilerGenerated, TypeIdentifier("15a6cf97-c415-4866-bdfb-7da65edb1faa", "ExampleLib.Options")]
public enum Options
}
My managed assembly is itself a library intended to be distributed as an API, and I would like to expose this enumeration and interface so that it can be used by outside parties without having to deliver the PIA generated from the typelib of the ATL COM library. Is it possible?
Apparently this cannot be done. One of the errors (CS1748) pointed me to this post which says the PIA must be linked in by both assemblies.

Subclass a C++ abstract class in Java using JNI

I have a C++ library that I have to use in an existing Android implementation. I'm using Android NDK and using the C++ classes via JNI.
However, I am not able to find how to subclass a C++ abstract class in Java using JNI.
Problems I face:
My aim is to provide Java implementation for the virtual methods in C++ by subclassing the abstract C++ class.
I have loaded the native library and I'm trying to declare the native methods.
The C++ methods have keyword 'virtual'. When I declare the native functions in Java after loading the C++ library, 'virtual' is not recognized. What is wrong here?
Any help is appreciated. I'm a newbie to JNI. Thanks in advance.
Let's consider we have a C++ class:
class iVehicle
{
public:
virtual void Run() {}; // not-pure virtual here for simplicity of a wrapper, but could be pure (see the end of the post)
virtual int GetSize() const; // we want to reuse it in Java
};
We want to create a class Bot in Java that extends class iVehicle in the sense that calls to super invoke the C++ code from iVehicle::GetSize() and, from the C++ point of view, we can use the instances of Bot as iVehicle* variables. That's tough since C++ provides no good built-in functionality for reflection.
Here is one possible solution.
To use C++ class in Java we need to generate a Java wrapper, i.e:
class iVehicle
{
public void Run() { Native_Run(); }
public int GetSize() { return Native_GetSize(); }
private native void Native_Run();
private native int Native_GetSize();
// typecasted to pointer in C++
private int NativeObjectHolder;
// create C++ object
native static private int CreateNativeObject();
}
The usage in Java is simple:
class Bot extends iVehicle
{
public int GetSize()
{
if ( condition ) return 0;
// call C++ code
return super.GetSize();
}
}
However, there is a C++ part to this code:
static jfieldID gNativeObjectHolderFieldID;
JNIEXPORT void JNICALL Java_com_test_iVehicle_Run( JNIEnv* env, jobject thiz )
{
int Value = env->GetIntField(thiz, gNativeObjectHolderFieldID);
iVehicle* Obj = (iVehicle*)Obj;
// todo: add checks here, for NULL and for dynamic casting
Obj->Run();
}
The similar code is for GetSize().
Then creating an instance of Java's Bot you have to call CreateNativeObject() and assign the returned value to the NativeObjectHolder field.
JNIEXPORT int JNICALL Java_com_test_iVehicle_CreateNativeObject( JNIEnv* env, jobject thiz )
{
iVehicle* Obj = new iVehicle;
return (int)Obj;
}
So, this is the scheme. To make this work you will need to add the destruction code and to parse C++ classes to generate all this glue code.
Added:
In case where iVehicle is actually abstract you will have to generate a non-abstract wrapper that you are able to instantiate:
class iVehicle
{
virtual void Run() = 0;
}
class iVehicle_Wrapper: public iVehicle
{
virtual void Run() { ERROR("Abstract method called"); };
}
And instantiate iVehicle_Wrapper in CreateNativeObject(). Vuala! You have inherited an abstract C++ class in Java.

C# 4, COM interop and UPnP: A trying triumvirate

I'm trying to write a bit of code (just for home use) that uses UPnP for NAT traversal, using C# 4 and Microsoft's COM-based NAT traversal API (Hnetcfg.dll).
Unfortunately (or perhaps fortunately) the last time I had to do COM interop in .NET was sometime around the last ice age, and I seem to be fundamentally confused about C#'s use of dynamic types for interop and how to write a callback (so that the COM server calls my managed code).
Here's an exciting few lines of code:
// Referencing COM NATUPNPLib ("NATUPnP 1.0 Type Library")
using System;
using NATUPNPLib;
class NATUPnPExample
{
public delegate void NewNumberOfEntriesDelegate(int lNewNumberOfEntries);
public static void NewNumberOfEntries(int lNewNumberOfEntries)
{
Console.WriteLine("New number of entries: {0}", lNewNumberOfEntries);
}
public static void Main(string[] args)
{
UPnPNAT nat = new UPnPNAT();
NewNumberOfEntriesDelegate numberOfEntriesCallback = NewNumberOfEntries;
nat.NATEventManager.NumberOfEntriesCallback = numberOfEntriesCallback;
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
}
}
In the above code, the Add and Remove calls work absolutely fine. Terrific.
The trouble is, I would also like to know when the number of port mapping entries have changed, and to do so I need to register a callback interface (INATEventManager::put_NumberOfEntriesCallback), which must support the INATNumberOfEntriesCallback or IDispatch interfaces. VS2012's object browser describes INATEventManager::put_NumberOfEntriesCallback thusly:
dynamic NumberOfEntriesCallback { set; }
Right, so I was under the impression that in C# 4 I shouldn't have to decorate anything with fancy attributes and that I can register my callback simply by jamming a delegate into INATEventManager::put_NumberOfEntriesCallback in a vulgar manner and leaving .NET to worry about IDispatch and clear up the mess; but it appears that I'm terribly wrong.
So, er... What should I do to ensure my NewNumberOfEntries method is called?
I'm also slightly concerned that I can write nat.NATEventManager.NumberOfEntriesCallback = 1; or nat.NATEventManager.NumberOfEntriesCallback = "Sausages"; without an exception being thrown.
It seems that I was able to make it work. Two options - with a custom interface "INATNumberOfEntriesCallback" (which does not seem to be declared in the type library btw, you need to declare it yourself) and using plain dispatch with DispId(0). The conversion to the IDispatch/IUnknown is preformed by the framework automatically. So:
Option 1.
Declare the INATNumberOfEntriesCallback and make a callback class which implements that interface (the tricky part is Guid - it comes from the "Natupnp.h" file, and does not seem to appear to be in the type library).
// declare INATNumberOfEntriesCallback interface
[ComVisible(true)]
[Guid("C83A0A74-91EE-41B6-B67A-67E0F00BBD78")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface INATNumberOfEntriesCallback
{
void NewNumberOfEntries(int val);
};
// implement callback object
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class CallbackNewNumberOfEntries : INATNumberOfEntriesCallback
{
public void NewNumberOfEntries(int val)
{
Console.WriteLine("Number of entries changed: {0}", val);
}
}
class NATUPnPExample
{
public static void Main(string[] args)
{
var nat = new UPnPNAT();
nat.NATEventManager.NumberOfEntriesCallback = new CallbackNewNumberOfEntries();
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
}
}
Option 2.
Use plain dispatch. The documentation says that you can use dispid(0) and it should be called, with 4 (!) parameters (see the remarks section in docs). So basically the following construction seems to work in "dispatch" way:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class CallbackDisp
{
[DispId(0)]
public void OnChange(string updateType, object obj, object name, object val)
{
Console.WriteLine("{0}: {1} = {2}", updateType, name, val);
}
}
class NATUPnPExample
{
public static void Main(string[] args)
{
var nat = new UPnPNAT();
nat.NATEventManager.NumberOfEntriesCallback = new CallbackDisp();
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
}
}
I had the same problem you had, and since there isn't much help on the topic your posting helped tremendously! It wouldn't let me comment on your answer because I don't have enough points or whatever but your answer is the best, but doesn't quite work how I thought it would.
nat.NATEventManager.ExternalIPAddressCallback = new CallbackDisp();
Works, using the same dispatch, and will tell you when the external IP changes. HOWEVER,
nat.NATEventManager.NumberOfEntriesCallback = new CallbackDisp();
only reports UPnP map changes from these conditions: A.) It was added/removed by the NATUPnP instance.. In this case:
nat.StaticPortMappingCollection.Add();
OR B.) it was already mapped when the instance was created:
var nat = new UPnPNAT();
As an example, if Utorrent was running when you started your program and you you had something to block the program from exiting(Console.WriteLine();) for example.. When you exit Utorrent the callback would fire, and notify you of the map changes. Which is exactly what I wanted in the first place. However, if you re-open Utorrent, or any other app that uses UPnP it will NOT fire the callback, and will not notify you of the change.
Needless to say it has been very frustrating. If you figure it out please share! I know I can easily implement the functionality by polling the StaticPortMappingCollection at a given interval, but it seems a little 'hacky' to me.

Resources