Partilhar via


"InteropServices.SEHException: External component has thrown an exception" - Solved!

I finally solved the problems with enabling XP Visual Styles (Themes) which I described here. My initial attempt worked on some computers but not others; apparently there is some mystic connection between the themed activation context, the color of my underwear and the current conversion rate from yen to zloty.  Anyway, a huge thanks to Nat (whoever you are) for the  helpful tips regarding various aspects of manifest creation and automation.

The solution?  Skip the default C# implementation (which is buggy) and implement your own, as detailed here:

Microsoft Knowledge Base Article - 830033:    HOW TO: Enable Office COM Add-ins to Opt-in to Windows XP Themes

or just copy the following code into a class:

using System.Runtime.InteropServices;

using System;

using System.Security;

using System.Security.Permissions;

using System.Collections;

using System.IO;

using System.Text;

using System.Windows.Forms;

      [ SuppressUnmanagedCodeSecurity ]

      internal class EnableThemingInScope : IDisposable

      {

            // Private data

            private uint cookie;

            private static ACTCTX enableThemingActivationContext;

            private static IntPtr hActCtx;

            private static bool contextCreationSucceeded = false;

            public EnableThemingInScope(bool enable)

            {

                  cookie = 0;

                  if (enable && OSFeature.Feature.IsPresent(OSFeature.Themes))

                  {

                        if (EnsureActivateContextCreated())

                        {

                              if (!ActivateActCtx(hActCtx, out cookie))

                              {

                                    // Be sure cookie always zero if activation failed

                                    cookie = 0;

                              }

                        }

                  }

            }

            ~EnableThemingInScope()

            {

                  Dispose(false);

            }

            void IDisposable.Dispose()

            {

                  Dispose(true);

            }

            private void Dispose(bool disposing)

            {

                  if (cookie != 0)

                  {

                        if (DeactivateActCtx(0, cookie))

                        {

                              // deactivation succeeded...

                              cookie = 0;

                        }

                  }

            }

            private bool EnsureActivateContextCreated()

            {

                  lock (typeof(EnableThemingInScope))

                  {

                        if (!contextCreationSucceeded)

                        {

                              // Pull manifest from the .NET Framework install

                              // directory

                              string assemblyLoc = null;

                       

                              FileIOPermission fiop = new FileIOPermission(PermissionState.None);

                              fiop.AllFiles = FileIOPermissionAccess.PathDiscovery;

                              fiop.Assert();

                              try

                              {

                                    assemblyLoc = typeof(Object).Assembly.Location;

                              }

                              finally

                              {

                                    CodeAccessPermission.RevertAssert();

                              }

                              string manifestLoc = null;

                              string installDir = null;

                              if (assemblyLoc != null)

                              {

                                    installDir = Path.GetDirectoryName(assemblyLoc);

                                    const string manifestName = "XPThemes.manifest";

                                    manifestLoc = Path.Combine(installDir, manifestName);

                              }

                              if (manifestLoc != null && installDir != null)

                              {

                              enableThemingActivationContext = new ACTCTX();

                                    enableThemingActivationContext.cbSize = Marshal.SizeOf(typeof(ACTCTX));

                                    enableThemingActivationContext.lpSource = manifestLoc;

                                    // Set the lpAssemblyDirectory to the install

                                    // directory to prevent Win32 Side by Side from

                                    // looking for comctl32 in the application

                                    // directory, which could cause a bogus dll to be

                                    // placed there and open a security hole.

                                    enableThemingActivationContext.lpAssemblyDirectory = installDir;

                                    enableThemingActivationContext.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;

 

                                    // Note this will fail gracefully if file specified

                                    // by manifestLoc doesn't exist.

                                    hActCtx = CreateActCtx(ref enableThemingActivationContext);

                                    contextCreationSucceeded = (hActCtx != new IntPtr(-1));

                              }

                        }

                        // If we return false, we'll try again on the next call into

                        // EnsureActivateContextCreated(), which is fine.

                        return contextCreationSucceeded;

                  }

            }

            // All the pinvoke goo...

            [DllImport("Kernel32.dll")]

            private extern static IntPtr CreateActCtx(ref ACTCTX actctx);

            [DllImport("Kernel32.dll")]

            private extern static bool ActivateActCtx(IntPtr hActCtx, out uint lpCookie);

            [DllImport("Kernel32.dll")]

            private extern static bool DeactivateActCtx(uint dwFlags, uint lpCookie);

            private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;

           

            private struct ACTCTX

            {

                  public int cbSize;

                  public uint dwFlags;

                  public string lpSource;

                  public ushort wProcessorArchitecture;

                  public ushort wLangId;

                  public string lpAssemblyDirectory;

                  public string lpResourceName;

                  public string lpApplicationName;

            }

      }

 

Then replace the default Main() with the following wrapper code. This procedure pushes a themed activation context before creating any controls:

            static void Main()
            {
                  using( new EnableThemingInScope( true ) )
                  {
                       Form form1 = new Form();
                       form1.CreateControl();
                       Application.Run(form1);
                  }
            }

...Enjoy !!

Comments