Powrót do strony wyboru lekcji

Programowanie wykorzystujące
wielozadaniowość systemu 1



Każdy plik wykonywalny w momencie uruchomienia tworzy tzn. Proces . W odróżnieniu od pojęcia Programu, który jest po prostu plikiem wykonywalnym na dysku, proces ma charakter dynamiczny. Jego stan zmienia się w czasie. Zmianie ulegają między innymi:


Na swoje potrzeby każdy proces otrzymuje od systemu operacyjnego następujące składniki:
   Biorąc pod uwagę rodzinę systemów Windows 32-biotywch począwszy od Windowsa 9x, następnie Windows NT itd. zastosowano tzw. mechanizm wielozadaniowości z wywłaszczeniem. Takie rozwiązanie pozwala na szybkie przełączenie przez system operacyjny pomiędzy wykonującymi się w tym samym czasie wątkami i procesami, tak aby użytkownik odniósł wrażenie iż wykonują się one jednocześnie.

Przykład

Tworzymy program uruchamiający proces programu Kalkulator i kończący działanie tego procesu poprzez wciśnięcie odpowiedniego przycisku w oknie. Na początku definiujemy standardowo typ instrukcji procesora, określamy model pamięci jako płaski z wywołaniem procedur typu STDCALL. Dołączamy także odpowiednie biblioteki: user32.lib i kernel32.lib:


.586 ;typ instrukcji procesora

.MODEL FLAT,STDCALL

includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib

Następnie określamy stałe potrzebne do użycia kontrolek w programie:


IDC_BTN1      EQU   101

IDC_BTN2      EQU   102

Następnie stałe związane z komunikatami obsługiwanymi w oknie:


STARTF_USESHOWWINDOW          EQU   1h
SW_SHOWMINIMIZED              EQU   2
WM_INITDIALOG                 EQU   110h
WM_CLOSE                      EQU   10h
WM_COMMAND                    EQU   111h

Stała STARTF_USESHOWWINDOW włącza pole dwShowWindow. Jest to jedno z pól struktury STARTUP, którą musimy przekazać jako parametr inicjujący funkcji CreateProcessA@40 inicjującej proces. Funkcja ta zostanie opisana poniżej. Stała SW_SHOWMINIMIZED aktywuje okno i wyświetla je w trybie zminimalizowanym, chyba że okno nie posiada takiej funkcji. Następnie definiujemy potrzebne funkcje API:


EXTERN TerminateProcess@8:NEAR

EXTERN CreateProcessA@40:NEAR

EXTERN EndDialog@8:NEAR

EXTERN GetModuleHandleA@4:NEAR

EXTERN DialogBoxParamA@20:NEAR

EXTERN ExitProcess@4:NEAR

Nowymi w porównaniu do poprzednich przykładów są tu funkcje: TerminateProcess@8 i CreateProcessA@40 .CreateProcessA@40 tworzy proces, przyjmując jednocześnie podczas wywołania 10 parametrów. Postać funkcji CreateProcessA@40 w API przedstawiona jest na poniższym listingu:


BOOL WINAPI CreateProcess(

LPCTSTR lpApplicationName,
LPTSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCTSTR lpCurrentDirectory,
LPSTARTUPINFO lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);

Pierwszy parametr - lpApplicationName to nazwa uruchomionego programu. Następnie parametr lpCommandLine określa tekst startowego wiersza poleceń, jeśli parametr 1 jest różny od null. Parametr 3 i 4 - lpProcessAttributes i lpThreadAttributes to atrybuty dostępu do procesu najczęściej równe 0. Piąty parametr jeśli otrzyma wartość zerową to wygenerowany proces nie dziedziczy deskryptorów procesu generującego. Jeśli jednak wartość ta jest niezerowa to będzie dziedziczył deskryptory. Szósty parametr pozwala na zmianę właściwości generowanego procesu. Jeżeli nadana zostanie mu wartość zerowa, to wtedy proces otrzymuje domyślne właściwości. Siódmy parametr jest wskaźnikiem na bufor przechowujący parametry środowiska. Wartość zerowa oznacza, iż dziedziczy owe parametry od środowiska generującego go procesu. Ósmy parametr określa aktualny dysk i katalog generowanego procesu. Wartość 0 powoduje że proces dziedziczy aktualny napęd i katalog generującego procesu. Dziewiąty parametr jest wskaźnikiem na strukturę przechowującą informacje o oknie tworzonego procesu. Struktura zostanie przedstawiona poniżej. 10 parametr to również wskaźnik na strukturę, która jest wypełniona po uruchomieniu aplikacji. Struktura przekazywana w 9 parametrze wygląda następująco:


STARTUP STRUC
cb                DD      0 ;rozmiar struktury w bajtach
lpReserved        DD      0 ;zarezerwowane, musi być zerem
lpDesktop         DD      0 ;nazwa pulpitu
lpTitle           DD      0 ;tytuł okna dla aplikacji konsolowych.
dwX               DD      0 ;współrzędna X lewego górnego roku okna
dwY               DD      0 ;współrzędna Y lewego górnego roku okna
dwXSize           DD      0 ;szerokość okna
dwYSize           DD      0 ;wysokość okna
dwXCountChars     DD      0 ;rozmiar bufora konsoli (współrzędne X)
dwYCountChars     DD      0 ;rozmiar bufora konsoli (współrzędne Y)
dwFillAttribute   DD      0 ;początkowe kolory tekstu dla aplikacji konsolowych
dwFlags           DD      0 ;znaczniki wartości pól
wShowWindow       DW      0 ;definiuje tryb wyświetlania okna
cbReserved2       DW      0 ;zarezerwowane
lpReserved2       DD      0
hStdInput         DD      0 ;deskryptor wejścia dla konsoli
hStdOutput        DD      0 ;deskryptor wyjścia dla konsoli
hStdError         DD      0 ;deskryptor wyświetlania komunikatów o błędach
STARTUP ENDS

Struktura podawana w dziesiątym parametrze funkcji CreateProcessA@40 - PROCINF przedstawia się następująco:


PROCINF STRUC
hProcess   DD      ? ;deskryptor utworzonego procesu
hThread    DD      ? ;deskryptor głównego wątku utworzonego procesu
idProc     DD      ? ;identyfikator nowego procesu
idThr      DD      ? ;identyfikator głównego wątku nowego procesu
PROCINF ENDS

Funkcja TerminateProcess@8 powoduje natomiast zakończenie uruchomionego procesu. Sekcja danych naszego programu wygląda następująco:


.DATA
HINST         DD    ?
PA            DB   'IDD_DLG1',   0 ;nazwa dialogu
PATH          DB    "C:\WINDOWS\system32\calc.exe",   0
STRUP         STARTUP       <?>
INF           PROCINF       <?>

Zmienna PATH to ścieżka do programu który uruchomimy w procesie. Zmienne STRUP i INF określają odpowiednio struktury STARTUP i PROCINF. Początkowy fragment sekcji kodu programu wygląda podobnie jak w przykładach poprzednich. W procedurze obsługi okna przechodzimy w zależności od otrzymanego komunikatu do odpowiedniej sekcji jego obsługi:


.CODE

START:

PUSH  0
CALL  GetModuleHandleA@4
MOV  [HINST],EAX

PUSH  0
PUSH  OFFSET  WNDPROC
PUSH  0
PUSH  OFFSET  PA
PUSH  [HINST]
CALL  DialogBoxParamA@20

PUSH  0
CALL  ExitProcess@4

;parametry:
;[EBP +14H] LPARAM
;[EBP +10H] WPARAM
;[EBP +0CH] MES
;[EBP +8] HWND

WNDPROC   PROC


PUSH  EBP
MOV  EBP,ESP
PUSH  EBX
PUSH  ESI
PUSH  EDI

CMP  DWORD  PTR  [EBP + 0CH],WM_CLOSE;komunikat związany ze zniszczeniem okna
JNE  WYKONANIE
JMP  KONCZ


WYKONANIE:

CMP  DWORD  PTR  [EBP + 0CH],WM_COMMAND;komunikat związany z kontrolkami
JNE  FINISH

CMP  WORD  PTR  [EBP + 10H],IDC_BTN1  ;czy uruchamiamy proces?
JNE  CZYZAKONCZYC
JMP  URUCHOM

KONCZ:

PUSH  0
PUSH  DWORD  PTR  [EBP+ 08H]
CALL  EndDialog@8
JMP  FINISH

URUCHOM:

W sekcji odpowiedzialnej za uruchomienie nowego procesu, poprzez wciśnięcie odpowiedniego przycisku przez użytkownika, wypełniamy strukturę STRUP i tworzymy nowy proces:


.CODE

START:

PUSH  0
CALL  GetModuleHandleA@4
MOV  [HINST],EAX

