locked
How To called Managed Code from Unmanaged Code ? RRS feed

  • Question

  • Hello,
     
           I want to know that is there any mechanism by which i can call my managed code(DLL which i developed using C#) into Unmanaged Code (Means my VC++ Application).
          
           Ur viewed Welcomed (prakash_paghdal@hotmail.com)

                    Thanks in Advanced....

    Thursday, November 17, 2005 6:36 AM

All replies

  • Hi Prakash,

    I have shifted your thread to the C# General forum since that's the right forum for your question.

    Generally you can register your managed Dll with COM and then use VC++ to call on the COM objects which inturn invoke your managed functions.
    Unless you are using C++/CLI (also called as Managed C++), then there are options with which you can communicate with both managed and unmanaged Dll's.

    VC++ forums might be a better place to inquire more about this kind of usage.

    Regards,
    Saurabh Nandu
    www.MasterCSharp.com

    Friday, November 18, 2005 9:19 AM
  • I just suffered through this experience in Visual Studio 2003. In general it is very easy, but there are a few tricks. There is an interesting article that shows a very simple way to do it: "A client in Managed Extensions for C++" on MSDN - see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptutorials/html/clients_for_the_simple_components.asp

    I first created a C# class in its own DLL. I then isolated all calls to this DLL (creating instances of the C# class) in a single source file in my C++ app. Then most of what you have to do is turn on the /clr compile switch for that single source file. Don't do it for the whole app (yet) since there are side effects to turning your whole app into managed code. Set the following compile properties of the single C++ source file:

    // NOTE: You MUST compile THIS FILE ONLY with the following settings in the .VCPROJ file:
    RelativePath="ExtractPatientInfo.cpp">
        <FileConfiguration
            Name="Debug|Win32">                    // These settings must be true for ALL BUILDS
                <Tool
                    Name="VCCLCompilerTool"

    BasicRuntimeChecks="0"            // CRITICAL - forced by /clr incompatibility with /RTC1
                // Do NOT select "Both"
                // This is in the file properties dialog under
                // Configuration Properties | C/C++ | Code Generation | Basic Runtime Checks
                // Select "default"
    UsePrecompiledHeader="0"        // CRITICAL or you'll get lots of errors.
                // Do NOT select "Use Precompiled Headers"
                // This is in the file properties dialog under
                // Configuration Properties | C/C++ | Precompiled Headers | Use Precompiled Headers
                // select "Not Using Precompiled Headers"
    DebugInformationFormat="3"/>    // CRITICAL - so debugger can still see info
                // (Edit and Continue won't work in Managed land -
                // do NOT select "Program Database For Edit And Continue")
                // This is in the file properties dialog under
                // Configuration Properties | C/C++ | General | Debug Information Format
                // select "Program Database"
    CompileAsManaged="2"/>            // CRITICAL in order to use .Net Framework
                // Do NOT select "Not using managed extensions"
                // This is in the file properties dialog under
                // Configuration Properties | C/C++ | General | Compile As Managed
                // select "Assembly Support" - this defines /clr

    At the top of the single C++ file that calls C# you must include the following:
    // Needed for Interop with C#
    #ifdef _MANAGED // the ifdef isn't strictly necessary, but is in case you make a mistake

    #using <mscorlib.dll>
    using namespace System;
    #ifdef _DEBUG
    #using "debug\H3Plus.dll"      // the name of your C# DLL goes here
    #else
    #using "release\H3Plus.dll"
    #endif // #ifdef _DEBUG
    // Do NOT set /clr at the project level or you will surely get lots of warnings (you would
    // also turn the entire program into Mananaged C++).
    #endif // #ifdef _MANAGED

    #ifdef _DEBUG
    #ifndef _MANAGED
    // gotta comment this out for Interop with C#
    #define new DEBUG_NEW
    #endif // #ifndef _MANAGED
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif // #ifdef _DEBUG


    I then had a function that created an instance of a C# class.

        // use gcroot to make sure the garbage collector doesn't move or delete it
        // until we're done with it. One of the nicest things about GCHandle (template-ized
        // via gcroot) is that it allows you to keep all types of references, including pinned
        // and weak references.
    #ifdef _DEBUG    // gcroot prevents debugger from seeing inside pInfo
            MyNamespace::MyClass* pInfo = MyNamespace2::MyClass2::MyFunct(sPath);
    #else
            gcroot<MyNamespace::MyClass*> pInfo = MyNamespace2::MyClass2::MyFunct(sPath);
    #endif // #ifdef _DEBUG
    CString sTemp = pInfo->Data.LastName; // works just fine


    When crossing the Managed / Unmanaged boundary you have to be aware of marshalling different data types (CString from Unmanaged becomes .Net string on the Managed side). Although I got lucky in the above that it handled the CString / string conversion automatically.

    The one thing I found out the hard way was to be careful about include files, especially if they bring in .INL inline files with inline functions. Those inline functions, when compiled within the single Managed C++ file, will be compiled as Managed code too, and then when they are called in OTHER files they will also be Managed. This becomes a speed problem because you cross the Managed / Unmanaged boundary  (and my inline functions were called a LOT, so it really slowed things down).

    One other issue is using the debugger. In the project properties dialog, go to Configuration Properties | Debugging and look at the Debugger Type. If you want to debug BOTH the C++ side and the C# side in the same session, you must set the debugger to Mixed, but be aware that this will run very slowly. If you are usually just debugging C++, set it to Native, which runs much quicker (but you can't step into C# code anymore).

    Hope that gets you started!

    Friday, November 18, 2005 3:58 PM
  • Another note: I discovered that when the CLR gets called (when you invoke Managed / C# code), this will by default initialize COM and OLE to the MTA (multithreaded apartment) model. This may not be an issue for you, but I was using the Microsoft MSFlxGrd.ocx control that expected to be running in STA (single threaded apartment) mode.

    The solution is to initialize the COM model to STA before the Framework gets a chance. See the second question in Paul DiLascia's column in March 2005 MSDN Magazine at http://msdn.microsoft.com/msdnmag/issues/05/03/CATWork/.

    Friday, November 18, 2005 4:04 PM