Is there any cross platform way to get the current username in a Qt C++ program?
I've crawled the internet and the documentation for a solution, but the only thing I find are OS dependent system calls.
I was actually thinking about it a couple of days ago, and I came to the conclusion of having different alternatives, each with its own trade-off, namely:
Environment variables using qgetenv.
The advantage of this solution would be that it is really easy to implement. The drawback is that if the environment variable is set to something else, this solution is completely unreliable then.
#include <QString>
#include <QDebug>
int main()
{
QString name = qgetenv("USER");
if (name.isEmpty())
name = qgetenv("USERNAME");
qDebug() << name;
return 0;
}
Home location with QStandardPaths
The advantage is that, it is relatively easy to implement, but then again, it can go unreliable easily since it is valid to use different username and "entry" in the user home location.
#include <QStandardPaths>
#include <QStringList>
#include <QDebug>
#include <QDir>
int main()
{
QStringList homePath = QStandardPaths::standardLocations(QStandardPaths::HomeLocation);
qDebug() << homePath.first().split(QDir::separator()).last();
return 0;
}
Run external processes and use platform specific APIs
This is probably the most difficult to implement, but on the other hand, this seems to be the most reliable as it cannot be changed under the application so easily like with the environment variable or home location tricks. On Linux, you would use QProcess to invoke the usual whoami command, and on Windows, you would use the GetUserName WinAPI for this purpose.
#include <QCoreApplication>
#include <QProcess>
#include <QDebug>
int main(int argc, char **argv)
{
// Strictly pseudo code!
#ifdef Q_OS_WIN
char acUserName[MAX_USERNAME];
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName))
qDebug << acUserName;
return 0;
#elif Q_OS_UNIX
QCoreApplication coreApplication(argc, argv);
QProcess process;
QObject::connect(&process, &QProcess::finished, [&coreApplication, &process](int exitCode, QProcess::ExitStatus exitStatus) {
qDebug() << process.readAllStandardOutput();
coreApplication.quit();
});
process.start("whoami");
return coreApplication.exec();
#endif
}
Summary: I would personally go for the last variant since, even though it is the most difficult to implement, that is the most reliable.
There is no way to get the current username with Qt.
However, you can read this links :
http://www.qtcentre.org/threads/12965-Get-user-name
http://qt-project.org/forums/viewthread/11951
I think the best method is :
#include <stdlib.h>
getenv("USER"); ///for MAc or Linux
getenv("USERNAME"); //for windows
EDIT : You can use qgetenv instead of getenv.
In QT5 and up it is possible to do the following :
QString userName = QDir::home().dirName();
`QDir::home() returns the user's home directory.
You can use qEnvironmentVariable
QString sysUsername = qEnvironmentVariable("USER");
if (sysUsername.isEmpty()) sysUsername = qEnvironmentVariable("USERNAME");
Also you can use QProcessEnvironment like this:
QProcessEnvironmentenv = QProcessEnvironment::systemEnviroment();
QString username = env.value("USER");
There is a way to get the current windows username with Qt. Here it is
mainwindow.ui
This is the form ui
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QDir>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->getUser();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::getUser()
{
QProcess *username = new QProcess();
QStringList cmdParamaters, split;
QString clean1, clean2, clean3,userName;
int cutOff, strLen;
cmdParamaters << "/c"<<"\"%USERPROFILE%\"";
username->setProcessChannelMode(QProcess::MergedChannels);
username->start("cmd.exe",cmdParamaters);
username->waitForFinished();
QString vusername (username->readAllStandardOutput());
cutOff = vusername.indexOf("'", 1);
ui->label_2->setText(vusername);
clean1 = vusername.left(cutOff);
ui->label_3->setText(clean1);
clean2 = clean1.remove(0,3);
strLen = clean2.length();
ui->label_4->setText(clean2);
clean3 = clean2.left(strLen-2);
split = clean3.split("\\");
userName = split[2]; //This is the current system username
ui->label_5->setText(userName);
delete username;
}
Output:
Code output
Related
I have a simple program that should retrieve the HTML from a website URL.
main.cpp
#include "Downloader.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
auto dl = new Downloader(&a);
QString url = "https://www.dognow.at/ergebnisse/?page=1";
dl->fetch(url);
return a.exec();
}
Downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QNetworkReply>
#include <QObject>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject* parent = nullptr);
void fetch(QString &url);
private:
QNetworkAccessManager* m_manager;
private slots:
void replyFinished(QNetworkReply* rep);
};
#endif // DOWNLOADER_H
Downloader.cpp
#include "Downloader.h"
#include <QDebug>
Downloader::Downloader(QObject* parent): QObject(parent),
m_manager(new QNetworkAccessManager(parent))
{}
void Downloader::fetch(QString& url)
{
qDebug() << "fetch " << url;
connect(m_manager, &QNetworkAccessManager::finished, this, &Downloader::replyFinished);
m_manager->get(QNetworkRequest(QUrl(url)));
}
void Downloader::replyFinished(QNetworkReply* rep)
{
QByteArray data=rep->readAll();
QString str(data);
qDebug() << "data len: " << str.length();
rep->close();
}
When I run the program on my local PC it works fine. When I run it on another machine the reply data is empty. On both systems I use Linux (x86_64) and Qt 5.15.0.
I hope someone can give me a hint where I should have a look at.
UPDATE: 2022-04-04 - 16:22:
when I run a simple curl command on the failing machine it works fine.
Ok, I found the problem.
On the failing machin I have an older ubuntu (16.04 LTS) running with an incompatible openssl version.
I found it out because I copied my own Qt libs build (debug) to the other machine and I got SSL error (incompatbile version).
I installed a newer openssl version and know it works.
There are 2 applications:
creates a file somewhere, and
should go along some path and pick up the contents of the file.
Can I in the first application specify the path to the file in QSettings, and the second to take this path from the registry and go through it to the file?
Please tell me a simple example.
I cannot suggest a cross-platform method based on registry, but want to show another ways.
Method 1 (based on common ini file)
Store the path in some common ini file, for example in <some_common_path>/settings_common.ini. Both applications shall have access to the file:
App 1 (Writer)
#include <QtCore/QCoreApplication>
#include <QSettings>
#include <QDebug>
#include <QThread>
const QString CommonSettingsFilePath = "c:/temp/settings_common.ini";
const QString CommonKey = "common/path";
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
for(;;)
{
static int it = 0;
QString pathString = QString("path_%1").arg(it++);
QSettings settings(CommonSettingsFilePath, QSettings::IniFormat);
settings.setValue(CommonKey, pathString);
QThread::sleep(1);
}
return a.exec();
}
App 2 (Reader)
#include <QtCore/QCoreApplication>
#include <QSettings>
#include <QDebug>
#include <QThread>
const QString CommonSettingsFilePath = "c:/temp/settings_common.ini";
const QString CommonKey = "common/path";
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
for (;;)
{
QSettings settings(CommonSettingsFilePath, QSettings::IniFormat);
QString pathString = settings.value(CommonKey, "").toString();
qDebug() << "Path read from ini =" << pathString;
QThread::sleep(2);
}
return a.exec();
}
Possible output of the App 2:
Path read from ini = "path_6"
Path read from ini = "path_8"
Path read from ini = "path_9"
Path read from ini = "path_11"
...
Method 2 (based on Inter-process communication)
IPC using Qt Remote Objects API:
App1 is Source, App2 (reader) will be Replica, the path is a property.
Only the main points are shown.
In both App1 and App2 .pro files add remoteobjects module:
QT += core remoteobjects ...
path.rep file:
#include <QtCore>
#include <QString>
class Path
{
PROP(QString path);
};
In App1 pro:
REPC_SOURCE = path.rep
App1 class:
#include "rep_path_source.h"
class CommonPath : public PathSimpleSource
{
Q_OBJECT
};
Then in App1:
CommonPath sourcePath;
QRemoteObjectHost sourceNode(QUrl("local:path")); // create host node
sourceNode.enableRemoting(&sourcePath); // enable remoting/sharing
...
sourcePath.setPath("some_path_aaa");
In App2 pro:
REPC_REPLICA = path.rep
In App2 furthermore:
#include "rep_path_replica.h"
QSharedPointer<PathReplica> replica;
QRemoteObjectNode repNode; // create remote object node
repNode.connectToNode(QUrl("local:path")); // connect with remote host node
replica.reset(repNode.acquire<PathReplica>()); // acquire replica of source from host node
replica->waitForSource();
...
qDebug() << replica->path();
Of course you can distribute all the necessary data in this way, not just the path.
What I'm trying to achieve (And struggling with) is basically passing commands to CMD through my QT Mainwindow application.
I would like to have my code, first run CMD (preferably hidden). I used here QProcess like this:
(in my Mainwindow.cpp file)
QString exePath = "C:/Windows/System32/cmd.exe";
QProcess pro;
pro.startDetached(exePath);
pro.waitForStarted();
this question helped me a lot
However, what this answer/question lacks is actual help on "appending" commands to CMD (not sure if this is a correct term, please correct me if I'm wrong!)
I have tried the following with this piece of code
(also in my Mainwindow.cpp file)
string exepathstring = "C:/Windows/System32/cmd.exe"; //because fstream doesnt accept argument of type QString
QProcess pro;
pro.startDetached(exePath); //do I have to use "detached" here?
pro.waitForFinished(); //not sure if i should use "for
//finished" or "for started" or something else
string connecttoserver = ui->lineEdit_command->text().toStdString(); //this is where people input a cmd command
//need to convert it to to be able to append it
fstream myoutfile(exepathstring, ios::in | ios::out | ios::app);
myoutfile <<""<< connecttoserver << endl;
Hoping that I can use a normal "append to file" code but it does nothing, I don't even get an error :(
could someone tell me where i'm going wrong?
and how can I go about achieving what I want?
which is
starting cmd (preferably in hidden) upon launch of my "mainwindow app"
take user input and let my app pass it to cmd upon my button click.
Here's my entire mainwindow.cpp source file
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QString>
#include <fstream>
#include <iostream>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{ui->setupUi(this);}
MainWindow::~MainWindow()
{delete ui;}
void MainWindow::on_pushButton_clicked()
{
QString exePath = "C:/Windows/System32/cmd.exe";
string exepathstring = "C:/Windows/System32/cmd.exe"; //because fstream doesnt accept argument of type QString
QProcess pro;
pro.startDetached(exePath);
pro.waitForFinished(); //not sure if i should use "for finished" or "for started" or something else
string connecttoserver = ui->lineEdit_command->text().toStdString(); /*this is where people input a cmd command
need to convert it to to be able to append it*/
fstream myoutfile(exepathstring, ios::in | ios::out | ios::app);
myoutfile <<""<< connecttoserver << endl;
}
Any input would really help me a lot ^.^ also I'm really sorry if I had used wrong terminology
If you looked at this post, one apparent problem is that you are using the static method startDetached() with the blocking function waitForFinished() ... QProcess::waitForStarted()/waitForFinished() won't catch signals from detached QProcess;
Thus you could use:
QProcess pro;
pro.start(exePath);
pro.waitForStarted(); // the correct is `waitForStarted()`
What your trying to do with fstream is not clear - to me - while in your description, you want user to send a command to your process:
then this could, for instance, be :
QByteArray user_cmd = QVariant(ui->lineEdit_command->text()).toByteArray();
pro.write(user_cmd);
pro.write("\n\r"); // press Enter to execute the command
Thus your code could be:
.h
#include <QProcess>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void readResult();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QProcess* pro;
};
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::on_pushButton_clicked);
QString exePath = "C:/Windows/System32";
pro = new QProcess(parent);
pro->setWorkingDirectory(exePath);
pro->setReadChannel(QProcess::StandardOutput);
connect(pro,&QProcess::readyReadStandardOutput, this, &MainWindow::readResult);
pro->start("cmd.exe");
if (!pro->waitForStarted())
{
qDebug() << "The process didnt start" << pro->error();
}
}
void MainWindow::on_pushButton_clicked()
{
if (ui->lineEdit_command->text().isEmpty())
return;
QByteArray cmd = QVariant(ui->lineEdit_command->text()).toByteArray();
pro->write(cmd);
pro->write("\n\r");
ui->lineEdit_command->clear();
}
void MainWindow::readResult()
{
while(pro->bytesAvailable()){
QString dirout = pro->readLine();
qDebug() << dirout;
}
}
MainWindow::~MainWindow()
{
delete ui;
}
I've been looking around on the web on how to create an authentication page when my Qt desktop app opens. I already built the app; that is pretty small and only composed of a MainWindow called from main.cpp.
Now I'd like to add an authentication page when the user opens the app. I created a Google API (following the instruction from this link: http://blog.qt.io/blog/2017/01/25/connecting-qt-application-google-services-using-oauth-2-0/); but it is really incomplete. And looking on the web, I wasn't able to find a single link that gives a working example where:
- The user runs the app and gets asked for his username and password;
- And if it doesn't exist yet, he can create one.
All I've found is incomplete piece of code like the link I shared above; or tutorial that shows how to create a login page with hard-coded passwords and usernames (this is not what I want, I want people to be able to add themselves dynamically based of the Google API).
So please, if someone has a little piece of code where the user gets asked for their username and password, with the code managing the request to the API, that would be great!
EDIT: Adding my code
I'm adding the code of my class GoogleGateway (inspired from what I found here: How to set redirect_uri using QOAuth2AuthorizationCodeFlow and QOAuthHttpServerReplyHandler)
GoogleGateway.h:
#ifndef GOOGLEGATEWAY_H
#define GOOGLEGATEWAY_H
#include <QObject>
class GoogleGateway : public QObject
{
Q_OBJECT
public:
GoogleGateway();
};
#endif // GOOGLEGATEWAY_H
GoogleGateway.cpp:
#include "googlegateway.h"
#include <QApplication>
#include <QObject>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QString>
#include <QFile>
#include <QUrl>
#include <QOAuth2AuthorizationCodeFlow>
#include <QOAuthHttpServerReplyHandler>
#include <QDesktopServices>
GoogleGateway::GoogleGateway() :
QObject(){
auto google = new QOAuth2AuthorizationCodeFlow;
google->setScope("email");
this->connect(google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, &QDesktopServices::openUrl);
QString val;
QFile file;
file.setFileName("/.../auth.json");
file.open(QIODevice::ReadOnly | QIODevice::Text);
val = file.readAll();
file.close();
QJsonDocument document = QJsonDocument::fromJson(val.toUtf8());
QJsonObject object = document.object();
const auto settingsObject = object["web"].toObject();
const QUrl authUri(settingsObject["auth_uri"].toString());
const auto clientId = settingsObject["client_id"].toString();
const QUrl tokenUri(settingsObject["token_uri"].toString());
const auto clientSecret(settingsObject["client_secret"].toString());
const auto redirectUris = settingsObject["redirect_uris"].toArray();
const QUrl redirectUri(redirectUris[0].toString());
const auto port = static_cast<quint16>(redirectUri.port());
google->setAuthorizationUrl(authUri);
google->setClientIdentifier(clientId);
google->setAccessTokenUrl(tokenUri);
google->setClientIdentifierSharedKey(clientSecret);
auto replyHandler = new QOAuthHttpServerReplyHandler(port, this);
google->setReplyHandler(replyHandler);
google->grant();
}
Now, what do I need to do in my MainWindow.cpp to prompt a login page that will use the class GoogleGateway? Does the class GoogleGateway look good as it is? Or do I need to modify something?
Also, I created an instance of the class GoogleGateway in my MainWindow constructor. And When I run the code, it opens a web tab in my Chrome but throws the Error 400 saying "Error: redirect_uri_mismatch". What does that mean?
Thanks for your help.
So, the article from Qt blog is almost complete. You just need to connect granted signal and make needed requests after that.
Note about /cb path in redirect_uri in Qt blog is not valid anymore(article came about a year ago).
NOTE: The path “/cb” is mandatory in the current
QOAuthHttpServerReplyHandler implementation.
So if you see access error from google after running your code, just copy-paste redirect_uri from there into GoogleConsole Authorized redirect URIs of your configured client. http://localhost:8080/ <- don't forget slash at the end
P.S.: Don't forget to dowload json file with credentials from console again.
Also if you want to call any Google APIs after authorization, you need to enable them in GoogleConsole for your project. To test the code just enable Google+ API
That's it. Here is the complete and working code. (Tested on Linux and Qt 5.10, Don't have Windows at the moment, can't test it there)
googlegateway.h
#ifndef GOOGLEGATEWAY_H
#define GOOGLEGATEWAY_H
#include <QObject>
#include <QOAuth2AuthorizationCodeFlow>
#include <QNetworkReply>
class GoogleGateway : public QObject
{
Q_OBJECT
public:
explicit GoogleGateway(QObject *parent = nullptr);
private:
QOAuth2AuthorizationCodeFlow * google;
};
#endif // GOOGLEGATEWAY_H
googlegateway.cpp
#include "googlegateway.h"
#include <QObject>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QString>
#include <QFile>
#include <QDir>
#include <QUrl>
#include <QOAuthHttpServerReplyHandler>
#include <QDesktopServices>
GoogleGateway::GoogleGateway(QObject *parent) : QObject(parent)
{
this->google = new QOAuth2AuthorizationCodeFlow(this);
this->google->setScope("email");
connect(this->google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, &QDesktopServices::openUrl);
QByteArray val;
QFile file;
file.setFileName(QDir::toNativeSeparators("/full/path/client_secret_XXXXXXX.apps.googleusercontent.com.json"));
if(file.open(QIODevice::ReadOnly | QIODevice::Text))
{
val = file.readAll();
file.close();
}
QJsonDocument document = QJsonDocument::fromJson(val);
QJsonObject object = document.object();
const auto settingsObject = object["web"].toObject();
const QUrl authUri(settingsObject["auth_uri"].toString());
const auto clientId = settingsObject["client_id"].toString();
const QUrl tokenUri(settingsObject["token_uri"].toString());
const auto clientSecret(settingsObject["client_secret"].toString());
const auto redirectUris = settingsObject["redirect_uris"].toArray();
const QUrl redirectUri(redirectUris[0].toString());
const auto port = static_cast<quint16>(redirectUri.port());
this->google->setAuthorizationUrl(authUri);
this->google->setClientIdentifier(clientId);
this->google->setAccessTokenUrl(tokenUri);
this->google->setClientIdentifierSharedKey(clientSecret);
auto replyHandler = new QOAuthHttpServerReplyHandler(port, this);
this->google->setReplyHandler(replyHandler);
this->google->grant();
connect(this->google, &QOAuth2AuthorizationCodeFlow::granted, [=](){
qDebug() << __FUNCTION__ << __LINE__ << "Access Granted!";
auto reply = this->google->get(QUrl("https://www.googleapis.com/plus/v1/people/me"));
connect(reply, &QNetworkReply::finished, [reply](){
qDebug() << "REQUEST FINISHED. Error? " << (reply->error() != QNetworkReply::NoError);
qDebug() << reply->readAll();
});
});
}
Please remember to set Redirect URI in google console to http://127.0.0.1:port_no/ instead of http://localhost:port_no/ for all localhost.
Remember to put the trailing '/' in the Redirect URI.
Rest of the code
this->google = new QOAuth2AuthorizationCodeFlow(this);
this->google->setScope("email");
connect(this->google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser, &QDesktopServices::openUrl);
this->google->setAuthorizationUrl(QUrl("https://accounts.google.com/o/oauth2/auth"));
this->google->setClientIdentifier(MY_CLIENT_ID);
this->google->setAccessTokenUrl(QUrl("https://oauth2.googleapis.com/token"));
this->google->setClientIdentifierSharedKey(MYTOKEN);
// In my case, I have hardcoded 8080 to test
auto replyHandler = new QOAuthHttpServerReplyHandler(8080, this);
this->google->setReplyHandler(replyHandler);
this->google->grant();
qDebug() << "Access";
connect(this->google, &QOAuth2AuthorizationCodeFlow::granted, [=](){
qDebug() << __FUNCTION__ << __LINE__ << "Access Granted!";
auto reply = this->google->get(QUrl("https://www.googleapis.com/plus/v1/people/me"));
connect(reply, &QNetworkReply::finished, [reply](){
qDebug() << "REQUEST FINISHED. Error? " << (reply->error() != QNetworkReply::NoError);
qDebug() << reply->readAll();
});
});
I have been trying to create a directory in root directory of Linux. But as I am not much familiar with Linux platform I am unable to write the correct program in QT. Can you please have a look at my code and tell me where did I did mistake?
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <QString>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QDir mDir;
QString mpath="/home/qtfile";
if (!mDir.exists(mpath))
{
mDir.mkpath(mpath);
qDebug() <<"Created";
}
else if (mDir.exists(mpath))
{
qDebug() <<"Already existed";
}
else
{
qDebug()<<"Directory could not be created";
}
return a.exec();
}
Thank you for your time and consideration
EDIT:- Thank you everyone. Now this problem is solved
This might be the issue of access rights #SamratLuitel is writing about in the comments.
Hence, you could try to give it a go in the proper home location, for example:
const QString& homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
QDir dir(homePath);
if (dir.mkdir("somedir"))
{
//success
}