[WPF] How to get the handle to device context for printing page using DocumentPaginator?

Deepak Gunasekaran 61 Reputation points
2021-01-06T11:55:31.037+00:00

We need to get the handle to the device context of the pages, when printing to render some vector contents in the page from an unmanaged (C++) library.

Unfortunately there is no some option available in the pages of DocumentPaginator as easily as we get from the Graphics of the print page in Windows Forms using GetHdc functionality in the OnPrintPage method.

As an alternate, we have tried to create FixedPage with UIElements as we could get the handle source using PresentationSource.FromVisual. But this has provided he value when it is added to Window and it come to view after applying the template. The print page will not come to view or cannot be attached to Window, so the values are always null.

It is possible to achieve in WinForms or using WinForms dependencies in WPF. But we need to achieve it in pure WPF. So, it is possible to achieve it in WPF without WinForms dependency and without bringing the UI element to view?

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,676 questions
Windows Server Printing
Windows Server Printing
Windows Server: A family of Microsoft server operating systems that support enterprise-level management, data storage, applications, and communications.Printing: Printer centralized deployment and management, scan and fax resources management, and document services
641 questions
{count} votes

3 answers

Sort by: Most helpful
  1. DaisyTian-1203 11,616 Reputation points
    2021-01-07T08:02:57.917+00:00

    As far as I know, WPF doesn't use device contexts.You can use WindowInteropHelper.Handle to get the window handle for a WPF window that is used to create this WindowInteropHelper. Then use GetDC to get the device context . You need to add using System.Windows.Interop; to use it.

     [DllImport("user32.dll")]  
        static extern IntPtr GetDC(IntPtr hWnd);  
    
        private void Window_Loaded(object sender, RoutedEventArgs e)  
        {  
            WindowInteropHelper wndHelper = new WindowInteropHelper(this);  
    
            IntPtr wpfHwnd = wndHelper.Handle;  
    
            IntPtr hdc = GetDC(wpfHwnd);  
        }  
    

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  2. DaisyTian-1203 11,616 Reputation points
    2021-01-12T02:40:27.813+00:00

    Here is my demo to test with the printer "Microsoft print to PDF":
    Code for xaml:

     <Button Name="btnPrintToPdf" Width="120" Height="38" Content="Print to PDF" Click="btnPrintToPdf_Click"></Button>  
    

    Code for cs:

    using System.Windows;  
    using System.Drawing.Drawing2D;  
    using Color = System.Drawing.Color;  
    using Pen = System.Drawing.Pen;  
    using System.Drawing;  
    using System.Drawing.Printing;  
      
    namespace MicrosoftPrintToPDF_Demo  
    {  
        public partial class MainWindow : Window  
        {  
            public MainWindow()  
            {  
                InitializeComponent();  
            }  
      
            private int NextPage = 0;  
      
            private void btnPrintToPdf_Click(object sender, RoutedEventArgs e)  
            {  
                PrintDocument pdocShapes = new PrintDocument();  
                NextPage = 0;  
                pdocShapes.PrinterSettings.PrinterName = "Microsoft Print to PDF";  
                pdocShapes.PrintPage += new PrintPageEventHandler(this.pdocShapes_PrintPage);  
                pdocShapes.Print();  
            }  
      
            private void pdocShapes_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)  
            {  
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;  
                switch (NextPage)  
                {  
                    case 0:  
                        using (Pen pen = new Pen(Color.Red, 10))  
                        {  
                            e.Graphics.DrawEllipse(pen, e.MarginBounds);  
                        }  
                        break;  
      
                    case 1:  
                        using (Pen pen = new Pen(Color.Green, 10))  
                        {  
                            e.Graphics.DrawRectangle(pen, e.MarginBounds);  
                        }  
                        break;  
      
                    case 2:  
                        using (Pen pen = new Pen(Color.Blue, 10))  
                        {  
                            PointF[] points =  
                            {  
                                new PointF(  
                                    e.MarginBounds.Left,  
                                    e.MarginBounds.Top + e.MarginBounds.Height / 2),  
                                new PointF(  
                                    e.MarginBounds.Left + e.MarginBounds.Width / 2,  
                                    e.MarginBounds.Top),  
                                new PointF(  
                                    e.MarginBounds.Right,  
                                    e.MarginBounds.Top + e.MarginBounds.Height / 2),  
                                new PointF(  
                                    e.MarginBounds.Left + e.MarginBounds.Width / 2,  
                                    e.MarginBounds.Bottom),  
                            };  
                            e.Graphics.DrawPolygon(pen, points);  
                        }  
                        break;  
                }  
                NextPage++;  
                e.HasMorePages = (NextPage <= 2);  
            }       
        }  
    }  
    

    If it is not meet your requirement, please let me know and give more details for me to implement.


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


  3. DaisyTian-1203 11,616 Reputation points
    2021-01-21T09:55:56.31+00:00

    The below code may give you some help:

     [DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);  
      
      
            [DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool ClosePrinter(IntPtr hPrinter);  
      
      
            [DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);  
      
      
            [DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool EndDocPrinter(IntPtr hPrinter);  
      
      
            [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool StartPagePrinter(IntPtr hPrinter);  
      
      
            [DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool EndPagePrinter(IntPtr hPrinter);  
      
      
            [DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]  
            public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);  
      
      
            public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)  
            {  
                Int32 dwError = 0, dwWritten = 0;  
                IntPtr hPrinter = new IntPtr(0);  
                DOCINFOA di = new DOCINFOA();  
                bool bSuccess = false; // Assume failure unless you specifically succeed.  
      
                di.pDocName = "My C#.NET RAW Document";  
                di.pDataType = "RAW";  
      
                if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))  
                {  
                    if (StartDocPrinter(hPrinter, 1, di))  
                    {  
                        if (StartPagePrinter(hPrinter))  
                        {  
                            bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);  
                            EndPagePrinter(hPrinter);  
                        }  
                        EndDocPrinter(hPrinter);  
                    }  
                    ClosePrinter(hPrinter);  
                }  
                if (bSuccess == false)  
                {  
                    dwError = Marshal.GetLastWin32Error();  
                }  
                return bSuccess;  
            }  
      
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]  
            public class DOCINFOA  
            {  
                [MarshalAs(UnmanagedType.LPStr)]  
                public string pDocName;  
                [MarshalAs(UnmanagedType.LPStr)]  
                public string pOutputFile;  
                [MarshalAs(UnmanagedType.LPStr)]  
                public string pDataType;  
            }  
    

    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments