私のアプリのユーザーは、DesktopDuplication API
.
キャプチャを開始すると、アプリが のフレームを解放できないため、アプリがクラッシュしOutputDuplication
ます。
ユーザーの PC の詳細:
Windows 10.0.18362.0, 64 bits
Nvidia GeForce GTX 960, driver version 441.66
エラーログ:
▬ Message -
HRESULT: [0x887A0001], Module: [SharpDX.DXGI], ApiCode: [DXGI_ERROR_INVALID_CALL/InvalidCall],
Message: The application made a call that is invalid. Either the parameters of the call or the state of some object was incorrect.
Enable the D3D debug layer in order to see details via debug messages.
○ Type -
SharpDX.SharpDXException
▲ Source -
SharpDX
▼ TargetSite -
Void CheckError()
♠ StackTrace -
at SharpDX.Result.CheckError()
at SharpDX.DXGI.OutputDuplication.ReleaseFrame()
at MyApp.Capture.DirectImageCapture.CaptureWithCursor(FrameInfo frame)
----------------------------------
▬ Message -
Object reference not set to an instance of an object.
○ Type -
System.NullReferenceException
▲ Source -
SharpDX.Direct3D11
▼ TargetSite -
Void GetDescription(SharpDX.Direct3D11.Texture2DDescription ByRef)
♠ StackTrace -
at SharpDX.Direct3D11.Texture2D.GetDescription(Texture2DDescription& descRef)
at MyApp.Capture.DirectImageCapture.GetCursor(Texture2D screenTexture, OutputDuplicateFrameInformation info, FrameInfo frame)
at MyApp.Capture.DirectImageCapture.CaptureWithCursor(FrameInfo frame)
ユーザーは、マウス カーソルがキャプチャされていないときに画面をキャプチャできるため、カーソルもキャプチャするキャプチャ メソッドに何か問題があるはずです。
var res = Result.Ok;
try
{
//Try to get the duplicated output frame within given time.
res = DuplicatedOutput.TryAcquireNextFrame(0, out var info, out var resource);
//Checks how to proceed with the capture. It could have failed, or the screen, cursor or both could have been captured.
if (res.Failure || resource == null || (info.AccumulatedFrames == 0 && info.LastMouseUpdateTime <= LastProcessTime))
{
//Somehow, it was not possible to retrieve the resource, frame or metadata.
//frame.WasDropped = true;
//BlockingCollection.Add(frame);
resource?.Dispose();
return FrameCount;
}
else if (info.AccumulatedFrames == 0 && info.LastMouseUpdateTime > LastProcessTime)
{
//Gets the cursor shape if the screen hasn't changed in between, so the cursor will be available for the next frame.
GetCursor(null, info, frame);
return FrameCount;
}
//Saves the most recent capture time.
LastProcessTime = Math.Max(info.LastPresentTime, info.LastMouseUpdateTime);
//Copy resource into memory that can be accessed by the CPU.
using (var screenTexture = resource.QueryInterface<Texture2D>())
{
//Copies from the screen texture only the area which the user wants to capture.
Device.ImmediateContext.CopySubresourceRegion(screenTexture, 0, new ResourceRegion(TrueLeft, TrueTop, 0, TrueRight, TrueBottom, 1), BackingTexture, 0);
//Copy the captured desktop texture into a staging texture, in order to show the mouse cursor and not make the captured texture dirty with it.
Device.ImmediateContext.CopyResource(BackingTexture, StagingTexture);
//Gets the cursor image and merges with the staging texture.
GetCursor(StagingTexture, info, frame);
}
//Get the desktop capture texture.
var data = Device.ImmediateContext.MapSubresource(StagingTexture, 0, MapMode.Read, MapFlags.None);
if (data.IsEmpty)
{
//frame.WasDropped = true;
//BlockingCollection.Add(frame);
Device.ImmediateContext.UnmapSubresource(StagingTexture, 0);
resource.Dispose();
return FrameCount;
}
#region Get image data
var bitmap = new System.Drawing.Bitmap(Width, Height, PixelFormat.Format32bppArgb);
var boundsRect = new System.Drawing.Rectangle(0, 0, Width, Height);
//Copy pixels from screen capture Texture to the GDI bitmap.
var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
var sourcePtr = data.DataPointer;
var destPtr = mapDest.Scan0;
for (var y = 0; y < Height; y++)
{
//Copy a single line.
Utilities.CopyMemory(destPtr, sourcePtr, Width * 4);
//Advance pointers.
sourcePtr = IntPtr.Add(sourcePtr, data.RowPitch);
destPtr = IntPtr.Add(destPtr, mapDest.Stride);
}
//Release source and dest locks.
bitmap.UnlockBits(mapDest);
//Set frame details.
FrameCount++;
frame.Path = $"{Project.FullPath}{FrameCount}.png";
frame.Delay = FrameRate.GetMilliseconds(SnapDelay);
frame.Image = bitmap;
BlockingCollection.Add(frame);
#endregion
Device.ImmediateContext.UnmapSubresource(StagingTexture, 0);
resource.Dispose();
return FrameCount;
}
catch (SharpDXException se) when (se.ResultCode.Code == SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
{
return FrameCount;
}
catch (SharpDXException se) when (se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceRemoved.Result.Code || se.ResultCode.Code == SharpDX.DXGI.ResultCode.DeviceReset.Result.Code)
{
//When the device gets lost or reset, the resources should be instantiated again.
DisposeInternal();
Initialize();
return FrameCount;
}
catch (Exception ex)
{
LogWriter.Log(ex, "It was not possible to finish capturing the frame with DirectX.");
OnError.Invoke(ex);
return FrameCount;
}
finally
{
try
{
//Only release the frame if there was a success in capturing it.
if (res.Success)
DuplicatedOutput.ReleaseFrame();
}
catch (Exception e)
{
LogWriter.Log(e, "It was not possible to release the frame.");
//HERE
//What should I do after the frame is not released properly?
//Should I reset the whole capture?
//DisposeInternal();
//Initialize();
}
}
各フレームのキャプチャが終了したら、 はDuplicatedOutput
フレームを解放する必要があります。
しかし、リリースが で失敗した場合InvalidCall
、どうすればよいですか?
また、(開発者のマシンではなく) ユーザーの PC でこの種のエラーをデバッグするにはどうすればよいですか?
編集:
これは私がやろうとしていることです:
onをGraphics Tools
有効にしてWindows Settings
、次のコードをキャプチャの初期化に追加しました。
#if DEBUG
Device = new Device(DriverType.Hardware, DeviceCreationFlags.VideoSupport | DeviceCreationFlags.Debug);
var debug = InfoQueue.TryCreate();
debug.SetBreakOnSeverity(DebugId.All, InformationQueueMessageSeverity.Corruption, true);
debug.SetBreakOnSeverity(DebugId.All, InformationQueueMessageSeverity.Error, true);
debug.SetBreakOnSeverity(DebugId.All, InformationQueueMessageSeverity.Warning, true);
var debug2 = DXGIDebug.TryCreate();
debug2.ReportLiveObjects(DebugId.Dx, DebugRloFlags.Summary | DebugRloFlags.Detail);
#else
次に、ノートブックの専用 GPU で実行するようにアプリを設定しますInvalidException
。
アプリを実行して試してみましoutput1.DuplicateOutput(Device);
たが、期待どおりに失敗しました。
その後、DebugView の実行中にアプリを実行しようとしましたが、エラーが発生したときではなく、アプリを閉じたときにのみメッセージが表示されました。
00000001 0.00000000 [14488] OnFocusWindowChanged to Lizard Mode
00000002 0.39583239 [14488] Lizard Mode: Unprivileged process
00000003 0.39594769 [14488] Lizard Mode: Restoring app mapping
00000004 9.81729603 [21620] D3D11 WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: UNKNOWN]
00000005 9.81732273 [21620] D3D11: **BREAK** enabled for the previous message, which was: [ WARNING STATE_CREATION #0: UNKNOWN ]
00000006 9.81803799 [21620] DXGI WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: ]
00000007 9.81806469 [21620] DXGI: **BREAK** enabled for the previous message, which was: [ WARNING STATE_CREATION #0: ]
00000008 10.78524113 [14488] Lizard Mode: Privileged process
00000009 10.78589630 [14488] Lizard Mode: Reverting to default M/KB Configuration
00000010 10.78692913 [14488] OnFocusWindowChanged to Lizard Mode
そこで、次のdxcap
コマンドを使用して、 を使用してエラーをキャプチャしようとしました。
dxcap -debug -toXML '[path]\debug.xml' -file '[path]\debug.vsglog' -c '[path]\bin\Debug\MyApp.exe'
残念ながら、次のようにCreateDevice()
失敗します。
HRESULT: [0x887A0004]、モジュール: [SharpDX.DXGI]、ApiCode: [DXGI_ERROR_UNSUPPORTED/Unsupported]、メッセージ: 指定されたデバイス インターフェイスまたは機能レベルは、このシステムではサポートされていません。
その後、もう一度試してみましたが、今回はのみDeviceCreationFlags.Debug
でうまくいきました。私はまだファイルを分析しています。