/****************************** Module Header ******************************\
* Module Name: LEDDE.C
*
* Purpose: ?????
*              
* Created: 1990
*
* Copyright (c) 1990, 1991  Microsoft Corporation
*
* History:
*   Raor, Srinik   (../../1990,91)  Designed and coded
*
\***************************************************************************/

#include <windows.h>
#include "dde.h"
#include "dll.h"

#define LN_FUDGE        16      // [],(), 3 * 3 (2 double quotes and comma)
#define RUNITEM

#define OLEVERB_CONNECT     0xFFFF

// Definitions for sending the server sys command.
char *srvrSysCmd[] = {"StdNewFromTemplate",
                      "StdNewDocument",
                      "StdEditDocument",
                      "StdOpenDocument"
                      };

#define EMB_ID_INDEX    11          // index of ones digit in #00
extern  char    embStr[];
extern  BOOL    gbCreateInvisible;
extern  BOOL    gbLaunchServer;

extern  ATOM    aMSDraw;

extern  BOOL (FAR PASCAL *lpfnIsTask) (HANDLE);

// !!! set error hints

OLESTATUS FARINTERNAL LeDoVerb (lpobj, verb, fShow, fActivate)
LPOBJECT_LE lpobj;
WORD        verb;
BOOL        fShow;
BOOL        fActivate;
{

    PROBE_ASYNC (lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    if (!QueryOpen(lpobj))
        return OLE_OK;

    lpobj->verb = verb;
    lpobj->fCmd = ACT_DOVERB;

    if (fActivate)
        lpobj->fCmd |= ACT_ACTIVATE;

    if (fShow)
        lpobj->fCmd |= ACT_SHOW;

    InitAsyncCmd (lpobj, OLE_RUN, DOCSHOW);
    return DocShow (lpobj);
}



OLESTATUS FARINTERNAL LeShow (lpobj, fActivate)
LPOBJECT_LE lpobj;
BOOL        fActivate;
{

    PROBE_ASYNC (lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    if (!QueryOpen(lpobj))
        return OLE_OK;

    lpobj->fCmd = ACT_SHOW;
    InitAsyncCmd (lpobj, OLE_SHOW, DOCSHOW);
    return DocShow (lpobj);
}


// DocShow : If the server is connected, show the item
// for editing. For embedded objects us NULL Item.
OLESTATUS DocShow (lpobj)
LPOBJECT_LE lpobj;
{
    switch (lpobj->subRtn) {

        case 0:
            SendStdShow (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 1:
            ProcessErr (lpobj);
            return EndAsyncCmd (lpobj);

        default:
            DEBUG_OUT ("Unexpected subroutine", 0);
            return OLE_ERROR_GENERIC;
    }
}


void SendStdShow (lpobj)
LPOBJECT_LE lpobj;
{

    WORD    len;
    WORD    size;
    LPSTR   lpdata = NULL;
    HANDLE  hdata = NULL;
    BOOL    bShow;

    lpobj->subErr = OLE_OK;
    
    if (lpobj->verb == OLEVERB_CONNECT) {
        lpobj->verb = NULL;
        return;
    }
    
    if (!(lpobj->fCmd & (ACT_SHOW | ACT_DOVERB)))
        return;

    if (bShow = (!lpobj->bOleServer || !(lpobj->fCmd & ACT_DOVERB))) {

        // show is off, do not show the server.
        if (!(lpobj->fCmd & ACT_SHOW))
            return;

        SETERRHINT(lpobj, OLE_ERROR_SHOW);
        //  and 18 "[StdShowItem(\"")for 5 extra for ",FALSE
        len = 18 + 7;
    } else {
        // 19 for the string [StdDoVerbItem(\"") and
        // 18 extra is for ",000,FALSE,FALSE
        SETERRHINT(lpobj, OLE_ERROR_DOVERB);
        len = 19 + 18;
    }

    len += GlobalGetAtomLen (lpobj->item);

    len +=  4;                 // ")]" + NULL

    hdata = GlobalAlloc (GMEM_DDESHARE, size = len);
    if (hdata == NULL || (lpdata = (LPSTR)GlobalLock (hdata)) == NULL)
        goto errRtn;

    if (bShow)
        lstrcpy (lpdata, "[StdShowItem(\"");
    else
        lstrcpy (lpdata, "[StdDoVerbItem(\"");

    len = lstrlen (lpdata);

    if (lpobj->item)
        GlobalGetAtomName (lpobj->item , lpdata + len, size - len);

    if (!bShow) {

        lstrcat (lpdata, (LPSTR)"\",");
        // assume that the number of verbs are < 10

        len = lstrlen (lpdata);
#ifdef  FIREWALLS
        ASSERT ( (lpobj->verb & 0x000f) < 9 , "Verb value more than 9");
#endif
        lpdata += len;
        *lpdata++ = (char)((lpobj->verb & 0x000f) + '0');
        *lpdata = 0;

        if (lpobj->fCmd & ACT_SHOW)
            lstrcat (lpdata, (LPSTR) ",TRUE");
        else
            lstrcat (lpdata, (LPSTR) ",FALSE");
                // StdVerbItem (item, verb, TRUE
        // add TRUE/FALSE constant for the activate
        if (!(lpobj->fCmd & ACT_ACTIVATE))
            lstrcat (lpdata, (LPSTR) ",TRUE)]");
        else
            lstrcat (lpdata, (LPSTR) ",FALSE)]");
            // [StdDoVerb ("item", verb, FALSE, FALSE)]
    } else
        lstrcat (lpdata, (LPSTR)"\")]");
        // apps like excel and wingraph do not suuport activate at
        // item level.


    GlobalUnlock (hdata);
    DocExecute (lpobj, hdata);
    return;

errRtn:
    if (lpdata)
        GlobalUnlock (hdata);

    if (hdata)
        GlobalFree (hdata);

    lpobj->subErr = OLE_ERROR_MEMORY;
    return;
}



OLESTATUS FARINTERNAL  LeQueryOpen (LPOBJECT_LE lpobj)
{

    if (QueryOpen(lpobj))
       return OLE_OK;
    else
       return OLE_ERROR_NOT_OPEN;

}


BOOL    INTERNAL  QueryOpen (LPOBJECT_LE lpobj)
{

    if (lpobj->pDocEdit &&  lpobj->pDocEdit->hClient) {
        if (IsServerValid (lpobj))
            return TRUE;
        // destroy the windows and pretend as if the server was never
        // connected.

        DestroyWindow (lpobj->pDocEdit->hClient);
        if (lpobj->pSysEdit && lpobj->pSysEdit->hClient)
            DestroyWindow (lpobj->pSysEdit->hClient);

    }
    return FALSE;
}



OLESTATUS FARINTERNAL  LeActivate (lpobj, verb, fShow, fActivate, hWnd, lprc)
LPOBJECT_LE lpobj;
WORD        verb;
BOOL        fShow;
BOOL        fActivate;
HWND        hWnd;
LPRECT      lprc;
{

    lpobj->verb = verb;
    if (lpobj->head.ctype == CT_EMBEDDED)
        return EmbOpen (lpobj, fShow, fActivate, hWnd, lprc);
    
#ifdef  FIREWALLS
    ASSERT (lpobj->head.ctype == CT_LINK, "unknown object");
#endif
    return LnkOpen (lpobj, fShow, fActivate, hWnd, lprc);
    
}


OLESTATUS FARINTERNAL  LeUpdate (lpobj)
LPOBJECT_LE lpobj;
{
    if (lpobj->head.ctype == CT_EMBEDDED)
        return EmbUpdate (lpobj);
    
#ifdef  FIREWALLS
    ASSERT (lpobj->head.ctype == CT_LINK, "unknown object");
#endif
    return LnkUpdate (lpobj);
}



OLESTATUS FARINTERNAL  EmbOpen (lpobj, fShow, fActivate, hWnd, lprc)
LPOBJECT_LE lpobj;
BOOL        fShow;
BOOL        fActivate;
HWND        hWnd;
LPRECT      lprc;
{

    PROBE_ASYNC (lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    if(QueryOpen (lpobj))
        return LeDoVerb (lpobj, lpobj->verb, fShow, fActivate);

    // show the window
    // advise for data only on close
    // and shut down the conv  after the advises.

    lpobj->fCmd = LN_EMBACT | ACT_DOVERB | ACT_ADVISE | ACT_CLOSE;
    if (fActivate)
        lpobj->fCmd |= ACT_ACTIVATE;

    if (fShow)
        lpobj->fCmd |= ACT_SHOW;

    InitAsyncCmd (lpobj, OLE_ACTIVATE, EMBOPENUPDATE);
    return EmbOpenUpdate (lpobj);

}



/***************************** Public  Function ****************************\
* OLESTATUS FARINTERNAL  EmbUpdate (lpobj)
*
* This function updates an EMB object. If the server is connected
* simply send a request for the native as well as the display formats.
* If the server is connected, then tries to start the conversationa and
* get the data. If the conversation fails, then load the server and
* start the conversation. The embeded objects may have links in it.
*
* Effects:
*
* History:
* Wrote it.
\***************************************************************************/


OLESTATUS FARINTERNAL  EmbUpdate (lpobj)
LPOBJECT_LE lpobj;
{

    // if we are loading the server, then definitly unload.
    // if the connection is established, then unload if it is
    // to be unloaded, when  all the previous requests are satisfied.


    PROBE_ASYNC (lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    lpobj->fCmd = LN_EMBACT | ACT_REQUEST | (QueryOpen(lpobj) ? 0 : ACT_UNLAUNCH);
    InitAsyncCmd (lpobj, OLE_UPDATE, EMBOPENUPDATE);
    return EmbOpenUpdate (lpobj);

}



OLESTATUS FARINTERNAL  EmbOpenUpdate (lpobj)
LPOBJECT_LE lpobj;
{

    switch (lpobj->subRtn) {

        case 0:

            SKIP_TO (QueryOpen(lpobj), step6);
            SendSrvrMainCmd  (lpobj, lpobj->lptemplate);
            lpobj->lptemplate = NULL;
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 1:

            if (ProcessErr (lpobj))
                 goto errRtn;

            // Init doc conversation should set the failure error
            if (!InitDocConv (lpobj, !POPUP_NETDLG))
                 goto errRtn;

            // If there is no native data, do not do any poke.
            // creates will not have any poke data to start with

            SKIP_TO (!(lpobj->hnative), step6);
            PokeNativeData (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 2:
            if (ProcessErr (lpobj))
                 goto errRtn;
            // Now poke the hostnames etc stuff.
            PokeHostNames (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 3:

            // do not worry about the poke hostname errors
            PokeTargetDeviceInfo (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 4:

            PokeDocDimensions (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 5:

            PokeColorScheme (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);


        case 6:

            step6:

            // wingraph does not accept the  doc dimensions
            // after sttedit.
            CLEAR_STEP_ERROR (lpobj);
            SETSTEP (lpobj, 6);
            STEP_NOP (lpobj);
            // step_nop simply increments the step numebr
            // merge the steps later on



        case 7:

            if (ProcessErr (lpobj))
                goto errRtn;

            SKIP_TO (!(lpobj->fCmd & ACT_ADVISE), step11);
            lpobj->optUpdate = oleupdate_onsave;
            lpobj->pDocEdit->nAdviseSave = 0;
            AdviseOn (lpobj, cfNative, aSave);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 8:

            // do not go for errors on /save. Some servers may not support
            // this.

            CLEAR_STEP_ERROR (lpobj);
            AdvisePict (lpobj, aSave);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 9:

            // do not worry about the error case for save. Ignore them

            CLEAR_STEP_ERROR (lpobj);
            lpobj->optUpdate = oleupdate_onclose;
            lpobj->pDocEdit->nAdviseClose = 0;
            AdviseOn (lpobj, cfNative, aClose);
            WAIT_FOR_ASYNC_MSG (lpobj);


        case 10:
            if (ProcessErr(lpobj))
                goto errRtn;

            AdvisePict (lpobj, aClose);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 11:

            step11:
            SETSTEP (lpobj, 11);
            if (ProcessErr(lpobj))
                goto errRtn;

            SKIP_TO (!(lpobj->fCmd & ACT_REQUEST), step13);
            
            // we don't want to send OLE_CHANGED when we get this data, if we
            // are going to request for picture data also.
            lpobj->pDocEdit->bCallLater = ((lpobj->lpobjPict) ? TRUE: FALSE);
            RequestOn (lpobj, cfNative);
            WAIT_FOR_ASYNC_MSG (lpobj);

            // If request pict fails, then native and pict are
            // not in sync.

        case 12:
            if (ProcessErr(lpobj))
                goto errRtn;

            lpobj->pDocEdit->bCallLater = FALSE;
            RequestPict (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);


        case 13:

            step13:
            SETSTEP(lpobj, 13);

            if (ProcessErr(lpobj))
                goto errRtn;

            SendStdShow (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 14:


            if (ProcessErr(lpobj))
                goto errRtn;

            SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step15);
            return EndAsyncCmd (lpobj);


        case 15:

errRtn:
            step15:
            ProcessErr (lpobj);

            if ((lpobj->asyncCmd == OLE_UPDATE) 
                    && (!(lpobj->fCmd & ACT_UNLAUNCH)))
                return EndAsyncCmd (lpobj);
                
            // if we launched and error, unlaunch (send stdexit)
            NextAsyncCmd (lpobj, EMBLNKDELETE);
            lpobj->fCmd |= ACT_UNLAUNCH;
            EmbLnkDelete (lpobj);
            return lpobj->mainErr;


      default:
            DEBUG_OUT ("Unexpected subroutine", 0);
            return OLE_ERROR_GENERIC;
    }
}




OLESTATUS FARINTERNAL  LnkOpen (lpobj, fShow, fActivate, hWnd, lprc)
LPOBJECT_LE    lpobj;
BOOL        fShow;
BOOL        fActivate;
HWND        hWnd;
LPRECT      lprc;
{

    PROBE_ASYNC (lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    if(QueryOpen (lpobj))
        return LeDoVerb (lpobj, lpobj->verb, fShow, fActivate);

    // Just end the system conversation. we are not unloading
    // this instance at all.

    lpobj->fCmd = LN_LNKACT |  ACT_DOVERB;

    if (lpobj->optUpdate == oleupdate_always)
        lpobj->fCmd |= ACT_ADVISE | ACT_REQUEST;
    else if (lpobj->optUpdate == oleupdate_onsave)
        lpobj->fCmd |= ACT_ADVISE;
    
    if (fActivate)
        lpobj->fCmd |= ACT_ACTIVATE;

    if (fShow)
        lpobj->fCmd |= ACT_SHOW;

    InitAsyncCmd (lpobj, OLE_ACTIVATE, LNKOPENUPDATE);
    return LnkOpenUpdate (lpobj);

}


OLESTATUS FARINTERNAL  LnkUpdate (lpobj)
LPOBJECT_LE lpobj;
{
    // if we are loading the server, then definitly unload.
    // if the connection is established, then unload if it is
    // to be unloaded, when  all the previous requests are satisfied.


    PROBE_ASYNC (lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    lpobj->fCmd = LN_LNKACT | ACT_REQUEST | (QueryOpen (lpobj) ? 0 : ACT_UNLAUNCH);
    InitAsyncCmd (lpobj, OLE_UPDATE, LNKOPENUPDATE);
    return LnkOpenUpdate (lpobj);
}



OLESTATUS FARINTERNAL  LnkOpenUpdate (lpobj)
LPOBJECT_LE lpobj;
{
    switch (lpobj->subRtn) {

        case 0:

            SKIP_TO (QueryOpen(lpobj), step2);
            InitDocConv (lpobj, !POPUP_NETDLG);
            if (QueryOpen(lpobj)) {
                if (lpobj->app == aPackage)
                    RemoveLinkStringFromTopic (lpobj);
                goto step2;
            }
            
            SendSrvrMainCmd (lpobj, NULL);
            WAIT_FOR_ASYNC_MSG (lpobj);


        case 1:

            if (ProcessErr (lpobj))
                 goto errRtn;

            if (lpobj->app == aPackage)
                RemoveLinkStringFromTopic (lpobj);
            
            if (!InitDocConv (lpobj, POPUP_NETDLG)) {
                lpobj->subErr = OLE_ERROR_OPEN;
                goto errRtn;
            }

        case 2:

            step2:

            SETSTEP (lpobj, 2);
            PokeTargetDeviceInfo (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);
  
       case 3:

            if (ProcessErr (lpobj))
                goto errRtn;

            SKIP_TO (!(lpobj->fCmd & ACT_ADVISE), step6);
            SKIP_TO (!(lpobj->fCmd & ACT_NATIVE), step4);
            AdviseOn (lpobj, cfNative, NULL);
            WAIT_FOR_ASYNC_MSG (lpobj);

       case 4:
            step4:
            SETSTEP  (lpobj, 4);
            if (ProcessErr (lpobj))
                goto errRtn;

            AdvisePict (lpobj, NULL);
            WAIT_FOR_ASYNC_MSG (lpobj);

       case 5:

            if (ProcessErr (lpobj))
                goto errRtn;

            // Now send advise for renaming the documnet.
            AdviseOn (lpobj, cfBinary, aStdDocName);
            WAIT_FOR_ASYNC_MSG (lpobj);

       case 6:

            step6:
            // if name advise fails ignore it
            SETSTEP (lpobj, 6);

            CLEAR_STEP_ERROR (lpobj);
            SKIP_TO (!(lpobj->fCmd & ACT_REQUEST), step8);
            SKIP_TO (!(lpobj->fCmd & ACT_NATIVE), step7);
            
            // we don't want to send OLE_CHANGED when we get this data, if we
            // are going to request for picture data also.
            lpobj->pDocEdit->bCallLater = ((lpobj->lpobjPict) ? TRUE: FALSE);
            RequestOn (lpobj, cfNative);
            WAIT_FOR_ASYNC_MSG (lpobj);

       case 7:
            step7:

            SETSTEP (lpobj, 7);
            if (ProcessErr (lpobj))
                goto errRtn;

            lpobj->pDocEdit->bCallLater = FALSE;
            RequestPict (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

      case 8:

            step8:

            SETSTEP     (lpobj, 8);
            if (ProcessErr (lpobj))
                goto errRtn;

            SKIP_TO (!(lpobj->fCmd & ACT_TERMDOC), step10);
            // terminate the document conversataion.
            TermDocConv (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);
    
      case 9:

            if (ProcessErr (lpobj))
                goto errRtn;

            // delete the server edit block
            DeleteDocEdit (lpobj);

            SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step14);
            return EndAsyncCmd (lpobj);

      case 10:

            step10:
            SETSTEP     (lpobj, 10);

            if (ProcessErr (lpobj))
                goto errRtn;

            SKIP_TO (!(lpobj->fCmd & ACT_TERMSRVR), step12);

            // terminate the server conversataion.
            TermSrvrConv (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

      case 11:

            if (ProcessErr (lpobj))
                goto errRtn;

            // delete the server edit block
            DeleteSrvrEdit (lpobj);
            return EndAsyncCmd (lpobj);


      case 12:

            step12:
            SETSTEP     (lpobj, 12);
            if (ProcessErr (lpobj))
                goto errRtn;

            SendStdShow (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

      case 13:

            if (ProcessErr (lpobj))
                goto errRtn;
            SKIP_TO ((lpobj->fCmd & ACT_UNLAUNCH), step14);
            return EndAsyncCmd (lpobj);


      case 14:

            errRtn:
            step14:
            ProcessErr (lpobj);

            if ((lpobj->asyncCmd == OLE_UPDATE) 
                    && (!(lpobj->fCmd & ACT_UNLAUNCH)))
                return EndAsyncCmd (lpobj);
                
            // if we launched and error, unlaunch (send stdexit)
            NextAsyncCmd (lpobj, EMBLNKDELETE);
            lpobj->fCmd |= ACT_UNLAUNCH;
            EmbLnkDelete (lpobj);
            return lpobj->mainErr;

       default:
            DEBUG_OUT ("Unexpected subroutine", 0);
            return OLE_ERROR_GENERIC;
    }
}



OLESTATUS EmbLnkClose (lpobj)
LPOBJECT_LE lpobj;
{
    switch (lpobj->subRtn) {

        case    0:
            TermDocConv (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case    1:

            // delete the edit block
            DeleteDocEdit (lpobj);
            TermSrvrConv (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case    2:

            // Do not set any errors, just delete the object.
            // delete the server edit block
            DeleteSrvrEdit (lpobj);
            return EndAsyncCmd (lpobj);


        default:
            DEBUG_OUT ("Unexpected subroutine", 0);
            return OLE_ERROR_GENERIC;
    }
}


OLESTATUS FARINTERNAL  LeClose (lpobj)
LPOBJECT_LE lpobj;
{
    PROBE_ASYNC (lpobj);
    if (IS_SVRCLOSING(lpobj))
        return OLE_OK;
    
    
    lpobj->fCmd = 0;
    
    if (lpobj->head.ctype == CT_EMBEDDED) {
        InitAsyncCmd (lpobj, OLE_CLOSE, EMBLNKDELETE);
        return EmbLnkDelete (lpobj);    
    }
    else {
        InitAsyncCmd (lpobj, OLE_CLOSE, EMBLNKCLOSE);
        return EmbLnkClose (lpobj);
    }
}



OLESTATUS FARINTERNAL  LeReconnect (lpobj)
LPOBJECT_LE    lpobj;
{
    // check for the existing conversation.
    // if the client window is non-null, then
    // connection exits.

    if (lpobj->head.ctype != CT_LINK)
        return OLE_ERROR_NOT_LINK;     // allow only for linked

    PROBE_ASYNC (lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    if (QueryOpen (lpobj))
        return OLE_OK;

    // start just the conversation. Do not load
    // the app.

    if (!InitDocConv (lpobj, !POPUP_NETDLG))
         return OLE_OK;             // document is not loaded , it is OK.

    lpobj->fCmd = LN_LNKACT;
    if (lpobj->optUpdate == oleupdate_always)
        lpobj->fCmd |= ACT_ADVISE | ACT_REQUEST;
    
    InitAsyncCmd (lpobj, OLE_RECONNECT, LNKOPENUPDATE);
    return LnkOpenUpdate (lpobj);
}




OLESTATUS INTERNAL PokeNativeData (lpobj)
LPOBJECT_LE lpobj;
{
   SETERRHINT(lpobj, OLE_ERROR_POKE_NATIVE);
   return SendPokeData (lpobj,
                    lpobj->item,
                    lpobj->hnative,
                    cfNative);
}




BOOL INTERNAL PostMessageToServer (pedit, msg, lparam)
PEDIT_DDE   pedit;
WORD        msg;
LONG        lparam;
{

#ifdef  FIREWALLS
    ASSERT (pedit, "Dde edit block is NULL");
#endif
    // save the lparam and msg fpr possible reposting incase of error.

    // we are in abort state.  no messages except for terminate.

    if (pedit->bAbort && msg != WM_DDE_TERMINATE)
        return FALSE;

    pedit->lParam = lparam;
    pedit->msg    = msg;

    if (pedit->hClient && pedit->hServer) {
        while (TRUE){
            if (!IsWindowValid (pedit->hServer))
                return FALSE;
            if (PostMessage (pedit->hServer, msg, pedit->hClient, lparam) == FALSE)
                Yield ();
            else
                return TRUE;
        }
    }
    return FALSE;
}


OLESTATUS FARINTERNAL LeCreateFromTemplate (lpclient, lptemplate, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
LPOLECLIENT         lpclient;
LPSTR               lptemplate;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpoleobject;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
{
    char            buf[MAX_STR];

    if (!MapExtToClass (lptemplate, (LPSTR)buf, MAX_STR))
        return OLE_ERROR_CLASS;

    return CreateFromClassOrTemplate (lpclient, (LPSTR) buf, lplpoleobject, 
                        optRender, cfFormat, LN_TEMPLATE, lptemplate, 
                        lhclientdoc, lpobjname);
}


OLESTATUS FARINTERNAL LeCreate (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat)
LPSTR               lpclass;
LPOLECLIENT         lpclient;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpoleobject;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
{
    if (gbCreateInvisible) {
        // this is in fact a call for invisible create
        return LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname, 
                        lplpoleobject, optRender, cfFormat, gbLaunchServer);
    }
    
    return CreateFromClassOrTemplate (lpclient, lpclass, lplpoleobject, 
                        optRender, cfFormat, LN_NEW, NULL, 
                        lhclientdoc, lpobjname);
}



OLESTATUS FARINTERNAL CreateFromClassOrTemplate (lpclient, lpclass, lplpoleobject, optRender, cfFormat, lnType, lptemplate, lhclientdoc, lpobjname)
LPOLECLIENT         lpclient;
LPSTR               lpclass;
LPOLEOBJECT FAR *   lplpoleobject;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
WORD                lnType;
LPSTR               lptemplate;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
{
    OLESTATUS       retval = OLE_ERROR_MEMORY;
    LPOBJECT_LE     lpobj = NULL;
    ATOM            aServer;
    char            chVerb [2];
    
    if (!(aServer = GetAppAtom (lpclass)))
        return OLE_ERROR_CLASS;
    
    if(!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED))) {
        GlobalDeleteAtom (aServer);
        goto errRtn;
    }
    
    // Now set the server.

    lpobj->head.lpclient = lpclient;
    lpobj->app           = GlobalAddAtom (lpclass);
    SetEmbeddedTopic (lpobj);
    lpobj->item          = NULL;
    lpobj->bOleServer    = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
    lpobj->aServer       = aServer;

    // launch the app and start the system conversation.
        
    if (!CreatePictObject (lhclientdoc, lpobjname, lpobj, 
                optRender, cfFormat, lpclass))
        goto errRtn;

        
    // show the window. Advise for data and close on receiving data
    lpobj->fCmd = lnType | ACT_SHOW | ACT_ADVISE | ACT_CLOSE;
    InitAsyncCmd (lpobj, lptemplate? OLE_CREATEFROMTEMPLATE : OLE_CREATE, EMBOPENUPDATE);
    *lplpoleobject = (LPOLEOBJECT)lpobj;

    lpobj->lptemplate = lptemplate;
    
    if ((retval = EmbOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
        return retval;

    // If there is error afterwards, then the client app should call
    // to delete the object.

errRtn:

    // for error termination OleDelete will terminate any conversation
    // in action.

    if (lpobj) {
        // This oledelete will not result in asynchronous command.
        OleDelete ((LPOLEOBJECT)lpobj); 
        *lplpoleobject = NULL;
    }
    
    return retval;
}



OLESTATUS FARINTERNAL CreateEmbLnkFromFile (lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, objType)
LPOLECLIENT         lpclient;
LPSTR               lpclass;
LPSTR               lpfile;
LPSTR               lpitem;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpoleobject;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
LONG                objType;
{
    OLESTATUS           retval = OLE_ERROR_MEMORY;
    LPOBJECT_LE         lpobj = NULL;
    ATOM                aServer;
    char                buf[MAX_STR];
    OLE_RELEASE_METHOD  releaseMethod;
    WORD                wFlags = NULL;
    char                chVerb[2];

    if (!lpclass && (lpclass = (LPSTR) buf) 
            && !MapExtToClass (lpfile, (LPSTR)buf, MAX_STR))
        return OLE_ERROR_CLASS;
    
    if (!(aServer = GetAppAtom (lpclass)))
        return OLE_ERROR_CLASS;
    
    if (!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_LINK))) {
        GlobalDeleteAtom (aServer);
        goto errFileCreate;
    }
    
    lpobj->head.lpclient = lpclient;
    lpobj->app           = GlobalAddAtom (lpclass);
    lpobj->topic         = GlobalAddAtom (lpfile);
    lpobj->aServer       = aServer;
    lpobj->bOleServer    = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
    if ((retval = SetNetName (lpobj)) != OLE_OK)
        goto errFileCreate;
    
    if (lpitem)
        lpobj->item = GlobalAddAtom (lpitem);

    if (!CreatePictObject (lhclientdoc, lpobjname, lpobj, 
                optRender, cfFormat, lpclass)) {
        retval = OLE_ERROR_MEMORY;
        goto errFileCreate;
    }
    
    *lplpoleobject = (LPOLEOBJECT) lpobj;
    
    if (objType == CT_EMBEDDED) {
        releaseMethod = OLE_CREATEFROMFILE;
        if ((optRender == olerender_format) && (cfFormat == cfNative))
            wFlags = 0;
        else
            wFlags = ACT_NATIVE;
    }
    else {          
        // caller wants linked object to be created
        
        // if no presentation data is requested and the link is to the whole
        // file, then there is no need to launch the server. 
            
        if ((optRender == olerender_none) && !lpobj->item)
            return FileExists (lpobj);
        
        // we want to establish hot link
        wFlags = ACT_ADVISE; 
        releaseMethod = OLE_CREATELINKFROMFILE;     
    }

    lpobj->fCmd = LN_LNKACT | ACT_REQUEST | ACT_UNLAUNCH | wFlags;      
    InitAsyncCmd (lpobj, releaseMethod , LNKOPENUPDATE);       
    
    if ((retval = LnkOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
        return retval;
    
    // If there is error afterwards, then the client app should call
    // to delete the object.


errFileCreate:  

    if (lpobj) {
        // This oledelete will not result in asynchronous command.
        OleDelete ((LPOLEOBJECT)lpobj); 
        *lplpoleobject = NULL;
    }
    
    return retval;
}



//////////////////////////////////////////////////////////////////////////////
//
// OLESTATUS FARINTERNAL LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, bActivate)
//
//  Arguments:
//
//     lpclient -   
//     lpclass  -   
//     lhclientdoc  -   
//     lpobjname    -   
//     lplpoleobject    -   
//     optRender    -   
//     cfFormat -   
//     fActivate    -
//
//  Returns:
//
//      OLE_ERROR_CLASS -   
//      OLE_OK  -   
//      EmbOpenUpdate (lpobj)   -   
//      retval  -   
//
//  Effects:
//
//////////////////////////////////////////////////////////////////////////////

OLESTATUS FARINTERNAL LeCreateInvisible (lpclient, lpclass, lhclientdoc, lpobjname, lplpoleobject, optRender, cfFormat, fActivate)
LPSTR               lpclass;
LPOLECLIENT         lpclient;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpoleobject;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
BOOL                fActivate;
{
    OLESTATUS       retval = OLE_ERROR_MEMORY;
    LPOBJECT_LE     lpobj = NULL;
    ATOM            aServer;
    char            chVerb [2];
    
    if (!(aServer = GetAppAtom (lpclass)))
        return OLE_ERROR_CLASS;
    
    if(!(lpobj = LeCreateBlank (lhclientdoc, lpobjname, CT_EMBEDDED))) {
        GlobalDeleteAtom (aServer);
        goto errRtn;
    }
    
    // Now set the server.

    lpobj->head.lpclient = lpclient;
    lpobj->app           = GlobalAddAtom (lpclass);
    lpobj->item          = NULL;
    lpobj->bOleServer    = QueryVerb (lpobj, 0, (LPSTR)&chVerb, 2);
    lpobj->aServer       = aServer;
    lpobj->lptemplate    = NULL;
    SetEmbeddedTopic (lpobj);
    
    if (!CreatePictObject (lhclientdoc, lpobjname, lpobj, 
                optRender, cfFormat, lpclass))
        goto errRtn;

    *lplpoleobject = (LPOLEOBJECT)lpobj;
    
    if (!fActivate)
        return OLE_OK;

    // show the window. Advise for data and close on receiving data
    lpobj->fCmd = LN_NEW | ACT_ADVISE | ACT_CLOSE;
    InitAsyncCmd (lpobj, OLE_CREATEINVISIBLE, EMBOPENUPDATE);

    // launch the app and start the system conversation.
    if ((retval = EmbOpenUpdate (lpobj)) <= OLE_WAIT_FOR_RELEASE)
        return retval;

    // If there is error afterwards, then the client app should call
    // to delete the object.

errRtn:

    // for error termination OleDelete will terminate any conversation
    // in action.

    if (lpobj) {
        // This oledelete will not result in asynchronous command.
        OleDelete ((LPOLEOBJECT)lpobj);
        *lplpoleobject = NULL;
    }
    
    return retval;
}



// LeSetUpdateOptions: sets the update options. If the server
// is connectd then it unadvises for the current options and
// advises for the new options.

OLESTATUS   FARINTERNAL LeSetUpdateOptions (lpobj, options)
LPOBJECT_LE         lpobj;
OLEOPT_UPDATE       options;
{

    PROBE_OLDLINK (lpobj);
    PROBE_ASYNC (lpobj);
    
    //!!! make sure the options are within range.
    
    if (lpobj->head.ctype != CT_LINK)
        return (OLE_ERROR_OBJECT);

    if (options > oleupdate_oncall)
        return OLE_ERROR_OPTION;

    if (lpobj->optUpdate == options)
        return OLE_OK;

    if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj)) {
       lpobj->optUpdate = options;
       return OLE_OK;
    }

    lpobj->optNew = options;
    lpobj->fCmd = 0;
    InitAsyncCmd (lpobj, OLE_SETUPDATEOPTIONS, LNKSETUPDATEOPTIONS);
    return LnkSetUpdateOptions (lpobj);

}

OLESTATUS   LnkSetUpdateOptions (lpobj)
LPOBJECT_LE         lpobj;
{

    switch (lpobj->subRtn) {

        case 0:

            if (lpobj->optUpdate == oleupdate_oncall)
                goto step1;

            // If the server is active then unadvise for old
            // options.

            UnAdvisePict (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 1:
            step1:

            SETSTEP (lpobj, 1);
            ProcessErr (lpobj);

            lpobj->optUpdate = lpobj->optNew;
            if (lpobj->optUpdate == oleupdate_oncall)
                goto step3;

            AdvisePict (lpobj, NULL);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 2:
            SETSTEP (lpobj, 2);
            if (ProcessErr (lpobj))
                goto errRtn;
            
            if (lpobj->optUpdate == oleupdate_onsave)
                goto step3;

            RequestPict (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);
            
        case 3:
            errRtn:
            step3:
            ProcessErr (lpobj);
            return EndAsyncCmd (lpobj);

        default:
            DEBUG_OUT ("Unexpected subroutine", 0);
            return OLE_ERROR_GENERIC;
    }
}



//AdvisePict: Sends advise for pict data

void    INTERNAL AdvisePict (lpobj, aAdvItem)
LPOBJECT_LE lpobj;
ATOM        aAdvItem;
{
    int         cftype;

    if (cftype = GetPictType (lpobj))
        AdviseOn (lpobj, cftype, aAdvItem);
}


//UnAdvisePict: Sends unadvise for pict data

void   INTERNAL UnAdvisePict (lpobj)
LPOBJECT_LE         lpobj;
{
    int         cftype;
    SETERRHINT (lpobj, OLE_ERROR_ADVISE_PICT);
    if (cftype = GetPictType (lpobj))
         UnAdviseOn (lpobj, cftype);
}

// GetPictType: Given the object, returns the pict type.

int     INTERNAL GetPictType (lpobj)
LPOBJECT_LE         lpobj;
{
    if (lpobj->lpobjPict)
        return (int)(*lpobj->lpobjPict->lpvtbl->EnumFormats)
                                (lpobj->lpobjPict, NULL);
    return NULL;
}


// AdviseOn : Sends advise for a given picture type
// Send advise only if the advise options is not on call.

void  INTERNAL AdviseOn (lpobj, cftype, advItem)
LPOBJECT_LE lpobj;
int         cftype;
ATOM        advItem;
{
    HANDLE          hopt   = NULL;
    DDEADVISE FAR   *lpopt = NULL;
    ATOM            item   = NULL;
    PEDIT_DDE       pedit;
    OLESTATUS       retval;

    if (cftype == (int)cfNative)
        SETERRHINT (lpobj, OLE_ERROR_ADVISE_NATIVE);
    else {
        if (cftype == (int)cfBinary)
            SETERRHINT (lpobj, OLE_ERROR_ADVISE_RENAME);
        else
            SETERRHINT (lpobj, OLE_ERROR_ADVISE_PICT);

    }
    
    if (lpobj->optUpdate == oleupdate_oncall)
        return;

    if(!(hopt = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof(DDEADVISE))))
        goto errRtn;

    retval = OLE_ERROR_MEMORY;
    if(!(lpopt = (DDEADVISE FAR *) GlobalLock (hopt)))
        goto errRtn;

    pedit = lpobj->pDocEdit;
    lpopt->fAckReq = TRUE;

    // get data always. Currently there is no way for the
    // deferred updates.

    lpopt->fDeferUpd = 0;
    lpopt->cfFormat = cftype;
    GlobalUnlock (hopt);

    pedit->hopt = hopt;
    
    if (advItem == aStdDocName)
        item = DuplicateAtom (advItem);
    else
        item = ExtendAtom (lpobj, lpobj->item);

    retval = OLE_ERROR_COMM;
    if (!PostMessageToServer(pedit, WM_DDE_ADVISE, MAKELONG (hopt, item)))
        goto errRtn;

#ifdef  FIREWALLS
    ASSERT (!pedit->bTerminating, "trying to post while termination")
    ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif
    pedit->awaitAck = AA_ADVISE;
    lpobj->bAsync    = TRUE;
    
    if (advItem == aClose)
       lpobj->pDocEdit->nAdviseClose++;
    else if (advItem == aSave)
       lpobj->pDocEdit->nAdviseSave++;     
   
    return;

errRtn:

    if (item)
        GlobalDeleteAtom (item);

    if (lpopt)
        GlobalUnlock (hopt);

    if (hopt)
        GlobalFree (hopt);
    lpobj->subErr = retval;

    return ;


}



//UnAdviseOn: Sends unadvise for an item.
void INTERNAL UnAdviseOn (lpobj, cftype)
LPOBJECT_LE lpobj;
int         cftype;
{
    ATOM        item;
    PEDIT_DDE   pedit;

    pedit  =  lpobj->pDocEdit;
    item    = ExtendAtom (lpobj, lpobj->item);

    if (!PostMessageToServer(pedit, WM_DDE_UNADVISE, MAKELONG (NULL, item)))
        lpobj->subErr = OLE_ERROR_COMM;
    else {
#ifdef  FIREWALLS
    ASSERT (!pedit->bTerminating, "trying to post while termination")
    ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif
        lpobj->bAsync    = TRUE;
        pedit->awaitAck = AA_UNADVISE;
    }
}

// RequestOn: Semd WM_DDE_REQUEST for the item of the
// for a given type;

void INTERNAL RequestOn (lpobj, cftype)
LPOBJECT_LE lpobj;
int         cftype;
{
    ATOM        item = NULL;
    PEDIT_DDE   pedit;
    OLESTATUS   retval = OLE_ERROR_COMM;

    if (cftype == (int)cfNative)
        SETERRHINT (lpobj, OLE_ERROR_REQUEST_NATIVE);
    else
        SETERRHINT (lpobj, OLE_ERROR_REQUEST_PICT);

    pedit = lpobj->pDocEdit;

    item = DuplicateAtom (lpobj->item);
    if (!PostMessageToServer (pedit, WM_DDE_REQUEST, MAKELONG (cftype, item)))
        goto errRtn;

#ifdef  FIREWALLS
    ASSERT (!pedit->bTerminating, "trying to post while termination")
    ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif

    lpobj->bAsync    = TRUE;
    pedit->awaitAck = AA_REQUEST;
    return;

errRtn:

    if (item)
        GlobalDeleteAtom (item);
    return ;

}


//RequestPict: Sends request for apicture type.
void INTERNAL RequestPict (lpobj)
LPOBJECT_LE         lpobj;
{
    int cftype;
    
    if (cftype = GetPictType (lpobj))
        RequestOn (lpobj, cftype);
}



// LeSetHostNames: Sets the host names. If the server is connected
// send the host names to the server.
OLESTATUS FARINTERNAL  LeSetHostNames (lpobj, lpclientName, lpdocName)
LPOBJECT_LE lpobj;
LPSTR       lpclientName;
LPSTR       lpdocName;
{
    OLESTATUS   retval = OLE_ERROR_MEMORY;

    if (lpobj->head.ctype != CT_EMBEDDED)
        return OLE_ERROR_OBJECT;

    PROBE_ASYNC (lpobj);
    if ((retval = SetHostNamesHandle (lpobj, lpclientName, lpdocName)) 
            != OLE_OK) 
        return retval;

    
    // If the server is connected poke the hostnames
    InitAsyncCmd (lpobj, OLE_OTHER, NULL);
    if ((retval = PokeHostNames (lpobj)) != OLE_WAIT_FOR_RELEASE)
        CLEARASYNCCMD(lpobj);

    return retval;
}



OLESTATUS   FARINTERNAL  LeSetTargetDevice (lpobj, hdata)
LPOBJECT_LE lpobj;
HANDLE      hdata;
{
    HANDLE      hdup = NULL;
    OLESTATUS   retval;

    PROBE_ASYNC (lpobj);
    
    if (!hdata) {
        // hdata == NULL means we should not make the target device sticky.
        // This will give the flexibility to the client app. Note that this
        // will not be effective till the next activation.
        if (lpobj->htargetDevice) {
            GlobalFree (lpobj->htargetDevice);
            lpobj->htargetDevice = NULL;
        }
        
        return OLE_OK;
    }
    
    if(!(hdup = DuplicateGlobal (hdata, GMEM_MOVEABLE)))
        return OLE_ERROR_MEMORY;

    if (lpobj->htargetDevice)
        GlobalFree (lpobj->htargetDevice);

    lpobj->htargetDevice = hdup;
    InitAsyncCmd (lpobj, OLE_OTHER, NULL);
    if ((retval = PokeTargetDeviceInfo (lpobj)) != OLE_WAIT_FOR_RELEASE)
        CLEARASYNCCMD(lpobj);
    
    return retval;
}



OLESTATUS FARINTERNAL  LeSetBounds(lpobj, lprcBounds)
LPOBJECT_LE        lpobj;
LPRECT             lprcBounds;
{
    OLESTATUS       retval = OLE_ERROR_MEMORY;
    HANDLE          hdata = NULL;
    LPBOUNDSRECT    lprc  = NULL;

    PROBE_ASYNC (lpobj);
    
    if (lpobj->head.ctype != CT_EMBEDDED)
        return OLE_ERROR_OBJECT;

    if(!(hdata = GlobalAlloc (GMEM_MOVEABLE, (WORD)sizeof (BOUNDSRECT))))
        return OLE_ERROR_MEMORY;

    if (!(lprc = (LPBOUNDSRECT)GlobalLock (hdata)))
        goto errrtn;

    // Now set the data

    lprc->defaultWidth    =  lprcBounds->right  - lprcBounds->left;;
    lprc->defaultHeight   =  -(lprcBounds->bottom - lprcBounds->top);
    lprc->maxWidth        =  lprcBounds->right  - lprcBounds->left;;
    lprc->maxHeight       =  -(lprcBounds->bottom - lprcBounds->top);

    GlobalUnlock (hdata);

    if (lpobj->hdocDimensions)
        GlobalFree (lpobj->hdocDimensions);

    lpobj->hdocDimensions = hdata;
    InitAsyncCmd (lpobj, OLE_OTHER, NULL);
    if ((retval = PokeDocDimensions (lpobj)) != OLE_WAIT_FOR_RELEASE)
        CLEARASYNCCMD(lpobj);

    return retval;
    
errrtn:
    if (lprc)
        GlobalUnlock (hdata);
    if (hdata)
        GlobalFree (hdata);
    
    return retval;
}


OLESTATUS FARINTERNAL LeSetData (lpobj, cfFormat, hData)
LPOBJECT_LE     lpobj;
OLECLIPFORMAT   cfFormat;
HANDLE          hData;
{
    OLESTATUS   retVal = OLE_OK;
    BOOL        fKnown = FALSE;
        
    PROBE_ASYNC (lpobj);
    
    if ((cfFormat == cfObjectLink) || (cfFormat == cfOwnerLink))
        return ChangeDocAndItem (lpobj, hData);
    
    if (fKnown = (cfFormat && (cfFormat == ((WORD) GetPictType (lpobj))))) {
        retVal =  (*lpobj->lpobjPict->lpvtbl->ChangeData) (lpobj->lpobjPict,
                                    hData, lpobj->head.lpclient, FALSE);
                                
        (*lpobj->lpobjPict->lpvtbl->GetData) (lpobj->lpobjPict, 
                                cfFormat, &hData);                      
    }
    else if (fKnown = (cfFormat == cfNative)) {
        retVal = LeChangeData (lpobj, hData, lpobj->head.lpclient, FALSE);
        hData = lpobj->hnative;
    }
    
    if (retVal != OLE_OK)
        return retVal;
    
    if (fKnown) 
        ContextCallBack (lpobj, OLE_CHANGED);
    
    if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj)) {
        if (!fKnown)
            return OLE_ERROR_NOT_OPEN;
        return OLE_OK;
    }

    // except for the following formats all the other data will be copied
    // into DDEPOKE block. So there is no need to duplicate the data of the
    // other formats
    if ((cfFormat == CF_METAFILEPICT) || (cfFormat == CF_BITMAP)
            || (cfFormat == CF_DIB)) {
            
        if (!(hData = DuplicateGDIdata (hData, cfFormat)))
            return OLE_ERROR_MEMORY;
    }
    
    // *** The last parameter must be NULL, don't change it ***
    InitAsyncCmd (lpobj, OLE_SETDATA, NULL);
    if ((retVal = SendPokeData (lpobj, lpobj->item, hData, cfFormat))
            != OLE_WAIT_FOR_RELEASE)
        CLEARASYNCCMD(lpobj);
    
    return retVal;
}



OLESTATUS   FARINTERNAL  LeSetColorScheme (lpobj, lplogpal)
LPOBJECT_LE     lpobj;
LPLOGPALETTE    lplogpal;
{
    HANDLE      hdup = NULL;
    DWORD       cblogpal;
    OLESTATUS   retval;
    LPBYTE      lptemp;
    
    lptemp = (LPBYTE) lplogpal;
    
    if (lpobj->head.ctype != CT_EMBEDDED)
        return OLE_ERROR_OBJECT;

    PROBE_ASYNC (lpobj);
    
    if (!lplogpal) {
        // lplogpal == NULL means we should not make color scheme sticky.
        // This will give the flexibility to the client app. Note that this
        // will not be effective till next activation.
        if (lpobj->hlogpal) {
            GlobalFree (lpobj->hlogpal);
            lpobj->hlogpal = NULL;
        }
        
        return OLE_OK;
    }
    
    
    FARPROBE_READ(lptemp + (cblogpal = 2*sizeof(WORD)));
    cblogpal += ((sizeof(PALETTEENTRY) * lplogpal->palNumEntries) -1);
    if (!FarCheckPointer (lptemp + cblogpal, READ_ACCESS))
        return OLE_ERROR_PALETTE;

    if (!(hdup = CopyData ((LPSTR) lplogpal, cblogpal)))
        return OLE_ERROR_MEMORY;    
    
    if (lpobj->hlogpal)
        GlobalFree (lpobj->hlogpal);

    lpobj->hlogpal = hdup;
    InitAsyncCmd (lpobj, OLE_OTHER, NULL);
    if ((retval = PokeColorScheme (lpobj)) != OLE_WAIT_FOR_RELEASE)
        CLEARASYNCCMD(lpobj);

    return retval;
}



//PokeHostNames: Pokes hostname data to the server
OLESTATUS INTERNAL PokeHostNames (lpobj)
LPOBJECT_LE lpobj;
{
    OLESTATUS   retVal = OLE_ERROR_MEMORY;

    // if the server is connectd then poke the host names
    if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
        return OLE_OK;

    if (!lpobj->hhostNames) 
        return OLE_OK;
    
    aStdHostNames = GlobalAddAtom ("StdHostNames");
    return SendPokeData (lpobj,aStdHostNames,lpobj->hhostNames,cfBinary);
}


OLESTATUS INTERNAL  PokeTargetDeviceInfo (lpobj)
LPOBJECT_LE lpobj;
{

   // if the server is connectd then poke the host names
   if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
        return OLE_OK;

   if (!lpobj->htargetDevice)
        return OLE_OK;

   aStdTargetDevice = GlobalAddAtom ("StdTargetDevice");
   return SendPokeData (lpobj, aStdTargetDevice,
                    lpobj->htargetDevice,
                    cfBinary);
}


OLESTATUS INTERNAL  PokeDocDimensions (lpobj)
LPOBJECT_LE lpobj;
{

   // if the server is connectd then poke the host names
   if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
        return OLE_OK;

   if (!lpobj->hdocDimensions)
        return OLE_OK;

   aStdDocDimensions = GlobalAddAtom ("StdDocDimensions");
   return SendPokeData (lpobj, aStdDocDimensions,
                    lpobj->hdocDimensions,
                    cfBinary);
}


OLESTATUS INTERNAL  PokeColorScheme (lpobj)
LPOBJECT_LE lpobj;
{
   // if the server is connected then poke the palette info
   if (!QueryOpen (lpobj) || IS_SVRCLOSING(lpobj))
        return OLE_OK;

   if (!lpobj->hlogpal)
        return OLE_OK;

   aStdColorScheme = GlobalAddAtom ("StdColorScheme"); 
   return SendPokeData (lpobj, aStdColorScheme,
                    lpobj->hlogpal,
                    cfBinary);
}


OLESTATUS INTERNAL SendPokeData (lpobj, aItem, hdata, cfFormat)
LPOBJECT_LE     lpobj;
ATOM            aItem;
HANDLE          hdata;
OLECLIPFORMAT   cfFormat;
{
    HANDLE      hdde = NULL;
    DDEPOKE FAR * lpdde = NULL;
    LPSTR       lpdst = NULL;
    LPSTR       lpsrc = NULL;
    OLESTATUS   retval = OLE_ERROR_MEMORY;
    DWORD       dwSize = NULL;
    PEDIT_DDE   pedit;
    BOOL        bGDIdata = FALSE;

    pedit = lpobj->pDocEdit;

    // If it is GDI data then we can stuff the handle into POKE block. 
    // Otherwise we have to copy the data into DDE data block. There
    // is a special case with old MSDraw, that will be handled by
    // the routine CanPutHandleInPokeBlock()
        
    if (!(bGDIdata = CanPutHandleInPokeBlock (lpobj, cfFormat))) {
        if (!(dwSize = GlobalSize (hdata)))
            return OLE_ERROR_MEMORY;
                
        if (!(lpsrc = (LPSTR) GlobalLock (hdata))) 
            return OLE_ERROR_MEMORY;
        
        GlobalUnlock (hdata);
    }
    
    // Now allocate the DDE data block

    if (!(hdde = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, 
                 (dwSize + sizeof(DDEPOKE) - sizeof(BYTE) + sizeof(HANDLE)))))
        goto errRtn;

    if (!(lpdde = (DDEPOKE FAR *)GlobalLock (hdde)))
        goto errRtn;

    GlobalUnlock (hdde);

    // !!! We may want to set it TRUE, for performance reasons. But it 
    // will require some rework on the server side
    lpdde->fRelease = 0;
    lpdde->cfFormat = cfFormat;

    if (bGDIdata) 
        *(LPHANDLE)lpdde->Value = hdata;
    else {
        lpdst = (LPSTR)lpdde->Value;
        UtilMemCpy (lpdst, lpsrc, dwSize);
        
        // For the CF_METAFILEPICT format, we would come here only if we are
        // dealing with the old version of MSDraw. In that case we want to
        // free the handle to METAFILEPICT strcuture, because we've already
        // copied its contents to DDEPOKE structure.
            
        // Note that that the old MSDraw expects the contents of METAFILEPICT
        // structure to be part of DDEPOKE, rather than the handle to it.

        if (cfFormat == CF_METAFILEPICT) {
            GlobalFree (hdata);
            hdata = NULL;
        }
    }

    // *** From here onwards if there is an error call FreePokeData(), don't
    // jump to errRtn
        
    aItem = DuplicateAtom (aItem);

    ASSERT(pedit->hData == NULL, "Poke data is not null");

    pedit->hData = hdde;
    if (!PostMessageToServer (pedit, WM_DDE_POKE, MAKELONG (hdde, aItem))) {
        if (aItem)
            GlobalDeleteAtom (aItem);
        FreePokeData (lpobj, pedit);
        return (lpobj->subErr = OLE_ERROR_COMM);
    }

#ifdef  FIREWALLS
    ASSERT (!pedit->bTerminating, "trying to post while termination")
    ASSERT (pedit->awaitAck == NULL, "Trying to Post msg while waiting for ack")
#endif
    if (lpobj->asyncCmd == OLE_NONE)
        lpobj->asyncCmd = OLE_OTHER;

    lpobj->bAsync    = TRUE;
    pedit->awaitAck = AA_POKE;
    // !!! after poke of the hostnames etc. we are not processing error.,

    // Data is freed after the Poke is acknowledged. OLE_RELEASE will be sent
    // to when ACK comes.
        
    return OLE_WAIT_FOR_RELEASE;

errRtn:
    if (hdata)
        FreeGDIdata (hdata, cfFormat);
    
    if (hdde)
        GlobalFree (hdde);

    pedit->hData = NULL;

    return (lpobj->subErr = retval);
}



// FreePokeData: Frees the poked data.
void  INTERNAL FreePokeData (lpobj, pedit)
LPOBJECT_LE lpobj;
PEDIT_DDE   pedit;
{
    DDEPOKE FAR * lpdde;
    
#ifdef  FIREWALLS
    ASSERT (pedit->hData, "Poke data handle is null");

#endif
    
    if (lpdde = (DDEPOKE FAR *) GlobalLock (pedit->hData)) {
        GlobalUnlock (pedit->hData);
        
        // The old version of MSDraw expects the contents of METAFILEPICT
        // structure to be part of DDEPOKE, rather than the handle to it.

        if (!lpobj->bOleServer && (lpobj->app == aMSDraw)
                && (lpdde->cfFormat == CF_METAFILEPICT)) {
            DeleteMetaFile (((LPMETAFILEPICT) ((LPSTR) &lpdde->Value))->hMF);
        }
        else { 
            FreeGDIdata (*(LPHANDLE)lpdde->Value, lpdde->cfFormat);
        }
    }
        
    GlobalFree (pedit->hData);
    pedit->hData = NULL;
}



BOOL INTERNAL  SendSrvrMainCmd (lpobj, lptemplate)
LPOBJECT_LE lpobj;
LPSTR       lptemplate;
{
    WORD        size;
    WORD        len;
    OLESTATUS   retval;
    int         cmd;
    HANDLE      hInst = NULL;
    LPSTR       lpdata= NULL;
    HANDLE      hdata = NULL;
    BOOL        bLaunch = TRUE;

    Puts("Launch App and Send Sys command");

#ifdef  FIREWALLS
    ASSERT (lpobj->aServer, "Serevr is NULL");
#endif

    if (!lpobj->aServer) {
        retval = OLE_ERROR_REGISTRATION;
        goto errRtn;
    }
    
    if (!lpobj->bOldLink) {
        bLaunch = !(lpobj->fCmd & ACT_NOLAUNCH);
        cmd = lpobj->fCmd & LN_MASK;
    }
    
    if (cmd == LN_LNKACT) {
        // take care of network based document        
        char    cDrive = lpobj->cDrive;
    
        if ((retval = CheckNetDrive (lpobj, POPUP_NETDLG)) != OLE_OK) {
            lpobj->cDrive = cDrive;
            goto errRtn;
        }
        
        if (cDrive != lpobj->cDrive)
            ContextCallBack (lpobj, OLE_RENAMED);
    }
    
    if (!InitSrvrConv (lpobj, hInst)) {

        if (!bLaunch)
            goto errRtn;
        
        if (!(hInst = LeLaunchApp (lpobj))) {
            // We failed to launch the app. If it is a linked object, see
            // whether the docname is valid for new servers.  We wouldn't
            // have given the doc name on the command line for the old
            // servers. So, there is no point in checking for file existance
            // in that case.
            if (lpobj->bOleServer && (lpobj->bOldLink || (cmd == LN_LNKACT))){
                if ((retval = FileExists (lpobj)) != OLE_OK)
                    goto errRtn;
            }
            
            retval = OLE_ERROR_LAUNCH;
            goto errRtn;
        }
        
        if (lpobj->bOldLink)
            return TRUE;

        if (lpobj->bOleServer && (cmd == LN_LNKACT)) {
            // We are not using any data blocks if the object is old link.
            // we launched with docname, and don't have to establish system
            // level and also we don't have to send exec strings.

            // for non-ole servers like excel, we do want to connect at
            // the system level, so that we can send "StdOpen". We also 
            // have to send "StdExit" for the server to exit in the
            // invisible launch case.

            return TRUE;
        }

        retval = OLE_ERROR_COMM;
        if(!InitSrvrConv (lpobj, hInst))
            goto errRtn;
#ifdef OLD
        if (!lpobj->bOleServer && (cmd == LN_LNKACT))
            return TRUE;
#endif
    }

    if (!lpobj->bOldLink) {
        cmd = lpobj->fCmd & LN_MASK;
        len =  lstrlen (srvrSysCmd[cmd >> LN_SHIFT]);

        // for template and new, add the class name also
        if (cmd == LN_NEW || cmd == LN_TEMPLATE)
            len += GlobalGetAtomLen (lpobj->app);

        // Now add the document length.
        len += GlobalGetAtomLen (lpobj->topic);

        // add the length of the template name
        if (lptemplate)
            len += lstrlen (lptemplate);

        // now add the fudge factor for the Quotes etc.
        len += LN_FUDGE;

        // allocate the buffer and set the command.
        hdata = GlobalAlloc (GMEM_DDESHARE, size = len);

        retval = OLE_ERROR_MEMORY;
        SETERRHINT(lpobj, OLE_ERROR_MEMORY);

        if (hdata == NULL || (lpdata = (LPSTR)GlobalLock (hdata)) == NULL)
            goto errRtn;
    }
    
    lstrcpy (lpdata, (LPSTR)"[");           // [
    lstrcat (lpdata, srvrSysCmd[cmd >> LN_SHIFT]);      // [Std....
    lstrcat (lpdata, "(\"");                // [std...("

    if (cmd == LN_NEW  || cmd == LN_TEMPLATE) {
        len = lstrlen (lpdata);
        GlobalGetAtomName (lpobj->app, (LPSTR)lpdata + len, size - len);
                                            // [std...("class
        lstrcat (lpdata, "\",\"");          // [std...("class", "
    }
    len = lstrlen (lpdata);
    // now get the topic name.
    GlobalGetAtomName (lpobj->topic, lpdata + len, (WORD)size - len);
                                            // [std...("class","doc
    if (lptemplate) {
        lstrcat (lpdata, "\",\"");          // [std...("class","doc","
        lstrcat  (lpdata, lptemplate);      // [std...("class","doc","temp
    }

    lstrcat (lpdata, "\")]");               // [std...("class","doc","temp")]

    GlobalUnlock (hdata);

    // !!!optimize with mapping.
    SETERRHINT(lpobj, (OLE_ERROR_TEMPLATE + (cmd >> LN_SHIFT)));

    return SrvrExecute (lpobj, hdata);

errRtn:
    if (lpdata)
        GlobalUnlock (hdata);

    if (hdata)
        GlobalFree (hdata);
    lpobj->subErr = retval;
    return FALSE;
}




// ExtendAtom: Create a new atom, which is the old one plus extension

ATOM INTERNAL ExtendAtom (lpobj, item)
LPOBJECT_LE lpobj;
ATOM    item;
{
    char    buffer[MAX_ATOM+1];
    LPSTR   lpext;

    Puts("ExtendAtom");

    buffer[0] = 0;
    if (item)
        GlobalGetAtomName (item, buffer, MAX_ATOM);

    switch (lpobj->optUpdate) {


        case oleupdate_always:
            lpext = (LPSTR)"";
            break;

        case oleupdate_onsave:
            lpext = (LPSTR)"/Save";
            break;

        case oleupdate_onclose:
            lpext = (LPSTR)"/Close";
            break;

        default:
            ASSERT (FALSE, "on call options not expected here");
            break;

    }
    
    lstrcat (buffer, lpext);
    if (buffer[0])
        return GlobalAddAtom (buffer);
    else
        return NULL;
}


BOOL INTERNAL CreatePictObject (lhclientdoc, lpobjname, lpobj, optRender, cfFormat, lpclass)
LHCLIENTDOC     lhclientdoc;
LPSTR           lpobjname;
LPOBJECT_LE     lpobj;
OLEOPT_RENDER   optRender;
OLECLIPFORMAT   cfFormat;
LPSTR           lpclass;
{
    LPOLEOBJECT lpPictObj = NULL;
    ATOM        aClass;
    
    lpobj->lpobjPict = NULL;
    if (optRender == olerender_format) {
        switch (cfFormat) {
            case NULL:
                return FALSE;
                
            case CF_METAFILEPICT:
                if (!(lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc, 
                                            lpobjname, CT_PICTURE))) 
                    return FALSE;
                break;

            case CF_DIB:
                if (!(lpPictObj = (LPOLEOBJECT) DibCreateBlank (lhclientdoc, 
                                            lpobjname, CT_PICTURE)))
                    return FALSE;
                break;
            
            case CF_BITMAP:
                if (!(lpPictObj = (LPOLEOBJECT) BmCreateBlank (lhclientdoc, 
                                            lpobjname, CT_PICTURE))) 
                    return FALSE;
                break;
                
            default:
                aClass = GlobalAddAtom (lpclass);
                if (!(lpPictObj = (LPOLEOBJECT) GenCreateBlank (lhclientdoc, 
                                            lpobjname, CT_PICTURE, aClass)))
                    return FALSE;

                ((LPOBJECT_GEN)lpPictObj)->cfFormat = cfFormat;
                break;
        }
    }
    else if (optRender == olerender_draw) {
          if (!(lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc, 
                                                lpobjname, CT_PICTURE))) 
                return FALSE;
#ifdef LATER
        if (AdviseOn (lpobj, (cfFormat = CF_METAFILEPICT), NULL))
            lpPictObj = (LPOLEOBJECT) MfCreateBlank (lhclientdoc, 
                                                lpobjname, CT_PICTURE);
        // !!! for the time being take assume we need to get metafile.
        else if (AdviseOn (lpobj, (cfFormat = CF_DIB), NULL))
            lpPictObj = (LPOLEOBJECT) DibCreateBlank (lhclientdoc, 
                                                lpobjname, CT_PICTURE);
        else if (AdviseOn (lpobj, (cfFormat = CF_BITMAP), NULL))
            lpPictObj = (LPOLEOBJECT) BmCreateBlank (lhclientdoc, 
                                                lpobjname, CT_PICTURE);
        else 
            goto errPict;
#endif
        
    }
    else
        return (optRender == olerender_none);

    if (lpobj->lpobjPict = lpPictObj)
        lpobj->lpobjPict->lpParent = (LPOLEOBJECT) lpobj;
    return TRUE;
}


OLESTATUS LnkChangeLnk (lpobj)
LPOBJECT_LE lpobj;
{

    switch (lpobj->subRtn) {

        case 0:
            TermDocConv (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case 1:

            // delete the edit block
            DeleteDocEdit (lpobj);
            TermSrvrConv (lpobj);
            WAIT_FOR_ASYNC_MSG (lpobj);

        case    2:

            // Do not set any errors, just delete the object.
            // delete the server edit block
            DeleteSrvrEdit (lpobj);

            // now try to activate the new link.
            SKIP_TO (!InitDocConv (lpobj, !POPUP_NETDLG), step3);
            lpobj->fCmd = LN_LNKACT | ACT_ADVISE | ACT_REQUEST;
            InitAsyncCmd (lpobj, OLE_SETDATA, LNKOPENUPDATE);
            return LnkOpenUpdate (lpobj);

        case    3:
            step3:
            return EndAsyncCmd (lpobj);

        default:
            DEBUG_OUT ("Unexpected subroutine", 0);
            return OLE_ERROR_GENERIC;
    }
}


OLESTATUS INTERNAL ChangeDocAndItem (lpobj, hinfo)
LPOBJECT_LE lpobj;
HANDLE      hinfo;
{
    LPSTR       lpinfo;
    ATOM        aNewTopic, aNewItem = NULL, aOldTopic;
    OLESTATUS   retVal = OLE_ERROR_BLANK;

    PROBE_SVRCLOSING(lpobj);
    
    if (!(lpinfo = GlobalLock (hinfo)))
        return OLE_ERROR_MEMORY;
    
    lpinfo += lstrlen (lpinfo) + 1;
    aNewTopic = GlobalAddAtom (lpinfo);
    lpinfo += lstrlen (lpinfo) + 1;
    if (*lpinfo)
        aNewItem = GlobalAddAtom (lpinfo);

    if (!aNewTopic && (lpobj->head.ctype == CT_LINK)) 
        goto errRtn;

    aOldTopic = lpobj->topic;
    lpobj->topic = aNewTopic;
    if ((retVal = SetNetName (lpobj)) != OLE_OK) {
        if (lpobj->topic)
            GlobalDeleteAtom (lpobj->topic);
        lpobj->topic = aOldTopic;
        goto errRtn;
    }

    if (aOldTopic)
        GlobalDeleteAtom (aOldTopic);
    
    if (lpobj->item)
        GlobalDeleteAtom (lpobj->item); 
    
    lpobj->item = aNewItem;
    
    // As the atoms have already changed, lpobj->hLink becomes irrelevant. 
    if (lpobj->hLink) {             
        GlobalFree (lpobj->hLink);
        lpobj->hLink = NULL;
    }
    
    GlobalUnlock(hinfo);
    
    // Now disconnect the old link and try to connect to the new one.
    lpobj->fCmd = 0;
    InitAsyncCmd (lpobj, OLE_SETDATA, LNKCHANGELNK);
    return LnkChangeLnk (lpobj);

errRtn:

    if (aNewItem)
        GlobalDeleteAtom (aNewItem);
    
    GlobalUnlock (hinfo);        
    return retVal;
}


BOOL    QueryUnlaunch (lpobj)
LPOBJECT_LE lpobj;
{
    if (!(lpobj->fCmd & ACT_UNLAUNCH))
        return FALSE;
    
    // only if we loaded the app
    if (lpobj->pSysEdit && lpobj->pSysEdit->hClient && lpobj->pSysEdit->hInst)
        return TRUE;
    
    return FALSE;
}


BOOL     QueryClose (lpobj)
LPOBJECT_LE lpobj;
{
    if (!((lpobj->fCmd & ACT_UNLAUNCH) ||
            (lpobj->head.ctype == CT_EMBEDDED)))
        return FALSE;

    // only if we loaded the documnet
    if (lpobj->pSysEdit && lpobj->pSysEdit->hClient)
        return TRUE;
    
    return FALSE;
}


OLESTATUS INTERNAL SetHostNamesHandle (lpobj, lpclientName, lpdocName)
LPOBJECT_LE lpobj;
LPSTR       lpclientName;
LPSTR       lpdocName;
{
    WORD        cbClient;
    WORD        size;
    HANDLE      hhostNames      = NULL;
    LPHOSTNAMES lphostNames     = NULL;
    LPSTR       lpdata;
  
    // 4 bytes  is for the two offsets
    size = (cbClient = lstrlen(lpclientName)+1) + (lstrlen(lpdocName)+1) + 4;

    if ((hhostNames = GlobalAlloc (GMEM_MOVEABLE, (DWORD) size))
            == NULL)
        goto errRtn;

    if ((lphostNames = (LPHOSTNAMES)GlobalLock (hhostNames)) == NULL)
        goto errRtn;

    lphostNames->clientNameOffset = 0;
    lphostNames->documentNameOffset = cbClient;

    lpdata = (LPSTR)lphostNames->data;
    lstrcpy (lpdata, lpclientName);
    lstrcpy (lpdata + cbClient, lpdocName);
    if (lpobj->hhostNames)
        GlobalFree ( lpobj->hhostNames);
    GlobalUnlock (hhostNames);
    lpobj->hhostNames = hhostNames;
    return OLE_OK;

errRtn:
    if (lphostNames)
        GlobalUnlock (hhostNames);

    if (hhostNames)
        GlobalFree (hhostNames);

    return  OLE_ERROR_MEMORY;
}


#if 0
OLESTATUS  FARINTERNAL LeAbort (lpobj)
LPOBJECT_LE lpobj;
{


    BOOL        bAbort = FALSE;
    PEDIT_DDE   pedit;


    // check whether the any transaction pending for
    // the document level.

    //  channel open
    //  any transaction pending.
    //  and we are not in terminate mode.


    if ((pedit = lpobj->pDocEdit)  &&   pedit->hServer &&
        pedit->awaitAck && !pedit->bTerminating) {
        pedit->bAbort = bAbort = TRUE;
        // delete any data we need to delete. Ricght now
        // we kill only the timer. We can not delete any
        // since the server could potentially look at the data.

        DeleteAbortData (lpobj, pedit);
    }

    if ((pedit = lpobj->pSysEdit)  &&   pedit->hServer &&
        pedit->awaitAck && !pedit->bTerminating) {
        pedit->bAbort = bAbort = TRUE;
        DeleteAbortData (lpobj, pedit);

    }

    if (!bAbort)
        return OLE_OK;

    // Now send the EndAsync
    lpobj->mainErr = OLE_ERROR_ABORT;
    EndAsyncCmd (lpobj);
    return OLE_OK;

}
#endif


OLESTATUS  FARINTERNAL ProbeAsync(lpobj)
LPOBJECT_LE lpobj;
{

    if (lpobj->asyncCmd == OLE_NONE)
        return OLE_OK;

    if (!IsServerValid (lpobj)) {

        // Now send the EndAsync
        lpobj->mainErr = OLE_ERROR_TASK;
        EndAsyncCmd (lpobj);
        return OLE_OK;
    }

    return OLE_BUSY;
}


BOOL    INTERNAL IsWindowValid (hwnd)
HWND    hwnd;
{

#define TASK_OFFSET 0x00FA

    LPSTR   lptask;
    HANDLE  htask;

    if (!IsWindow (hwnd))
        return FALSE;

    if (bWLO)
        return TRUE;
    
    // now get the task handle and find out it is valid.
    htask  = GetWindowTask (hwnd);

    if ((wWinVer == 0x0003) || !lpfnIsTask) {
        lptask = (LPSTR)(MAKELONG (TASK_OFFSET, htask));

        if (!FarCheckPointer(lptask, READ_ACCESS))
            return FALSE;

        // now check for the signature bytes of task block in kernel
        if (*lptask++ == 'T' && *lptask == 'D')
            return TRUE;
    }
    else {
        // From win31 onwards the API IsTask can be used for task validation
        if ((*lpfnIsTask)(htask))
            return TRUE;
    }

    return FALSE;
}



BOOL    INTERNAL IsServerValid (lpobj)
LPOBJECT_LE     lpobj;
{

    MSG msg;
    BOOL    retval = FALSE;


    if (lpobj->pDocEdit && lpobj->pDocEdit->hServer) {

        retval = TRUE;

        if (!IsWindowValid (lpobj->pDocEdit->hServer)) {
            if (!PeekMessage ((LPMSG)&msg, lpobj->pDocEdit->hClient, WM_DDE_TERMINATE, WM_DDE_TERMINATE,
                            PM_NOREMOVE | PM_NOYIELD)){
#ifdef  FIREWALLS
                ASSERT (FALSE, "Server truely died");
#endif
                return FALSE;
            }

        }

    }

    if (lpobj->pSysEdit && lpobj->pSysEdit->hServer) {
        retval = TRUE;

        if (!IsWindowValid (lpobj->pSysEdit->hServer)) {

            if (!PeekMessage ((LPMSG)&msg, lpobj->pSysEdit->hClient, WM_DDE_TERMINATE, WM_DDE_TERMINATE,
                                PM_NOREMOVE | PM_NOYIELD)){
#ifdef  FIREWALLS
                ASSERT (FALSE, "Server truely died");
#endif
                return FALSE;

            }


        }
    }

   return retval;
}


OLESTATUS FARINTERNAL LeExecute (lpobj, hCmds, wReserve)
LPOBJECT_LE lpobj;
HANDLE      hCmds;
WORD        wReserve;
{
    // Assumes all the creates are in order
    PROBE_CREATE_ASYNC(lpobj);
    PROBE_SVRCLOSING(lpobj);
    
    if (!(lpobj =  (*lpobj->head.lpvtbl->QueryProtocol) (lpobj, 
                                            PROTOCOL_EXECUTE)))
        return OLE_ERROR_PROTOCOL;

    if (!QueryOpen (lpobj))
        return OLE_ERROR_NOT_OPEN;
    
    if (!(hCmds = DuplicateGlobal (hCmds, GMEM_MOVEABLE|GMEM_DDESHARE)))
        return OLE_ERROR_MEMORY;
        
    InitAsyncCmd (lpobj, OLE_OTHER, NULL);
    SETERRHINT(lpobj, OLE_ERROR_COMMAND);
    if (DocExecute(lpobj, hCmds))
        return OLE_WAIT_FOR_RELEASE;
    else
        return OLE_ERROR_COMMAND;
}


void INTERNAL FreeGDIdata (hData, cfFormat)
HANDLE          hData;
OLECLIPFORMAT   cfFormat;
{
    if (cfFormat == CF_METAFILEPICT) {
        LPMETAFILEPICT  lpMfp;
        
        if (lpMfp = (LPMETAFILEPICT) GlobalLock (hData)) {
            GlobalUnlock (hData);
            DeleteMetaFile (lpMfp->hMF);
        }

        GlobalFree (hData);
    }
    
    else if (cfFormat == CF_BITMAP) 
        DeleteObject (hData);
    
    else if (cfFormat == CF_DIB)
        GlobalFree (hData);
}


// This routine figures out whether the handle to data block can be copied
// to DDEPOKE block rather than the contents of the handle

BOOL INTERNAL CanPutHandleInPokeBlock (lpobj, cfFormat)
LPOBJECT_LE     lpobj;
OLECLIPFORMAT   cfFormat;
{
    if (cfFormat == CF_BITMAP || cfFormat == CF_DIB)
        return TRUE;

    if (cfFormat == CF_METAFILEPICT) {
        // The old version of MSDraw expects the contents of METAFILEPICT
        // structure to be part of DDEPOKE, rather than the handle to it.

        if (!lpobj->bOleServer && lpobj->app == aMSDraw)
            return FALSE;
        
        return TRUE;
    }
    
    return FALSE;
}