How to print to console when using Qt - c++

I'm using Qt4 and C++ for making some programs in computer graphics. I need to be able to print some variables in my console at run-time, not debugging, but cout doesn't seem to work even if I add the libraries. Is there a way to do this?

If it is good enough to print to stderr, you can use the following streams originally intended for debugging:
#include<QDebug>
//qInfo is qt5.5+ only.
qInfo() << "C++ Style Info Message";
qInfo( "C Style Info Message" );
qDebug() << "C++ Style Debug Message";
qDebug( "C Style Debug Message" );
qWarning() << "C++ Style Warning Message";
qWarning( "C Style Warning Message" );
qCritical() << "C++ Style Critical Error Message";
qCritical( "C Style Critical Error Message" );
// qFatal does not have a C++ style method.
qFatal( "C Style Fatal Error Message" );
Though as pointed out in the comments, bear in mind qDebug messages are removed if QT_NO_DEBUG_OUTPUT is defined
If you need stdout you could try something like this (as Kyle Strand has pointed out):
QTextStream& qStdOut()
{
static QTextStream ts( stdout );
return ts;
}
You could then call as follows:
qStdOut() << "std out!";

I found this most useful:
#include <QTextStream>
QTextStream out(stdout);
foreach(QString x, strings)
out << x << endl;

Writing to stdout
If you want something that, like std::cout, writes to your application's standard output, you can simply do the following (credit to CapelliC):
QTextStream(stdout) << "string to print" << endl;
If you want to avoid creating a temporary QTextStream object, follow Yakk's suggestion in the comments below of creating a function to return a static handle for stdout:
inline QTextStream& qStdout()
{
static QTextStream r{stdout};
return r;
}
...
foreach(QString x, strings)
qStdout() << x << endl;
Remember to flush the stream periodically to ensure the output is actually printed.
Writing to stderr
Note that the above technique can also be used for other outputs. However, there are more readable ways to write to stderr (credit to Goz and the comments below his answer):
qDebug() << "Debug Message"; // CAN BE REMOVED AT COMPILE TIME!
qWarning() << "Warning Message";
qCritical() << "Critical Error Message";
qFatal("Fatal Error Message"); // WILL KILL THE PROGRAM!
qDebug() is closed if QT_NO_DEBUG_OUTPUT is turned on at compile-time.
(Goz notes in a comment that for non-console apps, these can print to a different stream than stderr.)
NOTE: All of the Qt print methods assume that const char* arguments are ISO-8859-1 encoded strings with terminating \0 characters.

Add this to your project file:
CONFIG += console

What variables do you want to print? If you mean QStrings, those need to be converted to c-Strings. Try:
std::cout << myString.toAscii().data();

It also has a syntax similar to prinft, e.g.:
qDebug ("message %d, says: %s",num,str);
Very handy as well

Go the Project's Properties -> Linker-> System -> SubSystem, then set it to Console(/S).

What about including iostream library and precise that cout is an object of std like this :
#include <iostream>
std::cout << "Hello" << std::endl;

If you are printing to stderr using the stdio library, a call to fflush(stderr) should flush the buffer and get you real-time logging.

