Что нового

_ScreenCapture() - Универсальный скриншот экрана

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Заметил такую штуку, в Windows XP (в Vista/7 не проверял) функция _ScreenCapture_Capture() берет не все, что находится на экране. Например окна имеющие стиль WS_EX_LAYERED невозможно захватить с помощью этой функции. Немного наморщив ум, написал аналогичную функцию для создания скриншота всего экрана, но работающую через "PrintScreen".

Код:
#Include <ClipBoard.au3>
#Include <GDIPlus.au3>

_ScreenCapture(@ScriptDir & '\Screenshot.bmp')

Func _ScreenCapture($sFile)

    Local $Result, $Timer, $hImage, $hBitmap = 0

    ClipPut('')
    Send('{PRINTSCREEN}')
    $Timer = TimerInit()
    While TimerDiff($Timer) < 1000
        _ClipBoard_Open(0)
        $hBitmap = _ClipBoard_GetDataEx($CF_BITMAP)
        _ClipBoard_Close()
        If $hBitmap Then
            ExitLoop
        EndIf
        Sleep(10)
    WEnd
    If Not $hBitmap Then
        Return 0
    EndIf
    _GDIPlus_Startup()
    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
    $Result = _GDIPlus_ImageSaveToFile($hImage, $sFile)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
    Return $Result
EndFunc   ;==>_ScreenCapture
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Хорошая идея, только вот содержимое буфера не помешало бы восстанавливать.
А ещё можно добавить опцию захвата только активного окна:

Код:
#Include <ClipBoard.au3>
#Include <GDIPlus.au3>

$sFile = @DesktopDir & '\Screenshot.bmp'

_ScreenCapture($sFile, True)
ShellExecute($sFile)

Func _ScreenCapture($sFile, $bActiveWindow = 0)
    Local $Result, $Timer, $Old_Clip, $hImage, $hBitmap = 0
	$Old_Clip = ClipGet()
    ClipPut('')
	If $bActiveWindow Then
		Send('!{PRINTSCREEN}')
	Else
		Send('{PRINTSCREEN}')
	EndIf
    $Timer = TimerInit()
    While TimerDiff($Timer) < 1000
        _ClipBoard_Open(0)
        $hBitmap = _ClipBoard_GetDataEx($CF_BITMAP)
        _ClipBoard_Close()
		If $hBitmap Then
            ExitLoop
		EndIf
        Sleep(10)
    WEnd
    If Not $hBitmap Then
		ClipPut($Old_Clip)
        Return 0
    EndIf
    _GDIPlus_Startup()
    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
    $Result = _GDIPlus_ImageSaveToFile($hImage, $sFile)
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_Shutdown()
	ClipPut($Old_Clip)
    Return $Result
EndFunc   ;==>_ScreenCapture
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Да верно, а еще можно добавить создание скриншота по заданным координатам для совместимости с _ScreenCapture_Capture().



Добавлено:
Сообщение автоматически объединено:

CreatoR сказал(а):
...только вот содержимое буфера не помешало бы восстанавливать.

Тоже хорошая идея, правда буфер может содержать не только текст, и в этом случае твой код все равно его очистит.

:(
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,669
Репутация
2,463
Yashied [?]
правда буфер может содержать не только текст, и в этом случае твой код все равно его очистит
Вот так кажется восстанавливает содержимое буфера для всех форматов:

Код:
Func _ScreenCaptureEx($sFile, $bActiveWindow = False)
	Local $Result, $Timer, $aOld_Clip, $iFormat, $hImage, $hBitmap
	
	_ClipBoard_Open(0)
	
	Dim $aOld_Clip[_ClipBoard_CountFormats()+1][2]
	
	Do
		$iFormat = _ClipBoard_EnumFormats($iFormat)
		
		If $iFormat <> 0 Then
			$aOld_Clip[0][0] += 1
			$aOld_Clip[$aOld_Clip[0][0]][0] = _ClipBoard_GetData($iFormat)
			$aOld_Clip[$aOld_Clip[0][0]][1] = $iFormat
		EndIf
	Until $iFormat = 0
	
	_ClipBoard_Empty()
	_ClipBoard_Close()
	
	If $bActiveWindow Then
		Send('!{PRINTSCREEN}')
	Else
		Send('{PRINTSCREEN}')
	EndIf
	
	$Timer = TimerInit()
	
	While TimerDiff($Timer) < 1000
		_ClipBoard_Open(0)
		$hBitmap = _ClipBoard_GetDataEx($CF_BITMAP)
		_ClipBoard_Close()
		If $hBitmap Then ExitLoop
		Sleep(10)
	WEnd
	
	$hBitmap = DllCall('user32.dll', 'ptr', 'CopyImage', 'ptr', $hBitmap, 'int', 0, 'int', 0, 'int', 0, 'int', 0)
	If Not @error Then $hBitmap = $hBitmap[0]
	
	_ClipBoard_Open(0)
	
	For $i = 1 To $aOld_Clip[0][0]
		_ClipBoard_SetData($aOld_Clip[$i][0], $aOld_Clip[$i][1])
	Next
	
	_ClipBoard_Close()
	
	If Not $hBitmap Then Return 0
	
	If $sFile <> "" Then
		_GDIPlus_Startup()
		$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
		$Result = _GDIPlus_ImageSaveToFile($hImage, $sFile)
		_GDIPlus_ImageDispose($hImage)
		_GDIPlus_Shutdown()
	Else
		$Result = $hBitmap
	EndIf
	
	Return $Result
EndFunc



Добавлено:
Сообщение автоматически объединено:

Но не хочет сохранять файл :(
Если заменить «_ClipBoard_GetData($iFormat)» на «_ClipBoard_GetDataEx($iFormat)», то сохранение работает, а вот восстановление буфера нет, в чём может быть дело? :scratch:

Исправлено.
 
Верх