Click here to Skip to main content
15,867,568 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I have a working project in c++ using a library done in c++ and partially c.

Now I have the use case where I need to interact with (corrected after spotting a missunderstanding) my c++ project using that library from c#.
I just added the files and the needed #includes to my first project, then I wrote my code using the lib functionality directly, that's why I chose C++ in the first place, to make it easier to interact with.

I have been researching a bit and based on a couple of things I found, I think the easiest way to do that with the fewest changes to the original library is using a wrapper in CLI.

But being honest...
I have never done this before and I haven't tried many things yet, because I don't want to loose time that I don't have. I would like to know if it might be done as I think or if there is a better way to do it. So the "what have you tried" below should be renamed "what have you thought" in this case...

I am using Visual Studio 2017 professional

What I have tried:

I am thinking on one VS-Solution with 3 Projects.

Project 1: C++
Library Files (2x .cpp, 8x .h and 1x .c)
MyAlreadyWorkingCode (1x .cpp, 1x .h)
MyNewConnectingCodeForCli (1x .cpp, 1x .h)

Project 2: CLI
CallerForCpp (1x .cpp, 1x .h)

Project 3: WPF
MyApp.xaml, MyApp.cs
ExternalTriggersManagement.cs
CallerForCLI.cs


###############################################

- The app will mostly react to extern triggers (process start and process end) and the GUI will mainly be used to show info about current and previous process.
- In case of external trigger process end (or manual request / click from user under certain circumstances) the correspondent function in CallerForCLI.cs will be called
- CallerForCPP will get the call from c# and forward it to MyNewConnectingCodeForCLI
- MyNewConnectingCodeForCLI will then use my already working c++ functions to make use of the library and generate the desired result.


Things I am not 100% sure yet:
- I have to declare the functions in MyNewConnectingCodeForCLI.h with __declspec to be visible from the outside but if I do an #include MyAlreadyWorkingCode.h in the MyNewConnectingCodeForCLI.cpp I should be able to use my existent functionality as usual without having to change the already working code. Or am I wrong?
- The CLI Project must be configured as dynamic library and with CLR support. And I suppose the CPP Project too
- I have to compile to be "delay-loaded" using a linker flag from CLI to CPP to avoid unresolved dependencies and then load / initialize the cpp.dll within the CLI before using its functionality
[ADDED]
- One of the few things I need to move from c# to c++ is a string so I will need to Marshal it. I am currently using a CString in the c++, I might change that to increase compatibility. What do you think would be the most compatible usage to reduce complexity in the marshal?

Do you think it is a good approach?
Comments and corrections are welcome.

---------
Addition after solution #1 and #2:
The Link that got me to ask about the above structure is: Using C++ in C# by Example « Programming Blog[^]. It seem not be using the "standard" ways. What do you think about?

EDIT:
I think this method might work if all source codes are in the same solution and can be compiled together. But I never saw it. That's why I asked.

I found another reference here in CP talking about wrapping c++ with cli: Quick C++/CLI - Learn C++/CLI in less than 10 minutes[^]

--------
2nd addition after comments and edit by Richard
My C++ solution generates a file and fills it with data acquired from the process. It has its own logging system and other features.
Now I have to use part of its functionality in other place, where the filename depends on another system. I want my new C# App to get the needed information from the other system (provider software, no access to code and very limited changes possible), compose the filename and send it to the C++ (one of the few data to be exchanged) project, where it will be used to generate the correspondent file with the needed content.

As I continue reading about the topic and due to some of the comments below, I start to think that re-writing my C++ Project and completelly transform it in a DLL might have its advantages regarding portability and usability by other constellations. If not I might end having to maintain parallel projects with the same sources, if it is successfull and the usage spreads
Posted
Updated 2-Aug-19 3:53am
v9

Take a look at Calling Native Functions from Managed Code | Microsoft Docs[^].


A very simple example:

UserDll.h

C++
#pragma once

#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>
#include <stdio.h>

// 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 USERDLL_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 
// USERDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef USERDLL_EXPORTS
#define USERDLL_API __declspec(dllexport)
#else
#define USERDLL_API __declspec(dllimport)
#endif

extern "C" USERDLL_API char* __stdcall UserTest(char* s);


UserDll.cpp

C++
// UserDll.cpp : Defines the exported functions for the DLL application.
//

#include "UserDll.h"
#include <string>


// This is an example of an exported function.
char* __stdcall UserTest(char* s)
{
    printf("received from C#: %s\n", s);
    
    char* cp = new char[64];
    strcpy(cp, "The rain in Spain falls mainly in the plain");
    
    return cp;
    }



UserDll.cs

C#
using System;
using System.Runtime.InteropServices;
using System.Text;

namespace PInvoke
{
    class UserDll
    {
        [DllImport("UserDll")]
        static extern IntPtr UserTest(string s);
        
        public static void Test()
        {
            IntPtr ip = UserTest("A message from C#");
            string ss = Marshal.PtrToStringAnsi(ip);
            Console.WriteLine("returned from C++: {0}", ss);
        }
    }
}
 
Share this answer
 
v2
Comments
Nelek 2-Aug-19 5:19am    
I had already been a while in that link, but it only explains how to call native from managed c++, having the functionality of .Net.

But I want to interact with the native from WPF and the CLI would be only a "call forwarder"
Richard MacCutchan 2-Aug-19 5:22am    
Pinvoke can be used from any .NET code to call native libraries. There is even a Pinvoke website which gives calling sequences for all standard Windows library functions. I have done it myself as an exercise calling Windows functions, and my own C/C++ library.
Nelek 2-Aug-19 5:35am    
Then I had understood it wrongly. I will have a closer look. Thanks
Nelek 2-Aug-19 6:35am    
To avoid repeating myself I have added info to the question
Richard MacCutchan 2-Aug-19 7:46am    
That link seems to be taking a more comprehensive approach by building the two halves together. But if you already have the C++ dll you just need to add the code in your C# module to make the P/Invoke calls. See my updated solution for my very basic example.
You might find this article interesting: C++/C# interoperability[^]
Also recent Visual Studio versions handle C++ dll's a lot better than before and can automatically generate "Interop" dll's.
What Visual Studio uses under the hood is Tlbimp.exe (Type Library Importer)[^]
Another option might be to create a REST API, see: GitHub - microsoft/cpprestsdk[^]
And also this CodeProject article: Take a REST : A Windows C++ Library for Quick Web Interfaces Interaction[^]
But this will probably be even more complex and not worth the effort if you don't need network communication.
 
Share this answer
 
v4
Comments
Nelek 2-Aug-19 5:37am    
Thank you for the link.

At least I am a bit lucky, since I don't have to share any data, it is enough for me to give some things as parameters in the functions. The rest is not dependent from each other.
Nelek 2-Aug-19 6:35am    
The Link that got me to ask about the above structure is: Using C++ in C# by Example « Programming Blog[^]. It seem not be using the "standard" ways. What do you think about?
RickZeeland 2-Aug-19 6:57am    
Interesting article, but as I never used C++ CLR I can't say much about it. We usually receive 3rd party C++ dll's that are part of some SDK and then have to write a wrapper around that.
Nelek 2-Aug-19 7:08am    
To avoid repeating myself in the comments, I just added the info to the question. This way other readers will get all the "bits"
Nelek 3-Aug-19 15:45pm    
I have seen the new Links (Edit 4). I don't think REST is going to be helpful for me in this case. If I had the need of network communication I think I would go for sockets instead (we already have a "Server" App managing other things)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900