Question

Accessing items in a TreeView of an external application

Asked by: Sebastion

Hi,

I've already had a look at http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_20272830.html, http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_20593454.html, though the links in there don't work (eg MadRemote, etc).  Also what's thrown me is http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_23524965.html whereby it seems someone was able to get this working with the existing "TreeView_GetSelection" function in CommCtrl.

I've probably gotten ahead of myself here abit, so first some information.  We have a application here and what I'm doing at the moment is writing an application that will just stress test it.  By this I mean it'll simulate a user going through it and repeating various actions in rapid succession, usually for hours on end (all the while keeping logs of everything which is happening).  

Reading various data like listboxes and text boxes is easily done already, as with the various navigations (the program knows what screen the system is currently on and re-acts accordingly), and the only thing holding me up at the moment is a TreeView who's contents change depending on the options set up and data in the database.  I've already made it possible for the program to choose an option in there, but for record purposes (and also to know how to react afterwards) I need to determine what option it's selected.

The program is able to already gather the hwnd of the window with the treeview, as well as drill down through the child components until it actually reaches the treeview itself.  I've also managed to get the number of items in the list via TVM_GETCOUNT, but when I try to get the actual selected item via either TVM_GETITEM or TreeView_GetItem I always get a null string and a failure bool .

I've only given the question 125 points because I have this feeling I'm going to be told that it isn't possible with the existing routines in CommCtrl (though it does make me ask the question of why those routines exist) and thus it's probably an open and shut case, but if it is possible then I'll up the points to 500.

I've added my two functions to the code section.  If anyone can give some insight it'd be greatly appreciated.

function GetSelectedTreeItem(HwndTree) : String;
var
  pitem: TTVItem;
begin
  try
    result := '';
    pitem.hItem := TreeView_GetSelection(HwndTree);
    pitem.mask := TVIF_TEXT;
    pitem.cchTextMax := 255;
    if TreeView_GetItem(HwndTree, pitem) then
      UpdateLog('Successfull GetItem')
     else
       UpdateLog('Unsuccessful GetItem');
     //SendMessage(HwndPOSChild, TVM_GETITEM, 0, longint(@pitem));
    Result:=pitem.pszText;
    //result := TreeView_GetSelection(HwndPOSChild);
  except
    result := '';
  end;
end;
 
function GetSelectedTreeItemV2(HwndTree) : String;
var
  TreeItem: TV_ITEM;
  TreeText: array [0 .. 255] of Char;
begin
  try
    FillChar(TreeItem, SizeOf(TreeItem), 0);
    result := '';
    TreeText := '';
    with TreeItem do
       begin
       mask := TVIF_TEXT or TVIF_HANDLE;
       hItem := TreeView_GetSelection(HwndTree);
       pszText := @TreeText;
       cchTextMax := 255;
      end;
    if (TreeView_GetItem(HwndTree, TreeItem)) then
      UpdateLog('Successfull GetItem')
    else
      UpdateLog('Unsuccessful GetItem');
    //SendMessage(HwndPOSChild, TVM_GETITEM, 0, longint(@TreeItem));
    Result:=TreeText;
  except
    result := '';
  end;
end;

                                  
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:

Select allOpen in new window

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2009-03-27 at 00:25:54ID24270236
Tags

Treeview external

Topic

Delphi Programming

Participating Experts
2
Points
500
Comments
14

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. Pascal?
    What is Pascal, is it a relative to C
  2. Delphi and Turbo Pascal
    What are the major differences between Delphi and Turbo Pascal?
  3. Pascal Units In Delphi!?
    Is it possible to use the procedures and functions of a pascal unit in Delphi? I know that it's not directly possible, but may be you have some idea about some indirect way, for example creating a dll file with Pascal and then call the dll from Delphi! Is this possible? If y...
  4. External TreeView using madRemote
    Hi all, I have followed another thread http://search.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20272830.html to its logical conclusion by madshi, and have realised this is where I am falling over. I am trying to read the nodes of an external systreevie...
  5. Sending/Receiving messages from an *external* TreeView
    Hi, I've asked this question previously without getting any answer. I'm now increasing the points in one last attempt to achieve this... :o) I need some code to perform this task. I know how to find the Handle to the external control with EnumWindowsProc and EnumChildProc, ...

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: Geert_GruwezPosted on 2009-03-27 at 00:30:55ID: 23998624

