?
Solved

Desktop icons' layout location.

Posted on 2003-03-09
17
Medium Priority
?
1,417 Views
Last Modified: 2012-06-22

   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
Comment
Question by:ivan_llanas
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 6
  • 4
  • +1
17 Comments
 
LVL 6

Expert Comment

by:DaFox
ID: 8099412
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
 

Author Comment

by:ivan_llanas
ID: 8099725

  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
 
LVL 20

Expert Comment

by:Madshi
ID: 8101179
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
Independent Software Vendors: 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!

 

Author Comment

by:ivan_llanas
ID: 8103260

   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
 
LVL 20

Expert Comment

by:Madshi
ID: 8103293
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
 

Author Comment

by:ivan_llanas
ID: 8103640

>>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
 
LVL 20

Expert Comment

by:Madshi
ID: 8103745
>> 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
 

Author Comment

by:ivan_llanas
ID: 8103999

   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
 
LVL 20

Accepted Solution

by:
Madshi earned 900 total points
ID: 8109224
>> 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
 
LVL 6

Expert Comment

by:DaFox
ID: 8109579
> ... 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
 
LVL 20

Expert Comment

by:Madshi
ID: 8109634
>> 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
 
LVL 6

Expert Comment

by:DaFox
ID: 8109668
> 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
 
LVL 20

Expert Comment

by:Madshi
ID: 8109679
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
 
LVL 6

Expert Comment

by:DaFox
ID: 8109770
Sure, thanks! ;-)
If Ivan doesn't give you the points (but I don't think so), I will...

Markus
0
 

Author Comment

by:ivan_llanas
ID: 8113395

>> 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
 

Author Comment

by:ivan_llanas
ID: 8113468

>> 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
 

Expert Comment

by:MassiveD
ID: 9990100
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

Independent Software Vendors: 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!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Suggested Courses

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question