<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7735655402128608226</id><updated>2024-09-04T13:34:06.813-07:00</updated><category term="C++"/><category term="tutorial"/><category term="Coltul Programatorului"/><category term="Crypted chat"/><category term="OBDC WRAPER; Functii ODBC"/><category term="Threads"/><category term="Tutorial C++"/><category term="Tutorial WinApi Threads"/><category term="Tutorial compilare libcurl"/><category term="Tutorial compilare openssl"/><category term="WinApi"/><category term="Word list generator;Generator lista cuvinte"/><category term="compilare"/><category term="encrypted chat. IP to IP chat"/><category term="libcurl 7.37.0"/><category term="mingw32"/><category term="msys"/><category term="multi-threading"/><category term="openssl 1.0.1h"/><category term="secure chat"/><category term="tutorial Threads"/><title type='text'>Florin&#39;s Blog</title><subtitle type='html'>Un blog cu si despre calculatoare</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://florinrada.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://florinrada.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>florin.rada</name><uri>http://www.blogger.com/profile/07336044099523183162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>6</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7735655402128608226.post-8034131235629052206</id><published>2014-06-17T10:51:00.001-07:00</published><updated>2014-06-24T02:02:56.755-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="compilare"/><category scheme="http://www.blogger.com/atom/ns#" term="libcurl 7.37.0"/><category scheme="http://www.blogger.com/atom/ns#" term="mingw32"/><category scheme="http://www.blogger.com/atom/ns#" term="msys"/><category scheme="http://www.blogger.com/atom/ns#" term="openssl 1.0.1h"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorial"/><category scheme="http://www.blogger.com/atom/ns#" term="Tutorial compilare libcurl"/><category scheme="http://www.blogger.com/atom/ns#" term="Tutorial compilare openssl"/><title type='text'>Tutorial compilare Openssl si curl cu ajutorul MinGW32 si msys</title><content type='html'>&amp;nbsp; &amp;nbsp;Acest tutorial este adresat in mare parte incepatorilor care doresc sa compileze aceste librarii fara batai de cap.&lt;br /&gt;
Pentru a putea efectua acesti pasi aveti nevoie de urmatoarele:&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Mingw32 si msys, compilator si mediu de dezvoltare cli ce pot fi descarcate de &lt;a href=&quot;http://www.mingw.org/&quot;&gt;aici&lt;/a&gt;.&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Perl ce poate fi descarcat de&amp;nbsp;&lt;a href=&quot;http://www.perl.org/&quot;&gt;aici&lt;/a&gt;.&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Libraria Openssl ce poate fi descarcata de&amp;nbsp;&lt;a href=&quot;https://www.openssl.org/source/&quot;&gt;aici&lt;/a&gt;, descarcati ultima versiune a arhivei(de obicei cea marcata cu rosu). Pentru a o dezarhiva sugerez sa folositi 7zip deoarece winrar se pare ca da rateuri la arhive tar.gz&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Libraria libcurl ce poate fi descarcata de&amp;nbsp;&lt;a href=&quot;http://curl.haxx.se/libcurl&quot;&gt;aici&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Pentru acesst tutorial vom face cateva presupuneri:&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Ati instalat compilatorul si msys la adresa C:/MinGW/ respectiv C:/MinGW/msys/ (daca instalati compilatorul la alta adresa, asigurati-va ca adresa respectiva nu contine spatii si alte semne&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Folderul in care se gaseste compilatorul(executabilul mingw32-g++/mingw32-gcc/mingw32-make) este C:/MinGW/bin&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Folderul in care se gasesc headerele este C:/MinGW/include&lt;br /&gt;
&amp;nbsp; &amp;nbsp;- Folderul in care se gasesc librariile statice(nume_librarie.a) este C:/MinGW/lib&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Incepem cu libraria OpenSSL(la data creeri acestui tutorial aceasta era la versiunea 1.0.1h)&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Dupa ce dezarhivam libraria ar trebui sa ramanem cu un folder numit openssl-1.0.1h. Copiem acest folder in folderul C:/Mingw/msys/home/Nume_userul_vostru/. Pornim msys(C:/MinGW/msys/1.0/msys.bat).&lt;br /&gt;
Schimbam directorul de lucru din cel in care porneste msys in /home/openssl-1.0.1h. Aici executam comanda urmatoare:&lt;br /&gt;
&amp;nbsp; &lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;./config --prefix=/mingw --openssldir=/openssl shared&lt;/pre&gt;
&lt;br /&gt;
--prefix=/mingw seteaza ca si compilator utilizat mingw&lt;br /&gt;
--openssldir=/openssl seteaza folderul in care fisierele rezultate in urma compilarii se vor salva. Acest folder se gasi in mod normal la aici: C:/MinGW/msys/1.0/openssl.&lt;br /&gt;
shared seteaza daca libraria va fi compilata sub forma de dll, sau sub forma de librarie statica(*.a)&lt;br /&gt;
&lt;br /&gt;
Dupa ce procesul de configurare se inchieie rulam pe rand comenzile &quot;make&quot; si &quot;make install&quot;.&lt;br /&gt;
Dupa ce termina si a 2-a comanda(make install) va trebui sa copiati din folderul C:/MinGw/msys/1.0/mingw cele 3 foldere, bin, include, lib in folderul C:/MinGW/msys/1.0/openssl. Acest pas va fi necesar pentru a putea compila libraria libcurl. Pentru a putea folosi ,mai usor, libraria aceasta in programele noastre este recomandat sa copiati cel putin folderele bin, include si lib din folderul c:/MinGW/msys/1.0/openssl in folderul C:/MinGW/ suprascriind folderele bin, include si lib din acest folder.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Compilarea librariei libcurl(la data creeri acestui tutorial aceasta era la versiunea 7.30.0)&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Dupa ce dezarhivam libraria, ar trebui sa avem un folder numit curl-7.37.0. Copiem acest folder in folderul C:/MinGw/msys/1.0/home/Nume_userul_vostru. Mutam directorul de lucru din /home/openssl-1.0.1h in /home/curl-7.37.0.&lt;br /&gt;
Executam comanda&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;./configure --with-ssl=/openssl/&lt;/pre&gt;
&lt;br /&gt;
--with-ssl va seta ca libraria sa se compileze cu includerea librariei openssl si ca aceasta librarie se gaseste la adresa /openssl// . Dupa ce configurarea se incheie executam pe rand comenzile &quot;make&quot; si &quot;make install&quot;&lt;br /&gt;
Dupa ce &quot;make install&quot; termina de executat, daca nu au existat erori, vom gasi fisierele noastre in folderul C:/MinGW/msys/1.0/local. De aici copiem folderele bin, include, lib si share in folderul C:/MinGW/ suprascriind folderele deja existente.&lt;br /&gt;
&lt;br /&gt;
In acest moment putem folosii librariile acesta pentru programele de care avem nevoie.&lt;br /&gt;
Pentru cei ce doresc cateva alternative, acestea exista.&lt;br /&gt;
Pentru Openssl avem urmatoarele:&lt;br /&gt;
&lt;a href=&quot;https://polarssl.org/&quot;&gt;PolarSSL&lt;/a&gt; si un tutorial despre cum sa il compilati aveti tot pe pagina lor &lt;a href=&quot;https://polarssl.org/&quot;&gt;aici&lt;/a&gt;. Aceasta implementare este disponibila atat sub liceenta open source cat si sub licenta platita.&lt;br /&gt;
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS&quot;&gt;Network Security Service(NSS)&lt;/a&gt; un proiect ce apartine fundatiei Mozila, ce include pe langa SSL/TSL mai multe metode de criptare a datelor utilizate in transferul de date.&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/NSS_Sources_Building_Testing&quot;&gt;Aici&lt;/a&gt; aveti cateva informatii despre compilarea si utilizarea acestei librarii.&lt;br /&gt;
O alta alternativa open source(in mare parte, foloseste licenta LGPL 2.0) este &lt;a href=&quot;http://gnutls.org/&quot;&gt;GNUTLS&lt;/a&gt;. &lt;a href=&quot;http://go.kblog.us/2013/01/compiling-gnutls-316-for-x64-windows.html&quot;&gt;Aici&lt;/a&gt; aveti un tutorial ce ar trebui sa va ajute la compilarea acestei librarii.&lt;br /&gt;
&lt;br /&gt;
Pentru LibCurl avem urmatoarele alternative:&lt;br /&gt;
&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/aa383630(v=vs.85).aspx&quot;&gt;WinInet&lt;/a&gt; este o alternativa ce functioneaza strict pe windows, pentru cei ce nu au o problema cu asta.Pentru aceasta &quot;librarie&quot;/Api aveti nevoie de minim Windows XP sau Windows Server 2003.&lt;br /&gt;
&lt;a href=&quot;http://www.w3.org/Library/&quot;&gt;LibWWW&lt;/a&gt; este o alta alternativa, de data aceasta open source.&lt;br /&gt;
&lt;br /&gt;
Daca aveti intrebari nu ezitati sa le puneti.&lt;br /&gt;
Sper sa va ajute.&lt;br /&gt;
&lt;br /&gt;
Surse de inspiratie:&lt;br /&gt;
&lt;a href=&quot;http://stackoverflow.com/questions/12636536/install-curl-with-openssl&quot;&gt;Stack Overflow&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.bowmansolutions.com/mingw-openldap/&quot;&gt;BowmanSolutions&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://florinrada.blogspot.com/feeds/8034131235629052206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://florinrada.blogspot.com/2014/06/tutorial-compilare-openssl-si-curl-cu.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/8034131235629052206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/8034131235629052206'/><link rel='alternate' type='text/html' href='http://florinrada.blogspot.com/2014/06/tutorial-compilare-openssl-si-curl-cu.html' title='Tutorial compilare Openssl si curl cu ajutorul MinGW32 si msys'/><author><name>florin.rada</name><uri>http://www.blogger.com/profile/07336044099523183162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7735655402128608226.post-3355193427485728008</id><published>2014-06-14T02:22:00.001-07:00</published><updated>2014-06-14T07:04:50.724-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="multi-threading"/><category scheme="http://www.blogger.com/atom/ns#" term="Threads"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorial"/><category scheme="http://www.blogger.com/atom/ns#" term="Tutorial C++"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorial Threads"/><category scheme="http://www.blogger.com/atom/ns#" term="Tutorial WinApi Threads"/><category scheme="http://www.blogger.com/atom/ns#" term="WinApi"/><title type='text'>Tutorial introducere in threading in WinApi(C++)</title><content type='html'>&lt;br /&gt;
Introducere in threaduri WinApi(C++)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Ce sunt threadurile?&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Threadurile sunt fire de executie separate care exista in interiorul unei aplicatii.&lt;br /&gt;
Firele de executie multiple, permit unei aplicatii sa faca(sau sa dea senzatia ca fac) mai multe lucruri in acelasi&lt;br /&gt;
timp. &lt;br /&gt;
Acest efect este atins prin permiterea fiecarui fir de executie o anumita perioada de lucru in procesor.  &lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;In majoritatea limbajelor de programare moderne(care in general incorporeaza concepte de programare&lt;br /&gt;
orientata pe obiect), threadurile sunt portretizate sub forma de obiecte, threadurile respective avand&lt;br /&gt;
caracteristici, si metode de utilizare. In contrast, threadurile din WinApi sunt mult mai bazice. In esenta un&lt;br /&gt;
thread in WinAPi este doar o simpla functie, ce se executa separat de threadul principal. Acest lucru, pe&lt;br /&gt;
langa ca le face un pic mai complicat de folosit le face insa si mai versatile, permitand programatorului sa&lt;br /&gt;
creeze pe baza facilitatilor respective, alte reprezentari ale threadurilor.&lt;br /&gt;
&lt;br /&gt;
Cam atat cu introducerea, deci hai sa mergem mai departe cu un pic de cod.&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

DWORD WINAPI trdFnk(LPVOID lpParam)
{
    for(int i = 0; i&amp;lt; 100;i++)
    {
        cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
    }
}

int main()
{
    int data = 0;
    DWORD identificatorTRD = 0;
    HANDLE trdHdl = CreateThread(NULL, 0, trdFnk, &amp;amp;data, 0, &amp;amp;identificatorTRD);
    if(trdHdl == NULL)
 {
  cout &amp;lt;&amp;lt;&quot;Eroare la creere thread, iesim.&quot; &amp;lt;&amp;lt; endl;
  return 0;
 }
 WaitForSingleObject(trdHdl, INFINITE);
    return 0;
}
&lt;/pre&gt;
Ce face codul asta?&lt;br /&gt;
Creaza un thread in care se face o enumerare dupa care iese.

Creerea unui tred e formata din 2 pasi.&lt;br /&gt;
&amp;nbsp; &amp;nbsp;1. O functie(ce va fii threadul nostru) care are definitia urmatoare:
 DWORD WINAPI&lt;br /&gt;
nume_functie(LPVOID lpParam). &amp;nbsp;Este necesar ca functia noastra thread sa respecte aceasta definitie pentru&lt;br /&gt;
&amp;nbsp;a fi recunoscuta de catre al 2-lea pas si anume:&lt;br /&gt;
&amp;nbsp; &amp;nbsp;2. Functia CreateThread, aceasta are urmatoarea definitie:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; HANDLE WINAPI CreateThread(
    _In_opt_   LPSECURITY_ATTRIBUTES lpThreadAttributes,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_       SIZE_T dwStackSize,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_       LPTHREAD_START_ROUTINE lpStartAddress,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_opt_   LPVOID lpParameter,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_       DWORD dwCreationFlags,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_Out_opt_  LPDWORD lpThreadId
  );&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Functia returneaza un obiect de tip HANDLE. Acesta nu este altceva decat un pointer&lt;br /&gt;
