The last blog post was a peek ahead. But we need to go backwards a bit because if we continue on that path in a naïve way, what you are going to see is that to fully exploit capabilities of Visio via IronPython is going pose some challenges:

  • First, we will have to deal with a lot of .Net and COM Interop issues and this because more complicated when going through IronPython
  • Second, we’d rather focus on drawing nice infographics not learning the the internal details of Visio’s automation API
  • Third, (trust me on this) we’ll have to write a lot of code

Again we want to focus on drawing nice graphics very easily via IronPython and the simplest way is to reuse some existing library. Fortunately I have such a library available. But in order to use it, we need to learn some basics about how our IronPython project can reference C# code written in another project. Doing this from a C# project to another C# project is easy: you simply “Add Reference” in Visual Studio. With IronPython it isn’t hard, but it isn’t quite as easy and it certainly isn’t obvious.

UNDERSTANDING THE PROJECT AND SOLUTION

As a mentioned in my previous blog post, I created a realy solution and project to host the “ironvisio” demo code. You can see the files on disk below.

image

And here is what I see in Solution Explorer

image

NOTE: Some of you may find the green and red icons next to the files unfamiliar. These are the icon from VisualHg. All this code is in a (public) Mercucrial source code repository and VisualHg makes it easy for me to deal with the repository without leaving Visual Studio.

CREATING A NEW C# PROJECT

I’ll follow the normal steps to create a C# project…

image

image

Notice that this project called “VisUtil” and is a C# class library and that this project will be created underneath the “ironvisio” folder.

image

The screenshot below confirms its location

image

Keep in mind the binaries will be under “bin/Debug” inside the “VisUtil” folder.

I’m going to have this library do some drawing on a Visio Page object. So the project needs a reference to Visio.

image

In this particular case, I am going to refer to the Visio 12.0 Type library (i.e. the one for Visio 2007).

image

 

 

And although it won’t matter too much – just notice that the the project is a .NET 3.5 project.

Solution Explorer clearly shows we have successfully added the reference.

image

Now rename Class1.cs to DrawUtil.cs and enter the following code.

using IVisio = Microsoft.Office.Interop.Visio;

namespace VisUtil
{
    public static class DrawUtil
    {
        public static IVisio.Shape DrawCircleFromCenter(IVisio.Page page, double x, double y, double r)
        {
            var shape = page.DrawOval(x - r, y - r, x + r, y + r);
            return shape;
        }
    }
}

All this code does is make it easy to draw given a center point and a radius.

 

Build it and everything should compile.

 

REFERENCING THAT PROJECT

Now the slightly complicated part. How should the “DemoIronVisio” project refer to the “VisUtil” project?

As you can see there is no “Add Reference” on the “DemoIronVisio” project.

image

We could try editing the “Search Path”

image

But this is flawed because, we will have to enter an absolute path. And that is going to break if we move the solution anywhere else on disk.

What we need is a way to refer to the “VisUtil” project relatively. That is, we must refer to the location of the VisUtil.DLL file relative to the “current” position of the demo.py file while demo.py is running.

So how to figure this out?

Let’s replace all of the code in demo.py with the following and see what paths are available in sys.path

import sys
import clr
import System
import os

print sys.path

System.Console.ReadKey()

this will print:

image

So the good news is that the location of demo.py is in sys.path as you can see from the screenshot. (In fact it is there twice for some reason). We could use this method to figure out the relative location of the “VisUtil.DLL” file.

But I believe a more reliable way is to use __file__.

import sys
import clr
import System
import os

print __file__

System.Console.ReadKey()

This shows the exact location of the script.

image

So now we need to construct the valid path to the VisUtil.py

 

import sys
import clr
import System
import os

print __file__

script_path = System.IO.Path.GetDirectoryName(__file__)
visutildll_file = System.IO.Path.Combine( script_path, r"VisUtil/bin/Debug/VisUtil.Dll" )

print
print
print "Location of VisUtil.Dll:", visutildll_file
print
print
print "Found the DLL:", System.IO.File.Exists(visutildll_file)

System.Console.ReadKey()

 

image

To load the assembly we’ll do this:

script_path = System.IO.Path.GetDirectoryName(__file__)
visutildll_file = System.IO.Path.Combine( script_path, r"VisUtil/bin/Debug/VisUtil.Dll" )
clr.AddReferenceToFileAndPath( visutildll_file )
import VisUtil

So the full script will look like this:

import sys
import clr
import System
import os

script_path = System.IO.Path.GetDirectoryName(__file__)
visutildll_file = System.IO.Path.Combine( script_path, r"VisUtil/bin/Debug/VisUtil.Dll" )
clr.AddReferenceToFileAndPath( visutildll_file )
import VisUtil


from ironvisio import *

app = IVisio.ApplicationClass()
docs = app.Documents
doc = docs.Add("")
page = app.ActivePage

VisUtil.DrawUtil.DrawCircleFromCenter( page, 2, 4, 1.5)

System.Console.ReadKey()

 

When run, this this what you will see.

image

Fantastic.

INTELLISENSE PROBLEMS

And now we encounter our first real irritation. Intellisense doesn’t seem to work well (i.e. so far not at all) in this case. So for example, if I type “VisUtil” and press “.” I see only the following.

image

 

And just to be clear, the reference to IVisio is working fine with Intellisense.

image

I still have yet to sort out what the source of the problem is or how to address it. I will let you learn what I discover in future posts.