Click here to Skip to main content
15,867,141 members
Articles / Desktop Programming / Win32

Save and Restore Icon Positions on Desktop

Rate me:
Please Sign up or sign in to vote.
4.93/5 (20 votes)
23 Aug 2013CPOL5 min read 85K   3.6K   33   32
The article describes how to save and restore positions of icons on Windows desktop.

Introduction

Recently, my company gave me a dock station for my laptop. It is a nice toy to play with, but soon I faced a little problem. From time to time (actually rather frequently) after reboot, my laptop forgets screen resolution. It does not bother me too much because restoring screen resolution is fast and easy. But the problem is that with resolution, it forgets positions of all icons on my desktop. It is easy to place them again, but not so fast as I have quite a lot of icons.

Of course, there are programs like IconRestorer which can help me. But after all, we are programmers and this is an interesting task to solve. So let the journey begin!

Registry

I Googled where Windows stores information about positions of icons on desktop. And there were nice and easy answers that this information is stored in the registry key "CurrentUser\Software\Microsoft\Windows\Shell\Bags\1\Desktop". I knew how to work with registry and it was an easy task. But very soon I realized that it is not a correct answer. Looks like Windows reads this information on LogIn and stores in on LogOut. And I'd like to restore positions of icons without rebooting my computer. So I needed another solution.

PInvoke

I Googled again and found that actually desktop is a ListView control inside some process. And anyone can send messages to this control using standard SendMessage API of Windows. And get some results. But it means that I should use PInvoke technology to work with legacy Windows API. Personally, I felt uneasy about PInvoke. First of all, you should know in which DLL each required function lives. Then there are different marshaling issues. I was scared about it. But fortunately, I found a great site: PInvoke.net. It is very easy to use and contains .NET wrappers for many native Windows functions and structures including some useful overloads. I am definitely going to use this site later on and hope it will help you too.

Process of Desktop

To be able to send messages to a control, one should get its handle - unique id of the control in Windows. In order to do it, one should first identify process containing this control. And here, I faced the first problem. You see, Windows can host the control of desktop in different processes. If you have one static image on desktop, you have one process. If you have several images and Windows changes background image from time to time, then you have another process. It took me some time to find a generic algorithm which should get handle of desktop control here.

Setting Positions of Icons

As it was said, icons are just items displayed into ListView control. It is very easy to get total number of these items:

C#
var numberOfIcons = 
  (int)Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);

It is also easy to set position of an icon to some point (x,y):

C#
public static IntPtr MakeLParam(int wLow, int wHigh)
{
    return (IntPtr)(((short)wHigh << 16) | (wLow & 0xffff));
}
 
...
 
Win32.SendMessage(_desktopHandle, Win32.LVM_SETITEMPOSITION, iconIndex, MakeLParam(x, y));

where iconIndex is index of icon between 0 and numberOfIcons - 1.

So the next thing to do was to get icon positions. And here was another problem waiting for me.

Getting Positions of Icons

It may look like it is very easy to get position of an icon. You just call something like this:

C#
Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMPOSITION, iconIndex, pointerToResult);

and variable pointerToResult contains pointer to a simple structure describing position of icon with index iconIndex. But it does not work. The problem is that control we send message to is in the another process. So the pointerToResult variable points to the memory in another process. And we can't access it due to memory protection. So the algorithm becomes more complicated. I took it from here. Shortly, you must first allocate shared memory, then send command to write some information into this shared memory and then read required information from there.

Now, I had the abilities both to get and set positions of icons. I wrote a simple program which saved and restored these positions. But appeared that it was not the end.

Getting Texts of Icons

Very soon, after I started using my program, I realized that it may swap icons. My Microsoft Word icon was restored on the place of Recycle Bin, etc. It means that after reboot index of Microsoft Word icon was changed and I can't rely on indexes only. I started thinking what I can use as a constant value to distinguish icons. The obvious answer was: 'their texts'. But this simple task became a nightmare. There are a lot of examples in the Internet how you can get texts of icons on your desktop using the same SendMessage mechanism. And no one worked on my laptop. Finally, I came across this piece of code solving this task using UIAutomationClient assembly. It allowed me to get texts of my icons and connect them with indexes of icons. I stored texts with positions and restored positions using index of icon having the same text on current load of computer.

One Last Piece

Now I was able to enjoy my program. It saved and restored positions of icons successfully. But soon, I noticed another problem. After the load of my laptop, I restored positions of icons. They were placed fine. But when I started several applications, all icons suddenly messed up again. I started to investigate this problem and found that I need to refresh desktop to preserve icon positions. Luckily it was easy to do:

C#
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

...

SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);

But very soon, it was clear that this code has one side effect. It also frequently arranges icons. This is not exactly what 'Refresh' command does for desktop. I started searching how to make real refresh. And I have not found anything working on my laptop. After some time, I suddenly realized that there is a shortcut 'F5' in Windows that refreshes the desktop and I only need to send this key to the desktop. The code is rather simple:

C#
PostMessage(_desktopHandle, WM_KEYDOWN, VK_F5, 0); 

where PostMessage is similar to SendMessage. Now everything seemed to work fine.

Points of Interest

It is still interesting for me if there is a way to get texts of icons using SendMessage:

C#
Win32.SendMessage(_desktopHandle, Win32.LVM_GETITEMTEXT, iconIndex, ...);

There must be some way...

P.S.

I understand that there is not much code in the article. But after all, I haven't created a lot of code. Most part of it was taken from different sources. I just wanted to show pitfalls on the way of solving takes of saving and restoring icon positions. If you need the code, just download my full project (see the link on the top of the article). Or follow links in the text to my sources of information.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Finstek
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseRun smoothly!!! Pin
HumXC4-Mar-22 3:52
HumXC4-Mar-22 3:52 
GeneralRe: Run smoothly!!! Pin
Ivan Yakimov4-Mar-22 3:58
professionalIvan Yakimov4-Mar-22 3:58 
GeneralRe: Run smoothly!!! Pin
HumXC4-Mar-22 8:49
HumXC4-Mar-22 8:49 
GeneralRe: Run smoothly!!! Pin
Ivan Yakimov4-Mar-22 18:59
professionalIvan Yakimov4-Mar-22 18:59 
GeneralRe: Run smoothly!!! Pin
HumXC4-Mar-22 20:21
HumXC4-Mar-22 20:21 
PraiseAbsolutely beautiful, works great 8 years later. Pin
PockyBum52216-Feb-21 5:38
PockyBum52216-Feb-21 5:38 
QuestionBroken Link Pin
Member 1459490016-Sep-19 19:57
Member 1459490016-Sep-19 19:57 
AnswerRe: Broken Link Pin
OriginalGriff16-Sep-19 20:02
mveOriginalGriff16-Sep-19 20:02 
GeneralRe: Broken Link Pin
Member 1459490017-Sep-19 4:15
Member 1459490017-Sep-19 4:15 
QuestionLVM_GETITEMRECT Pin
ElektroKill24-Jul-19 22:59
ElektroKill24-Jul-19 22:59 
QuestionHow to desktop icon image? Pin
Hal Plourde11-Nov-18 4:05
Hal Plourde11-Nov-18 4:05 
PraiseComplaint Pin
Ravi Bhavnani10-May-18 13:00
professionalRavi Bhavnani10-May-18 13:00 
PraiseThank You! Pin
EO20122-Feb-18 10:09
EO20122-Feb-18 10:09 
QuestionSave in IniFile or textfile instead Registry? Pin
forumarbeit23-Nov-17 9:57
forumarbeit23-Nov-17 9:57 
AnswerRe: Save in IniFile or textfile instead Registry? Pin
Ivan Yakimov24-Nov-17 2:56
professionalIvan Yakimov24-Nov-17 2:56 
QuestionSolution for LVM_GETITEMTEXT Pin
Member 1346922916-Oct-17 20:26
Member 1346922916-Oct-17 20:26 
AnswerRe: Solution for LVM_GETITEMTEXT Pin
Ivan Yakimov16-Oct-17 22:54
professionalIvan Yakimov16-Oct-17 22:54 
GeneralCommand line tool, based on you code Pin
Stanislav Povolotsky24-Jun-16 5:39
Stanislav Povolotsky24-Jun-16 5:39 
GeneralRe: Command line tool, based on you code Pin
Ivan Yakimov26-Jun-16 20:22
professionalIvan Yakimov26-Jun-16 20:22 
QuestionDoesn't work on Windows 8.1 x64 Pin
The_Immortal9-Feb-16 9:52
The_Immortal9-Feb-16 9:52 
AnswerRe: Doesn't work on Windows 8.1 x64 Pin
Ivan Yakimov9-Feb-16 19:32
professionalIvan Yakimov9-Feb-16 19:32 
AnswerNice tutorial Pin
Member 1116911620-Oct-14 23:51
Member 1116911620-Oct-14 23:51 
GeneralThanks IY! Pin
RedDk4-Aug-14 6:30
RedDk4-Aug-14 6:30 
BugAlmost Perfect Pin
travis3018-Jun-14 11:48
travis3018-Jun-14 11:48 
GeneralNice! Pin
deejay5000029-Nov-13 9:53
deejay5000029-Nov-13 9:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.