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

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

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

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

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

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

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

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

Спасибо, кто откликнется,
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
01.05.2013, 22:34
Ответы с готовыми решениями:

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

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

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

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

40
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
08.05.2013, 10:21  [ТС] 21
Author24 — интернет-сервис помощи студентам
Ниже предлагаю усовершенствованные варианты кропания снимков. Что очень важно- добавлены вот эти 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
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
08.05.2013, 13:36 22
Лучший ответ Сообщение было отмечено как решение

Решение

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
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 13:40 23
Цитата Сообщение от Убежденный Посмотреть сообщение
Снимок неполный будет (я писал уже на этот счет). Добавьте флаг CAPTUREBLT:
Флаг не включил, потому-что у меня Windows 7 (а тут этот флаг не определен), хотя, наверное, в других версиях изображения будет неполным (не тестировал).
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
08.05.2013, 13:44 24
CAPTUREBLT определен в файле WinGdi.h из Windows SDK и работает на всех системах,
начиная от Windows XP.
0
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 13:50 25
Цитата Сообщение от Убежденный Посмотреть сообщение
И это тоже не будет правильно работать.
Можете предложить лучший вариант?

Добавлено через 59 секунд
Цитата Сообщение от Убежденный Посмотреть сообщение
CAPTUREBLT определен в файле WinGdi.h из Windows SDK и работает на всех системах,
начиная от Windows XP.
Как раз таки до Windows XP.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
08.05.2013, 13:58 26
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
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 14:02 27
BitBlt
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
08.05.2013, 14:06 28
CAPTUREBLT - это документированный флаг функции BitBlt, который поддерживается на
Windows 2000 и всех последующих системах, как и layered-окна. Если бы это было не так, на
соответствующих страницах MSDN была бы предупреждающая врезка.
0
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 14:19 29
У меня изображение выходит полным, включая все окна (в том числе и прозрачные) и без этого флажка.
С чем это может быть связано?
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
08.05.2013, 14:30 30
Создайте окно с расширенным стилем WS_EX_LAYERED и сделайте его скриншот.
Без флага CAPTUREBLT это окно чудным образом в скриншот не попадет.
0
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 14:31 31
О, чудо! Оно туда попало, я уже протестировал.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
08.05.2013, 15:15 32
Какая система ? Vista, Windows 7 ? Если да, отключите "Aero" (например, можно в
"Персонализации" просто поставить классическую тему оформления) и попробуйте еще раз.
1
121 / 121 / 32
Регистрация: 04.03.2013
Сообщений: 370
08.05.2013, 16:26 33
Да, действительно, вы правы, без этого флажка не работает.
0
Ушел с форума
Эксперт С++
16473 / 7436 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
08.05.2013, 20:21 34
Виноват, мне следовало сразу сказать про классическую/упрощенную тему,
просто за давностью уже подзабыл. Кстати, сейчас ради интереса проверил CAPTUREBLT на
Windows XP - полупрозрачные окна все равно не захватываются. Может, из-за того,
что в виртуальной машине...

Добавлено через 41 минуту
Хотя нет, это я брежу. У меня там в коде стоит StretchBlt, а он на Windows XP почему-то
не захватывает полупрозрачные окна. BitBlt на этой же системе отрабатывает нормально.
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
20.05.2013, 11:22  [ТС] 35
Цитата Сообщение от Убежденный Посмотреть сообщение
Для 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
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
21.05.2013, 19:17  [ТС] 36
Нашёл ещё две утечки памяти в 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
6 / 6 / 3
Регистрация: 04.09.2016
Сообщений: 32
04.09.2016, 18:10 37
Поначалу не заметил второй странички обсуждений, и ковырял неисправленный код))
Доволен тем, что все утечки памяти нашёл сам))
Понимаю, что тема уже не первый год висит, однако, два вопроса не дают покоя... может кто ещё заходит сюда из создателей темы...
Не знаю, какая такая тайна за этим скрывается, но мне невдомёк, наверное не хватает знаний - зачем нужна эта отдельная процедура?
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
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,679
02.10.2016, 00:12  [ТС] 38
...Был задан вопрос, по этому сообщению что за параметр "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 39
Убежденный, СПАСИБО!!!
РАБОТАЕТ!!!

Добавлено через 2 минуты
Убежденный, СПАСИБО
ВСЕ РАБОТАЕТ!!!
0
1 / 1 / 0
Регистрация: 24.06.2016
Сообщений: 44
17.11.2019, 09:19 40
подскажите как сохранить в jpg формате? если делать этим способом то файл получается 50кб а если jpg то 5кб
или может есть более удобный способ сделать скриншот участка окна по HWND и сохранить в jpg в C++/CLI
0
17.11.2019, 09:19
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.11.2019, 09:19
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru