Извлечение превьюшек из thumbs.db

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Извлечение превьюшек из thumbs.db

Сообщение pronto » 21.06.2011 (Вт) 10:36

Доброго времени суток, форумчане!
Пытаюсь реализовать сабж, но даже после трёхдневного курения MSDN и других источников так и не получилось. Пока я научился криво извлекать имена Storage'й (или Stream'ов ? Этот момент тоже непонятен). Что делать дальше, чтобы получить данные Stream'ов и сопоставить их с именами файлов в папке, пока не соображу...
Код: Выделить всё
Enum COM_HRESULT
   
   S_OK = 0& ' усё окейжешь
   
   STG_E_INVALIDFUNCTION = &H80030001 ' Indicates that the grfMode is set to STGM_DELETEONRELEASE (StgOpenStorageEx&)
                                      ' Unable to perform requested operation.
   STG_E_FILENOTFOUND = &H80030002  'could not be found.
   STG_E_PATHNOTFOUND = &H80030003 'The path %1 could not be found.
   STG_E_TOOMANYOPENFILES = &H80030004 ' There are insufficient resources to open another file.
   STG_E_ACCESSDENIED = &H80030005 ' Access Denied.
   STG_E_INVALIDHANDLE = &H80030006 ' Attempted an operation on an invalid object.
   STG_E_INSUFFICIENTMEMORY = &H80030008 ' There is insufficient memory available to complete operation.
   STG_E_INVALIDPOINTER = &H80030009 ' Indicates an invalid pointer in the ppObjectOpen parameter (StgOpenStorageEx&)
   STG_E_NOMOREFILES = &H80030012 ' There are no more entries to return.
   STG_E_DISKISWRITEPROTECTED = &H80030013 'Disk is write-protected.
   STG_E_SEEKERROR = &H80030019 'An error occurred during a seek operation.
   STG_E_WRITEFAULT = &H8003001D 'A disk error occurred during a write operation.
   STG_E_READFAULT = &H8003001E 'A disk error occurred during a read operation.
   STG_E_SHAREVIOLATION = &H80030020 ' A share violation has occurred.
   STG_E_LOCKVIOLATION = &H80030021 ' Indicates that access was denied because another caller has the file open and locked
   STG_E_FILEALREADYEXISTS = &H80030050 'already exists.
   STG_E_INVALIDPARAMETER = &H80030057 ' Indicates an invalid value for the grfAttrs, reserved1, reserved2, grfMode, or stgfmt parameters.
                                       ' Can occur if the FILE_FLAG_NO_BUFFERING flag is specified for grfAttrs,
                                       ' but the sector size of the file is not an integer multiple of the sector size of the underlying disk
                                       ' (StgOpenStorageEx&)
   STG_E_MEDIUMFULL = &H80030070 'There is insufficient disk space to complete operation.
   STG_E_PROPSETMISMATCHED = &H800300F0 ' Illegal write of non-simple property to simple property set.
   STG_E_ABNORMALAPIEXIT = &H800300FA 'An API call exited abnormally.
   STG_E_INVALIDHEADER = &H800300FB 'The file %1 is not a valid compound file.
   STG_E_INVALIDNAME = &H800300FC 'Indicates an invalid name in the pwcsName parameter (StgOpenStorageEx&)
   STG_E_UNKNOWN = &H800300FD 'An unexpected error occurred.
   STG_E_UNIMPLEMENTEDFUNCTION = &H800300FE ' That function is not implemented.
   STG_E_INVALIDFLAG = &H800300FF ' Indicates an invalid flag combination in the grfMode pointer;
                                  ' this includes both the STGM_DELETEONRELEASE and STGM_CONVERT flag.
                                  ' (StgOpenStorageEx&)
   STG_E_INUSE = &H80030100 ' Attempted to use an object that is busy.
   STG_E_NOTCURRENT = &H80030101 'The storage has been changed since the last commit.
   STG_E_REVERTED = &H80030102 'Attempted to use an object that has ceased to exist.
   STG_E_CANTSAVE = &H80030103 'Can 't save.
   STG_E_OLDFORMAT = &H80030104 'The compound file %1 was produced with an incompatible version of storage.
   STG_E_OLDDLL = &H80030105 'The compound file %1 was produced with a newer version of storage.
   STG_E_SHAREREQUIRED = &H80030106 'Share.exe or equivalent is required for operation.
   STG_E_NOTFILEBASEDSTORAGE = &H80030107 'Illegal operation called on non-file based storage.
   STG_E_EXTANTMARSHALLINGS = &H80030108 'Illegal operation called on object with extant marshallings.
   STG_E_DOCFILECORRUPT = &H80030109 ' The docfile has been corrupted.
   STG_E_BADBASEADDRESS = &H80030110 ' OLE32.DLL has been loaded at the wrong address.
   STG_E_DOCFILETOOLARGE = &H80030111 'The compound file is too large for the current implementation
   STG_E_NOTSIMPLEFORMAT = &H80030112 'The compound file was not created with the STGM_SIMPLE flag
   STG_E_INCOMPLETE = &H80030201 ' The file download was aborted abnormally. The file is incomplete.
   STG_E_TERMINATED = &H80030202 'The file download has been terminated.
   STG_S_CONVERTED = &H30200    'The underlying file was converted to compound file format.
   STG_S_BLOCK = &H30201    'The storage operation should block until more data is available.
   STG_S_RETRYNOW = &H30202    'The storage operation should retry immediately.
   STG_S_MONITORING = &H30203    'The notified event sink will not influence the storage operation.
   STG_S_MULTIPLEOPENS = &H30204    'Multiple opens prevent consolidated. (commit succeeded).
   STG_S_CONSOLIDATIONFAILED = &H30205    ' Consolidation of the storage file failed. (commit succeeded).
   STG_S_CANNOTCONSOLIDATE = &H30206    'Consolidation of the storage file is inappropriate. (commit succeeded).
   E_NOINTERFACE = &H80004002  ' Indicates that the specified interface is not supported
End Enum

Private Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Private Type STGOPTIONS
   usVersion As Integer
   reserved As Integer
   ulSectorSize As Long
   pwcsTemplateFile As String
End Type

Enum STGFMT
   STGFMT_STORAGE = 0
   STGFMT_FILE = 3
   STGFMT_ANY = 4
   STGFMT_DOCFILE = 5
End Enum

Private Declare Sub RtlMoveMemory Lib "kernel32" _
      (ByVal hpvDest As Long, _
       ByVal hpvSource As Long, _
       ByVal cbCopy As Long)

Private Declare Function IIDFromString Lib "ole32" _
      (ByVal lpszIID As Long, _
       iid As GUID) As Long

Private Declare Function StgOpenStorageEx& Lib "ole32" _
      (ByVal pwcsName As Long, _
       ByVal grfMode As Long, _
       ByVal StgFormat As STGFMT, _
       ByVal grfAttrs As Long, _
       pStgOptions As STGOPTIONS, _
       ByVal reserved As Long, _
       riid As GUID, _
       ppObjectOpen As Any)

Private tsOptions As STGOPTIONS
Private ThumbStorage As IStorage
Private stgDATA As STATSTG
Private StgElement As IEnumSTATSTG '

Private Const IIDSTR_IStorage = "{0000000B-0000-0000-C000-000000000046}"
Private IID_IStorage As GUID

Option Explicit

Private Sub Command1_Click()
     
   Dim RETVAL As Long
   Dim ThumbFilePath As String
   
   ' подготовка параметров
   ThumbFilePath = "D:\Graphics\thumbs.db"
     
   IIDFromString StrPtr(IIDSTR_IStorage), IID_IStorage
   
   tsOptions.usVersion = 1
   tsOptions.ulSectorSize = 512
   
   RETVAL = StgOpenStorageEx(ByVal StrPtr(ThumbFilePath), _
                ByVal STGM_READ Or STGM_SHARE_EXCLUSIVE, _
                ByVal STGFMT_DOCFILE, _
                ByVal 0, _
                tsOptions, _
                ByVal 0, _
                IID_IStorage, _
                ThumbStorage)
   
      If RETVAL = S_OK Then
         Dim tName As String
         tName = Space$(32) ' буфер под имя
         
         Set StgElement = ThumbStorage.EnumElements ' ([0], [0], [0])
                 
         Do
            RETVAL = StgElement.Next(1, stgDATA, 0)
           
            If RETVAL = S_OK Then
               RtlMoveMemory ByVal StrPtr(tName), ByVal stgDATA.pwcsName, ByVal 32
               Debug.Print tName, Hex(stgDATA.cbSize)
            Else
               Exit Do
            End If
         Loop 'While RETVAL = S_OK
         
         Set StgElement = Nothing
         Set ThumbStorage = Nothing

      Else
         Debug.Print "Hex-код ошибки :  " & Hex(RETVAL)
      End If

End Sub


Описание интерфейсов беру в olelib.tlb
O, sancta simplicitas!

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Извлечение превьюшек из thumbs.db

Сообщение FireFenix » 21.06.2011 (Вт) 14:24

Для Вист'ы и выше, существует http://msdn.microsoft.com/en-us/library ... 85%29.aspx
Так же есть http://vinetto.sourceforge.net/ с исходниками на питоне http://vinetto.svn.sourceforge.net/view ... tto/trunk/
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: Извлечение превьюшек из thumbs.db

Сообщение pronto » 21.06.2011 (Вт) 15:06

Спасибо, конечно, но хотелось бы и для XP. Медитировать в программу на Питоне нет никакого резона, так как есть готовый универсальный инструмент и нужно приручить его. Можно грубо отпарсить файл на предмет JFIF сигнатур и не парится... Но нужно сопоставить превьюшку с файлом в папке. В общем, пока я на распутье...
O, sancta simplicitas!

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Извлечение превьюшек из thumbs.db

Сообщение Хакер » 21.06.2011 (Вт) 20:40

pronto писал(а):Этот момент тоже непонятен). Что делать дальше, чтобы получить данные Stream'ов и сопоставить их с именами файлов в папке, пока не соображу.

Это и есть главный вопрос топика?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: Извлечение превьюшек из thumbs.db

Сообщение pronto » 22.06.2011 (Ср) 3:23

В общем-то, да... Но я уже пытался принять tName за имена Stream'ов и открыть поток с таким именем:
Код: Выделить всё
Set ImageStream = ThumbStorage.OpenStream(tName, 0, STGM_READ Or STGM_SHARE_EXCLUSIVE, 0)
ImageStream.Stat imgDATA   ' 'As STATSTG
If imgDATA.pwcsName Then
   tName = Space$(32)
   RtlMoveMemory ByVal StrPtr(tName), ByVal imgDATA.pwcsName, ByVal 32
   Do
      i = i + 1
      If Asc(Mid$(tName, i, 1)) = 0 Then
         tName = Mid$(tName, 1, i - 1)
         i = 0
         Exit Do
      End If
   Loop

End If

Debug.Print tName, CLng(imgDATA.cbSize)

то получаю точно такие же имена, как и после выполнения первой части кода (в пред. посте), и нулевые размеры:
Код: Выделить всё
результат
tName     imgDATA.cbSize
   1              0
   2              0
   3              0
   4              0
   5              0
   6              0
   7              0
   8              0
   9              0
   01             0
   11             0
   21             0
   31             0
   41             0
   Catalog        0
O, sancta simplicitas!

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Извлечение превьюшек из thumbs.db

Сообщение Хакер » 23.06.2011 (Чт) 8:01

pronto писал(а):Но я уже пытался принять tName за имена Stream'ов и открыть поток с таким именем:

Как же меня, блин, даже не то, что раздражает, а пугает и вызывает крайнее непонимание, когда люди находят проблему ну совершенно на ровном месте.

