I spent the last couple of days working on wrapping a native win32 api in managed code. I’ve been tasked with working with the Task Scheduler portion of windows, which has a pretty good native API, but no managed API.
I thought, ‘hey no problem, a little COM interop and I’m done’. It was, of course, more challenging than it should have been.
One of the things I have to do is modify the parameters to an existing scheduled task. There’s an MSDN sample (in c/c++) that was dead easy to follow. Of course, translating it to C# was more painful than I expected. Here’s the sample, go check it out: Setting Task Parameters (Windows).
I was able to get the ITask interface in managed code, and could query the current parameters, and even set the new ones no problem. I created an ITask interface in C#, and marked it up with the ComImport attribute.
The problem came when I was trying to persist the changes to disk. The native code used IUnknown::QueryInterface to get a pointer to an IPersistFile object. Here’s that code:
IPersistFile *pIPersistFile;
hr = pITask->QueryInterface(IID_IPersistFile,
(void **)&pIPersistFile);
I tried a bunch of methods to do the same thing in managed code, and couldn’t get it to work. I was getting object references, but they were of the wrong type. The thing I was missing is that the QueryInterface method above is really just returning a pointer to the same object, cast as an IPersistFile, because ITask implements IPersistFile. Put that way, it sounds easy, right?
Here’s the C# code to get the IPersistFile interface:
IPersistFile persistFile = nativeTask as IPersistFile;
Simple, right? I have to say, I felt like an idiot for not realizing that ITask implemented IPersistFile sooner. Polymorphism is a wonderful thing.