/****************************** Module Header ******************************\
* Module Name: Pbhandlr.C -- Native data based handler (for Pbrush server) 
*
* PURPOSE: Contains handler routines for Pbrush server. This handler makes
*   use of most of the standard library methods. It replaces only the "Draw",
*   "QueryBounds", "CopyToClipboard" methods of the OLE object. Note that this
*   handler draws the picture from the native data.
*
* Created: December 1990
*
* Copyright (c) 1990  Microsoft Corporation
*
* History:
*   SriniK  (../12/1990)    Original
*
\***************************************************************************/

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


OLESTATUS FAR PASCAL _loadds PbDraw (LPOLEOBJECT, HDC, LPRECT, LPRECT, HDC);
OLESTATUS FAR PASCAL _loadds PbQueryBounds (LPOLEOBJECT, LPRECT);
OLESTATUS FAR PASCAL _loadds PbCopyToClipboard (LPOLEOBJECT);
OLESTATUS FAR PASCAL _loadds PbGetData (LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR *);
OLECLIPFORMAT FAR PASCAL _loadds PbEnumFormats (LPOLEOBJECT, OLECLIPFORMAT);

extern OLESTATUS  FARINTERNAL wDibDraw (HANDLE, HDC, LPRECT, LPRECT, HDC, BOOL);


void    PbGetExtents (LPSTR, LPPOINT);
void    PbReplaceFunctions (LPOLEOBJECT);
HANDLE  PbGetPicture (LPOLEOBJECT);
BOOL    IsStandardPict (LPOLEOBJECT);

extern void FARINTERNAL DibGetExtents(LPSTR, LPPOINT);

OLEOBJECTVTBL   vtblDLL;

extern  OLECLIPFORMAT   cfOwnerLink;
extern  OLECLIPFORMAT   cfObjectLink;
extern  OLECLIPFORMAT   cfNative;

OLESTATUS (FAR PASCAL *DefQueryBounds)      (LPVOID, LPRECT);
OLESTATUS (FAR PASCAL *DefDraw)             (LPVOID, HDC, LPRECT, LPRECT, HDC);
OLESTATUS (FAR PASCAL *DefCopyToClipboard)  (LPVOID);
OLECLIPFORMAT (FAR PASCAL *DefEnumFormats)  (LPVOID, OLECLIPFORMAT);
OLESTATUS (FAR PASCAL *DefGetData)          (LPVOID, OLECLIPFORMAT, HANDLE FAR *);


OLESTATUS FAR PASCAL PbLoadFromStream (lpstream, lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, objType, aClass, cfFormat)
LPOLESTREAM         lpstream;
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
LONG                objType;
ATOM                aClass;
OLECLIPFORMAT       cfFormat;
{
    OLESTATUS   retVal;
    
    if (objType == OT_LINK) 
        retVal = DefLoadFromStream (lpstream, lpprotocol, lpclient, 
                        lhclientdoc, lpobjname, lplpobj, 
                        objType, aClass, cfNative);
    else
        retVal = DefLoadFromStream (lpstream, lpprotocol, lpclient, 
                        lhclientdoc, lpobjname, lplpobj, 
                        objType, aClass, cfFormat);
                    
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);

    return retVal;
}



OLESTATUS FAR PASCAL PbCreateFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, objType)
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
LONG                objType;
{
    OLESTATUS   retVal;
    
    if ((optRender == olerender_draw) 
            && (IsClipboardFormatAvailable (cfNative))) {       
        if (objType == OT_EMBEDDED) 
            retVal =  DefCreateFromClip (lpprotocol, lpclient, 
                                lhclientdoc, lpobjname, lplpobj, 
                                olerender_none, NULL, objType);
        else
            retVal =  DefCreateFromClip (lpprotocol, lpclient, 
                                lhclientdoc, lpobjname, lplpobj, 
                                olerender_format, cfNative, objType);
    }
    else {
        retVal = DefCreateFromClip (lpprotocol, lpclient, 
                            lhclientdoc, lpobjname, lplpobj, 
                            optRender, cfFormat, objType);
    }
    
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);
        
    return retVal;
}



