Конференция "Media" » Глюки при снятии скриншотов почему?
 
  • gedevan (09.12.15 15:53) [0]
    Код работает в обычной винде и в виртуальных машинах с гостевой XP,windows 7,windows 8. Редко бывают какие то глюки, но это не критично.
    Но вот я установил гостевую windows 10 и имеем, когда я делаю скриншот в основном потоке (скриншот окна по хендлу) то все нормально. Если я делаю этим кодом скриншоты всего рабочего стола - все нормально, но как только я пытаюсь скриншотить окно по хендлу в отдельном потоке он мне выдает какой то 1й скрин окна и все....сколько дальше он не скриншотит в результате я вижу только этот первый скрин. Причем если я перезапущу свою программу!!! т.е. в ней гарантировано все удалится, то после попытки делать скриншоты он опять покажет мне тот же самый "первый скрин" что за дела? Ранее у меня такое случалось  и на windows 8, чем закончилось хз. Может что то не так с моим кодом?

    procedure TScreenShot.Execute;
    var
     T: Cardinal;
     pause: Integer;
     res: boolean;
     pt: TPoint;
    begin

     if fOfflineMode then // в офлайн версии нельзя запускать поток.
       exit;

     T := GetTickCount;
     if (fType = 'Global') then //при выполнении этого условия все работает всегда
     begin
       fScreen.Width := screen.Width;
       fScreen.Height := screen.Height;
       fhSrcDC := GetDC(0);
       fhDC1 := CreateCompatibleDC(fhSrcDC);
       SelectObject(fhDC1, fScreen.Handle);
       pt.X := 0;
       pt.Y := 0;
     end;

     while (not Terminated) do // and (getasynckeystate($1B) = 0) do
     begin
       res := true;

       SimpSync.StartWrite;

        if fType = 'Local' then //а при выполнении этого глюки
       begin
         try
           res := MyFindWindow;
         except
           ferrorText := 'koshmar';
         end;

         if fClientShot then
         begin
           pt.X := fClR.left - R.left;
           pt.Y := fClR.Top - R.Top;
         end
         else
         begin
           pt.X := 0;
           pt.Y := 0;
         end;
       end;

       if res then
       begin
         BitBlt(fhDC1, 0, 0, fScreen.Width, fScreen.Height, fhSrcDC, pt.X,
           pt.Y, SRCCOPY);
       end;

       SimpSync.EndWrite;
     end;
    end;




    Function TScreenShot.MyFindWindow(): boolean;
    begin

     if isWindow(FHandle) then
     begin

       if (not IsWindowVisible(FHandle)) or IsIconic(FHandle) then
       begin
         ShowWindow(FHandle, SW_SHOWNORMAL);
         sleep(200);
       end;
       // на случай если окно сдвинули или изменили в размерах, нужно координаты обновить

       GetWindowRect(FHandle, fR);

       if fR.left < 0 then
       begin
         result := false;
         exit;
       end;

       if CheckSizeWindow then
       // если окно съехало или изменилось в размерах поменяем дескрипторы, а то возникает ошибка
       begin

         if fhSrcDC <> 0 then
         // если мы пересоздаем окно, то убьем старые дескрипторы
         begin
           DeleteDC(fhSrcDC);
           ReleaseDC(FHandle, fhDC1);
           DeleteDC(fhDC1);
         end;

         fhSrcDC := GetwINDOWDC(FHandle);
         fhDC1 := CreateCompatibleDC(fhSrcDC);
         SelectObject(fhDC1, fScreen.Handle);
       end;

       if fClientShot then
       begin
         GetClientRect(FHandle, fClR);
         MapWindowPoints(FHandle, 0, fClR, 2);
         // получает координаты клиенской части в глобальных координатах
         fScreen.Width := fClR.Width;
         fScreen.Height := fClR.Height;
       end
       else
       begin
         fScreen.Width := fR.Width;
         fScreen.Height := fR.Height;
       end;

       result := true;
       exit;
     end;

     result := false;

     
       WaitForSingleObject(MyMutex, INFINITE);
       FHandle := FindWindowA(CNP, WNP);
       ReleaseMutex(MyMutex);
     
     if FHandle > 0 then
     begin
       if (fhSrcDC <> 0) then
       // если мы нашли окно заново, то возможно его перезапустили, а потому, убьем старые дескрипторы
       begin
         ReleaseDC(FHandle, fhDC1);
         DeleteDC(fhSrcDC);
         DeleteDC(fhDC1);
       end;

       GetWindowRect(FHandle, fR);
       if fClientShot then
       begin
         GetClientRect(FHandle, fClR);
         MapWindowPoints(FHandle, 0, fClR, 2);
         fScreen.Width := fClR.Width;
         fScreen.Height := fClR.Height;
       end
       else
       begin
         fScreen.Width := fR.Width;
         fScreen.Height := fR.Height;
       end;

       If (fScreen.Width = 0) or (fScreen.Height = 0) then
       Begin
         ferrorText := ferrorText + 'Размер области формы равен нулю';
         // А вдруг у него нет размера ???
         result := false;
         exit; // Тогда выходим
       End;

       fhSrcDC := GetwINDOWDC(FHandle);
       fhDC1 := CreateCompatibleDC(fhSrcDC);
       SelectObject(fhDC1, fScreen.Handle);

        if fhSrcDC > 0 then
         result := true;
     end;

    end;

  • Rouse_ © (09.12.15 19:17) [1]
    Все очень просто, они еще более разграничили доступ к DC окон, к которым у тебя не может быть доступа. Я не думаю что для тебя новость что GUI нить - это основная, и сама в себе содержит много всякой дряни, в том числе и структуры окон описываемые неким хэндлом в качестве идентификатора (по сути являющимся также составной структурой), принадлежащих данной нити (в которых и лежит тот заветный HDC, который тебе и нужен).
    Раньше было все проще, указывая хэндл принадлежащий процессу но не данной нити - раскручивалась цепочка поиска по всем нитям, а теперь - будьте добры, научитесь программировать правильно. Все что не принадлежит текущей нити (окна и их DC) идет трансфером в основную нить.
    Есть простой выход - подключай свою текущую нить к основной и все у тебя заработает (как это описано в MSDN)
  • gedevan (09.12.15 20:42) [2]
    чессно гря, я понятия не имею где там и что конкретно искать, а есть ссылка?

    Сейчас у меня связь с основным потоком идет в одном направлении (основной поток забирает скриншоты), боюсь будут дедлоки (
  • Pavia © (09.12.15 22:00) [3]

    > Rouse_ ©   (09.12.15 19:17) [1]

    А можно подробнее? Вроде где-то краем уха слышал.
  • Rouse_ © (10.12.15 11:49) [4]
    Чуть попозже, это нужно код писать демку делать, а времени ноль, я и так без выходных третий месяц работаю :)
  • gedevan (08.01.16 00:53) [5]
    ну когда же когда?
  • Rouse_ © (08.01.16 02:40) [6]
    Блин ну фень юаня почитайте, че как маленькие то :)
  • Лори (09.01.16 17:08) [7]
    Это в той на которую недавно давали ссылку? Она ж 2012 года вроде) Откуда там про особенности Win10?)))

    Мне тоже любопытно, книгу начал, Win10 ещё не видел даже. Дочитаю, поставлю - отпишусь об экспериментах.
    Хотя код выше несколько странный. Никогда не видел чтоб использовали MapWindowPoints для подобного. А что с Windows.PrintWindow() не так?
 
Конференция "Media" » Глюки при снятии скриншотов почему?
Есть новые Нет новых   [134427   +37][b:0][p:0.004]