Important
裝置元數據已被取代,將在未來的 Windows 版本中移除。 如需這項功能取代的相關信息,請參閱 驅動程式套件容器元數據。
在 Windows 8.1 中,使用者可以從 UWP 裝置應用程式的新式 UI 檢查其印表機狀態。 本主題使用 列印設定和列印通知 範例的 C# 版本來示範如何查詢印表機狀態並顯示它。 若要深入瞭解一般 UWP 裝置應用程式,請參閱 認識 UWP 裝置應用程式。
印表設定和列印通知範例的 C# 版本會使用 InkLevel.xaml 頁面來示範如何取得印表機狀態(在此案例中為筆跡層級),並加以顯示。 列印協助程式類別可用來建立裝置內容(IPrinterExtensionContext),並執行裝置查詢。 The PrinterHelperClass.cs file is in the DeviceAppForPrintersLibrary project and uses APIs defined in the PrinterExtensionLibrary project. 印表機延伸模組連結庫提供方便的方式來存取 v4 印表驅動程式的印表機延伸模組介面。 如需詳細資訊,請參閱 印表機擴充功能庫概觀。
Note
本主題中顯示的程式代碼範例是以 列印設定和列印通知 範例的 C# 版本為基礎。 此範例也適用於 JavaScript 和 C++。 請注意,由於C++可以直接存取 COM,因此範例C++版本不包含程式代碼庫專案。 下載範例以查看最新版本的程序代碼。
Prerequisites
開始之前:
請確定您的印表機是使用 v4 印表驅動程式安裝。 如需詳細資訊,請參閱 開發 v4 列印驅動程式。
設定好您的開發電腦。 See Getting started for info about downloading the tools and creating a developer account.
將您的應用程式與市集產生關聯。 如需相關信息,請參閱 步驟 1:建立 UWP 裝置應用程式 。
為您的印表機建立裝置元數據,使其與您的應用程式產生關聯。 如需詳細資訊,請參閱 步驟 2:建立裝置元數據 。
If you're writing your app with C# or JavaScript, add the PrinterExtensionLibrary and DeviceAppForPrintersLibrary projects to your UWP device app solution. 您可以在 [列印設定] 和 [列印通知 ] 範例中找到這些專案。
Note
因為C++可以直接存取 COM,C++應用程式不需要個別的連結庫來處理以 COM 為基礎的印表機裝置內容。
步驟 1:尋找印表機
在建立裝置內容之前,應用程式必須判斷印表機的裝置識別碼。 若要這樣做,此範例會使用 EnumerateAssociatedPrinters 方法來搜尋連接至計算機的所有印表機。 然後,它會檢查每個印表機的容器,並透過比較每個容器的 PackageFamilyName 屬性來尋找關聯。
Note
The System.Devices.AppPackageFamilyName for devices that are associated with your app can be found under the Packaging tab on the Manifest Designer in Microsoft Visual Studio.
This example shows the EnumerateAssociatedPrinters method from the InkLevel.xaml.cs file:
async void EnumerateAssociatedPrinters(object sender, RoutedEventArgs e)
{
// Reset output text and associated printer array.
AssociatedPrinters.Items.Clear();
BidiOutput.Text = "";
// GUID string for printers.
string printerInterfaceClass = "{0ecef634-6ef0-472a-8085-5ad023ecbccd}";
string selector = "System.Devices.InterfaceClassGuid:=\"" + printerInterfaceClass + "\"";
// By default, FindAllAsync does not return the containerId for the device it queries.
// We have to add it as an additional property to retrieve.
string containerIdField = "System.Devices.ContainerId";
string[] propertiesToRetrieve = new string[] { containerIdField };
// Asynchronously find all printer devices.
DeviceInformationCollection deviceInfoCollection = await DeviceInformation.FindAllAsync(selector, propertiesToRetrieve);
// For each printer device returned, check if it is associated with the current app.
for (int i = 0; i < deviceInfoCollection.Count; i++)
{
DeviceInformation deviceInfo = deviceInfoCollection[i];
FindAssociation(deviceInfo, deviceInfo.Properties[containerIdField].ToString());
}
}
FindAssociation 方法被 EnumerateAssociatedPrinters 呼叫,用來檢查印表機是否與目前的應用程式相關聯。 換句話說,此方法會檢查應用程式是否為 UWP 裝置應用程式。 當應用程式與印表機定義於本機電腦上的裝置元數據時,就會有此關聯。
This example shows the FindAssociation method from the InkLevel.xaml.cs file:
async void FindAssociation(DeviceInformation deviceInfo, string containerId)
{
// Specifically telling CreateFromIdAsync to retrieve the AppPackageFamilyName.
string packageFamilyName = "System.Devices.AppPackageFamilyName";
string[] containerPropertiesToGet = new string[] { packageFamilyName };
// CreateFromIdAsync needs braces on the containerId string.
string containerIdwithBraces = "{" + containerId + "}";
// Asynchronously getting the container information of the printer.
PnpObject containerInfo = await PnpObject.CreateFromIdAsync(PnpObjectType.DeviceContainer, containerIdwithBraces, containerPropertiesToGet);
// Printers could be associated with other device apps, only the ones with package family name
// matching this app's is associated with this app. The packageFamilyName for this app will be found in this app's packagemanifest
string appPackageFamilyName = "Microsoft.SDKSamples.DeviceAppForPrinters.CS_8wekyb3d8bbwe";
var prop = containerInfo.Properties;
// If the packageFamilyName of the printer container matches the one for this app, the printer is associated with this app.
string[] packageFamilyNameList = (string[])prop[packageFamilyName];
if (packageFamilyNameList != null)
{
for (int j = 0; j < packageFamilyNameList.Length; j++)
{
if (packageFamilyNameList[j].Equals(appPackageFamilyName))
{
AddToList(deviceInfo);
}
}
}
}
找到關聯時, FindAssociation 方法會使用 AddToList 方法,將裝置標識元新增至相關聯的裝置標識符清單。 這些標識符會儲存在名為 AssociatedPrinters的 ComboBox 中。
This example shows the AddToList method from the InkLevel.xaml.cs file:
void AddToList(DeviceInformation deviceInfo)
{
// Creating a new display item so the user sees the friendly name instead of the interfaceId.
ComboBoxItem item = new ComboBoxItem();
item.Content = deviceInfo.Properties["System.ItemNameDisplay"] as string;
item.DataContext = deviceInfo.Id;
AssociatedPrinters.Items.Add(item);
// If this is the first printer to be added to the combo box, select it.
if (AssociatedPrinters.Items.Count == 1)
{
AssociatedPrinters.SelectedIndex = 0;
}
}
步驟 2:顯示狀態
方法 GetInkStatus 會使用異步事件型模式,從印表機要求資訊。 這個方法會使用相關聯的裝置標識碼來取得可用來取得裝置狀態的裝置內容。 呼叫 printHelper.SendInkLevelQuery() 方法會啟動裝置查詢。 當回應傳回時, OnInkLevelReceived 會呼叫 方法並更新UI。
Note
此 C# 範例遵循與 JavaScript 範例不同的模式,因為 C# 可讓您將發送器傳送至 PrintHelperClass,以便將事件訊息張貼回 UI 線程。
This example shows the GetInkStatus and OnInkLevelReceived methods from the InkLevel.xaml.cs file:
void GetInkStatus(object sender, RoutedEventArgs e)
{
if (AssociatedPrinters.Items.Count > 0)
{
// Get the printer that the user has selected to query.
ComboBoxItem selectedItem = AssociatedPrinters.SelectedItem as ComboBoxItem;
// The interfaceId is retrieved from the detail field.
string interfaceId = selectedItem.DataContext as string;
try
{
// Unsubscribe existing ink level event handler, if any.
if (printHelper != null)
{
printHelper.OnInkLevelReceived -= OnInkLevelReceived;
printHelper = null;
}
object context = Windows.Devices.Printers.Extensions.PrintExtensionContext.FromDeviceId(interfaceId);printHelper.SendInkLevelQuery()
// Use the PrinterHelperClass to retrieve the bidi data and display it.
printHelper = new PrintHelperClass(context);
try
{
printHelper.OnInkLevelReceived += OnInkLevelReceived;
printHelper.SendInkLevelQuery();
rootPage.NotifyUser("Ink level query successful", NotifyType.StatusMessage);
}
catch (Exception)
{
rootPage.NotifyUser("Ink level query unsuccessful", NotifyType.ErrorMessage);
}
}
catch (Exception)
{
rootPage.NotifyUser("Error retrieving PrinterExtensionContext from InterfaceId", NotifyType.ErrorMessage);
}
}
}
private void OnInkLevelReceived(object sender, string response)
{
BidiOutput.Text = response;
}
列印協助程式類別會負責將 Bidi 查詢傳送至裝置並接收回應。
This example shows the SendInkLevelQuery method, and others, from the PrintHelperClass.cs file. 請注意,這裡只會顯示一些列印協助程序類別方法。 下載 列印設定和列印通知 範例,以查看完整的程序代碼。
public void SendInkLevelQuery()
{
printerQueue.OnBidiResponseReceived += OnBidiResponseReceived;
// Send the query.
string queryString = "\\Printer.Consumables";
printerQueue.SendBidiQuery(queryString);
}
private void OnBidiResponseReceived(object sender, PrinterQueueEventArgs responseArguments)
{
// Invoke the ink level event with appropriate data.
dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
OnInkLevelReceived(sender, ParseResponse(responseArguments));
});
}
private string ParseResponse(PrinterQueueEventArgs responseArguments)
{
if (responseArguments.StatusHResult == (int)HRESULT.S_OK)
return responseArguments.Response;
else
return InvalidHResult(responseArguments.StatusHResult);
}
private string InvalidHResult(int result)
{
switch (result)
{
case unchecked((int)HRESULT.E_INVALIDARG):
return "Invalid Arguments";
case unchecked((int)HRESULT.E_OUTOFMEMORY):
return "Out of Memory";
case unchecked((int)HRESULT.ERROR_NOT_FOUND):
return "Not found";
case (int)HRESULT.S_FALSE:
return "False";
case (int)HRESULT.S_PT_NO_CONFLICT:
return "PT No Conflict";
default:
return "Undefined status: 0x" + result.ToString("X");
}
}
Testing
您必須先使用裝置元數據連結到印表機,才能測試 UWP 裝置應用程式。
您需要印表機的裝置元數據套件複本,才能將裝置應用程式資訊新增至該套件。 如果您沒有裝置元數據,您可以使用 裝置元數據撰寫精靈 來建置它,如 步驟 2:為您的 UWP 裝置應用程式建立裝置元數據主題中所述。
Note
若要使用 裝置元數據撰寫精靈,您必須先安裝 Microsoft Visual Studio Professional、Microsoft Visual Studio Ultimate 或 獨立 SDK for Windows 8.1,才能完成本主題中的步驟。 安裝 Microsoft Visual Studio Express for Windows 會安裝不包含精靈的 SDK 版本。
下列步驟會建置您的應用程式並安裝裝置元數據。
啟用測試簽署。
按兩下 DeviceMetadataWizard.exe,從 %ProgramFiles[x86]%\Windows Kits\8.1\bin\x86 啟動 裝置元數據撰寫精靈
From the Tools menu, select Enable Test Signing.
重新啟動電腦
開啟方案 (.sln) 檔案來建置方案。 按 F7,或在載入範例後,從頂端功能表中選擇 建置->建置方案。
中斷連線並卸載印表機。 需要此步驟,Windows 會在下次偵測到裝置時讀取更新的裝置元數據。
編輯並儲存裝置元數據。 若要將裝置應用程式連結至您的裝置,您必須將裝置應用程式與裝置產生關聯。
Note
如果您尚未建立裝置元數據,請參閱 步驟 2:建立 UWP 裝置應用程式的裝置元數據。
如果 裝置元數據撰寫精靈 尚未開啟,請按兩下 DeviceMetadataWizard.exe,從 %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86 啟動。
點選 編輯裝置元資料。 這可讓您編輯現有的裝置元數據套件。
In the Open dialog box, locate the device metadata package associated with your UWP device app. (It has a devicemetadata-ms file extension.)
在 [指定 UWP 裝置應用程式資訊] 頁面上,於 [UWP 裝置應用程式] 方塊中輸入 Microsoft 市集應用程式資訊。 按下 [匯入 UWP 應用程式指令清單檔],自動輸入 套件名稱、發行者名稱,UWP 應用程式識別碼。
If your app is registering for printer notifications, fill out the Notification handlers box. In Event ID, enter the name of the print event handler. In Event Asset, enter the name of the file where that code resides.
When you're done, click Next until you get to the Finish page.
在 [檢閱裝置元數據套件] 頁面上,確定所有設定都正確無誤,然後選取 [將裝置元數據套件複製到本機計算機上的元數據存放區 複選框。 Then click Save.
重新連線印表機,讓 Windows 在裝置連線時讀取更新的裝置元數據。
Troubleshooting
問題:列舉與應用程式相關聯的裝置時找不到印表機
如果列舉相關聯的印表機時找不到印表機:
Possible cause: Test signing is not turned on. 如需開啟偵錯的相關資訊,請參閱本主題中的偵錯部分。
Possible cause: The app is not querying for the right Package Family Name. 檢查程式代碼中的套件系列名稱。 Open up package.appxmanifest in Microsoft Visual Studio and make sure that the package family name you are querying for matches the one in the Packaging tab, in the Package Family Name field.
Possible cause: The device metadata is not associated with the Package Family Name. 使用 [裝置元數據撰寫精靈 ] 開啟裝置元數據,並檢查套件系列名稱。 Start the wizard from %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86, by double-clicking DeviceMetadataWizard.exe.
問題:找到與應用程式相關聯的印表機,但無法查詢 Bidi 資訊
如果在列舉相關聯的印表機時找到印表機,但執行 Bidi 查詢時卻返回錯誤...
Possible cause: Wrong package family name. 檢查程式代碼中的套件系列名稱。 Open up package.appxmanifest in Visual Studio and make sure that the package family name you are querying for matches the one in the Packaging tab, in the Package Family Name field.
Possible cause: Printer was installed using a v3 printer, rather than a v4 printer. 若要查看已安裝的版本,請開啟 PowerShell 並輸入下列命令:
get-printer | Select Name, {(get-printerdriver -Name $_.DriverName).MajorVersion}