Well, after studying several examples on the Internet describing how to output messages from a GUI in Qt to stdout, I have refined a working stand-alone example on redirecting messages to a console, via qDebug() and installing qInstallMessageHandler(). The console will be showed at the same time as the GUI and can be hidden if deemed necessary. The code is easy to integrate with existing code in your project. Here is the full sample and feel free to use it in any way as you like, as long as you adhere to the License GNU GPL v2. You have to use a form of some sort and a MainWindow I think - otherwise the sample will run, but probably crash when forced to quit. Note: there is no way to quit via a close button or a menu close because I have tested those alternatives and the application will crash eventually every now and then. Without the close button the application will be stable and you can close it down from the main window. Enjoy!
#include "mainwindow.h"
#include <QApplication>
//GNU GPL V2, 2015-02-07
#include <QMessageBox>
#include <windows.h>
#define CONSOLE_COLUMNS 80
#define CONSOLE_ROWS 5000
#define YOURCONSOLETITLE "Your_Console_Title"
typedef struct{
CONSOLE_SCREEN_BUFFER_INFOEX conScreenBuffInfoEX;
HANDLE con_screenbuf;
HWND hwndConsole;
HMENU consoleMenu ;
QString consoleTitle;
QMessageBox mBox;
QString localMsg;
QString errorMessage;
WINBOOL errorCode;
} consoleT;
static consoleT *console;
BOOL WINAPI catchCTRL( DWORD ctrlMsg ){
if( ctrlMsg == CTRL_C_EVENT ){
HWND hwndWin = GetConsoleWindow();
ShowWindow(hwndWin,SW_FORCEMINIMIZE);
}
return TRUE;
}
void removeCloseMenu(){
int i;
for( i = 0; i < 10; i++){
console->hwndConsole = FindWindowW( NULL, console->consoleTitle.toStdWString().data());
if(console->hwndConsole != NULL)
break;
}
if( !(console->errorCode = 0) && (console->hwndConsole == NULL))
console->errorMessage += QString("\nFindWindowW error: %1 \n").arg(console->errorCode);
if( !(console->errorCode = 0) && !(console->consoleMenu = GetSystemMenu( console->hwndConsole, FALSE )) )
console->errorMessage += QString("GetSystemMenu error: %1 \n").arg(console->errorCode);
if(!(console->errorCode = DeleteMenu( console->consoleMenu, SC_CLOSE, MF_BYCOMMAND )))
console->errorMessage += QString("DeleteMenu error: %1 \n").arg(console->errorCode);
}
void initialiseConsole(){
console->conScreenBuffInfoEX.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
console->consoleMenu = NULL;
console->consoleTitle = YOURCONSOLETITLE;
console->con_screenbuf = INVALID_HANDLE_VALUE;
console->errorCode = 0;
console->errorMessage = "";
console->hwndConsole = NULL;
console->localMsg = "";
if(!(console->errorCode = FreeConsole()))
console->errorMessage += QString("\nFreeConsole error: %1 \n").arg(console->errorCode);
if(!(console->errorCode = AllocConsole()))
console->errorMessage += QString("\nAllocConsole error: %1 \n").arg(console->errorCode);
if( (console->errorCode = -1) && (INVALID_HANDLE_VALUE ==(console->con_screenbuf = CreateConsoleScreenBuffer( GENERIC_WRITE | GENERIC_READ,0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL))))
console->errorMessage += QString("\nCreateConsoleScreenBuffer error: %1 \n").arg(console->errorCode);
if(!(console->errorCode = SetConsoleActiveScreenBuffer(console->con_screenbuf)))
console->errorMessage += QString("\nSetConsoleActiveScreenBuffer error: %1 \n").arg(console->errorCode);
if(!(console->errorCode = GetConsoleScreenBufferInfoEx(console->con_screenbuf, &console->conScreenBuffInfoEX)))
console->errorMessage += QString("\nGetConsoleScreenBufferInfoEx error: %1 \n").arg(console->errorCode);
console->conScreenBuffInfoEX.dwSize.X = CONSOLE_COLUMNS;
console->conScreenBuffInfoEX.dwSize.Y = CONSOLE_ROWS;
if(!(console->errorCode = SetConsoleScreenBufferInfoEx(console->con_screenbuf, &console->conScreenBuffInfoEX)))
console->errorMessage += QString("\nSetConsoleScreenBufferInfoEx error: %1 \n").arg(console->errorCode);
if(!(console->errorCode = SetConsoleTitleW(console->consoleTitle.toStdWString().data())))
console->errorMessage += QString("SetConsoleTitle error: %1 \n").arg(console->errorCode);
SetConsoleCtrlHandler(NULL, FALSE);
SetConsoleCtrlHandler(catchCTRL, TRUE);
removeCloseMenu();
if(console->errorMessage.length() > 0){
console->mBox.setText(console->errorMessage);
console->mBox.show();
}
}
void messageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg){
if((console->con_screenbuf != INVALID_HANDLE_VALUE)){
switch (type) {
case QtDebugMsg:
console->localMsg = console->errorMessage + "Debug: " + msg;
WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length(), NULL, NULL );
WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
break;
case QtWarningMsg:
console->localMsg = console->errorMessage + "Warning: " + msg;
WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length() , NULL, NULL );
WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
break;
case QtCriticalMsg:
console->localMsg = console->errorMessage + "Critical: " + msg;
WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length(), NULL, NULL );
WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
break;
case QtFatalMsg:
console->localMsg = console->errorMessage + "Fatal: " + msg;
WriteConsoleW(console->con_screenbuf, console->localMsg.toStdWString().data(), console->localMsg.toStdWString().length(), NULL, NULL );
WriteConsoleA(console->con_screenbuf, "\n--\n", 4, NULL, NULL );
abort();
}
}
}
int main(int argc, char *argv[])
{
qInstallMessageHandler(messageHandler);
QApplication a(argc, argv);
console = new consoleT();
initialiseConsole();
qDebug() << "Hello World!";
MainWindow w;
w.show();
return a.exec();
}

"build & run" > Default for "Run in terminal" --> Enable
to flush the buffer use this command --> fflush(stdout);
you can also use "\n" in printf or cout.

For Qt5 QString must be converted, for example:
QString sResultText = lblLineEdit->text(); //<--text from QLineEdit
qInfo(sResultText.toUtf8().data()); //<--show converted result

Related

How to check if QProcess is executing correctly?

QProcess process_sdcompare;
QString command_sdcompare;
QStringList args_sdcompare;
command_sdcompare = "diff";
args_sdcompare << "Filename" << "Filename";
process_sdcompare.start(command_sdcompare,args_sdcompare,QIODevice::ReadOnly);
process_sdcompare.waitForFinished();
QString StdOut_sdcompare = process_sdcompare.readAllStandardOutput(); //Reads standard output
QString StdError_sdcompare = process_sdcompare.readAllStandardError(); //Reads standard error
if(StdOut_sdcompare.isEmpty()) //the process output is checked here if empty it is a success
return 1;
I am running the above code. When I check for an error condition after comparing not similar text files, isEmpty() returns false.
How do I check if the QProcess execution occurred without errors?
I use QProcess::error() to query the last error (for quick debugging), however a "nicer" way to do it:
// capture any errors (do this before you run the process)
connect(&process_sdcompare, &QProcess::errorOccurred, this, &ThisClass::processError);
Then define slot:
ThisClass::processError(QProcess::ProcessError error)
{
qDebug() << "error enum val = " << error << endl;
}
update
Or with Lambda:
// No need to define a slot function...
connect(&process_sdcompare, &QProcess::errorOccurred, [=](QProcess::ProcessError error)
{
qDebug() << "error enum val = " << error << endl;
});
I think all the status and error functions are pretty useless to figure out if the process execution was actually successful. Example, trying to execute a program which does not exist (under windows):
error(): QProcess::ProcessError(FailedToStart)
exitStatus(): QProcess::ExitStatus(NormalExit)
exitCode(): 0
errorString(): "Process failed to start: Das System kann die angegebene Datei nicht finden."
If the process was actually executed successfully:
error(): QProcess::ProcessError(UnknownError)
exitStatus(): QProcess::ExitStatus(NormalExit)
exitCode(): 0
errorString(): "Unknown error"
So I would consider "Unknown error" not an indicator for success.
The solution I think could look like this:
QProcess *m_proc = new QProcess(this);
bool errorOccured = false;
QProcess::ProcessError procError;
QObject::connect(m_proc, &QProcess::errorOccurred, [&](QProcess::ProcessError error)
{
procError = error;
errorOccured = true;
});
m_proc->start(...);
When waitForFinished returns, it returns a bool that broadly indicates success. As Karsten recommended, you can then check for actual success or failure using QProcess::exitCode.
This is how you use QProcess
QProcess process_sdcompare;
QStringList args_sdcompare;
args_sdcompare << "Filename" << "Filename";
process_sdcompare.setProgram("diff");
process_sdcompare.setArguments(args_sdcompare);
process_sdcompare.start();
if (process_sdcompare.waitForStarted() && process_sdcompare.waitForFinished()) {
QString StdOut_sdcompare = process_sdcompare.readAllStandardOutput();
QString StdError_sdcompare = process_sdcompare.readAllStandardError();
if(StdOut_sdcompare.isEmpty())
return 1;
}
}

C++: Reading data from printer

