Jump to content


Photo

Obtener el nombre del papel de la impresora

Impresion

  • Please log in to reply
5 replies to this topic

#1 jorgebq77

jorgebq77

    Member

  • Miembros
  • PipPip
  • 11 posts

Posted 15 May 2022 - 08:37 PM

Saludos mis queridos foristas,

 

En internet encontré este código para obtener los papeles de una impresora usando el API de Windows y el objeto TPrinter de Delphi.

 

Aquí esta el código:


delphi
  1. procedure GetPaperNames(sl : TStrings);
  2. type
  3. TPaperName = array[0..63] of Char;
  4. TPaperNameArray = array[1..High(Integer) div SizeOf(TPaperName)] of TPaperName;
  5. PPaperNameArray = ^TPaperNameArray;
  6. var
  7. Device, Driver, Port : array[0..255] of Char;
  8. hDevMode : THandle;
  9. I, NumPaperFormats : Integer;
  10. pPaperFormats : PPaperNameArray;
  11. begin
  12. Printer.PrinterIndex := Printer.PrinterIndex;
  13. Printer.GetPrinter(Device, Driver, Port, hDevmode);
  14. NumPaperFormats := DeviceCapabilities(Device, Port, DC_PAPERNAMES, nil, nil);
  15. if NumPaperFormats > 0 then
  16. begin
  17. GetMem(pPaperFormats, NumPaperFormats * SizeOf(TPaperName));
  18. try
  19. DeviceCapabilities(Device, Port, DC_PAPERNAMES, Pchar(pPaperFormats), nil);
  20. sl.Clear;
  21. for I:= 1 to NumPaperFormats do
  22. sl.add( pPaperformats^[I] );
  23.  
  24. finally
  25. FreeMem(pPaperFormats);
  26. end;
  27. end;
  28. end;

Tomando este código como referencia he hecho una función para obtener el nombre del papel de la impresora pasando como parámetro el numero de papel. por ejemplo, si le paso a la función el código 1 (correspondiente a DMPAPER_LETTER) la función devolverá el papel "US Letter 8 1/2 x 11 in", si le paso el código 5 (correspondiente a DMPAPER_LEGAL)  la función devolverá el papel "US Legal 8 1/2 x 14 in", si le paso el código 9 (correspondiente a DMPAPER_A4)  la función devolverá el papel "A4 210 x 297 mm" y así sucesivamente.

 

Aquí esta la función que diseñe para obtener el nombre del papel :


delphi
  1. function GetPaperName(IdxPrinter, Papel : Word) : string;
  2. type
  3. TPaperName = array[0..63] of Char;
  4. TPaperNameArray = array[1..High(Integer) div SizeOf(TPaperName)] of TPaperName;
  5. PPaperNameArray = ^TPaperNameArray;
  6. var
  7. Device, Driver, Port : array[0..255] of Char;
  8. hDevMode : THandle;
  9. I, NumPaperFormats : Integer;
  10. pPaperFormats : PPaperNameArray;
  11. begin
  12. Printer.PrinterIndex := IdxPrinter;
  13. Printer.GetPrinter(Device, Driver, Port, hDevmode);
  14. NumPaperFormats := DeviceCapabilities(Device, Port, DC_PAPERNAMES, nil, nil);
  15. if NumPaperFormats > 0 then
  16. begin
  17. GetMem(pPaperFormats, NumPaperFormats * SizeOf(TPaperName));
  18. try
  19. DeviceCapabilities(Device, Port, DC_PAPERNAMES, Pchar(pPaperFormats), nil);
  20.  
  21. for I:= 1 to NumPaperFormats do
  22. begin
  23. if I = Papel then
  24. begin
  25. Result := pPaperformats^[I];
  26. Break;
  27. end;
  28. end;
  29.  
  30. finally
  31. FreeMem(pPaperFormats);
  32. end;
  33. end;
  34. end;

