Tutorial: Llamar a las API de Windows (Visual Basic)

Las API de Windows son bibliotecas de vínculos dinámicos (DLL) que forman parte del sistema operativo Windows. Se usan para realizar tareas cuando es difícil escribir procedimientos equivalentes propios. Por ejemplo, Windows proporciona una función denominada FlashWindowEx, que hace que la barra de título de una aplicación pueda alternar entre tonos claros y oscuros.

La ventaja de usar las API de Windows en el código es que pueden ahorrar tiempo de desarrollo, ya que contienen docenas de funciones útiles que ya están escritas y preparadas para su uso. La desventaja es que las API de Windows pueden ser difíciles de manejar y apenas dejan margen si las cosas salen mal.

Las API de Windows representan una categoría especial de interoperabilidad. Las API de Windows no usan código administrado, no tienen bibliotecas de tipos integradas y usan tipos de datos diferentes a los que se usan con Visual Studio. Debido a estas diferencias, y como las API de Windows no son objetos COM, la interoperabilidad con las API de Windows y .NET Framework se realiza mediante la invocación de plataforma o PInvoke. La invocación de plataforma es un servicio que permite que el código administrado llame a funciones no administradas implementadas en archivos DLL. Para más información, consulte Consumir funciones de DLL no administradas. Puede usar PInvoke en Visual Basic mediante la instrucción Declare o aplicando el atributo DllImport a un procedimiento vacío.

Antes, las llamadas API de Windows eran una parte importante de la programación de Visual Basic, pero ahora, con Visual Basic .NET, rara vez son necesarias. Siempre que sea posible, debe usar código administrado de .NET Framework para realizar tareas, en vez de usar las llamadas API de Windows. En este tutorial se proporciona información para aquellas situaciones en las que es necesario usar las API de Windows.

Nota:

Es posible que tu equipo muestre nombres o ubicaciones diferentes para algunos de los elementos de la interfaz de usuario de Visual Studio en las siguientes instrucciones. La edición de Visual Studio que se tenga y la configuración que se utilice determinan estos elementos. Para obtener más información, vea Personalizar el IDE.

Llamadas API mediante Declare (declaraciones)

La forma más habitual de llamar a las API de Windows es con la instrucción Declare.

Para declarar un procedimiento de DLL

  1. Determine el nombre de la función a la que desea llamar, junto con sus argumentos, tipos de argumentos y valor devuelto, así como el nombre y la ubicación de la DLL que la contiene.

    Nota

    Para obtener una información completa sobre las API de Windows, consulte la documentación del SDK de Win32 en la API de Windows del SDK de plataforma. Para más información sobre las constantes que usan las API de Windows, examine los archivos de encabezado, como Windows.h, incluidos con el SDK de plataforma.

  2. Para abrir un nuevo proyecto de aplicación Windows, haga clic en Nuevo en el menú Archivo y después haga clic en Proyecto. Aparecerá el cuadro de diálogo Nuevo proyecto .

  3. Seleccione Aplicación Windows en la lista de plantillas de proyecto de Visual Basic. Se muestra el nuevo proyecto.

  4. Agregue la siguiente función Declare a la clase o al módulo en el que desea usar la DLL:

    Declare Auto Function MBox Lib "user32.dll" Alias "MessageBox" (
        ByVal hWnd As Integer,
        ByVal txt As String,
        ByVal caption As String,
        ByVal Typ As Integer) As Integer
    

Partes de la instrucción Declare

La instrucción Declare incluye los siguientes elementos.

Modificador automático

El modificador Auto indica al tiempo de ejecución que convierta la cadena basada en el nombre del método según las reglas de Common Language Runtime (o en el nombre de alias si se ha especificado).

Palabras clave Lib (biblioteca) y Alias

El nombre que sigue a la palabra clave Function es el nombre que usa el programa para acceder a la función importada. Puede ser el mismo que el nombre real de la función a la que está llamando, o puede usar cualquier nombre de procedimiento válido y, después, emplear la palabra clave Alias para especificar el nombre real de la función a la que está llamando.

Especifique la palabra clave Lib, seguida del nombre y la ubicación de la DLL que contiene la función a la que está llamando. No es necesario especificar la ruta de acceso de los archivos ubicados en los directorios del sistema de Windows.

Use la palabra clave Alias si el nombre de la función a la que está llamando no es un nombre de procedimiento de Visual Basic válido, o si entra en conflicto con el nombre de otros elementos de la aplicación. Alias indica el nombre auténtico de la función a la que está llamando.

Declaraciones de tipos de datos y argumentos

Declare los argumentos y sus tipos de datos. Esta parte puede ser difícil porque los tipos de datos que usa Windows no se corresponden con los tipos de datos de Visual Studio. Visual Basic le ahorra gran parte del esfuerzo al convertir argumentos en tipos de datos compatibles, un proceso denominado serialización. Puede controlar explícitamente cómo se serializarán los argumentos mediante el atributo MarshalAsAttribute definido en el espacio de nombres System.Runtime.InteropServices.

Nota

Las versiones anteriores de Visual Basic le permitían declarar parámetros As Any, por lo que se podían usar datos de cualquier tipo de datos. Visual Basic requiere que use un tipo específico de datos para todas las instrucciones Declare.

Constantes de la API de Windows

Algunos argumentos son combinaciones de constantes. Por ejemplo, la API MessageBox que se muestra en este tutorial acepta un argumento entero denominado Typ, que controla la forma en la que se muestra el cuadro de mensaje. Puede determinar el valor numérico de estas constantes examinando las instrucciones #define del archivo WinUser.h. Los valores numéricos se muestran generalmente en formato hexadecimal, por lo que es posible que quiera usar una calculadora para agregarlos y convertirlos en decimales. Por ejemplo, si desea combinar las constantes del estilo de exclamación MB_ICONEXCLAMATION 0x00000030 y el estilo Sí/No MB_YESNO 0x00000004, puede agregar los números y obtener un resultado de 0x00000034 o 52 decimales. Aunque puede usar directamente el resultado decimal, es mejor declarar estos valores como constantes en la aplicación y combinarlos mediante el operador Or.

Para declarar constantes para las llamadas API de Windows
  1. Consulte la documentación de la función de Windows a la que está llamando. Determine el nombre de las constantes que usa dicha función y el nombre del archivo .h que contiene los valores numéricos de estas constantes.

  2. Use un editor de texto, como el Bloc de notas, para ver el contenido del archivo de encabezado (.h) y busque los valores asociados a las constantes que está usando. Por ejemplo, la API MessageBox usa la constante MB_ICONQUESTION para mostrar un signo de interrogación en el cuadro de mensaje. La definición de MB_ICONQUESTION está en WinUser.h y aparece de la siguiente manera:

    #define MB_ICONQUESTION 0x00000020L

  3. Agregue instrucciones Const equivalentes a la clase o al módulo para que estas constantes estén disponibles para la aplicación. Por ejemplo:

    Const MB_ICONQUESTION As Integer = &H20
    Const MB_YESNO As Integer = &H4
    Const IDYES As Integer = 6
    Const IDNO As Integer = 7
    
Para llamar al procedimiento de DLL
  1. Agregue un botón denominado Button1 al formulario de inicio del proyecto y después haga doble clic en él para ver su código. Se muestra el controlador de eventos del botón.

  2. Agregue código al controlador de eventos Click del botón que agregó para llamar al procedimiento y proporcionar los argumentos adecuados:

    Private Sub Button1_Click(ByVal sender As System.Object,
        ByVal e As System.EventArgs) Handles Button1.Click
    
        ' Stores the return value.
        Dim RetVal As Integer
        RetVal = MBox(0, "Declare DLL Test", "Windows API MessageBox",
            MB_ICONQUESTION Or MB_YESNO)
    
        ' Check the return value.
        If RetVal = IDYES Then
            MsgBox("You chose Yes")
        Else
            MsgBox("You chose No")
        End If
    End Sub
    
  3. Presione F5 para ejecutar el proyecto. El cuadro de mensaje se muestra con los botones de respuesta y No. Haga clic en cualquiera de ellos.

Serialización de datos

Visual Basic convierte automáticamente los tipos de datos de parámetros y valores devueltos de las llamadas API de Windows, pero puede usar el atributo MarshalAs para especificar explícitamente tipos de datos no administrados que una API espera. Para más información sobre la serialización de interoperabilidad, vea Serialización de interoperabilidad.

Para usar Declare y MarshalAs en una llamada API
  1. Determine el nombre de la función a la que desea llamar, junto con sus argumentos, tipos de datos y valor devuelto.

  2. Para simplificar el acceso al atributo MarshalAs, agregue una instrucción Imports a la parte superior del código de la clase o del módulo, como en el ejemplo siguiente:

    Imports System.Runtime.InteropServices
    
  3. Agregue un prototipo de función para la función importada a la clase o al módulo que está usando, y aplique el atributo MarshalAs a los parámetros o al valor devuelto. En el ejemplo siguiente, una llamada API que espera el tipo void* se serializa como AsAny:

    Declare Sub SetData Lib "..\LIB\UnmgdLib.dll" (
        ByVal x As Short,
        <MarshalAsAttribute(UnmanagedType.AsAny)>
            ByVal o As Object)
    

Llamadas API mediante DllImport

El atributo DllImport proporciona una segunda manera de llamar a funciones que están en archivos DLL sin bibliotecas de tipos. DllImport equivale aproximadamente a usar una instrucción Declare, pero da un mayor control sobre la forma de llamar a las funciones.

Puede usar DllImport con la mayoría de las llamadas API de Windows, siempre que la llamada haga referencia a un método compartido (a veces denominado estático). No se pueden usar métodos que requieran una instancia de una clase. A diferencia de las instrucciones Declare, las llamadas DllImport no pueden usar el atributo MarshalAs.

Para llamar a una API de Windows mediante el atributo DllImport

  1. Para abrir un nuevo proyecto de aplicación Windows, haga clic en Nuevo en el menú Archivo y después haga clic en Proyecto. Aparecerá el cuadro de diálogo Nuevo proyecto .

  2. Seleccione Aplicación Windows en la lista de plantillas de proyecto de Visual Basic. Se muestra el nuevo proyecto.

  3. Agregue un botón denominado Button2 al formulario de inicio.

  4. Haga doble clic en Button2 para abrir la vista de código del formulario.

  5. Para simplificar el acceso a DllImport, agregue una instrucción Imports a la parte superior del código de la clase de formulario de inicio:

    Imports System.Runtime.InteropServices
    
  6. Declare una función vacía que preceda a la instrucción End Class para el formulario y asigne un nombre a la función MoveFile.

  7. Aplique los modificadores Public y Shared a la declaración de función y establezca parámetros para MoveFile en función de los argumentos que usa la función de la API de Windows:

    Public Shared Function MoveFile(
        ByVal src As String,
        ByVal dst As String) As Boolean
        ' Leave the body of the function empty.
    End Function
    

    La función puede tener cualquier nombre de procedimiento válido; el atributo DllImport especifica el nombre en la DLL. También controla la serialización de interoperabilidad para los parámetros y los valores devueltos, por lo que puede elegir tipos de datos de Visual Studio similares a los tipos de datos que usa la API.

  8. Aplique el atributo DllImport a la función vacía. El primer parámetro es el nombre y la ubicación de la DLL que contiene la función a la que está llamando. No es necesario especificar la ruta de acceso de los archivos ubicados en los directorios del sistema de Windows. El segundo parámetro es un argumento con nombre, que especifica el nombre de la función en la API de Windows. En este ejemplo, el atributo DllImport obliga a que las llamadas a MoveFile se reenvíen a MoveFileW en KERNEL32.DLL. El método MoveFileW copia un archivo de la ruta de acceso src a la ruta de acceso dst.

    <DllImport("KERNEL32.DLL", EntryPoint:="MoveFileW", SetLastError:=True,
        CharSet:=CharSet.Unicode, ExactSpelling:=True,
        CallingConvention:=CallingConvention.StdCall)>
    Public Shared Function MoveFile(
        ByVal src As String,
        ByVal dst As String) As Boolean
        ' Leave the body of the function empty.
    End Function
    
  9. Agregue código al controlador de eventos Button2_Click para llamar a la función:

    Private Sub Button2_Click(ByVal sender As System.Object,
        ByVal e As System.EventArgs) Handles Button2.Click
    
        Dim RetVal As Boolean = MoveFile("c:\tmp\Test.txt", "c:\Test.txt")
        If RetVal = True Then
            MsgBox("The file was moved successfully.")
        Else
            MsgBox("The file could not be moved.")
        End If
    End Sub
    
  10. Cree un archivo denominado Test.txt y colóquelo en el directorio C:\Tmp del disco duro. Cree el directorio Tmp si es necesario.

  11. Presione F5 para iniciar la aplicación. Aparece el formulario principal.

  12. Haga clic en Button2. Si el archivo se puede mover, se mostrará el mensaje "El archivo se movió correctamente".

Consulte también