I am trying to create a simple dropdown menu in a dialog box. Here is the bit of code that actually does it:
BOOL CALLBACK Remove(HWND hDlgc, UINT message, WPARAM wParam, LPARAM lParam)
//message handler for remove category box
{
//UNREFERENCED_PARAMETER(lParam);
HINSTANCE current = GetModuleHandle(NULL);
//GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_PIN, "comctl32.dll", NULL);
CreateWindow(WC_COMBOBOXW, _TEXT(""), CBS_DROPDOWN | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 100, 100, 200, 200, hDlgc, NULL, NULL, NULL, NULL);
This will work and it will show the combo box, but only after waiting for 2 minutes or so... very undesirable! my program will go into a not responding state before the combo box shows up. The output shows that comctl32.dll get loaded and unloaded about 1500 times before the combo box shows up. When it does, it is still unresponsive and I have to wait more until it begins to work. I tried pinning the module to stop the loading and unloading but that did not do anything. Any help appreciated. As you can see I am very new to win32 programming. I got the backend of my program to work nicely, its just this gui that is bugging me.
EDIT: here is the as short as i could get it code. Just create a blank desktop project in VS, and then replace the "about" function in the bottom with the following: (and also include commctrl.h)
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
HWND dd_Hand = CreateWindow(WC_COMBOBOXW, _TEXT(""), CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
20, 20, 200, 200, hDlg, NULL, NULL, NULL);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
If I do this, I get the symptoms described previously.
EDIT AGAIN: I put the createwindow function for the combobox into the WM_CREATE case of WndProc, and everything works as it should, loads instantly. I am starting to doubt that this is the right way to create a combobox within a dialog box. Any suggestions for doing this another way (havent been able to find a way to do this with a splitbutton resource) are also welcome.
Solution was simple. just put this code:
HWND dd_Hand = CreateWindow(WC_COMBOBOXW, _TEXT(""), CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
20, 20, 200, 200, hDlg, NULL, NULL, NULL);
and the code that loads the combobox so it runs only once. No more problems. Also another even simpler way to do this would be to create a combobox resource and use the SendMessage() function.
Related
I'm trying to create a Windows desktop app which has a Rich Edit control, and I want to handle certain keystrokes within the control e.g. hitting enter will execute some code based on what's been typed on that line, similar to a console app. I started with the regular Windows Desktop App template in Visual Studio, and created my control within the WndProc:
case WM_CREATE:
{
LoadLibrary(TEXT("Msftedit.dll"));
//Console creation
hwndEdit = CreateWindowEx(
WS_EX_CLIENTEDGE, // extended styles
MSFTEDIT_CLASS, // Predefined class
NULL, // text
WS_TABSTOP | WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, // Styles
0, // x position - size and position handled separately
0, // y position
0, // Button width
0, // Button height
hWnd, // Parent window
(HMENU)ID_CONSOLE, // Control ID
(HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE),
NULL); // Pointer not needed
}
break;
So far, so good. However, when I try to create a procedure for the control and attach it, it doesn't seem to do anything and to be honest, based on the documentation and a lot of Google searches, I'm still not entirely sure how it should be done. My procedure looks like the below:
LRESULT CALLBACK EditControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
//static HWND hwndEdit;
switch (uMsg)
{
case WM_PAINT:
return TRUE;
// Other cases...
case WM_KEYDOWN:
switch (wParam)
{
case VK_RETURN:
MessageBox(NULL, L"You pressed enter!", L"Title", NULL);
}
/*case WM_CREATE:
{
HWND console = GetDlgItem(hWnd, ID_CONSOLE);
SetWindowSubclass(console, EditControlProc, 0, 0);
return TRUE;
}*/
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
and my attempt to attach that to the control (which I based on the example here) was:
case WM_CREATE:
{
HWND console = GetDlgItem(hWnd, ID_CONSOLE);
SetWindowSubclass(console, EditControlProc, 0, 0);
return TRUE;
}
I tried handling this within various messages (the last of which was WM_CREATE as above - the link shows WM_INITDIALOG but that didn't work) with no success, and to be honest I'm not sure where I should add this in my case.
I know this is a really basic question and I feel like there should be loads of examples to show me how it's done and I might just be making a stupid mistake (far from unheard of in my short programming studentship), but I've been searching for days and haven't found what I'm looking for so would really appreciate a pointer or two.
Thanks!
I am working on Zoom SDK which is based on win32 gui.
I have created 3 buttons using CreateWindow method on the window handle, which is provided by the ZoomSDK.
Code + Screenshot - 1
Now there are two problems with this.
As soon as I click the buttons, they disappear.
See the Screen Shots BEFORE
See the Screen Shots AFTER
I want to know the reason why this is happening and how can I fix this?
HWND hFirstView, hSecondView;
cntrl->GetMeetingUIWnd(hFirstView, hSecondView);
cntrl->MoveFloatVideoWnd(100, 100);
HWND btnHwnd = CreateWindow(
TEXT("button"),
L"Open App",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
0, 0,
50, 25,
hFirstView,
(HMENU)100,
hInst,
NULL);
HWND btnHwnd2 = CreateWindow(
TEXT("button"),
L"Other",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
50, 0,
50, 25,
hFirstView,
(HMENU)101,
hInst,
NULL);
HWND btnHwnd3 = CreateWindow(
TEXT("button"),
L"Raise Hand",
WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
100, 0,
50, 25,
hFirstView,
(HMENU)103,
hInst,
NULL);
HDC hdc = GetDC(btnHwnd);
SetBkColor(hdc, GetSysColor(COLOR_BTNSHADOW));
SetTextColor(hdc, GetSysColor(COLOR_BACKGROUND));
ReleaseDC(btnHwnd, hdc);
int btnId = GetDlgCtrlID(btnHwnd);
//oldWndProc = (WNDPROC) GetWindowLong(hFirstView, GWL_WNDPROC);
oldWndProc = (WNDPROC) SetWindowLong(hFirstView,
GWL_WNDPROC, (LONG)WndProc);
SendMessage(btnHwnd, BM_SETSTATE, 1, 0);
SetWindowText(hFirstView, L"Title");
I want to handle click event for these buttons. I have tried to use SetWindowsLong to set another WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int id = GetWindowLong(hWnd, GWL_ID);
switch (message)
{
case WM_COMMAND: {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
if (wParam == 1023) {
MessageBox(NULL, L"Sign of releaf!", L"Whoaa!", 0);
}
}
break;
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}
Now, this WndProc gets called for other events such mouse move etc. It is not working for my three buttons. I want to handle click event i.e WM_COMMAND or any other technique possible.
Because I can not go inside the sdk (they don't provide sources, only .lib) so I can not change their WndProc, nor their internal WM_PAINT. The buttons are sort of overlay on top.
You should not be calling SetBkColor() and SetTextColor() from outside a WM_PAINT handler. The correct way to color a button is to either:
have the parent window handle the WM_CTLCOLORBTN notification.
The WM_CTLCOLORBTN message is sent to the parent window of a button before drawing the button. The parent window can change the button's text and background colors.
give the button the BS_OWNERDRAW style, and then have the parent window handle the WM_DRAWITEM notification.
Sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
Also, when a button sends a BN_CLICKED notification to its parent window, your subclass WndProc() doesn't need to use GetWindowLong(GWL_ID). First, you are calling it on the wrong HWND. And second, the button ID is carried in the message's wParam data.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_COMMAND: {
if (HIWORD(wParam) == BN_CLICKED) {
switch (LOWORD(wParam)) {
case 100:
case 101:
case 103:
MessageBox(NULL, L"Sign of relief!", L"Whoaa!", 0);
break;
}
}
break;
}
}
return CallWindowProc(oldWndProc, hWnd, message, wParam, lParam);
}
I am creating a listbox control like this:
HWND hAvailable = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", NULL,
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
LBS_DISABLENOSCROLL | LBS_SORT,
0, 0, 0, 0, hWnd, (HMENU)IDC_AVAILABLELIST,
hInst, NULL);
and listening for events in my callback function, under WM_COMMAND like this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
int wmId, wmEvent;
switch (message) {
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
case IDC_AVAILABLELIST:
// We get here, with LBN_SETFOCUS and LBN_KILLFOCUS
if (wmEvent == LBN_SELCHANGE || wmEvent == LBN_DBLCLK) {
// Never gets here!
}
[ ... ]
The issue is that when I change the selection, I can see the new item being selected but I am not receiving the appropriate event.
When I select an item, I get an LBN_SETFOCUS event, followed by an LBN_KILLFOCUS event. Any attempt to get the currently selected index with int idx = SendMessage(hAvailable, LB_GETCURSEL, 0, 0); returns -1 even though an item is in fact selected.
If you read the documentation for LBN_SELCHANGE and LBN_DBLCLK, they both say:
This notification code is sent only by a list box that has the LBS_NOTIFY style.
The documentation for LBS_NOTIFY says:
LBS_NOTIFY
Causes the list box to send a notification code to the parent window whenever the user clicks a list box item (LBN_SELCHANGE), double-clicks an item (LBN_DBLCLK), or cancels the selection (LBN_SELCANCEL).
You are not enabling that style on your ListBox control.
As for LB_GETCURSEL, it returns LB_ERR (-1) when there is no selection.
I had the same problem. This is true. The LBS_NOTIFY needs to be in the style.
What is very peculiar about this issue is that yesterday my code did not need the LBS_NOTIFY but today it does. So weird right! I'm using Visual Studios 2019. Also, adding the LBS_NOTIFY resolved the problem only after a reboot.
im using dev c++(no qt or visual studio) and have the following button code:
HWND hwndButton = CreateWindowEx(
WS_EX_CLIENTEDGE,
"BUTTON",
"Submit",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
100,
45,
100,
40,
hWnd,
NULL,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL);
i am completely new to gui programming, and i wanted to have the window close when the button is clicked as a test for reading user input.
after reading online it looks like something that occurs within:
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(EXIT_SUCCESS);
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return FALSE;
}
and i have also seen people talk about "OnOk();" but i have no idea where i would put it. how would i have the window close if the button is clicked? where would i have the function to close it? where does the message even go that says the button was clicked? ive been searching for hours on the internet and have had no luck.
I'm using CreateWindowEx() function to create an "EDIT" window, i.e. where a user can type.
g_hwndMain = CreateWindowEx(0,
WC_TEXT,
NULL,
WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL,
0, 0, 400, 200,
phwnd, NULL,
g_hInstance, NULL);
But I would also like the window to be static. Is there a way to do it during the creation of the window? Or any other function that may be used after the creation of the window? I tried using SetWindowPos function after creating the window using SWP_NOSENDCHANGING and SWP_NOREPOSITION, but that didn't o the trick. ANy ideas?
No, I mean Immovable Window. Basically, the window I create should be able to accept text and be immovable at the same time.
You need to handle the WM_WINDOWPOSCHANGING message for that window and then set the SWP_NOMOVE flag of the flags member of the WINDOWPOS structure before you forward it along.
This blog post has an example (though he's preventing size changes, the technique is the same).
Thanks for your help. Ok So far I've done this to handle WM_WINDOWPOSCHANGING message
BOOL OnWindowPosChanging(HWND hwnd, WINDOWPOS *pwp)
{
return 0;
}
LRESULT CALLBACK
WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
switch (uiMsg) {
HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, OnWindowPosChanging);
}
return DefWindowProc(hwnd, uiMsg, wParam, lParam);
}
and when I create my window, I do this:
g_hwndMain = CreateWindowEx(0,
TEXT("EDIT"),
NULL,
WS_BORDER,
0, 0, 400, 200,
phwnd, NULL,
g_hInstance, NULL);
if (!g_hwndMain) {
RemoveImages(spHTMLDoc);//Just so I know that the window has been created properly
}
else{
SetWindowPos(g_hwndMain, HWND_TOP, 500, 500, 300, 300, SWP_NOSENDCHANGING | SWP_SHOWWINDOW );
}
The SWP_NOMOVE flag does not let the code change the position of the window, but the user is still able to change the window's position by moving it using a mouse. But this is exactly what I want to prevent. The window should be static. Any thing missing in my code, or any more suggestions?