|
Вопрос # 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-библиотеки добавить парные функции освобождения памяти либо перепишу эту библиотеку сам и как надо.
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|