P/Invoke c++ exported function from c# library char* emty in dll

63 views Asked by At

I have made a c++ console application master-project with cmake and vc++ in VS Code.

This is the CMakeLists.txt of the master-project.

include_directories(include)
include_directories(../sub-project/include)

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
make_directory(${EXECUTABLE_OUTPUT_PATH})

add_executable (master-project
                "source/*.cpp")
target_compile_features(master-project PUBLIC cxx_std_17)
target_link_libraries(master-project 
                      sub-project)

This c++ project contains a shared library sub-project as a dependency. This is the CMakeLists.txt of the sub-project:

include(GenerateExportHeader)
include_directories(include)

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
make_directory(${LIBRARY_OUTPUT_PATH})

add_library(sub-project SHARED "source/*.cpp" ${CMAKE_CURRENT_BINARY_DIR}/sub-project_exports.h)
GENERATE_EXPORT_HEADER(sub-project
                       BASE_NAME sub-project
                       EXPORT_MACRO_NAME SUB-PROJECT_EXPORTS
                       EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/sub-project_exports.h
                       STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC)
target_include_directories(sub-project
                           PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
target_compile_features(sub-projectPUBLIC cxx_std_17)
target_link_libraries(sub-project
                      pqxx)

sub-project.hpp

#include "sub-project_exports.h"

class SUB-PROJECT_EXPORTS foo
{
public int bar(char* msg);
}

sub-project.cpp

#include "sub-project.hpp"

int foo::bar(char* msg)
{
cout<<"msg string:"<<msg<<" and msg len:"<<strlen(msg)<<endl;
return strlen(msg);
}

As you can notice, whole class foo is exported using cmake's 'GENERATE_EXPORT_HEADER' function.

I want to use this this exported class in sub-project.dll from a c# library project. The c# code used is:

[DllImport("sub-project.dll",
            EntryPoint = "foo_mangledname",
            CharSet = CharSet.Ansi,
            CallingConvention = CallingConvention.Cdecl)]
static extern void Foo();

[DllImport("sub-project.dll",
            EntryPoint = "bar_mangledname",
            CharSet = CharSet.Ansi,
            CallingConvention = CallingConvention.Cdecl)]
static extern int Bar([MarshalAs(UnmanagedType.LPStr)] string msg);

I used the DUMPBIN /EXPORT command from developer powershell of visual studio to find the mangled names of exported members.

Use of the imported functions in c#:

static void Main(string[] args)
{
string msg = "Print this message";
Console.WriteLine("Returned msg.length():" + Bar(msg))
}

The expected output on console is:

msg string:Print this message and msg len:18
Returned msg.length():18

But the actual output I'm getting

msg string: and msg len:0
Returned msg.length():0

I've tried changinf Charset.Ansi to Charset.Auto and Charset.Unicode, with same result.

I've also tried changing the Marshalling of the string argument of funtion Bar to all available unmanaged string types, but no success. Some types marsharas types output load of gibberish, some resulted in memory exception.

Can anyone help in figuring out why the library is getting an empty string?

0

There are 0 answers