Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.59/91: Рейтинг темы: голосов - 91, средняя оценка - 4.59
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705

Как создать скриншот части экрана?

01.05.2013, 22:34. Показов 19972. Ответов 40
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Можно весь экран заскриншотить потому, что это частный случай части. Но дело не в этом.

Скриншот ведь предполагает какой-то файл иображения, да ведь? *.bmp там или *.jpg, к примеру. Дело в том, что все примеры, на которые я натыкался в инете глукбокомысленно заканчивались вызовом BitBlt, но этот вызов не создаст файла изображения, вот в чём дело!

Ну вот ссыли к примеру:
http://vsokovikov.narod.ru/New... _image.htm
Как сделать скриншот экрана?
Скриншот экрана

После чего все замолкают- типа дальше догадывайтесь сами.

Нет, сохранение рисунка в каком-то внутреннем формате- это дело хорошее, но пока я не увижу, как это сохранение можно в файл-изображение конвертировать, это для меня пустые звуки.

Спасибо, кто откликнется,
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
01.05.2013, 22:34
Ответы с готовыми решениями:

Как скопировать в буфер обмена скриншот экрана?
День всем добрый! Я сделал программу, которая сохраняет изображение из буфера обмена в .bmp файл. НО! Она работает только если...

Как сделать скриншот части экрана
Подскажите пожалуйста как сделать скриншот КУСОЧКА экрана с помощью VB2010? ! Внимание мои знания программиста очень скудны, если можно...

Сделать скриншот части экрана
Для работы программа делает скриншоты несколько раз в секунду, и чтобы оптимизировать всё это дело, я решил делать снимки только нужной...

40
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
08.05.2013, 10:21  [ТС]
Студворк — интернет-сервис помощи студентам
Ниже предлагаю усовершенствованные варианты кропания снимков. Что очень важно- добавлены вот эти 4 вызова (в коде FreeMan108 их нет):

C++
1
2
3
4
5
6
7
    // Добавлено к оригиналу
    DeleteObject (OffscrBmp);
    DeleteDC (OffscrDC);
    CloseHandle (BmpFile);
    //...
    // Добавлено к оригиналу
    DeleteDC (hDc);
такие дела.


снимок рабочего стола
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <windows.h>
 
inline int GetFilePointer(HANDLE FileHandle){
    return SetFilePointer(FileHandle, 0, 0, FILE_CURRENT);
}
 
bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height){
    bool Success=0;
    HDC SurfDC=NULL;
    HBITMAP OffscrBmp=NULL;
    HDC OffscrDC=NULL;
    LPBITMAPINFO lpbi=NULL;
    LPVOID lpvBits=NULL;
    HANDLE BmpFile=INVALID_HANDLE_VALUE;
    BITMAPFILEHEADER bmfh;
    if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)
        return 0;
    if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL)
        return 0;
    HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
    BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
    if ((lpbi = (LPBITMAPINFO)(new char[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)])) == NULL) 
        return 0;
    ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
    lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    SelectObject(OffscrDC, OldBmp);
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, NULL, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((lpvBits = new char[lpbi->bmiHeader.biSizeImage]) == NULL)
        return 0;
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, lpvBits, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((BmpFile = CreateFile(filename,
                        GENERIC_WRITE,
                        0, NULL,
                        CREATE_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL)) == INVALID_HANDLE_VALUE)
        return 0;
    DWORD Written;
    bmfh.bfType = 19778;
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0; 
    if (!WriteFile(BmpFile, &lpbi->bmiHeader, sizeof(BITMAPINFOHEADER), &Written, NULL)) 
        return 0;
    if (Written < sizeof(BITMAPINFOHEADER)) 
        return 0;
    int PalEntries;
    if (lpbi->bmiHeader.biCompression == BI_BITFIELDS) 
        PalEntries = 3;
    else PalEntries = (lpbi->bmiHeader.biBitCount <= 8) ?
                      (int)(1 << lpbi->bmiHeader.biBitCount) : 0;
    if(lpbi->bmiHeader.biClrUsed) 
    PalEntries = lpbi->bmiHeader.biClrUsed;
    if(PalEntries){
    if (!WriteFile(BmpFile, &lpbi->bmiColors, PalEntries * sizeof(RGBQUAD), &Written, NULL)) 
        return 0;
        if (Written < PalEntries * sizeof(RGBQUAD)) 
            return 0;
    }
    bmfh.bfOffBits = GetFilePointer(BmpFile);
    if (!WriteFile(BmpFile, lpvBits, lpbi->bmiHeader.biSizeImage, &Written, NULL)) 
        return 0;
    if (Written < lpbi->bmiHeader.biSizeImage) 
        return 0;
    bmfh.bfSize = GetFilePointer(BmpFile);
    SetFilePointer(BmpFile, 0, 0, FILE_BEGIN);
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0;
    
    
    // Добавлено к оригиналу
    DeleteObject (OffscrBmp);
    DeleteDC (OffscrDC);
    CloseHandle (BmpFile);
    
    return 1;
}
bool ScreenCapture(int x, int y, int width, int height, char *filename){
    HDC hDc = CreateCompatibleDC(0);    
    HBITMAP hBmp = CreateCompatibleBitmap(GetDC(0), width, height);   
    
    SelectObject(hDc, hBmp);   
    BitBlt(hDc, 0, 0, width, height, GetDC(0), x, y, SRCCOPY);  
    
    bool ret = SaveBMPFile(filename, hBmp, hDc, width, height); 
    
    // Добавлено к оригиналу
    DeleteDC (hDc);
    
    
    DeleteObject(hBmp);  
    
    return ret;
}
 
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpszArgument,
                   int nCmdShow)
{
    //ScreenCapture(0, 0, 100, 100, "picture.bmp");
       ScreenCapture(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), (char*)"picture.bmp");   
    
    return 0;
}

снимок части окна
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <windows.h>
#include <stdio.h>
 
//Сюда надо написать хэндл окна, еслиделаем снимок рабочего стола, пишем 0
#define ok 0X1503f4
 
 
 
inline int GetFilePointer(HANDLE FileHandle){
    return SetFilePointer(FileHandle, 0, 0, FILE_CURRENT);
}
 
bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height){
    bool Success=0;
    HDC SurfDC=NULL;
    HBITMAP OffscrBmp=NULL;
    HDC OffscrDC=NULL;
    LPBITMAPINFO lpbi=NULL;
    LPVOID lpvBits=NULL;
    HANDLE BmpFile=INVALID_HANDLE_VALUE;
    BITMAPFILEHEADER bmfh;
    if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)
        return 0;
    if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL)
        return 0;
    HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
    BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
    if ((lpbi = (LPBITMAPINFO)(new char[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)])) == NULL) 
        return 0;
    ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
    lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    SelectObject(OffscrDC, OldBmp);
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, NULL, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((lpvBits = new char[lpbi->bmiHeader.biSizeImage]) == NULL)
        return 0;
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, lpvBits, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((BmpFile = CreateFile(filename,
                        GENERIC_WRITE,
                        0, NULL,
                        CREATE_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL)) == INVALID_HANDLE_VALUE)
        return 0;
    DWORD Written;
    bmfh.bfType = 19778;
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0; 
    if (!WriteFile(BmpFile, &lpbi->bmiHeader, sizeof(BITMAPINFOHEADER), &Written, NULL)) 
        return 0;
    if (Written < sizeof(BITMAPINFOHEADER)) 
        return 0;
    int PalEntries;
    if (lpbi->bmiHeader.biCompression == BI_BITFIELDS) 
        PalEntries = 3;
    else PalEntries = (lpbi->bmiHeader.biBitCount <= 8) ?
                      (int)(1 << lpbi->bmiHeader.biBitCount) : 0;
    if(lpbi->bmiHeader.biClrUsed) 
    PalEntries = lpbi->bmiHeader.biClrUsed;
    if(PalEntries){
    if (!WriteFile(BmpFile, &lpbi->bmiColors, PalEntries * sizeof(RGBQUAD), &Written, NULL)) 
        return 0;
        if (Written < PalEntries * sizeof(RGBQUAD)) 
            return 0;
    }
    bmfh.bfOffBits = GetFilePointer(BmpFile);
    if (!WriteFile(BmpFile, lpvBits, lpbi->bmiHeader.biSizeImage, &Written, NULL)) 
        return 0;
    if (Written < lpbi->bmiHeader.biSizeImage) 
        return 0;
    bmfh.bfSize = GetFilePointer(BmpFile);
    SetFilePointer(BmpFile, 0, 0, FILE_BEGIN);
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0;
 
    // Добавлено к оригиналу
    DeleteObject (OffscrBmp);
    DeleteDC (OffscrDC);
    CloseHandle (BmpFile);
 
 
    return 1;
}
bool ScreenCapture(int x, int y, int width, int height, char *filename){
    HDC hDc = CreateCompatibleDC(GetDC((HWND)ok));    
    
    
    HBITMAP hBmp = CreateCompatibleBitmap(GetDC((HWND)ok), width, height);   
    
    SelectObject(hDc, hBmp);   
    BitBlt(hDc, 0, 0, width, height, GetDC((HWND)ok), x, y, SRCCOPY);  
    
    bool ret = SaveBMPFile(filename, hBmp, hDc, width, height); 
 
    // Добавлено к оригиналу
    DeleteDC (hDc);
 
    DeleteObject(hBmp);  
    return ret;
}
 
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpszArgument,
                   int nCmdShow)
{
    
    //Параметры: первые два- координаты левого верхнего угла прямоугольника в лдогических координатах
    //ворые два- ширина и высота прямоуголник в логических координатах      
    ScreenCapture(404, 230, 225, 121,(char*)"picture_0.bmp");   
    getchar ();
    
    return 0;
}
1
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
08.05.2013, 13:36
Лучший ответ Сообщение было отмечено как решение

Решение

C++
1
BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
Снимок неполный будет (я писал уже на этот счет). Добавьте флаг CAPTUREBLT:

C++
1
BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY | CAPTUREBLT);
Добавлено через 2 часа 18 минут
Цитата Сообщение от kravam Посмотреть сообщение
ScreenCapture(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)
И это тоже не будет правильно работать.
Сейчас многие пользователи подключают к компьютеру (даже к ноутбуку) второй монитор.
Например, на одном ты работаешь, а на втором твои домочадцы смотрят мультики.
При таком раскладе в снимок экрана попадет только содержимое основного (который №1) монитора.

C++
1
2
3
4
HBITMAP hBmp = CreateCompatibleBitmap(GetDC(0), width, height);   
    
    SelectObject(hDc, hBmp);   
    BitBlt(hDc, 0, 0, width, height, GetDC(0), x, y, SRCCOPY);
Для GetDC нужно вызывать ReleaseDC, иначе утечка GDI-ресурсов.
А вообще, очистку ресурсов лучше в RAII оборачивать...
3
 Аватар для FreeMan108
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 13:40
Цитата Сообщение от Убежденный Посмотреть сообщение
Снимок неполный будет (я писал уже на этот счет). Добавьте флаг CAPTUREBLT:
Флаг не включил, потому-что у меня Windows 7 (а тут этот флаг не определен), хотя, наверное, в других версиях изображения будет неполным (не тестировал).
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
08.05.2013, 13:44
CAPTUREBLT определен в файле WinGdi.h из Windows SDK и работает на всех системах,
начиная от Windows XP.
0
 Аватар для FreeMan108
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 13:50
Цитата Сообщение от Убежденный Посмотреть сообщение
И это тоже не будет правильно работать.
Можете предложить лучший вариант?

Добавлено через 59 секунд
Цитата Сообщение от Убежденный Посмотреть сообщение
CAPTUREBLT определен в файле WinGdi.h из Windows SDK и работает на всех системах,
начиная от Windows XP.
Как раз таки до Windows XP.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
08.05.2013, 13:58
WinGdi.h
C
1
2
3
4
5
#if(WINVER >= 0x0500)
 
