how to change the text drawn by drawtext()?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <windows.h>

HINSTANCE hEdit1;
HWND Edit1;
HINSTANCE hButton1;
HWND Button1;

char *str = new char;
int strlength = 0;

#define ID_BUTTON1 210
case WM_PAINT:
             {
             PAINTSTRUCT ps;
             RECT rect = {0,40,80,60};
             ps.rcPaint = rect;
             BeginPaint(hwnd, &ps);
             
             SetBkMode(ps.hdc, TRANSPARENT);
             DrawText(ps.hdc, str, strlength, &rect, DT_CENTER);
             
             EndPaint(hwnd, &ps);   
             break;
             }
             
case WM_CREATE:
             {
                   Edit1 = CreateWindowEx(
                           0, TEXT("EDIT"),   
                           TEXT("INS"),         
                           WS_CHILD | WS_VISIBLE | WS_TABSTOP |
                           WS_DLGFRAME, 
                           0, 0, 80, 20,   
                           hwnd,         
                           NULL,
                           hEdit1, 
                           NULL);
                   Button1 = CreateWindowEx(
                             0, TEXT("BUTTON"),   
                             TEXT("get string"),         
                             WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
                             0, 20, 80, 20,   
                             hwnd,         
                             (HMENU)ID_BUTTON1,
                             hButton1, 
                             NULL);
                  break;
}
             
        
        
case WM_COMMAND:
             {
             if (wParam == ID_BUTTON1){
                                       RECT rect = {0,40,80,60};
                                       strlength = GetWindowTextLength(Edit1);
                                       str = new char [strlength];
                                       GetWindowText(Edit1, str, strlength);
                                       UpdateWindow(hwnd);
                                       }
             break;
             }


I made an edit control which enable user input, and a button control which should get the length of the user input and copy them up into "str" then immediately update the window. And the window should draw the text int the edit box, but it is seem that the drawtext() didn't draw anything. What did i missed cause this problem?
Last edited on
Lot of odd stuff there, but this ...

1
2
3
4
PAINTSTRUCT ps;
RECT rect = {0,40,80,60};
ps.rcPaint = rect;
BeginPaint(hwnd, &ps);


is incorrect usage. The 2nd parameter of BeginPaint is an output parameter - not an input parameter. Meaning, that Windows loads it upon call with a rect struct containing the coordinates of the Invalid Rectangle. So what is happening in your case is that your rect isn't being used in any way to draw your text. Likely all coordinates are zero at the point of your button click, and your text is being drawn into a 0, 0, 0, 0 rectangle. That may be why it doesn't seem to work.
I change the draw text argument to see whether it is working or not:
DrawText(ps.hdc, "123abc", 54, &rect, DT_CENTER);

when i run the code, i see it draw "ing BUTTON", but i can't figure out where is these word come from. And it does not response to the button click.

In the WM_CREATE, i added a static control. And in the WM_COMMAND, i added a setwindowtext function to see if there anything problem with my getwindowtext or my str.
1
2
3
4
5
6
7
8
9
10
11
12
Static1 = CreateWindowEx( // in WM_CREATE
                             0, TEXT("STATIC"),   
                             str,         
                             WS_CHILD | WS_VISIBLE | WS_TABSTOP, 
                             0, 60, 80, 80,   
                             hwnd,         
                             NULL,
                             hStatic1, 
                             NULL);

// in WM_COMMAND
SetWindowText(Static1, str);


The static control does change its text to the inside the edit box when the button is clicked.
Don't know if this is my good deed for the day or not, but here is a complete working program for you that does what you want. I named my main file Main.cpp and the header Main.h ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Main.h
#ifndef Main_h
#define Main_h

#define  IDC_BUTTON1          1500
#define  IDC_EDITBOX1         1505

#define dim(x) (sizeof(x) / sizeof(x[0]))

struct WndEventArgs
{
 HWND                         hWnd;
 WPARAM                       wParam;
 LPARAM                       lParam;
 HINSTANCE                    hIns;
};

