Sprawdzanie nazwy konta na którym zalogował się użytkownik.

Do sprawdzenia nazwy konta na którym zalogował się użytkownik można posłużyć się funkcją GetUserName:

//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 char User[_MAX_PATH];
 DWORD size = sizeof(User);
 if(GetUserName(User, &size));
  Label1->Caption = (AnsiString)User;
}
//--------------------------------

...powrót do menu. 

Wyliczanie aktywnych procesów w systemie.

Żeby skorzystać z funkcji wyliczających aktywne procesy w systemie Windows, należy posłużyć się funkcjami zawartymi w bibliotece tlhelp32.h, więc należy włączyć tą bibliotekę do sekcji include.

//--------------------------------
#include <tlhelp32.h>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 void *Snap;
 PROCESSENTRY32 proces;

 Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS , 0);
 proces.dwSize = sizeof(PROCESSENTRY32);

 if(Process32First(Snap , &proces))
 {
  do
  {
   if(proces.szExeFile[ 0 ] != '[')
    ListBox1->Items->Add(proces.szExeFile);
  }
  while(Process32Next(Snap , &proces));
 }
 CloseHandle(Snap);
}
//--------------------------------

W powyższym przykładzie wykorzystano funkcję Process32First do wyszukiwania aktywnych procesów, jeżeli dodamy jeszcze funkcję Module32First to możliwe będzie wyliczenie aktywnych procesów i pobranie ścieżek dostępu do tychże procesów:

//--------------------------------
#include <tlhelp32.h>

BOOL EnumProcess(DWORD dwPID, LPCSTR ExeName)
{
 BOOL bRet;
 char *File;
 char buf[512];
 HANDLE hModuleSnap;
 MODULEENTRY32 me32 = {0};
 bRet = false;
 hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
 if(hModuleSnap == (HANDLE)-1) return false;

 me32.dwSize = sizeof(MODULEENTRY32);
 if(Module32First(hModuleSnap, &me32))
 {
  do{
     String fileA = (String)ExeName;
     String fileB = ExtractFileName((String)me32.szExePath);
     if(SameText(fileB, fileA))
     {
      Form1->ListBox1->Items->Add(fileA + " -> " + (String)me32.szExePath); // wynik zostaje wyświetlony w ListBox1
     }
     if(strcmpi(ExeName, buf) == 0)
     {
      bRet = true; break;
     }
    }
  while(Module32Next(hModuleSnap, &me32));
 }
 CloseHandle(hModuleSnap);
 return bRet;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button8Click(TObject *Sender)
{
 void *Snap;
 PROCESSENTRY32 proces;

 Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS , 0);
 proces.dwSize = sizeof(PROCESSENTRY32);

 if(Process32First(Snap , &proces))
 {
  do{
     if(proces.szExeFile[ 0 ] != '[')
     {
      EnumProcess(proces.th32ProcessID, proces.szExeFile);
     }
    }
  while(Process32Next(Snap , &proces));
 }
 CloseHandle(Snap);
}
//---------------------------------------------------------------------------

...powrót do menu. 

Sprawdzanie ile pamięci zużywa nasz program.

W celu sprawdzenia ile pamięci zużywa nasz program należy posłużyć się biblioteką psapi.h, więc należy włączyć tą bibliotekę do sekcji include. Sprawdzeniu ulega oczywiście tylko zużycie pamięci aktywnego procesu, czyli uruchomionego programu. Przedstawiony kod nie sprawdza zużycia pamięci przez inne procesy, a tylko przez własny program.

//--------------------------------
#include <psapi.h>
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 typedef BOOL (_stdcall *PGetProcessMemoryInfo)(HANDLE, void*, DWORD);

 PGetProcessMemoryInfo Memproc;
 HMODULE hMod;
 PROCESS_MEMORY_COUNTERS ProcMem;

 memset(&ProcMem, 0, sizeof(ProcMem));
 ProcMem.cb = sizeof(ProcMem);

 hMod = ::LoadLibrary("psapi.dll");

 if(!hMod) return;
 Memproc = (PGetProcessMemoryInfo)::GetProcAddress(hMod, "GetProcessMemoryInfo");
 if(!Memproc) return;
 if((*Memproc)(GetCurrentProcess(), &ProcMem, sizeof(ProcMem)))
  ShowMessage("Program wykorzystuje: " + IntToStr(ProcMem.WorkingSetSize / 1024) + " KB pamięci.");

 FreeLibrary(hMod);
}
//--------------------------------

Struktura PROCESS_MEMORY_COUNTERS zwraca znacznie więcej informacji o użyciu pamięci nie tylko RAM, ale również pamięci wirtualnej (pliku wymiany):

...powrót do menu. 

Sprawdzanie i zmiana priorytetu aplikacji.

Do sprawdzania priorytetu aplikacji służy funkcja GetPriorityClass, natomiast do zmiany priorytetu aplikacji służy funkcja SetPriorityClass. Jeżeli chcemy sprawdzić priorytet własnego programu, to zadanie jest o tyle proste, że wystarczy wywołać funkcję GetPriorityClass z argumentem GetCurrentProcess(). W przypadku zmiany priorytetu własnej aplikacji jest podobnie, wystarczy wywołać funkcję SetPriorytyClass z argumentem GetCurrentProcess(), określającym proces któremu zmieniamy priorytet oraz wartością priorytetu. Dostępne są cztery wartości dla priorytetów:

IDLE_PRIORITY_CLASS - niski
NORMAL_PRIORITY_CLASS - normalny
HIGH_PRIORITY_CLASS - wysoki
REALTIME_PRIORITY_CLASS - czasu rzeczywistego

Przykład sprawdzenia priorytetu własnej aplikacji:

//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 switch(GetPriorityClass(GetCurrentProcess()))
 {
  case IDLE_PRIORITY_CLASS:     Label1->Caption = "Niski"; break;
  case NORMAL_PRIORITY_CLASS:   Label1->Caption = "Normalny"; break;
  case HIGH_PRIORITY_CLASS:     Label1->Caption = "Wysoki"; break;
  case REALTIME_PRIORITY_CLASS: Label1->Caption = "Czasu rzecz."; break;
 }
}
//--------------------------------

Przykład zmiany na wysoki priorytetu własnej aplikacji:

//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
}
//--------------------------------

To były te prostsze zadania. Jeżeli chcemy zmienić priorytet innego procesu (programu), to musimy znać nazwę klasy tego procesu, lub nazwę jego okna, mając te dane możemy sprawdzić priorytet jaki został przypisany do takiej aplikacji. W poniższym przykładzie sprawdzany jest priorytet programu Borland C++ Builder (nazwa procesu: bcb.exe), nazwa klasy dla BCB to TAppBuilder:

//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 HANDLE hWnd = FindWindow("TAppBuilder", NULL);
 DWORD ThreadID;
 GetWindowThreadProcessId(hWnd, &ThreadID);
 HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, true, ThreadID);
 switch( GetPriorityClass(ProcessHandle) )
 {
  case IDLE_PRIORITY_CLASS:     Label1->Caption = "Niski"; break;
  case NORMAL_PRIORITY_CLASS:   Label1->Caption = "Normalny"; break;
  case HIGH_PRIORITY_CLASS:     Label1->Caption = "Wysoki"; break;
  case REALTIME_PRIORITY_CLASS: Label1->Caption = "Czasu rzecz."; break;
 }
}
//--------------------------------

Zmiana priorytetu dla wybranej aplikacji będzie wyglądała podobnie:

//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 HANDLE hWnd = FindWindow("TAppBuilder", NULL);
 DWORD ThreadID;
 GetWindowThreadProcessId(hWnd, &ThreadID);
 HANDLE ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, true, ThreadID);
 SetPriorityClass(ProcessHandle, NORMAL_PRIORITY_CLASS);
}
//--------------------------------

Funkcję pokazującą jak wyliczyć w systemie klasy aktywnych procesów podałem w poradzie wyliczanie okien, tutaj bym ją trochę jednak przerobił, żeby nieco graniczyć wyniki wyszukiwania:

//--------------------------------
bool CALLBACK EnumWindowsProc(HWND hWnd, TListView *ListView)
{
 char WindowName[80], ClassName[80];

 GetWindowText(hWnd, WindowName, 80);
 GetClassName(hWnd, ClassName, 80);
 if(!AnsiString(WindowName).IsEmpty())
 {
  HANDLE hWnd2 = FindWindow(ClassName, WindowName);
  if(hWnd2 && !IsWindowUnicode(hWnd2))
  {
   ListView->Items->Add();
   int i = ListView->Items->Count - 1;
   ListView->Items->Item[i]->Caption = AnsiString(WindowName);
   ListView->Items->Item[i]->SubItems->Add(AnsiString(ClassName));
   ListView->Items->Item[i]->Update();
  }
 }
 return true;
}
//--------------------------------

...powrót do menu. 

Sprawdzanie zużycia pamięci przez procesy uruchomione w systemie.