I'm trying to read the status and some other information from a printer, however I'm not getting any data returned from the printer. I can't figure out what I'm missing or doing wrong?
I'm using Qt creator where I have included the WinSpool library
As a side note: This is my first time trying to read data from a piece of hardware.
The msdn pages for the printer functions are:
SetPrinterData GetPrinterData OpenPrinter
Code
BOOL status = false;
HANDLE hPrinter = NULL;
PRINTER_DEFAULTS defaults;
defaults.pDatatype = (LPTSTR)__TEXT("RAW");
defaults.pDevMode = 0;
defaults.DesiredAccess = PRINTER_READ;
status = OpenPrinter((LPTSTR)__TEXT("CN551A"),&hPrinter,&defaults);
if(status) {
qDebug() << "Status: OPEN OK";
}
// pValueName found in registry
LPTSTR pValueName = (LPTSTR)"PrinterData";
DWORD type = REG_BINARY;
BYTE pData[2];
pData[0] = 0;
pData[1] = 0;
status = SetPrinterData(&hPrinter,pValueName,type,pData,sizeof(pData));
if(status) {
qDebug() << "Status: SET OK";
}
BYTE buffer[263];
LPDWORD pcbNeeded = 0;
LPDWORD pType = (LPDWORD)REG_BINARY;
status = GetPrinterData(&hPrinter, pValueName,pType,buffer,sizeof(buffer),
pcbNeeded);
if(status) {
qDebug() << "Status: GET OK";
qDebug() << "pType: " << pType;
qDebug() << "pcbNeeded " << pcbNeeded;
qDebug() << "buffer " << *buffer;
/* Prints a bunch of numbers
for(int i =0; i < sizeof(buffer); i++) {
qDebug() << buffer[i];
}
*/
}
ClosePrinter(&hPrinter);
Output
Status: OPEN OK
Status: SET OK
Status: GET OK
pType: 0x3
pcbNeeded 0x0
buffer 1
I'm using Qt creator where I have included the WinSpool library
As a side note: This is my first time trying to acheive this.
Edit
I found a C# program which reads status and information in the ReadBytesFromPrinter function in PrintLabel.cs using Windows API calls, just like I would like to, but I still wasn't able to figure out my mistake/error. Thought I'd link it, if someone could spot what's wrong with my code compared to theirs.
You're misinterpreting the return values of the GetPrinterData and SetPrinterData. Those calls are in fact failing, not succeeding. The return value for success is ERROR_SUCCESS, which I believe you'll find is zero. Any other value is the error code you need to display and investigate. See the MSDN entry for SetPrinterData.

Move files to Trash/Recycle Bin in Qt

Is there a Qt function to move files to Recycle Bin instead of truly deleting them, for OSes that support it, or do I need to use OS-specific code?
Since Qt 5.15.0 Alpha, this method has been added, which should be what you were looking for.
bool QFile::moveToTrash()
The corresponding code changes can be found here.
(This issue is old and the corresponding Bugreport at https://bugreports.qt.io/browse/QTBUG-47703 has already been posted, but I currently lack the reputation to comment, and found this to be a useful information.)
Qt doesnt provide a MoveToTrash. Here's a part of my code
for Windows
#ifdef Q_OS_WIN32
#include "windows.h"
void MoveToTrashImpl( QString file ){
QFileInfo fileinfo( file );
if( !fileinfo.exists() )
throw OdtCore::Exception( "File doesnt exists, cant move to trash" );
WCHAR from[ MAX_PATH ];
memset( from, 0, sizeof( from ));
int l = fileinfo.absoluteFilePath().toWCharArray( from );
Q_ASSERT( 0 <= l && l < MAX_PATH );
from[ l ] = '\0';
SHFILEOPSTRUCT fileop;
memset( &fileop, 0, sizeof( fileop ) );
fileop.wFunc = FO_DELETE;
fileop.pFrom = from;
fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
int rv = SHFileOperation( &fileop );
if( 0 != rv ){
qDebug() << rv << QString::number( rv ).toInt( 0, 8 );
throw OdtCore::Exception( "move to trash failed" );
}
}
#endif
and for Linux
#ifdef Q_OS_LINUX
bool TrashInitialized = false;
QString TrashPath;
QString TrashPathInfo;
QString TrashPathFiles;
void MoveToTrashImpl( QString file ){
#ifdef QT_GUI_LIB
if( !TrashInitialized ){
QStringList paths;
const char* xdg_data_home = getenv( "XDG_DATA_HOME" );
if( xdg_data_home ){
qDebug() << "XDG_DATA_HOME not yet tested";
QString xdgTrash( xdg_data_home );
paths.append( xdgTrash + "/Trash" );
}
QString home = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
paths.append( home + "/.local/share/Trash" );
paths.append( home + "/.trash" );
foreach( QString path, paths ){
if( TrashPath.isEmpty() ){
QDir dir( path );
if( dir.exists() ){
TrashPath = path;
}
}
}
if( TrashPath.isEmpty() )
throw Exception( "Cant detect trash folder" );
TrashPathInfo = TrashPath + "/info";
TrashPathFiles = TrashPath + "/files";
if( !QDir( TrashPathInfo ).exists() || !QDir( TrashPathFiles ).exists() )
throw Exception( "Trash doesnt looks like FreeDesktop.org Trash specification" );
TrashInitialized = true;
}
QFileInfo original( file );
if( !original.exists() )
throw Exception( "File doesnt exists, cant move to trash" );
QString info;
info += "[Trash Info]\nPath=";
info += original.absoluteFilePath();
info += "\nDeletionDate=";
info += QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss.zzzZ");
info += "\n";
QString trashname = original.fileName();
QString infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
QString filepath = TrashPathFiles + "/" + trashname;
int nr = 1;
while( QFileInfo( infopath ).exists() || QFileInfo( filepath ).exists() ){
nr++;
trashname = original.baseName() + "." + QString::number( nr );
if( !original.completeSuffix().isEmpty() ){
trashname += QString( "." ) + original.completeSuffix();
}
infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
filepath = TrashPathFiles + "/" + trashname;
}
QDir dir;
if( !dir.rename( original.absoluteFilePath(), filepath ) ){
throw Exception( "move to trash failed" );
}
File infofile;
infofile.createUtf8( infopath, info );
#else
Q_UNUSED( file );
throw Exception( "Trash in server-mode not supported" );
#endif
}
#endif
There is no API yet.
https://bugreports.qt.io/browse/QTBUG-181
The issue is closed and the fix version is: Some future release
Edit: A new issue has been opened at https://bugreports.qt.io/browse/QTBUG-47703.
Edit Apparently it is now done in 5.15.0 Alpha bool QFile::moveToTrash()
I think that there is no cross-platform way. Simple moving files to "trash" location will not give effect, because user may switch off this possibility.
Maybe, this url will help: http://www.hardcoded.net/articles/send-files-to-trash-on-all-platforms.htm
I'm relatively certain that there is no Qt API that wraps this for all supported platforms. That means, unfortunately, that you will have to write platform-specific code.
I don't know anything about where/how Linux distributions store deleted files, and I imagine that it probably varies depending on which file manager you're using. I believe that moving files to a ~/.Trash folder is the standard way of doing it, but I'm not sure if this is reliable. For example, in the case of files stored on external volumes.
Things are a bit easier on Mac OS X, where there is a supported API to do this: FSMoveObjectToTrashSync, provided by Core Services. At least, that's how I remember you're supposed to do it. The documentation claims that this method is now deprecated in OS X 10.8. I have no idea what the recommended alternative is.
As a Windows programmer, I think that platform is much easier. :-) The basic solution is to call the SHFileOperation function:
#include <Windows.h> // general Windows header file
#include <ShellAPI.h> // for shell functions, like SHFileOperation
#include <string> // (or use QString)
void RecycleFileOnWindows()
{
std::wstring path = L"C:\\Users\\Administrator\\Documents\\deleteme.txt";
path.append(1, L'\0'); // path string must be double nul-terminated
SHFILEOPSTRUCT shfos = {};
shfos.hwnd = nullptr; // handle to window that will own generated windows, if applicable
shfos.wFunc = FO_DELETE;
shfos.pFrom = path.c_str();
shfos.pTo = nullptr; // not used for deletion operations
shfos.fFlags = FOF_ALLOWUNDO; // use the recycle bin
const int retVal = SHFileOperation(&shfos);
if (retVal != 0)
{
// The operation failed...
if (shfos.fAnyOperationsAborted)
{
// ...but that's because the user canceled.
MessageBox(nullptr, L"Operation was canceled", nullptr, MB_OK | MB_ICONINFORMATION);
}
else
{
// ...for one of the other reasons given in the documentation.
MessageBox(nullptr, L"Operation failed", nullptr, MB_OK | MB_ICONERROR);
}
}
}
There are also flags that you can set to customize confirmation, error reporting, and other behavior. The linked documentation contains all the details you need to build upon this basic example.
On Windows Vista and later, the SHFileOperation function has been superseded by the methods provided by the IFileOperation interface. If you're targeting only these later versions of Windows, you should prefer to use this interface. Otherwise, SHFileOperation will continue to work fine.
if(QSysInfo::kernelType()=="linux")
{
QDateTime currentTime(QDateTime::currentDateTime()); // save System time
QString trashFilePath=QDir::homePath()+"/.local/share/Trash/files/"; // trash file path contain delete files
QString trashInfoPath=QDir::homePath()+"/.local/share/Trash/info/"; // trash info path contain delete files information
// create file format for trash info file----- START
QFile infoFile(trashInfoPath+FileName.completeBaseName()+"."+FileName.completeSuffix()+".trashinfo"); //filename+extension+.trashinfo // create file information file in /.local/share/Trash/info/ folder
infoFile.open(QIODevice::ReadWrite);
QTextStream stream(&infoFile); // for write data on open file
stream<<"[Trash Info]"<<endl;
stream<<"Path="+QString(QUrl::toPercentEncoding(FileName.absoluteFilePath(),"~_-./"))<<endl; // convert path string in percentage decoding scheme string
stream<<"DeletionDate="+currentTime.toString("yyyy-MM-dd")+"T"+currentTime.toString("hh:mm:ss")<<endl; // get date and time format YYYY-MM-DDThh:mm:ss
infoFile.close();
// create info file format of trash file----- END
QDir file;
file.rename(FileName.absoluteFilePath(),trashFilePath+FileName.completeBaseName()+"."+FileName.completeSuffix()); // rename(file old path, file trash path)
}
Trash files in linux exist /home/user_name/.local/share/Trash/files/ directory but it also require info file for each trash file which exist in /home/user_name/.local/share/Trash/info/ directory. when we want to move file into trash, actually move file into /home/user_name/.local/share/Trash/files/ directory and create info file in /home/user_name/.local/share/Trash/info/ directory. inside .trashinfo format use percentage decoding scheme for set file path where file existed, info file also contain time and date of deletion.

