我希望让用户为当前未注册的文件扩展名选择一个关联应用程序(打开方式)。
目前,我正在使用ShellExecute
告诉API打开文件,并返回ERROR_NO_ASSOCIATION
错误代码。
有没有一种方法可以告诉API应该让用户选择一个新的关联应用程序?
我使用
procedure ShellOpenAs(const AFileName: string; AHandle: HWND);
begin
ShellExecute(AHandle, 'open', PChar('rundll32.exe'), PChar('shell32.dll,OpenAs_RunDLL ' + AFileName), nil, SW_SHOWNORMAL);
end;
编辑(受David评论和https://dev59.com/nGrWa4cB1Zd3GeqP_HOE#13229516的启发):
可以直接调用OpenAs_RunDLL
,而不必使用ShellExecute
和RunDll32
:
procedure OpenAs_RunDLL(hwnd: HWND; hinst: HINST; lpszCmdLine: LPSTR; nCmdShow: Integer); stdcall; external shell32;
procedure ShellOpenAs(AHandle: HWND; const AFileName: string);
begin
OpenAs_RunDLL(AHandle, HInstance, PChar(AFileName), SW_SHOWNORMAL);
end;
在Windows Vista及更高版本中,还存在SHOpenWithDialog。(我认为有趣的是,微软编写了一个与RunDLL兼容的入口点,但直到Vista之前都没有提供常规API函数。)
openas
动词:ShellExecute(AHandle, 'openas', PChar(AFileName), nil, nil, SW_SHOWNORMAL);
- Remy Lebeauopenas
对于 ShellExecute()
和 ShellExecuteEx()
都有效。 - Remy LebeauOpenAs_RunDLL
比调用ShellExecute
更容易。 - David Heffernanpublic const uint SEE_MASK_INVOKEIDLIST = 12;//add this line in your code
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE);
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.nShow = SW_SHOWNORMAL;
sei.lpVerb = "openas";
sei.lpFile = "C:\\yourfile.ext";
sei.lfmask= SEE_MASK_INVOKEIDLIST;//add this line in your code
ShellExecuteEx(&sei);
SEE_MASK_INVOKEIDLIST是一个变量,从系统注册表中获取“Verb”参数。
不要使用明确的动词。例如,使用特定的动词如“打开”是一个大错误:
更加正确的方法是 将动词设为空。系统会自动选择最合适的动词:
换句话说,简单明了。
ShellExecute(0, nil, 'C:\MyFile.StrangeExt', ...);
将显示“打开方式”对话框。
只有在需要执行特定操作时才使用特定动词。例如,“打印”,“浏览”,“runas”。否则 - 只需传递nil。
rundll32.exe shell32.dll,OpenAs_RunDLL "C:\Path\TEXT.TXT"
- David Heffernan