C Windows programiranje - pomoć

poruka: 9
|
čitano: 5.049
|
moderatori: XXX-Man, vincimus
1
+/- sve poruke
ravni prikaz
starije poruke gore
16 godina
neaktivan
offline
C Windows programiranje - pomoć

Dosad sam ucio programirati samo u C/C++. Vise-manje sam ucia neke elementarne algoritme, rekurzije, strukture i takve stvari. No vec odavno zelim krenit na Windows programiranje. Tako sam nabavia knjigu "C Windows programiranje" od Tihomira Tucakovica, a zasad mi se cini kao najbolje rjesenje za moje potrebe. Iako je sve detaljno objasnjeno i dostupno u obliku koda nakon svake lekcije, neke stvari me jos muce i nerazumljive su mi. Cak bi reka da su mi previse nerazumljive, jer toliko je toga novoga i razlikuje se od klasicnog programiranja na koje sam navika. Pa ako neko ima volje da mi odgovori na moja pitanja, ili barem na neka koja zna, bia bi zahvalan. Krenut cu redom nekakvim, i gdje bude potrebno potkrijepit screenshotom.

 

1) Pojavljivanje Command Prompta

Ako kompajlan kod stvoren u editoru kao source file, kad god pokrenem program, prati ga command prompt u pozadini. Ako pak stvorim projekt, i odaberem Windows Application, ovaj problem se nece dogodit.

U cemu je razlika, i zasto moram stvarat projekt da bi izbjega pojavljivanje cmd-a? (Zasad se ne obazirem na to, i pisem svaki program kao zaseban source code, bez ikakvih dodatnih fileova)

 

2) Mađarska notacija

Kaze da ime varijabli pocinje malim slovom ili slovima koja oznacavaju kojeg je tipa podatka varijabla. (n - short integer, s - string, h - handle itd.) Ali negdje mi je to skroz nerazumljivo, pokazat cu kasnije u kojem dijelu.

Zanima me je li nuzno ispred imena svake varijable stavljati ova mala slova?

 

3) LRESULT CALLBACK, WINAPI itd. (pretpostavljan da ce ih bit jos..)

Sto tocno znace ove sintakse. Zanima me jesu to nekakvi predodređeni tipovi podataka ili slicno?

 

4) RAZLIKA IZMEĐU HINSTANCE I HWND

Ja to tumacim da je HINSTANCE rukovatelj mojim cijelim programom, a HWND svakog nekog manjeg dijela programa. Ali to mi je jos mutno, pa ako moze netko razradit malo?

 

5) WNDCLASSEX i CreateWindowEx


typedef struct _WNDCLASSEXA {
   UINT cbSize;
   UINT style;
   WNDPROC lpfnWndProc;
   int cbClsExtra;
   int cbWndExtra;
   HINSTANCE hInstance;
   HICON hIcon;
   HCURSOR hCursor;
   HBRUSH hbrBackground;
   LPCSTR lpszMenuName;
   LPCSTR lpszClassName;
   HICON hIconSm;
} WNDCLASSEXA,*LPWNDCLASSEXA,*PWNDCLASSEXA;

 

WINUSERAPI HWND WINAPI CreateWindowExA(

DWORD,

LPCSTR,LPCSTR,

DWORD,

int,int,

int,int,

HWND,

HMENU,

HINSTANCE,

LPVOID

);

 

U WNDCLASSEX me muce nazivi varijabli npr. lpfnWndProc(gdje bi po mađ. notaciji lpfn trebao biti prefiks, al sta on oznacuje?, ista stvar za cbSize, lpszMenuName itd.)

Jos me zanima ima li ikakve veze ova funkcija CreateWindowEx sa WNDCLASSEX. Jesu li povezane ikako?

 

7) PETLJA PORUKE

Ovde su glavne ove dvije funkcije TranslateMessage i DispatchMessage. Ako moze ko malo prosirit njihovu ulogu kao i ulogu same petlje.

 

8) WINDOW PROCEDURA - LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

Ovo se u knjizi spominje kao mozak programa, sto je meni doslo kao sok jer sam zamislja da ce vecina koda biti u WinMain-u. Kako napredujem dalje, skuzia san da se ugl ovaj dio najvise mijenja, tj. nadograđuje.

Isto ako netko moze malo prosirit rad ove funkcije. Ova zadnja 2 parametra me malo zbunjuju takodjer.

 

Za kraj, sam autor je napisao da sve ovo sta ja ovde pitam je zapravo nebitno i da se to zaboravi. Ali ako se vec ovaj kod ispod smatra temeljom windows aplikacije, onda bi ga ja volia temeljno i razumit. Ne volin bas radit nesto sablonski, ako vec moran onda volim znati sta radim u detalj. Sve je ovo meni jos dosta konfuzno s obzirom da se tek 3 dana bavim s ovim, ali ako ocu krenit dalje smatram da bi ovo trialo prozvakat. Trenutno sam dogura do izrade kontrole (Gumbovi, klizne trake, editiranje teksta itd.). Jos jedno pitanje za kraj, jeli mi nuzno poznavanje klasa, bas pravim C++ klasa za rad s Windows programima. Zasad nisam naisao na neku vecu prepreku s njima.

Spirit...
Moj PC  
1 0 hvala 0
16 godina
neaktivan
offline
C Windows programiranje - pomoć

Cijeli kod:

/*
PROTOTIP PROZORA - program koji kreira jednostavan prozor
*/

#include <windows.h>

// Prototip funkcije s windows procedurama

LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);

// Ime klase prozora

static char gszClassName[] = "MojaKlasaProzora";

// Funkcija WinMain

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
   
    WNDCLASSEX WndClass;
    HWND hwnd;
    MSG Msg;
   
    // Registriranje klase prozora
   
    WndClass.cbSize        = sizeof(WNDCLASSEX);
    WndClass.style         = NULL;
    WndClass.lpfnWndProc   = WindowProcedure;
    WndClass.cbClsExtra    = 0;
    WndClass.cbWndExtra    = 0;
    WndClass.hInstance     = hInstance;
    WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
    WndClass.lpszMenuName  = NULL;
    WndClass.lpszClassName = gszClassName;
    WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
   
    // Provjera je li klasa prozora registrirana
   
    if(!RegisterClassEx(&WndClass)){
          MessageBox(0, "Registriranje prozora nije uspjelo!", "Greska!", MB_ICONSTOP | MB_OK);
          return 0;
    }
   
    // Kreiranje prozora
   
    hwnd = CreateWindowEx(
                 WS_EX_STATICEDGE,
                 gszClassName,
                 "Naslov",
                 WS_OVERLAPPEDWINDOW,
                 CW_USEDEFAULT, CW_USEDEFAULT,
                 500, 400,
                 NULL, NULL,
                 hInstance,
                 NULL);
   
    // Provjera je li prozor uspjesno kreiran
   
    if(hwnd == NULL){
            MessageBox(0, "Kreiranje prozora nije uspjelo!", "Greska!", MB_ICONSTOP | MB_OK);
            return 0;
    }
   
    // Prikazivanje prozora na ekranu
   
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
   
    // Petlja koja obradjuje poruke
   
    while(GetMessage(&Msg, NULL, 0, 0)){
                           TranslateMessage(&Msg);
                           DispatchMessage(&Msg);
    }
   
    // Odjava klase prozora
   
    UnregisterClass("MojaKlasaProzora", hInstance);
   
    return Msg.wParam;
   
}

    // Funkcija s Windows procedurama

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
        switch(Message){
                        case WM_CLOSE:
                             DestroyWindow(hwnd);
                             break;
                        case WM_DESTROY:
                             PostQuitMessage(0);
                             break;
                        default:
                             return DefWindowProc(hwnd, Message, wParam, lParam);
     }
      
      
     return 0;
       
}                          
 

Spirit...
Moj PC  
0 0 hvala 0
14 godina
neaktivan
offline
C Windows programiranje - pomoć

Ako već želiš raditi windows aplikacije u C++u probaj C++ Builder. Puno jednostavnije i bolje od ovoga.

Kada lajavci laju onda završe ovako: http://i471.photobucket.com/albums/rr77/toropreto/2012-07-0813_30_07.gif
Moj PC  
2 3 hvala 0
14 godina
neaktivan
offline
Re: C Windows programiranje - pomoć
Neutral kaže...

 

4) RAZLIKA IZMEĐU HINSTANCE I HWND

Blizu si, HWND - handle window, a HINSTANCE - handle instance, znači HWND upravlja prozorom, a HINSTANCE instancom aplikacije.

 

Nažalost ti ne mogu mnogo pomoći oko WinAPI-a, radio sam ga malo, ali nisam baš kompetentan da pričam o njemu. Najpoznatija knjiga o programiranju u WinAPI-u je Programming Windows 5th edition od Charlesa Petzolda.

Poruka je uređivana zadnji put pet 5.7.2013 11:44 (royalhero).
15 godina
neaktivan
offline
Re: C Windows programiranje - pomoć
Neutral kaže...
1) Pojavljivanje Command Prompta

 

Ako kompajlan kod stvoren u editoru kao source file, kad god pokrenem program, prati ga command prompt u pozadini. Ako pak stvorim projekt, i odaberem Windows Application, ovaj problem se nece dogodit.

U cemu je razlika, i zasto moram stvarat projekt da bi izbjega pojavljivanje cmd-a? (Zasad se ne obazirem na to, i pisem svaki program kao zaseban source code, bez ikakvih dodatnih fileova)

 

Riječ je o linkeru. Postoji nekoliko različitih tipova izvršnih datoteka koje linker može kreirati. Postoji jedno polje unutar headera izvršne datoteke koje govori operacijskom sustavu treba li za izvršavanje tog programa otvoriti konzolu, gdje ga u memoriju treba strpati i slično...

 

http://msdn.microsoft.com/en-us/library/fcc1zstk%28v=vs.71%29.aspx

 

Kada kao vrstu projekta odabereš Windows Application ne dogodi se nikakva magija, samo se odabere jedan preset switcheva za kompajler i linker koji rezultira izvršnom datotekom koja ne otvara konzolu.

 

Neutral kaže...
2) Mađarska notacija

Kaze da ime varijabli pocinje malim slovom ili slovima koja oznacavaju kojeg je tipa podatka varijabla. (n - short integer, s - string, h - handle itd.) Ali negdje mi je to skroz nerazumljivo, pokazat cu kasnije u kojem dijelu.

Zanima me je li nuzno ispred imena svake varijable stavljati ova mala slova?

Ne nije nužno, ali je winAPI kod sav pisan sa sistemskom mađarskom notacijom. Naviknut ćeš se. Za svoje vlastite varijable i tipove podataka možeš koristiti kakva god želiš imena. Štoviše sistemska mađarska notacija ima i dosta kritičara čije je stajalište da je suvišna i kontraproduktivna.

 

http://en.wikipedia.org/wiki/Hungarian_notation#Systems_vs._Apps_Hungarian

 

Neutral kaže...
3) LRESULT CALLBACK, WINAPI itd. (pretpostavljan da ce ih bit jos..)

Sto tocno znace ove sintakse. Zanima me jesu to nekakvi predodređeni tipovi podataka ili slicno?

Da, tipovi podataka (osnovni tipovi tipa int, void, long...) u različitim kombinacijama. Npr. UINT je unsigned int. Mogao si otkriti što se iza kojeg tipa točno krije da si malo kopao po sistemskim headerima, ali evo:

http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx

 

Neutral kaže...
4) RAZLIKA IZMEĐU HINSTANCE I HWND

Ja to tumacim da je HINSTANCE rukovatelj mojim cijelim programom, a HWND svakog nekog manjeg dijela programa. Ali to mi je jos mutno, pa ako moze netko razradit malo?

HINSTANCE = handle of instance, odnosno handle od tvoje aplikacije u memoriji

HWND = handle of window, tj. handle od nekog prozora. Ovdje je bitno napomenuti da su i kontrole (button, checkbox, scrollbar) zapravo "prozori" (bude ti bilo jasnije kada jednom budeš išao izrađivati vlastitu kontrolu)

 

Što je handle (hrv. ručica)? To nije ništa drugo nego pokazivač na neku strukturu u memoriji. Npr. kada otvoriš novi prozor dobiješ handle od tog prozora, i on se odnosi baš na taj prozor i nijedan drugi. To je kao njegov otisak prsta, kako bi sistem mogao razlikovati taj prozor od drugog prozora. Koristiš ga kako bi vršio operacije na tom prozoru. Postoje handlei za sve i svašta, npr vjerojatno si već radio sa FILE handleom kada si radio sa datotekama u C-u.

 

Ono što je svim handleima zajedničko jest da svi služe kako bi identificirali neki svoj objekt (datoteku, prozor, thread, ikonu...), i da za njihovo korištenje ne moraš znati što se krije na memorijskoj adresi na koju pokazuju (štoviše, uopće ne bi trebao ni pokušavati petljati po njihovoj memoriji), te konačno da ih moraš samo znati upiknuti u funkcije koje ih koriste i to je to.

 

Neutral kaže...
5) WNDCLASSEX i CreateWindowEx


typedef struct _WNDCLASSEXA {
   UINT cbSize;
   UINT style;
   WNDPROC lpfnWndProc;
   int cbClsExtra;
   int cbWndExtra;
   HINSTANCE hInstance;
   HICON hIcon;
   HCURSOR hCursor;
   HBRUSH hbrBackground;
   LPCSTR lpszMenuName;
   LPCSTR lpszClassName;
   HICON hIconSm;
} WNDCLASSEXA,*LPWNDCLASSEXA,*PWNDCLASSEXA;

 

WINUSERAPI HWND WINAPI CreateWindowExA(

DWORD,

LPCSTR,LPCSTR,

DWORD,

int,int,

int,int,

HWND,

HMENU,

HINSTANCE,

LPVOID

);

 

U WNDCLASSEX me muce nazivi varijabli npr. lpfnWndProc(gdje bi po mađ. notaciji lpfn trebao biti prefiks, al sta on oznacuje?, ista stvar za cbSize, lpszMenuName itd.)

Jos me zanima ima li ikakve veze ova funkcija CreateWindowEx sa WNDCLASSEX. Jesu li povezane ikako?

lpfn = long pointer function. Malo nakaradno napisano ali ukratko kaže da je to pokazivač na funkciju i da je veličine "long int".

cb = count bytes. Odnosno količina bajtova, iliti veličina nečega izražena u bajtovima.

 

http://en.wikipedia.org/wiki/Hungarian_notation

http://msdn.microsoft.com/en-us/library/aa260976%28v=vs.60%29.aspx

 

Što se ovog drugog tiče, ovako stvari stoje. Da bi kreirao prozor prvo moraš imati registriranu njegovu klasu u memoriji.

 

Dakle imaš WNDCLASS i WNDCLASSEX strukture koje popuniš odgovarajućim podatcima.

Zatim pozoveš RegisterClass ili RegisterClassEx kako bi sistemu predao nacrt svoje window klase.

Te konačno pozoveš CreateWindow ili CreateWindowEx funkciju sa imenom klase prozora koji želiš stvoriti.

 

