ATL的dll与Qt程序通信和传递消息

ATL的dll与Qt程序通信和传递消息

开发时遇到的需要完成的需求是:Windows右键菜单拓展,增加菜单项,但具体增加的菜单项的名称需要从Qt应用程序中获取状态进而显示不同名称,因此需要ATL的dll与Qt应用程序之前进程消息传递和通信。

Windows下发送消息的方法有几种:
SendMessage:阻塞的,等窗口程序处理完消息再返回。
PostMessage:不阻塞,将消息放到消息队列中立即返回。通过指定目标窗口句柄来确定目标线程,通常情况下由窗口过程来处理消息。
SendMessageTimeout:相当于加了超时时间的SendMessage。
PostThreadMessage:直接指定目标线程ID来确定目标线程,没有目标窗口,只能在消息循环中直接根据消息类型做相应的处理。

发送消息时可以广播HWND_BROADCAST,但是广播只能发给所有的顶层窗口,非顶层是收不到的。并且如果用SendMessage发送广播,有程序没有返回时就会阻塞,因此应使用PostMessage发送广播消息。

如果想传递消息,则必须使用WM_COPYDATA消息,而这种消息只能用SendMessage发送,不能用PostMessage发送。但有时又担心超时,因此我们使用SendMessageTimeout来发送WM_COPYDATA消息。避免程序阻塞。
发送WM_COPYDATA消息,实际上会传递COPYDATASTRUCT结构体,

typedef struct tagCOPYDATASTRUCT {
  ULONG_PTR dwData;
  DWORD     cbData;
  PVOID     lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;

其中dwData是自定义数据,我们可以通过RegisterWindowMessage注册一个窗口消息,保证该消息在系统范围内是唯一的。这样接收数据时就可以判断是否是我们自己发出去的消息。cbData是发送的字符串的长度,lpData是发送的字符串指针。

首先要明确的是,我们此次做的消息通知都是发送到窗口的,因此无论是对于dll和Qt的客户端,都应该是以窗口为基础接收消息。客户端的窗口很容易找到,因为本来就是桌面客户端。dll是没有窗口的,如何接收消息和发送消息呢?
此处的方案是给dll创建一个隐藏窗口。指定类名,窗口不能接受广播消息,但可以通过FindWindow或FindWindowEx查找到该类名的窗口句柄,向指定窗口发送消息。
具体的代码如下:

dll中涉及的代码:

创建自定义消息类型

const UINT WM_WSW_Message = ::RegisterWindowMessage(_T("dllCustomMessage"));

发送消息:

//参数分别是要发送的字符串和RegisterWindowMessage返回值
void sendMsg(std::string strJson, const UINT strMessage)
{
	//查找指定标题名的窗口句柄
    HWND hwnd = FindWindowEx(nullptr, nullptr, nullptr, _T("Client"));
    if (hwnd)
    {
        LRESULT copyDataResult;
        COPYDATASTRUCT cpd;
        cpd.dwData = strMessage;
        cpd.cbData = strJson.length();
        cpd.lpData = (void*)strJson.c_str();
        //发送消息
        copyDataResult = SendMessageTimeout(hwnd, WM_COPYDATA, NULL, (LPARAM)&cpd, SMTO_ABORTIFHUNG, 15000, 0);
       
    }
}

创建隐藏窗口,接收消息

//创建隐藏窗口
void createMsgWnd()
{
    if (m_hWnd != NULL) 
    	return;

    HINSTANCE hInst = GetModuleHandle(0);
    LPCTSTR lpWndClsName = _T("customHideWindow");
    WNDCLASS wc = { 0 };
    wc.lpszClassName = lpWndClsName;
    wc.style = CS_NOCLOSE;
    wc.hInstance = hInst;
    wc.lpfnWndProc = __WindowProc;
    //注册这个类
    if (RegisterClass(&wc))
    {
        //不能接受广播消息 创建窗口
        m_hWnd = CreateWindow(lpWndClsName, lpWndClsName, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInst, this);      
    }
}

//回调函数,有消息来通过回调得到
LRESULT CALLBACK __WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CAISearch* pThis = NULL;

    if (uMsg == WM_NCCREATE) {
        LPCREATESTRUCT lpCS = reinterpret_cast<LPCREATESTRUCT>(lParam);
        pThis = static_cast<CATLTestMenu*>(lpCS->lpCreateParams);
        ATLASSERT(NULL != pThis);
        ::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG>(pThis));
    }
    else
    {
        pThis = reinterpret_cast<CATLTestMenu*>(::GetWindowLongPtr(hwnd, GWLP_USERDATA));
        if (NULL == pThis || pThis->m_hWnd != hwnd) {
            return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
        }
        //使用类自己的方法处理消息
        return pThis->handleMessage(uMsg, wParam, lParam);
    }

    return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}

LRESULT CAISearch::handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	//如果是传递字符串的消息
    if (uMsg == WM_COPYDATA) {
        const UINT WM_WSW_Message = ::RegisterWindowMessage(_T("clientCustomMessage"));
        COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)lParam;
        if (pCopyData->dwData == WM_WSW_Message)
        {
        	//获取到客户端发送过来的数据
            string strJson = string((char*)pCopyData->lpData, pCopyData->cbData);           
            return S_OK;
        }
    }
    //关闭窗口的消息
    else if (uMsg == WM_CLOSE)
    {
        HINSTANCE hInst = GetModuleHandle(0);
        LPCTSTR lpWndClsName = _T("customHideWindow");
        //销毁窗口
        DestroyWindow(m_hWnd);
		//反注册这个类
        UnregisterClass(lpWndClsName, hInst);
    }

    return ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
}

手动关闭隐藏窗口

//向隐藏窗口句柄发送关闭消息
SendMessage(m_hWnd, WM_CLOSE, 0, NULL);

客户端中涉及代码:

主窗口接收Windows消息,主窗口集成QWidget,重载nativeEvent方法,消息类型为"windows_generic_MSG"代表windows平台

bool nativeEvent(const QByteArray & eventType, void * message, long * result)
    {
		//windows平台
        if (eventType == "windows_generic_MSG") 
        {
            MSG* msg = reinterpret_cast<MSG*>(message); //
			//消息类型
            if (msg->message == WM_COPYDATA)
            {
                COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*)msg->lParam;
                //消息是注册的消息,对上了,证明是dll发送的
                const UINT WM_WSW_Message = ::RegisterWindowMessage(_T("dllCustomMessage"));
                if(pCopyData->dwData == WM_WSW_Message)
                {
                	//成功拿到dll发送的数据,进行下一步处理
                    string strJson = string((char*)pCopyData->lpData, pCopyData->cbData);
                    return true;
                }
            }
        }

        return QWidget::nativeEvent(eventType, message, result);
    }

向dll发送消息

void sendMsg(std::string strJson)
    {
    	const UINT strMessage  = RegisterWindowMessage(_T("clientCustomMessage")); 
        LRESULT copyDataResult;
        COPYDATASTRUCT cpd;
        cpd.dwData = strMessage;
        cpd.cbData = strJson.length();
        cpd.lpData = (void*)strJson.c_str();

        HWND hParentWnd = NULL;
        HWND hChild = NULL;
        string str = "customHideWindow";
        WCHAR wsz[64];
        swprintf(wsz, 100, L"%S", str.c_str());
        LPCWSTR szName = wsz;
        //查找dll那个隐藏窗口的句柄
        hParentWnd = ::FindWindow(NULL, szName);
        if (hParentWnd != NULL)
        {
        	//找到了句柄,发送消息,消息类型是自定义消息类型
            copyDataResult = SendMessage(hParentWnd, WM_COPYDATA, NULL, (LPARAM)&cpd);
        }     
    }

有问题欢迎大家一起交流探讨学习。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值