0

I am doing a POC where I need to invoke a c# method from a c++ application. So I did the following:

  1. Create a c# library.
  2. Create a c++/cli library wrapping the dll from step 1.
  3. Creating a c++ library that would consume cli wrapper.
  4. Creating an unmanaged console application that would use c++ dll output from step 3.

Guys, I have done a lot of searches in last days but did not get any useful help.

  1. Created the c# project with output: DotNetLogger.dll
  2. Created the c++/cli project with output: CliLogger.dll Also referenced DotNetLogger.dll Also exported a method.
  3. Create C++ project with output CppLogger.dll and so on.

Also, C# project setting: v4.6.2 C++/CLI project settings: /CLR enabled with v4.6.2 C++ project setting: no /clr

namespace DotNetLogger
{
    public class ManagedLogger
    {
        public void Ping()
        {
          //Do something
        }
    }
}

using namespace System;
using namespace DotNetLogger;

namespace CliLogger {
    public ref class LoggerBridge
    {
    public:
        ManagedLogger^ obj;
        LoggerBridge() {
            obj = gcnew ManagedLogger();
        }
        void Result() {
            return obj->Ping();
        }
    };
}

__declspec(dllexport) void AreYouThere() {
    CliLogger::LoggerBridge obj;
    return obj.Result();
}

#pragma once

#include "D:\Logger_POC_NoWorks\InteropLogger\CliLogger\CliLogger.h"

__declspec(dllimport) void AreYouThere();

class UnmanagedLogger {
public:
    void InvokeResult() {
        return AreYouThere();
    }
};


#include "pch.h"
#include <iostream>
#include "D:\Logger_POC_NoWorks\InteropLogger\CppLogger\CppLogger.h"


int main()
{
    UnmanagedLogger uLogger;
    uLogger.InvokeResult();
}

Expected Result: The console application shall build successfully in VS 2017.

But I am getting compiler errors;

  1. Warning C4273 'AreYouThere': inconsistent dll linkage ServiceCode d:\logger_poc_noworks\interoplogger\cpplogger\cpplogger.h 5

  2. Error C2871 'DotNetLogger': a namespace with this name does not exist ServiceCode d:\logger_poc_noworks\interoplogger\clilogger\clilogger.h 4

  3. Error C2039 'LoggerBridge': is not a member of 'CliLogger' ServiceCode d:\logger_poc_noworks\interoplogger\clilogger\clilogger.h 21

And many cascading errors.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
Ronny
  • 1
  • 2
  • Related (if not duplicate): https://stackoverflow.com/questions/12647766/exporting-dll-functions-to-unmanaged-programs – Aconcagua Sep 03 '19 at 09:05
  • `#include "D:\Logger_POC_NoWorks\InteropLogger\CppLogger\CppLogger.h"` – don't use absolute include paths in source code, instead just use the relative part in code `#include "CppLogger\CppLogger.h"` and specify the include path appropriately in project settings (preferrably as relative path to project location, there should be a variable for). Otherwise you'd need to change code any time you move your project (or other's would have to, if you share code with them). – Aconcagua Sep 03 '19 at 09:14

2 Answers2

0

I'm guessing your second block of code is clilogger.h?

You don't need to include cliLogger.h in your 3rd block of code as you are only using AreYouThere which you have already declared, this declaration also conflicts with the declaration from the header (hence the inconsistent dll linkage warning). This header also contains CLI code which will produce errors in your pure c++ file (probably the cause of your 'LoggerBridge': is not a member of 'CliLogger' error).

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
0

The #include directive is resolved by the pre-processor, which just is a pure text processor unaware of actual C++ (or C) semantics. So this piece of code

#include "D:\Logger_POC_NoWorks\InteropLogger\CliLogger\CliLogger.h"

__declspec(dllimport) void AreYouThere();

class UnmanagedLogger { /* ... */ }

will result in

using namespace System;
using namespace DotNetLogger;

namespace CliLogger { /* ... */ }

__declspec(dllexport) void AreYouThere()
{
    CliLogger::LoggerBridge obj;
    return obj.Result();
}

__declspec(dllimport) void AreYouThere();

class UnmanagedLogger { /* ... */ }

being presented to compiler after pre-processing, which will result in two problems:

  1. Unmanaged compiler still sees managed code (e. g. public ref class LoggerBridge, which is invalid in pure unmanaged C++).
  2. You get the incompatible declaration of AreYouThere, first with dllexport, then second time with dllimport.

So you need a separate header only containing unmanaged code and managing the import/export problem.

Typically, you'd have something like:

#ifdef INSIDE_MY_DLL_IMPLEMENTATION // invent up some better name yourself...
#define DLL_IMPORT __declspec(dllexport)
#else
#define DLL_IMPORT __declspec(dllimport)
#endif

DLL_IMPORT void areYouThere();

In referencing project, you'd just include the header then, inside DLL code, you'd have instead:

#define INSIDE_MY_DLL_IMPLEMENTATION // must precede, of course...
#include "new_interface_file.h"

Generalising now: You can use this pattern for any DLL, managed or purely unmanaged alike. For the latter case, you could even consider different compilers (e. g. __attribute__((dllimport)) for GCC, although you might need some extra work as GCC attributes don't precede, but follow function declaration). Solely: different C++ implementations (compilers) most likely come with incompatible ABI, so you should fall back to a pure C interface if you plan multiple compiler compatibility:

#ifdef __cplusplus
extern "C"
{
#endif

// ...

#ifdef __cplusplus
}
#endif
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • Thanks Aconcagua for the detailed information. Also, I clearly understood the reasons behind those issues.However, I do have one doubt about having a seperate header for exporting the functions. Does the header to export the functions remain in CLI project or shall I make a seperate project? My bet on CLI but still want to confirm once? – Ronny Sep 03 '19 at 16:55
  • Why en extra project? Consider your DLL some product, then the header is part of, like the manuals for a washing machine. So I'd keep the header together with the rest of the dll. You might organize everything in sub folders, though. – Aconcagua Sep 03 '19 at 22:45