C# 在新的浏览器进程中打开一个 URL

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/742598/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:25:56  来源:igfitidea点击:

Open a URL in a new browser process

c#windowssystemshellexecute

提问by Gordon

I need to open a URL in a new browser process. I need to be notified when that browser process quits. The code I'm currently using is the following:

我需要在新的浏览器进程中打开一个 URL。当浏览器进程退出时,我需要得到通知。我目前使用的代码如下:

        Process browser = new Process();
        browser.EnableRaisingEvents = true;
        browser.StartInfo.Arguments = url;
        browser.StartInfo.FileName = "iexplore";

        browser.Exited += new EventHandler(browser_Exited);

        browser.Start();

Clearly, this won't due because the "FileName" is fixed to iexplore, not the user's default web browser. How do I figure out what the user's default web browser is?

显然,这不会因为“FileName”固定为 iexplore,而不是用户的默认 Web 浏览器。如何确定用户的默认 Web 浏览器是什么?

I'm running on Vista->forward. Though XP would be nice to support if possible.

我在 Vista->forward 上运行。如果可能的话,尽管支持 XP 会很好。

A bit more context: I've created a very small stand-alone web server that serves some files off a local disk. At the end of starting up the server I want to start the browser. Once the user is done and closes the browser I'd like to quit the web server. The above code works perfectly, other than using only IE.

更多的上下文:我创建了一个非常小的独立 Web 服务器,它为本地磁盘上的一些文件提供服务。在启动服务器结束时,我想启动浏览器。一旦用户完成并关闭浏览器,我想退出网络服务器。除了仅使用 IE 之外,上面的代码完美运行。

Thanks in advance!

提前致谢!

采纳答案by Gordon

Ok. I now have working C# code to do what I want. This will return the "command line" you should run to load the current default browser:

好的。我现在有工作 C# 代码来做我想做的事。这将返回您应该运行以加载当前默认浏览器的“命令行”:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;

namespace testDefaultBrowser
{
    public enum ASSOCIATIONLEVEL
    {
        AL_MACHINE,
        AL_EFFECTIVE,
        AL_USER,
    };

    public enum ASSOCIATIONTYPE
    {
        AT_FILEEXTENSION,
        AT_URLPROTOCOL,
        AT_STARTMENUCLIENT,
        AT_MIMETYPE,
    };

    [Guid("4e530b0a-e611-4c77-a3ac-9031d022281b"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IApplicationAssociationRegistration
    {
        void QueryCurrentDefault([In, MarshalAs(UnmanagedType.LPWStr)] string pszQuery,
        [In, MarshalAs(UnmanagedType.I4)] ASSOCIATIONTYPE atQueryType,
        [In, MarshalAs(UnmanagedType.I4)] ASSOCIATIONLEVEL alQueryLevel,
        [Out, MarshalAs(UnmanagedType.LPWStr)] out string ppszAssociation);

        void QueryAppIsDefault(
            [In, MarshalAs(UnmanagedType.LPWStr)] string pszQuery,
            [In] ASSOCIATIONTYPE atQueryType,
            [In] ASSOCIATIONLEVEL alQueryLevel,
            [In, MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName,
            [Out] out bool pfDefault);

        void QueryAppIsDefaultAll(
            [In] ASSOCIATIONLEVEL alQueryLevel,
            [In, MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName,
            [Out] out bool pfDefault);

        void SetAppAsDefault(
            [In, MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName,
            [In, MarshalAs(UnmanagedType.LPWStr)] string pszSet,
            [In] ASSOCIATIONTYPE atSetType);

        void SetAppAsDefaultAll(
            [In, MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName);

        void ClearUserAssociations();
    }

    [ComImport, Guid("591209c7-767b-42b2-9fba-44ee4615f2c7")]//
    class ApplicationAssociationRegistration
    {
    }

    class Program
    {
        static void Main(string[] args)
        {
            IApplicationAssociationRegistration reg = 
                (IApplicationAssociationRegistration) new ApplicationAssociationRegistration();

            string progID;
            reg.QueryCurrentDefault(".txt",
                ASSOCIATIONTYPE.AT_FILEEXTENSION,
                ASSOCIATIONLEVEL.AL_EFFECTIVE,
                out progID);
            Console.WriteLine(progID);

            reg.QueryCurrentDefault("http",
                ASSOCIATIONTYPE.AT_URLPROTOCOL,
                ASSOCIATIONLEVEL.AL_EFFECTIVE,
                out progID);
            Console.WriteLine(progID);
        }
    }
}

Whew! Thanks everyone for help in pushing me towards the right answer!

哇!感谢大家帮助推动我走向正确的答案!

回答by adeel825

The way to determine the default browser is explained in this blog post:

这篇博文中解释了确定默认浏览器的方法:

http://ryanfarley.com/blog/archive/2004/05/16/649.aspx

http://ryanfarley.com/blog/archive/2004/05/16/649.aspx

From the blog post above:

从上面的博客文章:

private string getDefaultBrowser()
{
    string browser = string.Empty;
    RegistryKey key = null;
    try
    {
        key = Registry.ClassesRoot.OpenSubKey(@"HTTP\shell\open\command", false);

        //trim off quotes
        browser = key.GetValue(null).ToString().ToLower().Replace("\"", "");
        if (!browser.EndsWith("exe"))
        {
            //get rid of everything after the ".exe"
            browser = browser.Substring(0, browser.LastIndexOf(".exe")+4);
        }
    }
    finally
    {
        if (key != null) key.Close();
    }
    return browser;
}

回答by Gordon

Ok, I think I might have found it - IApplicationAssociationRegistration::QueryCurrentDefault [1]. According to the docs this is what is used by ShellExecute. I'll post code when I get it to work, but I'd be interested if others think this is the right thing to use (BTW, I'm Vista or greater for OS level).

好的,我想我可能已经找到了 - IApplicationAssociationRegistration::QueryCurrentDefault [1]。根据文档,这是 ShellExecute 使用的内容。当我让它工作时,我会发布代码,但如果其他人认为这是正确的使用方式,我会很感兴趣(顺便说一句,我是 Vista 或更高版本的操作系统)。

[1]: http://msdn.microsoft.com/en-us/library/bb776336(VS.85).aspxQueryCurrentDefault

[1]:http: //msdn.microsoft.com/en-us/library/bb776336(VS.85) .aspxQueryCurrentDefault

回答by Unsliced

If you pass a path of the known file type to the (file) explorer application, it will 'do the right thing', e.g.

如果您将已知文件类型的路径传递给(文件)资源管理器应用程序,它将“做正确的事”,例如

 Process.Start("explorer.exe", @"\path.to\filename.pdf");

and open the file in the PDF reader.

并在 PDF 阅读器中打开文件。

But if you try the same thing with a URL, e.g.

但是如果你用一个 URL 尝试同样的事情,例如

Process.Start("explorer.exe", @"http://www.stackoverflow.com/");

it fires up IE (which isn't the default browser on my machine).

它启动 IE(这不是我机器上的默认浏览器)。

I know doesn't answer the question, but I thought it was an interesting sidenote.

我知道没有回答这个问题,但我认为这是一个有趣的旁注。

回答by Gordon

Ok. Been away on the conference circuit for a week, now getting back to this. I can do this with C++ now - and it even seems to behave properly! My attempts to translate this into C# (or .NET) have all failed however (Post On Question).

好的。离开会议巡回赛一个星期,现在回到这个。我现在可以用 C++ 做到这一点 - 它甚至似乎表现得很好!然而,我将其翻译成 C#(或 .NET)的尝试都失败了(发布问题)。

Here is the C++ code for others that stumble on this question:

这是其他人偶然发现这个问题的 C++ 代码:

#include "stdafx.h"
#include <iostream>
#include <shobjidl.h>
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit

#include <atlbase.h>
#include <atlstr.h>
#include <AtlDef.h>
#include <AtlConv.h>

using namespace std;
using namespace ATL;

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = CoInitialize(NULL);
    if (!SUCCEEDED(hr)) {
        cout << "Failed to init COM instance" << endl;
        cout << hr << endl;
    }

    IApplicationAssociationRegistration *pAAR;
    hr = CoCreateInstance(CLSID_ApplicationAssociationRegistration,
        NULL, CLSCTX_INPROC, __uuidof(IApplicationAssociationRegistration),
        (void**) &pAAR);
    if (!SUCCEEDED(hr))
    {
        cout << "Failed to create COM object" << endl;
        cout << hr << endl;
        return 0;
    }

    LPWSTR progID;
    //wchar_t *ttype = ".txt";
    hr = pAAR->QueryCurrentDefault (L".txt", AT_FILEEXTENSION, AL_EFFECTIVE, &progID);
    if (!SUCCEEDED(hr)) {
        cout << "Failed to query default for .txt" << endl;
        cout << hr << endl;
    }
    CW2A myprogID (progID);
    cout << "Result is: " << static_cast<const char*>(myprogID) << endl;

    /// Now for http

    hr = pAAR->QueryCurrentDefault (L"http", AT_URLPROTOCOL, AL_EFFECTIVE, &progID);
    if (!SUCCEEDED(hr)) {
        cout << "Failed to query default for http" << endl;
        cout << hr << endl;
    }
    CW2A myprogID1 (progID);
    cout << "Result is: " << static_cast<const char*>(myprogID1) << endl;

    return 0;
}

I will post the C# code when I finally get it working!

当我最终让它工作时,我会发布 C# 代码!

回答by bsneeze

Short answer, you can't.

简短的回答,你不能。

If the default browser is, say, Firefox, and the user already has a Firefox instance running, it will just be opened in another window or tab of the same firefox.exe process, and even after they close your page, the process won't exit until they close every window and tab. In this case, you would receive notification of the process exiting as soon as you started it, due to the temporary firefox.exe proc that would marshal the URL to the current process. (Assuming that's how Firefox's single instance management works).

如果默认浏览器是 Firefox,并且用户已经运行了 Firefox 实例,则它只会在同一 firefox.exe 进程的另一个窗口或选项卡中打开,即使他们关闭您的页面,该进程也不会“ t 退出,直到他们关闭每个窗口和选项卡。在这种情况下,由于临时 firefox.exe proc 会将 URL 编组到当前进程,您会在启动它后立即收到进程退出的通知。(假设 Firefox 的单实例管理就是这样工作的)。

回答by Nyerguds

I've written this code for a project once... it keeps in mind any additional parameters set for the default browser. It was originally created to open HTML documentation in a browser, for the simple reason I always set my default program for HTML to an editorrather than a browser, and it annoys me to no end to see some program open its HTML readme in my text editor. Obviously, it works perfectly for URLs too.

我曾经为一个项目编写过这段代码......它记住了为默认浏览器设置的任何其他参数。它最初是为了在浏览器中打开 HTML 文档而创建的,原因很简单,我总是将 HTML 的默认程序设置为编辑器而不是浏览器,并且看到某些程序在我的文本中打开它的 HTML 自述文件让我感到非常恼火编辑。显然,它也适用于 URL。

    /// <summary>
    ///     Opens a local file or url in the default web browser.
    /// </summary>
    /// <param name="path">Path of the local file or url</param>
    public static void openInDefaultBrowser(String pathOrUrl)
    {
        pathOrUrl = "\"" + pathOrUrl.Trim('"') + "\"";
        RegistryKey defBrowserKey = Registry.ClassesRoot.OpenSubKey(@"http\shell\open\command");
        if (defBrowserKey != null && defBrowserKey.ValueCount > 0 && defBrowserKey.GetValue("") != null)
        {
            String defBrowser = (String)defBrowserKey.GetValue("");
            if (defBrowser.Contains("%1"))
            {
                defBrowser = defBrowser.Replace("%1", pathOrUrl);
            }
            else
            {
                defBrowser += " " + pathOrUrl;
            }
            String defBrowserProcess;
            String defBrowserArgs;
            if (defBrowser[0] == '"')
            {
                defBrowserProcess = defBrowser.Substring(0, defBrowser.Substring(1).IndexOf('"') + 2).Trim();
                defBrowserArgs = defBrowser.Substring(defBrowser.Substring(1).IndexOf('"') + 2).TrimStart();
            }
            else
            {
                defBrowserProcess = defBrowser.Substring(0, defBrowser.IndexOf(" ")).Trim();
                defBrowserArgs = defBrowser.Substring(defBrowser.IndexOf(" ")).Trim();
            }
            if (new FileInfo(defBrowserProcess.Trim('"')).Exists)
                Process.Start(defBrowserProcess, defBrowserArgs);
        }
    }