Freigeben über


How to call C++ code from Managed, and vice versa (Interop)

Interop - calling native (C++) code from managed (C#, VB, J#, MC++) and vice versa - can be very useful if you are trying to extend your libraries without porting existing code. However, it can often be confusing for a newbie to figure out how to set this up.

There are several ways in which you could accomplish this.

(a) Using COM-Interop
(b) Using imports/pinvoke (explicit method calls)
(c) IJW and MC++ apps :   MC++ & IJW apps can freely call back and forth to each other.
(d) Hosting. This is rare, but the CLR can be hosted by an unmanaged app which means that the runtime invokes a bunch of hosting callbacks.

Here is how (a) works:

For Native Exe->Managed Dll

(a)     define C# (VB, J#) class with a public interface, and build the file as dll
(b)     run regasm on the dll to create the tlb file
(c)     define C++ code which #imports the type library and creates the C# dll’s interface object using CoCreateInstance() and then calls methods through that.

For managed client->Native Dll

(a)     create C++ Dll
(b)     Create managed exe, add a reference to the Native COM Dll
(c)     Create the Com object and call the methods.

Here are code samples for the cases

Native Exe calling Managed Dll

Dll code is (filename CSDll.cs)

using System;
using System.Collections.Generic;
using System.Text;
namespace CSDll
{
    using System;

    [System.Runtime.InteropServices.Guid("D4660088-308E-49fb-AB1A-77224F3FF851")]
    public interface IMyManagedInterface
    {
        int factorial(int arg);
    }

    /// <summary>
    ///    Summary description for Class1.
    /// </summary>
    [System.Runtime.InteropServices.Guid("46A951AC-C2D9-48e0-97BE-91F3C9E7B065")]
    public class Class1 : IMyManagedInterface
    {
        public Class1()
        {
        }

        public int factorial(int arg)
        {
            int result;

            if (arg == 1)
            {
                result = arg;
            }
            else
            {
                result = arg * factorial(arg - 1);
            }

            return result;
        }

    }
}

Compile this with "csc /debug /t:library csdll.cs" to build a dll with symbol info.
Now run "regasm csdll.dll /tlb:csdll.tlb" to create the type library

C++ code is as (filename cppexe.cpp)

#include "windows.h"
#include <stdio.h>
#import "CSDll.tlb" named_guids

int main(int argc, char* argv[])
{
    HRESULT hRes = S_OK;
    CoInitialize(NULL);
    CSDll::IMyManagedInterface *pManagedInterface = NULL;

    hRes = CoCreateInstance(CSDll::CLSID_Class1, NULL, CLSCTX_INPROC_SERVER, 
     CSDll::IID_IMyManagedInterface, reinterpret_cast<void**> (&pManagedInterface));

    if (S_OK == hRes)
    {
        long retVal =0;
        hRes = pManagedInterface->raw_factorial(4, &retVal);
        printf("The value returned by the dll is %ld\n",retVal);
        pManagedInterface->Release();
    }

    CoUninitialize();
    return 0;
}

Build this with "cl /Zi cppexe.cpp" -> when you run the exe it should print the value 24.

To debug this app, open the exe as a project in Visual Studio. Then go to project->properties->configuration prop->debugging and set debugger type to Mixed. Now when you debug, you should be able to step into the managed dll code from the calling C++ exe.

Managed Exe calling Native Dll

(a) Create an Atl COM Dll from wizard say Atl Dll
(b) Add an ATL Simple Object AtlObj
(c) Add a method to AtlObj say factorial(), you will need to add it to the .idl file to expose it from the COM object
(d) Create a C# console app
(e) project->right click->Add Reference
(f) In the add reference dialog, select the COM tab, find your COM component and add the reference to it
(g) You can now create the AtlObj object as of any other class and call its methods.

You can also accomplish this without using COM by simply using exports/imports.

Managed Exe calling Native Dll using import

(a) Create a Win32 Dll that exports symbols, you can do this from the wizard, just make sure the "export symbols" checkbox is checked.
(b) You need to put extern "C" {} around the definition & declaration of the exported function say fnWin32Dll()
(b) Now create your C# Exe, add using System.Runtime.InteropServices;
(c) add code

   [[DllImport("Win32 Dll.dll")]
   public static extern int fnWin32Dll(); ' this is the C++ function exposed by the dll

(d) Now you can just call the function in your code
   int var = fnWin32Dll();

Note that your C# Exe needs to be able to find the Dll. You can copy the Dll next to the C# Exe and it will run just fine.

These are the most common ways of making cross-language calls, I will follow up later with explanations and examples of the other ways you can make these calls.

Comments

  • Anonymous
    June 26, 2005
    Question: Is there a way to call a native .exe (MFC in this case, and I don't have the source for the app) from managed code? I'm writing a managed winforms app and I need to wrap up the functionality of a standalone .exe in my project.

    thanks.

  • Anonymous
    June 28, 2005
    Hi X.Static,

    There is no way to call functions in a random exe. This is just the way executables have been designed, it could cause plenty of trouble if any exe could call into any other.

    In order for two executables to communicate they have to be designed that way from scratch.

    You can
    (a) Create a COM Exe, its exposed functions can be called by another Exe
    (b) Have one exe write to a port while another reads from it and executes the commands received from the other exe
    (c) Have one exe write to a file (not very sophisticated but completely feasible) while another reads from it and executes commands accordingly.

    Regards,
    D.V.

  • Anonymous
    January 21, 2009
    PingBack from http://www.hilpers.it/1860341-mixare-codice-managed-e-unmanaged

  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/671065-is-is-possible-to-call