OLESTATUS FAR PASCAL PbCreateLinkFromClip (lpprotocol, lpclient, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
{
    OLESTATUS       retVal;

    if ((optRender == olerender_draw) 
            && (IsClipboardFormatAvailable (cfNative))) {
        retVal =  DefCreateLinkFromClip (lpprotocol, lpclient, 
                            lhclientdoc, lpobjname, lplpobj, 
                            olerender_format, cfNative);
    }
    else {
        retVal =  DefCreateLinkFromClip (lpprotocol, lpclient, 
                            lhclientdoc, lpobjname, lplpobj, 
                            optRender, cfFormat);       
    }
    
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);

    return retVal;
}



OLESTATUS FAR PASCAL PbCreateFromTemplate (lpprotocol, lpclient, lptemplate, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LPSTR               lptemplate;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
{
    OLESTATUS   retVal;
    
    if (optRender == olerender_draw) 
        retVal =  DefCreateFromTemplate (lpprotocol, lpclient, lptemplate, 
                            lhclientdoc, lpobjname, lplpobj, 
                            olerender_none, NULL);

    else 
        retVal = DefCreateFromTemplate (lpprotocol, lpclient, lptemplate, 
                            lhclientdoc, lpobjname, lplpobj, 
                            optRender, cfFormat);
                        
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);

    return retVal;                          
}



OLESTATUS FAR PASCAL PbCreate (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LPSTR               lpclass;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
{
    OLESTATUS   retVal;
    
    if (optRender == olerender_draw)
        retVal = DefCreate (lpprotocol, lpclient, lpclass, 
                        lhclientdoc, lpobjname, lplpobj, 
                        olerender_none, NULL);
    else 
        retVal = DefCreate (lpprotocol, lpclient, lpclass, 
                        lhclientdoc, lpobjname, lplpobj, 
                        optRender, cfFormat);
                    
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);

    return retVal;
}



OLESTATUS FAR PASCAL PbCreateFromFile (lpprotocol, lpclient, lpclass, lpfile, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LPSTR               lpclass;
LPSTR               lpfile;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
{
    OLESTATUS   retVal;
    
    if (optRender == olerender_draw) 
        retVal =  DefCreateFromFile (lpprotocol, lpclient, lpclass, lpfile, 
                            lhclientdoc, lpobjname, lplpobj, 
                            olerender_none, NULL);

    else 
        retVal = DefCreateFromFile (lpprotocol, lpclient, lpclass, lpfile, 
                            lhclientdoc, lpobjname, lplpobj, 
                            optRender, cfFormat);
                        
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);

    return retVal;                          
}


OLESTATUS FAR PASCAL PbCreateLinkFromFile (lpprotocol, lpclient, lpclass, lpfile, lpitem, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat)
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LPSTR               lpclass;
LPSTR               lpfile;
LPSTR               lpitem;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
{
    OLESTATUS   retVal;
    
    if (optRender == olerender_draw) 
        retVal =  DefCreateLinkFromFile (lpprotocol, lpclient, 
                            lpclass, lpfile, lpitem,
                            lhclientdoc, lpobjname, lplpobj, 
                            olerender_format, cfNative);

    else 
        retVal = DefCreateLinkFromFile (lpprotocol, lpclient, 
                            lpclass, lpfile, lpitem,
                            lhclientdoc, lpobjname, lplpobj, 
                            optRender, cfFormat);
                        
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);

    return retVal;                          
}



OLESTATUS FAR PASCAL PbCreateInvisible (lpprotocol, lpclient, lpclass, lhclientdoc, lpobjname, lplpobj, optRender, cfFormat, fActivate)
LPSTR               lpprotocol;
LPOLECLIENT         lpclient;
LPSTR               lpclass;
LHCLIENTDOC         lhclientdoc;
LPSTR               lpobjname;
LPOLEOBJECT FAR *   lplpobj;
OLEOPT_RENDER       optRender;
OLECLIPFORMAT       cfFormat;
BOOL                fActivate;
{
    OLESTATUS   retVal;
    
    if (optRender == olerender_draw)
        retVal = DefCreateInvisible (lpprotocol, lpclient, lpclass, 
                        lhclientdoc, lpobjname, lplpobj, 
                        olerender_none, NULL, fActivate);
    else 
        retVal = DefCreateInvisible (lpprotocol, lpclient, lpclass, 
                        lhclientdoc, lpobjname, lplpobj, 
                        optRender, cfFormat, fActivate);
                    
    if (retVal <= OLE_WAIT_FOR_RELEASE)
        PbReplaceFunctions (*lplpobj);

    return retVal;
}


void PbReplaceFunctions (lpobj)
LPOLEOBJECT lpobj;
{
    if (IsStandardPict (lpobj))
        return;
    
    vtblDLL = *lpobj->lpvtbl;
    lpobj->lpvtbl = (LPOLEOBJECTVTBL) &vtblDLL;
    
    DefDraw                         = lpobj->lpvtbl->Draw;
    DefQueryBounds                  = lpobj->lpvtbl->QueryBounds;
    DefCopyToClipboard              = lpobj->lpvtbl->CopyToClipboard;
    DefEnumFormats                  = lpobj->lpvtbl->EnumFormats;
    DefGetData                      = lpobj->lpvtbl->GetData;   
    
    lpobj->lpvtbl->Draw             = PbDraw;
    lpobj->lpvtbl->QueryBounds      = PbQueryBounds;
    lpobj->lpvtbl->CopyToClipboard  = PbCopyToClipboard;
    lpobj->lpvtbl->EnumFormats      = PbEnumFormats;    
    lpobj->lpvtbl->GetData          = PbGetData;        
}



OLESTATUS  FAR PASCAL _loadds PbQueryBounds (lpobj, lprc)
LPOLEOBJECT lpobj;
LPRECT      lprc;
{
    OLESTATUS   retVal;
    HANDLE      hData;
    LPSTR       lpData;
    POINT       point;

    if ((retVal = (*DefQueryBounds) (lpobj, lprc)) == OLE_OK) {
        if (lprc->top || lprc->bottom || lprc->right || lprc->left)
            return OLE_OK;
    }
    
    if ((*DefGetData) (lpobj, cfNative, &hData) != OLE_OK)
        return retVal;

    if (!hData)
        return OLE_ERROR_BLANK;     
            
    if (!(lpData = GlobalLock (hData)))
        return OLE_ERROR_MEMORY;

    DibGetExtents ((lpData+sizeof(BITMAPFILEHEADER)), &point);
    GlobalUnlock (hData);    
    
    lprc->left     = 0;
    lprc->top      = 0;
    lprc->right    = point.x;
    lprc->bottom   = point.y;
    
    return OLE_OK;      
}


OLESTATUS  FAR PASCAL _loadds PbDraw (lpobj, hdc, lprc, lpWrc, hdcTarget)
LPOLEOBJECT     lpobj;
HDC             hdc;
LPRECT          lprc;
LPRECT          lpWrc;
HDC             hdcTarget;
{
    HANDLE  hData;
    
    if ((*DefGetData) (lpobj, cfNative, &hData) != OLE_OK)
        return (*DefDraw) (lpobj, hdc, lprc, lpWrc, hdcTarget);

    return wDibDraw (hData, hdc, lprc, lpWrc, hdcTarget, TRUE);
}


OLECLIPFORMAT FAR PASCAL _loadds PbEnumFormats (lpobj, cfFormat)
LPOLEOBJECT     lpobj;
OLECLIPFORMAT   cfFormat;
{
    OLECLIPFORMAT   retFormat = NULL;

    if (cfFormat == CF_METAFILEPICT)
        return NULL;
    
    if (!(retFormat =  (*DefEnumFormats) (lpobj, cfFormat))) 
        return CF_METAFILEPICT;
    
    return retFormat;
}


OLESTATUS  FAR PASCAL _loadds PbGetData (lpobj, cfFormat, lpHandle)
LPOLEOBJECT     lpobj;
OLECLIPFORMAT   cfFormat;
HANDLE FAR *    lpHandle;
{
    OLESTATUS retval;
    
    retval = (*DefGetData) (lpobj, cfFormat, lpHandle);

    if (retval == OLE_OK || retval == OLE_BUSY || retval  == OLE_ERROR_BLANK)
        return retval;
    
    if (cfFormat == CF_METAFILEPICT) {
        if (*lpHandle = PbGetPicture (lpobj))
            return OLE_WARN_DELETE_DATA;
        
        return OLE_ERROR_MEMORY;
    }

    return OLE_ERROR_FORMAT;
}



OLESTATUS  FAR PASCAL _loadds PbCopyToClipboard (lpobj)
LPOLEOBJECT     lpobj;
{
    OLESTATUS   retVal;
    HANDLE      hPict;
    
    if ((retVal = (*DefCopyToClipboard) (lpobj)) == OLE_OK) {
        if (hPict = PbGetPicture (lpobj))
            SetClipboardData (CF_METAFILEPICT, hPict);        
        else
            retVal = OLE_ERROR_MEMORY;
    }
    
    return retVal;
}

HANDLE PbGetPicture (lpobj)
LPOLEOBJECT lpobj;
{
    HANDLE          hMF, hMfp, hData;
    RECT            rc = {0, 0, 0, 0};
    POINT           point;
    HDC             hMetaDC;
    LPMETAFILEPICT  lpmfp;
    OLESTATUS       retVal;
    LPSTR           lpData;
    
    if ((*DefGetData) (lpobj, cfNative, &hData) != OLE_OK)
        return NULL;
    
    if (!hData)
        return NULL;
            
    if (!(lpData = GlobalLock (hData)))
        return NULL;

    lpData += sizeof(BITMAPFILEHEADER);
    rc.right  = (int) ((LPBITMAPINFOHEADER)lpData)->biWidth;
    rc.bottom = (int) ((LPBITMAPINFOHEADER)lpData)->biHeight;
    DibGetExtents(lpData, &point);
    GlobalUnlock (hData);    
    
    if (!(hMetaDC = CreateMetaFile (NULL)))
        return NULL;
    
    SetWindowOrg (hMetaDC, 0, 0);
    SetWindowExt (hMetaDC, rc.right, rc.bottom);
    retVal = PbDraw (lpobj, hMetaDC, &rc, NULL, NULL);
    hMF = CloseMetaFile (hMetaDC);

    if (retVal != OLE_OK) 
        goto error;

    if (hMF && (hMfp = GlobalAlloc (GMEM_MOVEABLE, sizeof(METAFILEPICT)))
            && (lpmfp = (LPMETAFILEPICT) GlobalLock (hMfp))) {
        lpmfp->hMF = hMF;
        lpmfp->xExt = point.x;
        lpmfp->yExt = -point.y;
        lpmfp->mm   = MM_ANISOTROPIC;
        GlobalUnlock (hMfp);
        return hMfp;
    }

error:  

    if (hMF)
        DeleteMetaFile (hMF);
    
    if (hMfp)
        GlobalFree (hMfp);

    return NULL;
}


// normal handler can't do this. since this handler is part of olecli.dll, we
// we are doing this.

BOOL IsStandardPict (lpobj)
LPOLEOBJECT lpobj;
{
    LPOBJECT_LE lpLEobj;
    LONG        type;
    
    lpLEobj = (LPOBJECT_LE) lpobj;
    if (!lpLEobj->lpobjPict)
        return FALSE;
    
    if ((*lpLEobj->lpobjPict->lpvtbl->QueryType) (lpLEobj->lpobjPict, &type)
            == OLE_ERROR_GENERIC)
        return FALSE;
    
    return TRUE;
}