Showing posts with label Interop. Show all posts
Showing posts with label Interop. Show all posts

Learn Something New Every Day...

Recently I started jotting down anything new that made me say "oh cool!". Some are rarely used C# language features, some are API mechanics, and some are just random trivia. Here's what I've come up with so far:

C#'s stackalloc Keyword

stackalloc is basically handy way to allocate an array on the stack and can provide several conveniences.

Instead of allocating a locally scoped array (which is backed by the heap and managed by the garbage collector), you can get better "bare metal" performance by using stackalloc:

float SomeFunction(float[] input)
{
float dataResults;
float[] data = new float[3];
// we are calculating a result from input and storing interim results in data
return dataResults;
}

At the end of this method, a float array is sitting around waiting to be garbage collected. Instead, that function can become:

unsafe float SomeFunction(float[] input)
{
float dataResults;
float* data = stackalloc float[3];
// do something with the data and input
return dataResults;
}

In addition to taking the garbage collector and heap allocation out of the equation to eek out a little more performance, you also get a native float pointer. This can make interop with unmanaged code quite friendly, rather than a giant mess of fixed statements that would come about as a result of using float arrays.

 

C#'s ?? operator

Consider the following method:

Foo EnsureNotNull(Foo foo)
{
if (foo != null)
return foo;
return new Foo();
}

You can trim that down a bit by using a ternary operator:

Foo EnsureNotNull(Foo foo)
{
return foo == null ? new Foo() : foo;
}

But why use that when ?? is a binary null check operator; I.e., it returns the left if it is not null and the right otherwise:

Foo EnsureNotNull(Foo foo)
{
return foo ?? new Foo();
}

 

Hardware Graphics Acceleration and Asynchronous Calls

This is a tip I learned way back in my hay day of amateur game development. Many OpenGL/Direct3D may be just asynchronous calls on the hardware, and subsequent operations may end up resulting in them waiting for the previous operation to finish. The following is a very common pattern in drawing routines:

void OnPaint()
{
glClear(GL_COLOR_BUFFER_BIT);
// paint a bunch of stuff
// glDrawStuff();
glSwapBuffers();
}

Here, the code is immediately making paint operations following the clear. This results in those operations waiting until the clear has completed before executing. Restructuring the code as follows can squeeze out a little more performance:

void OnPaint()
{
// paint a bunch of stuff
// glDrawStuff();
glSwapBuffers();
// clear the buffer after the background and foreground are swapped
// this clear will take place asynchronously and be complete
// when we start to draw the next frame!
glClear(GL_COLOR_BUFFER_BIT);
}

I implemented this in GLMaps recently, and saw an FPS increase from 49 to 51. That's a ~4% increase! Using this technique, any static preprocessing/setup can actually just be run at the end of the drawing operations, rather than at the beginning. (Concurrently using the CPU and GPU between frames to get a net gain in FPS)

 

Handy C# 3.0 Shorthand

This tip didn't actually catch me by surprise, since I read through the C# 3.0 new features. However, old habits die hard, so I often forget to use them. Prior to C# 3.0, the following would be a standard class declaration:

class Foo
{
int myBar;
public int Bar
{
get
{
return myBar;
}
set
{
myBar = value;
}
}

double myMoo;
public double Moo
{
get
{
return myMoo;
}
private set
{
myMoo = value;
}
}

float myCool;
private float Cool
{
get
{
return myCool;
}
set
{
myCool = value;
}
}
}

With C# class declaration shorthand, developers can now eliminate much of the redundancy (the properties and backing fields are implicitly defined):

class Foo
{
public int Bar
{
get;
set;
}

public double Moo
{
get;
private set;
}

public float Cool
{
get;
set;
}
}

Also, when declaring an instance of that class, prior to C# 3.0, a common pattern is to set some initial properties:

void MakeFoo()
{
Foo foo = new Foo();
foo.Bar = 0;
foo.Cool = 0;
}

With C# 3.0, you get additional shorthand (less characters, not lines), and a more aesthetically pleasing syntax:

void MakeFoo()
{
Foo foo = new Foo()
{
Bar = 0,
Cool = 0
};
}

 

That's it for tips for now. Share 'em if you got 'em!

Day 8: VARIANT_BOOL, BOOL, bool, HRESULTs, and managed Exceptions

