Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

SysListView32

Posted on 1999-07-07
36
Medium Priority
?
469 Views
Last Modified: 2010-05-18
I am trying to receive the icons position on Windows 95/98 desktop.
I can move them. but I cant get the position. What am I doing wrong?
I am using this code:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  CommCtrl, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  P: Tpoint;

implementation

{$R *.DFM}
Function GetDesktopListViewHandle: THandle;
Var
  S: String;
Begin
        Result:= FindWindow('ProgMan', Nil);
       Result:= GetWindow(Result, GW_CHILD);
       Result:= GetWindow(Result, GW_CHILD);
       SetLength(S, 40);
       GetClassName(Result, PChar(S), 39);
       If PChar(S) <> 'SysListView32' Then Result:= 0;
End;

// Move icon on Win 95 desktop. This works.
procedure TForm1.Button1Click(Sender: TObject);
begin
      ListView_SetItemPosition(GetDesktopListViewHandle,0,10,10);
end;

// Get the icon position on Win 95 desktop. This don't work, Why?
procedure TForm1.Button2Click(Sender: TObject);
Var
      Ok: Boolean;
begin
      Ok:= ListView_GetItemPosition(GetDesktopListViewHandle,0,P);
      If Ok Then
        Label3.Caption:= 'Ok'
  Else
        Label3.Caption:= 'Error';
  // Returns Ok (True)

  Label1.Caption:=IntToStr(P.X);
  // Returns 0 Why ?
      Label2.Caption:=IntToStr(P.Y);
  // Returns 0 Why ?
end;

end.
0
Comment
Question by:mappemuppe
[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
  • 13
  • 10
  • 6
  • +2
36 Comments
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387011
Ok:= ListView_GetItemPosition(GetDesktopListViewHandle,0,@P);

Does that help?

Epsylon.

0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387012
Well, that must be it. Please grade me an 'A' for maximum points (4 x 600) if it works, otherwise reject the answer

Cheers,

Epsylon.
0
 

Author Comment

by:mappemuppe
ID: 1387013
You most think of SendMessage(hWndLV, LVM_GETITEMPOSITION, i, Longint(@ppt)) but that doesn't work either

Is there a bug in my Delphi 3?
0
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.

 

Author Comment

by:mappemuppe
ID: 1387014
Adjusted points to 610
0
 
LVL 2

Expert Comment

by:rene100
ID: 1387015
hi map...

all you have to do is declaring the P-var local, i.e. in TForm1.Button2Click, the it should work.

regards
rene
0
 
LVL 2

Expert Comment

by:rene100
ID: 1387016
sorry, i'm wrong... that doesn't work either...:-(
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387017
It works when I create a ListView in the apps itself and then use ListView1.Handle instead of GetDesktopListViewHandle, so the problem must be somewhere else I think....
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387018
Hi guys, I know the problem. But you won't like it!
We're talking about messages that go from one app to another app. A pointer that is valid in our app is NOT valid in the explorer's app, since each and every process has its own address/memory context from $00000000-$FFFFFFFF. That means, SetPosition works, because we transport two 32bit values, but GetPosition does NOT work, because we transport a pointer.
Now perhaps you wonder, why WM_GETTEXT works. Microsoft uses memory mapped files to make WM_GETTEXT work even between different apps. But they didn't implement the same stuff for image list messages. So forget about it!!
Of course there is a solution for everything! But it's just not so nice...
You can write a quite little dll that does not much more than being loaded in the explorer's address/memory context, call GetPosition THERE and then transport the position via WM_COPYDATA or via memory mapped files. If you have a bit time, I'll write this dll this weekend for you.
If you want to do it yourself, simply call SetWindowsHookEx with the thread id of the listView handle (GetWindowThreadProcessID). This way you can easily inject your dll in the explorer's address/memory context.

Regards, Madshi.
0
 
LVL 20

Accepted Solution

by:
Madshi earned 2440 total points
ID: 1387019
Well, I'm sure about my comment, so I'll lock this question...   :-)
If you have questions about my comment, please ask...
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387020
Well that's typical Microsoft. Shoot the bastards   :o)
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387021
:-)  Well, yes, that's what I think quite often, too...  :-)
0
 

Author Comment

by:mappemuppe
ID: 1387022
Thank you for your answer.
 
I wood be very glad if you wood write the dll for me.

