PCCERT_CONTEXT = ^_CERT_CONTEXT;
type
TCert = record
SubjName : PChar;
CertCTX : PCCERT_CONTEXT;
end;
TCertArray = array [0..65535] of TCert;
PCertArray = ^TCertArray;
var pmas: PCertArray;
procedure ...();
begin
GetMem(pmas, sizeof(TCert)*2);
Sample(pmas, 2); //Вызываем функцию из Dll
end;
Как передать массив в dll
type TCert = record
SubjName : PChar;
CertCTX : PCCERT_CONTEXT;
end;
В dll (написанной мною на Делфи) есть функция:
function Sample(var mas : array of TCert) : integer; export;
Как мне из программы ее вызвать и передать массив mas туда по ссылке чтобы он пришел в функцию dll корректно?
a := Sample(mas);
mas[0].CertCTX = $160B15
mas[1].CertCTX = $160B15
а когда он с этими данными приходит в функцию Dll, там ваще какая то фигня типа:
{{mas[0].CertCTX = NULL } {mas[0].CertCTX = NULL}...}
Это ведь не нормально? соответственно когда я туда пробую писать чтото, то валятся ошибки... Решение я чувствую где то рядом и совсем простое..
ShareMem подключил?
В упрощенном виде выглядит это так:
******Программа******************
type TCert = record
SubjName : PChar;
CertCTX : PCCERT_CONTEXT;
end;
PCCERT_CONTEXT = ^_CERT_CONTEXT
var mas : array of TCert;
procedure ...();
begin
SetLength(mas, 2);
Sample(mas); //Вызываем функцию из Dll
end;
**************************
В длл-ке: function Sample(var mas : array of TCert) : integer; export;
Что происходит: массив размером 2 уходит в dll с пустым содержимым. Как он приходит в dll я не знаю, просто Делфи начинает очень криво отображать если в AddWatch загнать mas. Далее массив заполняется и поидее возвращается программе.
Так вот я выяснил что перед выходом из процедуры Sample массив заполнен данными!
mas[0].SubjName = "testtest"
mas[0].CertCTX = "$1608B12"
и в программу приходит ПОЧТИ правильно!
mas[0].SubjName = "testtest"
mas[0].CertCTX = nil - но почему тут nil??
Код:
В длл-ке: function Sample(pmas: PCertArray; Items: Integer): integer; export;
А перед этим проверь, интерфейсная часть твоей записи объявлена лишь в одном модуле который используется как в dll-ке так и в программе?
Я честно скоро сойду с ума с этой задачей. Я уже неделю ее пишу и ни на шаг не продвинулся.
Проблема еще в том, что у меня на работе делфи 7, а дома - 2009. И код не совместим, как это не парадоксально. В 7-ке я сделал такой код который работает как надо, без ошибок после закрытия приложения. Но функцию я посадил в тело программы а не в dll. В 2009-ом тоже самое естественно не работает.
Я не знаю что делать... давайте начнем разговор с более общих вещей.
Код который я привел должен быть совместим across versions. Давай выкладывай компилирующийся пример
http://depositfiles.com/files/phyd25hxq
Вот инструкция что нужно сделать с архивом:
1. Установить сертификаты из папки "Сертификаты". Запускаем каждый *.cer, на первой закладке кнопка "установить сертификат". Появляется окно, нажимаем "далее". Выбираем "Поместить все сертификаты в следующее хранилище". Обзор. Должен быть выбран пункт "Личные". ОК. Далее. Готово. Так оба сертификата
2. Посмотреть сертификаты можно если набрать в выполнить: certmgr.msc
Самая верхняя папка - "личные" Вот их мы и должны получить в программе
3. В папке win32api - все модули какие тока может запросить делфи. Самые важные уже лежат в одной папке с проектом(wcrypt.pas, jwa*.pas).
4. Приложение - Project1. dpr
5. Библиотека - XCryptoLib.dpr
В программе и библиотеке все настроено друг на друга(кода минимум оставил, комменты максимум), но почему то валяться ошибки. Я запутался уже совсем там с памятью, с копированием данных, указателей и т.п
PS: буду очень благодарен если кто поможет :) обещаю бесплатно выслать продукт над которым сейчас работаю, бета которого намечена на декабрь 2008.
Ну я только лишь "слегка" взглянул и сразу увидел классическую ошибку которую ты допустил: разделяемая между приложением и библиотекой структура объявлена 2 раза - и там, и там. И естественно эти объявления отличаются. Запомни: когда пишешь приложение предоставляющее или использующее внешний интерфейс (будь то плагин или один проект на несколько человек) - интерфейсные модули должны быть вынесены отдельно и использоваться каждым "куском" приложения - они должны быть разделяемы между кусками. Все эти объявления экспортируемых функций, разделяемых структур и т. д. должны быть в отдельном модуле, который будет использовать и библиотека и программа.
Решение проблемы (для тех у такая же проблема была):
Вынес описание структуры TCert и описания функций dll которые раньше в программе лежали в отдельный *.pas файл, подключил его в uses в библиотеке и в проге самой
Phodopus говори e-mail, и ФИО свое. С меня причитается ;-)
PS: у меня кстати новый вопрос, почему нельзя при загрузки программы загрузить dll динамически, а дальше исользовать ее функции в теле программы на всем протяжении ее работы. А потом при закрытии программы освободить память и выгрузить библиотеку? Выдает ошибку access violation
но если надо обязательно динамически, то гони код загрузки и код выгрузки. :)
Объявления в разделе interface:
Код:
var
frmMain: TfrmMain;
hndDLLHandle: THandle;
DFunc: TDFunc;
type
TDFunc = procedure (par1 : DWord; par2 : DWORD);
frmMain: TfrmMain;
hndDLLHandle: THandle;
DFunc: TDFunc;
type
TDFunc = procedure (par1 : DWord; par2 : DWORD);
Загрузка:
Код:
procedure TfrmMain.FormCreate(Sender: TObject);
begin
try
hndDLLHandle := loadLibrary ( 'Mylib.dll' );
if hndDLLHandle <> 0 then
begin
@DFunc := getProcAddress (hndDLLHandle, 'DFunc');
end;
exit;
finally
freeLibrary ( hndDLLHandle );
end;
end;
begin
try
hndDLLHandle := loadLibrary ( 'Mylib.dll' );
if hndDLLHandle <> 0 then
begin
@DFunc := getProcAddress (hndDLLHandle, 'DFunc');
end;
exit;
finally
freeLibrary ( hndDLLHandle );
end;
end;
Выгрузка:
Код:
procedure TfrmMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
freeLibrary ( hndDLLHandle );
end;
begin
freeLibrary ( hndDLLHandle );
end;
[highlight=delphi]
procedure TfrmMain.FormCreate(Sender: TObject);
begin
hndDLLHandle := loadLibrary( 'Mylib.dll' );
if hndDLLHandle <> 0 then
begin
@DFunc := getProcAddress (hndDLLHandle, 'DFunc');
end;
end;[/highlight]