Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: Alatey от Май 30, 2012, 18:09



Название: [РЕШЕНО] mouse_event застревает
Отправлено: Alatey от Май 30, 2012, 18:09
Здравствуйте уважаемые форумчане :). У меня нетривиальный случай.

Пишу клиент-серверное приложение для удалённого управления рабочим столом.
Эмулирую нажатие мыши с помощью mouse_event:
Код:
#include <windows.h>
typedef void (*ME)(__in DWORD dwFlags, __in DWORD dx, __in DWORD dy, __in DWORD dwData, __in ULONG_PTR dwExtraInfo);
...
QLibrary myLib("user32.dll");
ME me= (ME)myLib.resolve("mouse_event");
me(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
me(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
// mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); <- так выдаёт ошибку компиляции.
Тестирую на VmVare. Всё работает... пока эмулированно не нажмёшь кнопку "свернуть окно" своего приложения, после чего на процедуре "me(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);" приложение "зависает" пока вручную не "отожмёшь" мышку (MOUSEEVENTF_LEFTUP), после чего приложение "отмерзает" и работает нормально. Как это преодолеть?

Хотел выкрутиться: вызывать "me(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);" из другого потока, чтобы основной поток не "зависал". Но так процедура не вызывается - выдаёт ошибку.
Код:
class DownMouseButtonThread : public QThread
{
    Q_OBJECT
public:
    DownMouseButtonThread()
{
     moveToThread(this);
    this->myLib = new QLibrary("user32.dll");
    this->me = (ME)this->myLib->resolve("mouse_event");
}
    ~DownMouseButtonThread() { delete this->myLib; }

    void run() { this->exec(); }

// вызываем из главного потока после me(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
// убеждаемся, что "зависшее" зажимание "отвисло" после отпускания, которое вызвано из главного потока
    void WaitOnButtonDown() { this->sem.acquire(); }

public slots:
    void onSetButtonDown()
{ // зажимаем мышь в этом потоке
    this->me(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); // здесь ошибка выполнения
    this->sem.release();
}

private:
    QSemaphore sem;
    QLibrary *myLib;
    ME me;
};


Название: Re: mouse_event застревает
Отправлено: Bepec от Май 30, 2012, 18:28
Хм. Вроде я отписывался уже тут, однако сообщенька потерялась видимо.

Вопрос - зачем ты извращаясь подгружаешь user32dll???
Инклудь windows.h и не парься с функциями.


Название: Re: mouse_event застревает
Отправлено: Alatey от Май 30, 2012, 19:37
чё-то не пойму куда писать. И там - не там и там -не там .... В qt-форуме нет раздела Win32API.
Уже подключил:
Код:
#include <windows.h>
#pragma comment (lib, "user32.lib")

И... блин... заработало (с моим потоком-выкрутасом) :) Весьма Вам благодарен "Bepec" !!!! :-*



Название: Re: mouse_event застревает
Отправлено: Bepec от Май 30, 2012, 19:40
В заголовке темы допиши [РЕШЕНО].
Всегда пожалуйста, за ваши деньги любой каприз ;)


Название: Re: mouse_event застревает
Отправлено: Alatey от Май 30, 2012, 20:13
Один раз заработало, а потом перестало, но это что-то с потоком.


Название: Re: mouse_event застревает
Отправлено: Bepec от Май 30, 2012, 20:23
Сделайте простой пример потока. Который допустим будет надпись изменять.
И сделайте простой пример, который двигает мышкой. Без потока ;)

И вот вы поймаете бага. Убейте бага. :D


Название: Re: mouse_event застревает
Отправлено: Alatey от Май 30, 2012, 23:21
Поток переписал, но приложение всё равно застревает.
Код:
class DownMouseButtonThread : public QThread
{
    Q_OBJECT
public:
    DownMouseButtonThread() { moveToThread(this); }
    void run()
{
   do
    {
        this->OnCommandSem.acquire();
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); // !!! застревает здесь !!!
        this->sem.release();
    }
    while(true);
}

    void SetButtonDown() { this->OnCommandSem.release(); }

    // убеждаемся, что "зависшее" зажимание "отвисло" после отпускания, которое вызвано из главного потока
    void WaitOnButtonDown() { this->sem.acquire(); }

private:
    QSemaphore sem;
    QSemaphore OnCommandSem;
};
...
// создаём поток
DownMouseButtonThread DownMouseButtonThread;
DownMouseButtonThread.start();
...
// при зажатии кнопки мыши
DownMouseButtonThread.SetButtonDown();
...
// при отжатии кнопки
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
DownMouseButtonThread.WaitOnButtonDown();
Моё мнение одно из двух:
1. нажатие на системную кнопку окна способно останавливает выполнение всех потоков приложения. Но не всегда (не могу пока уловить такие условия).
2. зажатие кнопки в потоке не отвисает, даже когда в главном потоке кнопка уже отжата. (что маловероятно)

Вижу 2 выхода:
1. не использовать (скрыть) системные кнопки форм (свернуть, развернуть закрыть), в место них сделать соответствующие кнопки на самих формах.
2. перенести эмуляцию мыши в отдельное приложение, т.е. эмуляция мыши и интерфейс всегда должны быть в разных приложениях.


Название: Re: mouse_event застревает
Отправлено: Bepec от Май 31, 2012, 06:53
Кстати да, факт - windows при нажатии на системные кнопки окна, тормозит GUI приложения. Потоки же в это время вроде не тормозятся.

Счас проверю :)

Потоки не тормозятся. Но если у тебя он работает синхронно с основным потоком, тогда да - капец до отжатия кнопачки :D


Название: Re: mouse_event застревает
Отправлено: Alatey от Май 31, 2012, 17:01
Сделал зажимание и отпускание в одном неосновном потоке - застревает :o.
Мне кажется что при клике блокируется поток который "издаёт" клик, и тот поток который его принимает (основной). Т.е. эмуляция зажатия и отжатия должно происходить в разных потоках, при том не являющихся основными. Буду проверять эту версию.

ПС: Интересная закономерность: если время между зажатием и отпусканием относительно маленькое, то не застревает ;D.


Название: Re: mouse_event застревает
Отправлено: Bepec от Май 31, 2012, 18:04
Я те по секрету скажу. Наверно у тебя где то потоки связаны. И основной поток блокирует дополнительный. Вот тебе и весь сказ, а не глюк.


Название: Re: mouse_event застревает
Отправлено: Alatey от Май 31, 2012, 19:49
да, вероятно так и есть, в главном потоке сокет принимает команды из сети. Теперь нужно перенести сокет в другой поток.

Проблема решена!
mouse_event всегда вызываю из одного неглавного потока.

ПС: меня запутало то, что команды эмуляции приходили через сокет, который блокировался в главном потоке и команда отпускания миши не поступала. Поэтому сокет теперь выполняется в неглавном потоке.
Верес был прав ;D