Regards

Mappemuppe.

(Sorry for my poor English)

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387023
Hi Mappemuppe,

no problem with your English...  :-)

Hey, and thanx for your trust...  :-)

Normally you should accept an answer if you have the ready solution and tested it fully. But of course I've no problem if you trust me...

Please tell me your Delphi version. I'll post the solution Friday, Saturday or Sunday here. Don't know yet when exactly.

Regards, Madshi.
0
 

Author Comment

by:mappemuppe
ID: 1387024
Hi madshi

I am using Delphi 3
It is the first time I am using expert exchange. And I am impresst over your quick response.

Regards

Mappemuppe :-)


0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387025
Hi Mappemuppe,

we've so many good experts here, that you normally can rely on a very fast answer...   :-)
So if you have difficult questions again: This is the right place to ask!

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387026
Well, I got it ready already today. So here it comes. Enjoy!!!   :-))

// "hook.dpr" - DLL project

library hook;

uses windows, messages, commctrl;

{$ifndef ver120} type cardinal = integer; {$endif}

function HookMessageProc(code, wParam, lParam: integer) : integer; stdcall;
begin
  result:=0;
end;

exports HookMessageProc;

type TDesktopItems  = record
                        itemCount : integer;
                        items     : array [0..$FFFE] of record
                                      pos  : TPoint;
                                      name : array [0..MAX_PATH] of char;
                                    end;
                      end;
     TPDesktopItems = ^TDesktopItems;

var fm  : cardinal;
    pdi : TPDesktopItems;
    lv  : cardinal;
    i1  : integer;
    lvi : TLVItem;
    ev  : cardinal;
begin
  lv:=FindWindowEx(FindWindowEx(FindWindow('Progman','Program Manager'),0,'SHELLDLL_DefView',''),0,'SysListView32','');
  if (lv<>0) and (GetCurrentThreadID=GetWindowThreadProcessID(lv,nil)) then begin
    fm:=OpenFileMapping(FILE_MAP_ALL_ACCESS,false,'mappedMemoryForDesktopIcons');
    if fm<>0 then
      try
        pdi:=MapViewOfFile(fm,FILE_MAP_ALL_ACCESS,0,0,0);
        if pdi<>nil then
          try
            with pdi^ do begin
              i1:=SendMessage(lv,LVM_GETITEMCOUNT,0,0);
              if i1<itemCount then itemCount:=i1;
              zeroMemory(@lvi,sizeOf(TLVItem));
              for i1:=0 to itemCount-1 do begin
                SendMessage(lv,LVM_GETITEMPOSITION,i1,integer(@items[i1].pos));
                with lvi do begin mask:=LVIF_TEXT; iSubItem:=0; pszText:=items[i1].name; cchTextMax:=MAX_PATH end;
                items[i1].name[SendMessage(lv,LVM_GETITEMTEXT,i1,integer(@lvi))]:=#0;
              end;
            end;
          finally UnMapViewOfFile(pdi) end;
      finally CloseHandle(fm) end;
    ev:=OpenEvent(EVENT_ALL_ACCESS,false,'eventForDesktopIcons');
    if ev<>0 then
      try
        SetEvent(ev);
      finally CloseHandle(ev) end;
  end;
end.

// "desktopItems.pas" - the main unit

unit desktopItems;

interface

uses Windows, Messages, SysUtils, CommCtrl;

type IDesktopItems = interface ['{AD828DE0-3570-11D3-A52D-00005A180D69}']
                       function  ItemCount   : integer;
                       function  GetPosition (index: integer) : TPoint;
                       property  Position    [index: integer] : TPoint read GetPosition;
                       function  GetName     (index: integer) : string;
                       property  Name        [index: integer] : string read GetName;
                       procedure Refresh;
                     end;

function GetDesktopItems : IDesktopItems;

implementation

{$ifndef ver120} type cardinal = integer; {$endif}

type TDesktopItem   = record
                        pos  : TPoint;
                        name : array [0..MAX_PATH] of char;
                      end;
     TDesktopItems  = record
                        itemCount : integer;
                        items     : array [0..$FFFE] of TDesktopItem;
                      end;
     TPDesktopItems = ^TDesktopItems;
     TIDesktopItems = class (TInterfacedObject, IDesktopItems)
                      private
                        FFileMapping   : cardinal;
                        FPDesktopItems : TPDesktopItems;
                        constructor Create;
                        destructor Destroy; override;
                        function  ItemCount   : integer;
                        function  GetPosition (index: integer) : TPoint;
                        function  GetName     (index: integer) : string;
                        procedure Refresh;
                      end;

