Reputation: 757
I have a window code and in it, I have a function subscribed to receive system messages:
... IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
In this function, when I see the message I am waiting for I trigger my class
... IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
...some code checking the type of the mesage, etc....
new MyClass(); //Trigger my class
}
If I do it like this, then I get this error "RPC_E_CANTCALLOUT_ININPUTSYNCCALL". After some research, if I understand this correctly, it won't allow me to run MyClass or similar code, because I am trying to execute it when the system isn't finished delivering all messages yet, or some similar issue.
So to bypass this issue I repost the message to myself like so:
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam);
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
...some code checking the type of the mesage, etc....
if (msg != 0xD903) //If msg is not 55555 this message is not a repost and therefore repost it
{
var devType = Marshal.ReadInt32(lParam, 4);
Debug.WriteLine(devType); //This correctly prints out "2" which i get from lParam
PostMessage(hwnd, 55555, wParam, lParam); //repost message
}
else //If the msg is 55555 this message is my repost and I can execute MyClass with no problems
{
var devType = Marshal.ReadInt32(lParam, 4);
Debug.WriteLine(devType); //This should also print out "2", since I am merely reposting the lParam, without changing it in any way, but instead it prints "0"
new MyClass(); //Trigger my class
}
}
To solve my problem, I need to either know:
Why is the devType 0 when I repost the message?
or
Is there some (easy) way where I can trigger MyClass directly when I recieve the system message, without having to repost the message to myself?
Upvotes: 1
Views: 400
Reputation: 5357
As to your LParam being 0... You are treating IntPtr as size being 4, which isn't the case if your Targetting AnyCpu and you are on a 64 bit OS. So if it's size is actually, 8 and it's stored in Little Endian in memory (which it is in windows) then reading 4 is going to get the first 4 bytes, which will be 0 if the values is less than the max value of 4 bytes. In Little Endian the value is stored from right to left (highest address to smallest address). So it's likely that nothing is in the first 4 bytes and you didn't read the last 4 bytes because you assumed an IntPtr was 4 bytes.
Try using
Marshal.ReadInt32(lParam, lParam.Size)
IntPtr.Size will return 4 when it's on the 32 bit Runtime and 8 when it's on the 64 bit runtime (managing that dilmma for you).
As to the rest of it,
Also keep in mind, if you are trying to do a global hook,
The only global hooks you can do in .Net on the MSG handler e.g. SetWindowsHookEx, are "WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL".
Now you can hook your own process just fine, but you can't hook other processes globally in .Net.
And if you are hooking your own process, why don't you just Override WndProc on the form class, then you don't need to DllImport anything and it will be in the right order (e.g. you won't get it to early or to late).
Upvotes: 1