![]() |
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 |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Hallo,
also wenn ihr schon den Overhead mit einem eigenen Formular bzw. einer VCL-Anwendung gehen wollt, dann nimmt man einfach zwei (oder mehrere) Panels und klatscht da jeweils eine Explorer-Instanz hinein. Das ist nicht mehr als ein 2-Minuten-Programm. 8-) In Beispiel ist Panel1.Align = alLeft und Panel2.Align = alClient.
Delphi-Quellcode:
unit uWinExplorer2;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls; type TFrmExplorer2 = class(TForm) Panel1: TPanel; Panel2: TPanel; procedure FormShow(Sender: TObject); procedure FormResize(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } procedure ExplorerStart(aPanel: TPanel; aDirectory: string); end; var FrmExplorer2: TFrmExplorer2; implementation {$R *.dfm} uses ShellApi; procedure TFrmExplorer2.ExplorerStart(aPanel: TPanel; aDirectory: string); var SEI: TShellExecuteInfo; Style: Integer; begin aPanel.Caption := aDirectory; FillChar(SEI, SizeOf(SEI), #0); SEI.cbSize := SizeOf(SEI); SEI.Wnd := Handle; SEI.fMask := SEE_MASK_NOCLOSEPROCESS; SEI.lpVerb := 'open'; SEI.lpFile := PChar('explorer.exe'); SEI.lpParameters := PChar(aDirectory); SEI.lpDirectory := nil; SEI.nShow := SW_SHOWMAXIMIZED; if ShellExecuteEx(@SEI) then begin if SEI.hProcess > 32 then begin Sleep(500); aPanel.Tag := FindWindow('CabinetWClass',nil); if aPanel.Tag > 0 then begin Winapi.Windows.SetParent(aPanel.Tag, aPanel.Handle); Style := GetWindowLong(aPanel.Tag, GWL_STYLE); SetWindowLong(aPanel.Tag, GWL_STYLE, Style and NOT WS_BORDER ); end; end; end; CloseHandle(SEI.hProcess); end; procedure TFrmExplorer2.FormResize(Sender: TObject); begin Panel1.Width := ClientWidth div 2; if Panel1.Tag > 0 then MoveWindow(Panel1.Tag, 0, 0, Panel1.Width, Panel1.Height, True); if Panel2.Tag > 0 then MoveWindow(Panel2.Tag, 0, 0, Panel2.Width, Panel2.Height, True); end; procedure TFrmExplorer2.FormShow(Sender: TObject); begin Caption := 'Windows-Explorer mit zwei Fenstern'; ExplorerStart(Panel1,'C:\Windows'); ExplorerStart(Panel2,'C:\Users'); end; end. |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Vorschlag:
Delphi-Quellcode:
macht den Bildaufbau ruhiger.
SEI.nShow := SW_MINIMIZE;
|
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
Ein Problem gibt es noch: Die Explorerfenster haben beim Panel oben einen Rand etwa so hoch wie normalerweise die Titelleiste. Damit wollte ich den Rand eigentlich verhindern, aber irgendwas scheint noch zu fehlen. Hab schon rumprobiert, finde aber keine Lösung.
Delphi-Quellcode:
Oder weigert sich der Explorer das anzunehmen?
Style := GetWindowLong(aPanel.Tag, GWL_STYLE);
SetWindowLong(aPanel.Tag, GWL_STYLE, Style and NOT WS_BORDER ); |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Hat keiner eine Idee? Wäre schön, wenn man diesen blöden Rand weg bekommen würde.
|
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Das ist nicht der einzige Schönheitsfehler:
Die beiden Explorer-Instanzen bleiben im RAM als Leichen zurück und können nur im Task-Manager beendet werden. Ich suche eine Lösung, evtl. mit CreateProcess/TerminateProcess. |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Richtig, da fehlt noch was. Aus dem Grund hab ich mir ja auch die Handles im TPanel.Tag gemerkt.
Delphi-Quellcode:
Mir unverständlich ist, dass die Explorer-Instanzen erst nach etwa 20 Sekunden aus dem Taskmanager verschwinden
procedure TFrmExplorer2.FormClose(Sender: TObject; var Action: TCloseAction);
begin if Panel1.Tag > 0 then SendMessage(Panel1.Tag, WM_CLOSE, 0, 0); if Panel2.Tag > 0 then SendMessage(Panel2.Tag, WM_CLOSE, 0, 0); end; |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Liste der Anhänge anzeigen (Anzahl: 3)
Zitat:
- > Disable Explorer Ribbon |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Moin aus Hamburg.
Code:
... PostMessage scheint hier zuverlässiger zu sein.
procedure TFrmExplorer2.FormClose(Sender: TObject; var Action: TCloseAction);
begin if Panel1.Tag > 0 then SendMessage(Panel1.Tag, WM_CLOSE, 0, 0); if Panel2.Tag > 0 then SendMessage(Panel2.Tag, WM_CLOSE, 0, 0); end; Selbst nach mehrmaligen Starten werden alle Instanzen gelöscht, bei SendMessage habe ich immer Leichen mit ca. 8Mb und 6 Threads im Taskmanager |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Am Ende eines Programms sollte man immer PostMessage bevorzugen.
Ich habe es ausserdem in die Destroy-Procedure geschrieben. Aber es dauert trotzdem lange, bis sie aus dem Task-Manager verschwinden.
Delphi-Quellcode:
procedure TForm1.FormDestroy(Sender: TObject);
begin if Panel1.Tag > 0 then PostMessage(Panel1.Tag, WM_CLOSE, 0, 0); if Panel2.Tag > 0 then PostMessage(Panel2.Tag, WM_CLOSE, 0, 0); end; |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
|
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Liste der Anhänge anzeigen (Anzahl: 2)
Nach dem gleichen Verfahren lassen sich auch 2 IEXPLORE.exe anzeigen.
Es sind nur geringe Änderungen erforderlich.
Delphi-Quellcode:
unit Unit1; //20150630 20150715
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Winapi.ShellApi, Vcl.StdCtrls, Winapi.ShlObj, Winapi.ActiveX, System.Win.ComObj; type TForm1 = class(TForm) Panel1: TPanel; Panel2: TPanel; Panel3: TPanel; bnClose: TButton; bnMax: TButton; bnMin: TButton; Button1: TButton; Button2: TButton; procedure FormShow(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure bnCloseClick(Sender: TObject); procedure bnMaxClick(Sender: TObject); procedure bnMinClick(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } procedure ExplorerStart(aPanel: TPanel; aDirectory: string); protected end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin SetWindowLong(Handle, GWL_STYLE, (GetWindowLong(Handle, GWL_STYLE) and not WS_Caption)); end; procedure TForm1.bnMaxClick(Sender: TObject); begin Perform(WM_SYSCOMMAND,SC_MAXIMIZE,0); end; procedure TForm1.bnMinClick(Sender: TObject); begin Perform(WM_SYSCOMMAND,SC_MINIMIZE,0); end; procedure TForm1.Button2Click(Sender: TObject); begin // end; procedure TForm1.ExplorerStart(aPanel: TPanel; aDirectory: string); var SEI: TShellExecuteInfo; begin aPanel.Caption := aDirectory; FillChar(SEI, SizeOf(SEI), #0); SEI.cbSize := SizeOf(SEI); SEI.Wnd := Handle; SEI.fMask := SEE_MASK_NOCLOSEPROCESS; SEI.lpVerb := 'open'; SEI.lpFile := PChar('iexplore.exe'); // <-------------------- SEI.lpParameters := PChar(aDirectory); SEI.lpDirectory := nil; SEI.nShow := SW_MINIMIZE; if ShellExecuteEx(@SEI) then begin if SEI.hProcess > 32 then begin Sleep(500); aPanel.Tag := FindWindow('IEFrame',nil); // <-------------------- if aPanel.Tag > 0 then begin Winapi.Windows.SetParent(aPanel.Tag, aPanel.Handle); SetWindowLongPtr(aPanel.Tag, GWL_STYLE, GetWindowLongPtr(aPanel.Tag, GWL_STYLE) and not WS_BORDER); SetWindowPos(aPanel.Tag, HWND_TOP, Left, Top, Width, Height, SWP_FRAMECHANGED); end; end; end; CloseHandle(SEI.hProcess); end; //------------------------------------------------------------------------------ procedure TForm1.FormDestroy(Sender: TObject); begin if Panel1.Tag > 0 then PostMessage(Panel1.Tag, WM_CLOSE, 0, 0); if Panel2.Tag > 0 then PostMessage(Panel2.Tag, WM_CLOSE, 0, 0); end; procedure TForm1.bnCloseClick(Sender: TObject); begin Application.Terminate; end; procedure TForm1.FormResize(Sender: TObject); begin Panel1.Width := ClientWidth div 2; if Panel1.Tag > 0 then MoveWindow(Panel1.Tag, 0, 0, Panel1.Width, Panel1.Height, True); if Panel2.Tag > 0 then MoveWindow(Panel2.Tag, 0, 0, Panel2.Width, Panel2.Height, True); end; procedure TForm1.FormShow(Sender: TObject); begin ExplorerStart(Panel1,'-new www.web.de'); // <------------ // Sample ExplorerStart(Panel2,'-new www.google.de'); // <------------// Sample end; end. |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Hab' das Ding etwas frisiert... Jetzt läuft das viel besser und stabiler bei mir...ist auch viel praktischer so: nur ein Klick und man hat beide vorne falls schon zwei geöffnet waren.
Ohne Delay oder Sleep.. Blitzschnell... Nur einmal zwei Fenster positionieren und das war's dann... Leider hab' ich noch immer keine Möglichkeit gefunden das Verhalten des WindowsExplorers abzuschalten.
Delphi-Quellcode:
WindowsTaste + E kann man problemlos nutzen und das neue Fenster kann man auch problemlos verschieben...
Unit u2WindowsExplorer;
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); End; Type PFindWindowStruct = ^TFindWindowStruct; TFindWindowStruct = Record Caption : String; ClassName: String; WindowHandle: THandle; End; Var Form1 : TForm1; stringlist_FindWindow : TStringlist; WindowHandle : THandle; Implementation {$R *.dfm} Procedure ErrorLog(ErrorInfo: String); Var LogFile : TStringlist; LoadedFile : TStringlist; boolean_Loaded : Boolean; Procedure LoadErrorLog; Begin Try boolean_Loaded := False; If FileExists('ErrorLog.txt') Then Begin LoadedFile := TStringlist.Create; LoadedFile.LoadFromFile('ErrorLog.txt'); boolean_Loaded := True; End; Except Exit; End; End; Procedure Free_LogFile; Begin Try FreeAndNil(LogFile); Except Exit; End; End; Procedure Free_LoadedFile; Begin Try FreeAndNil(LoadedFile); Except Exit; End; End; Begin LoadErrorLog; Try LogFile:= TStringlist.Create; Try If boolean_Loaded = True Then Begin LogFile.Add(ErrorInfo); LogFile.Text := LogFile.Text + LoadedFile.Text; Free_LoadedFile; End Else Begin LogFile.Add(ErrorInfo); End; LogFile.SaveToFile('ErrorLog.txt'); Finally Free_LogFile; End; Except Free_LoadedFile; Exit; End; End; Function EnumWindowsProc(hWindow: HWND; lParam: LongInt): Boolean; StdCall; Var lpBuffer: PChar; WindowCaptionFound : Boolean; ClassNameFound : Boolean; Procedure Free_Memory; Begin Try FreeMem(lpBuffer, SizeOf(lpBuffer^)); Except ErrorLog('EnumWindowsProc (Free_Memory) Failed'); Exit; End; End; Begin Try GetMem(lpBuffer, 255); Result := True; WindowCaptionFound := False; ClassNameFound := False; Try If GetWindowText(hWindow, lpBuffer, 255) > 0 Then Begin If PFindWindowStruct(lParam).Caption = '' Then WindowCaptionFound := True Else Begin If Pos(PFindWindowStruct(lParam).Caption, StrPas(lpBuffer)) > 0 Then WindowCaptionFound := True; End; If PFindWindowStruct(lParam).ClassName = '' Then ClassNameFound := True Else Begin If GetClassName(hWindow, lpBuffer, 255) > 0 Then Begin If Pos(PFindWindowStruct(lParam).ClassName, StrPas(lpBuffer)) > 0 Then ClassNameFound := True; If (WindowCaptionFound And ClassNameFound) Then Begin PFindWindowStruct(lParam).WindowHandle := hWindow; stringlist_FindWindow.Add(IntToStr(hWindow)); End; End; End; End; Finally Free_Memory; End; Except ErrorLog('EnumWindowsProc Failed'); Exit; End; End; Function FindAWindow(WinCaption: String; WinClassName: String): THandle; Var WindowInfo: TFindWindowStruct; Begin Try WindowInfo.Caption := WinCaption; WindowInfo.ClassName := WinClassName; WindowInfo.WindowHandle := 0; EnumWindows(@EnumWindowsProc, LongInt(@WindowInfo)); Result := WindowInfo.WindowHandle; Except ErrorLog('FindAWindow Failed'); Exit; End; End; Procedure Start2WindowsExplorer; Begin Try 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 ErrorLog('Start2WindowsExplorer Failed'); Exit; End; End; Procedure Close1WindowsExplorer; Procedure Terminate; Begin Try WindowHandle := StrToInt(stringlist_FindWindow[0]); PostMessage(WindowHandle, WM_QUIT, 0, 0); Except ErrorLog('Close1WindowsExplorer (Terminate) Failed'); Exit; End; End; Begin Try PostMessage(WindowHandle, WM_CLOSE, 0, 0); Start2WindowsExplorer; Except ErrorLog('Close1WindowsExplorer Failed'); Terminate; Exit; End; End; Procedure Bring2WindowsExplorerToFront; Var i : Integer; Begin Try For i:= 0 To stringlist_FindWindow.Count-1 Do Begin WindowHandle := StrToInt(stringlist_FindWindow[i]); If IsIconic(WindowHandle) Then ShowWindow(WindowHandle, SW_RESTORE) Else Begin ShowWindow(WindowHandle, SW_MINIMIZE); ShowWindow(WindowHandle, SW_RESTORE); End; End; Except ErrorLog('Bring2WindowsExplorerToFront Failed'); Exit; End; End; Procedure DeleteAllAndStart2WindowsExplorer; Var i: Integer; Begin Try For i:= 0 To stringlist_FindWindow.Count-1 Do Begin WindowHandle := StrToInt(stringlist_FindWindow[i]); PostMessage(WindowHandle, WM_CLOSE, 0, 0); End; Start2WindowsExplorer; Except ErrorLog('DeleteAllAndStart2WindowsExplorer Failed'); Exit; End; End; Procedure TForm1.FormCreate(Sender: TObject); Procedure Free_Stringlist; Begin Try FreeAndNil(stringlist_FindWindow); Except ErrorLog('FormCreate (Free_Stringlist) Failed'); Exit; End; End; Begin Try Form1.Height := 1; Form1.Width := 1; Form1.Top := 0; Form1.Left := 0; Form1.AlphaBlend := True; Form1.AlphaBlendValue := 0; stringlist_FindWindow := TStringlist.Create; Try FindAWindow(':\', 'CabinetWClass'); Case stringlist_FindWindow.Count Of 0 : Start2WindowsExplorer; 1 : Close1WindowsExplorer; 2 : Bring2WindowsExplorerToFront; Else Begin DeleteAllAndStart2WindowsExplorer; End; End; Finally Free_Stringlist; End; Except ErrorLog('FormCreate Failed'); 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); Procedure Terminate; Begin Try Application.Terminate; Except Exit; End; End; Begin Try Close; Except Terminate; End; End; End. Darin zu suchen ist wahrscheinlich keine so gute Idee, hab' ich noch nicht getestet. Auf STRG+N sollte man aber verzichten... Ich hätte niemals gedacht, dass es so nervig sein kann ein Fenster das "wsNormal" ist nach vorne zu holen.
Delphi-Quellcode:
Zwei einfache wsNormal-Fenster wirklich immer nach vorne zu kriegen ohne "Topmost" ist tatsächlich ein kleines Wunder!
ShowWindow(WindowHandle, SW_Show); // Funktioniert nicht!
ShowWindow(WindowHandle, SW_ShowNormal); // Funktioniert nicht! SetWindowPos(WindowHandle, HWND_TOP, .... // Funktioniert nicht! SetWindowPos(WindowHandle, HWND_NoTOPMOST, // Funktioniert nicht! SetWindowPos(WindowHandle, HWND_TOPMOST, // Das funzt, ist aber bei normaler Shell nicht zu empfehlen, bei eigener Shell vielleicht 'ne Lösung. ShowWindow(WindowHandle, SW_MINIMIZE); //und gleichzeitig dahinter SW_Restore ShowWindow(WindowHandle, SW_RESTORE); // Das hat bis jetzt immer geklappt.. zu 100%, auch bei mehreren Fenstern //Vielleicht sollte ich nochmal WindowState probieren, aber ich meine, ich hätte damit früher schonmal Schwierigkeiten bekommen... //SetForegroundWindow funzt nur für ein Fenster... Alter Schwede ich kotz gleich in die Ecke... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Kann es sein, dass du eine "Exception Paranoia" hast?
|
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
@Sir Rufo:
Nennt man das jetzt so? ... grins... Ja mag sein, dass die Bezeichnung ins Schwarze trifft... Ich hab' jetzt zwar gelernt, wie man es offiziell richtig macht, aber ich kann mich noch nicht so richtig dazu durchringen das umzusetzen. Es gibt da immer noch so eine Stimme die sagt:"Mach das Programm nicht zu geschwätzig, mach 'n ErrorLog für dich und schick' nur die Meldung 'raus, die dem Nutzer auch wirklich weiterhelfen kann. Ich pendel noch zwischen den Polen und werd' meinen Weg wohl noch finden... Kann sich nur noch um 100 Jahre handeln... Ach so, vielleicht hast du auch einfach nur das WM_Quit gesehen... das kann da eigentlich weg... hab' 'n bisschen 'rumgespielt... Hat aber auch 'was praktisches, ich teste meine Programme meistens außerhalb der IDE, dann muß ich bei 'nem falschen Stringlist Index nicht immer per Taskmanager Delphi7 killen und anschließend wieder neu starten... so weiß ich immer wo es kracht und zwar präzise mit meinen eigenen Worten bzw. Prozeduren... Gut Ding will Weile haben oder wie war das... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
|
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
@Aviator:
Ja, das wär' schön... bei kleineren Fehlern, die mal auftreten kann man RESET (STRG+F2) drücken und ist wieder in der IDE. Aber bei sehr vielen StringlistINDEX-Fehlern stoppt Delphi das Programm und zeigt das auch in der Titelleiste an. Dann funktioniert RESET nicht mehr und auch per Taskmanager kann ich das Programm nicht mehr abschießen. Das Einzige was dann noch geht ist Delphi7 komplett per Taskmanager abzuschießen und das ist nervig, da ich dann alle Units neuladen muss und wieder an die Position wo ich war gehen muss... Man kann den Ladevorgang zwar automatisieren, aber damit hatte ich schonmal 'ne Menge "Spass" und hab' das dann wieder abgeschaltet. Ja ich hab' gehört, dass es einen Debugger gibt, hab' ihn noch nie benutzt... vielleicht wird das irgendwann mal interessant, wenn ich genau herausfinden muss was der Prozess genau macht. Normalerweise programmiere ich einfach alles um, schließlich kann man ja eine Sache auf 1000 verschiedene Arten machen und die verschiedensten Befehle dazu nutzen. Also wenn etwas auf eine Art nicht klappt, egal ob es an mir liegt oder daran, dass es einfach so nicht geht, dann mache ich es eben auf eine andere Art... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Liste der Anhänge anzeigen (Anzahl: 1)
Final Version... :-)
- fehlendes FensterHandle hinzugefügt - Overkill entfernt - Exception-Handling minimal informativer gemacht ;-) - kein Sleep erforderlich Ergebnis: läuft super schnell und stabil bei mir... Sollte ich alle paar Monate die Fenster mal wieder neu positionieren müssen wäre mir das auch egal, aber bis jetzt läuft alles sauber... Läuft auch unter Lazarus // {$Mode Delphi} // oder selber Handanlegen und anpassen
Delphi-Quellcode:
Fur alle die Windows 7 mögen und dazu noch den WindowsExplorer hier eine einfache Anleitung:
Program TwoWindowsExplorer;
Uses Windows, Messages, Classes, SysUtils, ShellApi; Type PFindWindowStruct = ^TFindWindowStruct; TFindWindowStruct = Record Caption : String; ClassName : String; WindowHandle: THandle; End; Var FoundWindows: TStringlist; WndHandle : THandle; Procedure ErrorLog(ErrorInfo: String); Var LoadErrorLog : TStringlist; SaveErrorInfo: TStringlist; ErrorLog : String; Procedure Free_LoadErrorLog; Begin Try FreeAndNil(LoadErrorLog); Except End; End; Procedure Free_SaveErrorInfo; Begin Try FreeAndNil(SaveErrorInfo); Except End; End; Function ErrorLogExists : Boolean; Begin Try Result:= False; If FileExists('ErrorLog.txt') Then Begin Try LoadErrorLog:= TStringlist.Create; LoadErrorLog.LoadFromFile('ErrorLog.txt'); ErrorLog:= LoadErrorLog.Text; Result:= True; Finally Free_LoadErrorLog; End; End; Except End; End; Begin Try Try SaveErrorInfo:= TStringlist.Create; SaveErrorInfo.Add(DateTimeToStr(Now)); SaveErrorInfo.Add(ErrorInfo); If ErrorLogExists Then Begin SaveErrorInfo.Add(' '); SaveErrorInfo.Add(Trim(ErrorLog)); End; SaveErrorInfo.SaveToFile('ErrorLog.txt'); Finally Free_SaveErrorInfo; End; Except End; End; Function EnumWindowsProc(hWindow: HWND; lParam: LongInt): Boolean; StdCall; Var lpBuffer : PChar; WindowCaptionFound: Boolean; ClassNameFound : Boolean; Procedure Free_Memory; Begin Try FreeMem(lpBuffer, SizeOf(lpBuffer^)); Except On E: Exception Do ErrorLog('EnumWindowsProc: Free_Memory Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Begin Try GetMem(lpBuffer, 255); Result := True; WindowCaptionFound:= False; ClassNameFound := False; Try If GetWindowText(hWindow, lpBuffer, 255) > 0 Then Begin If PFindWindowStruct(lParam).Caption = '' Then WindowCaptionFound:= True Else Begin If Pos(PFindWindowStruct(lParam).Caption, StrPas(lpBuffer)) > 0 Then WindowCaptionFound:= True; End; If PFindWindowStruct(lParam).ClassName = '' Then ClassNameFound:= True Else Begin If GetClassName(hWindow, lpBuffer, 255) > 0 Then Begin If Pos(PFindWindowStruct(lParam).ClassName, StrPas(lpBuffer)) > 0 Then ClassNameFound:= True; If (WindowCaptionFound And ClassNameFound) Then Begin PFindWindowStruct(lParam).WindowHandle:= hWindow; FoundWindows.Add(IntToStr(hWindow)); End; End; End; End; Finally Free_Memory; End; Except On E: Exception Do ErrorLog('EnumWindowsProc Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Function FindAWindow(WinCaption: String; WinClassName: String): THandle; Var WindowInfo: TFindWindowStruct; Begin Try WindowInfo.Caption := WinCaption; WindowInfo.ClassName := WinClassName; WindowInfo.WindowHandle:= 0; EnumWindows(@EnumWindowsProc, LongInt(@WindowInfo)); Result:= WindowInfo.WindowHandle; Except On E: Exception Do ErrorLog('FindAWindow Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure StartTwoExplorer; Begin Try If DirectoryExists('I:\') Then Begin ShellExecute(0, Nil, PChar('I:\MARTIN'), Nil, Nil, SW_SHOW); ShellExecute(0, Nil, PChar('I:\MARTIN\(DOWNLOADS)'), Nil, Nil, SW_SHOW); End Else Begin ShellExecute(0, Nil, PChar('C:\'), Nil, Nil, SW_SHOW); ShellExecute(0, Nil, PChar('D:\'), Nil, Nil, SW_SHOW); End; Except On E: Exception Do ErrorLog('StartTwoExplorer Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure CloseOneExplorer; Begin Try WndHandle:= StrToInt(FoundWindows[0]); PostMessage(WndHandle, WM_CLOSE, 0, 0); StartTwoExplorer; Except On E: Exception Do ErrorLog('CloseOneExplorer Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure TwoExplorerToFront; Var I: Integer; Begin Try For I:= 0 To FoundWindows.Count-1 Do Begin WndHandle:= StrToInt(FoundWindows[I]); If IsIconic(WndHandle) Then ShowWindow(WndHandle, SW_RESTORE) Else Begin ShowWindow(WndHandle, SW_MINIMIZE); ShowWindow(WndHandle, SW_RESTORE); End; End; Except On E: Exception Do ErrorLog('TwoExplorerToFront Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure CloseAllExplorer; Var I: Integer; Begin Try For I:= 0 To FoundWindows.Count-1 Do Begin WndHandle:= StrToInt(FoundWindows[I]); PostMessage(WndHandle, WM_CLOSE, 0, 0); End; StartTwoExplorer; Except On E: Exception Do ErrorLog('CloseAllExplorer Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure Free_Stringlist; Begin Try FreeAndNil(FoundWindows); Except On E: Exception Do ErrorLog('Free_Stringlist Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End; Begin Try FoundWindows:= TStringlist.Create; Try FindAWindow('','CabinetWClass'); Case FoundWindows.Count Of 0 : StartTwoExplorer; 1 : CloseOneExplorer; 2 : TwoExplorerToFront; Else CloseAllExplorer; End; Finally Free_Stringlist; End; Except On E: Exception Do ErrorLog('MainProgram Failed'+#13#10+E.ClassName+#13#10+E.Message); End; End. 1. Quicklaunch einrichten und Icon auswählen, Rechtsklick auf Icon - Eigenschaften: Pfad zur EXE eingeben 2. Icon klicken und damit die EXE zum ersten Mal starten 3. Fenster positionieren (Hinweis: Die Fenster müssen von Hand ausgerichet werden. Man kann aber die automatische Andockmöglichkeit unter Windows7 nutzen damit das schneller geht. Ausschließlich Andocken geht nicht, da sich der Explorer dann die Position nicht merkt! 4. Fenster schließen und erneut auf das eingerichtete Icon klicken: Feintuning vornehmen, so das nur noch 1 Pixel oder wenige Pixel unten unausgefüllt bleiben... Wer Lust hat zu Fummeln bekommt sicher auch den letzten Pixel noch weg... 5. Fertig! Ab jetzt nur noch den neuen Button benutzen, egal ob kein Fenster gestartet ist oder nur ein Fenster sichtbar ist oder ob beide Fenster schon im Hintergrund laufen... Es ist nur noch ein Klick notwendig um die beiden WindowsExplorer-Fenster anzeigen zu lassen. Hinweis: Es kann sein, dass man bis zu 3 bis 4 Versuche benötigt bis sich der WindowsExplorer die Position gemerkt hat. Wenn die Position dann einmal drin ist hat man Ruhe und gleichzeitig läuft das Ganze richtig schnell... Ob das auch unter Windows 8 oder 8.1 läuft kann ich nicht sagen. Ob das auch mit mehreren Monitoren oder größeren Monitoren und mehr Fenstern geht kann ich auch nicht sagen... TryAndError...for yourself... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Finally .... :-) :-) :-)
Ich hab's !!! Man kann den Windows-Explorer doch völlig problemlos positionieren mit "MoveWindow" und das Ganze ohne "Sleep". Zuerst hatte ich an zwei Stellen "Sleep(10)", dachte das wäre notwendig, aber wenn ich das weglasse funzt es genauso. Also weg damit... nicht das 20ms irgend eine Rolle gespielt hätten... Und wo liegt jetzt die Magie??? Here it comes: ...and the winner is: "die Repeat-Schleife" ... gepriesen sei die heilige Repeat-Schleife für ihre Existenz...
Delphi-Quellcode:
Das die Lösung so einfach ist hätte mir ruhig mal einer von euch "stecken" können... ... den Wald vor lauter Bäumen... :P
Repeat
slFoundWnd.Clear; FindAllWindows('','CabinetWClass'); Until slFoundWnd.Count >= 2; Und hier das ganze Ding: Da mir das BringToFront mit "Minimize" und "Restore" zu nervig war hab' ich einfach alles weggelassen und lösche jetzt einfach immer alle Fenster. Somit gibt es nur noch eine Prozedur "StartTwoWinEx"... ist auch gleich viel übersichtlicher... Ich brauche eh nur zwei Fenster... Jetzt kann man die beiden Windows-Explorer-Fenster drehen, biegen, zerknüddeln... ohne das sich irgendwas an der erneuten Darstellung ändert. Schon beim nächsten Klick auf den QuickLaunch-Button sieht alles wieder sauber und gerade aus (bildschirmfüllend) und ich brauche die TaskbarButton überhaupt nicht mehr benutzen... sehr schön ...
Delphi-Quellcode:
Getestet mit D7 und W7x64 Sp1...
PROGRAM TwoWindowsExplorer;
USES Windows, Messages, Classes, Forms, SysUtils, ShellApi; TYPE PFindWindowStruct = ^TFindWindowStruct; TFindWindowStruct = Record Caption : String; ClassName : String; WindowHandle: THandle; End; VAR slFoundWnd: TStringlist; WndHandle : THandle; I : Integer; Procedure ErrorLog(ErrorInfo: String); Var slLoad : TStringlist; slSave : TStringlist; strErrorLog: String; Procedure Free_slLoad; Begin Try FreeAndNil(slLoad); Except End; End; Procedure Free_slSave; Begin Try FreeAndNil(slSave); Except End; End; Function ErrorLogExists: Boolean; Begin Try Result:= False; If FileExists('ErrorLog.txt') Then Begin Try slLoad:= TStringlist.Create; slLoad.LoadFromFile('ErrorLog.txt'); strErrorLog:= slLoad.Text; Result:= True; Finally Free_slLoad; End; End; Except End; End; Begin Try Try slSave:= TStringlist.Create; slSave.Add(DateTimeToStr(Now)); slSave.Add(ErrorInfo); If ErrorLogExists Then Begin slSave.Add(' '); slSave.Add(Trim(strErrorLog)); End; slSave.SaveToFile('ErrorLog.txt'); Finally Free_slSave; End; Except End; End; Function EnumWindowsProc(hWindow: HWND; lParam: LongInt): Boolean; StdCall; Var lpBuffer : PChar; WindowCaptionFound: Boolean; ClassNameFound : Boolean; Procedure Free_Memory; Begin Try FreeMem(lpBuffer, SizeOf(lpBuffer^)); Except On E: Exception Do ErrorLog('EnumWindowsProc: Free_Memory'+#13#10+E.ClassName+#13#10+E.Message); End; End; Begin Try GetMem(lpBuffer, 255); Result := True; WindowCaptionFound:= False; ClassNameFound := False; Try If GetWindowText(hWindow, lpBuffer, 255) > 0 Then Begin If PFindWindowStruct(lParam).Caption = '' Then WindowCaptionFound:= True Else Begin If Pos(PFindWindowStruct(lParam).Caption, StrPas(lpBuffer)) > 0 Then WindowCaptionFound:= True; End; If PFindWindowStruct(lParam).ClassName = '' Then ClassNameFound:= True Else Begin If GetClassName(hWindow, lpBuffer, 255) > 0 Then Begin If Pos(PFindWindowStruct(lParam).ClassName, StrPas(lpBuffer)) > 0 Then ClassNameFound:= True; If (WindowCaptionFound And ClassNameFound) Then Begin PFindWindowStruct(lParam).WindowHandle:= hWindow; slFoundWnd.Add(IntToStr(hWindow)); End; End; End; End; Finally Free_Memory; End; Except On E: Exception Do ErrorLog('EnumWindowsProc'+#13#10+E.ClassName+#13#10+E.Message); End; End; Function FindAllWindows(WinCaption: String; WinClassName: String): THandle; Var WindowInfo: TFindWindowStruct; Begin Try WindowInfo.Caption := WinCaption; WindowInfo.ClassName := WinClassName; WindowInfo.WindowHandle:= 0; EnumWindows(@EnumWindowsProc, LongInt(@WindowInfo)); Result:= WindowInfo.WindowHandle; Except On E: Exception Do ErrorLog('FindAllWindows'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure StartTwoWinEx; Begin Try If DirectoryExists('I:\') And DirectoryExists('I:\(DOWNLOADS)') Then Begin ShellExecute(0, Nil, PChar('I:\'), Nil, Nil, SW_SHOW); ShellExecute(0, Nil, PChar('I:\(DOWNLOADS)'), Nil, Nil, SW_SHOW); Repeat slFoundWnd.Clear; FindAllWindows('','CabinetWClass'); // Sleep(10); Until slFoundWnd.Count >= 2; // Sleep(10); MoveWindow(StrToInt(slFoundWnd[0]), 0, 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); MoveWindow(StrToInt(slFoundWnd[1]), (Screen.WorkAreaWidth Div 2), 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); End Else Begin ShellExecute(0, Nil, PChar('C:\'), Nil, Nil, SW_SHOW); ShellExecute(0, Nil, PChar('D:\'), Nil, Nil, SW_SHOW); Repeat slFoundWnd.Clear; FindAllWindows('','CabinetWClass'); Until slFoundWnd.Count >= 2; MoveWindow(StrToInt(slFoundWnd[0]), 0, 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); MoveWindow(StrToInt(slFoundWnd[1]), (Screen.WorkAreaWidth Div 2), 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); End; Except On E: Exception Do ErrorLog('StartTwoWinEx'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure Free_slFoundWnd; Begin Try FreeAndNil(slFoundWnd); Except On E: Exception Do ErrorLog('Free_slFoundWnd'+#13#10+E.ClassName+#13#10+E.Message); End; End; Begin Try slFoundWnd:= TStringlist.Create; Try FindAllWindows('','CabinetWClass'); If slFoundWnd.Count >= 1 Then Begin For I:= 0 To slFoundWnd.Count-1 Do Begin WndHandle:= StrToInt(slFoundWnd[I]); SendMessage(WndHandle, WM_CLOSE, 0, 0); End; End; StartTwoWinEx; Finally Free_slFoundWnd; End; Except On E: Exception Do ErrorLog('MAIN PRG'+#13#10+E.ClassName+#13#10+E.Message); End; End. Auf älteren Lazarus-Versionen lieft das im Delphi-Mode sehr gut, aber Version 1.6 mag den PFindWindowStruct TypeCast 4->8 wohl nicht... Wenn ich auch noch nicht kapiert hab' was der Compiler damit eigentlich meint... egal das finde ich auch noch 'raus... Natürlich kann man das Ganze auch umbauen auf 4 oder 8 oder 150 Mio Fenster.... :-) (Wer hätte das gedacht...) Ach ja, ich hatte keine Lust das übertriebene Exception-Handling zu löschen... Nein.. niemand muß das so nachmachen... Ich wußte das geht irgendwie und ich wußte ich krieg' das hin... hahaha.... Hat jemand von euch Lust das mal unter W8 oder W10 zu testen... Verhält sich der Explorer dort genauso ??? Muß auch nicht unbedingt, ich bin nur neugierig... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Durch die vollkommen transparenten Fensterränder sieht es unter Windows 10 so aus als sei zwischen den Fenstern Platz. In Wirklichkeit sind das nur die Rahmen aber die sieht man ja nicht.
Leider lässt sich das programmtechnisch auch kaum lösen. Aero Snap ist ja leider per API nicht erreichbar und wenn man die Fenster so platziert, dass kein Abstand dazwischen sichtbar ist, überlappen sie in Wirklichkeit. Da andere Fenstermanager mittlerweile aber auch Aero Snap Features haben, scheint es auf undokumentiertem Weg evtl. doch zu gehen. Das hätte den Vorteil, dass die Fenster auch wieder ihre normale Größe einnehmen, wenn man sie aus dem doppelt maximierten Zustand herauszieht. |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Finde ich ganz praktisch:
Delphi-Quellcode:
Kompiliert mit Delph7 unter Win10, getestet unter XP/8.1/10. Klappt :thumb:
...
... ... // Sorgt für mehr Übersicht auf dem Desktop: procedure MinAllWindows; begin KeyBd_Event(VK_LWIN, MapvirtualKey(VK_LWIN, 0), 0, 0); KeyBd_Event(Ord('M'), MapvirtualKey(Ord('M'), 0), 0, 0); KeyBd_Event(Ord('M'), MapvirtualKey(Ord('M'), 0), KEYEVENTF_KEYUP, 0); KeyBd_Event(VK_LWIN, MapvirtualKey(VK_LWIN, 0), KEYEVENTF_KEYUP, 0); end; // ^ Minimiert alle Fenster Procedure StartTwoWinEx; Begin MinAllWindows; // Eingefügt Try If DirectoryExists('I:\') And DirectoryExists('I:\(DOWNLOADS)') Then ... ... ... Danke! |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Funktioniert KeyBd_Event vielleicht auch mit Win + Left und Win + Right?
Dann müsste man nur statt MoveWindow erst das eine Fenster fokussieren, Win + Left schicken, dann das zweite Fokussieren und Win + Right schicken. |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
Na wenigstens funktioniert das in W10 noch. Wenn der Spalt nicht zu groß ist stört das ja vielleicht nicht so sehr. Zitat:
Also muß ich doch wieder zurück zu "MoveTwoWinExToFront" mit Hilfe von Minimize und Restore.... Eigenartigerweise ist das aber nicht immer der Fall, manchmal funzt es und beide Fenster kommen nach vorne. Oder ich probier mal deine Prozedur... wenn alle Fenster vorher minimiert werden, dann würde man in dem Fall auch das zweite Fenster sehen. Windows ist da offenbar etwas eigensinnig ... Interessant unter XP und 8.1 geht das also auch... gut zu wissen... Zitat:
Ist wahrscheinlich gehopst wie gesprungen... wenn schon zwei geöffnet sind müssen die erstmal wieder nach vorne... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Wozu die ganzen Try-Except-Blöcke, wenn sie doch leer sind?
Insbesondere hier:
Delphi-Quellcode:
Und warum das Auslagern in eine eigene Prozedur? Das suggeriert, dass hier noch mehr passiert, tut es aber nicht. Davon abgesehen bitte mal dies zu FreeAndNil lesen:
Procedure Free_slLoad;
Begin Try FreeAndNil(slLoad); Except End; End; ![]() |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
Es funktioniert tatsächlich problemlos. Mit SetForegroundWindow lässt sich der Windows Explorer nach vorne holen und dann mit folgendem Code links snappen (und rechts dann analog):
Delphi-Quellcode:
keybd_event(VK_LWIN, MapVirtualKey(VK_LWIN, 0), 0, 0);
keybd_event(VK_LEFT, MapVirtualKey(VK_LEFT, 0), 0, 0); keybd_event(VK_LEFT, MapVirtualKey(VK_LEFT, 0), KEYEVENTF_KEYUP, 0); keybd_event(VK_LWIN, MapVirtualKey(VK_LWIN, 0), KEYEVENTF_KEYUP, 0); |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
Wenn etwas nicht so läuft wie ich es erwarte, dann habe ich alles an einer Stelle im ErrorLog, sehe ich keinen, dann konnte er wohl nicht erstellt werden. Jetzt noch 'ne Exception, die mir sagt, dass der Log nicht erstellt werden konnte ist mir zuviel... schließlich hab' ich's ja versucht... das reicht mir dann... Ja.. ja, das ist das was ich im Moment mache... morgen oder übermorgen mache ich es vielleicht schon ganz anders... Danke für den Blog-Link... kannte ich aber schon und benutze immer noch FreeAndNil... ist wohl die Gewohnheit... :-) Zitat:
@Erdbär Man kann deine Procedure noch etwas verkleinern: :P
Delphi-Quellcode:
Danke nochmal für den Tipp... ich hab's mal mit eingebaut... Außerdem war die FensterSuche wohl für diesen Zweck etwas überdimensioniert... hab' sie deutlich kleiner gemacht:
Procedure TForm1.Button3Click(Sender: TObject);
Begin Keybd_event(VK_LWIN, 0, 0, 0); Keybd_event(Byte('M'), 0, 0, 0); Keybd_event(Byte('M'), 0, KEYEVENTF_KEYUP, 0); Keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0); End;
Delphi-Quellcode:
Noch'n bisschen mehr und das Ding wird richtig sexy.... (OK, nur wenn man sich das irre Exception-Handling wegdenkt... :-)).
PROGRAM TwoWinEx;
USES Windows, Messages, Classes, Forms, SysUtils, ShellApi; VAR slFoundWnd: TStringlist; WndHandle : THandle; I : Integer; Procedure ErrorLog(ErrorInfo: String); Var slLoad : TStringlist; slSave : TStringlist; strErrorLog: String; Procedure Free_slLoad; Begin Try FreeAndNil(slLoad); Except End; End; Procedure Free_slSave; Begin Try FreeAndNil(slSave); Except End; End; Function ErrorLogExists: Boolean; Begin Try Result:= False; If FileExists('ErrorLog.txt') Then Begin Try slLoad:= TStringlist.Create; slLoad.LoadFromFile('ErrorLog.txt'); strErrorLog:= slLoad.Text; Result:= True; Finally Free_slLoad; End; End; Except End; End; Begin Try Try slSave:= TStringlist.Create; slSave.Add(DateTimeToStr(Now)); slSave.Add(ErrorInfo); If ErrorLogExists Then Begin slSave.Add(' '); slSave.Add(Trim(strErrorLog)); End; slSave.SaveToFile('ErrorLog.txt'); Finally Free_slSave; End; Except End; End; Function SearchCallback(Wnd: HWND; sl:TStringlist): BOOL; StdCall; Var ClassName: Array[0..255] Of Char; Begin Try If GetClassName(Wnd, ClassName, 255) > 0 Then Begin If Pos('CabinetWClass', String(ClassName)) <> 0 Then sl.Add(IntToStr(Wnd)); End; Result:= True; Except On E: Exception Do ErrorLog('SearchCallback'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure SearchWnd; Begin Try EnumWindows(@SearchCallback, lParam(slFoundWnd)); Except On E: Exception Do ErrorLog('SearchWnd'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure MinAllWnds; Begin Try Keybd_event(VK_LWIN, 0, 0, 0); Keybd_event(Byte('M'), 0, 0, 0); Keybd_event(Byte('M'), 0, KEYEVENTF_KEYUP, 0); Keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0); Except On E: Exception Do ErrorLog('MinAllWnds'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure StartTwoWinEx; Begin Try If DirectoryExists('I:\') And DirectoryExists('I:\(DOWNLOADS)') Then Begin ShellExecute(0, Nil, PChar('I:\'), Nil, Nil, SW_SHOW); ShellExecute(0, Nil, PChar('I:\(DOWNLOADS)'), Nil, Nil, SW_SHOW); Repeat slFoundWnd.Clear; SearchWnd; Until slFoundWnd.Count >= 2; MoveWindow(StrToInt(slFoundWnd[0]), 0, 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); MoveWindow(StrToInt(slFoundWnd[1]), (Screen.WorkAreaWidth Div 2), 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); End Else Begin ShellExecute(0, Nil, PChar('C:\'), Nil, Nil, SW_SHOW); ShellExecute(0, Nil, PChar('D:\'), Nil, Nil, SW_SHOW); Repeat slFoundWnd.Clear; SearchWnd; Until slFoundWnd.Count >= 2; MoveWindow(StrToInt(slFoundWnd[0]), 0, 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); MoveWindow(StrToInt(slFoundWnd[1]), (Screen.WorkAreaWidth Div 2), 0, (Screen.WorkAreaWidth Div 2), Screen.WorkAreaHeight, True); End; Except On E: Exception Do ErrorLog('StartTwoWinEx'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure Free_slFoundWnd; Begin Try FreeAndNil(slFoundWnd); Except On E: Exception Do ErrorLog('Free_slFoundWnd'+#13#10+E.ClassName+#13#10+E.Message); End; End; Begin Try slFoundWnd:= TStringlist.Create; Try SearchWnd; If slFoundWnd.Count >= 1 Then Begin For I:= 0 To slFoundWnd.Count-1 Do Begin WndHandle:= StrToInt(slFoundWnd[I]); SendMessage(WndHandle, WM_CLOSE, 0, 0); End; End; MinAllWnds; StartTwoWinEx; Finally Free_slFoundWnd; End; Except On E: Exception Do ErrorLog('MAIN PRG'+#13#10+E.ClassName+#13#10+E.Message); End; End. |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Nur so als kleine Info...
Wenn man das in Lazarus mit {$Mode ObjFpc}{$H+} compilieren möchte, dann muß man die Fenstersuche als PtrInt deklarieren:
Delphi-Quellcode:
Dann funzt 32bit und 64bit ... Ohne die Umstellung funzt nur {$Mode Delphi}... aber nur als 32bit-EXE...
Function SearchCallback(Wnd: HWND; lParam: PtrInt): BOOL; StdCall;
Var ClassName: Array[0..255] Of Char; Begin Try If GetClassName(Wnd, ClassName, 255) > 0 Then Begin If Pos('CabinetWClass', String(ClassName)) <> 0 Then slFoundWnd.Add(IntToStr(Wnd)); End; Result:= True; Except On E: Exception Do ErrorLog('SearchCallback'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure SearchWnd; Begin Try EnumWindows(@SearchCallback, 0); Except On E: Exception Do ErrorLog('SearchWnd'+#13#10+E.ClassName+#13#10+E.Message); End; End; EDIT: Uses Interfaces; // oder man compiliert nur mit FPC und läßt den Overkill weg... |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Es funktioniert mit SetForegroundWindow und Win + Left / Win + R übrigens, ich habe den Quelltext gestern Abend kurz statt MoveWindow eingesetzt. Allerdings geht es erst einmal nur mit einem Sleep(1000) zwischen den Schritten, das scheint daran zu liegen, dass Windows 10 bei der Tastenkombi die anderen Fenster als Vorschlag anzeigt, damit man nur das Fenster für die andere Seite anklicken muss.
Vielleicht lässt sich das auch lösen, indem man mit GetForegroundWindow prüft wann das passende Fenster wirklich den Fokus hat. |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
So geht's am besten:
"StartTwoWinEx" gekürzt und WorkArea selber eingebaut, so braucht man "Forms" nicht einbinden und die EXE ist kleiner (90,5 kb statt 362 kb). Jetzt kann man das Programm mit Delphi7 kompilieren und mit Lazarus und mit FreePascal (Einfach in Lazarus "Project".."Neues Project".. "Einfaches Programm" öffnen und {$APPTYPE GUI} eingeben und LongInt ersetzen mit PtrInt. Ohne LCL und LCLBase bekommt die EXE dann folgende Grösse: 32bit = 246 kb, 64bit = 335 kb; In den Projekt-Einstellungen Win32App-Box deaktivieren. Die D7-EXE ist natürlich schwer zu schlagen... es sei denn man nimmt API-Only oder KOL... :)
Delphi-Quellcode:
@ jaenicke:
PROGRAM TwoWinEx;
//{$APPTYPE GUI} //nur für FPC (Kein cmd-Fenster) USES Windows, Messages, Classes, SysUtils, ShellApi; VAR slFoundWnd: TStringlist; WndHandle : THandle; I : Integer; Procedure ErrorLog(ErrorInfo: String); Var slLoad : TStringlist; slSave : TStringlist; strErrorLog: String; Procedure Free_slLoad; Begin Try FreeAndNil(slLoad); Except End; End; Procedure Free_slSave; Begin Try FreeAndNil(slSave); Except End; End; Function ErrorLogExists: Boolean; Begin Try Result:= False; If FileExists('ErrorLog.txt') Then Begin Try slLoad:= TStringlist.Create; slLoad.LoadFromFile('ErrorLog.txt'); strErrorLog:= slLoad.Text; Result:= True; Finally Free_slLoad; End; End; Except End; End; Begin Try Try slSave:= TStringlist.Create; slSave.Add(DateTimeToStr(Now)); slSave.Add(ErrorInfo); If ErrorLogExists Then Begin slSave.Add(' '); slSave.Add(Trim(strErrorLog)); End; slSave.SaveToFile('ErrorLog.txt'); Finally Free_slSave; End; Except End; End; Function SearchCallback(Wnd: HWND; lParam: LongInt): BOOL; StdCall; //FPC: PtrInt Var ClassName: Array[0..255] Of Char; Begin Try If GetClassName(Wnd, ClassName, 255) > 0 Then Begin If Pos('CabinetWClass', String(ClassName)) <> 0 Then slFoundWnd.Add(IntToStr(Wnd)); End; Result:= True; Except On E: Exception Do ErrorLog('SearchCallback'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure SearchWnd; Begin Try EnumWindows(@SearchCallback, 0); Except On E: Exception Do ErrorLog('SearchWnd'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure MinAllWnds; Begin Try Keybd_event(VK_LWIN, 0, 0, 0); Keybd_event(Byte('M'), 0, 0, 0); Keybd_event(Byte('M'), 0, KEYEVENTF_KEYUP, 0); Keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0); Except On E: Exception Do ErrorLog('MinAllWnds'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure StartTwoWinEx; Var Path1, Path2: String; WorkArea : TRect; Begin Try If DirectoryExists('I:\') And DirectoryExists('I:\(DOWNLOADS)') Then Begin Path1:= 'I:\'; Path2:= 'I:\(DOWNLOADS)'; End Else Begin Path1:= 'C:\'; Path2:= 'D:\'; End; ShellExecute(0, Nil, PChar(Path1), Nil, Nil, SW_SHOW); ShellExecute(0, Nil, PChar(Path2), Nil, Nil, SW_SHOW); Repeat slFoundWnd.Clear; SearchWnd; Until slFoundWnd.Count >= 2; SystemParametersInfo(SPI_GETWORKAREA, 0, @WorkArea,0) ; MoveWindow(StrToInt(slFoundWnd[0]), WorkArea.Left, WorkArea.Top, ((WorkArea.Right-WorkArea.Left) Div 2), (WorkArea.Bottom-WorkArea.Top), True); MoveWindow(StrToInt(slFoundWnd[1]), ((WorkArea.Right-WorkArea.Left) Div 2), WorkArea.Top, ((WorkArea.Right-WorkArea.Left) Div 2), (WorkArea.Bottom-WorkArea.Top), True); Except On E: Exception Do ErrorLog('StartTwoWinEx'+#13#10+E.ClassName+#13#10+E.Message); End; End; Procedure Free_slFoundWnd; Begin Try FreeAndNil(slFoundWnd); Except On E: Exception Do ErrorLog('Free_slFoundWnd'+#13#10+E.ClassName+#13#10+E.Message); End; End; Begin Try slFoundWnd:= TStringlist.Create; Try SearchWnd; If slFoundWnd.Count >= 1 Then Begin For I:= 0 To slFoundWnd.Count-1 Do Begin WndHandle:= StrToInt(slFoundWnd[I]); SendMessage(WndHandle, WM_CLOSE, 0, 0); End; End; MinAllWnds; StartTwoWinEx; Finally Free_slFoundWnd; End; Except On E: Exception Do ErrorLog('MAIN PRG'+#13#10+E.ClassName+#13#10+E.Message); End; End. "Sleep 1000" ist zwar nicht die Ewigkeit, aber besser wäre natürlich ohne... "MoveWindow" ist doch uralt oder? Das hatten doch schon die ersten Win9x-Versionen im Programm?? Ist doch gar nicht schlecht wenn man das überall verwenden kann. Ich probier jetzt nochmal "SetForegroundWindow" und Restore & Co. .. mal sehen wie das optisch wirkt... (mal ohne MinAllWnds). |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
Zitat:
Beim von Luckie schon angesprochenen kontraproduktivem Auslagern von
Delphi-Quellcode:
in eine extra Methode platzierst du beispielsweise einen leeren try..except Block, der niemals greifen kann. Deine StringList erzeugst du ja vorher schon in einem try..finally Resourcen-Schutzblock. Sprich: Die List ist auf jeden Fall erstellt, also kann
FreeAndNil
Delphi-Quellcode:
gar nicht fehlschlagen. Dass
Free
Delphi-Quellcode:
hier unnötigt ist, hat Luckie ja auch schon erwähnt. Konkret wäre dies die korrekte Herangehensweise:
FreeAndNil
Delphi-Quellcode:
Andere Stelle:
SL := TStringList.Create;
try // .. finally SL.Free; end; ![]() Dann sind an einigen Stellen die Resourcen-Schutzblöcke falsch positioniert. Die
Delphi-Quellcode:
Funktion sollte beispielsweise eher so aussehen:
ErrorLogExists
Delphi-Quellcode:
Also erst die StringList erzeugen und dann den Resourcen-Schutzblock mit
function ErrorLogExists: Boolean;
begin Result := false; if FileExists('ErrorLog.txt') then begin slLoad := TStringlist.Create; try slLoad.LoadFromFile('ErrorLog.txt'); strErrorLog := slLoad.Text; Result := true; finally slLoad.Free; end; end; end;
Delphi-Quellcode:
einleiten. Wichtig ist, dass das
try
Delphi-Quellcode:
nicht mit im Block ist, sonst ist nicht garantiert, dass das
Create
Delphi-Quellcode:
im finally Block funktioniert.
Free
Dieser Artikel könnte für dich auch noch interessant sein: ![]() |
AW: Zwei Windows Explorer starten und nebeneinander bildschirmfüllend positionieren
@Zacherl:
Ja, du hast ja Recht.... Hab' die ganze Procedure neu gebaut und jetzt ist sie viel besser:
Delphi-Quellcode:
Natürlich ist da immer noch zu viel TryExceptEnd (was ich generell zu übertrieben benutze..) drin... ich brauche halt nur 'nen ErrorLog und möchte weiter nichts sehen...
Procedure ErrorLog(ErrorInfo: String);
Var slSave: TStringlist; Begin Try slSave:= TStringlist.Create; Try If FileExists('ErrorLog.txt') Then Begin Try slSave.LoadFromFile('ErrorLog.txt'); Except End; End; slSave.Text:= DateTimeToStr(Now)+#13#10+ ErrorInfo+#13#10+ ''+#13#10+ slSave.Text; slSave.SaveToFile('ErrorLog.txt'); Finally slSave.Free; End; Except End; End; Danke für die Info mit der Windows-Api... hab' nie groß darüber nachgedacht... Warum ich das nicht gleich gesehen hab' weiß der Kuckuck... EDIT: Ok, das TryExceptEnd hinter Finally ist wirklich quatsch.... (Warum sollte es beim Speicherfreigeben Probleme geben... wahrscheinlich unwahrscheinlich :-)). Der erste generelle TryExceptEnd-Block sichert das SaveToFile... (und das Erstellen der Stringlist, wenn ich auch nicht wüßte was da schiefgehen sollte..) hat also zumindest einen Sinn... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:14 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