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


Отображение состояния принтера в приложении устройства 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\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 (пошаговое руководство)