Держи пример:
ThumbnailViewer.zip
Версия 1.0.0
(9.8 Кб) Скачиваний: 225

(olelib.tlb от Edanmo не прилагается, в силу наличия у тебя таковой)

Вот я никогда не работает с Thumbs.db и только сегодня узнал, что это оказывается COM Structured Storage. Но пример был сделан с нуля минут 10—15.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: Извлечение превьюшек из thumbs.db

Сообщение pronto » 23.06.2011 (Чт) 8:45

Хакер, благодарю за помощь! И не пугайся, пожалуйста! :D Для такого Гуру, как ты, нет ничего невозможного, а меня запутала неизвестная структура файла. И то, что имена файлов не являются именами соответствующих потоков...
O, sancta simplicitas!

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Извлечение превьюшек из thumbs.db

Сообщение Хакер » 23.06.2011 (Чт) 8:49

pronto писал(а):Для такого Гуру, как ты, нет ничего невозможного, а меня запутала неизвестная структура файла. И то, что имена файлов не являются именами соответствующих потоков...

Ну да, открыть википедию и прочитать, что там есть стрим с именем «Catalog» — это, конечно, надо быть таким гуру как я...
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

pronto
Постоялец
Постоялец
 
Сообщения: 597
Зарегистрирован: 04.12.2005 (Вс) 6:20
Откуда: Владивосток

Re: Извлечение превьюшек из thumbs.db

Сообщение pronto » 23.06.2011 (Чт) 9:08

На Вики кривая не вывела, делал упор на MSDN... Буду извлекать урок из этого — что на задачу надо смотреть со всех сторон.
O, sancta simplicitas!

ark
Бывалый
Бывалый
 
Сообщения: 216
Зарегистрирован: 18.07.2011 (Пн) 0:57

Re: Извлечение превьюшек из thumbs.db

Сообщение ark » 18.07.2011 (Пн) 2:22

Не всё так просто
Вообще-то я парсил STG врукопашную, не люблю пользовать чужие либы, даже от самого Morcillo. Зато получил массу удовольствия - это ж надо, для файлов размером в несколько КБ придумать собственную внутреннюю файловую систему! Тот же FAT, только круче. Вместо одной таблицы целых три - MSAT, SAT и SSAT. Кстати, по конфигурации размер файла возможен до 2 ТБ - узнаю мелкомягкий размах :)
Теперь к тумбам. Подробные структуры:
Код: Выделить всё
Public Type CatalogHeader
   cbBytes      As Integer ' размер хедера - 0х10
   wVersion     As Integer ' версия тумба (6 или 7)
   ThumbsCount  As Long
   ThumbWidth   As Long
   ThumbHeight  As Long
End Type
Public Type CatalogItem
   ItemSize     As Long ' размер, т.е. 16 + длина_имени*2 (имя в юникоде, более того, в UTF-16, еще более длина имени может быть до 1ГБ - MS в своем репертуаре)
   ItemID       As Long ' нужен для связи со стримами изображений - имя стрима - перевернутая строка ID, ID=123, стрим - 321 (возможно, когда нибудь MS раскроет тайный смысл)
   Created      As FILETIME
   strFileName  As String
End Type
Public Type IMAGE_STREAM_HEADER
   cbSize As Long ' размер хедера (12 для версии 6 и 7, 24 для 3)
   Version As Long ' версия картинки 3 или 1 (для 6 или 7 версий тумбов)
   streamSize As Long ' от конца хедера до конца стрима
End Type

Public Type V6_Header
   Unknown As Long 'всегда==1
   ImageStreamSize As Long ' от конца хедера до конца стрима
   ImgWidth As Long ' в отличие от каталога, размер именно картинки, а не тумба
   ImgHeight As Long
End Type

Public Type ImageStreamV6
   stmHeader As IMAGE_STREAM_HEADER
   v6Hdr As V6_Header
   ImgData() As Byte 'MS_PEG (?) stream
