Ventanas.  virus  Cuadernos.  Internet.  oficina.  Utilidades.  Conductores

Este artículo está dirigido a novatos en programación C++ como yo que, por casualidad o por deseo, decidimos aprender WinAPI.
Solo quiero advertirte:
No pretendo ser un gurú de C++ o WinAPI.
Solo estoy aprendiendo y quiero dar aquí algunos ejemplos y consejos que me facilitan el aprendizaje de las funciones y mecanismos de WinAPI.

En este artículo, asumo que ya está lo suficientemente familiarizado con C ++ para poder crear clases y sobrecargar varios operadores para ellas, y que ya ha "ocultado" algunos de sus mecanismos en una clase.

Creación y uso de una consola

Para depurar una aplicación Win32 o simplemente para ver cómo va todo dentro, siempre uso la consola.
Dado que está creando una aplicación GUI, no una aplicación de consola, la consola no está conectada. Para poder llamarlo en las entrañas de Internet se encontró este código

Si (AllocConsole())
{



estándar::ios::sync_with_stdio();
}
Para mayor comodidad, le aconsejo que lo envuelva en una función. Por ejemplo:
anular CreateConsole()
{
si (AllocConsole())
{
int hCrt = _open_osfhandle((largo)GetStdHandle(STD_OUTPUT_HANDLE), 4);
*salida estándar = *(::_fdopen(hCrt, "w"));
::setvbuf(salida estándar, NULL, _IONBF, 0);
*stderr = *(::_fdopen(hCrt, "w"));
::setvbuf(stderr, NULL, _IONBF, 0);
estándar::ios::sync_with_stdio();
}

La consola llamada funciona solo en modo de salida y funciona de la misma manera que en las aplicaciones de consola. Información de salida como de costumbre - cout/wcout.
Para que este código funcione, los siguientes archivos deben estar incluidos en el proyecto:
#incluir
#incluir #incluir
e incluya el espacio de nombres estándar en el espacio de nombres global:
utilizando el espacio de nombres estándar;
Por supuesto, si no desea hacer esto, simplemente agregue std:: a todas las entidades que se encuentran en él.

Herencia de objetos para salida y aritmética. operaciones

Al crear y estudiar las propias "ventanas", siempre necesitaba enviar algún valor a la consola.
Por ejemplo:
Obtiene el tamaño del área de cliente de la ventana utilizando la función GetClientRect, donde la dirección del objeto de la estructura RECT se pasa como un parámetro para llenar este objeto con datos. Si necesita saber el tamaño del área de cliente recibida, simplemente puede imprimirlo en la consola ya conectada

salida<

Pero hacer esto cada vez (especialmente si a menudo tiene que hacer algo como esto) es muy inconveniente.
Aquí es donde la herencia viene al rescate.
Cree una clase que herede públicamente de la estructura RECT y sobrecargue el operador de salida<< так, как вам угодно.
Por ejemplo:

Clase newrect:public RECT
{
público:
flujo amigo y operador<<(ostream &strm,newrect &rect)
{
strm<<"Prtint RECT object:\n";
strm<cadena de retorno;
}
};

Ahora solo genera el objeto con cout/wcout:

salida<

Y todo se le mostrará en una forma conveniente según lo necesite.
Puede hacer lo mismo con cualquier operador que necesite.
Por ejemplo, si necesita comparar o asignar estructuras (digamos el mismo RECT o POINT), sobrecargue operator==() y operator=() respectivamente.
Si desea implementar menos que el operador< что бы быстро сравнивать размеры окна и т.д. перегрузите operator<().
Puede hacer esto, supongo, con casi cualquier estructura, y lo más importante, todas las funciones que funcionan con un objeto de estructura RECT regular también funcionarán bien con su sucesor.
Y también recomiendo poner toda esta belleza en un archivo de complemento separado y usarlo si es necesario.

clase propia

No sé los demás, pero como estoy completamente verde, decidí crear un nuevo proyecto para cada función estudiada o para cada capítulo / subcapítulo del libro, para que todo estuviera en los estantes y yo Podría volver en cualquier momento y refrescar los puntos necesarios en mi memoria.
Dado que en WinAPI, incluso para crear la ventana más simple, debe completar la estructura de clase, registrarla y escribir un procedimiento de ventana trivial, después del tercer o cuarto proyecto recordé que todavía escribo en C ++.
Al final, escondí todo en una clase simple. El identificador de la ventana, su nombre, el nombre de la clase, la dirección del procedimiento de la ventana, la clase de la ventana (WNDCLASS) están ocultos en la sección privada de la clase.
Para obtenerlos, basta con describir métodos Get simples, por ejemplo:
HWND ObtenerHWND()
LPCTSTR GetClsName() etc.
Llenar y registrar la clase de ventana, crear la ventana en sí y mostrarla se realiza en el constructor.
Para mayor comodidad, puede sobrecargar el constructor y ocultar el llenado y el registro de la clase de ventana en una función de clase privada separada y llamarla en cada uno de los constructores. La conveniencia de la sobrecarga es que a veces necesito crear una ventana muy simple y llamo al constructor con dos parámetros: el nombre de la ventana y la instancia de la aplicación.
Otras veces necesito crear una ventana con un tamaño específico, no el procedimiento de ventana predeterminado, y algún otro estilo definido: llamo al constructor con los parámetros asociados.
Tengo esta clase definida en un archivo de inclusión separado, que se encuentra en la carpeta de inclusión del IDE.
Una plantilla para tal clase:
clase BaseWindow
{
WNDCLASSEX_wcex;
TCHAR_nombre_clase;
TCHAR_nombreVentana;
HWND_hwnd;
bool_Creación de ventana();
público:
BaseWindow(LPCTSTR windowName,HINSTANCE hInstance,DWORD style,UINT x,UINT y,UINT height,UINT width);
BaseWINdow(LPCTSTR windowName,HINSTANCE hInstance);
const HWND ObtenerHWND() const(retornar HWND;)
LPCTSTR GetWndName()const(return _windowName;)
};

Una vez que piense detenidamente y escriba una clase de este tipo, hará su vida más fácil y pasará más tiempo aprendiendo y perfeccionando sus habilidades que escribiendo lo mismo cada vez. Además, lo considero muy útil: hacer una clase de este tipo usted mismo y complementarla según sea necesario.

PD

Todo lo anterior es cierto para:
Plataforma - Windows 7 32 bits
IDE-Visual Studio 2010
Tal vez algunos de estos consejos causen risa e ironía, pero aún así, todos alguna vez fuimos novatos / pasantes / juniors de alguna manera.
Le pido que trate la publicación con comprensión. La crítica constructiva es, por supuesto, bienvenida.

¡Finalmente! ¡Finalmente! Hoy comenzaremos a crear una ventana de Windows completa. Adiós miserable consola!!!

En este punto, ya debería tener un buen conocimiento de la sintaxis de C ++, poder trabajar con bifurcaciones y bucles, y tener una buena comprensión de cómo funcionan las funciones. Si has dominado una batalla naval, puedes considerar que has aprendido todo esto.

notación húngara

Todo el código que encontraremos en WinAPI está escrito en húngaro. Es una convención de codificación.

En este caso, el nombre de la variable va precedido de la letra inicial del tipo. Todas las palabras en los nombres de variables y funciones comienzan con una letra mayúscula.

Aquí hay algunos prefijos:

b - variable de tipo bool.
l es una variable de tipo entero largo.
w - de la palabra (palabra) - 16 bits. Variable de tipo corto sin signo.
dw - de doble palabra (doble palabra) - 32 bits. Variable de tipo unsigned long.
sz - cadena terminada en cero. Solo una cuerda regular que usamos todo el tiempo.
p o lp - puntero (del puntero). lp (del puntero largo): estos punteros han pasado del pasado. Ahora lp y p significan lo mismo.
h - descriptor (del identificador).

Por ejemplo, el puntero se llamaría así:

vacío*pData;

Microsoft utiliza esta notación. Muchos critican esta forma de nombrar las variables. Pero cosas como esta (convenciones de codificación) son vitales en las grandes empresas.

Permítame recordarle que los identificadores constantes generalmente consisten solo en letras mayúsculas: WM_DESTROY. WM_DESTOY es 2, la constante se define a través de define.

Además, winAPI usa muchos tipos anulados. Aquí, en esta página, http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx, puede encontrar descripciones de todos los tipos de Windows (en inglés).

Y una cosa más que no entendimos. A los punteros a menudo se les asigna el valor NULL. Piense en ello como solo 0 y los punteros que se establecen en NULL (cero) no apuntan a ninguna ubicación de memoria.

API de Windows (WinAPI)

Todos los programas de Windows utilizan una interfaz de programación WinAPI especial. Es un conjunto de funciones y estructuras C que hacen que su programa sea compatible con Windows.

La API de Windows tiene enormes capacidades para trabajar con el sistema operativo. Incluso se podría decir ilimitado.

No cubriremos ni el uno por ciento de todas las características de WinAPI. Inicialmente, quería tomar más material, pero tomaría demasiado tiempo, y empantanado en el pantano de WinAPI, llegaríamos a DirectX en un par de años. La descripción de WinAPI tomará dos lecciones (incluida esta) En ellos, consideraremos solo el marco de aplicación bajo Windows.

Un programa de Windows, al igual que un programa de DOS, tiene una función principal. Aquí esta función se llama WinMain.

Función WinMain

El programa de Windows consta de las siguientes partes (todo esto sucede dentro de WinMain):

Cree y registre una clase de ventana. No confundir con las clases de C++. WinAPI está escrito en C, no hay clases en el sentido habitual de la palabra para nosotros.
Creación de una ventana de programa.
El bucle principal en el que se procesan los mensajes.
Manejo de mensajes de programa en un procedimiento de ventana. Un procedimiento de ventana es una función normal.
Estos cuatro puntos son la base del programa de Windows. Durante esta lección y la próxima, analizaremos todo esto en detalle. Si se confunde con la descripción del programa, vuelva a estos puntos.

Ahora veamos todo esto en detalle:

WinAPI: estructura WNDCLASS

En primer lugar, debe crear y completar la variable estructural WNDCLASS y luego registrar la clase de ventana en función de ella.

Así es como se ve esa estructura:

codigo c++ typedef struct ( estilo UINT; // estilo de ventana WNDPROC lpfnWndProc; // puntero a procedimiento de ventana int cbClsExtra; // bytes adicionales después de la clase. Siempre establecido en 0 int cbWndExtra; // bytes adicionales después de la instancia de la ventana. Siempre establecido en 0 HINSTANCE hInstance ; // instancia de la aplicación Pasada como parámetro a WinMain HICON hIcon; // icono de la aplicación HCURSOR hCursor; // cursor de la aplicación HBRUSH hbrBackground; // color de fondo LPCTSTR lpszMenuName; // nombre del menú LPCTSTR lpszClassName; // nombre de la clase ) WNDCLASS, * PWNDCLASE;

La estructura WNDCLASS en WinAPI define las propiedades básicas de la ventana creada: iconos, el tipo de cursor del mouse, si la ventana tiene un menú, a qué aplicación pertenecerá la ventana...

Después de completar esta estructura, puede registrar una clase de ventana basada en ella. No se trata de clases como en C++. Más bien, podemos considerar que la clase de ventana es una plantilla de este tipo, la registró en el sistema y ahora se pueden crear varias ventanas basadas en esta plantilla. Y todas estas ventanas tendrán las propiedades que definiste en la variable de estructura WNDCLASS.

WinAPI: función CreateWindow

Después de registrar la clase de ventana, se crea la ventana principal de la aplicación sobre esta base (ahora hemos pasado al segundo punto). Esto se hace usando la función CreateWindow. Tiene el siguiente prototipo:

codigo c++ HWND CreateWindow(LPCTSTR lpClassName, // nombre de clase LPCTSTR lpWindowName, // nombre de ventana (mostrado en la barra de título) DWORD dwStyle, // estilo de ventana int x, // coordenada horizontal desde el borde izquierdo de la pantalla int y, // coordenada vertical desde int nWidth, // ancho de ventana int nHeight, // alto de ventana HWND hWndParent, // ventana principal HMENU hMenu, // identificador de menú HINSTANCE hInstance, // instancia de aplicación LPVOID lpParam // parámetro; siempre establecido en NULL);

Si en la clase de ventana (estructura WNDCLASS) se establecen las propiedades básicas de la ventana, entonces aquí, más específico para cada ventana: tamaño de ventana, coordenadas ...

Esta función devuelve un identificador de ventana. Con la ayuda del descriptor, puede referirse a la ventana, es como un identificador.

Tenga en cuenta que hay muchos tipos nuevos aquí. De hecho, son todos viejos, recién redefinidos. Por ejemplo: HWND es una anulación del tipo HANDLE, que a su vez es una anulación de PVOID, que a su vez es una anulación de void*. ¡Cuán profunda es la verdad! Pero aún así, el tipo HWND es un puntero para anular.

La ventana consta de varias partes. En casi todos los programas verá: el título de la ventana, el menú del sistema (si hace clic en el icono de la aplicación en la parte superior izquierda de la ventana), tres botones del sistema para trabajar con la ventana: minimizar, maximizar y cerrar. Además, casi siempre en la aplicación hay un menú. Eso es solo lo último que definitivamente no haremos. Y, por supuesto, la mayor parte de la ventana está ocupada por los llamados. el área de cliente donde trabaja habitualmente el usuario.

Se trata del modo ventana. Durante mucho tiempo practicaremos con DiectX en una ventana, no usaremos el modo de pantalla completa.

Manejo de mensajes

La principal diferencia de todos nuestros programas anteriores de los programas bajo Windows es el manejo de mensajes.

Por ejemplo, cuando el usuario presiona una tecla en el teclado, se genera un mensaje de que se ha presionado una tecla. Luego, este mensaje se envía a la aplicación que estaba activa cuando el usuario presionó la tecla.

Aquí tenemos un evento (evento): se presionó una tecla.

Un evento puede ser: mover el cursor del mouse, cambiar el enfoque de la aplicación, presionar una tecla del teclado, cerrar una ventana. Hay muchos eventos. ¡Muy! En un segundo pueden ocurrir decenas de eventos en el sistema operativo.

Entonces, cuando ocurre un evento, el sistema operativo crea un mensaje: se presionó tal tecla, se cambiaron las coordenadas del cursor del mouse, se abrió una nueva ventana.

Los mensajes pueden ser creados tanto por el sistema operativo como por varias aplicaciones.

El mensaje es una estructura, y se ve así:

codigo c++ typedef struct tagMSG ( HWND hwnd; // ventana que recibirá este mensaje UINT mensaje; // código de mensaje WPARAM wParam; // parámetro LPARAM lParam; // parámetro DWORD time; // hora en que ocurrió el mensaje POINT pt; // coordenadas mouse cursor ) MENSAJE;

Observe cómo los typedefs redefinen las estructuras.

Para crear esta estructura, puede utilizar el siguiente código:

codigo c++ mensaje.mensaje == 2; // estas dos lineas son equivalentes ya que msg.message == WM_DESTROY; // la constante WM_DESTROY es igual a dos

Aquí, el campo que contiene el código del mensaje (nombre del mensaje se compara con la constante WM_DESTROY. WM - de Windows Message (mensaje de Windows). WM_DESTROY - este es el mensaje que se genera cuando se cierra la ventana (destruir - destruir).

Los códigos de mensaje se definen mediante constantes y tienen el prefijo WM_: WM_CLOSE, WM_CREATE, etc.

La estructura MSG contiene el tipo HWND - from Window Handle (manejador de ventana o identificador de ventana). Es tal pieza la que "describe" una ventana. Esto es algo así como un identificador (nombre de ventana).

Recuerde esta palabra: manejar (descriptor, descriptor). En Windows, este concepto se usa muy a menudo. Casi todos los tipos de Windows que comienzan con H son descriptores: descriptor de icono, descriptor de fuente, descriptor de instancia de aplicación. Hay treinta de ellos por lo que recuerdo.

Todas las interacciones entre aplicaciones en Windows se realizan utilizando estos mismos descriptores de ventana (HWND).

Hay otro descriptor importante: el descriptor de la aplicación (HINSTANCE, el primer parámetro de WinMain): este es un identificador de aplicación único, gracias al cual el sistema operativo no puede confundir dos programas diferentes. Es como un código de barras. Lo revisaremos más tarde.

Cada vez que el usuario realiza alguna acción, se crea y se completa un mensaje: se establece el identificador de la ventana que debe recibir este mensaje, se establece el identificador del mensaje, se completan los parámetros, se completa la hora (actual) y se indican las coordenadas del cursor del ratón (ver estructura).

Luego, el mensaje se coloca en la cola de mensajes del sistema operativo. Cuando la cola llega a nuestro mensaje, se envía a la ventana deseada (windows sabe a qué ventana enviar cada mensaje gracias a los descriptores). Cuando un mensaje llega a una aplicación, se coloca en la cola de mensajes de la aplicación. Tan pronto como la cola lo alcanza, se procesa.

Mire, entre el momento en que el usuario realizó alguna acción (ocurrió un evento y se generó un mensaje) y el momento en que el programa reaccionó a esta acción (el mensaje fue procesado por el programa), ocurren muchos eventos. Después de todo, tanto en la cola de mensajes de Windows como en la cola de mensajes de la aplicación, puede haber muchos mensajes. En el primer caso, podemos hablar de cientos, en el segundo caso, al menos de unos pocos.

Procedimiento de ventana (Procedimiento de ventana - WndProc)

Continuamos desde el momento en que el mensaje ingresó a la cola de mensajes de la aplicación. Tan pronto como la cola lo alcanza, se procesa. Para procesar mensajes en cada programa, debe haber una función especial: un procedimiento de ventana. Por lo general, se llama WndProc (por Procedimiento de ventana). La llamada al procedimiento de ventana se encuentra en el bucle del programa principal y se ejecuta en cada iteración del bucle.

Los mensajes (en forma de variables MSG estructurales) ingresan a esta función en forma de parámetros: un identificador de ventana, un identificador de mensaje y dos parámetros. Tenga en cuenta que los campos time y pt no se pasan al procedimiento de ventana. Es decir, el mensaje ya está "analizado".

Dentro del procedimiento de ventana, hay una rama de cambio, en la que se verifica el identificador del mensaje. Aquí hay un ejemplo de un procedimiento de ventana simple (es completamente funcional):

codigo c++// ignorar HRESULT y __stdcall por ahora. Los veremos más adelante HRESULT __stdcall WndProc(HWND hWnd, UINT mensaje, WPARAM wParam, LPARAM lParam) ( switch (mensaje) ( case WM_PAINT: // código de procesamiento de mensajes WM_PAINT return 0; case WM_DESTROY: // código de procesamiento de mensajes WM_DESTROY return 0; ) // controlador para todos los demás mensajes )

Y el último es el bucle principal. El es muy simple. Cada iteración del bucle comprueba la cola de mensajes de la aplicación. Si hay un mensaje en la cola de mensajes, se extrae de la cola. Luego, en el cuerpo del ciclo, se llama a un procedimiento de ventana para procesar el mensaje tomado de la cola.

Eso, en general, es todo por hoy. Ya está claro que un programa bajo WinAPI es mucho más complicado que un programa bajo DOS. Como escribí anteriormente, en la próxima lección analizaremos el código de un programa en funcionamiento.

Como ejercicio, cree un nuevo proyecto. En la ventana Nuevo proyecto, seleccione la plantilla (plantilla) - Win32Project (hasta ahora hemos elegido Aplicación de consola Win32). En una de las siguientes ventanas, no marque la casilla Proyecto vacío (un proyecto vacío) y el IDE generará un programa en blanco.

Si observa detenidamente el código en el archivo project_name.cpp, encontrará todas las cosas que discutimos: la variable de estructura MSG, completar la estructura WNDCLASS, crear la ventana con la función CreateWindow, el bucle principal del programa. Además, la función WndProc está definida en el archivo. Procesa varios mensajes en las ramas del interruptor: WM_COMMAND, WM_PAINT, WM_DESTROY. Encuéntrelo todo en el archivo.

Además de lo que hemos considerado, el programa contiene mucho código adicional. En el próximo número, veremos el código del programa, en el que se eliminará todo lo superfluo. Será mucho más simple y claro que lo que genera el IDE.

API (interfaz de programación de aplicaciones) es una interfaz de programación de aplicaciones, un término mencionado a menudo por los desarrolladores de software. Si la aplicación que está desarrollando tiene una función que le permite acceder a ella desde otras aplicaciones, esta es la API de su aplicación. Los parámetros que toma su función forman su API, ya que son los medios por los cuales otras aplicaciones interactúan con la función.

El sistema operativo Windows proporciona un gran conjunto de características que permiten que varias aplicaciones, incluidas las aplicaciones de Visual FoxPro, se comuniquen con Windows a un nivel bastante bajo. Estas funciones se conocen comúnmente como la API de Windows. El uso de la API de Windows en las aplicaciones de Visual FoxPro le permite implementar características que son inalcanzables para las herramientas de lenguaje estándar.

Declaración de funciones de la API de Windows en Visual FoxPro

Las funciones de la API de Windows están vinculadas a bibliotecas vinculadas dinámicamente (Biblioteca de vínculos dinámicos, DLL). Por regla general, los archivos de tales bibliotecas tienen la extensión dll. Antes de usar una función API de Windows en su aplicación, debe anunciar. El comando DECLARE..DLL se usa para declarar una función:

DECLARAR[ cFunctionType] Nombre de la función EN LibraryName ; [cParamType1 [@] ParamName1, cParamType2 [@] ParamName2, ...]

Opciones de comando:

cFunctionType
parámetro opcional, especifica el tipo de datos devueltos por la función:

cFunctionType Tamaño,
byte
Descripción
corto entero de 16 bits
Entero, largo 4 entero de 32 bits
Soltero 4 número real de 32 bits
Doble 8 número real de 64 bits
Cadena - Cadena de caracteres

Nombre de la función
el nombre de la función en la DLL. El nombre de la función distingue entre mayúsculas y minúsculas, lo que significa que GetDC y GETDC son nombres de funciones completamente diferentes.

LibraryName
el nombre de la DLL que contiene la función. Para las bibliotecas Kernel32.dll, Gdi32.dll, User32.dll, Mpr.dll y Advapi32.dll, puede usar el sinónimo WIN32API.

Apodo
parámetro opcional, le permite usar su propio alias en lugar del nombre de la función. La ortografía de un alias, a diferencia del nombre de una función, no distingue entre mayúsculas y minúsculas. Normalmente, se utiliza un alias cuando el nombre de la API de la función coincide con el nombre de una función de Visual FoxPro integrada (o la suya).

cParamType
especifica el tipo de datos del valor pasado a la función:

El parámetro se puede pasar tanto por valor como por referencia. El carácter "@" se utiliza para indicar que un parámetro se pasa por referencia.

Desde la perspectiva de Visual FoxPro, no hay diferencia entre los tipos de datos Long e Integer. Normalmente, el tipo Integer se usa para representar enteros con signo y el tipo Long se usa para representar enteros sin signo.

ParamName
parámetro opcional, es puramente descriptivo y generalmente se ignora.

Todas las funciones de la API de Windows, así como el propio Windows, están escritas en el lenguaje de programación C. Por lo tanto, para comprender cómo usar correctamente las funciones API en Visual FoxPro (que, por cierto, también está escrito en C, al menos en su núcleo), conozcamos qué tipos de datos se usan en C y Windows, y , no menos importante, tratemos tipos de datos como enumeraciones, estructuras y punteros. Además, aprenderá qué son los prototipos de función en C y cómo, según la descripción de un prototipo de función en MSDN, declararlo correctamente en el comando DECLARE..DLL.

Tipos de datos básicos de C

Si está familiarizado con el lenguaje de programación C, sabrá lo fácil que es crear varios tipos de datos en él. Basta con escribir el siguiente código:

Typedef int INT32;

y aquí tienes un nuevo tipo INT32, que corresponde totalmente al tipo int. Pero desde el punto de vista de C, estos son tipos completamente diferentes, ¡e intentar asignar una variable de tipo INT32 a una variable de tipo int resultará en un error!

La abundancia de tipos de datos hace que muchos desarrolladores piensen que la programación de API es difícil. ¡Pero no lo es! En C, se utilizan principalmente los siguientes tipos de datos:

    tipo carbonizarse - carácter en formato ANSI. Tiene una longitud de 8 bits (un byte).

    tipo wchar - carácter en formato Unicode. Tiene una longitud de 16 bits (dos bytes).

    tipo En t - números enteros. Se dividen en tres tipos en C: En t, corto Y largo tiempo. Estos últimos suelen abreviarse como corto Y largo. Tipo corto es de 16 bits y tipos En t Y largo- Enteros de 32 bits.

    tipo flotar son números reales con parte fraccionaria. Tienen una longitud de 32 bits (4 bytes).

    tipo doble- Números reales de doble precisión. Tienen una longitud de 64 bits (8 bytes).

    tipo enumeración - tipo de datos enumerados.

    tipo vacío se usa para denotar cantidades que tienen longitud cero y no tienen valor.

    tipo puntero - puntero; no contiene información en el sentido convencional, como otros tipos de C; en cambio, cada puntero contiene la dirección de la ubicación de la memoria donde se almacenan los datos reales. Tiene una longitud de 32 bits (4 bytes).

Por extraño que parezca, no hay ningún tipo de cadena en C. De hecho, todas las cadenas se representan en C como matrices de caracteres.

Algunos tipos pueden declararse como sin firmar. modificador no firmado (sin firmar) se utiliza con los siguientes tipos de datos: carbonizarse, corto, En t Y largo.

Por ejemplo, la siguiente declaración de variable en C:

Int firmado nombre de la variable;

significa que esta variable es un entero de 32 bits sin signo.

modificador constante indica que una variable del tipo especificado es una constante, es decir, su valor no se puede cambiar.

tipo enumerado enumeración asocia un conjunto de constantes con nombre, denominadas constantes enumeradas, con una variable. Una declaración de tipo enumerado se ve así:

enumeración etiqueta_campo { const1, const2, ... } variable;

Si etiqueta_campo se omite, luego de la llave de cierre, debe especificar variable. Si etiqueta_campo indicado, luego no indicado variable.

Históricamente, el tipo enumerado es equivalente al tipo int, es decir, una variable de tipo enumerado ocupa 4 bytes en la memoria. Cada constante enumerada tiene un valor determinado por su número de serie en la lista; la numeración comienza desde cero. Considere la enumeración CombineMode:

Enum CombineMode( CombineModeReplace, CombineModeIntersect, CombineModeUnion, CombineModeXor, CombineModeExclude, CombineModeComplement );

En esta enumeración, la constante CombineModeReplace tiene el valor 0, la constante CombineModeIntersect tiene el valor 1 y así sucesivamente; la constante CombineModeComplement es 5.

Los valores de las constantes enumeradas se pueden especificar explícitamente, como en el siguiente ejemplo:

Enum DashCap( DashCapFlat = 0, DashCapRound = 2, DashCapTriangle = 3 );

Los tipos de datos enumerados cubren el 99 % de todos los tipos de datos utilizados en la programación de la API de Windows. Suena demasiado fácil, ¿no? ¿Por qué las descripciones de las funciones API contienen todos estos tipos: HWND, HINSTANCE, POINT y similares?

La razón de esto es que C tiene una característica llamada tipeo estricto. Una vez introducida, una variable del mismo tipo solo puede tomar valores que coincidan con su tipo. No puede almacenar una cadena en una variable primero y luego asignarle un número. En Visual FoxPro, normalmente intentamos simular esto a través de convenciones de nomenclatura. Por ejemplo, cName es una variable de tipo carácter, mientras que nCount es de tipo numérico. Escritura estricta le permite crear un nuevo tipo de datos dando un nuevo nombre a un tipo de datos existente. Cada nuevo tipo parece ser diferente de los otros tipos, aunque almacenan lo mismo internamente.

Windows hace que este concepto sea más difícil de usar. Por ejemplo, el tipo LONG es en realidad un int largo, mientras que el tipo UINT es en realidad un int sin signo. Ambos tipos son enteros de 32 bits. Los tipos de datos derivados se definen en varios archivos de inclusión (archivos con la extensión .h). Si compró Visual Studio .NET, puede encontrar estos archivos en la carpeta ..\VC7\PlatformSDK\Include\.

Tipos de datos de Windows

Determinar cuál de los tipos base de C representa realmente el tipo de datos utilizado en una función de API es una de las tareas más difíciles en la programación de API. Usa la siguiente regla: si no puedes encontrar una palabra flotar, doble, char o calle en cualquier parte del nombre de una función o parámetro, generalmente es un número entero de 32 bits. Tomará algún tiempo comprender y desarrollar habilidades, pero luego convertirá fácilmente los tipos de datos. La siguiente tabla enumera los principales tipos de datos de Windows y sus tipos correspondientes utilizados al declarar una función en Visual FoxPro:

Tipo de datos
ventanas
Escriba la declaración
funciones
Descripción
BOOL Largo entero de 32 bits. 0 significa falso, todo lo demás significa verdadero.
BOOLEANO Largo igual que BOOL.
BYTE Cadena entero de 8 bits
CARBONIZARSE Cadena entero de 8 bits
CLSID Cadena
COLORREF Largo entero de 32 bits
PALABRA DORADA Largo entero de 32 bits
DOBLE Doble número real de 64 bits
FLOTAR Soltero número real de 32 bits
GUID Cadena número de 128 bits (16 bytes)
MANEJAR Largo
HBITMAPA Largo Entero sin signo de 32 bits
HDC Largo Entero sin signo de 32 bits
HICON Largo Entero sin signo de 32 bits
HGGLOBAL Largo Entero sin signo de 32 bits
HKL Largo Entero sin signo de 32 bits
HLOCAL Largo Entero sin signo de 32 bits
HINSTANCIA Largo Entero sin signo de 32 bits
HRESULTADO Largo Entero sin signo de 32 bits
HWND Largo Entero sin signo de 32 bits
LARGO Largo entero de 32 bits
LPARAM Largo Entero sin signo de 32 bits
CORTO Entero entero de 16 bits
TAMAÑO_T Largo Entero sin signo de 32 bits
TCHAR Cadena Corresponde a CHAR para cadenas de formato ANSI y WCHAR para cadenas de formato Unicode
UCHAR Cadena Carácter en codificación ANSI
UINT Largo Entero sin signo de 32 bits
LARGO Largo Entero sin signo de 32 bits
USCORTO Entero
UUID Cadena número de 128 bits (16 bytes)
VACÍO No no importa
WCHAR Cadena carácter UNICODE
WNDPROC Largo Entero sin signo de 32 bits
PALABRA Entero Entero sin signo de 16 bits
WPARAM Largo Entero sin signo de 32 bits

Punteros

Otro concepto muy utilizado en C son los punteros. Un puntero es una variable que contiene la dirección de un área de memoria donde se almacenan los datos. El tipo de un puntero siempre está determinado por el tipo de datos al que apunta; su tamaño es siempre de cuatro bytes. Por ejemplo, un puntero a una variable de tipo CORTO es un número entero de 32 bits, como un puntero a cualquier otro tipo de datos. La descripción del puntero utilizada en la programación de la API de Windows comienza con los caracteres "LP", que significa Long Pointer o "long pointer", que trabaja con un modelo de memoria de 32 bits. El carácter "C" (const) puede seguir, indicando que los datos no deben cambiarse. La siguiente es una descripción del tipo de datos de la variable cuya dirección se almacena en el puntero. Por ejemplo, LPDWORD es un puntero a una variable DWORD.

Los punteros a datos numéricos se pasan por referencia cuando se declara una función API de Windows. Como ejemplo, considere la función GetFileSize. Aquí está su prototipo (más sobre los prototipos de funciones a continuación):

DWORD GetFileSize(HANDLE hFile, // identificador de archivo LPDWORD lpFileSizeHigh // puntero);

El segundo parámetro pasado a la función es un puntero a una variable DWORD en la que la función colocará el valor del tamaño del archivo en bytes.

La declaración de esta función en Visual FoxPro es:

DECLARAR GetFileSize EN WIN32API Long hFile, Long @ FileSizeHight

Como puede ver, el parámetro FileSizeHight se pasa a la función enlace, porque pasar por referencia es solo pasar un puntero.

La situación es más complicada con las cuerdas. Como ya se mencionó, las cadenas de caracteres en C son matrices, por lo que en la programación de funciones API, el tipo calle, que define una matriz de caracteres de tipo CHAR (respectivamente, el tipo wstr define una matriz de caracteres de tipo WCHAR). La siguiente tabla muestra los tipos de punteros a cadenas de caracteres:

tipo de puntero
por línea
Descripción
LPSTR Puntero a la cadena de formato ANSI terminada en nulo que se va a modificar. Pasado por referencia
LPCSTR Puntero a una cadena de formato ANSI terminada en nulo no modificable. Pasado por valor
LPTSTR Corresponde al tipo LPSTR para cadenas de formato ANSI y al tipo LPWSTR para cadenas de formato UNICODE. Pasado por referencia.
LPCTSTR Corresponde al tipo LPSTR para cadenas de formato ANSI y al tipo LPWSTR para cadenas de formato UNICODE. Pasado por valor.
LPWSTR Puntero a la cadena UNICODE terminada en nulo que se va a modificar. Pasado por referencia
LPCWSTR Puntero a una cadena UNICODE terminada en nulo no modificable. Pasado por valor

Los punteros a datos de caracteres se pueden pasar por referencia o por valor: el tipo String en una declaración de función en Visual FoxPro siempre pasa un puntero a una variable que contiene datos de caracteres. Use pasar datos de caracteres por referencia solo cuando una función API necesite cambiar el valor de un parámetro.

estructuras

Una estructura puede verse como un conjunto de variables de varios tipos que forman un todo único. En C, se crea una estructura usando la palabra clave estructura seguido de un opcional campo de etiqueta(etiqueta) y lista elementos estructuras:

estructura etiqueta_campo { elemento_tipo elemento1; elemento_tipo elemento2; ..... elemento_tipo elementoN; };

También es posible declarar una estructura como esta:

Estructura( elemento_tipo elemento1; elemento_tipo elemento2; ..... elemento_tipo elementoN; } variable;

falta este anuncio campo de etiqueta y se crea un llamado tipo estructural anónimo; esta sintaxis te permite asociar una o más variables con este tipo de estructura, como en el siguiente ejemplo:

Estructura (PALABRA wAño; PALABRA wMes; PALABRA wDíaDeLaSemana; PALABRA wDía; PALABRA qué hora; PALABRA wMinuto; PALABRA wSegundo; PALABRA wMilisegundos; ) HORA DEL SISTEMA, * HORA DEL SISTEMA;

Las estructuras son muy similares a las entradas de la tabla de Visual FoxPro. Entonces, si la entrada de la tabla personal contiene campos fio,DIRECCIÓN,número de tlf y correo electrónico, se utiliza la siguiente sintaxis para acceder al campo tlfnumber:

Número personal.tlf

El acceso al campo de la estructura se ve de la misma manera:

SYSTEMTIME.wMinuto

Visual FoxPro utiliza variables que contienen cadenas de caracteres para formar estructuras. Por ejemplo, para la estructura SYSTEMTIME discutida anteriormente, necesitaría una variable de 16 bytes. Los dos primeros bytes de esta variable contienen el valor del campo wAño, en los próximos dos bytes - el valor del campo wMes, en los próximos dos bytes - el valor del campo wDíaDeLaSemana, y así sucesivamente, hasta que la estructura esté completamente formada. Y al declarar una función API en Visual FoxPro, el tipo de parámetro en el que se pasa la variable que contiene la estructura debe ser de tipo String. Aprenderá a escribir datos numéricos en una variable de cadena un poco más adelante.

Al programar la API de Windows en C, la descripción de un puntero a una estructura comienza con los caracteres LP (Long Pointer) seguido del nombre de la estructura. Así, un puntero a una estructura SYSTEMTIME será de tipo LPSYSTEMTIME, un puntero a una estructura POINT será de tipo LPPOINT, y así sucesivamente. Como puede ver, nada complicado, pero gracias a este concepto, hay una cantidad extremadamente grande de tipos de punteros a estructuras.

Si los datos en la estructura transferida no deben cambiar, entonces un puntero a dicha estructura se declara de la siguiente manera:

CONSTITUCIÓN nombre_estructura *

Aquí el modificador CONST significa que los datos en la estructura no deben cambiar, y el símbolo (*) después del nombre de la estructura significa que toda esta línea es una descripción de un puntero a la estructura. El siguiente ejemplo muestra el prototipo de la función CopyRect, que copia una estructura a otra:

BOOL CopyRect(LPRECT lprcDst, CONSTANTE * lprcSrc);

Descripción de prototipos de funciones en MSDN

Ahora que todo se ha vuelto más o menos claro con los tipos de datos, echemos un vistazo más de cerca a un concepto de C como prototipos de funciones.

Según el estándar ANSI, todas las funciones en C deben tener prototipos. El prototipo de la función es bastante simple:

tipo_retorno nombre de la función( parámetro_tipo(s) parámetro_nombre(s));

Si el prototipo especifica el tipo VOID como tipo_retorno, significa que la función no devuelve ningún valor. Si el tipo VOID se especifica como tipo_parámetro, significa que la función no tiene parámetros.

Puede encontrar información sobre los prototipos de las funciones de la API de Windows incluidas en las bibliotecas Kernel32.dll, Gdi32.dll, User32.dll, Mpr.dll y Advapi32.dll en MSDN para Visual Studio.NET abriendo los siguientes temas de ayuda en ordenar: :

Biblioteca de MSDN

Desarrollo de Windows Win32 API SDK Documentación Referencia

En la sección Referencia, puede ver las descripciones de las funciones abriendo una de las siguientes subsecciones:

Aquí hay otra dirección en MSDN, que también tiene información sobre las funciones de la API:

Biblioteca de MSDN

Diseño y desarrollo de interfaz de usuario SDK Documentación Shell de Windows Referencia de Shell Funciones de Shell

La siguiente figura muestra un fragmento de la ventana de ayuda de MSDN:

Así es como, por ejemplo, se describe la función CopyRect en MSDN:

Copiar Recto

El Copiar Recto La función copia las coordenadas de un rectángulo a otro.

BOOL CopiarRect(
LPRECT lprcDst, // rectángulo de destino
CONSTANTE* lprcSrc// rectángulo fuente
);

Parámetros

lprcDst
puntero a la RECT estructura que recibe las coordenadas lógicas del rectángulo fuente.
lprcSrc
Puntero a la estructura RECT cuyas coordenadas se van a copiar en unidades lógicas.

Valores devueltos

Si la función tiene éxito, el valor devuelto es distinto de cero.
Si la función falla, el valor de retorno es cero.
Windows NT/2000/XP: Para obtener información de error ampliada, llame a GetLastError.

Observaciones

Debido a que las aplicaciones pueden usar rectángulos para diferentes propósitos, las funciones de rectángulo no usan una unidad de medida explícita. En cambio, todas las coordenadas y dimensiones del rectángulo se dan en valores lógicos con signo. El modo de mapeo y la función en la que se usa el rectángulo determinan las unidades de medida.

Código de ejemplo

Para ver un ejemplo, véase Usar rectángulos.

Requisitos

Windows NT/2000/XP: Incluido en Windows NT 3.1 y posterior.
Windows 95/98/Me: Incluido en Windows 95 y posteriores.
Encabezado: Declarado en Winuser.h; incluir Windows.h.
Biblioteca: use User32.lib.

Como puedes ver, la información es bastante exhaustiva. La función devuelve un valor de tipo BOOL, se le pasan dos parámetros: tipo LPRECT y CONST RECT* - punteros a estructuras de tipo RECT. Al declarar esta función en Visual FoxPro, debe especificar que el primer parámetro se pasa por referencia y el segundo parámetro se pasa por valor:

DECLARAR Long CopyRect IN User32.dll Cadena @ Horario de verano, Cadena origen

¿Y cómo determiné que esta función está en la biblioteca User32.dll? Muy simple. En la sección de recomendaciones ( Requisitos) la cláusula de la biblioteca dice Use User32.lib. Sustituto de extensión liberación extensión dll- ¡y eso es! Por cierto, en el mismo lugar, en el párrafo de Cabecera, se informa en qué archivo include se encuentra la descripción del prototipo de función.

¡Pero eso no es todo! Dado que la función trabaja con estructuras, su descripción contiene un hipervínculo a la estructura RECT. Haga clic en este hipervínculo y aparecerá en la pantalla una descripción detallada de la estructura.

Dar forma a estructuras en Visual FoxPro

La novena versión de Visual FoxPro mejora enormemente las funciones integradas de BINTOC y CTOBIN. Estas funciones ahora se pueden usar para convertir datos numéricos en un formato adecuado para usar en estructuras. Permítame recordarle que la función BINTOC convierte un número en una cadena y la función CTOBIN convierte una cadena en un número.

Sintaxis de la función BINTOC:

BINTOC( nExpresión, Bandera electrónica)

De todos los posibles valores que puede tomar el parámetro Bandera electrónica, estamos interesados ​​en lo siguiente:

La sintaxis de la función CTOBIN es:

CTOBIN(c expresión, Bandera electrónica)

Posibles valores de parámetros Bandera electrónica:

A continuación se muestran ejemplos del uso de estas funciones:

CTOBIN(BINTOC(1000.55,"4RS"), "4RS") && Resultado: 1000 ? CTOBIN(BINTOC(-1000.55,"4RS"), "4RS") && Resultado: -1000 ? CTOBIN(BINTOC(1000.55,"F"), "4N") && Resultado: 1000.549987929 ? CTOBIN(BINTOC(-1000.55,"F"), "4N") && Resultado: -1000.549987929 ? CTOBIN(BINTOC(1000.55,"B"), "8N") && Resultado: 1000.55 ? CTOBIN(BINTOC(-1000.55,"B"), "8N") && Resultado: -1000.55

Como ejemplo, escribamos una estructura RECT en una variable de Visual FoxPro. Esta estructura se usa en la función CopyRect discutida anteriormente para describir las coordenadas de un área rectangular. Así es como se describe esta estructura en MSDN:

Typedef struct _RECT ( LARGO a la izquierda; LARGO arriba; LARGO a la derecha; LARGO abajo; ) RECT, *PRECT;

Como puede ver, la estructura RECT contiene cuatro campos, cada uno de los cuales almacena un valor LONG. Para formarlo en Visual FoxPro, necesita una cadena de 16 bytes.

A continuación se muestra el código que declara la función CopyRect, forma las estructuras Dst y Src para pasarlas como parámetros a la función y luego copia una estructura a otra. El ejemplo usa la función BINTOC para convertir un número en una cadena:

DECLARE Long CopyRect IN WIN32API String @ Dst, String Src * Forma Src estructura cSrc = BINTOC(nLeft,"4RS") + BINTOC(nTop,"4RS") + ; BINTOC(nRight,"4RS") + BINTOC(nBottom,"4RS") * Preparar espacio para la estructura Dst cDst = REPLICATE(CHR(0),16) nResult = CopyRect(@cDst, cSrc) && Copiar

El siguiente ejemplo muestra cómo, utilizando la función CTOBIN, puede "analizar" una estructura obteniendo los valores numéricos de sus campos:

NLeft = CTOBIN(SUBSTR(cDst,1,4), "4RS") && RECT.left nTtop = CTOBIN(SUBSTR(cDst,5,4), "4RS") && RECT.top nRight = CTOBIN(SUBSTR(cDst, 9,4), "4RS") && RECT.derecho nInferior = CTOBIN(SUBSTR(cDst,13,4), "4RS") && RECT.inferior

Estructuras que contienen punteros

Muy a menudo hay una situación en la que la estructura que se pasa a la función API de Windows contiene punteros. Como ejemplo, considere la función StartDoc, que crea un documento para imprimir en una impresora. Aquí está su prototipo:

Int StartDoc(HDC hdc, // manejar a DC CONST DOCINFO* lpdi// contiene nombres de archivos);

Como puede ver, el segundo parámetro pasado a la función es un puntero a una estructura DOCINFO. Aquí está la estructura:

Estructura Typedef (int cbTamaño; LPCTSTR lpszNombreDoc; LPCTSTR salida lpsz; LPCTSTR lpszTipo de datos; PALABRA DORADA fwType; ) DOCINFO, *LPDOCINFO;

El primer campo de la estructura, cbTamaño, contiene la longitud de la estructura en bytes. Pero los siguientes tres campos son punteros a variables que contienen datos de caracteres. En particular, el campo lpszNombreDoc contiene puntero en la línea con el nombre del documento a imprimir (este es el mismo nombre de documento que ve cuando visualiza la cola de documentos a imprimir).

En Visual FoxPro, es bastante difícil formar una estructura que contenga punteros. Primero, debe asignar un bloque de memoria y obtener un puntero hacia él. En segundo lugar, es necesario volver a escribir el valor de la variable de Visual FoxPro en esta memoria; por lo tanto, tendremos un mecanismo de puntero completamente implementado. Lo último que debe hacer es poner el valor del puntero en una estructura. En este caso, se debe cumplir un requisito esencial: la memoria asignada no debe ser reubicable; de ​​lo contrario, puede resultar que nuestro puntero en algún momento apunte a un área en la que nuestros datos no tienen nada que ver.

Hay varias posibilidades para obtener un bloque de memoria. Puede tomar una "pieza" tanto de la memoria general de Windows como de la memoria asignada al proceso (es decir, su aplicación). El segundo método tiene un mayor rendimiento, sin embargo, aquí consideraremos que el método de trabajo con la memoria de Windows es más simple.

La función GlobalAlloc recibe un bloque de memoria del tamaño especificado de Windows y le devuelve un puntero. Aquí está el prototipo de esta función:

HGLOBAL GlobalAlloc(UINT uBanderas, // atributos de asignación de memoria SIZE_T dwBytes// tamaño en bytes);

Parámetro uBanderas determina cómo se asignará la memoria. MSDN dice que puede tomar uno de los siguientes valores:

De la tabla se deduce que para el parámetro uBanderas se debe utilizar el valor GPTR. Pero, como lo sabes cual es este valor? Busque en MSDN una descripción de la función GlobalAlloc y en la sección Requisitos ver qué archivo de inclusión contiene su prototipo. Este es el archivo Winbase.h. Es en él donde se debe buscar una descripción de los valores de las constantes. Aquí hay un fragmento de este archivo, que define las constantes enumeradas en la tabla:

/* Indicadores de memoria global */ #define GMEM_FIXED 0x0000 #define GMEM_MOVEABLE 0x0002 #define GMEM_NOCOMPACT 0x0010 #define GMEM_NODISCARD 0x0020 #define GMEM_ZEROINIT 0x0040 #define GMEM_MODIFY 0x0080 #define GMEM_DI SCARDABLE 0x0100 #define GMEM_NOT_BANKED 0x1000 #define GMEM_SHARE 0x2000 #define GMEM_DDESHARE 0x2000 #define GMEM_NOTIFY 0x4000 #define GMEM_LOWER GMEM_NOT_BANKED #define GMEM_VALID_FLAGS 0x7F72 #define GMEM_INVALID_HANDLE 0x8000 #define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT) #define GPTR (GMEM_FIXED | GMEM_ZEROINIT)

Por lo tanto, GPTR = GMEM_FIXED + GMEM_ZEROINIT = 0x0000 + 0x0040 = 0x0040.

¿Cuál es el tamaño del bloque de memoria asignado? Por supuesto, igual a la longitud de la cadena que almacena el nombre del documento. El siguiente ejemplo muestra los pasos desde la declaración de una función API hasta la asignación de un bloque de memoria:

uBanderas, Largo dwBytes cDocumentName = "Nombre del documento a imprimir" && Nombre del documento nLenDocumentName = LEN(cDocumentName) && Longitud de cadena hGlobal = GlobalAlloc(GPTR, nLenDocumentName)

La siguiente tarea es reescribir el contenido de la variable cDocumentName en el bloque de memoria resultante. Usemos la función incorporada de Visual FoxPro SYS(2600) para esto. Aquí está su sintaxis:

SISTEMA(2600, dwAddress, longitud [, cNuevaCadena])

La función se comporta de manera diferente dependiendo de si se especifica el parámetro. cNuevaCadena O no.

Si el parámetro cNuevaCadena indicado, entonces la función copia longitud byte de variable cNuevaCadena en la memoria en la dirección especificada en dwAddress.

Si el parámetro cNuevaCadena No especificado, entonces la función devuelve longitud bytes de la memoria en la dirección especificada en dwAddress.

Como puede ver, el parámetro dwAddress- Este puntero.

Escribamos el contenido de la cadena cDocumentName en la memoria asignada por la función GlobalAlloc:

SYS(2600, hGlobal, nLenDocumentName, cDocumentName)

Aquí está el código completo para formar la estructura DOCINFO:

#DEFINE GPTR 0x0040 DECLARE Long GlobalAlloc IN WIN32API Long uBanderas, Largo dwBytes cDocumentName = "Nombre del documento a imprimir" nLenDocumentName = LEN(cDocumentName) hGlobal = GlobalAlloc(GPTR, nLenDocumentName) SYS(2600, dwAddress, longitud [, cNuevaCadena]) * Empezando a formar la estructura DOCINFO * cDocInfo es una variable en la que se forma la estructura cDocInfo = BINTOC(20,"4RS") && DOCINFO. cbTamaño cDocInfo = cDocInfo + BINTOC(hGlobal,"4RS") && DOCINFO. lpszNombreDoc cDocInfo = cDocInfo + REPLICATE(CHR(0),12) && Otros campos de estructura * Fin de generación de estructura

La estructura se forma en una variable cDocInfo. En los primeros cuatro bytes escribimos el número 20: este es el tamaño de la estructura (campo cbTamaño). Los siguientes cuatro bytes agregados a la variable son un puntero al área de memoria en la que se reescriben los contenidos de la variable cDocumentName, el nombre del documento. Luego se agregan doce bytes cero más a la variable: estos son los campos de la estructura salida lpsz, lpszTipo de datos Y fwType, que, según la documentación, puede ignorarse; esto significa que los campos deben tener valores nulos. Por lo tanto, se obtuvo una cadena de 20 bytes de longitud, que era necesaria.

Características del uso de la memoria

Cuando utilice las funciones de la API de Windows en sus aplicaciones, debe tener en cuenta que Visual FoxPro no puede administrar la memoria reservada por estas funciones. Por lo tanto, si asigna memoria, por ejemplo, utilizando la función GlobalAlloc, debe devolver esta memoria a Windows después de usarla llamando a la función GlobalFree. Para cada función API que reserva memoria, hay una función antípoda que libera la memoria reservada.

Aquí está el prototipo de la función GlobalFree:

HGLOBAL GlobalFree(HGLOBAL hMem // puntero al bloque de memoria);

La función recibe solo un parámetro: un puntero a un bloque de memoria. Aquí está su declaración y uso en Visual FoxPro:

DECLARAR Long GlobalFree IN WIN32API Long hGlobal GlobalFree(hGlobal)

donde hGlobal es un puntero al bloque de memoria devuelto por la función GlobalAlloc.

Si olvida devolver la memoria asignada, corre el riesgo de encontrarse con un problema llamado pérdida de memoria. Las consecuencias de una fuga de este tipo pueden ser muy tristes: desde una fuerte ralentización de la aplicación, provocada por la fragmentación de la memoria, hasta el bloqueo del sistema operativo.

Pasar a una función de matriz

Una matriz, en términos de C, es una variable que contiene múltiples elementos del mismo tipo. El acceso a cada elemento individual de la matriz se realiza mediante un índice. Todos los elementos de una matriz tienen el mismo tamaño, no puede describir matrices con tipos de datos mixtos. Todos los elementos de la matriz se almacenan secuencialmente en la memoria, uno tras otro, con el valor de índice mínimo correspondiente al primer elemento y el valor de índice máximo correspondiente al último.

Una matriz de Visual FoxPro tiene una organización completamente diferente que le permite almacenar tipos de datos completamente diferentes en sus elementos. Por lo tanto, no es posible pasar una matriz de Visual FoxPro a una función API de Windows simplemente proporcionando su nombre como parámetro. Además, en el comando DECLARE..DLL no existe un tipo de datos como matrices.

Sin embargo, hay una salida a esta situación. Al igual que con las estructuras, las variables de caracteres se utilizan para pasar matrices. Los datos numéricos de la matriz deben convertirse en una cadena, que se pasa como parámetro a la función API de Windows. El siguiente ejemplo muestra el código de la función ArrayToString que genera una cadena a partir de una matriz. La función get obtiene una matriz taArray(enlace) y bandera tlTypeOfValue, que indica cómo convertir los valores de los elementos de la matriz, como números enteros ( tlTipoDeValor=.Verdadero ( tlTipoDeValor=.T.) números:

FUNCIÓN ArrayToString PARÁMETROS taArray, tlTypeOfValue EXTERNAL ARRAY taArray LOCAL lnLenArray, lnIndex, lcStruct, lcType lcType = IIF(tlTypeOfValue = .t., "F", "4RS") lnLenArray = ALEN(taArray) && Número de elementos en la matriz lcStruct = " " FOR lnIndex = 1 TO lnLenArray lcStruct = lcStruct + BINTOC(taArray, lcType) ENDFOR RETURN lcStruct ENDFUNC

La función funciona con matrices unidimensionales y bidimensionales.

Codificación de datos de caracteres: formatos ANSI y UNICODE

En la codificación ANSI (utilizada en Visual FoxPro), cada carácter está definido por un byte, por lo que el número máximo de caracteres es 256, que es, por supuesto, muy pequeño. Por ejemplo, durante la rusificación, algunos de los caracteres ANSI estándar se reemplazan con caracteres cirílicos. Y en algunos alfabetos, por ejemplo, el kana japonés, hay tantos caracteres que un byte simplemente no es suficiente para codificarlos. Para admitir dichos lenguajes y, lo que es más importante, para facilitar la "traducción" de programas a otros lenguajes, se desarrolló la codificación Unicode. Cada carácter en Unicode consta de dos bytes, lo que hizo posible ampliar el conjunto de caracteres válidos a 65536.

Una gran cantidad de funciones de la API de Windows utilizan el formato Unicode cuando trabajan con cadenas de caracteres. Para trabajar con tales funciones, es necesario convertir los datos de caracteres de un formato a otro.

La función integrada de Visual FoxPro STRCONV convierte cadenas de ANSI a UNICODE y viceversa. Aquí está su sintaxis:

STRCONV( cExpresión, nConversionSetting [, nRegionalIdentifier [, nRegionalIDType]])

Parámetro cExpresión es la cadena a convertir. Parámetro nConversionSetting indica la naturaleza de la conversión. De todos sus valores posibles, sólo nos interesan dos:

  • 5 - convertir de ANSI a UNICODE
  • 6 - convertir de UNICODE a ANSI

Parámetros opcionales nRegionalIdentifier Y nRegionalIDType definir configuraciones regionales adicionales y se pueden ignorar de forma segura.

A continuación se muestran ejemplos del uso de la función STRCONV:

CUnicodeString = STRCONV(cANSISTring, 5) && Convertir a Unicode cANSISTring = STRCONV(cUnicodeString, 6) && Convertir a ANSI

Mientras lee esta sección, puede tener la impresión de que trabajar con las funciones de la API de Windows en Visual FoxPro es bastante fácil. Si y no. Por ejemplo, algunas funciones de la API utilizan tipos de datos que no son compatibles con el comando DECLARE..DLL, como los números enteros de 64 bits. También hay una serie de funciones llamadas funciones de devolución de llamada. En el prototipo de tal función, el modificador CALLBACK está presente antes de la declaración del tipo de retorno. Desafortunadamente, no puede usar tales funciones, al menos no directamente. También sucede que una estructura contiene un puntero a una función; dichas API tampoco se pueden usar en Visual FoxPro.

La API de Windows (interfaz de programación de aplicaciones) es una interfaz de programación del sistema en modo usuario para la familia de sistemas operativos Windows. Antes del lanzamiento de las versiones de 64 bits de Windows, la API para las versiones de 32 bits de los sistemas operativos Windows se denominaba Win32 API para distinguirla de la versión original de 16 bits de la API de Windows (que servía como interfaz de programación para las versiones iniciales de Windows de 16 bits).

La API de Windows consta de varios miles de funciones a las que se puede llamar, que se dividen en las siguientes categorías principales:

  • Servicios básicos.
  • Servicios de componentes.
  • Servicios de interfaz de usuario.
  • Servicios gráficos y multimedia (Graphics and Multimedia Services).
  • Mensajería y colaboración (Messaging and Collaboration).
  • Redes.
  • Servicios web.

Puede encontrar una descripción de la API de Windows en la documentación del Kit de desarrollo de software (SDK) de Windows. Esta documentación está disponible en www.msdn.microsoft.com. También se incluye con todos los niveles de suscripción en Microsoft Developer Network (MSDN) dedicado a los desarrolladores.

Microsoft .NET Framework consta de una biblioteca de clases denominada Biblioteca de clases de Framework (FCL) y un tiempo de ejecución de código Common Language Runtime (CLR) administrado. El CLR tiene las características de compilación justo a tiempo, verificación de tipos, recolección de elementos no utilizados y seguridad de acceso al código. Al ofrecer estas funciones, CLR proporciona un entorno de desarrollo que mejora la productividad del programador y reduce los errores de programación más comunes.

El CLR se implementa como un servidor COM clásico, cuyo código se encuentra en una DLL estándar de Windows diseñada para funcionar en modo usuario. Prácticamente todos los componentes de .NET Framework se implementan como archivos DLL estándar de modo de usuario de Windows, en capas sobre las funciones nativas de la API de Windows. (Ninguno de los componentes de .NET Framework se ejecuta en modo kernel). La relación entre estos componentes se muestra en la figura.

Servicios, funciones y programas estándar.

Algunos términos en la documentación de usuario y programación de Windows tienen diferentes significados en diferentes contextos. Por ejemplo, la palabra servicio puede hacer referencia a una rutina llamada en el sistema operativo, un controlador de dispositivo o un proceso de servicio. Lo que significan exactamente estos términos se muestra en la siguiente lista:

  • Funciones de la API de Windows. Subrutinas documentadas e invocables en WindowsAPI. Por ejemplo, CreateProcess, CreateFile y GetMessage.
  • Servicios del sistema nativo (o llamadas al sistema). Servicios centrales no documentados en el sistema operativo llamado cuando se ejecuta en modo de usuario. Por ejemplo, NtCreateUserProcess es un servicio interno al que llama la función CreateProcess de Windows para crear un nuevo proceso.
  • Funciones de soporte del kernel (o subrutinas). Subrutinas dentro del sistema operativo Windows que solo se pueden llamar desde el modo kernel. Por ejemplo, ExAllocatePoolWithTag es una rutina a la que llaman los controladores de dispositivos para asignar memoria desde las áreas asignadas dinámicamente del sistema Windows (llamadas agrupaciones).
  • Servicios de Windows. Procesos iniciados por el Administrador de control de servicios (Windowsservicecontrolmanager). Por ejemplo, el servicio Administrador de tareas se ejecuta como un proceso de modo de usuario que admite el comando at (similar a los comandos UNIX at o cron).
  • Bibliotecas DLL (bibliotecas de enlaces dinámicos - bibliotecas enlazadas dinámicamente). Un conjunto de rutinas a las que se puede llamar vinculadas entre sí como un archivo binario que las aplicaciones que usan esas rutinas pueden cargar dinámicamente. Los ejemplos incluyen Msvcrt.dll (una biblioteca en tiempo de ejecución para aplicaciones escritas en C) y Kernel32.dll (una de las bibliotecas del subsistema API de Windows). Las DLL son ampliamente utilizadas por componentes y aplicaciones de Windows que se ejecutan en modo de usuario. La ventaja que brindan las DLL sobre las bibliotecas estáticas es que pueden ser utilizadas por varias aplicaciones a la vez, y Windows garantiza que solo se mantenga una copia del código DLL en la memoria para aquellas aplicaciones que hacen referencia a la DLL. Tenga en cuenta que los ensamblados .NET no ejecutables se compilan como archivos DLL, pero sin ninguna rutina exportada. El CLR analiza los metadatos compilados para acceder a los tipos y miembros de clase apropiados.

Historia de la API de Win32.

Curiosamente, Win32 no fue pensado como la interfaz de programación original para lo que entonces se conocía como Windows NT. Debido a que el proyecto de Windows NT comenzó como un reemplazo de la versión 2 de OS/2, la interfaz de programación original era la PresentationManagerAPI de OS/2 de 32 bits. Pero un año después del lanzamiento del proyecto, Microsoft Windows 3.0, que salió a la venta, despegó. Como resultado, Microsoft cambió de dirección y convirtió a Windows NT en el reemplazo futuro de la familia de productos Windows en lugar de un reemplazo para OS/2. En este sentido, se hizo necesario desarrollar una especificación para la API de Windows; antes de eso, en Windows 3.0, la API existía solo en forma de una interfaz de 16 bits.

Aunque la API de Windows tenía la intención de introducir muchas características nuevas que no estaban disponibles en Windows 3.1, Microsoft decidió hacer que la nueva API fuera lo más compatible posible con nombres, semántica y tipos de datos con la API de Windows de 16 bits para aliviar la carga de portar las aplicaciones existentes. Windows de 16 bits.-aplicaciones en Windows NT. Esto, de hecho, explica el hecho de que muchos nombres de funciones e interfaces pueden parecer inconsistentes: esto era necesario para garantizar la compatibilidad de la nueva API de Windows con la antigua API de Windows de 16 bits.

La abreviatura de API, Interfaz de programación de aplicaciones (API) es simplemente un conjunto de funciones listas para usar que los desarrolladores de aplicaciones pueden usar. En general, este concepto es equivalente a lo que solía llamarse biblioteca de subrutinas. Sin embargo, la mayoría de las veces, API se refiere a alguna categoría especial de tales bibliotecas.

Durante el desarrollo de casi cualquier aplicación bastante compleja (MyApplication), se forma un conjunto de funciones internas específicas para el usuario final, que se utilizan para implementar este programa en particular, que se denomina API MyApplication. A menudo resulta que estas funciones también se pueden usar de manera efectiva para crear otras aplicaciones, incluso por parte de otros programadores. En este caso, los autores, en base a la estrategia de promocionar su producto, deben decidir si abren o no el acceso a este conjunto a usuarios externos. Con una respuesta positiva, en la descripción del paquete de software, como su ventaja, aparece una frase que "el kit incluye un conjunto abierto de funciones API".

Por lo tanto, la mayoría de las veces, una API se refiere a un conjunto de funciones que forman parte de una aplicación, pero que al mismo tiempo están disponibles para su uso en otros programas. Por ejemplo, Excel, además de la interfaz para el usuario final, tiene un conjunto de funciones API de Excel que se pueden usar, en particular, al crear aplicaciones usando VB.

En consecuencia, la API de Windows es un conjunto de funciones que forma parte del propio sistema operativo y al mismo tiempo está disponible para cualquier otra aplicación. Y en este sentido, la analogía con el conjunto de interrupciones del sistema BIOS / DOS, que en realidad es una API de DOS, está bastante justificada.

La diferencia radica en que la composición de las funciones de la API de Windows, por un lado, es mucho más amplia que en DOS, por otro lado, no incluye muchas de las herramientas para la gestión directa de los recursos informáticos que estaban disponibles para programadores en el sistema operativo anterior. Además, el acceso a la API de Windows se realiza mediante llamadas de procedimiento ordinarias, y las funciones de DOS se llaman a través de una instrucción de máquina especial del procesador, que se llama Interrupción ("interrupción").

API Win16 y API Win32

Como saben, el cambio de Windows 3.xa Windows 95 marcó la transición de una arquitectura de sistema operativo de 16 bits a una de 32 bits. Al mismo tiempo, la API de Windows de 16 bits (API Win16) se reemplazó con una nueva variante de 32 bits (API Win32). En este caso, solo debe tener en cuenta que, con algunas excepciones, el conjunto de API Win32 es el mismo para las familias Windows 9x y Windows NT.

Al familiarizarse con Win API, resulta que muchas funciones integradas no son más que una llamada a los procedimientos del sistema correspondientes, pero solo se implementan en la forma de la sintaxis de este lenguaje. Ante esto, la necesidad de utilizar la API viene determinada por las siguientes opciones:

Funciones de API que se implementan completamente como funciones integradas. Sin embargo, a veces, en este caso, es útil cambiar al uso de la API, ya que esto a veces puede mejorar significativamente el rendimiento (en particular, debido a la ausencia de conversiones innecesarias de los parámetros pasados).

Las funciones integradas solo implementan un caso especial de la función API correspondiente. Esta es una opción bastante común.

Una gran cantidad de funciones API no tienen ningún análogo en la versión de compiladores que existe hoy. Por ejemplo, no puede eliminar un directorio usando VB; para hacer esto, necesita usar la función DeleteDirectory.

También se debe enfatizar que algunas funciones de API (su participación en Win API es muy pequeña) no se pueden llamar desde programas debido a una serie de restricciones de idioma, por ejemplo, la incapacidad de trabajar con direcciones de memoria. Pero en algunos casos, las técnicas de programación no triviales pueden ayudar (en particular, en el caso de las mismas direcciones).

Ganar APIYBiblioteca de enlaces dinámicos (DLL)

El conjunto de API Win se implementa como archivos DLL dinámicos.

En este caso, por DLL nos referimos a la variante tradicional de las bibliotecas dinámicas binarias, que brindan acceso directo de las aplicaciones a los procedimientos necesarios: subrutinas o funciones (al igual que sucede cuando se llaman procedimientos dentro de un proyecto). Dichas bibliotecas se pueden crear utilizando diferentes herramientas: VC ++, Delphi, Fortran, Assembler.

Por lo general, los archivos de biblioteca dinámica tienen la extensión .DLL, pero esto no es necesario en absoluto. La extensión .EXE se usaba a menudo para Win16, los controladores de dispositivos externos se indican con .DRV.

Determinar la cantidad exacta de API de Windows y los archivos que las contienen es difícil (pero todos están en el directorio del sistema). En este sentido, es mejor destacar la composición de las bibliotecas que forman el núcleo del sistema operativo y las principales bibliotecas con funciones adicionales clave.

Bibliotecas API Win32 del kernel del sistema operativo Windows 95/98:

KERNEL32.DLL: funciones de bajo nivel para administrar memoria, tareas y otros recursos del sistema;

USER32.DLL: aquí es donde residen la mayoría de las funciones de administración de la interfaz de usuario;

GDI32.DLL: biblioteca de interfaz de dispositivo gráfico: varias funciones de salida a dispositivos externos;

COMDLG32.DLL: Funciones relacionadas con el uso de cuadros de diálogo de propósito general.

Bibliotecas principales con funciones de extensión:

COMCTL32.DLL: un conjunto de controles adicionales de Windows, incluidos Tree List y Rich Text;

MAPI32.DLL: funciones de correo electrónico;

NETAPI32.DLL: controles y funciones de red;

ODBC32.DLL: las funciones de esta biblioteca son necesarias para trabajar con varias bases de datos a través del protocolo ODBC;

WINMM.DLL: operaciones de acceso a medios del sistema.

Si nota un error, seleccione un fragmento de texto y presione Ctrl + Enter
COMPARTIR: