The MASM Forum Archive 2004 to 2012

General Forums => The Workshop => Topic started by: Jimg on April 11, 2008, 05:34:27 PM

Title: Talking to the desktop
Post by: Jimg on April 11, 2008, 05:34:27 PM
   I have a program that I wrote to put my desktop icons back where I want them when they get moved by some other process or situation beyond my control.
   
   The problem is that even though I can easily move the icons with code, turning off autoarrange and aligntogrid if needed, they will not hold.  In some situations, the desktop returns them to where they were before I moved them unless I manually click on at least one icon and move it somewhere after running my program.  This seems to lock in all the positions I set with my program.
   
   I have spent many hours trying to find some way to lock the positions in with code but have been unsuccessful.  So I've finally given up and am using the following code to emulate manually moving an icon-

    inv SetCursorPos,txpos,typos
    inv mouse_event,MOUSEEVENTF_LEFTDOWN,txpos,typos,0,0
    add txpos,10
    inv mouse_event,MOUSEEVENTF_MOVE,10,0,0,0
    inv Sleep,500
    inv mouse_event,MOUSEEVENTF_LEFTUP,0,0,0,0
    inv Sleep,500
    inv SetCursorPos,oldpos.x,oldpos.y
   
    Which works unless some other window is covering up the icon I'm trying to move, in which case the mouse movements go to that window instead.
   
    So, the only possibilities I can see are
   
    1. minimize all the windows on the desktop to be sure they are out of the way, or
   
    2. send the messages directly to the desktop.
   
    I've tried number two with no luck so far.  I trapped the messages to the desktop listview resulting from the above code with spy++ and, filtering out all the crud, they turn out to be-
   
0002008A P WM_MOUSEMOVE fwKeys:0000 xPos:15 yPos:170
0002008A S WM_SETCURSOR hwnd:0002008A nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
0002008A R WM_SETCURSOR fHaltProcessing:False
0002008A P WM_MOUSEMOVE fwKeys:0000 xPos:15 yPos:170
0002008A S WM_MOUSEACTIVATE hwndTopLevel:00020090 nHittest:HTCLIENT uMsg:WM_LBUTTONDOWN
0002008A R WM_MOUSEACTIVATE fuActivate:MA_NOACTIVATE
0002008A S WM_SETCURSOR hwnd:0002008A nHittest:HTCLIENT wMouseMsg:WM_LBUTTONDOWN
0002008A R WM_SETCURSOR fHaltProcessing:False
0002008A P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:15 yPos:170
0002008A P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:23 yPos:170
0002008A S WM_SETCURSOR hwnd:0002008A nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
0002008A R WM_SETCURSOR fHaltProcessing:False
0002008A P WM_MOUSEMOVE fwKeys:0000 xPos:23 yPos:170
0002008A S WM_SETCURSOR hwnd:0002008A nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
0002008A R WM_SETCURSOR fHaltProcessing:False
0002008A P WM_MOUSEMOVE fwKeys:0000 xPos:23 yPos:170


I've tried to sendmessage directly to the listview like this:

    mov eax,typos
    shl eax,16
    or eax,txpos
    mov tmp,eax
    inv SendMessage,hListView,WM_MOUSEMOVE,0,tmp
    inv Sleep,100
    inv SendMessage,hListView,WM_LBUTTONDOWN,MK_LBUTTON,tmp
    inv Sleep,500
    mov eax,txpos
    add eax,10
    mov edx,typos
    shl edx,16
    or eax,edx
    mov tmp2,eax
    inv SendMessage,hListView,WM_MOUSEMOVE,MK_LBUTTON,tmp2
    inv Sleep,500
    inv SendMessage,hListView,WM_LBUTTONUP,0,tmp2
    inv Sleep,500

but it doesn't work.  Obviously this is yet another fine point of manipulating windows I just missed along the way.


   If anyone can make a suggestion on how to implement option 1 above, or can tell me what is wrong with option 2, or better still, how to lock in the positions with code, I would appreciate it.
   
Title: Re: Talking to the desktop
Post by: sinsi on April 12, 2008, 01:06:06 AM
Have you had a play around with this registry key?
HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Bags\1\Desktop

I think this is where windows keeps icon positions etc - when I wrote my desktop icon program, deleting some values in the key seemed to
prevent windows from arbitrarily repositioning my icons.

