I have the following function, which will hopefully tell me whether or not a folder exists, but when I call it, I get this error -
cannot convert parameter 1 from 'System::String ^' to 'std::string'
The function -
#include <sys/stat.h>
#include <string>
bool directory_exists(std::string path){
struct stat fileinfo;
return !stat(path.c_str(), &fileinfo);
}
The call (from the form.h file that holds the form where the user selects the folder) -
private:
System::Void radioListFiles_CheckedChanged(System::Object^ sender, System::EventArgs^ e) {
if(directory_exists(txtActionFolder->Text)){
this->btnFinish->Enabled = true;
}
}
Is anyone able to tell me how to filx this? Thanks.
You're trying to convert from a managed, C++/CLI string (System::String^) into a std::string. There is no implicit conversion provided for this.
In order for this to work, you'll have to handle the string conversion yourself.
This will likely look something like:
std::string path = context->marshal_as<std::string>(txtActionFolder->Text));
if(directory_exists(path)) {
this->btnFinish->Enabled = true;
}
That being said, in this case, it might be easier to stick to managed APIs entirely:
if(System::IO::Directory::Exists(txtActionFolder->Text)) {
this->btnFinish->Enabled = true;
}
You are trying to convert a CLR string to a STL string to convert it to a C-string to use it with a POSIX-emulation function. Why such a complication? Since you are using C++/CLI anyway, just use System::IO::Directory::Exists.
To make this work you need to convert from the managed type System::String to the native type std::string. This involves a bit of marshaling and will result in 2 separate string instances. MSDN has a handy table for all of the different types of marshaling for strings
http://msdn.microsoft.com/en-us/library/bb384865.aspx
In this particular case you can do the following
std::string nativeStr = msclr::interop::marshal_as<std::string>(managedStr);
Related
I am working on an MFC application where when I write Something like this:CString sName; sName.LoadString(IDS_NAME_STRING) it works fine but when I try to write while initializing in one line like CString sName = sName.LoadString(IDS_NAME_STRING), I am getting error
Error C2440 'initializing': cannot convert from 'BOOL' to 'ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<_CharType>>>'
I am not getting what's wrong with the latter statement. Can anyone help me to understand this error?
CString::LoadString returns a value of type BOOL. That's what the error message is telling you. It turned out to be a bit longer as it includes the full template instantiations. It's ultimately saying
cannot convert from 'BOOL' to 'CString'
The solution is what you already have:
CString sName;
sName.LoadString(IDS_NAME_STRING);
If you'd rather have that as a single statement, you'll have to implement a function for it, e.g.
CString load_string(uint32_t id) {
CString s;
s.LoadString(id);
return s;
}
With that you can write
auto s = load_string(IDS_NAME_STRING);
Note that the function load_string mirrors the behavior of the initial code: If a string resource with any given ID cannot be found, it returns an empty string. If you'd rather have failure communicated to clients you could throw an exception.
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
}
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 [...]
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.
For deserializing JSON into a c++ class, I'm using Cereal, which uses RapidJSON. As expected, c++ std::string can't have a null value. But other platforms do support null for strings (.NET SQL etc) and I get JSON from them with null values for strings. I need to tolerate this, and just make an empty string for nulls. What's the best way to do that?
I default to string substitute on the JSON changing nulls to "" like the following, but it is not a clean solution.
#include <cereal/archives/json.hpp>
#include <boost/algorithm/string.hpp>
// i.e. substitue all ":null with ":"" Like {"key":null} into {"key":""}
boost::replace_all(json, "\":null", "\":\"\"");
auto r = std::make_shared<R>();
std::stringstream ss(json);
{
cereal::JSONInputArchive archive(ss);
r->serialize(archive);
}
In case someone looks for this answer based on the exception generated by Cereal, it is: "rapidjson internal assertion failure: IsString()"
in cereal-1.1.2\include\cereal\external\rapidjson\document.h
change this
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
to this
const Ch* GetString() const { if (IsNull_()) return ""; RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
I'm not proposing this should be changed in the cereal source because some people may want strict type checking like the original
I run successfully:
Process::Start("C:\\Users\\Demetres\\Desktop\\JoypadCodesApplication.exe");
from a Windows Forms application (visual c++) and as expected, I got 2 programs running simultaneously. My questions is:
Can I pass a string -indicating the file name- to the Process::Start method? I tried:
std::string str="C:\\Users\\Demetres\\Desktop\\JoypadCodesApplication.exe";
Process::Start("%s", str);
but failed. Is this possible?
EDIT:
I think you actually need to marshal to a System::String^ for passing an argument.
You can even marshal directly from a std::string to a System::String^.
///marshal_as<type>(to_marshal)
///marshal_context ctx; ctx.marshal_as<const char *>(to_marshal)
#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>
#include <msclr/marshal_atl.h>
using namespace msclr::interop;
using namespace System::Runtime::InteropServices;
Process::Start(marshal_as<String^>(str));
But in this case, you can just use a String^ instead:
String^ str = L"path to file";
Process::Start(str);
When you are working with C++/CLI, you either need to marshal back and forth or use the right data type from the start for how you want to use it.
MSDN: Overview of Marshaling in C++
Process::Start expects a String^ and you are attempting to pass it a std::string. It does not have a variadric version, and does not know what a std::string is. To pass the value from a std::string, you must marshal it:
std::string str("Some Path");
Process::Start(marshal_as<String^>(str));
I need to change the below c# code to c++ code.
public static byte[] StrToByteArray(string str)
{
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
return encoding.GetBytes(str);
}
on this website i found the c++ code for UTF8Encoding from which i created this code
void StrToByteArray(string unicodeString)
{
UTF8Encoding^ utf8 = gcnew UTF8Encoding;
array<Byte>^encodedBytes = utf8->GetBytes( unicodeString );
}
but this gives me the following error
Error 2 error C2664: 'cli::array
^System::Text::Encoding::GetBytes(cli::array
^)' : cannot convert parameter 1 from
'std::string' to
'cli::array
Why would it do this while it is identical to the documentation? (except i am using a normal string, but using a top level string^ gives me an error on that.)
i'm not sure if it is related but my code is managed.
note: i tried not worrying yet about returning any data till i get this working.
string is a different data type in C++ as it is in C#. Try using System::String^ instead.