/*++

Copyright (C) Microsoft Corporation, 1994 - 1999

Module Name:

    server.c

Abstract:

    Server side of post message test.  Note, this guy is a hidden
    win32 app.  The client controls it via PostMessage.  It's ugly.

Author:

    Mario Goertzel (mariogo)   31-Mar-1994

Revision History:
--*/

#include <rpcperf.h>
#include <pmsgtest.h>

HANDLE hRequestEvent;
HANDLE hReplyEvent;
HANDLE hWorkerEvent;
HANDLE hWorkerThread;
BOOL   fShutdown = FALSE;
LONG   lIterations;
LONG   lTestCase;
BOOL   fMsgMO = 0;

BOOL APIENTRY InitInstance(HINSTANCE, INT);
LRESULT APIENTRY MainWndProc(HWND, UINT, WPARAM, LPARAM);

DWORD WINAPI Worker (LPVOID);

int APIENTRY WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    LPSTR lpCmdLine,
    int nCmdShow
    )
{
    ULONG cCount = 1;
    ULONG status;
    int fStop;
    MSG msg;

    UNREFERENCED_PARAMETER( lpCmdLine );

    if (hPrevInstance)
        {
        return FALSE;
        }

    if (!InitInstance(hInstance, nCmdShow))
        return FALSE;

    fStop = 0;
    while (!fStop)
        {
        if (fMsgMO)
            {
            status = MsgWaitForMultipleObjects(cCount,
                                               &hRequestEvent,
                                               FALSE,
                                               2000,
                                               QS_ALLINPUT);
            if (status == WAIT_OBJECT_0)
                {

                if (lTestCase == 11)
                    SetEvent(hWorkerEvent);
                else
                    SetEvent(hReplyEvent);

                continue;

                }
            else if (status == WAIT_OBJECT_0 + 1)
                {
                // Fall through and do a GetMessage and DispatchMessage.
                }
            else
                {
                *(long *)status = 10;  //GPF on error.
                }
            }

        if (GetMessage(&msg, NULL, 0, 0) == FALSE)
            {
            break;
            }

        DispatchMessage(&msg);
        }
    return (int) msg.wParam;
}

BOOL APIENTRY InitInstance( HINSTANCE hInstance, INT nCmdShow )
{
    HWND     hWnd;
    WNDCLASS wc;
    DWORD    dwThreadId;

    wc.style = 0; //CS_HREDRAW | CS_VREDRAW;        // redraw if size changes
    wc.lpfnWndProc = MainWndProc;                   // points to window proc.
    wc.cbClsExtra = 0;                              // no extra class memory
    wc.cbWndExtra = 0;                              //  no extra window memory
    wc.hInstance = hInstance;                       // handle of instance
    wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);      // predefined app. icon
    wc.hCursor = LoadCursor(NULL,IDC_ARROW);        // predefined arrow
    wc.hbrBackground = GetStockObject(WHITE_BRUSH); // white background brush
    wc.lpszMenuName =  0; //"MainMenu";             // name of menu resource
    wc.lpszClassName = CLASS;                       // name of window class

    if (RegisterClass(&wc) == 0)
        return !GetLastError();

    hWnd = CreateWindow(
                        CLASS,
                        TITLE,
                        0,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        NULL,
                        NULL,
                        hInstance,
                        NULL
                        );

    if (!hWnd) {
        return !GetLastError();
        }

    hRequestEvent = CreateEvent(0,
                                FALSE,
                                FALSE,
                                REQUEST_EVENT);
    if (!hRequestEvent) return FALSE;

    hReplyEvent = CreateEvent(0,
                              FALSE,
                              FALSE,
                              REPLY_EVENT);
    if (!hReplyEvent) return FALSE;

    hWorkerEvent = CreateEvent(0,
                               FALSE,
                               FALSE,
                               WORKER_EVENT);
    if (!hWorkerEvent) return FALSE;

    hWorkerThread = CreateThread(0,
                                 0,
                                 Worker,
                                 0,
                                 0,
                                 &dwThreadId
                                 );
    if (!hWorkerThread) return FALSE;

    return TRUE;
}


LRESULT APIENTRY MainWndProc(
    HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
{

    switch(message)
        {
        case WM_DESTROY:
            CloseHandle(hReplyEvent);
            fShutdown = TRUE;
            SetEvent(hWorkerEvent);
            CloseHandle(hWorkerThread);
            CloseHandle(hWorkerEvent);
            CloseHandle(hReplyEvent);
            CloseHandle(hRequestEvent);
            PostQuitMessage(0);
            break;

        case MSG_PERF_MESSAGE:
            {
            switch(wParam)
                {
                case 3:
                case 9:
                case 11:
                    fMsgMO = TRUE;
                    // Fall through
                case 1:
                case 5:
                case 7:

                    lIterations = (long)lParam;
                    lTestCase   = (long)wParam;
                    SetEvent(hWorkerEvent);

                    // Worker now completes required test and tells the
                    // client when finished.

                    break;

                case 4:
                    fMsgMO = TRUE;
                    // Fall through
                case 2:
                    if (lParam == 0)
                        {
                        // Client sends many messages (queues them up),
                        // server must signal when the last message arrives.
                        SetEvent(hReplyEvent);
                        }
                    break;

                case 6:   // send message
                    return 69;

                case 10:
                    fMsgMO = TRUE;
                    // Fall through
                case 8:
                    SetEvent(hReplyEvent);
                    break;

                case 12:
                    fMsgMO = TRUE;

                default:
                    break;
                }
            }

            case MSG_PERF_MESSAGE2:
            {

                // lParam is the number of iterations left
                // wParam the test case.

                if ( (lParam == 1)
                    || (wParam == 7)
                    || (wParam == 9) )
                    {
                    // Finished all the iterations, or we are running
                    // the force context-switch version. Let the worker know.

                    SetEvent(hWorkerEvent);
                    }

                break;
            }
            case WM_COPYDATA:
            {
            COPYDATASTRUCT *pData = (COPYDATASTRUCT *)lParam;
            return TRUE;
            }
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }

    return TRUE;
}

DWORD WINAPI Worker (LPVOID pArg)
{
    LONG i;
    HWND hWnd = FindWindow(CLASS, TITLE);
    UNREFERENCED_PARAMETER(pArg);

    WaitForSingleObject(hWorkerEvent, INFINITE);
    if (fShutdown) return 0;

    if (lTestCase == 5)
        {
        // SendMessage test case.
        
        for(i = lIterations; i >= 0; i--)
            SendMessage(hWnd, MSG_PERF_MESSAGE2, lTestCase, i);

        goto worker_done;
        }

    if (lTestCase == 11)
        {
        // SetEvent/MsgWaitForMultipleObjects

        for(i = lIterations; i; i--)
            {
            SetEvent(hRequestEvent);
            WaitForSingleObject(hWorkerEvent, INFINITE);
            }
        goto worker_done;
        }

    for (i = lIterations; i; i--)
        {
        // One of the PostMessage test cases.

        PostMessage(hWnd, MSG_PERF_MESSAGE2, lTestCase, i);

        if (lTestCase > 4)
            {
            // Forced context switch version, wait for server
            // to process the last message.

            WaitForSingleObject(hWorkerEvent, INFINITE);
            }
        }

    if (lTestCase <= 4)
        {
        // Wait for the server to finish processing the queued-up messages.
        WaitForSingleObject(hWorkerEvent, INFINITE);
        }

worker_done:
    SetEvent(hReplyEvent);  // Tell the client that we finished this
                            // in process test.
    return 0;
}