Qt is a powerful framework for developing cross-platform applications, offering extensive libraries and tools to streamline the development process. This essay provides an overview of essential techniques and best practices for working with Qt, including managing dependencies, handling permissions, incorporating icons, managing translations, enforcing single-instance applications, and implementing basic encryption.
Including Qt Headers
When including Qt headers, if you encounter compilation success but linkage failure, it may be necessary to specify the appropriate namespaces in your project file (.pro
). For example:
QT += core gui
QT += network
QT += xml
QT += webkit
These lines ensure that the necessary Qt modules are linked correctly during the build process.
Obtaining Administrator Privileges
To grant your executable administrative privileges on Windows, you can modify the project file (.pro
) as follows:
QMAKE_LFLAGS += /MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"
This line modifies the linker flags to request elevated permissions when the application is run.
Adding Application Icons
To add an icon to your Qt application, include the following lines in your project file:
RC_FILE = icon.rc
OTHER_FILES += \icon.rc
This configuration ensures that the specified icon resource is included in the build process and linked with the application.
Adding Library Dependencies
Managing dependencies in Qt projects involves specifying include paths and library paths. Update your project file (.pro
) to include necessary libraries as shown:
INCLUDEPATH += $$PWD/../ext/win/include $$PWD/../../boost_1_40_0/boost/property_tree/detail $$PWD/../lib $$PWD/../../boost_1_40_0 $$PWD/../curl $$PWD/../
DEPENDPATH += $$PWD/../ext/win/x86 $$PWD/../../boost_1_40_0/libx86/lib
win32:CONFIG(release, debug|release): {
LIBS += -L$$PWD/../ext/win/x86/ -L$$PWD/../../boost_1_40_0/libx86/lib -L$$PWD/../curl/lib -L$$PWD/plugins/imageformats -lxmlrpc_Win32_Release -lsqlite3_Win32_Release -lWS2_32 -lIPHlpApi -lMpr -lPowrProf \
-libboost_filesystem-vc90-mt-1_42 -lAdvapi32 -lKernel32 -lUser32 -lqgif4 -llibcurl -lws2_32 -llibeay32 -lssleay32
}
else:win32:CONFIG(debug, debug|release): {
LIBS += -L$$PWD/../ext/win/x86/ -L$$PWD/../../boost_1_40_0/libx86/lib -L$$PWD/../curl/lib -L$$PWD/plugins/imageformats -lxmlrpc_Win32_Debug -lsqlite3_Win32_Debug -lWS2_32 -lIPHlpApi -lMpr -lPowrProf \
-libboost_filesystem-vc90-mt-gd-1_42 -lAdvapi32 -lKernel32 -lUser32 -lqgifd4 -llibcurld -lws2_32 -llibeay32 -lssleay32
}
This configuration helps in resolving dependencies by specifying the paths for include files and libraries.
Internationalization
Internationalizing a Qt application involves preparing the project for translations. First, add the following line to the project file to include the translation file:
TRANSLATIONS += scc.ts
In the application code, wrap translatable strings with the tr()
function. To generate and compile translation files, use the lupdate
and lrelease
commands. At the program entry point, load the appropriate translation file based on the selected language:
QTranslator qtTranslator;
if(lang == LANG_EN){
} else if(lang == LANG_ZH){
qtTranslator.load("scc.qm");
a.installTranslator(&qtTranslator);
}
Enforcing Single-Instance Applications
To ensure that only one instance of an application runs at a time, implement a singleton pattern. Below is a typical implementation:
#ifndef SINGLEINSTANCE_H
#define SINGLEINSTANCE_H
#if WIN32
#include <windows.h>
#include <string>
#include "util.h"
using std::string;
class CLimitSingleInstance {
protected:
DWORD m_dwLastError;
HANDLE m_hMutex;
public:
CLimitSingleInstance(string strMutexName) {
string name = "Global\\" + strMutexName;
m_hMutex = CreateMutex(NULL, TRUE, s2ws(name).c_str());
m_dwLastError = GetLastError();
}
~CLimitSingleInstance() {
if (m_hMutex) {
CloseHandle(m_hMutex);
m_hMutex = NULL;
}
}
BOOL IsAnotherInstanceRunning() {
return (ERROR_ALREADY_EXISTS == m_dwLastError || m_hMutex == 0);
}
};
static CLimitSingleInstance g_SingleShineCloudClientInstanceObj("{F5A38595-26E4-4999-AB15-395BC6B23402}");
static inline bool isAnotherSCCRunning() {
return g_SingleShineCloudClientInstanceObj.IsAnotherInstanceRunning();
}
#else
#include <string>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include "db.h"
#include <stdlib.h>
#include "sutil.h"
#include <errno.h>
using std::string;
struct flock* file_lock(short type, short whence) {
static struct flock ret;
ret.l_type = type;
ret.l_start = 0;
ret.l_whence = whence;
ret.l_len = 0;
ret.l_pid = getpid();
return &ret;
}
class CLimitSingleInstance {
string filename;
int fp;
bool isLock;
public:
CLimitSingleInstance(string file) : isLock(false), filename(file), fp(open(file.c_str(), O_CREAT | O_RDWR)) {
if(fp != -1 && fcntl(fp, F_SETLK, file_lock(F_WRLCK, SEEK_SET)) != -1) {
isLock = true;
}
}
CLimitSingleInstance() : isLock(false) {
const char* id = DBGetOptionValue("host_cpid");
string appPath = suGetApplicationPath() + "/locks/";
system(("mkdir -p " + appPath).c_str());
appPath += id;
filename = appPath;
fp = open(filename.c_str(), O_CREAT | O_RDWR);
if(fp != -1) {
system(("chmod u+rw \"" + filename + "\"").c_str());
if(fcntl(fp, F_SETLK, file_lock(F_WRLCK, SEEK_SET)) != -1) {
isLock = true;
}
}
DBReleaseOptionValue(id);
}
~CLimitSingleInstance() {
if(fp != -1) {
fcntl(fp, F_SETLK, file_lock(F_UNLCK, SEEK_SET));
close(fp);
}
}
bool IsAnotherInstanceRunning() {
return (fp == -1) ? false : !isLock;
}
};
static inline bool isAnotherSlaveRunning() {
static CLimitSingleInstance g_SingleShineWonderSlaveInstanceObj;
return g_SingleShineWonderSlaveInstanceObj.IsAnotherInstanceRunning();
}
#endif
#endif // SINGLEINSTANCE_H
Basic Encryption
For basic encryption, you can use the following simple encryption class:
#ifndef SIMPLECRYPT_H
#define SIMPLECRYPT_H
#include <QString>
#include <QVector>
#include <QFlags>
class SimpleCrypt {
public:
enum CompressionMode { CompressionAuto, CompressionAlways, CompressionNever };
enum IntegrityProtectionMode { ProtectionNone, ProtectionChecksum, ProtectionHash };
enum Error { ErrorNoError, ErrorNoKeySet, ErrorUnknownVersion, ErrorIntegrityFailed };
SimpleCrypt();
explicit SimpleCrypt(quint64 key);
void setKey(quint64 key);
bool hasKey() const { return !m_keyParts.isEmpty(); }
void setCompressionMode(CompressionMode mode) { m_compressionMode = mode; }
CompressionMode compressionMode() const { return m_compressionMode; }
void setIntegrityProtectionMode(IntegrityProtectionMode mode) { m_protectionMode = mode; }
IntegrityProtectionMode integrityProtectionMode() const { return m_protectionMode; }
Error lastError() const { return m_lastError; }
QString encryptToString(const QString& plaintext);
QString encryptToString(QByteArray plaintext);
QByteArray encryptToByteArray(const QString& plaintext);
QByteArray encryptToByteArray(QByteArray plaintext);
QString decryptToString(const QString& cyphertext);
QByteArray decryptToByteArray(const QString& cyphertext);
QString decryptToString(QByteArray cypher);
QByteArray decryptToByteArray(QByteArray cypher);
enum CryptoFlag { CryptoFlagNone = 0, CryptoFlagCompression = 0x01, CryptoFlagChecksum = 0x02, CryptoFlagHash = 0x04 };
Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag)
private:
void splitKey();
quint64 m_key;
QVector<char> m_keyParts;
CompressionMode m_compressionMode;
IntegrityProtectionMode m_protectionMode;
Error m_lastError;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(SimpleCrypt::CryptoFlags