I am using C++/CLI and I want to call the function WNetAddConnection2
from Windows Networking.
First, I know that C++/CLI is not the language of choice for my work, but I have no possibility to change that right now and e.g. use C# instead.
The problem now is, that this function takes wchar_t*, so I need to convert System::String^ to wchar_t*.
Solution 1): use pin_ptr
and PtrToSTringChars
from vcclr.h
Solution 2): use StringToHGlobalUni
. (The title mentions StringHToGlobalAnsi
because more people are searching for that so they might find this post and it's answers faster).
I have found out that both solutions work. But #1 does not really. I have put the WNet-functions into a ref class CWNetShare
with following constructor:
CWNetShare::CWNetShare (String^ i_sLocalDrive, ...) {
pin_ptr<const wchar_t> wszTemp;
wszTemp = PtrToStringChars(i_sLocalDrive);
m_wszLocalDrive = const_cast<wchar_t*>(wszTemp);
where m_wszLocalDrive
is a private CWNetShare
member of type wchar_t*
.
The real problem: while calling the constructor by m_oWNetShare = gcnew CWNetShare
from a Winform class constructor (I know, C++/CLI and Winforms...), everything seems fine. The string i_sLocalDrive
and others are converted and assigned correctly. But when accessing m_oWNetShare
later, the values in all m_wsz... variables are lost. It looks like the object was moved around by the GC.
Therefore I have made a test:
ref class CManaged {
public:
wchar_t* m_wszNothing;
wchar_t* m_wszPinned;
wchar_t* m_wszMarshal;
System::String^ m_sTest;
CManaged ()
{
m_sTest = "Hello";
m_wszNothing = L"Test";
pin_ptr<const wchar_t> wszTemp;
wszTemp = PtrToStringChars(m_sTest);
m_wszPinned = const_cast<wchar_t*>(wszTemp);
m_wszMarshal = static_cast<wchar_t*>(System::Runtime::InteropServices::Marshal::StringToHGlobalUni (m_sTest).ToPointer());
}
};
Again a winform with m_oManaged = gcnew CManaged;
in its constructor. When accessing m_oManaged later, then if m_oManaged was not moved, m_wszPinned
is ok.
But after GCing, it's showing nonsense. BUT m_wsznothing keeps it's value, so it's not a problem of wchar_t*
, but of the pin_ptr somehow. The address of m_oManaged
has changed, but the address of m_wszPinned
is the same, so why is the value lost then?
What is going wrong here?
Does pin_ptr and PtrToSTringChars have a use at all then?
I'm using marshalling now, which works.