Модераторы: feodorv, GremlinProg, xvr, Fixin

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Таймер без окна 
:(
    Опции темы
Andrey44
Дата 15.2.2010, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1501
Регистрация: 4.12.2006
Где: На работе

Репутация: 8
Всего: 26



Вобщем вопрос.
Есть класс, в нем надо делать что-то, через какое-то время.
Можно делать  SetTimer(0, ID_TIMER, TIMEOUT, (LPTIMERPROC)TimerProc);
Но тогда функция TimerProc должна быть static, а мне надо иметь доступ к нестатическим членам класса.
Как можно это обойти? Не ложить же статик-мембереом указатель на самого себя, или не объявлять глобальную переменную. smile 


--------------------
????? ??, ??????? ?????.  smile 
PM MAIL WWW ICQ   Вверх
artsb
Дата 15.2.2010, 12:20 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 5
Всего: 64



Цитата(Andrey44 @  15.2.2010,  12:17 Найти цитируемый пост)
Как можно это обойти?

Сделать её другом класса?


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
Andrey44
Дата 15.2.2010, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1501
Регистрация: 4.12.2006
Где: На работе

Репутация: 8
Всего: 26



И что будет? TimerProc получит доступ к неявному указателю this?


--------------------
????? ??, ??????? ?????.  smile 
PM MAIL WWW ICQ   Вверх
artsb
Дата 15.2.2010, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 5
Всего: 64



Цитата(Andrey44 @  15.2.2010,  12:32 Найти цитируемый пост)
И что будет?

Действительно, что-то я сморозил не то  smile 
ИМХО простого выхода из этой ситуации нет. Если он вообще есть конечно...

Это сообщение отредактировал(а) artsb - 15.2.2010, 12:46


--------------------
Чем отличается умный человек от мудрого?
Умный - выпутается из любой ситуации.
Мудрый - просто в неё не попадёт.
PM MAIL   Вверх
GremlinProg
Дата 15.2.2010, 21:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



можно сделать так:
Код

id = SetTimer( NULL, (UINT_PTR)this, TIMEOUT, (LPTIMERPROC)TimerProc );

Код

VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ){
  ...
( ( CMyObject* )idEvent )->MyTimerMethod( ..., dwTime, ... );
  ...
}

можно TimerProc сделать шаблоном, тогда вообще все просто:
Код

template< typename T, void(T::*method)( ... ) >
VOID CALLBACK TimerProc( HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime ){
   ( ( ( T* )idEvent )->*method )( ... );
}



--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
Dem_max
Дата 16.2.2010, 07:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 16
Всего: 39



не забывай что функция Таймера это CallBack функция, из которой нужно вернуть управление циклу сообщений.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Earnest
Дата 16.2.2010, 08:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Цитата(GremlinProg @  15.2.2010,  22:47 Найти цитируемый пост)
можно сделать так:

Ты точно знаешь, что это сработает? Дело в том, что MSDN пишет, что при hWnd == 0 ид-р таймера игнорируется.
Цитата

nIDEvent
[in] Specifies a nonzero timer identifier. If the hWnd parameter is NULL, this parameter is ignored.

Я тоже было хотела это предложить, да призадумалась над этой фразой. Как минимум, надо проверять (что ид-р будет приходить в call-back без искажений).


--------------------
...
PM   Вверх
Dem_max
Дата 16.2.2010, 08:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 16
Всего: 39



Создавай таймер с помощью потока.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Earnest
Дата 16.2.2010, 08:47 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Цитата(Dem_max @  16.2.2010,  09:45 Найти цитируемый пост)
Создавай таймер с помощью потока. 

Если выбирать между ни зачем больше не нужным потоком и статической переменной, я бы выбрала статическую переменную. Вот ей богу. По принципу Оккама.


--------------------
...
PM   Вверх
Andrey44
Дата 16.2.2010, 08:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1501
Регистрация: 4.12.2006
Где: На работе

Репутация: 8
Всего: 26



GremlinProg, сделал как ты написал, не работает.Все приходит, захожу в функцию обработчик таймера, но в this какой-то мусор. В MSDN написано что idEvent должен быть 0 если HWND == 0.


--------------------
????? ??, ??????? ?????.  smile 
PM MAIL WWW ICQ   Вверх
azesmcar
Дата 16.2.2010, 09:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 5
Всего: 211



Что-то вроде этого

Код

template <typename type, void (type::*func)(), unsigned int offset>
void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
    (TimerArguments<type>::object<offset>()->*func)(); 
};


создаем шаблонную функцию, которая будет вызываться таймером и вызывать соответствующую member функцию. Типы можно передать в compile-time, проблема с this, это решаем таким образом - создаем класс для регистрации объектов, пусть он может хранить по умолчанию 100 объектов.

Код

template <typename type, unsigned int size = 100>
class TimerArguments
{
public:
    template <unsigned int Id>
    static void registerObject(type * object) {
        arguments[Id] = object;
    }

    template <unsigned int Id>
    static type * object() {
        return arguments[Id];
    }
private:
    static type * arguments[size];
};


использование
Код

// регистрируем свой объект под определенным номером
TimerArguments<Timer>::registerObject<0>(&tm);
// таймер пусть вызывает функцию с передачей во время 
// компиляции определенного идентификатора объекта, для него и будет вызвана функция.
SetTimer(NULL, 0, 1000, (TIMERPROC)TimerProc<Timer, &Timer::execute, 0>);


Пойдет?  

полный пример
Код

#include <iostream>
#include <windows.h>

class Timer
{
public:
    void execute()
    {
        std::cout << "OnTimer" << std::endl;
    };
};

template <typename type, unsigned int size = 100>
class TimerArguments
{
public:
    template <unsigned int Id>
    static void registerObject(type * object) {
        arguments[Id] = object;
    }

    template <unsigned int Id>
    static type * object() {
        return arguments[Id];
    }
private:
    static type * arguments[size];
};

template <typename type, unsigned int size>
type * TimerArguments<type, size>::arguments[size] = {0};

template <typename type, void (type::*func)(), unsigned int offset>
void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
{
    (TimerArguments<type>::object<offset>()->*func)(); 
};

int main()
{
    Timer tm;
    TimerArguments<Timer>::registerObject<0>(&tm);
    SetTimer(NULL, 0, 1000, (TIMERPROC)TimerProc<Timer, &Timer::execute, 0>);

    MSG message;
    while (GetMessage(&message, 0, 0, 0))
    {
        TranslateMessage(&message);
        DispatchMessage(&message);
    }
}

Это навскидку, можно доработать.


Это сообщение отредактировал(а) azesmcar - 16.2.2010, 09:28
PM   Вверх
GremlinProg
Дата 16.2.2010, 09:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2706
Регистрация: 9.8.2005
Где: Тюмень

Репутация: 99
Всего: 106



Цитата(Earnest @  16.2.2010,  10:36 Найти цитируемый пост)
Ты точно знаешь, что это сработает?

в районе полугода-года я пользовался таймером без окна в объектной модели,
а отказался я от использования этого таймера по причине использования им очереди сообщений независимо от того, есть HWND или нет, что в моем случае означало его бесполезность, т.к. там нужно было следить за сменой состояния этой самой очереди,
масло масляное вобщем с ним выходило

т.е. независимо от первого параметра, сообщение поступит в обычную очередь и будет извлечено обычным способом,
тут просто предоставляется возможность в цикле сообщений дополнить это сообщение желаемым дескриптором,
что на самом деле реализуется крайне редко, т.е. в основном такой таймер, с hwnd=0 используется за пределами окон

вот как раз эта очередь и дальнейшее дополнение сообщения WM_TIMER и требует какой-то внутренней идентификации "импульса" таймера, чтобы можно было дальше обработать сообщение обычным образом, через процедуру окна,

а другого способа ввести эту идентификацию кроме как через nIDEvent нету
можно конечно и проверить, полагаю, Andrey44 это сделать проще

Добавлено через 10 минут и 49 секунд
Цитата(Andrey44 @  16.2.2010,  10:52 Найти цитируемый пост)
но в this какой-то мусор

если приходит не 0, значит там точно не мусор, смотри за периодом жизни объекта, думаю в этом дело


--------------------
"Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины."
PM WWW ICQ   Вверх
maxim1000
Дата 16.2.2010, 09:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

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



есть ещё вариант специально создать окно для обработки таймера
начиная с Windows XP даже есть тип окна "message only window"

если уж окна совсем не хочется, можно воспользоваться waitable timer, ожидание которого можно встроить в очередь сообщений, но тогда понадобится переменная, доступная коду работы с очередью, которая хранит соответствие индексов, таймеров и функторов


--------------------
qqq
PM WWW   Вверх
Andrey44
Дата 16.2.2010, 09:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1501
Регистрация: 4.12.2006
Где: На работе

Репутация: 8
Всего: 26



Цитата(Earnest @  16.2.2010,  08:47 Найти цитируемый пост)
Если выбирать между ни зачем больше не нужным потоком и статической переменной, я бы выбрала статическую переменную. Вот ей богу. По принципу Оккама.
 smile В этой ситуации это проще всего. Так наверное я и сделаю.



--------------------
????? ??, ??????? ?????.  smile 
PM MAIL WWW ICQ   Вверх
Earnest
Дата 16.2.2010, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 33
Всего: 183



Цитата(maxim1000 @  16.2.2010,  10:28 Найти цитируемый пост)
можно воспользоваться waitable timer

Не прокатит: его нужно ждать функцией WaitForSingleObject (или Multiple) и, соответственно, стоять. Либо писать цикл - заглянул в таймер (с нулевым ожиданием), сделал что-то и т.д. Но это страшно неудобно. В общем, WaitableTimer - отличная штука для рабочего потока, но не для главного. 


--------------------
...
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




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


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

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