2010-06-28 16 views
12

मैं वैश्विक माउस और कीबोर्ड इनपुट को कैप्चर करने की कोशिश कर रहा हूं।निम्न-स्तर के माउस और कीबोर्ड हुक को समझना (win32)

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) { 
    if (nCode >= 0) { 
    if (wParam == WM_RBUTTONDOWN) printf("right mouse down\n"); 
    if (wParam == WM_RBUTTONUP) printf("right mouse up\n"); 
    } 
    return CallNextHookEx(0, nCode, wParam, lParam); 
} 

HHOOK mousehook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0); 
while(true) { 
    MSG msg; 
    if (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
    } 
#ifdef TEST 
    Sleep(50); 
#endif 
} 

तो यहाँ सब कुछ काम करता है, अगर मैं #define TESTSleep में डालने के लिए छोड़कर, माउस अविश्वसनीय रूप से सुस्त हो जाता है, के रूप में अगर मैं अचानक ही माउस 20 बार एक दूसरे को अद्यतन करने के लिए अनुमति देते हैं उम्मीद की जा सकती। और नींद के बिना, मैं 100% पर सीपीयू pegging हूँ। लेकिन यह अभी ठीक है (अगर मैं GetMessage का उपयोग करता हूं तो यह दूर हो जाता है)।

अब जब मैं इसे समझता हूं, निम्न-स्तरीय हुक उस प्रक्रिया में स्विच-स्विचिंग द्वारा काम करते हैं, और फिर प्रक्रिया को भेजकर इसे हुक कॉलबैक निष्पादित करने के लिए कुछ प्रकार का संदेश भेजते हैं। मुझे थोड़ा उलझन में आता है, हालांकि, मेरा प्रोग्राम कभी भी "msg recvd" प्रिंट नहीं करेगा, लेकिन जब भी मैं दायां माउस बटन क्लिक करता हूं तो यह "दायां माउस डाउन/अप" प्रिंट करता है। इससे मुझे यह निष्कर्ष निकाला जाता है कि MouseHookProc को PeekMessage कॉल के दौरान बुलाया जा रहा है। यह किसी प्रकार का विशेष संदेश होता है और PeekMessage 0 देता है। लेकिन मुझे अभी भी PeekMessage या कुछ समकक्ष कॉल करने की आवश्यकता है।

चूंकि मेरे प्रोग्राम को चीजों का एक गुच्छा करने की ज़रूरत है, इसलिए मैं स्पष्ट रूप से मेरे संदेश पंपिंग लूप का वजन नहीं कर सकता (वह जो PeekMessage कहता है) जो दूसरे कार्य को कॉल करके कहता है, वापस लौटने के लिए कहें। थोड़ी भारी उठाने के साथ-साथ माउस प्रतिक्रिया को बनाए रखने के लिए मैं अपने कार्यक्रम को कैसे बढ़ा सकता हूं? एक बहुप्रचारित Win32 प्रोग्राम में, अभी भी एक संदेश कतार है, है ना?

अद्यतन: एमएस के दस्तावेज़ीकरण पर पढ़ने के बाद मुझे लगता है कि मुझे पता है कि मेरे लिए क्या करना सही है। मुझे बस अपने आवेदन में एक धागा पैदा करना चाहिए जो माउस हुक को पंजीकृत करने के लिए SetWindowsHookEx पर कॉल करता है, और उसके बाद अपने संदेश लूप में बैठता है, और सिस्टम इस धागे में माउस अपडेट भेजने का ख्याल रखेगा। यह MouseHookProc के भीतर जो चाहें वह करने के लिए स्वतंत्र होगा, और मेरा शेष आवेदन स्वतंत्र रूप से चलाया जाएगा।

+0

क्या आपके पास एक डीएलएल के अंदर 'माउसहूकप्रोक' है और एक EXE के अंदर 'SetWindowsHookEx' और' PeekMessage' लूप 'है? – Oleg

+0

मैं एक डीएलएल इंजेक्ट करने से बचना चाहता था। सिस्टम के लिए अपने 'माउसहूकप्रोक' को कॉल करने के लिए सिस्टम पर स्विच करने के लिए मेरी ज़रूरतों के लिए यह अधिक उपयुक्त लगता है, इसलिए मैं निम्न स्तर के माउस हुक का उपयोग क्यों करना चाहता हूं। जैसा कि मैं इसे समझता हूं, एक नियमित माउस हुक, अगर मैं इसे वैश्विक होना चाहता हूं, तो डीएलएल विधि का उपयोग करना चाहिए। –

उत्तर

9

समस्या अपने संदेश पाश है , यह 100% सीपीयू चक्र जलता है क्योंकि आप PeekMessage() का उपयोग करते हैं। विंडोज़ जानता है कि अगर आप संदेशों के लिए मतदान नहीं करते हैं, तो भी अपनी समस्या को हल करने के लिए GetMessage() का उपयोग करें। नींद (1) का उपयोग करने से आपकी समस्या भी हल हो जाएगी लेकिन यहां जरूरी नहीं है।

Why must SetWindowsHookEx be used with a windows message queue

3
कर के बजाय

:

