У меня есть программа на C#, которая опросит об изменениях в коллекции EnumDesktopWindows. Если пользователь закрывает или открывает окно, процедура опроса обнаруживает это и отправляет обновленный список доступных окон в другой проект .net windows. Однако мне не нравится метод опроса. Я бы предпочел, чтобы любое изменение в EnumDesktopWindows запускало событие, так что ответ на изменение выполняется асинхронно.делегат pinvoke async при изменении коллекций окон на рабочем столе?
Лучшее, что я мог придумать, - это то, что вы видите ниже. Я попробовал предложение Скотта C. выполнить из окна консоли, но это не сработало.
В настоящее время то, что вы видите ниже, захватывает CreateWnd = 3 при загрузке Windows Form (это приложение для форм Windows). Однако он не захватывает глобально: он только захватывает события окна из текущего исполняемого исполняемого файла. Если у кого-то есть глаза орла и вы можете определить, как сделать этот захват кода глобально, я дам вам ответ.
Чтобы проверить это; сначала создать проект с Windows Forms приложений и добавьте следующий код в Form1.cs (вам нужно будет добавить ListBox в форму с именем lstLog правильно скомпилировать)
using System;
using System.Windows.Forms;
namespace Utilities
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var gwh = new GlobalWindowHook();
gwh.WindowCreated += onWindowCreated;
}
private void onWindowCreated()
{
lstLog.Items.Add("window creation event detected.");
}
}
}
Создайте файл класса в одном проекте под названием GlobalWindowHook .cs и скопировать пасту:
using System;
using System.Runtime.InteropServices;
namespace Utilities
{
internal class GlobalWindowHook
{
private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
public enum HookType
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
public enum HCBT
{
MoveSize = 0,
MinMax = 1,
QueueSync = 2,
CreateWnd = 3,
DestroyWnd = 4,
Activate = 5,
ClickSkipped = 6,
KeySkipped = 7,
SysCommand = 8,
SetFocus = 9
}
private IntPtr hhook = IntPtr.Zero;
public GlobalWindowHook()
{
hook();
}
~GlobalWindowHook()
{
unhook();
}
public void hook()
{
IntPtr hInstance = LoadLibrary("User32");
hhook = SetWindowsHookEx(HookType.WH_CBT, hookProc, hInstance, 0);
}
public void unhook()
{
UnhookWindowsHookEx(hhook);
}
public IntPtr hookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code != (int) HCBT.CreateWnd && code != (int) HCBT.DestroyWnd)
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
//Do whatever with the created or destroyed window.
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
[DllImport("user32.dll")]
private static extern IntPtr SetWindowsHookEx(HookType code, HookProc func, IntPtr hInstance, int threadId);
[DllImport("user32.dll")]
private static extern bool UnhookWindowsHookEx(IntPtr hInstance);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr LoadLibrary(string fileName);
}
}
После выполнения вышеуказанных шагов выполните проект форм окон. Вы должны увидеть, что он определяет одно созданное окно, а именно тот, который вы только что выполнили.
Я думаю, что вы можете сделать это с помощью 'SetWindowsHookEx()' с 'WH_CBT' типа крюка. – cdhowie
http://msdn.microsoft.com/en-us/library/windows/desktop/dd373640%28v=vs.85%29.aspx –
Я только что изменил свой вопрос, обновив его своей лучшей попыткой до сих пор (спасибо вы Скотт). Я все еще преследую ответ. – sapbucket