CInject – Extending code injection with plugins

December 4, 2011 Applications, CSharp, Open Source , , , ,

If you are new to CInject, please consider reading this article

Plugins? Yes, you can now create CInject plugins to customize CInject for your needs.  To develop a plugin, you do not need to master C# language, or understand Reflection, or Mono Cecil.  All you need to know is concepts of inheritance, and a little about working of CInject.  So lets not beat around the bush and get to the point.

How do I create a plugin?

To create your own plugin, create a Class Library project in Visual Studio 2010.  Let’s name the project as CInject.Plugin.Sample. The project output will be an assembly whose name should match the format





So lets right click the Visual Studio Project and click on Properties. In the tab “Application”, change the Assembly Name to CInject.Plugin.SamplePlugin. Next, we need to add reference to some assemblies

Adding Project References

  • CInject.PluginInterface.dll – This assembly is shipped with CInject and exposes interface IPlugin that we need to implement
  • System.ComponentModel.Composition.Codeplex – This assembly can be downloaded from CodePlex (MEF), or from the CInject package.
  • System.Drawing – This assembly is required for implementing Plugin Menus.
  • System.Windows.Form – This assembly is required as CInject is a Windows Application


Implemeting IPlugin


Let’s create a class called SamplePlugin.cs.  The name of the class has nothing to do with the name of the plugin so you can name it as you want.  This class needs to be decorated with Export attribute of MEF framework (found in namespace System.ComponentModel.Composition).  The Export attribute has 2 constructors, but for CInject we will use the constructor that takes one parameter i.e. Type.  So we decorate it with


Since we are developing the plugin for CInject, the class needs to implement the interface IPlugin and should have a valid Name, Version, Menu and an implementation of OnMessageReceived and HandleError.  Let’s understand the significance of the each member of IPlugin interface

  • Name – This is the name of the plugin [To be used in the next release]
  • Version – This is the version of the plugin [To be used in the next release]
  • Menu – If you want your plugin to display a Menu you can implement it; othewise, you can choose to return a NULL value (as shown in the code below)
  • OnStart – This method is called when the plugin is loaded into memory
  • OnClose – This method is called when the plugin is unloaded from the memory. This method should clean up the resources from the memory to allow successful closure of the application
  • OnMessageReceived – This method receives the events & messages from the CInject application. This method should ideally contain logic to handle the events and perform some plugin related logic
  • HandleError – Any technical unhandled errors raised while execution of OnMessageReceived, OnStart, and OnClose will be caught in HandleError method. This method should not throw any exception and should be written very carefully


SamplePlugin code
  1. using CInject.PluginInterface;
  2. using System.ComponentModel.Composition;
  3. namespace CInject.Plugin.Sample
  4. {
  5.     [Export(typeof(IPlugin))]
  6.     public class SamplePlugin : IPlugin
  7.     {
  8.         public string Name
  9.         {
  10.             get { return “SamplePlugin”; }
  11.         }
  12.         public string Version
  13.         {
  14.             get { return “1.0”; }
  15.         }
  16.         public System.Windows.Forms.ToolStripMenuItem Menu
  17.         {
  18.             get
  19.             {
  20.                 return null; // NULL – plugin does not have any menu
  21.             }
  22.         }
  23.         public void OnMessageReceived(EventType eventType, Message message)
  24.         {
  25.             // Implement logic for Message Received from CInject Application            
  26.         }
  27.         public void HandleError(System.Exception exception)
  28.         {
  29.             // This should never throw any exception            
  30.         }
  31.         public void OnStart()
  32.         {
  33.             // Should read configuration, initialize variables, etc
  34.         }
  35.         public void OnClose()
  36.         {
  37.             // Should clean up the memory resources
  38.         }
  39.     }
  40. }


Handling the events & messages


There are multiple events that CInject application raises. Let’s have a quick look at them

  • ProcessStart – Called when overall processing starts
  • MethodInjectionStart – Called before an assembly method is injected
  • MethodInjectionComplete – Called after an assembly method is injected
  • ProcessComplete – Called when overall processing completes
  • TargetAssemblyLoaded – Called when a target assembly is loaded
  • InjectionAssemblyLoaded – Called when an injection assembly is loaded
  • ApplicationStarted – Called when CInject application has started
  • ApplicationClosing – Called when CInject application is closing
  • Error – Called when an error occurs within CInject application.  This is different from HandleError that handles the unhandled exceptions raised by plugin code


OnMessageReceived code
  1. public void OnMessageReceived(EventType eventType, PluginInterface.Message message)
  2.         {
  3.             switch (eventType)
  4.             {
  5.                 case EventType.ApplicationClosing:
  6.                 case EventType.ApplicationStarted:
  7.                     break;
  8.                     // Here Error property will be null
  9.                     // Only Result will be non-null  
  10.                     MessageBox.Show(“I received a injection related message: “ + message.Result);
  11.                 case EventType.TargetAssemblyLoaded:
  12.                 case EventType.InjectionAssemblyLoaded:
  13.                     break;
  14.                     // Here Error property will be null
  15.                     // Only Result will be non-null with injector/target assembly path
  16.                     MessageBox.Show(“I received a injection related message: “ + message.Result);
  17.                 case EventType.MethodInjectionStart:
  18.                 case EventType.MethodInjectionComplete:
  19.                     // Here Error property will be null
  20.                     // Expect Target, Injector will be non-null
  21.                     MessageBox.Show(“I received a injection related message: “ + message.ToString());
  22.                     break;
  23.                 case EventType.ProcessComplete:
  24.                 case EventType.ProcessStart:
  25.                     // Here Error property will be null
  26.                     // Expect only the Result to be non-null
  27.                     MessageBox.Show(“I received a process related message: “ + message.Result);
  28.                     break;
  29.                 case EventType.Error:
  30.                     MessageBox.Show(“I received an error message: “ + message.Error);
  31.                     break;
  32.             }
  33.         }


Compiling and deploying

You can now compile the class library to create a plugin named CInject.Plugin.SamplePlugin.dll and deploy it in Plugins sub-folder in the CInject application.  The CInject application automatically scans for

  • Assemblies that match the name pattern CInject.Plugin.AnyNameHere.dll
  • Searches for IPlugin implementation(s) with Export attribute within the searched assembly CInject.Plugin.AnyNameHere.dll
  • Loads them in memory and raises events OnStart, OnMessageReceived (with EventType ApplicationStarted) in same order
  • Unloads them from memory when application is closed and raises events OnClose, OnMessageReceived (with EventType ApplicationClosing) in same order



CInject – Code Injection with Runtime intelligence

October 4, 2011 CSharp, Open Source, Visual Studio , , , ,

CInject adds more value to your existing applications by injecting runtime intelligence.  You can use injectors provided by with CInject, or define your own injector.

This article will highlight some cases where you can directly use CInject

Existing application has no or very little logging
Application is performing slower than I expected
Don't know what gets passed as arguments to few methods

Using Injectors with CInject

September 28, 2011 CSharp, Open Source, Visual Studio, Winform , , , , ,

If you don’t know what is CInject, I would recommend you to read this article and get the latest version of CInject from CodePlex website.

There are few injectors that are shipped with CInject

  • LogInjector – Allows injecting logging in any .NET assembly/executable even if you do not have code of the assembly/executable.  LogInjector is built on .NET 4.0 Client Profile and uses log4net for logging purpose
  • PerformanceInjector – Allows logging the time required to execute injected method in the target assemblies
  • ObjectValueInjector – Allows getting any property of arguments passed to the injected method

You can get started with directly using them without writing a single line of code.


Quick Guide to using CInject

So, to get started all you would require is to

  • Download the latest stable version of CInject and unzip it to, lets say, C:\CInject
  • Locate the assemblies (DLL) / executables (EXE) that need to be injected with along with their configuration files
  • Locate your injectors assembly (DLL) and their configuration files.
  • Open the downloaded CInject application [C\CInject\Cinject.exe]
  • Choosing the Target Assembly
    • If you are targeting a single assembly (to be injected), click on Assembly > Load Assembly (F3).  As soon as you select the assembly, CInject will try to create a tree of classes and methods in the assembly.
    • If you are targeting multiple assemblies (to be injected), click on Assembly > Select Directory (F2).  CInject will browse through DLLs and EXEs in the directory and create a tree of classes and methods in each assembly or executable
  • Choosing the Injector Assembly
    • Auto Load – If you have copied the injector assemblies into CInject directory [here, C:\CInject], they will be automatically loaded in CInject
    • Manually Load – Click on Assembly > Load Injector (F4).  This will load the injectors
  • Select all the classes/methods (in the blue panel) that you would want to inject. Then, select the LogInjector (in the yellow panel)
  • You can click on ‘Add selected injectors to selected methods in target assembly’.  This will add some entries in the grid (Assembly, Method, Injector).  However, this does not mean that the assembly has been injected.  If by mistake you have selected a wrong injector or a method, you can remove them by selecting it in the grid and clicking ‘Remove selected row’
  • Select Inject > Run (F5) to inject and proceed ahead to inject the target assemblies.
  • You will be prompted when the injection has been completed.  With CInject 1.4, all the required files for each injector will be automatically copied to the folder of target assembly
  • You can now execute the target assembly. This is the new assembly with selected injectors

