This is my main loop:
while(TRUE)
{
PeekMessage(&msg,hWnd,0,0,PM_REMOVE);
if (msg.message==WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
and this is my callback procedure:
LRESULT CALLBACK WinProc(HWND hWnd,UINT msg1,WPARAM wParam,LPARAM lParam)
{
switch(msg1)
{
case WM_DESTROY :
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc(hWnd,msg1,wParam,lParam);
}
I found out that when I press Close button WM_NCLBUTTONDOWN will be returned by the PeekMessage function in the next loop, and no WM_QUIT!
The correct way to do a message loop is
BOOL bRet;
MSG msg;
while ((bRet = GetMessage(&msg, hWnd, 0, 0)) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
You can use PeekMessage if you really need to... but why are you ignoring the return value?
Also, note that this is specific to a window. I believe PostQuitMessage is for a thread... I don't remember it off the top of my head, but you might need to pass NULL instead of hWnd.
If you have any other windows, that may hijack their message loop as well -- I don't think it's usually an issue, but it might potentially be one; keep that in mind.
Here's some code I found. It should give you something to work with.
// Main message loop:
do
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Run game code here.
gTradeApp->ExecuteNextAction();
}
while (msg.message != WM_QUIT);
and the WndProc
LRESULT CALLBACK WndProc(HWND aHWnd, UINT aMessage, WPARAM aWParam, LPARAM aLParam)
{
switch (aMessage)
{
case WM_COMMAND:
return HandleCommand(aHWnd, aMessage, aWParam, aLParam);
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(aHWnd, aMessage, aWParam, aLParam);
}
return 0;
}
I recommend sticking with this, to ensure errors (-1) returned by GetMessage can be handled properly:
while(GetMessage(&Msg, NULL, 0, 0) > 0) {
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
Also, another error is not handling WM_CLOSE properly. Try this instead to make your program actually listen to WM_CLOSE (the close button):
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
switch(Message) {
case WM_CLOSE: {
DestroyWindow(hwnd); // this
break;
}
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hwnd, Message, wParam, lParam);
}
return 0;
}
Related
So, my window procedure is currently trapping all WM_CHAR messages, it works fine with ASCII characters but when I try something like:
case 'ф':
MessageBox(NULL, TEXT("Ф detected"), TEXT("key"), MB_OK);
it fails for some reason.
What's wrong with my approach and how do I fix this?
EDIT: source-code:
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
switch(wParam)
{
case '3':
MessageBox(NULL, TEXT("'3' was pressed"), TEXT("key detected"), MB_OK);
return 0;
case 'ф':
MessageBox(NULL, TEXT( "ф was pressed"), TEXT("key detected"), MB_OK);
return 0;
default:
return 0;
}
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
Non-Unicode characters need to be replace as Unicode characters in switch-case:
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CHAR:
switch(wParam)
{
case L'3':
MessageBox(NULL, TEXT("'3' was pressed"), TEXT("key detected"), MB_OK);
return 0;
case L'ф':
MessageBox(NULL, TEXT( "ф was pressed"), TEXT("key detected"), MB_OK);
return 0;
default:
return 0;
}
case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
The values of 'ф' and L'ф' are different. The values of 'ф' and other characters not in the ASCII table are often resolved to '?' (63)
If i use the win32 api,how to respond WM_RBUTTONUP?
case WM_RBUTTONUP:
{
break;
}
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
case IDE_FRIEND:
{
switch (wmEvent) {
case WM_RBUTTONUP:
{
POINT pt;
GetCursorPos(&pt);
TrackPopupMenu(g_hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hWnd, nullptr);
break;
}
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
break;
}
When I click the right mouse button,it will not enter 'case WM_RBUTTONUP'
'IDE_FRIEND' is associated with listbox.
Right-click on listbox will generate context message for parent window. You should be able to catch it like this:
case WM_CONTEXTMENU:
{
if (hListBox == (HWND)wParam)
{
int x = LOWORD(lParam);
int y = HIWORD(lParam);
TrackPopupMenu(g_hMenu, TPM_RIGHTBUTTON, x, y, 0, hWnd, nullptr);
}
break;
}
case WM_RBUTTONUP:
{
//main window's right-click message
break;
}
case WM_COMMAND:
{
//...
}
Edit:
To do the same thing with subclass
#include "CommCtrl.h" //may need to add this
#pragma comment(lib, "comctl32.lib")
LRESULT CALLBACK ListBoxProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp,
UINT_PTR, DWORD_PTR)
{
switch (msg){
case WM_RBUTTONUP:
{
//add listbox menu here
break;
}
case WM_NCDESTROY://safely remove subclass
{
RemoveWindowSubclass(hwnd, ListBoxProc, 0);
return DefSubclassProc(hwnd, msg, wp, lp);
}
}
return DefSubclassProc(hwnd, msg, wp, lp);
}
LRESULT CALLBACK MainWindowProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
//...
case WM_CREATE:
ListBox = CreateWindow(L"listbox", ... )
SetWindowSubclass(ListBox, ListBoxProc, 0, 0);
//...
}
If I have n Client connect the Server,how to accept it in FD_ACCEPT and how to receive it in FD_READ and how to send it in FD_WRITE and not use like this form
e.p.
while(1){
ClientSocket=accept(ListenSocket,0,0);
if(ClientSocket!=INVALID_SOCKET)
_beginthreadex();
}
how to achieve it in this form
case WM_SERVER_SOCKET:
wEvent = WSAGETSELECTEVENT(lParam);//LOWORD
switch (wEvent) {
case FD_ACCEPT:
ClientSocket=accept(ListenSocket, nullptr, nullptr);
break;
case FD_READ:
break;
case FD_WRITE:
break;
case FD_CLOSE:
break;
}
break;
or this form just can handle one Client connection?
is it necessary do it in this form?
I want use it for a simple chat application
WSAAsyncSelect() is what you are looking for, eg:
WNDCLASS cls = {0};
cls.lpfnWndProc = &SocketWndProc;
cls.hInstance = ...;
cls.lpszClassName = TEXT("MySocketWnd");
RegisterClass(&cls);
HWND hWnd = CreateWindowEx(0, cls.lpszClassName, nullptr, 0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, cls.hInstance, nullptr);
SOCKET ListenSocket = socket(...);
bind(ListenSocket, ...);
listen(ListenSocket, ...);
WSAAsyncSelect(ListenSocket, hWnd, WM_SERVER_SOCKET, FD_ACCEPT | FD_READ | FD_WRITE | FD_CLOSE);
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
closesocket(ListenSocket);
DestroyWindow(hWnd);
LRESULT CALLBACK SocketWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg != WM_SERVER_SOCKET)
return DefWindowProc(hWnd, uMsg, wParam, lParam);
SOCKET sckt = (SOCKET) wParam;
WORD wEvent = WSAGETSELECTEVENT(lParam);
WORD wError = WSAGETSELECTERROR(lParam);
if (wError != 0)
{
// wEvent on sckt failed, do something ...
return 0;
}
switch (wEvent)
{
case FD_ACCEPT:
{
// sckt has a pending client...
SOCKET ClientSocket = accept(sckt,...);
// do something with new client (add it to a tracking list, etc) ...
break;
}
case FD_READ:
{
// sckt has pending data...
int numBytes = recv(sckt, ...);
// process data as needed...
break;
}
case FD_WRITE:
{
// sckt can receive data, send any pending data ...
break;
}
case FD_CLOSE:
{
// sckt has disconnected, do something (remove it from list, etc)...
break;
}
}
return 0;
}
I have created a simple win 32 application..in which it has a textbox and a button in a dialog window..first when I created this..it didnt display the dialog window and then what I did is added the code below to handle the close(WM_CLOSE) of the dialog window...but I want to know, how to handle the button click event..
void ValidatePassword(CString encryptedPassword)
{
//create password dialog window
CreateEvent(NULL,true,false,L"TestEvent");
MSG msg;
HWND hwnd = CreateWindowEx(0,WC_DIALOG,L"Security Alert",WS_OVERLAPPEDWINDOW|WS_VISIBLE,
600,300,300,200,NULL,NULL,NULL,NULL);
//create label
CreateWindowEx(NULL,L"Static",L"Requires Password to Run the File:", WS_CHILD|WS_VISIBLE,
10,25,300,20,hwnd,(HMENU)label_id,NULL,NULL);
//create textboxcontrol within the dialog
CreateWindowEx(WS_EX_CLIENTEDGE,L"EDIT",L"",WS_CHILD|WS_VISIBLE | ES_PASSWORD,
10,50,125,25,hwnd,(HMENU)textbox_id,NULL,NULL);
//create button
HWND button = CreateWindowEx(WS_EX_CLIENTEDGE,L"Button",L"OK",WS_CHILD|WS_VISIBLE,
10,100,100,25,hwnd,(HMENU)button_id,NULL,NULL);
ShowWindow (hwnd, SW_SHOW);
UpdateWindow(hwnd);
//SetWindowLong(button,DWL_DLGPROC, (long)myProc);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT WINAPI myProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HWND hwndButton;
switch (message)
{
/* Handles all Windows Messages */
case WM_COMMAND:
{
if(((HWND)lParam) && (HIWORD(wParam) == BN_CLICKED))
{
int iMID;
iMID = LOWORD(wParam);
switch(iMID)
{
case button_id:
{
MessageBox(hwnd, (LPCTSTR)"You just pushed me!", (LPCTSTR) "My Program!", MB_OK|MB_ICONEXCLAMATION);
break;
}
default:
break;
}
}
break;
}
case WM_DESTROY:
{
PostQuitMessage (0); /* send a WM_QUIT to Message Queue, to shut off program */
break;
}
}
return 0;
}
Yikes.
It should not be necessary to call SetWindowLong to set the dialog proc for a dialog. Your "simple" program should look something like
#include <windows.h>
#include "resource.h"
BOOL CALLBACK myProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if( LOWORD(wParam) == IDCLOSE) // close button click
EndDialog(hwnd,0);
return TRUE;
}
return FALSE;
}
int CALLBACK WinMain(HINSTANCE hExe,HINSTANCE,LPCSTR,INT)
{
return DialogBox(hExe,MAKEINTRESOURCE(IDD_DIALOG),NULL,myProc);
}
Check for WM_COMMAND. LOWORD(wParam) will be your control ID and lParam will be your hWnd for the button.
I am making a dll that controls a dialogue box. I like to get a certain area to have red text. This code does compile, but the effect is not seen. Here is the area where the dialogProc is done:
LRESULT CALLBACK DialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
CheckDlgButton(hDlg, IDC_CHECK, FALSE);
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_CHECK:
if (IsDlgButtonChecked(hDlg, IDC_CHECK))
{
EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
}
else
{
EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
EnableWindow(GetDlgItem(hDlg, IDCANCEL), TRUE);
}
break;
case IDOK:
{
EndDialog(hDlg, TRUE);
return FALSE;
}
case IDCANCEL:
{
EndDialog(hDlg, FALSE);
return FALSE;
}
case WM_CTLCOLORSTATIC:
// Set the colour of the text for our URL
if ((HWND)lParam == GetDlgItem(hDlg,IDC_WARNING))
{
// we're about to draw the static
// set the text colour in (HDC)lParam
SetBkMode((HDC)wParam,TRANSPARENT);
SetTextColor((HDC)wParam, RGB(255,0,0));
return (BOOL)CreateSolidBrush (GetSysColor(COLOR_MENU));
}
return TRUE;
}
}
return FALSE;
}
WM_CTLCOLORSTATIC is a separate message from WM_COMMAND. Your desired handling of the message appears to be correct except that the check for the message is inside your check for WM_COMMAND specific items. Try reorganizing your outer switch statement. Perhaps something like the following:
LRESULT CALLBACK DialogProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
// ...
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_CHECK:
// ...
break;
case IDOK:
// ...
break;
case IDCANCEL:
// ...
break;
}
break;
case WM_CTLCOLORSTATIC:
// Set the colour of the text for our URL
if ((HWND)lParam == GetDlgItem(hDlg, IDC_WARNING))
{
// we're about to draw the static
// set the text colour in (HDC)lParam
SetBkMode((HDC)wParam,TRANSPARENT);
SetTextColor((HDC)wParam, RGB(255,0,0));
// NOTE: per documentation as pointed out by selbie, GetSolidBrush would leak a GDI handle.
return (BOOL)GetSysColorBrush(COLOR_MENU);
}
break;
}
return FALSE;
}
Also note that it would be kinda weird to filter WM_COMMAND's wParam argument when wParam is supposed to provide the HDC for WM_CTLCOLORSTATIC.
WM_CTLCOLORSTATIC Notification at MSDN