动态数组可以用作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; 
+1

当然你可以将'AList'的**指针**传递给'EnumWindows'。我不知道delphi,它是如何在它的语法中。可能是'lparam(@AList)'并声明'FindActiveUSERApps(AHandle:HWND; AList:^ THandleList)'或者如何在delphi中声明指针?你需要传递**指针**到对象'lparam'并且在回调中你没有对象,但是作为第二个参数 – RbMm

+0

传递一个动态数组可以很好地指向THANDleList。这取决于你想用它做什么。 –

,不使用动态数组实际看到您的实现,我假设你用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轻松返回动态数组。

+0

我也喜欢Tlist方法。但我只想知道动态阵列是否“未被使用”以备将来使用。我已经尝试了上述方法,直到我在GetActiveUserApps中的Alist参数中添加了一个VAR后才开始工作: function GetActiveUserApps(var AList:THandleList):boolean; 非常感谢您的帮助。赞赏。 – TomB

+0

的确,我错过了这个变种。固定。 –