Что нового

Работа с дескриптором типа HDROP, идентифицирующим список файлов ($CF_HDROP)

mef-t

Осваивающий
Сообщения
306
Репутация
30
Доброго времени суток.

Это уже вторая тема по работе с буфером обмена.
Существуют 2 функции: _ClipBoard_GetData() и _ClipBoard_SetData()
Их описание сводится к тому, что достаточно получить содержимое буфера обмена одной функцией и затем его можно разместить в буфере второй функцией.
На практике все оказалось не так.
Самое страшное не то, что я не понимаю, как реализовать изъятие и возврат не текстового содержимого, а то, что я нигде не смог найти информации по данной теме. В основном это связано с не умением пользоваться поиском, но так и с тем, что нужно знать чуть больше чем я знаю сейчас.

Первый вопрос был связан с копированием изображения.
http://autoit-script.ru/index.php/topic,16198
Ответ получен.

На текущий момент мне нужно получить информацию о копируемых файлах и каталогах.
Данную информацию можно получить как объект или как дескриптор типа HDROP.

Следующий код не работает:

Код:
_ClipBoard_Open(0)
	$hfile = _ClipBoard_GetDataEx($CF_HDROP)
	ConsoleWrite('$hfile = ' & $hfile & @CRLF)
	_ClipBoard_Empty()
	_ClipBoard_Close()
;~ 	Работа с буфером обмена
	_ClipBoard_Open(0)
	_ClipBoard_SetDataEx($hfile, $CF_HDROP)
	_ClipBoard_Close()

Проблема в том, что буфер обмена закрывается и дескриптор обнуляется.
Мне необходимо скопировать данный дескриптор. Просьба подсказать, как?
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
mef-t
Опять та же ошибка :smile:

Вы получаете указатель и после очистки буфера он указывает неизвестно куда.
Лично я никогда не работал с CF_HDROP, поэтому пришлось немного поэкспериментировать...
http://msdn.microsoft.com/en-us/library/windows/desktop/bb776902(v=vs.85).aspx#CF_HDROP

Код:
#include <Clipboard.au3>
#include <WinAPI.au3>

Const $tagDROPFILES = "dword pFiles; long ptX; long ptY; bool fNC; bool fWide; "

_ClipBoard_Open(0)
$hDROP = _ClipBoard_GetDataEx($CF_HDROP)

$tStruct = DllStructCreate( $tagDROPFILES, $hDROP )
	$pFiles = DllStructGetData( $tStruct, "pFiles" )
	$ptX = DllStructGetData( $tStruct, "ptX" )
	$ptY = DllStructGetData( $tStruct, "ptY" )
	$fNC = DllStructGetData( $tStruct, "fNC" )
	$fWide = DllStructGetData( $tStruct, "fWide" )
ConsoleWrite( "pFiles=" & Hex( $pFiles ) & @CRLF & _
	"ptX=" & $ptX & @CRLF & _
	"ptY=" & $ptY & @CRLF & _
	"fNC=" & $fNC & @CRLF & _
	"fWide=" & $fWide & @CRLF )
$tFileList = DllStructCreate( "wchar[260]", $hDROP + $pFiles )
	$sFirstFile = DllStructGetData( $tFileList, 1 )
	ConsoleWrite( "First file from FileList: " & $sFirstFile & @CRLF )

_ClipBoard_Empty()
_ClipBoard_Close()
;============================

Dim $tStruct = "", $tFileList = ""
_ClipBoard_Open(0)

$iLen = StringLen( $sFirstFile )
$hMemory = _MemGlobalAlloc( 0x14 + 0x02 + ( $iLen * 2 ), $GHND )
If $hMemory <> 0 Then
	$hLock = _MemGlobalLock($hMemory)
	If $hLock <> 0 Then
		$tStruct = DllStructCreate( $tagDROPFILES & "wchar[" & $iLen & "]; byte[2];", $hLock )
			DllStructSetData( $tStruct, "pFiles", $pFiles )
			DllStructSetData( $tStruct, "ptX", $ptX )
			DllStructSetData( $tStruct, "ptY", $ptY )
			DllStructSetData( $tStruct, "fNC", $fNC )
			DllStructSetData( $tStruct, "fWide", $fWide )
			DllStructSetData( $tStruct, 6, $sFirstFile )
			DllStructSetData( $tStruct, 7, Binary( 0x00 ) )

		_MemGlobalUnlock( $hMemory )
		_ClipBoard_SetDataEx( $hMemory, $CF_HDROP )
	EndIf
EndIf
_ClipBoard_Close()

MsgBox( 64, "", "Пробуй" )



