summaryrefslogtreecommitdiffstats
path: root/src/winrtrunner/appxengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/winrtrunner/appxengine.cpp')
-rw-r--r--src/winrtrunner/appxengine.cpp680
1 files changed, 35 insertions, 645 deletions
diff --git a/src/winrtrunner/appxengine.cpp b/src/winrtrunner/appxengine.cpp
index 039fa4fe2..b79668bdb 100644
--- a/src/winrtrunner/appxengine.cpp
+++ b/src/winrtrunner/appxengine.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "appxengine.h"
+#include "appxengine_p.h"
#include <QtCore/QDateTime>
#include <QtCore/QDir>
@@ -66,280 +67,7 @@ using namespace ABI::Windows::System;
QT_USE_NAMESPACE
-#define wchar(str) reinterpret_cast<LPCWSTR>(str.utf16())
-#define hStringFromQString(str) HStringReference(reinterpret_cast<const wchar_t *>(str.utf16())).Get()
-#define QStringFromHString(hstr) QString::fromWCharArray(WindowsGetStringRawBuffer(hstr, Q_NULLPTR))
-
-// Set a break handler for gracefully breaking long-running ops
-static bool g_ctrlReceived = false;
-static bool g_handleCtrl = false;
-static BOOL WINAPI ctrlHandler(DWORD type)
-{
- switch (type) {
- case CTRL_C_EVENT:
- case CTRL_CLOSE_EVENT:
- case CTRL_LOGOFF_EVENT:
- g_ctrlReceived = g_handleCtrl;
- return g_handleCtrl;
- case CTRL_BREAK_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- default:
- break;
- }
- 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:
- Runner *runner;
- bool hasFatalError;
-
- QString manifest;
- QString packageFullName;
- QString packageFamilyName;
- ProcessorArchitecture packageArchitecture;
- QString executable;
- qint64 pid;
- HANDLE processHandle;
- DWORD exitCode;
- QSet<QString> dependencies;
- QSet<QString> installedPackages;
-
- ComPtr<IPackageManager> packageManager;
- ComPtr<IUriRuntimeClassFactory> uriFactory;
- ComPtr<IApplicationActivationManager> appLauncher;
- ComPtr<IAppxFactory> packageFactory;
- ComPtr<IPackageDebugSettings> packageDebug;
-
- void retrieveInstalledPackages();
-};
-
-class XmlStream : public RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>, IStream>
-{
-public:
- XmlStream(const QString &fileName)
- : m_manifest(fileName)
- {
- m_manifest.open(QFile::ReadOnly);
- }
-
- ~XmlStream()
- {
- }
-
- HRESULT __stdcall Read(void *data, ULONG count, ULONG *bytesRead)
- {
- *bytesRead = m_manifest.read(reinterpret_cast<char *>(data), count);
- return S_OK;
- }
-
- HRESULT __stdcall Seek(LARGE_INTEGER pos, DWORD start, ULARGE_INTEGER *newPos)
- {
- switch (start) {
- default:
- case STREAM_SEEK_SET:
- /* pos.QuadPart += 0; */
- break;
- case STREAM_SEEK_CUR:
- pos.QuadPart += m_manifest.pos();
- break;
- case STREAM_SEEK_END:
- pos.QuadPart += m_manifest.size();
- break;
- }
- if (!m_manifest.seek(pos.QuadPart))
- return STG_E_INVALIDPOINTER;
- if (newPos) {
- ULARGE_INTEGER newPosInt = { m_manifest.pos() };
- *newPos = newPosInt;
- }
- return S_OK;
- }
-
- HRESULT __stdcall Stat(STATSTG *stats, DWORD flags)
- {
- QFileInfo info(m_manifest);
- // ms to 100-ns units
- ULARGE_INTEGER lastModifiedInt = { info.lastModified().toMSecsSinceEpoch() * 10000 };
- ULARGE_INTEGER createdInt = { info.created().toMSecsSinceEpoch() * 10000 };
- ULARGE_INTEGER lastReadInt = { info.lastRead().toMSecsSinceEpoch() * 10000 };
- STATSTG newStats = {
- flags == STATFLAG_NONAME ? NULL : reinterpret_cast<LPWSTR>(m_manifest.fileName().data()),
- STGTY_STREAM, { m_manifest.size() },
- { lastModifiedInt.u.LowPart, lastModifiedInt.u.HighPart },
- { createdInt.u.LowPart, createdInt.u.HighPart },
- { lastReadInt.u.LowPart, lastReadInt.u.HighPart },
- 0, 0, CLSID_NULL, 0, 0
- };
- *stats = newStats;
- return S_OK;
- }
-
- // Unimplemented methods
- HRESULT __stdcall Write(const void *, ULONG, ULONG *) { return E_NOTIMPL; }
- HRESULT __stdcall SetSize(ULARGE_INTEGER) { return E_NOTIMPL; }
- HRESULT __stdcall CopyTo(IStream *, ULARGE_INTEGER, ULARGE_INTEGER *, ULARGE_INTEGER *) { return E_NOTIMPL; }
- HRESULT __stdcall Commit(DWORD) { return E_NOTIMPL; }
- HRESULT __stdcall Revert() { return E_NOTIMPL; }
- HRESULT __stdcall LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) { return E_NOTIMPL; }
- HRESULT __stdcall UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) { return E_NOTIMPL; }
- HRESULT __stdcall Clone(IStream **) { return E_NOTIMPL; }
-
-private:
- QFile m_manifest;
-};
-
-static bool getManifestFile(const QString &fileName, QString *manifest = 0)
+bool AppxEngine::getManifestFile(const QString &fileName, QString *manifest)
{
if (!QFile::exists(fileName)) {
qCWarning(lcWinRtRunner) << fileName << "does not exist.";
@@ -374,27 +102,6 @@ static bool getManifestFile(const QString &fileName, QString *manifest = 0)
return false;
}
-bool AppxEngine::canHandle(Runner *runner)
-{
- return getManifestFile(runner->app());
-}
-
-RunnerEngine *AppxEngine::create(Runner *runner)
-{
- AppxEngine *engine = new AppxEngine(runner);
- if (engine->d_ptr->hasFatalError) {
- delete engine;
- return 0;
- }
- return engine;
-}
-
-QStringList AppxEngine::deviceNames()
-{
- qCDebug(lcWinRtRunner) << __FUNCTION__;
- return QStringList(QStringLiteral("local"));
-}
-
#define CHECK_RESULT(errorMessage, action)\
do {\
if (FAILED(hr)) {\
@@ -424,7 +131,8 @@ static ProcessorArchitecture toProcessorArchitecture(APPX_PACKAGE_ARCHITECTURE a
}
}
-AppxEngine::AppxEngine(Runner *runner) : d_ptr(new AppxEnginePrivate)
+AppxEngine::AppxEngine(Runner *runner, AppxEnginePrivate *dd)
+ : d_ptr(dd)
{
Q_D(AppxEngine);
d->runner = runner;
@@ -442,27 +150,18 @@ AppxEngine::AppxEngine(Runner *runner) : d_ptr(new AppxEnginePrivate)
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
CHECK_RESULT_FATAL("Failed to initialize COM.", return);
- hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Management_Deployment_PackageManager).Get(),
- &d->packageManager);
- CHECK_RESULT_FATAL("Failed to instantiate package manager.", return);
-
hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_Uri).Get(),
IID_PPV_ARGS(&d->uriFactory));
CHECK_RESULT_FATAL("Failed to instantiate URI factory.", return);
- hr = CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC_SERVER,
- IID_IApplicationActivationManager, &d->appLauncher);
- CHECK_RESULT_FATAL("Failed to instantiate application activation manager.", return);
-
- hr = CoCreateInstance(CLSID_PackageDebugSettings, nullptr, CLSCTX_INPROC_SERVER,
- IID_IPackageDebugSettings, &d->packageDebug);
- CHECK_RESULT_FATAL("Failed to instantiate package debug settings.", return);
-
hr = CoCreateInstance(CLSID_AppxFactory, nullptr, CLSCTX_INPROC_SERVER,
IID_IAppxFactory, &d->packageFactory);
CHECK_RESULT_FATAL("Failed to instantiate package factory.", return);
- ComPtr<IStream> manifestStream = Make<XmlStream>(d->manifest);
+ ComPtr<IStream> manifestStream;
+ hr = SHCreateStreamOnFile(wchar(d->manifest), STGM_READ, &manifestStream);
+ CHECK_RESULT_FATAL("Failed to open manifest stream.", return);
+
ComPtr<IAppxManifestReader> manifestReader;
hr = d->packageFactory->CreateManifestReader(manifestStream.Get(), &manifestReader);
if (FAILED(hr)) {
@@ -520,8 +219,6 @@ AppxEngine::AppxEngine(Runner *runner) : d_ptr(new AppxEnginePrivate)
.absoluteFilePath(QString::fromWCharArray(executable));
CoTaskMemFree(executable);
- d->retrieveInstalledPackages();
-
ComPtr<IAppxManifestPackageDependenciesEnumerator> dependencies;
hr = manifestReader->GetPackageDependencies(&dependencies);
CHECK_RESULT_FATAL("Failed to retrieve the package dependencies from the manifest.", return);
@@ -540,9 +237,6 @@ AppxEngine::AppxEngine(Runner *runner) : d_ptr(new AppxEnginePrivate)
CoTaskMemFree(name);
hr = dependencies->MoveNext(&hasCurrent);
}
-
- // Set a break handler for gracefully exiting from long-running operations
- SetConsoleCtrlHandler(&ctrlHandler, true);
}
AppxEngine::~AppxEngine()
@@ -551,6 +245,30 @@ AppxEngine::~AppxEngine()
CloseHandle(d->processHandle);
}
+qint64 AppxEngine::pid() const
+{
+ Q_D(const AppxEngine);
+ qCDebug(lcWinRtRunner) << __FUNCTION__;
+
+ return d->pid;
+}
+
+int AppxEngine::exitCode() const
+{
+ Q_D(const AppxEngine);
+ qCDebug(lcWinRtRunner) << __FUNCTION__;
+
+ return d->exitCode == UINT_MAX ? -1 : HRESULT_CODE(d->exitCode);
+}
+
+QString AppxEngine::executable() const
+{
+ Q_D(const AppxEngine);
+ qCDebug(lcWinRtRunner) << __FUNCTION__;
+
+ return d->executable;
+}
+
bool AppxEngine::installDependencies()
{
Q_D(AppxEngine);
@@ -558,8 +276,6 @@ bool AppxEngine::installDependencies()
QSet<QString> toInstall;
foreach (const QString &dependencyName, d->dependencies) {
- if (d->installedPackages.contains(dependencyName))
- continue;
toInstall.insert(dependencyName);
qCDebug(lcWinRtRunner).nospace()
<< "dependency to be installed: " << dependencyName;
@@ -568,13 +284,7 @@ bool AppxEngine::installDependencies()
if (toInstall.isEmpty())
return true;
- const QByteArray extensionSdkDirRaw = qgetenv("ExtensionSdkDir");
- if (extensionSdkDirRaw.isEmpty()) {
- qCWarning(lcWinRtRunner).nospace()
- << QStringLiteral("The environment variable ExtensionSdkDir is not set.");
- return false;
- }
- const QString extensionSdkDir = QString::fromLocal8Bit(extensionSdkDirRaw);
+ const QString extensionSdkDir = extensionSdkPath();
if (!QFile::exists(extensionSdkDir)) {
qCWarning(lcWinRtRunner).nospace()
<< QString(QStringLiteral("The directory '%1' does not exist.")).arg(
@@ -625,331 +335,11 @@ bool AppxEngine::installDependencies()
qCDebug(lcWinRtRunner).nospace()
<< "installing dependency " << name << " from " << dit.filePath();
- if (installPackage(dit.filePath()))
- toInstall.remove(name);
- }
-
- return true;
-}
-
-bool AppxEngine::installPackage(const QString &filePath)
-{
- Q_D(const AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__ << filePath;
-
- const QString nativeFilePath = QDir::toNativeSeparators(QFileInfo(filePath).absoluteFilePath());
- const bool addInsteadOfRegister = nativeFilePath.endsWith(QStringLiteral(".appx"),
- Qt::CaseInsensitive);
- HRESULT hr;
- ComPtr<IUriRuntimeClass> uri;
- hr = d->uriFactory->CreateUri(hStringFromQString(nativeFilePath), &uri);
- CHECK_RESULT("Unable to create an URI for the package.", return false);
-
- ComPtr<IAsyncOperationWithProgress<DeploymentResult *, DeploymentProgress>> deploymentOperation;
- if (addInsteadOfRegister) {
- hr = d->packageManager->AddPackageAsync(uri.Get(), NULL, DeploymentOptions_None,
- &deploymentOperation);
- CHECK_RESULT("Unable to add package.", return false);
- } else {
- hr = d->packageManager->RegisterPackageAsync(uri.Get(), 0,
- DeploymentOptions_DevelopmentMode,
- &deploymentOperation);
- CHECK_RESULT("Unable to start package registration.", return false);
- }
-
- ComPtr<IDeploymentResult> results;
- while ((hr = deploymentOperation->GetResults(&results)) == E_ILLEGAL_METHOD_CALL)
- Sleep(1);
-
- HRESULT errorCode;
- hr = results->get_ExtendedErrorCode(&errorCode);
- CHECK_RESULT("Unable to retrieve package registration results.", return false);
-
- if (FAILED(errorCode)) {
- HString errorText;
- if (SUCCEEDED(results->get_ErrorText(errorText.GetAddressOf()))) {
- qCWarning(lcWinRtRunner) << "Unable to register package:"
- << QString::fromWCharArray(errorText.GetRawBuffer(NULL));
- }
- if (HRESULT_CODE(errorCode) == ERROR_INSTALL_POLICY_FAILURE) {
- // The user's license has expired. Give them the opportunity to renew it.
- FILETIME expiration;
- hr = AcquireDeveloperLicense(GetForegroundWindow(), &expiration);
- if (FAILED(hr)) {
- qCWarning(lcWinRtRunner) << "Unable to renew developer license:"
- << qt_error_string(hr);
- }
- if (SUCCEEDED(hr))
- return install(false);
- }
- return false;
- }
-
- return SUCCEEDED(hr);
-}
-
-bool AppxEngine::install(bool removeFirst)
-{
- Q_D(const AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- ComPtr<IPackage> packageInformation;
- HRESULT hr = d->packageManager->FindPackageByUserSecurityIdPackageFullName(
- NULL, hStringFromQString(d->packageFullName), &packageInformation);
- if (SUCCEEDED(hr) && packageInformation) {
- qCWarning(lcWinRtRunner) << "Package already installed.";
- if (removeFirst)
- remove();
- else
- return true;
- }
-
- return installDependencies() && installPackage(d->manifest);
-}
-
-bool AppxEngine::remove()
-{
- Q_D(const AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- ComPtr<IAsyncOperationWithProgress<DeploymentResult *, DeploymentProgress>> deploymentOperation;
- HRESULT hr = d->packageManager->RemovePackageAsync(hStringFromQString(d->packageFullName), &deploymentOperation);
- if (FAILED(hr)) {
- qCWarning(lcWinRtRunner) << "Unable to start package removal:" << QDir::toNativeSeparators(d->manifest);
- return false;
- }
-
- ComPtr<IDeploymentResult> results;
- while ((hr = deploymentOperation.Get()->GetResults(&results)) == E_ILLEGAL_METHOD_CALL)
- Sleep(1);
-
- if (FAILED(hr)) {
- qCWarning(lcWinRtRunner) << "Unable to remove package:" << QDir::toNativeSeparators(d->manifest);
- return false;
- }
-
- return SUCCEEDED(hr);
-}
-
-bool AppxEngine::start()
-{
- Q_D(AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- 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),
- wchar(launchArguments), AO_NONE, &pid);
- CHECK_RESULT("Failed to activate application.", return false);
- d->pid = qint64(pid);
- CloseHandle(d->processHandle);
- d->processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, pid);
-
- return true;
-}
-
-bool AppxEngine::enableDebugging(const QString &debuggerExecutable, const QString &debuggerArguments)
-{
- Q_D(AppxEngine);
-
- const QString &debuggerCommand = debuggerExecutable + QLatin1Char(' ') + debuggerArguments;
- HRESULT hr = d->packageDebug->EnableDebugging(wchar(d->packageFullName),
- wchar(debuggerCommand),
- NULL);
- CHECK_RESULT("Failed to enable debugging for application.", return false);
- return true;
-}
-
-bool AppxEngine::disableDebugging()
-{
- Q_D(AppxEngine);
-
- HRESULT hr = d->packageDebug->DisableDebugging(wchar(d->packageFullName));
- CHECK_RESULT("Failed to disable debugging for application.", return false);
-
- return true;
-}
-
-bool AppxEngine::suspend()
-{
- Q_D(AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- HRESULT hr = d->packageDebug->Suspend(wchar(d->packageFullName));
- CHECK_RESULT("Failed to suspend application.", return false);
-
- return true;
-}
-
-bool AppxEngine::waitForFinished(int secs)
-{
- Q_D(AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- debugMonitor->start(d->packageFamilyName);
-
- g_handleCtrl = true;
- int time = 0;
- forever {
- PACKAGE_EXECUTION_STATE state;
- HRESULT hr = d->packageDebug->GetPackageExecutionState(wchar(d->packageFullName), &state);
- CHECK_RESULT("Failed to get package execution state.", return false);
- qCDebug(lcWinRtRunner) << "Current execution state:" << state;
- if (state == PES_TERMINATED || state == PES_UNKNOWN)
- break;
-
- ++time;
- if ((secs && time > secs) || g_ctrlReceived) {
- g_handleCtrl = false;
+ if (!installPackage(manifestReader.Get(), dit.filePath())) {
+ qCWarning(lcWinRtRunner) << "Failed to install package:" << name;
return false;
}
-
- Sleep(1000); // Wait one second between checks
- qCDebug(lcWinRtRunner) << "Waiting for app to quit - msecs to go:" << secs - time;
}
- g_handleCtrl = false;
-
- if (!GetExitCodeProcess(d->processHandle, &d->exitCode))
- d->exitCode = UINT_MAX;
return true;
}
-
-bool AppxEngine::stop()
-{
- Q_D(AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- // ### We won't have a process handle if we didn't start the app. We can look it up
- // using a process snapshot, or by calling start if we know the process is already running.
- // For now, simply continue normally, but don't fetch the exit code.
- if (!d->processHandle)
- qCDebug(lcWinRtRunner) << "No handle to the process; the exit code won't be available.";
-
- if (d->processHandle && !GetExitCodeProcess(d->processHandle, &d->exitCode)) {
- d->exitCode = UINT_MAX;
- qCWarning(lcWinRtRunner).nospace() << "Failed to obtain process exit code.";
- qCDebug(lcWinRtRunner, "GetLastError: 0x%x", GetLastError());
- return false;
- }
-
- if (!d->processHandle || d->exitCode == STILL_ACTIVE) {
- HRESULT hr = d->packageDebug->TerminateAllProcesses(wchar(d->packageFullName));
- CHECK_RESULT("Failed to terminate package process.", return false);
-
- if (d->processHandle && !GetExitCodeProcess(d->processHandle, &d->exitCode))
- d->exitCode = UINT_MAX;
- }
-
- return true;
-}
-
-qint64 AppxEngine::pid() const
-{
- Q_D(const AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- return d->pid;
-}
-
-int AppxEngine::exitCode() const
-{
- Q_D(const AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- return d->exitCode == UINT_MAX ? -1 : HRESULT_CODE(d->exitCode);
-}
-
-QString AppxEngine::executable() const
-{
- Q_D(const AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- return d->executable;
-}
-
-QString AppxEngine::devicePath(const QString &relativePath) const
-{
- Q_D(const AppxEngine);
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- // Return a path safe for passing to the application
- QDir localAppDataPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
- const QString path = localAppDataPath.absoluteFilePath(
- QStringLiteral("Packages/") + d->packageFamilyName
- + QStringLiteral("/LocalState/") + relativePath);
- return QDir::toNativeSeparators(path);
-}
-
-bool AppxEngine::sendFile(const QString &localFile, const QString &deviceFile)
-{
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- // Both files are local, just use QFile
- QFile source(localFile);
-
- // Remove the destination, or copy will fail
- if (QFileInfo(source) != QFileInfo(deviceFile))
- QFile::remove(deviceFile);
-
- bool result = source.copy(deviceFile);
- if (!result)
- qCWarning(lcWinRtRunner) << "Unable to sendFile:" << source.errorString();
-
- return result;
-}
-
-bool AppxEngine::receiveFile(const QString &deviceFile, const QString &localFile)
-{
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- // Both files are local, so just reverse the sendFile arguments
- return sendFile(deviceFile, localFile);
-}
-
-void AppxEnginePrivate::retrieveInstalledPackages()
-{
- qCDebug(lcWinRtRunner) << __FUNCTION__;
-
- ComPtr<ABI::Windows::Foundation::Collections::IIterable<Package*>> packages;
- HRESULT hr = packageManager->FindPackagesByUserSecurityId(NULL, &packages);
- CHECK_RESULT("Failed to find packages.", return);
-
- ComPtr<ABI::Windows::Foundation::Collections::IIterator<Package*>> pkgit;
- hr = packages->First(&pkgit);
- CHECK_RESULT("Failed to get package iterator.", return);
-
- boolean hasCurrent;
- hr = pkgit->get_HasCurrent(&hasCurrent);
- while (SUCCEEDED(hr) && hasCurrent) {
- ComPtr<IPackage> pkg;
- hr = pkgit->get_Current(&pkg);
- CHECK_RESULT("Failed to get current package.", return);
-
- ComPtr<IPackageId> pkgId;
- hr = pkg->get_Id(&pkgId);
- CHECK_RESULT("Failed to get package id.", return);
-
- HString name;
- hr = pkgId->get_Name(name.GetAddressOf());
- CHECK_RESULT("Failed retrieve package name.", return);
-
- ProcessorArchitecture architecture;
- if (packageArchitecture == ProcessorArchitecture_Neutral) {
- architecture = packageArchitecture;
- } else {
- hr = pkgId->get_Architecture(&architecture);
- CHECK_RESULT("Failed to retrieve package architecture.", return);
- }
-
- const QString pkgName = QStringFromHString(name.Get());
- qCDebug(lcWinRtRunner) << "found installed package" << pkgName;
-
- if (architecture == packageArchitecture)
- installedPackages.insert(pkgName);
-
- hr = pkgit->MoveNext(&hasCurrent);
- }
-}