Drucken von Desktop-Apps

In diesem Abschnitt wird beschrieben, wie Sie über ein natives Windows-Desktopprogramm drucken.

Übersicht

Um die beste Benutzererfahrung beim Drucken aus einem nativen Windows-Programm zu bieten, muss das Programm so konzipiert sein, dass es über einen dedizierten Thread drucken kann. In einem nativen Windows-Programm ist das Programm für die Verwaltung von Ereignissen und Nachrichten der Benutzeroberfläche verantwortlich. Druckvorgänge können zeitenintensive Berechnungen erfordern, wenn der Anwendungsinhalt für den Drucker gerendert wird. Dies kann verhindern, dass das Programm auf Benutzerinteraktionen reagiert, wenn diese Verarbeitung im selben Thread wie die Ereignisverarbeitung der Benutzerinteraktion ausgeführt wird.

Wenn Sie bereits mit dem Schreiben eines nativen Multithread-Programms vertraut sind, wechseln Sie direkt zu Drucken aus einer Windows-Anwendung und erfahren, wie Sie Ihrem Programm Druckfunktionen hinzufügen.

Grundlegende Windows-Programmanforderungen

Führen Sie die Druckauftragsverarbeitung eines Programms nicht im Thread aus, der die Benutzerinteraktion verarbeitet, um eine optimale Leistung und Reaktionsfähigkeit des Programms zu erzielen.

Diese Trennung von Druck und Benutzerinteraktion beeinflusst, wie das Programm die Anwendungsdaten verwaltet. Sie sollten diese Auswirkungen gründlich verstehen, bevor Sie mit dem Schreiben der Anwendung beginnen. In den folgenden Themen werden die grundlegenden Anforderungen für die Verarbeitung des Druckens in einem separaten Thread eines Programms beschrieben.

Grundlagen des Windows-Programms

Ein natives Windows-Programm muss die Standard Fensterprozedur bereitstellen, um die Fenstermeldungen zu verarbeiten, die es vom Betriebssystem empfängt. Jedes Fenster in einem Windows-Programm verfügt über eine entsprechende WndProc-Funktion , die diese Fenstermeldungen verarbeitet. Der Thread, in dem diese Funktion ausgeführt wird, wird als Benutzeroberfläche oder UI-Thread bezeichnet.

Verwenden Sie Ressourcen für Zeichenfolgen.
Verwenden Sie Zeichenfolgenressourcen aus der Ressourcendatei des Programms anstelle von Zeichenfolgenkonstanten für Zeichenfolgen, die möglicherweise geändert werden müssen, wenn Sie eine andere Sprache unterstützen. Bevor ein Programm eine Zeichenfolgenressource als Zeichenfolge verwenden kann, muss das Programm die Ressource aus der Ressourcendatei abrufen und in einen lokalen Speicherpuffer kopieren. Dies erfordert zu Beginn eine zusätzliche Programmierung, ermöglicht jedoch eine einfachere Änderung, Übersetzung und Lokalisierung des Programms in der Zukunft.
Verarbeiten Sie Daten in Schritten.
Verarbeiten Sie den Druckauftrag in Schritten, die unterbrochen werden können. Dieser Entwurf ermöglicht es dem Benutzer, einen langen Verarbeitungsvorgang abzubrechen, bevor er abgeschlossen ist, und verhindert, dass das Programm andere Programme blockiert, die möglicherweise gleichzeitig ausgeführt werden.
Verwenden Sie Fensterbenutzerdaten.
Druckanwendungen verfügen häufig über mehrere Fenster und Threads. Um die Daten zwischen Threads und Verarbeitungsschritten verfügbar zu halten, ohne statische, globale Variablen zu verwenden, verweisen Sie auf die Datenstrukturen mit einem Datenzeiger, der Teil des Fensters ist, in dem sie verwendet werden.

Das folgende Codebeispiel zeigt einen Standard Einstiegspunkt für eine Druckanwendung. Dieses Beispiel zeigt, wie Zeichenfolgenressourcen anstelle von Zeichenfolgenkonstanten verwendet werden, und zeigt auch die Standard Nachrichtenschleife, die die Fenstermeldungen des Programms verarbeitet.

int APIENTRY 
wWinMain(
        HINSTANCE hInstance, 
        HINSTANCE hPrevInstance, 
        LPWSTR lpCmdLine, 
        int nCmdShow
)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    MSG msg;
    HACCEL hAccelTable;
    HRESULT hr = S_OK;

    // Register the main window class name
    WCHAR szWindowClass[MAXIMUM_RESOURCE_STRING_LENGTH];            
    LoadString(
        hInstance, 
        IDC_PRINTSAMPLE, 
        szWindowClass, 
        MAXIMUM_RESOURCE_STRING_LENGTH);
    MyRegisterClass(hInstance, szWindowClass);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        // Unable to initialize this instance of the application
        //  so display error message and exit
        MessageBoxWithResourceString (
            hInstance, 
            GetDesktopWindow(), 
            IDS_ERROR_INSTINITFAIL, 
            IDS_CAPTION_ERROR, 
            (MB_OK | MB_ICONEXCLAMATION));
        return FALSE;
    }    
    
    // Init COM for printing interfaces
    if (FAILED(hr = CoInitializeEx(0, COINIT_MULTITHREADED)))
    {
        // Unable to initialize COM
        //  so display error message and exit
        MessageBoxWithResourceString (
            hInstance, 
            GetDesktopWindow(), 
            IDS_ERROR_COMINITFAIL, 
            IDS_CAPTION_ERROR, 
            (MB_OK | MB_ICONEXCLAMATION));
        return FALSE;
    }

    hAccelTable = LoadAccelerators(
                    hInstance, 
                    MAKEINTRESOURCE(IDC_PRINTSAMPLE));

    // Main message handling loop
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    // Uninitialize (close) the COM interface
    CoUninitialize();

    return (int) msg.wParam;
}

Dokumentinformationen

Native Windows-Programme, die drucken, sollten für die Multithreadverarbeitung konzipiert sein. Eine der Anforderungen eines Multithreaddesigns besteht darin, die Datenelemente des Programms zu schützen, sodass sie sicher sind, dass mehrere Threads gleichzeitig verwendet werden können. Sie können Datenelemente schützen, indem Sie Synchronisierungsobjekte verwenden und die Daten organisieren, um Konflikte zwischen den Threads zu vermeiden. Gleichzeitig muss das Programm Änderungen an den Programmdaten verhindern, während es gedruckt wird. Das Beispielprogramm verwendet verschiedene Multithread-Programmiertechniken.

Synchronisierungsereignisse
Das Beispielprogramm verwendet Ereignisse, Threadhandles und Wartefunktionen, um die Verarbeitung zwischen dem Druckthread und dem Standard Programm zu synchronisieren und anzugeben, dass die Daten verwendet werden.
Anwendungsspezifische Windows-Nachrichten
Das Beispielprogramm verwendet anwendungsspezifische Fenstermeldungen, um das Programm mit anderen nativen Windows-Programmen kompatibel zu machen. Das Aufteilen der Verarbeitung in kleinere Schritte und das Anstehen dieser Schritte in der Fenstermeldungsschleife erleichtert es Windows, die Verarbeitung zu verwalten, ohne andere Anwendungen zu blockieren, die möglicherweise auch auf dem Computer ausgeführt werden.
Datenstrukturen
Das Beispielprogramm wird nicht in einem objektorientierten Stil mit Objekten und Klassen geschrieben, obwohl es Datenelemente in Datenstrukturen gruppiert. Das Beispiel verwendet keinen objektorientierten Ansatz, um zu vermeiden, dass ein Ansatz besser oder schlechter als ein anderer ist.
Sie können die Funktionen und Datenstrukturen des Beispielprogramms als Ausgangspunkt verwenden, wenn Sie Ihr Programm entwerfen. Unabhängig davon, ob Sie sich für das Entwerfen eines objektorientierten Programms entscheiden oder nicht, ist es wichtig, die zugehörigen Datenelemente zu gruppieren, damit Sie sie bei Bedarf sicher in verschiedenen Threads verwenden können.

Druckergerätekontext

Beim Drucken sollten Sie den inhalt rendern, der in einem Gerätekontext gedruckt werden soll. Vorgehensweise: Abrufen eines Druckergerätekontexts beschreibt die verschiedenen Möglichkeiten, wie Sie einen Druckergerätekontext abrufen können.

Drucken aus einer Windows-Anwendung