|
|
/*-----------------------------------------------------------------------------+
| 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 <windows.h>
#include <commdlg.h>
#include <mmsystem.h>
#include <port1632.h>
#include <shellapi.h>
#include <string.h>
#include <ole.h>
#include "mplayer.h"
#include "ole1.h"
//////////////////////////////////////////////////////////////////////////
//
// (c) Copyright Microsoft Corp. 1991 - All Rights Reserved
//
/////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#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 <gfErrorBox>. 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 */
|