| 
| 
 | Вопрос # 2 663/ вопрос открыт / | 
 |  Доброго времени суток, уважаемые эксперты!
 Помогите разрешить следующую проблему.
 
 Есть уже разработанная на С++ DDL библиотека доступа к спец. железу.
 Необходимо использовать экспортированные из нее функции в приложение написанном на Delphi.
 С самим экспортом проблем нет (делается штатно - либо статически либо динамически с соответствующим приведением типов). Проблема в том, что некоторые функции этой библиотеки используют захват памяти  на своей стороне с помощью сишной функции CoTaskMemAlloc(...), а освобождаться захваченная память должна на стороне пользователя (т.е. в Delpfi приложении) которое эту библиотеку будет использует.
 
 например для функции GetDevices(...) из C++ DLL библиотеки:
 
 EXTERN_C __declspec( dllexport ) int GetDevices(unsigned __int64 ** devices, int *count)
 {
 int r = start();
 if(r != 0)
 {
 return 3;
 }
 unsigned __int64 * DEVICES = NULL;
 if (m_count > 0);
 {
 DEVICES = (unsigned __int64 *)CoTaskMemAlloc(sizeof(unsigned __int64) * m_count);
 for (int i = 0; i < m_count; i++)
 {
 DEVICES[i] = dev[i].addr;
 }
 }
 *devices = DEVICES;
 *count = m_count;
 return 0;
 }
 
 
 В вызывающем приложении на С# это делается легко и будет выглядеть так:
 ...
 ulong megaADDR = 0;
 ...
 unsafe
 {
 int count = 0;
 
 IntPtr ptr = IntPtr.Zero;
 GetDevices(ref ptr, out count);
 
 ulong* p = (ulong*)ptr.ToPointer();
 
 if (count > 0)
 {
 megaADDR = ((ulong*)ptr.ToPointer())[0]; // Или другой какой нибуть индекс по массиву
 }
 
 Marshal.FreeCoTaskMem(ptr);
 }
 ...
 
 А как тоже самое сделать в приложении написанном на Delphi ???
 Заодно подскажите как указатель на указатель в Delpfi лучше оформить для сишной функции GetDevices(unsigned __int64 ** devices, int *count) из DLL?
 
|  |   Вопрос задал: VictorK (статус: Посетитель)Вопрос отправлен: 19 апреля 2009, 20:22
 Состояние вопроса: открыт, ответов: 0.
 |  
 Мини-форум вопросаВсего сообщений: 8; последнее сообщение — 22 апреля 2009, 19:18; участников в обсуждении: 3. 
|   | Death_Master (статус: Посетитель), 19 апреля 2009, 22:03 [#1]:А может ли сама dll обладать функциями освобождения памяти? Если да, то их можно просто импортировать и вызывать по необходимости...
 Обычно захожу по ночам... (60-70%)Если нужно что-то написать, то беру оборудованием, деньгими и пивом(при личной встрече)...
 P.S. Помогаю и рассказываю бесплатно ^_^.....Nyaaa!
 |  
|   | VictorK (статус: Посетитель), 19 апреля 2009, 22:18 [#2]:Увы, DLL уже разработана и используется давно и многими, т.е. "Отлита в бронзе" и изменению не подлежит. Заказчик заказывает музыку. Можно либо сделать либо отказаться.
 |  
|   | Death_Master (статус: Посетитель), 19 апреля 2009, 22:22 [#3]:В таком случае можно сделать дополнительную dll: прога -> dll- обёртка( с функциями работы с памятью) -> исходная dll
 в такой конфигурации будут все необходимые функции
   Обычно захожу по ночам... (60-70%)Если нужно что-то написать, то беру оборудованием, деньгими и пивом(при личной встрече)...
 P.S. Помогаю и рассказываю бесплатно ^_^.....Nyaaa!
 |  
|   | VictorK (статус: Посетитель), 19 апреля 2009, 22:43 [#4]:Спасибо за идею Death Master. Конечно как крайний вариант доп. Dll-обертка подойдет, но хотелось бы сделать это более естественно как в C#.
 Уж больно много там подобных функций, разбираться переписывать довольно накладно будет.
 |  
|   | Вадим К (статус: Академик), 20 апреля 2009, 21:47 [#5]:А почему просто не взять и не написать это прям так на делфи? например
 (ulong*)ptr.ToPointer();
 это будет
 PLongInt(@prt);
 Что бы сделать массивы, надо просто привести к нужному типу, например есть PByteArray для байтового. правда так как это массив, то надо будет ещё крышечку, то есть где то
 (PByteArray(prt)^)[0]
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | VictorK (статус: Посетитель), 22 апреля 2009, 05:16 [#6]:Спасибо всем за подсказки. 
 С  передачей указателя на указатель массива получилось сделать так:
 
 ....
 
 //  Получение списка устройств
 //EXTERN_C __declspec( dllexport ) int GetDevices(unsigned __int64 ** devices, int *count);
 type
 PUInt64Array = ^TUInt64Array;
 TUInt64Array = array[0..(MaxInt div 16) - 1] of UInt64;
 function GetDevices(var pdevices: pointer; var Count:integer):integer; cdecl;  external RPTDev_DRVDllName name 'GetDevices';
 
 ...
 
 var
 ppDevs: Pointer;  Count: integer;
 i : integer;  DevArray: array of UInt64;
 
 ...
 
 Count:= 0;  ppDevs:= nil;
 GetDevices(ppDevs, Count);
 
 if Count <> 0 then
 begin
 SetLength(DevArray, Count);
 for i := 0 to Count-1 do
 begin
 DevArray[i] := (PUInt64Array(ppDevs)^)[i];
 end;
 end;
 
 
 А вот с освобождением памяти, попробовал использовать
 CoTaskMemFree(ptr); из
 uses Ole2;
 и получил кучу конфликтов имен при компиляции.
 
 Наверное придется либо писать свою Dll-библиотеку, либо уламывать сделать функции вызов освобождения памяти в самой Dll-библиотеке, что-то типа вот так:
 
 В DLL-библиотеке
 // Освобождение памяти массива списока устройств
 EXTERN_C __declspec( dllexport ) int FreeDevices(unsigned __int64* devices)
 {
 CoTaskMemFree(devices);
 return 0;
 }
 
 
 В Delphi - приложении
 ...
 // Освобождение памяти массива списока устройств
 function FreeDevices(var pdevices: PUInt64):integer; cdecl;  external RPTDev_DRVDllName name 'FreeDevices';
 
 ...
 
 FreeDevices(PUInt64(ppDevs^));
 |  
|   | Вадим К (статус: Академик), 22 апреля 2009, 09:02 [#7]:По правилам, память должен освобождать тот, кто её выделил. В противном случае возможна куча проблем. В вторых, освобождать память надо "парной функцией", а не какой попало, что Вы делаете.
 Галочка "подтверждения прочтения" - вселенское зло. |  
|   | VictorK (статус: Посетитель), 22 апреля 2009, 19:18 [#8]:Согласен, память надо освобождать корректно. Увы эта DLL-ка не мое творение, хотелось оставить все как есть.
 Буду просить хозяина DLL-библиотеки добавить парные функции освобождения памяти либо перепишу эту библиотеку сам и как надо.
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |