Jump to content
Tuts 4 You

[win32 api] trayicon conflicts with edit box's <enter> key


alaphate

Recommended Posts

233d0a9b.jpg

I can calculate the result by pressing <enter>,

however, It will doesn't work after I click the application's tray icon.

Thanks a lot, my buddies

Attachment is my project.

Below is my source code.

#include <windows.h>
#include <stdio.h>
#include "resource.h"HINSTANCE hInst;
NOTIFYICONDATA nid;
bool isMin = false;BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
char szBuf[15];
double a, b, result; switch(message) {
case WM_INITDIALOG:
//create tray icon
nid.cbSize = sizeof(nid);
nid.hIcon = LoadIcon(hInst, "MYICON");
nid.uCallbackMessage = WM_USER + 1;
nid.hWnd = hwnd;
nid.uID = WM_USER + 2;
strcpy(nid.szTip, "System Tray Icon");
nid.uFlags = NIF_TIP | NIF_ICON | NIF_MESSAGE;
Shell_NotifyIcon(NIM_ADD, &nid);
return 0;
case WM_COMMAND:
switch LOWORD(LOWORD(wParam)) {
case IDOK: //calculate the result
GetDlgItemText(hwnd, ID_A, szBuf, 15);
a = atof(szBuf);
GetDlgItemText(hwnd, ID_B, szBuf, 15);
b = atof(szBuf);
result = a + b;
if(result) {
sprintf(szBuf, "%.2f", result);
SetDlgItemText(hwnd, ID_RESULT, szBuf);
}
return 0;
case IDCANCEL:
break;
case IDEXIT:
DestroyWindow(hwnd);
break;
}
return 0;
case WM_DESTROY:
//delete tray icon
Shell_NotifyIcon(NIM_DELETE, &nid);
EndDialog(hwnd, 0);
return 0;
}
return 0;
}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow) {
hInst = hInstance;
DialogBox(hInst, "ABOUTBOX", NULL, DlgProc);
return 0;
}

trayicon.zip

Link to comment

Hi, nearly there just need a few changes.

Next, add these to your DlgProc

// ------- part 1 ---------------- Handle the mouse when it's over our tray-icon ---------------
//
case WM_USER+1:
SetForegroundWindow(hwnd);
switch ( lParam ) {
case WM_MOUSEMOVE:
// OnTrayIconMouseMove( hWnd );
return 0; case WM_RBUTTONUP:
//OnTrayIconRBtnUp( hWnd );
DestroyWindow(hwnd);
return 0; case WM_LBUTTONDBLCLK:
//OnTrayIconLBtnDblClick( hWnd );
PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, NULL);
return 0;
}
return 0; // ------ part 2 -------------- Make the [X]-(close) button work correctly --------------
//
case WM_CLOSE:
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nid);
EndDialog(hwnd, 0);
return 0;
// ---- part 3 --- Add/Remove the tray icon when we minimize/restore the app ------------------
//
// First, remove "Shell_NotifyIcon(NIM_ADD, &nid)" from WM_INITDIALOG, since the app starts
// visible you probably don't want a tray-icon yet. We don't need to add the tray-icon at startup
// if we handle it whenever the window is minimized/restored
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_MINIMIZE:
Shell_NotifyIcon(NIM_ADD, &nid);
break; case SC_RESTORE:
Shell_NotifyIcon(NIM_DELETE, &nid);
break;
}
break;

Double L click restores program, single R click kills program.

I'll leave it to ya to make program title dissapear from the task-bar whenever the tray-icon is shown. :thumbsup:

moddedCode.zip

Link to comment

I guess when you click the tray icon the calculate button loses the focus, hitting enter wont push the button anymore.

Either make it the default button or try catching keyboard input in your dialog proc, dunnno if it can be done with WM_CHAR or WM_KEYDOWN and VK_ENTER.

As a sidenote, I think EndDialog should be called on WM_CLOSE instead of WM_DESTROY

Link to comment

thx for replying

when caret is in the edit box, I hit <enter>, it will invoke the default button and calculate the result.

however, after i clicked the tray icon, the <tab> key works fine

while the <enter> key cannot invoke the default push button when the caret is in edit box!!

I know one way to solve this problem is to override edit box's wndproc.

Is there another way to tackle this problem?

Link to comment
enhzflep,

thx for adding functions to my code :)

No worries mate. Sorry I misunderstood your question. You just have to

keep track of who had focus when you minimized and then give it back to them

when you restore the window. Just need a static var + a line each to get/set.

Just add these changes

		case WM_SYSCOMMAND:
static HWND focusHwnd;
switch (wParam)
{
case SC_MINIMIZE:
focusHwnd = GetFocus();
Shell_NotifyIcon(NIM_ADD, &nid);
break; case SC_RESTORE:
Shell_NotifyIcon(NIM_DELETE, &nid);
SetFocus(focusHwnd);
break;
}
break;
As a sidenote, I think EndDialog should be called on WM_CLOSE instead of WM_DESTROY

Guilty as charged. I figured it didn't matter in this case - but it's a bad habit in any case. Sorry

Link to comment

enhzflep,

I tried the changes, but it didn't solve my problem.

for example:

Before I clicked the tray icon, I input 32 + 32, then press <enter>, I got the result 64

but after I clicked the tray icon, I input 32 + 30, then press <enter>, I still got the result 64

because the <enter> key didn't invoke my calculation.

Edited by alaphate
Link to comment
enhzflep,

I tried the changes, but it didn't solve my problem.

for example:

Before I clicked the tray icon, I input 32 + 32, then press <enter>, I got the result 64

but after I clicked the tray icon, I input 32 + 30, then press <enter>, I still got the result 64

because the <enter> key didn't invoke my calculation.

Ah, of course - I only tried to return app by clicking on task-bar icon, not on tray icon. What a silly duffer I was.

I've just been playing with Winspector (windows message spy like Spy++), and it suddenly occured to me that if the application is returned from the system tray using the tray icon, that certain window messages were no longer being passed.

There were 5 WM_COMMAND messages sent in a row, but specifically the first message:

WM_COMMAND

Code: BN_CLICKED

Control ID: 1

Control HWND: 0x00bb0312

When I minimized the app and then restored it with a tray-icon click, I noticed that the above message was no longer sent.

The first WM_COMMAND message now sent was:

WM_COMMAND

Code: 0

Control ID: 1026

Control HWND: 0x000000

Around this time, I remembered that WM_USER = 1024. Somewhere in the code I recalled seeing something like WM_USER+2, so I went to that line and changed it to IDOK and recompiled. As for the result, I can happily report that that was the source of the issue.

Along the way I cleaned up the code a little, added a new trick or two and added some comments to help explain the expected return values from a DialogProc or WindowProc - you should return 0 if a message is NOT handled, or a non-zero value if the message has been handled and you don't want windows to process it.

I forget what prompted me to review them now, though you can get funky results if you return the wrong thing. The strange thing is, that I've only ever seen reference to ensuring that a non-zero value is returned when handling the WM_PAINT message. Failing to do so ensures that windows paints straight over the top of your work - believing that the window is undrawn and needs attention.

Great question - amongst other things I managed to learn how to remove a task-bar icon for an app that's been minimized to the system tray. :thanks:

See atachment for code & binary.

[EDIT] Using VS2008 express just this minute, but dunno how to tell VS to use XP themes. If edit the executable after compilation and change the Manifest data to the data contained in 012.Manifest, you'll get nice buttons with gradients & coloured highlighting.

moddedCode_mkII.zip

Edited by enhzflep
Link to comment

Awesome! It's the best solution.

The code you proded is easy understood, thanks a lot.

I leaned how to debug my app from you :)

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...