NT4/private/windows/media/mplayer2/server.c
2020-09-30 17:12:29 +02:00

697 lines
22 KiB
C

/*---------------------------------------------------------------------------
| SERVER.C
| This file has the IClassFactory Interface implementation. It also has
| the Vtbl initializations.
|
| Created By: Vij Rajarajan (VijR)
+---------------------------------------------------------------------------*/
#define SERVERONLY
#include <windows.h>
#include "mpole.h"
#include "mplayer.h"
extern IID iidUnknownObject;
extern IID iidClassFactory;
HMODULE hMciOle;
static SZCODE aszMCIOLE[] = TEXT("MCIOLE32.DLL"); // WOW-proofing
static ANSI_SZCODE aszOleQueryObjPos[] = ANSI_TEXT("OleQueryObjPos");
/**************************************************************************
* The VTBLs are initialized here.
**************************************************************************/
// Method tables.
IClassFactoryVtbl srvrVtbl=
{
// IOleClassFactory method table
/* srvrVtbl.QueryInterface = */ SrvrQueryInterface,
/* srvrVtbl.AddRef = */ SrvrAddRef,
/* srvrVtbl.Release = */ SrvrRelease,
/* srvrVtbl.CreateInstance = */ SrvrCreateInstance,
/* srvrVtbl.LockServer = */ SrvrLockServer
};
IOleObjectVtbl oleVtbl =
{
// IOleObject method table
/* oleVtbl.QueryInterface = */ OleObjQueryInterface,
/* oleVtbl.AddRef = */ OleObjAddRef,
/* oleVtbl.Release = */ OleObjRelease,
/* oleVtbl.SetClientSite = */ OleObjSetClientSite,
/* oleVtbl.GetClientSite = */ OleObjGetClientSite,
/* oleVtbl.SetHostNames = */ OleObjSetHostNames,
/* oleVtbl.Close = */ OleObjClose,
/* oleVtbl.SetMoniker = */ OleObjSetMoniker,
/* oleVtbl.GetMoniker = */ OleObjGetMoniker,
/* oleVtbl.InitFromData = */ OleObjInitFromData,
/* oleVtbl.GetClipboardData = */ OleObjGetClipboardData,
/* oleVtbl.DoVerb = */ OleObjDoVerb,
/* oleVtbl.EnumVerbs = */ OleObjEnumVerbs,
/* oleVtbl.Update = */ OleObjUpdate,
/* oleVtbl.IsUpToDate = */ OleObjIsUpToDate,
/* oleVtbl.GetUserClassID = */ OleObjGetUserClassID,
/* oleVtbl.GetUserType = */ OleObjGetUserType,
/* oleVtbl.SetExtent = */ OleObjSetExtent,
/* oleVtbl.GetExtent = */ OleObjGetExtent,
/* oleVtbl.Advise = */ OleObjAdvise,
/* oleVtbl.Unadvise = */ OleObjUnadvise,
/* oleVtbl.EnumAdvise = */ OleObjEnumAdvise,
/* oleVtbl.GetMiscStatus = */ OleObjGetMiscStatus,
/* oleVtbl.SetColorScheme = */ OleObjSetColorScheme,
};
IDataObjectVtbl dataVtbl =
{
// IDataObject method table
/* dataVtbl.QueryInterface = */ DataObjQueryInterface,
/* dataVtbl.AddRef = */ DataObjAddRef,
/* dataVtbl.Release = */ DataObjRelease,
/* dataVtbl.GetData = */ DataObjGetData,
/* dataVtbl.GetDataHere = */ DataObjGetDataHere,
/* dataVtbl.QueryGetData = */ DataObjQueryGetData,
/* dataVtbl.GetCanonicalFormatEtc = */ DataObjGetCanonicalFormatEtc,
/* dataVtbl.SetData = */ DataObjSetData,
/* dataVtbl.EnumFormatEtc = */ DataObjEnumFormatEtc,
/* dataVtbl.Advise = */ DataObjAdvise,
/* dataVtbl.Unadvise = */ DataObjUnadvise,
/* dataVtbl.EnumAdvise = */ DataObjEnumAdvise
};
IEnumFORMATETCVtbl ClipDragEnumVtbl =
{
// Clipboard dataobject's formatetc enumerator method table
/* ClipDragEnumVtbl.QueryInterface = */ ClipDragEnumQueryInterface,
/* ClipDragEnumVtbl.AddRef = */ ClipDragEnumAddRef,
/* ClipDragEnumVtbl.Release = */ ClipDragEnumRelease,
/* ClipDragEnumVtbl.Next = */ ClipDragEnumNext,
/* ClipDragEnumVtbl.Skip = */ ClipDragEnumSkip,
/* ClipDragEnumVtbl.Reset = */ ClipDragEnumReset,
/* ClipDragEnumVtbl.Clone = */ ClipDragEnumClone
};
IPersistStorageVtbl persistStorageVtbl =
{
/* persistStorageVtbl.QueryInterface = */ PSQueryInterface,
/* persistStorageVtbl.AddRef = */ PSAddRef,
/* persistStorageVtbl.Release = */ PSRelease,
/* persistStorageVtbl.GetClassID = */ PSGetClassID,
/* persistStorageVtbl.IsDirty = */ PSIsDirty,
/* persistStorageVtbl.InitNew = */ PSInitNew,
/* persistStorageVtbl.Load = */ PSLoad,
/* persistStorageVtbl.Save = */ PSSave,
/* persistStorageVtbl.SaveCompleted = */ PSSaveCompleted,
/* persistStorageVtbl.HandsOffStorage = */ PSHandsOffStorage
};
IOleInPlaceObjectVtbl ipVtbl =
{
// IOleInPlaceObject method table
/* ipVtbl.QueryInterface = */ IPObjQueryInterface,
/* ipVtbl.AddRef = */ IPObjAddRef,
/* ipVtbl.Release = */ IPObjRelease,
/* ipVtbl.GetWindow = */ IPObjGetWindow,
/* ipVtbl.ContextSensitiveHelp = */ IPObjContextSensitiveHelp,
/* ipVtbl.InPlaceDeactivate = */ IPObjInPlaceDeactivate,
/* ipVtbl.UIDeactivate = */ IPObjUIDeactivate,
/* ipVtbl.SetObjectRects = */ IPObjSetObjectRects,
/* ipVtbl.ReactivateAndUndo = */ IPObjReactivateAndUndo
};
IOleInPlaceActiveObjectVtbl ipActiveVtbl =
{
// IOleInPlaceActiveObject method table
/* ipActiveVtbl.QueryInterface = */ IPActiveQueryInterface,
/* ipActiveVtbl.AddRef = */ IPActiveAddRef,
/* ipActiveVtbl.Release = */ IPActiveRelease,
/* ipActiveVtbl.GetWindow = */ IPActiveGetWindow,
/* ipActiveVtbl.ContextSensitiveHelp = */ IPActiveContextSensitiveHelp,
/* ipActiveVtbl.TranslateAccelerator = */ IPActiveTranslateAccelerator,
/* ipActiveVtbl.OnFrameWindowActivate = */ IPActiveOnFrameWindowActivate,
/* ipActiveVtbl.OnDocWindowActivate = */ IPActiveOnDocWindowActivate,
/* ipActiveVtbl.ResizeBorder = */ IPActiveResizeBorder,
/* ipActiveVtbl.EnableModeless = */ IPActiveEnableModeless
};
IDataObjectVtbl clipdragVtbl =
{
// ClipDrag IDataObject method table
/* clipdragVtbl.QueryInterface = */ ClipDragQueryInterface,
/* clipdragVtbl.AddRef = */ ClipDragAddRef,
/* clipdragVtbl.Release = */ ClipDragRelease,
/* clipdragVtbl.GetData = */ ClipDragGetData,
/* clipdragVtbl.GetDataHere = */ ClipDragGetDataHere,
/* clipdragVtbl.QueryGetData = */ ClipDragQueryGetData,
/* clipdragVtbl.GetCanonicalFormatEtc = */ ClipDragGetCanonicalFormatEtc,
/* clipdragVtbl.SetData = */ ClipDragSetData,
/* clipdragVtbl.EnumFormatEtc = */ ClipDragEnumFormatEtc,
/* clipdragVtbl.Advise = */ ClipDragAdvise,
/* clipdragVtbl.Unadvise = */ ClipDragUnadvise,
/* clipdragVtbl.EnumAdvise = */ ClipDragEnumAdvise
};
IDropSourceVtbl dropsourceVtbl =
{
// DragDrop IDropSource method table
/* dropsourceVtbl.QueryInterface = */ DropSourceQueryInterface,
/* dropsourceVtbl.AddRef = */ DropSourceAddRef,
/* dropsourceVtbl.Release = */ DropSourceRelease,
/* dropsourceVtbl.QueryContinueDrag = */ DropSourceQueryContinueDrag,
/* dropsourceVtbl.GiveFeedback = */ DropSourceGiveFeedback
};
#ifdef LATER
IDropTargetVtbl droptargetVtbl =
{
// DragDrop IDropTarget method table
/* droptargetVtbl.QueryInterface = */ DropTargetQueryInterface,
/* droptargetVtbl.AddRef = */ DropTargetAddRef,
/* droptargetVtbl.Release = */ DropTargetRelease,
/* droptargetVtbl.DragEnter = */ DropTargetDragEnter,
/* droptargetVtbl.DragOver = */ DropTargetDragOver,
/* droptargetVtbl.DragLeave = */ DropTargetDragLeave,
/* droptargetVtbl.Drop = */ DropTargetDrop
};
#endif
IPersistFileVtbl persistFileVtbl =
{
/* persistFileVtbl.QueryInterface = */ PFQueryInterface,
/* persistFileVtbl.AddRef = */ PFAddRef,
/* persistFileVtbl.Release = */ PFRelease,
/* persistFileVtbl.GetClassID = */ PFGetClassID,
/* persistFileVtbl.IsDirty = */ PFIsDirty,
/* persistFileVtbl.Load = */ PFLoad,
/* persistFileVtbl.Save = */ PFSave,
/* persistFileVtbl.SaveCompleted = */ PFSaveCompleted,
/* persistFileVtbl.GetCurFile = */ PFGetCurFile
};
/**************************************************************************
*************** IClassFactory INTERFACE IMPLEMENTATION.
***************************************************************************/
STDMETHODIMP SrvrQueryInterface (
LPCLASSFACTORY lpolesrvr,
REFIID riid,
LPVOID FAR *lplpunkObj
)
{
LPSRVR lpsrvr;
DPF("*srvrqi");
lpsrvr = (LPSRVR)lpolesrvr;
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) {
*lplpunkObj = (LPVOID)lpsrvr;
lpsrvr->cRef++;
return NOERROR;
} else {
*lplpunkObj = (LPVOID) NULL;
RETURN_RESULT( E_NOINTERFACE);
}
}
STDMETHODIMP_(ULONG) SrvrAddRef(
LPCLASSFACTORY lpolesrvr
)
{
LPSRVR lpsrvr;
DPF("*srvrAR");
lpsrvr = (LPSRVR)lpolesrvr;
return ++lpsrvr->cRef;
}
STDMETHODIMP_(ULONG) SrvrRelease (
LPCLASSFACTORY lpolesrvr
)
{
LPSRVR lpsrvr;
DPF("*srvrREL");
lpsrvr = (LPSRVR)lpolesrvr;
DPFI("* SRVR CREF: %d*",lpsrvr->cRef);
if (--lpsrvr->cRef == 0) {
DestroyServer(lpsrvr);
return 0;
}
return lpsrvr->cRef;
}
STDMETHODIMP SrvrCreateInstance (
LPCLASSFACTORY lpolesrvr,
LPUNKNOWN lpUnkOuter,
REFIID riid,
LPVOID FAR *lplpunkObj
)
{
static BOOL fInstanceCreated = FALSE;
DPF("*srvrcreateinst");
/*********************************************************************
** OLE2NOTE: this is an SDI app; it can only create and support one
** instance. After the instance is created, the OLE libraries
** should not call CreateInstance again. it is a good practise
** to specifically guard against this.
*********************************************************************/
if (fInstanceCreated)
RETURN_RESULT( E_FAIL);
else {
fInstanceCreated = TRUE;
}
/*********************************************************************
** OLE2NOTE: create and initialize a new document instance. the **
** document's refcnt should start out as 1. **
*********************************************************************/
if (!InitNewDocObj(&docMain))
RETURN_RESULT( E_OUTOFMEMORY);
*lplpunkObj = (LPUNKNOWN) &docMain;
return NOERROR;
}
//Increment or decrement the lock count as required. The server should not
//quit when there is a lock on the server.
STDMETHODIMP SrvrLockServer(
LPCLASSFACTORY lpolesrvr,
BOOL fLock
)
{
LPSRVR lpsrvr;
DPF("*srvrLOCKSERVER");
lpsrvr = (LPSRVR)lpolesrvr;
if (fLock)
{
lpsrvr->cLock++;
DPFI("CLOCK = %d\n", lpsrvr->cLock);
}
else if ((--lpsrvr->cLock == 0) && (docMain.cRef == 0))
{
DPFI("CLOCK UNLOCK ZERO = %d\n", lpsrvr->cLock);
PostCloseMessage();
}
return NOERROR;
}
/**************************************************************************
Stub routine if we can't find MCIOLE.DLL
***************************************************************************/
OLE1_OLESTATUS FAR PASCAL NullOleQueryObjPos(LPOLEOBJECT lpobj, HWND FAR* lphwnd, LPRECT lprc, LPRECT lprcWBounds)
{
DPF("NullQueryObjPos called, MCIOLE.DLL was not loaded\n");
return OLE1_OLEERROR_GENERIC;
}
#ifdef OLE1_HACK
BOOL FAR PASCAL InitOle1Server(HWND hwnd, HANDLE hInst);
#endif
/**************************************************************************
* InitServer:
* This function initializes the server object with the IClassFactory
* Vtbl and also load the mciole.dll library to support OLE 1.0 apps.
**************************************************************************/
BOOL InitServer (HWND hwnd, HANDLE hInst)
{
int err;
OQOPROC fp;
srvrMain.olesrvr.lpVtbl = &srvrVtbl;
srvrMain.dwRegCF=0;
srvrMain.cRef = 0;
srvrMain.cLock = 0;
err = SetErrorMode(SEM_NOOPENFILEERRORBOX);
hMciOle = LoadLibrary(aszMCIOLE);
SetErrorMode(err);
fp = (OQOPROC)GetProcAddress(hMciOle, aszOleQueryObjPos);
if (hMciOle && fp)
OleQueryObjPos = fp; // Avoid cast on LVALUE!!
else
OleQueryObjPos = (OQOPROC)NullOleQueryObjPos;
#ifdef OLE1_HACK
InitOle1Server(hwnd, hInst);
#endif
return TRUE;
}
void DestroyServer (LPSRVR lpsrvr)
{
lpsrvr->fEmbedding = FALSE;
}
/**************************************************************************
* InitNewDocObj:
* Initializes the the lpdoc structure.
**************************************************************************/
BOOL InitNewDocObj(LPDOC lpdoc)
{ DPFI("*INITNEWDOCOBJ*");
// Fill the fields in the object structure.
if(gfOle2IPEditing)
return TRUE;
lpdoc->cRef = 1;
lpdoc->doctype = doctypeNew;
lpdoc->m_Ole.lpVtbl = &oleVtbl;
lpdoc->m_Ole.lpdoc = lpdoc;
lpdoc->m_Data.lpVtbl = &dataVtbl;
lpdoc->m_Data.lpdoc = lpdoc;
lpdoc->m_PersistStorage.lpVtbl = &persistStorageVtbl;
lpdoc->m_PersistStorage.lpdoc = lpdoc;
lpdoc->lpIpData = NULL;
lpdoc->m_InPlace.lpVtbl = &ipVtbl;
lpdoc->m_InPlace.lpdoc = lpdoc;
lpdoc->m_IPActive.lpVtbl = &ipActiveVtbl;
lpdoc->m_IPActive.lpdoc = lpdoc;
lpdoc->m_PersistFile.lpVtbl = &persistFileVtbl;
lpdoc->m_PersistFile.lpdoc = lpdoc;
lpdoc->aDocName = GlobalAddAtom (TEXT("(Untitled)"));
lpdoc->lpoleclient = NULL;
lpdoc->lpdaholder = NULL;
lpdoc->hwnd = ghwndApp;
lpdoc->hwndParent = NULL;
#ifdef OLE1_HACK
SetDocVersion( DOC_VERSION_OLE2 );
#endif /* OLE1_HACK */
return TRUE;
}
/**************************************************************************
* DestroyDoc:
* This function Releases the references we hold. This function is called
* at the termination of our operation as a server.
**************************************************************************/
void DestroyDoc (LPDOC lpdoc)
{
if (lpdoc->lpoleclient) {
/******************************************************************
** OLE2NOTE: we no longer need the ClientSite ptr, so release it **
******************************************************************/
IOleClientSite_Release(lpdoc->lpoleclient);
lpdoc->lpoleclient = NULL;
}
if (lpdoc->lpoaholder)
{
IOleAdviseHolder_Release(lpdoc->lpoaholder);
lpdoc->lpoaholder = NULL;
}
if (lpdoc->lpdaholder)
{
IDataAdviseHolder_Release(lpdoc->lpdaholder);
lpdoc->lpdaholder = NULL;
}
if (lpdoc->aDocName)
{
GlobalDeleteAtom (lpdoc->aDocName);
lpdoc->aDocName = (ATOM)0;
}
#ifdef OLE1_HACK
SetDocVersion( DOC_VERSION_NONE );
#endif /* OLE1_HACK */
}
/* SendDocMsg
* ----------
*
* This function sends a message to a specific doc object.
*
* LPOBJ lpobj - The object
* WORD wMessage - The message to send
*
*
*/
SCODE SendDocMsg (LPDOC lpdoc, WORD wMessage)
{
HRESULT status = S_OK;
// if no clients connected, no message.
if (lpdoc->cRef == 0)
{
DPFI("*OLE_NOMSG");
return S_OK;
}
switch (wMessage) {
case OLE_CLOSED:
// tell the clients that the UI is shutting down for this obj
DPFI("*OLE_CLOSED");
#if 0
//NOTE: We have to SendOnCLose for all clients even OLE1. But
//OLE2 has bug (or by design flaw) that causes the OLE1 client
//doc. to be marked as changed because OLE2 always resaves
//the object even if the object has not changed. So may be we
//should not send the SendOnClose if we just Played in the OLE1 client.
if (gfPlayingInPlace || gfOle1Client)
break;
#endif
DPFI("*SENDING ONCLOSE");
if (lpdoc->lpoaholder)
status = IOleAdviseHolder_SendOnClose(lpdoc->lpoaholder);
break;
case OLE_SAVED:
// inform clients that the object has been saved
DPFI("*OLE_SAVED");
if (lpdoc->lpoaholder)
status = IOleAdviseHolder_SendOnSave(lpdoc->lpoaholder);
break;
case OLE_SAVEOBJ:
// ask the embedding client to save the object now
//If we are just playing then don't send this message.
#if 0
// Yes, do, so that broken links can be fixed.
if(gfOle2IPPlaying || gfPlayingInPlace || glCurrentVerb == OLEIVERB_PRIMARY)
break;
#endif
DPFI("*OLE_SAVEOBJ");
if (lpdoc->lpoleclient)
status = IOleClientSite_SaveObject(lpdoc->lpoleclient);
break;
case OLE_SHOWOBJ:
if(lpdoc->lpoleclient)
status = IOleClientSite_ShowObject(lpdoc->lpoleclient);
break;
case OLE_CHANGED:
// send data changed notification if any have registered
//If we are just playing then don't send this message.
#if 0
// Yes, do, so that broken links can be fixed.
if(gfOle2IPPlaying || gfPlayingInPlace)
break;
#endif
DPFI("*OLE_CHANGED");
if (lpdoc->lpdaholder)
status = IDataAdviseHolder_SendOnDataChange
(lpdoc->lpdaholder, (LPDATAOBJECT)&lpdoc->m_Data, 0, 0);
break;
case OLE_SIZECHG:
// Inform clients that the size of the object has changed.
// This is relevant only if we are inplace Editing.
DPFI("*OLE_SIZEOBJ");
if (gfOle2IPEditing)
{
RECT rc = gInPlacePosRect;
if (ghwndMCI && gfInPlaceResize)
{
DPFI("***In OLE_SIZECHG gfACTIVE***");
gfInPlaceResize = FALSE;
}
else if(ghwndMCI)
{
/* gInPlacePosRect contains the size of the in-place window
* including playbar, if there is one.
* Don't include the playbar on the OnPosRectChange:
*/
DPFI("***getextent gfNotActive***");
if (gwOptions & OPT_BAR)
rc.bottom -= TITLE_HEIGHT;
}
MapWindowPoints(NULL,ghwndCntr,(POINT FAR *)&rc,(UINT)2);
DPF("IOleInPlaceSite::OnPosRectChange %d, %d, %d, %d\n", rc);
if (!gfInPPViewer)
IOleInPlaceSite_OnPosRectChange(lpdoc->lpIpData->lpSite, (LPRECT)&rc);
}
break;
}
return GetScode(status);
}
BOOL ItsSafeToClose(void);
void FAR PASCAL InitDoc(BOOL fUntitled)
{
if (gfEmbeddedObject && IsObjectDirty())
{
CleanObject();
}
if (ItsSafeToClose())
CloseMCI(TRUE);
if (fUntitled)
{
LOADSTRING(IDS_UNTITLED, gachFileDevice);
}
}
BOOL CreateDocObjFromFile (
LPCTSTR lpszDoc,
LPDOC lpdoc
)
{
lpdoc->doctype = doctypeFromFile;
// set file name atom
if (lpdoc->aDocName)
GlobalDeleteAtom (lpdoc->aDocName);
lpdoc->aDocName = GlobalAddAtom(lpszDoc);
//SetTitle(lpdoc, lpszDoc);
// register as running
return TRUE;
}
//Open a new document (file or media). Subclass the playback window if
// the device has one. This will be used for drag drop operations.
BOOL OpenDoc (UINT wid, LPTSTR lpsz)
{
if (!DoOpen(wid,lpsz))
return FALSE;
/**********************************************************************
** OLE2NOTE: shut down current doc before openning a new one. this **
** will send OLE_CLOSED to any clients if they exist. **
**********************************************************************/
CreateDocObjFromFile (lpsz, &docMain);
SubClassMCIWindow();
return TRUE;
}
/* SetTitle
* --------
*
* Sets the main window's title bar. The format of the title bar is as follows
*
* If embedded
* <Server App name> - <object type> in <client doc name>
*
* Example: "SNWBOARD.AVI - Media Clip in OLECLI.DOC"
* where OLECLI.DOC is a Winword document
*/
BOOL SetTitle (LPDOC lpdoc, LPCTSTR lpszDoc)
{
TCHAR szBuf[cchFilenameMax];
TCHAR szBuf1[cchFilenameMax];
if (lpszDoc && lpszDoc[0])
{
// Change document name.
if (lpdoc->aDocName)
GlobalDeleteAtom (lpdoc->aDocName);
lpdoc->aDocName = GlobalAddAtom (lpszDoc);
}
if (gfEmbeddedObject)
{
if (!(gwDeviceType & DTMCI_FILEDEV) && (gwCurDevice > 0))
{
lstrcpy(gachWindowTitle,garMciDevices[gwCurDevice].szDeviceName);
}
if (lpszDoc && lpszDoc[0])
{
/* Load "Media Clip in %s":
*/
if(!LOADSTRING(IDS_FORMATEMBEDDEDTITLE, szBuf))
return FALSE;
if (gachWindowTitle[0])
{
/* Format with server app name:
*/
wsprintf (szBuf1, TEXT("%s - %s"), gachWindowTitle, szBuf);
wsprintf (szBuf, szBuf1, gachClassRoot, FileName (lpszDoc));
}
else
{
/* Format without server app name:
*/
wsprintf (szBuf1, TEXT("%s"), szBuf);
wsprintf (szBuf, szBuf1, gachClassRoot, FileName (lpszDoc));
}
}
else
{
return FALSE;
}
SetWindowText (ghwndApp, szBuf);
}
return TRUE;
}