Hah - almost 12 months to the day - Desktop icons and the shell (http://www.masm32.com/board/index.php?topic=7069.0) - although it's not much use.
Title: Re: Talking to the desktop
Post by: Jimg on April 12, 2008, 04:48:23 AM
Quote from: sinsi on April 12, 2008, 01:06:06 AM
Have you had a play around with this registry key?
HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Bags\1\Desktop

Yes, that's where the key FFlags is kept which determines if AutoArrange, AlignToGrid, and ShowDesktopIcons is kept.  I set that from the program so it doesn't revert to autoarrange upon bootup.

Information found at:  http://www.msfn.org/board/lofiversion/index.php/t22555.html

Auto Arrange off, Align to Grid off:
"FFlags"=dword:00000220

Auto Arrange on:
"FFlags"=dword:00000221

Auto Arrange off - align to Grid On:
"FFlags"=dword:00000224

Auto Arange on, Align to Grid on:
"FFlags"=dword:00000225

Hide Desktop Icons:
"FFlags"=dword:00001220

Sort by name:
"Sort"=dword:00000000

Sort by size:
"Sort"=dword:00000001

Sort by type:
"Sort"=dword:00000002

Sort by Modified:
"Sort"=dword:00000003

For example, if you wanted to enable auto arrange and sort by type:

[HKEY_CURRENT_USER\Software\Microsoft\Windows\Shell\Bags\1\Desktop]
"FFlags"=dword:00000221
"Sort"=dword:00000002


A year ago, windows XP was much better behaved than now. 

Also, this key is for XP only.  I'm trying for a more generic solution that will work with windows 98 also.

Title: Re: Talking to the desktop
Post by: sinsi on April 12, 2008, 05:44:51 AM
Have you tried deleting values ItemPos800x600(1), ItemPos1024x768(1), etc. (basically ItemPos*)? The shell seems to (re)create them at will.

To get around the abrupt repositioning, I have a save/restore program that writes/reads to a key in HKCU. I've got quite a few icons on my desktop, but
using LVS_SMALLICON fits them all, and looks cool too  :8)
Title: Re: Talking to the desktop
Post by: Jimg on April 12, 2008, 03:32:35 PM
I'm just a very positional person.  I know where the icon is supposed to be so I find them quickly and easily (although anyone else looking at my desktop couldn't understand this).
Title: Re: Talking to the desktop
Post by: Jimg on April 12, 2008, 05:50:40 PM
Quote from: sinsi on April 12, 2008, 05:44:51 AM
Have you tried deleting values ItemPos800x600(1), ItemPos1024x768(1), etc. (basically ItemPos*)? The shell seems to (re)create them at will.
Yes, I've deleted the key, and XP sp2 never put it back.  It still remembers the positions and settings.  The only way I've found to make it behave is physically move an icon as I said above.  This forces the desktop to set a flag that tells the system to save all the info on shutdown.  I have not been able to find a way to set this flag in code, or even what or where this flag is.
Edit:  I take that back, on the third reboot, after I reposition the icons where I wanted them, and move an icon manually to lock it in, and rebooted, it put the key back.  Apparently this key is only used if you don't have autoalign set, and only written if you manually move an icon, and then only on shutdown.  But deleting it had no real effect.

So back to my original question--  Someone must know how to minimize all open windows so no part of the desktop is hidden so I can use the code I presented first above, or alternately, how to send the appropriate messages to the desktop listview that will make it think the user has physically moved an icon even if a windows covers the icon, as I attempted in my second chunk of code above.
Title: Re: Talking to the desktop
Post by: xmetal on April 12, 2008, 06:37:40 PM
Quote from: Jimg on April 12, 2008, 05:50:40 PM
Someone must know how to minimize all open windows so no part of the desktop is hidden...

:bg


app db "Show Desktop.scf",0
.
.
.
invoke ShellExecute,0,0,addr app,0,0,0
Title: Re: Talking to the desktop
Post by: Jimg on April 12, 2008, 07:19:56 PM
Quote from: xmetal on April 12, 2008, 06:37:40 PM

app db "Show Desktop.scf",0
.
.
.
invoke ShellExecute,0,0,addr app,0,0,0

You had me excited there for a moment...
All I have to do is be able to find it, since it's not in the path.

I've never done shell programming before.  The commands that do the work seem to be-
[Shell]
Command=2
[Taskbar]
Command=ToggleDesktop

