C# 获取文件类型的默认应用程序

C# get default application for file type

我正在使用此代码获取“.txt”等文件类型的默认应用程序。 它工作得很好,但为什么我必须调用同一个方法两次?我唯一发现的是 lenth 是在第一次调用后设置的。但是我真的必须执行函数两次因为我首先需要长度吗?

如果我只执行一次,它就会崩溃。

代码

using System.Runtime.InteropServices;
[DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern uint AssocQueryString(
    AssocF flags, 
    AssocStr str,  
    string pszAssoc, 
    string pszExtra, 
    [Out] StringBuilder pszOut, 
    ref uint pcchOut
); 
[Flags]
public enum AssocF
{
    None = 0,
    Init_NoRemapCLSID = 0x1,
    Init_ByExeName = 0x2,
    Open_ByExeName = 0x2,
    Init_DefaultToStar = 0x4,
    Init_DefaultToFolder = 0x8,
    NoUserSettings = 0x10,
    NoTruncate = 0x20,
    Verify = 0x40,
    RemapRunDll = 0x80,
    NoFixUps = 0x100,
    IgnoreBaseClass = 0x200,
    Init_IgnoreUnknown = 0x400,
    Init_Fixed_ProgId = 0x800,
    Is_Protocol = 0x1000,
    Init_For_File = 0x2000
}
public enum AssocStr
{
    Command = 1,
    Executable,
    FriendlyDocName,
    FriendlyAppName,
    NoOpen,
    ShellNewValue,
    DDECommand,
    DDEIfExec,
    DDEApplication,
    DDETopic,
    InfoTip,
    QuickTip,
    TileInfo,
    ContentType,
    DefaultIcon,
    ShellExtension,
    DropTarget,
    DelegateExecute,
    Supported_Uri_Protocols,
    ProgID,
    AppID,
    AppPublisher,
    AppIconReference,
    Max
}

使用示例:

static string AssocQueryString(AssocStr association, string extension)
    {
        const int S_OK = 0;
        const int S_FALSE = 1;

        uint length = 0;
        uint ret = AssocQueryString(AssocF.None, association, extension, null, null, ref length);
        if (ret != S_FALSE)
        {
            throw new InvalidOperationException("Could not determine associated string");
        }

        var sb = new StringBuilder((int)length); // (length-1) will probably work too as the marshaller adds null termination
        ret = AssocQueryString(AssocF.None, association, extension, null, sb, ref length);
        if (ret != S_OK)
        {
            throw new InvalidOperationException("Could not determine associated string"); 
        }

        return sb.ToString();
    }

A​​ssocQueryString 是一个 WinAPI 函数。这是一种系统级的通用函数,可用于不同类型的应用程序。使用应用程序可能恰好具有非常严格的性能 and/or 内存要求。这就是为什么 WinAPI 函数从不自己进行内存分配(因为内存分配在性能方面可能是一项相对昂贵的任务),它们期望调用者向它们提供所有必需的内存。

在许多情况下(例如 A​​ssocQueryString 功能)在函数执行之前无法知道所需的内存量。这里 API 开发人员 "merged" 将两个函数合二为一:如果您使用 null 而不是输出字符串调用 A​​ssocQueryString,它将计算您需要的字符串长度,否则它将使用您提供的字符串,期望您已经为该字符串分配了足够的内存。

您无需担心函数调用两次。事实上,您调用的是两个略有不同的函数:一个是计算所需的字符串长度,另一个是实际完成这项工作(即在注册表中搜索文件关联)。