using gcnew as a copy constructor - c++-cli

i know that gcnew is used to allocate managed memory.
i also didn't find any System::String(System::String ^)constructor.
normally if you want to copy a System::String class you will use something like
System::String ^s1 = gcnew System::String("a");
System::String ^s2 = System::String::Copy(s1);
but what about this?
System::String ^s1 = gcnew System::String("a");
System::String ^s2 = gcnew System::String(s1);

Related

How to pass a reference to a void* from C++/CLI to a native C function

I'm trying to call a native Windows API from managed C++/CLI. One of the arguments is a void**. The idea is that the function will allocate a memory structure and return a void pointer to the caller, which should be passed back to the API on the next call. So I need to allocate storage for a pointer on the managed side and pass a reference to the C API. I can't figure out how to do this.
I've tried declaring a void * in the caller and passing a reference via various operators: &, internal_ptr<>, pin_ptr<>. I did the same with an IntPtr. I get errors saying the compiler can't convert this to a void**.
Here's one attempt using IntPtr and pin_ptr. I get the following compile error on line 28 (the line that declares the pin_ptr):
E0144 a value of type "interior_ptr<System::IntPtr>" cannot be used to initialize an entity of type "cli::pin_ptr<void *>"
#include <msclr\marshal.h>
using namespace msclr::interop;
using namespace System;
namespace CLRStorage
{
public ref class CompoundFile
{
private:
String ^ pathname;
IntPtr pRootStorage;
public:
CompoundFile CompoundFile::Create(String^ path)
{
STGOPTIONS stgOptions;
stgOptions.usVersion = 1;
stgOptions.reserved = 0;
stgOptions.ulSectorSize = 4096;
stgOptions.pwcsTemplateFile = NULL;
auto cf = gcnew CompoundFile();
cf->pathname = path;
marshal_context^ context = gcnew marshal_context();
pin_ptr<void*> ppRootStorage = &cf->pRootStorage;
StgCreateStorageEx(
context->marshal_as<WCHAR*>(path),
STGM_READWRITE & STGM_CREATE,
STGFMT_DOCFILE,
0,
&stgOptions,
NULL,
IID_IStorage,
ppRootStorage);
}
};
}
IntPtr can be converted to and from void*, but it isn't the same type.
Since the parameter is out-only, the simple solution is just to use a temporary:
void* pRootStorage;
StgCreateStorageEx(
context->marshal_as<WCHAR*>(path),
STGM_READWRITE & STGM_CREATE,
STGFMT_DOCFILE,
0,
&stgOptions,
NULL,
IID_IStorage,
&pRootStorage);
cf->pRootStorage = IntPtr(pRootStorage);
This will actually be a tiny bit faster as well, because no pinning is needed.
You also have a separate problem with bad member function syntax. You want
static CompoundFile^ Create(String^ path)
instead of
CompoundFile CompoundFile::Create(String^ path)
and don't forget to
return cf;
Then, marshal_context is not a ref class, so this line is wrong:
marshal_context^ context = gcnew marshal_context();
Instead use
marshal_context context;
and since it is not a pointer,
context.marshal_as<WCHAR*>(path)

Pass LPWSTR to C# [duplicate]

I need to convert my SHA1 (wchar_t*) to a normal String^ in order to use it in a certain function. Any ideas? I tried Google but all the results were the exact opposite of my question. :\
NOTE: I am using C++.NET framework and Windows Forms Applications
Use the constructor; like this:
const wchar_t* const pStr1 = ...;
System::String^ const str1 = gcnew System::String(pStr1);
const char* const pStr2 = ...;
System::String^ const str2 = gcnew System::String(pStr2);
If you're using the standard C++ string classes (std::wstring or std::string), you can get a pointer with the c_str() method. Your code then might be
const std::wstring const std_str1 = ...;
System::String^ const str1 = gcnew System::String(std_str1.c_str());
See System.String and extensive discussion here.
If on doing Dan's solution you get an error cannot convert parameter 1 from 'std::string' to 'const wchar_t *', then you're asking the wrong question. Instead of asking how to convert wchar_t* to String^, you should be asking how to convert std::string to String^.
Use the built-in c_str function to get a plain char* out of the std::string, and pass that to the constructor.
std::string unmanaged = ...;
String^ managed = gcnew String(unmanaged.c_str());
You could also try:
#include <msclr\marshal_cppstd.h>
...
String^ managedString = msclr::interop::marshal_as<String^>(/* std::string or wchar_t * or const wchar_t * */);
You can refer to Overview of Marshaling in C++ for all the supported types you could use

Transfer array of bytes (gcroot<System::Byte []> cosbuf;) from /oldsyntax to /clr

