Out of scope problem (I think) [C++]

Started by
19 comments, last by yckx 12 years, 6 months ago
Hi, I'm using C++ and the windows api to make a simple chat program. Right now, I'm still setting up the gui and trying to get some basic things working. I'm having trouble getting the text length from my child windows because I believe they are going out of scope. When I put a breakpoint after the GetWindowTextLength() the handle I pass to that function is always 0x00000000. Here's what the code looks like.


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
char cChatMessage[256];

HWND hTextBox = NULL;
HWND hSendButton = NULL;
HWND hChatDisplay = NULL;

HDC hdc;
TEXTMETRIC tmFontSize;

RECT rcClientCoor;
GetClientRect(hwnd, &rcClientCoor);
RECT rcTextBoxCoor = { 0, rcClientCoor.bottom - 20, rcClientCoor.right - 200, 20 };
RECT rcSendButtonCoor = { rcTextBoxCoor.right + 20, rcClientCoor.bottom - 20, (rcClientCoor.right - rcTextBoxCoor.right), 20};
RECT rcChatDisplayCoor = { 0, 0, rcTextBoxCoor.right, rcTextBoxCoor.top - 20 };

int iMessageLength;
switch(msg)
{
case WM_CREATE:
hTextBox = CreateWindow(TEXT("Edit"), TEXT(""), WS_VISIBLE | WS_CHILD | WS_BORDER | ES_AUTOHSCROLL,
rcTextBoxCoor.left, rcTextBoxCoor.top, rcTextBoxCoor.right, rcTextBoxCoor.bottom,
hwnd, (HMENU)IDC_TEXTBOX, NULL, NULL);

hSendButton = CreateWindow(TEXT("Button"), TEXT("Send"), WS_VISIBLE | WS_CHILD | WS_BORDER | BS_PUSHBUTTON,
rcSendButtonCoor.left, rcSendButtonCoor.top, rcSendButtonCoor.right, rcSendButtonCoor.bottom,
hwnd, (HMENU)IDC_SEND, NULL, NULL);

hChatDisplay = CreateWindow(TEXT("Edit"), TEXT(""), WS_VISIBLE | WS_CHILD |WS_BORDER | ES_MULTILINE,
rcChatDisplayCoor.left, rcChatDisplayCoor.top, rcChatDisplayCoor.right, rcChatDisplayCoor.bottom,
hwnd, (HMENU)IDC_CHATDISPLAY, NULL, NULL);
break;
case WM_SIZE:

break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_FILE_EXIT:
DestroyWindow(hwnd);
break;
case ID_CONNECT_CONNECTTO:
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONNECTTO), hwnd, ConnectToDlgProc);
break;
case ID_HELP_ABOUT:
MessageBox(hwnd, "Created by SonicD007", "About", MB_OK);
break;
case IDC_SEND:
//change from hard coded 256 to get text length somehow
GetDlgItemText(hwnd, IDC_TEXTBOX, (LPSTR)cChatMessage, 256);

SetDlgItemText(hwnd, IDC_TEXTBOX, "");

//This is where the problem is. hTextBox is null (out of scope I believe)
iMessageLength = GetWindowTextLength(hTextBox);

MessageBox(hwnd, (LPCSTR)iMessageLength, "Text length", MB_OK);
InvalidateRect(hwnd, &rcClientCoor, TRUE);
break;
}
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
GetDlgItemText(hwnd, IDC_TEXTBOX, (LPSTR)cChatMessage, 256);

SetDlgItemText(hwnd, IDC_TEXTBOX, "");
InvalidateRect(hwnd, &rcClientCoor, TRUE);
break;
}
break;

case WM_PAINT:
PAINTSTRUCT ps;
hdc = BeginPaint(hwnd, &ps);
GetTextMetrics(hdc, &tmFontSize);
EndPaint(hwnd, &ps);
break;

case WM_CLOSE:
DestroyWindow(hwnd);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;

default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

if(!RegisterClassEx(&wc))
{
MessageBox(NULL, "Window Registration Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
g_szClassName,
"Chat Chat v0.1",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
NULL, NULL, hInstance, NULL);

if(hwnd == NULL)
{
MessageBox(NULL, "Window Creation Failed!", "Error!",
MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}


Any help would be appreciated. Also feel free to critique the code, I know there's no error checking and it looks pretty sloppy at the moment but I appreciate the helpful comments. Thanks.
Advertisement
Local variables don't retain their value across different function calls unless they are declared static. However, rather than use static in this case, you should probably use an actual data structure for your window information.

Local variables don't retain their value across different function calls unless they are declared static. However, rather than use static in this case, you should probably use an actual data structure for your window information.


Can you show me an example of what you mean with the data structure? Is this a viable approach or is this horribly wrong?

struct myWindow {
TEXT type,
TEXT txt,
DWORD style,
etc...
myWindow(TEXT,TEXT,DWORD, x,y,w,z,HWND,HMENU)
{
CreateWindow()
}
};

Can you show me an example of what you mean with the data structure? Is this a viable approach or is this horribly wrong?


There are many approaches, what SiCrane suggest is to collect all the common data into a (global) structure, instead of many individual variables.
Sorry but I'm still not getting what I need to do. I tried making the handles global static variables but I'm still getting the handle as unused. Tried making a global struct with three HWND variables declared that were then set to CreateWindow in the WM_CREATE portion and it still wasn't working. I'm obviously doing something wrong =/
Can you show us some of the alternatives you tried, and any relevant compile/runtime errors that they produced?

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Attempt # 1: Tried declaring the variables as static. Result: still null
Attempt # 2: Tried declaring the variables as globals. Result: still null
Attempt # 3: Tried declaring the variables as globals and as static. Result: still null
Attempt # 4: Tried creating a global struct such as: Result: still null

struct myWindow{
HWND window
};

Then when I called CreateWindow() I did it like so:

myWindow mw;
mw.window = CreateWindow(parameters in here);


Everything compiles and runs. I put a breakpoint where I was calling the MessageBox to display the windowtextlength and looked at the line before the MessageBox which was:

iMessageLength = GetWindowTextLength(hTextBox) (mw.window when I tried the struct approach)


Every attempt had hTextBox as unused and iMessageLength was 0 because of that.
hTextBox is only set when msg == WM_CREATE so if this never happens hTextBox will always be null.
I'm pretty sure the WM_Create message does get sent otherwise I wouldn't be able to see or interact with the child windows
Maybe a dumb question, but did you make sure to remove the local versions from WndProc and only update the globals for WM_CREATE? If you put a breakpoint in WM_CREATE and watch your globals/struct, does it get set to a valid-looking value? If so, try setting a data breakpoint on the variable for one of the child HWNDs and see if it gets modified someplace else.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

This topic is closed to new replies.

Advertisement