/*-----------------------------------------------------------------------------+ | OLE1.C | | | | (C) Copyright Microsoft Corporation 1991. All rights reserved. | | | | Revision History | | 02-Jun-94 AndrewBe created, based upon the OLE1 SERVER.C | | | +-----------------------------------------------------------------------------*/ #ifdef OLE1_HACK /* This was originally server.c in the OLE1 Media Player. * It is here somewhat munged to bolt onto the side of the OLE2 Media Player, * to get around the fact that OLE1/OLE2 interoperability is broken in Daytona. * * The OLE2 interface is Unicode, whereas the OLE1 interface is ANSI. * This accounts for some, though probably not all, of the horrors that are * about to unfold before your eyes. */ #ifndef UNICODE #error This file assumes that UNICODE is defined. #endif #undef UNICODE #define SERVERONLY #include #include #include #include #include #include #include #include "mplayer.h" #include "ole1.h" ////////////////////////////////////////////////////////////////////////// // // (c) Copyright Microsoft Corp. 1991 - All Rights Reserved // ///////////////////////////////////////////////////////////////////////// #include #undef _MAX_PATH // ??? someone hacking? #undef _MAX_DIR // ??? someone hacking? #undef _MAX_FNAME // ??? someone hacking? #undef _MAX_EXT // ??? someone hacking? #include "toolbar.h" DWORD gDocVersion = DOC_VERSION_NONE; extern PSTR gpchFilter; #define WAITDIFFERENTLY // dont ask.... extern UINT gwPlaybarHeight; // tell playbar how tall to make itself // so it covers the title STATICDT BOOL gfMouseUpSeen = FALSE; // OK to close play in place? STATICDT BOOL gfKeyStateUpSeen = FALSE; // OK to close play in place? /* Height of picture given to client to be pasted */ STATICDT UINT gwPastedHeight; /* DELAYED BROKEN LINK */ extern WCHAR gachFile[MAX_PATH]; STATICDT CHAR gachDeviceA[80]; STATICDT WCHAR gachDeviceW[80]; extern BOOL gfBrokenLink; STATICDT int gerr; STATICDT HWND ghwndClient = NULL; STATICDT RECT grcClient; /* ........................ */ extern HANDLE ghInst; extern POINT gptBtnSize; #define abs(x) ((x) < 0 ? -(x) : (x)) /************************************************************************** ***************************************************************************/ #ifndef GetWS #define GetWS(hwnd) GetWindowLongPtr(hwnd, GWL_STYLE) #define PutWS(hwnd, f) SetWindowLongPtr(hwnd, GWL_STYLE, f) #define TestWS(hwnd,f) (GetWS(hwnd) & f) #define SetWS(hwnd, f) PutWS(hwnd, GetWS(hwnd) | f) #define ClrWS(hwnd, f) PutWS(hwnd, GetWS(hwnd) & ~(f)) #endif /************************************************************************ Important Note: No method should ever dispatch a DDE message or allow a DDE message to be dispatched. Therefore, no method should ever enter a message dispatch loop. Also, a method should not show a dialog or message box, because the processing of the dialog box messages will allow DDE messages to be dispatched. the hacky way we enforce this is with the global . see errorbox.c and all the "gfErrorBox++"'s in this file. Note that we are an exe, not a DLL, so this does not rely on non-preemptive scheduling. Should be OK on NT too. ***************************************************************************/ /************************************************************************** GLOBALS ***************************************************************************/ STATICDT BOOL gfUnblockServer; // STATICDT int nBlockCount; #ifndef _WIN32 HHOOK hHookMouse; // Mouse hook handle. HOOKPROC fpMouseHook; // Mouse hook proc address. #else /* ** These functions are exported from mciole32.dll. ** */ typedef BOOL (*LPINSTALLHOOK)( HWND, DWORD ); typedef BOOL (*LPREMOVEHOOK)( VOID ); LPINSTALLHOOK fpInstallHook; LPREMOVEHOOK fpRemoveHook; BOOL fHookInstalled = FALSE; #endif HWND ghwndFocusSave; // saved focus window HMODULE hMciOle; OLECLIPFORMAT cfLink; OLECLIPFORMAT cfOwnerLink; OLECLIPFORMAT cfNative; OLESERVERDOCVTBL docVTbl; OLEOBJECTVTBL itemVTbl; OLESERVERVTBL srvrVTbl; SRVR gSrvr; OLE1DOC gDoc; ITEM gItem; /************************************************************************** STRINGS ***************************************************************************/ #ifdef _WIN32 STATICDT ANSI_SZCODE aszInstallHook[] = "InstallHook"; STATICDT ANSI_SZCODE aszRemoveHook[] = "RemoveHook"; #endif extern ANSI_SZCODE aszAppName[] = "MPlayer"; /* Formatting characters for string macros: */ STATICDT WCHAR szFormatAnsiToUnicode[] = L"%hs"; STATICDT CHAR szFormatUnicodeToAnsi[] = "%ws"; STATICDT WCHAR szFormatUnicodeToUnicode[] = L"%ws"; /* Unicode - ANSI string-copying macros: */ #define COPYSTRINGA2W(pTarget, pSource) wsprintfW(pTarget, szFormatAnsiToUnicode, pSource) #define COPYSTRINGW2A(pTarget, pSource) wsprintfA(pTarget, szFormatUnicodeToAnsi, pSource) #define COPYSTRINGW2W(pTarget, pSource) wsprintfW(pTarget, szFormatUnicodeToUnicode, pSource) /************************************************************************** ***************************************************************************/ void FAR PASCAL Ole1PlayInPlace(HWND hwndApp, HWND hwndClient, LPRECT prc); void FAR PASCAL Ole1EndPlayInPlace(HWND hwndApp); OLESTATUS FAR PASCAL ItemSetData1(LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat, HANDLE hdata); BOOL NEAR PASCAL ScanCmdLine(LPSTR szCmdLine); STATICFN int NEAR PASCAL Ole1ReallyDoVerb(LPOLEOBJECT lpobj, UINT verb, BOOL fShow, BOOL fActivate); STATICFN OLESTATUS NEAR PASCAL SetDataPartII(LPWSTR szFile, LPWSTR szDevice); STATICFN BOOL NetParseFile(LPSTR szFile, LPSTR szPath); int FAR PASCAL ParseOptions(LPTSTR pOpt); extern BOOL FindRealFileName(LPTSTR szFile, int iLen); HWND TopWindow(HWND hwnd); void PASCAL DinkWithWindowStyles(HWND hwnd, BOOL fRestore); HANDLE GetLink( VOID ); /* * */ VOID SetDocVersion( DWORD DocVersion ) { #if DBG if( ( DocVersion != DOC_VERSION_NONE ) && ( gDocVersion != DOC_VERSION_NONE ) ) { DPF0( "Expected gDocVersion == 0!! It's %u\n", gDocVersion ); } #endif /* DBG */ gDocVersion = DocVersion; DPF0( "gDocVersion set to %u\n", DocVersion ); } /************************************************************************** * Ole1UpdateObject() - handle the update of the object * ***************************************************************************/ void Ole1UpdateObject(void) { if (gfEmbeddedObject) { // // some client's (ie Excel 3.00 and PowerPoint 1.0) dont // handle saved notifications, they expect to get a // OLE_CLOSED message. // // we will send a OLE_CLOSED message right before we // revoke the DOC iff gfDirty == -1, see FileNew() // if (SendChangeMsg(OLE_SAVED) == OLE_OK) CleanObject(); else { DPF("Unable to update object, setting gfDirty = -1\n"); gfDirty = -1; } } } /* * */ BOOL FAR PASCAL Ole1FixLinkDialog(LPSTR szFile, LPSTR szDevice, int iLen) { UINT wDevice; char achFile[MAX_PATH + 1]; /* file or device name buffer */ char achTitle[80]; /* string holding the title bar name */ HWND hwndFocus; OPENFILENAME ofn; BOOL f; static SZCODE aszDialog[] = "MciOpenDialog"; // in open.c too. // // I GIVE UP!!! Put up an open dlg box and let them find it themselves! // // If we haven't initialized the device menu yet, do it now. if (gwNumDevices == 0) InitDeviceMenu(); // find out the device number for the specifed device wDevice = gwCurDevice; LoadString(ghInst, IDS_FINDFILE, achFile, CHAR_COUNT(achFile)); wsprintf(achTitle, achFile, FileName(szFile)); // title bar for locate dlg /* Start with the bogus file name */ lstrcpy(achFile, FileName(szFile)); /* Set up the ofn struct */ ofn.lStructSize = sizeof(OPENFILENAME); /* MUST use ActiveWindow to make user deal with us NOW in case of multiple*/ /* broken links */ ofn.hwndOwner = GetActiveWindow(); ofn.hInstance = ghInst; ofn.lpstrFilter = gpchFilter; ofn.lpstrCustomFilter = NULL; ofn.nMaxCustFilter = 0; if (wDevice == 0) ofn.nFilterIndex = gwNumDevices+1; // select "All Files" else ofn.nFilterIndex = wDevice; ofn.lpstrFile = achFile; ofn.nMaxFile = sizeof(achFile); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.lpstrInitialDir = NULL; ofn.lpstrTitle = achTitle; // ofn.Flags = OFN_ENABLETEMPLATE | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_SHAREAWARE | OFN_PATHMUSTEXIST; ofn.nFileOffset = 0; ofn.nFileExtension = 0; ofn.lpstrDefExt = NULL; ofn.lCustData = 0; ofn.lpfnHook = NULL; // ofn.lpTemplateName = aszDialog; ofn.lpTemplateName = NULL; // Show the cursor in case PowerPig is hiding it ShowCursor(TRUE); hwndFocus = GetFocus(); /* Let the user pick a filename */ BlockServer(); gfErrorBox++; f = GetOpenFileName(&ofn); if (f) { lstrcpyn(szFile, achFile, iLen); gfDirty = TRUE; // make sure the object is dirty now } gfErrorBox--; UnblockServer(); SetFocus(hwndFocus); // Put cursor back how it used to be ShowCursor(FALSE); return f; } /**************************************************************************/ /* We've just gotten our delayed message that we need to bring up an open */ /* dialog to let the user fix the broken link, and then we can finish the */ /* SetData and the DoVerb. */ /**************************************************************************/ void FAR PASCAL DelayedFixLink(UINT verb, BOOL fShow, BOOL fActivate) { CHAR achFileA[MAX_PATH]; gfBrokenLink = FALSE; COPYSTRINGW2A(gachDeviceA, garMciDevices[gwCurDevice].szDevice); COPYSTRINGW2W(gachDeviceW, garMciDevices[gwCurDevice].szDevice); COPYSTRINGW2A(achFileA, gachFile); /* Something goes wrong? Get out of here and give up. */ if (!Ole1FixLinkDialog(achFileA, gachDeviceA, CHAR_COUNT(achFileA)) || SetDataPartII(gachFile, gachDeviceW) != OLE_OK) PostMessage(ghwndApp, WM_CLOSE, 0, 0L); // GET OUT !!! else Ole1ReallyDoVerb(NULL, verb, fShow, fActivate); } /************************************************************************** ***************************************************************************/ BOOL FAR PASCAL InitOle1Server(HWND hwnd, HANDLE hInst) { long cb; int err; char aszPlay[40]; char aszEdit[40]; #ifdef _WIN32 /* ** On NT we have to install a global mouse HookProc which has to ** in a DLL. Also we have to tell the DLL which process/thread we are ** interested in, therefore let the DLL install the HookProc. When the ** HookProc detects an "interesting" mouse message it stops the ** device from playing. However, the device "stopping" function is ** inside mplayer, so we have to export it so that the HookProc can ** call it. */ if ( hMciOle ) { fpInstallHook = (LPINSTALLHOOK)GetProcAddress(hMciOle, aszInstallHook); fpRemoveHook = (LPREMOVEHOOK)GetProcAddress(hMciOle, aszRemoveHook); } else { fpInstallHook = NULL; fpRemoveHook = NULL; } #endif cfLink = RegisterClipboardFormat("Link"); cfOwnerLink = RegisterClipboardFormat("OwnerLink"); // The scheme of casting everything to FARPROC relies on then being able // to do a cast on lvalue later to make it all work. Last time I checked // that wouldn't wash on MIPS. So we have be a little cleaner. #define MPI(fn) MakeProcInstance((FARPROC)fn, hInst); // // srvr vtable. // *(FARPROC*)&srvrVTbl.Open = MPI(SrvrOpen); *(FARPROC*)&srvrVTbl.Create = MPI(SrvrCreate); *(FARPROC*)&srvrVTbl.CreateFromTemplate = MPI(SrvrCreateFromTemplate); *(FARPROC*)&srvrVTbl.Edit = MPI(SrvrEdit); *(FARPROC*)&srvrVTbl.Exit = MPI(SrvrExit); *(FARPROC*)&srvrVTbl.Release = MPI(SrvrRelease1); *(FARPROC*)&srvrVTbl.Execute = MPI(SrvrExecute); // // doc table // *(FARPROC*)&docVTbl.Save = MPI(DocSave); *(FARPROC*)&docVTbl.Close = MPI(DocClose); *(FARPROC*)&docVTbl.GetObject = MPI(DocGetObject); *(FARPROC*)&docVTbl.Release = MPI(DocRelease); *(FARPROC*)&docVTbl.SetHostNames = MPI(DocSetHostNames); *(FARPROC*)&docVTbl.SetDocDimensions = MPI(DocSetDocDimensions); *(FARPROC*)&docVTbl.SetColorScheme = MPI(DocSetColorScheme); *(FARPROC*)&docVTbl.Execute = MPI(DocExecute); // // item table. // *(FARPROC*)&itemVTbl.Show = MPI(ItemOpen); *(FARPROC*)&itemVTbl.DoVerb = MPI(ItemDoVerb); *(FARPROC*)&itemVTbl.GetData = MPI(ItemGetData); *(FARPROC*)&itemVTbl.SetData = MPI(ItemSetData1); *(FARPROC*)&itemVTbl.Release = MPI(ItemRelease); *(FARPROC*)&itemVTbl.SetTargetDevice = MPI(ItemSetTargetDevice); *(FARPROC*)&itemVTbl.EnumFormats = MPI(ItemEnumFormats); *(FARPROC*)&itemVTbl.SetBounds = MPI(ItemSetBounds); *(FARPROC*)&itemVTbl.SetColorScheme = MPI(ItemSetColorScheme); gSrvr.lhsrvr = 0L; gDoc.lhdoc = 0L; gItem.lpoleclient = NULL; gSrvr.olesrvr.lpvtbl = &srvrVTbl; err = OleRegisterServer(aszAppName, (LPOLESERVER)&gSrvr, &gSrvr.lhsrvr, hInst, OLE_SERVER_MULTI); if (err != OLE_OK) { gSrvr.lhsrvr = 0L; Error(ghwndApp, IDS_CANTSTARTOLE); return TRUE; } gSrvr.hwnd = hwnd; // corresponding main window return TRUE; } /************************************************************************** ***************************************************************************/ void FAR PASCAL TermServer(void) { if (hMciOle) FreeLibrary(hMciOle); } /************************************************************************** ***************************************************************************/ void FAR PASCAL NewDoc(BOOL fUntitled) { // // some client's (ie Excel 3.00 and PowerPoint 1.0) dont // handle saved notifications, they expect to get a // OLE_CLOSED message. // // if the user has chosen to update the object, but the client did // not then send a OLE_CLOSED message. // if (gfEmbeddedObject && IsObjectDirty()) { UpdateObject(); if (gfDirty == -1) SendChangeMsg(OLE_CLOSED); CleanObject(); } BlockServer(); /* !!! If PlayMCI errors, and we close the client, we get called, but */ /* we can't CloseMCI now or we'll explode. */ if (!gfErrorBox && IsWindowEnabled(ghwndApp)) CloseMCI(TRUE); // app.c has a better way of not dispatching evil timer messages #if 0 // A leftover WM_TIMER is UAE'ing Packager going down if (PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE | PM_NOYIELD)) { DPF("Ack! *** We removed a WM_TIMER msg from someone's queue!\n"); } #endif UnblockServer(); RevokeDocument(); // // register a "untitled" doc????? // if (fUntitled) { LoadStringW(ghInst, IDS_UNTITLED, (LPWSTR)gachFileDevice, 40); RegisterDocument(0,0); } } /************************************************************************** ***************************************************************************/ void FAR PASCAL ServerUnblock() { if (gfUnblockServer) { BOOL fMoreMsgs = TRUE; while (fMoreMsgs && gSrvr.lhsrvr) OleUnblockServer (gSrvr.lhsrvr, &fMoreMsgs); // We have taken care of all the messages in the OLE queue gfUnblockServer = FALSE; } } /************************************************************************** ***************************************************************************/ void FAR PASCAL BlockServer() { // gfErrorBox++; if (nBlockCount++ == 0) OleBlockServer(gSrvr.lhsrvr); } /************************************************************************** ***************************************************************************/ void FAR PASCAL UnblockServer() { /* Don't wrap around! */ if (!nBlockCount) return; if (--nBlockCount == 0) gfUnblockServer = TRUE; // gfErrorBox--; } /************************************************************************** ***************************************************************************/ void FAR PASCAL TerminateServer(void) { LHSERVER lhsrvr; if (gfPlayingInPlace) Ole1EndPlayInPlace(ghwndApp); // Is this right? DPF("IDM_EXIT: Revoking server...\n"); lhsrvr = gSrvr.lhsrvr; if (lhsrvr) { ServerUnblock(); gSrvr.lhsrvr = (LHSERVER)0; ////////ShowWindow(ghwndApp,SW_HIDE); // Insert 2nd obj over 1st in Write bug // RevokeServer won't Destroy us OleRevokeServer(lhsrvr); } else { /* Probably, there never was a server... */ DPF("Closing application window\n"); // This delete server should release the server immediately // EndDialog(ghwndApp, TRUE); // DestroyWindow(ghwndApp); PostMessage(ghwndApp, WM_USER_DESTROY, 0, 0); } } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL SrvrRelease1 (LPOLESERVER lpolesrvr) { LHSERVER lhsrvr; /* If we're visible, but we don't want to be released, then ignore. */ if (gSrvr.lhsrvr && (IsWindowVisible(ghwndApp) || !gfRunWithEmbeddingFlag)) { DPF("SrvrRelease: Ignoring releases...\n"); return OLE_OK; } lhsrvr = gSrvr.lhsrvr; if (lhsrvr) { DPF("SrvrRelease: Calling RevokeServer\n"); ServerUnblock(); gSrvr.lhsrvr = 0; OleRevokeServer(lhsrvr); } else { DPF("SrvrRelease: Closing application window\n"); // This delete server should release the server immediately // EndDialog(ghwndApp, TRUE); // DestroyWindow(ghwndApp); PostMessage(ghwndApp, WM_USER_DESTROY, 0, 0); } return OLE_OK; // return something } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL SrvrExecute (LPOLESERVER lpoledoc, HGLOBAL hCommands) { return OLE_ERROR_GENERIC; } /************************************************************************** ***************************************************************************/ BOOL FAR PASCAL RegisterDocument(LHSERVERDOC lhdoc, LPOLESERVERDOC FAR *lplpoledoc) { /* If we don't have a server, don't even bother. */ if (!gSrvr.lhsrvr) return TRUE; gDoc.hwnd = ghwndApp; // corresponding main window /* should only be one document at a time... */ while (gDoc.lhdoc != (LHSERVERDOC)0 && gDoc.lhdoc != -1) RevokeDocument(); #ifdef WAITDIFFERENTLY while (gDoc.lhdoc == -1) { MSG rMsg; /* variable used for holding a message */ DPF("RegisterDoc: Waiting for document to be released....\n"); /* call the server code and let it unblock the server */ ServerUnblock(); if (!GetMessage(&rMsg, NULL, 0, 0)) { DPF("VERY BAD: got WM_QUIT while waiting...\n"); } TranslateMessage(&rMsg); DispatchMessage(&rMsg); } #endif if (lhdoc == (LHSERVERDOC)0) { CHAR szAnsi[MAX_PATH]; DPF("Registering document: %ws\n", (LPWSTR)gachFileDevice); COPYSTRINGW2A(szAnsi, gachFileDevice); if (OleRegisterServerDoc(gSrvr.lhsrvr, szAnsi, (LPOLESERVERDOC)&gDoc, (LHSERVERDOC FAR *)&gDoc.lhdoc) != OLE_OK) return FALSE; } else { gDoc.lhdoc = lhdoc; } DPF0( "RegisterDocument: Locks on server doc: %x\n", GlobalFlags(gDoc.lhdoc) & (GMEM_LOCKCOUNT | GMEM_INVALID_HANDLE) ); ////UpdateCaption(); //!!! ////DPF("Adding document handle: %lx\n",lhdoc); ////gDoc.aName = GlobalAddAtom(MakeAnsi((LPWSTR)gachFileDevice)); gDoc.oledoc.lpvtbl = &docVTbl; if (lplpoledoc) *lplpoledoc = (LPOLESERVERDOC)&gDoc; SetDocVersion( DOC_VERSION_OLE1 ); return TRUE; } /************************************************************************** ***************************************************************************/ void FAR PASCAL RevokeDocument(void) { LHSERVERDOC lhdoc; if (gDoc.lhdoc == -1) { DPF("RevokeDocument: Document has been revoked, waiting for release!\n"); return; } if (gDoc.lhdoc) { DPF0( "RevokeDocument: Locks on server doc: %x\n", GlobalFlags(gDoc.lhdoc) & (GMEM_LOCKCOUNT | GMEM_INVALID_HANDLE) ); DPF("Revoking document: lhdoc=%lx\n",gDoc.lhdoc); lhdoc = gDoc.lhdoc; if (lhdoc) { gDoc.lhdoc = -1; if (OleRevokeServerDoc(lhdoc) == OLE_WAIT_FOR_RELEASE) { #ifndef WAITDIFFERENTLY while (gDoc.lhdoc != 0) { MSG msg; DPF("RevokeDocument: waiting for release...\n"); /* call the server code and let it unblock the server */ ServerUnblock(); if (!GetMessage(&msg, NULL, 0, 0)) { DPF("VERY BAD: got WM_QUIT while waiting...\n"); } TranslateMessage(&msg); DispatchMessage(&msg); } DPF("RevokeDocument: done waiting for release\n"); #endif } else { //!! WinAssert(gDoc.lhdoc == 0); } SetDocVersion( DOC_VERSION_NONE ); } else { DPF0("Document already revoked!"); } SetEmbeddedObjectFlag(FALSE); } } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL SrvrOpen ( LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpdocname, LPOLESERVERDOC FAR *lplpoledoc) { BOOL f; DPF("SrvrOpen: %s\n",lpdocname); SetEmbeddedObjectFlag(TRUE); BlockServer(); f = OpenMciDevice((LPSTR)lpdocname, (LPSTR)NULL); UnblockServer(); if (!f) return OLE_ERROR_GENERIC; SetEmbeddedObjectFlag(FALSE); RegisterDocument(lhdoc, lplpoledoc); return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL SrvrCreate ( LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpclassname, OLE_LPCSTR lpdocname, LPOLESERVERDOC FAR *lplpoledoc) { DPF("SrvrCreate: %s!%s\n",lpdocname,lpclassname); BlockServer(); CloseMCI(TRUE); UnblockServer(); /* Set the title of the client document we're imbedded in */ COPYSTRINGA2W((LPWSTR)gachDocTitle, lpdocname); RegisterDocument(lhdoc,lplpoledoc); /* You are dirty by default according to OLE */ gfDirty = TRUE; return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL SrvrCreateFromTemplate ( LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpclassname, OLE_LPCSTR lpdocname, OLE_LPCSTR lptemplatename, LPOLESERVERDOC FAR *lplpoledoc) { BOOL f; DPF("SrvrCreateFromTemplate: %s as %s class=%s\n",lptemplatename,lpdocname,lpclassname); SetEmbeddedObjectFlag(TRUE); BlockServer(); f = OpenMciDevice((LPSTR)lptemplatename, (LPSTR)NULL); UnblockServer(); if (!f) return OLE_ERROR_GENERIC; RegisterDocument(lhdoc,lplpoledoc); gfDirty = TRUE; return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL SrvrEdit ( LPOLESERVER lpolesrvr, LHSERVERDOC lhdoc, OLE_LPCSTR lpclassname, OLE_LPCSTR lpdocname, LPOLESERVERDOC FAR *lplpoledoc) { DPF("SrvrEdit: %s class=%s\n",lpdocname,lpclassname); BlockServer(); CloseMCI(TRUE); UnblockServer(); /* Set the title of the client document we're imbedded in */ COPYSTRINGA2W((LPWSTR)gachDocTitle, lpdocname); RegisterDocument(lhdoc,lplpoledoc); return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL SrvrExit ( LPOLESERVER lpolesrvr) { LHSERVER lhsrvr; // Server lib is calling us to exit. // Let us hide the main window. // But let us not delete the window. DPF("SrvrExit\n"); ShowWindow (ghwndApp, SW_HIDE); lhsrvr = gSrvr.lhsrvr; if (lhsrvr) { gSrvr.lhsrvr = 0; OleRevokeServer(lhsrvr); } return OLE_OK; // How does the application ever end? // Application will end when Release is received } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocSave ( LPOLESERVERDOC lpoledoc) { DPF("DocSave\n"); ////BlockServer(); ////FileSave(FALSE); // Save should send change message ////UnblockServer(); return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocClose ( LPOLESERVERDOC lpoledoc) { DPF("DocClose\n"); BlockServer(); NewDoc(FALSE); UnblockServer(); DPF("Leaving DocClose\n"); #ifdef WAITDIFFERENTLY TerminateServer(); #else PostMessage(ghwndApp, WM_CLOSE, 0, 0L); // GET OUT !!! #endif return OLE_OK; // Should we exit the app here? } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocSetHostNames( LPOLESERVERDOC lpoledoc, OLE_LPCSTR lpclientName, OLE_LPCSTR lpdocName) { DPF("DocSetHostNames: %s -- %s\n",lpclientName,lpdocName); COPYSTRINGA2W((LPWSTR)gachDocTitle, lpdocName); SetEmbeddedObjectFlag(TRUE); // update menu items gfValidCaption = FALSE; UpdateDisplay(); return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocSetDocDimensions( LPOLESERVERDOC lpoledoc, OLE_CONST RECT FAR * lprc) { DPF("DocSetDocDimensions [%d,%d,%d,%d]\n", *lprc); return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocRelease ( LPOLESERVERDOC lpoledoc) { DPF("DocRelease\n"); // !!! what is this supposed to do? // Revoke document calls DocRelease. ////if (gDoc.aName) ////////GlobalDeleteAtom (gDoc.aName); /* This marks the document as having been released */ gDoc.lhdoc = 0L; // Should we kill the application here? // No, I don't think so. return OLE_OK; // return something } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocExecute (LPOLESERVERDOC lpoledoc, HANDLE hCommands) { return OLE_ERROR_GENERIC; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocSetColorScheme (LPOLESERVERDOC lpdoc, OLE_CONST LOGPALETTE FAR* lppalette) { return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL DocGetObject ( LPOLESERVERDOC lpoledoc, OLE_LPCSTR lpitemname, LPOLEOBJECT FAR * lplpoleobject, LPOLECLIENT lpoleclient) { DPF("DocGetObject: '%s'\n",lpitemname); gItem.hwnd = ghwndApp; gItem.oleobject.lpvtbl = &itemVTbl; // If the item is not null, then do not show the window. // So do we show the window here, or not? *lplpoleobject = (LPOLEOBJECT)&gItem; gItem.lpoleclient = lpoleclient; /* !!! We have been given OLD options before any updates. We don't need */ /* to parse options here... we'll do it when given our native data in */ /* ItemSetData. */ #if 0 /* Get the options from the item string */ BlockServer(); err = ParseOptions(lpitemname); UnblockServer(); #endif return OLE_OK; } /************************************************************************** get the native data that represents the currenly open MCI file/device. currently this is exactly the same as cfLink data! ***************************************************************************/ STATICFN HANDLE NEAR PASCAL Ole1GetLink () { HANDLE hUnicode; DWORD cbUnicode; LPWSTR pUnicode; DWORD cbAnsi; LPSTR pAnsi; HANDLE hAnsi; DPF("Ole1GetLink\n"); hUnicode = GetLink(); if( !hUnicode ) return NULL; cbUnicode = GlobalSize( hUnicode ); if( cbUnicode == 0 ) return NULL; pUnicode = GlobalLock( hUnicode ); if( !pUnicode ) { GlobalUnlock( hUnicode ); GlobalFree( hUnicode ); return NULL; } cbAnsi = ( cbUnicode * sizeof(CHAR) ) / sizeof(WCHAR); hAnsi = GlobalAlloc( GMEM_DDESHARE | GMEM_ZEROINIT, cbAnsi ); if( !hAnsi ) return NULL; pAnsi = GlobalLock( hAnsi ); if( !pAnsi ) { GlobalFree( hAnsi ); return NULL; } while( *pUnicode ) { DWORD Len; COPYSTRINGW2A( pAnsi, pUnicode ); Len = wcslen( pUnicode ); pAnsi += ( Len + 1 ); pUnicode += ( Len + 1 ); } GlobalUnlock( hUnicode ); GlobalUnlock( hAnsi ); GlobalFree( hUnicode ); return hAnsi; } /************************************************************************** ***************************************************************************/ STATICFN HBITMAP NEAR PASCAL GetBitmap (PITEM pitem) { DPF(" GetBitmap\n"); return BitmapMCI(); } /************************************************************************** ***************************************************************************/ STATICFN HANDLE PASCAL NEAR GetPalette(PITEM pitem) { extern HPALETTE CopyPalette(HPALETTE); // in MCI.C DPF(" GetPalette\n"); return CopyPalette(PaletteMCI()); } /************************************************************************** ***************************************************************************/ STATICFN HANDLE PASCAL NEAR GetDib(PITEM pitem) { HBITMAP hbm; HPALETTE hpal; HANDLE hdib; HDC hdc; extern HANDLE FAR PASCAL DibFromBitmap(HBITMAP hbm, HPALETTE hpal); extern void FAR PASCAL DitherMCI(HANDLE hdib, HPALETTE hpal); DPF(" GetDib\n"); hbm = GetBitmap(pitem); hpal = PaletteMCI(); hdib = DibFromBitmap(hbm, hpal); // // if we are on a palette device. possibly dither to the VGA colors // for apps that dont deal with palettes! // hdc = GetDC(NULL); if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) && (gwOptions & OPT_DITHER)) { DitherMCI(hdib, hpal); hpal = NULL; // no longer working with a palette } ReleaseDC(NULL, hdc); DeleteObject(hbm); return hdib; } /************************************************************************** ***************************************************************************/ STATICFN HANDLE PASCAL NEAR GetPicture (PITEM pitem) { HPALETTE hpal; HANDLE hdib; HANDLE hmfp; HDC hdc; extern HPALETTE CopyPalette(HPALETTE); // in MCI.C HANDLE FAR PASCAL PictureFromDib(HANDLE hdib, HPALETTE hpal); DPF(" GetPicture\n"); hdib = GetDib(pitem); /* If we're dithered, don't use a palette */ hdc = GetDC(NULL); if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) && (gwOptions & OPT_DITHER)) hpal = NULL; else hpal = PaletteMCI(); if (hpal) hpal = CopyPalette(hpal); ReleaseDC(NULL, hdc); hmfp = PictureFromDib(hdib, hpal); if (hpal) DeleteObject(hpal); GlobalFree(hdib); return hmfp; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL ItemOpen ( LPOLEOBJECT lpoleobject, BOOL fActivate) { /* Start an edit session, and if there is something to play, play it */ /* This is called by Excel to play an object, because it doesn't know */ /* about the PLAY verb. It's also called to Insert a New object into */ /* any client. */ /* All this work is done in our special -1 verb in ReallyDoVerb. */ DPF("ItemOpen\n"); Ole1ReallyDoVerb(lpoleobject, (UINT)(-1), TRUE, fActivate); return OLE_OK; } /************************************************************************** ***************************************************************************/ /************************************************************************** * I know this looks odd, but ItemDoVerb is exported so we can't call it* * internally and sometimes we need to. * ***************************************************************************/ OLESTATUS FAR PASCAL ItemDoVerb ( LPOLEOBJECT lpobj, UINT verb, BOOL fShow, BOOL fActivate) { return Ole1ReallyDoVerb(lpobj, verb, fShow, fActivate); } /************************************************************************** ***************************************************************************/ typedef enum { OLE1_OLEOK, /* 0 Function operated correctly */ OLE1_OLEWAIT_FOR_RELEASE, /* 1 Command has been initiated, client */ /* must wait for release. keep dispatching */ /* messages till OLE1_OLERELESE in callback */ OLE1_OLEBUSY, /* 2 Tried to execute a method while another */ /* method is in progress. */ OLE1_OLEERROR_PROTECT_ONLY, /* 3 Ole APIs are called in real mode */ OLE1_OLEERROR_MEMORY, /* 4 Could not alloc or lock memory */ OLE1_OLEERROR_STREAM, /* 5 (OLESTREAM) stream error */ OLE1_OLEERROR_STATIC, /* 6 Non static object expected */ OLE1_OLEERROR_BLANK, /* 7 Critical data missing */ OLE1_OLEERROR_DRAW, /* 8 Error while drawing */ OLE1_OLEERROR_METAFILE, /* 9 Invalid metafile */ OLE1_OLEERROR_ABORT, /* 10 Client chose to abort metafile drawing */ OLE1_OLEERROR_CLIPBOARD, /* 11 Failed to get/set clipboard data */ OLE1_OLEERROR_FORMAT, /* 12 Requested format is not available */ OLE1_OLEERROR_OBJECT, /* 13 Not a valid object */ OLE1_OLEERROR_OPTION, /* 14 Invalid option(link update / render) */ OLE1_OLEERROR_PROTOCOL, /* 15 Invalid protocol */ OLE1_OLEERROR_ADDRESS, /* 16 One of the pointers is invalid */ OLE1_OLEERROR_NOT_EQUAL, /* 17 Objects are not equal */ OLE1_OLEERROR_HANDLE, /* 18 Invalid handle encountered */ OLE1_OLEERROR_GENERIC, /* 19 Some general error */ OLE1_OLEERROR_CLASS, /* 20 Invalid class */ OLE1_OLEERROR_SYNTAX, /* 21 Command syntax is invalid */ OLE1_OLEERROR_DATATYPE, /* 22 Data format is not supported */ OLE1_OLEERROR_PALETTE, /* 23 Invalid color palette */ OLE1_OLEERROR_NOT_LINK, /* 24 Not a linked object */ OLE1_OLEERROR_NOT_EMPTY, /* 25 Client doc contains objects. */ OLE1_OLEERROR_SIZE, /* 26 Incorrect buffer size passed to the api */ /* that places some string in caller's */ /* buffer */ OLE1_OLEERROR_DRIVE, /* 27 Drive letter in doc name is invalid */ OLE1_OLEERROR_NETWORK, /* 28 Failed to establish connection to a */ /* network share on which the document */ /* is located */ OLE1_OLEERROR_NAME, /* 29 Invalid name(doc name, object name), */ /* etc.. passed to the APIs */ OLE1_OLEERROR_TEMPLATE, /* 30 Server failed to load template */ OLE1_OLEERROR_NEW, /* 31 Server failed to create new doc */ OLE1_OLEERROR_EDIT, /* 32 Server failed to create embedded */ /* instance */ OLE1_OLEERROR_OPEN, /* 33 Server failed to open document, */ /* possible invalid link */ OLE1_OLEERROR_NOT_OPEN, /* 34 Object is not open for editing */ OLE1_OLEERROR_LAUNCH, /* 35 Failed to launch server */ OLE1_OLEERROR_COMM, /* 36 Failed to communicate with server */ OLE1_OLEERROR_TERMINATE, /* 37 Error in termination */ OLE1_OLEERROR_COMMAND, /* 38 Error in execute */ OLE1_OLEERROR_SHOW, /* 39 Error in show */ OLE1_OLEERROR_DOVERB, /* 40 Error in sending do verb, or invalid */ /* verb */ OLE1_OLEERROR_ADVISE_NATIVE, /* 41 Item could be missing */ OLE1_OLEERROR_ADVISE_PICT, /* 42 Item could be missing or server doesn't */ /* this format. */ OLE1_OLEERROR_ADVISE_RENAME, /* 43 Server doesn't support rename */ OLE1_OLEERROR_POKE_NATIVE, /* 44 Failure of poking native data to server */ OLE1_OLEERROR_REQUEST_NATIVE, /* 45 Server failed to render native data */ OLE1_OLEERROR_REQUEST_PICT, /* 46 Server failed to render presentation */ /* data */ OLE1_OLEERROR_SERVER_BLOCKED, /* 47 Trying to block a blocked server or */ /* trying to revoke a blocked server */ /* or document */ OLE1_OLEERROR_REGISTRATION, /* 48 Server is not registered in regestation */ /* data base */ OLE1_OLEERROR_ALREADY_REGISTERED,/*49 Trying to register same doc multiple */ /* times */ OLE1_OLEERROR_TASK, /* 50 Server or client task is invalid */ OLE1_OLEERROR_OUTOFDATE, /* 51 Object is out of date */ OLE1_OLEERROR_CANT_UPDATE_CLIENT,/* 52 Embed doc's client doesn't accept */ /* updates */ OLE1_OLEERROR_UPDATE, /* 53 erorr while trying to update */ OLE1_OLEERROR_SETDATA_FORMAT, /* 54 Server app doesn't understand the */ /* format given to its SetData method */ OLE1_OLEERROR_STATIC_FROM_OTHER_OS,/* 55 trying to load a static object created */ /* on another Operating System */ /* Following are warnings */ OLE1_OLEWARN_DELETE_DATA = 1000 /* Caller must delete the data when he is */ /* done with it. */ } OLE1_OLESTATUS; OLE1_OLESTATUS (FAR PASCAL *OleQueryObjPos)(LPVOID lpobj, HWND FAR* lphwnd, LPRECT lprc, LPRECT lprcWBounds); STATICFN int NEAR PASCAL Ole1ReallyDoVerb ( LPOLEOBJECT lpobj, UINT verb, BOOL fShow, BOOL fActivate) { BOOL fWindowWasVisible = IsWindowVisible(ghwndApp); int dx,dy; HWND hwndClient; HWND hwndT; RECT rcSave; RECT rcClient; RECT rc; UINT err; HPALETTE hpal; HDC hdc; INT xTextExt, yTextExt; int yOrig, yNow, xOrig, ytitleNow, xtitleOrig, xNow; int xIndent; int wWinNow; // ACK! We haven't finished doing ItemSetData yet because we have to // bring up an open dialog. So we can't do the ItemDoVerb yet. We will // Post a message to ourselves that will do both the SetData and DoVerb // and we will succeed the DoVerb right now so the client will be happy // and start dispatching messages again. if (gfBrokenLink) { // We need to get client info NOW because our OLE handler can only // answer this question now... if we click on two broken links at the // same time, it will get confused about which object we want. gerr = OleQueryObjPos(lpobj, &ghwndClient, &grcClient, NULL); PostMessage(ghwndApp, WM_DO_VERB, verb, MAKELONG(fShow, fActivate)); return OLE_OK; } // // dont even try to nest things. // if (gfPlayingInPlace) return OLE_OK; if (verb == OLEVERB_PRIMARY) { DPF("ItemDoVerb: Play\n"); // // if the device can't window and the user does not want a playbar // dont play in place - just start the media and run invisible. // if (!(gwDeviceType & DTMCI_CANWINDOW) && !(gwOptions & OPT_BAR)) { gwOptions &= ~OPT_PLAY; } // // Select the palette in right now on behalf of the active // window, so USER will think it is palette aware. // // any palette will do we dont even have to realize it!! // if ((hpal = PaletteMCI()) && (hwndT = GetActiveWindow())) { hdc = GetDC(hwndT); hpal = SelectPalette(hdc, hpal, FALSE); SelectPalette(hdc, hpal, FALSE); ReleaseDC(hwndT, hdc); } if (ghwndClient) { hwndClient = ghwndClient; err = gerr; rcClient = grcClient; ghwndClient = NULL; } else err = OleQueryObjPos(lpobj, &hwndClient, &rcClient, NULL); #ifdef DEBUG if (gwOptions & OPT_PLAY) { DPF("ObjQueryObjPos: hwnd=%04X [%d %d %d %d]\n",hwndClient, rcClient); if (err != OLE_OK) { DPF("ItemDoVerb: CANT GET OBJECT POSITION!!!\n"); } else { if (!(gwDeviceType & DTMCI_CANWINDOW)) DPF("ItemDoVerb: DEVICE CANT WINDOW\n"); if (!IsWindow(hwndClient)) DPF("ItemDoVerb: Invalid Client Window?\n"); if (!IsWindowVisible(hwndClient)) DPF("ItemDoVerb: Client window is not visible, playing in a popup\n"); } } #endif /* We want to play in place and we can. */ /* If we're a link, not an embedded object, and there was an instance */ /* of MPlayer up when we said "Play" that was already editing this */ /* file, we don't want to play in place... we'll just play in that */ /* instance. We can tell this by the fact that our main MPlayer */ /* window is already visible. */ if (err == OLE_OK && (gwOptions & OPT_PLAY) && IsWindow(hwndClient) && IsWindowVisible(hwndClient) && !fWindowWasVisible) { extern HPALETTE FAR PASCAL CreateSystemPalette(void); rc = grcSize; // default playback window size for this movie /* If we can't window, or something's wrong, use ICON size */ if (IsRectEmpty(&rc)) SetRect(&rc, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON)); /* rcSave is the area for the MCI window above the control bar */ /* (if we have one). */ /* rcClient is the area of the MCI window (0 based) to play in.*/ /* Control bar may be longer than picutre, so rcClient may be */ /* smaller than rcSave. */ rcSave = rcClient; // remember stretched size /* Make rcClient 0 based from rcSave */ rcClient.left = 0; rcClient.right = rcSave.right - rcSave.left; rcClient.top = 0; rcClient.bottom = rcSave.bottom - rcSave.top; /* Assume playbar will be regular height for now */ if (gwOptions & OPT_BAR) gwPlaybarHeight = TOOLBAR_HEIGHT; else gwPlaybarHeight = 0; // // munge rectangle to account for a title in the picture // and the fact that picture is centred above title. // Remember, it's been stretched around. // if (gwOptions & OPT_TITLE) { CHAR szAnsi[MAX_PATH]; hdc = GetDC(NULL); if (ghfontMap) SelectObject(hdc, ghfontMap); #ifdef _WIN32 COPYSTRINGW2A(szAnsi, gachCaption); MGetTextExtent( hdc, szAnsi, lstrlen(szAnsi), &xTextExt, &yTextExt); #else xTextExt = GetTextExtent(hdc, gachCaption, lstrlen(gachCaption)); #endif ReleaseDC(NULL, hdc); if (gwPastedHeight) yOrig = gwPastedHeight; else yOrig = rc.bottom - rc.top; xOrig = rc.right - rc.left; xtitleOrig = max(xTextExt + 4, xOrig); yNow = rcClient.bottom - rcClient.top; xNow = rcClient.right - rcClient.left; ytitleNow = (int)((long)yNow - ((long)yOrig * yNow) / (yOrig + TITLE_HEIGHT)); /* for windowed devices, center the playback area above the */ /* control bar if the control bar is longer. */ if (gwDeviceType & DTMCI_CANWINDOW) { wWinNow =(int)((long)xOrig * (long)xNow / (long)xtitleOrig); xIndent = (xNow - wWinNow) / 2; rcClient.left += xIndent; rcClient.right = rcClient.left + wWinNow; } // Align top of control bar with the top of the title bar. // The control bar (if there) will appear under rcSave. rcClient.bottom = rcClient.top + yNow - ytitleNow; rcSave.bottom = rcSave.top + yNow - ytitleNow; /* When we make the playbar, make it cover the title */ /* if the caption was stretched taller than ordinary.*/ if (gwOptions & OPT_BAR) gwPlaybarHeight = max(ytitleNow, TOOLBAR_HEIGHT); } /* Enforce a minimum width for the control bar */ if ((gwOptions & OPT_BAR) && (rcSave.right - rcSave.left < 3 * GetSystemMetrics(SM_CXICON))){ rcSave.right = rcSave.left + 3 * GetSystemMetrics(SM_CXICON); if (gwDeviceType & DTMCI_CANWINDOW) xIndent = TRUE; // force SetWindowMCI to be called to // avoid stretching to this new size. } if (gwDeviceType & DTMCI_CANWINDOW) { // // If we've only stretched a bit, don't stretch at all. // We might be off a bit due to rounding problems. // dx = (rcClient.right - rcClient.left) - (rc.right - rc.left); dy = (rcClient.bottom - rcClient.top) - (rc.bottom - rc.top); if (dx && abs(dx) <= 2) { DPF("Adjusting for x round off\n"); rcClient.right = rcClient.left + (rc.right - rc.left); // Fix Save rect too rcSave.right = rcSave.left + (rc.right - rc.left); } if (dy && abs(dy) <= 2) { DPF("Adjusting for y round off\n"); rcClient.bottom = rcClient.top + (rc.bottom - rc.top); // Fix Save rect, too. rcSave.bottom = rcSave.top + (rc.bottom - rc.top); } // // try to get the right palette from the client, if our // pesentation data was dithered or, the user asked us to // always use the object palette, then ignore any client // palette. // #ifdef DEBUG if (GetProfileInt("options", "UseClientPalette", !(gwOptions & OPT_USEPALETTE))) gwOptions &= ~OPT_USEPALETTE; else gwOptions |= OPT_USEPALETTE; #endif if (!(gwOptions & OPT_USEPALETTE) && !(gwOptions & OPT_DITHER)) { // // try to get a OWNDC Palette of the client, PowerPoint // uses a PC_RESERVED palette in "SlideShow" mode. so // we must use it's exact palette. // hdc = GetDC(hwndClient); hpal = SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE); SelectPalette(hdc, hpal, FALSE); ReleaseDC(hwndClient, hdc); if (hpal == NULL || hpal == GetStockObject(DEFAULT_PALETTE)) { /* Assume client realized the proper palette for us */ DPF("Using system palette\n"); if (ghpalApp) DeleteObject(ghpalApp); hpal = ghpalApp = CreateSystemPalette(); } else { DPF("Using clients OWNDC palette\n"); } if (hpal) SetPaletteMCI(hpal); } else { DPF("Using MCI Object's normal palette\n"); } } else { // // for non window devices, just have the playbar show up! // so use a zero height MCI Window area. // rcSave.top = rcSave.bottom; } // // if we are not in small mode, get there now // if (!gfPlayOnly) { ShowWindow(ghwndApp, SW_HIDE); gfPlayOnly = TRUE; SizeMPlayer(); } ClrWS(ghwndApp, WS_THICKFRAME|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_BORDER); if (gwOptions & OPT_BORDER) SetWS(ghwndApp, WS_BORDER); /* Set the size of Mplayer to have enough space for the MCI */ /* playback area and a playbar and the non-client area. */ rcSave.bottom += gwPlaybarHeight; AdjustWindowRect(&rcSave, GetWS(ghwndApp), FALSE); Ole1PlayInPlace(ghwndApp, hwndClient, &rcSave); fShow = FALSE; fActivate = FALSE; /* become visible */ ShowWindow(ghwndApp,SW_SHOWNA); /* Remember to play the video in the rcClient area of rcSave */ if ((gwDeviceType & DTMCI_CANWINDOW) && (gwOptions & OPT_TITLE) && xIndent != 0) SetDestRectMCI(&rcClient); /* Let keyboard interface work on control bar, and let the */ /* accelerators go through. */ toolbarSetFocus(ghwndToolbar, BTN_PLAY); SetFocus(ghwndToolbar); gfCloseAfterPlaying = TRUE; /* We won't play in place - use a popup window or nothing. */ } else { /* If we want a playbar, then use MPlayer reduced mode to play. */ /* If we don't want one, then don't show mplayer's window - */ /* we'll just use the default MCI window (for a windowed device)*/ /* or nothing for a non-windowed device. If we stole an already*/ /* running instance of mplayer, we must use it and not run */ /* silently. */ if ((gwOptions & OPT_BAR) || fWindowWasVisible) { DPF("Using Toplevel window for playback\n"); /* go to our little miniature version */ if (!gfPlayOnly && !fWindowWasVisible) { gwPlaybarHeight = TOOLBAR_HEIGHT; gfPlayOnly = TRUE; SizeMPlayer(); } fShow = fActivate = TRUE; gfCloseAfterPlaying = !fWindowWasVisible; } else { DPF("Running silently\n"); if (!fWindowWasVisible) SetWindowMCI(NULL); // make sure we're using default MCI win fShow = fActivate = FALSE; gfCloseAfterPlaying = TRUE; // we're invisible, so close auto. } } Yield(); // If play goes to full screen mode, PowerPig will Yield(); // time out and put up errors thinking we didn't play. PostMessage(ghwndApp, WM_COMMAND, ID_PLAYSEL, 0); // play selection } else if (verb == 1) { DPF("ItemDoVerb: Edit\n"); if (gfPlayOnly) { gfPlayOnly = FALSE; SizeMPlayer(); } /* If we come up empty, it's OK to be in OPEN or NOT_READY mode and */ /* don't try to seek anywhere. */ if (gwDeviceID) { switch (gwStatus) { case MCI_MODE_OPEN: case MCI_MODE_NOT_READY: Error(ghwndApp, IDS_CANTEDIT); break; default: // Seek to the position we were when we copied. Stop first. if (StopMCI()) { // fix state so Seek recognizes we're stopped gwStatus = MCI_MODE_STOP; SeekMCI(gdwPosition); } break; } } /* Let UpdateDisplay set focus properly by saying we're invalid */ gwStatus = (UINT)(-1); /* Our special ItemOpen verb */ } else if (verb == -1) { Ole1ReallyDoVerb(lpobj, 1, fShow, fActivate); if (gwDeviceID) Ole1ReallyDoVerb(lpobj, OLEVERB_PRIMARY, fShow, fActivate); return OLE_OK; } else { DPF("ItemDoVerb: Unknown verb: %d\n", verb); } if (fShow) { ShowWindow(ghwndApp, SW_SHOW); if (IsIconic(ghwndApp)) SendMessage(ghwndApp, WM_SYSCOMMAND, SC_RESTORE, 0L); } if (fActivate) { BringWindowToTop (ghwndApp); // let WM_ACTIVATE put client SetActiveWindow (ghwndApp); // underneath us } return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL ItemRelease ( LPOLEOBJECT lpoleobject) { DPF("ItemRelease\n"); gItem.lpoleclient = NULL; return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL ItemGetData ( LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat, LPHANDLE lphandle) { PITEM pitem; DPF("ItemGetData\n"); #ifndef _WIN32 pitem = (PITEM)(WORD)(DWORD)lpoleobject; #else // LKG: What was that doing? Are they unpacking something subtle? pitem = (PITEM)lpoleobject; #endif //_WIN32 if (cfFormat == cfNative) { *lphandle = Ole1GetLink (); if (!(*lphandle)) return OLE_ERROR_MEMORY; if (gfEmbeddedObject) CleanObject(); return OLE_OK; } *lphandle = NULL; if (cfFormat == CF_METAFILEPICT) { *lphandle = GetPicture (pitem); } else if (cfFormat == CF_PALETTE) { *lphandle = GetPalette(pitem); } else if (cfFormat == CF_DIB) { *lphandle = GetDib(pitem); } else if (cfFormat == cfLink || cfFormat == cfOwnerLink){ *lphandle = Ole1GetLink (); } else return OLE_ERROR_MEMORY; // this is actually unknown format. if (!(*lphandle)) return OLE_ERROR_MEMORY; // honestly this time return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL ItemSetTargetDevice ( LPOLEOBJECT lpoleobject, HGLOBAL hdata) { DPF("ItemSetTargetDevice\n"); return OLE_OK; } /************************************************************************** ***************************************************************************/ STATICFN OLESTATUS NEAR PASCAL SetDataPartII(LPWSTR szFile, LPWSTR szDevice) { int status = OLE_OK; LHSERVERDOC lhdocTemp; // TERRIBLE HACK! set gfEmbeddedObject so OpenMCI does // not re-register this document!!! // BlockServer(); lhdocTemp = gDoc.lhdoc; gDoc.lhdoc = (LHSERVERDOC)0; /* So it won't be killed by CloseMCI!! */ gfEmbeddedObject++; /* Coming up: Horrible cast to get rid of warning. * * This file is compiled non-Unicode, in contrast to the rest of MPlayer. * This means that LPTSTR in the function prototypes mean different things * depending on who included them. OpenMciDevice and other Unicode * routines called from this module expect Unicode strings, but the * compiler thinks they're ANSI. We can keep the compiler happy by * casting them to LPTSTR. Does that make sense? * * Places where this unspeakable act is perpetrated are indicated thus: */ if (!OpenMciDevice((LPTSTR)szFile, (LPTSTR)szDevice)) // ^^^^^^^^ ^^^^^^^^ status = OLE_ERROR_FORMAT; gfEmbeddedObject--; gDoc.lhdoc = lhdocTemp; /* Set the selection to what we parsed in ParseOptions. */ if (status == OLE_OK) { SendMessage(ghwndTrackbar, TBM_SETSELSTART, 0, glSelStart); SendMessage(ghwndTrackbar, TBM_SETSELEND, 0, glSelEnd); } UnblockServer(); return status; } /**************************************************************************/ /**************************************************************************/ OLESTATUS FAR PASCAL ItemSetData1(LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat, HANDLE hdata) { LPBYTE p, pSave, pT; // Why BYTE?? And is this heading // for UNICODE trouble? LPWSTR pUnicode; LPSTR szFile, szDevice; char achFile[MAX_PATH]; char ach[40]; OLESTATUS status; WCHAR FileNameW[MAX_PATH]; DPF("ItemSetData1\n"); if (hdata == NULL) return OLE_ERROR_MEMORY; if (cfFormat != cfNative) return OLE_ERROR_FORMAT; p = GlobalLock(hdata); if (p == NULL) return OLE_ERROR_MEMORY; szFile = p + lstrlen((LPSTR)p) + 1; // pick off the Filename p = szFile + lstrlen(szFile) + 1; pSave = p; szDevice = ach; // copy over Device name and for (pT = ach; *p && *p != ',';) // NULL terminate it (it ends *pT++ = *p++; // with a ',' right now). *pT = '\0'; #ifdef DEBUG DPF(" %s|%s!%s\n", (LPSTR)p, (LPSTR)szFile, (LPSTR)szDevice); #endif BlockServer(); // cause CloseMCI can yield CloseMCI(TRUE); // nuke old gachCaption UnblockServer(); pUnicode = AllocateUnicodeString(pSave); if( !pUnicode ) return OLE_ERROR_MEMORY; ParseOptions((LPTSTR)pUnicode); // this will set new gachCaption // YUK ^^^^^^^^ \\ FreeUnicodeString(pUnicode); // If this file doesn't exist, we won't continue setting data, we will // succeed and get out, and do it later, because we can't bring up a dialog // right now because clients like WinWord won't dispatch any msgs. lstrcpyn(achFile, szFile, sizeof(achFile)); // if the filename we were given is bad, try and find it somewhere COPYSTRINGA2W(FileNameW, szFile); if (FindRealFileName((LPTSTR)FileNameW, sizeof(achFile))) { // YUK ^^^^^^^^ \\ // We found it on the disk somewhere, so continue with SetData WCHAR szDeviceW[80]; COPYSTRINGA2W(szDeviceW, szDevice); status = SetDataPartII(FileNameW, szDeviceW); } else { // Nowhere to be found. We need to ask the user to find it... LATER!! if (gfBrokenLink) { DPF("ACK!! Got Second ItemSetData with BrokenLink!!"); return OLE_ERROR_GENERIC; } // Succeed to ItemSetData so client will be happy lstrcpyn(gachDeviceA, szDevice, sizeof(gachDeviceA)); COPYSTRINGA2W(gachFile, szFile); gfBrokenLink = TRUE; status = OLE_OK; } return status; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL ItemSetColorScheme (LPOLEOBJECT lpobj, OLE_CONST LOGPALETTE FAR * lppalette) { DPF("ItemSetColorScheme\n"); return OLE_OK; } /************************************************************************** ***************************************************************************/ OLESTATUS FAR PASCAL ItemSetBounds (LPOLEOBJECT lpobj, OLE_CONST RECT FAR* lprc) { DPF("ItemSetBounds: [%d,%d,%d,%d]\n", *lprc); return OLE_OK; } /************************************************************************** ***************************************************************************/ OLECLIPFORMAT FAR PASCAL ItemEnumFormats( LPOLEOBJECT lpoleobject, OLECLIPFORMAT cfFormat) { ////DPF("ItemEnumFormats: %u\n",cfFormat); if (cfFormat == 0) return cfLink; if (cfFormat == cfLink) return cfOwnerLink; if (cfFormat == cfOwnerLink) return CF_METAFILEPICT; if (cfFormat == CF_METAFILEPICT) return CF_DIB; if (cfFormat == CF_DIB) return CF_PALETTE; if (cfFormat == CF_PALETTE) return cfNative; //if (cfFormat == cfNative) // return NULL; return (OLECLIPFORMAT)0; } /************************************************************************** ***************************************************************************/ int FAR PASCAL SendChangeMsg (UINT options) { CHAR szAnsi[MAX_PATH]; if (gDoc.lhdoc && gDoc.lhdoc != -1) { if (options == OLE_SAVED) { DPF("SendChangeMsg(OLE_SAVED): Calling OleSavedServerDoc\n"); DPF0( "SendChangeMsg: Locks on server doc: %x\n", GlobalFlags(gDoc.lhdoc) & (GMEM_LOCKCOUNT | GMEM_INVALID_HANDLE) ); return OleSavedServerDoc(gDoc.lhdoc); } else if (options == OLE_RENAMED) { DPF("SendChangeMsg(OLE_RENAMED): new name is '%ws'.\n", (LPWSTR)gachFileDevice); COPYSTRINGW2A(szAnsi, gachFileDevice); return OleRenameServerDoc(gDoc.lhdoc, szAnsi); } else if (gItem.lpoleclient) { DPF("SendChangeMsg(%d) client=%lx\n",options,gItem.lpoleclient); return (*gItem.lpoleclient->lpvtbl->CallBack) (gItem.lpoleclient, options, (LPOLEOBJECT)&gItem); } } return OLE_OK; } /************************************************************************** ***************************************************************************/ void FAR PASCAL CopyObject(HWND hwnd) { PITEM pitem = &gItem; // // we put two types of OLE objects in the clipboard, the type of // OLE object is determined by the *order* of the clipboard data // // Embedded Object: // cfNative // OwnerLink // Picture // ObjectLink // // Linked Object: // OwnerLink // Picture // ObjectLink // if (OpenClipboard (hwnd)) { // Copying an object can take a long time - especially large AVI frames // Tell the user its coffee time. HCURSOR hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT)); BlockServer(); EmptyClipboard(); SetClipboardData(cfNative, Ole1GetLink()); /* Don't ask me why we do this even if it is untitled... */ SetClipboardData (cfOwnerLink, Ole1GetLink()); CopyMCI(NULL); #if 0 // DON'T OFFER LINKS ANYMORE! /* Only offer link data if not untitled and not a embedded object */ if (gwDeviceType & DTMCI_FILEDEV) SetClipboardData(cfLink, Ole1GetLink()); #endif UnblockServer(); CloseClipboard(); SetCursor(hcurPrev); // We're back!!! } } /************************************************************************** ***************************************************************************/ /************************************************************************** STUFF FOR PLAY IN PLACE ***************************************************************************/ #ifndef _WIN32 /************************************************************************** ***************************************************************************/ LRESULT CALLBACK _EXPORT MouseHook(int hc, WPARAM wParam, LPARAM lParam) { LPMOUSEHOOKSTRUCT lpmh = (LPVOID)lParam; BOOL fDownNow, fDownBefore; // // NOTE SS != DS // if (hc == HC_ACTION) { #ifdef XDEBUG char ach[80]; wsprintf( ach , "MouseHook: %c%c pt=[%d,%d] hwnd=%04X ht=%04X\r\n" , (GetAsyncKeyState(VK_LBUTTON) < 0 ? 'L' : ' ') , (GetAsyncKeyState(VK_RBUTTON) < 0 ? 'R' : ' ') , lpmh->pt , lpmh->hwnd , lpmh->wHitTestCode ); OutputDebugString(ach); #endif /* If the mouse was DOWN when we started, we wait until it comes up */ /* before we let mouse downs kill us. If KeyState said it was DOWN */ /* we wait until it says it is UP before we let DOWN KeyStates kill */ /* us. */ /* We're checking Async because we have to... it's the NOW state. */ /* We're ALSO checking GetKeyState because Faris' machine misses */ /* some mouse downs unless we call every function possible !!**!!** */ fDownNow = GetAsyncKeyState(VK_LBUTTON) || GetAsyncKeyState(VK_RBUTTON); fDownBefore = GetKeyState(VK_LBUTTON) || GetKeyState(VK_RBUTTON); if ((fDownNow && gfMouseUpSeen) || (fDownBefore && gfKeyStateUpSeen)) { // // the user is clicking on the client DOC, allow him/her to // only click on the caption (for moving sizing) or we will // exit. // if (lpmh->hwnd != GetDesktopWindow() && lpmh->wHitTestCode != HTCAPTION) { // Do this NOW before anybody gets a chance to yield and draw // with the wrong styles... if (gfPlayingInPlace) Ole1EndPlayInPlace(ghwndApp); PostMessage(ghwndApp, WM_CLOSE, 0, 0L); // GET OUT !!! } } if (!fDownNow) gfMouseUpSeen = TRUE; if (!fDownBefore) gfKeyStateUpSeen = TRUE; } return CallNextHookEx(hHookMouse, hc, wParam, lParam); } #endif /************************************************************************** ***************************************************************************/ void FAR PASCAL Ole1PlayInPlace(HWND hwndApp, HWND hwndClient, LPRECT prc) { HWND hwndP; DPF("Ole1PlayInPlace(%04X, %04X, [%d %d %d %d])\n", hwndApp, hwndClient, *prc); if (gfPlayingInPlace) // this is bad return; #ifdef DEBUG if (GetPrivateProfileInt("options", "PopupWindow", FALSE, "mplayer.ini")) #else if (FALSE) #endif { DPF("Using Popup window for playback\n"); // // this is code for a popup window. // ClientToScreen(hwndClient, (LPPOINT)prc); ClientToScreen(hwndClient, (LPPOINT)prc+1); SetWS(hwndApp, WS_POPUP); hwndP = TopWindow(hwndClient); #ifndef _WIN32 // I haven't the faintest idea what this is trying to do, but I see it's // within the scope of a retail if(FALSE) anyway. // If you understand it then either delete the function or replace this comment. // Laurie SetWindowWord(hwndApp, GWW_HWNDPARENT, (WORD)hwndP); // set owner #endif gfParentWasEnabled = IsWindowEnabled(hwndP); EnableWindow(hwndP, FALSE); } else { DPF("Using Child window for playback\n"); SetWS(hwndApp, WS_CHILD); SetParent(hwndApp, hwndClient); DinkWithWindowStyles(hwndApp, FALSE); } gfPlayingInPlace = TRUE; SetWindowPos(hwndApp, HWND_TOP, prc->left,prc->top, prc->right - prc->left, prc->bottom - prc->top, SWP_NOACTIVATE); #ifndef _WIN32 if (fpMouseHook == NULL) fpMouseHook = (HOOKPROC)MakeProcInstance((FARPROC)MouseHook, ghInst); #endif // // Is the key down at this INSTANT ??? Then wait until it comes up before // we allow GetAsyncKeyState to make us go away // gfMouseUpSeen = !((GetAsyncKeyState(VK_LBUTTON) & 0x8000) || (GetAsyncKeyState(VK_RBUTTON) & 0x8000)); // // Is GetKeyState saying it's down? If so, wait until GetKeyState returns // up before we let GetKeyState kill us. // gfKeyStateUpSeen= !(GetKeyState(VK_LBUTTON) || GetKeyState(VK_RBUTTON)); #ifdef _WIN32 /* ** Tell mciole32.dll to install its mouse HookProc. */ #ifdef DEBUG if ( fHookInstalled ) { DPF( "Hook already installed\n" ); DebugBreak(); } #endif if ( fpInstallHook ) { DWORD wow_thread_id = 0L; /* ** This is a HACK. If the client applications is a WOW app the ** HIWORD of the window handle will be 0xFFFF. */ if ( HIWORD(hwndClient) == 0xFFFF ) { wow_thread_id = GetWindowThreadProcessId( hwndClient, NULL ); } fHookInstalled = (*fpInstallHook)( ghwndApp, wow_thread_id ); } #else /* !_WIN32 */ hHookMouse = SetWindowsHookEx( WH_MOUSE, fpMouseHook, ghInst, GetWindowTask(hwndClient) ); #endif ghwndFocusSave = GetFocus(); } /************************************************************************** ***************************************************************************/ void FAR PASCAL Ole1EndPlayInPlace(HWND hwndApp) { HWND hwndP; HWND hwndT; #if 0 // can't do this because SS != DS DPF("Ole1EndPlayInPlace()\n"); #endif if (!gfPlayingInPlace || !IsWindow(hwndApp)) return; /* Do this BEFORE hiding our window and BEFORE we do anything that */ /* might yield so client can't redraw with the wrong styles set. */ DinkWithWindowStyles(hwndApp, TRUE); gfPlayingInPlace = FALSE; #ifdef _WIN32 /* ** Tell mciole32.dll to remove its mouse HookProc. */ if ( fpRemoveHook ) { fHookInstalled = !(*fpRemoveHook)(); } #else /* !_WIN32 */ UnhookWindowsHookEx(hHookMouse); hHookMouse = NULL; #endif hwndP = GetParent(hwndApp); // // If we have the focus, then restore it to who used to have it. // ACK!! If the person who used to have it is GONE, we must give it away // to somebody (who choose our parent) because our child can't // keep the focus without making windows crash hard during the WM_DESTROY // (or maybe later whenever it feels like crashing at some random time). // See bug #8634. // if ((hwndT = GetFocus()) && GetWindowTask(hwndT) == MGetCurrentTask) { if (IsWindow(ghwndFocusSave)) SetFocus(ghwndFocusSave); else SetFocus(hwndP); } if (!hwndP || (gwOptions & OPT_BAR) || (gwOptions & OPT_BORDER) || (gwOptions & OPT_AUTORWD)) { // // hide the aplication window // SetWindowPos(hwndApp, NULL, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_HIDEWINDOW| SWP_NOACTIVATE); } else { // // hide our window, but don't redraw it will look // like we are still on the last frame. // // this is when we are playing in place, and there is // no playbar, and no rewind // // this is for Playing a AVI in a PowerPoint slide // without redraw problems. // SetWindowPos(hwndApp, NULL, 0, 0, 0, 0, SWP_NOREDRAW|SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE| SWP_HIDEWINDOW|SWP_NOACTIVATE); } SetParent(hwndApp, NULL); ClrWS(hwndApp, WS_CHILD); if (hwndP && gfParentWasEnabled) EnableWindow(hwndP, TRUE); // // set either the owner or the WS_CHILD bit so it will // not act up because we have the palette bit set and cause the // desktop to steal the palette. // #if 0 // The folowing was ifdef-ed away before I saw it, but note that it // wouldn't work on WIN32 anyway. SetWindowWord(hwndApp, GWW_HWNDPARENT, (WORD)GetDesktopWindow()); #else SetWS(hwndApp, WS_CHILD); #endif } #endif /* OLE1_HACK */