![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
|
|
#1
|
|||
|
|||
|
Уже пол дня бъюсь на проблемой:
Функция возвращяет неправильные результаты вычисления и после закрытия приложения вываливается "Invalid Pointer Operation". Причём если функцию описать в приложении, то всё работает как надо и ничего не вываливается. Помогите разобраться с причаними DLL код: Код:
uses
ShareMem
. . . . .
function ExtractFileName(FilePath: PChar; ShowExtension: byte): PChar;
var
FNameLength, CopyLength: Word;
FNameTrunc: PChar;
begin
FNameLength := Length(FilePath);
CopyLength := FNameLength;
case ShowExtension of
0: begin
while (FilePath[FNameLength] <> '\') and (FNameLength > 0) do
Dec(FNameLength);
if FNameLength <> 0 then
FNameTrunc := PChar(Copy(FilePath, FNameLength + 2, CopyLength-FNameLength))
else
FNameTrunc := Pchar('');
end;
1: begin
while (FilePath[FNameLength] <> '\') and (FNameLength > 0) do
Dec(FNameLength);
if FNameLength <> 0 then
Begin
FNameTrunc := PChar(Copy(FilePath, FNameLength + 2, CopyLength-FNameLength));
FNameLength :=Length(FNameTrunc);
while (FNameTrunc[FNameLength] <> '.') and (FNameLength > 0) do
Dec(FNameLength);
FNameTrunc := PChar(Copy(FNameTrunc, 1, FNameLength));
End
else
FNameTrunc := PChar('');
end;
2: begin
FNameTrunc := PChar(FilePath);
end;
else
FNameTrunc := PChar('Incorrect input value in Case. Use 0 - Name+Ext; 1 - Name; 2 - full path; Only!');
end;
Result := FNameTrunc;
End;
. . . .
exports
ExtractFileName;Эта функция находится в DLL и предназначения для отделения имени файла от его расширения. Как видно, она имеет 3 режима в зависимости от переданных параметров: 1)Отделить имя и расшир от пути; 2) отделить имя от пути и расшир; 3) собственно ничего не делать. Вызываю из программы её таким способом: Код:
procedure Button1.Click(Sender: TObject);
var
ExtractFileName : Function(FilePath: PChar; ShowExtension: byte) : PChar; Stdcall;
DLLInstance : THandle;
GettedFileName : String;
begin
OpenWordFile(FileOpen1.Dialog.FileName);
@ExtractFileName := nil; //Очищаем адресс функции от мусора
DLLInstance := LoadLibrary(PChar('Main.dll')); //Подгружаем DLL к приложению
if (DLLInstance = 0) then
begin
MessageDlg('Невозможно загрузить DLL', mtError, [mbOK], 0);
Exit;
end;
try
@ExtractFileName := GetProcAddress(DLLInstance, 'ExtractFileName'); //Пытаемся вызвать из DLL указанную фунцию
if Assigned(@ExtractFileName) then
Begin
GettedFileName := 'Файл:' + ' ' + StrPas(ExtractFileName(Pchar(FileOpen1.Dialog.FileName), 0));
AddTextInDB.StatusBar.Panels.Items[0].Text := GettedFileName;
End
else
MessageDlg('Искомая функция не найдена!', mtError, [mbOK], 0);
finally
FreeLibrary(DLLInstance);
end;
End;Так же очень буду признателен за критику стиля написания кода и наличие\отсутствие нужных на ваш взгляд моментов. Последний раз редактировалось Yo_Asakyra, 27.04.2012 в 19:04. |
|
#2
|
|||
|
|||
|
1. Непонятно, зачем вообще писать такую функцию, т.к. есть уже готовые ExtractFileName, ExtractFileExt, ChangeFileExt, etc...
2. Не вижу описание типа импортируемой функции. Возможно засада именно там, т.к. тип передачи параметров должен быть одинаковый и в dll и у типа в вызывающем модуле. 3. Не стоит использовать PChar там, где этого можно избежать. Лучше WideString. А если не из Delphi использовать не требуется, то вообще используй String. 4. Основная ошибка. Память, выделенная в dll, должна освобождаться в dll же. Даже при использовании модуля ShareMem. Т.е. либо передавай заранее выделенный буфер в функцию (фактически, процедуру), либо после отработки вызывай процедуру освобождения памяти из dll. У тебя там идет неявние выделение памяти. Кстати, от него тоже лучше избавиться. |
| Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Yo_Asakyra (28.04.2012)
| ||
|
#3
|
|||
|
|||
|
Большое спасибо за подсказки
Я читал, что PСhar необходимо всегда использовать при работе с DLL (и в качесте возвращаемых значений функций, и в качестве аргументов строкового типа). Неужели это не так? |
|
#4
|
||||
|
||||
|
Именно так, а вот String использовать можно, но не желательно.
|
|
#5
|
||||
|
||||
|
а какой вообще смысл выносить эту функцию в DLL? сделать ее в обычном модуле, положить в папку прописаную в library path и при потребностях подключать этот модуль в дальнейшем. меньше места займет
![]() по проблеме: у тебя объявляется локальная переменная FNameTrunc типа указатель на Char. ей присваиваются указатели на String. память под строки выделяется и освобождается неявно компилятором. т.е. при завершении работы функции память на которую ссылается FNameTrunc "не существует". а она же еще и возвращается! решение: как уже написал lmikle передавай в функцию буфер и его размер для возвращаемого значения. пример Windows API функция: Цитата:
![]() |
| Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
Yo_Asakyra (28.04.2012)
| ||
|
#6
|
|||
|
|||
|
Простите, вопрос снят - основная проблема устранена
![]() Но всё-таки почему копилятор перепрыгивает инициализацию переменных? begin //отсуда N := 0; FirstTmp := 0; SecondTmp := 0; //суда Последний раз редактировалось Yo_Asakyra, 30.04.2012 в 18:11. |
|
#7
|
|||
|
|||
|
Цитата:
Не совсем так. PChar остался из соображений совместимости. Более правильно, все-таки, использовать WideString. Цитата:
А тебе компилятор предупреждений не дает на этих строках, типа значение не используется? Возможно, при оптимизации этот код удален из-за его излишности. |
| Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Yo_Asakyra (30.04.2012)
| ||