Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. DrawText is giving me garbage

DrawText is giving me garbage

Scheduled Pinned Locked Moved C / C++ / MFC
helpc++graphicsxml
14 Posts 3 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    thebeekeeper
    wrote on last edited by
    #1

    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

    M L 2 Replies Last reply
    0
    • T thebeekeeper

      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

      M Offline
      M Offline
      Mark Salsbery
      wrote on last edited by
      #2

      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++ :java:

      T 1 Reply Last reply
      0
      • T thebeekeeper

        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

        L Offline
        L Offline
        led mike
        wrote on last edited by
        #3

        Have you looked at this article?[^]

        led mike

        1 Reply Last reply
        0
        • M Mark Salsbery

          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++ :java:

          T Offline
          T Offline
          thebeekeeper
          wrote on last edited by
          #4

          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.

          M 1 Reply Last reply
          0
          • T thebeekeeper

            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.

            M Offline
            M Offline
            Mark Salsbery
            wrote on last edited by
            #5

            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++ :java:

            T 1 Reply Last reply
            0
            • M Mark Salsbery

              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++ :java:

              T Offline
              T Offline
              thebeekeeper
              wrote on last edited by
              #6

              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.

              M 1 Reply Last reply
              0
              • T thebeekeeper

                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.

                M Offline
                M Offline
                Mark Salsbery
                wrote on last edited by
                #7

                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++ :java:

                T 2 Replies Last reply
                0
                • M Mark Salsbery

                  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++ :java:

                  T Offline
                  T Offline
                  thebeekeeper
                  wrote on last edited by
                  #8

                  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());
                  // CListBox -- looks right
                  m_UpdateBox.AddString(converted);
                  // CMyListBox -- looks wrong
                  m_ProductList.AddString(converted);
                  // Output window -- looks right
                  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 :omg:

                  M 1 Reply Last reply
                  0
                  • M Mark Salsbery

                    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++ :java:

                    T Offline
                    T Offline
                    thebeekeeper
                    wrote on last edited by
                    #9

                    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!

                    M 2 Replies Last reply
                    0
                    • T thebeekeeper

                      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());
                      // CListBox -- looks right
                      m_UpdateBox.AddString(converted);
                      // CMyListBox -- looks wrong
                      m_ProductList.AddString(converted);
                      // Output window -- looks right
                      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 :omg:

                      M Offline
                      M Offline
                      Mark Salsbery
                      wrote on last edited by
                      #10

                      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++ :java:

                      1 Reply Last reply
                      0
                      • T thebeekeeper

                        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!

                        M Offline
                        M Offline
                        Mark Salsbery
                        wrote on last edited by
                        #11

                        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++ :java:

                        1 Reply Last reply
                        0
                        • T thebeekeeper

                          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!

                          M Offline
                          M Offline
                          Mark Salsbery
                          wrote on last edited by
                          #12

                          thebeekeeper wrote:

                          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().

                          Ooops I missed that part :) What conversion are you using there? Are you sure that conversion is succeeding? I'm thinking no :)

                          Mark Salsbery Microsoft MVP - Visual C++ :java:

                          T 1 Reply Last reply
                          0
                          • M Mark Salsbery

                            thebeekeeper wrote:

                            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().

                            Ooops I missed that part :) What conversion are you using there? Are you sure that conversion is succeeding? I'm thinking no :)

                            Mark Salsbery Microsoft MVP - Visual C++ :java:

                            T Offline
                            T Offline
                            thebeekeeper
                            wrote on last edited by
                            #13

                            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. X|

                            M 1 Reply Last reply
                            0
                            • T thebeekeeper

                              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. X|

                              M Offline
                              M Offline
                              Mark Salsbery
                              wrote on last edited by
                              #14

                              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++ :java:

                              1 Reply Last reply
                              0
                              Reply
                              • Reply as topic
                              Log in to reply
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes


                              • Login

                              • Don't have an account? Register

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • World
                              • Users
                              • Groups