Модераторы: gambit, Kefir, Partizan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> WPF + WinApi 
:(
    Опции темы
vikaz
Дата 18.11.2013, 06:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 869
Регистрация: 15.2.2006

Репутация: 1
Всего: 12



Всем привет.

Эпопея с установкой хука на ОС для определенной комбинации клавиш продолжается. :(

Проблема, которая возникла на данный момент, это работа WinApi функции UnregisterHotKey. После завершения приложения, хук остается в системе и окно с тестовым сообщением, продолжает появляться после завершения программы. При этом, я никак не могу выбить хук из системы. Сначала, это было забавным, когда приложения выгруженное из памяти (но видимо ссылка где-то остается), продолжало показывать тестовое сообщение на комбинацию клавиш, которую я задал при регистрации, но сейчас от смеха не осталось и следа.

Был написан следующий класс:
Код

public class HotKey : IDisposable
    {
        public event Action HotKeyPressed;

        private static Object myStaticLock = new Object();
        private readonly IntPtr _hWnd;
        private static int _hotkeyCounter = 0xA000;
        private readonly int _hotkeyIndex;
        private bool _isDisposed, _isRegistered;
        private Keys _key;
        private ModifierKeys _modifierKeys;

        public HotKey()
        {
            EventDispatchingNativeWindow.Instance.EventHandler += nw_EventHandler;
            lock (myStaticLock)
            {
                _hotkeyIndex = ++_hotkeyCounter;
            }
            _hWnd = EventDispatchingNativeWindow.Instance.Handle;
        }

        public void SetHotKey(ModifierKeys modifierKeys, Keys key)
        {
            UnregisteredHotkey();
            _modifierKeys = modifierKeys;
            _key = key;
            RegisterHotKey();
        }

        private void nw_EventHandler(ref Message m, ref bool handled)
        {
            if (handled) return;
            if (m.Msg == WinApi.WM_HOTKEY && m.WParam.ToInt32() == _hotkeyIndex)
            {
                OnHotKeyPressed();
                handled = true;
            }
        }

        public void RegisterHotKey()
        {
            if (!_isRegistered && !_isDisposed)
            {
                bool success = WinApi.RegisterHotKey(_hWnd, _hotkeyIndex, _modifierKeys, _key);
                if (!success)
                {
                    throw new HotkeyAlreadyInUseException();
                }
                _isRegistered = true;
            }
        }

        public void UnregisteredHotkey()
        {
            if (_isRegistered && !_isDisposed)
            {
                WinApi.UnregisterHotKey(_hWnd, _hotkeyIndex);
                _isRegistered = false;
            }
        }

        public void Dispose()
        {
            if (!_isDisposed)
            {
                UnregisteredHotkey();
                EventDispatchingNativeWindow.Instance.EventHandler -= nw_EventHandler;
                _isDisposed = true;
            }
        }

        ~HotKey()
        {
            Dispose();
        }

        private void OnHotKeyPressed()
        {
            if (HotKeyPressed != null)
                HotKeyPressed();
        }
    }

    public class HotkeyAlreadyInUseException : Exception { }


Вспомогательный класс, который необходим для работы HotKey:

Код

public delegate void WndProcEventHandler(ref Message m, ref bool handled);

    public class EventDispatchingNativeWindow : NativeWindow
    {
        private static Object myLock = new Object();
        private static EventDispatchingNativeWindow _instance;

        public static EventDispatchingNativeWindow Instance
        {
            get
            {
                lock (myLock)
                {
                    if (_instance == null)
                        _instance = new EventDispatchingNativeWindow();
                    return _instance;
                }
            }
        }

        public event WndProcEventHandler EventHandler;

        public EventDispatchingNativeWindow()
        {
            CreateHandle(new CreateParams());
        }

        protected override void WndProc(ref Message m)
        {
            bool handled = false;
            if (EventHandler != null)
                EventHandler(ref m, ref handled);
            if (!handled)
                base.WndProc(ref m);
        }
    }


Код

public class HotKeySingleton
    {
        private static HotKey _instance;
        private static object syncLock = new object();

        private HotKeySingleton()
        {
        }

        public static HotKey GetInstance()
        {
            if (_instance == null)
            {
                lock (syncLock)
                {
                    if (_instance == null)
                    {
                        _instance = new HotKey();
                    }
                }
            }
            return _instance;
        }
    }


Вот как я работаю с этими классами в mvvm классе:

Код

private HotKey _hotKey;

// Default ctor
        public MainPageViewModel()
        {
            _hotKey = HotKeySingleton.GetInstance();
            _hotKey.SetHotKey(ModifierKeys.Control | ModifierKeys.Shift, Keys.X);
            _hotKey.HotKeyPressed += () => MessageBox.Show("HotKey");            
        }


В классе HotKey я реализовал интерфейс IDisposable. 

И при выходе из приложения я вижу, как вызывается метод ~HotKey(), который в свою очередь вызывает Dispose(), который выбивает хук из системы. Т.е. объект удаляется, как нужно и весь код относящийся к удалению хука, так же выполняется. Но почему хук остается в системе, для меня так и осталась загадкой. :(

Как может появляться сообщение "HotKey", когда приложение уже закрыто?

Подскажите, в чем может быть проблема.

Спасибо!

UPD: Добавил функцию получения ошибки в функцию Unregistred:
Код

public void UnregisteredHotkey()
        {
            if (_isRegistered && !_isDisposed)
            {
                WinApi.UnregisterHotKey(_hWnd, _hotkeyIndex);
                var error = Marshal.GetLastWin32Error();
                _isRegistered = false;
            }
        }


Мне вернулся код 1419, который как бы мне говорит, что HotKey не зарегистрирован. (http://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx).

Это меня очень удивило.

А когда я заново запускаю приложение, то регистрация возвращает ошибку с кодом 1409,которая сообщает, что HotKey уже зарегистрирован. :(

UPD2: Я не знаю от чего это зависит, но эта проблема уходит если вырубить VS! Т.е. если VS закрыто, а я запускаю приложение через exe файл, то все работает нормально. И при закрытии приложения, никаких тестовых окон не всплывает.

Осталось понять почему так.

Ну и почему при UnRegistered возвращается код 1419 не понятно!

UPD3: И все же какая-то проблема с самим классом HotKey. У этого класса метод Unregistered публичный. Я добавил кнопки на форму (start и stop) и вызывал их через команды:
Код

private void StopExecuteCommand()
        {
            _hotKey.UnregisteredHotkey();
        }

private void StartExecuteCommand()
        {
            _hotKey.RegisterHotKey();
        }


Когда вызывается метод UnregisteredHotkey, код ошибки = 0!!!! :( Но как только закрываю приложения, этот же код (UnregisteredHotkey) возвращает ошибку 1419! :(


--------------------
user posted image

Нет ничего настолько исправного, чтобы в нем не было ошибок. /Ф. Петрарка/ 
PM MAIL ICQ Skype   Вверх
jonie
Дата 24.11.2013, 21:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 2
Всего: 118



Цитата


UPD2: Я не знаю от чего это зависит, но эта проблема уходит если вырубить VS! Т.е. если VS закрыто, а я запускаю приложение через exe файл, то все работает нормально. И при закрытии приложения, никаких тестовых окон не всплывает.
дело в том что студия обычно (по умолчанию) производит отладку через хост процесс и его НЕ убивает при завершении процесса. Собственно вот он и висит. Воообще говоря винда должна подчистить за тобой твои косяки (если есть) при завершении процесса и убрать из таблицы хуков невалидный.

Для справки:
Цитата


To disable the hosting process

    Open an executable project in Visual Studio. Projects that do not produce executables (for example, class library or service projects) do not have this option.

    On the Project menu, click Properties.

    Click the Debug tab.

    Clear the Enable the Visual Studio hosting process check box.


(с) http://msdn.microsoft.com/en-us/library/vs...o/ms185330.aspx


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | WPF и Silverlight | Следующая тема »


 




[ Время генерации скрипта: 0.1393 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.