mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1187 lines
30 KiB
1187 lines
30 KiB
/*
|
|
OLE SERVER DEMO
|
|
Obj.c
|
|
|
|
This file contains object methods and various object-related support
|
|
functions.
|
|
|
|
(c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
|
|
*/
|
|
|
|
/*
|
|
Important Note:
|
|
|
|
No method should ever dispatch a DDE message or allow a DDE message to
|
|
be dispatched.
|
|
Therefore, no method should ever enter a message dispatch loop.
|
|
Also, a method should not show a dialog or message box, because the
|
|
processing of the dialog box messages will allow DDE messages to be
|
|
dispatched.
|
|
*/
|
|
|
|
|
|
#define SERVERONLY
|
|
#include <windows.h>
|
|
#include <ole.h>
|
|
|
|
#include "srvrdemo.h"
|
|
|
|
|
|
|
|
// Static functions.
|
|
static HBITMAP GetBitmap (LPOBJ lpobj);
|
|
static HANDLE GetLink (LPOBJ lpobj);
|
|
static HANDLE GetMetafilePict (LPOBJ lpobj);
|
|
static HANDLE GetEnhMetafile (LPOBJ lpobj);
|
|
static HANDLE GetNative (LPOBJ lpobj);
|
|
static INT GetObjNum (LPOBJ lpobj);
|
|
static HANDLE GetText (LPOBJ lpobj);
|
|
static VOID DrawObj (HDC hdc, LPOBJ lpobj, RECT rc, INT dctype);
|
|
|
|
|
|
|
|
/* CreateNewObj
|
|
* ------------
|
|
*
|
|
* BOOL fDoc_Changed - The new value for the global variable fDocChanged.
|
|
* When initializing a new document, we need to create
|
|
* a new object without the creation counting as a
|
|
* change to the document.
|
|
*
|
|
* RETURNS: A pointer to the new object
|
|
*
|
|
*
|
|
* CUSTOMIZATION: Re-implement
|
|
* Some applications (like Server Demo) have a finite number of
|
|
* fixed, distinct, non-overlapping objects. Other applications
|
|
* allow the user to create an object from any section of the
|
|
* document. For example, the user might select a portion of
|
|
* a bitmap from a paint program, or a few lines of text from
|
|
* a word processor. This latter type of application probably
|
|
* will not have a function like CreateNewObj.
|
|
*
|
|
*/
|
|
LPOBJ CreateNewObj (BOOL fDoc_Changed)
|
|
{
|
|
HANDLE hObj = NULL;
|
|
LPOBJ lpobj = NULL;
|
|
// index into an array of flags indicating if that object number is used.
|
|
INT ifObj = 0;
|
|
|
|
if ((hObj = LocalAlloc (LMEM_MOVEABLE|LMEM_ZEROINIT, sizeof (OBJ))) == NULL)
|
|
return NULL;
|
|
|
|
if ((lpobj = (LPOBJ) LocalLock (hObj)) == NULL)
|
|
{
|
|
LocalFree (hObj);
|
|
return NULL;
|
|
}
|
|
|
|
// Fill the fields in the object structure.
|
|
|
|
// Find an unused number.
|
|
for (ifObj=1; ifObj <= cfObjNums; ifObj++)
|
|
{
|
|
if (docMain.rgfObjNums[ifObj]==FALSE)
|
|
{
|
|
docMain.rgfObjNums[ifObj]=TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ifObj==cfObjNums+1)
|
|
{
|
|
// Cannot create any more objects.
|
|
MessageBeep(0);
|
|
return NULL;
|
|
}
|
|
|
|
wsprintf (lpobj->native.szName, "Object %d", ifObj);
|
|
|
|
lpobj->aName = GlobalAddAtom (lpobj->native.szName);
|
|
lpobj->hObj = hObj;
|
|
lpobj->oleobject.lpvtbl = &objvtbl;
|
|
lpobj->native.idmColor = IDM_RED; // Default color
|
|
lpobj->native.version = version;
|
|
lpobj->native.nWidth = OBJECT_WIDTH; // Default size
|
|
lpobj->native.nHeight = OBJECT_HEIGHT;
|
|
SetHiMetricFields (lpobj);
|
|
|
|
// Place object in a location corrsponding to its number, for aesthetics.
|
|
lpobj->native.nX = (ifObj - 1) * 20;
|
|
lpobj->native.nY = (ifObj - 1) * 20;
|
|
|
|
if (!CreateWindow (
|
|
"ObjClass",
|
|
"Obj",
|
|
WS_BORDER | WS_THICKFRAME | WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
|
|
lpobj->native.nX,
|
|
lpobj->native.nY,
|
|
lpobj->native.nWidth,
|
|
lpobj->native.nHeight,
|
|
hwndMain,
|
|
NULL,
|
|
hInst,
|
|
(LPSTR) lpobj ))
|
|
return FALSE;
|
|
|
|
fDocChanged = fDoc_Changed;
|
|
|
|
return lpobj;
|
|
}
|
|
|
|
|
|
|
|
/* CutOrCopyObj
|
|
* ------------
|
|
*
|
|
* Put data onto clipboard in all the formats supported. If the
|
|
* fOpIsCopy is TRUE, the operation is COPY, otherwise it is CUT.
|
|
* This is important, because we cannot put the Object Link format
|
|
* onto the clipboard if the object was cut from the document (there is
|
|
* no longer anything to link to).
|
|
*
|
|
* BOOL fOpIsCopy - TRUE if the operation is COPY; FALSE if CUT
|
|
*
|
|
* CUSTOMIZATION: None
|
|
*
|
|
*
|
|
*/
|
|
VOID CutOrCopyObj (BOOL fOpIsCopy)
|
|
{
|
|
LPOBJ lpobj;
|
|
HANDLE hData;
|
|
// UINT hBit;
|
|
|
|
if (OpenClipboard (hwndMain))
|
|
{
|
|
EmptyClipboard ();
|
|
|
|
lpobj = SelectedObject();
|
|
|
|
if ((hData = GetNative (lpobj)) != NULL)
|
|
SetClipboardData(cfNative, hData);
|
|
|
|
if ((hData = GetLink(lpobj)) != NULL)
|
|
SetClipboardData(cfOwnerLink, hData);
|
|
|
|
if (fOpIsCopy && docMain.doctype == doctypeFromFile)
|
|
{
|
|
// Can create a link if object exists in a file.
|
|
if ((hData = GetLink(lpobj)) != NULL)
|
|
SetClipboardData(cfObjectLink, hData);
|
|
}
|
|
|
|
if ((hData = GetEnhMetafile(lpobj)) != NULL)
|
|
{
|
|
SetClipboardData(CF_ENHMETAFILE, hData);
|
|
GlobalFree(hData);
|
|
}
|
|
|
|
if ((hData = GetBitmap(lpobj)) != NULL)
|
|
{
|
|
// SetClipboardData(CF_BITMAP, GetBitmap(lpobj));
|
|
SetClipboardData(CF_BITMAP, hData);
|
|
DeleteObject(hData);
|
|
}
|
|
|
|
|
|
CloseClipboard ();
|
|
}
|
|
}
|
|
|
|
|
|
/* DestroyObj
|
|
* ----------
|
|
*
|
|
* Revoke an object, and free all memory that had been allocated for it.
|
|
*
|
|
* HWND hwnd - The object's window
|
|
*
|
|
* CUSTOMIZATION: Re-implement, making sure you free all the memory that
|
|
* had been allocated for the OBJ structure and each of its
|
|
* fields.
|
|
*
|
|
*/
|
|
VOID DestroyObj (HWND hwnd)
|
|
{
|
|
LPOBJ lpobj = HwndToLpobj (hwnd);
|
|
|
|
if(lpobj->aName)
|
|
{
|
|
GlobalDeleteAtom (lpobj->aName);
|
|
lpobj->aName = '\0';
|
|
}
|
|
|
|
if (lpobj->hpal)
|
|
DeleteObject (lpobj->hpal);
|
|
// Allow the object's number to be reused.
|
|
docMain.rgfObjNums [GetObjNum(lpobj)] = FALSE;
|
|
|
|
|
|
// Free the memory that had been allocated for the object structure itself.
|
|
LocalUnlock (lpobj->hObj);
|
|
LocalFree (lpobj->hObj);
|
|
}
|
|
|
|
|
|
|
|
/* DrawObj
|
|
* -------
|
|
*
|
|
* This function draws an object onto the screen, into a metafile, or into
|
|
* a bitmap.
|
|
* The object will always look the same.
|
|
*
|
|
* HDC hdc - The device context to render the object into
|
|
* LPOBJ lpobj - The object to render
|
|
* RECT rc - The rectangle bounds of the object
|
|
* DCTYPE dctype - The type of device context.
|
|
*
|
|
* CUSTOMIZATION: Server Demo specific
|
|
*
|
|
*/
|
|
static VOID DrawObj (HDC hdc, LPOBJ lpobj, RECT rc, INT dctype)
|
|
{
|
|
HPEN hpen;
|
|
HPEN hpenOld;
|
|
HPALETTE hpalOld = NULL;
|
|
|
|
|
|
if (dctype == dctypeMetafile)
|
|
{
|
|
SetWindowOrgEx (hdc, 0, 0, NULL);
|
|
// Paint entire object into the given rectangle.
|
|
SetWindowExtEx (hdc, rc.right, rc.bottom, NULL);
|
|
}
|
|
|
|
if (lpobj->hpal)
|
|
{
|
|
hpalOld = SelectPalette (hdc, lpobj->hpal, TRUE);
|
|
RealizePalette (hdc);
|
|
}
|
|
|
|
// Select brush of the color specified in the native data.
|
|
SelectObject (hdc, hbrColor [lpobj->native.idmColor - IDM_RED] );
|
|
|
|
hpen = CreatePen (PS_SOLID,
|
|
/* Width */ (rc.bottom-rc.top) / 10,
|
|
/* Gray */ 0x00808080);
|
|
hpenOld = SelectObject (hdc, hpen);
|
|
|
|
// Draw rectangle with the gray pen and fill it in with the selected brush.
|
|
Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
|
|
|
|
// Print name of object inside rectangle.
|
|
SetBkMode (hdc, TRANSPARENT);
|
|
SetTextAlign (hdc, TA_BASELINE | TA_CENTER);
|
|
TextOut (hdc,
|
|
rc.right/2,
|
|
(rc.top+rc.bottom)/2,
|
|
lpobj->native.szName,
|
|
lstrlen (lpobj->native.szName));
|
|
|
|
// Restore original objects
|
|
SelectObject (hdc,
|
|
(dctype == dctypeMetafile || dctype == dctypeEnhMetafile)
|
|
? GetStockObject (BLACK_PEN) : hpenOld);
|
|
if (hpalOld)
|
|
{
|
|
SelectPalette (hdc,
|
|
(dctype == dctypeMetafile || dctype == dctypeEnhMetafile)
|
|
? GetStockObject (DEFAULT_PALETTE) : hpalOld,
|
|
TRUE);
|
|
}
|
|
|
|
DeleteObject (hpen);
|
|
}
|
|
|
|
|
|
|
|
/* GetBitmap
|
|
* ---------
|
|
*
|
|
* Return a handle to an object's picture data in bitmap format.
|
|
*
|
|
* LPOBJ lpobj - The object
|
|
*
|
|
* RETURNS: A handle to the object's picture data
|
|
*
|
|
* CUSTOMIZATION: Re-implement
|
|
*
|
|
*/
|
|
static HBITMAP GetBitmap (LPOBJ lpobj)
|
|
{
|
|
HDC hdcObj;
|
|
HDC hdcMem;
|
|
RECT rc;
|
|
HBITMAP hbitmap;
|
|
HBITMAP hbitmapOld;
|
|
|
|
|
|
hdcObj = GetDC (lpobj->hwnd);
|
|
// Create a memory device context.
|
|
hdcMem = CreateCompatibleDC (hdcObj);
|
|
GetClientRect (lpobj->hwnd, (LPRECT)&rc);
|
|
// Create new bitmap object based on the bitmap of the OLE object.
|
|
hbitmap = CreateCompatibleBitmap
|
|
(hdcObj, rc.right - rc.left, rc.bottom - rc.top);
|
|
// Select new bitmap as the bitmap object for the memory device context.
|
|
hbitmapOld = SelectObject (hdcMem, hbitmap);
|
|
|
|
// Paint directly into the memory dc using the new bitmap object.
|
|
DrawObj (hdcMem, lpobj, rc, dctypeBitmap);
|
|
|
|
// Restore old bitmap object.
|
|
hbitmap = SelectObject (hdcMem, hbitmapOld);
|
|
DeleteDC (hdcMem);
|
|
ReleaseDC (lpobj->hwnd, hdcObj);
|
|
|
|
// convert width and height to HIMETRIC units
|
|
rc.right = rc.right - rc.left;
|
|
rc.bottom = rc.bottom - rc.top;
|
|
DeviceToHiMetric ( (LPPOINT) &rc.right );
|
|
|
|
// Set the 1/10 of HIMETRIC units for the bitmap
|
|
SetBitmapDimensionEx (hbitmap, (DWORD) (rc.right/10), (DWORD) (rc.bottom/10), NULL);
|
|
|
|
// if (OpenClipboard (hwndMain))
|
|
// {
|
|
// // EmptyClipboard ();
|
|
// SetClipboardData(CF_BITMAP, hbitmap);
|
|
// CloseClipboard();
|
|
// }
|
|
return hbitmap;
|
|
}
|
|
|
|
|
|
|
|
/* GetLink
|
|
* -------
|
|
*
|
|
* Return a handle to an object's object or owner link data.
|
|
* Link information is in the form of three zero-separated strings,
|
|
* terminated with two zero bytes: CLASSNAME\0DOCNAME\0OBJNAME\0\0
|
|
*
|
|
* LPOBJ lpobj - The object
|
|
*
|
|
* RETURNS: A handle to the object's link data
|
|
*
|
|
* CUSTOMIZATION: Re-implement
|
|
*
|
|
*/
|
|
static HANDLE GetLink (LPOBJ lpobj)
|
|
{
|
|
|
|
CHAR sz[cchFilenameMax];
|
|
LPSTR lpszLink = NULL;
|
|
HANDLE hLink = NULL;
|
|
INT cchLen;
|
|
INT i;
|
|
|
|
// First make the class name.
|
|
lstrcpy (sz, szClassName);
|
|
cchLen = lstrlen (sz) + 1;
|
|
|
|
// Then the document name.
|
|
cchLen += GlobalGetAtomName
|
|
(docMain.aName, (LPSTR)sz + cchLen,
|
|
cchFilenameMax - cchLen) + 1;
|
|
|
|
// Then the object name.
|
|
lstrcpy (sz + cchLen, lpobj->native.szName);
|
|
cchLen += lstrlen (lpobj->native.szName) + 1;
|
|
|
|
// Add a second null to the end.
|
|
sz[cchLen++] = 0;
|
|
|
|
|
|
hLink = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, cchLen);
|
|
if (hLink == NULL)
|
|
return NULL;
|
|
if ((lpszLink = GlobalLock (hLink)) == NULL)
|
|
{
|
|
GlobalFree (hLink);
|
|
return NULL;
|
|
}
|
|
|
|
for (i=0; i < cchLen; i++)
|
|
lpszLink[i] = sz[i];
|
|
|
|
GlobalUnlock (hLink);
|
|
|
|
return hLink;
|
|
}
|
|
|
|
|
|
|
|
/* GetMetafilePict
|
|
* ---------------
|
|
*
|
|
* Return a handle to an object's picture data in metafile format.
|
|
*
|
|
* LPOBJ lpobj - The object
|
|
*
|
|
* RETURNS: A handle to the object's data in metafile format.
|
|
*
|
|
* CUSTOMIZATION: Re-implement
|
|
*
|
|
*/
|
|
static HANDLE GetMetafilePict (LPOBJ lpobj)
|
|
{
|
|
|
|
LPMETAFILEPICT lppict = NULL;
|
|
HANDLE hpict = NULL;
|
|
HANDLE hMF = NULL;
|
|
RECT rc;
|
|
HDC hdc;
|
|
|
|
hdc = CreateMetaFile(NULL);
|
|
|
|
GetClientRect (lpobj->hwnd, (LPRECT)&rc);
|
|
|
|
// Paint directly into the metafile.
|
|
DrawObj (hdc, lpobj, rc, dctypeMetafile);
|
|
|
|
// Get handle to the metafile.
|
|
if ((hMF = CloseMetaFile (hdc)) == NULL)
|
|
return NULL;
|
|
|
|
if(!(hpict = GlobalAlloc (GMEM_DDESHARE, sizeof (METAFILEPICT))))
|
|
{
|
|
DeleteMetaFile (hMF);
|
|
return NULL;
|
|
}
|
|
|
|
if ((lppict = (LPMETAFILEPICT)GlobalLock (hpict)) == NULL)
|
|
{
|
|
DeleteMetaFile (hMF);
|
|
GlobalFree (hpict);
|
|
return NULL;
|
|
}
|
|
|
|
rc.right = rc.right - rc.left;
|
|
rc.bottom = rc.bottom - rc.top;
|
|
|
|
DeviceToHiMetric ( (LPPOINT) &rc.right);
|
|
|
|
lppict->mm = MM_ANISOTROPIC;
|
|
lppict->hMF = hMF;
|
|
lppict->xExt = rc.right;
|
|
lppict->yExt = rc.bottom;
|
|
GlobalUnlock (hpict);
|
|
return hpict;
|
|
}
|
|
|
|
/* GetEnhMetafile
|
|
* ---------------
|
|
*
|
|
* Return a handle to an object's picture data in metafile format.
|
|
*
|
|
* LPOBJ lpobj - The object
|
|
*
|
|
* RETURNS: A handle to the object's data in metafile format.
|
|
*
|
|
* CUSTOMIZATION: Re-implement
|
|
*
|
|
*/
|
|
static HANDLE GetEnhMetafile (LPOBJ lpobj)
|
|
{
|
|
|
|
LPMETAFILEPICT lppict = NULL;
|
|
HANDLE hemf = NULL;
|
|
HANDLE hMF = NULL;
|
|
RECT rc;
|
|
HDC hdc, hdc2;
|
|
|
|
|
|
GetClientRect (lpobj->hwnd, (LPRECT)&rc);
|
|
|
|
rc.right -= rc.left;
|
|
rc.bottom -= rc.top;
|
|
rc.left = rc.top = 0;
|
|
|
|
DeviceToHiMetric ( (LPPOINT) &rc.right );
|
|
|
|
hdc = CreateEnhMetaFile ( NULL, NULL, &rc, NULL );
|
|
|
|
//* this is necessary because
|
|
//* we need to draw the object
|
|
//* in device coordinates that are
|
|
//* the same physical size as the HIMETRIC
|
|
//* logical space used in CreateEnhMetaFile.
|
|
//* In this case we have scaled the HIMETRIC
|
|
//* units down in order to use the logical
|
|
//* pixel ratio (which is recommended UI)
|
|
//* so we therefore have to convert the
|
|
//* scaled HIMETRIC units back to Device.
|
|
|
|
hdc2 = GetDC(NULL);
|
|
|
|
SetMapMode(hdc2, MM_HIMETRIC);
|
|
LPtoDP (hdc2, (LPPOINT)&rc.right, 1);
|
|
if (rc.bottom < 0) rc.bottom *= -1;
|
|
|
|
ReleaseDC(NULL,hdc2);
|
|
|
|
DrawObj (hdc, lpobj, rc, dctypeMetafile);
|
|
|
|
if ((hemf = (HANDLE)CloseEnhMetaFile (hdc)) == NULL)
|
|
return NULL;
|
|
|
|
return hemf;
|
|
}
|
|
|
|
|
|
/* GetNative
|
|
* ---------
|
|
*
|
|
* Return a handle to an object's native data.
|
|
*
|
|
* LPOBJ lpobj - The object whose native data is to be retrieved.
|
|
*
|
|
* RETURNS: a handle to the object's native data.
|
|
*
|
|
* CUSTOMIZATION: The line "*lpnative = lpobj->native;" will change to
|
|
* whatever code is necessary to copy an object's native data.
|
|
*
|
|
*/
|
|
static HANDLE GetNative (LPOBJ lpobj)
|
|
{
|
|
LPNATIVE lpnative = NULL;
|
|
HANDLE hNative = NULL;
|
|
|
|
hNative = GlobalAlloc (GMEM_DDESHARE | GMEM_ZEROINIT, sizeof (NATIVE));
|
|
if (hNative == NULL)
|
|
return NULL;
|
|
if ((lpnative = (LPNATIVE) GlobalLock (hNative)) == NULL)
|
|
{
|
|
GlobalFree (hNative);
|
|
return NULL;
|
|
}
|
|
|
|
// Copy the native data.
|
|
*lpnative = lpobj->native;
|
|
|
|
GlobalUnlock (hNative);
|
|
return hNative;
|
|
}
|
|
|
|
|
|
|
|
/* GetObjNum
|
|
* ---------
|
|
*
|
|
* LPSTR lpobj - The object whose number is desired
|
|
*
|
|
* RETURNS: The number of the object, i.e., the numerical portion of its name.
|
|
*
|
|
* CUSTOMIZATION: Server Demo specific
|
|
*/
|
|
static INT GetObjNum (LPOBJ lpobj)
|
|
{
|
|
LPSTR lpsz;
|
|
INT n=0;
|
|
|
|
lpsz = lpobj->native.szName + 7;
|
|
while (*lpsz && *lpsz>='0' && *lpsz<='9')
|
|
n = 10*n + *lpsz++ - '0';
|
|
return n;
|
|
}
|
|
|
|
|
|
|
|
/* GetText
|
|
* -------
|
|
*
|
|
* Return a handle to an object's data in text form.
|
|
* This function simply returns the name of the object.
|
|
*
|
|
* LPOBJ lpobj - The object
|
|
*
|
|
* RETURNS: A handle to the object's text.
|
|
*
|
|
* CUSTOMIZATION: Re-implement, if your application supports CF_TEXT as a
|
|
* presentation format.
|
|
*
|
|
*/
|
|
static HANDLE GetText (LPOBJ lpobj)
|
|
{
|
|
HANDLE hText = NULL;
|
|
LPSTR lpszText = NULL;
|
|
|
|
if(!(hText = GlobalAlloc (GMEM_DDESHARE, sizeof (lpobj->native.szName))))
|
|
return NULL;
|
|
|
|
if (!(lpszText = GlobalLock (hText)))
|
|
return NULL;
|
|
|
|
lstrcpy (lpszText, lpobj->native.szName);
|
|
|
|
GlobalUnlock (hText);
|
|
|
|
return hText;
|
|
}
|
|
|
|
|
|
|
|
/* ObjDoVerb OBJECT "DoVerb" METHOD
|
|
* ---------
|
|
*
|
|
* This method is called by the client, through the library, to either
|
|
* PLAY, or EDIT the object. PLAY is implemented as a beep, and
|
|
* EDIT will bring up the server and show the object for editing.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* WORD wVerb - The verb acting on the object: PLAY or EDIT
|
|
* BOOL fShow - Should the object be shown?
|
|
* BOOL fTakeFocus - Should the object window get the focus?
|
|
*
|
|
* RETURNS: OLE_OK
|
|
*
|
|
* CUSTOMIZATION: Add any more verbs your application supports.
|
|
* Implement verbPlay if your application supports it.
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjDoVerb
|
|
(LPOLEOBJECT lpoleobject, UINT wVerb, BOOL fShow, BOOL fTakeFocus)
|
|
{
|
|
switch (wVerb)
|
|
{
|
|
case verbPlay:
|
|
{ // The application can do whatever is appropriate for the object.
|
|
INT i;
|
|
for (i=0; i<25;i++) MessageBeep (0);
|
|
return OLE_OK;
|
|
}
|
|
|
|
case verbEdit:
|
|
if (fShow)
|
|
return objvtbl.Show (lpoleobject, fTakeFocus);
|
|
else
|
|
return OLE_OK;
|
|
default:
|
|
// Unknown verb.
|
|
return OLE_ERROR_DOVERB;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ObjEnumFormats OBJECT "EnumFormats" METHOD
|
|
* ---------------
|
|
*
|
|
* This method is used to enumerate all supported clipboard formats.
|
|
* Terminate by returning NULL.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* OLECLIPFORMAT cfFormat - The 'current' clipboard format
|
|
*
|
|
* RETURNS: The 'next' clipboard format which is supported.
|
|
*
|
|
* CUSTOMIZATION: Verify that the list of formats this function
|
|
* returns matches the list of formats your application
|
|
* supports.
|
|
*
|
|
*/
|
|
OLECLIPFORMAT APIENTRY ObjEnumFormats
|
|
(LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat)
|
|
{
|
|
if (cfFormat == 0)
|
|
return cfNative;
|
|
|
|
if (cfFormat == cfNative)
|
|
return cfOwnerLink;
|
|
|
|
if (cfFormat == cfOwnerLink)
|
|
return CF_ENHMETAFILE;
|
|
|
|
if (cfFormat == CF_ENHMETAFILE)
|
|
return CF_METAFILEPICT;
|
|
|
|
if (cfFormat == CF_METAFILEPICT)
|
|
return CF_BITMAP;
|
|
|
|
if (cfFormat == CF_BITMAP)
|
|
return cfObjectLink;
|
|
|
|
if (cfFormat == cfObjectLink)
|
|
return 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* ObjGetData OBJECT "GetData" METHOD
|
|
* -----------
|
|
*
|
|
* Return the data requested for the specified object in the specified format.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* WORD cfFormat - The data type requested in standard
|
|
* clipboard format
|
|
* LPHANDLE lphandle - Pointer to handle to memory where data
|
|
* will be stored
|
|
*
|
|
* RETURNS: OLE_OK if successful
|
|
* OLE_ERROR_MEMORY if there was an error getting the data.
|
|
* OLE_ERROR_FORMAT if the requested format is unknown.
|
|
*
|
|
*
|
|
* CUSTOMIZATION: Add any additional formats your application supports, and
|
|
* remove any formats it does not support.
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjGetData
|
|
(LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat, LPHANDLE lphandle)
|
|
{
|
|
|
|
LPOBJ lpobj;
|
|
|
|
lpobj = (LPOBJ) lpoleobject;
|
|
|
|
if (cfFormat == cfNative)
|
|
{
|
|
if (!(*lphandle = GetNative (lpobj)))
|
|
return OLE_ERROR_MEMORY;
|
|
// The client has requested the data in native format, therefore
|
|
// the data in the client and server are in sync.
|
|
fDocChanged = FALSE;
|
|
return OLE_OK;
|
|
}
|
|
|
|
if (cfFormat == CF_ENHMETAFILE)
|
|
{
|
|
if (!(*lphandle = GetEnhMetafile (lpobj)))
|
|
return OLE_ERROR_MEMORY;
|
|
return OLE_OK;
|
|
}
|
|
|
|
if (cfFormat == CF_METAFILEPICT)
|
|
{
|
|
if (!(*lphandle = GetMetafilePict (lpobj)))
|
|
return OLE_ERROR_MEMORY;
|
|
return OLE_OK;
|
|
}
|
|
|
|
if (cfFormat == CF_BITMAP)
|
|
{
|
|
if (!(*lphandle = (HANDLE)GetBitmap (lpobj)))
|
|
return OLE_ERROR_MEMORY;
|
|
return OLE_OK;
|
|
}
|
|
|
|
if (cfFormat == CF_TEXT)
|
|
{
|
|
if (!(*lphandle = GetText (lpobj)))
|
|
return OLE_ERROR_MEMORY;
|
|
return OLE_OK;
|
|
}
|
|
|
|
if (cfFormat == cfObjectLink)
|
|
{
|
|
if (!(*lphandle = GetLink (lpobj)))
|
|
return OLE_ERROR_MEMORY;
|
|
return OLE_OK;
|
|
}
|
|
|
|
if (cfFormat == cfOwnerLink)
|
|
{
|
|
if (!(*lphandle = GetLink (lpobj)))
|
|
return OLE_ERROR_MEMORY;
|
|
return OLE_OK;
|
|
}
|
|
|
|
return OLE_ERROR_FORMAT;
|
|
}
|
|
|
|
|
|
|
|
/* ObjQueryProtocol OBJECT "QueryProtocol" METHOD
|
|
* ----------------
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* OLE_LPCSTR lpszProtocol - The protocol name, either "StdFileEditing"
|
|
* or "StdExecute"
|
|
*
|
|
* RETURNS: If lpszProtocol is supported, return a pointer to an OLEOBJECT
|
|
* structure with an appropriate method table for that protocol.
|
|
* Otherwise, return NULL.
|
|
*
|
|
* CUSTOMIZATION: Allow any additional protocols your application supports.
|
|
*
|
|
*
|
|
*/
|
|
LPVOID APIENTRY ObjQueryProtocol
|
|
(LPOLEOBJECT lpoleobject, OLE_LPCSTR lpszProtocol)
|
|
{
|
|
return lstrcmp (lpszProtocol, "StdFileEditing") ? NULL : lpoleobject ;
|
|
}
|
|
|
|
|
|
|
|
/* ObjRelease OBJECT "Release" METHOD
|
|
* -----------
|
|
*
|
|
* The server application should not destroy data when the library calls the
|
|
* ReleaseObj method.
|
|
* The library calls the ReleaseObj method when no clients are connected
|
|
* to the object.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
*
|
|
* RETURNS: OLE_OK
|
|
*
|
|
* CUSTOMIZATION: Re-implement. Do whatever needs to be done, if anything,
|
|
* when no clients are connected to an object.
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjRelease (LPOLEOBJECT lpoleobject)
|
|
{
|
|
INT i;
|
|
/* No client is connected to the object so break all assocaiations
|
|
between clients and the object. */
|
|
for (i=0; i < clpoleclient; i++)
|
|
((LPOBJ)lpoleobject)->lpoleclient[i] = NULL;
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
/* ObjSetBounds OBJECT "SetBounds" METHOD
|
|
* ------------
|
|
*
|
|
* This method is called to set new bounds for an object.
|
|
* The bounds are in HIMETRIC units.
|
|
* A call to this method is ignored for linked objects because the size of
|
|
* a linked object depends only on the source file.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* OLE_CONST RECT FAR* lprect - The new bounds
|
|
*
|
|
* RETURNS: OLE_OK
|
|
*
|
|
* CUSTOMIZATION: Re-implement
|
|
* How an object is sized is application-specific. (Server Demo
|
|
* uses MoveWindow.)
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjSetBounds (LPOLEOBJECT lpoleobj, OLE_CONST RECT FAR * lprect)
|
|
{
|
|
if (docMain.doctype == doctypeEmbedded)
|
|
{
|
|
RECT rect = *lprect;
|
|
LPOBJ lpobj = (LPOBJ) lpoleobj;
|
|
|
|
// the units are in HIMETRIC
|
|
rect.right = rect.right - rect.left;
|
|
rect.bottom = rect.top - rect.bottom;
|
|
HiMetricToDevice ( (LPPOINT) &rect.right);
|
|
MoveWindow (lpobj->hwnd, lpobj->native.nX, lpobj->native.nY,
|
|
rect.right + 2 * GetSystemMetrics(SM_CXFRAME),
|
|
rect.bottom + 2 * GetSystemMetrics(SM_CYFRAME),
|
|
TRUE);
|
|
}
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
/* ObjSetColorScheme OBJECT "SetColorScheme" METHOD
|
|
* -----------------
|
|
*
|
|
* The client calls this method to suggest a color scheme (palette) for
|
|
* the server to use for the object.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* OLE_CONST LOGPALETTE FAR * lppal - Suggested palette
|
|
*
|
|
* RETURNS: OLE_ERROR_PALETTE if CreatePalette fails,
|
|
* OLE_OK otherwise
|
|
*
|
|
*
|
|
* CUSTOMIZATION: If your application supports color schemes, then this
|
|
* function is a good example of how to create and store
|
|
* a palette.
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjSetColorScheme
|
|
(LPOLEOBJECT lpoleobject, OLE_CONST LOGPALETTE FAR *lppal)
|
|
{
|
|
HPALETTE hpal = CreatePalette (lppal);
|
|
LPOBJ lpobj = (LPOBJ) lpoleobject;
|
|
|
|
if (hpal==NULL)
|
|
return OLE_ERROR_PALETTE;
|
|
|
|
if (lpobj->hpal)
|
|
DeleteObject (lpobj->hpal);
|
|
lpobj->hpal = hpal;
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
/* ObjSetData OBJECT "SetData" METHOD
|
|
* ----------
|
|
*
|
|
* This method is used to store data into the object in the specified
|
|
* format. This will be called with Native format after an embedded
|
|
* object has been opened by the Edit method.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* WORD cfFormat - Data type, i.e., clipboard format
|
|
* HANDLE hdata - Handle to the data.
|
|
*
|
|
* RETURNS: OLE_OK if the data was stored properly
|
|
* OLE_ERROR_FORMAT if format was not cfNative.
|
|
* OLE_ERROR_MEMORY if memory could not be locked.
|
|
*
|
|
* CUSTOMIZATION: The large then-clause will need to be re-implemented for
|
|
* your application. You may wish to support additional
|
|
* formats besides cfNative.
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjSetData
|
|
(LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat, HANDLE hdata)
|
|
{
|
|
LPNATIVE lpnative;
|
|
LPOBJ lpobj;
|
|
|
|
lpobj = (LPOBJ)lpoleobject;
|
|
|
|
if (cfFormat != cfNative)
|
|
{
|
|
return OLE_ERROR_FORMAT;
|
|
}
|
|
|
|
lpnative = (LPNATIVE) GlobalLock (hdata);
|
|
|
|
if (lpnative)
|
|
{
|
|
lpobj->native = *lpnative;
|
|
if (lpobj->aName)
|
|
GlobalDeleteAtom (lpobj->aName);
|
|
lpobj->aName = GlobalAddAtom (lpnative->szName);
|
|
// CreateNewObj made an "Object 1" but we may be changing its number.
|
|
docMain.rgfObjNums[1] = FALSE;
|
|
docMain.rgfObjNums [GetObjNum(lpobj)] = TRUE;
|
|
|
|
MoveWindow (lpobj->hwnd, 0, 0,
|
|
// lpobj->native.nWidth + 2 * GetSystemMetrics(SM_CXFRAME),
|
|
// lpobj->native.nHeight+ 2 * GetSystemMetrics(SM_CYFRAME),
|
|
lpobj->native.nWidth,
|
|
lpobj->native.nHeight,
|
|
|
|
FALSE);
|
|
GlobalUnlock (hdata);
|
|
}
|
|
// Server is responsible for deleting the data.
|
|
GlobalFree(hdata);
|
|
return lpnative ? OLE_OK : OLE_ERROR_MEMORY;
|
|
}
|
|
|
|
|
|
|
|
/* ObjSetTargetDevice OBJECT "SetTargetDevice" METHOD
|
|
* -------------------
|
|
*
|
|
* This method is used to indicate the device type that an object
|
|
* will be rendered on. It is the server's responsibility to free hdata.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - The OLE object
|
|
* HANDLE hdata - Handle to memory containing
|
|
* a StdTargetDevice structure
|
|
*
|
|
* RETURNS: OLE_OK
|
|
*
|
|
* CUSTOMIZATION: Implement. Server Demo currently does not do anything.
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjSetTargetDevice (LPOLEOBJECT lpoleobject, HANDLE hdata)
|
|
{
|
|
if (hdata == NULL)
|
|
{
|
|
// Rendering for the screen is requested.
|
|
}
|
|
else
|
|
{
|
|
LPSTR lpstd = (LPSTR) GlobalLock (hdata);
|
|
// lpstd points to a StdTargetDevice structure.
|
|
// Use it to do whatever is appropriate to generate the best results
|
|
// on the specified target device.
|
|
GlobalUnlock (hdata);
|
|
// Server is responsible for freeing the data.
|
|
GlobalFree (hdata);
|
|
}
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
/* ObjShow OBJECT "Show" METHOD
|
|
* --------
|
|
*
|
|
* This method is used to display the object.
|
|
* The server application should be activated and brought to the top.
|
|
* Also, in a REAL server application, the object should be scrolled
|
|
* into view. The object should be selected.
|
|
*
|
|
* LPOLEOBJECT lpoleobject - Pointer to the OLE object
|
|
* BOOL fTakeFocus - Should server window get the focus?
|
|
*
|
|
* RETURNS: OLE_OK
|
|
*
|
|
*
|
|
* CUSTOMIZATION: In your application, the document should be scrolled
|
|
* to bring the object into view. Server Demo brings the
|
|
* object to the front, in case it is a linked object inside a
|
|
* document with other objects obscuring it.
|
|
*
|
|
*/
|
|
OLESTATUS APIENTRY ObjShow (LPOLEOBJECT lpoleobject, BOOL fTakeFocus)
|
|
{
|
|
LPOBJ lpobj;
|
|
HWND hwndOldFocus;
|
|
|
|
hwndOldFocus = GetFocus();
|
|
lpobj = (LPOBJ) lpoleobject;
|
|
|
|
if (fTakeFocus)
|
|
SetForegroundWindow (lpobj->hwnd);
|
|
|
|
ShowWindow(hwndMain, SW_SHOWNORMAL);
|
|
|
|
SetFocus (fTakeFocus ? lpobj->hwnd : hwndOldFocus);
|
|
return OLE_OK;
|
|
}
|
|
|
|
|
|
|
|
/* PaintObj
|
|
* ---------
|
|
*
|
|
* This function is called by the WM_PAINT message to paint an object
|
|
* on the screen.
|
|
*
|
|
* HWND hwnd - The object window in which to paint the object
|
|
*
|
|
* CUSTOMIZATION: Server Demo specific
|
|
*
|
|
*/
|
|
VOID PaintObj (HWND hwnd)
|
|
{
|
|
LPOBJ lpobj;
|
|
RECT rc;
|
|
HDC hdc;
|
|
PAINTSTRUCT paintstruct;
|
|
|
|
BeginPaint (hwnd, &paintstruct);
|
|
hdc = GetDC (hwnd);
|
|
|
|
lpobj = HwndToLpobj (hwnd);
|
|
GetClientRect (hwnd, (LPRECT) &rc);
|
|
|
|
DrawObj (hdc, lpobj, rc, dctypeScreen);
|
|
|
|
ReleaseDC (hwnd, hdc);
|
|
EndPaint (hwnd, &paintstruct);
|
|
}
|
|
|
|
|
|
|
|
/* RevokeObj
|
|
* ---------
|
|
*
|
|
* Call OleRevokeObject because the user has destroyed the object.
|
|
*
|
|
* LPOBJ lpobj - The object which has been destroyed
|
|
*
|
|
*
|
|
* CUSTOMIZATION: You will only need to call OleRevokeObject once if there
|
|
* is only one LPOLECLIENT in your OBJ structure, which there
|
|
* should be.
|
|
*
|
|
*/
|
|
VOID RevokeObj (LPOBJ lpobj)
|
|
{
|
|
INT i;
|
|
|
|
for (i=0; i< clpoleclient; i++)
|
|
{
|
|
if (lpobj->lpoleclient[i])
|
|
OleRevokeObject (lpobj->lpoleclient[i]);
|
|
else
|
|
/* if lpobj->lpoleclient[i]==NULL then there are no more non-NULLs
|
|
in the array. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SendObjMsg
|
|
* ----------
|
|
*
|
|
* This function sends a message to a specific object.
|
|
*
|
|
* LPOBJ lpobj - The object
|
|
* WORD wMessage - The message to send
|
|
*
|
|
* CUSTOMIZATION: You will only need to call CallBack once if there
|
|
* is only one LPOLECLIENT in your OBJ structure, which there
|
|
* should be.
|
|
*
|
|
*/
|
|
VOID SendObjMsg (LPOBJ lpobj, WORD wMessage)
|
|
{
|
|
INT i;
|
|
for (i=0; i < clpoleclient; i++)
|
|
{
|
|
if (lpobj->lpoleclient[i])
|
|
{
|
|
// Call the object's Callback function.
|
|
lpobj->lpoleclient[i]->lpvtbl->CallBack
|
|
(lpobj->lpoleclient[i], wMessage, (LPOLEOBJECT) lpobj);
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SizeObj
|
|
* -------
|
|
*
|
|
* Change the size of an object.
|
|
*
|
|
* HWND hwnd - The object's window
|
|
* RECT rect - The requested new size in device units
|
|
* BOOL fMove - Should the object be moved? (or just resized?)
|
|
*
|
|
* CUSTOMIZATION: Server Demo specific
|
|
*
|
|
*/
|
|
VOID SizeObj (HWND hwnd, RECT rect, BOOL fMove)
|
|
{
|
|
LPOBJ lpobj;
|
|
|
|
lpobj = HwndToLpobj (hwnd);
|
|
if (fMove)
|
|
{
|
|
lpobj->native.nX = rect.left;
|
|
lpobj->native.nY = rect.top;
|
|
}
|
|
lpobj->native.nWidth = rect.right - rect.left;
|
|
lpobj->native.nHeight = rect.bottom - rect.top ;
|
|
SetHiMetricFields (lpobj);
|
|
InvalidateRect (hwnd, (LPRECT)NULL, TRUE);
|
|
fDocChanged = TRUE;
|
|
if (docMain.doctype == doctypeFromFile)
|
|
{
|
|
// If object is linked, update it in client now.
|
|
SendObjMsg (lpobj, OLE_CHANGED);
|
|
}
|
|
}
|