1. 程式人生 > >遷移桌面程式到MS Store(14)——APPX嵌入WCF Service以Admin許可權執行

遷移桌面程式到MS Store(14)——APPX嵌入WCF Service以Admin許可權執行

Windows10 1809版本開始,微軟又對UWP開放了新的Capability:AllowElevation。 通過這個新的Capability,UWP APP能夠在執行時向用戶請求Admin許可權,配合Windows 1607版本就引入的RunFullTrust Capability(參考《遷移桌面程式到MS Store(9)——APPX With Desktop Extension 》),我們可以讓MS Store中的APP擁有無限接近傳統桌面程式的能力。
本篇提到的Sample工程位於全球最大的同性交友平臺GitHub:
https://github.com/manupstairs/UWPAllowElevation

上圖解釋了整個程式執行的流程,UWP APP通過RunFullTrust Capability來執行一個exe程式,在這個exe程式中,又因為新的AllowElevation而能夠請求Admin許可權來啟動WCF Servcie。使用者在UAC彈窗中確認授予Admin許可權後,我們就在UWP APP的身後擁有了一個具有Admin許可權的WCF Service。
首先讓我們建立WCFBackgroundProcess工程,包含一個Hello World級別的WCF Service。在該服務的介面中,我們定義了三個方法,用來啟動,停止和查詢Windows Service狀態。這麼設計是因為這些操作需要Admin許可權。

    [ServiceContract]
    public interface ILocalService
    {

        [OperationContract]
        ServiceControllerStatus StartService(string name);

        [OperationContract]
        ServiceControllerStatus StopService(string name);

        [OperationContract]
        ServiceControllerStatus GetServiceStatus(string name);
    }

WCFBackgroundProcess工程本身是一個Console型別的程式,作為exe啟動後,我們就可以在UWP Client工程中,新增對WCFBackgroundProcess中服務的引用。具體可以參考《遷移桌面程式到MS Store(7)——APPX + Service》。

    class Program
    {
        static void Main(string[] args)
        {
            var selfHost = new ServiceHost(typeof(LocalServiceWrapper));

            selfHost.Open();

            Console.WriteLine("The service is ready.");

            // Close the ServiceHost to stop the service.
            Console.WriteLine("Press <Enter> to terminate the service.");
            Console.WriteLine();
            Console.ReadLine();
            selfHost.Close();
        }
    }

Launcher工程是一個標準的Console程式,內容非常簡單,通過ProcessStartInfo類來啟動WCFBackgroundProcess.exe。該工程在UWP環境下所需的AllowElevation我們在建立Packaging工程時會新增。

    class Program
    {
        static void Main(string[] args)
        {
            string result = Assembly.GetExecutingAssembly().Location;
            int index = result.LastIndexOf("\\");
            string rootPath = $"{result.Substring(0, index)}\\..\\";

            rootPath += @"WCFBackgroundProcess\WCFBackgroundProcess.exe";

            ProcessStartInfo info = new ProcessStartInfo
            {
                Verb = "runas",
                UseShellExecute = true,
                FileName = rootPath
            };
            Process.Start(info);
        }
    }

接著建立UWPClient工程,這是一個標準的UWP專案。除了WCFBackgroundService的引用外,我們還需要通過NuGet新增Windows Desktop Extension for the UWP來實現對Launcher.exe的呼叫(參考《遷移桌面程式到MS Store(9)——APPX With Desktop Extension 》)。

 

UWPClient僅包含唯一的MainPage,四個按鈕事件分別負責啟動Launcher.exe,啟動、停止、查詢BluetoothService的狀態,程式碼如下:

    public sealed partial class MainPage : Page
    {
        private string serviceName = "bthserv";
        private LocalServiceClient client = new LocalServiceClient();

        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void StopButton_Click(object sender, RoutedEventArgs e)
        {
            var status = await client.StopServiceAsync(serviceName);
            textBlockStatus.Text = status.ToString();
        }

        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            var status = await client.StartServiceAsync(serviceName);
            textBlockStatus.Text = status.ToString();
        }

        private async void QueryButton_Click(object sender, RoutedEventArgs e)
        {
            var status = await client.GetServiceStatusAsync(serviceName);
            textBlockStatus.Text = status.ToString();
        }

        private async void RunWCFService_Click(object sender, RoutedEventArgs e)
        {
            if (ApiInformation.IsApiContractPresent("Windows.ApplicationModel.FullTrustAppContract", 1, 0))
            {
                await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
            }
        }
    }

以上就是所有的準備工作。然後我們建立作為啟動專案的AllowElevationPackaging工程(參考《遷移桌面程式到MS Store(1)——通過Visual Studio建立Packaging工程》)。在AllowElevationPackaging的Applications中包含之前建立的所有三個工程,同時將UWPClient設為Entry Point。

右鍵選中Package.aapxmanifest後進行編輯,在<Application/>節點中新增:

      <Extensions>
        <desktop:Extension xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" Category="windows.fullTrustProcess" Executable="Launcher\Launcher.exe" />
      </Extensions>

同時修改Capabilities節點:

  <Capabilities>
    <Capability Name="internetClient" />
    <rescap:Capability Name="runFullTrust" />
    <rescap:Capability Name="allowElevation" />
  </Capabilities>

完成後儲存關閉檔案,大功告成!編譯整個解決方案確保沒有任何錯誤,然後讓我們點選F5開始執行(記得將AllowElevationPackaging設為啟動項)。
首先我們先點選Apply for Elevation capability and Run WCF Service按鈕。在UAC視窗中我們同意給予Admin許可權,WCF Service順利啟動。感興趣的同學可以通過視窗的標題欄檢視WCFBackgroundProcess.exe的物理路徑。

然後我們即可以開始查詢藍芽服務的執行狀態了。如果用的是藍芽滑鼠,在點選Stop Blue Support Service的同時不要驚慌失措哦。本篇作為《遷移桌面程式到MS Store》系列的最終篇,沒人看的系列就準備太監了。猶豫就會敗北,果斷就會白給。後續部落格將專注於.NET Core的學習,與諸君共勉!

GitHub:
https://github.com/manupstairs/UWPAllowEleva