PDA

View Full Version : QProcess not communicating with .net framework > 3.5



SimpleIsBetter
30th April 2015, 21:02
Hi all,

I have a main Qt application, launching a C# app with QProcess.
I would like to communicate with the C# app using the QProcess tools, the standard channels.
Although the communication is working perfectly when I compile the C# app with .net framework 3.5, I am not receiving any data from the process when it is compiled with .net 4.0 or 4.5

I posted a thread on the msdn forums : https://social.msdn.microsoft.com/Forums/en-US/8bbe87d8-f97f-4258-bce3-dfedd6314e93/consolereadline-not-working-with-net-framework-35?forum=csharpgeneral

I have made a minimal console example to replicate the issue:

#include <QCoreApplication>
#include <QProcess>
#include <iostream>
#include <string>
using namespace std;

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

// Path to the C# executable
QString program = "D:/Documents/ConsoleApplication1/ConsoleApplication1/bin/Release/ConsoleApplication1.exe";

// Start child Process
QProcess * process = new QProcess();
process->setProgram(program);
// Execute lambda function whenever a message from the process is received
QObject::connect(process, &QProcess::readyReadStandardOutput, [&](){ cout << process->readAll().toStdString(); } );
process->start();

string text;
cin >> text;
process->write( QByteArray::fromStdString(text) + "\r\n" );

return a.exec();
}

and a minimal C# example :

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string text;
while (true)
{
Console.WriteLine("0");
text = Console.ReadLine();
Console.WriteLine("1");
Console.WriteLine(text);
}
}
}
}

I am using Qt 5.4.1 on windows 7, and compiling with msvc 2010 32 bits.

Thanks in advance for your help :)

jefftee
1st May 2015, 04:10
QProcess doesn't care if your program is using .net 3.5, 4.0, or 4.5 of course. Is your QProcess starting your command line program successfully? Use the QProcess::error, QProcess::started, and QProcess::stateChanged signals to figure out what's going on.

I am also assuming you can successfully manually run your command line program when compiled with .net 4.0 or 4.5, correct?

Edit: What is the return value from process->write()?

SimpleIsBetter
1st May 2015, 18:36
Is your QProcess starting your command line program successfully ? Yes

I am also assuming you can successfully manually run your command line program when compiled with .net 4.0 or 4.5, correct ? Correct

Edit: What is the return value from process->write() ? The return value is equal to the number of byte sent.


Here is the code that I am actually using for debugging :

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}

mainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>

#include "process.h"

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);

public slots:
void incomingMessageFromCSharp(QByteArray ba);
void sendMessageToCSharp();

private:
Process *process;
};

#endif // MAINWINDOW_H


mainWindow.cpp

#include "mainwindow.h"

#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QString program = "D:/Documents/Laverie/Nayax/ConsoleApplication1/ConsoleApplication1/bin/Release/ConsoleApplication1.exe";

process = new Process(this);
connect(process, SIGNAL(messageReceived(QByteArray)), this, SLOT(incomingMessageFromCSharp(QByteArray)));
process->setProgram(program);
process->start();

QPushButton * pb = new QPushButton("Send ping", this);
connect(pb, SIGNAL(clicked()), this, SLOT(sendMessageToCSharp()));
}

void MainWindow::sendMessageToCSharp()
{
QByteArray ba ="ping";
ba += '\r';
ba += '\n';
process->sendMessage(ba);
}

void MainWindow::incomingMessageFromCSharp(QByteArray ba)
{
//
}


process.h

#ifndef PROCESS_H
#define PROCESS_H

#include <QProcess>

class Process : public QProcess
{
Q_OBJECT

public:
explicit Process(QObject * parent = 0);
~Process();

public slots:
void processError(QProcess::ProcessError error);
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
void processReadyReadStandardError();
void processReadyReadStandardOutput();
void processStarted();
void processStateChanged(QProcess::ProcessState state);

void sendMessage(QByteArray ba);

signals:
void messageReceived(QByteArray);

protected:
QString enumErrorToString(QProcess::ProcessError error);
QString enumStateToString(QProcess::ProcessState state);
};

#endif // PROCESS_H


process.cpp

#include "process.h"

#include <QDebug>

Process::Process(QObject *parent) :
QProcess(parent)
{
// Error signal
connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError(QProcess::ProcessError)));

// Process finished signal
connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(processFinished(int,QProcess::ExitStatus)));

// Standard error signal
connect(this, SIGNAL(readyReadStandardError()), this, SLOT(processReadyReadStandardError()));

// Standard output signal
connect(this, SIGNAL(readyReadStandardOutput()), this, SLOT(processReadyReadStandardOutput()));

// Process started signal
connect(this, SIGNAL(started()), this, SLOT(processStarted()));

// Process state signal
connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(processStateChanged(QProcess::ProcessState))) ;

}

Process::~Process()
{
this->close();
}

void Process::sendMessage(QByteArray ba)
{
qDebug() << "Sending message " << ba;
qint64 nBytes = this->write(ba);
if ( nBytes != ba.size() )
qWarning() << "Message partially sent : " << nBytes << " sent instead of " << ba.size();
}

void Process::processError(QProcess::ProcessError error)
{
if ( error == QProcess::FailedToStart )
qCritical() << "Process failed to start. Check that the path is correct: " << enumErrorToString(error);
else {
qWarning() << "QProcess error: " << enumErrorToString(error);
}
}

void Process::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
if ( exitStatus == QProcess::CrashExit ) {
qWarning() << "Process crashed";
}
else if ( exitStatus == QProcess::NormalExit )
qDebug() << "Process exited normally : " << exitCode;
else
qCritical() << "enum value not recognized : " << exitStatus;
}

void Process::processReadyReadStandardError()
{
qWarning() << "Error :\n" << this->readAllStandardError();
}

void Process::processReadyReadStandardOutput()
{
QByteArray ba = this->readAllStandardOutput();
qDebug() << "Message Received : " << ba;
emit messageReceived(ba);
}

void Process::processStarted()
{
qDebug() << "Process started";
}

void Process::processStateChanged(QProcess::ProcessStat e state)
{
qDebug() << "Process state changed : " << enumStateToString(state);
}


QString Process::enumErrorToString(QProcess::ProcessError error)
{
switch (error) {
case QProcess::FailedToStart:
return "QProcess::FailedToStart";
case QProcess::Crashed:
return "QProcess::Crashed";
case QProcess::Timedout:
return "QProcess::Timedout";
case QProcess::WriteError:
return "QProcess::WriteError";
case QProcess::ReadError:
return "QProcess::ReadError";
case QProcess::UnknownError:
return "QProcess::UnknownError";
default:
return "Unknown enum value : " + error;
}
}

QString Process::enumStateToString(QProcess::ProcessState state) {
switch (state) {
case QProcess::NotRunning:
return "QProcess::NotRunning";
case QProcess::Starting:
return "QProcess::Starting";
case QProcess::Timedout:
return "QProcess::Running";
default:
return "Unknown enum value : " + state;
}
}

jefftee
1st May 2015, 19:34
If you are successfully writing the bytes to the running QProcess, and based on the number of bytes written returned from process->write, it would appear that the data is being written correctly to the running QProcess, so my only guess is that something is different on the .net side.

Your running QProcess receiving the data correctly, however, then your running QProcess writes to stdout, you're not receiving the readyReadStandardOutput signal, correct?

Have you tried w/o subclassing QProcess? Not sure if that would make a difference but would remove one layer to debug... :)

SimpleIsBetter
1st May 2015, 20:59
I tried without subclasssing QProcess, and unfortunately I obtain the exact same behaviour :

I can read data from the process without any issue,
but when I write data to the process, the data is never received.

Thuan Seah Tan
21st September 2015, 04:54
Wondering if anyone has any success getting QProcess to interact with a C# program compiled with .NET 4.0 or later? I did a test program that does nothing but Console.ReadLine() and Console.WriteLine() in a infinite loop, and QProcess works when the program is compiled with .NET 3.0 but not when it is compiled with .NET 4.0.

SimpleIsBetter
22nd September 2015, 19:39
I ended up using a pipe to send message from Qt to the C# code. NamedPipeClientStream on the C# side and QLocalServer on the Qt side.