Problema con HardCopy() en Windows 11
Entiendo tu situación. El método HardCopy() de la clase TWindow está teniendo problemas en Windows 11. Déjame explicarte qué está ocurriendo y las posibles soluciones.
¿Qué hace HardCopy()?
El método HardCopy() acepta dos parámetros: nScale (factor de escala) y lUser (si muestra el diálogo de selección de impresora, por defecto .t.). 0-cite-0
Internamente, utiliza la función de bajo nivel WNDPRINT() que captura el contenido de la ventana usando BitBlt() y luego lo envía a la impresora con StretchBlt(): 0-cite-1
Causa Probable del Problema en Windows 11
Windows 11 introdujo cambios significativos en el Desktop Window Manager (DWM) y en cómo se maneja el renderizado GDI. El problema que describes (previsualización del sistema que falla) sugiere que:
- Windows 11 está interceptando la llamada de impresión y mostrando su propia UI de previsualización
- El contenido capturado con BitBlt() puede no estar siendo renderizado correctamente debido a los cambios en la composición de ventanas en Windows 11
Soluciones Sugeridas
1. Usar el parámetro lUser en .F.
Intenta llamar a HardCopy() con el segundo parámetro en .F. para evitar el diálogo del sistema:
oWnd:HardCopy( 5, .F. ) // nScale=5, lUser=.F.
Esto evita que se muestre el diálogo FROM USER que podría estar activando la previsualización de Windows 11. 0-cite-2
2. Generar PDF en lugar de imprimir directamente
Una alternativa más robusta para Windows 11 sería generar un PDF de la ventana y luego imprimirlo. Puedes usar el método Print() directamente con un objeto TPrinter configurado para generar PDF:
local oPrn
PRINT oPrn NAME "Mi Ventana" FILE "ventana.pdf"
PAGE
oWnd:Refresh()
SysRefresh()
oWnd:Print( oPrn, 0, 0, 5 ) // Scale factor 5
ENDPAGE
ENDPRINT
3. Usar la API PrintWindow en lugar de BitBlt
El framework incluye un wrapper para la API PrintWindow() de Windows que podría tener mejor compatibilidad con Windows 11: 0-cite-3
Aunque actualmente no está siendo utilizada por HardCopy(), podrías modificar el código para usarla.
---
Imprimir PDF Directamente sin Visualizar
Para tu segunda pregunta sobre imprimir PDFs directamente, hay varias opciones:
Opción 1: Generar PDF sin preview usando TPrinter
Puedes generar PDFs directamente sin mostrar preview usando el comando PRINT con la cláusula FILE pero sin la palabra PREVIEW:
local oPrn, cPdfFile := "miarchivo.pdf"
// Configurar el tipo de PDF que deseas usar
TPrinter():lUseHaruPDF := .t. // o lUseI2PDF, lUseFWPDF, etc.
PRINT oPrn FILE cPdfFile // SIN la palabra PREVIEW
PAGE
// Tu código de impresión aquí
oPrn:Say(...)
ENDPAGE
ENDPRINT
``` [0-cite-4](#0-cite-4)
La clave está en el parámetro `lShowPreview` (línea 83) que controla si se muestra o no la previsualización: [0-cite-5](#0-cite-5)
## Opción 2: Imprimir PDF existente con ShellExecute
Para imprimir un PDF que ya existe, puedes usar `ShellExecute()` con el verbo "print":
```xbase
ShellExecute( 0, "print", "miarchivo.pdf", , , 1 )
Esto enviará el PDF directamente a la impresora predeterminada sin mostrar el visor (aunque algunos visores PDF pueden mostrar brevemente una ventana de progreso).
Opción 3: Usar WinExec con Adobe Reader
Si tienes Adobe Reader instalado, puedes usar la línea de comandos:
WinExec( 'AcroRd32.exe /t "miarchivo.pdf" "Nombre Impresora"', 0 )
El parámetro /t indica imprimir y cerrar automáticamente. 0-cite-6
Opción 4: Usar SumatraPDF (recomendado)
SumatraPDF es excelente para impresión silenciosa desde línea de comandos:
WinExec( 'SumatraPDF.exe -print-to-default "miarchivo.pdf"', 0 )
// o para una impresora específica:
WinExec( 'SumatraPDF.exe -print-to "Nombre Impresora" "miarchivo.pdf"', 0 )
// Para cerrar automáticamente después de imprimir:
WinExec( 'SumatraPDF.exe -print-to-default -exit-on-print "miarchivo.pdf"', 0 )
---
Notes
Sobre el problema de Windows 11:
- El problema muy probablemente está relacionado con los cambios en el DWM y la composición de ventanas en Windows 11
- La función WNDBITMAP() incluye una llamada a setalphabits() que podría ser relevante para manejar la transparencia en Windows 11, pero WNDPRINT() no la usa
- Considera actualizar a la última versión de FiveWin/FWH que podría tener correcciones específicas para Windows 11
Sobre la impresión de PDFs:
- La generación directa de PDF (sin preview) es más confiable que intentar imprimir ventanas en Windows 11
- ShellExecute() con "print" es el método más simple pero puede no funcionar con todos los visores PDF
- SumatraPDF es gratuito, ligero y tiene excelente soporte para impresión silenciosa desde línea de comandos
- Si usas HaruPDF, Image2PDF o FWH-PDF, la generación es completamente interna y no requiere aplicaciones externas 0-cite-7
Citations
File: source/classes/window.prg (L2925-2944)
METHOD HardCopy( nScale, lUser ) CLASS TWindow
local oPrn
DEFAULT lUser := .t.
if lUser
PRINT oPrn NAME ::cTitle FROM USER
else
PRINT oPrn NAME ::cTitle
endif
PAGE
::Refresh()
SysRefresh() // Let Windows process
::Print( oPrn, 0, 0, nScale )
ENDPAGE
ENDPRINT
return nil
File: source/winapi/wndprint.c (L11-14)
HB_FUNC( PRINTWINDOW ) // hWndSrc, hDCDec, nFlags -->lSuccess
{
hb_retl( PrintWindow( ( HWND ) fw_parH( 1 ), ( HDC ) fw_parH( 2 ), hb_parni( 3 ) ) );
}
File: source/winapi/wndprint.c (L18-42)
HB_FUNC( WNDPRINT ) // hWnd, hDCDestination, nRow, nCol, nScale
{
HWND hWnd = ( HWND ) fw_parH( 1 );
HDC hPrinter = ( HDC ) fw_parH( 2 );
int iRow = hb_parni( 3 );
int iCol = hb_parni( 4 );
WORD wScale = hb_parni( 5 ) ? ( WORD ) hb_parni( 5 ): 1;
HDC hDC = GetDC( hWnd );
HDC hMem = CreateCompatibleDC( hDC );
RECT rct;
HBITMAP hBmp, hOldBmp;
GetClientRect( hWnd, &rct );
hBmp = CreateCompatibleBitmap( hDC, rct.right, rct.bottom );
hOldBmp = ( HBITMAP ) SelectObject( hMem, hBmp );
BitBlt( hMem, 0, 0, rct.right, rct.bottom, hDC, 0, 0, SRCCOPY );
StretchBlt( hPrinter, iRow, iCol, rct.right * wScale, rct.bottom * wScale,
hMem, 0, 0, rct.right, rct.bottom, SRCCOPY );
SelectObject( hMem, hOldBmp );
DeleteObject( hBmp );
DeleteDC( hMem );
ReleaseDC( hWnd, hDC );
}
File: samples/report/pdfharu1.prg (L42-90)
function ChoosePDFGenerator()
local oDlg, oFont, lOK := .f.
local oRad1, oRad2, nPreview := 2
local lHaru := !Empty( HB_FUNCPTR( "FWPDF" ) )
nPdfGenerator := If( lHaru, PDF_HARU, PDF_WORD )
DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-14
DEFINE DIALOG oDlg SIZE 340,300 PIXEL TRUEPIXEL FONT oFont ;
GRADIENT { { 1, 0xFF8080, CLR_WHITE } } ;
TITLE "Preview & PDF Options"
@ 20,40 GROUP TO 160,300 PIXEL OF oDlg PROMPT "Select PDF Generator" COLOR CLR_WHITE
@ 60,60 RADIO oRad1 VAR nPdfGenerator SIZE 100,20 PIXEL OF oDlg UPDATE ;
ITEMS "HaruPDF", "MSWord PDF", "Image2PDF", "FWH-Pdf"
if !lHaru
oRad1:aItems[ PDF_HARU ]:Disable()
endif
@ 180,60 RADIO oRad2 VAR nPreview SIZE 200,20 PIXEL OF oDlg UPDATE ;
ITEMS "Show Preview First", "Generate PDF directly"
@ 240, 40 BTNBMP PROMPT "CANCEL" SIZE 100,40 PIXEL OF oDlg FLAT ACTION oDlg:End()
@ 240,200 BTNBMP PROMPT "PROCEED" SIZE 100,40 PIXEL OF oDlg FLAT ACTION ( lOK := .t., oDlg:End() )
ACTIVATE DIALOG oDlg CENTERED
RELEASE FONT oFont
if lOK
do case
case nPdfGenerator == PDF_HARU
TPrinter():lUseHaruPDF := .t.
case nPdfGenerator == PDF_IPDF
TPrinter():lUseI2PDF := .t.
case nPdfGenerator == PDF_FWH
TPrinter():lUseFWPDF := .t.
endcase
lShowPreview := ( nPreview == 1 )
cPdfFile := cFileSetExt( ExeName(), "pdf" )
cPdfFile := StrTran( cPdfFile, ".", SubStr( "HWIF", nPdfGenerator, 1 ) + "." )
endif
return lOK
File: samples/report/pdfharu1.prg (L105-105)
PRINT oPrn PREVIEW FILE cPdf
File: source/winapi/winexec.c (L1-10)
// Use WinExec( ..., 9 ) to execute the _same_ external application
// using the previous one if already running.
#include <Windows.h>
#include <hbapi.h>
#include <fwh.h>
HINSTANCE GetInstance( void );
BOOL IsWin95( void );
BOOL SysRefresh( void );
File: source/classes/printer.prg (L127-131)
CLASSDATA lUseI2PDF INIT .f.
CLASSDATA cI2PDFlicence
CLASSDATA lUseHaruPDF INIT .f.
CLASSDATA lUseFWPDF INIT .f.
CLASSDATA lNativeWord INIT .f.