if (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 
Sleep(50); 

स्विच यह करने के लिए:

while (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    // Add this potentially... 
    if (msg.message == WM_QUIT) 
     break; 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
} 
Sleep(10); 

यह रिक्त होने तक उसे (कोई नींद होने की तरह) अपने ऐप्लिकेशन कतार में सभी संदेशों को संसाधित करने के लिए जारी रखने के लिए अनुमति देगा, तब ऐप "निष्क्रिय" होने पर कुछ CPU समय छोड़ देता है।

3

MouseHookProc dll में होनी चाहिए, अन्यथा आप पर कब्जा नहीं कर सकते हैं "वैश्विक" इनपुट (http://msdn.microsoft.com/en-us/library/ms997537.aspx)

पाश के बारे में - आप इसे इस प्रकार संशोधित कर सकते हैं:

while(true) { 
    MSG msg; 
    while (PeekMessage(&msg,0,0,0,PM_REMOVE)) { 
    printf("msg recvd\n"); 
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
    } 
#ifdef TEST 
    DoStuff(); 
    Sleep(50); 
#endif 
} 
+4

एक निम्न-स्तरीय माउस हुक * डीएलएल की आवश्यकता नहीं है, यह WH_MOUSE जैसे वैश्विक हुक नहीं है। –

6

मैं तुम्हें aksed आप DLL में जगह MouseHookProc जगह है या नहीं, क्योंकि प्रयास एक EXE यह एक ठेठ त्रुटि है अंदर इसे छोड़ दें। मैंने इसे कई साल पहले भी बनाया था।

सबसे पहले, तुम कैसे http://msdn.microsoft.com/en-us/library/ms644990.aspx में पढ़ सकते हैं:

SetWindowsHookEx किसी अन्य प्रक्रिया में एक DLL इंजेक्षन करने के लिए इस्तेमाल किया जा सकता है। 32-बिट डीएलएल को 64-बिट प्रक्रिया में इंजेक्शन नहीं दिया जा सकता है, और 64-बिट DLL 32-बिट प्रक्रिया में इंजेक्शन नहीं किया जा सकता है। एक आवेदन अन्य प्रक्रियाओं में हुक के उपयोग की आवश्यकता है, यह आवश्यक है है कि एक 32-बिट अनुप्रयोग कॉल SetWindowsHookEx 32-बिट प्रक्रियाओं में एक 32-बिट DLL सुई, और एक 64-बिट आवेदन कॉल SetWindowsHookEx 64-बिट DLL को 64-बिट प्रक्रियाओं में इंजेक्ट करने के लिए। 32-बिट और 64-बिट DLL के पास नाम अलग-अलग होना चाहिए।

तो आपको एक डीएलएल में जगह लेनी होगी। बिल्कुल सही होने के लिए यदि आप 32-बिट और 64-बिट प्लेटफ़ॉर्म दोनों का समर्थन करना चाहते हैं तो आपको दो डीएलएस लागू करना होगा: एक 32-बिट और 64-बिट DLL। पर क्यों? और कैसे SetWindowsHookEx काम करता है?

आप

HINSTANCE hinstDLL = LoadLibrary(TEXT("c:\\myapp\\syshook.dll")); 
HOOKPROC hkprcMouse = (HOOKPROC)GetProcAddress(hinstDLL, "MouseHookProc"); 
HHOOK hhookMouse = SetWindowsHookEx( 
        WH_MOUSE_LL, 
        hkprcMouse, 
        hinstDLL, 
        0); 

निम्नलिखित की तरह कोड एक EXE में निष्पादित यदि आप user32.dll ही खिड़कियों स्टेशन पर अन्य सभी प्रक्रियाओं में अपने syshook.dll सुई ( अनुरोध देना dll नहीं होगा तेजी से उपयोगकर्ता स्विचिंग के माध्यम से लॉग इन अन्य उपयोगकर्ताओं की सेवाओं और प्रक्रियाओं के लिए इंजेक्शन दिया जाना चाहिए)। फिर user32.dll विभिन्न प्रक्रियाओं में syshook.dll पर LoadLibrary पर कॉल करें। फिर यदि कार्य MouseHookProc कहा जाएगा, तो उस प्रक्रिया के संदर्भ में कहा जाएगा जिसमें माउस संदेश प्राप्त होता है। यदि प्रक्रिया कंसोल अनुप्रयोग नहीं है तो कोड

printf("right mouse down\n"); 

काम नहीं कर सकता है।

तो मुझे उम्मीद है कि अब आप अनावश्यक होंगे कि आपको डीएलएल में MouseHookProc क्यों रखना होगा।

+2

मुझे लगता है कि यहां कुछ भ्रम हो सकता है। उस समय के लिए मुझे इस विषय से जितनी भी आवश्यकता है, उतनी ही कम है: http://stackoverflow.com/questions/2060345/in-what-thread-does-a-low-level-mouse-and-keyboard- हुक-कॉलबैक-रन मदद करने के लिए समय लेने के लिए धन्यवाद, यद्यपि! –

+2

यह बहुत ही रोचक जानकारी है! यह बहुत दिलचस्प है कि 'WH_MOUSE_LL' जीनरल डीएलएल इंजेक्शन नियम का एक निष्पादन है। धन्यवाद! मैं आपको "SetWindowsHookEx' के एक छोटे से दस्तावेज़ को बदलने के लिए माइक्रोसॉफ्ट को सुझाव देने के लिए http://msdn.microsoft.com/en-us/library/ms644990.aspx पर" माइक्रोसॉफ्ट को इस विषय के बारे में टिप्पणियां भेजें "का उपयोग करने की सलाह दूंगा। http://msdn.microsoft.com/en-us/library/ms644986.aspx से जानकारी। – Oleg

+0

तो आप WH_MOUSE_LL के साथ कह रहे हैं कि यह एक डीएलएल में काम किए बिना काम करता है, लेकिन अन्य संदेश प्रकारों के लिए यह एक डीएल के भीतर होना चाहिए? – rogerdpack

संबंधित मुद्दे