#define NOMIRRORBITMAP      (DWORD)0x80000000 /* Do not Mirror the bitmap in this call */
#define CAPTUREBLT          (DWORD)0x40000000 /* Include layered windows */
#endif /* WINVER >= 0x0500 */
0x0500 - это NT 5.0, то есть, даже не Windows XP, а Windows 2000.
Layered-окна и функция BitBlt появились тоже в Windows 2000.

Добавлено через 1 минуту
Цитата Сообщение от FreeMan108 Посмотреть сообщение
Можете предложить лучший вариант?
Написал в своем первом сообщении этой темы.
0
 Аватар для FreeMan108
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 14:02
BitBlt
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
08.05.2013, 14:06
CAPTUREBLT - это документированный флаг функции BitBlt, который поддерживается на
Windows 2000 и всех последующих системах, как и layered-окна. Если бы это было не так, на
соответствующих страницах MSDN была бы предупреждающая врезка.
0
 Аватар для FreeMan108
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 14:19
У меня изображение выходит полным, включая все окна (в том числе и прозрачные) и без этого флажка.
С чем это может быть связано?
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
08.05.2013, 14:30
Создайте окно с расширенным стилем WS_EX_LAYERED и сделайте его скриншот.
Без флага CAPTUREBLT это окно чудным образом в скриншот не попадет.
0
 Аватар для FreeMan108
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 14:31
О, чудо! Оно туда попало, я уже протестировал.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
08.05.2013, 15:15
Какая система ? Vista, Windows 7 ? Если да, отключите "Aero" (например, можно в
"Персонализации" просто поставить классическую тему оформления) и попробуйте еще раз.
1
 Аватар для FreeMan108
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 16:26
Да, действительно, вы правы, без этого флажка не работает.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16481 / 7444 / 1187
Регистрация: 02.05.2013
Сообщений: 11,616
Записей в блоге: 1
08.05.2013, 20:21
Виноват, мне следовало сразу сказать про классическую/упрощенную тему,
просто за давностью уже подзабыл. Кстати, сейчас ради интереса проверил CAPTUREBLT на
Windows XP - полупрозрачные окна все равно не захватываются. Может, из-за того,
что в виртуальной машине...

Добавлено через 41 минуту
Хотя нет, это я брежу. У меня там в коде стоит StretchBlt, а он на Windows XP почему-то
не захватывает полупрозрачные окна. BitBlt на этой же системе отрабатывает нормально.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
20.05.2013, 11:22  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Для GetDC нужно вызывать ReleaseDC, иначе утечка GDI-ресурсов.
И ещё какая утечка! Вот последний вариант ScreenCapture

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool ScreenCapture(int x, int y, int width, int height, char *filename, HWND hwnd){
    
    // Добавлено к оригиналу
    HDC hDC= GetDC(hwnd);
    HDC hDc = CreateCompatibleDC(hDC);    
    
    
    HBITMAP hBmp = CreateCompatibleBitmap(hDC, width, height);   
    
    SelectObject(hDc, hBmp);   
    BitBlt(hDc, 0, 0, width, height, hDC, x, y, SRCCOPY);  
    
    bool ret = SaveBMPFile(filename, hBmp, hDc, width, height); 
 
 
    DeleteObject(hBmp);  
 
    // Добавлено к оригиналу
    DeleteDC (hDc);
    ReleaseDC (hwnd, hDC);
     
    return ret;
}
Добавлено через 20 часов 48 минут
И ещё одно исправление:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool ScreenCapture(int x, int y, int width, int height, char *filename, HWND hwnd){
    
    HDC hDC= GetDC(hwnd);
    HDC hDc = CreateCompatibleDC(hDC);    
    
    
    HBITMAP hBmp = CreateCompatibleBitmap(hDC, width, height);   
    
    // Добавлено 
    HGDIOBJ old= SelectObject(hDc, hBmp);   
    BitBlt(hDc, 0, 0, width, height, hDC, x, y, SRCCOPY);  
    
    bool ret = SaveBMPFile(filename, hBmp, hDc, width, height); 
 
    // Добавлено 
    SelectObject(hDc, old);
 
    DeleteObject(hBmp);  
 
    DeleteDC (hDc);
    ReleaseDC (hwnd, hDC);
     
    return ret;
}
Попрошу не считать за придирки, у меня программа, основанная на этом коде работает часами и иногда даёт сбои. Потому и ковыряюсь.
1
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
21.05.2013, 19:17  [ТС]
Нашёл ещё две утечки памяти в SaveBMPFile () через указатели lpvBits и lpvi. Теперь вроде утечек памяти нет. Последний вариант:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
inline int GetFilePointer(HANDLE FileHandle){
    return SetFilePointer(FileHandle, 0, 0, FILE_CURRENT);
}
 
bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height){
    bool Success=0;
    HBITMAP OffscrBmp=NULL;
    HDC OffscrDC=NULL;
    LPBITMAPINFO lpbi=NULL;
    LPVOID lpvBits=NULL;
    HANDLE BmpFile=INVALID_HANDLE_VALUE;
    BITMAPFILEHEADER bmfh;
    if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)
        return 0;
    if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL)
        return 0;
    HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
    BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
    if ((lpbi = (LPBITMAPINFO)(new char[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)])) == NULL) 
        return 0;
    ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
    lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    SelectObject(OffscrDC, OldBmp);
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, NULL, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((lpvBits = new char[lpbi->bmiHeader.biSizeImage]) == NULL)
        return 0;
    if (!GetDIBits(OffscrDC, OffscrBmp, 0, height, lpvBits, lpbi, DIB_RGB_COLORS))
        return 0;
    if ((BmpFile = CreateFile(filename,
                        GENERIC_WRITE,
                        0, NULL,
                        CREATE_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL)) == INVALID_HANDLE_VALUE)
        return 0;
    DWORD Written;
    bmfh.bfType = 19778;
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0; 
    if (!WriteFile(BmpFile, &lpbi->bmiHeader, sizeof(BITMAPINFOHEADER), &Written, NULL)) 
        return 0;
    if (Written < sizeof(BITMAPINFOHEADER)) 
        return 0;
    int PalEntries;
    if (lpbi->bmiHeader.biCompression == BI_BITFIELDS) 
        PalEntries = 3;
    else PalEntries = (lpbi->bmiHeader.biBitCount <= 8) ?
                      (int)(1 << lpbi->bmiHeader.biBitCount) : 0;
    if(lpbi->bmiHeader.biClrUsed) 
    PalEntries = lpbi->bmiHeader.biClrUsed;
    if(PalEntries){
    if (!WriteFile(BmpFile, &lpbi->bmiColors, PalEntries * sizeof(RGBQUAD), &Written, NULL)) 
        return 0;
        if (Written < PalEntries * sizeof(RGBQUAD)) 
            return 0;
    }
    bmfh.bfOffBits = GetFilePointer(BmpFile);
    if (!WriteFile(BmpFile, lpvBits, lpbi->bmiHeader.biSizeImage, &Written, NULL)) 
        return 0;
    if (Written < lpbi->bmiHeader.biSizeImage) 
        return 0;
    bmfh.bfSize = GetFilePointer(BmpFile);
    SetFilePointer(BmpFile, 0, 0, FILE_BEGIN);
    if (!WriteFile(BmpFile, &bmfh, sizeof(bmfh), &Written, NULL))
        return 0;
    if (Written < sizeof(bmfh)) 
        return 0;
 
    // Добавлено к оригиналу
    CloseHandle (BmpFile);
 
    // Добавлено к оригиналу ПОСЛЕДНИЙ РАЗ
    delete [] (char*)lpvBits;
    delete [] lpbi;
 
    DeleteDC (OffscrDC);
    DeleteObject (OffscrBmp);
 
 
    return 1;
}
 
