Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2007.07.08;
Скачать: [xml.tar.bz2];

Вниз

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

 
Humorist   (2007-01-24 18:22) [0]

Стоит задача: получить изображение окна, которое скрыто другими. Два дня бьюсь.
Сочинил (с помощью инета) следующую прогу:

procedure CreateWindwowBitmap(Wnd: HWND);
var
 R: TRect;
 W, H: Integer;
 DC, memDC: HDC;
 bm, oldBM: HBITMAP;

 bmp:TBitmap;
begin
 GetWindowRect(Wnd, R);
 W := R.Right - R.Left;
 H := R.Bottom - R.Top;
 DC := GetWindowDC(Wnd);
 memDC := CreateCompatibleDC(DC);
 bm := CreateCompatibleBitmap(DC, W, H);
 oldBM := SelectObject(memDC, bm);
 BitBlt(memDC, 0,0, w, h, DC, 0,0, SRCCOPY);
 SelectObject(memDC, oldBM);
 DeleteDC(memDC);
 DeleteObject(oldBM);
 ReleaseDC(Wnd, DC);

 bmp:=TbitMap.Create;
 bmp.Handle:=bm;
 bmp.SaveToFile("d:\eee.bmp");
 bmp.Free;

end;

Однако она сохраняет в файл то, что ВИДНО на экране.
Что не так делаю ? Помогите, плиз...


 
TRUNK ©   (2007-01-24 21:44) [1]


> Что не так делаю ?

Всё так. Просто если часть окна закрыта другим окном, эта закрытая часть окном вообще не рисуется для экономии времени.


 
Humorist   (2007-01-25 11:41) [2]

1. Правильно ли я понял, что  получить изображение окна, которое скрыто другими, нельзя в принцине ?
А нельзя ли требуемое окно вывести на передний план, взять его изображение, а затем снова спрятать (или не прятать - если это не так уж необходимо) ?

2. Попробовал WM_PRINT:

procedure CreateWindwowBitmap2(Wnd: HWND);
var
 R: TRect;
 W, H: Integer;
 DC, memDC: HDC;
 bm, oldBM: HBITMAP;

 bmp:TBitmap;
begin
 GetWindowRect(Wnd, R);
 W := R.Right - R.Left;
 H := R.Bottom - R.Top;
 DC := GetWindowDC(Wnd);

bmp:=TbitMap.Create;
bmp.Width:=W;
bmp.Height:=H;

 SendMessage(bmp.Canvas.Handle,WM_PRINT,DC,PRF_CHILDREN or PRF_CLIENT or PRF_ERASEBKGND or PRF_NONCLIENT or PRF_OWNED);
 ReleaseDC(Wnd, DC);

bmp.SaveToFile("d:\qqq.bmp");
bmp.Free;

end;

Однако результа представляет из себя белый прямоугольник.

Может все-таки существуют варианты ?


 
Sapersky   (2007-01-25 13:50) [3]

В XP есть функция PrintWindow.
+ хакерские методы вроде:
http://expire.free.fr/board/index.php?showtopic=109


 
TRUNK ©   (2007-01-25 14:12) [4]


> Humorist   (25.01.07 11:41) [2]
> А нельзя ли требуемое окно вывести на передний план, взять
> его изображение, а затем снова спрятать

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


 
Humorist   (2007-01-25 14:28) [5]


> Я думал о таком варианте. Вопрос в том сколько времени уйдёт
> на перерисовку окна после того, как оно будет выведено на
> передний план.
> Другими словами, после вывода окна вперёд возможно придётся
> некоторое время подождать перед тем, как делать его снимок.
>


Уважаемый, TRUNK, подскажите, пожалуйста,  как перерисовать окно на передний план. (Для моей задачи некоторое время ожидания окончания перерисовки - пусть даже заданное с запасом и заведомо большее требуемого - не столь важно. Образ окна требуется получать достаточно редко).
Я попробовал в приведенном мною первом примере в самом начале написать

ShowWindow(Wnd,SW_RESTORE);

Однако результата это не дало


 
Humorist   (2007-01-25 14:35) [6]


> Sapersky  

> В XP есть функция PrintWindow.
> + хакерские методы вроде:
> http://expire.free.fr/board/index.php?showtopic=109
> <Цитата>


Спасибо за совет.
1. Однако W2K.
2. По указанному адресу требуется регистрация, я, вроде, сделал все что нужно, однако на указанный адрес обещанные дальнейшие инструкции не пришли. Не могли бы Вы выслать архив по SPrintWindow() на адрес antol2004@rambler.ru, плиз.


 
TRUNK ©   (2007-01-25 14:52) [7]

Примерно так (не проверял):

SetWindowPos(Wnd,HWND_TOP,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);
// ждём немного
// делаем снимок
SetWindowPos(Wnd,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);


 
TRUNK ©   (2007-01-25 14:59) [8]


> SelectObject(memDC, oldBM);
> DeleteDC(memDC);
> DeleteObject(oldBM);

Эти строки надо переделать так:
bm := SelectObject(memDC, oldBM);
DeleteObject(bm);
DeleteDC(memDC);


 
Sapersky   (2007-01-25 15:36) [9]

Не могли бы Вы выслать архив по SPrintWindow() на адрес antol2004@rambler.ru, плиз.

Отправил, но версия там (не помню уж где её добыл) 0.1.1 BETA, со всеми возможными вытекающими. Поищи SPrintWindow гуглом, может быть есть новее.
Я сам сейчас предпочёл бы скорее стандартный PrintWindow (если он даст более-менее приличную скорость). По приводимой здесь
http://delphimaster.net/view/15-1168458032/ ([43], [99])
статистике XP стоит у 70-80% пользователей.


 
Humorist   (2007-01-25 19:44) [10]


> TRUNK ©   (25.01.07 14:52) [7]
> Примерно так (не проверял):
>
> SetWindowPos(Wnd,HWND_TOP,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);
>
> // ждём немного
> // делаем снимок
> SetWindowPos(Wnd,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);
>


Отчично !
Работает так, как надо.
(Есть, конечно, нюанс: если у окна, образ которого мы хотим получить, есть дочернее окно, и оно перекрывает наше, то получается именно такая картинка (наше окно, перекрытое его дочерним). И убрать на задний план дочернее окно не удается.)

Но в любом случае это огромный прогресс. Большое спасибо.

> Эти строки надо переделать так:
> bm := SelectObject(memDC, oldBM);
> DeleteObject(bm);
> DeleteDC(memDC);


После переделки результирующий файл оказался пустым. Оставил так как было.


 
TRUNK ©   (2007-01-26 10:46) [11]


> наше окно, перекрытое его дочерним

Попробуй заменить HWND_TOP на HWND_TOPMOST.


> После переделки результирующий файл оказался пустым

Признаю свою ошибку: я забыл посмотреть на следующие четыре строки в которых происходит сохранение битмэпа. Приведу окончательный вариант:

BitBlt(memDC, 0,0, w, h, DC, 0,0, SRCCOPY);
bm := SelectObject(memDC, oldBM);

bmp := TBitmap.Create;
bmp.Handle := bm;
bmp.SaveToFile("d:\eee.bmp");
bmp.Free;

DeleteObject(bm);
DeleteDC(memDC);
ReleaseDC(Wnd, DC);


 
TCrash   (2007-01-26 12:12) [12]

Humorist   (25.01.07 14:28) [5]
SetForegroundWindow(Wnd)


 
TCrash   (2007-01-26 12:14) [13]

Сорри, не дочитав ветку нарисовал ответ :)


 
Humorist   (2007-01-26 13:08) [14]


> TRUNK ©   (26.01.07 10:46) [11]
>
>
> Попробуй заменить HWND_TOP на HWND_TOPMOST.


Попробовал. Родительское окно становится активным; однако дочернее все равно находится поверх него. Поробовал разные последоватенльности HWND_TOPMOST и HWND_BOTTOM в отношении родительского и дочернего окна; то что нужно не получилось. Может попробовать скрывать дочернее окно или отправлять его за пределы рабочего стола, а затем возвращать на место ?



> окончательный вариант:
>
> BitBlt(memDC, 0,0, w, h, DC, 0,0, SRCCOPY);
> bm := SelectObject(memDC, oldBM);
>
> bmp := TBitmap.Create;
> bmp.Handle := bm;
> bmp.SaveToFile("d:\eee.bmp");
> bmp.Free;
>
> DeleteObject(bm);
> DeleteDC(memDC);


Все работает. Не стоит ли для корректности поставть try - finally ? В окончательном варианте что-то типа

procedure CreateWindwowBitmap(Wnd: HWND);
var
R: TRect;
W, H: Integer;
DC, memDC: HDC;
bm, oldBM: HBITMAP;

bmp:TBitmap;
k:integer;
begin
try
SetWindowPos(Wnd,HWND_TOP,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);
sleep(100);

GetWindowRect(Wnd, R);
W := R.Right - R.Left;
H := R.Bottom - R.Top;
DC := GetWindowDC(Wnd);
memDC := CreateCompatibleDC(DC);

bm := CreateCompatibleBitmap(DC, W, H);
oldBM := SelectObject(memDC, bm);

BitBlt(memDC, 0,0, w, h, DC, 0,0, SRCCOPY);
bm := SelectObject(memDC, oldBM);

bmp := TBitmap.Create;
bmp.Handle := bm;
bmp.SaveToFile("d:\eee.bmp");
finally
bmp.Free;

DeleteObject(bm);
DeleteDC(memDC);
ReleaseDC(Wnd, DC);
end;

end;


> Sapersky


Спасибо за письмо. Однако с SPrintWindow еще не разбирался: вроде появился другой путь решения задачи. А PrintWindow  все-таки не подходит: имеется в наличии W2K.


 
TRUNK ©   (2007-01-26 13:51) [15]

Если нужна полная защита, тогда пиши так:

procedure CreateWindwowBitmap(Wnd: HWND);
var
R: TRect;
W,H: Integer;
DC,memDC: HDC;
bm,oldBM: HBITMAP;
bmp: TBitmap;
begin
SetWindowPos(Wnd,HWND_TOP,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);
sleep(100);
GetWindowRect(Wnd,R);
W := R.Right - R.Left;
H := R.Bottom - R.Top;
DC := GetWindowDC(Wnd);
if (DC = 0) then
 Exit;
try
 memDC := CreateCompatibleDC(DC);
 if (memDC = 0) then
   Exit;
 try
   bm := CreateCompatibleBitmap(DC, W, H);
   if (bm = 0) then
     Exit;
   try
     oldBM := SelectObject(memDC, bm);
     if (oldBM = 0) then
       Exit;
     if (BitBlt(memDC, 0,0, w, h, DC, 0,0, SRCCOPY) = 0) then
       Exit;
     bm := SelectObject(memDC, oldBM);
     if (bm = 0) then
       Exit;
     bmp := TBitmap.Create;
     try
       bmp.Handle := bm;
       bmp.SaveToFile("d:\eee.bmp");
     finally
       bmp.Free;
     end;
   finally
     DeleteObject(bm);
   end;
 finally
   DeleteDC(memDC);
 end;
finally
 ReleaseDC(Wnd, DC);
end;
end;


 
Humorist   (2007-01-26 13:56) [16]


> TRUNK ©   (26.01.07 13:51) [15]


Ок. Спасибо большое за деятельное участие ! Буду внедрять.


 
GrayFace ©   (2007-01-27 09:04) [17]

Sapersky   (25.01.07 13:50) [3]
http://expire.free.fr/board/index.php?showtopic=109

Я в шоке!
TRUNK ©   (26.01.07 13:51) [15]
Если нужна полная защита, тогда пиши так:

procedure CreateWindwowBitmap(Wnd: HWND);
var
R: TRect;
W,H: Integer;
DC,memDC: HDC;
bm,oldBM: HBITMAP;
bmp: TBitmap;
begin
SetWindowPos(Wnd,HWND_TOP,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE);
sleep(100);
GetWindowRect(Wnd,R);
W := R.Right - R.Left;
H := R.Bottom - R.Top;
DC := GetWindowDC(Wnd);
if (DC = 0) then
Exit;
bm:=0;
bmp:=nil;
memDC:=0;
try
memDC := CreateCompatibleDC(DC);
if (memDC = 0) then
  Exit;
  bm := CreateCompatibleBitmap(DC, W, H);
  if (bm = 0) then
    Exit;
    oldBM := SelectObject(memDC, bm);
    if (oldBM = 0) then
      Exit;
    if (BitBlt(memDC, 0,0, w, h, DC, 0,0, SRCCOPY) = 0) then
      Exit;
    bm := SelectObject(memDC, oldBM);
    if (bm = 0) then
      Exit;
    bmp := TBitmap.Create;
      bmp.Handle := bm;
      bmp.SaveToFile("d:\eee.bmp");
finally
ReleaseDC(Wnd, DC);
DeleteDC(memDC);
DeleteObject(bm);
bmp.Free;
end;
end;

(Отступы как попало, т.к. не менял)


 
GrayFace ©   (2007-01-27 09:05) [18]

Exit везде лучше заменить на RaiseLastOSError


 
homm ©   (2007-01-27 16:16) [19]

> (Для моей задачи некоторое время ожидания окончания перерисовки
> - пусть даже заданное с запасом и заведомо большее требуемого
> - не столь важно. Образ окна требуется получать достаточно
> редко).

Подход не верный. Нужно дожидатся выполнения последнего WM_PAINT в очереди, а не определенный промежуток времени


 
GrayFace ©   (2007-01-28 16:13) [20]

homm ©   (27.01.07 16:16) [19]
Подход не верный. Нужно дожидатся выполнения последнего WM_PAINT в очереди, а не определенный промежуток времени

Простого решения в голову не приходит.


 
Humorist   (2007-01-29 13:11) [21]


> homm ©   >
> Подход не верный. Нужно дожидатся выполнения последнего
> WM_PAINT в очереди, а не определенный промежуток времени


Правильно ли я понимаю, что нужно организоваывать ловушку ?


 
Piroxyline ©   (2007-01-29 14:30) [22]

А если получить дц, а потом узнать, какой битмап им используется, и снять с него данные? И безо всяких хуков.


 
Humorist   (2007-01-29 14:34) [23]


> Piroxyline ©   (29.01.07 14:30) [22]
> А если получить дц, а потом узнать, какой битмап им используется,
>  и снять с него данные? И безо всяких хуков.


ДЦ известен. Что значит узнать какой битмап используется; и как это узнать ?


 
Piroxyline ©   (2007-01-29 15:15) [24]

Чтобы на DC было изображение, нужно сделать ему SelectObject(DC, Bitmap). В справке вроде это было где-то написано. Узнать можно при помощи функции GetObject с соответствующими параметрами (они указаны в справке).


 
Humorist   (2007-01-29 15:21) [25]


> Piroxyline ©   (29.01.07 15:15) [24]
> Чтобы на DC было изображение, нужно сделать ему SelectObject(DC,
>  Bitmap). В справке вроде это было где-то написано. Узнать
> можно при помощи функции GetObject с соответствующими параметрами
> (они указаны в справке).


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


 
Piroxyline ©   (2007-01-29 15:45) [26]

Нет, я не это имел в виду! Если получить битмап данного дц, то тогда можно получить данные об изображении на данном дц, которое хранится в памяти, и массив точек этого изображения вроде бы как через GetDIBits). Что мешает так сделать и скопировать этот массив точек на свой битмап? Щас поэкспериментирую с этим и кинусь исходником.


 
DVM ©   (2007-01-29 15:55) [27]


> TRUNK ©   (26.01.07 13:51) [15]


> GrayFace ©   (27.01.07 09:04) [17]

Оба варианта одинаково плохи.


 
Humorist   (2007-01-29 18:31) [28]


>
> DVM ©   (29.01.07 15:55) [27]
>
> > TRUNK ©   (26.01.07 13:51) [15]
>
>
> > GrayFace ©   (27.01.07 09:04) [17]
>
> Оба варианта одинаково плохи.


А какой хороший ?


 
DVM ©   (2007-01-30 11:19) [29]


> Humorist   (29.01.07 18:31) [28]
> А какой хороший ?

Дело все в том, что нет гарантии, что после выполнения SetWindowPos() окно успеет себя перерисовать. И разные там задержки - это не выход.
Нормального решения ИМХО нет.

По поводу кода из 15. Обычно принято делать так:
Создание чего-либо
try
 ...
finally
 Освобождение чего-либо
end;

Зачем создание помещать внутрь try. Если произойдет исключение при создании - будет выполнено освобождение того чего нет. В том конкретном коде так скорее всего не будет, но писать надо правильно всегда.

По поводу кода 17.

try
Создаем объект 1
Создаем объект 2
 ....
finally
 Освобождаем 1
 Освобождаем 2
end;

Если при уничтожении объекта 1 произойдет исключение, то следующие за нм не будут уничтожены. А если при создании объекта 1 произойдет исключение? Каша.

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


 
GrayFace ©   (2007-01-30 15:16) [30]

Humorist   (29.01.07 13:11) [21]
Правильно ли я понимаю, что нужно организоваывать ловушку ?

Да, больше ничего в голову не приходит. На WH_CALLWNDPROCRET. А потом GetQueueStatus использовать.

DVM ©   (29.01.07 15:55) [27]
Оба варианта одинаково плохи.

Честно говоря, не смотрел, что там делается. Просто убрал нагромождения try..finally, да от Exit-ов посоветовал избавиться.

DVM ©   (30.01.07 11:19) [29]
Зачем создание помещать внутрь try. Если произойдет исключение при создании - будет выполнено освобождение того чего нет. В том конкретном коде так скорее всего не будет, но писать надо правильно всегда.

В [15] создание не помещается в try, в [17] первый объект тоже создается вне try.

DVM ©   (30.01.07 11:19) [29]
Если при уничтожении объекта 1 произойдет исключение, то следующие за нм не будут уничтожены.

Да, тут есть слабое место. Правда, исключения в Free очень маловероятны.

DVM ©   (30.01.07 11:19) [29]
А если при создании объекта 1 произойдет исключение? Каша.

Нет. Объект 1 не создастся, остальные инициализированы нулями, поэтому их Free ничего плохого не даст.


 
DVM ©   (2007-01-30 15:53) [31]


> GrayFace ©   (30.01.07 15:16) [30]


> В [15] создание не помещается в try

А то что же?
try
memDC := CreateCompatibleDC(DC);
try
bm := CreateCompatibleBitmap(DC, W, H);

> Нет. Объект 1 не создастся, остальные инициализированы нулями,
>  поэтому их Free ничего плохого не даст.

Да, здесь верно. Я перепутал немного.

> Правда, исключения в Free очень маловероятны.

Да они тут вообще маловероятны.


 
GrayFace ©   (2007-01-31 13:01) [32]

DVM ©   (30.01.07 15:53) [31]
> В [15] создание не помещается в try

А то что же?
try
memDC := CreateCompatibleDC(DC);
try
bm := CreateCompatibleBitmap(DC, W, H);


DC := GetWindowDC(Wnd);
try
memDC := CreateCompatibleDC(DC);
try


 
Piroxyline ©   (2007-01-31 13:08) [33]

try тут не надо, так как при ошибке не будет останова, а вернется или 0 (что вероятнее), или Cardinal(-1)


 
Humorist   (2007-02-02 11:21) [34]

Большое спасибо за помощь всем!

Честно говоря, еще до завершения дискуссии внедрил решение (TRUNK ©   (26.01.07 13:51) [15] ). Используется для отлова экранов с ссобщениями. Некоторые сообщения отображаются короткое время (т.е. хэндл окна получил, а к тому моменту, когда собираюсь писать его образ, окна уже и нет). Ни разу не возникло ни одного исключения. Сейчас переделаю в соответствии с последними рекомендациями. Еще раз спасибо.



Страницы: 1 вся ветка

Форум: "WinAPI";
Текущий архив: 2007.07.08;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.101 c
2-1181322418
artdeveloper
2007-06-08 21:06
2007.07.08
Использование Firefox (Gecko) аналогично TWebBrowser


15-1181324300
isasa
2007-06-08 21:38
2007.07.08
Навеяно Розычем()инициативная группа)


1-1178468555
TStas
2007-05-06 20:22
2007.07.08
Как получить путь с спецпапкам?


15-1181225632
Interior
2007-06-07 18:13
2007.07.08
Пакет легализации пиратского ПО


15-1181200151
cosinus
2007-06-07 11:09
2007.07.08
Помогите с ошибкой в 2003...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский