我正在寫一個應用程序使用Qt框架和MS RDP組件。我需要的是在屏幕上顯示它之前對遠程計算機的桌面圖像進行後處理。 所以,主要問題是:有沒有辦法從MsRdpClientNotSafeForScripting實例中獲取遠程桌面圖片位圖? 換句話說,我需要直接訪問包含遠程計算機桌面圖像數據的內存。有沒有辦法從MS RDP組件(AxMSTSCLib)獲取桌面圖片位圖?
我使用ActiveQt來處理RDP組件。我試圖從AxWidget
獲得一個OLE對象,並在HBITMAP
(代碼OnMakeScreenShotSlot()
)上繪製它。但是,首先,獲取屏幕位圖是錯誤的方法,當然,這個方法畢竟會給出錯誤的結果:(附加代碼)當我們按下「屏幕截圖」按鈕時會出現文件「screen.bmp」,其中包含帶文字的白色矩形「我還活着!」在中心(而不是遠程計算機桌面的圖像)。 「我還活着!」是IMsRdpClient實例的ConnectedStatusText
屬性的值。
附上代碼。工作環境:Windows 8,MSVC 2012,Qt 4.8.5,x86。
Main.cpp的:
#include <QApplication>
#include "containerwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ContainerWidget *w = new ContainerWidget();
w->show();
return a.exec();
}
containerwidget.h:
#ifndef CONTAINERWIDGET_H
#define CONTAINERWIDGET_H
#include <QWidget>
#include <QAxWidget>
#include <QAxObject>
#include <QPushButton>
class ContainerWidget : public QWidget
{
Q_OBJECT
QAxWidget *m_rdpWidget;
QPushButton *m_screenshotButton;
void initRdpWidget();
public:
ContainerWidget(QWidget *parent = 0);
~ContainerWidget();
public slots:
void OnMakeScreenshotSlot();
};
#endif // CONTAINERWIDGET_H
containerwidget.cpp:
#include "containerwidget.h"
#include <QBoxLayout>
#include <QDebug>
#include <QUuid>
#include <comdef.h>
ContainerWidget::ContainerWidget(QWidget *parent) :
QWidget(parent)
{
initRdpWidget();
m_screenshotButton = new QPushButton("Make screenshot", this);
connect(m_screenshotButton, SIGNAL(clicked()), this, SLOT(OnMakeScreenshotSlot()));
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->addWidget(m_rdpWidget);
mainLayout->addWidget(m_screenshotButton);
}
ContainerWidget::~ContainerWidget()
{
if (m_rdpWidget) {
m_rdpWidget->dynamicCall("Disconnect()");
}
}
void ContainerWidget::initRdpWidget()
{
m_rdpWidget = new QAxWidget();
m_rdpWidget->setControl("{7cacbd7b-0d99-468f-ac33-22e495c0afe5}");
m_rdpWidget->dynamicCall("SetDesktopWidth(int)", 800);
m_rdpWidget->dynamicCall("SetDesktopHeight(int)", 600);
m_rdpWidget->dynamicCall("SetServer(QString)", "ip");
m_rdpWidget->dynamicCall("SetUserName(QString)", "user");
m_rdpWidget->dynamicCall("SetConnectedStatusText(QString)", "I'm alive!");
QAxObject *advancedSettings2 = m_rdpWidget->querySubObject("AdvancedSettings2");
if (advancedSettings2) {
advancedSettings2->dynamicCall("SetClearTextPassword(QString)", "password");
advancedSettings2->dynamicCall("SetAuthenticationLevel(int)", 2);
}
m_rdpWidget->dynamicCall("Connect()");
m_rdpWidget->setFixedSize(800, 600);
m_rdpWidget->setVisible(true);
}
void ContainerWidget::OnMakeScreenshotSlot()
{
if (m_rdpWidget != NULL) {
IOleObject *oleObj = NULL;
m_rdpWidget->queryInterface((QUuid)IID_IOleObject, (void **)&oleObj);
if (oleObj == NULL) {
qDebug() << "bad ole obj.";
return;
}
IViewObject2 *iviewObj2 = NULL;
HRESULT hres = oleObj->QueryInterface(IID_IViewObject2, (void **)&iviewObj2);
if (SUCCEEDED(hres)) {
SIZE picSize;
hres = iviewObj2->GetExtent(DVASPECT_CONTENT, -1, NULL, &picSize);
if (SUCCEEDED(hres)) {
HDC dc = GetDC(0);
SIZE adjustedSize;
adjustedSize.cx = MulDiv(picSize.cx, GetDeviceCaps(dc, LOGPIXELSX), 2540);
adjustedSize.cy = MulDiv(picSize.cy, GetDeviceCaps(dc, LOGPIXELSY), 2540);
ReleaseDC(0, dc);
RECT r;
SetRect(&r, 0, 0, adjustedSize.cx, adjustedSize.cy);
HDC tmpDC = GetDC(0);
HDC memDC = CreateCompatibleDC(tmpDC);
HBITMAP hBmp = CreateCompatibleBitmap(memDC, adjustedSize.cx, adjustedSize.cy);
HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, hBmp);
OleDraw(oleObj, DVASPECT_CONTENT, memDC, &r);
QPixmap p = QPixmap::fromWinHBITMAP(hBmp);
p.save(QString("screen.bmp"));
SelectObject(memDC, oldBmp);
DeleteDC(memDC);
ReleaseDC(0, tmpDC);
} else {
qDebug() << "bad picSize.";
}
} else {
qDebug() << "bad iviewobj2.";
}
}
}