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:
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.
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.
And here is what I see in Solution Explorer
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.
I’ll follow the normal steps to create a C# project…
Notice that this project called “VisUtil” and is a C# class library and that this project will be created underneath the “ironvisio” folder.
The screenshot below confirms its location
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.
In this particular case, I am going to refer to the Visio 12.0 Type library (i.e. the one for Visio 2007).
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.
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.
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.
We could try editing the “Search Path”
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:
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.
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()
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.
Fantastic.
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.
And just to be clear, the reference to IVisio is working fine with Intellisense.
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.