.PrintActiveViewCS_Net\PrintActiveViewCS_Net.cs
Print active view
.PrintActiveViewCS_Net\PrintActiveViewCS_Net.cs
// Copyright 2006 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Drawing.Printing;
using System.Diagnostics;
using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.ADF.CATIDs;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Output;
using ESRI.ArcGIS.SystemUI;
using System.Collections;
using System.Windows.Forms;

namespace PrintActiveViewCS_Net
{
    /// <summary>
    /// PrintActiveViewCS_Net creates a command which will print the active view to the default printer's default page.
    /// </summary>
    [Guid("c18e5cf0-7a6f-484e-ae25-bea6559072e1")]
    [ClassInterface(ClassInterfaceType.None)]
    [ProgId("PrintActiveViewCS_Net.PrintActiveViewCS_Net")]
    public sealed class PrintActiveViewCS_Net : BaseCommand
    {
        #region COM Registration Function(s)
        [ComRegisterFunction()]
        [ComVisible(false)]
        static void RegisterFunction(Type registerType)
        {
            // Required for ArcGIS Component Category Registrar support
            ArcGISCategoryRegistration(registerType);

            //
            // TODO: Add any COM registration code here
            //
        }

        [ComUnregisterFunction()]
        [ComVisible(false)]
        static void UnregisterFunction(Type registerType)
        {
            // Required for ArcGIS Component Category Registrar support
            ArcGISCategoryUnregistration(registerType);

            //
            // TODO: Add any COM unregistration code here
            //
        }

        #region ArcGIS Component Category Registrar generated code
        /// <summary>
        /// Required method for ArcGIS Component Category registration -
        /// Do not modify the contents of this method with the code editor.
        /// </summary>
        private static void ArcGISCategoryRegistration(Type registerType)
        {
            string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID);
            MxCommands.Register(regKey);
            ControlsCommands.Register(regKey);

        }
        /// <summary>
        /// Required method for ArcGIS Component Category unregistration -
        /// Do not modify the contents of this method with the code editor.
        /// </summary>
        private static void ArcGISCategoryUnregistration(Type registerType)
        {
            string regKey = string.Format("HKEY_CLASSES_ROOT\\CLSID\\{{{0}}}", registerType.GUID);
            MxCommands.Unregister(regKey);
            ControlsCommands.Unregister(regKey);

        }

        #endregion
        #endregion
        /* GDI callback to GetDeviceCaps and CreateDC function */
        [DllImport("GDI32.dll")]
        public static extern int GetDeviceCaps(int hdc, int nIndex);

        [DllImport("GDI32.dll")]
        public static extern int CreateDC(string strDriver, string strDevice, string strOutput, IntPtr pData);

        [DllImport("User32.dll")]
        public static extern int ReleaseDC(int hWnd, int hDC);

        /* reference to the application itself */
        IHookHelper m_hookHelper;

        public PrintActiveViewCS_Net()
        {

            base.m_category = "Developer Samples";
            base.m_caption = "Print Active View CSharp.NET";
            base.m_message = "Prints the Active View to DEFAULT printer with CSharp.Net";
            base.m_toolTip = "Print Active View CSharp.NET";
            base.m_name = base.m_category + "_" + base.m_caption;

            try
            {
                // the bitmap for the tool's icon
                string bitmapResourceName = GetType().Name + ".bmp";
                base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
            }
        }

        #region Overriden Class Methods

        /// <summary>
        /// Occurs when this command is created
        /// </summary>
        /// <param name="hook">Instance of the application</param>
        public override void OnCreate(object hook)
        {
            if (m_hookHelper == null)

                m_hookHelper = new HookHelperClass();

            m_hookHelper.Hook = hook;

        }

        /// <summary>
        /// Occurs when this command is clicked
        /// </summary>
        public override void OnClick()
        {
            PrintActiveViewParameterized(3);
        }

        #endregion

