GitXplorerGitXplorer
M

COMClassLoader

public
0 stars
0 forks
0 issues

Commits

List of commits on branch master.
Unverified
483ae51e18775407b8d78cca6f67ce4c1b2d6816

Fix bug when passing a relative path to to UnregisteredClassLoader

MMattKotsenas committed 7 years ago
Unverified
62a13aad7f835f1ebeaeb28622645973d1f8a37c

Add TODOs to README

MMattKotsenas committed 7 years ago
Unverified
698edcde5d1fee48939f1e38ae77e0de82535c9f

Create .nuspec for COMClassLoader

MMattKotsenas committed 7 years ago
Unverified
16570f14e773e5fd790a1b4cb3b64ffc5be5963e

Add README.md

MMattKotsenas committed 7 years ago
Unverified
510037bc7a6287abf95ae827fd0b9438ba4bd8b3

Create UnregisteredClassLoader

MMattKotsenas committed 7 years ago
Unverified
bc2ebb4b1c9cfda126c4127f748b6cf7d60c6252

Refactor ClassLoader to RegisteredClassLoader

MMattKotsenas committed 7 years ago

README

The README file for this repository.

COMClassLoader

An extensible library for resolving and loading COM classes in .NET.

Introduction

Using COM objects from .NET can be a pain. Like with the Global Assembly Cache (GAC), .NET prefers to interact with registered COM objects, which complicates deployments, and is a big cause of "works on my machine" problems.

Making matters worse, .NET has accumulated multiple ways working with COM objects over the years, including Primary Interop Assembilies (PIAs), registration free COM manifests, tlbimp, and more.

COMClassLoader provides a unified interface, extensibilitiy, and configuration-as-code for dealing with COM types.

Examples

Creating registered COM objects

Here's an example of creating a late-bound instance of a COM object, IShellLink, for a type that is known to be registered. All you have to do is declare your managed types (or get tlbimp or Visual Studio to generate them for you), and call RegisteredClassLoader.Load.

// Definitions of COM types (this may be done automatically by adding a COM library as a project reference)
[ComImport]
[Guid("0AFACED1-E828-11D1-9187-B532F1E9575D")]
internal class ShellLinkFolder
{
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")]
internal 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);
}

// Create a new instance of IShellLink
var link = new RegisteredClassLoader().Load<ShellLinkFolder, IShellLink>();

// Use methods as usual
var sb = new StringBuilder();
link.SetDescription("Hello, World!");
link.GetDescription(sb, sb.MaxCapacity);
Console.WriteLine(sb.ToString()); // Hello, World!

Creating COM objects without registering

Using COM objects that haven't been registered is just as easy. The only difference is that you need to provide the path to the COM assembly like this

var myComObject = new UnregisteredClassLoader(@"path\to\MyComClass.dll").Load<MyComEntryClass, IMyComInterface>();

and now you must provide your own ComImport definitions.

// TODO

  • [ ] Support safe unloading of unmanaged assemblies (currently the COM server lives for the life of the host process)
  • [ ] Support creating / using registration free COM manifests (see https://dzone.com/articles/quick-guide-registration-free)
  • [ ] Create extensible factories so that activation techniques can be chained together (e.g. fallback mechanisms)