using System;
using System.Security;
using Vanara.PInvoke;
using static Vanara.PInvoke.Kernel32;
namespace Vanara.Windows.Forms
{
/// Provides an activation context for a manifest file or PE image. On disposal, the context is deactivated.
///
[SuppressUnmanagedCodeSecurity]
public class ActivationContext : IDisposable
{
private SafeHACTCTX hActCtx;
private IntPtr localCookie;
/// Initializes a new instance of the class.
/// No current activation context exists.
public ActivationContext() => hActCtx = SafeHACTCTX.GetCurrent();
/// Initializes a new instance of the class.
/// The path of a manifest file. Do not use this constructor if specifying a PE image.
///
/// The base directory in which to perform private assembly probing if assemblies in the activation context are not present in the
/// system-wide store.
///
public ActivationContext(string source, string assemblyDirectory = null)
{
var actctx = new ACTCTX(source);
CreateAndAttach(ref actctx, assemblyDirectory: assemblyDirectory);
}
/// Initializes a new instance of the class.
/// Specifies the path of PE image (EXE or DLL file) to be used to create the activation context.
///
/// The resource name to be loaded from the PE. If the resource name is an integer, set this member using MAKEINTRESOURCE.
///
///
/// The base directory in which to perform private assembly probing if assemblies in the activation context are not present in the
/// system-wide store.
///
///
/// The name of the current application. If the value of this member is set to null, the name of the executable that launched the
/// current process is used.
///
/// Specifies the language manifest that should be used. The default is the current user's current UI language.
/// Identifies the type of processor used. Specifies the system's processor architecture.
/// if set to true [set as process default].
public ActivationContext(string peImagePath, string resourceName, string assemblyDirectory = null, string appName = null, ushort langId = 0, ProcessorArchitecture processor = 0, bool setAsProcessDefault = false)
{
var actctx = new ACTCTX(peImagePath ?? throw new ArgumentNullException(nameof(peImagePath)));
if (resourceName == null) throw new ArgumentNullException(nameof(resourceName));
CreateAndAttach(ref actctx, resourceName, assemblyDirectory, appName, langId, processor, setAsProcessDefault);
}
/// Initializes a new instance of the class.
///
/// Specifies the handle to an already opened module (EXE or DLL file) to be used to create the activation context.
///
///
/// The resource name to be loaded from the PE. If the resource name is an integer, set this member using MAKEINTRESOURCE.
///
///
/// The base directory in which to perform private assembly probing if assemblies in the activation context are not present in the
/// system-wide store.
///
///
/// The name of the current application. If the value of this member is set to null, the name of the executable that launched the
/// current process is used.
///
/// Specifies the language manifest that should be used. The default is the current user's current UI language.
/// Identifies the type of processor used. Specifies the system's processor architecture.
/// if set to true [set as process default].
public ActivationContext(HINSTANCE hInst, string resourceName, string assemblyDirectory = null, string appName = null, ushort langId = 0, ProcessorArchitecture processor = 0, bool setAsProcessDefault = false)
{
if (hInst.IsNull) throw new ArgumentNullException(nameof(hInst));
if (resourceName == null) throw new ArgumentNullException(nameof(resourceName));
var actctx = ACTCTX.Empty;
actctx.hModule = hInst;
CreateAndAttach(ref actctx, resourceName, assemblyDirectory, appName, langId, processor, setAsProcessDefault);
}
/// Initializes a new instance of the class.
/// An activation context structure.
public ActivationContext(in ACTCTX context)
{
Create(context);
Activate();
}
/// Gets the local cookie associated with the activation.
public IntPtr Cookie => localCookie;
/// Gets a value indicating if the context is invalid.
public bool IsInvalid => hActCtx.IsNull;
///
public void Dispose()
{
if (localCookie != IntPtr.Zero && DeactivateActCtx(0, localCookie))
localCookie = IntPtr.Zero;
hActCtx.Dispose();
}
private void Activate()
{
if (!ActivateActCtx(hActCtx, out localCookie)) Win32Error.ThrowLastError();
}
private void Create(in ACTCTX context)
{
hActCtx = CreateActCtx(context);
if (hActCtx.IsInvalid) Win32Error.ThrowLastError();
}
private void CreateAndAttach(ref ACTCTX actctx, string resourceName = null, string assemblyDirectory = null, string appName = null, ushort langId = 0, ProcessorArchitecture processor = 0, bool setAsProcessDefault = false)
{
if (resourceName != null)
{
actctx.lpResourceName = resourceName;
actctx.dwFlags |= ActCtxFlags.ACTCTX_FLAG_RESOURCE_NAME_VALID;
}
if (assemblyDirectory != null)
{
actctx.lpAssemblyDirectory = assemblyDirectory;
actctx.dwFlags |= ActCtxFlags.ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
}
if (appName != null)
{
actctx.lpApplicationName = appName;
actctx.dwFlags |= ActCtxFlags.ACTCTX_FLAG_APPLICATION_NAME_VALID;
}
if (langId != 0)
{
actctx.wLangId = langId;
actctx.dwFlags |= ActCtxFlags.ACTCTX_FLAG_LANGID_VALID;
}
if (processor != 0)
{
actctx.wProcessorArchitecture = processor;
actctx.dwFlags |= ActCtxFlags.ACTCTX_FLAG_PROCESSOR_ARCHITECTURE_VALID;
}
if (setAsProcessDefault)
{
actctx.dwFlags |= ActCtxFlags.ACTCTX_FLAG_SET_PROCESS_DEFAULT;
}
Create(actctx);
Activate();
}
}
}