W poradzie 'sprawdzanie ile pamięci zużywa nasz program' pokazałem sposób na sprawdzenie zużycia pamięci przez program, który tą funkcję wywołuje. Uchwyt do procesu został tam pobrany poprzez funkcję GetCurrentProcess(), podstawiając w to miejsce uchwyt do innego procesu, możemy sprawdzić ile pamięci taki proces zużywa, wymaga to otwarcia procesu i uzyskania do niego pełnego dostępu funkcję OpenProcess, tutaj od razu nadmienię, że do pewnych procesów systemowych, sam system dostępu nie chce udzielić i tak np. nie udało mi się uzyskać dostępu do procesów 'csrss.exe' i 'alg.exe'. W poradzie 'sprawdzanie i zmiana priorytetu aplikacji' również została użyta funkcja OpenProcess, a jako pierwszy argument została jej przekazana wartość PROCESS_ALL_ACCESS, to jest żądanie pełnego dostępu do procesu i jeżeli od procesów systemowych również zażądamy pełnego dostępu, to jak łatwo się domyślić nie uzyskamy go, dlatego jako pierwszy argument należy podać  PROCESS_QUERY_INFORMATION co jest prośbą o dostęp do informacji o procesie, a więc bez możliwości ingerencji w sam proces.
Do realizacji tego zadania trzeba stworzyć trzy odrębne funkcje, które będą ze sobą współpracowały. Funkcja GetMemory będzie odczytywała informacje o zużyci pamięci przez proces przekazany jej jako argument i będzie zwracała wynik w postaci zmienne typu AnsiString. Funkcja GetMemory pobiera jako argument numer procesu, czyli jego identyfikator, dlatego potrzebna jest kolejna funkcja wyliczająca uruchomione w systemie procesy i tutaj zaproponuję dwie różne funkcje.
    Pierwsza z nich EnumWindowProc będzie zliczała nie tyle wszystkie procesy uruchomione w systemie ile uruchomione programy, czyli zliczanie będzie odbywało się w oparciu o okna programów. Żeby ograniczyć liczbę zaindeksowanych okien wprowadziłem do niej funkcję filtrującą IsWindowVisible - ograniczająca indeksowanie tylko do okien widocznych na pasku zadań, to znaczy że programy zminimalizowane do zasobnika systemowego (systray) nie zostaną zaindeksowane. Chciałem w ten sposób uzyskać taki efekt jaki mamy w Menadżerze zadań na zakładce Aplikacje, jednak nie udało mi się znaleźć sposobu na ograniczenie indeksowania tylko dla aplikacji na pasku zadań, więc indeksowany jest zarówno pasek zdań jak i samo okno programu, dlatego będą się one powtarzać na liście.
    Druga funkcja GetProcess pobiera nazwy procesów uruchomionych w systemie, czyli dokładnie to co widać w Menadżerze zadań na zakładce Procesy i tutaj już nie ma problemu z powtarzaniem się tych samych procesów.
Zanim przystąpimy do pisania kodu, umieszczamy na formularzu komponent ListBox1 i dwa komponenty Button1 i Button2. W zdarzeniu OnClick dla przycisku Button1 zostanie wywołana funkcja EnumWindow indeksująca programy w oparciu o okna, natomiast w zdarzeniu OnClick przycisku Button2 zostanie wywołana funkcja GetProces indeksująca procesy. W obiekcie ListBox1 będzie wyświetlana lista okien wraz ze zużyciem pamięci jeśli zostanie naciśnięty przycisk Button1, lub lista procesów również ze zużyciem pamięci po wybraniu przycisku Button2. Do projektu należy włączyć dwie biblioteki:
#include <psapi.h> i #include <tlhelp32.h>

//--------------------------------
#include <psapi.h>
AnsiString GetMemory(DWORD ThreadID)
{
 typedef BOOL (_stdcall *PGetProcessMemoryInfo)(HANDLE, void*, DWORD);
 String Result;
 PGetProcessMemoryInfo Memproc;
 HMODULE hMod;
 PROCESS_MEMORY_COUNTERS ProcMem;

 memset(&ProcMem, 0, sizeof(ProcMem));
 ProcMem.cb = sizeof(ProcMem);

 hMod = ::LoadLibrary("psapi.dll");

 HANDLE ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION , true, ThreadID);

 if(!hMod) return "access denied";
 Memproc = (PGetProcessMemoryInfo)::GetProcAddress(hMod, "GetProcessMemoryInfo");
 if(!Memproc) return "access denied";
 if((*Memproc)(ProcessHandle, &ProcMem, sizeof(ProcMem)))
  Result = FloatToStrF(ProcMem.WorkingSetSize / 1024, ffNumber, 7, 0) + " KB";
 else
  Result = "access denied";

 FreeLibrary(hMod);
 return Result;
}
//---------------------------------------------------------------------------
bool CALLBACK EnumWindowsProc(HWND hWnd, TStrings *EnumList)
{
 char WindowName[255];
 DWORD ID;
 GetWindowText(hWnd, WindowName, 255);
 GetWindowThreadProcessId(hWnd, &ID);

 if(*WindowName != '\0')
 {
  if(IsWindowVisible(hWnd) >= 1)
  {
   String tmp = (String)WindowName + " - " + GetMemory(ID);
   if(EnumList->IndexOf(tmp) < 0)
    EnumList->Add((String)WindowName + " - " + GetMemory(ID));
  }
 }
 return true;
}
//---------------------------------------------------------------------------
#include <tlhelp32.h>
void __fastcall GetProcess(TStrings *ProcList)
{
 HWND Snap;
 PROCESSENTRY32 proces;

 Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 proces.dwSize = sizeof(PROCESSENTRY32);

 if(Process32First(Snap, &proces))
 {
  do
  {
   if(proces.szExeFile[0] != '[')
   {
    ProcList->Add((String)(String)proces.szExeFile + " - " + GetMemory(proces.th32ProcessID));
   }
  }
  while(Process32Next(Snap , &proces));
 }
 CloseHandle(Snap);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 ListBox1->Items->Clear();
 EnumWindows((WNDENUMPROC)EnumWindowsProc, (LPARAM)ListBox1->Items);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 ListBox1->Items->Clear();
 GetProcess(ListBox1->Items);
}
//--------------------------------

