The Background (Or, look how far I've gone on my own!)
I'm starting from the Windows 8 Media Extension Sample. I'm using the grayscale example as a starting point to learn how to pass values from managed code into a COM object, and how to pass values from my COM object back to managed code. In my IDL file, I've got a GrayscaleEffect class (taken exactly from the example) and a custom interface that should let me query a string over in the c# world.
The IDL file:
namespace GrayscaleTransform
{
[version(NTDDI_WIN8), uuid(553B5684-4C22-4D21-8638-1E7D86D84F10)]
interface MyInterface : IInspectable {
HRESULT GetMsg([out] HSTRING *message);
}
[version(NTDDI_WIN8)]
runtimeclass GrayscaleEffect {
interface Windows.Media.IMediaExtension;
interface MyInterface;
}
}
My GrayscaleEffect class implementation implements GetMsg to return the string "Woozle"
The relevant c#:
cap = new MediaCapture();
await cap.InitializeAsync();
previewElement1.Source = cap;
await cap.StartPreviewAsync();
PropertySet props = new PropertySet();
await cap.AddEffectAsync(
Windows.Media.Capture.MediaStreamType.VideoPreview,
"GrayscaleTransform.GrayscaleEffect",
props);
if (this.props.ContainsKey("ref"))
{
var augGui = (GrayscaleTransform.MyInterface)this.props["ref"];
string message;
augGui.GetMsg(out message);
}
After the call to GetMsg, I can see that message contains the string "Woozle" just like I expect - Excellent!
The Problem
Now I want to do something a little bit fancier. Instead of a method that lets me pass a string from COM to C#, I want to implement a method that lets me pass a delegate from C# to COM. I'd like to get the MFT class to call this method every 10th video frame or something - that part's not important. I want my interface to have a method called SubscribeEvent
that takes a delegate as a parameter. For now, it can be a void delegate that takes no arguments.
This page leads me to believe that I should be able to declare a WinRT delegate over in the COM world and be able to pass a delegate of the same type from C# (see the 3rd item from the end). Cool - seems easy. My best try so far has been something like this in the idl:
delegate void CallbackMethod();
[version(NTDDI_WIN8), uuid(553B5684-4C22-4D21-8638-1E7D86D84F10)]
interface MyInterface : IInspectable {
HRESULT Subscribe(CallbackMethod cb);
}
Unfortunately this results in an error - seems to be related to the declaration of the delegate CallbackMethod:
error MIDL9008: internal compiler problem - See documentation for suggestions on how to find a workaround.
Edit
This one is obvious. That syntax is a C++/cx thing. Upon closer inspection, I don't have the C++/CX extensions turned on. This is a WRL project which means it's regular flavor c++ with template magic.
I also tried to wire up an event by implementing the IConnectionPoint interface, but when I include OCIdl.h I get a compile error that desktop components cannot be compiled for ARM.
The Question
Am I barking up the wrong tree here? Should I be making my GrayscaleEffect class be a WinRT runtime class using C++/CX? Maybe we're venturing into "New question" territory here, but when I try to implement IMFTransform with a WinRT class in C++/CX, I get
error C2811: 'GrayscaleRT::Class1' : cannot inherit from 'IMFTransform', a ref class can only inherit from a ref class or interface class
A better question:
How about this: Can I pass a delegate here at all? I fell like I ought to be able to, if only I knew the magic combination of WRL templates to make it work.