Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Wanneer u werkt tussen COM en de beheerde code van .NET Framework, kunt u een of meer van de volgende veelvoorkomende problemen tegenkomen.
Interop Marshalling
Soms moet u mogelijk gegevenstypen gebruiken die geen deel uitmaken van .NET Framework. Interop-assembly's verwerken het grootste deel van het werk voor COM-objecten, maar mogelijk moet u bepalen welke gegevenstypen worden gebruikt wanneer beheerde objecten worden blootgesteld aan COM. Structuren in klassebibliotheken moeten bijvoorbeeld het BStr onbeheerde type opgeven voor tekenreeksen die zijn verzonden naar COM-objecten die zijn gemaakt door Visual Basic 6.0 en eerdere versies. In dergelijke gevallen kunt u het kenmerk MarshalAsAttribute gebruiken om ervoor te zorgen dat beheerde typen worden weergegeven als niet-beheerde typen.
Fixed-Length tekenreeksen exporteren naar niet-beheerde code
In Visual Basic 6.0 en eerdere versies worden tekenreeksen geëxporteerd naar COM-objecten als reeksen van bytes zonder null-beëindigingsteken. Voor compatibiliteit met andere talen bevat Visual Basic .NET een beëindigingsteken bij het exporteren van tekenreeksen. De beste manier om deze incompatibiliteit te verhelpen, is door tekenreeksen te exporteren die niet het beëindigingsteken hebben als matrices van Byte of Char.
Overnamehiërarchieën exporteren
Beheerde klassehiërarchieën worden afgevlakt wanneer ze als COM-objecten worden weergegeven. Als u bijvoorbeeld een basisklasse met een lid definieert en vervolgens de basisklasse overneemt in een afgeleide klasse die wordt weergegeven als een COM-object, kunnen clients die gebruikmaken van de afgeleide klasse in het COM-object de overgenomen leden niet gebruiken. Leden van de basisklasse kunnen alleen worden geopend vanuit COM-objecten als exemplaren van een basisklasse en alleen als de basisklasse ook als com-object wordt gemaakt.
Overbelaste methoden
Hoewel u overbelaste methoden met Visual Basic kunt maken, worden deze niet ondersteund door COM. Wanneer een klasse met overbelaste methoden wordt weergegeven als com-object, worden nieuwe methodenamen gegenereerd voor de overbelaste methoden.
Denk bijvoorbeeld aan een klasse met twee overbelastingen van de methode Synch. Wanneer de klasse wordt weergegeven als een COM-object, kunnen de nieuwe gegenereerde methodenamen worden Synch en Synch_2.
De naamwijziging kan twee problemen veroorzaken voor consumenten van het COM-object.
Clients verwachten mogelijk niet de gegenereerde methodenamen.
De gegenereerde methodenamen in de klasse die als com-object worden weergegeven, kunnen veranderen wanneer nieuwe overbelastingen worden toegevoegd aan de klasse of de basisklasse. Dit kan problemen met versiebeheer veroorzaken.
Als u beide problemen wilt oplossen, geeft u elke methode een unieke naam, in plaats van overbelasting te gebruiken, wanneer u objecten ontwikkelt die als COM-objecten worden weergegeven.
Gebruik van COM-objecten door middel van tussenliggende assemblages
U gebruikt interoperabiliteitsassembly's bijna alsof ze beheerde codevervangingen zijn voor de COM-objecten die ze vertegenwoordigen. Omdat ze echter wrappers zijn en geen werkelijke COM-objecten, zijn er enkele verschillen tussen het gebruik van interopassembly's en standaardassembly's. Deze verschilgebieden omvatten de blootstelling van klassen en gegevenstypen voor parameters en retourwaarden.
Klassen weergegeven als interfaces en klassen
In tegenstelling tot klassen in standaardassembly's worden COM-klassen weergegeven in interopassembly's als interface en een klasse die de COM-klasse vertegenwoordigt. De naam van de interface is identiek aan die van de COM-klasse. De naam van de interop-klasse is hetzelfde als die van de oorspronkelijke COM-klasse, maar met het woord 'Klasse' toegevoegd. Stel dat u een project hebt met een verwijzing naar een interop-assembly voor een COM-object. Als de COM-klasse MyComClassheet, tonen IntelliSense en objectbrowser een interface met de naam MyComClass en een klasse met de naam MyComClassClass.
Exemplaren van een .NET Framework-klasse maken
Over het algemeen maakt u een exemplaar van een .NET Framework-klasse met behulp van de New-instructie met een klassenaam. Het hebben van een COM-klasse die wordt vertegenwoordigd door een interop-assembly is het ene geval waarin u de New-instructie met een interface kunt gebruiken. Tenzij u de COM-klasse met een Inherits instructie gebruikt, kunt u de interface net als een klasse gebruiken. De volgende code laat zien hoe u een Command-object maakt in een project met een verwijzing naar het COM-object microsoft ActiveX-gegevensobjecten 2.8 Library:
Dim cmd As New ADODB.Command
Als u echter de COM-klasse gebruikt als basis voor een afgeleide klasse, moet u de interop-klasse gebruiken die de COM-klasse vertegenwoordigt, zoals in de volgende code:
Class DerivedCommand
Inherits ADODB.CommandClass
End Class
Notitie
Interop-assembly's implementeren impliciet interfaces die COM-klassen vertegenwoordigen. U moet niet proberen de Implements instructie te gebruiken om deze interfaces te implementeren of er een fout optreedt.
Gegevenstypen voor parameters en retourwaarden
In tegenstelling tot leden van standaardassembly's kunnen interop-assemblyleden gegevenstypen hebben die verschillen van die in de oorspronkelijke objectdeclaratie. Hoewel interop-assemblies COM-typen impliciet converteren naar compatibele Common Language Runtime-typen, moet u opletten voor de gegevenstypen die door beide kanten worden gebruikt om runtimefouten te voorkomen. In COM-objecten die zijn gemaakt in Visual Basic 6.0 en eerdere versies, gaan waarden van het type Integer bijvoorbeeld uit van het equivalente type .NET Framework, Short. Het is raadzaam om de objectbrowser te gebruiken om de kenmerken van geïmporteerde leden te onderzoeken voordat u ze gebruikt.
COM-methoden op moduleniveau
De meeste COM-objecten worden gebruikt door een exemplaar van een COM-klasse te maken met behulp van het trefwoord New en vervolgens methoden van het object aan te roepen. Een uitzondering op deze regel omvat COM-objecten die AppObj- of GlobalMultiUse COM-klassen bevatten. Dergelijke klassen lijken op methoden op moduleniveau in Visual Basic .NET-klassen. Visual Basic 6.0 en eerdere versies maken impliciet voor u exemplaren van dergelijke objecten aan wanneer u voor de eerste keer een van hun methoden aanroept. In Visual Basic 6.0 kunt u bijvoorbeeld een verwijzing toevoegen naar de Microsoft DAO 3.6-objectbibliotheek en de methode DBEngine aanroepen zonder eerst een exemplaar te maken:
Dim db As DAO.Database
' Open the database.
Set db = DBEngine.OpenDatabase("C:\nwind.mdb")
' Use the database object.
Visual Basic .NET vereist dat u altijd exemplaren van COM-objecten maakt voordat u hun methoden kunt gebruiken. Als u deze methoden in Visual Basic wilt gebruiken, declareert u een variabele van de gewenste klasse en gebruikt u het nieuwe trefwoord om het object toe te wijzen aan de objectvariabele. Het Shared trefwoord kan worden gebruikt wanneer u ervoor wilt zorgen dat er slechts één exemplaar van de klasse wordt gemaakt.
' 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
Niet-verwerkte fouten in gebeurtenishandlers
Een veelvoorkomend interoperabiliteitsprobleem betreft fouten in gebeurtenis-handlers die gebeurtenissen verwerken die worden gegenereerd door COM-objecten. Dergelijke fouten worden genegeerd, tenzij u specifiek controleert op fouten met behulp van On Error- of Try...Catch...Finally-instructies. Het volgende voorbeeld is bijvoorbeeld afkomstig van een Visual Basic .NET-project met een verwijzing naar het COM-object Microsoft ActiveX-gegevensobjecten 2.8 Library.
' 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
In dit voorbeeld treedt een fout op, zoals verwacht. Als u echter hetzelfde voorbeeld probeert zonder het Try...Catch...Finally blok, wordt de fout genegeerd alsof u de OnError Resume Next-instructie hebt gebruikt. Zonder foutafhandeling mislukt de deling door nul ongemerkt. Omdat dergelijke fouten nooit niet-verwerkte uitzonderingsfouten veroorzaken, is het belangrijk dat u een vorm van uitzonderingsafhandeling gebruikt in gebeurtenis-handlers die gebeurtenissen van COM-objecten verwerken.
Com-interoperabiliteitsfouten begrijpen
Zonder foutafhandeling genereren interop-aanroepen vaak fouten die weinig informatie bieden. Gebruik indien mogelijk gestructureerde foutafhandeling om meer informatie te geven over problemen wanneer ze optreden. Dit kan met name handig zijn als u fouten in applicaties opspoort. Bijvoorbeeld:
Try
' Place call to COM object here.
Catch ex As Exception
' Display information about the failed call.
End Try
U vindt informatie zoals de foutbeschrijving, HRESULT en de bron van COM-fouten door de inhoud van het uitzonderingsobject te bekijken.
Problemen met ActiveX-beheer
De meeste ActiveX-besturingselementen die met Visual Basic 6.0 werken, werken zonder problemen met Visual Basic .NET. De belangrijkste uitzonderingen zijn containerbesturingselementen of besturingselementen die visueel andere besturingselementen bevatten. Enkele voorbeelden van oudere besturingselementen die niet correct werken met Visual Studio zijn als volgt:
Besturingselement Microsoft Forms 2.0 Frame
Up-Down controle, ook wel bekend als spincontrole
Sheridan Tab-besturingselement
Er zijn slechts enkele tijdelijke oplossingen voor problemen met niet-ondersteunde ActiveX-besturingselementen. U kunt bestaande besturingselementen migreren naar Visual Studio als u de eigenaar bent van de oorspronkelijke broncode. Anders kunt u contact opnemen met softwareleveranciers voor bijgewerkte .NET-compatibele versies van besturingselementen ter vervanging van niet-ondersteunde ActiveX-besturingselementen.
ReadOnly-eigenschappen van Besturingselementen doorgegeven door ByRef
Visual Basic veroorzaakt soms COM-fouten, zoals 'Fout 0x800A017F CTL_E_SETNOTSUPPORTED', wanneer u ReadOnly eigenschappen van sommige oudere ActiveX-besturingselementen doorgeeft als ByRef parameters aan andere procedures. Vergelijkbare procedureaanroepen van Visual Basic 6.0 veroorzaken geen fout en de parameters worden behandeld alsof u ze doorgeeft op waarde. Het Visual Basic .NET-foutbericht geeft aan dat u een eigenschap wilt wijzigen die geen eigenschapsprocedure heeft met Set.
Als u toegang hebt tot de procedure die wordt aangeroepen, kunt u deze fout voorkomen door het trefwoord ByVal te gebruiken om parameters te declareren die ReadOnly eigenschappen accepteren. Bijvoorbeeld:
Sub ProcessParams(ByVal c As Object)
'Use the arguments here.
End Sub
Als u geen toegang hebt tot de broncode van de opgeroepen procedure, kunt u afdwingen dat de eigenschap wordt doorgegeven door een extra set van haakjes rond de aanroepende procedure te plaatsen. In een project met bijvoorbeeld een verwijzing naar het COM-object Microsoft ActiveX Data Objects 2.8 Library kunt u het volgende gebruiken:
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
Assemblies uitrollen die interop-interacties mogelijk maken
Het implementeren van assembly's die COM-interfaces beschikbaar maken, biedt enkele unieke uitdagingen. Er treedt bijvoorbeeld een mogelijk probleem op wanneer afzonderlijke toepassingen verwijzen naar dezelfde COM-assembly. Deze situatie is gebruikelijk wanneer een nieuwe versie van een assembly wordt geïnstalleerd en een andere toepassing nog steeds de oude versie van de assembly gebruikt. Als u een assembly verwijdert die een DLL deelt, kunt u deze onbedoeld niet beschikbaar maken voor de andere assembly's.
Om dit probleem te voorkomen, moet u gedeelde assembly's installeren in de Global Assembly Cache (GAC) en een MergeModule voor het onderdeel gebruiken. Als u de toepassing niet in de GAC kunt installeren, moet deze worden geïnstalleerd in CommonFilesFolder in een versiespecifieke submap.
Assemblages die niet worden gedeeld, moeten zij aan zij in de map van de aanroepende toepassing worden geplaatst.