Hello GitHub
This commit is contained in:
100
internal/Calculator.UIAutomationLibrary/Utilities/Constants.cs
Normal file
100
internal/Calculator.UIAutomationLibrary/Utilities/Constants.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// The path to the certificate file.
|
||||
/// </summary>
|
||||
public const string CertificateFileName = @"Calculator.cer";
|
||||
|
||||
/// <summary>
|
||||
/// The path to the appxbundle file.
|
||||
/// </summary>
|
||||
public const string PackageFileName = @"Calculator.appxbundle";
|
||||
|
||||
/// <summary>
|
||||
/// The path to the appxbundle file.
|
||||
/// </summary>
|
||||
public const string VCLibsPackageFileName = @"Microsoft.VCLibs.appx";
|
||||
|
||||
/// <summary>
|
||||
/// The path to the appxbundle file.
|
||||
/// </summary>
|
||||
public const string WinUIPackageFileName = @"Microsoft.UI.Xaml.appx";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the CoreWindow.
|
||||
/// </summary>
|
||||
public const string AppWindowName = "Calculator";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the process executable.
|
||||
/// </summary>
|
||||
public const string ProcessName = "Calculator.exe";
|
||||
|
||||
/// <summary>
|
||||
/// The package name.
|
||||
/// </summary>
|
||||
public const string PackageName = "Microsoft.WindowsCalculator";
|
||||
|
||||
/// <summary>
|
||||
/// The package family name for the app to test.
|
||||
/// </summary>
|
||||
public const string PackageFamilyName = PackageName + "_8wekyb3d8bbwe";
|
||||
|
||||
/// <summary>
|
||||
/// The package App User Model Id.
|
||||
/// </summary>
|
||||
public const string PackageAppUserModelId = PackageFamilyName + "!App";
|
||||
|
||||
/// <summary>
|
||||
/// AutomationId for the top level UI element.
|
||||
/// </summary>
|
||||
public const string TopLevelWindowAutomationId = "CalculatorWindow";
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the first page is loaded.
|
||||
/// </summary>
|
||||
public const string AppLaunchEndETWEventName = "AppLaunchEnd";
|
||||
|
||||
/// <summary>
|
||||
/// App Provider GUID for ETW Events
|
||||
/// </summary>
|
||||
public static readonly Guid CalculatorETWProviderGUID = new Guid("0905CA09-610E-401E-B650-2F212980B9E0");
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when a calculator mode change is complete.
|
||||
/// </summary>
|
||||
public const string AppModeChangeEndETWEventName = "ModeChangeEnd";
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the History panel is opened by flyout or by changing pivot tabs.
|
||||
/// </summary>
|
||||
public const string HistoryBodyOpenedETWEventName = "HistoryBodyOpened";
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the Memory panel is opened by flyout or by changing pivot tabs.
|
||||
/// </summary>
|
||||
public const string MemoryBodyOpenedETWEventName = "MemoryBodyOpened";
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the About flyout control is loaded.
|
||||
/// </summary>
|
||||
public const string AboutFlyoutOpenedETWEventName = "AboutFlyoutOpened";
|
||||
|
||||
/// <summary>
|
||||
/// Event fired when the Nav Bar control is opened.
|
||||
/// </summary>
|
||||
public const string NavBarOpenedETWEventName = "NavBarOpened";
|
||||
|
||||
/// <summary>
|
||||
/// Margin used to click in the gutter beneath the History and Memory lists
|
||||
/// </summary>
|
||||
public const int ClickMargin = 10;
|
||||
}
|
||||
}
|
101
internal/Calculator.UIAutomationLibrary/Utilities/EtwHelper.cs
Normal file
101
internal/Calculator.UIAutomationLibrary/Utilities/EtwHelper.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.OneCoreUap.Test.AppModel;
|
||||
using WEX.Logging.Interop;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public class EtwHelper
|
||||
{
|
||||
private static bool etwServiceWasInstalled = false;
|
||||
|
||||
/// <summary>
|
||||
/// Installs and starts the Etw.Service so that Tests may utilize Etw Waiters.
|
||||
/// Wex.Services.exe is part of TAEF.
|
||||
/// </summary>
|
||||
public static void InstallAndStartETWService()
|
||||
{
|
||||
etwServiceWasInstalled = ServiceHelper.IsInstalled("Etw.Service");
|
||||
if (!etwServiceWasInstalled)
|
||||
{
|
||||
string wexServices = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), "Wex.Services.exe");
|
||||
if (!File.Exists(wexServices))
|
||||
{
|
||||
throw new FileNotFoundException(wexServices);
|
||||
}
|
||||
|
||||
Log.Comment("Attempting to install Etw.Service...");
|
||||
var startInfo = new ProcessStartInfo();
|
||||
startInfo.FileName = wexServices;
|
||||
startInfo.Arguments = "/install:Etw.Service";
|
||||
|
||||
var process = new Process();
|
||||
process.StartInfo = startInfo;
|
||||
if (process.Start())
|
||||
{
|
||||
process.WaitForExit();
|
||||
Log.Comment("Completed installation of Etw.Service");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("ETW service was not able to be installed. Process didn't start.");
|
||||
}
|
||||
}
|
||||
|
||||
Log.Comment("Attempting to start Etw.Service...");
|
||||
ServiceHelper.Start("Etw.Service");
|
||||
Log.Comment("Etw.Service started");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the Etw.Service.
|
||||
/// </summary>
|
||||
public static void StopAndRemoveETWService()
|
||||
{
|
||||
if (ServiceHelper.IsInstalled("Etw.Service"))
|
||||
{
|
||||
Log.Comment("Attempting to stop Etw.Service...");
|
||||
ServiceHelper.Stop("Etw.Service");
|
||||
Log.Comment("Etw.Service stopped");
|
||||
|
||||
// if we installed the Etw.Service as part of this test we should also remove it.
|
||||
// This prevents cases where TDP is upgraded but the service tregistration is referencing the old
|
||||
// location that no longer exists.
|
||||
if (!etwServiceWasInstalled)
|
||||
{
|
||||
|
||||
string wexServices = Path.Combine(TAEFHelper.GetTestDeploymentDirectory(), "Wex.Services.exe");
|
||||
if (!File.Exists(wexServices))
|
||||
{
|
||||
throw new FileNotFoundException(wexServices);
|
||||
}
|
||||
|
||||
Log.Comment("Attempting to remove Etw.Service...");
|
||||
var startInfo = new ProcessStartInfo();
|
||||
startInfo.FileName = wexServices;
|
||||
startInfo.Arguments = "/remove:Etw.Service";
|
||||
|
||||
var process = new Process();
|
||||
process.StartInfo = startInfo;
|
||||
if (process.Start())
|
||||
{
|
||||
process.WaitForExit();
|
||||
Log.Comment("Completed removal of Etw.Service");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("ETW service could not be removed. Process didn't start.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public static class Impersonater
|
||||
{
|
||||
public static void RunAs(RunAsUser user, Action action)
|
||||
{
|
||||
IntPtr errorInfo;
|
||||
SafeAccessTokenHandle restrictedToken;
|
||||
GetRunAsUserToken getRunAsUserToken = ResolveGetRunAsUserTokenMethod();
|
||||
Marshal.ThrowExceptionForHR(getRunAsUserToken(user, out restrictedToken, out errorInfo), errorInfo);
|
||||
|
||||
WindowsIdentity.RunImpersonated(restrictedToken, action);
|
||||
}
|
||||
|
||||
public static void RunAs<T>(RunAsUser user, Func<T> function)
|
||||
{
|
||||
IntPtr errorInfo;
|
||||
SafeAccessTokenHandle restrictedToken;
|
||||
GetRunAsUserToken getRunAsUserToken = ResolveGetRunAsUserTokenMethod();
|
||||
Marshal.ThrowExceptionForHR(getRunAsUserToken(user, out restrictedToken, out errorInfo), errorInfo);
|
||||
|
||||
WindowsIdentity.RunImpersonated(restrictedToken, function);
|
||||
}
|
||||
|
||||
// From: https://microsoft.visualstudio.com/EngSys/_git/validation.taef?path=%2Fsrc%2FTAEF%2FCommon%2FPublished%2FRunAsFromSystem.h&version=GBdevelop
|
||||
public enum RunAsUser
|
||||
{
|
||||
ElevatedUser,
|
||||
User,
|
||||
RestrictedUser,
|
||||
LowIL,
|
||||
InteractiveUser,
|
||||
};
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
private delegate int GetRunAsUserToken(RunAsUser user, out SafeAccessTokenHandle token, out IntPtr errorInfo);
|
||||
|
||||
// GetRunAsUserToken is defined in a namespace so we have to do some tricks to use P/Invoke.
|
||||
// We got the actual exported method name by running dumpbin /exports TE.Common.dll
|
||||
private static GetRunAsUserToken ResolveGetRunAsUserTokenMethod()
|
||||
{
|
||||
IntPtr teCommonDll = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
teCommonDll = LoadLibrary(@"TE.Common.dll");
|
||||
|
||||
IntPtr x64GetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YAJW4RunAsUser@12@PEAPEAXPEAPEAUIErrorInfo@@@Z");
|
||||
if (x64GetRunAsUserToken != IntPtr.Zero)
|
||||
{
|
||||
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(x64GetRunAsUserToken);
|
||||
}
|
||||
IntPtr x86GetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YGJW4RunAsUser@12@PAPAXPAPAUIErrorInfo@@@Z");
|
||||
if (x86GetRunAsUserToken != IntPtr.Zero)
|
||||
{
|
||||
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(x86GetRunAsUserToken);
|
||||
}
|
||||
IntPtr armGetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YAJW4RunAsUser@12@PAPAXPAPAUIErrorInfo@@@Z");
|
||||
if (armGetRunAsUserToken != IntPtr.Zero)
|
||||
{
|
||||
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(armGetRunAsUserToken);
|
||||
}
|
||||
IntPtr arm64GetRunAsUserToken = GetProcAddress(teCommonDll, "?GetRunAsUserToken@TestExecution@WEX@@YAJW4RunAsUser@12@PEAPEAXPEAPEAUIErrorInfo@@@Z");
|
||||
if (arm64GetRunAsUserToken != IntPtr.Zero)
|
||||
{
|
||||
return Marshal.GetDelegateForFunctionPointer<GetRunAsUserToken>(arm64GetRunAsUserToken);
|
||||
}
|
||||
|
||||
throw new Exception("Unable to find the GetRunAsUserToken function in DLL 'TE.Common.dll'");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (teCommonDll != IntPtr.Zero)
|
||||
{
|
||||
FreeLibrary(teCommonDll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr LoadLibrary(string dllToLoad);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern bool FreeLibrary(IntPtr hModule);
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using Microsoft.OneCoreUap.Test.AppModel;
|
||||
using WEX.Logging.Interop;
|
||||
using Windows.Foundation;
|
||||
using Windows.Management.Deployment;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public class InstallHelper
|
||||
{
|
||||
public static void InstallCertFile(string certFilePath)
|
||||
{
|
||||
// Ensure cert exists.
|
||||
if (!File.Exists(certFilePath))
|
||||
{
|
||||
throw new FileNotFoundException(certFilePath);
|
||||
}
|
||||
|
||||
// For some reason, attempting to use CertificateHelper.InstallFromSignedPackage() to install
|
||||
// the certificate associated with the appx package fails with the error:
|
||||
// "A certificate chain could not be built to a trusted root authority."
|
||||
// The reason is that the cert needs to be installed in 'StoreName.TrustedPeople',
|
||||
// but DeploymentHelper.AddPackage() attempts to install it in 'StoreName.Root'.
|
||||
// Therefore, the cert has been installed manually beforehand.
|
||||
Log.Comment($"Starting install of certificate at {certFilePath}");
|
||||
|
||||
X509Certificate2 certificate = new X509Certificate2(certFilePath);
|
||||
X509Store trustedPeopleStore = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine);
|
||||
trustedPeopleStore.Open(OpenFlags.MaxAllowed);
|
||||
trustedPeopleStore.Add(certificate);
|
||||
|
||||
Log.Comment($"Completed install of certificate");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upgrades the appx/appxbundle from the path if needed.
|
||||
/// </summary>
|
||||
public static void InstallPackage(string appxFilePath, params string[] dependencyAppxFilePaths)
|
||||
{
|
||||
// Ensure the files exist.
|
||||
if (!File.Exists(appxFilePath))
|
||||
{
|
||||
throw new FileNotFoundException(appxFilePath);
|
||||
}
|
||||
foreach (var path in dependencyAppxFilePaths.Where(p => !File.Exists(p)))
|
||||
{
|
||||
throw new FileNotFoundException(path);
|
||||
}
|
||||
|
||||
Log.Comment($"Starting install of app package at {appxFilePath}");
|
||||
|
||||
PackageManager packageManager = new PackageManager();
|
||||
var deploymentOperation = packageManager.AddPackageAsync(
|
||||
new Uri(appxFilePath),
|
||||
dependencyAppxFilePaths.Select(d => new Uri(d)),
|
||||
DeploymentOptions.ForceApplicationShutdown | DeploymentOptions.ForceTargetApplicationShutdown | DeploymentOptions.ForceUpdateFromAnyVersion);
|
||||
|
||||
WaitForDeploymentOperation(deploymentOperation);
|
||||
|
||||
Log.Comment("Completed install of app package");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits for a deployment operation to complete
|
||||
/// </summary>
|
||||
private static void WaitForDeploymentOperation(IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> operation)
|
||||
{
|
||||
ManualResetEvent isCompletedEvent = new ManualResetEvent(false);
|
||||
operation.Completed = (IAsyncOperationWithProgress<DeploymentResult, DeploymentProgress> asyncInfo, AsyncStatus asyncStatus) =>
|
||||
{
|
||||
isCompletedEvent.Set();
|
||||
};
|
||||
|
||||
isCompletedEvent.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
internal const int GW_OWNER = 4;
|
||||
|
||||
internal delegate bool EnumThreadWindowsCallback(IntPtr hWnd, IntPtr lParam);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern int GetWindowTextLength(IntPtr hWnd);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern bool IsWindowVisible(IntPtr hWnd);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern IntPtr GetWindow(IntPtr hWnd, int uCmd);
|
||||
|
||||
[DllImport("api-ms-win-ntuser-ie-window-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
|
||||
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool StartService(IntPtr hService, int dwNumServiceArgs, string[] lpServiceArgVectors);
|
||||
|
||||
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus);
|
||||
|
||||
[DllImport("api-ms-win-service-management-l1-1-0.dll")]
|
||||
internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
|
||||
|
||||
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool CloseServiceHandle(IntPtr hSCObject);
|
||||
|
||||
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
|
||||
|
||||
[DllImport("api-ms-win-service-management-l1-1-0.dll", SetLastError = true)]
|
||||
internal static extern bool QueryServiceStatus(IntPtr hService, ref SERVICE_STATUS dwServiceStatus);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
internal struct SERVICE_STATUS
|
||||
{
|
||||
public int dwServiceType;
|
||||
public int dwCurrentState;
|
||||
public int dwControlsAccepted;
|
||||
public int dwWin32ExitCode;
|
||||
public int dwServiceSpecificExitCode;
|
||||
public int dwCheckPoint;
|
||||
public int dwWaitHint;
|
||||
}
|
||||
|
||||
internal static uint STANDARD_RIGHTS_REQUIRED = 0xF0000;
|
||||
|
||||
internal static uint SC_MANAGER_CONNECT = 0x0001;
|
||||
internal static uint SC_MANAGER_CREATE_SERVICE = 0x0002;
|
||||
internal static uint SC_MANAGER_ENUMERATE_SERVICE = 0x0004;
|
||||
internal static uint SC_MANAGER_LOCK = 0x0008;
|
||||
internal static uint SC_MANAGER_QUERY_LOCK_STATUS = 0x0010;
|
||||
internal static uint SC_MANAGER_MODIFY_BOOT_CONFIG = 0x0020;
|
||||
internal static uint SC_MANAGER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
|
||||
SC_MANAGER_CONNECT |
|
||||
SC_MANAGER_CREATE_SERVICE |
|
||||
SC_MANAGER_ENUMERATE_SERVICE |
|
||||
SC_MANAGER_LOCK |
|
||||
SC_MANAGER_QUERY_LOCK_STATUS |
|
||||
SC_MANAGER_MODIFY_BOOT_CONFIG);
|
||||
|
||||
internal static uint SERVICE_QUERY_CONFIG = 0x0001;
|
||||
internal static uint SERVICE_CHANGE_CONFIG = 0x0002;
|
||||
internal static uint SERVICE_QUERY_STATUS = 0x0004;
|
||||
internal static uint SERVICE_ENUMERATE_DEPENDENTS = 0x0008;
|
||||
internal static uint SERVICE_START = 0x0010;
|
||||
internal static uint SERVICE_STOP = 0x0020;
|
||||
internal static uint SERVICE_PAUSE_CONTINUE = 0x0040;
|
||||
internal static uint SERVICE_INTERROGATE = 0x0080;
|
||||
internal static uint SERVICE_USER_DEFINED_CONTROL = 0x0100;
|
||||
internal static uint SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
|
||||
SERVICE_QUERY_CONFIG |
|
||||
SERVICE_CHANGE_CONFIG |
|
||||
SERVICE_QUERY_STATUS |
|
||||
SERVICE_ENUMERATE_DEPENDENTS |
|
||||
SERVICE_START |
|
||||
SERVICE_STOP |
|
||||
SERVICE_PAUSE_CONTINUE |
|
||||
SERVICE_INTERROGATE |
|
||||
SERVICE_USER_DEFINED_CONTROL);
|
||||
|
||||
[Flags]
|
||||
internal enum SERVICE_CONTROL : uint
|
||||
{
|
||||
STOP = 0x00000001,
|
||||
PAUSE = 0x00000002,
|
||||
CONTINUE = 0x00000003,
|
||||
INTERROGATE = 0x00000004,
|
||||
SHUTDOWN = 0x00000005,
|
||||
PARAMCHANGE = 0x00000006,
|
||||
NETBINDADD = 0x00000007,
|
||||
NETBINDREMOVE = 0x00000008,
|
||||
NETBINDENABLE = 0x00000009,
|
||||
NETBINDDISABLE = 0x0000000A,
|
||||
DEVICEEVENT = 0x0000000B,
|
||||
HARDWAREPROFILECHANGE = 0x0000000C,
|
||||
POWEREVENT = 0x0000000D,
|
||||
SESSIONCHANGE = 0x0000000E
|
||||
}
|
||||
|
||||
internal enum SERVICE_STATE : int
|
||||
{
|
||||
SERVICE_STOPPED = 0x00000001,
|
||||
SERVICE_START_PENDING = 0x00000002,
|
||||
SERVICE_STOP_PENDING = 0x00000003,
|
||||
SERVICE_RUNNING = 0x00000004,
|
||||
SERVICE_CONTINUE_PENDING = 0x00000005,
|
||||
SERVICE_PAUSE_PENDING = 0x00000006,
|
||||
SERVICE_PAUSED = 0x00000007
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public class PerfConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// Path where the regions, wprprofiles and wpaprofiles will be deployed to by the spkg.
|
||||
/// </summary>
|
||||
public const string ConfigDirectory = @"Config\";
|
||||
|
||||
/// <summary>
|
||||
/// Our FunGates source, where we can view test results.
|
||||
/// </summary>
|
||||
public const string FunGatesSource =
|
||||
#if DEBUG
|
||||
"TestSite";
|
||||
#else
|
||||
"Utility Apps Performance Tests";
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The Windows Performance Recorder profile. These strings must have the config directory prefix.
|
||||
/// For use with the WPRProfileFile test attribute.
|
||||
/// </summary>
|
||||
public const string AppLifecycleWPRProfile = ConfigDirectory + "AppLifecycle.Profile.wprp";
|
||||
|
||||
/// <summary>
|
||||
/// The regions of interest file that contains the events we are interested in measuring.
|
||||
/// </summary>
|
||||
public const string AppLifecycleRegions = ConfigDirectory + "AppLifecycle.regions.xml";
|
||||
|
||||
/// <summary>
|
||||
/// These are uses with the DataSource test property to specify iteration info.
|
||||
/// </summary>
|
||||
public const string AppLifecycleInterationsSource = "Table:" + ConfigDirectory + "AppLifecycle.Iterations.xml#PerformanceConfigurations";
|
||||
}
|
||||
}
|
@@ -0,0 +1,156 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public class ServiceHelper
|
||||
{
|
||||
public static void Start(string serviceName, int timeoutInMilliSeconds = 30000)
|
||||
{
|
||||
IntPtr hService = IntPtr.Zero;
|
||||
IntPtr hSCManager = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
hSCManager = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_ALL_ACCESS);
|
||||
if (IntPtr.Zero == hSCManager)
|
||||
{
|
||||
throw new Exception($"Start: Cannot Open OpenSCManager, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
hService = NativeMethods.OpenService(hSCManager, serviceName, NativeMethods.SERVICE_ALL_ACCESS);
|
||||
if (IntPtr.Zero == hService)
|
||||
{
|
||||
throw new Exception($"Start: Cannot Open Service, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
NativeMethods.SERVICE_STATUS serviceStatus = new NativeMethods.SERVICE_STATUS();
|
||||
if (!NativeMethods.QueryServiceStatus(hService, ref serviceStatus))
|
||||
{
|
||||
throw new Exception($"Start: Unable to query status of Service, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
if (serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_RUNNING &&
|
||||
serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_START_PENDING)
|
||||
{
|
||||
if (!NativeMethods.StartService(hService, 0, null))
|
||||
{
|
||||
throw new Exception($"Start: Service cannot be started, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
}
|
||||
|
||||
WaitForStatus(hService, NativeMethods.SERVICE_STATE.SERVICE_RUNNING, TimeSpan.FromMilliseconds(timeoutInMilliSeconds));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (IntPtr.Zero != hService)
|
||||
{
|
||||
NativeMethods.CloseServiceHandle(hService);
|
||||
}
|
||||
if (IntPtr.Zero != hSCManager)
|
||||
{
|
||||
NativeMethods.CloseServiceHandle(hSCManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Stop(string serviceName, int timeoutInMilliSeconds = 30000)
|
||||
{
|
||||
IntPtr hSCManager = IntPtr.Zero;
|
||||
IntPtr hService = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
hSCManager = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_ALL_ACCESS);
|
||||
if (IntPtr.Zero == hSCManager)
|
||||
{
|
||||
throw new Exception($"Stop: Cannot Open OpenSCManager, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
hService = NativeMethods.OpenService(hSCManager, serviceName, NativeMethods.SERVICE_ALL_ACCESS);
|
||||
if (IntPtr.Zero == hService)
|
||||
{
|
||||
throw new Exception($"Stop: Cannot Open Service, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
NativeMethods.SERVICE_STATUS serviceStatus = new NativeMethods.SERVICE_STATUS();
|
||||
if (!NativeMethods.QueryServiceStatus(hService, ref serviceStatus))
|
||||
{
|
||||
throw new Exception($"Stop: Unable to query status of Service, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
if (serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_STOPPED &&
|
||||
serviceStatus.dwCurrentState != (int)NativeMethods.SERVICE_STATE.SERVICE_STOP_PENDING)
|
||||
{
|
||||
if (!NativeMethods.ControlService(hService, NativeMethods.SERVICE_CONTROL.STOP, ref serviceStatus))
|
||||
{
|
||||
throw new Exception($"Stop: Service cannot be stopped, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
}
|
||||
|
||||
WaitForStatus(hService, NativeMethods.SERVICE_STATE.SERVICE_STOPPED, TimeSpan.FromMilliseconds(timeoutInMilliSeconds));
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (IntPtr.Zero != hService)
|
||||
{
|
||||
NativeMethods.CloseServiceHandle(hService);
|
||||
}
|
||||
|
||||
if (IntPtr.Zero != hSCManager)
|
||||
{
|
||||
NativeMethods.CloseServiceHandle(hSCManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsInstalled(string svcName)
|
||||
{
|
||||
IntPtr sc_handle = NativeMethods.OpenSCManager(null, null, NativeMethods.SC_MANAGER_ALL_ACCESS);
|
||||
if (sc_handle == IntPtr.Zero)
|
||||
{
|
||||
throw new Exception($"IsInstalled: Cannot open service manager, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
|
||||
bool bResult = false;
|
||||
IntPtr sv_handle = NativeMethods.OpenService(sc_handle, svcName, NativeMethods.SERVICE_QUERY_CONFIG);
|
||||
if (sv_handle.ToInt64() != 0)
|
||||
{
|
||||
bResult = true;
|
||||
NativeMethods.CloseServiceHandle(sv_handle);
|
||||
}
|
||||
NativeMethods.CloseServiceHandle(sc_handle);
|
||||
return bResult;
|
||||
}
|
||||
|
||||
private static void WaitForStatus(IntPtr hService, NativeMethods.SERVICE_STATE desiredStatus, TimeSpan timeout)
|
||||
{
|
||||
Stopwatch swLoop = new Stopwatch();
|
||||
swLoop.Start();
|
||||
|
||||
NativeMethods.SERVICE_STATUS serviceStatus = new NativeMethods.SERVICE_STATUS();
|
||||
|
||||
do
|
||||
{
|
||||
Thread.Sleep(500);
|
||||
if (!NativeMethods.QueryServiceStatus(hService, ref serviceStatus))
|
||||
{
|
||||
throw new Exception($"WaitForStatus: Unable to query status of service, {Marshal.GetLastWin32Error()}");
|
||||
}
|
||||
}
|
||||
while (serviceStatus.dwCurrentState != (int)desiredStatus && (swLoop.ElapsedMilliseconds <= timeout.TotalMilliseconds));
|
||||
|
||||
if (serviceStatus.dwCurrentState != (int)desiredStatus)
|
||||
{
|
||||
throw new Exception($"WaitForStatus: Service failed to reach desired state: {desiredStatus}, current state: {serviceStatus.dwCurrentState}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Linq;
|
||||
using System.Windows.Automation;
|
||||
using MS.Internal.Mita.Foundation;
|
||||
using MS.Internal.Mita.Foundation.Controls;
|
||||
using MS.Internal.Mita.Foundation.Waiters;
|
||||
using WEX.Logging.Interop;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public static class UIObjectExtensions
|
||||
{
|
||||
private const string NamePropertyName = "Name";
|
||||
private static UICondition CoreWindowCondition = UICondition.CreateFromClassName("Windows.UI.Core.CoreWindow");
|
||||
|
||||
public static Window GetParentCoreWindow(this UIObject uiObject)
|
||||
{
|
||||
if (uiObject.Matches(CoreWindowCondition))
|
||||
{
|
||||
return new Window(uiObject);
|
||||
}
|
||||
|
||||
return new Window(uiObject.Ancestors.Find(CoreWindowCondition));
|
||||
}
|
||||
|
||||
public static Window GetTopLevelWindow(this Window window)
|
||||
{
|
||||
var node = window;
|
||||
while (node != null && node.Parent != null && node.Parent.ControlType == ControlType.Window)
|
||||
{
|
||||
node = new Window(node.Parent);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public static void VerifyParentTreeStructure(this UIObject uiObject)
|
||||
{
|
||||
var node = uiObject;
|
||||
while (node != null && node.Parent != null)
|
||||
{
|
||||
if (!node.Parent.Children.Contains(node))
|
||||
{
|
||||
Log.Comment($"- [VerifyingTree] {node} specifies {node.Parent} as parent but is not part of its children.");
|
||||
}
|
||||
if (!node.Parent.Descendants.Contains(node))
|
||||
{
|
||||
Log.Comment($"- [VerifyingTree] {node} specifies {node.Parent} as parent but is not part of its descendants.");
|
||||
}
|
||||
node = node.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool DoesDescendantExist(this UIObject uiObject, string automationId)
|
||||
{
|
||||
UIObject temp;
|
||||
return uiObject.Descendants.TryFind(automationId, out temp);
|
||||
}
|
||||
|
||||
public static PropertyChangedEventWaiter GetNameChangedWaiter(this TextBlock textBlock)
|
||||
{
|
||||
return new PropertyChangedEventWaiter(textBlock, UIProperty.Get(NamePropertyName));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using WEX.Logging.Interop;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public class Utilities
|
||||
{
|
||||
public static void KillExistingCalculatorProcesses()
|
||||
{
|
||||
Log.Comment("Killing any existing Calculator processes");
|
||||
|
||||
foreach (var process in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Constants.ProcessName)))
|
||||
{
|
||||
try
|
||||
{
|
||||
process.Kill();
|
||||
Log.Comment($"Killed {process.ProcessName}, Id: {process.Id}");
|
||||
}
|
||||
catch (Exception) when (process.HasExited)
|
||||
{
|
||||
Log.Comment($"{process.ProcessName}, Id: {process.Id} already exited.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using MS.Internal.Mita.Foundation.Controls;
|
||||
using WEX.Logging.Interop;
|
||||
|
||||
namespace Calculator.UIAutomationLibrary
|
||||
{
|
||||
public class WindowHelper
|
||||
{
|
||||
public static void SetAsForeground(Window window)
|
||||
{
|
||||
Log.Comment($"Set window {window.NativeWindowHandle} as the foreground window.");
|
||||
|
||||
NativeMethods.SetForegroundWindow(window.NativeWindowHandle);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user