Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1041 lines
24 KiB

/* server.c - This module contains the OLE server worker/public routines.
*
* Created by Microsoft Corporation.
*/
#include "packager.h"
#define CBLINKMAX 260
/*
* This server only supports one document per instance. The items are
* just rectangles over the document, possibly overlapping.
*/
static LHCLIENTDOC lhClipDoc = 0;
static OLESERVERDOCVTBL vdocvtbl; // Document virtual table
static OLEOBJECTVTBL vitemvtbl; // Item virtual table
static OLESERVERVTBL vsrvrvtbl; // Server virtual table
static LPSAMPITEM vlpitem[CITEMSMAX]; // Pointers to active OLE items
static INT cItems = 0; // Number of active OLE items
static CHAR szClip[] = "Clipboard";
static VOID DeleteDoc(LPSAMPDOC lpdoc);
static BOOL SendItemChangeMsg(LPSAMPITEM lpitem, UINT options);
static INT FindItem(LPSAMPITEM lpitem);
/************ Server initialization and termination routines **********/
/* InitServer() - Initializes the OLE server
*/
BOOL
InitServer(
VOID
)
{
// Allocate the server block
if (!(ghServer = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(PBSRVR)))
|| !(glpsrvr = (LPSAMPSRVR)LocalLock(ghServer)))
goto errRtn;
// Initialize the server, document, and item virtual tables
vsrvrvtbl.Open = SrvrOpen;
vsrvrvtbl.Create = SrvrCreate;
vsrvrvtbl.CreateFromTemplate = SrvrCreateFromTemplate;
vsrvrvtbl.Edit = SrvrEdit;
vsrvrvtbl.Exit = SrvrExit;
vsrvrvtbl.Release = SrvrRelease;
vsrvrvtbl.Execute = SrvrExecute;
vdocvtbl.Save = DocSave;
vdocvtbl.Close = DocClose;
vdocvtbl.SetHostNames = DocSetHostNames;
vdocvtbl.SetDocDimensions = DocSetDocDimensions;
vdocvtbl.GetObject = DocGetObject;
vdocvtbl.Release = DocRelease;
vdocvtbl.SetColorScheme = DocSetColorScheme;
vdocvtbl.Execute = DocExecute;
vitemvtbl.QueryProtocol = ItemQueryProtocol;
vitemvtbl.Release = ItemDelete;
vitemvtbl.Show = ItemShow;
vitemvtbl.DoVerb = ItemDoVerb;
vitemvtbl.GetData = ItemGetData;
vitemvtbl.SetData = ItemSetData;
vitemvtbl.SetTargetDevice = ItemSetTargetDevice;
vitemvtbl.SetBounds = ItemSetBounds;
vitemvtbl.EnumFormats = ItemEnumFormats;
vitemvtbl.SetColorScheme = ItemSetColorScheme;
// Try to register the server
glpsrvr->olesrvr.lpvtbl = &vsrvrvtbl;
if (Error(OleRegisterServer(gszAppClassName, (LPOLESERVER)glpsrvr,
(LONG_PTR * )&glpsrvr->lhsrvr, ghInst, OLE_SERVER_MULTI)))
goto errRtn;
// Initialize the client name
lstrcpy(gszClientName, "");
return TRUE;
errRtn:
ErrorMessage(E_FAILED_TO_REGISTER_SERVER);
// If we failed, clean up
if (glpsrvr)
{
LocalUnlock(ghServer);
glpsrvr = NULL;
}
if (ghServer)
LocalFree(ghServer);
ghServer = NULL;
return FALSE;
}
/* DeleteServer() - Revokes the OLE server.
*/
VOID
DeleteServer(
LPSAMPSRVR lpsrvr
)
{
if (gfServer)
{
gfServer = FALSE;
OleRevokeServer(lpsrvr->lhsrvr);
}
}
/* DestroyServer() - Deallocates the OLE server.
*/
VOID
DestroyServer(
VOID
)
{
if (ghServer)
{
// Release the server virtual table and info
LocalUnlock(ghServer);
LocalFree(ghServer);
ghServer = NULL;
// Destroy the window only when we're all through
DestroyWindow(ghwndFrame);
gfServer = FALSE;
}
}
/********************* Document support functions ********************/
/* InitDoc() - Initialize and register the document with the OLE library.
*/
LPSAMPDOC
InitDoc(
LPSAMPSRVR lpsrvr,
LHSERVERDOC lhdoc,
LPSTR lptitle
)
{
HANDLE hdoc = NULL;
LPSAMPDOC lpdoc = NULL;
if (!(hdoc = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, sizeof(PBDOC)))
|| !(lpdoc = (LPSAMPDOC)LocalLock(hdoc)))
goto errRtn;
lpdoc->hdoc = hdoc;
lpdoc->aName = GlobalAddAtom(lptitle);
lpdoc->oledoc.lpvtbl = &vdocvtbl;
if (!lhdoc)
{
if (Error(OleRegisterServerDoc(lpsrvr->lhsrvr, lptitle,
(LPOLESERVERDOC)lpdoc, (LHSERVERDOC * ) & lpdoc->lhdoc)))
goto errRtn;
}
else
{
lpdoc->lhdoc = lhdoc;
}
gfDocExists = TRUE;
gfDocCleared = FALSE;
return lpdoc;
errRtn:
ErrorMessage(E_FAILED_TO_REGISTER_DOCUMENT);
// Clean up
if (lpdoc)
LocalUnlock(hdoc);
if (hdoc)
LocalFree(hdoc);
return NULL;
}
/* DeleteDoc() - Notify the OLE library that the document is to be deleted.
*/
static VOID
DeleteDoc(
LPSAMPDOC lpdoc
)
{
if (gfOleClosed)
SendDocChangeMsg(lpdoc, OLE_CLOSED);
OleRevokeServerDoc(lpdoc->lhdoc);
}
/* ChangeDocName() - Notify the OLE library that the document name is changing.
*/
VOID
ChangeDocName(
LPSAMPDOC *lplpdoc,
LPSTR lpname
)
{
// If the document exists, delete and re-register.
if (*lplpdoc)
{
GlobalDeleteAtom((*lplpdoc)->aName);
(*lplpdoc)->aName = GlobalAddAtom(lpname);
//
// If the document contains items, just notify the children.
// If we aren't embedded, always delete and re-register.
//
OleRenameServerDoc((*lplpdoc)->lhdoc, lpname);
if (gfEmbedded && cItems)
return;
DeleteDoc(*lplpdoc);
}
*lplpdoc = InitDoc(glpsrvr, 0, lpname);
}
/* SendDocChangeMsg() - Notify the client that the document has changed.
*/
BOOL
SendDocChangeMsg(
LPSAMPDOC lpdoc,
UINT options
)
{
BOOL fSuccess = FALSE;
INT i;
for (i = 0; i < cItems; i++)
{
if (SendItemChangeMsg(vlpitem[i], options))
fSuccess = TRUE;
}
return fSuccess;
}
/* CreateNewDoc() - Called when a document is newly created.
*
* Returns: hDocument if document successfully created, NULL otherwise.
* Note: This function is only called when the document is being
* created through OLE actions.
*/
LPSAMPDOC
CreateNewDoc(
LPSAMPSRVR lpsrvr,
LHSERVERDOC lhdoc,
LPSTR lpstr
)
{
glpdoc = InitDoc(lpsrvr, lhdoc, lpstr);
StringCchCopy(szUntitled, ARRAYSIZE(szUntitled), lpstr);
SetTitle(TRUE);
return glpdoc;
}
/* CreateDocFromFile() - Called when a document is to be created from a file.
*
* Returns: hDocument if document successfully created, NULL otherwise.
* Note: This function is only called when the document is being
* created through OLE actions. The file name is temporarily
* set to load the file, then it is reset to "". This is so
* that we won't save back to the template if we exit.
*/
LPSAMPDOC
CreateDocFromFile(
LPSAMPSRVR lpsrvr,
LHSERVERDOC lhdoc,
LPSTR lpstr
)
{
// Initialize document
if (!(glpdoc = InitDoc(lpsrvr, lhdoc, lpstr)) || !(*lpstr))
return NULL;
lstrcpy(szUntitled, lpstr); // This could overrun, but I don't see how I can check the length of the lpstr coming in
SetTitle(TRUE);
return glpdoc;
}
/********************** Item support functions ************************/
/* CopyObjects() - Copies selection to the clipboard.
*/
BOOL
CopyObjects(
VOID
)
{
HANDLE hdata;
// If we can't open the clipboard, fail
if (!OpenClipboard(ghwndFrame))
return FALSE;
Hourglass(TRUE);
// Empty the clipboard
EmptyClipboard();
//
// Copy the clipboard contents.
//
// Start with Native Data - which will just contain all the objects
// which intersect with the selection rectangle.
//
if (hdata = GetNative(TRUE))
{
SetClipboardData(gcfNative, hdata);
OleSavedClientDoc(lhClipDoc);
}
if (lhClipDoc)
{
OleRevokeClientDoc(lhClipDoc);
lhClipDoc = 0;
}
if (hdata = GetLink())
SetClipboardData(gcfOwnerLink, hdata);
//
// Metafile data: Re-invert the image before putting
// it onto the clipboard.
//
if (hdata = GetMF())
SetClipboardData(CF_METAFILEPICT, hdata);
CloseClipboard();
Hourglass(FALSE);
return TRUE;
}
/* CreateNewItem() - Allocate a new item.
*
* Note: lpitem->rc will be filled out by the caller.
*/
LPSAMPITEM
CreateNewItem(
LPSAMPDOC lpdoc
)
{
HANDLE hitem = NULL;
LPSAMPITEM lpitem = NULL;
// Now create the item
if (!(hitem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(ITEM)))
|| !(lpitem = (LPSAMPITEM)GlobalLock(hitem)))
goto errRtn;
lpitem->hitem = hitem;
lpitem->oleobject.lpvtbl = &vitemvtbl;
return lpitem;
errRtn:
if (lpitem)
GlobalUnlock(hitem);
if (hitem)
GlobalFree(hitem);
return NULL;
}
/* SendItemChangeMsg() - Notify the client that the item has changed.
*/
static BOOL
SendItemChangeMsg(
LPSAMPITEM lpitem,
UINT options
)
{
if (lpitem->lpoleclient)
{
(*lpitem->lpoleclient->lpvtbl->CallBack)
(lpitem->lpoleclient, options, (LPOLEOBJECT)lpitem);
return TRUE;
}
return FALSE;
}
/******************** Data reading/writing functions *********************/
/* GetNative(fClip) - Write the item native format to a memory block.
*
* This function will just write the objects which intersect
* with the selection rectangle into a memory block. If we
* are running as an embedded instance, return ALL items, even
* those which are not in the selection area. Then we will
* never lose objects that we move out of the selection area
* when editing an embedded object.
*
* Args: fClip - TRUE means native data is for copying to clipboard
*
* Returns: A handle containing the native format, or NULL.
*/
HANDLE
GetNative(
BOOL fClip
)
{
BOOL fSuccess = FALSE;
DWORD cBytes = 0L;
HANDLE hdata = NULL;
LPSTR lpdata = NULL;
DWORD cEmbWrite;
LPOLEOBJECT lpobjapp = NULL;
LPOLEOBJECT lpobjcon = NULL;
LPPICT lpcPict;
LPPICT lpaPict;
WORD w;
// Compute the size of the appearance
lpaPict = glpobj[APPEARANCE];
lpcPict = glpobj[CONTENT];
switch (gpty[APPEARANCE])
{
case ICON:
cBytes += IconWriteToNative(glpobj[APPEARANCE], NULL);
break;
case PICTURE:
if (fClip)
{
if (Error(OleRegisterClientDoc(
gszAppClassName, szClip, 0L, &lhClipDoc)))
goto Error;
if (Error(OleClone(
lpaPict->lpObject, glpclient, lhClipDoc,
szAppearance, &lpobjapp)))
goto Error;
cBytes += PicWriteToNative(lpaPict, lpobjapp, NULL);
}
else
{
cBytes += PicWriteToNative(lpaPict, lpaPict->lpObject, NULL);
}
break;
default:
break;
}
// Compute the content size
switch (gpty[CONTENT])
{
case CMDLINK:
cBytes += CmlWriteToNative(glpobj[CONTENT], NULL);
break;
case PEMBED: /* EmbWrite returns -1L if the user cancels */
cEmbWrite = EmbWriteToNative(glpobj[CONTENT], NULL);
if (cEmbWrite == (DWORD) - 1L)
return FALSE;
cBytes += cEmbWrite;
break;
case PICTURE:
if (fClip)
{
if (!lhClipDoc && (Error(OleRegisterClientDoc(
gszAppClassName, szClip, 0L, &lhClipDoc))))
goto Error;
if (Error(OleClone(lpcPict->lpObject, glpclient,
lhClipDoc, szContent, &lpobjcon)))
goto Error;
cBytes += PicWriteToNative(lpcPict, lpobjcon, NULL);
}
else
{
cBytes += PicWriteToNative(lpcPict, lpcPict->lpObject, NULL);
}
break;
default:
break;
}
if (cBytes == 0L) // then no data
goto Error;
cBytes += (DWORD)(2 * sizeof(WORD));
// Allocate a memory block for the data
if (!(hdata = GlobalAlloc(GMEM_ZEROINIT, cBytes)) ||
!(lpdata = (LPSTR)GlobalLock(hdata)))
goto Error;
// Write out the appearance
w = (WORD)gpty[APPEARANCE];
MemWrite(&lpdata, (LPSTR)&w, sizeof(WORD));
switch (gpty[APPEARANCE])
{
case ICON:
IconWriteToNative(glpobj[APPEARANCE], &lpdata);
break;
case PICTURE:
if (fClip)
PicWriteToNative(lpaPict, lpobjapp, &lpdata);
else
PicWriteToNative(lpaPict, lpaPict->lpObject, &lpdata);
break;
default:
break;
}
// Write out the content
w = (WORD)gpty[CONTENT];
MemWrite(&lpdata, (LPSTR)&w, sizeof(WORD));
switch (gpty[CONTENT])
{
case CMDLINK:
CmlWriteToNative(glpobj[CONTENT], &lpdata);
break;
case PEMBED:
EmbWriteToNative(glpobj[CONTENT], &lpdata);
break;
case PICTURE:
if (fClip)
PicWriteToNative(lpcPict, lpobjcon, &lpdata);
else
PicWriteToNative(lpcPict, lpcPict->lpObject, &lpdata);
break;
default:
break;
}
fSuccess = TRUE;
Error:
if (lpobjcon)
OleRelease (lpobjcon);
if (lpobjapp)
OleRelease (lpobjapp);
if (lpdata)
GlobalUnlock(hdata);
if (!fSuccess && hdata)
{
GlobalFree(hdata);
hdata = NULL;
}
return hdata;
}
/* PutNative() - Read the item native data from a selector.
*
* Reads as many objects as it can, in upwards order (better error recovery).
* Note: It may be worthwhile to scale the object(s) to the window here.
*
* Returns: TRUE iff successful.
*/
BOOL
PutNative(
HANDLE hdata
)
{
BOOL fSuccess = FALSE;
LPSTR lpdata;
WORD w;
if (!(lpdata = (LPSTR)GlobalLock(hdata)))
goto Error;
// Delete any previous panes
DeletePane(APPEARANCE, TRUE);
DeletePane(CONTENT, TRUE);
// Read in the appearance
MemRead(&lpdata, (LPSTR)&w, sizeof(WORD));
gpty[APPEARANCE] = w;
switch (gpty[APPEARANCE])
{
case ICON:
if (!(glpobj[APPEARANCE] = IconReadFromNative(&lpdata)))
gpty[APPEARANCE] = NOTHING;
break;
case PICTURE:
if (glpobj[APPEARANCE] =
PicReadFromNative(&lpdata, gszCaption[APPEARANCE]))
{
SendMessage(ghwndPane[APPEARANCE], WM_FIXSCROLL, 0, 0L);
break;
}
default:
gpty[APPEARANCE] = NOTHING;
break;
}
// Read the content
MemRead(&lpdata, (LPSTR)&w, sizeof(WORD));
gpty[CONTENT] = w;
switch (gpty[CONTENT])
{
case CMDLINK:
if (!(glpobj[CONTENT] = CmlReadFromNative(&lpdata)))
gpty[CONTENT] = NOTHING;
break;
case PEMBED:
if (!(glpobj[CONTENT] = (LPVOID)EmbReadFromNative(&lpdata)))
gpty[CONTENT] = NOTHING;
break;
case PICTURE:
if (glpobj[CONTENT] =
(LPVOID)PicReadFromNative(&lpdata, gszCaption[CONTENT]))
{
SendMessage(ghwndPane[CONTENT], WM_FIXSCROLL, 0, 0L);
EnableWindow(ghwndPict, TRUE);
break;
}
default:
gpty[CONTENT] = NOTHING;
break;
}
fSuccess = TRUE;
InvalidateRect(ghwndFrame, NULL, TRUE);
Error:
if (lpdata)
GlobalUnlock(hdata);
return fSuccess;
}
/* GetLink() - Retrieves ObjectLink/OwnerLink information.
*
* This function returns a string describing the selected area.
*/
HANDLE
GetLink(
VOID
)
{
CHAR pchlink[CBLINKMAX];
INT cblink;
HANDLE hlink;
LPSTR lplink;
// Link data - <App name>\0<Doc name>\0<Item name>\0\0
StringCchCopy((LPSTR)pchlink, ARRAYSIZE(pchlink), gszAppClassName); // ok const
cblink = lstrlen((LPSTR)pchlink) + 1;
// Copy the file name
StringCchCopy((LPSTR)(pchlink + cblink), ARRAYSIZE(pchlink) - cblink, szDummy); // szDummy size = 20
cblink += lstrlen((LPSTR)(pchlink + cblink)) + 1;
// Copy the item name
StringCchCopy((LPSTR)(pchlink + cblink), ARRAYSIZE(pchlink) - cblink, szDummy);
cblink += lstrlen((LPSTR)(pchlink + cblink)) + 1;
pchlink[cblink++] = 0; /* throw in another NULL at the end */
// Allocate a memory block for the data
if (!(hlink = GlobalAlloc(GMEM_ZEROINIT, cblink)) ||
!(lplink = (LPSTR)GlobalLock(hlink)))
goto Error;
// Copy the data, then return the memory block
MemWrite(&lplink, (LPSTR)pchlink, cblink);
GlobalUnlock(hlink);
return hlink;
Error:
if (hlink)
GlobalFree(hlink);
return NULL;
}
/* GetMF() - Retrieve a metafile of the selected area.
*
* Note: Originally, tried to Blt directly from the Window DC. This
* doesn't work very well because when the window is obscured,
* the obscured portion shows up when the link is updated.
*/
HANDLE
GetMF(
VOID
)
{
BOOL fError = TRUE;
HANDLE hdata = NULL;
HDC hdcMF = NULL;
HDC hdcWnd = NULL;
HFONT hfont;
HANDLE hmfpict;
LPMETAFILEPICT lpmfpict;
LPIC lpic;
LPPICT lppict;
RECT rcTemp;
RECT rcText;
INT cxImage;
INT cyImage;
hmfpict = GlobalAlloc(GMEM_ZEROINIT, sizeof(METAFILEPICT));
if (!hmfpict)
goto Error;
lpmfpict = (LPMETAFILEPICT)GlobalLock(hmfpict);
// If the picture has a metafile, use it!
if (gpty[APPEARANCE] == PICTURE)
{
LPMETAFILEPICT lpmfpictOrg = NULL;
if (Error(OleGetData(
((LPPICT)glpobj[APPEARANCE])->lpObject, CF_METAFILEPICT, &hdata))
|| !hdata
|| !(lpmfpictOrg = (LPMETAFILEPICT)GlobalLock(hdata)))
goto NoPicture;
// Copy the metafile
lpmfpict->hMF = CopyMetaFile(lpmfpictOrg->hMF, NULL);
GlobalUnlock(hdata);
// If we failed, just draw it
if (!lpmfpict->hMF)
goto NoPicture;
// Finish filling in the metafile header
lpmfpict->mm = lpmfpictOrg->mm;
lpmfpict->xExt = lpmfpictOrg->xExt;
lpmfpict->yExt = lpmfpictOrg->yExt;
GlobalUnlock(hmfpict);
return hmfpict;
}
NoPicture:
// Get the window DC, and make a DC compatible to it.
if (!(hdcWnd = GetDC(NULL)))
goto Error;
switch (gpty[APPEARANCE])
{
case ICON:
lpic = (LPIC)glpobj[APPEARANCE];
// Set the icon text rectangle, and the icon font
SetRect(&rcText, 0, 0, gcxArrange, gcyArrange);
hfont = SelectObject(hdcWnd, ghfontTitle);
// Figure out how large the text region will be
// since this is going in a metafile we will not wrap
// the icon text
DrawText(hdcWnd, lpic->szIconText, -1, &rcText,
DT_CALCRECT | DT_WORDBREAK | DT_NOPREFIX | DT_SINGLELINE);
if (hfont)
SelectObject(hdcWnd, hfont);
// Compute the image size
rcText.right++;
cxImage = (rcText.right > gcxIcon) ? rcText.right : gcxIcon;
cyImage = gcyIcon + rcText.bottom + 1;
break;
case PICTURE:
lppict = (LPPICT)glpobj[APPEARANCE];
cxImage = lppict->rc.right - lppict->rc.left + 1;
cyImage = lppict->rc.bottom - lppict->rc.top + 1;
break;
default:
cxImage = GetSystemMetrics(SM_CXICON);
cyImage = GetSystemMetrics(SM_CYICON);
break;
}
cxImage += cxImage / 4; // grow the image a bit
cyImage += cyImage / 8;
// Create the metafile
if (!(hdcMF = CreateMetaFile(NULL)))
goto Error;
// Initialize the metafile
SetWindowOrgEx(hdcMF, 0, 0, NULL);
SetWindowExtEx(hdcMF, cxImage - 1, cyImage - 1, NULL);
//
// Fill in the background
//
// We displace back to (0, 0) because that's where the BITMAP resides.
//
SetRect(&rcTemp, 0, 0, cxImage, cyImage);
switch (gpty[APPEARANCE])
{
case ICON:
IconDraw(glpobj[APPEARANCE], hdcMF, &rcTemp, FALSE, cxImage, cyImage);
break;
case PICTURE:
PicDraw(glpobj[APPEARANCE], hdcMF, &rcTemp, 0, 0, TRUE, FALSE);
break;
default:
DrawIcon(hdcMF, 0, 0, LoadIcon(ghInst, MAKEINTRESOURCE(ID_APPLICATION)));
break;
}
// Map to device independent coordinates
rcTemp.right =
MulDiv((rcTemp.right - rcTemp.left), HIMETRIC_PER_INCH, giXppli);
rcTemp.bottom =
MulDiv((rcTemp.bottom - rcTemp.top), HIMETRIC_PER_INCH, giYppli);
// Finish filling in the metafile header
lpmfpict->mm = MM_ANISOTROPIC;
lpmfpict->xExt = rcTemp.right;
lpmfpict->yExt = rcTemp.bottom;
lpmfpict->hMF = CloseMetaFile(hdcMF);
fError = FALSE;
Error:
if (hdcWnd)
ReleaseDC(NULL, hdcWnd);
// If we had an error, return NULL
if (fError && hmfpict)
{
GlobalUnlock(hmfpict);
GlobalFree(hmfpict);
hmfpict = NULL;
}
return hmfpict;
}
/* InitEmbedded() - Perform operations specific to editing embedded objects.
*
* This routine changes the menu items as appropriate.
*/
VOID
InitEmbedded(
BOOL fCreate
)
{
HMENU hmenu;
if (hmenu = GetMenu(ghwndFrame))
EnableMenuItem(hmenu, IDM_UPDATE, fCreate ? MF_GRAYED : MF_ENABLED);
gfEmbedded = TRUE;
}
/***************** Item circular queue/utility functions *****************/
/* AddItem() - Add an item to the global item list.
*/
LPSAMPITEM
AddItem(
LPSAMPITEM lpitem
)
{
INT i;
HANDLE hitem;
i = FindItem((LPSAMPITEM)lpitem);
if (i < cItems)
{
vlpitem[i]->ref++;
// Free the duplicate item
GlobalUnlock(hitem = lpitem->hitem);
GlobalFree(hitem);
}
else
{
if (i < CITEMSMAX)
{
vlpitem[cItems] = (LPSAMPITEM)lpitem;
vlpitem[cItems++]->ref = 1;
}
else
{
return NULL;
}
}
return vlpitem[i];
}
/* DeleteItem() - Delete an item from the global item list.
*
* Returns: TRUE iff successful.
*/
BOOL
DeleteItem(
LPSAMPITEM lpitem
)
{
BOOL fFound;
HANDLE hitem;
INT i;
i = FindItem(lpitem);
if ((fFound = (i < cItems && vlpitem[i]->ref))
&& !(--vlpitem[i]->ref))
{
// Free the item
GlobalUnlock(hitem = vlpitem[i]->hitem);
GlobalFree(hitem);
// Shift everything else down
cItems--;
for ( ; i < cItems; i++)
vlpitem[i] = vlpitem[i + 1];
}
return fFound;
}
/* FindItem() - Locate an item in the global item list.
*/
static INT
FindItem(
LPSAMPITEM lpitem
)
{
BOOL fFound = FALSE;
INT i;
for (i = 0; i < cItems && !fFound;)
{
if (lpitem->aName == vlpitem[i]->aName)
{
fFound = TRUE;
}
else
{
i++;
}
}
return i;
}
/* EndEmbedding() - Return to normal editing.
*
* This routine changes the menu items as appropriate.
*/
VOID
EndEmbedding(
VOID
)
{
HMENU hmenu;
// Fix the "Untitled" string
LoadString(ghInst, IDS_UNTITLED, szUntitled, CBMESSAGEMAX);
if (hmenu = GetMenu(ghwndFrame))
EnableMenuItem(hmenu, IDM_UPDATE, MF_GRAYED);
gfEmbedded = FALSE;
}