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
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
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
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
CommonDialogClass. The secret is to use the non-
Iprefixed interface, e.g.
CommonDialog(if you try to use
ICommonDialogyou'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 objects.
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!
- 2019-09-07 - First published
- 2020-11-22 - Updated formatting