Esta función que diseñe devuelve el nombre del papel pero de forma incorrecta.... : pues lamentablemente no soy experto en el uso del API de Windows. Por eso les pido de favor que me ayuden a corregir dicha función ya que la necesito para pasársela a los reporteadores que uso (FastReport y ReportBuilder). Esta utilidad la usare para evitarle a los usuarios el tener que elegir el tamaño del papel cada vez que quieran imprimir. Como pista creo que el error esta en el bucle donde comparo el parámetro "Papel" con el índice del bucle.

 

Esperando que me hayan entendido les agradezco su ayuda y atención.

 

Att: Jorge

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


  • 0

#2 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 16 May 2022 - 08:43 AM

Así de bote pronto no será que TPaperName es base 0 y TPaperNameArray es base 1

 

De cualquier forma hay que analizar el código para poder darte una mejor respuesta.

 

Saludos


  • 0

#3 jorgebq77

jorgebq77

    Member

  • Miembros
  • PipPip
  • 11 posts

Posted 17 May 2022 - 12:57 PM

El amigo escafandra tal vez tenga la respuesta ya que es un experto en el manejo del API de Windows.  ;)

  • 0

#4 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 18 May 2022 - 05:30 AM

El problema está en que cuando se solicita la lista de nombre, ésta no está ordenada según los valores de dmPaperSize. Para poder obtener el nombre ordenado hay que listar los nombre por un lado, y los índices por el otro (DC_PAPERS).

La forma de conseguir un array con los indices del tamaño del papel según dmPaperSize es la siguiente: 

delphi
  1. DeviceCapabilitiesA(Device, Port, DC_PAPERS, PAnsiChar(pPapers), nil);

De esta forma y modificando lo justo la función que proponías en tu post, te propongo esta solución:

delphi
  1. function GetPaperName(IdxPrinter, Papel : Word) : string;
  2. type
  3. TPaperName = array[0..63] of AnsiChar;
  4. TAWord = array[1..High(WORD)] of WORD;
  5. TPaperNameArray = array[1..High(Integer) div SizeOf(TPaperName)] of TPaperName;
  6. PPaperNameArray = ^TPaperNameArray;
  7. PAWord = ^TAWord;
  8. var
  9. Device, Driver, Port : array[0..255] of AnsiChar;
  10. hDevMode : THandle;
  11. I, NumPaperFormats : Integer;
  12. pPaperFormats : PPaperNameArray;
  13. pPapers: PAWord; //PWORD;
  14. begin
  15. Result := '';
  16. Printer.PrinterIndex := IdxPrinter;
  17. Printer.GetPrinter(Device, Driver, Port, hDevmode);
  18. NumPaperFormats := DeviceCapabilities(Device, Port, DC_PAPERNAMES, nil, nil);
  19. if NumPaperFormats > 0 then
  20. begin
  21. GetMem(pPaperFormats, NumPaperFormats * SizeOf(TPaperName));
  22. GetMem(pPapers, NumPaperFormats * SizeOf(WORD));
  23. ZeroMemory(pPapers, NumPaperFormats);
  24. try
  25. DeviceCapabilitiesA(Device, Port, DC_PAPERNAMES, PAnsiChar(pPaperFormats), nil);
  26. DeviceCapabilitiesA(Device, Port, DC_PAPERS, PAnsiChar(pPapers), nil);
  27.  
  28. for I:= 1 to NumPaperFormats do
  29. begin
  30. if pPapers^[I] = Papel then
  31. begin
  32. Result := pPaperformats^[I];
  33. Break;
  34. end;
  35. end;
  36. finally
  37. FreeMem(pPaperFormats);
  38. FreeMem(pPapers);
  39. end;
  40. end;
  41. end;

Para evitar conflictos con UNICODE, he usado la versión Ansi de la API DeviceCapabilitiesA. De esta forma el código es compatible con versiones antiguas de delphi. Esto impica usar Array de  AnsiChar. Dado que el origen de indice de los array los estableciste en 1, los respeto. Personalmente prefiero que empiezen en cero por coherencia con el diseño de la API. Al tener el array de Papers que contiene los dmPaperSize, Solo hay que comparar cada elemento del array con el Papel solicitado, el índice de ese valor, será el que usaremos para encontrar el nombre del papel en el array correspòndiente de nombres. 
 
 
Saludos.
 
