windows-nt/Source/XPSP1/NT/shell/osshell/accesory/packager/picture.c
2020-09-26 16:20:57 +08:00

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;
}