Lucrul cu com-obiecte folosind ansambluri de interacțiune, sau "de ce în pachetul de birou

Această documentație a fost mutată în arhivă și nu este acceptată.

Pe această pagină ...

În cadrul .NET Framework, există mai multe mecanisme de schimb de date între aplicațiile .NET Framework și obiectele COM. Cu toate acestea, pentru a preveni scurgeri de memorie atunci când lucrați cu obiecte COM sau în cazul unei terminări bruște a obiectului COM, aceste funcții ar trebui utilizate cu suficientă îndemânare.







Cel mai convenabil mod de a lucra cu obiectele COM este ansamblurile interop. În acest caz, aplicația gestionată .NET interacționează cu modulul RCW (Runtime Callable Wrapper - wrapperul apelurilor .NET) care controlează schimbul cu obiectul COM. Modulele RCW efectuează multe funcții utile atunci când lucrează cu obiecte COM, inclusiv activarea componentelor și marshalingul parametrilor (de exemplu, conversia datelor șir în șiruri COM ale BSTR). Microsoft oferă ansambluri speciale de interacțiune pentru a lucra cu sistemul Microsoft Office, denumit Primar Interop Assemblies (PIA). Cu toate acestea, aceste instrumente nu rezolvă problemele asociate procesării ciclurilor de viață ale obiectelor COM și, prin urmare, este necesară găsirea abilității de a recunoaște și de a rezolva aceste probleme prin alte mijloace.

Butonul nu mai funcționa

Dintr-o dată, fără niciun motiv aparent, când se face clic pe buton, procedura de procesare a evenimentului Click se oprește. Evenimentul Click pentru buton nu mai funcționează.

Majoritatea dezvoltatorilor ar detecta rapid o problemă dacă programul Eveniment clic nu mai funcționa imediat după finalizarea procedurii și variabila este ieșită din domeniul de aplicare. Acesta este exact momentul în care apare o problemă în aplicația COM care gestionează aplicația Word. Cu toate acestea, în .NET Framework, obiectul nu este neapărat distrus imediat după ce acesta nu mai este vizibil. În schimb, acesta va exista până când .NET Framework îl va distruge în orice moment. În tot acest timp, programul de eveniment clic când utilizatorul apasă butonul de meniu reușește și apoi se oprește brusc de funcționarea corectă atunci când .NET Framework distruge în final obiectul. Aceasta este o diferență fundamentală în modul de procesare a ciclurilor de viață ale obiectelor și, prin urmare, de memorie, în COM și .NET Framework.

Managementul memoriei în modelele COM și .NET

Se utilizează .NET Framework. dacă pot spune așa, o abordare "opusă", nestricătoare a eliberării memoriei. Obiectele sunt șterse din memorie în timpul colectării gunoiului, verificând în același timp că obiectele nu mai sunt utilizate. Procesul de colectare a gunoiului este suficient de pasiv. Se efectuează numai după cum este necesar; de obicei când nu există suficientă memorie. În .NET Framework, în cazul în care o variabilă este distrusă, obiectul pe care se referă pur și simplu devine un candidat pentru ștergere cândva în viitor. Pentru mai multe informații despre acest concept și colecția de gunoi în .NET Framework, consultați articolul "Programarea colecției de gunoi" din Ghidul dezvoltatorului .NET Framework Developer's Guide.

Această metodă de eliberare a memoriei creează o problemă pentru evenimentul Click. Într-o aplicație .NET, variabila care se referă la modulul RCW care controlează aplicația Word este în afara scopului la sfârșitul procedurii, dar numai înseamnă că modulul RCW care gestionează obiectul COM este marcat pentru colectarea deșeurilor. În cele din urmă, modulul RCW poate fi scos din memorie atunci când se îndepărtează gunoiul și la acel moment obiectul COM controlat de modulul RCW va fi distrus. Numai după ce această aplicație .NET își pierde conexiunea cu evenimentul Click și butonul nu mai funcționează.

Gestionarea memoriei COM

Cu toate acestea, dacă trebuie să eliberați obiectul COM înainte de finalizarea aplicației, există o altă problemă: memoria nu este restaurată corect. În aplicația .NET, puteți distruge toate referințele la modulul RCW pentru obiectul COM corespunzător, însă obiectul COM nu va fi în mod necesar șters. De exemplu, o aplicație care descarcă și descarcă în mod constant Word pentru a procesa o serie de documente poate să nu aibă suficientă memorie, deoarece instanțele folosite anterior ale aplicației Word rămân în ea. Programatorul trebuie să gestioneze în mod independent obiectele COM pentru a reduce sarcina memoriei.

Deci, obiectele COM de la Office ilustrează posibile probleme. Ca și multe servere COM mari, diferite aplicații Office conțin în mod literal sute de obiecte, iar pentru sarcini normale, trebuie să instanțiați mai multe obiecte. De exemplu, următorul program lansează aplicația Word, folosind ansamblul principal interop (PIA), și apoi utilizează modulul RCW, rezultând un document:

Acest program încarcă trei elemente în memorie: un modul RCW care controlează obiectul Application al aplicației Word, colecția Documente și obiectul Document. Dacă următoarea etapă încarcă o imagine mare în document, cantitatea de memorie ocupată de obiectul COM poate deveni foarte mare.

După ce terminați să lucrați cu obiecte, le puteți șterge, pentru aceasta puteți distruge variabilele care fac referință la obiectele din Word:







Din păcate, când se colectează gunoi, memoria ocupată de obiectele COM nu poate fi restabilită, chiar dacă procesul de colectare a gunoiului este pornit din cauza lipsei de memorie. Atunci când se colectează gunoi, se face o încercare de a șterge selectiv obiecte din memorie: obiecte care nu au fost folosite de mult timp sunt atribuite o prioritate mai mare pentru colectarea gunoiului decât pentru obiectele care au fost folosite mult timp. Aceasta înseamnă că eliberarea obiectului COM imediat după ce ați terminat lucrul cu acesta crește probabilitatea ca acesta să fie șters mai rapid atunci când are loc colectarea deșeurilor.

Notă. Pentru mai multe informații despre colectarea gunoiului și impactul său asupra performanței, consultați articolul despre Garbage Collector Basics și Sugestii de performanță din Ghidul dezvoltatorului .NET Framework Developer's Guide.

Când lucrați cu un obiect COM dintr-o aplicație .NET, se folosesc două obiecte: wrapperul RCW și obiectul COM (sau obiecte). În timpul procesului de colectare a gunoiului, este cunoscută numai dimensiunea modulului RCW (care poate fi mică), iar dimensiunea obiectului COM (care poate fi mare) nu este cunoscută. Prin urmare, în ciuda faptului că aplicația .NET poate elibera modulul RCW, în timpul colectării gunoiului, modulul RCW poate să nu fie scos din memorie, chiar dacă este scurtcircuitat. În timp ce modulul RCW rămâne în memorie, obiectul COM pe care îl gestionează rămâne, de asemenea, în memorie.

Se pare că problema poate fi rezolvată dacă forțați o colecție de gunoi pentru RCW. Totuși, forțarea colectorului de gunoi să funcționeze aproape întotdeauna este o soluție proastă în .NET Framework. În plus, poate fi inutil, deoarece nu garantează îndepărtarea obiectului COM. Chiar și în cazul unui apel explicit, colectarea de gunoi este întotdeauna arbitrară în .NET Framework.

Există două mecanisme de eliminare a obiectelor COM din memorie: obiectul AppDomain și metoda ReleaseComObject. Utilizarea unui obiect AppDomain este cea mai simplă soluție pentru gestionarea obiectelor COM, dar există un risc semnificativ de degradare a performanței. Când se folosește metoda ReleaseComObject, nu există o astfel de problemă, dar în acest caz este necesară planificarea și codarea mai atentă.

Gestionarea obiectelor COM folosind clasa AppDomain

În cadrul .NET Framework, obiectul AppDomain oferă un mediu separat pentru rularea aplicației. Din punctul de vedere al gestionării obiectelor COM, obiectele AppDomain sunt bune deoarece, atunci când sunt descărcate, toate resursele pe care le utilizează sunt descărcate. Strategia este simplă: pentru fiecare obiect COM creat, creați un obiect AppDomain și încărcați obiectul COM în el. În plus, această metodă va simplifica munca cu obiecte COM, deoarece puteți descărca mai multe obiecte COM într-un singur domeniu și le puteți șterge pe toate în același timp.

Cu toate acestea, crearea unui obiect AppDomain poate necesita resurse semnificative, deci nu ar trebui să fie utilizat atunci când este important să se mențină performanțe ridicate. În plus, dacă există o posibilitate de acces extern la obiectul AppDomain, securitatea accesului la cod este încălcată (dacă nu există acces extern, obiectul AppDomain este sigur).

Următorul exemplu presupune că există un obiect COM de tip MyDLL.MyObject într-un fișier numit MyDLL.DLL. Pentru a adăuga o legătură la această bibliotecă COM în aplicație, selectați comanda Add Reference din meniul Project, apoi faceți clic pe Browse (Răsfoire) și selectați fișierul MyDLL.DLL.

