Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / February 2006

Tip: Looking for answers? Try searching our database.

Retrieving Desktop Icon Positions

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
avec.fromage@blueyonder.co.uk - 26 Feb 2006 15:52 GMT
Hi,

I'd like to be able to read the positions of all the Icons on my WinXP
desktop.  I've had a look around to see how to do it and I've come up
with the code below...but it doesn't work.  :o(

The x and y properties of my POINT structure are always zero.  It seems
the structure isn't getting updated at all from the SendMessage
function and so the code just displays the default values.

Any suggestions?

Thanks in advance, AF.
-----------------

using System;
using System.Runtime.InteropServices;

namespace DesktopIcons
{
       class GetInfo
       {
               const uint LVM_FIRST = 0x1000;
               const uint LVM_GETITEMCOUNT = (LVM_FIRST + 4);
               const uint LVM_GETITEMPOSITION = (LVM_FIRST + 16);

               [DllImport("user32.dll", SetLastError = true)]
               public static extern IntPtr FindWindow(string
lpClassName, string lpWindowName);

               [DllImport("user32.dll", SetLastError = true)]
               public static extern IntPtr FindWindowEx(IntPtr
parentHandle, IntPtr childAfter, string className, string windowTitle);

               [DllImport("user32.dll", CharSet=CharSet.Auto)]
               public static extern int SendMessage(IntPtr hWnd, uint
Msg, int wParam, IntPtr lParam);

               [DllImport("user32.dll", CharSet=CharSet.Auto)]
               public static extern int SendMessage(IntPtr hWnd, uint
Msg, int wParam, ref IntPtr lParam);

               [StructLayout(LayoutKind.Sequential,
CharSet=CharSet.Ansi)]
                       public struct POINT
               {
                       public long x;
                       public long y;
               }

               [STAThread]
               static void Main(string[] args)
               {

                       IntPtr handle = FindWindow("progman", null);
                       handle = FindWindowEx(handle, IntPtr.Zero,
"shelldll_defview", null);
                       handle = FindWindowEx(handle, IntPtr.Zero,
"syslistview32", null);

                       // Get the Number of Icons
                       int iconCount = SendMessage(handle,
LVM_GETITEMCOUNT, 0, IntPtr.Zero);

                       Console.WriteLine("Number of Icons on Desktop:
" + iconCount.ToString());

                       IntPtr ptr =
Marshal.AllocHGlobal(Marshal.SizeOf(typeof(POINT)));

                       POINT p;
                       p.x = 0;
                       p.y = 0;

                       Marshal.StructureToPtr(p, ptr, true);

                       // Get First Icon Position
                       SendMessage(handle, LVM_GETITEMPOSITION, 0, ref
ptr);

                       p = (POINT)Marshal.PtrToStructure(ptr,
typeof(POINT));

                       Console.WriteLine("First Icon Position: (x = "
+ p.x.ToString() + ", y = " + p.y.ToString() + ")");

                       Marshal.FreeHGlobal(ptr);
               }

       }
Mattias Sjögren - 27 Feb 2006 18:56 GMT
>The x and y properties of my POINT structure are always zero.  It seems
>the structure isn't getting updated at all from the SendMessage
>function and so the code just displays the default values.
>
>Any suggestions?

The pointer to your POINT structure is only valid in your own process,
not in the shell desktop process. For this to work, you either have to
get code running in the desktop process or use shared memory that can
be written to by another process.

Mattias

Signature

Mattias Sjögren [C# MVP]  mattias @ mvps.org
http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Please reply only to the newsgroup.

Charles Law - 27 Feb 2006 19:44 GMT
Hi AF

Further to Mattias's comments, here's some code that will do it in VB.NET.
I've included all the API definitions as well, since I noted that your POINT
structure used longs instead of ints. Shouldn't be tricky to convert.

Call SaveDesktop to create an array of the positions of all the desktop
icons.

The code below does not work on Windows 95/98/Me because the memory mapping
is different, but will work on NT/2000/XP.

Good luck.

<code>
Imports System.Runtime.InteropServices

Module Desktop

   Private Const STANDARD_RIGHTS_REQUIRED As Integer = &HF0000
   Private Const SECTION_QUERY As Integer = &H1S
   Private Const SECTION_MAP_WRITE As Integer = &H2S
   Private Const SECTION_MAP_READ As Integer = &H4S
   Private Const SECTION_MAP_EXECUTE As Integer = &H8S
   Private Const SECTION_EXTEND_SIZE As Integer = &H10S
   Private Const SECTION_ALL_ACCESS As Integer = STANDARD_RIGHTS_REQUIRED
Or SECTION_QUERY Or SECTION_MAP_WRITE Or SECTION_MAP_READ Or
SECTION_MAP_EXECUTE Or SECTION_EXTEND_SIZE

   Public Declare Function OpenProcess Lib "kernel32" (ByVal
dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal
dwProcessId As Integer) As IntPtr

   Private Const PROCESS_VM_OPERATION As Integer = &H8S
   Private Const PROCESS_VM_READ As Integer = &H10S
   Private Const PROCESS_VM_WRITE As Integer = &H20S

   Public Declare Function VirtualAllocEx Lib "kernel32" (ByVal hProcess As
IntPtr, ByVal lpAddress As Integer, ByVal dwSize As Integer, ByVal
flAllocationType As Integer, ByVal flProtect As Integer) As IntPtr
   Public Declare Function VirtualFreeEx Lib "kernel32" (ByVal hProcess As
IntPtr, ByVal lpAddress As IntPtr, ByVal dwSize As Integer, ByVal dwFreeType
As Integer) As Integer
   Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As
IntPtr) As Integer

   Public Const MEM_COMMIT As Integer = &H1000S
   Private Const MEM_RESERVE As Integer = &H2000S
   Public Const MEM_RELEASE As Integer = &H8000S

   Public Const PAGE_READWRITE As Integer = &H4

   Public Function GetMemSharedNT(ByVal pid As Integer, ByVal memSize As
Integer, ByRef hProcess As IntPtr) As IntPtr

       hProcess = OpenProcess(PROCESS_VM_OPERATION Or PROCESS_VM_READ Or
PROCESS_VM_WRITE, 0, pid)

       GetMemSharedNT = VirtualAllocEx(hProcess, 0, memSize, MEM_RESERVE Or
MEM_COMMIT, PAGE_READWRITE)

   End Function

   Public Sub FreeMemSharedNT(ByVal hProcess As IntPtr, ByVal MemAddress As
IntPtr, ByVal memSize As Integer)

       VirtualFreeEx(hProcess, MemAddress, memSize, MEM_RELEASE)

       CloseHandle(hProcess)

   End Sub

   Private Structure POINTAPI
       Dim x As Integer
       Dim y As Integer
   End Structure

   Private Declare Function FindWindow Lib "user32" Alias "FindWindowA"
(ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
   Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA"
(ByVal hWndParent As IntPtr, ByVal hWndChildAfter As Integer, ByVal
lpClassName As String, ByVal lpWindowName As String) As IntPtr
   Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal
hWnd As IntPtr, ByRef lpdwProcessId As Integer) As IntPtr
   Private Declare Function GetWindowLong Lib "user32" Alias
"GetWindowLongA" (ByVal hWnd As IntPtr, ByVal nIndex As Integer) As Integer

   Private Const GWL_STYLE As Integer = (-16)

   Private Const LVS_AUTOARRANGE As Integer = &H100S

   Private Declare Function ReadProcessMemory Lib "kernel32" (ByVal
hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByRef lpBuffer As
POINTAPI, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer)
As Integer
   Private Declare Function WriteProcessMemory Lib "kernel32" (ByVal
hProcess As IntPtr, ByVal lpBaseAddress As IntPtr, ByRef lpBuffer As
POINTAPI, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer)
As Integer
   Private Declare Function GetParent Lib "user32" (ByVal hWnd As IntPtr)
As IntPtr

   Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal
lParam As Integer) As Integer
   Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal
lParam As IntPtr) As Integer

   Private Const LVM_FIRST As Integer = &H1000S
   Private Const LVM_GETITEMCOUNT As Integer = (LVM_FIRST + 4)
   Private Const LVM_GETITEMPOSITION As Integer = (LVM_FIRST + 16)
   Private Const WM_COMMAND As Integer = &H111S
   Private Const IDM_TOGGLEAUTOARRANGE As Integer = &H7041S

   <StructLayout(LayoutKind.Sequential)> Private Structure LVITEM
       Dim mask As Int32
       Dim iItem As Int32
       Dim iSubItem As Int32
       Dim state As Int32
       Dim stateMask As Int32
       Dim pszText As IntPtr
       Dim cchTextMax As Int32
       Dim iImage As Int32
       Dim lParam As Int32
       Dim iIndent As Int32
   End Structure

   Private m_OriginalPoint() As POINTAPI
   Private m_AutoArrange As Boolean

   Public Function SaveDesktop() As Boolean

       Dim lvi As LVITEM

       Dim pid As Integer
       Dim tid As IntPtr
       Dim hProcess As IntPtr
       Dim SysShared As IntPtr
       Dim dwSize As Integer
       Dim IconCount As Integer
       Dim BytesWritten As Integer
       Dim BytesRead As Integer
       Dim handleDesktop As IntPtr
       Dim styleHandle As Integer

       ' Get a handle to the desktop listview
       handleDesktop = GetSysLVHwnd()

       If handleDesktop.Equals(IntPtr.Zero) Then
           Return False
       End If

       ' Get the style of the listview
       styleHandle = GetWindowLong(handleDesktop, GWL_STYLE)

       ' If the list view is set for auto-arrange we have to turn it off
for the time being
       If (styleHandle And LVS_AUTOARRANGE) = LVS_AUTOARRANGE Then
           m_AutoArrange = True

           Dim handleParent As IntPtr

           handleParent = GetParent(handleDesktop)

           SendMessage(handleParent, WM_COMMAND, IDM_TOGGLEAUTOARRANGE, 0)
       End If

       ' See how many icons there are on the desktop
       IconCount = SendMessage(handleDesktop, LVM_GETITEMCOUNT, 0, 0)

       If IconCount = 0 Then
           Return False
       End If

       ReDim m_OriginalPoint(IconCount - 1)

       dwSize = Len(m_OriginalPoint(0))

       ' Get the thread and process ids
       tid = GetWindowThreadProcessId(handleDesktop, pid)

       ' Get the position
       SysShared = GetMemSharedNT(pid, dwSize, hProcess)

       WriteProcessMemory(hProcess, SysShared, m_OriginalPoint(0), dwSize,
BytesWritten)

       For i As Integer = 0 To IconCount - 1
           SendMessage(handleDesktop, LVM_GETITEMPOSITION, i, SysShared)

           ReadProcessMemory(hProcess, SysShared, m_OriginalPoint(i),
dwSize, BytesRead)
       Next i

       FreeMemSharedNT(hProcess, SysShared, dwSize)

       If m_AutoArrange Then
           ' Restore auto-arrange
       End If

       Return True

   End Function

   Private Function GetSysLVHwnd() As IntPtr

       Dim lHandle As IntPtr

       lHandle = FindWindow("Progman", vbNullString)
       lHandle = FindWindowEx(lHandle, 0, "SHELLDLL_defVIEW", vbNullString)

       Return FindWindowEx(lHandle, 0, "SysListView32", vbNullString)

   End Function

End Module
</code>

HTH

Charles

> Hi,
>
[quoted text clipped - 86 lines]
>
>        }
avec.fromage@blueyonder.co.uk - 28 Feb 2006 09:24 GMT
Thanks for the help guys.  Charles - your code worked a treat!  :o)

I'll post my C# version shortly.  ;o)

Thanks again,

AF

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.