windows-nt/Source/XPSP1/NT/com/winole/samples/clidemo/object.c
2020-09-26 16:20:57 +08:00

1178 lines
42 KiB
C

/*
* object.c - OLE object support routines
*
* Created by Microsoft Corporation.
* (c) Copyright Microsoft Corp. 1990 - 1992 All Rights Reserved
*/
//*** INCLUDES ****
#include <windows.h> //* WINDOWS
#include <shellapi.h> //* SHELL
#include <ole.h> //* OLE
#include "global.h" //* global variables and structures
#include "stream.h" //* application includes:
#include "dialog.h"
#include "object.h"
#include "clidemo.h"
#include "demorc.h"
#include "utility.h"
#include "register.h"
#define HIMETRIC_PER_INCH 2540
//*** VARIABLES ***
//*** Globals
INT cOleWait = 0;
INT giXppli ;
INT giYppli ;
/***************************************************************************
* CallBack()
*
* This routine will be called whenever an object has been changed,
* saved, renamed, is being painted, or an asynchronous operation has
* completed. This routine is called by the OLE client DLL in the
* above situations. A pointer to this function is kept in the client
* vtbl. It is our obligation as a client application to insure that a
* pointer to this procedure is in the vtbl.
*
* IMMPORTANT: notice that we are posting messages here rather that doing
* the work right away. Well, this is done to avoid any possibility of
* getting into another dispatch message loop. A MessageBox woul do this!
*
* Returns int - see below
*
* The return value is generally ignored, except for these notifications:
* OLE_QUERY_PAINT and OLE_QUERY_RETRY. For these two notifications,
* returning TRUE means continue the current operation(eg painting or retry)
* Returning FALSE means stop the current operation. This is useful as an
* object which takes a long time to paint can be interrupted in order to
* perform other operations.
***************************************************************************/
INT APIENTRY CallBack( //* ENTRY:
LPOLECLIENT lpClient, //* client application pointer
OLE_NOTIFICATION flags, //* notification code being sent
LPOLEOBJECT lpObject //* OLE object pointer
){ //* LOCAL:
APPITEMPTR pItem; //* application item pointer
pItem = (APPITEMPTR)lpClient;
switch (flags)
{
case OLE_CLOSED: //* server has closed
if (!pItem->fVisible)
{
PostMessage(hwndFrame, WM_DELETE, 0L, (DWORD)pItem);
Dirty(DOC_UNDIRTY);
}
SetFocus( hwndFrame );
break;
case OLE_SAVED: //* server has saved object
case OLE_CHANGED: //* object has changes
cOleWait++;
pItem->fServerChangedBounds = pItem->fVisible = TRUE;
PostMessage(pItem->hwnd, WM_CHANGE, 0, 0L);
break;
case OLE_RELEASE: //* notification that an asynchronous
ToggleBlockTimer(FALSE); //* toggle timer off
if (hRetry)
PostMessage(hRetry,WM_COMMAND,IDCANCEL,0L);
if (cOleWait) //* operation has completed
{
pItem->fRetry = TRUE;
if (!--cOleWait)
Hourglass(FALSE);
Release(pItem);
}
break;
case OLE_QUERY_RETRY: //* Continue retrying.
ToggleBlockTimer(FALSE); //* toggle timer off
if (!hRetry && pItem->fRetry)
PostMessage(hwndFrame,WM_RETRY,0L, (DWORD)pItem);
return (pItem->fRetry);
case OLE_QUERY_PAINT: //* continue repainting
return TRUE; //* a false return terminates either
default:
break;
}
return 0; //* return value is ignored in
//* most cases, see header
}
/***************************************************************************
* Release()
*
* Check for an error on the OLE_RELEASE notification.
**************************************************************************/
static VOID Release( //* ENTRY:
APPITEMPTR pItem //* Item pointer
){ //* LOCAL:
DWORD wParam; //* error code parameter
if ((wParam = OleQueryReleaseError(pItem->lpObject)) == OLE_OK)
return;
switch (OleQueryReleaseMethod(pItem->lpObject))
{
case OLE_LNKPASTE:
pItem->fVisible = FALSE;
break;
case OLE_CREATEFROMTEMPLATE:
case OLE_CREATE:
pItem->fVisible = FALSE;
cOleWait++;
PostMessage(hwndFrame, WM_DELETE,1L, (DWORD)pItem);
Dirty(DOC_UNDIRTY);
}
//* post a message to the main window
//* which will display a message box
PostMessage(hwndFrame,WM_ERROR,wParam,0);
}
/***************************************************************************
* Error()
*
* This function checks for error conditions
* generated by OLE API callsFor OLE_WAIT_FOR_RELEASE,
* we keep track of the number of objects waiting, when
* this count is zero, it is safe to exit the application.
*
* Returns OLESTATUS - 0 if OLE_WAIT_FOR_RELEASE or OLE_OK
* otherwise the OLESTATUS returned after an action
* is taken.
*************************************************************************/
OLESTATUS FAR Error( //* ENTRY
OLESTATUS olestat //* OLE status
){
switch (olestat)
{
case OLE_WAIT_FOR_RELEASE:
if (!cOleWait)
Hourglass(TRUE);
cOleWait++; //* increment wait count
case OLE_OK:
return 0;
case OLE_ERROR_STATIC: //* static object
ErrorMessage(W_STATIC_OBJECT);
break;
case OLE_ERROR_REQUEST_PICT:
case OLE_ERROR_ADVISE_RENAME:
case OLE_ERROR_DOVERB:
case OLE_ERROR_SHOW:
case OLE_ERROR_OPEN:
case OLE_ERROR_NETWORK:
case OLE_ERROR_ADVISE_PICT:
case OLE_ERROR_COMM: //* Invalid links
InvalidLink();
break;
case OLE_BUSY:
RetryMessage(NULL,RD_CANCEL);
default:
break;
}
return olestat;
}
/****************************************************************************
* PreItemCreate()
*
* This routine allocates an application item structure. A pointer to this
* structure is passed as the client structure, therefore we need to
* have a pointer to the vtbl as the first entry. We are doing this
* to allow acess to the application item information during a OLE
* DLL callback. This approach simplifies matters.
*
* Returns APPITEMPTR - a pointer to a new application item structure
* which can operate as a client structure.
***************************************************************************/
APPITEMPTR FAR PreItemCreate( //* ENTRY:
LPOLECLIENT lpClient, //* OLE client pointer
BOOL fShow, //* show/no-show flag
LHCLIENTDOC lhcDoc //* client document handle
){ //* LOCAL:
HANDLE hitem; //* temp handle for new item
APPITEMPTR pItem; //* application item pointer
if (hitem = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(APPITEM)))
if (pItem = (APPITEMPTR)LocalLock(hitem))
{ //* set the vtbl pointer
pItem->oleclient.lpvtbl = lpClient->lpvtbl;
pItem->lpObjectUndo = NULL;
pItem->fVisible = fShow;
pItem->fServerChangedBounds = FALSE;
pItem->lhcDoc = lhcDoc;
return pItem; //* SUCCESS return
}
ErrorMessage(E_FAILED_TO_ALLOC);
return NULL; //* ERROR return
}
/***************************************************************************
* ItemWndProc()
*
* This function handles item window message processing.
* There is an item window for each OLE object. This was done to
* to simplify hit testing and repainting. These windows are child
* windows.
* returns long - standard child routine
**************************************************************************/
LONG APIENTRY ItemWndProc( //* ENTRY:
HWND hwnd, //* standard windows parameters
UINT msg,
DWORD wParam,
LONG lParam
){ //* LOCAL:
static POINT dragPt; //* Mouse drag point
static RECT dragRect; //* Mouse drag rectangle
static BOOL fCaptured; //* captured flag
APPITEMPTR pItem; //* application item pointer
PAINTSTRUCT ps; //* paint structure
POINT pt; //* point
RECT rc; //* bounding rectangle
// char lpstr[256];
switch (msg)
{
case WM_SIZE:
if (pItem = (APPITEMPTR)GetWindowLong(hwnd,0))
{
if (!pItem->fServerChangedBounds && pItem->otObject == OT_EMBEDDED)
ObjSetBounds(pItem);
else
pItem->fServerChangedBounds = FALSE;
}
break;
case WM_CHANGE:
--cOleWait;
pItem = (APPITEMPTR)GetWindowLong(hwnd,0);
if (!Error(OleQueryBounds(pItem->lpObject, &rc)))
{
ConvertToClient(&rc);
SetWindowPos(
hwnd,
NULL,
0,
0,
rc.right - rc.left + 2*GetSystemMetrics(SM_CXFRAME),
rc.bottom - rc.top + 2*GetSystemMetrics(SM_CYFRAME),
SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME
);
if (!pItem->fNew && !fLoadFile)
ShowNewWindow(pItem);
else
InvalidateRect(hwnd, NULL, TRUE);
Dirty(DOC_DIRTY);
}
break;
case WM_NCLBUTTONDOWN:
SetTopItem((APPITEMPTR)GetWindowLong(hwnd,0));
return (DefWindowProc(hwnd, msg, wParam, lParam));
case WM_PAINT:
BeginPaint(hwnd, (LPPAINTSTRUCT)&ps);
GetClientRect(hwnd, &rc);
pItem = (APPITEMPTR)GetWindowLong(hwnd, 0);
//* Call OLE draw
Error(OleDraw(pItem->lpObject, ps.hdc, &rc, NULL, NULL));
EndPaint(hwnd, (LPPAINTSTRUCT)&ps);
break;
case WM_LBUTTONDBLCLK: //* execute a verb
ANY_OBJECT_BUSY;
ExecuteVerb(OLEVERB_PRIMARY,(APPITEMPTR)GetWindowLong(hwnd,0));
break;
case WM_LBUTTONDOWN:
GetWindowRect(hwnd, (LPRECT)&dragRect);
ScreenToClient(hwndFrame, (LPPOINT)&dragRect);
ScreenToClient(hwndFrame, (LPPOINT)&dragRect.right);
dragPt.x = (LONG)(SHORT)LOWORD(lParam);
dragPt.y = (LONG)(SHORT)HIWORD(lParam);
ClientToScreen(hwnd, (LPPOINT)&dragPt);
ScreenToClient(hwndFrame, (LPPOINT)&dragPt);
SetCapture(hwnd);
fCaptured = TRUE;
SetTopItem((APPITEMPTR)GetWindowLong(hwnd,0));
break;
case WM_LBUTTONUP:
if (!fCaptured)
break;
ReleaseCapture();
fCaptured = FALSE;
Dirty(DOC_DIRTY);
break;
case WM_MOUSEMOVE:
if (!fCaptured)
break;
pt.x = (LONG)(SHORT)LOWORD(lParam);
pt.y = (LONG)(SHORT)HIWORD(lParam);
ClientToScreen(hwnd, (LPPOINT)&pt);
ScreenToClient(hwndFrame, (LPPOINT)&pt);
OffsetRect(
(LPRECT)&dragRect,
pt.x - dragPt.x,
pt.y - dragPt.y
);
MoveWindow(
hwnd,
dragRect.left, dragRect.top,
dragRect.right - dragRect.left,
dragRect.bottom - dragRect.top, TRUE
);
dragPt.x = pt.x;
dragPt.y = pt.y;
break;
default:
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
return 0L;
}
/****************************************************************************
* PostItemCreate()
*
* This function creates a child window which will contain the newly
* created OLE object. A pointer to our item information is stored in the
* extra bytes of this window. This is where we internally keep track
* of information related to the object as well as the
* pointer to the object for subsequent OLE API calls. This routine is
* called after an OLE object has been created by the client library.
*
* Returns BOOL - TRUE if application item has been created.
****************************************************************************/
BOOL FAR PostItemCreate( //* ENTRY:
LPOLEOBJECT lpObject, //* OLE object pointer
LONG otObject, //* OLE object type
LPRECT lprcObject, //* object bounding rect
APPITEMPTR pItem //* application item pointer
){ //* LOCAL:
INT i; //* index
RECT rc; //* bounding rectangle
CHAR pData[OBJECT_LINK_MAX];//* copy of link data
if (lprcObject) //* if the size of the objects
rc = *lprcObject; //* bounding rectangle is not
else if (OleQueryBounds(lpObject, &rc) == OLE_OK)
ConvertToClient(&rc);
else
SetRect(&rc, 0, 0, 0, 0);
if (!(pItem->hwnd = CreateWindow( //* Create the child window
szItemClass, "",
WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME,
rc.left,rc.top,
rc.right - rc.left + 2 * GetSystemMetrics(SM_CXFRAME),
rc.bottom - rc.top + 2 * GetSystemMetrics(SM_CYFRAME),
hwndFrame, NULL, hInst, NULL
))) goto Error;
//* in windows extra bytes
SetWindowLong(pItem->hwnd, 0, (LONG)pItem);
pItem->otObject = otObject;
pItem->lpObject = lpObject;
pItem->fRetry = TRUE;
if( pItem->otObject == OT_EMBEDDED )//* if object is embedded tell library
{ //* the container name and object name.
UINT cb=CBOBJNAMEMAX; //* The name will be the server window title.
CHAR sz[CBOBJNAMEMAX]; //* when the object is edited.
OleQueryName(lpObject, (LPSTR)sz, (UINT FAR *)&cb );
WaitForObject(pItem);
Error(OleSetHostNames(lpObject, (LPSTR)szAppName, (LPSTR)sz ));
WaitForObject(pItem);
}
else if (pItem->otObject == OT_LINK)//* if the object is linked
{ //* retrieve update options
WaitForObject(pItem);
if(Error(OleGetLinkUpdateOptions(pItem->lpObject, &pItem->uoObject)))
goto Error;
if (ObjGetData(pItem,pData))
{
for (i=0; pData[i];i++); //* Skip past the server name
pItem->aLinkName = AddAtom(&pData[++i]);
}
else
pItem->aLinkName = AddAtom("");
}
iObjects++;
Dirty(DOC_DIRTY);
//* a user interface recommendations.
return TRUE; //* SUCCESS return
Error: //* ERROR Tag
ErrorMessage(E_FAILED_TO_CREATE_CHILD_WINDOW);
FreeAppItem(pItem);
return FALSE; //* ERROR return
}
/***************************************************************************
* ConvertToClient()
*
* This function will convert to client from himetric.
**************************************************************************/
VOID FAR ConvertToClient( //* ENTRY:
LPRECT lprc //* pointer to bounding rectangle
){ //* LOCAL
//* If we have an empty rectangle then set the default size
if (!(lprc->left || lprc->top || lprc->right || lprc->bottom))
SetRect(lprc, 0, 0, CXDEFAULT, CYDEFAULT);
else
{
//* We got the himetric units, converts them to pixels now.
lprc->right = MulDiv (giXppli, (lprc->right - lprc->left),
HIMETRIC_PER_INCH);
lprc->bottom = MulDiv (giYppli, (lprc->top - lprc->bottom),
HIMETRIC_PER_INCH);
lprc->left = 0;
lprc->top = 0;
}
}
/***************************************************************************
* ObjInsert()
*
* Query the user for object type to insert and insert the new OLE object
***************************************************************************/
VOID FAR ObjInsert( //* ENTRY:
LHCLIENTDOC lhcDoc, //* OLE document handle
LPOLECLIENT lpClient //* pointer to OLE client structure
){ //* LOCAL:
LPOLEOBJECT lpObject; //* pointer to OLE object
APPITEMPTR pItem; //* item pointer
CHAR szServerName[CBPATHMAX];//* Class name for OleCreate()
CHAR szClassName[CBPATHMAX];//* Class name for OleCreate()
CHAR szTmp[CBOBJNAMEMAX]; //* buffer to unique object name
if (DialogBoxParam(hInst, MAKEINTRESOURCE(DTCREATE),hwndFrame,
(DLGPROC) fnInsertNew, (LONG)((LPSTR)szClassName)) != IDCANCEL)
{
if (pItem = PreItemCreate(lpClient, FALSE, lhcDoc))
{
RegGetClassId(szServerName, szClassName);
pItem->aServer = AddAtom(szServerName);
if ( Error( OleCreate(STDFILEEDITING,(LPOLECLIENT)&(pItem->oleclient),
(LPSTR)szClassName, lhcDoc,CreateNewUniqueName(szTmp),
&lpObject,olerender_draw, 0)))
{
ErrorMessage(E_FAILED_TO_CREATE_OBJECT);
FreeAppItem(pItem);
}
else
PostItemCreate(lpObject, OT_EMBEDDED, NULL, pItem);
}
}
}
/***************************************************************************
* ObjDelete()
*
* Delete an OLE object. For this application, all OLE objects
* are associated with a child window; therefore the window must be
* destroyed.
*
* NOTE: There is one case when we call OleRelease and the other when
* we call OleDelete. We call OleRelease when we are deregistering
* a document and OleDelete when removing an object from a document.
**************************************************************************/
VOID FAR ObjDelete( //* ENTRY:
APPITEMPTR pItem, //* pointer to application item
BOOL fDelete //* delete or release flag
){ //* LOCAL:
if (pItem->lpObjectUndo)
{
Error(OleDelete(pItem->lpObjectUndo));
//* wait for asynchronous operation
WaitForObject(pItem);
}
if (fDelete ? Error(OleDelete(pItem->lpObject))
: Error(OleRelease(pItem->lpObject)))
{
ErrorMessage(E_FAILED_TO_DELETE_OBJECT);
return; //* ERROR return
}
if (pItem->fVisible)
{
ShowWindow(pItem->hwnd, SW_HIDE);
pItem->fVisible = FALSE;
}
//* the operation has to complete
WaitForObject(pItem); //* before the application structure
FreeAppItem(pItem);
iObjects--;
}
/***************************************************************************
* ObjPaste()
*
* This function obtains an object from the clipboard.
* Handles both embedded and linked objects. An item window is
* created for each new object.
*
* Returns BOOL - TRUE if object was pasted succesfully.
**************************************************************************/
VOID FAR ObjPaste( //* ENTRY:
BOOL fPaste, //* Paste/PasteLink flag
LHCLIENTDOC lhcDoc, //* client document handle
LPOLECLIENT lpClient //* pointer to client
){ //* LOCAL:
LPOLEOBJECT lpObject; //* object pointer
LONG otObject; //* object type
APPITEMPTR pItem; //* application item pointer
CHAR szTmp[CBOBJNAMEMAX]; //* temporary object name string
if (!(pItem = PreItemCreate(lpClient, TRUE, lhcDoc)))
return; //* ERROR return
if (!OpenClipboard(hwndFrame))
goto Error; //* ERROR jump
if (fPaste) //* PASTE the object.
{ //* Try "StdFileEditing" protocol
if (Error(OleCreateFromClip(STDFILEEDITING,(LPOLECLIENT)&(pItem->oleclient),lhcDoc,
CreateNewUniqueName(szTmp),&lpObject, olerender_draw,0)))
{
//* next try "Static" protocol
if (Error(OleCreateFromClip(
STATICP, (LPOLECLIENT)&(pItem->oleclient), lhcDoc,
CreateNewUniqueName(szTmp), &lpObject, olerender_draw, 0)))
goto Error; //* ERROR jump
}
}
else
{ //* LINK therefore must be
// "STdFileEditing" protocol
if (Error(OleCreateLinkFromClip(
STDFILEEDITING,(LPOLECLIENT)&(pItem->oleclient), lhcDoc,
CreateNewUniqueName(szTmp), &lpObject, olerender_draw, 0)))
goto Error; //* ERROR jump
}
OleQueryType(lpObject, &otObject);
CloseClipboard();
if (!PostItemCreate(lpObject, otObject, NULL, pItem))
return; //* ERROR return
ShowNewWindow(pItem);
return; //* SUCCESS return
Error: //* TAG Error
ErrorMessage(E_GET_FROM_CLIPBOARD_FAILED);
CloseClipboard();
FreeAppItem(pItem);
return; //* ERROR return
}
/***************************************************************************
* ObjCopy()
*
* This function places an OLE object on the clipboard via the \
* OleCopyToClipboard() function.
*
* Returns BOOL - TRUE if object successfully placed on clipboard
**************************************************************************/
BOOL FAR ObjCopy( //* ENTRY:
APPITEMPTR pItem //* pointer to app item
){ //* LOCAL:
BOOL fReturn = TRUE; //* return value
if (!OpenClipboard(hwndFrame))
return FALSE; //* ERROR return
EmptyClipboard();
if (Error(OleCopyToClipboard(pItem->lpObject)))
fReturn = FALSE; //* prepare for ERROR out
CloseClipboard();
return fReturn; //* ERROR or SUCCESS
}
/***************************************************************************
* ObjCreateFromTemplate()
*
* Creates an embedded object from file.
**************************************************************************/
VOID FAR ObjCreateFromTemplate( //* ENTRY:
LHCLIENTDOC lhcDoc, //* client document handle
LPOLECLIENT lpClient //* client vtbl. pointer
){ //* LOCAL:
LPOLEOBJECT lpObject; //* OLE object pointer
APPITEMPTR pItem; //* application item pointer
CHAR szTmp[CBOBJNAMEMAX]; //* temporary object name string
CHAR szFileName[CBPATHMAX];//* file name string
*szFileName = 0;
if (!OfnGetName(hwndFrame, szFileName, IDM_INSERTFILE))
return; //* ERROR operation aborted by user
if (!(pItem = PreItemCreate(lpClient, FALSE, lhcDoc)))
return; //* ERROR
if (Error(OleCreateFromTemplate(STDFILEEDITING, (LPOLECLIENT)pItem, szFileName,
lhcDoc, CreateNewUniqueName(szTmp), &lpObject, olerender_draw, 0)))
{
ErrorMessage(E_CREATE_FROM_TEMPLATE);
FreeAppItem(pItem);
return; //* ERROR
}
PostItemCreate(lpObject, OT_EMBEDDED, NULL, pItem);
} //* SUCCESS
/****************************************************************************
* ObjGetData()
*
* Get the object link data. The data that is retrieved from OLE is copied
* into lpLinkData if lpLinkData is not NULL. Otherwise, space is dynamically
* allocated or reallocated; space is allocated if pItem->lpLinkData is NULL
* otherwise the pointer is reallocated. The data is returned is freed if
* there has been an OLE_WARN_DELETE_DATA error.
***************************************************************************/
BOOL FAR ObjGetData( //* ENTRY:
APPITEMPTR pItem, //* OLE object
LPSTR lpLinkData //* pointer to linkdata
){ //* LOCAL:
HANDLE hData; //* handle to OLE link data
LPSTR lpData; //* pointer to OLE link data
LPSTR lpWork; //* copy of OLE link data
BOOL fFree = FALSE; //* free OLE memory flag
LONG lSize; //* size of OLE link data
INT i;
switch (Error(OleGetData(pItem->lpObject,
(OLECLIPFORMAT)(pItem->otObject == OT_LINK ? vcfLink : vcfOwnerLink), &hData)))
{
case OLE_WARN_DELETE_DATA:
fFree = TRUE;
case OLE_OK:
if(lpData = GlobalLock(hData))
{
//* copy the link data to new buffer
lSize=SizeOfLinkData(lpData);
if (!lpLinkData)
{
if (!pItem->lpLinkData) //* allocate
AllocLinkData(pItem,lSize);
else //* otherwise reallocate
ReallocLinkData(pItem,lSize);
lpWork = pItem->lpLinkData;
}
else
lpWork = lpLinkData;
if (lpWork)
for (i=0L; i<(INT)lSize; i++)
*(lpWork+i)=*(lpData+i);
GlobalUnlock(hData); //* free the linked data as needed
if (fFree)
GlobalFree(hData);
return TRUE; //* SUCCESS
}
default:
return FALSE; //* FAILURE
}
}
/***************************************************************************
* ObjChangeLink()
*
* Change the linkdata. This routine will change the document portion of
* link data to lpDoc. The old linkdata is expected to be in
* lpaItem->lpLinkData
**************************************************************************/
VOID FAR ObjChangeLinkData( //* ENTRY:
APPITEMPTR pItem, //* OLE object
LPSTR lpDoc //* document name
){ //* LOCAL:
LONG lSize; //* used to link data size
LPSTR lpLinkData; //* OLE link data pointer
static CHAR pWork[OBJECT_LINK_MAX]; //* used to construct new link data
INT i; //* index
HANDLE hData;
pItem->aLinkName = AddAtom(lpDoc);
for (
lpLinkData = pItem->lpLinkData, i=0;
pWork[i] = *lpLinkData;
lpLinkData++, i++
);
//* into working buffer.
lstrcpy((LPSTR)&pWork[++i],lpDoc); //* copy new document name.
for (; pWork[i]; i++); //* skip to end of document name
for (++lpLinkData;*lpLinkData;lpLinkData++);
//* copy item name.
lstrcpy((LPSTR)&pWork[++i],++lpLinkData);
for (; pWork[i]; i++); //* skip to end of buffer
//* which is the end of item info.
pWork[++i] = 0; //* add extra null.
lSize = SizeOfLinkData(pWork); //* reallocate space so there is
ReallocLinkData(pItem,lSize); //* a properly sized block of info
//* to send the linked data to the
if (lpLinkData = pItem->lpLinkData) //* OLE DLL.
for (i=0; i<(INT)lSize; i++) //* copy new linkdata into this space
*lpLinkData++ = pWork[i];
else
return; //* ERROR return
Error(OleSetData(pItem->lpObject, vcfLink, GlobalHandle(pItem->lpLinkData)));
/*
* The handle passed into OleSetData is owned by the OLE client library
* and should not be used after the call. On win32s, it is inaccessible
* after the call, so restore it by calling OleGetData. Note that the
* data is *still* owned by the library, but we will now have access
* to the memory.
*/
Error(OleGetData(pItem->lpObject, vcfLink, &hData));
if (hData) {
pItem->lpLinkData = GlobalLock(hData);
}
} //* SUCCESS return
/****************************************************************************
* ObjSaveUndo()
*
* Clone the OLE object so that any changes to object can be undone if the
* user choses to exit without update.
***************************************************************************/
VOID FAR ObjSaveUndo( //* ENTRY:
APPITEMPTR pItem //* application item
){ //* LOCAL:
CHAR szTmp[CBOBJNAMEMAX]; //* holder of object name
LPSTR lpClone; //* pointer to clond object name
UINT i=CBOBJNAMEMAX;
if (!pItem->lpObjectUndo)
{
OleQueryName(pItem->lpObject, szTmp, &i);
//* give clone a unique name by
//* altering object name prefix.
for (lpClone = OBJCLONE, i=0; *lpClone; szTmp[i++] = *lpClone++);
if (Error(OleClone(pItem->lpObject, (LPOLECLIENT)pItem,
pItem->lhcDoc, szTmp, &(pItem->lpObjectUndo))))
return; //* ERROR return
pItem->otObjectUndo = pItem->otObject;
pItem->uoObjectUndo = pItem->uoObject;
pItem->aLinkUndo = pItem->aLinkName;
GetClientRect(pItem->hwnd, &pItem->rect);
if (OleQueryOpen(pItem->lpObject) == OLE_OK)
pItem->fOpen = TRUE;
}
} //* SUCCESS return
/****************************************************************************
* ObjUndo()
*
* Restore an object to its state before changes. The lpObject Undo is a
* clone to the original object with a different name, therefore, all we
* have to do is rename that object and ditch the changed object.
***************************************************************************/
VOID FAR ObjUndo( //* ENTRY:
APPITEMPTR pItem //* application item
){ //* LOCAL:
CHAR szTmp[CBOBJNAMEMAX]; //* object name holder
UINT i = CBOBJNAMEMAX;
OleQueryName(pItem->lpObject, szTmp, &i);
if (Error(OleDelete(pItem->lpObject)))
return; //* ERROR return
//* reset app item vars
pItem->lpObject = pItem->lpObjectUndo;
pItem->otObject = pItem->otObjectUndo;
pItem->uoObject = pItem->uoObjectUndo;
pItem->aLinkName = pItem->aLinkUndo;
pItem->lpObjectUndo = (LPOLEOBJECT)NULL;
pItem->otObjectUndo = (LONG)NULL;
if (Error(OleRename(pItem->lpObject,szTmp)))
return; //* ERROR return
if (pItem->fOpen)
{
Error(OleReconnect(pItem->lpObject));
pItem->fOpen = FALSE;
}
SetWindowPos(
pItem->hwnd,
NULL, 0, 0,
pItem->rect.right - pItem->rect.left + 2*GetSystemMetrics(SM_CXFRAME),
pItem->rect.bottom - pItem->rect.top + 2*GetSystemMetrics(SM_CYFRAME),
SWP_NOZORDER | SWP_NOMOVE | SWP_DRAWFRAME
);
InvalidateRect(pItem->hwnd,NULL,TRUE);
} //* SUCCESS return
/****************************************************************************
* ObjDelUndo()
*
* Delete the undo object if the user is happy with the changes he/she made.
***************************************************************************/
VOID FAR ObjDelUndo( //* ENTRY:
APPITEMPTR pItem //* application item
){
if (Error(OleDelete(pItem->lpObjectUndo)))
return; //* ERROR return
pItem->lpObjectUndo = (LPOLEOBJECT)NULL;
pItem->otObjectUndo = (LONG)NULL;
DeleteAtom(pItem->aLinkUndo);
pItem->lpObjectUndo = NULL;
} //* SUCCESS return
/****************************************************************************
* ObjFreeze()
*
* Convert an object to a static object.
***************************************************************************/
VOID FAR ObjFreeze( //* ENTRY:
APPITEMPTR pItem //* application item
){ //* LOCAL:
CHAR szTmp[CBOBJNAMEMAX]; //* temporary object name
LPSTR lpTemp; //* temporary prefix string
LPOLEOBJECT lpObjectTmp; //* temporary object pointer
UINT i=CBOBJNAMEMAX;
OleQueryName(pItem->lpObject, szTmp, &i);
//* create a unique name by changing
//* the object name prefix
for (lpTemp = OBJTEMP, i=0; *lpTemp; szTmp[i++] = *lpTemp++);
//* this API creates a static object
if (Error(OleObjectConvert(pItem->lpObject, STATICP, (LPOLECLIENT)pItem,
pItem->lhcDoc, szTmp, &lpObjectTmp)))
return;
//* delete old object
if (Error(OleDelete(pItem->lpObject)))
return;
WaitForObject(pItem);
pItem->lpObject = lpObjectTmp;
pItem->otObject = OT_STATIC;
pItem->uoObject = -1L;
for (lpTemp = OBJPREFIX, i=0; *lpTemp; szTmp[i++] = *lpTemp++);
if (Error(OleRename(pItem->lpObject,szTmp)))
return;
}
/***************************************************************************
* ObjCreateWrap()
*
* Create a wrapped object from the drag and drop feature of the 3.1 shell.
* NOTE: We are assuming that only one file has been dropped. See the SDK
* documentation for instructions on how to deal with multiple files.
***************************************************************************/
VOID FAR ObjCreateWrap( //* ENTRY:
HANDLE hdrop, //* handle to dropped object
LHCLIENTDOC lhcDoc, //* document handle
LPOLECLIENT lpClient //* pointer to client structure
){ //* LOCAL:
CHAR szDragDrop[CBPATHMAX];//* Drag and drop file name
LPOLEOBJECT lpObject; //* pointer to OLE object
POINT pt; //* position of dropped object
RECT rc; //* object size and position
CHAR szTmp[CBOBJNAMEMAX]; //* buffer for unique object name
APPITEMPTR pItem; //* application item pointer
INT x,y; //* icon sizes
x = GetSystemMetrics(SM_CXICON) / 2;
y = GetSystemMetrics(SM_CYICON) / 2;
//* Get the drag and drop filename
//* position
DragQueryPoint(hdrop, &pt);
DragQueryFile(hdrop, 0, szDragDrop, CBPATHMAX);
DragFinish(hdrop);
SetRect(&rc, pt.x - x, pt.y - y, pt.x + x, pt.y + y);
if (!(pItem = PreItemCreate(lpClient, TRUE, lhcDoc)))
return; //* ERROR return
//* create OLE object
if (Error(OleCreateFromFile(STDFILEEDITING, (LPOLECLIENT)pItem,
"Package", szDragDrop, lhcDoc, CreateNewUniqueName(szTmp),
&lpObject, olerender_draw, 0)))
{
ErrorMessage(E_FAILED_TO_CREATE_OBJECT);
FreeAppItem(pItem);
return; //* ERROR return
}
if (PostItemCreate(lpObject, OT_EMBEDDED, &rc, pItem))
ShowNewWindow(pItem);
} //* SUCCESS return
/***************************************************************************
* UpdateObjectMenuItem()
*
* Add an object popup menu for the chosen object if multiple verbs exist.
* The registration system is used to determine which verbs exist for the
* given object.
**************************************************************************/
VOID FAR UpdateObjectMenuItem( //* ENTRY:
HMENU hMenu //* main menu
){ //* LOCAL
INT cVerbs; //* verb
APPITEMPTR pItem; //* application item ponter
DWORD dwSize = KEYNAMESIZE;
CHAR szClass[KEYNAMESIZE], szBuffer[200];
CHAR szVerb[KEYNAMESIZE];
HMENU hPopupNew=NULL;
HKEY hkeyTemp;
CHAR pLinkData[OBJECT_LINK_MAX];
//* delete current item and submenu
DeleteMenu(hMenu, POS_OBJECT, MF_BYPOSITION );
if (!(pItem = GetTopItem()) )
goto Error; //* ERROR jump
else if (!pItem->fVisible)
goto Error; //* ERROR jump
//* if STATIC ?
if ((pItem->otObject != OT_EMBEDDED) && (pItem->otObject != OT_LINK))
goto Error; //* ERROR jump
if (!ObjGetData(pItem, pLinkData)) //* get linkdata as key reg database
goto Error; //* ERROR jump
//* open reg database
szClass[0] = 0;
if (RegOpenKey(HKEY_CLASSES_ROOT, szClass, &hkeyTemp))
goto Error; //* ERROR jump
//* check if class is reg-db
if (RegQueryValue(HKEY_CLASSES_ROOT, pLinkData, szClass, &dwSize))
{
RegCloseKey(hkeyTemp);
goto Error; //* ERROR jump
}
for (cVerbs=0; ;++cVerbs) //* extract all verbs from reg-db
{
dwSize = KEYNAMESIZE;
wsprintf(szBuffer, "%s\\protocol\\StdFileEditing\\verb\\%d",
(LPSTR)pLinkData,cVerbs);
if (RegQueryValue(HKEY_CLASSES_ROOT, szBuffer, szVerb, &dwSize))
break;
if (!hPopupNew)
hPopupNew = CreatePopupMenu();
InsertMenu(hPopupNew, (UINT)-1, MF_BYPOSITION, IDM_VERBMIN+cVerbs, szVerb);
}
//* NOTE: For International versions the following verb menu
//* may need to be formatted differently.
switch (cVerbs) //* determine how many verbs found
{
case 0: //* none
wsprintf(szBuffer, "Edit %s %s", (LPSTR)szClass, (LPSTR)"&Object");
InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, IDM_VERBMIN, szBuffer);
break;
case 1: //* one
wsprintf(szBuffer, "%s %s %s", (LPSTR)szVerb, (LPSTR)szClass,
(LPSTR)"&Object");
DestroyMenu(hPopupNew);
InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, IDM_VERBMIN, szBuffer);
break;
default: //* > 1
wsprintf(szBuffer, "%s %s", (LPSTR)szClass, (LPSTR)"&Object");
InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION | MF_POPUP, (UINT)hPopupNew, szBuffer);
EnableMenuItem(hMenu, POS_OBJECT, MF_ENABLED|MF_BYPOSITION);
break;
}
RegCloseKey(hkeyTemp); //* close reg-db
return; //* SUCCESS return
Error: //* ERROR tag
InsertMenu(hMenu, POS_OBJECT, MF_BYPOSITION, 0, "&Object");
EnableMenuItem(hMenu, POS_OBJECT, MF_GRAYED | MF_BYPOSITION);
} //* ERROR return
/***************************************************************************
* ExecuteVerb()
*
* Execute the verb for the given object.
***************************************************************************/
VOID FAR ExecuteVerb( //* ENTRY:
UINT iVerb, //* verb
APPITEMPTR pItem //* application item pointer
){ //* LOCAL
RECT rc; //* holds client area bounding rect
if (pItem->otObject == OT_STATIC) //* if the object is static beep
{
ErrorMessage(W_STATIC_OBJECT);
return; //* return
}
//* get cliet area rectangle
GetClientRect(hwndFrame, (LPRECT)&rc);
//* execute OLE verb
if (Error(OleActivate(pItem->lpObject, iVerb, TRUE, TRUE, hwndFrame, &rc)))
return;
WaitForObject(pItem); //* wait for async. operation
ObjSetBounds(pItem);
} //* SUCCESS return
/****************************************************************************
* ObjSetBounds
*
* Set the object bounds. The object bounds are the child windos bounding
* rectangle. OLE servers recieve need the bounding rectangle in HIMETRIC
* coordinates. So, we convert from screen coordinates to HIMETRIC.
*
* Returns BOOL - TRUE if successful.
***************************************************************************/
BOOL FAR ObjSetBounds( //* ENTRY:
APPITEMPTR pItem //* application item pointer
){ //* LOCAL:
RECT itemRect; //* bounding rectangle
GetWindowRect(pItem->hwnd,&itemRect);//* get item window react
itemRect.right -= GetSystemMetrics(SM_CXFRAME);
itemRect.left += GetSystemMetrics(SM_CXFRAME);
itemRect.top += GetSystemMetrics(SM_CYFRAME);
itemRect.bottom -= GetSystemMetrics(SM_CYFRAME);
itemRect.right = MulDiv ((itemRect.right - itemRect.left),
HIMETRIC_PER_INCH, giXppli);
itemRect.bottom = - MulDiv((itemRect.bottom - itemRect.top),
HIMETRIC_PER_INCH, giYppli);
itemRect.top = 0;
itemRect.left = 0;
//* set the rect for the server
if (Error(OleSetBounds(pItem->lpObject,(LPRECT)&itemRect)))
return FALSE; //* ERROR return
WaitForObject(pItem); //* wait for async. operation
return TRUE; //* SUCCESS return
}