다음을 통해 공유


UWP 디바이스 앱에서 프린터 상태 표시하는 방법

Windows 8.1에서 사용자는 UWP 디바이스 앱의 최신 UI에서 프린터 상태 검사 수 있습니다. 이 항목에서는 인쇄 설정 및 인쇄 알림 샘플의 C# 버전을 사용하여 프린터 상태 쿼리하고 표시하는 방법을 보여 줍니다. 일반적으로 UWP 디바이스 앱에 대한 자세한 내용은 UWP 디바이스 앱 모임을 참조 하세요.

인쇄 설정 및 인쇄 알림 샘플의 C# 버전은 InkLevel.xaml 페이지를 사용하여 프린터 상태(이 경우 잉크 수준)를 가져와서 표시하는 방법을 보여 줍니다. 인쇄 도우미 클래스는 디바이스 컨텍스트(IPrinterExtensionContext)를 만들고 디바이스 쿼리를 수행하는 데 사용됩니다. PrinterHelperClass.cs 파일은 DeviceAppForPrintersLibrary 프로젝트에 있으며 PrinterExtensionLibrary 프로젝트에 정의된 API를 사용합니다. 프린터 확장 라이브러리는 v4 인쇄 드라이버의 프린터 확장 인터페이스에 액세스하는 편리한 방법을 제공합니다. 자세한 내용은 프린터 확장 라이브러리 개요참조하세요.

참고 항목

이 항목에 표시된 코드 예제는 인쇄 설정 및 인쇄 알림 샘플의 C# 버전을 기반으로 합니다 . 이 샘플은 JavaScript 및 C++에서도 사용할 수 있습니다. C++는 COM에 직접 액세스할 수 있으므로 샘플의 C++ 버전에는 코드 라이브러리 프로젝트가 포함되지 않습니다. 샘플을 다운로드하여 최신 버전의 코드를 확인합니다.

필수 조건

시작하기 전에 다음을 수행합니다.

  1. v4 인쇄 드라이버를 사용하여 프린터가 설치되어 있는지 확인합니다. 자세한 내용은 v4 인쇄 드라이버 개발을 참조 하세요.

  2. 개발 PC를 설정합니다. 도구 다운로드 및 개발자 계정 만들기에 대한 자세한 내용은 시작 정보를 참조하세요.

  3. 스토어와 앱을 연결합니다. 자세한 내용은 1단계: UWP 디바이스 앱 만들기를 참조하세요.

  4. 프린터를 앱과 연결하는 디바이스 메타데이터를 만듭니다. 자세한 내용은 2단계: 디바이스 메타데이터 만들기를 참조하세요.

  5. C# 또는 JavaScript를 사용하여 앱을 작성하는 경우 PrinterExtensionLibraryDeviceAppForPrintersLibrary 프로젝트를 UWP 디바이스 앱 솔루션에 추가합니다. 인쇄 설정 및 인쇄 알림 샘플에서 이러한 각 프로젝트를 찾을 수 있습니다 .

    참고 항목

    C++는 COM에 직접 액세스할 수 있으므로 C++ 앱은 COM 기반 프린터 디바이스 컨텍스트를 사용하기 위해 별도의 라이브러리가 필요하지 않습니다.

1단계: 프린터 찾기

디바이스 컨텍스트를 만들려면 앱에서 프린터의 디바이스 ID를 결정해야 합니다. 이를 위해 샘플에서는 이 메서드를 EnumerateAssociatedPrinters 사용하여 PC에 연결된 모든 프린터를 검색합니다. 그런 다음 각 프린터의 컨테이너를 검사 각 컨테이너의 PackageFamilyName 속성을 비교하여 연결을 찾습니다.

참고 항목

앱과 연결된 디바이스의 System.Devices.AppPackageFamilyName은 Microsoft Visual Studio 매니페스트 디자이너의 패키징 탭에서 찾을 수 있습니다.

이 예제에서는 InkLevel.xaml.cs 파일의 메서드를 보여줍니다EnumerateAssociatedPrinters.

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

호출된 EnumerateAssociatedPrinters메서드는 FindAssociation 프린터가 현재 애플리케이션과 연결된 경우 검사. 즉, 이 메서드는 앱이 UWP 디바이스 앱인지 검사. 이 연결은 앱과 프린터가 로컬 PC의 디바이스 메타데이터에 정의되어 있을 때 존재합니다.

이 예제에서는 InkLevel.xaml.cs 파일의 메서드를 보여줍니다FindAssociation.

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 연결된 디바이스 ID 목록에 디바이스 ID를 추가합니다. 이러한 ID는 ComboBox AssociatedPrinters에 저장됩니다.

이 예제에서는 InkLevel.xaml.cs 파일의 메서드를 보여줍니다AddToList.

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 비동기 이벤트 기반 패턴을 사용하여 프린터에서 정보를 요청합니다. 이 메서드는 연결된 디바이스 ID를 사용하여 디바이스 상태 가져오는 데 사용할 수 있는 디바이스 컨텍스트를 가져옵니다. 메서드에 대한 호출은 printHelper.SendInkLevelQuery() 디바이스 쿼리를 시작합니다. 응답이 반환되면 메서드가 OnInkLevelReceived 호출되고 UI가 업데이트됩니다.

참고 항목

이 C# 예제는 JavaScript 샘플과 다른 패턴을 따릅니다. C#에서는 이벤트 메시지를 UI 스레드에 다시 게시할 수 있도록 PrintHelperClass에 디스패처를 보낼 수 있기 때문입니다.

이 예제에서는 InkLevel.xaml.cs 파일의 메서드와 OnInkLevelReceived 메서드보여 GetInkStatus 줍니다.

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 쿼리를 디바이스로 보내고 응답을 수신하는 작업을 처리합니다.

이 예제에서는 PrintHelperClass.cs 파일의 메서드 및 기타 메서드를 보여 SendInkLevelQuery 냅니다. 일부 인쇄 도우미 클래스 메서드만 여기에 표시됩니다. 인쇄 설정 및 인쇄 알림 샘플을 다운로드하여 전체 코드를 확인합니다.

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 또는 Windows 8.1용 독립 실행형 SDK를 설치해야 합니다. Windows용 Microsoft Visual Studio Express를 설치하면 마법사를 포함하지 않는 SDK 버전이 설치됩니다.

다음 단계에서는 앱을 빌드하고 디바이스 메타데이터를 설치합니다.

  1. 테스트 서명을 사용하도록 설정합니다.

    1. DeviceMetadataWizard.exe 두 번 클릭하여 %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86에서 디바이스 메타데이터 제작 마법사시작합니다.

    2. 도구 메뉴에서 테스트 서명 사용을 선택합니다.

  2. 컴퓨터를 다시 부팅

  3. 솔루션(.sln) 파일을 열어 솔루션을 빌드합니다. F7 키를 누르거나 샘플이 로드된 후 상단 메뉴에서 빌드> 솔루션으로 이동합니다.

  4. 프린터 연결을 끊고 제거합니다. 이 단계는 다음에 디바이스가 검색될 때 Windows에서 업데이트된 디바이스 메타데이터를 읽도록 하는 데 필요합니다.

  5. 디바이스 메타데이터를 편집하고 저장합니다. 디바이스 앱을 디바이스에 연결하려면 디바이스 앱을 디바이스와 연결해야 합니다.

    참고 항목

    디바이스 메타데이터를 아직 만들지 않은 경우 2단계: UWP 디바이스 앱에 대한 디바이스 메타데이터 만들기를 참조하세요.

    1. 디바이스 메타데이터 작성 마법사가 아직 열려 있지 않으면 DeviceMetadataWizard.exe 두 번 클릭하여 %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86에서 시작합니다.

    2. 디바이스 메타데이터 편집을 클릭합니다. 이렇게 하면 기존 디바이스 메타데이터 패키지를 편집할 수 있습니다.

    3. 열기 대화 상자에서 UWP 디바이스 앱과 연결된 디바이스 메타데이터 패키지를 찾습니다. (devicemetadata-ms 파일 확장명입니다.)

    4. UWP 디바이스 앱 정보 지정 페이지의 UWP 디바이스 앱 상자에 Microsoft Store 앱 정보를 입력합니다. UWP 앱 매니페스트 파일 가져오기를 클릭하여 패키지 이름, 게시자 이름UWP 앱 ID를 자동으로 입력합니다.

    5. 앱이 프린터 알림을 등록하는 경우 알림 처리기 상자를 입력 합니다 . 이벤트 ID에서 인쇄 이벤트 처리기의 이름을 입력합니다. 이벤트 자산에서 해당 코드가 있는 파일의 이름을 입력합니다.

    6. 완료되면 마침 페이지에 도착할 때까지 다음클릭합니다.

    7. 디바이스 메타데이터 패키지 검토 페이지에서 모든 설정이 올바른지 확인하고 로컬 컴퓨터 검사 상자의 메타데이터 저장소에 디바이스 메타데이터 패키지 복사를 선택합니다. 그런 다음 Save를 클릭합니다.

  6. 디바이스가 연결될 때 Windows에서 업데이트된 디바이스 메타데이터를 읽도록 프린터를 다시 연결합니다.

문제 해결

문제: 앱과 연결된 디바이스를 열거할 때 프린터를 찾을 수 없습니다.

연결된 프린터를 열거할 때 프린터를 찾을 수 없는 경우:

  • 가능한 원인: 테스트 서명이 켜져 있지 않습니다. 설정에 대한 자세한 내용은 이 항목의 디버깅 섹션을 참조하세요.

  • 가능한 원인: 앱이 올바른 패키지 패밀리 이름을 쿼리하지 않습니다. 코드에서 패키지 패밀리 이름을 확인합니다. Microsoft Visual Studio에서 package.appxmanifest를 열고 쿼리하는 패키지 패밀리 이름이 패키지 패밀리 이름 필드의 패키징 탭에 있는 이름과 일치하는지 확인합니다.

  • 가능한 원인: 디바이스 메타데이터가 패키지 패밀리 이름과 연결되어 있지 않습니다. 디바이스 메타데이터 작성 마법사를 사용하여 디바이스 메타데이터를 열고 패키지 패밀리 이름을 검사. DeviceMetadataWizard.exe 두 번 클릭하여 %ProgramFiles(x86)%\Windows Kits\8.1\bin\x86에서 마법사를 시작합니다.

문제: 앱과 연결된 프린터를 찾았지만 Bidi 정보를 쿼리할 수 없음

연결된 프린터를 열거할 때 프린터가 발견되었지만 Bidi 쿼리가 오류를 반환하는 경우...

  • 가능한 원인: 잘못된 패키지 패밀리 이름입니다. 코드에서 패키지 패밀리 이름을 확인합니다. Visual Studio에서 package.appxmanifest를 열고 쿼리하는 패키지 패밀리 이름이 패키지 패밀리 이름 필드의 패키징 탭에 있는 이름과 일치하는지 확인합니다.

  • 가능한 원인: 프린터가 v4 프린터가 아닌 v3 프린터를 사용하여 설치되었습니다. 설치된 버전을 확인하려면 PowerShell을 열고 다음 명령을 입력합니다.

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

v4 인쇄 드라이버 개발

프린터 확장 인터페이스(v4 인쇄 드라이버)

양방향 통신

UWP 앱 시작

UWP 디바이스 앱 만들기(단계별 가이드)

UWP 디바이스 앱에 대한 디바이스 메타데이터 만들기(단계별 가이드)