首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >运行ProgId谓词的命令

运行ProgId谓词的命令
EN

Stack Overflow用户
提问于 2012-08-26 14:55:10
回答 2查看 1.7K关注 0票数 2

有没有一种方法可以执行progid谓词的命令,而不必在注册表中挖掘和执行字符串操作?

使用ShObjIdl.idl,我可以运行以下命令来获取默认浏览器的ProgId:

代码语言:javascript
复制
var reg = new ShellObjects.ApplicationAssociationRegistration();

string progID;
reg.QueryCurrentDefault("http", ShellObjects.ASSOCIATIONTYPE.AT_URLPROTOCOL, ShellObjects.ASSOCIATIONLEVEL.AL_EFFECTIVE, out progID);

这给了我"ChromeHTML.FHXQEQDDJYXVQSFWM2SVMV5GNA“。在注册表中,我可以看到这个progid有以下shell/open/命令:

代码语言:javascript
复制
"C:\Users\Paul\AppData\Local\Google\Chrome\Application\chrome.exe" -- "%1"

是否有一个API可以传递给ProgId,以及动词和参数,它会运行它吗?

我走过的一条路是使用ShellExecuteEx:

代码语言:javascript
复制
var shellExecuteInfo = new SHELLEXECUTEINFO();
shellExecuteInfo.cbSize = Marshal.SizeOf(shellExecuteInfo);
shellExecuteInfo.fMask = SEE_MASK_CLASSNAME;
shellExecuteInfo.hwnd = IntPtr.Zero;
shellExecuteInfo.lpVerb = "open";
shellExecuteInfo.lpFile = "google.com";
shellExecuteInfo.nShow = SW_SHOWNORMAL;
shellExecuteInfo.lpClass = "http";

ShellExecuteEx(ref shellExecuteInfo);

但是,由于窗口对lpFile进行检查而导致的“Windows无法找到”错误会失败,因为这与URL无关(from:http://blogs.msdn.com/b/oldnewthing/archive/2010/07/01/10033224.aspx )。

这就是我想出的解决方案:

代码语言:javascript
复制
    private static void Main(string[] args)
    {
        if (!OpenUrlInDefaultBrowser("google.com"))
            Console.WriteLine("An error happened");
    }

    [DllImport("Shlwapi.dll")]
    private static extern int AssocQueryString(ASSOCF flags, ASSOCSTR str, string pszAssoc, string pszExtra, StringBuilder pszOut, ref uint pcchOut);

    private enum ASSOCF
    {
        ASSOCF_NONE = 0x00000000
    }

    private enum ASSOCSTR
    {
        ASSOCSTR_COMMAND = 1
    }

    [DllImport("Shell32.dll", CharSet=CharSet.Auto)]
    private static extern int SHEvaluateSystemCommandTemplate(string pszCmdTemplate, out string ppszApplication, out string ppszCommandLine, out string ppszParameters);

    private static bool OpenUrlInDefaultBrowser(string url)
    {
        string browserProgId;
        if (!GetDefaultBrowserProgId(out browserProgId))
            return false;

        string browserCommandTemplate;
        if (!GetCommandTemplate(browserProgId, out browserCommandTemplate))
            return false;

        string browserExecutable;
        string parameters;
        if (!EvaluateCommandTemplate(browserCommandTemplate, out browserExecutable, out parameters))
            return false;

        parameters = ReplaceSubstitutionParameters(parameters, url);

        try
        {
            Process.Start(browserExecutable, parameters);
        }
        catch (InvalidOperationException) { return false; }
        catch (Win32Exception) { return false; }
        catch (FileNotFoundException) { return false; }

        return true;
    }

    private static bool GetDefaultBrowserProgId(out string defaultBrowserProgId)
    {
        try
        {
            // midl "C:\Program Files (x86)\Windows Kits\8.0\Include\um\ShObjIdl.idl"
            // tlbimp ShObjIdl.tlb
            var applicationAssociationRegistration = new ApplicationAssociationRegistration();
            applicationAssociationRegistration.QueryCurrentDefault("http", ShellObjects.ASSOCIATIONTYPE.AT_URLPROTOCOL, ShellObjects.ASSOCIATIONLEVEL.AL_EFFECTIVE, out defaultBrowserProgId);
        }
        catch (COMException)
        {
            defaultBrowserProgId = null;
            return false;
        }
        return !string.IsNullOrEmpty(defaultBrowserProgId);
    }

    private static bool GetCommandTemplate(string defaultBrowserProgId, out string commandTemplate)
    {
        var commandTemplateBufferSize = 0U;
        AssocQueryString(ASSOCF.ASSOCF_NONE, ASSOCSTR.ASSOCSTR_COMMAND, defaultBrowserProgId, "open", null, ref commandTemplateBufferSize);
        var commandTemplateStringBuilder = new StringBuilder((int)commandTemplateBufferSize);
        var hresult = AssocQueryString(ASSOCF.ASSOCF_NONE, ASSOCSTR.ASSOCSTR_COMMAND, defaultBrowserProgId, "open", commandTemplateStringBuilder, ref commandTemplateBufferSize);
        commandTemplate = commandTemplateStringBuilder.ToString();

        return hresult == 0 && !string.IsNullOrEmpty(commandTemplate);
    }

    private static bool EvaluateCommandTemplate(string commandTemplate, out string application, out string parameters)
    {
        string commandLine;
        var hresult = SHEvaluateSystemCommandTemplate(commandTemplate, out application, out commandLine, out parameters);

        return hresult == 0 && !string.IsNullOrEmpty(application) && !string.IsNullOrEmpty(parameters);
    }

    private static string ReplaceSubstitutionParameters(string parameters, string replacement)
    {
        // Not perfect but good enough for this purpose
        return parameters.Replace("%L", replacement)
                         .Replace("%l", replacement)
                         .Replace("%1", replacement);
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-08-27 02:34:50

显式类不会删除lpFile引用有效资源(文件或URL)的要求。类指定如何执行资源(而不是从文件类型或URL协议推断类),但您仍然必须传递有效的资源。google.com被视为一个文件名,因为它不是一个URL,并且该文件不存在,因此您将得到"not“错误。

通常情况下,您要做的事情比提取命令行要复杂得多,因为大多数浏览器使用DDE而不是命令行作为它们的主要调用。(当DDE失败时,命令行是回退。)

但是,如果确实希望执行命令行,可以使用AssocQueryString获取ASSOCSTR_COMMAND,然后通过SHEvaluateSystemCommandTemplate执行插入以使命令行执行。

票数 2
EN

Stack Overflow用户

发布于 2012-08-26 18:44:55

这里的基本错误是您从http://中忽略了FileName。加上这些,一切都会好起来的。

代码语言:javascript
复制
shellExecuteInfo.lpFile = "http://google.com";

您根本不需要设置lpClasslpFilehttp://开头这一事实决定了这个类。

与其自己打电话给ShellExecuteEx,不如让Process为您做这件事:

代码语言:javascript
复制
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = @"http://google.com";
psi.UseShellExecute = true;
Process.Start(psi);

甚至:

代码语言:javascript
复制
Process.Start(@"http://google.com");
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12131100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档