Component Object Model (Component Object Model, COM) a fost conceput cu scopul de a oferi o oportunitate de a crea componente în orice limbă / platformă care oferă suport pentru acest model, și să le utilizeze în orice limbă / platformă (altele), ca are suport pentru COM. .NET Framework nu este o excepție și îl face ușor de utilizat terți COM-obiecte și de export tipurile .NET sub forma COM-obiecte.
Esența organizării interacțiunilor folosind COM-obiecte este aceeași ca atunci când se utilizează mecanismul de P / Invoke: declarați reprezentarea driven-COM a obiectului, și de a efectua CLR creează un înveliș obiect care implementează triajul. Există două tipuri de ambalaje: înveliș, numit de rulare (Runtime nevărsată Wrapper, RCW). care permite rularea de cod a reușit să utilizeze COM-obiecte:

și un înveliș, numit COM-obiecte (COM nevărsată Wrapper, antiorar). care permit apeluri COM-obiect cod gestionat:

terță parte COM-obiecte sunt adesea prevăzute cu principalele interacțiuni de asamblare (Interop asamblare primar, PIA). cuprinzând determinarea, de către producător semnat și stabilește cache-ul de asamblare la nivel mondial (Global Adunarea Cache, CAG). În caz contrar, puteți utiliza instrumentul tlbimp.exe. Face parte din Windows SDK-ul, care generează automat un ansamblu de Interop, pe baza informațiilor conținute în biblioteca de tip.
Atunci când interacțiunile folosind COM-obiecte reutilizat de infrastructură marshaling parametri P / mecanism Invoke, dar cu alte valori implicite (de exemplu, linia implicită este transformată într-o BSTR), astfel încât toate sfaturile pe care a fost dat într-un articol anterior privind P / Invoca mecanism se aplică, de asemenea, și aici.
Modelul COM are propriile probleme de performanță, datorită trăsăturile caracteristice ale COM, cum ar fi unitățile de multi-threaded model și inconsecvență între natură COM, pe baza de numărare de referință, și modelul de colectare a gunoiului în .NET.
managementul ciclului de viață
Ia-o referință la COM-obiect în .NET, sunt obtinerea de fapt o referință la un obiect RCW înveliș. Wrapper RCW întotdeauna stochează doar o referință la obiectul COM, iar pentru fiecare, este creat obiectul COM, doar o singură instanță a unui obiect RCW înveliș. Wrapper RCW menține propria numărului de referință care nu este asociat cu un contor-referință obiect COM. Valoarea acestui număr de referință este, în general 1, dar poate fi mai mare atunci când participă la marshaling număr mai mare de interfețe sau atunci când una și aceeași interfață accesează mai multe fire de execuție.
Deoarece colector de gunoi .NET pentru a rula în momente imprevizibile și nu este conștient de blocuri de memorie negestionate alocate pentru a crea ambalaje pentru RCW COM-obiecte, nu se poate accelera de colectare a gunoiului, astfel încât cantitatea de memorie poate fi foarte mare.
Opțional determina metoda Marshal.ReleaseComObject (). pentru a elibera în mod explicit obiectul. Fiecare apel reduce numărul de referință în RCW și atunci când ajunge la zero, numărul de referință este redusă automat la COM-obiect corespunzător (la fel ca un apel fiializatora RCW). După apelarea Marshal.ReleaseComObject (), metoda nu poate fi utilizat pentru înfășurare RCW.
Dacă referința contra RCW apelului poate fi mai mare decât zero, Marshal.ReleaseComObject () metoda care trebuie invocată într-o buclă până când se returnează o valoare nulă. Cel mai bine este de a apela Marshal.ReleaseComObject () în blocul în cele din urmă pentru a asigura eliberarea obiectului COM, chiar dacă undeva între crearea unei instanțe și eliberarea unei excepții are loc.
Marshaling peste unitățile de frontieră
Modelul COM pune în aplicare propriile mecanisme de sincronizare de execuție fir pentru susținerea apelurilor între diferitele fluxuri care pot fi utilizate chiar și atunci când se lucrează cu obiecte care nu sunt destinate inițial pentru a fi utilizate într-un mediu multithread. Aceste mecanisme pot reduce performanța aplicării lor necorespunzătoare. Deși această problemă nu este direct legată de interacțiunile folosind COM-obiecte din .NET, cu toate acestea, merită discutată, deoarece este adesea întâlnită în practică, pentru că, probabil, dezvoltatorii care sunt obișnuiți cu metodele tipice de sincronizare în .NET nu poate știu ce se întâmplă exact sub acoperirea COM-obiecte.
Modelul COM leagă performanța de obiecte, și fluxuri de unități (apartamente). angajați limitele prin care modelul COM efectuează apeluri. În total există mai multe tipuri de unități:
Single-unitate (un singur fir Apartament, STA)
Fiecare unitate are un singur fir de executie, dar poate fi orice număr de obiecte. Deși pot exista mai multe departamente STA.
Unitate de Multithreaded (multi-threaded Apartament, MTA)
Fiecare unitate poate fi orice număr de fire și obiecte, dar în acest proces poate fi doar o singură unitate de MTA. Acest tip este utilizat în .NET implicit.
Unități Potokonezavisimye (Neutru filet Apartament, NTA)
Conțin obiecte, dar nu curge. Procesul poate fi doar o singură unitate de NTA.
Legare pentru a efectua diviziunea are loc atunci când fluxul de apel CoInitialize sau CoInitializeEx pentru a inițializa COM-obiect în acest flux. Funcția CoInitialize asociază un flux cu o noua divizie a STA, iar funcția CoInitializeEx vă permite să specificați tipul de unitate, STA sau MTA.
În .NET, nu trebuie să apeleze direct aceste funcții, în schimb, este suficient pentru a adăuga un atribut sau STAThread MTAThread la punctul de intrare în fluxul (metoda principală). De asemenea, puteți provoca Thread.SetApartmentState metoda (), fie prin valoarea proprietății stabilită Thread.ApartmentState înainte de a începe executarea unui fir, dacă se dorește. Cu excepția cazului în care se prevede altfel. NET inițializează firele (inclusiv firul principal al aplicației) ca aparținând unității AIT.
Legarea COM-obiecte se realizează cu unități, pornind de la parametrul ThreadingModel în registru, care poate avea următoarele valori:
Single - element implicit este plasat în divizia STA.
Apartament - obiect trebuie să fie plasat la orice unitate STA, și să curgă numai din această unitate va fi permis să invoce în mod direct obiectul. Alte elemente pot fi plasate în alte unități STA.
Free - articolul este plasat în Divizia MTA. Acest obiect poate fi utilizat în mod direct și simultan din orice număr de fluxuri de unități în AIT. Obiectivul este de a oferi sprijin pentru utilizare într-un mediu multithread.
Ambele - obiectul este plasat într-o divizie care a creat programul său (STA sau MTA). De fapt, după ce creați devine obiect sau AIT-stabiliza- asemănător.
Neutru - un obiect plasat în unitatea potokonezavisimoe și nu necesită marshaling. Aceasta este - cel mai eficient mod.
Figura de mai jos prezintă o diagramă a raportului dintre unități, fluxuri și obiecte:

Când încercați să creați un model de obiect pentru a sprijini fluxuri, este incompatibil cu modelul de curgere în această unitate, veți primi un pointer la interfața care indică de fapt, la proxy. Dacă aveți nevoie pentru a trece obiectul COM-interfață la un alt fir de care aparține o altă unitate, un pointer la interfața care urmează să fie transmise nu direct, ci prin mecanismul marshaling. Infrastructura COM returnează obiectul proxy corespunzător.
În procesul de marshaling funcția de apel (inclusiv parametri) este convertit într-un mesaj care va fi trimis tuturor unităților de STA primire. Pentru STA obiecte de toate este implementat ca o fereastră ascunsă, procedura de fereastră care primește mesaje și transmite COM-obiect cu ciot (stub). Cu această abordare, COM-obiecte în divizia STA COM este întotdeauna invocată în același fir de execuție, care asigură siguranța atunci când se lucrează într-un mediu multithread.
În cazul în care unitatea de asteptare nu este compatibil cu unitatea de COM-obiect, fluxul este pornit și executat parametru între fire marshaled.
Pentru a evita degradarea performanței datorită marshaling între fire să încerce să asigure coerența între unitatea diviziunea COM-obiect și generarea fluxului său. Crearea și utilizarea obiectelor-STA COM STA în fluxurile unităților și obiectelor COM din divizia MTA - în fluxurile AIT. COM-obiecte marcate ca sprijinind ambele tipuri de unități pot fi utilizate în mod liber de către oricare dintre firele din fără nici aeriene suplimentare.
Apel obiecte STA din ASP.NET
În mod implicit, ASP.NET de execuție efectuează pagina fluxuri MTA. În cazul în care aceste pagini sunt numite obiecte în unitățile de STA, vine în mecanismul marshaling. În cazul în care cea mai mare parte a obiectelor folosite STA apartine diviziuni, acest lucru va avea ca rezultat degradarea performanței. Această problemă poate fi eliminată prin verificarea atributului pagina AspCompat. așa cum se arată mai jos:
Vă rugăm să rețineți că designerii de pagini continuă să fie difuzate în firul MTA de execuție, astfel încât crearea de obiecte STA ar trebui să fie efectuată în tratare a evenimentelor Page_Load și Page_Init.
Importul bibliotecilor de tip, și codul de acces de securitate
Mecanismul de cod de acces de securitate efectuează aceleași verificări de securitate ca P / Invoke. Puteți adăuga cheie / nesigure atunci când se solicită tlbimp.exe de utilitate, care se va adăuga atribut SuppressUnmanagedCodeSecurityAttribute la tipurile generate. Utilizați această caracteristică numai sistemelor care utilizează încredere absolută, deoarece poate da naștere la probleme de siguranță.
Înainte de versiunea de lansare a Framework 4.0 vine cu aplicația sau distribui ansambluri Interop Interop de asamblare primare (Primary Interop adunări, PIA). Aceste ansambluri de obicei, devine foarte mare (chiar și în comparație cu codul pe care le folosește) și, în general, nu sunt incluse în kit-ul de instalare COM-componente; în schimb, acestea trebuie să fie instalate separat, pentru că ei înșiși nu sunt necesare pentru operarea ei înșiși COM-obiecte. Un alt motiv pentru care ansamblurile PIA nu sunt incluse în setul de instalare este că acestea sunt instalate în cache-ul de asamblare la nivel mondial (CAG). Aceasta introduce o dependență .NET Framework într-un alt mod complet aplicatii independente.
Începând cu versiunea .NET Framework 4.0, compilatoare C # si VB.NET poate verifica ce COM-interfețele și metodele utilizate în cod, și copiați și încorporați ansamblul de asteptare este de numai definiții cu adevărat necesare, reducând dimensiunea codului și eliminând necesitatea de a distribui PIA bibliotecii. La Microsoft, această caracteristică a fost numit NoPIA. Acesta acționează atât în ceea ce privește PIA, și în ceea ce privește ansamblurile Interop, în general.
Ansambluri PIA au o caracteristică importantă, care se numește tipuri de echivalență. Din moment ce acestea au o denumire strict și plasate în ansamblurile de cache la nivel mondial, diverse componente pot fi controlate social și înfășoară termeni RCW Nete ei vor avea tipuri echivalente. În contrast, ansamblul Interop generate cu tlbimp.exe, nu au această caracteristică, pentru că fiecare componentă în acest caz, va primi propria sa, separat de alții, un ansamblu Interop. Odată cu apariția de caracteristici de sprijin NoPIA eliminat necesitatea unei ansambluri stricte de denumire și Microsoft au propus o soluție care vă permite să interpreteze RCW înveliș din alte ansambluri, ca aparținând aceluiași tip, în cazul în care interfețele au aceeași GUID.
Pentru a activa NOPIA, selectați Proprietăți din meniul contextual Visual Studio atunci când faceți clic-dreapta pe ansamblul Interop în secțiunea Referințe și setați tipurile Embed Interop (Pentru a introduce tipuri de interacțiuni) la valoarea True:

excepții
Cele mai multe metode de COM-interfețe raportează succesul sau eșecul returnând o valoare de tip HRESULT. Valorile negative HRESULT (cu setul ridicat de biți) raportează o eroare, și un zero (S_OK) sau valori pozitive - despre succesul. În plus, COM-obiect poate returna informații suplimentare de eroare în funcția de apel SetErrorInfo, care trece IErrorInfo obiect creat prin apelarea CreateErrorInfo.
Cand numita COM-metoda prin mecanismul interacțiunilor cu COM, marshaller ciot convertește valoarea HRESULT controlată de excludere, în funcție de cea mai mare valoare HRESULT și a datelor cuprinse în obiectul IErrorInfo. Deoarece excitația este o excepție, mai degrabă operație costisitoare, funcția COM-obiect, care nu de multe ori, pot afecta negativ performanța. Puteți suprima conversia automată a excepțiilor, metode de marcare atribut PreserveSigAttribute. În acest caz, va trebui să modificați semnătura gestionate ca o valoare returnată de tip int, cu privire la rezultatul care va fi de stabilire a parametrului retval.