简体   繁体   中英

How do I get File Type Information based on extension? (not MIME) in c#

How do I get the general File type description based on extension like Explorer does it? So not MIME but the information that the end-user sees, like.

.doc = Microsoft Office Word 97 - 2003 Document .zip = ZIP File .avi = Video File.

And how can I get the 'secondary' information that seems to be available, which I guess it not extension based. Like on "Video Files" it can give you the 'Length' of the movie or on doc files how many pages it has.. etc etc..

Thanks Dan, Alright.. This answers the first question I had. Sadly not the second. Note: Not everything prints.. Credits to PInvoke.net

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;


namespace WindowsFormsApplication1
{
    static class Program
    {
        [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut);

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Debug.WriteLine(FileExtentionInfo(AssocStr.Command, ".doc"), "Command");
            Debug.WriteLine(FileExtentionInfo(AssocStr.DDEApplication, ".doc"), "DDEApplication");
            Debug.WriteLine(FileExtentionInfo(AssocStr.DDEIfExec, ".doc"), "DDEIfExec");
            Debug.WriteLine(FileExtentionInfo(AssocStr.DDETopic, ".doc"), "DDETopic");
            Debug.WriteLine(FileExtentionInfo(AssocStr.Executable, ".doc"), "Executable");
            Debug.WriteLine(FileExtentionInfo(AssocStr.FriendlyAppName, ".doc"), "FriendlyAppName");
            Debug.WriteLine(FileExtentionInfo(AssocStr.FriendlyDocName, ".doc"), "FriendlyDocName");
            Debug.WriteLine(FileExtentionInfo(AssocStr.NoOpen, ".doc"), "NoOpen");
            Debug.WriteLine(FileExtentionInfo(AssocStr.ShellNewValue, ".doc"), "ShellNewValue");

            //  DDEApplication: WinWord
            //DDEIfExec: Ñﻴ߾
            //  DDETopic: System
            //  Executable: C:\Program Files (x86)\Microsoft Office\Office12\WINWORD.EXE
            //  FriendlyAppName: Microsoft Office Word
            //  FriendlyDocName: Microsoft Office Word 97 - 2003 Document


        }

        public static string FileExtentionInfo(AssocStr assocStr, string doctype)
        {
            uint pcchOut = 0;
            AssocQueryString(AssocF.Verify, assocStr, doctype, null, null, ref pcchOut);

            StringBuilder pszOut = new StringBuilder((int)pcchOut);
            AssocQueryString(AssocF.Verify, assocStr, doctype, null, pszOut, ref pcchOut);
            return pszOut.ToString();
        }

        [Flags]
        public enum AssocF
        {
            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
        }

        public enum AssocStr
        {
            Command = 1,
            Executable,
            FriendlyDocName,
            FriendlyAppName,
            NoOpen,
            ShellNewValue,
            DDECommand,
            DDEIfExec,
            DDEApplication,
            DDETopic
        }

    }
}

My code that include check to prevent from some common errors... Hope it helps :-)

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace HQ.Util.Unmanaged
{
    /// <summary>
    /// Usage:  string executablePath = FileAssociation.GetExecFileAssociatedToExtension(pathExtension, "open");
    /// </summary>
    public static class FileAssociation
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ext"></param>
        /// <param name="verb"></param>
        /// <returns>Return null if not found</returns>
        public static string GetExecFileAssociatedToExtension(string ext, string verb = null)
        {
            if (ext[0] != '.')
            {
                ext = "." + ext;
            }

            string executablePath = FileExtentionInfo(AssocStr.Executable, ext, verb); // Will only work for 'open' verb
            if (string.IsNullOrEmpty(executablePath))
            {
                executablePath = FileExtentionInfo(AssocStr.Command, ext, verb); // required to find command of any other verb than 'open'

                // Extract only the path
                if (!string.IsNullOrEmpty(executablePath) && executablePath.Length > 1) 
                {
                    if (executablePath[0] == '"')
                    {
                        executablePath = executablePath.Split('\"')[1];
                    }
                    else if (executablePath[0] == '\'')
                    {
                        executablePath = executablePath.Split('\'')[1];
                    }
                }
            }

            // Ensure to not return the default OpenWith.exe associated executable in Windows 8 or higher
            if (!string.IsNullOrEmpty(executablePath) && File.Exists(executablePath) &&
                !executablePath.ToLower().EndsWith(".dll"))
            {
                if (executablePath.ToLower().EndsWith("openwith.exe"))
                {
                    return null; // 'OpenWith.exe' is th windows 8 or higher default for unknown extensions. I don't want to have it as associted file
                }
                return executablePath;
            }
            return executablePath;
        }

        [DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut);

        private static string FileExtentionInfo(AssocStr assocStr, string doctype, string verb)
        {
            uint pcchOut = 0;
            AssocQueryString(AssocF.Verify, assocStr, doctype, verb, null, ref pcchOut);

            Debug.Assert(pcchOut != 0);
            if (pcchOut == 0)
            {
                return "";
            }

            StringBuilder pszOut = new StringBuilder((int)pcchOut);
            AssocQueryString(AssocF.Verify, assocStr, doctype, verb, pszOut, ref pcchOut);
            return pszOut.ToString();
        }

        [Flags]
        public enum AssocF
        {
            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
        }

        public enum AssocStr
        {
            Command = 1,
            Executable,
            FriendlyDocName,
            FriendlyAppName,
            NoOpen,
            ShellNewValue,
            DDECommand,
            DDEIfExec,
            DDEApplication,
            DDETopic
        }



    }
}

Reading stuff like this directly from the registry is generally a bad idea (see Raymond Chen's blog for all the gory details ). In this particular case, the API you want is AssocQueryString in shlwapi.h .

Here's C++ code:

TCHAR buf[1024];
DWORD sz = sizeof(buf) / sizeof(TCHAR);
AssocQueryString(ASSOCF_INIT_DEFAULTTOSTAR, ASSOCSTR_FRIENDLYDOCNAME, L".sql", NULL, buf, &sz);

You can use this from C# either via C++/CLI exposing a nice .NET-friendly API; or call it directly via P/Invoke .

Some extra if's for unknown file types in XP.. May not really give the right results when using it with anything but FriendlyDocName, but just as an example:

public static string FileExtentionInfo(AssocStr assocStr, string doctype)
{
   if ((doctype.Length <= 1) || !doctype.StartsWith(".")) return "";

   uint pcchOut = 0;
   AssocQueryString(AssocF.Verify, assocStr, doctype, null, null, ref pcchOut);

   if (pcchOut == 0) return (doctype.Trim('.').ToUpper() + " File");

   StringBuilder pszOut = new StringBuilder((int)pcchOut);
   AssocQueryString(AssocF.Verify, assocStr, doctype, null, pszOut, ref pcchOut);
   return pszOut.ToString();
}

The good old FileSystemObject has this functionality built into it.

If you don't mind using it then the following code is very short.

Add a reference to Microsoft Scripting Runtime to your project and try this in a Windows Form app.

private void Form1_Load(object sender, EventArgs e) {
  getSometypes();
}
private void getSometypes()
{
  System.Diagnostics.Debug.WriteLine(getFileType(".txt"));
  System.Diagnostics.Debug.WriteLine(getFileType(".doc"));
  System.Diagnostics.Debug.WriteLine(getFileType(".xlsx"));
}    
private string getFileType(object ext)
{
  Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
  string tempPath = System.IO.Path.GetTempPath();
  string tempFile = "";
  tempFile = tempPath + "tmp" + ext;
  System.IO.File.WriteAllText(tempFile, "");
  var f = fso.GetFile(tempFile);
  string t = f.Type;
  f.Delete();
  return t;
}

The getFileType creates a temporary file with the supplied extension, then with the FileSystemObject the file is opened and its Type is returned, which is the type description you want. The getSometypes writes them out in the Output window.

In this case (in Swedish):

Textdokument
Microsoft Word 97–2003-dokument
Microsoft Excel-kalkylblad

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM