Delphi 中的 AccessViolationException - 不可能(检查一下,难以置信......)
德尔福XE。 Windows 7。
有一个函数(请参阅下面的代码)或 I:=0
会在大型项目中导致 AV 错误。在新项目中同样的功能没有报错!!!我删除了大项目中的所有内容,只留下了一个按钮和该功能。它仍然会导致错误...
一行错误:
if ISAeroEnabled then // this line is a cause
i:=0; // or this line
我在各处设置了断点(我检查了整个函数,我在每行上设置了断点 -> 函数中没有错误),调试器显示错误位于 i:=0;
如果要删除函数(并保留 i:=0;
) -> 一切正常!
错误消息:首次机会异常,价格为 747FB727。异常类 EAccessViolation,带有消息“模块‘MngProject.exe’中地址 004AE5AF 处的访问冲突”。写入地址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.
Delphi XE. Windows 7.
There is a function (please see a code below) or I:=0
that causes an AV error in a big project. There is no the error with the same function in a new project!!! I deleted everything from the big project, and I left only a button and that function. It still causes the error...
A line with the error:
if ISAeroEnabled then // this line is a cause
i:=0; // or this line
I set breakpoints everywhere (I checked the whole function, I set breakpoints on EACH LINE -> no errors in the function), a debugger shows me that the error is in i:=0;
If to delete a function (and leave i:=0;
) -> all is ok!
The error message: 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)
Why does it work in a new project but not in mine?
Here's the whole project: http://www.2shared.com/file/UP22Om4j/Bug.html
The code:
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
尝试将
PBoolean
更改为PBOOL
PBoolean 是一个指向 Pascal Boolean 的指针,大小为 1 个字节。 PBOOL 是一个指向 Windows(基于 C)BOOL 的指针,大小为 4 个字节。您需要匹配 Windows 期望的大小。
通常,将 Windows API 调用转换为 Delphi 时,请使用与 API 相同的命名数据类型。 Windows.pas 具有将这些映射到 Delphi 类型的类型定义,例如 type BOOL = LongBool;
另外,在 Delphi 中通常(但不是必需)将指针参数更改为 var。 var 参数是用于传递引用的 Pascal 语法糖,在 C 中不可用。
注意: 我无法测试这一点,因为我只有 XP 可用。
Try changing
PBoolean
toPBOOL
PBoolean is a pointer to a Pascal Boolean which is 1 byte in size. PBOOL is a pointer to a Windows (C based) BOOL, which is 4 bytes in size. You need to match the size expected by windows.
In general, when translating Windows API calls to Delphi, use the same named data type as the API. Windows.pas has type definitions mapping these to Delphi types, e.g.
type BOOL = LongBool;
Also it is usual (but not required) in Delphi to change pointer parameters to var. A var parameter is Pascal syntactic sugar for pass-by-reference which isn't available in C.
NOTE: I can't test this, as I only have XP available.