# .NET Interface for Total Commander plugins

Provided interface allows to create Total Commander plugins using .NET supporting languages.

This product is provided under the MIT License.

1. Main features.
2. Common considerations.
   - Definition of terms (to avoid misunderstanding).
   - .NET Framework version.
   - Paths to .NET Framework utilities.
3. Content of the downloaded folders.
   - Folder 'Documentation'.
   - Folder 'TcPluginCore'.
   - Folder 'Deployment'.
   - Folder 'TcPluginSamples'.
4. How to create new TC plugin with provided .NET Interface.
   - Requirements.
   - New plugin creation process.
5. How it works.
6. Advanced notes.
   - Plugin Configuration.
   - Tracing.
   - File System plugins: manage the lifetime cycle.
   - File System plugins: content features.
   - Lister plugins: WinForms vs. WPF.
   - WinForms Lister plugins: keyboard handling.
7. Deployment.
8. Source code.

## 1. Main features.

If you are .NET developer and have a good idea for Total Commander plugin - provided .NET Interface is the right choice for you.
With this interface you can concentrate on the main functionality of your plugin without having to worry about most of mundane tasks of TC plugin building.

Main features:

- use all flexibility and power of .NET Framework to implement required plugin functionality,
- your plugin project will contain managed code only, not even one line of C++ unmanaged code,
- base classes for all TC plugin types - File System, Lister, Packer, Content, and QuickSearch
- easy debugging with included tracing system,
- all optional methods not implemented in managed plugin are excluded from the final TC plugin (so TC will never call them),
- TC calls are translated into managed calls with parameters marshaling,
- one unified Plugin Loader loads all types of TC plugins,
- each plugin is loaded into separate Application Domain (AD) to provide isolation and security boundaries for executing managed code,
- control over the lifetime policy for managed plugin instance is allowed,
- Unicode and 64-bit plugin features are supported automatically,
- final binary files are compact (usually less than 100 KB).

## 2. Common considerations.

### 2.1. Definition of terms (to avoid misunderstanding).

Hereinafter term plugin will be used in two different contexts:

- Term TC plugin will be used for standard Total Commander (TC) plugin (file with .wfx, .wlx, .wdx, or .wcx extension).
- Term managed plugin or sometimes just plugin will be used for managed class library created with provided .NET Interface.

### 2.2. .NET Framework version.

Provided interface allows creating managed plugins using .NET Framework version 2.0 and higher.
However, some steps in development process depend on .NET Framework version that developer uses to create new managed plugin.

Actually differences are related to CLR (Common Language Runtime) versions rather than .NET Framework versions.
The .NET Framework 4.0, 4.5, and later releases include CLR 4, but the .NET Framework 2.0, 3.0, and 3.5 include CLR 2.0. (There is no intermediate CLR version.)

Plugin wrapper - intermediate layer between Total Commander and managed plugin - has to be built in different ways depending on CLR version.
It's a reason to use separate wrapper builders for CLR2 and CLR4 in provided interface.
Please take your attention to item 9 in New plugin creation process section. It describes how to select proper wrapper builder.

### 2.3. Paths to .NET Framework utilities.

Provided interface uses some .NET Framework utilities in its work: ilasm.exe (IL Assembler), ildasm.exe (IL Disassembler), and gacutil.exe (Global Assembly Cache Tool).
Paths to these utilities depend on versions of .NET Framework and Visual Studio installed on developer computer.
WARNING: Please check if utilities' paths in provided interface correspond to the files on your computer and fix them if required in the following script and configuration files:

- GAC_Install.bat and GAC_Uninstall.bat in the TcPluginCore folder - gacutil.exe is used here.
- WrapperBuilder.exe.config in the TcPluginCore\clr2 subfolder - IL Assembler and IL Disassembler for CLR2 are used here.
- WrapperBuilder.exe.config in the TcPluginCore\clr4 subfolder - IL Assembler and IL Disassembler for CLR4 are used here.

## 3. Content of the downloaded folders.

### 3.1. Folder 'Documentation'.

ReadMe.html | This file
license.txt | File with the MIT License text.
dotNetPluginMethods.xlsx | Excel spreadsheet with description of each TC plugin method and specifics of their implementation in managed plugins. Also it contains description of all settings used for plugin configuration.

### 3.2. Folder 'TcPluginCore'.

This folder contains files required for plugin developer to create and debug new managed plugins:
Assemblies in this folder were compiled in Debug configuration.

TcPluginInterface.dll | TC plugin interface assembly; contains interfaces and base classes for TC plugins.
TcPluginInterface.pdb | Debugging information for above assembly.
TcPluginTools.dll | TC plugin utility assembly; contains classes for plugin loading, callbacks and error handling.
TcPluginTools.pdb | Debugging information for above assembly.
TcWpfListerHandlerBuilder.dll | Lister handler assembly used to create WPF based Lister plugins.
GAC_Install.bat | Script to install core assemblies into the GAC (Global Assembly Cache). The assemblies are installed into CRL2 cache located in the %windir%\assembly folder.
GAC_Uninstall.bat | Script to remove core assemblies from the GAC.
TcPluginLib.msi | Windows Installer package - alternative way to install/remove TcPluginInterface and TcPluginTools assemblies into the GAC.
WpfLsHandlerBuilder.msi | Windows Installer package - alternative way to install/remove TcWpfListerHandlerBuilder assembly into the GAC.
Totalcmd.exe.config | Total Commander configuration file; it contains tracing settings for new plugin debugging.
Subfolder clr2 | Contains the following files required to build TC plugin wrappers if managed plugin is developed with CLR2 (.NET Framework versions 2.0 - 3.5).
WrapperBuilder.exe | Console program to build plugin wrapper DLL that exports required TC plugin methods.
WrapperBuilder.exe.config | WrapperBuilder configuration specific for CLR2.
WfxWrapper.dll | Template assembly for TC File System plugin wrapper.
WlxWrapper.dll | Template assembly for TC Lister plugin wrapper.
WcxWrapper.dll | Template assembly for TC Packer plugin wrapper.
WdxWrapper.dll | Template assembly for TC Content plugin wrapper.
QSWrapper.dll | Template assembly for TC QuickSearch plugin wrapper.
Subfolder clr4 | Contains the files required to build TC plugin wrappers if managed plugin is developed with CLR4 (.NET Framework versions 4.0 and higher). Files are the same as in clr2 subfolder except for the following:
WrapperBuilder.exe.config | WrapperBuilder configuration specific for CLR4.

Store this folder on developer's computer and install main assemblies into the GAC using GAC_Install.bat or .msi files.
This folder should be accessible for any new managed plugin project. I recommend you to add it as subfolder to new project folder.

### 3.3. Folder 'Deployment'.

This folder contains two Windows Installer packages: TcPluginLib.msi and WpfLsHandlerBuilder.msi.
First package contains core assemblies required in order for any TC plugin developed with provided .NET Interface to work.
Second package contains TcWpfListerHandlerBuilder assembly required for WPF based Lister TC plugins.
Assemblies in these packages were compiled in Release configuration.

You have to provide these packages to the end user with your plugin. See details of package installation below.

### 3.4. Folder 'TcPluginSamples'.

This folder contains two sample solutions containing several sample TC plugins created with provided .NET Interface.
It’s good start point - please look through these samples before starting your own plugin.

Solution TcPluginSamples contains sample TC plugins created with .NET Framework 2.0.

FSSample | File System plugin sample - just local file system
FSSampleWithContent | The same as above with Content features
ListerSample | Lister plugin sample - simple text viewer with trace log. Created with Windows Forms user interface.
ListerSampleWpf | Lister plugin sample - simple text viewer with trace log. Created with Windows Presentation Foundation (WPF) user interface. (.NET Framework 3.5 required)
PackerSampleCS | Sample Packer plugin - MD5/SHA1 checksum generator/checker (idea of Stanislaw Y. Pusep)
PackerSampleZip | Sample Packer plugin - simple ZIP packer using ICSharpCode.SharpZipLib assembly
ContentSample | Simple Content plugin, shows additional file information columns
QSSample | Simple QuickSearch plugin

Solution TcPluginSamples_clr4 contains sample TC plugins created with .NET Framework 4.0 or higher (CLR4).

FSSample_clr4 | File System plugin sample - just local file system
ListerSample_clr4 | Lister plugin sample created with Windows Forms user interface. Simple file viewer with additional tab which displays TC calls to the plugin

## 4. How to create new TC plugin with provided .NET Interface.

### 4.1. Requirements.

0. First of all - you have to have a good idea for new TC plugin.
   Otherwise provided .NET Interface will not help you! :-)

1. IDE to create .NET assemblies. I used Microsoft Visual Studio (2008 and 2013).

   You can also try alternative IDEs, such as SharpDevelop, MonoDevelop or Embarcadero RAD Studio.

2. Content of the downloaded TcPluginCore folder.
   You can use it to create any number of different managed plugins.

   Install required core assemblies into the GAC using GAC_Install.bat or .msi files.

### 4.2. New plugin creation process.

Below are steps to create new File System (wfx) plugin called YourPlugin.
Creation of another TC plugins (wlx, wdx or wcx) is similar.

1. Create new .NET project YourPlugin.

2. I recommend you to add the folder TcPluginCore from this distributive as subfolder to new project folder.
   Actually you can keep this folder anywhere on your hard drive; check paths in the steps 3 and 9 in this case.

3. Add reference to assembly TcPluginCore\TcPluginInterface.dll.
   Set Copy Local property for the assembly to False.

4. Create a class implementing your plugin functionality.
   Inherit it from base class FsPlugin defined in TcPluginInterface assembly.
   (Use base classes ListerPlugin, PackerPlugin, ContentPlugin, or QSPlugin for another plugin types.)

5. Create constructor receiving one parameter of type StringDictionary - plugin settings dictionary.
   Do not forget to call the base constructor.

   public YourPlugin(StringDictionary pluginSettings)
   : base(pluginSettings)
   { <...Your code here...> };

6. Create override methods for all mandatory and some optional methods of plugin interface. (You can find all method descriptions in the dotNetPluginMethods.xlsx spreadsheet.)
   Any optional methods not overridden in your plugin will be excluded from the plugin wrapper.

7. Special cases:
   - If you need to implement Content features in your File System plugin - read additional information below.
   - If you need to managing the lifetime cycle for your File System plugin - read additional information below.
   - If you create Lister plugin with Windows Presentation Foundation (WPF) user interface- read additional information below.

8. Build your project in Debug mode.

9. Build plugin wrapper - intermediate layer between Total Commander and your managed plugin with proper .wfx extension.
   This wrapper is a real TC plugin using your managed plugin as a class library.
   Use WrapperBuilder.exe console application to do it (run "WrapperBuilder /?" for parameter details).

   - Preferred way is to add WrapperBuilder call to the post-build event of your project. Use following line to create both 32-bit and 64-bit wrapper versions:
     $(SolutionDir)TcPluginCore\clr4\WrapperBuilder.exe /wfx /p=$(TargetPath) /v /$(ConfigurationName)
     Important notes:
     - Select clr2 or clr4 subfolder depending on .NET Framework version used to develop your plugin.
       Use clr2 if your plugin is developed with the .NET Framework 2.0, 3.0, or 3.5.
       Use clr4 if you use the .NET Framework 4.0 or higher (see details).
     - Substitute wfx with wlx, wcx, wdx, or qs for other plugin types.
     - Add key /x32 to the command line if you want to create plugin wrapper for 32-bit version only.
       Key /x64 will create wrapper for 64-bit version only.

     By default WrapperBuilder creates wrapper file with the same name as your managed plugin assembly and w?x extension (tcmatch.dll file for QuickSearch plugin).
     You can change wrapper file name using WrapperBuilder /o key.

   - Also you can run it as a separate console application.

10. After the build your output folder will usually contain the following files:

    - YourPlugin.wfx -plugin wrapper, works as real TC plugin,
    - YourPlugin.wfx64 - 64-bit version of plugin wrapper (if you called WrapperBuilder with /x64 key),
    - YourPlugin.dll - managed plugin; your class library implementing main plugin features
11. Configure plugin - see details in Plugin Configuration section.
12. After the full cycle of debugging rebuild your project in Release mode for deployment.

## 5. How it works.

Assembly TcPluginInterface.dll in current .NET Interface provides following class hierarchy:

This layer provides base plugin functionality: configuration, communication with plugin loader, error handling and tracing capabilities, event handlers for callback functions, life cycle management.

Developer implements own managed class derived from one of the base plugin classes. It uses all flexibility and power of .NET Framework to implement main features provided in new plugin.

Managed plugin communicates with TC through plugin wrapper. This wrapper is a real TC plugin which methods are called by TC.
Wrapper templates (separate for each plugin type) are managed class libraries that translate TC calls into managed calls providing parameters marshaling and cross Application Domain boundary communication.
During the development stage WrapperBuilder program prepares wrapper template to become a real TC plugin:

