2012-03-03 26 views
9

Bir Delphi XE uygulamasında, odak değişikliklerini izlemek için genel bir kanca kurmaya çalışıyorum. Ben ev sahibi uygulama penceresinin bir mesaj gönderdiğinde kanca prosedür var aynı dll olarakSetWindowsHookEx yerel bir kanca oluşturur. Nasıl global hale getirilir?

focusHook := SetWindowsHookEx(WH_CBT, @FocusHookProc, HInstance, 0); 
// dwThreadId (the last argument) set to 0 should create a global hook 

: kanca bir dll oluşturulan

function FocusHookProc(code : integer; wParam: WPARAM; lParam: LPARAM) : LResult; stdcall; 
begin 
    if (code < 0) then 
    begin 
    result := CallNextHookEx(focusHook, code, wParam, lParam); 
    exit; 
    end; 

    result := 0; 

    if (code = HCBT_SETFOCUS) then 
    begin 
    if (hostHWND <> INVALID_HANDLE_VALUE) then 
     PostMessage(hostHWND, cFOCUSMSGID, wParam, lParam); 
    end; 
end; 

Bu çalışır, ancak ev sahibi yalnızca bildirimlerini alır odakta uygulamanın kendisi içinde değişir. Ana formda bir not ve birkaç tane TButton vardır ve bunlar arasında odak geçişi beklenen iletiyi üretir. Bununla birlikte, uygulamanın dışındaki herhangi bir odak değişikliği asla bildirilmez. Ben DLL birden çok örneği ile ilgili bir şey vardır herhalde

diğer süreçler enjekte alıyorum. Kabul edilen bir yanıt here ile benzer bir soru var, ancak C için ve ben bir Delphi dll (ör. Paylaşılan bellek kurmak için pragma deyimleri) içinde aynı şeyi nasıl yapabilirim göremiyorum.

(Bu çoğunlukla bir kavramın kanıtıdır, ancak yine de işe almak isterim. Uygulamamın hemen önce etkinleştiğinden hangi pencerenin etkin olduğunu bilmem gerekir. Alt + sekme, etkinleştirme hotkey vs. Sorun şu ki, fare veya alt + sekmesi kullanılırsa, GetForegroundWindow her zaman kendi uyguladığımın pencere tanıtıcısını döndürür, ne kadar erken koyarım, örneğin uygulamanın ana mesaj kuyruğunu çırpmak gibi. Ben fikir gibi değil gerçekten yapmak gerçi.) DLL yana

cevap

15

başka bir süreç içine enjekte edilir tek çözüm,, değiltüm kırılma noktalarını sen süreç dışında herhangi bir amaçla isabet alacağım konum ayıklama. Ayrıca, diğer işlemdeki DLL'nin her örneği kendi global/statik verilerini de alır. Eğer hostHWND bir global ise, bu süreçte olduğu gibi diğer süreçte de aynı değer olmayacaktır. Aslında başlangıç ​​bile olmayacak. İşlemler arasında değerleri paylaşmak için paylaşılan bir bellek bloğu kullanmanız gerekir. Paylaşılan muteksler ve diğer senkronizasyon nesneleri, paylaşılan bellek yazmalarının korunmasını sağlamak için kullanılmalıdır. Son olarak, Windows Vista + kullanıyorsanız, yalnızca aynı erişim düzeyine ve aşağıya sahip olan işlemler DLL'ye enjekte edilir. IOW, işlemi oturum açmış kullanıcı olarak çalıştırıyorsanız, yalnızca oturum açmış kullanıcı olarak çalıştığı işlenen bu DLL'e enjekte edilir.

+2

+1, her DLL'de kendi verileriyle ilgili olası bir sorundur. Bu özel durumda, OP'nin paylaşılan belleği kullanması gerekmeyebilir: Yukarıdaki kod için basit bir düzeltme, hedef pencereyi vermek olabilir. Belirli bir sınıf adı ve kanca kodu bu hedefi bulmak için FindWindow'u kullanır. Ayrıca, başka bir kanca kısıtlaması: 32-bit kancalar sadece 32-bit koduna kancalanabilir; aynı şekilde 64-bit ile; Bu nedenle hem 32 hem de 64 bitlik işlemleri kancalamak sorunlu olabilir. – BrendanMcK

3

CBT kancası yerine WinEvents kullanmayı deneyin: SetWinEventHook EVENT_OBJECT_FOCUS'u hem minimum hem de maksimum etkinlik olarak, WINEVENT_OUTOFPROC bayrağını ve idThread ve idProcess için 0'ı kullanmayı deneyin. Bu size, ayrı bir DLL gerektirmeden, aynı masaüstündeki herhangi bir işlemden odak olaylarını dinleyebilecek bir kanca verecek ve hem 32 bit hem de 64 bit uygulamalarda çalışacaktır. uyarılar bir çift var

: Biri olaylar anlık olmaması; İşleminize esas olarak gönderildiği gibi hafif bir gecikme var (bir DLL'nin çalışmasını engelleyen pro-out seçeneğinin nasıl olduğu), ancak kullanımınız için yeterince hızlı olabilirler. (Izlemiyosun DLL çengel PostMessage kullanmak Ve eğer bu aynı sorunu olurdu!) Ayrıca

, gerçek HWND odak değişiklikleri daha fazla etkinlik alacak: Çeşitli kontroller odak sinyali bu odak değişikliği olayları göndermek değiştir - örneğin bir liste kutusundaki öğeler arasında hareket odaklanır. Bunları sadece idObject = OBJID_WINDOW ve idChild = 0 olanları için geri aramada filtreleyerek filtreleyebilirsiniz.

Alternatif olarak, EVENT_OBJECT_FOCUS (see MSDN for the full list of events) yerine EVENT_SYSTEM_FOREGROUND olaylarını dinlerseniz, yalnızca en üst düzeydeki pencere ön plan olaylarını almanız gerektiği gibi görünür.

İlgili konular