• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1428
  • Last Modified:

Desktop icons' layout location.


   Does anybody know where the Desktop icons' layout is saved/placed? If this layout is nowhere (Explorer memory), how can I get/set the icons' layout?

   I need to do all this programatically by myself. I cannot use EzDesk, *.reg files or any other software.

   Thanks in advance.
0
ivan_llanas
Asked:
ivan_llanas
  • 6
  • 6
  • 4
  • +1
1 Solution
 
DaFoxCommented:
Hi Ivan.

One of madshi's components are able to do this, but, as you mentioned, you don't want to use third party components...
Jeffrey Richter once showed in his book how to do this. His code example is called "DIPS". There are also some Delphi versions available, I just can't find them atm. One of them is called "NicoDIPS" by Nico Bendlin (1:1 translated from Jeffrey Richter, I guess).
I'll try to find one of these files tomorrow, if you're interested.

Markus
0
 
ivan_llanasAuthor Commented:

  Ups! Sorry, I didn't make it clear enough with "any other software"; of course a Delphi component (with source, of course) will be a valid solution as long as I can read the code and see how it is done (or even use the component if I like it).

   By the way I'm interested in anything that could give me a clue in this affair, thanks a lot!
0
 
MadshiCommented:
Thanks Markus for refering to me...  :-)

Ivan, please have a look here:

http://help.madshi.net/ShellObjs.htm#Desktop

madShell is free for non-commercial usage (only). There's one demo contained which does exactly what you're looking for, namely saving and restoring the desktop's icon positions. In contrast to Jeffrey Richter's code my stuff even works without needing any self written dlls. Please use the latest beta version, only that contains the demo I was talking about:

http://madshi.bei.t-online.de/madCollectionBeta.exe

Regards, Madshi.
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
ivan_llanasAuthor Commented:

   Yes, that's what I need, but I need the source (at least) to get/set the position of each icon (methods Items[i].Position and Items[i]).SetPosition).
   I already have an Enumeration method (IShellFolder.EnumObjects and IEnumIdList.Next). I use PItemIDList instead of IIDList (never heard of it :P).

   The thing is: I have a list of PItemIDList's, and I need to get/set their positions. I can increase the amount of points if you consider the info worth of it...

   One more thing. The demo provided does not work with the system-icons. Looking at the desktop.txt file, I realized that these icons doesn't even figure there.
   
   I would like to talk with you about your madKernel package; I'm interested in discussing some processes-accessing methods, if you don't mind.
   
   All my programs are 100% freeware and recycled-bytes-made ;) . You can check it at www.geocities.com/ivan_llanas .

   Thanks.
   
0
 
MadshiCommented:
Hi ivan,

>> Yes, that's what I need, but I need the source (at least) to get/set the position of each icon (methods Items[i].Position and Items[i]).SetPosition).

Why do you need the source? I can't give away the sources of my packages for free, I'm sorry. That's much too dangerous.

>> I use PItemIDList instead of IIDList (never heard of it :P).

Well, IIDList is part of madShell, it's no Microsoft interface.

>> One more thing. The demo provided does not work with the system-icons. Looking at the desktop.txt file, I realized that these icons doesn't even figure there.

Did you use the latest beta version I linked in my previous comment or did you use the current official version? The latest beta version should include the system icons. About which OS are we talking? And which system icons do you mean in detail?

>> I would like to talk with you about your madKernel package; I'm interested in discussing some processes-accessing methods, if you don't mind.

Okay, ask.
0
 
ivan_llanasAuthor Commented:

>>Did you use the latest beta version I linked in my previous comment or did you use the current official version? The latest beta version should include the system icons. About which OS are we talking? And which system icons do you mean in detail?

   I used the link you specified in your last comment (http://madshi.bei.t-online.de/madCollectionBeta.exe). My OS is WinXP Pro (with several sys-patches). The icons are all the system ones: "My Computer" renamed as "The World", "Recycle Bin" as "Stasis Cell" ;) , "My Docs" as "Data Crystals", "Net Neigh..." as "The Galaxy"... and so on, pretty stupid, isn't it? ;)

>>Why do you need the source? I can't give away the sources of my packages for free, I'm sorry. That's much too dangerous

   Well, I don't need the whole sources, of course, just a couple of lines (I presume; I'm very brave ;). The calls I need to get/set the position from a PItemIDList.

   About the madKernel; I would like to know the way you access to the current running processes. I'm using CreateToolhelp32Snapshot and Process32First-Next. But I haven't been able to get the memory used by the process, the owner-user, the app fullpath (only in NT, Win9x gets the whole path)... Well, I get PID, PPID, Priority, Threads count, CPU time used and exe-filename (without path).

0
 
MadshiCommented:
>> The icons are all the system ones: "My Computer"

Ah, I'm sorry, I just noticed that I didn't recompile the demo. It's still compiled with the last official version, not with the latest beta version. Please load that demo project in Delphi and recompile it, then it will also give you the position of those system icons.

>> Well, I don't need the whole sources, of course, just a couple of lines (I presume; I'm very brave ;). The calls I need to get/set the position from a PItemIDList.

It's more than "a couple of" lines. You didn't answer on *why* you need the sources. You can compile your programs without having the sources, or not? Anyway, as I already said, I can't the sources to you, also not just the part which deals with the desktop icon position. Sorry.

>> About the madKernel; I would like to know the way you access to the current running processes. I'm using CreateToolhelp32Snapshot and Process32First-Next.

That won't work in NT4.

>> But I haven't been able to get the memory used by the process, the owner-user, the app fullpath (only in NT, Win9x gets the whole path)

Use PsApi to get the full path. You'll find sources for that (even for Delphi) on the net.

About memory: Perhaps VirtualQueryEx helps? The owner user? Look at GetKernelObjectSecurity.
0
 
ivan_llanasAuthor Commented:

   Man you're fast!

>> You didn't answer on *why* you need the sources.

   Sorry, I didn't think this was that important. I need the sources for two reasons: I change easily from one version of Delphi to another, and dcu's are not compatibles between versions; but the most important reason is that I want to know What and How I am doing things. It's not a matter of not relying on others' work, but a feeling of curiosity and a willing of knowing (uf, my English, is not as good as I would need to say what I think :P but surely you get the point, don't you?).

>>It's more than "a couple of" lines.

   Ops, pitty. Well, can you tell me if you access to this information using the Explorer process and the listview HWND or are you using the IShellFolder and fellows' interfaces? I do not want a code; I really prefer a help or a guide to get the answer by myself than getting the code that solves my "problem".

>>That won't work in NT4.

   Sure? It works with 9x/2000/XP.

   Thanks a lot for the clues for the processes' functions... I'll investigate them very soon (if I had the time :P )... I'm developing more than 12 applications simultaneously... I'm (as my friends say) getting insane...

   Thanks again.
0
 
MadshiCommented:
>> I change easily from one version of Delphi to another, and dcu's are not compatibles between versions

madCollection includes DCUs for D4, D5, D6 and D7...   :-)

>> but the most important reason is that I want to know What and How I am doing things. It's not a matter of not relying on others' work, but a feeling of curiosity and a willing of knowing

Yes, okay.

>> Well, can you tell me if you access to this information using the Explorer process and the listview HWND or are you using the IShellFolder and fellows' interfaces? I do not want a code; I really prefer a help or a guide to get the answer by myself than getting the code that solves my "problem".

Okay, you can use the ListView_GetItemPosition function to get the position of all the desktop symbols. The only problem with this is that this function ends up in sending a message to the list view control, and the message contains a pointer. Now a pointer is usually only valid in one process. So if your process sends this list view control message to another process, it won't work. Now there are several ways to get around this problem. The usual way (which Jeffrey Richter uses in his book) is to write a little dll and inject it into the explorer by misusing SetWindowsHookEx. Then the dll can send the desktop icon positions to the application e.g. by using WM_COPYDATA.

>> >> That won't work in NT4.
>> Sure? It works with 9x/2000/XP.

Yes, I'm sure. It works everywhere, but not in NT4. NT4 simply doesn't support the toolhelp functions.

Regards, Madshi.
0
 
DaFoxCommented:
> ... inject it into the explorer by misusing SetWindowsHookEx

Not everybody knows how to do that with CreateRemoteThread(), especially on Win9x. SetWindowsHookEx() is definitly the easiest way to do it and it works reliable, although I agree that CreateRemoteThread() is more professional ;-)

Madshi, why don't you need dlls? I didn't get it in your last comment! :-)

Markus
0
 
MadshiCommented:
>> Madshi, why don't you need dlls? I didn't get it in your last comment! :-)

That's probably because I didn't say it...   =:-P
0
 
DaFoxCommented:
> That's probably because I didn't say it...   =:-P

How do you want to get the 300 points then? Kretzschmar is gone if you don't take your chance! ;-p
Just kidding...
In fact, this is not really important to me. I just wondered how to do this. I won't develop my own dll-less icon positioner ;-)

Markus
0
 
MadshiCommented:
I won't get meikl, anyway, he's just too fast for me...   :-)

The secret is that the list view control wants to write to a buffer/pointer which is valid in its own process. So you have to give him one. But that's all I'll say about this, ok?
0
 
DaFoxCommented:
Sure, thanks! ;-)
If Ivan doesn't give you the points (but I don't think so), I will...

Markus
0
 
ivan_llanasAuthor Commented:

>> Okay, you can use the ListView_GetItemPosition

   All right; so it is a matter of involving the Explorer's ListView. Great. About "sending a pointer" to another process, well, there's no problem, they created the "fabulous" :P MemoryMaps or even the Read/WriteProcessMemory functions.

>>Yes, I'm sure. It works everywhere, but not in NT4. NT4 simply doesn't support the toolhelp functions.

   Ups, thanks for the info; I dind't know it. The only NT4 available to me was retired a few months ago and I cannot use one of my machines to hold a NT4 just for compatibility testing... By the other hand I used to assume that NT4 is a dead OS (at least for the desktop ;).

   Markus is right about the 300 points, but the guides you gave were enough to get a satisfactory solution, I have what I wanted; and I'm feeling really good this morning (I've had a very bad feeling about the whole world from a few days ago) and you have contributed a bit :P (moreover, I will not let those points get lost in cyber-space...) Points fly to you, MadShi.

   Of course you can add any comment to this question to make a better solution... ;)

   Here is the piece of the (test) code :

//------------------------------------------------------------------------------
procedure TForm1.Button1Click (Sender: TObject);
var ListView_WND  : HWND;
    Explorer_PID  : THandle;
    ItemInfo      : TLVITEM;
    IconPos       : TPoint;
    Buffer        : array [0..MAX_PATH] of Char;
    sh_ItemInfo   : TLVITEM;
    sh_IconPos    : TPoint;
    sh_Buffer     : array [0..MAX_PATH] of Char;
    res           : LRESULT;
    i, MaxIcon    : integer;
    BytesCount    : DWORD;
begin
   ListView_WND := GetListViewHandle;
   // Get the icons count on the desktop
   MaxIcon := SendMessage (ListView_WND, LVM_GETITEMCOUNT, 0, 0)-1;
   if MaxIcon<1 then Exit; // Nothing to do... :(
   Explorer_PID := GetExlorerPID (ListView_WND); // Get the ListView's owner PID
   for i:=0 to MaxIcon do
   begin
      // Get the icon position.
      res := SendMessage (ListView_WND, LVM_GETITEMPOSITION, i, integer(@sh_IconPos));
      if res=0 then raise Exception.Create ('Unable to get the icon position.');

      // Get the info from the "shared" memory
      if not ReadProcessMemory (Explorer_PID, @sh_IconPos, @IconPos, sizeof(TPoint), BytesCount) then
         raise Exception.Create ('ReadProcessMemory error');

      // Get the icon label.
      ItemInfo.iSubItem   := 0;
      ItemInfo.cchTextMax := MAX_PATH;
      ItemInfo.mask       := LVIF_TEXT;
      ItemInfo.pszText    := @sh_Buffer;
      if not WriteProcessMemory (Explorer_PID, @sh_ItemInfo, @ItemInfo, sizeof(TLVITEM), BytesCount) then
         raise Exception.Create ('WriteProcessMemory error');
      res := SendMessage (ListView_WND, LVM_GETITEMTEXT, i, integer(@sh_ItemInfo));
      if res<0 then raise Exception.Create ('Unable to get the icon label.');
      if not ReadProcessMemory (Explorer_PID, @sh_Buffer, @Buffer, sizeof(Buffer), BytesCount) then
         raise Exception.Create ('ReadProcessMemory error');

      // Display current icon info
      ListBox1.Items.Add (Format ('%s : %d,%d - %d', [StrPas (Buffer), IconPos.x, IconPos.y, i]));
    end;
end;
{
Note : All sh_* vars can be substituted by the * vars; the dual vars is to
       keep it clearer.
}
//------------------------------------------------------------------------------

   This procedure is to GET the positions. To set them it is the same idea but finding in a seved list the icon's caption and using the LVM_SETITEMPOSITION.

   Of course it's not 100% done by me. I tranlated a portion of a C++ source I found in the web; but I don't like it too much; dealing with Read/WriteProcessMemory must not be very good idea... But it works and this saves me to use an external-dll hook more complex to code, also.

   I wonder if this code works for a non-admin user. I'll try it when I have the time...

   Thanks.
0
 
ivan_llanasAuthor Commented:

>> Okay, you can use the ListView_GetItemPosition

   All right; so it is a matter of involving the Explorer's ListView. Great. About "sending a pointer" to another process, well, there's no problem, they created the "fabulous" :P MemoryMaps or even the Read/WriteProcessMemory functions.

