|
| | | |
V.3. Inne - ६ㄙҚ ਸ • Windows Recycle Bin i plik Info2 •
- 3.1 Jak z pliku tekstowego wygenerowanego przez program Cards4Labs do odczytu kart SIM wyodrębnić dane i przedstawić najważniejsze z nich za pomocą Html'u ?
- 3.2 Jak wylistować pliki w folderze głównym i podfolderach oraz ... ?
- 3.3 Windows Recycle Bin - Gdzie i jak system Windows przechowuje informacje o usuniętych plikach ?
- 3.4 Jak zrobić miniatury (thumbsy) plików graficznych i dołączyć je do listy właściwości plików znajdujących się w folderze i podfolderach. ?
-

- 3.6 Jakie dane zawierają pliki logów programu Skype ?
- 3.7 Jak pobrać i przekonwertować znacznik czasu (TimeStamp) programu Skype na DateTime systemu Windows ?
- 3.8 Jak pobrać dane dotyczące historii czatów, zapisane przez program Skype w plikach chatmsg.dbb i chatmember.dbb ?
- 3.9 Jak pobrać dane dotyczące historii rozmów telefonicznych, zapisane przez program Skype w plikach call.dbb i callmember.dbb ?
| | | | |
|
| | |
|
3.1 Jak z pliku tekstowego wygenerowanego przez program Cards4Labs do odczytu kart SIM wyodrębnić dane i przedstawić najważniejsze z nich za pomocą Html'u ?
Ta naprawdę, to prawie całe zagadnienie sprowadza się do wczytania całej zawartości pliku tekstowego (raportu wygenerowanego przez program Cards4Labs) do zmiennej i rozdzielenie tekstu w/m charakterystycznych zwrotów, bądź tekstu całej linii, następnie należy odczytć dane i przekonwertowć je na kod Html.
Problem pojawia się, gdy tekst wiadomości kodowany jest w UCS-2, (jest to 16-bitowe kodowanie znaków Unicode, gdzie każdy znak zapisany jest za pomocą 2 bajtów).

Przykładowy fragment danych:
Data coding scheme | : 0x08 • oznaczenie schematu kodowania |
Group | : General data coding |
Meaning | : Class 0, UCS2 alphabet |
Service centre timestamp | : 24-12-07 15:30:43 GMT+01 |
User data length | : 88 • nie zawsze długość danych jest prawidłowo podawana ! |
User data | : |
0 - 15 | 00 57 00 65 00 73 00 6f 01 42 00 79 00 63 00 68 | .W.e.s.o.B.y.c.h |
16 - 31 | 00 20 01 5b 00 77 00 69 01 05 00 74 00 20 00 64 | . .[.w.i...t. .d |
32 - 47 | 00 6c 00 61 00 20 00 43 00 69 00 65 00 62 00 69 | .l.a. .C.i.e.b.i |
48 - 63 | 00 65 00 20 00 69 00 20 00 54 00 77 00 6f 00 69 | .e. .i. .T.w.o.i |
64 - 79 | 00 63 00 68 00 20 00 62 00 6c 00 69 00 73 00 6b | .c.h. .b.l.i.s.k |
80 - 87 | 00 69 00 63 00 68 00 2e | .i.c.h.. |

Po wczytaniu poszczególne linii rekordu User data do tablicy aLin(0),
Dim aLin(0 To 5) As String
aLin(0) = | " 0 - 15 | 00 57 00 65 00 73 00 6f 01 42 00 79 00 63 00 68 | .W.e.s.o.B.y.c.h | " |
aLin(...) = | ".......... | .......... | .......... | " |
aLin(5) = | " 80 - 87 | 00 69 00 63 00 68 00 2e | .i.c.h.. | " |
możemy wyodrębnić znaki reprezentujące zakodowany tekst wiadomości (w zapisie szesnastkowym) w poniższy sposób:
Dim sLastLine As String
Dim lDelta As Long
Dim sHex As String
Dim lUB As Long
Dim i As Long
Const MY_START_POS As Long = 16
Const MY_CHARS_IN_LINE As Long = 3 * MY_START_POS
lUB = UBound(aLin)
' pobierz ostatnią linię rekordu i usuń końcowe spacje
sLastLine = RTrim$(Mid$(aLin(lUB), MY_START_POS, MY_CHARS_IN_LINE)) & " "
' oblicz ile było pustych spacji na końcu ostatniej linii
lDelta = MY_CHARS_IN_LINE - Len(sLastLine)
' przygotuj ciąg wyściowy
sHex = Space((lUB + 1) * MY_CHARS_IN_LINE - lDelta)
For i = 0 To lUB - 1
Mid$(sHex, i * MY_CHARS_IN_LINE + 1, _
MY_CHARS_IN_LINE) = _
Mid$(aLin(i), MY_START_POS, _
MY_CHARS_IN_LINE)
Next
' dopisz ostatnią linię
Mid$(sHex, lUB * MY_CHARS_IN_LINE + 1, _
Len(sLastLine)) = sLastLine
mając wyodrębniony ciąg znaków sHex korzystamy z funkcji zbUCS2Win_Mid opisanej w przykładzie: 4.23 Jak przekonwertować tekst Unicode (UCS-2) w zapisie szesnastkowym (każdy bajt rozdzielony jest znakiem spacji) na tekst ANSI ?
ΔΔΔ | | | | |
|
| | |
|
3.2 Jak wylistować pliki w folderze głównym i podfolderach oraz ... ?
Możemy to zrobić wywołując komendę DIR w oknie poleceń za pomocą funkcji Shell(...)

' przykładowe wywołanie:
Private Sub btnTest_Click()
Call zbDirToFile("C:\PlikiTest", "C:\~Dir2File.txt", "*")
End Sub

Public Sub zbDirToFile(sFolderName As String, _
sDestFilePath As String, _
sMask As String, _
Optional fSubFolders As Boolean = True)
Dim sCmdLine As String
' wywołaj polecenie DIR i przekieruj strumień
' do pliku sDestFilePath
sCmdLine = Environ$("COMSPEC") & " /c Dir " & """" & _
IIf(Right$(sFolderName, 1) = "\", sFolderName, _
sFolderName & "\") & sMask & """" & " /A /B " & _
IIf(fSubFolders, "/S", "") & " > " & sDestFilePath
Call Shell(sCmdLine, vbHide)
' zmienna sCmdLine będzie miała w tym przypadku postać:
' C:\WINDOWS\system32\cmd.exe /c DIR "C:\PlikiTest\" /A /B /S > C:\~Dir2File.txt
' co praktycznie sprowadza się do wpisania w oknie poleceń komendy:
' DIR C:\PlikiTest\ /A /B /S > C:\~Dir2File.txt
End Sub

Otrzymujemy wynikowy plik C:\~Dir2File.txt w którym w każdej linii zapisana jest pełna nazwa pliku. Niestety komenda DIR zwraca tekst w stronie kodowej IBM-852, więc musimy go przekonwertować za pomocą funkcji zbCP1ToCP2 na stronę kodową Windows 1250.
Musimy pamiętać również, że funkcja Shell wywołująca komendę DIR jest asynchroniczna, więc raczej powinniśmy użyć wywołania synchronicznego zbShellSynchroWin
Komenda DIR nie zawsze zwraca prawidłowo nazwy plików np.
C:\PlikiTest\Procesor Intel® Core™2 Duo.url
błędnie zwraca jako
C:\PlikiTest\Procesor IntelR Coret2 Duo.url
W wykazie plików będzie figurował także docelowy plik C:\~Dir2File.txt, do którego przekierowywany jest strumień z komendy DIR.
Aby nie pisać po dysku (nie tworzyć pliku) możemy spróbować odczytać dane bezpośrednio z okna poleceń. Sposób ten został przedstawiony w przykładzie:
Jak odczytać tekst z okna poleceń MS-DOS (konsoli) ?
• Moim zdaniem używanie polecenia DIR do listowania plików na dysku nie jest najlepszym rozwiązaniem. Raczej nie uzyskamy pełnej listy plików z ich prawidłowymi nazwami. Występują jeszcze dodatkowe ograniczenia, ale o nich w następnym przykładzie.

Korzystając z przykładów • Jak pobrać pełne ścieżki do wszystkich podfolderów znajdujących się w folderze ? • oraz
• Jak pobrać (zapisać w tabeli) pełne ścieżki wszystkich plików znajdujących się w folderze (również w podfolderach) ? •
spróbujmy odpowiedzieć ponownie na pytanie (rozszerzjąc trochę zakres pytania):
I to przykładowe rozwiązanie nie jest pozbawione wad. Przy próbie wylistowania zawartości folderu zawierającego w nazwie znaki Unicode wyświetlany jest komunikat: "Błąd odczytu folderu: przykładowo D:\V6(????????)\" gdzie w miejscu znaków Unikodu (一卡多号操作手册) występują najczęściej znaki zapytania. Także w wynikach przeszukiwania folderu o prawidłowej nazwie nie są uwzględniane podfoldery zawierające znaki Unikodowe, a tym samym pomijane są wszystkie tam znajdujące się pliki.
Z dołączonego do przykładu folderu testowego "PlikiTest" zostanie wylistowanych 15 zamiast 20-tu tam się znajdujących plików. Nazwy dwóch plików będą błędnie wyświetlone: w pierwszej nazwie pliku będziemy mieli same ??????, a w przypadku drugiego pliku zamiast Ola作手ma册kota.txt zobaczymy Ola??ma?kota.txt
Aby wylistować wszystkie pliki możemy skorzystać z funkcji zbListFilesFSO korzystajacej z obiektu FileSystemObject z Windows Scripting Host. Metoda ta jest jednak ok. 8 do 10 razy wolniejsza od metody wykorzystującej API. Co prawda uzyskamy listę zawierająca nazwy 20-tu plików, ale z błędnie wyświetlonymi nazwami plików zawierających znaki Unikodu.
• Jedyna zaletą tego przykładu jest możliwość wylistowania plików i pobrania ich właściwości w starszych, nie obsługujących Unikodu, systemach Windows.
ΔΔΔ | | | | |
|
| | |
|
3.3 Windows Recycle Bin - Gdzie i jak system Windows przechowuje informacje o usuniętych plikach ?
1. Gdzie system Windows przechowuje informacje o usuniętych plikach ?
Informacje na ten temat można pobrać u „źródeł” tzn. na oficjalnej stronie Microsoft'u patrz. W jaki sposób Kosz przechowuje pliki ? Poniżej krótkie streszczenie artykułu rozszerzone o moje własne spostrzeżenia.
Kiedy w normalny sposób tzn. poprzez zaznaczenie pliku (folderu) i bez wciśniętego klawisza Shift usuwamy plik (folder) z dysku, to fizycznie ten plik (folder) nie jest usuwany, lecz zostaje przeniesiony do systemowego Kosza znajdującego się na dysku, na którym zlokalizowany jest usuwany plik (folder). Informacja o usuniętym pliku (folderze) zapisywana jest w pliku Info2 znajdującym się w Koszu.
Lokalizacja pliku Info2 w systemowym folderze Kosz |
System operacyjny | System plików | Ścieżka |
Windows 98/Me/XP | FAT32 | ?:\Recycled\Info2 |
Windows NT/2000/XP | NTFS | ?:\Recycler\<SID>\Info2 |
gdzie:
Po przeniesieniu pliku (folderu) do Kosza jego nazwa zmieniana jest na nową nazwę w/g schematu: [D] [?] [#] [.ext]
gdzie:
D - pierwszy znak - zawsze litera D,
? - drugi znak - literowe oznaczenie dysku, z którego usunięto plik (folder),
# - trzeci i następne - przyrostowo generowany liczbowy identyfikator,
.ext - rozszerzenie
Trzy pierwsze elementy nazwy występują zawsze, czwarty element ( rozszerzenie) występuje jedynie wtedy, gdy nazwa usuniętego pliku (folderu) zawiera kropkę. Jest to ciąg znaków, który znajduje się za ostatnią kropką w nazwie pliku (folderu).
Jeżeli usuwany folder zawiera podfoldery i pliki, to nazwy podfolderów i plików wewnątrz folderu nie są zmieniane. Folder jest w całości wraz z zawartością przenoszony do Kosza i zmieniana jest tylko jego nazwa w/g opisanego już schematu.
2. Jaka jest struktura pliku Info2 ?
Informacje o strukturze pliku Info2 dostępne w Internecie można praktycznie ograniczyć do poniższych dwóch adresów:
- http://www.e-fense.com/helix/Docs/Recycler_Bin_Record_Reconstruction.pdf - Forensic Analysis of Microsoft Windows Recycle Bin Records
autor: Keith Jones - Computer Forensics Manager. - Link już nieaktualny !
- INFO2 RECYCLE BIN file - A PRIMER
autor: Steve Hailey - CyberSecurity Institute
Z artykułów tych wynika, że plik Info2 zawiera 16-bajtowy nagłówek, w którym cztery ostatnie bajty (0x00 00 03 20) określają wielkość rekordu zawierającego dane o usuniętym pliku (folderze).
Wielkość tego rekordu równa jest 800 bajtów (dziesiętnie), tak więc pierwszy rekord zaczyna się od 17 bajtu, a kończy na 816 bajcie.
Wynika z tego, że w rekordzie 4 pierwsze bajty zawierają bliżej nieokreślone informacje, a nazwa ASCII usuniętego pliku (folderu) zaczyna się od 5 bajtu rekordu.
2.1. Nagłówek pliku Info2
Moim zdaniem na początku pliku Info2 znajduje się 20-bajtowy nagłówek, którego zawartość można opisać za pomocą poniższej struktury:
Private Type INFO2_HEADER
Version As Long
RemovedObjects As Long
LastIndex As Long
RecordSize As Long
OccupiedSpace As Long
End Type
gdzie:
- Version - najprawdopodobniej nr wersji, zazwyczaj równy 0x00 00 00 05, w starszej wersji równy 0x00 00 00 04,
- RemovedObjects - ilość usuniętych plików i folderów w Koszu, które zostały oznaczone wg schematu [D] [?] [#] [.ext]
- LastIndex - ostatni najwyższy indeks, który został wykorzystany do oznaczenia pliku (folderu) w Koszu,
- RecordSize - wielkość w bajtach rekordu zawierającego dane o usuniętym pliku (folderze), wynosi 0 x 00 00 30 20, czyli (dziesiętnie) 800 bajtów, lub 0 x 00 00 01 18, czyli (dziesiętnie) 280 bajtów,
- OccupiedSpace - sumaryczna wielkość w bajtach wszystkich plików w Koszu (także tych znajdujących się w folderach i podfolderach),
W trakcie pracy systemu Windows elementy struktury INFO2_HEADER takie jak RemovedObjects, LastIndex, OccupiedSpace nie są aktualizowane podczas operacji usuwania lub przywracania plików i folderów.
Elementy te są aktualizowane podczas wybrania przez użytkownika w menu Start polecenia Wyloguj lub polecenie Zamknij system. Anulowanie wybranego polecenia nie wstrzymuje aktualizacji pliku Info2.
Jeżeli system zostanie zamknięty nieprawidłowo (reset komputera, zanik napięcia) to plik Info2 nie zostaje zaktualizowany.
Podczas startu systemu plik ten także nie jest aktualizowany, ale podczas usuwania pliku (folderu) system zna prawidłowy indeks dla usuwanego pliku (folderu).
Nagłówek w trakcie pracy systemu zostanie zmieniony także wtedy, gdy użytkownik uruchomi polecenie
"Opróżnij Kosz" z menu podręcznego, lub z menu Plik. Wtedy wszystkie pliki (foldery) są usuwane z Kosza, a plik Info2 jest
resetowany tzn. z całego pliku Info2 pozostaje tylko 20-bajtowy nagłówek z domyślnymi wartościami dla
Wersion = 0x00 00 00 05 oraz RecordSize = 0 x 00 00 30 20,
pozostałe elementy struktury nagłówka zostają wyzerowane. Ale w trakcie wylogowywania się użytkownika lub zamykania systemu
element struktury LastIndex zostanie nadpisany aktualną (pamiętaną) przez system wartością indeksu.
2.2. Rekord w pliku Info2
Za 20-bajtowym nagłówkiem pliku znajdują się zazwyczaj 800-bajtowe rekordy zawierające informacje o kolejno usuwanych plikach (folderach). Pierwszy rekord zaczyna się od 21 bajtu, a kończy na 820 bajcie. Dalej, aż do końca pliku, co 800 bajtów zapisane są kolejne rekordy. Strukturę 800-bajtowego rekordu, możemy przedstawić następująco:
Private Type INFO2_RECORD_W
FilePathA As String * 260
FileIndex As Long
DriveIndex As Long
ftRemoved As FILETIME
BytesCluster As Long
FilePathW As String * 520
End Type
gdzie:
- FilePathA - oryginalna nazwa usuniętego pliku (folderu) zapisana w wersji ASCII (maksymalnie 259 znaków),
- FileIndex - przyrostowo generowany indeks usuniętego pliku (folderu), odpowiada identyfikatorowi # w nazwie pliku (folderu) w Koszu,
- DriveIndex - liczbowy odpowiednik litery dysku, z którego usunięty został plik (folder) zgodnie ze schematem 1 => a, 2 => b, 3 => c itd. Odpowiada on drugiej literze w nazwie pliku (folderu) w Koszu,
- ftRemoved - data i czas usunięcia pliku (folderu) zapisana w 64-bitowej strukturze FILETIME (patrz FILETIME Structure) określająca ilość 100 nanosekundowych okresów, które upłynęły od 1 stycznia 1601 roku.
Strukturę tę możemy zadeklarować następująco:
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
- BytesCluster - liczba określająca ilość bajtów zajętych przez klastry, które zajmuje na dysku usunięty plik (folder),
- FilePathW - oryginalna nazwa usuniętego pliku (folderu) zapisana w Unicode (maksymalnie 259 szerokich znaków),
Rekord może być mniejszy i zawierać tylko 280 bajtów. Różnica wielkości wynika z braku w takim rekordzie obszaru, odpowiadającego zmiennej FilePathW o długości 520 bajtów, zawierającego oryginalną lokalizację pliku w wersji Unicode. W takim przypadku pierwszy rekord będzie zaczynał się od 21 bajtu, a kończył na 300 bajcie.
Strukturę takiego rekordu, możemy przedstawić następująco:
Private Type INFO2_RECORD_A
FilePathA As String * 260
FileIndex As Long
DriveIndex As Long
ftRemoved As FILETIME
BytesCluster As Long
' FilePathW As String * 520
End Type
gdzie poszczególne składowe są takie same jak w strukturze INFO2_RECORD_W.
2.3. Zawartość Kosza, a zmiany w rekordach w pliku Info2 ?
- Gdy w trakcie usuwania plików (folderów) do Kosza przekroczony zostanie limit miejsca w Koszu (określony we właściwościach Maksymalny rozmiar Kosza) to znajdujące się już w Koszu pliki (foldery) są usuwane, a na zwolnione miejsce przenoszone są nowsze pliki (foldery). W pliku Info2 w rekordzie odpowiadającemu usuwanemu z Kosza plikowi pierwszy znak (oznaczenie literowe dysku) pełnej ścieżki pierwotnej lokalizacji pliku (zapisanej w ASCII) zostaje nadpisany znakiem vbNullChar.
- Taka sama operacja nadpisania pierwszego znaku w elemencie FilePathA struktury INFO2_RECORD zostanie wykonana,
jeżeli w systemowym Koszu zaznaczymy pliki (foldery) i uruchomimy polecenie "Przywróć" z menu podręcznego, lub z menu Plik, albo zaznaczone obiekty usuniemy klawiszem DELETE, bądź przeciągniemy i opuścimy te obiekty do innej lokalizacji.
Praktycznie, w każdym przypadku usunięcia (przeniesienia) plików i folderów z systemowego Kosza, w pliku Info2 w odpowiadających tym plikom (folderom) rekordach, pierwszy znak (oznaczenie literowe dysku) pełnej ścieżki pierwotnej lokalizacji pliku (zapisanej w ASCII) zostanie nadpisany znakiem vbNullChar.
- Jeżeli użytkownik uruchomi polecenie "Opróżnij Kosz" z menu podręcznego, lub z menu Plik to wtedy wszystkie pliki i foldery zostają usunięte z Kosza, a z pliku Info2 pozostanie jedynie 20 bajtów zresetowanego nagłówka pliku bez jakichkolwiek rekordów.
- Można powiedzieć, że w pliku Info2 znajduje się (w pewnym, dość ograniczonym zakresie) historia usuwania i przywracania plików. Historia ta jest mocno ulotna i dość nieprecyzyjna, ale czasami jej znajomość może przynieść korzyści.
3. Jak pobrać dane z pliku Info2 ?
3.1 Deklaracje niezbędnych funkcji API, struktur oraz pomocnicza funkcja konwertująca:
Private Declare Function FileTimeToSystemTime _
Lib "kernel32" _
(lpFileTime As FILETIME, _
lpSystemTime As SYSTEMTIME) As Long
Private Declare Function FileTimeToLocalFileTime _
Lib "kernel32" _
(lpFileTime As FILETIME, _
lpLocalFileTime As FILETIME) As Long
Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As Long)
Private Declare Function lstrlen Lib "kernel32" _
Alias "lstrlenW" _
(ByVal lpString As String) As Long
Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type INFO2_HEADER
Version As Long
RemovedObjects As Long
LastIndex As Long
RecordSize As Long
OccupiedSpace As Long
End Type
Private Type INFO2_RECORD_A
FilePathA As String * 260
FileIndex As Long
DriveIndex As Long
ftRemoved As FILETIME
BytesCluster As Long
End Type
Private Type INFO2_RECORD_W
FilePathA As String * 260
FileIndex As Long
DriveIndex As Long
ftRemoved As FILETIME
BytesCluster As Long
FilePathW As String * 520
End Type
' pomocnicza funkcja konwertującą strukturę FILETIME na datę
Private Function zbConvertFiletimeToDate( _
ft As FILETIME) As Date
Dim ftLocal As FILETIME
Dim st As SYSTEMTIME
' konwertuj czas do lokalnej strefy czasowej
FileTimeToLocalFileTime ft, ftLocal
' konwertuj czas do formatu SYSTEMTIME
FileTimeToSystemTime ftLocal, st
' konwertuj elementy struktury SYSTEMTIME na datę
zbConvertFiletimeToDate = CDate( _
CDbl(DateSerial( _
st.wYear, st.wMonth, st.wDay)) + _
CDbl(TimeSerial( _
st.wHour, st.wMinute, st.wSecond)))
End Function
' 3.2 Deklaracje zmiennych i stałych w funkcji czytającej dane z pliku Info2:
Private Function zbReadDataFromInfo2( _
sPathInfo2A As String) As Long
Dim ifH As INFO2_HEADER | ' struktura nagłówka pliku Info2 |
Dim ifRA As INFO2_RECORD_A | ' struktura rekordu pliku Info2 (tylko ASCII) |
Dim ifRW As INFO2_RECORD_W | ' struktura rekordu pliku Info2 (ASCII + Unicode) |
Dim sFilePathA As String | ' pomocnicza zmienna dla ASCII |
Dim sFilePathW As String | ' pomocnicza zmienna dla Unicode |
Dim sPathRecycledA As String | ' ścieżka folderu, w którym znajduje się plik Info2 |
Dim sNameInRecycledA As String | ' nazwa pliku (folderu) w Koszu |
Dim sExtA As String | ' ciąg znaków (ASCII) występujący po kropce |
Dim fExistInRecycled As Boolean | ' czy plik (folder) istnieje fizycznie w Koszu |
Dim fIsDirectory As Boolean | ' czy obiekt jest folderem, czy plikiem |
Dim lInStr As Long | ' położenie szukanego ciągu w innym ciągu |
Dim ff As Integer | ' uchwyt pliku |
Dim i As Long | ' licznik |
Const MY_ATTRIB As Integer = vbSystem + vbHidden + vbReadOnly + vbArchive | ' pełny atrybut pliku (folderu) |
Const SIZE_HEADER As Long = 20 | ' wielkość nagłówka pliku Info2 |
Const SIZE_RECORD_A As Long = 280 | ' wielkość rekordu w pliku Info2 (tylko ASCII) |
Const SIZE_RECORD_W As Long = 800 | ' wielkość rekordu w pliku Info2 (ASCII + Unicode) |
' 3.3 Instrukcje sprawdzające:
' sprawdzana jest poprawność lokalizacji pliku Info2, wielkość nagłówka i wielkość rekordu oraz przedstawione są dane startowe zawarte w nagłówku pliku, do późniejszego wykorzystania pobierana jest ścieżka folderu z plikiem Info2
' 3.3.1. Sprawdź, czy plik Info2 istnieje na dysku
If Len(Dir(sPathInfo2A, MY_ATTRIB)) = 0 Then
Debug.Print "Plik " & sPathInfo2A & " nie istnieje na dysku !"
Exit Function
End If
' 3.3.2. Sprawdź przed otwarciem pliku, czy nagłówek ma prawidłową wielkość
If FileLen(sPathInfo2A) < SIZE_HEADER Then
Debug.Print "Plik " & sPathInfo2A & " jest zbyt mały !"
Exit Function
End If
' 3.3.3. Pobierz nagłówek pliku do struktury INFO2_HEADER
' pobierz wolny numer pliku
ff = FreeFile
' otwórz plik Info2 do odczytu w trybie binarnym
Open sPathInfo2A For Binary Access Read As #ff
' wczytaj nagłówek pliku Info2 do struktury INFO2_HEADER
Get #ff, , ifH
' 3.3.4. Sprawdź wielkość rekordu
If (ifH.RecordSize <> SIZE_RECORD_W) And _
(ifH.RecordSize <> SIZE_RECORD_A) Then
Debug.Print "Procedura obsługuje jedynie " & _
"rekordy 280- lub 800-bajtowe !"
Close #ff
Exit Function
Else
Debug.Print "[RecordSize] - Wielkośc rekordu:", , _
ifH.RecordSize
End If
' 3.3.5. Dane startowe dla Kosza zapisane w nagłówku pliku Info2
Debug.Print "[RemovedObjects] - Usuniętych obiektów:", , _
ifH.RemovedObjects
Debug.Print "[LastIndex] - Ostatni numer obiektu:", , _
ifH.LastIndex
Debug.Print "[OccupiedSpace] - Zajęte miejsce w Koszu:", , _
ifH.OccupiedSpace
Debug.Print String(30, "="); " Koniec nagłówka pliku "; _
String(50, "=")
' 3.3.6. Pobierz (do późniejszego wykorzystania) ścieżkę folderu, w którym znajduje się plik Info2
Do
lInStr = i
i = InStr(i + 1, sPathInfo2A, "\", vbBinaryCompare)
Loop Until i = 0
If lInStr > 0 Then sPathRecycledA = Left$(sPathInfo2A, lInStr)
' 3.4 Analiza rekordów w pliku Info2:
' 3.4.1. Informacje, które są zapisane w poszczególnych rekordach (z uwzględnieniem wielkości rekordu) •
Do
If ifH.RecordSize = SIZE_RECORD_A Then
' pobierz rekord (280-bajtowy) do struktury INFO2_RECORD_A
Get #ff, , ifRA
' przekopiuj 280 bajtów struktury SIZE_RECORD_A do INFO2_RECORD_W
CopyMemory ifRW, ifRA, SIZE_RECORD_A
Else
' pobierz rekord (800-bajtowy) do struktury INFO2_RECORD_W
Get #ff, , ifRW
End If
' jeżeli został osiągnięty koniec pliku, to wyjdź z pętli Do
If EOF(ff) Then Exit Do
' analizuj zawartość pobranego rekordu
With ifRW
' [FilePathA] - oryginalna lokalizacja pliku (wersja ASCII),
' sprawdź, czy pierwszy znak nie został usunięty
lInStr = InStr(1, .FilePathA, vbNullChar)
If lInStr = 1 Then
Debug.Print "[FilePathA] - Plik przywrócony do" & _
" pierwotnej lokalizacji, " & _
" lub usunięty z Kosza " & _
"z powodu braku miejsca !"
' szukaj końca ciągu pierwotnej lokalizacji pliku (folderu)
lInStr = InStr(2, .FilePathA, vbNullChar)
' odtwórz pełną nazwę lokalizacji pliku (folderu)
sFilePathA = Chr$(Asc("A") + .DriveIndex) & _
Mid$(ifRA.FilePathA, 2, lInStr - 2)
Else
sFilePathA = Left$(.FilePathA, lInStr - 1)
Debug.Print "[FilePathA] - " & _
"Oryginalna lokalizacja (ASCII):", _
sFilePathA
End If
If ifH.RecordSize = SIZE_RECORD_A Then
' dla 280-bajtowego rekordu uzupełnij w strukturze
' INFO2_RECORD_W brakujący Unikodowy
' element lokalizacji pliku
.FilePathW = StrConv(Chr$(Asc("A") + _
.DriveIndex) & _
Mid$(ifRA.FilePathA, 2), vbUnicode)
End If
' [FileIndex] - liczbowy indeks usuniętego pliku (folderu),
Debug.Print "[FileIndex] - Indeks pliku:", , , .FileIndex
' [DriveIndex] - liczbowy odpowiednik litery dysku z którego usunięto plik (folder),
' indeks ten możemy przekonwertować na oznaczenie literowe w poniższy sposób:
Debug.Print "[DriveIndex] - " & _
"Oznaczenie literowe napędu:", _
Chr$(Asc("A") + .DriveIndex) & ":\"
' [ftRemoved] - data usunięcia pliku (folderu) zapisana w strukturze FILETIME,
' do konwersji struktury FILETIME na datę musimy użyć własnej funkcji:
Debug.Print "[ftRemoved] - " & _
"Data usunięcia pliku (folderu):", _
zbConvertFiletimeToDate(.ftRemoved)
' [BytesCluster] - ilość bajtów w zajmowanych klastrach na dysku,
Debug.Print "[BytesCluster] - " & _
"ilość zajmowanych bajtów w klastrach:", _
.BytesCluster
' [FilePathW] - oryginalna lokalizacja pliku (folderu), wersja UNICODE,
' sprawdź wielkość rekordu, oryginalna lokalizacja [FilePathW] występuje tylko w 800-bajtowych rekordach
If ifH.RecordSize = SIZE_RECORD_A Then
Debug.Print "[FilePathW] - " & _
"rekordy 280-bajtowe nie zawierają lokalizacji " & _
"pliku (folderu) zapisanej w wersji Unicode"
Else
sFilePathW = Left$(.FilePathW, 2 * lstrlen(.FilePathW))
Debug.Print "[FilePathW] - " & _
"oryginalna lokalizacja (Unicode):", sFilePathW
sFilePathA = StrConv(sFilePathW, vbFromUnicode)
End If
' 3.4.2. Inne informacje - dla uproszczenia kodu będziemy posługiwali się ścieżką pliku w wersji ASCII
' (sExtension) - rozszerzenie pliku, również i folderu, jeżeli zawiera w nazwie kropkę,
Do
' szukaj ostatniej kropki w ciągu wejściowym,
lInStr = i
i = InStr(i + 1, sFilePathA, ".", vbBinaryCompare)
Loop Until i = 0
sExtA = ""
' jeżeli znaleziono kropkę, to pobierz znaki znajdujące się za nią
If lInStr > 0 Then
sExtA = Mid$(sFilePathA, lInStr + 1)
End If
Debug.Print "(sExtension) - " & _
"rozszerzenie pliku (folderu) - ASCII:", sExtA
' (sNameInRecycledA) - nazwa pliku (folderu) pod jaką figuruje w Koszu,
sNameInRecycledA = "D" & Chr$(Asc("a") + _
.DriveIndex) & CStr(.FileIndex)
If Len(sExtA) > 0 Then
sNameInRecycledA = sNameInRecycledA & "." & sExtA
End If
Debug.Print "(sNameInRecycledA) - " & _
"nazwa pliku (folderu) w Koszu :", _
sNameInRecycledA
' (fExistInRecycled) - czy plik (folder) istnieje fizycznie w Koszu,
fExistInRecycled = CBool(Len(Dir(sPathRecycledA & _
sNameInRecycledA, _
vbDirectory + MY_ATTRIB)))
' (fIsDirectory) - czy istniejący obiekt jest folderem, czy plikiem,
If fExistInRecycled = True Then
fIsDirectory = (GetAttr(sPathRecycledA & _
sNameInRecycledA) And _
vbDirectory) = vbDirectory
If fIsDirectory = True Then
Debug.Print "(fIsDirectory) - " & _
"czy obiekt jest folderem:", _
"Tak, jest folderem."
' skoro obiekt jest folderem, niektóre dane
' wszystkich plików w folderzei podfolderach
'możemy pobrać do tablicy wfdRet() w poniższy sposób:
' zbListAllFilesW StrConv(sPathRecycledA, _
vbUnicode), "*.*", sPathRet(), _
wfdRet(), True
Else
Debug.Print "(fIsDirectory) - " & _
"czy obiekt jest folderem:", _
"Jest plikiem."
' niektóre dane pojedynczego pliku, możemy
' pobrać w poniższy sposób:
' zbListAllFilesW StrConv(sPathRecycledA, _
vbUnicode), sNameInRecycledA, _
sPathRet(), wfdRet(), False
' w wyniku otrzymamy jednoelementową tablicę wfdRet(0)
End If
Else
Debug.Print "(fExistInRecycled) - " & _
"czy plik, folder istnieje w Koszu:", _
"Obiekt nie istnieje w koszu !"
End If
Debug.Print String(35, "-") & " Koniec rekordu " & String(55, "-")
End With
Loop
Close #ff
DoCmd.RunCommand acCmdDebugWindow
End Function
ΔΔΔ | | | | |
|
| | |
|
3.4 Jak zrobić miniatury (thumbsy) plików graficznych i dołączyć je do listy właściwości plików znajdujących się w folderze i podfolderach. ?
Aby odpowiedzieć na to pytanie musimy skorzystać z dwóch już prezentowanych przykładów i połączyć je w jeden:
Przykład pierwszy odpowiada na pytanie: Jak wylistować pliki w folderze głównym i podfolderach oraz ... ? a przykład drugi mówi nam Jak zrobić miniatury plików graficznych tzw. Thumbsy ? Wykorzystuje on darmową bibliotekę FreeImage.dll, patrz. O przykładach z użyciem biblioteki FreeImage.dll
Ograniczenia wynikające z zastosowania biblioteki FreeImage.dll podczas tworzenia miniatur plików graficznych w formacie *.jpeg
- Teoretycznie obsługiwane są tylko następujące typy plików:
*.bmp, *.ico, *.jpeg, *.jng, *.koala, *.lbm, *.mng, *.pbm, *.pbmraw, *.pcd, *.pcx, *.pgm, *.pgmraw, *.png, *.ppm, *.ppmraw, *.ras, *.targa, *.tiff, *.wbmp, *.psd, *.cut, *.xbm, *.xpm, *.dds, *.gif, *.hdr, *.faxg3, *.sgi, *.exr, *.j2k, *.jp2
- Niestety, nie wszystkie typy plików są w pełni obsługiwane przez tą bibliotekę,
- Występują problemy przy zapisie miniatury animowanego pliku *.gif zapisywanego jako plik *.jpeg. Miniatura tego pliku zostaje prawidłowo zapisana (pierwszy obrazek animacji) jako plik *.png
- Także niektóre zwykłe pliki *.gif nie są prawidłowo zapisywane jako plik *.jpeg, ale zostaje prawidłowo zapisany jako plik typu *.png
- Czasami plik *.png nie jest zapisywany prawidłowo jako plik *.jpeg, ale zostaje prawidłowo zapisany jako plik typu *.png
Jak przykład działa:
- Tworzona jest lista lokalizacji wszystkich plików (w wersji Unicode),
- Kolejno, każdy plik jest kopiowany do folderu np. FolderaBazy\Thumbs_Indeks z nową nazwą zawierającą tylko cyfry,
- Sprawdzamy, czy plik jest obsługiwany przez bibliotekę FreeImage,
- Jeżeli tak, to wykonujemy jego miniaturę i próbujemy zapisać ją jako *.jpeg, lub *.png, a w ostateczności jako *.bmp.
- Skopiowany oryginał pliku jest usuwany z dysku.
Po wstępnych testach mogę powiedzieć, że FreeImage w połączeniu z Access'em, który przecież nie jest programem graficznym,
ma pewne problemy z przetwarzaniem dużej ilości plików graficznych. Im większe pliki, tym tym większe problemy, ale nie dyskwalifikują one ani biblioteki FreeImage, ani tym bardziej Accessa, który został przecież stworzony do zupełnie innych celów.
<<• idź do str. 2 •>>
ΔΔΔ | | | | |
|
| |