DR Developer's Guide
DR Interfaces | DR Methods | DR Types and Misc API

IMoaDrMovieContext



Interface ID: IID_IMoaDrMovieContext
Pointer type: PIMoaDrMovieContext
Inheritance: IMoaUnknown
Header file: driservc.h
Description
The IMoaDrMovieContext interface lets you set up the player's context so you can access the current movie. This interface is especially important in Windows if you create your own windows and receive messages directly from Windows. If the operating system calls your Xtra directly and you call the player, the player does not know what context you are executing in.

You do not need this interface if you do not have your own windows or use threads, or if you are coding for the Macintosh (the threading and windowing model of the Macintosh is simpler than that of Windows). However, this interface is available on both platforms--calling it unnecessarily is harmless.

Note: IMoaDrMovieContext was introduced in Director 7 because of a change in behavior between Director 6 and Director 7. In Director 6, the player used global variables to keep track of the current movie, and Xtras could callback into the player at any time. However, in Director 7, the player uses stack contexts to track the current movie.

There are two issues that are inter-related:
  1. In Internet Explorer, Director runs in Apartment Model. Under Apartment Model, each control instance will always be called on the same thread, but different instances may be called on different threads. And a window created by a thread will always have messages dispatched to it on that thread. So, if you display two copies of a page with a Shockwave movie using your Xtra, your Xtra is likely to be called on different threads.
  2. In Internet Explorer or Navigator on Windows, if you create your own windows, the operating system sends messages to your window without the player knowing. So when you call into the player, it does not know what movie the calls apply to. In Navigator, Director is always called on the same thread, so threading is not a problem. But not knowing what window a call applies to is a problem in both browsers.

    In Internet Explorer, if you have your own window, the operating system sends you messages without the player having any opportunity to control multiple threads. Another movie in another window might be in the middle of a player operation when you get your message. If you call into the player while the other movie is in there, the player is likely to crash.

If you do not have your own windows or background threads, this will not matter. You will always get control by the player calling you, and it makes sure that only one thread is executing in it at a time. So you might be called on different threads, but you will never be executing your code on two threads at the same time. When it calls you, the player also knows what movie the call applies to.
Pushing and popping contexts
Whenever an Xtra might be calling the player back from a message sent directly to its window proc by Windows, the player calls must be bracketed with calls to PushXtraContext() and PopXtraContext(). The DrContextState must be a local variable in the calling function.
For example, m_pIDrMovieContext is a IMoaDrMovieContext member of the asset Xtra's object class:
/* This code is sometimes called directly from a Windows event
/  received by the Xtra's wndproc. */
DrContextState drContextState;
if (m_pObj->m_pIDrMovieContext &&
    !(m_pObj->m_pIDrMovieContext->PushXtraContext(&drContextState)))
{
    ... /* Call other Director interfaces at will */
    m_pObj->m_pIDrMovieContext->PopXtraContext(&drContextState);
}
If the PushXtraContext() call is not made or the PopXtraContext() call is dropped, the player may crash or produce other unexpected results. These calls inform the player what movie context applies and, for the ActiveX control only, provide protection for multiple threads.
The Xtra needs to acquire an IDrMovieContext interface during a call from the player, for example, during the sprite asset's constructor.
Use a different instance of IMoaDrMovieContext for each instance of your Xtra class. The IMoaDrMovieContext includes which movie you are being used in, so if you try to share a single copy between multiple instances, you will get information about the wrong movie when you make calls to the player.
Use IMoaDrPlayer to get an IMoaDrMovie interface to the active movie. Then QueryInterface that interface to get an IMoaDrMovieContext interface. Release the IMoaDrMovie and IMoaDrPlayer interfaces (unless you need them for other reasons), and keep the IMoaDrMovieContext as a member of your asset Xtra object. The following C++ code snippet works:
/* m_pIDrMovieContext is a new member of the asset pObj class */
m_pIDrMovieContext = NULL;
PIMoaDrPlayer pIMoaDrPlayer = NULL;
PIMoaDrMovie pIMoaDrMovie = NULL;
if (!m_pICallback->QueryInterface(&IID_IMoaDrPlayer, (PPMoaVoid)&pIMoaDrPlayer))
{
    if (!pIMoaDrPlayer->GetActiveMovie(&pIMoaDrMovie))
    {
        pIMoaDrMovie->QueryInterface(&IID_IMoaDrMovieContext, (PPMoaVoid)&m_pIDrMovieContext);
        pIMoaDrMovie->Release();
    }
    pIMoaDrPlayer->Release();
}
The destructor must release, of course:
if (m_pIDrMovieContext != NULL)
{
    m_pIDrMovieContext->Release();
    m_pIDrMovieContext = NULL;
}
Releasing and reacquiring threads
ReleaseExclusiveThread() and ReacquireExclusiveThread() should rarely be needed and are effective only in the ActiveX control. You might need them in a situation such as the following.
When a GoToNetPage is issued, Internet Explorer requires services that happen to be implemented on its main thread. There may be a Shockwave movie on that thread. The following scenario can cause a deadlock because the thread of window 2 is waiting for services from the thread of window 1 and vice versa:
  1. Window 2 (running on a secondary thread) is executing player code.
  2. Window 1 (running on the main thread) blocks at entry to the player.
  3. Window 2 issues a GoToNetPage, which calls Internet Explorer services.
  4. Internet Explorer services send a message to the main thread and wait for a response.
If you encounter this type of situation in the ActiveX control only, use ReleaseExclusiveThread() to give up the player, make the system call that needs to run on the main thread, then call ReacquireExclusiveThread(). You must reacquire after you release -- there are counted resources in there, and if you return to a caller who calls PopXtraContext(), the system will crash.
As of March 2006, of the Xtras written for Director by Adobe, the following xtras needed thread protection. None of these xtras needed to release and reacquire the thread.
Xtras with background threads
On Windows, you must not call the player from threads you create, unless you are running within the ActiveX control.
The Director ActiveX control includes thread protection, because of the use of Apartment Model. So, if you are in the control, you can use IMoaDrMovieContext::PushXtraContext() and PopXtraContext() to call the player from a background thread. Use the code described earlier for handling messages sent directly from Windows to your Xtra.
None of the other environments--Authoring, Projectors, Netscape Plugin, or ShockMachine--include thread reentrancy protection. The player must always be called on the main thread.
If you have a background thread, you can handle this by using SendMessage() to switch to the primary thread for player calls:
  1. On the primary thread (for example, in your Xtra class's constructor), create a window, hWnd. Dispose of the window in the destructor.
  2. Attach a window proc to the window.
  3. Structure your code so that it contains a procedure or function with the logic you need to call from the background thread, including PushXtraContext() and PopXtraContext() calls. Package the parameters to the function so that they can be sent through the window proc. The arguments can be a DWORD and a WORD, returning a DWORD. The DWORDs might be pointers to structures.
  4. Define a windows user message code, such as WM_BACKGROUND_TO_PRIMARY.
  5. In the wndproc, handle WM_BACKGROUND_TO_PRIMARY by calling your proc from step 3, passing lParam and wParam, and returning the result.
  6. On the background thread, instead of calling the proc from step 3, call SendMessage(hWnd, ...) to send the message to window created in step 1.
Windows will switch to the thread that created the window, execute the message on that thread, and resume the background thread only when the message has been processed and the result is returned from the wndproc.
A couple of notes:
Use caution with threads and windows
Code carefully to never pop without a push or vice-versa. If you use exceptions, make sure your catch pops if it needs to. Never release without reacquiring. Protect your global variables and any other data that is shared between instances with push/pop to make sure multiple threads do not find their way into the same code at the same time. Test your Xtra in several movies at the same time in Internet Explorer/Windows, and stress all the instances at the same time. That should uncover any lingering code that needs to be protected.

Methods

PushXtraContext()
PopXtraContext()
ReleaseExclusiveThread()
ReacquireExclusiveThread()

PopXtraContext()

Syntax
PopXtraContext(PDrContextState pDrContextState)
Parameters
pDrContextState
Address of the DrContextState local variable that was provided to PushXtraContext()
Returns
MoaError
Description
This method leaves the context established by PushXtraContext().

PushXtraContext()

Syntax
PushXtraContext(PDrContextState pDrContextState)
Parameters
pDrContextState
Address of a DrContextState that is a local variable in the calling procedure
Returns
MoaError
Description
This method establishes a movie context for subsequent calls to the player. In the ActiveX control, this method also blocks multiple threads from simultaneous execution. pDrContextState must be a local variable in the calling function. Before returning to its caller, that function must leave the established context by calling PopXtraContext() with the same pDrContextState.

ReacquireExclusiveThread()

Syntax
ReacquireExclusiveThread(PDrContextState pDrContextState)
Parameters
pDrContextState
Address of the DrContextState local variable that was provided to ReacquireExclusiveThread()
Returns
MoaError
Description
This method reacquires the context released by ReleaseExclusiveThread(). This method is rarely used.

ReleaseExclusiveThread()

Syntax
ReleaseExclusiveThread(PDrContextState pDrContextState)
Parameters
pDrContextState
Address of a DrContextState that is a local variable in the calling procedure
Returns
MoaError
Description
In the ActiveX control only, this method releases the player so it can be called from other threads. This method must be followed by a ReacquireExclusiveThread() call using the same pDrContextState. pDrContextState must be the address of a local variable in the calling function. This method is rarely used.

Copyright(c) 1995-2006 Adobe Macromedia Software LLC, Inc.