/*++
 *
 *  WOW v1.0
 *
 *  Copyright (c) 1991, Microsoft Corporation
 *
 *  WUMAN.C
 *  WOW32 16-bit User API support (manually-coded thunks)
 *
 *  History:
 *  Created 27-Jan-1991 by Jeff Parsons (jeffpar)
--*/


#include "precomp.h"
#pragma hdrstop

MODNAME(wuman.c);

WBP W32WordBreakProc = NULL;

extern DWORD fThunkStrRtns;


/* Called By Kernel When Initialization is Complete */

ULONG FASTCALL WU32FinalUserInit(PVDMFRAME pFrame)
{
    UNREFERENCED_PARAMETER(pFrame);
    return TRUE;
}


ULONG FASTCALL WU32ExitWindows(PVDMFRAME pFrame)
// BUGBUG mattfe 4-mar-92, this routine should not return if we close down
// all the apps successfully.
{
    ULONG ul;
    register PEXITWINDOWS16 parg16;

    GETARGPTR(pFrame, sizeof(EXITWINDOWS16), parg16);

    ul = GETBOOL16(ExitWindows(
    DWORD32(parg16->dwReserved),
    WORD32(parg16->wReturnCode)
    ));

    FREEARGPTR(parg16);

    RETURN(ul);
}

WORD gUser16CS = 0;

ULONG FASTCALL WU32NotifyWow(PVDMFRAME pFrame)
{
    ULONG ul;
    register PNOTIFYWOW16 parg16;

    GETARGPTR(pFrame, sizeof(NOTIFYWOW16), parg16);

    switch (FETCHWORD(parg16->Id)) {
        case FUN_LOADACCELERATORS:
            ul = WU32LoadAccelerators(FETCHDWORD(parg16->pData));
            break;

        case FUN_LOADICON:
        case FUN_LOADCURSOR:
            ul = (ULONG) W32CheckIfAlreadyLoaded(parg16->pData, FETCHWORD(parg16->Id));
            break;

        case FUN_WINHELP:
            {
                // this call is made from IWinHelp in USER.exe to find the
                // '16bit' help window if it exists.
                //

                LPSZ lpszClass;
                GETMISCPTR(parg16->pData, lpszClass);
                ul = (ULONG)(pfnOut.pfnWOWFindWindow)((LPCSTR)lpszClass, (LPCSTR)NULL);
                if (ul) {
                    // check if hwndWinHelp belongs to this process or not.
                    DWORD pid, pidT;
                    pid = pidT = GetCurrentProcessId();
                    GetWindowThreadProcessId((HWND)ul, &pid);
                    ul = (ULONG)MAKELONG((WORD)GETHWND16(ul),(WORD)(pid == pidT));
                }
                FREEMISCPTR(lpszClass);
            }
            break;

        case FUN_FINALUSERINIT:
            {
                static BYTE CallCsrFlag = 0;
                extern DWORD   gpsi;
                PUSERCLIENTGLOBALS pfinit16;
                WORD UNALIGNED *pwMaxDWPMsg;
                PBYTE pDWPBits;
#ifdef DEBUG
                WORD wMsg;
                int i;
                PSZ pszFormat;
#endif

                GETVDMPTR(parg16->pData, sizeof(USERCLIENTGLOBALS), pfinit16);
                GETVDMPTR(pfinit16->lpwMaxDWPMsg, sizeof(WORD), pwMaxDWPMsg);
                GETVDMPTR(pfinit16->lpDWPBits, pfinit16->cbDWPBits, pDWPBits);

                // store the 16bit hmod of user.exe
                gUser16hInstance = (WORD)pfinit16->hInstance;
                WOW32ASSERTMSGF((gUser16hInstance),
                                ("WOW Error gUser16hInstance == NULL!\n"));

                // store the 16bit CS of user.exe
                gUser16CS = HIWORD(pFrame->vpCSIP);

                // initialize user16client globals

                if (pfinit16->lpgpsi) {
                    BYTE **lpT;
                    GETVDMPTR(pfinit16->lpgpsi, sizeof(DWORD), lpT);
                    *lpT = (BYTE *)gpsi;
                    FLUSHVDMCODEPTR((ULONG)pfinit16->lpgpsi, sizeof(DWORD), lpT);
                    FREEVDMPTR(lpT);
                }
                if (pfinit16->lpCsrFlag) {
                    BYTE **lpT;
                    GETVDMPTR(pfinit16->lpCsrFlag, sizeof(DWORD), lpT);
                    *lpT = (LPSTR)&CallCsrFlag;
                    FLUSHVDMCODEPTR((ULONG)pfinit16->lpCsrFlag, sizeof(DWORD), lpT);
                    FREEVDMPTR(lpT);
                }

                if (HIWORD(pfinit16->dwBldInfo) != HIWORD(pfnOut.dwBldInfo)) {
                    MessageBeep(0);
                    MessageBoxA(NULL, "user.exe and user32.dll are mismatched.",
                            "WOW Error", MB_OK | MB_ICONEXCLAMATION);
                }

                *pwMaxDWPMsg = (pfnOut.pfnWowGetDefWindowProcBits)(pDWPBits, pfinit16->cbDWPBits);

                FLUSHVDMCODEPTR(pfinit16->lpwMaxDWPMsg, sizeof(WORD), pwMaxDWPMsg);
                FLUSHVDMCODEPTR(pfinit16->lpDWPBits, pfinit16->cbDWPBits, pDWPBits);

#ifdef DEBUG
                LOGDEBUG(LOG_TRACE, ("WU32NotifyWow: got DefWindowProc bits, wMaxDWPMsg = 0x%x.\n", *pwMaxDWPMsg));
                LOGDEBUG(LOG_TRACE, ("The following messages will be passed on to 32-bit DefWindowProc:\n"));

#define FPASSTODWP32(msg) \
    (pDWPBits[msg >> 3] & (1 << (msg & 7)))

                wMsg = 0;
                i = 0;

                while (wMsg <= *pwMaxDWPMsg) {
                    if (FPASSTODWP32(wMsg)) {
                        if ( i & 3 ) {
                            pszFormat = ", %s";
                        } else {
                            pszFormat = "\n%s";
                        }
                        LOGDEBUG(LOG_TRACE, (pszFormat, aw32Msg[wMsg].lpszW32));
                        i++;
                    }
                    wMsg++;
                }

                LOGDEBUG(LOG_TRACE, ("\n\n"));
#endif

                //
                // Return value tells User16 whether to thunk
                // string routines to Win32 or use the fast
                // US-only versions.  TRUE means thunk.
                //
                // If the locale is U.S. English, we default to
                // not thunking, outside the U.S. we default to
                // thunking.  See wow32.c's use of fThunkStrRtns.
                //
                // We engage in this nastiness because the Winstone 94
                // Access 1.1 test takes *twice* as long to run in
                // the US if we thunk lstrcmp and lstrcmpi to Win32.
                //
                // By adding a value "ThunkNLS" to the WOW registry
                // key of type REG_DWORD, the user can force thunking
                // to Win32 (value 1) or use the fast US-only ones (value 0).
                //

                ul = fThunkStrRtns;

                FREEVDMPTR(pDWPBits);
                FREEVDMPTR(pwMaxDWPMsg);
                FREEVDMPTR(pfinit16);

            }
            break;

        default:
            ul = 0;
            break;
    }

    FREEARGPTR(parg16);
    return ul;
}


ULONG FASTCALL WU32WordBreakProc(PVDMFRAME pFrame)
{
    PSZ         psz1;
    ULONG ul;
    register PWORDBREAKPROC16 parg16;

    GETARGPTR(pFrame, sizeof(WORDBREAKPROC16), parg16);
    GETPSZPTR(parg16->lpszEditText, psz1);

    ul = (*W32WordBreakProc)(psz1, parg16->ichCurrentWord, parg16->cbEditText,
                             parg16->action);

    FREEPSZPTR(psz1);
    FREEARGPTR(parg16);
    RETURN(ul);
}

//
// WU32MouseEvent:  Thunk for 16-bit register-based API mouse_event,
//                  with the help of user16 function mouse_event (in
//                  winmisc2.asm).
//

ULONG FASTCALL WU32MouseEvent(PVDMFRAME pFrame)
{
    ULONG ul;
    register PMOUSEEVENT16 parg16;
    typedef ULONG (WINAPI *PFMOUSE_EVENT)(DWORD, DWORD, DWORD, DWORD, DWORD);

    GETARGPTR(pFrame, sizeof(PMOUSEEVENT16), parg16);

    //
    // mouse_event is declared void, but we'll return the same value as
    // user32.
    //

    ul = ((PFMOUSE_EVENT)(PVOID)mouse_event)(
             parg16->wFlags,
             parg16->dx,
             parg16->dy,
             parg16->cButtons,
             parg16->dwExtraInfo
             );

    FREEARGPTR(parg16);
    RETURN(ul);
}



//
// WU32KeybdEvent:  Thunk for 16-bit register-based API keybd_event,
//                  with the help of user16 function keybd_event (in
//                  winmisc2.asm).
//

ULONG FASTCALL WU32KeybdEvent(PVDMFRAME pFrame)
{
    ULONG ul;
    register PKEYBDEVENT16 parg16;
    typedef ULONG (WINAPI *PFKEYBD_EVENT)(BYTE, BYTE, DWORD, DWORD);

    GETARGPTR(pFrame, sizeof(PKEYBDEVENT16), parg16);

    //
    // keybd_event is declared void, but we'll return the same value as
    // user32.
    //

    ul = ((PFKEYBD_EVENT)(PVOID)keybd_event)(
             LOBYTE(parg16->bVirtualKey),
             LOBYTE(parg16->bScanCode),
             ((HIBYTE(parg16->bVirtualKey) == 0x80) ? KEYEVENTF_KEYUP : 0) |
             ((HIBYTE(parg16->bScanCode) == 0x1) ? KEYEVENTF_EXTENDEDKEY : 0),
             parg16->dwExtraInfo
             );

    FREEARGPTR(parg16);
    RETURN(ul);
}