what if there is no item selected ?
i suppose you select an item and that works ?

 

by: SebastionPosted on 2009-03-27 at 16:57:24ID: 24006476

I imagine if no item is selected then it'll return an empty string, but I've selected an item in the treeview and it still doesn't work.  I've even made the program select a random item in there via sending the up and down keys, but it still doesn't return the string of the highlighted item.

 

by: SebastionPosted on 2009-03-30 at 17:22:39ID: 24024751

I'm increasing the points on this since I haven't heard anything yet, which may mean that it might not be as simple as "not possible" (hopefully).

 

by: Geert_GruwezPosted on 2009-03-31 at 05:17:37ID: 24028007

why not convert the handle to a X: TTreeview first and then just use X.Selected.Text ???

uses CommCtrl, StrUtils;
 
function GetTreeView(aHandle: THandle): TTreeView;
var
  Item: TTVItem;
  ItemId: HTreeItem;
begin
  Result := nil;
  ItemId := TreeView_GetRoot(aHandle);
  with Item do
  begin
    hItem := ItemId;
    mask := TVIF_PARAM;
  end;
  if TreeView_GetItem(aHandle, Item) then
    Result := TTreeView(TTreeNode(Item.lParam).TreeView);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var X: TTreeView;
begin
  X := GetTreeView(TreeView1.Handle);
  ShowMessage(IfThen(X.Selected <> nil, X.Selected.Text, 'nothing selected'));
end;

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:

Select allOpen in new window

 

by: SebastionPosted on 2009-03-31 at 18:17:53ID: 24035293

Hi Geert,

I've tried your code but the "TreeView_GetItem" still fails and as a result the resulting TTreeView is null.  I've attached my code below.  Did the above code work for you?  I'm just wondering if something might be wrong with how I'm doing it if it is indeed possible to get the selected item in an external app.

function GetSelectedTreeItemV3(HwndTree) : TTreeView;
var
  TreeItem: TTVItem;
  ItemId: HTreeItem;
begin
  try
    FillChar(TreeItem, SizeOf(TreeItem), 0);
    result := nil;
    ItemId := TreeView_GetRoot(HwndTree);
    with TreeItem do
       begin
       mask := TVIF_PARAM;
       hItem := ItemId;
      end;
    if (TreeView_GetItem(HwndTree, TreeItem)) then
      begin
      UpdateLog('Successfull GetItem');
      result := TTreeView(TTreeNode(TreeItem.lParam).TreeView);
      end;
    else
      UpdateLog('Unsuccessful GetItem');
  except
    result := nil;
  end;
end;

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:

Select allOpen in new window

 

by: rllibbyPosted on 2009-03-31 at 21:18:01ID: 24035928

If I understand you correctly, your trying to get the treeview item in another process (not the same as the calling process). If thats true, then what you have will fail as the process memory spaces are not the same (memory in process 1 is not the same as memory in process 2).

But, what you want is do-able as long as you are able to allocate memory in the process space of the other process. I created a wrapper class that allows you to do this fairly easily, which can be downloaded from:

http://home.roadrunner.com/~rllibby/downloads/processmemory.zip

I will post up an example of using it to get an external tree item in the morning. One thing to keep in mind though is that some of your code, such as:

result := TTreeView(TTreeNode(TreeItem.lParam).TreeView);

will not fly. You can't cast the external treeview and expect to do anything with it, as the Delphi VCL code will fail for the same reasons you code currently fails... memory space between processes. But you will be able to call any of the TreeView_{functions} that you need.

