|
Otßzky a odpov∞di |
|||||
Programßtorskß poradna |
||||||
╚asovß nßroΦnost (min): |
ZaΦßteΦnφk |
PokroΦil² |
Profesionßl |
|||
|
|
|
||||
|
Pou₧it² operaΦnφ systΘm : Hlavnφ v²vojov²
nßstroj : DalÜφ v²vojov² software : Jin² software : |
Windows 2000 SP3 Visual C# .NET 2002 Äßdn² Äßdn² |
||||
|
|
Cht∞l bych z aplikace napsanΘ v C# zavolat API funkci
Windows, ovÜem nem∙₧u najφt zp∙sob, jak to provΘst. Mohl byste mi poradit? |
Budete-li se pokouÜet volat z °φzenΘ
aplikace ne°φzenou funkci aplikaΦnφho programovacφho rozhranφ (API) Windows,
budete muset splnit p°ed samotn²m pou₧itφm vßmi po₧adovanΘ funkce n∞kolik
podmφnek: 1.
Deklaraci API funkce musφ p°edchßzet pou₧itφ
specißlnφho atributu DllImportAttribute, kter² se nachßzφ ve jmennΘm
prostoru System.Runtime.InteropServices. Atribut DllImportAttribute
naznaΦuje, ₧e bude importovßna API funkce s ne°φzen²m k≤dem. Ve
skuteΦnosti je atribut pouze jin²m oznaΦenφm pro specißlnφ t°φdu se stejn²m
nßzvem (DllImportAttribute). Konstruktor tΘto t°φdy pracuje
s jednφm parametrem typu string, kter²m je nßzev DLL knihovny, ve
kterΘ je ulo₧en k≤d API funkce, kterou chcete pou₧φt. 2.
DeklaraΦnφ p°φkaz API funkce musφ obsahovat
klφΦovß slova static a extern. 3.
Deklarace API funkce v °φzenΘm k≤du musφ
p°esn∞ odpovφdat prototypu funkce v ne°φzenΘm k≤du. To znamenß, ₧e
deklarace musφ obsahovat stejnΘ jmΘno, dßle stejnou signaturu
s p°φsluÜn²mi datov²mi typy formßlnφch parametr∙ funkce a takΘ stejnou
nßvratovou hodnotu (pokud existuje). Jestli₧e budou spln∞ny tyto podmφnky, bude
API funkce ·sp∞Ün∞ naimportovßna do k≤du vaÜφ °φzenΘ aplikace. S API
funkcφ m∙₧ete poslΘze pracovat jako s jakoukoliv jinou funkcφ. Podφvejme
se na ukßzku pou₧itφ API funkce operaΦnφho systΘmu Windows: áááááááááááá // ...
Tento programov² k≤d se nachßzφ uvnit° t°φdy Form1. áááááááááááá static
void Main() áááááááááááá { ááááááááááááááááááá Application.Run(new Form1()); áááááááááááá } áááááááááááá [System.Runtime.InteropServices.DllImport("User32")] ááááááááááááááááááá private
static extern
bool MoveWindow(int
hWnd, ááááááááááááááááááá int
X, int Y, int
nWidth, int nHeight, bool
bRepaint); áááááááááááá [System.Runtime.InteropServices.DllImport("User32")] ááááááááááááááááááá private
static extern
bool AnimateWindow(int
hWnd, ááááááááááááááááááá uint
dwTime, uint dwFlags); áááááááááááá private
void button1_Click(object
sender, System.EventArgs e) áááááááááááá { ááááááááááááááááááá frm = new Form(); ááááááááááááááááááá frm.Load += new EventHandler(frm_Load); ááááááááááááááááááá frm.Show(); áááááááááááá } áááááááááááá áááááááááááá Form frm; áááááááááááá private
void frm_Load(object
sender, System.EventArgs e) áááááááááááá { ááááááááááááááááááá int
handle = frm.Handle.ToInt32(); ááááááááááááááááááá MoveWindow(handle, 362,
234, 300, 300, true); ááááááááááááááááááá AnimateWindow(handle, 200,
0x00080000); áááááááááááá } áááááááááááá // ...
zde pokraΦuje k≤d t°φdy Form1. Ukßzkov² programov² k≤d pou₧φvß pro p°esun
a animaci nov∞ vytvo°enΘ instance t°φdy Form dv∞ API funkce: MoveWindow
a AnimateWindow. P°ed ka₧dou z funkcφ se nachßzφ atribut DllImport
se jmΘnem dynamicky linkovanΘ knihovny (DLL), ve kterΘ je ulo₧en k≤d danΘ funkce
(ob∞ zde pou₧itΘ funkce jsou ulo₧eny v souboru User32.dll). Velmi
d∙le₧itΘ je, aby byl atribut zapsßn v hranat²ch zßvorkßch. Za atributem
se nachßzφ samotn² deklaraΦnφ p°φkaz, kter² je slo₧en z modifikßtoru
p°φstupu (private), klφΦov²ch slov static a extern, typem
nßvratovΘ hodnoty funkce a jejφ signaturou (datovΘ typy p°itom musφ odpovφdat
datov²m typ∙m pou₧itφm v ne°φzenΘm k≤du API funkce). Ve v²Üe uvedenΘ
programovΘ ukßzce je dßle deklarovßna referenΦnφ prom∞nnß frm
s oborem t°φdy, kterΘ m∙₧e uchovßvat referenci na instance t°φdy Form.
áV udßlostnφ procedu°e button1_Click
je vytvo°ena novß instance t°φdy Form,
p°iΦem₧ dochßzφ takΘ k vytvo°enφ systΘmovΘho delegßta (EventHandler) pro zpracovatele udßlosti
Load nov∞ vytvo°enΘ instance.
Jakmile bude aktivovßna metoda Show objektu frm, delegßt
usm∞rnφ program tak, aby byl uskuteΦn∞n programov² k≤d, jen₧ se nachßzφ ve
zpracovateli udßlosti frm_Load. Kdy₧ dojde k udßlosti Load
objektu frm, bude vykonßn k≤d zpracovatele frm_Load (k udßlosti
dojde po zavolßnφ metody Show p°φsluÜnΘ instance). Zpracovatel
udßlosti frm_Load obsahuje nßsledujφcφ °ßdky programovΘho k≤du: private void frm_Load(object sender, System.EventArgs e) áááááá { áááááááááááá int
handle = frm.Handle.ToInt32(); áááááááááááá MoveWindow(handle, 362, 234, 300,
300, true); áááááááááááá AnimateWindow(handle, 200,
0x00080000); áááááá } Co proboha
tento k≤d provßdφ? Tak p°edevÜφm, je zφskßn handle okna instance t°φdy Form.
Handle p°edstavuje jednoznaΦn² identifikßtor, pomocφ kterΘho Windows
p°istupujφ k vytvo°enΘ instanci (hodnota identifikßtoru handle je v tomto
p°φpad∞ p°evedena do podoby 32bitovΘho celΘho Φφsla pomocφ metody ToInt32).
Handle okna pot°ebujeme zφskat, nebo¥ jej vyu₧ijeme v obou API funkcφch.
Abyste p°esn∞ v∞d∞li, co uvedenΘ API funkce provßd∞jφ, p°edstavφme si je
podrobn∞ji: 1.
API funkce
MoveWindow mß tuto vÜeobecnφ podobu (v C/C++): BOOL MoveWindow( á HWND hWnd,ááááá // handle okna á int X,ááááááááá // horizontßlnφ
pozice okna
á int Y,ááááááááá // vertikßlnφ
pozice okna á int nWidth,áááá //
Üφ°ka okna
á int nHeight,ááá // v²Üka
okna á BOOL bRepaintáá // volba, kterß
urΦuje, zdali bude po p°emφst∞nφ realizovßno áááááááááááááááááááááááááááááááááá ááááááááááááááááá // takΘ
p°ekreslenφ okna ); Podoba naÜφ funkce je nßsledovnφ: MoveWindow(handle, 362, 234, 300, 300, true); Funkce zachovßvß implicitnφ velikost okna instance t°φdy Form
(300x300 pixel∙), ovÜem m∞nφ pozici levΘho hornφho bodu okna na bod se
sou°adnicemi (362, 234). Poslednφ parametr (bRepaint) je nastaven na
hodnotu true, co₧ znamenß, ₧e ihned potΘ, co se okno instance p°esune,
bude provedeno jeho p°ekreslenφ. á áá 2.
API funkce
AnimateWindow mß tuto vÜeobecnφ
podobu (op∞t v C/C++): BOOL AnimateWindow( á HWND
hwnd,áááá // handle
okna á DWORD
dwTime,á // doba
trvßnφ animace okna á DWORD
dwFlagsá // typ
animace ); A op∞t se podφvejme na naÜφ implementaci funkce AnimateWindow: AnimateWindow(handle, 200, 0x00080000); Prvnφm parametrem funkce je handle okna, kterΘ bude animovßno. Druh² parametr (dwTime) je datovΘho typu DWORD (typ DWORD p°edstavuje 32bitovΘ celΘ Φφslo bez znamΘnka, jeho₧ maximßlnφ hodnota je 232-1). V C# se typ DWORD samoz°ejm∞ nepou₧φvß, ovÜem jeho ekvivalentem je datov² typ uint, jen₧ disponuje stejn²m rozsahem platn²ch celoΦφseln²ch hodnot. Parametr dwTime odpovφdß dob∞ trvßnφ animace, kterß se udßvß v milisekundßch. V naÜem p°φpad∞ bude animace trvat 200 milisekund, co₧ je doporuΦenß hodnota danß zp∙sobem prßce operaΦnφho systΘmu. Nejhroziv∞ji pravd∞podobn∞ vypadß t°etφ parametr (dwFlags), jeho₧ hodnotou je podivn∞ vyhlφ₧ejφcφ Φφslo v ÜestnßctkovΘ soustav∞ 0x0008000. Numerickß hodnota 0x0008000 odpovφdß internφ konstant∞ AW_BLEND, kterß se pou₧φvß v p°φpad∞, kdy mß b²t okno animovßno pomocφ tzv. fade efektu. Fade efekt znamenß plynulΘ animovßnφ zobrazenφ okna, p°iΦem₧ na zaΦßtku je okno tak°ka pr∙hlednΘ a postupn∞ se äzapl≥ujeô do standardnφho barevnΘho schΘmatu a podoby. á
|
|
Doposud jsem programoval ve Visual Basicu .NET. Myslφte, ₧e bych se
mohl nauΦit programovat takΘ ve Visual C#? |
Zcela jist∞ ano. Visual C# je velmi
zajφmav² jazyk, kter² vhodn∞ kombinuje rychl² nßvrh aplikacφ, jen₧ je znßm²
prßv∞ z Visual Basicu a flexibilnφ syntaxi, kterß je p°ednostφ jazyka
C++. Proto₧e vÜechny jazyky platformy .NET vyu₧φvajφ spoleΦnΘ integrovanΘ prost°edφ,
na prvnφ pohled mo₧nß ani nepost°ehnete, ₧e se nachßzφte uvnit° Visual C#. Visual
C# taktΘ₧ nabφzφ vizußlnφ v²voj aplikacφ, tak₧e grafickou podobu aplikace
m∙₧ete navrhnout p°esn∞ tak, jak to d∞lßte ve Visual Basicu .NET. Na druhΘ
stran∞ je pravdou, ₧e zßpis programovΘho k≤du se od Visual Basicu podstatn∞
liÜφ a zde vßm zcela urΦit∞ pom∙₧e p°edchßzejφcφ zkuÜenost s jazykem C
nebo C++ (p°φpadn∞ s Javou). Pokud neznßte uvedenΘ jazyky, nemusφte
zoufat. Serißl ZaΦφnßme s jazykem
Visual C# vßm poskytne vÜechny pot°ebnΘ informace nato, abyste mohli psßt
svΘ prvnφ programy i ve Visual C#. Ve skuteΦnosti jsou jazyky Visual C# a
Visual Basic .NET do velkΘ mφry podobnΘ ve smyslu implementace stejn²ch, nebo
p°inejmenÜφm velmi podobn²ch programovacφch prvk∙. Ku p°φkladu, oba jazyky umo₧≥ujφ
°φdit tok programu pomocφ rozhodovacφ konstrukce If (if v C#), ovÜem zßpis tΘto
konstrukce je v C# jin² ne₧ ve Visual Basicu (podobn∞ je tomu takΘ t°eba p°i
cyklech Φi prvcφch OOP). SeΦteno a podtr₧eno, jestli₧e dob°e ovlßdßte Visual
Basic .NET, p°i pilnΘm studiu se do taj∙ Visual C# m∙₧ete dostat velmi
rychle. Pon∞kud problematiΦt∞jÜφ je ovÜem p°echod k Visual C# pro
programßtory, kte°φ pracujφ s Visual Basicem verze 6. Ty toti₧ budou
muset nejd°φve zvlßdnout vÜechny inovace a modifikace, je₧ p°inßÜφ v²vojovß
platforma .NET.áá ááááááááá |
|
Pracuji s formulß°em, kter² bych pot°eboval vertikßln∞ i
horizontßln∞ vycentrovat na obrazovce poΦφtaΦe. Vφm, ₧e v re₧imu nßvrhu
mohu nastavit vlastnost StartPosition na hodnotu CenterScreen,
co mßm vÜak ud∞lat, kdy₧ chci provΘst vyst°ed∞nφ formulß°e za b∞hu programu? |
Udßlostnφ proceduru Load formulß°e upravte do nφ₧e uvedenΘ podoby: áááááá private
void Form1_Load(object
sender, System.EventArgs e) áááááááááááá { ááááááááááááááááááá this.Top
= (Screen.PrimaryScreen.Bounds.Height - this.Height)
/ 2; ááááááááááááááááááá this.Left
= (Screen.PrimaryScreen.Bounds.Width - this.Width)
/ 2; áááááááááááá } Abyste mohli provΘst vyst°ed∞nφ formulß°e,
musφte znßt rozm∞ry zobrazovacφ plochy obrazovky a rozm∞ry samotnΘho
formulß°e. Rozm∞ry formulß°e jsou znßmΘ, nakolik Visual C# implicitn∞ vytvß°φ
formulß°e s velikostφ 300x300 obrazov²ch bod∙ neboli pixel∙. P°i zrozenφ
instance formulß°e jsou do vlastnostφ Height a Width tΘto
instance ulo₧eny hodnoty 300 pixel∙. Pro zjiÜt∞nφ rozm∞r∙ viditelnΘ plochy
obrazovky pou₧ijeme t°φdu Screen. Konstruktor t°φdy Screen ovÜem
nenφ ve°ejn² a proto nenφ mo₧nΘ p°φmo vytvß°et instance tΘto t°φdy. Pokud
ovÜem zavolßme statickou vlastnost PrimaryScreen, poda°φ se nßm zφskat
instanci t°φdy Screen. Vrßcenß
instance p°edstavuje hlavnφ zobrazovacφ jednotku poΦφtaΦovΘho systΘmu (pokud
systΘm pracuje jenom s jednou obrazovkou, bude vrßcena tato,
v opaΦnΘm p°φpad∞ bude vrßcena ta zobrazovacφ jednotka, kterß je
nakonfigurovßna jako primßrnφ). Dßle pokraΦujeme zavolßnφm vlastnosti Bounds
vytvo°enΘ instance t°φdy Screen. Vlastnost Bounds vracφ
instanci t°φdy Rectangle (jde o objekt, jen₧ popisuje obdΘlnφkov²
region hlavnφ zobrazovacφ jednotky). Mßme-li instanci t°φdy Rectangle,
m∙₧eme koneΦn∞ pou₧φt vlastnost Height (resp. Width) pro
zjiÜt∞nφ v²Üky (resp. Üφ°ky) viditelnΘ plochy obrazovky. P°edpoklßdejme, ₧e
vlastnφte 17-palcov² monitor a pou₧φvßte rozliÜenφ 1024x768 obrazov²ch bod∙.
Za t∞chto podmφnek vrßtφ p°φkaz Screen.PrimaryScreen.Bounds.Height hodnotu
768 a p°φkaz Screen.PrimaryScreen.Bounds.Width zase vrßtφ hodnotu 1024. Od
takto zφskan²ch hodnot poslΘze odeΦteme hodnoty, kterΘ reprezentujφ v²Üku
(resp. Üφ°ku) formulß°e a finßlnφ v²sledky vyd∞lφme dv∞ma. Do vlastnosti Top
formulß°e bude po provedenφ vÜech nastφn∞n²ch operacφ ulo₧ena hodnota 234,
zatφmco vlastnost Left bude obsahovat hodnotu 362 (viz obrßzek). ááááá |
|
Cht∞l bych se zeptat, jak je mo₧nΘ ve Visual C# vytvß°et zpracovatele
udßlosti, a to jak v re₧imu nßvrhu, tak i za b∞hu aplikace.á |
V re₧imu nßvrhu aplikace vytvo°φte
zpracovatele udßlosti takto: 1.
Na formulß°i vyberte ten ovlßdacφ prvek, pro
kter² chcete vytvo°it zpracovatele udßlosti. 2.
V okn∞ Properties Window klepn∞te na
tlaΦφtko Events ( 3.
Vyhledejte polo₧ku s nßzvem po₧adovanΘ
udßlosti (nap°. Click) a poklepejte na tuto polo₧ku. 4.
Visual C# okam₧it∞ vygeneruje programovou kostru
udßlostnφ procedury a otev°e okno editoru pro zßpis programovΘho k≤du. 5.
Vypl≥te t∞lo vytvo°enΘ udßlostnφ procedury
vhodn²m programov²m k≤dem. Jestli₧e budete chtφt spojit udßlost
s jejφm zpracovatelem za b∞hu programu, budete muset vÜechny pot°ebnΘ
operace provΘst p°φmo z programovΘho k≤du. Aby bylo mo₧nΘ vytvo°it
spojenφ mezi udßlostφ a p°φsluÜn²m zpracovatelem, musφte vytvo°it systΘmovΘho
delegßta, kter² bude zodpov∞dn² za to, aby udßlost naÜla svΘho zpracovatele. Nßsledujφcφ fragment k≤du byl vy≥at ze
t°φdy Form1. M∙₧ete si v n∞m vÜimnout udßlostnφ proceduru button1_Click.
V tΘto procedu°e dochßzφ k vytvo°enφ novΘ instance t°φdy Button (s nßzvem btnTlaΦφtko1), dßle
jsou nastaveny n∞kterΘ klφΦovΘ vlastnosti nov∞ vytvo°enΘ instance a instance
je p°idßna do kolekce ovlßdacφch prvk∙ formulß°e. Spojenφ mezi udßlosti Click tlaΦφtka
btnTlaΦφtko1 a zpracovatelem tΘto udßlosti (btnTlaΦφtko1_Click)
zabezpeΦuje systΘmov² delegßt EventHandler. P°i tΘto programovΘ
operaci je velmi d∙le₧itΘ sprßvnΘ pou₧itφ operßtor∙ += a new. Nakonec u₧ staΦφ jenom napsat udßlostnφ
proceduru btnTlaΦφtko1_Click, kterß ovÜem musφ disponovat stejn²mi
prvky, jako systΘmov² delegßt (nesmφ vracet hodnotu a musφ pracovat se dv∞ma
parametry typu object a System.EventArgs). Pokud mßte
zkuÜenosti s jazykem C nebo C++, m∙₧ete si delegßta p°edstavit jako
funkΦnφ ukazatel, kter² je ale v jazyce Visual C# zcela typov∞ bezpeΦn².
Delegßt tak ve skuteΦnosti obsahuje runtime adresu funkce, v naÜem
p°φpad∞ zpracovatele udßlosti, a tohoto zpracovatele aktivuje v₧dy, kdy₧ je o
to po₧ßdßn (neboli v₧dy, kdy₧ u₧ivatel klepne na tlaΦφtko). áá ááááá áááááá private void button1_Click(object
sender, System.EventArgs
e) áááááááááááá { ááááááááááááááááááá Button btnTlaΦφtko1 = new Button(); ááááááááááááááááááá btnTlaΦφtko1.Text = "TlaΦφtko"; ááááááááááááááááááá btnTlaΦφtko1.Location = new Point(10, 100); ááááááááááááááááááá btnTlaΦφtko1.Size = new Size(200, 100); ááááááááááááááááááá this.Controls.Add(btnTlaΦφtko1); ááááááááááááááááááá btnTlaΦφtko1.Click += new System.EventHandler(btnTlaΦφtko1_Click); áááááááááááá } áááááááááááá private
void btnTlaΦφtko1_Click(object sender, EventArgs
e) áááááááááááá { ááááááááááááááááááá MessageBox.Show("Prßv∞ jste klepli na tlaΦφtko."); áááááááááááá } Graficky m∙₧eme vztah mezi udßlostφ, jejφm
zpracovatelem a systΘmov²m delegßtem znßzornit takto: |
Jßn Hanßk