God, what a mess.

  true false
VARIANT_BOOL -1 0
bool (C#/C++) true false
BOOL (C++) not 0 0
HRESULT >= 0 < 0

I ran into this mess while creating COM interfaces in C# that were being used in C++ (via tlbexp). I discovered some silly behavior with regards to how C# or tlbexp marshals bool return types, which was the cause of a couple bugs:

C# COM Interface:

[Guid("91B57DDB-5CCF-4cb5-9A26-A7F9559BAFFF")]
public interface IFoo
{
    // by default bool is marshalled as VARIANT_BOOL
    bool Bar();
    void Goo();
}

Seriously? Why is it defaulted to VARIANT_BOOL and not BOOL? VARIANT_BOOL is a Visual Basic concept (and a retarded one at that). Looking at the table above, it is the complete opposite behavior of COM HRESULTs. The fix:

[Guid("91B57DDB-5CCF-4cb5-9A26-A7F9559BAFFF")]
public interface IFoo
{
    [return: MarshalAs(UnmanagedType.Bool)]
    bool Bar();
    void Goo();
}

Another issue that bothered me was that these COM calls actually look like the following:

virtual HRESULT __stdcall raw_Bar (
  /*[out,retval]*/long* pRetVal ) = 0;

virtual HRESULT __stdcall Goo () = 0;

All COM calls are returning HRESULTs behind the scenes, which is expected. However, what happens when the C# code throws an exception? You would expect the marshaller to maybe catch it and return an HRESULT failure? Nope. On .NET CF (and maybe even in the desktop version too), the application crashes (without any chance for recovery) in native code. Beautiful. This basically requires that your C# COM methods have a try/catch wrap around all operation, as an exception would be fatal. I guess I can understand why you wouldn't want to have the COM interop handling arbitrarily catch all exceptions, but it is quite tedious to have to do it yourself.

Windows Mobile Video Power States

All in all, development on Klaxon has given me some great insight into how power states affect program execution. One of the changes I am making to the newest version of Klaxon is to turn the device's video off when the user hits snooze.

Since the earliest versions of Klaxon, I have been using the SystemIdleTimerReset call to prevent the device from going to sleep. This behavior is necessary because the application needs to continue running to pick up sensor events. However, using SystemIdleTimerReset has the unintended effect of leaving the display on: it should be turned off so as not to drain the battery or have a distracting bright light on in the room while the user is trying to sleep. So I did some searching to see if there was a way to explicitly turn off the video, but allow program execution to continue. The behavior I wanted is similar to how Windows Media Player can turn off the video but the songs keep playing, and the device does not go to sleep until Windows Media Player is stopped.

It turns out that Windows Mobile has several video power states, which are described quite nicely in an MSDN article. I ended up wrapping these native power management calls into a bow tied package for usage in C# for your reusing pleasure:

using System;
using System.Runtime.InteropServices;

namespace WindowsMobile.Utilities
{
public enum VideoPowerState
{
VideoPowerOn = 1,
VideoPowerStandBy,
VideoPowerSuspend,
VideoPowerOff
};

public static class Device
{
const int SETPOWERMANAGEMENT = 6147;
const int GETPOWERMANAGEMENT = 6148;

[DllImport("coredll")]
extern static IntPtr GetDC(IntPtr hwnd);

[DllImport("coredll")]
extern static int ExtEscape(IntPtr hdc, int nEscape, int cbInput, ref VideoPowerManagement vpm, int zero, IntPtr empty);

[DllImport("coredll")]
extern static int ExtEscape(IntPtr hdc, int nEscape, int zero, IntPtr empty, int cbOutput, ref VideoPowerManagement outData);

struct VideoPowerManagement
{
public int Length;
public int DPMSVersion;
public VideoPowerState PowerState;
}

public static VideoPowerState VideoPowerState
{
get
{
IntPtr hdc = GetDC(IntPtr.Zero);
VideoPowerManagement ret = new VideoPowerManagement();
ExtEscape(hdc, GETPOWERMANAGEMENT, 0, IntPtr.Zero, 12, ref ret);
return ret.PowerState;
}
set
{
IntPtr hdc = GetDC(IntPtr.Zero);
VideoPowerManagement vpm = new VideoPowerManagement();
vpm.Length = 12;
vpm.DPMSVersion = 1;
vpm.PowerState = value;
ExtEscape(hdc, SETPOWERMANAGEMENT, vpm.Length, ref vpm, 0, IntPtr.Zero);
}
}
}
}

Usage:

Just get or set the Device.VideoPowerState property to do whatever you need!

Day 7 or 37, who knows: .Net CF and Marshalling ANSI strings in structures

Consider the following code:

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Text;

namespace SmartDeviceProject5
{
class Program
{
static void Main(string[] args)
{
Foo foo = new Foo();
try
{
SomeMethod(foo); // KABOOM! NotSupportedException
}
catch (Exception e)
{
}
try
{
AnotherMethod("hello"); // KABOOM! NotSupportedException
}
catch (Exception e)
{
}
}

[DllImport("SomeDLL")]
extern static void SomeMethod(Foo foo);

[DllImport("SomeDLL")]
extern static void AnotherMethod([MarshalAs(UnmanagedType.LPStr)] string someString);
}

public struct Foo
{
public string Bar;
public string Borked;
}

}

When attempting to run this program, it will throw an exception upon calling the SomeMethod PInvoke. Attempting to call the "AnotherMethod" function will fail just as well.
This happens because C# automatically marshals all strings in structures as LPTStr (which for some reason is LPStr in Windows Mobile). However, in methods, strings are marshalled as LPWStr. I don't get it. Anyways, .Net Compact Framework does not support marshalling as LPStr in structures or method calls for whatever reason, even though the code to make it happen is all there (as I will show you).
Changing the code by adding the MarshalAs attribute to explicitly Marshal them as LPWStr would make it work:



    [DllImport("SomeDLL")]
extern static void AnotherMethod([MarshalAs(UnmanagedType.LPWStr)] string someString);
}

public struct Foo
{
[MarshalAs(UnmanagedType.LPWStr)]
public string Bar;
[MarshalAs(UnmanagedType.LPWStr)]
public string Borked;
}


Although LPWStr (Unicode) is more or less the standard now, but if you really really want/need to Marshal it as a LPStr, tough cookies, you get a NotSupportedException.
Generally, if you need to marshal a structure with strings, it's highly unlikely that you are going to need to mix LPWStr and LPStr in the same structure. To that end, I wrote a custom MarshalAnsi class that marshals a structure and all its contents; any strings found are marshalled as LPStr:


using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;

namespace System.Runtime.InteropServices
{
    /// <summary>
    /// .NET Compact framework does not support marshalling strings to ascii.
    /// Need to do it manually.
    /// </summary>
    static class MarshalAnsi
    {
        /// <summary>
        /// This Dictionary maintains all the strings allocated by an IntPtr that a structure
        /// was Marshalled to.
        /// </summary>
        static Dictionary<IntPtr, List<IntPtr>> myStringsForObject = new Dictionary<IntPtr,List<IntPtr>>();

        public static IntPtr StructureToPtr(object structure)
        {
            Type type = structure.GetType();
            var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.GetField | BindingFlags.Public | BindingFlags.NonPublic);
            
            // determine the total size of the structure. Need to special case strings and bools
            int totalSize = 0;
            foreach (FieldInfo field in fieldInfos)
            {
                totalSize += field.FieldType == typeof(string) ? Marshal.SizeOf(typeof(IntPtr)) :
                              field.FieldType == typeof(bool) ? Marshal.SizeOf(typeof(int)) : Marshal.SizeOf(field.FieldType);
            }

