2009-11-18 94 views
2

我正在使用僅支持Windows的Qt應用程序,並且需要從Microsoft OneNote插件接收數據。該插件是用C#編寫的,可以發送WM_COPYDATA消息。我如何在C++ Qt應用程序中接收這些消息?在Qt應用程序中接收WM_COPYDATA消息

我需要:

  • 能夠指定「類名」窗口寄存器,當它調用RegisterClassEx,這樣我就可以確保插件WM_COPYDATA發送消息到正確的窗口。
  • 有權訪問消息ID以檢查它是否包含WM_COPYDATA和lParam,其中包含帶有實際數據的COPYDATASTRUCT。這個信息在WndProc中傳遞,但我無法找到一個可以攔截這些消息的鉤子。

回答

6

這可以全部在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的的WINDOWTITLE:

    EventReceiverWindow::EventReceiverWindow() 
    { 
        setWindowTitle("ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver"); 
    } 
    
  3. 重寫winEvent來處理WM_COPY數據結構,併發出信號,當你得到它:

    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"); 
    
0

您可以使用Qt解決方案中的QWinHost來創建一個虛擬窗口。以下the guide會告訴你如何指定你的類名並檢查你的消息的事件循環。

+0

可惜我不願意付出... :(有另一種方式 – andrewrk 2009-11-18 10:57:38

+0

其實Qt的解決方案有一個LGPL許可證 - 您不必爲許可證支付 – andrewrk 2009-11-18 23:40:27

1

您也可以創建一個虛擬窗口,僅用於使用Win32 API接收該消息。我想你將無法訪問Qt-Window的窗口過程,所以這應該是最簡單的方法。

可能(我不會)還通過設置新的WndProc子類的窗口(與SetWindowLong(Ptr),該窗口的句柄可以用QWidget::winId()獲得)。在這個WndProc中,你可以處理你特定的WM_COPYDATA並將所有其他的窗口消息傳遞給舊的WndProc。

0

要處理窗口收到的消息,請覆蓋您的QCoreApplication::winEventFilter。如果這不起作用,你可以看看QAbstractEventDispatcher

對於類名,您可以嘗試使用QWidget::winId以及Win32 API。我會盡力爲你找到它,但現在我不能,也許試試GetClassName

+0

我需要「Set class name」。另外,winEventFilter爲我提供參數MSG * msg,long * result,其中不包含lParam,其中包含實際發送的消息與WM_COPYDATA。 – andrewrk 2009-11-18 21:07:21

+0

進一步調查,它看起來像味精是一個結構,包括消息ID以及lParam,所以這個解決方案非常棒。 stackoverflow的安全性不會讓我改變我的投票你的答案。 – andrewrk 2009-11-18 21:14:35

+0

此外,這仍然不能解決我需要能夠設置類名稱的問題。 – andrewrk 2009-11-18 21:19:28

相關問題