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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.