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
r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
I think I've found a good workaround for the problem reported above.
The file type is stored in the second "column" of the desktop listview (even if that column is not visible). It's not the extension, but the human readable form of the file type (for example "File folder" for a folder). It is therefore possible to save it with the icon name.

However, there is still a problem. The human readable form of the extension is not always unique. For example JPG and PNG files can be identified both as "Image". So, this is probably not sufficient to uniquely identify all icons.

We can perhaps use other columns as well: Column 3 holds the size of the file (empty for a folder), column 4 holds the modification date, column 5 the creation date and column 6 the attribute flags. However, IMO, we cannot use most of those fields, as they can change if the user edits a file before restoring the icons. I suppose however that using the creation date should be safe, as it is not subject to change often.

I have modified your script to add that "unique ID". Here it is (for x64 ONLY!)
/*
   Save and Load desktop icon positions
   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 ; Icons names
      ControlGet, list2, list, Col2 ; Icons types
      ControlGet, list5, list, Col5 ; Icons creation dates
      Loop, Parse, list2, `n
         filetype_%A_Index% := A_LoopField
      Loop, Parse, list5, `n
         cr_date_%A_Index% := A_LoopField
      if !coords
      {
         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% . "," . cr_date_%A_Index% . ")"
            ret .= iconid ":" (NumGet(iCoord) & 0xFFFF) | ((Numget(iCoord, 4) & 0xFFFF) << 16) "`n"
         }
         DllCall("VirtualFreeEx", "UInt", hProcess, "UInt", pItemCoord, "UInt", 0, "UInt", MEM_RELEASE)
      }
      else
      {
         SendMessage, %WM_SETREDRAW%,0,0
         Loop, Parse, list, `n
         {
            iconid := A_LoopField . "(" . filetype_%A_Index% . "," . cr_date_%A_Index% . ")"
            If RegExMatch(coords,"\Q" iconid "\E:\K.*",iCoord_new)
               SendMessage, %LVM_SETITEMPOSITION%, % A_Index-1, %iCoord_new%
         }
         SendMessage, %WM_SETREDRAW%,1,0
         ret := true
      }
   }
   DllCall("CloseHandle", "UInt", hProcess)
   return ret
}

r0lZ

Rapte_Of_Suzaku
  • Members
  • 901 posts
  • Last active: Jul 08 2011 02:12 PM
  • Joined: 29 Feb 2008
Pretty good workaround! Other ideas:[*:1qk1pd5o]score each icon based on similarity to originally saved state. So the size doesn't have to be the same as before, but it gets more points if it is closer to the earlier size. The "Type" column value would be an absolute requirement, and the rest would be used when necessary.
[*:1qk1pd5o]Since the desktop folder path is known, you can scan the actual folder directly for a item that matches the info available for a given icon. This is the most reliable of the workarounds, but can still fail (2 image files of types JPG and PNG with the same name, size, attributes, and creation date. It is entirely possible, though unlikely).
[*:1qk1pd5o]like the previous option, but temporarily modify the ambiguous file and wait for the change to be visible in the syslistview32. I call it the "Poke it and see what happens" method. As fun as it sound, I'd rather not implement it...
[*:1qk1pd5o]Perhaps there is some more info in the syslistview32 that would help... I'll look over the available messages and such later.
[*:1qk1pd5o]Make "show extensions" a requirement for optimal performance.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
I'm not sure I will implement other methods, as the one I have implemented works pretty well. But you can of course try other methods.

Make "show extensions" a requirement for optimal performance.

I don't like to force the user to show extensions, but I agree that I could check if the "hide extensions for known file types" option is disabled, and switch off the part that saves the additional info if it's the case, for speed purposes. However, the Restore will completely fail if the user changes the option after having saved the icons.


BTW, there is another problem. If the user has 2 monitors, I think that the icons are saved on a per monitor basis. I suppose that currently, the script saves and restores all icons on the same monitor. I can't check that, as I am a poor owner of a single monitor. Do you have 2 monitors?
r0lZ

Rapte_Of_Suzaku
  • Members
  • 901 posts
  • Last active: Jul 08 2011 02:12 PM
  • Joined: 29 Feb 2008
Nope, it works fine for dual monitors. Though what if the user changes monitors or screen sizes? I haven't looked into that yet.

I'll just put it on my todo list that this lib could be more robust. Hopefully my second to last idea will work out for the extension part.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007

Nope, it works fine for dual monitors.

Nice! :-)

Though what if the user changes monitors or screen sizes? I haven't looked into that yet.

IMO, when the user changes the screen resolution, the icons are automatically reorganized by Windows. He should therefore re-save the icon positions. It's not a problem for your lib, but for the GUI that implements it.

BTW, do you know a way to be notified when the screen resolution changes? It would be nice to restore the icon positions automatically (if a bank for that resolution has already been saved, of course).

Anyway, IMO, it is more important to have a way to restore the icon sizes. Any news of that frontline?
r0lZ

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Here is a working and complete example.

This script uses your lib (with my modifications) and the method explained elsewhere to change the current Desktop location, to toggle between the two locations, and, of course, restore the icon positions.

The first time you run it, it displays a dialog allowing the user to select a folder for the "alternate desktop". After that, it acts as a simple toggle. It is less sophisticated than your script for VirtuaWin, but it is usable, and IMO, 2 desktop locations are sufficient for many users. (I use it to toggle my programming environment with my normal desktop.)

It can theoretically work under a 32bit or 64bit system, but you need to use the correct version of AHK_L. I haven't tested it under a 32bit system yet, but I guess it should run OK.
; 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_MyDocuments . "\SwapDesktopLocations"
inifile := settingsdir . "\SwapDesktopLocations.ini"

; 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, %settingsdir%
{
    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, SwapDesktopLocation, %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

    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, SwapDesktopLocation, %txt%

    exit, 0
}

; get desktop folder locations and verify if they exist
IniRead, desktop1loc, %inifile%, Settings, Desktop1
IniRead, desktop2loc, %inifile%, Settings, Desktop2
if (desktop1loc == "ERROR")
{
    soundbeep
    exit, 1
}
if (desktop2loc == "ERROR")
{
    soundbeep
    exit, 1
}
IfNotExist, %desktop1loc%
{
    soundbeep
    exit, 1
}
IfNotExist, %desktop2loc%
{
    soundbeep
    exit, 1
}

; determines the current desktop
if (A_Desktop == desktop1loc)
{
    newpath := desktop2loc
    curiconset := "Desktop1"
    newiconset := "Desktop2"
}
else
{
    newpath := desktop1loc
    curiconset := "Desktop2"
    newiconset := "Desktop1"
}

; Save current icons positions
SaveDesktopIconsPositions(settingsdir . "\" . curiconset . ".iconspos")

; 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 plkaces
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)

; restore current icons positions
RestoreDesktopIconsPositions(settingsdir . "\" . newiconset . ".iconspos")

; Finally, show the icons again
Control, Show,, SysListView321, ahk_class %desktopname%

; 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

; done
exit, 0


/*
   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         
      ControlGet, list2, list, Col2
      ControlGet, list5, list, Col5
      Loop, Parse, list2, `n
         filetype_%A_Index% := A_LoopField
      Loop, Parse, list5, `n
         cr_date_%A_Index% := A_LoopField
      if !coords
      {
        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% . "," . cr_date_%A_Index% . ")"
                ret .= iconid ":" (NumGet(iCoord) & 0xFFFF) | ((Numget(iCoord, 4) & 0xFFFF) << 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% . "," . cr_date_%A_Index% . ")"
                ret .= iconid ":" (NumGet(iCoord) & 0xFFFF) | ((Numget(iCoord, 4) & 0xFFFF) << 16) "`n"
             }
         }
         DllCall("VirtualFreeEx", "UInt", hProcess, "UInt", pItemCoord, "UInt", 0, "UInt", MEM_RELEASE)
      }
      else
      {
         SendMessage, %WM_SETREDRAW%,0,0
         Loop, Parse, list, `n
         {
            iconid := A_LoopField . "(" . filetype_%A_Index% . "," . cr_date_%A_Index% . ")"
            If RegExMatch(coords,"\Q" iconid "\E:\K.*",iCoord_new)
               SendMessage, %LVM_SETITEMPOSITION%, % A_Index-1, %iCoord_new%
         }
         SendMessage, %WM_SETREDRAW%,1,0
         ret := true
      }
   }
   DllCall("CloseHandle", "UInt", hProcess)
   return ret
}

; save positions to file
SaveDesktopIconsPositions(filename)
{
    coords := DeskIcons()
    FileDelete, %filename%
    FileAppend, %coords%, %filename%
}

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

There is still one thing that I don't like: the way I check if the script is running under a 64bit system. Currently, I check if "Program Files (x86)" exists. Do you know a better method?
r0lZ

Rapte_Of_Suzaku
  • Members
  • 901 posts
  • Last active: Jul 08 2011 02:12 PM
  • Joined: 29 Feb 2008
This is where I left off:
LVM_FIRST := 0x1000
	LVM_SETTILEVIEWINFO:= LVM_FIRST+162
	LVM_GETTILEVIEWINFO:= LVM_FIRST+163
	VarSetCapacity( info, 10*8, 0 )
	SendMessage, %LVM_GETTILEVIEWINFO%,0,&info,SysListView321, ahk_class Progman
	MsgBox %ErrorLevel%
	ListVars
	Msgbox resize
	SendMessage, %LVM_SETTILEVIEWINFO%,0,&info,SysListView321, ahk_class Progman

I'm doing something wrong (ErrorLevel =1), but don't have time to mess with it more right now (new job, new apartment, my furniture only just arrived!). It may be something simple, as I didn't spend much time with it. See LVM_GETTILEVIEWINFO Message for relevant documentation. It looks like it should return the icon size through the "sizeTile" part of the info struct.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Thanks. I don't understand the method yet, but I will analyze it tomorrow.
r0lZ

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Hum, my script doesn't work well any more. For whatever reason, the 5th column of the desktop listview doesn't contain the creation date any more, and it is therefore useless to save it.

(I think that I have reorganized the columns when I have played with the "funny display modes" and temporally created that 5th column, just to be sure that that was possible. After a reboot, that column has been reset, and is now empty.)

Luckily, the 2nd column still contains the file type, so the script works relatively well, as long as there are no several files with the same name and the same human readable file type. But it is not as good as I thought.

Maybe we can force the 5th column with some trick, but perhaps it's not a good idea. I will think at your alt methods later...


I have also had a look at your method to retrieve the icon size, but I can't get it to work. I have always 1, -1 or -4 as the ErrorLevel, or FAIL. Anyway, the structure is still empty. :-(
r0lZ

gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
so is there a working windows 7 version. I couldnt understand half of all these posts.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
Yes, this one works well, under Win7 x64 (and should work also under Win7 x32, Vista x64 and x32, and XP, but I have not tested it).

The only problem is that it is theoretically possible to have several icons with the same name and file type, when the folder option to hide the extensions for known file types is enabled. For example, if you have a file named "test.jpg" and another one "test.png" on your desktop, and both the "png" and "jpg" extensions are registered under the same file type name (for example "image"), then they are displayed as "test" (without the extension) and there is no way for the script to distinguish which icon should go at which location, and in that case, one or both of the two icons will probably be misplaced after a save and restore.

There is no problem if "hide extensions for known file types" is disabled in Control Panel -> Folder Options -> View tab.

This is my working example that swaps two Desktop locations. The icon save and restore library is at the end of the file.

You have to use the latest version of AutoHotkey_L (x64 or x32 depending of your system) to execute or compile the script.
; 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_MyDocuments . "\SwapDesktopLocations"
inifile := settingsdir . "\SwapDesktopLocations.ini"

; 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, %settingsdir%
{
    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, SwapDesktopLocation, %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

    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, SwapDesktopLocation, %txt%

    exit, 0
}

; get desktop folder locations and verify if they exist
IniRead, desktop1loc, %inifile%, Settings, Desktop1
IniRead, desktop2loc, %inifile%, Settings, Desktop2
if (desktop1loc == "ERROR")
{
    soundbeep
    exit, 1
}
if (desktop2loc == "ERROR")
{
    soundbeep
    exit, 1
}
IfNotExist, %desktop1loc%
{
    soundbeep
    exit, 1
}
IfNotExist, %desktop2loc%
{
    soundbeep
    exit, 1
}

; determines the current desktop
if (A_Desktop == desktop1loc)
{
    newpath := desktop2loc
    curiconset := "Desktop1"
    newiconset := "Desktop2"
}
else
{
    newpath := desktop1loc
    curiconset := "Desktop2"
    newiconset := "Desktop1"
}

; Save current icons positions
SaveDesktopIconsPositions(settingsdir . "\" . curiconset . ".iconspos")

; 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 plkaces
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)

; restore old icons positions
RestoreDesktopIconsPositions(settingsdir . "\" . newiconset . ".iconspos")

; Finally, show the icons again
Control, Show,, SysListView321, ahk_class %desktopname%

; 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

; done
exit, 0


/*
   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
      {
        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% . ")"
                ret .= iconid ":" (NumGet(iCoord) & 0xFFFF) | ((Numget(iCoord, 4) & 0xFFFF) << 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% . ")"
                ret .= iconid ":" (NumGet(iCoord) & 0xFFFF) | ((Numget(iCoord, 4) & 0xFFFF) << 16) "`n"
             }
         }
         DllCall("VirtualFreeEx", "UInt", hProcess, "UInt", pItemCoord, "UInt", 0, "UInt", MEM_RELEASE)
      }
      else
      {
         SendMessage, %WM_SETREDRAW%,0,0
         Loop, Parse, list, `n
         {
            iconid := A_LoopField . " (" . filetype_%A_Index% . ")"
            ;iconid := A_LoopField . "(" . filetype_%A_Index% . ")"
            If RegExMatch(coords,"\Q" iconid "\E:\K.*",iCoord_new)
               SendMessage, %LVM_SETITEMPOSITION%, % A_Index-1, %iCoord_new%
         }
         SendMessage, %WM_SETREDRAW%,1,0
         ret := true
      }
   }
   DllCall("CloseHandle", "UInt", hProcess)
   return ret
}

; save positions to file
SaveDesktopIconsPositions(filename)
{
    coords := DeskIcons()
    FileDelete, %filename%
    FileAppend, %coords%, %filename%
}

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

r0lZ

gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
It didnt work.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007
What are the symptoms? Do you run it under an x32 or x64 system?
r0lZ

gamax92
  • Members
  • 411 posts
  • Last active: Aug 06 2013 05:00 AM
  • Joined: 05 Dec 2010
x32. The script wont run.

r0lZ
  • Members
  • 192 posts
  • Last active: Feb 11 2012 11:19 PM
  • Joined: 21 Apr 2007

The script wont run.

What I am supposed to understand? It MUST run. Of course, there might be a problem, but if you have AHK_L (correct version) installed, you must at least see a dialog explaining how to create a new desktop folder.

I have just tested the compiled x32 script under Win7 in a virtual box, and it works perfectly well.
r0lZ