/*++
 *
 *  WOW v1.0
 *
 *  Copyright (c) 1991, Microsoft Corporation
 *
 *  WMSGEM.C
 *  WOW32 16-bit message thunks
 *
 *  History:
 *  Created 11-Mar-1991 by Jeff Parsons (jeffpar)
--*/


#include "precomp.h"
#pragma hdrstop

MODNAME(wmsgem.c);

VPVOID  WordBreakProc16 = 0;

extern WBP W32WordBreakProc;

#ifdef DEBUG

MSGINFO amiEM[] = {
   {OLDEM_GETSEL,               "EM_GETSEL"},                       // 0x0400
   {OLDEM_SETSEL,               "EM_SETSEL"},                       // 0x0401
   {OLDEM_GETRECT,              "EM_GETRECT"},                      // 0x0402
   {OLDEM_SETRECT,              "EM_SETRECT"},                      // 0x0403
   {OLDEM_SETRECTNP,            "EM_SETRECTNP"},                    // 0x0404
   {OLDEM_SCROLL,               "EM_SCROLL"},                       // 0x0405
   {OLDEM_LINESCROLL,           "EM_LINESCROLL"},                   // 0x0406
   {OLDEM_GETMODIFY,            "EM_GETMODIFY"},                    // 0x0408
   {OLDEM_SETMODIFY,            "EM_SETMODIFY"},                    // 0x0409
   {OLDEM_GETLINECOUNT,         "EM_GETLINECOUNT"},                 // 0x040A
   {OLDEM_LINEINDEX,            "EM_LINEINDEX"},                    // 0x040B
   {OLDEM_SETHANDLE,            "EM_SETHANDLE"},                    // 0x040C
   {OLDEM_GETHANDLE,            "EM_GETHANDLE"},                    // 0x040D
   {OLDEM_GETTHUMB,             "EM_GETTHUMB"},                     // 0x040E
   {OLDEM_LINELENGTH,           "EM_LINELENGTH"},                   // 0x0411
   {OLDEM_REPLACESEL,           "EM_REPLACESEL"},                   // 0x0412
   {OLDEM_SETFONT,              "EM_SETFONT"},                      // 0x0413
   {OLDEM_GETLINE,              "EM_GETLINE"},                      // 0x0414
   {OLDEM_LIMITTEXT,            "EM_LIMITTEXT"},                    // 0x0415
   {OLDEM_CANUNDO,              "EM_CANUNDO"},                      // 0x0416
   {OLDEM_UNDO,                 "EM_UNDO"},                         // 0x0417
   {OLDEM_FMTLINES,             "EM_FMTLINES"},                     // 0x0418
   {OLDEM_LINEFROMCHAR,         "EM_LINEFROMCHAR"},                 // 0x0419
   {OLDEM_SETWORDBREAK,         "EM_SETWORDBREAK"},                 // 0x041A
   {OLDEM_SETTABSTOPS,          "EM_SETTABSTOPS"},                  // 0x041B
   {OLDEM_SETPASSWORDCHAR,      "EM_SETPASSWORDCHAR"},              // 0x041C
   {OLDEM_EMPTYUNDOBUFFER,      "EM_EMPTYUNDOBUFFER"},              // 0x041D
   {OLDEM_GETFIRSTVISIBLELINE,  "EM_GETFIRSTVISIBLELINE"},          // 0x041E
   {OLDEM_SETREADONLY,          "EM_SETREADONLY"},                  // 0x041F
   {OLDEM_SETWORDBREAKPROC,     "EM_SETWORDBREAKPROC"},             // 0x0420
   {OLDEM_GETWORDBREAKPROC,     "EM_GETWORDBREAKPROC"},             // 0x0421
   {OLDEM_GETPASSWORDCHAR,      "EM_GETPASSWORDCHAR"}               // 0x0422
};

PSZ GetEMMsgName(WORD wMsg)
{
    INT i;
    register PMSGINFO pmi;

    for (pmi=amiEM,i=NUMEL(amiEM); i>0; i--,pmi++) {
        if ((WORD)pmi->uMsg == wMsg)
            return pmi->pszMsgName;
    }
    return GetWMMsgName(wMsg);
}

#endif


BOOL FASTCALL ThunkEMMsg16(LPMSGPARAMEX lpmpex)
{
    WORD wMsg = lpmpex->Parm16.WndProc.wMsg;

    LOGDEBUG(7,("    Thunking 16-bit edit control message %s(%04x)\n", (LPSZ)GetEMMsgName(wMsg), wMsg));

    wMsg -= WM_USER;

    //
    // For app defined (control) messages that are out of range
    // return TRUE.
    //
    // ChandanC Sept-15-1992
    //

    if (wMsg < (EM_GETPASSWORDCHAR - EM_GETSEL + 1)) {
        switch(lpmpex->uMsg = wMsg + EM_GETSEL) {
    
        case EM_GETSEL:
            // 16 bit apps cannot pass non-zero values in wParam or lParam for this
            // message to NT since they will be considered long pointers.
            // This is a hack for ReportWin - MarkRi
    
            // NOTE: There is a case possible where the app is trying to pass
            // thru a GETSEL msg that NT has sent it in which case things get more
            // complicated but we haven't found an app YET that has this problem.
            lpmpex->uParam = 0 ;
            lpmpex->lParam = 0 ;
            break ;
    
    
        case EM_SETSEL:
            lpmpex->uParam = LOWORD(lpmpex->Parm16.WndProc.lParam);
            lpmpex->lParam = HIWORD(lpmpex->Parm16.WndProc.lParam);
            break;
    
        case EM_GETLINE:
            GETMISCPTR(lpmpex->Parm16.WndProc.lParam, (LPSZ)lpmpex->lParam);
            break;
    
        case EM_GETRECT:
            lpmpex->lParam = (LONG)lpmpex->MsgBuffer;
            break;
    
        case EM_LINESCROLL:
            lpmpex->uParam = INT32(HIWORD(lpmpex->Parm16.WndProc.lParam));
            lpmpex->lParam = INT32(LOWORD(lpmpex->Parm16.WndProc.lParam));
            break;
    
        case EM_SETHANDLE:
            lpmpex->uParam = (UINT)MAKELONG(lpmpex->Parm16.WndProc.wParam,
                                  LOWORD((DWORD)lpmpex->pww->hInstance) | 1);
             break;
    
        case EM_REPLACESEL:
            {   PSZ psz;
                int i;
                GETPSZPTR(lpmpex->Parm16.WndProc.lParam, psz);
        
                if (psz) {
                    i = strlen(psz)+1;
                    lpmpex->lParam = (LONG) LocalAlloc (LMEM_FIXED, i);
                    RtlCopyMemory ((PSZ)lpmpex->lParam, psz, i);
                }
                FREEPSZPTR(psz);
            }
            break;
    
        case EM_SETRECT:
        case EM_SETRECTNP:
            if (lpmpex->Parm16.WndProc.lParam) {
                lpmpex->lParam = (LONG)lpmpex->MsgBuffer;
                getrect16((VPRECT16)lpmpex->Parm16.WndProc.lParam, (LPRECT)lpmpex->lParam);
            }
            break;
    
        case EM_SETTABSTOPS:
            {
                INT cItems = INT32(lpmpex->Parm16.WndProc.wParam);
                if (cItems > 0) {
                    (PVOID)lpmpex->lParam = STACKORHEAPALLOC(cItems * sizeof(INT), 
                                   sizeof(lpmpex->MsgBuffer), lpmpex->MsgBuffer);
                    getintarray16((VPINT16)lpmpex->Parm16.WndProc.lParam, cItems, (LPINT)lpmpex->lParam);
                }
            }
            break;
    
        case EM_SETWORDBREAKPROC:
            if (lpmpex->Parm16.WndProc.lParam) {
    
                LONG l;
    
                l = lpmpex->Parm16.WndProc.lParam;
    
                //
                // FEATURE-O-RAMA
                //
                // if the selector already has the high bit on then turn off bit 2
                // of the selector (the LDT bit, which should always be on).  we
                // need a way to not blindly strip off the high bit in our wndproc.
                //
    
                if (l & WNDPROC_WOW) {
                    WOW32ASSERT(l & WOWCLASS_VIRTUAL_NOT_BIT31);
                    l &= ~WOWCLASS_VIRTUAL_NOT_BIT31;
                }
    
                lpmpex->lParam = l | WNDPROC_WOW;
                LOGDEBUG (0, ("WOW::WMSGEM.C: EM_SETWORDBREAKPROC: lpmpex->Parm16.WndProc.lParam = %08lx, new lpmpex->Parm16.WndProc.lParam = %08lx\n", lpmpex->Parm16.WndProc.lParam, lpmpex->lParam));
    
            }
            break;
    
        case EM_GETSEL + 0x07:
        case EM_GETSEL + 0x0F:
        case EM_GETSEL + 0x10:
            lpmpex->uMsg = 0;
            break;
        } // switch
    }
    return TRUE;
}


VOID FASTCALL UnThunkEMMsg16(LPMSGPARAMEX lpmpex)
{

    LPARAM lParam = lpmpex->Parm16.WndProc.lParam;
    LPARAM lParamNew = lpmpex->lParam;

    switch(lpmpex->uMsg) {

    case EM_GETHANDLE:
        lpmpex->lReturn = GETHMEM16(lpmpex->lReturn);
        break;

    case EM_GETRECT:
        if (lParamNew) {
            putrect16((VPRECT16)lParam, (LPRECT)lParamNew);
        }
        break;

    case EM_REPLACESEL:
        if (lParamNew) {
            LocalFree ((HLOCAL)lParamNew);
        }
        break;

    case EM_SETTABSTOPS:
        if (lpmpex->Parm16.WndProc.wParam > 0) {
            STACKORHEAPFREE((LPINT)lParamNew, lpmpex->MsgBuffer);
        }

    case EM_GETWORDBREAKPROC:
        if (lpmpex->lReturn) {
            if (lpmpex->lReturn & WNDPROC_WOW) {

                LOGDEBUG (0, ("WOW::WMSGEM.C: EM_GETWORDBREAKPROC: lReturn = %08lx ", lpmpex->lReturn));
                lpmpex->lReturn = lpmpex->lReturn & (~WNDPROC_WOW);

                //
                // if the actual selector had the high bit on then we turned off
                // bit 2 of the selector (the LDT bit, which will always be on)
                //

                if (!(lpmpex->lReturn & WOWCLASS_VIRTUAL_NOT_BIT31)) {
                    lpmpex->lReturn |= (WNDPROC_WOW | WOWCLASS_VIRTUAL_NOT_BIT31);
                }

                LOGDEBUG (0, (" and new lReturn = %08lx\n", lpmpex->lReturn));
            }
            else {
                PARM16 Parm16;
                LONG   lReturn;

                if (!WordBreakProc16) {

                    W32WordBreakProc = (WBP)(lpmpex->lReturn);

                    Parm16.SubClassProc.iOrdinal = FUN_WOWWORDBREAKPROC;

                    if (!CallBack16(RET_SUBCLASSPROC, &Parm16, (VPPROC)NULL,
                                   (PVPVOID)&lReturn)) {
                                    WOW32ASSERT(FALSE);
                        WordBreakProc16 = lpmpex->lReturn;
                    }
                }
                else {
                    lpmpex->lReturn = WordBreakProc16;
                }
            }
        }
        break;
    }
}
