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; } //-------------------------------- |
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); } //--------------------------------------------------------------------------- |
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):
.PageFaultCount - liczba błędów strony
.PageFileUsage - użycie pamięci wirtualne, pliku wymiany
.PeakPageFileUsage - maksymalna przestrzeń zarezerwowana w pliku wymiany
.PeakWorkingSetSize - szczytowe użycie pamięci RAM
.QuotaNonPagedPoolUsage - niestronicowana pula pamięci
.QuotaPagedPoolUsage - stronicowana pula pamięci
.QuotaPeakNonPagedPoolUsage - szczytowa niestronicowana pula pamięci
.QuotaPeakPagedPoolUsage - szczytowa stronicowana pula pamięci
.WorkingSetSize - użycie pamięci RAM
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; } //-------------------------------- |
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):
.PageFaultCount - liczba błędów strony
.PageFileUsage - użycie pamięci wirtualne, pliku wymiany
.PeakPageFileUsage - maksymalna przestrzeń zarezerwowana w pliku wymiany
.PeakWorkingSetSize - szczytowe użycie pamięci RAM
.QuotaNonPagedPoolUsage - niestronicowana pula pamięci
.QuotaPagedPoolUsage - stronicowana pula pamięci
.QuotaPeakNonPagedPoolUsage - szczytowa niestronicowana pula pamięci
.QuotaPeakPagedPoolUsage - szczytowa stronicowana pula pamięci
.WorkingSetSize - użycie pamięci RAM
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(); } //--------------------------------------------------------------------------- |
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ś
// 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:
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.
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.
// 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..
APPEND
BLASTER
COMSPEC
COPYCMD
DIRCMD
DOSSHELL
MSDOSDATA
NO_SEP
PATH
PROMPT
TEMP
TZ
CMDLINE
COMPUTERNAME
TMP
winbootdir
windir
WINPMT
ALLUSERSPROFILE
APPDATA
CD
CMDCMDLINE
CMDEXTVERSION
COMMONPROGRAMFILES
DATE
ERRORLEVEL
HOMEDRIVE
HOMEPATH
HOMESHARE
LOGONSERVER
MORE
NUMBER_OF_PROCESSORS
OS
OS2LIBPATH
PATHEXT
PROCESSOR_ARCHITECTURE
PROCESSOR_IDENTIFER
PROCESSOR_LEVEL
PROCESSOR_REVISION
PROGRAMFILES
RANDOM
SESSIONNAME
SYSTEMDRIVE
SYSTEMROOT
TIME
USERDOMAIN
USERNAME
USERPROFILE