LogInjector Configuration

You can alter the log configuration by editing LogInject.log4net.xml based on the Apache log4net configuration.

Currently, LogInjector supports DEBUG, INFO and ERROR modes

  • Debug:   Prints additional information such as calls to the destructor of the method, type of parameter to each method invoked
  • Info: Just logs the name method invoked
  • Error: Logs exceptions if LogInjector fails at any point

Apart from the method information, it logs Data-Time, Thread Id, and Assembly.  You can configure these details in the xml file accompanied with the CInject executables.

In case you would want to use any other version of .NET, you would have to rebuild the code in Visual Studio.

PerformanceInjector Configuration

PerformanceInjector also uses log4net for logging the performance of the methods.  The configuration can be mentioned in loginject.log4net.xml file.

PerformanceInjector supports only INFO level of logging.

ObjectValueInjector Configuration

ObjectValueInjector uses ObjectSearch.xml to define which property needs to be retrieved in the arguments to the injected methods.

If the defined property (in configuration) does not exist in the argument, this injector does not throw any exception.  If the defined property (in configuration) exist in the argument, injector will try to get the value of the property.  If property value is NULL, it will log <null>

ObjectValueInjector uses DEBUG level of logging

CInject – Quick Guide to get started with building your injectors

September 28, 2011 CSharp, Open Source, Visual Studio , , , , ,

If you don’t know what is CInject, I would recommend you to read this article and get the download latest version of CInject from CodePlex website.

Creating a Basic Injector

Once you have the latest executable, you can follow through these steps to create your own injector

Create a new Visual Studio Class Library Project (C# or VB.NET) and add a Reference to CInject.Injections.dll.  You will find this assembly with the CInject application


Add a class called ‘MyInjector’ that derives from ICInject interface.  This interface is part of CInject.Injections reference

The MyInjector class would look like


using CInject.Injections.Interfaces;

namespace InjectorLib
    public class MyInjector : ICInject
        public void OnComplete()
            // This is called before exit of injected method

        public void OnInvoke(CInject.Injections.Library.CInjection injection)
            // Called at the entry of injected method

            // To get the arguments passed to injected method
            var arguments = injection.Arguments;

            // To get value of property Text in any argument
            var propertyValues = injection.GetPropertyValue("Text");

        public void Dispose()
            // dispose here if you want to

Compile the Visual Studio Project to create a DLL named MyInjector.dll and follow the steps mentioned in Using Injectors in CInject

Adding Configuration to your Injector

Adding configuration to an injector is similar to adding a configuration to any other project.  You can choose from one of the following ways

  1. Rely on the configuration to be added in the configuration (app.config / web.config) of the target assembly / executable
  2. Add an independent configuration file (say, myconfig.xml) that needs to be copied in the target assembly/executable folder
  3. Add an independent configuration file and retrieve it from a Network Shared drive

I would not recommend Point -1 as it may cause conflicting configurations.  To use step 2, you can use a very handy feature of CInject

Let’s say that your configuration file is myinjector-configuration.xml and it is added to the Visual Studio Project

You need to change the property of the configuration file to ‘Copy Always’ and decorate your injector class with DependentFiles attribute

using CInject.Injections.Attributes;
using CInject.Injections.Interfaces;

namespace InjectorLib
    public class MyInjector : ICInject
        #region Code

        // Other code here


When CInject applies this injector to any assembly, it ensures that it copies myinjector-configuration.xml to root folder of target assembly / executable.

You can access this configuration file in code using standard .NET libraries


What if I some dependent / referenced assemblies as well?

Dependent / Referenced assemblies in your injector work same as configuration files.

You just have to mention them in the DependentFiles attribute and ensure that they are in the same directory as that of the injector.





Follow on Feedly