AccessViolationException в Delphi - невозможно (проверить это, невероятно ...) - PullRequest
0 голосов
/ 26 августа 2011

Delphi XE.Windows 7.

Существует функция (см. Код ниже) или I:=0, которая вызывает ошибку AV в большом проекте.В новом проекте нет ошибки с той же функцией !!!Я удалил все из большого проекта, и я оставил только кнопку и эту функцию.Это по-прежнему вызывает ошибку ...

Строка с ошибкой:

if ISAeroEnabled then // this line is a cause
       i:=0;         // or this line

Я устанавливаю точки останова везде (я проверил всю функцию, я установил точки останова на EACH LINE -> нет ошибок в функции), отладчик показывает мне, что ошибка в i:=0;

Если удалить функцию (и оставить i:=0;) -> все в порядке!

Сообщение об ошибке: First chance exception at $747FB727. Exception class EAccessViolation with message 'Access violation at address 004AE5AF in module 'MngProject.exe'. Write of address 0017FFF8'. Process MngProject.exe (4980)

Почему это работает в новом проекте, но не в моем?

Вот весь проект: http://www.2shared.com/file/UP22Om4j/Bug.html

код:

unit MainFormModule;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  StdCtrls;
type
  TMainForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public

    { Public declarations }
  end;

var
     mainform:tmainform;
implementation
{$R *.dfm}

function  ISAeroEnabled: Boolean;
type
  _DwmIsCompositionEnabledFunc = function(IsEnabled: PBoolean): HRESULT; stdcall;
var
  Flag                       : Boolean;
  DllHandle                  : THandle;
  OsVersion                  : TOSVersionInfo;
  DwmIsCompositionEnabledFunc: _DwmIsCompositionEnabledFunc;
begin
  Result:=False;
  ZeroMemory(@OsVersion, SizeOf(OsVersion));
  OsVersion.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);

  if ((GetVersionEx(OsVersion)) and (OsVersion.dwPlatformId = VER_PLATFORM_WIN32_NT) and (OsVersion.dwMajorVersion >= 6)) then //is Vista or Win7?
  begin
    DllHandle := LoadLibrary('dwmapi.dll');
    if DllHandle <> 0 then
    begin
      @DwmIsCompositionEnabledFunc := GetProcAddress(DllHandle, 'DwmIsCompositionEnabled');
      if (@DwmIsCompositionEnabledFunc <> nil) then
      begin
        DwmIsCompositionEnabledFunc(@Flag);
        Result:=Flag;
      end;
    end;
      FreeLibrary(DllHandle);
  end;
end;

procedure Tmainform.Button1Click(Sender: TObject);
var i:integer;
begin
    if ISAeroEnabled then // AV is here
       i:=0;              // Or here
end;
end.

1 Ответ

23 голосов
/ 26 августа 2011

Попробуйте изменить PBoolean на PBOOL

function(IsEnabled: PBOOL): HRESULT; stdcall;

var
  Flag: BOOL;

PBoolean - указатель на логическое значение Паскаля, размер которого составляет 1 байт.PBOOL - это указатель на BOOL для Windows (C), размер которого составляет 4 байта.Вы должны соответствовать размеру, ожидаемому окнами.

В общем, при переводе вызовов API Windows в Delphi используйте тот же именованный тип данных, что и API.В Windows.pas есть определения типов, сопоставляющие их с типами Delphi, например, type BOOL = LongBool;

Также в Delphi обычно (но не обязательно) изменять параметры указателя на var.Параметр var - это синтаксический сахар Паскаля для передачи по ссылке, который недоступен в C.

function(var IsEnabled: BOOL): HRESULT; stdcall;
....
    DwmIsCompositionEnabledFunc(Flag); // no @ operator

ПРИМЕЧАНИЕ: Я не могу проверить это, так как у меня только XPимеется.

...