2
* activeprofiles_win.cpp - Class for interacting with other app instances
3
* Copyright (C) 2006 Maciej Niedzielski
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "activeprofiles.h"
22
#include "applicationinfo.h"
25
#include <QCoreApplication>
33
This file uses WinAPI a lot. It is important to remember that we still want to support Win9x family.
34
For that reason, we have to use QT_WA macro for functions that exist in two versions.
36
Also note that writing QString("x").toLocal8Bit().constData() is a bad idea and must not be done.
39
class ActiveProfiles::Private : public QWidget
42
Private(ActiveProfiles *aprof) : app(ApplicationInfo::IPCName()), home(ApplicationInfo::homeDir()), ap(aprof), profile(""), mutex(0), changesMutex(0) {
44
app.replace('\\', '/'); // '\\' has a special meaning in mutex name
45
home.replace('\\', '/');
47
const QString m = QString("%1 ChangesMutex {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app);
48
const QString c = QString("%1 IPC Command {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}").arg(app);
51
changesMutex = CreateMutex(0, FALSE, (LPCWSTR)m.utf16());
52
psiIpcCommand = RegisterWindowMessage((LPCWSTR)c.utf16());
54
QByteArray a = m.toLocal8Bit(); // must not call constData() of a temp object
55
changesMutex = CreateMutexA(0, FALSE, (LPCSTR)a.constData());
57
psiIpcCommand = RegisterWindowMessageA((LPCSTR)a.constData());
61
qWarning("Couldn't create IPC mutex");
64
qWarning("Couldn't register IPC WM_message");
68
QString app, home, profile;
69
ActiveProfiles * const ap;
70
HANDLE mutex, changesMutex;
72
QString mutexName(const QString &profile) const {
73
return "ProfileMutex\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}";
76
QString windowName(const QString &profile) const {
77
return "ProfileWindow\0x01" + app + "\0x01" + home + "\0x01" + profile + "\0x01 {4F5AEDA9-7D3D-4ebe-8614-FB338146CE80}";
81
WaitForSingleObject(changesMutex, INFINITE);
85
ReleaseMutex(changesMutex);
88
void setWindowText(const QString &text) {
90
SetWindowTextW(winId(), (LPCWSTR)text.utf16());
92
QByteArray a = text.toLocal8Bit();
93
SetWindowTextA(winId(), (LPCSTR)a.constData());
98
static UINT psiIpcCommand; // = RegisterWindowMessage()
99
static WPARAM raiseCommand; // = 1
102
static const int stringListMessage = 1;
104
bool sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const;
105
bool winEvent(MSG *msg, long *result);
107
bool sendStringList(const QString &to, const QStringList &list) const;
110
UINT ActiveProfiles::Private::psiIpcCommand = 0;
111
WPARAM ActiveProfiles::Private::raiseCommand = 1;
113
bool ActiveProfiles::Private::sendMessage(const QString &to, UINT message, WPARAM wParam, LPARAM lParam) const
117
hwnd = FindWindowW(0, (LPCWSTR)windowName(to).utf16());
119
QByteArray a = windowName(to).toLocal8Bit();
120
hwnd = FindWindowA(0, (LPCSTR)a.constData());
126
SendMessageA(hwnd, message, wParam, lParam);
130
bool ActiveProfiles::Private::sendStringList(const QString &to, const QStringList &list) const
137
ba.append(list[0].toUtf8());
138
for (int i = 1; i < list.size(); ++i) {
139
const int z = ba.size();
140
ba.append(" " + list[i].toUtf8());
145
cd.dwData = stringListMessage;
146
cd.cbData = ba.size()+1;
147
cd.lpData = (void*)ba.data();
149
return sendMessage(to, WM_COPYDATA, (WPARAM)winId(), (LPARAM)(LPVOID)&cd);
152
bool ActiveProfiles::Private::winEvent(MSG *msg, long *result)
154
*result = 1; // by default - not ok
156
if (msg->message == WM_COPYDATA) {
157
COPYDATASTRUCT *cd = (COPYDATASTRUCT *)msg->lParam;
158
if (cd->dwData == stringListMessage) {
159
char *data = (char*)cd->lpData;
160
const char *end = data + cd->cbData - 1;
162
// handle this error here, not to worry later
170
QString s = QString::fromUtf8(data);
172
data += strlen(data) + 1;
175
if (list[0] == "openUri") {
176
emit ap->openUri(list[1]);
182
else if (msg->message == psiIpcCommand) {
183
if (msg->wParam == raiseCommand) {
184
emit ap->raiseMainWindow();
193
ActiveProfiles::ActiveProfiles()
194
: QObject(QCoreApplication::instance())
196
d = new ActiveProfiles::Private(this);
199
ActiveProfiles::~ActiveProfiles()
205
bool ActiveProfiles::setThisProfile(const QString &profile)
207
if (profile == d->profile)
210
if (profile.isEmpty()) {
218
m = CreateMutexW(0, TRUE, (LPCWSTR)d->mutexName(profile).utf16());
220
QByteArray a = d->mutexName(profile).toLocal8Bit();
221
m = CreateMutexA(0, TRUE, (LPCSTR)a.constData());
224
if (GetLastError() == ERROR_ALREADY_EXISTS) {
231
CloseHandle(d->mutex);
234
d->profile = profile;
235
d->setWindowText(d->windowName(profile));
241
void ActiveProfiles::unsetThisProfile()
244
CloseHandle(d->mutex);
246
d->profile = QString::null;
247
d->setWindowText("");
251
QString ActiveProfiles::thisProfile() const
256
bool ActiveProfiles::isActive(const QString &profile) const
260
m = OpenMutexW(0, FALSE, (LPCWSTR)d->mutexName(profile).utf16());
262
QByteArray a = d->mutexName(profile).toLocal8Bit();
263
m = OpenMutexA(0, FALSE, (LPCSTR)a.constData());
265
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
274
bool ActiveProfiles::raiseOther(QString profile, bool withUI) const
278
lab = new QLabel(tr("This psi profile is already running...<br>please wait..."));
279
QTimer::singleShot(250, lab, SLOT(show()));
282
bool res = d->sendMessage(profile, d->psiIpcCommand, d->raiseCommand, 0);
292
bool ActiveProfiles::sendOpenUri(const QString &uri, const QString &profile) const
295
list << "openUri" << uri;
296
return d->sendStringList(isActive(profile)? profile : pickProfile(), list);