I'm starting out with win32 programming.
I created my first dialog but I can't drag it around with my mouse; it simply stays where it is. Why?
This is its proc function:
static bool CALLBACK ChangeColumnProc(HWND dialog, uint32 message, WPARAM wParam, LPARAM lParam)
{
static ColumnInfo *column = NULL;
switch(message)
{
case WM_INITDIALOG:
column = (ColumnInfo *)lParam;
InitializeDialog(dialog, column);
return true;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK:
SaveChanges(dialog, column);
break;
case IDCANCEL:
EndDialog(dialog, lParam);
break;
default:
return false;
}
return true;
}
return false;
}
This is how I create it:
if(DialogBoxParam(StartupInfo.Instance, MAKEINTRESOURCE(IDD_CHANGE_COLUMN), StartupInfo.Window, (DLGPROC)ChangeColumnProc, (LPARAM)&column) == IDOK)
What am I doing wrong?
The return type of the dialog procedure is INT_PTR, not bool. Return (INT_PTR)FALSE if you don't handle the message.
Related
I am trying to change the text of the "static text" control and its color at once, and I have done that, but the problem is when changing the text first and then changing the color of that text, it takes a little noticeable time between changing the text and its color.
bool IsGameOpen = false;
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INITDIALOG:
{
SetTimer(hDlg, GAME_STATUS_TIMER, 1000, NULL);
return TRUE;
}
case WM_TIMER:
switch (wParam) {
case GAME_STATUS_TIMER:
if (Mem->FindProcess()) {
SetDlgItemTextW(hDlg, GAME_CURRENT_STATUS_LBL, L"Open");
IsGameOpen = true;
} else {
SetDlgItemTextW(hDlg, GAME_CURRENT_STATUS_LBL, L"Closed");
IsGameOpen = false;
}
break;
}
return TRUE;
case WM_CTLCOLORSTATIC:
{
if ((HWND)lParam == GetDlgItem(hDlg, GAME_CURRENT_STATUS_LBL)) {
if (IsGameOpen) {
SetTextColor((HDC)wParam, RGB(29, 122, 9));
return (BOOL)GetSysColorBrush(COLOR_MENU);
} else {
SetTextColor((HDC)wParam, RGB(176, 12, 12));
return (BOOL)GetSysColorBrush(COLOR_MENU);
}
}
break;
}
}
return FALSE;
}
What's wrong with my code that makes the program take a little noticeable time between changing the text and its color?
As stated in comments, the Static control is likely being repainted immediately, and thus sending WM_CTLCOLORSTATIC to you, while SetDlgItemTextW() is being processed, but you haven't updated your IsGameOpen variable yet, so the new color doesn't take effect until the next time the Static control has to be repainted.
Try this instead:
case GAME_STATUS_TIMER:
IsGameOpen = Mem->FindProcess();
SetDlgItemTextW(hDlg, GAME_CURRENT_STATUS_LBL, IsGameOpen ? L"Open" : L"Closed");
break;
LRESULT handleDoubleClicks(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, POINT ptLastClickPos, DWORD dwLastClickTime)
{
DWORD dwClickTime = GetMessageTime();
POINT ptClickPos = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
switch(message)
{
case WM_LBUTTONDOWN:
if (dwLastClickTime + GetDoubleClickTime() > dwClickTime
&& abs(ptLastClickPos.x - ptClickPos.x) < GetSystemMetrics(SM_CXDOUBLECLK)
&& abs(ptLastClickPos.y - ptClickPos.y) < GetSystemMetrics(SM_CYDOUBLECLK))
{
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
else
{
dwLastClickTime = dwClickTime;
ptLastClickPos = ptClickPos;
wchar_t waCoord[20];
wsprintf(waCoord, _T("(%i,%i)"), ptLastClickPos.x, ptLastClickPos.y);
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
This is function i have made to handle double click:
This function is called when windows recieve WM_LBUTTONDOWN it will take the time of the message and coordinate of the click and will transfer it to the function here i want the fuction to recieve another message WM_LBUTTONDOWN and determine the time of the message and compare with the previous click time and the co ordinates to identify if it is a double click.
But this is not working .May be I am Wrong with the approach I am newbie Pls help me to solve this problem.
case WM_LBUTTONDOWN:
{
dwLastClickTime= GetMessageTime();
// SetTimer(hWnd,0,GetDoubleClickTime(),0);
ptLastClickPos.x = LOWORD(lParam);
ptLastClickPos.y = HIWORD(lParam);
handleDoubleClicks(hWnd, message, wParam, lParam, ptLastClickPos, dwLastClickTime);
}
You could use SetTimer, after one click, not immediately judge it as a click, but start the timer, check whether there is another click within the timer range, if there is, it is judged as double-click, if not, and the previous time is determined as a single click.
#define TIMER_ID 10
static int click_count = 0;
static POINT point = { 0 };
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_TIMER:
{
KillTimer(hWnd, TIMER_ID);
if (click_count == 1)
{
wchar_t waCoord[20];
wsprintf(waCoord, _T("(%i,%i)"), point.x, point.y);
MessageBox(hWnd, waCoord, _T("Left mouse button click"), MB_OK);
}
else if(click_count == 2)
{
MessageBox(hWnd, TEXT("Double click"), TEXT("I appear when double clicked"), MB_OKCANCEL);
}
else if (click_count == 3)
{
MessageBox(hWnd, TEXT("Triple click"), TEXT("I appear when triple clicked"), MB_OKCANCEL);
}
click_count = 0;
return 0;
}
break;
case WM_LBUTTONDOWN:
{
if (click_count == 0)
{
SetTimer(hWnd, TIMER_ID, GetDoubleClickTime(), NULL);
}
click_count++;
return 0;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
And make sure your window doesn't have CS_DBLCLKS style. Otherwise, the second WM_LBUTTONDOWN message that would normally be generated becomes a WM_LBUTTONDBLCLK message, according to the document: Double Clicks
The focus event on the combo box is generated twice.
this is the code for the Action Procedure of the Dialog box.
INT_PTR DialogBox::ActionProc(
HWND hwndDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case COMBOBOX:
{
if (CBN_SETFOCUS == HIWORD(wParam))
{
MessageBox(
hwndDlg,
CString("Test"),
CString("Test"),
(MB_ICONEXCLAMATION | MB_OK));
}
break;
}
default:
break;
}
break;
}
default:
break;
}
return INT_PTR(true);
}
the MessageBox Gets displayed twice(because the focus event is generated twice on the combo box). Is there a way to display it only once.
I have tried focussing to another element such as:
INT_PTR DialogBox::ActionProc(
HWND hwndDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch (message)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case COMBOBOX:
{
if (CBN_SETFOCUS == HIWORD(wParam))
{
MessageBox(
hwndDlg,
CString("Test"),
CString("Test"),
(MB_ICONEXCLAMATION | MB_OK));
SendDlgItemMessage(
hwndDlg,
ANOTHER_CONTROL,
WM_SETFOCUS,
0,
0);
}
break;
}
default:
break;
}
break;
}
default:
break;
}
return INT_PTR(true);
}
Can some one tell me what i am doing wrong.
This is in Windows Desktop API.
I've created a formview using the Visual Studio resource editor but I can't get it to show.
The procedure to handle it's messages is this:
BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDC_BUTTONCancel:
EndDialog(hDlg,0);
return TRUE;
}
break;
}
return FALSE;
}
When a button is pressed in the main window I call:
DialogBox(hInst, MAKEINTRESOURCE(IDD_FORMVIEW), hwnd, (DLGPROC)DlgProc);
The main window freezes, but there is no dialog shown.
I'd appreciate some help. Thanks in advance.
I am doing a voice chat application which uses a push-to-talk key. I have done a hook so it will register push-to-talk outside application too.
HHOOK hHook = SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)pushtotalk,0,0);
LRESULT CALLBACK pushtotalk(int key, WPARAM wParam,LPARAM lParam) {
if (key < 0) {
return (CallNextHookEx(hook,key,wParam,lParam));
}
else if (connected) {
KBDLLHOOKSTRUCT* kbdll = (KBDLLHOOKSTRUCT*)lParam;
if (kbdll ->vkCode == 75 && wParam == WM_KEYDOWN) {
MessageBox(mainhWnd,"KEYSTART","KEYSTART",0);
}
else if (kbdll ->vkCode == 75 && wParam == WM_KEYUP) {
MessageBox(mainhWnd,"KEYSTOP","KEYSTOP",0);
}
}
return (CallNextHookEx(hook,key,wParam,lParam));
}
Problems;
1) Sometimes, (for example the first execution of the proc in the application), the proc causes a 5 sec system freeze before continuing. Why?
2) The hook only works on process that were started before my application started, if I start a text program after starting my application, the hooks wont register. Is there a fix for this?
3) If I hold down the key for ~3 seconds, alot of MessageBoxes shows obviously, but after that, the proc will never register another key being pushed down, so I guess I somehow gets disconnected from the hook chain?
Cheers
EDIT: Here's the main message loop for the application
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
case WM_COMMAND:
switch (LOWORD(wParam)) {
case ID_MENU_EXIT:
SendMessage(hWnd,WM_CLOSE,0,0);
break;
case ID_MENU_PREFERENCES:
voiceManager->send((void*) "1");
break;
case ID_BUTTON_CONNECT:
onConnect(hWnd);
break;
case ID_BUTTON_DISCONNECT:
onDisconnect(hWnd);
break;
case ID_BUTTON_SEND:
onSendText(hWnd);
break;
default:
break;
}
break;
case SOCKET_TCP:
switch (lParam) {
case FD_READ:
{
// Disable repeated FD_READ call while we process message
WSAAsyncSelect(wParam,hWnd,SOCKET_TCP, FD_WRITE | FD_ACCEPT | FD_CLOSE);
// first four bytes is packet size
// second four bytes are used to identify type of msg
char* psize = (char*)malloc(5);
char* ptype = (char*)malloc(5);
psize[4] = '\0';
ptype[4] = '\0';
recv(wParam,psize,4,0);
recv(wParam,ptype,4,0);
// allocate memory for the buffer
int size_to_recv = atoi(psize);
char* textbuff = (char*)malloc(size_to_recv);
// receive
int i = size_to_recv;
while (i > 0) {
int read = recv(wParam,textbuff,i,0);
i = i - read;
}
// handle msg depending on type
switch(identifyMsg(ptype)) {
case 1:
// handle 'text' msg
onReadText(hWnd,textbuff);
break;
case 2:
// handle 'name' msg
onReadName(hWnd,textbuff);
break;
case 3:
// handle 'list' msg
onReadList(hWnd,textbuff);
break;
case 4:
// handle 'remv' msg
onReadRemv(hWnd,textbuff,size_to_recv);
break;
case 5:
// handle 'ipad' msg -- add ip
voiceManager->addParticipant(inet_addr(textbuff));
break;
case 6:
// handle 'iprm' msg -- remove ip
voiceManager->removeParticipant(inet_addr(textbuff));
break;
default:
break;
}
// re-enable FD_READ
WSAAsyncSelect(wParam,hWnd,SOCKET_TCP, FD_WRITE | FD_ACCEPT | FD_READ | FD_CLOSE);
// free resources
free(psize);
free(ptype);
free(textbuff);
break;
}
case FD_WRITE:
break;
case FD_CONNECT:
break;
case FD_CLOSE:
onDisconnect(hWnd);
break;
default:
break;
}
break;
case WM_PAINT:
paintText(hWnd);
break;
case WM_DESTROY:
shutdownConnection(hWnd);
// reset window procs
SetWindowLong(GetDlgItem(hWnd,ID_EDIT_SEND), GWL_WNDPROC,(LONG) OriginalEditProc);
SetWindowLong(GetDlgItem(hWnd,ID_EDIT_IP), GWL_WNDPROC,(LONG) OriginalEditProc);
PostQuitMessage(0);
return 0;
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
default:
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
LRESULT CALLBACK sendEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == WM_CHAR) {
if (wParam == VK_RETURN) {
onSendText(GetParent(hWnd));
return 0;
}
}
if (message == WM_KEYUP || message == WM_KEYDOWN) {
if (wParam == VK_RETURN) {
return 0;
}
}
return CallWindowProc(OriginalEditProc, hWnd, message, wParam,lParam);
}
Where sendEditProc is a sub/superclass designed to intercept 'enter' keys when inside an edit control 'send'
Does this help?
Here's the message loop; it's the standard so nothing fancy that could go wrong afaik :)
while (GetMessage(&msg, NULL,0,0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
You're calling CallNextHookEx one too many times. If key < 0 return CallNextHookEx, otherwise return 0.
The problem you're seeing has to do with keyboard repeats and the MessageBox or MessageBeep methods being very, very expensive calls. Try this test:
HHOOK hHook;
BOOL bTalkEnabled = FALSE;
LRESULT CALLBACK pushtotalk(int key, WPARAM wParam, LPARAM lParam)
{
if (key < 0)
return CallNextHookEx(hHook, key, wParam, lParam);
KBDLLHOOKSTRUCT* kbdll = (KBDLLHOOKSTRUCT*)lParam;
if (kbdll->vkCode == VK_F11)
{
BOOL bStarted = FALSE;
BOOL bStopped = FALSE;
if (wParam == WM_KEYDOWN)
{
if (!bTalkEnabled)
{
bStarted = TRUE;
bTalkEnabled = TRUE;
}
}
else if (wParam == WM_KEYUP)
{
if (bTalkEnabled)
{
bStopped = TRUE;
bTalkEnabled = FALSE;
}
}
if (bStarted)
OutputDebugString(L"Pushed\r\n");
if (bStopped)
OutputDebugString(L"Released\r\n");
}
return 0;
}
You can monitor the debug strings by running the app under the debugger (check the Output window), or you can get DebugView and watch that.
Notice that I do not check for connected as you did. You don't want to perform that check in the hook, do that outside the hook and only use the hook to determain if the key is pressed or not pressed.