I can't get my head around pointers using a custom record and making array of records then a pointer to that record, specifically what I want to achieve is to make a record for each top level window handle with the given classname, meaning there is more than 1, for each window I use EnumChildWindow
to obtain handles to child windows with in. I wanted to make record of each of these and pass it to a combobox with title and make the record an object of that item so I can access each recorded later on via selecting it.
My problem is my handling of pointers, I keep getting access denied on the first instance of adding any to one of the array records.
Breaks here
Param[Form1.iEnumWin].MainHwnd:= aHwnd;
here is the full code I am using so people can get a better understanding on what I am trying to do.
implementation
{$R *.dfm}
type
TMyEnumParam = record
sTitle: String;
MainHwnd: Hwnd;
InTxtHwnd: Hwnd;
OutTxtHwnd: Hwnd;
NickListHwnd: Hwnd;
end;
PMyEnumParam = ^TMyEnumParam;
type
ATMyEnumParam = Array[0..9] of PMyEnumParam;
PATMyEnumParam = ^ATMyEnumParam;
{ Get the window Title based on Hwnd }
function GetWindowTitle(HWND: HWND): string;
begin
SetLength(Result, 255);
SetLength(Result, GetWindowText(HWND, PChar(Result), 255));
end;
{ Get the Classname based on Hwnd }
function GetWindowClass(HWND: HWND): string;
begin
SetLength(Result, 255);
SetLength(Result, GetClassName(HWND, PChar(Result), 255));
end;
{ EnumChildWidows Callback Add to our records }
Function EnumChildProc(aHwnd: Hwnd; Param: PMyEnumParam): Boolean; stdcall;
begin
if ((GetDlgCtrlID(aHwnd) = 202) and (isWindowVisible(aHwnd) = True)) then
Param.InTxtHwnd:= aHwnd;
if ((GetDlgCtrlID(aHwnd) = 203) and (isWindowVisible(aHwnd) = True)) then
Param.OutTxtHwnd:= aHwnd;
if ((GetDlgCtrlID(aHwnd) = 1789) and (isWindowVisible(aHwnd) = True)) then
Param.NickListHwnd:= aHwnd;
Result:= True;
end;
{ EnumWindow fill our array of records for each window }
function EnumWindowsProc(aHwnd: HWND; Param: PATMyEnumParam): BOOL; stdcall;
begin
Result := True;
if GetWindowClass(aHwnd) = 'DlgGroupChat Window Class' then
begin
Param[Form1.iEnumWin].MainHwnd:= aHwnd;
Param[Form1.iEnumWin].sTitle:= GetWindowTitle(aHwnd);
EnumChildWindows(aHwnd, @EnumChildProc, LParam(@Param[Form1.iEnumWin]));
Form1.cbbRooms.AddItem(Param[Form1.iEnumWin].sTitle, TObject(Param[form1.iEnumWin]));
inc(Form1.iEnumWin);
end;
end;
{ On change display room Title for each item }
procedure TForm1.cbbRoomsChange(Sender: TObject);
var
i: Integer;
aHwnd: PMyEnumParam;
begin
i := cbbRooms.ItemIndex;
if cbbRooms.ItemIndex <> -1 then
begin
aHwnd:= PMyEnumParam(cbbRooms.Items.Objects[i]);
if aHwnd.MainHwnd > 0 then
begin
ShowMessage(aHwnd.sTitle);
end;
end;
end;
{ Call EnumWindows and fill our array records }
procedure TForm1.FormCreate(Sender: TObject);
var
arInfo: PATMyEnumParam;
begin
iEnumWin:= 0;
EnumWindows(@EnumWindowsProc, LParam(@arInfo));
end;
Please if anyone can point (no pun intended) me in the right direction I would be grateful.
There are many things wrong with your code. Here's a non-exhaustive list:
^PATMyEnumParam
to EnumWindows
which you then cast to PATMyEnumParam
in the callback.But your biggest problem is that your code is attempting to run before you can walk. It has full complexity and all the functionality that you need. Yet you cannot yet manage to make a single successful call to EnumWindows
.
My biggest piece of advice here is not in the detail, but the generality of problem solving. Start by writing a simple piece of code. Understand it. Then enhance it.
So, in that vein, here is how to make a call to EnumerateWindows
:
program EnumWindowsDemo_17620346;
{$APPTYPE CONSOLE}
uses
System.SysUtils, Winapi.Windows, Generics.Collections;
type
TWindowInfo = record
Handle: HWND;
// expand with more fields in due course
end;
function EnumWindowProc(hwnd: HWND; lParam: LPARAM): BOOL; stdcall;
var
WindowList: TList<TWindowInfo>;
WindowInfo: TWindowInfo;
begin
WindowList := TList<TWindowInfo>(lParam);
WindowInfo.Handle := hwnd;
WindowList.Add(WindowInfo);
Result := True;
end;
procedure Main;
var
WindowList: TList<TWindowInfo>;
WindowInfo: TWindowInfo;
begin
WindowList := TList<TWindowInfo>.Create;
try
EnumWindows(@EnumWindowProc, LPARAM(WindowList));
for WindowInfo in WindowList do
Writeln(WindowInfo.Handle);
finally
WindowList.Free;
end;
end;
begin
Main;
Readln;
end.
Starting from here you can expand this concept, because all the tricky parts are already taken care of. Specifically the pointer, casting and memory management.