>>Yes, I'm sure. It works everywhere, but not in NT4. NT4 simply doesn't support the toolhelp functions.

   Ups, thanks for the info; I dind't know it. The only NT4 available to me was retired a few months ago and I cannot use one of my machines to hold a NT4 just for compatibility testing... By the other hand I used to assume that NT4 is a dead OS (at least for the desktop ;).

   Markus is right about the 300 points, but the guides you gave were enough to get a satisfactory solution, I have what I wanted; and I'm feeling really good this morning (I've had a very bad feeling about the whole world from a few days ago) and you have contributed a bit :P (moreover, I will not let those points get lost in cyber-space...) Points fly to you, MadShi.

   Of course you can add any comment to this question to make a better solution... ;)

   Here is the piece of the (test) code :

//------------------------------------------------------------------------------
procedure TForm1.Button1Click (Sender: TObject);
var ListView_WND  : HWND;
    Explorer_PID  : THandle;
    ItemInfo      : TLVITEM;
    IconPos       : TPoint;
    Buffer        : array [0..MAX_PATH] of Char;
    sh_ItemInfo   : TLVITEM;
    sh_IconPos    : TPoint;
    sh_Buffer     : array [0..MAX_PATH] of Char;
    res           : LRESULT;
    i, MaxIcon    : integer;
    BytesCount    : DWORD;
begin
   ListView_WND := GetListViewHandle;
   // Get the icons count on the desktop
   MaxIcon := SendMessage (ListView_WND, LVM_GETITEMCOUNT, 0, 0)-1;
   if MaxIcon<1 then Exit; // Nothing to do... :(
   Explorer_PID := GetExlorerPID (ListView_WND); // Get the ListView's owner PID
   for i:=0 to MaxIcon do
   begin
      // Get the icon position.
      res := SendMessage (ListView_WND, LVM_GETITEMPOSITION, i, integer(@sh_IconPos));
      if res=0 then raise Exception.Create ('Unable to get the icon position.');

      // Get the info from the "shared" memory
      if not ReadProcessMemory (Explorer_PID, @sh_IconPos, @IconPos, sizeof(TPoint), BytesCount) then
         raise Exception.Create ('ReadProcessMemory error');

      // Get the icon label.
      ItemInfo.iSubItem   := 0;
      ItemInfo.cchTextMax := MAX_PATH;
      ItemInfo.mask       := LVIF_TEXT;
      ItemInfo.pszText    := @sh_Buffer;
      if not WriteProcessMemory (Explorer_PID, @sh_ItemInfo, @ItemInfo, sizeof(TLVITEM), BytesCount) then
         raise Exception.Create ('WriteProcessMemory error');
      res := SendMessage (ListView_WND, LVM_GETITEMTEXT, i, integer(@sh_ItemInfo));
      if res<0 then raise Exception.Create ('Unable to get the icon label.');
      if not ReadProcessMemory (Explorer_PID, @sh_Buffer, @Buffer, sizeof(Buffer), BytesCount) then
         raise Exception.Create ('ReadProcessMemory error');

      // Display current icon info
      ListBox1.Items.Add (Format ('%s : %d,%d - %d', [StrPas (Buffer), IconPos.x, IconPos.y, i]));
    end;
end;
{
Note : All sh_* vars can be substituted by the * vars; the dual vars is to
       keep it clearer.
}
//------------------------------------------------------------------------------

   This procedure is to GET the positions. To set them it is the same idea but finding in a seved list the icon's caption and using the LVM_SETITEMPOSITION.

   Of course it's not 100% done by me. I tranlated a portion of a C++ source I found in the web; but I don't like it too much; dealing with Read/WriteProcessMemory must not be very good idea... But it works and this saves me to use an external-dll hook more complex to code, also.

   I wonder if this code works for a non-admin user. I'll try it when I have the time...

   Thanks.
0
 
MassiveDCommented:
I gathered much information from this article. I thought I would contribute back. I believe the last code example you gave has a serious problem in it. When you call

res := SendMessage (ListView_WND, LVM_GETITEMPOSITION, i, integer(@sh_IconPos));

I believe you are making explorer.exe overwrite its own memory with the icon position. The process works, but I believe it may cause explorer to become unstable or crash. I'm a C/C++ guy and I am not totally familiar with Delphi (but I learned Pascal on Borland’s Turbo Pascal). It looks to me like you are passing a pointer to sh_IconPos. This pointer will not be valid inside the explorer.exe process space. As a result, explorer.exe could (and probably will) corrupt itself. You need to allocate memory inside explorer.exe and then pass a pointer to that. When the call to ListView_GetItemPosition (or the direct SendMessage call) is done, you can then read the point back using ReadProcessMemory. How is this feat of remote process memory allocation done? A call to the Win32 function VirtualAllocEx. This requires a more work, since you have to open the process, but I believe it is safe. Sorry Madshi, but I don’t believe in holding back information to ensure people will pay for/use my library. If you are interested in more detail, let me know.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 6
  • 6
  • 4
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now