none
InvokeMember on IDipatch starts new thread RRS feed

  • Question

  • I have a native MFC application, that instantiates .NET dialogs. I have implemented a COM object that implements the IDispatch interface for the .NET dialogs to communicate with the native world.

    When the .NET dialog calls InvokeMember then a new thread is started which executes the method.

    Any idea how we make the .NET dialog call the COM interface without starting a new thread ?

    P.S. Other ideas for how to communicate between the native world and the .NET world are also very welcome.

    This is how .NET calls the IDispatch interface using the InvokeCom() method:

     [Guid("00020400-0000-0000-C000-000000000046")]
     [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
     public interface IDispatch
     {
     [PreserveSig]
     int GetTypeInfoCount(out int Count);
     [PreserveSig]
     int GetTypeInfo([MarshalAs(UnmanagedType.U4)] int iTInfo, [MarshalAs(UnmanagedType.U4)] int lcid, out System.Runtime.InteropServices.ComTypes.ITypeInfo typeInfo);
     [PreserveSig]
     int GetIDsOfNames(ref Guid riid, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)] string[] rgsNames, int cNames, int lcid, [MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
     [PreserveSig]
     int Invoke(int dispIdMember, ref Guid riid, uint lcid, ushort wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, out object pVarResult, ref System.Runtime.InteropServices.ComTypes.EXCEPINFO pExcepInfo, IntPtr[] pArgErr);
     }
    
    
     public class NET_Proces
     {
     IDispatch m_IDispatch;
    
     private static NET_Proces instance;
    
     private NET_Proces() { }
    
     public static NET_Proces Instance
     {
      get 
      {
      if (instance == null)
      {
       instance = new NET_Proces();
      }
      return instance;
      }
     }
    
     public void Init(System.IntPtr testPtr)
     {
      m_IDispatch = (IDispatch)Marshal.GetObjectForIUnknown(testPtr);
     }
    
        private String InvokeCom(string funcName, params object[] args)
        {
          Object objectOut = null;
    
          objectOut = m_IDispatch.GetType().InvokeMember(funcName, System.Reflection.BindingFlags.InvokeMethod, null, m_IDispatch, args);
    
          if (objectOut != null)
             return objectOut.ToString();
          else
             return "";
        }
     }
    

    And the COM interface is initialized like this using CLI/Interop:

    extern "C" AFX_EXT_API void WINAPI NET_ProcesInteropInit(CComPtr<IDispatch> & pNET_ComInterface)
    {
    	NET_Proces::NET_Proces::Instance->Init((System::IntPtr)&*pNET_ComInterface);
    }
    

    And the COM interface is created like this in the native code:

    class XMLDispatch : public IDispatch
    {
    protected:
    	DWORD	m_refCount;
    
    	// IUnknown
    	virtual STDMETHODIMP_(DWORD) AddRef();
    	virtual STDMETHODIMP_(DWORD) Release();
    
    	// IDispatch
    	virtual STDMETHODIMP GetTypeInfoCount(UINT*) { return E_NOTIMPL; }
    	virtual STDMETHODIMP GetTypeInfo(UINT,LCID,ITypeInfo**) { return E_NOTIMPL; }
    	virtual STDMETHODIMP QueryInterface(REFIID,void** );
    
    	//Return a dispatchId matching the Names.
    	virtual STDMETHODIMP GetIDsOfNames( REFIID, OLECHAR**, UINT, LCID, DISPID*);
    	//Handle calls to window extern, through dispacth::Invoke
    	STDMETHODIMP Invoke( DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*);
    
    public :
    	XMLDispatch();
    };
    
    CComPtr<IDispatch> pIDispatch( new XMLDispatch );
    NET_ProcesInteropInit(pIDispatch);

     

    Monday, October 18, 2010 3:19 PM

All replies

  • Hello Rolf,

    1. >> When the .NET dialog calls InvokeMember then a new thread is started which executes the method.

    >> Any idea how we make the .NET dialog call the COM interface without starting a new thread ?

    Just some points of clarification :

    1.1 I assume that you mean that whenever the .NET dialog calls InvokeMember(), the target COM method executes on a thread that is different from the one that the dialog box is running in. Pls let me know if this understanding is correct.

    1.2 If point 1.1 is correct, then is the thread (that the target COM method executes in) always the same one (albeit different from the one that the .NET dialog executes in) or may be a different one ?

     

    2. Note that the thread that a COM method executes in depends on the apartment type of the object.

    2.1 If your COM object is a Single-Threaded Apartment (STA) object then it will always execute on the same thread : the STA thread in which it is instantiated. Hence whenever the .NET dialog executes its methods (via InvokeMember()), it will execute on the same thread. This thread may be the thread in which the .NET dialog executes in.

    2.2 If the object is a Multi-Threaded Apartment (MTA) object then it may execute on any of the threads of the MTA of the current application. This thread may also be a .NET thread too.

     

    3. >> Other ideas for how to communicate between the native world and the .NET world are also very welcome.

    3.1 I'll continue with this question in another post.

     

    - Bio.

     

    Monday, December 27, 2010 11:41 AM
  • Hello Rolf,

    On the declaration of the IDispatch interface in your C# code :

    1. You have declared it but the code you have shared with us so far has not demonstrated any use of it.

    2. In actual fact, you do not need to define the IDispatch interface in your C# project unless you intend to derive a C# class from it.

    3. To call the IDispatch methods of a COM object, you can use the Type::InvokeMember() method just as you have done so in the NET_Process::InvokeMember() method :

    objectOut = m_IDispatch.GetType().InvokeMember(funcName, System.Reflection.BindingFlags.InvokeMethod, null, m_IDispatch, args);

    4. In fact m_IDispatch need not be declared as of type IDispatch. It can also be declared as type Object, e.g. :

    Object m_IDispatch;

    5. A small modification of the Init() method is recommended :

            public void Init(System.IntPtr testPtr)
            {
                m_IDispatch = Marshal.GetObjectForIUnknown(testPtr);
            }

    Yes, remove the cast to IDispatch.

    6. You can use the IDispatch interface of course. But it can be rather cumbersome.

     

    - Bio.

     

    Tuesday, December 28, 2010 5:51 PM
  • Hello Rolf,

    Concerning other ways besides COM interop to communicate between the native world and the .NET world, here are the techiniques that I am aware of :

    1. P/Invoke.

    2. Marshal.GetDelegateForFunctionPointer(). Here is a link that explains this technique in more detail : http://blogs.msdn.com/b/junfeng/archive/2004/07/14/181932.aspx

     

    - Bio.

     

     

    Wednesday, December 29, 2010 2:17 PM