Regards,
Russell






 


 

by: Geert_GruwezPosted on 2009-03-31 at 23:54:21ID: 24036522

i only tested it within the same project using the windows handle of the treeview
i wasn't aware of these memory issues
thx Russel for the intel

 

by: rllibbyPosted on 2009-04-01 at 07:40:15ID: 24039619

Source for example first, then dfm

--- source ---
unit Unit1;

interface

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

type
  TForm1            =  class(TForm)
     lblTree:       TLabel;
     txtHwnd:       TEdit;
     tvLocal:       TTreeView;
     btnLoad:       TButton;
     btnCancel:     TButton;
     procedure      btnLoadClick(Sender: TObject);
     procedure      btnCancelClick(Sender: TObject);
  private
     // Private declarations
     FTreeMem:      TProcessMemory;
     FItem:         TProcessMemoryItem;
     FText:         TProcessMemoryItem;
     FCancel:       Boolean;
  public
     // Public declarations
     function       TreeItemHasChildren(hwndTree: HWND; RemoteNode: HTREEITEM): Boolean;
     function       TreeItemText(hwndTree: HWND; RemoteNode: HTREEITEM): String;
     procedure      LoadTreeItem(hwndTree: HWND; ParentNode: TTreeNode; RemoteParentNode, RemoteNode: HTREEITEM);
  end;

const
  TV_TEXTMAX        =  1024;

var
  Form1:            TForm1;

implementation
{$R *.DFM}

procedure TForm1.LoadTreeItem(hwndTree: HWND; ParentNode: TTreeNode; RemoteParentNode, RemoteNode: HTREEITEM);
var  tvNode:        TTreeNode;
     htiChild:      HTREEITEM;
begin

  // Check remote node
  if Assigned(RemoteNode) then
  begin
     // Process messages
     Application.ProcessMessages;
     // Check cancel
     if FCancel then exit;
     // Add local tree item
     tvNode:=tvLocal.Items.AddChild(ParentNode, TreeItemText(hwndTree, RemoteNode));
     // Determine if the tree item has children
     if (TreeItemHasChildren(hwndTree, RemoteNode)) then
     begin
        // Process messages
        Application.ProcessMessages;
        // Get first child
        htiChild:=TreeView_GetChild(hwndTree, RemoteNode);
        // Load the children
        while Assigned(htiChild) do
        begin
           // Allow cancel
           if FCancel then break;
           // Load the child
           LoadTreeItem(hwndTree, tvNode, RemoteNode, htiChild);
           // Get next sibling
           htiChild:=TreeView_GetNextSibling(hwndTree, htiChild);
        end;
     end;
  end;

end;

function TForm1.TreeItemHasChildren(hwndTree: HWND; RemoteNode: HTREEITEM): Boolean;
var  tvItem:        TV_ITEM;
begin

  // Default result
  result:=False;

  // Check remote node
  if Assigned(RemoteNode) then
  begin
     // Clear local struct
     FillChar(tvItem, SizeOf(TV_ITEM), 0);
     // Set mask for what we want
     tvItem.mask:=TVIF_HANDLE or TVIF_CHILDREN;
     // Set handle
     tvItem.hItem:=RemoteNode;
     // Now copy local data to remote memory
     FItem.Write(tvItem, SizeOf(TV_ITEM));
     // Make the call
     if (SendMessage(hwndTree, TVM_GETITEM, 0, Integer(FItem.Memory)) <> 0) then
     begin
        // Copy the remote data back to local space
        Move(FItem.LocalMemory^, tvItem, SizeOf(TV_ITEM));
        // Now check the cChildren field of the struct (we wont deal with callbacks for child nodes)
        result:=(tvItem.cChildren = 1);
     end;
  end;

end;

function TForm1.TreeItemText(hwndTree: HWND; RemoteNode: HTREEITEM): String;
var  tvItem:        TV_ITEM;
begin

  // Default result
  result:='< Failure >';

  // Check remote node
  if Assigned(RemoteNode) then
  begin
     // Clear local struct
     FillChar(tvItem, SizeOf(TV_ITEM), 0);
     // Set mask for what we want
     tvItem.mask:=TVIF_HANDLE or TVIF_TEXT;
     // Set handle
     tvItem.hItem:=RemoteNode;
     // Set remote text pointer
     tvItem.pszText:=FText.Memory;
     tvItem.cchTextMax:=TV_TEXTMAX;
     // Now copy local data to remote memory
     FItem.Write(tvItem, SizeOf(TV_ITEM));
     // Make the call
     if (SendMessage(hwndTree, TVM_GETITEM, 0, Integer(FItem.Memory)) <> 0) then
     begin
        // We now need to get the string data which has been filled in on the remote side
        SetString(result, PChar(FText.LocalMemory), StrLen(FText.LocalMemory));
     end;
  end;

end;

procedure TForm1.btnLoadClick(Sender: TObject);
var  hwndTree:      HWND;
     htiRoot:       HTREEITEM;
     htiNext:       HTREEITEM;
begin

  // Lock the tree
  tvLocal.Items.BeginUpdate;

  // Resource protection
  try
     // Clear items
     tvLocal.Items.Clear;
     // Convert string to window handle
     hwndTree:=StrToIntDef(txtHwnd.Text, 0);
     // Check window
     if IsWindow(hwndTree) then
     begin
        // Attempt to get the root item
        htiRoot:=TreeView_GetRoot(hwndTree);
        // Check the root
        if Assigned(htiRoot) then
        begin
           // Create remote memory handler
           FTreeMem:=TProcessMemory.CreateFromHwnd(hwndTree);
           // Resource protection
           try
              // Allocate remote memory for getting tree item data
              FItem:=FTreeMem[FTreeMem.Add(SizeOf(TV_ITEM))];
              // Allocate remote memory for getting tree item text
              FText:=FTreeMem[FTreeMem.Add(TV_TEXTMAX)];
              // Set cancel state
              FCancel:=False;
              // Seed load
              htiNext:=htiRoot;
              // While next
              while Assigned(htiNext) do
              begin
                 // Recursively load the tree items
                 LoadTreeItem(hwndTree, nil, nil, htiRoot);
                 // Get next
                 htiNext:=TreeView_GetNextSibling(hwndTree, htiNext);
              end;
           finally
              // Free and nil
              FreeAndNil(FTreeMem);
           end;
        end
        else
           // Failed to get root
           tvLocal.Items.Add(nil, '< Failed to get the root item >');
     end
     else
        // Not a valid window
        tvLocal.Items.Add(nil, '< Not a valid window handle >');
  finally
     // Unlock the tree
     tvLocal.Items.EndUpdate;
  end;

end;

procedure TForm1.btnCancelClick(Sender: TObject);
begin

  // Set cancel state
  FCancel:=True;

end;

end.

--- dfm ---
object Form1: TForm1
  Left = 336
  Top = 264
  BorderIcons = [biSystemMenu, biMinimize]
  BorderStyle = bsDialog
  Caption = 'Process Memory Demo'
  ClientHeight = 385
  ClientWidth = 330
  Color = clBtnFace
  Font.Charset = ANSI_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Verdana'
  Font.Style = []
  OldCreateOrder = False
  Position = poScreenCenter
  Scaled = False
  PixelsPerInch = 96
  TextHeight = 13
  object lblTree: TLabel
    Left = 8
    Top = 16
    Width = 101
    Height = 13
    Caption = 'TreeView Handle:'
  end
  object btnLoad: TButton
    Left = 160
    Top = 348
    Width = 77
    Height = 25
    Caption = 'Load'
    TabOrder = 0
    OnClick = btnLoadClick
  end
  object txtHwnd: TEdit
    Left = 120
    Top = 12
    Width = 197
    Height = 21
    TabOrder = 1
  end
  object tvLocal: TTreeView
    Left = 8
    Top = 44
    Width = 309
    Height = 293
    Indent = 19
    TabOrder = 2
  end
  object btnCancel: TButton
    Left = 240
    Top = 348
    Width = 77
    Height = 25
    Caption = 'Cancel'
    TabOrder = 3
    OnClick = btnCancelClick
  end
end

 

by: SebastionPosted on 2009-04-01 at 19:43:04ID: 24045948

Hi Russell,

I tried to merge your code into mine but no luck (I'll sort it out later), so I instead created a new project and things seemed to have partially worked except the resulting TTreeView in the local app only has the first item from the remote tree view, and it's listed it 10 times (which is the same amount of non-expanded tree view items in the remote one).  To probably give a better explanation I'll give abit of a visual:

RemoteTreeView:

Item1
Item2
Item3
Item4
Item5
Item6
Item7
Item8
Item9
Item10

LocalTreeView:
Item1
Item1
Item1
Item1
Item1
Item1
Item1
Item1
Item1
Item1

The code I used was an exact replicate of yours, except instead of using a text box for the window ID I used a procedure to find the remote TTreeView (which must have succeeded to get the correct string for Item1).

 

by: SebastionPosted on 2009-04-01 at 19:48:40ID: 24045973

Just to clarify something to, does the selected item remain intact when bringing it over?  Also, with the above examples even though there are 10 items in the treeview listed down, some are just category headers (ie they have some sub-items below them:

RemoteTreeView:

Item1
Item2
Item3
  Item3.1
  Item3.2
  Item3.3
Item4
Item5
Item6
Item7
Item8
  Item8.1
Item9
Item10

Using TreeView_GetCount does get the correct count of tree items (14 in the above example).

 

by: rllibbyPosted on 2009-04-01 at 20:10:14ID: 24046068


Not sure why your getting the results you get (without seeing your code), but my example wasn't really the point of the question. Your question was in regards to getting treeview information from a remote tree (across memory spaces), which is what I tried to address.

In regards to the question:
> Just to clarify something to, does the selected item remain intact when bringing it over? <

Getting TVM_GETITEM item info does not change the selection.

 

by: SebastionPosted on 2009-04-02 at 21:26:23ID: 24056642

Here's the code of the program I've created.  

First, here's a picture of the sample tree view program which has just has a form, a panel and a tree view (the panel is there because my main application has a panel, so hierarchically it remains the same) (http://img18.imageshack.us/img18/7553/sampletreeview.jpg).  This program has no real code except for the defaults which delphi puts in.  The items were added visually.  The form caption is "TreeViewTest"

The code below is the program I use to get the contents of this program.  It's very similar to the code you gave above except it doesn't have the option to cancel, and I moved hwnd location to it's own function.  The results of this program can be seen at http://img17.imageshack.us/img17/327/treeviewapp.jpg

unit main;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, ProcessMemory, CommCtrl;
 
type
  TForm1 = class(TForm)
    tvLocal: TTreeView;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
     FTreeMem:      TProcessMemory;
     FItem:         TProcessMemoryItem;
     FText:         TProcessMemoryItem;
  public
    { Public declarations }
     function       TreeItemHasChildren(hwndTree: HWND; RemoteNode: HTREEITEM): Boolean;
     function       TreeItemText(hwndTree: HWND; RemoteNode: HTREEITEM): String;
     procedure      LoadTreeItem(hwndTree: HWND; ParentNode: TTreeNode; RemoteParentNode, RemoteNode: HTREEITEM);
     function GetHwnd: Hwnd;
  end;
 
const
  TV_TEXTMAX        =  1024;
 
var
  Form1: TForm1;  
  WindowList : TList;   
 
implementation
 
{$R *.dfm}
 
procedure InitiateWindowsList;
begin
  WindowList := TList.Create;
end;
 
procedure ClosewindowsList;
begin
  WindowList.Free;
end;
 
function GetWindow (Handle: HWND; LParam: longint): bool; stdcall;
begin
  Result := true;
  { add each handle to the list }
  WindowList.Add (Pointer(Handle));
end;
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  ClosewindowsList;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  InitiateWindowsList;
end;
 
procedure TForm1.LoadTreeItem(hwndTree: HWND; ParentNode: TTreeNode; RemoteParentNode, RemoteNode: HTREEITEM);
var  tvNode:        TTreeNode;
     htiChild:      HTREEITEM;
begin
 
  // Check remote node
  if Assigned(RemoteNode) then
  begin
     // Process messages
     Application.ProcessMessages;
     // Add local tree item
     tvNode:=tvLocal.Items.AddChild(ParentNode, TreeItemText(hwndTree, RemoteNode));
     // Determine if the tree item has children
     if (TreeItemHasChildren(hwndTree, RemoteNode)) then
     begin
        // Process messages
        Application.ProcessMessages;
        // Get first child
        htiChild:=TreeView_GetChild(hwndTree, RemoteNode);
        // Load the children
        while Assigned(htiChild) do
        begin
           // Load the child
           LoadTreeItem(hwndTree, tvNode, RemoteNode, htiChild);
           // Get next sibling
           htiChild:=TreeView_GetNextSibling(hwndTree, htiChild);
        end;
     end;
  end;
 
end;
 
function TForm1.TreeItemHasChildren(hwndTree: HWND; RemoteNode: HTREEITEM): Boolean;
var  tvItem:        TV_ITEM;
begin
 
  // Default result
  result:=False;
 
  // Check remote node
  if Assigned(RemoteNode) then
  begin
     // Clear local struct
     FillChar(tvItem, SizeOf(TV_ITEM), 0);
     // Set mask for what we want
     tvItem.mask:=TVIF_HANDLE or TVIF_CHILDREN;
     // Set handle
     tvItem.hItem:=RemoteNode;
     // Now copy local data to remote memory
     FItem.Write(tvItem, SizeOf(TV_ITEM));
     // Make the call
     if (SendMessage(hwndTree, TVM_GETITEM, 0, Integer(FItem.Memory)) <> 0) then
     begin
        // Copy the remote data back to local space
        Move(FItem.LocalMemory^, tvItem, SizeOf(TV_ITEM));
        // Now check the cChildren field of the struct (we wont deal with callbacks for child nodes)
        result:=(tvItem.cChildren = 1);
     end;
  end;
 
end;
 
function TForm1.TreeItemText(hwndTree: HWND; RemoteNode: HTREEITEM): String;
var  tvItem:        TV_ITEM;
begin
 
  // Default result
  result:='< Failure >';
 
  // Check remote node
  if Assigned(RemoteNode) then
  begin
     // Clear local struct
     FillChar(tvItem, SizeOf(TV_ITEM), 0);
     // Set mask for what we want
     tvItem.mask:=TVIF_HANDLE or TVIF_TEXT;
     // Set handle
     tvItem.hItem:=RemoteNode;
     // Set remote text pointer
     tvItem.pszText:=FText.Memory;
     tvItem.cchTextMax:=TV_TEXTMAX;
     // Now copy local data to remote memory
     FItem.Write(tvItem, SizeOf(TV_ITEM));
     // Make the call
     if (SendMessage(hwndTree, TVM_GETITEM, 0, Integer(FItem.Memory)) <> 0) then
     begin
        // We now need to get the string data which has been filled in on the remote side
        SetString(result, PChar(FText.LocalMemory), StrLen(FText.LocalMemory));
     end;
  end;
 
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  hwndTree:      HWND;
  htiRoot:       HTREEITEM;
  htiNext:       HTREEITEM;
begin
  hwndTree := GetHwnd;
  tvLocal.Items.BeginUpdate;
  // Resource protection
  try
     // Clear items
     tvLocal.Items.Clear;
     // Convert string to window handle
     //hwndTree:=StrToIntDef(txtHwnd.Text, 0);
     // Check window
     if IsWindow(hwndTree) then
     begin
        // Attempt to get the root item
        htiRoot:=TreeView_GetRoot(hwndTree);
        // Check the root
        if Assigned(htiRoot) then
        begin
           // Create remote memory handler
           FTreeMem:=TProcessMemory.CreateFromHwnd(hwndTree);
           // Resource protection
           try
              // Allocate remote memory for getting tree item data
              FItem:=FTreeMem[FTreeMem.Add(SizeOf(TV_ITEM))];
              // Allocate remote memory for getting tree item text
              FText:=FTreeMem[FTreeMem.Add(TV_TEXTMAX)];
              // Seed load
              htiNext:=htiRoot;
              // While next
              while Assigned(htiNext) do
              begin
                 // Recursively load the tree items
                 LoadTreeItem(hwndTree, nil, nil, htiRoot);
                 // Get next
                 htiNext:=TreeView_GetNextSibling(hwndTree, htiNext);
              end;
           finally
              // Free and nil
              FreeAndNil(FTreeMem);
           end;
        end
        else
           // Failed to get root
           tvLocal.Items.Add(nil, '< Failed to get the root item >');
     end
     else
        // Not a valid window
        tvLocal.Items.Add(nil, '< Not a valid window handle >');
  finally
     // Unlock the tree
     tvLocal.Items.EndUpdate;
  end;
 
end;
 
function TForm1.GetHwnd : Hwnd;
var
  HwndPOS, HwndPOSChild : HWND;
  Buffer: array [0..255] of char;
  i : Integer;
begin
  WindowList.Clear;
  EnumWindows (@GetWindow, 0);
  // Lock the tree
    for i := 0 to WindowList.Count - 1 do begin
      HwndPOS := HWND (WindowList [i]);
      if IsWindowVisible (HwndPOS) then begin
        GetWindowText (HwndPOS, Buffer, SizeOf (Buffer) - 1);
        if Buffer [0] <> #0 then //if not empty
          if StrPas(Buffer) = 'TreeViewTest' then
            begin
            HwndPOSChild := FindWindowEx(HwndPOS, 0, 'TPanel', nil);
            if HwndPOSChild > 0 then
              begin
              HwndPOSChild := FindWindowEx(HwndPOSChild, 0, 'TTreeView', nil);  //Media Tree
              if HwndPOSChild > 0 then
                begin
                result := HwndPOSChild;//we found our TTreeView;
                exit;
                end;
              end;
            end;
      end;
    end;
end;
 
end.

                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:

Select allOpen in new window

 

by: rllibbyPosted on 2009-04-03 at 06:28:07ID: 24059643

LoadTreeItem was passing hitRoot instead of htiNext:

           // Create remote memory handler
           FTreeMem:=TProcessMemory.CreateFromHwnd(hwndTree);
           // Resource protection
           try
              // Allocate remote memory for getting tree item data
              FItem:=FTreeMem[FTreeMem.Add(SizeOf(TV_ITEM))];
              // Allocate remote memory for getting tree item text
              FText:=FTreeMem[FTreeMem.Add(TV_TEXTMAX)];
              // Set cancel state
              FCancel:=False;
              // Seed load
              htiNext:=htiRoot;
              // While next
              while Assigned(htiNext) do
              begin
                 // Recursively load the tree items
                 LoadTreeItem(hwndTree, nil, nil, htiNext); // <---
                 // Get next
                 htiNext:=TreeView_GetNextSibling(hwndTree, htiNext);
              end;
           finally
              // Free and nil
              FreeAndNil(FTreeMem);
           end;

----

 

by: SebastionPosted on 2009-04-05 at 16:33:10ID: 24073453

Ah, that works better now.  Thanks for the help Russell.  I'm going to close this off as I have what I need.

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...