I have one parent dialog , this dialog have menu , in this menu (Help->about).
when I click on the about selection, show about DialogBox.
I want if I click on Ok or close(X) button, close this dialog box only not the main dialog box.
This my attempts:
// ------------- Main dialog function
BOOL CALLBACK DlgFunc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp){
switch(msg){
case WM_COMMAND:
switch(LOWORD(wp)){
case IDM_HABOUT: // Here, I set when I click on help selection in the menu creates (about dialogbox)
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_AboutDlg), hwnd, AboutDlgFunc);
break;
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return false;
}
return true;
}
// ------------- About dialog function
BOOL CALLBACK AboutDlgFunc(HWND HabutWnd, UINT msg, WPARAM wp, LPARAM lp){
switch(msg){
case WM_COMMAND:
if(LOWORD(wp) == IDOK)
EndDialog(HabutWnd,0);
break;
case WM_CLOSE:
EndDialog(HabutWnd,0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return false;
}
return true;
}
Don't call PostQuitMessage in WM_DESTROY inside AboutDlgFunc. This essentially causes the entire program to quit.
Related
I wrote a Win32 backup program, that runs fine - however it will hang as soon as any callback event acours.
The function calls in case of IDC_F_BACKUP and IDC_F_SAVEAS work ok, but whenever the input and output folders
are defined and 'start' (IDC START) is hit, any other callback event (for example a mouse click or a window move)
will freeze this application (and it's icon changes to a windoews default one).
As I understood, a callback function should return within a short timeframe. I have no idea how to realize this
requirement since whenever the 'start' button has been hit the backup runs for much more than 30 minutes.
Here my windows procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
/* ========================================================================
** Callback loop for the Windows procedure
** ========================================================================
*/
{
switch(msg) {
//case WM_MOVE:
//case WM_SHOWWINDOW:
//case WM_WINDOWPOSCHANGING:
case WM_PAINT:
case WM_CREATE:
DisplaySettings();
ActivityMonitor(L"\0");
break;
case WM_CLOSE:
DestroyWindow(hWnd);
DestroyWindow(hWnd);
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND: {
switch(LOWORD(wParam)) {
case IDC_START: {
DWORD p;
const WCHAR szEndMsg[]=L"====> backup successfully completed <====";
if((szInpPath[0]==L'?') || (szOutpPath[0]==L'?')) {
MessageBoxW( NULL, L"Path not found", L"Error",MB_OK );
}else {
// create and initialize error log file:
strCopyW(&szOutpPath[nOP_End], (WCHAR*)L"\\skipped_files.log", MAX_PATH);
//MessageBoxW( NULL, szOutpPath, L"Log file", MB_OK );
hLog = _wfopen(szOutpPath, L"a+");
Test((hLog!=0), L"can not create log file");
szOutpPath[nOP_End] = L'\0';
fwprintf(hLog, L"\n\n\n");
for(p=0; p<20; p++) fwprintf(hLog, L"----");
fwprintf(hLog, L"\nBackup starting at %s", szInpPath);
fwprintf(hLog, L"\nFollowing files could not be archived:\n");
// go ...
BackupDirectory(); // <========== this function runs those 30 minutes ....
ActivityMonitor(L" ");
ActivityMonitor(szEndMsg);
fwprintf(hLog, szEndMsg);
InvalidateRect( hWnd, &rcMonitor, TRUE ); // invalidate the monitor area
UpdateWindow(hWnd);
//RedrawWindow(hWnd, &rcMonitor, 0, RDW_UPDATENOW);
fclose(hLog);
DisplaySettings();
szInpPath[nIP_End] = L'\0'; // restore input path
szOutpPath[nOP_End] = L'\0'; // restore output path
}
break;
}
case IDC_F_BACKUP:
nIP_End = SelectPath(hWnd, szInpPath, L"Select the folder to be backed up");
DisplaySettings();
break;
case IDC_F_SAVEAS:
nOP_End = SelectPath(hWnd, szOutpPath, L"Create a folder for this backup");
DisplaySettings();
break;
case IDC_VERSION:
MessageBoxW( NULL, L"\n FolderClone.exe Version 1.1 /MN"
L"\n Create a zip-backup of the selected"
L"\n directory (archive all files per folder,"
L"\n directory structure left unchanged).", L" ? ",MB_OK );
break;
case IDC_F_EXIT:
PostMessage(hWnd, WM_CLOSE, 0, 0);
break;
}//switch(LOWORD(wParam))
break;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}//WM_COMMAND
return 0L;
}//switch(msg)
return (0L);
}
I want to create two buttons that perform separate functions.
When button_B1 is clicked, Function_B1() runs.
When button_B2 is clicked, Function_B2() runs.
How do I call a function on a button click?
When a Win32 button is clicked, it sends a BN_CLICKED notification to its parent window, where the message carries the button's HWND and ID. In the parent window's wndproc, you can catch the notification and call whatever function you want for whichever button is sending the notification.
case WM_COMMAND:
{
if ((HIWORD(wParam) == BN_CLICKED) && (lParam != 0))
{
switch (LOWORD(wParam))
{
case ID_BTN1:
Function_B1();
break;
case ID_BTN2:
Function_B2();
break;
}
}
break:
}
Or
case WM_COMMAND:
{
if ((HIWORD(wParam) == BN_CLICKED) && (lParam != 0))
{
HWND hwndBtn = (HWND) lParam;
if (hwndBtn == hwndBtn1)
Function_B1();
else if (hwndBtn == hwndBtn2)
Function_B2();
}
break:
}
Thank you, Remy.
I just had a problem with the switch statement:
case WM_COMMAND:
{
switch (wmId)
{
case 1:
Function_B1(hWnd, wParam, lParam);
break;
case 2:
Function_B2(hWnd, wParam, lParam);
break;
case 3:
Function_B3(hWnd, wParam, lParam);
break;
I have a dialog box with a Tree-View control where the user can edit the item labels. I want the user to be able to cancel the label edit by pressing ESC key.
The problem is that pressing ESC closes the dialog window immediately.
I have tried getting the handle to the EditBox control by a TreeView_GetEditControl() call upon TVN_BEGINLABELEDIT message and subclassing it to trap the ESC key, but when I do that, typing in edit box becomes impossible.
What is the problem?
Here is the relevant code:
INT_PTR CALLBACK DlgProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam) {
switch(message) {
//...
case WM_NOTIFY:
{
LPNMHDR pNmHdr = (LPNMHDR)lParam;
switch(pNmHdr->code) {
case TVN_BEGINLABELEDIT:
{
HWND hwndTV = (HWND)GetWindowLongPtr(hWnd, GWLP_USERDATA); // stored handle to Tree-View ctl
HWND hWndEditBox = TreeView_GetEditControl(hwndTV);
// subclass edit box
TreeViewGlobals::g_wpOrigEditBoxProc =
(WNDPROC)SetWindowLongPtr(hWndEditBox,
GWLP_WNDPROC, (LONG_PTR)EditBoxCtl_SubclassProc);
break;
}
case TVN_ENDLABELEDIT:
{
SetWindowLongPtr(hWnd, DWLP_MSGRESULT, (LONG)TRUE); // accept edit
return TRUE;
}
default:
break;
}
}
default:
break;
}
return FALSE;
}
INT_PTR CALLBACK EditBoxCtl_SubclassProc(HWND hWndEditBox, UINT message,
WPARAM wParam, LPARAM lParam) {
switch(message) {
HANDLE_MSG(hWndEditBox, WM_GETDLGCODE, EditBoxCtl_OnGetDlgCode);
HANDLE_MSG(hWndEditBox, WM_KEYDOWN, EditBoxCtl_OnKey); // does not receive WM_KEYDOWN for ESC unless I handle WM_GETDLGCODE above
default:
break;
}
return CallWindowProc(TreeViewGlobals::g_wpOrigEditBoxProc,
hWndEditBox, message, wParam, lParam);
}
UINT EditBoxCtl_OnGetDlgCode(HWND hWndEditBox, LPMSG lpmsg) {
if(lpmsg) {
if(lpmsg->message == WM_KEYDOWN && lpmsg->wParam == VK_ESCAPE) {
return DLGC_WANTMESSAGE;
}
}
return 0;
}
void EditBoxCtl_OnKey(HWND hWndEditBox, UINT vk, BOOL fDown,
int cRepeat, UINT flags) {
switch(vk) {
case VK_ESCAPE:
Beep(4000, 150); // never beeps
break;
default:
break;
}
}
P.S. I noticed that when I remove WM_GETDLGCODE handler in EditBoxCtl_SubclassProc(), it becomes possible to type in the edit box again, but then I can't trap WM_KEYDOWN for ESC key from that procedure.
Below is the solution that I found. The trick seems to be calling the original control proc with WM_GETDLGCODE intercepted in subclass proc, storing the return value and then returning it with DLGC_WANTALLKEYS or DLGC_WANTMESSAGE flag set to prevent system from further processing the keystroke.
The upside to this approach is that pressing ESC cancels editing and reverts the item label to its original text, and pressing ENTER while editing no longer just closes the dialog(which was another problem) without any additional code to handle those cases.
Here is the code that works:
INT_PTR CALLBACK EditBoxCtl_SubclassProc(HWND hWndEditBox, UINT message,
WPARAM wParam, LPARAM lParam) {
switch(message) {
//HANDLE_MSG(hWndEditBox, WM_GETDLGCODE, EditBoxCtl_OnGetDlgCode); // can't use this: need wParam and lParam for CallWindowProc()
case WM_GETDLGCODE: {
INT_PTR ret = CallWindowProc(TreeViewGlobals::g_wpOrigEditBoxProc,
hWndEditBox, message, wParam, lParam);
MSG* lpmsg = (MSG*)lParam;
if(lpmsg) {
if(lpmsg->message == WM_KEYDOWN &&
(lpmsg->wParam == VK_ESCAPE || lpmsg->wParam == VK_RETURN) )
{
return ret | DLGC_WANTALLKEYS;
}
}
return ret;
}
default:
break;
}
return CallWindowProc(TreeViewGlobals::g_wpOrigEditBoxProc,
hWndEditBox, message, wParam, lParam);
}
The problem is that the modal dialog has its own message loop and its own translation with IsDialogMessage. Using the MFC I would say, just use PreTranslateMessage but this isn't available in plain WinApi. You don't have access to the internal message loop and the keyboard interface.
So the Escape key is handled inside the message loop. And causes a WM_COMMAND message with IDCANCEL to be sent. (See the MSDN specs about dialogs)
Maybe the easiest way is to interrcept the WM_COMMAND message sent to the dialog, check if who has the focus and if the inplace edit control has the focus you just set the focus back to the tree control and eat forget the IDCANCEL and don't close the dialog.
you need remember the tree-view hwnd when you receive TVN_BEGINLABELEDIT (in class member, associated with dialog) and zero it when you receive TVN_ENDLABELEDIT. when user press esc or enter in modal dialog box - you receive WM_COMMAND with IDCANCEL (on esc) or IDOK( on enter). you need check saved tree-view hwnd and if it not 0 - call TreeView_EndEditLabelNow
switch (uMsg)
{
case WM_INITDIALOG:
m_hwndTV = 0;
break;
case WM_NOTIFY:
switch (reinterpret_cast<NMHDR*>(lParam)->code)
{
case TVN_BEGINLABELEDIT:
m_hwndTV = reinterpret_cast<NMHDR*>(lParam)->hwndFrom;
return TRUE;
case TVN_ENDLABELEDIT:
m_hwndTV = 0;
//set the item's label to the edited text
SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, TRUE);
return TRUE;
}
break;
case WM_CLOSE:
EndDialog(hwndDlg, 0);
break;
case WM_COMMAND:
switch (wParam)
{
case IDCANCEL:
if (m_hwndTV)
{
TreeView_EndEditLabelNow(m_hwndTV, TRUE);
}
else
{
EndDialog(hwndDlg, IDCANCEL);
}
break;
case IDOK:
if (m_hwndTV)
{
TreeView_EndEditLabelNow(m_hwndTV, FALSE);
}
else
{
EndDialog(hwndDlg, IDOK);
}
break;
}
break;
}
I am using NM_CUSTOMDRAW for changing the color of Tree View item & its child on some conditions.I want to get subitems control individually but dwDrawStage never get this case CDDS_ITEMPREPAINT| CDDS_SUBITEM my code snippet is here:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
int j;
HWND hwndTree;
TVITEM tv;
TVHITTESTINFO hti;
char achBuf[100];
switch (message)
{
case WM_CREATE:
RECT rcClient; // dimensions of client area
// handle to tree-view control
// Ensure that the common control DLL is loaded.
InitCommonControls();
// Get the dimensions of the parent window's client area, and create
// the tree-view control.
GetClientRect(hWnd, &rcClient);
hwndTV = CreateWindowEx(0,
WC_TREEVIEW,
TEXT("Tree View"),
WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_HASLINES,
0,
0,
rcClient.right,
rcClient.bottom,
hWnd,
(HMENU)ID_TREEVIEW,
hInst,
NULL);
// Initialize the image list, and add items to the control.
// InitTreeViewImageLists and InitTreeViewItems are application-
// defined functions, shown later.
if (!InitTreeViewItems(hwndTV))
{
DestroyWindow(hwndTV);
return FALSE;
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(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 IDC_MAIN_BUTTON:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
//TreeView_EnsureVisible(hwndTV,hti);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_NOTIFY:
{
LPNMTREEVIEW pnm = (LPNMTREEVIEW)lParam;
if (pnm->hdr.code == NM_CUSTOMDRAW)
{
//LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam;
//TreeView_GetItem(
//pnm->iItem
LPNMTVCUSTOMDRAW lplvcd = (LPNMTVCUSTOMDRAW)lParam;
//pnm->iItem
//TreeView_GetItem(hWnd,pnm->iItem);
switch (lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT :
return CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
if(found_unMatched(lplvcd->nmcd.lItemlParam))
{
hwndTree = GetDlgItem(hWnd,ID_TREEVIEW);
lplvcd->clrText = RGB(0, 255,0);
ZeroMemory(&tv, sizeof(TVITEM));
tv.hItem=(HTREEITEM)lplvcd->nmcd.dwItemSpec;
tv.mask=TVIF_TEXT|TVIF_HANDLE;
tv.cchTextMax=100;
tv.pszText=(LPWSTR)achBuf;
if(TreeView_GetItem(hwndTree,&tv))
{
achBuf;
}
hChild =(HTREEITEM)TreeView_GetChild(hwndTree,(HTREEITEM)lplvcd->nmcd.dwItemSpec);
hSibling=(HTREEITEM)TreeView_GetNextSibling(hwndTree,hChild);
}
return CDRF_NOTIFYSUBITEMDRAW;
break;
case CDDS_POSTPAINT:
return CDRF_DODEFAULT;
break;
case CDDS_ITEMPOSTPAINT| CDDS_SUBITEM :
hwndTree = GetDlgItem(hWnd,ID_TREEVIEW);
ZeroMemory(&tv, sizeof(TVITEM));
tv.hItem=(HTREEITEM)lplvcd->nmcd.dwItemSpec;
tv.mask=TVIF_TEXT|TVIF_HANDLE;
tv.cchTextMax=100;
tv.pszText=(LPWSTR)achBuf;
if(TreeView_GetItem(hwndTree,&tv))
{
achBuf;
}
if((HTREEITEM)lplvcd->nmcd.dwItemSpec==hSibling)
{
lplvcd->clrText = RGB(176, 0,0);
}
return CDRF_NEWFONT;
break;
case CDDS_ITEMPOSTPAINT:
double_click=1;
break;
}
}}break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
this will color my parent node but child nodes(subitem) remained default(black) and return CDRF_NOTIFYSUBITEMDRAW didnt work. Please help!!!
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?