我曾试图做类似的事情,但最终得出结论,微软提供的COM库不完整。我不使用它是因为文档中提到“注意:此主题是预发布文档,可能会在以后的版本中更改。”
所以,我决定看看IISExpressTray.exe在做什么。它似乎在做类似的事情。
我反汇编了IISExpressTray.dll并发现列出所有IISexpress进程并停止IISexpress进程没有任何奇技淫巧。
它没有调用那个COM库,也没有从注册表中查找任何内容。
所以,我最终得出的解决方案非常简单。要启动IIS express进程,我只需使用Process.Start()并传入我需要的所有参数。
要停止IIS express进程,我从Reflector中复制了IISExpressTray.dll中的代码。我看到它只是向目标IISExpress进程发送WM_QUIT消息。
这是我编写的启动和停止IIS express进程的类。希望这能帮助其他人。
class IISExpress
{
internal class NativeMethods
{
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr GetTopWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("user32.dll", SetLastError = true)]
internal static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
}
public static void SendStopMessageToProcess(int PID)
{
try
{
for (IntPtr ptr = NativeMethods.GetTopWindow(IntPtr.Zero); ptr != IntPtr.Zero; ptr = NativeMethods.GetWindow(ptr, 2))
{
uint num;
NativeMethods.GetWindowThreadProcessId(ptr, out num);
if (PID == num)
{
HandleRef hWnd = new HandleRef(null, ptr);
NativeMethods.PostMessage(hWnd, 0x12, IntPtr.Zero, IntPtr.Zero);
return;
}
}
}
catch (ArgumentException)
{
}
}
const string IIS_EXPRESS = @"C:\Program Files\IIS Express\iisexpress.exe";
const string CONFIG = "config";
const string SITE = "site";
const string APP_POOL = "apppool";
Process process;
IISExpress(string config, string site, string apppool)
{
Config = config;
Site = site;
AppPool = apppool;
StringBuilder arguments = new StringBuilder();
if (!string.IsNullOrEmpty(Config))
arguments.AppendFormat("/{0}:{1} ", CONFIG, Config);
if (!string.IsNullOrEmpty(Site))
arguments.AppendFormat("/{0}:{1} ", SITE, Site);
if (!string.IsNullOrEmpty(AppPool))
arguments.AppendFormat("/{0}:{1} ", APP_POOL, AppPool);
process = Process.Start(new ProcessStartInfo()
{
FileName = IIS_EXPRESS,
Arguments = arguments.ToString(),
RedirectStandardOutput = true,
UseShellExecute = false
});
}
public string Config { get; protected set; }
public string Site { get; protected set; }
public string AppPool { get; protected set; }
public static IISExpress Start(string config, string site, string apppool)
{
return new IISExpress(config, site, apppool);
}
public void Stop()
{
SendStopMessageToProcess(process.Id);
process.Close();
}
}
我不需要列出所有现有的IIS Express进程。如果你需要,从我在反编译器中看到的内容来看,IISExpressTray.dll所做的是调用Process.GetProcessByName("iisexpress", ".")
要使用我提供的类,这里有一个我用来测试的示例程序。
class Program
{
static void Main(string[] args)
{
Console.Out.WriteLine("Launching IIS Express...");
IISExpress iis1 = IISExpress.Start(
@"C:\Users\Administrator\Documents\IISExpress\config\applicationhost.config",
@"WebSite1(1)",
@"Clr4IntegratedAppPool");
IISExpress iis2 = IISExpress.Start(
@"C:\Users\Administrator\Documents\IISExpress\config\applicationhost2.config",
@"WebSite1(1)",
@"Clr4IntegratedAppPool");
Console.Out.WriteLine("Press ENTER to kill");
Console.In.ReadLine();
iis1.Stop();
iis2.Stop();
}
}
这可能不是你问题的答案,但我认为对你问题感兴趣的人可能会发现我的工作很有用。请随意改进代码。以下是一些你可能希望增强的地方:
- 而不是硬编码iisexpress.exe的位置,你可以修改我的代码以从注册表中读取。
- 我没有包含iisexpress.exe支持的所有参数。
- 我没有进行错误处理。所以,如果IISExpress进程由于某些原因(例如端口被占用)启动失败,我将不知道。我认为最简单的解决方法是监视StandardError流,如果我从StandardError流中获得任何东西,则抛出异常
CreateNoWindow = true
,并在我的测试夹具的SetUp/TearDown期间使用它。非常感谢! - Colin Zabranskyprocess.Kill()
,但由于某些原因它无法正常工作(顺便问一下,有人知道为什么吗?),使用停止消息可以解决问题。 - Alex from Jitbit