2017-02-18 24 views
1

我正在重做一些代碼以準備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。這取決於你想用它做什麼。 –

回答

5

,不使用動態數組實際看到您的實現,我假設你用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

的確,我錯過了這個變種。固定。 –

相關問題