Microsoft Word Interop automation FilePrintSetup Error

3.7k views Asked by At

I am getting "There is a printer error." when tying to send a print job to a printer using automation on Windows 7 with Word 2010. Same code works fine on Windows XP box with Word 2007. I am not sure if Windows 7 or word 2010 is causing the error.

Any help appreciated

using Microsoft.Office.Interop.Word;
.....

object oWordbasic = wordDoc.Application.WordBasic;

object[] argValues = new object[] { value, 1  }; //first arg is a printer name
String[] argNames = new String[] { "Printer", "DoNotSetAsSysDefault", };

//Error Here
oWordbasic.GetType().InvokeMember("FilePrintSetup", System.Reflection.BindingFlags.InvokeMethod, null, oWordbasic, argValues, null, null, argNames);

I get the Error Below

System.Reflection.TargetInvocationException was caught
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeType.InvokeDispMethod(String name, BindingFlags invokeAttr, Object target, Object[] args, Boolean[] byrefModifiers, Int32 culture, String[] namedParameters)
       at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
       at PBP.ABC.Framework.Wrappers.Microsoft.Word.WordDocument.set_ActivePrinterName(String value) in 
  InnerException: System.Runtime.InteropServices.COMException
       HelpLink=wdmain11.chm#24696
       Message=There is a printer error.
       Source=Microsoft Word
       ErrorCode=-2146827168
       InnerException: 

If I leave out the printer parameters, the invoke work but not printing to the printer specified. It will print to the default printer.

Thanks.

2

There are 2 answers

0
Pete On BEST ANSWER

Might work for you - this is what I had to do in Word to print without changing the active printer, I was getting an error and found that sometimes Word liked just the printer name and other times wanted to also have the port.

... to get the printer names and ports use InstalledPrinter as below

private InstalledPrinter PreferredPrinter { get; set; }
private InstalledPrinter DefaultPrinter { get; set; }

    private void SetDefaultAndPreferredPrinters()
    {
        if (UserSettings[SETTING_PREFERRED_PRINTER] == null)
        {
            UserSettings[SETTING_PREFERRED_PRINTER] = string.Empty;
        }
        _preferredPrinterName = ((string)UserSettings[SETTING_PREFERRED_PRINTER]).Trim();

        List<InstalledPrinter> installedPrinters = InstalledPrinter.GetList();

        DefaultPrinter = null;
        PreferredPrinter = null;

        foreach (InstalledPrinter installedPrinter in installedPrinters)
        {
            if (installedPrinter.IsDefault)
            {
                DefaultPrinter = installedPrinter;
            }
            if (installedPrinter.Name.Equals(_preferredPrinterName, StringComparison.InvariantCultureIgnoreCase))
            {
                PreferredPrinter = installedPrinter;
            }
        }
    }

public enum PrinterStatus{
  Other = 1,
  Unknown,
  Idle,
  Printing,
  Warmup,
  Stopped,
  Offline,
  Degraded
}

public class InstalledPrinter{

        private static readonly ILog _s_logger =
        LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

public string DriverName { get; set; }

public string Location { get; set; }

public string Name { get; set; }

public bool Network { get; set; }

public string PortName { get; set; }

public string ServerName { get; set; }

public bool Shared { get; set; }

public PrinterStatus Status { get; set; }

public bool WorkOffline { get; set; }

public bool IsDefault { get; set; }

public static List<InstalledPrinter> GetList()
{
    PrinterSettings ps = new PrinterSettings();
        string sDefault = ps.PrinterName;

    string query = "Select * From Win32_Printer";

    ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);

    ManagementObjectCollection results = searcher.Get();

    List<InstalledPrinter> list = new List<InstalledPrinter>(results.Count);

    foreach (ManagementObject printManagementObject in results)
    {
        InstalledPrinter entry = new InstalledPrinter();

        foreach (PropertyInfo propertyInfo in typeof(InstalledPrinter).GetProperties()) {
            object[] oparams = {1};
            if (propertyInfo.Name != "IsDefault") {//The IsDefault property is worked out logically, the rest of the properties map identically to the columns of the WMI query results.
                try {
                    oparams[0] = ConvertValue(
                        printManagementObject[propertyInfo.Name], propertyInfo.PropertyType);
                    propertyInfo.GetSetMethod().Invoke(
                        entry,
                        oparams);
                }catch(Exception e) {
                    _s_logger.Error(string.Format("Failed to enumerate printer property Name:{0}, Type:{1}", propertyInfo.Name, propertyInfo.PropertyType));
                }
            }
        }
        _s_logger.Info(string.Format("Finished enumerating properties of printer: {0}", entry.Name == null ? "<Null>" : entry.Name));
        if (sDefault.Equals(entry.Name, StringComparison.CurrentCultureIgnoreCase)) {
            entry.IsDefault = true;
        }
        list.Add(entry);
    }
    return list;
}

private static object ConvertValue(object value, Type type)
{
    if (value != null)
    {
        object printerStatusRetval = null;
        if (type == typeof(DateTime))
        {
            string time = value.ToString();
            time = time.Substring(0, time.IndexOf("."));
            return DateTime.ParseExact(time, "yyyyMMddHHmmss", null);
        }
        else if (type == typeof(long))
            return Convert.ToInt64(value);
        else if (type == typeof(int))
            return Convert.ToInt32(value);
        else if (type == typeof(short))
            return Convert.ToInt16(value);
        else if (type == typeof(string))
            return value.ToString();
        else if (type == typeof(PrinterStatus))
            try {
                printerStatusRetval = Enum.Parse(typeof (PrinterStatus), value.ToString());
            } catch (Exception e) {
                _s_logger.Error(string.Format("Failed to convert PrinterStatus with value {0}", value));
                printerStatusRetval = value.ToString();
            }
                return printerStatusRetval;
    }
    return null;
}

}

...then after instantiating Word I have something like this to set the printer:

            object[] oWordDialogParams = {PreferredPrinter.Name, true};
            object[] oWordDialogParamsWithPort = {string.Format("{0} on {1}", PreferredPrinter.Name, PreferredPrinter.PortName), true};
            string[] argNames = {"Printer", "DoNotSetAsSysDefault"};
//oWord is my own class that provides a fairly simple wrapper around MS Word
            oWord.Application.ActivePrinter = UserSettings[SETTING_PREFERRED_PRINTER] as string;
            Dialog printDialog = oWord.Application.Dialogs[WdWordDialog.wdDialogFilePrintSetup];
            object wordBasic = oWord.Application.WordBasic;
            try {
                wordBasic.GetType().InvokeMember("FilePrintSetup"
                    , BindingFlags.InvokeMethod
                    , null
                    , wordBasic
                    , oWordDialogParams
                    , null
                    , null
                    , argNames);
            }catch(Exception e) {
                _s_logger.Info("Failed to print using printer name, trying printer name and port", e);
                try {
                    wordBasic.GetType().InvokeMember("FilePrintSetup"
                        , BindingFlags.InvokeMethod
                        , null
                        , wordBasic
                        , oWordDialogParamsWithPort
                        , null
                        , null
                        , argNames);
                }catch(Exception e2) {
                    _s_logger.Info("Failed to print using printer name and port", e2);
                    throw;
                }
            }
0
Deepfreezed On

Did not find a way to fix the issue. Put in a if condition to handle Word 2010 differently and use unmanaged code to print. Link outlines how to do this