Форум программистов, компьютерный форум, киберфорум
Delphi: Графика, звук, видео
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 01.03.2024
Сообщений: 11
1

Копирование содержимого окна в bitmap

30.06.2024, 18:43. Показов 685. Ответов 19
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всех приветствую,

Столкнулся со следующей проблемой при копировании содержимого экрана в bitmap:

содержимое одного из окно десктопового приложения не копируется, в bitmap прилетает изображение экрана находящееся за данным окном.
Толи защита какая то стоит от printScr, понять не могу.

Также происходит при попытке копирования в буфер стандартными средствами винды (printScr, ножницы, win+shift+s),
окно данного приложения просто игнорируется, а в буфер прилетает картинка рабочего стола.

делаю все стандартно ...

Delphi
1
2
3
4
5
6
7
8
9
10
11
var 
  scrCopy: TBitMap;
  DC:HDC;
begin
  DC:=GetDC(0);
  scrCopy := TBitMap.Create;
  scrBtn.Width := Screen.Width; //ширина
  scrBtn.Height := Screen.Height; //высота
  BitBlt(scrCopy.Canvas.Handle, 0, 0, scrCopy.Width, scrCopy.Height, DC, 300, 170, SRCCOPY);
  scrCopy.SaveToFile('С:\scrCopy.bmp');
end;
Вопрос собственно, что за защита такая и как скопировать пиксели окна этого хитрого приложения, куда покопать?

Спасибо!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.06.2024, 18:43
Ответы с готовыми решениями:

Увеличение содержимого окна пропорционально увеличению самого окна
Добрый день, возник такой вопрос как можно увеличивать содержимое окна(например Image)...

Копирование одного bitmap в другой
Здравствуйте. Подскажите, как можно скопировать картинку из одного bitmap в другой, уже...

Копирование изображения в Bitmap с имеющегося pictureBox
необходимо скопировать изображение с уже нарисованного pictureBox в BitMap, с целью дальнейшей...

Копирование массива в Bitmap. Получаю белые прямоугольники
Добрый день всем. Имею проблему. В основной программе из больших (1600 x 1200 ) картинок делаю...

Передача изображения не в Handle окна, а в bitmap
Здравствуйте, форумчане! Хочу приобрести плату видеозахвата на 4 видеовхода с аппаратным...

19
Модератор
3748 / 2248 / 782
Регистрация: 15.11.2015
Сообщений: 8,956
30.06.2024, 22:26 2
И что это за приложение? Как называется?

А если попробовать поискать окно самого приложения и его скопировать?
0
0 / 0 / 0
Регистрация: 01.03.2024
Сообщений: 11
30.06.2024, 22:51  [ТС] 3
Цитата Сообщение от AzAtom Посмотреть сообщение
И что это за приложение? Как называется?
А если попробовать поискать окно самого приложения и его скопировать?
Приложение для игры в покер, TigerGaming. Что интересно при запуске все нормально, в буфер копируется, как только залогинился появляется описанный выше финт. Чет ничего найти не смог в интернетах по данной теме. Как они такое провернули? ))).

Есть мысль развернуть на виртуальной машине и попробовать скопировать экран прогой с основной, но какой то кривой способ как по мне.

Можно пример с поиском окна приложения и его копированием. Хотя бы общий.
0
Модератор
3748 / 2248 / 782
Регистрация: 15.11.2015
Сообщений: 8,956
30.06.2024, 23:21 4
Artem1979, окно ищется функцией
Delphi
1
  WindowH := FindWindow('ClassName', 'WindowName');
Если известно только имя окна, то можно указать только его
Delphi
1
  WindowH := FindWindow(nil, 'WindowName');
А дальше получить его DC
Delphi
1
2
3
4
5
6
7
8
  WindowH := FindWindow(nil, 'WindowName'); // Поменять на название нужного окна
  DC := GetDC(WindowH);
  scrCopy := TBitMap.Create;
  scrBtn.Width := Screen.Width; //ширина
  scrBtn.Height := Screen.Height; //высота
  BitBlt(scrCopy.Canvas.Handle, 0, 0, scrCopy.Width, scrCopy.Height, DC, 300, 170, SRCCOPY);
  scrCopy.SaveToFile('С:\scrCopy.bmp');
  ReleaseDC(WindowH, DC); // Не забываем после работы освободить контекст устройства.
Добавлено через 12 минут
Вот, копируется содержимое своего окна на себя же со сдвигом:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var
  WindowH: HWND;
  DC: HDC;
  bmph: Windows.TBitmap;
  bmp: HGDIOBJ;
begin
  WindowH := FindWindow(nil, 'Form1');
  DC := GetDC(WindowH);
 
  FillChar(bmph, SizeOf(bmph), 0);
  bmp := GetCurrentObject(DC, OBJ_BITMAP); // Получение размеров DC
  GetObject(bmp, sizeof(BITMAP), @bmph); // Получение размеров DC
 
  BitBlt(Canvas.Handle, 0, 0, bmph.bmWidth, bmph.bmHeight, DC, 10, 10, SRCCOPY);
  ReleaseDC(WindowH, DC);
end;
1
0 / 0 / 0
Регистрация: 01.03.2024
Сообщений: 11
01.07.2024, 01:24  [ТС] 5
Спасибо. Проверил, до логина заголовок окна определил без проблем, все отлично работает, скрин окна сохраняется.

После логина в приложение запускает несколько процессов с одинаковым именем GameBrowser.exe, и у всех заголовок окна Н/Д согласно tasklist. Как быть в случае если заголовков нет?

Добавлено через 44 минуты
Нашел заголовок, обратился, определил DC (не пустой), при этом файл scrCopy.bmp на выходе получаем пустым (белое поле). Не видит BitBlt содержимого окна даже с указанным DC. Как такое может быть не понимаю.

Добавлено через 44 минуты
Полагаю тут не обошлось без оверлей.

Цитата:
"Захват экрана - это получение либо статической картинки (мгновенный снимок), либо динамической (видео) собственно того, что на этом экране отображается в данный момент. Если картинка на экране формируется штатными средствами (сначала образ экрана обрабатывается центральным процессором, затем записывается в ОЗУ и оттуда транслируется в видео-подсистему для вывода на экран), то захват экрана в виде отдельного кадра можно осуществить штатными средствами ОС - через клавишу PrintScreen. В этом случае экранный образ помешается в буфер обмена и доступен для любого приложения.

Если используется оверлей (то есть картинка изначально формируется графическим процессором, хранится в видеопамяти и оттуда сразу выводится на экран - это характерно для приложений, использующих вычислительные мощности видеокарты, например, игр и видео-плееров), то штатными системными средствами захватить экран не получится - в буфере обмена будет лишь чёрный прямоугольник. Для захвата экрана в режиме оверлей нужен специальный софт, извлекающий картинку непосредственно из памяти видеокарты и сохраняющий её в виде графического файла или видео-ролика."

Кто подскажет как извлечь картинку из памяти видеокарты?
0
4174 / 1824 / 218
Регистрация: 06.10.2010
Сообщений: 4,111
01.07.2024, 06:54 6
Начиная с Windows 8 появился специальный API для записи экрана.

Вот исходник примера на C (сам не проверял) - https://gist.github.com/mmozei... f3f3165790
0
4174 / 1824 / 218
Регистрация: 06.10.2010
Сообщений: 4,111
01.07.2024, 14:46 7
Работает как-то нестабильно: пришлось добавить sleep после DuplicateOutput. Во вложении исходник на Delphi 7, делает скриншот, сохраняет bmp в TEMP, затем открывает этот BMP. В коде нет никаких проверок, написано кое-как, только чтобы проверить работу API, под x64 скорее всего не заработает.
Вложения
Тип файла: 7z DesktopDuplicate.7z (11.4 Кб, 13 просмотров)
0
0 / 0 / 0
Регистрация: 01.03.2024
Сообщений: 11
01.07.2024, 19:04  [ТС] 8
Файл bmp в Темпе создал, а вот открыть не получается, пишет что не является точечным рисунком или формат не поддерживается. Весит 14мб.
0
4174 / 1824 / 218
Регистрация: 06.10.2010
Сообщений: 4,111
02.07.2024, 05:39 9
Возможно просмотровщик не понимает отрицательную высоту (хотя это документированная фича). mspaint из winXP и XnView понимают.
0
Модератор
3748 / 2248 / 782
Регистрация: 15.11.2015
Сообщений: 8,956
02.07.2024, 09:56 10
Цитата Сообщение от murderer Посмотреть сообщение
Во вложении исходник на Delphi 7
У меня dxgiDuplication остаётся nil. Win7 64 bit.
0
4174 / 1824 / 218
Регистрация: 06.10.2010
Сообщений: 4,111
02.07.2024, 10:13 11
AzAtom
Оно только в Win8 появилось.

Добавлено через 16 минут
Можно ещё попробовать BitBlt из DC, полученного таким образом:
Delphi
1
DC:=CreateDCW('DISPLAY',0,0,0);
0
0 / 0 / 0
Регистрация: 01.03.2024
Сообщений: 11
02.07.2024, 13:08  [ТС] 12
Цитата Сообщение от murderer Посмотреть сообщение
Возможно просмотровщик не понимает отрицательную высоту (хотя это документированная фича). mspaint из winXP и XnView понимают.
Да, действительно XnView открывает файл, скриншот есть, вот только окно с хитрым приложением также не видит, копия экрана получается без нужного окна, так же как и при использовании BitBlt.

Добавлено через 7 минут
Цитата Сообщение от murderer Посмотреть сообщение
Можно ещё попробовать BitBlt из DC, полученного таким образом:
DelphiВыделить код
1
DC:=CreateDCW('DISPLAY',0,0,0);
Тоже самое, скринит все что находится за окном приложения, нужное окно не видит

Добавлено через 4 минуты
Все что смог найти касательно overlay, вот такую статью : http://www.silicontaiga.ru/home.asp?artId=5748

Расписано хорошо, как его скринить не понятно
0
4174 / 1824 / 218
Регистрация: 06.10.2010
Сообщений: 4,111
02.07.2024, 14:32 13
Через mstsc видно изображение?

Добавлено через 3 минуты
Вот чего нарыл - https://learn.microsoft.com/en... l-overview
0
Модератор
3748 / 2248 / 782
Регистрация: 15.11.2015
Сообщений: 8,956
02.07.2024, 16:36 14
Интересно, кто-то ещё использует оверлей? Когда я в MPC включал вывод видео через оверлей система отключала темы.

Вот это попробуй, нашёл в инете. У меня на win 7 не сработало, выдаёт ошибку доступа к памяти, хотя, вроде, память выделена и указатель не нулевой.
Модуль с классом для захвата экрана:
Delphi
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
aunit DTM_ImageCatcher;
 
interface
 
uses
  Classes, SysUtils, Controls, Graphics,
  Forms, Windows, D3DX9, Direct3D9, DirectDraw;
 
  type
    TCatchType = (ctWinapi = 0,ctDirectX = 1,ctDDraw);
    TImageCatcher = class
      private
        FBitmap: Graphics.TBITMAP;
        FCatchType: TCatchType;
        FTargetHandle: HWND;
        procedure GetTargetRect(out Rect: TRect);
        procedure GetDDrawData();
        procedure GetDirectXData();
        procedure GetWinapiData();
        procedure GetTargetDimensions(out w, h: integer);
        procedure GetTargetPosition(out left, top: integer);
      public
        constructor Create;
        procedure Reset;
        destructor Destroy;override;
 
        procedure GetScreenShot();
        procedure ActivateTarget;
        property Bitmap: Graphics.TBITMAP read FBitmap write FBitmap;
        property CatchType: TCatchType read FCatchType write FCatchType;
        property TargetHandle: HWND read FTargetHandle write FTargetHandle;
    end;
implementation
 
{ TImageCather }
 
procedure TImageCatcher.ActivateTarget;
begin
 SetForegroundWindow(TargetHandle);
end;
 
 
constructor TImageCatcher.Create;
begin
 Reset;
 FBitmap:=Graphics.TBitmap.Create;
 FBitmap.PixelFormat:=pf24bit;
end;
 
destructor TImageCatcher.Destroy;
begin
  FreeAndNil(FBitmap);
  inherited;
end;
 
procedure TImageCatcher.GetDDrawData();
var
  DDSCaps: TDDSCaps;
  DesktopDC: HDC;
  DirectDraw: IDirectDraw;
  Surface: IDirectDrawSurface;
  SurfaceDesc: TDDSurfaceDesc;
  x, y, w, h: integer;
begin
  GetTargetDimensions(w, h);
  GetTargetPosition(x, y);
  if DirectDrawCreate(nil, DirectDraw, nil) = DD_OK then
    if DirectDraw.SetCooperativeLevel(GetDesktopWindow, DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN or DDSCL_ALLOWREBOOT) = DD_OK then
    begin
      FillChar(SurfaceDesc, SizeOf(SurfaceDesc), 0);
      SurfaceDesc.dwSize := Sizeof(SurfaceDesc);
      SurfaceDesc.dwFlags := DDSD_CAPS;
      SurfaceDesc.ddsCaps.dwCaps := DDSCAPS_PRIMARYSURFACE;
      SurfaceDesc.dwBackBufferCount := 0;
      if DirectDraw.CreateSurface(SurfaceDesc, Surface, nil) = DD_OK then
      begin
        if Surface.GetDC(DesktopDC) = DD_OK then
          try
            Bitmap.Width := Screen.Width;
            Bitmap.Height := Screen.Height;
            BitBlt(Bitmap.Canvas.Handle, 0, 0, W, H, DesktopDC, x, y, SRCCOPY);
          finally
            Surface.ReleaseDC(DesktopDC);
          end;
      end;
    end;
end;
 
procedure TImageCatcher.GetDirectXData();
var
  BitsPerPixel: Byte;
  pD3D: IDirect3D9;
  pSurface: IDirect3DSurface9;
  g_pD3DDevice: IDirect3DDevice9;
  D3DPP: TD3DPresentParameters;
  ARect: TRect;
  LockedRect: TD3DLockedRect;
  BMP: Graphics.TBitmap;
  i, p: Integer;
  x, y: integer;
  w, h: integer;
begin
  GetTargetDimensions(w, h);
  GetTargetPosition(x, y);
  BitsPerPixel := 32;
  FillChar(d3dpp, SizeOf(d3dpp), 0);
  with D3DPP do
  begin
    Windowed := True;
    Flags := D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
    SwapEffect := D3DSWAPEFFECT_DISCARD;
    BackBufferWidth := Screen.Width;
    BackBufferHeight := Screen.Height;
    BackBufferFormat := D3DFMT_X8R8G8B8;
  end;
  pD3D := Direct3DCreate9(D3D_SDK_VERSION);
  pD3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetDesktopWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, @ D3DPP, g_pD3DDevice);
  g_pD3DDevice.CreateOffscreenPlainSurface(Screen.Width, Screen.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, pSurface, nil);
  g_pD3DDevice.GetFrontBufferData(0, pSurface);
  ARect := Screen.DesktopRect;
  pSurface.LockRect(LockedRect, @ ARect, D3DLOCK_NO_DIRTY_UPDATE or D3DLOCK_NOSYSLOCK or D3DLOCK_READONLY);
  BMP := Graphics.TBitmap.Create;
  BMP.Width := Screen.Width;
  BMP.Height := Screen.Height;
  case BitsPerPixel of
    8: BMP.PixelFormat := pf8bit;
    16: BMP.PixelFormat := pf16bit;
    24: BMP.PixelFormat := pf24bit;
    32: BMP.PixelFormat := pf32bit;
  end;
  p := Cardinal(LockedRect.pBits);
  for i := 0 to Screen.Height - 1 do
  begin
    CopyMemory(BMP.ScanLine[i], Ptr(p), Screen.Width * BitsPerPixel div 8);
    p := p + LockedRect.Pitch;
  end;
//  Bitmap.SetSize(w, h);
  Bitmap.Width := w;
  Bitmap.Height := h;
  BitBlt(Bitmap.Canvas.Handle, 0, 0, w, h, BMP.Canvas.Handle, x, y, SRCCOPY);
  BMP.Free;
  pSurface.UnlockRect;
end;
 
procedure TImageCatcher.GetScreenShot();
begin
  case CatchType of
    ctWinapi: GetWinapiData();
    ctDirectX: GetDirectXData();
    ctDDraw: GetDDrawData();
  end;
  SetForegroundWindow(Application.Handle);
end;
 
procedure TImageCatcher.GetTargetDimensions(out w, h: integer);
var
  Rect: TRect;
begin
  GetTargetRect(rect);
  w := Rect.Right - Rect.Left;
  h := Rect.Bottom - Rect.Top;
end;
 
procedure TImageCatcher.GetTargetPosition(out left, top: integer);
var
  Rect: TRect;
begin
  GetTargetRect(rect);
  left := Rect.Left;
  top := Rect.Top;
end;
 
procedure TImageCatcher.GetTargetRect(out Rect: TRect);
begin
  GetWindowRect(TargetHandle, Rect);
end;
 
procedure TImageCatcher.Reset;
begin
  CatchType := ctWinapi;
  TargetHandle := 0;
end;
 
procedure TImageCatcher.GetWinapiData();
var
  hWinDC: THandle;
  w, h: integer;
