I'm trying to use win32api on user32.dll to get mouse wheel input.
I tried the following:
#state = Win32API.new('user32','DefWindowProc',['i'],'i')
p #state.call(0x0800)
But it keeps returning 0 no matter what I do with my mouse wheel.
I thought something is wrong with my mouse, so I tried to do:
#state = Win32API.new('user32','GetKeyState',['L'],'L')
p #state.call(0x01) #left key
p #state.call(0x02) #right key
It worked, so I'm not sure what's wrong with the mouse wheel.
Regards
Edit 2/20/2014:
I tried to do the following:
GetActiveWindow = Win32API.new('user32','GetForegroundWindow','','i')
DefWindowProc = Win32API.new('user32','DefWindowProc','iiii','i')
DefWindowProc.call(GetActiveWindow.call,
Then, I got stuck with the UINT / Message (2nd argument).
Edit 2/20/2014:
I found the WM_MOUSEWHEEL message
Latest revision:
GetActiveWindow = Win32API.new('user32','GetForegroundWindow','','i')
DefWindowProc = Win32API.new('user32','DefWindowProc','iiii','i')
#WM_MOUSEWHEEL message 0x020A
DefWindowProc.call(GetActiveWindow.call, 0x020A,
Now I just need to figure out the 3rd and 4th argument.
As I don't know Ruby, I will give here a solution in C/C++ using only standard Win32 APIs. If you can call Win32 APIs from Ruby, that will work.
Note that the solution involves "callback" and "pointer". I know that's possible in Python (for example, with the ctypes module) and hope that same thing is possible with Ruby.
Register a Window Class and create a Window from that class, the window will be a Message-Only Window, so it will be invisible, with no GUI.
Use the RegisterRawInputDevices API to ask for raw events from mouse devices.
Set up a message loop, with the standard GetMessage/DispatchMessage combo.
Process the sent WM_INPUT message in your Window Procedure
4.1. Allocate memory for the raw datas
4.2. Retrieve the raw datas
4.3. Filter for mouse event and wheel datas
4.4. Process (I just print the wheel delta)
4.5. Free allocated memory.
Below, full source code. Build with VS2012 Express on Windows 7.
#include <Windows.h>
#include <stdio.h>
LRESULT CALLBACK MyWindowProc( HWND, UINT, WPARAM, LPARAM );
int main( void ) {
WNDCLASS WndClass;
memset( &WndClass, 0, sizeof( WndClass ) );
WndClass.hInstance = GetModuleHandle( NULL );
WndClass.lpszClassName = L"MyRawInputClass";
WndClass.lpfnWndProc = MyWindowProc;
RegisterClass( &WndClass );
HWND hWnd = CreateWindow( WndClass.lpszClassName, NULL, 0, 0, 0, 0, 0,
HWND_MESSAGE, 0, WndClass.hInstance, 0 );
RAWINPUTDEVICE RawInputDevice;
RawInputDevice.usUsagePage = 0x01; // Generic Desktop Controls
RawInputDevice.usUsage = 0x02; // Mouse
RawInputDevice.dwFlags = RIDEV_INPUTSINK;
RawInputDevice.hwndTarget = hWnd;
BOOL bWin32Success = RegisterRawInputDevices( &RawInputDevice, 1,
static_cast<UINT>( sizeof( RAWINPUTHEADER ) ) );
BOOL bRet;
MSG msg;
while( ( bRet = GetMessage( &msg, hWnd, 0, 0 ) ) != 0 ) {
if (bRet != -1) {
DispatchMessage(&msg);
}
}
// NO GUI, UNREACHABLE
DestroyWindow( hWnd );
UnregisterClass( WndClass.lpszClassName, WndClass.hInstance );
return 0;
}
LRESULT CALLBACK MyWindowProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam ) {
switch ( uiMsg ) {
case WM_INPUT: {
UINT dwSize;
HRAWINPUT hRawInput = reinterpret_cast<HRAWINPUT>( lParam );
UINT uiRetCode = GetRawInputData( hRawInput, RID_INPUT, NULL, &dwSize,
static_cast<UINT>( sizeof( RAWINPUTHEADER ) ) );
if ( uiRetCode != 0xffffffff ) {
LPBYTE lpb = new BYTE[ dwSize ];
uiRetCode = GetRawInputData( hRawInput, RID_INPUT, lpb, &dwSize,
static_cast<UINT>( sizeof( RAWINPUTHEADER ) ) );
if ( uiRetCode > 0 ) {
RAWINPUT* praw = reinterpret_cast<RAWINPUT*>( lpb );
if ( praw->header.dwType == RIM_TYPEMOUSE ) {
if ( praw->data.mouse.usButtonFlags & RI_MOUSE_WHEEL ) {
signed int siDelta = static_cast<SHORT>( praw->data.mouse.usButtonData );
printf( "WHEEL EVENT: Delta = %d\n", siDelta );
}
}
}
delete[] lpb;
}
break;
} // WM_INPUT
default:
return DefWindowProc( hWnd, uiMsg, wParam, lParam );
}
return 0;
}
Related
I'm trying to make a screenshot helper that takes screenshots when it receives signal from other application. In my design, the higher layer application will send a window message to the helper, and the helper will then take a screenshot for user (by simulating Win+Prtsc). I've done this without any problem, but when I try to add a feature that implements by detecting the gap between two message, I found that GetMessageTime() function works weird.
The problem is that I added a MessageBox for debugging, and GetMessageTime returns the proper ticks the message was sent at. But when I removed that MessageBox, GetMessageTime kept returning 0. I searched the web and MSDN documents but found nothing about this. So I'm just wondering what happened and what should I do, without changing the architecture that using HWND_MESSAGE window to receive message.
MessageReceiver
#include <Windows.h>
#include <stdio.h>
HWND hwndMain;
UINT hotkeyTriggeredMessageId;
INPUT winPlusPrtscKeyCombo[4];
LONG lastHotkeyTime = -1000;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
if (message == hotkeyTriggeredMessageId) {
printf("last:%d,this:%d,diff:%d\n", lastHotkeyTime, GetMessageTime(), lastHotkeyTime - GetMessageTime());
MessageBox(NULL, L"triggered!", L"", NULL);
printf("last:%d,this:%d,diff:%d\n", lastHotkeyTime, GetMessageTime(), lastHotkeyTime - GetMessageTime());
SendInput(4, winPlusPrtscKeyCombo, sizeof(INPUT));
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int main() {
MSG msg;
BOOL bRet;
WNDCLASS wc = { 0 };
memset(winPlusPrtscKeyCombo, 0, sizeof(INPUT) * 4);
winPlusPrtscKeyCombo[0].type = INPUT_KEYBOARD;
winPlusPrtscKeyCombo[0].ki.wVk = VK_LWIN;
winPlusPrtscKeyCombo[1].type = INPUT_KEYBOARD;
winPlusPrtscKeyCombo[1].ki.wVk = VK_SNAPSHOT;
winPlusPrtscKeyCombo[2].type = INPUT_KEYBOARD;
winPlusPrtscKeyCombo[2].ki.wVk = VK_SNAPSHOT;
winPlusPrtscKeyCombo[2].ki.dwFlags = KEYEVENTF_KEYUP;
winPlusPrtscKeyCombo[3].type = INPUT_KEYBOARD;
winPlusPrtscKeyCombo[3].ki.wVk = VK_LWIN;
winPlusPrtscKeyCombo[3].ki.dwFlags = KEYEVENTF_KEYUP;
HINSTANCE hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.hInstance = hInstance;
wc.lpszClassName = L"MessageReceiverWindow";
if (!RegisterClass(&wc)) {
return FALSE;
}
hwndMain = CreateWindow(L"MessageReceiverWindow", L"MessageReceiverWindow", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInstance, 0);
hotkeyTriggeredMessageId = RegisterWindowMessage(L"MESSAGE_HOTKEY_TRIGGERED");
ChangeWindowMessageFilterEx(hwndMain, hotkeyTriggeredMessageId, MSGFLT_ALLOW, NULL);
UpdateWindow(hwndMain);
while (GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
return 0;
}
MessageSender
#include <stdio.h>
#include <Windows.h>
UINT hotkeyTriggeredMessageId;
HWND targetWindow;
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) {
hotkeyTriggeredMessageId = RegisterWindowMessage(L"MESSAGE_HOTKEY_TRIGGERED");
targetWindow = FindWindowEx(HWND_MESSAGE, NULL, L"MessageReceiverWindow", NULL);
SendMessage(targetWindow, hotkeyTriggeredMessageId, NULL, NULL);
return 0;
}
I can't understand why I got a loop on BeginPaint function. I have already read posts about this kind of loop but almost all of them recommend: "Don't forget to use BeginPaint function on WM_PAINT message, because it entails subsequent WM_PAINT messages otherwise". This isn't my case. May you give me some advices?
This is my windowclass ("CWindow"):
class CWindow {
public:
CWindow();
virtual ~CWindow();
bool RegisterClass(HINSTANCE hInstance);
bool CreateWnd(HINSTANCE hInstance);
bool Show(int nShow);
private:
HWND handleWindow;
ATOM atom;
bool isRegistered;
bool isCreated;
static LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void OnPaint();
void OnDestroy();
};
WndProc function.
LRESULT CALLBACK CWindow::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
CWindow* windowPtr = reinterpret_cast<CWindow*> ( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
PAINTSTRUCT ps;
HDC hdc;
switch( msg ) {
case WM_PAINT:
// There is a loop right here!
hdc = BeginPaint( windowPtr->handleWindow, &ps );
// The code below doesn't executed!
RECT rect;
(void)GetClientRect(windowPtr->handleWindow, &rect);
(void)DrawText(hdc, TEXT("Hello, Windows 98!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint( windowPtr->handleWindow, &ps );
break;
case WM_DESTROY:
windowPtr->OnDestroy();
break;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
RegisterClass
bool CWindow::RegisterClass(HINSTANCE hInstance)
{
const TCHAR app_name[] = TEXT("HelloWin");
WNDCLASSEX windowClass;
ZeroMemory( &windowClass, sizeof(windowClass) );
windowClass.cbSize = sizeof(windowClass);
windowClass.style = CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = WindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = 0;
windowClass.hIcon = 0;
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hbrBackground = 0;
windowClass.lpszMenuName = NULL;
windowClass.lpszClassName = app_name;
windowClass.hIconSm = NULL;
atom = RegisterClassEx( &windowClass );
DWORD errorCode = GetLastError();
if( errorCode ) {
isRegistered = 0;
std::wcout << L"ErrorCode: " << errorCode << std::endl;
} else {
isRegistered = 1;
}
return isRegistered;
}
CreateWindow
bool CWindow::CreateWnd(HINSTANCE hInstance)
{
handleWindow = CreateWindow((PCTSTR)atom, // window class name or atom
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
DWORD errorCode = GetLastError();
if( !handleWindow ) {
isCreated = 0;
} else {
isCreated = 1;
}
return isCreated;
}
Show
bool CWindow::Show(int nShow)
{
if( isCreated ) {
ShowWindow( handleWindow, nShow );
return UpdateWindow( handleWindow );
} else {
return 0;
}
}
WinMain
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevINstance, LPSTR lpCmdLine, int nShow )
{
CWindow window;
window.RegisterClass( hInstance );
window.CreateWnd( hInstance );
window.Show( nShow );
int response = 0;
MSG msg;
while( GetMessage( &msg, 0, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return 0;
}
Since you never call SetWindowLongPtr,
CWindow* windowPtr = reinterpret_cast<CWindow*>( GetWindowLongPtr( hWnd, GWLP_USERDATA ) );
returns a nullptr, that you subsequently try to dereference:
BeginPaint( windowPtr->handleWindow, &ps )
That will trigger an access violation exception, causing the BeginPaint call to never even get executed, leaving the invalid region as is. As a consequence, the system keeps generating WM_PAINT messages. That's the same issue as not calling BeginPaint altogether.1
To solve this, you'll either have to attach the window handle to the window instance by calling SetWindowLongPtr, or simply use the hWnd parameter that's passed into your CWindow::WindowProc.
1 Note that the system silently handles unhandled exceptions in your WindowProc on 64-bit versions of Windows under certain conditions.
I'm using MS visual c++ 2010 express to write a notepad program. I need to be able to save files from my tabbed interface ( each edit control is stored into a vector ). I can't seem to figure out how to save, depending on which edit control is visible to the user ( active tab ). Everything I've tried so far either doesn't save the contents or only saves from the first edit control. When the user adds a new file to the tabbed interface, it added that edit control to the back of the vector. This is my latest attempt:
std::vector<HWND>vect;
BOOL SaveTextFileFromEdit( HWND hEdit, LPCTSTR pszFileName )
{
HANDLE hFile;
BOOL bSuccess = FALSE;
hFile = CreateFile( pszFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if( hFile != INVALID_HANDLE_VALUE )
{
DWORD dwTextLength = GetWindowTextLength( hEdit );
if( dwTextLegth > 0 )
{
DWORD dwBufferSize = dwTextLength + 1;
LPSTR pszText = ( LPSTR )GlobalAlloc( GPTR, dwBufferSize );
if( pszText != NULL )
{
if( GetWindowText( hEdit, pszText, dwBufferSize ) )
{
DWORD dwWritten;
if( WriteFile( hFile, pszText, dwTextLength, &dwWritten, NULL ) )
bSuccess = TRUE;
}
GlobalFree( pszText );
}
}
CloseHandle( hFile );
}
return bSuccess;
}
LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
case WM_COMMAND:
switch( LOWORD( wParam ) )
{
case ID_FILE_SAVEAS:
{
OPENFILENAME ofn;
char szFileName[ MAX_PATH ] = "";
ZeroMemory( &ofn, sizeof( ofn ) );
ofn.lStructSize = sizeof( ofn );
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
ofn.lpstrFile = szFileName;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrDefExt = "txt";
ofn.flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
if( GetSaveFileName( &ofn ) )
{
HWND hEdit, hTabs;
hTabs = GetDlgItem( hwnd, IDC_MAIN_TAB );
int curTab = TabCtrl_GetCurSel( hTabs );
hEdit = GetDlgItem( hTabs, IDC_MAIN_EDIT );
// This is what i did have: hEdit = GetDlgItem( vect[ curTab ], IDC_MAIN_EDIT );
// Which wasn't saving anything
if( SaveTextFileFromEdit( hEdit, szFileName ) )
{
// EVERYTHING IS GOOD
}
}
}
break;
}
break;
}
return 0;
}
If the vector has each edit control's HWND then you don't need GetDlgItem at all: You already have the HWND that it would return.
hEdit = vect[ curTab ];
I need to hookup alt+alphanumberic keypress inside a child window control.
I have written this program to test it's functionality. But it seems it does not response to keystrokes
like ALT+X , ALT+X which are necessary for my application(keyboard translator).
#include <windows.h>
#include <stdio.h>
#include <wchar.h>
#include <tchar.h>
#include <string.h>
#ifndef NULL
#define NULL 0
#endif
/* glaobal variables */
HWND hwndEdit = NULL;
HWND hwndWindow = NULL;
WCHAR* lpszClassName = L"Vijesekara Keyboard Test Application";
WCHAR* lpszAppName = L"Vijesekara Keyboard Test Application";
int main_window_width = 0;
int main_window_height = 0;
WNDPROC edit_old_wndproc;
/*
GWL_WNDPROC
*/
#ifndef GWL_WNDPROC
#define GWL_WNDPROC (-4)
#endif
/* child window ID's */
#ifndef __CHILD_WINDOW_EDIT_ID__
#define __CHILD_WINDOW_EDIT_ID__
#define ID_EDIT 2000
// :TODO: more comes from here //
#endif
/* constrains on child window positions */
#ifndef __CHILD_WINDOW_POSITION__
#define __CHILD_WINDOW_POSITION__
#define EDIT_CHILD_LEFT_PRECENTAGE 0.05
#define EDIT_CHILD_RIGHT_PRECENTAGE 0.05
#define EDIT_CHILD_TOP_PRECENTAGE 0.10
#define EDIT_CHILD_BOTTOM_PRECENTAGE 0.10
// :TODO: Other controls //
#endif
/* main window procedure */
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam);
/* edit box procedure */
LRESULT CALLBACK EditBoxProc(HWND ,UINT , WPARAM , LPARAM );
/* resize child windows */
void ResizeChildWindows();
/* win main entry */
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW |CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.hInstance = hInstance ;
wndclass.hIcon = (HICON)LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor = (HCURSOR)LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground =(HBRUSH) GetStockObject( WHITE_BRUSH );
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = lpszClassName ;
/* Register class */
int result ;
result = RegisterClass( &wndclass) ;
/* if failed to register window */
if ( 0 == result )
{
MessageBox(NULL,L"Registering Window Have Been Failed" , lpszAppName, MB_OK);
exit(0);
}
/* Create the window */
hwndWindow = CreateWindow(lpszAppName , lpszAppName ,WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,\
CW_USEDEFAULT, CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
if(NULL == hwndWindow )
{
MessageBox(NULL,L"Window Creation have being failed", lpszAppName,MB_OK);
exit(0);
}
ShowWindow(hwndWindow, iCmdShow);
/* Enter message loop */
MSG msg ;
while(GetMessage(&msg,NULL, 0,0 ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
/* window procedure */
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_CREATE:
if( hwndEdit != NULL)
{
MessageBox(NULL,L"Edit control handle have already initialized",lpszAppName , MB_OK);
exit(0);
}
hwndEdit = CreateWindow( L"edit" ,NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL\
|WS_BORDER|ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL,0,0,0,0,hwnd,(HMENU)ID_EDIT\
,GetModuleHandle(NULL),NULL);
if( NULL == hwndEdit )
{
MessageBox(hwnd, L"Edit child window control creation failed", lpszAppName, MB_OK);
exit(0);
}
edit_old_wndproc = (WNDPROC)SetWindowLongPtr(hwndEdit,GWL_WNDPROC,(LONG_PTR)EditBoxProc );
break;
case WM_SIZE:
main_window_height = HIWORD(lParam);
main_window_width = LOWORD (lParam);
ResizeChildWindows();
return 0;
case WM_COMMAND:
/*:TODO:process */
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd,message,wParam,lParam);
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
/* resize window procedure */
void ResizeChildWindows()
{
MoveWindow(hwndEdit,main_window_width*EDIT_CHILD_LEFT_PRECENTAGE , main_window_height* EDIT_CHILD_TOP_PRECENTAGE , \
main_window_width * (1- EDIT_CHILD_LEFT_PRECENTAGE - EDIT_CHILD_RIGHT_PRECENTAGE) ,// height
main_window_height * (1- EDIT_CHILD_TOP_PRECENTAGE - EDIT_CHILD_BOTTOM_PRECENTAGE), TRUE // width
);
}
static int alt=0;
static int ctl=0;
static int sys =0;
WCHAR buffer[1024];
LRESULT CALLBACK EditBoxProc(HWND hwnd, UINT message, WPARAM wParam , LPARAM lParam)
{
switch ( message)
{
case WM_SYSCHAR:
sys =1;
if( lParam && (1<<29) ) { alt= 1;}
else {
alt=0;
}
case WM_KEYPRESS:
wsprintf( buffer,TEXT("KeyCode is :%d"), wParam);
MessageBox( NULL,buffer, TEXT("Vijesekara Keyboard"), MB_OK);
SetFocus(hwnd);
/* keyboard procedure */
alt =0;
if ( sys==1)
{
sys=0;
break;
}
return 0;
default:
break;
}
return CallWindowProc(edit_old_wndproc ,hwndEdit,message,wParam,
lParam);
}
// end of vijesekara_keyboard.cpp
Note: Inside the subclassed textbox , the WM_CHAR message is not working for the alt keystrokes, I it does
not sent a WM_CHAR message with alt key pressed to the for AlT+keystokes.So I log all the messages using spy++
and then I found WM_SYSCHAR have been sent instead of WM_CHAR for those messages inside a editbox child
window.
Any idea how could I do this?
--Thanks in advance--
Okay this is pretty strange,
This is my spy+ output for the Alt+A key.
So then I have hook the WM_SYSKEYUP message, and the Fixup is this,
case WM_SYSKEYUP:
if( lParam && (1<<29) ) {alt=1;}else{break;}
if( wParam == 'A' || wParam=='Z'|| wParam =='X' || wParam== 'W' || wParam == 'Y' ){}else{break;}
case WM_SYSCHAR:
sys =1;
if( lParam && (1<<29) ) { alt=1; }
else {
alt=0;
break;
}
case WM_CHAR:
wsprintf( buffer,TEXT("KeyCode is :%d"), wParam);
MessageBox( NULL,buffer, TEXT("Vijesekara Keyboard"), MB_OK);
SetFocus(hwnd);
/* keyboard procedure */
alt =0;
return 0;
And also when I break (calling the default window procedure) on WM_SYSKEYU it gives a nasty ding-dong sound
inside the Windows.I have return it then that sound disappear.
What arx claim is very strange. And Yes I have mistaken WM_KEYPRESS, there's no something called WM_KEYPRESS.
And It should be corrected to WM_CHAR. According to him without these chances MessageBox appears. That's
pretty strange. #Arx, you could please post your answer, so somebody else who digging it may benefit, and also
I could give you some credits too. And also dig why was that happened and after that we could accept that
and this answer would keep as an alternative answer (does not address the question, but have fixed the
application).
I am creating a system tray program with a shortcut/context menu, but I can't seem to receive WM_COMMAND messages in the Windows Procedure. It simply doesn't send when I click the menu item, and I've been checking for ages whether I have set up the menu correctly.
Here is my code:
#include <Windows.h>
#include <stdio.h>
#include "resource.h"
#define WM_TRAYICON (WM_USER + 0x0001) //a custom message for the notification icon
HWND hwnd; //window handle
HINSTANCE hinst; //module handle
WNDCLASSEX wnd; //window class
MSG msg; //event message or notification
NOTIFYICONDATA nid; //notification icon object
HMENU cmenu;
MENUITEMINFO menuitem1;
MENUITEMINFO menuitem2;
CURSORINFO cursor;
LRESULT CALLBACK MainWProc ( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
switch( uMsg )
{
case WM_COMMAND:
printf("asfd\r\n");
break;
case WM_CREATE:
printf("just created\r\n");
break;
case WM_TRAYICON:
switch( LOWORD(lParam) )
{
case WM_CONTEXTMENU:
GetCursorInfo( &cursor );
//printf("xPos: %d\r\nyPos = %d\r\n\r\n", xPos, yPos );
TrackPopupMenuEx( cmenu, TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_NOANIMATION | TPM_HORIZONTAL | TPM_VERTICAL, cursor.ptScreenPos.x, cursor.ptScreenPos.y, hwnd, NULL );
//DestroyMenu(
break;
}
break;
case WM_INITMENU:
printf("open menu\r\n");
break;
case WM_DESTROY:
//clean things up
Shell_NotifyIcon( NIM_DELETE, &nid );
break;
default:
break;
}
return DefWindowProc( hwnd, uMsg, wParam, lParam );
}
void main()
{
int result;
hinst = GetModuleHandle( NULL );
cursor.cbSize = sizeof( cursor );
memset( &wnd, 0, sizeof( wnd ) );
wnd.cbSize = sizeof( wnd );
wnd.lpszClassName = "MainWClass";
wnd.lpfnWndProc = MainWProc;
wnd.hInstance = hinst;
result = RegisterClassEx( &wnd );
hwnd = CreateWindowEx
(
0, //extended styles
wnd.lpszClassName, //class name
"Main Window", //window name
WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_MINIMIZEBOX, //style tags
CW_USEDEFAULT, //horizontal position
CW_USEDEFAULT, //vertical position
CW_USEDEFAULT, //width
CW_USEDEFAULT, //height
(HWND) NULL, //parent window
(HMENU) NULL, //class menu
(HINSTANCE) wnd.hInstance, //some HINSTANCE pointer
NULL //Create Window Data?
);
if( !hwnd )
{
printf("CreateWindowEx failed: %d\n", GetLastError() );
Sleep( INFINITE );
}
nid.cbSize = sizeof( nid );
nid.hWnd = hwnd;
nid.uID = 1;
nid.uVersion = NOTIFYICON_VERSION_4;
nid.uCallbackMessage = WM_TRAYICON;
nid.hIcon = LoadIcon( hinst, MAKEINTRESOURCE( IDI_ICON1 ) );
strcpy( nid.szTip, "My Tooltip!" );
nid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_SHOWTIP;
cmenu = CreatePopupMenu();
menuitem1.cbSize = sizeof( menuitem1 );
menuitem1.fMask = MIIM_TYPE;
menuitem1.fType = MFT_STRING;
menuitem1.hSubMenu = NULL;
//menuitem1.cch = ;
menuitem1.dwTypeData = "Open a world of wonder!";
InsertMenuItem( cmenu, 0, true, &menuitem1 );
if( ! Shell_NotifyIcon( NIM_ADD, &nid ) )
{
printf("Shell_NotifyIcon( NIM_ADD, &nid ) failed.\r\n");
Sleep( INFINITE );
}
if( ! Shell_NotifyIcon( NIM_SETVERSION, &nid ) )
{
printf("Shell_NotifyIcon( NIM_SETVERSION, &nid ) failed.\r\n");
Sleep( INFINITE );
}
UpdateWindow( hwnd );
for( ; ; )
{
if( GetMessage(&msg, hwnd, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
Um, you passed the TPM_RETURNCMD flag which means "don't post a WM_COMMAND message. Just return the value you would have posted."