După vacanță, înainte de examen

26 June 2008

Nu am mai blogat de mult (din nou) pentru că am fost plecat. Cu ocazia zielei mele de naștere am fost o săptămână la Hunedoara, pe urmă un weekend la Cluj la nași, cu acces limitat la internet și fără chestii tehnice de povestit.

Acum mă ”pregătesc” pe ultima sută de metrii de examenul de licență. La noi la universitate se dă, pe lângă susținerea proiectului, un examen grilă din algoritmi, structuri de date și, la alegere, limbajul C sau baze de date. Normal că a trebuit să cumpăr cărțulia cu întrebări și răspunsuri. La prima vedere am zis că e OK – chestii elementare, nu-mi fac griji. Până dau de întrebări de genul:

În cazul unei structuri de date de tip arbore ordonat, dacă gradul fiecărui nod este cel mult 2 atunci despre arbore se spune că

a) este arbore binar ordonat 
b) este arbore binar 
c) este arbore dinar de căutare 
d) este arbore binar echilibrat 
e) este arbore binar perfect echilibrat 

(Întrebarea 105 – structuri de date, pagina 84, Teste Grilă pentru examenul de licență. Informatică – ediția a doua, ISBN (10) 973-661-844-7, ISBN(13) 978-973-661-844-4)

Acum, citind întrebarea, se vede pe loc că nu e echilibrat – e doar un arbore binar. Buuuun. O structură de tip arbore ordonat, care e și arbore binar. Eu zic că e a – arbore binar ordonat - pentru că e arbore binar și ordonat, b – arbore binar – pentru că b e inclus în a, c - pentru că unui arbore binar ordonat i se poate spune, din câte știu eu, arbore binar de căutare.

Răspunsul corect (după cum apare la sfârșitul cărții) e b. Atât. Arbore binar. Ce contează ca în enunț scrie că e structură ordonată? Nu, varianta a nu e corectă. E doar arbore binar.

OK. A fost ambiguu. Uitați următoarea întrebare:

Dacă a este o variabilă de tip int și a = -1, valoarea expresiei ~++a este:

a) -1 
b) 0 
c) 1 
d) expresia este greșită sintactic 

(Întrebarea 81 – limbajul C, pagina 111)

Rezultatul ”corect”, după cum scrie la capătul cărții, este a și d. Acum expicați-mi cum poate o expresie să fie atât greșită sintactic cât și să se evalueze la o valoare?

Și mă opresc aici din dat exemple, deși sunt multe. Și eu ce fac până la urmă? Domnii profesori nu au binevoit să ne anunțe dacă corectarea se va face strict după carte sau așa cum trebuie. În caz că se va face după carte - eu nu sunt tocilar de fel, așă că nu o să pot memora răspunsurile cum sunt în carte. Când voi citi enunțul problemei, voi da răspunsul pe care eu îl consider corect. S-ar putea să nu coincidă cu noțiunea domnilor profesori de corect. Voi fi depunctat. Sunt convins că așa se va face pentru că ”șefii de an”, ”capii de promoție” și cum se mai zice vor învăța grilele pe de rost și ei sunt cei care vor face scandal dacă în urma corectării, li se va strica linia de 10. ”Păi de ce e greșit? Că în carte așa scria”. Și atunci eu ce fac? Mă iau după ei și memorez tâmpenii ca să dau răspunsuri satisfăcătoare? Să risc să fie totuși o corectare corectă și să nu fie bine? Să dau răspunsuri pe care eu și orice om întreg la cap le consideră corecte și să se corecteze după răspunsurile de la spatele cărții?

Urați-mi baftă că o să am nevoie. Jur că sunt scârbit de școala asta și de 90% dintre profesori și de 100% din sistemul de învățământ și de 110% din ce se predă. Ajung din nou la concluzia la care am ajuns acum mulți, mulți ani. Sfântul 5. Vreau să trec. Mi se rupe de nota la care mă evaluează ei și de grilele lor și de tot. Eu știu ce știu și sunt destul de mulțumit cu ce știu (totdeauna se poate mai mult, dar am atâtea contraexemple colegi de an cu mine). Vreau să scap.


