How do I go about instantiating a COM Object in C# by CLSID?

c#, com, pinvoke, shell32

Solution

Here is a piece of code that allows you to create a folder shortcut. The CoCreateInstance can (in general) be replaced by declaring a simple class decorated with the Guid attribute with the required CLSID, and the ComImport attribute. The `new` call will do the COM magic automatically. With this code, you don't even need a Shell32 reference (or you can reuse the IShellLink declaration from there if you prefer).

Usage:

static void Main(string[] args)
{
    CreateFolderShortcut(@"c:\temp", Path.GetFullPath("Shortcut to Temp"));
}

Code:

public static void CreateFolderShortcut(string path, string shortcutPath)
{
    CreateFolderShortcut(path, shortcutPath, null);
}

public static void CreateFolderShortcut(string path, string shortcutPath, string comment)
{
    if (path == null)
        throw new ArgumentNullException("path");

    IShellLink link = (IShellLink)new ShellLinkFolder();

    if (comment != null)
    {
        link.SetDescription(comment);
    }
    link.SetPath(path);

    IPersistFile file = (IPersistFile)link;
    file.Save(shortcutPath, false);
}

[ComImport]
[Guid("00021401-0000-0000-C000-000000000046")]
private class ShellLink
{
}

[ComImport]
[Guid("0AFACED1-E828-11D1-9187-B532F1E9575D")]
private class ShellLinkFolder
{
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")]
private interface IShellLink
{
    void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, int fFlags);
    void GetIDList(out IntPtr ppidl);
    void SetIDList(IntPtr pidl);
    void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
    void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
    void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
    void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
    void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
    void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
    void GetHotkey(out short pwHotkey);
    void SetHotkey(short wHotkey);
    void GetShowCmd(out int piShowCmd);
    void SetShowCmd(int iShowCmd);
    void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
    void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
    void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
    void Resolve(IntPtr hwnd, int fFlags);
    void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}

Problem

Forgive me if my terminology is off, as this is somewhat uncharted territory for me. I have a program which needs to create a `FolderShortcut`. Microsoft has documentation on how to create it in C++, and I'm trying to translate the directions to C#. The instructions state that the `CoCreateInstance` function needs to be called with `CLSID_FolderShortcut` as a parameter, which I infer to mean that it's instantiating a COM object. The CLSID for this object is `{0AFACED1-E828-11D1-9187-B532F1E9575D}`. I've tried adding a reference to Shell32.dll from the COM tab, but the `FolderShortcut` object does not show up in Intellisense (maybe it's not in the typelib?). I also thought about doing a `DLLImport`, but, of course, that only gives me access to functions, not objects. What do I need to do to get access to this object in .Net?

Original source