ما الذي يمكن أن يتسبب في تفكيك Windows لخطاف لوحة المفاتيح منخفض المستوى (العالمي)؟

StackOverflow https://stackoverflow.com/questions/2655278

سؤال

لدينا بعض خطافات لوحة المفاتيح العالمية مثبتة عبر SetWindowsHookEx مع WH_KEYBOARD_LL يبدو أنه لا يطوّس بشكل عشوائي بواسطة Windows.

لقد تحققنا من أنها لم تعد متصلة بسبب الاتصال UnhookWindowsHookEx على المقبض يعود false. (تم التحقق أيضًا من عودته true عندما كان يعمل بشكل صحيح)

لا يبدو أن هناك نسخة ثابتة ، فقد سمعت أنه يمكن أن يفسدوا بسبب المهلة أو الاستثناءات التي يتم إلقاؤها ، لكنني حاولت أن أتركها تجلس على نقطة توقف في طريقة المناولة لأكثر من دقيقة ، وكذلك مجرد رمي استثناء عشوائي (C#) ولا يزال يبدو أنه يعمل.

في رد الاتصال لدينا ننشر بسرعة إلى موضوع آخر ، بحيث لا يكون هذا هو المشكلة. لقد قرأت عن الحلول في Windows 7 لتعيين المهلة أعلى في السجل لأن Windows 7 أكثر عدوانية بشأن المهلات على ما يبدو (نحن جميعًا ندير Win7 هنا ، لذلك لست متأكدًا مما إذا كان هذا يحدث على نظام التشغيل الآخر) ، لكن هذا لا يفعل ذلك يبدو وكأنه حل مثالي.

لقد فكرت فقط في أن يكون لديك سلسلة خلفية تعمل لتحديث الخطاف بين الحين والآخر ، وهو أمر مخترق ، لكنني لا أعرف أي عواقب سلبية حقيقية للقيام بذلك ، ويبدو أنه أفضل من تغيير إعداد سجل Windows العالمي .

أي اقتراحات أو حلول أخرى؟ كل من الفئة التي تحدد السنانير والمندوبين التي يتم ربطها بها ثابتة ، لذلك لا ينبغي أن يحصلوا على GC'd.

تحرير: تم التحقق من المكالمات إلى GC.Collect(); أنهم ما زالوا يعملون ، لذلك لا يتم جمعهم.

هل كانت مفيدة؟

المحلول

أعتقد أن هذا يجب أن يكون مشكلة مهلة.

أبلغ المطورون الآخرون عن مشكلة محددة في Windows7 مع عدم وجود خطافات منخفضة المستوى إذا تجاوزوا قيمة مهلة (غير موثقة).

نرى هذا الموضوع للمطورين الآخرين يناقشون نفس المشكلة. قد تكون بحاجة إلى إجراء حلقة مزدحمة (أو مجموعة بطيئة للقمامة) بدلاً من النوم للتسبب في سلوك غير مألوف. قد تخلق نقطة توقف في وظيفة LowleVelkeyboardProc أيضًا مشاكل في المهلة. (هناك أيضًا ملاحظة مفادها أن تحميل وحدة المعالجة المركزية الثقيلة بواسطة مهمة أخرى قد يثير السلوك - على الأرجح لأن المهمة الأخرى تسرق دورات وحدة المعالجة المركزية من وظيفة lowlevelkeyboardproc وتسببها في استغرق وقتًا طويلاً.)

الحل المقترح في هذا الموضوع هو محاولة ضبط LowlevelhookStimeout قيمة DWORD في السجل في HKEY_CURRENT_USER لوحة التحكم سطح المكتب إلى قيمة أكبر.

تذكر أن أحد أمجاد C# هو أنه حتى العبارات البسيطة يمكن أن تستغرق وقتًا طويلاً في حالة حدوث مجموعة من القمامة .. قد يفسر هذا (أو تحميل وحدة المعالجة المركزية بواسطة مؤشرات ترابط أخرى) الطبيعة المتقطعة للمشكلة.

نصائح أخرى

هناك شيئان فكرت بهما قد يساعدك في معرفة مكان المشكلة.

  1. للمساعدة في عزل موقع المشكلة ، قم بتشغيل آخر WH_KEYBOARD_LL ربط في وقت واحد مع الخطاف الحالي الخاص بك وعدم القيام بأي شيء آخر غير تمرير البيانات على سلسلة الخطاف. عندما تكتشف أن الخطاف الأصلي الخاص بك هو غير مطبوخ ، تحقق ومعرفة ما إذا كان هذا الخطاف "الدمية" قد تم تفكيكه أيضًا. إذا كان الخطاف "الدمية" غير مطبوخ أيضًا ، فيمكنك أن تكون متأكدًا إلى حد ما من أن المشكلة خارج خطافتك (أي في النوافذ أو شيء يتعلق بعاملتك ككل؟) ربما في مكان ما داخل خطافك.

  2. قم بتسجيل المعلومات التي تصل إلى خطافك عبر رد الاتصال وقم بتشغيلها حتى يتم ربط الخطاف. كرر هذا عدة مرات وفحص البيانات المسجلة لمعرفة ما إذا كان يمكنك تمييز نمط يؤدي إلى عدم التخلص.

سأحاول هذه في وقت واحد ، فقط في حالة تأثير إما على نتائج الآخرين. إذا لم يكن لديك أي خيوط فيما يمكن أن تكون عليه المشكلة ، فقد تحاول تشغيلها معًا.

إنها لقطة طويلة ، ولكن بأي فرصة هل لديك برامج مكافحة الفيروسات؟ يمكن أن يلاحظ ذلك خطاف لوحة المفاتيح وطرده.

من الأرجح أن يحذرك ، ويزيله على الفور ، لكنه أحد تلك الأشياء الغريبة التي تستحق التحقق منها.

ربما يكون لدى شخص آخر خطاف لا يدعو callnexthookex ()؟

أعلم أنه حل قبيح ولكن يمكنك تعيين مؤقت لمدة 5 دقائق من أي وقت مضى ، ثم يمكنك إعادة صياغة أحداث لوحات المفاتيح الخاصة بك؟

واجهت نفس المشكلة مع Machine Win7 ، بعد فترة من الوقت كانت خطافات لوحة المفاتيح قد فقدت مرجعتها ، واضطررت إلى إعداد مؤقت لكل 5 دقائق لربط الأحداث مرة أخرى ، والآن يبقيه جديدًا.

أنا أستخدم المشروع التالي من: http://www.codeproject.com/articles/7294/processing-global-mouse-and-keyboard-hooks-in-c لأداء المهام عند الضغط على مفتاح معين.

لقد لاحظت أنه بعد أن قمت بمهمة مع مفتاح Hotkey ، توقفت عن الاستماع إلى keypresses جديدة ، ثم غيرت لوحة المفاتيح إلى Static ويبدو أنها حل مشكلتي. ليس لدي أي فكرة عن سبب حل مشكلتي ، لذلك لا تتردد في التعليق على هذا!

فصل المفتاح الساخن الخاص بي:

 class Hotkey
{
    private static KeyboardHookListener _keyboardHookListener;

    public void Start()
    {
        _keyboardHookListener = new KeyboardHookListener(new GlobalHooker()) { Enabled = true };
        _keyboardHookListener.KeyDown += KeyboardListener_OnkeyPress;
    }

    private void KeyboardListener_OnkeyPress(object sender, KeyEventArgs e)
    {
        // Let's backup all projects
        if (e.KeyCode == Keys.F1)
        {
            // Initialize files
            var files = new Files();

            // Backup all projects
            files.BackupAllProjects();
        }
        // Quick backup - one project
        else if (e.KeyCode == Keys.F2)
        {
            var quickBackupForm = new QuickBackup();
            quickBackupForm.Show();
        }
    }
}

متأخر جدًا ولكن اعتقدت أنني سأشارك شيئًا. التجمع من هنا هناك تلميحات زوجين مثل وضع setwindowshookex في موضوع منفصل وأنها مشكلة جدولة أكثر.

لاحظت أيضًا أن التطبيق.

public static bool active = true;

[StructLayout(LayoutKind.Sequential)]
public struct NativeMessage
{
    public IntPtr handle;
    public uint msg;
    public IntPtr wParam;
    public IntPtr lParam;
    public uint time;
    public System.Drawing.Point p;
}

[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool PeekMessage(out NativeMessage message,
    IntPtr handle, uint filterMin, uint filterMax, uint flags);
public const int PM_NOREMOVE = 0;
public const int PM_REMOVE = 0x0001;

protected void MouseHooker()
{
    NativeMessage msg;

    using (Process curProcess = Process.GetCurrentProcess())
    {
        using (ProcessModule curModule = curProcess.MainModule)
        {
            // Install the low level mouse hook that will put events into _mouseEvents
            _hookproc = MouseHookCallback;
            _hookId = User32.SetWindowsHookEx(WH.WH_MOUSE_LL, _hookproc, Kernel32.GetModuleHandle(curModule.ModuleName), 0);
        }
    }
        while (active)
        {
            while (PeekMessage(out msg, IntPtr.Zero,
                (uint)WM.WM_MOUSEFIRST, (uint)WM.WM_MOUSELAST, PM_NOREMOVE))
                ;
            Thread.Sleep(10);
        }

        User32.UnhookWindowsHookEx(_hookId);
        _hookId = IntPtr.Zero;            
}

public void HookMouse()
{
    active = true;
    if (_hookId == IntPtr.Zero)
    {
        _mouseHookThread = new Thread(MouseHooker);
        _mouseHookThread.IsBackground = true;
        _mouseHookThread.Priority = ThreadPriority.Highest;
        _mouseHookThread.Start();
    }
}

لذا ، فقط قم بتغيير منطقي النشط إلى خطأ في إلغاء تنشيط الحدث واستدعاء HookMouse في الحدث المنشط.

HTH

تحرير: لاحظت أن الألعاب قد تباطأت مع هذا ، لذلك قررت إلغاء توضيح عندما لا يكون التطبيق نشطًا باستخدام الأحداث المنشطة وإلغاء تنشيطها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top