Recevoir des messages WM_COPYDATA dans une application Qt

Je travaille sur une application Windows uniquement, et je dois recevoir des données d’un plug-in Microsoft OneNote. Le plugin est écrit en C # et peut envoyer des messages WM_COPYDATA. Comment recevoir ces messages dans une application C ++ Qt?

J’ai besoin de:

  • Etre capable de spécifier le “nom de la classe” dans lequel une fenêtre est enregistrée comme lorsqu’elle appelle RegisterClassEx, afin que je puisse s’assurer que le plugin envoie les messages WM_COPYDATA à la bonne fenêtre.
  • Avoir access à l’identifiant du message pour vérifier s’il s’agit de WM_COPYDATA et de lParam, qui contient le COPYDATASTRUCT avec les données réelles. Cette information est transmise dans WndProc, mais je ne parviens pas à trouver un hook où je peux intercepter ces messages.

Cela peut être traité dans Qt:

  1. Étendez QWidget avec une classe qui capturera les messages WM_COPYDATA:

    class EventReceiverWindow : public QWidget { Q_OBJECT public: EventReceiverWindow(); signals: void eventData(const QSsortingng & data); private: bool winEvent ( MSG * message, long * result ); }; 
  2. Générez un GUID à définir en tant que fenêtre de QWidget. Titre:

     EventReceiverWindow::EventReceiverWindow() { setWindowTitle("ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver"); } 
  3. Remplacez winEvent pour gérer la structure WM_COPYDATA et émettre un signal lorsque vous l’obtenez:

     bool EventReceiverWindow::winEvent ( MSG * message, long * result ) { if( message->message == WM_COPYDATA ) { // extract the ssortingng from lParam COPYDATASTRUCT * data = (COPYDATASTRUCT *) message->lParam; emit eventData(QSsortingng::fromAscii((const char *)data->lpData, data->cbData)); // keep the event from qt *result = 0; return true; } // give the event to qt return false; } 
  4. Dans une autre classe, vous pouvez utiliser cette classe pour recevoir les chaînes de message:

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

     void OneNoteInterface::handleEventData(const QSsortingng &data) { qDebug() << "message from our secret agent: " << data; } 
  5. Et dans le programme qui envoie les messages, trouvez simplement la fenêtre par la légende unique de la fenêtre. Voici un exemple en C #:

     private struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; [MarshalAs(UnmanagedType.LPStr)] public ssortingng lpData; } private const int WM_COPYDATA = 0x4A; [DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)] static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, ssortingng 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, Ssortingng 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); } } 

    Ensuite vous pouvez:

     IntPtr hwnd = FindWindowByCaption(IntPtr.zero, "ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver"); sendMessageTo(hwnd, "omg hai"); 

Vous pouvez également créer une fenêtre factice uniquement pour recevoir ce message avec l’API Win32. Je suppose que vous n’aurez pas access à un proc de fenêtre de Qt-Window, cela devrait donc être le moyen le plus simple.

Vous pourriez (je ne le ferais pas) également sous-classer la fenêtre en définissant un nouveau WndProc (avec SetWindowLong(Ptr) , le handle de la fenêtre peut être obtenu avec QWidget::winId() ). Dans ce WndProc, vous pouvez simplement gérer votre WM_COPYDATA spécifique et transmettre tous les autres messages de fenêtre à l’ancien WndProc.

Pour gérer les messages que votre fenêtre reçoit, remplacez votre QCoreApplication :: winEventFilter . Si cela ne fonctionne pas, vous pouvez consulter QAbstractEventDispatcher .

Pour le nom de la classe, vous pouvez essayer d’utiliser QWidget :: winId avec l’API Win32. Je voudrais essayer de le trouver pour vous mais je ne peux pas maintenant, peut-être essayer GetClassName .

Vous pouvez utiliser QWinHost from Qt solutions pour créer une fenêtre factice. En suivant le guide , vous apprendrez à spécifier le nom de votre classe et à vérifier la boucle de l’événement pour votre message.