【问题标题】:Process.Start a file without ExtensionProcess.Start 一个没有扩展名的文件
【发布时间】:2018-05-25 12:19:26
【问题描述】:

我们已经知道System.Diagnostics.Process.Start("C:\filename.png") 的工作原理,但是如果文件名不以扩展名结尾怎么办?

如何使用与 .png 扩展名等关联的默认程序运行不带扩展名的文件名?

类似:

openFile("C:\filename","PNG")

【问题讨论】:

  • 你怎么知道没有扩展名的文件是什么类型?一种选择是读取第一组字节并从那里开始......
  • 我碰巧知道文件类型。我只需要知道与“已知”文件类型关联的默认程序,并使用给定的文件名运行该程序。
  • 默认情况下,它应该使用与文件关联的默认程序运行。
  • @Amin Vanda 如果您想要系统关联(扩展至 Opener),请查看 Shlwapi.dll (ShellApi) -> AssocQueryString() 函数。使用 SHGetFileInfo() 反转它 -> 可执行到已注册的扩展。
  • Process.Start 的工作方式与控制台窗口基本相同。无法执行没有扩展名的数据文件并通过控制台窗口在应用程序中自动打开它,因此也无法使用Process.Start 完成。在控制台窗口中,您可以知道文件是什么类型,找出与之关联的应用程序,并使用数据文件的路径作为命令行参数来执行该应用程序。 Process.Start 也是如此。

标签: .net vb.net file registry system.diagnostics


【解决方案1】:

您当然可以将文件名和扩展名拼凑在一起,并希望获得最好的结果。
或者测试文件扩展名是否具有预定义的打开程序,即注册表中的一个条目,它将扩展名与可以处理该文件格式的应用程序相关联。

系统提供了一个 API - AssocQueryString - 提供此信息(当然,您也可以手动查找注册表,但情况可能会发生变化,API 函数已经知道它)。 它也可以用于其他一些任务。

查看声明部分以查找 VB.Net 函数调用和相关的枚举器。

此辅助方法只允许调用 API 函数,而无需指定特殊标志。您只需定义要检索的信息类型。
例如:

AssociationQuery.Executable
返回与指定扩展关联的可执行文件的完整路径。

AssociationQuery.Command
返回Rundll32 命令,当文件扩展名不直接与独立可执行文件关联,而是与 dll 或系统小程序关联时,Shell 执行该命令。 或者返回与 Shell 动词相关的命令(打开、打印、编辑、新建等)。

AssociationQuery.FriendlyDocName
返回关联文件类型的友好名称。例如,.docx 扩展将返回 Microsoft Word 文档(取决于本地语言)。

AssociationQuery.FriendlyAppName
返回关联应用程序的友好名称。例如,.docx 扩展将返回 Word 2016(取决于本地语言)。

有关这些开关的更多信息以及声明部分中其他可用开关的描述,请参见下面的示例。


helper 方法(如下所述调用此方法):

Public Function FileExtentionInfo(AssociationType As AssociationQuery, Extension As String) As String
    If (Extension.Length <= 1) OrElse Not Extension.StartsWith(".") Then
        Return String.Empty
    Else
        Dim flags As AssocFlags = AssocFlags.NoTruncate Or AssocFlags.RemapRunDll
        Return ShellExtensionInfo(True, AssociationType, flags, Extension)
    End If
End Function

worker方法

Private Function ShellExtensionInfo(Verify As Boolean, AssociationType As AssociationQuery, flags As AssocFlags, Extension As String) As String
    Dim pcchOut As UInteger = 0
    flags = flags Or (If(Verify, AssocFlags.Verify, AssocFlags.IgnoreUnknown))
    AssocQueryString(flags, AssociationType, Extension, Nothing, Nothing, pcchOut)

    If pcchOut = 0 Then
        Return String.Empty
    Else
        Dim pszOut As New StringBuilder(CType(pcchOut, Integer))
        AssocQueryString(flags, AssociationType, Extension, Nothing, pszOut, pcchOut)
        Return pszOut.ToString()
    End If
End Function

要得到结果,只需调用辅助函数,询问你想要什么样的信息或关联(AssociationQuery)。

例如这个调用:

Dim Executable As String = FileExtentionInfo(AssociationQuery.Executable, ".docx")

可以返回(取决于安装的软件和用户选择):

C:\Program Files\Microsoft Office\Office16\WINWORD.EXE

如前所述,并非所有扩展都有关联的可执行文件。某些文件扩展名可能会映射到由Rundll32.exe 启动的系统小程序/工具。

在这种情况下,使用AssociationQuery.Executable 作为参数可能不会返回可行的结果。
例如,如果未安装图像编辑软件,则在可执行文件中查询 .jpg.png 扩展可能会返回:

C:\Program Files (x86)\Windows Photo Viewer\PhotoViewer.dll

在这种情况下,使用AssociationQuery.Command作为参数来获取关联的命令行,然后可以将其传递给Process.Start()
因此,在同样的情况下,结果将是:

C:\Windows\System32\rundll32.exe "C:\Program Files (x86)\Windows Photo Viewer\PhotoViewer.dll", ImageView_Fullscreen %1

其中%1 表示要打开的文件的名称。
在分配给ProcessStartInfo.Arguments 属性之前,此参数必须替换为文件路径。

使用与可执行文件关联的文件扩展名(此处为 MS Word 的 .docx 扩展名)和与 DLL 组件关联的文件扩展名(.png 扩展名,通常与如果用户或程序安装没有关联其他查看器/编辑器,则为预定义的系统小程序)。

如示例中所示,文件名不需要指定 扩展名:关联程序可以识别和解码文件 任何情况下的内容(即扩展名没有定义文件格式):

Dim FileName = "C:\Files\Docs\SomeDoc"
'Dim FileName = "C:\Files\Images\SomeImage"

Dim execProgram As String = FileExtentionInfo(AssociationQuery.Executable, "docx")
'Dim execProgram As String = FileExtentionInfo(AssociationQuery.Executable, "png")

Dim execExtension = Path.GetExtension(execProgram).ToLower()

Dim pInfo As ProcessStartInfo = New ProcessStartInfo()
If execExtension.Contains("exe") Then
    pInfo.FileName = execProgram
    pInfo.Arguments = FileName
Else
    Dim rundllCmd As String = FileExtentionInfo(AssociationQuery.Command, "png")
    Dim rundllParts = rundllCmd.Split({ChrW(32) + ChrW(34)}, StringSplitOptions.None)
    pInfo.FileName = rundllParts(0)
    pInfo.Arguments = ChrW(34) & rundllParts(1).Replace("%1", FileName)
End If

pInfo.UseShellExecute = False
Process.Start(pInfo)

声明

VB.Net DllImportAssocQueryString()。见 MSDN AssocQueryString function

<DllImport("Shlwapi.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
Public Shared Function AssocQueryString(flags As AssocFlags, str As AssociationQuery, 
                       pszAssoc As String, pszExtra As String, <Out> pszOut As System.Text.StringBuilder, 
                       <[In]> <Out> ByRef pcchOut As UInteger) As UInteger
End Function

及其枚举:参见 MSDN ASSOCF enumerationASSOCSTR enumeration

<Flags> _
Public Enum AssocFlags
    None = &H0                     'No option selected
    Init_NoRemapCLSID = &H1        'Instructs the interface methods not to map CLSID values to ProgID values.
    Init_ByExeName = &H2           'THe pszAssoc parameter is an executable file name: the root key for search is set to the executable file's ProgID.
    Open_ByExeName = &H2           'Alias for Init_ByExeName
    Init_DefaultToStar = &H4       'If the value is not found under the root key, it should retrieve the comparable value from the * subkey.
    Init_DefaultToFolder = &H8     'If the value is not found under the root key, it should retrieve the comparable value from the Folder subkey.
    NoUserSettings = &H10          'Only the HKEY_CLASSES_ROOT should be searched, HKEY_CURRENT_USER should be ignored.
    NoTruncate = &H20              'The return string should not be truncated. Return an error value and the required size for the complete string.
    Verify = &H40                  'Instructs to verify that data is accurate. This setting allows to read data from the user's hard disk for verification.
    RemapRunDll = &H80             'Instructs to ignore Rundll.exe and return information about its target.
    NoFixUps = &H100               'Instructs not to fix errors in the registry, such as the friendly name of a function not matching the one found in the .exe file.
    IgnoreBaseClass = &H200        'Specifies that the BaseClass value should be ignored.
    IgnoreUnknown = &H400          'Windows 7:   "Unknown" ProgID should be ignored; instead, fail.
    InitFixedProgid = &H800        'Windows 8:   The supp. ProgID should be mapped using the sys defaults, rather than the current user defaults.
    IsProtocol = &H1000            'Windows 8:   The value is a protocol, should be mapped using the current user defaults.
    InitForFile = &H2000           'Windows 8.1: The ProgID corresponds with a file extension based association. Use together with InitFixedProgid.
End Enum

Public Enum AssociationQuery
    Command = 1,                   'A command string associated with a Shell verb (=> Open, Edit, Print, New).
    Executable,                    'An executable from a Shell verb command string. Not all associations have executables.
    FriendlyDocName,               'The friendly name of a document type.    (Microsoft Office 2016 Document)
    FriendlyAppName,               'The friendly name of an executable file. (Microsoft Office Word)
    NoOpen,                        'Ignore the information associated with the open subkey.
    ShellNewValue,                 'Look under the ShellNew subkey.
    DDECommand,                    'A template for DDE commands.
    DDEIfExec,                     'The DDE command to use to create a process.
    DDEApplication,                'The application name in a DDE broadcast.
    DDETopic,                      'The topic name in a DDE broadcast.
    Infotip,                       'The InfoTip registry value. Returns an info tip for an item from which to create an info tip, such as when hovering the cursor over a file name. 
    Quicktip,                      'Corresponds to the QuickTip registry value. Similar to InfoTip, but more suitable for network transport.
    TileInfo,                      'Corresponds to the TileInfo registry value. Similar to InfoTip, for a file type in a window that is in tile view.
    ContentType,                   'Describes a general type of MIME file association, such as image and bmp, to make general assumptions about a specific file type.
    DefaultIcon,                   'Returns the path to the default icon for this association. Positive numbers: index of the dll's resource table, Negative numbers: resource ID.
    ShellExtension,                'If a Shell extension is associated, use this to get the CLSID of the Shell extension object, passing the string of the IID as the pwszExtra parameter.
    DropTarget,                    'For a verb invoked through COM and the IDropTarget interface, use this flag to get the IDropTarget object's CLSID. The verb is specified in the pwszExtra parameter.
    DelegateExecute,               'For a verb invoked through COM and the IExecuteCommand interface, use this flag to get the IExecuteCommand object's CLSID. This CLSID is registered in the verb's command subkey as the DelegateExecute entry. The verb is specified in the pwszExtra parameter.
    SupportedURIProtocols,         'Windows 8   
    ProgID,                        'The ProgID provided by the app associated with the file type or URI scheme. This if configured by users in their default program settings.
    AppID,                         'The AppUserModelID of the app associated with the file type or URI scheme. This is configured by users in their default program settings.
    AppPublisher,                  'The publisher of the app associated with the file type or URI scheme. This is configured by users in their default program settings.
    AppIconReference,              'The icon reference of the app associated with the file type or URI scheme. This is configured by users in their default program settings.
    Max                            'The maximum defined ASSOCSTR value, used for validation purposes.
End Enum

【讨论】:

    猜你喜欢
    • 2014-02-10
    • 2016-12-24
    • 2012-12-24
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    相关资源
    最近更新 更多