Stampa di app desktop

Questa sezione descrive come stampare da un programma desktop di Windows nativo.

Panoramica

Per offrire la migliore esperienza utente quando si stampa da un programma Windows nativo, il programma deve essere progettato per stampare da un thread dedicato. In un programma Windows nativo, il programma è responsabile della gestione di eventi e messaggi dell'interfaccia utente. Le operazioni di stampa possono richiedere periodi di calcolo intenso perché viene eseguito il rendering del contenuto dell'applicazione per la stampante, che può impedire al programma di rispondere all'interazione dell'utente se questa elaborazione viene eseguita nello stesso thread dell'elaborazione degli eventi dell'interazione dell'utente.

Se si ha già familiarità con come scrivere un programma Windows nativo multithreading, passare direttamente a Come stampare da un'applicazione Windows e imparare ad aggiungere funzionalità di stampa al programma.

Requisiti di base del programma Windows

Per prestazioni ottimali e velocità di risposta del programma, non eseguire l'elaborazione del processo di stampa di un programma nel thread che elabora l'interazione dell'utente.

Questa separazione della stampa dall'interazione dell'utente influirà sul modo in cui il programma gestisce i dati dell'applicazione. È necessario comprendere attentamente queste implicazioni prima di iniziare a scrivere l'applicazione. Negli argomenti seguenti vengono descritti i requisiti di base per la gestione della stampa in un thread separato di un programma.

Nozioni di base sul programma Windows

Un programma Windows nativo deve fornire la procedura della finestra principale per elaborare i messaggi della finestra ricevuti dal sistema operativo. Ogni finestra di un programma Windows ha una funzione WndProc corrispondente che elabora questi messaggi della finestra. Il thread in cui viene eseguita questa funzione è denominato interfaccia utente o thread dell'interfaccia utente.

Usare le risorse per le stringhe.
Usare le risorse stringa del file di risorse del programma anziché le costanti stringa per le stringhe che potrebbero essere necessarie per essere modificate quando si supporta un altro linguaggio. Prima che un programma possa usare una risorsa stringa come stringa, il programma deve recuperare la risorsa dal file di risorse e copiarla in un buffer di memoria locale. Ciò richiede una programmazione aggiuntiva all'inizio, ma consente di semplificare la modifica, la traduzione e la localizzazione del programma in futuro.
Elaborare i dati nei passaggi.
Elaborare il processo di stampa in passaggi che possono essere interrotti. Questa progettazione consente all'utente di annullare un'operazione di elaborazione lunga prima del completamento e impedisce al programma di bloccare altri programmi che potrebbero essere in esecuzione contemporaneamente.
Usare i dati utente della finestra.
Le applicazioni di stampa hanno spesso diverse finestre e thread. Per mantenere disponibili i dati tra thread e passaggi di elaborazione senza usare variabili statiche globali, fare riferimento alle strutture di dati da un puntatore dati che fa parte della finestra in cui vengono usati.

Nell'esempio di codice seguente viene illustrato un punto di ingresso principale per un'applicazione di stampa. Questo esempio illustra come usare le risorse stringa anziché le costanti stringa e mostra anche il ciclo di messaggi principale che elabora i messaggi della finestra del programma.

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

Informazioni sul documento

I programmi Windows nativi che stampano devono essere progettati per l'elaborazione multithread. Uno dei requisiti di una progettazione multithreading consiste nel proteggere gli elementi dati del programma in modo che siano sicuri per più thread da usare contemporaneamente. È possibile proteggere gli elementi dati usando gli oggetti di sincronizzazione e organizzare i dati per evitare conflitti tra i thread. Allo stesso tempo, il programma deve impedire modifiche ai dati del programma durante la stampa. Il programma di esempio usa diverse tecniche di programmazione multithreading.

Eventi di sincronizzazione
Il programma di esempio usa eventi, handle di thread e funzioni di attesa per sincronizzare l'elaborazione tra il thread di stampa e il programma principale e per indicare che i dati sono in uso.
Messaggi di Windows specifici dell'applicazione
Il programma di esempio usa messaggi di finestra specifici dell'applicazione per rendere il programma più compatibile con altri programmi Windows nativi. Suddividendo l'elaborazione in passaggi più piccoli e accodando tali passaggi nel ciclo di messaggi della finestra, Windows semplifica la gestione dell'elaborazione senza bloccare altre applicazioni che potrebbero essere in esecuzione anche nel computer.
strutture di dati
Il programma di esempio non viene scritto in uno stile orientato agli oggetti usando oggetti e classi, anche se raggruppa gli elementi dati in strutture di dati. L'esempio non usa un approccio orientato agli oggetti per evitare che un approccio sia migliore o peggiore di un altro.
È possibile usare le funzioni e le strutture di dati del programma di esempio come punto di partenza quando si progetta il programma. Indipendentemente dal fatto che si decida di progettare un programma orientato a oggetti o meno, l'importante considerazione di progettazione da ricordare consiste nel raggruppare gli elementi dati correlati in modo che sia possibile usarli in modo sicuro in thread diversi in base alle esigenze.

Contesto dispositivo stampante

Durante la stampa, potrebbe essere necessario eseguire il rendering del contenuto da stampare in un contesto di dispositivo. Procedura: Recuperare un contesto di dispositivo stampante descrive i diversi modi in cui è possibile ottenere un contesto di dispositivo della stampante.

Come stampare da un'applicazione Windows