【问题标题】:C# Capture Microsoft Print to PDF dialogC# 捕获 Microsoft 打印到 PDF 对话框
【发布时间】:2019-02-09 20:00:19
【问题描述】:

我想捕获并禁止在非办公应用程序中使用 Microsoft Print to PDF 驱动程序时显示的 Savefiledialog。然后以编程方式输入文件路径,可能使用 System.Windows.Automation。

当 SaveFileDialog 显示时,我似乎找不到句柄。我相信我可以处理 Windows.Automation 部分。

我想使用 Microsoft 驱动程序,因为它随所有 Windows 10 一起提供。

还有其他方法可以捕获/抑制此对话框吗?我目前通过注册表在本地计算机上使用另一个 pdf 驱动程序执行此操作。但我想转向 Microsoft PDF,因为它是标准的。

主题: How to programmatically print to PDF file without prompting for filename in C# using the Microsoft Print To PDF printer that comes with Windows 10 - 不能解决我的问题,从 Revit API 运行时会打印一个空白页。 Autodesk Revit 必须启动打印(并通过其 api 完成)。

尝试从 user32.dll 中查找对话框的代码

public static List<IntPtr>GetChildWindows( IntPtr parent) {
  List<IntPtr>result=new List<IntPtr>();
  GCHandle listHandle=GCHandle.Alloc(result);
  try {
    EnumWindowProc childProc=new EnumWindowProc(EnumWindow);
    EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
  }
  finally {
    if (listHandle.IsAllocated) listHandle.Free();
  }
  return result;
}

public static string GetText(IntPtr hWnd) {
  int length=GetWindowTextLength(hWnd);
  StringBuilder sb=new StringBuilder(length + 1);
  GetWindowText(hWnd, sb, sb.Capacity);
  return sb.ToString();
}

private void Test() {
  Process[] revits=Process.GetProcessesByName( "Revit");
  List<IntPtr>children=GetChildWindows( revits[0].MainWindowHandle);
  var names=new List<string>();
  foreach (var child in children) {
    names.Add(GetText(child));
  }
}

【问题讨论】:

  • @你的编辑:所以如果那个 API 控制着打印,你怎么能从用户代码中截取打印机通信呢?还是那是您的实际问题?因为我认为当我们可以将文件名注入到进程中时,“重复”帖子仍然会有助于一个可能的解决方案。
  • 是您的进程调用 print 然后导致保存对话框,还是由另一个进程启动?只是想知道到目前为止您为找到窗口句柄所做的尝试。我假设您已经尝试过来自 user32.dll 的EnumWindows。如果您获得启动“保存”对话框的进程的主窗口,我认为您应该能够在该进程的子窗口下找到它。您能否发布不起作用的代码,以便我们知道您尝试了什么?
  • @dlatikay - API 控制打印过程,我无法拦截它以传递信息。
  • @pstrjds 我可以获取主窗口,但似乎无法获取小时候的对话框。代码发布

标签: c# pdf revit-api


【解决方案1】:

我在自己的系统上运行了一些测试,似乎枚举顶级窗口会找到“保存文件”对话框。我尝试从多个程序打印到 MS PDF 打印机,结果都是一样的。下面是改编自MS Docs 窗口枚举示例的一些代码。我在代码中添加了获取进程 ID,因此您可以检查以确保它是您的窗口。

// P/Invoke declarations
protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);

// Callback for examining the window
protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
    int size = GetWindowTextLength(hWnd);
    if (size++ > 0 && IsWindowVisible(hWnd))
    {
        StringBuilder sb = new StringBuilder(size);
        GetWindowText(hWnd, sb, size);
        if (sb.ToString().Equals("Save Print Output As", StringComparison.Ordinal))
        {
            uint procId = 0;
            GetWindowThreadProcessId(hWnd, out procId);
            Console.WriteLine($"Found it! ProcID: {procId}");
        }
    }
    return true;
}

void Main()
{
   EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero);
}

【讨论】:

  • 我在玩 spy++,但没有太多使用经验。我一直认为保存文件对话框是 Revit 的子项。
  • @Ryan - 我认为它也是一个子窗口,但后来我认为值得尝试看看它是否是一个顶级窗口,因为你显然有代码来枚举子窗口那是行不通的。我启动了 Spy++,果然它被列为顶级窗口,所以我拿了示例代码,做了一些调整,结果很好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多