windows 在 Qt 应用程序中接收 WM_COPYDATA 消息
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1755196/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Receive WM_COPYDATA messages in a Qt app
提问by andrewrk
I am working on a Windows-only Qt application, and I need to receive data from a Microsoft OneNote plugin. The plugin is written in C#, and can send WM_COPYDATA messages. How do I receive these messages in a C++ Qt app?
我正在开发一个仅限 Windows 的 Qt 应用程序,我需要从 Microsoft OneNote 插件接收数据。该插件是用 C# 编写的,可以发送 WM_COPYDATA 消息。如何在 C++ Qt 应用程序中接收这些消息?
I need to:
我需要:
- Be able to specify the "class name" a window registers as when it calls RegisterClassEx, so that I can make sure the plugin sends WM_COPYDATA messages to the correct window.
- Have access to the message id to check if it's WM_COPYDATA and lParam, which contains the COPYDATASTRUCT with the actual data. This information is passed in WndProc, but I am unable to find a hook where I can intercept these messages.
- 能够指定窗口在调用 RegisterClassEx 时注册的“类名”,以便我可以确保插件将 WM_COPYDATA 消息发送到正确的窗口。
- 有权访问消息 id 以检查它是否是 WM_COPYDATA 和 lParam,其中包含具有实际数据的 COPYDATASTRUCT。此信息在 WndProc 中传递,但我无法找到可以拦截这些消息的挂钩。
回答by andrewrk
This can all be handled within Qt:
这一切都可以在 Qt 中处理:
Extend QWidget with a class that will capture the WM_COPYDATA messages:
class EventReceiverWindow : public QWidget { Q_OBJECT public: EventReceiverWindow(); signals: void eventData(const QString & data); private: bool winEvent ( MSG * message, long * result ); };
Generate a GUID to set as the QWidget's windowTitle:
EventReceiverWindow::EventReceiverWindow() { setWindowTitle("ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver"); }
Override winEvent to handle the WM_COPYDATA structure and emit a signal when you get it:
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; }
In another class, you can use this class to receive the message strings:
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; }
And in the program that is sending the messages, simply find the windowby the unique window caption. Here's an example in 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); } }
then you can:
IntPtr hwnd = FindWindowByCaption(IntPtr.zero, "ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver"); sendMessageTo(hwnd, "omg hai");
使用将捕获 WM_COPYDATA 消息的类扩展 QWidget:
class EventReceiverWindow : public QWidget { Q_OBJECT public: EventReceiverWindow(); signals: void eventData(const QString & data); private: bool winEvent ( MSG * message, long * result ); };
生成一个 GUID 来设置为 QWidget 的 windowTitle:
EventReceiverWindow::EventReceiverWindow() { setWindowTitle("ProjectName-3F2504E0-4F89-11D3-9A0C-0305E82C3301::EventReceiver"); }
覆盖 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; }
在另一个类中,您可以使用此类来接收消息字符串:
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; }
在发送消息的程序中,只需通过唯一的窗口标题找到窗口。这是 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");
回答by OregonGhost
You can also create a dummy window just for receiving that message with the Win32 API. I guess you won't have access to a Qt-Window's window proc, so this should be the easiest way.
您还可以创建一个虚拟窗口,仅用于使用 Win32 API 接收该消息。我猜您将无法访问 Qt-Window 的窗口过程,所以这应该是最简单的方法。
You could(I wouldn't) also subclass the window by setting a new WndProc (with SetWindowLong(Ptr)
, the window's handle can be obtained with QWidget::winId()
). In this WndProc, you could just handle your specific WM_COPYDATA and pass all other window messages to the old WndProc.
您也可以(我不会)通过设置一个新的 WndProc 来子类化窗口(使用SetWindowLong(Ptr)
,可以使用 获得窗口的句柄QWidget::winId()
)。在这个 WndProc 中,您可以只处理您的特定 WM_COPYDATA 并将所有其他窗口消息传递给旧的 WndProc。
回答by Idan K
To handle messages your window receives, override your QCoreApplication::winEventFilter. If that doesn't work you can take a look at QAbstractEventDispatcher.
要处理您的窗口收到的消息,请覆盖您的QCoreApplication::winEventFilter。如果这不起作用,您可以查看QAbstractEventDispatcher。
For the class name you could try using QWidget::winIdalong with Win32 API. I would try and find it for you but I can't right now, maybe try GetClassName.
对于类名,您可以尝试使用QWidget::winId和 Win32 API。我会尝试为您找到它,但我现在不能,也许尝试GetClassName。