2009-06-01 32 views
13

Noto en la documentación de MSDN que hay multiple ways para declarar una referencia a una función en una DLL externa desde un programa VB.NET.DllImport vs Declare en VB.NET

Lo confuso es que MSDN afirma que sólo se puede utilizar la clase DllImportAttribute con prototipos de funciones compartidas "in rare cases", pero no pude encontrar la explicación de esta afirmación, mientras que sólo tiene que utilizar la palabra clave Declare lugar.

¿Por qué son diferentes y dónde usaré cada caso de forma adecuada?

Respuesta

9

Declarar es realmente un intento de mantener una sintaxis P/Invoke que sería más familiar para los usuarios de Visual Basic 6.0 convirtiendo a VB.NET. Tiene muchas de las mismas características que P/Invoke, pero la clasificación de ciertos tipos, en particular las cadenas, son muy diferentes y pueden causar confusión a las personas más familiarizadas con las reglas de DllImport.

No estoy del todo seguro de lo que la documentación alude con la distinción "raro". Uso DllImport en mi código frecuentemente desde VB.NET y C# sin problema.

En general, usaría DllImport sobre Declare a menos que provenga de un fondo de Visual Basic 6.0. La documentación y las muestras para DllImport son mucho mejores y hay muchas herramientas destinadas a generar declaraciones DllImport.

6

En mi opinión, dado que esta palabra clave no se ve depreciada, etc. de lo que busqué, simplemente use palabras clave en tiempo de compilación en lugar de atributos.

Además, cuando utiliza Declare, no es necesario que escriba End Function. La ventaja de esto es que puede crear un módulo completo de declaraciones de funciones importadas línea por línea, sin necesidad de pulular su código con DllImport sy End Function s.

Cuando declara utilizando la palabra clave Declare, el compilador trata esta función como Shared de todos modos, por lo que se puede acceder a través de otros objetos extenal.

Pero creo que en el actual VB.NET ambos están dirigidos al mismo objetivo y no hay diferencia de rendimiento, no hay garantía en este caso.

Así que mi conclusión es: no utilizar la declare en lugar de DllImport, especialmente la lectura de lo que usted ha citado Microsoft stated que se debe utilizar en casos raros.

16

Aparentemente, las declaraciones Declare y DllImport son básicamente las mismas. Puede usar el que prefiera.

A continuación se presenta una discusión de los pocos puntos que pueden funcionar de manera diferente en cada uno, que pueden influir en la preferencia por uno sobre el otro:

Empecé con un artículo de MSDN en relación con Visual Studio 2003 titulado Using the DllImport Attribute. (Un poco viejo, pero dado que la declaración de DllImport parece haberse originado en .NET, parecía apropiado volver al principio.)

Con un ejemplo comunicado DllImport de:

[DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = Unicode)] 
int MessageBox(void* hWnd, wchar_t* lpText, wchar_t* lpCaption, unsigned int uType); 

Se dice que si el valor EntryPoint se deja fuera, el CLR buscará el nombre de la función (de mensaje, en este caso) como por defecto . Sin embargo, en este caso, dado que se especificó un CharSet de Unicode, el CLR buscaría PRIMERO una función llamada "MessageBoxW" - la 'W' indica un tipo de retorno Unicode. (La versión del tipo de retorno ANSI sería "MessageBoxA".) Si no se encontrara "MessageBoxW", ENTONCES el CLR buscaría una función API realmente llamada "MessageBox".

detalles actuales acerca de la clase DllImportAttribute se pueden encontrar aquí, donde vi la versión de .NET Framework 4: DLLImportAttribute Class

Un comentario clave en la sección Comentarios de este .NET Framework 4 es la página que:

Aplica este atributo directamente a las definiciones de métodos C# y C++; sin embargo, el compilador de Visual Basic emite este atributo cuando usa la instrucción Declare.

Por lo tanto, al menos en lo que respecta a VB.NET, el compilador termina con una declaración Declare de todos modos.

También hay una nota importante en esta página:

El DllImportAttribute no admite el cálculo de referencias de tipos genéricos.

Por lo tanto, parece que si desea utilizar un tipo genérico, tendría que utilizar una declaración Declare.

A continuación, me dirigí a la información de declaración Declare. Una versión de Visual Studio 2010 (Visual información instrucción básica) era aquí: Declare Statement

Un elemento clave en este caso era esta nota:

Puede utilizar Declarar sólo a nivel de módulo. Esto significa que el contexto de declaración para una referencia externa debe ser una clase, estructura o módulo, y no puede ser un archivo fuente, espacio de nombres, interfaz, procedimiento o bloque.

Al parecer, si desea establecer una llamada a la API fuera de una clase, estructura o módulo, que tendrá que utilizar la instrucción DllImport en lugar de la Declare.

El ejemplo Declare declaración de esta página es:

Declare Function getUserName Lib "advapi32.dll" Alias "GetUserNameA" (
    ByVal lpBuffer As String, ByRef nSize As Integer) As Integer 

Siguiendo ese ejemplo es esta golosina poco de información:

El DllImportAttribute proporciona una forma alternativa de uso de funciones en código no administrado. El siguiente ejemplo declara una función importada sin usar una declaración Declare.

seguidos, por supuesto, de un ejemplo del uso de DllImport.

Respecto a los resultados Unicode vs ANSI, según esta página Declare, si especifica un valor CharSet (disponible en Declare, pero no en el ejemplo anterior) CLR hará el mismo tipo de búsqueda automática que DllImport - para Unicode o ANSI.

Si no se especifica un valor CharSet en la declaración Declare, entonces debe asegurarse de que su nombre de función en la declare es el mismo que el nombre de la función en el archivo de cabecera de la función API actual, o debe specifiy un Alias valor que coincide con el nombre de la función real en el archivo de encabezado (como se muestra en el ejemplo anterior).

No pude encontrar ninguna documentación específica de Microsoft que indique que DllImport o Declare fueron preferidos, o incluso recomendados, entre sí en cualquier situación que no sean las mencionadas anteriormente.

Mi conclusión, por tanto, es:

1) A menos que se han de fijar su definición en uno de los lugares una declaración Declare no se puede utilizar, ya sea técnica funcionará bien,

y

2) si está utilizando DllImport, asegúrese de especificar el valor CharSet que desea (Unicode o ANSI), o puede obtener resultados inesperados.

+3

Este es un gran artículo escrito y una gran investigación. ¡Muchas gracias! – Mike

1

Si necesita establecer una de las siguientes opciones, utilice el atributo DllImportAttribute, o use Declare. De https://msdn.microsoft.com/en-us/library/w4byd5y4.aspx

Para aplicar el BestFitMapping, CallingConvention, ExactSpelling, campos PreserveSig, SetLastError o ThrowOnUnmappableChar a una declaración Microsoft Visual Basic 2005, se debe utilizar el atributo DllImportAttribute en lugar de la instrucción Declare.

No está claro a partir de la referencia anterior solo si esto se aplica solo a "Visual Basic 2005" o no, ya que la referencia anterior es de un artículo de .NET 4.5. Sin embargo, también me encontré con este artículo (https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.dllimportattribute(v=vs.110).aspx), que es específico de la clase DllImportAttribute en .NET 4.5:

el compilador de Visual Basic emite este atributo cuando se utiliza la instrucción Declare. Para definiciones de métodos complejos que incluyen BestFitMapping, CallingConvention, ExactSpelling, PreserveSig, SetLastError o campos ThrowOnUnmappableChar, aplicar este atributo directamente a definiciones de métodos de Visual Basic.

Esto le indica que la opción Declare es el azúcar sintáctica VB.net que se convierte en DllImportAttribute en tiempo de compilación, y describe los escenarios exactos cuando se utiliza directamente DllImportAttribute se recomienda.