![]() |
Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Hi Leute,
für alle die wie ich Delphi/Lazarus Newbie und ProgrammierNewbie sind... So kann man mit einem Klick zwei WindowsExplorer starten und nebeneinander anordnen. Einfach irgendwo hinlegen und den Pfad in die Verknüpfung schreiben.. Ach was? JaJa Ob das jetzt der ultimativ beste Weg ist wage ich mal zu bezweifeln... grins...
Delphi-Quellcode:
Kann man natürlich auch als KonsolenAnwendung erstellen, aber dann muß man das Konsolenfenster ausblenden.
Unit ShowTwoWindowsExplorer;
Interface Uses Windows, Messages, SysUtils, Classes, Controls, Forms, ShellApi; Type TForm1 = Class(TForm) Procedure FormCreate(Sender: TObject); Procedure FormActivate(Sender: TObject); Procedure FormShow(Sender: TObject); Private Procedure WMSysCommand(Var Message: TWMSysCommand); Message WM_SysCommand; End; Var Form1: TForm1; Implementation {$R *.dfm} // Yes, this is optional or certainly overkill... hahaha... Procedure TForm1.WMSysCommand(var Message: TWMSysCommand); Begin Try If Message.CmdType And $FFF0 = SC_MINIMIZE Then Form1.Hide Else Inherited; Except Exit; End; End; Procedure TForm1.FormCreate(Sender: TObject); Var hwnd_Explorer : HWND; Begin Try Form1.Height := 1; Form1.Width := 1; Form1.Top := 0; Form1.Left := 0; Form1.AlphaBlend := True; Form1.AlphaBlendValue := 0; If DirectoryExists('I:\') Then Begin ShellExecute(Form1.Handle, Nil, PChar('I:\MARTIN\(DOWNLOADS)'), Nil, Nil, SW_SHOW); hwnd_Explorer := FindWindow(Nil, 'I:\MARTIN\(DOWNLOADS)'); MoveWindow(hwnd_Explorer, 0, 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); SetWindowPos(hwnd_Explorer, HWND_NOTOPMOST,0,0,0,0, SWP_NOSIZE); ShellExecute(Form1.Handle, Nil, PChar('I:\MARTIN'), Nil, Nil, SW_SHOW); hwnd_Explorer := FindWindow(Nil, 'I:\MARTIN'); MoveWindow(hwnd_Explorer, (Screen.Width div 2), 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); SetWindowPos(hwnd_Explorer, HWND_NOTOPMOST,0,0,0,0, SWP_NOSIZE); End Else Begin ShellExecute(Form1.Handle, Nil, PChar('C:\'), Nil, Nil, SW_SHOW); hwnd_Explorer := FindWindow(Nil, 'C:\'); MoveWindow(hwnd_Explorer, 0, 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); SetWindowPos(hwnd_Explorer, HWND_NOTOPMOST,0,0,0,0, SWP_NOSIZE); ShellExecute(Form1.Handle, Nil, PChar('D:\'), Nil, Nil, SW_SHOW); hwnd_Explorer := FindWindow(Nil, 'D:\'); MoveWindow(hwnd_Explorer, (Screen.Width div 2), 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); SetWindowPos(hwnd_Explorer, HWND_NOTOPMOST,0,0,0,0, SWP_NOSIZE); End; Except Exit; End; End; Procedure TForm1.FormShow(Sender: TObject); Var Owner: HWND; Begin Try Owner := GetWindow(Form1.Handle, GW_OWNER); ShowWindow(Owner, SW_HIDE); Except Exit; End; End; Procedure TForm1.FormActivate(Sender: TObject); Begin Try Close; Except FreeAndNil(Form1); Exit; End; End; End. Ist also wahrscheinlich schon egal oder Geschmacksache oder was auch immer... Ich bin froh, dass das funktioniert und frage mich warum ich das nicht schon früher benutzt habe. Obwohl Windows7 das (Downloads)-Verzeichnis immer rechts zeigt... sollte eigentlich laut QuellCode links liegen, aber vielleicht liegt das auch an der Uhrzeit... Ich seh' den Wald vor lauter Bäumen nicht mehr.... grins... Hat 'ne Weile gedauert bis ich die Sleep(50)-Befehle herausnehmen konnte... Ich hab' SW_ShowNormal statt SW_Show benutzt und das ging nur mit Sleep und jetzt weis ich auch warum... Alle bis jetzt ausprobierten Explorer (DoubleCommander, SpeedCommander, TotalCommander, FreeCommander..) starten deutlich langsamer als der WindowsExplorer und zeigen auch nicht gleichzeitig Details und Bilder an. Ok, die werden natürlich weiterentwickelt.. vielleicht kann der eine oder andere das ja mittlerweile doch... Ich bin müde... zugegeben ich wollte nur mal sehen wie man etwas posted... Ist das überhaupt das richtige Themegebiet ? Na ja, ist vielleicht auch egal... Weiterhin viel Spaß und gute Unterhaltung... Gruß Martin |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Anmerkungen:
Jedem Window ein eigenes Handle. SetWindowPos ist überflüssig. Ohne Sleep geht es bei mir nicht. DirectoryExists immer anwenden. WINDOWS ist - wie üblich - verwirrend: Pfadname: C:\Users\HATHOR\Documents Window-Title: Dokumente
Delphi-Quellcode:
Das ganze lässt sich vereinfachen - mehr braucht man nicht, wenn das Programm sonst nichts tut:
Var hwnd_Explorer1, hwnd_Explorer2 : HWND;
If DirectoryExists('C:\Users\HATHOR\Documents') then BEGIN ShellExecute(Form1.Handle, Nil, PChar('C:\Users\HATHOR\Documents'), Nil, Nil, SW_SHOW); Application.ProcessMessages; Sleep(500); hwnd_Explorer1 := FindWindow(Nil, 'Dokumente'); MoveWindow(hwnd_Explorer1, 0, 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); // SetWindowPos(hwnd_Explorer1, HWND_NOTOPMOST,0,0,0,0, SWP_NOSIZE); END; // If DirectoryExists('F:\TOOLS') then BEGIN ShellExecute(Form1.Handle, Nil, PChar('F:\TOOLS'), Nil, Nil, SW_SHOW); Application.ProcessMessages; Sleep(500); hwnd_Explorer2 := FindWindow(Nil, 'F:\TOOLS'); MoveWindow(hwnd_Explorer2, (Screen.Width div 2), 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); // SetWindowPos(hwnd_Explorer2, HWND_NOTOPMOST,0,0,0,0, SWP_NOSIZE); END;
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
Var hwnd_Explorer1, hwnd_Explorer2 : HWND; begin If DirectoryExists('C:\Users\HATHOR\Documents') then BEGIN ShellExecute(Form1.Handle, Nil, PChar('C:\Users\HATHOR\Documents'), Nil, Nil, SW_SHOW); Application.ProcessMessages; Sleep(500); hwnd_Explorer1 := FindWindow(Nil, 'Dokumente'); MoveWindow(hwnd_Explorer1, 0, 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); END; If DirectoryExists('F:\TOOLS') then BEGIN ShellExecute(Form1.Handle, Nil, PChar('F:\TOOLS'), Nil, Nil, SW_SHOW); Application.ProcessMessages; Sleep(500); hwnd_Explorer2 := FindWindow(Nil, 'F:\TOOLS'); MoveWindow(hwnd_Explorer2, (Screen.Width div 2), 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); END; Application.Terminate; end; |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Hallo,
die Idee als solches finde ich ja gut. Die Zähne beisse ich mir aber schon seit über einer Stunde daran aus, das "Sleep" zu ersetzen, weil es ja hardwareabhängig ist. Der Grundgedanke ist, aus dem ProcessHandle das WindowHandle zu bekommen.
Delphi-Quellcode:
Vielleicht hat ja jemand eine Idee?
function ShellExecExplorer(aClientHandle: THandle;
aParameters: string; var aExplorerHandle: THandle): Boolean; var SEI: TShellExecuteInfo; begin aExplorerHandle := 0; FillChar(SEI, SizeOf(SEI), #0); SEI.cbSize := SizeOf(SEI); SEI.Wnd := aClientHandle; SEI.fMask := SEE_MASK_NOCLOSEPROCESS; SEI.lpVerb := 'open'; SEI.lpFile := PChar('explorer.exe'); SEI.lpParameters := PChar(aParameters); SEI.lpDirectory := nil; SEI.nShow := SW_SHOWNORMAL; Result := ShellExecuteEx(@SEI); if Result then begin if SEI.hProcess > 32 then begin Sleep(1000); // WaitForInputIdle(SEI.hProcess, INFINITE); hab ich probiert, tut nicht end; end; CloseHandle(SEI.hProcess); end; |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
|
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Wenn die Explorer-Instanz nicht innerhalb der Sleep-Zeit gestartet wird, findet FindWindow kein Handle und folglich funzt auch MoveWindow nicht.
In der Zwischenzeit hab ich noch etwas rum gespielt. Schön wär es auch, wenn eine bereits vorhandene Instanz angezeigt und neu positioniert würde. Je länger ich daran "spiele" umso mehr gefällt mir der Gedanke. Aktueller Stand (ist noch nicht fertig)
Delphi-Quellcode:
const
TC = ' | '; function ShellExecExplorer(aClientHandle: THandle; aParameters: string; var aExplorerHandle: THandle): Boolean; var SEI: TShellExecuteInfo; begin aExplorerHandle := 0; FillChar(SEI, SizeOf(SEI), #0); SEI.cbSize := SizeOf(SEI); SEI.Wnd := aClientHandle; SEI.fMask := SEE_MASK_NOCLOSEPROCESS; SEI.lpVerb := 'open'; SEI.lpFile := PChar('explorer.exe'); SEI.lpParameters := PChar(aParameters); SEI.lpDirectory := nil; SEI.nShow := SW_SHOWNORMAL; Result := ShellExecuteEx(@SEI); if Result then begin if SEI.hProcess > 32 then begin Sleep(1000); // WaitForInputIdle(SEI.hProcess, 2000{ INFINITE}); end; end; CloseHandle(SEI.hProcess); end; function EnumWindowsProc(aHandle: HWND; aLST: TStrings): Bool; stdcall; export; var Caption, ClassName: array[0..MAX_PATH] of Char; begin Result := True; if IsWindowVisible(aHandle) then begin GetClassName(aHandle, ClassName, MAX_PATH); if SameText(string(ClassName),'CabinetWClass') then begin GetWindowText(aHandle, Caption, MAX_PATH); aLST.Add(IntToStr(aHandle)+TC+UpperCase(string(Caption))); end; end; end; function JustDirectory(aDirectory: string): string; var p: integer; begin if (Pos(':',aDirectory) = 0) AND (Pos('\',aDirectory) = 0) AND (Pos('.',aDirectory) = 0) then Exit(aDirectory); Result := ExtractFileDir(aDirectory); p := Pos(':',Result); if p = 0 then exit; if Length(Result) <= 3 then SetLength(Result,1) else begin Delete(Result,1,3); p := Pos('\',Result); while p > 0 do begin Delete(Result,1,p); p := Pos('\',Result); end; end; end; function GetExplorerHandle(aCaption: string): THandle; var i, p: integer; LST: TStrings; begin Result := 0; LST := TStringList.Create; try EnumWindows(@EnumWindowsProc, Integer(LST)); aCaption := UpperCase(JustDirectory(aCaption)); for i := 0 to Pred(LST.Count) do begin if Pos(aCaption, LST[i]) > 0 then begin p := Pos(TC,LST[i]) - 1; Result := StrToIntDef(Copy(LST[i],1,p),0); Break; end; end; finally LST.Free; end; end; procedure WinExplorerStart(aClientHandle: THandle; aLeftFileNameOrDirectory, aRightFileNameOrDirectory : string); var ExplorerHandle: THandle; procedure ShowExplorer(aHandle: THandle); var ForegroundWindowThreadID : Dword; WindowThreadID : DWord; begin if aHandle = GetForegroundWindow then exit; ForegroundWindowThreadID := GetWindowThreadProcessId(GetForegroundWindow, nil); WindowThreadID := GetWindowThreadProcessId(aHandle, nil); if (ForegroundWindowThreadID <> WindowThreadID) then begin AttachThreadInput(ForegroundWindowThreadID, WindowThreadID, true); SetForegroundWindow(aHandle); AttachThreadInput(ForegroundWindowThreadID, WindowThreadID, false); end else SetForegroundWindow(aHandle); ShowWindow(aHandle, SW_RESTORE); end; function Start(aCmdLine: string): boolean; begin Result := false; ExplorerHandle := GetExplorerHandle(JustDirectory(aCmdLine)); if ExplorerHandle = 0 then begin if FileExists(aCmdLine) then aCmdLine := '/select,' + aCmdLine else begin aCmdLine := ExcludeTrailingBackslash(aCmdLine); // if not DirectoryExists(aCmdLine) then exit; // => keine gute Idee weil z.B. "Dokumente" oder "Dieser PC" // nicht funktioniert end; ShellExecExplorer(aClientHandle, aCmdLine, ExplorerHandle); ExplorerHandle := GetExplorerHandle(JustDirectory(aCmdLine)); end else ShowExplorer(ExplorerHandle); Result := ExplorerHandle > 0; end; begin if Start(aLeftFileNameOrDirectory) then MoveWindow(ExplorerHandle, 0, 0, (Screen.Width div 2), Screen.WorkAreaHeight, True); if Start(aRightFileNameOrDirectory) then MoveWindow(ExplorerHandle, Screen.Width div 2, 0, Screen.Width div 2, Screen.WorkAreaHeight, True); end; procedure TForm1.Button1Click(Sender: TObject); begin WinExplorerStart(Handle,'C:\Windows', 'Dokumente'); end; |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Nur so ein paar Ideen: wenn Du doch eh schon ShellExecuteEx verwendest, hast Du doch auch das Prozesshandle. Das könntest Du erstens dazu benutzen, um mit WaitForInputIdle darauf zu warten, dass der Prozess "befehlsbereit" ist, zum anderen dazu, mit EnumWindows und GetWindowThreadProcessId (oder ähnlichen Funktionen) das oder die Fenster zu ermitteln, die zum gerade gestarteten Prozess gehören (dürfte ja eigentlich nur ein Top-Level-Window je Explorer-Instanz sein, wenn ich keinen Denkfehler mache). Und das passt Du dann eben entsprechend an.
|
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
"WaitForInputIdle" hab ich ja schon versucht, siehe Kommentar, aber das kommt sofort zurück.
Die grundsätzliche Idee die hinter der Verwendung von ShellExecuteEx steckt ist ja, über das Processhandle auf das WindowHandle zu kommen. Aber wie? Da fehlt mir leider das Basiswissen. Na ja, wenn es nicht geht, auch nicht schlimm. Ist kein Pflichtprojekt :) |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Andere Version - aber die Version in #2 gefällt mir besser...
Delphi-Quellcode:
Function CallFileName( pFileName, pParameter : PChar): THandle;
var SEI: TShellExecuteInfo; begin FillChar(SEI, SizeOf(SEI), 0); SEI.cbSize := SizeOf(SEI); SEI.fMask := SEE_MASK_NOCLOSEPROCESS; SEI.Wnd := GetTopWindow(0); SEI.lpVerb := 'OPEN'; SEI.lpFile := pFileName; SEI.lpParameters := pParameter; SEI.lpDirectory := ''; SEI.nShow := SW_SHOWNORMAL; SEI.hInstApp := 0; SEI.hProcess := 0; ShellExecuteEx( @SEI ); Sleep(500); Result := SEI.hProcess; end; procedure TForm1.Button1Click(Sender: TObject); var tmpHandle : THandle; begin tmpHandle :=CallFileName(PChar('Explorer.exe'), PChar('F:\TOOLS')); MoveWindow(GetForegroundWindow, 0, 0,(Screen.Width div 2), Screen.WorkAreaHeight, True); tmpHandle :=CallFileName(PChar('Explorer.exe'), PChar('C:\')); MoveWindow(GetForegroundWindow, Screen.Width div 2, 0,(Screen.Width div 2), Screen.WorkAreaHeight, True); end; |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Hey, danke für die Antworten und Tipps...
hab' gerade erst wieder etwas Zeit... @Hathor: Ja das mit dem Handle sollte man wahrscheinlich immer sauber machen, auch wenn es in diesem Beispiel scheinbar egal ist. SetWindowPos hab' ich nur benutzt um das Delphi7 Programm daran zu hindern in den Vordergrund zu kommen nach dem Close in OnActivate. Hab's dann drin gelassen... Ich glaub' ShellExecute kontrolliert auch das Verzeichnis, aber ich hab' nie ausprobiert welche Reaktion ich dann bekomme wenn ein Verzeichnis nicht ansprechbar ist. Selbst zu prüfen ist wohl auch sauberer. Muß deine letzte Variante gleich mal testen... Zum Thema Windows: Nach ein wenig herumspielen mit Lazarus geht meine kompilierte D7-EXE nicht mehr... Ich glaub' das jetzt echt nicht... auch nach einem Neustart funktioniert nur noch das Aufrufen, aber nicht mehr das Positionieren. Zumal mir Lazarus 'ne 14.3 MB EXE gebaut hat???? Na ja, ich fang' gerade erst an mit Lazarus, hab' wohl was falsches eingegeben, dachte mir 362 KB ist schon groß genug (D7). Wer es kleiner mag muß wohl KOL oder ASM nehmen. Aber die Grösse auf der Platte ist nicht so wichtig, die Grösse im RAM ist wichtig... @mm1256: Danke, einiges aus deinem QuellCode kann ich sicherlich in anderen Projekten verwenden... zumindest wenn ich das mal alles kapiert hab'... Ich wollte jetzt eigentlich mal CreateProcess + WaitForInputIdle testen, da ich das noch nie benutzt habe, aber nachdem das bei dir nichts gebracht hat, kann ich mir das wohl sparen. Mann ich hab' meine D7-EXE auf meinem mobilen CORE i7 mit ca. 13GB freiem RAM schon 'ne Weile benutzt und gerade ohne Sleep ging das echt geschmeidig und sehr praktisch... Jetzt nach dem Lazarus Test geht es überhaupt nicht mehr. Windows 7 ist da wohl sehr eigen.. sehr viel mehr als ich vermutet hatte.... Ich war gerade angefangen zu lernen wie ich eine eigene Komponente baue.. TPngForm. Zwecks alphablended translucency... Mann damit kann man ja Sachen bauen... der Hammer (SetWindowLong, UpdateLayeredWindow)... Das haut einem ja den Hintern weg... DAS ROCKT !!! Damit kann ich statt TLabel-Text jetzt jeden HighEnd Text benutzen... Bin gespannt wie lange die CPU braucht von String nach Png... Jetzt muß ich erstmal den doppelten Explorer wieder zurückbekommen, ich hatte mich schon so daran gewöhnt... Und dabei ist seit Windows 3.1 diese W7_64bit_SP1-Version das allerbeste was ich bis jetzt von MS unterm Hintern hatte... und wohl auch die letzte Version von MS, die ich benutzen werde... Aber man soll ja nie NIE sagen... BESTEN DANK NOCHMAL... ich werd' jetzt testen... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Hi,
hier noch eine ganz einfache Möglichkeit ohne Sleep. Diese hat bis jetzt unter Windows 7 immer funktioniert. Zwei einfache Schritte: (1) Man schreibt den Pfad zu der aus diesem Quellcode compilierten EXE ins Feld "Ziel" eines QuickLaunch Icons.
Delphi-Quellcode:
(2)
Unit ShowTwoWindowsExplorer;
Interface Uses Windows, Messages, SysUtils, Classes, Controls, Forms, ShellApi; Type TForm1 = Class(TForm) Procedure FormCreate(Sender: TObject); Procedure FormActivate(Sender: TObject); Procedure FormShow(Sender: TObject); Private End; Var Form1: TForm1; Implementation {$R *.dfm} Procedure TForm1.FormCreate(Sender: TObject); Begin Try Form1.Height := 1; Form1.Width := 1; Form1.Top := 0; Form1.Left := 0; Form1.AlphaBlend := True; Form1.AlphaBlendValue := 0; If DirectoryExists('I:\') Then Begin ShellExecute(Form1.Handle, Nil, PChar('I:\MARTIN'), Nil, Nil, SW_SHOW); ShellExecute(Form1.Handle, Nil, PChar('I:\MARTIN\(DOWNLOADS)'), Nil, Nil, SW_SHOW); End Else Begin ShellExecute(Form1.Handle, Nil, PChar('C:\'), Nil, Nil, SW_SHOW); ShellExecute(Form1.Handle, Nil, PChar('D:\'), Nil, Nil, SW_SHOW); End; Except Exit; End; End; Procedure TForm1.FormShow(Sender: TObject); Var Owner: HWND; Begin Try Owner := GetWindow(Form1.Handle, GW_OWNER); ShowWindow(Owner, SW_HIDE); Except Exit; End; End; Procedure TForm1.FormActivate(Sender: TObject); Begin Try Close; Except FreeAndNil(Form1); Exit; End; End; End. Man klickt auf das Explorer Icon und startet damit die EXE. Von den beiden sich öffnenden Explorer-Fenstern schiebt man eins nach ganz rechts und eins nach ganz links, so dass diese sich automatisch bilschirmfüllend positionieren. Jetzt verkleinert man beide Fenster gleichweit per Maus am oberen Rand um 1 oder 2 Pixel. Der untere Rand wird dabei von Windows 7 automatisch verkleinert. Sollten beide nicht exakt nebeneinander erscheinen, dann einfach das tiefere Fenster an der Titelleiste nach oben verschieben. Jetzt schließt man beide Fenster. Das war's auch schon... Für alle, die - Windows 7 verwenden - einen 21 oder 24 Zoll oder noch größeren Bildschirm benutzen - per einfachem Klick zwei unterschiedliche Ordner angezeigt haben wollen mit Dateiansicht Detail und Bildvorschau - die Position der Explorer-Fenster nur selten verändern - sich nicht an den unteren fehlenden 4 Pixeln stören Der Windows Explorer versucht ja mit aller Kraft seine letzte Position immer wieder einzunehmen und ob man das in der Registry deaktivieren kann oder auf Default Werte setzen kann, kann ich im Moment noch nicht sagen... Da ich den Explorer ohne Verzeichnisbaum benutze und die Position eigentlich niemals verändere ist das die für mich schnellste und beste Möglichkeit bis jetzt... Alle anderen wie QDir, SpeedCommander, DoubleCommander, TotalCommander, FreeCommander und Co. starten zu langsam um mal eben schnell was auch immer zu tun... Zudem zeigt von denen keiner eine DETAILS-Ansicht und eine Bildvorschau. Außerdem kann man sich natürlich auch zwei QuickLaunch Icons erstellen. Einmal ein Fenster und einmal zwei nebeneinander. Mit 4 Fenstern hab' ich das noch nicht probiert... grins Gruß Martin |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:55 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