我正在尝试建立一个自动检查是否可以毫无问题地打开多个32位WPF应用程序。
我不想使用Process.Start,因为我无法确定每个程序是否会在出现问题时返回非零退出代码(我将不得不用更多代码关闭这些WPF应用程序)。
我的计划是:在运行时加载程序集并触发它们的start方法(连接到一些异常事件接收器以获取有关问题的信息并关闭稍后打开的窗口)。
这是我到目前为止所得到的:
public void Check(string executablePath)
{
try
{
Assembly assembly;
try
{
assembly = Assembly.LoadFrom(executablePath);
}
catch (BadImageFormatException e)
{
Logger.InfoFormat("Not a 32 bit .NET application : {0}", Path.GetFileName(executablePath));
return;
}
assembly.EntryPoint.Invoke(null, new object[] { });
Logger.InfoFormat("OK : {0}", Path.GetFileName(executablePath));
}
catch (Exception e)
{
Logger.Error(e);
}
}
我的问题:一旦我调用了EntryPoint方法,就会出现来自应用程序内部的错误屏幕,告诉我发生了IOExeption(它无法找到启动画面的资源)
我是否必须以某种方式在其他程序集中预加载这些资源才能使其正常工作?
更新
使用Dirks回答我能够创建一个新的应用程序域,并将该入口点的调用委托给由该域创建的MarshalByRefObject后代。
由于这个网站(目前不在线),我也能够更改Assembly.EntryAssembly的值
执行工作的代码段:
private void ModifyEntryAssembly(Assembly assembly)
{
AppDomainManager manager = new AppDomainManager();
FieldInfo entryAssemblyfield = manager.GetType().GetField("m_entryAssembly", BindingFlags.Instance | BindingFlags.NonPublic);
if (entryAssemblyfield == null)
{
throw new Exception("Could not retrieve entryAssemblyField.");
}
entryAssemblyfield.SetValue(manager, assembly);
AppDomain domain = AppDomain.CurrentDomain;
FieldInfo domainManagerField = domain.GetType().GetField("_domainManager", BindingFlags.Instance | BindingFlags.NonPublic);
if (domainManagerField == null)
{
throw new Exception("Could not retrieve domainManagerField.");
}
domainManagerField.SetValue(domain, manager);
}
现在,我从被调用的可执行文件中获取启动画面和登录对话框,现在更进一步!
抛出EEntryPointException还有另一个问题,但这是另一个问题的另一个故事......谢谢!
答案 0 :(得分:2)
在条目程序集 1 中搜索WPF初始屏幕,在您的情况下,它是您的主要可执行文件,而不是您要检查的可执行文件。< / p>
您可以通过在自己的应用程序域中启动测试中的应用程序来解决此问题,然后将获得自己的条目程序集:
class Test
{
public static void Main()
{
var otherDomain = AppDomain.CreateDomain("otherDomain");
otherDomain.ExecuteAssembly("MyExecutable.exe");
}
}
但是,您应该知道您的方法会给您误报,因为正在测试的应用程序在另一个环境中运行。例如,调用Assembly.GetExecutingAssembly()
将在被测应用程序中提供不同的结果。而您的方法将无法同时测试32位和64位应用程序。
<子> 1
正如您从reference source所看到的,SplashScreen
构造函数的下方重载调用了Assembly.GetEntryAssembly()
:
public SplashScreen(string resourceName)
: this(Assembly.GetEntryAssembly(), resourceName)
{
}