Delphi 为什么';t AssocQueryString是否查找与图像扩展相关联的可执行文件?
我使用AssocQueryString来获取与某些扩展相关联的可执行文件。 它适用于扩展名“.pdf”和“.txt”,但我注意到,对于我尝试过的所有图像扩展名(“.bmp”、“.png”、“.jpg”、“.ico”),它都不会返回任何内容 更多信息: 它也适用于图像扩展,但仅当请求与“编辑”而不是“打开”关联的可执行文件时 双击bmp文件会导致使用默认的Windows 10照片查看器打开该文件 更新 目前,我的代码是:Delphi 为什么';t AssocQueryString是否查找与图像扩展相关联的可执行文件?,delphi,winapi,windows-10,file-type,file-association,Delphi,Winapi,Windows 10,File Type,File Association,我使用AssocQueryString来获取与某些扩展相关联的可执行文件。 它适用于扩展名“.pdf”和“.txt”,但我注意到,对于我尝试过的所有图像扩展名(“.bmp”、“.png”、“.jpg”、“.ico”),它都不会返回任何内容 更多信息: 它也适用于图像扩展,但仅当请求与“编辑”而不是“打开”关联的可执行文件时 双击bmp文件会导致使用默认的Windows 10照片查看器打开该文件 更新 目前,我的代码是: var Buffer: array [0..1024] of Char;
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}”。。如何在Win7上看到相同的结果?(dll或可执行文件名)
此外,我注意到,将“.bmp”更改为不存在(如“.abcde”)后,返回类似的结果。。为此,我甚至不知道是否有关联的程序。如注释中所述,您的计算机对图像文件扩展名的注册不是使用应用程序打开文件,而是使用Rundll32调用的DLL 根据文件: ASSOCSTR_可执行文件
来自Shell谓词命令字符串的可执行文件。例如,此字符串作为子项的(默认)值,例如
HKEY\u CLASSES\u ROOT\ApplicationName\shell\Open\command
如果命令使用Rundll.exe,请在IQueryAssociations::GetString的flags参数中设置ASSOCF_REMAPRUNDLL标志以检索目标可执行文件
小心并非所有应用程序关联都有可执行文件。不要假设可执行文件始终存在 根据文件: ASSOCF_REMAPRUNDLL
指示
IQueryAssociations
方法忽略Rundll.exe
并返回有关其目标的信息。通常,IQueryAssociations
方法返回命令字符串中第一个.exe
或.dll
的信息。如果命令使用Rundll.exe
,则设置此标志会告诉方法忽略Rundll.exe
,并返回有关其目标的信息
另外,在调用AssocQueryString()
时,请尝试将pszExtra
参数设置为NULL,而不是特定的动词
另外,请注意AssocQueryString()
最后一个参数的文档:
cchOut[输入,输出]类型:德沃德* 指向一个值的指针,该值在调用函数时设置为pszOut缓冲区中的字符数。当函数成功返回时,该值设置为实际放入缓冲区的字符数 您正在将
BufSize
变量设置为字节计数而不是字符计数。您的代码假设Sizeof(Char)
为1,但只有在Delphi2007及更早版本中才是如此。在Delphi2009及更高版本中,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;
系统上的图像文件会返回什么?@IInspectable:结果为31(SE_ERR_NOASSOC->“指定的文件类型与可执行文件没有关联。”->)。如果将
pszExtra
参数留空(passnil
而不是'open'
),您将看到.bmp扩展名实际上与PhotoViewer.dll关联,而不是一个可执行文件(至少在Win7 64上-我怀疑在Win10上类似)assoc.bmp
从命令提示符显示它是一个Paint.Picture,根据ftype Paint.Picture
它与rundl32 PhotoViewer.dll
@KenWhite关联:我确认在Windows 10上“assoc.bmp”也显示“Paint.Picture”。我尝试将nil作为pszExtra参数传递,但结果仍然是一个空字符串。您想如何处理这些信息?非常感谢您的建议和文档引用。我尝试过你的解决方案,但在这两种情况下,AssocQueryString在我的系统上返回-2147023741。你是对的。也许我误解了一些东西,但您的两个代码示例都设置了ASSOCF\u REMAPRUNDLL标志。如果我双击一个“.bmp”文件,它就会用Windows10照片查看器打开。为什么AssocQueryString仍然返回错误\u NO\u关联?@ExDev:代码在Win7上运行良好,它会按预期返回PhotoViewer.dll
。当我在Win10上运行完全相同的代码时,它失败了。我注意到Win10上的.bmp
没有open
动词(只有edit
和printto
)。正如文档所说,关联不一定有可执行文件。但是,ASSOCSTR\u DELEGATEEXECUTE
适用于Win10上的.bmp
(尽管其谓词没有显式的DELEGATEEXECUTE
值),并且返回的CLSID属于“关联启动执行命令”COM对象,因此,行为上的差异可能与使用IExecuteCommand
vs命令ilne有关。我通过添加当前代码更新了我的问题。它返回“{4ED3A719-CEA8-4BD9-910D-E252F997AFC2}”。代码中有什么错误吗?我的意思是,我能得到与Win7相同的结果吗?('PhotoViewer.dll')@ExDev我仍然想知道:您想对关联信息做什么?
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;