Conversion from System::String^ to LPCTSTR

G

Guest

I have seen the following function to convert from a System::String^ to a
const wchar_t*. I would like to get a LPCTSTR and AFAIK LPCTSTR is equal to
const wchar_t*. Then it should all work right? But I only get the first
character. And when I try to do std::wstring l_s(convert(somestring)) I get
really strange characters into l_s string representation, but when I check
l_s individual characters they look ok.

const wchar_t* convert(
System::String^ s)
{
// Pin memory so GC can't move it while native function is called
pin_ptr<const wchar_t> wch = PtrToStringChars(s);

return wch;
}
 
J

Jochen Kalmbach [MVP]

Hi Joachim!
I would like to get a LPCTSTR and AFAIK LPCTSTR is equal to
const wchar_t*.

No. LPCTSTR ist either const char* or const wchar_t* depending on
UNICODE macro.

My prefered way for cenversion is:

#include <windows.h>
#include <tchar.h>
using namespace System;
struct StringConvA
{
char *szAnsi;
StringConvA(System::String ^s)
:
szAnsi(static_cast<char*>(System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(s).ToPointer()))

{}
~StringConvA()
{

System::Runtime::InteropServices::Marshal::FreeHGlobal(IntPtr(szAnsi));
}
operator LPCSTR() const
{
return szAnsi;
}
};

struct StringConvW
{
wchar_t *szUnicode;
StringConvW(System::String^ s)
:
szUnicode(static_cast<wchar_t*>(System::Runtime::InteropServices::Marshal::StringToHGlobalUni(s).ToPointer()))

{}
~StringConvW()
{

System::Runtime::InteropServices::Marshal::FreeHGlobal(IntPtr(szUnicode));
}
operator LPCWSTR() const
{
return szUnicode;
}
};

#ifdef _UNICODE
#define StringConvT StringConvW
#else
#define StringConvT StringConvA
#endif

And then use it with:
#include <string>
int _tmain()
{
String ^s = "abc";
std::string ansi = StringConvA(s);
std::wstring unicode = StringConvW(s);
}

or

#include <stdio.h>
int _tmain()
{
String ^s = "abc";
printf("%s", (LPCSTR) StringConvA(s));
wprintf(L"%s", (LPCWSTR) StringConvW(s));
_tprintf(_T("%s"), (LPCTSTR) StringConvT(s));
return 0;
}


Greetings
Jochen
 
B

Ben Voigt

const wchar_t* convert(
System::String^ s)
{
// Pin memory so GC can't move it while native function is called
pin_ptr<const wchar_t> wch = PtrToStringChars(s);

return wch;
}

Complete misuse of pin_ptr here. You must never use a pin_ptr as a return
value.

OTOH, this will work, because the wstring constructor is called while the
string is still pinned:

std::wstring convert(System::String^ const s)
{
return std::wstring(pin_ptr<const wchar_t>(PtrToStringChars(s)));
}
 
G

Guest

Thank you Ben,

However, that still doesn't solve my problem (and by the way I get
compilation error with it:

error C3834: illegal explicit cast to a pinning pointer; use a pinned local
variable instead f:\Development\Source\Test\MCPP\MCPP\MCPPImpl.cpp 54)

Regards,
Joachim
 
B

Ben Voigt

Joachim said:
Thank you Ben,

However, that still doesn't solve my problem (and by the way I get
compilation error with it:

error C3834: illegal explicit cast to a pinning pointer; use a pinned
local
variable instead f:\Development\Source\Test\MCPP\MCPP\MCPPImpl.cpp 54)

ok, yeah, pin_ptr needs an explicit local, so split the one-liner:

std::wstring convert(System::String^ const s)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(s);
return std::wstring(wch);
}
 
B

Ben Voigt

Joachim said:
Ben,

Yes that did compile, but it didn't solve the problem

Regards,
Joachim

How about:

std::basic_string<TCHAR> convert(System::String^ const s)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(s);
#if _UNICODE
return std::wstring(wch);
#else
int needed = wcstombs(nullptr, wch, 0) + 1;
char* pch = alloca(needed);
wcstombs(pch, wch, needed);
// optional, unpin early with wch = nullptr;
return std::string(pch);
#endif
}
 
G

Guest

No, it is unicode.

Ben Voigt said:
How about:

std::basic_string<TCHAR> convert(System::String^ const s)
{
pin_ptr<const wchar_t> wch = PtrToStringChars(s);
#if _UNICODE
return std::wstring(wch);
#else
int needed = wcstombs(nullptr, wch, 0) + 1;
char* pch = alloca(needed);
wcstombs(pch, wch, needed);
// optional, unpin early with wch = nullptr;
return std::string(pch);
#endif
}
 
G

Guest

The (3rd party) function which I am passing the LPCTSTR on to takes and
LPCTSTR as argument and is working in a native C++/ATL/COM environment. In
that environment it is passed as a TCHAR*. But in this Managed C++
environment, even if I directly before the call to the function specifies
TCHAR* l_s(_T("test.mpg")) it only comes out as the filename "t".
 
B

Ben Voigt

Joachim said:
The (3rd party) function which I am passing the LPCTSTR on to takes and
LPCTSTR as argument and is working in a native C++/ATL/COM environment. In
that environment it is passed as a TCHAR*. But in this Managed C++
environment, even if I directly before the call to the function specifies
TCHAR* l_s(_T("test.mpg")) it only comes out as the filename "t".

Is the third-party function compiled as unicode? Is it compiled from source
or provided as a binary? Statically or dynamically linked?

Also, please don't refer to VC++ 2005 as Managed C++. That is specifically
the now-dead flavor of managed extension from VC++ 2003. The replacement,
which we are discussing, is C++/CLI.
 
G

Guest

Yes, it must be compiled as unicode since I use it in the working native c++
version from a unicode environment.
It is provided as a binary dll and is linked statically.
 
B

Ben Voigt

Joachim said:
Yes, it must be compiled as unicode since I use it in the working native
c++
version from a unicode environment.

Does the header file declare both Unicode and ANSI versions, like windows.h
does?

e.g. CreateFile is a #define for either CreateFileA or CreateFileW

A DLL function never accepts a TCHAR, it either accepts char or wchar_t.
With a little #define magic (or inline forwarder functions), you can make
functions that appear to accept TCHAR, but actually use different functions
inside the DLL for unicode vs ansi.
It is provided as a binary dll and is linked statically.

I'll assume you mean it's dynamically linked as a load-time import.
 
G

Guest

The function takes an LPCTSTR as argument. I then assume that they make
themselves independent of if it is unicode or not.
A DLL function never accepts a TCHAR, it either accepts char or wchar_t.
With a little #define magic (or inline forwarder functions), you can make
functions that appear to accept TCHAR, but actually use different functions
inside the DLL for unicode vs ansi.

Yes, I know. Thank you.
I'll assume you mean it's dynamically linked as a load-time import.

It is a dll. I link its functions with my application at link time, not at
runtime. If that is not statically can you please clarify it for me.

Thanks,
Joachim
 
B

Ben Voigt

Joachim said:
The function takes an LPCTSTR as argument. I then assume that they make
themselves independent of if it is unicode or not.

Source code can be usable for both unicode and ansi/multibyte, but compiled
object code cannot. There is also no way for the library to test whether
your application used a particular preprocessor define (_UNICODE) while
compiling (if your language even uses the C preprocessor). Each function in
the library is designed to accept either unicode or ansi input (it might be
possible to heuristically make a determination, but that's ridiculously
inefficient compared to the accepted method). Usually there is a A or W
suffix or the function, and the header file compiled with your application
and run through the preprocessor using your environment, selects the right
one.

If the documentation says LPCTSTR, but there aren't -A and -W variants, then
the documentation is wrong.
Yes, I know. Thank you.


It is a dll. I link its functions with my application at link time, not at
runtime. If that is not statically can you please clarify it for me.

That's not statically. Statically is linking with a .obj or .lib, where the
code and data segments are merged with your application by the linker to
form one executable module that you distribute. If the library is
distributed separately, as a DLL, and merged by the process loader, that's
dynamic linking. There are several forms of dynamic linking:
* load-time, the DLL is listed in your imports table, and the OS loader
merges it before your application starts execution
* delay-load, also listed in the import table, but with a special flag, and
not loaded until you try to access it
* late-bound, the DLL isn't listed in the imports table, but you make a
runtime request. This can be an explicit LoadLibrary, or implicitly via
creating a COM object that has an InProcServer. The advantage is that
failure to merge the library doesn't cause an immediate application
shutdown, but a trappable error.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top