Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Při spolupráci mezi com a spravovaným kódem rozhraní .NET Framework můžete narazit na jeden nebo několik následujících běžných problémů.
Maršálování spolupráce
Někdy možná budete muset použít datové typy, které nejsou součástí rozhraní .NET Framework. Sestavení interoperability zpracovávají většinu práce u objektů COM, ale možná budete muset řídit datové typy, které se používají při zpřístupnění spravovaných objektů pro COM. Například struktury v knihovnách tříd musí určovat BStr nespravovaný typ u řetězců odesílaných do objektů COM vytvořených v jazyce Visual Basic 6.0 a staršími verzemi. V takových případech můžete pomocí atributu MarshalAsAttribute způsobit zveřejnění spravovaných typů jako nespravovaných typů.
Exportování řetězců Fixed-Length 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ší způsob, jak tuto nekompatibilitu vyřešit, je exportovat řetězce, které nemají znak ukončení jako pole Byte nebo Char.
Export hierarchií dědičnosti
Hierarchie spravovaných tříd se zplošťují, když jsou vystaveny jako COM objekty. Pokud například definujete základní třídu s členem a potom základní třídu zdědíte v odvozené třídě, která je vystavena jako COM objekt, klienti, kteří používají odvozenou třídu jako objekt COM, nebudou moci používat zděděné členy. K členům základní třídy lze přistupovat z objektů MODELU COM pouze jako instance základní třídy a pak pouze v případě, že je základní třída vytvořena také jako objekt MODELU COM.
Přetížené metody
I když můžete vytvořit přetížené metody pomocí jazyka Visual Basic, com je nepodporuje. Pokud je třída obsahující přetížené metody vystavena jako objekt COM, jsou generovány nové názvy metod pro přetížené metody.
Představte si například třídu, která má dvě přetížení metody Synch. Když je třída vystavena jako objekt COM, mohou být nové generované názvy metod Synch a Synch_2.
Přejmenování může způsobit dva problémy pro uživatele objektu COM.
Klienti nemusí očekávat vygenerované názvy metod.
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 s verzováním.
Chcete-li vyřešit oba problémy, při vývoji objektů, které budou vystaveny jako objekty COM, dejte každé metodě jedinečný název místo přetížení metod.
Použití objektů COM prostřednictvím sestavení pro interop
Sestavení vzájemné spolupráce se používají téměř jako kdyby se jedná o nahrazení spravovaného kódu pro objekty MODELU COM, které představují. Vzhledem k tomu, že se jedná o obálky a nikoliv skutečné objekty COM, existují určité rozdíly mezi používáním interop sestavení a standardními sestaveními. Mezi tyto oblasti rozdílu patří vystavení tříd a datových typů pro parametry a návratové hodnoty.
Třídy představované jako rozhraní i třídy
Na rozdíl od tříd ve standardních sestaveních jsou třídy COM v interoperačních sestaveních vystaveny jako rozhraní i jako třída, která reprezentuje třídu COM. Název rozhraní je shodný s názvem třídy COM. Název třídy zprostředkovatele komunikace je stejný jako název původní COM třídy, ale se slovem "Třída" připojeným. Předpokládejme například, že máte projekt s odkazem na sestavení pro spolupráci s objektem COM. Pokud je třída COM pojmenována 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ě platí, že vytvoříte instanci třídy rozhraní .NET Framework pomocí příkazu New s názvem třídy. Třída COM reprezentovaná interop assembly je jediným případem, kdy můžete použít příkaz New s rozhraním. Pokud nepoužíváte třídu COM s příkazem Inherits, můžete rozhraní použít stejně jako třída. Následující kód ukazuje, jak vytvořit Command objekt v projektu, který má odkaz na objekt COM knihovny Microsoft ActiveX 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 interop třídy, 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í COM třídy. Neměli byste se pokoušet použít příkaz Implements k implementaci těchto rozhraní nebo dojde k chybě.
Datové typy pro parametry a návratové hodnoty
Na rozdíl od členů standardních sestavení mohou členové interoperabilního sestavení mít datové typy, které se liší od těch použitých v původní deklaraci objektu. Přestože sestavení zprostředkovatele komunikace implicitně převádějí COM typy na kompatibilní typy modulu CLR (Common Language Runtime), měli byste věnovat pozornost datovým typům, které obě strany používají, abyste předešli chybám za běhu. 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. Než je použijete, doporučujeme, abyste pomocí prohlížeče objektů prozkoumali charakteristiky importovaných členů.
Metody COM na úrovni modulu
Většina objektů COM se používá vytvořením instance třídy COM pomocí klíčového slova New a následné volání metod objektu. Jednou z výjimek tohoto pravidla jsou objekty COM, které obsahují AppObj nebo GlobalMultiUse třídy COM. Tyto třídy se podobají metodám na úrovni modulu ve třídách .NET jazyka Visual Basic. Visual Basic 6.0 a starší verze implicitně vytvářejí instance takových objektů 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 prvního 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ů MODELU 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é slovo Shared 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 obsluhách událostí
Jedním z běžných problémů s interoperabilitou jsou chyby v obslužných rutinách událostí, které zpracovávají události vyvolané objekty MODELU COM. Tyto chyby se ignorují, pokud výslovně nekontrolujete chyby pomocí On Error nebo Try...Catch...Finally příkazů. Následující příklad je například z projektu .NET jazyka Visual Basic, který má 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 = "..."
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á chybu podle očekávání. Pokud ale zkusíte stejný příklad bez bloku Try...Catch...Finally, bude chyba ignorována, jako kdybyste použili příkaz OnError Resume Next. Bez zpracování chyb dělení nulou bez upozornění selže. Vzhledem k tomu, že takové chyby nikdy nevyvolají neošetřené chyby výjimek, 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ů MODELU COM.
Principy chyb zprostředkovatele komunikace modelu COM
Bez zpracování chyb volání zprostředkovatele často generují chyby, které poskytují málo informací. Kdykoli je to možné, použijte strukturované zpracování chyb a poskytněte další informace o problémech, když k nim dojde. To může být užitečné zejména při ladění aplikací. Napří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, najdete tak, že prozkoumáte obsah 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, fungují s .NET jazyka Visual Basic bez problémů. Hlavní výjimky jsou ovládací prvky kontejneru nebo ovládací prvky, které vizuálně obsahují jiné ovládací prvky. Některé příklady starších ovládacích prvků, které nefungují správně se sadou Visual Studio, jsou následující:
Ovládací prvek Microsoft Forms 2.0 Frame
Up-Down ovládací prvek, označovaný také jako otočný ovladač
Ovládací prvek Sheridan Tab
Existují pouze několik alternativních řešení pro nepodporované problémy s ovládacími prvky ActiveX. Existující ovládací prvky můžete migrovat do sady Visual Studio, pokud vlastníte původní zdrojový kód. V opačném případě můžete u dodavatelů softwaru zkontrolovat, zda jsou aktualizované . Net kompatibilní verze ovládacích prvků, které nahradí nepodporované ovládací prvky ActiveX.
Předávání vlastností ovládacích prvků pouze pro čtení ByRef
Visual Basic někdy vyvolává chyby 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 jiným funkcím. Podobná volání procedur z jazyka Visual Basic 6.0 nevyvolají chybu a parametry se považují za předané hodnotou. Chybová zpráva jazyka Visual Basic .NET indikuje, že se pokoušíte změnit vlastnost, která nemá vlastnost Set procedura.
Pokud máte přístup k volanému postupu, můžete této chybě zabránit pomocí klíčového slova ByVal deklarovat parametry, které přijímají ReadOnly vlastnosti. Například:
Sub ProcessParams(ByVal c As Object)
'Use the arguments here.
End Sub
Pokud nemáte přístup ke zdrojovému kódu pro volání procedury, můžete vynutit předání vlastnosti hodnotou přidáním další sady závorek kolem volající procedury. Například v projektu, který má odkaz na objekt COM knihovny Microsoft ActiveX 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í COM, představuje několik jedinečných výzev. Například potenciální problém nastane, 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í. Pokud odinstalujete sestavení, které sdílí knihovnu DLL, můžete ostatním sestavením neúmyslně způsobit její nedostupnost.
Chcete-li se tomuto problému vyhnout, 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 do 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 ve stejném adresáři jako volající aplikace.