So, how do I execute these with an invoke?  I don't really want to write them to a file if I don't have to.
Are these kernel32 commands?
I know just enough to get in serious trouble here.

Title: Re: Talking to the desktop
Post by: jj2007 on April 12, 2008, 07:51:10 PM
Quote from: Jimg on April 12, 2008, 05:50:40 PM
Someone must know how to minimize all open windows so no part of the desktop is hidden...
Press Windows key and M simultaneously.
Title: Re: Talking to the desktop
Post by: Jimg on April 12, 2008, 08:08:22 PM
Funny.
Or are you suggesting invoke keybd_event?  Before I spend some more hours trying to figure that one out....
After a little searching, it looks like ÿ+M is the one wanted.  Still, how to do that with invoke keybd_event?

After hours of searching, I've found the command "Show the Desktop" as part of Explorer.exe, but I have no idea how to execute it.
Title: Re: Talking to the desktop
Post by: MichaelW on April 12, 2008, 08:46:36 PM
This is a crude test that seems to work OK.

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      dir   db "%USERPROFILE%\Application Data\"
            db "Microsoft\Internet Explorer\Quick Launch\",0
      app   db "Show Desktop.scf",0
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    invoke ExpandEnvironmentStrings, ADDR dir, 0, 0
    push eax
    mov ebx, halloc(eax)
    pop eax
    invoke ExpandEnvironmentStrings, ADDR dir, ebx, eax
   
    invoke ShellExecute, 0, 0, ADDR app, 0, ebx, 0

    hfree ebx
    inkey "Press any key to exit..."
    exit
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
end start
Title: Re: Talking to the desktop
Post by: Jimg on April 12, 2008, 08:52:12 PM
Thanks Michael, I try that next.

In the meantime, I found that this works-
inv keybd_event, VK_LWIN, 0, 0, 0
inv keybd_event, VK_D, 0, 0, 0
inv keybd_event, VK_LWIN, 0, KEYEVENTF_KEYUP, 0

Both methods will have to be tried out on Windows 98 also.
Title: Re: Talking to the desktop
Post by: MichaelW on April 12, 2008, 09:02:04 PM
For Windows 98 I think the environment variable USERPROFILE does not exist, but I do seem to recall a Show Desktop in the Quick Launch toolbar.

Title: Re: Talking to the desktop
Post by: sinsi on April 12, 2008, 10:18:43 PM
If you're game enough, you can use IShellDispatch, but I don't know if that includes 98.

Looking at FFlags, is it the FOLDERFLAGS enum?
Title: Re: Talking to the desktop
Post by: Jimg on April 12, 2008, 10:49:53 PM
After looking at shell stuff for a while, I'm really starting to like the dumb send the keystrokes method.  It also works on 98.
Title: Re: Talking to the desktop
Post by: Jimg on April 13, 2008, 03:08:46 AM
Quote from: sinsi on April 12, 2008, 10:18:43 PM
Looking at FFlags, is it the FOLDERFLAGS enum?
It sure looks like it.
Title: Re: Talking to the desktop
Post by: MichaelW on April 13, 2008, 04:30:36 AM
All I had to do to make my test code work under Windows 98 SE (and presumably also under 98 FE and 95) is change the environment variable from USERPROFILE to WINDIR.

At least for 95, this functionality appears to be dependent on the version of IE installed:

http://support.microsoft.com/kb/190355
Title: Re: Talking to the desktop
Post by: sinsi on April 13, 2008, 04:47:38 AM
You can also use EnumWindows and minimize each window
Title: Re: Talking to the desktop
Post by: Jimg on April 13, 2008, 03:30:19 PM
All of these are good solutions, however, what is the drawback of four simple invokes to keybd_event to send the windows-M command?  I'm all for simplicity unless there is some reason not to.
Title: Re: Talking to the desktop
Post by: Jimg on April 13, 2008, 07:05:32 PM
And, of course, all this is just one giant kludge because I can't find any other way to set the Desktop-Changed flag so it will save it's new positions when the computer is shut down or rebooted.  I'm sure there's a simple message to send to FolderView or Progman to set it, it's just not documented anywhere I can think to look.
Title: Re: Talking to the desktop
Post by: sinsi on April 14, 2008, 08:38:25 AM
To manually save positions, click the desktop and hit F5. When I did this (after deleting the ItemPos... value) it was recreated straight away.
I don't know how to do this in code though.
Title: Re: Talking to the desktop
Post by: sinsi on April 14, 2008, 11:53:58 AM
I found MinimizeAll and UndoMinimizeAll in my copy of shell32.dll (XPSP2), but the PSDK says supported (even on 95) via shell32.dll version 4.71+

MinimizeAll:

    include \masm32\include\masm32rt.inc
    .data
    x1 db 'Shell_TrayWnd',0
    .code
start:
    invoke FindWindow,offset x1,0
    test eax,eax
    jz done
    invoke PostMessage,eax,WM_COMMAND,19fh,0
done:
    exit
end start


UndoMinimizeAll:

    include \masm32\include\masm32rt.inc
    .data
    x1 db 'Shell_TrayWnd',0
    .code
start:
    invoke FindWindow,offset x1,0
    test eax,eax
    jz done
    invoke PostMessage,eax,WM_COMMAND,1a0h,0
done:
    exit
end start

Title: Re: Talking to the desktop
Post by: Jimg on April 14, 2008, 04:18:39 PM
Quote from: sinsi on April 14, 2008, 08:38:25 AM
To manually save positions, click the desktop and hit F5. When I did this (after deleting the ItemPos... value) it was recreated straight away.
I don't know how to do this in code though.
I know how to do it in code (with keybd_event), now all I need is to find the correct key to delete for the current resolution.
Title: Re: Talking to the desktop
Post by: Jimg on April 14, 2008, 04:26:18 PM
Quote from: sinsi on April 14, 2008, 11:53:58 AM
I found MinimizeAll and UndoMinimizeAll in my copy of shell32.dll (XPSP2), but the PSDK says supported (even on 95) via shell32.dll version 4.71+
What tool did you use to find this, I have been looking for many hours with no success.  I can see them with ResHacker in the typelib, but that didn't really help me.
Quote

    invoke PostMessage,eax,WM_COMMAND,19fh,0
    invoke PostMessage,eax,WM_COMMAND,1a0h,0

How did you find out these message numbers?  They aren't in the menu items.
Title: Re: Talking to the desktop
Post by: sinsi on April 15, 2008, 03:07:38 AM
That code is basically the code from shell32.dll, found with IDA
Title: Re: Talking to the desktop
Post by: Jimg on April 15, 2008, 05:03:13 PM
Well, it certainly works better then using keybd_event, but I sure wish I could find some hard documentation on it before including it.  Blindly including code with a hardcoded message number is what bit me before.  Now I iterate through the menus of the shell32 to find Auto Arrange so even if the number changes again, I should at least have a fighting chance.   These aren't menu commands as far as I can tell.  You wouldn't know how to iterate through to find these two, would you?

In this link http://msdn2.microsoft.com/en-us/library/bb774083.aspx Microsoft shows how to do it in three different languages, none of which helps me at all with Masm.
Title: Re: Talking to the desktop
Post by: sinsi on April 15, 2008, 09:50:12 PM
That was the link that made me think there was a function in shell32.dll to minimize all - the code is from IShellDispatch::MinimizeAll, not an exported function  :(
I tested it on NT4 SP6, 2000 SP4 and XP SP2 with no worries.
Title: Re: Talking to the desktop
Post by: jj2007 on April 16, 2008, 03:10:10 AM
See this link (http://www.codeguru.com/forum/showthread.php?t=310202):

(Bond) used Resource Hacker on explorer.exe and found it to be 415, though they BOTH seem to work.
Code:

MENUITEM "&Adjust Date/Time", 408
MENUITEM "Ca&scade Windows", 403
MENUITEM "Tile Windows &Horizontally", 404
MENUITEM "Tile Windows V&ertically", 405
MENUITEM SEPARATOR
MENUITEM "&Minimize All Windows", 415
MENUITEM "&Undo", 416
MENUITEM SEPARATOR
MENUITEM "Tas&k Manager...", 420
MENUITEM SEPARATOR
MENUITEM "P&roperties", 413


Finally, if there is a MASM equivalent to this code (http://www.com.it-berater.org/COM/windows_shell/interfaces/IShellDispatch.htm), let me know - I am willing to learn  :wink

FUNCTION  IShellDispatch_MinimizeAll ( _
  BYVAL pthis AS DWORD PTR _
  ) AS LONG

  LOCAL HRESULT AS LONG
  CALL DWORD @@pthis[14] USING IShellDispatch_MinimizeAll (pthis) TO HRESULT
  FUNCTION = HRESULT

END FUNCTION