SXS Activation Context — Activate and Deactivate


In Windows  XP the Side-by-Side technology is officially introduced:


http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sbscs/setup/isolated_applications_and_side_by_side_assemblies_start_page.asp


In a nutshell, applications/components write data to a special XML file called Sxs Manifest File. Later the data can be retrieved by various components in application or OS. Different components use their own manifests so they don’t interfere with other components.  For details please refer to the MSDN document.


Today there are three kinds of data can be described in Sxs manifest files:


1.       File redirection, used for LoadLibrary


2.       COM class registration, for inproc COM


3.       Window class registration, for CreateWindow/Ex


In the future more information may be enabled in Sxs manifests.


Activation Context is the runtime data structure to maintain the data in Sxs manifests. It is the boundary for Sxs data isolation. When components (for example, nt library loader, COM, User32) look up  their registration data, the search is performed in the following order:


1.       The most recent activated Activation Context


2.       The process default Activation Context


3.       The system default Activation Context


CreateProcess automatically creates a process default Activation Context if the application has a Sxs manifest, either as an external file as app.exe.manifest, or as internal Win32 resource of type RT_MANIFEST, ID 1.


Activation Context can also be created by calling API CreateActCtx.


(The system default Activation Context is not interesting. It only exists for backward compatibility reason.)


To activate/deactivate an ActivationContext, call ActivateActCtx/DeactivateActCtx.


Since components search their data in the most recent activated Activation Context, care is neede to be taken when using Sxs technology.


1.       Be sure to call ActivateActCtx when entering your isolation boundary so that you don’t read data from other people’s activation context. .


2.       Be sure to call DeactivateCtx when leaving your isolation boundary so that you don’t pollute other people’s activation context.


To enforce this rule, Sxs  maintains activation contexts in a way like a stack:


1.       ActivateActCtx pushes the activation context to the top of the stack, and it becomes the most recent activated activation context.


2.       DeactivateActCtx pops the activation context from the top of the stack, and the next one in the stack becomes the most recent activated action context.


3.       On deactivation, Sxs checks to see if the activation context to be deactivated is on the top of the stack or not. If it is not the top of the stack, Sxs throws one of the following two exceptions:


a.       If the activation context is on the stack, but not the top of the stack, Sxs throws exception STATUS_SXS_EARLY_DEACTIVATION (0xC015000F), with the message “The activation context being deactivated is not the most recently activated one.”


b.      If the activate context can not be found in the stack, exception STATUS_SXS_INVALID_DEACTIVATION (0xC0150010) is thrown, with the message “The activation context being deactivated is not active for the current thread of execution.”


You may see those two exceptions occasionally. The most likely reason is that someone calls ActivateActCtx on entrance, but forgets to call DeactivateActCtx on exit.


To ensure that this never happen in your code, use __try/__finally:


ActivateActCtx(hActCtx, &dwCookie);
__try
{

}
__finally {
DeactivateActCtx(0, dwCookie);
}


If you don’t clean up the activation context stack correctly, someone on top of you may try to clean up their stack, and end up with the deactivation exceptions.

Comments (7)

  1. anon says:

    I’d love to hear the story behind the ZombifyActivationContext API:

    http://msdn.microsoft.com/library/en-us/sbscs/setup/zombifyactctx.asp?frame=true

  2. junfeng says:

    MSDN documentation is clear about it, isn’t it?

    Remarks

    This function is intended for use in debugging threads using activation contexts. If the activation context deactivated by this function is subsequently accessed, the access fails and an assertion failure is shown in the debugger.

  3. Eric says:

    A application can run on vs2003,we ported the application to vs2005,when debug it on vs2005,it will throw the exception with the message:“The activation context being deactivated is not the most recently activated one.”

    What’s the reason and what should I do to fix this problem?

  4. junfeng says:

    Eric,

    This is case 3.a in my article. It means someone activated their activation context but did not deactivate it.

    Most likely they did not use my recommendation in this article. The code in between throws exception and the context is not cleaned up.

    Unfortunately I can’t tell you who is at fault and how to fix their code.

  5. Eric says:

    Thanks for your reply!

    My concern is why it can run correctly on vs2003,but throw the exception on vs2005.And it is in the MFC source code that throw the exception.

    Sorry to bother you! But hope to get your reply again.Thanks!

  6. Brandon Cernicky says:

    Thank you Junfeng for posting this information.  This likely saved me weeks of debugging.

    I have a VS 2005 C++ dll that uses AFX_MANAGE_STATE(AfxGetStaticModuleState()); in its public functions and I was receiving the “The activation context being deactivated is not the most recently activated one.” error message when I threw an exception or called into a 3rd party library that ended up throwing an exception/terminating/ending execution.

    By pushing the AFX_MANAGE_STATE(AfxGetStaticModuleState()); in its own scope and using a try/catch block I was able to ensure that MFC macro deconstructed and popped the context so that when the 3rd party library function was called, the proper context was in play.

    This is short of the full code and problem, but your posting/blog helped me tremendously.

    void MyFunction()

    {

    bool bDo3rdParty = false;

    //AFX_MANAGE_STATE put in its own scope

    // so that it will certainly deconstruct

    {

    AFX_MANAGE_STATE(AfxGetStaticModuleState());

    try

    {

    call something

    }

    catch (CMyException ex)

    {

    bDo3rdParty = true;

    }

    }

    if (bDo3rdParty)

    {

    call 3rd party which will throw exception, which

    normally would not permit AFX_MANAGE_STATE to exit

    }

    }