qt createWindowContainer embed realvnc

举报
Amrf 发表于 2019/03/12 19:52:47 2019/03/12
【摘要】 ​实际使用的vnc服务端是realvnc,后来实际使用的方案是vncviewer嵌入;

实际使用的vnc服务端是realvnc 5,后来实际使用的方案是vncviewer嵌入;pic.PNG

参考文档:

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++相关的我在另一篇博客中说明=========================



【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。