long fnWndProc_OnCreate       (WndEventArgs& Wea);
long fnWndProc_OnCommand      (WndEventArgs& Wea);
long fnWndProc_OnPaint        (WndEventArgs& Wea);
long fnWndProc_OnDestroy      (WndEventArgs& Wea);

struct EVENTHANDLER
{
 unsigned int                 iMsg;
 long                         (*fnPtr)(WndEventArgs&);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                  fnWndProc_OnCreate},
 {WM_COMMAND,                 fnWndProc_OnCommand},
 {WM_PAINT,                   fnWndProc_OnPaint},
 {WM_DESTROY,                 fnWndProc_OnDestroy}
};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Main.cpp
#include <windows.h>
#include <tchar.h>
#include "Main.h"


long fnWndProc_OnCreate(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hCtl;

 Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 hCtl=CreateWindowEx(0,_T("button"),_T("Button #1"),WS_CHILD | WS_VISIBLE,75,60,150,30,Wea.hWnd,(HMENU)IDC_BUTTON1,Wea.hIns,0);
 hCtl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD | WS_VISIBLE,75,110,150,30,Wea.hWnd,(HMENU)IDC_EDITBOX1,Wea.hIns,0);
 pBuffer=(TCHAR*)GlobalAlloc(GPTR,256);
 if(pBuffer)
    SetWindowLongPtr(Wea.hWnd,0,(LONG)pBuffer);

 return 0;
}


long fnWndProc_OnCommand(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hEdit;

 switch(LOWORD(Wea.wParam))
 {
    case IDC_BUTTON1:
         hEdit=GetDlgItem(Wea.hWnd,IDC_EDITBOX1);
         pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
         if(pBuffer)
         {
            GetWindowText(hEdit,pBuffer,255);
            InvalidateRect(Wea.hWnd,NULL,FALSE);
         }
         break;
 }

 return 0;
}


long fnWndProc_OnPaint(WndEventArgs& Wea)
{
 HDC hDC=NULL;
 PAINTSTRUCT ps;
 TCHAR* pBuffer=NULL;
 int iPrev=0;

 hDC=BeginPaint(Wea.hWnd,&ps);
 iPrev=SetBkMode(hDC,TRANSPARENT);
 pBuffer=(TCHAR*)GetWindowLong(Wea.hWnd,0);
 TextOut(hDC,75,160,pBuffer,_tcslen(pBuffer));
 SetBkMode(hDC,iPrev);
 EndPaint(Wea.hWnd,&ps);

 return 0;
}


long fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;

 pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
 if(pBuffer)
    GlobalFree(pBuffer);
 PostQuitMessage(0);

 return 0;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(unsigned int i=0; i<dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("TextOut");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=0;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=sizeof(void*);
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}


The above program contains no global variables. I consider this to be good practice. Also, it doesn't use a switch logic structure to route messages to the message handling procedures, but rather a for loop. I also consider this as something you might want to consider.

Further note that BeginPaint should return a HDC that you use for DrawText or TextOut.
Last edited on
Wow, never see this before, there are some part I still don't understand. What is that fnPtr in the main.h? And your window procedure always looping from create then command then paint then destroy?

And thanks for spending your time to help me out.
Last edited on

What is that fnPtr in the main.h? And your window procedure always looping from create then command then paint then destroy?


I've a tutorial on that here ...

http://www.jose.it-berater.org/smfforum/index.php?topic=3391.0

Also, you can substitute DrawText for TextOut if you like. TextOut is just easier to use.

Does the program do what you want?

Also, fnWndProc_OnCreate(), fnWndProc_OnCommand(), fnWndProc_OnPaint(), and fnWndProc_OnDestroy() are only called when a WM_CREATE, a WM_COMMAND, a WM_PAINT, and a WM_DESTROY come through my Window Procedure. My link above will explain that.

It looks to me where you were going wrong is your WM_PAINT code. You need to save the return value from BeginPaint in an HDC variable and use that in your DrawText.
...
http://lmgtfy.com/?q=DrawText&l=1

char *str = new char; is wrong. Stick to std::string and use c_str().
Last edited on
I didn't know what to make of that either EssGeEich. That's why I said ...


Lot of odd stuff there, ...


All that term seems to do is allocate room for 1 char. And that is not enough for even one character, being as it needs to be null terminated. However, due to memory allocation granularity, one would likely end up with 4 or 8 bytes of usable room. I'd never recommend operating like that though.
Yeah the program does what I want it to do. I really have no idea how to use that c_str(), my compiler said it has bot been declare even after i included the string header.

The cbwndextra hold TCHAR typed text with 256 bytes of size right? If i want the cbwndextra to hold struct, is this the right way :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
struct pBufferStruct
{
  TCHAR pBuffer1[255];
  TCHAR pBuffer2[255];     
};


long fnWndProc_OnCreate(WndEventArgs& Wea)
{
 pBufferStruct* pBuffer = NULL;
 HWND hCtl;

 Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 hCtl=CreateWindowEx(0,_T("button"),_T("Button #1"),WS_CHILD | WS_VISIBLE,75,60,150,30,Wea.hWnd,(HMENU)IDC_BUTTON1,Wea.hIns,0);
 hCtl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD | WS_VISIBLE,75,110,150,30,Wea.hWnd,(HMENU)IDC_EDITBOX1,Wea.hIns,0);
 pBuffer=(pBufferStruct*)GlobalAlloc(GPTR,256);
 //if(pBuffer)
    SetWindowLongPtr(Wea.hWnd,0,(LONG)malloc(sizeof(pBufferStruct)));

 return 0;
}


long fnWndProc_OnCommand(WndEventArgs& Wea)
{
 pBufferStruct* pBuffer=NULL;
 HWND hEdit;

 switch(LOWORD(Wea.wParam))
 {
    case IDC_BUTTON1:
         hEdit=GetDlgItem(Wea.hWnd,IDC_EDITBOX1);
         pBuffer=(pBufferStruct*)GetWindowLongPtr(Wea.hWnd,0);
         if(pBuffer)
         {
            GetWindowText(hEdit,pBuffer->pBuffer1,255);
            InvalidateRect(Wea.hWnd,NULL,FALSE);
         }
         break;
 }

 return 0;
}


long fnWndProc_OnPaint(WndEventArgs& Wea)
{
 HDC hDC=NULL;
 PAINTSTRUCT ps;
 pBufferStruct* pBuffer=NULL;
 int iPrev=0;

 hDC=BeginPaint(Wea.hWnd,&ps);
 iPrev=SetBkMode(hDC,TRANSPARENT);
 pBuffer=(pBufferStruct*)GetWindowLong(Wea.hWnd,0);
 TextOut(hDC,75,160,pBuffer->pBuffer1,_tcslen(pBuffer->pBuffer1));
 SetBkMode(hDC,iPrev);
 EndPaint(Wea.hWnd,&ps);

 return 0;
}


long fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 pBufferStruct* pBuffer=NULL;

 pBuffer=(pBufferStruct*)GetWindowLongPtr(Wea.hWnd,0);
 if(pBuffer)
    GlobalFree(pBuffer);
 PostQuitMessage(0);

 return 0;
}


The weird things with this changes is the program appeared with ''&g painted at the TextOut position. And other things seem to be work fine.

In the globalAlloc, only 256 size is allocated, does this mean those two member(pBuffer1 and pBuffer2) share 256 bytes only?
You are only using C. Not C++. std::string is part of <iostream>, not of <string.h> or <cstring>.
Also, never use GlobalAlloc/GlobalFree/malloc/free unless EXPLICITLY required.
Use New/Delete instead. Who the hell is sharing codes using GlobalAlloc/GlobalFree I don't know, it's being kinda common these days to find GlobalAlloc and GlobalFree here on c++.com.

freddie1 wrote:

All that term seems to do is allocate room for 1 char. And that is not enough for even one character, being as it needs to be null terminated. However, due to memory allocation granularity, one would likely end up with 4 or 8 bytes of usable room. I'd never recommend operating like that though.

That's why I said it's
EssGeEich wrote:
wrong
.

