![]() |
|
|
Регистрация | << Правила форума >> | 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 использовать можно, но не желательно.
Je venus de nulle part 55.026263 с.ш., 73.397636 в.д. |
#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)
|