Click here to Skip to main content
Click here to Skip to main content

Reading contents of Web Folders in C#

, 28 Feb 2006
Rate this:
Please Sign up or sign in to vote.
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.

Problem

Once I needed to make some automation processing of Microsoft Word documents located in a SharePoint Portal Server. But I faced an interesting problem – how to find all the documents in SharePoint programmatically?

Investigation – Flops and Boomers

Trial of the FileSearch interface

First, as long as I already used Word automation interfaces, I tried to use the file searching capabilities implemented in the Microsoft Office API, namely the FileSearch interface exposed by Office’s Application object. I assumed that whilst Microsoft Word is capable of opening documents directly from SharePoint, of course, it would be able to search through Word documents on the server…

Naïve assumption - of course not. Things are never so simple that you may relax and have the fun of the “famous” KISS principle. It was able to work properly only on local disk, or, at most, at a network file share.

Trial of the SharePoint Web Services

OK, I know that the SharePoint Server exposes its content in the form of web services. I tried that stuff too, but those entities that I had to work with seemed to me much more complicated than was required for such a simple task - a lot of lists and items of different types. Also, I was not sure about the compatibility between different versions of the SharePoint Server (like 2001, 2003, and the next 2006), and furthermore, I wanted a solution that might work with not only the SharePoint Portal Server, but with any Web Folder that you may browse in Windows Explorer (e.g., running under pure Windows Server 2003).

Trial of WebDAV and Web Extender Client (WEC) protocols

As you may know, it is possible to browse a web folder in Windows Explorer only if the IIS server supports either the FrontPage Web Extender Client (WEC) or the Web Distributed Authoring and Versioning (WebDAV) protocol extensions.

There are different ways of making WebDAV/WEC requests – through composing XML requests, or through writing a defined set of HTTP headers into the HTTP request. These would require deep scrutinizing of the standards.

I found out that MS Office products use the FPWEC.DLL COM library usually located at %PROGRAMFILES%\Common Files\Microsoft Shared\web server extensions\60\BIN. It contains a set of wrappers for these protocols, but I found no documentation on them, and their usage did not seem to be straightforward, mainly in the asynchronous manner.

Unfortunately, I didn’t find any free really-working C# library that would allow mw to easily use WebDAV.

One of the ways is to use the OLE DB Provider for Internet Publishing from old ADO. However, on MSDN, there is this statement that “the .NET Framework Data Provider for OLE DB does not support OLE DB version 2.5 interfaces. OLE DB Providers that require support for OLE DB 2.5 interfaces will not function properly with the .NET Framework Data Provider for OLE DB. This includes the Microsoft OLE DB Provider for Exchange and the Microsoft OLE DB Provider for Internet Publishing”. I didn’t like to use COM interop over ADO 2.5 interfaces from my C# code, and I skipped this solution. However, you may try it – it may be quite feasible in some cases.

The Alternative Solution – Web Folder Short Cuts

Suddenly, I remembered that sometimes when you try browsing a web folder, a shortcut to the web folder is added to the My Network Places folder available in the Windows Explorer.

As you may know, these shortcuts are physically placed into the c:\Documents and Settings\{USER NAME}\NetHood hidden folder. A web folder shortcut is a physical directory with a read-only file attribute (the directory name is equal to the name of the shortcut) that contains two specific files:

  • Desktop.ini (file attributes are Hidden, System) – a text file that contains the ProgID of a shell extension that will handle how to represent the content of the shortcut to the user.
  • target.lnk – a binary file that contains a URL to the web folder the shortcut represents.

So I tried to read the content of the web folder shortcut just as Windows Explorer is expected to do; I used the “Shell Objects for Scripting” (VBScript sample):

dim oShell
dim oFolder
dim sDir
Dim s

set oShell = CreateObject("Shell.Application")
set oFolder = oShell.NameSpace("c:\Documents and" & _ 
              " Settings\Administrator" & _ 
              "\NetHood\The_ShortCut_Name")

for i=0 to oFolder.Items.Count-1
    s = s + oFolder.Items.Item(i).Path+ _
            chr(10)+chr(13)
next

MsgBox s

… and it has worked out. Inside, the appropriate shell extension (pre-installed with Windows) provides the necessary Folder and FolderItem objects, doing all the hard work of interacting with the web server through WebDAV/WEC for us – we will just utilize their results. Note, that passing a pure HTTP URL to the Shell.Application object won't work.

Recently, I came across a script code that allows creating web folder shortcuts (Code Ccomments) - many thanks to the author. I converted the code into C#:

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
        };        

        /// <span class="code-SummaryComment"><summary>
</span>
        /// Returns path to a directory with name 
        /// 'shortcutName' that is mapped
        /// to the specified web siteUrl.
        /// If the directory already exists - does nothing
        /// <span class="code-SummaryComment"></summary>
</span>
        /// <span class="code-SummaryComment"><param name="siteUrl">The target url</param>
</span>
        /// <span class="code-SummaryComment"><param name="shortcutContainerPath">Folder where
</span>
        ///           the shortcut folder mapped to
        /// the specified web siteUrl will be created<span class="code-SummaryComment"></param>
</span>
        /// <span class="code-SummaryComment"><param name="shortcutName">Name of the 
</span>
        ///          shortcut folder<span class="code-SummaryComment"></param>
</span>
        public static string CreateWebFolderLink(string siteUrl, 
               string shortcutContainerPath, string shortcutName)
        {
            if (siteUrl.Length >

By the way, you may use the CreateWebFolderLink method to create the necessary web folder shortcuts to be visible in the “My Network Places” folder; for that, just pass the “c:\Documents and Settings\{USER NAME}\NetHood” string as the shortcutContainerPath parameter.

So now, when one wants to get a list of files in a web folder, the algorithm will be as follows:

  • We create a temporary shortcut to the web folder.
  • We use Shell32 to read its contents.

Create a temporary shortcut to the web folder:

/// <span class="code-SummaryComment"><summary>
</span>
/// 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
/// <span class="code-SummaryComment"></summary>
</span>
/// <span class="code-SummaryComment"><param name="siteUrl"></param>
</span>
/// <span class="code-SummaryComment"><param name="shortcutContainerPath"></param>
</span>
/// <span class="code-SummaryComment"><returns></returns>
</span>
public static string CreateWebFolderLink(Uri siteUrl)
{
    //derive shortcut name
    string sitePath = siteUrl.ToString();
    string shortcutName = 
           sitePath.GetHashCode().ToString();

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

Use Shell32 to read contents:

In order that the following code is compiled, you need to add a COM reference to the Shell32 library (its caption is “Microsoft Shell Controls and Automation”) to your project.

/// <span class="code-SummaryComment"><summary>
</span>
/// Uses Shell32
/// <span class="code-SummaryComment"></summary>
</span>
/// <span class="code-SummaryComment"><param name="siteUrl"></param>
</span>
/// <span class="code-SummaryComment"><param name="filePathPattern">For example,
</span>
///        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(@"(?<span class="code-SummaryComment"><!.*/Forms/[^/]+)\.doc$", 
///          RegexOptions.Compiled | RegexOptions.IgnoreCase)</param>
</span>
/// <span class="code-SummaryComment"><param name="searchSubFolders"></param>
</span>
/// <span class="code-SummaryComment"><returns></returns>
</span>
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);
        }  
    }
}

Conclusion

The suggested solution seems to be quite simple and feasible for Windows or console applications. However, for server applications, use it with caution – you may likely face some problems with security (I am a bit doubtful whether an “ASP.NET” user would be able to use the Shell32 COM Interop) and multithreading. For such circumstances, I think the best approach would still be to use Web Services or WebDAV/WEC protocols directly.

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

About the Author

Roman Koreshkov
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

 
QuestionPlssssssssssssss help Pinmemberpallavijain12-Mar-13 5:00 
QuestionWebshare folder. PinmemberManjunath_N1-Mar-13 1:05 
Question.lnk is not readable PinmemberManjunath_N15-Feb-13 3:45 
QuestionThe type or namespace name 'Shell32' could not be found (are you missing a using directive or an assembly reference?) Pinmemberakil chehade16-Oct-12 2:46 
AnswerRe: The type or namespace name 'Shell32' could not be found (are you missing a using directive or an assembly reference?) PinmemberRoman Koreshkov16-Oct-12 4:30 
QuestionNice Article PinmemberPrakash Varun 201031-May-12 22:10 
AnswerBinary File Specification for LNK File PinmemberCVisions21-Apr-11 9:22 
GeneralRe: Binary File Specification for LNK File PinmemberRoman Koreshkov21-Apr-11 23:52 
AnswerRe: Binary File Specification for LNK File PinmemberCVisions25-Apr-11 5:27 
GeneralNot Work in Windows7 Pinmembercwchiu9-Nov-09 21:10 
GeneralFix for japanese support PinmemberKU27-Jul-09 23:05 
GeneralRe: Fix for japanese support PinmemberRoman Koreshkov27-Jul-09 23:25 
QuestionDoes it work in vista? Pinmemberaustin ajit4-Feb-09 13:44 
AnswerRe: Does it work in vista? PinmemberRoman Koreshkov4-Feb-09 20:42 
GeneralMapping Sharepoint sites under My Network Places\Web Folders PinmemberKfir Haliva28-Jun-08 13:01 
QuestionIs there another way? Pinmembermike payne3-Apr-08 23:12 
AnswerRe: Is there another way? PinmemberVivekv4-Apr-08 10:51 
Generalfile/folder attributes PinmemberVivekv31-Mar-08 8:42 
QuestionLogin Pinmembermiauwmiauwmiauw19-Dec-07 21:54 
GeneralThreads in knots... Pinmembertherearefartoomanybens28-Nov-07 11:57 
GeneralNot working Pinmemberarslanjatt21-Nov-07 22:24 
GeneralRe: Not working PinmemberRoman Koreshkov21-Nov-07 23:24 
GeneralRe: Not working Pinmemberarslanjatt22-Nov-07 1:09 
AnswerRe: Not working PinmemberRoman Koreshkov22-Nov-07 1:48 
GeneralRe: Not working Pinmemberarslanjatt22-Nov-07 2:26 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140709.1 | Last Updated 1 Mar 2006
Article Copyright 2006 by Roman Koreshkov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid