I am using Qt 5.7.0 on Ubuntu 16.04.1 x64.
When I try to using QNetworkAccessManager::post() to transfer file, it will got Error "QIODevice:device not open".
It's strange that release version of the program will go wrong certainly, while the same problem only occur after a long time running(look like that) in debug version.
Here is relative function:
QHttpMultiPart* PacketFactory::getPacket(QString id, QString imgPath) {
QHttpMultiPart *pMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart idPart;
idPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
idPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"id\""));
idPart.setBody(id.toUtf8());
// some text/plain part
...
QFile *imgFile = new QFile(imgPath);
imgFile->setParent(pMultiPart);
Q_ASSERT(imgFile->open(QIODevice::ReadWrite));
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"img\"; filename=\"1.jpg\""));
imagePart.setBodyDevice(imgFile);
pMultiPart->append(imagePart);
return pMultiPart;
}
Another:
QNetworkRequest NetManager::getRequest(int dst) {
QString url;
switch (op) {
case DST_LOCAL:
url = "http://127.0.0.1/query"
break;
...
}
return QNetworkRequest(QUrl(url));
}
Here is invoke code:
QNetworkRequest request = m_pNetManager->getRequest(NetManager::DST_LOCAL);
QHttpMultiPart *pMultiPart = PacketFactory::getPacket(...);
QNetworkReply *pReply = m_NetworkAccessManager.post(request, pMultiPart);
QObject::connect(pReply, SIGNAL(finished()), this, SLOT(handlePacket()));
pMultiPart->setParent(pReply);
Thanks for advices.
Related
In the app I upload a video file (24Mb about) every 2 minutes and this works well. It works also if I upload a new file after the previous one have ended.
Two minutes is enough time for the file to upload, but if the connection is slow and a new file tries to upload the app hungs.
Can I somehow have two uploads at the same time?
My code:
QString MainWindow::rename_video()
{
QString oldName="C:/Qt/Qt5.10.1/Nuevo/build_principal_16/riderout.mp4";
QString newName=QString::number(QDateTime::currentMSecsSinceEpoch())+".mp4";
QFile f(oldName);
if (f.rename(newName)) {
// upload
m_file = new QFile("C:/Qt/Qt5.10.1/Nuevo/build_principal_16/"+newName);
QFileInfo fileInfo(*m_file);
QUrl url("ftp://jumpemirates.com/app/history/"+newName);
url.setUserName("user#email.com");
url.setPassword("password");
url.setPort(21);
if (m_file->open(QIODevice::ReadOnly))
QNetworkReply *reply = m_manager->put(QNetworkRequest(url), m_file);
} else {
qWarning("Unable to rename video file.");
return "";
}
return newName;
}
void MainWindow::uploadFinished(QNetworkReply *reply) {
if (!reply->error()) {
m_file->close();
m_file->deleteLater();
reply->deleteLater();
}
}
I am trying to get clipboard data via QClipboard. Here is my code:
void MainWindow::getText()
{
QClipboard *clipboard = QGuiApplication::clipboard();
const QMimeData *mime = clipboard->mimeData (QClipboard::Selection);
QString originalText = clipboard->text(); // no crashes in windows
//QString originalText = mime->text (); //this line causing program crash
.................
}
getText() called every 5 second using QTimer. The above code works perfectly in linux, when I try to run the code in windows 7 it crashed.
clipboard->mimeData can be null, so you might want to either cache the previous state, or do the following:
QString originalText = mime ? mime->text() : QString();
Windows doesn't support QClipboard::Selection, that's why application crashes everytime. Here is how I solved it
QString originalText;
if(QSysInfo::productType() == "windows") {
QString clipboard = QApplication::clipboard()->text();
originalText = clipboard;
} else {
// for linux
QClipboard *clipboard = QGuiApplication::clipboard();
const QMimeData *mime = clipboard->mimeData (QClipboard::Selection);
originalText = mime->text ();
}
I'm trying to create and implement a DDE dll with Qt but as for now I'm being unable to properly connect to a service which I know to be working after testing it with Excel.
The dll connection function is as following:
UINT respTemp;
respTemp = DdeInitializeA(&pidInst, NULL, APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0L);
//handle error messages here
//...
//![]
hszService = DdeCreateStringHandleA(pidInst, (LPCSTR)service.utf16(), CP_WINANSI); //service.toLatin1().toStdString().c_str()
hszTopic = DdeCreateStringHandleA(pidInst, (LPCSTR)topic.utf16(), CP_WINANSI); //topic.toLatin1().toStdString().c_str()
hConv = DdeConnect(pidInst, hszService, hszTopic, NULL);
DdeFreeStringHandle(pidInst, hszService);
DdeFreeStringHandle(pidInst, hszTopic);
if (!hConv)
{
UINT ddeLastError = DdeGetLastError(pidInst);
switch (ddeLastError)
{
case DMLERR_DLL_NOT_INITIALIZED: return DDEConn_DLLNotInitialized;
case DMLERR_INVALIDPARAMETER: return DDEConn_InvalidParameter;
case DMLERR_NO_CONV_ESTABLISHED: return DDEConn_NoConvEstablished;
default: return DDEConn_NoConnectionStablished;
}
}
connStatus = true;
return DDEConn_NoError;
The test function is as follows:
void MainWindow::on_start_clicked()
{
const QString application = "profitchart"; //=profitchart|COT!VALE5.ult
const QString topic = "COT";
const QString item = "VALE5.ult";
test = CommDDE::instance();
CommDDE::DDEConnectionErrorList resp = test->connect(application,topic);
if (resp == CommDDE::DDEConn_NoError)
{
qDebug() << "request RESULT: " << test->request(item);
}
else
qDebug() << "Can't connect to application" << resp;
}
Always when I try to connect I get error DMLERR_NO_CONV_ESTABLISHED after the call to DdeConnect. I couldn't find guidence on what to do when such error occurs. I don't know too much about the details of configuring such functions so I used the default configuration used by a working dll from which I got part of the raw material for this dll. Should I try a different configuration I'm not aware of? Remembering that the call is working on Excel.
It would seem I found the answer: the commented way of writting the service and topic names were the right ways of passing the parameters to DdeCreateStringHandleA and DdeCreateStringHandleA.
I've written HttpUrlConnection wrapper. It supports file uploading, so I'm using HttpUrlConnection.setChunkedStreamingMode() to prevent OutOfMemoryException.
But after writing all data to OutputStream I getting IOException. Without this method everything works fine.
Here the code:
HttpURLConnection connection = getConnection();
if(!isSent) {
OutputStream output;
if(!files.isEmpty()) {
connection.setRequestProperty(HEADER_CONTENT_TYPE, CONTENT_TYPE_MULTIPART);
// Tried to add this line, but still not working
connection.setRequestProperty("Transfer-Encoding","chunked");
connection.setChunkedStreamingMode(chunkSize);
output = new BufferedOutputStream(connection.getOutputStream());
writeParamsMultipart(output);
writeFilesMultipart(output);
output.write((PREFIX + BOUNDARY + PREFIX + LINEND).getBytes());
} else {
connection.setRequestProperty(HEADER_CONTENT_TYPE, CONTENT_TYPE_FORM);
output = new BufferedOutputStream(connection.getOutputStream());
output.write(paramsToUrlencoded(post).getBytes());
}
output.flush();
output.close();
isSent = true;
}
// Getting exception on this line
InputStream input = new BufferedInputStream(connection.getInputStream());
if(ENCODING_GZIP.equalsIgnoreCase(connection.getHeaderField(HEADER_CONTENT_ENCODING))) {
input = new GZIPInputStream(input);
}
return input;
chunkSize by default 1024 bytes. What's the problem?
It's FileNotFoundException
That means that the URL is incorrect. It's the equivalent of HTTP 403.
Nothing to do with chunked transfer mode.
I have the following code, and I would like to add some HTTP header info along with the call. Anyway that I can do that?
void NeoAPI::call(QString apiCall) {
if (this->ApiCall.contains(apiCall)) {
QNetworkAccessManager* manager = new QNetworkAccessManager(0);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(netReplyFinished(QNetworkReply*)));
QUrl url = this->ApiCall[apiCall];
url.addQueryItem("memberid","76710"); // Set for backdoor debugging
manager->get(QNetworkRequest(url));
} else {
this->requestResultText = QString("Call %1 doesn't exist").arg(apiCall);
}
}
void NeoAPI::netReplyFinished(QNetworkReply *netReply) {
if (netReply->error() == QNetworkReply::NoError) {
this->requestResultText = netReply->readAll();
} else {
this->requestResultText = "API Call Failed";
}
QMessageBox messageBox;
messageBox.setText(this->requestResultText);
messageBox.exec();
//delete netReply;
}
Also, if I wasn't using these inside a class, what would the this in the connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(netReplyFinished(QNetworkReply*))); be?
Thanks!
Yes, see the documentation of QNetworkRequest.
You'll want to do something like:
QNetworkRequest request(url);
request.setHeader( QNetworkRequest::ContentTypeHeader, "some/type" );
request.setRawHeader("Last-Modified", "Sun, 06 Nov 1994 08:49:37 GMT");
manager->get( header );
Also, if I wasn't using these inside a
class, what would the this in the
connect(manager,
SIGNAL(finished(QNetworkReply*)),
this,
SLOT(netReplyFinished(QNetworkReply*)));
be?
It wouldn't be anything. To connect a signal to a slot, that slot must be a member function of some object. The Qt primer on signals and slots explains this.