Where are positions of desktop shortcuts stored? Where are positions of desktop shortcuts stored? shell shell

Where are positions of desktop shortcuts stored?


UPDATE 6/3/20
++++++++++++++++++++++++++++++++++++++
I just switched over to a Win10 64-bit machine and find the solution below no longer works. I believe because of a change in the desktop internals. I figured out how to do this. See "WIN10 ADDENDUM" at the end of this answer.
++++++++++++++++++++++++++++++++++++++

I finally figured out how to do what I want (display and re-arrange desktop icons). My original question concerned locating, reading and writing to the file where the icon info is stored, but this is not a useful approach. Here is what I learned:

Explorer.exe displays desktop items in a giant ListView covering the whole desktop with ListView items corresponding to each visible icon. At startup, Explorer reads info from some arcane file and populates the ListView. On exit, it re-writes that file from the ListView. So modifying the file would not help because it would be overwritten on exit.

The right way to manipulate desktop items is to directly manipulate items in the ListView. Any changes are immediately visible on change, and are saved on exit. To access the items, we can use several Windows messages: LVM_GETITEM, LVM_GETITEMCOUNT, LVM_GETITEMPOSITION and LVM_SETITEMPOSITION. These messages are fairly simple to use with one complication: some require pointers to parameter structures. These structures must be in Explorer's address space not my app's, so some trickery is needed. Here's how to do it. I use LVM_GETITEMPOSITION as an example, which requires a pointer to a POINT structure.

  • Declare a POINT structure in your app.

  • Allocate a mirror structure in Explorer's address space using API VirtualAllocEx().

  • Send LVM_GETITEMPOSITION to Explorer specifying a pointer to this structure.

  • Read back the result into your app's POINT using API ReadProcessMemory(). This function can read memory across different address spaces.

I have prototyped these operations and they work as I wanted. My code is quite long but I will post excerpts as soon as I clean it up.

UPDATE 10/4/2019 ------------------------------------

CODE EXCERPTS

A set of commonly used utility functions was created to make code more compact and readable. These are named "exp*()" and are included at the end. A reference can be found at http://ramrodtechnology.com/explorer. Much of the basic technique herein was shamelessly stolen from https://www.codeproject.com/Articles/5570/Stealing-Program-s-Memory

Setup

// COMMONLY USED VARSHANDLE hProcess;        // explorer process handleHWND hWndLV;        // explorer main window// SET UP CONVENIENCE VARShProcess = expGetProcessHandle();   // get explorer process handleif( !hProcess ) exit( 1 );hWndLV = expGetListView();      // get main ListView of Desktopif( !hWndLV   ) exit( 1 );

Function to Print All Item Names

//@ Process a list view window and print item namesintprintAllNames(){    int ok,icount,indx;    LVITEM item;                    // point in app space    LVITEM *_pitem;                 // point in exp space    char text[512];    char *_ptext;    int nr,nwrite;              // count of bytes read/written        printf( "\n" );    // ALLOC ITEMS IN EXP SPACE    _pitem = expAlloc( sizeof(LVITEM) );    _ptext = expAlloc( sizeof(text  ) );    printf( "  NAME\n" );    printf( "  ==================================\n" );    icount = expGetItemCount();    for( indx=0; indx<icount; indx++ ) {            // for each item in LV      // SETUP ITEM IN EXP SPACE      memset( &item, 0, sizeof(LVITEM) );   // preclear      item.iItem      = indx;       // index of item to read      item.iSubItem   = 0;          // sub index (always 0)      item.mask       = LVIF_TEXT;      // component to read      item.pszText    = _ptext;     // buffer to recv text      item.cchTextMax = sizeof(text);   // size of buffer      // WRITE ITEM REQ TO EXP SPACE      ok = WriteProcessMemory( hProcess, _pitem, &item, sizeof(LVITEM), &nwrite );      // SEND MESSAGE TO GET ITEM INTO EXP SPACE      ok = SendMessage( hWndLV, LVM_GETITEM, indx, (LPARAM)_pitem );      // READ EXP TEXT INTO APP SPACE      memset( &item, 0, sizeof(LVITEM) );      ok = ReadProcessMemory( hProcess, _pitem, &item, sizeof(POINT), &nr );      ok = ReadProcessMemory( hProcess, _ptext, &text, sizeof(text),  &nr );      // PRINT RESULT      printf( "  %s\n", text );    }    ok = expFree( _pitem );    ok = expFree( _ptext );    return( TRUE );    //r Returns TRUE on success, FALSE on error}  

Function To Print All Item Positions

//@ Process a list view window and print positionintprintAllPositions(){    int ok,icount,indx,nr;    POINT pt;                   // point in app space    POINT *_ppt;                    // point in exp space        icount = expGetItemCount();    _ppt = expAlloc( sizeof(POINT) );    if( !_ppt ) return( FALSE );    printf( "   X    Y\n" );    printf( "---- ----\n" );    for( indx=0; indx<icount; indx++ ) {        // for each item in LV      ok = SendMessage( hWndLV, LVM_GETITEMPOSITION, indx, (LPARAM)_ppt );      ok = ReadProcessMemory( hProcess, _ppt, &pt, sizeof(POINT), &nr );      printf( "%4d %4d\n", pt.x, pt.y );    }    ok = expFree( _ppt );    return( TRUE );    //r Returns TRUE on success}

Function To Move Item
See 'expSetItemPosition' below. UPDATED 10/6/19

Explorer Utility Functions

// EXPLORER UTILITY FUNCTIONS//@ Allocate a block of memory in explorer spacevoid *expAlloc(  int size)     // size of block{    void *p;    p = VirtualAllocEx(         hProcess,        NULL,        size,        MEM_COMMIT,         PAGE_READWRITE );    return( p );    //r Returns addr of memory in EXPLORER space or NULL on error}//@ Free virtual memory in EXPLORER spaceintexpFree(  void *p)  // pointer to free{    int ok;    ok = VirtualFreeEx( hProcess, p, 0, MEM_RELEASE );    return( ok );    //r Returns TRUE on success, else FALSE}static int  aBiggest;       // biggest area so farstatic HWND hWndBiggest;    // hWnd with biggest area//@ Find main list view of explorerHWNDexpGetListView(){    //n Approach: Enumerate all child windows of desktop and find largest.    //n This will be the main explorer window.    HWND hWndDesktop;    hWndDesktop = GetDesktopWindow();    if( !hWndDesktop ) return( NULL );    aBiggest    = -1;       // init    hWndBiggest = NULL;     // init    EnumChildWindows( hWndDesktop, CallbackDesktopChild, 0 );        return( hWndBiggest );    //r Returns hWnd of largest explorer list view}//@ Callback for EnumChildWindowsBOOL CALLBACK CallbackDesktopChild(  HWND hWnd,  LPARAM dwUser){    //n Get size of child. If biggest, save hWnd.    int i,w,h,a;    char classname[MAXPATH+1];    RECT rect;    i = GetClassName( hWnd, classname, MAXPATH );   // get class    if( stricmp( classname, "SysListView32" ) ) {   // not a list view?      return( TRUE );               // skip it    }    // CALC SIZE    i = GetWindowRect( hWnd, &rect );    w = rect.right - rect.left;    h = rect.bottom - rect.top;    // CHECK IF BIGGEST    a = w * h;    if( a > aBiggest ) {    // is biggest?      aBiggest    = a;      hWndBiggest = hWnd;    }    return( TRUE );     // TRUE to continue enumeration}//@ Get process handle of explorer.exeHANDLEexpGetProcessHandle(){    //n Approach: take process snapshot and loop through to find "explorer.exe"    //n Needs tlhelp32.h and comctl32.lib        int i,stat;    PROCESSENTRY32 pe;    HANDLE hSnapshot;    char *name;    HANDLE h;    // TAKE A SNAPSHOT    hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );    if( !hSnapshot ) return( NULL );    // LOOP THROUGH PROCESSES AND FIND "explorer.exe"    for( i=0;;i++ ) {      pe.dwSize = sizeof( PROCESSENTRY32 );      if( i == 0 ) stat = Process32First( hSnapshot, &pe );      else         stat = Process32Next ( hSnapshot, &pe );      if( !stat ) break;                // done or error?      name = pe.szExeFile;      if( !stricmp( name, "explorer.exe" ) ) {  // matches?        h = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe.th32ProcessID );         return( h );      }    }    return( NULL );    //r Returns explorer process handle or NULL on error}//@ Get count of items in explorer list viewintexpGetItemCount(){    int count;    count = SendMessage( hWndLV, LVM_GETITEMCOUNT, 0, 0 );    return( count );    //r Returns count of item}//@ Get position of list view icon by indexintexpGetItemPosition(  int indx, // index of item  int *x,   // ptr to int to recv x  int *y)   // ptr to int to recv y{    int i,ok,icount;    char classname[MAXPATH+1];    POINT pt;                   // point in app space    POINT *_ppt;                    // point in exp space    int nr;                     // count of bytes read    //int w,h;    i = GetClassName( hWndLV, classname, MAXPATH );    // GET COUNT OF ITEMS IN LIST VIEW    icount = expGetItemCount();    if( indx < 0 || indx >= icount ) return( FALSE );    // ALLOC POINT IN EXP SPACE    _ppt = expAlloc( sizeof(POINT) );    if( !_ppt ) return( FALSE );    // SEND MESSAGE TO GET POS INTO EXP SPACE POINT    ok = SendMessage( hWndLV, LVM_GETITEMPOSITION, indx, (LPARAM)_ppt );    if( !ok ) return( FALSE );    // READ EXP SPACE POINT INTO APP SPACE POINT    ok = ReadProcessMemory( hProcess, _ppt, &pt, sizeof(POINT), &nr );    if( !ok ) return( FALSE );    ok = expFree( _ppt );    if( !ok ) return( FALSE );    if( x ) *x = pt.x;    if( y ) *y = pt.y;    //r Returns TRUE on success    return( TRUE );  }  //@ Move itemintexpSetItemPosition(  char *name,   // icon name  int x,        // new x coord  int y)        // new y coord{    int ok,indx;    LPARAM lParam;    indx = expGetItemIndex( name );    if( indx < 0 ) return( FALSE );    lParam = MAKELPARAM( x, y );    ok = SendMessage( hWndLV, LVM_SETITEMPOSITION, indx, lParam );    if( !ok ) return( FALSE );    return( TRUE );    //r Returns TRUE on success}

WIN10 ADDENDUM6/19/20
++++++++++++++++++++++++++++++++++

Under Win10, the solution is much more complicated. You must use various COM objects and interfaces, e.g. IShellWindows, etc. (God, I hate COM). I did not create a library but rather offer a complete working program below. I compiled this using MSVC 2019. Error checking has been omitted for clarity (but you should do it).

//  icons.cpp - Display (and optionally move) desktop icons#include <windows.h>#include <stdio.h>#include <conio.h>#include <ShlObj.h>#include <atlbase.h>intmain(int argc,char** argv){    CComPtr<IShellWindows> spShellWindows;    CComPtr<IShellBrowser> spBrowser;    CComPtr<IDispatch> spDispatch;    CComPtr<IShellView> spShellView;    CComPtr<IFolderView>  spView;    CComPtr<IShellFolder> spFolder;    CComPtr<IEnumIDList>  spEnum;    CComHeapPtr<ITEMID_CHILD> spidl;    CComVariant vtLoc(CLSID_ShellWindows);    CComVariant vtEmpty;    STRRET str;    int count=0;    HRESULT hr;    long lhWnd;    // INITIALIZE COM    CoInitialize(NULL);        // GET ShellWindows INTERFACE    hr = spShellWindows.CoCreateInstance(CLSID_ShellWindows);    // FIND WINDOW    hr = spShellWindows->FindWindowSW(        &vtLoc, &vtEmpty, SWC_DESKTOP, &lhWnd, SWFO_NEEDDISPATCH, &spDispatch);    // GET DISPATCH INTERFACE    CComQIPtr<IServiceProvider>(spDispatch)->      QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&spBrowser));    spBrowser->QueryActiveShellView(&spShellView);    spShellView->QueryInterface(IID_PPV_ARGS(&spView) );    hr = spView->GetFolder(IID_PPV_ARGS(&spFolder));    // GET ENUMERATOR    spView->Items(SVGIO_ALLVIEW, IID_PPV_ARGS(&spEnum));    // get enumerator    // ENUMERATE ALL DESKTOP ITEMS    for (; spEnum->Next(1, &spidl, nullptr) == S_OK; spidl.Free()) {      // GET/PRINT ICON NAME AND POSITION      char* name;      POINT pt;      spFolder->GetDisplayNameOf(spidl, SHGDN_NORMAL, &str);      StrRetToStr(&str, spidl, &name);      spView->GetItemPosition(spidl, &pt);      printf("%5d %5d \"%s\"\n", pt.x, pt.y, name);#define MOVE_ICON#ifdef MOVE_ICON      // OPTIONAL: MOVE *SINGLE* SELECTED ITEM      {        if( !_stricmp(name, "ICON_NAME_TO_MOVE") ) {        PCITEMID_CHILD apidl[1] = { spidl };        int numitems = 1;        // SET pt TO NEW POSITION HERE        hr = spView->SelectAndPositionItems(numitems, apidl, &pt, 0);        }      }#endif      count++;    }    CoUninitialize();           // release COM    fprintf(stderr, "enumerated %d desktop icons\n", count);    fprintf(stderr, "Press any key to exit...\n");    _getch();    exit(0 );}