none
Consulta sobre la manera correcta de referenciar funciones API de Windows

    Pregunta

  • Veo por la red diversas formas de hacer referencia a las funciones API de Windows en VB.Net, incluso en la declaración de variables veo que indistintamente usan Long, Integer, Int32, UInteger, IntPtr.

    Entiendo que para los identificadores de ventana se debe usar IntPtr.

    Haciendo mil y una pruebas, veo que de varias formas funciona, pero me temo que puede haber problemas durante la ejecución si instalo el programa en otro equipo, dependiendo de la versión del S.O. y de la arquitectura del procesador (si es de 32 o 64 bits).

    De todo lo que he leído, según yo, esta es la manera correcta:

    <DllImport("User32.dll")>
      Private Shared Function IsWindowVisible(Handle As IntPtr) As Boolean
      End Function

    La consulta es, cuál es la manera idónea para no tener inconvenientes con la declaración de variables, la manera más genérica posible.

    martes, 8 de noviembre de 2016 0:15

Respuestas

  • "James-2016" preguntó:

    > La consulta es, cuál es la manera idónea para no tener inconvenientes
    > con la declaración de variables, la manera más genérica posible.

    Digamos que no existe una manera genérica para declarar los diversos tipos de datos de los parámetros de una función de la API de Windows, así como del tipo de dato que ésta retorna. Lo correcto es recurrir a la declaración original de la API, estudiar los tipos de datos que admiten sus parámetros y valor de retorno, y aplicar el tipo de dato de .NET que más se aproxime a ellos.

    > <DllImport("User32.dll")>
    > Private Shared Function IsWindowVisible(Handle As IntPtr) As Boolean
    > End Function

    Para la función que has puesto de ejemplo, nos iríamos a la declaración de la misma:

    IsWindowVisible function

    Y observamos que el único parámetro de entrada es del tipo HWND (un identificador de ventana), por tanto, es correcto pasarle un valor System.IntPtr, que sería el valor devuelto por la propiedad Handle de un formulario o de un control.

    Y en cuanto al valor de retorno, observamos que es el del tipo BOOL, es decir, un valor System.Boolean.

    Podemos decir que, en principio, la declaración que efectúas de la función IsWindowsVisible es correcta, y normalmente va a funcionar tanto en plataformas de 32 como de 64 bits, devolviéndote el valor True/False si la ventana cuyo identificador has especificado está visible o no.

    Pero si en el Análisis de código de tu proyecto has indicado que deseas utilizar las Reglas de corrección extendidas de Microsoft, obtendrás la advertencia del compilador número 1414, que indica Marcar los argumentos P/Invoke booleanos con el atributo MarshalAs.

    Es decir, para dejar de obtener la advertencia 1414, ese valor Boolean que devuelve la función IsWindowsVisible tendrías que declararlo como indico a continuación:

        <DllImport("user32.dll", SetLastError:=True)>
        Private Shared Function IsWindowVisible(Handle As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
        End Function

    Con ello indicamos que el valor 0 será tomado como False, y cualquier otro valor distinto de cero (1, -1, 23, 2938, etc.) se tomará como True, que dicho sea de paso es el valor predeterminado que devolverán los valores BOOL de las funciones de invocación de plataforma (P/Invoke):

    Cálculo de referencias predeterminado para tipos booleanos

    De ahí que tanto si indicas como no el atributo MarshalAs en el valor de retorno de la función, éste te va a devolver un valor de 32 bits (4 bytes), que de ser 0 se tomará como False y distinto de cero se tomará como True. Pero ¿y si deseas que el valor 1 se tome como True y 0 como False, o el valor -1 represente True y el 0 False? Entonces necesitarás especificar el atributo MarshalAs pasándole el tipo de valor Boolean no administrado a partir del cual se van a calcular las referencias de los datos especificados (en el caso de los parámetros de entrada de la función del tipo Boolean) o devueltos (en el caso del valor de retorno Boolean de la función API).

    Que lo dicho. No busques una manera genérica de declarar las funciones de la API de Windows porque unas veces podemos utilizar unos parámetros y otras veces otros, los cuales pueden que sean totalmente correctos para nuestros propósitos. Al final será la experiencia la que te indique cuando tienes que declarar unos tipos y cuando otros. ;-)

    Te dejo un enlace a una página que te puede resultar de utilidad si te encuentras trabajando con las funciones de la API de Windows:

    PINVOKE .NET

    En el menú de la izquierda, selecciona la biblioteca que contiene la función API que deseas utilizar (user32, por ejemplo), y en el submenú que te aparecerá, busca la función API, donde te aparecerá la declaración de la función en C#, Visual Basic .NET y Visual Basic clásico:

    IsWindowVisible (user32)


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    lunes, 14 de noviembre de 2016 20:27
    Moderador