            // allocate the pointer, and create it's list of allocated strings
            IntPtr ret = Marshal.AllocHGlobal(totalSize);
            List<IntPtr> strings = new List<IntPtr>();
            myStringsForObject.Add(ret, strings);
            // structure pointer offset, which is incremented as we write to the structure
            int ofs = 0;
            foreach (FieldInfo field in fieldInfos)
            {
                object toWrite = null;

                if (field.FieldType == typeof(string))
                {
                    // allocate memory for the string if need be, and add it to the 
                    // pointers string allocation list
                    string str = field.GetValue(structure) as string;
                    IntPtr strPtr;
                    if (str == null)
                        strPtr = IntPtr.Zero;
                    else
                    {
                        byte[] bytes = Encoding.ASCII.GetBytes(str);
                        strPtr = Marshal.AllocHGlobal(bytes.Length + 2);
                        strings.Add(strPtr);
                        Marshal.Copy(bytes, 0, strPtr, bytes.Length);
                        Marshal.WriteInt16(strPtr, bytes.Length, 0);
                    }
                    toWrite = strPtr;
                }
                else if (field.FieldType == typeof(bool))
                {
                    // need to write this as an int, not a bool. 
                    // BOOL in C/C++ is really an int, which is of size 4.
                    toWrite = (bool)field.GetValue(structure) ? 1 : 0;
                }
                else
                {
                    // just do the default behavior
                    toWrite = field.GetValue(structure);
                }
                Marshal.StructureToPtr(toWrite, (IntPtr)((int)ret + ofs), false);
                // increment the structure pointer offset
                ofs += Marshal.SizeOf(toWrite);
            }

            return ret;
        }

        /// <summary>
        /// Destroy the memory allocated by a structure, and all strings as well.
        /// </summary>
        /// <param name="ptr"></param>
        public static void DestroyStructure(IntPtr ptr)
        {
            List<IntPtr> strings = myStringsForObject[ptr];
            myStringsForObject.Remove(ptr);
            foreach (IntPtr strPtr in strings)
            {
                Marshal.FreeHGlobal(strPtr);
            }
            Marshal.FreeHGlobal(ptr);
        }
    }
}

Usage:
Simply pass a structure into this class and it will return a pointer with the marshalled data. All strings are marshalled as Ansi strings.
Remember to call MarshalAnsi.DestroyStructure with the pointer returned from MarshalAnsi.StructureToPtr when it is no longer in use.

Day 6?: Mergebin - Combine your Unmanaged and Mananaged DLLs into one Handy Package

MC++ is nice. It lets you mix unmanaged and managed code and allows you to easily create assemblies where you need to do a lot of interop work. Unfortunately, MC++ is not available for .NET CF. So, whenever you need to do any significant degree of interop, you usually end up doing one of the following:

  • Doing a lot of PInvokes into code that really isn't PInvoke friendly. This generally results in a lot of manual marshalling of arguments and unsafe code. This doesn't work if what you need to PInvoke is a .lib or a non-flat/C style DLL.
  • Writing a unmanaged DLL that does all the heavy lifting, and creating managed PInvokes to access it.
  • Writing a COM object for Windows Mobile and referencing that in your C# project.

The first solution is pretty kludgy, but it works. The latter two solutions result in two outputs: a managed assembly and an interop DLL. The DLLs must always be deployed with each other to function properly. Not a very elegant solution either.

I've been playing with SQLite recently. SQLite is the most used database engine in the world, and it runs on basically any device imaginable, including Windows Mobile. SQLite is written entirely in C/C++, so naturally someone wrote a managed wrapper for it called System.Data.SQLite.

One of the interesting things I noticed about System.Data.SQLite is that it somehow manages to deploy as one assembly, even though one of the source DLLs is managed and the other is an unmanaged interop. After diving into the managed code, I noticed something quite peculiar: it was calling PInvokes contained within itself! Somehow a single DLL contained both managed and unmanaged code!

Turns out that the creator of SQLite also created a tool called Mergebin that allows you to merge your managed assembly and unmanaged interop assembly into one nice bow tied package. Very elegant! The full source to the Mergebin tool is included with System.Data.SQLite. I looked over it, and although I have a very rough idea of how DLLs work, so the actual technical implementation of it is all Greek to me. Interesting stuff nonetheless!

Note:

Just a few posts ago, I talked about how I managed to combine two .NET assemblies into one. It involved embedding one assembly as a resource of it's dependent assembly. Pretty kludgy. I probably should have Googled to see if there was a tool possible to merge two .NET assemblies, and there is: ILMerge. I haven't looked into it at all though, so I'm not sure if it will work for .NET CF.

CeRunAppAtTime, CeSetUserNotificationEx, Connection Manager Process Scheduling and how they are affected by Power States in .NET Compact Framework

After releasing the first version of Klaxon, several users reported that Klaxon was not starting at the designated time if the device was sleeping: often several minutes late, or not at all.

