Windows WebDAV client settings (WebClient Service)

Windows WebDAV client relies on the WebClient Service. The WebClient service has the following settings:

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\WebClient\Parameters]
"AcceptOfficeAndTahoeServers"=dword:00000001
"BasicAuthLevel"=dword:00000001
"ClientDebug"=dword:00000000
"FileAttributesLimitInBytes"=dword:000f4240
"FileSizeLimitInBytes"=dword:02faf080
"InternetServerTimeoutInSec"=dword:0000001e
"LocalServerTimeoutInSec"=dword:0000000f
"SendReceiveTimeoutInSec"=dword:00000001
"ServerNotFoundCacheLifeTimeInSec"=dword:00000001
"ServiceDebug"=dword:00000000
"ServiceDll"=...
"ServiceDllUnloadOnStop"=dword:00000001
"SupportLocking"=dword:00000001
"AuthForwardServerList"=...

Important to mention is AuthForwardServerList which is a list of servers, the WebClient will authenticate to. Also interesting is FileSizeLimitInBytes which defines the maximum file size the WebDAV WebClient will will up- or download.

Advertisements

Windows WebDAV client cache settings (MRxDAV Service)

Windows WebDAV access might cache certain operations. This leads to problems when your software relies on a consistent state.

Our problem was that a call to .NET File.Exists on a WebDAV share returned a cached value. Using WireShark we could see that only one HTTP request is sent per minute.

Beside WebClient there is another Windows Service MRxDAV used for providing WebDAV. It comes with its own settings that allow to control all time-outs:

[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\MRxDAV\Parameters]
"CloseRequestTimeoutInSec"=dword:00000708
"CreateRequestTimeoutInSec"=dword:00000708
"CreateSrvCallRequestTimeoutInSec"=dword:00000014
"CreateVNetRootRequestTimeoutInSec"=dword:0000003c
"DAVDebugFlag"=dword:00000000
"DevFsCtlRequestTimeoutInSec"=dword:00000258
"FileInformationCacheLifeTimeInSec"=dword:0000003c
"FileNotFoundCacheLifeTimeInSec"=dword:0000003c
"FinalizeFcbRequestTimeoutInSec"=dword:0000003c
"FinalizeFobxRequestTimeoutInSec"=dword:0000003c
"FinalizeSrvCallRequestTimeoutInSec"=dword:00000258
"FinalizeVNetRootRequestTimeoutInSec"=dword:00000258
"FsCtlRequestTimeoutInSec"=dword:00000708
"LockRefreshRequestTimeoutInSec"=dword:00000258
"NameCacheMaxEntries"=dword:0000012c
"QueryDirectoryRequestTimeoutInSec"=dword:00000258
"QueryFileInfoRequestTimeoutInSec"=dword:00000258
"QueryVolumeInfoRequestTimeoutInSec"=dword:00000258
"ReNameRequestTimeoutInSec"=dword:00000258
"SetFileInfoRequestTimeoutInSec"=dword:00000258
"UMRxDebugFlag"=dword:00000000

It turns out that FileNotFoundCacheLifeTimeInSec controls the number of seconds, a call to File.Exist is cached. The default value is 60 seconds (which is 0x3C). After setting it to 0, the problems were gone. Note that FileInformationCacheLifeTimeInSec might also be a good candidate for a different value.

The registry key is also described for adminisrators in technet.microsoft.com

More information about MRxDAV can be found in Windows Driver documentation about Installable File Systems and Redirected Drive Buffering SubSystem.

.NET FIPS compliance (MD5, Lucene.NET)

FIPS is the US Federal Information Processing Standard. It can be enabled in Windows registry like this:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy
"Enabled"=dword:00000001

Afterwards all attemps to create a System.Security.Cryptography.MD5 will fail:

 System.InvalidOperationException: This implementation is not part of the Windows Platform FIPS validated cryptographic algorithms.
 System.Security.Cryptography.MD5CryptoServiceProvider..ctor()
 System.Security.Cryptography.CryptoConfig.CreateFromName(String name, Object[] args)
 System.Security.Cryptography.MD5.Create()

This is also a problem when using Lucene.NET as they use MD5 to create hashes for directories. When enabling the switch it offers, Lucene.NET will use SHA1 instead:

namespace Lucene.Net.Support
{
    public static class Cryptography
    {
        public static bool FIPSCompliant = false;

        public static HashAlgorithm HashAlgorithm
        {
            get
            {
                if (FIPSCompliant)
                {
                    //LUCENENET-175
                    //No Assumptions should be made on the HashAlgorithm. It may change in time.
                    //SHA256 SHA384 SHA512 etc.
                    return SHA1.Create();
                }
                return MD5.Create();
            }
        }
    }
}

OpenXml: Add image to presentation

With the following code snippet, a image can be added to a presentation PPTX. The code is not nice but serves as a working example.

public static void AddImage(string file, string image)
{
    using (var presentation = PresentationDocument.Open(file, true))
    {
        var slidePart = presentation
            .PresentationPart
            .SlideParts
            .First();

        var part = slidePart
            .AddImagePart(ImagePartType.Png);

        using (var stream = File.OpenRead(image))
        {
            part.FeedData(stream);
        }

        var tree = slidePart
            .Slide
            .Descendants<DocumentFormat.OpenXml.Presentation.ShapeTree>()
            .First();

        var picture = new DocumentFormat.OpenXml.Presentation.Picture();

        picture.NonVisualPictureProperties = new DocumentFormat.OpenXml.Presentation.NonVisualPictureProperties();
        picture.NonVisualPictureProperties.Append(new DocumentFormat.OpenXml.Presentation.NonVisualDrawingProperties
        {
            Name = "My Shape",
            Id = (UInt32)tree.ChildElements.Count - 1
        });

        var nonVisualPictureDrawingProperties = new DocumentFormat.OpenXml.Presentation.NonVisualPictureDrawingProperties();
        nonVisualPictureDrawingProperties.Append(new DocumentFormat.OpenXml.Drawing.PictureLocks()
        {
            NoChangeAspect = true
        });
        picture.NonVisualPictureProperties.Append(nonVisualPictureDrawingProperties);
        picture.NonVisualPictureProperties.Append(new DocumentFormat.OpenXml.Presentation.ApplicationNonVisualDrawingProperties());

        var blipFill = new DocumentFormat.OpenXml.Presentation.BlipFill();
        var blip1 = new DocumentFormat.OpenXml.Drawing.Blip()
        {
            Embed = slidePart.GetIdOfPart(part)
        };
        var blipExtensionList1 = new DocumentFormat.OpenXml.Drawing.BlipExtensionList();
        var blipExtension1 = new DocumentFormat.OpenXml.Drawing.BlipExtension()
        {
            Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}"
        };
        var useLocalDpi1 = new DocumentFormat.OpenXml.Office2010.Drawing.UseLocalDpi()
        {
            Val = false
        };
        useLocalDpi1.AddNamespaceDeclaration("a14", "http://schemas.microsoft.com/office/drawing/2010/main");
        blipExtension1.Append(useLocalDpi1);
        blipExtensionList1.Append(blipExtension1);
        blip1.Append(blipExtensionList1);
        var stretch = new DocumentFormat.OpenXml.Drawing.Stretch();
        stretch.Append(new DocumentFormat.OpenXml.Drawing.FillRectangle());
        blipFill.Append(blip1);
        blipFill.Append(stretch);
        picture.Append(blipFill);

        picture.ShapeProperties = new DocumentFormat.OpenXml.Presentation.ShapeProperties();
        picture.ShapeProperties.Transform2D = new DocumentFormat.OpenXml.Drawing.Transform2D();
        picture.ShapeProperties.Transform2D.Append(new DocumentFormat.OpenXml.Drawing.Offset
        {
            X = 0,
            Y = 0,
        });
        picture.ShapeProperties.Transform2D.Append(new DocumentFormat.OpenXml.Drawing.Extents
        {
            Cx = 1000000,
            Cy = 1000000,
        });
        picture.ShapeProperties.Append(new DocumentFormat.OpenXml.Drawing.PresetGeometry
        {
            Preset = DocumentFormat.OpenXml.Drawing.ShapeTypeValues.Rectangle
        });

        tree.Append(picture);
    }
}

OpenXml: Add shape to presentation

Following snippet loads a presentation using the OpenXml SDK and adds a simple rectangular shape to the first slide.

public static void AddShape(string file)
{
    using (var presentation = PresentationDocument.Open(file, true))
    {
        var tree = presentation
            .PresentationPart
            .SlideParts
            .ElementAt(0)
            .Slide
            .Descendants<DocumentFormat.OpenXml.Presentation.ShapeTree>()
            .First();

        var shape = new DocumentFormat.OpenXml.Presentation.Shape();

        shape.NonVisualShapeProperties = new DocumentFormat.OpenXml.Presentation.NonVisualShapeProperties();
        shape.NonVisualShapeProperties.Append(new DocumentFormat.OpenXml.Presentation.NonVisualDrawingProperties
        {
            Name = "My Shape",
            Id = (UInt32)tree.ChildElements.Count - 1
        });
        shape.NonVisualShapeProperties.Append(new DocumentFormat.OpenXml.Presentation.NonVisualShapeDrawingProperties());
        shape.NonVisualShapeProperties.Append(new DocumentFormat.OpenXml.Presentation.ApplicationNonVisualDrawingProperties());

        shape.ShapeProperties = new DocumentFormat.OpenXml.Presentation.ShapeProperties();
        shape.ShapeProperties.Transform2D = new DocumentFormat.OpenXml.Drawing.Transform2D();
        shape.ShapeProperties.Transform2D.Append(new DocumentFormat.OpenXml.Drawing.Offset
        {
            X = 0,
            Y = 0,
        });
        shape.ShapeProperties.Transform2D.Append(new DocumentFormat.OpenXml.Drawing.Extents
        {
            Cx = 1000000,
            Cy = 1000000,
        });
        shape.ShapeProperties.Append(new PresetGeometry
        {
            Preset = ShapeTypeValues.Rectangle
        });
        shape.ShapeProperties.Append(new SolidFill
        {
            SchemeColor = new SchemeColor
            {
                Val = SchemeColorValues.Accent2
            }
        });
        shape.ShapeProperties.Append(new Outline(new NoFill()));

        tree.AppendChild(shape);
    }
}

OpenXml: Units of measurement

Ever wondered what that coordinate system in OpenXml is? It’s fixed point arithmetic based long (64bit). It is optimized for fitting both inch and metric base. Office Interop uses DPI based floating point instead. Here some code to convert. But beware: It’s optimized for code-less and not for rounding errors!

    public static class EMU
    {
        // 20.1.2.1 EMU Unit of Measurement
        //
        // 1 EMU = 1 / 914400 US inch = 1 / 360000 cm
        //
        public static float EmuToDpi(this long value)
        {
            return (float)((double)value / 12700.0);
        }
        public static long DpiToEmu(this float value)
        {
            return (long)(value * 12700.0f);
        }
    }

OpenXml: Loading a PowerPoint presentation with C# and OpenXml

OpenXml is the open source library to load and modify Microsoft Office documents without the need of Office.

In this example, I want to open a presentation, iterate over all shapes and print their shape name.

First, I create a C# console application inside Visual Studio. Then I load the OpenXml package from the nu-get console:

Install-Package DocumentFormat.OpenXml

The example application is a console application that opens the presentation provided through command line argument. Then it iterates over all shapes and prints their name to console:

using DocumentFormat.OpenXml.Packaging;
using System;
using System.Linq;

namespace OpenXML1
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var presentation = PresentationDocument.Open(args[0], false))
            {
                foreach (var shape in presentation
                    .PresentationPart
                    .SlideParts
                    .Select(p => p.Slide)
                    .SelectMany(s => s
                        .Descendants<DocumentFormat.OpenXml.Presentation.Shape>()))
                {
                    Console.WriteLine(shape
                        .NonVisualShapeProperties
                        .NonVisualDrawingProperties
                        .Name);
                }
            }
        }
    }
}