//**************************************************************************
// wusercli.c :
//     Contains all functions that execute USER32 client code on 16bitside.
//     Most of these functions don't exist on x86 builds. So any changes
//     to these files must be reflected in wow16\user\usercli.asm
//
//                                                          - nanduri
//**************************************************************************

#include "precomp.h"
#pragma hdrstop

MODNAME(wusercli.c);


//**************************************************************************
//  WU32ClientToScreen -
//
//**************************************************************************

ULONG FASTCALL WU32ClientToScreen(PVDMFRAME pFrame)
{
    POINT t2;
    register PCLIENTTOSCREEN16 parg16;

    GETARGPTR(pFrame, sizeof(CLIENTTOSCREEN16), parg16);
    GETPOINT16(parg16->f2, &t2);

    ClientToScreen( HWND32(parg16->f1), &t2 );

    PUTPOINT16(parg16->f2, &t2);
    FREEARGPTR(parg16);
    RETURN(0);
}


//**************************************************************************
//  WU32GetClientRect -
//
//**************************************************************************

ULONG FASTCALL WU32GetClientRect(PVDMFRAME pFrame)
{
    RECT t2;
    register PGETCLIENTRECT16 parg16;

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

    /*
     * Home Design Gold 2.0
     *
     * If the call fails, don't overwrite the passed-in
     * rect.
     */
    if (GetClientRect(HWND32(parg16->hwnd), &t2)) {
        PUTRECT16(parg16->vpRect, &t2);
    }

    FREEARGPTR(parg16);
    RETURN(0);
}



//**************************************************************************
//  WU32GetCursorPos -
//
//**************************************************************************

ULONG FASTCALL WU32GetCursorPos(PVDMFRAME pFrame)
{
    POINT t1;
    register PGETCURSORPOS16 parg16;

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

    GetCursorPos( &t1 );

    PUTPOINT16(parg16->f1, &t1);
    FREEARGPTR(parg16);
    RETURN(0);
}


//**************************************************************************
//  WU32GetDesktopWindow -
//
//**************************************************************************

ULONG FASTCALL WU32GetDesktopWindow(PVDMFRAME pFrame)
{
    ULONG ul;

    UNREFERENCED_PARAMETER(pFrame);

    ul = GETHWND16(GetDesktopWindow());

    RETURN(ul);
}


//**************************************************************************
//  WU32GetDlgItem -
//
//**************************************************************************

ULONG FASTCALL WU32GetDlgItem(PVDMFRAME pFrame)
{
    ULONG ul;
    register PGETDLGITEM16 parg16;

    //
    // pass the child ID zero-extended.  this ID is the hMenu param to
    // CreateWindow, so USER gets this ID with hiword = 0.
    // Visual Basic relies on this.
    //


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

    ul = GETHWND16(GetDlgItem(HWND32(parg16->f1),WORD32(parg16->f2)));

    if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_DBASEHANDLEBUG) {
        ((PTDB)SEGPTR(pFrame->wTDB,0))->TDB_CompatHandle = (USHORT) ul;
    }


    FREEARGPTR(parg16);
    RETURN(ul);
}


//**************************************************************************
//  WU32GetMenu -
//
//**************************************************************************

ULONG FASTCALL WU32GetMenu(PVDMFRAME pFrame)
{
    ULONG ul;
    register PGETMENU16 parg16;

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

    ul = GETHMENU16(GetMenu(HWND32(parg16->f1)));

    FREEARGPTR(parg16);
    RETURN(ul);
}



//**************************************************************************
//  WU32GetMenuItemCount -
//
//**************************************************************************

ULONG FASTCALL WU32GetMenuItemCount(PVDMFRAME pFrame)
{
    ULONG ul;
    register PGETMENUITEMCOUNT16 parg16;

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

    ul = GETWORD16(GetMenuItemCount( HMENU32(parg16->f1) ));

    FREEARGPTR(parg16);
    RETURN(ul);
}


//**************************************************************************
//  WU32GetSysColor -
//
//**************************************************************************

ULONG FASTCALL WU32GetSysColor(PVDMFRAME pFrame)
{
    ULONG ul;
    register PGETSYSCOLOR16 parg16;

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

    ul = GETDWORD16(GetSysColor( INT32(parg16->f1) ));

    FREEARGPTR(parg16);
    RETURN(ul);
}



//**************************************************************************
//  WU32GetSystemMetrics -
//
//**************************************************************************

ULONG FASTCALL WU32GetSystemMetrics(PVDMFRAME pFrame)
{
    ULONG ul;
    register PGETSYSTEMMETRICS16 parg16;
    int     sm;

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

    sm = INT32(parg16->f1);

    ul = GETINT16(GetSystemMetrics(sm) );

    FREEARGPTR(parg16);
    RETURN(ul);
}


//**************************************************************************
//  WU32GetTopWindow -
//
//**************************************************************************

ULONG FASTCALL WU32GetTopWindow(PVDMFRAME pFrame)
{
    ULONG ul;
    register PGETTOPWINDOW16 parg16;

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

    ul = GETHWND16(GetTopWindow(HWND32(parg16->f1)));

    FREEARGPTR(parg16);
    RETURN(ul);
}


char szTrayWnd[] = "Shell_TrayWnd";

//**************************************************************************
//  WU32GetWindowRect -
//
//**************************************************************************

ULONG FASTCALL WU32GetWindowRect(PVDMFRAME pFrame)
{
    RECT t2;
    register PGETWINDOWRECT16 parg16;

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

    /*
     * Home Design Gold 2.0
     *
     * If the call fails, don't overwrite the passed-in
     * rect.
     */
    if (GetWindowRect(HWND32(parg16->f1), &t2)) {

        // Sierra on-line setup hack (expects tray rect to be Classic style)
        // See bug #425058
        // Unfortunately we can't cache the tray hwnd because if explorer dies
        // while the VDM is still running, explorer will get a new hwnd when it
        // is restarted that won't match our cached one.

        // IMHO this could be a general fix and not under an app compat flag
        // in BlackComb.
        if(CURRENTPTD()->dwWOWCompatFlags2 & WOWCF2_FIXLUNATRAYRECT) {

            char szClassName[20];

            if(GetClassName((HWND)parg16->f1,
                            szClassName,
                            sizeof(szClassName))) {

                if(!lstrcmp(szClassName, szTrayWnd)) {

                    // these will only be 0 for the Luna theme
                    if((t2.left == 0) || (t2.top == 0)) {

                        // Find tray position on desktop. Leave the border that
                        // is actually in the desktop alone so that the apps can
                        // calculate their windows accurately.

                        /*******************************************************
                        * Note: IMHO the code that is commented out below could
                        *       be uncommented for BlackComb as it more acurr-
                        *       ately resembles what would be returned in
                        *       Classic view.  Instead, since we are late in the
                        *       cycle for Whistler (RC2), we adjust the bare
                        *       minimum required to fix the known Sierra cases.
                        *
                        * // if tray is at the BOTTOM of the desktop window
                        * if(t2.top > 0) {
                        *     t2.left--;
                        *     t2.right++;
                        *     t2.bottom++;
                        *
                        * // else if the tray is at the RIGHT of desktop window
                        * } else if(t2.left > 0) {
                        *     t2.top--;
                        *     t2.right++;
                        *     t2.bottom++;
                        *
                        * // else if the tray is at the TOP of desktop window
                        * } else if(t2.right > t2.bottom) {
                        *     t2.top--;
                        *     t2.left--;
                        *     t2.right++;
                        *
                        * // else the tray must be at the LEFT of desktop window
                        * } else {
                        *     t2.top--;
                        *     t2.left--;
                        *     t2.bottom++;
                        * }
                        *******************************************************/

                       // if tray is at the BOTTOM of the desktop window
                       if(t2.top > 0)
                           t2.bottom++;

                       // else if the tray is at the TOP of the desktop window
                       else if(t2.right > t2.bottom)
                           t2.top--;
                    }
                }
            }
        }
        PUTRECT16(parg16->f2, &t2);
    }

    FREEARGPTR(parg16);
    RETURN(0);
}



//**************************************************************************
//  WU32IsWindow -
//
//**************************************************************************

ULONG FASTCALL WU32IsWindow(PVDMFRAME pFrame)
{
    ULONG  ul;
    HWND   hWnd;
    register PISWINDOW16 parg16;

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

    hWnd = HWND32(parg16->f1);

    ul = GETBOOL16(IsWindow(hWnd));

    // For apps that get burned by recycled handles -- ie. the old handle they
    // had has been destroyed & realloc'd to a different window -- not the one
    // they were expecting.  This needs to be handled on an app by app basis.
    if(ul && (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_FAKENOTAWINDOW)) {

        // NetScape 4.0x install (the bug is in InstallShield)
        // Test the offset portion of the 16:16 return address to this call.
        // Bug #132616 et al
        switch(pFrame->vpCSIP & 0x0000FFFF) {

            case 0x4880:  // (InstallShield 3.00.104.0)
            case 0x44E4:  // (InstallShield 3.00.091.0)

            {
                ULONG  result;
                LPVOID lp;

                // we only want this to fail for calls during Int.Shld cleanup
                // we probably shouldn't fail it if was created by a WOW process
                result = GetWindowLong(hWnd, GWL_WNDPROC);
                if(!IsWOWProc(result)) {
                    goto IW_HACK;
                }

                // extra sanity check: InstallSheild calls GetWindowLong & uses
                // the returned value as a 16:16 ptr
                result = GetWindowLong(hWnd, DWL_MSGRESULT);
                GETVDMPTR(result, sizeof(VPVOID), lp);
                if(!lp) {
                    goto IW_HACK;
                }
                break;
                    
            }
        }
    }

    FREEARGPTR(parg16);
    RETURN(ul);

IW_HACK:
    WOW32WARNMSG((0),"WOW32::IsWindow hack hit!\n");
    RETURN(0);
   
}



//**************************************************************************
//  WU32ScreenToClient -
//
//**************************************************************************

ULONG FASTCALL WU32ScreenToClient(PVDMFRAME pFrame)
{
    POINT t2;
    register PSCREENTOCLIENT16 parg16;

    GETARGPTR(pFrame, sizeof(SCREENTOCLIENT16), parg16);
    GETPOINT16(parg16->f2, &t2);

    ScreenToClient( HWND32(parg16->f1), &t2 );

    PUTPOINT16(parg16->f2, &t2);
    FREEARGPTR(parg16);
    RETURN(0);
}


//**************************************************************************
//  WU32IsChild -
//
//**************************************************************************

ULONG FASTCALL WU32IsChild(PVDMFRAME pFrame)
{
    ULONG ul;
    register PISCHILD16 parg16;

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

    ul = GETBOOL16(IsChild( HWND32(parg16->f1), HWND32(parg16->f2) ));

    FREEARGPTR(parg16);
    RETURN(ul);
}



//**************************************************************************
//  WU32IsIconic -
//
//**************************************************************************

ULONG FASTCALL WU32IsIconic(PVDMFRAME pFrame)
{
    ULONG ul;
    register PISICONIC16 parg16;

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

    ul = GETBOOL16(IsIconic( HWND32(parg16->f1) ));

    FREEARGPTR(parg16);
    RETURN(ul);
}



//**************************************************************************
//  WU32IsWindowEnabled -
//
//**************************************************************************

ULONG FASTCALL WU32IsWindowEnabled(PVDMFRAME pFrame)
{
    ULONG ul;
    register PISWINDOWENABLED16 parg16;

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

    ul = GETBOOL16(IsWindowEnabled( HWND32(parg16->f1) ));

    FREEARGPTR(parg16);
    RETURN(ul);
}



//**************************************************************************
//  WU32IsWindowVisible -
//
//**************************************************************************

ULONG FASTCALL WU32IsWindowVisible(PVDMFRAME pFrame)
{
    ULONG ul;
    register PISWINDOWVISIBLE16 parg16;

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

    ul = GETBOOL16(IsWindowVisible( HWND32(parg16->f1) ));

    FREEARGPTR(parg16);
    RETURN(ul);
}


//**************************************************************************
//  WU32IsZoomed -
//
//**************************************************************************

ULONG FASTCALL WU32IsZoomed(PVDMFRAME pFrame)
{
    ULONG ul;
    register PISZOOMED16 parg16;

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

    ul = GETBOOL16(IsZoomed( HWND32(parg16->f1) ));

    FREEARGPTR(parg16);
    RETURN(ul);
}



//**************************************************************************
//  WU32GetTickCount -
//
//**************************************************************************

ULONG FASTCALL WU32GetTickCount(PVDMFRAME pFrame)
{
    ULONG   ul;

    UNREFERENCED_PARAMETER(pFrame);

    ul = (ULONG)GetTickCount();

    if (CURRENTPTD()->dwWOWCompatFlags & WOWCF_GRAINYTICS) {

        //
        // round down to the nearest 55ms    this is for RelayGold, which
        // spins calling this API until consecutive calls return a delta
        // greater than 52.
        //

        ul = ul - (ul % 55);
    }

    RETURN(ul);
}



//**************************************************************************
//  On I386 all these functions her handled on clientside. But conditionally
//  they may endup doing the actual work via these thunks.
//
//  So any changes here like 'win31 compatiblity code' may have to be added
//  in mvdm\wow16\user\usercli.asm too.
//
//                                                               - nanduri
//**************************************************************************


//**************************************************************************
//  WU32DefHookProc -
//
//**************************************************************************

ULONG FASTCALL WU32DefHookProc(PVDMFRAME pFrame)
{
    ULONG ul = 0;
    register PDEFHOOKPROC16 parg16;
    HOOKSTATEDATA HkData;
    ULONG hHook16;
    INT iHookCode;
    INT nCode;
    LONG wParam;
    LONG lParam;
    LPINT lpiFunc;

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

    nCode = INT32(parg16->f1);
    wParam = WORD32(parg16->f2);
    lParam = DWORD32(parg16->f3);

    GETMISCPTR(parg16->f4, lpiFunc);
    hHook16 = FETCHDWORD(*lpiFunc);
    FREEVDMPTR(lpiFunc);

    if (ISVALIDHHOOK(hHook16)) {
        iHookCode = GETHHOOKINDEX(hHook16);
        HkData.iIndex = (BYTE)iHookCode;
        if ( W32GetHookStateData( &HkData ) ) {
            ul = (ULONG)WU32StdDefHookProc(nCode, wParam, lParam, iHookCode);
        }
    }

    FREEARGPTR(parg16);
    RETURN(ul);
}


//**************************************************************************
//  WU32GetKeyState -
//
//**************************************************************************

ULONG FASTCALL WU32GetKeyState(PVDMFRAME pFrame)
{
    ULONG ul;
    SHORT sTmp;
    register PGETKEYSTATE16 parg16;

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

    sTmp = GetKeyState(INT32(parg16->f1));

    // compatiblity:
    // MSTEST (testdrvr.exe) tests the bit 0x80 for checking the
    // shift key state. This works in win31 because the keystate in win31 is
    // one byte long and because of similar code below
    //
    // win31 code is similar to:
    //             mov al, byte ptr keystate
    //             cbw
    //             ret
    //
    // if 'al' is 0x80, cbw will make ax = 0xff80 and thus in win31
    // (state & 0x8000) and (state & 0x0080) will work and mean the same.
    //

    ul = (ULONG)((sTmp & 0x8000) ? (sTmp | 0x80) : sTmp);



    FREEARGPTR(parg16);
    RETURN(ul);
}



//**************************************************************************
//  WU32GetKeyboardState -
//
//**************************************************************************

ULONG FASTCALL WU32GetKeyboardState(PVDMFRAME pFrame)
{
    PBYTE pb1;
    register PGETKEYBOARDSTATE16 parg16;

    GETARGPTR(pFrame, sizeof(GETKEYBOARDSTATE16), parg16);
    ALLOCVDMPTR(parg16->f1, 256, pb1);

#ifdef HACK32   // bug 5704
    if (pb1) {
        GetKeyboardState( pb1 );
    }
#else
        GetKeyboardState( pb1 );
#endif

    FLUSHVDMPTR(parg16->f1, 256, pb1);
    FREEVDMPTR(pb1);
    FREEARGPTR(parg16);
    RETURN(0);
}
