Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Drucken mittels des PrintDlgEx-Dialogs (https://www.delphipraxis.net/124688-drucken-mittels-des-printdlgex-dialogs.html)

r29d43 23. Nov 2008 11:35


Drucken mittels des PrintDlgEx-Dialogs
 
Hallo,

"PrintDlgEx" hat ja einige Vorteile gegenüber der nur PrintDlg-Funktion, aber leider findet man hier im Forum so gut wie nichts darüber. Irgendwie scheint auch diese Funktion in der CommDlg-Unit nicht berücksichtigt zu sein. Warum, geht die nicht mit Delphi?


Bzw.: Ist es schonmal jemandem gelungen die zu nutzen? Wenn ja, wie?


Thx im Voraus,
rXdY

SirThornberry 23. Nov 2008 11:42

Re: Drucken mittels des PrintDlgEx-Dialogs
 
woran scheiterst du?
Zitat:

Warum, geht die nicht mit Delphi?
Wieso sollte die nicht mit Delphi funktionieren? Der Funktion sollte es egal sein mit welchem compiler das Programm erstellt wurde.

r29d43 23. Nov 2008 11:47

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Zitat:

Zitat von SirThornberry
woran scheiterst du?

irgendwie scheint Delphi die Funktion gar nicht zu kennen (=undefinierter Bezeichner), oder in welcher Unit könnte die (und deren Konstanten) sonst erwähnt sein (außer CommDlg)?

SirThornberry 23. Nov 2008 12:22

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Wenn die Funktion nicht in einer Unit definiert ist könntest du sie selbst definieren. Woher weißt du von der Funktion? Aus dem MSDN?

r29d43 23. Nov 2008 12:40

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Zitat:

Zitat von SirThornberry
Wenn die Funktion nicht in einer Unit definiert ist könntest du sie selbst definieren.

...was aber natürlich auch sehr mühevoll wäre :-), das dann mittels dieser external-Deklarationen zu tätigen. Aber vielleicht geht es ja doch normal mittels Delphi, ...besser, ich warte da erst nochmal ein bisschen ab. :mrgreen:


Zitat:

Zitat von SirThornberry
Woher weißt du von der Funktion? Aus dem MSDN?

aus der PSDK. In der Erklärung von PrintDlg ist die da peripher noch so miterwähnt.

quendolineDD 23. Nov 2008 12:59

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Übersetz dir doch die Funktion aus der MSDN und alle benötigten Structures.

r29d43 23. Nov 2008 14:26

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Also, habe es jetzt doch mal versucht, die Funktion selbst zu definieren. Leider aber gibt's bei der Zeile des eigentlichen Funktionsaufrufes dann eine Exception. Hier erstmal der bis dahin nötige Code:

Delphi-Quellcode:
const
  PD_ALLPAGES                   = $00000000;
  PD_SELECTION                  = $00000001;
  PD_PAGENUMS                   = $00000002;
  PD_NOSELECTION                = $00000004;
  PD_NOPAGENUMS                 = $00000008;
  PD_COLLATE                    = $00000010;
  PD_PRINTTOFILE                = $00000020;
  PD_PRINTSETUP                 = $00000040;
  PD_NOWARNING                  = $00000080;
  PD_RETURNDC                   = $00000100;
  PD_RETURNIC                   = $00000200;
  PD_RETURNDEFAULT              = $00000400;
  PD_SHOWHELP                   = $00000800;
  PD_ENABLEPRINTHOOK            = $00001000;
  PD_ENABLESETUPHOOK            = $00002000;
  PD_ENABLEPRINTTEMPLATE        = $00004000;
  PD_ENABLESETUPTEMPLATE        = $00008000;
  PD_ENABLEPRINTTEMPLATEHANDLE  = $00010000;
  PD_ENABLESETUPTEMPLATEHANDLE  = $00020000;
  PD_USEDEVMODECOPIES           = $00040000;
  PD_USEDEVMODECOPIESANDCOLLATE = $00040000;
  PD_DISABLEPRINTTOFILE         = $00080000;
  PD_HIDEPRINTTOFILE            = $00100000;
  PD_NONETWORKBUTTON            = $00200000;
  PD_CURRENTPAGE                = $00400000;
  PD_NOCURRENTPAGE              = $00800000;
  PD_EXCLUSIONFLAGS             = $01000000;
  PD_USELARGETEMPLATE           = $10000000;

type
  TPrintDlgEx = record
    lStructSize : Cardinal;
    hWndOwner : HWnd;
    hDevMode : Cardinal;
    hDevNames : Cardinal;
    hDC : HDC;
    Flags : Cardinal;
    Flags2 : Cardinal;
    ExclusionFlags : Cardinal;
    nPageRanges : Word;
    nMaxPageRanges : Word;
    lpPageRanges : Pointer;
    nMinPage : Word;
    nMaxPage : Word;
    nCopies : Word;
    hInstance : Cardinal;
    lpPrintTemplateName : PAnsiChar;
    lpCallback : Pointer;
    nPropertyPages : Cardinal;
    lphPropertyPages : Cardinal;
    nStartPage : Cardinal;
    dwResultAction : Cardinal;
  end;

type TPrintDlgExFunc = function (Pdex : TPrintDlgEx): DWord; stdcall;


procedure TForm1.Button1Click(Sender: TObject);
var hComDlg32 : THandle;
    PrintDlgEx : TPrintDlgExFunc;
    pdex : TPrintDlgEx;
begin

  hComDlg32 := LoadLibrary('comdlg32.dll');
  if hComDlg32 <> 0 then begin
    @PrintDlgEx := GetProcAddress(hComDlg32,'PrintDlgExA');
    if Assigned(PrintDlgEx) then begin


        ZeroMemory(@pdex, sizeof(TPrintDlgEx));
        pdex.lStructSize := sizeof(TPrintDlgEx);
        pdex.hWndOwner  := Handle;
        pdex.Flags      := PD_ALLPAGES
                            or PD_NOPAGENUMS
        ;
        pdex.nCopies    := 1;

        PrintDlgEx (pdex); // <--- Exception hier!!!
    end;
    FreeLibrary(hComDlg32);
  end;

end;

Event. sieht ja irgendjemand, wo da ein Fehler sein könnte :roteyes:

SirThornberry 23. Nov 2008 14:52

Re: Drucken mittels des PrintDlgEx-Dialogs
 
verrätst du uns auch noch die Exception? Ich würde darauf tippen das der record packed sein sollte (also anstele von "record" einen "packed record" nehmen)

Namenloser 23. Nov 2008 14:57

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Vielleicht erwartet die Funktion einen Pointer

DeddyH 23. Nov 2008 15:02

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Jepp, steht zumindest so im MSDN.
Zitat:

Parameters

lppd
[in, out] Pointer to a PRINTDLGEX structure that contains information used to initialize the property sheet. When PrintDlgEx returns, this structure contains information about the user's selections.

r29d43 23. Nov 2008 15:51

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Zitat:

Zitat von SirThornberry
verrätst du uns auch noch die Exception? Ich würde darauf tippen das der record packed sein sollte (also anstele von "record" einen "packed record" nehmen)

Die Exception lautete:

---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt Project1.exe ist eine Exception der Klasse EAccessViolation mit der Meldung 'Zugriffsverletzung bei Adresse 77AA88A0 in Modul 'comdlg32.dll'. Lesen von Adresse 0000004A' aufgetreten.
---------------------------
Anhalten Fortsetzen Hilfe
---------------------------

..und ein packed record brachte leider keine Verbesserung.


@NamenLozer & DeddyH,

leider gings mit einem Pointer auch nicht. War auch irgendwie zu erwarten, denn wahrscheinlicherweise wird PrintDlgEx hier das gleiche an Parameter-Art erwarten wie PrintDlg auch. Und das ist da nunmal nur der einfache Bezeichner der Variable. Der Rest wird wohl durch die sogenannte Compilermagic erledigt.

r29d43 23. Nov 2008 15:58

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Ok, einen Fehler habe ich eben noch gefunden: In der Definition von TPrintDlgEx habe ich fünf "Word"s, die natürlich "DWord"s sein müssen.

..aber leider geht's immer noch nicht :(

SirThornberry 23. Nov 2008 16:01

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Es wird definitiv ein Pointer erwartet. Ich kenne zumindest keine Apifunktion die wirklich die gesamten Daten auf dem Stack erwartet.
Ich würde an deiner Stelle einfach mal einen Packed Record draus machen UND einen Pointer auf die Struktur übergeben.

Zitat:

..aber leider geht's immer noch nicht
Bei dieser Fehlerbeschreibung kann dir keiner weiter helfen. Die letzte Fehlermeldung hat ziemlich darauf hingewiesen das ein Pointer erwartet wird. Du hingegen hast dann wohl eine Struktur übergeben. Entsprechend wurde versucht die Anfangswerte in deiner Struktur als Pointer zu interpretieren welcher somit auf Adresse 0 gezeigt hat -> bumm

r29d43 23. Nov 2008 16:23

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Logo :wall: , jetzt wo ich die Funktion ja selbst definiert habe, muss da natürlich tatsächlich ein Pointer stehen :wall: :wall: :wall: . Wenn man PrintDlg benutzt ist das nämlich nicht nötig, weil eben die Compilermagic da dann automatisch die Adresse der Variablen hinschreibt. Da ich die ganze Zeit über nur mit PrintDlg arbeitete, habe ich mich da diesbezüglich wohl etwas zu sehr von dem ablenken lassen, was da als Parametertyp tatsächlich steht.


Also, jetzt gibt's zwar keine Exception mehr, aber es taucht auch noch kein Dialog auf. Nehme aber an, jetzt fehlen einfach noch ein paar richtig eingestellte Parameter.

SirThornberry 23. Nov 2008 16:43

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Du kannst ja mit GetLastError schauen warum nichts passiert bzw. gibt Die Funktion vielleicht auch einen Fehler zurück. Compilermagic ist beim Original auch nicht im Spiel. Anstelle eines Pointers kann man es auch per var declarieren dann ist es intern als Pointer übergeben.
Compilermagic kommt eigentilch nur in der system-unit zum Einsatz.

r29d43 23. Nov 2008 19:17

Re: Drucken mittels des PrintDlgEx-Dialogs
 
's lag, wie ich vermutet hatte, ein E_INVALIDARG -Error vor. Nachdem ich also die Argumente dann etwas optimiert bzw. vervollständigt hatte, tauchte auch endlich der Dialog auf.

Hier event. nochmal der bis dato resultierende Code hierfür (event. möchte den Dialog ja auch nochmal jemand anderes anwenden):

Delphi-Quellcode:
const
  PD_ALLPAGES                   = $00000000;
  PD_SELECTION                  = $00000001;
  PD_PAGENUMS                   = $00000002;
  PD_NOSELECTION                = $00000004;
  PD_NOPAGENUMS                 = $00000008;
  PD_COLLATE                    = $00000010;
  PD_PRINTTOFILE                = $00000020;
  PD_PRINTSETUP                 = $00000040;
  PD_NOWARNING                  = $00000080;
  PD_RETURNDC                   = $00000100;
  PD_RETURNIC                   = $00000200;
  PD_RETURNDEFAULT              = $00000400;
  PD_SHOWHELP                   = $00000800;
  PD_ENABLEPRINTHOOK            = $00001000;
  PD_ENABLESETUPHOOK            = $00002000;
  PD_ENABLEPRINTTEMPLATE        = $00004000;
  PD_ENABLESETUPTEMPLATE        = $00008000;
  PD_ENABLEPRINTTEMPLATEHANDLE  = $00010000;
  PD_ENABLESETUPTEMPLATEHANDLE  = $00020000;
  PD_USEDEVMODECOPIES           = $00040000;
  PD_USEDEVMODECOPIESANDCOLLATE = $00040000;
  PD_DISABLEPRINTTOFILE         = $00080000;
  PD_HIDEPRINTTOFILE            = $00100000;
  PD_NONETWORKBUTTON            = $00200000;
  PD_CURRENTPAGE                = $00400000;
  PD_NOCURRENTPAGE              = $00800000;
  PD_EXCLUSIONFLAGS             = $01000000;
  PD_USELARGETEMPLATE           = $10000000;

  START_PAGE_GENERAL            = $ffffffff;


type
  TPrintDlgEx = packed record
    lStructSize : Cardinal;
    hWndOwner : HWnd;
    hDevMode : Cardinal;
    hDevNames : Cardinal;
    hDC : HDC;
    Flags : Cardinal;
    Flags2 : Cardinal;
    ExclusionFlags : Cardinal;
    nPageRanges : DWord;
    nMaxPageRanges : DWord;
    lpPageRanges : Pointer;
    nMinPage : DWord;
    nMaxPage : DWord;
    nCopies : DWord;
    hInstance : Cardinal;
    lpPrintTemplateName : PAnsiChar;
    lpCallback : Pointer;
    nPropertyPages : Cardinal;
    lphPropertyPages : Cardinal;
    nStartPage : Cardinal;
    dwResultAction : Cardinal;
  end;

  TPageRange = packed record
    nFromPage, nToPage : DWord;
  end;

type TPrintDlgExFunc = function (PDEx : Pointer): DWord; stdcall;


...

procedure TForm1.Button1Click(Sender: TObject);
var hComDlg32 : THandle;
    PrintDlgEx : TPrintDlgExFunc;
    PrintDlgExResult : integer;
    pdex : TPrintDlgEx;
    PageRangeArray : array[1..3] of TPageRange;
begin

  hComDlg32 := LoadLibrary('comdlg32.dll');
  if hComDlg32 <> 0 then begin
    @PrintDlgEx := GetProcAddress(hComDlg32,'PrintDlgExA');
    if Assigned(PrintDlgEx) then begin

        ZeroMemory(@pdex, sizeof(TPrintDlgEx));
        pdex.lStructSize := sizeof(TPrintDlgEx);
        pdex.hWndOwner  := Handle;
        pdex.Flags      := PD_ALLPAGES
//                            or PD_NOCURRENTPAGE

                            ;
        pdex.nPageRanges := 1;
        pdex.nMaxPageRanges := 3;
        PageRangeArray[1].nFromPage := 1;
        PageRangeArray[1].nToPage := 1;
        pdex.lpPageRanges := @PageRangeArray[1];
        pdex.nMinPage   := 1;
        pdex.nMaxPage   := 10;
        pdex.nCopies    := 1;
        pdex.nStartPage := START_PAGE_GENERAL;

        PrintDlgExResult := PrintDlgEx(@pdex);
        if PrintDlgExResult <> S_Ok then begin
          if PrintDlgExResult = E_OUTOFMEMORY then showMessage('E_OUTOFMEMORY');
          if PrintDlgExResult = E_INVALIDARG then showMessage('E_INVALIDARG');
          if PrintDlgExResult = E_POINTER then showMessage('E_POINTER');
          if PrintDlgExResult = E_HANDLE then showMessage('E_HANDLE');
          if PrintDlgExResult = E_FAIL then showMessage('E_FAIL');
        end;
    end;
    FreeLibrary(hComDlg32);
  end;
  .
  .
  .
end;

DeddyH 23. Nov 2008 19:21

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Das find ich ja mal cool, dass Du spontan Deine Lösung hier postest (ist leider irgendwie nicht selbstverständlich). Nur würde ich statt der ganzen "if"s am Codeende eine case-Abfrage bevorzugen, aber das kann ja jeder so machen wie er will. :thumb:

Namenloser 23. Nov 2008 20:18

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Wo wir schon grade dabei sind: es wäre auch bessre, eine Exception zu erzeugen, statt eine MessageBox. Das kann man dann, je nach dem, was man mal damit vor hat, besser abfangen.

Apollonius 23. Nov 2008 20:35

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Wenn man eine Exception haben möchte, sollte man die Funktion etwas umdeklarieren:
Delphi-Quellcode:
procedure PrintDlgEx(var lppd: TPrintDlgEx); safecall;
Die Aufrufkonvention Safecall führt dazu, dass automatisch eine Exception geworfen wird, wenn die Funktion einen Fehlercode zurückgibt. Der Rückgabewert wird vollständig wegabstrahiert.

Namenloser 23. Nov 2008 21:07

Re: Drucken mittels des PrintDlgEx-Dialogs
 
Wieder was dazu gelernt :mrgreen:


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:51 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz