![]() |
Delphi-Version: 11 Alexandria
Ärger mit Shellexecute
Hi zusammen
In meinem OpenfileFrame möchte ich PDF-Dateien direkt in einem entsprechenden Programm öffnen, bearbeiten und wieder schliessen Zudem soll das fremde Programm auf einem Container als Parent platziert werden. Dazu verwende ich vorerstfolgendes Codeschnipsel, noch ohne die beabsichtigte Platzierung:
Delphi-Quellcode:
Sorgen macht mir die Zeile mit Shellexecute.Die Fehlermeldung :
procedure TAlexOpenfileFrame.TVFilesExplorerMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var AnItem: TTreeNode; P: TPoint; LSelectItem, ext : String; begin AnItem := TVFilesExplorer.GetNodeAt(X, Y); if Button =(mbLeft) then begin LSelectItem := PNameRec(AnItem.Data)^.RealName; ext := ExtractFileExt(LSelectItem); if ext = '.pdf' then begin ShellExecute(handle, 'open', PChar('F:\Externer Programmordner\Ashampoo\Ashampoo PDF Free\Ashampoo PDF.exe', PChar(LSelectItem), nil, SW_SHOWNORMAL)); end; end; ... ... Zitat:
Gruss Delbor |
AW: Ärger mit Shellexecute
Zähl doch einfach mal die öffnenden und die schließenden Klammern, dann wirst Du merken, dass nach dem ersten Cast zu PChar die Klammer nicht geschlossen ist. Soviel Eigeninitiative könnte man aber IMO schon erwarten.
[edit] Ah, das hast Du scheinbar bereits gemacht und dann wohl einfach mal eine Klammer ganz ans Ende gesetzt. Kann man machen, aber das muss nicht funktionieren. [/edit] |
AW: Ärger mit Shellexecute
Hi DeddyH
Zitat:
"Wer Augen hat zu sehen...", oder ist der schon abgewandelt? Vielen Dank und schönes restliches Wochenende! Gruss Delbor |
AW: Ärger mit Shellexecute
Hi zusammen
Nachdem ich nun die Klammer richtig gesetzt habe, lässt sich nun das fremde Programm starten. Nun will ich es noch auf ein Tabsheet einpassen Es soll da bis zur Beendigung des "Mutterprogramms" bleiben, so dass es jederzeit erneut zur Verfügung steht. Das soll vorerst mal mit diesem Code geschehen:
Delphi-Quellcode:
und
procedure TAlexOpenfileFrame.TVFilesExplorerMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var AnItem: TTreeNode; P: TPoint; LSelectItem, ext : String; begin FCodeReportlist.Add('procedure TAlexOpenfileFrame.TVFilesExplorerMouseDown'); FCodeReportlist.Add('--------------------------------------'); AnItem := TVFilesExplorer.GetNodeAt(X, Y); if Button =(mbLeft) then begin LSelectItem := PNameRec(AnItem.Data)^.RealName; ext := ExtractFileExt(LSelectItem); if ext = '.pdf' then begin ShellExecute(handle, 'open', PChar('F:\Externer Programmordner\Ashampoo\Ashampoo PDF Free\Ashampoo PDF.exe'), PChar(LSelectItem), nil, SW_SHOWNORMAL); SetAppParent(Application.Name); end; end; if Button =(mbRight) then begin
Delphi-Quellcode:
Zur Zeit habe ich einen Breakpoint beim Aufruf 'SetAppParent'gesetzt, Delphi hält da an,und zur gleichen Zeit wird die App gestartet. Allerdings nicht auf dem Tabsheet, sondern Solo.
procedure TAlexOpenfileFrame.SetAppParent(Application : String);
var aWnd : Hwnd; WPM : TWindowPlacement; Rect : TRect; begin aWnd:=Findwindow(PChar(Application),nil); if aWnd<>0 then begin Winapi.Windows.SetParent(awnd,OfficerAlexMain.tbsAppParent.Handle); WPM.Length:=SizeOf(WPM); GetWindowPlacement(awnd,@WPM); Rect.Top :=0; Rect.Left :=0; Rect.Right :=OfficerAlexMain.tbsAppParent.Width; Rect.Bottom:=OfficerAlexMain.tbsAppParent.Height; wpm.rcNormalPosition:=Rect; SetWindowPlacement(awnd,@WPM); end; end; Der letzte Parameter von Shellexecute ist hier SW_SHOWNORMAL - der könnte wohl in SW_Hide geändert werden und erst bei/nach Rückkehr aus SetAppParent auf SW_SHOWNORMAL gesetzt werden - ob das allerdings so einfach ist, wie das in Pascal wohl wäre... Hat jemand eine bessere Idee? Gruss Delbor |
AW: Ärger mit Shellexecute
Natürlich nicht.
Du setzt die Platzierung (Position/Placement) über die Position, aber du setzt nicht den Parent, also die Form in dein Panel. ![]() |
AW: Ärger mit Shellexecute
Hi zusammen
Im Moment ist vor allem das eine Handle nil(0):
Delphi-Quellcode:
Ich hab bisher noch weiter gesucht und mit verscchiedenen Codeversionne gearbeitet - wenn aWnd 0 ist, nützt das alles nichts.
aWnd:=FindWindow(PChar('Ashampoo PDF'), nil);
if aWnd<>0 then begin Winapi.Windows.SetParent(awnd,OfficerAlexMain.tbsAppParent.Handle); end; Ich habe auch ![]()
Delphi-Quellcode:
von zwei ähnlichen Prozeduren mal separat als Reaktion auf einen Button nachgebaut:
procedure TOfficerAlexMain.FindPaint;
var aWnd : Hwnd; WPM : TWindowPlacement; Rect : TRect; begin aWnd:=Findwindow('paint.net',nil); if aWnd<>0 then begin Winapi.Windows.SetParent(awnd,OfficerAlexMain.tbsAppParent.Handle); WPM.Length:=SizeOf(WPM); GetWindowPlacement(awnd,@WPM); Rect.Top :=0; Rect.Left :=0; Rect.Right :=Panel1.Width; Rect.Bottom:=Panel1.Height; wpm.rcNormalPosition:=Rect; SetWindowPlacement(awnd,@WPM); end; end;
Delphi-Quellcode:
Hier und in meinen bisherigen Umsetzungen ist die Variable aWnd immer 0, womit der darunter folgende Code nicht ausgeführt wird.
procedure TOfficerAlexMain.FindPaint;
var aWnd : Hwnd; WPM : TWindowPlacement; Rect : TRect; begin aWnd:=Findwindow('paint.net',nil); if aWnd<>0 then begin Winapi.Windows.SetParent(awnd,OfficerAlexMain.tbsAppParent.Handle); WPM.Length:=SizeOf(WPM); GetWindowPlacement(awnd,@WPM); Rect.Top :=0; Rect.Left :=0; Rect.Right :=Panel1.Width; Rect.Bottom:=Panel1.Height; wpm.rcNormalPosition:=Rect; SetWindowPlacement(awnd,@WPM); end; end; Wieso das? Gruss Delbor |
AW: Ärger mit Shellexecute
Wenn es das Paint.net ist das ich meine ist es normal das du kein Handle (HWND) bekommst
denn dein Class Name stimmt nicht und dieser ändert sich mit jeden neuem Start der Anwendung. Prüfe den Classnamen einfach mal mit einer Spy Anwendung. Paint.net vers. 4.3.11 1 Start WindowsForms10.Window.8.app.0.24cbd2a_r3_ad1 2 Start WindowsForms10.Window.8.app.0.2428e43_r3_ad1 TIP: Versuche es einfach mal mit dem Window Title. |
AW: Ärger mit Shellexecute
Hast Du es mal mit
![]() |
AW: Ärger mit Shellexecute
Vielleicht hilft dir mein code schnippsel weiter um ans ziel zu gelangen.
Delphi-Quellcode:
nach dem aufruf steht in globaler variable Exec.WindowHandle was du brauchst. Ist ein Versuch Wert.
type
TExec = packed record Filename : string; PID : DWORD; WindowHandle : HWND; end; var Exec: TExec; procedure ResetExec; begin Exec.Filename := ''; Exec.PID := 0; Exec.WindowHandle := 0; end; function EnumWindowsProc(Wnd : HWND; ProcessID : Cardinal) : Boolean; stdcall; var PID : Cardinal; begin GetWindowThreadProcessId(Wnd, @PID); if ProcessID = PID then Exec.WindowHandle := Wnd; Result := True; end; function ExecFile(const AFilename: string): Boolean; var Executable : string; Security : TSecurityAttributes; ProcessInfo: TProcessInformation; StartupInfo: TStartupInfo; dummy : HINST; begin Result := False; ResetExec; if (not FileExists(AFilename)) then Exit; SetLength(Executable, MAX_PATH); dummy := FindExecutable(PChar(AFilename), nil, PChar(Executable)); if dummy > 32 then begin SetLength(Executable, StrLen(PChar(Executable))); UniqueString(Executable); Security.nLength := SizeOf(TSecurityAttributes); Security.lpSecurityDescriptor := nil; Security.bInheritHandle := False; FillChar(StartupInfo, SizeOf(TStartupInfo), #0); StartupInfo.cb := SizeOf(TStartupInfo); StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK; StartupInfo.wShowWindow := SW_SHOWNORMAL {SW_HIDE}; Win32Check(CreateProcess(PChar(Executable), PChar(Format('%s %s', [Executable, AFilename])), @Security, @Security, False, CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, nil, PChar(ExtractFilePath(Executable)), StartupInfo, ProcessInfo)); try WaitForInputIdle(ProcessInfo.hProcess, INFINITE); Exec.Filename := Executable; Exec.PID := ProcessInfo.dwProcessId; EnumWindows(@EnumWindowsProc, LPARAM(Exec.PID)); finally CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); Result := True; end; end; end; |
AW: Ärger mit Shellexecute
Hi zusammen
Ich hab mir gestern abend das von DeddyH vorgeschlagene Wynspy mal 'installiert', aber heute morgen nichts davon vorgefunden, ausser dass mir Windows unter 'Zuletzt neu hinzugefügt' Delphi Alexandria meldet. Das hab ich gestartet und hatte bislang den Eindruck eines gewöhnlichen Delphi-Starts, bin allerdings noch nicht alle Menuepunkte durchgegangen. Den Code von CodeZwerg werd ich mir mal in eine Unit/Klasse packen. Gruss Delbor |
AW: Ärger mit Shellexecute
Zitat:
Diese Methodik funktioniert zu 100% immer zuverlässig solange das "ExecFile" kein "Wrapper" für andere Executables ist (Programm A lädt beim start Programm B oder Fenster wird in DLL erzeugt... etc) bzw solange die ProcessID ein Fenster besitzt. Wenn Du noch Fragen dazu haben solltest, ich hoffe ich kann Dir weiterhelfen. |
AW: Ärger mit Shellexecute
Muss es unbedingt Ashampo zur Anzeige von PDF-Dateien sein?
Wenn nein: Bei mir ist seit 'ner Weile ![]() Zuerst wird geprüft, ob Sumatra vorhanden ist, wenn ja, wird es genutzt. Sollte es nicht gefunden werden, wird es mit dem AcrobatReader versucht. Den Teil kann man aber auch entfernen, wenn die Nutzung vom Acrobat ausgeschlossen werden soll. Da ich nur Delphi 7 habe, wirst Du im folgenden Quelltext vermutlich einige Anpassungen vornehmen müssen. Zuerst die DFM:
Delphi-Quellcode:
und dann die dazugehörige Unit:
object fmPDFVorschau: TfmPDFVorschau
Left = 476 Top = 60 Width = 249 Height = 138 Caption = 'PDF-Vorschau' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] KeyPreview = True OldCreateOrder = False OnCreate = FormCreate OnKeyDown = FormKeyDown OnResize = FormResize OnShow = FormResize PixelsPerInch = 96 TextHeight = 13 object pnPDF: TPanel Left = 0 Top = 0 Width = 241 Height = 111 Align = alClient BevelOuter = bvNone TabOrder = 0 end end
Delphi-Quellcode:
unit uPDFVorschau;
interface uses AcroPDFLib_TLB, Forms, Classes, Controls, ExtCtrls; type TfmPDFVorschau = class(TForm) pnPDF: TPanel; procedure FormResize(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormCreate(Sender: TObject); protected procedure CreateParams(var Params: TCreateParams) ; override; private { Private-Deklarationen } fAcroPDF : TAcroPDF; fPDFFile : String; fUseSumatraPDF : Boolean; public { Public-Deklarationen } procedure LoadPDF(APdfFile : String); procedure LoadArcoPDF; procedure LoadSumatraPdF; property PDFFile : String read fPDFFile; property UseSumatraPDF : Boolean read fUseSumatraPDF write fUseSumatraPDF default false; end; var fmPDFVorschau: TfmPDFVorschau; implementation {$R *.dfm} uses Windows, SysUtils, ShellAPI; const csCaption = 'PDF-Vorschau - %s'; // Eigenen Button in die Taskbar machen, damit man per STRG+TAB zwischen den // Fenstern wechseln kann. Der eingebettet Acrobat nimmt sich leider das Recht // heraus alle Tastaturkürzel zu ignorieren, wenn sie vom Programm sind und // sich selbst so in den Focus zu setzen, dass man nicht per Mausklick ... // problemlos mit dem Programm arbeiten kann. procedure TfmPDFVorschau.CreateParams(var Params: TCreateParams); begin inherited; Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; Params.WndParent := 0; end; procedure TfmPDFVorschau.FormCreate(Sender: TObject); begin // Das muss ggfls. angepasst werden. fUseSumatraPDF := FileExists('.\Lib\SumatraPDF.exe'); end; procedure TfmPDFVorschau.FormResize(Sender: TObject); begin if not fUseSumatraPDF then begin if Assigned(fAcroPDF) then begin if fAcroPDF.Visible then begin fAcroPDF.LoadFile(fPDFFile); fAcroPDF.Update; end; end; end else if Assigned(pnPDF) then begin pnPDF.Align := alTop; Application.ProcessMessages; pnPDF.Align := alClient; end; end; procedure TfmPDFVorschau.LoadPDF(APDFFile : String); begin fPDFFile := APDFFile; Caption := Format(csCaption,[ChangeFileExt(ExtractFileName(fPDFFile),'')]); case fUseSumatraPDF of true : LoadSumatraPDF; false : LoadArcoPDF; end; end; procedure TfmPDFVorschau.LoadArcoPDF; begin Screen.Cursor := crHourGlass; if Assigned(pnPDF) then pnPDF.Visible := False; if not Assigned(fAcroPDF) then begin fAcroPDF := TAcroPDF.Create(Self); fAcroPDF.Parent := Self; fAcroPDF.Left := 0; fAcroPDF.Top := 0; fAcroPDF.Width := Width; fAcroPDF.Height := Height; fAcroPDF.TabStop := False; fAcroPDF.Align := alClient; fAcroPDF.ParentShowHint := False; fAcroPDF.ShowHint := True; fAcroPDF.TabOrder := 0; fAcroPDF.Visible := True; end; fAcroPDF.src := fPDFFile; fAcroPDF.LoadFile(fPDFFile); Screen.Cursor := crDefault; Show; end; procedure TfmPDFVorschau.LoadSumatraPDF; var sParam : String; begin Screen.Cursor := crHourGlass; if Assigned(fAcroPDF) then fAcroPDF.Visible := False; // Caption := Format(csCaption,[fPDFFile]); // -reuse-instance funktioniert nur, wenn immer die gleiche Datei geladen wird, // andernfalls entsteht für jede PDF-Datei eine neue Instanz von SumatraPDF. // Die Instanzen von SumatraPDF werden beendet, wenn man das Programm beendet. // Bei diesem Vorgehen entsteht aber nur eine Instanz von SumatraPDF. pnPDF.Free; Sleep(1000); // Warten, bis sich SumatraPDF beendet hat. pnPDF := TPanel.Create(Self); pnPDF.Parent := Self; pnPDF.Left := 0; pnPDF.Top := 0; pnPDF.Width := Width; pnPDF.Height := Height; pnPDF.BevelOuter := bvNone; pnPDF.TabOrder := 1; pnPDF.Align := alClient; pnPDF.Visible := True; sParam := Format('-lang de -reuse-instance -plugin %d "%s"',[pnPDF.Handle,fPDFFile]); ShellExecute(Self.Handle,'open',PAnsiChar('SumatraPDF.exe'),PAnsiChar(sParam),'',sw_normal); Screen.Cursor := crDefault; Show; end; procedure TfmPDFVorschau.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin case key of 27 : Close; end; end; end. |
AW: Ärger mit Shellexecute
Zitat:
Das ist denke ich ein separat aufrufbares Programm, welches einem alle handles usw. anzeigt. |
AW: Ärger mit Shellexecute
Einfach auf den Link Klicken, dann sieht man, dass das ein Programm des DP-Mitglieds toms ist ;-)
|
AW: Ärger mit Shellexecute
Hi zusammen
@ Delphi.Narium: Nebst einem kostenpflichtigen Programm, das ich mir schon vor Jahr(-zehnt)en zugelegt habe, habe ich mir noch Ashampo PDF Free zugelegt, womit ich PDFs ausfüllen und sie mit beliebigen, auch benutzerdefinierten Stempeln versehen kann - und die Internethilfe ist in normalem Deutsch ohne jegliches Fachchinesisch abgehalten (..). Das ist für mich der Hauptgrund, warum ich vorerst bei Ashompoo bleiben will. Für mein Programm hingegen muss es völlig gleichgültig sein, mit welchen fremden Programmen es arbeitet. @Turbomagic: Zitat:
Gruss Delbor |
AW: Ärger mit Shellexecute
Der Download ist ein Zip-Archiv, da wird nichts installiert. Du musst also den Ordner öffnen, in den Du entpackt hast und dort die WinSpy.exe starten.
|
AW: Ärger mit Shellexecute
|
AW: Ärger mit Shellexecute
Hier ist eine deutlich jüngere Version von Winspy aus dem Jahr 2018:
![]() VirusTotal ![]() Bestimmt nur ein Fehlalarm? Gruß, Andreas |
AW: Ärger mit Shellexecute
Liste der Anhänge anzeigen (Anzahl: 4)
Hi zusammen
Zitat:
Anhang 55129 Nach dem entpacken und "installieren": Anhang 55130 und der Taskmanager Anhang 55131 Wie ich den wieder anzeige, ist mir ein Rätsel. Auch das menü des Taskmanagers weiss es nicht: Anhang 55132 Zumindest, wenn ich richtig gelesen habe. Was mache ich falsch? @Andreas13 Habe deinen Beitag eben jetzt gesehen. Danke! Allerdings von wegen Viruse - ich arbeite mit dem windowseigenen Defender. Gruss Delbor |
AW: Ärger mit Shellexecute
Nutze lieber den Window Detective, der kann noch ein bisschen mehr und kann wahlweise per Installer heruntergeladen werden:
![]() |
AW: Ärger mit Shellexecute
Zitat:
Idr. muss man per "AttachThreadInput()" die beiden seperaten prozesse vereinen, aber nichts desto trotz, generisch betrachtet ist es das schlimmste an was man überhaupt denken kann, da du keine Ahnung von den inneren Message-Ketten hast, die bei solch einem vorhaben schlichtweg zerschossen werden könnten. |
AW: Ärger mit Shellexecute
Hi zusammen
Zitat:
Ich werde noch einen Versuch mit Createprozess und warten auf das Ende probieren - aber ich fürchte, dass ich dann entweder das eine oder andere Programm bearbeiten kann, nicht jedoch beide. Dein zweiter Abschnitt, und besonders dein letzter Satz, habensaber in sich! Gruss Delbor |
AW: Ärger mit Shellexecute
Zitat:
Zitat:
Nebenbei, "CreateProcess()" nutze ich nur um sofort die 100% stimmende ProcessID zu erhalten um dann wiederum das WindowHandle zu ermitteln. (Windows arbeitet nun mal intern nur mit ProcessIDs und Handles) Da ein Prozess mehrfach geladen werden kann sind andere Methoden zur Ermittlung eher... schwammig :-) |
AW: Ärger mit Shellexecute
Bei einem externen Programm mußt du das richtige Fenster finden und dort kannst du den Parant auf etwas in deinem Programm (Form/Panel/...) setzen.
Vom Acrobat-Reader gibt es noch eine ActiveX-Komponente, die man in sein Programm einbinden kann. Aber offiziell wird sie nicht mehr für "fremde" Programme entwickelt, sondern nur für die Einfondung in die bekanntestens Browser. (sagt der Hersteller) Und außerdem ändern die Arschlöcher andauern das Verhalten, was dann im eigenen Programm keinen Spaß macht und unsere Kunden nervt. Daher nutzen wir aktuell die Komponente von DevExpress, um PDFs im Programm anzuzeigen. (die kann nicht alles und ist auch etwas langsamer, aber daran wird weiter gearbeitet) Diese Komponente ist nun im Programm und bleibt somit immer gleich. Versuch mal einem Nutzer deines Programms zu erklären, dass es nicht deine Schuld ist, wenn es ein Update bei Acrobat gab und es in "deinem" Programm dann nicht mehr so geht, wie es soll. Selbst Schuld, dass Acrobat nun immer mehr an Bedeutung verliert, dazumal inzwischen alle großen Browser selber was für PDF mitbringen. Im Prinzip kann man somit nun auch im Delphi z.B. den TWebBrowser nutzen und darin dann die PDF anzeigen und sei es, indem man selbst eine Version von z.B. ![]() |
AW: Ärger mit Shellexecute
Hi zusammen
Mein dringlichstes 'Problem', nämlich die Anzeige eines fremden Programmws in meinem, habe ich nun 'gelöst'. Bei MausDown in meinem TAlexOpenfileFrame:
Delphi-Quellcode:
und
if Button =(mbLeft) then
begin LSelectItem := PNameRec(AnItem.Data)^.RealName; ext := ExtractFileExt(LSelectItem); if ext = '.pdf' then begin ShellExecAndWait('F:\Externer Programmordner\Ashampoo\Ashampoo PDF Free\Ashampoo PDF.exe', LSelectItem, SW_Normal ); end; end;
Delphi-Quellcode:
Der Code stammt bis auf meine Komponenten von
procedure TAlexOpenfileFrame.ShellExecAndWait(dateiname, Parameter: string; ShowHide: Integer); // benötigt ShellAPI in Uses
var executeInfo: TShellExecuteInfo; dw: DWORD; begin FillChar(executeInfo, SizeOf(executeInfo), 0); with executeInfo do begin cbSize := SizeOf(executeInfo); fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT; Wnd := GetActiveWindow(); executeInfo.lpVerb := 'open'; executeInfo.lpParameters := PChar(Parameter); lpFile := PChar(dateiname); nShow := ShowHide; end; if ShellExecuteEx(@executeInfo) then dw := executeInfo.HProcess else begin ShowMessage('Fehler: ' + SysErrorMessage(GetLastError)); exit; end; while WaitForSingleObject(executeInfo.hProcess, 50) <> WAIT_OBJECT_0 do Application.ProcessMessages; CloseHandle(dw); end; ![]() ![]() Na ja, so ähnlich zumindest. Ich bin so frei und erspare mir den Versuch des Abgleichs mit all den in diesem Forum gefundenen wohl mehreren dutzend Codeschnipsel. Das vorerst wichtigste: Ich kann abwechselnd mit beiden Programmen arbeiten. Gruss Delbor |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:36 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 by Thomas Breitkreuz