Конференция "WinAPI" » Чем принципиально отличаются эти два примера кода ... [D7, WinXP]
 
  • Megavolt_Old (09.12.09 17:50) [0]
    Код снимает копию экрана и отображает на форме.

    Особенности:

    1. Второй код снимает копию экрана с ToolTip (всплывающе подсказки во многих приложениях кроме дельфи. Например в проводнике). Что даёт промежуточное копирование во временную DC не очень понятно.

    2. Через какое то время оба они перестают работать. Т.е. таймер считает а картинка не обновляется :(

    procedure TForm1.Timer1Timer(Sender: TObject);
    const  CAPTUREBLT = $40000000;
    var
     hdcScreen: HDC;
     hdcCompatible: HDC;
     bmp: TBitmap;
     hbmScreen: HBITMAP;
    begin
     Timer1.Enabled:=false;

     try
       hdcScreen:=GetDC(0);
       Win32Check(BitBlt(Form1.Canvas.Handle,0,0,200,300,  hdcScreen,  0, 0, SRCCOPY or CAPTUREBLT));
     finally
       DeleteDC(hdcScreen);
     end;
     Timer1.Enabled:=true;
     Label1.Caption:=IntToStr(GetTickCount);
    end;

    procedure TForm1.Timer1Timer(Sender: TObject);
    const  CAPTUREBLT = $40000000;
    var
     hdcScreen: HDC;
     hdcCompatible: HDC;
     bmp: TBitmap;
     hbmScreen: HBITMAP;
    begin
     Timer1.Enabled:=false;

     //hdcScreen := CreateDC('DISPLAY', nil, nil, nil);
     try
       hdcScreen:=GetDC(0);
       try
         hdcCompatible := CreateCompatibleDC(hdcScreen); // Create a compatible bitmap for hdcScreen.
         hbmScreen := CreateCompatibleBitmap(hdcScreen,
                                             GetDeviceCaps(hdcScreen, HORZRES),
                                             GetDeviceCaps(hdcScreen, VERTRES));// Select the bitmaps into the compatible DC.
         SelectObject(hdcCompatible, hbmScreen);
         Win32Check(BitBlt(hdcCompatible,0,0,GetDeviceCaps(hdcScreen, HORZRES),GetDeviceCaps(hdcScreen, VERTRES),hdcScreen,0,0,SRCCOPY or CAPTUREBLT));
         Win32Check(BitBlt(Form1.Canvas.Handle,0,0,200,300,  hdcCompatible,  0, 0, SRCCOPY or CAPTUREBLT));
       finally
         DeleteDC(hdcCompatible);
       end;
     finally
       DeleteDC(hdcScreen);
     end;
     Timer1.Enabled:=true;
     Label1.Caption:=IntToStr(GetTickCount);
    end;

  • MegaVolt_old (09.12.09 18:28) [1]
    Второй пункт уточню:

    Зависает только второй код. Из-за утечки GDI объектов. Каких я пока не понял кто что видит подскажите.
  • DVM © (09.12.09 18:56) [2]

    > Каких я пока не понял кто что видит подскажите.

    проблема в CreateCompatibleBitmap + SelectObject

    плюс почему у тебя создание объекта внутри try except
  • DVM © (09.12.09 18:58) [3]

    > внутри try except

    я хотел сказать внутри try finally.
  • Sapersky (09.12.09 20:53) [4]
    Create[Compatible]DC -> DeleteDC, GetDC -> ReleaseDC
  • MegaVolt_Old (10.12.09 00:27) [5]
    DVM
    >проблема в CreateCompatibleBitmap + SelectObject

    Ага похоже что так. Только вот как её исправить я не понял. Попробовал так как в коде ниже не помогло. Подскажи пожалуйста я не очень большой спец в API :(

    >плюс почему у тебя создание объекта внутри try except

    Вай вай... Какой позор. Мне очень стыдно.... :(

    Sapersky

    Поправил так как ты предложил ничего не изменилось :( Похоже они равнозначны.

    procedure TForm1.Timer1Timer(Sender: TObject);
    const  CAPTUREBLT = $40000000;
    var
     hdcScreen: HDC;
     hdcCompatible: HDC;
     bmp: TBitmap;
     hbmScreen,hbmOld: HBITMAP;
    begin
     Timer1.Enabled:=false;

     //hdcScreen := CreateDC('DISPLAY', nil, nil, nil);
     hdcScreen:=GetDC(0);
     try
       hdcCompatible := CreateCompatibleDC(hdcScreen); // Create a compatible bitmap for hdcScreen.
       try
         hbmScreen := CreateCompatibleBitmap(hdcScreen,
                                             GetDeviceCaps(hdcScreen, HORZRES),
                                             GetDeviceCaps(hdcScreen, VERTRES));// Select the bitmaps into the compatible DC.
         hbmOld:=SelectObject(hdcCompatible, hbmScreen);
         Win32Check(BitBlt(hdcCompatible,0,0,GetDeviceCaps(hdcScreen, HORZRES),GetDeviceCaps(hdcScreen, VERTRES),hdcScreen,0,0,SRCCOPY or CAPTUREBLT));
         Win32Check(BitBlt(Form1.Canvas.Handle,0,0,200,300,  hdcCompatible,  0, 0, SRCCOPY or CAPTUREBLT));
         SelectObject(hdcCompatible, hbmOld);
         DeleteDC(hbmScreen);

       finally
         DeleteDC(hdcCompatible);
       end;
     finally
       ReleaseDC(0,hdcScreen);
     end;
     Timer1.Enabled:=true;
     Label1.Caption:=IntToStr(GetTickCount);
    end;

  • DVM © (10.12.09 01:21) [6]

    > Попробовал так как в коде ниже не помогло


    > DeleteDC(hbmScreen);

    Конечно, если создавать Bitmap, а удалять DC. В справке по CreateCompatibleBitmap что сказано про удаление, какая там функция?
  • MegaVolt_Old (10.12.09 01:26) [7]
    DVM Мдя... накосячил так накосячил.... Большущее тебе спасибо :)

    Может ты ещё знаешь почему второй код показывает tooltip-ы а первый нет? Почему промежуточное копирование даёт такой хитрый эффект?
  • han_malign (18.12.09 14:25) [8]

    > Почему промежуточное копирование даёт такой хитрый эффект?

    либо DC не совсем Compatible, либо GDI(который не +(плюс)) вообще не умеет напрямую копировать из Common DC в Private DC(кажется где-то что-то такое упоминалось, но найти не могу, возможно просто дежа-вю)
  • _L_ (16.01.10 13:42) [9]
    > Sapersky   (09.12.09 20:53) [4]
    > Create[Compatible]DC -> DeleteDC, GetDC -> ReleaseDC


    А мне говорили что надо всегда оба писать... То есть вот так например:

    GetDC();
    ...
    ReleaseDC();
    DeleteDC();



    А не рациональнее сделать глобальные переменные - GetDC(0) вроде ж постоянное...
    Постоянно создавать и уничтожать часто используемые HDC не вижу смысла - лишняя работа для ОС...
    Да и есть ли смысл так жоско всё упаковывать в "Try ... Finally ..."?

    > Может ты ещё знаешь почему второй код показывает tooltip-ы а первый нет?

    Хм... Флаг CAPTUREBLT по идее должен все слоёные окна включать в скрин... Надо бы разузнать почму так... Для начала я б выбросил все "Try ... Finally ..." - не удобно понимать код с ними (да и есть ли какой толк с него)...

    P.S. А для чего делается так?:
    begin
    Timer1.Enabled:=false;
    ...
    Timer1.Enabled:=true;
    end;

  • _L_ (16.01.10 15:00) [10]
    Потестил... Там кажется чудовищные глюки из-за "Form1.Canvas.Handle"...
    А если через промежуточный TBitmap делать - то всё норм, как ни в чём ни бывало...

    То ли в винде касяк, то ли в VCL... Надо будет переписать на чистом WinAPI чтоб точно выяснить...
  • SPeller © (18.01.10 06:13) [11]

    > чудовищные глюки из-за "Form1.Canvas.Handle"

    Я его тоже не люблю :) Всегда отдельный контекст брал.
 
Конференция "WinAPI" » Чем принципиально отличаются эти два примера кода ... [D7, WinXP]
Есть новые Нет новых   [134431   +15][b:0][p:0.003]