I have now updated my c++ project from /oldsyntax to /clr, but I have problems to run it.
The old program (which runs fine has this)
gcroot<System::Byte []> cosbuf; (in header file)
And this in the constructor
cosbuf = new System::Byte[4096]; // This will not compile
and then this in the cpp file
System::Byte __pin *cosbuf_pin = &cosbuf[0];
char *cosbuf_ptr = reinterpret_cast<char*>(cosbuf_pin);
I tried to convert it to :
gcroot<array<System::Byte>^> cosbuf; // in .h file
array< System::Byte >^ cosbuf = gcnew array< System::Byte >(4096); // in constructor
pin_ptr<unsigned char> cosbuf_pin = &cosbuf[0]; // in cpp program
char *cosbuf_ptr = reinterpret_cast<char*>(cosbuf_pin);
This compile, but the cosbuf_pin assignement with pin_ptr throw exception with "Object reference not set to an instance of the object".
Either I need other ways of having a cosbuf_ptr to the cosbuf or some other data structures is needed. Basically an array of 4096 bytes is needed for this buffer.
You are declaring a new variable in the Constructor instead of using the one defined in the class.
Replace
array< System::Byte >^ cosbuf = gcnew array< System::Byte >(4096); // in constructor
with
cosbuf = gcnew array< System::Byte >(4096); // in constructor

StringToCoTaskMemUni or StringToCoTaskMemAnsi methods can cause hang?

I have the below code in c++/CLI and observing hang while converting the .net string to char * using StringToCoTaskMemAnsi
const char* CDICashInStringStore::CDIGetStringVal( void )
{
unsigned int identifier = (unsigned int)_id;
debug(" cashincdistores--routing call to .Net for CDI String %d", identifier);
NCR::APTRA::INDCDataAccess::IStringValue^ stringValueProvider = (NCR::APTRA::INDCDataAccess::IStringValue^)GetStringProvider()->GetProvider();
String^ strValue = stringValueProvider->GetStringValue(identifier);
debug(" cashincdistores-- going to call StringToCoTaskMemAnsi);
IntPtr iPtr = Marshal::StringToCoTaskMemAnsi(strValue);
debug(" cashincdistores-- StringToCoTaskMemAnsi called);
// use a local (retVal is not needed)
const char * ansiStr = strdup((const char *) iPtr.ToPointer());
Marshal::FreeCoTaskMem(iPtr);
debug(" cashincdistores--got results %d %s",identifier,ansiStr);
// The returned memory will be free() 'ed by the user
return ansiStr;
}
In our logging I can see "cashincdistores-- going to call StringToCoTaskMemAnsi" and suspecting there is a hang after calling the 'StringToCoTaskMemAnsi' method.
Does there is a chance of hang in 'StringToCoTaskMemAnsi' marshalling method. what could cause the hang ?
Why are you using COM in the first place? You don't need any COM in that code.
Disclaimer: You should probably not be returning a const char * someone else will have to free from your function. That's a very easy way to produce memory leaks or multiple free errors.
Ignoring the disclaimer above, you have a couple possibilities:
First way:
#include <msclr/marshal.h>
msclr::interop::marshal_context context;
const char* strValueAsCString = context.marshal_as<const char*>(strValue);
// Probably bad
const char* ansiStr = strdup(strValueAsCString);
The strValueAsCString pointer will remain valid as long as context is in scope.
Another way:
#include <string>
#include <msclr/marshal_cppstd.h>
std::string strValueAsStdString = msclr::interop::marshal_as<std::string>(strValue);
// Probably bad
const char* ansiStr = strdup(strValueAsStdString.c_str());
Here, the std::string manages the lifetime of the string.
See Overview of Marshaling for reference.

How to convert System::IntPtr to char*

can any body tell How to convert System::IntPtr to char* in managed c++
this is my main function
int main(void)
{
String* strMessage = "Hello world";
CManagedClass* pCManagedClass = new CManagedClass();//working
pCManagedClass->ShowMessage(strMessage);//working
****above said error here***
char* szMessage = (char*)Marshal::StringToHGlobalAnsi(strMessage);
CUnmanagedClass cUnmanagedClass; cUnmanagedClass.ShowMessageBox(szMessage);
Marshal::FreeHGlobal((int)szMessage);
return 0;
}
thanks in advance
I'm not a huge C++/CLI programmer, but the following should work just fine.
IntPtr p = GetTheIntPtr();
char* pChar = reinterpret_cast<char*>(p.ToPointer());
The IntPtr class has a method called ToPointer which returns the address as a void* type. That will be convertible to char* in C++/CLI.
EDIT
Verified this works on VS2008 and VS2015
Instead of
char* szMessage = (char*)Marshal::StringToHGlobalAnsi(strMessage).ToPointer();
Marshal::FreeHGlobal((int)szMessage);
Use
marshal_context conversions.
const char* szMessage = conversions.marshal_as<const char*>(strMessage);
It cleans itself up, the magic of C++ RAII.
Attention!
I want to add something to JaredPar answer.I don't know where your IntPtr is coming from but you should also use pin_ptr in order to prevent the garbage collector from messing up your memory. I did lot of CLR/Native inter op in the past and using pin_ptr is one of those things that I learnt to do in the hard way.
read the following:
click me