Primijetio si vjerojatno da postoje ove "EX" varijante funkcija i struktura. Riječ je o praktički istoj stvari samo što "EX" varijante (EX dolazi od "extended"), imaju dodatne članove/argumente (za detalje pogledati na msdn)

 

Neutral kaže...
7) PETLJA PORUKE

Ovde su glavne ove dvije funkcije TranslateMessage i DispatchMessage. Ako moze ko malo prosirit njihovu ulogu kao i ulogu same petlje.

Većina programa ima svoju glavnu petlju. To je petlja koja se ponavlja tako dugo dok se program izvršava, kada petlja završi obično je i kraj programa. Tako i svaka windows aplikacija ima svoju petlju.

 

Prozori komuniciraju sa sistemom preko poruka (možeš ih smatrati i signalima ako ti je tako lakše). Npr kada klikneš na neki prozor, sistem pošalje tom prozoru WM_LBUTTONDOWN poruku sa koordinatama na kojima se dogodio lijevi klik mišem. Na aplikaciji je tada da vidi što će sa tom porukom (reagirati nekako na nju ili će ju jednostavno ignorirati), postoji cijela hrpetina različitih poruka za različite stvari.

 

Tu ti uskače tzv. message loop (petlja poruke). Cijela svrha te petlje je da se ponavlja u beskonačnost i preuzima od sistema poruke namijenjene prozoru aplikacije sve dok korisnik ne zatvori program. Bez te petlje program bi se odmah završio jer ne bi stalno ispitivao sustav postoji li nekakva poruka za njega.

 

Tri se funkcije uglavnom koriste u petlji poruke, to su:

GetMessage čiju je svrhu lako skužiti iz samog imena funkcije. Ta funkcija čini dvije bitne stvari:

  1. preuzima poruke od sistema
  2. vraća vrijednost TRUE tako dugo dok ne primi WM_QUIT poruku što omogućava lagan izlazak iz petlje kada za to dođe trenutak (kraj izvršavanja programa).

TranslateMessage koja pretvara virtual key poruke u znakovne poruke (dakle ima veze samo sa pritiscima tipki na tipkovnici)

DispatchMessage funkcija šalje poruke glavnoj funkciji nekog prozora (window procedure).

 

Dakle petlja se vrti u tri koraka:

  1. Uzmi poruku od sustava
  2. Prevedi poruku
  3. Proslijedi prevedenu poruku prozoru kojemu je namijenjena (odnosno njegovoj callback funkciji).

 

Neutral kaže...
8) WINDOW PROCEDURA - LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)

Ovo se u knjizi spominje kao mozak programa, sto je meni doslo kao sok jer sam zamislja da ce vecina koda biti u WinMain-u. Kako napredujem dalje, skuzia san da se ugl ovaj dio najvise mijenja, tj. nadograđuje.

Isto ako netko moze malo prosirit rad ove funkcije. Ova zadnja 2 parametra me malo zbunjuju takodjer.

To i jest mozak windows programa.

 

Pomislio si da bi to trebao biti WinMain ali nije. Naime WinMain je samo takozvani entry point (odnosno točka od koje program počinje sa izvršavanjem). Vjerojatno ti ta asocijacija dolazi iz C-a gdje se uglavnom glavnina manjih programa strpa u main funkciju, ali imaj na umu da ni u C-u main funkcija ne mora biti glavna. Ona je također tamo samo entry point a ti imaš potpunu slobodu odlučiti želiš li obaviti većinu posla u toj funkciji ili ne. Kod windows programa baš i nemaš potpunu slobodu odrediti gdje ćeš što raditi pa se moraš držati onoga što su programeri iz microsofta zamislili.

 

Posao koji WinMain funkcija obavlja je da postavi i registrira klasu prozora, kreira prozor, i da onda počne izvršavati petlju poruke. Petlja poruke za svaku primljenu poruku pozove WindowProcedure tvojeg prozora (točnije taj dio pozivanja obavlja funkcija DispatchMessage).

 

Tu se vraćamo na WNDCLASS strukturu. Jedan od članova te strukture je i lpfnWndProc, što je u biti pokazivač na tvoju WindowProcedure funkciju (ako se do sada nisi susreo sa pokazivačima na funkcije ovo bi te moglo malo zbuniti). Kada si registrirao tu klasu sistem je zabilježio da se za tu klasu prozora treba pozivati funkcija koju si postavio u lpfnWndProc. Kada petlja poruke primi poruku ona ju šalje upravo toj funkciji koju si stavio u lpfnWndProc.

 

Tu sada dolazimo do parametara WindowProcedure funkcije:

 

  1. Prvi parametar je HWND tipa i on predstavlja handle od tvog prozora.
  2. Drugi parametar je UINT tipa i on ti govori koju si poruku primio (UINT je unsigned int, svaka vrsta poruke ima svoj jedinstveni broj).
  3. Posljednja dva parametra funcije predstavljaju parametre same poruke. Recimo ako je poruka WM_LBUTTONDOWN (lijevi klik miša), wParam će sadržavati vrijednosti koje ti govore je li pritisnuta i neka funkcijska tipka na tipkovnici u vrijeme klika mišem, dok će lParam sadržavati koordinate na kojima se klik dogodio (dvije 16 bitne vrijednosti spojene u jedan 32 bitni long int, potrebno je razumjeti bitovne operacije kako bi ovo razumio), da bi dobio vrijednosti koristiš GET_X_LPARAM i GET_Y_LPARAM makroe (ili HIWORD i LOWORD makroe)

 

Neutral kaže...
Za kraj, sam autor je napisao da sve ovo sta ja ovde pitam je zapravo nebitno i da se to zaboravi. Ali ako se vec ovaj kod ispod smatra temeljom windows aplikacije, onda bi ga ja volia temeljno i razumit. Ne volin bas radit nesto sablonski, ako vec moran onda volim znati sta radim u detalj. Sve je ovo meni jos dosta konfuzno s obzirom da se tek 3 dana bavim s ovim, ali ako ocu krenit dalje smatram da bi ovo trialo prozvakat. Trenutno sam dogura do izrade kontrole (Gumbovi, klizne trake, editiranje teksta itd.). Jos jedno pitanje za kraj, jeli mi nuzno poznavanje klasa, bas pravim C++ klasa za rad s Windows programima. Zasad nisam naisao na neku vecu prepreku s njima.

Autor je u biti u pravu, ne moraš znati detalje oko mnogih stvari kako bi ih mogao koristiti. Ali te razumijem. I ja sam poput tebe, ne volim apstraktne koncepte i stvari mi sjednu u glavu tek kada ja to sve pošteno raskopam i shvatim što u biti nešto zapravo jest.

 

Windows API je jedna malo poveća tema ali kada malo zaviriš ispod površine brzo ćeš skužiti kako zapravo tu nema ništa komplicirano (primjer sa tipovima podataka koje sam ti linkao) i brzo ti razne radnje postanu sasvim logične.

 

Kada smo kod klasa nemoj miješati ove windows klase (WNDCLASS i WNDCLASSEX tipa) sa C++ klasama (iako su windows klase nastale po uzoru na C++ klase). Ne, za rad sa Windows API-jem i pisanje takvih programa ti uopće nije potrebno znanje C++-a i OOP-a. Ali za rad sa frameworkovima kao što su MFC, COM pa na kraju krajeva i C++ builder kojeg tracer zagovara, apsolutno moraš koristiti C++ jer se radi o C++ zasnovanim frameworkovima.

 

Za bolje razumijevanje tematike preporučam knjigu Programming Windows (peto izdanje) (bitno je da je peto, a ne šesto, jer se šesto bavi puno novijim pristupom pisanja GUI aplikacija) kao i čitanje dokumentacije na MSDN-u.

 

Kao i sljedeće linkove:

http://www.winprog.org/tutorial/

http://www.zetcode.com/gui/winapi/

http://www.functionx.com/win32/

 

DISCLAIMER:

Napisao sam svašta a ovih dana sna gotovo da i nisam vidio. Ako netko primijeti pogreške neka me obavijesti.

What Andy giveth, Bill taketh away.
Poruka je uređivana zadnji put sub 6.7.2013 1:21 (rustweaver).
16 godina
offline
Re: C Windows programiranje - pomoć
Neutral kaže...

..

2) Mađarska notacija

Kaze da ime varijabli pocinje malim slovom ili slovima koja oznacavaju kojeg je tipa podatka varijabla. (n - short integer, s - string, h - handle itd.) Ali negdje mi je to skroz nerazumljivo, pokazat cu kasnije u kojem dijelu.

Zanima me je li nuzno ispred imena svake varijable stavljati ova mala slova?

..

 -notacija je samo dogovor, 'nepisana pravila' koja služe boljem razumijevanju ''programerskog jezika''. Jednako kao što u rečenicama postoje mala-velika slova, odlomci.. preglednost, cjelina, razumljivost. Funkcionalno je svejdno koji naziv varijable odabereš (kompiler ju ionako prevodi u svoju internu). Varijabla Ime, IME, I, name, NAME, Name... je na kraju samo varijabla, ali ako u kontekstu programa nazoveš varijablu npr Ime i dodjeliš joj vrijednost npr Pero, tad je to logičniji naziv nego neki drugi naziv, npr varijabla1 koji nam nebi ništa govorio o sadržaju. To je ako govorimo o izboru naziva.

Mađarska notacija je inače (naj)prihvaćeniji oblik označivanja varijabli. Tad mala-VELIKA slova postanu bitna zbog ČITLJIVOSTI-preglednosti. .. vidi u postu gdje postavljaš pitanja npr CreateWindowEx je čitljivije nego da su sva slova jednake veličine (mala ili velika), odnosno izbjedli smo razmake ili neke druge znakove tj uštedjeli smo nešto mjesta za pisanje, na zauzimanje imena varijable itd. Sama varijabla bi se mogla nazvati npr cwe ili CreWindEX.. ili bilo kako, ali kraćenjem gubiš dio ''samoopisivosti'' tj razumijevanje koda ovisi o REMovima (dokumentaciji) dok je ovako lakše praćenje.

To sve su samo norme kako bi se programeri međusobno bolje razumijeli, tj da bi programer A, mogao raditi u timu s programerom B, C ...

prefix-sufix-samo ime.. to su sve samo ''nepisana pravila'', koja ne moraš poštivati odnosno to ovisi o tipu posla, timu...

prefix ''n'' je uobičajn za brojače, dok se kombinacijom malih i velikih slova samo štadi mjesto dok se zadržava preglednost-čitljivost.  pa nName unutar gornjeg primjera s variablom Name, možemo lako prepoznati kao vrijednost koja će vjerojatno držati informaciju koliko imamo takvih imena ili nešto u tom kontekstu. npr Name=Pero nName=2 bi moglo značiti da u bazi imamo dvojicu Pere.., za zečeve bi moglo biti koliko komada itd.

 

Notacija je zapravo samo lijepo formatiran naziv-riječ (i čitav blok, rutina, aplikacija) koja se unutar branše koristi. Notaciju se ne uči na način 'štrebanje'.. ona ti sama dođe kao posljedica, tj poželjno ju je što prije prihvatiti... (ako ćeš ikad raditi u timovima ili na tuđem kodu).

C64/TurboModul-OpenSourceProject.org.cn.部分作品为网上收集整理,供开源爱好者学习使用
16 godina
neaktivan
offline
C Windows programiranje - pomoć

Hvala svima na odgovorima i preporukama, posebice rustweaveru :)

Vratit cu se ovde opet s pitanjima kako buden napredovao kroz knjigu.

Spirit...
Moj PC  
0 0 hvala 0
16 godina
neaktivan
offline
C Windows programiranje - pomoć

Pozdrav ljudi, evo svracam opet.

Dosa sam do 6. poglavlja knjige, zove se sat. Uglavnom to je nebitno, bitno je da imam problema sa kompajliranjem samog koda. Javlja mi gresku tipa [Linker error].

Tocnije,  [Linker error] undefined reference to `GetStockObject@4'

 

Malo sam googla, i pronasao par rjesenja. Koliko sam svatia, problem je u tome sto sam pisao source code, umisto da san napravia C Project. Kad napravim project, i u main.c kopiran kod, on zaista radi.

Evo link di sam pronasa to rjesenje: Link

Ako moze ko malo objasnit sto je covjek htio reci :)

 

Dakle uspio sam kompajlirat kod, ali kad kliknem ukljuci brojac, program mi se odmah ugasi. Nije da crasha ili nesto, sam se ugasi. Sad cu opet proci kroz kod i probat nac gresku.

EDIT: Zaboravia jedan break, sve super sad! Ali svejedno, ako mi ko moze objasnit sto je tocno ovaj Linker error. Nije mi se nikad prije dogodia :S

 


Kod:

#include <windows.h>
#include <winbase.h>

#define IDT_SAT             1
#define IDT_SAT1            2
#define IDC_BROJAC          101
#define IDC_TOCNOVRIJEME    102
#define IDC_GUMBBROJAC      501

int i = 0, iBroj = 1;
char szLokalnoVrijeme[100];

// Deklarirane strukture tipa SYSTEMTIME u koju se pohranjuju datum i tocno vrijeme
SYSTEMTIME lpVrijeme;

LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);

static char gszClassName[] = "MojaKlasaProzora";
static char szImePrograma[] = "Sat";
HINSTANCE hInst = NULL;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
   
    WNDCLASSEX WndClass;
    HWND hwnd;
    MSG Msg;
   
    hInst = hInstance;
   
    WndClass.cbSize        = sizeof(WNDCLASSEX);
    WndClass.style         = NULL;
    WndClass.lpfnWndProc   = WindowProcedure;
    WndClass.cbClsExtra    = 0;
    WndClass.cbWndExtra    = 0;
    WndClass.hInstance     = hInstance;
    WndClass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
    WndClass.lpszMenuName  = NULL;
    WndClass.lpszClassName = gszClassName;
    WndClass.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
   
    if(!RegisterClassEx(&WndClass)){
          MessageBox(0, "Registriranje prozora nije uspjelo!", "Greska!", MB_ICONSTOP | MB_OK);
          return 0;
    }
   
    hwnd = CreateWindowEx(
                 WS_EX_STATICEDGE,
                 gszClassName,
                 szImePrograma,
                 WS_OVERLAPPEDWINDOW,
                 CW_USEDEFAULT, CW_USEDEFAULT,
                 195, 135,
                 NULL, NULL,
                 hInstance,
                 NULL);
   
    if(hwnd == NULL){
            MessageBox(0, "Kreiranje prozora nije uspjelo!", "Greska!", MB_ICONSTOP | MB_OK);
            return 0;
    }
   
    // Ukljucivanje i provjera sata
   
    if(!SetTimer(hwnd, IDT_SAT1, 1000, NULL)){
            MessageBox(0, "Nema slobodnih satova!", szImePrograma, MB_ICONSTOP | MB_OK);
            return FALSE;
    }
   
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
   
    while(GetMessage(&Msg, NULL, 0, 0)){
                           TranslateMessage(&Msg);
                           DispatchMessage(&Msg);
    }
   
    UnregisterClass("MojaKlasaProzora", hInstance);
   
    return Msg.wParam;
   
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam){
       
        static HWND hBrojac, hGumbBrojac, hTocnoVrijeme;
        char szTekst[30], szTocnoVrijeme[40];
        int iLenght, iDate, iTime;
       
        switch(Message){
                        case WM_CREATE:
                            
                             hBrojac = CreateWindowEx(
                                                       0,
                                                       "Static",
                                                       NULL,
                                                       WS_CHILD | WS_VISIBLE | WS_BORDER | SS_RIGHT,
                                                       5, 75,
                                                       50, 20,
                                                       hwnd, (HMENU) IDC_BROJAC,
                                                       hInst,
                                                       NULL);
   
                             if(!hBrojac){
                                              MessageBox(0, "Kreiranje staticke kontrole nije uspjelo!", "Greska!", MB_ICONSTOP | MB_OK);
                                              return 0;
                             }
                            
                             hTocnoVrijeme = CreateWindowEx(
                                                       0,
                                                       "Static",
                                                       NULL,
                                                       WS_CHILD | WS_VISIBLE | SS_RIGHT,
                                                       55, 5,
                                                       130, 37,
                                                       hwnd, (HMENU) IDC_TOCNOVRIJEME,
                                                       hInst,
                                                       NULL);
   
                             if(!hTocnoVrijeme){
                                              MessageBox(0, "Kreiranje staticke kontrole nije uspjelo!", "Greska!", MB_ICONSTOP | MB_OK);
                                              return 0;
                             }
                            
                             hGumbBrojac = CreateWindowEx(
                                                       0,
                                                       "Button",
                                                       "Ukljuci brojac",
                                                       WS_CHILD | WS_VISIBLE,
                                                       65, 65,
                                                       120, 40,
                                                       hwnd, (HMENU) IDC_GUMBBROJAC,
                                                       hInst,
                                                       NULL);
   
                             if(!hGumbBrojac){
                                              MessageBox(0, "Kreiranje gumba nije uspjelo!", "Greska!", MB_ICONSTOP | MB_OK);
                                              return 0;
                             }
                            
                             SetFocus(hGumbBrojac);
                            
                             SetDlgItemInt(hwnd, IDC_BROJAC, i, 0);
                             SendMessage(hTocnoVrijeme, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), 0);
                            
                             break;
                       
                        case WM_TIMER:                  // Poruke tipa WM_TIMER koje salju satovi
                             switch(LOWORD(wParam)){
                                                    case IDT_SAT:      // Identifikator sata
                                                         {
                                                                       MessageBeep(0);
                                                                      
                                                                       // Povecanje vrijednosti u statickoj kontroli
                                                                       i++;
                                                                       SetDlgItemInt(hwnd, IDC_BROJAC, i, 0);
                                                         }
                                                         break;
                                                   
                                                    case IDT_SAT1:     // identifikator sata
                                                         // Dobivanje datuma i tocnog vremena i pohranjivanje u strukturu lpVrijeme
                                                        
                                                         GetLocalTime(&lpVrijeme);
                                                        
                                                         // Pohranjivanje datuma i tocnog vremena u string
                                                        
                                                         wsprintf(szLokalnoVrijeme, "%02d.%02d.%d."
                                                                  " godine\r\n%02d:%02d:%02d", lpVrijeme.wDay, lpVrijeme.wMonth,
                                                                  lpVrijeme.wYear, lpVrijeme.wHour, lpVrijeme.wMinute, lpVrijeme.wSecond);
                                                        
                                                         // Ispisivanje datuma i tocnog vremena u staticnoj kontroli
                                                        
                                                         SetWindowText(hTocnoVrijeme, szLokalnoVrijeme);
                                                        
                                                         break;
                             }
                             break;
                       
                        case WM_COMMAND:
                             switch(wParam){
                                            case IDC_GUMBBROJAC:
                                                 {
                                                                if(!SetTimer (hwnd, IDT_SAT, 500, NULL)){
                                                                             MessageBox(hwnd, "Nema slobodnih satova!",
                                                                             szImePrograma, MB_ICONEXCLAMATION | MB_OK);
                                                                             return FALSE;
                                                                }
                                                               
                                                                if(iBroj == 1){
                                                                               SetWindowText(hGumbBrojac, (LPCTSTR)"Iskljuci brojac");
                                                                               SetTimer(hwnd, IDT_SAT, 500, NULL);
                                                                               iBroj = 0;
                                                                }
                                                                else{
                                                                     KillTimer(hwnd, IDT_SAT);
                                                                     SetWindowText(hGumbBrojac, (LPCTSTR)"Ukljuci brojac");
                                                                     iBroj = 1;
                                                                     i = 0;
                                                                     SetDlgItemInt(hwnd, IDC_BROJAC, i, 0);
                                                                }
                                                 }
                                                 break;
                                           
                                            break;
                                            }
                                
                        case WM_CLOSE:
                             DestroyWindow(hwnd);
                             break;
                        case WM_DESTROY:
                             PostQuitMessage(0);
                             break;
                        default:
                             return DefWindowProc(hwnd, Message, wParam, lParam);
     }
      
      
     return 0;
       
}                          
 

Spirit...
Poruka je uređivana zadnji put uto 16.7.2013 18:14 (Neutral).
Moj PC  
0 0 hvala 0
15 godina
neaktivan
offline
Re: C Windows programiranje - pomoć
Neutral kaže...

Pozdrav ljudi, evo svracam opet.

Dosa sam do 6. poglavlja knjige, zove se sat. Uglavnom to je nebitno, bitno je da imam problema sa kompajliranjem samog koda. Javlja mi gresku tipa [Linker error].

Tocnije,  [Linker error] undefined reference to `GetStockObject@4'

Kompajler je skup alata koji prevode izvorni kod u strojni jezik te potom načine izvršnu datoteku (executable). Taj se proces odvija u dvije faze. Prvo kompajler prevede sve source datoteke u strojni jezik i to na način da prevodi datoteku po datoteku stvarajući takozvane objekt datoteke (ekstenzija .o ili .obj). Nakon toga nastupa linker, njegov je posao povezati sve objektne datoteke u jednu cjelinu, i pri tome još u miks dodaje i programski kod iz statičkih biblioteka (koje nisu ništa drugo nego kolekcija objektnih datoteka u jednoj datoteci, ekstenzija tih datoteka je uglavnom .lib ili .a). Kada linker pospaja sav potreban kod u jednu cjelinu nastane izvršna datoteka.

 

Sada kada znaš što je linker i što on radi malo ti je jasnija ova greška. Naime, negdje u tvom programu je pozvana funkcija GetStockObject, a ta funkcija nije definirana nigdje u tvom kodu nego je deklarirana kroz header windows.h. Linkeru treba adresa te funkcije a nije ju uspio pronaći zato što funkcija nije definirana nigdje u tvom kodu niti u standardnim runtime bibliotekama. To je zapravo funkcija koja se nalazi u windows GDI dinamičkoj biblioteci (gdi32.dll) i da bi linkeru rekao da se ta funkcija nalazi tamo moraš svoj program linkati sa libgdi32.a import bibliotekom.

 

Koja je razlika između statičke, dinamičke i import biblioteke?

 

Statička biblioteka je kolekcija raznih funkcija koje se doslovno kopiraju u tvoj program prilikom kompajliranja. Ako ti treba funkcija X, a ona nije definirana nigdje u tvom programu nego se nalazi u biblioteci, linker će ju doslovno kopirati u tvoj program.

 

Dinamička biblioteka (ekstenzija .dll) je također kolekcija raznih funkcija, ali te funkcije se ne kopiraju u tvoj program prilikom kompajliranja, nego se biblioteka učita u memoriju programa kada se program izvršava, te onda u toj memoriji program pronađe funkciju koja mu treba.

 

Import biblioteka zapravo nije prava biblioteka. One idu u paru sa dinamičkim bibliotekama i njihov sadržaj nije ništa drugo nego popis svih funkcija koje se nalaze u nekoj dinamičkoj biblioteci. Kada linker nađe neku funkciju na popisu neke import biblioteke on zabilježi naziv dinamičke biblioteke koja ide uz tu import biblioteku, te u specijalno područje izvršne datoteke koje se naziva 'Import' dodaje naziv dinamičke biblioteke. Kada operacijski sustav učitava izvršnu datoteku u memoriju onda zaviri i u 'Import' područje te u memoriju tog programa učita i sve dinamičke biblioteke koje se nalaze na tom popisu.

 

I sve to skupa u tvom primjeru:

GetStockObject nije definiran u tvojoj source datoteci, nego se nalazi u gdi32.dll dinamičkoj biblioteci. Da bi koristio tu funkciju moraš svoj program linkati sa libgdi32.a import bibliotekom koja će linkeru reći da se tražena funkcija nalazi u gdi32.dll biblioteci, te će linker staviti naziv te biblioteke u Import sekciju izvršne datoteke. Kada windowsi budu učitavali izvršnu datoteku tvog programa naći će gdi32.dll biblioteku u Import sekciji te će ju učitati u memorijski adresni prostor tvog programa nakon čega će program moći normalno koristiti GetStockObject funkciju kao da je od početka bila njegov dio.

 

Ovo @4 nakon naziva funkcije je zapravo name mangling shema C jezika, i u biti broj govori koliko sveukupno bajtova stack memorije argumenti funkcije zauzimaju (u ovom slučaju 4 bajta, odnosno 32 bitni integer ili pointer na 32 bitnu memorijsku adresu).

 

Trivia: ekstenzija dinamičkih biblioteka na Windowsu je .dll (dynamic link library), na Linuxu .so (shared object), a na MacOS-u .dynlib (dynamic library).

 

P.S.

Malo sam proširio odgovor na tvoje pitanje čisto kako bih kasnije imao nekakav post koji bih mogao linkati naokolo kada nekome zatreba objašnjenje ovih stvari. Također, ovo nije potpuno objašnjenje. Nisam ni spomenuo relokacijske tabele i još neke tehnikalije, ali IMO dovoljno za početak.

What Andy giveth, Bill taketh away.
Poruka je uređivana zadnji put sri 17.7.2013 11:53 (rustweaver).
1
Nova poruka
E-mail:
Lozinka:
 
vrh stranice