这是我previous question的后续跟进。我意识到自己在那个问题上自己缩小了问题的能力很差,道歉。我现在对正在发生的事情有一个非常具体的想法,所以希望有人能够把我推向正确的方向。
SSCCE:
program SSCCE;
{$APPTYPE CONSOLE}
{$R *.res}
uses System.SysUtils, FMX.Context.DX10;
begin
try
TCustomDX10Context.CheckDevice;
WriteLn('Everything went fine, guess we have to dig deeper.');
except
on E: Exception do Writeln(E.ClassName, ': ', E.Message);
end;
Write('Press enter to exit.');
ReadLn;
end.
CheckDevice在@IntfClear
中产生访问冲突。这是FMX.Context.DX10中的CheckDevice的代码:
class function TCustomDX10Context.CheckDevice: TD3D10DriverType;
var
dx10lib: THandle;
g_pd3dDevice: ID3D10Device1;
begin
if not FChecked then
begin
FChecked := True;
FDriverType := D3D10_DRIVER_TYPE_NULL;
dx10lib := LoadLibrary(D3D10_1_dll);
if dx10lib <> 0 then
try
if GlobalUseDX10Software then
FDriverType := D3D10_DRIVER_TYPE_WARP
else begin
if GlobalUseDX10 then
begin
{ check for support for DX10 hardware }
SaveClearFPUState;
try
if GetProcAddress(dx10lib, 'D3D10CreateDevice1') <> nil then
begin
if Succeeded(D3D10CreateDevice1(nil, D3D10_DRIVER_TYPE_HARDWARE, 0, D3D10_CREATE_DEVICE_BGRA_SUPPORT, D3D10_FEATURE_LEVEL_10_1, D3D10_1_SDK_VERSION, g_pd3dDevice)) then
begin
g_pd3dDevice := nil;
FDriverType := D3D10_DRIVER_TYPE_HARDWARE;
end;
end;
finally
RestoreFPUState;
end;
end;
end;
finally
FreeLibrary(dx10Lib);
end;
end;
Result := FDriverType;
end;
我已经让遇到问题的用户尝试了一些变体,我可以确认,只要g_pd3dDevice
的引用超出范围,就会调用@IntfClear
并随后生成访问违规。
0040e028 +010 <...>.exe System 191 +0 @IntfClear
0096a360 +0d0 <...>.exe FMX.Context.DX10 314 +20 TCustomDX10Context.CheckDevice
009759a1 +005 <...>.exe FMX.Canvas.D2D RegisterCanvasClasses
009900b4 +000 <...>.exe FMX.Platform.Win 3404 +0 TPlatformWin.RegisterCanvasClasses
009d575a +056 <...>.exe FMX.Types TCanvasManager.GetDefaultCanvas
009d56f2 +00e <...>.exe FMX.Types TCanvasManager.CreateFromWindow
314是成功进行API调用后被g_pd3dDevice
标记的行,注释掉该行会在函数结束时用完范围之后清除接口时导致AV出现。这可能是由D3D10CreateDevice1
返回无效设备引起的,还是还有其他事情发生?此外,由于AV出现在@IntfClear
我不认为我可以尝试除了它并吃掉它,即使这可能不会做太多好事......