Carets for Custom Controls

5 June 2008

I decided to start posting in English (at least the technical posts). I hope this way I can reach more people who might be interested in the things I blog about (the .NET Framework, C#, compilers and such).

Today I was thinking about developing a custom control that receives text input. But how am I supposed to display the caret? I searched the Internet for some .NET controls that do the same thing and the best I got was a separate thread used only for blinking a custom drawn caret. That seemed a bit strange – are all WinForm controls implemented that way?

I decided to go to the source – how does WinAPI go about drawing them? Well, pretty simple – there are a bunch of functions in user32.dll. I imported some of them:

[DllImport("user32.dll")]
static extern bool CreateCaret(IntPtr hWnd, int hBitmap, int nWidth, int nHeight);

[DllImport("user32.dll")]
static extern bool SetCaretPos(int X, int Y);

[DllImport("user32.dll")]
static extern bool ShowCaret(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool DestroyCaret();

From here on, things are pretty simple. One thing to note though, MSDN clearly states that there is only one caret created per message queue – that is, you can’t have two different carets blinking at the same time in different controls (or the same control for that matter). So, to add a custom caret to the form itself, I just handled the Activated and Deactivated events:

private void Form1_Activated(object sender, EventArgs e)
{
    CreateCaret(this.Handle, 1, 5, 10);
    SetCaretPos(0, 0);
    ShowCaret(this.Handle);
}

private void Form1_Deactivate(object sender, EventArgs e)
{
    DestroyCaret();
}

The argument 1 for hBitmap will give it the neat appearance – more about it on MSDN. This example is very basic but I think it’s a good starting point.


Fața nevăzută a CLR-ului

1 June 2008

Eram curios cum funcționează metoda Assembly.Load – nu mai conteză de ce. Ca norocul, am pe calculator Shared Source Common Language Infrastructure 2.0 (de pe DVD-ul ARK, dar daca vreti, il puteti lua si de la Microsoft Research sub numele de Rotor). SSCLI sunt sursele de la .NET Framework, compilatorul de C# și altele, distribuite ca shared source.

După cum ziceam, caut Assembly.Load și găsesc declarația în /clr/src/bcl/system/reflection/Assembly.cs. Metoda apelează nLoad. Caut nLoad și găsesc în același fișier următoarea declarație:

[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern Assembly nLoad(
    AssemblyName fileName,
    String codeBase,
    Evidence assemblySecurity,
    Assembly locationHint,
    ref StackCrawlMark stackMark,
    bool throwOnFileNotFound,
    bool forIntrospection);

Sunt curios dacă pot și eu apela metoda nLoad. Aflu rapid că nu - StackCrawlMark este un alias declarat la începutul fișierului ca

using StackCrawlMark = System.Threading.StackCrawlMark;

unde System.Threading.StackCrawlMark are vizibilitatea internal – adică nu poate fi utilizat în afara assembly-ului în care apare :( OK, totuși, ce înseamnă atributul

[MethodImplAttribute(MethodImplOptions.InternalCall)]?

Cică, spune MSDN, atributul denotă o metodă implementată chiar în CLR. După încă puține săpături, descopăr toate metodele astfel implementate în fișierul ecall.cpp (/clr/src/vm/echall.cpp) – ecall probabil de la Engine Call. Chiar dacă Base Class Library e scris în C#, mașina virtuală e scrisă în C++. În fișier este o listă măricică de funcții care sunt apelate de BCL cu ajutorul atributului de mai sus.

De curiozitate, încerc să apelez și eu o astfel de metodă – nu nLoad pentru că nu pot din cauza lui StackCrawlMark, dar găsesc ceva mai simplu: string GetFullName(). Declar și eu frumos

[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string GetFullName();

și apelez

Console.WriteLine(GetFullName());

Să nu uit de using System.Runtime.CompilerServices pentru cine vrea să refacă experimentul – acolo e declarat atributul MethodImpl.

Rezultatul? Excepție de tip System.Security.SecurityException: ECall methods must be packaged into a system module. Deci apelurile de tip InternalCall pot fi făcute doar din mscorlib.dll. Asta este. Măcar acum știu de existența lor.