|
|
/*
* 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, fnInsertNew, (LPARAM)((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
}
|