PUSH  0
PUSH  OFFSET  WNDPROC
PUSH  0
PUSH  OFFSET  PA
PUSH  [HINST]
CALL  DialogBoxParamA@20

PUSH  0
CALL  ExitProcess@4

;parametry:
;[EBP +14H] LPARAM
;[EBP +10H] WPARAM
;[EBP +0CH] MES
;[EBP +8] HWND

WNDPROC   PROC


PUSH  EBP
MOV  EBP,ESP
PUSH  EBX
PUSH  ESI
PUSH  EDI

CMP  DWORD  PTR  [EBP + 0CH],WM_CLOSE;komunikat związany ze zniszczeniem okna
JNE  WYKONANIE
JMP  KONCZ


WYKONANIE:

CMP  DWORD  PTR  [EBP + 0CH],WM_COMMAND;komunikat związany z kontrolkami
JNE  FINISH

CMP  WORD  PTR  [EBP + 10H],IDC_BTN1  ;czy uruchamiamy proces?
JNE  CZYZAKONCZYC
JMP  URUCHOM

KONCZ:

PUSH  0
PUSH  DWORD  PTR  [EBP+ 08H]
CALL  EndDialog@8
JMP  FINISH

URUCHOM:

MOV  STRUP.cb,68

MOV  STRUP.lpReserved,0

MOV  STRUP.lpDesktop,0

MOV  STRUP.lpTitle,0

MOV  STRUP.dwFlags,STARTF_USESHOWWINDOW

MOV  STRUP.cbReserved2,0

MOV  STRUP.lpReserved2,0

MOV  STRUP.wShowWindow, SW_SHOWMINIMIZED

PUSH  OFFSET  INF
PUSH  OFFSET  STRUP
PUSH  0
PUSH  0
PUSH  0
PUSH  0
PUSH  0
PUSH  0
PUSH  OFFSET  PATH
PUSH  0
CALL  CreateProcessA@40
JMP  FINISH

Natomiast sekcja odpowiedzialna za obsługę przycisku, który wywołuje zakończenie procesu - wygląda następująco:


CZYZAKONCZYC:

CMP  WORD  PTR  [EBP + 10H],IDC_BTN2  ;czy kończymy uruchomiony proces?
JNE  FINISH

PUSH  0
PUSH  INF.hProcess
CALL  TerminateProcess@8

FINISH:

MOV  EAX,0

POP  EDI
POP  ESI
POP  EBX
POP  EBP
RET
WNDPROC  ENDP

Przykładowe wywołanie programu przestawione jest na rysunku poniżej - Rys.1


Nie można wyświetlić obrazu
Rys.1. Interfejs programu przykładowego.


Całość programu przedstawiona jest na poniższym listingu:


.586 ;typ instrukcji procesora

.MODEL FLAT,STDCALL

includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib

IDC_BTN1      EQU   101

IDC_BTN2      EQU   102

STARTF_USESHOWWINDOW          EQU   1h
SW_SHOWMINIMIZED              EQU   2
WM_INITDIALOG                 EQU   110h
WM_CLOSE                      EQU   10h
WM_COMMAND                    EQU   111h

EXTERN TerminateProcess@8:NEAR

EXTERN CreateProcessA@40:NEAR

EXTERN EndDialog@8:NEAR

EXTERN GetModuleHandleA@4:NEAR

EXTERN DialogBoxParamA@20:NEAR

EXTERN ExitProcess@4:NEAR

STARTUP STRUC
cb                DD      0 ;rozmiar struktury w bajtach
lpReserved        DD      0 ;zarezerwowane, musi być zerem
lpDesktop         DD      0 ;nazwa pulpitu
lpTitle           DD      0 ;tytuł okna dla aplikacji konsolowych.
dwX               DD      0 ;współrzędna X lewego górnego roku okna
dwY               DD      0 ;współrzędna Y lewego górnego roku okna
dwXSize           DD      0 ;szerokość okna
dwYSize           DD      0 ;wysokość okna
dwXCountChars     DD      0 ;rozmiar bufora konsoli (współrzędne X)
dwYCountChars     DD      0 ;rozmiar bufora konsoli (współrzędne Y)
dwFillAttribute   DD      0 ;początkowe kolory tekstu dla aplikacji konsolowych
dwFlags           DD      0 ;znaczniki wartości pól
wShowWindow       DW      0 ;definiuje tryb wyświetlania okna
cbReserved2       DW      0 ;zarezerwowane
lpReserved2       DD      0
hStdInput         DD      0 ;deskryptor wejścia dla konsoli
hStdOutput        DD      0 ;deskryptor wyjścia dla konsoli
hStdError         DD      0 ;deskryptor wyświetlania komunikatów o błędach
STARTUP ENDS

