I have difficulties creating a dialog box - winapi

I really do not know what i am doing wrong.
I would like to create a dialogbox.
It is just does not show.
Declaration
BOOL CALLBACK NewDlgProc(HWND main, UINT msg, WPARAM wParam, LPARAM lParam);
Diagproc:
BOOL CALLBACK NewDlgProc(HWND main, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
{
}
break;
default:
return FALSE;
}
return TRUE;
}
In windproc wm_command:
case ID_MENU_NEW:
{
int NewDlg = DialogBox(GetModuleHandle(NULL),
MAKEINTRESOURCE(ID_DIALOG_NEW), main, NewDlgProc);
if(NewDlg == 0)
MessageBox(main, "Cannot create dialogbox", "Error", MB_OK | MB_ICONERROR);
}
break;
resource.h:
#define ID_DIALOG_NEW 201
dlg.rc
#include <windows.h>
#include "resource.h"
ID_DIALOG_NEW DIALOG DISCARDABLE 100,100, 100,100
STYLE DS_MODALFRAME | WS_VISIBLE | WS_CHILD | WS_CAPTION
CAPTION "Add new"
FONT 8, "Ms Sans Serif"
BEGIN
END

A dialog can have an owner or be unowned, but it cannot have a parent. Consequently, you cannot have the WS_CHILD window style for a dialog. Replace that with WS_POPUP, and everyone will be happy.
Relevant quote from the MSDN (About Dialog Boxes : Modal Dialog Boxes):
An application must not create a modal dialog box having the WS_CHILD style.

How come in your dialog procedure you are not calling DefDlgProc() for the messages you are not handling?
BOOL CALLBACK NewDlgProc(HWND main, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
{
}
break;
default:
return DefDlgProc(main, msg, wParam, lParam); // need default processing!!!!!!!!!!
}
return TRUE;
}

Related

How do I force a redraw of WIN32 scrolled window while holding scrollbar down

We've noticed an issue with ScrollWindowEx on our Windows app. Because there are a lot of child windows, if you hold down the scrollbar and move around, it causes a huge stall in DesktopWindowManager.
This is documented here
Why is my MFC application hanging after interacting with both scroll-bars?
So, I've taken the call to ScrollWindowEx out and now I can move my scrollbar with no issues, however the window and all its children only get drawn at the new position when I let go of the scrollbar.
It seems that my entire program stalls and gets stuck in the message loop when the scroll bar is held down. This isnt a problem if we can force the window that the scrollbar is attached to to update. But how do I do that ?
I've tried this
UpdateWindow(pPane);
RedrawWindow(pPane,NULL,NULL,RDW_ALLCHILDREN|RDW_INVALIDATE|RDW_ERASE | RDW_INTERNALPAINT | RDW_UPDATENOW);
And it does update and redraw - you can see the glitching - BUT it redraws it at the position that it was last left at. Not where the new position of the scroll bar would set it.
Im calling
SetScrollInfo(...)
with the correct parameters, otherwise it wouldn't work normally
How can I get it to redraw the window and its children with the correct parameters, whilst the scroll bar is held down?
This is my scroll message handler
case WM_VSCROLL:
{
int iVScrollPos;
SCROLLINFO vsi;
ZeroMemory(&vsi, sizeof(SCROLLINFO));
vsi.cbSize=sizeof(SCROLLINFO);
vsi.fMask=SIF_ALL;
GetScrollInfo(hWnd,SB_VERT,&vsi);
iVScrollPos=vsi.nPos;
switch(LOWORD(wParam))
{
case SB_LINEUP:
if(vsi.nPos>vsi.nMin)
vsi.nPos=vsi.nPos-10;
break;
case SB_PAGEUP:
vsi.nPos = vsi.nPos - vsi.nPage;
break;
case SB_LINEDOWN:
if(vsi.nPos<vsi.nMax)
vsi.nPos=vsi.nPos+10;
break;
case SB_PAGEDOWN:
vsi.nPos = vsi.nPos + vsi.nPage;
break;
case SB_THUMBTRACK:
vsi.nPos=vsi.nTrackPos;
break;
}
vsi.nMin=0;
vsi.nMax=pOW->dialogysize;
vsi.nPage=sy;
SetScrollInfo(hWnd,SB_VERT,&vsi,TRUE);
GetScrollInfo(hWnd, SB_VERT, &vsi);
if(vsi.nPos != iVScrollPos)
{
RedrawWindow(hWnd,NULL,NULL,RDW_ALLCHILDREN|RDW_INVALIDATE|RDW_ERASE | RDW_INTERNALPAINT | RDW_UPDATENOW);
}
The window redraws as you move the scroll bar, but in the same place it was when you held the mouse down on the scrollbar. It onlyupdates position when you let go of the mouse button.
Thanks
Shaun
EDIT - Ive created a sample that reproduces the behaviour. Note we have a separate window class to hold the multiple edit windows. I havent handled the WM_SIZE and WM_MOVE messages in this demo but the code should work with the window as it is.
IF USESCROLL is defined in and you move the scrollbar up and down it casues a lockup in DesktopWindowManager
IF USESCROLL is not commented in, then the trackPos in the structure still gets updated and I call reDrawWindow, but the child edit windows dont move as I scroll the scrollbar.
As I dont want to have the lockup, how can I get them to move please ?
Thanks again
Shaun
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK PaneProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
// Register the window class.
WNDCLASS wc = { };
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = "Class";
RegisterClass(&wc);
wc.lpfnWndProc = PaneProc;
wc.hInstance = hInstance;
wc.lpszClassName = "Pane";
RegisterClass(&wc);
// Create the window.
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
(LPCSTR)"Class", // Window class
(LPCSTR)"Test", // Window text
WS_OVERLAPPEDWINDOW| WS_BORDER | WS_CAPTION | WS_CLIPSIBLINGS | WS_THICKFRAME | WS_SYSMENU, // Window style
200,200,400,400,
NULL,NULL,hInstance,NULL);
if (hwnd == NULL)
{
return 0;
}
HWND hwndPane = CreateWindowEx(
0, // Optional window styles.
(LPCSTR)"Pane", // Window class
(LPCSTR)"Test", // Window text
WS_OVERLAPPEDWINDOW|WS_VISIBLE|WS_VSCROLL, // Window style
220,220,400,400,
hwnd,NULL,hInstance,NULL);
if (hwndPane == NULL)
{
return 0;
}
for(int i=0;i<200;i++)
{
HWND eb = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("Edit"), NULL,ES_AUTOHSCROLL | WS_CHILD| WS_VISIBLE, 16, 16+24*i, 64, 24, hwndPane, (HMENU)i+10000, hInstance, NULL);
char tmp[64];
sprintf(tmp,"%d",i);
SetWindowText(eb,tmp);
}
ShowWindow(hwnd, nCmdShow);
ShowWindow(hwndPane, nCmdShow);
// Run the message loop.
while(1)
{
MSG msg = { };
while (PeekMessage(&msg, NULL, 0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Sleep(10);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK PaneProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
int iVScrollPos;
SCROLLINFO vsi;
ZeroMemory(&vsi, sizeof(SCROLLINFO));
vsi.cbSize=sizeof(SCROLLINFO);
vsi.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_VERT,&vsi);
iVScrollPos=vsi.nPos;
vsi.nMin=0;
vsi.nMax=16+24*200+40;
vsi.nPage=400;
SetScrollInfo(hwnd,SB_VERT,&vsi,TRUE);
GetScrollInfo(hwnd, SB_VERT, &vsi);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_VSCROLL:
{
int iVScrollPos;
SCROLLINFO vsi;
ZeroMemory(&vsi, sizeof(SCROLLINFO));
vsi.cbSize=sizeof(SCROLLINFO);
vsi.fMask=SIF_ALL;
GetScrollInfo(hwnd,SB_VERT,&vsi);
iVScrollPos=vsi.nPos;
switch(LOWORD(wParam))
{
case SB_THUMBTRACK:
vsi.nPos=vsi.nTrackPos;
break;
}
vsi.nMin=0;
vsi.nMax=16+24*200+40;
vsi.nPage=400;
SetScrollInfo(hwnd,SB_VERT,&vsi,TRUE);
GetScrollInfo(hwnd, SB_VERT, &vsi);
if(vsi.nPos != iVScrollPos)
{
float ScrollAmtY=-(vsi.nPos - iVScrollPos);
#define USESCROLL
#ifdef USESCROLL
int ok=ScrollWindowEx(hwnd ,0,ScrollAmtY,NULL,NULL,NULL,NULL,SW_INVALIDATE|SW_ERASE|SW_SCROLLCHILDREN);
#else
UpdateWindow(hwnd);
RedrawWindow(hwnd,NULL,NULL,RDW_ALLCHILDREN|RDW_INVALIDATE|RDW_ERASE | RDW_INTERNALPAINT | RDW_UPDATENOW);
#endif
}
return 0;
}
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Detect CTRL+A in a texbox

I have a main window hwndMain and a multiline Edit textbox:
hwndEdit = CreateWindowEx(0, L"EDIT", NULL, WS_CHILD | WS_VISIBLE | ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 300, 200, hwndMain, 0, (HINSTANCE) GetWindowLong(hwndMain, GWL_HINSTANCE), NULL);
I use this to detect CTRL+A in the textbox (because strangely, it's not available out-of-the-box):
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_KEYDOWN:
{
if (wParam == VK_CONTROL) // something here missing for detecting "A"
{
SendMessage(hwndEdit, EM_SETSEL, 0, -1); // select all ; this code works on its own, tested
}
...
Unfortunately, nothing happens when I do CTRL+A or CTRL+B or CTRL+ anything.
What is wrong?
Note: Ok the code for detecting A is still missing (i still don't know how to do it), but the code here should work for any CTRL+key...
Just check for WM_KEYDOWN for A and than use GetKeyState
case WM_KEYDOWN:
{
if (wParam=='A' && (::GetKeyState(VK_CONTROL) & 0x8000)!=0)
{
SendMessage(hwndEdit, EM_SETSEL, 0, -1); // select all
}
Remember that WM_KEYDOWN is only sent to the window that has the focus and not to parent windows.
After you create all your windows:
hwndEdit = CreateWindowEx(.....)
...
//Subbclassing
SetWindowSubclass(hwndEdit, (SUBCLASSPROC)EditWndProc, 0, 1);
LRESULT CALLBACK EditWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwrefData){
switch(message){ //handle the messages
case WM_KEYDOWN:
//your code
break;
default: //for messages that we don't deal with
return DefSubclassProc(hwnd, message, wParam, lParam);
}
return DefSubclassProc(hwnd, message, wParam, lParam);
}

WM_KEYDOWN not working

I'm writing a notepad program and would like the user to be able to press ctrl+n, ctrl+s, ctrl+o, etc, But I'm not even getting a response for the WM_KEYDOWN case. This is how my function is setup:
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_CREATE:
// CREATE STUFF HERE
break;
case WM_SIZE:
// RESIZE STUFF HERE
break;
case WM_COMMAND:
// COMMAND ACTIONS HERE
break;
case WM_NOTIFY:
// NOTIFICATIONS HERE
break;
case WM_KEYDOWN:
MessageBox( hwnd, "OK", "OK", MB_OK );
break;
case WM_CLOSE:
// CLOSE WINDOW HERE
break;
case WM_DESTROY:
// DESTROY WINDOW
break;
default:
return DefWindowProc( hwnd, msg, wParam, lParam );
}
return 0;
}
Anybody know what I'm doing wrong? Am I supposed to put the WM_KEYDOWN case somewhere else?

WM_LBUTTONDOWN & WM_LBUTTONUP not received

I created toplevel window, but for unknown reasons my WNDPROC does not receive WM_LBUTTONDOWN/WM_LBUTTONUP nor WM_MOUSEMOVE messages.
Any suggestions?
Relevant code:
WNDCLASSEX wc = {0};
Wc.cbSize = 48;
Wc.cbWndExtra = 80;
Wc.hCursor = LoadCursorW(g_hInstance, MAKEINTRESOURCEW(1002));
Wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
Wc.lpszClassName = Ici[dItemIndex].sInit;
Wc.lpfnWndProc = Ici[dItemIndex].wInit;
RegisterClassExW(&Wc);
g_hRuler1 = CreateWindowExW(WS_EX_TOOLWINDOW,
RULER_CONTROL,
L"",
WS_POPUP|WS_VISIBLE|0x1,
100 ,100, 40, RECTHEIGHT(g_rScreen),
NULL, NULL, hInst, NULL);
LRESULT WINAPI Ruler_Window(HWND hWindow, UINT uWindow, WPARAM wParam, LPARAM lParam)
{
if (uWindow == WM_GETMINMAXINFO)
{
goto DODEFAULT;
}
if (uWindow == WM_NCCREATE)
{
g_pGRI = RULER_ALLOCATE();
RULER_SET_POINTER(hWindow, (LONG_PTR)g_pGRI);
return 1L;
}
g_pGRI = RULER_GET_POINTER(hWindow);
g_pGRI->hWindow = hWindow;
switch(uWindow)
{
case WM_CREATE:
{
return Ruler_OnCreate(wParam, lParam);
}
case WM_PAINT:
{
return Ruler_OnPaint(wParam, lParam);
}
case WM_MOUSEMOVE:
{
return Ruler_OnMouseMove(wParam, lParam);
}
case WM_DESTROY:
{
return Ruler_OnDestroy(wParam, lParam);
}
case WM_SETCURSOR:
{
return Ruler_OnSetCursor(wParam, lParam);
}
case WM_LBUTTONDOWN:
{
return Ruler_OnLeftButtonDown(wParam, lParam);
}
case WM_LBUTTONUP:
{
return Ruler_OnLeftButtonUp(wParam, lParam);
}
case GM_SETINDICATORS:
{
return Ruler_OnSetIndicators(wParam, lParam);
}
DODEFAULT:
return DefWindowProcW(hWindow, uWindow, wParam, lParam);
}
}
Spy++ messages of window after left button click.
I think that the problem here is that you are most likely not calling DefWindowProc from your custom wndProc method (Ruler_Window).
Your code structure in your wndProc is a little... interesting.
You handle the messages you are interested in in a switch statement (with the exception of WM_NCCREATE, which is fine), but your switch statement doesn't actually have a default: entry... instead you have created a label called DODEFAULT, which you only reference once - when the message is WM_GETMINMAXINFO you goto DODEFAULT. Ignoring the issue of using a goto here, you basically do not handle any messages other than those listed in your code, and more importantly, you don't pass other messages to the default handler.
A very quick, very simple rewrite of your Ruler_Window method:
LRESULT WINAPI Ruler_Window(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_NCCREATE)
{
g_pGRI = RULER_ALLOCATE();
RULER_SET_POINTER(hWindow, (LONG_PTR)g_pGRI);
return DefWindowProcW(hWindow, uMsg, wParam, lParam);
}
// not sure what g_pGRI is, guessing it's a global?
// should this actually be passed into the handlers below?
g_pGRI = RULER_GET_POINTER(hWindow);
g_pGRI->hWindow = hWindow;
switch(uMsg)
{
case WM_CREATE:
return Ruler_OnCreate(wParam, lParam);
case WM_PAINT:
return Ruler_OnPaint(wParam, lParam);
case WM_MOUSEMOVE:
return Ruler_OnMouseMove(wParam, lParam);
case WM_DESTROY:
return Ruler_OnDestroy(wParam, lParam);
case WM_SETCURSOR:
return Ruler_OnSetCursor(wParam, lParam);
case WM_LBUTTONDOWN:
return Ruler_OnLeftButtonDown(wParam, lParam);
case WM_LBUTTONUP:
return Ruler_OnLeftButtonUp(wParam, lParam);
case GM_SETINDICATORS:
return Ruler_OnSetIndicators(wParam, lParam);
default:
break;
}
return DefWindowProcW(hWindow, uMsg, wParam, lParam);
}
Note, I also changed the name of the message parameter to be uMsg, as it makes reading the code much easier, IMHO.
I suspect that the problem is that you are not calling DefWindowProc for WM_NCCREATE and WM_CREATE. This means that the window is never setting up its client areas, so the messages are coming in as WM_NC*.
You should always pass WM_NCCREATE and WM_CREATE on to DefWindowProc.

Get HMENU from HWND within a Hook

I'm installing a hook within my application to get the standard EDIT context menu (with undo/copy/edit/paste/etc.). I need to insert a new menu item for my application.
I've set a windows hook, but I can't seem to get the HMENU for the context menu. This is where I set the hook:
g_hHook = SetWindowsHookEx(WH_CALLWNDPROC, HookCallWndProc, NULL, GetCurrentThreadId());
Here is my callback function:
LRESULT CALLBACK HookCallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
LPCWPSTRUCT cwps = (LPCWPSTRUCT)lParam;
switch(cwps->message)
{
case WM_CREATE:
{
WCHAR szClass[128];
GetClassName(cwps->hwnd, szClass, 127);
if (wcscmp(szClass, L"#32768") == 0)
{
LPCREATESTRUCT lpcs = (LPCREATESTRUCT)cwps->lParam;
HMENU hMenu = GetMenu(cwps->hwnd);
// hMenu is 0x0
//MENUINFO info;
//ZeroMemory(&info, sizeof(MENUINFO));
//info.cbSize = sizeof(info);
//GetMenuInfo(hMenu, &info);
MessageBox(NULL, L"Test", L"Test", NULL);
}
break;
}
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
I also tried setting the hook with WH_CALLWNDPROCRET, but this one doesn't even capture the WM_CREATE message for the menu.
Does anyone know how to obtain the HMENU for this particular situation?
Thanks,
Kevin
You can send the MN_GETHMENU message to get the HMENU:
case WM_CREATE:
{
WCHAR szClass[128];
GetClassName(cwps->hwnd, szClass, 127);
if (wcscmp(szClass, L"#32768") == 0)
{
// Must delay MN_GETHMENU...
PostMessage(g_hDlg,WM_APP,(WPARAM)cwps->hwnd,(LPARAM)HookCallWndProc);
}
break;
}
...
LRESULT CALLBACK MyWindow(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
switch(msg)
{
case WM_APP:
if (lp == (LPARAM)HookCallWndProc) // Just making sure it is our special message
{
HMENU hMenu = (HMENU) SendMessage((HWND)wp,MN_GETHMENU,0,0);
if (hMenu)
{
AppendMenu(hMenu,MF_STRING,666,L"Hello SO");
}
}
break;
This is a bit hacky but hacks are pretty much unavoidable when customizing controls like this...

Resources