Condividi tramite


Esecuzione asincrona (metodo di notifica)

ODBC consente l'esecuzione asincrona di operazioni di connessione e istruzione. Un thread applicazione può chiamare una funzione ODBC in modalità asincrona e la funzione può rispondere prima del completamento dell'operazione, consentendo al thread dell'applicazione di eseguire altre attività. Nell’SDK Windows 7, per le operazioni asincrone di istruzione o connessione, un'applicazione ha determinato che l'operazione asincrona è stata completata usando il metodo di polling. Per altre informazioni, vedere Esecuzione asincrona (metodo di polling). A partire dall’SDK Windows 8, è possibile determinare che un'operazione asincrona è stata completata usando il metodo di notifica.

Nel metodo di polling, le applicazioni devono chiamare la funzione asincrona ogni volta che vuole lo stato dell'operazione. Il metodo di notifica è simile al callback e all'attesa in ADO.NET. ODBC usa tuttavia eventi Win32 come oggetto di notifica.

Non è possibile utilizzare contemporaneamente la libreria di cursori ODBC e la notifica asincrona ODBC. L'impostazione di entrambi gli attributi restituirà un errore SQLSTATE S1119 (la libreria di cursori e la notifica asincrona non possono essere abilitati contemporaneamente).

Per informazioni sugli sviluppatori di driver, vedere Notifica completamento della funzione asincrona.

Nota

Il metodo di notifica non è supportato con la libreria di cursori. Un'applicazione riceverà un messaggio di errore se tenta di abilitare la libreria di cursori tramite SQLSetConnectAttr, quando è abilitato il metodo di notifica.

Panoramica

Quando una funzione ODBC viene chiamata in modalità asincrona, il controllo viene immediatamente restituito all'applicazione chiamante con il codice restituito SQL_STILL_EXECUTING. L'applicazione deve eseguire ripetutamente il polling della funzione fino a quando non restituisce un valore diverso da SQL_STILL_EXECUTING. Il ciclo di polling aumenta l'utilizzo della CPU, causando prestazioni scarse in molti scenari asincroni.

Ogni volta che viene usato il modello di notifica, il modello di polling è disabilitato. Le applicazioni non devono chiamare di nuovo la funzione originale. Chiamare la funzione SQLCompleteAsync per completare l'operazione asincrona. Se un'applicazione chiama nuovamente la funzione originale prima del completamento dell'operazione asincrona, la chiamata restituirà SQL_ERROR con SQLSTATE IM017 (il polling è disabilitato in modalità di notifica asincrona).

Quando si usa il modello di notifica, l'applicazione può chiamare SQLCancel o SQLCancelHandle per annullare un'istruzione o un'operazione di connessione. Se la richiesta di annullamento ha esito positivo, ODBC restituirà SQL_SUCCESS. Questo messaggio non indica che la funzione è stata effettivamente annullata; indica che la richiesta di annullamento è stata elaborata. Se la funzione viene effettivamente annullata dipende dal driver e dall'origine dati. Quando un'operazione viene annullata, Gestione driver segnalerà comunque l'evento. Gestione driver restituisce SQL_ERROR nel buffer del codice restituito e lo stato è SQLSTATE HY008 (Operazione annullata) per indicare che l'annullamento ha esito positivo. Se la funzione ha completato la normale elaborazione, Gestione driver restituisce SQL_SUCCESS o SQL_SUCCESS_WITH_INFO.

Comportamento di livello inferiore

La versione di Gestione driver ODBC che supporta questa notifica una volta terminata l’operazione è ODBC 3.81.

Versione ODBC applicazione Versione Gestione driver Versione driver Comportamento
Nuova applicazione di qualsiasi versione ODBC ODBC 3.81 Driver ODBC 3.80 L'applicazione può usare questa funzionalità se il driver la supporta. In caso contrario, Gestione driver genererà un errore.
Nuova applicazione di qualsiasi versione ODBC ODBC 3.81 Driver precedente a ODBC 3.80 Gestione driver genererà un errore se il driver non supporta questa funzionalità.
Nuova applicazione di qualsiasi versione ODBC Precedente a ODBC 3.81 Any Quando l'applicazione usa questa funzionalità, una Gestione driver precedente considererà i nuovi attributi come attributi specifici del driver, e il driver dovrà generare un errore. Una nuova Gestione driver non passerà questi attributi al driver.

Un'applicazione deve controllare la versione di Gestione driver prima di usare questa funzionalità. In caso contrario, se un driver scritto male non dà errore e la versione di Gestione driver è precedente a ODBC 3.81, il comportamento non è definito.

Casi d'uso

Questa sezione illustra i casi d'uso per l'esecuzione asincrona e il meccanismo di polling.

Integrare dati da più origini ODBC

Un'applicazione di integrazione dati recupera in modo asincrono i dati da più origini dati. Alcuni dati provengono da origini dati remote e altri da file locali. L'applicazione non può continuare fino al completamento delle operazioni asincrone.

Anziché eseguire ripetutamente il polling di un'operazione per determinare se è completa, l'applicazione può creare un oggetto evento e associarlo a un handle di connessione ODBC o a un handle di istruzione ODBC. L'applicazione chiama quindi le API di sincronizzazione del sistema operativo per attendere un oggetto evento o molti oggetti evento (sia eventi ODBC che altri eventi di Windows). ODBC segnalerà l'oggetto evento al termine dell'operazione asincrona ODBC corrispondente.

In Windows, verranno usati gli oggetti evento Win32 e questo fornirà all'utente un modello di programmazione unificato. Gestione driver in altre piattaforme può usare l'implementazione dell'oggetto evento specifica per tali piattaforme.

L'esempio di codice seguente illustra l'uso della notifica asincrona di connessione e istruzione:

// This function opens NUMBER_OPERATIONS connections and executes one query on statement of each connection.  
// Asynchronous Notification is used  
  
#define NUMBER_OPERATIONS 5  
int AsyncNotificationSample(void)  
{  
    RETCODE     rc;  
  
    SQLHENV     hEnv              = NULL;  
    SQLHDBC     arhDbc[NUMBER_OPERATIONS]         = {NULL};  
    SQLHSTMT    arhStmt[NUMBER_OPERATIONS]        = {NULL};  
  
    HANDLE      arhDBCEvent[NUMBER_OPERATIONS]    = {NULL};  
    RETCODE     arrcDBC[NUMBER_OPERATIONS]        = {0};  
    HANDLE      arhSTMTEvent[NUMBER_OPERATIONS]   = {NULL};  
    RETCODE     arrcSTMT[NUMBER_OPERATIONS]       = {0};  
  
    rc = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &hEnv);  
    if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
  
    rc = SQLSetEnvAttr(hEnv,  
        SQL_ATTR_ODBC_VERSION,  
        (SQLPOINTER) SQL_OV_ODBC3_80,  
        SQL_IS_INTEGER);  
    if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
  
    // Connection operations begin here  
  
    // Alloc NUMBER_OPERATIONS connection handles  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &arhDbc[i]);  
        if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
    }  
  
    // Enable DBC Async on all connection handles  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE, (SQLPOINTER)SQL_ASYNC_DBC_ENABLE_ON, SQL_IS_INTEGER);  
        if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
    }  
  
    // Application must create event objects  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        arhDBCEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-signaled  
        if (!arhDBCEvent[i]) goto Cleanup;  
    }  
  
    // Enable notification on all connection handles  
    // Event  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        rc= SQLSetConnectAttr(arhDbc[i], SQL_ATTR_ASYNC_DBC_EVENT, arhDBCEvent[i], SQL_IS_POINTER);  
        if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
    }  
  
    // Initiate connect establishing  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        SQLDriverConnect(arhDbc[i], NULL, (SQLTCHAR*)TEXT("Driver={ODBC Driver 11 for SQL Server};SERVER=dp-srv-sql2k;DATABASE=pubs;UID=sa;PWD=XYZ;"), SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);  
    }  
  
    // Can do some other staff before calling WaitForMultipleObjects  
    WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE); // Wait All  
  
    // Complete connect API calls  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], & arrcDBC[i]);  
    }  
  
    BOOL fFail = FALSE; // Whether some connection openning fails.  
  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        if ( !SQL_SUCCEEDED(arrcDBC[i]) )   
            fFail = TRUE;  
    }  
  
    // If some SQLDriverConnect() fail, clean up.  
    if (fFail)  
    {  
        for (int i=0; i<NUMBER_OPERATIONS; i++)  
        {  
            if (SQL_SUCCEEDED(arrcDBC[i]) )   
            {  
                SQLDisconnect(arhDbc[i]); // This is also async  
            }  
            else  
            {  
                SetEvent(arhDBCEvent[i]); // Previous SQLDriverConnect() failed. No need to call SQLDisconnect().  
            }  
        }  
        WaitForMultipleObjects(NUMBER_OPERATIONS, arhDBCEvent, TRUE, INFINITE);   
        for (int i=0; i<NUMBER_OPERATIONS; i++)  
        {  
            if (SQL_SUCCEEDED(arrcDBC[i]) )   
            {     
                SQLCompleteAsync(SQL_HANDLE_DBC, arhDbc[i], &arrcDBC[i]);; // To Complete  
            }  
        }  
  
        goto Cleanup;  
    }  
  
    // Statement Operations begin here  
  
    // Alloc statement handle  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        rc = SQLAllocHandle(SQL_HANDLE_STMT, arhDbc[i], &arhStmt[i]);  
        if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
    }  
  
    // Enable STMT Async on all statement handles  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        rc = SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_INTEGER);  
        if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
    }  
  
    // Create event objects  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        arhSTMTEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL); // Auto-reset, initial state is not-signaled  
        if (!arhSTMTEvent[i]) goto Cleanup;  
    }  
  
    // Enable notification on all statement handles  
    // Event  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        rc= SQLSetStmtAttr(arhStmt[i], SQL_ATTR_ASYNC_STMT_EVENT, arhSTMTEvent[i], SQL_IS_POINTER);  
        if ( !SQL_SUCCEEDED(rc) ) goto Cleanup;  
    }  
  
    // Initiate SQLExecDirect() calls  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        SQLExecDirect(arhStmt[i], (SQLTCHAR*)TEXT("select au_lname, au_fname from authors"), SQL_NTS);  
    }  
  
    // Can do some other staff before calling WaitForMultipleObjects  
    WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE); // Wait All  
  
    // Now, call SQLCompleteAsync to complete the operation and get return code  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);  
    }  
  
    // Check return values  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;  
    }  
  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        //Do some binding jobs here, set SQL_ATTR_ROW_ARRAY_SIZE   
    }  
  
    // Now, initiate fetching  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        SQLFetch(arhStmt[i]);  
    }  
  
    // Can do some other staff before calling WaitForMultipleObjects  
    WaitForMultipleObjects(NUMBER_OPERATIONS, arhSTMTEvent, TRUE, INFINITE);   
  
    // Now, to complete the operations and get return code  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        SQLCompleteAsync(SQL_HANDLE_STMT, arhStmt[i], &arrcSTMT[i]);  
    }  
  
    // Check return code  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        if ( !SQL_SUCCEEDED(arrcSTMT[i]) ) goto Cleanup;  
    }  
  
    // USE fetched data here!!  
  
