0

Short version I am using unicode. I am attempting to use a std::string, to a function that requires a const WCHAR string; DrawString(const WCHAR, ...

I compile with GCC. Everything is unicode, I have specified.

I have been trying to convert a string, into a wchar_t*. The purpose is so that I can output using a GDI+ function, its parameters require it so.

Here is how I have outputted string literals, no problems, debugs fine, works fine. http://msdn.microsoft.com/en-us/library/ms535991%28v=vs.85%29.aspx for reference why:

// works fine
wchar_t* wcBuff;
wcBuff = (wchar_t*)L"Some text here.\0"; 
AddString(wcBuff, wcslen(wcBuff), &gFontFamilyInfo, FontStyleBold, 20, ptOrg_Controls, &strFormat_Info);

Now this is what I have been trying, all day, and a side note: my conversion function works fine, it is not an issue, nor creating one.

// problems
string s = "Level " + convert::intToString(6) + "\0"; 

// try 1 - Segfault
wchar_t* wcBuff = new wchar_t[s.length() + 1]; 
copy(s.begin(), s.end(), wcBuff);

// random tries, compiles, but access violations (my conversion function here has worked other places, do not know for sure here.
wchar_t* wcBuff;
wstring wstr = convert::stringToWideChar(s);
wstring strvalue = convert::stringToWideChar(s);           
wcBuff = (wchar_t*)strvalue.c_str(); 
wcBuff = (wchar_t*)wstr.c_str();

wstring foo;
foo.assign(s.begin(), s.end());
wcBuff = (wchar_t*)foo.c_str();

Everything compiles, but then presents problems. Some runtime errors as soon as it reaches that point. Others access violations and segfaults. Some compiles and debugs no problem, but the strings output constantly changes with random characters.

Any ideas?

Evan Carslake
  • 2,267
  • 15
  • 38
  • 56
  • 1
    duplicate http://stackoverflow.com/questions/2573834/c-convert-string-or-char-to-wstring-or-wchar-t?rq=1 – Ulterior Sep 24 '14 at 21:18
  • 1
    duplicate http://stackoverflow.com/questions/246806/i-want-to-convert-stdstring-into-a-const-wchar-t – WhozCraig Sep 24 '14 at 21:23
  • I actually read that topic, and tried all examples, none of them worked. I'm not using visual studio so I don't have the included header files. Both of @Potatoswatter examples resulted in random string output. – Evan Carslake Sep 24 '14 at 21:25
  • What is the encoding of your `std::string`? (I have no idea) What is the encoding that the GDI+ function expects? (maybe UTF-16?) As an aside, `(wchar_t*)L"Some text here.\0"` is dangerous. – Yakk - Adam Nevraumont Sep 24 '14 at 21:25
  • 3
    What is `convert::stringToWideChar` and why do you think it works? Why are you manually null terminating your strings? Why are you C-style casting? Stop that: it is dangerous, and you are doing it wrong. Why are you using `=` on a pointer when you `new`ed it a few lines before? You should take an intro class on C++ and learn how pointers work, you are using them wrong. Here is the 2nd hit on google on the subject: http://www.cprogramming.com/tutorial/lesson1.html – Yakk - Adam Nevraumont Sep 24 '14 at 21:28
  • Those were attempts, I made an effort. The first example is how I've been doing it so far. GDI+ requires C type strings, the parameter in add string is -1, meaning I have terminated it and doesn't need a length. The "works fine" had the exact syntax as an example on MSDN on the subject. – Evan Carslake Sep 24 '14 at 21:33
  • http://msdn.microsoft.com/en-us/library/ms535991%28v=vs.85%29.aspx for reference why I am using the literals as such. – Evan Carslake Sep 24 '14 at 21:41
  • It seems you don't understand null termination properly. The `"\0"` on the end of `string s = "Level " + convert::intToString(6) + "\0"; ` has no effect and should be removed; and the `\0` on the end of `L"Some text here.\0"` should also be removed – M.M Sep 24 '14 at 22:03

4 Answers4

0
#include <string>

int main() {

   // Can use convenient wstring
   std::wstring wstr = L"My wide string";

   // When you need a whar_t* just do this
   const wchar_t* s = wstr.c_str();

  // unicode form of strcpy
  wchar_t buf[100] = {0};
  wcscpy (buf,s);

  // And if you want to convert from string to wstring
  std::string thin = "I only take up one byte per character!";
  std::wstring wide(thin.begin(), thin.end());

   return 0;
}
Angus Comber
  • 9,316
  • 14
  • 59
  • 107
0

(this is not really an answer, but it's too big for a comment)

Try 1: you didn't null-terminate the string

Try 2: can't comment without seeing the conversion function. Remove the casts.

Try 3: Remove the casts, should be OK.

In all cases use wchar_t const *wcBuff. If "Try 3" fails then it means you have a bug somewhere else in your code, that is showing up here. Try to produce a MCVE. You should be able to get it down to about 10-20 lines.

Even if you manage to write the correct code for what you're intending, this is a fairly naive conversion as it doesn't handle characters outside the 0-127 range properly. You need to think about whether that is what you want, or whether you want to do a UTF-8 conversion, etc.

In Windows you can use MultiByteToWideChar.

Community
  • 1
  • 1
M.M
  • 138,810
  • 21
  • 208
  • 365
  • Thanks for the input everyone. I, however, did a lot more searching and in every single use of "Path.AddString()" GDI+ example uses a string literal. I believe this is not possible for that reason. Some versions that sort of worked, behaved randomly. GDI+ has a DrawString() function with reasonable parameters, at the cost of less control of how it looks. – Evan Carslake Sep 25 '14 at 03:11
  • @EvanCarslake produce a MCVE and post it again (or file a bug report) – M.M Sep 25 '14 at 03:28
  • I've now taken it fully a part. I could not think of a way to create a MCVE. http://pastebin.com/rQnVPPyA It works, I just need a way to assign variable text to 'n'. I defined the first characters by hand just to test it. – Evan Carslake Sep 25 '14 at 04:31
  • To make a MCVE, remove some code unrelated to the problem and check if the problem still occurs. Repeat this procedure until your code is down to the smallest possible, or you find what caused the problem. – M.M Sep 25 '14 at 04:32
  • I attempted to make a MCVE, but there is just too much code to go through. There is all of the Win32 stuff, GDI+ calls, HDCs, strings and data types. I thought of making a small example in a regular common console but got stumped. http://pastebin.com/2KCdt959 I updated what I have a little bit, and put it in better context of where it is implemented. At the moment the compiler raises no errors, no warnings, debugging no errors, access violations, segfaults...etc. There is just one problem, when drawn there appears to be an additional (random) character, unable to fix with a length - 1.Thanks – Evan Carslake Sep 25 '14 at 17:48
  • Well, if you want to get to the bottom of it at some stage, you know what to do :) – M.M Sep 25 '14 at 19:59
0

I first get my data into a wstring. Like this:

(Converting from string):

  std::string sString = "This is my string text";
  std::wstring str1(sString.begin(), sString.end());

(Converting from int):

wstring str1 = std::to_wstring(BirthDate);

Then, I use it in GDI+ Command like this:

graphics.DrawString(str1.c_str(), -1,
    &font, PointF(10, 5), &st);
Dicer
  • 396
  • 6
  • 13
-1

First thing first. GDI+ is a C++ library. It uses Microsoft C++ ABI. Microsoft C++ ABI is wildly incompatible with gcc so you might just forget about using it. You can try to use WinAPI or any other library that uses C calling conventions.

Now for the wstring question. wchar_t is 32 bits wide in gcc, but Windows APIs require it to be 16 bits wide. You cannot use any native Windows call that requires wchar_t.

You can use -fshort-wchar command line option in gcc, that would make wchar_t 16 bits wide and you will regain compatibility with Windows APIs, but lose compatibility with libc, so no library functions that act on wchar_t for you. std::wstring will probably work as it's header-only, but wprintf or wscpy or all other compiled stuff won't.

None of this is detected at compile time, as the only things gcc sees are header files. It cannot tell whether corresponding libraries are compiled with 16-bit wchar_t or 32-bit wchar_t.

You can use uint16_t when you need to pass an array of wchar_t to a Windows function. If you can use C++11, it has char16_t that you can use too. Here's an example that should work with Basic Multilingual Plane characters:

std::wstring myLittleNiceWstring; 
...
std::vector<uint16_t> myUglyCompatibilityString;
std::copy(myLittleNiceWstring.begin(),
          myLittleNiceWstring.end(),
          std::back_inserter(myUglyCompatibilityString));
myUglyCompatibilityString.push_back(0);

UglyWindowsAPI(static_cast<WCHAR*>(myUglyCompatibilityString.data());

If you have non-BMP characters, you need to convert UTF32 to UTF16 rather than just copy characters with std::copy. You can use libiconv for that or write a conversion routine yourself (it's rather simple) or just boorow some code from the internet.

It is my opinion that Windows-centric development with GCC is rather difficult because of this and other issues. You can use gcc as long as you stick to POSIX-ish APIs.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • If this is what's going on , then the call to the GDI function should give a compilation error. OP hasn't mentioned that so far – M.M Sep 24 '14 at 22:05
  • @MattMcNabb There will be no compilation errors. Windows APIs use WCHAR and it is typedefed to `wchar_t`. By looking at the function declaration you cannot tell what the ABI is. Will update the answer. – n. m. could be an AI Sep 24 '14 at 22:21