void(typedef PVOID HANDLE). Un pointer void poate fii folosit pentru a indica
catre orice alt tip de&lt;br /&gt;
obiect.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Argumente:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes:
  - LPSECURITY_ATTRIBUTES este&lt;br /&gt;
o structura cu 3 membri. Structura este folosita pentru a seta diferite atribute de securitate ale unei&lt;br /&gt;
aplicatii sau fir de executie(thread). Structura e definita cam asa:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; typedef struct _SECURITY_ATTRIBUTES {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; DWORD  nLength; &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; LPVOID lpSecurityDescriptor;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; BOOL   bInheritHandle;
  } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -DWORD nLength contine marimea acestei structuri.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -De aici membrul important este LPVOID lpSecurityDescriptor, care este o alta structura nedocumentata.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -BOOL bInheriteHandle seteaza daca alte procese /threaduri create din threadul curent sa ii mosteneasca atributele de securitate.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-_In_ SIZE_T dwStackSize:
  - stocheaza marimea initiala a stivei firului de executie(marimea in memorie pe care firul de executie o ocupa), daca acest parametru este 0, atunci firul de executie va 
  avea aceeasi marime ca si procesul/firul de executie parinte. Marimea stivei firului de executie se va modifica pe parcursul rularii firului, aceasta marime putand sa scada sau sa creasca.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-_In_ LPTHREAD_START_ROUTINE lpStartAddress
  - este de fapt numele functiei care reprezinta&lt;br /&gt;
firul nostru de executie.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-_In_opt_ LPVOID lpParameter:
  - este un alt pointer void ce poate indica catre orice tip de obiect, aici puteti sa puneti, fie de unul singur sau daca este necesa trimiterea mai multor variabile, acestea se pot pune&lt;br /&gt;
intr-un struct.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-_In_ DWORD dwCreationFlags:
  - reprezinta unul din flagurile/starile in care threadul este &lt;br /&gt;
creeat - 0 inseamna ca threadul ruleaza imediat ce a fost creat.
   - CREATE_SUSPENDED inseamna ca threadul este creeat intr-o stare suspendata, acesta incepe sa ruleze doar dupa ce functia ResumeThread a fost chemata
   - STACK_SIZE_PARAM_IS_A_RESERVATION, daca acest parametru este specificat,&lt;br /&gt;
atunci dwStackSize va reprezenta marimea initiala a stive, daca nu este specificat
    va reprezenta marimea&lt;br /&gt;
memoriei rezervate pentru firul respectiv de executie. Memoria rezervata este cantitatea de memorie la care&lt;br /&gt;
sistemul de operare garanteaza
    ca firul de executie va avea acces.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-_Out_opt_  LPDWORD lpThreadId:
  - reprezinta id-ul firului de executie, cu acest id firul de executie&lt;br /&gt;
poate fi identificat in interiorul aplicatiei. Acest id este utilizat pentru functii de genul OpenThread, functie&lt;br /&gt;
folosita pentru a deschide si accesa obiectul unui thread.
   Acest id este creat in functia CreateThread si stocat in acest parametru.&lt;br /&gt;
Pentru a creea un thread suspendat,atunci cand nu dorim sa porneasca imediat, vom folosi parametrul&lt;br /&gt;
CREATE_SUSPENDED
Ceva de genul acesta:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

DWORD WINAPI trdFnk(LPVOID lpParam)
{
    for(int i = 0; i&amp;lt; 100;i++)
    {
        cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
    }
}

int main()
{
    int data = 0;
    DWORD identificatorTRD = 0;
    HANDLE trdHdl = CreateThread(NULL, 0, trdFnk, &amp;amp;data, CREATE_SUSPENDED, &amp;amp;identificatorTRD);
 if(trdHdl == NULL)
 {
  cout &amp;lt;&amp;lt;&quot;Eroare la creere thread, iesim.&quot; &amp;lt;&amp;lt; endl;
  return 0;
 }
 ResumeThread(trdHdl);
    WaitForSingleObject(trdHdl, INFINITE);
    return 0;
}
&lt;/pre&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;&lt;/pre&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;&lt;/pre&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;&lt;/pre&gt;
&amp;nbsp; &amp;nbsp;Ok, sa zicem ca trebuie sa suspendam un thread care ruleaza. Pentru asta va trebui sa apelam urmatoarea&lt;br /&gt;
functie:
 DWORD WINAPI SuspendThread(
   _In_  HANDLE hThread
 );
 - argumentul necesar este&lt;br /&gt;
handle-ul threadului. Acesta este obtinut prin chemarea functiei CreateThread despre care am vorbit putin&lt;br /&gt;
mai sus.
Bine-inteles, dupa ce am suspendat un thread o sa avem nevoie as il si repornim, corect? Pentru&lt;br /&gt;
asta folosim functia
 DWORD WINAPI ResumeThread(
   _In_  HANDLE hThread
 );
 - la fel ca si&lt;br /&gt;
SuspendThread, ResumeThread primeste ca argument handle-ul threadului.

Haide sa vedem un mic exemplu:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

DWORD WINAPI trdFnk(LPVOID lpParam)
{
    for(int i = 0; i&amp;lt; 100;i++)
    {
        cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        Sleep(100); // Am adaugat un mic timer ca threadul sa nu termine treaba asa repede :)
    }
}

int main()
{
    int data = 0;
    DWORD identificatorTRD = 0;
    HANDLE trdHdl = CreateThread(NULL, 0, trdFnk, &amp;amp;data, 0, &amp;amp;identificatorTRD);
 if(trdHdl == NULL)
 {
  cout &amp;lt;&amp;lt;&quot;Eroare la creere thread, iesim.&quot; &amp;lt;&amp;lt; endl;
  return 0;
 }
 cout &amp;lt;&amp;lt; &quot;Suspendam threadul... &quot;;
 Sleep(5000); // asteptam 5 secunde dupa care suspendam threadul.
 SuspendThread(trdHdl);
 cout &amp;lt;&amp;lt; &quot;Threadul a fost suspendat, asteptam inca 5 secunde dupa care il repornim.&quot;;
 Sleep(5000);
 ResumeThread(trdHdl);
    WaitForSingleObject(trdHdl, INFINITE);
    return 0;
}
&lt;/pre&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;&lt;/pre&gt;
&amp;nbsp; &amp;nbsp;Atunci cand lucram cu threadurile, se poate intampla, daca codul nu este scris corect, sa avem situatii in care&lt;br /&gt;
2 threaduri incearca sa acceseze aceeasi variabila sau aceleasi date.
Desigur asta e problema cea mai&lt;br /&gt;
comuna, pot aparea multe altele.
Acest lucru tine de sincronizarea datelor si threadurilor. Winapi pune la&lt;br /&gt;
dispozitie 5 obiecte care ajuta la contrulul si efectuarea sincronizarii.
Acestea sunt mutex, event,&lt;br /&gt;
semaphore si waitableTimer si critical_section.&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Sa le luam pe rand sa vorbim un pic despre ele.&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Mutex:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; - Mutexi sunt folositi pentru a proteja variabile de la a fi accesate si modificate de catre 2 sau mai multe&lt;br /&gt;
threaduri/procese in acelasi timp. 
  Ei fac asta prin permiterea unui proces/thread sa preia proprietatea asupra&lt;br /&gt;
acelui mutex. Un alt thread care incearca sa modifice variabila respectiva
  va trebui sa verifice si sa astepte&lt;br /&gt;
pana mutex-ul respectiv nu mai este sub proprietatea altui thread/proces pentru a putea sa efectueze&lt;br /&gt;
actiunea dorita.
  Un mutex se creeaza cu ajutorul functiei CreateMutex care are urmatoarea definitie:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; HANDLE WINAPI CreateMutex(
    _In_opt_  LPSECURITY_ATTRIBUTES lpMutexAttributes,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_      BOOL bInitialOwner,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_opt_  LPCTSTR lpName
  );&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Parametrii sunt urmatorii:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_opt_  LPSECURITY_ATTRIBUTES lpMutexAttributes este o structura cu 3 membri.&lt;br /&gt;
Structura este folosita pentru a seta diferite atribute de securitate ale unei aplicatii sau fir de&lt;br /&gt;
executie(thread)
    Structura e definita cam asa:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;typedef struct _SECURITY_ATTRIBUTES {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; DWORD  nLength;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; LPVOID lpSecurityDescriptor;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; BOOL   bInheritHandle;
    } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - DWORD nLength contine marimea acestei structuri.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - De aici membrul important este LPVOID lpSecurityDescriptor, care este o alta structura&lt;br /&gt;
nedocumentata.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - BOOL bInheriteHandle seteaza daca alte procese /threaduri create din threadul curent sa ii mosteneasca atributele de securitate.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_      BOOL bInitialOwner va specifica daca threadul/procesul care creeaza acest mutex este si&lt;br /&gt;
detinatorul lui initial, in felul acesta &quot;inchizand&quot; mutex-ul, caz in care oricare alt thread
   ce va dori sa il&lt;br /&gt;
foloseasca va trebui sa astepte pana cand threadul/procesul creator il va elibera.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-_In_opt_  LPCTSTR lpName - este numele atribuit mutex-ului. Acest nume va fi folosit cu functia&lt;br /&gt;
OpenMutex prin care un thread poate sa preia proprietatea asupra unui thread care nu este detinut de&lt;br /&gt;
nimeni.
  Daca functia este executata cu succes atunci aceasta returneaza un handle catre obiectul dorit.&lt;br /&gt;
Daca obiectul exista deja(pe baza numelui furnizat ultimului argument) atunci este returnat un handle catre&lt;br /&gt;
acest obiect deja
  existent. In acest caz se poate apela functia GetLastError care va returna&lt;br /&gt;
ERROR_ALREADY_EXISTS. In cazul in care functia esueaza, valoarea returnata va fi NULL.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Mai jos avem un mic exemplu ce foloseste mutex-i pentru a proteja o variabila.
  In acest exemplu creem&lt;br /&gt;
2 threaduri, un mutex si un contor(ctr). Threadurile preiau proprietatea asupra mutex-ului pe rand si&lt;br /&gt;
incrementeaza variabila
  dupa care elibereaza mutex-ul.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

int ctr = 0; // counterul ce va fi incrementat pe rand de cele 2 threaduri
HANDLE mutex; // mutex-ul care va proteja variabila respectiva.

DWORD WINAPI trdLoop(LPVOID lpParam)
{
    DWORD dwWaitResult; // va stoca rezultatul actiuni de asteptare pentru obtinerea proprietatii threadului
    do
    {
        dwWaitResult = WaitForSingleObject(mutex, INFINITE);
        switch(dwWaitResult)
        {
        case WAIT_OBJECT_0:
            {
                    cout &amp;lt;&amp;lt; GetCurrentThreadId() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ctr++ &amp;lt;&amp;lt; endl;
                    if(ReleaseMutex(mutex) == 0)
     {
      cout &amp;lt;&amp;lt; &quot;Eroare la eliberare mutex, eroare: &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; endl;
     }
                    break;
            }
        default:
            {
                cout &amp;lt;&amp;lt; &quot;Eroare nespecificata in threadul &quot; &amp;lt;&amp;lt; GetCurrentThreadId() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; endl;
            }
        }

        //cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        Sleep(100); // Dormim un pic pentru a nu printa prea repede datele si pentru a da timp si celuilalt thread sa execute, altfel threadurile vor executa
  // incrementarea aproape la intamplare, in functie de cum primesc timp de procesare pe procesor
    }while(ctr &amp;lt; 100);
}

int main()
{
    DWORD identificatorTRD1 = 0;
    DWORD identificatorTRD2 = 0;
    // creem intai mutex-ul deoarece daca creem intai threadurile vor porni direct
    // si vor incerca sa acceseze un mutex care nu exista
    mutex = CreateMutex(NULL, FALSE, &quot;grMutex&quot;); 
 if(mutex == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere mutex, iesim.&quot; &amp;lt;&amp;lt; endl;
        return 0;
    }

    HANDLE trdHdl1 = CreateThread(NULL, 0, trdLoop, NULL, 0, &amp;amp;identificatorTRD1);
 if(trdHdl1 == NULL)
 {
  cout &amp;lt;&amp;lt;&quot;Eroare la creere thread 1, iesim.&quot; &amp;lt;&amp;lt; endl;
  return 0;
 }
 HANDLE trdHdl2 = CreateThread(NULL, 0, trdLoop, NULL, 0, &amp;amp;identificatorTRD2);
 if(trdHdl2 == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere thread 2, iesim.&quot; &amp;lt;&amp;lt; endl;
        return 0;
    }

    WaitForSingleObject(trdHdl1, INFINITE); // asteptam ca threadul1 sa termine
    WaitForSingleObject(trdHdl2, INFINITE); // asteptam ca threadul2 sa termine
 // inchidem handle-urile
 CloseHandle(trdHdl1);
 CloseHandle(trdHdl2);
 CloseHandle(mutex);

    return 0;
}
&lt;/pre&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;&lt;/pre&gt;
&amp;nbsp; &amp;nbsp;CriticalSection(sectiune critica):&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; - Este asemanator unui mutex, doar ca o sectiune critica poate fi folosita doar in interiorul unui singur&lt;br /&gt;
proces, pe cand un mutex, poate fi folosit si la comunicarea intre procese.
 Procesul de utilizare a unei&lt;br /&gt;
sectiuni critice este urmatorul:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- definirea unei structuri de tipul CRITICA_SECTION, in multe cazuri aceasta strucuta va fi globala, dar nu este obligatoriu
   este important ca threadurile ce se vor folosi de ea, sa o poata accesa, intr-un fel sau altul.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- initializarea acestei structuri cu ajutorul functiei InitializeCriticalSection&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- un tread va incerca sa preia controlul asupra unei sectiuni critice cu ajutorul functiei&lt;br /&gt;
EnterCriticalSection, care va astepta in cazul in care sectiunea critica este detinuta de alt proces/thread,&lt;br /&gt;
sau 
  TryEnterCriticalSection care va returna imediat indiferent daca va putea sau nu sa preia proprietatea&lt;br /&gt;
acelei sectiuni critice&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- parasirea sectiuni critice cu functia LeaveCriticalSection, aceasta functie trebuie folosita de fiecare data cand folositi una din functiile de intrare.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Haide sa vedem un exemplu:
 Folosim un exemplu aproape identic cu cel de la Mutex doar ca in cazul acesta folosim o sectiune critica pentru a proteja variabila ctr.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

int ctr = 0; // counterul ce va fi incrementat pe rand de cele 2 threaduri
CRITICAL_SECTION crit_sect; // sectiunea critica ce va progeja  variabila ctr;
/**
DWORD WINAPI trdFnk(LPVOID lpParam)
{
    for(int i = 0; i&amp;lt; 100;i++)
    {
        cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        Sleep(100); // Am adaugat un mic timer ca threadul sa nu termine treaba asa repede :)
    }
    cout &amp;lt;&amp;lt; &quot;Exiting thread\n&quot;;
    ExitThread((DWORD) 0);
}
*/
DWORD WINAPI trdLoop(LPVOID lpParam)
{
    DWORD dwWaitResult; // va stoca rezultatul actiuni de asteptare pentru obtinerea proprietatii threadului
    do
    {
        EnterCriticalSection(&amp;amp;crit_sect); // intram in sectiunea critica
        {
            cout &amp;lt;&amp;lt; GetCurrentThreadId() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ctr++ &amp;lt;&amp;lt; endl; // efectuam operatia pe care o dorim
        }
        LeaveCriticalSection(&amp;amp;crit_sect); // iesim din sectiunea critical
        //cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        Sleep(10); // dam timp si celuilalt thread sa preia controlul aspura sectini critice si sa faca incrementarea
        // in caz contrar doar primul thread va face incrementarile.
    }while(ctr &amp;lt; 100);
}

int main()
{
    DWORD identificatorTRD1 = 0;
    DWORD identificatorTRD2 = 0;
    // creem intai seciunea critica deoarece daca creem intai threadurile vor porni direct
    // si vor incerca sa acceseze o sectiune critiune critica inexistenta
    InitializeCriticalSection(&amp;amp;crit_sect); // initializam sectiunea critica
    HANDLE trdHdl1 = CreateThread(NULL, 0, trdLoop, NULL, 0, &amp;amp;identificatorTRD1);
 if(trdHdl1 == NULL)
 {
  cout &amp;lt;&amp;lt;&quot;Eroare la creere thread 1, iesim.&quot; &amp;lt;&amp;lt; endl;
  return 0;
 }
 HANDLE trdHdl2 = CreateThread(NULL, 0, trdLoop, NULL, 0, &amp;amp;identificatorTRD2);
 if(trdHdl2 == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere thread 2, iesim.&quot; &amp;lt;&amp;lt; endl;
        return 0;
    }

    WaitForSingleObject(trdHdl1, INFINITE); // asteptam ca threadul1 sa termine
    WaitForSingleObject(trdHdl2, INFINITE); // asteptam ca threadul2 sa termine
 // inchidem handle-urile
 CloseHandle(trdHdl1);
 CloseHandle(trdHdl2);

    return 0;
}
&lt;/pre&gt;
&amp;nbsp; &amp;nbsp;Semaphores:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; - Semafoarele sunt obiecte folosite pentru a limita numarul de threaduri care pot avea acces la o resursa&lt;br /&gt;
in acelasi timp
  Sa zicem ca avem o baza de date si vrem sa limitam numarul de conexiuni la acea baza de&lt;br /&gt;
date. In cazul acesta vom folosi un semaphore
  Creerea unui semaphore se face cu ajutorul urmatoarei functii:
  &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; HANDLE WINAPI CreateSemaphore(
    _In_opt_  LPSECURITY_ATTRIBUTES &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;lpSemaphoreAttributes,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_      LONG lInitialCount,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_      LONG lMaximumCount,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;_In_opt_  LPCTSTR lpName
  );&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Daca functia este executata cu succes atunci aceasta returneaza un handle catre obiectul dorit. Daca&lt;br /&gt;
obiectul exista deja(pe baza numelui furnizat ultimului argument) atunci este returnat un handle catre acest&lt;br /&gt;
obiect deja
  existent. In acest caz se poate apela functia GetLastError care va returna&lt;br /&gt;
ERROR_ALREADY_EXISTS. In cazul in care functia esueaza, valoarea returnata va fi NULL.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Parametrii asteptati de aceasta functie sunt urmatorii:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_opt_  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes la fel ca si in celelalte cazuri de mai sus acest parametru spune ce permisiuni are acest semaphore&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_      LONG lInitialCount - numarul initial de threaduri/procese care pot sa acceseze&lt;br /&gt;
aceasta resursa. Atunci cand un thread/proces preia proprietatea asupra acestui semaphore
   aceasta valoare&lt;br /&gt;
este decrementata, iar cand threadul respectiv elibereaza semaphore-ul, cu ajutorul functiei&lt;br /&gt;
ReleaseSemaphore, aceasta valoare este incrementata. Valoarea aceasta nu poate depasii valoarea&lt;br /&gt;
lMaximumCount&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_      LONG lMaximumCount - numarul maxim de threaduri/procese care pot accesa aceasta resursa &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_opt_  LPCTSTR lpName - numele semaphore-ului.
 Mai jos aveti un exemplu in care mai multe&lt;br /&gt;
threaduri incrementeaza o variabila, totusi semaforul nu permite decat la 4 threaduri sa faca incrementarea in&lt;br /&gt;
acelasi timp.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; In acest exemplu ne folosim de sectiunea critica pentru a ne asigura ca nu sunt 2 threaduri care incearca sa scrie aceeasi variabila in acelasi timp.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

int ctr = 0; // counterul ce va fi incrementat pe rand de cele 2 threaduri
CRITICAL_SECTION crit_sect; // Sectiune critica ce va proteja variabila ctr de la a fi scrisa de mai multe threaduri odata.
HANDLE semafor; // ce se va asigura ca doar 4 threaduri lucreaza in acelasi timp
int MAX_SEM = 4; // numarul maxim de threaduri ce pot accesa variabila
int MAX_THREADS = 10; // numarul maxim de threaduri

DWORD WINAPI trdLoop(LPVOID lpParam)
{
    DWORD dwWaitResult; // va stoca rezultatul actiuni de asteptare pentru obtinerea proprietatii threadului
    for(int i = 0; i &amp;lt; MAX_THREADS; i++)
    {
        dwWaitResult = WaitForSingleObject(semafor, INFINITE); // asteptam ca semaforul sa semnalizeze ca avem permisiunea sa accesam zona respectiva
        switch(dwWaitResult)
        {
        case WAIT_OBJECT_0:
            {
                EnterCriticalSection(&amp;amp;crit_sect); // intram in sectiunea critica
                {
                    cout &amp;lt;&amp;lt; GetCurrentThreadId() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ctr++ &amp;lt;&amp;lt; endl; // efectuam operatia pe care o dorim
                }
                LeaveCriticalSection(&amp;amp;crit_sect); // iesim din sectiunea critical
                break;
            }
        default:
            {
                cout &amp;lt;&amp;lt; &quot;Caz necunoscut, eroare: &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; endl;
            }

        }
        ReleaseSemaphore(semafor, 1, NULL);

        //cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; endl;
        Sleep(10); // dam timp si celuilalt thread sa preia controlul aspura sectini critice si sa faca incrementarea
        // in caz contrar doar primul thread va face incrementarile.
    }
}

int main()
{
    DWORD identificatoriThreaduri[MAX_THREADS];
    semafor = CreateSemaphore(NULL, MAX_SEM, MAX_SEM, NULL);
    HANDLE thrds[MAX_THREADS];
    if(semafor == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere semafor, iesim.&quot; &amp;lt;&amp;lt; endl;
        return 0;
    }
    // creem intai mutex-ul deoarece daca creem intai threadurile vor porni direct
    // si vor incerca sa acceseze un mutex care nu exista
    InitializeCriticalSection(&amp;amp;crit_sect);
    for(int i = 0; i &amp;lt; MAX_THREADS;i++) // creem cele 10 threaduri
    {
        thrds[i] = CreateThread(NULL, 0, trdLoop, NULL, 0, &amp;amp;identificatoriThreaduri[i]);
        if(thrds[i] == NULL)
        {
            cout &amp;lt;&amp;lt; &quot;Eroare la creere thread numarul &quot; &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot; iesim. &quot; &amp;lt;&amp;lt; endl;
            return 0;
        }
    }
    WaitForMultipleObjects(MAX_THREADS, thrds, TRUE, INFINITE); // asteptam ca threadurile sa termine.

    for(int i = 0; i &amp;lt; MAX_THREADS;i++)
    {
        CloseHandle(thrds[i]);
    }

    return 0;
}
&lt;/pre&gt;
&amp;nbsp; &amp;nbsp;Waitable time&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; -Este un obiect folosit in mare parte atunci cand avem nevoie sa verificam sau sa facem ceva la un&lt;br /&gt;
anumit interval de timp
 Sa zicem ca o data la 5 secunde trebuie sa verificam ceva si sa facem ceva dupa,&lt;br /&gt;
in cazul acesta s-ar putea folosi un waitable timer.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; El este creat cu functia urmatoare:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;HANDLE WINAPI CreateWaitableTimer(
   _In_opt_  LPSECURITY_ATTRIBUTES &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; lpTimerAttributes,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_      BOOL bManualReset,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_opt_  LPCTSTR lpTimerName
 );&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Daca functia este executata cu succes atunci aceasta returneaza un handle catre obiectul dorit. Daca&lt;br /&gt;
obiectul exista deja(pe baza numelui furnizat ultimului argument) atunci este returnat un handle catre acest&lt;br /&gt;
obiect deja
 existent. In acest caz se poate apela functia GetLastError care va returna&lt;br /&gt;
ERROR_ALREADY_EXISTS. In cazul in care functia esueaza, valoarea returnata va fi NULL.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Parametri:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_opt_  LPSECURITY_ATTRIBUTES lpTimerAttributes descriptorul de securitate comun celor 5 obiecte folosite in sincronizare&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_      BOOL bManualReset specifica daca este un timer ce trebui resetat manual sau se va reseta&lt;br /&gt;
singur. Daca valoarea este adevarata atunci
   timerul va trebui resetat de catre programator dupa efectuarea&lt;br /&gt;
unui WaitOnSingleObject/WaitOnMultipleObjects. Daca acest parametru este false
   atunci timer-ul se va&lt;br /&gt;
reseta automat atunci cand are loc cu succes o asteptare pentru una din functiile de asteptare.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_opt_  LPCTSTR lpTimerName numele timer-ului, acesta poate fi NULL
 Trebuie avut grija cu&lt;br /&gt;
aceste obiecte insa, in conditiile in care timer-ul este verificat de prea multe ori, poatet folosi o parte mare din&lt;br /&gt;
timpul procesorului, acest lucru ne mai permitand celorlalte threaduri sa 
 execute operatiile lor. Din aceasta&lt;br /&gt;
cauza este de preferat, acolo unde se poate sa se foloseasca evenimente, despre care vom discuta un pic&lt;br /&gt;
mai jos.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Mai jos aveti un exemplu de folosire al waitable timers:&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

int ctr = 0; // counterul ce va fi incrementat pe rand de cele 2 threaduri
HANDLE timer; // ce se va asigura ca doar 4 threaduri lucreaza in acelasi timp

DWORD WINAPI trdLoop(LPVOID lpParam)
{
    DWORD dwWaitResult; // va stoca rezultatul actiuni de asteptare pentru obtinerea proprietatii threadului
    LARGE_INTEGER timpAsteptare;
    timpAsteptare.QuadPart = -1000000LL; // 100 milisecunde (1/100) secunde in pasi de 100 nanosecunde
    do
    {
        dwWaitResult = WaitForSingleObject(timer, INFINITE);
        if(dwWaitResult != WAIT_OBJECT_0)
        {
            cout &amp;lt;&amp;lt; &quot;Eroare la asteptare: &quot; &amp;lt;&amp;lt; GetLastError() &amp;lt;&amp;lt; endl;
        }
        cout &amp;lt;&amp;lt; &quot;Thread &quot; &amp;lt;&amp;lt; GetCurrentThreadId() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ctr++ &amp;lt;&amp;lt; endl;
        if(!SetWaitableTimer(timer, &amp;amp;timpAsteptare, 0, NULL, NULL, 0))
        {
            cout &amp;lt;&amp;lt; &quot;Eroare la setare timer, iesim. &quot; &amp;lt;&amp;lt; endl;
            return 1;
        }
    }while (ctr &amp;lt; 10);
}

