Server does not read from clients - c++

Gist of the program: The server creates n client processes. On the client, the user enters a character string that is sent to the server. On the server, the string is processed as follows: the frequency of occurrence of vowels and numbers in the entered string is calculated. This information is then sent to the client.
Two programs (server and clients) were based on console editions(They works perfectly). When I add QT support to server, console clients and gui server works fine, but when i add gui to client - it stop working and i don't know what to do.
I guess the problem is not even named pipes, but clumsy code in terms of Qt (in client). The client outputs that a connection to the server has been established, and the server indicates that it cannot read a string from the pipe.
Server can create n gui clients and then, when i try to write string to client, client closes.
Code of the client:
gui_pipe_client.h:
#pragma once
#include <LotsOfLibraries...>
class Window : public QWidget {
Q_OBJECT // этот макрос должен включаться в классы, которые объявляют свои собственные сигналы и слоты
private:
HANDLE. m_hndlNP;
public:
Window(QWidget *parent = 0, HANDLE m_hndlNP = NULL);
private slots:
int OnSend();
private:
QLabel *lbl;
QLineEdit *textfield;
QPushButton *button_send;
};
gui_pipe_client.cpp:
#include "gui_pipe_client.h"
#include <QGridLayout>
#include <thread> //!NEW!
using namespace std;
#define PIPE_TIMEOUT 5000
#define BUFSIZE 4096
Window::Window(QWidget *parent, HANDLE hndlNP)
: QWidget(parent), m_hndlNP(hndlNP){
QLineEdit *textfield = new QLineEdit(this);
textfield->setPlaceholderText("Enter string...");
QPushButton *button_send = new QPushButton("Send", this);
QPushButton *button_quit = new QPushButton("Quit", this);
lbl = new QLabel("kjiqofj13fjio2;3fjl;3jiofj2l3;fij3;fioj423j;fj32jf;o3f", this);
lbl->setWordWrap(true);
QGridLayout *grid = new QGridLayout(this);
grid->addWidget(textfield, 0, 0);
grid->addWidget(button_send, 1, 0);
grid->addWidget(button_quit, 2, 0);
grid->addWidget(lbl, 3, 0);
setLayout(grid);
connect(button_send, &QPushButton::clicked, this, &Window::OnSend); // привязка сигнала и слота
connect(button_quit, &QPushButton::clicked, qApp, &QApplication::quit); // signal - slot
}
int Window::OnSend() {
button_send->setEnabled(false);
char text[1024];
const QByteArray stringData = textfield->text().toUtf8();
//char text[100];
text[qMin(1023,stringData.size())]='\0';
std::copy(stringData.constBegin(),stringData.constBegin()+qMin(1023,stringData.size()),text);
printf("%s", text);
char answer[1024];
DWORD read_bytes;
DWORD written_bytes;
if (WriteFile(m_hndlNP, text, 1024, &written_bytes, NULL)) {
if (!ReadFile(m_hndlNP, answer, 1024, &read_bytes, NULL)) {
//printf("ReadFile failed with %d.\n", GetLastError());
system("pause"); // TEMPORARY
//return EXIT_FAILURE;
}
}
else {
printf("WriteFile failed with %d.\n", GetLastError());
system("pause"); // TEMPORARY
//return EXIT_FAILURE;
}
//cout << "Writting and reading was successful\n";
lbl->setText((QString) (answer));
// ***CLOSING PIPE CONNECTION***
CloseHandle(m_hndlNP);
//QApplication::quit();
}
main.cpp:
#include "gui_pipe_client.h"
using namespace std;
int main(int argc, char *argv[]) {
cout << "Client is launched\n";
HANDLE hndlNP = CreateFile(
TEXT("\\\\.\\pipe\\os_lab4_pipe"),
GENERIC_READ | GENERIC_WRITE,
NULL, // Prevents other processes from opening a file or device
NULL, // cannot be inherited by any child processes
OPEN_EXISTING,
NULL, // no attributes
NULL // no template
);
if (hndlNP == INVALID_HANDLE_VALUE) {
printf("CreateFile error\n");
cout << "CreateFile error\n";
//return EXIT_FAILURE;
}
cout << "Pipe connection established\n";
QApplication app(argc, argv);
Window window(0, hndlNP);
window.resize(600, 600);
window.setWindowTitle("Pipe client");
window.show();
return app.exec();
}

Related

