Конференция "WinAPI" » Снимок частично закрытого окна [D6, WinXP]
 
  • Bora.ru (17.09.07 20:32) [0]
    Можно ли получить полный скриншот окна, если его определенную часть перекрывает другое окно? Или это принципиально невозможно?
  • Anatoly Podgoretsky © (17.09.07 20:33) [1]
    > Bora.ru  (17.09.2007 20:32:00)  [0]

    Принципиально не возможно, только выводить на другое окно.
  • homm © (17.09.07 21:28) [2]
    > [1] Anatoly Podgoretsky ©   (17.09.07 20:33)
    > Принципиально не возможно,

    … но есть всякие частные случаи. Можно поиграться с SendMessage(WM_PAINT, 0, DC)
  • Dimaxx © (18.09.07 00:11) [3]
    А если попробовать получить хэндл активного окна, сделать активным нужное, снять скрин и "вернуть" активное приложение в фокус? Разве не сработает?
  • Dimaxx © (18.09.07 00:13) [4]
    Тьфу, хэндл не активного, а перекрывающего окна...
  • Германн © (18.09.07 01:09) [5]

    > Dimaxx ©   (18.09.07 00:13) [4]

    Ждём-с ещё одно "Тьфу" :-)
  • Dimaxx © (18.09.07 14:04) [6]
    Хватит и одного "тьфу". Вернуть "на место" надо именно активное. :)
  • Инс © (18.09.07 20:11) [7]
    Можно. Только есть масса особенностей. Лучше всего обычно работает PrintWindow но сразу же получаем ограничение Win2000. Есть еще сообщение WM_PRINT но далеко не все окна его правильно обрабатывают. Можно попробывать еще что-то вроде такого:

    type
     PPaintData = ^TPaintData;
     TPaintData = record
       Parent: HWND;
       DC: HDC;
     end;

    procedure PaintWindowToDC(Wnd: HWND; Bmp: TBitmap);
    var
     R: TRect;
     PD: TPaintData;

     function EnumWnd(Wnd: HWND; P: PPaintData): bool; stdcall;
     var
       SDC: integer;
       R: TRect;
       PD: TPaintData;
     begin
       try
         GetWindowRect(Wnd, R);
         Windows.ScreenToClient(P.Parent, R.TopLeft);
         SDC:= SaveDC(P.DC);
         try
           SetViewportOrgEx(P.DC, R.Left, R.Top, nil);
           SendMessage(Wnd, WM_ERASEBKGND, integer(P.DC), 0);
           SendMessage(Wnd, WM_PAINT, integer(P.DC), 0);
           PD.Parent:= Wnd;
           PD.DC:= P.DC;
           EnumChildWindows(Wnd, Addr(EnumWnd), integer(@PD));
         finally
           RestoreDC(P.DC, SDC);
         end;
         Result:= true;
       except
         Result:= false;
       end;
     end;

    begin
     GetClientRect(Wnd, R);
     Bmp.Width:= R.Right;
     Bmp.Height:= R.Bottom;
     PD.Parent:= Wnd;
     Bmp.Canvas.Lock;
     try
       PD.DC:= Bmp.Canvas.Handle;
       SendMessage(Wnd, WM_ERASEBKGND, integer(PD.DC), 0);
       SendMessage(Wnd, WM_PAINT, integer(PD.DC), 0);
       EnumChildWindows(Wnd, Addr(EnumWnd), integer(@PD));
     finally
       Bmp.Canvas.Unlock;
     end;
    end;


    Функция не моя (копирайт - Набережных Сергей), сам не пробовал.
  • homm © (18.09.07 20:25) [8]
          SetViewportOrgEx(P.DC, R.Left, R.Top, nil);
          SendMessage(Wnd, WM_ERASEBKGND, integer(P.DC), 0);
          SendMessage(Wnd, WM_PAINT, integer(P.DC), 0);



    Не хватает еще, как минимум
    SendMessage(Wnd, WM_PRINT, integer(P.DC), PRF_CLIENT);

  • homm © (18.09.07 20:26) [9]
    SendMessage(Wnd, WM_PRINT, integer(P.DC), PRF_CLIENT);


    Т.е. наоборот,
    PRF_NONCLIENT
  • Инс © (18.09.07 20:48) [10]

    > Не хватает еще, как минимум

    Ну да, логично, но если использовать WM_PRINT, то можно вообще одной строкой кода отделаться.
  • homm © (18.09.07 21:05) [11]
    > [10] Инс ©   (18.09.07 20:48)
    > Ну да, логично, но если использовать WM_PRINT, то можно
    > вообще одной строкой кода отделаться.

    Как раз нельзя. Принт понимают куда меньшее количество контролов, чем WM_PAINT, integer(P.DC). И уж совсем филосовское понимание сообщений у RichEdit, которому вообще все по барабану.
  • Инс © (18.09.07 21:39) [12]

    > [11] homm ©   (18.09.07 21:05)

    Однажды, кстати, столкнулся с проблемой, где один контрол никак не хотел себя рисовать правильно, какое бы сообщение (WM_PAINT, WM_PRINT) ему не посылать. Причем контрол какой-то самопальный. Там проблема была оказалось в том, что в обработчике WM_PAINT прорисовка осуществлялась не на DC, который был передан в качестве параметра. Автор компонента заново получал DC с помощью GetDC(Handle) и рисовал на нем. Что получалось в результате вполне понятно - возвращался пустой квадрат, а контрол перерисовывался. Но PrintWindow, как ни странно, выдавал правильный результат. Интересно, как он работает, судя по этому эксперименту, не через WM_PRINT, как можно было бы подумать...
  • homm © (18.09.07 21:48) [13]
    > [12] Инс ©   (18.09.07 21:39)
    > Интересно, как он работает, судя по этому эксперименту,
    > не через WM_PRINT

    Как ни странно,Ю в справке сказано, что именно через WM_PRINT. Вполне возможно врут :)
  • Инс © (18.09.07 22:02) [14]

    > Вполне возможно врут :)

    Черт его знает. Видимо не врут, просто алгоритм сложнее, чем мы его себе представляем. GetWindowText тоже через WM_GETTEXT работает, но посылка сообщения почему-то дает правильный результат постабильнее...
  • Инс © (18.09.07 22:10) [15]

    > Вполне возможно врут :)

    Скорее всего на более низком уровне PrintWindow работает, чем просто отослать сообщение.
  • homm © (18.09.07 22:13) [16]
    > [14] Инс ©   (18.09.07 22:02)
    > Видимо не врут, просто алгоритм сложнее, чем мы его себе
    > представляем.

    Помоему в описании была (лень снова открывть) фраза «similar to WM_PRINT» :)
  • Инс © (18.09.07 22:41) [17]

    > [16] homm ©   (18.09.07 22:13)

    А уж как мне лень, блин, кто бы мог только представить... :)

    Remarks

    This function is similar to WM_PRINT.


    Плюс, я в [7] наврал немного. В WinXP она только появилась, если верить MSDN.
  • Charger © (07.04.08 18:26) [18]
    ап. :(
    Приведенная функция PaintWindowToDC вообще ничего не снимает с приложения, только размеры определяет. Или я не правильно её вызываю?
    PaintWindowToDC(wnd,image1.Picture.Bitmap);

    Как я понял, проблема топика не решена?
  • Игорь Шевченко © (08.04.08 10:02) [19]
    не все йогурты умеют себя выводить на произвольный DC
  • Eraser © (08.04.08 14:31) [20]
    интересно, на каком принципе в висте превьюшки для панели задач сделаны?
    одно точно, что винап, с включенным modern-skin там отображается без этого скина )
  • Charger © (08.04.08 16:05) [21]
    Ну то что не все, примем на веру, хотя поясните, какое приложение не выводит.
    Вышеназванная функция ВООБЩЕ ничего не выводит.  Ни у какого приложения, даже не перекрытого. Ну непорядок это.

    В висте то далеко, есть пример поближе. В ХР, Aston shell, тоже показывает превьюшки. Кстати от Винампа там только квадратик виден... но калькулятор, блокнот, окно прогресса тотал командера и прочее и прочее (кроме некоторых игр) выводит в актуальном состоянии. Вот КАК? На сайте Астона сказали, что не могут сказать этого. )
     WinSign показывает только следующие мессаги окну, когда для него генерится миниатюра:
    000443:000209FC "Заголовок"  WM_PAINT Sent   (0,0)-(858,955)
    000444:000209FC "Заголовок"  WM_NCPAINT Sent   wp=00000001!
    000445:000209FC "Заголовок"  WM_GETTEXT Sent   510 bytes at 0012E014
    000446:000209FC "Заголовок"  WM_PAINT Dispatched   (0,0)-(858,955)
    000447:000209FC "Заголовок"  WM_PAINT Dispatched   (0,0)-(858,955)

    Обычные сообщения, но когда я такое посылаю, WinSign показывает не тот результат, что-то вроде

    000440:00140A4C "Form1"  WM_PAINT Sent   lp=0012F558!  (0,0)-(0,0)
    000441:00140A4C "Form1"  WM_NCPAINT Sent   wp=00000001!
    000442:00140A4C "Form1"  WM_PAINT Sent   wp=56011EE4!  (0,0)-(0,0)
     шлю кодом
    SendMessage(wnd, WM_PAINT,0,longInt(@R));
    SendMessage(wnd, WM_NCPAINT,1,0);

    В общем не получается. Подскажите где неправ.
  • Charger © (08.04.08 16:07) [22]
    И еще, может кто-то разобратся в статье: http://www.fengyuan.com/article/wmprint.html ?
  • Charger © (12.05.08 12:16) [23]
    Удалено модератором
    Примечание: Создание пустых сообщений
 
Конференция "WinAPI" » Снимок частично закрытого окна [D6, WinXP]
Есть новые Нет новых   [134433   +22][b:0][p:0.002]