none
clr hosting and .NET events (delegates) RRS feed

  • Question

  • Hi all,

    I've dived in the deep end trying to host the CLR in a Win32 dll to allow me to bridge the CLR with other windows languages.  This interoperability actually relies on other languages supporting COM and more specifically the IDispatch interface.

    In short, through hunting through varies blogs on the internet I've got a working solution that uses a combination of a simple Win32 DLL and a .NET 2.0 supporting assembly.  The Win32 DLL is responsible for loading the CLR and starting the application domain.   It then loads the .NET 2.0 bridging assembly and returns an IDispatch pointer to the wrapper class.  This class is COM exposed.  Basically through the use of reflection I am able to load any assembly and and object and interop with it through this DLL and assembly (if that makes sense).

    Here is my code that loads the required assembly and returns its IDispatch:

    DWORD WINAPI DotNetInstanceFrom(char *AssemblyFile, char *class, char *ErrMsg, DWORD *dwErrorSize)
    {
    
    	// Required object ref
    	CComPtr<_ObjectHandle> spObjectHandle;
    	
    	// Have we loaded the application domain already?
    	if (!spDefAppDomain)
    	{
    		// Call exported load function explicitly
    		if (LoadClr(ErrMsg,dwErrorSize) != 1)
    			// Ok we failed!
    			return -1;
    	}
    
    	DWORD hr;
    
    	//Creates an instance of the .NET type specified within the passed Assembly
    	hr = spDefAppDomain->CreateInstanceFrom(		
    	_bstr_t(AssemblyFile), 
    	_bstr_t(class),
    	&spObjectHandle
    	);	
    
    	*dwErrorSize = 0;
    
    	// Did we fail?
    	if (FAILED(hr)) 
    	{		
    		*dwErrorSize = SetError(hr,ErrMsg);
    		return -1;
    	}
    
    	// Unwrap the object
    	CComVariant VntUnwrapped;
    	hr = spObjectHandle->Unwrap(&VntUnwrapped);
    	if (FAILED(hr))
    		return -1;
    
    	// Retrieve IDispatch 
    	CComPtr<IDispatch> pDisp;
    	pDisp = VntUnwrapped.pdispVal;
    	
    	// Pass the raw COM pointer back
    	return (DWORD) pDisp.p;
    }
    

    Basically this call is always used to load my bridging assembly that is of Dual interface.  This is then in turn used to load other assemblies, create types and call methods (members or static).  Basically the Win32 shim loads this single COM based assembly and offloads the rest of the work to it using IDispatch.

    Unfortunately my knowledge of this interface regarding Events is limited and also I'm not terribly comfortable with ATL either.  I'm now at a point where I was hoping to expose a delegate in my bridging class (within my assembly) that I could somehow funnel .NET events through.  My first issue is how do I even turn a known .NET delegate type into a COM based event?  Is this even possible the way I'm going about this?

    I was hoping to use reflection like I have been when calling methods to handle different types of delegates but again, I've never used reflection with delegates or events so I have no idea if this is even realistic.

    Any adivce or pointers, somewhere to basically start from would be fantastic.

    TIA

    Regards

    Richard 

     

    Monday, September 26, 2011 10:36 PM

Answers

All replies

  • The .NET Framework version 2.0 and later provides the ability to marshal function pointers between managed and unmanaged code using the following methods:

    1. Use the Marshal.GetDelegateForFunctionPointer method to marshal an unmanaged function pointer into a delegate. This method uses the System.IntPtr class to represent an unmanaged function pointer.
    1. Use the Marshal.GetFunctionPointerForDelegate method to marshal a delegate into a function pointer that is callable from unmanaged code. When you use this method, you must manually keep the delegate from being collected by the garbage collector. The garbage collector does not track references to unmanaged code.

     

    You can refer to the MSDN document to get start:

    How to: Marshal Callbacks and Delegates Using C++ Interop 

    I have found two code projects to help you:

    Using managed delegate types in the unmanaged world

    Yet another approach to Delegates in unmanaged C++

     

    I hope this can help you.


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by NozFx Thursday, September 29, 2011 11:07 AM
    Wednesday, September 28, 2011 5:44 AM
  • Hi Paul,

    Thanks for your reply.  This is great, dunno how I missed it.  Looks like I can get some use from this.  Saying this I haven't explained myself very well. 

    My only issue is that I was hoping to some how get a COM event (via IDispatch) exposed to the client.  I guess this is probably an unrealistic task and a performance nightmare.  Basically I wanted to call into the assembly or win32 dll and register any undertmined event via IDispatch.  I believe a pure IDispatch class is able to do this via ::invoke.  What I am not sure about is how I can dynamically bind to a .NET based event and some how funnel the callback through IDispatch. 

    Does this make any sense? ;)

    So for example:

    Lets say the client is VFP.  It calls my win32 dll and gets an IDispatch reference to a .NET based class that serves as a factory to create instances and call methods of other .NET based classes (with limitations of course).  Basically I'm able to create a COM object from a COM visible .NET class without it being registered.  The problem is VFP requires the interface to be known to implement COM based event handlers.  I have no interface registered so I don't know if there is any way around this.  I cannot bind to any events of the exposed class.  I know, for instance, that a pure IDispatch class is able to support evnets via ::invoke so I'm guessing late binding to events is possible?  I was hoping to define a single event that could be late bound to.  Not sure if this is entirely possible.

    I guess getting an unmanaged function pointer is a start.  But thinking about it not sure at this stage how that helps raise a COM based event though.  I may have to have some interface registered to even attempt this, but I was hoping not.

    Regards

    Richard

    Wednesday, September 28, 2011 6:18 PM
  • Hi Richard,

     

    The .NET Framework provides a delegate-based event system to connect an event sender (source) to an event receiver (sink). When the sink is a COM client, the source must include additional elements to simulate connection points. With these modifications, a COM client can register its event sink interface in the traditional way by calling the IConnectionPoint::Advise method.

     

    There are detail steps to To interoperate with a COM event sink:

    How to: Raise Events Handled by a COM Sink


    Paul Zhou [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by NozFx Thursday, September 29, 2011 11:07 AM
    Thursday, September 29, 2011 4:54 AM
  • Hi Paul,

    Many thanks for your prompt response.  I will now do some reading ;)

    I've probably bitten off more than I can chew, I guess I need to find a good book on low level COM too.

    Thanks again

    Regards

    Richard

     

    Thursday, September 29, 2011 11:09 AM