How to constantly read UDP packets in QT?

I am sending myself UDP packets generally using this method here:
How to receive proper UDP packet in QT?
I am setting up modes so that in Write mode, it sends UDP packets every second, and in Read mode, it just receives packets. To do this I set up a simple boolean variable called readmode when readmode = true it reads and writes when = false. I left the connect(socket, SIGNAL(readyRead()), this,SLOT(readyRead())); and the call to the send function in the MainWindow constructor and put the if statements, testing the state of readMode to actually do something, in the send function and readyRead() function themselves.
My problem is that I only receive packets whenever I start the program in Read mode first before opening the window for the program to write. If I start sending packets before I open the Read program, I get nothing.
For clarification I am opening two instances of this program and I set one to Read and the other to Write, but the Read has to be started first for it to work, but once states are changed, it stops working.
How can I get it to read all the time?
Code sample:
bool readMode = true; //Write mode = false, Read Mode = true
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer = new QTimer(this);
timer->start(1000);
ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Read");
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText("Write");
out_socket = new QUdpSocket(this);
out_socket->bind(60500);
in_socket = new QUdpSocket(this);
in_socket->bind(60510);
connect(timer, SIGNAL(timeout()),this,SLOT(UDP_test()));
connect(in_socket,SIGNAL(readyRead()),this,SLOT(readyRead()));
}
void MainWindow::UDP_test() //Write Mode
{
if (readMode == false) //Write Mode
{
QByteArray Data;
Data.append(fullResultString);
out_socket->writeDatagram(Data,QHostAddress("192.168.127.10"),60510);
}
void MainWindow::readyRead() //Read Mode
{
if (readMode == true) //Readmode
{
while(in_socket->hasPendingDatagrams())
{
QByteArray UDPBuffer;
UDPBuffer.resize(in_socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
in_socket->readDatagram(UDPBuffer.data(),UDPBuffer.size(), &sender, &senderPort);
}
That's to be expected: each invocation of the process attempts to bind the input socket. The first time, with the socket not bound yet - it succeeds. The second time - it fails, as the port is already bound - so reading won't work. Everything aside, the code never checks for errors, and thus leaves the user (i.e. you) unaware that things have failed. With error checking it'd be obvious why it doesn't work. The output socket doesn't need to be bound to an explicitly specified port number. The input socket should only be bound when the program is in receive mode.
QUdpSocket doesn't emit readyRead if it already contains (not read) datagramms when it receives a new datagram. You source code doesn't complete. So we can't see how do you change your global variable 'readMode'.
here the simple demo application:
#include <QApplication>
#include <QWidget>
#include <QUdpSocket>
#include <QPushButton>
#include <QListWidget>
#include <QGridLayout>
#include <QDebug>
#include <QUuid>
int main( int argc, char** argv ) {
QApplication app( argc, argv );
QWidget form;
auto*const log_widget = new QListWidget( &form );
auto*const client = new QUdpSocket( qApp );
auto*const server = new QUdpSocket( qApp );
const quint16 TEST_PORT = 31088;
if( ! server->bind( QHostAddress::LocalHost, TEST_PORT ) ) {
exit( 1 );
}
QObject::connect( server, &QUdpSocket::readyRead, [=]() {
log_widget->insertItem( 0, "readyRead() has been received" );
});
auto*const write_button = new QPushButton( "&Write", &form );
QObject::connect( write_button, &QPushButton::clicked, [=]() {
const auto packet = QUuid::createUuid().toByteArray();
client->writeDatagram( packet, QHostAddress::LocalHost, TEST_PORT );
log_widget->insertItem( 0, "A datagram has been sent." );
});
auto*const read_button = new QPushButton( "&Read", &form );
QObject::connect( read_button, &QPushButton::clicked, [=]() {
if( server->hasPendingDatagrams() ) {
const int size = static_cast< int >( server->pendingDatagramSize() );
if( size > 0 ) {
QByteArray packet;
packet.resize( size );
server->readDatagram( packet.data(), size );
log_widget->insertItem( 0, "Read OK: datagram have been read." );
} else {
log_widget->insertItem( 0, "Read Error: invalid datagram size." );
}
} else {
log_widget->insertItem( 0, "Read Error: there is no any datagram." );
}
});
auto*const check_button = new QPushButton( "&Check", &form );
QObject::connect( check_button, &QPushButton::clicked, [=]() {
if( server->hasPendingDatagrams() ) {
log_widget->insertItem( 0, "Check: there is at least one datagram." );
} else {
log_widget->insertItem( 0, "Check: there is no any datagram." );
}
});
auto*const grid = new QGridLayout( &form );
grid->addWidget( write_button, 0, 0 );
grid->addWidget( read_button, 0, 1 );
grid->addWidget( check_button, 0, 2 );
grid->addWidget( log_widget, 1, 0, 1, 3 );
form.show();
return app.exec();
}

How to embed one qApplication's GUI into another qApplication's mainWindow?

There are two qApplications A & B, they can be executed separately with their own main window.
I would like to achieve the following:
1) //Open Application B.
//Inside App B's code
QProcess* proA = new QProcss();
proA->start(A.exe) //Under Windows7
2) //Instead of showing app A in a separate window.
//I would like to show it as a widget of app B's main window.
Sort of like google chrome. A similar post here:QT How to embed an application into QT widget talked about the similar problem. But it involves implement your own window management system. Is there simpler solutions as both my app are Qt's qApp and both uses QWindow.
It's definitely possible if the two QApplications are in different processed.
Create two process each with it's QApplication and QWidget
From one process, find the winId of the other processe's QWidget and reparent it to your own widget.
To manage the widget from the other process reparented to yours, you may use qtwinmigrate. Originally this was meant to embed a MFC widget (with its own CWinApp) in a Qt widget, but it can also help embedding a QWidget from a separate process.
Here is a piece of working code:
Child process:
#include <QLabel>
#include <QWidget>
#include <QVBoxLayout>
#include <QApplication>
#include <sstream>
int main(int argc, char **argv)
{
QApplication app(argc,argv);
QWidget widget;
widget.setWindowTitle( "CHILD WINDOW" );
std::stringstream str;
str << "QWidget ID: " << widget.winId() << std::endl;
str << "Process Name: " << argv[0];
Qt::WindowFlags flags = widget.windowFlags();
flags |= Qt::FramelessWindowHint;
flags |= Qt::MSWindowsFixedSizeDialogHint;
flags |= Qt::SubWindow;
widget.setWindowFlags( flags );
widget.setLayout(new QVBoxLayout(&widget));
QLabel label;
widget.layout()->addWidget(&label);
label.setText(str.str().c_str());
widget.setStyleSheet( "background: red" );
widget.show();
QEvent e(QEvent::EmbeddingControl);
QApplication::sendEvent(&label, &e);
app.processEvents();
return app.exec();
}
Parent process:
#include <QMainWindow>
#include <QApplication>
#include <QMessageBox>
#include <QVBoxLayout>
#include <QLabel>
#include <QProcess>
#include "windows.h"
#include "qtwinmigrate5/qwinhost.h"
#include <iostream>
#include <sstream>
/* The EnumChildProc callback */
static HWND hWndHandle = NULL;
static qint64 childProcessID = 0;
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam)
{
DWORD dwProcessID = 0;
if (GetWindowThreadProcessId(hwnd, &dwProcessID) &&
dwProcessID == childProcessID )
{
char strTemp[256] = "";
GetWindowText(hwnd, strTemp, 256);
std::string str = strTemp;
if (str == "CHILD WINDOW") // sanity check
hWndHandle = hwnd;
}
return ( hWndHandle == NULL ); // must return TRUE; If return is FALSE it stops the recursion
}
void* GetChildWindowHandle( qint64 pid )
{
hWndHandle = NULL;
childProcessID = pid;
EnumWindows(EnumChildProc, 0);
return hWndHandle;
}
int main(int argc, char **argv)
{
QApplication app(argc,argv);
QMainWindow wnd;
wnd.setWindowTitle("That's the parent window!");
// Create child process:
QProcess process;
process.start("test_3rdparty_inprg_qtwinmigrate_child.exe");
if (process.state() != QProcess::Running)
{
QMessageBox::critical(NULL, "ERROR", "Unable to create child process");
return 1;
}
// Create qtwinmigrate widget container:
QWinHost* host = new QWinHost( &wnd );
// Get child process wiindow handle
HWND hChildWnd = NULL;
int timeout = 20;
while ((hChildWnd = (HWND)GetChildWindowHandle(process.processId())) == NULL)
{
// let child process more time to create and show its widget....
Sleep(200);
--timeout;
if (timeout == 0)
break;
}
int res = 1;
if (hChildWnd != NULL)
{
// attach child window handle to qtwinmigrate widget container
host->setWindow(hChildWnd);
char strTemp[256] = "";
GetWindowText(hChildWnd, strTemp, 256);
QWidget centralWidget(&wnd);
wnd.setCentralWidget(&centralWidget);
QVBoxLayout* layout = new QVBoxLayout(&centralWidget);
std::stringstream str;
str << "Attached data window " << std::showbase << std::hex << hChildWnd << std::endl;
str << "Window title: " << strTemp << std::endl;
str << "Widget below runs in a separate process:" << std::endl;
layout->addWidget( new QLabel( str.str().c_str(), &centralWidget ) );
layout->addWidget(host);
wnd.resize(400, 200);
wnd.show();
res = app.exec();
}
else
{
QMessageBox::critical(NULL, "ERROR", "Unable to find child process widget");
}
// kill child process
process.kill();
return res;
}
1- Compile child process into an executable named test_3rdparty_inprg_qtwinmigrate_child.exe.
2- Compile parent process into an executable
3- Run parent process, this one will start the child process, find it's top level widget window handle and insert it within its own QMainWindow as a child. When done, it will kill the child process.
As a end user, it's hard to tell the widgets are not part of the same process, they are perfectly embedded (the red part of the widget comes from the child process):
well, that's the idea of the whole QWidget approach: Everything that can be put in a container can be part of another application.
However, putting a complete, unmodified Qt application into another one will not be possible: There can only be one QApplication instance, and only one global event loop.

How to manage single instance of a Qt app on crash?

I want to execute my application as single instance, currently I am using QSharedMemory and working fine. I am using Qt5.2.1 on Ubuntu 12.04.
Below is my test code:
QApplication a(argc, argv);
a.processEvents();
const char* MEM_KEY = "56";
QSharedMemory sharedMem(MEM_KEY);
if( !sharedMem.create( 512, QSharedMemory::ReadWrite) )
{
QMessageBox msgBox;
msgBox.setText( QObject::tr("Can't start more than one instance of the application.") );
msgBox.setIcon( QMessageBox::Critical );
msgBox.exec();
exit(0);
}
MainWindow w;
w.show();
int p=0;
//p=p/0; // create exception here
return a.exec();
But the if makes the application crash(as shown in above code). If I start the application again, it shows Can't start more than one instance of the application, which means the previous instance is still there even if it has crashed. It should not happen in my case.
How can I restart my application in such a situation?
Edit:
Actually my original project contains lot of source files (the above one just made for testing). I want to implement it on my original project with editing least source file, if possible only by editing main.cpp
You can use a QSetting:
int main(int argc, char *argv[])
{
QSettings settings;
QApplication a(argc, argv);
if(!settings.exitedNormaly()) {
// In case of crash
}
// set the flag to false
settings.setExitedNormaly(false);
MainWindow w(&settings);
w.processArg(argc, argv);
w.show();
int result = a.exec();
settings.setExitedNormaly(result == 0);
return result;
}
Combined with your shared memory, you'll be able to unlock the block in case of application crash.
for linux:
//----------------------------------
QProcess *m_prSystemCall;
m_prSystemCall = new QProcess();
QString Commnd = "pgrep " + qApp->applicationDisplayName();
m_prSystemCall->start(Commnd);
m_prSystemCall->waitForFinished(8000);
QString output(m_prSystemCall->readAllStandardOutput());
QStringList AppList = output.split("\n", QString::SkipEmptyParts);
qDebug() <<"pgrep out:"<<AppList;
for(int i=0;i<AppList.size()-1;i++)
{
Commnd = "kill " + AppList.at(i);
m_prSystemCall->start(Commnd);
m_prSystemCall->waitForFinished(8000);
}
//-------------------------------------------------------
and for Windows:
#include <tlhelp32.h>
#include <comdef.h>
QString pName = qApp->applicationDisplayName();
pName += ".exe";
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
DWORD myPID = GetCurrentProcessId();
while (Process32Next(snapshot, &entry) == TRUE)
{
const WCHAR* wc = entry.szExeFile ;
_bstr_t b(wc);
const char* c = b;
if (stricmp(c, pName.toStdString().c_str()) == 0)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
qDebug() <<"myPID: "<< myPID << "entry.th32ProcessID" << entry.th32ProcessID;
if(myPID != entry.th32ProcessID)
TerminateProcess(hProcess,0);
QThread::msleep(10);
CloseHandle(hProcess);
}
}
}
CloseHandle(snapshot);

Qt GUI for UDP packet reception

I am developing a GUI using Qt for a test UDP server application i wrote in C using the sockets interface available in unix. I aim of the GUI is to display all the messages (perror and fprintf) in either a "text edit box" or "text browser box". Here is my code,
//-----------------------------Main.Cpp------------------------------------------//
//-----------------------------QT specific headers-------------------------------//
#include "mainwindow.h"
#include <QApplication>
#include <QLabel>
//------------------------------------------------------------------------------------//
int main(int argc, char *argv[])
{
int sock_fd=0;
funct_class funct_class_obj;
QApplication a(argc, argv);
MainWindow w;
sock_fd=funct_class_obj.udp_config();
funct_class_obj.recv_fucnt(sock_fd);
return a.exec();
}
//--------------------------------End of main.cpp------------------------------//
//-----------------------------mainwindow.cpp----------------------------------//
//-----------------------------QT specific headers-----------------------------//
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QApplication>
#include <QLabel>
//-----------------------------------------------------------------------------//
//--------------------------------C program specific headers------------------//
#include <stdio.h>
#include <stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
//---------------------------------------------------------------------------//
unsigned char message[50];
QString mystr;
int funct_class:: udp_config()
{
int sock_fd=0;
if ((sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
perror("\nError creating socket\n");
//mystr = "\nError creating socket\n";
else
{
fprintf(stdout, "\nSuccessfully created socket with descriptor:%d\n", sock_fd);
//mystr = "Successfully created socket";
struct sockaddr_in sock_addr = {0};
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(PORT);
if (inet_aton("127.0.0.1", &sock_addr.sin_addr) < 0)
perror("\nError converting destination IP address from dotted decimal to binary\n");
// mystr = "Error converting destination IP address from dotted decimal to binary";
else
{
if (bind(sock_fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) // Bind function call binds the properties assigned above to the socket created earlier
perror("\nError binding the port and IP address with the socket\n");
//mystr = "Error binding the port and IP address with the socket";
else
fprintf(stdout, "\nBinding port and IP address successful\n");
// mystr = "Binding port and IP address successful";
}
}
return sock_fd;
}
void funct_class:: recv_fucnt(int sock_fd)
{
struct sockaddr_in recv_sockaddr = {0};
socklen_t recv_sockaddr_len = sizeof(recv_sockaddr);
int recv_data=0;
if ((recv_data = recvfrom(sock_fd, message, sizeof(message), 0x00, (struct sockaddr*)&recv_sockaddr, &recv_sockaddr_len)) <= 0)
perror("\nError receiving data/no data received\n");
//mystr = "Error receiving data/no data received";
else
fprintf(stdout, "\nSuccessfully received %d bytes of data\n", recv_data);
fprintf(stdout, "\nData is :%s", message);
//mystr = "Successfully received data";
mystr = QString::fromStdString((const char*)message);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->testedit->setText(mystr);
//ui->mytextbrowser->setText((mystr));
}
MainWindow::~MainWindow()
{
delete ui;
}
//-----------------------------End of mainwindow.cpp---------------------------//
//------------------------------------mainwindow.h-----------------------------//
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#define PORT 5030
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
class funct_class{
public:
int udp_config();
void recv_fucnt(int sock_fd);
};
#endif // MAINWINDOW_H
//-------------------------------End of mainwindow.h-----------------------------//
The application is compiling fine, but i am facing problems when i execute it. It just freezes and even if i manage to get it out from freeze, i am not able to display the required string either in the "text edit box" or "text browser box". Please help.
P.S.: I am a newbie to GUI programming and Cpp.
The issue seems to be pretty clear:
ui->testedit->setText(mystr);
This is only called in the constructor and nowhere else. That means, when your mystr is updated, the widget will not be aware of it. It does not work like you seem to expect; it is not a one-time property binding so that the widget will be be notified automatically and transparently when the string changes. You have to do that work on your own.
Beside, you really ought to aim for using QtNetwork in a Qt based client rather than platform specific POSIX API with BSD sockets.

Is there any way to get desktop picture bitmap from MS RDP component (AxMSTSCLib)?

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.";
}
}
}
Well, it seems like there is no way to get raw image bytes from MsTsc component.