分配给Excel.Application.ActivePrinter时出现COMException

时间:2013-02-13 22:12:00

标签: .net vb.net excel com comexception

我有一个函数,我正在传递一个Microsoft.Office.Interop.Excel.Application实例。该功能使用Windows内置的传真打印机或Microsoft XPS Document Writer将文件保存为tiff图像。

但是,当我尝试分配给应用程序的ActivePrinter属性时,会抛出带有以下消息的COMException:

  

HRESULT的异常:0x800A03EC

以下是代码:

'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

使用的打印机都已确认为已安装/在注册表中。采用Word应用程序类的类似函数可以正常工作。 我对COM相关的东西很新,而且我有一种感觉,这可能只是我在游戏中与excel相关的无知,但我在搜索google / stackoverflow时几乎找不到与此相关的内容,除了一两个旧的,未答复的线程。有一些涉及大量数据/大范围,但不涉及ActivePrinter属性

编辑 - 答案的简短摘要,详见M Patel的链接:

Excel对于设置它的ActivePrinter属性很挑剔;而不是打印机名称,它需要打印机和端口,例如“在Ne01上传真:”。 该端口应该可以从注册表中获得,可以在:

  

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

  

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

使用链接中详述的方法,或者在我的情况下使用Microsoft.Win32.Registry.GetValue()。后者将返回“winspool,Ne01:”的内容。 以“在Ne01上传真:”的方式将该字符串的最后一部分连接到打印机名称,允许设置ActivePrinter属性,没有例外。

我还应该注意到我的问题发生在excel 2010

2 个答案:

答案 0 :(得分:2)

使用excel interop打印excel doc时遇到了同样的异常。

使用MS Word: -

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

但是使用MS Excel: -

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

以下是使用office interop打印任何办公室(MS Word,MS Excel,PS Powerpoint)文档的一般功能。

    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;
    }

将以上功能用于MS Excel时,我会更新打印机名称,如下所示。在从MS Excel实例将打印机名称传递给上述函数时,我使用

    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;
    }

进一步检查可以做到这一点:

1)使用PrinterSettings类检查目标打印机是否存在。

2)(打印到文件)检查打印选项是否为PDF / To XPS / FAX等。

答案 1 :(得分:1)