Monday, April 23, 2012

A Trick in F# Interop

When I try to crack the .CAB file, I found the COM interop in F# is different from C#.

the code sample in C# like the following code after adding "Microsoft Shell Controls And Automation" from "COM" tab.


bool ExpandCabFile(string CabFile, string DestDir)
    {
      if (!Directory.Exists(DestDir)) return false;
      Shell sh = new Shell();
      Folder fldr = sh.NameSpace(DestDir);
      foreach (FolderItem f in sh.NameSpace(CabFile).Items()) fldr.CopyHere(f, 0);
      return true;
    }


It should be straightforward to transform from this C# to F#. But it turns out the Shell cannot be created because it is an interface! Yes, you are not reading a typo. Shell is a interface if you use the Object Viewer.

The C# side can pick up the CoClass attribute so the new statement is calling into the ShellClass. Actually you cannot new ShellClass in C# code.


    [CoClass(typeof(ShellClass))]
    [Guid("866738B9-6CF2-4DE8-8767-F794EBE74F4E")]
    public interface Shell : IShellDispatch5
    {
    }

In F# side, you have to create ShellClass instead of Shell. So if you want to convert C# code which involves COM component to F# code, try to find the real class by finding the CoClass attribute. The complete F# code is listed below:


    let shell = new ShellClass()
    let folder = shell.NameSpace(Path.GetDirectoryName(fn))
    let fileName = Path.GetFileName(fn)
    let currentFolder =
    if not (Directory.Exists currentFolder) then
        Directory.CreateDirectory currentFolder |> ignore
    for item in shell.NameSpace(fn).Items() do
        folder.CopyHere(item, 0)


1 comment:

Onorio said...

Funny I was trying to get some code using the IShell COM interface going in F#. I wonder if this may have been the problem. Thanks.