Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Почему выдаёт Access Violitation?

548
01 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Я использую DirectX8 для Дельфи.
У меня есть 2 класса, которые получают ссылку на устройтво IDirect3DDevice8. При создании формы у меня создаётся 2 разных устройства, для каждого класса, каждое устройство должно рисовать на своём компоненте (Panel1, Panel2). В одном классе есть вожможность сохранения в файл. В файл записываются значения чисел массива, из которого периодически заполняются массивы для рисования линий для VertexBuffer. Если не сохранять в файл, то программа будет выполняться нормально, но если выполнить сохранение, то при завершении программы происходит ошибка Access Violitation. Причём этой ошибки не происходит если используется только одно устройство , т. е. второе устройство вообще не создаётся. Я считаю, что дело по большей части в Дельфи, а не DX.

Вот примерный код:
Код:
TClass1 = class
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;
303
01 мая 2008 года
makbeth
1.0K / / 25.11.2004
Приведенный код ни о чем совершенно не говорит. ИМХО ключевая фраза:
Цитата:
...этой ошибки не происходит если используется только одно устройство , т. е. второе устройство вообще не создаётся.


Копать надо где-то здесь.

548
01 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Вот часть кода где инициализируются устройства
Код:
private
    { 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;
548
01 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Может ли как-то влиять то, что оба устройства создаются от одного IDirect3D?
257
02 мая 2008 года
kosfiz
1.6K / / 18.09.2005
у меня тут вопросик по твоему коду возник: а что файл создается и в него что-то сохраняется? дело в том, что в коде:
[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]
файл не создается и не открывается на запись и т.д. а значит здесь должно вылетать исключение. предположение проверил у себя - действительно исключение. или может ты просто пропустил когда сюда писал?
303
02 мая 2008 года
makbeth
1.0K / / 25.11.2004
Maximillian_Cavalera, подозреваю, что AV случается в методе Cleanup (он вызывается только в конце?). Дело в том, что Delphi очень хорошо умеет работать с интерфейсами и код удаления объекта интерфейса компилятор генерирует автоматически. Соответственно, вместо твоего кода:
Код:
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.Cleanup;
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;
548
02 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Цитата: kosfiz
у меня тут вопросик по твоему коду возник: а что файл создается и в него что-то сохраняется? дело в том, что в коде:
[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 при одном девайсе и происходит ТОЛЬКО после сохранения в файл.

303
03 мая 2008 года
makbeth
1.0K / / 25.11.2004
Цитата: Maximillian_Cavalera
makbeth, ты предлагаешь не писать *._Release, а просто ставить nil?


Именно это я и предлагаю. Вообще, попробуй убрать вызов _Release и посмотреть получившийся код в окне дизассемблера - вопросы отпадут сами собой ;)

Цитата:
Почему кстати не происходит AV при одном девайсе и происходит ТОЛЬКО после сохранения в файл.


А вот это уже интереснее :rolleyes: Скорее чего-то не то с вызовами DirectX - надо курить мануалы...

548
03 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
Кстати я пробовал не писать Release, но всё равно после сохранения в файл при закрытии программы вылетает AV, даже при двух девайсах.
Ещё вопрос, чем чревато если я просто пропишу try except блок, чтобы пользователь не получал сообщения об ошибке.
303
04 мая 2008 года
makbeth
1.0K / / 25.11.2004
Цитата: Maximillian_Cavalera
Кстати я пробовал не писать Release, но всё равно после сохранения в файл при закрытии программы вылетает AV, даже при двух девайсах.


Значит, где-то не по науке используешь DX.. Попробуй пошукать по профильным веткам. А вообще надо локализовать момент выброса исключения.

Цитата:
Ещё вопрос, чем чревато если я просто пропишу try except блок, чтобы пользователь не получал сообщения об ошибке.


Чревато тем, что из-за этой подавленной ошибки потом может вылезти что нибудь покрасивше - например полный вынос системы (ибо это DX, батенька :) ), причем в самый неподходящий момент, а это отловить намного сложнее. Вообще это сильно порочная практика. Такими вещами пользоваться не советую.

548
04 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
makbeth, а что именно нужно посмотреть в профильных ветках.
548
05 мая 2008 года
Maximillian_Cavalera
157 / / 16.08.2007
А по каким именно веткам?
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог