Получать сообщения WM_COPYDATA в приложении Qt - PullRequest
2 голосов
/ 18 ноября 2009

Я работаю над приложением Qt только для Windows, и мне нужно получить данные из плагина Microsoft OneNote. Плагин написан на C # и может отправлять сообщения WM_COPYDATA. Как получить эти сообщения в приложении C ++ Qt?

Мне нужно:

  • Уметь указывать "имя класса", которое регистрирует окно, как при вызове RegisterClassEx, так что я могу убедиться, что плагин отправляет сообщения WM_COPYDATA в правильное окно.
  • Иметь доступ к идентификатору сообщения, чтобы проверить, являются ли это WM_COPYDATA и lParam, который содержит COPYDATASTRUCT с фактическими данными. Эта информация передается в WndProc, но я не могу найти перехват, где я могу перехватить эти сообщения.

Ответы [ 4 ]

6 голосов
/ 21 ноября 2009

Все это может быть обработано в Qt:

  1. Расширьте QWidget классом, который будет захватывать сообщения WM_COPYDATA:

        class EventReceiverWindow : public QWidget
    {
        Q_OBJECT
    public:
        EventReceiverWindow();
    
    signals:
        void eventData(const QString & data);
    
    private:
        bool winEvent ( MSG * message, long * result );
    };
    
  2. Генерирует GUID для установки в качестве заголовка окна QWidget:

    EventReceiverWindow::EventReceiverWindow()
    {
        setWindowTitle("ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver");
    }
    
  3. Переопределение winEvent для обработки структуры WM_COPYDATA и выдачи сигнала при его получении:

    bool EventReceiverWindow::winEvent ( MSG * message, long * result )
    {
            if( message->message == WM_COPYDATA ) {
                // extract the string from lParam
                COPYDATASTRUCT * data = (COPYDATASTRUCT *) message->lParam;
    
                emit eventData(QString::fromAscii((const char *)data->lpData, data->cbData));
    
                // keep the event from qt
                *result = 0;
                return true;
            }
    
            // give the event to qt
            return false;
    }
    
  4. В другом классе вы можете использовать этот класс для получения строк сообщения:

    EventReceiverWindow * eventWindow = new EventReceiverWindow;
    QObject::connect(eventWindow, SIGNAL(eventData(const QString &)), this, SLOT(handleEventData(const QString &)));
    

    ...

    void OneNoteInterface::handleEventData(const QString &data)
    {
        qDebug() << "message from our secret agent: " << data;
    }
    
  5. А в программе, которая отправляет сообщения, просто найдите окно по уникальному заголовку окна. Вот пример в C #:

    private struct COPYDATASTRUCT
    {
        public IntPtr dwData;
        public int cbData;
        [MarshalAs(UnmanagedType.LPStr)]
        public string lpData;
    }
    
    private const int WM_COPYDATA = 0x4A;
    
    [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
    static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
    
    [DllImport("User32.dll", EntryPoint = "SendMessage")]
    private static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, ref COPYDATASTRUCT lParam);
    
    private void sendMessageTo(IntPtr hWnd, String msg)
    {
        int wParam = 0;
        int result = 0;
    
        if (hWnd != IntPtr.Zero )
        {
            byte[] sarr = System.Text.Encoding.Default.GetBytes(msg);
            int len = sarr.Length;
            COPYDATASTRUCT cds;
            cds.dwData = IntPtr.Zero;
            cds.lpData = msg;
            cds.cbData = len + 1;
            result = SendMessage(hWnd, WM_COPYDATA, wParam, ref cds);
        }
    }
    

    тогда вы можете:

    IntPtr hwnd = FindWindowByCaption(IntPtr.zero, "ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver");
    sendMessageTo(hwnd, "omg hai");
    
1 голос
/ 18 ноября 2009

Вы также можете создать фиктивное окно только для получения этого сообщения с помощью Win32 API. Я полагаю, у вас не будет доступа к оконному процессу Qt-Window, так что это должен быть самый простой способ.

Вы могли бы (я бы не стал) также подклассировать окно, устанавливая новый WndProc (с SetWindowLong(Ptr), дескриптор окна можно получить с помощью QWidget::winId()). В этом WndProc вы можете просто обработать свой конкретный WM_COPYDATA и передать все остальные оконные сообщения старому WndProc.

0 голосов
/ 18 ноября 2009

Для обработки сообщений, которые получает ваше окно, переопределите QCoreApplication :: winEventFilter . Если это не сработает, вы можете взглянуть на QAbstractEventDispatcher .

Для имени класса вы можете попробовать использовать QWidget :: winId вместе с Win32 API. Я бы попробовал найти его для вас, но сейчас не могу, может быть, попробуйте GetClassName .

0 голосов
/ 18 ноября 2009

Вы можете использовать QWinHost из решений Qt, чтобы создать фиктивное окно. После руководство покажет вам, как указать имя вашего класса и проверить цикл событий для вашего сообщения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...