Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este tópico descreve como iniciar e interromper o thread de processamento do trabalho de impressão.
Visão geral
Para evitar que as atividades de impressão bloqueiem a resposta da interface do usuário, crie um thread separado para processar o trabalho de impressão. O thread que é iniciado quando o programa é iniciado, é o thread que manipula as mensagens de janela que resultam da interação do usuário e, portanto, é o thread da interface do usuário. O programa deve processar essas mensagens sem demora para que a interface do usuário responda à entrada do mouse e teclado do usuário em tempo hábil. Para que o programa seja capaz de responder a essas mensagens rapidamente, a quantidade de processamento que pode ser realizada durante qualquer mensagem é limitada. Quando uma solicitação de usuário requer processamento extensivo, um thread diferente deve executar esse processamento para permitir que a interação subsequente do usuário seja manipulada pelo programa.
O processamento de dados em um thread separado requer que o programa coordene a operação do thread da interface do usuário e o thread de processamento. Por exemplo, enquanto o thread de processamento está processando os dados, o thread principal não deve alterar esses dados. Uma maneira de gerenciar isso é por meio de objetos de sincronização thread-safe, como semáforos, eventos e mutexes.
Ao mesmo tempo, alguma interação do usuário deve ser impedida enquanto o thread de processamento está em execução. No programa de exemplo, os dados da aplicação são protegidos e a interação do usuário é limitada devido ao processamento do trabalho de impressão ser gerido pela caixa de diálogo de progresso modal. Uma caixa de diálogo modal impede que o usuário interaja com a janela principal do programa, o que impede que o usuário altere os dados do programa do aplicativo enquanto os dados são impressos.
A única ação que o usuário pode executar enquanto um trabalho de impressão está sendo processado é cancelar o trabalho de impressão. Essa restrição é sinalizada ao usuário pela forma do cursor. Quando o cursor está sobre o botão Cancelar, um cursor de seta é exibido, o que indica que o usuário pode clicar nesse botão. Quando o cursor está sobre qualquer outra parte da área da janela do programa, um cursor de espera é exibido, o que indica que o programa está ocupado e não pode responder à entrada do usuário.
Criação do Procedimento de Fio de Impressão
Recomendamos incluir esses recursos durante o processamento de impressão.
O processamento de impressão é dividido em etapas
Você pode dividir o processamento de impressão em etapas de processamento discretas que podem ser interrompidas se o usuário clicar no botão Cancelar. Isso é útil porque o processamento de impressão pode incluir operações intensivas do processador. Dividir esse processamento em etapas pode impedir que o processamento de impressão bloqueie ou atrase outros threads ou processos. Dividir o processamento em etapas lógicas também torna possível encerrar o processamento de impressão de forma limpa a qualquer momento, de modo que terminar um trabalho de impressão antes que ele tenha terminado não deixará nenhum recurso órfão.
Esta é uma lista de exemplo de etapas de impressão.
HRESULT PrintStep_1_StartJob (PPRINTTHREADINFO threadInfo); HRESULT PrintStep_2_DoOnePackage (PPRINTTHREADINFO threadInfo); HRESULT PrintStep_3_DoOneDoc (PPRINTTHREADINFO threadInfo); HRESULT PrintStep_4_DoOnePage (PPRINTTHREADINFO threadInfo); HRESULT PrintStep_5_ClosePackage (PPRINTTHREADINFO threadInfo); HRESULT PrintStep_6_CloseJob (PPRINTTHREADINFO threadInfo);Verificar se há um evento de cancelamento entre as etapas
Quando o utilizador clica no botão Cancelar, o segmento da interface do utilizador sinaliza o evento de cancelamento. O thread de processamento deve verificar o evento cancel periodicamente para saber quando um usuário clicou no botão Cancelar. As instruçõesWaitForSingleObject executam essa verificação e também dão a outros programas a chance de serem executados para que o processamento do trabalho de impressão não bloqueie ou atrase outros threads ou processos.
O exemplo de código a seguir ilustra um dos testes para ver se o evento cancel ocorreu.
waitStatus = WaitForSingleObject ( threadInfo->quitEvent, stepDelay); if (WAIT_OBJECT_0 == waitStatus) { hr = E_ABORT; }Enviar atualizações de status para o thread da interface do usuário
A cada etapa do processamento de impressão, a thread de processamento de impressão envia mensagens de atualização para a caixa de diálogo de progresso de impressão, para que esta possa atualizar a barra de progresso. Observe que a caixa de diálogo de progresso da impressão está sendo executada no thread da interface do usuário.
O exemplo de código a seguir ilustra uma das chamadas de mensagem de atualização.
// Update print status PostMessage ( threadInfo->parentWindow, USER_PRINT_STATUS_UPDATE, 0L, 0L);
Iniciando o thread de impressão
O thread de processamento de impressão é executado até que a função PrintThreadProc retorne. As etapas a seguir iniciam o thread de impressão.
Prepare os dados e os elementos da interface do usuário para impressão.
Antes de iniciar o thread de processamento de impressão, você deve inicializar os elementos de dados que descrevem o trabalho de impressão e os elementos da interface do usuário. Esses elementos incluem o estado do cursor, para que o cursor de espera seja exibido adequadamente. Você também deve configurar a barra de progresso para refletir o tamanho do trabalho de impressão. Essas etapas de preparação são descritas em detalhes em Como: Coletar informações de trabalho de impressão do usuário.
O exemplo de código a seguir mostra como configurar a barra de progresso para refletir o tamanho do trabalho de impressão que o usuário solicitou.
// Compute the number of steps in this job. stepCount = ((( // One copy of a document contains // one step for each page + // one step for the document ((threadInfo->documentContent)->pages + 1) * // Each copy of the document includes // two steps to open and close the document threadInfo->copies) + 2) * // Each job includes one step to start the job threadInfo->packages) + 1; // Send the total number of steps to the progress bar control. SendMessage ( dlgInfo->progressBarWindow, PBM_SETRANGE32, 0L, (stepCount));Inicie o thread de processamento de impressão.
Chame CreateThread para iniciar o thread de processamento.
O exemplo de código a seguir inicia o thread de processamento.
// Start the printing thread threadInfo->printThreadHandle = CreateThread ( NULL, 0L, (LPTHREAD_START_ROUTINE)PrintThreadProc, (LPVOID)threadInfo, 0L, &threadInfo->printThreadId);Verifique se o processamento de impressão falhou no início.
CreateThread retorna um identificador para o thread criado se o thread foi criado com êxito. A função PrintThreadProc que foi iniciada no novo thread verifica algumas condições antes de iniciar o processamento real do trabalho de impressão. Se detetar algum erro nessas verificações, o PrintThreadProc poderá retornar sem processar nenhum dado de trabalho de impressão. O thread da interface do usuário pode verificar se o thread de processamento foi iniciado com êxito aguardando o identificador de thread por um período de tempo maior do que o necessário para executar os testes iniciais, mas não mais do que o necessário. Quando o thread sai, o identificador para o thread torna-se sinalizado. O código verifica o estado do thread por um curto período de tempo depois que ele inicia o thread de processamento. A funçãoWaitForSingleObject retorna quando o tempo limite ocorre ou o identificador de thread é sinalizado. Se a função WaitForSingleObject retornar um estado WAIT_OBJECT_0, o thread saiu antecipadamente e, portanto, deve-se fechar a caixa de diálogo de progresso de impressão, como mostra o exemplo de código a seguir.
// Make sure the printing thread started OK // by waiting to see if it is still running after // a short period of time. This time delay should be // long enough to know that it's running but shorter // than the shortest possible print job. waitStatus = WaitForSingleObject ( threadInfo->printThreadHandle, THREAD_START_WAIT); // If the object is signaled, that means that the // thread terminated before the timeout period elapsed. if (WAIT_OBJECT_0 == waitStatus) { // The thread exited, so post close messages. PostMessage (hDlg, USER_PRINT_CLOSING, 0L, (LPARAM)E_FAIL); PostMessage (hDlg, USER_PRINT_COMPLETE, 0L, (LPARAM)E_FAIL); }
Parando o thread de impressão
Quando o usuário clica no botão Cancelar na caixa de diálogo de progresso da impressão, o thread de impressão é notificado para que possa parar de processar o trabalho de impressão de forma ordenada. Embora o botão Cancelar e o evento quitEvent sejam aspetos importantes deste processamento, você deve projetar toda a sequência de processamento para ser interrompida com êxito. Isso significa que as etapas na sequência não devem deixar nenhum recurso alocado que não seja liberado se um usuário cancelar a sequência antes de ela ter sido concluída.
O exemplo de código a seguir mostra como o programa de exemplo verifica o quitEvent antes de processar cada página no documento que está sendo impresso. Se o quitEvent for sinalizado ou um erro for detetado, o processamento de impressão será interrompido.
// While no errors and the user hasn't clicked cancel...
while (((waitStatus = WaitForSingleObject (
threadInfo->quitEvent,
stepDelay)) == WAIT_TIMEOUT) &&
SUCCEEDED(hr))
{
// ...print one page
hr = PrintStep_4_DoOnePage (threadInfo);
// Update print status
PostMessage (
threadInfo->parentWindow,
USER_PRINT_STATUS_UPDATE,
0L,
0L);
if (threadInfo->currentPage < (threadInfo->documentContent)->pages)
{
// More pages, so continue to the next one
threadInfo->currentPage++;
}
else
{
// Last page printed so exit loop and close
break;
}
}