Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.04.23;
Скачать: CL | DM;

Вниз

Не пойму где ошибка (вызов функции из DLL)   Найти похожие ветки 

 
Хинт ©   (2006-03-30 18:26) [0]

function hGetLastError: PChar;
var
 DLL: THandle;
 hFunc: function: PChar;
begin
 Result := "";
 DLL := LoadLibrary(PChar("hToPr.dll"));
 if (DLL = 0) then
   begin
     Result:="hToPr: ошибка загрузки библиотеки";
     Exit;
   end;
 try
   @hFunc := GetProcAddress(DLL, "hGetLastError");
   if Assigned(@hFunc) then Result:=hFunc else Result:="hToPr: не найдена искомая функция";
 finally
   FreeLibrary(DLL);
 end;
end;

При вызове функции ShowMessage(GetLastError) вылетает ошибка "Access violation at address...". В чем тут ошибка?


 
Хинт ©   (2006-03-30 18:28) [1]

Код библиотеки:

> library hToPr;
>
> uses
>   Windows,
>   Messages,
>   SysUtils,
>   tlHelp32,
>   Classes;
>
> var
>   Error:string;
>
> {$R *.res}
>
> function hGetLastError: PChar; stdcall;
> begin
>  Result:=PChar(Error);
> end;
>
> ...
>
> exports
>  hGetLastError, ...;
> begin
>
> end.
>


 
Гаврила ©   (2006-03-30 18:30) [2]

ощибка в том, что некая бииблиотечная функция, к вызову которой все сводится, неявно освободила память, на которую вернула ссылку


 
Гаврила ©   (2006-03-30 18:30) [3]

А, нет
тогда ошибка скорее всего в соглашении о вызовах


 
han_malign ©   (2006-03-30 18:31) [4]

эээ
@hFunc := GetProcAddress(DLL, "hGetLastError");
  if Assigned(@hFunc) then Result:=hFunc....
- и как ты себе представляешь исполняемый код функции в виде ASCIIZ строки???


 
NightLord ©   (2006-03-30 18:36) [5]

try
  @hFunc := GetProcAddress(DLL, "hGetLastError");
  if Assigned(@hFunc) then Result:=hFunc else Result:="hToPr: не найдена искомая функция";
finally
  FreeLibrary(DLL);
end;
Дак как ты можешь вызвать функцию из библиотеки если ты ее удалил из памяти?


 
NightLord ©   (2006-03-30 18:38) [6]

сорри невнимательно прочитал код библиотеки -(


 
begin...end ©   (2006-03-30 18:40) [7]

> han_malign ©   (30.03.06 18:31) [4]

Вы о чём?


 
Хинт ©   (2006-03-30 18:41) [8]

Совсем не понял смысла [4] и [5]


 
begin...end ©   (2006-03-30 18:42) [9]

> Хинт ©   (30.03.06 18:41) [8]

Главное, чтобы был понятен смысл [3].


 
Rouse_ ©   (2006-03-30 18:43) [10]


> Вы о чём?

Вглядись внимательно в код :)


 
Хинт ©   (2006-03-30 18:43) [11]

Убрать stdcall? Можно немного подробнее


 
Гаврила ©   (2006-03-30 18:44) [12]

Кстати да
во первых - соглашение о вызовах
во вторых
Память то выделена внутри библиотеки
var
 Error:string;
А мы ее выгрузили. А потом читаем по этому адресу.
Нехорошо


 
begin...end ©   (2006-03-30 18:45) [13]

> Rouse_ ©   (30.03.06 18:43) [10]

Вгляделся. И что?


 
Хинт ©   (2006-03-30 18:45) [14]


> во первых - соглашение о вызовах

Убрать stdcall?

> var  Error:string;А мы ее выгрузили. А потом читаем по этому
> адресу.

Т.е. в Result заносится адрес строки, а не сама строка?


 
Rouse_ ©   (2006-03-30 18:47) [15]


> Вгляделся. И что?

Да какбы было бы интересно что делать с результатом...


 
Гаврила ©   (2006-03-30 18:52) [16]


> Убрать stdcall?


с двух сторон должно быть одинаково - или и там и там есть
или и там и там нету

> .е. в Result заносится адрес строки, а не сама строка?


в Result заносится адрес первого символа строки


 
begin...end ©   (2006-03-30 18:54) [17]

