locked
C++ APP class access from C# class RRS feed

  • Question

  • I have the following code:

    (A) In MyUnmanaged.exe:

    (a) declare Unmanaged_Struct.h:

    class CMyUnmanagedData
    {
    public:
        void get_SomeData(...);
    };


    (b) inplement CallManagedCode.cpp:  (/clr)

    #include "Unmanaged_Struct.h"

    extern void call_unmanaged_code()
    {
        CMyUnmanagedData unmanaged_data;
        // fill in unmanaged_data

        MyManagedProj::CMyManaged^ obj = gcnew MyManagedProj::CMyManaged();
        // TODO: find a way to pass unmanaged_data.get_SomeData() into obj

    }

    (B) In MyManagedProj.cs:

    (a) implement CMyManaged.cs:

    namespace MyManagedProj
    {
        public class CMyManaged
        {
            public void access_UnmanagedStruct()
            {
                // TODO: call CMyUnmanagedData::get_SomeData()
            }
        };
    };

    Most of the coding suggestions I've seen are to convert the C++ code to an export-dll and import to the C# project. However, in my case the C++ code is in a .exe, so I am a bit stuck on how to solve this problem in a "clean" way, e.g. through a C# wrapper class etc. with almost no alternation to the original CMyUnmanagedData class.

    The "alternative" aproach is to write a C# mirror version of CMyUnmanagedData (e.g. CMyManagedData), copy the content from CMyUnmanagedData to CMyManagedData, and finally pass CMyManagedData to MyManagedProj.CMyManaged. But this approach is just ugly and I really don't perfer it.

    Sunday, August 7, 2016 1:48 PM

Answers

  • >Most of the coding suggestions I've seen are to convert the C++ code to an export-dll and import to the C# project. However, in my case the C++ code is in a .exe,

    You can reuse the C++ code in a DLL. 

    David


    David http://blogs.msdn.com/b/dbrowne/

    • Proposed as answer by Hart Wang Monday, August 8, 2016 1:25 PM
    • Marked as answer by DotNet Wang Wednesday, August 17, 2016 5:51 AM
    Sunday, August 7, 2016 2:28 PM
  • 4. Write a C++/CLR assembly that exposes managed wrapper types, written in C++ and natively accessing the existing C++ compilation units.

    David


    David http://blogs.msdn.com/b/dbrowne/

    • Proposed as answer by Hart Wang Monday, August 8, 2016 1:25 PM
    • Marked as answer by DotNet Wang Wednesday, August 17, 2016 5:51 AM
    Sunday, August 7, 2016 3:26 PM

All replies

  • >Most of the coding suggestions I've seen are to convert the C++ code to an export-dll and import to the C# project. However, in my case the C++ code is in a .exe,

    You can reuse the C++ code in a DLL. 

    David


    David http://blogs.msdn.com/b/dbrowne/

    • Proposed as answer by Hart Wang Monday, August 8, 2016 1:25 PM
    • Marked as answer by DotNet Wang Wednesday, August 17, 2016 5:51 AM
    Sunday, August 7, 2016 2:28 PM
  • There are 3 ways to use DLL's in .NET:

    1. Use a .NET DLL. This can include a .NET wrapper DLL around other two approaches, but just having a .NET DLL is usually the best.
    2. Use COM interop. COM was the direct predecessor of .NET and such massive work has been done to make both able to interoperate.
    3. Use P/Invoke. This is the ultimative fallback.

    However, unless you have a .NET DLL you will have to deal with unmanaged code. Wich can quickly get you into all those issues with pointers and binarity the .NET Developers were smart enough to avoid (I worked with native C++, I know it's strenght and it's weakpoints).

    What exactly is that native C++ DLL/exe doing? Could you replicate it in .NET?

    • Proposed as answer by Hart Wang Monday, August 8, 2016 9:25 AM
    Sunday, August 7, 2016 3:12 PM
  • 4. Write a C++/CLR assembly that exposes managed wrapper types, written in C++ and natively accessing the existing C++ compilation units.

    David


    David http://blogs.msdn.com/b/dbrowne/

    • Proposed as answer by Hart Wang Monday, August 8, 2016 1:25 PM
    • Marked as answer by DotNet Wang Wednesday, August 17, 2016 5:51 AM
    Sunday, August 7, 2016 3:26 PM
  • Hi,

    Thank you for posting here.

    I have one demo that call native dll from C# code. you can refer to the demo to write your code.

    Native.cpp file:

    // NativeDLL.cpp : Defines the exported functions for the DLL application.
    //
    
    #include "stdafx.h"
    #include "NativeDLL.h"
    
    
    
    // This is an example of an exported variable
    extern NATIVEDLL_API int nNativeDLL = 45;
    
    // This is an example of an exported function.
    extern NATIVEDLL_API int fnNativeDLL()
    {
    	return 42;
    }
    
    // This is the constructor of a class that has been exported.
    // see NativeDLL.h for the class definition
    CNativeDLL::CNativeDLL()
    {
    	return;
    }
    
     NATIVEDLL_API int CNativeDLL::addnumber_export_three(int A, int B, int C)
    {
    	return A + B + C;
    }
    
    NATIVEDLL_API string CNativeDLL::export_string(string str)
    {
    	return str;
    }
    
    extern "C" NATIVEDLL_API int export_addnumber_three(int a, int b, int c)
    {
    	//CNativeDLL A;
    	return CNativeDLL::addnumber_export_three(a, b, c);
    }
    
    // LP_MYPERSON structure_pass(LP_MYPERSON  persion)
    //{
    //	LP_MYPERSON a;
    //
    //	a->first = persion->first;
    //	a->last = persion->last;
    //
    //	return a;
    //}
    
    extern "C" NATIVEDLL_API int TestStructInStruct(MYPERSON2* pPerson2)
    {
    
    	return 115;
    }

    Native.h file

    // The following ifdef block is the standard way of creating macros which make exporting 
    // from a DLL simpler. All files within this DLL are compiled with the NATIVEDLL_EXPORTS
    // symbol defined on the command line. This symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see 
    // NATIVEDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
    // defined with this macro as being exported.
    #include "stdafx.h"
    #ifdef NATIVEDLL_EXPORTS
    #define NATIVEDLL_API __declspec(dllexport)
    #else
    #define NATIVEDLL_API __declspec(dllimport)
    #endif
    
    
    typedef struct _MYPERSON
    {
    	char* first;
    	char* last;
    } MYPERSON, *LP_MYPERSON;
    
    typedef struct _MYPERSON2
    {
    	MYPERSON* person;
    	int age;
    } MYPERSON2, *LP_MYPERSON2;
    
    typedef struct _MYPERSON3
    {
    	MYPERSON person;
    	int age;
    } MYPERSON3;
    
    typedef struct _MYARRAYSTRUCT
    {
    	bool flag;
    	int vals[3];
    } MYARRAYSTRUCT;
    
    
    
    
    // This class is exported from the NativeDLL.dll
    class NATIVEDLL_API CNativeDLL {
    public:
    	CNativeDLL(void);
    	// TODO: add your methods here.
    	 static int addnumber_export_three(int A, int B, int C);
    	static string export_string(string str);
    
    };
    
    
    extern "C" NATIVEDLL_API int nNativeDLL;
    
    extern "C" NATIVEDLL_API int fnNativeDLL();
    
    extern "C" NATIVEDLL_API int export_addnumber_three(int a, int b, int c);
    
    extern "C" NATIVEDLL_API LP_MYPERSON structure_pass(LP_MYPERSON * persion);
    
    extern "C" NATIVEDLL_API int TestStructInStruct(MYPERSON2* pPerson2);
    


    C# code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    
    
    
    using System.Runtime.InteropServices;
    
    
    
    
     namespace ConsoleApplication8
    {
    
    
        //class Program
        //{
        //    // [DllImport("NativeDLL.dll", EntryPoint = "addnumber_export_three")]
        //    [DllImport("NativeDLL.dll")]
        //    public static extern int addnumber_export_three(int A, int B, int C);
    
        //    public static void Main(string[] args)
        //    {
        //        int b = addnumber_export_three(1, 2, 3);
        //    }
        //}
    
    
        class PlatformInvokeTest
        {
            [DllImport("msvcrt.dll")]
            public static extern int puts(string c);
            [DllImport("msvcrt.dll")]
            internal static extern int _flushall();
    
            [DllImport("NativeDLL")]
            public static extern int export_addnumber_three(int A, int B, int C);
            [DllImport("NativeDLL")]
            public static extern int fnNativeDLL();
    
            //[DllImport("Kernel32.dll")]
            //public static extern void  GetSystemInfo( LPSYSTEM_INFO lpSystemInfo);
    
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            public struct MyPerson
            {
                public string first;
                public string last;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct MyPerson2
            {
                public IntPtr person;
                public int age;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct MyPerson3
            {
                public MyPerson person;
                public int age;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            public struct MyArrayStruct
            {
                public bool flag;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
                public int[] vals;
            }
    
    
    
           [DllImport("NativeDLL.dll")]
            public static extern int TestStructInStruct(MyPerson2  person2);
    
           
    
            [DllImport("Cpp.dll")]
            public static extern int getStuNumber(int i);
    
            public static void Main()
            {
             //   puts("Test");
              //  _flushall();
    
                MyPerson2 personAll;
                personAll.age = 30;
    
                MyPerson Person;
                Person.first = "sdada";
                Person.last = "over";
    
                IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(Person));
                Marshal.StructureToPtr(Person, buffer, false);
    
                personAll.person = buffer;
    
           
    
             int res = TestStructInStruct(personAll);
    
    
                int b = getStuNumber(2);
                int C = fnNativeDLL();
              
                int g = export_addnumber_three(1, 2, 3);
    
                Console.Write("res={0} \n", res);
    
    
    
            
            }
        }
    
    
    
    }
    

    You can cope these file, than compile it into dll file, than call dll file from the C# code.

    If your issue has been resolved, please remember to close your thread by marking useful post as answer.

    Your cooperation will be grateful.

    Best Regards,

    Hart


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place. Click HERE to participate the survey.

    • Proposed as answer by Hart Wang Monday, August 8, 2016 9:26 AM
    • Unproposed as answer by Eyal Solnik Saturday, October 1, 2016 9:08 AM
    Monday, August 8, 2016 9:25 AM