Solucionando problemas de interoperabilidade (Visual Basic)Troubleshooting Interoperability (Visual Basic)

Ao interoperar entre COM e o código gerenciado do .NET Framework, você pode encontrar um ou mais dos seguintes problemas comuns.When you interoperate between COM and the managed code of the .NET Framework, you may encounter one or more of the following common issues.

Marshaling de interoperabilidadeInterop Marshaling

Às vezes, talvez seja necessário usar tipos de dados que não fazem parte do .NET Framework.At times, you may have to use data types that are not part of the .NET Framework. Os assemblies de interoperabilidade lidam com a maior parte do trabalho para objetos COM, mas você pode ter que controlar os tipos de dados que são usados quando objetos gerenciados são expostos a COM.Interop assemblies handle most of the work for COM objects, but you may have to control the data types that are used when managed objects are exposed to COM. Por exemplo, estruturas em bibliotecas de classes devem especificar o BStr tipo não gerenciado em cadeias de caracteres enviadas a objetos com criados por Visual Basic 6,0 e versões anteriores.For example, structures in class libraries must specify the BStr unmanaged type on strings sent to COM objects created by Visual Basic 6.0 and earlier versions. Nesses casos, você pode usar o MarshalAsAttribute atributo para fazer com que os tipos gerenciados sejam expostos como tipos não gerenciados.In such cases, you can use the MarshalAsAttribute attribute to cause managed types to be exposed as unmanaged types.

Exportando cadeias de caracteres Fixed-Length para código não gerenciadoExporting Fixed-Length Strings to Unmanaged Code

No Visual Basic 6,0 e versões anteriores, as cadeias de caracteres são exportadas para objetos COM como sequências de bytes sem um caractere de terminação nulo.In Visual Basic 6.0 and earlier versions, strings are exported to COM objects as sequences of bytes without a null termination character. Para compatibilidade com outras linguagens, Visual Basic .NET inclui um caractere de terminação ao exportar cadeias de caracteres.For compatibility with other languages, Visual Basic .NET includes a termination character when exporting strings. A melhor maneira de resolver essa incompatibilidade é exportar cadeias de caracteres que não tenham o caractere de término como matrizes de Byte ou Char .The best way to address this incompatibility is to export strings that lack the termination character as arrays of Byte or Char.

Exportando hierarquias de herançaExporting Inheritance Hierarchies

Hierarquias de classe gerenciada mesclam quando expostas como objetos COM.Managed class hierarchies flatten out when exposed as COM objects. Por exemplo, se você definir uma classe base com um membro e, em seguida, herdar a classe base em uma classe derivada que é exposta como um objeto COM, os clientes que usam a classe derivada no objeto COM não poderão usar os membros herdados.For example, if you define a base class with a member, and then inherit the base class in a derived class that is exposed as a COM object, clients that use the derived class in the COM object will not be able to use the inherited members. Os membros da classe base podem ser acessados de objetos COM somente como instâncias de uma classe base e, em seguida, somente se a classe base também for criada como um objeto COM.Base class members can be accessed from COM objects only as instances of a base class, and then only if the base class is also created as a COM object.

Métodos sobrecarregadosOverloaded Methods

Embora você possa criar métodos sobrecarregados com Visual Basic, eles não têm suporte do COM.Although you can create overloaded methods with Visual Basic, they are not supported by COM. Quando uma classe que contém métodos sobrecarregados é exposta como um objeto COM, novos nomes de método são gerados para os métodos sobrecarregados.When a class that contains overloaded methods is exposed as a COM object, new method names are generated for the overloaded methods.

Por exemplo, considere uma classe que tem duas sobrecargas do Synch método.For example, consider a class that has two overloads of the Synch method. Quando a classe é exposta como um objeto COM, os novos nomes de método gerados podem ser Synch e Synch_2 .When the class is exposed as a COM object, the new generated method names could be Synch and Synch_2.

A renomeação pode causar dois problemas para os consumidores do objeto COM.The renaming can cause two problems for consumers of the COM object.

  1. Os clientes podem não esperar os nomes de métodos gerados.Clients might not expect the generated method names.

  2. Os nomes de métodos gerados na classe exposta como um objeto COM podem ser alterados quando novas sobrecargas são adicionadas à classe ou sua classe base.The generated method names in the class exposed as a COM object can change when new overloads are added to the class or its base class. Isso pode causar problemas de controle de versão.This can cause versioning problems.

Para resolver os dois problemas, dê a cada método um nome exclusivo, em vez de usar sobrecarga, ao desenvolver objetos que serão expostos como objetos COM.To solve both problems, give each method a unique name, instead of using overloading, when you develop objects that will be exposed as COM objects.

