Click here to Skip to main content
15,886,258 members
Articles / Web Development / IIS

Reading contents of Web Folders in C#

Rate me:
Please Sign up or sign in to vote.
4.59/5 (11 votes)
28 Feb 20065 min read 120.9K   812   44  
An analysis of the different ways of getting the list of files in a web folder (including SharePoint) programmatically, and a simple solution. The sample code is for C# 2.0.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.Text.RegularExpressions;

namespace Utils
{
    public static class PathRoutines
    {

        //'44 seems to be the length where we have to change a byte from 00 to a 01.
        private const int URL_CUTOFF = 44;

        //This is where we construct the target.lnk file byte by byte. Most of the lines are shown in 16 byte chunks,
        //mostly because that is the way I saw it in the Debug utility I was using to inspect shortcut files.
        private static readonly byte[] LINK_CONTENT_PREFIX = new byte[]
        {//Line 1, 16 bytes
          0x4C, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00,
         //Line 2, 16 bytes
          0x00, 0x00, 0x00, 0x46, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        //Line 3, 16 bytes
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        //Line 4., 16 bytes. 13th byte is significant.
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        //Line 5. 13th byte is significant.
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        //When I was analyzing the next byte of shortcuts I created, I found that it is set to various values,
        //and I have no idea what they are referring to. In desperation I tried substituting some values.
        //00 caused a crash of Explorer. FF seeems to work fine for all.
          0xFF};

        private static readonly byte[] LINK_CONTENT_MID = new byte[]
        {
            0x14, 0x00,
            //Line 6, 16 bytes
            0x1F, 0x50, 0xE0, 0x4F, 0xD0, 0x20, 0xEA, 0x3A, 0x69, 0x10, 0xA2, 0xD8, 0x08, 0x00, 0x2B, 0x30,
            //Line 7, 16 bytes
            0x30, 0x9D, 0x14, 0x00, 0x2E, 0x00, 0x00, 0xDF, 0xEA, 0xBD, 0x65, 0xC2, 0xD0, 0x11, 0xBC, 0xED,
            //Line 8, 16 bytes
            0x00, 0xA0, 0xC9, 0x0A, 0xB5, 0x0F, 0xA4
        };

        private static readonly byte[] LINK_CONTENT_MID2 = new byte[]
        {
            0x4C, 0x50, 0x00, 0x01, 0x42, 0x57, 0x00, 0x00,
            //Line 9, 16 bytes
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
            //Line 10, 2 bytes
            0x00, 0x00
        };

        private static readonly byte[] LINK_CONTENT_POSTFIX = new byte[]
        {
            //Last line, 13 bytes
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        };        

        /// <summary>
        /// Uses Shell32
        /// </summary>
        /// <param name="siteUrl"></param>
        /// <param name="filePathPattern">For example, to make a wildcard search ".doc" use the following
        /// reg expression: Regex regex = new Regex(@".*\.doc", RegexOptions.Compiled | RegexOptions.IgnoreCase); 
        /// to exclude word template documents assigned to a SharePoint workspace, use the following reg 
        /// expression: new Regex(@"(?<!.*/Forms/[^/]+)\.doc$", RegexOptions.Compiled | RegexOptions.IgnoreCase)</param>
        /// <returns></returns>
        public static StringCollection SearchFilesInWebFolder(Uri siteUrl, Regex filePathPattern, bool searchSubFolders)
        {
            string mapFolderPath = CreateWebFolderLink(siteUrl);
            
            StringCollection ret = new StringCollection();

            Shell32.ShellClass shell = new Shell32.ShellClass();

            Shell32.Folder mapFolder = shell.NameSpace(mapFolderPath);
            SearchInFolder(mapFolder, filePathPattern, searchSubFolders, ret);

            return ret;
        }

        private static void SearchInFolder(Shell32.Folder folder, Regex filePathPattern, bool searchSubFolders, StringCollection resultList)
        {
            foreach (Shell32.FolderItem item in folder.Items())
            {
                if (item.IsLink)
                    continue;

                if (item.IsFolder && searchSubFolders)
                {
                    SearchInFolder((Shell32.Folder) item.GetFolder, filePathPattern, searchSubFolders, resultList);
                    continue;
                }

                if (filePathPattern.IsMatch(item.Path))
                {
                    resultList.Add(item.Path);
                }  
            }
        }


        public static string GetFileName(Uri uri)
        {
            if (uri == null)
                return null;

            return System.IO.Path.GetFileName(uri.ToString());
        }


        /// <summary>
        /// Returns path to a shortcut folder that is mapped to the specified web siteUrl. Name of the folder is derived
        /// automatically.
        /// If the shortcut folder already exists - does nothing
        /// </summary>
        /// <param name="siteUrl"></param>
        /// <param name="shortcutContainerPath"></param>
        /// <returns></returns>
        public static string CreateWebFolderLink(Uri siteUrl)
        {
            //derive shortcut name
            string sitePath = siteUrl.ToString();
            string shortcutName = sitePath.GetHashCode().ToString();

            return CreateWebFolderLink(sitePath, Path.GetTempPath(), shortcutName);
        }

        public static string CreateWebFolderLink(Uri siteUrl, string shortcutContainerPath, string shortcutName)
        {
            return CreateWebFolderLink(siteUrl.ToString(), shortcutContainerPath, shortcutName);
        }

        /// <summary>
        /// Returns path to a folder with name 'shortcutName' that is mapped to the specified web siteUrl.
        /// If the folder already exists - does nothing
        /// </summary>
        /// <param name="siteUrl">The target url</param>
        /// <param name="siteName">Name of the folder</param>
        /// <param name="siteContainerPath">Directory where the Web Folder mapped to the specified web siteUrl will be created</param>
        public static string CreateWebFolderLink(string siteUrl, string shortcutContainerPath, string shortcutName)
        {
            if (siteUrl.Length > 255)
                throw new ArgumentOutOfRangeException("Length of Url [" + siteUrl + "] is more than 255 symbols");

            string localFolderPath = Path.Combine(shortcutContainerPath, shortcutName);

            DirectoryInfo localDir = null;
            if (Directory.Exists(localFolderPath))
                return localFolderPath;

            localDir = Directory.CreateDirectory(localFolderPath);
            localDir.Attributes = FileAttributes.ReadOnly;

            string desktop_ini_filePath = Path.Combine(localFolderPath, "Desktop.ini");
            StreamWriter writer = new StreamWriter(desktop_ini_filePath, false);
            writer.WriteLine("[.ShellClassInfo]");
            writer.WriteLine("CLSID2={0AFACED1-E828-11D1-9187-B532F1E9575D}");
            writer.WriteLine("Flags=2");
            writer.WriteLine("ConfirmFileOp=0");
            writer.Close();

            //'We make Desktop.ini a system-hidden file by assigning it attribute of 6
            //Set fs = CreateObject("Scripting.FileSystemObject")
            //Set g = fs.GetFile(newPath & "\Desktop.ini")
            //g.Attributes = 6

            //'We make the folder read-only by assigning it 1.
            //Set fs = CreateObject("Scripting.FileSystemObject")
            //Set g = fs.GetFolder(newPath)
            //g.Attributes = 1

            string lnk_filePath = Path.Combine(localFolderPath, "target.lnk");
            FileStream fs = new FileStream(lnk_filePath, FileMode.Create);
            BinaryWriter stream = new BinaryWriter(fs, Encoding.BigEndianUnicode);
            stream.Write(LINK_CONTENT_PREFIX, 0, LINK_CONTENT_PREFIX.Length);


            //'This byte is 00 if the URL is 44 characters or less, 01 if greater.
            if (siteUrl.Length > URL_CUTOFF)
            {
                stream.Write((byte)0x01);
            }
            else
            {
                stream.Write((byte)0x00);
            }

            stream.Write(LINK_CONTENT_MID, 0, LINK_CONTENT_MID.Length);

            //'This byte is 00 if the URL is 44 characters or less, 01 if greater.
            if (siteUrl.Length > URL_CUTOFF)
            {
                stream.Write((byte)0x01);
            }
            else
            {
                stream.Write((byte)0x00);
            }

            stream.Write(LINK_CONTENT_MID2, 0, LINK_CONTENT_MID2.Length);

            //The next byte represents the length of the site name.
            stream.Write((byte)shortcutName.Length);

            //MemoryStream s = new MemoryStream();
            //BinaryWriter b = new BinaryWriter(s, Encoding.BigEndianUnicode);

            char[] webFolderNameChars = shortcutName.ToCharArray();
            stream.Write(webFolderNameChars, 0, webFolderNameChars.Length);


            //b.Write(webFolderNameChars, 0, webFolderNameChars.Length);

            //Middle line, separates the Folder Name from the URL. 3 bytes.
            stream.Write((byte)0x00);
            stream.Write((byte)0x00);
            stream.Write((byte)0x00);

            //The next byte represents the length of the site URL.
            stream.Write((byte)siteUrl.Length);

            char[] sitePathChars = siteUrl.ToCharArray();
            stream.Write(sitePathChars, 0, sitePathChars.Length);

            stream.Write(LINK_CONTENT_POSTFIX, 0, LINK_CONTENT_POSTFIX.Length);

            stream.Close();

            return localFolderPath;

        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
Roman Koreshkov has been on Systems Architect position in many software development companies.
He is keen on object-relational mapping methodologies, business layers, business rules and requirements management and code-generation stuff.
His current engagement is architecturing a next-generation HR products with the highest level of flexibility and performance.
His current professional passion is the new AJAX technologies and approaches.

Comments and Discussions