I am attempting to create a portable desktop. I want the script to replace the user's desktop suddenly with a custom folder they can carry around on a thumb drive. The reason being that I know my users are going to be lazy and I want them to be able to just store files on the desktop but be able to carry those files around with them.
The Microsoft powertoy TweakUI changes where the special folder location of the desktop points to (once you make the change in TweakUI, one simply has to send a refresh to the desktop to have the change go live). My question is specifically how can I make AutoIt do exactly the same thing?
I am totally new to scripting and especially new to using DLL's so I know very little about the windows shell or structures or pointers so please help me out! I know I can accomplish what I want to do by simply changing the registry values indicating the desktop location and then restart explorer.exe but this is crude and ungraceful. I think I have a general framework for what must happen. I think I am using the shell32.dll functions ILCreateFromPath and SHParseDisplayName to create the thing I need to pass to the 0x00020000 eventID of the SHChangeNotify function. I'm not sure if I need to add some registry changing function as well?
This is what I have so far. As far as I can tell, the only part of this that works is the part that sends a simple refresh to the desktop. Please be careful running the following code as it is dysfunctional and may cause explorer to hang!
#include-once
#include <Constants.au3>
DllOpen("shell32.dll")
;Create pidl for old desktop
$OldDesktop = "C:\Documents and Settings\Administrator\Desktop"
$oldppidl = DllCall("shell32.dll", "ptr", "ILCreateFromPath", "wstr", $OldDesktop)
$structureToMake = "int_ptr pbc;int_ptr ppidl;uint sfgaoIn;uint psfgaoOut"
$oldpdn = DllStructCreate($structureToMake)
DllStructSetData($oldpdn,"pbc",0)
DllStructSetData($oldpdn,"ppidl",$oldppidl)
DllStructSetData($oldpdn,"sfgaoIn",0)
DllStructSetData($oldpdn,"psfgaoOut",0)
$oldret = DllCall("shell32.dll", "int", "SHParseDisplayname", "wstr", $OldDesktop, "ptr", DllStructGetData($oldpdn,"pbc"), "ptr", DllStructGetData($oldpdn,"ppidl"), "int", DllStructGetData($oldpdn,"sfgaoIn"), "ptr", DllStructGetData($oldpdn,"psfgaoOut"))
;Create pidl for new desktop
$NewDesktop = "E:\PortableDesktop"
$newppidl = DllCall("shell32.dll", "ptr", "ILCreateFromPath", "wstr", $NewDesktop)
$newpdn = DllStructCreate($structureToMake)
DllStructSetData($newpdn,"pbc",0)
DllStructSetData($newpdn,"ppidl",$newppidl)
DllStructSetData($newpdn,"sfgaoIn",0)
DllStructSetData($newpdn,"psfgaoOut",0)
$newret = DllCall("shell32.dll", "int", "SHParseDisplayname", "wstr", $NewDesktop, "ptr", DllStructGetData($newpdn,"pbc"), "ptr", DllStructGetData($newpdn,"ppidl"), "int", DllStructGetData($newpdn,"sfgaoIn"), "ptr", DllStructGetData($newpdn,"psfgaoOut"))
;Notify the shell to change the desktop folder. This is attempting to do what TweakUI does
DllCall("shell32.dll", "none", "SHChangeNotify", "long", 0x00020000, "uint", 0x1000, "ptr", $oldret, "ptr", $newret)
;Send simple refresh to desktop. (Like hitting F5)
DllCall("shell32.dll", "none", "SHChangeNotify", "long", 0x8000000, "uint", 0x1000, "ptr", 0, "ptr", 0)
DllClose("shell32.dll")
Ok as a clue, I believe this C# code does what I want. I am not familiar with C# and so this is like hieroglyphics to me. I did not write this, I found it on the web elsewhere:
SHChangeNotify with SHCNE_RENAMEFOLDER doing this.
1) Define Pinvoke functions:
[DllImport("shell32.dll")]
public static extern Int32 SHParseDisplayName( [MarshalAs(UnmanagedType.LPWStr)] String pszName, IntPtr pbc, out IntPtr ppidl, UInt32 sfgaoIn, out UInt32 psfgaoOut);
[DllImport("Shell32.dll")]
public static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
2) Method to notify system about new desktop folder path:
public static void ApplyNewDesktopPath(string OldDesktop, string NewDesktop)
{
uint iAttribute;
IntPtr oldPidl;
IntPtr newPidl;
SHParseDisplayName(OldDesktop, IntPtr.Zero, out oldPidl, 0, out iAttribute);
SHParseDisplayName(NewDesktop, IntPtr.Zero, out newPidl, 0, out iAttribute);
SHChangeNotify(0x00020000, 0x1000, oldPidl, newPidl);
}
3) Refresh desktop to show new content:
public static void RefreshDesktop()
{
SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
}