Question

I'm writing an app using Qt Framework and MS RDP component. What I need is to post-process remote computer's desktop image before picturing it on the screen. So, the main question is: is there any way to grab remote desktop picture bitmap from MsRdpClientNotSafeForScripting instance? In other words, I need direct access to memory containing the remote computer's desktop image data.

I'm using ActiveQt to work with the RDP component. I've tried to get an OLE object from AxWidget and paint it on the HBITMAP (code in OnMakeScreenShotSlot()). But, in the first place, it's wrong way to get the screen bitmap, and, well, this method gives the wrong result after all: (attached code) when we press "Screenshot" button the file "screen.bmp" appears which contains white rectangle with text "I'm alive!" in the centre (but not the image of remote computer's desktop). "I'm alive!" is the value of the ConnectedStatusText property of IMsRdpClient instance.

Code is attached. Work environment: 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.";
        }
    }
}
Was it helpful?

Solution

Well, it seems like there is no way to get raw image bytes from MsTsc component.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top