• Integrating .Net & Maya 2009 UI – Pt 1

    This article is specific to Maya 2009, I have also created an updated tutorial for Maya 2012 (64bit) Developers

    In this multi-part tutorial we’ll be covering two main areas, embedding .Net forms within Maya and extracting Maya UI components and embedding them within your .Net dialogs. To get this to work we will be exploiting the windows messaging system and as a result, this will only work on Windows based systems. This technique is not exclusive to Maya and can be used for many other applications and has saved me on many occasions. Please understand that this tutorial is aimed at intermediate users of .Net and Maya Python scripting, as there will be some C# code used to interface with the windows messaging system and Python code to load the .Net windows within Maya. If you want to learn more about the following concepts you can check out the Addition Resources I have included.

    There are some drawbacks to using .Net dialogs within Maya, namely debugging and error handling, so please take this into consideration before implementing it within your pipeline. For this demo I will be using Visual Studio C# Express 2010, but the concepts and code can be used within other software versions.

    Also throughout this tutorial I will be referring to C# and Maya Python code that has been condensed to save on space but I have included the full Part 1 source code and solution for your viewing pleasure

    By the end of this multi-part tutorial you will be able to embed your .Net Dialogs within Maya 2009 (32bit) properly, extract Maya UI components and embed them within your .Net application, and have a basic understanding of windows messaging. Recently Maya's UI has switched over to Qt, which mean some of the code listed here will not work, I will be adding an addendum tutorial to show the alterations that need to be made for Qt versions of Maya.

    I have broken the tutorial up into a couple of parts:

    1. Creating the .Net application
    2. Connecting Maya with .Net using Python
    3. Embedding the .Net window within Maya
      1. Windows, controls & HWND’s
        1. Finding a windows HWND
        2. Windows Modifier
      2. C# code used to parent UI
        1. Code References
        2. Find and Parent code
      3. Maya code used to spawn UI

    Creating the .Net application

    Let’s start by creating a C# (Windows Forms Application) solution; I have created one called MayaUITutorial. I renamed Form1 to embedForm, this will contain code to find a specific Maya window and embed itself into it.


    Fig 1.0

    In this image I have added a single button and removed the window’s border from the embedForm so it can be embedded cleanly within Maya.

    Connecting Maya with .Net using Python

    First things first, to run any .Net code within Maya you need to have installed Python.Net for Maya 2009 (Python 2.5) and instead of writing it all out again, my mate Seth Gibson has put together a mid level tutorial just on this: http://tech-artists.org/wiki/PythonNetInMaya If your Python.Net is up and running I would still recommend you take a look at this tutorial and become familiar with the interface.

    Now that we have .Net setup and running in Maya, let’s get stuck right into the best bits.

    Embedding .Net in Maya

    One of the main issues with spawning a .Net window within Maya is having it sort correctly, minimize/maximize with the Maya window and not displaying in the task bar as if it were a separate application. Although this can be done with Windows messaging it can be simplified by parenting the .Net window within a native Maya window. By doing this simple trick you solve the major issues associated with the spawning and destruction of.Net windows. To complete this parenting work around we can use the windows messaging system to our advantage.

    Windows, Controls & HWND’s

    Every window and control within Windows has a “Windows Handle” or HWND; this is a unique address that identifies the UI and what messages it receives. In addition to this ID each UI has an owner or parent which can also pass messages onto its children e.g. If a parent window is told to minimize then its children will also follow.

    Finding a window’s HWND

    When a window is created it is assigned a HWND, it is more than extremely rare for a window to have the same ID as when it was last created. To find the correct window that we want to access we need to assign a unique name/ title to it so we can identify it from all the other similar controls. Later on we will be running through some code that will search for this unique window, as part of the function call we will need to include the UI class name. There are a couple of ways to find what a control’s class is;  if you have the Professional version of Visual Studio there is a tool called “Microsoft Spy++”, otherwise you can get an app called “Windows Modifier”. For this tutorial we’ll be using Windows Modifier as it has a couple of extra features that we can use to our benefit.

    Windows Modifier

    Windows Modifier is as the title suggests a tool to modify windows. In addition to investigating the window's Class and HWND it has the ability to modify the size, state and the parent of a particular window. With this you can test out UI changes and parenting without even writing a line of code.


    Fig 2.0

    In the image above we can see that Windows Modifier has two ways to display its UI Tree (Window Text and Class Name). When we call the find function within C# we will be using both the text and class name of the selected window to get the correct HWND of the window, so take note we will be using this in the next section.


    Fig 2.1

    As a side note, in this image we have a Maya window that has had its UI modified as a demonstration of what is possible with windows messaging, after a form has been created. It is quite easy to move elements of a window to fit the needs of your interface. We will be focusing more on this in part 2 of the tutorial.

    Alright… enough talking, let’s get stuck into some juicy code.

    C# Code used to Parent UI

    To embed a .Net window within a Maya window we need to write some code in both C# and Maya. The C# code will be responsible for finding the Maya window and attaching itself within it. Maya will then create the unique window and call the necessary code to initiate the .Net form creation and attachment. Let’s start with the C# code first as it will make things a little clearer down the track.

    C# Code References

    The following condensed code is taken from the emebedForm:

    using System.Runtime.InteropServices;
    namespace MayaUI
    {
        public partial class embedForm : Form
        {
            // Include SetParent Reference
            [DllImport("User32", CharSet = CharSet.Auto, ExactSpelling = true)]
            internal static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndParent);
     
            // Include hWnd of a selected window references
            [DllImport("user32.dll", SetLastError = true)]
            static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
     
            [DllImport("user32.dll", SetLastError = true)]
            static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    First of all we need to include System.Runtime.InteropServices to get access to the DllImportAttribue creating references to SetParent (Setting the parent of a particular UI), FindWindow and FindWindowEx (Finding a window’s HWND based on a combination of the window title, class and parent). Using this in conjunction with a unique windows title we are able to get the correct HWND. These imports enable us to use shared unmanaged code within our managed application, or in other words, giving us access to the Windows API (WIN32 API)

    NB: In the case that you are making multiple instances of your window you will have to pass the unique name to the form at time of creation. For this tutorial however we will assume that the window will not be instanced.

    Find and Parent code

    The following condensed code is used to search and attach the .Net window within a specifically named Maya window. As we are only looking for the window’s HWND there isn’t an awful lot of code in this example but in the next tutorial we will be digging a little deeper into a window’s components so you’ll get a couple more lines to check out.

    public partial class embedForm : Form
    {
        public void Embed_Control()
        {
            //Set the name and Class of the Maya blank window
            string lpszParentClass = "AfxFrameOrView80";
            string lpszParentWindow = "Embed Viewport.NET";
     
            IntPtr ParenthWnd = new IntPtr(0);
     
            /* Attach the .Net Form into the Maya blank window */
            ParenthWnd = FindWindow(lpszParentClass, lpszParentWindow);
            SetParent(this.Handle, ParenthWnd);
        }
     
        private void embedForm_Load(object sender, EventArgs e)
        {
            Embed_Control();
        }
    }

    I created a new procedure called Embed_Control and have set it to run on form load. I have set the Parent Class and Parent Window Names based on the information I obtained from Windows Modifier and the unique name I gave my window. FindWindow is then called using this information and the result is a HWND to the Maya window. Now we only need to call SetParent using the .Net Forms HWND (this.Handle) as the child and the Maya window HWND as the parent. We now have a .Net window embedded.

    Maya code used to spawn UI

    The following code is taken from the Demo.py file; it contains the imports and Embed Class functionality you will need for Part 1 of the tutorial.

    # Load all required Modules
    import clr
    import sys
    import threading
    import maya.cmds
     
    # Add path to Maya .Net DLL
    sys.path.append( ' Path to MayaUITutorial.dll ')
     
    # Add Reference to the .Net Tutorial Runtime Lib
    clr.AddReference('MayaUITutorial')
    import MayaUI
     
    ##############################################################################
    ## EMBED CLASS
    ##
     
    class MayaUITutorial_Embed():
     
        def __init__(self):
            # Create ref .Net embedForm
            self.Form = MayaUI.embedForm()
     
            # Attach function to Button event
            self.Form.cmdButton.Click += self.cmdButton
     
        def Show(self):
            # Create a Maya window for the .Net to attach in
            self.MayaWindow = maya.cmds.window( title='Embed Viewport.NET', iconName='.Net Demo', widthHeight=(350, 250) )
     
            # Spawn and start new thread for .Net window
            formThread = threading.Thread( target = self.Form.Show(), args = () )
            formThread.start()
     
            #Display the Maya window
            maya.cmds.showWindow( self.MayaWindow )
     
        def cmdButton(self, *args):
            print 'Cmds Run'

    In the above code, I have imported the necessary CLR, SYS and Threading modules. In the __init__ method I created an instance of the embedForm and connected the event handler for the button on the form. We call the Maya window create method at this point as we need to have a window to attach to. The core part of this python code is within the Show method, it is very similar to the example shown in Seth’s tutorial except in the thread creation where I have used .Show() instead of .ShowDialog(). We want to have the dialog as a non-modal window ( doesn’t draw exclusive focus, i.e. File Dialogs) so we can have it open constantly while we work. Lastly we call the show method of the Maya window.

    The creation of this window is the core element of the whole two tutorials. Making sure that this is a unique name is imperative to making it all work. Then we can spawn the window using:

    import Demo
    MayaUITutorialEmbedWindow = Demo.MayaUITutorial_Embed()
    MayaUITutorialEmbedWindow.Show()

    And we can get access to the Maya window to modify it using:

    maya.cmds.window( MayaUITutorialEmbedWindow.MayaWindow, edit=True, widthHeight=(150, 170) )

     

    In Part 2 we will be looking at embedding Maya UI in .Net dialogs.
    So stay tuned...

    Additional Resources

     
     


    1 responses to “Integrating .Net & Maya 2009 UI – Pt 1”


     Leave a reply