Megosztás:


Objektumok alapértelmezett rendezése

A nem felügyelt kód számára elérhető paraméterek és mezők a következő típusok egyikeként vannak begépelve System.Object :

  • Egy variáns, ha az objektum paraméter.

  • Felület, ha az objektum egy struktúramező.

Csak a COM-interop támogatja az objektumtípusok rendezését. Az alapértelmezett viselkedés az objektumok COM-variánsokra való beállítása. Ezek a szabályok csak a típusra Object vonatkoznak, és nem vonatkoznak az Object osztályból származó, erősen gépelt objektumokra.

Rendezési beállítások

Az alábbi táblázat a Object adattípus csoportosítási lehetőségeit mutatja be. Az MarshalAsAttribute attribútum számos UnmanagedType enumerálási értéket biztosít a marsall objektumok számára.

Számbavétel típusa A nem felügyelt formátum leírása
UnmanagedType.Struct

(a paraméterek alapértelmezett beállítása)
COM-stílusú változat.
UnmanagedType.Interface Egy IDispatch interfész, ha lehetséges; ellenkező esetben egy IUnknown interfész.
UnmanagedType.IUnknown

(a mezők alapértelmezett beállítása)
Egy IUnknown felület.
UnmanagedType.IDispatch Egy IDispatch felület.

Az alábbi példa a felügyelt felület definícióját mutatja be a következőhöz MarshalObject: .

Interface MarshalObject
   Sub SetVariant(o As Object)
   Sub SetVariantRef(ByRef o As Object)
   Function GetVariant() As Object

   Sub SetIDispatch( <MarshalAs(UnmanagedType.IDispatch)> o As Object)
   Sub SetIDispatchRef(ByRef <MarshalAs(UnmanagedType.IDispatch)> o _
      As Object)
   Function GetIDispatch() As <MarshalAs(UnmanagedType.IDispatch)> Object
   Sub SetIUnknown( <MarshalAs(UnmanagedType.IUnknown)> o As Object)
   Sub SetIUnknownRef(ByRef <MarshalAs(UnmanagedType.IUnknown)> o _
      As Object)
   Function GetIUnknown() As <MarshalAs(UnmanagedType.IUnknown)> Object
End Interface
interface MarshalObject {
   void SetVariant(Object o);
   void SetVariantRef(ref Object o);
   Object GetVariant();

   void SetIDispatch ([MarshalAs(UnmanagedType.IDispatch)]Object o);
   void SetIDispatchRef([MarshalAs(UnmanagedType.IDispatch)]ref Object o);
   [MarshalAs(UnmanagedType.IDispatch)] Object GetIDispatch();
   void SetIUnknown ([MarshalAs(UnmanagedType.IUnknown)]Object o);
   void SetIUnknownRef([MarshalAs(UnmanagedType.IUnknown)]ref Object o);
   [MarshalAs(UnmanagedType.IUnknown)] Object GetIUnknown();
}

Az alábbi kód egy típustárba exportálja a MarshalObject felületet.

interface MarshalObject {
   HRESULT SetVariant([in] VARIANT o);
   HRESULT SetVariantRef([in,out] VARIANT *o);
   HRESULT GetVariant([out,retval] VARIANT *o)
   HRESULT SetIDispatch([in] IDispatch *o);
   HRESULT SetIDispatchRef([in,out] IDispatch **o);
   HRESULT GetIDispatch([out,retval] IDispatch **o)
   HRESULT SetIUnknown([in] IUnknown *o);
   HRESULT SetIUnknownRef([in,out] IUnknown **o);
   HRESULT GetIUnknown([out,retval] IUnknown **o)
}

Feljegyzés

Az interop marshaller automatikusan felszabadít minden lefoglalt objektumot a változaton belül a hívás után.

Az alábbi példa egy formázott értéktípust mutat be.

Public Structure ObjectHolder
   Dim o1 As Object
   <MarshalAs(UnmanagedType.IDispatch)> Public o2 As Object
End Structure
public struct ObjectHolder {
   Object o1;
   [MarshalAs(UnmanagedType.IDispatch)]public Object o2;
}

A következő kód exportálja a formázott típust egy típustárba.

struct ObjectHolder {
   VARIANT o1;
   IDispatch *o2;
}

Objektum és felület rendezése

Ha egy objektumot a COM-nak felületként tesznek ki, akkor ez a felület lesz a felügyelt típus Object osztályfelülete (_Object felület). Ez a felület IDispatch (UnmanagedType) vagy IUnknown (UnmanagedType.IUnknown) típusként van megadva az eredményül kapott típustárban. A COM-ügyfelek dinamikusan meghívhatják a felügyelt osztály tagjait vagy a származtatott osztályok által implementált tagokat az _Object interfészen keresztül. Az ügyfél bármely más, a felügyelt típus által explicit módon implementált felületet is meghívhat QueryInterface .

Objektum rendezése Variant-ra

Ha egy objektumot egy változathoz rendeznek, a belső változattípus futásidőben lesz meghatározva a következő szabályok alapján:

  • Ha az objektumhivatkozás null (a Visual Basicben semmi), az objektum egy VT_EMPTY típusú változatra lesz rendezve.

  • Ha az objektum az alábbi táblázatban felsorolt bármilyen típusú példány, az eredményül kapott változattípust a rendezőbe beépített és a táblázatban látható szabályok határozzák meg.

  • Más objektumok, amelyeknek explicit módon kell szabályozni a rendezési viselkedést, implementálhatják az interfészt IConvertible . Ebben az esetben a variáns típusát a metódusból IConvertible.GetTypeCode visszaadott típuskód határozza meg. Ellenkező esetben az objektum VT_UNKNOWN típusú változatként van rendezve.

Rendszertípusok rendezése Variant-ra

Az alábbi táblázat a felügyelt objektumtípusokat és a hozzájuk tartozó COM-változattípusokat mutatja be. Ezek a típusok csak akkor lesznek konvertálva, ha a meghívott metódus aláírása típus System.Object.

Objektumtípus COM-változat típusa
Null objektumhivatkozás (a Visual Basicben semmi). VT_EMPTY
System.DBNull VT_NULL
System.Runtime.InteropServices.ErrorWrapper VT_ERROR
System.Reflection.Missing VT_ERROR E_PARAMNOTFOUND
System.Runtime.InteropServices.DispatchWrapper VT_DISPATCH
System.Runtime.InteropServices.UnknownWrapper VT_UNKNOWN
System.Runtime.InteropServices.CurrencyWrapper VT_CY
System.Boolean VT_BOOL
System.SByte VT_I1
System.Byte VT_UI1
System.Int16 VT_I2
System.UInt16 VT_UI2
System.Int32 VT_I4
System.UInt32 VT_UI4
System.Int64 VT_I8
System.UInt64 VT_UI8
System.Single VT_R4
System.Double VT_R8
System.Decimal VT_DECIMAL
System.DateTime VT_DATE
System.String VT_BSTR
System.IntPtr VT_INT
System.UIntPtr VT_UINT
System.Array VT_ARRAY

MarshalObject Az előző példában definiált felület használatával az alábbi kódpéldából megtudhatja, hogyan adhat át különböző típusú változatokat egy COM-kiszolgálónak.

Dim mo As New MarshalObject()
mo.SetVariant(Nothing)         ' Marshal as variant of type VT_EMPTY.
mo.SetVariant(System.DBNull.Value) ' Marshal as variant of type VT_NULL.
mo.SetVariant(CInt(27))        ' Marshal as variant of type VT_I2.
mo.SetVariant(CLng(27))        ' Marshal as variant of type VT_I4.
mo.SetVariant(CSng(27.0))      ' Marshal as variant of type VT_R4.
mo.SetVariant(CDbl(27.0))      ' Marshal as variant of type VT_R8.
MarshalObject mo = new MarshalObject();
mo.SetVariant(null);            // Marshal as variant of type VT_EMPTY.
mo.SetVariant(System.DBNull.Value); // Marshal as variant of type VT_NULL.
mo.SetVariant((int)27);          // Marshal as variant of type VT_I2.
mo.SetVariant((long)27);          // Marshal as variant of type VT_I4.
mo.SetVariant((single)27.0);   // Marshal as variant of type VT_R4.
mo.SetVariant((double)27.0);   // Marshal as variant of type VT_R8.

Azok a COM-típusok, amelyek nem rendelkeznek megfelelő felügyelt típusokkal, burkolóosztályokkal, például ErrorWrapper, DispatchWrapper, UnknownWrapperés CurrencyWrapper. Az alábbi példakód bemutatja, hogyan használhatja ezeket a burkolókat különböző típusú változatok com-kiszolgálónak való átadására.

Imports System.Runtime.InteropServices
' Pass inew as a variant of type VT_UNKNOWN interface.
mo.SetVariant(New UnknownWrapper(inew))
' Pass inew as a variant of type VT_DISPATCH interface.
mo.SetVariant(New DispatchWrapper(inew))
' Pass a value as a variant of type VT_ERROR interface.
mo.SetVariant(New ErrorWrapper(&H80054002))
' Pass a value as a variant of type VT_CURRENCY interface.
mo.SetVariant(New CurrencyWrapper(New Decimal(5.25)))
using System.Runtime.InteropServices;
// Pass inew as a variant of type VT_UNKNOWN interface.
mo.SetVariant(new UnknownWrapper(inew));
// Pass inew as a variant of type VT_DISPATCH interface.
mo.SetVariant(new DispatchWrapper(inew));
// Pass a value as a variant of type VT_ERROR interface.
mo.SetVariant(new ErrorWrapper(0x80054002));
// Pass a value as a variant of type VT_CURRENCY interface.
mo.SetVariant(new CurrencyWrapper(new Decimal(5.25)));

A burkolóosztályok a System.Runtime.InteropServices névtérben vannak definiálva.

Az IConvertible interfész a Variant-hoz való rendezése

Az előző szakaszban felsoroltaktól eltérő típusok a felület implementálásával szabályozhatják a IConvertible rendezés módját. Ha az objektum megvalósítja az IConvertible interfészt, a COM-változat típusát futásidőben határozza meg a TypeCode metódusból IConvertible.GetTypeCode visszaadott számbavétel értéke.

Az alábbi táblázat az enumerálás lehetséges értékeit TypeCode és az egyes értékekhez tartozó COM-variánstípust mutatja be.

TypeCode COM-változat típusa
TypeCode.Empty VT_EMPTY
TypeCode.Object VT_UNKNOWN
TypeCode.DBNull VT_NULL
TypeCode.Boolean VT_BOOL
TypeCode.Char VT_UI2
TypeCode.Sbyte VT_I1
TypeCode.Byte VT_UI1
TypeCode.Int16 VT_I2
TypeCode.UInt16 VT_UI2
TypeCode.Int32 VT_I4
TypeCode.UInt32 VT_UI4
TypeCode.Int64 VT_I8
TypeCode.UInt64 VT_UI8
TypeCode.Single VT_R4
TypeCode.Double VT_R8
TypeCode.Decimális VT_DECIMAL
TypeCode.DateTime VT_DATE
TypeCode.String VT_BSTR
Nem támogatott. VT_INT
Nem támogatott. VT_UINT
Nem támogatott. VT_ARRAY
Nem támogatott. VT_RECORD
Nem támogatott. VT_CY
Nem támogatott. VT_VARIANT

A COM-variáns értékét a IConvertible.ToType felület meghívásával határozzuk meg, ahol To a Típus az IConvertible.GetTypeCode-ból visszaadott típusnak megfelelő konverziós rutin. Például az IConvertible.GetTypeCode-ból typeCode.Double értéket visszaadó objektum a VT_R8 típusú COM-változatként van rendezve. A variáns értékét, amely a COM-változat dblVal mezőjében van tárolva, a IConvertible interfészre történő konvertálással és a ToDouble metódus meghívásával kaphatja meg.

Variant objektumba rendezése

Amikor egy variánst objektumhoz rendez, a rendezővariáns típusa és néha értéke határozza meg a létrehozott objektum típusát. Az alábbi táblázat azonosítja az egyes változattípusokat és a megfelelő objektumtípusokat, amelyeket az m marshallerreates ad át a COM-ból a .NET-keretrendszer.

COM-változat típusa Objektumtípus
VT_EMPTY Null objektumhivatkozás (a Visual Basicben semmi).
VT_NULL System.DBNull
VT_DISPATCH System.__ComObject vagy null, ha (pdispVal == null)
VT_UNKNOWN System.__ComObject vagy null ha (punkVal == null)
VT_ERROR System.UInt32
VT_BOOL System.Boolean
VT_I1 System.SByte
VT_UI1 System.Byte
VT_I2 System.Int16
VT_UI2 System.UInt16
VT_I4 System.Int32
VT_UI4 System.UInt32
VT_I8 System.Int64
VT_UI8 System.UInt64
VT_R4 System.Single
VT_R8 System.Double
VT_DECIMAL System.Decimal
VT_DATE System.DateTime
VT_BSTR System.String
VT_INT System.Int32
VT_UINT System.UInt32
| VT_ARRAY VT_* System.Array
VT_CY System.Decimal
VT_RECORD Megfelelő dobozos értéktípus.
VT_VARIANT Nem támogatott.

Előfordulhat, hogy a COM-ból a felügyelt kódba, majd a COM-ba visszakerülő változattípusok a hívás időtartama alatt nem őrzik meg ugyanazt a változattípust. Gondolja át, mi történik, ha a COM-ból a .NET-keretrendszerbe továbbít egy típusvariánst VT_DISPATCH . A rendezés során a rendszer átalakítja a variánst .System.Object Ha a Object ezt követően visszakerül a COM-hoz, akkor egy VT_UNKNOWN típusú változatra lesz átültetve. Nincs garancia arra, hogy az objektum felügyelt kódból COM-ba való beállításakor előállított változat ugyanaz a típus lesz, mint az objektum előállításához eredetileg használt változat.

ByRef-változatok rendezése

Bár maguk a változatok átadhatók érték vagy hivatkozás alapján, a VT_BYREF jelölő bármely változattípussal is használható annak jelzésére, hogy a változat tartalmát hivatkozással, nem pedig érték alapján adja át. A változatok referencia alapján történő rendezése és a jelölőkészlettel való VT_BYREF rendezés közötti különbség zavaró lehet. Az alábbi ábra tisztázza a különbségeket:

A veremen átadott variánst ábrázoló diagram. Érték és hivatkozás szerint átadott variánsok

Objektumok és változatok érték szerinti rendezési viselkedése

  • Ha objektumokat ad át a felügyelt kódból a COM-nak, az objektum tartalma a rendező által létrehozott új változatba lesz másolva a Marshalling Object to Variant parancsban meghatározott szabályok használatával. A nem felügyelt oldalon végrehajtott módosításokat a rendszer nem propagálja vissza az eredeti objektumra a hívásból való visszatéréskor.

  • Ha a com-ról felügyelt kódra továbbítja a variánsokat, a rendszer egy újonnan létrehozott objektumba másolja a változat tartalmát a Marshalling Variant objektumba definiált szabályokkal. A felügyelt oldalon az objektum módosításai nem lesznek visszaterjesztve az eredeti változatra a hívásból való visszatéréskor.

Objektumok és változatok beállításának alapértelmezett viselkedése hivatkozás alapján

Ha a módosításokat vissza szeretné propagálja a hívónak, a paramétereket hivatkozással kell átadni. Használhatja például a kulcsszót a ref C# (vagy ByRef a Visual Basic felügyelt kódban) a paraméterek hivatkozással történő átadásához. A COM-ban a referenciaparaméterek egy mutató, például egy *változat használatával lesznek átadva.

  • Amikor egy objektumot hivatkozással ad át a COM-nak, a rendező létrehoz egy új változatot, és a hívás előtt átmásolja az objektumhivatkozás tartalmát a változatba. A variáns a nem felügyelt függvénynek lesz átadva, ahol a felhasználó szabadon módosíthatja a változat tartalmát. A hívásból való visszatéréskor a nem felügyelt oldalon végrehajtott módosításokat a rendszer visszaterjeszti az eredeti objektumra. Ha a változat típusa eltér a hívásnak átadott változat típusától, a rendszer a módosításokat egy másik típusú objektumra propagálja. Vagyis a hívásba átadott objektum típusa eltérhet a hívásból visszaadott objektum típusától.

  • Ha egy változatot referencia alapján ad át a felügyelt kódnak, a rendező létrehoz egy új objektumot, és a hívás előtt átmásolja a változat tartalmát az objektumba. Az objektumra mutató hivatkozást a rendszer átadja a felügyelt függvénynek, ahol a felhasználó szabadon módosíthatja az objektumot. A hívásból való visszatéréskor a hivatkozott objektumon végrehajtott módosítások az eredeti változatra lesznek propagálva. Ha az objektum típusa eltér a hívásnak átadott objektum típusától, az eredeti változat típusa megváltozik, és az érték visszakerül a változatba. A hívásba átadott változat típusa is eltérhet a hívásból visszaadott változat típusától.

A VT_BYREF jelzőkészlettel rendelkező változatok beállításának alapértelmezett viselkedése

  • A felügyelt kódnak érték szerint átadott variánsok VT_BYREF jelölője azt jelezheti, hogy a változat egy érték helyett egy hivatkozást tartalmaz. Ebben az esetben a variáns továbbra is egy objektumhoz van rendezve, mert a variánst érték adja át. A rendező automatikusan elhalasztja a változat tartalmát, és egy újonnan létrehozott objektumba másolja a hívást. Az objektum ezután bekerül a felügyelt függvénybe; azonban a hívásból való visszatéréskor az objektum nem lesz újra propagálva az eredeti változatba. A felügyelt objektum módosításai elvesznek.

    Figyelemfelhívás

    Az érték által átadott változatok értékét nem lehet módosítani, még akkor sem, ha a variáns rendelkezik a VT_BYREF jelölőkészlettel.

  • A felügyelt kódnak hivatkozással átadott változatok VT_BYREF jelölője azt is jelezheti, hogy a változat egy másik hivatkozást tartalmaz. Ha igen, akkor a variáns egy ref objektumhoz lesz rendezve, mert a variánst hivatkozással továbbítja a függvény. A rendező automatikusan elhalasztja a változat tartalmát, és egy újonnan létrehozott objektumba másolja a hívást. A hívásból való visszatéréskor az objektum értékét a rendszer csak akkor propagálja vissza az eredeti változatban lévő hivatkozásra, ha az objektum típusa megegyezik az átadott objektum típusával. Ez azt jelenti, hogy a propagálás nem változtatja meg a jelölőkészlettel rendelkező VT_BYREF változat típusát. Ha az objektum típusa módosul a hívás során, InvalidCastException a hívásból való visszatéréskor történik.

Az alábbi táblázat összefoglalja a variánsok és objektumok propagálási szabályait.

Forrás Művelet A módosítások újraterjesztése
Variantv Objektumo Soha
Objektumo Variantv Soha
Változat*Pv Ref Objecto Mindig
Ref objektumo Változat*Pv Mindig
Vváltozat(VT_BYREF|VT_*) Objektumo Soha
Variantv(VT_BYREF|VT_) Ref Objecto Csak akkor, ha a típus nem változott.

Lásd még