2010-09-27 69 views
3

如何打开浏览器网站URL没有Process.start(...)的:开放的网站没有的Process.Start

System.Diagnostics.Process.Start(@"http://www.google.com"); 

我不能在Windows服务使用Process.Start(),我不是没有知道为什么。

+3

有什么理由限制? – 2010-09-27 10:00:34

+12

_exactly_对你想要达到的目标的描述,而不是告诉我们你为什么不想要的东西也会有所帮助。 – Oded 2010-09-27 10:02:54

回答

11

看到问题的答案“How can a Windows service execute a GUI application?”:

使用WTSEnumerateSessions找到合适的桌面,然后CreateProcessAsUser启动该应用程序,桌面

注也认为你不应该“T做到这一点:)

如果你正在做的是推出一个URL,该命令可能是

cmd.exe /c start http://example.com/

如果要抑制短暂显示的命令提示符窗口,你可以在STARTUPINFO structurewShowWindow字段设置为SW_HIDE,或在.NET中ProcessStartInfo.WindowStyle属性设置为ProcessWindowStyle.Hidden

+0

好的答案Hugh – 2011-11-10 09:04:37

11

服务在隔离的会话中运行。该会话拥有自己的桌面,与登录屏幕非常相似。然而,用户永远无法看到它。这是一项非常基本的安全措施,服务通常使用非常特权的帐户运行。你可以使用Process.Start(),用户永远不会看到程序的UI。

这不是一个真正的问题,在服务中启动浏览器是毫无意义的。

+0

没错,除了在服务上启动浏览器没有意义的部分,在某些情况下,它可以是有意义的,例如测试网站的特定行为。但是,您不能期望看到浏览器打开。 – 2010-10-05 17:03:12

+0

@Gabriel:在这种情况下,您不需要浏览器 - 只需从网站获取信息。 – 2010-10-06 16:47:51

+0

@Reed Copsey,但是如果您需要自动测试浏览器上网站的功能行为。你应该用浏览器进行测试。 – 2010-10-07 14:13:43

-2

您可以尝试使用“与桌面互动”设置来运行您的服务。这应该可以解决您的问题,但可能会导致其他问题,例如当有人退出主控制台时,您的服务将停止。

+5

“与桌面交互”不支持从Vista开始,因此建议不要使用它。 – Giorgi 2010-10-06 08:47:51

+0

猜猜我没有看到他们正在运行Vista。哦,等等,它不是在说问题。 – Mike 2010-10-13 18:27:32

3

服务不能使用桌面运行,所以我不建议尝试打开浏览器。

如果您只是需要相关网站的信息,为了下载和解析信息,您可能需要考虑使用WebClient而不是浏览器。这将允许您从任何Uri下载,并在服务中解析结果。

1

Windows 7上的服务无法以任何方式与桌面进行交互。

因此,您需要的是一个小的进程,它将使用某种与服务通信的方法,为登录的用户启动并等待服务消息。您可以通过启动组或其他任何方式启动它,只需将其设置得非常小且不明显即可。当然,如果你想让它注意到,你可以使用托盘图标,甚至一些状态窗口。

服务消息可能与在服务和用户进程之间共享的目录中使用URL编写文件一样简单。这样你就可以得到你所需要的并且与大多数Windows版本保持兼容。

+0

它有许多方法可以在当前登录的用户的上下文中创建一个进程。看到我的回答 – Vinzenz 2010-10-12 14:10:36

+0

也许你就会知道如何从服务中访问waveIn/waveOut设备。同样的方案是否足够? – 2010-10-12 14:55:42

-1

如果你有兴趣在响应尝试:

string url = @"http://www.google.com"; 
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 
response = (HttpWebResponse)request.GetResponse(); 
Stream receiveStream = response.GetResponseStream(); 
StreamReader reader = new StreamReader(receiveStream); 
+0

他想在用户的默认浏览器中打开它 – Vinzenz 2010-10-12 14:10:10

-1

为什么不尝试模拟启动使用System.Diagnostics程序的Web浏览器谁也只对特定的代码登录的机器上的privilages用户.Process.Start。
一旦网页加载完成,您打算如何处理浏览器?

+0

不需要看我的示例。 – Vinzenz 2010-10-12 14:09:42

0

固定代码从这里:http://18and5.blogspot.com/2008/01/i-hope-my-frustration-can-help-someone.html 我不得不修复下面的例子将实际工作的参数处理。

using System; 
using System.Reflection; 
using System.Security.Principal; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 


namespace Common.Utilities.Processes 
{ 
    public class ProcessUtilities 
    { 
     /*** Imports ***/ 
     #region Imports 

     [DllImport("advapi32.dll", EntryPoint = "AdjustTokenPrivileges", SetLastError = true)] 
     public static extern bool AdjustTokenPrivileges(IntPtr in_hToken, [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, UInt32 BufferLength, IntPtr PreviousState, IntPtr ReturnLength); 

     [DllImport("advapi32.dll", EntryPoint = "OpenProcessToken", SetLastError = true)] 
     public static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); 

     [DllImport("advapi32.dll", EntryPoint = "LookupPrivilegeValue", SetLastError = true, CharSet = CharSet.Auto)] 
     public static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, out LUID lpLuid); 

     [DllImport("userenv.dll", EntryPoint = "CreateEnvironmentBlock", SetLastError = true)] 
     public static extern bool CreateEnvironmentBlock(out IntPtr out_ptrEnvironmentBlock, IntPtr in_ptrTokenHandle, bool in_bInheritProcessEnvironment); 

     [DllImport("kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true)] 
     public static extern bool CloseHandle(IntPtr handle); 

     [DllImport("wtsapi32.dll", EntryPoint = "WTSQueryUserToken", SetLastError = true)] 
     public static extern bool WTSQueryUserToken(UInt32 in_nSessionID, out IntPtr out_ptrTokenHandle); 

     [DllImport("kernel32.dll", EntryPoint = "WTSGetActiveConsoleSessionId", SetLastError = true)] 
     public static extern uint WTSGetActiveConsoleSessionId(); 

     [DllImport("Wtsapi32.dll", EntryPoint = "WTSQuerySessionInformation", SetLastError = true)] 
     public static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned); 

     [DllImport("wtsapi32.dll", EntryPoint = "WTSFreeMemory", SetLastError = false)] 
     public static extern void WTSFreeMemory(IntPtr memory); 

     [DllImport("userenv.dll", EntryPoint = "LoadUserProfile", SetLastError = true)] 
     public static extern bool LoadUserProfile(IntPtr hToken, ref PROFILEINFO lpProfileInfo); 

     [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Auto)] 
     public static extern bool CreateProcessAsUser(IntPtr in_ptrUserTokenHandle, string in_strApplicationName, string in_strCommandLine, ref SECURITY_ATTRIBUTES in_oProcessAttributes, ref SECURITY_ATTRIBUTES in_oThreadAttributes, bool in_bInheritHandles, CreationFlags in_eCreationFlags, IntPtr in_ptrEnvironmentBlock, string in_strCurrentDirectory, ref STARTUPINFO in_oStartupInfo, ref PROCESS_INFORMATION in_oProcessInformation); 

     #endregion //Imports 

     /*** Delegates ***/ 

     /*** Structs ***/ 
     #region Structs 

     [StructLayout(LayoutKind.Sequential)] 
     public struct LUID 
     { 
      public uint m_nLowPart; 
      public uint m_nHighPart; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct TOKEN_PRIVILEGES 
     { 
      public int m_nPrivilegeCount; 
      public LUID m_oLUID; 
      public int m_nAttributes; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct PROFILEINFO 
     { 
      public int dwSize; 
      public int dwFlags; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public String lpUserName; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public String lpProfilePath; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public String lpDefaultPath; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public String lpServerName; 
      [MarshalAs(UnmanagedType.LPTStr)] 
      public String lpPolicyPath; 
      public IntPtr hProfile; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct STARTUPINFO 
     { 
      public Int32 cb; 
      public string lpReserved; 
      public string lpDesktop; 
      public string lpTitle; 
      public Int32 dwX; 
      public Int32 dwY; 
      public Int32 dwXSize; 
      public Int32 dwXCountChars; 
      public Int32 dwYCountChars; 
      public Int32 dwFillAttribute; 
      public Int32 dwFlags; 
      public Int16 wShowWindow; 
      public Int16 cbReserved2; 
      public IntPtr lpReserved2; 
      public IntPtr hStdInput; 
      public IntPtr hStdOutput; 
      public IntPtr hStdError; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct PROCESS_INFORMATION 
     { 
      public IntPtr hProcess; 
      public IntPtr hThread; 
      public Int32 dwProcessID; 
      public Int32 dwThreadID; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct SECURITY_ATTRIBUTES 
     { 
      public Int32 Length; 
      public IntPtr lpSecurityDescriptor; 
      public bool bInheritHandle; 
     } 

     #endregion //Structs 

     /*** Classes ***/ 

     /*** Enums ***/ 
     #region Enums 

     public enum CreationFlags 
     { 
      CREATE_SUSPENDED = 0x00000004, 
      CREATE_NEW_CONSOLE = 0x00000010, 
      CREATE_NEW_PROCESS_GROUP = 0x00000200, 
      CREATE_UNICODE_ENVIRONMENT = 0x00000400, 
      CREATE_SEPARATE_WOW_VDM = 0x00000800, 
      CREATE_DEFAULT_ERROR_MODE = 0x04000000, 
     } 

     public enum WTS_INFO_CLASS 
     { 
      WTSInitialProgram, 
      WTSApplicationName, 
      WTSWorkingDirectory, 
      WTSOEMId, 
      WTSSessionId, 
      WTSUserName, 
      WTSWinStationName, 
      WTSDomainName, 
      WTSConnectState, 
      WTSClientBuildNumber, 
      WTSClientName, 
      WTSClientDirectory, 
      WTSClientProductId, 
      WTSClientHardwareId, 
      WTSClientAddress, 
      WTSClientDisplay, 
      WTSClientProtocolType 
     } 

     #endregion //Enums 

     /*** Defines ***/ 
     #region Defines 

     private const int TOKEN_QUERY = 0x08; 
     private const int TOKEN_ADJUST_PRIVILEGES = 0x20; 
     private const int SE_PRIVILEGE_ENABLED = 0x02; 

     public const int ERROR_NO_TOKEN = 1008; 
     public const int RPC_S_INVALID_BINDING = 1702; 

     #endregion //Defines 

     /*** Methods ***/ 
     #region Methods 

     /* 
      If you need to give yourself permissions to inspect processes for their modules, 
      and create tokens without worrying about what account you're running under, 
      this is the method for you :) (such as the token privilege "SeDebugPrivilege") 
     */ 
     static public bool AdjustProcessTokenPrivileges(IntPtr in_ptrProcessHandle, string in_strTokenToEnable) 
     { 
      IntPtr l_hProcess = IntPtr.Zero; 
      IntPtr l_hToken = IntPtr.Zero; 
      LUID l_oRestoreLUID; 
      TOKEN_PRIVILEGES l_oTokenPrivileges; 

      Debug.Assert(in_ptrProcessHandle != IntPtr.Zero); 

      //Get the process security token 
      if (false == OpenProcessToken(in_ptrProcessHandle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out l_hToken)) 
      { 
       return false; 
      } 

      //Lookup the LUID for the privilege we need 
      if (false == LookupPrivilegeValue(String.Empty, in_strTokenToEnable, out l_oRestoreLUID)) 
      { 
       return false; 
      } 

      //Adjust the privileges of the current process to include the new privilege 
      l_oTokenPrivileges.m_nPrivilegeCount = 1; 
      l_oTokenPrivileges.m_oLUID = l_oRestoreLUID; 
      l_oTokenPrivileges.m_nAttributes = SE_PRIVILEGE_ENABLED; 

      if (false == AdjustTokenPrivileges(l_hToken, false, ref l_oTokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero)) 
      { 
       return false; 
      } 

      return true; 
     } 

     /* 
      Start a process the simplest way you can imagine 
     */ 
     static public int SimpleProcessStart(string in_strTarget, string in_strArguments) 
     { 
      Process l_oProcess = new Process(); 
      Debug.Assert(l_oProcess != null); 

      l_oProcess.StartInfo.FileName = in_strTarget; 
      l_oProcess.StartInfo.Arguments = in_strArguments; 

      if (true == l_oProcess.Start()) 
      { 
       return l_oProcess.Id; 
      } 

      return -1; 
     } 

     /* 
      All the magic is in the call to WTSQueryUserToken, it saves you changing DACLs, 
      process tokens, pulling the SID, manipulating the Windows Station and Desktop 
      (and its DACLs) - if you don't know what those things are, you're lucky and should 
      be on your knees thanking God at this moment. 

      DEV NOTE: This method currently ASSumes that it should impersonate the user 
           who is logged into session 1 (if more than one user is logged in, each 
           user will have a session of their own which means that if user switching 
           is going on, this method could start a process whose UI shows up in 
           the session of the user who is not actually using the machine at this 
           moment.) 

      DEV NOTE 2: If the process being started is a binary which decides, based upon 
           the user whose session it is being created in, to relaunch with a 
           different integrity level (such as Internet Explorer), the process 
           id will change immediately and the Process Manager will think 
           that the process has died (because in actuality the process it 
           launched DID in fact die only that it was due to self-termination) 
           This means beware of using this service to startup such applications 
           although it can connect to them to alarm in case of failure, just 
           make sure you don't configure it to restart it or you'll get non 
           stop process creation ;) 
     */ 
     static public int CreateUIProcessForServiceRunningAsLocalSystem(string in_strTarget, string in_strArguments) 
     { 
      PROCESS_INFORMATION l_oProcessInformation = new PROCESS_INFORMATION(); 
      SECURITY_ATTRIBUTES l_oSecurityAttributes = new SECURITY_ATTRIBUTES(); 
      STARTUPINFO l_oStartupInfo = new STARTUPINFO(); 
      PROFILEINFO l_oProfileInfo = new PROFILEINFO(); 
      IntPtr l_ptrUserToken = new IntPtr(0); 
      uint l_nActiveUserSessionId = 0xFFFFFFFF; 
      string l_strActiveUserName = ""; 
      int l_nProcessID = -1; 
      IntPtr l_ptrBuffer = IntPtr.Zero; 
      uint l_nBytes = 0; 

      try 
      { 
       //The currently active user is running what session? 
       l_nActiveUserSessionId = WTSGetActiveConsoleSessionId(); 

       if (l_nActiveUserSessionId == 0xFFFFFFFF) 
       { 
        throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "The call to WTSGetActiveConsoleSessionId failed, GetLastError returns: " + Marshal.GetLastWin32Error().ToString()); 
       } 

       if (false == WTSQuerySessionInformation(IntPtr.Zero, (int)l_nActiveUserSessionId, WTS_INFO_CLASS.WTSUserName, out l_ptrBuffer, out l_nBytes)) 
       { 
        int l_nLastError = Marshal.GetLastWin32Error(); 

        //On earlier operating systems from Vista, when no one is logged in, you get RPC_S_INVALID_BINDING which is ok, we just won't impersonate 
        if (l_nLastError != RPC_S_INVALID_BINDING) 
        { 
         throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "The call to WTSQuerySessionInformation failed, GetLastError returns: " + Marshal.GetLastWin32Error().ToString()); 
        } 

        //No one logged in so let's just do this the simple way 
        return SimpleProcessStart(in_strTarget, in_strArguments); 
       } 

       l_strActiveUserName = Marshal.PtrToStringAnsi(l_ptrBuffer); 
       WTSFreeMemory(l_ptrBuffer); 

       //We are supposedly running as a service so we're going to be running in session 0 so get a user token from the active user session 
       if (false == WTSQueryUserToken((uint)l_nActiveUserSessionId, out l_ptrUserToken)) 
       { 
        int l_nLastError = Marshal.GetLastWin32Error(); 

        //Remember, sometimes nobody is logged in (especially when we're set to Automatically startup) you should get error code 1008 (no user token available) 
        if (ERROR_NO_TOKEN != l_nLastError) 
        { 
         //Ensure we're running under the local system account 
         WindowsIdentity l_oIdentity = System.Security.Principal.WindowsIdentity.GetCurrent(); 

         if ("NT AUTHORITY\\SYSTEM" != l_oIdentity.Name) 
         { 
          throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "The call to WTSQueryUserToken failed and querying the process' account identity results in an identity which does not match 'NT AUTHORITY\\SYSTEM' but instead returns the name:" + l_oIdentity.Name + " GetLastError returns: " + l_nLastError.ToString()); 
         } 

         throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "The call to WTSQueryUserToken failed, GetLastError returns: " + l_nLastError.ToString()); 
        } 

        //No one logged in so let's just do this the simple way 
        return SimpleProcessStart(in_strTarget, in_strArguments); 
       } 

       //Create an appropriate environment block for this user token (if we have one) 
       IntPtr l_ptrEnvironment = IntPtr.Zero; 

       Debug.Assert(l_ptrUserToken != IntPtr.Zero); 

       if (false == CreateEnvironmentBlock(out l_ptrEnvironment, l_ptrUserToken, false)) 
       { 
        throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "The call to CreateEnvironmentBlock failed, GetLastError returns: " + Marshal.GetLastWin32Error().ToString()); 
       } 

       l_oSecurityAttributes.Length = Marshal.SizeOf(l_oSecurityAttributes); 
       l_oStartupInfo.cb = Marshal.SizeOf(l_oStartupInfo); 

       //DO NOT set this to "winsta0\\default" (even though many online resources say to do so) 
       l_oStartupInfo.lpDesktop = String.Empty; 
       l_oProfileInfo.dwSize = Marshal.SizeOf(l_oProfileInfo); 
       l_oProfileInfo.lpUserName = l_strActiveUserName; 

       //Remember, sometimes nobody is logged in (especially when we're set to Automatically startup) 
       if (false == LoadUserProfile(l_ptrUserToken, ref l_oProfileInfo)) 
       { 
        throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "The call to LoadUserProfile failed, GetLastError returns: " + Marshal.GetLastWin32Error().ToString()); 
       } 

       if (false == CreateProcessAsUser(l_ptrUserToken, in_strTarget, in_strTarget + " " + in_strArguments, ref l_oSecurityAttributes, ref l_oSecurityAttributes, false, CreationFlags.CREATE_UNICODE_ENVIRONMENT, l_ptrEnvironment, null, ref l_oStartupInfo, ref l_oProcessInformation)) 
       { 
        //System.Diagnostics.EventLog.WriteEntry("CreateProcessAsUser FAILED", Marshal.GetLastWin32Error().ToString()); 
        throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "The call to CreateProcessAsUser failed, GetLastError returns: " + Marshal.GetLastWin32Error().ToString()); 
       } 

       l_nProcessID = l_oProcessInformation.dwProcessID; 
      } 
      catch (Exception l_oException) 
      { 
       throw new Exception("ProcessUtilities" + "->" + MethodInfo.GetCurrentMethod().Name + "->" + "An unhandled exception was caught spawning the process, the exception was: " + l_oException.Message); 
      } 
      finally 
      { 
       if (l_oProcessInformation.hProcess != IntPtr.Zero) 
       { 
        CloseHandle(l_oProcessInformation.hProcess); 
       } 
       if (l_oProcessInformation.hThread != IntPtr.Zero) 
       { 
        CloseHandle(l_oProcessInformation.hThread); 
       } 
      } 

      return l_nProcessID; 
     } 

     #endregion //Methods 
    } 
} 

这是你必须做的来电:

Common.Utilities.Processes.ProcessUtilities.CreateUIProcessForServiceRunningAsLocalSystem(
      @"C:\Windows\System32\cmd.exe", 
      " /c \"start http://www.google.com\"" 
); 

我测试我自己的系统和它的工作就像一个魅力(Windows 7的64位启用UAC)

不过,我建议创建一个微型存根应用程序,它不会使cmd窗口闪烁。哪些将接受url作为参数。 另外,你不应该像使用例子那样使用cmd.exe的硬编码路径。然而代码工作,剩下的应该是清楚的,我希望:-)

HTH

0

这是一个设计问题,如果一个服务必须与用户交互(为例,服务登录之前开始)。

我通常通过制作一个以用户会话开始的小程序来解决这个问题。如果我必须与服务中的用户进行交互,它将首先查看用户级别程序是否正在运行,如果是,它将向其发送命令。