mirror of https://github.com/dahall/Vanara.git
150 lines
6.7 KiB
C#
150 lines
6.7 KiB
C#
using System;
|
|
using System.Security;
|
|
using Vanara.PInvoke;
|
|
using static Vanara.PInvoke.Kernel32;
|
|
|
|
namespace Vanara.Windows.Forms
|
|
{
|
|
/// <summary>Provides an activation context for a manifest file or PE image. On disposal, the context is deactivated.</summary>
|
|
/// <seealso cref="System.IDisposable"/>
|
|
[SuppressUnmanagedCodeSecurity]
|
|
public class ActivationContext : IDisposable
|
|
{
|
|
private SafeHACTCTX hActCtx;
|
|
private IntPtr localCookie;
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="ActivationContext"/> class.</summary>
|
|
/// <exception cref="InvalidOperationException">No current activation context exists.</exception>
|
|
public ActivationContext() => hActCtx = SafeHACTCTX.GetCurrent();
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="ActivationContext"/> class.</summary>
|
|
/// <param name="source">The path of a manifest file. Do not use this constructor if specifying a PE image.</param>
|
|
/// <param name="assemblyDirectory">
|
|
/// The base directory in which to perform private assembly probing if assemblies in the activation context are not present in the
|
|
/// system-wide store.
|
|
/// </param>
|
|
public ActivationContext(string source, string assemblyDirectory = null)
|
|
{
|
|
var actctx = new ACTCTX(source);
|
|
CreateAndAttach(ref actctx, assemblyDirectory: assemblyDirectory);
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="ActivationContext"/> class.</summary>
|
|
/// <param name="peImagePath">Specifies the path of PE image (EXE or DLL file) to be used to create the activation context.</param>
|
|
/// <param name="resourceName">
|
|
/// The resource name to be loaded from the PE. If the resource name is an integer, set this member using MAKEINTRESOURCE.
|
|
/// </param>
|
|
/// <param name="assemblyDirectory">
|
|
/// The base directory in which to perform private assembly probing if assemblies in the activation context are not present in the
|
|
/// system-wide store.
|
|
/// </param>
|
|
/// <param name="appName">
|
|
/// 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.
|
|
/// </param>
|
|
/// <param name="langId">Specifies the language manifest that should be used. The default is the current user's current UI language.</param>
|
|
/// <param name="processor">Identifies the type of processor used. Specifies the system's processor architecture.</param>
|
|
/// <param name="setAsProcessDefault">if set to <c>true</c> [set as process default].</param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="ActivationContext"/> class.</summary>
|
|
/// <param name="hInst">
|
|
/// Specifies the handle to an already opened module (EXE or DLL file) to be used to create the activation context.
|
|
/// </param>
|
|
/// <param name="resourceName">
|
|
/// The resource name to be loaded from the PE. If the resource name is an integer, set this member using MAKEINTRESOURCE.
|
|
/// </param>
|
|
/// <param name="assemblyDirectory">
|
|
/// The base directory in which to perform private assembly probing if assemblies in the activation context are not present in the
|
|
/// system-wide store.
|
|
/// </param>
|
|
/// <param name="appName">
|
|
/// 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.
|
|
/// </param>
|
|
/// <param name="langId">Specifies the language manifest that should be used. The default is the current user's current UI language.</param>
|
|
/// <param name="processor">Identifies the type of processor used. Specifies the system's processor architecture.</param>
|
|
/// <param name="setAsProcessDefault">if set to <c>true</c> [set as process default].</param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="ActivationContext"/> class.</summary>
|
|
/// <param name="context">An activation context structure.</param>
|
|
public ActivationContext(in ACTCTX context)
|
|
{
|
|
Create(context);
|
|
Activate();
|
|
}
|
|
|
|
/// <summary>Gets the local cookie associated with the activation.</summary>
|
|
public IntPtr Cookie => localCookie;
|
|
|
|
/// <summary>Gets a value indicating if the context is invalid.</summary>
|
|
public bool IsInvalid => hActCtx.IsNull;
|
|
|
|
/// <inheritdoc/>
|
|
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();
|
|
}
|
|
}
|
|
} |