/*--------------------------------------------------------------------------- | SERVER.C | This file has the IClassFactory Interface implementation. It also has | the Vtbl initializations. | | Created By: Vij Rajarajan (VijR) +---------------------------------------------------------------------------*/ #define SERVERONLY #include #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 * - in * * 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; }