Multitasking with Windows

The Windows operating system is a cooperative, nonpreemptive multitasking system. In a Windows-based program, use either of the following background processing techniques to complete a long task, such as processing a query. The first technique uses a PeekMessage loop instead of a GetMessage loop in the WinMain function, and requires the creation of a function to do a small piece of the background task each time it is called. The second technique uses the Windows timer. Both techniques use the dbsqlsend, dbdataready, and dbsqlok functions to allow background processing of a query.

The following example WinMain function shows how to create a PeekMessage loop for background processing. The benefits of this technique include:

//////////////////////////////////////////////////////////////////////
//
//  FUNCTION: WinMain
//
//  PURPOSE: Calls initialization function, processes message loop
//
//  COMMENTS:  Uses a PeekMessage loop for background processing
//  Note that this is a modified version of the Windows-based GENERIC 
//  sample application.
//
//////////////////////////////////////////////////////////////////////

int PASCAL WinMain(
    HANDLE hInstance,
    HANDLE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow)
{
    MSG msg;    // message 

    if (!hPrevInstance)
        if (!InitApplication(hInstance))  // Initialize shared things 
            return (FALSE);

    // Perform initializations that apply to a specific instance 
    if (!InitInstance(hInstance, nCmdShow))
        return (FALSE);

    while (TRUE)
    {
        if (PeekMessage(&msg,
            NULL,
            0,
            0,
            PM_REMOVE))
        {
            // PeekMessage has found a message--process it 
            if (msg.message != WM_QUIT)
            {
                TranslateMessage(&msg); // Translate virt. key codes 
                DispatchMessage(&msg);  // Dispatch msg. to window 
            }
            else
            {
                // WM_QUIT message found, so break out of the
                // message loop
                 
                break;
            }
        }
        else
        {
            // PeekMessage has not found a message, so call
            // DoBackgroundPart to do a portion of the background
            // processing. DoBackgroundPart returns TRUE if
            // it has more background work to do, or FALSE when all
            // background work is completed.
             
            if (!DoBackgroundPart())
            {
                // All background processing is now finished, so call
                // WaitMessage to yield control to Windows.
                 
                WaitMessage();
            }
        }
    }

    return (msg.wParam);    // Returns the value from PostQuitMessage 
}

The preceding example calls a user-defined function DoBackgroundPart that does a small portion of the background processing each time it is called. In a DB-Library program, this function should do background query processing. A sample DoBackgroundPart function is shown below. This function returns true when it needs to continue processing the query, and false when the query processing is complete.

///////////////////////////////////////////////////////////////////
//
//  FUNCTION:   DoBackgroundPart()
//
//  PURPOSE:    Does a small part of the background processing each
//              time it is called.
//
//  COMMENTS:   This function assumes two global variables.
//
//                  DBPROCESS//pDbproc;
//                  BOOL bQueryPending;
//
//              bQueryPending is TRUE only after another
//              part of the program has sent a query to 
//              SQL Server using the dbsqlsend function.
//
//  RETURNS:    TRUE when there is more background work to do
//              FALSE when no background work is pending.
//
///////////////////////////////////////////////////////////////////

BOOL DoBackgroundPart(void)
{
    BOOL bContinue = FALSE;

    // bQueryPending is a global flag indicating if query
    // processing is pending
     
    if (bQueryPending)
    {
        if (dbdataready(pDbproc))
        {
            dbsqlok(pDbproc);
            ProcessQuery();
            bQueryPending = FALSE;
            bContinue = FALSE;
        }
        else
        {
            bContinue = TRUE;
        }
    }
    else
    {
        bContinue = FALSE;
    }
    return (bContinue);
}

The second background processing technique uses a Windows timer and does not require a PeekMessage loop. The following example illustrates the timer technique, and should be placed in the main window procedure. The SetTimer function creates a timer that sends a WM_TIMER message to your application every 1000 milliseconds. Have your application check dbdataready after each WM_TIMER message.

case WM_SENDQUERY:
    dbsqlsend (pDbproc);
    SetTimer (hWnd, 1, 1000, 0);
    break;

case WM_TIMER:
    if (dbdataready(pDbproc))
    {
        dbsqlok (pDbproc);
        KillTimer (hWnd, 1);
        ProcessQuery();
    }
    break;

For further information about programming for Microsoft Windows, see your documentation for Windows.