2009
11.18

Recently I had a need to utilize functionality written in Python, but was restricted to doing it from a C# application. The Python code was legacy and not easily duplicated, so I wanted to leverage it if at all possible. Iron Python, which is an implementation that runs under .NET, was a possibility, but seemed a bit much just to get some information out of existing Python code.
I ran across a great series on devshed.com about how to create a COM server in Python. Step 1 solved. The next question was how to call it from C#, since there was no way to create a typelib from Python. Good old late binding to the rescue.
Following is the code I ended up creating. This Python code just calls string.swapcase, but hopefully it is enough to give you the idea. (You need the win32com Python for Windows extensions installed first: http://sourceforge.net/projects/pywin32/)

Create TestServer.py with the following contents:

import win32com.server.register

class PythonUtil:
  _public_methods_ = [ 'SwapCaseString' ]
  _reg_progid_ = "PythonUtil.Utilities"
  # NEVER copy the following ID
  # Use "print pythoncom.CreateGuid()" to make a new one.
  _reg_clsid_ = "{691830C5-6322-48b0-B1D3-0055657757D5}"

  def SwapCaseString(self, val, item=None):
    import string
    if item != None: item = str(item)
    return string.swapcase(str(val))
    
	
# Add code so that when this script is run by
# Python.exe, it self-registers.
if __name__=='__main__':
  print "COM server being registered..."
  import win32com.server.register
  win32com.server.register.UseCommandLine(PythonUtil)
  

This .py file must be run once from the command line to register the COM server.

Awesome. Now my Python COM server is ready to go. How to call it from C#?

Since I don’t have a typelib that would allow Visual Studio to create a nice wrapper class, I have to revert to a late binding solution. Late binding is just the process of invoking a method at run-time without the compiler knowing about it ahead of time.
Late binding IDispatch calls have been around since COM was invented (I think?), so all I had to do was find how to do them in the huge .NET documentation marshmallow. It turns out that Activator is the class that will do the job.
Here’s the C# client side of the code:

using System.Runtime.InteropServices;
using System.Reflection;

object instance = 
 Activator.CreateInstance(Type.GetTypeFromProgID("PythonUtil.Utilities"));
if (instance != null)
{
    Type type = instance.GetType();
    string swap = "Swap Case This String";
    object[] paramList = { swap };  //1 string in params

    object objRet = type.InvokeMember("SwapCaseString", 
     BindingFlags.Default | BindingFlags.InvokeMethod, 
     null, instance, paramList);
    string myString = (string)objRet;  
    //myString should now hold "sWAP cASE tHIS sTRING"
}

Just make sure the ProgID strings are the same on both the Python and C# sides and everything should work great.
This is a simple example, but hopefully you can extend it to solve some problems you are facing.
midniteblogger.