|
This article should help.
Regards,
--Perspx
Don't trust a computer you can't throw out a window
-- Steve Wozniak
|
|
|
|
|
|
|
I'm losing my mind over some Unicode issue and hopefully someone can help me out. I haven't done a ton of MFC stuff before, so hopefully it's a simple problem.
I've Unicode enabled in this project because I've got a 3rd party library that requires it. I've subclassed CListBox to get a list box that shows multiple lines per item. I'm overriding DrawItem and MeasureItem. In DrawItem I have the following lines for drawing text:
LPCTSTR lpszText = (LPCTSTR) lpDrawItemStruct->itemData;
...
dc.DrawText(lpszText, _tcslen(lpszText), &lpDrawItemStruct->rcItem, DT_LEFT | DT_TOP | DT_WORDBREAK);
In my main dialog class I add data to the list box like this:
m_ProductList.AddString((LPCTSTR)updates[i]->ToString().c_str());
And my text comes out looking like garbage. Usually Chinese characters. I can get the output to look correct if I do:
m_ProductList.AddString(TEXT("yoyoyoyoy\nzomgzomg\nblabla"));
I tried looking at what the TEXT macro does, but the farthest I can get is that is is an alias for L## which is difficult to google.
I've tried a lot of stuff and nothing has worked. I've tried: MultiByteToWideChar, CT2CW, A2W, and some other stuff.
My understanding of this issue is that I've got a UTF-8 encoded string from an XML file that's stored in a std::string. Then, since I'm using Unicode, DrawText is actually DrawTextW. So, I have to convert my string to Unicode, but nothing seems to be able to do that conversion.
Thanks,
Nick
|
|
|
|
|
Instead of trying a bunch of stuff, it may be easier to take a close
look at the type of the characters in your strings.
A good clue is the need for casts. You shouldn't need any casts.
If you do, then look at why.
For example:
m_ProductList.AddString((LPCTSTR)updates[i]->ToString().c_str());
Why the cast to LPCTSTR?
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I was a little confused about that part too. If I don't cast it, I get a compile error: cannont convert from const char* to LPCTSTR. I always thought those were the same thing.
Another odd part of this problem is that when I use a standard CListBox, I can correctly add items to it like this:
USES_CONVERSION;
CA2CT converted(updates[i]->ToString().c_str());
m_UpdateBox.AddString(converted)
Which makes it seem like I'm incorrectly calling DrawText in my subclass because when I add the same text to my list box I get bad data on the display.
|
|
|
|
|
thebeekeeper wrote: I get a compile error: cannont convert from const char* to LPCTSTR. I always thought those were the same thing.
That's exactly what I'm talking about That's a perfect example why
casting away problems is BAD. C++ is a strongly typed language - know
your data types!
No, LPCTSTR is NOT the same as a char *.
Here's the macro breakdown for LPCTSTR:
LP = long pointer
C = constant
T = generic-character-type (wchar_t for Unicode builds, else char)
STR = string
thebeekeeper wrote: when I use a standard CListBox, I can correctly add items to it like this:
Yes, because you're converting the string to the type the
listbox is expecting.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thanks for that tip on data types. I never realized LPCTSTR was just an alias for the generic string type of the build.
I guess this is really what I don't understand. CA2CT converts ASCII to wchar_t since this is a Unicode build, right?
CListBox::AddItem expects LPCTSTR. But this is actually a LPCWSTR, right? So, why does converting with CA2CT work with the stock CListBox and not my subclass? CListBox::DrawItem has to be calling DrawTextW, which is the same thing I'm calling.
|
|
|
|
|
thebeekeeper wrote: CA2CT converts ASCII to wchar_t since this is a Unicode build, right?
Right. A is ANSI, T is generic...A2T is ANSI to generic.
thebeekeeper wrote: why does converting with CA2CT work with the stock CListBox and not my subclass?
Is the source string already a Unicode (wchar_t) string?
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
No, it's coming out of std::string c_str(), so it's a const char*. There's no way that can be Unicode, right?
Also, if I use OutputDebugString, it works after I use the CA2W conversion and looks correct in the output window. So, I've got this:
USES_CONVERSION;
CA2W converted(updates[i]->ToString().c_str());
m_UpdateBox.AddString(converted);
m_ProductList.AddString(converted);
OutputDebugString(converted);
I'm starting to think I'm pulling out bad data in my DrawItem method, but I copied that code from MSDN, so it can't be wrong
|
|
|
|
|
thebeekeeper wrote: it's coming out of std::string c_str(), so it's a const char*. There's no way that can be Unicode, right?
Right, but a deeper question is why are you using a string
type hardwired to char in a Unicode environment?
I recommend using generic string types everywhere in
an MFC app. MFC does, so it works out nice when we do.
Using all generics makes any code you write compilable in
both Unicode and non-Unicode builds, just like MFC. Plus
you don't need to do all those string conversions, which are
inefficient.
If you must use STL strings, you could make your own generic
string class:
typedef std::basic_string<TCHAR, char_traits<TCHAR>,
allocator<TCHAR>> genericstdstring;
Use genericstdstring in place of std::string.
thebeekeeper wrote: but I copied that code from MSDN, so it can't be wrong
Umm...if you say so
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
AHA! I just figured out that I'm doing the conversion correctly (maybe), the problem is I have bad data to convert.
I inspected the memory location that lpDrawItemStruct->itemData was pointing to, and it looked like garbage. So, I added a method to my class where I can send text and store it in a vector. Then, in DrawItem I just look in my own vector for strings to draw, and everything works fine.
I guess this works for now, but I'd really like to know how to get my string out of itemData so I can use AddString on my list box like a normal person.
The only idea that I have right now is that my initial cast in DrawItem is bad.
LPCTSTR lpszText = (LPCTSTR) lpDrawItemStruct->itemData;
I don't see how this could be bad since that's exactly what I'm passing to AddString. The strange this is that it works when I pass in a literal with TEXT("..."), but not a converted const char* from string.c_str().
Thanks for your help!
|
|
|
|
|
thebeekeeper wrote: The only idea that I have right now is that my initial cast in DrawItem is bad.
That cast is valid and necessary, since
DRAWITEMSTRUCT.itemData is a ULONG_PTR.
I'm not sure why you're getting garbage there...
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
|
I'm using the same CA2W conversion that I use on a const char* from c_str(). And no, it doesn't work, but the strange thing is that it's like the data is going bad when I pass it into CMyList::AddString().
So, if I create a LPCWSTR hello = TEXT("hello") and pass it into CListBox and CMyList::AddString everything works fine.
But! If I do a CA2W conversion and pass it into both of those same methods, it works for CListBox, but now for CMyList.
|
|
|
|
|
thebeekeeper wrote: I'm using the same CA2W conversion
Why did you switch to CA2W, when the generic CA2CT was the
appropriate conversion?
Again, why is the conversion even necessary? Do you really
need to use char type strings anywhere? char has been pretty much
obsolete for a decade
Mixing hardwired character types and generic types causes
problems like these, which is why I recommend using the
generic types.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
|
What is the best way to embed hard data directly to a chip (preferably using C++)?
|
|
|
|
|
claytoncruppenink wrote: What is the best way to embed hard data directly to a chip
Buy a scalpel.
i.e. you should at least be more specific.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
can you please indicate the procedure to buy a scalpel and how I can use it in C++ with a chip please.
thx, it's urgentzzzzz
|
|
|
|
|
okay, but only if you iz abuzing drugz
|
|
|
|
|
Do you want codez with that?
Regards,
--Perspx
Don't trust a computer you can't throw out a window
-- Steve Wozniak
|
|
|
|
|
Ready-to-use code at
www.cpallini.freeproductz.com[^]
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
I think your magic site is very helpful here.
|
|
|
|
|
Hamid. wrote: I think your magic site is very helpful here.
Indeed.
OT: Hamid it has been a long time since I saw one of your posts, how do you do?
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|