Share via


Cómo mostrar el estado de la impresora en una aplicación de dispositivo para UWP

En Windows 8.1, los usuarios pueden comprobar el estado de su impresora desde la interfaz de usuario moderna de una aplicación de dispositivo para UWP. En este tema se usa la versión de C# del ejemplo Configuración de impresión y notificaciones de impresión para mostrar cómo consultar el estado de la impresora y mostrarlo. Para obtener más información sobre las aplicaciones de dispositivos para UWP en general, consulte Conocer las aplicaciones de dispositivos para UWP.

La versión de C# del ejemplo Configuración de impresión y notificaciones de impresión usa la página InkLevel.xaml para mostrar cómo obtener el estado de la impresora (en este caso, el nivel de tinta) y mostrarlo. Se usa una clase auxiliar de impresión para crear un contexto de dispositivo (IPrinterExtensionContext) y realizar las consultas del dispositivo. El archivo PrinterHelperClass.cs se encuentra en el proyecto DeviceAppForPrintersLibrary y usa las API definidas en el proyecto PrinterExtensionLibrary. La biblioteca de extensiones de impresora proporciona una manera cómoda de acceder a las interfaces de extensión de impresora del controlador de impresión v4. Para obtener más información, consulte Información general sobre la biblioteca de extensiones de impresora.

Nota:

Los ejemplos de código que se muestran en este tema se basan en la versión de C# del ejemplo Configuración de impresión y notificaciones de impresión. Este ejemplo también está disponible en JavaScript y C++. Tenga en cuenta que, dado que C++ puede acceder directamente a COM, la versión de C++ del ejemplo no incluye proyectos de biblioteca de código. Descargue los ejemplos para ver las versiones más recientes del código.

Requisitos previos

Antes de comenzar:

  1. Asegúrese de que la impresora esté instalada con un controlador de impresión v4. Para obtener más información, consulte Desarrollo de controladores de impresión v4.

  2. Configure su equipo de desarrollo. Consulte Introducción para obtener información sobre cómo descargar las herramientas y crear una cuenta de desarrollador.

  3. Asocie la aplicación con la tienda. Consulte Paso 1: Creación de una aplicación de dispositivo para UWP para obtener información.

  4. Cree metadatos de dispositivo para la impresora que la asocien con la aplicación. Consulte Paso 2: Creación de metadatos de dispositivo para obtener más información.

  5. Si está escribiendo su aplicación con C# o JavaScript, agregue los proyectos PrinterExtensionLibrary y DeviceAppForPrintersLibrary a la solución de aplicación de dispositivo para UWP. Puede encontrar cada uno de estos proyectos en el ejemplo Configuración de impresión y notificaciones de impresión.

    Nota:

    Dado que C++ puede acceder directamente a COM, las aplicaciones de C++ no requieren una biblioteca independiente para trabajar con el contexto del dispositivo de impresora basado en COM.

Paso 1: Búsqueda de la impresora

Para poder crear un contexto de dispositivo, la aplicación debe determinar el identificador de dispositivo de la impresora. Para ello, el ejemplo usa el método EnumerateAssociatedPrinters para buscar en todas las impresoras conectadas al equipo. A continuación, comprueba el contenedor de cada impresora y busca una asociación comparando la propiedad PackageFamilyName de cada contenedor.

Nota:

System.Devices.AppPackageFamilyName para dispositivos asociados a la aplicación se pueden encontrar en la pestaña Empaquetado del Diseñador de manifiestos de Microsoft Visual Studio.

En este ejemplo se muestra el método EnumerateAssociatedPrinters del archivo 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());
    }
}

El método FindAssociation, al que se llama mediante EnumerateAssociatedPrinters, comprueba si una impresora está asociada a la aplicación actual. En otras palabras, este método comprueba si la aplicación es una aplicación de dispositivo para UWP. Esta asociación existe cuando la aplicación y la impresora se definen en los metadatos del dispositivo en el equipo local.

En este ejemplo se muestra el método FindAssociation del archivo 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);
            }
        }
    }
}

Cuando se encuentra una asociación, el método FindAssociation usa el método AddToList para agregar el identificador de dispositivo a una lista de identificadores de dispositivo asociados. Estos identificadores se almacenan en un ComboBox denominado AssociatedPrinters.

En este ejemplo se muestra el método AddToList del archivo 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;
    }
}

Paso 2: Mostrar el estado

El método GetInkStatus usa un patrón asincrónico basado en eventos para solicitar información de la impresora. Este método usa un identificador de dispositivo asociado para obtener un contexto de dispositivo que se puede usar para obtener el estado del dispositivo. La llamada al método printHelper.SendInkLevelQuery() inicia la consulta del dispositivo. Cuando se devuelve la respuesta, se llama al método OnInkLevelReceived y se actualiza la interfaz de usuario.

Nota:

Este ejemplo de C# sigue un patrón diferente al ejemplo de JavaScript, ya que C# le permite enviar un distribuidor a PrintHelperClass para que pueda volver a publicar los mensajes de evento en el subproceso de la interfaz de usuario.

En este ejemplo se muestran los métodos GetInkStatus y OnInkLevelReceived del archivo 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;
}

La clase auxiliar de impresión se encarga de enviar la consulta bidi al dispositivo y recibir la respuesta.

En este ejemplo se muestra el método SendInkLevelQuery y otros, del archivo PrintHelperClass.cs. Tenga en cuenta que aquí solo se muestran algunos de los métodos de la clase auxiliar de impresión. Descargue el ejemplo Configuración de impresión y notificaciones de impresión para ver el código completo.

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

Prueba

Para poder probar la aplicación de dispositivo para UWP, debe estar vinculada a la impresora mediante metadatos del dispositivo.

Necesita una copia del paquete de metadatos del dispositivo para la impresora, para agregarle la información de la aplicación del dispositivo. Si no tiene metadatos de dispositivo, puede crearlos mediante el Asistente para creación de metadatos de dispositivo, tal como se describe en el tema Paso 2: Creación de metadatos de dispositivo para la aplicación de dispositivo para UWP.

Nota:

Para usar el Asistente para creación de metadatos de dispositivo, debe instalar Microsoft Visual Studio Professional, Microsoft Visual Studio Ultimate o el SDK independiente para Windows 8.1, antes de completar los pasos de este tema. La instalación de Microsoft Visual Studio Express para Windows instala una versión del SDK que no incluye el asistente.

Los pasos siguientes permiten crear la aplicación e instalar los metadatos del dispositivo.

  1. Habilite la firma de pruebas.

    1. Inicie el Asistente para creación de metadatos de dispositivo desde %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86, haciendo doble clic en DeviceMetadataWizard.exe

    2. En el menú Herramientas, seleccione Habilitar firma de pruebas.

  2. Reinicie el equipo.

  3. Cree la solución abriendo el archivo de solución (.sln). Pulse F7 o vaya a Crear->Crear solución en el menú superior después de cargar el ejemplo.

  4. Desconecte y desinstale la impresora. Este paso es necesario para que Windows lea los metadatos del dispositivo actualizado la próxima vez que se detecte el dispositivo.

  5. Edite y guarde los metadatos del dispositivo. Para vincular la aplicación de dispositivo al dispositivo, debe asociar la aplicación de dispositivo al dispositivo.

    Nota:

    Si aún no ha creado los metadatos del dispositivo, consulte Paso 2: Creación de metadatos de dispositivo para la aplicación de dispositivo para UWP.

    1. Si el Asistente para creación de metadatos de dispositivo todavía no está abierto, inícielo desde %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86, haciendo doble clic en DeviceMetadataWizard.exe.

    2. Haga clic en Editar metadatos del dispositivo. Esto le permitirá editar el paquete de metadatos del dispositivo existente.

    3. En el cuadro de diálogo Abrir, busque el paquete de metadatos del dispositivo asociado a la aplicación de dispositivo para UWP. (Tiene una extensión de archivo devicemetadata-ms).

    4. En la página Especificar información de la aplicación de dispositivo para UWP, escriba la información de la aplicación de Microsoft Store en el cuadro Aplicación de dispositivo para UWP. Haga clic en Importar archivo de manifiesto de aplicación para UWP para introducir automáticamente el Nombre del paquete, el Nombre del publicador y el Identificador de la aplicación para UWP.

    5. Si la aplicación está registrada para recibir notificaciones de impresora, rellene el cuadro Controladores de notificaciones. En Identificador de evento, escriba el nombre del controlador de eventos de impresión. En Recurso de evento, escriba el nombre del archivo donde reside ese código.

    6. Cuando haya terminado, haga clic en Siguiente hasta llegar a la página Finalizar.

    7. En la página Revisar el paquete de metadatos del dispositivo, asegúrese de que toda la configuración sea correcta y active la casilla Copiar el paquete de metadatos del dispositivo en el almacén de metadatos del equipo local. A continuación, haga clic en Save(Guardar).

  6. Vuelva a conectar la impresora para que Windows lea los metadatos del dispositivo actualizados cuando se conecte el dispositivo.

Solución de problemas

Problema: no se encuentra la impresora al enumerar dispositivos asociados a la aplicación

Si la impresora no se encuentra al enumerar las impresoras asociadas:

  • Causa posible: la firma de prueba no está activada. Consulte la sección Depuración de este tema para obtener información sobre cómo activarla.

  • Causa posible: la aplicación no está consultando el nombre de familia de paquete adecuado. Compruebe el nombre de familia del paquete en el código. Abra package.appxmanifest en Microsoft Visual Studio y asegúrese de que el nombre de familia de paquete que está consultando coincide con el de la pestaña Empaquetado, en el campo Nombre de familia de paquete.

  • Causa posible: los metadatos del dispositivo no están asociados con el nombre de familia de paquete. Use el Asistente para creación de metadatos de dispositivo para abrir los metadatos del dispositivo y comprobar el nombre de familia de paquete. Inicie el asistente desde %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86, haciendo doble clic en DeviceMetadataWizard.exe.

Problema: se encontró la impresora asociada a la aplicación, pero no puede consultar la información de Bidi.

Si se encontró la impresora al enumerar las impresoras asociadas, pero una consulta bidi devuelve un error...

  • Causa posible: nombre de familia de paquete incorrecto. Compruebe el nombre de familia del paquete en el código. Abra package.appxmanifest en Visual Studio y asegúrese de que el nombre de familia de paquete que está consultando coincide con el de la pestaña Empaquetado, en el campo Nombre de familia de paquete.

  • Causa posible: la impresora se instaló con una impresora v3, en lugar de una impresora v4. Para ver qué versión está instalada, abra PowerShell y escriba el siguiente comando:

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

Desarrollo de controladores de impresión v4

Interfaces de extensión de impresora (controlador de impresión v4)

Comunicaciones bidireccionales

Introducción a las aplicaciones para UWP

Creación de una aplicación de dispositivo para UWP (guía paso a paso)

Creación de metadatos de dispositivo para una aplicación de dispositivo para UWP (guía paso a paso)