Administración de transacciones (Intercambio de datos)
Después de establecer una conversación con un servidor, un cliente puede enviar transacciones para obtener datos y servicios del servidor.
En los temas siguientes se describen los tipos de transacciones que los clientes pueden usar para interactuar con un servidor.
- Solicitud de transacción
- Transacción poke
- Asesoramiento de transacción
- Ejecutar transacción
- Transacciones sincrónicas y asincrónicas
- Control de transacciones
- Clases de transacción
- Tipos de transacción
Solicitud de transacción
Una aplicación cliente puede usar la transacción XTYP_REQUEST para solicitar un elemento de datos desde una aplicación de servidor. El cliente llama a la función DdeClientTransaction , especificando XTYP_REQUEST como tipo de transacción y especificando el elemento de datos que necesita la aplicación.
La Biblioteca de administración dinámica de Intercambio de datos (DDEML) pasa la transacción XTYP_REQUEST al servidor, especificando el nombre del tema, el nombre del elemento y el formato de datos solicitados por el cliente. Si el servidor admite el tema, el elemento y el formato solicitados, el servidor debe devolver un identificador de datos que identifique el valor actual del elemento. DDEML pasa este identificador al cliente como el valor devuelto de DdeClientTransaction. El servidor debe devolver NULL si no admite el tema, el elemento o el formato solicitados.
DdeClientTransaction usa el parámetro lpdwResult para devolver una marca de estado de transacción al cliente. Si el servidor no procesa la transacción de XTYP_REQUEST , DdeClientTransaction devuelve NULL y lpdwResult apunta a la marca DDE_FNOTPROCESSED o DDE_FBUSY. Si se devuelve la marca DDE_FNOTPROCESSED, el cliente no puede determinar por qué el servidor no procesó la transacción.
Si un servidor no admite la transacción de XTYP_REQUEST , debe especificar la marca de filtro CBF_FAIL_REQUESTS en la función DdeInitialize . Esta marca impide que DDEML envíe la transacción al servidor.
Transacción poke
Un cliente puede enviar datos no solicitados a un servidor mediante DdeClientTransaction para enviar una transacción XTYP_POKE a la función de devolución de llamada de un servidor.
La aplicación cliente crea primero un búfer que contiene los datos que se van a enviar al servidor y, a continuación, pasa un puntero al búfer como parámetro a DdeClientTransaction. Como alternativa, el cliente puede usar la función DdeCreateDataHandle para obtener un identificador de datos que identifique los datos y, a continuación, pasar el identificador a DdeClientTransaction. En cualquier caso, el cliente también especifica el nombre del tema, el nombre del elemento y el formato de datos cuando llama a DdeClientTransaction.
DDEML pasa la transacción XTYP_POKE al servidor, especificando el nombre del tema, el nombre del elemento y el formato de datos que solicitó el cliente. Para aceptar el elemento de datos y el formato, el servidor debe devolver DDE_FACK. Para rechazar los datos, el servidor debe devolver DDE_FNOTPROCESSED. Si el servidor está demasiado ocupado para aceptar los datos, el servidor debe devolver DDE_FBUSY.
Cuando devuelve DdeClientTransaction , el cliente puede usar el parámetro lpdwResult para acceder a la marca de estado de transacción. Si la marca está DDE_FBUSY, el cliente debe enviar la transacción de nuevo más adelante.
Si un servidor no admite la transacción XTYP_POKE , debe especificar la marca de filtro CBF_FAIL_POKES en DdeInitialize. Esta marca impide que DDEML envíe esta transacción al servidor.
Asesoramiento de transacción
Una aplicación cliente puede usar DDEML para establecer uno o varios vínculos a elementos de una aplicación de servidor. Cuando se ha establecido este vínculo, el servidor envía actualizaciones periódicas sobre el elemento vinculado al cliente (normalmente, siempre que cambie el valor del elemento asociado a la aplicación de servidor). La vinculación establece un bucle de aviso entre las dos aplicaciones que permanecen en su lugar hasta que el cliente finaliza.
Hay dos tipos de bucles de aviso: "caliente" y "cálido". En un bucle de aviso activo, el servidor envía inmediatamente un identificador de datos que identifica el valor cambiado. En un bucle de aviso intermedio, el servidor notifica al cliente que el valor del elemento ha cambiado, pero no envía el identificador de datos hasta que el cliente lo solicite.
Un cliente puede solicitar un bucle de aviso activo con un servidor especificando el tipo de transacción XTYP_ADVSTART en una llamada a DdeClientTransaction. Para solicitar un bucle de aviso intermedio, el cliente debe combinar la marca XTYPF_NODATA con el tipo de transacción XTYP_ADVSTART . En cualquier caso, DDEML pasa la transacción XTYP_ADVSTART a la función de devolución de llamada de Intercambio de datos dinámicos (DDE) del servidor. La función de devolución de llamada DDE del servidor debe examinar los parámetros que acompañan a la transacción de XTYP_ADVSTART (incluido el formato solicitado, el nombre del tema y el nombre del elemento) y, a continuación, devolver TRUE para permitir que el bucle de aviso o FALSE lo deniegue.
Una vez establecido un bucle de aviso, la aplicación de servidor debe llamar a la función DdePostAdvise siempre que cambie el valor del elemento asociado al nombre del elemento solicitado. Esta llamada hace que se envíe una transacción XTYP_ADVREQ a la propia función de devolución de llamada DDE del servidor. La función de devolución de llamada DDE del servidor debe devolver un identificador de datos que identifique el nuevo valor del elemento de datos. A continuación, DDEML notifica al cliente que el elemento especificado ha cambiado enviando la transacción XTYP_ADVDATA a la función de devolución de llamada DDE del cliente.
Si el cliente solicitó un bucle de aviso activo, DDEML pasa el identificador de datos al elemento cambiado al cliente durante la transacción de XTYP_ADVDATA . De lo contrario, el cliente puede enviar una transacción de XTYP_REQUEST para obtener el identificador de datos.
Es posible que un servidor envíe actualizaciones más rápido de lo que un cliente puede procesar los nuevos datos. La velocidad de las actualizaciones puede ser un problema para un cliente que debe realizar operaciones de procesamiento largas en los datos. En este caso, el cliente debe especificar la marca XTYPF_ACKREQ cuando solicita un bucle de aviso. Esta marca hace que el servidor espere a que el cliente confirme que ha recibido y procesado un elemento de datos antes de que el servidor envíe el siguiente elemento de datos. Los bucles de asesoramiento que se establecen con la marca de XTYPF_ACKREQ son más sólidos con servidores rápidos, pero en ocasiones pueden perder actualizaciones. Se garantiza que los bucles de asesoramiento establecidos sin la marca de XTYPF_ACKREQ no pierdan las actualizaciones siempre que el cliente se mantenga al día con el servidor.
Un cliente puede finalizar un bucle de aviso especificando el tipo de transacción XTYP_ADVSTOP en una llamada a DdeClientTransaction.
Si un servidor no admite bucles de aviso, debe especificar la marca de filtro CBF_FAIL_ADVISES en la función DdeInitialize . Esta marca impide que DDEML envíe el XTYP_ADVSTART y XTYP_ADVSTOP transacciones al servidor.
Ejecutar transacción
Un cliente puede usar la transacción XTYP_EXECUTE para hacer que un servidor ejecute un comando o una serie de comandos.
Para ejecutar un comando de servidor, el cliente crea primero un búfer que contiene una cadena de comandos para que el servidor se ejecute y, a continuación, pasa un puntero al búfer o un identificador de datos que identifica el búfer cuando llama a DdeClientTransaction. Otros parámetros necesarios incluyen el identificador de conversación, el identificador de cadena de nombre del elemento, la especificación de formato y el tipo de transacción XTYP_EXECUTE . Una aplicación que crea un identificador de datos para pasar datos de ejecución debe especificar NULL para el parámetro hszItem de la función DdeCreateDataHandle y cero para el parámetro uFmt .
DDEML pasa la transacción XTYP_EXECUTE a la función de devolución de llamada DDE del servidor y especifica el nombre de formato, el identificador de conversación, el nombre del tema y el identificador de datos que identifican la cadena de comandos. Si el servidor admite el comando, debe usar la función DdeAccessData para obtener un puntero a la cadena de comandos, ejecute el comando y, a continuación, devuelva DDE_FACK. Si el servidor no admite el comando o no puede completar la transacción, debe devolver DDE_FNOTPROCESSED. El servidor debe devolver DDE_FBUSY si está demasiado ocupado para completar la transacción.
En general, la función de devolución de llamada de un servidor debe procesar la transacción XTYP_EXECUTE antes de devolver con las excepciones siguientes:
- Cuando el comando pasado con el XTYP_EXECUTE transacción solicita que finalice el servidor, el servidor no debe finalizar hasta que su función de devolución de llamada vuelva del procesamiento XTYP_EXECUTE.
- Si el servidor debe realizar una operación, como procesar un cuadro de diálogo o una transacción DDE que pueda causar problemas de recursividad DDEML, el servidor debe devolver el código de retorno CBR_BLOCK para bloquear la transacción de ejecución, realizar la operación y reanudar el procesamiento de la transacción de ejecución.
Cuando devuelve DdeClientTransaction , el cliente puede usar el parámetro lpdwResult para acceder a la marca de estado de la transacción. Si la marca está DDE_FBUSY, el cliente debe enviar la transacción de nuevo más adelante.
Si un servidor no admite la transacción de XTYP_EXECUTE , debe especificar la marca de filtro CBF_FAIL_EXECUTES en la función DdeInitialize . Al hacerlo, se impide que DDEML envíe la transacción al servidor.
Transacciones sincrónicas y asincrónicas
Un cliente puede enviar transacciones sincrónicas o asincrónicas. En una transacción sincrónica, el cliente especifica un valor de tiempo de espera que indica la cantidad máxima de tiempo que esperará al servidor para procesar la transacción. DdeClientTransaction no devuelve hasta que el servidor procesa la transacción, se produce un error en la transacción o el valor de tiempo de espera expira. El cliente especifica el valor de tiempo de espera cuando llama a DdeClientTransaction.
Durante una transacción sincrónica, el cliente entra en un bucle modal mientras espera a que se procese la transacción. El cliente todavía puede procesar la entrada del usuario, pero no puede enviar otra transacción sincrónica hasta que DdeClientTransaction devuelva.
Un cliente envía una transacción asincrónica especificando la marca TIMEOUT_ASYNC en DdeClientTransaction. La función devuelve una vez iniciada la transacción, pasando un identificador de transacción al cliente. Cuando el servidor termina de procesar la transacción asincrónica, DDEML envía una transacción XTYP_XACT_COMPLETE al cliente. Uno de los parámetros que DDEML pasa al cliente durante la transacción de XTYP_XACT_COMPLETE es el identificador de transacción. Al comparar este identificador de transacción con el identificador devuelto por DdeClientTransaction, el cliente identifica la transacción asincrónica que el servidor ha terminado de procesar.
Un cliente puede usar la función DdeSetUserHandle como ayuda para procesar una transacción asincrónica. Esta función permite a un cliente asociar un valor definido por la aplicación con un identificador de conversación y un identificador de transacción. El cliente puede usar la función DdeQueryConvInfo durante la transacción de XTYP_XACT_COMPLETE para obtener el valor definido por la aplicación. Debido a esta función, una aplicación no necesita mantener una lista de identificadores de transacción activos.
Cuando un cliente completa correctamente una solicitud de datos mediante una transacción sincrónica, DDEML no tiene forma de indicar cuándo el cliente ha terminado de usar los datos recibidos. La aplicación cliente debe pasar el identificador de datos recibido a la función DdeFreeDataHandle , notificando al DDEML que el identificador ya no se usará. Los identificadores de datos devueltos por transacciones sincrónicas son propiedad efectiva del cliente.
Si un servidor no procesa una transacción asincrónica de forma oportuna, el cliente puede abandonar la transacción llamando a la función DdeAbandonTransaction . DDEML libera todos los recursos asociados a la transacción y descarta los resultados de la transacción cuando el servidor termina de procesarlo. Un tiempo de espera durante una transacción sincrónica cancela eficazmente la transacción.
El método de transacción asincrónico se proporciona para las aplicaciones que deben enviar un gran volumen de transacciones DDE mientras realizan simultáneamente una cantidad considerable de procesamiento, como realizar cálculos. El método asincrónico también es útil en las aplicaciones que deben detener el procesamiento de transacciones DDE temporalmente para que puedan completar otras tareas sin interrupción. En la mayoría de las otras situaciones, una aplicación debe usar el método sincrónico.
Las transacciones sincrónicas son más sencillas de mantener y son más rápidas que las transacciones asincrónicas. Sin embargo, solo se puede realizar una transacción sincrónica a la vez, mientras que muchas transacciones asincrónicas se pueden realizar simultáneamente. Con las transacciones sincrónicas, un servidor lento puede hacer que un cliente permanezca inactivo mientras espera una respuesta. Además, las transacciones sincrónicas hacen que el cliente escriba un bucle modal que pueda omitir el filtrado de mensajes en el propio bucle de mensajes de la aplicación.
Si el cliente ha instalado un procedimiento de enlace para filtrar mensajes (es decir, es decir, el tipo de enlace de WH_MSGFILTER en una llamada a la función SetWindowsHookEx ), una transacción sincrónica no hará que el sistema omita el procedimiento de enlace. Cuando se produce un evento de entrada mientras el cliente espera a que finalice una transacción sincrónica, el procedimiento de enlace recibe un código de enlace MSGF_DDEMGR. El principal peligro de usar un bucle modal de transacción sincrónica es que un bucle modal creado por un cuadro de diálogo puede interferir con su operación. Las transacciones asincrónicas siempre deben usarse cuando un archivo DLL usa DDEML.
Control de transacciones
Una aplicación puede suspender transacciones a su función de devolución de llamada DDE, ya sea aquellas transacciones asociadas a un identificador de conversación específico o a todas las transacciones independientemente del identificador de conversación. Esta funcionalidad es útil cuando una aplicación recibe una transacción que requiere un procesamiento prolongado. En tal caso, la aplicación puede devolver el CBR_BLOCK código de retorno para suspender las transacciones futuras asociadas con el identificador de conversación de la transacción, de modo que la aplicación pueda procesar otras conversaciones.
Cuando se ha completado el procesamiento, la aplicación llama a la función DdeEnableCallback para reanudar las transacciones asociadas a la conversación suspendida. La llamada a DdeEnableCallback hace que DDEML vuelva a enviar la transacción que dio lugar a que la aplicación suspenda la conversación. Por lo tanto, la aplicación debe almacenar el resultado de la transacción de tal manera que pueda obtener y devolver el resultado sin volver a procesar la transacción.
Una aplicación puede suspender todas las transacciones asociadas a un identificador de conversación específico especificando el identificador y la marca EC_DISABLE en una llamada a DdeEnableCallback. Al especificar un identificador NULL , una aplicación puede suspender todas las transacciones de todas las conversaciones.
Cuando se ha suspendido una conversación, DDEML guarda las transacciones de la conversación en una cola de transacciones. Cuando la aplicación vuelve a habilitar la conversación, DDEML quita las transacciones guardadas de la cola y pasa cada transacción a la función de devolución de llamada adecuada. La capacidad de la cola de transacciones es grande, pero una aplicación debe volver a habilitar una conversación suspendida lo antes posible para evitar la pérdida de transacciones.
Una aplicación puede reanudar el procesamiento de transacciones habituales especificando la marca EC_ENABLEALL en DdeEnableCallback. Para una reanudación más controlada del procesamiento de transacciones, la aplicación puede especificar la marca EC_ENABLEONE. Esta marca quita una transacción de la cola de transacciones y la pasa a la función de devolución de llamada adecuada; una vez procesada esa transacción, las conversaciones se vuelven a deshabilitar.
Si la marca de EC_ENABLEONE y un identificador de conversación se especifican en la llamada a DdeEnableCallback, solo esa conversación se bloquea después de procesar la transacción. Si se especifica un identificador de conversación NULL , todas las conversaciones se bloquean después de procesar una transacción en cualquier conversación.
Clases de transacción
DDEML tiene cuatro clases de transacciones. Cada clase se identifica mediante una constante que comienza con el prefijo XCLASS_. Las clases se definen en el archivo de encabezado DDEML. El valor de clase se combina con el valor de tipo de transacción y se pasa a la función de devolución de llamada DDE de la aplicación receptora.
La clase de una transacción determina el valor devuelto que se espera que una función de devolución de llamada devuelva si procesa la transacción. Los siguientes valores devueltos y tipos de transacción están asociados a cada una de las cuatro clases de transacción.
Clase | Valor devuelto | Transacción |
---|---|---|
XCLASS_BOOL | TRUE o FALSE |
XTYP_ADVSTART XTYP_CONNECT |
XCLASS_DATA | Un identificador de datos, el CBR_BLOCK código de retorno o NULL |
XTYP_ADVREQ XTYP_REQUEST XTYP_WILDCONNECT |
XCLASS_FLAGS | Marca de transacción: DDE_FACK, DDE_FBUSY o DDE_FNOTPROCESSED |
XTYP_ADVDATA XTYP_EXECUTE XTYP_POKE |
XCLASS_NOTIFICATION | None |
XTYP_ADVSTOP XTYP_CONNECT_CONFIRM XTYP_DISCONNECT XTYP_ERROR XTYP_REGISTER XTYP_UNREGISTER XTYP_XACT_COMPLETE |
Tipos de transacción
Cada tipo de transacción DDE tiene un receptor y una actividad asociada que hace que DDEML genere cada tipo.
Tipo de transacción | Receptor | Causa |
---|---|---|
XTYP_ADVDATA | Remoto | Un servidor respondió a una transacción de XTYP_ADVREQ devolviendo un identificador de datos. |
XTYP_ADVREQ | Servidor | Un servidor denominado función DdePostAdvise , que indica que el valor de un elemento de datos en un bucle de aviso ha cambiado. |
XTYP_ADVSTART | Servidor | Un cliente especificó el tipo de transacción XTYP_ADVSTART en una llamada a la función DdeClientTransaction . |
XTYP_ADVSTOP | Servidor | Un cliente especificó el tipo de transacción XTYP_ADVSTOP en una llamada a DdeClientTransaction. |
XTYP_CONNECT | Servidor | Un cliente llamado la función DdeConnect y especificó un nombre de servicio y un nombre de tema admitidos por el servidor. |
XTYP_CONNECT_CONFIRM | Servidor | El servidor devolvió TRUE en respuesta a una transacción de XTYP_CONNECT o XTYP_WILDCONNECT . |
XTYP_DISCONNECT | Cliente/servidor | Asociado de una conversación denominada función DdeDisconnect , lo que hace que ambos asociados reciban esta transacción. |
XTYP_ERROR | Cliente/servidor | Se ha producido un error crítico. Es posible que DDEML no tenga recursos suficientes para continuar. |
XTYP_EXECUTE | Servidor | Un cliente especificó el tipo de transacción XTYP_EXECUTE en una llamada a DdeClientTransaction. |
XTYP_MONITOR | Aplicación de supervisión de DDE | Se produjo un evento DDE en el sistema. Para obtener más información sobre las aplicaciones de supervisión de DDE, consulte Supervisión de aplicaciones. |
XTYP_POKE | Servidor | Un cliente especificó el tipo de transacción XTYP_POKE en una llamada a DdeClientTransaction. |
XTYP_REGISTER | Cliente/servidor | Una aplicación de servidor usó la función DdeNameService para registrar un nombre de servicio. |
XTYP_REQUEST | Servidor | Un cliente especificó el tipo de transacción XTYP_REQUEST en una llamada a DdeClientTransaction. |
XTYP_UNREGISTER | Cliente/servidor | Una aplicación de servidor usó DdeNameService para anular el registro de un nombre de servicio. |
XTYP_WILDCONNECT | Servidor | Un cliente llamado la función DdeConnect o DdeConnectList , especificando NULL para el nombre del servicio, el nombre del tema o ambos. |
XTYP_XACT_COMPLETE | Remoto | Una transacción asincrónica, enviada cuando el cliente especificó la marca TIMEOUT_ASYNC en una llamada a DdeClientTransaction, ha concluido. |