Click here to Skip to main content
14,330,663 members
Rate this:
Please Sign up or sign in to 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
Rate this:
Please Sign up or sign in to vote.

Solution 1

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


A very simple example:

UserDll.h

#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

// 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

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);
        }
    }
}
   
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.
Nelek 2-Aug-19 9:24am
   
I don't have a C++ Dll... I have a VC++ Console Project that is already working as stand alone solution (MyAlreadyWorkingCode.exe), whose functionality have to be used in a new place with a c# GUI

That's why I would like to touch as few as possible from the working code. So it is easier to check for differences when updating a part. But I am starting to think on doing it a stand alone DLL (in the way you told me) so that I am more flexible for future changes in one place or another.

I am editing the Question to give some more info
Richard MacCutchan 2-Aug-19 9:39am
   
"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 that library from c#."


I assumed (maybe wrongly) that the library is a dll.
Nelek 2-Aug-19 9:42am
   
If you see the first part of the "What have you tried", the Library are source files (8x .h, 2x .cpp and 1x .c). The C code being used internally in the C++ of the library.
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.

That's what I tried to describe above with that "project X" info.

But I admit... there is need of a correction (added above too):
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 my c++ project using that library from c#."
Richard MacCutchan 2-Aug-19 9:57am
   
Sorry, but now I am even more confused. You cannot use C# code to access functions inside a C/C++ executable, unless it expose everything via COM.

If you are just trying to send data to the other program then you can use sockets/IPC/shared memory etc.
Nelek 2-Aug-19 14:36pm
   
I don't know where I lost you and I have the impression that with every try to explain it, you are getting even more lost.


I don't want to access the exe. I don't have any external DLL or separated exes. I have ALL source codes of the working project in C++.
On the other hand I have to program a C# app where I would have to do the same as in my C++ project, and the library to do that is in c++ (integrated in my c++ as source code, where I can use the #include an call the methods directly).

I just search for the easiest / less unnecessary re-working method to be able to trigger the functionality contained in my C++ project, from the C# project. That's why I thought that the wrapping trick could do it.

Please look at the "What have I tried". 1 solution with 3 Projects (each in a language), ALL in source codes, no dlls and no exes, ALL compiled together.
Richard MacCutchan 3-Aug-19 3:12am
   
"I just search for the easiest / less unnecessary re-working method to be able to trigger the functionality contained in my C++ project, from the C# project. That's why I thought that the wrapping trick could do it."

Then all you need is what I suggested at first. Build the C++ library into a DLL and use P/Invoke to access it from the C# code. Assuming that everything needed by the C# app is already in the library code, then converting it to a DLL (presumably it is currently a static library) will not require any changes to the C++ application.
Nelek 3-Aug-19 7:50am
   
I'll give it a try.

Thank you for your time
Richard MacCutchan 3-Aug-19 9:40am
   
No problem, I hope you can resolve it one way or another.
Nelek 3-Aug-19 15:41pm
   
Me too :)
Nelek 2-Aug-19 14:40pm
   
By the way... thanks for the time you are investing in trying to help me :) And sorry if I can't explain you the things as you need.

It is a bit frustrating but I appretiate your effords. Please don't think I am getting pissed off
Rate this:
Please Sign up or sign in to vote.

Solution 2

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.
   
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)
RickZeeland 3-Aug-19 16:37pm
   
Well, we can't be all hip and trendy ;)

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




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100