Uso de objetos COM por meio de assemblies de interoperabilidadeUse of COM Objects Through Interop Assemblies

Você usa assemblies de interoperabilidade quase como se eles fossem substituições de código gerenciado para os objetos COM que eles representam.You use interop assemblies almost as if they are managed code replacements for the COM objects they represent. No entanto, como são wrappers e não objetos COM reais, há algumas diferenças entre usar assemblies de interoperabilidade e assemblies padrão.However, because they are wrappers and not actual COM objects, there are some differences between using interop assemblies and standard assemblies. Essas áreas de diferença incluem a exposição de classes e tipos de dados para parâmetros e valores de retorno.These areas of difference include the exposure of classes, and data types for parameters and return values.

Classes expostas como interfaces e classesClasses Exposed as Both Interfaces and Classes

Ao contrário das classes em assemblies padrão, as classes COM são expostas em assemblies de interoperabilidade como uma interface e uma classe que representa a classe COM.Unlike classes in standard assemblies, COM classes are exposed in interop assemblies as both an interface and a class that represents the COM class. O nome da interface é idêntico ao da classe COM.The interface's name is identical to that of the COM class. O nome da classe Interop é o mesmo da classe COM original, mas com a palavra "Class" acrescentada.The name of the interop class is the same as that of the original COM class, but with the word "Class" appended. Por exemplo, suponha que você tenha um projeto com uma referência a um assembly de interoperabilidade para um objeto COM.For example, suppose you have a project with a reference to an interop assembly for a COM object. Se a classe COM for nomeada MyComClass , o IntelliSense e o pesquisador de objetos mostrarão uma interface chamada MyComClass e uma classe denominada MyComClassClass .If the COM class is named MyComClass, IntelliSense and the Object Browser show an interface named MyComClass and a class named MyComClassClass.

Criando instâncias de uma classe de .NET FrameworkCreating Instances of a .NET Framework Class

Em geral, você cria uma instância de uma classe de .NET Framework usando a New instrução com um nome de classe.Generally, you create an instance of a .NET Framework class using the New statement with a class name. Ter uma classe COM representada por um assembly de interoperabilidade é o único caso em que você pode usar a New instrução com uma interface.Having a COM class represented by an interop assembly is the one case in which you can use the New statement with an interface. A menos que você esteja usando a classe COM com uma Inherits instrução, você pode usar a interface da mesma forma que faria com uma classe.Unless you are using the COM class with an Inherits statement, you can use the interface just as you would a class. O código a seguir demonstra como criar um Command objeto em um projeto que tem uma referência ao objeto com da biblioteca do Microsoft ActiveX Data Objects 2,8:The following code demonstrates how to create a Command object in a project that has a reference to the Microsoft ActiveX Data Objects 2.8 Library COM object:

Dim cmd As New ADODB.Command

No entanto, se você estiver usando a classe COM como a base para uma classe derivada, deverá usar a classe Interop que representa a classe COM, como no código a seguir:However, if you are using the COM class as the base for a derived class, you must use the interop class that represents the COM class, as in the following code:

Class DerivedCommand
    Inherits ADODB.CommandClass
End Class

Observação

Os assemblies de interoperabilidade implementam implicitamente interfaces que representam classes COM.Interop assemblies implicitly implement interfaces that represent COM classes. Você não deve tentar usar a Implements instrução para implementar essas interfaces ou um erro será resultado.You should not try to use the Implements statement to implement these interfaces or an error will result.

Tipos de dados para parâmetros e valores de retornoData Types for Parameters and Return Values

Ao contrário dos membros de assemblies padrão, os membros do assembly de interoperabilidade podem ter tipos de dados diferentes daqueles usados na declaração de objeto original.Unlike members of standard assemblies, interop assembly members may have data types that differ from those used in the original object declaration. Embora os assemblies de interoperabilidade convertam implicitamente tipos COM em tipos de Common Language Runtime compatíveis, você deve prestar atenção aos tipos de dados que são usados por ambos os lados para evitar erros de tempo de execução.Although interop assemblies implicitly convert COM types to compatible common language runtime types, you should pay attention to the data types that are used by both sides to prevent runtime errors. Por exemplo, em objetos COM criados no Visual Basic 6,0 e em versões anteriores, os valores do tipo Integer assumem o .NET Framework tipo equivalente, Short .For example, in COM objects created in Visual Basic 6.0 and earlier versions, values of type Integer assume the .NET Framework equivalent type, Short. É recomendável que você use o pesquisador de objetos para examinar as características dos membros importados antes de usá-los.It is recommended that you use the Object Browser to examine the characteristics of imported members before you use them.

Métodos COM de nível de móduloModule level COM methods

A maioria dos objetos COM é usada pela criação de uma instância de uma classe COM usando a New palavra-chave e, em seguida, a chamada de métodos do objeto.Most COM objects are used by creating an instance of a COM class using the New keyword and then calling methods of the object. Uma exceção a essa regra envolve objetos COM que contêm AppObj ou GlobalMultiUse classes com.One exception to this rule involves COM objects that contain AppObj or GlobalMultiUse COM classes. Essas classes parecem métodos de nível de módulo em classes Visual Basic .NET.Such classes resemble module level methods in Visual Basic .NET classes. Visual Basic 6,0 e versões anteriores criam implicitamente instâncias desses objetos para você pela primeira vez que você chama um de seus métodos.Visual Basic 6.0 and earlier versions implicitly create instances of such objects for you the first time that you call one of their methods. Por exemplo, no Visual Basic 6,0, você pode adicionar uma referência à biblioteca de objetos do Microsoft DAO 3,6 e chamar o DBEngine método sem primeiro criar uma instância:For example, in Visual Basic 6.0 you can add a reference to the Microsoft DAO 3.6 Object Library and call the DBEngine method without first creating an instance:

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

Visual Basic .NET requer que você sempre Crie instâncias de objetos COM antes de poder usar seus métodos.Visual Basic .NET requires that you always create instances of COM objects before you can use their methods. Para usar esses métodos no Visual Basic, declare uma variável da classe desejada e use a nova palavra-chave para atribuir o objeto à variável de objeto.To use these methods in Visual Basic, declare a variable of the desired class and use the new keyword to assign the object to the object variable. A Shared palavra-chave pode ser usada quando você deseja garantir que apenas uma instância da classe seja criada.The Shared keyword can be used when you want to make sure that only one instance of the class is created.

' 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

Erros sem tratamento em manipuladores de eventosUnhandled Errors in Event Handlers

Um problema de interoperabilidade comum envolve erros em manipuladores de eventos que manipulam eventos gerados por objetos COM.One common interop problem involves errors in event handlers that handle events raised by COM objects. Esses erros são ignorados, a menos que você verifique especificamente se há erros usando On Error Try...Catch...Finally instruções or.Such errors are ignored unless you specifically check for errors using On Error or Try...Catch...Finally statements. Por exemplo, o exemplo a seguir é de um projeto Visual Basic .NET que tem uma referência ao objeto COM da biblioteca do Microsoft ActiveX Data Objects 2,8.For example, the following example is from a Visual Basic .NET project that has a reference to the Microsoft ActiveX Data Objects 2.8 Library COM object.

' 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

Este exemplo gera um erro como esperado.This example raises an error as expected. No entanto, se você tentar o mesmo exemplo sem o Try...Catch...Finally bloco, o erro será ignorado como se você tiver usado a OnError Resume Next instrução.However, if you try the same example without the Try...Catch...Finally block, the error is ignored as if you used the OnError Resume Next statement. Sem tratamento de erros, a divisão por zero falha silenciosamente.Without error handling, the division by zero silently fails. Como esses erros nunca geram erros de exceção sem tratamento, é importante que você use alguma forma de manipulação de exceção em manipuladores de eventos que manipulam eventos de objetos COM.Because such errors never raise unhandled exception errors, it is important that you use some form of exception handling in event handlers that handle events from COM objects.

Noções básicas sobre erros de interoperabilidade COMUnderstanding COM interop errors

Sem tratamento de erros, as chamadas de interoperabilidade geralmente geram erros que fornecem pouca informação.Without error handling, interop calls often generate errors that provide little information. Sempre que possível, use o tratamento de erros estruturado para fornecer mais informações sobre problemas quando eles ocorrerem.Whenever possible, use structured error handling to provide more information about problems when they occur. Isso pode ser especialmente útil quando você depura aplicativos.This can be especially helpful when you debug applications. Por exemplo:For example:

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

Você pode encontrar informações como a descrição do erro, HRESULT e a fonte de erros COM examinando o conteúdo do objeto de exceção.You can find information such as the error description, HRESULT, and the source of COM errors by examining the contents of the exception object.

Problemas do controle ActiveXActiveX Control Issues

A maioria dos controles ActiveX que funcionam com o Visual Basic 6,0 funcionam com o Visual Basic .NET sem problemas.Most ActiveX controls that work with Visual Basic 6.0 work with Visual Basic .NET without trouble. As principais exceções são controles de contêiner ou controles que contêm visualmente outros controles.The main exceptions are container controls, or controls that visually contain other controls. Alguns exemplos de controles mais antigos que não funcionam corretamente com o Visual Studio são os seguintes:Some examples of older controls that do not work correctly with Visual Studio are as follows:

  • Controle de quadro do Microsoft Forms 2,0Microsoft Forms 2.0 Frame control

  • Up-Down controle, também conhecido como controle de rotaçãoUp-Down control, also known as the spin control

  • Controle da guia SheridanSheridan Tab Control

Há apenas algumas soluções alternativas para problemas de controle ActiveX sem suporte.There are only a few workarounds for unsupported ActiveX control problems. Você pode migrar controles existentes para o Visual Studio se possuir o código-fonte original.You can migrate existing controls to Visual Studio if you own the original source code. Caso contrário, você pode verificar se os fornecedores de software foram atualizados. Versões compatíveis com NET de controles para substituir controles ActiveX sem suporte.Otherwise, you can check with software vendors for updated .NET-compatible versions of controls to replace unsupported ActiveX controls.

Passando Propriedades ReadOnly de controles ByRefPassing ReadOnly Properties of Controls ByRef

O Visual Basic .NET às vezes gera erros COM, como "Error 0x800A017F CTL_E_SETNOTSUPPORTED", quando você passa ReadOnly Propriedades de alguns controles ActiveX mais antigos como ByRef parâmetros para outros procedimentos.Visual Basic .NET sometimes raises COM errors such as, "Error 0x800A017F CTL_E_SETNOTSUPPORTED", when you pass ReadOnly properties of some older ActiveX controls as ByRef parameters to other procedures. Chamadas de procedimento semelhantes do Visual Basic 6,0 não geram um erro e os parâmetros são tratados como se você os passasse por valor.Similar procedure calls from Visual Basic 6.0 do not raise an error, and the parameters are treated as if you passed them by value. A mensagem de erro Visual Basic .NET indica que você está tentando alterar uma propriedade que não tem um procedimento de propriedade Set .The Visual Basic .NET error message indicates that you are trying to change a property that does not have a property Set procedure.

Se você tiver acesso ao procedimento que está sendo chamado, poderá evitar esse erro usando a ByVal palavra-chave para declarar parâmetros que aceitam ReadOnly Propriedades.If you have access to the procedure being called, you can prevent this error by using the ByVal keyword to declare parameters that accept ReadOnly properties. Por exemplo:For example:

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

Se você não tiver acesso ao código-fonte para o procedimento que está sendo chamado, poderá forçar a propriedade a ser passada por valor adicionando um conjunto extra de colchetes em volta do procedimento de chamada.If you do not have access to the source code for the procedure being called, you can force the property to be passed by value by adding an extra set of brackets around the calling procedure. Por exemplo, em um projeto que tem uma referência ao objeto COM da biblioteca do Microsoft ActiveX Data Objects 2,8, você pode usar:For example, in a project that has a reference to the Microsoft ActiveX Data Objects 2.8 Library COM object, you can use:

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

Implantando assemblies que expõem a interoperabilidadeDeploying Assemblies That Expose Interop

A implantação de assemblies que expõem interfaces COM apresenta alguns desafios exclusivos.Deploying assemblies that expose COM interfaces presents some unique challenges. Por exemplo, um problema potencial ocorre quando aplicativos separados fazem referência ao mesmo assembly COM.For example, a potential problem occurs when separate applications reference the same COM assembly. Essa situação é comum quando uma nova versão de um assembly é instalada e outro aplicativo ainda está usando a versão antiga do assembly.This situation is common when a new version of an assembly is installed and another application is still using the old version of the assembly. Se você desinstalar um assembly que compartilha uma DLL, você poderá torná-la inadvertidamente indisponível para os outros assemblies.If you uninstall an assembly that shares a DLL, you can unintentionally make it unavailable to the other assemblies.

Para evitar esse problema, você deve instalar assemblies compartilhados no GAC (cache de assembly global) e usar um MergeModule para o componente.To avoid this problem, you should install shared assemblies to the Global Assembly Cache (GAC) and use a MergeModule for the component. Se você não puder instalar o aplicativo no GAC, ele deverá ser instalado em CommonFilesFolder em um subdiretório específico da versão.If you cannot install the application in the GAC, it should be installed to CommonFilesFolder in a version-specific subdirectory.

Os assemblies que não são compartilhados devem estar localizados lado a lado no diretório com o aplicativo de chamada.Assemblies that are not shared should be located side by side in the directory with the calling application.

Consulte tambémSee also