Thread: Using GetTextExtentPoint32 to get char width

  1. #1
    Registered User
    Join Date
    Sep 2007
    Posts
    127

    Using GetTextExtentPoint32 to get char width

    Hi,

    I'm trying to output a single character, get that character's width, and then increase a variable by that amount. Currently, my code looks like this:

    In MainWndProc:
    Code:
        static char ch[2];
        LPSTR ch1;
        SIZE sz;
        size_t * pcch;
    Then, in WM_PAINT:
    Code:
                    TextOut(hdc, PosX, PosY * dwCharY, ch, 1);
                    ch1 = ch;
                    StringCchLength(ch1, 11, pcch);
                    GetTextExtentPoint32(hdc, ch1, *pcch, &sz);
                    PosX += sz.cx;
    Unfortunately when I run the program, it crashes after 1 character is output. Anyone got any ideas as to how I can increase the text's x position without having it crash? I'm pretty new to this stuff.

    Thanks.

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Unfortunately when I run the program, it crashes after 1 character is output. Anyone got any ideas as to how I can increase the text's x position without having it crash?

    You really need to get a firm grasp on pointers. It's not a chunk of memory but rather an *address* to some chunk of memory (supplied by you). Incidentally, you don't necessarily need to even *declare* a pointer - simply pass the address of the memory directly to whatever function you're using (StringCchLength, for instance).

    Finally, if you insist on using such a wacky API as StringCchLength, you need to at least use it correctly. It returns an HRESULT that needs to be checked with the SUCCEEDED macro, and the length you pass to it should not, of course, exceed the size of the string (I'm not say it will necessarily fail, but it is incorrect nonetheless).
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    Quote Originally Posted by Sebastiani View Post
    >> Unfortunately when I run the program, it crashes after 1 character is output. Anyone got any ideas as to how I can increase the text's x position without having it crash?

    You really need to get a firm grasp on pointers. It's not a chunk of memory but rather an *address* to some chunk of memory (supplied by you). Incidentally, you don't necessarily need to even *declare* a pointer - simply pass the address of the memory directly to whatever function you're using (StringCchLength, for instance).

    Finally, if you insist on using such a wacky API as StringCchLength, you need to at least use it correctly. It returns an HRESULT that needs to be checked with the SUCCEEDED macro, and the length you pass to it should not, of course, exceed the size of the string (I'm not say it will necessarily fail, but it is incorrect nonetheless).
    Thanks for the reply. So if StringCchLength isn't suitable, what would be? To be honest I just used it like that because they did so on msdn here:

    Drawing Text from Different Fonts on the Same Line (Windows)

    About the pointers- in that example, they just declare size_t * pcch; and then proceed to put it into StringCchLength. Do you need to do something else to do it before that?

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Thanks for the reply. So if StringCchLength isn't suitable, what would be? To be honest I just used it like that because they did so on msdn here:

    Well, it *is* generally a bad idea to incorporate random pieces of code into your programs. Now you see why. If you see a code example somewhere, the best thing to do is dissect it, find out what it does, and only when you fully understand the implications of using it should you add it to your code. In this case, StringCchLength is similar to strlen/wcslen (or more appropriately the strnlen/wcsnlen extensions), and IMO complete overkill. To your credit, looking at the MSDN example, it looks like whoever put together the sample screwed up. That's pretty funny, but I'm actually not suprised - I've also seen MSDN examples that use void main! So perhaps it would be a good idea to be weary of code samples posted on MSDN. At any rate, in this case you know that the string being passed to GetTextExtentPoint32 has a length of 1, so there really isn't any need for StringCchLength or pcch at all.

    >> About the pointers- in that example, they just declare size_t * pcch; and then proceed to put it into StringCchLength. Do you need to do something else to do it before that?

    The correct way would have been to declare a size_t variable and pass the address of it to the function.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #5
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Code:
    size_t            sz;
    
    TextOut(hdc, PosX, PosY * dwCharY, ch, 1);
    GetTextExtentPoint32(hdc, ch, 1, &sz); //you know the number of chars in the string
    PosX += sz.cx;
    or use lstrlen() to find the string length.

    Also look at DrawText() and CALC_RECT
    (first call to find out the rect req and then call again to write the text, using the rect to position correctly).
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  6. #6
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    Quote Originally Posted by Sebastiani View Post
    >> Thanks for the reply. So if StringCchLength isn't suitable, what would be? To be honest I just used it like that because they did so on msdn here:

    Well, it *is* generally a bad idea to incorporate random pieces of code into your programs. Now you see why. If you see a code example somewhere, the best thing to do is dissect it, find out what it does, and only when you fully understand the implications of using it should you add it to your code. In this case, StringCchLength is similar to strlen/wcslen (or more appropriately the strnlen/wcsnlen extensions), and IMO complete overkill. To your credit, looking at the MSDN example, it looks like whoever put together the sample screwed up. That's pretty funny, but I'm actually not suprised - I've also seen MSDN examples that use void main! So perhaps it would be a good idea to be weary of code samples posted on MSDN. At any rate, in this case you know that the string being passed to GetTextExtentPoint32 has a length of 1, so there really isn't any need for StringCchLength or pcch at all.

    >> About the pointers- in that example, they just declare size_t * pcch; and then proceed to put it into StringCchLength. Do you need to do something else to do it before that?

    The correct way would have been to declare a size_t variable and pass the address of it to the function.
    Right, cool. Thanks for that. That all makes sense. I have read/ understood stuff about pointers before, and used them in some console-based programs. What you've said/ suggested there goes along with what I've read.

    The thing is, often with more complicated programs (ie this Windows stuff) it seems like they'll introduce stuff that works differently to the stuff in my C++ book. Hence that was why I was just like "Screw it I'll just try what they wrote even though it doesn't seem to make sense.".

  7. #7
    Registered User
    Join Date
    Sep 2007
    Posts
    127
    Quote Originally Posted by novacain View Post
    Code:
    size_t            sz;
    
    TextOut(hdc, PosX, PosY * dwCharY, ch, 1);
    GetTextExtentPoint32(hdc, ch, 1, &sz); //you know the number of chars in the string
    PosX += sz.cx;
    or use lstrlen() to find the string length.

    Also look at DrawText() and CALC_RECT
    (first call to find out the rect req and then call again to write the text, using the rect to position correctly).
    I tried using DrawText in my example program. Basically what I'm aiming at is a program that will let me output text to a window the same way I can with the console (ie text that will just go to the next line when it reaches the edge of the window etc.). I tried using DrawText in the following way, but it didn't work. It just drew a single, weird looking character in the rectangle. Again, I tried to base it on stuff from msdn. Do you know why it doesn't work?

    Also, I looked up CALC_RECT but couldn't find anything other than something this guy wrote for his own program:

    Problem with function - C++ Forums

    Anyway thanks again for the help, and here's my current code:

    Code:
        static char ch[2];                  // current character 
        static char output_line[500];
        static PTCHAR pchOutputBuf; // input buffer 
        static string outputbuf;
        static int PosX = 0;
        static int PosY = 0;

    Code:
        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            PosX = 0;
            PosY = 0;
            SetRect(&rc, 200, 200, 300, 300);
            for (int b = 0; b < 2; b++) {
                for (int a = 0; a < strlen(output_line); a++)
                    ch[0] = 00;
                for (int a = 0; a < outputbuf.size(); a++) {
                    ch[0] = outputbuf[a];
                    TextOut(hdc, PosX, PosY * dwCharY, ch, 1);
                    ch1 = ch;
                    DrawText(hdc, ch1, 1, &rc, DT_LEFT);
                    GetTextExtentPoint32(hdc, ch1, 1, &sz);
                    PosX += sz.cx;
                    if ((DWORD) PosX > dwLineLen) { 
                        PosX = 0;
                        ++PosY; 
                    } 
                }
            }
            EndPaint(hwnd, &ps);
            return 0;
    and

    Code:
        case WM_TIMER:
            //process the timer msgs, check which timer has fired
            switch (wParam)
                case IDT_TIMER1:
                {
                    hdc = GetDC(hwnd); 
                    outputbuf += "Hello world. This is a long string to fill up the window. ";
                    ReleaseDC(hwnd, hdc);
                    InvalidateRect(hwnd, NULL, TRUE); 
                    return 0;
    		    }
            return 0;
    Thanks for your help.

  8. #8
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by bengreenwood View Post
    I tried to base it on stuff from msdn. Do you know why it doesn't work?
    You have to understand each line of the code and decide if that line is required by your app.
    You need to use a debugger to find which line of your code is failing (break points).

    MSDN takes a while to comprehend. After a while you get used to it.


    Use the code from before, creating a mem DC and using it in the paint.

    Code:
    //use the mem DC we did before 
    //so need the previous code in
    //WM_CREATE
    //WM_DESTROY
    //WM_PAINT
    
    case IDT_TIMER1:
        
    //process text timer
    
    //add text to output buffer
    
    //for each char in output
         //find char width on screen
    
         //find where to draw
         if (width + XPos > line size) //too big to fit on current line
              XPos = 0; //reset to begining of line
              YPos += line size; //move down to new line
    
         //draw char to mem DC at [XPos , YPos]
    
         //update the x coord
         XPos += width; 
    
    //call for a paint
    picky
    I have seen too many bugs in software casued by uninitialised variables.
    Code:
    static char output_line[500] = {0}; //init to empty
    /picky

    Quote Originally Posted by bengreenwood View Post
    Also, I looked up CALC_RECT but couldn't find anything
    In MFC
    Code:
    //find the size the text requires with the same output styles we are using
    m_DetailsDC.DrawText(sTemp,TextSize,DT_CALCRECT|DT_CENTER|DT_VCENTER|DT_SINGLELINE );
    
    //center the text in the Total area
    Output.left = (TotalSize.Width() - TextSize.Width())/2;
    Output.right = Output.left + TextSize.Width();
    Output.top = (TotalSize.Height() - TextSize.Height())/2;
    Output.bottom = Output.top + TextSize.Height();
    
    //draw the string
    m_DetailsDC.DrawText(sTemp,Output,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
    EDIT: You know this can be done with an EDIT control. You can change the backgnd and font colour. The edit control will do most of the work (scroll, new lines etc)
    Last edited by novacain; 07-31-2009 at 03:43 AM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Another syntax error
    By caldeira in forum C Programming
    Replies: 31
    Last Post: 09-05-2008, 01:01 AM
  2. Conversion Char To Char * Problem
    By ltanusaputra in forum Windows Programming
    Replies: 3
    Last Post: 03-01-2008, 02:06 PM
  3. Program Crashing
    By Pressure in forum C Programming
    Replies: 3
    Last Post: 04-18-2005, 10:28 PM
  4. Half-life SDK, where are the constants?
    By bennyandthejets in forum Game Programming
    Replies: 29
    Last Post: 08-25-2003, 11:58 AM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM