Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

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? Или еще что?


Наверх

Титульная страница Поиск, карта сайта Написать письмо