Important
设备元数据已弃用,并将在 Windows 的将来版本中删除。 有关替代功能的信息,请参阅驱动程序包容器元数据。
在 Windows 8.1 中,打印机的 UWP 设备应用可以管理打印作业。 本主题使用 打印作业管理和打印机维护 示例的 C# 版本来演示如何创建打印作业视图、监视这些作业,并在必要时取消作业。 若要了解有关 UWP 设备应用的一般详细信息,请参阅 UWP 设备应用简介。
打印作业管理和打印机维护示例的 C# 版本演示了使用 DeviceAppForPrinters2 项目中DeviceMaintenance.xaml.cs文件的打印机维护。 To work with Bidi, the sample uses the printer extension library in the PrinterExtensionLibrary project. 打印机扩展库提供了一种访问 v4 打印驱动程序的打印机扩展接口的便捷方法。 有关详细信息,请参阅 打印机扩展库概述。
本主题中显示的代码示例基于 打印作业管理和打印机维护 示例的 C# 版本。 此示例在 JavaScript 和 C++中也可用。 请注意,由于C++可以直接访问 COM,因此示例C++版本不包括代码库项目。 下载示例以查看最新版本的代码。
管理打印作业
Windows 8.1 introduces new printer extension interfaces in the v4 printer driver that you can use for managing print jobs: IPrinterQueue2, IPrinterQueueView, IPrinterQueueViewEvent, IPrintJob, and IPrintJobCollection. 通过这些接口,可以监视和取消打印作业。 有关详细信息,请参阅打印作业管理(v4 打印机驱动程序)。
C# 和 JavaScript 应用不能直接使用 COM API。 如果要编写 C# 或 JavaScript UWP 设备应用,请使用打印机扩展库访问这些接口(如本主题所示)。
Prerequisites
准备工作:
请确保使用 v4 打印驱动程序安装打印机。 有关详细信息,请参阅 开发 v4 打印驱动程序。
设置开发电脑。 See Getting started for info about downloading the tools and creating a developer account.
将应用与应用商店相关联。 有关该应用的信息,请参阅 “创建 UWP 设备应用 ”。
为将它与应用关联的打印机创建设备元数据。 有关此内容的详细信息,请参阅 “创建设备元数据 ”。
为应用的主页生成 UI。 可以从“开始”启动启动所有 UWP 设备应用,其中将显示它们全屏。 使用“开始”体验以与设备的特定品牌和功能匹配的方式突出显示产品或服务。 它可以使用的 UI 控件类型没有特殊限制。 若要开始设计全屏体验,请参阅 Microsoft应用商店设计原则。
If you're writing your app with C# or JavaScript, add the PrinterExtensionLibrary project to your UWP device app solution. 可以在 打印作业管理和打印机维护 示例中找到此项目。
由于C++可以直接访问 COM,C++应用不需要单独的库来处理基于 COM 的打印机设备上下文。
步骤 1:查找打印机
在应用可以管理打印作业之前,它必须先找到具有打印作业的打印机。 为此, 打印作业管理和打印机维护 示例包括一个名为 PrinterEnumeration (在 PrinterEnumeration.cs 文件中)的方便类。 此类通过设备元数据查找与应用关联的所有打印机,并返回一个对象列表 PrinterInfo ,其中包含每个打印机的名称和设备 ID。
This example shows the EnumeratePrinters_Click method in the PrintJobManagement.xaml.cs file. 它演示示例如何使用 PrinterEnumeration 该类获取关联的打印机列表。
private async void EnumeratePrinters_Click(object sender, RoutedEventArgs e)
{
try
{
rootPage.NotifyUser("Enumerating printers. Please wait", NotifyType.StatusMessage);
// Retrieve the running app's package family name, and enumerate associated printers.
string currentPackageFamilyName = Windows.ApplicationModel.Package.Current.Id.FamilyName;
// Enumerate associated printers.
PrinterEnumeration pe = new PrinterEnumeration(currentPackageFamilyName);
List<PrinterInfo> associatedPrinters = await pe.EnumeratePrintersAsync();
// Update the data binding source on the combo box that displays the list of printers.
PrinterComboBox.ItemsSource = associatedPrinters;
if (associatedPrinters.Count > 0)
{
PrinterComboBox.SelectedIndex = 0;
rootPage.NotifyUser(associatedPrinters.Count + " printers enumerated", NotifyType.StatusMessage);
}
else
{
rootPage.NotifyUser(DisplayStrings.NoPrintersEnumerated, NotifyType.ErrorMessage);
}
}
catch (Exception exception)
{
rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
}
}
For more info about the PrinterEnumeration and PrinterInfo classes, see the PrinterEnumeration.cs file.
步骤 2:获取打印机队列
Once you've identified the printer having the print jobs that you want to manage, create a view of the print jobs, with object based on the IPrinterQueueView interface (defined in the PrinterExtensionTypes.cs file of the PrinterExtensionLibrary project). 在 打印作业管理和打印机维护 示例中,每次打印机选择更改时,都会命名 currentPrinterQueueView 并重新创建此对象。
在方法中 Printer_SelectionChanged ,示例首先使用对象 PrinterInfo 创建名为 context 的打印机扩展上下文对象。 然后,它使用 GetPrinterQueueView 方法 context 创建 currentPrinterQueueView 对象。 最后,添加事件处理程序来处理 currentPrinterQueueView's OnChanged 事件。
This example shows the Printer_SelectionChanged method in the PrintJobManagement.xaml.cs file. 它演示如何创建基于 IPrinterQueueView的打印机队列视图对象。
private void Printer_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
// Remove the current printer queue view (if any) before displaying the new view.
if (currentPrinterQueueView != null)
{
currentPrinterQueueView.OnChanged -= OnPrinterQueueViewChanged;
currentPrinterQueueView = null;
}
// Retrieve a COM IPrinterExtensionContext object, using the static WinRT factory.
// Then instantiate one "PrinterExtensionContext" object that allows operations on the COM object.
PrinterInfo queue = (PrinterInfo)PrinterComboBox.SelectedItem;
Object comContext = Windows.Devices.Printers.Extensions.PrintExtensionContext.FromDeviceId(queue.DeviceId);
PrinterExtensionContext context = new PrinterExtensionContext(comContext);
// Display the printer queue view.
const int FirstPrintJobEnumerated = 0;
const int LastPrintJobEnumerated = 10;
currentPrinterQueueView = context.Queue.GetPrinterQueueView(FirstPrintJobEnumerated, LastPrintJobEnumerated);
currentPrinterQueueView.OnChanged += OnPrinterQueueViewChanged;
}
catch (Exception exception)
{
rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
}
}
此外,每当打印作业视图发生更改时,事件处理程序将调用该方法 OnPrinterQueueViewChanged 。 此方法负责使用对象的 IEnumerable 集合IPrintJob重新绑定PrintJobListBox。 The collection is passed to the method via the PrinterQueueViewEventArgs object, which is defined in the PrinterExtensionTypes.cs file.
This example shows the OnPrinterQueueViewChanged method in the PrintJobManagement.xaml.cs file.
private async void OnPrinterQueueViewChanged(object sender, PrinterQueueViewEventArgs e)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
// Update the data binding on the ListBox that displays print jobs.
PrintJobListBox.ItemsSource = e.Collection;
if (PrintJobListBox.Items.Count > 0)
{
// If there are print jobs in the current view, mark the first job as selected.
PrintJobListBox.SelectedIndex = 0;
}
});
}
步骤 3:显示打印作业状态
由于绑定到 PrintJobListBox 对象的集合 IPrintJob ,因此显示作业的状态非常简单。 所选打印作业被强制转换为对象 IPrintJob ,然后使用该对象的属性填充 PrintJobDetails TextBox。
在 打印作业管理和打印机维护 示例中,每次选择不同的打印作业时,都会显示打印作业状态。 此方法负责 PrintJob_SelectionChanged 此更新。
This example shows the PrintJob_SelectionChanged method in the PrintJobManagement.xaml.cs file. 它显示如何基于 IPrintJob 对象显示打印作业的状态。
private void PrintJob_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
// Display details of the selected print job.
IPrintJob job = (IPrintJob)PrintJobListBox.SelectedItem;
if (job != null)
{
PrintJobDetails.Text =
"Details of print job: " + job.Name + "\r\n" +
"Pages printed: " + job.PrintedPages + "/" + job.TotalPages + "\r\n" +
"Submission time: " + job.SubmissionTime + "\r\n" +
"Job status: " + DisplayablePrintJobStatus.ToString(job.Status);
}
else
{
PrintJobDetails.Text = "Please select a print job";
}
}
catch (Exception exception)
{
rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
}
}
为了帮助显示打印作业状态说明,该方法 PrintJob_SelectionChanged 使用静态字典命名 printJobStatusDisplayNames,以帮助显示用户友好的文本格式的作业状态说明。
This example shows the DisplayablePrintJobStatus class in the PrintJobManagement.xaml.cs file. 此类包含由该 PrintJob_SelectionChanged类使用的静态成员。
internal class DisplayablePrintJobStatus
{
/// <summary>
/// Converts the PrintJobStatus bit fields to a display string.
/// </summary>
internal static string ToString(PrintJobStatus printJobStatus)
{
StringBuilder statusString = new StringBuilder();
// Iterate through each of the PrintJobStatus bits that are set and convert it to a display string.
foreach (var printJobStatusDisplayName in printJobStatusDisplayNames)
{
if ((printJobStatusDisplayName.Key & printJobStatus) != 0)
{
statusString.Append(printJobStatusDisplayName.Value);
}
}
int stringlen = statusString.Length;
if (stringlen > 0)
{
// Trim the trailing comma from the string.
return statusString.ToString(0, stringlen - 1);
}
else
{
// If no print job status field was set, display "Not available".
return "Not available";
}
}
/// <summary>
/// Static constructor that initializes the display name for the PrintJobStatus field.
/// </summary>
static DisplayablePrintJobStatus()
{
printJobStatusDisplayNames = new Dictionary<PrintJobStatus, string>();
printJobStatusDisplayNames.Add(PrintJobStatus.Paused, "Paused,");
printJobStatusDisplayNames.Add(PrintJobStatus.Error, "Error,");
printJobStatusDisplayNames.Add(PrintJobStatus.Deleting, "Deleting,");
printJobStatusDisplayNames.Add(PrintJobStatus.Spooling, "Spooling,");
printJobStatusDisplayNames.Add(PrintJobStatus.Printing, "Printing,");
printJobStatusDisplayNames.Add(PrintJobStatus.Offline, "Offline,");
printJobStatusDisplayNames.Add(PrintJobStatus.PaperOut, "Out of paper,");
printJobStatusDisplayNames.Add(PrintJobStatus.Printed, "Printed,");
printJobStatusDisplayNames.Add(PrintJobStatus.Deleted, "Deleted,");
printJobStatusDisplayNames.Add(PrintJobStatus.BlockedDeviceQueue, "Blocked device queue,");
printJobStatusDisplayNames.Add(PrintJobStatus.UserIntervention, "User intervention required,");
printJobStatusDisplayNames.Add(PrintJobStatus.Restarted, "Restarted,");
printJobStatusDisplayNames.Add(PrintJobStatus.Complete, "Complete,");
printJobStatusDisplayNames.Add(PrintJobStatus.Retained, "Retained,");
}
/// <summary>
/// Private constructor to prevent default instantiation.
/// </summary>
private DisplayablePrintJobStatus() { }
/// <summary>
/// Contains the mapping between PrintJobStatus fields and display strings.
/// </summary>
private static Dictionary<PrintJobStatus, string> printJobStatusDisplayNames;
}
步骤 4:取消打印作业
与显示打印作业状态类似,当你有对象 IPrintJob 时,取消打印作业非常简单。 该 IPrintJob 类提供一个 RequestCancel 方法,用于启动相应打印作业的取消。 此示例的方法对此 CancelPrintJob_Click 进行了演示。
This example shows the CancelPrintJob_Click method in the PrintJobManagement.xaml.cs file.
private void CancelPrintJob_Click(object sender, RoutedEventArgs e)
{
try
{
IPrintJob job = (IPrintJob)PrintJobListBox.SelectedItem;
job.RequestCancel();
}
catch (Exception exception)
{
rootPage.NotifyUser("Caught an exception: " + exception.Message, NotifyType.ErrorMessage);
}
}
Testing
在测试 UWP 设备应用之前,必须使用设备元数据将其链接到打印机。
需要打印机的设备元数据包的副本,才能将设备应用信息添加到其中。 如果没有设备元数据,可以使用 设备元数据创作向导 生成它,如主题 “为 UWP 设备应用创建设备元数据”中所述。
若要使用 设备元数据创作向导,必须先安装 Microsoft Visual Studio Professional、Microsoft Visual Studio Ultimate 或 适用于 Windows 8.1 的独立 SDK,然后才能完成本主题中的步骤。 安装 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 将在下次检测到设备时读取更新的设备元数据。
编辑和保存设备元数据。 若要将设备应用链接到设备,必须将设备应用与设备相关联。
如果尚未创建设备元数据,请参阅 为 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 应用 ID。
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 在设备连接时读取更新的设备元数据。