I have C++ DLL, that implements CTB_HOOK and c# app, from which I P/Invoke this DLL.
The system calls the function below when messages to hooked thread are intercepted (before activating, creating, destroying, minimizing, maximizing, moving, or sizing a window and so on). I want to pass nCode to my c# application.
static LRESULT CALLBACK CBTHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_ACTIVATE)
{
MessageBox(NULL, TEXT("HCBT_ACTIVATE"), TEXT("inside hook"), MB_OK);
}
//here I want to pass nCode(code of intercepted message) to my c# app.
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
At first tried to use a callback to C# from C++ code (good article on this topic). But soon I've realized I have no way to a pass pointer to c#_callback_function to CBTHookProc (I wanted to save pointer to c#_callback_function as a global variable, but since each process using a DLL has its own instance of all the DLLs global nothing succeeded).
Then I googled for DLL share data, but I is only suitable for static variables.
So, is there a way to callback from hook procedure? Or maybe some other way to get data from hook procedure?
Related
I have a virtual mouse driver and an actual mouse on my computer.
I'm using LowLevelMouseProc to capture events windows wide and I would like to not process events from the virtual mouse.
I cannot use RawInput as I need to process message of another process.
Is there any way to know which device has sent the message ?
Forcing the dwExtraInfo also on a real mouse device may help me if possible.
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
MSLLHOOKSTRUCT hookStruct;
if (nCode < 0)
{
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
hookStruct = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
// I'd like to know from here which mouse has sent the message.
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
There is nothing exposed from the .NET Windows API to distinguish between different mice. There was a Microsoft SDK for multiple inputs at one time but it was dropped before Windows 10 so it likely doesn't work anymore.
rawinput-sharp shows how to do it but it uses raw input, as the name suggests, which I know you said you don't want to do. This limitation you have put on yourself has gotten you stuck. It's like saying "how do I see the screen with my eyes closed?"
Perhaps you could correlate the two events somehow to get the filter you are looking for. Or maybe you could filter out all events from the LowLevelMouseProc and pass the raw input from just one device into the LowLevelMouseProc.
There is a related discussion from the GameDev SE site.
I am trying to make a little program that installs a global hook and catches keyboard input.
For now, I am trying to make every input changed to 'X' for example.
So if i write anywhere "hello" it will actually write "XXXXX".
I succeeded with hooking and even stopping any input from passing my hook but I can't figure out how to change the input.
The relevant method:
IntPtr HookCallBack(int nCode, IntPtr wParam, IntPtr lParam)
{
// Trying to change the input.
Marshal.WriteInt32(lParam, 88);
// Locked down
if (isKeyboardLockedDown)
return new IntPtr(1); // A non-zero return value blocks additional processing of key strokes.
// Not locked down.
else
return NativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
}
As written above - if I understand right - lParam is the address where the input key is stored.
Therefor I overwrite it with "X".
That method doesn't work for some reason.
Any suggestions?
If the input is X:
Invoke CallNextHookEx()
Otherwise
Do not invoke CallNextHookEx(). Instead, call SendInput to post an X.
SendInput
Synthesizes keystrokes, mouse motions, and button clicks.
Note: In general it is unwise not to invoke CallNextHookEx(). Then again, it is in general not wise to replace all input with X :-)
iv'e done a similar project in C. Instead of changing the data i generated input. It works smoothly and not slowing the typing process down.
I used a global flag. True for input i generate and false for input from the user.
This is pretty much how it looked:
HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(flag){
flag = FALSE;
return CallNextHookEx(NULL, nCode, wParam, lParam);}
else{
flag = TRUE;
keybd_event(what ever you want);
return 0;}
}
I get this problem only with thread-specific hooks. WH_KEYBOARD_LL and WH_MOUSE_LL work both fine as the dll doesn't have to be injected somewhere. This is one of the callback procedures form the dll:
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
HookData[WH_KEYBOARD + 1].lpfn(nCode, wParam, lParam);
return CallNextHookEx(HookData[WH_KEYBOARD + 1].hhook, nCode, wParam, lParam);
}
lpfn is the method from the managed code (C# project) that will marshal and store the parameters for further analisys. When that method is called, the process of the thread I want to monitor crashes for "access violation" (the thread I use to test the hook is that of the window of notepad).
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MessageBox(NULL, L"Value", L"KeyboardHook", MB_OK);
return CallNextHookEx(HookData[WH_KEYBOARD + 1].hhook, nCode, wParam, lParam);
}
I tried then this way and it worked fine, showing a message box everytime I pressed a key when the window of notepad was focused.
So, is there a way to call that method? Or maybe am I calling that method in a wrong way? If I can't call that method, is there another way to pass the callback parameters to the C# project everytime the callback procedure is called?
I am using a class i got from this blog:
http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
This function get the key code for a single key, i wanted to alter it so i can catch ctrl+C so i altered the above function as follows:
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if ((Keys)(vkCode) == Keys.C && (Control.ModifierKeys == Keys.Control))
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
The problem is Control.ModifierKeys always returns NONE, i googled too much with any results, i want to note that i am using this code in class in a separate module in the solution. What am i doing here, please provide a solution.
Yes, this will go wrong in general but especially when your program does itself not have a GUI or uses a hidden window. Windows maintains keyboard state for each individual process, it is updated when a program receives a keyboard message. This is necessary because key strokes are stored in the message queue and get retrieved by the program later, sometimes much later. The problem with a keyboard hook is that it was another process that got the message, not yours. You've still got the stale keyboard state.
To make it truly reliable, you'll need to know the keyboard state of the other process. But that's not something you can get to, the GetKeyboardState() function only allows permitting retrieving your own state. This in general makes translating key strokes to typing keys very difficult. A WH_KEYBOARD hook is a much better solution but you cannot write such a hook in C#.
A workaround is to track the state of the Control key yourself. Or by pinvoking GetAsyncKeyState() to check the actual unbuffered state of the Control key.
That won't work for you!
The implementation of Control.ModifierKeys just calls the Windows API function GetKeyState() three times, with parameters 0x10, 0x11 and 0x12 in turn, and ors the results appropriately.
But the state is tied to which message from the message queue is being processed.
I think you need to use PInvoke to call the Windows API function GetAsyncKeyState() instead.
I'm currently involved in a project that is migrating some old VB6 code to C# (.Net Framework 3.5). My mandate is to just do the migration; any functional enhancements or refactoring is to be pushed to a later phase of the project. Not ideal, but there you go.
So part of the VB6 code makes a call out to the Windows API SetTimer function. I've migrated this and cannot get it to work.
The migrated project builds as a DLL; I've created a small WinForms test harness that links to the DLL and calls the code in question. Very simple, just to prove that the call can be made.
The relevant code in the migrated DLL is as follows:
[DllImport("user32.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public extern static int SetTimer(int hwnd, int nIDEvent, int uElapse, AsyncObjectCallerDelegate lpTimerFunc);
public delegate void AsyncObjectCallerDelegate(int hwnd, int uMsg, int idEvent, int dwTime);
static public int StartTimer( AsyncGeoServer.GeoWrapper AsyncObj)
{
m_objGeoWrapper = AsyncObj;
int lngReturn = SetTimer(0, 0, 1, new AsyncObjectCallerDelegate(AsyncObjectCaller));
// When the line below is removed, the call functions correctly.
// MessageBox.Show("This is a temp message box!", "Temp Msg Box", MessageBoxButtons.OKCancel);
return lngReturn;
}
static private void AsyncObjectCaller(int hwnd, int uMsg, int idEvent, int dwTime)
{
// Perform processing here - details removed for clarity
}
static public void StopTimer( int TimerID)
{
try { KillTimer(0, TimerID); }
catch { }
}
The above calls are wrapped by the DLL in an outer DoProcessing() method; this creates an event using CreateEvent before calling StartTimer (both Windows Kernel calls), then calls WaitForSingleObject before continuing processing. The AsyncObjectCaller function will set the event as part of its execution to allow processing to continue.
So my issue is this: if the code is called as listed above, it fails. The AsyncObjectCaller callback method never gets triggered and the WaitForSingleObject call times out.
If, however, I uncomment the MessageBox.Show call in StartTimer, it works as expected... sort of. The AsyncObjectCaller callback method gets triggered immediately after the call to MessageBox.Show. I've tried putting MessageBox.Show in various locations in the code, and it's the same no matter where I put it (as long as it's called after the call to SetTimer) - the callback function doesn't get triggered until the messagebox is displayed.
I'm completely stumped, and none too familiar with either VB6 or Windows API coding, coming from a mainly .Net background.
Thanks for any help!
Your AsyncObjectCallerDelegate is incorrect. It might work in 32-bit code, but will fail miserably in 64-bit. The Windows API function prototype is:
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
In C#, that would be:
delegate void AsyncObjectCallerDelegate(IntPtr hWnd, uint uMsg, IntPtr nIDEvent, uint dwTime);
Also, your managed prototype should be:
static extern IntPtr SetTimer(IntPtr hWnd, IntPtr nIDEvent, uint uElapse, AsyncObjectCallerDelegate lpTimerFunc);
That said, I'd echo what Alex Farber said: you should use one of the .NET timer objects for this. Since this doesn't appear to be a UI timer (you're passing 0 for the window handle), I'd suggest System.Timers.Timer or System.Threading.Timer. If you want the timer to raise an event, use System.Timers.Timer. If you want the timer to call a callback function, use System.Threading.Timer.
Note that the event or callback will be executed on a pool thread--NOT the program's main thread. So if the processing will be accessing any shared data, you'll have to keep thread synchronization issues in mind.
The problem is that your program is not pumping a message loop or is not letting the UI thread go idle. An API function like SetTimer() requires a message loop to work. Application.Run() in a Windows Forms project for example. The callback can only run when the your main thread is inside the loop, dispatching Windows messages.
It works when you use MessageBox.Show(), that's a function that pumps its own message loop. So that the message box can respond to the user clicking the OK button. But of course, that will only work for as long as the box is up.
You'll probably need to restructure your program so it is based on a Windows Forms project template. Calling Application.DoEvents() in a loop is a very imperfect workaround.
public extern static int SetTimer(int hwnd, int nIDEvent, int uElapse, IntPtr lpTimerFunc);
int lngReturn = SetTimer(0, 0, 1, Marshal.GetFunctionPointerForDelegate(new AsyncObjectCallerDelegate(AsyncObjectCaller)));
I understand that your mandate is to just do the migration, but i any case, it is better to use Windows Forms timer instead of this, it wraps native SetTimer API, and there is no need in these interoperability tricks.