begin
  GetTargetDimensions(w, h);
  hWinDC := GetWindowDC(TargetHandle);
  Bitmap.Width := w;
  Bitmap.Height := h;
  hWinDC := GetWindowDC(TargetHandle);
  BitBlt(Bitmap.Canvas.Handle, 0, 0, Bitmap.Width, Bitmap.Height, hWinDC, 0, 0, SRCCOPY);
  ReleaseDC(TargetHandle, hWinDC);
end; 
 
end.
И его использование:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uses
  DTM_ImageCatcher;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  IC: TImageCatcher;
  Wnd: HWND;
begin
  IC := TImageCatcher.Create;
  Wnd := FindWindow(nil, 'WindowName');
  IC.TargetHandle := Wnd;
  IC.CatchType := ctDirectX; // Откуда делать снимок
  IC.ActivateTarget;
  Sleep(500);
  IC.GetScreenShot;
  IC.Bitmap.SaveToFile(ExtractFilePath(ParamStr(0)) + 'ScrShot.bmp');
  IC.Free;
end;
Добавлено через 12 минут
Добавил задержку перед снимком и перестал вылетать. Но выдаёт белый прямоугольник. Пробовал на MPC HC.

Добавлено через 1 минуту
Правда, вывод был не через оверлей.

Добавлено через 6 минут
Переключил вывод на оверлей и начало вылетать с ошибкой доступа к памяти.
0
0 / 0 / 0
Регистрация: 01.03.2024
Сообщений: 11
02.07.2024, 21:00  [ТС] 15
Попробовал, код отработал полностью, ошибок нет. На выходе пустой файл bmp размером 14кб. ((

Добавлено через 2 минуты
а как именно Вы переключили вывод на оверлей?
0
57 / 52 / 5
Регистрация: 18.11.2018
Сообщений: 279
03.07.2024, 00:40 16
Цитата Сообщение от Artem1979 Посмотреть сообщение
Расписано хорошо, как его скринить не понятно
OBS может нужное вам окно захватывать?
0
4174 / 1824 / 218
Регистрация: 06.10.2010
Сообщений: 4,111
03.07.2024, 05:02 17
Цитата Сообщение от Artem1979 Посмотреть сообщение
а как именно Вы переключили вывод на оверлей?
Копирование содержимого окна в bitmap
0
57 / 52 / 5
Регистрация: 18.11.2018
Сообщений: 279
03.07.2024, 13:11 18
Цитата Сообщение от Иван Ежик Посмотреть сообщение
OBS может нужное вам окно захватывать?
Я к тому что будет ли его видно в предпросмотре OBS
Копирование содержимого окна в bitmap
0
0 / 0 / 0
Регистрация: 01.03.2024
Сообщений: 11
03.07.2024, 18:54  [ТС] 19
Цитата Сообщение от Иван Ежик Посмотреть сообщение
Я к тому что будет ли его видно в предпросмотре OBS
Нет не видит, ни через захват экрана, ни через захват окна.
При захвате экрана видит все что за нужным окном, а при захвате окна черный квадрат
0
57 / 52 / 5
Регистрация: 18.11.2018
Сообщений: 279
03.07.2024, 19:03 20
Цитата Сообщение от Artem1979 Посмотреть сообщение
При захвате экрана видит все что за нужным окном, а при захвате окна черный квадрат
Очень похоже что вы попали на защиту от скриншотов.
гуглить " WDA_EXCLUDEFROMCAPTURE "
Сделать её две строчки, а вот отключить возможно только через инъект своей dll в чужой процесс.
Исходник самой защиты прилагаю? можете посмотреть на него в OBS
NoShow.zip
Если поведение один в один с вашим приложением, то вероятнось что это именно защита, немаленькая.
1
03.07.2024, 19:03
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.07.2024, 19:03
Помогаю со студенческими работами здесь

Печать BitMap без диалогового окна
Здравствуйте. Я прочитал и на вашем форуме и в книгах много примеров о том как запустить печать, но...

Копирование содержимого из ячейки
Всем привет. В ячейку I3 поступают данные из сторонней программы. Мне необходимо скопировать...

Копирование содержимого файла
Здравствуйте! Подскажите пожалуйста скрипт на такую тему: есть файл .doc (имя может быть разное),...

Копирование содержимого экрана
Кто может подсказать где взять информацию по работе с экраном на с++. Что бы можно было бы создать...

Копирование содержимого RichTextBox'а
Здравствуйте, у меня вопрос. На форме есть RichTextBox. Я кидаю туда текст через...


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

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