Recently I've been experimenting with the Microsoft Windows Image Acquisition Library (WIA), a COM library that therefore requires the use of interop in .NET. In the course of testing some of the different features of this library I triggered a compile error I haven't come across for a long time. As it isn't often I work with COM interop I thought I'd write a quick post detailing how to resolve or work around the compile errors to more firmly cement it in my head for the next time.
About interop embedding
In older versions of .NET (or Visual Studio), when you referenced a COM library
an interop DLL was generated - you could always tell these from their filenames
as they would start with
Interop.. I also seem to remember that back in the
days of .NET 1.1 I would manually run a utility program to generate the interop
DLL's, to avoid some form of naming prefix.
More recent versions of Visual Studio still do this, but will also try and avoid having to include the interop DLL by packaging up all the interfaces and embedding them directly in your application, just like any other class you'd written.
This is a neat feature as it reduces application size and deployment complexity - there's no need to ship an extra DLL, and only interfaces relating to functionality you're directly using is embedded.
However, this only works if you use the original interfaces, and not the classes generated by the interop importer. Trying to use any non-interface will produce a compile error, similar to
Interop type 'CommonDialogClass' cannot be embedded. Use the applicable interface instead
Fixing it the simplest way
Personally, I would go with the second option and so I don't recommend you use this approach
The easiest way of resolve this is to disable embedding the interop library. To
do this, expand the References node in the Solution Explorer and select
the COM reference you added. In the Properties window, set the value of the
Embed Interop Types property to
Fixing it properly
The error message is fairly clear in how to resolve the problem - "Use the applicable interface instead". However, it is bit of a puzzle as well as it requires breaking the normal rules.
Classes versus Interfaces
The WIA library has an interface named
ICommonDialog. This interface provides
access to a variety of user interfaces for connecting to a scanner or camera.
The interop library has this interface, but also generates a further interface -
CommonDialog (that implements
ICommonDialog) and a concrete class
CommonDialogClass that implements both interfaces.
As a seasoned developer, you know fine well that you can't create a new instance of an interface, you have to create an instance of the class which implements it. So naturally you might write code similar to
WIA.CommonDialogClass dialog; // error dialog = new WIA.CommonDialogClass(); // error
Unfortunately, this will give you two different compile errors, once for each
CommonDialogClass. The secret is to use the non-
I prefixed interface, e.g.
CommonDialog (if you try to use
ICommonDialog you'll get normal compile
error you would trying to new up any other interface.). Even though this is
completely against the rules as you might know them, this is valid code - it is
just part of the magic done under the scenes to allow managed access to COM
WIA.ICommonDialog dialog; // or CommonDialog dialog = new WIA.CommonDialog(); // no error
There is one caveat and that is constants. Some COM libraries might define global constants and while the interop library will include these constants, they are placed inside classes and so if you try to access them you'll get the same compile error.
There's no easy workaround this time as far as I know - you need to copy the constant values into your own code. An easy way is just to type the class name in your code editor and press F12. Visual Studio will then open the meta data for the interop class which will show the constants and their values - you can then just copy and paste these into your own application.
As I noted in my preamble, I don't often work with COM so the article above may not present the whole picture. Clarifications or comments welcome!