My implementation of process scheduling was using Connection Manager. At first I thought the device going to sleep was disabling all the active connections, so the event would not fire. I switched the implementation to use CeRunAppAtTime, and still encountered the same problem. CeRunAppAtTime is deprecated and there were several blog posts describing the various issues people had with it. I then switched the implementation again; this time to use CeSetUserNotificationEx, which is the new hotness in process scheduling. Still the same issue. I did notice something peculiar however: if I scheduled the event with a System Notification Dialog (like a calendar event), it would work.

In all 3 implementations, Klaxon would launch immediately after the device was turned on. Another oddity was that the Klaxon form loaded was almost instantaneously, when generally it has a 5-6 second when I launch it via the Programs list. This led me to believe that it was actually launched and resident, but the device was then somehow put back into suspension. Turns out I was right. There are a few well hidden forum posts which document this issue.

Basically, if the device is not explicitly set to a "power on" state within a few seconds of going into the "resuming" state, it goes back into a suspended state. So the fix is to call SetSystemPowerState, which looks like the following:

using System;
using WindowsMobile.Utilities;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;

namespace Klaxon
{
    static class Program
    {
        [DllImport("coredll.dll")]
        extern static UInt32 SetSystemPowerState(String pwsSystemState, UInt32 StateFlags, UInt32 Options);
        const UInt32 POWER_STATE_ON = 0x00010000;
        const UInt32 POWER_FORCE = 0x00001000;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [MTAThread]
        static void Main(string[] args)
        {
            SetSystemPowerState(null, POWER_STATE_ON, POWER_FORCE);
            Run(args);
        }

        static void Run(string[] args)
        {
            InteractiveService.Run(args, typeof(AlarmListForm), new ThreadStart(KlaxonService.Run));
        }
    }
}

Note that I am not calling the InteractiveService.Run in the Main method. This is because when Main is called, all types that it references will have their respective assemblies loaded. In my case, this would be System.Windows.Forms, WindowsMobile.Utilities, and a few others. This would add to the "spin up" time and risk the device being put into suspension before SetSystemPowerState is called.

HTC Touch Diamond Nav Sensor API

diamondnav

Scott, from scottandmichelle.net, figured out how to detect which way the nav sensor was being moved. I did some further investigation with the data output and managed to figure the rotation per second readings that were also being returned with it.

The new HTCNavSensor has a single event:

Rotated

This event fires whenever the Nav sensor event is detected. The rotation event will provide the user with an approximate rotation per second value and a radial delta. The radial delta is a double value that describes how much the user has moved along the nav sensor since the last time the event was fired. I.e, a radial delta value of .25 would mean that the user moved his finger around a quarter rotation since the last the last time the nav sensor event fired.

As usual, the updated API can be downloaded here. The other sensor APIs (accelerometer and light sensor) are also available in the same zip file. So that wraps up accessing all the different sensors on the HTC Touch Diamond!

Let me know if you find any bugs!

Edit: I found a bug where the nav sensor was reporting clockwise movement when actually moving clockwise. Fixed that. Also updated the Nav Sensor Test to show a red line that rotates as you rotate around the sensor.

HTC Light Sensor API

lightsensor

Goofed around with the HTCSensorSDK.dll some more and figured out how to access the light sensor. I've updated the HTC Accelerometer API to allow access to the light sensor, and converted the values to make it developer friendly. The API exposes the following:

GetLumens

This returns a double value that describes the environmental lumens. It works decent at best, but it's a starting point. I calibrated this using a lightbulb, monitor, and other random light sources around the house I had the lumens values available for.

Brightness

Retrieves an arbitrary enum that describes the brightness of the environment. Values are Dark, Dim, Normal, and Bright.

BrightnessChanged

This event will notify you whenever the brightness changes.

You can download the API here. Let me know if you find any bugs!

Update:

I've updated the SDK to access the Nav sensor as well!

Secrets of the Windows Mobile Home Screen API

homescreen

One of my recent projects at Enterprise Mobile was creating a custom home screen (see above) for the new MotoQ9h and Blackjack II devices. The top row is the standard Windows Mobile "Icon Bar". The second row has the clock, messaging center (SMS, Mail, Voicemail), and current profile. Below that is the status text and the application bar. (Everything below the icon bar is a single full screen plug-in.)

