summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Knight <andrew.knight@digia.com>2014-03-16 12:16:50 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-03-18 08:21:53 +0100
commita796e09922c53824aa9a503688710eaa8d0bfa05 (patch)
tree907844e6a8c6a4a62d94db562bd46b74ba7699dd
parent782b827306ea735803f7b31ff996b1ca316b896b (diff)
downloadqttools-a796e09922c53824aa9a503688710eaa8d0bfa05.tar.gz
winrtrunner: Relay debug messages from local apps
When local (Appx) app runs with -qdevel, it writes all debug messages to shared memory. This change allows winrtrunner to retrieve and relay this output to the user. All debug messages are printed with the logging category "qt.winrtrunner.app" to differientate them from winrtrunner's own output. Change-Id: I5a42d33680b75c00624147152a09a4ed9031e33c Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
-rw-r--r--src/winrtrunner/appxengine.cpp154
-rw-r--r--src/winrtrunner/main.cpp3
-rw-r--r--src/winrtrunner/runner.cpp1
-rw-r--r--src/winrtrunner/runner.h1
4 files changed, 157 insertions, 2 deletions
diff --git a/src/winrtrunner/appxengine.cpp b/src/winrtrunner/appxengine.cpp
index e832195a1..32f84714b 100644
--- a/src/winrtrunner/appxengine.cpp
+++ b/src/winrtrunner/appxengine.cpp
@@ -85,6 +85,155 @@ static BOOL WINAPI ctrlHandler(DWORD type)
return false;
}
+QString sidForPackage(const QString &packageFamilyName)
+{
+ QString sid;
+ HKEY regKey;
+ LONG result = RegOpenKeyEx(
+ HKEY_CLASSES_ROOT,
+ L"Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Mappings",
+ 0, KEY_READ, &regKey);
+ if (result != ERROR_SUCCESS) {
+ qCWarning(lcWinRtRunner) << "Unable to open registry key:" << qt_error_string(result);
+ return sid;
+ }
+
+ DWORD index = 0;
+ wchar_t subKey[MAX_PATH];
+ forever {
+ result = RegEnumKey(regKey, index++, subKey, MAX_PATH);
+ if (result != ERROR_SUCCESS)
+ break;
+ wchar_t moniker[MAX_PATH];
+ DWORD monikerSize = MAX_PATH;
+ result = RegGetValue(regKey, subKey, L"Moniker", RRF_RT_REG_SZ, NULL, moniker, &monikerSize);
+ if (result != ERROR_SUCCESS)
+ continue;
+ if (lstrcmp(moniker, reinterpret_cast<LPCWSTR>(packageFamilyName.utf16())) == 0) {
+ sid = QString::fromWCharArray(subKey);
+ break;
+ }
+ }
+ RegCloseKey(regKey);
+ return sid;
+}
+
+class OutputDebugMonitor
+{
+public:
+ OutputDebugMonitor()
+ : runLock(CreateEvent(NULL, FALSE, FALSE, NULL)), thread(0)
+ {
+ }
+ ~OutputDebugMonitor()
+ {
+ if (runLock) {
+ SetEvent(runLock);
+ CloseHandle(runLock);
+ }
+ if (thread) {
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+ }
+ }
+ void start(const QString &packageFamilyName)
+ {
+ if (thread) {
+ qCWarning(lcWinRtRunner) << "OutputDebugMonitor is already running.";
+ return;
+ }
+
+ package = packageFamilyName;
+
+ thread = CreateThread(NULL, 0, &monitor, this, NULL, NULL);
+ if (!thread) {
+ qCWarning(lcWinRtRunner) << "Unable to create thread for app debugging:"
+ << qt_error_string(GetLastError());
+ return;
+ }
+
+ return;
+ }
+private:
+ static DWORD __stdcall monitor(LPVOID param)
+ {
+ OutputDebugMonitor *that = static_cast<OutputDebugMonitor *>(param);
+
+ const QString handleBase = QStringLiteral("Local\\AppContainerNamedObjects\\")
+ + sidForPackage(that->package);
+ const QString eventName = handleBase + QStringLiteral("\\qdebug-event");
+ const QString shmemName = handleBase + QStringLiteral("\\qdebug-shmem");
+
+ HANDLE event = CreateEvent(NULL, FALSE, FALSE, reinterpret_cast<LPCWSTR>(eventName.utf16()));
+ if (!event) {
+ qCWarning(lcWinRtRunner) << "Unable to open shared event for app debugging:"
+ << qt_error_string(GetLastError());
+ return 1;
+ }
+
+ HANDLE shmem = 0;
+ DWORD ret = 0;
+ forever {
+ HANDLE handles[] = { that->runLock, event };
+ DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+
+ // runLock set; exit thread
+ if (result == WAIT_OBJECT_0)
+ break;
+
+ // debug event set; print message
+ if (result == WAIT_OBJECT_0 + 1) {
+ if (!shmem) {
+ shmem = OpenFileMapping(GENERIC_READ, FALSE,
+ reinterpret_cast<LPCWSTR>(shmemName.utf16()));
+ if (!shmem) {
+ qCWarning(lcWinRtRunner) << "Unable to open shared memory for app debugging:"
+ << qt_error_string(GetLastError());
+ ret = 1;
+ break;
+ }
+ }
+
+ const quint32 *data = reinterpret_cast<const quint32 *>(
+ MapViewOfFile(shmem, FILE_MAP_READ, 0, 0, 4096));
+ QtMsgType messageType = static_cast<QtMsgType>(data[0]);
+ QString message = QString::fromWCharArray(
+ reinterpret_cast<const wchar_t *>(data + 1));
+ UnmapViewOfFile(data);
+ switch (messageType) {
+ default:
+ case QtDebugMsg:
+ qCDebug(lcWinRtRunnerApp, qPrintable(message));
+ break;
+ case QtWarningMsg:
+ qCWarning(lcWinRtRunnerApp, qPrintable(message));
+ break;
+ case QtCriticalMsg:
+ case QtFatalMsg:
+ qCCritical(lcWinRtRunnerApp, qPrintable(message));
+ break;
+ }
+ continue;
+ }
+
+ // An error occurred; exit thread
+ qCWarning(lcWinRtRunner) << "Debug output monitor error:"
+ << qt_error_string(GetLastError());
+ ret = 1;
+ break;
+ }
+ if (shmem)
+ CloseHandle(shmem);
+ if (event)
+ CloseHandle(event);
+ return ret;
+ }
+ HANDLE runLock;
+ HANDLE thread;
+ QString package;
+};
+Q_GLOBAL_STATIC(OutputDebugMonitor, debugMonitor)
+
class AppxEnginePrivate
{
public:
@@ -517,7 +666,8 @@ bool AppxEngine::start()
Q_D(AppxEngine);
qCDebug(lcWinRtRunner) << __FUNCTION__;
- const QString launchArguments = d->runner->arguments().join(QLatin1Char(' '));
+ const QString launchArguments =
+ (d->runner->arguments() << QStringLiteral("-qdevel")).join(QLatin1Char(' '));
DWORD pid;
const QString activationId = d->packageFamilyName + QStringLiteral("!App");
HRESULT hr = d->appLauncher->ActivateApplication(wchar(activationId),
@@ -556,6 +706,8 @@ bool AppxEngine::waitForFinished(int secs)
Q_D(AppxEngine);
qCDebug(lcWinRtRunner) << __FUNCTION__;
+ debugMonitor->start(d->packageFamilyName);
+
g_handleCtrl = true;
int time = 0;
forever {
diff --git a/src/winrtrunner/main.cpp b/src/winrtrunner/main.cpp
index 56179a492..9311a4725 100644
--- a/src/winrtrunner/main.cpp
+++ b/src/winrtrunner/main.cpp
@@ -137,7 +137,8 @@ int main(int argc, char *argv[])
QStringList filterRules = QStringList() // Default logging rules
<< QStringLiteral("qt.winrtrunner.warning=true")
- << QStringLiteral("qt.winrtrunner.critical=true");
+ << QStringLiteral("qt.winrtrunner.critical=true")
+ << QStringLiteral("qt.winrtrunner.app=true");
if (parser.isSet(verbosityOption)) {
bool ok;
uint verbosity = parser.value(verbosityOption).toUInt(&ok);
diff --git a/src/winrtrunner/runner.cpp b/src/winrtrunner/runner.cpp
index 6796ea570..4e5ba43dd 100644
--- a/src/winrtrunner/runner.cpp
+++ b/src/winrtrunner/runner.cpp
@@ -57,6 +57,7 @@
QT_USE_NAMESPACE
Q_LOGGING_CATEGORY(lcWinRtRunner, "qt.winrtrunner")
+Q_LOGGING_CATEGORY(lcWinRtRunnerApp, "qt.winrtrunner.app")
class RunnerPrivate
{
diff --git a/src/winrtrunner/runner.h b/src/winrtrunner/runner.h
index 4561550a1..b5f108e47 100644
--- a/src/winrtrunner/runner.h
+++ b/src/winrtrunner/runner.h
@@ -82,5 +82,6 @@ private:
};
Q_DECLARE_LOGGING_CATEGORY(lcWinRtRunner)
+Q_DECLARE_LOGGING_CATEGORY(lcWinRtRunnerApp)
#endif // RUNNER_H