Take a look at our Tutorials to understand how std::string works, and get used to new C++ functionalities, they're there to be used.
http://www.cplusplus.com/doc/tutorial/

The cbwndextra hold TCHAR typed text with 256 bytes of size right? If i want the cbwndextra to hold struct, is this the right way :


No, not exactly. The WNDCLASSEX::cbWndExtra bytes are generally used to hold pointers to data rather than data itself. Those bytes are accessed in increments of 4 or 8 depending on whether you are compiling for 32 bit or 64 bit.

In the case you gave above with this ...

1
2
3
4
5
struct BufferStruct
{
  TCHAR pBuffer1[255];
  TCHAR pBuffer2[255];     
};


If you allocated one of those like so ...

BufferStruct* pBufferStruct=NULL;
pBufferStruct=new BufferStruct;

Then the sizeof(BufferStruct) = 1010, but the sizeof pBufferStruct is only 4 or 8 depending on 32/64 bit compile. What you would store in the WNDCLASSEX::cbWndExtra bytes is pBufferStruct.
Last edited on
Here's an example ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;

struct SomeStructure
{
 int  iSomething;
 char szBuffer[12];
};

int main()
{
 SomeStructure* pStruct=new SomeStructure;
 pStruct->iSomething=12345;
 cout << "pStruct->iSomething = " << pStruct->iSomething << "\n";
 delete pStruct;

 return 0;
}


Storing the pointer pStruct at offset 0 in the WNDCLASSEX::.cbWndExtra would look like this ...

SetWindowLongPtr(hWnd, 0, (LONG_PTR)pStruct);
Last edited on
I see EssGeEich doesn't like my GlobalAlloc(). Here's the program using HeapAlloc() instead. Check out how much better it runs! ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Form3.h
#ifndef Main_h
#define Main_h

#define  IDC_BUTTON1          1500
#define  IDC_EDITBOX1         1505

#define dim(x) (sizeof(x) / sizeof(x[0]))

struct WndEventArgs
{
 HWND                         hWnd;
 WPARAM                       wParam;
 LPARAM                       lParam;
 HINSTANCE                    hIns;
};

long fnWndProc_OnCreate       (WndEventArgs& Wea);
long fnWndProc_OnCommand      (WndEventArgs& Wea);
long fnWndProc_OnPaint        (WndEventArgs& Wea);
long fnWndProc_OnDestroy      (WndEventArgs& Wea);

struct EVENTHANDLER
{
 unsigned int                 iMsg;
 long                         (*fnPtr)(WndEventArgs&);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                  fnWndProc_OnCreate},
 {WM_COMMAND,                 fnWndProc_OnCommand},
 {WM_PAINT,                   fnWndProc_OnPaint},
 {WM_DESTROY,                 fnWndProc_OnDestroy}
};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Main.cpp
#include <windows.h>
#include <tchar.h>
#include "Main.h"


long fnWndProc_OnCreate(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hCtl;

 Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 hCtl=CreateWindowEx(0,_T("button"),_T("Button #1"),WS_CHILD | WS_VISIBLE,75,60,150,30,Wea.hWnd,(HMENU)IDC_BUTTON1,Wea.hIns,0);
 hCtl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD | WS_VISIBLE,75,110,150,30,Wea.hWnd,(HMENU)IDC_EDITBOX1,Wea.hIns,0);
 pBuffer=(TCHAR*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,256);
 if(pBuffer)
    SetWindowLongPtr(Wea.hWnd,0,(LONG)pBuffer);

 return 0;
}


long fnWndProc_OnCommand(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hEdit;

 switch(LOWORD(Wea.wParam))
 {
    case IDC_BUTTON1:
         hEdit=GetDlgItem(Wea.hWnd,IDC_EDITBOX1);
         pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
         if(pBuffer)
         {
            GetWindowText(hEdit,pBuffer,255);
            InvalidateRect(Wea.hWnd,NULL,FALSE);
         }
         break;
 }

 return 0;
}

long fnWndProc_OnPaint(WndEventArgs& Wea)
{
 HDC hDC=NULL;
 PAINTSTRUCT ps;
 TCHAR* pBuffer=NULL;
 int iPrev=0;

 hDC=BeginPaint(Wea.hWnd,&ps);
 iPrev=SetBkMode(hDC,TRANSPARENT);
 pBuffer=(TCHAR*)GetWindowLong(Wea.hWnd,0);
 TextOut(hDC,75,160,pBuffer,_tcslen(pBuffer));
 SetBkMode(hDC,iPrev);
 EndPaint(Wea.hWnd,&ps);

 return 0;
}



long fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;

 pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
 if(pBuffer)
    HeapFree(GetProcessHeap(),0,pBuffer);
 PostQuitMessage(0);

 return 0;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(unsigned int i=0; i<dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("TextOut");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=0;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=sizeof(void*);
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}


That produced a 12288 byte executable on disk.
I also see EssGeEich isn't happy with your (and mine) null terminated character string buffers. So we better use the C++ Standard Library's String Class I guess. So here's a version with that ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Form3.h
#ifndef Main_h
#define Main_h

#define  IDC_BUTTON1          1500
#define  IDC_EDITBOX1         1505

#define dim(x) (sizeof(x) / sizeof(x[0]))

struct WndEventArgs
{
 HWND                         hWnd;
 WPARAM                       wParam;
 LPARAM                       lParam;
 HINSTANCE                    hIns;
};

long fnWndProc_OnCreate       (WndEventArgs& Wea);
long fnWndProc_OnCommand      (WndEventArgs& Wea);
long fnWndProc_OnPaint        (WndEventArgs& Wea);
long fnWndProc_OnDestroy      (WndEventArgs& Wea);

struct EVENTHANDLER
{
 unsigned int                 iMsg;
 long                         (*fnPtr)(WndEventArgs&);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                  fnWndProc_OnCreate},
 {WM_COMMAND,                 fnWndProc_OnCommand},
 {WM_PAINT,                   fnWndProc_OnPaint},
 {WM_DESTROY,                 fnWndProc_OnDestroy}
};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Main.cpp
#define  UNICODE
#define  _UNICODE
#include <windows.h>
#include <string>
#include <tchar.h>
#include "Main.h"


long fnWndProc_OnCreate(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hCtl;

 Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 hCtl=CreateWindowEx(0,_T("button"),_T("Button #1"),WS_CHILD | WS_VISIBLE,75,60,150,30,Wea.hWnd,(HMENU)IDC_BUTTON1,Wea.hIns,0);
 hCtl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD | WS_VISIBLE,75,110,150,30,Wea.hWnd,(HMENU)IDC_EDITBOX1,Wea.hIns,0);
 pBuffer=(TCHAR*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,256);
 if(pBuffer)
    SetWindowLongPtr(Wea.hWnd,0,(LONG)pBuffer);

 return 0;
}


long fnWndProc_OnCommand(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hEdit;

 switch(LOWORD(Wea.wParam))
 {
    case IDC_BUTTON1:
         hEdit=GetDlgItem(Wea.hWnd,IDC_EDITBOX1);
         pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
         if(pBuffer)
         {
            GetWindowText(hEdit,pBuffer,255);
            InvalidateRect(Wea.hWnd,NULL,FALSE);
         }
         break;
 }

 return 0;
}

long fnWndProc_OnPaint(WndEventArgs& Wea)
{
 HDC hDC=NULL;
 PAINTSTRUCT ps;
 TCHAR* pBuffer=NULL;
 int iPrev=0;

 hDC=BeginPaint(Wea.hWnd,&ps);
 iPrev=SetBkMode(hDC,TRANSPARENT);
 pBuffer=(TCHAR*)GetWindowLong(Wea.hWnd,0);
 std::wstring strText=pBuffer;
 TextOut(hDC,75,160,strText.c_str(),strText.length());
 SetBkMode(hDC,iPrev);
 EndPaint(Wea.hWnd,&ps);

 return 0;
}



long fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;

 pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
 if(pBuffer)
    HeapFree(GetProcessHeap(),0,pBuffer);
 PostQuitMessage(0);

 return 0;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(unsigned int i=0; i<dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("TextOut");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=0;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=sizeof(void*);
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}


Well, that was a real big help, wasn't it? And now, using the C++ String Class, even though it hasn't added one helpful thing to the program, its now compiling in at 98304 bytes using Code::Blocks 12.11, as compared to the 12288 bytes of the previous version. So its bloated about 8 times bigger.
But wait! There's more. Lets even improve the program further by using 'new' memory allocation and the much loved and indispensable iostream (never seen a program here yet without #include <iostream>) ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//Form3.h
#ifndef Main_h
#define Main_h

#define  IDC_BUTTON1          1500
#define  IDC_EDITBOX1         1505
#define  ALLOCATED_OBJECTS     256

#define dim(x) (sizeof(x) / sizeof(x[0]))

struct WndEventArgs
{
 HWND                         hWnd;
 WPARAM                       wParam;
 LPARAM                       lParam;
 HINSTANCE                    hIns;
};

long fnWndProc_OnCreate       (WndEventArgs& Wea);
long fnWndProc_OnCommand      (WndEventArgs& Wea);
long fnWndProc_OnPaint        (WndEventArgs& Wea);
long fnWndProc_OnDestroy      (WndEventArgs& Wea);

struct EVENTHANDLER
{
 unsigned int                 iMsg;
 long                         (*fnPtr)(WndEventArgs&);
};

const EVENTHANDLER EventHandler[]=
{
 {WM_CREATE,                  fnWndProc_OnCreate},
 {WM_COMMAND,                 fnWndProc_OnCommand},
 {WM_PAINT,                   fnWndProc_OnPaint},
 {WM_DESTROY,                 fnWndProc_OnDestroy}
};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// Main.cpp
#define  UNICODE
#define  _UNICODE
#include <windows.h>
#include <iostream>
#include <tchar.h>
#include "Main.h"


long fnWndProc_OnCreate(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hCtl;

 Wea.hIns=((LPCREATESTRUCT)Wea.lParam)->hInstance;
 hCtl=CreateWindowEx(0,_T("button"),_T("Button #1"),WS_CHILD | WS_VISIBLE,75,60,150,30,Wea.hWnd,(HMENU)IDC_BUTTON1,Wea.hIns,0);
 hCtl=CreateWindowEx(WS_EX_CLIENTEDGE,_T("edit"),_T(""),WS_CHILD | WS_VISIBLE,75,110,150,30,Wea.hWnd,(HMENU)IDC_EDITBOX1,Wea.hIns,0);
 pBuffer=new TCHAR[ALLOCATED_OBJECTS * sizeof(TCHAR)];
 if(pBuffer)
 {
    wmemset(pBuffer,0,ALLOCATED_OBJECTS);
    SetWindowLongPtr(Wea.hWnd,0,(LONG_PTR)pBuffer);
 }

 return 0;
}


long fnWndProc_OnCommand(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;
 HWND hEdit;

 switch(LOWORD(Wea.wParam))
 {
    case IDC_BUTTON1:
         hEdit=GetDlgItem(Wea.hWnd,IDC_EDITBOX1);
         pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
         if(pBuffer)
         {
            GetWindowText(hEdit,pBuffer,255);
            InvalidateRect(Wea.hWnd,NULL,TRUE);
         }
         break;
 }

 return 0;
}

long fnWndProc_OnPaint(WndEventArgs& Wea)
{
 HDC hDC=NULL;
 PAINTSTRUCT ps;
 TCHAR* pBuffer=NULL;
 int iPrev=0;

 hDC=BeginPaint(Wea.hWnd,&ps);
 iPrev=SetBkMode(hDC,TRANSPARENT);
 pBuffer=(TCHAR*)GetWindowLong(Wea.hWnd,0);
 std::wstring strText=pBuffer;
 TextOut(hDC,75,160,strText.c_str(),strText.length());
 SetBkMode(hDC,iPrev);
 EndPaint(Wea.hWnd,&ps);

 return 0;
}



long fnWndProc_OnDestroy(WndEventArgs& Wea)
{
 TCHAR* pBuffer=NULL;

 pBuffer=(TCHAR*)GetWindowLongPtr(Wea.hWnd,0);
 if(pBuffer)
    delete [] pBuffer;
 PostQuitMessage(0);

 return 0;
}


LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
 WndEventArgs Wea;

 for(unsigned int i=0; i<dim(EventHandler); i++)
 {
     if(EventHandler[i].iMsg==msg)
     {
        Wea.hWnd=hwnd, Wea.lParam=lParam, Wea.wParam=wParam;
        return (*EventHandler[i].fnPtr)(Wea);
     }
 }

 return (DefWindowProc(hwnd, msg, wParam, lParam));
}


int WINAPI WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
 TCHAR szClassName[]=_T("TextOut");
 WNDCLASSEX wc;
 MSG messages;
 HWND hWnd;

 wc.lpszClassName=szClassName;                wc.lpfnWndProc=fnWndProc;
 wc.cbSize=sizeof (WNDCLASSEX);               wc.style=0;
 wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);     wc.hInstance=hIns;
 wc.hIconSm=LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor=LoadCursor(NULL,IDC_ARROW);
 wc.hbrBackground=(HBRUSH)COLOR_BTNSHADOW;    wc.cbWndExtra=sizeof(void*);
 wc.lpszMenuName=NULL;                        wc.cbClsExtra=0;
 RegisterClassEx(&wc);
 hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,75,75,320,305,HWND_DESKTOP,0,hIns,0);
 ShowWindow(hWnd,iShow);
 while(GetMessage(&messages,NULL,0,0))
 {
    TranslateMessage(&messages);
    DispatchMessage(&messages);
 }

 return messages.wParam;
}


That one works the best so far (not)! And check out the size with the indispensable iostream - 483328 bytes! So its 39.33 times bigger than the orioginal version I posted! But it really works good, not?



What does those bytes mean actually? What is the different when it becomes bigger?
What they are Selenium (.cbWndExtra bytes) is a half baked C-ism for attaching or associating data with an instantiation of a Window Class. In C++ one instantiates an object based on a C++ class, and can easily create member variables within the class, i.e., class data or member variables. Of course, in C++ we give them names such as in the case of a CBox, CBox::m_BoxLength, etc. Well, in C using the Windows Api there is no exact equivalent of that. But the creators of Windows added a variable to the Window Class struct named WNDCLASSEX::cbWndExtra bytes. You can specify the number of extra bytes you want in multiples of 4 or 8 depending on 32 bit or 64 bit compiles. You access them in the same way in multiples of 4 or 8 bytes starting with zero (zero based counting).

So in the case of your little problem, I looked at your window as a window whose design was to store the text entered into a text box as part of the object itself. So, in the WM_CREATE handler I allocated a buffer into which text could be written. When you click the button the persisted text is displayed in a WM_PAINT triggered by an InvalidateRect() call (that forces a WM_PAINT). When the window is destroyed the buffer is freed. You can store an unlimited amount of data that way, and eliminate global variables. Also, while not strictly C++ coding - it is pure OOP in a C sense. You have data associated with its object.
Last edited on
It's bigger, as long as you compile for DEBUG mode.
Compiling for RELEASE mode, for me, including iostream/strings, using a DLL-scriptable fully-functional HTTP server, with only speed optimizations, the executable takes 51kb.
The Debug mode "packs" variables infos in the executable.

For storing per-window data, you should use (as I've seen previously mentioned) SetWindowLongPtr and GetWindowLongPtr with GWLP_USERDATA. It does not require cbWndExtra to be defined to a valid number - it can even be 0.

NOT SetWindowLong - Careful. It won't work as flawlessly on 64-bit systems.
Last edited on
Thanks guys, i learnt a lot from this post
Another way to associate or 'persist' data with a window is using SetProp()/GetProp(). Some folks like those better than using WNDCLASSEX::cbWndExtra bytes or GWLP_USERDATA. Its a personal choice.
Topic archived. No new replies allowed.