Rozwiązywanie problemów związanych z współdziałaniem (Visual Basic)

Podczas współdziałania między modelem COM i kodem zarządzanym .NET Framework może wystąpić co najmniej jeden z następujących typowych problemów.

Interop Marshalling

Czasami może być konieczne użycie typów danych, które nie są częścią .NET Framework. Zestawy międzyoperacyjności obsługują większość pracy dla obiektów COM, ale może być konieczne sterowanie typami danych używanymi podczas uwidocznienia obiektów zarządzanych w modelu COM. Na przykład struktury w bibliotekach klas muszą określać BStr niezarządzany typ ciągów wysyłanych do obiektów COM utworzonych przez program Visual Basic 6.0 i starsze wersje. W takich przypadkach można użyć atrybutu MarshalAsAttribute , aby spowodować uwidocznienie typów zarządzanych jako typy niezarządzane.

Eksportowanie ciągów Fixed-Length do kodu niezarządzanych

W języku Visual Basic 6.0 i starszych wersjach ciągi są eksportowane do obiektów COM jako sekwencje bajtów bez znaku zakończenia o wartości null. W celu zachowania zgodności z innymi językami program Visual Basic .NET zawiera znak zakończenia podczas eksportowania ciągów. Najlepszym sposobem rozwiązania tego niezgodności jest wyeksportowanie ciągów, które nie mają znaku zakończenia jako tablice Byte lub Char.

Eksportowanie hierarchii dziedziczenia

Zarządzane hierarchie klas spłaszcza się, gdy są uwidocznione jako obiekty COM. Jeśli na przykład zdefiniujesz klasę bazową z składową, a następnie odziedziczysz klasę bazową w klasie pochodnej, która jest uwidoczniona jako obiekt COM, klienci korzystający z klasy pochodnej w obiekcie COM nie będą mogli używać dziedziczonych składowych. Dostęp do składowych klas bazowych można uzyskać z obiektów COM tylko jako wystąpień klasy bazowej, a następnie tylko wtedy, gdy klasa bazowa jest również tworzona jako obiekt COM.

Metody przeciążone

Chociaż można tworzyć metody przeciążone za pomocą języka Visual Basic, nie są one obsługiwane przez com. Gdy klasa zawierająca przeciążone metody jest uwidaczniany jako obiekt COM, dla przeciążonych metod są generowane nowe nazwy metod.

Rozważmy na przykład klasę, która ma dwa przeciążenia Synch metody. Gdy klasa jest uwidaczniona jako obiekt COM, nowe wygenerowane nazwy metod mogą mieć Synch wartość i Synch_2.

Zmiana nazwy może powodować dwa problemy dla użytkowników obiektu COM.

  1. Klienci mogą nie oczekiwać wygenerowanych nazw metod.

  2. Wygenerowane nazwy metod w klasie uwidocznione jako obiekt COM mogą ulec zmianie po dodaniu nowych przeciążeń do klasy lub jej klasy bazowej. Może to spowodować problemy z przechowywaniem wersji.

Aby rozwiązać oba problemy, nadaj każdej metodzie unikatową nazwę, zamiast przeciążenia, podczas opracowywania obiektów, które będą widoczne jako obiekty COM.

Korzystanie z obiektów COM za pośrednictwem zestawów międzyoperacyjnych

Zestawy międzyoperacyjności są używane niemal tak, jakby były zastępowaniem kodu zarządzanego dla obiektów COM, które reprezentują. Jednak ponieważ są to otoki, a nie rzeczywiste obiekty COM, istnieją pewne różnice między używaniem zestawów międzyoperacyjnych i zestawów standardowych. Te obszary różnic obejmują ekspozycję klas i typy danych dla parametrów i wartości zwracanych.

Klasy uwidocznione jako interfejsy i klasy

W przeciwieństwie do klas w zestawach standardowych klasy COM są uwidocznione w zestawach międzyoperacyjnych zarówno jako interfejs, jak i klasę reprezentującą klasę COM. Nazwa interfejsu jest taka sama jak nazwa klasy COM. Nazwa klasy międzyoperacyjnej jest taka sama jak nazwa oryginalnej klasy COM, ale z dołączonym słowem "Klasa". Załóżmy na przykład, że masz projekt z odwołaniem do zestawu międzyoperacyjnej dla obiektu COM. Jeśli klasa COM ma nazwę MyComClass, funkcja IntelliSense i przeglądarka obiektów wyświetlają interfejs o nazwie i klasę o nazwie MyComClassMyComClassClass.

