You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用DirectX11捕获屏幕时触发读取访问违例异常的问题

DirectX11屏幕捕获读取访问违例(DesktopResource=0xFFFFFFFFFFFFFFFF)修复方案

错误原因分析

DesktopResource=0xFFFFFFFFFFFFFFFF是无效指针访问,说明屏幕捕获的核心资源初始化失败,常见诱因包括:

  • D3D11设备创建参数不兼容DXGI屏幕复制需求
  • DXGI输出设备选择错误(如选中非活跃显示器)
  • IDXGIOutputDuplication创建失败未做错误处理,直接使用空指针
  • Windows权限不足或其他软件占用屏幕捕获资源

核心修复步骤

1. 确保D3D11设备支持DXGI特性

创建设备时必须启用DEBUG层(方便排查驱动级错误),并指定兼容的Feature Level:

D3D_FEATURE_LEVEL featureLevels[] = {
    D3D_FEATURE_LEVEL_11_1,
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0
};
UINT numFeatureLevels = ARRAYSIZE(featureLevels);
ID3D11Device* pDevice = nullptr;
ID3D11DeviceContext* pDeviceContext = nullptr;
D3D_FEATURE_LEVEL featureLevel;

HRESULT hr = D3D11CreateDevice(
    nullptr,
    D3D_DRIVER_TYPE_HARDWARE,
    nullptr,
    D3D11_CREATE_DEVICE_DEBUG, // 启用DEBUG层,发布版可移除
    featureLevels,
    numFeatureLevels,
    D3D11_SDK_VERSION,
    &pDevice,
    &featureLevel,
    &pDeviceContext
);
if (FAILED(hr)) {
    // 处理设备创建失败,fallback到WARP设备
    hr = D3D11CreateDevice(
        nullptr,
        D3D_DRIVER_TYPE_WARP,
        nullptr,
        0,
        featureLevels,
        numFeatureLevels,
        D3D11_SDK_VERSION,
        &pDevice,
        &featureLevel,
        &pDeviceContext
    );
}

2. 正确遍历并选择DXGI输出设备

不能硬编码输出索引,需确认目标显示器为活跃状态:

IDXGIDevice* pDxgiDevice = nullptr;
IDXGIAdapter* pAdapter = nullptr;
IDXGIOutput1* pOutput1 = nullptr;

pDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&pDxgiDevice);
pDxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&pAdapter);

// 遍历所有输出设备,找到主显示器
for (UINT i = 0; ; i++) {
    IDXGIOutput* pOutput = nullptr;
    HRESULT hr = pAdapter->EnumOutputs(i, &pOutput);
    if (hr == DXGI_ERROR_NOT_FOUND) break;

    DXGI_OUTPUT_DESC outputDesc;
    pOutput->GetDesc(&outputDesc);
    if (outputDesc.AttachedToDesktop) {
        pOutput->QueryInterface(__uuidof(IDXGIOutput1), (void**)&pOutput1);
        pOutput->Release();
        break;
    }
    pOutput->Release();
}

3. 严格处理DuplicateOutput的返回值

IDXGIOutputDuplication创建失败是导致空指针的核心原因,必须检查HRESULT并处理常见错误:

IDXGIOutputDuplication* pDesktopDuplication = nullptr;
HRESULT hr = pOutput1->DuplicateOutput(pDevice, &pDesktopDuplication);
if (FAILED(hr)) {
    switch (hr) {
        case DXGI_ERROR_ACCESS_DENIED:
            MessageBox(nullptr, L"请以管理员权限运行", L"权限错误", MB_OK);
            break;
        case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
            MessageBox(nullptr, L"屏幕捕获资源被占用", L"资源冲突", MB_OK);
            break;
        default:
            char errMsg[256];
            sprintf_s(errMsg, "DuplicateOutput失败: 0x%X", hr);
            MessageBoxA(nullptr, errMsg, "错误", MB_OK);
            break;
    }
    // 释放资源并退出
    pOutput1->Release();
    pAdapter->Release();
    pDxgiDevice->Release();
    pDevice->Release();
    pDeviceContext->Release();
    return false;
}

4. 捕获帧时的安全检查

获取桌面资源前必须判断AcquireNextFrame的返回值,避免空指针:

DXGI_OUTDUPL_FRAME_INFO frameInfo;
IDXGIResource* pDesktopResource = nullptr;
HRESULT hr = pDesktopDuplication->AcquireNextFrame(500, &frameInfo, &pDesktopResource);

if (hr == DXGI_ERROR_WAIT_TIMEOUT) {
    // 超时,跳过本次捕获
    continue;
}
if (FAILED(hr)) {
    // 资源丢失,重新初始化Duplication
    pDesktopDuplication->ReleaseFrame();
    // 此处添加重新创建Duplication的逻辑
    continue;
}

// 后续处理pDesktopResource...

转换为OpenGL/ImGui可渲染纹理

捕获到的DXGI资源需转换为CPU可读格式,再导入到OpenGL/ImGui:

1. 将捕获帧转换为CPU可访问纹理

ID3D11Texture2D* pAcquiredTexture = nullptr;
pDesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)&pAcquiredTexture);

// 创建Staging纹理(CPU可读)
D3D11_TEXTURE2D_DESC desc;
pAcquiredTexture->GetDesc(&desc);
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
desc.Usage = D3D11_USAGE_STAGING;
desc.BindFlags = 0;
desc.MiscFlags = 0;

ID3D11Texture2D* pStagingTexture = nullptr;
pDevice->CreateTexture2D(&desc, nullptr, &pStagingTexture);
pDeviceContext->CopyResource(pStagingTexture, pAcquiredTexture);

// 映射纹理获取像素数据
D3D11_MAPPED_SUBRESOURCE mappedResource;
pDeviceContext->Map(pStagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource);
// mappedResource.pData 即为像素数据,格式为 DXGI_FORMAT_B8G8R8A8_UNORM

2. 导入到ImGui渲染

// 全局存储ImGui纹理ID
static ImTextureID g_ImGuiScreenTexture = 0;
const int width = desc.Width;
const int height = desc.Height;

if (!g_ImGuiScreenTexture) {
    // 创建新纹理
    ImGui_ImplOpenGL3_CreateTextureFromPixels(
        (const void*)mappedResource.pData,
        width, height, 4, // 4通道BGRA
        &g_ImGuiScreenTexture
    );
} else {
    // 更新现有纹理
    ImGui_ImplOpenGL3_UpdateTextureFromPixels(
        g_ImGuiScreenTexture,
        (const void*)mappedResource.pData,
        width, height, 4
    );
}

// 渲染到ImGui窗口
ImGui::Begin("Screen Capture");
ImGui::Image(g_ImGuiScreenTexture, ImVec2(width, height));
ImGui::End();

// 释放临时资源
pDeviceContext->Unmap(pStagingTexture, 0);
pStagingTexture->Release();
pAcquiredTexture->Release();
pDesktopResource->Release();
pDesktopDuplication->ReleaseFrame();

内容的提问来源于stack exchange,提问作者Tim van Naarden

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 23:47:17