Если захочешь получать список всех файлов, то действуй примерно так (все в цикле):
Максимальная длинна пути + имя файла + расширение = 260 (wchar).
1)Создаем структуру в начале текущего пути.
2)Извлекаем юникод-строку (наш текущий файл). Получаем длинну строки (StrLen * 2 ).
3)Создаем структуру byte[2] следом за нашей строкой (начало текущего пути + длинна строки), если равно "0000" - то это последний файл в списке, иначе ("00XX") - то новое начало текущего пути равно (начало текущего пути + длинна строки + 1) и переходим к пункту 1.
Код:
c:\temp1.txt'\0'c:\temp2.txt'\0''\0'
 
Автор
mef-t

mef-t

Осваивающий
Сообщения
306
Репутация
30
Ошибка та же, но я о ее наличии знаю, и даже указал в сообщении: первое предложение после кода.
Пока смотрю Ваш код.


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

Осилить не смог.
OffTopic:
Нет, самую малость из описанного я понял, но она ничтожно мала, которой можно пренебречь. Т.е. я ничего не понял.


Большая просьба расписать код. Ага. Увидел текст под кодом. Понял.

P.S. $CF_HDROP - это известный для autoit (точнее тот что в справке) формат. Но так же содержимое буфера возвращается и в других форматах, один из которых - object.
Может быть есть более простой вариант, при котором данные будут скопированы.
P.P.S. В идеале мне вообще нужен код, который при любом содержимом буфера сможет выполнять поставленную задачу: копировать содержимое, чистить буфер, работать с буфером, возвращать содержимое.
Я буду очень благодарен за помощь.
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
mef-t
Код:
_ClipBoard_CountFormats

Посмотрите пример к этой функции. В соответствии с типом содержимого делайте бэкап, а затем его восстанавливайте.
Не все так просто как хотелось бы :smile:
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
mef-t [?]
Следующий код не работает:
А так:
Код:
$hGUI = GUICreate("")
_ClipBoard_Open ($hGUI)
$hfile = _ClipBoard_GetDataEx($CF_HDROP)
ConsoleWrite('$hfile = ' & $hfile & @CRLF)
_ClipBoard_Empty()
_ClipBoard_Close()

;~  Работа с буфером обмена
_ClipBoard_Open($hGUI)
_ClipBoard_SetDataEx($hfile, $CF_HDROP)
_ClipBoard_Close()
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
inververs
Глупости вы пишете :smile:

mef-t
Полноценный вариант ( списывает и восстанавливает любое количество(а именно до 999) файлов ):

Код:
#include <Clipboard.au3>
#include <WinAPI.au3>

Const $tagDROPFILES = "dword pFiles; long ptX; long ptY; bool fNC; bool fWide; "

_ClipBoard_Open(0)
$pDROPFILES = _ClipBoard_GetDataEx( $CF_HDROP )

$tDROPFILES = DllStructCreate( $tagDROPFILES, $pDROPFILES )
	$pFiles = DllStructGetData( $tDROPFILES, "pFiles" )
	$ptX = DllStructGetData( $tDROPFILES, "ptX" )
	$ptY = DllStructGetData( $tDROPFILES, "ptY" )
	$fNC = DllStructGetData( $tDROPFILES, "fNC" )
	$fWide = DllStructGetData( $tDROPFILES, "fWide" )
ConsoleWrite( "pFiles=" & Hex( $pFiles ) & @CRLF & _
    "ptX=" & $ptX & @CRLF & _
    "ptY=" & $ptY & @CRLF & _
    "fNC=" & $fNC & @CRLF & _
    "fWide=" & $fWide & @CRLF & _
	"FileList_UNICODESTR_ARRAY:" & @CRLF )

Local $aFileList[999] = [0], $pCurFile = $pDROPFILES + $pFiles
While 1
	$tFILELIST = DllStructCreate( "wchar[260]", $pCurFile )
		$sCurFile = DllStructGetData( $tFILELIST, 1 )
		$iCurFileLen = StringLen( $sCurFile )

	If $iCurFileLen Then
		$aFileList[0] += 1
		$aFileList[$aFileList[0]] = $sCurFile
		ConsoleWrite( $sCurFile & @CRLF )
		; *
		$pCurFile += ( $iCurFileLen * 2 ) + 0x02
	Else
		ExitLoop
	EndIf
WEnd
_ClipBoard_Empty()
_ClipBoard_Close()

MsgBox( 64, "", "Бэкап сделан(буфер очищен). Для возврата данных нажмите ОК" )
; =====================================

