Related
I'm learning win32 Programming. In order to better comprehend the concepts of the programming in win32 framework, So that I am going to write a simple calculator. I design its view but now I want when a user click on a button, for example button 1, Its number shows on a static label. I used SetDlgItemText, But it doesn't work. I put the picture of the program in the following:
I have 12 button with IDs IDC_Button01 to IDC_Button12 and I have a static label element with IDC_Display ID. I put my code in the following section.
#include <windows.h>
#include <tchar.h>
#include "resource.h"
#pragma comment(linker, \
"\"/manifestdependency:type='Win32' "\
"name='Microsoft.Windows.Common-Controls' "\
"version='6.0.0.0' "\
"processorArchitecture='*' "\
"publicKeyToken='6595b64144ccf1df' "\
"language='*'\"")
#pragma comment(lib, "ComCtl32.lib")
// Step 4: the Window Procedure
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
const char g_szClassName[] = "myWindowClass";
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HWND hDlg;
BOOL ret;
MSG msg;
hDlg = CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_MainWindow), 0, DialogProc, 0);
ShowWindow(hDlg, nCmdShow);
// Step 3: The Message Loop
while ((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
if (ret == -1) /* error found */
return -1;
if (!IsDialogMessage(hDlg, &msg)) {
TranslateMessage(&msg); /* translate virtual-key messages */
DispatchMessage(&msg); /* send it to dialog procedure */
}
}
return msg.wParam;
}
// Step 4: the Window Procedure
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL:
SendMessage(hDlg, WM_CLOSE, 0, 0);
return TRUE;
case IDOK:
MessageBox(hDlg, TEXT("Program will quit."), TEXT("Message"), MB_ICONQUESTION);
PostQuitMessage(0);
return TRUE;
}
break;
case IDC_BUTTON1:
SetDlgItemText(hDlg, IDC_Display, TEXT("1"));
case WM_CLOSE:
if (MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"), MB_ICONQUESTION | MB_YESNO) == IDYES)
{
DestroyWindow(hDlg);
}
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
The resource ID is not a valid Windows message, the WM_COMMAND is used to send a notification to a parent window
INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
..
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_BUTTON1: {
SetDlgItemText(hDlg, IDC_Display, TEXT("1"));
return TRUE;
} break;
break;
wParam is set to the control identifier.
I am trying to install global keyboard hook and on every DLL_PROCESS_ATTACH Notification try to subclass foreground window. I have separate exe and dll for both 64 bit and 32 bit application. I works ok if only one type (32 or 64 bit) exe and dll pair but not working for both at a time. I was not getting DLL_ATTACH_NOTIFICATION for 32 bit applications if I use 32 bit hook first and then 64 bit.Due to this i was unable to subclass 32 bit application.
sample code for DLL both for 32 and 64 bit with different name
`//#include "stdafx.h"
#include <tchar.h>
#include <process.h>
#pragma data_seg(".HOOKDATA")//Shared data among all instances.
HHOOK g_hKbdHook = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.HOOKDATA,RWS")//linker directive
#pragma data_seg(".HOOKDATA32")//Shared data among all instances.
HHOOK g_hKbdHook32 = NULL;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.HOOKDATA32,RWS")//linker directive
HINSTANCE g_hInstance = NULL;
HINSTANCE g_hInstance32 = NULL;
HWND hwndKeyFocused = NULL;
static HWND hwndOld;
static HWND hwndFocused;
static WNDPROC oldWindowProc;
BOOL APIENTRY
DllMain(
HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
DWORD dw;
int iRet;
HWND hwnd;
BOOL boIs32bit;
DWORD dwProcID;
HANDLE hProcess;
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
dwProcID = GetCurrentProcessId();
hProcess = OpenProcess(
PROCESS_VM_READ |
PROCESS_VM_WRITE |
PROCESS_VM_OPERATION |
PROCESS_CREATE_THREAD |
PROCESS_QUERY_INFORMATION,
FALSE,
dwProcID
);
IsWow64Process(
hProcess,
&boIs32bit
);
if (TRUE == boIs32bit)
{
g_hInstance32 = (HINSTANCE)hModule;;
}
else
{
g_hInstance = (HINSTANCE)hModule;
}
hwnd = GetForegroundWindow();
oldWindowProc =(WNDPROC) SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)HackingWndProc);
dw = GetLastError();
hwndOld = hwnd;
break;
case DLL_PROCESS_DETACH:
SetWindowLongPtr(hwndOld, GWLP_WNDPROC, (LONG_PTR)oldWindowProc );
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
}
g_hKbdHook = NULL;
return TRUE;
}
BOOLEAN __stdcall
Init(
)
{
g_hKbdHook = NULL;
g_hKbdHook = SetWindowsHookEx(WH_KEYBOARD, ProcessKey, g_hInstance, NULL);
if(g_hKbdHook==NULL)
{
return FALSE;
}
return TRUE;
}
BOOLEAN __stdcall
Init32(
)
{
g_hKbdHook32 = NULL;
g_hKbdHook32 = SetWindowsHookEx(WH_KEYBOARD, ProcessKey32, g_hInstance32, NULL);
if(g_hKbdHook32 == NULL)
{
return FALSE;
}
return TRUE;
}
BOOLEAN __stdcall
DeInit(
)
{
UnhookWindowsHookEx(g_hKbdHook);
if (NULL != g_hKbdHook32)
{
UnhookWindowsHookEx(g_hKbdHook32);
}
return TRUE;
}
LRESULT CALLBACK
ProcessKey(
int ncode,
WPARAM wparam,
LPARAM lparam
)
{
return (CallNextHookEx(g_hKbdHook, ncode, wparam, lparam));//pass control to next hook in the hook chain.
}
LRESULT CALLBACK HackingWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return CallWindowProc(
oldWindowProc,
hWnd,
message,
wParam,
lParam
);
}
LRESULT CALLBACK
ProcessKey32(
int ncode,
WPARAM wparam,
LPARAM lparam
)
{
return (CallNextHookEx(g_hKbdHook32, ncode, wparam, lparam));//pass control to next hook in the hook chain.
}
enter code here
`
I'm trying to handle mouse events on my screen(outside of client window). I use pure Win32 API.
I have created separate DLL with SetWindowHookEx function and reference this to my Win32 Application. But its handle only window event, and when mouse is outside of window or window is not active nothing happens.
//Hook.h
#ifndef _DEFINED_44E531B1_14D3_11d5_A025_006067718D04
#define _DEFINED_44E531B1_14D3_11d5_A025_006067718D04
#if _MSC_VER > 1000
#pragma once
#endif
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#ifdef _COMPILING_44E531B1_14D3_11d5_A025_006067718D04
#define LIBSPEC __declspec(dllexport)
#else
#define LIBSPEC __declspec(dllimport)
#endif // _COMPILING_44E531B1_14D3_11d5_A025_006067718D04
LIBSPEC BOOL InstallHook(HWND hWnd);
LIBSPEC BOOL UnInstallHook(HWND hWnd);
#undef LIBSPEC
#ifdef __cplusplus
}
#define UWM_MOUSEMOVE_MSG (L"UWM_MOUSEMOVE_USER_MSG")
#define UWM_MOUSELBUTTONUP_MSG ( L"UWM_MOUSELBUTTONUP_USER_MSG" )
#define UWM_MOUSELBUTTONDOWN_MSG ( L"UWM_MOUSELBUTTONDOWN_USER_MSG" )
#define UWM_MOUSERBUTTONUP_MSG ( L"UWM_MOUSERBUTTONUP_USER_MSG" )
#define UWM_MOUSERBUTTONDOWN_MSG ( L"UWM_MOUSERBUTTONDOWN_USER_MSG" )
#define UWM_MOUSELDBCLICK_MSG ( L"UWM_MOUSERBUTTONDOWN_USER_MSG" )
#endif // __cplusplus
#endif // _DEFINED_44E531B1_14D3_11d5_A025_006067718D04
//Hook.cpp
// Hook.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "Hook.h"
#pragma data_seg()
#pragma comment(linker, "/section:.Segment,rws")
HWND hWndServer = NULL;
UINT UWM_MOUSEMOVE;
UINT UWM_MOUSELBUTTONUP;
UINT UWM_MOUSELBUTTONDOWN;
UINT UWM_MOUSERBUTTONUP;
UINT UWM_MOUSERBUTTONDOWN;
UINT UWM_MOUSELDBCLICK;
HINSTANCE hInst;
//HWND hWndServer = NULL;
HHOOK hook;
static LRESULT CALLBACK MouseMsgProc(UINT nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)
{
CallNextHookEx(hook, nCode, wParam, lParam);
return 0;
}
LPMSG msg = (LPMSG)lParam;
switch( msg->message )
{
case WM_LBUTTONDBLCLK:
SendMessage( hWndServer, UWM_MOUSELDBCLICK, 0 , 0);
break;
case WM_MOUSEMOVE:
SendMessage( hWndServer, UWM_MOUSEMOVE, 0, 0);
break;
case WM_NCMOUSEMOVE:
SendMessage( hWndServer, UWM_MOUSEMOVE, 0, 0);
break;
case WM_LBUTTONDOWN:
SendMessage( hWndServer, UWM_MOUSELBUTTONDOWN, 0 , 0 );
break;
case WM_NCLBUTTONDOWN:
SendMessage( hWndServer, UWM_MOUSELBUTTONDOWN, 0 , 0);
break;
case WM_LBUTTONUP:
SendMessage( hWndServer, UWM_MOUSELBUTTONUP, 0 , 0 );
break;
case WM_NCLBUTTONUP:
SendMessage( hWndServer, UWM_MOUSELBUTTONUP, 0 , 0);
break;
case WM_RBUTTONDOWN:
SendMessage( hWndServer, UWM_MOUSERBUTTONDOWN, 0 , 0 );
break;
case WM_NCRBUTTONDOWN:
SendMessage( hWndServer, UWM_MOUSERBUTTONDOWN, 0 , 0);
break;
case WM_RBUTTONUP:
SendMessage( hWndServer, UWM_MOUSERBUTTONUP, 0 , 0 );
break;
case WM_NCRBUTTONUP:
SendMessage( hWndServer, UWM_MOUSERBUTTONUP, 0 , 0);
break;
default:
break;
}
return CallNextHookEx(hook, nCode, wParam, lParam);
}
__declspec(dllexport) BOOL InstallHook( HWND hWndParent)
{
if(hWndServer != NULL)
return FALSE; // already hooked!
hook = SetWindowsHookEx( WH_GETMESSAGE, (HOOKPROC)MouseMsgProc,
hInst, 0);
if(hook != NULL)
{
hWndServer = hWndParent;
return TRUE;
}
return FALSE;
}
__declspec(dllexport) BOOL UnInstallHook( HWND hWndParent )
{
if(hWndParent != hWndServer || hWndParent == NULL)
return FALSE;
BOOL unhooked = UnhookWindowsHookEx(hook);
if(unhooked)
hWndServer = NULL;
return unhooked;
return TRUE;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hInst = hModule;
UWM_MOUSEMOVE = ::RegisterWindowMessage(UWM_MOUSEMOVE_MSG);
UWM_MOUSELBUTTONUP = ::RegisterWindowMessage(UWM_MOUSELBUTTONUP_MSG);
UWM_MOUSELBUTTONDOWN = ::RegisterWindowMessage(UWM_MOUSELBUTTONDOWN_MSG);
UWM_MOUSERBUTTONUP = ::RegisterWindowMessage(UWM_MOUSERBUTTONUP_MSG);
UWM_MOUSERBUTTONDOWN = ::RegisterWindowMessage(UWM_MOUSERBUTTONDOWN_MSG);
UWM_MOUSELDBCLICK = ::RegisterWindowMessage(UWM_MOUSELDBCLICK_MSG);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//Win32 Application main.cpp
#include "stdafx.h"
#include "stdafx.h"
#include <sstream>
#include "strsafe.h"
#include "../Hook/Hook.h"
#define MAX_LOADSTRING 100
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
//Mouse Events
static UINT UWM_MOUSEDBCLICK = ::RegisterWindowMessage( UWM_MOUSELDBCLICK_MSG );
static UINT UWM_MOUSELBUTTONUP = ::RegisterWindowMessage(UWM_MOUSELBUTTONUP_MSG);;
static UINT UWM_MOUSELBUTTONDOWN = ::RegisterWindowMessage(UWM_MOUSELBUTTONDOWN_MSG);
static UINT UWM_MOUSERBUTTONUP = ::RegisterWindowMessage(UWM_MOUSERBUTTONUP_MSG);
static UINT UWM_MOUSERBUTTONDOWN = ::RegisterWindowMessage(UWM_MOUSERBUTTONDOWN_MSG);
static UINT UWM_MOUSEMOVE = ::RegisterWindowMessage(UWM_MOUSEMOVE_MSG);
//
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_ACTIONX, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_ACTIONX));
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ACTIONX));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_ACTIONX);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
BOOL result=InstallHook(hWnd);
return TRUE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
//Global Mouse Move Handle
if(message==UWM_MOUSEMOVE){
MessageBox(
NULL,
(LPCWSTR)L"Resource not available\nDo you want to try again?",
(LPCWSTR)L"Account Details",
MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2
);
return 0;
}
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
case IDM_PLAY:
PlayMouse();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
Use WH_MOUSE hook to hook mouse messages only.
Few suggestions:
Ensure you hook installed successfully (SetWindowsHookEx returned non-NULL value)
Ensure messages delivered to hook procedure (Set breakpoint to these points or use trace functions)
You either need to send HWND of target window to the each process or send broadcast message
For Windows Vista and later processes with lower privileges cannot send messages to process with higher privileges. You need to use ChangeWindowMessageFilter to add necessary messages to the filter
Use PostMesssage instead of SendMessage, you don't need blocking calls here anyway
while defining a hook you have to provide the handle for the window for which you want to intercept the signal. Maybe passing handle of the desktop there can catch all the mouse event even outside the client window.
I've been trying to figure this out for ages and I'm absolutely stumped! I'm trying to subclass an edit control so I can capture when the enter key is pressed.
I've seen lots of other posts about sub-classing with snippets of code to add to do it, but I can't seem to implement it into my application. I apologize if I'm making a stupid mistake, but I simply cannot figure this out.
I know this code is poorly written and has no error checking, but I wanted to post as little code as possible to convey the problem.
#include <Windows.h>
#include <wchar.h>
HWND editHWND;
WNDPROC wpOrigEditProc;
LRESULT APIENTRY EditSubclassProc(HWND hwnd,UINT uMsg,WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CHAR)
{
//do my stuff
}
return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_CREATE:
wpOrigEditProc = (WNDPROC) SetWindowLong(editHWND,GWL_WNDPROC, (LONG) EditSubclassProc);
SetWindowLong(editHWND, GWL_WNDPROC,(LONG) wpOrigEditProc);
break;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
int WINAPI wWinMain( HINSTANCE hInst,HINSTANCE,LPWSTR,INT )
{
WNDCLASSEX wc = { sizeof( WNDCLASSEX ),CS_CLASSDC,MsgProc,0,0,
GetModuleHandle( NULL ),NULL,NULL,NULL,NULL,
L"My Window",NULL };
RegisterClassEx( &wc );
HWND hWnd = CreateWindowW( L"My Window",L"test application",
WS_OVERLAPPEDWINDOW,100,100,800,600,
NULL,NULL,wc.hInstance,NULL );
editHWND = CreateWindow( L"edit",L"hi there",WS_VISIBLE | WS_CHILD | WS_BORDER,100,100,300,50,hWnd,(HMENU)17,0,0);
ShowWindow( hWnd,SW_SHOWDEFAULT );
MSG msg;
ZeroMemory( &msg,sizeof( msg ) );
while( msg.message != WM_QUIT )
{
if( PeekMessage( &msg,NULL,0,0,PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
UnregisterClass( L"My Window",wc.hInstance );
return 0;
}
MsgProc() is the window procedure for the "My Window" window. When you are processing the WM_CREATE message, you are processing that window's creation, before the second CreateWindow() has been called to create the Edit window.
Worse, even if you were subclassing the Edit window correctly, you are removing the subclass immediately after setting it. So EditSubClassProc() would never have a change to be called anyway.
Since you are not defining a custom window procedure for the Edit window at the time it is being created, you cannot use a WM_CREATE message to subclass the Edit window (unless you use a message hook, which is overkill in this situation). Just call SetWindowLong() after CreateWindow() has exited.
Try this:
#include <Windows.h>
#include <wchar.h>
HWND editHWND = NULL;
WNDPROC wpOrigEditProc = NULL;
LRESULT APIENTRY EditSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CHAR)
{
//do my stuff
}
return CallWindowProc(wpOrigEditProc, hwnd, uMsg, wParam, lParam);
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
int WINAPI wWinMain( HINSTANCE hInst,HINSTANCE,LPWSTR,INT )
{
WNDCLASSEX wc = { sizeof( WNDCLASSEX ),CS_CLASSDC,MsgProc,0,0,
GetModuleHandle( NULL ),NULL,NULL,NULL,NULL,
TEXT("My Window"),NULL };
RegisterClassEx( &wc );
HWND hWnd = CreateWindowW( TEXT("My Window"),TEXT("test application"),
WS_OVERLAPPEDWINDOW,100,100,800,600,
NULL,NULL,wc.hInstance,NULL );
editHWND = CreateWindow( TEXT("edit"),TEXT("hi there"),WS_VISIBLE | WS_CHILD | WS_BORDER,100,100,300,50,hWnd,(HMENU)17,0,0);
wpOrigEditProc = (WNDPROC) SetWindowLongPtr(editHWND, GWL_WNDPROC, (LONG_PTR) EditSubclassProc);
ShowWindow( hWnd, SW_SHOWDEFAULT );
MSG msg;
while ( GetMessage( &msg,NULL,0,0 ) > 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
UnregisterClass( TEXT("My Window"),wc.hInstance );
return 0;
}
With that said, another way to subclass a window is to use SetWindowSubclass() instead:
#include <Windows.h>
#include <wchar.h>
HWND editHWND = NULL;
LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
if (uMsg == WM_CHAR)
{
//do my stuff
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_CLOSE:
DestroyWindow(hWnd);
return 0;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
int WINAPI wWinMain( HINSTANCE hInst,HINSTANCE,LPWSTR,INT )
{
WNDCLASSEX wc = { sizeof( WNDCLASSEX ),CS_CLASSDC,MsgProc,0,0,
GetModuleHandle( NULL ),NULL,NULL,NULL,NULL,
TEXT("My Window"),NULL };
RegisterClassEx( &wc );
HWND hWnd = CreateWindowW( TEXT("My Window"),TEXT("test application"),
WS_OVERLAPPEDWINDOW,100,100,800,600,
NULL,NULL,wc.hInstance,NULL );
editHWND = CreateWindow( TEXT("edit"),TEXT("hi there"),WS_VISIBLE | WS_CHILD | WS_BORDER,100,100,300,50,hWnd,(HMENU)17,0,0);
SetWindowSubclass(editWND, EditSubclassProc, 0, 0);
ShowWindow( hWnd, SW_SHOWDEFAULT );
MSG msg;
while ( GetMessage( &msg,NULL,0,0 ) > 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
UnregisterClass( TEXT("My Window"),wc.hInstance );
return 0;
}
I made hook for calculator and want to get messages which calculator receives. To do that, I set my own window procedure, but during unhooking if I use SetWindowLong(..) to recover the old window procedure program crushes.
DLL code:
#define EXPORT_API extern "C" __declspec(dllexport)
EXPORT_API void InstallHook();
EXPORT_API void UninstallHook();
#pragma data_seg("Shared")
HHOOK g_hHook = NULL;
WNDPROC g_OldWndProc = NULL;
#pragma data_seg()
#pragma comment(linker, "/section:Shared,rws")
HWND GetTargetWindowHwnd()
{
return ::FindWindowA(0, "Calculator");
}
// my new wnd procedure to catch messages
LRESULT CALLBACK NewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = 0;
switch(uMsg)
{
case WM_CLOSE:
{
MessageBoxA(0, "Here we are!", "", 0);
}
break;
default:
lResult = CallWindowProc(g_OldWndProc, hwnd, uMsg, wParam, lParam);
break;
}
lResult = CallWindowProc(g_OldWndProc, hwnd, uMsg, wParam, lParam);
return lResult;
}
// hook procedure
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSG *pMsg = (MSG *)lParam;
HWND hWnd = GetTargetWindowHwnd();
bool flagIn = false;
if( hWnd == pMsg->hwnd )
{// if messege was sent to my target window
if(g_OldWndProc == NULL)
{
// save the adress of old wnd procedure to recover it later
g_OldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
// set my wnd procedure
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)NewWndProc);
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
EXPORT_API void InstallHook()
{
try
{
g_hHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hInstance, 0);
}
catch(...)
{
MessageBoxA(0, "Hook error", "Error", 0);
}
}
EXPORT_API void UninstallHook()
{
if(g_OldWndProc)
{
// recovering old wnd proc
HWND hWnd = GetTargetWindowHwnd();
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)g_OldWndProc);
g_OldWndProc = NULL;
}
if (g_hHook)
{
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
}
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hInstance = (HINSTANCE) hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
EXE CODE:
void CHookTestDlg::OnBnClickedBtnInstall()
{
InstallHook();
}
void CHookTestDlg::OnBnClickedBtnUninstall()
{
UninstallHook();
}
If I don't use my wnd procedure it works normal. If I use SetWindowLong(..) to recover the old window procedure program crushes during unhook. What is wrong?
The problem is that you are setting the window proc on the target window from within the target process (calc), and in that case, it is succeeding. But when you call UninstallHook, that code runs in your own exe's process; and in that case, SetWindowLong will fail.
(Putting the hook values in shared memory won't help; SetWindowLong will still refuse to change the window proc across a process boundary - see MSDN for details.)
To get this to work, you would need to communicate to the hooked instance of the DLL and ask it to reset the wndproc from within that target process, and once that is done, then unhook the hook.
(atzz's advice on unhooking is also valid. Hooking windows that you don't own is generally best avoided.)
When unsubclassing, always check that the window was not subclassed by someone else after you. I.e. before restoring WindowProc, you should read it again and compare against expected value (NewWndProc). If it is different, you must not unload the DLL, because another subclasser has a pointer to your DLL code stored, and this pointer will become dangling as soon as your DLL is unloaded.