Как использовать BitBlt для захвата снимка экрана?

Я время от времени сталкивался с этим «BitBlt» в своем поиске, но я не понимаю, как его использовать.

Судя по тому, что говорят люди, это самый быстрый способ сделать снимок экрана, который показывает Windows. Тем не менее, я ничего не могу сказать об этом сам, поскольку у меня это не работает.

Единственное, что мне удалось хотя бы попробовать, это метод:

 gfxBmp.CopyFromScreen(0,0,0,0 rc.Size,CopyPixelOperation.CaptureBlt);

Который, я думаю, использует его? (rc.size = размер определенного окна) К сожалению, это ничего не делает, я получаю черную картинку. однако, если я использую SourceCopy, это работает, но это нормальный метод.

В настоящее время я пытаюсь заменить некоторый код, чтобы использовать BltBit, но он тоже не работает так хорошо:

    public MemoryStream CaptureWindow(IntPtr hwnd, EncoderParameters JpegParam)
    {
        NativeMethods.Rect rc;
        NativeMethods.GetWindowRect(hwnd, out rc);
        using (Bitmap bmp = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
        {

            using (Graphics gfxBmp = Graphics.FromImage(bmp))
            {
                IntPtr hdcBitmap = gfxBmp.GetHdc();
                try
                { 

                    NativeMethods.BitBlt(hdcBitmap, 0, 0, 0, 0, hwnd, 0, 0, 0xCC0020);

                }
                finally
                {
                    gfxBmp.ReleaseHdc(hdcBitmap);
                }
            }
            MemoryStream ms = new MemoryStream();
            bmp.Save(ms, GetEncoderInfo(ImageFormat.Jpeg), JpegParam);

            return ms;
        }
    }

person Zerowalker    schedule 09.08.2013    source источник


Ответы (1)


Вы правы, Graphics.CopyFromScreen уже использует BitBlt внутри. Далее код из .NET 4.0 Framework:

// [...]
new UIPermission(UIPermissionWindow.AllWindows).Demand();
int width = blockRegionSize.Width;
int height = blockRegionSize.Height;
using (DeviceContext deviceContext = DeviceContext.FromHwnd(IntPtr.Zero))
{
    HandleRef hSrcDC = new HandleRef(null, deviceContext.Hdc);
    HandleRef hDC = new HandleRef(null, this.GetHdc());
    try
    {
        if (SafeNativeMethods.BitBlt(hDC, destinationX, destinationY, width, height, hSrcDC, sourceX, sourceY, (int)copyPixelOperation) == 0)
        {
            throw new Win32Exception();
        }
    }
    finally
    {
        this.ReleaseHdc();
    }
}

Есть и другие возможности захвата скриншотов. Вы также можете использовать функцию WinAPI PrintWindow.

Но для контента, ускоренного графической картой, оба варианта не будут работать. Аппаратное наложение находится в памяти графического процессора, где вы не можете получить к нему доступ. Вот почему вы часто получаете черное изображение для видео, игр, ...

person Thomas B.    schedule 09.08.2013
comment
Оно делает? он использует его даже с SourceCopy? Что касается кода, я не понимаю, как реализовать его в моем коде (другой сегмент кода в моем посте). В настоящее время я использую PrintWindow, хотя у меня есть небольшая проблема с ним, так как он заставляет окно постоянно обновляться. Некоторым приложениям это не нравится. - person Zerowalker; 09.08.2013
comment
Код был лишь выдержкой из кода CopyFromScreen. Используйте ILSpy(ilspy.net), чтобы убедиться в этом самостоятельно. - person Thomas B.; 09.08.2013
comment
А, тогда я понимаю, почему ты так написал. Хм, все же нужно как-то заставить его работать, так как я получаю только черный экран, независимо от того, что я захватываю с помощью BlBit (может быть рабочий стол или что-то еще). - person Zerowalker; 09.08.2013