ситуация такая — нужно к стороннему симулятору (автомобильного трафика) подключить мой модуль управления (который должен будет разруливать траффик в симуляторе). причем нужно, чтобы при старте симуляции модуль бы инициализировался из файла нужными пользовательскими настройками.
правильно я вижу подход к решению данной проблемы:
— организую в dll-ке статический объект, вмещающий в себя собственно ядро модуля управления;
— в конструктор объекта всмещаю загрузку из файла настроек и инициализацию ядра;
— организую в dll-ке функции, обсепечивающие интерфейс работы симулятора с модулем.
в таком варианте меня смущает следующее: если за загрузку dll-ки в общем случае отвечает операционная система, как обеспечить гарантированную переинициализацию объекта новыми настройками (ведь может же случиться так, что операционная система не выгрузит из памяти старуюю dll-ку со старым объектом, и при новой симуляции, начнет использовать его же).
Здравствуйте, _hum_, Вы писали:
__>ситуация такая — нужно к стороннему симулятору (автомобильного трафика) подключить мой модуль управления (который должен будет разруливать траффик в симуляторе). причем нужно, чтобы при старте симуляции модуль бы инициализировался из файла нужными пользовательскими настройками.
Симулятор — это отдельный EXE, так? И DLL твоя ему никак не нужна, он ее не загрузит. Как ты хочешь ему ее впихнуть ?
__>правильно я вижу подход к решению данной проблемы:
__>- организую в dll-ке статический объект, вмещающий в себя собственно ядро модуля управления; __>- в конструктор объекта всмещаю загрузку из файла настроек и инициализацию ядра;
До сих пор все ясно
__>- организую в dll-ке функции, обсепечивающие интерфейс работы симулятора с модулем.
А вот тут надо уточнить. Что за интерфейс с работающим симулятором (отдельным процессом, не использующим эту DLL) ?
__>в таком варианте меня смущает следующее: если за загрузку dll-ки в общем случае отвечает операционная система
DLL никуда сама не загружается. Ее явно или неявно загружает некий процесс, и при этом не симулятор (которому она не нужна), а твой процесс, который ее загрузит , и о котором ты ничего пока не сказал.
>, как обеспечить гарантированную переинициализацию объекта новыми настройками (ведь может же случиться так, что операционная система не выгрузит из памяти старуюю dll-ку со старым объектом, и при новой симуляции, начнет использовать его же).
Если твой процесс DLL загрузит — может и выгрузить, и перезагрузить.
Мне кажется, ты не совсем верно понимаешь принципы функционирования процессов и подключения DLL. Опиши лучше подробнее задачу. В чужой процесс (симулятор) ты не вмешаешься так просто и DLL ему не впихнешь (разве что хуком, но это особая песня)
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, _hum_, Вы писали:
__>>ситуация такая — нужно к стороннему симулятору (автомобильного трафика) подключить мой модуль управления (который должен будет разруливать траффик в симуляторе). причем нужно, чтобы при старте симуляции модуль бы инициализировался из файла нужными пользовательскими настройками.
PD>Симулятор — это отдельный EXE, так? И DLL твоя ему никак не нужна, он ее не загрузит. Как ты хочешь ему ее впихнуть ?
да, симулятор — это отдельный exe
ну, я предполагаю, что у симулятора есть предопределенный свой интерфейс работы с внешними модулями. он, например, делает у себя загрузку библиотеки, имеющей предопределенное фиксированное имя , и вызывает из этой библиотеки функции с заранее предопределенными именами.
типа
// simulator sideauto hLibrary = LoadLibrary("external_control_module.dll");
if (hLibrary != NULL)
{
auto Func = (int(*)(void)) GetProcAddress(hLibrary, "GetControlValue");
if (Func != NULL)
{
int x = ((Func)(x ));
//<....>
};
};
PD>Если твой процесс DLL загрузит — может и выгрузить, и перезагрузить.
вы про FreeLibrary ? если да, то ведь это не обязывает операционную систему выгружать ее совсем из памяти.
Здравствуйте, _hum_, Вы писали:
__>правильно я вижу подход к решению данной проблемы:
зависит от модели взаимодействия .exe и твоего плагина
покажи сигнатуру методов, которые нужно реализовать в плагине
особенно важны методы, отвечающие за создание\удаление плагинной логики, старт\стоп симуляции. если ты их не видишь, то надо искать внимательнее. можешь дать ссылку на симулятор и подробную доку от него, сами поищем
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, _hum_, Вы писали:
__>>правильно я вижу подход к решению данной проблемы:
U>зависит от модели взаимодействия .exe и твоего плагина U>покажи сигнатуру методов, которые нужно реализовать в плагине U>особенно важны методы, отвечающие за создание\удаление плагинной логики, старт\стоп симуляции. если ты их не видишь, то надо искать внимательнее. можешь дать ссылку на симулятор и подробную доку от него, сами поищем
спасибо, но я пока еще не знаю, какой именно будет симулятор использоваться, просто прикидываю в голове, как оно вообще может быть, чтоб заранее накидать заготовки и тем самым потом сэкономить время
скорее всего, какой-нибудь PTV VISSIM. а там, судя по брошюре:
External Signal Control
This module allows users to simulate signal controllers that are available as a separate application (*.exe) or a program library (*.dll). These can either be standard controllers supplied by PTV AG or other providers or control procedures that users have developed themselves (using the API add-on).
API package (Application Programmer’s Interface):
PTV Vissim API package enables users to integrate their own or external applications in order to take influence on a PTV Vissim simulation.
The SignalControl.DLL and SignalGUI.DLL allow for the integration of user-defined signal controllers as DLLs. Functionality is provided to read relevant information (detector information, current signal states) and write signal states.
Здравствуйте, _hum_, Вы писали:
__>спасибо, но я пока еще не знаю, какой именно будет симулятор использоваться, просто прикидываю в голове, как оно вообще может быть, чтоб заранее накидать заготовки и тем самым потом сэкономить время __>скорее всего, какой-нибудь PTV VISSIM. а там, судя по брошюре:
движок вызывает плагин в зависимости от фазы init\create\kill
#define DRIVER_COMMAND_INIT 0
/* called from VISSIM once at the start of a simulation run */
/* values set before: DRIVER_DATA_PATH */
/* DRIVER_DATA_TIMESTEP */
/* DRIVER_DATA_TIME */
/* values got after: DRIVER_DATA_WANTS_SUGGESTION */
/* DRIVER_DATA_AUTOMATIC_LANECHANGE */#define DRIVER_COMMAND_CREATE_DRIVER 1
/* called from VISSIM once per vehicle entering the network */
/* values set before: DRIVER_DATA_VEH_ID */
/* DRIVER_DATA_VEH_DESIRED_VELOCITY */#define DRIVER_COMMAND_KILL_DRIVER 2
/* called from VISSIM once per vehicle leaving the network */
/* value set before: DRIVER_DATA_VEH_ID */#define DRIVER_COMMAND_MOVE_DRIVER 3
/* called from VISSIM once per time step during a simulation run */
/* values set before: all values */
/* (driving behaviour data only if */
/* DRIVER_DATA_WANTS_SUGGESTION) */
/*--------------------------------------------------------------------------*/
DRIVERMODEL_API int DriverModelExecuteCommand (long number);
/* Executes the command <number> if that is available in the driver */
/* module. Return value is 1 on success, otherwise 0. */
/*==========================================================================*/
смотрите сами, хватит ли вам таких уведомлений
по какому правилу движок выгружает плагины — опять же надо либо в доках искать, либо экспериментировать (логировать хуки в плагине, а потом изучать)
Здравствуйте, uzhas, Вы писали:
U>по какому правилу движок выгружает плагины — опять же надо либо в доках искать, либо экспериментировать (логировать хуки в плагине, а потом изучать)
есть доки в таком духе:
Vissim Signal Controller DLL Interface LK 2016-04-27
This document describes how external controllers can be connected to Vissim through a DLL interface (available since Vissim 4.10) to be used during simulation and/or test runs.
Introduction
Since Vissim 6, all signal controllers (SCs) are simulated by an external program. If this program file is an *.exe, the old DDE interface is used and one instance of this *.exe is started for each SC using it during a simulation run. If the program file is a *.dll, however, the DLL interface is used. This means that the *.dll is loaded only once for a simulation run and has to handle the controller logic and data for all SCs that it is assigned to.
The controller frequency (usually 1/s) defines how many controller time steps (passes through the controller logic) must take place per simulation second. It is set by the external controller during the initialization sequence. The simulation resolution in Vissim (simulation time steps per simulation second) must be a multiple of the controller frequency. Other combinations of values cause run-time errors. (Example: If the simulation resolution is 10 and the controller frequency is 2, Vissim simulates 5 simulation time steps between two passes through the controller logic.)
In each controller time step Vissim contacts all controller DLLs at the end of the current simulation time step. First, the current signalization states and detector data of all SCs are passed to the respective DLLs. Second, the DLLs are asked to calculate new desired signal states which are subsequently passed back to Vissim. Depending on parameters set by the controller logic, either these signal states are applied immediately, or transition states (e.g. amber when switching from green to red) are inserted automatically, as defined in the signal group parameters in Vissim. In the next simulation time step the vehicles in Vissim will react on the new signalization.
Module structure
The source code of a signal controller DLL for Vissim consists of a frame which handles the communication with Vissim and a kernel which contains the actual control strategy. The modules of the frame are made available by PTV in form of C(++) source code and only sc_dll_main.cpp needs to be adapted for the connection of the kernel. The kernel must exist as C(++) source code, too. Suitable kernel functions must be called from sc_dll_main.cpp and the kernel can call data access functions from module sc_dll_functions.cpp/.h on its part. The technical details of the DLL communication are transparent for the kernel.
(If a controller process with an existing interface (e.g. TCP/IP) is to be connected to Vissim, it is recommended to create a signal control DLL that interfaces between the Vissim data format and the controller data format. In this case the complete handling of the communication between the signal control DLL and the controller process needs to be done in the kernel.)
Control flow
At the start of a simulation/test run Vissim loads each signal control DLL that is used by at least one SC in the current network. (The DLL is usually located in the same directory as Vissim.exe or in the current data directory.)
The subsequent initialization sequence for each SC has two parts:
First, Vissim calls the function SC_DLL_ReadDataFiles(). This function has the (up to) two data filenames as parameters that can be entered in the SC dialog box in Vissim.
uzhas, спасибо. надо будет разобраться, как у них там все сделано, и зачем они предполагают использование cpp-шников, но, на ваш взгляд, мое вышеописанное представление, в целом, верно (чтоб от него отталкиваться при разборе док)?
Здравствуйте, _hum_, Вы писали:
__>ну, я предполагаю, что у симулятора есть предопределенный свой интерфейс работы с внешними модулями. он, например, делает у себя загрузку библиотеки, имеющей предопределенное фиксированное имя , и вызывает из этой библиотеки функции с заранее предопределенными именами.
Предполагаю — не разговор. Точно есть ?
PD>>Если твой процесс DLL загрузит — может и выгрузить, и перезагрузить.
__>вы про FreeLibrary ? если да, то ведь это не обязывает операционную систему выгружать ее совсем из памяти.
Почему не обязывает? Вполне обязывает.
Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference count reaches zero, the module is unloaded from the address space of the calling process and the handle is no longer valid
Здравствуйте, _hum_, Вы писали:
__>uzhas, спасибо. надо будет разобраться, как у них там все сделано, и зачем они предполагают использование cpp-шников, но, на ваш взгляд, мое вышеописанное представление, в целом, верно (чтоб от него отталкиваться при разборе док)?
я бы порекомендовал след. подход в своей .dll:
1) создаем глобальный объект, который в себе будет держать конфиг и логику (можно несколько объектов, главное ниже)
2) в конструкторе класса ничего сложного не делаем (особенно работу с файлами)
3) при вызове хука на инициализацию мы читаем нужные файлы и инициализируем плагинную логику
4) в деструкторе тоже с файлами не работаем, просто освобождаем память
длл может выгрузить симулятор, это нам не страшно — легкий деструктор вызовется и почистит память
если же симулятор снова решит загрузить нашу dll, то он обязан будет вызвать хук инициализации, мы его уже поддерживаем. см. пункт 3
Здравствуйте, uzhas, Вы писали:
U>Здравствуйте, _hum_, Вы писали:
__>>uzhas, спасибо. надо будет разобраться, как у них там все сделано, и зачем они предполагают использование cpp-шников, но, на ваш взгляд, мое вышеописанное представление, в целом, верно (чтоб от него отталкиваться при разборе док)?
U>я бы порекомендовал след. подход в своей .dll: U>1) создаем глобальный объект, который в себе будет держать конфиг и логику (можно несколько объектов, главное ниже) U>2) в конструкторе класса ничего сложного не делаем (особенно работу с файлами) U>3) при вызове хука на инициализацию мы читаем нужные файлы и инициализируем плагинную логику U>4) в деструкторе тоже с файлами не работаем, просто освобождаем память
U>длл может выгрузить симулятор, это нам не страшно — легкий деструктор вызовется и почистит память U>если же симулятор снова решит загрузить нашу dll, то он обязан будет вызвать хук инициализации, мы его уже поддерживаем. см. пункт 3
U>почему в конструкторах и деструкторах не следует делать чего-то сложного (к примеру, явно или неявно делать LoadLibrary), можно почитать тут: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx
да, если предполагается вызов инициализатора, то, конечно, лучше вынести за пределы конструктора.
кстати, а почему вы считаете, что глобальная лучше, чем статическая локальная? вроде ж изначально все советуют избегать глобальных переменных.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Здравствуйте, _hum_, Вы писали:
__>>вы про FreeLibrary ? если да, то ведь это не обязывает операционную систему выгружать ее совсем из памяти.
PD>Почему не обязывает? Вполне обязывает.
PD>Frees the loaded dynamic-link library (DLL) module and, if necessary, decrements its reference count. When the reference count reaches zero, the module is unloaded from the address space of the calling process and the handle is no longer valid
PD>https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms683152(v=vs.85).aspx
Здравствуйте, _hum_, Вы писали:
__>кстати, а почему вы считаете, что глобальная лучше, чем статическая локальная? вроде ж изначально все советуют избегать глобальных переменных.
я ничего такого не имел в виду. вас в ненужную сторону повело (в офтоп). попробую уточнить, что я назвал "глобальной"
хуки у длл являются глобальными точками входа в код этой длл. грамотные API (это не ваш случай) готовы работать с несколькими инстансами логики из длл
API обычно выглядит так
void* CreateLogic();
void DeleteLogic(void* handle);
int CalculateSomething(void* handle, int params);
внутри хуков можно работать лишь с входными параметрами и не обращаться куда-то. при этом время жизни выделенных объектов полностью контролируется через хуки и нет надобности что-то держать в глобальных переменных
как раз в вашем случае придется работать с такими переменными, т.к. в хуки не передается контекст явно
под глобальными переменными имеются в виду автоматические переменные, которые переживают период вызова хука. с точки зрения плюсов это могут быть глобальные переменные, статические (как на уровне функции, так и на уровне класса или TU) (всякие tls, реестр, файлы, базы данных оставим за скобками, хотя и они могут хранить некое глобальное состояние приложения). деструкторы у этих переменных вызываются сишным рантаймом перед выгрузкой .dll
можно вместо "глобальный" употребить "неявное состояние" (или контекст, или синглтон), с которым работает хук. как вы это в коде оформите — вопрос десятый, суть будет одна
Здравствуйте, uzhas, Вы писали:
U>можно вместо "глобальный" употребить "неявное состояние" (или контекст, или синглтон), с которым работает хук. как вы это в коде оформите — вопрос десятый, суть будет одна
Здравствуйте, _hum_, Вы писали:
__>- в конструктор объекта всмещаю загрузку из файла настроек и инициализацию ядра;
Лучше избегать сложную логику в конструкторах/деструкторах глобальных объектов в DLL.
Потому что они вызываются из DllMain (с флагами DLL_PROCESS_ATTACH/DLL_PROCESS_DETACH соотвественно)
Если есть в API такая пара функций, которые бы вызывались в начале и в конце работы, то лучше фактическое конструирование глобального объекта через них сделать.
Здравствуйте, _hum_, Вы писали:
__>ситуация такая — нужно к стороннему симулятору (автомобильного трафика) подключить мой модуль управления (который должен будет разруливать траффик в симуляторе). причем нужно, чтобы при старте симуляции модуль бы инициализировался из файла нужными пользовательскими настройками. __>правильно я вижу подход к решению данной проблемы:
__>- организую в dll-ке статический объект, вмещающий в себя собственно ядро модуля управления; __>- в конструктор объекта всмещаю загрузку из файла настроек и инициализацию ядра; __>- организую в dll-ке функции, обсепечивающие интерфейс работы симулятора с модулем.
__>в таком варианте меня смущает следующее: если за загрузку dll-ки в общем случае отвечает операционная система, как обеспечить гарантированную переинициализацию объекта новыми настройками (ведь может же случиться так, что операционная система не выгрузит из памяти старуюю dll-ку со старым объектом, и при новой симуляции, начнет использовать его же).
Я бы всю работу с модулем поместил в один интерфейс, описанный в одном *.h файле.
#ifdef EXPORT_ROUTE
//При сборке dll взводить EXPORT_ROUTE#define ROUTELIB_API __declspec(dllexport)
#else//Если компонент используется как зависимость, то будет импорт#define ROUTELIB_API __declspec(dllimport)
#endif//Все методы в стиле plain c, что бы не зависеть от языка на стороне клиента
//Указатель на объект, реализующий управление(Router)typedef struct IRouter * RouterCorePtr;
//Создать объект
ROUTELIB_API int CreateRouterCore( RouterCorePtr * core_ptr);
//загрузка данных лучше не в конструкторе а отдельным методом
ROUTELIB_API LoadData( const char * data_path );
//Функции для работы с компонентом
ROUTELIB_API double GetCurrentTraffic( RouterCorePtr * core_ptr, int route_id );
//....
//Освободить объект
ROUTELIB_API int ReleaseRouterCore( RouterCorePtr * core_ptr );
//Коды ошибокnamespace router_results
{
const int ok = 0;
const int internal_err = -1;
//....
}
На стороне компонента:
typedef Router * Router_ptr;
ROUTELIB_API CreateRouterCore( RouterCorePtr * core_ptr )
{
Router_ptr router_ptr = new Router();
*core_ptr = reinterpret_cast<RouterCorePtr >( router_ptr );
}
ROUTELIB_API double GetCurrentTraffic( RouterCorePtr * core_ptr, int route_id )
{
//И так во всех методах кастим указатель. Всё это с проверками, конечно
Router_ptr router_ptr = reinterpret_cast<Router_ptr>( core_ptr );
//Собственно вызовreturn router_ptr->GetCurrentTraffic( route_id );
}
Полагаться на статический объект в DLL я бы не стал. Лучше пусть инициализацией явным образом управляет клиент.
Здравствуйте, TimurSPB, Вы писали: TSP>Здравствуйте, _hum_, Вы писали: __>>ситуация такая — нужно к стороннему симулятору (автомобильного трафика) подключить мой модуль управления (который должен будет разруливать траффик в симуляторе). причем нужно, чтобы при старте симуляции модуль бы инициализировался из файла нужными пользовательскими настройками. __>>правильно я вижу подход к решению данной проблемы: __>>- организую в dll-ке статический объект, вмещающий в себя собственно ядро модуля управления; __>>- в конструктор объекта всмещаю загрузку из файла настроек и инициализацию ядра; __>>- организую в dll-ке функции, обсепечивающие интерфейс работы симулятора с модулем. __>>в таком варианте меня смущает следующее: если за загрузку dll-ки в общем случае отвечает операционная система, как обеспечить гарантированную переинициализацию объекта новыми настройками (ведь может же случиться так, что операционная система не выгрузит из памяти старуюю dll-ку со старым объектом, и при новой симуляции, начнет использовать его же). TSP>Я бы всю работу с модулем поместил в один интерфейс, описанный в одном *.h файле.
code
TSP>
TSP> #ifdef EXPORT_ROUTE
TSP> //При сборке dll взводить EXPORT_ROUTE
TSP> #define ROUTELIB_API __declspec(dllexport)
TSP> #else
TSP> //Если компонент используется как зависимость, то будет импорт
TSP> #define ROUTELIB_API __declspec(dllimport)
TSP> #endif
TSP> //Все методы в стиле plain c, что бы не зависеть от языка на стороне клиента
TSP> //Указатель на объект, реализующий управление(Router)
TSP> typedef struct IRouter * RouterCorePtr;
TSP> //Создать объект
TSP> ROUTELIB_API int CreateRouterCore( RouterCorePtr * core_ptr);
TSP> //загрузка данных лучше не в конструкторе а отдельным методом
TSP> ROUTELIB_API LoadData( const char * data_path );
TSP> //Функции для работы с компонентом
TSP> ROUTELIB_API double GetCurrentTraffic( RouterCorePtr * core_ptr, int route_id );
TSP> //....
TSP> //Освободить объект
TSP> ROUTELIB_API int ReleaseRouterCore( RouterCorePtr * core_ptr );
TSP> //Коды ошибок
TSP> namespace router_results
TSP> {
TSP> const int ok = 0;
TSP> const int internal_err = -1;
TSP> //....
TSP> }
TSP>
TSP>На стороне компонента: TSP>
TSP> typedef Router * Router_ptr;
TSP> ROUTELIB_API CreateRouterCore( RouterCorePtr * core_ptr )
TSP> {
TSP> Router_ptr router_ptr = new Router();
TSP> *core_ptr = reinterpret_cast<RouterCorePtr >( router_ptr );
TSP> }
TSP> ROUTELIB_API double GetCurrentTraffic( RouterCorePtr * core_ptr, int route_id )
TSP> {
TSP> //И так во всех методах кастим указатель. Всё это с проверками, конечно
TSP> Router_ptr router_ptr = reinterpret_cast<Router_ptr>( core_ptr );
TSP> //Собственно вызов
TSP> return router_ptr->GetCurrentTraffic( route_id );
TSP> }
TSP>
TSP>Полагаться на статический объект в DLL я бы не стал. Лучше пусть инициализацией явным образом управляет клиент.
такой вариант не пройдет, потому как требует перекпомпиляцию симулятора (если, конечно, я правильно понял вашу идею)
Здравствуйте, Alexander G, Вы писали:
AG>Здравствуйте, _hum_, Вы писали:
__>>- в конструктор объекта всмещаю загрузку из файла настроек и инициализацию ядра;
AG>Лучше избегать сложную логику в конструкторах/деструкторах глобальных объектов в DLL. AG>Потому что они вызываются из DllMain (с флагами DLL_PROCESS_ATTACH/DLL_PROCESS_DETACH соотвественно)
AG>Вот тут написано, чего конкретно следует избегать AG>https://msdn.microsoft.com/en-us/library/windows/desktop/dn633971.aspx
AG>Если есть в API такая пара функций, которые бы вызывались в начале и в конце работы, то лучше фактическое конструирование глобального объекта через них сделать.
TSP>>Полагаться на статический объект в DLL я бы не стал. Лучше пусть инициализацией явным образом управляет клиент. __>такой вариант не пройдет, потому как требует перекпомпиляцию симулятора (если, конечно, я правильно понял вашу идею)
Тогда надо смотреть на протокол работы симулятора с компонентом.
Если всё in-process то возможны варианты:
1. Инициализация не выделена отдельно. Тогда шаманить с событиями загрузки DLL. Это вариант так себе, но что делать.
2. Там есть явный init без параметров. В нем уже и можно будет делать создание некоторого синглетона, который все реализует.
3. Если там фигурирует некий handle в каждом вызове, то я в таких случаях делаю как в исходном ответе. Храним в handle указатель на свои объекты и кастим его при вызове.
Если там RPC, COM и прочее, то там всё в соответствии с конкретной используемой технологией.
Здравствуйте, TimurSPB, Вы писали:
TSP>>>Полагаться на статический объект в DLL я бы не стал. Лучше пусть инициализацией явным образом управляет клиент. __>>такой вариант не пройдет, потому как требует перекпомпиляцию симулятора (если, конечно, я правильно понял вашу идею) TSP>Тогда надо смотреть на протокол работы симулятора с компонентом. TSP>Если всё in-process то возможны варианты: TSP>1. Инициализация не выделена отдельно. Тогда шаманить с событиями загрузки DLL. Это вариант так себе, но что делать. TSP>2. Там есть явный init без параметров. В нем уже и можно будет делать создание некоторого синглетона, который все реализует. TSP>3. Если там фигурирует некий handle в каждом вызове, то я в таких случаях делаю как в исходном ответе. Храним в handle указатель на свои объекты и кастим его при вызове. TSP>Если там RPC, COM и прочее, то там всё в соответствии с конкретной используемой технологией.