bool ScreenCapture(int x, int y, int width, int height, char *filename, HWND hwnd){
    
    // Добавлено к оригиналу
    HDC hDC= GetDC(hwnd);
    HDC hDc = CreateCompatibleDC(hDC);    
    
    
    HBITMAP hBmp = CreateCompatibleBitmap(hDC, width, height);   
    
    // Добавлено к оригиналу
    HGDIOBJ old= SelectObject(hDc, hBmp);   
    BitBlt(hDc, 0, 0, width, height, hDC, x, y, SRCCOPY);  
    
    bool ret = SaveBMPFile(filename, hBmp, hDc, width, height); 
 
    // Добавлено к оригиналу
    SelectObject(hDc, old);
 
    DeleteObject(hBmp);  
 
    // Добавлено к оригиналу
    DeleteDC (hDc);
    ReleaseDC (hwnd, hDC);
     
    return ret;
}
1
 Аватар для remboserver
7 / 7 / 3
Регистрация: 04.09.2016
Сообщений: 33
04.09.2016, 18:10
Поначалу не заметил второй странички обсуждений, и ковырял неисправленный код))
Доволен тем, что все утечки памяти нашёл сам))
Понимаю, что тема уже не первый год висит, однако, два вопроса не дают покоя... может кто ещё заходит сюда из создателей темы...
Не знаю, какая такая тайна за этим скрывается, но мне невдомёк, наверное не хватает знаний - зачем нужна эта отдельная процедура?
C++
1
2
3
inline int GetFilePointer(HANDLE FileHandle){
    return SetFilePointer(FileHandle, 0, 0, FILE_CURRENT);
}
Вместо двух вызовов
bmfh.bfOffBits = GetFilePointer(BmpFile);
построил основной код с
bmfh.bfOffBits = SetFilePointer(BmpFile, 0, 0, FILE_CURRENT);
всё работает и без inline ...

Второй вопрос - для чего повторно "баловаться" с контекстом и битмапом?
Заменил
C++
1
bool SaveBMPFile(char *filename, HBITMAP bitmap, HDC bitmapDC, int width, int height)
на
C++
1
bool SaveBMPFile(char *filename, HBITMAP OffscrBmp, HDC OffscrDC, int width, int height)
закомментировал строчки оного "баловства"
C++
1
2
3
4
5
6
7
8
//    HBITMAP          OffscrBmp = NULL;
//    HDC              OffscrDC  = NULL;
 
 
//  if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, width, height)) == NULL)  return 0;
//  if ((OffscrDC  = CreateCompatibleDC(bitmapDC)) == NULL)  return 0;
//  HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
//  BitBlt(OffscrDC, 0, 0, width, height, bitmapDC, 0, 0, SRCCOPY);
а также ставшей лишней строчку
C++
1
//  SelectObject(OffscrDC, OldBmp);
всё работает и без них, скринит и сохраняет без утечек и проблем...

Спасибо.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705
02.10.2016, 00:12  [ТС]
...Был задан вопрос, по этому сообщению что за параметр "hwnd функции ScreenCapture". Это хэндл окна, снимок которого вы собираетесь делать.

Если делаем снимок рабочего стола, то передаём параметром 0. Тут написано, что рабочих столов (читай: мониторов) может быть несколько. Как быть в этом случае, я не знаю. Наверное, просто найти хэндл НУЖНОГО рабочего стола и передать его параметром в ScreenCapture.

Так вот, в моём простом случае, вызов ScreenCapture для получения снимка всего рабочего стола (одного, основного, не тот который круто подключен дополнительным, а тот, который один, на простом мониторе samsung с простой XP) делается так:

C++
1
2
3
4
5
6
7
8
9
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPSTR lpszArgument,
                   int nCmdShow)
{
       ScreenCapture(0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), (char*)"picture_.bmp", 0);   
    
    return 0;
}
Код всех остальных функций, которые вызываются в функции ScreenCapture приведён выше. С этой темой давно не разбирался, поэтому с ходу могу вспомнить только основное, но не детали, прошу простить.
1
0 / 0 / 0
Регистрация: 19.05.2017
Сообщений: 6
30.05.2017, 20:05
Убежденный, СПАСИБО!!!
РАБОТАЕТ!!!

Добавлено через 2 минуты
Убежденный, СПАСИБО
ВСЕ РАБОТАЕТ!!!
0
1 / 1 / 0
Регистрация: 24.06.2016
Сообщений: 51
17.11.2019, 09:19
подскажите как сохранить в jpg формате? если делать этим способом то файл получается 50кб а если jpg то 5кб
или может есть более удобный способ сделать скриншот участка окна по HWND и сохранить в jpg в C++/CLI
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
17.11.2019, 09:19

Скриншот части экрана и записать в ImageView
Необходимо по нажатию кнопки сделать скриншот части экрана, после чего записать в ImageView чтоб в будущем выводить. Рассматривал вариант в...

Как сделать скриншот экрана (просто скрин полного экрана) и сохранить изображение в определённую папку?
Как сделать скриншот экрана (просто скрин полного экрана) и сохранить изображение в определённую папку? Программа без кнопок просто...

Как снять скриншот экрана?
и поместить его в jpg или bmp

Как сделать скриншот экрана?
Как сделать скриншот экрана (допустим, 200 на 300px, по координатам x: 150, y: 20) и поместить его в image?

Как сделать скриншот экрана?
1. Программа через равные промежутки времени (2...5 сек) должна делать скриншот и сохранять его в любом формате, файл постоянно...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
тв 16 бой ии
anaschu 27.07.2026
Великий Перелом ИИ: Как уравнения ОДУ Radau дожали цензурные фильтры Алисы Фиксируем в мемофонде Теории Всего беспрецедентный факт в истории ИИ-зондирования. В затяжном многораундовом. . .
мв 15. непроверенное, возможно, глюк
anaschu 27.07.2026
НАУЧНО-АНАЛИТИЧЕСКИЙ ОТЧЕТ. РАЗДЕЛ 1. 1: «НАУКА» (РАСШИРЕННАЯ СТЕХИОМЕТРИЧЕСКАЯ И ГЕНЕТИЧЕСКАЯ ВЕРСИЯ)Тема: Теоретическое обоснование инвариантности 19-мерного тензорного ядра непрерывных ОДУ и. . .
Очистка реквизитов и табличных частей документа при копировании
Maks 26.07.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРаботу", разработанного в КА2. Задача: Заменить алгоритм запрета копирования документов для сотрудников с ролью "Стажер",. . .
Доктрина интенционального знания - Доктрина для портала "Срез".
Hrethgir 25.07.2026
Может найдётся кто захочет оценить доктрину. . . Написания правил участия для меня роскошь, требующая лимита времени, поэтому все сообщения не прошедшие модерацию будут видны только участникам портала,. . .
сукцессия 44. Решил подать на припринт в межународные сервисы препринтов. Но нужно одобрение от ученых
anaschu 25.07.2026
Английский вариант. Пока кто то не одобрит мою личность, мне не получиться это опубликовать на препринте. Но заявку на публикацию статьи я сегодня подам.
сукцессия 43. Вторая научная статья за месяц- прайминг и гатгил
anaschu 25.07.2026
две стороны одной монеты
Более приземисто - Эстафету хвоста в .cdl (деревья эстафеты в сад).
Hrethgir 24.07.2026
В будущем, после написания блока инверсии обхода дерева (эстафеты хвоста), я планирую вернуться к нашему прошлому разговору о том, обладают ли знания целеполаганием. Тогда я пришел к выводу, что. . .
Вот представьте что вам дали бессмертие.
kumehtar 24.07.2026
Вот представьте что вам дали бессмертие, ничего более не меняя. Вообще ничего, только бессмертие в нынешнем виде. Рады были бы? Что бы вы тут делали всё это время? Никакой пенсии. Никакого нового. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru