Sign in to follow this  
SonicD007

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

Recommended Posts

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.

[code]
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;
}[/code]

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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
[quote name='SiCrane' timestamp='1317656362' post='4868584']
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.
[/quote]

Can you show me an example of what you mean with the data structure? Is this a viable approach or is this horribly wrong?
[code]
struct myWindow {
TEXT type,
TEXT txt,
DWORD style,
etc...
myWindow(TEXT,TEXT,DWORD, x,y,w,z,HWND,HMENU)
{
CreateWindow()
}
};
[/code]

Share this post


Link to post
Share on other sites
[quote name='SonicD007' timestamp='1317661549' post='4868613']
Can you show me an example of what you mean with the data structure? Is this a viable approach or is this horribly wrong?
[/quote]

There are many approaches, what SiCrane suggest is to collect all the common data into a (global) structure, instead of many individual variables.

Share this post


Link to post
Share on other sites
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 =/

Share this post


Link to post
Share on other sites
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
[code]
struct myWindow{
HWND window
};
[/code]
Then when I called CreateWindow() I did it like so:
[code]
myWindow mw;
mw.window = CreateWindow(parameters in here);
[/code]

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:
[code]
iMessageLength = GetWindowTextLength(hTextBox) (mw.window when I tried the struct approach)
[/code]

Every attempt had hTextBox as unused and iMessageLength was 0 because of that.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
I looked through everything again using the debugger and I noticed that CreateWindow is returning 0 to the handles. Maybe CreateWindow is failing for some reason? I'm going to try CreateWindowEx and if it's still 0, I'm going to try using GetLastError. Maybe I'll get a clue as to how to fix this from there.

If you notice why CreateWindow is returning 0 that would be helpful. Thanks.

EDIT: CreateWindowEx also returns 0

Share this post


Link to post
Share on other sites
[quote name='rip-off' timestamp='1317850384' post='4869561']
Why do you think that changing from CreateWindow to CreateWindowEx would change anything? What did GetLastError say?
[/quote]

I didn't think it would change anything but I figured I might as well try it. GetLastError returned 0 (ERROR_SUCCESS) so CreateWindow() is successful. I also used GetLastError() here:
[code]
case IDC_SEND:
//TO DO: don't assume its 256 char long buffer overflow possible
GetDlgItemText(hwnd, IDC_TEXTBOX, (LPSTR)cChatMessage, 256);
SetDlgItemText(hwnd, IDC_TEXTBOX, "");

iMessageLength = GetWindowTextLength(meow.hTextBox);
dw = GetLastError();
MessageBox(hwnd, (LPCSTR)iMessageLength, "length", MB_OK);
SetDlgItemText(hwnd, IDC_CHATDISPLAY, cChatMessage);
InvalidateRect(hwnd, &rcClientCoor, TRUE);
break;
[/code]

It returned 0 there as well. (I set breakpoints so I could look at what dw held because I didn't want to use format message to turn it into a string just to display it)

Share this post


Link to post
Share on other sites
If CreateWindow() or CreateWindowEx() doesn't return a window handle and GetLastError() is 0, then that generally means that your WndProc function isn't handling the window creation messages properly.

Share this post


Link to post
Share on other sites
Ok, I made a struct called like so:
[code]
struct myWindow{
HWND hTextBox;
HWND hSendButton;
HWND hChatDisplay;
HWND hChatScrollBar;
};
[/code]

In winmain, those handles are set to createwindow and if they're null it returns a messagebox saying "uh oh window is null". In winmain I don't get any messagebox because the handles aren't null. In WndProc though, the messagebox does get triggered. I don't know what's going on here =/

The winmain and wndproc are based off theforger's skeleton windows program code.

Share this post


Link to post
Share on other sites
This is the entire source
[code]
#include <windows.h>
#include <string>
#include "resource.h"

const char g_szClassName[] = "Chat Chat";
BOOL CALLBACK ConnectToDlgProc(HWND, UINT, WPARAM, LPARAM);

HWND hTextBox;
HWND hSendButton;
HWND hChatDisplay;

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

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, "");
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;
}

BOOL CALLBACK ConnectToDlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_INITDIALOG:

return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
EndDialog(hwnd, IDOK);
break;
case IDCANCEL:
EndDialog(hwnd, IDCANCEL);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}[/code]

Share this post


Link to post
Share on other sites
Hi,

i'm not quite sure what you are trying to achieve. Is it just the text length of the user input?
If so, why not simply asking for the string length?
[code] //change from hard coded 256 to get text length somehow
GetDlgItemText(hwnd, IDC_TEXTBOX, (LPSTR)cChatMessage, 256); //256 here is just the maximum size of your char[] buffer
int length = strlen(cChatMessage);[/code]

I assume your GetWindowTextLength() does not work because you're running a dialog based application.

best regards & good luck

Share this post


Link to post
Share on other sites
[quote name='Acid-Chris' timestamp='1317906747' post='4869766']
Hi,

i'm not quite sure what you are trying to achieve. Is it just the text length of the user input?
If so, why not simply asking for the string length?
[code] //change from hard coded 256 to get text length somehow
GetDlgItemText(hwnd, IDC_TEXTBOX, (LPSTR)cChatMessage, 256); //256 here is just the maximum size of your char[] buffer
int length = strlen(cChatMessage);[/code]

I assume your GetWindowTextLength() does not work because you're running a dialog based application.

best regards & good luck
[/quote]

I actually completely forgot I could do that. That would be one way I could do this (I'll probably end up doing that actually). I would still like to find out why this isn't working though. Thanks for pointing that out.

[quote name='rip-off' timestamp='1317906931' post='4869767']
I am not a Win32 programmer, but yckx's bet paid off. Your WndProc returns 0 for all events it handles, it only uses DefWindowProc when it doesn't handle an event.
[/quote]

Even if it does return 0 when it handles an event, shouldn't the handles still be accessible if they're being stored in a global HWND variable? I tried changing that return 0 to return DefWindProc and the hTextBox handle is [code]0x0004046c {unused=7471215 }[/code].

I could use the strlen() workaround but I'm still confused as to why this way isn't working. I would still like to figure this out. Thanks for the replies.

EDIT: I actually still need to be able to use the GetWindowTextLength function because I need to know the length so I can append text to the end of it

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this