/****************************** 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
*   curts created portable version for WIN16/32
*
\***************************************************************************/

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


OLESTATUS FAR PASCAL _LOADDS PbDraw (LPOLEOBJECT, HDC, OLE_CONST RECT FAR*, OLE_CONST RECT FAR*, 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)      (LPOLEOBJECT, LPRECT);
OLESTATUS (FAR PASCAL *DefDraw)             (LPOLEOBJECT, HDC, LPRECT, LPRECT, HDC);
OLESTATUS (FAR PASCAL *DefCopyToClipboard)  (LPOLEOBJECT);
OLECLIPFORMAT (FAR PASCAL *DefEnumFormats)  (LPOLEOBJECT, OLECLIPFORMAT);
OLESTATUS (FAR PASCAL *DefGetData)          (LPOLEOBJECT, OLECLIPFORMAT, HANDLE FAR *);


OLESTATUS FAR PASCAL PbLoadFromStream (
    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 (
    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, 0, 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 (
    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 (
    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, 0);

    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 (
    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, 0);
    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 (
    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, 0);

    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 (
    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 (
    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, 0, 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 (
    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 (
    LPOLEOBJECT lpobj,
    LPRECT      lprc
){
    OLESTATUS     retVal;
    HANDLE        hData = NULL;
    LPSTR         lpData;
    POINT         point;
	 HANDLE        hbminfo = NULL;
	 LPBITMAPINFO  lpbminfo;

    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)))
		  goto error;
	 
	 if (!(hbminfo = GlobalAlloc(GHND, sizeof(BITMAPINFO))) )
		  goto error;

	 if (!(lpbminfo = (LPBITMAPINFO)GlobalLock(hbminfo)) )
		  goto error;
	 
    memcpy((LPSTR)lpbminfo, (LPSTR)(lpData+sizeof(BITMAPFILEHEADER)), sizeof(BITMAPINFO));
	 
    DibGetExtents ((LPSTR)lpbminfo, &point);
	 
    GlobalUnlock (hData);
	 GlobalUnlock (hbminfo);
	 GlobalFree (hbminfo);
    
    lprc->left     = 0;
    lprc->top      = 0;
    lprc->right    = point.x;
    lprc->bottom   = point.y;
    
    return OLE_OK;

error:

    if (hData)
       GlobalUnlock (hData);
	 
	 if (hbminfo)
	 {   
		 GlobalUnlock (hbminfo);
	    GlobalFree (hbminfo);
	 }   

	 return OLE_ERROR_MEMORY;
	 
}


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

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


OLECLIPFORMAT FAR PASCAL _LOADDS PbEnumFormats (
    LPOLEOBJECT     lpobj,
    OLECLIPFORMAT   cfFormat
){
    OLECLIPFORMAT   retFormat = 0;

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


OLESTATUS  FAR PASCAL _LOADDS PbGetData (
    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 (
    LPOLEOBJECT     lpobj
){
    OLESTATUS   retVal;
    HANDLE      hPict; 
    
    if ((retVal = (*DefCopyToClipboard) (lpobj)) == OLE_OK) {
        if (hPict = PbGetPicture (lpobj))
            SetClipboardData (CF_METAFILEPICT, hPict);
        else
            return OLE_ERROR_MEMORY;         
    }
    
    return retVal;
}

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

	 if (!(lpbminfo = (LPBITMAPINFO)GlobalLock(hbminfo)) )
		  goto memory_error;
	 
    memcpy((LPSTR)lpbminfo, (LPSTR)(lpData+sizeof(BITMAPFILEHEADER)), sizeof(BITMAPINFO));

    rc.right  = (int) lpbminfo->bmiHeader.biWidth;
    rc.bottom = (int) lpbminfo->bmiHeader.biHeight;
    DibGetExtents((LPSTR)lpbminfo, &point);
	 
    GlobalUnlock (hData);
	 GlobalUnlock (hbminfo);
	 GlobalFree (hbminfo);
	
    if (!(hMetaDC = CreateMetaFile (NULL)))
        return NULL;
    
    MSetWindowOrg (hMetaDC, 0, 0);
    MSetWindowExt (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;

memory_error:

	 GlobalUnlock(hData);

	 if (hbminfo)
	 {   
	    GlobalUnlock(hbminfo);
		 GlobalFree(hbminfo);
	 }
 
	 return(NULL);
	 
}


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

BOOL IsStandardPict (
    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;
}