PD/ adjunto un extracto del archivo wingdi.h donde se definen los tamaños de papel.

Attached Files


  • 1

#5 jorgebq77

jorgebq77

    Member

  • Miembros
  • PipPip
  • 11 posts

Posted 18 May 2022 - 09:20 AM

Muy valiosa tu aportación querido escafandra, sabia perfectamente que tu darías con este asunto..

 

Solo una aclaración, probé la modificación de la función que propones pero no compila en estas dos líneas:


delphi
  1. Printer.GetPrinter(Device, Driver, Port, hDevmode);

El error que sale en esa línea es :[dcc32 Error] Unit1.pas(342): E2010 Incompatible types: 'PWideChar' and 'array[0..255] of AnsiChar'

 

 

en esta otra línea :


delphi
  1. NumPaperFormats := DeviceCapabilities(Device, Port, DC_PAPERNAMES, nil, nil);

 el error que sale es : [dcc32 Error] Unit1.pas(343): E2010 Incompatible types: 'PWideChar' and 'array[0..255] of AnsiChar'

 

 

Sale el mismo error en ambas líneas por que en el procedimiento GetPrinter espera parámetros de tipo PWideChar y la función DeviceCapabilities también espera parámetros de tipo PWideChar.

 

Trate de convertir los parámetros a PWideChar y me da el error [dcc32 Error] Unit1.pas(342): E2089 Invalid typecast

 

Como puedo solventar estos dos errores ??? Yo uso el Delphi Tokyo 10.2

 

Gracias por tu valiosa ayuda compañero.


  • 0

#6 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 18 May 2022 - 11:00 AM

El error es por el UNICODE

 

Si vas a usar Tokyo, entonces usa la versión W


delphi
  1. function GetPaperName(IdxPrinter, Papel : Word) : string;
  2. type
  3. TPaperName = array[0..63] of Char;
  4. TAWord = array[1..High(WORD)] of WORD;
  5. TPaperNameArray = array[1..High(Integer) div SizeOf(TPaperName)] of TPaperName;
  6. PPaperNameArray = ^TPaperNameArray;
  7. PAWord = ^TAWord;
  8. var
  9. Device, Driver, Port : array[0..255] of Char;
  10. hDevMode : THandle;
  11. I, NumPaperFormats: Integer;
  12. pPaperFormats : PPaperNameArray;
  13. pPapers: PAWord; //PWORD;
  14. begin
  15. Result := '';
  16. Printer.PrinterIndex := IdxPrinter;
  17. Printer.GetPrinter(Device, Driver, Port, hDevmode);
  18. NumPaperFormats := DeviceCapabilities(Device, Port, DC_PAPERNAMES, nil, nil);
  19. if NumPaperFormats > 0 then
  20. begin
  21. GetMem(pPaperFormats, NumPaperFormats * SizeOf(TPaperName));
  22. GetMem(pPapers, NumPaperFormats * SizeOf(WORD));
  23. ZeroMemory(pPapers, NumPaperFormats * SizeOf(WORD));
  24. try
  25. DeviceCapabilities(Device, Port, DC_PAPERNAMES, PChar(pPaperFormats), nil);
  26. DeviceCapabilities(Device, Port, DC_PAPERS, PChar(pPapers), nil);
  27.  
  28. for I:= 1 to NumPaperFormats do
  29. begin
  30. if pPapers^[I] = Papel then
  31. begin
  32. Result := pPaperformats^[I];
  33. Break;
  34. end;
  35. end;
  36. finally
  37. FreeMem(pPaperFormats);
  38. FreeMem(pPapers);
  39. end;
  40. end;
  41. end;

Saludos.


  • 0





Also tagged with one or more of these keywords: Impresion

IP.Board spam blocked by CleanTalk.