8

これはとても単純な必要性のように思えますが、どういうわけか私はこれを達成する方法を見つけることができません。私はこのようなコードを持っています:

Microsoft.Office.Interop.Word.Application word = new Microsoft.Office.Interop.Word.Application();
MemoryStream documentStream = getDocStream();
FileInfo wordFile = new FileInfo("c:\\test.docx");
object fileObject = wordFile.FullName;
object oMissing = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Word.Document doc = wordInstance.Documents.Open(ref fileObject, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);
doc.Activate();
doc.PrintOut(oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);

使用するプリンターとトレイの設定ドライブが必要です。調べてみると、Microsoft.Office.Interop.Word.Application.ActivePrinterが見つかりました。これは、ドキュメントに「アクティブなプリンタの名前」と記載されている設定可能な文字列プロパティですが、プリンタにとってそれが何を意味するのかわかりません。 「アクティブプリンタ」、特に2つある場合。これはどのように達成できますか?

4

3 に答える 3

16

TL;DR特定のプリンターに印刷することはできません。デフォルトのプリンタを使用したいものに変更する必要があります。その後、通常どおりに印刷します。

この分野で最初に作業を行ってから状況が劇的に変化した可能性がありますが、特定のプリンターに印刷する方法を見つけることができませんでした。その代わりに、システムのデフォルトプリンターを必要なものに変更し、そのコンピューターで必要なすべてのドキュメントを印刷してから、以前の状態に戻しました。(実際には、他に特定のデフォルトプリンターを期待していなかったため、元に戻すのをやめました。したがって、それは問題ではありませんでした)。

短い答え:

Microsoft.Office.Interop.Word._Application _app = [some valid COM instance];
Microsoft.Office.Interop.Word.Document doc = _app.Documents.Open(ref fileName, ...);
doc.Application.ActivePrinter = "name of printer";
doc.PrintOut(/* ref options */);

しかし、これは非常に信頼性が低いことがわかりました。詳細については、以下をお読みください。

まだ行っていない場合は、とのすべてのありふれた作業ビットを処理するために、独自のラッパークラスを構築することを強くお勧めし_Documentます_Application。当時ほど悪くはないかもしれませんが(dynamic私たちにとっては選択肢ではありませんでした)、それでも良い考えです。あなたはこれに特定のおいしいコードが欠けていることに気付くでしょう...私はあなたが求めているものに関連するコードに焦点を合わせようとしました。また、このDocWrapperクラスはコードの多くの別々の部分のマージです-無秩序を許してください。最後に、例外処理が奇妙である(または例外をスローすることによる設計が不十分である)と考える場合、私は多くの場所からコードの一部をまとめようとしていることを忘れないでください(独自のカスタムタイプも除外しています)。コード内のコメントを読んでください、彼らは重要です。

class DocWrapper
{
  private const int _exceptionLimit = 4;

  // should be a singleton instance of wrapper for Word
  // the code below assumes this was set beforehand
  // (e.g. from another helper method)
  private static Microsoft.Office.Interop.Word._Application _app;

  public virtual void PrintToSpecificPrinter(string fileName, string printer)
  {
    // Sometimes Word fails, so needs to be restarted.
    // Sometimes it's not Word's fault.
    // Either way, having this in a retry-loop is more robust.
    for (int retry = 0; retry < _exceptionLimit; retry++)
    {
      if (TryOncePrintToSpecificPrinter(fileName, printer))
        break;

      if (retry == _exceptionLimit - 1) // this was our last chance
      {
        // if it didn't have actual exceptions, but was not able to change the printer, we should notify somebody:
        throw new Exception("Failed to change printer.");
      }
    }
  }

  private bool TryOncePrintToSpecificPrinter(string fileName, string printer)
  {
    Microsoft.Office.Interop.Word.Document doc = null;

    try
    {
      doc = OpenDocument(fileName);

      if (!SetActivePrinter(doc, printer))
        return false;

      Print(doc);

      return true; // we did what we wanted to do here
    }
    catch (Exception e)
    {
      if (retry == _exceptionLimit)
      {
        throw new Exception("Word printing failed.", e);
      }
      // restart Word, remembering to keep an appropriate delay between Quit and Start.
      // this should really be handled by wrapper classes
    }
    finally
    {
      if (doc != null)
      {
        // release your doc (COM) object and do whatever other cleanup you need
      }
    }

    return false;
  }

  private void Print(Microsoft.Office.Interop.Word.Document doc)
  {
    // do the actual printing:
    doc.Activate();
    Thread.Sleep(TimeSpan.FromSeconds(1)); // emperical testing found this to be sufficient for our system
    // (a delay may not be required for you if you are printing only one document at a time)
    doc.PrintOut(/* ref objects */);
  }

  private bool SetActivePrinter(Microsoft.Office.Interop.Word.Document doc, string printer)
  {
    string oldPrinter = GetActivePrinter(doc); // save this if you want to preserve the existing "default"

    if (printer == null)
      return false;

    if (oldPrinter != printer)
    {
      // conditionally change the default printer ...
      // we found it inefficient to change the default printer if we don't have to. YMMV.
      doc.Application.ActivePrinter = printer;
      Thread.Sleep(TimeSpan.FromSeconds(5)); // emperical testing found this to be sufficient for our system
      if (GetActivePrinter(doc) != printer)
      {
        // don't quit-and-restart Word, this one actually isn't Word's fault -- just try again
        return false;
      }

      // successful printer switch! (as near as anyone can tell)
    }

    return true;
  }

  private Microsoft.Office.Interop.Word.Document OpenDocument(string fileName)
  {
    return _app.Documents.Open(ref fileName, /* other refs */);
  }

  private string GetActivePrinter(Microsoft.Office.Interop.Word._Document doc)
  {
    string activePrinter = doc.Application.ActivePrinter;
    int onIndex = activePrinter.LastIndexOf(" on ");
    if (onIndex >= 0)
    {
      activePrinter = activePrinter.Substring(0, onIndex);
    }
    return activePrinter;
  }
}
于 2012-06-20T22:42:21.457 に答える
2

プリンターを指定する方法はありますが、システムのデフォルトとして設定しないでください(C ++ / CLRを使用していますが、C#に移植可能である必要があります)。

String^ printername = "...";
auto wordapp= gcnew Microsoft::Office::Interop::Word::Application();
if (wordapp != nullptr)
{
  cli::array<Object^>^ argValues= gcnew cli::array<Object^>(2);
  argValues[0]= printername;
  argValues[1]= 1;
  cli::array<String^>^ argNames= gcnew cli::array<String^>(2);
  argNames[0]= "Printer";
  argNames[1]= "DoNotSetAsSysDefault";
  Object^ wb= wordapp->WordBasic;
  wb->GetType()->InvokeMember( "FilePrintSetup", System::Reflection::BindingFlags::InvokeMethod, nullptr, wb, argValues, nullptr, nullptr, argNames);
}
于 2016-02-15T14:35:36.703 に答える
1

Word.Applicationを使用したC#プロジェクトを継承しました。これはC#プロジェクトであり、翻訳は非常に簡単に思えたので、@ Lars C ++コードを使用し、プロジェクトにC#翻訳メソッドを追加しました。誰かの生活を少し楽にすることを期待して、彼のコードの直接翻訳をここに投稿します。

string printername = "...";
var wordapp = new Microsoft.Office.Interop.Word.Application();
if (wordapp != null)
{
    object[] argValues = new object[2];
    argValues[0] = printername;
    argValues[1] = 1;
    string[] argNames = new string[2];
    argNames[0] = "Printer";
    argNames[1] = "DoNotSetAsSysDefault";
    var wb = wordapp.WordBasic;
    wb.GetType().InvokeMember("FilePrintSetup", System.Reflection.BindingFlags.InvokeMethod, null, wb, argValues, null, null, argNames);
}
于 2018-11-09T22:31:02.303 に答える