Różne 2.

  W tym dziale znajdują się porady, które trudno jest zakwalifikować do odrębnych grup, czyli wszystkiego po trochu.

Menu 2

  1. Wyliczanie zasobów sieciowych.

  2. Co zrobić jeżeli program napisany w BCB nie uruchamia się na innych komputerach?

  3. Tworzenie plików i folderów.

  4. Kopiowanie i przenoszenie plików.

  5. Jak na obiekcie StatusBar umieścić pasek postępu - ProgressBar?

  6. Dynamiczne tworzenie obiektów.

  7. Podłączanie zdarzenia do dynamicznie tworzonego obiektu.

  8. Wyświetlanie ikon skojarzonych z plikiem lub folderem.

  9. Jak zmienić atrybuty plików i folderów?

  10. Zmiana czasu i daty systemowej.

  11. Pobieranie informacji o pamięci.

  12. Pobieranie informacji o dyskach.

  13. Kopiowanie, przenoszenie i kasowanie katalogów, i plików za pomocą "latających folderów."

  14. Odczytywanie rozmiaru pliku - kod w C.

  15. Zapisywanie i odczytywanie komponentów do/z pliku.

  16. Zapisywanie i odczytywanie bufora do/z pliku.

  17. goto instrukcja skoku do.

  18. Tworzenie przestrzeni dla zmiennych lub funkcji.

  19. Odczyt i zmiana daty utworzenia pliku.

  20. Sprawdzanie stanu klawiszy Caps Lock i Insert.

  21. Rezerwowanie pliku wymiany na potrzeby programu.

  22. Zmiana położenia ScrollBox w drugim obiekcie w oparciu o położenie ScrollBox w obiekcie pierwszym.

  23. Tworzenie pliku z zasobami i zapisywanie zasobów do pliku.

  24. Jak dodać własny deinstalator programu do listy Dodaj usuń programy?

  25. Wyliczanie komponentów na formularzu, dostęp do komponentów poprzez pętlę.

  26. Dostosowanie rozmiaru komponentów do zmieniającego się rozmiaru formularza.

  27. Wyliczanie dysków zainstalowanych w komputerze.

  28. Odczytywanie nazwy dysku.

  29. Odczytywanie systemu plików dysku.

  30. Sprawdzanie czy płyta znajduje się w napędzie.

  31. Wywołanie okna dialogowego umożliwiającego wybranie i stworzenie katalogu.

  32. Dostęp do właściwości komponentów poprzez nazwę klasy.

  33. Zapisywanie i doczytywanie stylu czcionki do/z pliku INI.

  34. Trochę inny progressBar.

  35. Przeliczanie czasu w milisekundach na godziny, minuty, sekundy i milisekundy.

  36. Blokowanie Menu Start.

  37. Pobieranie ścieżki dostępu do domyślnego programu powiązanego z plikiem.

  38. Umieszczanie kursorów (*.cur, *.ani) w zasobach programu.

  39. Umieszczanie plików AVI w zasobach programu.

  40. Wyświetlanie zawartości konsoli CMD.exe w Memo - wg. pomysłu kinio

  41. Pobieranie informacji o wersji BIOS'u, typie procesora...

  42. USUWANIE KATALOGU Z CAŁĄ ZAWARTOŚCIĄ.

  43. Wstawianie własnego PopupMenu do kontrolki TCppWebBRowser.

  44. Kopiowanie tekstu z kontrolki CppWebBrowser do schowka.

« Powrót do menu 1



 

Wyliczanie zasobów sieciowych.

  W niniejszej poradzie pokażę jak można uzyskać informację na temat wszystkich dostępnych i aktywnych połączeń sieciowych. Całe zadanie ogranicza się do stworzenia pojedynczej funkcji, jednakże nie jest to żadna z gotowych funkcji, tylko trzeba ją dopiero stworzyć. Funkcję nazwałem EnumNetRes (nazwa jest dowolna) jej działanie opiera się na trzech funkcjach API
WNetOpenEnum, WNetEnumResource, WNetCloseEnum. Najpierw umieszczamy w pliku nagłówkowym, w sekcji private deklarację funkcji, a następnie przechodzimy do pliku źródłowego i umieszczamy w nim definicję tejże funkcji, trzeba też umieścić na formularzu obiekt ListBox1 ponieważ to właśnie w nim zostaną wyświetlone wszystkie źródła połączeń sieciowych:

// Plik nagłówkowy np. Unit1.h.
//--------------------------------
private:
        void __fastcall
EnumNetRes(NETRESOURCE* nr);
//--------------------------------

 

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::EnumNetRes(NETRESOURCE* nr)
{
 HANDLE hEnum;

 if(WNetOpenEnum(RESOURCE_GLOBALNET,RESOURCETYPE_ANY,
    RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_CONNECTABLE,
    nr,&hEnum) != NO_ERROR) return;

 DWORD Count = -1;
 DWORD BufferSize = 0;
 DWORD ReturnVal = 0;

 NETRESOURCE *NetRes=(NETRESOURCE *)new char[1024];
 ZeroMemory(NetRes, sizeof(NETRESOURCE));
 for(;;)
 {
  ReturnVal = WNetEnumResource(hEnum, &Count, NetRes, &BufferSize);
  if(ReturnVal == ERROR_MORE_DATA)
  { 
   Count = -1;
   delete [] NetRes;
   NetRes = (NETRESOURCE*)new char[BufferSize];
   ZeroMemory(NetRes, sizeof(NETRESOURCE));
   ReturnVal = WNetEnumResource(hEnum, &Count, NetRes, &BufferSize);
  }
  if(ReturnVal != NO_ERROR) break;

  for(unsigned int i = 0; i < Count; i++)
  {
   ListBox1->Items->Add(NetRes[i].lpRemoteName);

   if((NetRes[i].dwUsage & RESOURCEUSAGE_CONTAINER) == RESOURCEUSAGE_CONTAINER)
       EnumNetRes(&NetRes[i]);
  }
  if(ReturnVal == ERROR_NO_MORE_ITEMS)
  {
   delete [] NetRes;
   WNetCloseEnum(hEnum);
  }
 }
 delete [] NetRes;
 WNetCloseEnum(hEnum);
}
//--------------------------------

Funkcję można wywołać w dowolnym zdarzeniu, np. OnClick dla przycisku Button1:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
 EnumNetRes(NULL);
}
//--------------------------------

Funkcja może potrzebować trochę czasu na sprawdzenie wszystkich połączeń, im jest ich więcej tym więcej czasu upłynie zanim funkcja wykona swoje zadanie, więc należy okazać odrobinę cierpliwości.

...powrót do menu. 

Tworzenie plików i folderów.

    Pliki można tworzyć za tysiące różnych sposobów a w tym serwisie opisałem ich kilka. Jednak tym razem chcę przedstawić sposób na proste utworzenie pliku z wykorzystaniem prostej funkcji FileCreate. W zasadzie działanie tej  funkcji polega na pobraniu jako argumentu nazwą pliku, który ma być utworzony:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 FileCreate("C:\\Moje dokumenty\\Nazwa_pliku.roz");
}
//--------------------------------

Jeżeli jednak  utworzymy w taki sposób plik, to nie da się go otworzyć ponieważ jego proces wciąż będzie pozostawał otwarty, czyli program będzie używał tego pliku. Dlatego trzeba po utworzeniu tego pliku zwolnić go tak by mógł być wykorzystany w innym procesie:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 int iFile = FileCreate("C:\\Moje dokumenty\\Nazwa_pliku.roz");
 FileClose(iFile);
}
//--------------------------------

Jak widać do zwolnienia procesu została wykorzystana nowa funkcja FileClose, która po prostu zamyka plik.

Jeżeli chodzi o tworzenie folderu, to sprawa wygląda podobnie, tylko że tym razem należy posłużyć się funkcją CreateDir, przekazując jej jako argument nazwę folderu, który chcemy utworzyć. Jednakże w ten sposób można tworzyć tylko pojedynczy folder i tylko w innym folderze lub bezpośrednio na dysku, jeżeli np. spróbujemy utworzyć w ten sposób folder w innym folderze, który nie istnieje to po prostu nic się nie stanie:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CreateDir("C:\\My Folder");
}
//--------------------------------

Można tą funkcję nieco rozszerzyć, tak żeby zwracała odpowiedni komunikat w zależności od tego czy katalog został utworzony czy nie:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if(!CreateDir("C:\\My Folder"))
  ShowMessage("Tworzenie folderu nie powiodło się!");
 else
  ShowMessage("Utworzono folder");
}
//--------------------------------

Jeżeli chcemy za jednym razem utworzyć kilka folderów to należy posłużyć się funkcją ForceDirectories, jednak by móc wykorzystać ta funkcję trzeba w pliku źródłowym lub nagłówkowym, w sekcji include włączyć plik FileCtrl.hpp:

// Plik źródłowy np. Unit1.cpp.
#include <FileCtrl.hpp>
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 ForceDirectories("C:\\My Folder\\Pictures\\My Pictures");
}
//--------------------------------

No i na zakończenie, kilka przydatnych funkcji:

DirectoryExists    -    sprawdza czy istnieje folder.

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if(DirectoryExists("C:\\My Folder\\Pictures\\My Pictures"))
  ShowMessage("Folder istnieje!");
}
//--------------------------------

ExtractFileDir        -    zwraca ścieżkę dostępu do katalogu lub pliku,
ExtractFilePath     -    jak wyżej.

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String dir1  = ExtractFileDir("C:\\My Folder\\Pictures\\My Pictures");
 String path1 = ExtractFilePath("C:\\My Folder\\Pictures\\My Pictures");

 String dir2  = ExtractFileDir("C:\\My Folder\\Pictures\\My Pictures\\Plik.txt");
 String path2 = ExtractFilePath("C:\\My Folder\\Pictures\\My Pictures\\Plik.txt");
}
//--------------------------------

Jako argument tych dwóch funkcji można przekazać ścieżkę dostępu do folderu, z którego uruchamiamy nasz program, co bardzo często się przydaje, ponieważ pozwala na odczytanie ścieżki dostępu do własnej aplikacji:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 String dir  = ExtractFileDir(Application->ExeName);
 String path = ExtractFilePath(Application->ExeName);
}
//--------------------------------

FileExists    -    sprawdza czy istnieje plik.

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if(FileExists("C:\\Moje dokumenty\\Plik.txt")
  ShowMessage("Plik istnieje");
}
//--------------------------------

...powrót do menu. 

Kopiowanie i przenoszenie plików.

    Krótko na ten temat. Do kopiowania plików można posłużyć się funkcją CopyFile:

CopyFile(const char * lpExistingFileName, const char * lpNewFileName, int bFailIfExists)

Jak widać przedstawiona funkcja pobiera trzy argumenty. Pierwszy argument to nazwa, a właściwie lokalizacja pliku który chcemy przekopiować, drugi argument to nazwa pliku i lokalizacja w której ma się znaleźć kopiowany przez nas plik, trzeci argument to forma zabezpieczenia, w zależności od tego jaką wartość podamy kopiowanie zostanie wykonane lub przerwane, jeżeli w nowej lokalizacji znajduje się już plik. W zasadzie trzeci argument może przyjąć tylko jedną z dwóch wartości, jeżeli ustawimy jego wartość na true to plik nie zostanie skopiowany jeżeli w zadanej lokalizacji znajduje się już plik o takiej samej nazwie, jeżeli ustawimy tą wartość na false, to plik zostanie zawsze skopiowany i jeżeli w zadanej lokalizacji znajduje się już plik o takiej samej nazwie, wtedy zostanie zastąpiony kopiowanym plikiem. Spróbujmy na przykładzie, załóżmy że mam plik w lokalizacji: c:\\temp\readme.txt i chcę go skopiować do innego katalogu: c:\\Moje dokumenty\readme.txt i dodatkowo chcę, żeby został zastąpiony plik, który ewentualnie znajduje się w katalogu Moje dokumenty:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CopyFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\readme.txt", true);
}
//--------------------------------

Można dołączyć komunikat, który będzie wyskakiwał jeżeli w podanej lokalizacji znajduje się już plik o takiej nazwie jak ten, który chcemy skopiować:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if(CopyFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\readme.txt", true) == false)
  Application->MessageBox("Kopiowanie się nie powiodło. W podanej lokalizacji znajduje się już plik o takiej nazwie.",
                          "Nie skopiowano pliku!", MB_OK | MB_ICONSTOP);
}
//--------------------------------

Podczas kopiowania pliku można zmieniać jego nazwę, np:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 CopyFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\Czytaj to.txt", true);
}
//--------------------------------

Co się zaś tyczy przenoszenia plików, to służy do tego funkcja MoveFile:

MoveFile(const char * lpExistingFileName, const char * lpNewFileName)

Jak widać funkcja ta nie różni się wiele od funkcji CopyFile, istotne różnice polegają na braku trzeciego argumentu, czyli pobierane są tylko lokalizacja przenoszonego pliku i lokalizacja w której ma się znaleźć plik przenoszony. No i dość istotna sprawa, w przypadku tej funkcji nie można zmieniać ustawienia regulującego przenoszenie pliku, w sytuacji gdy w zadanej lokalizacji znajduje się już plik o takiej samej nazwie - przenoszenie pliku się nie powiedzie, czyli plik po prostu nie zostanie przeniesiony, pozostałe rzeczy nie zmieniają się:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 MoveFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\readme.txt");
}
//--------------------------------

 

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if(MoveFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\readme.txt") == false)
  Application->MessageBox("Przenoszenie pliku się nie powiodło. W podanej lokalizacji znajduje się już plik o takiej nazwie.",
                          "Nie przeniesiono pliku!", MB_OK | MB_ICONSTOP);
}
//--------------------------------

I podobnie jak to było w przypadku kopiowania, można zmienić nazwę przenoszonego pliku:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 MoveFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\Czytaj to.txt");
}
//--------------------------------

Gdybyśmy jednak potrzebowali, żeby podczas przenoszenia pliku został zastąpiony plik znajdujący się w lokalizacji do której przenosimy plik, należy posłużyć się dodatkowo funkcją DeleteFile, która została opisana w poradzie kasowanie plików i folderów, a która to funkcja kasuje wybrany plik:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 if(MoveFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\readme.txt") == false)
 {
  int id = Application->MessageBox("W podanej lokalizacji znajduje się już plik o takiej nazwie. Czy chcesz go zastąpić?",
                          "Przenoszenie pliku.", MB_YESNO | MB_ICONQUESTION);
  if(id == ID_YES)
  {
   DeleteFile("c:\\\\Moje dokumenty\\readme.txt");
   MoveFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\readme.txt");
  }
 }
}
//--------------------------------

lub znacznie prościej i bez pytań o zgodę na zastąpienie pliku:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 DeleteFile("c:\\\\Moje dokumenty\\readme.txt");
 MoveFile("c:\\\\temp\\readme.txt", "c:\\\\Moje dokumenty\\readme.txt");
}
//--------------------------------

...powrót do menu. 

Jak w obiekcie StatusBar umieścić pasek postępu - ProgressBar?

    Zadanie bardzo proste w realizacji. Umieszczamy na formularzu obiekt StatusBar1, a resztę realizujemy za pomocą kodu:

// Plik nagłówkowy np Unit1.h
//--------------------------------
private:
        TProgressBar *ProgressBar1;
//--------------------------------

Jak widać w pliku nagłówkowym został zadeklarowany pasek postępu o nazwie ProgressBar1 typu TProgressBar. W pliku źródłowym należy utworzyć definicję tegoż obiektu:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 ProgressBar1 = new TProgressBar(StatusBar1);
 ProgressBar1->Parent = StatusBar1;
 ProgressBar1->Position = 50;
 ProgressBar1->Visible = true;
}
//--------------------------------

Ustawiłem pozycję obiektu ProgressBar1 na 50 tylko po to, żeby po uruchomieniu programu było ten pasek widać, ale właściwością Position tego obiektu steruje się dokładnie tak samo jak w przypadku komponentu TProgressBar. Można oczywiście posunąć się dalej i dokładniej wyregulować położenie obiektu ProgressBar1 na obiekcie StatusBar1:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 ProgressBar1 = new TProgressBar(StatusBar1);
 ProgressBar1->Parent = StatusBar1;
 ProgressBar1->Position = 50;
 ProgressBar1->Height = StatusBar1->Height - 2;
 ProgressBar1->Top = 2;
 ProgressBar1->Left = 2;
 ProgressBar1->Width = StatusBar1->Width - 2;
 ProgressBar1->Visible = true;
}
//--------------------------------

Jak nie trudno się domyślić w ten sam sposób można umieścić na StatusBar niemal każdy inny obiekt.

...powrót do menu. 

Zmiana czasu i daty systemowej.

Zmiany czasu i daty systemowej można dokonać za pomocą struktury date dostępnej w bibliotece dos.h, jednak ta metoda ma to do siebie, że nie działa w Windows XP, pomimo to jednak zaprezentuję ją pokrótce:

#include <dos.h> // należy włączyć ta bibliotekę do projektu.

// Plik źródłowy np. Unit1.cpp.

//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 int day = 26, month = 1, year = 2006;
 struct date d;
 d.da_day = (char)day;
 d.da_mon = (char)month;
 d.da_year = year;
 setdate(&d);
}
//--------------------------------

I to tyle jeśli chodzi o zmianę daty za pomocą dos'a. Teraz zaprezentuję funkcję SetLocalTime, która również zmienia datę systemową i działa w Windows XP:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 SYSTEMTIME czas;
 czas.wYear   = 2006;
 czas.wMonth  = 1;
 czas.wDay    = 23;
 czas.wHour   = 16;
 czas.wMinute = 11;

 SetLocalTime(&czas);
}
//--------------------------------

Ważna uwaga, jeśli chcemy zmienić np. tylko datę nie zmieniając czasu, to należy przekazać do struktury SYSTEMTIME aktualny czas, w przeciwnym razie może się zdarzyć, że zostanie ustawiony jakiś przypadkowy czas, to samo dotyczy daty, jeśli chcemy zmienić tylko czas, zresztą co istotne, jeżeli zmieniamy tylko jeden parametr to pozostałe należy ustawić na aktualne. Istnieje kilka sposobów na pobranie aktualnej daty i czasu, ale ja wykorzystam tutaj funkcję GetLocalTime, która również odczytuje aktualny czas:

// Plik źródłowy np. Unit1.cpp.
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 SYSTEMTIME systemTime;
 GetLocalTime(&systemTime);


 SYSTEMTIME czas;
 czas.wYear   = systemTime.wYear;
 czas.wMonth  = 2;
 czas.wDay    = 23;
 czas.wHour   = systemTime.wHour;
 czas.wMinute = systemTime.wMinute;
 czas.wSecond = systemTime.wSecond;

 SetLocalTime(&czas);
}
//--------------------------------

Zaprezentowana funkcja znajduje się w bibliotece Borland C++ Builder 6, nie wiem czy wcześniejsze wersje ją posiadają.

...powrót do menu.