qt createWindowContainer embed realvnc
实际使用的vnc服务端是realvnc 5,后来实际使用的方案是vncviewer嵌入;
参考文档:
https://archive.realvnc.com/products/vnc/documentation/4.2/unix/man/vncviewer.html
https://serverfault.com/questions/224434/realvnc-command-line-switches
https://stackoverflow.com/questions/12679464/run-an-external-application-inside-a-qwidget
https://stackoverflow.com/questions/18472840/qt-how-to-embed-an-application-into-qt-widget
https://github.com/BackupGGCode/portable-executable-library (import_adder.exe注意至少需要一个导出函数)
android 下的vncserver
https://blog.csdn.net/richu123/article/details/51438009
时间旧了,有的代码具体是解决什么问题的我也记不清了;
依稀记得主体上分为两部分,一部分是嵌入的工具程序;
另一部分是用于注入realvnc客户端的dll(为了捕捉客户端很早的窗口句柄创建采用的静态注入);
//=======这步逻辑应该是当时出现嵌入后的vnc客户端无法输入按键文字的问题的解决方案==========
class NativeFilter : public QAbstractNativeEventFilter { public: bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) { if(pMain!=NULL) { WidgetContainer* pcover = pMain->getVncCover(); if(pcover!=NULL){ HWND hwnd = (HWND)pcover->getVncHwnd(); if (hwnd!=0 && IsWindow(hwnd) && pcover->rect().contains(pcover->mapFromGlobal(QCursor::pos()))) { MSG *param = static_cast<MSG *>(message); switch (param->message){ case WM_SETFOCUS: case WM_KILLFOCUS: case WM_KEYDOWN: case WM_SYSKEYDOWN: case WM_CHAR: case WM_UNICHAR: case WM_KEYUP: case WM_SYSKEYUP: case WM_HOTKEY: case WM_DEADCHAR: case WM_SYSDEADCHAR: case WM_APPCOMMAND: case WM_INPUTLANGCHANGEREQUEST: case WM_INPUTLANGCHANGE: case WM_IME_STARTCOMPOSITION: case WM_IME_ENDCOMPOSITION: case WM_IME_COMPOSITION: //case WM_IME_KEYLAST: case WM_IME_SETCONTEXT: case WM_IME_NOTIFY: case WM_IME_CONTROL: case WM_IME_COMPOSITIONFULL: case WM_IME_SELECT: case WM_IME_CHAR: case WM_IME_REQUEST: case WM_IME_KEYDOWN: case WM_IME_KEYUP: case WM_SYSCHAR: //case WM_SYSCOMMAND: //case WM_COMMAND: case WM_ACTIVATE: case WM_SETHOTKEY: case WM_GETHOTKEY: //qDebug( QString("%0 hwnd=%1").arg("vnc1 native WM_SYSKEYUP").arg((int)param->hwnd).toLocal8Bit().data()); SendMessage(hwnd,param->message,param->wParam,param->lParam);//PostMessage return true; default: break; } } } } return false; } }; NativeFilter *closeFilter = new NativeFilter; app.installNativeEventFilter(closeFilter);
//=================这部分代码是解决从来没有运行过vnc客户端的机器上面的异常=======================
const std::wstring testSubKey = L"SOFTWARE\\RealVNC\\vncviewer"; winreg::RegKey key(HKEY_CURRENT_USER, testSubKey); key.SetStringValue(L"Scaling", L"AspectFit"); key.SetStringValue(L"EulaAccepted", L"xxxxxxxxxxxx"); key.Close(); winreg::RegKey key1(HKEY_CURRENT_USER,L"SOFTWARE\\RealVNC\\vncviewer\\KnownHosts"); WORD val = 0x0101; key1.SetBinaryValue(L"xxxxxxxxxxxx::5900/extra",(void*)&val,2); key1.SetBinaryValue(L"xxxxxxxxx::5900/extra",(void*)&val,2); key1.Close();
//============为了保存连接设置可以通过-config传入.vnc的连接配置文件名======================
.vnc文件一般结构
[Connection] Host=xx.xx.xx.xx Password=加密的,加密方式(https://github.com/paulmarsy/VncPassword/tree/master/src/vncpassword) [Options] ShareFiles=1 EnableChat=1 Encryption=Server UserName= Scaling=AspectFit ServerCutText=1 ClientCutText=1 SendKeyEvents=1 SendPointerEvents=1 UseLocalCursor=1
//=========嵌入服务端和vnc客户端之间的交互我当时采用的是QSharedMemory
用于获取一些关注的客户端句柄的创建和显示
//==================隐藏嵌入的客户端的任务栏图标========================
void ShowInTaskbar(HWND hWnd, BOOL bshow) { HRESULT hr; ITaskbarList *pTaskbarList; hr = CoCreateInstance(CLSID_TaskbarList,NULL,CLSCTX_INPROC_SERVER, IID_ITaskbarList,(void**)&pTaskbarList); if ( hr == S_OK ){ hr = pTaskbarList->HrInit(); if ( hr == S_OK ){ if(bshow){ pTaskbarList->AddTab(hWnd); }else{ pTaskbarList->DeleteTab(hWnd); } } pTaskbarList->Release(); } }
//=======嵌入服务端在收到客户端窗口句柄创建之后获取到hwnd==============
if(m_vncDlg==NULL){ m_vncDlg = QWindow::fromWinId((WId) hwnd); this->m_vncwidget = QWidget::createWindowContainer(m_vncDlg,this); ShowInTaskbar((HWND)this->m_vncwidget->winId(),false); if(m_layout==NULL) m_layout=new QGridLayout(this); m_layout->addWidget(this->m_vncwidget,0,0); }
//========嵌入服务端在收到客户端窗口显示之后重设窗口大小=======
this->m_vncwidget->setGeometry(this->geometry());
//========嵌入服务端在收到客户端窗口最大化之后保存风格=============
if (maxMode== false){ m_enOrigWindowFlags = this->windowFlags(); m_pParent=(QWidget*)this->parent(); m_ind=((QSplitter*)m_pParent)->indexOf(this); ((QSplitter*)m_pParent)->replaceWidget(m_ind,m_tmp); this->setParent(NULL); this->setWindowFlags( Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint); this->showMaximized(); this->showFullScreen(); maxMode = true; }
//========嵌入服务端在收到客户端窗口恢复后还原风格=====
if (maxMode){ this->overrideWindowFlags(m_enOrigWindowFlags); ((QSplitter*)m_pParent)->replaceWidget(m_ind,this); this->show(); maxMode = false; ShowInTaskbar((HWND)this->m_vncDlg->winId(),false); }
//=========VNC客户端部分,鼠标右键时添加active和setfocus消息以处理嵌入后获取不到焦点消息的问题======================
LRESULT CALLBACK hookMouseProc( int nCode, WPARAM wParam,LPARAM lParam) { LPMOUSEHOOKSTRUCT inf =(LPMOUSEHOOKSTRUCT)lParam; switch(nCode) { case HC_ACTION: //printf("action x=%d,y=%d\n",inf->pt.x,inf->pt.y); switch(wParam) { case WM_LBUTTONDOWN: PostMessage(inf->hwnd,WM_ACTIVATE,WA_ACTIVE,0); PostMessage(inf->hwnd,WM_SETFOCUS,0,0); ...
//=========在SetWindowPos函数上挂钩泳衣检测最大化和恢复======================
BOOL WINAPI newSetWindowPos( HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, UINT uFlags) { if(aCDesktopWin && hWnd==wndMap[QString("vwr::CDesktopWin")]) { if(hWndInsertAfter==HWND_TOP && uFlags==SWP_FRAMECHANGED){//全屏 pClient->downShareMemory(); ... return true; }else if(hWndInsertAfter==HWND_NOTOPMOST && uFlags==SWP_FRAMECHANGED){ pClient->downShareMemory(); ... return true; } } return oldSetWindowPos(hWnd,hWndInsertAfter,X,Y,cx,cy,uFlags); }
//==============atom=IsBadStringPtr======================
if(GetAtomNameA((ATOM)lpszClass,bu,127)>0){ LPCWSTR lpszName = IsBadStringPtr(lpCreate->lpcs->lpszName,128)?L"null":lpCreate->lpcs->lpszName; GetClassName(hWnd,szText,127); int id=GetWindowLong(hWnd,GWLP_ID); GetWindowText(hWnd,szText1,GetWindowTextLength(hWnd)+1);
--这部分又记不清了,挂钩相关的也忘的差不多了可以打拳去了
//=========python嵌入c++相关的我在另一篇博客中说明=========================
- 点赞
- 收藏
- 关注作者
评论(0)