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

With embedding disabled, you have to include an additional DLL that may include code you aren't using
With embedding disabled, you have to include an additional DLL that may include code you aren't using

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 false.

Fixing it properly

With embedding enabled, there's no extra DLL - just a slight increase in your application size
With embedding enabled, there's no extra DLL - just a slight increase in your application size
The meta data for a sample application showing that only the interfaces that were in use were embedded into the application
The meta data for a sample application showing that only the interfaces that were in use were embedded into the application

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

csharp
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 objects.

csharp
WIA.ICommonDialog dialog; // or CommonDialog

dialog = new WIA.CommonDialog(); // no error

Constants

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.

Closing thoughts

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!

Update History

  • 2019-09-07 - First published
  • 2020-11-22 - Updated formatting

Like what you're reading? Perhaps you like to buy us a coffee?

Donate via Buy Me a Coffee

Donate via PayPal


Comments

# Cris McLaughlin

I was messing around with WIA myself and stumbled across an awesome open source .net project: https://www.naps2.com/. It really helped me understand how to work with WIA and Twain in .net.

Reply

# Dr. Harshadkumar G.

Thanks a lot to explain this, Solved this will first solution.

Reply