Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

Obtaining the position of icons on your (WinNT-based) desktop


Environment: Windows XP Pro, Visual C++.NET 2002

I have a huge monitor at home, 22". And I also have an ADSL-connection. So, when I'm at work, I'd like to connect to my home PC using Remote Desktop and do some stuff remotely. However, for some reason, the computers I connect from to my own computer never have a monitor that's the same size as mine and, thus, never the same desktop resolution. Remote Desktop then just displays my home desktop at a lower resolution when connected.

Having aligned my icons around the edges of my desktop, this causes them to be 'reorganized' so they're all messed up. Now, this isn't a problem per se, but when I get home, the icons remain at their messed-up positions, requiring me to reposition them every time I connected with Remote Desktop. Which, in my case, is daily.

Time to fire up the old development tools and write a tool that finds out the position of each icon on my desktop and save it somewhere so they can be restored at their positions at the click of a button.

This has proven to be more difficult then it seemed. Below it a step-by-step walkthrough of what I did (roughly), what problems I encountered, and how I overcame the problems. All in all, this little project took two to three hours out of my life.

The first step in getting the positions of the icons is to be able to ask something for them. And whadya know? The desktop, as you see it, is just a big ListView. So, we can use the FindWindow() and FindWindowEx() APIs to get the handle of the ListView. First, we use FindWindow() to find the window with the title "Program Manager;" then, we use FindWindowEx() to find the child window (of the program manager) with the class name "SHELLDLL_DefView" (it doesn't have a window title). Then we use FindWindowEx() again to find the child window of the SHELLDLL_DefView, with the name "FolderView." This is the ListView. So, now we have a HWND to the ListView that shows you the icons.

Next up is to ask the ListView for the icons and their positions.

We can get the number of icons pretty simply. Just SendMessage() it the LVM_GETITEMCOUNT message and it will return you the number of icons. So far, so good. Now, we can get the position of each icon by using the message LVM_GETITEMPOSITION. We need to send this message for every icon on the desktop. The WPARAM of the message is the index (which icon do we want to query?) and the LPARAM is a pointer to a POINT structure, that will receive the X and Y positions.

I did all of this, but the POINT structure never got filled. A very strange problem, indeed. The function returns TRUE, indicating success, but I get no info. After some thinking about the problem, it occurred to me. I'm sending the pointer to a place in the memory of my process, to another process. That pointer is not valid because each process has its own memory space. In other words, the pointer I send to the ListView isn't valid in its address space. So, now I need to have a pointer that is valid in the process space of the ListView, but I need to read it as well. So it's gonna need to be valid in both processes. To do this, you need to create shared memory. This seemed horribly complex to me, it was late (2:00 AM), and I wanted this small tool finished before I could go to bed. So, why not do something completely different? Why not allocate memory in the address space of the ListView and read from that? I know how to do that.

Allocating memory in the process space of another process is very easy. Just use VirtualAllocEx(). And, reading from and writing and to it is easy, as well; we have ReadProcessMemory() and WriteProcessMemory() for that. The problem I faced, however, was getting the process handle to the process that is hosting the ListView. In this case, Windows Explorer.

So, how do we find the process handle of explorer? As it turns out, there's a very simple API call for this; it's simple because we already know the handle of a window that belongs to the process we need: GetWindowThreadProcessId(). With this API, we can get the PID of the process and then use OpenProcess() to get a handle to the process.

So, now we have a process handle, we have the window handle to the ListView and we can use VirtualAllocEx(), ReadProcessMemory(), WriteProcessMemory() and VirtualFeeEx() to deal with the out-of-process-pointer issue. Combine these things, and you can get the positions of each icon on your desktop.

One final note: Because I use VirtualAllocEx() and VirtualFreeEx(), this program only works in NT-based systems (Windows NT/2000/XP), which isn't a problem for me. If you want to make this work for Win9x-based systems, you can easily do so by altering two functions in VirtualMem.cpp; I kept them nicely abstracted.

Update Info

  • Rewrote the entire program to be totally independent of MFC.
  • Used the comments made by mr_williams@rave.ch and ef_ef_ef@yahoo.com to improve the program.


Download demo project - 86 Kb
Download source - 52 Kb


  • Obtaining Icon Positions

    Posted by Legacy on 10/01/2002 07:00am

    Originally posted by: Michael Lynn


    You may wish to check out my follow up. I wrote mine using Visual C++ 6, no MFC required and I save to and restore from text files. I also have a version for Windows 9x.



  • faster way to get explorer process

    Posted by Legacy on 02/21/2002 08:00am

    Originally posted by: mr_williams

    theres a faster way to get the processid of the explorer process. since the "progman" window is in the same address space u can use GetWindowThreadProcessId to get PID.
    i can't talk C++ only asm, but im sure u get the point:


    szProgman db "progman",0


    hDesk dd ?
    dwPID dd ?


    call FindWindow, offset szProgman, NULL
    mov hDesk, eax
    call GetWindowThreadProcessId, hDesk, offset dwPID

    afterwards u can use OpenProcess with the dwPID to open explorers address space...

  • 2-3 hours with Jeffrey Richter's book

    Posted by Legacy on 12/18/2001 08:00am

    Originally posted by: Alex Farber

    It doesn't look as 2-3 hours project, but if you have "Programming Applications for Microsoft Windows", maybe...

  • For 9x Devs - An Example

    Posted by Legacy on 12/17/2001 08:00am

    Originally posted by: redllar

    Nice article :) I thought I'd add to it by indicating that
    memory-mapped files are a good way to "share" memory
    between processes on 9x boxes.

    Here's a quick example of a function related to the
    article, which removes the desktop icon's text, so that
    they're left with just the icons themselves:

    void HideDTopIconText()
    HWND hWnd = FindDTopLView();
    if( hWnd ) {
    int nItems = ListView_GetItemCount(hWnd);
    if( nItems > 0 ) {
    char szText[40];
    HANDLE hFileMap =
    CreateFileMapping((HANDLE)0xFFFFFFFF, NULL,
    PAGE_READWRITE, 0, max(sizeof(szText), sizeof
    (LVITEM)), "MyMapping");
    if( hFileMap ) {
    LPVOID pFileMap = MapViewOfFile(hFileMap,
    FILE_MAP_WRITE, 0, 0, 0);
    if( pFileMap ) {
    for( int i = 0; i < nItems; i++ ) {
    LVITEM *plvItem = (LVITEM *)pFileMap;
    ZeroMemory(plvItem, sizeof(LVITEM));
    plvItem->mask = LVIF_TEXT;
    plvItem->iItem = i;
    plvItem->pszText = (char *)pFileMap;
    plvItem->cchTextMax = sizeof(szText);
    int nChars = SendMessage(hWnd, LVM_GETITEMTEXT,
    (WPARAM)i, (LPARAM)pFileMap);
    if( nChars ) {
    CopyMemory(szText, pFileMap, nChars+1);
    ZeroMemory(plvItem, sizeof(LVITEM));
    plvItem->mask = LVIF_TEXT;
    plvItem->iItem = i;
    SendMessage(hWnd, LVM_SETITEMTEXT, (WPARAM)i,

  • Waooo! Greate Idea!! But probleme to work on WinNT 4.0

    Posted by Legacy on 12/17/2001 08:00am

    Originally posted by: EF

    It's sound like a greate ID ...

    But the following line of code return NULL:

    hFolderView = ::FindWindowEx(hDesktopView, NULL, NULL, "FolderView");

    On NT 4.0 the listControl does not seems to be named "FolderView" or... I' don't know!!

    Any way ... Great Idea!

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date