I'm developing an app which have to implement a WiFi connection mechanism (it'll be a fullscreen touchscreen app). To do that I'm using the DBus to communicate with Network Manager. I managed to successfully make it scan access points and list them in the QTableView. Next thing will be to connect to the chosen wifi network. First thing I do when trying to connect is checking if there is an existing connection to that access point already in the system so I do this:
settings = new QDBusInterface("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Settings", "org.freedesktop.NetworkManager.Settings", dbusConnection, this);
QDBusMessage msg = settings->call("ListConnections");
QDBusArgument arg = msg.arguments().at(0).value<QDBusArgument>();
QList<QDBusObjectPath> pathsList = qdbus_cast<QList<QDBusObjectPath>>(arg);
foreach (QDBusObjectPath p, pathsList) {
QDBusInterface *conn = new QDBusInterface("org.freedesktop.NetworkManager", p.path(), "org.freedesktop.NetworkManager.Settings.Connection", dbusConnection);
QDBusMessage msg = conn->call("GetSettings");
qDebug() << "Reply: " << msg;
}
I receive the message and can read it with qDebug(). The message is in d-bus format: a{sa{sv}} as the documentation for Network Manager says. And I have problem to parse it to any usable form. From what I understand, the equivalent Qt classes I should put the data to are:
QList<QMap<QString, QMap<QString, QVariant>>>
And I think I should do it with the QDBusArgument class but can't figure out how exactly it should be done. Can someone tell me what is the best way to do this?
Thanks.
I managed to solve my problem, it turned out to be quite easy. I created the map object and used >> operator:
QDBusArgument arg = args.at(0).value<QDBusArgument>();
QMap<QString, QMap<QString, QVariant>> map;
arg >> map;
Related
I am using QProcess::start to launch Qt Assistant with my custom help project file. It works fine until i load project(not help project file) to my programm. Programm generates images from specific data using custom library. Even when all processes ends and i see generated images and nothing else happens, when i trying to launch Qt Assistant, my programm hangs at QProcess:start function when trying to start process. The code is:
show() function(public):
if (!run())
return false;
QByteArray ba("setSource ");
ba.append("qthelp://insyn_help/doc/");
proc->write(ba + page.toLocal8Bit() + '\n');
return true;
run() function(private):
if (!proc)
proc = new QProcess();
if (proc->state() == QProcess::Running)
return true;
QString app = QString(QT_BIN_DIR) + QDir::separator() + QString("assistant");
QString path = QString(PREFIX) + QString(HELP_INSTALL_PATH) + QString("/help_project.qhc");
QStringList args;
args << QLatin1String("-collectionFile")
<< QLatin1String(path.toLatin1())
<< QLatin1String("-enableRemoteControl");
QFileInfo help_project(path);
if (help_project.exists()) {
proc->start(app,args);
if (!proc->waitForStarted()) {
m_exitCode = 1;
emit closed();
return false;
}
}
This code is a part of AssistantLauncher class which was registered using qmlRegisterType and added to main.qml as a member of application window. My programm doesn't touch it anywhere (except calling a method show()). It is separate object (except it is a part of appWindow). The question is why does the process can not start only after my programm did some work? And why QProcess::start even dont have timeout.
UPD: I moved proc->start(app,args); to the child process, which i getting by using fork() and now my programm hangs on pid_t child = fork(). So the problem is that new process can not be created.
The answer is to do not use fork() because it is dangerous in big projects. More at http://www.evanjones.ca/fork-is-dangerous.html . posix_spawn also hangs my project. Now i decided to fork() new process at the beginning and send commands to it through the pipe.
Im trying to send some data using the bulkout endpoint of a usb device.
I can open the usb device (corsair k65rgb keyboard) interface 2 (which control the lighting) using createfile and SetupDiGetDeviceInterfaceDetail.
But the example code I have write data using HidD_SetFeature. And from the usb sniffer it write urb function classe interface (using the control endpoint)
but when I open corsair cue software it use urb function bulk or interrupt transfer.
So I know its possible to send bulk data. But im lost on how to do it
Thank you
I use QT 5.9 and VS2015
You could try the winusb call WinUsb_WritePipe() for transfering data using bulk transfers.
A interface handle is required before we can use WinUsb calls.It is obtained by using setupApi calls and after the required device is found.
Use CreateFile() call to open the file handle and perform WinUsb_Initialise() to obtain the interface handle.
We can use this interface handle for further WinUsb calls.For Bulk transfer we would also require pipe(Endpoint) information which can be obtained by
WinUsb_QueryPipe() call.
Check the following reference for list of winusb calls:
https://learn.microsoft.com/en-us/windows/desktop/api/winusb/
This is an example code for Bulk transfer using a winusb call.
BOOL WriteToBulkEndpoint(WINUSB_INTERFACE_HANDLE hDeviceHandle, UCHAR* pID, ULONG* pcbWritten)
{
if (hDeviceHandle==INVALID_HANDLE_VALUE || !pID || !pcbWritten)
{
return FALSE;
}
BOOL bResult = TRUE;
UCHAR szBuffer[] = "Hello World";
ULONG cbSize = strlen(szBuffer);
ULONG cbSent = 0;
bResult = WinUsb_WritePipe(hDeviceHandle, *pID, szBuffer, cbSize, &cbSent, 0);
if(!bResult)
{
goto done;
}
printf("Wrote to pipe %d: %s \nActual data transferred: %d.\n", *pID, szBuffer, cbSent);
*pcbWritten = cbSent;
done:
return bResult;
}
Check the following reference for more details:
Refer:
https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/using-winusb-api-to-communicate-with-a-usb-device
https://learn.microsoft.com/en-us/windows/desktop/api/winusb/nf-winusb-winusb_writepipe
I am trying to scan my serial ports periodically to see if my device is connected or not. Here is what I have done and it works well. I would like to see if there is a better and optimized way to do so.
I created the following timer in my constructor to check the serial port frequently. I made a method (scanSerialPorts()) and call it every 1 second.
QTimer *timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(scanSerialPorts()));
timer->start(1000);
This is my scanSerialPorts() implementation:
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
currentPortName = info.systemLocation();
}
if (currentPortName == "My Desired PortName" ) {
updateSettings();
if ( !serial->isOpen()){
qDebug() << "Serial Not Open";
openSerialPort();
}
} else
{
serial->close();
}
updateSettings(); // Fills up the serial port parameters.
openSerialPort(); //Opens up the serial port.
I used QT examples to write this. Please let me know what you think and how I can make it better.
As it is, you only scan the last port, since the rest of the code is outside the foreachloop;
You close the other (probably not opened) ports instead of the one you're opening
Most probably, availablePorts won't change during execution, so you could move it outside of the scan function to save some processing time in the timer. The same for updateSettings().
I am developing a simple tcp server with qt. There is no problem with that. But the problem is, i have listed every connected client in a listbox and i want to see the incoming data only from the selected client from the listbox but i can only see the last connected client's messages.
here is the code,
this is the constructor part
server = new QTcpServer();
client = new QTcpSocket();
connect(server, SIGNAL(newConnection()),this, SLOT(acceptConnection()));
server->listen(QHostAddress::Any, ui->txtPort->text().toInt(bool(),10));
if(server->isListening())
{
ui->statusBar->showMessage("Server Started..");
}
else
{
ui->statusBar->showMessage("Server Not Started..");
}
connect(client,SIGNAL(disconnected()),this,SLOT(client_disconnected()));
connect(ui->listWidget,SIGNAL(clicked(QModelIndex)),this,SLOT(selected_client()));
here is acceptConnection() part
client = server->nextPendingConnection();
ui->listWidget->insertItem(client_count,client->peerAddress().toString());
client_count++;
and this is the listWidget item's selected item event
ui->txtRead->clear();
selected_client_index = ui->listWidget->currentIndex().row();
connect(client, SIGNAL(readyRead()),this, SLOT(startRead()));
and lastly the startRead() part
char buffer[1024] = {0};
client->read(buffer, client->bytesAvailable());
qDebug() << buffer;
ui->txtRead->insertPlainText(buffer);
How can i select the specific client and show its messages ?
Thanks in advance.
You should not use client in startRead, but some selectedClient, that You remembers in selected_client() SLOT.
As for now, when You use client = server->nextPendingConnection(), You are losing any previous clients. You should save them into some QList<QTcpSocket*>.
i am wondering if its possible to solve this problem.
Ive got qt application and if user tick the checkbox, i want this application to launch on startup of operating system.
Ive already googled, and ive come up with this solution>
my QT application needs admin privileges in order to modify registry, so
create manifest file ( <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>)
2.apply this command
mt -manifest manifestfile -outputresource:binfile.exe;1
3.use this piece of code in QT to modify registry
void MainWindow::set_on_startup() {
QSettings settings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
if (ui->checkBox->checkState()) {
QString value = QCoreApplication::applicationFilePath(); //get absolute path of running exe
QString apostroph = "\"";
#ifdef DEBUG
ui->textEdit->append(QCoreApplication::applicationFilePath ());
#endif
value.replace("/","\\");
value = apostroph + value + apostroph + " --argument";
#ifdef DEBUG
ui->textEdit->append(value);
#endif
//write value to the register
settings.setValue("name", value);
}
else {
settings.remove("name");
}
}
So, this looks good right ?
BUT... application with default admin priveleges cant be launched on startup of operating system, BUT application without admin priveleges cant modify registry. So , there is one solution - tell a user, that if he wants to set this "startup" option, he first needs to start application as admin, then the application will be able to modify registry, and default privileges will remain "asInvoker", but this seems really impractical and i think that users will be discouraged by this.
So, how to solve this problem ? how other applications solve this problem ?
You won't need admiministrator privileges if you use following key:
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
Notice
HKEY_CURRENT_USER
instead of using
HKEY_LOCAL_MACHINE
My 2 cents! : )
Why not simply put the app shortcut in "Startup" folder.
Qt provides a cross-platform way of determining the paths to many default system directories using the QDesktopServices class.
(Source: Thanks to Dave Mateer for his answer to this question.)
The method is:
QDesktopServices::storageLocation(QDesktopServices::ApplicationsLocation)
This gives (on my Win 7):
C:\Users\user_name\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
and all we need is:
C:\Users\user_name\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Simple!
I use this without any hassle of UAC or any kind of rights problem in most of my apps.
This may not be the best way... but it is certainly an easy way.
(Please pitch in thoughts/comments if this approach has any big disadvantages.)
Update:
To create the short-cut for the application in startup folder, use this code:
QFileInfo fileInfo(QCoreApplication::applicationFilePath());
QFile::link(QCoreApplication::applicationFilePath(), QDesktopServices::storageLocation(QDesktopServices::ApplicationsLocation) + QDir::separator() + "Startup" + QDir::separator() + fileInfo.completeBaseName() + ".lnk");
I hope this helps! : )
Include this header QSettings
#include <QSettings>
And add this into your code.
QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run",
QSettings::NativeFormat);
settings.setValue("YourApplicationName",
QCoreApplication::applicationFilePath().replace('/', '\\'));
For everybody who are trying to solve the problem, this is the 100% working solution:
How can I ask the user for elevated permissions at runtime?
create app1.exe
create app2.exe with admin priveleges - tutorial is in the first post (manifest file, mt.exe, etc..)
when user tick the checkbox in app1.exe, i call the the app2.exe (for example with no arguments) - you can find all function for this # the link ive just posted above
// well, in fact, you dont have to use the function from the example above:
i find this call much better
QObject *parent = new QObject();
QString program = AppToExec; //"/path/to/the/app2.exe"
QStringList arguments ;
arguments << ""; //just in case we want arguments
QProcess *myProcess = new QProcess(parent);
myProcess->start(program);
app2.exe, for example
QApplication a(argc, argv);
MainWindow w;
// w.show();
if (argc == 1) {
w.test();
a.quit();
}
problem solved.
Using this link
create stratup app and code:
void make_startup_app(){
QString appName = "app.exe";
QString appNameLink = appName+".lnk";
QFile::link(appName, appNameLink);
QString userName = QDir::home().dirName();
QString dir_startup = "C:/Users/" + userName +
"/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/"+ appNameLink;
QFile::copy(appNameLink, dir_startup);
}