I'm at a loss on this one, not really even sure what code to post.
I have a c++ application. The initial window has an edit control, custom control, and menu. When the user presses F5, a new window open with its own message loop. The new window then opens a DialogBox, and is modal as expected.
The odd part is that the DialogBox seems to be hidden behind the 2nd window. I have to alt-tab to the first window, then alt-tab back to the second window to get to the dialog box.
If I cancel out of the DialogBox, the second window is destroyed (as expected), and a MessageBox is shown (as expected), but that message box seems to be hidden behind the first window. Again, I have to alt-tab twice to get the MessageBox to the forefront, and OK out of it.
Does anyone have any ideas what could cause this odd Pop-Under behavior with both the DialogBox and MessageBox?
Thanks!
Code to create the Dialog Box
INT_PTR ip = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_AMBIGUOUS), this->hWnd, DlgAmbiguous);
Code for the DlgAmbiguous Proceduels
INT_PTR CALLBACK DlgAmbiguous(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
{
HWND hStaticTerm = GetDlgItem(hDlg, IDC_TERM);
SetWindowText(hStaticTerm, lpAmbiguousTerm);
if (wcscmp(lpAmbiguousTerm, L"canvas") == 0)
{
HWND hComboBox = GetDlgItem(hDlg, IDC_MEANING);
SendMessage(hComboBox, CB_ADDSTRING, NULL, reinterpret_cast<LPARAM>(_T("Program Window")));
SendMessage(hComboBox, CB_ADDSTRING, NULL, reinterpret_cast<LPARAM>(_T("Region in Program Window")));
}
return (INT_PTR)TRUE;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDOK)
{
HWND hComboBox = GetDlgItem(hDlg, IDC_MEANING);
iAmbiguousResult = SendMessage(hComboBox, CB_GETCURSEL, NULL, NULL);
EndDialog(hDlg, iAmbiguousResult + 100);
return (iAmbiguousResult == -1) ? FALSE : TRUE;
}
else if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, DLG_CANCEL);
return (INT_PTR)FALSE;
}
break;
}
return (INT_PTR)FALSE;
When you open a window, regardless if it runs on the same thread or not, it makes sense to specify its parent window. This will force new window to appear above its parent. The same applies to the dialog box:
INT_PTR WINAPI DialogBox(
_In_opt_ HINSTANCE hInstance,
_In_ LPCTSTR lpTemplate,
_In_opt_ HWND hWndParent,
_In_opt_ DLGPROC lpDialogFunc
);
Note the third parameter. Other option to bring your window on top is by calling the SetWindowPos function.
Related
I'm struggling properly creating a dialog box.
The first problem was getting the dialog box itself visible. When displaying a dialog it did only show controls inside of the dialob box, but the dialog box itself were invisiblem but it was still possible to press the close button. I fixed this by adding a custom class name to the dialog boxes properties and registering the class. Does someone know what exactly the problem was? A colleague of mine didn't need to explicit register the class and add it to the dialog boxes properties.
But my current problem is as follows:
I have this callback function:
static BOOL CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
MessageBox(NULL, L"init dialog", L"Message Box", NULL);
break;
case WM_CLOSE:
DestroyWindow(hwnd);
MessageBox(NULL, L"close dialog", L"Message Box", NULL);
break;
case WM_DESTROY:
MessageBox(NULL, L"destroying dialog", L"Message Box", NULL);
break;
}
return TRUE;
}
and this initiation of a new dialog box:
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
TCHAR szTitle[MAX_LOADSTRING] = TEXT("This is the DialogBox Title"); // Titelleistentext
TCHAR szWindowClass[MAX_LOADSTRING] = TEXT("MyDialogBoxClass"); // Klassenname des Hauptfensters
g_hInst = hInstance; // Instanzenhandle in der globalen Variablen speichern
if (!MyRegisterClass(hInstance, szWindowClass))
{
return FALSE;
}
hWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG_FTPHELPER), NULL, DialogProc);
if (!hWnd)
{
return FALSE;
}
SetWindowText(hWnd, szTitle);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
if (g_hWndCommandBar)
{
CommandBar_Show(g_hWndCommandBar, TRUE);
}
return TRUE;
}
When displaying a new dialog box it doesn't call the "DialogProc" function not even once, never, it makes me sick...
Does someone know the answer to this problem?
best greetings and thank you for your help!
Your DialogProc function always returns TRUE, meaning that it handled whatever message it received. However, you only actually handle three messages, and there are many others (such as WM_CREATE) that are called by the system in order to 'set up' the dialog window.
You should only return TRUE if you have completely handled the message, and FALSE otherwise, so that the system can call the default procedure for messages that you don't handle.
From the Microsoft documentation:
Typically, the dialog box procedure should return TRUE if it processed
the message, and FALSE if it did not. If the dialog box procedure
returns FALSE, the dialog manager performs the default dialog
operation in response to the message.
So my program works, all apart from one thing, I would like for my button, 'pushBtn' , aka BTN_PUSH_TALK , to send a BN_PUSHED or BN_UNPUSHED message so I can handle it accordingly.
Following steps online, as well as trial and improvement, right now the only response I ever get is once I am done holding / clicking the button.
pushBtn = CreateWindowEx(0, L"BUTTON", L"TALK", WS_CHILD |
WS_VISIBLE |
BS_DEFPUSHBUTTON , 0 , 290 , 50, 50,
hWnd,(HMENU)BTN_PUSH_TALK, GetModuleHandle(NULL), NULL);
Handler (or at least what matters) :
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM
lParam)
{
bool asd;
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case BTN_PUSH_TALK:
switch (HIWORD(wParam))
{
case BN_UNPUSHED:
if (connected && inputChoiceStr == "Push To Talk") {
tplug->setDuck(false);
}
break;
case BN_PUSHED:
if (connected && inputChoiceStr == "Push To Talk") {
tplug->setDuck(true);
}
break;
}
break;
I expected once i clicked and held down the button , that the BN_PUSHED case would be entered, however it is not.
On letting go, I expect the BN_UNPUSHED case to be entered, but this was not the case either.
case BTN_PUSH_TALK is reached, meaning the button is identifiable, however the switch case within this block of code is never reached.
Buttons send WM_COMMAND on click. To achieve a push/release notification you must subclass the button class (SetWindowLongPtr() with GWLP_WNDPROC) and then handle WM_LBUTTONDOWN and WM_LBUTTONUP in your new Window Proc.
If I'm reading the question right, your goal is to get notifications when a standard push button is initially pushed by the user, whereas standard notification behavior of buttons only posts WM_COMMANDs on "clicks" where a click is the whole mouse down plus mouse up sequence.
Historically in order to get the BN_PUSHED and BN_UNPUSHED notifications in your WM_COMMAND handler you had to use the BS_NOTIFY window style when creating the button. However, if you read the documentation for BN_PUSHED or BN_UNPUSHED you will see
This notification code is provided only for compatibility with 16-bit versions of Windows earlier than version 3.0. Applications should use the BS_OWNERDRAW button style and the DRAWITEMSTRUCT structure for this task.
These were very old notifications that from what I can tell are not just deprecated but no longer even supported. You can do, however, as the documentation suggests: use an owner drawn button i.e. a button created with the BS_OWNERDRAW style.
This turns out to be more difficult than just creating the button with BS_NOTIFY turned on, because the button will no longer perform default painting by itself. Given this added chore, I'd recommend not doing it this way unless you want to custom paint your buttons anyway -- unless you happen to want some nonstandard visual look-and-feel for these buttons as well as nonstandard notification behavior. Otherwise, I would probably just do Win32 subclassing as someone else suggested to trap WM_LBUTTONDOWN etc. and then call the standard button WNDPROC after doing some action on the events i cared about.
Anyway the minimal owner drawn button that reports button down and button up events is like the following. (I post the button events as custom messages but you could do whatever you wish there)
#include <windows.h>
#define BTN_ID 101
#define WM_PUSHBUTTONDOWN WM_APP + 1
#define WM_PUSHBUTTONUP WM_APP + 2
HINSTANCE g_instance = 0;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
g_instance = hInstance;
MSG msg = { 0 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = WndProc;
wc.hInstance = hInstance;
wc.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_BACKGROUND);
wc.lpszClassName = L"owner_draw_btn";
if (!RegisterClass(&wc))
return -1;
if (!CreateWindow(wc.lpszClassName, L"foobar", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 640, 480, 0, 0, hInstance, NULL))
return -1;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT HandleDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
auto* dis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);
if (dis->CtlType != ODT_BUTTON)
return 0;
auto style = (dis->itemState & ODS_SELECTED) ?
DFCS_BUTTONPUSH | DFCS_PUSHED :
DFCS_BUTTONPUSH;
auto rect = &dis->rcItem;
DrawFrameControl(dis->hDC, rect, DFC_BUTTON, style);
TCHAR text[512];
auto n = GetWindowText(dis->hwndItem, text, 512);
DrawText(dis->hDC, text, n, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
if (dis->itemAction == ODA_SELECT) {
PostMessage(
hWnd,
(dis->itemState & ODS_SELECTED) ? WM_PUSHBUTTONDOWN : WM_PUSHBUTTONUP,
dis->CtlID,
0
);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
CreateWindow(
L"button", L"foobar",
BS_OWNERDRAW | WS_CHILD | WS_VISIBLE,
10, 10, 150, 35, hWnd,
(HMENU) BTN_ID,
g_instance,
0
);
return 0;
case WM_DRAWITEM:
return HandleDrawItem(hWnd, wParam, lParam);
case WM_PUSHBUTTONDOWN:
OutputDebugString(L"Button down event\n");
break;
case WM_PUSHBUTTONUP:
OutputDebugString(L"Button up event\n");
break;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
The code below, sends a WM_CHANGEUISTATE to the window procedure itself, with the arguments:
LOWORD(wParam) = UIS_CLEAR
HIWORD(wParam) = UISF_HIDEACCEL
lParam = 0x00000000
when the window client area is left clicked with the mouse.
According to this blog by Raymond Chen this should make the mnemonics in the System menu to be shown, when the menu is accessed with the mouse. The paragraph below was extracted from this article:
Clearing a flag shows the corresponding indicator. For example, if you
have a UIS_CLEAR for UISF_HIDEFOCUS, that means that you want to show
focus indicators.
In my case, I have a UIS_CLEAR for UISF_HIDEACCEL, meaning that I want to show the menu accelerators.
If you run the code below and click with the mouse left button on the app client area, you should make the accelerators visible in the System menu, even when this menu is accessed with the mouse. But that doesn't happen, i.e., if you activate the system menu with a left click on the window's icon, or with a right click on the window's title bar, the mnemonics in the System menu will not be shown. What am I missing?
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow)
{
WNDCLASSEX wndclassx;
wchar_t szAppName[] = L"WM_CHANGEUISTATE";
wndclassx.cbSize = sizeof(WNDCLASSEX);
wndclassx.style = CS_HREDRAW | CS_VREDRAW;
wndclassx.lpfnWndProc = WndProc;
wndclassx.cbClsExtra = 0;
wndclassx.cbWndExtra = 0;
wndclassx.hInstance = hInstance;
wndclassx.hIcon = 0;
wndclassx.hCursor = LoadCursor(0, IDC_ARROW);
wndclassx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndclassx.lpszClassName = szAppName;
wndclassx.lpszMenuName = nullptr;
wndclassx.hIconSm = 0;
if (!RegisterClassEx(&wndclassx)) return 0;
HWND hWnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, 0);
ShowWindow(hWnd, SW_MAXIMIZE);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONUP:
{
BOOL b;
// Note that in my system (Windows 10) I have:
//
// Control Panel > Ease of Access > Ease of Access Center > Make the keyboard easier
//
// and the option "Underline keyboard shortcuts and access keys" unmarked (the default). Therefore, the value
// returned in b below will be 0x00000000 (FALSE).
SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &b, 0);
// If b = FALSE, the SendMessage() below should underline the accelerators in the System menu, when this menu is
// accessed with the mouse. But that doesn't work. Why?
if( !b ) SendMessage(hwnd, WM_CHANGEUISTATE, MAKEWPARAM(UIS_CLEAR, UISF_HIDEACCEL), NULL);
}
break;
// Setting a break in the return below, one can see that WM_CHANGEUISTATE message is being sent to the window and
// passed to DefWindowProc().
case WM_CHANGEUISTATE:
return DefWindowProc(hwnd, message, wParam, lParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
This seems like a bug/oversight in Windows. DefWindowProc does not send WM_QUERYUISTATE before displaying the system menu. The menu implementation checks the last input event directly and if it was from a keyboard it displays the underlines.
I tried sending and posting WM_CHANGEUISTATE and WM_UPDATEUISTATE in response to WM_ENTERMENULOOP, WM_INITMENUPOPUP, WM_NCRBUTTONDOWN and WM_SYSCOMMAND without any luck.
The only workaround I was able to come up with is to hack the HTSYSMENU/icon menu by changing SC_MOUSEMENU to SC_KEYMENU:
case WM_SYSCOMMAND:
if ((wParam & 0xFFF0) == SC_MOUSEMENU)
{
return SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, ' ');
}
return DefWindowProc(hwnd, message, wParam, lParam);
SC_KEYMENU has special handling in DefWindowProc and forces underlines if applicable.
This does not handle right-click on the icon, caption nor task bar...
My issue is that I am trying to create a Opengl/Win32 application and I am unable to keep my dialog box open. It literally flashes as if someone pressed cancel on it RIGHT when it opened.
I've looked around google and found a few others with this issue, but none of the solutions they posted have helped me, so I turn to the StackOverflow community!
Initially, I wrote code for the Dialog Procedure...
LRESULT CALLBACK LoginDlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
ShowWindow(hWndDlg, SW_SHOW); // These were added to get the window to show up
UpdateWindow(hWndDlg); // even if the chance was small.
switch(Msg)
{
case WM_INITDIALOG:
return true;
case WM_COMMAND:
switch(wParam)
{
case IDOK:
EndDialog(hWndDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
I then wrote the actual code to display the box.
void DisplayLoginBox()
{
LoginDlgHwnd = NULL;
LoginDlgHwnd = (HWND)DialogBox(GetModuleHandle(NULL),
MAKEINTRESOURCE(LOGIN_DIALOG),
app.GetHandle(),
reinterpret_cast<DLGPROC>(LoginDlgProc)
);
if(LoginDlgHwnd == NULL)
MessageBox(NULL, NULL, NULL, MB_OK);
}
app.GetHandle() returns a hwnd of the main program. This function works properly. and LoginDlgHwnd is a global variable.
The actual dialog is created and included properly as well. Do you have any ideas?
-Celestialkey
DialogBox does not return a hwnd, the function does not return until the dialog is closed, if you want a modeless dialog and a handle, use CreateDialog
The DLGPROC DialogBox parameter should not require a cast, change LoginDlgProc' LRESULT to INT_PTR
MessageBox(NULL, NULL, NULL, MB_OK); will not display anything, it needs text in the 2nd parameter
It is hard to say why the dialog does not stay open, but you should check the return value of DialogBox, if it is 0, the parent hwnd is invalid, if it is -1, call GetLastError() to get more info. One thing you could try is to remove all controls in the LOGIN_DIALOG dialog template (If you used common controls, but did not call InitCommonControls, the dialog would not work etc)
After creating the initial dialog box that works perfectly fine, I create another dialog box when the Join Game button is pressed. The dialog box is created and show successfully, however I am unable to type in the edit box or even press or exit the dialog. Does anyone understand how to fix this or why it happens? I made sure the dialog box itself was not the problem by creating and displaying it from the main loop in the application. It worked fine when I created it that way. So why does it error when being created from another dialog?
My code is below.
This code is for the DLGPROC function that each dialog uses.
#define WIN32_LEAN_AND_MEAN
#include "Windows.h"
#include ".\Controllers\Menu\MenuSystem.h"
#include ".\Controllers\Game Controller\GameManager.h"
#include ".\Controllers\Network\Network.h"
#include "resource.h"
#include "main.h"
using namespace std;
extern GameManager g;
extern bool men;
NET_Socket server;
extern HWND d;
HWND joinDlg;
char ip[64];
void JoinMenu(){
joinDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO), NULL, (DLGPROC)GameJoinDialogPrompt);
SetFocus(joinDlg);
// ShowWindow(joinDlg, SW_SHOW);
ShowWindow(d, SW_HIDE);
}
LRESULT CALLBACK GameJoinDialogPrompt(HWND Dialogwindow, UINT Message, WPARAM wParam, LPARAM lParam){
switch(Message){
case WM_COMMAND:{
switch(LOWORD(wParam)){
case IDCONNECT:{
GetDlgItemText(joinDlg, IDC_IP, ip, 63);
if(server.ConnectToServer(ip, 7890, NET_UDP) == NET_INVALID_SOCKET){
LogString("Failed to connect to server! IP: %s", ip);
MessageBox(NULL, "Failed to connect!", "Error", MB_OK);
ShowWindow(joinDlg, SW_SHOW);
break;
}
}
LogString("Connected!");
break;
case IDCANCEL:
ShowWindow(d, SW_SHOW);
ShowWindow(joinDlg, SW_HIDE);
break;
}
break;
}
case WM_CLOSE:
PostQuitMessage(0);
break;
}
return 0;
}
LRESULT CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message, WPARAM wParam, LPARAM lParam){
switch(Message){
case WM_PAINT:{
PAINTSTRUCT ps;
RECT rect;
HDC hdc = GetDC(Dialogwindow);
hdc = BeginPaint(Dialogwindow, &ps);
GetClientRect (Dialogwindow, &rect);
FillRect(hdc, &rect, CreateSolidBrush(RGB(0, 0, 0)));
EndPaint(Dialogwindow, &ps);
break;
}
case WM_COMMAND:{
switch(LOWORD(wParam)){
case IDC_HOST:
if(!NET_Initialize()){
break;
}
if(server.CreateServer(7890, NET_UDP) != 0){
MessageBox(NULL, "Failed to create server.", "Error!", MB_OK);
PostQuitMessage(0);
return -1;
}
ShowWindow(d, SW_HIDE);
break;
case IDC_JOIN:{
JoinMenu();
}
break;
case IDC_EXIT:
PostQuitMessage(0);
break;
default:
break;
}
break;
}
return 0;
}
}
I call the first dialog using the below code
void EnterMenu(){
// joinDlg = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO), g_hWnd, (DLGPROC)GameJoinDialogPrompt);//
d = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_SELECTMENU), g_hWnd, (DLGPROC)GameMainDialogPrompt);
}
The dialog boxes are not DISABLED by default, and they are visible by default. Everything is set to be active on creation and no code deactivates the items on the dialog or the dialog itself.
First, make sure you write the correct signature for the dialog procedures:
INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg,
WPARAM wParam, LPARAM lParam);
(See http://msdn.microsoft.com/en-us/library/ms645469(v=VS.85).aspx)
Your dialog procedures should therefore look like this:
INT_PTR CALLBACK GameJoinDialogPrompt(HWND Dialogwindow, UINT Message,
WPARAM wParam, LPARAM lParam)
{ /* ... */ }
INT_PTR CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message,
WPARAM wParam, LPARAM lParam)
{ /* ... */ }
Then you should be able to do this without warnings or errors:
void EnterMenu()
{
d = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_SELECTMENU),
g_hWnd, &GameMainDialogPrompt);
// Note the ampersand. Also note that no cast is needed. You should
// not need to use a cast to pass in the address of the function.
}
See http://blogs.msdn.com/oldnewthing/archive/2004/01/15/58973.aspx for why it's extremely important to get the function signature right.
That being said, your joinDlg should be a modal dialog box, since it is requesting information from the user:
void JoinMenu()
{
// DialogBox() creates a modal dialog box. It "blocks" its owner until
// it closes. On the other hand, CreateDialog() creates a non-modal
// dialog box.
joinDlg = DialogBox(g_hInstance, MAKEINTRESOURCE(IDD_GETADDRESSINFO),
d, &GameJoinDialogPrompt);
// Again, note the ampersand and the lack of a cast when passing in
// the address of the dialog procedure. Also, the main dialog box is
// serving as the owner of this dialog box.
}
Also note that dialog box procedures are different from windows procedures in that they return either TRUE or FALSE: TRUE if your dialog procedure processed the message, FALSE otherwise. (There are some "weird" messages that violate this rule, but you're not handling for those messages)
So your dialog procedures should look something like this:
INT_PTR CALLBACK GameMainDialogPrompt(HWND Dialogwindow, UINT Message,
WPARAM wParam, LPARAM lParam)
{
switch(Message)
{
case WM_PAINT:
/* Do painting */
return TRUE; // We handled the paint message
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_HOST:
/* Do command */
return TRUE; // We handled this particular command.
case IDC_JOIN:
/* Do command */
return TRUE; // We handled this particular command.
case IDC_EXIT:
/* Do command */
return TRUE; // We handled this particular command.
}
return FALSE; // The command wasn't handled.
}
return FALSE; // The message wasn't handled.
}
Dialog procedures do not call DefWindowProc() nor return 0!
In addiiton to the other excellent post you are also doing silly things like:
if(server.CreateServer(7890, NET_UDP) != 0){
MessageBox(NULL, "Failed to create server.", "Error!", MB_OK);
PostQuitMessage(0);
in a WM_COMMAND handler. This is a horrible piece of code as it stalls the dialogs modal loop without disabling it, or popping up the message box.
If you call a modal window from a different window (or dialogs) message proc you MUST disable the stalled window. Practically speaking, pass the windows HWND to the MessageBox call.
If all else fails, start fresh with this:
In resource.h:
#define IDD_DIALOG1 101
#define IDD_DIALOG2 102
#define ID_OPEN 1001
#define ID_MESSAGE 1002
In a resource file:
#include <winres.h>
#include "resource.h"
IDD_DIALOG1 DIALOGEX 0, 0, 300, 200
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER |
WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Main Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Open Secondary Dialog", ID_OPEN, 73 ,49, 133, 64
END
IDD_DIALOG2 DIALOGEX 0, 0, 200, 150
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER |
WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Secondary Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Message Box", ID_MESSAGE, 50, 49, 88, 50
END
In a source file:
#include <windows.h>
#include "resource.h"
INT_PTR CALLBACK SecondaryDialogProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_MESSAGE:
// Show a message box. Note that we're passing in our own HWND into
// the function, so we "block" this dialog box until the user
// dismisses this message box.
::MessageBox(hwnd, "Hello World!", "Greetings", MB_OK);
return TRUE;
}
return FALSE;
case WM_CLOSE:
// Because this is a modal dialog box (we used ::DialogBox()), we
// use ::EndDialog() instead of ::DestroyWindow() to destroy this
// dialog box.
::EndDialog(hwnd, 0);
return TRUE;
}
return FALSE;
}
INT_PTR CALLBACK MainDialogProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_OPEN:
// Open a modal dialog box. This will block the main dialog box
// until the secondary dialog box is closed.
::DialogBox(::GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG2), hwnd, &SecondaryDialogProc);
return TRUE;
}
return FALSE;
case WM_CLOSE:
// We close this dialog box with ::DestroyWindow(). This causes the
// WM_DESTROY message to be sent.
::DestroyWindow(hwnd);
return TRUE;
case WM_DESTROY:
// Since the main dialog box is being destroyed, we quit
// the application.
::PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd)
{
// Open a non-modal dialog box using ::CreateDialog().
HWND mainDlg = ::CreateDialog(::GetModuleHandle(NULL),
MAKEINTRESOURCE(IDD_DIALOG1), NULL, &MainDialogProc);
// The first ::ShowWindow() call should use nShowCmd.
::ShowWindow(mainDlg, nShowCmd);
MSG msg;
while (::GetMessage(&msg, NULL, 0, 0) > 0)
{
// So our main dialog behaves properly.
if(!::IsDialogMessage(mainDlg, &msg))
{
::TranslateMessage( & msg );
::DispatchMessage( & msg );
}
}
return msg.wParam;
}
Here, this is just the bare bones code to open up a main dialog, with a button to open another dialog. See if this works first, then add your business logic.