Save & Restore Desktop Icons Position[Windows]

Share your advanced PureBasic knowledge/code with the community.
Dude
Addict
Addict
Posts: 1907
Joined: Mon Feb 16, 2015 2:49 pm

Re: Save & Restore Desktop Icons Position[Windows]

Post by Dude »

Rashad, I just discovered today that your code in the first post is failing for me again. After some testing, I realized "ReadData(fn,@count,SizeOf(Integer))" in RestoreDesktopIconsPositions() was returning 0 sometimes. So if I ignored that and put "count=4" after that line (4 is the number of icons on my desktop), it worked and successfully restored all icons again. So it appears ReadData is not getting the correct saved icon count from the saved icon file. Do you know how to fix that? I looked but am not sure. :oops:
Denis
Enthusiast
Enthusiast
Posts: 704
Joined: Fri Apr 25, 2003 5:10 pm
Location: Doubs - France

Re: Save & Restore Desktop Icons Position[Windows]

Post by Denis »

Hi Rashad,

excellent code (as always), works on Win 11 pro.
I modified and saved the screen resolution in the file as well to get the same layout and position on another computer with a lower resolution.
But I have a question, why a loop from 1 to 3 in the RestoreDesktopIconsPositions() procedure?

Code: Select all

For no = 1 To 3
If i do the loop once, it's Ok.
A+
Denis
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: Save & Restore Desktop Icons Position[Windows]

Post by RASHAD »

Hi Denis
This is an old thread :)
Just searched my archive and next is my last attempt
You will need Restore.png and Delete.png
Support PB x86 and x64
Added Balloon Tool-tip

Code: Select all


Prototype GetNativeSystemInfo(*lpSystemInfo.SYSTEM_INFO)

#PROCESSOR_ARCHITECTURE_AMD64 = 9
#PROCESSOR_ARCHITECTURE_IA64  = 6
#PROCESSOR_ARCHITECTURE_INTEL = 0
#PROCESSOR_ARCHITECTURE_UNKNOWN = $ffff
#SHCNE_ASSOCCHANGED = $8000000
#SHCNF_IDLIST       = $1000

Structure LV_ITEM1 Align 2
  mask.l
  iItem.l
  iSubItem.l
  state.l
  stateMask.l
  Padding.l
  *pszText
  Padding1.l
  cchTextMax.l
  iImage.l
  lParam.l
  Padding2.l
EndStructure

Structure DeskInfo
  sz.i
  name.s
  pt.point
EndStructure

Global Dim GlobalDeskinfo.DeskInfo(0)
Global Explorer, GlobalLVItem , GlobalBuffer ,hDesktopListView ,String$,count
String$ = Space(#MAX_PATH)

hProgman = FindWindow_("ProgMan", 0)
hDesktopWnd = GetDesktopWindow_()
If hProgman 
  hShellViewWin = FindWindowEx_(hProgman, 0, "SHELLDLL_DefView", 0);
  If hShellViewWin
    hDesktopListView = FindWindowEx_(hShellViewWin, 0, "SysListView32", 0);
  Else   
    Repeat
      hWorkerW = FindWindowEx_( hDesktopWnd, hWorkerW, "WorkerW", #Null );
      hShellViewWin = FindWindowEx_(hWorkerW, 0, "SHELLDLL_DefView", 0)  ;
    Until hShellViewWin <> #Null And hWorkerW <> #Null   
    hDesktopListView = FindWindowEx_(hShellViewWin, 0, "SysListView32", 0);     
  EndIf   
EndIf

Procedure refresh()
  ClearGadgetItems(0)
  If ExamineDirectory(0, GetHomeDirectory(), "*.dmr")
    n = 1
    While NextDirectoryEntry(0)
      AddGadgetItem(0,-1,Str(n)+Chr(10)+ DirectoryEntryName(0))
      n+1
    Wend
    FinishDirectory(0)
  EndIf
EndProcedure 

Import ""
  GetNativeSystemInfo(*info)
EndImport

Procedure Is64bitOS()
  Protected Info.SYSTEM_INFO
  GetNativeSystemInfo(Info)
  If info\wProcessorArchitecture
    ProcedureReturn #True
  EndIf
EndProcedure

Procedure DesktopProcessOpen()
  Protected ExplorerID
  Protected Flags = #PROCESS_VM_OPERATION | #PROCESS_VM_READ | #PROCESS_VM_WRITE | #PROCESS_QUERY_INFORMATION
  
  GetWindowThreadProcessId_(hDesktopListView,@ExplorerID)
  Explorer = OpenProcess_(Flags,#Null,ExplorerID)
  GlobalLVItem = VirtualAllocEx_(Explorer,#Null,SizeOf(LV_ITEM),#MEM_COMMIT,#PAGE_READWRITE )
  GlobalBuffer = VirtualAllocEx_(Explorer,#Null,#MAX_PATH,#MEM_COMMIT,#PAGE_READWRITE)
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    If Is64bitOS()
      ItemB.LV_ITEM1
      
      With ItemB
        \mask       = #LVIF_TEXT
        \iSubItem   = 0
        \pszText    = GlobalBuffer
        \cchTextMax = #MAX_PATH
      EndWith : WriteProcessMemory_(Explorer,GlobalLVItem,ItemB,SizeOf(ItemB),#Null)
      
    Else
      ItemA.LV_ITEM
      
      With ItemA
        \mask       = #LVIF_TEXT
        \iSubItem   = 0
        \pszText    = GlobalBuffer
        \cchTextMax = #MAX_PATH
      EndWith : WriteProcessMemory_(Explorer,GlobalLVItem,ItemA,SizeOf(ItemA),#Null)
    EndIf   
    
  CompilerElse
    ItemA.LV_ITEM
    
    With ItemA
      \mask       = #LVIF_TEXT
      \iSubItem   = 0
      \pszText    = GlobalBuffer
      \cchTextMax = #MAX_PATH
    EndWith : WriteProcessMemory_(Explorer,GlobalLVItem,ItemA,SizeOf(ItemA),#Null)
  CompilerEndIf 
  
EndProcedure

Procedure DesktopProcessClose ( )
  VirtualFreeEx_(Explorer,GlobalLVItem,#Null,#MEM_RELEASE)
  VirtualFreeEx_(Explorer,GlobalBuffer,#Null,#MEM_RELEASE)
  CloseHandle_(Explorer)
EndProcedure

Procedure.s DesktopGetIconString(Index)
  SendMessage_(hDesktopListView,#LVM_GETITEMTEXT,Index,GlobalLVItem)
  ReadProcessMemory_(Explorer,GlobalBuffer,@String$,#MAX_PATH,#Null) 
  ProcedureReturn String$   
EndProcedure

Procedure DesktopGetIconPosition(index,*pt.point)
  If SendMessage_(hDesktopListView,#LVM_GETITEMPOSITION,index,GlobalLVItem )
    ReadProcessMemory_(Explorer,GlobalLVItem,*pt,SizeOf(Point),#Null)
    ProcedureReturn #True
  Else
    ProcedureReturn #False
  EndIf   
EndProcedure

Procedure SaveDesktopIconsPositions() 
  Protected fn,index,pt.point,name.s
  file$ = FormatDate("%yy-%mm-%dd-%hh-%ii-%ss", Date())+".dmr"
  fn = OpenFile(#PB_Any,GetHomeDirectory()+file$)
  
  If fn
    DesktopProcessOpen()
    Count = SendMessage_(hDesktopListView,#LVM_GETITEMCOUNT,#Null,#Null)
    ReDim GlobalDeskinfo.DeskInfo(count)
    
    WriteData(fn,@count,SizeOf(Integer))
    
    For index = 0 To Count-1
      
      GlobalDeskinfo(index)\name = DesktopGetIconString(index) 
      GlobalDeskinfo(index)\sz = StringByteLength(GlobalDeskinfo(index)\name)     
      
      If DesktopGetIconPosition(index,pt)
        GlobalDeskinfo(index)\pt\x = pt\x
        GlobalDeskinfo(index)\pt\y = pt\y
      EndIf   
      
      WriteData(fn,@GlobalDeskinfo(index)\sz,SizeOf(Integer))
      WriteData(fn,@GlobalDeskinfo(index)\name,GlobalDeskinfo(index)\sz)
      WriteData(fn,@GlobalDeskinfo(index)\pt,SizeOf(point))
    Next
    CloseFile(fn)
  EndIf
  DesktopProcessClose()
EndProcedure

Procedure RestoreDesktopIconsPositions()
  Protected count,*buf,name.s,len,pt.point,fn,index 
  ShowWindow_(hDesktopListView,#SW_HIDE)
  ;For no = 1 To 3 
  *buf = AllocateMemory(#MAX_PATH)
  count = ArraySize(GlobalDeskinfo()) 
  DesktopProcessOpen()  
  file$ = GetGadgetItemText(0,GetGadgetState(0),1)
  fn = ReadFile(#PB_Any,GetHomeDirectory()+file$)
  If fn
    ReadData(fn,@count,SizeOf(Integer))
    If count > 0   
      For index = 0 To count-1
        FillMemory(*buf, #MAX_PATH)
        ReadData(fn,@len,SizeOf(Integer))
        ReadData(fn,*buf,len)
        name = PeekS(*buf,len)
        ReadData(fn,@PT,SizeOf(point))
        For item = 0 To count - 1
          If DesktopGetIconString(item) = name              
            SendMessage_(hDesktopListView,#LVM_SETITEMPOSITION,item,pt\y<<16|pt\x)
            Break
          EndIf
        Next
      Next
    EndIf
    CloseFile(fn)
  EndIf
  DesktopProcessClose()
  FreeMemory(*buf)
  ;Next
  ;SHChangeNotify_(#SHCNE_ASSOCCHANGED, #SHCNF_IDLIST, 0, 0)
  ShowWindow_(hDesktopListView,#SW_SHOW) 
EndProcedure

Procedure IsMouseOver(hWnd) 
  GetWindowRect_(hWnd,r.RECT) 
  GetCursorPos_(p.POINT) 
  Result = PtInRect_(r,p\y << 32 + p\x) 
  ProcedureReturn Result
EndProcedure

Define Event
UsePNGImageDecoder()
LoadFont(0,"Consolas",14)
Dim gtext$(5)

OpenWindow(0,0,0,500,300,"Desktop Icons Positions",#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
SetWindowColor(0,$0)
If CreateToolBar(0, WindowID(0))
  ToolBarID = ToolBarID(0)
  TBIL = SendMessage_(ToolBarID, #TB_GETIMAGELIST , 0, 0)
  ImageList_SetIconSize_(TBIL,24,24)
  SetWindowLongPtr_(ToolBarID(0),#GWL_STYLE, GetWindowLongPtr_(ToolBarID(0),#GWL_STYLE)|#CCS_NODIVIDER)
  SendMessage_(ToolBarID,#TB_SETBUTTONSIZE,0,24 | 24 << 16)
  SendMessage_(ToolBarID,#TB_AUTOSIZE,0,0)
  
  ToolBarImageButton(0, 0)
  ToolBarImageButton(1, LoadImage(0, #PB_Compiler_Home + "examples/sources/Data/ToolBar/Save.png"))   
  gtext$(1) = " Save "
  ToolBarImageButton(2, 0) 
  ToolBarImageButton(3, LoadImage(0, "Restore.png"))
  gtext$(3) = " Restore "
  ToolBarImageButton(4, 0) 
  ToolBarImageButton(5, LoadImage(0, "Delete.png"))
  gtext$(5) = " Delete "
EndIf
DisableToolBarButton(0,0,1)
DisableToolBarButton(0,2,1)
DisableToolBarButton(0,4,1)

FrameGadget(1, 10, 35, 480,250, " Desktop Icons Positions ")
ListIconGadget(0,20,62,460,210,"No.",42,#PB_ListIcon_FullRowSelect | #PB_ListIcon_GridLines)
SetWindowLongPtr_(GadgetID(0), #GWL_STYLE, GetWindowLongPtr_(GadgetID(0), #GWL_STYLE)|#LVS_NOCOLUMNHEADER)
SetGadgetFont(0,FontID(0))     
AddGadgetColumn(0,1,"Desktop State",414)
SetGadgetColor(0,#PB_Gadget_BackColor,$050505)
SetGadgetColor(0,#PB_Gadget_FrontColor,$FFFFFF)
SetGadgetColor(0,#PB_Gadget_LineColor,$858585)
refresh()

ttip = CreateWindowEx_(0, "Tooltips_Class32", "", #TTS_BALLOON, 0, 0, 0, 0, 0, 0, 0, 0)
SetWindowTheme_(ttip, @null.w, @null.w) 
SendMessage_(ttip,#TTM_SETTIPTEXTCOLOR,#Red,0)
SendMessage_(ttip,#TTM_SETTIPBKCOLOR,$CBFEFD,0)
SendMessage_(ttip,#WM_SETFONT,FontID(0),0)
;   SendMessage_(ttip,#TTM_SETMAXTIPWIDTH,0,180)
;   SendMessage_(ttip, #TTM_SETDELAYTIME, #TTDT_AUTOMATIC,500)

ti.TOOLINFO
ti\cbSize   = SizeOf(ti)
ti\uFlags   = #TTF_IDISHWND | #TTF_SUBCLASS 

Repeat
  Event = WaitWindowEvent()
  Select Event
    Case #WM_MOUSEMOVE 
      If IsMouseOver(ToolBarID)
        iindex = SendMessage_(ToolBarID,#TB_GETHOTITEM,0,0)
        If iindex >= 0 And  iindex <> oldiindex          
          ti\uId= ToolBarID
          Text$ = gtext$(iindex)
          ti\lpszText = @Text$              
          SendMessage_(ttip, #TTM_SETDELAYTIME, #TTDT_AUTOPOP,1000)
          SendMessage_(ttip, #TTM_ADDTOOL, 0, ti)
          ;             Else
          ;               ti\uId= ToolBarID
          ;               Text$ = ""
          ;               ti\lpszText = @Text$              
          ;               SendMessage_(ttip, #TTM_SETDELAYTIME, #TTDT_AUTOPOP,1000)
          ;               SendMessage_(ttip, #TTM_ADDTOOL, 0, ti)
        EndIf
      EndIf
      oldiindex = iindex
      
    Case #PB_Event_Menu
      Select EventMenu()
        Case 1
          SaveDesktopIconsPositions()
          refresh()          
          MessageRequester("Info","Desktop Icons Position Saved",#MB_ICONINFORMATION|#MB_OK)
        Case 3 
          RestoreDesktopIconsPositions()
          MessageRequester("Info","Desktop Icons Position Restored",#MB_ICONINFORMATION|#MB_OK)
        Case 5
          DeleteFile(GetHomeDirectory()+GetGadgetItemText(0,GetGadgetState(0),1))
          refresh()
      EndSelect
  EndSelect
Until Event = #PB_Event_CloseWindow
Egypt my love
Denis
Enthusiast
Enthusiast
Posts: 704
Joined: Fri Apr 25, 2003 5:10 pm
Location: Doubs - France

Re: Save & Restore Desktop Icons Position[Windows]

Post by Denis »

Thanks Rashad, works fine.

I go less often on the forum so sometimes I discover old posts :oops: but still excellent. Lots of good coders here with lots of interesting stuff.
A+
Denis
Post Reply