上一篇《2020年的UWP(2)——In Process App Service》中我們了解了UWP和Desktop Extension可以通過AppService進行數據交互。本篇我們就來梳理在不同場景,UWP和Desktop Extension可能存在的交互方式。
對Desktop Extension中程序的類型,我暫時分為以下四種:
- 執行后立即退出
- 等待request,處理完后退出
- 一或多個request/response周期
- 和UWP程序相同生命周期
本篇我們僅討論第一種,Desktop Extension中執行后立即退出的程序。該類型有以下特征:
- 簡單的單向調用:
- 不接受request
- 不關心返回結果
- 調用后立即退出
下圖是該類型交互場景的示意圖。通過FullTrustProcessLauncher從UWP端啟動Desktop Extension,我已在《遷移桌面程序到MS Store(9)——APPX With Desktop Extension》介紹過了,本篇不再贅述。
比較典型的如執行某個特定操作,例如調用LockScreen的Win32 API。
class Program { [DllImport("user32.dll", SetLastError = true)] public static extern bool LockWorkStation(); static void Main(string[] args) { LockWorkStation(); } }
我們觀察從UWP端啟動Desktop Extension的代碼:
private async void Button_Click(object sender, RoutedEventArgs e) { await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync(); }
LaunchFullTrustProcessForCurrentAppAsync方法沒有傳遞參數給LockScreen方法,也不關心返回值。啟動Desktop Extension后也不會通過AppService進一步發送request。
似乎和本篇的主題,數據交互毫不相關。但實際情況下,一個Desktop Extension的exe中,會有多個像LockScreen這種一次性的消費型方法。這就要求我們能夠區分UWP端具體要執行哪一個。
首先我們來介紹標准的做法,給LaunchFullTrustProcessForCurrentAppAsync方法傳參。
public static IAsyncAction LaunchFullTrustProcessForCurrentAppAsync(string parameterGroupId);
這里要注意的是。這里所謂的參數parameterGroupId,不會傳遞到Desktop Extension的Main方法里。而是用這個string參數去Package.appxmanifest文件中做匹配,在Package.appxmanifest文件中對應的那個字符串才會被傳遞給Main方法。
<Applications> <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="$targetentrypoint$"> <uap:VisualElements DisplayName="DataExchangeSimpleCallPackage" Description="DataExchangeSimpleCallPackage" BackgroundColor="transparent" Square150x150Logo="Images\Square150x150Logo.png" Square44x44Logo="Images\Square44x44Logo.png"> <uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" /> <uap:SplashScreen Image="Images\SplashScreen.png" /> </uap:VisualElements> <Extensions> <desktop:Extension Category="windows.fullTrustProcess" Executable="ExistAfterCallsProgram\ExistAfterCallsProgram.exe"> <desktop:FullTrustProcess> <desktop:ParameterGroup GroupId="LockScreen" Parameters="LockScreen" /> <desktop:ParameterGroup GroupId="ControlPanel" Parameters="ControlPanel" /> </desktop:FullTrustProcess> </desktop:Extension> </Extensions> </Application> </Applications>
因為都是寫死的字符串,除了用來區分Desktop Extension中數量有限的方法外,並不適合作為一種靈活的傳參方式用於具體方法的邏輯判斷。
通常意義上的靈活傳參給Desktop Extension,基本都是通過AppService來實現,在介紹另外三種類型時會展開討論。
在不使用AppService的簡單交互場景,除了欽定的使用parameterGroupId的做法外。還有一種容易被忽視的方式,即使用LocalSettings。
不提示的話,很難想到在同一個Package里的UWP和Desktop Extension,是可以訪問相同的LocalSettings對象的。
在UWP的MainPage.cs中,我們將“mspaint.exe”存儲到key為“content”的LocalSettings鍵值對中。
private async void ButtonLocalSettings_Click(object sender, RoutedEventArgs e) { ApplicationData.Current.LocalSettings.Values["content"] = "mspaint.exe"; await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync("LocalSettings"); }
而在Desktop Extension中,我們同樣也可以取到這個值,從而達成數據交互的目的。在這個例子中,我們可以傳遞需要運行的exe、msi文件名或路徑,而不用為每一個文件創建單獨的parameterGroupId。
static void Main(string[] args) { string funcName = args[2]; switch (funcName) { case "LockScreen": LockWorkStation(); break; case "ControlPanel": Process.Start("control.exe"); break; case "LocalSettings": var content = ApplicationData.Current.LocalSettings.Values["content"].ToString(); Process.Start(content); break; } }
本篇討論了UWP和Desktop Extension的簡單數據交互,“執行后立即退出”的場景。后續我們會接着講另外的三種類型,感謝看到這里的同學們!
Github:
https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/DataExchangeUWP/ExitAfterCalls
MS Store:
https://www.microsoft.com/en-us/p/dataexchangesimplecall/9p429tjhk8p7?activetab=pivot:overviewtab