Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Shellexecute richtig anwenden/übersetzen (https://www.delphipraxis.net/198222-shellexecute-richtig-anwenden-uebersetzen.html)

Delbor 15. Okt 2018 14:06

Delphi-Version: 10.2 Tokyo

Shellexecute richtig anwenden/übersetzen
 
Hi zusammen
In einem in Javascript geschriebenen Beispielcode wird Shellexecute aufgerufen:


Ich hab im Editor 2 Zeilen, von denen die erste die Javascript-Schnipel wiedergibt und die 2. diie entsprechende Schreibweise in ObjectPascal definieren sollte.
Delphi-Quellcode:
    ShellExecute("RUNDLL32.exe", "PRINTUI.DLL,PrintUIEntry /k /n \"PDFCreator\"", "", "open", 1);
    ShellExecute('RUNDLL32.exe', 'PRINTUI.DLL,PrintUIEntry /k /n \'PDFCreator\'', '', 'open', 1);
Die ersten 2 Parameter sind String, bzw. PChar. Der 3. Parameter besteht ausdem Bezeichner PDFCreator, gefolgt von einem Backslash. Das ist insofern Korrekt, als Shellexecute an dieser Stelle tatsächlich keinen String erwartet.

Ich hab eigentlich nicht erwartet, dass das gleich funktioniert, insbesondere, da an shellexecute PChars übergeben werden müssen. Dass aber ein Kompilierungsversuch fehlschlägt, weil shellexecute unbekannt ist - in meiner Usesliste ist als erstes Winapi.Windows eingetragen ist - so hab ich denn ShellAPI dazugefügt. Komischerweise weiss Delphi selbst nichts von seinem guten Bekannten.
Ein kleiner Hinweis auf der entsprechenden Helpseite, und man wüsste, was einzubinden ist. Und die Entwicklung mit Delphi wäre noch schneller!
Gegenwärtiger Stand: wie ich erwartet hatte, moniert sich Delphi am Parameter PDFCreator. Die fehlenden PChar-Umwandlungen machen sich wohl erst später bemerkbar.
Aber was soll der Parameter PDFCreator sein? Das Handle der von der RunDll zu startenden Anwendung?

Gruss
Delbor

Dalai 15. Okt 2018 14:11

AW: Shellexecute richtig anwenden/übersetzen
 
Das "PDFCreator" ist keine Variable sondern einfach in Anführungszeichen gesetzt - daher auch die Backslashes jeweils vor den Quotes.

Grüße
Dalai

Uwe Raabe 15. Okt 2018 14:19

AW: Shellexecute richtig anwenden/übersetzen
 
Da in Delphi die Anführungszeichen ja eh anders sind, wäre die richtige Umsetzung dann wohl:
Delphi-Quellcode:
  ShellExecute('RUNDLL32.exe', 'PRINTUI.DLL,PrintUIEntry /k /n "PDFCreator"', '', 'open', 1);

Delbor 15. Okt 2018 16:31

AW: Shellexecute richtig anwenden/übersetzen
 
Hi zusammen
Danke euch beiden. PDFCreator ist somit eine Art "Mitparameter"...
Natürlich funktioniertdies aber immer noch nicht, da Shellexecute als ersten Parameter ein Handle erwartet. Dementsprechend meine Fehlermeldungen:
Zitat:

[dcc32 Fehler] PDFCreatorFrameUnit.pas(73): E2010 Inkompatible Typen: 'HWND' und 'string'
[dcc32 Fehler] PDFCreatorFrameUnit.pas(73): E2010 Inkompatible Typen: 'PWideChar' und 'Integer'
[dcc32 Fehler] PDFCreatorFrameUnit.pas(84): E2035 Nicht genügend wirkliche Parameter
[dcc32 Fataler Fehler] F2063 Verwendete Unit 'PDFCreatorFrameUnit.pas' kann nicht compiliert werden
Nachstehend 2 Zeilen aus dem Beispiel, das die Verwendung da aufzeigen soll:
Delphi-Quellcode:
var objShell = new ActiveXObject("Shell.Application");
...
...
objShell.ShellExecute("RUNDLL32.exe", "PRINTUI.DLL,PrintUIEntry /k /n \"PDFCreator\"", "", "open", 1);
Ich seh hier nicht die geringste Spur eines Handles. Selbst wenn der eigentliche Aufruf der Windowsfunktion Shellexecute in einer gleichnamigen Methode des JS-Objektes 'objshell' liegen würde (worauf dieser Code mE hinweist), müste dieesem das aktuele Handle mitgeteilt werden. Oder liege ich da falsch?

Gruss
Delbor

PS: Offenbar gar nicht so sehr...

Hobbycoder 15. Okt 2018 16:48

AW: Shellexecute richtig anwenden/übersetzen
 
So wie ich das sehe, wird das Handle da nicht benötigt.

https://docs.microsoft.com/en-us/win...l-shellexecute

DeddyH 15. Okt 2018 17:04

AW: Shellexecute richtig anwenden/übersetzen
 
Da wird wohl intern das Handle der Application übergeben. In Delphi kapselt Application.MessageBox ja auch die Win32-MessageBox, so dass man da kein Handle angeben muss.

KodeZwerg 15. Okt 2018 17:17

AW: Shellexecute richtig anwenden/übersetzen
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1415781)
Da in Delphi die Anführungszeichen ja eh anders sind, wäre die richtige Umsetzung dann wohl:
Delphi-Quellcode:
  ShellExecute('RUNDLL32.exe', 'PRINTUI.DLL,PrintUIEntry /k /n "PDFCreator"', '', 'open', 1);

Delphi-Quellcode:
uses ShellApi;

...

function ExecuteShell(const Executable, Commands: String; const ShowConsole: Boolean): Cardinal;
 var
  ProcessInfo: TShellExecuteInfo;
 begin
  Result := Cardinal($FFFFFFFF);
  FillChar(ProcessInfo, SizeOf(TShellExecuteInfo), #0);
  with ProcessInfo do
  begin
   cbSize:= SizeOf( TShellExecuteInfo );
   fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT;
   Wnd := GetActiveWindow();
   lpVerb := 'open';
   lpFile:= PChar(Executable);
   lpParameters := PChar(Commands);
   lpDirectory := PChar(ExtractFilePath(Executable)); // <<-- diese zeile könnte probleme verursachen, eventuell anpassen (!)
   if ShowConsole then nShow := SW_SHOWDEFAULT else nShow := SW_HIDE;
  end;
  if ShellExecuteEx(@ProcessInfo) then
  begin
   if not GetExitCodeProcess(ProcessInfo.hProcess, Result) then Result := Cardinal($FFFFFFFF);
// GetExitCodeProcess(ProcessInfo.hProcess, Result);
   CloseHandle(ProcessInfo.hProcess);
  end
  else
  begin
   Result := GetLastError;
   exit;
  end;
 end;


...

ExecuteShell('RUNDLL32.exe', 'PRINTUI.DLL,PrintUIEntry /k /n "PDFCreator"', True);
Vielleicht klappt das?

Delbor 15. Okt 2018 19:03

AW: Shellexecute richtig anwenden/übersetzen
 
Hi KodeZwerg

Vielen Dank für deinen Code - funktioniert bestens und erzeugt mir so ein durchsuchbares Test-PDF. Alles, was mir jetzt noch bleibt,ist, die Quelle zu ändern - der Scanner liefert mir ein Bmp, bzw. ein von mir daraus erstelltes Jpeg. Aber das sollte eigentlich kein Problem mehr sein.

Gruss
Delbor

KodeZwerg 15. Okt 2018 20:06

AW: Shellexecute richtig anwenden/übersetzen
 
Freut mich das es klappt, nicht vergessen, habs oben nicht erwähnt, fehlercode prüfen/auswerten.
$FFFFFFFF = totaler fehler
nun kommt es darauf an,
man hat entweder den init-rückgabe wert der ShellExecuteEx oder einen vom System GetLastError auszuwerten.
shau am besten mal in doku nach dessen rückgabewerte, meine sind unbrauchbar/veraltet.
(ich kann dir mit dem creator nicht helfen, habe das teil nicht)

Viel Erfolg dabei, spiel damit ruhig rum, ich könnte mir vorstellen das lpDirectory in deinem speziellen fall (rundll) da ärger macht, aber wenn du bereits was damit erreichen konntest, um so besser :)

/edit
ps: ich habe es von hier, da stehen sehr viele varianten zur verfügung, im original ist auch noch eine "Warte" funktion, vielleicht wäre das sogar besser für dich?

Dalai 16. Okt 2018 02:57

AW: Shellexecute richtig anwenden/übersetzen
 
Zitat:

Zitat von Delbor (Beitrag 1415795)
Ich seh hier nicht die geringste Spur eines Handles.

Nur der Vollständigkeit halber: Die Windows API-Funktion MSDN-Library durchsuchenShellExecute aus Shell32.dll erwartet ein Handle und hat auch sonst eine andere Signatur (=Parameter), wie man in der MS-Doku zu dieser Funktion nachlesen kann. Delphi verwendet genau diese Funktion, nicht Shell.ShellExecute, das offenbar ein in Skriptsprachen (z.B. VB) übliches Shellobjekt ist.

Grüße
Dalai

Delbor 16. Okt 2018 22:03

AW: Shellexecute richtig anwenden/übersetzen
 
Hi zusammen

Die Prozedur von Kodezwerg macht keinerlei Probleme - dafür sorgt meine:
Delphi-Quellcode:
procedure TPDFCreatorFrame.ImageToPDF;
  var job : IPrintjob;
      jobinfo : IPrintJobInfo;
      PDFQueue : TQueue;
      LOutput : IOutputFiles;
begin
  PDFQueue := TQueue.Create(Self);
  try
    Showmessage('procedure TPDFCreatorFrame.ImageToPDF: Der Wert von FFilename ist: '+' "'+ FFilename + '" ');
//    FFilename ist: 'C:\PDFOfficerAppdata\PdfOfficerData\ScannedPic.jpeg';
    PDFQueue.Initialize; //  Initializing PDFCreator queue...
    ExecuteShell('RUNDLL32.exe', 'PRINTUI.DLL,PrintUIEntry /k /n "PDFCreator"', True);
    Showmessage('Setting up target path to: ' + Self.FFileName);
    Showmessage('Printing one windows test page...');
    if not PDFQueue.WaitForJob(10)then
      Showmessage('The print job did not reach the queue within ' + IntToStr(10) + ' seconds')
    else
      Showmessage('Currently there are ' + IntToStr(PDFQueue.Count) + ' job(s) in the queue');
    Showmessage('Getting job instance');
    job := PDFQueue.NextJob;

    jobinfo := job.PrintJobInfo;
    ShowMessage('jobinfo.PrintJobName := ' + jobinfo.PrintJobName);   //<== Printjobname ist 'Testseite'
    job.SetProfileByGuid('DefaultGuid');
    Showmessage('Converting under \"DefaultGuid\" conversion profile');
    job.ConvertTo(FFileName);
    if not job.IsSuccessful and not job.IsFinished then
      Showmessage('Could not convert the file: ' + FFileName)
    else
      Showmessage('Job finished successfully');
    PDFQueue.ReleaseCom;
  finally
    PDFQueue.Free;
  end;
end;
Die Prozedure wird aufgerufen, wenn der Scanvorgang beendet ist, das gescannte Bild in Jpeg verwandelt und gespeichert ist. Von daher kommt der Wert von FFilename.
Stelle ichnur auf diesen Code ab, muss ich annehmen, dass PDFQueue bei der Initialisierung den Pfad erhält. Laut dem Beispieöcode ist das aber nicht der Fall:
Delphi-Quellcode:
var objFSO = new ActiveXObject("Scripting.FileSystemObject");
var objShell = new ActiveXObject("Shell.Application");

var Scriptname = objFSO.GetFileName(WScript.ScriptFullname);

if (WScript.Version < 5.6)
{
 WScript.Echo("You need the \"Windows Scripting Host version 5.6\" or greater!");
 WScript.Quit();
}

try
{
var PDFCreatorQueue = new ActiveXObject("PDFCreator.JobQueue");

WScript.Echo("Initializing PDFCreator queue...");
PDFCreatorQueue.Initialize();

{ hier ermittelt das Script den Pfad und übergibt den Pfad an das Objekt objFSO  -  gibts bei mir nicht}
 var fullPath = objFSO.GetParentFolderName(WScript.ScriptFullname) + "\\TestPage.jpg"; // Hier der Pfad zur Testseite
WScript.Echo("Setting up target path to: " + fullPath);
{Allerdings steht hier der Pfad erstmal in der Variablen "fullpath". Wenn ich das richtig lese (und verstanden habe),führt Shellexecute in den folgenden Zeilen}
{Rundll32 aus, und diese PrintUI.DLL unter Angabe des Einsprungpunktes -  von der Übergabe eines Dateinamens seh ich hier nichts} 
WScript.Echo("Printing windows test page...");
 objShell.ShellExecute("RUNDLL32.exe", "PRINTUI.DLL,PrintUIEntry /k /n \"PDFCreator\"", "", "open", 1);
Gruss
Delbor

KodeZwerg 17. Okt 2018 06:32

AW: Shellexecute richtig anwenden/übersetzen
 
moin, gibts zufällig "PDFQueue" <<-- darüber mehr informationen?
zeige mal bitte was "TQueue" ist.

Delbor 17. Okt 2018 07:35

AW: Shellexecute richtig anwenden/übersetzen
 
Hi Kodezwerg

Guten Morgen, Kodezwerg!
So ist die Definition in der TLB:
Delphi-Quellcode:
  IQueue = dispinterface
    ['{3803F46C-F5AA-4B86-8B9C-6EFFAC9CDCFA}']
    procedure Initialize; dispid 1610743808;
    function WaitForJob(timeOut: Integer): WordBool; dispid 1610743809;
    function WaitForJobs(jobCount: Integer; timeOut: Integer): WordBool; dispid 1610743810;
    property Count: Integer readonly dispid 1610743811;
    property NextJob: IPrintJob readonly dispid 1610743812;
    function GetJobByIndex(jobIndex: Integer): IPrintJob; dispid 1610743813;
    procedure MergeJobs(const job1: IPrintJob; const job2: IPrintJob); dispid 1610743814;
    procedure MergeAllJobs; dispid 1610743815;
    procedure Clear; dispid 1610743816;
    procedure DeleteJob(index: Integer); dispid 1610743817;
    procedure ReleaseCom; dispid 1610743818;
  end;
Und ddas sind die Definitionen der Wrapperkomponenten im Frame:
Delphi-Quellcode:
type
  TPDFCreatorFrame = class(TFrame)
    PdfCreatorObj1: TPdfCreatorObj;
    OutputFiles1: TOutputFiles;
    Printers1: TPrinters;
    PrintJob1: TPrintJob;
    PrintJobInfo1: TPrintJobInfo;
    Queue1: TQueue;
Gruss
Delbor

KodeZwerg 17. Okt 2018 08:18

AW: Shellexecute richtig anwenden/übersetzen
 
Code:
ShellExecute method
Run a script or application in the Windows Shell.

Syntax
      .ShellExecute "application", "parameters", "dir", "verb", window
das ist was das script macht, das ist was wir da mit shellexecuteex auch machen.
(um ganz genau zu seien musst du lpDirectory auf := '' setzen)


also das script funktioniert und erzeugt tatsächlich eine datei, ja?
ich bin gerade mehrere "Scripting.FileSystemObject" definitionen hinterher und da wirds oftmals im execute part eingebettet was hier nicht der fall ist.

hier kann man sich den Print Befehl anschauen

per definition macht "/k = prints a test page on a printer."
und "/n[name] = Specifies the printer name."

Delbor 17. Okt 2018 10:35

AW: Shellexecute richtig anwenden/übersetzen
 
Hi Kodezwerg

Danke für deinen Link! Da ich meinen Englischkenntnissen immer noch nicht so ganz traue, hab ich mir angewöhnt, solche Seiten per Google zu übersetzen - allerdings klappt das Übersetzenlassen kompletter Websites nicht immer. Und so wird das dannoft zur Sisiphusarbeit, und da brauchts dannöfters mal Pause.
Und die bringen doch schon mal gute Erkenntnisse:

Zitat:

Zitat von KodeZwerg (Beitrag 1415934)
[CODE]
per definition macht "/k = prints a test page on a printer."
und "/n[name] = Specifies the printer name."

Aus meiner Word-Datei für die Übersetzungen:
Zitat:

Modification Parameters Description
-------------- --------
/a[file] / a [Datei] Gibt den Namen der Binärdatei an.
Wenn ich das richtig verstehe, muss ich also lediglich den Parameter "/k" durch "a[FFilename] ersetzen...

Aber das hat soeben nicht geklappt. Leider hab ich im entscheidenden Moment zuwenig aufgepasst, aber wenn ich das richtig mitbekommen habe, krachte es hier:
Delphi-Quellcode:
lpDirectory := PChar(ExtractFilePath(Executable)); // <<-- diese zeile könnte probleme verursachen, eventuell anpassen (!)
Die Meldung: "Die Argumente sind ungültig"

Gruss
Delbor

Delbor 17. Okt 2018 11:03

AW: Shellexecute richtig anwenden/übersetzen
 
Zitat:

Zitat von KodeZwerg (Beitrag 1415934)
(um ganz genau zu seien musst du lpDirectory auf := '' setzen)

Das habe ich überlesen...
Zitat:

Zitat von KodeZwerg (Beitrag 1415934)
also das script funktioniert und erzeugt tatsächlich eine datei, ja?
ich bin gerade mehrere "Scripting.FileSystemObject" definitionen hinterher und da wirds oftmals im execute part eingebettet was hier nicht der fall ist.

Ja, aber eben nur die Windows-Testseite.

Gruss
Delbor

KodeZwerg 17. Okt 2018 11:45

AW: Shellexecute richtig anwenden/übersetzen
 
Delphi-Quellcode:
procedure TPDFCreatorFrame.ImageToPDF;
  var job : IPrintjob;
      jobinfo : IPrintJobInfo;
      PDFQueue : TQueue;
      LOutput : IOutputFiles;
begin
  PDFQueue := TQueue.Create(Self);
  try
    Showmessage('procedure TPDFCreatorFrame.ImageToPDF: Der Wert von FFilename ist: '+' "'+ FFilename + '" ');
// FFilename ist: 'C:\PDFOfficerAppdata\PdfOfficerData\ScannedPic.jpeg';
    LOutput := IOutputFiles.Create(FFilename); // oder sowas ?
    PDFQueue.Initialize; // Initializing PDFCreator queue...
da der das ganze anscheinend als objekt abarbeitet eventuell dem das irgendwie mittleilen?
ich bin da echt nur am raten da ich das nicht habe.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:48 Uhr.

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