Tworzenie wystąpień klasy .NET Framework

Ogólnie rzecz biorąc, należy utworzyć wystąpienie klasy .NET Framework przy użyciu New instrukcji z nazwą klasy. Posiadanie klasy COM reprezentowanej przez zestaw międzyoperatorowy jest jednym przypadkiem, w którym można użyć instrukcji New z interfejsem. Jeśli nie używasz klasy COM z instrukcją Inherits , możesz użyć interfejsu tak samo jak klasa. Poniższy kod przedstawia sposób tworzenia Command obiektu w projekcie, który zawiera odwołanie do obiektu COM biblioteki Microsoft ActiveX Data Objects 2.8:

Dim cmd As New ADODB.Command

Jeśli jednak używasz klasy COM jako podstawy dla klasy pochodnej, musisz użyć klasy międzyoperacyjnej reprezentującej klasę COM, jak w poniższym kodzie:

Class DerivedCommand
    Inherits ADODB.CommandClass
End Class

Uwaga

Zestawy międzyoperacyjnie implementują interfejsy reprezentujące klasy COM. Nie należy próbować używać instrukcji Implements w celu zaimplementowania tych interfejsów lub wystąpi błąd.

Typy danych dla parametrów i wartości zwracanych

W przeciwieństwie do składowych standardowych zestawów składowe międzyoperacyjności mogą mieć typy danych, które różnią się od tych używanych w oryginalnej deklaracji obiektu. Mimo że zestawy międzyoperacyjnie konwertują typy COM na zgodne typy środowiska uruchomieniowego języka wspólnego, należy zwrócić uwagę na typy danych używane przez obie strony, aby zapobiec błędom środowiska uruchomieniowego. Na przykład w obiektach COM utworzonych w języku Visual Basic 6.0 i starszych wersjach wartości typu Integer zakładają, że typ .NET Framework równoważny, Short. Zaleca się użycie przeglądarki obiektów do zbadania właściwości importowanych elementów członkowskich przed ich użyciem.

Metody MODELU COM na poziomie modułu

Większość obiektów COM jest używanych przez utworzenie wystąpienia klasy COM przy użyciu New słowa kluczowego , a następnie wywołanie metod obiektu. Jednym wyjątkiem od tej reguły są obiekty COM, które zawierają AppObj klasy COM lub GlobalMultiUse COM. Takie klasy przypominają metody na poziomie modułu w klasach .NET języka Visual Basic. Program Visual Basic 6.0 i starsze wersje niejawnie tworzą wystąpienia takich obiektów po raz pierwszy wywołania jednej z ich metod. Na przykład w języku Visual Basic 6.0 można dodać odwołanie do biblioteki obiektów microsoft DAO 3.6 i wywołać DBEngine metodę bez uprzedniego utworzenia wystąpienia:

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

Program Visual Basic .NET wymaga, aby zawsze tworzyć wystąpienia obiektów COM, zanim będzie można używać ich metod. Aby użyć tych metod w języku Visual Basic, zadeklaruj zmienną żądanej klasy i użyj nowego słowa kluczowego, aby przypisać obiekt do zmiennej obiektu. Słowo Shared kluczowe może być używane, gdy chcesz mieć pewność, że zostanie utworzone tylko jedno wystąpienie klasy.

' 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

Nieobsługiwane błędy w procedurach obsługi zdarzeń

Jednym z typowych problemów międzyoperacyjności są błędy w programach obsługi zdarzeń, które obsługują zdarzenia zgłaszane przez obiekty COM. Takie błędy są ignorowane, chyba że w szczególności sprawdzasz błędy przy użyciu On Error instrukcji lub Try...Catch...Finally . Na przykład poniższy przykład pochodzi z projektu .NET języka Visual Basic, który zawiera odwołanie do obiektu COM biblioteki 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

Ten przykład zgłasza błąd zgodnie z oczekiwaniami. Jeśli jednak wypróbujesz ten sam przykład bez Try...Catch...Finally bloku, błąd zostanie zignorowany tak, jakby użyto instrukcji OnError Resume Next . Bez obsługi błędów dzielenie przez zero w trybie dyskretnym kończy się niepowodzeniem. Ponieważ takie błędy nigdy nie zgłaszają nieobsługiwane błędy wyjątków, należy użyć jakiejś formy obsługi wyjątków w programach obsługi zdarzeń obsługujących zdarzenia z obiektów COM.

Opis błędów międzyoperacjności modelu COM

Bez obsługi błędów wywołania międzyoperacowe często generują błędy, które zapewniają niewielkie informacje. Jeśli to możliwe, użyj obsługi błędów strukturalnych, aby uzyskać więcej informacji o problemach, gdy wystąpią. Może to być szczególnie przydatne podczas debugowania aplikacji. Na przykład:

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

Informacje takie jak opis błędu, HRESULT i źródło błędów COM można znaleźć, sprawdzając zawartość obiektu wyjątku.

Problemy z kontrolkami ActiveX

Większość kontrolek ActiveX, które współpracują z programem Visual Basic 6.0, współdziała z platformą .NET w języku Visual Basic bez problemów. Główne wyjątki to kontrolki kontenera lub kontrolki, które wizualnie zawierają inne kontrolki. Oto kilka przykładów starszych kontrolek, które nie działają poprawnie w programie Visual Studio:

  • Microsoft Forms kontrolka ramki 2.0

  • kontrolka Up-Down, znana również jako kontrolka pokrętła

  • Sheridan, kontrolka Tab

Istnieje tylko kilka obejść problemów z nieobsługiwaną kontrolką ActiveX. Istniejące kontrolki można migrować do programu Visual Studio, jeśli jesteś właścicielem oryginalnego kodu źródłowego. W przeciwnym razie możesz sprawdzić u dostawców oprogramowania, aby uzyskać zaktualizowany plik . Wersje kontrolek zgodne z platformą NET w celu zastąpienia nieobsługiwanych kontrolek ActiveX.

Przekazywanie właściwości ReadOnly kontrolek ByRef

Program Visual Basic .NET czasami zgłasza błędy COM, takie jak "Błąd 0x800A017F CTL_E_SETNOTSUPPORTED", podczas przekazywania ReadOnly właściwości niektórych starszych kontrolek ActiveX jako ByRef parametrów do innych procedur. Podobne wywołania procedur z programu Visual Basic 6.0 nie zgłaszają błędu, a parametry są traktowane tak, jakby zostały przekazane przez wartość. Komunikat o błędzie platformy .NET w języku Visual Basic wskazuje, że próbujesz zmienić właściwość, która nie ma procedury właściwości Set .

Jeśli masz dostęp do wywoływanej procedury, możesz zapobiec temu błędowi, używając słowa kluczowego ByVal do deklarowania parametrów, które akceptują ReadOnly właściwości. Na przykład:

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

Jeśli nie masz dostępu do kodu źródłowego dla wywoływanej procedury, możesz wymusić przekazanie właściwości przez wartość, dodając dodatkowy zestaw nawiasów wokół procedury wywołującej. Na przykład w projekcie, który zawiera odwołanie do obiektu COM biblioteki Microsoft ActiveX Data Objects 2.8, można użyć:

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

Wdrażanie zestawów, które uwidaczniają międzyoperacjności

Wdrażanie zestawów, które uwidacznia interfejsy COM, stanowi pewne unikatowe wyzwania. Na przykład potencjalny problem występuje, gdy oddzielne aplikacje odwołują się do tego samego zestawu COM. Taka sytuacja występuje często, gdy jest zainstalowana nowa wersja zestawu, a inna aplikacja nadal używa starej wersji zestawu. W przypadku odinstalowania zestawu, który współudzieli bibliotekę DLL, można przypadkowo uczynić go niedostępnym dla innych zestawów.

Aby uniknąć tego problemu, należy zainstalować zestawy udostępnione w globalnej pamięci podręcznej zestawów (GAC) i użyć modułu MergeModule dla składnika. Jeśli nie możesz zainstalować aplikacji w GAC, należy ją zainstalować w folderze CommonFilesFolder w podkatalogu specyficznym dla wersji.

Zestawy, które nie są udostępniane, powinny znajdować się obok siebie w katalogu z aplikacją wywołującą.

Zobacz też