3

I wonder if there is some way to encapsulate a python script as a COM object.

I've seen that many topics talk about invoking a COM component from python, but I am interested in the opposite: to create a COM component that is in fact python.

I have some libraries made in python that I want to be called from an excel spreadsheet, and I think this could be a good way to do this.

2
  • Unfortunately it is not easy to build a COM object without the help of a library. There are different Python libraries helping to use external COM objectes, but I know none able to easily build a callable COM object. So I am afraid that current question is too broad for this site. My advice would be to create such an object in C++ with ATL and have it call Python code, but example code would be way too large for a SO answer. Commented May 13, 2018 at 22:00
  • Perhaps this could help: github.com/mhammond/pywin32. There's an example which seems to create a COM object: github.com/mhammond/pywin32/blob/master/com/win32com/servers/… Commented May 14, 2018 at 0:19

1 Answer 1

2

One way to perhaps do this would be to create a COM object using .NET and execute Python code using IronPython.

Here is an idea of how it could work:

using System;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;
using IronPython.Hosting;

namespace PythonComObject
{
    [Guid("F34B2821-14FB-1345-356D-DD1456789BBF")]
    public interface PythonComInterface
    {
        [DispId(1)]
        bool RunSomePython();
        [DispId(2)]
        bool RunPythonScript();
    }

    // Events interface 
    [Guid("414d59b28-c6b6-4e65-b213-b3e6982e698f"), 
    InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface PythonComEvents 
    {
    }

    [Guid("25a337e0-161c-437d-a441-8af096add44f"),
    ClassInterface(ClassInterfaceType.None),
    ComSourceInterfaces(typeof(PythonComEvents))]
    public class PythonCom : PythonComInterface
    {
        private ScriptEngine _engine;

        public PythonCom()
        {
            // Initialize IronPython engine
            _engine = Python.CreateEngine();
        }

        public bool RunSomePython()
        {
            string someScript = @"def return_message(some_parameter):
                                      return True";
            ScriptSource source = _engine.CreateScriptSourceFromString(someScript, SourceCodeKind.Statements);

            ScriptScope scope = _engine.CreateScope();
            source.Execute(scope);
            Func<int, bool> ReturnMessage = scope.GetVariable<Func<int, bool>>("return_Message");

            return ReturnMessage(0);
        }


        public bool RunPythonScript()
        {
            ScriptSource source = _engine.CreateScriptSourceFromFile("SomeScript.py");
            ScriptScope scope = _engine.CreateScope();
            source.Execute(scope);               
            Func<int, bool> some_method = scope.GetVariable<Func<int, bool>>("some_method");
            return some_method(1);
        }
    }
}

I haven't tried this, it is just an idea, I hope it works or at least get you in the right direction.

Some helpful references:

https://blogs.msdn.microsoft.com/seshadripv/2008/06/30/how-to-invoke-a-ironpython-function-from-c-using-the-dlr-hosting-api/

http://ironpython.net

https://www.nuget.org/packages/IronPython/

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I will have a close look at that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.