BitBlt在OpenGL渲染的窗口上失败

时间:2016-10-10 23:08:38

标签: c# winapi opengl bitmap

我正在制作一个程序,以便在我流式传输时拍摄游戏的屏幕截图,因此需要截屏并自动保存,但是当我将游戏设置为使用OpenGL时,我的功能会失败,它会一直保存图像一遍又一遍,它只是在我重新开始游戏后改变图像。

它似乎在第一次运行时有效,但在下一次运行时它会保存第一张图像。

以下是我正在使用的内容:

public static Bitmap PrintWindow(IntPtr hwnd) {
       try {
           RECT rc;
           GetClientRect(hwnd, out rc);

           IntPtr hdcFrom = GetDC(hwnd);
           IntPtr hdcTo = CreateCompatibleDC(hdcFrom);
           //X and Y coordinates of window
           int Width = rc.right;
           int Height = rc.bottom;
           Bitmap bmp = null;

           IntPtr hBitmap = CreateCompatibleBitmap(hdcFrom, Width, Height);
           if (hBitmap != IntPtr.Zero) {
               // adjust and copy
               IntPtr hLocalBitmap = SelectObject(hdcTo, hBitmap);

               BitBlt(hdcTo, 0, 0, Width, Height, hdcFrom, 0, 0, CopyPixelOperation.SourceCopy);
               SelectObject(hdcTo, hLocalBitmap);
               //We delete the memory device context.
               DeleteDC(hdcTo);
               //We release the screen device context.
               ReleaseDC(hwnd, hdcFrom);
               //Image is created by Image bitmap handle and assigned to Bitmap variable.
               bmp = System.Drawing.Image.FromHbitmap(hBitmap);
               //Delete the compatible bitmap object. 
               DeleteObject(hBitmap);
               bmp.Save("saving.png", System.Drawing.Imaging.ImageFormat.Png);
           }

           return bmp;
       }
       catch {

       }

       return new Bitmap(0, 0);
   }

如果我改变游戏图形以使用DirectX它运行良好,它只是在使用OpenGL时发生,所以如果它对于openGL窗口必须是不同的,或者如果它不可能捕获那种窗口,那就不要了。

2 个答案:

答案 0 :(得分:4)

使用双缓冲OpenGL与使用GDI操作¹是互斥的。使用namespace Drupal\api_articles\Plugin\rest\resource; use Drupal\Core\Session\AccountProxyInterface; use Drupal\rest\Plugin\ResourceBase; use Drupal\rest\ResourceResponse; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Psr\Log\LoggerInterface; /** * Provides a resource to get view modes by entity and bundle. * * @RestResource( * id = "article_rest_resource", * label = @Translation("Article rest resource"), * uri_paths = { * "canonical" = "/api/v1/articles", * "https://www.drupal.org/link-relations/create" = "/api/v1/articles" * } * ) */ class ArticleRestResource extends ResourceBase { /** * A current user instance. * * @var \Drupal\Core\Session\AccountProxyInterface */ protected $currentUser; /** * Constructs a Drupal\rest\Plugin\ResourceBase object. * * @param array $configuration * A configuration array containing information about the plugin instance. * @param string $plugin_id * The plugin_id for the plugin instance. * @param mixed $plugin_definition * The plugin implementation definition. * @param array $serializer_formats * The available serialization formats. * @param \Psr\Log\LoggerInterface $logger * A logger instance. * @param \Drupal\Core\Session\AccountProxyInterface $current_user * A current user instance. */ public function __construct( array $configuration, $plugin_id, $plugin_definition, array $serializer_formats, LoggerInterface $logger, AccountProxyInterface $current_user) { parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger); $this->currentUser = $current_user; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->getParameter('serializer.formats'), $container->get('logger.factory')->get('api_articles'), $container->get('current_user') ); } /** * Responds to GET requests. * * Returns a list of bundles for specified entity. * * @throws \Symfony\Component\HttpKernel\Exception\HttpException * Throws exception expected. */ public function get() { // You must to implement the logic of your REST Resource here. // Use current user after pass authentication to validate access. if (!$this->currentUser->hasPermission('access content')) { throw new AccessDeniedHttpException(); } return new ResourceResponse("Implement REST State GET!"); } } 截取屏幕截图。

¹:嗯,从技术上讲,如果你知道自己在做什么,并采取正确的预防措施,你可以将它们混合在一起。但它比值得做的更麻烦。

答案 1 :(得分:0)

在最近的Windows 10更新后,DirectX渲染窗口现在遇到了同样的问题。我发现了一种解决方法,但你不会喜欢它...... 如果你设置hwnd = 0,BitBlt现在指的是整个屏幕,而不只是一个窗口。然后,您可以更改BitBlt的源偏移值以仅捕获目标窗口 虽然这有效,但它比原来的方式要慢得多。 :( 在我的笔记本电脑上,抓住一个1080p的窗口过去需要3ms,但现在,使用这种解决方法,它需要27ms,这真的破坏了流媒体性能。 :( 不过,它总比没有好。