Callback вызов
От: LeonCrew Беларусь  
Дата: 01.09.06 22:54
Оценка:
Коллеги, посоветуйте, как лучше организовать обработку вызова Callback.
Изначально к ПК можно было подключать только одно устройство и в драйверах никто не предусмотрел идентификатор устройства при вызове Callback функции. Фактически, разработчик делал так:
SetCallback( DeviceId, CallbackFunc );

Где-то в программе:
int __stdcall CallbackFunc( const void *Buffer, int Length)
{
….
}

Теперь же при модернизации устройства стало возможным подключать до 64 таких устройств к одному ПК. Если изначально известно сколько будет устройств подключено или использовано в данной задаче, то вопросов не возникает, но! Поставлена задача написать универсальный класс для работы с любым количеством устройств. Как выполнить данную задачу, если пишется класс с static функцией на которую ссылаются все SetCallback и при этом нет возможности понять, с какова устройства пришел непосредственно вызов.
Править драйвера устройства нет возможности. На данный момент есть мысль: написать обработчик в виде DLL и запускать столько копий DLL сколько устройств.

Платформа Windows, но если есть более универсальный способ – буду только рад.
Re: Callback вызов
От: Alex Alexandrov США  
Дата: 02.09.06 05:02
Оценка: 2 (1)
Здравствуйте, LeonCrew, Вы писали:

LC>Коллеги, посоветуйте, как лучше организовать обработку вызова Callback.

LC>Изначально к ПК можно было подключать только одно устройство и в драйверах никто не предусмотрел идентификатор устройства при вызове Callback функции. Фактически, разработчик делал так:
LC>
LC>SetCallback( DeviceId, CallbackFunc );
LC>

LC>Где-то в программе:
LC>
LC>int __stdcall CallbackFunc( const void *Buffer, int Length)
LC>{
LC>….
LC>}
LC>

LC>Теперь же при модернизации устройства стало возможным подключать до 64 таких устройств к одному ПК. Если изначально известно сколько будет устройств подключено или использовано в данной задаче, то вопросов не возникает, но! Поставлена задача написать универсальный класс для работы с любым количеством устройств. Как выполнить данную задачу, если пишется класс с static функцией на которую ссылаются все SetCallback и при этом нет возможности понять, с какова устройства пришел непосредственно вызов.
LC>Править драйвера устройства нет возможности. На данный момент есть мысль: написать обработчик в виде DLL и запускать столько копий DLL сколько устройств.

LC>Платформа Windows, но если есть более универсальный способ – буду только рад.


Может, я что-то не так понял, но тем не менее. Если известно, что устройств не больше, чем 64, то нельзя ли просто написать 64 небольших функции-транслятора и новый SetCallbackEx:


typedef (*NewCallbackFunc)(DeviceId deviceId, const void *Buffer, int Length);

NewCallbackFunc g_callbacks[64] = { 0 };

int SetCallbackEx(DeviceId deviceId, NewCallbackFunc callbackFunc)
{
    switch (deviceId):
    {
    case 0 :
        g_callbacks[0] = callbackFunc;
        return SetCallback(0,  CallbackThunk0);
    case 1:
        g_callbacks[1] = callbackFunc;
        return SetCallback(1,  CallbackThunk1);
    // ...
    case 63:
        g_callbacks[63] = callbackFunc;
        return SetCallback(63,  CallbackThunk63);
    default: return ERROR_WRONG_DEVICE_ID;
    }
}

int __stdcall CallbackThunk0(const void *Buffer, int Length)
{
    assert(g_callbacks[0]);
    g_callbacks[0](0, Buffer, Length);
}

int __stdcall CallbackThunk1(const void *Buffer, int Length)
{
    assert(g_callbacks[1]);
    g_callbacks[1](1, Buffer, Length);
}


Большую часть можно сделать макросами.

P.S. Чтобы избежать новых проблем в будущем, я бы сразу сделал не SetCallback, а AddCallback/RemoveCallback. Для поддержки множества слушателей.
It's kind of fun to do the impossible (Walt Disney)
Re: Callback вызов
От: apple-antonovka  
Дата: 02.09.06 15:36
Оценка: 1 (1)
Можно сделать динамическую генерацию функций-врапперов.
Если колбяка типа __stdcall и код нужен для х8 то всего делов то:
Выделить страницу памяти через VirtualAlloc с PAGE_EXECUTE (можно и простым malloc'ом если не важна совместимость с DEP)
Записать в этот кусочек памяти:

pop eax //запомним адрес возврата
push DeviceId //положим на стек доп аргумент для device_callback
push eax //вернем адрес возврата на вершину стека
jmp CallbackFunc

где CallbackFunc — статическая функция принимающая на вход помимо остальных параметров первым параметром — device_id:
int __stdcall CallbackFunc( DWORD DeviceId, const void *Buffer, int Length)
{
….
}

Соответственно в SetCallback( DeviceId, CallbackFunc ); вторым параметром суем указатель на наш динамически сгенеренный враппер.
Re[2]: Callback вызов
От: Alex Alexandrov США  
Дата: 02.09.06 16:11
Оценка:
Здравствуйте, apple-antonovka, Вы писали:

AA>Можно сделать динамическую генерацию функций-врапперов.

AA>Если колбяка типа __stdcall и код нужен для х8 то всего делов то:

Если ограничение в 64 устройства достаточно жесткое, то не вижу никакого смысла городить платформенно-зависимый ассемблерный огород.
It's kind of fun to do the impossible (Walt Disney)
Re[2]: Callback вызов
От: apple-antonovka  
Дата: 02.09.06 16:37
Оценка:
Чем городить огород из набора функций проще написать так вот:

template<int i>
static int __stdcall callback(const void *Buffer, int Length)
{
printf("%s %u %u\n",Buffer,Length,i);
.....
}

А потом назначать колбяки:
switch(i)
{
case 1:SetCallback( 1, callback<1> );break;
case 2:SetCallback( 2, callback<2> );break;
}
Re[3]: Callback вызов
От: apple-antonovka  
Дата: 02.09.06 16:38
Оценка:
Небольшое уточнение — не под всеми компилерами это сработает как положено. В VC6 например нет
Re[2]: Callback вызов
От: LeonCrew Беларусь  
Дата: 02.09.06 23:41
Оценка: :)
Здравствуйте, Alex Alexandrov, Вы писали:


AA>Может, я что-то не так понял, но тем не менее. Если известно, что устройств не больше, чем 64, то нельзя ли просто написать 64 небольших функции-транслятора и новый SetCallbackEx:


Главное, чтобы потом инженерам не пришло в голову создать еще более "большое устройство" из этих малых устройств, например из 256

AA>P.S. Чтобы избежать новых проблем в будущем, я бы сразу сделал не SetCallback, а AddCallback/RemoveCallback. Для поддержки множества слушателей.


Драйвера писал человек который больше не работает и похоже, что исходники ушли вместе с ним....
Re[2]: Callback вызов
От: LeonCrew Беларусь  
Дата: 02.09.06 23:44
Оценка:
Здравствуйте, apple-antonovka, Вы писали:

AA>Можно сделать динамическую генерацию функций-врапперов.

AA>Если колбяка типа __stdcall и код нужен для х8 то всего делов то:
AA>Выделить страницу памяти через VirtualAlloc с PAGE_EXECUTE (можно и простым malloc'ом если не важна совместимость с DEP)

AA>Соответственно в SetCallback( DeviceId, CallbackFunc ); вторым параметром суем указатель на наш динамически сгенеренный враппер.


Подход интерестный, но будет ли он работать в Vista? Как-то в свете последних лет, microsoft упорно пыталась препятствовать данным трюкам.
Re[3]: Callback вызов
От: apple-antonovka  
Дата: 03.09.06 02:23
Оценка:
LC>Подход интерестный, но будет ли он работать в Vista? Как-то в свете последних лет, microsoft упорно пыталась препятствовать данным трюкам.
А кудаж он денется? VirtualAlloc там все так же выделяет PAGE_EXECUTE_..., а __stdcall — он и в Африке __stdcall
Re[3]: Callback вызов
От: Alex Alexandrov США  
Дата: 03.09.06 15:20
Оценка:
Здравствуйте, LeonCrew, Вы писали:

LC>Здравствуйте, Alex Alexandrov, Вы писали:


LC>Главное, чтобы потом инженерам не пришло в голову создать еще более "большое устройство" из этих малых устройств, например из 256

Ну значит будет таблица из 256 функций. Я же говорю — я не знаю степень динамичности этого ограничения. Это уж кроме тебя никто не определит.

AA>>P.S. Чтобы избежать новых проблем в будущем, я бы сразу сделал не SetCallback, а AddCallback/RemoveCallback. Для поддержки множества слушателей.

LC>Драйвера писал человек который больше не работает и похоже, что исходники ушли вместе с ним....
Я имел в виду, что имеет смысл сделать это в том коде, который напишешь ты. Правильней будет сказать "я бы сразу сделал не SetCallbackEx, а AddCallbackEx/RemoveCallbackEx"
It's kind of fun to do the impossible (Walt Disney)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.