constructor TIDesktopItems.Create;
begin
  inherited;
  Refresh;
end;

destructor TIDesktopItems.Destroy;
begin
  if FPDesktopItems<>nil then UnMapViewOfFile(FPDesktopItems);
  if FFileMapping  <>0   then CloseHandle    (FFileMapping  );
  inherited;
end;

function TIDesktopItems.ItemCount : integer;
begin
  result:=FPDesktopItems^.itemCount;
end;

function TIDesktopItems.GetPosition(index: integer) : TPoint;
begin
  if (index<0) or (index>=FPDesktopItems^.itemCount) then
    raise Exception.Create('Index out of range.');
  result:=FPDesktopItems^.items[index].pos;
end;

function TIDesktopItems.GetName(index: integer) : string;
begin
  if (index<0) or (index>=FPDesktopItems^.itemCount) then
    raise Exception.Create('Index out of range.');
  result:=FPDesktopItems^.items[index].name;
end;

procedure TIDesktopItems.Refresh;
var lv   : cardinal;
    ic   : integer;
    dll  : cardinal;
    hook : cardinal;
    ev   : cardinal;
begin
  if FPDesktopItems<>nil then UnMapViewOfFile(FPDesktopItems);
  if FFileMapping  <>0   then CloseHandle    (FFileMapping  );
  lv:=FindWindowEx(FindWindowEx(FindWindow('Progman','Program Manager'),0,'SHELLDLL_DefView',''),0,'SysListView32','');
  if lv<>0 then ic:=SendMessage(lv,LVM_GETITEMCOUNT,0,0) else ic:=0;
  FFileMapping:=CreateFileMapping(cardinal(-1),nil,PAGE_READWRITE,0,4+ic*sizeOf(TDesktopItem),'mappedMemoryForDesktopIcons');
  if FFileMapping<>0 then begin
    FPDesktopItems:=MapViewOfFile(FFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);
    FPDesktopItems^.itemCount:=ic;
    dll:=LoadLibrary(pchar(ExtractFilePath(ParamStr(0))+'hook.dll'));
    if dll<>0 then
      try
        ev:=CreateEvent(nil,true,false,'eventForDesktopIcons');
        if ev<>0 then
          try
            hook:=SetWindowsHookEx(WH_GETMESSAGE,GetProcAddress(dll,'HookMessageProc'),dll,GetWindowThreadProcessID(lv,nil));
            if hook<>0 then
              try
                PostThreadMessage(GetWindowThreadProcessID(lv,nil),WM_NULL,0,0);
                WaitForSingleObject(ev,2000);
              finally UnhookWindowsHookEx(hook) end;
          finally CloseHandle(ev) end;
      finally FreeLibrary(dll) end;
  end else FPDesktopItems:=nil;
end;

function GetDesktopItems : IDesktopItems;
begin
  result:=TIDesktopItems.Create;
end;

end.

// "testDesktopItems.dpr" - application test project

program testDesktopItems;

uses Windows,
     SysUtils,
     desktopItems in 'desktopItems.pas';

procedure testDesktopItemsUnit;
var i1 : integer;
    s1 : string;
begin
  with GetDesktopItems do
    for i1:=0 to ItemCount-1 do
      s1:=s1+IntToStr(Position[i1].x)+'/'+IntToStr(Position[i1].y)+': "'+Name[i1]+'"'#$D#$A;
  MessageBox(0,pchar(s1),'Desktop Icons',0);
end;

begin
  testDesktopItemsUnit;
end.

Regards, Madshi.

P.S: It compiles and runs fine on my win98 computer with D3 and D4. If you have any problems, ask me...
0
 
LVL 2

Expert Comment

by:CalvinDay
ID: 1387027
I had 62 points and I paid 61 see the answer. Very NICE WORK!
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387028
Thanx...   :-)))
0
 

Author Comment

by:mappemuppe
ID: 1387029
Hi Madshi
I got your code and I will tjeck  et out, and let you now.

Regards
Mappemuppe :-)

0
 

Author Comment

by:mappemuppe
ID: 1387030
Hi Madshi

I have just tested your code it works fine!
You truly deserved the "A" and all the points I gave you. Please tell me how to give you credit, if my project ever becomes a reality.

Regards and thanks

mappemuppe.

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387031
Hi mappemuppe,

Thank you for the compliment. Well, I've planned to write such a DLL anyway this weekend. So it was a funny coincidence, that your question came exactly this week...   :-)

If you really want to give me credit, you could add a note like "Thanks to Mathias Rauen ("madshi@gmx.net" - "http://beam.to/madshi") for helping me finishing this project." to your documention/help file/whatever...  :-))
Is this what you meant with giving credit or did you mean something different?

Hmm. What's the purpose of your project, if I may ask?

Thnx.

Regards, Madshi.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387032
Well done, Madshi  :o)

Your code looks unreadable but that doesn't matter when it works. Great job!


Cheers!
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387033
Thanx Eps...  :-)

Well, I always write much code in each line, because I want to see as much code as possible without having to scroll all the time. Perhaps I should buy a 19" monitor...   :-))

But the code looks a bit better in the Delphi editor (with monospace font) than here on EE.

Regards, Madshi.
0
 
LVL 2

Expert Comment

by:CalvinDay
ID: 1387034
With so much code on each line, I thought you were an old C programmer.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387035
No, I hate C. I'm coming from Modula-2 and TP..   :-)
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387036
Used languages:

1985-1989: Commodore 64: basic
1986-1989: Commodure 64: assembler (forgot cpu number)
1989-1995: Amiga: Amiga Basic, M68000 assembler and ARexx
1990-1996: Amiga: C
1993-1996: Amiga: C++
1991-1993: Unix: C and shl
1992-1996: Turbo Pascal hated that
1994-1997: Borland C++
1996-2000: Delphi
1997-2000: HTML and JavaScript (Little bit Perl)

And whatever I may have forgotten.

Ah yes, I have been programming on the Mac emulator for the Amiga  :o)

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387037
Do you write diaries?    :O)
0
 
LVL 2

Expert Comment

by:CalvinDay
ID: 1387038
No, but I did Borland C and C++ number too. I used to love C++. But after Delphi, there's no way I go back.

I programmed in Fortran using Amadal and Data General, and in Basic on the Wang and the early IBM series 5110, 5120 and S23. We used the keypunch and teletype machines with cards and hole punch tape. You could tell how big a program was by the size of your stack or roll.

I started programming 1971 with a dial up teletype to University of Houston. Wasn't near as much fun as it is now.
0
 
LVL 2

Expert Comment

by:CalvinDay
ID: 1387039
Sorry Epsylon, I thought Madshi asked me? I see Madshi hates C and you have done some.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387040
I just have a very good memory, particular for numbers. And I mean that.

I forgot:
- AutoLisp (ACAD) in 1993: that was a real challenge  :o)   I graduated on that.
- C and Pascal on PR1ME mainframe systems (1989-1993). Those systems had harddrives as big as coffins and sounded like a Boing 747.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387041
Well, I hate C, nevertheless I did some things with it (e.g. writing a NLM for Novell). It's quite sad, that we can't develop device drivers with Delphi yet...
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387042
I think I'll have a go with your WinObj, Madshi.
0
 
LVL 2

Expert Comment

by:CalvinDay
ID: 1387043
Epsylon - That's when you had a computer room; raised floors, etc. You didn't use Primus (SQL on the Prime I think)

Madshi - I attemped a Print Driver for 98. Couldn't get it to work. I had to use Delphi 1.0 (16 bit) The translation of the .h to .pas was real hairy. A bet you could have done it.
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387044
NO I did some X.25 stuff.....
0
 
LVL 13

Expert Comment

by:Epsylon
ID: 1387045
Does anyone want such a PR1ME system? I know 1. You can come and get it for free  :o)
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1387046
Hi CalvinDay, well, I'm not too experiences with translating *.h files. I guess, Eps would be much better at that job...  :-)

Eps, please tell me, if you have any problems with or suggestions for winObj...  :O)

Regards, Madshi.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This course is ideal for IT System Administrators working with VMware vSphere and its associated products in their company infrastructure. This course teaches you how to install and maintain this virtualization technology to store data, prevent vuln…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

670 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