<< Microsoft Workaround for Stale Reference in VS2005 | Home | Bypassing a Proxy with HttpWebRequest >>

.NET C# and Com Interoperability

posted @ Wednesday, September 14, 2005 1:19 PM

I've recently been using DotLucene at work to implement a search engine for a client's web site. Recommended by Steve Eichert, I've really enjoyed working with it, and I've only scratched the surface of what it can do. One of the things I need to do for this search engine is index some binary files like PDF and DOC. Most examples use the IFilter objects used by Windows Indexing Service to parse these files (you have to download the free Adobe IFilter for PDFs to parse them). You then need to use .Net Interop services to access the COM object that will return to you the correct IFilter for whatever file type you are parsing. I found some great code for using IFilters in a Desktop Search example on CodeProject. This works great if your indexing routine has access to the the files on the file system.

The problem I've run into is that the files I need to parse are stored in a SQL Server database. Using the same COM object, query.dll, there is a method BindIFilterFromStream that is supposed to take a stream and retrieve the appropriate IFilter for you, in the same way that LoadIFilter does for a file on the file system. The problem is, I am no Interop expert, and I can't get this method to run properly for me. Mattias Sjogren, a .net Interop guru, was kind enough to give me some pointers on how to properly pass parameters to the method. It required copying a byte[] to the native heap, and converting it to a UCOMIStream object. It was actually pretty simple (assuming I'm right - this part seems to work):

// copy stream to byte array
byte[] b = new byte[stream.Length];
stream.Read(b, 0, b.Length);
// allocate space on the native heap
IntPtr nativePtr = Marshal.AllocHGlobal(b.Length);
// copy byte array to native heap
Marshal.Copy(b, 0, nativePtr, b.Length);
// Create a UCOMIStream from the allocated memory
UCOMIStream comStream;
CreateStreamOnHGlobal(nativePtr, true, out comStream);

The problem is, when I finally call the BindIFilterToStream method, I get a result code back of -2147467259 and a Win32 error 127 ("The specified procedure could not be found.” ). I don't know what procedure can't be found, but since I'm getting a result code (and have gotten other error messages from BindIFilterToStream previously) I don't think it's not finding the BindIFilterFromStream method. Again, not being an Interop expert (or even having USED interop previously) I'm stumped. I emailed Mattias again, risking being a nuissance, and am hoping he can help. If I get this working, I'll definitely post about it because I can't find ANY examples of someone calling BindIFilterFromStream from managed C# code. I've been googling for days. I feel like it is something really simple that is just eluding me due to my lack of experience with this stuff. If you have any suggestions, please let me know!