首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么我不能检测到发送到我的CommonDialog的Windows消息?拦截他们的正确方法是什么?

为什么我不能检测到发送到我的CommonDialog的Windows消息?拦截他们的正确方法是什么?
EN

Stack Overflow用户
提问于 2019-02-18 23:40:45
回答 1查看 291关注 0票数 0

我试图检测用户何时单击FormCommonDialog

表单相当简单。我创建了一个拦截消息的MessageFilter类:

代码语言:javascript
运行
复制
class MessageFilter : IMessageFilter
{
    private const int WM_LBUTTONDOWN = 0x0201;
    public bool PreFilterMessage(ref Message message)
    {
        if (message.Msg == WM_LBUTTONDOWN)
        {
            Console.WriteLine("activity");
        }
        return false;
    }
}

我注册了消息过滤器:

代码语言:javascript
运行
复制
MessageFilter mf = new MessageFilter();
Application.AddMessageFilter(mf);

Form form = new Form();
form.ShowDialog();

Application.RemoveMessageFilter(mf)

当我运行控制台应用程序并单击Form时,我会看到登录到控制台的"activity“。

当我用一个Form替换CommonDialog

代码语言:javascript
运行
复制
SaveFileDialog dialog = new SaveFileDialog();
dialog.ShowDialog();

我不能再检测鼠标的点击,即使我可以看到Windows被发送到CommonDialog (FWIW,我无法检测到任何消息):

那我为什么不能拦截这些信息呢?

我想到的是,由于Application.AddMessageFilter是特定于线程的,如果CommonDialog是在与调用dialog.ShowDialog()的线程不同的线程上创建的,那么我就不会收到任何这些消息。

但是,我做了一个快速测试,尝试向调用WM_CLOSE的线程上的所有CommonDialogs发送一条dialog.ShowDialog()消息,它起了作用:

代码语言:javascript
运行
复制
int threadId = 0;
Thread thread = new Thread(() =>
{
    threadId = NativeMethods.GetCurrentThreadIdWrapper();
    SaveFileDialog dialog = new SaveFileDialog();
    dialog.ShowDialog();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Thread.Sleep(2000);
NativeMethods.CloseAllWindowsDialogs(threadId);
Thread.Sleep(2000);

NativeMethods看起来像:

代码语言:javascript
运行
复制
static class NativeMethods
{
    public static int GetCurrentThreadIdWrapper()
    {
        return GetCurrentThreadId();
    }

    public static void CloseAllWindowsDialogs(int threadId)
    {
        EnumThreadWndProc callback = new EnumThreadWndProc(CloseWindowIfCommonDialog);
        EnumThreadWindows(threadId, callback, IntPtr.Zero);
        GC.KeepAlive(callback);
    }

    private static bool CloseWindowIfCommonDialog(IntPtr hWnd, IntPtr lp)
    {
        if (IsWindowsDialog(hWnd))
        {
            UIntPtr result;
            const int WM_CLOSE = 0x0010;
            const uint SMTO_ABORTIFHUNG = 0x0002;
            SendMessageTimeout(hWnd, WM_CLOSE, UIntPtr.Zero, IntPtr.Zero, SMTO_ABORTIFHUNG, 5000, out result);
        }

        return true;
    }

    private static bool IsWindowsDialog(IntPtr hWnd)
    {
        const int MAX_PATH_LENGTH = 260; // https://learn.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
        StringBuilder sb = new StringBuilder(MAX_PATH_LENGTH);
        GetClassName(hWnd, sb, sb.Capacity);

        return sb.ToString() == "#32770";
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern int GetCurrentThreadId();

    private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint msg, UIntPtr wp, IntPtr lp, uint fuFlags, uint timeout, out UIntPtr lpdwResult);
}

为什么我不能拦截CommonDialog消息?我能做些什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-19 01:06:31

设置一个本地鼠标钩子怎么样?

我的项目做得很好。

代码语言:javascript
运行
复制
public const int WM_LBUTTONDOWN = 0x0201;
// add other button messages if necessary

public const int WH_MOUSE = 7;

private IntPtr _hookHandle;

private void HookStart() {
    int threadId = GetCurrentThreadId();

    HookProc mouseClickHandler = new HookProc(MouseClickHandler);
    _hookHandle = SetWindowsHookEx(WH_MOUSE, mouseClickHandler, IntPtr.Zero, (uint) threadId);
    if (_hookHandle == IntPtr.Zero) throw new Exception("Hooking failed!");
}

private void HookStop() {        
    if (UnhookWindowsHookEx(_hookHandle) == IntPtr.Zero) throw new Exception("Unhooking failed!");
}

private IntPtr MouseClickHandler(int nCode, IntPtr wParam, IntPtr lParam) {
    if (nCode >= 0 && wParam == (IntPtr) WM_LBUTTONDOWN) {
        // user clicked
    }
    return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
}

public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, uint threadId);
[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int UnhookWindowsEx(IntPtr idHook);
[DllImport("kernel32.dll")]
public static extern int GetCurrentThreadId();
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54756961

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档