Поделиться через


Отображение состояния принтера в приложении устройства UWP

В Windows 8.1 пользователи могут проверить состояние принтера из современного пользовательского интерфейса приложения устройства UWP. В этом разделе используется версия C# параметров печати и пример уведомлений о печати , чтобы продемонстрировать, как запрашивать состояние принтера и отображать его. Дополнительные сведения о приложениях устройств UWP см. в статье "Знакомство с приложениями устройств UWP".

Версия на C# примера настроек печати и уведомлений о печати использует страницу InkLevel.xaml для демонстрации получения состояния принтера (в данном случае уровня чернил) и его отображения. Вспомогательный класс для печати используется для создания контекста устройства (IPrinterExtensionContext) и выполнения запросов к устройству. Файл PrinterHelperClass.cs находится в проекте DeviceAppForPrintersLibrary и использует API, определенные в проекте PrinterExtensionLibrary . Библиотека расширений принтера предоставляет удобный способ доступа к интерфейсам расширения принтера драйвера печати версии 4. Дополнительные сведения см. в обзоре библиотеки расширений принтера.

Примечание.

Примеры кода, показанные в этом разделе, основаны на версии C# параметров печати и образца уведомлений о печати . Этот пример также доступен в JavaScript и C++. Обратите внимание, что поскольку C++ может напрямую получить доступ к COM, версия C++ примера не включает проекты библиотеки кода. Скачайте примеры, чтобы просмотреть последние версии кода.

Предпосылки

Прежде чем начать:

  1. Убедитесь, что принтер установлен с помощью драйвера печати версии 4. Дополнительные сведения см. в статье "Разработка драйверов печати версии 4".

  2. Настройте компьютер разработки. Сведения о скачивании средств и создании учетной записи разработчика см. в статье "Начало работы ".

  3. Свяжите приложение с магазином. См. шаг 1. Создание приложения устройства UWP для получения сведений об этом.

  4. Создайте метаданные устройства для вашего принтера, которые будут связаны с вашим приложением. Дополнительные сведения см. в шаге 2. Создание метаданных устройства .

  5. Если вы пишете приложение с помощью C# или JavaScript, добавьте проекты PrinterExtensionLibrary и DeviceAppForPrintersLibrary в решение приложения устройства UWP. Вы можете найти каждый из этих проектов в параметрах печати и образце уведомлений о печати .

    Примечание.

    Так как C++ может получить доступ к COM напрямую, приложения C++ не требуют отдельной библиотеки для работы с контекстом устройства принтера на основе COM.

Шаг 1. Поиск принтера

Перед созданием контекста устройства приложение должно определить идентификатор устройства принтера. Для этого в примере используется EnumerateAssociatedPrinters метод для поиска по всем принтерам, подключенным к компьютеру. Затем он проверяет контейнер для каждого принтера и ищет связь, сравнивая свойство PackageFamilyName каждого контейнера.

Примечание.

System.Devices.AppPackageFamilyName для устройств, связанных с приложением, можно найти на вкладке "Упаковка " в конструкторе манифестов в Microsoft Visual Studio.

В этом примере показан EnumerateAssociatedPrinters метод из файла InkLevel.xaml.cs :

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. Эта связь существует, когда приложение и принтер определены в метаданных устройства на локальном компьютере.

В этом примере показан FindAssociation метод из файла InkLevel.xaml.cs :

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 используется для добавления идентификатора устройства в список ассоциированных идентификаторов устройств. Эти идентификаторы хранятся в comboBox с именем AssociatedPrinters.

В этом примере показан AddToList метод из файла InkLevel.xaml.cs :

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, и обновляется пользовательский интерфейс.

Примечание.

Этот пример C# следует другому шаблону, отличному от примера JavaScript, так как C# позволяет отправлять диспетчер в PrintHelperClass, чтобы отправлять сообщения о событиях обратно в поток пользовательского интерфейса.

В этом примере показаны методы GetInkStatus и OnInkLevelReceived из файла InkLevel.xaml.cs.

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 на устройство и получении ответа.

В этом примере показан метод SendInkLevelQuery и другие из файла PrintHelperClass.cs. Обратите внимание, что здесь показаны только некоторые вспомогательные методы класса печати. Скачайте пример параметров печати и уведомлений о печати , чтобы просмотреть полный код.

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");
    }
}

Тестирование

Прежде чем протестировать приложение устройства UWP, его необходимо связать с принтером с помощью метаданных устройства.

Чтобы добавить информацию о приложении устройства, вам нужна копия пакета метаданных устройства для вашего принтера. Если у вас нет метаданных устройства, его можно создать с помощью мастера разработки метаданных устройств, как описано в разделе шаг 2. Создание метаданных устройства для приложения устройства UWP.

