Home » excel » .net – COMException when assigning to Excel.Application.ActivePrinter

.net – COMException when assigning to Excel.Application.ActivePrinter

Posted by: admin May 14, 2020 Leave a comment

Questions:

I have a function, into which I’m passing an Microsoft.Office.Interop.Excel.Application instance. The function uses Windows’ built in Fax printer, or the Microsoft XPS Document Writer, to save the file as a tiff image.

However, when I try to assign to the application’s ActivePrinter property, a COMException with the following message is thrown:

Exception from HRESULT: 0x800A03EC

Here’s the code:

'Save the current default printer
Dim strDefaultPrinter As String = excelApp.ActivePrinter 

'Assign printer string constant to ActivePrinter - throws exception
excelApp.ActivePrinter = FAX_PRINTER

excelApp.ActiveWorkbook.PrintOutEx(, , , , , True, "c:\RestOfFilePath...") ' Print to file = true

'Reset the default printer
excelApp.ActivePrinter = strDefaultPrinter

The printers used are all confirmed as installed/in the registry. A similar function that takes a Word application class works fine.
I’m pretty new to COM related stuff, and I have a feeling this may just be my excel-related ignorance at play, but I can find almost nothing relating to this when searching google/stackoverflow, except for one or two old, unanswered threads. There are a few that relate to large amounts of data/large ranges, but not the ActivePrinter property

EDIT – A brief summary of the answer, detailed in M Patel’s link:

Excel is picky about setting it’s ActivePrinter property; instead of printer name alone, it requires both printer and port, e.g. “Fax on Ne01:”.
This port should be available from the registry, either at:

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Devices

or

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Devices

Using the method detailed in the link, or in my case using Microsoft.Win32.Registry.GetValue(). The latter will return something along the lines of “winspool,Ne01:”.
Concatenating the last part of that string on to the printer name in the manner “Fax on Ne01:”, allows the ActivePrinter property to be set without the exception.

I should also note that my problem was occurring in excel 2010

How to&Answers:

Maybe the link below will help? It looks like the formatting of the name you assign to the ActivePrinter property matters.

http://netindonesia.net/blogs/jimmy/archive/2011/02/25/how-to-change-the-active-printer-to-specific-printer-in-excel-using-net-and-how-the-heck-can-i-find-the-right-printer-name-and-port-combination-that-excel-wants.aspx

Answer:

I had the same exception while printing the excel doc using excel interop.

With MS Word :-

document.Application.ActivePrinter = "Brother MFC.. Printer"; // Works without exception

But with MS Excel :-

document.Application.ActivePrinter = "Brother MFC.. Printer"; // throws COM exception

Below is a general function to print any office(MS Word, MS Excel, PS Powerpoint) document using office interop.

    void PrintToPrinter(dynamic app, dynamic document, string printer, int numberOfCopies)
    {
        bool PrintToFile = false;

        // Trying to print document without activation throws print exception
        document.Activate();

        // The only way to change printer is to set the default printer of document or of application
        // Remember the active printer name to reset after printing document with intended printer
        oldPrinterName = document.Application.ActivePrinter;

        for (int retry = 0; retry < retryLimit; retry++)
        {
            try
            {
                if (!GetActivePrinter(document).Contains(printer))
                {
                    try
                    {
                        document.Application.ActivePrinter = printer;
                        docPrinterChanged = true;                            
                    }
                    catch (Exception)
                    {
                        try
                        {
                            app.ActivePrinter = printer;
                            appPrinterChanged = true;
                        }
                        catch (Exception)
                        {
                            continue;
                        }
                    }
                }
                object oMissing = System.Reflection.Missing.Value;
                document.PrintOut(
                   true,            // Background
                   false,           // Append overwrite
                   oMissing,        // Page Range
                   oMissing,        // Print To File - OutputFileName
                   oMissing,        // From page
                   oMissing,        // To page
                   oMissing,        // Item
                   numberOfCopies,  // Number of copies to be printed
                   oMissing,        //
                   oMissing,        //
                   PrintToFile,     // Print To file
                   true             // Collate
                   );
                break;
            }
            catch (Exception)
            {
                continue;
            }
        }
        try
        {
            if(docPrinterChanged)
                document.Application.ActivePrinter = oldPrinterName;
            else if(appPrinterChanged)
                app.ActivePrinter = oldPrinterName;   
        }
        catch (Exception)
        {
        }
    }

    private static string GetActivePrinter(dynamic document)
    {

        string activePrinter = document.Application.ActivePrinter;

        if (activePrinter.Length >= 0)
            return activePrinter;
        return null;
    }

When using the above function for MS Excel I update the printer name as shown below. While passing the printer name to the above function from MS Excel instance, I use

    bool IFilePrint.PrintFile(string fullFileName, string printerName, int numberOfCopies)
    {

        // .......

        Excel.Workbook document = null;
        try
        {
            document = this.Application.Workbooks.Open(fullFileName);
        }
        catch
        {
            document = null;
        }

        string portNumber = null;

        // Find correct printerport
        using (RegistryKey key = Registry.CurrentUser.OpenSubKey(fullFileName))
        {
            if (key != null)
            {
                object value = key.GetValue(printerName);
                if (value != null)
                {
                    string[] values = value.ToString().Split(',');
                    if (values.Length >= 2) port = values[1];
                }
            }
        }

        // Get current concatenation string ('on' in en, 'auf' in de, etc..)
        var split = this.Application.ActivePrinter.Split(' ');
        if (split.Length >= 3)
            printerName = String.Format("{0} {1} {2}", printerName, split[split.Length - 2], port);

        PrintToPrinter(this.Application, document, printerName, numberOfCopies);

        // ...........
        }
        catch (Exception)
        { }
        result = true;   
        return result;
    }

Further check on this can done:

1) Check if the intended printer exists using PrinterSettings class.

2) (Print to file) Check if intended print option is To PDF/ To XPS / FAX etc.