Мониторинг изменений в буфере обмена через WinApi32 - PullRequest
0 голосов
/ 21 февраля 2020

Я хочу отслеживать изменения в буфере обмена (только текст). Я пытаюсь найти некоторые решения и нашел следующие вопросы по StackOverflow:

Но моя проблема / требование заключается в том, что я не хочу добавлять зависимость к Windows .Forms ни WPF (мое приложение является консольным приложением). Я пытаюсь посмотреть доступные методы в user32.dll. Я написал код, который создает окно и стили окна. Переопределите метод WndPr c для пользовательского, а затем добавьте прослушиватель в изменения буфера обмена. Функция WndProcFunction была вызвана 4 раза для следующих сообщений:

  • WM_GETMINMAXINFO
  • WM_NCCREATE
  • WM_NCCALCSIZE
  • WM_CREATE

Но когда я изменяю содержимое буфера обмена, было отправлено сообщение типа WM_CLIPBOARDUPDATE, а также любое сообщение, которое будет соответствовать WndProcFunction. Я пытаюсь использовать «старый API» (SetDashboardViewer), но это ничего не меняет. Код выглядит следующим образом:

using PInvoke;

...
internal static class User32Ext
{
    [DllImport("user32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool AddClipboardFormatListener(IntPtr hwnd);

    [DllImport("user32.dll", SetLastError=true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd);

    [DllImport("kernel32.dll")]
    internal static extern uint GetLastError();
}

class Program
{
    private static IntPtr _nextInChain = IntPtr.Zero;

    internal static unsafe IntPtr WndProcFunction(IntPtr hwnd, User32.WindowMessage windowMessage, void* wParam1, void* lParam1)
    {
        if (windowMessage == User32.WindowMessage.WM_CREATE)
        {
            var listener = User32Ext.AddClipboardFormatListener(hwnd);
            var result = User32.OpenClipboard(window);
            //_nextInChain = User32Ext.SetClipboardViewer(hwnd);
        }
        if (windowMessage == User32.WindowMessage.WM_CLIPBOARDUPDATE)
        {
            var pointerToText = User32.GetClipboardData_IntPtr(1);
            var text = Marshal.PtrToStringAnsi(pointerToText);
            Console.WriteLine(text);
        }

        if (windowMessage == User32.WindowMessage.WM_DRAWCLIPBOARD)
        {
            if (_nextInChain != IntPtr.Zero)
            {
                User32.SendMessage(_nextInChain, windowMessage, wParam1, lParam1);
            }
        }

        if (windowMessage == User32.WindowMessage.WM_CHANGECBCHAIN)
        {
            _nextInChain = hwnd;
            //send message...
        }

        if (windowMessage == User32.WM_DESTROY)
        {
            //chain msg
            User32Ext.RemoveClipboardFormatListener(hwnd);
        }

        return hwnd; //success
    }

    static void Main(string[] args)
    {
        unsafe
        {
            var hInstance = Marshal.GetHINSTANCE(typeof(Program).Module);
            string name = "Test";
            User32.WNDCLASSEX wndClassEx = new User32.WNDCLASSEX
            {
                cbSize = Marshal.SizeOf(typeof(User32.WNDCLASSEX)),
                style = User32.ClassStyles.CS_GLOBALCLASS,
                cbClsExtra = 0,
                cbWndExtra = 0,
                hbrBackground = IntPtr.Zero,
                hCursor = IntPtr.Zero,
                hIcon = IntPtr.Zero,
                hIconSm = IntPtr.Zero,
                lpszMenuName = null,
                hInstance = hInstance,
                lpfnWndProc = new User32.WndProc(WndProcFunction)
            };

            var stringPtr = Marshal.StringToHGlobalAuto(name);
            wndClassEx.lpszClassName_IntPtr = stringPtr;

            var register = User32.RegisterClassEx(ref wndClassEx);
            var window = User32.CreateWindowEx(
                User32.WindowStylesEx.WS_EX_TRANSPARENT,
                name,
                "Test Window",
                0,
                0, 0, 0, 0,
                IntPtr.Zero,
                IntPtr.Zero,
                wndClassEx.hInstance,
                IntPtr.Zero
            );

            User32.SetClipboardData(13, stringPtr);
            ...
        }
    }
}

Есть ли что-то, что мне все еще не хватает в коде, какой-то дополнительный слушатель? Я смотрю на коды ошибок после каждого вызова метода (ов) из user32.dll. Но все безуспешно.

1 Ответ

1 голос
/ 21 февраля 2020

A message l oop требуется для получения сообщений. Если вам не нужно окно, вы можете создать окно только для сообщений , которое позволяет отправлять и получать сообщения.

Он не виден, не имеет z-порядка, не может быть перечислен и не принимает широковещательные сообщения. Окно просто отправляет сообщения.

В C#, в конце вашей main функции, оно будет выглядеть так:

    MSG msg;  
    while (User32.GetMessage(out msg, IntPtr.Zero, 0, 0) != 0)  
    {  
        User32.TranslateMessage(ref msg);  
        User32.DispatchMessage(ref msg);  
    }  

См. MSG , Создание сообщения L oop.

...