Search code examples
c#compinvokeshell32

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


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?


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