Tom*_*omB 1 windows arrays delphi callback delphi-xe6
我正在重做一些64位准备好的代码.这将EnumWindows与回调一起使用,以返回运行的delphi应用程序列表(除IDE和其自身之外),然后将其终止.最初它使用TStringlist来保存这些应用程序的句柄.我想改变它直接以数字形式收集句柄.我已经得到了一个非常令人满意的解决方案,使用通用TList来收集句柄.
一路上,我最初尝试使用动态数组 - 它没有用.在验证了TList解决方案之后,出于学术兴趣重新审视了它,并尝试使用动态数组实现它的每种方式 - 都没有成功.我在文档中找不到任何禁令,虽然我在Rudy V的博客中遇到过这个说明:"不管怎样,Delphi字符串和动态数组都不应该作为参考计数类型传递给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;
Run Code Online (Sandbox Code Playgroud)
在没有使用动态数组实际看到您的实现的情况下,我假设您通过扩展它来向此数组添加元素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;
Run Code Online (Sandbox Code Playgroud)
也就是说,我个人更喜欢TList方法,以简化和清晰.特别是因为您可以轻松地从中返回动态数组AList.ToArray.