Ele*_*ios 10 .net c# vb.net reflection .net-assembly
我使用的共享下一个C#代码示例大卫赫弗南 "为从应用程序的资源加载.NET程序集,并从内存中运行它:
Assembly a = Assembly.Load(bytes);
MethodInfo method = a.EntryPoint;
if (method != null)
method.Invoke(a.CreateInstance(method.Name), null);
Run Code Online (Sandbox Code Playgroud)
在这里,我只是在VB.NET中分享我正在使用的改编:
Public Shared Sub Execute(ByVal resource As Byte(), ByVal parameters As Object())
Dim ass As Assembly = Assembly.Load(resource)
Dim method As MethodInfo = ass.EntryPoint
If (method IsNot Nothing) Then
Dim instance As Object = ass.CreateInstance(method.Name)
method.Invoke(instance, parameters)
If (instance IsNot Nothing) AndAlso (instance.GetType().GetInterfaces.Contains(GetType(IDisposable))) Then
DirectCast(instance, IDisposable).Dispose()
End If
instance = Nothing
method = Nothing
ass = Nothing
Else
Throw New EntryPointNotFoundException("Entrypoint not found in the specified resource. Are you sure it is a .NET assembly?")
End If
End Sub
Run Code Online (Sandbox Code Playgroud)
问题是如果执行的程序集有一个应用程序退出指令,那么它也会终止我的主/主机应用程序.例如:
从这个源代码编译的ConsoleApplication1.exe:
Module Module1
Sub Main()
Environment.Exit(0)
End Sub
End Module
Run Code Online (Sandbox Code Playgroud)
当我将ConsoleApplication1.exe添加到应用程序资源,然后我加载它并使用该Assembly.Load
方法运行它时,它也会因为调用而终止我的应用程序Environment.Exit
.
如何在不修改已执行程序集的源代码的情况下防止这种情况?
也许我可以做一些事情,比如将一种退出事件处理程序关联到执行的程序集以正确处理/忽略它?在这一点上我有什么选择?
PS:对我来说无论给定的解决方案是用C#还是VB.NET编写的.
请注意两件事,第一件是我的意图是以自动/抽象的方式解决这个问题,我的意思是最后的结果应该只需要调用"Execute"方法传递资源和参数而不用担心其余的部分; 其次,我希望执行的程序集同步运行,而不是异步运行......如果这可能对可能的解决方案很重要.
更新:我的第一个解决方案不适用于OP所要求的程序资源中包含的程序集; 而是从磁盘加载它.从字节数组加载的解决方案将遵循(进行中).请注意,以下几点适用于这两种解决方案:
由于该Environment.Exit()
方法由于缺少权限而抛出异常,因此在遇到该方法后,该方法的执行将不会继续.
你会需要你的主要方法需要的所有权限,但你可以找到那些很快就在智能感知键入"权限",或者通过检查SecurityException
的TargetSite
属性(是的一个实例MethodBase
,并会告诉你哪些方法失败).
如果您的Main中的另一种方法需要UnmanagedCode
权限,那么您运气不好,至少使用此解决方案.
请注意,我发现该UnmanagedCode
权限是纯粹通过反复试验Environment.Exit()
所需的权限.
好的,这是我到目前为止所发现的,请耐心等待.我们将创建一个沙盒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...");
}
Run Code Online (Sandbox Code Playgroud)
警告:癌症解决方案如下.
在更改我的解决方案以加载字节数组时,OP和我发现了一个奇怪的异常文件未找到异常:即使你传入一个字节数组Assembly.Load()
,domain.ExecuteAssemblyByName()
仍然会在磁盘上搜索程序集,原因有些奇怪.显然我们不是唯一有问题的人:加载字节数组装配.
首先,我们有一个Helper
班级:
public class Helper : MarshalByRefObject
{
public void LoadAssembly(Byte[] data)
{
var a = Assembly.Load(data);
a.EntryPoint.Invoke(null, null);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,使用加载程序集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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在第二个解决方案中,SecurityException
变为a TargetInvocationException
,其InnerException
属性为a SecurityException
.不幸的是,这意味着您无法使用e.TargetSite
哪种方法来查看异常.
这个解决方案并不完美.以某种方式通过方法的IL并人为地删除调用将会好得多Environment.Exit()
.
归档时间: |
|
查看次数: |
2142 次 |
最近记录: |