Struktura PROCESS_MEMORY_COUNTERS zwraca znacznie więcej informacji o użyciu pamięci nie tylko RAM, ale również pamięci wirtualnej (pliku wymiany):

 

...powrót do menu. 

Zamykanie procesów.

Nie trzeba chyba nikomu wyjaśniać czym jest zamykanie procesów, możemy to zrobić np. za pomocą Menadżera zadań wybierając jakiś proces na zakładce Procesy, a potem przycisk 'Zakończ proces'. Niniejsza porada opiera się na mechanizmie, który został zastosowany w poradzie 'sprawdzanie zużycia pamięci przez procesy uruchomione w systemie', z tym, że tutaj funkcja zamiast funkcji pobierającej informacje o pamięci została stworzona funkcja CloseProcess, wykorzystująca inną gotową funkcję TerminateProcess kończąca działanie dowolnego procesu. Nie jest jednak tak, że można zamknąć każdy proces, do niektórych procesów systemowych, system nie udzieli dostępu i nie pozwoli go zamknąć.
Nie będę w tej poradzie wyjaśniał mechanizmów działania, bo można o nich przeczytać w wymienionej wyżej poradzie, wspomnę jednak, że tym razem posłużymy się dodatkowym obiektem WindowList typu TStringList, który będzie przechowywał informacje o oknach i procesach uruchomionych w systemie oraz numery identyfikacyjne tych procesów niezbędne do ich zamknięcia. Procesy będą zamykane na dwa sposoby, jeden poprzez wybranie z listy ListBox1 nazwy okna, a drugi sposób poprzez wybranie z ListBox1 nazwy procesu. To czy w ListBox1 znajdą się nazwy okien czy nazwy procesów, będzie zależało od tego, którą z dwóch funkcji indeksujących wybierzemy poprzez przyciski. Po wybraniu Button1 na liście zostaną umieszczone nazwy okien, natomiast po wybraniu Button2 nazwy procesów. Z listy WindowList zostaną do ListBox1 przepisane tylko nazwy okien lub procesów bez ich numerów identyfikacyjnych, te będą przechowywane na liście WindowList, dlatego należy zadeklarować ją jako obiekt globalny w pliku nagłówkowym w sekcji private, a potem zdefiniować w konstruktorze klasy formularza.
W przedstawionym niżej kodzie da się zauważyć jeszcze jeden, być może dla niektórych niezrozumiały element, otóż jest to obiekt SelButton typu TComponent, a służy on do zapamiętania przez program, na który przycisk ostatnio kliknęliśmy, żeby po usunięciu wybranego na liście procesu odświeżyć tą listę zgodnie z wcześniejszym wyborem, czyli jeżeli wybraliśmy indeksowanie procesów na podstawie okien programów to program to zapamięta i po usunięciu z listy wybranego procesu odświeży ją zgodnie z wyborem i ponownie umieści na niej nazwy okien a nie nazwy procesów. Procesy będą zamykane po dwukrotnym kliknięciu na ListBox1.

// Plik nagłówkowy np. Unit1.h
//--------------------------------
private:
        TStringList *WindowList;
 

 

