Delphi中的AccessViolationException - 不可能(检查它,难以置信......)

max*_*fax -3 delphi error-handling access-violation

德尔福XE.Windows 7的.

有一个功能(请参阅下面的代码)或I:=0导致大项目中的AV错误.在新项目中没有相同功能的错误!我删除了大项目中的所有内容,我只留下了一个按钮和该功能.它仍然会导致错误......

带错误的一行:

if ISAeroEnabled then // this line is a cause
       i:=0;         // or this line
Run Code Online (Sandbox Code Playgroud)

我在任何地方设置了断点(我检查了整个函数,我在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.
Run Code Online (Sandbox Code Playgroud)

Ger*_*oll 23

尝试PBoolean改为PBOOL

function(IsEnabled: PBOOL): HRESULT; stdcall;

var
  Flag: BOOL;
Run Code Online (Sandbox Code Playgroud)

PBoolean是指向Pascal布尔值的指针,其大小为1个字节.PBOOL是指向Windows(基于C)BOOL的指针,其大小为4个字节.您需要匹配Windows预期的大小.

通常,在将Windows API调用转换为Delphi时,请使用与API相同的命名数据类型.Windows.pas具有将这些定义映射到Delphi类型的类型定义,例如type BOOL = LongBool;

在Delphi中通常(但不是必需的)将指针参数更改为var.var参数是用于传递引用的Pascal语法糖,在C中不可用.

function(var IsEnabled: BOOL): HRESULT; stdcall;
....
    DwmIsCompositionEnabledFunc(Flag); // no @ operator
Run Code Online (Sandbox Code Playgroud)

注意:我无法测试这个,因为我只有XP可用.

  • `通常,在将Windows API调用转换为Delphi时,请使用与API相同的命名数据类型.Windows.pas具有将这些类型定义映射到Delphi类型的类型定义,例如类型BOOL = LongBool;`这是**如此真实**.我继续重复这一点. (3认同)
  • @maxfax - 它通过运气在一个新项目中工作.您正在将指向单个字节的指针传递给期望4个字节的函数.这导致您的某些堆栈被覆盖,结果不可预测.另请注意,对GetVersionEx(OsVersion)的调用是不必要的,因为这些信息已经由Delphi RTL加载到SysUtils.Win32Platform,Win32MajorVersion和Win32MinorVersion中. (2认同)