2

I am using Il2CppInspector to generate scaffolding for a Unity game. I am able to convert System.String (app::String in Il2CppInspector) to std::string using the functions provided below.

How would I reverse this process; how do I convert a std::string to System.String?

helpers.cpp

    // Helper function to convert Il2CppString to std::string
    std::string il2cppi_to_string(Il2CppString* str) {
        std::u16string u16(reinterpret_cast<const char16_t*>(str->chars));
        return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(u16);
    }
    // Helper function to convert System.String to std::string
    std::string il2cppi_to_string(app::String* str) {
        return il2cppi_to_string(reinterpret_cast<Il2CppString*>(str));
    }

In short, I am looking for a function that takes in a std::string and returns an app::String

    // Helper function to convert std::string to System.String
    app::String string_to_il2cppi(std::string str) {
        // Conversion code here
    }
UnAlpha
  • 127
  • 14
  • Do you mean `std::string` to `System.String` instead? `std::wstring_convert` has a [`from_bytes()`](https://en.cppreference.com/w/cpp/locale/wstring_convert/from_bytes) method – Remy Lebeau May 10 '21 at 03:52
  • Whoops... yes. I meant `std::string` to `System.String` thank you for pointing that out. Will fix. – UnAlpha May 10 '21 at 03:55
  • does this help you? https://stackoverflow.com/questions/13718188/convert-from-stdstring-to-string – amitklein May 11 '21 at 12:36
  • or maybe this https://stackoverflow.com/questions/946813/c-cli-converting-from-systemstring-to-stdstring – amitklein May 11 '21 at 12:36
  • Those do not work as I am not using CLR for this project. – UnAlpha May 12 '21 at 05:41
  • Would this help: https://learn.microsoft.com/en-us/cpp/dotnet/how-to-convert-standard-string-to-system-string?view=msvc-160? Or this: http://msdn.microsoft.com/en-us/library/ezh7k8d5.aspx? – BusterCody3 May 13 '21 at 22:53
  • The first link uses CLR, the second is unrelated. A non-il2cpp solution would be to reverse the il2cppi_to_string function, there's another way, which I'm looking into. – UnAlpha May 14 '21 at 21:05
  • (The way you would reverse the function is using the from_bytes method) Remy posted. I tried that, didn't have any luck with it. So I'm trying something else at the moment. – UnAlpha May 14 '21 at 21:06

2 Answers2

0

Export Il2CppInspector with all namespaces, which will give you access to Marshal_PtrToStringAnsi.

app::String* string_to_il2cppi(std::string str) {
    return app::Marshal_PtrToStringAnsi((void*)&str, NULL);
}

Limitation: do not attempt to convert a string with null terminators inside of them example:

std::string test = "Hello\0world";

Use BullyWiiPlaza's solution if this is an issue for you.

UnAlpha
  • 127
  • 14
0

The accepted answer is actually wrong, there is no size parameter and copying stops at the first null byte (0x00) according to the MSDN documentation.

The following code fixes these problems and works correctly:

app::String* string_to_il2cppi(const std::string& string)
{
    const auto encoding = (*app::Encoding__TypeInfo)->static_fields->utf8Encoding;

    const auto managed_string = app::String_CreateStringFromEncoding((uint8_t*)&string.at(0), string.size(), encoding, nullptr);

    return managed_string;
}

A quote from djkaty:

To create a string, you cannot use System.String‘s constructors – these are redirected to icalls that throw exceptions. Instead, you should use the internal Mono function String.CreateString. This function has many overloads accepting various types of pointer and array; an easy one to use accepts a uint16_t* to a Unicode string and can be called as follows [...]

BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
  • Just because you can't get it to work doesn't mean it's wrong. And why did you edit my answer with an incorrect MSDN link? This is an Il2CppInspector question, thus Marshal_PtrToStringAnsi is exported using it, not a native call. – UnAlpha Sep 12 '21 at 21:07
  • @UnAlpha: Exported functions are from the Unity game's assembly or from the .NET framework, in this case it's from the framework so the MSDN link was correct. See the example code which casts to a `char *` (= `void *`) and then to an `IntPtr`:https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.ptrtostringansi Also obviously if your code fails to work for any input, it's wrong. You definitely need a size parameter, otherwise how would the code know when to stop? A 0x00 byte is **not** a terminator in `std::string`s. That cannot even possibly work in general. – BullyWiiPlaza Sep 13 '21 at 21:05
  • "Cannot work in general" My game mod project uses it, and it does exactly what it says it does. I didn't come up with this - it was recommended to me on another forum and it's how they are converting std::string to System Strings aswell. - If you try it and couldn't get it working, my guess would be you haven't exported all namespaces in Il2cppInspector, and that your not using the exported project it prebuilds for you with said namespaces. – UnAlpha Sep 14 '21 at 22:43
  • @UnAlpha: Buddy, you're implying I couldn't compile it but I could. It just produced faulty output unlike my version of the conversion function. I kept wondering why I crashed and this was the reason and I fixed it by using my version of the code instead. So actually try it on a `std::string` containing null bytes and tell me if it still works correctly or not lol: `std::string test = "Hello\0world";` – BullyWiiPlaza Sep 15 '21 at 10:37
  • Okay it doesn't work with null terminators in the string, that's much different than saying it doesn't work in general. That's why I thought you couldn't get it to compile. I now understand why your method is better so I will mark it as the answer and put a notice of that limitation on my answer. – UnAlpha Sep 16 '21 at 03:08