我试图做类似的事情。我的结论是微软提供的 COM 库是不完整的。我不使用它是因为文档提到“注意:本主题是预发布文档,在未来的版本中可能会发生变化”。
所以,我决定看看 IISExpressTray.exe 在做什么。它似乎在做类似的事情。
我反汇编了IISExpressTray.dll,发现列出所有IISexpress进程并停止IISexpress进程并没有什么神奇之处。
它不调用那个 COM 库。它不会从注册表中查找任何内容。
所以,我最终得到的解决方案非常简单。要启动 IIS express 进程,我只需使用 Process.Start() 并传入我需要的所有参数。
为了停止 IIS express 进程,我使用反射器从 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 流中得到任何东西时抛出异常