window procedure HWND varible must static??

like below, my little program is this: you write some text in the edit box, and click "add" button, and it will add to the combo box, but when I first write, it doesn't add text to the combo box, then I had a hard time to find out that my HWND variable have to be static, I'm confused, because these variable can visible in the block, why they have to be static???
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
BOOL CALLBACK 
	MsgDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
	// Text buffer to be filled with string user entered 
	// into edit control. 
	char msgText[256]; 
	// Handles to the combo box controls. 
	static HWND hComboBox  = 0; // question : ****must static??**** 
	static HWND hEditBox   = 0; // question :****must static??****
	static HWND hAddButton = 0; // question :****must static??****
	int index = 0; 
    //========================================
    // below are no error
    //========================================
    switch( msg ) 
	{ 
	case WM_INITDIALOG: 
		// Controls are child windows to the dialog they lie on. 
		// In order to get and send information to and from a 
		// control we will need a handle to it.  So save a handle 
		// to the controls as the dialog is being initialized.  
		// Recall that we get a handle to a child control on a  
		// dialog box with the GetDlgItem. 
		hComboBox  = GetDlgItem(hDlg, IDC_COMBOBOX); 
		hEditBox   = GetDlgItem(hDlg, IDC_EDIT_MSG); 
		hAddButton = GetDlgItem(hDlg, IDB_ADD_BUTTON);  
		return true; 
	case WM_COMMAND: 
		switch(HIWORD(wParam)) {
		case CBN_SELENDOK:
			index = SendMessage(hComboBox, CB_GETCURSEL, 0, 0);
			SendMessage(hComboBox, CB_GETLBTEXT, (WPARAM)index, (LPARAM)msgText);
			MessageBox(0, msgText, "Combo Box", MB_OK);
			return true;
		}
		switch(LOWORD(wParam)) {
		case IDB_ADD_BUTTON:
			GetWindowText(hEditBox, msgText, 256);
			if(strlen(msgText) > 0)
				SendMessage(hComboBox, CB_ADDSTRING, 0, (LPARAM)msgText);
			return true;
		}
		return true;
	case WM_CLOSE: 
		DestroyWindow(hDlg); 
		return true; 
	case WM_DESTROY: 
		PostQuitMessage(0); 
		return true; 
	} 
	return false; 
} 
Last edited on
Yes, they have to be static, otherwise it will be automatically deleted when the function MsgDlgProc returns (and Windows calls this function multiple times).

However you could change the code like this:
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
BOOL CALLBACK 
	MsgDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
	// Text buffer to be filled with string user entered 
	// into edit control. 
	char msgText[256]; 
	// Handles to the combo box controls. 
	HWND hComboBox  = GetDlgItem(hDlg, IDC_COMBOBOX); 
	HWND hEditBox   = GetDlgItem(hDlg, IDC_EDIT_MSG); 
	HWND hAddButton = GetDlgItem(hDlg, IDB_ADD_BUTTON);
	int index = 0; 
    //========================================
    // below are no error
    //========================================
    switch( msg ) 
	{ 
	case WM_INITDIALOG: 
		// Controls are child windows to the dialog they lie on. 
		// In order to get and send information to and from a 
		// control we will need a handle to it.  So save a handle 
		// to the controls as the dialog is being initialized.  
		// Recall that we get a handle to a child control on a  
		// dialog box with the GetDlgItem. 
		  
		return true; 
	case WM_COMMAND: 
		switch(HIWORD(wParam)) {
		case CBN_SELENDOK:
			index = SendMessage(hComboBox, CB_GETCURSEL, 0, 0);
			SendMessage(hComboBox, CB_GETLBTEXT, (WPARAM)index, (LPARAM)msgText);
			MessageBox(0, msgText, "Combo Box", MB_OK);
			return true;
		}
		switch(LOWORD(wParam)) {
		case IDB_ADD_BUTTON:
			GetWindowText(hEditBox, msgText, 256);
			if(strlen(msgText) > 0)
				SendMessage(hComboBox, CB_ADDSTRING, 0, (LPARAM)msgText);
			return true;
		}
		return true;
	case WM_CLOSE: 
		DestroyWindow(hDlg); 
		return true; 
	case WM_DESTROY: 
		PostQuitMessage(0); 
		return true; 
	} 
	return false; 
} 
Last edited on
You can also let Windows store a pointer for you:
1
2
YourDataType * Data = new YourDataType();
SetWindowLongPtr( (Window Handle), GWLP_USERDATA, (LONG_PTR)Data );

And get it back like this:
 
 YourDataType * Ptr = (YourDataType *)GetWindowLongPtr( (Window Handle), GWLP_USERDATA );


Remember to use new to store the pointer, or you may give a pointer to the stack - Thing that you should NEVER do unless you know what will happen.
Remember to delete your pointer in the WM_DESTROY handling:
1
2
3
4
case WM_DELETE:
 YourDataType * Ptr = (YourDataType *)GetWindowLongPtr( (Window Handle), GWLP_USERDATA );
if(Ptr) delete Ptr;
SetWindowLongPtr( (Window Handle), GWLP_USERDATA, 0);


So in the beginning create a struct that holds everything:

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
struct WindowProcData {
	DWORD Test;
	char msgText[256]; 
	HWND hComboBox; 
	HWND hEditBox; 
	HWND hAddButton;
};
// Then, in your WndProc:
case WM_INITDIALOG:
{
	WindowProcData * wpd = new WindowProcData;
	wpd->Test = 0xCFF4F3F3; // Test this later - To make sure you're having a good structure
	wpd->hComboBox = ... // initialize
	SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)(wpd));
}
break;
case WM_COMMAND:
{
	WindowProcData * wpd = (WindowProcData *)(GetWindowLongPtr(hDlg,GWLP_USERDATA));
	if(wpd && wpd->Test == 0xCFF4F3F3)
	{
		// You can keep on and use wpd almost safely!
	}
}
break;
case WM_DESTROY:
{
	WindowProcData * wpd = (WindowProcData *)(GetWindowLongPtr(hDlg,GWLP_USERDATA));
	if(wpd && wpd->Test == 0xCFF4F3F3)
	{
		delete wpd;
		wpd = 0;
		SetWindowLongPtr(hDlg,GWLP_USERDATA,0);
	}
}
Last edited on
What's GWL_USERDATA ? That will not work if you compile for 64 bit (code will not even compile). Use GWLP_USERDATA instead for both 32 and 64 bit .

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644898%28v=vs.85%29.aspx
modoran wrote:
What's GWL_USERDATA ? That will not work if you compile for 64 bit (code will not even compile). Use GWLP_USERDATA instead for both 32 and 64 bit .

Oh yeah I always forget :|
hi,
modoran
,frist thanks a lot
is there any advantage or disadvantage in mine and your version? can you list some things?
His version is a bit slower, because it always re-computes the variables. Mine is the best one, it is safer to use more than one of the same windows of the same type without problems. It is also widely used in windows for professional applications I believe, I've seen many applications use the same way to store per-window data (SFML, Scintilla... ).
Topic archived. No new replies allowed.