// Plik źródłowy np. Unit1.cpp
//--------------------------------
_fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 WindowList = new TStringList;
}
//---------------------------------------------------------------------------
bool CALLBACK EnumWindowsProc(HWND hWnd, TStrings *EnumList)
{
 char WindowName[80];
 DWORD ID;
 GetWindowText(hWnd, WindowName, 80);
 GetWindowThreadProcessId(hWnd, &ID);
 if(!AnsiString(WindowName).IsEmpty())
 {
  if(IsWindowVisible(hWnd) >= 1)
  {
   String tmp = (String)WindowName + "=" + (String)ID;
   if(EnumList->IndexOf(tmp) < 0)
    EnumList->Add((String)WindowName + "=" + (String)ID);
  }
 }
 return true;
}
//---------------------------------------------------------------------------
#include <tlhelp32.h>
void __fastcall GetProcess(TStrings *ProcList)
{
 HWND Snap;
 PROCESSENTRY32 proces;

 Snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
 proces.dwSize = sizeof(PROCESSENTRY32);

 if(Process32First(Snap, &proces))
 {
  do
  {
   if(proces.szExeFile[0] != '[')
   {
    ProcList->Add((String)(String)proces.szExeFile + "=" + (String)proces.th32ProcessID);
   }
  }
  while(Process32Next(Snap , &proces));
 }
 CloseHandle(Snap);
}
//---------------------------------------------------------------------------
bool CloseProcess(DWORD ID)
{
 DWORD ExitCode;
 HWND hWnd;
 bool Result = true;

 if(ID)
 {
  hWnd = OpenProcess(PROCESS_ALL_ACCESS, true, ID);
  if(hWnd)
  {
   GetExitCodeProcess(hWnd, &ExitCode);
   Result = TerminateProcess(hWnd, ExitCode);
  }
  else return false;
 }
 else return false;

 CloseHandle(hWnd);
 return Result;
}
//---------------------------------------------------------------------------
TComponent *SelButton;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 SelButton = dynamic_cast<TButton *>(Sender);
 ListBox1->Items->Clear();
 WindowList->Clear();

 EnumWindows((WNDENUMPROC)EnumWindowsProc,(LPARAM)WindowList);

 for(int i = 0; i < WindowList->Count; i++)
  ListBox1->Items->Add(WindowList->Names[i]);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 SelButton = dynamic_cast<TButton *>(Sender);
 ListBox1->Items->Clear();
 WindowList->Clear();

 GetProcess(WindowList);

 for(int i = 0; i < WindowList->Count; i++)
  ListBox1->Items->Add(WindowList->Names[i]);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListBox1DblClick(TObject *Sender)
{
 if(CloseProcess((DWORD)WindowList->Values[ListBox1->Items->Strings[ListBox1->ItemIndex]].ToInt()))
  Application->MessageBox("Proces został pomyślnie zamknięty!", "Procesy", MB_OK | MB_ICONINFORMATION);
 else
  Application->MessageBox((
   "Operacja nie może być dokończona!\n\nBrak dostępu!\nKod błędu: " + (String)GetLastError()).c_str(),
   "Procesy", MB_OK | MB_ICONSTOP);

 dynamic_cast<TButton *>(SelButton)->Click();
}
//---------------------------------------------------------------------------


...powrót do menu. 

Uruchamianie programu z poświadczeniami dla wybranego użytkownika (tylko WinXP).

W Windows XP po wywołaniu menu kontekstowego dla dowolnego programu (*.exe) znajduje się polecenie 'Uruchom jako...' pozwalające na uruchomienie tegoż programu z poświadczeniami dla dowolnego użytkownika, którego konto znajduje się w systemie, czyli jeżeli jesteśmy np. zalogowani na koncie użytkownika "Cyfrowy Baron" i powiedzmy że ten użytkownik nie posiada uprawnień administratora, to jak wiadomo nie może np. instalować programów. Możemy jednak za pomocą polecenia 'Uruchom jako...', uruchomić dany program z poświadczeniami administratora podając login i hasło. To polecenie pozwala uruchamiać programy nie tylko dla konta administratora, lecz dla wszystkich kont, koniecznym warunkiem jest znajomość hasła do danego konta.
Jeżeli nie zrozumiałeś
(~łaś), to ta porada nie jest dla Ciebie i nie czytaj tego dalej, bo prawdopodobnie nie zrozumiesz.
Korzystając z funkcji CreateProcessWithLogonW możemy wymusić uruchomienie dowolnego programu z poświadczeniami dla wybranego użytkownika, wystarczy przekazać w tym celu funkcji trzy argumenty: nazwę użytkownika, hasło i ścieżkę dostępu do uruchamianego pliku.

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 STARTUPINFOW si = { 0 };
 PROCESS_INFORMATION pi = { 0 };
 String wUserName = "Uzytkownik";
 String wPassword = "haslo";
 String wExecute = "C:\\totalcmd\\Totalcmd.exe";
 String wFile = "Totalcmd.exe";

 si.cb = sizeof(si);
 CreateProcessWithLogonW(WideString(wUserName).c_bstr(), NULL,
                         WideString(wPassword).c_bstr(), LOGON_WITH_PROFILE,
                         WideString(wExecute).c_bstr(), WideString(wFile).c_bstr(),
                         CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi);
}
//---------------------------------------------------------------------------


Funkcja zadziała prawidłowo tylko na koncie dla którego utworzono hasło.
Jeżeli w Windows spróbujemy użyć polecenia 'Uruchom jako...' na koncie bez hasła to otrzymamy następujący komunikat:
"Błąd logowania: Ograniczenie konta użytkownika. Do możliwych przyczyn należą: niedozwolone puste hasła, ograniczenie godzin logowania lub wymuszanie ograniczenia zasad."

Przy użyciu funkcji w takiej samej sytuacji taki komunikat się oczywiście nie pojawi, program po prostu się nie uruchomi. Można zastosować warunek, jeżeli uruchomienie się powiedzie to funkcja zwraca wartość większą od zera, jeśli się nie powiedzie to funkcja zwróci 0.

...powrót do menu. 

Sprawdzanie ile czasu upłynęło od uruchomienia systemu.

Przedstawiony w tej poradzie kod sprawdza ile czasu upłynęło od chwili uruchomienia systemu. Kod można wywołać w dowolnym momencie od chwili załadowania systemu, oznacza to, że nie zachodzi konieczność uruchamiania jakiegokolwiek programu w chwili uruchomienia systemu i zapisywania czasu uruchomienia systemu. Nie ma potrzeby tworzenia programu monitorującego czas pracy systemu, wystarczy w dowolnym momencie uruchomić program i kliknąć np. na przycisku Button1, żeby sprawdzić ile czasu upłynęło od zabototwania.

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 LARGE_INTEGER freq, counter, sec, time;
 QueryPerformanceFrequency(&freq);
 QueryPerformanceCounter(&counter);
 sec.QuadPart = counter.QuadPart / freq.QuadPart;
 int h = sec.QuadPart/3600;
 time.QuadPart = sec.QuadPart - (h * 3600);
 int m = time.QuadPart/60;
 time.QuadPart = time.QuadPart - (m * 60);
 AnsiString hour = IntToStr(h);
 hour += " godz. ";
 hour += IntToStr(m);
 hour += " min. ";
 hour += IntToStr(time.QuadPart);
 hour += " sek.";
 Edit1->Text = hour;
}
//---------------------------------------------------------------------------

Zaprezentowany kod stanowi alternatywę dla porady 'sprawdzanie ile czasu uruchomiony jest Windows'.

...powrót do menu. 

Odczytywanie klucza instalacyjnego Windows.

W życiu każdego informatyka może zdarzyć się sytuacja, gdy gubi klucz instalacyjny systemu. Stwarza to poważny problem, ponieważ nie można zainstalować systemu z oryginalnego "krążka", nie mając doń klucza. W przypadku systemu Windows 95/98 można było bez problemu odczytać ten klucz z rejestru, ale z systemem WindowsXP jest trudniej, ponieważ klucz nie występuje w rejestrze w postaci jawnej, lecz jest zakodowany w postaci binarnej, co uniemożliwia jego podejrzenie. Klucz znajduje się w kluczu rejestru 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion' 'DigitalProductId', a ta porada jest o tym, jak za pomocą prostej funkcji wyciągnąć ten klucz z rejestru i go wyświetlić np. w obiekcie Edit1. Nie będę objaśniał działania funkcji, Ci którym na tym zależy niech ją sobie przeanalizują, a pozostali mogą ją po prostu skopiować i użyć:
 

