使用隐藏的WindowStyle启动Process.Start url

时间:2016-05-01 01:57:08

标签: c# url process styles webclient

我有一个在服务器上验证我的凭据的URL。有没有办法让它看不见?简单的代码看起来完全像这样:

public void DoAuth()
    {
        String uri = GetUri();
        ProcessStartInfo startInfo = new ProcessStartInfo(uri);
        startInfo.WindowStyle = ProcessWindowStyle.Hidden;
        Process.Start(startInfo);

    }

然而ProcessWindowStyle.Hidden似乎没有做到这一点。如果我将UseShellExecute设置为false,那么我会收到Win32Exception消息The system cannot find the file specified 该网址是Spotify服务器上的身份验证,用于获取播放列表,它看起来像这样https://accounts.spotify.com/authorize/client_id=26d287105as12315e12ds56e31491889f3cd293..

还有其他方法可以让这个过程不可见吗?

编辑:http示例

public void DoAuth()
    {
        String uri = GetUri();

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        HttpWebResponse webResponse;
        try
        {
            webResponse = (HttpWebResponse)request.GetResponse();
            Console.WriteLine("Error code: {0}", webResponse.StatusCode);
            using (Stream data = webResponse.GetResponseStream())
            using (var reader = new StreamReader(data))
            {
                //do what here?
            }
        }
        catch (Exception e)
        {
            throw;
        }
    }

包含上述示例的整个.cs文件:

using SpotifyAPI.Web.Enums;
using SpotifyAPI.Web.Models;
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;

namespace SpotifyAPI.Web.Auth
{
    public class ImplicitGrantAuth
    {
        public delegate void OnResponseReceived(Token token, String state);

        private SimpleHttpServer _httpServer;
        private Thread _httpThread;
        public String ClientId { get; set; }
        public String RedirectUri { get; set; }
        public String State { get; set; }
        public Scope Scope { get; set; }
        public Boolean ShowDialog { get; set; }

        public event OnResponseReceived OnResponseReceivedEvent;

        /// <summary>
        ///     Start the auth process (Make sure the internal HTTP-Server ist started)
        /// </summary>
        public void DoAuth()
        {
            String uri = GetUri();

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            HttpWebResponse webResponse;
            try
            {
                webResponse = (HttpWebResponse)request.GetResponse();
                Console.WriteLine("Error code: {0}", webResponse.StatusCode);
                using (Stream data = webResponse.GetResponseStream())
                using (var reader = new StreamReader(data))
                {
                    //nothing
                }
            }
            catch (Exception e)
            {
                throw;
            }


            /*ProcessStartInfo startInfo = new ProcessStartInfo(uri);
            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
            Process.Start(startInfo);
            */
        }

        private String GetUri()
        {
            StringBuilder builder = new StringBuilder("https://accounts.spotify.com/authorize/?");
            builder.Append("client_id=" + ClientId);
            builder.Append("&response_type=token");
            builder.Append("&redirect_uri=" + RedirectUri);
            builder.Append("&state=" + State);
            builder.Append("&scope=" + Scope.GetStringAttribute(" "));
            builder.Append("&show_dialog=" + ShowDialog);
            return builder.ToString();
        }

        /// <summary>
        ///     Start the internal HTTP-Server
        /// </summary>
        public void StartHttpServer(int port = 80)
        {
            _httpServer = new SimpleHttpServer(port, AuthType.Implicit);
            _httpServer.OnAuth += HttpServerOnOnAuth;

            _httpThread = new Thread(_httpServer.Listen);
            _httpThread.Start();
        }

        private void HttpServerOnOnAuth(AuthEventArgs e)
        {
            OnResponseReceivedEvent?.Invoke(new Token
            {
                AccessToken = e.Code,
                TokenType = e.TokenType,
                ExpiresIn = e.ExpiresIn,
                Error = e.Error
            }, e.State);
        }

        /// <summary>
        ///     This will stop the internal HTTP-Server (Should be called after you got the Token)
        /// </summary>
        public void StopHttpServer()
        {
            _httpServer.Dispose();
            _httpServer = null;
        }
    }
}

他们被这样称呼:

_auth.OnResponseReceivedEvent += _auth_OnResponseReceivedEvent;
_auth.StartHttpServer(8000);
_auth.DoAuth();

带有完整可运行样本的github网址在这里:https://github.com/JohnnyCrazy/SpotifyAPI-NET 下载并运行Spotify测试以连接Spotify的web api以重现我的样本。

4 个答案:

答案 0 :(得分:3)

Windows上的GUI程序的入口点是着名的WinMain() function。它看起来像这样:

  int CALLBACK WinMain(
    _In_ HINSTANCE hInstance,
    _In_ HINSTANCE hPrevInstance,
    _In_ LPSTR     lpCmdLine,
    _In_ int       nCmdShow
  );

hInstance和hPrevInstance参数是遗留的,并且可追溯到Windows版本&lt; = 3,尚未支持进程的版本,并且需要应用程序来处理任务本身的多个实例。 lpCmdLine参数是命令行参数。

nCmdShow是您的重要问题和主题。预期值为SW_HIDE,SW_SHOWNORMAL,SW_SHOWMAXIMIZE或SW_SHOWMINIMIZE。您可以轻松地将它们映射到可能的ProcessWindowStyle枚举值。

它也会在桌面上的快捷方式属性中公开。例如:

enter image description here

我展开了Run组合框,注意与ProcessWindowStyle枚举值的匹配。除Hidden之外,还有一些麻烦。

典型的C程序将nCmdShow参数直接传递给ShowWindow()函数以显示主窗口(省略错误检查):

   HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   ShowWindow(hWnd, nCmdShow);

你会对这样的节目感到满意。然而,这并不是许多程序实际工作的方式。他们检查 nCmdShow的值并明确过滤掉SW_HIDDEN。或者他们恢复用户上次使用的窗口状态。换句话说,他们这样做:

   HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   if (nCmdShow == SW_HIDDEN) nCmdShow = SW_SHOWNORMAL;
   if (HasPreviousWindowState) nCmdShow = PreviousWindowState;   // optional
   ShowWindow(hWnd, nCmdShow);

这是有充分理由的。恢复以前的状态是一个明显的可用性偏好,许多用户会更喜欢它以这种方式为浏览器工作。我做。

更多关于快捷方式配置对话框中缺少的Hidden选项,操作系统和精心设计的GUI程序都有意避免产生可用性噩梦。程序启动的地方,但用户无法激活程序。隐藏窗口没有任务栏按钮。 Alt + Tab不起作用。用户重新获得对程序的控制权的唯一方法是使用任务管理器终止它。它也是可利用的,恶意软件可以启动程序并征用它并且用户从不会注意到它。

这样一个程序阻止这种情况发生的所有正当理由。没有什么可以做的,程序会覆盖你的选择并对此有最后的发言权。

答案 1 :(得分:2)

进入Visual Studio中的项目属性,并将项目类型更改为类库。保存。然后将其更改为Windows应用程序并保存。

这应该摆脱你没有明确创建的任何UI。

答案 2 :(得分:2)

我认为你不需要开始一个新程序来获得Spoitfy的授权。您应该进行Get / Post调用并获取授权令牌,然后将其包含在未来的API调用中。

GET https://accounts.spotify.com/authorize

我指的是Spoitfy的在线帮助页面。

https://developer.spotify.com/web-api/authorization-guide/

答案 3 :(得分:1)

经典XY问题,您没有在寻找隐藏窗口的方法,you want to authenticate a user without user-actions involved

由于requestArray无法使用简单的HTTP请求,因此您需要一种解决方法:

无需用户操作进行身份验证:无头浏览器

虽然ImplicitGrantAuth没有为此类任务制作,但它仍然可行但不干净。您需要一个无头浏览器,您可以在C#应用中控制它,例如Selenium

使用Selenium(related SO Question)考虑以下代码:

ImplicitGrantAuth

这只是伪正确的代码,但你应该明白这个想法。使用您可以控制的无头浏览器,填写所有表单输入,提交和分析URL。 Facebook登录将是相同的原则。

但请注意: OAuth并非专为此类用途而设计,您可能不应在生产中使用此类hacky变通方法