我试图做类似的事情。我的结论是微软提供的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
{
// Methods
[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 流中获取任何内容时抛出异常