Acrylic Automation: Crossing the Barrier

Ok, so I really was chomping at the bit to blog.  Now that we've gone beta I can get a lot of things off of my chest.  Just too awkward to blog much before the product was announced, you know?  In this post I'm going to give a bit of info on how to write a managed dll that interops with unmanaged code.  (FYI: I can't really give the explicit details on how to access the Acrylic automation interfaces at this point.

This is going to be in Managed C++ in 2005.  I've mentioned before that it blows P/Invoking out of the water.  The syntax is radically different than the Managed Extensions for C++ that was in VS.Net and is really remarkably easy to read and use for those who know C#, so be strong! ;)

Making a project managed in C++ is simply a matter of setting the /clr switch, which you can get to in the project properties panel under "Configuration Properties: General: Project Defaults: Common Language Runtime support".  There are some variations of this switch that are pretty well documented and I won't go into them here.  Our configuration type is "Dynamic Library (.dll)", of course.  (This is in the same properties area.)

We include the standard <windows.h> header and windows version pound defines as we need access to the Win32 api in a number of places.  Here's a simplified code snippet that shows you how things work:

 // Plugin.h

// You need to include the relevant headers for the interfaces you're trying to hit.
// This would be defined by the App you're trying to interact with.
#include "AppPlugginInterfaceHeaders.h"

extern "C" // Or "C++" whatever your application uses
{
   //
   // The application plugin entry point.
   // The __declspec(dllexport) specifies that this function should be exported.
   // IApplicationPluginHost is defined in the header provided by the app and included above.
   //
   __declspec(dllexport) bool PluginEntry(IApplicationPluginHost *hostAPIs);
}
 
 // Plugin.cpp


// Or wherever else you have your windows includes if you do..
#include "Stdafx.h"
#include "Plugin.h"

__declspec(dllexport) bool PluginEntry(IApplicationPluginHost *hostAPIs)
{
   // Code to check and save the interface passed back from the application.
}

That's pretty much the sum of it.  From there it's using the host api pointer to grab other interfaces and access functions through those interfaces.  So something like hostAPIs->SomeFunction(). We do also have a DllMain (which must be unmanaged according to the SDK) to do some thread initialization that is very app specific in our case.  (This would be DLL_THREAD_ATTACH and DLL_THREAD_DETACH message processing.)

In case you're curious, putting completely unmanaged code in your /clr app requires a #pragma managed(push, off) statement before said code and a #pragma managed(pop) afterwords.