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)