У меня есть код окна, и в нем у меня есть функция, подписанная на получение системных сообщений:
... IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
В этой функции, когда я вижу сообщение, которое я ожидаю, я запускаю свой класс
... 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
}
Если я сделаю это так, то получаю эту ошибку "RPC_E_CANTCALLOUT_ININPUTSYNCCALL". После некоторых исследований, если я это правильно пойму, это не позволит мне запускать MyClass или аналогичный код, потому что я пытаюсь выполнить его, когда система еще не завершена, доставляя все сообщения или какую-то аналогичную проблему.
Поэтому, чтобы обойти эту проблему, я отправляю сообщение себе так:
[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
}
}
Чтобы решить мою проблему, мне нужно либо знать:
Почему devType 0 при отправке сообщения?
или
Есть ли какой-нибудь (простой) способ, с помощью которого я могу запускать MyClass напрямую, когда получаю системное сообщение, не переписывая сообщение самому себе?
Что касается вашего LParam, то 0... Вы обрабатываете IntPtr как размер 4, что не так, если ваш Targeting AnyCpu и вы находитесь на 64-битной ОС. Так что, если размер на самом деле равен 8, и он хранится в Little Endian в памяти (который находится в окнах), тогда чтение 4 будет получать первые 4 байта, который будет равен 0, если значения меньше максимального значения 4 байт. В Little Endian значение сохраняется справа налево (наивысший адрес до наименьшего адреса). Так что, вероятно, ничего не было в первых 4 байтах, и вы не читали последние 4 байта, потому что вы предполагали, что IntPtr имеет 4 байта.
Попробуйте использовать
Marshal.ReadInt32 (lParam, lParam.Size)
IntPtr.Size вернет 4, когда он будет 32-битным Runtime и 8, когда он будет работать в 64-битной среде исполнения (управляя этим dilmma для вас).
Что касается остальной части,
Также имейте в виду, если вы пытаетесь сделать глобальный крючок,
Единственными глобальными перехватами, которые вы можете использовать в.Net для обработчика MSG, например SetWindowsHookEx, являются "крюк низкого уровня WH_KEYBOARD_LL и WH_MOUSE_LL".
Теперь вы можете подключить свой собственный процесс просто отлично, но вы не можете перехватывать другие процессы глобально в.Net.
И если вы подключаете свой собственный процесс, почему бы вам просто не переопределить WndProc в классе формы, тогда вам не нужно ничего делать в DllImport и оно будет в правильном порядке (например, вы не получите его на ранней стадии или до конца).