VCL - drugie kroki

Kontynuujemy rozpoczętą w poprzednim numerze budowę komponentu VCL do obsługi plików. Dokończymy implementację metod, wprowadzimy zdarzenia i dodamy funkcje ułatwiające pobieranie informacji o plikach.

Kontynuujemy rozpoczętą w poprzednim numerze budowę komponentu VCL do obsługi plików. Dokończymy implementację metod, wprowadzimy zdarzenia i dodamy funkcje ułatwiające pobieranie informacji o plikach.

W poprzedniej części artykułu implementację metody Execute zakończyliśmy fragmentem kodu odpowiedzialnym za tworzenie plików i katalogów. Omówiliśmy także funkcję Przeszukuj. Do wykonania wszystkich pozostałych operacji metoda Execute używa funkcji WykonajOperacje(rodzaj). Parametr rodzaj jest typu UINT, podobnie jak pole wFunc odpowiadające za rodzaj operacji w strukturze SHFILEOPSTRUCT.

Dalej o operacjach

Na szczególną uwagę zasługuje fragment kodu, który pobiera nazwy plików z listy wejściowej i/lub wyjściowej, a następnie tworzy z nich tablice dopasowane do wymagań struktury SHFILEOPSTRUCT. Pola pFrom i pTo tej struktury określają lokalizacje plików, na których zostaną wykonane wskazane operacje. Nazwy kolejnych elementów tablic wskazywanych przez pFrom i pTo muszą być oddzielone pustym znakiem '\0', a koniec listy podwójnym znakiem '\0'. Elementy muszą być tablicami znakowymi. Dla większości funkcji operujących na ciągach znaków (np. Length(), StrCat(), String.c_str()) znak '\0' oznacza koniec łańcucha. Trzeba w związku z tym uważać, żeby niechcący nie odciąć fragmentu tablicy. W metodzie WykonajOperację(rodzaj) kopiowanie danych z listy do tablicy zostało zrealizowane następująco:

bool __fastcall TFilesExplorer::

WykonajOperacje(UINT operacja)

{

SHFILEOPSTRUCT struktura;

ZeroMemory(&struktura,sizeof(struktura));

char *Lokalizacja =

new char[MAXPATH*ListaWejsciowa->Count];

char *NowaLokalizacja =

new char[MAXPATH*ListaWejsciowa->Count];

for(int i=0;i<MAXPATH*ListaWejsciowa->

Count;i++)

{

Lokalizacja[i] = '\0';

NowaLokalizacja[i] = '\0';

}

int index = 0;

for(int i=0;i<ListaWejsciowa->Count;i++)

{

for(int j=1;j<=ListaWejsciowa->

Strings[i].Length();j++)

Lokalizacja[index++] =

ListaWejsciowa->Strings[i][j];

Lokalizacja[index++] = '\0';

}

struktura.pFrom = Lokalizacja;

index = 0;

for(int i=0;i<ListaWyjsciowa->Count;i++)

{

for(int j=1;j<=ListaWyjsciowa->

Strings[i].Length();j++)

NowaLokalizacja[index++] =

ListaWyjsciowa->Strings[i][j];

NowaLokalizacja[index++] = '\0';

}

struktura.pTo = NowaLokalizacja;

struktura.hwnd = handle;

struktura.wFunc = operacja;

struktura.fFlags = o->OdczytajFlagi();

struktura.lpszProgressTitle =

o->OdczytajNazweOkna();

SHFileOperation(&struktura);

przerwano =

struktura.fAnyOperationsAborted;

return true;

}

Pakiet komponentu TFilesExplorer - pliki składowe i wymagane biblioteki.

Pakiet komponentu TFilesExplorer - pliki składowe i wymagane biblioteki.

W powyższej metodzie najpierw tworzymy i zerujemy strukturę SHFILEOPSTRUCT. Następnie tworzymy dynamicznie dwie tablice znakowe. Każda ma wielkość równą iloczynowi liczby wierszy na odpowiednich listach oraz maksymalnej długości ścieżki w systemie. Utworzone tablice należy następnie wyzerować, za co odpowiada pierwsza pętla for. Kolejny etap to utworzenie zmiennej index do indeksowania tablic Lokalizacja i NowaLokalizacja. Po tych czynnościach wypełniamy pierwszą tablicę, wpisując kolejne znaki z każdego wiersza ListyWej. Przechodząc do następnego wiersza, za każdym razem dopisujemy do tablicy znak '\0', który oddziela kolejne elementy. Instrukcja dopisująca znak '\0' właściwie tylko poprawia czytelność listingu i wcale nie jest konieczna, bo cała tablica została wcześniej wyzerowana i w tym miejscu już jest wartość 0. Wystarczyłoby więc zwiększyć o jeden zmienną index i kontynuować wpisywanie znaków z następnego wiersza. Z tego samego powodu nie musimy dopisywać na końcu tablicy dodatkowego znaku '\0'. Podobny schemat stosujemy do ListyWyj, a po zakończeniu każdej pętli przypisujemy tablice Lokalizacja i NowaLokalizacja do zmiennych pFrom i pTo.

Kolejne właściwości

W powyższej metodzie pojawiła się też zmienna handle przypisana do pola hwnd, które przechowuje uchwyt właściciela. Jeżeli przypiszemy jej uchwyt jakiegoś okna, to będzie ono wykorzystywane do wyświetlania informacji o postępie operacji. Dozwolone jest również użycie wartości 0 w tym polu. Wówczas operacje będą wykonywane w tle. Dostęp do pola hwnd zapewnimy, dodając zmienną handle do naszego komponentu, natomiast zmianę wartości pola hwnd umożliwimy, dodając właściwość:

__property HWND Uchwyt = {read=handle, write=handle, nodefault};

Właściwość umieszczamy w części public, ale przed __published. Właściwości typu HWND nie mogą być opublikowane, dlatego zmiany wartości będziemy dokonywać z poziomu kodu programu.

Kolejne nowe elementy użyte w metodzie WykonajOperacje to o->OdczytajFlagi() oraz o->OdczytajNazweOkna(). Obie są metodami klasy opcje. Pierwsza przekazuje flagi informujące o sposobie wykonania czynności, a druga nazwę wyświetlanego ewentualnie okna postępu.

Zanim przejdziemy do wspomnianych metod klasy opcje, zwróćmy jeszcze uwagę na przedostatnią instrukcję metody WykonajOperacje(rodzaj). Zmiennej przerwano przypisujemy wartość określającą, czy wykonanie operacji nie zostało przypadkiem przerwane przez użytkownika. Z racji swojego przeznaczenia zmienna jest tylko do odczytu i nie może być modyfikowana przez osobę korzystającą z komponentu. Dlatego odpowiednią właściwość należy zadeklarować następująco:

__property bool Przerwano={read=przerwano};

Taka deklaracja właściwości powoduje, że można jedynie pobierać jej wartość. Deklarację umieszczamy przed klauzulą __published, ponieważ dostęp do niej z poziomu środowiska C++Buildera nie ma większego sensu.

Klasę opcje z jej właściwościami zadeklarowaliśmy już wcześniej. Teraz musimy zaimplementować metody OdczytajFlagi(void) i OdczytajNazweOkna(void). Zacznijmy od drugiej. Jej zadaniem jest zwrócenie w odpowiedniej postaci wartości zapisanej we właściwości:

__property AnsiString NazwaOknaPost = {read=NOPostepu, write=NOPostepu}.

Działanie funkcji sprowadza się do wykonania konwersji łańcucha za pomocą funkcji c_str() w następujący sposób:

LPCSTR __fastcall opcje::

OdczytajNazweOkna(void)

{

return NOPostepu.c_str();

}


Zobacz również