Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

DeskIcons - Get/Set Desktop Icon Positions


  • Please log in to reply
80 replies to this topic
gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
Ini:
[Settings]
Desktop1=C:\Users\Jim Coonradt\Desktop
Desktop2=C:\Users\Jim Coonradt\AppData\SaveDesktop


Directory:
Desktop1.iconspos
Desktop2.iconspos
SwapDesktopLocations.ini


r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Seems OK. I'll have a look tomorrow. 4:00 AM here!
r0lZ

gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
<!-- m -->http://img528.images.../snapshotu.png/<!-- m --> - Good Screen
<!-- m -->http://img263.images...altdesktop.png/<!-- m --> - Second Desktop
<!-- m -->http://img98.imagesh.../i/errorlp.png/<!-- m --> - Restore First Desktop

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
There is one thing I don't understand. When you have launched the script for the first time, it has asked an alternate location for your desktop. Have you created the new folder "SaveDesktop" in your AppData folder, or was it already existing? Normally, after the first use, when you swap to the alt desktop, you should have an almost blank desktop, with only the icons of the special folders that Windows displays anyway (the Recycle Bin, and, on your system, perhaps also My Computer and Control Panel).

But your screenshot shows many icons. How is it possible? If you navigate with Explorer to your alt desktop folder, can you see that icons as well?

The problem could be related to the use of a conflicting app. Maybe your "Restore Desktop layout Utility thing". What program are you using? (Personnaly, I use Desktop Icons Save and Restore, and it works relatively well (despite some problems with icons that are sometimes off by one row). Anyway, I have not noticed any compatibility issue with the script.

BTW, I have already had problems with the script. Sometimes, none of the icons are restored (except the recycle bin), but I'm sure that was caused by bugs during the development of the script. As far as I know, there are no problems any more (except the minor problem with the icons with the same name and file type, described earlier). I will continue to test the script carefully. If you can find a way to reproduce the problem you had, please let me know.
r0lZ

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Maybe I've found why you have already many icons on your alt desktop. They are probably icons that are on your "Public desktop" (available to all users). Can you verify if you have icons in "C:\Users\Public\Desktop" (or "C:\Users\Public\Public Desktop")?

Furthermore, if you have some icons there and identical icons (same name and same file type) on your normal desktop, that could explain why they have been misplaced. I am currently searching a way to fix that problem, but it's not easy!
r0lZ

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
@Rapte_Of_Suzaku: Have you tested that case? The icons on the public desktop are shown anyway, even when the user swaps to his alt desktop (because the Public Desktop location is not changed). Apparently, the public icons positions are restored correctly, but there is a similar problem than with the duplicate file names and file types: it is possible to have icons (and even folders) with the same name and exactly the same file type on both desktops. Currently, your script has no way to distinguish them. I think it should be possible to modify the script to select the first entry in the list of icon positions for the first match, and in some way mark that entry as "already restored". Then, when the next icon with the same name and type is found, the script should not use the already restored entry, and use the next one (if it exists). But honestly, I don't know how to modify the RegExMatch instruction to search the next occurrence. Any idea?
r0lZ

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
I found a way that seems to work well, but I need a second loop (to parse the coords list one line at a time) inside the first loop (that parses the icons list of the current desktop). Of course, that's slower than your method. (I'm not sure it's really important, as there are usually not thousands of icons on the desktop and modern machines are fast, but I would prefer a more elegant method anyway.)

Furthermore, I'm not sure that the positions of the identical icons will not be swapped (for example test.jpg can be at the position of test.png, and vice-versa). But at least, they do not move around. And, as far as I can test, the positions are always correct. However, with my script, the icon positions are saved only when the user swaps the desktop location. It is therefore not easy to create an icon on the user desktop that is not currently visible. So, usually, when the icons are restored, the order and number of icons has not changed, so my method works well. But I'm not sure it will work as well if someone uses the DeskIcons lib to save and restore the icons of a single desktop on demand.

Anyway, here is the modified part of the script:
            ; restore desktop icon positions
            SendMessage, %WM_SETREDRAW%,0,0
            Loop, Parse, list, `n
            {
                iconid := A_LoopField . "(" . filetype_%A_Index% . ")"
                Loop, Parse, coords, `n
                {
                    already_restored := iconnum_%A_Index%
                    if (! already_restored)
                    {
                        If RegExMatch(A_LoopField,"\Q" iconid "\E:\K.*",iCoord_new)
                        {
                            iconnum_%A_Index% := 1
                            SendMessage, %LVM_SETITEMPOSITION%, % A_Index-1, %iCoord_new%
                            break
                        }
                    }
                }
            }
            SendMessage, %WM_SETREDRAW%,1,0
            ret := true

Note that that methods works well also for duplicate icon names and types on the user's desktop. :-)
r0lZ

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
If you are interested in the source code or the compiled x64 or x32 exe, I have updated the online version. Download it here: <!-- m -->http://www.4shared.c... ... ation.html<!-- m -->
r0lZ

gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
Why would you be asking me if i have icons with duplicate names, you got the pictures.

Yes i had some icons in my public folder, that would explain why. being the only member on my machine, i move them to my desktop.
The only thing my My Computer desktop icon thing struggles on is the two NullDc's.

So i remove one from the desktop save a copy and move it back. then it works fine.

EDIT: It seems the icons that scrued up were the one in the public folder.
Make a thing that says, "DeskIcons has detected that you have some icons on your desktop that are in your public Desktop folder."

EDIT2: I have not retested this.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Thanks for the confirmation.
r0lZ

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
I have noticed another bug in my script.

Usually, swapping the desktop location works well, and the icons are correctly restored. But from time to time (and especially the first time you use it after a reboot), the icons are not correctly restored, and they are all stacked to the right side of your desktop (except the icons that are common to the two desktops).

I have finally understood why this happens. Apparently, after the desktop switch, when Windows is notified of the change, Windows needs some times to initialize the desktop listview, but the notification function SHChangeNotify() returns almost immediately. So, in some rare cases, the listview is still populated with the icons of the "old" desktop when the script tries to restore the icon positions. Of course, that doesn't work well.

On my relatively fast 64bit machine, and with few icons on my desktops, it is sufficient to add a "sleep 250" instruction after SHChangeNotify(), and I haven't been able to reproduce the bug any more. But I don't know if that delay is sufficient for slower machines, or more icons. Therefore, I have added a parameter in the INI file, called SwapDelay. You can change it to suit your needs. If you have problems with icons not correctly restored, try to increase that delay (in ms) to 500 or 1000.

There is perhaps a better solution to be notified when Windows has finished to populate the listview, but honestly, I don't think so. Any idea?


I have also modified the location of the folder used to store the INI file and the two files containing the icons positions. It is now in your %APPDATA% folder, instead of in "My Documents". A more logical location IMO, as the user should not need to access that folder often.
(Of course, if you have already used a previous version, you can safely remove the old SwapDesktopLocation folder from your My Documents folder, and you will be prompted again to specify the location of your alt desktop.)


And I have added another parameter in the INI: Debug. If you set it to 1, a log file is produced (stored in the same location than the INI file), each time the desktop is swapped. You can use it to try to understand why something fails. It is recommended to leave Debug=0, as the debug mode slows down slightly the desktop swapping operation.)


I have updated the online version:
<!-- m -->http://www.4shared.c... ... ation.html<!-- m -->

And here is the code:
; SwapDesktopLocation.ahk
; By r0lZ, December 2010
;
; Autohotkey script to swap the desktop location
; and save/restore the icons positions for each desktop
;
; Using AutoHotkey_L v 1.0.90.00

; initialisation
#NoEnv
#UseHook off
#SingleInstance IGNORE
menu, tray, noicon
FileEncoding, UTF-16    ; needed to save the icon positions to a file
setWorkingDir, %A_ScriptDir%
settingsdir := A_AppData . "\SwapDesktopLocations"
inifile := settingsdir . "\SwapDesktopLocations.ini"
log := settingsdir . "\SwapDesktopLocation.log"
FileDelete, %log%
IniRead, debug, %inifile%, Settings, Debug, 0


; determines if we're running a 32 or 64 bit system
; Checks if "Program Files (x86)" exists.  Any better way?
SplitPath, A_ProgramFiles, , basedir
checkdir := basedir . "\" . "Program Files (x86)"
ifExist, %checkdir%
{
    ; We're running under a 64 bit system
    if (A_PtrSize == 4)
    {
        msgbox, 16, Swap Desktop Location, You must use the x64 version to run this program under a 64bit system.`nSorry.
        exit, 1
    }
    desktopCmd := "DesktopCmd64.exe"
}
else
{
    ; We're running under a 32 bit system
    if (A_PtrSize == 8)
    {
        msgbox, 16, Swap Desktop Location, You must use the x32 version to run this program under a 32bit system.`nSorry.
        exit, 1
    }
    desktopCmd := "DesktopCmd.exe"
}

; first time setup
IfNotExist, %inifile%
{
    A_Quotes = "
    txt := "Since it's the first time you use this program, you will need to specify a folder for your alternate desktop.  (The folder must exist.)  Of course, do NOT specify your current Desktop location!"
    txt := txt . "`n`nThe settings will be saved in your Documents folder.  If you need to restart the installation procedure, just delete the folder " . A_Quotes . settingsdir . A_Quotes . " and restart this program."
    txt := txt . "`n`nYou will now be prompted for the folder location for your alternate desktop.  Click OK to continue..."
    MsgBox, 33, Swap Desktop Location, %txt%
    ifMsgBox cancel
        exit, 0
    FileSelectFolder, dest, A_MyDocuments, 3, Alternate desktop Folder
    if ErrorLevel
        exit, 0
    if (A_Desktop == dest)
        exit, 0
    FileCreateDir, %settingsdir%
    IniWrite, %A_Desktop%, %inifile%, Settings, Desktop1
    IniWrite, %dest%,      %inifile%, Settings, Desktop2
    IniWrite, 250,         %inifile%, Settings, SwapDelay
    IniWrite, 0,           %inifile%, Settings, Debug

    txt := "Installation done."
    txt := txt . "`n`nYour standard desktop location is " . A_Quotes . A_Desktop . A_Quotes . "."
    txt := txt . "`n`nYour alternate desktop location is " . A_Quotes . dest . A_Quotes . "."
    txt := txt . "`n`nThe next time you run this program, your desktop locations will be swapped."
    MsgBox, 64, Swap Desktop Location, %txt%

    exit, 0
}


; done
rc := SwapDesktops()
exit, %rc%

; Swap desktop loactions
SwapDesktops()
{
    global settingsdir, inifile

    ; get desktop folder locations and verify if they exist
    IniRead, desktop1loc, %inifile%, Settings, Desktop1
    IniRead, desktop2loc, %inifile%, Settings, Desktop2
    IniRead, swapdelay,   %inifile%, Settings, SwapDelay, 250
    if (desktop1loc == "ERROR")
    {
        soundbeep
        ToLog("Error: Desktop1 not defined in ini file")
        return, 1
    }
    if (desktop2loc == "ERROR")
    {
        soundbeep
        ToLog("Error: Desktop2 not defined in ini file")
        return, 1
    }
    IfNotExist, %desktop1loc%
    {
        soundbeep
        ToLog("Error: Desktop1 folder does not exist")
        return, 1
    }
    IfNotExist, %desktop2loc%
    {
        soundbeep
        ToLog("Error: Desktop2 folder does not exist")
        return, 1
    }
    
    ; determines the current desktop
    if (A_Desktop == desktop1loc)
    {
        newpath := desktop2loc
        curiconset := "Desktop1"
        newiconset := "Desktop2"
        ToLog("Current desktop is the normal desktop")
    }
    else
    {
        newpath := desktop1loc
        curiconset := "Desktop2"
        newiconset := "Desktop1"
        ToLog("Current desktop is the alt desktop")
    }
    
    ; Save current icons positions
    SaveDesktopIconsPositions(settingsdir . "\" . curiconset . ".iconspos")
    
    ToLog("Swapping desktops")

    ; swap desktop folders
    DllCall("shell32\SHSetFolderPath", uint,0, uint,0, uint,0, uint,&newpath)
    
    ; hides the desktop icons during the change, so that the icons appear directly
    ; at their right places (to avoid the flickering effect).
    ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
    if hwWindow
        desktopname := "Progman"
    else
        desktopname := "WorkerW"
    Control, Hide,, SysListView321, ahk_class %desktopname%
    
    ; notify Windows of the change
    DllCall("Shell32\SHChangeNotify", uint,0x8000000, uint,0x1000, uint,0, uint,0)

    ; necessary to let Windows refresh the desktop
    sleep, %swapdelay%

    ; restore old icons positions
    ; (The first time the desktop is swapped, there is no iconpos file for the alt desktop yet,
    ; so use the normal iconpos file instead.  It will at least restore the location of
    ; the Recycle Bin and other special folders shown anyway by Windows.)
    ifExist, %settingsdir%\%newiconset%.iconspos
        RestoreDesktopIconsPositions(settingsdir . "\" . newiconset . ".iconspos")
    else
        RestoreDesktopIconsPositions(settingsdir . "\" . curiconset . ".iconspos")
    
    ; Finally, show the icons again
    Control, Show,, SysListView321, ahk_class %desktopname%

    ToLog("Done Swapping desktops`n")
    
    ; saves current icons positions as "CurrentDesktop" with desktopCmd 
    ; (for interactive restore with the Desktop Icon Save and Restore shell extension).
    ; DesktopCmd.exe or DesktopCmd64.exe must be in your path or in the same directory
    ; than the script or compiled exe for this to work.  Nothing is saved if the exe
    ; cannot be found.
    ; Download DesktopCmd.exe (command line version) here:
    ; http://www.midiox.com/index.htm?http://www.midiox.com/desktoprestore.htm
    RunWait, %desktopCmd% save /n CurrentDesktop /y, , Hide UseErrorLevel

    sleep, %swapdelay%

    return 0
}

ToLog(text)
{
    global debug, log
    if (debug)
        FileAppend, %text%`n, %log%
}

/*
    Save and Load desktop icon positions, by Rapte_Of_Suzaku, modified by r0lZ.
    See: http://www.autohotkey.com/forum/viewtopic.php?t=65704
    based on save/load desktop icon positions by temp01 (http://www.autohotkey.com/forum/viewtopic.php?t=49714)
    
    Example:
        ; save positions
        coords := DeskIcons()
        MsgBox now move the icons around yourself
        ; load positions
        DeskIcons(coords)
    
    Plans:
        handle more settings (icon sizes, sort order, etc)
         - http://msdn.microsoft.com/en-us/library/ff485961%28v=VS.85%29.aspx   
*/
DeskIcons(coords="")
{
    Critical
    static MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x04, MEM_RELEASE := 0x8000
    static LVM_GETITEMPOSITION := 0x00001010, LVM_SETITEMPOSITION := 0x0000100F, WM_SETREDRAW := 0x000B
   
    ControlGet, hwWindow, HWND,, SysListView321, ahk_class Progman
    if !hwWindow ; #D mode
        ControlGet, hwWindow, HWND,, SysListView321, ahk_class WorkerW
    IfWinExist ahk_id %hwWindow% ; last-found window set
        WinGet, iProcessID, PID
    hProcess := DllCall("OpenProcess"   , "UInt",   0x438         ; PROCESS-OPERATION|READ|WRITE|QUERY_INFORMATION
                        , "Int",   FALSE         ; inherit = false
                        , "UInt",   iProcessID)
    if hwWindow and hProcess
    {   
        ControlGet, list, list, Col1 ; file names         
        ControlGet, list2, list, Col2 ; file types
        Loop, Parse, list2, `n
            filetype_%A_Index% := A_LoopField
        if !coords
        {
            ; save desktop icon positions
            if (A_PtrSize == 8)
            {
                ; we're running under a 64bit system
                VarSetCapacity(iCoord, 16)
                pItemCoord := DllCall("VirtualAllocEx", "UInt", hProcess, "UInt", 0, "UInt", 8, "UInt", MEM_COMMIT, "UInt", PAGE_READWRITE)
                Loop, Parse, list, `n
                {
                    SendMessage, %LVM_GETITEMPOSITION%, % A_Index-1, %pItemCoord%
                    DllCall("ReadProcessMemory", "UInt", hProcess, "UInt", pItemCoord, "UInt64", &iCoord, "UInt", 16, "UIntP", cbReadWritten)
                    iconid := A_LoopField . " (" . filetype_%A_Index% . ")"
                    posx := NumGet(iCoord) & 0xFFFF
                    posy := Numget(iCoord, 4) & 0xFFFF
                    ToLog("Saving pos: " . iconid . " : " . posx . "x" . posy)
                    ret .= iconid ":" posx | (posy << 16) "`n"
                }
            }
            else
            {
                ; we're running under a 32bit system
                VarSetCapacity(iCoord, 8)
                pItemCoord := DllCall("VirtualAllocEx", "UInt", hProcess, "UInt", 0, "UInt", 8, "UInt", MEM_COMMIT, "UInt", PAGE_READWRITE)
                Loop, Parse, list, `n
                {
                    SendMessage, %LVM_GETITEMPOSITION%, % A_Index-1, %pItemCoord%
                    DllCall("ReadProcessMemory", "UInt", hProcess, "UInt", pItemCoord, "UInt", &iCoord, "UInt", 8, "UIntP", cbReadWritten)
                    iconid := A_LoopField . " (" . filetype_%A_Index% . ")"
                    posx := NumGet(iCoord) & 0xFFFF
                    posy := Numget(iCoord, 4) & 0xFFFF
                    ToLog("Saving pos: " . iconid . " : " . posx . "x" . posy)
                    ret .= iconid ":" posx | (posy << 16) "`n"
                }
            }
            DllCall("VirtualFreeEx", "UInt", hProcess, "UInt", pItemCoord, "UInt", 0, "UInt", MEM_RELEASE)
        }
        else
        {
            ; restore desktop icon positions
            SendMessage, %WM_SETREDRAW%,0,0
            Loop, Parse, list, `n
            {
                iconid := A_LoopField . " (" . filetype_%A_Index% . ")"
                Loop, Parse, coords, `n
                {
                    already_restored := iconnum_%A_Index%
                    if (! already_restored)
                    {
                        If RegExMatch(A_LoopField,"\Q" iconid "\E:\K.*",iCoord_new)
                        {
                            iconnum_%A_Index% := 1
                            ToLog("Restoring pos: " . iconid . ":" . xpos . "x" . ypos)
                            SendMessage, %LVM_SETITEMPOSITION%, % A_Index-1, %iCoord_new%
                            break
                        }
                    }
                }
            }
            SendMessage, %WM_SETREDRAW%,1,0
            ret := true
        }
    }
    DllCall("CloseHandle", "UInt", hProcess)
    return ret
}

; save positions to file
SaveDesktopIconsPositions(filename)
{
    ToLog("Saving icons positions to " . filename)

    coords := DeskIcons()
    if (coords != "")
    {
        FileDelete, %filename%
        FileAppend, %coords%, %filename%
    }
}

RestoreDesktopIconsPositions(filename)
{
    ToLog("Restoring icons positions from " . filename)

    FileRead, coords, %filename%
    if (coords != "")
        DeskIcons(coords)
}

As far as I know, there is no bug any more. :-)
r0lZ

Rapte_Of_Suzaku
  • Members
  • 901 posts
  • Last active: Jul 08 2011 02:12 PM
  • Joined: 29 Feb 2008
O_o woah. I forgot that these forums don't send you a reply notification for each new post past the first new post of a watched topic!

I have the same stacking problem with DynamicDesktop. Indeed, the problem is that the listview doesn't refresh instantly. Sorry for not mentioning it earlier (might have saved you a bit of time in debugging). Sleep does help, but the problem will come back if your computer is working hard on other tasks.

The fundamental problem is that we are trying to programmatically control a system designed only for human interaction. There probably isn't a way to be notified of when the listview is fully populated (I've looked). The best I could think of is counting the number of icons in the listview and waiting until it matches up with the number of icons expected (determined by counting the number of files present in the public and user desktops + checking the registry to determine how many "special" shortcuts are present (like "Computer")). But what if the number of icons on two desktops are the same? Maybe the script could write a temporary file to the target user desktop folder (thus changing the number).

But that's messy, and IIRC slowed things down. The problem is made worse if you switch desktops rapidly (A to B to C, all before B even loads).

If you haven't already, you might want to make your own topic for your desktop script! PM me with a link to your topic if/when you do, so that I can mention it in DynamicDesktop as being the better choice for users uninterested in VirtuaWin.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Sorry for having squatted your thread. But since my script is mainly a modification and a concrete example of your DeskIcons library, I've thought it make sense to continue in this thread. (BTW, my script is not at all tied to VirtuaWin, and is not a replacement for your DynamicDesktop script.)

If you are a moderator, feel free to split this thread. If the thread is not split when I'll have a new version ready, I will start a new one.


There is probably another way to check if the desktop has been correctly populated. I have the list of icons supposed to be present on the desktop (since they have been saved during the last switch), so I don't need to count the items on the desktop, and it is easy to know the number of items in the listview. If both numbers are equal, then I can assume that the right icons are *probably* loaded, and begin the work to layer them out. During that process, I can also count the number of icons that have been properly layered out. If all icons have been processed, then it's OK. Otherwise, the procedure must be restarted.

Of course, if the user adds an icon on the "invisible desktop" manually (by creating a file in the directory), then that procedure will fail, and the script must have a way to stop refreshing the icons, or an infinite loop can occur.

There is also a similar problem if both desktops have exactly the same icons (for examples if both desktops have no icons except special folders and public icons). So, perhaps the most efficient way to distinguish if the icons are correct would be to create a file on the alt desktop. I think I will try to implement that method.

Oh, and since currently my script must be launched each time the user wants to switch the desktop location, it is easy to avoid the problems caused by too rapid switch operations. I've simply added a sleep at the end of the script, and "#SingleInstance IGNORE". It is therefore impossible to launch it when another instance is still running.
r0lZ

Rapte_Of_Suzaku
  • Members
  • 901 posts
  • Last active: Jul 08 2011 02:12 PM
  • Joined: 29 Feb 2008
No, feel free to squat here. It's just that I think your script deserves its own topic. My DynamicDesktop also happens to have a standalone (non-VirtuaWin) mode, but it is more of a demo. I'd link to your script because anyone uninterested in VirtuaWin would have a better experience using your script.

For my uses, I only set frequently used folders as desktop targets. More often than not, files will be changed since last time I visited that desktop. I use the desktop as a work folder, not as a collection of shortcuts. So if I'm working on AHK stuff, I'll move to my AHK desktop which will display my AHK script test area.

Mods have a green color to their name when you see them in the forum "users currently here" or whatever list. And admins are orange.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Using the frequently used folders folder is a good idea. Will try it.

I have already modified my script. There is a bug in the old script, that doesn't work well when new icons are created or old icons are removed in the "hidden folder" (so it will certainly fail if you use it to swap to the frequently used folders).

And I have implemented a way to wait for the refresh of the listview. I simply create a file in the "hidden desktop" before swapping it. Then I check if that file is present in the listview. When it's the case, I delete it, and I restore the icon positions. Unfortunately, when the test file is deleted, Windows again needs a long time (about one second) to remove it from the listview, so I need a second check, this time to be sure that it has been removed. Therefore, the swap is slower than with the "sleep" method, but it works well even when the PC is busy.

There is still a little problem. Icons that have been created in the "hidden desktop" folder have no saved positions, of course. Therefore they should be moved in the first empty space by Windows when that folder is made current. Unfortunately, for a reason that I don't understand, they are one column to the right of that first empty space. Seems it's a problem with Windows, as I don't force their position at all. That problem is not very important, as the user has never positioned that icon manually, so it is not really at a wrong position, but I would prefer to position it correctly, like Windows does when the file is created by a program. Do you know a way to instruct Windows to put the icon in the first empty space (without having to compute its position)? Perhaps some "magic" coordinates for the LVM_SETITEMPOSITION message? (I've tried 0, but that doesn't work.)
r0lZ