动态数组可以用作Windows回调函数的参数吗?
我正在重做一些代码以准备64位。这使用带回调的EnumWindows返回运行delphi应用程序(除IDE和本身之外)的列表 ,然后它们被关闭。原来它使用一个TStringlist来保存这些应用程序的句柄。我想改变它直接以数字形式收集手柄。 我使用通用的TList来收集句柄,我得到了一个非常满意的解决方案。动态数组可以用作Windows回调函数的参数吗?
一路上,我最初尝试使用动态数组 - 它没有工作。在验证了TList解决方案之后,我重新考虑了它,出于学术兴趣,并且尝试使用动态数组来实现它的每一种方式 - 所有这些都没有成功。我找不到文档中的任何禁令,虽然我没碰到过 本说明鲁迪五世的博客:“德尔福的字符串和动态数组不应视为引用计数的类型反正API函数传递......”
所以,我只是寻求一个“裁决”,即动态数组可以或不可以用作回调函数的参数。
type
THandleList=Tlist<THandle>;
const
ReqdClass: string = 'TApplication' ;
procedure KillWindowViaHandle(Ahwnd:THandle; Amsg: Cardinal=WM_CLOSE);
begin
PostMessage(Ahwnd, Amsg, 0, 0);
end;
// Get Active "User" Applications (except for bds.exe & caller). Relies on top
// level window having classname of TApplication. Returns list of handles.
function FindActiveUSERApps(AHandle: HWND; AList: lparam): BOOL ; stdcall;
var
classname: string;
pid: DWORD;
imagename: string;
begin
Result := true; // keep it going .. want them all
GetWindowThreadProcessID(AHandle, @pid); // not interested in ThreadID returned
imagename := GetProcessFileName(pid) ;
SetLength(ClassName, 255);
SetLength(ClassName, GetClassName(AHandle, PChar(className), Length(className)));
if (ansicontainstext(classname, ReqdClass)) and
(not ansisametext(ImageName, 'bds.exe')) and
(not ansisametext(ImageName, ExtractFileName(Application.ExeName))) then
THandleList(Alist).Add(AHandle) ;
end;
function GetActiveUSERApps(AList: THandleList): boolean;
begin
AList.Clear;
EnumWindows(@FindActiveUSERApps, lparam(AList));
result := Alist.Count > 0;
end;
function KillActiveUSERApps: boolean;
var
i : integer;
ActiveList: THandleList;
begin
result := false;
ActiveList := THandleList.Create;
try
GetActiveUSERApps(ActiveList);
for i:= 0 to activelist.Count - 1 do
KillWindowviaHandle(ActiveList[i]);
// noticed that some processes were resistant to being killed via WM_CLOSE.
// So try gentle approach first, and then if necessary, use the big stick.
GetActiveUSERApps(activeList);
for i:= 0 to activelist.Count - 1 do
KillWindowviaHandle(ActiveList[i], WM_QUIT);
result := true;
finally
ActiveList.Free;
end;
end;
,不使用动态数组实际看到您的实现,我假设你用SetLength
扩大其元素加入到这个阵列。这又会改变内部是指针的数组变量。因此,调用方法仍然使用旧指针变量作为参数传递的不存在的动态数组。
您可以通过使用指向动态数组的指针来克服这一点。
type
THandleList = TArray<THandle>;
PHandleList = ^THandleList;
function FindActiveUSERApps(AHandle: HWND; AList: lparam): BOOL ; stdcall;
var
...
PList: PHandleList;
begin
...
PList := PHandleList(AList);
SetLength(PList^, Length(PList^) + 1);
PList^[High(PList^)] := AHandle;
end;
function GetActiveUSERApps(var AList: THandleList): boolean;
begin
AList.Clear;
EnumWindows(@FindActiveUSERApps, lparam(@AList));
result := Alist.Count > 0;
end;
这就是说,我个人更喜欢简单和清晰的TList方法。尤其是您可以使用AList.ToArray
轻松返回动态数组。
我也喜欢Tlist方法。但我只想知道动态阵列是否“未被使用”以备将来使用。我已经尝试了上述方法,直到我在GetActiveUserApps中的Alist参数中添加了一个VAR后才开始工作: function GetActiveUserApps(var AList:THandleList):boolean; 非常感谢您的帮助。赞赏。 – TomB
的确,我错过了这个变种。固定。 –
当然你可以将'AList'的**指针**传递给'EnumWindows'。我不知道delphi,它是如何在它的语法中。可能是'lparam(@AList)'并声明'FindActiveUSERApps(AHandle:HWND; AList:^ THandleList)'或者如何在delphi中声明指针?你需要传递**指针**到对象'lparam'并且在回调中你没有对象,但是作为第二个参数 – RbMm
传递一个动态数组可以很好地指向THANDleList。这取决于你想用它做什么。 –