Update:我的第一个解决方案不适用于像OP所要求的程序资源中包含的程序集;相反,它从磁盘加载它。从字节数组加载的解决方案将随之而来(正在进行中)。请注意,以下几点适用于这两种解决方案:
As the Environment.Exit()
方法由于缺乏权限而抛出异常,该方法的执行将not遇到后继续。
您将需要 Main 方法所需的所有权限,但只需在智能感知中键入“权限”或检查SecurityException
's TargetSite
属性(这是一个实例MethodBase
并会告诉您哪种方法失败了)。
如果您的 Main 中的另一个方法需要UnmanagedCode
许可,你运气不好,至少使用这个解决方案。
请注意,我发现UnmanagedCode
许可是Environment.Exit()
needs 纯粹通过尝试和错误.
解决方案 1:当程序集位于磁盘上时
好的,这就是我到目前为止发现的内容,请耐心等待。我们将创建一个沙盒 AppDomain:
AppDomainSetup adSetup = new AppDomainSetup();
adSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
// This is where the main executable resides. For more info on this, see "Remarks" in
// https://msdn.microsoft.com/en-us/library/system.appdomainsetup.applicationbase(v=vs.110).aspx#Anchor_1
PermissionSet permission = new PermissionSet(PermissionState.None);
// Permissions of the AppDomain/what it can do
permission.AddPermission(new SecurityPermission(SecurityPermissionFlag.AllFlags & ~SecurityPermissionFlag.UnmanagedCode));
// All SecurityPermission flags EXCEPT UnmanagedCode, which is required by Environment.Exit()
// BUT the assembly needs SecurityPermissionFlag.Execution to be run;
// otherwise you'll get an exception.
permission.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
permission.AddPermission(new UIPermission(PermissionState.Unrestricted));
// the above two are for Console.WriteLine() to run, which is what I had in the Main method
var assembly = Assembly.LoadFile(exePath); // path to ConsoleApplication1.exe
var domain = AppDomain.CreateDomain("SomeGenericName", null, adSetup, permission, null); // sandboxed AppDomain
try
{
domain.ExecuteAssemblyByName(assembly.GetName(), new string[] { });
}
// The SecurityException is thrown by Environment.Exit() not being able to run
catch (SecurityException e) when (e.TargetSite == typeof(Environment).GetMethod("Exit"))
{
Console.WriteLine("Tried to run Exit");
}
catch (SecurityException e)
{
// Some other action in your method needs SecurityPermissionFlag.UnmanagedCode to run,
// or the PermissionSet is missing some other permission
}
catch
{
Console.WriteLine("Something else failed in ConsoleApplication1.exe's main...");
}
解决方案2:当程序集是字节数组时
警告:癌症解决方案如下。
当更改我的解决方案以加载字节数组时,OP和我发现了一个奇怪的异常文件未找到异常:即使你传入一个字节数组Assembly.Load()
, domain.ExecuteAssemblyByName()
由于某些奇怪的原因,仍然在磁盘上搜索程序集。显然我们并不是唯一遇到这个问题的人:加载字节数组汇编 https://stackoverflow.com/questions/17836159/loading-byte-array-assembly.
首先,我们有一个Helper
class:
public class Helper : MarshalByRefObject
{
public void LoadAssembly(Byte[] data)
{
var a = Assembly.Load(data);
a.EntryPoint.Invoke(null, null);
}
}
正如你所看到的,使用加载程序集Assembly.Load()
并调用它的入口点。这是我们将加载到的代码AppDomain
:
AppDomainSetup adSetup = new AppDomainSetup();
adSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
// This is where the main executable resides. For more info on this, see "Remarks" in
// https://msdn.microsoft.com/en-us/library/system.appdomainsetup.applicationbase(v=vs.110).aspx#Anchor_1
PermissionSet permission = new PermissionSet(PermissionState.None);
// Permissions of the AppDomain/what it can do
permission.AddPermission(new SecurityPermission(SecurityPermissionFlag.AllFlags & ~SecurityPermissionFlag.UnmanagedCode));
// All SecurityPermission flags EXCEPT UnmanagedCode, which is required by Environment.Exit()
// BUT the assembly needs SecurityPermissionFlag.Execution to be run;
// otherwise you'll get an exception.
permission.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
permission.AddPermission(new UIPermission(PermissionState.Unrestricted));
// the above two are for Console.WriteLine() to run, which is what I had in the Main method
var domain = AppDomain.CreateDomain("SomeGenericName", null, adSetup, permission, null); // sandboxed AppDomain
try
{
Helper helper = (Helper)domain.CreateInstanceAndUnwrap(typeof(Helper).Assembly.FullName, typeof(Helper).FullName);
// create an instance of Helper in the new AppDomain
helper.LoadAssembly(bytes); // bytes is the in-memory assembly
}
catch (TargetInvocationException e) when (e.InnerException.GetType() == typeof(SecurityException))
{
Console.WriteLine("some kind of permissions issue here");
}
catch (Exception e)
{
Console.WriteLine("Something else failed in ConsoleApplication1.exe's main... " + e.Message);
}
请注意,在第二个解决方案中,SecurityException
成为一个TargetInvocationException
与它的InnerException
财产是SecurityException
。不幸的是,这意味着您不能使用e.TargetSite
查看哪个方法引发了异常。
结论/注意事项
这个解决方案并不完美。最好以某种方式检查方法的 IL 并人为地删除对Environment.Exit()
.