Program do usuwania błędnych skrótów.
Program przedstawiony w tym kursie praktycznym ma za zadanie przeskanowanie
Menu Start w poszukiwaniu błędnych skrótów, czyli takich które prowadzą do
nieistniejących już plików. Wykorzystam tutaj funkcje
wyszukiwania plików,
odczytywania informacji o skrótach i sprawdzania ścieżek dostępu do
specjalnych folderów, wszystkie te funkcje można znaleźć w serwisie, tutaj
zostaną one nieco zmodyfikowane by dostosować je do potrzeb programu. Opis
tworzenie programu postaram przedstawić się w maksymalnie najprostszy sposób tak
by mogli go zrozumieć początkujący. Nie będę tutaj opisywał sposobu działania
kodu, ale opiszę rolę jaką w programie pełnią jego poszczególne składniki.
Zaczynamy od utworzenia nowego projektu, zapisujemy go w katalogu, a następnie
przechodzimy do formularza Form1 i zmieniamy jego właściwości w
oknie Object Inspector na zakładce Properies według podanego
wzoru:
BorderIcons -> biMaximize = false (usuwa ikonę maksymalizacja z paska tytułowego)
BorderStyle = bsSingle (zmienia zachowanie formularza uniemożliwiając zmianę jego rozmiaru)
Height = 424
Position = poDesktopCenter (ustawia pozycjonowanie formularza w chwili uruchomienia na wyśrodkowane na pulpicie)
Width = 870
Następnie umieszczamy na formularzu komponenty tak jak widać na załączonym obrazku:
Następnie ustawiamy
właściwości poszczególnych komponentów według wzoru:
TButton: Skan Caption = Skanuj Left = 16 Top = 24 |
TButton: Del Caption = Usuń Left = 104 Top = 24 |
TProgressBar: ProgressBar1 Left = 200 Top = 28 Width = 649 |
TListView: ListView1 Columns = (Add news) Skrót; (Add news) Plik Height = 313 Left = 16 Top = 64 ViewStyle = vsReport Width = 833 |
Teraz możemy przystąpić do kodowania na wstępie w pliku źródłowym (Unit1.cpp) na samej górze dodajemy wpis #define NO_WIN32_LEAN_AND_MEAN, a trochę niżej w sekcji include włączmy do projektu bibliotekę shlobj.h:
// Plik źródłowy
Unit1.cpp |
Wpis NO_WIN32_LEAN_END_MEAN musi być dodany ponieważ korzystamy z biblioteki shlobj.h, a w środowisku Borland C++ Builder w wersji 6 ta biblioteka wywołuje błędy, a ten wpis naprawia ten błąd umożliwiając korzystanie z tej biblioteki. Biblioteka shlobj.h jest potrzebna ponieważ w dalszej części programowania będzie wykorzystywali znajdujące się w niej funkcje, a to po to, żeby nie tworzyć tychże funkcji samodzielnie od podstaw - takie ułatwienie, ale nie należy się tym przejmować, ponieważ programiście nieustannie tworzą jakieś biblioteki, a inni programiści wykorzystują je do własnych potrzeb.
Teraz tworzymy funkcję o nazwie ShortcutInfo, która
będzie odczytywała informacje o skrócie, w przypadku tego programu funkcja
będzie zwracała jako wynik swojej pracy ścieżkę dostępu do programu do którego
prowadzi skrót, czyli przykładowo mamy w Menu Start skrót o nazwie WorPad.lnk,
skrót prowadzi do programu C:\Program Files\Windows NT\Accessories\wordpad.exe i
właśnie funkcja będzie zwracała tą ścieżkę dostępu, ktoś mógłby się spytać: A po
co mi ta ścieżka dostępu? A no po to, że jeżeli chcemy sprawdzić czy skrót
prowadzi do istniejącego pliku, to trzeba sprawdzić najpierw do jakiego pliku
ten skrót prowadzi, a potem trzeba sprawdzić czy taki plik istnieje, i jeżeli np.
plik nie istnieje no to już wiemy, że jest to błędny skrót i to jest przykład na
to jak powinien podchodzić informatyk do problemu, ponieważ z doświadczenia
wiem, że większość tzw. informatyków stając przed podobnym problemem zaczyna się
zastanawiać skąd wziąć funkcję, która od razu odpowie, czy skrót jest błędny czy
nie, a programowanie nie na tym polega.
Tak więc funkcja ShortcutInfo nie odpowie nam, czy
jest to błędny skrót czy nie, ale zrobi to kolejna funkcja, ale o tym później.
Funkcja ShortcutInfo pobiera dwa argumenty pierwszy lnkFileName jest typu
AnsiString i trzeba tutaj podawać ścieżkę dostępu do skrótu (i tylko do
skrótu *.lnk), z którego chcemy wydobyć ścieżkę pliku do którego ten skrót
prowadzi. Drugi argument FileName jest typu char i tutaj nie można
przekazywać funkcji żadnych parametrów, należy jej przekazać wskaźnik do
zmiennej typu char, czyli taką zmienną, gdyż funkcja zwróci ścieżkę
dostępu do pliku, właśnie do tej zmiennej. Sama funkcja jest typu bool co
oznacza, że zwraca wartości typu true jeżeli odczyt informacji ze skrótu
zakończył się sukcesem, lub false jeżeli nie udało się wydobyć informacji
ze skrótu, gdy np. sam skrót nie istnieje. Powiedziałem tutaj, że funkcja zwraca
wartość typu bool, ale to tylko bezpośrednio, ponieważ pośrednio poprzez
drugi argument czyli zmienną FileName, funkcja zwraca również ścieżkę
dostępu do pliku (element docelowy).
// Plik źródłowy
Unit1.cpp bool ShortcutInfo(const
AnsiString lnkFileName, char *FileName) |
Kolejnym krokiem jest utworzenie funkcji sprawdzającej czy mamy do czynienia z błędnym skrótem czy nie, funkcja TestShortcut korzysta z funkcji zawartych w bibliotece stdio.h dlatego trzeba tą bibliotekę również włączyć do projektu poprzez sekcję include. Funkcja ta pobiera dwa argumenty, pierwszy link jest typu AnsiString i przekazuje on do funkcji ścieżkę dostępu do skrótu, ten argument jest dokładnie taki sam jak pierwszy argument funkcji ShortcutInfo, a to dlatego, że ta funkcja po prostu przekazuje ten argument dalej, czyli najpierw ścieżka dostępu do skrótu będzie przekazywana do funkcji TestShortcut, a następnie funkcja TestShortcut przekaże ten argument do funkcji ShortcutInfo, dzieje się tak dlatego, że to właśnie ta funkcja sprawdza czy skrót jest błędny, a funkcji ShortcutInfo potrzebuje tylko do wyciągnięcia ścieżki dostępu do pliku. Drugi argument funkcji Buf typu char spełnia dokładnie taką samą rolę jak drugi argument funkcji ShortcutInfo czyli pobiera ścieżkę dostępu do pliku z funkcji ShortcutInfo i przekazuje ją funkcji TestShortcut, a ta wykorzystuje go potem do sprawdzenie czy plik istnieje po czym przekazuje go dalej w celach informacyjnych, ale o tym później:
// Plik źródłowy Unit1.cpp |
Pokrótce wyjaśnię jak działa ta funkcja. Więc już na wstępie mamy zadeklarowane
dwie zmienne typu char. Zmienna Win służy do przechowywania
ścieżki dostępu do katalogu systemowego Windows, zmienna file służy do
przechowywania informacji o pliku do którego prowadzi skrót, informacja ta, co
wyjaśniłem wcześniej jest wyciągana ze skrótu poprzez funkcję ShortcutInfo.
Informację o tym gdzie znajduje się katalog systemowy Windows pobiera funkcja
GetWindowsDirectory i przekazuje ją w postaci ścieżki dostępu do zmiennej
Win. Niektórzy może się zastanawiają po co sprawdzać ścieżkę dostępu do
katalogu Windows skoro wiadomo, że jest to C:\Windows, otóż niekoniecznie,
Windows 98 musiał być instalowany na dysku C:, ale Windows XP już nie więc może
się zdarzyć, że jest zainstalowany na innym dysku i dlatego właśnie potrzebujemy
tej informacji. Kolejne pytanie, które się ciśnie na usta to: po co nam ta
ścieżka dostępu? Niektóre skróty do plików mogą mieć podane w polu 'Element
docelowy', nie pełną ścieżkę dostępu do pliku, lecz ścieżka do katalogu Windows
może być podana jako zmienna środowiskowa %SystemRoot% jak ma to np.
miejsce w przypadku kalkulatora:
W dalszej części kodu funkcja wykorzystując informację o tym gdzie znajduje się katalog Windows podstawia pod tą zmienną środowiskową właśnie tą ścieżkę i w efekcie zamiast %SystemRoot%\System32\calc.exe otrzymuje np. c:\Windows\System32\calc.exe, a wydobyciem zmiennej środowiskowej i jej zamianą na pełną ścieżkę dostępu zajmuje się ten fragment kodu:
Jak widać na tym przykładzie ścieżka wydobyta ze skrótu zostaje obcięta o zmienną środowiskową, a w jej miejsce zostaje podstawiona ścieżka dostępu do katalogu Windows.
Funkcja TestShortcut wydobywa ścieżkę odstępu do pliku, do którego prowadzi skrót wywołując funkcję
ShortcutInfo(link, file); jak widać przekazuje ona funkcji ShortcutInfo jako pierwszy argument ścieżkę dostępu do skrótu, którą sama otrzymała poprzez zmienną link, oraz wskaźnik w postaci zmiennej file, który pobierze informację o elemencie docelowym skrótu. Potem zmienna file zostaje przepisana do nowo utworzonej zmiennej path typu AnsiString.
Kolejna cześć kodu:
if(FileExists(path) || path.IsEmpty())
{
sprintf(Buf, "%s", "");
return true;
}
sprintf(Buf, "%s", file);
return false;
sprawdza czy element docelowy skrótu istnieje. Konkretnie za sprawdzenie pliku odpowiada funkcja FileExists pobierająca jako jedyny argument ścieżkę dostępu właśnie do tego pliku przechowywaną w zmiennej path. Jeżeli plik istnieje funkcja zwraca wartość true, w przeciwnym razie false. W tej części kodu znajduje się również taki fragment path.IsEmpty(), który sprawdza, czy zmienna path zawiera w ogóle jakąś wartość, jest on potrzebny z tego względu, że jeżeli mamy do czynienia ze skrótem prowadzącym do adresu internetowego np. http://cyfbar.republika.pl/index.html to funkcja ShortcutInfo nie zwróci ścieżki dostępu do tego adresu, lecz pustą wartość, co przez funkcję FileExists zostało by rozpoznane jako nieistniejący plik i w efekcie program uznałby to za błędny skrót i ten fragment kodu właśnie eliminuje tą nieprawidłowość.
Znaczenie tego fragmentu kodu: if(FileExists(path) || path.IsEmpty()) jest takie: Jeżeli funkcja FileExists zwróci wartość true to znaczy, że plik przekazany funkcji w ścieżce dostępu zmiennej path istnieje, lub jeżeli ścieżka dostępu (zmienna path) jest pusta to wykonaj kod zawarty miedzy nawiasami, czyli wystarczy, że jeden z tych warunków zostanie spełniony a funkcja zakończy swoje działanie wykonując kod zawarty między nawiasami, a tam zmiennej Buf zostaje przekazana pusta wartość (zostaje wyczyszczona z poprzedniej wartości) i funkcja zwraca wartość true informując tym samym program, że jest to prawidłowy skrót. Jeżeli natomiast żaden z tych warunków nie jest spełniony to wykonuje się dalsza cześć kodu, czyli zmiennej Buf zostaje przypisana wartość zmiennej file zawierającej element docelowy badanego skrótu, a to po to żeby użytkownik wiedział do jakiego nieistniejącego pliku prowadzi dany skrót, następnie funkcja zwraca wartość false informując tym samym program, że jest to błędny skrót.
To nie jest jeszcze koniec kodowania, teraz trzeba stworzyć kod wyszukujący wszystkie skróty w Menu Start. Posłużę się tutaj funkcją wyszukiwania folderów, podfolderów i plików prezentowaną już w serwisie:
// Plik źródłowy Unit1.cpp |
Zanim przejdziemy dalej, trzeba jeszcze dodać deklarację tej funkcji do pliku nagłówkowego (Unit1.h) w sekcji private:
// Plik nagłówkowy Unit1.h |
Funkcja FindDir może działać w dwóch trybach, pierwszy to policzenie ile
skrótów znajduje się w Menu Start, dzieje się to wtedy gdy wywołamy
funkcję z czwartym argumentem - oblicz - ustawionym na true, nie
ma to większego wpływu na szybkość działania programu, testowałem to u siebie i
600 skrótów funkcja obliczyła w mniej niż sekundę. Ten element jest potrzebny
tylko do zobrazowanie na ProgressBar1 postępu sprawdzania błędnych
skrótów. W drugim trybie funkcja (czwarty argument otrzymuje wartość false)
wylicza ponownie wszystkie skróty, jednak tym razem wywołuje funkcje
TestShortcut i przekazując jej jako argumenty ścieżkę dostępu do testowanego
skrótu oraz wskaźnik do zmiennej buf przechowującej informację o błędnym
elemencie docelowym skrótu. Jako pierwszy argument funkcja FindDir
pobiera wskaźnik do obiektu typu TListView, ponieważ to właśnie w tym
obiekcie funkcja będzie tworzyła listę błędnych skrótów, drugi argument to
ścieżka dostępu do katalogu w którym będą wyszukiwane skróty, trzeci argument to
rozszerzenie dla poszukiwanego typu plików i tutaj należy zawsze podawać wartość
"lnk", czwarty argument to przełącznik trybu pracy funkcji który opisałem
wyżej. Funkcja steruje również paskiem postępu ProgressBar.
Teraz w zdarzeniu OnClick dla przycisku Scan wywołamy wszystkie funkcje przeprowadzając tym samym wyszukiwanie błędnych skrótów. Zdarzenie OnClick tworzymy w Obiect Inspector na zakładce Events:
// Plik źródłowy Unit1.cpp |
W tym kodzie na
uwagę zasługuje funkcja SHGetSpecialFolderPath, która zwraca ścieżkę
dostępu do folderów specjalnych, a w tym programie funkcja zwraca ścieżkę
dostępu do katalogu [Menu Start] w którym to właśnie znajdują się skróty.
W zdarzeniu OnClick przycisku Scan ta funkcja jest wywoływana
czterokrotnie, za pierwszym razem funkcja sprawdza ścieżkę dostępu do katalogu
[Menu Start] dla wszystkich użytkowników (All Users\Menu Start),
za drugim razem tylko dla bieżącego użytkownika. Po każdym wywołaniu funkcji
następuje również wywołanie funkcji FindDir, w dwóch pierwszych
przypadkach jest to robione w celu obliczenia ile jest tych skrótów, po czym
maksymalna wartość ProgressBar1 zostaje ustawiona na wyliczona liczbę
skrótów, następnie funkcje SHGetSpecialFolderPath i FindDir
zostają ponownie wywołane dwukrotnie, ale tym razem w celu wyszukania błędnych
skrótów. Wynik wyszukiwania zostanie zobrazowany w ListView1, na liście pojawią
się ścieżki dostępu do błędnych skrótów z informacją o tym do jakich
nieistniejących plików prowadzą.
Zanim przejdę do kolejnego kodu wspomnę jeszcze o argumencie przekazywanym
funkcji SHGetSpecialFolderPath, otóż mamy tam takie argumenty:
CSIDL_COMMON_STARTMENU - All Users\Menu Start
CSIDL_STARTMENU
- <nazwa zalogowanego użytkownika>\Menu Start
Możliwych argumentów jest więcej i można je znaleźć w poradzie: ścieżki dostępu do katalogów specjalnych, ja wymienię tutaj jednak jeszcze trzy inne i bardzo przydatne:
CSIDL_DESKTOP - Pulpit
CSIDL_DESKTOPDIRECTORY - <nazwa zalogowanego użytkownika>\Pulpit
CSIDL_COMMON_DESKTOPDIRECTORY - All Users\Pulpit
Teraz tworzymy ostatni element programu, czyli kod usuwający błędne skróty na podstawie zawartości listy ListView. W tym celu tworzymy zdarzeni OnClick dla przycisku Del i umieszczamy w nim taki kod:
// Plik źródłowy Unit1.cpp |
Tutaj w każdym obiegu pętli for jest sprawdzana lista i jest z niej pobierana ścieżka dostępu do błędnego skrótu, następnie jest ona przekazywana do funkcji DeleteFile jako jej argument, i funkcja ta na tej podstawie usuwa błędny skrót.
Program usuwa tylko skróty które uzna za błędne, wiec gdyby nawet się okazało, że rozpoznał skróty prawidłowe jako błędne, to usunie tylko skrót i nie ma to żadnego wpływy na plik do którego ten skrót prowadzi.
Program nie jest doskonały to tylko przykład, służący do nauki programowania. Do wad programu można zaliczyć np. to iż program nie usuwa katalogów, z których zostały usunięte wszystkie skróty, no i druga wada to, że usuwa błędne skróty tylko z konta All Users i z konta aktualnie zalogowanego użytkownika, czyli nie przeszukuje kont innych użytkowników, chociaż z drugie strony to może nawet lepiej, jednak zawsze można dodać do programu opcję, że administrator może usuwać błędne skróty ze wszystkich kont.
Pliki źródłowe projektu BCB 6, archiwum RAR - rozmiar 258 kb.
Opracował: Cyfrowy Baron