0

I write a C# dll and call it from C++ function. But when i parse a string from C++ to C# function, i will show something weird like this:

d^¡Aè☺

Here is my C++ code:

#include "pch.h"
#include<stdio.h>
#include<Windows.h>
#include<string>

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Reflection;

int main()
{
    const char* pemodule = ("C:\\Users\\source\\repos\\ClassLibrary2\\ClassLibrary2\\bin\\Debug\\ClassLibrary2.dll");
    HMODULE hlib = LoadLibraryA(pemodule);
    typedef int(__cdecl *add)(int a, int b);

    typedef int(__cdecl* AntiMacro)(std::string path);
    auto pAntiMacro = (AntiMacro)GetProcAddress(hlib, "AntiMacro");

    std::string path = "C:\\macro\\test";
    int a = pAntiMacro(path);
    printf("%d\n", a);
    return 0;
}

And here is my C# DLL:

[DllExport]
        public static int AntiMacro(string filepath)
        {
            Console.WriteLine(filepath);
            bool isFolder = false;
            string fullpath = "";
            try
            {
                fullpath = Path.GetFullPath(filepath);
                Console.WriteLine(fullpath.ToString());
            }
            catch (Exception)
            {
                Console.WriteLine(fullpath);
                Console.WriteLine("Invalid path 1");
                return 1;
            }

I tried to change

std::string path = "C:\\macro\\test"

to

const char *path = "C:\\macro\\test"

But it still not working, is that string in C++ is different from C#?

TomC
  • 33
  • 6
  • 5
    To start with `std::string` and C# string are completly different. You have to marshal the strings when passing between C# and C++. See e.g.: https://learn.microsoft.com/en-us/cpp/dotnet/how-to-convert-system-string-to-standard-string?view=msvc-170. – wohlstad Jun 13 '23 at 10:56
  • C# string is much different than string in C++. C++ strings are null-terminated strings which are nothing but char array. – Anand Sowmithiran Jun 13 '23 at 10:56
  • have a look at this it may help you https://stackoverflow.com/questions/4455234/passing-string-from-c-to-c-sharp – Ahmed Anter Jun 13 '23 at 10:57
  • @AnandSowmithiran You're talking about C strings, not C++ strings which are `std::string`. – Thomas Jun 13 '23 at 11:12
  • @Thomas How so? std::string is just a wrapper for dynamically allocated array of characters to store the string data. By convention they are null terminated, the only difference is that there is an object pointer than handles the manipulation, rather than just having an array of chars allocated in the memory. – DreTaX Jun 13 '23 at 11:22
  • I would not use that kind of code to make an interop between C# and C++. There are all kind of caveats. And strings mostly behave different, because the C# one is managed by the garbage collector and can be moved around in memory (or removed) even when C++ still has a pointer to its (old) location. To make a good interop use : C++/CLI [quick introduction](https://www.codeproject.com/Articles/19354/Quick-C-CLI-Learn-C-CLI-in-less-than-10-minutes) – Pepijn Kramer Jun 13 '23 at 11:52
  • `std::string` form C++ is something completely different then `System.String` form C# and this is source of your problems. You have UB. – Marek R Jun 13 '23 at 13:31
  • @DreTaX Not true. `std::string` tracks its own length, and [may contain nulls](https://stackoverflow.com/questions/2845769/can-a-stdstring-contain-embedded-nulls). Since C++11, there is an added null terminator for convenience when interoperating with C, but even then the claim that `std::string` is a "null-terminated string which is nothing but a char array" is quite wrong. – Thomas Jun 14 '23 at 09:08
  • Of course it tracks its own length, It's a wrapper, more specifically a class standard guarantees that std::string objects are stored in contiguous memory and are followed by a null character ('\0') to provide compatibility with C-style strings when needed I was just picking your words of C strings and C++ strings, which I solely believe is not the right way to call them, even though many people do it – DreTaX Jun 14 '23 at 13:55

3 Answers3

3

You first need to convert std:string into char*

std::string path = "C:\\macro\\test";
const char *cstr = path.data();
int a = pAntiMacro(cstr);

You also need marshalling for the string

[DllExport]
public static int AntiMacro(
  [MarshalAs(UnmanagedType.LPStr)]
  string filepath)
{

But using C++/CLI might be a better option either way.

Charlieface
  • 52,284
  • 6
  • 19
  • 43
2

To work with C# DLLs in C++, you need to use the .NET Framework's Common Language Runtime (CLR) and interact with the DLL through managed interop: https://learn.microsoft.com/en-us/cpp/dotnet/overview-of-marshaling-in-cpp?view=msvc-170

Also see this: How to turn System::String^ into std::string? https://stackoverflow.com/a/53016935/5033623

I highly do not recommend this approach though unless you have a very specific reason to work with C# API calls in your native application. It's usually the other way around.

DreTaX
  • 760
  • 2
  • 9
  • 22
0

UPDATE: i found the solution. As Charlieface said: i need to put this in my code:

[DllExport]
public static int AntiMacro(
  [MarshalAs(UnmanagedType.LPStr)]
  string filepath)
{

But it still not working, so i rewrite it a little bit:

    [DllExport]
    public static int AntiMacro(
      [MarshalAs(UnmanagedType.LPUTF8Str)]
      string filepath)

I change UnmanagedType.LPStr to UnmanagedType.LPUTF8Str and it work perfectly. And edit my C++ code as Charlieface provided.

TomC
  • 33
  • 6