Sdílet prostřednictvím


Řešení potíží s interoperabilitou (Visual Basic)

Při spolupráci mezi objektem COM a spravovaným kódem rozhraní .NET Framework můžete narazit na jeden nebo více z následujících běžných problémů.

Zařazování spolupráce

Někdy může být nutné použít datové typy, které nejsou součástí rozhraní .NET Framework. Sestavení interoperability zpracovávají většinu práce pro objekty COM, ale možná budete muset řídit datové typy, které se používají, když jsou spravované objekty vystaveny modelu COM. Například struktury v knihovnách tříd musí určovat BStr nespravovaný typ v řetězcích odesílaných do objektů COM vytvořených v jazyce Visual Basic 6.0 a starších verzích. V takových případech můžete atribut použít MarshalAsAttribute k tomu, aby se spravované typy zveřejnily jako nespravované typy.

Export Fixed-Length řetězců do nespravovaného kódu

V jazyce Visual Basic 6.0 a starších verzích jsou řetězce exportovány do objektů COM jako sekvence bajtů bez znaku ukončení null. Z důvodu kompatibility s jinými jazyky obsahuje Visual Basic .NET při exportu řetězců znak ukončení. Nejlepším způsobem, jak tuto nekompatibilitu vyřešit, je exportovat řetězce, které nemají znak ukončení, jako pole nebo ByteChar.

Export hierarchií dědičnosti

Hierarchie spravovaných tříd se při zveřejnění jako objekty modelu COM zploštěnou. Pokud například definujete základní třídu se členem a potom zdědíte základní třídu v odvozené třídě, která je vystavena jako objekt MODELU COM, klienti, kteří používají odvozenou třídu v objektu COM, nebudou moci zděděné členy používat. Ke členům základní třídy lze přistupovat z objektů MODELU COM pouze jako instance základní třídy a poté pouze v případě, že základní třída je také vytvořena jako objekt modelu COM.

Přetížené metody

I když můžete vytvořit přetížené metody pomocí jazyka Visual Basic, nejsou podporovány com. Když je třída, která obsahuje přetížené metody, vystavena jako objekt COM, jsou pro přetížené metody generovány nové názvy metod.

Představte si například třídu, která má dvě přetížení Synch metody . Když je třída vystavena jako objekt COM, nové vygenerované názvy metod mohou být Synch a Synch_2.

Přejmenování může uživatelům objektu COM způsobit dva problémy.

  1. Klienti nemusí očekávat názvy vygenerovaných metod.

  2. Vygenerované názvy metod ve třídě vystavené jako objekt COM se mohou změnit při přidání nových přetížení do třídy nebo její základní třídy. To může způsobit problémy se správou verzí.

Chcete-li vyřešit oba problémy, při vývoji objektů, které budou vystaveny jako objekty COM, místo použití přetížení dejte každé metodě jedinečný název.

Použití objektů COM prostřednictvím sestavení vzájemné spolupráce

Používáte sestavení zprostředkovatele komunikace téměř jako by se jedná o nahrazení spravovaného kódu pro objekty COM, které představují. Vzhledem k tomu, že se jedná o obálky a nikoli skutečné objekty MODELU COM, existují určité rozdíly mezi používáním sestavení vzájemné spolupráce a standardních sestavení. Mezi tyto oblasti rozdílu patří expozice tříd a datových typů pro parametry a návratové hodnoty.

Třídy vystavené jako rozhraní i třídy

Na rozdíl od tříd ve standardních sestaveních jsou třídy modelu COM vystaveny v sestaveních vzájemné spolupráce jako rozhraní i třída, která představuje třídu modelu COM. Název rozhraní je stejný jako název třídy COM. Název třídy zprostředkovatele komunikace je stejný jako název původní třídy modelu COM, ale s připojeným slovem "Třída". Předpokládejme například, že máte projekt s odkazem na sestavení zprostředkovatele komunikace pro objekt COM. Pokud má třída modelu COM název MyComClass, IntelliSense a Prohlížeč objektů zobrazí rozhraní s názvem MyComClass a třídu s názvem MyComClassClass.

Vytváření instancí třídy rozhraní .NET Framework

Obecně lze vytvořit instanci třídy rozhraní .NET Framework pomocí New příkazu s názvem třídy. Třída modelu COM reprezentovaná sestavením zprostředkovatele komunikace je jedním z případů, ve kterém můžete použít New příkaz s rozhraním. Pokud nepoužíváte třídu COM s příkazem Inherits , můžete rozhraní použít stejně jako třídu . Následující kód ukazuje, jak vytvořit Command objekt v projektu, který má odkaz na objekt COM knihovny Microsoft ActiveX Data Objects 2.8:

Dim cmd As New ADODB.Command

Pokud však používáte třídu modelu COM jako základ pro odvozenou třídu, musíte použít třídu zprostředkovatele komunikace, která představuje třídu modelu COM, jako v následujícím kódu:

Class DerivedCommand
    Inherits ADODB.CommandClass
End Class

Poznámka

Sestavení interoperability implicitně implementují rozhraní, která představují třídy modelu COM. Neměli byste se pokoušet použít Implements příkaz k implementaci těchto rozhraní, jinak dojde k chybě.

Datové typy pro parametry a návratové hodnoty

Na rozdíl od členů standardních sestavení mohou mít členové sestavení zprostředkovatele komunikace datové typy, které se liší od typů použitých v původní deklaraci objektu. Přestože sestavení zprostředkovatele interoperability implicitně převádí typy modelu COM na kompatibilní typy modulu runtime společného jazyka, měli byste věnovat pozornost datovým typům, které jsou používány oběma stranami, aby se zabránilo chybám modulu runtime. Například v objektech COM vytvořených v jazyce Visual Basic 6.0 a starších verzích hodnoty typu Integer předpokládají ekvivalentní typ rozhraní .NET Framework, Short. Doporučujeme použít Prohlížeč objektů k prozkoumání vlastností importovaných členů, než je použijete.

Metody MODELU COM na úrovni modulu

Většina objektů COM se používá vytvořením instance třídy MODELU COM pomocí klíčového New slova a poté voláním metod objektu. Jedna výjimka z tohoto pravidla zahrnuje objekty COM, které obsahují AppObj třídy com nebo GlobalMultiUse . Tyto třídy se podobají metodám na úrovni modulu ve třídách Visual Basic .NET. Visual Basic 6.0 a starší verze implicitně vytvářejí instance takových objektů pro vás při prvním volání jedné z jejich metod. Například v jazyce Visual Basic 6.0 můžete přidat odkaz na knihovnu objektů Microsoft DAO 3.6 a volat metodu DBEngine bez vytvoření instance:

Dim db As DAO.Database  
' Open the database.  
Set db = DBEngine.OpenDatabase("C:\nwind.mdb")  
' Use the database object.  

Visual Basic .NET vyžaduje, abyste před použitím jejich metod vždy vytvořili instance objektů COM. Chcete-li použít tyto metody v jazyce Visual Basic, deklarujte proměnnou požadované třídy a pomocí nového klíčového slova přiřaďte objekt proměnné objektu. Klíčové Shared slovo lze použít, pokud chcete zajistit, aby byla vytvořena pouze jedna instance třídy.

' Class level variable.
Shared DBEngine As New DAO.DBEngine

Sub DAOOpenRecordset()
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim fld As DAO.Field
    ' Open the database.
    db = DBEngine.OpenDatabase("C:\nwind.mdb")

    ' Open the Recordset.
    rst = db.OpenRecordset(
        "SELECT * FROM Customers WHERE Region = 'WA'",
        DAO.RecordsetTypeEnum.dbOpenForwardOnly,
        DAO.RecordsetOptionEnum.dbReadOnly)
    ' Print the values for the fields in the debug window.
    For Each fld In rst.Fields
        Debug.WriteLine(fld.Value.ToString & ";")
    Next
    Debug.WriteLine("")
    ' Close the Recordset.
    rst.Close()
End Sub

Neošetřené chyby v obslužných rutinách událostí

Jedním z běžných problémů interoperability jsou chyby v obslužných rutinách událostí, které zpracovávají události vyvolané objekty MODELU COM. Tyto chyby se ignorují, pokud konkrétně nekontrolujete chyby pomocí On Error příkazů nebo Try...Catch...Finally . Například následující příklad pochází z projektu Visual Basic .NET, který obsahuje odkaz na objekt COM knihovny Microsoft ActiveX Data Objects 2.8.

' To use this example, add a reference to the 
'     Microsoft ActiveX Data Objects 2.8 Library  
' from the COM tab of the project references page.
Dim WithEvents cn As New ADODB.Connection
Sub ADODBConnect()
    cn.ConnectionString =
    "Provider=Microsoft.Jet.OLEDB.4.0;" &
    "Data Source=C:\NWIND.MDB"
    cn.Open()
    MsgBox(cn.ConnectionString)
End Sub

Private Sub Form1_Load(ByVal sender As System.Object,
    ByVal e As System.EventArgs) Handles MyBase.Load

    ADODBConnect()
End Sub

Private Sub cn_ConnectComplete(
    ByVal pError As ADODB.Error,
    ByRef adStatus As ADODB.EventStatusEnum,
    ByVal pConnection As ADODB.Connection) Handles cn.ConnectComplete

    '  This is the event handler for the cn_ConnectComplete event raised 
    '  by the ADODB.Connection object when a database is opened.
    Dim x As Integer = 6
    Dim y As Integer = 0
    Try
        x = CInt(x / y) ' Attempt to divide by zero.
        ' This procedure would fail silently without exception handling.
    Catch ex As Exception
        MsgBox("There was an error: " & ex.Message)
    End Try
End Sub

Tento příklad vyvolá podle očekávání chybu. Pokud ale zkusíte stejný příklad bez Try...Catch...Finally bloku, bude chyba ignorována, jako kdybyste použili OnError Resume Next příkaz . Bez zpracování chyb dělení nulou bezobslužně selže. Vzhledem k tomu, že tyto chyby nikdy nevyvolá neošetřené výjimky chyby, je důležité použít nějakou formu zpracování výjimek v obslužných rutinách událostí, které zpracovávají události z objektů COM.

Vysvětlení chyb zprostředkovatele komunikace COM

Bez zpracování chyb volání zprostředkovatele komunikace často generují chyby, které poskytují málo informací. Kdykoli je to možné, použijte strukturované zpracování chyb a poskytněte více informací o problémech, když k nim dojde. To může být zvlášť užitečné při ladění aplikací. Příklad:

Try
    ' Place call to COM object here.
Catch ex As Exception
    ' Display information about the failed call.
End Try

Informace, jako je popis chyby, HRESULT a zdroj chyb MODELU COM, můžete najít prozkoumáním obsahu objektu výjimky.

Problémy s ovládacími prvky ActiveX

Většina ovládacích prvků ActiveX, které pracují s jazykem Visual Basic 6.0, funguje bez problémů s jazykem Visual Basic .NET. Hlavními výjimkami jsou kontejnerové ovládací prvky nebo ovládací prvky, které vizuálně obsahují jiné ovládací prvky. Tady je několik příkladů starších ovládacích prvků, které se sadou Visual Studio nefungují správně:

  • Microsoft Forms 2.0 Frame control

  • Up-Down ovládací prvek, označovaný také jako číselník

  • Ovládací prvek Sheridan Tab

Pro nepodporované problémy s ovládacími prvky ActiveX existuje pouze několik alternativních řešení. Pokud vlastníte původní zdrojový kód, můžete do sady Visual Studio migrovat existující ovládací prvky. V opačném případě můžete u dodavatelů softwaru vyhledat aktualizované . Verze ovládacích prvků kompatibilních s platformou NET, které nahradí nepodporované ovládací prvky ActiveX.

Předávání vlastností ReadOnly ovládacích prvků ByRef

Visual Basic .NET někdy vyvolá chyby modelu COM, například "Error 0x800A017F CTL_E_SETNOTSUPPORTED", když předáte ReadOnly vlastnosti některých starších ovládacích prvků ActiveX jako ByRef parametry do jiných procedur. Volání podobné procedury z Visual Basic 6.0 nevolají chybu a parametry jsou zpracovávány, jako kdybyste je předali podle hodnoty. Chybová zpráva jazyka Visual Basic .NET označuje, že se pokoušíte změnit vlastnost, která nemá proceduru vlastnosti Set .

Pokud máte přístup k volané proceduře, můžete této chybě zabránit použitím klíčového ByVal slova k deklaraci parametrů, které přijímají ReadOnly vlastnosti. Příklad:

Sub ProcessParams(ByVal c As Object)
    'Use the arguments here.
End Sub

Pokud nemáte přístup ke zdrojovému kódu volané procedury, můžete vynutit předání vlastnosti hodnotou přidáním další sady hranatých závorek kolem volající procedury. Například v projektu, který obsahuje odkaz na objekt COM knihovny Microsoft ActiveX Data Objects 2.8, můžete použít:

Sub PassByVal(ByVal pError As ADODB.Error)
    ' The extra set of parentheses around the arguments
    ' forces them to be passed by value.
    ProcessParams((pError.Description))
End Sub

Nasazení sestavení, která zpřístupňují interoperabilitu

Nasazení sestavení, která zpřístupňují rozhraní MODELU COM, představuje několik jedinečných výzev. Například k potenciálnímu problému dochází, když samostatné aplikace odkazují na stejné sestavení MODELU COM. Tato situace je běžná, když je nainstalována nová verze sestavení a jiná aplikace stále používá starou verzi sestavení. Odinstalujete-li sestavení, které sdílí knihovnu DLL, můžete jej neúmyslně znepřístupnit ostatním sestavením.

Chcete-li se vyhnout tomuto problému, měli byste nainstalovat sdílená sestavení do globální mezipaměti sestavení (GAC) a použít MergeModule pro komponentu. Pokud aplikaci nemůžete nainstalovat v GAC, měla by být nainstalována do CommonFilesFolder v podadresáři specifické pro verzi.

Sestavení, která nejsou sdílena, by měla být umístěna vedle sebe v adresáři s volající aplikací.

Viz také