Примечание.

Чтобы использовать мастер разработки метаданных устройств, необходимо установить Microsoft Visual Studio Professional, Microsoft Visual Studio Ultimate или автономный пакет SDK для Windows 8.1, прежде чем выполнить действия, описанные в этом разделе. Установка Microsoft Visual Studio Express для Windows устанавливает версию пакета SDK, которая не включает мастер.

Следующие шаги по созданию приложения и установке метаданных устройства.

  1. Включите тестовую подпись.

    1. Запустите мастер создания метаданных устройства из %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86, дважды щелкнув DeviceMetadataWizard.exe

    2. В меню "Инструменты" выберите "Включить тестовую подпись".

  2. Перезагрузка компьютера

  3. Создайте решение, открыв файл решения (.sln). Нажмите клавишу F7 или перейдите к решению сборки> из верхнего меню после загрузки примера.

  4. Отключите и удалите принтер. Этот шаг необходим, чтобы Windows считывала обновленные метаданные устройства при следующем обнаружении устройства.

  5. Изменение и сохранение метаданных устройства. Чтобы подключить приложение устройства к вашему устройству, необходимо установить между ними связь.

    Примечание.

    Если вы еще не создали метаданные устройства, см. шаг 2. Создание метаданных устройства для приложения устройства UWP.

    1. Если мастер разработки метаданных устройства еще не открыт, запустите его с %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86, дважды щелкнув DeviceMetadataWizard.exe.

    2. Нажмите кнопку "Изменить метаданные устройства". Это позволит изменить существующий пакет метаданных устройства.

    3. В диалоговом окне "Открыть" найдите пакет метаданных устройства, связанный с приложением устройства UWP. (Он имеет расширение файла devicemetadata-ms .)

    4. На странице сведений о приложении устройства UWP введите сведения о приложении Microsoft Store в поле приложения устройства UWP . Щелкните импорт файла манифеста приложения UWP , чтобы автоматически ввести имя пакета, имя издателя и идентификатор приложения UWP.

    5. Если приложение регистрируется для уведомлений принтера, заполните поле обработчиков уведомлений . Введите имя обработчика событий печати в идентификаторе события. В ресурсе событий введите имя файла, в котором находится этот код.

    6. По завершении нажмите кнопку "Далее ", пока не перейдете на страницу "Готово ".

    7. На странице "Проверка пакета метаданных устройства " убедитесь, что все параметры верны и установите флажок "Копировать пакет метаданных устройства" в хранилище метаданных на локальном компьютере . Затем нажмите кнопку Сохранить.

  6. Повторно подключите принтер, чтобы Windows считывала обновленные метаданные устройства при подключении устройства.

Устранение неполадок

Проблема. Не удается найти принтер при перечислении устройств, связанных с приложением

Если принтер не найден при перечислении связанных принтеров:

  • Возможные причины: Проверка подписи не включена. Подробнее о включении см. в разделе "Отладка" этой темы.

  • Возможные причины: Приложение не запрашивает правильное имя семейства пакетов. Проверьте имя семейства пакетов в вашем коде. Откройте package.appxmanifest в Microsoft Visual Studio и убедитесь, что имя семейства пакетов, которое вы запрашиваете, соответствует имени на вкладке Упаковка в поле "Имя семейства пакетов".

  • Возможные причины: Метаданные устройства не связаны с именем семейства пакетов. Используйте мастер создания метаданных устройства, чтобы открыть метаданные устройства и проверить имя семейства пакетов. Запустите мастер из %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86, дважды щелкнув DeviceMetadataWizard.exe.

Проблема: найден принтер, связанный с приложением, но не может запрашивать сведения о Bidi

Если принтер найден при перечислении связанных принтеров, но запрос Bidi возвращает ошибку...

  • Возможные причины: Неправильное имя семейства пакетов. Проверьте имя семейства пакетов в коде. Откройте package.appxmanifest в Visual Studio и убедитесь, что имя семейства пакетов, которое вы запрашиваете, соответствует указанному на вкладке Упаковка в поле «Имя семейства пакетов».

  • Возможные причины: Принтер был установлен с помощью принтера версии 3, а не принтера версии 4. Чтобы узнать, какая версия установлена, откройте PowerShell и введите следующую команду:

    get-printer | Select Name, {(get-printerdriver -Name $_.DriverName).MajorVersion}
    

Разработка драйверов печати версии 4

Интерфейсы расширения принтера (драйвер печати версии 4)

Двунаправленная связь

Начало работы с приложениями UWP

Создание приложения устройства UWP (пошаговое руководство)

Создание метаданных устройства для приложения устройства UWP (пошаговое руководство)