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

しつこいですかw

https://qiita.com/tanakah/items/e36e764ae4592523e11b

https://qiita.com/tanakah/items/9a0bacc08a720cfdb75b

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


https://blog.techlab-xe.net/post-5285/

と

https://github.com/mika-sandbox/dotnet-window-capture

をみて、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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167175/a42ab0d5-2a11-8ae3-8dcb-b3c2f71047f4.png)