Cleanup:  
  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        if (arhStmt[NUMBER_OPERATIONS])  
        {  
            SQLFreeHandle(SQL_HANDLE_STMT, arhStmt[i]);  
            arhStmt[i] = NULL;  
        }  
    }  
  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        if (arhSTMTEvent[i])  
        {  
            CloseHandle(arhSTMTEvent[i]);  
            arhSTMTEvent[i] = NULL;  
        }  
    }  
  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        if (arhDbc[i])  
        {  
            SQLFreeHandle(SQL_HANDLE_DBC, arhDbc[i]);  
            arhDbc[i] = NULL;  
        }  
    }  
  
    for (int i=0; i<NUMBER_OPERATIONS; i++)  
    {  
        if (arhDBCEvent[i])  
        {  
            CloseHandle(arhDBCEvent[i]);  
            arhDBCEvent[i] = NULL;  
        }  
    }  
  
    if (hEnv)  
    {  
        SQLFreeHandle(SQL_HANDLE_ENV, hEnv);  
        hEnv = NULL;  
    }  
  
    return 0;  
}  
  

Determinare se un driver supporta la notifica asincrona

Un'applicazione ODBC può determinare se un driver ODBC supporta la notifica asincrona chiamando SQLGetInfo. Gestione driver ODBC chiamerà di conseguenza SQLGetInfo del driver con SQL_ASYNC_NOTIFICATION.

SQLUINTEGER InfoValue;  
SQLLEN      cbInfoLength;  
  
SQLRETURN retcode;  
retcode = SQLGetInfo (hDbc,   
                      SQL_ASYNC_NOTIFICATION,   
                      &InfoValue,  
                      sizeof(InfoValue),  
                      NULL);  
if (SQL_SUCCEEDED(retcode))  
{  
if (SQL_ASYNC_NOTIFICATION_CAPABLE == InfoValue)  
      {  
          // The driver supports asynchronous notification  
      }  
      else if (SQL_ASYNC_NOTIFICATION_NOT_CAPABLE == InfoValue)  
      {  
          // The driver does not support asynchronous notification  
      }  
}  

Associazione di un handle di eventi Win32 a un handle ODBC

Le applicazioni sono responsabili della creazione di oggetti evento Win32 usando le funzioni Win32 corrispondenti. Un'applicazione può associare un handle di eventi Win32 a un handle di connessione ODBC o a un handle di istruzione ODBC.

Gli attributi di connessione SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE e SQL_ATTR_ASYNC_DBC_EVENT determinano se ODBC viene eseguito in modalità asincrona e se ODBC abilita la modalità di notifica per un handle di connessione. Gli attributi di istruzione SQL_ATTR_ASYNC_ENABLE e SQL_ATTR_ASYNC_STMT_EVENT determinano se ODBC viene eseguito in modalità asincrona e se ODBC abilita la modalità di notifica per un handle di istruzione.

SQL_ATTR_ASYNC_ENABLE o SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE SQL_ATTR_ASYNC_STMT_EVENT o SQL_ATTR_ASYNC_DBC_EVENT Modalità
Abilitare non null Notifica asincrona
Abilitare Null Polling asincrono
Disabilita qualsiasi Sincrona

Un'applicazione può disabilitare in modo temporaneo la modalità operativa asincrona. ODBC ignora i valori di SQL_ATTR_ASYNC_DBC_EVENT se l'operazione asincrona a livello di connessione è disabilitata. ODBC ignora i valori di SQL_ATTR_ASYNC_STMT_EVENT se l'operazione asincrona a livello di istruzione è disabilitata.

Chiamata sincrona di SQLSetStmtAttr e SQLSetConnectAttr

  • SQLSetConnectAttr supporta operazioni asincrone, ma la chiamata di SQLSetConnectAttr per impostare SQL_ATTR_ASYNC_DBC_EVENT è sempre sincrona.

  • SQLSetStmtAttr non supporta l'esecuzione asincrona.

Scenario di errore
Quando SQLSetConnectAttr viene chiamato prima di stabilire una connessione, Gestione driver non è in grado di determinare quale driver usare. Pertanto, Gestione driver restituisce l'esito positivo di SQLSetConnectAttr, ma l'attributo potrebbe non essere pronto per l'impostazione nel driver. Gestione driver imposta questi attributi quando l'applicazione chiama una funzione di connessione. Gestione driver può generare un errore perché il driver non supporta le operazioni asincrone.

Ereditarietà degli attributi di connessione
In genere, le istruzioni di una connessione erediteranno gli attributi di connessione. Tuttavia, l'attributo SQL_ATTR_ASYNC_DBC_EVENT non può essere ereditato e influisce solo sulle operazioni di connessione.

Per associare un handle di evento a un handle di connessione ODBC, un'applicazione ODBC chiama l’API ODBC SQLSetConnectAttr e specifica SQL_ATTR_ASYNC_DBC_EVENT come attributo, e l'handle di evento come valore dell'attributo. Il nuovo attributo ODBC SQL_ATTR_ASYNC_DBC_EVENT è di tipo SQL_IS_POINTER.

HANDLE hEvent;  
hEvent = CreateEvent(   
            NULL,                // default security attributes  
            FALSE,               // auto-reset event  
            FALSE,               // initial state is non-signaled  
            NULL                 // no name  
            );  

In genere, le applicazioni creano oggetti evento di reimpostazione automatica. ODBC non reimposta l'oggetto evento. Le applicazioni devono assicurarsi che l'oggetto non sia in stato segnalato prima di chiamare qualsiasi funzione ODBC asincrona.

SQLRETURN retcode;  
retcode = SQLSetConnectAttr ( hDBC,  
                              SQL_ATTR_ASYNC_DBC_EVENT, // Attribute name  
                              (SQLPOINTER) hEvent,      // Win32 Event handle  
                              SQL_IS_POINTER);          // Length Indicator  

SQL_ATTR_ASYNC_DBC_EVENT è un attributo solo di Gestione driver che non verrà impostato nel driver.

Il valore predefinito di SQL_ATTR_ASYNC_DBC_EVENT è NULL. Se il driver non supporta la notifica asincrona, il recupero o l'impostazione di SQL_ATTR_ASYNC_DBC_EVENT restituirà SQL_ERROR con SQLSTATE HY092 (identificatore di attributo/opzione non valido).

Se l'ultimo valore SQL_ATTR_ASYNC_DBC_EVENT impostato su un handle di connessione ODBC non è NULL e l'applicazione ha abilitato la modalità asincrona impostando l'attributo SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE con SQL_ASYNC_DBC_ENABLE_ON, la chiamata a qualsiasi funzione di connessione ODBC che supporta la modalità asincrona riceverà una notifica di completamento. Se l'ultimo valore SQL_ATTR_ASYNC_DBC_EVENT impostato su un handle di connessione ODBC è NULL, ODBC non invierà alcuna notifica all'applicazione, indipendentemente dal fatto che la modalità asincrona sia abilitata.

Un'applicazione può impostare SQL_ATTR_ASYNC_DBC_EVENT prima o dopo l'impostazione dell'attributo SQL_ATTR_ASYNC_DBC_FUNCTION_ENABLE.

Le applicazioni possono impostare l'attributo SQL_ATTR_ASYNC_DBC_EVENT su un handle di connessione ODBC prima di chiamare una funzione di connessione (SQLConnect, SQLBrowseConnect o SQLDriverConnect). Poiché Gestione driver ODBC non conosce il driver ODBC che verrà usato dall'applicazione, restituirà SQL_SUCCESS. Quando l'applicazione chiama una funzione di connessione, Gestione driver ODBC verificherà se il driver supporta la notifica asincrona. Se il driver non supporta la notifica asincrona, Gestione driver ODBC restituirà SQL_ERROR con SQLSTATE S1_118 (il driver non supporta la notifica asincrona). Se il driver supporta la notifica asincrona, Gestione driver ODBC chiamerà il driver e imposterà gli attributi corrispondenti SQL_ATTR_ASYNC_DBC_NOTIFICATION_CALLBACK e SQL_ATTR_ASYNC_DBC_NOTIFICATION_CONTEXT.

Analogamente, un'applicazione chiama SQLSetStmtAttr su un handle di istruzione ODBC e specifica l'attributo SQL_ATTR_ASYNC_STMT_EVENT per abilitare o disabilitare la notifica asincrona a livello di istruzione. Poiché una funzione di istruzione viene sempre chiamata dopo la connessione, SQLSetStmtAttr restituirà immediatamente SQL_ERROR con SQLSTATE S1_118 (il driver non supporta la notifica asincrona) se il driver corrispondente non supporta operazioni asincrone o se il driver supporta l'operazione asincrona ma non supporta la notifica asincrona.

SQLRETURN retcode;  
retcode = SQLSetStmtAttr ( hSTMT,  
                           SQL_ATTR_ASYNC_STMT_EVENT, // Attribute name   
                           (SQLPOINTER) hEvent,       // Win32 Event handle  
                           SQL_IS_POINTER);           // length Indicator  

SQL_ATTR_ASYNC_STMT_EVENT, che può essere impostato su NULL, è un attributo solo di Gestione driver che non verrà impostato nel driver.

Il valore predefinito di SQL_ATTR_ASYNC_STMT_EVENT è NULL. Se il driver non supporta la notifica asincrona, il recupero o l'impostazione dell’attributo SQL_ATTR_ASYNC_STMT_EVENT restituirà SQL_ERROR con SQLSTATE HY092 (identificatore di attributo/opzione non valido).

Un'applicazione non deve associare lo stesso handle di evento a più handle ODBC. In caso contrario, la notifica andrà persa se due chiamate di funzione ODBC asincrone vengono completate su due handle che condividono lo stesso handle di eventi. Per evitare che un handle di istruzione erediti lo stesso handle di eventi dall'handle di connessione, ODBC restituisce SQL_ERROR con SQLSTATE IM016 (Impossibile impostare l'attributo dell'istruzione nell'handle di connessione) se un'applicazione imposta SQL_ATTR_ASYNC_STMT_EVENT su un handle di connessione.

Chiamata di funzioni ODBC asincrone

Dopo aver abilitato la notifica asincrona e aver avviato un'operazione asincrona, l'applicazione può chiamare qualsiasi funzione ODBC. Se la funzione appartiene al set di funzioni che supportano l'operazione asincrona, l'applicazione riceverà una notifica di completamento al termine dell'operazione, indipendentemente dal fatto che la funzione abbia esito positivo o negativo. L'unica eccezione si verifica quando l'applicazione chiama una funzione ODBC con un handle di connessione o istruzione non valido. In questo caso, ODBC non otterrà l'handle dell'evento e lo imposterà sullo stato segnalato.

L'applicazione deve assicurarsi che l'oggetto evento associato si trovi in uno stato non segnalato prima di avviare un'operazione asincrona sull'handle ODBC corrispondente. ODBC non reimposta l'oggetto evento.

Ottenere notifiche da ODBC

Un thread dell’applicazione può chiamare WaitForSingleObject per attendere un handle di evento o chiamare WaitForMultipleObjects per attendere una matrice di handle di eventi e essere sospeso fino a quando uno o tutti gli oggetti evento non vengono segnalati o fino a quando non è trascorso l'intervallo di timeout.

DWORD dwStatus = WaitForSingleObject(  
                        hEvent,  // The event associated with the ODBC handle  
                        5000     // timeout is 5000 millisecond   
);  
  
If (dwStatus == WAIT_TIMEOUT)  
{  
    // time-out interval elapsed before all the events are signaled.   
}  
Else  
{  
    // Call the corresponding Asynchronous ODBC API to complete all processing and retrieve the return code.  
}