Что нового

Корректное восстановление содержимого буфера обмена

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
У кого есть рабочий пример запоминания и последующего восстановления содержимого буфера обмена?

Пока делаю вот так:

Код:
#include <ClipBoard.au3>

$sText = _ClipBoard_GetSelText()
MsgBox(0, '', $sText)

Func _ClipBoard_GetSelText()
	Local $aOld_Clip, $iTimer, $sSelText
	Local $hWnd = GUICreate('')
	
	$aOld_Clip = _ClipBoard_Remember($hWnd)
	
	If @error Or Not _ClipBoard_Open($hWnd) Then
		GUIDelete($hWnd)
		Return SetError(1, 0, '')
	EndIf
	
	ClipPut('')
	Send('^{INS}')
	$iTimer = TimerInit()
	
	Do
		If _ClipBoard_IsFormatAvailable($CF_TEXT) Then
			$sSelText = ClipGet()
		EndIf

		Sleep(10)
	Until TimerDiff($iTimer) > 250 Or $sSelText <> ''
	
	_ClipBoard_Close()
	_ClipBoard_Restore($aOld_Clip)
	GUIDelete($hWnd)
	
	If StringStripWS($sSelText, 8) = '' Then
		Return SetError(2, 0, '')
	EndIf
	
	Return $sSelText
EndFunc

Func _ClipBoard_Remember($hWnd)
	Local $iFormat
	Local $aRet[1][2]
	
	If Not _ClipBoard_Open($hWnd) Then
		Return SetError(1, 0, 0)
	EndIf
	
	Do
		$iFormat = _ClipBoard_EnumFormats($iFormat)
		
		If $iFormat <> 0 Then
			$aRet[0][0] += 1
			ReDim $aRet[$aRet[0][0] + 1][2]
			$aRet[$aRet[0][0]][1] = $iFormat
		EndIf
	Until $iFormat = 0
	
	_ClipBoard_Close()
	
	For $i = 1 To $aRet[0][0]
		$aRet[$i][0] = _ClipBoard_GetData($aRet[$i][1])
	Next
	
	Return $aRet
EndFunc

Func _ClipBoard_Restore(ByRef $aClip)
	If UBound($aClip, 0) <> 2 Then
		Return SetError(1)
	EndIf
	
	For $i = 1 To $aClip[0][0]
		_ClipBoard_SetData($aClip[$i][0], $aClip[$i][1])
	Next
	
	$aClip = 0
	
	Return 1
EndFunc


Работает, т.е содержимое восстанавливается, но за исключением одного(?) формата - скопированный файл.
Никак не могу понять почему не восстанавливает скопированный файл :scratch:.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
CreatoR
содержимое восстанавливается
Не полностью. Если в IE10 скопировать текст (например, с этой страницы), то, после выполнения скрипта, в любой текстовый редактор вставляются знаки вопросов. Значит, проблема не только со скопированным файлом, а несколько шире.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Решение нашлось:

Код:
#include <Clipboard.au3>

$sText = _ClipBoard_GetSelText()
MsgBox(0, '', $sText)

Func _ClipBoard_GetSelText()
    Local $aOld_Clip, $iTimer, $sSelText
    
    $aOld_Clip = _ClipBoard_Remember()
    
    If @error Or Not _ClipBoard_Open(0) Then
        Return SetError(1, 0, '')
    EndIf
    
    ClipPut('')
    Send('^{INS}')
    $iTimer = TimerInit()
    
    Do
        If _ClipBoard_IsFormatAvailable($CF_TEXT) Then
            $sSelText = ClipGet()
        EndIf

        Sleep(10)
    Until TimerDiff($iTimer) > 250 Or $sSelText <> ''
    
    _ClipBoard_Close()
    _ClipBoard_Restore($aOld_Clip)
    _ClipBoard_MemFree($aOld_Clip)
    
    If StringStripWS($sSelText, 8) = '' Then
        Return SetError(2, 0, '')
    EndIf
    
    Return $sSelText
EndFunc

