Együttműködési hibák elhárítása (Visual Basic)

Amikor együttműködik a COM és a .NET-keretrendszer felügyelt kódja között, az alábbi gyakori problémák közül egy vagy több merülhet fel.

Interop Marshalling

Időnként előfordulhat, hogy olyan adattípusokat kell használnia, amelyek nem részei a .NET-keretrendszer. Az interop szerelvények kezelik a COM-objektumok legtöbb munkáját, de előfordulhat, hogy szabályoznia kell a felügyelt objektumok COM-nak való közzétételekor használt adattípusokat. Az osztálytárak struktúráinak például meg kell adniuk a nem felügyelt típust a BStr Visual Basic 6.0-s és korábbi verziói által létrehozott COM-objektumoknak küldött sztringeken. Ilyen esetekben a MarshalAsAttribute attribútum használatával a felügyelt típusok nem felügyelt típusokként lesznek közzétéve.

Fixed-Length sztringek exportálása nem felügyelt kódba

A Visual Basic 6.0-s és korábbi verzióiban a sztringeket a rendszer bájtok sorozataként exportálja a COM-objektumokba null értékű megszakítási karakter nélkül. A más nyelvekkel való kompatibilitás érdekében a Visual Basic .NET sztringek exportálásakor egy leállítási karaktert tartalmaz. Ennek az inkompatibilitásnak a legjobb megoldásához exportálja azokat a sztringeket, amelyekből hiányzik a végződés karaktere a vagy Chara tömbjekéntByte.

Öröklési hierarchiák exportálása

A felügyelt osztályhierarchiák elsimulnak, ha COM-objektumként vannak elérhetővé téve. Ha például egy taggal rendelkező alaposztályt határoz meg, majd egy COM-objektumként közzétett származtatott osztályban örökli az alaposztályt, a COM-objektum származtatott osztályát használó ügyfelek nem fogják tudni használni az örökölt tagokat. Az alaposztálytagok csak az alaposztály példányaiként érhetők el COM-objektumokból, majd csak akkor, ha az alaposztály COM-objektumként is létrejön.

Többszörös szerepű metódusok

Bár a Visual Basic használatával túlterhelt metódusokat is létrehozhat, a COM nem támogatja őket. Ha egy túlterhelt metódusokat tartalmazó osztály COM-objektumként van elérhetővé téve, a rendszer új metódusneveket hoz létre a túlterhelt metódusokhoz.

Vegyük például azt az osztályt, amelynek a metódus két túlterhelése Synch van. Ha a osztály COM-objektumként van elérhetővé téve, az új létrehozott metódusnevek lehetnek Synch és Synch_2.

Az átnevezés két problémát okozhat a COM-objektum felhasználói számára.

  1. Előfordulhat, hogy az ügyfelek nem várják el a létrehozott metódusneveket.

  2. A COM-objektumként közzétett osztályban létrehozott metódusnevek megváltozhatnak, ha új túlterheléseket adnak hozzá az osztályhoz vagy annak alaposztályához. Ez verziószámozási problémákat okozhat.

Mindkét probléma megoldásához adjon minden metódusnak egyedi nevet a túlterhelés használata helyett, amikor COM-objektumként elérhetővé válik objektumok fejlesztésekor.

COM-objektumok használata interop szerelvényeken keresztül

Az interop szerelvényeket szinte úgy használja, mintha felügyelt kódcserék lennének az általuk képviselt COM-objektumokhoz. Mivel azonban burkolók, és nem tényleges COM-objektumok, van néhány különbség az interop szerelvények és a standard szerelvények használata között. A különbség ezen területei közé tartozik az osztályok kitettsége, valamint a paraméterek és a visszaadott értékek adattípusa.

Interfészként és osztályként is elérhető osztályok

A szabványos szerelvények osztályaitól eltérően a COM-osztályok interop szerelvényekben vannak elérhetővé téve interfészként és a COM osztályt képviselő osztályként is. A felület neve megegyezik a COM osztály nevével. Az interop osztály neve megegyezik az eredeti COM osztály nevével, de az "Osztály" szó hozzá van fűzve. Tegyük fel például, hogy van egy projektje, amely egy COM-objektum interop szerelvényére hivatkozik. Ha a COM osztály neve MyComClass, az IntelliSense és az Object Browser egy nevű MyComClass felületet és egy nevű MyComClassClassosztályt jelenít meg.

.NET-keretrendszer osztály példányainak létrehozása

Általában egy .NET-keretrendszer osztály egy példányát hozza létre az New osztálynévvel rendelkező utasítással. Az interop szerelvény által jelölt COM-osztály az egyetlen eset, amelyben az New utasítást egy illesztővel használhatja. Hacsak nem a COM osztályt használja utasítással Inherits , ugyanúgy használhatja a felületet, mint egy osztályt. Az alábbi kód bemutatja, hogyan hozhat létre Command olyan objektumot egy projektben, amely a Microsoft ActiveX Data Objects 2.8 Library COM objektumra hivatkozik:

Dim cmd As New ADODB.Command

Ha azonban a COM osztályt használja egy származtatott osztály alapjaként, akkor a COM osztályt képviselő interop osztályt kell használnia, az alábbi kódban leírtak szerint:

Class DerivedCommand
    Inherits ADODB.CommandClass
End Class

Megjegyzés

Az interop szerelvények implicit módon implementálják a COM-osztályokat képviselő interfészeket. Ne próbálja meg az utasítást Implements használni ezen felületek implementálásához, mert a hibaüzenetet kapja.

Paraméterek és visszatérési értékek adattípusai

A szabványos szerelvények tagjaitól eltérően az interop szerelvény tagjai olyan adattípusokkal rendelkezhetnek, amelyek eltérnek az eredeti objektumdeklarációban használt adatoktól. Bár az interop szerelvények implicit módon konvertálják a COM-típusokat kompatibilis közös nyelvi futtatókörnyezet-típusokká, érdemes figyelni azokat az adattípusokat, amelyeket mindkét oldal használ a futásidejű hibák megelőzése érdekében. A Visual Basic 6.0-s és korábbi verzióiban létrehozott COM-objektumokban például a típusértékek Integer a .NET-keretrendszer egyenértékű típust feltételezik. Short Javasoljuk, hogy a használat előtt az Object Browser használatával vizsgálja meg az importált tagok jellemzőit.

Modulszintű COM-metódusok

A LEGTÖBB COM-objektumot úgy használja a rendszer, hogy létrehoz egy COM-osztálypéldányt a New kulcsszóval, majd meghívja az objektum metódusait. A szabály alól kivételt képeznek azok a COM-objektumok, amelyek vagy GlobalMultiUse COM-osztályokat tartalmaznakAppObj. Az ilyen osztályok a Visual Basic .NET-osztályok modulszintű metódusaihoz hasonlítanak. A Visual Basic 6.0-s és korábbi verziói implicit módon létrehozzák az ilyen objektumok példányait, amikor először hívja meg az egyik metódusukat. A Visual Basic 6.0-ban például hozzáadhat egy hivatkozást a Microsoft DAO 3.6 objektumtárhoz, és meghívhatja a DBEngine metódust példány létrehozása nélkül:

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

A Visual Basic .NET használatához mindig létre kell hoznia COM-objektumok példányait. Ha ezeket a metódusokat a Visual Basicben szeretné használni, deklaráljon egy változót a kívánt osztályból, és az új kulcsszóval rendelje hozzá az objektumot az objektumváltozóhoz. A Shared kulcsszó akkor használható, ha meg szeretné győződni arról, hogy a osztálynak csak egy példánya van létrehozva.

' 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

Nem kezelt hibák az eseménykezelőkben

Az egyik gyakori együttműködési probléma a COM-objektumok által kiváltott eseményeket kezelő eseménykezelők hibáit érinti. Az ilyen hibák figyelmen kívül lesznek hagyva, kivéve, ha kifejezetten a vagy Try...Catch...Finally utasításokkal On Error keres hibákat. Az alábbi példa például egy Visual Basic .NET-projektből származik, amely a Microsoft ActiveX Data Objects 2.8 Library COM objektumra hivatkozik.

' 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

Ez a példa a várt módon jelez hibát. Ha azonban a blokk nélkül próbálja meg ugyanazt a Try...Catch...Finally példát, a rendszer figyelmen kívül hagyja a hibát, mintha a utasítást OnError Resume Next használta volna. Hibakezelés nélkül a nulladik osztás csendesen meghiúsul. Mivel az ilyen hibák soha nem okoznak kezeletlen kivételhibákat, fontos, hogy valamilyen kivételkezelést használjon a COM-objektumok eseményeit kezelő eseménykezelőkben.

A COM-együttműködés hibáinak ismertetése

Hibakezelés nélkül az interop hívások gyakran olyan hibákat eredményeznek, amelyek kevés információt nyújtanak. Amikor csak lehetséges, használjon strukturált hibakezelést, hogy több információt nyújtson a felmerülő problémákról. Ez különösen hasznos lehet az alkalmazások hibakeresése során. Például:

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

A kivételobjektum tartalmának vizsgálatával olyan információkat talál, mint a hiba leírása, a HRESULT és a COM-hibák forrása.

ActiveX-vezérléssel kapcsolatos problémák

A Visual Basic 6.0-val működő ActiveX-vezérlők többsége probléma nélkül együttműködik a Visual Basic .NET-tel. A fő kivételek a tárolóvezérlők, vagy a más vezérlőket vizuálisan tartalmazó vezérlők. Néhány példa a Visual Studióval nem megfelelően működő régebbi vezérlőkre:

  • Microsoft Forms 2.0 Keret vezérlőelem

  • Up-Down vezérlő, más néven a spin vezérlőelem

  • Sheridan Tab Control

Csak néhány kerülő megoldás létezik a nem támogatott ActiveX-vezérlési problémákra. Az eredeti forráskód birtokában meglévő vezérlőket migrálhat a Visual Studióba. Ellenkező esetben a szoftvergyártóknál érdeklődhet a frissítésről. A nem támogatott ActiveX-vezérlők lecseréléséhez a vezérlők NET-kompatibilis verziói.

A Vezérlők ByRef olvasási tulajdonságainak átadása

A Visual Basic .NET időnként COM-hibákat (például "Hiba 0x800A017F CTL_E_SETNOTSUPPORTED" okoz, amikor bizonyos régebbi ActiveX-vezérlők tulajdonságait paraméterekként ByRef adja át ReadOnly más eljárásoknak. A Visual Basic 6.0 hasonló eljáráshívásai nem okoznak hibát, és a paramétereket úgy kezeli a rendszer, mintha érték alapján adta volna át őket. A Visual Basic .NET hibaüzenete azt jelzi, hogy olyan tulajdonságot próbál módosítani, amely nem rendelkezik tulajdonságeljárással Set .

Ha rendelkezik hozzáféréssel a meghívandó eljáráshoz, ezt a hibát megakadályozhatja, ha a kulcsszóval deklarálja a ByVal tulajdonságokat elfogadó ReadOnly paramétereket. Például:

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

Ha nem fér hozzá a meghívandó eljárás forráskódjaihoz, kényszerítheti a tulajdonság érték szerinti átadását egy további szögletes zárójelek hozzáadásával a hívási eljárás köré. Egy olyan projektben például, amely a Microsoft ActiveX Data Objects 2.8 Library COM objektumra hivatkozik, a következőket használhatja:

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

Interop-t közzétesző szerelvények üzembe helyezése

A COM-felületeket elérhetővé tevő szerelvények üzembe helyezése egyedi kihívásokat jelent. Lehetséges probléma például akkor fordul elő, ha a különálló alkalmazások ugyanarra a COM-szerelvényre hivatkoznak. Ez a helyzet akkor gyakori, ha egy szerelvény új verziója van telepítve, és egy másik alkalmazás továbbra is a szerelvény régi verzióját használja. Ha eltávolít egy DLL-t használó szerelvényt, akaratlanul elérhetetlenné teheti azt a többi szerelvény számára.

A probléma elkerülése érdekében telepítse a megosztott szerelvényeket a globális szerelvény-gyorsítótárba (GAC), és használjon mergeModule-t az összetevőhöz. Ha nem tudja telepíteni az alkalmazást a GAC-ban, azt egy verzióspecifikus alkönyvtárban kell telepíteni a CommonFilesFolder mappába.

A nem megosztott szerelvényeknek egymás mellett kell lenniük a címtárban a hívó alkalmazással.

Lásd még