Position der Desktop-Icons sichern und wiederherstellen

Icons auf dem Windows-Desktop

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.

Desktop-Icons mit pcwSIcon3 sichern und wiederherstellen

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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;

2 Kommentare

  • Gibt es auf dem Notebook evtl. eine Sicherheitssoftware, die die Arbeit des Tools behindert? Ich kann mir gerade keinen Fehler vorstellen, der sonst dazu führt.

    Sie können versuchen, die ActiveX-DLL neu zu registrieren. Dazu öffnen Sie als Administrator eine Kommandozeile und setzen den Befehl

    regsvr32.exe „C:\Program Files\PC-WELT\pcwSIcons3\pcwSIcon3.dll“

    ab. Passen Sie den Pfad zur Datei pcwSIcon3.dll ggf. an.
    Es sollte die Meldung erscheinen

    „DllRegisterServer in C:\Program Files\PC-WELT\pcwSIcons3\pcwSIcon3.dll erfolgreich durchgeführt.“

    Probieren Sie bitte auch aus, ob pcwSIcons3_CLI.exe funktioniert. Das Kommandozeilenprogramm kommt ohne die ActiveX-DLL aus. Sollte auch dieses nicht funktionieren, muss das Problem woanders liegen.

  • Guten Abend Herr Eggeling!

    Ich nutze Ihr pcwSIcons3 Software sehr gerne auf meinem Desktop Rechner und probiere gerade – verzweifelnd – die Software auch auf meinem Notebook zum Laufen zu bringen.

    Wenn ich mit den vbs Scripts (SaveIcons und RestoreIcons) arbeite, dann erscheinen zwar die Meldungen wie „Layout speichern.“, aber die pcwSIcon3.ini bleibt leer.

    Wenn ich die exe starte, einen Layout-Name eingebe und auf „Positionen speichern“ klicke, dann wird weder der Layout-Name eingetragen noch die ini bearbeitet.

    Haben Sie mir einen Tipp, wie ich die Software zum Funktionieren überreden kann?

    Vielen Dank!
    Matthias

    System: Windows 7, 64-bit, aktuelle Auflösung lt. SIcons3 3840×1080 (Notebook + externer Monitor).

Schreibe einen Kommentar

Mit Absenden des Kommentars akzeptieren Sie die Datschutzerklärung.
Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.