summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Wolff <oliver.wolff@qt.io>2017-03-23 13:28:39 +0100
committerOliver Wolff <oliver.wolff@qt.io>2017-03-24 12:58:28 +0000
commit3947d229cb8ed8dde5ab72708a4a149ac6d83cae (patch)
treea5f9f364e1e94389cbb2ea8cf7690f0ee332cde3
parent99c4243d04df2c543a3ea5c66d2e37ed7ac5e081 (diff)
downloadqttools-3947d229cb8ed8dde5ab72708a4a149ac6d83cae.tar.gz
winrtrunner: Fix waiting for local package (un-)installation
Debugging did not work on some machines as the waiting loop used in qlocalappxengine was not implemented properly. Instead of relying on an undocumented return value of GetResults we register a callback that is triggered when the deployment operation is finished and trigger an event inside that callback in order to avoid a busy loop. Task-number: QTCREATORBUG-17907 Change-Id: I0bd6535ef0e333ec27b9f339e0c786a63d3b9d07 Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>
-rw-r--r--src/winrtrunner/appxlocalengine.cpp74
1 files changed, 64 insertions, 10 deletions
diff --git a/src/winrtrunner/appxlocalengine.cpp b/src/winrtrunner/appxlocalengine.cpp
index 2c3c0dd66..09615ff58 100644
--- a/src/winrtrunner/appxlocalengine.cpp
+++ b/src/winrtrunner/appxlocalengine.cpp
@@ -60,6 +60,9 @@ 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
@@ -378,7 +381,7 @@ bool AppxLocalEngine::installPackage(IAppxManifestReader *reader, const QString
hr = d->uriFactory->CreateUri(hStringFromQString(nativeFilePath), &uri);
RETURN_FALSE_IF_FAILED("Failed to create an URI for the package");
- ComPtr<IAsyncOperationWithProgress<DeploymentResult *, DeploymentProgress>> deploymentOperation;
+ ComPtr<DeploymentOperation> deploymentOperation;
if (addInsteadOfRegister) {
hr = d->packageManager->AddPackageAsync(uri.Get(), NULL, DeploymentOptions_None,
&deploymentOperation);
@@ -390,13 +393,41 @@ bool AppxLocalEngine::installPackage(IAppxManifestReader *reader, const QString
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, 15000, 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 to info.");
+ AsyncStatus status;
+ hr = asyncInfo->get_Status(&status);
+ RETURN_FALSE_IF_FAILED("Failed to retrieve deployment operation's status.");
+
+ if (status != Completed) {
+ qCWarning(lcWinRtRunner) << "Deployment operation did not succeed.";
+ return false;
+ }
+
ComPtr<IDeploymentResult> results;
- while ((hr = deploymentOperation->GetResults(&results)) == E_ILLEGAL_METHOD_CALL)
- Sleep(1);
+ 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 package registration results.");
+ RETURN_FALSE_IF_FAILED("Failed to retrieve extended error code.");
if (FAILED(errorCode)) {
HString errorText;
@@ -462,17 +493,40 @@ bool AppxLocalEngine::remove()
qCDebug(lcWinRtRunner) << __FUNCTION__;
// ### TODO: use RemovePackageWithOptions to preserve previous state when re-installing
- ComPtr<IAsyncOperationWithProgress<DeploymentResult *, DeploymentProgress>> deploymentOperation;
+ ComPtr<DeploymentOperation> deploymentOperation;
HRESULT hr = d->packageManager->RemovePackageAsync(hStringFromQString(d->packageFullName), &deploymentOperation);
RETURN_FALSE_IF_FAILED("Unable to start package removal");
- ComPtr<IDeploymentResult> results;
- while ((hr = deploymentOperation.Get()->GetResults(&results)) == E_ILLEGAL_METHOD_CALL)
- Sleep(1);
+ 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, 15000, 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;
+ }
- RETURN_FALSE_IF_FAILED("Unable to remove package");
+ ComPtr<IAsyncInfo> asyncInfo;
+ hr = deploymentOperation.As(&asyncInfo);
+ RETURN_FALSE_IF_FAILED("Failed to cast deployment operation.");
- return SUCCEEDED(hr);
+ 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()