At first glance, I assumed this would be a breeze. I have a powerful layout, key handling, and paint framework that I use in every project I work on, and thought that creating a home screen leveraging that would make it trivial. Sadly I was sorely mistaken.

Those of you familiar with WM Home Screen development know that there are actually two APIs: the Home Screen API (Smartphone) and the Today Screen API (Pocket PC). I was only interested in the prior. Smartphone Home Screen development is considerably more difficult: you don't have nearly as much control. The developer must implement IHomePlugin which only receives paint events (the plug-in is supplied only an HDC) and some key events (left and right only). On Pocket PC, you get an HWND and all the good things that go along with it.

That didn't phase me too much. My plan of action was to implement this IHomePlugin interface in managed code and then let the magic happen. Easy enough. I implement a dummy plug-in in C#, and try to register the COM object... and it doesn't work. It refused to register, the error claiming it was an invalid DLL. I poked at it for a while before finally giving up and checking to see if Google would know why I could not register a C# COM object on Windows Mobile.

I searched for a while, and found plenty of examples of how to invoke unmanaged code from managed code. Then I noticed, not a single site showed how to invoke managed from unmanaged. I began searching explicitly for that, and found my answer:

The .Net Compact Framework does not support hosting the runtime from native code. This means that you will not be able to call CoCreateInstace to instantiate a managed object, or register managed objects as COM objects on the system. You will also not be able to call CorBindToRuntime or ClrCreateManagedInstance. In order to call managed functions from native code, you must first use the runtime to marshal a managed interface or a delegate down to native code. This means you must always start out in managed code (with a .net executable) in order to expose .net components to native code.

This was news to me. And pretty devastating; the thought of creating a fairly complex home screen from scratch in unmanaged code was daunting. If it is not obvious, I'm primarily a .NET developer. Don't get me wrong, I have grass roots in C, but, the facts of life are that the lower level your programming language, the higher the development time and bug count.

So I quickly thought of a workaround though: create a managed service executable that hosts the UI framework. And using a combination of MessageWindows and sharing memory between processes, I could construct a bridge from unmanaged to managed code:

Implement IHomePlugin in unmanaged code and add that plug-in to the home screen. The unmanaged plug-in will do the following:

  1. Create a pool of shared memory.
  2. Create a back buffer HDC. This back buffer is what painted whenever the home screen requests a repaint. The managed code will write to this back buffer across process boundaries.
  3. Whenever the PE_DATACHANGE event is received, invalidate the plug-in.
  4. In the shared memory, write the HDC value, system colors, and plug-in dimensions.
  5. Start my managed executable.

Once started, the managed executable does the following:

  1. Gets the back buffer HDC and other relevant values from the shared memory pool.
  2. Paint to the back buffer HDC.
  3. Notifies the Home Screen API that a plug-in has had a data change event using SHOnPluginDataChange. This in turn causes the plug-in to invalidate and repaint from the back buffer.

That solves the painting issue, but the plug-in still needed to get key events from the Home Screen API and deliver them to managed code. Easy enough: the managed executable can create a MessageWindow and the unmanaged can deliver the key events provided by the Home Screen API. The managed code can then process the key event, repaint the back buffer, and invalidate the plug-in to refresh the screen.

This works great, but the catch with the API is that it delivers only left and right key presses. It won't send up and down key events (because then the user can't navigate to another plug-in on the home screen). However, since my plug-in was full screen, I did not matter. I needed a way to navigate vertically between elements laid out in my single full screen plug-in.

The solution to capturing all key events is a neat trick that native Win32 API developers are familiar with. Have the unmanaged plug-in subclass the home screen window (DesktopExplorerWindow as found in the VS Remote Spy++ tool) proc to steal the key presses and send them off to the managed code.

And there you go, a fully functional "managed" Home Screen Plug-In. My initial worry was that performance would suffer terribly from the cross process communication, but the home screen was actually very responsive. Users reported that the UI was quite "snappy".

Unfortunately I don't have any sample code to provide (yet), since this is all company IP. But maybe it will be released in the future!

Note: I should mention that Home Screen development actually gets easier with this interprocess communication. Developing a purely unmanaged plug-in means that the entire home.exe process needs to be stopped and started with every little change made to the plug-in. This can grow to be quite tedious. With the two-process model, starting and stopping the second managed process leaves the home.exe undisturbed.