Windows Semaphore and QSystemSemaphore

I have a problem with semaphores in Windows between two application. An application waits for release signal(Qt) and the other application sends release signal(MSVC2008). But it dose not work.
I tested Qt-Qt and MSVC2008-MSVC2008 modes and they was succeed. But when I try Qt-MSVC2008 mode it fails.
// MSVC2008:
#include <windows.h>
#include <stdio.h>
int main()
{
const WCHAR semName[] = L"TestSem";
PHANDLE sem = (HANDLE *) CreateSemaphore (NULL, 0, 1, semName);
if (sem == NULL)
{
sem = (HANDLE *)OpenSemaphore (SEMAPHORE_ALL_ACCESS, 0, semName);
}
if (sem == NULL)
{
printf("OPEN/CREATE ERROR\n");
return 0;
}
BOOL r = ReleaseSemaphore(sem, 1 ,NULL);
if (r)
printf("OK\n");
else
printf("RELEASE ERROR\n");
CloseHandle (sem);
return 0;
}
and
// Qt 4.8.0 :
#include <QSystemSemaphore>
#include <QCoreApplication>
#include <iostream>
int main()
{
QSystemSemaphore *sem_read = new QSystemSemaphore("TestSem");
std::cout << "Wait for signal: " << std::endl;
while (1)
{
sem_read->acquire();
std::cout << "Hi" << std::endl;
}
return 0;
}
I expect when Qt-app is running, after executing MSVC2008-app, it prints one "Hi" in the screen. But it dose not. What is the problem?!
Note: I'm using Windows 7 and MinGW compiler for Qt
Looking at the Qt sources (4.7.3) I see at corelib/kernel/qsystemsemaphore_p.h:79 that the semaphore name generated by Qt is prefixed by qipc_systemsem_.
[UPDATE] The sha1 hash of "TestSem" is also appended, so the resulting Qt semaphore name is qipc_systemsem_TestSem3ec37c26f212774998f34a4e6722cac152ad17fa
Confirmed working.
To generate the semaphore name:
QString prefix = "qipc_systemsem_";
QString key = "TestSem";
QString result = prefix;
QString part1 = key;
part1.replace(QRegExp(QLatin1String("[^A-Za-z]")), QString());
result.append(part1);
QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex();
result.append(QLatin1String(hex));
qDebug() << result;
2 things I'd look into:
QSystemSemaphore requires an initial values and initiated with 0 if it is not given. Maybe start it with 1?
this is a system semaphore, could it be that your first test did not release it? try to change the name maybe.

