Desktop-Icons führen bei Windows manchmal ein Eigenleben. Wenn sich die Auflösung ändert, etwa bei der Installation eines neuen Grafiktreibers oder nach dem Start älterer Spiele, ist die Anordnung der Icons auf dem Windows-Desktop nicht mehr dieselbe. Mit dem Tool pcwSIcons3 können Sie die Positionen der Icons sichern und wiederherstellen.
Downloads zu diesem Artikel:
pcwSIcons3_setup.exe: Setup-Programm für alle Programme. Das Installationsprogramm installiert automatisch die 32- oder 64-Bit-Version (für Windows Vista, Windows 7 oder Windows 8)
pcwSIcons3.zip: ZIP-Archiv mit allen Programmen. Achtung: Die ActiveX-DLL müssen Sie selbst registrieren. Batch-Dateien für diesen Zweck liegen bei (als Administrator ausführen)
pcwSIcons_CLI.zip: Nur das Kommandozeilenprogramm (32-Bit und 64-Bit), beispielsweise für die Verwendung in einer Batch-Datei.
pcwSIcons3-Source: Source-Code für alle Programm (Delphi XE3).
Das Problem begleitet Windows seit Jahren. Und jeder, der häufig die Icons auf dem Desktop nutzt und hier eine gewisse Ordnung bevorzugt, kennt es wahrscheinlich. Unter bestimmten Bedingungen werden die Icons neu angeordnet und die eigene Ordnung ist dahin. Das passiert bevorzugt bei Änderungen der Bildschirmauflösung, etwa bei der Installation einen neuen Grafiktreibers oder bei bestimmten Spielen. Ein weiteres Problem sind PCs, an denen in der Regel mehrere Monitore hängen, aber eben nicht immer. Icons die auf dem zweiten Bildschirm liegen, landen dann irgendwo auf dem ersten Bildschirm, wenn nur ein Monitor angeschlossen ist. Ähnliches gilt für Notebooks, wenn sie hin und wieder mit höherer Auflösung oder im Zwei-Bildschirm-Betrieb laufen.
Es wäre daher wünschenswert, die Anordnung der Icons zu speichern und bei Bedarf wiederherzustellen. Dafür gibt es bereits einige Tools, die jedoch nicht so flexibel sind, wie ich mir das wünsche. Da ich im Besitz eines Editors und eines Compilers bin, habe ich mich also selbst an Werk gemacht. Der verwendete Delphi-Code ist schon ziemlich alt. Er stammt ursprünglich aus den Zeiten von Windows 95, funktioniert mit einigen Anpassungen aber auch heute noch. Ich habe das Programm mit Embarcadero Delphi XE3 erstellt, es sollte aber mit einigen kleinen Änderungen auch mit anderen Delphi/Freepascal-Umgebungen zu erstellen sein. Das Programm ist ursprünglich für eine PC-WELT-Artikel entstanden und ich habe es jetzt etwas weiterentwickelt. Der Quellcode steht unter GPL.
Wie funktionieren die Programme?
Aber zuerst – für Nicht-Programmierer – zu den Programmen selbst. Um alle Wünsche abzudecken, gibt es davon mehrere Varianten. Das erste Progrämmchen ist eine ActiveX-DLL. Diese lässt sich per Script oder über ein mausbedienbares Programm nutzen. Das zweite Tool kann unabhängig davon auf der Kommandozeile oder in einer Batch-Datei verwendet werden.
Das erste Programm heißt pcwSIcon3 und lässt sich am einfachsten per Setup-Programm installieren. Dieses sorgt auch für die Registrierung der ActiveX-DLL. Das Setup-Programm installiert – je nach System-Architektur – die 32- oder die 64-Bit-Version der Dateien. Im Startmenü findet sich danach das Programm PC-WELT-pcwSIcons3. Es bietet eine einfache Oberfläche. Über die Schaltfläche „Positionen speichern“ lassen sich die Icon-Positionen in einer INI-Datei sichern. Diese liegt unter %APPDATA%\pcwSIcons3\pcwSIcon3.ini. Das Tool ermittelt die aktuelle Bildschirmauflösung und speichert diese als Layout-Namen. Auf diese Weise lassen sich die Icon-Positionen für unterschiedliche Auflösungen getrennt speichern. In das Eingabefeld hinter „Layout-Name“ kann man auch selbst einen Namen eintippen, beispielsweise MeinDesktop. Per Klick auf „Wiederherstellen“ setzt das Tool die Icons wieder an die zuvor gespeicherte Stelle.
Für die Automatisierung dieses Vorgangs dienen die beiden Scripte SaveIcons.vbs und RestoreIcons.vbs. Diese erreichen Sie über das Windows-Startmenü oder direkt über den Installationsordner, etwa „C:\Program Files\PC-WELT\pcwSIcons3“. Sie können die VBS-Scripte bei Bedarf anpassen. Dazu öffnen Sie die VBS-Dateien in einem Editor. Sie können hinter „.IniFileName“ den Pfad anpassen, in dem die INI-Datei gespeichert wird und hinter „ ‚.Resolution“ einen eigenen Namen für das Bildschirm-Layout festlegen. Standardmäßig wird die Bildschirmauflösung als Name verwendet. Für den täglichen Gebrauch sollten Sie noch die „MsgBox“-Zeile auskommentieren, damit keine Meldung auf dem Bildschirm erscheint.
Programm für die Kommandozeile: Wer statt VB-Script lieber eine Batch-Datei verwenden möchte nimmt das Programm pcwSIcons3_CLI_X64.exe beziehungsweise pcwSIcons3_CLI_x86.exe. Es arbeitet unabhängig von der ActiveX-DLL, bietet aber die gleichen Funktionen. Mit der Zeile
pcwSIcons3_CLI.exe /i:c:\MyIniFile.ini /s
lassen sich die Icon-Positionen in der Datei „MyIniFile.ini“ speichern und mit
pcwSIcons3_CLI.exe /i:c:\MyIniFile.ini /r
wieder zurücksichern. Über den Parameter „/l“ können Sie einen benutzerdefinierten Namen für das Bildschirmlayout angeben:
pcwSIcons3_CLI.exe /i:c:\MyIniFile.ini /s /l:"MyDesktopLyaout"
Der Quellcode
Beim Windows-Desktop handelt es sich um ein Fenster ohne Rahmen, das seit den ersten Windows „Progman“ heißt und den Titel „Program Manager“ trägt. Dieses Fenster wird komplett von einem SysListView32 ausgefüllt, das die Desktop-Icons anzeigt. In einem ersten Schritt muss man mit der API-Funktion FindWindow den Handle dieses Fensters ermitteln. Danach findet man mit EnumchildWindows heraus, wie die Unterfenster heißen. Eins davon trägt (hoffentlich) die Bezeichnung „FolderView“. Mit ListView_GetItemCount erhält man dann die Anzahl der Icons auf dem Desktop. Mit GetWindowThreadProcessId und OpenProcess kann man sich dann Zugang zumListView verschaffen und die einzelnen Elemente mit ListView_GetItemPosition auslesen. Hier der entscheidende Ausschnitt aus dem Quellcode:
Procedure IterateIcons(const S:string; TheAction: TIconAction);
TYPE
PSharedStuff = ^TSharedStuff;
TSharedStuff = record
Buffer : ARRAY[0..MAX_PATH] OF Char;
LV : TLVItem;
Pt : TPoint;
end;
var
TI: TIniFile;
hWnd1: HWND;
dwProcessId: DWORD;
hProcess: THandle;
Pointer1: Pointer;
PLVItem1: PLVITEM;
PChar1: PChar;
I: Integer;
NumberOfBytesRead: SIZE_T;
NumberOfItems: Integer;
N: Integer;
myIconPoint: TPoint;
PSS:PSharedStuff;
Procedure OneIconNT(N:Integer);
begin
//*************** ein Icon lesen **************
with PLVItem1^ do
begin
cchTextMax := 256;
pszText := Pointer(Cardinal(Pointer1) + SizeOf(TLVItem));
mask := LVIF_TEXT;
iItem := N;
iSubItem := 0;
end;
WriteProcessMemory(hProcess, Pointer1, PLVItem1,SizeOf(TLVItem) ,NumberOfBytesRead);
SendMessage(hWnd1, LVM_GETITEM, N, lparam(Pointer1));
ReadProcessMemory( hProcess, Pointer(Cardinal(Pointer1) +
SizeOf(TLVItem)), PChar1,DWORD(256),
NumberOfBytesRead);
ListView_GetItemPosition(hWnd1, N, PPoint(Pointer1)^);
ReadProcessMemory( hProcess, Pointer1, @myIconPoint,
DWORD(sizeof(TPoint)), NumberOfBytesRead);
Case TheAction Of
SaveToIni: TI.WriteInteger (S, PChar1, Integer(PointToSmallPoint(myIconPoint)));
RestFromIni: begin
I:=TI.ReadInteger(S, PChar1, -1);
If I <>-1 Then
begin
myIconPoint:=SmallPointToPoint(TSmallPoint(I));
end;
ListView_SetItemPosition(hWnd1,N, myIconPoint.x, myIconPoint.y);
end;
end;
end;
//************** W95/98 ****************
Procedure OneIcon95(N:Integer);
Begin
WITH PSS^.LV DO
begin
mask := LVIF_TEXT;
iItem := N;
iSubItem := 0;
state := 0;
statemask := 0;
pszText := @PSS^.Buffer;
cchTextMax := MAX_PATH;
iImage := 0;
end;
SendMessage(hWnd1, LVM_GETITEM, 0, Integer(@PSS^.LV));
SendMessage(hWnd1, LVM_GETITEMPOSITION, N, Integer(@PSS^.pt));
Case TheAction Of
SaveToIni: TI.WriteInteger(S, StrPas(Pss^.Buffer),
Integer(PointToSmallPoint(PSS^.Pt)));
RestFromIni: begin
I:=TI.ReadInteger(S, StrPas(PSS^.Buffer), -1);
If I <>-1 Then
begin
PSS^.Pt:=SmallPointToPoint(TSmallPoint(I));
end;
ListView_SetItemPosition(hWnd1,N, PSS.Pt.x, PSS.Pt.y);
end;
end;
end;
//************* main *******************
Begin
TI:=TIniFile.Create(sIniFileName);
hWnd1 := DesktopListViewHandle;
if hWnd1 = 0 then exit;
//************** 95/98/ME ***************
if TOSVersion.ToString='' then begin
//
end;
If CheckForWin95= VER_PLATFORM_WIN32_WINDOWS Then
begin
NumberOfItems := ListView_GetItemCount(hWnd1);
hProcess:=CreateFileMapping( $FFFFFFFF, NIL, PAGE_READWRITE,
0, SizeOf(TSharedStuff), LVMapName);
PSS:=MapViewOfFile(hProcess, FILE_MAP_ALL_Access,0,0,0);
IF TheAction=SaveToIni Then TI.EraseSection(S);
try
For N:=0 To NumberOfItems-1 Do OneIcon95(N);
finally
TI.Free;
end;
CloseHandle(hProcess);
end
//************** NT/2K/Vista/7/8***************
Else If CheckForWin95= VER_PLATFORM_WIN32_NT Then
begin
GetWindowThreadProcessId(hWnd1, @dwProcessId);
hProcess := OpenProcess(
PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE,
false, dwProcessId);
if hProcess = 0 then exit;
Pointer1 := VirtualAllocEx(hProcess, nil, 4096,
MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
PLVItem1 := AllocMem(SizeOf(TLVItem));
PChar1 := StrAlloc(256);
NumberOfItems := ListView_GetItemCount(hWnd1);
IF TheAction=SaveToIni Then TI.EraseSection(S);
try
For N:=0 To NumberOfItems-1 Do OneIconNT(N);
finally
TI.Free;
end;
VirtualFreeEx(hProcess, PLVItem1, 0, MEM_RELEASE);
CloseHandle(hProcess);
end
else
WriteLn('Diese Plattform wird nicht unterstützt.');
end;
Schreibe einen Kommentar