Коллегу попросили слегка поколупаться в старом проекте:
Приходит ко мне - грит, я в шоке: убил полдня - задница! Ничего не понимаю! Не работает! Давай вместе посмотрим!
Итак, имеется DLL-ка, в ней две функции:
Load1: function (aS: pChar): boolean; stdcall = nil;
Load2: function (aS: pChar; var codeErr: LongInt): boolean; stdcall = nil;
Инициализация:
@Load1 := GetProcAddress (hLib, 'Load1');
@Load2 := GetProcAddress (hLib, 'Load2');
Вызов Load1:
procedure PerformLoad (TaskObject: TTaskObject);
var
ErrorCode: integer;
s: string;
begin
s := TaskObject.RequestText;
if Load1 (@s[1]) then // вызов старой функции библиотеки
ErrorCode := 0
else
ErrorCode := 1;
TaskObject.ErrorCode := ErrorCode;
end;
Вызов снаружи:
// Инициализация объекта LocalTaskObject
...
PerformLoad (LocalTaskObject);
if (LocalTaskObject.ErrorCode = 0) then
...
Всё работало. Но. Надо ему было заменить Load1 на Load2:
procedure PerformLoad (TaskObject: TTaskObject);
var
ErrorCode: Integer;
s: string;
begin
s := TaskObject.RequestText;
Load2 (@s[1], ErrorCode); // вызов новой функции библиотеки
TaskObject.ErrorCode := ErrorCode;
end; //Вот здесь ещё всё хорошо - объект TaskObject в отладчике "живой"
И внезапно:
// Инициализация объекта LocalTaskObject
...
PerformLoad (LocalTaskObject); // передаём "живой" объект
if (LocalTaskObject.ErrorCode = 0) then // и внезапно вот здесь LocalTaskObject становится nil
...
Увидев подобное, я несколько прифигел. В чём разница? Что может освобождать или затирать объект? Ладно, говорю, давай попробуем тупой костыль:
function PerformLoad (TaskObject: TTaskObject): TTaskObject;
var
ErrorCode: integer;
s: string;
begin
s := TaskObject.RequestText;
Load2 (@s[1], ErrorCode); // вызов новой функции библиотеки
TaskObject.ErrorCode := ErrorCode;
result := TaskObject;
end;
// Вызов
// Инициализация объекта LocalTaskObject
...
LocalTaskObject := PerformLoad (LocalTaskObject); // передаём "живой" объект
if (LocalTaskObject.ErrorCode = 0) then // и внезапно всё опять заработало
...
Но как?