// Plik źródłowy np. Unit1.cpp
//--------------------------------
AnsiString GetProductKey()
{
 String strResult;
 HKEY hRegistryKey;
 BYTE *DigitalProductID;
 DWORD DataLength;
 BYTE ProductKeyExtract[15];
 char sCDKey[256];
 long ByteCounter;
 long ByteConvert;
 int nCur;
 char *KeyChars[] = {"B", "C", "D", "F", "G", "H", "J", "K", "M", "P", "Q",
                     "R", "T", "V", "W", "X", "Y", "2", "3", "4", "6", "7",
                     "8", "9", NULL};

 if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
    "SOFTWARE\\MICROSOFT\\Windows NT\\CurrentVersion",
    REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, &hRegistryKey) == ERROR_SUCCESS)
 {
  DataLength = 164;
  DigitalProductID = (BYTE *)malloc(DataLength);
  memset(DigitalProductID, 0, DataLength);
  if(RegQueryValueEx(hRegistryKey, "DigitalProductId",
     NULL, NULL, DigitalProductID, &DataLength) == ERROR_SUCCESS)
  {
   for(ByteCounter = 52; ByteCounter <= 66; ByteCounter++)
   {
    ProductKeyExtract[ByteCounter - 52] = DigitalProductID[ByteCounter];
   }
   ProductKeyExtract[sizeof(ProductKeyExtract)] = NULL;
  }
 }

 memset(sCDKey, 0, sizeof(sCDKey));

 for(ByteCounter = 24; ByteCounter >= 0; ByteCounter--)
 {
  nCur = 0;
  for(ByteConvert = 14; ByteConvert >= 0; ByteConvert--)
  {
   nCur = (nCur * 256) ^ ProductKeyExtract[ByteConvert];
   ProductKeyExtract[ByteConvert] = nCur / 24;
   nCur = nCur % 24;
  }
  strrev(sCDKey);
  strcat(sCDKey, KeyChars[nCur]);
  strrev(sCDKey);

  if(!(ByteCounter % 5) && (ByteCounter))
  {
   strrev(sCDKey);
   strcat(sCDKey, "-");
   strrev(sCDKey);
  }
 }

 RegCloseKey(hRegistryKey);
 if(DigitalProductID) delete DigitalProductID;

 return (AnsiString)sCDKey;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
 Edit1->Text = GetProductKey();
}
//---------------------------------------------------------------------------

...powrót do menu. 

Wywoływanie okna właściwości pliku.

Z menu kontekstowego dla dowolnego pliku możemy wybrać polecenie 'Właściwości', które to polecenie wywołuje okno 'Właściwości' dla wybranego pliku. W BCB też możemy skorzystać ze struktury SHELLEXECUTEINFO umożliwiającej wywołanie właśnie okna właściwości pliku. W przykładzie stworzę funkcję o nazwie ShowProperties pobierającą jeden argument będący ścieżką dostępu do pliku dla którego chcemy wyświetlić okno 'Właściwości'. Całość jest banalnie prosta, więc nie będę tego wyjaśniał:
 

// Plik źródłowy np. Unit1.cpp
//--------------------------------
void ShowProperties(String FileName)
{
 SHELLEXECUTEINFO ShExecInfo ={0};
 ShExecInfo.cbSize = sizeof(ShExecInfo);
 ShExecInfo.fMask = SEE_MASK_INVOKEIDLIST ;
 ShExecInfo.hwnd = GetDesktopWindow();
 ShExecInfo.lpVerb = "properties";
 ShExecInfo.lpFile = FileName.c_str();
 ShExecInfo.lpParameters = "";
 ShExecInfo.lpDirectory = NULL;
 ShExecInfo.nShow = SW_SHOW;
 ShExecInfo.hInstApp = NULL;
 ShellExecuteEx(&ShExecInfo);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
 ShowProperties("c:\\windows\\clock.avi");
}
//---------------------------------------------------------------------------

...powrót do menu. 

Obliczanie częstotliwości procesora.

Myślę, że każdy użytkownik komputera wie z jaką częstotliwością pracuje jego procesor, więc ta porada jest raczej mało praktyczna, ponieważ pozwala tylko na sprawdzenie częstotliwości procesora. Nie bez powodu umieściłem w tytule porady określenie 'obliczanie', ponieważ sprawdzenie tej częstotliwości będzie się odbywało poprzez obliczenie różnicy czasu jaka upłynie pomiędzy wywołaniem funkcji QueryPerformanceFrequency i QueryPerformanceCounter, w związku z tym zwłoka w działaniu funkcji wyniesie do 1 sekundy. Przedstawiony kod wykorzystuje wstawki asemblerowe.
 

// Plik źródłowy np. Unit1.cpp
//--------------------------------
double RDTSC(void)
{
 unsigned long a, b;
 double x;
 asm
 {
  db 0x0F,0x31
  mov [a],eax
  mov [b],edx
 }
 x = b;
 x *= 4294967296;
 x += a;
 return x;
}
//---------------------------------------------------------------------------
bool FrequenceCpu (double* frequence)
{
 unsigned __int64 Fwin;
 unsigned __int64 Twin_avant, Twin_apres;
 double Tcpu_avant, Tcpu_apres;
 double Fcpu;

 if(!QueryPerformanceFrequency((LARGE_INTEGER*)&Fwin)) return false;

 Tcpu_avant = RDTSC();
 QueryPerformanceCounter((LARGE_INTEGER*)&Twin_avant);

 do
 {
  QueryPerformanceCounter((LARGE_INTEGER*)&Twin_apres);
 }while(Twin_apres - Twin_avant < 10000);

 Tcpu_apres = RDTSC();
 QueryPerformanceCounter((LARGE_INTEGER*)&Twin_apres);

 Fcpu = (Tcpu_apres - Tcpu_avant);
 Fcpu *= Fwin;
 Fcpu /= (double)(Twin_apres - Twin_avant);
 *frequence = Fcpu;
 return true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button5Click(TObject *Sender)
{
 double freq;
 if(FrequenceCpu(&freq))
 if(freq/1000000 < 1000)
  Label1->Caption = FloatToStrF(freq/1000000, ffNumber, 7, 0) + " MHz";
 else
  Label1->Caption = FloatToStrF(freq/1000000000, ffNumber, 7, 2) + " GHz";
}
//---------------------------------------------------------------------------

...powrót do menu. 

Odczytywanie identyfikatora procesora i zmiennych środowiskowych.

Niewiele osób zdaje sobie pewnie sprawę z istnienia bardzo przydatnej funkcji getenv przy pomocy której można odczytać identyfikator procesora i zmienne śropdowiskowe.

Przykład odczytania identyfikatora procesora:
 

// Plik źródłowy np. Unit1.cpp
//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
 Label1->Caption = StrUpper( getenv("PROCESSOR_IDENTIFIER") );
}
//---------------------------------------------------------------------------

 

Wykorzystując tą samą funkcję możemy odczytać np. ścieżkę dostępu do katalogu Program Files:
 

// Plik źródłowy np. Unit1.cpp
//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
 Label1->Caption = getenv("PROGRAMFILES");
}
//---------------------------------------------------------------------------

Funkcja pobiera jeden argument i jest to typ odczytywanej wartości, zmiennej środowiskowej.
Jeżeli chcielibyśmy zmienić jakąś zmienną środowiskową, to należy posłużyć się funkcją putenv:

// Plik źródłowy np. Unit1.cpp
//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
 Label1->Caption = putenv("PATH=D:\\WINDOWS");
}
//---------------------------------------------------------------------------

Jak widać funkcja putenv również pobiera jeden argument i jest to typ zmiennej środowiskowej którą chcemy zmienić plus znak równości plus nowa wartość wprowadzana. W przykładzie podałem jako typ zmiennej środowiskowej wartość PATH, która odpowiada ścieżce dostępu do katalogu Windows, następnie wprowadziłem nową wartość po znaku równości. Należy uważać przy korzystaniu z funkcji putenv, bo może się okazać, że po zmianie jakiejś zmiennej środowiskowej komputer się już nie uruchomi.

Niżej przedstawiam listę niektórych argumentów, które można przekazać funkcji getenv, nie wszystkie argumenty można zastosować w odniesieniu do funkcji putenv, niektóre zmienne środowiskowe odnoszą się tylko do konkretnego systemu operacyjnego..

...powrót do menu. 

 

 

 

 

 

 

Zamiast funkcji: FloatToStrF można użyć IntToStr, ale wtedy liczba nie zostanie sformatowana, czyli nie będzie wyświetlana z separatorem tysiąca.
Ten fragment kodu zapobiega ponownemu umieszczeniu na liście tego samego okna.
proces.szExeFile - nazwa pliku procesu
proces.th32ProcessID - numer identyfikacyjny procesu
ID - numer identyfikacyjny procesu uzyskany poprzez funkcję GetWindowThreadProcessId
Konstruktor klasy formularza Form1.
Funkcja wyliczająca okna uruchomionych programów.
Funkcja wyliczająca procesy.
Funkcja sprawdzajaca zużycie pamięci przez proces.
Funkcja kończąca działanie procesu.
Program zapamiętuje, że kliknięto w Button1.
Program zapamiętuje, że kliknięto w Button2.
Odświeżenie listy poprzez odwołanie się do zapamiętanego zdarzenia.
Ten argument można pominąć, ale wtedy należy przekazać bezpośrednio do funkcji wartość NULL.
Zaleca się jednak podawanie tego argumentu.
Zamiast tego argumentu można tutaj wstawić wartość NULL.
WideString(AnsiString).c_bstr() - funkcja konwertująca zmienną typu AnsiString na 16-bitową zmienną wchar_t, ponieważ takiego typu oczekuje funkcja.
Uchwyt do pulpitu. Można też pobrać uchwyt do programu, ale wtedy należałoby przekazać funkcji jeszcze jeden argument pobierajacy wskaźnik do programu.
Rodzaj danych przekazywanych strukturze. W tym przypadku są to właściwości pliku.
Ścieżka dostępu do pliku dla którego właściwosći chcemy wyswietlić. Struktura oczekuje tutaj zmiennej typu char, dlatego zastosowano konwersję ze zmiennej AnsiString na char [.c_str()]