După ce adăugați o referință la obiectul COM, îl puteți încărca în AppDomain utilizând metoda CreateInstanceFromAndUnWrap. Metoda primește doi parametri: calea completă la ansamblul interop și punctul de intrare pentru modulul de clasă. Locația ansamblului interop poate fi determinată utilizând obiectul Type. Obiectul Adunării asociat are o proprietate Locație care indică locul unde puteți găsi ansamblul de interacțiune. Inițial, modulul RCW este înfășurat pentru a preveni încărcarea inutilă a datelor din biblioteca de tip, dar metoda CreateInstanceFromAndUnWrap elimină de asemenea această împachetare.

Următorul exemplu definește un obiect AppDomain numit MyDomain și apoi încarcă obiectul COM în el. După ce a lucrat cu obiectul COM, AppDomain este descărcat, eliberând obiectul COM:

Gestionarea unui obiect COM folosind ReleaseComObject

Ca o alternativă la utilizarea obiectelor AppDomain, puteți să ștergeți cu forța un obiect COM din memorie scăzând numărul referințelor de referință COM la zero. După scoaterea obiectului COM din memorie, puteți elibera modulul RCW (pentru colectarea suplimentară a gunoiului). Această metodă este mai complicată decât cea anterioară, dar evită pierderea de performanță asociată cu crearea unui obiect AppDomain.

Când creați un obiect COM în modulul RCW, o unitate este setată în numărul său de referință. Indiferent de cât de mulți clienți .NET se referă la modulul RCW într-un singur proces, valoarea numărului de referință al obiectului COM rămâne unul. Cu toate acestea, dacă transferați modulul RCW din limitele procesului, valoarea numărului de referință al obiectului COM poate crește, astfel încât numărul de referință nu este neapărat egal cu unul.

.NET Framework oferă o modalitate de reducere directă a valorii numărului de referințe pentru obiecte COM, prin trecerea modulului RCW la metoda ReleaseComObject din clasa System.Marshall. Această metodă returnează valoarea numărului de referință al obiectului COM după ce este redus. În acest exemplu, aplicația Word este încărcată, valoarea numărului de referință este decrementată și apoi modulul RCW este eliberat:

Pentru a gestiona cazurile în care valoarea returnată de ReleaseComObject, mai mare decât zero, este posibil de a apela o metodă într-un ciclu care va provoca ReleaseComObject obiect, atâta timp cât valoarea returnată nu este egal cu zero:

Utilizarea metodei ReleaseComObject eliberează obiectul COM, în timp ce alte obiecte depind încă de acesta. După aceea, o încercare de a lucra cu modulul RCW de aplicatii .NET conduce la excluderea System.Runtime.InteropServices.InvalidComObjectException informații suplimentare «obiect COM care a fost separat de RCW său de bază nu poate fi utilizată» ( «COM-obiect, care este deconectat de la RCW , nu-l poți folosi "). Astfel, trebuie să știți exact când aplicația închide obiectul, astfel încât contorul să poată fi redus. O modalitate de a asigura coerența și claritatea este plasarea apelurilor la metoda ReleaseComObject în metoda generală a obiectului finalizer / dispose. Aceasta oferă o corespondență unu-la-unu între implementarea metodei finalizării obiectului .NET și eliberarea obiectului COM corespunzător.

concluzie

Acest articol descrie problemele tipice care apar atunci când se dezvoltă programele .NET Framework care funcționează cu obiecte COM și oferă recomandări cu privire la modul de modificare a soluției software pentru rezolvarea acestor probleme. Este de dorit în special să se evite conectarea obiectului COM din domeniul de aplicare înainte de distrugerea obiectului COM. Adică când aplicația este pregătită să elibereze obiectul COM, trebuie să vă asigurați că obiectul COM este șters din memorie. Dintre cele două mecanisme descrise, clasa AppDomain este cel mai simplu mecanism pentru gestionarea ciclurilor de viață ale unui obiect COM și utilizarea metodei ReleaseComObject oferă o performanță mai bună.

Peter Vogel (Master of Business, Certified Developer of Microsoft) - Șeful serviciilor de informații PHV. PHV este specializată în dezvoltare cu .NET și XML. Peter a proiectat, creat și instalat intraneturi și sisteme componente pentru Bayer AG, Exxon, Christie Digital și Banca Canadiană a băncii comerciale canadiene imperiale.







Trimiteți-le prietenilor: