Maybe the link below will help? It looks like the formatting of the name you assign to the ActivePrinter property matters.
COMException when assigning to Excel.Application.ActivePrinter
-
09-03-2022 - |
Question
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
Solution 2
OTHER TIPS
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.