PROCINF STRUC
hProcess   DD      ? ;deskryptor utworzonego procesu
hThread    DD      ? ;deskryptor głównego wątku utworzonego procesu
idProc     DD      ? ;identyfikator nowego procesu
idThr      DD      ? ;identyfikator głównego wątku nowego procesu
PROCINF ENDS

.DATA
HINST         DD    ?
PA            DB   'IDD_DLG1',   0 ;nazwa dialogu
PATH          DB    "C:\WINDOWS\system32\calc.exe",   0
STRUP         STARTUP       <?>
INF           PROCINF       <?>

.CODE

START:

PUSH  0
CALL  GetModuleHandleA@4
MOV  [HINST],EAX

PUSH  0
PUSH  OFFSET  WNDPROC
PUSH  0
PUSH  OFFSET  PA
PUSH  [HINST]
CALL  DialogBoxParamA@20

PUSH  0
CALL  ExitProcess@4

;parametry:
;[EBP +14H] LPARAM
;[EBP +10H] WPARAM
;[EBP +0CH] MES
;[EBP +8] HWND

WNDPROC   PROC


PUSH  EBP
MOV  EBP,ESP
PUSH  EBX
PUSH  ESI
PUSH  EDI

CMP  DWORD  PTR  [EBP + 0CH],WM_CLOSE;komunikat związany ze zniszczeniem okna
JNE  WYKONANIE
JMP  KONCZ


WYKONANIE:

CMP  DWORD  PTR  [EBP + 0CH],WM_COMMAND;komunikat związany z kontrolkami
JNE  FINISH

CMP  WORD  PTR  [EBP + 10H],IDC_BTN1  ;czy uruchamiamy proces?
JNE  CZYZAKONCZYC
JMP  URUCHOM

KONCZ:

PUSH  0
PUSH  DWORD  PTR  [EBP+ 08H]
CALL  EndDialog@8
JMP  FINISH

URUCHOM:

MOV  STRUP.cb,68

MOV  STRUP.lpReserved,0

MOV  STRUP.lpDesktop,0

MOV  STRUP.lpTitle,0

MOV  STRUP.dwFlags,STARTF_USESHOWWINDOW

MOV  STRUP.cbReserved2,0

MOV  STRUP.lpReserved2,0

MOV  STRUP.wShowWindow, SW_SHOWMINIMIZED

PUSH  OFFSET  INF
PUSH  OFFSET  STRUP
PUSH  0
PUSH  0
PUSH  0
PUSH  0
PUSH  0
PUSH  0
PUSH  OFFSET  PATH
PUSH  0
CALL  CreateProcessA@40
JMP  FINISH

CZYZAKONCZYC:

CMP  WORD  PTR  [EBP + 10H],IDC_BTN2  ;czy kończymy uruchomiony proces?
JNE  FINISH

PUSH  0
PUSH  INF.hProcess
CALL  TerminateProcess@8

FINISH:

MOV  EAX,0

POP  EDI
POP  ESI
POP  EBX
POP  EBP
RET
WNDPROC  ENDP

END Start

Pobierz kod

Plik zasobów programu wygląda następująco:


#include "..\include\resource.h"

#define IDC_BTN1 101
#define IDC_BTN2 102


IDD_DLG1 DIALOGEX 75,87,381,210
CAPTION "Procesy"
FONT 8,"MS Sans Serif", 0, 0, 0
STYLE  WS_VISIBLE|WS_OVERLAPPEDWINDOW
BEGIN
  CONTROL "Uruchom proces kalkulatora",IDC_BTN1,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,51,27,102,15
  CONTROL "Zakończ proces kalkulatora",IDC_BTN2,"Button",WS_CHILD|WS_VISIBLE|WS_TABSTOP,210,27,107,15
END

Pobierz kod

Ćwiczenie 7

Zmodyfikować kod przykład tak, aby można było dodatkowo tworzyć i zamykać proces notatnika i painta. Przykładowe wywołanie programu na rysunku poniżej. - Rys.2.

Pobierz szablon

Nie można wyświetlić obrazu
Rys.2. Interfejs programu.

<Powrót do strony kursuKolejna lekcja>