Func _ClipBoard_Remember()
	Local $iFormat = 0, $hMem, $hMem_New, $pSource, $pDest, $aResult, $iSize, $iErr = 0, $iErr2 = 0
	Local $avClip
	
	Dim $avClip[1][2]
	
	If Not _ClipBoard_Open(0) Then
		Return SetError(-1, 0, 0)
	EndIf
	
	Do
		$iFormat = _ClipBoard_EnumFormats($iFormat)
		
		If $iFormat <> 0 Then
			ReDim $avClip[UBound($avClip) + 1][2]
			$avClip[0][0] += 1
			; aClip[n][0] = iFormat, aClip[n][1] = hMem
			$avClip[UBound($avClip) - 1][0] = $iFormat
			$hMem = _ClipBoard_GetDataEx($iFormat)
			
			If $hMem = 0 Then
				$iErr += 1
				ContinueLoop
			EndIf
			
			$pSource = _MemGlobalLock($hMem)
			$iSize = _MemGlobalSize($hMem)
			$hMem_New = _MemGlobalAlloc($iSize, $GHND)
			$pDest = _MemGlobalLock($hMem_New)
			
			Local $aResult = DllCall("msvcrt.dll", "int:cdecl", "memcpy_s", "ptr", $pDest, "ulong_ptr", $iSize, "ptr", $pSource, "ulong_ptr", $iSize)
			
			If @error Or $aResult[0] <> 0 Then
				$iErr2 += 1
			EndIf
			
			_MemGlobalUnlock($hMem)
			_MemGlobalUnlock($hMem_New)
			$avClip[UBound($avClip) - 1][1] = $hMem_New
		EndIf
	Until $iFormat = 0
	
	_ClipBoard_Close()
	
	; Return:
	; | 0       - no errors
	; |-2       - _MemGlobalAlloc errors
	; |-4       - _MemCopyMemory errors
	; |-6       - both errors
	; @extended:
	;           - total number of errors
	Local $ErrRet = 0
	If $iErr Then $ErrRet -= 2
	If $iErr2 Then $ErrRet -= 4
	
	If $ErrRet Then
		Return SetError($ErrRet, $iErr + $iErr2, 0)
	EndIf
	
	Return $avClip
EndFunc

Func _ClipBoard_Restore(ByRef $avClip)
	; DO NOT free the memory handles after a call to this function
	; the system now owns the memory
	Local $iErr = 0
	
	If Not IsArray($avClip) Or UBound($avClip, 0) <> 2 Or $avClip[0][0] <= 0 Then
		Return SetError(-1, 0, 0)
	EndIf
	
	If Not _ClipBoard_Open(0) Then
		Return SetError(-2, 0, 0)
	EndIf
	
	If Not _ClipBoard_Empty() Then
		_ClipBoard_Close()
		Return SetError(-3, 0, 0)
	EndIf
	
	; seems to work without closing / reopening the clipboard, but MSDN implies we should do this
	; since a call to EmptyClipboard after opening with a NULL handle sets the owner to NULL,
	; and SetClipboardData is supposed to fail, so we close and reopen it to be safe
	_ClipBoard_Close()
	
	If Not _ClipBoard_Open(0) Then
		Return SetError(-3, 0, 0)
	EndIf
	
	For $i = 1 To $avClip[0][0]
		If _ClipBoard_SetDataEx($avClip[$i][1], $avClip[$i][0]) = 0 Then
			$iErr += 1
		EndIf
	Next
	
	_ClipBoard_Close()
	
	If $iErr Then
		Return SetError(-4, $iErr, 0)
	EndIf
	
	Return 1
EndFunc

Func _ClipBoard_MemFree(ByRef $avClip)
	Local $iErr = 0
	
	If Not IsArray($avClip) Or UBound($avClip, 0) <> 2 Or $avClip[0][0] <= 0 Then
		Dim $avClip[1][2]
		Return SetError(-1, 0, 0)
	EndIf
	
	For $i = 1 To $avClip[0][0]
		If Not _MemGlobalFree($avClip[$i][1]) Then
			$iErr += 1
		EndIf
	Next
	
	Dim $avClip[1][2]
	
	If $iErr Then
		Return SetError(-2, $iErr, 0)
	EndIf
	
	Return 1
EndFunc
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
OffTopic:
InnI [?]
Почему-то всегда так - стОит создать тему, как сразу находится решение
Тоже заметил такую тенденцию, видимо нужен "взгляд со стороны", чтобы понять где кроется решение :smile:.

.
 
Верх