_ClipBoard_Open(0)
$iUnicodeArray_TotalLen = 0x01
$sUnicodeArray_TagStrings = ""
For $Idx = 1 To $aFileList[0] Step 1
	$iLen = StringLen( $aFileList[$Idx] )
	
	$iUnicodeArray_TotalLen += ( $iLen * 2 ) + 0x01
	$sUnicodeArray_TagStrings &= "wchar[" & $iLen & "]; byte[1]; "
Next
$sUnicodeArray_TagStrings &= "byte[1];"
; ---

$hMemory = _MemGlobalAlloc( $pFiles + $iUnicodeArray_TotalLen, $GHND )
If $hMemory <> 0 Then
	$hLock = _MemGlobalLock($hMemory)
	If $hLock <> 0 Then
		$tDROPFILES = DllStructCreate( $tagDROPFILES & $sUnicodeArray_TagStrings, $hLock )
			DllStructSetData( $tDROPFILES, "pFiles", $pFiles )
            DllStructSetData( $tDROPFILES, "ptX", $ptX )
            DllStructSetData( $tDROPFILES, "ptY", $ptY )
            DllStructSetData( $tDROPFILES, "fNC", $fNC )
            DllStructSetData( $tDROPFILES, "fWide", $fWide )
			
		For $Idx = 1 To $aFileList[0] Step 1
			DllStructSetData( $tDROPFILES, 6 + ( ( $Idx - 1 ) * 2 ), $aFileList[$Idx] )
		Next
		
		_MemGlobalUnlock( $hMemory )
		_ClipBoard_SetDataEx( $hMemory, $CF_HDROP )
    EndIf
EndIf
_ClipBoard_Close()

MsgBox( 64, "", "HDROP восстановлен!" )


Единственное - pFiles указывает на смещение относительно текущей структуры до списка файлов( и как я понял всегда равен 0x14 ), однако никогда не говори всегда :smile: Мой пример не запишет данные обратно если оно будет отличаться, однако оно лечится парой костыльных условий, которые мне стыдно вводить.

Код:
pFiles=0000000000000014
ptX=0
ptY=0
fNC=0
fWide=1
FileList_UNICODESTR_ARRAY:
C:\Users\Firex\Desktop\555555555555555555.txt
C:\Users\Firex\Desktop\utorrent.exe
 
Автор
mef-t

mef-t

Осваивающий
Сообщения
306
Репутация
30
Еще один момент.
Когда я копирую файл в win Explorer, то если я его вставляю в ту же папку, т.е. туда же, где есть файл с таким названием, то система его вставляет с измененным именем <имя файла - копия.расширение>. Т.е. добавляет значение " - копия". Это реакция именно системы на подобное действие? Связано с тем, что она является владельцем памяти?
И можно ли это же сделать тут?


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

Еще один момент.
Если после копирования удалить файл, то система скажет, что он удален.
Если же удалить файл во время работы программы (после очистки буфера и перед его восстановлением), то система просто ничего не скопирует без каких либо уведомлений. Причина все в том же?
А если присвоить explorer в качестве владельца это будет решено, или нет?
 

firex

AutoIT Гуру
Сообщения
943
Репутация
208
mef-t
Нашел еще один недочет - при запуске скрипта как x64 запись обратно нестабильна, поправил.

Если же удалить файл во время работы программы (после очистки буфера и перед его восстановлением), то система просто ничего не скопирует без каких либо уведомлений.
Мы записываем в буфер лишь адрес файла(сам файл не хранится в буфере), и соответственно если записать несуществующий файл такая реакция вполне возможна. Можно просто перед восстановлением сделать проверку (FileExists) файлов и отсутствующие исключить.

mef-t [?]
Когда я копирую файл в win Explorer, то если я его вставляю в ту же папку, т.е. туда же, где есть файл с таким названием, то система его вставляет с измененным именем <имя файла - копия.расширение>. Т.е. добавляет значение " - копия". Это реакция именно системы на подобное действие? Связано с тем, что она является владельцем памяти?
Вообще без понятия если честно, экспериментировал - ничего не вышло. На msdn подобная проблема не описана...

Вроде все поправил, вот только с последним не знаю что делать:
Код:
#include <Clipboard.au3>
#include <WinAPI.au3>
#include <Array.au3>

Const $tagDROPFILES = "dword pFiles; long ptX; long ptY; bool fNC; bool fWide; "

_ClipBoard_Open(0)
$pDROPFILES = _ClipBoard_GetDataEx( $CF_HDROP )

$tDROPFILES = DllStructCreate( $tagDROPFILES, $pDROPFILES )
    $pFiles = DllStructGetData( $tDROPFILES, "pFiles" )
    $ptX = DllStructGetData( $tDROPFILES, "ptX" )
    $ptY = DllStructGetData( $tDROPFILES, "ptY" )
    $fNC = DllStructGetData( $tDROPFILES, "fNC" )
    $fWide = DllStructGetData( $tDROPFILES, "fWide" )
ConsoleWrite( "pFiles=" & Hex( $pFiles ) & @CRLF & _
    "ptX=" & $ptX & @CRLF & _
    "ptY=" & $ptY & @CRLF & _
    "fNC=" & $fNC & @CRLF & _
    "fWide=" & $fWide & @CRLF & _
    "FileList_UNICODESTR_ARRAY:" & @CRLF )

Local $aFileList[999] = [0], $pCurFile = $pDROPFILES + $pFiles
While 1
    $tFILELIST = DllStructCreate( "wchar[260]", $pCurFile )
        $sCurFile = DllStructGetData( $tFILELIST, 1 )
        $iCurFileLen = StringLen( $sCurFile )

    If $iCurFileLen Then
        $aFileList[0] += 1
        $aFileList[$aFileList[0]] = $sCurFile
        ConsoleWrite( $sCurFile & @CRLF )
        ; *
        $pCurFile += ( $iCurFileLen * 2 ) + 0x02
    Else
        ExitLoop
    EndIf
WEnd
_ClipBoard_Empty()
_ClipBoard_Close()

MsgBox( 64, "", "Бэкап сделан(буфер очищен). Для возврата данных нажмите ОК" )
; =====================================

Do
	For $Idx = 1 To $aFileList[0] Step 1 ;Пропускаем все отсутсвующие файлы...
		If Not FileExists( $aFileList[$Idx] ) Then
			ConsoleWrite( "File( " & $aFileList[$Idx] & " ) not found, skipped..." & @CRLF )
			_ArrayDelete( $aFileList, $Idx )
			$aFileList[0] -= 1
			ContinueLoop 2
		EndIf
	Next
	ExitLoop
Until False

_ClipBoard_Open(0)
$iUnicodeArray_TotalLen = 0x02
$sUnicodeArray_TagStrings = ""
For $Idx = 1 To $aFileList[0] Step 1
    $iLen = StringLen( $aFileList[$Idx] )

	$iUnicodeArray_TotalLen += ( $iLen * 2 ) + 0x02
	$sUnicodeArray_TagStrings &= "wchar[" & $iLen & "]; byte[1]; "
Next
$sUnicodeArray_TagStrings &= "byte[1];"
; ---

$pFiles = 0x14 ;Use only 0x14 (size of $tagDROPFILES)
$hMemory = _MemGlobalAlloc( $pFiles + $iUnicodeArray_TotalLen, $GHND )
If $hMemory <> 0 Then
    $hLock = _MemGlobalLock($hMemory)
    If $hLock <> 0 Then
        $tDROPFILES = DllStructCreate( $tagDROPFILES & $sUnicodeArray_TagStrings, $hLock )
            DllStructSetData( $tDROPFILES, "pFiles", $pFiles )
            DllStructSetData( $tDROPFILES, "ptX", $ptX )
            DllStructSetData( $tDROPFILES, "ptY", $ptY )
            DllStructSetData( $tDROPFILES, "fNC", $fNC )
            DllStructSetData( $tDROPFILES, "fWide", $fWide )

		ConsoleWrite( "Alloc: " & $pFiles + $iUnicodeArray_TotalLen & @CRLF & _
			"Need: " & DllStructGetSize( $tDROPFILES ) & @CRLF )

        For $Idx = 1 To $aFileList[0] Step 1
			DllStructSetData( $tDROPFILES, 6 + ( ( $Idx - 1 ) * 2 ), $aFileList[$Idx] )
        Next

        _MemGlobalUnlock( $hMemory )
        _ClipBoard_SetDataEx( $hMemory, $CF_HDROP )
    EndIf
EndIf
_ClipBoard_Close()

MsgBox( 64, "", "HDROP восстановлен!" )


Код:
pFiles=0000000000000014
ptX=0
ptY=0
fNC=0
fWide=1
FileList_UNICODESTR_ARRAY:
D:\theme.txt
D:\WarZBoT.cfg
D:\Новый текстовый документ.txt
File( D:\theme.txt ) not found, skipped...
File( D:\Новый текстовый документ.txt ) not found, skipped...
Alloc: 52
Need: 52
 
Автор
mef-t

mef-t

Осваивающий
Сообщения
306
Репутация
30
Спасибо.
Буду дальше пробовать.
Чувствую, в скором времени появится тема с вопросом про звуковую дорожку и тому подобное :smile:
 
Верх