int main()
{
    timer = CreateWaitableTimer(NULL, TRUE, NULL);// creem timer cu resetare manuala
    LARGE_INTEGER timpAsteptare;
    HANDLE thrd;
    DWORD identificatorThread;
    timpAsteptare.QuadPart = -1000000LL;
    if(timer == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere waitable timer, iesim. &quot; &amp;lt;&amp;lt; endl;
        return 0;
    }
    if(!SetWaitableTimer(timer, &amp;amp;timpAsteptare, 0, NULL, NULL, 0)) // il setam la 100 milisecunde
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la setare timer, iesim. &quot; &amp;lt;&amp;lt; endl;
        return 0;
    }
    thrd = CreateThread(NULL, 0, trdLoop, NULL, 0, &amp;amp;identificatorThread); // creem si rula, thread
    if(thrd == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere thread, iesim. &quot; &amp;lt;&amp;lt; endl;
        return 0;
    }

    WaitForSingleObject(thrd, INFINITE); //asteptam ca threadul sa termine

    CloseHandle(thrd); // inchidem threadul
    CloseHandle(timer); // inchidem timerul


    return 0;
}
 
&lt;/pre&gt;
&amp;nbsp; &amp;nbsp;Evenimente&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; -Comparativ cu celelalte obiecte de sincronizare nu sunt folosite pentru a proteja variabile comune sau&lt;br /&gt;
pentru a face o actiune la un anumit interval de timp.
 Evenimentele sunt folosite pentru a semnaliza intre&lt;br /&gt;
threaduri intalnirea anumitor conditii, incheierea unei anumite actiuni, smd.
 Procesul de utilizare al&lt;br /&gt;
evenimentelor este urmatorul:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- Creere eveniment cu anumite stari(manual reset/auto reset, stare initiala semnalizata sau nesemnalizata
  &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- Setarea evenimentului(in general de catre cel care l-a si creat)
  - In alt threadu/proces sau in acelasi&lt;br /&gt;
thread asteptam ca threadul sa devina semnalizat cu functia WaitForSingleObject, sau daca avem de&lt;br /&gt;
asteptat dupa mai multe evenimente cu WaitForMultipleObjects&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- Daca evenimentul este creeat cu manual reset in resetam cu ajutorul functiei SetEvent, sau daca&lt;br /&gt;
dorim sa il resetam inainte ca acesta sa fie prelucrat cu functia WaitForSingleObject /&lt;br /&gt;
WaitForMultipleObjects folosim functia ResetEvent.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Creerea unui event se face cu ajutorul urmatoarei functii:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;HANDLE WINAPI CreateEvent(
    _In_opt_  LPSECURITY_ATTRIBUTES lpEventAttributes,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_      BOOL bManualReset,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_      BOOL bInitialState,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_opt_  LPCTSTR lpName
  );&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Parametri:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - _In_opt_  LPSECURITY_ATTRIBUTES lpEventAttributes - descriptorul a tributelor de securitate &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - _In_      BOOL bManualReset specifica daca evenimentul se reseteaza manual(cu functiile specificate&lt;br /&gt;
mai sus) sau se reseteaza singur la starea de nesemnalizare&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - _In_      BOOL bInitialState specifica daca evenimentul este creeat in stare semnalizata sau&lt;br /&gt;
nesemnalizata. Un eveniment, sau orice alt obiect cu care am lucrat pana acum, care este in stare semnalizata
   &lt;br /&gt;
va fi prins de functiile de genul WaitForSingle/MultipleObject. Atunci cand un astfel de obiect este&lt;br /&gt;
nesemnalizat atunci functiile de asteptare ruleaza pana cand obiectul este semnalizat&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - _In_opt_  LPCTSTR lpName numele evenimentului. In acest caz este de preferat sa numiti&lt;br /&gt;
evenimentele, pentru a fi mai usor de utilizat.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Daca functia este executata cu succes atunci aceasta returneaza un handle catre obiectul dorit.&lt;br /&gt;
Daca obiectul exista deja(pe baza numelui furnizat ultimului argument) atunci este returnat un handle catre&lt;br /&gt;
acest obiect deja
 existent. In acest caz se poate apela functia GetLastError care va returna&lt;br /&gt;
ERROR_ALREADY_EXISTS. In cazul in care functia esueaza, valoarea returnata va fi NULL.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Mai jos avem un mic exemplu. Codul creeaza 2 threaduri, primul thread ruleaza incrementand&lt;br /&gt;
variabila ctr, al 2-lea thread asteapta in acest timp ca primul thread sa termine. Cand threadul termina&lt;br /&gt;
semnalizeaza acest
 lucru cu functia SetEvent. Dupa asta al 2-lea thread face si el incrementarile pe care le&lt;br /&gt;
are de facut.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;windows.h&amp;gt;

using namespace std;

int ctr = 0; // counterul ce va fi incrementat pe rand de cele 2 threaduri
HANDLE event; // evenimentul nostru

DWORD WINAPI trdLoop1(LPVOID lpParam) // primul thread
{
    for(int i = 0; i &amp;lt; 10; i++)
    {
        cout &amp;lt;&amp;lt; &quot;Thread &quot; &amp;lt;&amp;lt; GetCurrentThreadId() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ctr++ &amp;lt;&amp;lt; endl;
        Sleep(100);
    }
    if(!SetEvent(event)) // Setam evenimentul ca semnalizat, in acest caz al 2-lea thread primeste confirmarea ca am terminat si poate incepe sa ruleze
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la setare eveniment, iesim.&quot; &amp;lt;&amp;lt; endl;
        return 0;
    }
}

DWORD WINAPI trdLoop2(LPVOID lpParam) // al 2-lea thread
{
    DWORD dwWaitResult = WaitForSingleObject(event, INFINITE);
    if(dwWaitResult == WAIT_OBJECT_0)
    {
        for(int i = 0; i &amp;lt; 10; i++)
        {
            cout &amp;lt;&amp;lt; &quot;Thread &quot; &amp;lt;&amp;lt; GetCurrentThreadId() &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; ctr++ &amp;lt;&amp;lt; endl;
            Sleep(100);
        }
    }
}

int main()
{
    DWORD identificatorTrd1;
    DWORD identificatorTrd2;
    event = CreateEvent(NULL, TRUE, FALSE, &quot;TRD1Finish&quot;); // creem evenimentul si ne asiguram ca e corect creat
    if(event == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere eveniment, iesim. &quot; &amp;lt;&amp;lt; endl;
        return 0;
    }
    HANDLE trd1;
    HANDLE trd2;
    trd1 = CreateThread(NULL, 0, trdLoop1, NULL, 0, &amp;amp;identificatorTrd1); // creem thread 1
    if(trd1 == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere thread1, iesim. &quot; &amp;lt;&amp;lt; endl;
        return 0;
    }
    trd2 = CreateThread(NULL, 0, trdLoop2, NULL, 0, &amp;amp;identificatorTrd2); // creem thread 2
    if(trd2 == NULL)
    {
        cout &amp;lt;&amp;lt; &quot;Eroare la creere thread2, iesim. &quot; &amp;lt;&amp;lt; endl;
        return 0;
    }

    WaitForSingleObject(trd1, INFINITE);
    WaitForSingleObject(trd2, INFINITE);

    CloseHandle(trd1);
    CloseHandle(trd2);
    CloseHandle(event);


    return 0;
}

&lt;/pre&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Pana acum am vorbit despre creerea, resumarea si inchiderea unui thread, si despre elementele de&lt;br /&gt;
sincronizare a datelor si threadurilor. Totusi in toate cele 3 cazuri am o functie pe care nu am explicat-o.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Aceasta este WaitForSingleObject(trdHdl, INFINITE); De fapt functia aceasta ce face? Asteapta dupa un semnal de la unul din posibilele handle-uri pe care le accepta, si anume : thread, mutex, event, semaphore si sectiune critica.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Pentru threade-uri semnalul asteptat este de incheiere al executiei&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Pentru mutex asteapta ca mutex-ul sa semnalizeze ca nu mai este &quot;inchis&quot;/&quot;detinut&quot; de catre un alt proces/thread&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Pentru semaphores asteapta pana cand exista un loc liber in lista cu obiecte ce detin proprietatea asupra semaforului.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Pentru sectiuni critice actioneaza la fel ca si in cazul mutexilor&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Pentru evenimente asteapta ca avenimentul respectiv sa devina semnalizat.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Functia este cam asa:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DWORD WINAPI WaitForSingleObject(&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_  HANDLE hHandle,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_  DWORD dwMilliseconds&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; );&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_  HANDLE hHandle este dupa cum am spus mai sus, handle-ul threadului pentru care dorim sa&lt;br /&gt;
asteptam sa termine.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_  DWORD dwMilliseconds este perioada de timp pe care programul sa o astepte. Acest al 2-lea argument poate primi 3 valori:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - valoarea zero caz in care pur si simplu verifica daca threadul a semnalizat ca si-a incheiat procesul, dupa care functia iese&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - o valoare nonzero pozitiva, in milisecunde dupa cum numele sugereaza&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - valoarea INFINITE caz in care functia va astepta pana cand threadul va semnaliza iesirea(dupa cum am facut noi acum)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Functia asta poate returna 4 valori:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_ABANDONED este returnat cand in thread termina executia inainte sa elibereze un mutex pe care il detine&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_OBJECT_0 este returnat atunci cand threadul asteptat si-a semnalizat incheierea executiei&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_TIMEOUT este returnat atunci cand parametrului dwMilliseconds ii este furnizata o valoare diferita de 0 si de INFINITE, iar aceasta perioada trece&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_FAILED indica faptul ca a aparut o eroare in asteptarea threadului respectiv. Pentru a vedea ce eroare am primit se poate apela functia GetLastError. Atentie, aceasta functie trebuie apelata imediat&lt;br /&gt;
dupa executia functiei aceasta deoarece orice alta functie din WinApi ce poate intalni o eroare va inlocui eroarea dorita de noi.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Exista o functie sora a acesteia, care asteapta un anumit set de threaduri sa termine executia&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Functia arata cam asa:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DWORD WINAPI WaitForMultipleObjects(&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _In_  DWORD nCount,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;_In_  const HANDLE *lpHandles,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;_In_  BOOL bWaitAll,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;_In_  DWORD dwMilliseconds&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;);&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_  DWORD nCount reprezinta numarul de handle-uri pentru care functia trebuie sa astepte. Acest trebuie sa aiba valoarea mai mare decat 0, si in mod normal ar trebui sa fie egal cu numarul de elemente din lpHandles&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_  const HANDLE *lpHandles este un pointer catre o matrice ce contine handle-urile catre threadurile noastre. Aveti grija, in aceasta matrice nu trebuie sa existe handle-uri care sa indice catre acelasi&lt;br /&gt;
thread. De asemenea aveti grija sa nu inchideti threadurile cu CloseHandle inainte ca acestea sa termine,&lt;br /&gt;
deoarece functia nu va mai functiona corect. In acest caz este vorba de &quot;comportament nedefinit&quot;.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_  BOOL bWaitAll specifica daca functia sa astepte dupa toate threadurile sau doar dupa 1 din ele. Daca parametrul este TRUE atunci functia va astepta dupa absolut toate threadurile din matrice. Daca parametrul este FALSE atunci functia va incheia executa in momentul in care primul thread semnalizeaza ca&lt;br /&gt;
si-a incheiat executia.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- _In_  DWORD dwMilliseconds reprezinta perioada pe care functia o va astepta, la fel ca si la functia WaitForSingleObject si aceasta va accepta aceleasi valori:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - valoarea zero caz in care pur si simplu verifica daca threadul a semnalizat ca si-a incheiat procesul, dupa care functia iese&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - o valoare nonzero pozitiva, in milisecunde dupa cum numele sugereaza&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - valoarea INFINITE caz in care functia va astepta pana cand threadul va semnaliza iesirea(dupa cum am facut noi acum)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; Functia aceasta poate returna urmatoarele valori:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_OBJECT_0 daca parametrul bWaitAll este TRUE. Asta inseamna ca toate threadurile au semnalizat ca si-au incheiat executia.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_OBJECT_0 + (nCount - 1) daca parametrul bWaitAll este false. In cazul asta valoarea returnata va fi suma dintre WAIT_OBJECT_0 si indexul la care se afla threadul ce a semnalizat incheierea&lt;br /&gt;
executiei. Evident, pentru a afla care este indexul threadului respectiv in matricea cu threaduri este suficient sa scadem din numarul returnat valoarea WAIT_OBJEC_0&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_ABANDONED_0 daca bWaitAll este TRUE indica faptul ca cel putin unul din handle-uri&lt;br /&gt;
este un mutex abandonat(vezi aceeasi valoare de return la WaitForSingleObject) si ca celelalte threaduri au&lt;br /&gt;
semnalizat incheierea executiei&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_ABANDONED_0 daca bWaitAll este FALSE indica indexul unui mutex care a fost abandonat(procesul/threadul care l-a creeat si-a terminat executia sau a fost inchis) dar care totusi este in stare semnalizata. In acest caz, proprietatea asupra threadului va fi trecuta catre threadul/procesul care a&lt;br /&gt;
executat functia de asteptare iar mutex-ul va fi trecut in stare nesemnalizata.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_TIMEOUT este returnat atunci cand perioada stabilita prin parametrul dwMillisecond este un numar finit iar conditia pusa de parametrul bWaitAll nu este satisfacuta(pentru bWaitAll adevarat, nu toate obiectele asteptate au fost semnalizate, daca bWaitAll este fals, nici &lt;br /&gt;
unul din obiectele asteptate nu a semnalizat.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- WAIT_FAILED indica faptul ca a existat o problema in executarea functiei. In acest caz se poate obtine textul erorii cu ajutorul functiei GetLastError.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;nbsp;Cam aici se incheie primul tutorial privind threadurile din WinApi in C++. Vor mai urma cateva tutoriale cu notiuni pe aceasta tema in care vom discuta si alte subiecte&lt;br /&gt;
Ca si un fel de tema de acasa incercati sa faceti si voi cate o mini aplicatie in care sa folositi cele invatate in acest tutorial.&lt;br /&gt;
Ca si cateva idei, puteti sa faceti un joculet in care sa folositi un waitable timer pentru a permite utilizatorului doar un anumit timp pentru efectuarea unei actiuni,&lt;br /&gt;
sau ati putea sa scriei un programel care pur si simplu copiaza un fisier dintr-o parte in alta(intr-un alt thread) iar la final threadul ce face copierea sa semnalizeze incheierea printr-un event.&lt;br /&gt;
Sper ca v-a placut tutorialul si ca va v-a ajuta. Daca aveti intrebari nu eziatati sa le puneti.</content><link rel='replies' type='application/atom+xml' href='http://florinrada.blogspot.com/feeds/3355193427485728008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://florinrada.blogspot.com/2014/06/tutorial-introducere-in-threading-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/3355193427485728008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/3355193427485728008'/><link rel='alternate' type='text/html' href='http://florinrada.blogspot.com/2014/06/tutorial-introducere-in-threading-in.html' title='Tutorial introducere in threading in WinApi(C++)'/><author><name>florin.rada</name><uri>http://www.blogger.com/profile/07336044099523183162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7735655402128608226.post-3469180305333524373</id><published>2012-07-03T08:38:00.000-07:00</published><updated>2012-07-03T08:38:09.749-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="OBDC WRAPER; Functii ODBC"/><title type='text'>[C++]Functii odbc operare baza date access 2003-2007</title><content type='html'>Salut, va prezint un alt proiect mai vechi, de aceasta data legat de operarea cu bazele de date access - asta aveam nevoie la timpul respectiv.
Sunt doar 4 functii simple una pentru &quot;select&quot; din sql, alta pentru &quot;insert&quot;, una pentru recuperarea erori/erorilor si una pentru a face curat dupa celelalte 3 functii.
Functiile sunt foarte simple, dar pentru proiectul la care am avut nevoie la momentul respectiv si-au facut treaba cu brio. Pentru a le utiliza aveti nevoie sa legati (link) libraria odbc32.
Functiile se folosesc de api-ul ODBC, si pot fi modificate pentru a putea rula cu orice tip de baza de date la care va puteti conecta cu ODBC. Pentru a le utiliza nu trebuie decat sa adaugati cele 2 fisiere proiectului vostru.
&lt;br&gt;&lt;br&gt;functii_odbc.h
&lt;pre class=&quot;brush: cpp&quot;&gt;
#ifndef FUNCTII_ODBC_H_INCLUDED
#define FUNCTII_ODBC_H_INCLUDED

#include &amp;lt;iostream&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;sstream&amp;gt;
#include &amp;lt;fstream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;windows.h&amp;gt;
#include &amp;lt;sql.h&amp;gt;
#include &amp;lt;sqlext.h&amp;gt;


int select(std::string dns, int numarCampuri, std::string querry, std::vector&amp;lt;std::vector&amp;lt; std::string&amp;gt; &amp;gt;&amp;amp; array, std::string&amp;amp; erroare);
void getErrors(SQLSMALLINT type,SQLHANDLE handle, std::string&amp;amp; error);
void freeDbResources(HSTMT&amp;amp; hStmt, HENV&amp;amp; hEnv, HDBC&amp;amp; hDbc);
int insert(std::string dns, std::string num_Tabel, std::vector&amp;lt;std::string&amp;gt; Campuri, std::vector&amp;lt;std::string&amp;gt; Valori, std::string&amp;amp; error);

#endif // FUNCTII_ODBC_H_INCLUDED
&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;functii_odbc.cpp
&lt;pre class=&quot;brush: cpp&quot;&gt;
#include &amp;quot;functii_odbc.h&amp;quot;
/**
 * Lista argumente:
 * string dns = adresa fisierului acces mdb/accdb pe hard-disk
 * numarCampuri = numarul de campuri care urmeaza a fi selectate prin querry-ul respectiv
 * vector&amp;lt;vector&amp;lt;string&amp;gt; &amp;gt;&amp;amp; array = este un vector de vectori de stringuri, trimis prin referinta care va contine datele extrase
 * in felul urmator: array[0][0] va fi prima coloana returnata pe primul rand
 * array[0][1] va fi a 2-a coloana
 * array[0][2] va fi a 3-a coloana smd
 * iar array[x][0], x va desemna randul de date extrase
 * string&amp;amp; eroare = va contine mesajele de eroare, in situatia in care apare o eroare in executia functiei sau a querry-ului atunci aceasta va fi salvata in acest string
 * Functia are doar 2 valori de return 1 = succes in executarea querry-ului, sau -1 eroare
 * Functia face doar cateva verificari de baza in privinta corectitudinii querry-ului
 * De asta trebuie sa se asigure utilizatorul inainte
 * Functia va verifica doar daca exista un posibil insert in querry caz in care iese.
 */
using namespace std;
int select(string dns, int numarCampuri, string querry, vector&amp;lt;vector&amp;lt;string&amp;gt; &amp;gt;&amp;amp; array, string&amp;amp; erroare)
{
    if(querry.find(&amp;quot;SELECT&amp;quot;) == string::npos || querry.find(&amp;quot;INSERT&amp;quot;) != string::npos)
    {
        erroare = &amp;quot;Nu ai introdus o comanda de select;&amp;quot;;
    }
    else
    {
        SQLCHAR valoareCustomers[numarCampuri][128];
        HSTMT querryStmt;
        string tempNume;
        int retCode[numarCampuri];
        HENV hEnv;
        HDBC hDbc;
        RETCODE rc;
        int len = querry.size();
        char szConnStrOut[255];
        int iConnStrLength2Ptr;
        char szDSN[256] = &amp;quot;Driver={Microsoft Access Driver (*.mdb)};DSN=&amp;#39;&amp;#39;;DBQ=&amp;quot;;
        unsigned char* statementQuerry = (unsigned char*)querry.c_str();
        //vStrArray.clear(); // golim vectorul primit ca container de output (este datoria utilizatorului sa se asigure ca nu are nimic important in vector inainte de a fi trimis acestei functii
        strcat(szDSN, dns.c_str());
        rc = SQLAllocEnv(&amp;amp;hEnv);
        if(!SQL_SUCCEEDED(rc))
        {
            erroare = &amp;quot;Nu am putut aloca Envorimentul.&amp;quot;;
            cout &amp;lt;&amp;lt; &amp;quot;Nu am putut aloca envorimentul.&amp;quot;;
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }
        rc = SQLAllocConnect(hEnv, &amp;amp;hDbc);
        if(!SQL_SUCCEEDED(rc))
        {
            erroare = &amp;quot;Nu am putut aloca conexiunea.&amp;quot;;
            cout &amp;lt;&amp;lt; &amp;quot;Nu am putut aloca conexiunea.&amp;quot;;
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }

        rc = SQLDriverConnect(hDbc, NULL, (SQLCHAR*)szDSN,
                            SQL_NTS, (SQLCHAR*)szConnStrOut,
                            255, (SQLSMALLINT*)&amp;amp;iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
        if(!SQL_SUCCEEDED(rc))
        {
            getErrors(SQL_HANDLE_DBC , hDbc, erroare);
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }
        rc = SQLAllocStmt(hDbc, &amp;amp;querryStmt);
        if(!SQL_SUCCEEDED(rc))
        {
            erroare = &amp;quot;Nu am putut aloca statementul.&amp;quot;;
            cout &amp;lt;&amp;lt; &amp;quot;Nu am putut aloca statementul.&amp;quot;;
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }
        rc = SQLPrepare(querryStmt, statementQuerry, SQL_NTS);
        if(!SQL_SUCCEEDED(rc))
        {
            erroare = &amp;quot;Nu am putut pregatii statementul.&amp;quot;;
            cout &amp;lt;&amp;lt; &amp;quot;Nu am putut pregatii statementul.&amp;quot;;
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }
        for(int i = 0; i &amp;lt; numarCampuri; i++)
        {
           rc = SQLBindCol(querryStmt, (i + 1), SQL_C_CHAR, valoareCustomers[i], 128, (SQLINTEGER*)&amp;amp;retCode[i]);
           if(!SQL_SUCCEEDED(rc))
            {
                erroare = &amp;quot;Nu am putut bindui coloana.&amp;quot;;
                cout &amp;lt;&amp;lt; &amp;quot;Nu am putut bindui coloana.&amp;quot;;
                freeDbResources(querryStmt, hEnv, hDbc);
                return -1;
            }
        }
        cout &amp;lt;&amp;lt; endl &amp;lt;&amp;lt; endl &amp;lt;&amp;lt; statementQuerry &amp;lt;&amp;lt; endl;
        rc = SQLExecute(querryStmt);
        if(SQL_ERROR == rc || SQL_SUCCESS_WITH_INFO == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;Eroare in executare statement, sau SQL_SUCCESS_WITH_INFO&amp;quot;;
            erroare = &amp;quot;Eroare in executare statement, sau SQL_SUCCESS_WITH_INFO&amp;quot;;
            getErrors(SQL_HANDLE_STMT, querryStmt, erroare);
            return -1;
        }
        else if(SQL_NEED_DATA == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;SQL_NEED_DATA.&amp;quot;;
            erroare = &amp;quot;SQL_NEED_DATA.&amp;quot;;
            getErrors(SQL_HANDLE_STMT, querryStmt, erroare);
            return -1;
        }
        else if(SQL_STILL_EXECUTING == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;SQL_STILL_EXECUTING.&amp;quot;;
            erroare = &amp;quot;SQL_STILL_EXECUTING.&amp;quot;;
            getErrors(SQL_HANDLE_STMT, querryStmt, erroare);
            return -1;
        }
        else if(SQL_NO_DATA == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;SQL_NO_DATA.&amp;quot;;
            erroare = &amp;quot;SQL_NO_DATA.&amp;quot;;
            getErrors(SQL_HANDLE_STMT, querryStmt, erroare);
            return -1;
        }
        else if(SQL_INVALID_HANDLE == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;SQL_INVALID_HANDLE.&amp;quot;;
            erroare = &amp;quot;SQL_INVALID_HANDLE&amp;quot;;
            getErrors(SQL_HANDLE_STMT, querryStmt, erroare);
            return -1;
        }
        rc = SQLFetch(querryStmt);
        if(SQL_SUCCESS == rc)
        {
            while(SQL_SUCCEEDED(rc))
            {
                vector&amp;lt;string&amp;gt; vString;
                string temp;
                for(int i = 0; i &amp;lt; numarCampuri; i++)
                {
                    temp = (char*)valoareCustomers[i];
                    vString.push_back(temp);
                }
                array.push_back(vString);
                rc = SQLFetch(querryStmt);
            }
            freeDbResources(querryStmt, hEnv, hDbc);
            return 1;
        }
        else if(SQL_SUCCESS_WITH_INFO == rc || SQL_ERROR == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;Nu am putut executa SQLFetch.\n&amp;quot;;
            cout &amp;lt;&amp;lt; &amp;quot;Nu am putut executa SQLFetch.\n&amp;quot;;
            getErrors(SQL_HANDLE_STMT, querryStmt, erroare);
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }
        else if(SQL_STILL_EXECUTING == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;Inca se executa statementul.\n&amp;quot;;
            erroare = &amp;quot;Inca se executa statementul.\n&amp;quot;;
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }
        else if(SQL_NO_DATA == rc)
        {
            cout &amp;lt;&amp;lt; &amp;quot;Nu exista date de returnat.\n&amp;quot;;
            erroare = &amp;quot;Nu exista date de returnat.\n&amp;quot;;
            freeDbResources(querryStmt, hEnv, hDbc);
            return -1;
        }
    }
    return -1;
}



/**
 * Functia preia prin referinta handle-urile pentru conexiune, mediu si statement si le elibereaza
 */
void freeDbResources(HSTMT&amp;amp; hStmt, HENV&amp;amp; hEnv, HDBC&amp;amp; hDbc)
{
    SQLFreeStmt(hStmt, SQL_UNBIND);
    SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
    SQLDisconnect(hDbc);
    SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
    SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
}


/**
 * Functia preia datele necesare pentru a putea prelua o eroare legata de un handle pentru conexiune, statement sau mediu
 * SQLSMALLINT type poate fi: QL_HANDLE_DBC, SQL_HANDLE_DBC_INFO_TOKEN, SQL_HANDLE_DESC, SQL_HANDLE_ENV, SQL_HANDLE_STMT
 * SQLHANDLE handle va fi de fapt handle-ul pentru care aven nevoie sa preluam eroarea
 * string&amp;amp; eroare = va tine textul erori
 * Functia preia doar erorile care pot fi preluate prin SQLGetDiagRec.
 * Mai multe informatii despre SQLGetDiagRec aici: http://msdn.microsoft.com/en-us/library/windows/desktop/ms716256(v=vs.85).aspx
 */
void getErrors(SQLSMALLINT type,SQLHANDLE handle, string&amp;amp; eroare)
{
    SQLINTEGER i = 1;
    SQLINTEGER native; // codul nativ al erori ( depinde de sistemul de operare si de driver
    SQLCHAR state[7]; // starea driverului mai multe informatii despre state : http://msdn.microsoft.com/en-us/library/windows/desktop/ms716412(v=vs.85).aspx
    SQLCHAR text[256]; // textul erori
    SQLSMALLINT len; // marimea textului erori
    SQLRETURN ret; // stocheaza raspunsul functiei SQLGetDiagRec
    ret = SQLGetDiagRec(type, handle, i, (SQLCHAR*)state, &amp;amp;native, (SQLCHAR*)text, sizeof(text), &amp;amp;len );
    if(SQL_SUCCESS == ret || SQL_SUCCESS_WITH_INFO == ret)
    {
        stringstream buffer(stringstream::in | stringstream::out);
        string temp;
        eroare = &amp;quot;Eroare:\n&amp;quot;;
        eroare.append(&amp;quot;State: &amp;quot;);
        cout &amp;lt;&amp;lt; &amp;quot;State: &amp;quot; &amp;lt;&amp;lt; state &amp;lt;&amp;lt; endl;
        buffer &amp;lt;&amp;lt; state;
        buffer &amp;gt;&amp;gt; temp;
        eroare.append(temp);
        buffer.flush();
        string temp3((char*)text);
        eroare.append(&amp;quot;\nTextul eroarei: &amp;quot;);
        eroare.append(temp3);
        buffer.flush();
        cout &amp;lt;&amp;lt; &amp;quot;Textul erori: &amp;quot; &amp;lt;&amp;lt; text &amp;lt;&amp;lt; endl;
    }
    else if(SQL_ERROR == ret)
    {
        eroare = &amp;quot;eroare Raporting: SQLGetDiagRec returneaza o eroare.\n&amp;quot;;
    }
    else if(SQL_INVALID_HANDLE == ret)
    {
        eroare = &amp;quot;eroare Raporting: Handleul furnizat pentru preluarea erori a fost incorect.\n&amp;quot;;
    }
    else if(SQL_NO_DATA == ret)
    {
        eroare = &amp;quot;eroare Raporting: Nu au fost date de returnat.\n&amp;quot;;
    }
}

/**
 * Lista argumente:
 * string dns = adresa pe disk a fisierului access
 * string num_Tabel = numele tabelului in care se face inserarea
 * vector&amp;lt;string&amp;gt; Campuri = Un vector ce contine campurile in care se va face inserarea
 * vector&amp;lt;string&amp;gt; Valori = Un vector cu valorile ce vor fi introduse in fiecare camp
 * string&amp;amp; eroare va tine textul oricarei posibile erori
 * Pentru cei doi vectori marimea lor trebuie sa fie identica.
 * Exemplu Campuri va contine stringurile &amp;quot;Nume&amp;quot;, &amp;quot;Prenume&amp;quot; &amp;quot;telefon&amp;quot;
 * vectorul Valori va contine &amp;quot;ION&amp;quot;, &amp;quot;VASILE&amp;quot;, &amp;quot;02345241590&amp;quot;
 * Functia are doar 2 valori de return 1 = succes in inserarea datelor, sau -1 eroare
 */
int insert(string dns, string num_Tabel, vector&amp;lt;string&amp;gt; Campuri, vector&amp;lt;string&amp;gt; Valori, string&amp;amp; eroare)
{
    //Incepem pregatirea statmentului
    string comanda = &amp;quot;INSERT INTO &amp;quot;;
    string comanda2 = &amp;quot;) VALUES (&amp;#39;&amp;quot;;
    string comanda3 = &amp;quot;);&amp;quot;;
    string campuri_tabel;
    string campuri_valori;
    //verificam daca numarul de campuri si de valori e identic
    if(Campuri.size() != Valori.size())
    {
        eroare = &amp;quot;Numarul de campuri si de valori nu este identic. Pentru ca inserarea sa se poata efectua este necesar ca cele 2 sa fie identice.\n&amp;quot;;
        return -1;
    }
    // pregatim lista cu campurile in care se introduc datele
    for(unsigned int i = 0; i &amp;lt; Campuri.size(); i++)
    {
        if(i == (Campuri.size() - 1))
        {
            campuri_tabel.append(Campuri[i]);
            //campuri_tabel.append(&amp;quot;)&amp;quot;);
        }
        else
        {
            campuri_tabel.append(Campuri[i]);
            campuri_tabel.append(&amp;quot;, &amp;quot;);
        }
    }
    // pregatim lista cu valorile de introdus
    for(unsigned int i = 0; i &amp;lt; Valori.size(); i++)
    {
        if(i == (Valori.size() - 1))
        {
            campuri_valori.append(Valori[i]);
            campuri_valori.append(&amp;quot;&amp;#39;&amp;quot;);
        }
        else
        {
            campuri_valori.append(Valori[i]);
            campuri_valori.append(&amp;quot;&amp;#39;, &amp;#39;&amp;quot;);
        }
    }
    string sql_statement;
    sql_statement.append(comanda);
    sql_statement.append(num_Tabel);
    sql_statement.append(&amp;quot;(&amp;quot;);
    sql_statement.append(campuri_tabel);
    sql_statement.append(comanda2);
    sql_statement.append(campuri_valori);
    sql_statement.append(&amp;quot;);&amp;quot;);
    // am terminat pregatirea statementului

    // pregatim conexiunea la bd
    // inceput definitii variabile necesare conexiunii la db
    HENV hEnv;
    HDBC hDbc;
    HSTMT hStmt;
    RETCODE rc;
    char szConnStrOut[255];
    int iConnStrLength2Ptr;
    char szDSN[256] = &amp;quot;Driver={Microsoft Access Driver (*.mdb)};DSN=&amp;#39;&amp;#39;;DBQ=&amp;quot;;
    // incheiere definitii
    // Initiem conexiunea
    strcat(szDSN, dns.c_str());
    rc = SQLAllocEnv(&amp;amp;hEnv);
    if(!SQL_SUCCEEDED(rc))
    {
        eroare = &amp;quot;Nu am putut aloca Envorimentul.&amp;quot;;
        cout &amp;lt;&amp;lt; &amp;quot;Nu am putut aloca envorimentul.&amp;quot;;
        return -1;
    }
    rc = SQLAllocConnect(hEnv, &amp;amp;hDbc);
    if(!SQL_SUCCEEDED(rc))
    {
        eroare = &amp;quot;Nu am putut aloca conexiunea.&amp;quot;;
        cout &amp;lt;&amp;lt; &amp;quot;Nu am putut aloca conexiunea.&amp;quot;;
        return -1;
    }

    rc = SQLDriverConnect(hDbc, NULL, (SQLCHAR*)szDSN,
                           SQL_NTS, (SQLCHAR*)szConnStrOut,
                           255, (SQLSMALLINT*)&amp;amp;iConnStrLength2Ptr, SQL_DRIVER_NOPROMPT);
    if(!SQL_SUCCEEDED(rc))
    {
        getErrors(SQL_HANDLE_DBC , hDbc, eroare);
        freeDbResources(hStmt, hEnv, hDbc);
        return -1;
    }
    rc = SQLAllocStmt(hDbc, &amp;amp;hStmt);
    rc = SQLPrepare(hStmt, (SQLCHAR*)sql_statement.c_str(), SQL_NTS);
    rc = SQLExecute(hStmt);
    if(!SQL_SUCCEEDED(rc))
    {

        eroare = &amp;quot;Inserarea nu a putut fi efectuata.&amp;quot;;
        cout &amp;lt;&amp;lt; &amp;quot;Inserarea nu a putut fi efectuata.&amp;quot;;
        getErrors(SQL_HANDLE_STMT, hStmt, eroare);
        freeDbResources(hStmt, hEnv, hDbc);
        return -1;
    }
    else if(SQL_SUCCEEDED(rc))
    {
        freeDbResources(hStmt, hEnv, hDbc);
        return 1;
    }
    return -1;
}
&lt;/pre&gt;

Sper sa va fie utile.</content><link rel='replies' type='application/atom+xml' href='http://florinrada.blogspot.com/feeds/3469180305333524373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://florinrada.blogspot.com/2012/07/cfunctii-odbc-operare-baza-date-access.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/3469180305333524373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/3469180305333524373'/><link rel='alternate' type='text/html' href='http://florinrada.blogspot.com/2012/07/cfunctii-odbc-operare-baza-date-access.html' title='[C++]Functii odbc operare baza date access 2003-2007'/><author><name>florin.rada</name><uri>http://www.blogger.com/profile/07336044099523183162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7735655402128608226.post-8929650143044346194</id><published>2012-07-03T08:02:00.000-07:00</published><updated>2012-07-03T08:02:16.170-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Word list generator;Generator lista cuvinte"/><title type='text'>[C++]Generator de lista cuvinte(passwords)</title><content type='html'>Va prezint un proiect ceva mai vechi de al meu, acesta a fost scris in principiu pentru a genera toate combinatiile, ordonat, ale unei liste de caractere.
Generarea cuvintelor se face incepand cu un cuvant format din prima litera a sirului * lungimea dorita a cuvantului si se va termina cu un cuvant format din ultima litera din sir * lingimea cuvantului cerut.De exemplu pentru un sir de caracter a-z si lungimea cuvantului de 5 caractere, functia va incepe cu &quot;aaaaa&quot; si va termina cu &quot;zzzzz&quot;. Generarea se face printr-o functie recursiva, intr-un thread separat pentru a nu bloca interfata aplicatiei. Sistemul nu este nici cel mai eficient si nici cel mai rapid, totusi poate fi folosit ca punct de plecare. Proiectul a fost scris utilizant framework-ul wxWidgets, inclusiv modelul de threading al acestuia. Puteti compila cele 4 fisiere cpp/h adaugandu-le unui proiect menit sa compileze o aplicatie wxWidgets. In mod normal ar trebui sa poata fi compilata chiar si pe linux cu un minim de modificari, totusi nu am testat la momentul respectiv.
Proiectul a fost postat initial &lt;a href=https://rstcenter.com/forum/49395-c-wxwidgets-simple-word-list-generator.rst&gt;aici&lt;/a&gt;, unde puteti si adresa intrebari daca aveti.
Link-ul direct pentru a descarca proiectul se gaseste &lt;a href=http://www.mediafire.com/?qao392o49pxsp11&gt;aici&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://florinrada.blogspot.com/feeds/8929650143044346194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://florinrada.blogspot.com/2012/07/cgenerator-de-lista-cuvintepasswords.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/8929650143044346194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/8929650143044346194'/><link rel='alternate' type='text/html' href='http://florinrada.blogspot.com/2012/07/cgenerator-de-lista-cuvintepasswords.html' title='[C++]Generator de lista cuvinte(passwords)'/><author><name>florin.rada</name><uri>http://www.blogger.com/profile/07336044099523183162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7735655402128608226.post-5697795414809581410</id><published>2012-06-22T01:42:00.000-07:00</published><updated>2014-05-01T10:10:24.638-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Crypted chat"/><category scheme="http://www.blogger.com/atom/ns#" term="encrypted chat. IP to IP chat"/><category scheme="http://www.blogger.com/atom/ns#" term="secure chat"/><title type='text'>[c++]Crypted ip to ip chat</title><content type='html'>[RO]&lt;br /&gt;
Va prezint un program de chat securizat. Traficul dintre cele 2 persoane care vorbesc este criptat cu ajutorul algoritmului RSA, care este un algoritm te criptare cu cheie publica/privata.Libraria utilizata este &lt;a href=http://www.cryptopp.com/&gt;crypto++&lt;/a&gt; iar pentru interfata grafica am utilizat libraria &lt;a href=http://www.wxwidgets.org/&gt;wxWidgets&lt;/a&gt; versiunea 2.8.12. Mai jos voi adauga un link de download a proiectului, acesta a fost facut cu ajutorul ide-ului &lt;a href=http://codeblocks.org&gt;Code Blocks&lt;/a&gt;. Proiectul poate fi compilat cu orice alt ide prin adaugarea celor 4 fisiere cpp/h unui proiect gol creat de voi, atat timp cat proiectul este setat corect pentru a putea compila un proiect wxWidgets. Puteti utiliza sample-urile care vin o data cu libraria wxWidgets ca punct de start. Pentru crypto++ sugerez sa folositi libraria statica. &lt;a href=http://www.mediafire.com/?55ews068o2wgio2&gt;Proiectul in romana&lt;/a&gt; &lt;br /&gt;
&lt;br /&gt;
[EN]&lt;br /&gt;
I present you a secure chat. The trafic between the 2 people talking is encrypted with the help of the RSA algorithm, which is a public/private key encryption algorithm. The library used is &lt;a href=http://www.cryptopp.com/&gt;crypto++&lt;/a&gt;, and for the graphic interface i used the &lt;a href=http://www.wxwidgets.org/&gt;wxWidgets&lt;/a&gt; library version 2.8.12. Below i will ad a download link for the project, which was created with the help of &lt;a href=http://codeblocks.org&gt;Code Blocks&lt;/a&gt; ide. The project can be compiled with any other ide by adding the 4 cpp/h files to an empty project you create, as long as the project is correctly set up to compile wxWidgets application. You can use the samples that come along the wxWidgets librari as a starting point. For crypto++ i sugest you use the static library. &lt;a href=http://www.mediafire.com/?54a9buuua96wj9b&gt;English project&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://florinrada.blogspot.com/feeds/5697795414809581410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://florinrada.blogspot.com/2012/06/ccrypted-ip-to-ip-chat.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/5697795414809581410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/5697795414809581410'/><link rel='alternate' type='text/html' href='http://florinrada.blogspot.com/2012/06/ccrypted-ip-to-ip-chat.html' title='[c++]Crypted ip to ip chat'/><author><name>florin.rada</name><uri>http://www.blogger.com/profile/07336044099523183162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7735655402128608226.post-7499221709348198467</id><published>2010-09-14T09:58:00.000-07:00</published><updated>2012-05-07T07:53:38.665-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Coltul Programatorului"/><title type='text'>[C++]Conversie numere scrise in cifre arabe si viceversa</title><content type='html'>Salut, mai jos va voi prezenta u bucata de cod scrisa in C++, care poate fi folosita in diferite aplicatii. Codul de mai jos v-a prelua de la utilizator fie o cifra intre 0 si 9 fie corespondentul lor scris adica : zero, unu, doi, si v-a afisa valoarea convertita, adica daca utilizatorul va introduce cifra 5 programul v-a afisa &quot;cinci&quot; . Dupa va voi explica ce face si codul in sine.  &lt;pre class=&quot;brush: cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;conio.h&amp;gt;
#include &amp;lt;string&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
 
using namespace std;
 
 
int main()
{    
   char din_nou = &amp;#39; &amp;#39;;
   const int marime_vector = 10;
   int numar_de_control = 0; //folosit pentru controlul buclelor(loop&amp;#39;s)
   string temp; // stocheaza imput-ul utilizatorului
   vector&amp;lt;string&amp;gt; numere(marime_vector);
   numere[0] = &amp;quot;zero&amp;quot;;
   numere[1] = &amp;quot;unu&amp;quot;;
   numere[2] = &amp;quot;doi&amp;quot;;
   numere[3] = &amp;quot;trei&amp;quot;;
   numere[4] = &amp;quot;four&amp;quot;;
   numere[5] = &amp;quot;cinci&amp;quot;;
   numere[6] = &amp;quot;sase&amp;quot;;
   numere[7] = &amp;quot;sapte&amp;quot;;
   numere[8] = &amp;quot;opt&amp;quot;;
   numere[9] = &amp;quot;noua&amp;quot;;
   do
   {
      numar_de_control = 0; // resetam numarul de control
      cout &amp;lt;&amp;lt; &amp;quot;Acest program v-a prelula de la utilizator un input,\n&amp;quot;;
      cout &amp;lt;&amp;lt; &amp;quot;precum &amp;#39;7&amp;#39; sau &amp;#39;sapte&amp;#39; si v-a printa pe ecran corespondentul lui.\n&amp;quot;;
      getline(cin,temp); // preluam imput de la utilizator
 
      if(temp.size() == 1) // utilizatorul introduce un singur caracter
      {
         if((int(temp[0]) &amp;gt;= 48 &amp;amp;&amp;amp; int(temp[0] &amp;lt;= 57)) || (temp[0] &amp;gt;= 0 &amp;amp;&amp;amp; temp[0] &amp;lt;= 9)) // check if it&amp;#39;s an number
         {
            for(int i = 0; i &amp;lt; 10; i++) // cautam numarul in vector
            {
               if(atoi(temp.c_str()) == i)
               {
                  cout &amp;lt;&amp;lt; &amp;quot;Ai introdus &amp;quot; &amp;lt;&amp;lt; temp &amp;lt;&amp;lt; &amp;quot; adica &amp;quot; &amp;lt;&amp;lt; numere[i] &amp;lt;&amp;lt; &amp;quot;.&amp;quot; &amp;lt;&amp;lt; endl;
 
               }
 
            }
         }
         else
         {
            cout &amp;lt;&amp;lt; &amp;quot;Nu ai introdus o cifra.\n&amp;quot;;
         }
      }
      if(temp.size() &amp;gt; 1) // utilizatorul introduce mai mult de un caracter
      {
         for(unsigned int i = 0; i &amp;lt; temp.size(); i++) // verificam daca exista caractere scrise cu caps lock
         {
            if(temp[i] &amp;gt;= 65 &amp;amp;&amp;amp; temp[i] &amp;lt;= 90)
            {
               cout &amp;lt;&amp;lt; &amp;quot;Ai introdus caractere cu caps lock, acestea sunt interzise, vrei sa incerci din nou?\n&amp;quot;;
               i = temp.size();
               numar_de_control = 1; // trecem numar_de_control la 1 daca gasim caractere cu caps lock
               din_nou = getch();
               break;
            }
         }
         if(numar_de_control != 0)
         {
            continue; // resetam bucla daca este gasit
         }
         else
         {
            for(int i = 0; i &amp;lt; marime_vector; i++) // cautam cifrele scrise pe litere in interiorul vectorului
            {
               if(temp == numere[i])
               {
                  cout &amp;lt;&amp;lt; &amp;quot;Ai introdus &amp;quot; &amp;lt;&amp;lt; temp &amp;lt;&amp;lt; &amp;quot; adica &amp;quot; &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &amp;quot;.\n&amp;quot;;
                  i = marime_vector;
               }
               else if(i == (marime_vector - 1)) // bucla ajunge la ultimul element si nu a gasit nici un cuvant cunoscut
               {
                  if(temp != numere[marime_vector -1])
                  {
                     cout &amp;lt;&amp;lt; &amp;quot;Cuvantul introdus nu este o cifra scrisa cu litere.\n&amp;quot;;
                  }
               }
 
            }
         }
 
 
      }
 
      cout &amp;lt;&amp;lt; &amp;quot;Vrei sa mai incerci o data ?\n&amp;quot;;
      din_nou = getch();
      system(&amp;quot;CLS&amp;quot;); // e un obicei prost dar pentru utilizatori de windows momentan nu este o problema
   }while(din_nou == &amp;#39;y&amp;#39; || din_nou == &amp;#39;Y&amp;#39;);
 
 
 
   return 0;
}

&lt;/pre&gt;Bun acum sa luam fiecare bucata de cod in parte si sa o analizam.&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;char din_nou = &amp;#39; &amp;#39;;
   const int marime_vector = 10;
   int numar_de_control = 0; //folosit pentru controlul buclelor(loop&amp;#39;s)
   string temp; // stocheaza imput-ul utilizatorului
   vector&amp;lt;string&amp;gt; numere(marime_vector);
   numere[0] = &amp;quot;zero&amp;quot;;
   numere[1] = &amp;quot;unu&amp;quot;;
   numere[2] = &amp;quot;doi&amp;quot;;
   numere[3] = &amp;quot;trei&amp;quot;;
   numere[4] = &amp;quot;four&amp;quot;;
   numere[5] = &amp;quot;cinci&amp;quot;;
   numere[6] = &amp;quot;sase&amp;quot;;
   numere[7] = &amp;quot;sapte&amp;quot;;
   numere[8] = &amp;quot;opt&amp;quot;;
   numere[9] = &amp;quot;noua&amp;quot;;
&lt;/pre&gt;Ce avem de fapt aici? Avem declarate variabilele pe care le vom folosii.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;char din_nou = &#39; &#39;; &lt;/pre&gt;Declaram variabila &quot;din_nou&quot;, de tip char, caruia ii asignam un caracter spatiu, este intotdeauna bine sa initializam variabilele dupa declararea lor pentru a nu avea probleme pe parcursul rularii programului.Aceasta v-a pastra un caracter de control, la sfarsitul programului utilizatorul v-a fi intrebat daca doreste sa incerce din nou, daca v-a apasa &quot;y&quot; sau &quot;Y&quot; atunci programul o va lua de la inceput, daca v-a apasa alta tasta programul se v-a inchide.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;const int marime_vector = 10;&lt;/pre&gt;Aici creem o valoare constanta de tip int, ea nu poate fi modificata pe parcursul rularii programului. Este preferata utilizarea valorilor constante asupra &quot;constantelor magice&quot;. Constantele magice sunt valori atribuite unor variabile , valori care insa nu se vor modifica pe parcursul rularii programului.&lt;br /&gt;
Sa va dau un exemplu:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;vector&amp;lt;string&amp;gt; numere[10]&lt;/pre&gt;Valoarea 10 este o &quot;constanta magica&quot; daca pe parcursul rularii unui program aceasta nu se v-a modifica.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;string temp = &quot; &quot;;&lt;/pre&gt;Aici creem si initializam o variabila de tip string, ce v-a contine ceea ce utilizatorul v-a introduce atunci cand este rugat.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;vector&amp;lt;string&amp;gt; numere(marime_vector);
numere[0] = &amp;quot;zero&amp;quot;;
numere[1] = &amp;quot;unu&amp;quot;;
numere[2] = &amp;quot;doi&amp;quot;;
numere[3] = &amp;quot;trei&amp;quot;;
numere[4] = &amp;quot;four&amp;quot;;
numere[5] = &amp;quot;cinci&amp;quot;;
numere[6] = &amp;quot;sase&amp;quot;;
numere[7] = &amp;quot;sapte&amp;quot;;
numere[8] = &amp;quot;opt&amp;quot;;
numere[9] = &amp;quot;noua&amp;quot;;
&lt;/pre&gt;Aici creem un vector de tip string, cu o marime fixa, aceasta este marime_vector = 10. Aveti un pic mai sus explicatia pentru &quot;marime_vector&quot;. Dupa ce creem vectorul il initializam, adica ii adaugam o valoare initiala.&lt;br /&gt;
&lt;br /&gt;
Pentru a nu fi necesara repornirea programului pentru fiecare incercare o sa folosim o constructie de tipul&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;do
{
   Cod de executat aici
}while(conditii de reexecutare)
&lt;/pre&gt;prin folosirea &quot;do&quot; ne asiguram ca programul este executat cel putin o data.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;while(conditii de executare)
{
 cod de executat
}
&lt;/pre&gt;O constructie de genul &quot;while&quot; v-a verifica intai conditiile si abea apoi v-a rula codul, ceea ce poate duce la neexecutarea codului daca nu sunt indeplinite conditiile nici macar o data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;numar_de_control = 0; 
cout &amp;lt;&amp;lt; &quot;Acest program v-a prelula de la utilizator un input,\n&quot;;
cout &amp;lt;&amp;lt; &quot;precum &#39;7&#39; sau &#39;sapte&#39; si v-a printa pe ecran corespondentul lui\n&quot;;
getline(cin,temp); 
&lt;/pre&gt;Aici avem partea de intampinare si solicitarea primului input al userului. Setam variabila &quot;numar_de_control&quot; la 0 aici deoarece avem nevoie ca de fiecare data cand programul trece prin bucla sa putem controla executia codului cu aceasta variabila, daca nu am avea variabila aici la urmatoarea trecere prin bucla o sa avem eroiri.&lt;br /&gt;
folosim linia urmatoare pentru a prelua absolut tot ceea ce utilizatorul a introdus.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;getline(cin,temp);
&lt;/pre&gt;Folosim &quot;getline&quot; in loc de &quot;cin&quot; deoarece la folosirea &quot;cin&quot; daca utilizatorul va introduce un spatiu in input, in variabila &quot;temp&quot; nu ar ajunge decat ceea ce s-a introdus pana la spatiu.&lt;br /&gt;
&lt;br /&gt;
In continuare intram in partea de control a executiei programului.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;if(temp.size() == 1) // user enters 1 character
{
   if((int(temp[0]) &amp;amp;gt;= 48 &amp;amp;amp;&amp;amp;amp; int(temp[0] &amp;amp;lt;= 57)) || (temp[0] &amp;amp;gt;= 0 &amp;amp;amp;&amp;amp;amp; temp[0] &amp;amp;lt;= 9)) // check if it&amp;#39;s an number
   {
      for(int i = 0; i &amp;amp;lt; 10; i++) // cautam numarul in vector
      {
         if(atoi(temp.c_str()) == i)
         {
            cout &amp;amp;lt;&amp;amp;lt; &amp;quot;Ai introdus &amp;quot; &amp;amp;lt;&amp;amp;lt; temp &amp;amp;lt;&amp;amp;lt; &amp;quot; adica &amp;quot; &amp;amp;lt;&amp;amp;lt; numere[i] &amp;amp;lt;&amp;amp;lt; &amp;quot;.&amp;quot; &amp;amp;lt;&amp;amp;lt; endl;

         }
      }
   }
   else
   {
      cout &amp;amp;lt;&amp;amp;lt; &amp;quot;Nu ai introdus o cifra.\n&amp;quot;;
   }
}
&lt;/pre&gt;Intai verificam daca utilizatorul a introdus un caracter.&lt;br /&gt;
Daca s-a introdus un singur caracter v-om presupune ca utilizatorul a dorit introducerea unei cifre si v-om verifica daca intr-adevar s-a introdus o cifra si nu altceva.&lt;br /&gt;
verificarea marimi sirului de caractere se v-a face prin urmatorul cod&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;if(temp.size() == 1)
&lt;/pre&gt;&quot;size()&quot; este o functie membru a obiectului &quot;string&quot;. Ea ne v-a returna o valoare de tip &quot;int&quot; pe care noi o comparam cu valoarea dorita, in cazul de fata &quot;1&quot;.&lt;br /&gt;
In continuare verificam daca s-a introdus un numar&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;if((int(temp[0]) &amp;gt;= 48 &amp;amp;&amp;amp; int(temp[0] &amp;lt;= 57)) || (temp[0] &amp;gt;= 0 &amp;amp;&amp;amp; temp[0] &amp;lt;= 9))
&lt;/pre&gt;Valorile &quot;48&quot;, &quot;57&quot;,  sunt luate din tabelul &lt;a href=&quot;http://www.asciitable.com/&quot;&gt;ASCI&lt;/a&gt; astfel verificam daca valoarea &quot;int&quot; a variabilei introduse este intre &quot;48 si &quot;57&quot; adica intre 0 si 9, apoi verificam separat si daca ceea ce s-a introdus este de tip &quot;int&quot; si comparam direct cu valorile &quot;0&quot; - &quot;9&quot;. Verificarea se face de 2 ori deoarece este posibil ca utilizatorul sa introduca o litera, asta fiind testat in prima parte a verificari, iar daca utilizatorul introduce o cifra, verificam in a 2-a parte a codului.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;for(int i = 0; i &amp;lt; marime_vector; i++) // cautam numarul in vector
{
   if(atoi(temp.c_str()) == i)
   {
      cout &amp;lt;&amp;lt; &quot;Ai introdus &quot; &amp;lt;&amp;lt; temp &amp;lt;&amp;lt; &quot; adica &quot; &amp;lt;&amp;lt; numere[i] &amp;lt;&amp;lt; &quot;.&quot; &amp;lt;&amp;lt; endl;

    }
}
&lt;/pre&gt;Aici folosim o construcite de tip for.Aceasta preaia un element de control, un contorizator, sub forma unei variabile, pe baza celei variabile se verifica niste conditii, iar daca acele conditii sunt indeplinite se v-a face o actiune(cea dupa i &amp;lt; marime_vector in cazul nostru si anume i++), dupa care se v-a executa codul dintre acolade. Acest tip de constructie este util atunci cand cunoastem numarul de executii necesar, in cazul nostru 10(marime_vector)&lt;br /&gt;
Functia &lt;a href=&quot;http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/&quot;&gt; atoi&lt;/a&gt; preia un &quot;c style string&quot; adica un sir de caractere utilizat in limbajul de programare &quot;C&quot; si mostenit de &quot;C++&quot;, sirul de caractere este tinut intr-un sir(array) de tip char. Functia returneaza o valoare de tip int pe care noi apoi o comparam cu valoarea &quot;i&quot;.Totusi noi nu avem un &quot;c style string&quot; ci un string normal. Aici intervine &lt;a href=&quot;http://www.cplusplus.com/reference/string/string/c_str/&quot;&gt;functia c_str&lt;/a&gt;. Aceasta preaia un string c++ si reda un &quot;c style string&quot;. Mai multe referinte pentru atoi si c_str aveti in linkurile puse pe numele lor. De ce comparam cu &quot;i&quot;? Pai tineti minte vectorul nostru &quot;numere&quot;? Putem afisa oricare din elemente dupa numarul lui, numerotarea incepe de la 0, primul element are 0, al 2-lea are 1, si asa mai departe. In momentul in care cifra introdusa de utilizator este egala cu &quot;i&quot; atunci stim care element din vectorul &quot;numere&quot; sa afisam. &lt;br /&gt;
Dupa ce gasim care este cifra noastra prin&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;if(atoi(temp.c_str()) == i)
&lt;/pre&gt;afisam cifra si corespondentul ei prin&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;cout &amp;lt;&amp;lt; &quot;Ai introdus &quot; &amp;lt;&amp;lt; temp &amp;lt;&amp;lt; &quot; adica &quot; &amp;lt;&amp;lt; numere[i] &amp;lt;&amp;lt; &quot;.&quot; &amp;lt;&amp;lt; endl;
&lt;/pre&gt;Intotdeauna cand folosim &quot;if&quot; este bine sa avem si un &quot;else&quot;, &quot;else&quot; este o masura de siguranta, daca nu sunt indeplinite conditiile de la &quot;if&quot; codul de la &quot;else&quot; v-a fi executat.&lt;br /&gt;
Aici afisam utilizatorului ca nu a introdus o cifra prin:&lt;br /&gt;
&lt;pre class=&quot;brush: cpp&quot;&gt;else
{
   cout &lt;&lt; &quot;Nu ai introdus o cifra.\n&quot;;
}
&lt;/pre&gt;
A doua parte a programului e ceva mai complicata fiind nevoie de mai multe verificari pentru a ne asigura ca totul este in regula.

&lt;pre class=&quot;brush: cpp&quot;&gt;if(temp.size() &amp;gt; 1) // utilizatorul introduce mai mult de un caracter
{
   for(unsigned int i = 0; i &amp;lt; temp.size(); i++) // verificam daca exista caractere scrise cu caps lock
   {
      if(temp[i] &amp;gt;= 65 &amp;amp;&amp;amp; temp[i] &amp;lt;= 90)
      {
         cout &amp;lt;&amp;lt; &quot;Ai introdus caractere cu caps lock, acestea sunt interzise, vrei sa incerci din nou?\n&quot;;
         i = temp.size();
         numar_de_control = 1; // trecem numar_de_control la 1 daca gasim caractere cu caps lock
         din_nou = getch();
         break;
      }
   }
   if(numar_de_control != 0)
   {
      continue; // resetam bucla daca este gasit
   }
   else
   {
      for(int i = 0; i &amp;lt; marime_vector; i++) // cautam cifrele scrise pe litere in interiorul vectorului
      {
         if(temp == numere[i])
         {
            cout &amp;lt;&amp;lt; &quot;Ai introdus &quot; &amp;lt;&amp;lt; temp &amp;lt;&amp;lt; &quot; adica &quot; &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot;.\n&quot;;
            i = marime_vector;
         }
         else if(i == (marime_vector - 1)) // loop reaces last item in vector and the number is not found
         {
            if(temp != numere[marime_vector -1])
            {
               cout &amp;lt;&amp;lt; &quot;Cuvantul introdus nu este o cifra scrisa cu litere.\n&quot;;
            }
         }
      }
   }
}
&lt;/pre&gt;Mai departe.
&lt;pre class=&quot;brush: cpp&quot;&gt;for(unsigned int i = 0; i &lt; temp.size(); i++) // verificam daca exista caractere scrise cu caps lock
{
   if(temp[i] &gt;= 65 &amp;&amp; temp[i] &lt;= 90)
   {
      cout &lt;&lt; &quot;Ai introdus caractere cu caps lock, acestea sunt interzise, vrei sa incerci din nou(y sau Y pentru da, orice alta tasta pentru nu)?\n&quot;;
      i = temp.size();
      numar_de_control = 1; // trecem numar_de_control la 1 daca gasim caractere cu caps lock
      din_nou = getch();
      break;
   }
}
&lt;/pre&gt;
Folosim din nou o constructie &quot;for&quot; pentru a trece prin fiecare caracter din string-ul introdus de catre utilizator de data asta pentru a verifica daca utilizatorul a introdus caractere scrise cu caps lock on. Folosim 65 si 90 deoarece in tabellul &lt;a href=http://www.asciitable.com/&gt;ASCII&lt;/a&gt; 65 este prima litera cu caps lock si anume &quot;A&quot; si 90 este &quot;Z&quot;. Daca este gasit un caracter cu caps lock atunci v-om intreba utilizatorul daca doreste sa incerce din nou, si v-a fi nevoit sa introduca &quot;y&quot; sau &quot;Y&quot; pentru a incerca din nou sau orice alta tasta daca nu mai doreste. Imediat dupa aceasta parte avem : 
&lt;pre class=&quot;brush: cpp&quot;&gt;if(numar_de_control != 0)
{
   continue; // resetam bucla daca este gasit
}
&lt;/pre&gt;Aici intra in joc &quot;numar_de control&quot;. Daca acesta este diferit de &quot;0&quot; bucla o va lua de la capat datorita comenzii &quot;continue&quot;.
Daca nu am gasit nici o majuscula atunci executam a 2-a parte din cod si anume:
&lt;pre class=&quot;brush: cpp&quot;&gt;else
{
   for(int i = 0; i &lt; marime_vector; i++) // cautam cifrele scrise pe litere in interiorul vectorului
   {
      if(temp == numere[i])
      {
         cout &lt;&lt; &quot;Ai introdus &quot; &lt;&lt; temp &lt;&lt; &quot; adica &quot; &lt;&lt; i &lt;&lt; &quot;.\n&quot;;
         i = marime_vector;
      }
      else if(i == (marime_vector - 1)) // loop reaces last item in vector and the number is not found
      {
         if(temp != numere[marime_vector -1])
         {
            cout &lt;&lt; &quot;Cuvantul introdus nu este o cifra scrisa cu litere.\n&quot;;
         }
      }
   }
}
&lt;/pre&gt;
Dupa cum spuneam mai sus ne folosim de &quot;if&quot; si &quot;else&quot;, intai am avut error checking, acum cautam de fapt cifra introdusa pe litere si afisam ceea ce gasim.
Folosim din nou un o bucla &quot;for&quot; pentru a trece prin fiecare element al vectorului &quot;numere&quot; si comparam cu ceea ce a introdus utilizatorul.
&lt;pre class=&quot;brush: cpp&quot;&gt;for(int i = 0; i &lt; marime_vector; i++) // cautam cifrele scrise pe litere in interiorul vectorului
{
   if(temp == numere[i])
   {
      cout &lt;&lt; &quot;Ai introdus &quot; &lt;&lt; temp &lt;&lt; &quot; adica &quot; &lt;&lt; i &lt;&lt; &quot;.\n&quot;;
      i = marime_vector;
   }
   else if(i == (marime_vector - 1)) // loop reaces last item in vector and the number is not found
   {
      if(temp != numere[marime_vector -1])
      {
         cout &lt;&lt; &quot;Cuvantul introdus nu este o cifra scrisa cu litere.\n&quot;;
      }
   }
}
&lt;/pre&gt;
Mai devreme am spus despre &quot;if&quot; si &quot;else&quot; totusi sunt cazuri unde dorim sa verificam mai multe chestii, c++ nu are o constructie speciala pentru asta dar putem combina if si else in felul urmator
&lt;pre class=&quot;brush: cpp&quot;&gt;if(conditie)
{
   cod de executat;
}
else if(conditie)
{
   cod de executat;
}
else if(conditie)
{
   cod de executat;
}
.
.
.
.
else
{
   cod de executat;
}
&lt;/pre&gt;Aici verificam daca prima conditie este indeplinita, daca nu mergem la a 2-a, la a 3-a, daca nu v-a fi indeplinita nici una din conditii atunci se va executa conditia &quot;else&quot;.
In cazul codului nostru totusi avem o mica exceptie, avem &quot;if&quot;, &quot;else if&quot; dar nu mai avem &quot;else&quot;, asta pentru ca in cazul de fata conditia de siguranta este executata in &quot;else if&quot; pentru ca si in cazul conditiei de siguranta trebuie sa verificam niste conditii, si anume daca am ajuns la capatul vectorului &quot;numere&quot;.

Daca utilizatorul nu a introdus un cuvant cunoscut, o cifra scrisa pe litere atunci calculatorul v-a afisa acest lucru prin:
&lt;pre class=&quot;brush: cpp&quot;&gt;if(temp != numere[marime_vector -1])
{
   cout &lt;&lt; &quot;Cuvantul introdus nu este o cifra scrisa cu litere.\n&quot;;
}
&lt;/pre&gt;
In incheiere utilizatorul este intrebat daca doreste sa ruleze programul inca o data prin:
&lt;pre class=&quot;brush: cpp&quot;&gt;cout &lt;&lt; &quot;Vrei sa mai incerci o data ?\n&quot;;
din_nou = getch();
system(&quot;CLS&quot;); // e un obicei prost dar pentru utilizatori de windows momentan nu este o problema
&lt;/pre&gt;
Afisam utilizatorului intrebarea prin &quot;cout&quot; dupa care folosim functia &quot;getch()&quot;. Aceasta functie de fapt preia un caracter introdus care nu este afisat pe ecran si returneaza valoarea int a acesteia, valoarea int este cea din tabelul ASCII. In acest moment aceasta functie este oarecum invechita si este sugerat sa folosititi functia &quot;_getch()&quot; efectul este acelasi pentru abmele, doar ca a 2-a este o varianta mai noua a functiei respective.
Dupa ce utilizatorul da raspunsul facem curat pe ecran folosint functia &quot;system()&quot;, aceasta preia anumiti parametri speciali, cum ar fi &quot;CLS&quot; dar functia aceasta primeste parametri in functie de sistemul de operare, spre exemplu pe un sistem linux, codul &quot;system(&quot;CLS&quot;); v-a da o eroare. Cateva referinte despre &quot;system()&quot; aveti &lt;a href=http://www.cplusplus.com/reference/clibrary/cstdlib/system/&gt;aici&lt;/a&gt;

Dupa ce am facut si curat pe ecran verificam ceea ce a introdus utilizatorul cand a fost intrebat daca doreste sa mai ruleze programul inca o data prin:
&lt;pre class=&quot;brush: cpp&quot;&gt;}while(din_nou == &#39;y&#39; || din_nou == &#39;Y&#39;);
&lt;/pre&gt;dupa care avem comanda de terminare cu succes si anume &quot;return 0;&quot;   Si cu asta am terminat acest program. Daca aveti intrebari postatile la comentarii si va voi raspunde cat de repede pot.</content><link rel='replies' type='application/atom+xml' href='http://florinrada.blogspot.com/feeds/7499221709348198467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://florinrada.blogspot.com/2010/09/cconversie-numere-scrise-in-cifre-arabe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/7499221709348198467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7735655402128608226/posts/default/7499221709348198467'/><link rel='alternate' type='text/html' href='http://florinrada.blogspot.com/2010/09/cconversie-numere-scrise-in-cifre-arabe.html' title='[C++]Conversie numere scrise in cifre arabe si viceversa'/><author><name>florin.rada</name><uri>http://www.blogger.com/profile/07336044099523183162</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>