GetWindowtext returning nothing - c++

I'm trying to learn how to make a GUI for a C++ using visual studio. I’ trying to create a button that when you push it a textbox with the content of a edit window appear, but the GetWindowText function is Returning a blank string when I run my program. I have tried to adjust the size of the buffer to see if that is the problem, but I haven’t been able to solve it that way. I have tried using number instead of the GetWindowTextLength() funktion, but I could not get it to work that way.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{` HMENU hMenubar = CreateMenu();
HMENU hFile = CreateMenu();
HMENU hOptions = CreateMenu();
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hFile, L"File");
AppendMenu(hMenubar, MF_POPUP, NULL, L"Edit");
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hOptions, L"Options");
AppendMenu(hFile, MF_STRING, NULL, L"Exit");
AppendMenu(hOptions, MF_STRING, NULL, L"option 1");
AppendMenu(hOptions, MF_STRING, NULL, L"option 2");
SetMenu(hWnd, hMenubar);
CreateWindow(TEXT("button"), TEXT("Hello"),
WS_VISIBLE | WS_CHILD,
10, 10, 80, 25,
hWnd, (HMENU) ID_BUTTON1, NULL, NULL);
static HWND hWndTextbox = CreateWindow(TEXT("edit"), TEXT("sim"),
WS_VISIBLE | WS_CHILD|WS_BORDER | ES_AUTOHSCROLL,
90, 120, 300, 20,
hWnd, (HMENU) ID_TEXT3, NULL, NULL);
CreateWindow(TEXT("button"), TEXT("shiny"),
WS_VISIBLE | WS_CHILD,
50, 50, 80, 50,
hWnd, (HMENU) ID_BUTTON2, NULL, NULL);
}
break;
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_BUTTON1) {
MessageBox(hWnd, TEXT("Button has been clicked"), TEXT("title for popup"), MB_ICONINFORMATION);
}
if (LOWORD(wParam) == ID_BUTTON2) {
// create some default vars
// Allocate buffer including terminating null
int length = GetWindowTextLength(hWndTextbox) + 1;
std::wstring uinput(GetWindowTextLength(hWndTextbox) + 1, 0);
// Address of first character is used to obtain pointer to non-const data
// (as opposed to wstring::c_str()).
int size = GetWindowText(hWndTextbox, &uinput[0], length+1);
// Resize buffer to the actual text length
uinput.resize(size);
// MessageBox only needs pointer to const string, so we can use wstring::c_str() here.
MessageBox(hWnd, uinput.c_str(), TEXT("Message box"), MB_OK);
}
break;
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}`
the rest of the code was auto generated by visual studio so I have only included the part where I made changes

Related

How to create a button when another button is pressed and hide the other one

(Questions are at the bottom)
I am trying to write a program, which has one button. If this button is pressed, it should create a new button, and delete the other one, you will see here:
constexpr unsigned int button1=111;
constexpr unsigned int button2=112;
bool buttonIsPressed = false;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static RECT rect;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_CREATE:
{
GetClientRect(hWnd, &rect);
CreateWindowEx(NULL,
L"BUTTON",
L"create new button",
WS_TABSTOP | WS_VISIBLE |
WS_CHILD | BS_DEFPUSHBUTTON,
/*windowWidth-15,*/
400,
rect.bottom - 40,
100,
28,
hWnd,
(HMENU)button1,
GetModuleHandle(NULL),
NULL);
if (buttonIsPressed == true)
{
CreateWindowEx(NULL,
L"BUTTON",
L"Text of the button",
WS_TABSTOP | WS_VISIBLE |
WS_CHILD | BS_DEFPUSHBUTTON,
/*windowWidth-15,*/
400,
rect.bottom - 40,
100,
28,
hWnd,
(HMENU)button2,
GetModuleHandle(NULL),
NULL);
}
}
case WM_PAINT:
{
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case button1:
{
buttonIsPressed = true;
break;
}
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
I also tried to use UpdateWindow and InvalidateRect.
Question 1: How can i create a new button when the other button is pressed?
Question 2: How can i stop drawing the other button. If I use InvalidateRect, the button becomes invisible, but as soon as i press on the window, it is visible again.
THANK YOU for your attention and your time.
You are close. You already know to create individual buttons (CreateWindowEx()). In the code you have shown, you just need to move the 2nd CreateWindowEx() from the WM_CREATE handler into the WM_COMMAND handler, being sure to check the reported ID/HWND to make sure it is the 1st button you are interested in, and then you can ShowWindow()/DestroyWindow() that button as needed and create the new button, eg:
constexpr unsigned int button1=111;
constexpr unsigned int button2=112;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static RECT rect;
//...
switch (message)
{
case WM_CREATE:
{
GetClientRect(hWnd, &rect);
CreateWindowEx(NULL,
L"BUTTON",
L"create new button",
WS_TABSTOP | WS_VISIBLE |
WS_CHILD | BS_DEFPUSHBUTTON,
/*windowWidth-15,*/
400,
rect.bottom - 40,
100,
28,
hWnd,
(HMENU)button1,
GetModuleHandle(NULL),
NULL);
break;
}
//...
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED)
{
switch (LOWORD(wParam))
{
case button1:
{
HWND hwndBtn = (HWND)lParam;
// use ShowWindow(hwndBtn, SW_HIDE) or DestroyWindow(hwndBtn) as needed...
GetClientRect(hWnd, &rect);
CreateWindowEx(NULL,
L"BUTTON",
L"Text of the button",
WS_TABSTOP | WS_VISIBLE |
WS_CHILD | BS_DEFPUSHBUTTON,
/*windowWidth-15,*/
400,
rect.bottom - 40,
100,
28,
hWnd,
(HMENU)button2,
GetModuleHandle(NULL),
NULL);
break;
}
case button2:
{
//...
break;
}
}
return 0;
}
break;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}

How to give the DKGRAY_BRUSH to the area of the main window?

I give the background main window color by registering the window class with the hbrBackground property like this :
wcex.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
and then :
RegisterClassExW(&wcex);
The result window is white. I have the darkgray color when I minimize/maximize the window.
How can I obtain the darkgray background immediately ?
Thank you !
EDIT : The callback function :
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hgGroupBox1;
static HWND hsFileSize;
static HWND hsFileName;
static HWND hsStatic1;
static HWND hsStatic2;
static HWND hsStatic3;
static HWND hsStatic4;
static HWND hsFileID;
static HWND hlbTagV2Frames;
static HWND hStatus;
static HBRUSH hbrBkgnd;
int hauteur, largeur;
std::wstringstream lbFrames;
switch (message)
{
case WM_CREATE:
hsStatic1 = CreateWindowEx(0, L"STATIC", L"Fichier :", WS_CHILD | WS_VISIBLE, 5, 5, 60, 20, hWnd, (HMENU)ID_STATIC1, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hsFileName = CreateWindowEx(0, L"STATIC", L"", WS_CHILD | WS_VISIBLE, 65, 5, 800, 20, hWnd, (HMENU)ID_STATICFILENAME, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hgGroupBox1 = CreateWindowEx(0, L"BUTTON", L"TagV2", WS_CHILD | WS_VISIBLE | BS_GROUPBOX, 5, 30, 420, hauteur - 100, hWnd, (HMENU)ID_GROUPEBOX1, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hsStatic2 = CreateWindowEx(0, L"STATIC", L"Taille :", WS_CHILD | WS_VISIBLE, 15, 50, 100, 20, hWnd, (HMENU)ID_STATIC2, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hsFileSize = CreateWindowEx(0, L"STATIC", nullptr, WS_CHILD | WS_VISIBLE | WS_BORDER, 15, 75, 100, 20, hWnd, (HMENU) ID_STATICFILESIZE, (HINSTANCE) GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hsStatic3 = CreateWindowEx(0, L"STATIC", L"Entête :", WS_CHILD | WS_VISIBLE, 15, 100, 100, 20, hWnd, (HMENU)ID_STATIC3, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hsFileID = CreateWindowEx(0, L"STATIC", nullptr, WS_CHILD | WS_VISIBLE | WS_BORDER, 15, 125, 200, 20, hWnd, (HMENU)ID_STATICENTETEID, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hsStatic4 = CreateWindowEx(0, L"STATIC", L"Attributs du tagV2 :", WS_CHILD | WS_VISIBLE, 15, 150, 150, 20, hWnd, (HMENU)ID_GROUPEBOX1, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
hlbTagV2Frames = CreateWindow(L"LISTBOX", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | LBS_NOTIFY, 15, 175, 400, 200, hWnd, (HMENU)ID_LISTBOXFRAMES, (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE), nullptr);
ShowWindow(hsStatic1, SW_SHOW);
ShowWindow(hgGroupBox1, SW_SHOW);
ShowWindow(hsStatic2, SW_SHOW);
ShowWindow(hsFileSize, SW_SHOW);
ShowWindow(hsStatic3, SW_SHOW);
ShowWindow(hsFileID, SW_SHOW);
ShowWindow(hStatus, SW_SHOW);
ShowWindow(hsStatic4, SW_SHOW);
ShowWindow(hlbTagV2Frames, SW_SHOW);
break;
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Analyse les sélections de menu :
switch (wmId)
{
case IDM_FICHIER_OUVRIR:
//Here comes the file treatement code.
}
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Ajoutez ici le code de dessin qui utilise hdc...
EndPaint(hWnd, &ps);
}
break;
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(0, 0, 0));
SetBkColor(hdcStatic, DKGRAY_BRUSH);
hbrBkgnd = CreateSolidBrush(DKGRAY_BRUSH);
return (INT_PTR)hbrBkgnd;
}
}
case WM_CTLCOLORBTN:
{
HDC hdcButton = (HDC)wParam;
SetTextColor(hdcButton, RGB(255, 255, 255));
SetBkColor(hdcButton, DKGRAY_BRUSH);
}
hbrBkgnd = CreateSolidBrush(DKGRAY_BRUSH);
return (INT_PTR)hbrBkgnd;
case WM_ERASEBKGND:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
WM_ERASEBKGND : Sent when the window background must be erased (for example, when a window is resized). The message is sent to
prepare an invalidated portion of a window for painting.
The simplest solution: delete WM_ERASEBKGND message or add return DefWindowProc(hWnd, message, wParam, lParam) in the WM_ERASEBKGND message if you do not want delete WM_ERASEBKGND.
You could use WM_PAINT to fill the main window with the Brush using FillRect in your windows procedure. That should accomplish what you want.
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, reinterpret_cast<HBRUSH>(COLOR_ACTIVECAPTION + 1));
EndPaint(hwnd, &ps);
} return 0;
See the FillRect function https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-fillrect

Enable Close Button for Dialog c++ winapi

Having simple window, button which opens dialog. But I want to add close button to it.
I have tried to add close button with adding WM_SYSMENU, with adding EnableMenuItem, but it didn't work:
Minimal code is:
resource.rc:
IDD_FORMVIEW DIALOGEX 0, 0, 178, 86
STYLE DS_SETFONT | DS_CONTROL | WS_VISIBLE | WS_SYSMENU
EXSTYLE WS_EX_OVERLAPPEDWINDOW
CAPTION "TEST"
FONT 12, "Microsoft Sans Serif", 400, 0, 0xCC
BEGIN
CTEXT "Test",IDC_STATIC,46,4,74,8,0,WS_EX_CLIENTEDGE
END
resource.h:
#define IDD_FORMVIEW 101
Test.cpp:
hwndButton = CreateWindowW(L"BUTTON",
L"ENTER",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS,
605, 510, 255, 45,
hWnd, (HMENU)1, NULL, NULL);
case WM_COMMAND:
{
switch (LOWORD(wParam)) {
case 2: {
if (hwndHTDW == NULL) {
hwndHTDW = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_FORMVIEW), hWnd, DialogProc);
ShowWindow(hwndHTDW, SW_SHOW);
UpdateWindow(hwndHTDW);
}
}
break;
}
}
{
switch (msg) {
case WM_INITDIALOG: {
EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_CLOSE,
MF_BYCOMMAND | MF_ENABLED);
return TRUE;
}
break;
default:
return FALSE;
}
return TRUE;
Modify your code a little bit.
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
hwndButton = CreateWindowW(L"BUTTON",
L"ENTER",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS,
605, 510, 255, 45,
hWnd, (HMENU)1, NULL, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case 1:
{
if (hwndHTDW == NULL)
{
hwndHTDW = CreateDialog(hInst, MAKEINTRESOURCE(IDD_FORMVIEW), hWnd, DialogProc);
Button_Close = CreateWindowW(L"BUTTON",
L"CLOSE",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS | WS_TABSTOP,
130, 100, 80, 30,
hwndHTDW, (HMENU)2, NULL, NULL);
ShowWindow(hwndHTDW, SW_SHOW);
UpdateWindow(hwndHTDW);
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
BOOL CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL fError;
switch (message)
{
case WM_INITDIALOG:
{
EnableMenuItem(GetSystemMenu(hwnd, FALSE), SC_CLOSE,
MF_BYCOMMAND | MF_ENABLED);
return TRUE;
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case 2:
{
EndDialog(hwnd, LOWORD(wParam));
return (INT_PTR)TRUE;
}
default:
break;
}
}
default:
return FALSE;
}
return TRUE;
}
Updated:
Create an extra button through CreateWindow and pass the handle of the dialog box to the button as a parameter.
HWND Button_Close = CreateWindowW(L"BUTTON",
L"CLOSE",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_CLIPSIBLINGS | WS_TABSTOP,
130, 100, 80, 30,
hwndHTDW, (HMENU)2, NULL, NULL);
In the callback function of the dialog box, add the WM_COMMAND event and add the following code.
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case 2:
{
EndDialog(hwnd, LOWORD(wParam));
return (INT_PTR)TRUE;
}
}

Edit control doesn't work correctly

I started to learning winapi c++ today. And i wrote this simple program that have to change window name to the name that i write in text box:
#include <Windows.h>
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
void AddMenu(HWND);
void AddControl(HWND);
HWND hEdit;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrewInst, LPSTR args, int ncmdshow)
{
WNDCLASSW wc = { 0 };
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpszClassName = L"class";
wc.lpfnWndProc = WindowProcedure;
if (!RegisterClassW(&wc))
return -1;
CreateWindowW(L"class", L"Window", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, NULL, NULL);
MSG msg = { 0 };
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_COMMAND:
switch (wp)
{
case 1:
MessageBeep(MB_SERVICE_NOTIFICATION); break;
case 2:
DestroyWindow(hWnd); break;
case 3:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
break;
}
case WM_CREATE:
AddMenu(hWnd);
AddControl(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wp, lp);
}
}
void AddMenu(HWND hWnd)
{
HMENU hMenu;
hMenu = CreateMenu();
HMENU file;
file = CreateMenu();
HMENU Sub;
Sub = CreateMenu();
AppendMenu(hMenu, MF_POPUP, (UINT_PTR)file, "File");
AppendMenu(file, MF_STRING, 1, "Open");
AppendMenu(file, MF_POPUP, (UINT_PTR)Sub, "Sub");
AppendMenu(file, MF_STRING, 2, "Exit");
AppendMenu(Sub, MF_STRING, 3, "Change");
SetMenu(hWnd, hMenu);
}
void AddControl(HWND hWnd)
{
CreateWindowW(L"Static", L"Enter text: ", WS_VISIBLE | WS_CHILD | WS_BORDER | SS_CENTER, 200, 100, 100, 20, hWnd, NULL, NULL, NULL);
hEdit = CreateWindowW(L"Edit", L"...", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, 200, 152, 100, 50, hWnd, NULL, NULL, NULL);
}
By default in text box i have .... So i run my program, starting to type hello world for expample but nothing changes. I highlited my 3 dots that had to change and boom, my text appeared. I go to the menu choose File -> Sub -> Change and my window name changes to 3 dots ....
BUT! If i delete these: | ES_MULTILINE | ES_AUTOVSCROLL then text box working correctly but menu doesnt show up in my window.
I found that i have to do smth with EN_CHANGE but idk what. I tried to change WM_COMMAND to EN_CHANGE and my textbox worked correctly, but other menu buttons didnt work at all...
Your failure is caused by handling all the edit control notifications the same way. You need to test the notification code (found in HIWORD(wParam)) to see whether it is EN_CHANGE, and let notifications you aren't handling pass through to DefWindowProc.
You also have an even bigger bug in that you reach the closing brace of a function with a non-void return type. You need to always return something; when you aren't calling DefWindowProc the system still expects a return value. The reason things start working when you change WM_COMMAND to EN_CHANGE is not because you are handling EN_CHANGE, it is because you no longer have incorrect handling of WM_COMMAND, and instead let the DefWindowProc take them.
The fall-through from WM_COMMAND into WM_CREATE isn't helping things either.
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_COMMAND:
switch (HIWORD(wParam)) /* command kind */
{
case 0: // menus
switch (LOWORD(wParam)) /* child ID */
{
case 1:
MessageBeep(MB_SERVICE_NOTIFICATION);
return 0;
case 2:
DestroyWindow(hWnd);
return 0;
case 3:
wchar_t text[100];
GetWindowTextW(hEdit, text, 100);
SetWindowTextW(hWnd, text);
return 0;
}
break;
}
break;
case WM_CREATE:
AddMenu(hWnd);
AddControl(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
// break actions also reach here
return DefWindowProcW(hWnd, msg, wParam, lParam);
}

GetWindowText malfunktion

I'm trying to learn how to make a GUI for a C++ using visual studio. but I have encountered some problems while using the GetWindowText() function. It does not change the LPTSTR title to the text in the textbox and I also get an error when debugging saying: “Exception thrown at 0x74F8207D (user32.dll) in Win32Project1.exe: 0xC0000005: Access violation writing location 0x002B8D38.” The code can be seen below what am I doing wrong?
#define ID_BUTTON1 1
#define ID_BUTTON2 2
#define ID_TEXT3 3
static HWND hWndTextbox;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
HMENU hMenubar = CreateMenu();
HMENU hFile = CreateMenu();
HMENU hOptions = CreateMenu();
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hFile, L"File");
AppendMenu(hMenubar, MF_POPUP, NULL, L"Edit");
AppendMenu(hMenubar, MF_POPUP, (UINT_PTR)hOptions, L"Options");
AppendMenu(hFile, MF_STRING, NULL, L"Exit");
AppendMenu(hOptions, MF_STRING, NULL, L"option 1");
AppendMenu(hOptions, MF_STRING, NULL, L"option 2");
SetMenu(hWnd, hMenubar);
CreateWindow(TEXT("button"), TEXT("Hello"),
WS_VISIBLE | WS_CHILD,
10, 10, 80, 25,
hWnd, (HMENU) ID_BUTTON1, NULL, NULL);
static HWND hWndTextbox = CreateWindow(TEXT("edit"), TEXT("tekst goes here"),
WS_VISIBLE | WS_CHILD|WS_BORDER | ES_AUTOHSCROLL,
90, 120, 300, 20,
hWnd, (HMENU) ID_TEXT3, NULL, NULL);
CreateWindow(TEXT("button"), TEXT("shiny"),
WS_VISIBLE | WS_CHILD,
50, 50, 80, 50,
hWnd, (HMENU) ID_BUTTON2, NULL, NULL);
}
break;
case WM_COMMAND:
{
if (LOWORD(wParam) == ID_BUTTON1) {
MessageBox(hWnd, L"Button has been clicked", L"title for popup", MB_ICONINFORMATION);
}
if (LOWORD(wParam) == ID_BUTTON2) {
// create some default vars
// int length = GetWindowTextLength(hWndTextbox) + 1;
LPTSTR title = L"test" ;
GetWindowText(hWndTextbox, title, GetWindowTextLength(hWndTextbox) + 1);
MessageBox(hWnd, title, L"Message box", MB_OK);
}
break;
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
the rest of the code was auto generated by visual studio so I have only included the part where I made changes.
The documentation for GetWindowText() states that parameter lpString is supposed to point to a "buffer that will receive the text", which implies a writable buffer.
With the code LPTSTR title = L"test"; you create a pointer to a string literal which usually is located in read-only memory. When GetWindowText() tries to write to that memory, it causes an access violation.
To solve the issue, use a writable buffer like this:
// Allocate buffer including terminating null
std::wstring title( GetWindowTextLength(hWndTextbox) + 1, 0 );
// Address of first character is used to obtain pointer to non-const data
// (as opposed to wstring::c_str()).
int size = GetWindowText( hWndTextbox, &title[0], title.size() );
// Resize buffer to the actual text length
title.resize( size );
// MessageBox only needs pointer to const string, so we can use wstring::c_str() here.
MessageBox(hWnd, title.c_str(), L"Message box", MB_OK);