![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Access Violation при возврате из функции [D7, Win95/98, Win2k]
Tihinen © (2005-08-06 01:06:00)Не могу понять что не так. Имеется вот такой кусок программы.
type
TDrawClass = class
private
fTarget:TCanvas;
function SubDrawRoutine(a:integer;b,c,d:Integer;e:integer;f:integer):integer;
public
constructor Create(Target:TCanvas);
destructor Destroy; override;
function Draw(DM:TMyMatrix;const DrawCycle:Integer=-1;Var1:Integer =0):Boolean;
// в качестве Target используется Саnvas созданного однажды Bitmap - чтото вроде теневого экрана
constructor TDrawClass.Create(Target:TCanvas);
begin
fTarget:=Target;
end;
destructor TDrawClass.Destroy;
begin
inherited Destroy;
end;
function TDrawClass.SubDrawRoutine(a:integer;b,c,d:Integer;e:integer;f:integer):integer;
begin
//вычисляются Rect1,Rect2,Rect3 исходя из параметров a,b,c,d,e,f
// исходя из них же грузится SourceBmp
//...
fTarget.CopyRect(Rect1,SourceBmp.Canvas,Rect1);
fTarget.CopyRect(Rect2,SourceBmp.Canvas,Rect2);
fTarget.CopyRect(Rect3,SourceBmp.Canvas,Rect3);
end;
function TDrawClass.Draw(DM:TMyMatrix;const DrawCycle:Integer=-1;Var1:Integer =0):Boolean;
begin
try
//
..
//циклически вызывается TDrawClass.SubDrawRoutine
//
Result:=True;
fTarget.Draw(0,0,ResX.GetBitmap('Top'));
fTarget.Draw(0,450,ResX.GetBitmap('Bottom'));
except
MessageBox(0,'1','1',0);
end;
end;
//на основной форме вызывается по таймеру Draw;
//...
procedure TMainForm.DXTimerTimer(Sender: TObject; LagCount: Integer);
begin
//...
try
MyDrawClass.Draw(DM,DrawCycle);
except
MessageBox(0,'2','2',0);
end;
//...
end;
происходит срабатывание второго эксепшна и вызывается второй мессаджбокс,
то есть Access Violation возникает на возврате из функции Draw, а не внутри нее.
Сопственно изза чего это может происходить? Причем возникает он совсем с непонятной периодичностью, то возникает то нет.
Но всегда одинаковый "по адресу 00000013 чтение адреса FFFFFFFF"
параметр DM: TMyMatrix = array [1..3,1..5] of integer является свойством третьего класса.
Мне вот кажется что дело тут вовсе не в рисовании, а в том что возврат из функции Draw осуществляется както коряво.
Памажите.
Tihinen (2005-08-08 21:23:00) [1]К чему бы мне обманывать?
и с какой это радости не откомпилируецца то?
type TDrawClass = class
Anatoly Podgoretsky (2005-08-06 11:55:00) [2]Tihinen (06.08.05 02:28) [6]
function Draw;
Не обманывай, это просто не откомпилируется и ни о каком AV говорить и не приходится.
Джо (2005-08-06 03:13:00) [3]
> [13] Джо © (06.08.05 03:05)
Коряво и неверно выразился.
Закомментируй все тело процедуры, при выходе из которой вылетает AV. Затем, начинай раскомментировать по одной строчку, каждый раз компилируя и запуская. Когда появится AV, будешь знать, из-за какой строчки. Ну, ты меня понял, надеюсь :)
Джо (2005-08-06 03:05:00) [4]
> [11] Tihinen (06.08.05 02:57)
> Джо. Пробуй локализовать.
> Что локализовывать?
Локализовать проблему. То есть, найти минимальное количество кода, при котором нет проблем. Затем потихоньку начинай добавлять (раскомментировать) остальные строки, наблюдая, когда проблема появится. Возможно, поможет пошаговая отладка с заходом во все процедуры (F7) с включенной опцией компилятора Use debug DCU's.
Джо (2005-08-06 03:02:00) [5]
> Мне хотелось бы услышать про испорченный стек. Меня вот
> данный вопрос интересует
А что тут интересного. Ну, вот самый простой пример:
procedure Proc;
var
I: Integer;
Arr: array [0..2] of Integer;
begin
for I := 0 to 3 do
begin
Arr[I] := 10;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Proc
end;
Нажмешь на кнопку и получишь AV. Потому что массив расположен в стэке, а ты вышел за пределы массива (for I := 0 to 3), таким образом запортив стэк. Соответственно, запортив то, что в нем лежало, возможно, и адрес возврата из процедуры.
Tihinen (2005-08-06 02:57:00) [6]Джо. Пробуй локализовать.
Что локализовывать?
Tihinen (2005-08-06 02:54:00) [7]GenerateDrum ну если опустить логику и математику на уровне целочисленных делений и прочая опять же содержит вот такие штуки
SourceBmp:=ResX.GetBitmap('Rotate');
fTarget.CopyRect(RectN,SourceBmp.Canvas,RectN);
дык вот нащщот ResX.GetBitmap;
есть вот такой класс
type
TResourceX = class
private
RS:TResourceStream;
BMPList:TList;
NameList:TStringList;
public
constructor Create;
destructor Destroy; override;
procedure AddJpeg(const ResName: string);
procedure AddGif(const ResName: string);
procedure AddBmp(const ResName: string);
function GetBitmap(const ResName: string):TBitmap;
end;
и в нем два вот таких метода. Тобишь при запуске все ресурсы загружаюцца в память, а потом когда надо получаю указатели на BMP изображения из памяти.
function TResourceX.GetBitmap(const ResName: string):TBitmap;
begin
Result:=TBitmap(BMPList[Namelist.IndexOf(UpperCase(ResName))]);
end;
procedure TResourceX.AddJpeg(const ResName: string);
var TmpImage:TJpegImage;
Bmp:TBitmap;
begin
RS := TResourceStream.Create(0, ResName, 'IMAGE');
TmpImage:=TJpegImage.Create;
TmpImage.LoadFromStream(RS);
TmpImage.DIBNeeded;
Bmp:=TBitmap.Create;
Bmp.Assign(TmpImage);
BMPList.Add(Bmp);
TmpImage.Free;
RS.Free;
NameList.Add(UpperCase(ResName));
end;
Ну и RotateCycles вот.
const RotateCycles: array [1..5] of integer =(8,16,24,32,40);
:)
Мне хотелось бы услышать про испорченный стек. Меня вот данный вопрос интересует. Потомучто звучит очень правдоподобно, но как это может выглядеть я почемуто не представляю.
Джо (2005-08-06 02:44:00) [8]Может быть все что угодно. Что, например, делает GenerateDrum? Что за массив RotateCycles - где объявлен и инициализирован? Что за ResX с загадочным методом GetBitmap? Почему GetBitmap вызывается, а, возможно, выделенный ресурс нигде не освобождается?
Одни вопросы...
Джо (2005-08-06 02:44:00) [9]Пробуй локализовать.
Tihinen (2005-08-06 02:32:00) [10]А как вот можно испортить стек? Вот выделенная и неочищенная память эт я понимаю. Но выделения памяти нигде я сопсна внутри функции не делаю.
Tihinen (2005-08-06 02:28:00) [11]да код привести несложно... просто врядли это чтото даст. Я наоборот пытаюсь максимально упростить картину для восприятия.
все именно вот так :
function Draw;
begin
try
//...
DebugStr:='DrawExit';
except
MessageBox(0,'1','1',0);
end;
end;
в теле программы
//....
try
DebugStr:='BeforeDraw';
Draw();
DebugStr:='AfterDraw';
except
MessageBox(0,'2','2',0);
end;
//....
На момент появления эксепшна DebugStr='DrawExit' !!!
Ну и если это чтото даст то вот эта функция. У меня были сомнения именно в передаче параметров в нее. Я бы предложил что это какой то системный сбой вообще не связанный с этим, поскольку используется DirectX и еще и Flash, но меня смущает, что происходит он всегда с функцией именно этой.
function TAniDrum.Draw(DM:TDrumMatrix;const Cycle:Integer; FlashCount:integer):Boolean;
var i:integer;
Upp,Mid,Btm:Integer;
Shift:Integer;
begin
Result:=False;
try
for i:=1 to 5 do
begin
if (Cycle>0) and (Cycle<RotateCycles[i]) then
begin
Upp:=-((Cycle mod 5)+1);
Mid:=Upp;
Btm:=Upp;
Shift:=0;
end
else
begin
Upp:=DM[1,i];
Mid:=DM[2,i];
Btm:=DM[3,i];
if Cycle=RotateCycles[i] then
Shift:=10
else
Shift:=0;
end;
Lop:='6';
FlashCount:=FlashCount-GenerateDrum(i-1,Upp,Mid,Btm,Shift,FlashCount);
Lop:='7';
end; //for i:=1 to 5 do
Result:=True;
fTarget.Draw(0,0,ResX.GetBitmap('Top'));
fTarget.Draw(0,450,ResX.GetBitmap('Bottom'));
if (Cycle>RotateCycles[5]+1) or (Cycle=0) then Result:=False;
Lop:='DrawExit';
except
MessageBox(0,'1','1',0)
end;
end;
Mx (2005-08-06 02:20:00) [12]
> Джо © (06.08.05 02:17) [4]
"Сложно" для приведенного варианта, потому и запросил "весь код".
P.S. Блин, опять два часа ночи, а я всё не сплю. А ведь каждый день обещаю себе лечь вовремя и выспаться...
Джо (2005-08-06 02:17:00) [13]
> Или, действительно, ошибка на самом возврате, но я себе
> это слабо представляю.
Представить не сложно ;) Это может быть, например, из-за того, что внутри процедуры запорчен стэк.
Mx (2005-08-06 02:14:00) [14]А я вот подумал: с учетом того, что raise внутри except-блока в TDrawClass.Draw нет, то второе исключение может возникнуть лишь если внутри этого блока какая-то ошибка. Или, действительно, ошибка на самом возврате, но я себе это слабо представляю.
А нельзя ли привести весь код TDrawClass.Draw? Какого вида переменные в нем используются?
Tihinen (2005-08-06 01:53:00) [15]Точно на возврате.
я вот ввел глобальную переменную DebugStr:String;
и функция Draw выглядит примерно так...
function TDrawClass.Draw;
begin
try
//
..
DebugStr:='1';
//..
DebugStr:='2';
//..
Result:=True;
DebugStr:='12';
fTarget.Draw(0,0,ResX.GetBitmap('Top'));
DebugStr:='13';
fTarget.Draw(0,450,ResX.GetBitmap('Bottom'));
DebugStr:='DrawExit';
except
MessageBox(0,'1','1',0);
end;
end;
и перед вызовом Draw - тоже самое
DebugStr:='0';
Draw;
DebugStr:='AfterExit';
и когда происходит экспшн - DebugStr всегда DrawExit, то есть последняя строчка функции Draw всегда выполняется. Такая вот штука :-/
DrPass (2005-08-06 01:32:00) [16]
> то есть Access Violation возникает на возврате из функции
> Draw,
Точно ли на возврате? А может, перед вызовом? Корректно ли инициализирован MyDrawClass? Или еще что?