1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

さらにDWMキャプチャを試してみる

Last updated at Posted at 2021-06-11

しつこいですかw

の続続編です。こういうのは一気に片付けないと。。。

をみて、DWMSharedSurfaceを使ったキャプチャを実装してみました。

前々回のソースに追加していきます。
DWMをつかったウィンドウ指定の隠れ関数があるらしい(なぜかdwmapi.dllじゃなくてuser32.dllに)
ってことなので抜き出します。

// DWM Capture
BOOL (__stdcall *DwmGetDxSharedSurface)(HWND, HANDLE *, uint64_t *, DWORD *, DWORD *, uint64_t *)=NULL;
uint64_t adapterLuid=0;
HANDLE pDXGI_SharedHandle=NULL;
ID3D11Texture2D *texture_shared=NULL;

関数の第1、第2引数だけあれば動作するらしいんですが、参考にさせてもらったサイトの情報に習い、アダプターのLUIDも生成しておきます。

  // load DWM-function
  HMODULE hdll=LoadLibrary("user32.dll");
  if(hdll){
    DwmGetDxSharedSurface=(BOOL(__stdcall *)(HWND, HANDLE *, uint64_t *, DWORD *, DWORD *, uint64_t *))
      GetProcAddress(hdll, "DwmGetDxSharedSurface");
  }
  if(DwmGetDxSharedSurface==NULL) printf("not found function: DwmGetDxSharedSurface\n");
  
  IDXGIAdapter1 *adapter;
  DXGI_ADAPTER_DESC1 dxgi_desc{};
  pDXGI_Factory->EnumAdapters1(0, &adapter); // index=0;
  adapter->GetDesc1(&dxgi_desc);
  adapterLuid=(((uint64_t)dxgi_desc.AdapterLuid.HighPart)<<32)|(dxgi_desc.AdapterLuid.LowPart);
  adapter->Release();
  printf("adapter's LUID=%llu\n", adapterLuid);

キャプチャ開始すると共有リソースに対象ウィンドウのテクスチャが更新され続けるようです。

bool CaptDWM_FrameCopy(IDXGISwapChain1 *swapchain)
{
  DXGI_SWAP_CHAIN_DESC1 sc_desc{};
  swapchain->GetDesc1(&sc_desc);

  int offset_x=1;
  int offset_y=GetSystemMetrics(SM_CYCAPTION)+8;
  D3D11_BOX src_region{};
  src_region.left   =offset_x;
  src_region.right  =offset_x+sc_desc.Width;
  src_region.top    =offset_y;
  src_region.bottom =offset_y+sc_desc.Height;
  src_region.front  =0;
  src_region.back   =1;
  
  ID3D11Texture2D *texture_dst;
  swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&texture_dst);
  
  pD3D_DC->CopySubresourceRegion(texture_dst, 0, 0, 0, 0, texture_shared, 0, &src_region);
  
  texture_dst->Release();
  return true;
}

bool CaptDWM_Start(MyWin wDst, HWND hwndSrc)
{
  if(pDXGI_SharedHandle!=NULL) return false;

  if(DwmGetDxSharedSurface==NULL) return false;
  DwmGetDxSharedSurface(hwndSrc, &pDXGI_SharedHandle, &adapterLuid, NULL, NULL, NULL);
  if((pDXGI_SharedHandle==NULL)||(pDXGI_SharedHandle==INVALID_HANDLE_VALUE)) return false;

  pD3D_Device->OpenSharedResource(pDXGI_SharedHandle, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(&texture_shared));
  if(texture_shared==NULL) return false;

  D3D11_TEXTURE2D_DESC texture_desc{};
  texture_shared->GetDesc(&texture_desc);

  printf("start capture(%d,%d) with DWM\n", texture_desc.Width, texture_desc.Height);
  return true;
}

void CaptDWM_Stop()
{
  if(texture_shared!=NULL) { texture_shared->Release(); texture_shared=NULL; }
  if(pDXGI_SharedHandle!=NULL){ CloseHandle(pDXGI_SharedHandle);  pDXGI_SharedHandle=NULL; }
}

ってことで、排他も考えずにガンガンコピーします。(DirectX11だとどうなんじゃろ?)

    if(mywinO.pDXGI_DC!=NULL){
      if(texture_shared!=NULL){
        CaptDWM_FrameCopy(mywinO.pDXGI_SwapChain);
        mywinO.pDXGI_DC->BeginDraw();
        mywinO.pDXGI_DC->SetTransform(D2D1::Matrix3x2F::Identity());
        mywinO.pDXGI_DC->DrawBitmap(Overlay_Image_Bitmap,
                                    D2D1::RectF(220.f, 0.f, 220.f+(float)overlay_image_width, 0.f+(float)overlay_image_height),
                                    1.f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
        mywinO.pDXGI_DC->EndDraw();
        mywinO.pDXGI_SwapChain->Present(1, 0);

    }

あの忌々しい黄色い枠はこの方法だと付きませんね^^(その分だけズレが発生しました)
しかーし、DierctXの描画はキャプチャされませんでした><

image.png

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?