979 lines
23 KiB
C
979 lines
23 KiB
C
|
/* picture.c - This file contains OLE object handling routines.
|
||
|
*
|
||
|
* Created by Microsoft Corporation.
|
||
|
*/
|
||
|
|
||
|
#include "packager.h"
|
||
|
#include "dialogs.h"
|
||
|
|
||
|
|
||
|
static OLECLIENTVTBL clientTbl;
|
||
|
static OLESTREAMVTBL streamTbl;
|
||
|
|
||
|
|
||
|
static VOID PicGetBounds(LPOLEOBJECT lpObject, LPRECT lprc);
|
||
|
|
||
|
/* InitClient() - Initialize the OLE client structures.
|
||
|
*/
|
||
|
BOOL
|
||
|
InitClient(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
gcfFileName = (OLECLIPFORMAT)RegisterClipboardFormat("FileName");
|
||
|
gcfLink = (OLECLIPFORMAT)RegisterClipboardFormat("ObjectLink");
|
||
|
gcfNative = (OLECLIPFORMAT)RegisterClipboardFormat("Native");
|
||
|
gcfOwnerLink = (OLECLIPFORMAT)RegisterClipboardFormat("OwnerLink");
|
||
|
|
||
|
glpclient = PicCreateClient(&CallBack, (LPOLECLIENTVTBL)&clientTbl);
|
||
|
|
||
|
if (!(glpStream = (LPAPPSTREAM)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(APPSTREAM))))
|
||
|
goto Error;
|
||
|
|
||
|
glpStream->lpstbl = (LPOLESTREAMVTBL)&streamTbl;
|
||
|
streamTbl.Get = (DWORD (CALLBACK*)(LPOLESTREAM, void FAR*, DWORD))ReadStream;
|
||
|
streamTbl.Put = (DWORD (CALLBACK*)(LPOLESTREAM, OLE_CONST void FAR*, DWORD))WriteStream;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
Error:
|
||
|
if (glpStream)
|
||
|
{
|
||
|
GlobalFree(glpStream);
|
||
|
glpStream = NULL;
|
||
|
}
|
||
|
|
||
|
if (glpclient)
|
||
|
{
|
||
|
GlobalFree(glpclient);
|
||
|
glpclient = NULL;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* EndClient() - Clean up for termination.
|
||
|
*/
|
||
|
VOID
|
||
|
EndClient(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
if (glpStream)
|
||
|
{
|
||
|
GlobalFree(glpStream);
|
||
|
glpStream = NULL;
|
||
|
}
|
||
|
|
||
|
if (glpclient)
|
||
|
{
|
||
|
GlobalFree(glpclient);
|
||
|
glpclient = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicCreate() -
|
||
|
*/
|
||
|
LPPICT
|
||
|
PicCreate(
|
||
|
LPOLEOBJECT lpObject,
|
||
|
LPRECT lprcObject
|
||
|
)
|
||
|
{
|
||
|
HANDLE hpict = NULL;
|
||
|
LPPICT lppict = NULL;
|
||
|
RECT rc;
|
||
|
|
||
|
if (lpObject)
|
||
|
{
|
||
|
if (!(hpict = GlobalAlloc(GMEM_MOVEABLE, sizeof(PICT)))
|
||
|
|| !(lppict = (LPPICT)GlobalLock(hpict)))
|
||
|
goto errRtn;
|
||
|
|
||
|
//
|
||
|
// If size of window is specified, use it; otherwise, retrieve
|
||
|
// the size of the item synchronously.
|
||
|
//
|
||
|
if (lprcObject)
|
||
|
rc = *lprcObject;
|
||
|
else {
|
||
|
SetRectEmpty(&rc);
|
||
|
PicGetBounds(lpObject, &rc);
|
||
|
}
|
||
|
|
||
|
// Store the data in the window itself
|
||
|
lppict->hdata = hpict;
|
||
|
lppict->lpObject = lpObject;
|
||
|
lppict->rc = rc;
|
||
|
lppict->fNotReady = FALSE;
|
||
|
}
|
||
|
|
||
|
return lppict;
|
||
|
|
||
|
errRtn:
|
||
|
ErrorMessage(E_FAILED_TO_CREATE_CHILD_WINDOW);
|
||
|
|
||
|
if (lppict)
|
||
|
GlobalUnlock(hpict);
|
||
|
|
||
|
if (hpict)
|
||
|
GlobalFree(hpict);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicDelete() - Deletes an object (called when the item window is destroyed).
|
||
|
*/
|
||
|
VOID
|
||
|
PicDelete(
|
||
|
LPPICT lppict
|
||
|
)
|
||
|
{
|
||
|
HANDLE hdata;
|
||
|
LPOLEOBJECT lpObject;
|
||
|
|
||
|
if (!lppict)
|
||
|
return;
|
||
|
|
||
|
if (lppict && lppict->lpObject)
|
||
|
{
|
||
|
lpObject = lppict->lpObject;
|
||
|
lppict->lpObject = NULL;
|
||
|
// Wait until the object isn't busy
|
||
|
WaitForObject(lpObject);
|
||
|
|
||
|
if (Error(OleDelete(lpObject)))
|
||
|
ErrorMessage(E_FAILED_TO_DELETE_OBJECT);
|
||
|
|
||
|
// Wait until the object deletion is complete
|
||
|
WaitForObject(lpObject);
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(hdata = lppict->hdata);
|
||
|
GlobalFree(hdata);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicDraw() - Draws the item associated with hwnd in the DC hDC.
|
||
|
*/
|
||
|
BOOL
|
||
|
PicDraw(
|
||
|
LPPICT lppict,
|
||
|
HDC hDC,
|
||
|
LPRECT lprc,
|
||
|
INT xHSB,
|
||
|
INT yVSB,
|
||
|
BOOL fPicture,
|
||
|
BOOL fFocus
|
||
|
)
|
||
|
{
|
||
|
BOOL fSuccess = FALSE;
|
||
|
DWORD ot;
|
||
|
HANDLE hdata;
|
||
|
HFONT hfont;
|
||
|
LPOLEOBJECT lpObjectUndo;
|
||
|
LPSTR lpdata;
|
||
|
RECT rc;
|
||
|
RECT rcFocus;
|
||
|
CHAR szDesc[CBMESSAGEMAX];
|
||
|
CHAR szFileName[CBPATHMAX];
|
||
|
CHAR szMessage[CBMESSAGEMAX + CBPATHMAX];
|
||
|
INT iDelta;
|
||
|
INT iPane;
|
||
|
|
||
|
iPane = (lppict == glpobj[CONTENT]);
|
||
|
lpObjectUndo = (gptyUndo[iPane] == PICTURE)
|
||
|
? ((LPPICT)glpobjUndo[iPane])->lpObject : NULL;
|
||
|
|
||
|
// If drawing the Picture, offset by scroll bars and draw
|
||
|
if (fPicture)
|
||
|
{
|
||
|
if (IsRectEmpty(&(lppict->rc)))
|
||
|
PicGetBounds(lppict->lpObject, &(lppict->rc));
|
||
|
|
||
|
rc = lppict->rc;
|
||
|
|
||
|
// If image is smaller than pane, center horizontally
|
||
|
if ((iDelta = lprc->right - lppict->rc.right) > 0)
|
||
|
OffsetRect(&rc, iDelta >> 1, 0);
|
||
|
else /* else, use the scroll bar value */
|
||
|
OffsetRect(&rc, -xHSB, 0);
|
||
|
|
||
|
// If image is smaller than pane, center vertically
|
||
|
if ((iDelta = lprc->bottom - lppict->rc.bottom) > 0)
|
||
|
OffsetRect(&rc, 0, iDelta >> 1);
|
||
|
else /* else, use the scroll bar value */
|
||
|
OffsetRect(&rc, 0, -yVSB);
|
||
|
|
||
|
// If we have an object, call OleDraw()
|
||
|
fSuccess = !Error(OleDraw(lppict->lpObject, hDC, &rc, NULL, NULL));
|
||
|
|
||
|
if (fFocus)
|
||
|
DrawFocusRect(hDC, &rc);
|
||
|
|
||
|
return fSuccess;
|
||
|
}
|
||
|
|
||
|
// Otherwise, draw the description string
|
||
|
OleQueryType(lppict->lpObject, &ot);
|
||
|
|
||
|
if ((ot == OT_LINK
|
||
|
&& Error(OleGetData(lppict->lpObject, gcfLink, &hdata)))
|
||
|
|| (ot == OT_EMBEDDED
|
||
|
&& Error(OleGetData(lppict->lpObject, gcfOwnerLink, &hdata)))
|
||
|
|| (ot == OT_STATIC
|
||
|
&& (!lpObjectUndo || Error(OleGetData(lpObjectUndo, gcfOwnerLink,
|
||
|
&hdata)))))
|
||
|
{
|
||
|
LoadString(ghInst, IDS_OBJECT, szFileName, CBMESSAGEMAX);
|
||
|
LoadString(ghInst, IDS_FROZEN, szDesc, CBMESSAGEMAX);
|
||
|
goto DrawString;
|
||
|
}
|
||
|
|
||
|
if (hdata && (lpdata = GlobalLock(hdata)))
|
||
|
{
|
||
|
switch (ot)
|
||
|
{
|
||
|
case OT_LINK:
|
||
|
while (*lpdata++)
|
||
|
;
|
||
|
|
||
|
// return value ignored
|
||
|
if(SUCCEEDED(StringCchCopy(szFileName, ARRAYSIZE(szFileName), lpdata)))
|
||
|
{
|
||
|
Normalize(szFileName);
|
||
|
LoadString(ghInst, IDS_LINKTOFILE, szDesc, CBMESSAGEMAX);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OT_EMBEDDED:
|
||
|
RegGetClassId(szFileName, ARRAYSIZE(szFileName), lpdata);
|
||
|
LoadString(ghInst, IDS_EMBEDFILE, szDesc, CBMESSAGEMAX);
|
||
|
break;
|
||
|
|
||
|
case OT_STATIC:
|
||
|
RegGetClassId(szFileName, ARRAYSIZE(szFileName), lpdata);
|
||
|
LoadString(ghInst, IDS_FROZEN, szDesc, CBMESSAGEMAX);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
GlobalUnlock(hdata);
|
||
|
|
||
|
DrawString:
|
||
|
if(SUCCEEDED(StringCchPrintf(szMessage, ARRAYSIZE(szMessage), szDesc, szFileName))) // return value ignored
|
||
|
{
|
||
|
|
||
|
hfont = SelectObject(hDC, ghfontChild);
|
||
|
DrawText(hDC, szMessage, -1, lprc,
|
||
|
DT_NOPREFIX | DT_CENTER | DT_VCENTER | DT_SINGLELINE);
|
||
|
|
||
|
if (fFocus)
|
||
|
{
|
||
|
rcFocus = *lprc;
|
||
|
DrawText(hDC, szMessage, -1, &rcFocus,
|
||
|
DT_CALCRECT | DT_NOPREFIX | DT_LEFT | DT_TOP | DT_SINGLELINE);
|
||
|
OffsetRect(&rcFocus, (lprc->left + lprc->right - rcFocus.right) / 2,
|
||
|
(lprc->top + lprc->bottom - rcFocus.bottom) / 2);
|
||
|
DrawFocusRect(hDC, &rcFocus);
|
||
|
}
|
||
|
|
||
|
if (hfont)
|
||
|
SelectObject(hDC, hfont);
|
||
|
|
||
|
fSuccess = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fSuccess;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicPaste() - Retrieves an object from the clipboard.
|
||
|
*/
|
||
|
LPPICT
|
||
|
PicPaste(
|
||
|
BOOL fPaste,
|
||
|
LPSTR lpstrName
|
||
|
)
|
||
|
{
|
||
|
LPOLEOBJECT lpObject;
|
||
|
|
||
|
if (!OpenClipboard(ghwndFrame))
|
||
|
return NULL; /* Couldn't open the clipboard */
|
||
|
|
||
|
Hourglass(TRUE);
|
||
|
|
||
|
// Don't replace the current object unless we're successful
|
||
|
if (fPaste)
|
||
|
{
|
||
|
if (Error(OleCreateFromClip(gszProtocol, glpclient, glhcdoc, lpstrName,
|
||
|
&lpObject, olerender_draw, 0)))
|
||
|
{
|
||
|
if (Error(OleCreateFromClip(gszSProtocol, glpclient, glhcdoc,
|
||
|
lpstrName, &lpObject, olerender_draw, 0)))
|
||
|
lpObject = NULL;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else if (Error(OleCreateLinkFromClip(
|
||
|
gszProtocol, glpclient, glhcdoc, lpstrName, &lpObject,
|
||
|
olerender_draw, 0)))
|
||
|
{
|
||
|
lpObject = NULL;
|
||
|
}
|
||
|
|
||
|
CloseClipboard();
|
||
|
Hourglass(FALSE);
|
||
|
|
||
|
if (!lpObject)
|
||
|
return NULL;
|
||
|
|
||
|
return PicCreate(lpObject, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Error() - check for OLE function error conditions
|
||
|
*
|
||
|
* This function increments gcOleWait as appropriate.
|
||
|
*
|
||
|
* Pre: Initialize ghwndError to where the focus should return.
|
||
|
*
|
||
|
* Returns: TRUE if an immediate error occurred.
|
||
|
*/
|
||
|
BOOL
|
||
|
Error(
|
||
|
OLESTATUS olestat
|
||
|
)
|
||
|
{
|
||
|
DWORD ot;
|
||
|
INT iPane;
|
||
|
|
||
|
switch (olestat)
|
||
|
{
|
||
|
case OLE_WAIT_FOR_RELEASE:
|
||
|
gcOleWait++;
|
||
|
return FALSE;
|
||
|
|
||
|
case OLE_OK:
|
||
|
return FALSE;
|
||
|
|
||
|
case OLE_ERROR_STATIC: /* Only happens w/ dbl click */
|
||
|
ErrorMessage(W_STATIC_OBJECT);
|
||
|
break;
|
||
|
|
||
|
case OLE_ERROR_ADVISE_PICT:
|
||
|
case OLE_ERROR_OPEN: /* Invalid link? */
|
||
|
case OLE_ERROR_NAME:
|
||
|
iPane = (GetTopWindow(ghwndFrame) == ghwndPane[CONTENT]);
|
||
|
if ((LPPICT)glpobj[iPane] == NULL)
|
||
|
{
|
||
|
ErrorMessage(E_FAILED_TO_CREATE_OBJECT);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OleQueryType(((LPPICT)glpobj[iPane])->lpObject, &ot);
|
||
|
if (ot == OT_LINK)
|
||
|
{
|
||
|
if (ghwndError == ghwndFrame)
|
||
|
{
|
||
|
if (DialogBoxAfterBlock (
|
||
|
MAKEINTRESOURCE(DTINVALIDLINK), ghwndError,
|
||
|
fnInvalidLink) == IDD_CHANGE)
|
||
|
PostMessage(ghwndFrame, WM_COMMAND, IDM_LINKS, 0L);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Failed, but already in Link Properties!!
|
||
|
ErrorMessage(E_FAILED_TO_UPDATE_LINK);
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* CallBack() - Routine that OLE client DLL calls when events occur.
|
||
|
*
|
||
|
* This routine is called when the object has been updated and may
|
||
|
* need to be redisplayed; if asynchronous operations have completed;
|
||
|
* and if the application allows the user to cancel long operations
|
||
|
* (like Painting, or other asynchronous operations).
|
||
|
*/
|
||
|
INT CALLBACK
|
||
|
CallBack(
|
||
|
LPOLECLIENT lpclient,
|
||
|
OLE_NOTIFICATION flags,
|
||
|
LPOLEOBJECT lpObject
|
||
|
)
|
||
|
{
|
||
|
INT iPane;
|
||
|
|
||
|
switch (flags)
|
||
|
{
|
||
|
case OLE_CLOSED:
|
||
|
if (gfInvisible)
|
||
|
PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
|
||
|
else
|
||
|
SetFocus(ghwndError);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case OLE_SAVED:
|
||
|
case OLE_CHANGED:
|
||
|
{
|
||
|
//
|
||
|
// The OLE libraries make sure that we only receive
|
||
|
// update messages according to the Auto/Manual flags.
|
||
|
//
|
||
|
iPane = (gpty[CONTENT] == PICTURE
|
||
|
&& ((LPPICT)glpobj[CONTENT])->lpObject == lpObject);
|
||
|
|
||
|
if (gpty[iPane] == PICTURE)
|
||
|
{
|
||
|
((LPPICT)glpobj[iPane])->fNotReady = FALSE;
|
||
|
InvalidateRect(ghwndPane[iPane], NULL, TRUE);
|
||
|
SetRect(&(((LPPICT)glpobj[iPane])->rc), 0, 0, 0, 0);
|
||
|
Dirty();
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case OLE_RELEASE:
|
||
|
{
|
||
|
if (gcOleWait)
|
||
|
gcOleWait--;
|
||
|
else
|
||
|
ErrorMessage(E_UNEXPECTED_RELEASE);
|
||
|
|
||
|
switch (Error(OleQueryReleaseError(lpObject)))
|
||
|
{
|
||
|
case FALSE:
|
||
|
switch (OleQueryReleaseMethod(lpObject))
|
||
|
{
|
||
|
case OLE_SETUPDATEOPTIONS:
|
||
|
iPane = (gpty[CONTENT] == PICTURE
|
||
|
&& ((LPPICT)glpobj[CONTENT])->lpObject ==
|
||
|
lpObject);
|
||
|
|
||
|
PostMessage(ghwndPane[iPane], WM_COMMAND,
|
||
|
IDM_LINKDONE, 0L);
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case TRUE:
|
||
|
switch (OleQueryReleaseMethod(lpObject))
|
||
|
{
|
||
|
case OLE_DELETE:
|
||
|
ErrorMessage(E_FAILED_TO_DELETE_OBJECT);
|
||
|
break;
|
||
|
|
||
|
case OLE_LOADFROMSTREAM:
|
||
|
ErrorMessage(E_FAILED_TO_READ_OBJECT);
|
||
|
break;
|
||
|
|
||
|
case OLE_LNKPASTE:
|
||
|
ErrorMessage(E_GET_FROM_CLIPBOARD_FAILED);
|
||
|
break;
|
||
|
|
||
|
case OLE_ACTIVATE:
|
||
|
ErrorMessage(E_FAILED_TO_LAUNCH_SERVER);
|
||
|
break;
|
||
|
|
||
|
case OLE_UPDATE:
|
||
|
ErrorMessage(E_FAILED_TO_UPDATE);
|
||
|
break;
|
||
|
|
||
|
case OLE_RECONNECT:
|
||
|
ErrorMessage(E_FAILED_TO_RECONNECT_OBJECT);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case OLE_QUERY_RETRY:
|
||
|
// if lpObject doesn't match any one of these 4 objects, it means
|
||
|
// that PicDelete() has been called on lpObject, so there is no
|
||
|
// point in continueing the RETRIES.
|
||
|
// See PicDelete() code for more info.
|
||
|
if ((glpobj[CONTENT]
|
||
|
&& lpObject == ((LPPICT)glpobj[CONTENT])->lpObject)
|
||
|
|| (glpobj[APPEARANCE]
|
||
|
&& lpObject == ((LPPICT) glpobj[APPEARANCE])->lpObject)
|
||
|
|| (glpobjUndo[CONTENT]
|
||
|
&& lpObject == ((LPPICT) glpobjUndo[CONTENT])->lpObject)
|
||
|
|| (glpobjUndo[APPEARANCE]
|
||
|
&& lpObject == ((LPPICT) glpobjUndo[APPEARANCE])->lpObject))
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
case OLE_QUERY_PAINT:
|
||
|
return TRUE;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* WaitForObject() - Waits, dispatching messages, until the object is free.
|
||
|
*
|
||
|
* If the object is busy, spin in a dispatch loop.
|
||
|
*/
|
||
|
VOID
|
||
|
WaitForObject(
|
||
|
LPOLEOBJECT lpObject
|
||
|
)
|
||
|
{
|
||
|
while (OleQueryReleaseStatus(lpObject) == OLE_BUSY)
|
||
|
ProcessMessage();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicSetUpdateOptions() - Sets the update options of the object.
|
||
|
*
|
||
|
* Returns: TRUE if the command completed synchronously.
|
||
|
*/
|
||
|
BOOL
|
||
|
PicSetUpdateOptions(
|
||
|
LPPICT lppict,
|
||
|
UINT idCmd
|
||
|
)
|
||
|
{
|
||
|
OLESTATUS olestat = OLE_ERROR_GENERIC;
|
||
|
|
||
|
olestat = OleSetLinkUpdateOptions(
|
||
|
lppict->lpObject,
|
||
|
(idCmd == IDD_AUTO) ? oleupdate_always : oleupdate_oncall);
|
||
|
|
||
|
if (Error(olestat))
|
||
|
ErrorMessage(E_FAILED_TO_UPDATE_LINK);
|
||
|
|
||
|
return (olestat == OLE_OK);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicReadFromNative() - Reads an object from the pointer lpstr.
|
||
|
*
|
||
|
* SIDE EFFECT: Advances the pointer past the object.
|
||
|
*/
|
||
|
LPPICT
|
||
|
PicReadFromNative(
|
||
|
LPSTR *lplpstr,
|
||
|
LPSTR lpstrName
|
||
|
)
|
||
|
{
|
||
|
LPOLEOBJECT lpObject;
|
||
|
LPSTR lpstrStart;
|
||
|
RECT rcObject;
|
||
|
WORD w;
|
||
|
|
||
|
// Save current position of file pointer
|
||
|
lpstrStart = *lplpstr;
|
||
|
SetFile(SOP_MEMORY, 0, lplpstr);
|
||
|
|
||
|
// Load the new object
|
||
|
if (Error(OleLoadFromStream((LPOLESTREAM)glpStream, gszProtocol, glpclient,
|
||
|
glhcdoc, lpstrName, &lpObject)))
|
||
|
{
|
||
|
// Reset file pointer, and try again
|
||
|
*lplpstr = lpstrStart;
|
||
|
SetFile(SOP_MEMORY, 0, lplpstr);
|
||
|
|
||
|
// Read it with the "Static" protocol
|
||
|
if (Error(OleLoadFromStream((LPOLESTREAM)glpStream, gszSProtocol,
|
||
|
glpclient, glhcdoc, lpstrName, &lpObject)))
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
rcObject.left = (INT)w;
|
||
|
MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
rcObject.top = (INT)w;
|
||
|
MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
rcObject.right = (INT)w;
|
||
|
MemRead(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
rcObject.bottom = (INT)w;
|
||
|
|
||
|
// Create a window at the right place, and display the object
|
||
|
return PicCreate(lpObject, &rcObject);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicWriteToNative() - Writes an object to memory.
|
||
|
*
|
||
|
* SIDE EFFECT: Moves pointer to end of written object
|
||
|
*/
|
||
|
DWORD
|
||
|
PicWriteToNative(
|
||
|
LPPICT lppict,
|
||
|
LPOLEOBJECT lpObject,
|
||
|
LPSTR *lplpstr
|
||
|
)
|
||
|
{
|
||
|
DWORD cb = 0L;
|
||
|
WORD w;
|
||
|
|
||
|
// Save the object
|
||
|
SetFile(SOP_MEMORY, 0, lplpstr);
|
||
|
|
||
|
if (Error(OleSaveToStream(lpObject, (LPOLESTREAM)glpStream)))
|
||
|
goto Done;
|
||
|
|
||
|
cb += gcbObject;
|
||
|
|
||
|
if (lplpstr)
|
||
|
{
|
||
|
w = (WORD)lppict->rc.left;
|
||
|
MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
w = (WORD)lppict->rc.top;
|
||
|
MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
w = (WORD)lppict->rc.right;
|
||
|
MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
w = (WORD)lppict->rc.bottom;
|
||
|
MemWrite(lplpstr, (LPSTR)&w, sizeof(WORD));
|
||
|
}
|
||
|
|
||
|
cb += (DWORD)(4 * sizeof(WORD));
|
||
|
|
||
|
Done:
|
||
|
return cb;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* Hourglass() - Puts up the hourglass as needed.
|
||
|
*/
|
||
|
VOID
|
||
|
Hourglass(
|
||
|
BOOL fOn
|
||
|
)
|
||
|
{
|
||
|
static HCURSOR hcurSaved = NULL; // Cursor saved when hourglass is up
|
||
|
static UINT cWait = 0; // Number of "Hourglass"es up
|
||
|
|
||
|
if (fOn)
|
||
|
{
|
||
|
if (!(cWait++))
|
||
|
hcurSaved = SetCursor(ghcurWait);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!(--cWait) && hcurSaved)
|
||
|
{
|
||
|
SetCursor(hcurSaved);
|
||
|
hcurSaved = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PicActivate(
|
||
|
LPPICT lppict,
|
||
|
UINT idCmd
|
||
|
)
|
||
|
{
|
||
|
DWORD ot;
|
||
|
DWORD ot2;
|
||
|
RECT rc;
|
||
|
INT iPane;
|
||
|
BOOL bAlreadyOpen = FALSE;
|
||
|
|
||
|
iPane = (lppict == glpobj[CONTENT]);
|
||
|
OleQueryType(lppict->lpObject, &ot);
|
||
|
if (ot != OT_STATIC)
|
||
|
{
|
||
|
// Compute the window dimensions
|
||
|
GetClientRect(ghwndPane[iPane], &rc);
|
||
|
bAlreadyOpen = (OleQueryOpen(lppict->lpObject) == OLE_OK);
|
||
|
|
||
|
// Open the object
|
||
|
if (Error(OleActivate(lppict->lpObject,
|
||
|
(idCmd == IDD_PLAY ? OLE_PLAY : OLE_EDIT),
|
||
|
TRUE, TRUE, ghwndPane[iPane], &rc)))
|
||
|
{
|
||
|
ErrorMessage(E_FAILED_TO_LAUNCH_SERVER);
|
||
|
goto errRtn;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
WaitForObject(lppict->lpObject);
|
||
|
if (!glpobj[iPane])
|
||
|
goto errRtn;
|
||
|
|
||
|
OleQueryType(lppict->lpObject, &ot2);
|
||
|
if (ot2 == OT_EMBEDDED)
|
||
|
Error(OleSetHostNames(lppict->lpObject, gszAppClassName,
|
||
|
(iPane == CONTENT) ? szContent : szAppearance));
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ErrorMessage(W_STATIC_OBJECT);
|
||
|
}
|
||
|
|
||
|
errRtn:
|
||
|
if (gfInvisible && !bAlreadyOpen)
|
||
|
PostMessage(ghwndFrame, WM_SYSCOMMAND, SC_CLOSE, 0L);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PicUpdate(
|
||
|
LPPICT lppict
|
||
|
)
|
||
|
{
|
||
|
DWORD ot;
|
||
|
|
||
|
OleQueryType(lppict->lpObject, &ot);
|
||
|
if (ot == OT_LINK)
|
||
|
{
|
||
|
if (Error(OleUpdate(lppict->lpObject)))
|
||
|
ErrorMessage(E_FAILED_TO_UPDATE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PicFreeze(
|
||
|
LPPICT lppict
|
||
|
)
|
||
|
{
|
||
|
DWORD ot;
|
||
|
LPOLEOBJECT lpObject;
|
||
|
INT iPane;
|
||
|
|
||
|
iPane = (lppict == glpobj[CONTENT]);
|
||
|
OleQueryType(lppict->lpObject, &ot);
|
||
|
if (ot != OT_STATIC)
|
||
|
{
|
||
|
if (Error(OleObjectConvert(lppict->lpObject, gszSProtocol, glpclient,
|
||
|
glhcdoc, gszCaption[iPane], &lpObject)))
|
||
|
{
|
||
|
ErrorMessage(E_FAILED_TO_FREEZE);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (Error(OleDelete(lppict->lpObject)))
|
||
|
ErrorMessage(E_FAILED_TO_DELETE_OBJECT);
|
||
|
|
||
|
lppict->lpObject = lpObject;
|
||
|
|
||
|
// Redraw the list box contents
|
||
|
PostMessage(ghwndError, WM_REDRAW, 0, 0L);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PicChangeLink(
|
||
|
LPPICT lppict
|
||
|
)
|
||
|
{
|
||
|
HANDLE hData;
|
||
|
OLESTATUS olestat;
|
||
|
|
||
|
// Change the link information
|
||
|
olestat = OleGetData(lppict->lpObject, gcfLink, &hData);
|
||
|
if (!Error(olestat) && hData)
|
||
|
{
|
||
|
hData = OfnGetNewLinkName(ghwndError, hData);
|
||
|
if (hData && !Error(OleSetData(lppict->lpObject, gcfLink, hData)))
|
||
|
PostMessage(ghwndError, WM_REDRAW, 0, 0L);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicCopy() - Puts an object onto the clipboard.
|
||
|
*
|
||
|
* Returns: TRUE iff successful.
|
||
|
*/
|
||
|
BOOL
|
||
|
PicCopy(
|
||
|
LPPICT lppict
|
||
|
)
|
||
|
{
|
||
|
BOOL fSuccess = FALSE;
|
||
|
|
||
|
// If we can't open the clipboard, fail
|
||
|
if (!lppict->lpObject || !OpenClipboard(ghwndFrame))
|
||
|
return FALSE;
|
||
|
|
||
|
// Empty the clipboard
|
||
|
EmptyClipboard();
|
||
|
|
||
|
// Successful if we managed to copy to the clipboard
|
||
|
fSuccess = !Error(OleCopyToClipboard(lppict->lpObject));
|
||
|
|
||
|
CloseClipboard();
|
||
|
return fSuccess;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicGetBounds() -
|
||
|
*/
|
||
|
static VOID
|
||
|
PicGetBounds(
|
||
|
LPOLEOBJECT lpObject,
|
||
|
LPRECT lprc
|
||
|
)
|
||
|
{
|
||
|
if (IsRectEmpty(lprc))
|
||
|
{
|
||
|
switch (OleQueryBounds(lpObject, lprc))
|
||
|
{
|
||
|
case OLE_WAIT_FOR_RELEASE:
|
||
|
Hourglass(TRUE);
|
||
|
gcOleWait++;
|
||
|
WaitForObject(lpObject);
|
||
|
Hourglass(FALSE);
|
||
|
|
||
|
case OLE_OK:
|
||
|
// Map from HIMETRIC into screen coordinates
|
||
|
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;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* PicSaveUndo() - Saves a copy of the object for Undo.
|
||
|
*/
|
||
|
VOID
|
||
|
PicSaveUndo(
|
||
|
LPPICT lppict
|
||
|
)
|
||
|
{
|
||
|
INT iPane = (lppict == glpobj[CONTENT]);
|
||
|
LPOLEOBJECT lpObject;
|
||
|
|
||
|
// Clone the object
|
||
|
if (Error(OleClone(lppict->lpObject, glpclient, glhcdoc, gszTemp, &lpObject))
|
||
|
|| !lpObject)
|
||
|
{
|
||
|
ErrorMessage(W_FAILED_TO_CLONE_UNDO);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Save the undo, delete the prior Undo
|
||
|
DeletePane(iPane, FALSE);
|
||
|
OleRename(lpObject, gszCaption[iPane]);
|
||
|
glpobj[iPane] = PicCreate(lpObject, &(lppict->rc));
|
||
|
gpty[iPane] = PICTURE;
|
||
|
|
||
|
if (iPane == CONTENT)
|
||
|
EnableWindow(ghwndPict, TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* PicPaste() - Creates object from a file
|
||
|
*/
|
||
|
LPPICT
|
||
|
PicFromFile(
|
||
|
BOOL fEmbedded,
|
||
|
LPSTR szFile
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
LPOLEOBJECT lpObject;
|
||
|
|
||
|
Hourglass(TRUE);
|
||
|
|
||
|
// Don't replace the current object unless we're successful
|
||
|
if (fEmbedded)
|
||
|
{
|
||
|
hr = OleCreateFromFile(gszProtocol, glpclient, NULL, szFile,
|
||
|
glhcdoc, gszCaption[CONTENT], &lpObject, olerender_draw, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = OleCreateLinkFromFile(gszProtocol, glpclient, NULL, szFile,
|
||
|
NULL, glhcdoc, gszCaption[CONTENT], &lpObject, olerender_draw, 0);
|
||
|
}
|
||
|
|
||
|
Hourglass(FALSE);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
|
||
|
WaitForObject(lpObject);
|
||
|
|
||
|
return PicCreate(lpObject, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
LPOLECLIENT
|
||
|
PicCreateClient(
|
||
|
PCALL_BACK fnCallBack,
|
||
|
LPOLECLIENTVTBL lpclivtbl
|
||
|
)
|
||
|
{
|
||
|
LPOLECLIENT pclient;
|
||
|
if (!(pclient = (LPOLECLIENT)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, sizeof(OLECLIENT))))
|
||
|
return NULL;
|
||
|
|
||
|
pclient->lpvtbl = lpclivtbl;
|
||
|
pclient->lpvtbl->CallBack = fnCallBack;
|
||
|
|
||
|
return pclient;
|
||
|
}
|