/*--------------------------------------------------------------------------- | DOVERB.C | This file is used to be called server.c in the OLE1 versions of MPlayer. | This file has the ReallyDoVerb function which is called by the the | OLE DoVerb method. This file also has some functions to do the | InPlace activation in OLE1 apps. | | Modified for OLE2 By: Vij Rajarajan (VijR) +---------------------------------------------------------------------------*/ #define SERVERONLY #include #include #include #undef _MAX_PATH // ??? someone hacking? #undef _MAX_DIR // ??? someone hacking? #undef _MAX_FNAME // ??? someone hacking? #undef _MAX_EXT // ??? someone hacking? #include "ctrls.h" #include "mpole.h" #include "mplayer.h" #include "toolbar.h" #include "ole2ui.h" #define OLE_OK S_OK #define NOVERB 1000 extern HANDLE ghInst; extern HWND ghwndFocus; // Who had focus when we went inactive extern HWND ghwndFocusSave; // saved focus window extern HOOKPROC fpMouseHook; // Mouse hook proc address. extern UINT gwPlaybarHeight; //tell playbar how tall to make //itself so it covers the title DWORD gdwPosition; LONG glCurrentVerb = NOVERB; BOOL gfBrokenLink = FALSE; static BOOL gfMouseUpSeen = FALSE; // OK to close play in place? static BOOL gfKeyStateUpSeen = FALSE; // OK to close play in place? extern HMODULE hMciOle; /* ** These functions are exported from mciole32.dll. ** */ typedef BOOL (*LPINSTALLHOOK)( HWND, DWORD ); typedef BOOL (*LPREMOVEHOOK)( VOID ); LPINSTALLHOOK fpInstallHook; LPREMOVEHOOK fpRemoveHook; BOOL fHookInstalled = FALSE; char aszInstallHook[] = "InstallHook"; char aszRemoveHook[] = "RemoveHook"; /* Height of picture given to client to be pasted */ static UINT gwPastedHeight; static DWORD gwOldOptions; static DWORD gwOldHeight; TCHAR gachFile[_MAX_PATH]; static int gerr; static HWND ghwndClient = NULL; static RECT grcClient; BOOL gfOle1Client = FALSE; WNDPROC gfnMCIWndProc; HWND ghwndSubclass; BOOL SkipInPlaceEdit = FALSE; //TRUE if we are just reactivating BOOL gfSeenPBCloseMsg; //TRUE if the subclasses PlayBack WIndow Proc //has seen the WM_CLOSE message HWND ghwndFocusSave; //Who had the focus when we were activated.? #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 static SZCODE aszAppName[] = TEXT("MPlayer"); STATICFN BOOL FileExists(LPTSTR szFile, LPTSTR szFullName, int iLen); STATICFN BOOL NetParseFile(LPTSTR szFile, LPTSTR szDrive, LPTSTR szPath); HPALETTE FAR PASCAL CreateSystemPalette(void); void TransferTools(HWND hwndToolWindow); #ifdef DEBUG BOOL ShowAppWindow(int nCmdShow) { return ShowWindow(ghwndApp, nCmdShow); } #define SHOWAPPWINDOW(nCmdShow) ShowAppWindow(nCmdShow) #else #define SHOWAPPWINDOW(nCmdShow) ShowWindow(ghwndApp, nCmdShow) #endif /************************************************************************* * DirtyObject(BOOL fDocStgChangeOnly) - mark the "object" dirty, * ie has been changed. * * We set the gfDirty flag to TRUE and iff we are a embedded object tell * the client we have changed by sending a SendDocMsg(OLE_CHANGED). * fDocStgChangeOnly is TRUE if the change would affect the Embedding if there * is one but not appearence of the object i.e. the Metafile. * OLE_CHANGED message is sent only if fDocStgChangeOnly is FALSE; ***************************************************************************/ void DirtyObject(BOOL fDocStgChangeOnly) { // // NOTE we want to send OLE_CHANGED even if selection has changed // if (gfOle2IPEditing && ((gwOptions & OPT_BAR) != (gwOldOptions &OPT_BAR)) && !fDocStgChangeOnly) { RECT rc; BOOL fCanWindow = gwDeviceType & DTMCI_CANWINDOW; if (fCanWindow) { GetWindowRect(ghwndApp, (LPRECT)&rc); OffsetRect((LPRECT)&rc, -rc.left, -rc.top); /* rc contains the coordinates of the current app window. * If we have a playbar, we must allow space for it: */ if ((gwOptions & OPT_BAR) && !(gwOldOptions &OPT_BAR)) { /* Add bar */ Layout(); gwPlaybarHeight = TOOLBAR_HEIGHT; } else if(!(gwOptions & OPT_BAR) && (gwOldOptions &OPT_BAR)) { /* Remove bar */ Layout(); gwPlaybarHeight = 0; } } else { HBITMAP hbm; BITMAP bm; GetWindowRect(ghwndIPHatch, (LPRECT)&rc); if (gwOptions & OPT_BAR) gwPlaybarHeight = TOOLBAR_HEIGHT; else gwPlaybarHeight = 0; hbm = BitmapMCI(); GetObject(hbm,sizeof(bm),&bm); rc.bottom = rc.top + bm.bmHeight; rc.right = rc.left + bm.bmWidth; DeleteObject(hbm); MapWindowPoints(NULL,ghwndCntr,(LPPOINT)&rc, (UINT)2); DPF("IOleInPlaceSite::OnPosRectChange %d, %d, %d, %d\n", rc); if (!gfInPPViewer) IOleInPlaceSite_OnPosRectChange(docMain.lpIpData->lpSite, &rc); } } if (gwOptions != gwOldOptions) { gwOldOptions = gwOptions; if (gfEmbeddedObject && !fDocStgChangeOnly) SendDocMsg(&docMain, OLE_CHANGED); } if (gfDirty /* IsObjectDirty() */) return; fDocChanged=gfDirty = TRUE; gfValidCaption = FALSE; } /************************************************************************** IsObjectDirty() - Object is dirty if the dirty flag is set or the selection has changed since we last cleaned or the Metafile has changed ***************************************************************************/ BOOL FAR PASCAL IsObjectDirty(void) { // don't let anyone insert an empty mplayer into a document if (gwDeviceID == (UINT)0) return FALSE; return (gfDirty || glSelStart != (long)SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0L) || glSelEnd != (long)SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0L) /// I don't see this. This line results in the Update Object dialog coming /// up when it shouldn't. What has it got to do with metafiles? /// ??? || gdwPosition != (DWORD)SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0L) ); } /************************************************************************** CleanObject() - mark the "object" clean. ***************************************************************************/ void CleanObject(void) { if (!IsObjectDirty()) return; fDocChanged = gfDirty = FALSE; /* Reset selection globals so we can see if they changed */ glSelStart = (long)SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0L); glSelEnd = (long)SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0L); gdwPosition = (DWORD)SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0L); gfValidCaption = FALSE; } /************************************************************************** //## Just parses the play etc options in the embedded object //## description string ***************************************************************************/ SCODE FAR PASCAL ParseOptions(LPSTR pOpt) { #ifdef UNICODE DWORD OptLen; #endif PTSTR pT, pSave; int c; if (pOpt == NULL || *pOpt == 0) return OLE_OK; #ifdef UNICODE OptLen = ANSI_STRING_BYTE_COUNT( pOpt ); pT = AllocMem( OptLen * sizeof( TCHAR ) ); if (pT == NULL) return E_OUTOFMEMORY; MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pOpt, OptLen, pT, OptLen ); #else pT = pOpt; #endif pSave = pT; // wasn't NULL terminated before for (c = 0; *pT && c < 5; pT++) // change 1st 5 ','s to '\0' if (*pT == TEXT(',')) { c++; *pT = TEXT('\0'); } pT = pSave; // restore back to beginning pT += STRLEN(pT) + 1; // skip over Device Name gwOptions = ATOI(pT); gwCurScale = (gwOptions & OPT_SCALE); /* Can't set selection now because Media isn't initialized (UpdateMCI) */ pT += STRLEN(pT) + 1; glSelStart = ATOL(pT); // remember start of selection for later pT += STRLEN(pT) + 1; glSelEnd = ATOL(pT); // remember end of selection for later pT += STRLEN(pT) + 1; // remember position in a global so we can Seek later!! gdwPosition = ATOL(pT); /* Maybe there is the original height of the picture given to the client in */ /* here hidden in the Position string after a semicolon. */ /* Old versions of Mplayer didn't have any such thing. */ for (; *pT && *pT != TEXT(';'); pT++); if (*pT == TEXT(';')) { pT++; gwPastedHeight = (UINT)ATOL(pT); } else gwPastedHeight = 0; pT += STRLEN(pT) + 1; lstrcpy(gachCaption, pT); #ifdef UNICODE FreeMem( pSave, OptLen * sizeof( TCHAR ) ); #endif return OLE_OK; } /************************************************************************** //## Used to find the parent window of the window handle passed till the //## window handle is a top level handle ***************************************************************************/ HWND TopWindow(HWND hwnd) { HWND hwndP; while ((hwndP = GetParent(hwnd)) != NULL) hwnd = hwndP; return hwnd; } /************************************************************************** ***************************************************************************/ void FAR PASCAL SetEmbeddedObjectFlag(BOOL flag) { TCHAR ach[60]; TCHAR achText[_MAX_PATH]; gfEmbeddedObject = flag; srvrMain.fEmbedding = flag; if (!ghMenu) return; /*** First fix the Close/Update menu item ***/ LOADSTRING(flag ? IDS_UPDATE : IDS_CLOSE, ach); if (flag) wsprintf(achText, ach, (LPTSTR)FileName(szClientDoc)); else lstrcpy(achText, ach); /* Menu option will either say "Close" or "Update" (for embedded obj) */ /* and for update, will have the doc name in the text. */ ModifyMenu(ghMenu, IDM_CLOSE, MF_BYCOMMAND, IDM_CLOSE, achText); /*** Now fix the Exit menu item ***/ LOADSTRING(flag ? IDS_EXITRETURN : IDS_EXIT, ach); if (flag) wsprintf(achText, ach, (LPTSTR)FileName(szClientDoc)); else lstrcpy(achText, ach); /* Menu option will either say "Close" or "Update" (for embedded obj) */ /* and for update, will have the doc name in the text. */ ModifyMenu(ghMenu, IDM_EXIT, MF_BYCOMMAND, IDM_EXIT, achText); DrawMenuBar(ghwndApp); /* Can't hurt... */ } /************************************************************************** //## MORE STUFF FOR PLAY IN PLACE, should disappear in OLE2. //VIJR: Nope. Still needed for playing inplace in OLE1 clients. ***************************************************************************/ void PASCAL DinkWithWindowStyles(HWND hwnd, BOOL fRestore) { #define MAX_DINK 80 static LONG_PTR lStyleSave[MAX_DINK]; static HWND hwndSave[MAX_DINK]; static int nSave; int i; HWND hwndT; RECT rc, rcT; if (!TestWS(hwnd, WS_CHILD)) return; if (fRestore) for (i=0; i lszPath && !SLASH(*lszCur) && *lszCur != TEXT(':');) lszCur = CharPrev(lszPath, lszCur); if (lszCur == lszPath) return (LPTSTR)lszCur; else return (LPTSTR)(lszCur + 1); } /************************************************************************** //## This function should be handled by OLE2 //VIJR: Nope. Still needed for playing inplace in OLE1 clients. ***************************************************************************/ void FAR PASCAL PlayInPlace(HWND hwndApp, HWND hwndClient, LPRECT prc) { if (gfPlayingInPlace) // this is bad return; DPF("Using Child window for playback\n"); SetWS(hwndApp, WS_CHILD); SetParent(hwndApp, hwndClient); if(!(gfOle2IPEditing || gfOle2IPPlaying)) DinkWithWindowStyles(hwndApp, FALSE); if(!gfOle2IPEditing) gfPlayingInPlace = TRUE; if(gfOle2IPPlaying) MapWindowPoints(NULL,hwndClient,(LPPOINT)prc,2); /* For OLE2, now calls MoveWindow in DoInPlaceEdit (inplace.c). * This fixes 23429, window positioning in Word. */ if(!(gfOle2IPEditing || gfOle2IPPlaying)) { SetWindowPos(hwndApp, HWND_TOP, prc->left,prc->top, prc->right - prc->left, prc->bottom - prc->top, SWP_NOACTIVATE); } if(!gfOle2IPPlaying) // OLE1 Clients { /* ** 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; } // 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 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 0x0000 or 0xFFFF. ** Chandan tells me that on Daytona the HIWORD could be ** either of the above. */ if ( HIWORD(hwndClient) == 0x0000 || HIWORD(hwndClient) == 0xFFFF) { wow_thread_id = GetWindowThreadProcessId( hwndClient, NULL ); } fHookInstalled = (*fpInstallHook)( ghwndApp, wow_thread_id ); } } ghwndFocusSave = GetFocus(); } //This function is new for OLE2. It sets the container window as //our window's (actually the hatch window's) parent and positions the window void FAR PASCAL EditInPlace(HWND hwndApp, HWND hwndClient, LPRECT prc) { RECT rc; rc = *prc; SetWS(hwndApp, WS_CHILD); SetParent(hwndApp, hwndClient); ScreenToClient(hwndClient,(LPPOINT)&rc); ScreenToClient(hwndClient,(LPPOINT)&rc+1); if(gwDeviceType & DTMCI_CANWINDOW) { /* Sometimes the position (though not the size) of this rectangle * gets messed up (most reliably in PowerPoint 7). * I can't figure out why this is happening (see the nightmarish * code in ReallyDoVerb() to get a flavour of what happens). * But it turns out that this call is unnecessary in any case, * since the window has already been positioned properly in * IPObjSetObjectRects(). * I suspect there's a lot of surplus window-positioning code, * but now isn't the time to start making major changes. * This is the minimal change that makes things work. */ //This fixes NTRaid bug #236641 in Excel. AND bug #247393 in Word //Sometimes there is confusion between who the parent is. mplay32 sets the document //window as the parent and the rectangle sent in SetObjectRects might not be with respect to //the document window (this might happen when the document window is not in the maximized state). //In this function we know the parent and the rectangle in that parent. Setting //the position here places our OLE object as the client requires. This change is even safe in //terms of introducing regressions. SetWindowPos(hwndApp, HWND_TOP, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_FRAMECHANGED); } else if(gwDeviceID) SetWindowPos(hwndApp, HWND_TOP, rc.left,rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW); else SetWindowPos(hwndApp, HWND_TOP, rc.left,rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_HIDEWINDOW); ghwndFocusSave = GetFocus(); //Set the focus for the parent. if((gwDeviceID == (UINT)0) && IsWindow(hwndClient)) { SetFocus(hwndClient); } } /************************************************************************** //## This is called to end PlayInPlace and make sure that the window goes //## away and the also to manage the palette stuff (May go away in OLE2) //## This function should be handled by OLE2 ***************************************************************************/ void FAR PASCAL EndPlayInPlace(HWND hwndApp) { HWND hwndP; HWND hwndT; 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. */ if (!(gfOle2IPEditing || gfOle2IPPlaying)) DinkWithWindowStyles(hwndApp, TRUE); gfPlayingInPlace = FALSE; /* ** Tell mciole32.dll to remove its mouse HookProc. */ if ( fHookInstalled && fpRemoveHook ) { fHookInstalled = !(*fpRemoveHook)(); } if (gfOle2IPPlaying) hwndP = ghwndCntr; else 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()) != NULL) && 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. // SetWS(hwndApp, WS_CHILD); } //If we were InPlace editing restore the windows state. void FAR PASCAL EndEditInPlace(HWND hwndApp) { HWND hwndP; HWND hwndT; if (!gfOle2IPEditing || !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); gfOle2IPEditing = FALSE; if (gfOle2IPPlaying) hwndP = ghwndCntr; else 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()) != NULL) && GetWindowTask(hwndT) == MGetCurrentTask) { if (IsWindow(ghwndFocusSave)) SetFocus(ghwndFocusSave); else if (IsWindow(hwndP)) SetFocus(hwndP); } if (!IsWindow(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 (IsWindow(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. // SetWS(hwndApp, WS_CHILD); } /* Tell the user that something's amiss with a network call. * For network-specific errors, call WNetGetLastError, * otherwise see if it's a system error. */ void DisplayNetError(DWORD Error) { DWORD ErrorCode; // address of error code TCHAR szDescription[512]; // address of string describing error TCHAR szProviderName[64]; // address of buffer for network provider name if (Error == ERROR_EXTENDED_ERROR) { if (WNetGetLastError(&ErrorCode, szDescription, CHAR_COUNT(szDescription), szProviderName, CHAR_COUNT(szProviderName)) == NO_ERROR) { Error1(ghwndApp, IDS_NETWORKERROR, szDescription); return; } } else { if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, Error, 0, szDescription, CHAR_COUNT(szDescription), NULL) > 0) { Error1(ghwndApp, IDS_NETWORKERROR, szDescription); return; } } /* If all else fails: */ Error(ghwndApp, IDS_UNKNOWNNETWORKERROR); } /************************************************************************** convert a file name to a fully qualifed path name, if the file exists on a net drive the UNC name is returned. ***************************************************************************/ STATICFN BOOL NetParseFile(LPTSTR szFile, LPTSTR szDrive, LPTSTR szPath) { BYTE UNBuffer[(MAX_PATH * sizeof(TCHAR)) + sizeof(UNIVERSAL_NAME_INFO)]; DWORD UNBufferSize = sizeof UNBuffer; DWORD_PTR Error; LPTSTR pUniversalName; // // Turn into a fully qualified path name // if (!FileExists(szFile, szPath, MAX_PATH)) return FALSE; // // if the file is not drive based (probably UNC) // if (szPath[1] != TEXT(':')) return TRUE; Error = WNetGetUniversalName(szDrive, UNIVERSAL_NAME_INFO_LEVEL, UNBuffer, &UNBufferSize); if (Error == ERROR_NOT_SUPPORTED) { /* This means that the network provider doesn't support * UNC conventions. Give WNetGetConnection a try. * Note: dynalink.h assumes that WNetGetUniversalName * will always be called before WNetGetConnection. */ UNBufferSize = CHAR_COUNT(UNBuffer); Error = WNetGetConnection(szDrive, (LPTSTR)UNBuffer, &UNBufferSize); if (Error == NO_ERROR) { /* What does the following mean? It was in the original code. */ if (!SLASH(UNBuffer[0]) || !SLASH(UNBuffer[1])) return TRUE; lstrcat((LPTSTR)UNBuffer, szPath+2); lstrcpy(szPath, (LPTSTR)UNBuffer); return TRUE; } } if (Error != NO_ERROR) { DisplayNetError((DWORD)Error); return FALSE; } pUniversalName = ((LPUNIVERSAL_NAME_INFO)UNBuffer)->lpUniversalName; lstrcat(pUniversalName, szPath+2); lstrcpy(szPath, pUniversalName); return TRUE; } /************************************************************************** Get the data that represents the currently open MCI file/device. as a link. MPlayer links look like this: MPLAYER|! [selection] //## This is the opposite of parse options and sets the data string to be //## embedded in the OLE object. Note we store the data in an ANSI string, regardless of whether we're compiled as a Unicode app, for Daytona/Chicago/OLE1/OLE2 compatibility. ***************************************************************************/ HANDLE GetLink( VOID ) { TCHAR szFileName[MAX_PATH]; TCHAR szFullName[MAX_PATH]; TCHAR szDevice[40]; TCHAR szDrive[4]; HANDLE h; LPSTR p; /* NOT LPTSTR */ int len; int lenAppName; int lenFullName; lstrcpy(szFileName,gachFileDevice); lstrcpy(szFullName,gachFileDevice); // // convert the filename into a UNC file name, if it exists on the net // if (gwDeviceType & DTMCI_FILEDEV) { if (szFileName[1] == TEXT(':')) { /* This is a file name with a drive letter. * Find out if it's redirected: */ szDrive[0] = szFileName[0]; szDrive[1] = szFileName[1]; szDrive[2] = TEXT('\\'); // GetDriveType requires the root. szDrive[3] = TEXT('\0'); // Null-terminate. if ((szDrive[1] == TEXT(':')) && GetDriveType(szDrive) == DRIVE_REMOTE) { szDrive[2] = TEXT('\0'); // Zap backslash. if (!NetParseFile(szFileName, szDrive, szFullName)) return NULL; } } } else if (gwDeviceType & DTMCI_SIMPLEDEV) { szFullName[0] = 0; } if (gwCurDevice == 0) GetDeviceNameMCI(szDevice, BYTE_COUNT(szDevice)); else lstrcpy(szDevice, garMciDevices[gwCurDevice].szDevice); #ifdef UNICODE // length of the string in bytes != length of the string in characters lenAppName = WideCharToMultiByte(CP_ACP, 0, aszAppName, -1, NULL, 0, NULL, NULL) - 1; lenFullName = WideCharToMultiByte(CP_ACP, 0, szFullName, -1, NULL, 0, NULL, NULL) - 1; #else lenAppName = STRLEN(aszAppName); lenFullName = STRLEN(szFullName); #endif /* How much data will we be writing? */ #ifdef UNICODE // length of the string in bytes != length of the string in characters len = 9 + // all the delimeters lenAppName + lenFullName + WideCharToMultiByte(CP_ACP, 0, szDevice, -1, NULL, 0, NULL, NULL)-1 + 5 + 10 + 10 + 10 + // max length of int and long strings WideCharToMultiByte(CP_ACP, 0, gachCaption, -1, NULL, 0, NULL, NULL)-1; #else len = 9 + // all the delimeters lenAppName + lenFullName + STRLEN(szDevice) + 5 + 10 + 10 + 10 + // max length of int and long strings STRLEN(gachCaption); #endif h = GlobalAlloc(GMEM_DDESHARE|GMEM_ZEROINIT, len * sizeof(CHAR)); if (!h) return NULL; p = GLOBALLOCK(h); /* This string must have two terminating null characters. * The GlobalAlloc GMEM_ZEROINIT flag should ensure this. */ #ifdef UNICODE wsprintfA(p, "%ws%c%ws%c%ws%c%d%c%d%c%d%c%d%c%d%c%ws", #else wsprintfA(p, "%s%c%s%c%s%c%d%c%d%c%d%c%d%c%d%c%s", #endif aszAppName, '*', // placeholder szFullName, '*', // placeholder szDevice, ',', (gwOptions & ~OPT_SCALE) | gwCurScale, ',', (long)SendMessage(ghwndTrackbar, TBM_GETSELSTART, 0, 0L), ',', (long)SendMessage(ghwndTrackbar, TBM_GETSELEND, 0, 0L), ',', (long)SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0L), ';', // new parameter snuck in since initial version // Height of picture we're giving the client - w/o caption grcSize.bottom - grcSize.top, ',', gachCaption); /* Replace *'s with NULL characters (wsprintf doesn't accept * 0 as a replacement parameter for %c): */ p[lenAppName] = '\0'; p[lenAppName + 1 + lenFullName] = '\0'; DPF("Native data %hs has been created\n", p); GLOBALUNLOCK(h); return h; } /**************************************************************************** AttachDir - Take the path part of szPath, append the filename part of szName, and return it as szResult. ****************************************************************************/ STATICFN void AttachDir(LPTSTR szResult, LPTSTR szPath, LPTSTR szName) { lstrcpy(szResult, szPath); lstrcpy(FileName(szResult), FileName(szName)); } /**************************************************************************** DOS share has a bug. If the file we're testing for existence is open already by someone else, we have to give it the same flag for SHARE as the other person is using. So we have to try both on and off. Only one of these will return TRUE but if one of them does, the file exists. Also we have to try with SHARE first, because the test without share might give a system modal error box!!! //## Check to see if DOS 7 has this bug or is it fixed Parameter iLen is the number of characters in the szFullName buffer ****************************************************************************/ STATICFN BOOL FileExists(LPTSTR szFile, LPTSTR szFullName, int iLen) { DWORD rc; LPTSTR pFilePart; rc = SearchPath(NULL, /* Default path search order */ szFile, NULL, /* szFile includes extension */ (DWORD)iLen, szFullName, &pFilePart); if(rc > (DWORD)iLen) { DPF0("Buffer passed to FileExists is of insufficient length\n"); } return (BOOL)rc; } /**************************************************************************** FindRealFileName - If szFile isn't valid, try searching client directory for it, or anywhere on the path, or bringing up a locate dlg. Set szFile to the valid path name. //## This function is used to repair broken links Parameter iLen is the number of characters in the szFile buffer ****************************************************************************/ BOOL FindRealFileName(LPTSTR szFile, int iLen) { TCHAR achFile[_MAX_PATH + 1]; /* file or device name buffer */ /* This isn't a file device, so don't do anything */ if (!szFile || *szFile == 0) return TRUE; /* The file name we've been given is valid, so do nothing. */ //!!! what about share if (FileExists(szFile, achFile, iLen)) { lstrcpy(szFile, achFile); return TRUE; } DPF("FindRealFileName: Can't find file '%"DTS"'\n", szFile); #if 0 /* This could never have worked: */ /* Look for the file in the directory of the client doc */ AttachDir(achFile, gachDocTitle, szFile); DPF("FindRealFileName: ...Looking for '%"DTS"'\n", (LPTSTR)achFile); if (FileExists(achFile, szFile, iLen)) return TRUE; #endif DPF("FindRealFileName: ...Looking on the $PATH\n"); /* Look for the file anywhere */ lstrcpy(achFile, FileName(szFile)); if (FileExists(achFile, szFile, iLen)) return TRUE; return FALSE; } /************************************************************************** * SubClassedMCIWndProc: * This the WndProc function used to sub-class the Play Back window. * This function is used to trap the drag-drops and also * to route the WM_CLOSE to the IDM_CLOSE of Mplayer. **************************************************************************/ LONG_PTR FAR PASCAL SubClassedMCIWndProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { static BOOL fDragCapture = FALSE; static RECT rcWin; POINT pt; LONG_PTR lRc; switch(wMsg) { case WM_LBUTTONDOWN: // break; // Disable drag from MPlayer! It's broken. if (!gfOle2IPEditing) { fDragCapture = TRUE; SetCapture(hwnd); GetClientRect(hwnd, (LPRECT)&rcWin); MapWindowPoints(hwnd, NULL, (LPPOINT)&rcWin, 2); } break; case WM_LBUTTONUP: if (!fDragCapture) break; fDragCapture = FALSE; ReleaseCapture(); break; case WM_MOUSEMOVE: if (!fDragCapture) break; LONG2POINT(lParam, pt); MapWindowPoints(hwnd, NULL, &pt, 1); if (!PtInRect((LPRECT)&rcWin, pt)) { ReleaseCapture(); DoDrag(); fDragCapture = FALSE; } SetCursor(LoadCursor(ghInst,MAKEINTRESOURCE(IDC_DRAG))); break; case WM_CLOSE: if (gfSeenPBCloseMsg || gfOle2IPEditing || gfOle2IPPlaying) { lRc = CallWindowProc(gfnMCIWndProc, hwnd, wMsg, wParam, lParam); } else { gfSeenPBCloseMsg = TRUE; PostMessage(ghwndApp,WM_COMMAND,IDM_CLOSE,0L); lRc = 0L; } CleanUpDrag(); return lRc; case WM_DESTROY: ghwndSubclass = NULL; CleanUpDrag(); break; case WM_ACTIVATE: /* Get the app's main window somewhere it can be seen * if the MCI window gets activated: */ if (((WORD)wParam != 0) && !IsIconic(ghwndApp)) { SetWindowPos(ghwndApp, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } break; } return CallWindowProc(gfnMCIWndProc, hwnd, wMsg, wParam, lParam); } /************************************************************************** * SubClassMCIWindow: * This function sub-classes the Play Back window by hooking in * SubClassedMCIWndProc function. **************************************************************************/ void SubClassMCIWindow(void) { HWND hwndMCI; hwndMCI = GetWindowMCI(); if(!IsWindow(hwndMCI)) return; if (gfnMCIWndProc != NULL && IsWindow(ghwndSubclass)) { SetWindowLongPtr(ghwndSubclass, GWLP_WNDPROC, (LONG_PTR)gfnMCIWndProc); } gfnMCIWndProc = (WNDPROC)GetWindowLongPtr(hwndMCI, GWLP_WNDPROC); if (hwndMCI) SetWindowLongPtr(hwndMCI, GWLP_WNDPROC, (LONG_PTR)SubClassedMCIWndProc); ghwndSubclass = hwndMCI; gfSeenPBCloseMsg = FALSE; #ifdef CHICAGO_PRODUCT SendMessage(hwndMCI, WM_SETICON, FALSE, (LPARAM)GetIconForCurrentDevice(GI_SMALL, IDI_DDEFAULT)); SetWindowText(hwndMCI, gachCaption); #endif } INT_PTR FAR PASCAL FixLinkDialog(LPTSTR szFile, LPTSTR szDevice, int iLen); /* ANSI-to-Unicode version of lstrcpyn: * * Zero terminates the buffer in case it isn't long enough, * then maps as many characters as will fit into the Unicode buffer. * */ #define LSTRCPYNA2W(strW, strA, buflen) \ strW[buflen-1] = L'\0', \ MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, \ (strA), min( strlen( strA )+1, (buflen)-1 ), \ (strW), ((buflen)-1) ) /************************************************************************** * ItemSetData(LPBYTE p): This function is left over from OLE1 days, but is * very important because the embedded data is still the same. This function * parses the embedded data and opens the appropriate device/file and sets * everything in motion. "p" is the pointer memory block having the embedded * data. * Note we store the data in an ANSI string, regardless of whether we're * compiled as a Unicode app, for Daytona/Chicago/OLE1/OLE2 compatibility. **************************************************************************/ SCODE ItemSetData(LPBYTE p) { LPSTR pSave, pT; LPSTR szFile, szDevice; CHAR ach[40]; TCHAR achFile[_MAX_PATH]; TCHAR achCaption[_MAX_PATH]; LPTSTR pDevice; SCODE scode = E_FAIL; if (p && *p != 0) { szFile = p + strlen(p) + 1; // pick off the Filename p = szFile + strlen(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'; /* It is OK for szFile and szDevice to be empty, since we may have * a Media Clip object with no device or file selected */ DPF("%hs|%hs!%hs\n", p, szFile, szDevice); CloseMCI(TRUE); // nuke old gachCaption scode = ParseOptions(pSave); // this will set new gachCaption if (scode != S_OK) return scode; // 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. #ifdef UNICODE LSTRCPYNA2W(achFile, szFile, CHAR_COUNT(achFile)); #else lstrcpyn(achFile, szFile, CHAR_COUNT(achFile)); #endif // Check for file existence. if the filename we were given is bad, // try and find it somewhere on the disk #ifdef UNICODE pDevice = AllocateUnicodeString(szDevice); if (!pDevice) return E_OUTOFMEMORY; #else pDevice = szDevice; #endif if (FindRealFileName(achFile, CHAR_COUNT(achFile))) { lstrcpy(achCaption, gachCaption); //Save caption. if (OpenMciDevice(achFile, pDevice)) { /* Set the selection to what we parsed in ParseOptions. */ SendMessage(ghwndTrackbar, TBM_SETSELSTART, 0, glSelStart); SendMessage(ghwndTrackbar, TBM_SETSELEND, 0, glSelEnd); } lstrcpy(gachCaption, achCaption); //Restore Caption } else if (FixLinkDialog(achFile, pDevice, sizeof(achFile)) ) { if (OpenMciDevice(achFile, pDevice)) { /* Set the selection to what we parsed in ParseOptions. */ SendMessage(ghwndTrackbar, TBM_SETSELSTART, 0, glSelStart); SendMessage(ghwndTrackbar, TBM_SETSELEND, 0, glSelEnd); gfBrokenLink = TRUE; } } else scode = E_FAIL; } #ifdef UNICODE FreeUnicodeString(pDevice); #endif return scode; } /************************************************************************** * UpdateObject() - handle the update of the object * If the object has changed in content or appearance a message is * sent to the container. ***************************************************************************/ void UpdateObject(void) { LONG lPos; if((gfOle2IPPlaying || gfPlayingInPlace) && !fDocChanged) return; if (IsWindow(ghwndTrackbar)) lPos = (LONG)SendMessage(ghwndTrackbar, TBM_GETPOS, 0, 0L); else lPos = -1; if (gfEmbeddedObject && (fDocChanged || ((lPos >= 0) && (lPos != (LONG)gdwPosition) && (gwDeviceType & DTMCI_CANWINDOW)))) { // // Some clients (e.g. Excel 3.00 and PowerPoint 1.0) don't // handle saved notifications; they expect to get an // OLE_CLOSED message. // // We will send an OLE_CLOSED message right before we // revoke the DOC iff gfDirty == -1 (see FileNew()). // if ((lPos >= 0) && (lPos != (LONG)gdwPosition) && (gwDeviceType & DTMCI_CANWINDOW)) { gdwPosition = (DWORD)lPos; SendDocMsg((LPDOC)&docMain,OLE_CHANGED); } if (fDocChanged) SendDocMsg(&docMain, OLE_SAVEOBJ); } } /************************************************************************** * int FAR PASCAL ReallyDoVerb: This is the main function in the server stuff. * This function used to implement the PlayInPlace in OLE1. Most of the code * has not been changed and has been used to munge the MPlayer for EditInPlace * in OLE2. For OLE2 this function calls DoInPlaceEdit to get the containers * hwnd and Object rectangle. For OLE1 clients the rectangle is still got * from the OleQueryObjPos funtion in mciole.dll. A new twist in the PlayVerb * is that if we are just hidden in a deactivated state we just reappear * and play instead of PlayingInPlace without the toolbars etc. This function * is also called when reactivating, deactivating etc. The BOOL SkipInPlaceEdit * is used to avoid redoing all the stuff if we are just reactivating. ***************************************************************************/ int FAR PASCAL ReallyDoVerb ( LPDOC lpobj, LONG verb, LPMSG lpmsg, LPOLECLIENTSITE lpActiveSite, BOOL fShow, BOOL fActivate) { BOOL fWindowWasVisible = IsWindowVisible(ghwndApp); int dx,dy; HWND hwndClient; HWND hwndT; RECT rcSave; RECT rcClient; RECT rc; LONG err; SCODE sc; HPALETTE hpal; HDC hdc; INT xTextExt; int yOrig, yNow, xOrig, ytitleNow, xtitleOrig, xNow; int xIndent = 0; // Avoid warning C4701: local variable 'xIndent' // may be used without having been initialized int wWinNow; HWND hwndMCI; int Result = S_OK; DPFI("VERB = %d\n", verb); /* MSProject assumes that our primary verb is Edit; in fact it's Play. * So when we're called with the default verb, make sure we've loaded * something from storage and, if not, do the Edit thing. * * Nope, that doesn't work, because if you insert an object, deactivate * it and then play it, PSLoad hasn't been called. A better bet is * to check whether we have a current device. */ if (gfRunWithEmbeddingFlag && gwDeviceType == 0) { if (verb == OLEIVERB_PRIMARY) { DPF("Primary Verb called without current device -- changing verb to Edit...\n"); verb = verbEdit; } } /* If a Media Clip is currently open, the user can give the focus back * to the container and issue another verb or double-click the object. * If this happens, set the focus back to the open object. * * We don't need to worry about resetting fObjectOpen, since the server * shuts down when the user exits and returns to the container. */ if (gfOle2Open) { SetFocus(ghwndApp); return S_OK; } // This is the first verb we are seeing. So the container must // have the focus. Save it so that we can return it later. if (glCurrentVerb == NOVERB) ghwndFocusSave = GetFocus(); if (verb == OLEIVERB_PRIMARY && !gfOle2IPEditing && (glCurrentVerb != verbEdit)) { EnableMenuItem((HMENU)GetMenu(ghwndApp), IDM_CLOSE, MF_GRAYED); } glCurrentVerb = verb; // // dont even try to nest things. // if (gfPlayingInPlace && verb != OLEIVERB_HIDE) return OLE_OK; if (gfBrokenLink) { PostMessage(ghwndApp, WM_SEND_OLE_CHANGE, 0, 0L); gfBrokenLink = FALSE; } //We are just reactivating. Don't do through all the steps again. if (gfOle2IPEditing) SkipInPlaceEdit = TRUE; // Make sure the timer's doing the right thing: gfAppActive = ( verb != OLEIVERB_HIDE ); // NTVDM can get into a spin if we have too meany TIMER messages, // so make sure we don't have any if there's no device. if (gwDeviceID) EnableTimer( gfAppActive ); else EnableTimer( FALSE ); if (verb == OLEIVERB_PRIMARY) { gfOle1Client = FALSE; //We are already up but deactivated. Just come up and play. if (gfOle2IPEditing) { if (!(gwDeviceType & DTMCI_CANWINDOW)) { Result = ReallyDoVerb(lpobj, verbEdit, lpmsg, lpActiveSite, fShow, fActivate); PostMessage(ghwndApp, WM_COMMAND, ID_PLAYSEL, 0); // play selection } else { ClrWS(ghwndApp, WS_THICKFRAME|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_BORDER); err = GetScode(DoInPlaceEdit(lpobj, lpmsg, lpActiveSite, verbEdit, &hwndClient, &rcClient)); if (err) { SHOWAPPWINDOW(SW_HIDE); PostMessage(ghwndApp,WM_CLOSE,0,0); return((int)err); } gfInPlaceResize = TRUE; rcClient = gInPlacePosRect; MapWindowPoints(NULL,ghwndCntr,(LPPOINT)&rcClient,2); DPF("IOleInPlaceSite::OnPosRectChange %d, %d, %d, %d\n", rcClient); if (!gfInPPViewer) IOleInPlaceSite_OnPosRectChange(docMain.lpIpData->lpSite, &rcClient); toolbarSetFocus(ghwndToolbar, BTN_PLAY); SetFocus(ghwndToolbar); PostMessage(ghwndApp, WM_COMMAND, ID_PLAYSEL, 0); // play selection } } else { if(gwDeviceID == (UINT)0) //Play without a device !?!!! { PostMessage(ghwndApp, WM_CLOSE, 0, 0L); sc = E_FAIL; return (int)sc; } // 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()) != NULL) && ((hwndT = GetActiveWindow()) != NULL)) { 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 = GetScode(DoInPlaceEdit(lpobj, lpmsg, lpActiveSite, verb, &hwndClient, &rcClient)); if (err != S_OK) { err = OleQueryObjPos(lpobj, &hwndClient, &rcClient, NULL); if (err == S_OK) { gfOle1Client = TRUE; ghwndCntr = hwndClient; } } else { if (gwOptions & OPT_TITLE) gwOptions |= OPT_BAR; else gwOptions &= ~OPT_BAR; } } /* 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 == S_OK) && (!gfOle1Client || (gwOptions & OPT_PLAY)) /* Ignore Play in client doc for OLE2 clients */ && (gfOle2IPPlaying || (IsWindow(hwndClient) && IsWindowVisible(hwndClient) && !fWindowWasVisible))) { 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 picture, 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) { SIZE Size; hdc = GetDC(NULL); if (ghfontMap) SelectObject(hdc, ghfontMap); GetTextExtentPoint32(hdc, gachCaption, STRLEN(gachCaption), &Size); xTextExt = Size.cx; ReleaseDC(NULL, hdc); 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) { // THIS CODE IS USED TO AVOID SLOW PLAYBACK // 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) { 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) { 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 // presentation data was dithered, or the user asked us to // always use the object palette, then ignore any client // palette. // #ifdef DEBUG if (GetProfileInt(TEXT("options"), TEXT("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 its exact palette. // hdc = GetDC(ghwndCntr); hpal = SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE); SelectPalette(hdc, hpal, FALSE); ReleaseDC(ghwndCntr, hdc); if (hpal == NULL || hpal==GetStockObject(DEFAULT_PALETTE)) { /* Assume client realized the proper palette for us */ 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) { SHOWAPPWINDOW(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, (DWORD)GetWS(ghwndApp), FALSE); if (!(gwDeviceType & DTMCI_CANWINDOW)) { rcSave.left += 2*GetSystemMetrics(SM_CXBORDER); rcSave.right -= 2*GetSystemMetrics(SM_CXBORDER); } PlayInPlace(ghwndApp, hwndClient, &rcSave); if (!gfOle2IPEditing) gfCloseAfterPlaying = TRUE; fShow = FALSE; fActivate = FALSE; /* become visible */ SHOWAPPWINDOW(SW_SHOW); /* 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); /* 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. */ DPF("DoVerb: Not is play in place stuff "); 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; // DIE when you are done playing 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 == verbEdit || verb == verbOpen || verb == OLEIVERB_OPEN || verb == OLEIVERB_SHOW || verb == OLEIVERB_INPLACEACTIVATE || verb == OLEIVERB_UIACTIVATE) { gfOle1Client = FALSE; #ifdef DEBUG switch(verb) { case verbEdit: DPFI("VERBEDIT\r\n");break; case OLEIVERB_SHOW: DPFI("OLEIVERB_SHOW\r\n");break; case OLEIVERB_INPLACEACTIVATE: DPFI("OLEIVERB_IPACTIVATE\r\n");break; case OLEIVERB_UIACTIVATE: DPFI("OLEIVERB_UIACTIVATE\r\n");break; } #endif // If we are already playing inside an Icon, then restore.. hwndMCI = GetWindowMCI(); if (IsWindow(hwndMCI) && IsIconic(hwndMCI)) SendMessage(hwndMCI, WM_SYSCOMMAND, SC_RESTORE, 0L); // 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_CANTPLAY); 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 // FORCES UPDATE gwStatus = (UINT)(-1); if (((hpal = PaletteMCI()) != NULL) && ((hwndT = GetActiveWindow()) != NULL)) { hdc = GetDC(hwndT); hpal = SelectPalette(hdc, hpal, FALSE); SelectPalette(hdc, hpal, FALSE); ReleaseDC(hwndT, hdc); } if (verb == verbOpen || verb == OLEIVERB_OPEN) { DoInPlaceDeactivate(lpobj); gfOle2IPEditing = FALSE; gfPlayOnly = FALSE; SetWindowPos(ghwndApp, NULL, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOSIZE|SWP_NOMOVE|SWP_HIDEWINDOW|SWP_NOACTIVATE); SetParent(ghwndApp, NULL); PutWS(ghwndApp, WS_THICKFRAME | WS_OVERLAPPED | WS_CAPTION | WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX); TransferTools(ghwndApp); if (lpobj->lpoleclient) /* This is NULL if it's the first verb issued to a link */ IOleClientSite_OnShowWindow(lpobj->lpoleclient, TRUE); SendMessage(ghwndTrackbar, TBM_SHOWTICS, TRUE, FALSE); gfOle2Open = TRUE; /* This global is referenced in SizeMPlayer */ SizeMPlayer(); SHOWAPPWINDOW(SW_SHOW); } else if((err = GetScode(DoInPlaceEdit(lpobj, lpmsg, lpActiveSite, verb, &hwndClient, &rcClient))) !=S_OK) { err = OleQueryObjPos(lpobj, &hwndClient, &rcClient, NULL); if (err == S_OK) { gfOle1Client = TRUE; } gfOle2IPEditing = FALSE; if (gfPlayOnly) { gfPlayOnly = FALSE; SizeMPlayer(); } } else { if (gwOptions & OPT_TITLE) gwOptions |= OPT_BAR; else gwOptions &= ~OPT_BAR; } if (gfOle2IPEditing && SkipInPlaceEdit) { gfInPlaceResize = TRUE; if(!(gwDeviceType & DTMCI_CANWINDOW) && (gwOptions & OPT_BAR)) { yNow = rcClient.bottom - rcClient.top; if (gwOldHeight) { ytitleNow = (int)((long)yNow * gwPlaybarHeight/gwOldHeight); gwPlaybarHeight = max(ytitleNow, TOOLBAR_HEIGHT); gwOldHeight = yNow; rcClient.top = rcClient.bottom - gwPlaybarHeight; } else { gwPlaybarHeight = TOOLBAR_HEIGHT; rcClient.top = rcClient.bottom - gwPlaybarHeight; ytitleNow = rcClient.bottom - rcClient.top; gwOldHeight = yNow; } } if(!(gwDeviceType & DTMCI_CANWINDOW) && !(gwOptions & OPT_BAR)) rcClient.bottom = rcClient.top = rcClient.left = rcClient.right = 0; EditInPlace(ghwndApp, hwndClient, &rcClient); Layout(); } else if (gfOle2IPEditing && gwDeviceID == (UINT)0 && IsWindow(ghwndFrame)) EditInPlace(ghwndApp, hwndClient, &rcClient); if(gfOle2IPEditing && gwDeviceID != (UINT)0 && !SkipInPlaceEdit) { gwOldOptions = gwOptions; 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) { SIZE Size; hdc = GetDC(NULL); if (ghfontMap) SelectObject(hdc, ghfontMap); GetTextExtentPoint32(hdc, gachCaption, STRLEN(gachCaption), &Size); xTextExt = Size.cx; ReleaseDC(NULL, hdc); if (gwPastedHeight && !(gwDeviceType & DTMCI_CANWINDOW) ) 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; if (gwDeviceType & DTMCI_CANWINDOW) ytitleNow = TITLE_HEIGHT; else { ytitleNow = (int)((long)yNow - ((long)yOrig * yNow) / (yOrig + TITLE_HEIGHT)); gwOldHeight = yNow; } /* 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 0 /* No, don't, because this screws up PowerPoint, which is usually * scaled. If anything, it would be better to hide the control bar * under these circumstances. */ 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. } #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(ghwndCntr); hpal = SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE); SelectPalette(hdc, hpal, FALSE); ReleaseDC(ghwndCntr, hdc); if (hpal == NULL || hpal==GetStockObject(DEFAULT_PALETTE)) { /* Assume client realized the proper palette for us */ 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"); 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; if(!(gwDeviceType & DTMCI_CANWINDOW) && (gwOptions & OPT_BAR)) rcSave.top = rcSave.bottom - gwPlaybarHeight; AdjustWindowRect(&rcSave, (DWORD)GetWS(ghwndApp), FALSE); if(!(gwDeviceType & DTMCI_CANWINDOW) && !(gwOptions & OPT_BAR)) rcSave.bottom = rcSave.top = rcSave.left = rcSave.right = 0; EditInPlace(ghwndApp, hwndClient, &rcSave); /* become visible */ SHOWAPPWINDOW(SW_SHOW); /* Remember to play the video in the rcClient area of rcSave */ if ((gwDeviceType & DTMCI_CANWINDOW) && (gwOptions & OPT_TITLE) && xIndent != 0) SetDestRectMCI(&rcClient); } } else if (verb == verbOpen || verb == OLEIVERB_OPEN) { DPFI("\n*verbopen"); DoInPlaceDeactivate(lpobj); if (gwDeviceID) return ReallyDoVerb(lpobj, verbEdit, lpmsg, lpActiveSite, fShow, fActivate); } else if (verb == OLEIVERB_HIDE) { DPFI("\n*^*^* OLEVERB_HIDE *^*^"); DoInPlaceDeactivate(lpobj); return S_OK; } else if (verb > 0) { Result = ReallyDoVerb(lpobj, OLEIVERB_PRIMARY, lpmsg, lpActiveSite, fShow, fActivate); if (Result = S_OK) Result = OLEOBJ_S_INVALIDVERB; } else return E_NOTIMPL; if (fShow ) { if (ghwndMCI || !gfOle2IPEditing) SHOWAPPWINDOW(SW_SHOW); /* MUST BE A POST or palette realization will not happen properly */ if (IsIconic(ghwndApp)) SendMessage(ghwndApp, WM_SYSCOMMAND, SC_RESTORE, 0L); } if (fActivate ) { BringWindowToTop (ghwndApp); // let WM_ACTIVATE put client SetActiveWindow (ghwndApp); // underneath us } return Result; }