Search code examples
c#.netatlcom+

CoInitializeSecurity for managed application, creating a shim?


I am currently researching the problem of setting com+ security context to: None for the managed winforms process.

In .NET it is impossible to set CoInitializeSecurity as the first line of the code after Main, too late to do it. That method is already invoked by CLR as I understood.

In the link below: http://www.pinvoke.net/default.aspx/ole32.coinitializesecurity

It is written:

"The workaround is to write an unmanaged "shim" that will call CoInitializeSecurity, then activate and call into managed code. You can do this via an export from a mixed-mode C++ DLL, by registering a managed component for use by COM, or by using the CLR hosting API."

Could someone shed some light on this? How should that be written in unmanaged code (language doesn't matter)

The managed application calls com+ server from time to time and I don't see any reason why I should activate the interface straightaway to pass the pointer to managed code?


Solution

  • The workaround is to write an unmanaged "shim" that will call CoInitializeSecurity, then activate and call into managed code. You can do this via an export from a mixed-mode C++ DLL, by registering a managed component for use by COM, or by using the CLR hosting API.

    What this means is that you create a very small native .exe ("Shim") say in c/c++ that calls CoInitializeEx() followed by a call to CoInitializeSecurity as a way to establish the COM security environment for the entire Windows process.

     ----------------------------------
    | Windows Process                  |
    |  -----------         ----------  |
    |  |   exe   |   COM   |  dll   |  |
    |  | "Shim"  |  ====>  |        |  |
    |  | (c/c++) |         |   c#   |  |
    |  -----------         ----------  |
     -----------------------------------
    

    Code:

    // pseudo c++ code
    .
    .
    .
    int main (int argc, char* argv)
    {
        CoInitializeEx(...);
        CoInitializeSecurity(...);
    
        IMyContractPtr pFoo (__uuidof (MyClass));
        pFoo->RunMe();
    
        CoUnitialize();
    }
    

    With that in place, the next trick is to invoke your .NET code from c/c++. The easiest thing to do here is to make a ComVisible(True) c# class, expose a method to COM, say RunMe() that, when invoked displays your WinForms form.

    public interface IMyContractPtr 
    {
        void RunMe();
    }
    
    [ComVisible(true)]  // there are cleaner ways to expose COM-visible 
    public class MyClass : IMyContractPtr 
    {
       public void RunMe()
       {
           var form = new MainForm();
           form.ShowDialog(); // example
       }
    }
    

    You'll need to move your code from your c# .exe project into a new c# assembly/library. It is this library that will be exposing the COM-visible class that will be called from your c/c++ app. (though the c/c++ app won't care whether it is in a COM exe or dll, for this excerise you don't want to confuse the issue by attempting to load another .exe into an already running Windows process)

    Message Pumps and Dialogs

    I've simplified things a bit here by making the main window a modal dialog. Modal dialogs have their own Windows Message Pump processing, something we have ripped out by placing your forms code into a dll and discarding your original program's Main() method and the goodness that is Application.Run(new MainForm());.

    Tell me more