Да, похоже, проблема в [12] (2), потому что соглашение о вызовах в данном случае роли не играет. Ввиду отсутствия параметров. Хотя вообще, конечно, правильно, чтобы и там, и там соглашения были одинаковыми.

> Rouse_ ©   (30.03.06 18:47) [15]

Использовать? :)
Я не совсем понял, в чём смысл [4]. Адрес функции получили, саму функцию вызвали. Что не так-то?


 
Хинт ©   (2006-03-30 18:59) [18]

Без FreeLibrary работает... Ошибка в Result:=hFunc.
Решение: заменить на Result:=PChar(Copy(hFunc,0,255))?
А как сообщить о соглашении в функции из [1]?


 
Хинт ©   (2006-03-30 19:04) [19]

Хм. Вот вызов другой функции:
function hCodeInject(PID: integer): boolean;
var
 func: function(PID: integer): boolean;
 LibHandle: THandle;
begin
 Result := false;
 @func := nil;
 LibHandle := LoadLibrary(lname);
 if LibHandle >= 32 then
   begin
     @func := GetProcAddress(LibHandle, "hCodeInject");
     if @func <> nil then Result := func(PID);
   end;
 FreeLibrary(LibHandle);
end;

Опять же "Access violation at address...", хотя никаких PChar"ов тут уже нет


 
Хинт ©   (2006-03-30 20:28) [20]

Чудеса! Из-под IDE работает нормально, а отдельно без Delphi уже "Access violation at address..."


 
Гаврила ©   (2006-03-30 23:25) [21]


> Без FreeLibrary работает...


> Опять же "Access violation at address...", хотя
> никаких PChar"ов тут уже нет


Проверь еще, может быть где-то косяк в самой библиотеке на финализации юнитов.
Хотя я почти уверен, что в примере
func: function(PID: integer): boolean;
опять не соблюдено соглашение о вызовах


 
Alexander Panov ©   (2006-03-31 00:04) [22]

>Хинт

Возьми за правило - выделять, изменять размер, освобождать память в одном месте. Если выделяешь в основной программе, в ней же освобождать и изменять размер. то же самое с DLL.

Для обработки строк в DLL используй стандартный прием, принятый в WINAPI:

Выделяешь в основной программе память, передаешь указатель и длину(!) в DLL. В DLL обрабатываешь, не затрагивая распределение памяти. Далее в основной программе делаешь с памятью все, что угодно.

function ProcessString(Str: PChar; LenStr: Integer): Integer; external "test.dll"; stdcall;

Первый вариант:

function Test(Str: PChar): String;
var
 LenResult: Integer;
begin
 GetMem(Str,500);
 try
   LenResult := ProcessString(Str,500);
   SetLength(Result, LenResult);
   Move(Str[0],Result[1],LenResult);
 finally
   FreeMem(Str);
 end;
end;


Второй вариант:

function Test(Str: String): String;
var
 LenResult: Integer;
begin
 Str := "1234567890";
 LenResult := ProcessString(PChar(Str),Length(Str));
 SetLength(Result, LenResult);
 Result := Str;
end;


Функция в DLL:

function ProcessString(Str: PChar; LenStr: Integer): Integer; stdcall;
var
 s: String;
begin
 s := String(Str);
 if s[1]="1"  
   then s :="Test1"  
   else  s :="Test2";
 if Length(s)>LenStr then SetLength(s,LenStr);
 FillChar(Str[0],LenStr,#0);
 Move(s[1],Str[0],Length(s);
end;


Ну и третий вариант(если кроме Delphi, других языков не будет использоваться) - использовать специальные менеджеры памяти ShareMem или FastMem.



Страницы: 1 вся ветка

Текущий архив: 2006.04.23;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.045 c
9-1127156871
KOT_BEGEMOT
2005-09-19 23:07
2006.04.23
Поворот спрайта в сторону курсора (DelphiX)


2-1144234255
Id
2006-04-05 14:50
2006.04.23
DBComboBox1.Style:=csDropDownList


15-1143781960
Ega23
2006-03-31 09:12
2006.04.23
С Днём рождения! 31 марта


2-1144297950
Alex_C
2006-04-06 08:32
2006.04.23
Как запустить программу и подождать пока откроется основное окно?


15-1143620715
Vlad Oshin
2006-03-29 12:25
2006.04.23
Помогите с входом в bios у Compaq