- Excludes all optional methods not implemented in new managed plugin from the template (and so prevents TC from calling those methods), and
- Transforms template managed class library into standard Windows DLL. It allows TC to call its methods as standard DLL calls. (WrapperBuilder uses method described by Emilio Reale and Selvin to do it)

Following scheme describes how TC, wrapper and managed plugin interact with each other.
Code in blue block is part of TC code, red block is managed plugin code, and black blocks contain code from provided .NET Interface

1. Total Commander calls some plugin function from the wrapper.

If this is the first call to plugin, steps 2 - 5 will be executed.

2. Plugin Wrapper calls Plugin Loader to create an object for communication with TC.
3. Plugin Loader reads configuration (file YourPlugin.wfx.config - see details) and defines assembly and class required for loading.
   Then it creates application domain (AD) for new managed plugin, loads required assembly there, and tries to create remote object of required class in the new AD.
   Working in separate AD provides isolation and security boundaries for executing managed code.
4. Managed plugin constructor is called inside the plugin AD. It creates instance of required class. This instance is remote object whose methods will be called by plugin wrapper.
   Then plugin returns a proxy for created object over AD boundary.
   So, managed plugin assembly is loaded only into plugin-specific AD domain, not into the default one.
   Default AD only contains the code from the provided .NET Interface.
5. Plugin Loader stores returned proxy object in the Plugin Wrapper.
   This proxy is used to transfer any subsequent TC calls to the managed plugin.

6. Proxy calls appropriate method from the managed plugin, marshaling passed parameters to the managed types.
7. Managed plugin executes calling method and returns result.
8. Proxy transforms returned value to the required unmanaged type/structure, and returns result to TC.

## 6. Advanced notes.

### 6.1. Plugin Configuration.

Main plugin constructor receives one parameter of type StringDictionary - plugin settings, containing string key-value pairs.
Plugin settings are loaded from YourPlugin.w?x.config file (*.w?x64.config for 64-bit plugin version).
Loaded key-value pairs are stored in the property Settings of the TcPlugin class.

public StringDictionary Settings { get; private set; }

See Configuration tab of dotNetPlugins.xlsx spreadsheet for information about settings used by plugin loader and wrappers.

Each configuration key uses default value, so simple plugins can be written with no configuration file at all.
You can add more key-value pairs in your plugin specific configuration and access them via Settings property.

Following is an example of configuration file for simple Lister plugin:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="pluginAssembly" value="YourPlugin.dll"/>
<add key="pluginClass" value="YourPluginTest"/>
<add key="pluginTitle" value="Test Local File System"/>
<add key="writeTrace" value="true"/>
<add key="showAuthorInfo" value="false"/>
</appSettings>
</configuration>

### 6.2. Tracing.

Tracing is available for debugging purposes. It works only if you build you plugin in Debug configuration, not in Release one.

To switch tracing ON set the following parameters in the plugin configuration file to true:

- writeTrace
- writeStatusInfo (File System plugins only - allows to trace FsStatusInfo calls)

You also need to set tracing parameters in Total Commander. Use file Totalcmd.exe.config file in the TcPluginCore folder to do it.
Copy this file to the main TC folder. If you already have a file with this name, just add system.diagnostics section into it.
Then configure the output file for tracing (attribute initializeData in listeners.traceListener key) and desired trace level (attribute value in switches.DotNetPlugins key, see trace level details in the file)

Following plugin actions are traced:

- Details of plugin loading and unloading (traced by plugin loader),
- Call to every TC plugin method, different methods have different tracing levels - see methods spreadsheet for details (traced by plugin wrappers),
  WARNING: some methods (with trace level 4 - Verbose) can produce a lot of tracing information,
- File System plugins can also trace each FsStatusInfo call (by FS plugin wrapper, with Warning trace level),
- Any message from your plugin - just call method TraceProc defined in base TcPlugin class.

Single trace line looks like:

<date> <time_with_milliseconds> - <plugin_id>: <message>

<plugin_id> depends on plugin type and useTitleForTrace boolean configuration parameter:

Plugin type | useTitleForTrace | <plugin_id>
--- | --- | ---
Lister, Packer, Content(wdx) |  | Plugin Title (read from configuration)
File System, Content (part of FS) | true | Plugin Title
File System, Content (part of FS) | false (default) | FS Plugin Number (initialized during FsInit call)

So real trace lines look like:

03/14/14 14:27:43.166 - 33: SetCryptCallback: CryptoNumber=1819109126, Flags=1,781CBB4
04/07/14 12:04:47.649 - .NET Lister: SendCommand (401858, NewParams, Ansi, Center): OK

### 6.3. File System plugins: managing the lifetime cycle.

Base managed plugin classes are inherited from the MarshalByRefObject class to allow communication across application domain boundaries.

Some of MarshalByRefObject methods allow control over the lifetime policy for managed plugin instance.

If your plugin has sensitive and secure connection to some external server (SFTP, Database, etc.) it can be helpful to limit connection time in idle state.
This feature is implemented in the base File System plugin class FsPlugin.

FsPlugin-overridden method InitializeLifetimeService associates a lifetime lease object with the plugin. This lease object is periodically examined by the application domain lease manager.
After the lease expires the managed plugin instance become not accessible. It works like the timeout feature for remote objects.

Plugin sets lease properties via plugin configuration parameters:

- initialLifeTime - initial time for the lease. If it does not exist or is TimeSpan.Zero, then the lease will never timeout and the plugin associated with it will have an infinite lifetime.
- renewOnCallTime - amount of time by which any TC method call renews plugin lifetime.

Parameter values must be valid time interval strings (see help for System.TimeSpan for details).

You can override InitializeLifetimeService method in your File System plugin to implement more complex lifetime strategy, including leases's sponsor support.

See more details about remote object lifecycle in Microsoft documentation.

I didn't implement this feature for other plugin types (lister, packer or content) in the provided interface because it seems useless for plugins other than File System.
But it can be easy implemented for any plugin type if needed.

### 6.4. File System plugins: content features.

IFsPlugin interface doesn't have methods for corresponding FsContent* functions. It has property of type ContentPlugin instead.

You can implement Content features for your File System plugin in different ways:

- In the same class as file system methods (add IContentPlugin interface in class definition),
- In the separate class in the same assembly as file system class, or
- In the class in separate assembly.

Plugin loader uses configuration parameters contentAssembly and contentClass (in addition to pluginAssembly and pluginClass) to search for class that implements content methods.
If plugin loader finds no such class, wrapper builder will exclude all FsContent* methods from created File System plugin wrapper.

### 6.5. Lister plugins: WinForms vs. WPF.

You can use both Windows Forms and Windows Presentation Foundation (WPF) user interface to create managed Lister plugin.

You need to create your own visual container class and return an instance of this class as a result of call to Load managed plugin method.
Derive your container class from:

- System.Windows.Forms.UserControl if you use Windows Forms to create plugin, or
- System.Windows.Controls.UserControl if you use WPF

Then WLX wrapper embeds this container as a child into the parent Total Commander Lister window, creates handle for the container and returns this handler back to TC.

WLX wrapper uses IListerHandlerBuilder interface to create handler for the visual container created in managed Lister plugin.
Implementation of this interface for WinForms is included in TcPluginInterface assembly.
But for WPF this interface is implemented in separate TcWPFListerHandlerBuilder assembly.

If you use WPF to create managed Lister plugin, you need to inform WLX wrapper to use corresponding handler builder class.
Set listerHandlerBuilderClass configuration key to "WPF" in the plugin configuration file to do it.

Another problem with WPF based Lister plugins is that I cannot find how to make WPF visual container serializable. (Sorry, I'm not familiar with WPF development ☹)
As a result this visual container cannot be passed over Application Domain boundary. It requires to load WPF based Lister managed plugin into default Application Domain.
Set startInDefaultDomain configuration key to "true" to do it.

Finally you have to have the following keys in the plugin configuration file for WPF based lister plugins:

<add key="startInDefaultDomain" value="true"/>
<add key="listerHandlerBuilderClass" value="WPF"/>

### 6.6. WinForms Lister plugins: keyboard handling.

Content of the managed Lister plugin visual container is displayed inside the Total Commander Lister window.
We want managed plugin to send some keyboard shortcuts into the TC Lister menu, such as:

- 1, ..., 8 numbers to switch display mode (in Options menu),
- P and N to navigate to previous/next file (File menu),
- Ctrl+P to open Print... dialog (if Print method is implemented),
- Escape to close Lister window, etc.

When WLX wrapper loads visual container into the Lister window, it also sets keyboard handler that intercepts keyboard combinations defined in Lister menu and send them into parent window.

If new managed Lister plugin is WinForms based, visual container if derived from System.Windows.Forms.UserControl class.
Unfortunately, this class avoids getting the focus unless you take special programming tricks. It also won't respond meaningfully to keyboard messages even when it does have focus.

It's a reason to have special property in managed Lister plugin

public object FocusedControl { get; set; }

to notify WLX wrapper what visual control of WinForms based plugin will send keyboard shortcuts to the parent window.
Just set this property to the topmost visual control inside the visual container returned by Load method call.

Otherwise, if FocusedControl == null, WinForms based managed Lister plugin will not communicate to parent TC Lister window.

## 7. Deployment.

The following components have to be installed on the client computer to run newly-created plugin:

1. Microsoft .NET Framework,
2. Core assemblies from the provided .NET Plugin Interface,
3. Content of the output folder of the new plugin project.

Components 1 and 2 are required for any plugin built with provided Interface and should only be installed once on client computer.
Component 3 is specific for concrete plugin.

### 7.1. Microsoft .NET Framework.

Required version depends on version used to create new managed plugin.
Core .NET Interface assemblies require .NET Framework 2.0.
TcWpfListerHandlerBuilder assembly for WPF based Lister plugins requires .NET Framework 3.5.

In most cases .NET Framework is already installed on the client computer.
Client can download required version from the official site.

### 7.2. Core .NET Plugin Interface assemblies.

The preferred place for these assemblies is .NET Global Assembly Cache (GAC) on client computer.

Two assemblies from provided .NET Plugin Interface - TcPluginInterface and TcPluginTools - are required in order for any TC plugin developed with provided .NET Interface to work.
Deployment folder contains Windows Installer package TcPluginLib.msi used to install/remove the Release versions of required assemblies into the GAC.

Assembly TcWpfListerHandlerBuilder is required for WPF based Lister plugins developed with provided interface.
Windows Installer package WpfLsHandlerBuilder.msi is used to install/remove the Release version of this assembly into the GAC.

Installation package(s) has to be executed on the client computer before plugin installation.

If required assemblies were already installed on client computer before (during another managed plugin installation) - installation packages will show Repair/Remove screen after start.
In this case client can ignore installation.

### 7.3. Plugin folder.

After the full cycle of debugging plugin developer will have the following files in the output (Release) folder:

- Plugin wrapper, real TC plugin with appropriate extension (.wfx, .wlx, .wdx or .wcx),
- 64-bit version of plugin wrapper (with extension like .wfx64),
- Assembly file with the same name as plugin wrapper and .dll extension - managed plugin providing main functionality.

Also there can be some additional files, depending on new plugin architecture:

- Plugin configuration files (separate for 32-bit and 64-bit TC plugins),
- Additional assemblies implementing some specific parts of plugin functionality,
- Some third-party assemblies and their configuration.
  (If you need some common features not implemented in standard .NET Framework - encoding/decoding, access to specific data sources, etc).

You have to provide whole plugin folder for the client to deploy.

You also can add appropriate pluginst.inf file, pack your plugin folder, and deploy it using TC plugin auto-installation.

## 8. Source code for provided .NET Interface.

Source code is available at project's SourceForge page.

Code is provided under the MIT License.

Folder TcPluginCore contains full source code for Microsoft Visual Studio solution containing the following projects:

TcPluginInterface | Class library with interfaces and base classes for managed plugins.
TcPluginTools | Class library with classes for plugin loading, callbacks and error handling.
WfxWrapper | Class library with template for File System plugin wrapper.
WlxWrapper | Class library with template for Lister plugin wrapper.
TcWpfListerHandlerBuilder | Class library with plugin handler builder used to create WPF based Lister plugins.
WcxWrapper | Class library with template for Packer plugin wrapper.
WdxWrapper | Class library with template for Content plugin wrapper
QSWrapper | Class library with template for QuickSearch plugin wrapper
WrapperBuilder | Console application to build plugin wrapper DLL.
TcPluginLibSetup | Windows Installer project. Creates MSI file installing main plugin assemblies (TcPluginInterface and TcPluginTools) into the GAC.
WpfLsHandlerBuilderSetup | Windows Installer project. Creates MSI file installing TcWpfListerHandlerBuilder assembly into the GAC.

After solution build folder TcPluginCore\Build\Debug will contain the same files as in the distributed TcPluginCore folder.
Folder TcPluginCore\Build\Release will contain the same files as in the distributed Deployment folder.

Please contact to author if you have some questions.

Please let me know if this product is helpful for your development.
Also please send me links to the new TC plugins created with provided interface.