public DwmCapture(IntPtr hWnd) { _captureHwnd = hWnd; #region Initialise the Direct3D device int adapterOrdinal = 0; _d3dEx = new Direct3DEx(); _adapterLuid = _d3dEx.GetAdapterLuid(adapterOrdinal); var presentParams = new PresentParameters { PresentFlags = PresentFlags.LockableBackBuffer, Windowed = true, BackBufferFormat = Format.A8R8G8B8, SwapEffect = SwapEffect.Flip }; _deviceEx = new DeviceEx(_d3dEx, adapterOrdinal, DeviceType.Hardware, _captureHwnd, SlimDX.Direct3D9.CreateFlags.Multithreaded | SlimDX.Direct3D9.CreateFlags.SoftwareVertexProcessing, presentParams); #endregion #region Setup the shared surface (using DWM) uint format = 0; IntPtr pSharedHandle = IntPtr.Zero; int hr = NativeMethods.GetSharedSurface(_captureHwnd, _adapterLuid, 0, 0, ref format, out pSharedHandle, 0); NativeMethods.UpdateWindowShared(_captureHwnd, 0, 0, 0, IntPtr.Zero, IntPtr.Zero); RECT winRect; NativeMethods.GetWindowRect(_captureHwnd, out winRect); Size size = new Size(winRect.Right - winRect.Left, winRect.Bottom - winRect.Top); /* Hack because SlimDX does not let you specify a shared handle for creating shared resources we * have to create an IDirect3DDevice9 reference to the device instead */ IDirect3DDevice9 devEx = (IDirect3DDevice9)Marshal.GetObjectForIUnknown(_deviceEx.ComPointer); IntPtr pTexture; devEx.CreateTexture((int)size.Width, (int)size.Height, 1, 1, format, 0, out pTexture, ref pSharedHandle); Texture texture = Texture.FromPointer(pTexture); _sharedSurface = texture.GetSurfaceLevel(0); _renderTarget = Surface.CreateRenderTarget(_deviceEx, (int)size.Width, (int)size.Height, Format.X8R8G8B8, MultisampleType.None, 0, false); _deviceEx.SetRenderTarget(0, _renderTarget); Surface.FromSurface(_renderTarget, _sharedSurface, Filter.None, 0); _systemMemorySurface = Surface.CreateOffscreenPlain(_deviceEx, (int)size.Width, (int)size.Height, Format.X8R8G8B8, Pool.SystemMemory); #endregion }
/// <summary> /// The InitializeDevice method is called by the Video Mixing Renderer 9 (VMR-9) /// when it needs the allocator-presenter to allocate surfaces. /// </summary> /// <param name="userId"> /// Application-defined identifier. This value is the same value that the application /// passed to the IVMRSurfaceAllocatorNotify9.AdviseSurfaceAllocator method in the /// dwUserID parameter. /// </param> /// <param name="lpAllocInfo"> /// Pointer to a VMR9AllocationInfo structure that contains a description of the surfaces to create. /// </param> /// <param name="lpNumBuffers"> /// On input, specifies the number of surfaces to create. When the method returns, /// this parameter contains the number of buffers that were actually allocated. /// </param> /// <returns>Returns an HRESULT code</returns> public int InitializeDevice(IntPtr userId, ref VMR9AllocationInfo lpAllocInfo, ref int lpNumBuffers) { if (m_allocatorNotify == null) { return(E_FAIL); } try { int hr; lock (m_staticLock) { /* These two pointers are passed to the the helper * to create our D3D surfaces */ var pDevice = GetComPointer(m_device); var pMonitor = GetAdapterMonitor(0); /* Setup our D3D Device with our renderer */ hr = m_allocatorNotify.SetD3DDevice(pDevice, pMonitor); DsError.ThrowExceptionForHR(hr); /* This is only used if the AllocateSurfaceHelper is used */ lpAllocInfo.dwFlags |= VMR9SurfaceAllocationFlags.TextureSurface; /* Make sure our old surfaces are free'd */ FreeSurfaces(); /* This is an IntPtr array of pointers to D3D surfaces */ DxSurfaces = new IntPtr[lpNumBuffers]; /* This is where the magic happens, surfaces are allocated */ hr = m_allocatorNotify.AllocateSurfaceHelper(ref lpAllocInfo, ref lpNumBuffers, DxSurfaces); if (hr < 0) { FreeSurfaces(); if (lpAllocInfo.Format > 0) { hr = m_device.CreateTexture(lpAllocInfo.dwWidth, lpAllocInfo.dwHeight, 1, 1, D3DFORMAT.D3DFMT_X8R8G8B8, 0, out m_privateTexture, IntPtr.Zero); DsError.ThrowExceptionForHR(hr); hr = m_privateTexture.GetSurfaceLevel(0, out m_privateSurface); DsError.ThrowExceptionForHR(hr); } lpAllocInfo.dwFlags &= ~VMR9SurfaceAllocationFlags.TextureSurface; lpAllocInfo.dwFlags |= VMR9SurfaceAllocationFlags.OffscreenSurface; DxSurfaces = new IntPtr[lpNumBuffers]; hr = m_allocatorNotify.AllocateSurfaceHelper(ref lpAllocInfo, ref lpNumBuffers, DxSurfaces); if (hr < 0) { FreeSurfaces(); return(hr); } } } /* Nofity to our listeners we have new surfaces */ InvokeNewSurfaceEvent(m_privateSurface != null ? GetComPointer(m_privateSurface) : DxSurfaces[0]); return(hr); } catch { return(E_FAIL); } }