I'm creating Windows Runtime Component (c++) to use it later in windows phone 8.1 application (c#). My problem is preety simple but I cannot find any answer to it:
I need to create a method which take string/char */anything which is filepath as parameter and pass it to external method which takes char * as parameter.
I've tried with std::string, String^, char *. But I still get errors like such types are not supported (not in String^ case) or some other one.
Is there some simple answer which tells me how should I do this?
Code samples with errors
beginning
#include "pch.h"
#include "Class1.h"
using namespace Platform;
namespace WindowsRuntimeComponent2
{
public ref class Class1 sealed
{
various types:
int Foo(std::string param) {
cause: Foo': signature of public member contains native type 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' WindowsRuntimeComponent2 and few more containing same information about string's dependencies
int Foo(char * param) {
cause: 'Foo': signature of public member contains native type 'std::basic_string<char,std::char_traits<char>,std::allocator<char>>' WindowsRuntimeComponent2
int Foo(String^ photoPath) {
this one do not cause any errors but I don't know how to parse it to my char *.
Essentially here you just need to know how to convert from System.String^ to std::string, this can be done in C++/CLI mode as follows:
#include <msclr\marshal_cppstd.h>
//...
int Foo(String^ photoPath) {
std::string unmanaged_photoPath = msclr::interop::marshal_as<std::string>(photoPath);
// then convert to c-style string as normal using unmanaged_photoPath.c_str();
return 0;
}
Related
I am beginner in C language family...
So, problem is - in my solution I have a repo (wrote in C#) that store List<int>, also I have an engine that (wrote in C++). So, I need pass List from C# implementation to C++ CLI for executing...
As far as I understood problem is C++ know how to work with std::vector and C# know how to work with List and I need somehow convert List to vector...
How to do it?
Any assumption appropriate.
EDIT
Sorry for misunderstanding, but my CLI works as a mapper for pure C++ implementation. So, as far as I understood from C# I need to pass my List to C++ CLI , C++ CLI will convert a List to vector and invoke another C++ file with pure C++ implementation.
This is my solution
h file
using namespace System;
using namespace System::Collections::Generic;
//forward declaration
class MathCore;
namespace MathCore_CLI_namespace
{
public ref class MathCore_CLI
{
public:
MathCore_CLI();
~MathCore_CLI();
int computeMulPlusVals(List<int>^ list_first, List<int>^ list_second);
//int computeMulPlusVals(std::vector<int> vect_first, std::vector<int> vect_second);
private:
MathCore * m_pMathCore;
};
}
cpp file
#include "stdafx.h"
#include "MathCore_CLI.h"
#include "..\Engine\MathCore.h"
#include <iostream>
#include <array>
using namespace System;
using namespace System::Collections::Generic;
namespace MathCore_CLI_namespace
{
const int size = 5;
int count = 0;
int arrayVal[size];
MathCore_CLI::MathCore_CLI()
{
m_pMathCore = new MathCore();
}
MathCore_CLI::~MathCore_CLI()
{
delete m_pMathCore;
}
int computeMulPlusVals(List<int>^ list_first, List<int>^ list_second)
{
return 0;
}
}
Error
What am I doind wrong?
C++ CLI directly supports List and you don't need a conversion. Here is a typical signature.
private: System::Void FooMethod( System::Collections::Generic::List<Int32>^ list )
Besides, In your updated question, you have a linker error.
Open C++ project properties, Find Linker and then Input. Add the location to your (EngineLib_Cli.dll) Library there
Also I found more optimized solution
int MathCore_CLI::computeMulPlusVals(array<int>^ arr_first, array<int>^ arr_second)
{
auto vec_first = std::vector<int>(arr_first->Length);
cli::pin_ptr<int> pPinnedFirst = &arr_first[0];
memcpy(vec_first.data(), pPinnedFirst, arr_first->Length * sizeof(int));
auto vec_second = std::vector<int>(arr_second->Length);
cli::pin_ptr<int> pPinnedSecond = &arr_second[0];
memcpy(vec_second.data(), pPinnedSecond, arr_second->Length * sizeof(int));
return m_pMathCore->computeMulPlusVals(vec_first, vec_second);
}
By steps
1) you need to create your vector
2) hold this memory in heap
3) just copy the data
It is going to be much more faster
First of all hey guys! I would like to access 2 C++ functions from my windows phone app.
so i followed every step of this tutorial and i managed to call the function as the poster of the tutorial. Now i wanted to access my own functions so i created the class in the header and in the .cpp file and the project is building ok as long as my functions are not public. Means i cant access them.
public ref class Base64Encoding sealed
{
public:
char *EncodeData(char *data, int length, int *resultLength); //this doesnt compile
char *DecodeString(char *data, int *resultLength); //this compiles buts inaccessible
};
i get a return exception saying error C3992: signature of public member contains invalid type char.
I did some googling and as far as i understand i cannot send parameters of type char since its unmanaged code or something like that.
So what is the issue here? why i cannot pass parameters of type char?
Update
i followed robwirving suggestion and now the header looks like this.
public ref class Base64Encoding sealed
{
public : Platform::String^ EncodeData(String^ StringData);
public : Platform::String^ DecodeString(String^ StringData);
};
in order now to get char* data from the String^ StringData parameter i did in my .cpp
#include <string>
#include <iostream>
#include <msclr\marshal_cppstd.h>
using namespace Platform;
using namespace std;
String^ EncodeData(String^ StringData)
{
// base64 lookup table. this is the encoding table for all 64 possible values
static char *figures = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
msclr::interop::marshal_context context;
std::string s = context.marshal_as<std::string>(StringData);
char *data = new char[s.size() + 1];
int length = s.length;
int *resultLength = s.length;
data[s.size()] = 0;
/* bla bla some functions irrelevant*/
.
.
.
return StringFromAscIIChars(result);
}
static String^ StringFromAscIIChars(char* chars)
{
size_t newsize = strlen(chars) + 1;
wchar_t * wcstring = new wchar_t[newsize];
size_t convertedChars = 0;
mbstowcs_s(&convertedChars, wcstring, newsize, chars, _TRUNCATE);
String^ str = ref new Platform::String(wcstring);
delete[] wcstring;
return str;
}
but now i get 2 errors on building.
1: error C1114: WinRT does not support #using of a managed assembly
2: IntelliSense: an ordinary pointer to a C++/CX mapping ref class or interface class is not allowed
You said the answer right in your question. You can't use a char in a public function of a WinRT component. You can however use strings, I'd suggest changing your functions to the following:
public ref class Base64Encoding sealed
{
public:
Platform::String^ EncodeData(Platform::String^ data);
Platform::String^ DecodeString(Platform::String^ data);
};
In the definition of your encode/decode functions you can then convert your inputs from a Platform::String^ to a char array, call your original C++ function, then convert the return value back to a Platform::String^
I know this may seem like a lot of extra work, but it makes the interop a lot easier for the C# that will consume your WinRT component.
Update:
I think your additional errors probably come from the including msclr\marshal_cppstd.h and the way you are converting your Platform::String^ to a std::string.
Reference this post for how to convert from Platform::String^ to a char*: How to convert Platform::String to char*?
I need to send a struct from C# managed code to a C library. The C library will populate the values in the struct. I have been trying to pass the struct as a reference so that the C# code will get the updated data values.
This is an example C function in libshlib.so:
void sharedStruct(struct data* d)
{
d->number = calcSomething();
d->message = doSomething();
}
I can send individual parameters (int and StringBuilder) and the library code runs and returns new values to the C# code that called it.
But how can I create a struct in C# that contains both int and string and send it to the unmanaged code (C library) which will populate the values to be used back in the C# code?
The C struct might be like this:
struct data
{
int number;
char* message;
};
Right now I'm trying to establish the best way to manipulate data in the C library for use in C#. I am writing both pieces of code so I am flexible but right now I haven't been able to get it working.
If you want the struct to be populated by the C code, then you are probably looking for an out variable. Note that the mono runtime by default will use free() to deallocate any strings you pass in and you might have to take extra care with padding in structures (see the StructLayout stuff in msdn). For strings, further problems can be had with character sets.
Sample code:
Managed.cs:
using System;
using System.Runtime.InteropServices;
struct Data
{
public int number;
public string message;
}
class Managed
{
[DllImport("unmanaged")]
extern static void Foo(out Data data);
static void Main()
{
Data data;
Foo(out data);
Console.WriteLine("number = {0}, message = {1}", data.number, data.message);
}
}
unmanaged.c:
#include <string.h>
struct data
{
int number;
char* message;
};
void Foo(struct data* data)
{
data->number = 42;
data->message = strdup("Hello from unmanaged code!");
}
Test run:
$ mcs Managed.cs
$ gcc -shared -fPIC -o libunmanaged.so unmanaged.c
$ LD_LIBRARY_PATH=$PWD mono Managed.exe
number = 42, message = Hello from unmanaged code!
I am in the need of using some functions in a C made program. To test I defined the following :
This is my .h file :
namespace amt
{
class AMT_EXPORT FaceRecognition
{
public:
std::string amt_test_string(std::string in);
};
};
This is my .cpp file :
#include <memory.h>
#include <string>
#include <iostream>
#include <fstream>
#include "api_shared.h"
#include <sys/stat.h>
using namespace std;
std::string amt::FaceRecognition::amt_test_string (std::string in)
{
std::string s="in: "+in;
std::cout<<s<<std::endl;
return s;
}
I am trying to invoke the method like this :
const string str = "C:\\minimal.dll";
[DllImport(str)]
public static extern string amt_test_string(string input);
static void Main(string[] args)
{
string myinput = "12";
string myoutput = "";
myoutput = amt_test_string(myinput);
Console.WriteLine(myoutput);
Console.Read();
}
But im getting an error saying that it cannot find the entry point named amt_test_string..why so? I am a newbie in C btw
That's not a C DLL, that's a C++ DLL. C and C++ are not the same language. In particular, C++ has name mangling, so the function name which gets exported to the DLL is decorated.
I'd strongly recommend that you avoid having C++ exports in your DLL for that reason. If you use only C exports, the symbol name will be predictable (i.e. will not depend on the specific details of how your C++ compiler decorates names), and you won't have to worry about runtime differences, like how your C++ standard library implements std::string.
I'd recommend your DLL export look like this:
extern "C" // This says that any functions within the block have C linkage
{
// Input is 'in', output gets stored in the 'out' buffer, which must be 'outSize'
// bytes long
void DLLEXPORT amt_FaceRecogniztion_amt_test_string(const char *in, char *out, size_t outSize)
{
...
}
}
This interface does not rely on any particular library's std::string implementation, and C# knows how to martial char* parameters as C strings. However, memory management is more complicated, as you need to figure out an upper bound on how big the output is going to be and pass in an appropriately sized bufer.
I'm working on a c++ project which uses a string path to call an XML file. When i compiled the c++ everything works perfectly and i'm able to use the XML file as my project requires.
I needed to use a C# GUI, so i made a wrapper to call all my functions from my C++ file. One problem arises after debugging between the both platforms, c# does not recognize the string path to call my file, the error that i got is that it can not find the given path. Does anyone know how to send a valid string path between both platforms?
Thanks in advance,
Carolina
int ClassUnmanaged::ReadFile(string path_to_file)
{
int status = XMLClass->ReadConfigFile(path_to_file);
if(status)
{
return status; //Error
}
else
{
return 0;
}
}
Wrapper.h for the C++ class
public __gc class Wrapper
{
public: Wrapper(void);
public: ~Wrapper(void);
/** Unmanaged pointer to Class Unmanaged API
*
*/
private: ClassUnmanaged__nogc* pointerUnmanaged;
public: int NewReadfile(string path_to_file);
}
Wrapper.cpp
int Wrapper::NewReadFile(string path)
{
pointerUnmanaged->ReadFile(path);//here i access to my class unmanaged
return 0;
}
UI.cs
In the UI.cs i can not call the function NewReadfile from the wrapper because of the string type that c++ uses. Any idea how to solve this?
You will need to change the NewReadFile method to public and then change it to take as input a type that C# know about like Sytem::String it should look like this (using the new managed C++ syntax adapt to the old one if needed)
int Wrapper::NewReadFile(System::String^ path)
{
char* pathAsCharArray = (char*)(void*)Marshal::StringToHGlobalAnsi(str);
try
{
std::string pathAsStdString(pathAsCharArray);
pointerUnmanaged->ReadFile(pathAsStdString);
}
finally
{
Marshal::FreeHGlobal(pathUnmanaged);
}
return 0;
}
There is a KB article named "How to convert from System::String* to Char* in Visual C++" that explain the concept. If your underlying API could support unicode and you use the new syntax a better way to do the conversion is something like :
pin_ptr<const wchar_t> pathAsCharArray = PtrToStringChars(path);
std::wstring pathAsStrign(pathAsCharArray);