End Type

Public Type ImageStreamV7
   stmHeader As IMAGE_STREAM_HEADER
   ImgData() As Byte  ' JPEG stream
End Type

По части изображений: приведенный пример позволяет читать только тумбы версии 7 (созданные эксплорером в ХР/2003, vinetto называет их ver. 2)
Я обнаружил, по крайней мере, еще 2 версии.
1. Условно, версия 3 - создается, по видимому, акробатом. Размеры тумбов 256х256 (в отличие от виндовских 96х96). Не имеет каталога. Имена стримов типа 256_ХХХХХХ - где ХХХХХ - по виду случайный GUID. Хедер стрима - 24 байта, первые 12 как у 7, 12-16 - всегда 1, 16-24 дата/время (FILETIME) Дальше, как и в 7-й версии, стандартный JPEG-овский стрим.
2. Версия 6 (эксплорер 98/МЕ/NT3.5/4/2000) - очередной мелкомягкий изврат. Каталог есть. Хедер изображения описан выше. Кроме 12 стандартных байт ещё 16. Сам стрим от стандартного JPEG-овского отличается следующим: отсутствуют Хаффмановские таблицы (подходят стандартные для яркости из спецификации JPEG), отсутствует таблица квантизации (подходит стандартная для яркости, только коэффициенты надо разделить на 2 и расставить зигзагом). В принципе, полученный стрим (с добавленным JFIF хедером и таблицами) можно было бы скормить любому декодеру (OLE в том числе, как в примере выше). Но! Дальше вообще упражнение для мазохистов. Стрим состоит из 4-х компонентов. На JPEG-диалекте это звучит CMYK, на мелкомягком - RGBA. В силу того, что прозрачность (А) никогда не используется, компонент №4 всегда FF. Но все декодеры (в том числе и родные MS) читают его как blac(K) - поэтому на выходе получаем черный прямоугольник Малевича. Единственный декодер, который это понимает - freeimage.dll с флагом FILO_JPEG_CMYK. В рукопашную есть 2 пути
а) - писАть свой джпег-декодер на VB
б) - выполнив а) (что я и сделал) и разобравшись со структурой джпега, сделать следующий финт: добавляем пустую (все нули) таблицу квантизации с №1 (первая имеет №0). Назначаем эту таблицу четвертому компоненту (меняем байт №51 в стриме тумба с 0 на 1) и подсовываем любому декодеру. Кто знаком с деджипигизацией, поймет, что четвертый компонент все равно будет не 0 а 127 (обратные преобразования косинусов используют знаковые байты). Но убрать серую маску имея GDI+ и ColorMatrix - плевое дело. Меняем красный на синий, умножаем цвета на 2.5 и сдвигаем на 0.2 взад. Да, не забудьте перевернуть картинку вертикально.
На всякий случай, матрица финального преобразования:
Код: Выделить всё
With clrMatrix
      .m(0, 2) = 2.5
      .m(1, 1) = 2.5
      .m(2, 0) = 2.5
      .m(3, 3) = 1
      .m(4, 4) = 1
      .m(0, 4) = -0.2
      .m(1, 4) = -0.2
      .m(2, 4) = -0.2
   End With

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Извлечение превьюшек из thumbs.db

Сообщение Хакер » 18.07.2011 (Пн) 9:24

ark писал(а):Не всё так просто
Вообще-то я парсил STG врукопашную, не люблю пользовать чужие либы, даже от самого Morcillo. Зато получил массу удовольствия - это ж надо, для файлов размером в несколько КБ придумать собственную внутреннюю файловую систему! Тот же FAT, только круче

Гиперидиотизм.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ark
Бывалый
Бывалый
 
Сообщения: 216
Зарегистрирован: 18.07.2011 (Пн) 0:57

Re: Извлечение превьюшек из thumbs.db

Сообщение ark » 18.07.2011 (Пн) 9:45

Содержательно
Главное, по теме


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 58

    TopList