Коллеги, посоветуйте, как лучше организовать обработку вызова Callback.
Изначально к ПК можно было подключать только одно устройство и в драйверах никто не предусмотрел идентификатор устройства при вызове Callback функции. Фактически, разработчик делал так:
SetCallback( DeviceId, CallbackFunc );
Где-то в программе:
int __stdcall CallbackFunc( const void *Buffer, int Length)
{
….
}
Теперь же при модернизации устройства стало возможным подключать до 64 таких устройств к одному ПК. Если изначально известно сколько будет устройств подключено или использовано в данной задаче, то вопросов не возникает, но! Поставлена задача написать универсальный класс для работы с любым количеством устройств. Как выполнить данную задачу, если пишется класс с static функцией на которую ссылаются все SetCallback и при этом нет возможности понять, с какова устройства пришел непосредственно вызов.
Править драйвера устройства нет возможности. На данный момент есть мысль: написать обработчик в виде DLL и запускать столько копий DLL сколько устройств.
Платформа Windows, но если есть более универсальный способ – буду только рад.
Здравствуйте, LeonCrew, Вы писали:
LC>Коллеги, посоветуйте, как лучше организовать обработку вызова Callback. LC>Изначально к ПК можно было подключать только одно устройство и в драйверах никто не предусмотрел идентификатор устройства при вызове Callback функции. Фактически, разработчик делал так: 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)
Можно сделать динамическую генерацию функций-врапперов.
Если колбяка типа __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 ); вторым параметром суем указатель на наш динамически сгенеренный враппер.
Здравствуйте, apple-antonovka, Вы писали:
AA>Можно сделать динамическую генерацию функций-врапперов. AA>Если колбяка типа __stdcall и код нужен для х8 то всего делов то:
Если ограничение в 64 устройства достаточно жесткое, то не вижу никакого смысла городить платформенно-зависимый ассемблерный огород.
It's kind of fun to do the impossible (Walt Disney)
AA>Может, я что-то не так понял, но тем не менее. Если известно, что устройств не больше, чем 64, то нельзя ли просто написать 64 небольших функции-транслятора и новый SetCallbackEx:
Главное, чтобы потом инженерам не пришло в голову создать еще более "большое устройство" из этих малых устройств, например из 256
AA>P.S. Чтобы избежать новых проблем в будущем, я бы сразу сделал не SetCallback, а AddCallback/RemoveCallback. Для поддержки множества слушателей.
Драйвера писал человек который больше не работает и похоже, что исходники ушли вместе с ним....
Здравствуйте, apple-antonovka, Вы писали:
AA>Можно сделать динамическую генерацию функций-врапперов. AA>Если колбяка типа __stdcall и код нужен для х8 то всего делов то: AA>Выделить страницу памяти через VirtualAlloc с PAGE_EXECUTE (можно и простым malloc'ом если не важна совместимость с DEP)
AA>Соответственно в SetCallback( DeviceId, CallbackFunc ); вторым параметром суем указатель на наш динамически сгенеренный враппер.
Подход интерестный, но будет ли он работать в Vista? Как-то в свете последних лет, microsoft упорно пыталась препятствовать данным трюкам.
LC>Подход интерестный, но будет ли он работать в Vista? Как-то в свете последних лет, microsoft упорно пыталась препятствовать данным трюкам.
А кудаж он денется? VirtualAlloc там все так же выделяет PAGE_EXECUTE_..., а __stdcall — он и в Африке __stdcall
Здравствуйте, 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)