Capitolul 1 - programarea ferestrelor

Programare pentru Windows

DirectX este instalat, compilatorul dvs. este configurat și sunteți gata să mergeți! Așteaptă o clipă, prietene, există câteva lucruri pe care ar trebui să le acorzi înainte de a intra în lumea programării jocurilor de rol.







Mai întâi de toate, există câteva subiecte legate de Windows pe care vreau să le discut. Aceste subiecte includ studiul firelor și secțiunilor multiple, secțiunile critice și COM. Cred că această informație este absolut necesară pentru citirea restului cărții (sugestie, sugestie).

Fire și Multithreading

Windows 95 a introdus programatorii cu ideea de a folosi sisteme multitasking (în ciuda faptului că Windows nu este adevărat sistem de operare multitasking, deoarece foloseste multitasking, în care bucăți mici de o multitudine de programe sunt executate unul câte unul). Ideea este că aveți mai multe procese (aplicații) care rulează simultan, fiecare dintre care este alocată o parte din timpul procesorului (numită o felie de timp).

De asemenea, multitaskingul permite ca fiecare proces să fie împărțit în mai multe subprocese separate, numite fire. Fiecare fir are sarcina proprie, de exemplu, scanarea datelor din rețea, prelucrarea datelor introduse de utilizator sau redarea audio. Utilizarea mai multor fire într-o singură aplicație se numește multithreading.

Crearea de fire suplimentare în cadrul aplicației dvs. este ușoară. Pentru a crea un fir, creați o funcție (utilizând un prototip de funcție specială) care conține codul pe care doriți să-l executați. Prototipul utilizat pentru funcția de flux arată astfel:

Parametrul lpParameter este un pointer definit de utilizator pe care îl furnizați atunci când creați un flux apelând funcția CreateThread:

Valoarea returnată de funcția CreateThread este un descriptor care trebuie să fie închis la închidere sau resursele de sistem nu sunt eliberate. Resursele folosite de fir sunt eliberate apelând funcția CloseHandle.

Aceasta este o funcție complexă și nu voi intra în detaliile muncii sale, dar în schimb voi da un exemplu pe care îl puteți folosi ca șablon. Exemplul prezintă o funcție de flux simplu și un apel pentru inițializarea acestuia:

Codul generat creează un fir care se execută imediat după terminarea funcției CreateThread. Un cursor la o variabilă BOOL este trecut la funcția de curgere. care monitorizează starea fluxului; steagul vă permite să determinați activitatea fluxului și stochează valorile TRUE (firul este activ) sau FALSE (firul nu este activ).

Când firul este finalizat, semnal că debitul nu mai este activa (scris valoarea FALSE în menționate anterior variabila logică) și completează funcția provocare ExitThread fluxului de lucru. care a transmis singurul parametru - fluxul de cod de finalizare, sau cu alte cuvinte, numărul informându motivul pentru care executia a fost finalizat. În cele mai multe cazuri, puteți utiliza în siguranță valoarea 0 în apelul ExitThread.

De fapt, un fir este pur și simplu o funcție care rulează simultan cu aplicația dvs. Pentru mai multe detalii despre utilizarea firelor, vedeți Capitolul 4.

Secțiuni critice

Deoarece Windows este un sistem multi-tasking, aplicațiile individuale pot interfera unele cu celelalte, în special aplicațiile care utilizează fire multiple. Ce se întâmplă dacă un fir umple o structură care conține date importante și un alt fir vrea să schimbe sau să citească aceste date în același timp?

Există o modalitate de a ne asigura că, dacă este necesar, un singur fir va avea control complet, iar această metodă este utilizarea secțiunilor critice. Când este activat, secțiunea critică va bloca toate celelalte fire încearcă să acceseze memoria partajată (aplicații de memorie utilizate de toate thread-urile), permițând astfel fluxul de unul singur schimba datele de aplicare, fără a avea grija interferențe de la alte fire. Pentru a utiliza o secțiune critică, trebuie mai întâi să o declarați și să o inițializați:







După aceasta, puteți introduce secțiunea critică, procesa datele și părăsi secțiunea critică, după cum se arată în exemplul de mai jos:

Dacă nu mai aveți nevoie de o secțiune critică (de exemplu, atunci când aplicația se închide), trebuie să o eliberați apelând:

Deși secțiunile critice pot fi explicate mai detaliat, nu este nevoie de acest lucru. Este destul de ușor de utilizat și sunt necesare pentru aplicații multi-filetate. Este necesar să vă amintiți doar o singură regulă - asigurați-vă că codul din secțiunea critică este executat rapid; blocați procesele sistemului și, dacă programul dvs. durează prea mult, poate duce la accidente de sistem.

Utilizarea COM

Folosind COM, creați componente software în așa fel încât funcționalitatea lor să fie compatibilă cu toate programele. Luați, de exemplu, Internet Explorer. Pun pariu că nu știți că bara de instrumente și fereastra browserului sunt obiecte COM. Mai mult decât atât, puteți utiliza aceste obiecte în aplicațiile dvs.!

Deși acesta este un motiv bun pentru a începe să utilizați COM, motivul mai convingător este DirectX; DirectX este compus în întregime din obiecte COM.

Inițializarea COM

Pentru a utiliza obiectele COM, trebuie să inițializați sistemul COM. Următoarele două funcții sunt utilizate pentru a inițializa COM:

Ambele funcții îndeplinesc sarcina, dar dacă aplicația dvs. este multietajată, atunci trebuie să utilizați a doua funcție, CoInitializeEx. Deoarece trebuie să specificați pavilionul COINIT_MULTITHREADED în parametrul dwCoInit. pentru ca sistemul COM să funcționeze corect.

Când ați terminat de utilizat sistemul COM, trebuie să îl opriți apelând funcția CoUninitialize. care nu au parametri:

Fiecare apel CoInitialize sau CoInitializeEx trebuie să aibă un apel separat CoUninitialize. Dacă apelați CoInitialize de două ori (acest lucru este permis), aveți nevoie de două apeluri CoUnitialize. Acest lucru este ilustrat de următorul fragment de cod:

IUnknown este clasa de bază pentru toate interfețele COM. Acesta conține doar trei funcții: AddRef. Release și QueryInterface. AddRef efectuează, dacă este necesar, inițializarea și mărește contorul, indicând de câte ori a fost creată o instanță a clasei. Trebuie să faceți ca numărul de referință să corespundă numărului de apeluri către funcția de eliberare. Resursa utilizată de instanța obiectului.

Nu confunda clasele, interfețele și obiectele! Un obiect este o instanță a unei clase. O interfață este un set de funcții furnizate de un obiect (cu alte cuvinte interfețele vă permit să interacționați cu un obiect).

A treia funcție, QueryInterface. utilizați pentru a accesa obiectele furnizate de obiect, inclusiv noile lor versiuni. Această situație poate apărea atunci când au fost lansate mai multe versiuni de obiecte, ca în cazul DirectX. Puteți utiliza în continuare vechile interfețe, iar pentru a accesa altele noi, trebuie să le solicitați. Dacă noua interfață există, obiectul întoarce un pointer; altfel QueryInterface returnează NULL. indicând că nu există nici o interfață sau o eroare.

Este necesar ca funcția să returneze o valoare de tip HRESULT. indicând o eroare sau finalizarea cu succes. Pentru a obține orice valoare în afara obiectului COM, va trece un pointer la o variabilă (care ar trebui să fie un cuvânt sau dublu cuvânt - octeți și alte tipuri nu sunt acceptate) la funcția și de a folosi acest index pentru a returna o valoare care este în interiorul obiectului.

Ca un exemplu, pentru a crea un obiect simplu (moștenit de la IUnknown), care primește două numere, le adaugă împreună și plasează rezultatul în variabila specificată de al treilea parametru:

Inițializarea și eliberarea obiectelor

Pentru a utiliza un obiect COM, trebuie (pe lângă scrierea unei biblioteci Windows încărcabile) să-l creați utilizând funcția CoCreateInstance:

Toate obiectele COM pe care le creați trebuie să fie eliberate în cele din urmă. În aceste scopuri, IUnknown :: Release este folosit fără parametri:

După ce ați părăsit interfața IAdd2. trebuie să îl eliberați după cum urmează:

Solicitare interfețe

Una dintre cele mai bune caracteristici ale COM este compatibilitatea înapoi. Dacă aveți un obiect COM nou (care conține interfețe noi), atunci veți avea acces complet prin obiect la vechile interfețe. Salvarea vechilor interfețe asigură că codul va funcționa corect chiar dacă utilizatorul final a instalat noi versiuni de obiecte COM. Acest lucru înseamnă, de asemenea, că vechile interfețe pot solicita noi interfețe.

Aceasta se face folosind metoda IUnknown :: QueryInterface:

Deoarece obiectul sursă care apelează funcția de interogare a fost deja creat, nu trebuie să vă faceți griji cu privire la specificarea identificatorului de clasă - specificați doar ID-ul interfeței necesare. Să revenim la obiectul clasei Math și să presupunem că doriți să obțineți interfața IAdd și apoi prin ea să solicitați interfața IAdd2:

Deși COM este un subiect extins, informațiile de mai sus sunt suficiente pentru a începe să utilizați DirectX. Veți afla mai multe despre DirectX în alte capitole ale cărții, așa că să schimbăm direcția și să vorbim despre alte lucruri importante pentru proiect - fluxul programului.







Articole similare

Trimiteți-le prietenilor: