Saturday, November 24, 2007

How to Generate RCW on the fly in your Nant Scripts

Have you ever tried to remember a research you've done couple of years ago and you're desperate to get your hands on the old code?  And the frustration of trying to remember what you did exactly, if you're unable to find or don't have access anymore to the source?

Well, I ran into one today:

Couple of years ago, I had to implement a build process for one of my projects.
One of the modules was a port from VB 6.0 (to VB.Net) and it was using MSXML2!

I wanted to generate the RCW on the fly for MSXML2.  Now, I want the solution to be generic enough to use on any project that uses interop.

I wrote a function:

<?xml version="1.0" encoding="utf-8"?>

<project>

<script language="C#" prefix="tlb">

    <imports>

        <import namespace="System" />

        <import namespace="System.Runtime.InteropServices" />

    </imports>

 

    <code>

    <![CDATA[

        <!-- Code Goes Here -->

 

    ]]>

 

    </code>

 

</script>

</project>

 

Here's the CDATA Section.  Given here to preserve formatting:

[DllImport("oleaut32.dll", PreserveSig=false)]

private static extern void QueryPathOfRegTypeLib(ref Guid guid, ushort majorVer, ushort minorVer, uint lcid, [MarshalAs(UnmanagedType.BStr)] out string path);

 

[Function("find-path")]

public string GetTypeLibPath(string guid, ushort major, ushort minor, uint lcid)

{

    Guid actualGuid = new Guid(guid);

    string tlbName = null;

 

    try

    {

        QueryPathOfRegTypeLib(ref actualGuid, major, minor, lcid, out tlbName);

    }

    catch (COMException e)

    {

        //Typelib wasn't found - tlbimp will barf

        //when the compile happens, but we won't worry about it.

        Console.WriteLine("[find-path] " + "ERROR!!! " + e.Message);

    }

 

    return tlbName.TrimEnd();

 

}


 

Now, wherever I wanted, I could use it thus:

<!-- Find out location of MSXML2 and create an interop assembly-->

<property name="com.typelib.fullpath"  value="${tlb::find-path('F5078F18-C551-11D3-89B9-0000F81FE221',3,0,0)}"/>

 

<!--

  Somehow the return value from the find-path function contains a character

  at the very end causing <tlbimp> to fail.  Removing the last character from

  the property as a workaround.     

-->

<tlbimp typelib="${string::substring(com.typelib.fullpath,0, string::get-length(com.typelib.fullpath)-1)}"

        output="${source.baseFolder}/Intouch8/bin/MSXML2.dll"

    />


The function I was trying to remember was the API call: QueryPathOfRegTypeLib.
Oooff... (sigh of relief).

Now that I've blogged it, I am sure I will find it next time :)

 

Technorati Tags: , ,

No comments: