diff options
-rw-r--r-- | .prev_configure.cmake | 123 | ||||
-rw-r--r-- | configure.cmake | 8 | ||||
-rw-r--r-- | configure.json | 11 | ||||
-rw-r--r-- | src/.prev_CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/shared/winutils/utils.h | 3 | ||||
-rw-r--r-- | src/src.pro | 6 | ||||
-rw-r--r-- | src/windeployqt/main.cpp | 44 | ||||
-rw-r--r-- | src/winrtrunner/CMakeLists.txt | 45 | ||||
-rw-r--r-- | src/winrtrunner/appxengine.cpp | 801 | ||||
-rw-r--r-- | src/winrtrunner/appxengine.h | 76 | ||||
-rw-r--r-- | src/winrtrunner/appxengine_p.h | 111 | ||||
-rw-r--r-- | src/winrtrunner/appxlocalengine.cpp | 884 | ||||
-rw-r--r-- | src/winrtrunner/appxlocalengine.h | 88 | ||||
-rw-r--r-- | src/winrtrunner/appxphoneengine.cpp | 565 | ||||
-rw-r--r-- | src/winrtrunner/appxphoneengine.h | 89 | ||||
-rw-r--r-- | src/winrtrunner/main.cpp | 372 | ||||
-rw-r--r-- | src/winrtrunner/runner.cpp | 384 | ||||
-rw-r--r-- | src/winrtrunner/runner.h | 90 | ||||
-rw-r--r-- | src/winrtrunner/runnerengine.h | 70 | ||||
-rw-r--r-- | src/winrtrunner/winrtrunner.pro | 31 | ||||
-rw-r--r-- | tests/auto/.prev_CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/auto/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/auto/auto.pro | 2 |
24 files changed, 136 insertions, 3681 deletions
diff --git a/.prev_configure.cmake b/.prev_configure.cmake new file mode 100644 index 000000000..97164e5f6 --- /dev/null +++ b/.prev_configure.cmake @@ -0,0 +1,123 @@ + + +#### Inputs + + + +#### Libraries + + + +#### Tests + +# libclang +qt_find_package(WrapLibClang PROVIDED_TARGETS WrapLibClang::WrapLibClang) + +if(TARGET WrapLibClang::WrapLibClang) + set(TEST_libclang "ON" CACHE BOOL "Required libclang version found." FORCE) +endif() + + + +#### Features + +qt_feature("assistant" PRIVATE + LABEL "Qt Assistant" + PURPOSE "Qt Assistant is a tool for viewing on-line documentation in Qt help file format." +) +qt_feature("clang" PRIVATE + LABEL "QDoc" + CONDITION TEST_libclang +) +qt_feature("clangcpp" PRIVATE + LABEL "Clang-based lupdate parser" + CONDITION QT_FEATURE_clang AND TEST_libclang +) +qt_feature("designer" PRIVATE + LABEL "Qt Designer" + PURPOSE "Qt Designer is the Qt tool for designing and building graphical user interfaces (GUIs) with Qt Widgets. You can compose and customize your windows or dialogs in a what-you-see-is-what-you-get (WYSIWYG) manner, and test them using different styles and resolutions." +) +qt_feature("distancefieldgenerator" PRIVATE + LABEL "Qt Distance Field Generator" + PURPOSE "The Qt Distance Field Generator tool can be used to pregenerate the font cache in order to optimize startup performance." +) +qt_feature("kmap2qmap" PRIVATE + LABEL "kmap2qmap" + PURPOSE "kmap2qmap is a tool to generate keymaps for use on Embedded Linux. The source files have to be in standard Linux kmap format that is e.g. understood by the kernel's loadkeys command." +) +qt_feature("linguist" PRIVATE + LABEL "Qt Linguist" + PURPOSE "Qt Linguist can be used by translator to translate text in Qt applications." +) +qt_feature("macdeployqt" PRIVATE + LABEL "Mac Deployment Tool" + PURPOSE "The Mac deployment tool automates the process of creating a deployable application bundle that contains the Qt libraries as private frameworks." + CONDITION APPLE +) +qt_feature("makeqpf" PRIVATE + LABEL "makeqpf" + PURPOSE "makeqpf is a tool to generate pre-rendered fonts in QPF2 format for use on Embedded Linux." +) +qt_feature("pixeltool" PRIVATE + LABEL "pixeltool" + PURPOSE "The Qt Pixel Zooming Tool is a graphical application that magnifies the screen around the mouse pointer so you can look more closely at individual pixels." +) +qt_feature("qdbus" PRIVATE + LABEL "qdbus" + PURPOSE "qdbus is a communication interface for Qt-based applications." +) +qt_feature("qev" PRIVATE + LABEL "qev" + PURPOSE "qev allows introspection of incoming events for a QWidget, similar to the X11 xev tool." +) +qt_feature("qtattributionsscanner" PRIVATE + LABEL "Qt Attributions Scanner" + PURPOSE "Qt Attributions Scanner generates attribution documents for third-party code in Qt." +) +qt_feature("qtdiag" PRIVATE + LABEL "qtdiag" + PURPOSE "qtdiag outputs information about the Qt installation it was built with." +) +qt_feature("qtpaths" PRIVATE + LABEL "qtpaths" + PURPOSE "qtpaths is a command line client to QStandardPaths." +) +qt_feature("qtplugininfo" PRIVATE + LABEL "qtplugininfo" + PURPOSE "qtplugininfo dumps metadata about Qt plugins in JSON format." +) +qt_feature("windeployqt" PRIVATE + LABEL "Windows deployment tool" + PURPOSE "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package." + CONDITION WIN32 +) +qt_configure_add_summary_section(NAME "Qt Tools") +qt_configure_add_summary_entry(ARGS "assistant") +qt_configure_add_summary_entry(ARGS "clang") +qt_configure_add_summary_entry(ARGS "clangcpp") +qt_configure_add_summary_entry(ARGS "designer") +qt_configure_add_summary_entry(ARGS "distancefieldgenerator") +qt_configure_add_summary_entry(ARGS "kmap2qmap") +qt_configure_add_summary_entry(ARGS "linguist") +qt_configure_add_summary_entry(ARGS "macdeployqt") +qt_configure_add_summary_entry(ARGS "makeqpf") +qt_configure_add_summary_entry(ARGS "pixeltool") +qt_configure_add_summary_entry(ARGS "qdbus") +qt_configure_add_summary_entry(ARGS "qev") +qt_configure_add_summary_entry(ARGS "qtattributionsscanner") +qt_configure_add_summary_entry(ARGS "qtdiag") +qt_configure_add_summary_entry(ARGS "qtpaths") +qt_configure_add_summary_entry(ARGS "qtplugininfo") +qt_configure_add_summary_entry(ARGS "windeployqt") +qt_configure_end_summary_section() # end of "Qt Tools" section +qt_configure_add_report_entry( + TYPE WARNING + MESSAGE "QDoc will not be compiled, probably because libclang could not be located. This means that you cannot build the Qt documentation. + Either ensure that llvm-config is in your PATH environment variable, or set LLVM_INSTALL_DIR to the location of your llvm installation. On Linux systems, you may be able to install libclang by installing the libclang-dev or libclang-devel package, depending on your distribution. On macOS, you can use Homebrew's llvm package. On Windows, you must set LLVM_INSTALL_DIR to the installation path." + CONDITION NOT QT_FEATURE_clang +) +qt_configure_add_report_entry( + TYPE WARNING + MESSAGE "Clang-based lupdate parser will not be available. LLVM and Clang C++ libraries have not been found." + CONDITION NOT QT_FEATURE_clangcpp +) diff --git a/configure.cmake b/configure.cmake index 7b48332f6..5f5d6bd60 100644 --- a/configure.cmake +++ b/configure.cmake @@ -95,12 +95,7 @@ qt_feature("qtplugininfo" PRIVATE qt_feature("windeployqt" PRIVATE LABEL "Windows deployment tool" PURPOSE "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package." - CONDITION WIN32 OR WINRT -) -qt_feature("winrtrunner" PRIVATE - LABEL "WinRT Runner Tool" - PURPOSE "The WinRT Runner Tool installs, runs, and collects test results for packages made with Qt." - CONDITION WINRT + CONDITION WIN32 ) qt_configure_add_summary_section(NAME "Qt Tools") qt_configure_add_summary_entry(ARGS "assistant") @@ -120,7 +115,6 @@ qt_configure_add_summary_entry(ARGS "qtdiag") qt_configure_add_summary_entry(ARGS "qtpaths") qt_configure_add_summary_entry(ARGS "qtplugininfo") qt_configure_add_summary_entry(ARGS "windeployqt") -qt_configure_add_summary_entry(ARGS "winrtrunner") qt_configure_end_summary_section() # end of "Qt Tools" section qt_configure_add_report_entry( TYPE WARNING diff --git a/configure.json b/configure.json index 2ff580062..3442f8cb5 100644 --- a/configure.json +++ b/configure.json @@ -111,13 +111,7 @@ "windeployqt": { "label": "Windows deployment tool", "purpose": "The Windows deployment tool is designed to automate the process of creating a deployable folder containing the Qt-related dependencies (libraries, QML imports, plugins, and translations) required to run the application from that folder. It creates a sandbox for Universal Windows Platform (UWP) or an installation tree for Windows desktop applications, which can be easily bundled into an installation package.", - "condition": "config.win32 || config.winrt", - "output": [ "privateFeature" ] - }, - "winrtrunner": { - "label": "WinRT Runner Tool", - "purpose": "The WinRT Runner Tool installs, runs, and collects test results for packages made with Qt.", - "condition": "config.winrt", + "condition": "config.win32", "output": [ "privateFeature" ] } }, @@ -157,8 +151,7 @@ On Windows, you must set LLVM_INSTALL_DIR to the installation path." "qtdiag", "qtpaths", "qtplugininfo", - "windeployqt", - "winrtrunner" + "windeployqt" ] } ] diff --git a/src/.prev_CMakeLists.txt b/src/.prev_CMakeLists.txt index 3f77c0bd9..1747a7d13 100644 --- a/src/.prev_CMakeLists.txt +++ b/src/.prev_CMakeLists.txt @@ -39,9 +39,6 @@ endif() if(WIN32) add_subdirectory(windeployqt) endif() -if(WINRT) - add_subdirectory(winrtrunner) -endif() -if(QT_FEATURE_commandlineparser AND TARGET Qt::Gui AND NOT ANDROID AND NOT QNX AND NOT UIKIT AND NOT WASM AND NOT WINRT) +if(QT_FEATURE_commandlineparser AND TARGET Qt::Gui AND NOT ANDROID AND NOT QNX AND NOT UIKIT AND NOT WASM) add_subdirectory(qtdiag) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3ac2dd38c..770f1cabc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,9 +54,6 @@ endif() if(WIN32) add_subdirectory(windeployqt) endif() -if(WINRT) - add_subdirectory(winrtrunner) -endif() -if(QT_FEATURE_commandlineparser AND TARGET Qt::Gui AND NOT ANDROID AND NOT QNX AND NOT UIKIT AND NOT WASM AND NOT WINRT) +if(QT_FEATURE_commandlineparser AND TARGET Qt::Gui AND NOT ANDROID AND NOT QNX AND NOT UIKIT AND NOT WASM) add_subdirectory(qtdiag) endif() diff --git a/src/shared/winutils/utils.h b/src/shared/winutils/utils.h index b15ca01cf..951ebf773 100644 --- a/src/shared/winutils/utils.h +++ b/src/shared/winutils/utils.h @@ -46,7 +46,6 @@ enum PlatformFlag { // OS WindowsBased = 0x00001, UnixBased = 0x00002, - WinRt = 0x00004, // CPU IntelBased = 0x00010, ArmBased = 0x00020, @@ -60,8 +59,6 @@ enum PlatformFlag { WindowsDesktopMinGW = WindowsBased + IntelBased + MinGW, WindowsDesktopClangMsvc = WindowsBased + IntelBased + ClangMsvc, WindowsDesktopClangMinGW = WindowsBased + IntelBased + ClangMinGW, - WinRtIntelMsvc = WindowsBased + WinRt + IntelBased + Msvc, - WinRtArmMsvc = WindowsBased + WinRt + ArmBased + Msvc, Unix = UnixBased, UnknownPlatform }; diff --git a/src/src.pro b/src/src.pro index 9ecfc82b4..8c75a8cd8 100644 --- a/src/src.pro +++ b/src/src.pro @@ -40,9 +40,8 @@ macos { qtHaveModule(dbus): SUBDIRS += qdbus -win32|winrt:SUBDIRS += windeployqt -winrt:SUBDIRS += winrtrunner -qtHaveModule(gui):qtConfig(commandlineparser):!wasm:!android:!uikit:!qnx:!winrt: SUBDIRS += qtdiag +win32:SUBDIRS += windeployqt +qtHaveModule(gui):qtConfig(commandlineparser):!wasm:!android:!uikit:!qnx: SUBDIRS += qtdiag qtNomakeTools( \ distancefieldgenerator \ @@ -54,6 +53,5 @@ qtNomakeTools( \ cross_compile:isEmpty(QMAKE_HOST_CXX.INCDIRS) { qdoc.depends += qtattributionsscanner windeployqt.depends += qtattributionsscanner - winrtrunner.depends += qtattributionsscanner linguist.depends += qtattributionsscanner } diff --git a/src/windeployqt/main.cpp b/src/windeployqt/main.cpp index 47395f628..cc6a3944a 100644 --- a/src/windeployqt/main.cpp +++ b/src/windeployqt/main.cpp @@ -212,10 +212,6 @@ static Platform platformFromMkSpec(const QString &xSpec) return WindowsDesktopClangMsvc; return xSpec.contains(QLatin1String("g++")) ? WindowsDesktopMinGW : WindowsDesktopMsvc; } - if (xSpec.startsWith(QLatin1String("winrt-x"))) - return WinRtIntelMsvc; - if (xSpec.startsWith(QLatin1String("winrt-arm"))) - return WinRtArmMsvc; return UnknownPlatform; } @@ -278,8 +274,6 @@ struct Options { bool dryRun = false; bool patchQt = true; bool ignoreLibraryErrors = false; - - inline bool isWinRt() const { return platform.testFlag(WinRt); } }; // Return binary from folder @@ -902,10 +896,6 @@ QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules, case WindowsDesktopMinGW: filter = QStringLiteral("qwindows"); break; - case WinRtIntelMsvc: - case WinRtArmMsvc: - filter = QStringLiteral("qwinrt"); - break; case Unix: filter = QStringLiteral("libqxcb"); break; @@ -1002,8 +992,7 @@ static bool deployTranslations(const QString &sourcePath, quint64 usedQtModules, arguments.append(QDir::toNativeSeparators(targetFilePath)); const QFileInfoList &langQmFiles = sourceDir.entryInfoList(translationNameFilters(usedQtModules, prefix)); for (const QFileInfo &langQmFileFi : langQmFiles) { - // winrt relies on a proper list of deployed files. We cannot cheat an mention files we do not ship here. - if (options.json && !options.isWinRt()) { + if (options.json) { options.json->addFile(langQmFileFi.absoluteFilePath(), absoluteTarget); } @@ -1418,7 +1407,7 @@ static DeployResult deploy(const Options &options, if (softwareRasterizer.isFile()) deployedQtLibraries.append(softwareRasterizer.absoluteFilePath()); } - if (options.systemD3dCompiler && !options.isWinRt() && machineArch != IMAGE_FILE_MACHINE_ARM64) { + if (options.systemD3dCompiler && machineArch != IMAGE_FILE_MACHINE_ARM64) { const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir, wordSize); if (d3dCompiler.isEmpty()) { std::wcerr << "Warning: Cannot find any version of the d3dcompiler DLL.\n"; @@ -1428,33 +1417,6 @@ static DeployResult deploy(const Options &options, } } // Windows - // We need to copy ucrtbased.dll on WinRT as this library is not part of - // the c runtime package. VS 2015 does the same when deploying to a device - // or creating an appx. - if (result.isDebug && options.platform == WinRtArmMsvc - && qmakeVariables.value(QStringLiteral("QMAKE_XSPEC")).endsWith(QLatin1String("msvc2015"))) { - const QString extensionPath = QString::fromLocal8Bit(qgetenv("ExtensionSdkDir")); - const QString ucrtVersion = QString::fromLocal8Bit(qgetenv("UCRTVersion")); - if (extensionPath.isEmpty() || ucrtVersion.isEmpty()) { - std::wcerr << "Warning: Cannot find ucrtbased.dll as either " - << "ExtensionSdkDir or UCRTVersion is not set in " - << "your environment.\n"; - } else { - const QString ucrtbasedLib = extensionPath - + QStringLiteral("/Microsoft.UniversalCRT.Debug/") - + ucrtVersion - + QStringLiteral("/Redist/Debug/arm/ucrtbased.dll"); - const QFileInfo ucrtPath(ucrtbasedLib); - if (ucrtPath.exists() && ucrtPath.isFile()) { - deployedQtLibraries.append(ucrtPath.absoluteFilePath()); - } else { - std::wcerr << "Warning: Cannot find ucrtbased.dll at " - << QDir::toNativeSeparators(ucrtbasedLib) - << " or it is not a file.\n"; - } - } - } - // Update libraries if (options.libraries) { const QString targetPath = options.libraryDirectory.isEmpty() ? @@ -1467,7 +1429,7 @@ static DeployResult deploy(const Options &options, return result; } - if (options.patchQt && !options.dryRun && !options.isWinRt()) { + if (options.patchQt && !options.dryRun) { const QString qt5CoreName = QFileInfo(libraryPath(libraryLocation, "Qt6Core", qtLibInfix, options.platform, result.isDebug)).fileName(); #ifndef QT_RELOCATABLE diff --git a/src/winrtrunner/CMakeLists.txt b/src/winrtrunner/CMakeLists.txt deleted file mode 100644 index 304b67e2b..000000000 --- a/src/winrtrunner/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -# Generated from winrtrunner.pro. - -##################################################################### -## winrtrunner Tool: -##################################################################### - -qt_get_tool_target_name(target_name winrtrunner) -qt_add_tool(${target_name} - BOOTSTRAP - TARGET_DESCRIPTION "Qt WinRT Runner" - SOURCES - ../shared/corecon/ccapi.h - ../shared/corecon/ccapi_11.h - ../shared/corecon/ccapi_12.h - ../shared/corecon/corecon.cpp ../shared/corecon/corecon.h - ../shared/winutils/elfreader.cpp ../shared/winutils/elfreader.h - ../shared/winutils/qmlutils.cpp ../shared/winutils/qmlutils.h - ../shared/winutils/utils.cpp ../shared/winutils/utils.h - appxengine.cpp appxengine.h appxengine_p.h - appxlocalengine.cpp appxlocalengine.h - appxphoneengine.cpp appxphoneengine.h - main.cpp - runner.cpp runner.h - runnerengine.h - DEFINES - QT_NO_CAST_FROM_ASCII - QT_NO_CAST_TO_ASCII - WINRT_LIBRARY - INCLUDE_DIRECTORIES - ../shared/corecon - ../shared/winutils - PUBLIC_LIBRARIES - Shlwapi - crypt32 - runtimeobject - urlmon - wsclient - xmllite -) - -#### Keys ignored in scope 1:.:.:winrtrunner.pro:<TRUE>: -# QMAKE_TARGET_DESCRIPTION = "Qt WinRT Runner" -# QT_FOR_CONFIG = "tools-private" -# _OPTION = "host_build" -# _REQUIREMENTS = "qtConfig(winrtrunner)" diff --git a/src/winrtrunner/appxengine.cpp b/src/winrtrunner/appxengine.cpp deleted file mode 100644 index 1f2ee5186..000000000 --- a/src/winrtrunner/appxengine.cpp +++ /dev/null @@ -1,801 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "appxengine.h" -#include "appxengine_p.h" - -#include <QtCore/QDateTime> -#include <QtCore/QDir> -#include <QtCore/QDirIterator> -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtCore/QLoggingCategory> -#include <QtCore/QStandardPaths> -#include <QtCore/QRegularExpression> - -#include <ShlObj.h> -#include <Shlwapi.h> -#include <wsdevlicensing.h> -#include <AppxPackaging.h> -#include <wrl.h> -#include <windows.applicationmodel.h> -#include <windows.management.deployment.h> -#include <wincrypt.h> - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Management::Deployment; -using namespace ABI::Windows::ApplicationModel; -using namespace ABI::Windows::System; - -QT_USE_NAMESPACE - -// *********** Taken from MSDN Example code -// https://msdn.microsoft.com/en-us/library/windows/desktop/jj835834%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 - -#define SIGNER_SUBJECT_FILE 0x01 -#define SIGNER_NO_ATTR 0x00 -#define SIGNER_CERT_POLICY_CHAIN_NO_ROOT 0x08 -#define SIGNER_CERT_STORE 0x02 - -typedef struct _SIGNER_FILE_INFO -{ - DWORD cbSize; - LPCWSTR pwszFileName; - HANDLE hFile; -} SIGNER_FILE_INFO; - -typedef struct _SIGNER_BLOB_INFO -{ - DWORD cbSize; - GUID *pGuidSubject; - DWORD cbBlob; - BYTE *pbBlob; - LPCWSTR pwszDisplayName; -} SIGNER_BLOB_INFO; - -typedef struct _SIGNER_SUBJECT_INFO -{ - DWORD cbSize; - DWORD *pdwIndex; - DWORD dwSubjectChoice; - union - { - SIGNER_FILE_INFO *pSignerFileInfo; - SIGNER_BLOB_INFO *pSignerBlobInfo; - }; -} SIGNER_SUBJECT_INFO, *PSIGNER_SUBJECT_INFO; - -typedef struct _SIGNER_ATTR_AUTHCODE -{ - DWORD cbSize; - BOOL fCommercial; - BOOL fIndividual; - LPCWSTR pwszName; - LPCWSTR pwszInfo; -} SIGNER_ATTR_AUTHCODE; - -typedef struct _SIGNER_SIGNATURE_INFO -{ - DWORD cbSize; - ALG_ID algidHash; - DWORD dwAttrChoice; - union - { - SIGNER_ATTR_AUTHCODE *pAttrAuthcode; - }; - PCRYPT_ATTRIBUTES psAuthenticated; - PCRYPT_ATTRIBUTES psUnauthenticated; -} SIGNER_SIGNATURE_INFO, *PSIGNER_SIGNATURE_INFO; - -typedef struct _SIGNER_PROVIDER_INFO -{ - DWORD cbSize; - LPCWSTR pwszProviderName; - DWORD dwProviderType; - DWORD dwKeySpec; - DWORD dwPvkChoice; - union - { - LPWSTR pwszPvkFileName; - LPWSTR pwszKeyContainer; - }; -} SIGNER_PROVIDER_INFO, *PSIGNER_PROVIDER_INFO; - -typedef struct _SIGNER_SPC_CHAIN_INFO -{ - DWORD cbSize; - LPCWSTR pwszSpcFile; - DWORD dwCertPolicy; - HCERTSTORE hCertStore; -} SIGNER_SPC_CHAIN_INFO; - -typedef struct _SIGNER_CERT_STORE_INFO -{ - DWORD cbSize; - PCCERT_CONTEXT pSigningCert; - DWORD dwCertPolicy; - HCERTSTORE hCertStore; -} SIGNER_CERT_STORE_INFO; - -typedef struct _SIGNER_CERT -{ - DWORD cbSize; - DWORD dwCertChoice; - union - { - LPCWSTR pwszSpcFile; - SIGNER_CERT_STORE_INFO *pCertStoreInfo; - SIGNER_SPC_CHAIN_INFO *pSpcChainInfo; - }; - HWND hwnd; -} SIGNER_CERT, *PSIGNER_CERT; - -typedef struct _SIGNER_CONTEXT -{ - DWORD cbSize; - DWORD cbBlob; - BYTE *pbBlob; -} SIGNER_CONTEXT, *PSIGNER_CONTEXT; - -typedef struct _SIGNER_SIGN_EX2_PARAMS -{ - DWORD dwFlags; - PSIGNER_SUBJECT_INFO pSubjectInfo; - PSIGNER_CERT pSigningCert; - PSIGNER_SIGNATURE_INFO pSignatureInfo; - PSIGNER_PROVIDER_INFO pProviderInfo; - DWORD dwTimestampFlags; - PCSTR pszAlgorithmOid; - PCWSTR pwszTimestampURL; - PCRYPT_ATTRIBUTES pCryptAttrs; - PVOID pSipData; - PSIGNER_CONTEXT *pSignerContext; - PVOID pCryptoPolicy; - PVOID pReserved; -} SIGNER_SIGN_EX2_PARAMS, *PSIGNER_SIGN_EX2_PARAMS; - -typedef struct _APPX_SIP_CLIENT_DATA -{ - PSIGNER_SIGN_EX2_PARAMS pSignerParams; - IUnknown* pAppxSipState; -} APPX_SIP_CLIENT_DATA, *PAPPX_SIP_CLIENT_DATA; - -bool signAppxPackage(PCCERT_CONTEXT signingCertContext, LPCWSTR packageFilePath) -{ - HRESULT hr = S_OK; - - DWORD signerIndex = 0; - - SIGNER_FILE_INFO fileInfo = {}; - fileInfo.cbSize = sizeof(SIGNER_FILE_INFO); - fileInfo.pwszFileName = packageFilePath; - - SIGNER_SUBJECT_INFO subjectInfo = {}; - subjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO); - subjectInfo.pdwIndex = &signerIndex; - subjectInfo.dwSubjectChoice = SIGNER_SUBJECT_FILE; - subjectInfo.pSignerFileInfo = &fileInfo; - - SIGNER_CERT_STORE_INFO certStoreInfo = {}; - certStoreInfo.cbSize = sizeof(SIGNER_CERT_STORE_INFO); - certStoreInfo.dwCertPolicy = SIGNER_CERT_POLICY_CHAIN_NO_ROOT; - certStoreInfo.pSigningCert = signingCertContext; - - SIGNER_CERT cert = {}; - cert.cbSize = sizeof(SIGNER_CERT); - cert.dwCertChoice = SIGNER_CERT_STORE; - cert.pCertStoreInfo = &certStoreInfo; - - // The algidHash of the signature to be created must match the - // hash algorithm used to create the app package - SIGNER_SIGNATURE_INFO signatureInfo = {}; - signatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO); - signatureInfo.algidHash = CALG_SHA_512; - signatureInfo.dwAttrChoice = SIGNER_NO_ATTR; - - SIGNER_SIGN_EX2_PARAMS signerParams = {}; - signerParams.pSubjectInfo = &subjectInfo; - signerParams.pSigningCert = &cert; - signerParams.pSignatureInfo = &signatureInfo; - - APPX_SIP_CLIENT_DATA sipClientData = {}; - sipClientData.pSignerParams = &signerParams; - signerParams.pSipData = &sipClientData; - - // Type definition for invoking SignerSignEx2 via GetProcAddress - typedef HRESULT (WINAPI *SignerSignEx2Function)( - DWORD, - PSIGNER_SUBJECT_INFO, - PSIGNER_CERT, - PSIGNER_SIGNATURE_INFO, - PSIGNER_PROVIDER_INFO, - DWORD, - PCSTR, - PCWSTR, - PCRYPT_ATTRIBUTES, - PVOID, - PSIGNER_CONTEXT *, - PVOID, - PVOID); - - // Load the SignerSignEx2 function from MSSign32.dll - HMODULE msSignModule = LoadLibraryEx( - L"MSSign32.dll", - NULL, - LOAD_LIBRARY_SEARCH_SYSTEM32); - - if (!msSignModule) { - qCWarning(lcWinRtRunner) << "LoadLibraryEx failed to load MSSign32.dll."; - return false; - } - - SignerSignEx2Function SignerSignEx2 = reinterpret_cast<SignerSignEx2Function>( - GetProcAddress(msSignModule, "SignerSignEx2")); - if (!SignerSignEx2) { - qCWarning(lcWinRtRunner) << "Could not resolve SignerSignEx2"; - FreeLibrary(msSignModule); - return false; - } - hr = SignerSignEx2(signerParams.dwFlags, - signerParams.pSubjectInfo, - signerParams.pSigningCert, - signerParams.pSignatureInfo, - signerParams.pProviderInfo, - signerParams.dwTimestampFlags, - signerParams.pszAlgorithmOid, - signerParams.pwszTimestampURL, - signerParams.pCryptAttrs, - signerParams.pSipData, - signerParams.pSignerContext, - signerParams.pCryptoPolicy, - signerParams.pReserved); - - FreeLibrary(msSignModule); - - RETURN_FALSE_IF_FAILED("Could not sign package."); - - if (sipClientData.pAppxSipState) - sipClientData.pAppxSipState->Release(); - - return true; -} -// ************ MSDN - -bool AppxEngine::getManifestFile(const QString &fileName, QString *manifest) -{ - if (!QFile::exists(fileName)) { - qCWarning(lcWinRtRunner) << fileName << "does not exist."; - return false; - } - - // If it looks like an appx manifest, we're done - if (fileName.endsWith(QStringLiteral("AppxManifest.xml"))) { - - if (manifest) - *manifest = fileName; - return true; - } - - // If it looks like an executable, check that manifest is next to it - if (fileName.endsWith(QLatin1String(".exe"))) { - QDir appDir = QFileInfo(fileName).absoluteDir(); - QString manifestFileName = appDir.absoluteFilePath(QStringLiteral("AppxManifest.xml")); - if (!QFile::exists(manifestFileName)) { - qCWarning(lcWinRtRunner) << manifestFileName << "does not exist."; - return false; - } - - if (manifest) - *manifest = manifestFileName; - return true; - } - - if (fileName.endsWith(QLatin1String(".appx"))) { - // For existing appx packages the manifest reader will be - // instantiated later. - return true; - } - - qCWarning(lcWinRtRunner) << "Appx: unable to determine manifest for" << fileName << "."; - return false; -} - -#define CHECK_RESULT(errorMessage, action)\ - do {\ - if (FAILED(hr)) {\ - qCWarning(lcWinRtRunner).nospace() << errorMessage " (0x"\ - << QByteArray::number(hr, 16).constData()\ - << ' ' << qt_error_string(hr) << ')';\ - action;\ - }\ - } while (false) - -#define CHECK_RESULT_FATAL(errorMessage, action)\ - do {CHECK_RESULT(errorMessage, d->hasFatalError = true; action;);} while (false) - -static ProcessorArchitecture toProcessorArchitecture(APPX_PACKAGE_ARCHITECTURE appxArch) -{ - switch (appxArch) { - case APPX_PACKAGE_ARCHITECTURE_X86: - return ProcessorArchitecture_X86; - case APPX_PACKAGE_ARCHITECTURE_ARM: - return ProcessorArchitecture_Arm; - case APPX_PACKAGE_ARCHITECTURE_X64: - return ProcessorArchitecture_X64; - case APPX_PACKAGE_ARCHITECTURE_NEUTRAL: - // fall-through intended - default: - return ProcessorArchitecture_Neutral; - } -} - -AppxEngine::AppxEngine(Runner *runner, AppxEnginePrivate *dd) - : d_ptr(dd) -{ - Q_D(AppxEngine); - if (d->hasFatalError) - return; - - d->runner = runner; - d->processHandle = NULL; - d->pid = -1; - d->exitCode = UINT_MAX; - - HRESULT hr; - 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_AppxFactory, nullptr, CLSCTX_INPROC_SERVER, - IID_IAppxFactory, &d->packageFactory); - CHECK_RESULT_FATAL("Failed to instantiate package factory.", return); - - bool existingPackage = runner->app().endsWith(QLatin1String(".appx")); - - if (existingPackage) { - ComPtr<IStream> appxStream; - hr = SHCreateStreamOnFile(wchar(runner->app()), STGM_READ, &appxStream); - CHECK_RESULT_FATAL("Failed to open appx stream.", return); - - ComPtr<IAppxPackageReader> packageReader; - hr = d->packageFactory->CreatePackageReader(appxStream.Get(), &packageReader); - if (FAILED(hr)) { - qCWarning(lcWinRtRunner).nospace() << "Failed to instantiate package reader. (0x" - << QByteArray::number(hr, 16).constData() - << ' ' << qt_error_string(hr) << ')'; - d->hasFatalError = true; - return; - } - - hr = packageReader->GetManifest(&d->manifestReader); - if (FAILED(hr)) { - qCWarning(lcWinRtRunner).nospace() << "Failed to query manifext reader from package"; - d->hasFatalError = true; - return; - } - } else { - if (!getManifestFile(runner->app(), &d->manifest)) { - qCWarning(lcWinRtRunner) << "Unable to determine manifest file from" << runner->app(); - d->hasFatalError = true; - return; - } - - ComPtr<IStream> manifestStream; - hr = SHCreateStreamOnFile(wchar(d->manifest), STGM_READ, &manifestStream); - CHECK_RESULT_FATAL("Failed to open manifest stream.", return); - - hr = d->packageFactory->CreateManifestReader(manifestStream.Get(), &d->manifestReader); - if (FAILED(hr)) { - qCWarning(lcWinRtRunner).nospace() << "Failed to instantiate manifest reader. (0x" - << QByteArray::number(hr, 16).constData() - << ' ' << qt_error_string(hr) << ')'; - // ### TODO: read detailed error from event log directly - if (hr == APPX_E_INVALID_MANIFEST) { - qCWarning(lcWinRtRunner) << "More information on the error can " - "be found in the event log under " - "Microsoft\\Windows\\AppxPackagingOM"; - } - d->hasFatalError = true; - return; - } - } - ComPtr<IAppxManifestPackageId> packageId; - hr = d->manifestReader->GetPackageId(&packageId); - CHECK_RESULT_FATAL("Unable to obtain the package ID from the manifest.", return); - - APPX_PACKAGE_ARCHITECTURE arch; - hr = packageId->GetArchitecture(&arch); - CHECK_RESULT_FATAL("Failed to retrieve the app's architecture.", return); - d->packageArchitecture = toProcessorArchitecture(arch); - - LPWSTR packageFullName; - hr = packageId->GetPackageFullName(&packageFullName); - CHECK_RESULT_FATAL("Unable to obtain the package full name from the manifest.", return); - d->packageFullName = QString::fromWCharArray(packageFullName); - CoTaskMemFree(packageFullName); - - LPWSTR packageFamilyName; - hr = packageId->GetPackageFamilyName(&packageFamilyName); - CHECK_RESULT_FATAL("Unable to obtain the package full family name from the manifest.", return); - d->packageFamilyName = QString::fromWCharArray(packageFamilyName); - CoTaskMemFree(packageFamilyName); - - LPWSTR publisher; - packageId->GetPublisher(&publisher); - CHECK_RESULT_FATAL("Failed to retrieve publisher name from package.", return); - d->publisherName = QString::fromWCharArray(publisher); - CoTaskMemFree(publisher); - - ComPtr<IAppxManifestApplicationsEnumerator> applications; - hr = d->manifestReader->GetApplications(&applications); - CHECK_RESULT_FATAL("Failed to get a list of applications from the manifest.", return); - - BOOL hasCurrent; - hr = applications->GetHasCurrent(&hasCurrent); - CHECK_RESULT_FATAL("Failed to iterate over applications in the manifest.", return); - - // For now, we are only interested in the first application - ComPtr<IAppxManifestApplication> application; - hr = applications->GetCurrent(&application); - CHECK_RESULT_FATAL("Failed to access the first application in the manifest.", return); - - LPWSTR executable; - application->GetStringValue(L"Executable", &executable); - CHECK_RESULT_FATAL("Failed to retrieve the application executable from the manifest.", return); - d->executable = QFileInfo(runner->app()).absoluteDir() - .absoluteFilePath(QString::fromWCharArray(executable)); - CoTaskMemFree(executable); - - ComPtr<IAppxManifestPackageDependenciesEnumerator> dependencies; - hr = d->manifestReader->GetPackageDependencies(&dependencies); - CHECK_RESULT_FATAL("Failed to retrieve the package dependencies from the manifest.", return); - - hr = dependencies->GetHasCurrent(&hasCurrent); - CHECK_RESULT_FATAL("Failed to iterate over dependencies in the manifest.", return); - while (SUCCEEDED(hr) && hasCurrent) { - ComPtr<IAppxManifestPackageDependency> dependency; - hr = dependencies->GetCurrent(&dependency); - CHECK_RESULT_FATAL("Failed to access dependency in the manifest.", return); - - LPWSTR name; - hr = dependency->GetName(&name); - CHECK_RESULT_FATAL("Failed to access dependency name.", return); - d->dependencies.insert(QString::fromWCharArray(name)); - CoTaskMemFree(name); - hr = dependencies->MoveNext(&hasCurrent); - } -} - -AppxEngine::~AppxEngine() -{ - Q_D(const 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); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - QSet<QString> toInstall; - for (const QString &dependencyName : qAsConst(d->dependencies)) { - toInstall.insert(dependencyName); - qCDebug(lcWinRtRunner).nospace() - << "dependency to be installed: " << dependencyName; - } - - if (toInstall.isEmpty()) - return true; - - const QString extensionSdkDir = extensionSdkPath(); - if (!QFile::exists(extensionSdkDir)) { - qCWarning(lcWinRtRunner).nospace().noquote() - << QStringLiteral("The directory \"%1\" does not exist.").arg( - QDir::toNativeSeparators(extensionSdkDir)); - return false; - } - qCDebug(lcWinRtRunner).nospace().noquote() - << "looking for dependency packages in \"" - << QDir::toNativeSeparators(extensionSdkDir) << '"'; - QDirIterator dit(extensionSdkDir, QStringList() << QStringLiteral("*.appx"), - QDir::Files, - QDirIterator::Subdirectories); - while (dit.hasNext()) { - dit.next(); - - HRESULT hr; - ComPtr<IStream> inputStream; - forever { - hr = SHCreateStreamOnFileEx(wchar(dit.filePath()), - STGM_READ | STGM_SHARE_EXCLUSIVE, - 0, FALSE, NULL, &inputStream); - if (HRESULT_CODE(hr) == ERROR_SHARING_VIOLATION) { - qCWarning(lcWinRtRunner).nospace() - << "Input stream is locked by another process. Will retry..."; - Sleep(1000); - } else { - break; - } - } - CHECK_RESULT("Failed to create input stream for package in ExtensionSdkDir.", continue); - - ComPtr<IAppxPackageReader> packageReader; - hr = d->packageFactory->CreatePackageReader(inputStream.Get(), &packageReader); - CHECK_RESULT("Failed to create package reader for package in ExtensionSdkDir.", continue); - - ComPtr<IAppxManifestReader> manifestReader; - hr = packageReader->GetManifest(&manifestReader); - CHECK_RESULT("Failed to create manifest reader for package in ExtensionSdkDir.", continue); - - ComPtr<IAppxManifestPackageId> packageId; - hr = manifestReader->GetPackageId(&packageId); - CHECK_RESULT("Failed to retrieve package id for package in ExtensionSdkDir.", continue); - - LPWSTR sz; - hr = packageId->GetName(&sz); - CHECK_RESULT("Failed to retrieve name from package in ExtensionSdkDir.", continue); - const QString name = QString::fromWCharArray(sz); - CoTaskMemFree(sz); - - if (!toInstall.contains(name)) - continue; - - APPX_PACKAGE_ARCHITECTURE arch; - hr = packageId->GetArchitecture(&arch); - CHECK_RESULT("Failed to retrieve architecture from package in ExtensionSdkDir.", continue); - if (d->packageArchitecture != arch) - continue; - - qCDebug(lcWinRtRunner).nospace().noquote() - << "installing dependency \"" << name << "\" from \"" - << QDir::toNativeSeparators(dit.filePath()) << '"'; - if (!installPackage(manifestReader.Get(), dit.filePath())) { - qCWarning(lcWinRtRunner) << "Failed to install package:" << name; - return false; - } - } - - return true; -} - -bool AppxEngine::createPackage(const QString &packageFileName) -{ - Q_D(AppxEngine); - - static QHash<QString, QString> contentTypes; - if (contentTypes.isEmpty()) { - contentTypes.insert(QStringLiteral("dll"), QStringLiteral("application/x-msdownload")); - contentTypes.insert(QStringLiteral("exe"), QStringLiteral("application/x-msdownload")); - contentTypes.insert(QStringLiteral("png"), QStringLiteral("image/png")); - contentTypes.insert(QStringLiteral("xml"), QStringLiteral("vnd.ms-appx.manifest+xml")); - } - - // Check for package map, or create one if needed - QDir base = QFileInfo(d->manifest).absoluteDir(); - QFile packageFile(packageFileName); - - QHash<QString, QString> files; - QFile mappingFile(base.absoluteFilePath(QStringLiteral("AppxManifest.map"))); - if (mappingFile.exists()) { - qCWarning(lcWinRtRunner) << "Creating package from mapping file:" << mappingFile.fileName(); - if (!mappingFile.open(QFile::ReadOnly)) { - qCWarning(lcWinRtRunner) << "Unable to read mapping file:" << mappingFile.errorString(); - return false; - } - - QRegularExpression pattern(QStringLiteral("^\"([^\"]*)\"\\s*\"([^\"]*)\"$")); - QRegularExpressionMatch match; - bool inFileSection = false; - while (!mappingFile.atEnd()) { - const QString line = QString::fromUtf8(mappingFile.readLine()).trimmed(); - if (line.startsWith(QLatin1Char('['))) { - inFileSection = line == QStringLiteral("[Files]"); - continue; - } - if (match.captured(2).compare(QStringLiteral("AppxManifest.xml"), Qt::CaseInsensitive) == 0) - continue; - if (inFileSection && (match = pattern.match(line)).hasMatch()) { - QString inputFile = match.captured(1); - if (!QFile::exists(inputFile)) - inputFile = base.absoluteFilePath(inputFile); - files.insert(QDir::toNativeSeparators(inputFile), QDir::toNativeSeparators(match.captured(2))); - } - } - } else { - qCWarning(lcWinRtRunner) << "No mapping file exists. Only recognized files will be packaged."; - // Add executable - files.insert(QDir::toNativeSeparators(d->executable), QFileInfo(d->executable).fileName()); - // Add all files but filtered artifacts - const QStringList excludeFileTypes = QStringList() - << QStringLiteral("ilk") << QStringLiteral("pdb") << QStringLiteral("obj") - << QStringLiteral("appx"); - - QDirIterator dirIterator(base.absolutePath(), QDir::Files, QDirIterator::Subdirectories); - while (dirIterator.hasNext()) { - const QString filePath = dirIterator.next(); - if (filePath.endsWith(QLatin1String("AppxManifest.xml"), Qt::CaseInsensitive)) - continue; - const QFileInfo fileInfo(filePath); - if (!excludeFileTypes.contains(fileInfo.suffix())) - files.insert(QDir::toNativeSeparators(filePath), QDir::toNativeSeparators(base.relativeFilePath(filePath))); - } - } - - ComPtr<IStream> outputStream; - HRESULT hr = SHCreateStreamOnFile(wchar(packageFile.fileName()), STGM_WRITE|STGM_CREATE, &outputStream); - RETURN_FALSE_IF_FAILED("Failed to create package file output stream"); - - ComPtr<IUri> hashMethod; - hr = CreateUri(L"http://www.w3.org/2001/04/xmlenc#sha512", Uri_CREATE_CANONICALIZE, 0, &hashMethod); - RETURN_FALSE_IF_FAILED("Failed to create the has method URI"); - - APPX_PACKAGE_SETTINGS packageSettings = { FALSE, hashMethod.Get() }; - ComPtr<IAppxPackageWriter> packageWriter; - hr = d->packageFactory->CreatePackageWriter(outputStream.Get(), &packageSettings, &packageWriter); - RETURN_FALSE_IF_FAILED("Failed to create package writer"); - - for (QHash<QString, QString>::const_iterator i = files.begin(); i != files.end(); ++i) { - qCDebug(lcWinRtRunner) << "Packaging" << i.key() << i.value(); - ComPtr<IStream> inputStream; - hr = SHCreateStreamOnFile(wchar(i.key()), STGM_READ, &inputStream); - RETURN_FALSE_IF_FAILED("Failed to open file"); - const QString contentType = contentTypes.value(QFileInfo(i.key()).suffix().toLower(), - QStringLiteral("application/octet-stream")); - hr = packageWriter->AddPayloadFile(wchar(i.value()), wchar(contentType), - APPX_COMPRESSION_OPTION_NORMAL, inputStream.Get()); - RETURN_FALSE_IF_FAILED("Failed to add payload file"); - } - - // Write out the manifest - ComPtr<IStream> manifestStream; - hr = SHCreateStreamOnFile(wchar(d->manifest), STGM_READ, &manifestStream); - RETURN_FALSE_IF_FAILED("Failed to open manifest for packaging"); - hr = packageWriter->Close(manifestStream.Get()); - RETURN_FALSE_IF_FAILED("Failed to finalize package."); - - return true; -} - -bool AppxEngine::sign(const QString &fileName) -{ - Q_D(const AppxEngine); - BYTE buffer[256]; - DWORD bufferSize = 256; - - if (!CertStrToName(X509_ASN_ENCODING, wchar(d->publisherName), CERT_X500_NAME_STR, 0, buffer, &bufferSize, 0)) { - qCWarning(lcWinRtRunner) << "CertStrToName failed"; - return false; - } - CERT_NAME_BLOB certBlob; - certBlob.cbData = bufferSize; - certBlob.pbData = buffer; - - CRYPT_ALGORITHM_IDENTIFIER identifier; - identifier.pszObjId = strdup(szOID_RSA_SHA256RSA); - identifier.Parameters.cbData = 0; - identifier.Parameters.pbData = NULL; - - CERT_EXTENSIONS extensions; - extensions.cExtension = 2; - extensions.rgExtension = new CERT_EXTENSION[2]; - - // Basic Constraints - CERT_BASIC_CONSTRAINTS2_INFO constraintsInfo; - constraintsInfo.fCA = FALSE; - constraintsInfo.fPathLenConstraint = FALSE; - constraintsInfo.dwPathLenConstraint = 0; - - BYTE *constraintsEncoded = NULL; - DWORD encodedSize = 0; - CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &constraintsInfo, - constraintsEncoded, &encodedSize); - constraintsEncoded = new BYTE[encodedSize]; - if (!CryptEncodeObject(X509_ASN_ENCODING, X509_BASIC_CONSTRAINTS2, &constraintsInfo, - constraintsEncoded, &encodedSize)) { - qCWarning(lcWinRtRunner) << "Could not encode basic constraints."; - delete [] constraintsEncoded; - return false; - } - - extensions.rgExtension[0].pszObjId = strdup(szOID_BASIC_CONSTRAINTS2); - extensions.rgExtension[0].fCritical = TRUE; - extensions.rgExtension[0].Value.cbData = encodedSize; - extensions.rgExtension[0].Value.pbData = constraintsEncoded; - - // Code Signing - char *codeSign = strdup(szOID_PKIX_KP_CODE_SIGNING); - CERT_ENHKEY_USAGE enhancedUsage; - enhancedUsage.cUsageIdentifier = 1; - enhancedUsage.rgpszUsageIdentifier = &codeSign; - - BYTE *enhancedKeyEncoded = 0; - encodedSize = 0; - CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &enhancedUsage, - enhancedKeyEncoded, &encodedSize); - enhancedKeyEncoded = new BYTE[encodedSize]; - if (!CryptEncodeObject(X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &enhancedUsage, - enhancedKeyEncoded, &encodedSize)) { - qCWarning(lcWinRtRunner) << "Could not encode enhanced key usage."; - delete [] constraintsEncoded; - return false; - } - - extensions.rgExtension[1].pszObjId = strdup(szOID_ENHANCED_KEY_USAGE); - extensions.rgExtension[1].fCritical = TRUE; - extensions.rgExtension[1].Value.cbData = encodedSize; - extensions.rgExtension[1].Value.pbData = enhancedKeyEncoded; - - PCCERT_CONTEXT context = CertCreateSelfSignCertificate(NULL, &certBlob, NULL, NULL, - &identifier, NULL, NULL, &extensions); - - delete [] constraintsEncoded; - - if (!context) { - qCWarning(lcWinRtRunner) << "Failed to create self sign certificate:" << GetLastError(); - return false; - } - - return signAppxPackage(context, wchar(fileName)); -} diff --git a/src/winrtrunner/appxengine.h b/src/winrtrunner/appxengine.h deleted file mode 100644 index c2d235ec6..000000000 --- a/src/winrtrunner/appxengine.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef APPXENGINE_H -#define APPXENGINE_H - -#include "runnerengine.h" -#include "runner.h" - -#include <QtCore/QScopedPointer> -#include <QtCore/QString> - -QT_USE_NAMESPACE - -struct IAppxManifestReader; -class AppxEnginePrivate; -class AppxEngine : public RunnerEngine -{ -public: - qint64 pid() const override; - int exitCode() const override; - QString executable() const override; - -protected: - explicit AppxEngine(Runner *runner, AppxEnginePrivate *dd); - ~AppxEngine(); - - virtual QString extensionSdkPath() const = 0; - virtual bool installPackage(IAppxManifestReader *reader, const QString &filePath) = 0; - - bool installDependencies(); - bool createPackage(const QString &packageFileName); - bool sign(const QString &fileName); - static bool getManifestFile(const QString &fileName, QString *manifest = 0); - - QScopedPointer<AppxEnginePrivate> d_ptr; - Q_DECLARE_PRIVATE(AppxEngine) -}; - -#endif // APPXENGINE_H diff --git a/src/winrtrunner/appxengine_p.h b/src/winrtrunner/appxengine_p.h deleted file mode 100644 index 5caa2810e..000000000 --- a/src/winrtrunner/appxengine_p.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef APPXENGINE_P_H -#define APPXENGINE_P_H - -#include <QtCore/qt_windows.h> -#include <QtCore/QSet> -#include <QtCore/QString> - -#include <wrl.h> -#include <windows.system.h> - -QT_USE_NAMESPACE - -class Runner; -struct IAppxFactory; -class AppxEnginePrivate -{ -public: - AppxEnginePrivate() - { - HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - if (FAILED(hr)) { - qCWarning(lcWinRtRunner) << "Failed to initialize COM:" << qt_error_string(hr); - hasFatalError = true; - } - hasFatalError = false; - } - - virtual ~AppxEnginePrivate() - { - uriFactory.Reset(); - packageFactory.Reset(); - manifestReader.Reset(); - CoUninitialize(); - } - - Runner *runner; - bool hasFatalError; - - QString manifest; - QString packageFullName; - QString packageFamilyName; - QString publisherName; - ABI::Windows::System::ProcessorArchitecture packageArchitecture; - QString executable; - qint64 pid; - HANDLE processHandle; - DWORD exitCode; - QSet<QString> dependencies; - QSet<QString> installedPackages; - - Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IUriRuntimeClassFactory> uriFactory; - Microsoft::WRL::ComPtr<IAppxFactory> packageFactory; - Microsoft::WRL::ComPtr<IAppxManifestReader> manifestReader; -}; - -#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, nullptr)) - -#define RETURN_IF_FAILED(msg, ret) \ - if (FAILED(hr)) { \ - qCWarning(lcWinRtRunner).nospace() << msg << ": 0x" << QByteArray::number(hr, 16).constData() \ - << ' ' << qt_error_string(hr); \ - ret; \ - } - -#define RETURN_HR_IF_FAILED(msg) RETURN_IF_FAILED(msg, return hr) -#define RETURN_OK_IF_FAILED(msg) RETURN_IF_FAILED(msg, return S_OK) -#define RETURN_FALSE_IF_FAILED(msg) RETURN_IF_FAILED(msg, return false) -#define RETURN_VOID_IF_FAILED(msg) RETURN_IF_FAILED(msg, return) - -#endif // APPXENGINE_P_H diff --git a/src/winrtrunner/appxlocalengine.cpp b/src/winrtrunner/appxlocalengine.cpp deleted file mode 100644 index 69bc39919..000000000 --- a/src/winrtrunner/appxlocalengine.cpp +++ /dev/null @@ -1,884 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "appxlocalengine.h" -#include "appxengine_p.h" - -#include "utils.h" - -#include <QtCore/QDateTime> -#include <QtCore/QDir> -#include <QtCore/QDirIterator> -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtCore/QLoggingCategory> -#include <QtCore/QStandardPaths> -#include <QtCore/QOperatingSystemVersion> - -#include <ShlObj.h> -#include <Shlwapi.h> -#include <wsdevlicensing.h> -#include <AppxPackaging.h> -#include <wrl.h> -#include <windows.applicationmodel.h> -#include <windows.management.deployment.h> - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Management::Deployment; -using namespace ABI::Windows::ApplicationModel; -using namespace ABI::Windows::System; - -typedef IAsyncOperationWithProgressCompletedHandler<DeploymentResult *, DeploymentProgress> DeploymentResultHandler; -typedef IAsyncOperationWithProgress<DeploymentResult *, DeploymentProgress> DeploymentOperation; - -QT_USE_NAMESPACE - -// 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, ®Key); - 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]; - const wchar_t *packageFamilyNameW = wchar(packageFamilyName); - 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, packageFamilyNameW) == 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 ackEventName = handleBase + QStringLiteral("\\qdebug-event-ack"); - 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 ackEvent = CreateEvent(NULL, FALSE, FALSE, reinterpret_cast<LPCWSTR>(ackEventName.utf16())); - if (!ackEvent) { - qCWarning(lcWinRtRunner) << "Unable to open shared acknowledge event for app debugging:" - << qt_error_string(GetLastError()); - return 1; - } - - HANDLE shmem = 0; - DWORD ret = 0; - quint64 size = 4096; - const quint32 resizeMessageType = QtInfoMsg + 1; - HANDLE handles[] = { that->runLock, event }; - forever { - DWORD result = WaitForMultipleObjects(2, handles, FALSE, INFINITE); - - // runLock set; exit thread - if (result == WAIT_OBJECT_0) - break; - - 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, size)); - if (!data) { - qCWarning(lcWinRtRunner) << "Unable to map view of shared memory for app debugging:" - << qt_error_string(GetLastError()); - ret = 1; - break; - } - const quint32 type = data[0]; - // resize message received; Resize shared memory - if (type == resizeMessageType) { - size = (data[2] << 8) + data[1]; - if (!UnmapViewOfFile(data)) { - qCWarning(lcWinRtRunner) << "Unable to unmap view of shared memory for app debugging:" - << qt_error_string(GetLastError()); - ret = 1; - break; - } - if (shmem) { - if (!CloseHandle(shmem)) { - qCWarning(lcWinRtRunner) << "Unable to close shared memory handle:" - << qt_error_string(GetLastError()); - ret = 1; - break; - } - shmem = 0; - } - SetEvent(ackEvent); - continue; - } - - // debug event set; print message - QtMsgType messageType = static_cast<QtMsgType>(type); - QString message = QString::fromWCharArray( - reinterpret_cast<const wchar_t *>(data + 1)); - UnmapViewOfFile(data); - SetEvent(ackEvent); - 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); - if (ackEvent) - CloseHandle(ackEvent); - return ret; - } - HANDLE runLock; - HANDLE thread; - QString package; -}; -Q_GLOBAL_STATIC(OutputDebugMonitor, debugMonitor) - -class AppxLocalEnginePrivate : public AppxEnginePrivate -{ -public: - ComPtr<IPackageManager> packageManager; - ComPtr<IApplicationActivationManager> appLauncher; - ComPtr<IPackageDebugSettings> packageDebug; - - Qt::HANDLE loopbackServerProcessHandle = INVALID_HANDLE_VALUE; - - void retrieveInstalledPackages(); -}; - -static bool getManifestFile(const QString &fileName, QString *manifest = 0) -{ - if (!QFile::exists(fileName)) { - qCWarning(lcWinRtRunner) << fileName << "does not exist."; - return false; - } - - // If it looks like an appx manifest, we're done - if (fileName.endsWith(QStringLiteral("AppxManifest.xml"))) { - - if (manifest) - *manifest = fileName; - return true; - } - - // If it looks like an executable, check that manifest is next to it - if (fileName.endsWith(QStringLiteral(".exe"))) { - QDir appDir = QFileInfo(fileName).absoluteDir(); - QString manifestFileName = appDir.absoluteFilePath(QStringLiteral("AppxManifest.xml")); - if (!QFile::exists(manifestFileName)) { - qCWarning(lcWinRtRunner) << manifestFileName << "does not exist."; - return false; - } - - if (manifest) - *manifest = manifestFileName; - return true; - } - - // TODO: handle already-built package as well - - qCWarning(lcWinRtRunner) << "Appx: unable to determine manifest for" << fileName << "."; - return false; -} - -bool AppxLocalEngine::canHandle(Runner *runner) -{ - return getManifestFile(runner->app()); -} - -RunnerEngine *AppxLocalEngine::create(Runner *runner) -{ - QScopedPointer<AppxLocalEngine> engine(new AppxLocalEngine(runner)); - if (engine->d_ptr->hasFatalError) - return 0; - - return engine.take(); -} - -QStringList AppxLocalEngine::deviceNames() -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - return QStringList(QStringLiteral("local")); -} - - - -static ProcessorArchitecture toProcessorArchitecture(APPX_PACKAGE_ARCHITECTURE appxArch) -{ - switch (appxArch) { - case APPX_PACKAGE_ARCHITECTURE_X86: - return ProcessorArchitecture_X86; - case APPX_PACKAGE_ARCHITECTURE_ARM: - return ProcessorArchitecture_Arm; - case APPX_PACKAGE_ARCHITECTURE_X64: - return ProcessorArchitecture_X64; - case APPX_PACKAGE_ARCHITECTURE_NEUTRAL: - // fall-through intended - default: - return ProcessorArchitecture_Neutral; - } -} - -AppxLocalEngine::AppxLocalEngine(Runner *runner) - : AppxEngine(runner, new AppxLocalEnginePrivate) -{ - Q_D(AppxLocalEngine); - if (d->hasFatalError) - return; - d->hasFatalError = true; - - HRESULT hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Management_Deployment_PackageManager).Get(), - &d->packageManager); - RETURN_VOID_IF_FAILED("Failed to instantiate package manager"); - - hr = CoCreateInstance(CLSID_ApplicationActivationManager, nullptr, CLSCTX_INPROC_SERVER, - IID_IApplicationActivationManager, &d->appLauncher); - RETURN_VOID_IF_FAILED("Failed to instantiate application activation manager"); - - hr = CoCreateInstance(CLSID_PackageDebugSettings, nullptr, CLSCTX_INPROC_SERVER, - IID_IPackageDebugSettings, &d->packageDebug); - RETURN_VOID_IF_FAILED("Failed to instantiate package debug settings"); - - d->retrieveInstalledPackages(); - - // Set a break handler for gracefully exiting from long-running operations - SetConsoleCtrlHandler(&ctrlHandler, true); - d->hasFatalError = false; -} - -AppxLocalEngine::~AppxLocalEngine() -{ -} - -bool AppxLocalEngine::installPackage(IAppxManifestReader *reader, const QString &filePath) -{ - Q_D(const AppxLocalEngine); - qCDebug(lcWinRtRunner).nospace().noquote() - << __FUNCTION__ << " \"" << QDir::toNativeSeparators(filePath) << '"'; - - HRESULT hr; - if (reader) { - ComPtr<IAppxManifestPackageId> packageId; - hr = reader->GetPackageId(&packageId); - RETURN_FALSE_IF_FAILED("Failed to get package ID from reader."); - - LPWSTR name; - hr = packageId->GetName(&name); - RETURN_FALSE_IF_FAILED("Failed to get package name from package ID."); - - const QString packageName = QString::fromWCharArray(name); - CoTaskMemFree(name); - if (d->installedPackages.contains(packageName)) { - qCDebug(lcWinRtRunner) << "The package" << packageName << "is already installed."; - return true; - } - } - - const QString nativeFilePath = QDir::toNativeSeparators(QFileInfo(filePath).absoluteFilePath()); - const bool addInsteadOfRegister = nativeFilePath.endsWith(QStringLiteral(".appx"), - Qt::CaseInsensitive); - ComPtr<IUriRuntimeClass> uri; - hr = d->uriFactory->CreateUri(hStringFromQString(nativeFilePath), &uri); - RETURN_FALSE_IF_FAILED("Failed to create an URI for the package"); - - ComPtr<DeploymentOperation> deploymentOperation; - if (addInsteadOfRegister) { - hr = d->packageManager->AddPackageAsync(uri.Get(), NULL, DeploymentOptions_None, - &deploymentOperation); - RETURN_FALSE_IF_FAILED("Failed to add package"); - } else { - hr = d->packageManager->RegisterPackageAsync(uri.Get(), 0, - DeploymentOptions_DevelopmentMode, - &deploymentOperation); - RETURN_FALSE_IF_FAILED("Failed to start package registration"); - } - - HANDLE ev = CreateEvent(NULL, FALSE, FALSE, NULL); - hr = deploymentOperation->put_Completed(Callback<DeploymentResultHandler>([ev](DeploymentOperation *, AsyncStatus) { - SetEvent(ev); - return S_OK; - }).Get()); - RETURN_FALSE_IF_FAILED("Could not register deployment completed callback."); - DWORD ret = WaitForSingleObjectEx(ev, 60000, FALSE); - CloseHandle(ev); - if (ret != WAIT_OBJECT_0) { - if (ret == WAIT_TIMEOUT) - qCWarning(lcWinRtRunner) << "Deployment did not finish within 15 seconds."; - else - qCWarning(lcWinRtRunner) << "Deployment finished event was not triggered."; - return false; - } - - ComPtr<IDeploymentResult> results; - hr = deploymentOperation->GetResults(&results); - RETURN_FALSE_IF_FAILED("Failed to retrieve package registration results."); - - HRESULT errorCode; - hr = results->get_ExtendedErrorCode(&errorCode); - RETURN_FALSE_IF_FAILED("Failed to retrieve extended error code."); - - if (FAILED(errorCode)) { - if (HRESULT_CODE(errorCode) == ERROR_INSTALL_PREREQUISITE_FAILED) { - qCWarning(lcWinRtRunner) << "Unable to register package: A requirement for installation was not met. " - "Check that your Windows version matches TargetDeviceFamily's MinVersion set in your AppxManifest.xml."; - } else { - 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); - RETURN_FALSE_IF_FAILED("Unable to renew developer license"); - return install(false); - } - return false; - } - - return SUCCEEDED(hr); -} - -bool AppxLocalEngine::parseExitCode() -{ - Q_D(AppxLocalEngine); - const QString exitFileName(QStringLiteral("exitCode.tmp")); - bool ok = false; - QFile exitCodeFile(devicePath(QString::number(pid()).append(QStringLiteral(".pid")))); - if (exitCodeFile.open(QIODevice::ReadOnly)) { - d->exitCode = exitCodeFile.readAll().toInt(&ok); - exitCodeFile.close(); - exitCodeFile.remove(); - } - if (!ok && !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; - } - return true; -} - -bool AppxLocalEngine::install(bool removeFirst) -{ - Q_D(const AppxLocalEngine); - 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(nullptr, d->manifest); -} - -bool AppxLocalEngine::remove() -{ - Q_D(const AppxLocalEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - // ### TODO: use RemovePackageWithOptions to preserve previous state when re-installing - ComPtr<DeploymentOperation> deploymentOperation; - HRESULT hr = d->packageManager->RemovePackageAsync(hStringFromQString(d->packageFullName), &deploymentOperation); - RETURN_FALSE_IF_FAILED("Unable to start package removal"); - - HANDLE ev = CreateEvent(NULL, FALSE, FALSE, NULL); - hr = deploymentOperation->put_Completed(Callback<DeploymentResultHandler>([ev](DeploymentOperation *, AsyncStatus) { - SetEvent(ev); - return S_OK; - }).Get()); - RETURN_FALSE_IF_FAILED("Could not register deployment completed callback."); - DWORD ret = WaitForSingleObjectEx(ev, 60000, FALSE); - CloseHandle(ev); - if (ret != WAIT_OBJECT_0) { - if (ret == WAIT_TIMEOUT) - qCWarning(lcWinRtRunner) << "Deployment did not finish within 15 seconds."; - else - qCWarning(lcWinRtRunner) << "Deployment finished event was not triggered."; - return false; - } - - ComPtr<IAsyncInfo> asyncInfo; - hr = deploymentOperation.As(&asyncInfo); - RETURN_FALSE_IF_FAILED("Failed to cast deployment operation."); - - AsyncStatus status; - hr = asyncInfo->get_Status(&status); - RETURN_FALSE_IF_FAILED("Failed to retrieve deployment operation's status."); - - if (status != Completed) { - qCWarning(lcWinRtRunner) << "Unable to remove package."; - return false; - } - - return true; -} - -bool AppxLocalEngine::start() -{ - Q_D(AppxLocalEngine); - 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); - RETURN_FALSE_IF_FAILED("Failed to activate application"); - d->pid = qint64(pid); - CloseHandle(d->processHandle); - d->processHandle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, true, pid); - - return true; -} - -bool AppxLocalEngine::enableDebugging(const QString &debuggerExecutable, const QString &debuggerArguments) -{ - Q_D(AppxLocalEngine); - - const QString &debuggerCommand = debuggerExecutable + QLatin1Char(' ') + debuggerArguments; - HRESULT hr = d->packageDebug->EnableDebugging(wchar(d->packageFullName), - wchar(debuggerCommand), - NULL); - RETURN_FALSE_IF_FAILED("Failed to enable debugging for application"); - return true; -} - -bool AppxLocalEngine::disableDebugging() -{ - Q_D(AppxLocalEngine); - - HRESULT hr = d->packageDebug->DisableDebugging(wchar(d->packageFullName)); - RETURN_FALSE_IF_FAILED("Failed to disable debugging for application"); - - return true; -} - -bool AppxLocalEngine::setLoopbackExemptClientEnabled(bool enabled) -{ - Q_D(AppxLocalEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__ << enabled; - - if (!enabled) { - PACKAGE_EXECUTION_STATE state; - HRESULT hr = d->packageDebug->GetPackageExecutionState(wchar(d->packageFullName), &state); - RETURN_FALSE_IF_FAILED("Failed to get package execution state"); - if (state != PES_TERMINATED && state != PES_UNKNOWN) { - qCWarning(lcWinRtRunner) << "Cannot unregister loopback exemption for running program." - << "Please use checknetisolation.exe to check/clean up the exemption list."; - return false; - } - } - - QByteArray stdOut; - QByteArray stdErr; - unsigned long exitCode = 0; - QString errorMessage; - QStringList arguments; - const QString binary = QStringLiteral("checknetisolation.exe"); - arguments << QStringLiteral("LoopbackExempt") - << (enabled ? QStringLiteral("-a") : QStringLiteral("-d")) - << QStringLiteral("-p=") + sidForPackage(d->packageFamilyName); - if (!runProcess(binary, arguments, QString(), &exitCode, &stdOut, &stdErr, &errorMessage)) { - qCWarning(lcWinRtRunner) << "Could not run" << binary; - return false; - } - if (exitCode) { - if (errorMessage.isEmpty()) { - errorMessage = binary + QStringLiteral(" returned ") + QString::number(exitCode) - + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr); - } - qCWarning(lcWinRtRunner) << errorMessage; - return false; - } - return true; -} - -bool AppxLocalEngine::setLoopbackExemptServerEnabled(bool enabled) -{ - Q_D(AppxLocalEngine); - const QOperatingSystemVersion minimal - = QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 14393); - if (QOperatingSystemVersion::current() < minimal) { - qCWarning(lcWinRtRunner) << "Cannot enable loopback exemption for servers. If you want" - << "to use this feature please update to a Windows version >=" - << minimal; - return false; - } - - if (enabled) { - QStringList arguments; - const QString binary = QStringLiteral("checknetisolation.exe"); - arguments << QStringLiteral("LoopbackExempt") << QStringLiteral("-is") - << QStringLiteral("-p=") + sidForPackage(d->packageFamilyName); - if (!runElevatedBackgroundProcess(binary, arguments, &d->loopbackServerProcessHandle)) { - qCWarning(lcWinRtRunner) << "Could not start" << binary; - return false; - } - } else { - if (d->loopbackServerProcessHandle != INVALID_HANDLE_VALUE) { - if (!TerminateProcess(d->loopbackServerProcessHandle, 0)) { - qCWarning(lcWinRtRunner) << "Could not terminate loopbackexempt debug session"; - return false; - } - if (!CloseHandle(d->loopbackServerProcessHandle)) { - qCWarning(lcWinRtRunner) << "Could not close loopbackexempt debug session process handle"; - return false; - } - } else { - qCWarning(lcWinRtRunner) << "loopbackexempt debug session could not be found"; - return false; - } - } - return true; -} - -bool AppxLocalEngine::setLoggingRules(const QByteArray &rules) -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - - QDir loggingIniDir(devicePath(QLatin1String("QtProject"))); - if (!loggingIniDir.exists() && !loggingIniDir.mkpath(QStringLiteral("."))) { - qCWarning(lcWinRtRunner) << "Could not create" << loggingIniDir; - return false; - } - QFile loggingIniFile(loggingIniDir.absolutePath().append(QLatin1String("/qtlogging.ini"))); - if (loggingIniFile.exists() && !loggingIniFile.remove()) { - qCWarning(lcWinRtRunner) << loggingIniFile << "already exists."; - return false; - } - if (!loggingIniFile.open(QIODevice::WriteOnly | QIODevice::Text)) { - qCWarning(lcWinRtRunner) << "Could not open" << loggingIniFile << "for writing."; - return false; - } - - QTextStream stream(&loggingIniFile); - stream << "[Rules]\n" << rules; - - return true; -} - - -bool AppxLocalEngine::suspend() -{ - Q_D(AppxLocalEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - HRESULT hr = d->packageDebug->Suspend(wchar(d->packageFullName)); - RETURN_FALSE_IF_FAILED("Failed to suspend application"); - - return true; -} - -bool AppxLocalEngine::waitForFinished(int secs) -{ - Q_D(AppxLocalEngine); - 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); - RETURN_FALSE_IF_FAILED("Failed to get package execution state"); - qCDebug(lcWinRtRunner) << "Current execution state:" << state; - if (state == PES_TERMINATED || state == PES_UNKNOWN) - break; - - ++time; - if ((secs && time > secs) || g_ctrlReceived) { - g_handleCtrl = false; - 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 AppxLocalEngine::stop() -{ - Q_D(AppxLocalEngine); - 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 && !parseExitCode()) { - return false; - } - - if (!d->processHandle || d->exitCode == STILL_ACTIVE) { - HRESULT hr = d->packageDebug->TerminateAllProcesses(wchar(d->packageFullName)); - RETURN_FALSE_IF_FAILED("Failed to terminate package process"); - - if (d->processHandle && !GetExitCodeProcess(d->processHandle, &d->exitCode)) - d->exitCode = UINT_MAX; - } - - return true; -} - -QString AppxLocalEngine::devicePath(const QString &relativePath) const -{ - Q_D(const AppxLocalEngine); - 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 AppxLocalEngine::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).nospace().noquote() - << "Unable to sendFile: " << source.errorString(); - } - - return result; -} - -bool AppxLocalEngine::receiveFile(const QString &deviceFile, const QString &localFile) -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - - // Both files are local, so just reverse the sendFile arguments - return sendFile(deviceFile, localFile); -} - -QString AppxLocalEngine::extensionSdkPath() const -{ - const QByteArray extensionSdkDirRaw = qgetenv("ExtensionSdkDir"); - if (extensionSdkDirRaw.isEmpty()) { - qCWarning(lcWinRtRunner) << "The environment variable ExtensionSdkDir is not set."; - return QString(); - } - return QString::fromLocal8Bit(extensionSdkDirRaw); -} - -void AppxLocalEnginePrivate::retrieveInstalledPackages() -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - - ComPtr<ABI::Windows::Foundation::Collections::IIterable<Package*>> packages; - HRESULT hr = packageManager->FindPackagesByUserSecurityId(NULL, &packages); - RETURN_VOID_IF_FAILED("Failed to find packages"); - - ComPtr<ABI::Windows::Foundation::Collections::IIterator<Package*>> pkgit; - hr = packages->First(&pkgit); - RETURN_VOID_IF_FAILED("Failed to get package iterator"); - - boolean hasCurrent; - hr = pkgit->get_HasCurrent(&hasCurrent); - while (SUCCEEDED(hr) && hasCurrent) { - ComPtr<IPackage> pkg; - hr = pkgit->get_Current(&pkg); - RETURN_VOID_IF_FAILED("Failed to get current package"); - - ComPtr<IPackageId> pkgId; - hr = pkg->get_Id(&pkgId); - RETURN_VOID_IF_FAILED("Failed to get package id"); - - HString name; - hr = pkgId->get_Name(name.GetAddressOf()); - RETURN_VOID_IF_FAILED("Failed retrieve package name"); - - ProcessorArchitecture architecture; - if (packageArchitecture == ProcessorArchitecture_Neutral) { - architecture = packageArchitecture; - } else { - hr = pkgId->get_Architecture(&architecture); - RETURN_VOID_IF_FAILED("Failed to retrieve package architecture"); - } - - const QString pkgName = QStringFromHString(name.Get()); - qCDebug(lcWinRtRunner) << "found installed package" << pkgName; - - if (architecture == packageArchitecture) - installedPackages.insert(pkgName); - - hr = pkgit->MoveNext(&hasCurrent); - } -} diff --git a/src/winrtrunner/appxlocalengine.h b/src/winrtrunner/appxlocalengine.h deleted file mode 100644 index 0049b6ba4..000000000 --- a/src/winrtrunner/appxlocalengine.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef APPXLOCALENGINE_H -#define APPXLOCALENGINE_H - -#include "appxengine.h" -#include "runner.h" - -#include <QtCore/QScopedPointer> -#include <QtCore/QString> - -QT_USE_NAMESPACE - -class AppxLocalEnginePrivate; -class AppxLocalEngine : public AppxEngine -{ -public: - static bool canHandle(Runner *runner); - static RunnerEngine *create(Runner *runner); - static QStringList deviceNames(); - - bool install(bool removeFirst = false) override; - bool remove() override; - bool start() override; - bool enableDebugging(const QString &debuggerExecutable, - const QString &debuggerArguments) override; - bool disableDebugging() override; - bool setLoopbackExemptClientEnabled(bool enabled) override; - bool setLoopbackExemptServerEnabled(bool enabled) override; - bool setLoggingRules(const QByteArray &rules) override; - bool suspend() override; - bool waitForFinished(int secs) override; - bool stop() override; - - QString devicePath(const QString &relativePath) const override; - bool sendFile(const QString &localFile, const QString &deviceFile) override; - bool receiveFile(const QString &deviceFile, const QString &localFile) override; - -private: - explicit AppxLocalEngine(Runner *runner); - ~AppxLocalEngine(); - - QString extensionSdkPath() const override; - bool installPackage(IAppxManifestReader *reader, const QString &filePath) override; - - bool parseExitCode(); - friend struct QScopedPointerDeleter<AppxLocalEngine>; - Q_DECLARE_PRIVATE(AppxLocalEngine) -}; - -#endif // APPXLOCALENGINE_H diff --git a/src/winrtrunner/appxphoneengine.cpp b/src/winrtrunner/appxphoneengine.cpp deleted file mode 100644 index 39c3b2712..000000000 --- a/src/winrtrunner/appxphoneengine.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "appxphoneengine.h" -#include "appxengine_p.h" - -#include <QtCore/QDir> -#include <QtCore/QDirIterator> -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtCore/QHash> -#include <QtCore/QUuid> -#include <QtCore/QLoggingCategory> -#include <QtCore/QDateTime> - -#include <comdef.h> -#include <psapi.h> - -#include <ShlObj.h> -#include <Shlwapi.h> -#include <wsdevlicensing.h> -#include <AppxPackaging.h> -#include <xmllite.h> -#include <wrl.h> -#include <windows.applicationmodel.h> -#include <windows.management.deployment.h> - -using namespace Microsoft::WRL; -using namespace Microsoft::WRL::Wrappers; -using namespace ABI::Windows::Foundation; -using namespace ABI::Windows::Management::Deployment; -using namespace ABI::Windows::ApplicationModel; -using namespace ABI::Windows::System; - -// From Microsoft.Phone.Tools.Deploy assembly -namespace PhoneTools { - enum DeploymentOptions - { - None = 0, - PA = 1, - Debug = 2, - Infused = 4, - Lightup = 8, - Enterprise = 16, - Sideload = 32, - TypeMask = 255, - UninstallDisabled = 256, - SkipUpdateAppInForeground = 512, - DeleteXap = 1024, - InstallOnSD = 65536, - OptOutSD = 131072 - }; - enum PackageType - { - UnknownAppx = 0, - Main = 1, - Framework = 2, - Resource = 4, - Bundle = 8, - Xap = 0 - }; -} - -QT_USE_NAMESPACE - -#include <corecon.h> -#include <ccapi_12.h> -Q_GLOBAL_STATIC_WITH_ARGS(CoreConServer, coreConServer, (12)) - -#undef RETURN_IF_FAILED -#define RETURN_IF_FAILED(msg, ret) \ - if (FAILED(hr)) { \ - qCWarning(lcWinRtRunner).nospace() << msg << ": 0x" << QByteArray::number(hr, 16).constData() \ - << ' ' << coreConServer->formatError(hr); \ - ret; \ - } - -// 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; -} - -class AppxPhoneEnginePrivate : public AppxEnginePrivate -{ -public: - QString productId; - - ComPtr<ICcConnection> connection; - CoreConDevice *device; - QSet<QString> dependencies; -}; - -static ProcessorArchitecture toProcessorArchitecture(APPX_PACKAGE_ARCHITECTURE appxArch) -{ - switch (appxArch) { - case APPX_PACKAGE_ARCHITECTURE_X86: - return ProcessorArchitecture_X86; - case APPX_PACKAGE_ARCHITECTURE_ARM: - return ProcessorArchitecture_Arm; - case APPX_PACKAGE_ARCHITECTURE_X64: - return ProcessorArchitecture_X64; - case APPX_PACKAGE_ARCHITECTURE_NEUTRAL: - // fall-through intended - default: - return ProcessorArchitecture_Neutral; - } -} - -static bool getPhoneProductId(IStream *manifestStream, QString *productId) -{ - // Read out the phone product ID (not supported by AppxManifestReader) - ComPtr<IXmlReader> xmlReader; - HRESULT hr = CreateXmlReader(IID_PPV_ARGS(&xmlReader), NULL); - RETURN_FALSE_IF_FAILED("Failed to create XML reader"); - - hr = xmlReader->SetInput(manifestStream); - RETURN_FALSE_IF_FAILED("Failed to set manifest as input"); - - while (!xmlReader->IsEOF()) { - XmlNodeType nodeType; - hr = xmlReader->Read(&nodeType); - RETURN_FALSE_IF_FAILED("Failed to read next node in manifest"); - if (nodeType == XmlNodeType_Element) { - PCWSTR uri; - hr = xmlReader->GetNamespaceUri(&uri, NULL); - RETURN_FALSE_IF_FAILED("Failed to read namespace URI of current node"); - if (wcscmp(uri, L"http://schemas.microsoft.com/appx/2014/phone/manifest") == 0) { - PCWSTR localName; - hr = xmlReader->GetLocalName(&localName, NULL); - RETURN_FALSE_IF_FAILED("Failed to get local name of current node"); - if (wcscmp(localName, L"PhoneIdentity") == 0) { - hr = xmlReader->MoveToAttributeByName(L"PhoneProductId", NULL); - if (hr == S_FALSE) - continue; - RETURN_FALSE_IF_FAILED("Failed to seek to the PhoneProductId attribute"); - PCWSTR phoneProductId; - UINT length; - hr = xmlReader->GetValue(&phoneProductId, &length); - RETURN_FALSE_IF_FAILED("Failed to read the value of the PhoneProductId attribute"); - *productId = QLatin1Char('{') + QString::fromWCharArray(phoneProductId, length) + QLatin1Char('}'); - return true; - } - } - } - } - return false; -} - -bool AppxPhoneEngine::canHandle(Runner *runner) -{ - return getManifestFile(runner->app()); -} - -RunnerEngine *AppxPhoneEngine::create(Runner *runner) -{ - QScopedPointer<AppxPhoneEngine> engine(new AppxPhoneEngine(runner)); - if (engine->d_ptr->hasFatalError) - return 0; - - return engine.take(); -} - -QStringList AppxPhoneEngine::deviceNames() -{ - QStringList deviceNames; - - const QList<CoreConDevice *> devices = coreConServer->devices(); - for (const CoreConDevice *device : devices) - deviceNames.append(device->name()); - return deviceNames; -} - -AppxPhoneEngine::AppxPhoneEngine(Runner *runner) - : AppxEngine(runner, new AppxPhoneEnginePrivate) -{ - Q_D(AppxPhoneEngine); - if (d->hasFatalError) - return; - d->hasFatalError = true; - - ComPtr<IStream> manifestStream; - HRESULT hr; - if (d->manifestReader) { - hr = d->manifestReader->GetStream(&manifestStream); - RETURN_VOID_IF_FAILED("Failed to query manifest stream from manifest reader."); - } else { - hr = SHCreateStreamOnFile(wchar(d->manifest), STGM_READ, &manifestStream); - RETURN_VOID_IF_FAILED("Failed to open manifest stream"); - } - - if (!getPhoneProductId(manifestStream.Get(), &d->productId)) { - qCWarning(lcWinRtRunner) << "Failed to read phone product ID from the manifest."; - return; - } - - if (!coreConServer->initialize()) { - while (!coreConServer.exists()) - Sleep(1); - } - - // Get the device - d->device = coreConServer->devices().value(d->runner->deviceIndex()); - if (!d->device || !d->device->handle()) { - d->hasFatalError = true; - qCWarning(lcWinRtRunner) << "Invalid device specified:" << d->runner->deviceIndex(); - return; - } - - - - // Set a break handler for gracefully exiting from long-running operations - SetConsoleCtrlHandler(&ctrlHandler, true); - d->hasFatalError = false; -} - -AppxPhoneEngine::~AppxPhoneEngine() -{ -} - -QString AppxPhoneEngine::extensionSdkPath() const -{ - const QByteArray extensionSdkDirRaw = qgetenv("ExtensionSdkDir"); - if (extensionSdkDirRaw.isEmpty()) { - qCWarning(lcWinRtRunner) << "The environment variable ExtensionSdkDir is not set."; - return QString(); - } - return QString::fromLocal8Bit(extensionSdkDirRaw); -} - -bool AppxPhoneEngine::installPackage(IAppxManifestReader *reader, const QString &filePath) -{ - Q_D(AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__ << filePath; - - ComPtr<ICcConnection3> connection; - HRESULT hr = d->connection.As(&connection); - RETURN_FALSE_IF_FAILED("Failed to obtain connection object"); - - ComPtr<IStream> manifestStream; - hr = reader->GetStream(&manifestStream); - RETURN_FALSE_IF_FAILED("Failed to get manifest stream from reader"); - - QString productIdString; - if (!getPhoneProductId(manifestStream.Get(), &productIdString)) { - qCWarning(lcWinRtRunner) << "Failed to get phone product ID from manifest reader."; - return false; - } - _bstr_t productId(wchar(productIdString)); - - VARIANT_BOOL isInstalled; - hr = connection->IsApplicationInstalled(productId, &isInstalled); - RETURN_FALSE_IF_FAILED("Failed to determine if package is installed"); - if (isInstalled) { - qCDebug(lcWinRtRunner) << "Package" << productIdString << "is already installed"; - return true; - } - - ComPtr<IAppxManifestProperties> properties; - hr = reader->GetProperties(&properties); - RETURN_FALSE_IF_FAILED("Failed to get manifest properties"); - - BOOL isFramework; - hr = properties->GetBoolValue(L"Framework", &isFramework); - RETURN_FALSE_IF_FAILED("Failed to determine whether package is a framework"); - - const QString deploymentFlags = QString::number(isFramework ? PhoneTools::None : PhoneTools::Sideload); - _bstr_t deploymentFlagsAsGenre(wchar(deploymentFlags)); - const QString packageType = QString::number(isFramework ? PhoneTools::Framework : PhoneTools::Main); - _bstr_t packageTypeAsIconPath(wchar(packageType)); - _bstr_t packagePath(wchar(QDir::toNativeSeparators(filePath))); - hr = connection->InstallApplication(productId, productId, deploymentFlagsAsGenre, - packageTypeAsIconPath, packagePath); - if (hr == 0x80073d06) { // No public E_* macro available - qCWarning(lcWinRtRunner) << "Found a newer version of " << filePath - << " on the target device, skipping..."; - } else { - RETURN_FALSE_IF_FAILED("Failed to install the package"); - } - - return true; -} - -bool AppxPhoneEngine::connect() -{ - Q_D(AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - HRESULT hr; - if (!d->connection) { - _bstr_t connectionName; - hr = static_cast<ICcServer *>(coreConServer->handle())->GetConnection( - static_cast<ICcDevice *>(d->device->handle()), 5000, NULL, connectionName.GetAddress(), &d->connection); - RETURN_FALSE_IF_FAILED("Failed to connect to device"); - } - - VARIANT_BOOL connected; - hr = d->connection->IsConnected(&connected); - RETURN_FALSE_IF_FAILED("Failed to determine connection state"); - if (connected) - return true; - - hr = d->connection->ConnectDevice(); - RETURN_FALSE_IF_FAILED("Failed to connect to device"); - - return true; -} - -bool AppxPhoneEngine::install(bool removeFirst) -{ - Q_D(AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - if (!connect()) - return false; - - ComPtr<ICcConnection3> connection; - HRESULT hr = d->connection.As(&connection); - RETURN_FALSE_IF_FAILED("Failed to obtain connection object"); - - _bstr_t productId(wchar(d->productId)); - VARIANT_BOOL isInstalled; - hr = connection->IsApplicationInstalled(productId, &isInstalled); - RETURN_FALSE_IF_FAILED("Failed to obtain the installation status"); - if (isInstalled) { - if (!removeFirst) - return true; - if (!remove()) - return false; - } - - if (!installDependencies()) - return false; - - const QDir base = QFileInfo(d->executable).absoluteDir(); - const bool existingPackage = d->runner->app().endsWith(QLatin1String(".appx")); - const QString packageFileName = existingPackage - ? d->runner->app() - : base.absoluteFilePath(d->packageFamilyName + QStringLiteral(".appx")); - if (!existingPackage) { - if (!createPackage(packageFileName)) - return false; - - if (!sign(packageFileName)) - return false; - } else { - qCDebug(lcWinRtRunner) << "Installing existing package."; - } - - return installPackage(d->manifestReader.Get(), packageFileName); -} - -bool AppxPhoneEngine::remove() -{ - Q_D(AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - if (!connect()) - return false; - - if (!d->connection) - return false; - - ComPtr<ICcConnection3> connection; - HRESULT hr = d->connection.As(&connection); - RETURN_FALSE_IF_FAILED("Failed to obtain connection object"); - - _bstr_t app = wchar(d->productId); - hr = connection->UninstallApplication(app); - RETURN_FALSE_IF_FAILED("Failed to uninstall the package"); - - return true; -} - -bool AppxPhoneEngine::start() -{ - Q_D(AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - if (!connect()) - return false; - - if (!d->runner->arguments().isEmpty()) - qCWarning(lcWinRtRunner) << "Arguments are not currently supported for Windows Phone Appx packages."; - - ComPtr<ICcConnection3> connection; - HRESULT hr = d->connection.As(&connection); - RETURN_FALSE_IF_FAILED("Failed to cast connection object"); - - _bstr_t productId(wchar(d->productId)); - DWORD pid; - hr = connection->LaunchApplication(productId, &pid); - RETURN_FALSE_IF_FAILED("Failed to start the package"); - - d->pid = pid; - return true; -} - -bool AppxPhoneEngine::enableDebugging(const QString &debuggerExecutable, const QString &debuggerArguments) -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - Q_UNUSED(debuggerExecutable); - Q_UNUSED(debuggerArguments); - return false; -} - -bool AppxPhoneEngine::disableDebugging() -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - return false; -} - -bool AppxPhoneEngine::setLoopbackExemptClientEnabled(bool) -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - return false; -} - -bool AppxPhoneEngine::setLoopbackExemptServerEnabled(bool) -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - return false; -} - -bool AppxPhoneEngine::setLoggingRules(const QByteArray &) -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - return false; -} - -bool AppxPhoneEngine::suspend() -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - return false; -} - -bool AppxPhoneEngine::waitForFinished(int secs) -{ - Q_D(AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - ComPtr<ICcConnection3> connection; - HRESULT hr = d->connection.As(&connection); - RETURN_FALSE_IF_FAILED("Failed to cast connection"); - - g_handleCtrl = true; - int time = 0; - forever { - ++time; - if ((secs && time > secs) || g_ctrlReceived) { - g_handleCtrl = false; - return false; - } - - Sleep(1000); // Wait one second between checks - qCDebug(lcWinRtRunner) << "Waiting for app to quit - msecs to go: " << secs - time; - } - g_handleCtrl = false; - return true; -} - -bool AppxPhoneEngine::stop() -{ - qCDebug(lcWinRtRunner) << __FUNCTION__; - - if (!connect()) - return false; - -#if 0 // This does not actually stop the app - QTBUG-41946 - Q_D(AppxPhoneEngine); - ComPtr<ICcConnection3> connection; - HRESULT hr = d->connection.As(&connection); - RETURN_FALSE_IF_FAILED("Failed to cast connection object"); - - _bstr_t productId(wchar(d->productId)); - hr = connection->TerminateRunningApplicationInstances(productId); - RETURN_FALSE_IF_FAILED("Failed to stop the package"); - - return true; -#else - return remove(); -#endif -} - -QString AppxPhoneEngine::devicePath(const QString &relativePath) const -{ - Q_D(const AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - return QStringLiteral("%FOLDERID_APPID_ISOROOT%\\") + d->productId - + QStringLiteral("\\%LOCL%\\") + relativePath; -} - -bool AppxPhoneEngine::sendFile(const QString &localFile, const QString &deviceFile) -{ - Q_D(const AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - HRESULT hr = d->connection->SendFile(_bstr_t(wchar(localFile)), _bstr_t(wchar(deviceFile)), - CREATE_ALWAYS, NULL); - RETURN_FALSE_IF_FAILED("Failed to send the file"); - - return true; -} - -bool AppxPhoneEngine::receiveFile(const QString &deviceFile, const QString &localFile) -{ - Q_D(const AppxPhoneEngine); - qCDebug(lcWinRtRunner) << __FUNCTION__; - - HRESULT hr = d->connection->ReceiveFile(_bstr_t(wchar(deviceFile)), - _bstr_t(wchar(localFile)), uint(2)); - RETURN_FALSE_IF_FAILED("Failed to receive the file"); - - return true; -} diff --git a/src/winrtrunner/appxphoneengine.h b/src/winrtrunner/appxphoneengine.h deleted file mode 100644 index b462e797f..000000000 --- a/src/winrtrunner/appxphoneengine.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef APPXPHONEENGINE_H -#define APPXPHONEENGINE_H - -#include "appxengine.h" -#include "runnerengine.h" -#include "runner.h" - -#include <QtCore/QScopedPointer> - -QT_USE_NAMESPACE - -class AppxPhoneEnginePrivate; -class AppxPhoneEngine : public AppxEngine -{ -public: - static bool canHandle(Runner *runner); - static RunnerEngine *create(Runner *runner); - static QStringList deviceNames(); - - bool install(bool removeFirst = false) override; - bool remove() override; - bool start() override; - bool enableDebugging(const QString &debuggerExecutable, - const QString &debuggerArguments) override; - bool disableDebugging() override; - bool setLoopbackExemptClientEnabled(bool enabled) override; - bool setLoopbackExemptServerEnabled(bool enabled) override; - bool setLoggingRules(const QByteArray &rules) override; - bool suspend() override; - bool waitForFinished(int secs) override; - bool stop() override; - - QString devicePath(const QString &relativePath) const override; - bool sendFile(const QString &localFile, const QString &deviceFile) override; - bool receiveFile(const QString &deviceFile, const QString &localFile) override; - -private: - explicit AppxPhoneEngine(Runner *runner); - ~AppxPhoneEngine(); - - QString extensionSdkPath() const; - bool installPackage(IAppxManifestReader *reader, const QString &filePath) override; - - bool connect(); - - friend struct QScopedPointerDeleter<AppxPhoneEngine>; - Q_DECLARE_PRIVATE(AppxPhoneEngine) -}; - -#endif // APPXPHONEENGINE_H diff --git a/src/winrtrunner/main.cpp b/src/winrtrunner/main.cpp deleted file mode 100644 index 77cdbb13f..000000000 --- a/src/winrtrunner/main.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtCore/QCommandLineParser> -#include <QtCore/QCoreApplication> -#include <QtCore/QDir> -#include <QtCore/QRegularExpression> -#include <QtCore/QStringList> -#include <QtCore/QMap> -#include <QtCore/QLoggingCategory> - -#include <iostream> - -#include "runner.h" - -QT_USE_NAMESPACE - -int main(int argc, char *argv[]) -{ - // If logging rules are set via env variable, we pass these to the application we are running. - // winrtrunner behaves different from other applications in the regard that its logging rules - // have to be enabled explicitly. Setting "*=true" will not enable extended logging. Reason is - // CI setting "*=true" if an auto test fails and additional winrtrunner output might just - // confuse users. - const QByteArray loggingRules = qgetenv("QT_LOGGING_RULES"); - const QList<QByteArray> rules = loggingRules.split(';'); - QRegularExpression runnerExp(QLatin1String("^qt\\.winrtrunner.*\\s*=\\s*true\\s*$")); - bool runnerRuleFound = false; - for (const QByteArray &rule : rules) { - if (runnerExp.match(QLatin1String(rule)).hasMatch()) { - runnerRuleFound = true; - break; - } - } - if (!runnerRuleFound) - qunsetenv("QT_LOGGING_RULES"); - QCoreApplication a(argc, argv); - QCommandLineParser parser; - parser.setApplicationDescription(QLatin1String("winrtrunner installs, runs, and collects test " - "results for packages made with Qt.")); - parser.addPositionalArgument(QStringLiteral("package [arguments]"), - QLatin1String("The executable or package manifest to act upon. " - "Arguments after the package name will be passed " - "to the application when it starts.")); - - QCommandLineOption testOption(QStringLiteral("test"), - QLatin1String("Install, start, collect output, stop (if needed), " - "and uninstall the package. This is the " - "default action of winrtrunner.")); - parser.addOption(testOption); - - QCommandLineOption startOption(QStringLiteral("start"), - QLatin1String("Start the package. The package is installed if " - "it is not already installed. Pass --install to " - "force reinstallation.")); - parser.addOption(startOption); - - QCommandLineOption debugOption(QStringLiteral("debug"), - QLatin1String("Start the package with the debugger attached. " - "The package is installed if it is not already " - "installed. Pass --install to force " - "reinstallation."), - QLatin1String("debugger")); - parser.addOption(debugOption); - - QCommandLineOption debuggerArgumentsOption(QStringLiteral("debugger-arguments"), - QLatin1String("Arguments that are passed to the " - "debugger when --debug is used. If no " - "debugger was provided this option is " - "ignored."), - QLatin1String("arguments")); - parser.addOption(debuggerArgumentsOption); - - QCommandLineOption suspendOption(QStringLiteral("suspend"), - QLatin1String("Suspend a running package. When combined " - "with --stop or --test, the app will be " - "suspended before being terminated.")); - parser.addOption(suspendOption); - - QCommandLineOption stopOption(QStringLiteral("stop"), - QLatin1String("Terminate a running package. Can be be " - "combined with --start and --suspend.")); - parser.addOption(stopOption); - - QCommandLineOption waitOption(QStringLiteral("wait"), - QLatin1String("If the package is running, waits the given " - "number of seconds before continuing to the next " - "task. Passing 0 causes the runner to wait " - "indefinitely."), - QStringLiteral("seconds")); - parser.addOption(waitOption); - - QCommandLineOption installOption(QStringLiteral("install"), - QStringLiteral("(Re)installs the package.")); - parser.addOption(installOption); - - QCommandLineOption removeOption(QStringLiteral("remove"), - QStringLiteral("Uninstalls the package.")); - parser.addOption(removeOption); - - QCommandLineOption deviceOption(QStringLiteral("device"), - QLatin1String("Specifies the device to target as a device name " - "or index. Use --list-devices to find available " - "devices. The default device is the first device " - "found for the active run profile."), - QStringLiteral("name|index")); - parser.addOption(deviceOption); - - QCommandLineOption profileOption(QStringLiteral("profile"), - QStringLiteral("Force a particular run profile."), - QStringLiteral("name")); - parser.addOption(profileOption); - - QCommandLineOption listDevicesOption(QStringLiteral("list-devices"), - QLatin1String("List the available devices " - "(for use with --device).")); - parser.addOption(listDevicesOption); - - QCommandLineOption verbosityOption(QStringLiteral("verbose"), - QLatin1String("The verbosity level of the message output " - "(0 - silent, 1 - info, 2 - debug). Defaults to 1."), - QStringLiteral("level"), QStringLiteral("1")); - parser.addOption(verbosityOption); - - QCommandLineOption ignoreErrorsOption(QStringLiteral("ignore-errors"), - QStringLiteral("Always exit with code 0, regardless of the error state.")); - parser.addOption(ignoreErrorsOption); - - QCommandLineOption loopbackExemptOption(QStringLiteral("loopbackexempt"), - QLatin1String("Enables localhost communication for clients," - "servers or both. Adding this possibility " - "for servers needs elevated rights and " - "might ask for these in a dialog." - "Possible values: client, server, clientserver"), - QStringLiteral("mode")); - parser.addOption(loopbackExemptOption); - - parser.addHelpOption(); - parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - QStringList arguments = QCoreApplication::arguments(); - parser.parse(arguments); - - QStringList filterRules = QStringList() // Default logging rules - << QStringLiteral("qt.winrtrunner.warning=true") - << QStringLiteral("qt.winrtrunner.critical=true") - << QStringLiteral("qt.winrtrunner.app=true"); - if (parser.isSet(verbosityOption)) { - bool ok; - uint verbosity = parser.value(verbosityOption).toUInt(&ok); - if (!ok || verbosity > 2) { - qCCritical(lcWinRtRunner) << "Incorrect value specified for verbosity."; - parser.showHelp(1); - } - switch (verbosity) { - case 2: // Enable debug print - filterRules.append(QStringLiteral("qt.winrtrunner.debug=true")); - break; - case 1: // Remove warnings - filterRules.removeFirst(); - // fall through - case 0: // Silent - filterRules.removeFirst(); - // fall through - default: // Impossible - break; - } - } - bool loopbackExemptClient = false; - bool loopbackExemptServer = false; - if (parser.isSet(loopbackExemptOption)) { - const QString value = parser.value(loopbackExemptOption); - if (value == QStringLiteral("client")) { - loopbackExemptClient = true; - } else if (value == QStringLiteral("server")) { - loopbackExemptServer = true; - } else if (value == QStringLiteral("clientserver")) { - loopbackExemptClient = true; - loopbackExemptServer = true; - } else { - qCCritical(lcWinRtRunner) << "Incorrect value specified for loopbackexempt."; - parser.showHelp(1); - } - } - QLoggingCategory::setFilterRules(filterRules.join(QLatin1Char('\n'))); - - if (parser.isSet(listDevicesOption)) { - std::wcout << "Available devices:\n"; - const QMap<QString, QStringList> deviceNames = Runner::deviceNames(); - for (auto it = deviceNames.cbegin(), end = deviceNames.cend(); it != end; ++it) { - std::wcout << reinterpret_cast<const wchar_t *>(it.key().utf16()) << ":\n"; - int index = 0; - for (const QString &device : it.value()) { - std::wcout << " " << index++ << ' ' - << reinterpret_cast<const wchar_t *>(device.utf16()) << '\n'; - } - } - std::wcout << std::endl; - return 0; - } - - // Process front-end args - if (parser.positionalArguments().count() < 1) - parser.showHelp(parser.isSet(QStringLiteral("help")) ? 0 : 1); - const QString app = parser.positionalArguments().first(); - const int appArgsPos = arguments.indexOf(app) + 1; - const QStringList mainArgs = arguments.mid(0, appArgsPos); - QStringList appArgs = arguments.mid(appArgsPos); - parser.process(mainArgs); - - // Exit codes: - // 1 - Bad arguments - // 2 - Bad package or no backend available - // 3 - Installation failed - // 4 - Removal failed - // 5 - Start failed - // 6 - Suspend failed - // 7 - Stop failed - // 8 - Test setup failed - // 9 - Test results retrieval failed - // 10 - Enabling debugging failed - // In "test" mode, the exit code of the app is returned - - bool ignoreErrors = parser.isSet(ignoreErrorsOption); - bool testEnabled = parser.isSet(testOption); - bool startEnabled = testEnabled || parser.isSet(startOption) || parser.isSet(debugOption); - bool suspendEnabled = parser.isSet(suspendOption); - bool waitEnabled = testEnabled || parser.isSet(waitOption); - bool stopEnabled = !testEnabled && parser.isSet(stopOption); // test and stop are mutually exclusive - bool installEnabled = testEnabled || startEnabled || parser.isSet(installOption); - bool removeBeforeInstall = testEnabled || parser.isSet(installOption); - bool removeEnabled = testEnabled || parser.isSet(removeOption); - // Default to test mode if no conflicting arguments were passed - if (!testEnabled && !installEnabled && !startEnabled && !stopEnabled && !suspendEnabled && !removeEnabled) - testEnabled = installEnabled = removeBeforeInstall = startEnabled = waitEnabled = stopEnabled = removeEnabled = true; - - int waitTime = parser.value(waitOption).toInt(); - if (!waitTime && testEnabled) - waitTime = 300; // The maximum wait period for test cases is 300 seconds (5 minutes) - - // Set up runner - Runner runner(app, appArgs, parser.value(profileOption), parser.value(deviceOption)); - if (!runner.isValid()) - return ignoreErrors ? 0 : 2; - - if (testEnabled && !runner.setupTest()) { - qCDebug(lcWinRtRunner) << "Test setup failed, exiting with code 8."; - return ignoreErrors ? 0 : 8; - } - - if (installEnabled && !runner.install(removeBeforeInstall)) { - qCDebug(lcWinRtRunner) << "Installation failed, exiting with code 3."; - return ignoreErrors ? 0 : 3; - } - - if (loopbackExemptClient && !runner.setLoopbackExemptClientEnabled(true)) { - qCDebug(lcWinRtRunner) << "Could not enable loopback exemption for client, " - "exiting with code 3."; - return ignoreErrors ? 0 : 3; - } - - if (loopbackExemptServer && !runner.setLoopbackExemptServerEnabled(true)) { - qCDebug(lcWinRtRunner) << "Could not enable loopback exemption for server, " - "exiting with code 3."; - return ignoreErrors ? 0 : 3; - } - - if (!loggingRules.isNull() && !runner.setLoggingRules(loggingRules)) { - qCDebug(lcWinRtRunner) << "Could not set logging rules, exiting with code 3."; - return ignoreErrors ? 0 : 3; - } - - if (parser.isSet(debugOption)) { - const QString &debuggerExecutable = parser.value(debugOption); - const QString &debuggerArguments = parser.value(debuggerArgumentsOption); - qCDebug(lcWinRtRunner) << "Debugger: " << debuggerExecutable; - qCDebug(lcWinRtRunner) << "Debugger Options: " << debuggerArguments; - if (debuggerExecutable.isEmpty() - || !runner.enableDebugging(debuggerExecutable, debuggerArguments)) { - qCDebug(lcWinRtRunner) << "Failed to enable debugging, exiting with code 10."; - return ignoreErrors ? 0 : 10; - } - } - - bool startFailed = startEnabled && !runner.start(); - - if (parser.isSet(debugOption) && !runner.disableDebugging()) - qCDebug(lcWinRtRunner) << "Failed to disable debugging"; - - if (startFailed) { - qCDebug(lcWinRtRunner) << "Start failed, exiting with code 5."; - return ignoreErrors ? 0 : 5; - } - - qint64 pid = runner.pid(); - if (pid != -1) - qCWarning(lcWinRtRunner) << "App started with process ID" << pid; - - if (waitEnabled) - runner.wait(waitTime); - - if (loopbackExemptClient) - runner.setLoopbackExemptClientEnabled(false); - - if (loopbackExemptServer) - runner.setLoopbackExemptServerEnabled(false); - - if (suspendEnabled && !runner.suspend()) { - qCDebug(lcWinRtRunner) << "Suspend failed, exiting with code 6."; - return ignoreErrors ? 0 : 6; - } - - if (stopEnabled && !runner.stop()) { - qCDebug(lcWinRtRunner) << "Stop failed, exiting with code 7."; - return ignoreErrors ? 0 : 7; - } - - if (testEnabled && !runner.collectTest()) { - qCDebug(lcWinRtRunner) << "Collect test failed, exiting with code 9."; - return ignoreErrors ? 0 : 9; - } - - if (removeEnabled && !runner.remove()) { - qCDebug(lcWinRtRunner) << "Remove failed, exiting with code 4."; - return ignoreErrors ? 0 : 4; - } - - if (stopEnabled) { - int exitCode = runner.exitCode(); - if (exitCode == -1) - return 0; // Exit code unknown; not necessarily an error - qCWarning(lcWinRtRunner) << "App exited with code" << exitCode; - return ignoreErrors ? 0 : exitCode; - } - - return 0; -} diff --git a/src/winrtrunner/runner.cpp b/src/winrtrunner/runner.cpp deleted file mode 100644 index d115b584b..000000000 --- a/src/winrtrunner/runner.cpp +++ /dev/null @@ -1,384 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "runner.h" - -#include "runnerengine.h" - -#ifndef RTRUNNER_NO_APPXPHONE -#include "appxphoneengine.h" -#endif -#ifndef RTRUNNER_NO_APPXLOCAL -#include "appxlocalengine.h" -#endif - -#include <QtCore/QDir> -#include <QtCore/QStandardPaths> -#include <QtCore/QLoggingCategory> - -QT_USE_NAMESPACE - -Q_LOGGING_CATEGORY(lcWinRtRunner, "qt.winrtrunner") -Q_LOGGING_CATEGORY(lcWinRtRunnerApp, "qt.winrtrunner.app") - -class RunnerPrivate -{ -public: - bool isValid; - QString app; - QString manifest; - QStringList arguments; - int deviceIndex; - struct TestPaths { - // File path in application bundle - QString deviceOutputFile; - // temporary output path (if absolute path or stdout (-) was given - QString localOutputFile; - // final output location. Might be equal to localOutputFile or stdout (-) - QString finalOutputFile; - }; - QList<TestPaths> testPaths; - - QString profile; - QScopedPointer<RunnerEngine> engine; - - QString defaultOutputFileName(const QString &format = QString()) - { - QString ret = QFileInfo(engine->executable()).baseName() + QStringLiteral("_output"); - if (!format.isEmpty()) - ret += QLatin1Char('_') + format; - ret += QStringLiteral(".txt"); - return ret; - } -}; - -QMap<QString, QStringList> Runner::deviceNames() -{ - QMap<QString, QStringList> deviceNames; -#ifndef RTRUNNER_NO_APPXLOCAL - deviceNames.insert(QStringLiteral("Appx"), AppxLocalEngine::deviceNames()); -#endif -#ifndef RTRUNNER_NO_APPXPHONE - deviceNames.insert(QStringLiteral("Phone"), AppxPhoneEngine::deviceNames()); -#endif - return deviceNames; -} - -Runner::Runner(const QString &app, const QStringList &arguments, - const QString &profile, const QString &deviceName) - : d_ptr(new RunnerPrivate) -{ - Q_D(Runner); - d->isValid = false; - d->app = app; - d->arguments = arguments; - d->profile = profile; - - bool deviceIndexKnown; - d->deviceIndex = deviceName.toInt(&deviceIndexKnown); -#ifndef RTRUNNER_NO_APPXLOCAL - if (!deviceIndexKnown) { - d->deviceIndex = AppxLocalEngine::deviceNames().indexOf(deviceName); - if (d->deviceIndex < 0) - d->deviceIndex = 0; - } - if ((d->profile.isEmpty() || d->profile.toLower() == QStringLiteral("appx")) - && AppxLocalEngine::canHandle(this)) { - if (RunnerEngine *engine = AppxLocalEngine::create(this)) { - d->engine.reset(engine); - d->isValid = true; - qCWarning(lcWinRtRunner) << "Using the Appx profile."; - return; - } - } -#endif -#ifndef RTRUNNER_NO_APPXPHONE - if (!deviceIndexKnown) { - d->deviceIndex = AppxPhoneEngine::deviceNames().indexOf(deviceName); - if (d->deviceIndex < 0) - d->deviceIndex = 0; - } - if ((d->profile.isEmpty() || d->profile.toLower() == QStringLiteral("appxphone")) - && AppxPhoneEngine::canHandle(this)) { - if (RunnerEngine *engine = AppxPhoneEngine::create(this)) { - d->engine.reset(engine); - d->isValid = true; - qCWarning(lcWinRtRunner) << "Using the AppxPhone profile."; - return; - } - } -#endif - // Place other engines here - - qCWarning(lcWinRtRunner) << "Unable to find a run profile for" << app << "."; -} - -Runner::~Runner() -{ -} - -bool Runner::isValid() const -{ - Q_D(const Runner); - return d->isValid; -} - -QString Runner::app() const -{ - Q_D(const Runner); - return d->app; -} - -QStringList Runner::arguments() const -{ - Q_D(const Runner); - return d->arguments; -} - -int Runner::deviceIndex() const -{ - Q_D(const Runner); - return d->deviceIndex; -} - -bool Runner::install(bool removeFirst) -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->install(removeFirst); -} - -bool Runner::remove() -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->remove(); -} - -bool Runner::start() -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->start(); -} - -bool Runner::enableDebugging(const QString &debuggerExecutable, const QString &debuggerArguments) -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->enableDebugging(debuggerExecutable, debuggerArguments); -} - -bool Runner::disableDebugging() -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->disableDebugging(); -} - -bool Runner::setLoopbackExemptClientEnabled(bool enabled) -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->setLoopbackExemptClientEnabled(enabled); -} - -bool Runner::setLoopbackExemptServerEnabled(bool enabled) -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->setLoopbackExemptServerEnabled(enabled); -} - -bool Runner::setLoggingRules(const QByteArray &rules) -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->setLoggingRules(rules); -} - -bool Runner::suspend() -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->suspend(); -} - -bool Runner::stop() -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->stop(); -} - -bool Runner::wait(int maxWaitTime) -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - return d->engine->waitForFinished(maxWaitTime); -} - -bool Runner::setupTest() -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - // Fix-up output path - int outputIndex = d->arguments.indexOf(QStringLiteral("-o")); - // if no -o was given: Use the default location winrtrunner can read from and write on stdout - if (outputIndex == -1) { - RunnerPrivate::TestPaths out; - out.localOutputFile = d->defaultOutputFileName(); - out.finalOutputFile = QLatin1Char('-'); - d->arguments.append(QStringLiteral("-o")); - out.deviceOutputFile = d->engine->devicePath(out.localOutputFile); - d->arguments.append(out.deviceOutputFile); - d->testPaths.append(out); - } else { - while (outputIndex != -1) { - ++outputIndex; - QString format; - RunnerPrivate::TestPaths out; - if (d->arguments.size() <= outputIndex) { - qCWarning(lcWinRtRunner) << "-o needs an extra parameter specifying the filename and optional format"; - return false; - } - - QString output = d->arguments.at(outputIndex); - int commaIndex = output.indexOf(QLatin1Char(',')); - // -o <name>,<format> - if (commaIndex != -1) { - format = output.mid(commaIndex + 1); - output = output.left(commaIndex); - } - out.finalOutputFile = output; - if (QFileInfo(output).isAbsolute() || output == QLatin1Char('-')) - out.localOutputFile = d->defaultOutputFileName(format); - else - out.localOutputFile = output; - out.deviceOutputFile = d->engine->devicePath(out.localOutputFile); - d->arguments[outputIndex] = out.deviceOutputFile; - if (!format.isEmpty()) - d->arguments[outputIndex] += QLatin1Char(',') + format; - d->testPaths.append(out); - outputIndex = d->arguments.indexOf(QStringLiteral("-o"), outputIndex); - } - } - - // Write a qt.conf to the executable directory - QDir executableDir = QFileInfo(d->engine->executable()).absoluteDir(); - QFile qtConf(executableDir.absoluteFilePath(QStringLiteral("qt.conf"))); - if (!qtConf.exists()) { - if (!qtConf.open(QFile::WriteOnly)) { - qCWarning(lcWinRtRunner) << "Could not open qt.conf for writing."; - return false; - } - qtConf.write(QByteArrayLiteral("[Paths]\nPlugins=/")); - } - - return true; -} - -bool Runner::collectTest() -{ - Q_D(Runner); - Q_ASSERT(d->engine); - - // Fetch test output - for (RunnerPrivate::TestPaths output : d->testPaths) { - if (!d->engine->receiveFile(output.deviceOutputFile, output.localOutputFile)) { - qCWarning(lcWinRtRunner).nospace().noquote() - << "Unable to copy test output file \"" - << QDir::toNativeSeparators(output.deviceOutputFile) - << "\" to local file \"" << QDir::toNativeSeparators(output.localOutputFile) << "\"."; - return false; - } - - if (output.finalOutputFile == QLatin1Char('-')) { - QFile testResults(output.localOutputFile); - if (!testResults.open(QFile::ReadOnly)) { - qCWarning(lcWinRtRunner) << "Unable to read test results:" << testResults.errorString(); - return false; - } - - const QByteArray contents = testResults.readAll(); - std::fputs(contents.constData(), stdout); - } else if (output.localOutputFile != output.finalOutputFile) { - if (QFile::exists(output.finalOutputFile) && !QFile::remove(output.finalOutputFile)) { - qCWarning(lcWinRtRunner) << "Could not remove file" << output.finalOutputFile; - return false; - } - if (!QFile(output.localOutputFile).copy(output.finalOutputFile)) { - qCWarning(lcWinRtRunner) << "Could not copy intermediate file" << output.localOutputFile - << "to final destination" << output.finalOutputFile; - return false; - } - } - } - return true; -} - -qint64 Runner::pid() -{ - Q_D(Runner); - if (!d->engine) - return -1; - - return d->engine->pid(); -} - -int Runner::exitCode() -{ - Q_D(Runner); - if (!d->engine) - return -1; - - return d->engine->exitCode(); -} diff --git a/src/winrtrunner/runner.h b/src/winrtrunner/runner.h deleted file mode 100644 index 00b251be8..000000000 --- a/src/winrtrunner/runner.h +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef RUNNER_H -#define RUNNER_H - -#include <QtCore/QString> -#include <QtCore/QStringList> -#include <QtCore/QMap> -#include <QtCore/QScopedPointer> -#include <QtCore/QLoggingCategory> - -QT_USE_NAMESPACE - -class RunnerPrivate; -class Runner -{ -public: - static QMap<QString, QStringList> deviceNames(); - - Runner(const QString &app, const QStringList &arguments, const QString &profile = QString(), - const QString &device = QString()); - ~Runner(); - - bool isValid() const; - QString app() const; - QStringList arguments() const; - int deviceIndex() const; - - bool install(bool removeFirst = false); - bool remove(); - bool start(); - bool enableDebugging(const QString &debuggerExecutable, const QString &debuggerArguments); - bool disableDebugging(); - bool setLoopbackExemptClientEnabled(bool enabled); - bool setLoopbackExemptServerEnabled(bool enabled); - bool setLoggingRules(const QByteArray &rules); - bool suspend(); - bool stop(); - bool wait(int maxWaitTime = 0); - bool setupTest(); - bool collectTest(); - qint64 pid(); - int exitCode(); - -private: - QScopedPointer<RunnerPrivate> d_ptr; - Q_DECLARE_PRIVATE(Runner) -}; - -Q_DECLARE_LOGGING_CATEGORY(lcWinRtRunner) -Q_DECLARE_LOGGING_CATEGORY(lcWinRtRunnerApp) - -#endif // RUNNER_H diff --git a/src/winrtrunner/runnerengine.h b/src/winrtrunner/runnerengine.h deleted file mode 100644 index 44565c46c..000000000 --- a/src/winrtrunner/runnerengine.h +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef RUNNERENGINE_H -#define RUNNERENGINE_H - -#include <QtCore/QString> - -QT_USE_NAMESPACE - -class RunnerEngine -{ -public: - virtual ~RunnerEngine() { } - virtual bool install(bool removeFirst = false) = 0; - virtual bool remove() = 0; - virtual bool start() = 0; - virtual bool enableDebugging(const QString &debugger, const QString &debuggerArguments) = 0; - virtual bool disableDebugging() = 0; - virtual bool setLoopbackExemptClientEnabled(bool enabled) = 0; - virtual bool setLoopbackExemptServerEnabled(bool enabled) = 0; - virtual bool setLoggingRules(const QByteArray &rules) = 0; - virtual bool suspend() = 0; - virtual bool waitForFinished(int secs) = 0; - virtual bool stop() = 0; - virtual qint64 pid() const = 0; - virtual int exitCode() const = 0; - virtual QString executable() const = 0; - virtual QString devicePath(const QString &relativePath) const = 0; - virtual bool sendFile(const QString &localFile, const QString &deviceFile) = 0; - virtual bool receiveFile(const QString &deviceFile, const QString &localFile) = 0; -}; - -#endif // RUNNERENGINE_H diff --git a/src/winrtrunner/winrtrunner.pro b/src/winrtrunner/winrtrunner.pro deleted file mode 100644 index fb0d58e6e..000000000 --- a/src/winrtrunner/winrtrunner.pro +++ /dev/null @@ -1,31 +0,0 @@ -include($$OUT_PWD/../../src/global/qttools-config.pri) -QT_FOR_CONFIG += tools-private -requires(qtConfig(winrtrunner)) - -option(host_build) -CONFIG += force_bootstrap - -DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII WINRT_LIBRARY - -SOURCES += \ - main.cpp \ - runner.cpp \ - appxengine.cpp \ - appxlocalengine.cpp \ - appxphoneengine.cpp - -HEADERS += \ - runner.h \ - runnerengine.h \ - appxengine.h \ - appxengine_p.h \ - appxlocalengine.h \ - appxphoneengine.h - -LIBS += -lruntimeobject -lwsclient -lShlwapi -lurlmon -lxmllite -lcrypt32 - -include(../shared/corecon/corecon.pri) -include(../shared/winutils/winutils.pri) - -QMAKE_TARGET_DESCRIPTION = "Qt WinRT Runner" -load(qt_tool) diff --git a/tests/auto/.prev_CMakeLists.txt b/tests/auto/.prev_CMakeLists.txt index bdf5c6b16..af1c24b03 100644 --- a/tests/auto/.prev_CMakeLists.txt +++ b/tests/auto/.prev_CMakeLists.txt @@ -17,6 +17,6 @@ if(TARGET Qt::Help AND NOT CMAKE_CROSSCOMPILING) endif() add_subdirectory(cmake) add_subdirectory(installed_cmake) -if(QT_FEATURE_process AND WIN32 AND NOT CMAKE_CROSSCOMPILING AND NOT WINRT) +if(QT_FEATURE_process AND WIN32 AND NOT CMAKE_CROSSCOMPILING) add_subdirectory(windeployqt) endif() diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt index ab374e67a..85bbc931d 100644 --- a/tests/auto/CMakeLists.txt +++ b/tests/auto/CMakeLists.txt @@ -19,6 +19,6 @@ endif() #add_subdirectory(cmake) #add_subdirectory(installed_cmake) # special case end -if(QT_FEATURE_process AND WIN32 AND NOT CMAKE_CROSSCOMPILING AND NOT WINRT) +if(QT_FEATURE_process AND WIN32 AND NOT CMAKE_CROSSCOMPILING) add_subdirectory(windeployqt) endif() diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 0d3966a7e..486b824bc 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -30,4 +30,4 @@ cross_compile:SUBDIRS -= qhelpcontentmodel qhelpenginecore qhelpindexmodel qhelp qhelpprojectdata \ !qtConfig(process): SUBDIRS -= qtattributionsscanner linguist qtdiag windeployqt -!win32|winrt: SUBDIRS -= windeployqt +!win32: SUBDIRS -= windeployqt |