быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,705

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

01.05.2013, 22:34. Показов 20045. Ответов 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
Ответ Создать тему
Опции темы

Новые блоги и статьи
Саморегулирующийся социальный контракт для сервера cross-section.
Hrethgir 14.08.2026
С кодом конечно таких глубоких размышлений пока не было, впрочем я уже привык к алгоритмизации. Суть предмета записи: снова в диалоге с нейросетью (я взял пока себе ник для учётки админа - Rector). . . .
Часы электронные
Uhbif79 12.08.2026
Выкладываю программу часов. Программа позволяет: 1. Использовать системное время и дату, 2. Есть возможность вводить время и дату вручную. 3. Реализованы 2 будильника: начало и конец рабочего дня. . . .
Часы с будильником на основе класса QLCDNumber
Uhbif79 12.08.2026
Всем добрый день, выкладываю программу часов с будильником на основе класса QLCDNumber. Здесь я пробовал самостоятельно создавал классы, впервые столкнулся с видимостью переменной одного класса из. . .
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru