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();
}
AssocQueryString 是一个 WinAPI 函数。这是一种系统级的通用函数,可用于不同类型的应用程序。使用应用程序可能恰好具有非常严格的性能 and/or 内存要求。这就是为什么 WinAPI 函数从不自己进行内存分配(因为内存分配在性能方面可能是一项相对昂贵的任务),它们期望调用者向它们提供所有必需的内存。
在许多情况下(例如 AssocQueryString 功能)在函数执行之前无法知道所需的内存量。这里 API 开发人员 "merged" 将两个函数合二为一:如果您使用 null 而不是输出字符串调用 AssocQueryString,它将计算您需要的字符串长度,否则它将使用您提供的字符串,期望您已经为该字符串分配了足够的内存。
您无需担心函数调用两次。事实上,您调用的是两个略有不同的函数:一个是计算所需的字符串长度,另一个是实际完成这项工作(即在注册表中搜索文件关联)。
我正在使用此代码获取“.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();
}
AssocQueryString 是一个 WinAPI 函数。这是一种系统级的通用函数,可用于不同类型的应用程序。使用应用程序可能恰好具有非常严格的性能 and/or 内存要求。这就是为什么 WinAPI 函数从不自己进行内存分配(因为内存分配在性能方面可能是一项相对昂贵的任务),它们期望调用者向它们提供所有必需的内存。
在许多情况下(例如 AssocQueryString 功能)在函数执行之前无法知道所需的内存量。这里 API 开发人员 "merged" 将两个函数合二为一:如果您使用 null 而不是输出字符串调用 AssocQueryString,它将计算您需要的字符串长度,否则它将使用您提供的字符串,期望您已经为该字符串分配了足够的内存。
您无需担心函数调用两次。事实上,您调用的是两个略有不同的函数:一个是计算所需的字符串长度,另一个是实际完成这项工作(即在注册表中搜索文件关联)。