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.