Почему выдаёт Access Violitation?
У меня есть 2 класса, которые получают ссылку на устройтво IDirect3DDevice8. При создании формы у меня создаётся 2 разных устройства, для каждого класса, каждое устройство должно рисовать на своём компоненте (Panel1, Panel2). В одном классе есть вожможность сохранения в файл. В файл записываются значения чисел массива, из которого периодически заполняются массивы для рисования линий для VertexBuffer. Если не сохранять в файл, то программа будет выполняться нормально, но если выполнить сохранение, то при завершении программы происходит ошибка Access Violitation. Причём этой ошибки не происходит если используется только одно устройство , т. е. второе устройство вообще не создаётся. Я считаю, что дело по большей части в Дельфи, а не DX.
Вот примерный код:
private
device : IDirect3DDevice8;
public
constructor Create(gDevice : IDirect3DDevice8);
begin
device := gDevice;
end;
procedure Render;
begin
что-то рисует.
end;
end;
TCUSTOMVERTEX = packed record
X, Y, Z, RHW : single;
Color : DWORD;
end;
TClass2 = class
private
device : IDirect3DDevice8;
массивЧисел : array [0..300000] of integer;
линия : array [0..10] of TCUSTOMVERTEX;
public
constructor Create(gDevice : IDirect3DDevice8);
var
i : integer;
begin
device := gDevice;
for i := 0 to 10 do
линия.X := массивЧисел;
ПоложитьВБуферВершин;
end;
procedure SaveToFile(fileName : String);
var
f : TextFile;
i : integer;
begin
AssignFile(f, fileName);
for i := 0 to размерМассива do
WriteLn(f, массив чисел);
Flush(f);
CloseFile(f);
end;
procedure Render;
begin
что-то рисует.
end;
end;
Form1
DirectX : IDirect3D8;
Device1 : IDirect3DDevice8;
Device2 : IDirect3DDevice8;
Form1OnCreate
ИнициализацияDirectX;
Class1 := TClass1.Create(Device1);
Class2 := TClass2.Create(Device2);
end;
Form1Button1Click;
Class2.SaveToFile('file.txt');
end;
Копать надо где-то здесь.
{ Private declarations }
DirectX : IDirect3D8;
DiagramDevice : IDirect3DDevice8;
HistogramDevice : IDirect3DDevice8;
Active : boolean;
procedure Cleanup;
procedure ErrorOut(const Caption : PChar; const hError : HRESULT);
procedure InitialGraphicUnits;
procedure DetectDevices;
function InitialGraphics : HRESULT;
public
{ Public declarations }
Diagram : TD3DDiagram; // это мои классы
Histogram : TD3DHistogram;
end;
var
Form1: TForm1;
implementation
uses Unit2, DiagramSettings, VideoSettings, HistogramSettings;
{$R *.dfm}
{ TForm1 }
procedure TForm1.Cleanup;
begin
if (Assigned(HistogramDevice)) then
begin
HistogramDevice._Release;
HistogramDevice := nil;
end;
Diagram.Free;
if (Assigned(DiagramDevice)) then
begin
DiagramDevice._Release;
DiagramDevice := nil;
end;
if (Assigned(DirectX)) then
begin
DirectX._Release;
DirectX := nil;
end;
end;
procedure TForm1.ErrorOut(const Caption: PChar; const hError: HRESULT);
begin
Active := false;
Cleanup;
MessageBox(Handle, PChar(DXGErrorString(hError)), Caption, 0);
end;
function TForm1.InitialGraphics: HRESULT;
var
displayMode : TD3DDISPLAYMODE;
presentParameters : TD3DPRESENT_PARAMETERS;
begin
DirectX := nil;
DiagramDevice := nil;
DirectX := Direct3DCreate8(D3D_SDK_VERSION);
if (DirectX = nil) then
begin
result := E_FAIL;
exit;
end;
if (FAILED(DirectX.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, displayMode))) then
begin
result := E_FAIL;
exit;
end;
ZeroMemory(@presentParameters, sizeof(presentParameters));
with presentParameters do
begin
Windowed := true;
SwapEffect := D3DSWAPEFFECT_DISCARD;
BackBufferFormat := displayMode.Format;
end;
if (FAILED(DirectX.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Panel5.Handle,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, presentParameters,
HistogramDevice))) then
begin
result := E_FAIL;
exit;
end;
presentParameters.BackBufferWidth := Screen.Width;
if (FAILED(DirectX.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Panel2.Handle,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, presentParameters,
DiagramDevice))) then
begin
result := E_FAIL;
exit;
end;
result := S_OK;
Active := true;
end;
[highlight=delphi]
procedure SaveToFile(fileName : String);
var
f : TextFile;
i : integer;
begin
AssignFile(f, fileName);
for i := 0 to размерМассива do
WriteLn(f, массив чисел);
Flush(f);
CloseFile(f);
end;
[/highlight]
файл не создается и не открывается на запись и т.д. а значит здесь должно вылетать исключение. предположение проверил у себя - действительно исключение. или может ты просто пропустил когда сюда писал?
begin
if (Assigned(HistogramDevice)) then
begin
HistogramDevice._Release;
HistogramDevice := nil;
end;
Diagram.Free;
if (Assigned(DiagramDevice)) then
begin
DiagramDevice._Release;
DiagramDevice := nil;
end;
if (Assigned(DirectX)) then
begin
DirectX._Release;
DirectX := nil;
end;
end;
компилятором будет сгенерирован:
begin
if (Assigned(HistogramDevice)) then
begin
HistogramDevice._Release;
--------------------------------------
HistogramDevice._Release; // AV здесь (эта строка подставлена компилятором)
HistogramDevice := nil;
end;
Diagram.Free;
if (Assigned(DiagramDevice)) then
begin
DiagramDevice._Release;
---------------------------------------
DiagramDevice._Release; // и здесь
DiagramDevice := nil;
end;
if (Assigned(DirectX)) then
begin
DirectX._Release;
---------------------------------------
DirectX._Release; // и здесь тоже
DirectX := nil;
end;
end;
[highlight=delphi]
procedure SaveToFile(fileName : String);
var
f : TextFile;
i : integer;
begin
AssignFile(f, fileName);
for i := 0 to размерМассива do
WriteLn(f, массив чисел);
Flush(f);
CloseFile(f);
end;
[/highlight]
файл не создается и не открывается на запись и т.д. а значит здесь должно вылетать исключение. предположение проверил у себя - действительно исключение. или может ты просто пропустил когда сюда писал?
Это я забыл написать ReWrite(f), спасибо что заметил. Данные в файл сохраняются нормально.
makbeth, ты предлагаешь не писать *._Release, а просто ставить nil?
Почему кстати не происходит AV при одном девайсе и происходит ТОЛЬКО после сохранения в файл.
Именно это я и предлагаю. Вообще, попробуй убрать вызов _Release и посмотреть получившийся код в окне дизассемблера - вопросы отпадут сами собой ;)
А вот это уже интереснее :rolleyes: Скорее чего-то не то с вызовами DirectX - надо курить мануалы...
Ещё вопрос, чем чревато если я просто пропишу try except блок, чтобы пользователь не получал сообщения об ошибке.
Значит, где-то не по науке используешь DX.. Попробуй пошукать по профильным веткам. А вообще надо локализовать момент выброса исключения.
Чревато тем, что из-за этой подавленной ошибки потом может вылезти что нибудь покрасивше - например полный вынос системы (ибо это DX, батенька :) ), причем в самый неподходящий момент, а это отловить намного сложнее. Вообще это сильно порочная практика. Такими вещами пользоваться не советую.