在Qt应用程序中接收WM_COPYDATA消息

时间:2009-11-18 10:53:38

标签: c++ windows qt

我正在开发一个仅限Windows的Qt应用程序,我需要从Microsoft OneNote插件接收数据。该插件是用C#编写的,可以发送WM_COPYDATA消息。如何在C ++ Qt应用程序中收到这些消息?

我需要:

  • 能够指定一个窗口注册的“类名”,就像它调用RegisterClassEx一样,这样我就可以确保插件将WM_COPYDATA消息发送到正确的窗口。
  • 可以访问消息ID以检查它是否为WM_COPYDATA和lParam,其中包含带有实际数据的COPYDATASTRUCT。此信息在WndProc中传递,但我无法找到可以拦截这些消息的钩子。

4 个答案:

答案 0 :(得分:6)

这一切都可以在Qt中处理:

  1. 使用将捕获WM_COPYDATA消息的类扩展QWidget:

        class EventReceiverWindow : public QWidget
    {
        Q_OBJECT
    public:
        EventReceiverWindow();
    
    signals:
        void eventData(const QString & data);
    
    private:
        bool winEvent ( MSG * message, long * result );
    };
    
  2. 生成GUID以设置为QWidget的windowTitle:

    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. 在发送邮件的程序中,只需find the window唯一的窗口标题即可。这是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 :(得分:1)

您还可以创建一个虚拟窗口,仅用于使用Win32 API接收该消息。我想你将无法访问Qt-Window的窗口过程,所以这应该是最简单的方法。

可以(我不会)通过设置一个新的WndProc(SetWindowLong(Ptr)来对窗口进行子类化,窗口的句柄可以用QWidget::winId()获得)。在这个WndProc中,你可以只处理你的特定WM_COPYDATA并将所有其他窗口消息传递给旧的WndProc。

答案 2 :(得分:0)

您可以使用Qt解决方案中的QWinHost来创建虚拟窗口。 the guide后面会显示如何指定您的班级名称并检查邮件的事件循环。

答案 3 :(得分:0)

要处理您的窗口收到的消息,请覆盖您的QCoreApplication::winEventFilter。如果这不起作用,您可以查看QAbstractEventDispatcher

对于类名,您可以尝试使用QWidget::winId和Win32 API。我会尝试为你找到它,但我现在不能,也许试试GetClassName