        public void PrintActiveViewParameterized(long iResampleRatio)
        {

            /* Prints the Active View of the document to selected output format. */
            //          
            IActiveView docActiveView = m_hookHelper.ActiveView;
            IPrinter docPrinter;
            long iPrevOutputImageQuality;
            IOutputRasterSettings docOutputRasterSettings;
            tagRECT deviceRECT;
            IPaper docPaper;
            /* printdocument is from the .NET assembly system.drawing.printing */
            System.Drawing.Printing.PrintDocument sysPrintDocumentDocument;

            
            short iNumPages;
            IEnvelope docPrinterBounds;
            IEnvelope VisibleBounds;


            docPrinterBounds = new EnvelopeClass();
            VisibleBounds = new EnvelopeClass();

            // save the previous output image quality, so that when the export is complete it will be set back.
            docOutputRasterSettings = docActiveView.ScreenDisplay.DisplayTransformation as IOutputRasterSettings;
            iPrevOutputImageQuality = docOutputRasterSettings.ResampleRatio;

            SetOutputQuality(docActiveView, iResampleRatio);


            /* Now we need to get the default printer name.  Since this is a generic command,
             * we can't use the printername property of the document.  So instead, we use the 
             * System.Drawing.Printing objects to find the default printer.
             */
            docPrinter = new EmfPrinterClass();
            sysPrintDocumentDocument = new System.Drawing.Printing.PrintDocument();
            docPaper = new PaperClass();

            /* testing to see if printer instantiated in sysPrintDocumentDocument is the 
             * default printer.  It SHOULD be, but this is just a reality check.
             */
            bool isDefault = sysPrintDocumentDocument.PrinterSettings.IsDefaultPrinter;

            if (isDefault)
            {
                //Set docPaper's printername to the printername of the default printer
                docPaper.PrinterName = sysPrintDocumentDocument.PrinterSettings.PrinterName;
                               
            }
            else
            {
                //if we get an unexpected result, return.
                MessageBox.Show("Error getting default printer info, exiting...");
                return;
            }


            //make sure the paper orientation is set to the orientation matching the current view.
            docPaper.Orientation = m_hookHelper.PageLayout.Page.Orientation;

            /* Now assign docPrinter the paper and with it the printername.  This process is two steps
             * because you cannot change an IPrinter's printer except by passing it as a part of 
             * the IPaper.  That's why we setup docPrinter.Paper.PrinterName first.
             */
            docPrinter.Paper = docPaper;

            //set the spoolfilename (this is the job name that shows up in the print queue)
            docPrinter.SpoolFileName = "PrintActiveViewSample";

            // Get the printer's hDC, so we can use the Win32 GetDeviceCaps fuction to
            //  get Printer's Physical Printable Area x and y margins
            int hInfoDC;
            hInfoDC = CreateDC(docPrinter.DriverName, docPrinter.Paper.PrinterName, "", IntPtr.Zero);


            // Find out how many printer pages the output will cover. 
 
            
            if (m_hookHelper.ActiveView is IPageLayout)
            {
                
                m_hookHelper.PageLayout.Page.PrinterPageCount(docPrinter, 0, out iNumPages);

            }
            else
            {
                iNumPages = 1;
            }

            for (short lCurrentPageNum = 0; lCurrentPageNum < iNumPages; lCurrentPageNum++)
            {

                m_hookHelper.PageLayout.Page.GetDeviceBounds(docPrinter, lCurrentPageNum, 0, docPrinter.Resolution, docPrinterBounds);

                //Transfer PrinterBounds envelope, offsetting by PHYSICALOFFSETX
                // the Win32 constant for PHYSICALOFFSETX is 112
                // the Win32 constant for PHYSICALOFFSETY is 113
                deviceRECT.bottom = (int)(docPrinterBounds.YMax - GetDeviceCaps(hInfoDC, 113));
                deviceRECT.left = (int)(docPrinterBounds.XMin - GetDeviceCaps(hInfoDC, 112));
                deviceRECT.right = (int)(docPrinterBounds.XMax - GetDeviceCaps(hInfoDC, 112));
                deviceRECT.top = (int)(docPrinterBounds.YMin - GetDeviceCaps(hInfoDC, 113));

                // Transfer offsetted PrinterBounds envelope back to the deviceRECT
                docPrinterBounds.PutCoords(0, 0, deviceRECT.right - deviceRECT.left, deviceRECT.bottom - deviceRECT.top);



                if (m_hookHelper.ActiveView is IPageLayout)
                {
                    //get the visible bounds for this layout, based on the current page number.
                    m_hookHelper.PageLayout.Page.GetPageBounds(docPrinter, lCurrentPageNum, 0, VisibleBounds);
                }
                else
                {
                    //if it's not a page layout, export whatever's on screen at the printer's dpi.

                    //get the page
                    IPage pPage;
                    pPage = m_hookHelper.PageLayout.Page;

                    //get paper object
                    docPaper = docPrinter.Paper;
                    if (docPaper == null)
                    {
                        MessageBox.Show("no paper defined");
                        return;
                    }
                    
                    //create an envelope for the bounds of the printer's page size in device units.
                    IEnvelope pDeviceFrame;
                    pDeviceFrame = new EnvelopeClass();
                    pPage.GetDeviceBounds(docPrinter, 1, 0, docPrinter.Resolution, pDeviceFrame);

                    //create and populate an envelope with the bounds of the printer page.
                    WKSEnvelope wksdevice;
                    pDeviceFrame.QueryWKSCoords(out wksdevice);
                    
                    //transfer the envelope to the deviceRECT. 
                    deviceRECT.left = (int)Math.Round(wksdevice.XMin);
                    deviceRECT.top = (int)Math.Round(wksdevice.YMin);
                    deviceRECT.right = (int)Math.Round(wksdevice.XMax);
                    deviceRECT.bottom = (int)Math.Round(wksdevice.YMax);

                    //since this is a data view, not a pagelayout, we don't need VisibleBounds, so set it to NULL.
                    VisibleBounds = null;

                }

                
                //Here's where the printing actually begins:
                //==========================================
                //The docPrinter.StartPrinting method returns the hDC of the printer, which we then
                //use as the hDC parameter of activeview.output.  ActiveView.Output is the function that
                //draws the content on the active view, at the specified resolution, to the deviceRECT specified.
                //VisibleBounds can be null, which means "print the active view", or can be set to a zoom extent.
                if (iNumPages == 1)
                {
                    VisibleBounds = null;
                }
                m_hookHelper.ActiveView.Output(docPrinter.StartPrinting(docPrinterBounds, 0), docPrinter.Resolution, ref deviceRECT, VisibleBounds, null);

                //here we call FinishPrinting, which actually flushes the output to the printer.
                docPrinter.FinishPrinting();
                
                //now set the output quality back to the previous output quality.
                SetOutputQuality(docActiveView, iPrevOutputImageQuality);
                                
            }
            //release the DC...
            ReleaseDC(0, hInfoDC);
        }
        private void SetOutputQuality(IActiveView docActiveView, long iResampleRatio)
        {
            /* This function sets OutputImageQuality for the active view.  If the active view is a pagelayout, then
             * it must also set the output image quality for EACH of the Maps in the pagelayout.
             */
            IGraphicsContainer docGraphicsContainer;
            IElement docElement;
            IOutputRasterSettings docOutputRasterSettings;
            IMapFrame docMapFrame;
            IActiveView tmpActiveView;

            if (docActiveView is IMap)
            {
                docOutputRasterSettings = docActiveView.ScreenDisplay.DisplayTransformation as IOutputRasterSettings;
                docOutputRasterSettings.ResampleRatio = (int)iResampleRatio;
            }
            else if (docActiveView is IPageLayout)
            {
                //assign ResampleRatio for PageLayout
                docOutputRasterSettings = docActiveView.ScreenDisplay.DisplayTransformation as IOutputRasterSettings;
                docOutputRasterSettings.ResampleRatio = (int)iResampleRatio;
                //and assign ResampleRatio to the Maps in the PageLayout
                docGraphicsContainer = docActiveView as IGraphicsContainer;
                docGraphicsContainer.Reset();

                docElement = docGraphicsContainer.Next();
                while (docElement != null)
                {
                    if (docElement is IMapFrame)
                    {
                        docMapFrame = docElement as IMapFrame;
                        tmpActiveView = docMapFrame.Map as IActiveView;
                        docOutputRasterSettings = tmpActiveView.ScreenDisplay.DisplayTransformation as IOutputRasterSettings;
                        docOutputRasterSettings.ResampleRatio = (int)iResampleRatio;
                    }
                    docElement = docGraphicsContainer.Next();
                }

                docMapFrame = null;
                docGraphicsContainer = null;
                tmpActiveView = null;
            }
            docOutputRasterSettings = null;

        }

    }
}