In my last post in this series I walked through the basics of launching and managing an external process. In this post I’ll be discussing simple process interactions via ShellExecute API Verbs. Using Verbs will allow you to perform simple tasks on specific file types without having to worry about building a complex communication layer to a specific application.
Introduction
In many cases an even moderate level of complexity in process interaction is undesirable. For simple operations such as opening or printing a file inside of an external application there is an easier way. To do these kinds of file oriented tasks you can execute that file using a Verb and avoid the large amount work involved in building any real type of interprocess communication architecture. Unfortunately, the tradeoff for this level of ease of use is that you give up direct control over exactly which program will be operating on your file.
What is a Verb and How Do They Work?
Verbs are a type of file association by which an application advertises a specific type of functionality on a specific file extension. For each file extension there is a verb list. Each verb in this list has an associated application which is capable of performing the specified action.
These verbs are defined by the programs which perform them. This means that they should be fairly reliable in so far as that we would hope the provider of a program would not set that Verb if the functionality was not supported. However, we all know that bugs happen, especially in other people’s software, and so a great deal of care should be used when dealing with exception handling when using Verbs.
Browsing Available Verbs for Any Extension
To see a list of file types, the actions they support and which application they will launch, you will need to go to the File Types tab inside of explorer’s Folder Options:
Selecting a file extension and then clicking the Advanced button will bring up a list of Actions for that extension:
By browsing your file types you can quickly determine which Verbs might be available on your expected deployment desktop. For example, Microsoft Office formats enjoy a wide variety of Verbs. If you can expect the Microsoft Office suite to be installed on your deployment platform then it is also reasonable to assume you will be able to leverage its default Verbs for simple Office printing.
However, it is important to remember that available Verbs will vary from machine to machine, depending on which software packages are installed. When using Verbs it is paramount to both verify that the verb you wish to use exists and handle possible exceptions in an elegant way.
A Simple Example
The following example loads a file in the default PDF viewer and instructs it to print:
ProcessStartInfo info = new ProcessStartInfo(@"C:\printme.pdf");
info.Verb = "print";
Process proc = new Process();
proc.StartInfo = info;
try
{
proc.Start();
}
catch (Win32Exception ex)
{
MessageBox.Show("A win32 exception was caught: " + ex.Message);
}
catch (InvalidOperationException)
{
MessageBox.Show("The Process Exited Too Quickly, The Verb Could Not Be Executed." );
}
Verbs are a godsend when printing document types which are unsupported natively. By using a verb here I am giving the responsibility of printing this PDF file to a program which has registered itself as being able to perform this action via the windows API. Of course, if no such program exists the Verb using program will not be able to print. However, this case can be preemptively checked for by comparing your Verb to those in the StartInfo’s Verbs property. It is an array of strings, one for each supported Verb for the specified file type:
Predicate<string> stringComparePred = (string str) => info.Verb == str;
bool verbExists = Array.Exists<String>(proc.StartInfo.Verbs, stringComparePred);
It’s also possible to see if a Verb is unsupported via the exception thrown. If a program is launched with an unsupported Verb, the proc.Start() call will throw a Win32Exception with 1155 as the value of its NativeErrorCode property.
try
{
proc.Start();
}
catch (Win32Exception ex)
{
if (ex.NativeErrorCode == 1155)
{
//Application rejected the verb.
MessageBox.Show("The selected Verb is not supported by the launched application.");
}
}
Also, as I discussed in my previous article, the number of different return codes that can be returned in Win32Exception is quite large. I suggest handling the most important ones for the use case specifically and letting the rest fall into a catchall.
Verbs with Arguments
Some Verbs also cue the receiving application to expect additional arguments. Perhaps the best example of this is the printto verb. After specifying this verb the receiving application will expect the network path the specific printer to be specified in it’s arguments.
if (_currentFileInfo.Verb.ToLower() == "printto")
{
//Pass in default printer.
PrinterSettings settings = new PrinterSettings();
proc.StartInfo.Arguments = settings.PrinterName;
}
While printto is the only standard Verb which uses an argument, other Verbs may as well. However, because Verbs are ultimately determined by the application which defined them, it is impossible to know without either inferring it from the Verb’s definition in the File Type’s configuration screen or reading about it in the application’s documentation.
Hiding The Application Window
In some cases it may be undesirable to show the window of the application launched by a Verb. A great example of this is if you wanted to support printing Word files but didn’t want your end user to see the Word interface every time they print. This can be achieved by setting the CreateNoWindow property of the ProcessStartInfo class to true and its UseShellExecute property to false:
ProcessStartInfo info = new ProcessStartInfo(@"C:\printme.doc");
info.Verb = "print";
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process proc = new Process();
proc.StartInfo = info;
try
{
proc.Start();
}
catch (Win32Exception ex)
...
On a machine with Office installed, this code will launch an instance of Word in the background and print the document without the end user ever seeing a Microsoft Word interface.
As a side note, if the UseShellExecute property is set to true, a new window will be created regardless of the value of CreateNoWindow.
Conclusion
Using Verbs is a great way to automate printing documents and other very simple tasks. However, because the availability of a given Verb may vary on different software configurations, I would not suggest depending on them for applications which will see wide deployment.
In writing this article I built a small application which lets you select a file and select a Verb to perform on it from a list of available Verbs for that file’s extension. It’s a simple example which you may find helpful when getting started with Verbs.
Summary
Pros:
- Verbs are by far the easiest mode of interprocess interaction.
- Verbs are well supported for Microsoft applications and file types.
- Verbs work well for adding quick printing support for many document types.
Cons:
- The Verb you need may not be supported by your file type.
- You cannot specify a specific application with a Verb.
- Verbs are dependant on installed software and will act different on different software configurations.
Additional Information
The MSDN Documentation on using the .NET Verb API.
The MSDN Documentation on Verbs and File Associations.
A very complete Code Project article on .NET Verb Features.
A Code Project article on using advanced Verb features via shell32.dll.