为啥 AssocQueryString 找不到与图像扩展关联的可执行文件?
Posted
技术标签:
【中文标题】为啥 AssocQueryString 找不到与图像扩展关联的可执行文件?【英文标题】:Why doesn't AssocQueryString find executable associated to image extensions?为什么 AssocQueryString 找不到与图像扩展关联的可执行文件? 【发布时间】:2017-01-15 00:04:33 【问题描述】:我正在使用 AssocQueryString 来获取与某些扩展关联的可执行文件。
它适用于像 .pdf
和 .txt
这样的扩展。但我注意到它不会为我尝试过的所有图像扩展返回任何内容(.bmp
、.png
、.jpg
、.ico
)。
uses
ShLwApi, Windows, Dialogs;
const
// ASSOCF enumerated values mapped to integer constants
ASSOCF_INIT_NOREMAPCLSID = $00000001;
ASSOCF_INIT_BYEXENAME = $00000002;
ASSOCF_OPEN_BYEXENAME = $00000002;
ASSOCF_INIT_DEFAULTTOSTAR = $00000004;
ASSOCF_INIT_DEFAULTTOFOLDER = $00000008;
ASSOCF_NOUSERSETTINGS = $00000010;
ASSOCF_NOTRUNCATE = $00000020;
ASSOCF_VERIFY = $00000040;
ASSOCF_REMAPRUNDLL = $00000080;
ASSOCF_NOFIXUPS = $00000100;
ASSOCF_IGNOREBASECLASS = $00000200;
var
Buffer: array [0..1024] of char;
BufSize: DWord;
begin
BufSize := Sizeof(Buffer);
Buffer[0] := #0;
AssocQueryString(
ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
'open',
Buffer,
@BufSize
);
ShowMessage(Buffer);
end;
更多信息:
它也适用于图像扩展,但前提是要求与“编辑”而不是“打开”关联的可执行文件。
双击 .bmp 文件会使用默认的 Windows 10 照片查看器打开该文件。
更新
目前,我的代码是:
var
Buffer: array [0..1024] of Char;
BufSize: DWord;
Res: HResult;
begin
BufSize := Length(Buffer);
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
(*ASSOCSTR_DELEGATEEXECUTE missing on Delphi 2007*) 18,
'.bmp',
nil,
Buffer,
@BufSize
);
If Res = S_OK then
ShowMessage(Buffer)
else
ShowMessage('Error ' + IntToStr(Res) + sLineBreak + SysErrorMessage(Res));
它显示“4ED3A719-CEA8-4BD9-910D-E252F997AFC2”。如何在 Windows 7 上看到相同的结果? (一个 dll 或一个可执行文件名)
此外,我注意到在将 .bmp
更改为不存在(如 '.abcde')后,会返回类似的结果。为此我什至不知道是否有相关的程序。
【问题讨论】:
FindExecutable 为您系统上的图像文件返回什么? @IInspectable: 结果为 31(SE_ERR_NOASSOC -> “指定文件类型与可执行文件没有关联。” -> msdn.microsoft.com/en-us/library/windows/desktop/…)。 如果您将pszExtra
参数留空(传递nil
而不是'open'
),您将看到.bmp 扩展名实际上与PhotoViewer.dll 相关联,而不是可执行文件(至少在 Win7 64 上 - 我怀疑它在 Win10 上是相似的)。命令提示符下的assoc .bmp
表示这是一个Paint.Picture,根据ftype Paint.Picture
与rundll32 PhotoViewer.dll
相关联。
@KenWhite:我确认“assoc .bmp”在 Windows 10 上也显示“Paint.Picture”。我尝试将 nil 作为 pszExtra 参数传递,但它仍然产生一个空字符串。
你想用这些信息做什么?
【参考方案1】:
如 cmets 中所述,您机器的图像文件扩展名注册不是使用应用程序打开文件,而是使用 Rundll32 调用的 DLL。
根据ASSOCSTR
文档:
ASSOCSTR_EXECUTABLE 来自 Shell 动词命令字符串的可执行文件。例如,此字符串作为子项的(默认)值,例如
HKEY_CLASSES_ROOT\ApplicationName\shell\Open\command
。 如果该命令使用 Rundll.exe,请在 IQueryAssociations::GetString 的 flags 参数中设置 ASSOCF_REMAPRUNDLL 标志以检索目标可执行文件。注意并非所有应用关联都有可执行文件。不要假设可执行文件将始终存在。
根据ASSOCF
文档:
ASSOCF_REMAPRUNDLL 指示
IQueryAssociations
方法忽略Rundll.exe
并返回有关其目标的信息。通常IQueryAssociations
方法返回有关命令字符串中第一个.exe
或.dll
的信息。如果命令使用Rundll.exe
,则设置此标志会告诉方法忽略Rundll.exe
并返回有关其目标的信息。
另外,在调用AssocQueryString()
时,尝试将pszExtra
参数设置为NULL 而不是特定动词。
另外,注意AssocQueryString()
最后一个参数的文档:
cchOut [输入,输出] 类型:双字*
指向一个值的指针,在调用该函数时,该值设置为 pszOut 缓冲区中的字符数。当函数返回成功时,该值被设置为实际放入缓冲区的字符数。
您将BufSize
变量设置为字节数而不是字符数。您的代码假设 Sizeof(Char)
为 1,但这仅在 Delphi 2007 及更早版本中成立。在 Delphi 2009 及更高版本中,Sizeof(Char)
改为 2。
并始终检查返回值是否有错误。
试试这个:
var
Buffer: array [0..1024] of Char;
BufSize: DWord;
Res: HResult;
begin
BufSize := Length(Buffer);
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
nil,
Buffer,
@BufSize
);
If Res = S_OK then
ShowMessage(Buffer)
else
ShowMessage('Error ' + IntToStr(Res));
end;
或者:
var
Buffer: string;
BufSize: DWord;
Res: HResult;
begin
BufSize := 0;
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
nil,
nil,
@BufSize
);
if Res = S_FALSE then
begin
SetLength(Buffer, BufSize-1);
Res := AssocQueryString(
ASSOCF_REMAPRUNDLL or ASSOCF_NOTRUNCATE,
ASSOCSTR_EXECUTABLE,
'.bmp',
nil,
PChar(Buffer),
@BufSize
);
end;
If Res = S_OK then
ShowMessage(Buffer)
else
ShowMessage('Error ' + IntToStr(Res));
end;
【讨论】:
非常感谢您的建议和文档报价。我已经尝试过您的解决方案,但在这两种情况下,AssocQueryString 在我的系统上都返回 -2147023741。 你是对的。也许我误解了一些东西,但是您的两个代码示例都设置了 ASSOCF_REMAPRUNDLL 标志。如果我双击“.bmp”文件,则它会使用 Windows 10 照片查看器打开。为什么 AssocQueryString 仍然返回 ERROR_NO_ASSOCIATION? @ExDev:代码在 Win7 上运行良好,它按预期返回PhotoViewer.dll
。当我在 Win10 上运行完全相同的代码时,它失败了。我注意到 Win10 上的 .bmp
没有 open
动词(只有 edit
和 printto
)。就像文档说的那样,不能保证关联具有可执行文件。但是,ASSOCSTR_DELEGATEEXECUTE
在 Win10 上适用于 .bmp
(尽管它的动词没有明确的 DelegateExecute
值),并且返回的 CLSID 属于“关联启动执行命令”COM 对象,因此行为上的差异可能有与使用 IExecuteCommand
与 command-ilne 有关。
我通过添加我当前的代码更新了我的问题。它返回“4ED3A719-CEA8-4BD9-910D-E252F997AFC2”。代码有问题吗?我的意思是,我能获得在 Win7 上看到的相同结果吗? ('PhotoViewer.dll')
@ExDev 我还想知道:你想对关联信息做什么?以上是关于为啥 AssocQueryString 找不到与图像扩展关联的可执行文件?的主要内容,如果未能解决你的问题,请参考以下文章