When calling ReadDirectoryChangesW, only the first call returns any changes (both sync and async)

The following is a minimal program which uses ReadDirectoryChangesW. The problem I am having is that only the first call to GetQueuedCompletionStatus returns. The second time through the loop it blocks forever no matter how many changes are made to the directory.
I have also attempted using the synchronous version and have the exact same problem.
#include <array>
#include <cassert>
#include <iostream>
#include <Windows.h>
int main() {
// Open the directory to monitor.
HANDLE dir = ::CreateFileA(
"G:\\Program Files (x86)\\Steam\\steamapps\\common\\eve online"
, FILE_LIST_DIRECTORY
, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
, NULL
, OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED
, NULL
);
if (dir == INVALID_HANDLE_VALUE) {
std::cout << "Failed to open directory for change notifications!\n";
return 1;
}
// Setup IOCP.
HANDLE iocp = ::CreateIoCompletionPort(
dir
, NULL
, NULL
, 1
);
// Monitor.
while (true) {
std::array<char, 1024 * 8> buf;
DWORD bytes_read;
OVERLAPPED overlapped;
std::memset(&overlapped, 0, sizeof(overlapped));
BOOL result = ::ReadDirectoryChangesW(
dir
, &buf.front()
, buf.size()
, false
, FILE_NOTIFY_CHANGE_FILE_NAME // Includes file creation.
, &bytes_read
, &overlapped
, NULL
);
if (result == FALSE) {
DWORD error = ::GetLastError();
std::cout << "Call to ReadDirectoryChangesW failed! " << error << "\n";
return 1;
}
// Wait for completion.
ULONG_PTR key;
LPOVERLAPPED overlapped_result;
result = ::GetQueuedCompletionStatus(
iocp
, &bytes_read
, &key
, &overlapped_result
, INFINITE
);
if (result == FALSE) {
std::cout << "Call to GetQueuedCompletionStatus failed!\n";
return 1;
}
// Print results!
for (FILE_NOTIFY_INFORMATION *fni =
reinterpret_cast<FILE_NOTIFY_INFORMATION *>(&buf.front());
;
fni = reinterpret_cast<FILE_NOTIFY_INFORMATION *>(
reinterpret_cast<char *>(fni) + fni->NextEntryOffset)) {
std::wstring filename(fni->FileName, fni->FileName + fni->FileNameLength);
std::wcout << "Got change: " << filename.c_str() << "\n";
if (fni->NextEntryOffset == 0) break;
}
}
}
A few problems.
First, you're trying to output multi-byte string literals to wcout. You should turn them into wide strings by prepending L.
Second, the FileNameLength variable represents the length of the name in bytes, not characters. You should divide it by 2 to get the number of characters.
How are you compiling this? Using Visual Studio it fails to compile because the third parameter to GetQueuedCompletionStatus is typed incorrectly. The parameter should be a pointer to a pointer to ULONG, not a pointer to ULONG. When I changed the declaration of the "key" variable to
ULONG_PTR key;
the programs works correctly.
The problem is your print logic is causing a buffer overrun because fni->FileNameLength is in bytes, not characters. Random memory corruption would explain why I got different results than you.
The fix is simply this:
std::wstring filename(fni->FileName, fni->FileName + fni->FileNameLength / sizoeof(fni->FileName[0]));