How to enable and disable a printer by using the SetPrinter function in Visual C# (315720)



The information in this article applies to:

  • Microsoft Visual C# .NET (2002)
  • Microsoft Visual C# 2005, Express Edition

This article was previously published under Q315720
This article refers to the following Microsoft .NET Framework Class Library namespace:
  • System.Runtime.InteropServices

IN THIS TASK

SUMMARY

This step-by-step article shows you how to programmatically enable and disable printing functionality on a printer installed on a computer that supports the Win32 application programming interface (API) in Visual C#.
back to the top

Requirements

You need the following hardware and software to perform the procedures in this article:
  • A Microsoft Windows NT, Microsoft Windows 2000, Microsoft Windows Server 2003, or Microsoft Windows XP-based computer
  • Microsoft Visual Studio .NET or Microsoft Visual Studio 2005
You need the following skills to perform the procedures in this article:
  • C# programming experience
  • Basic knowledge of the Windows API
back to the top

Create an Application to Control the Printer

To create an application to control the printer, follow these steps:
  1. Start Visual Studio .NET or Visual Studio 2005, and then create a new Visual C# console application project named PrinterControl.
  2. Edit Class1.cs in Visual Studio .NET or Program.cs in Visual Studio 2005. After the using System; statement, add the following statement:
    using System.Runtime.InteropServices;
    					
  3. At the start of the body of class Class1 in Visual Studio .NET or class Program in Visual Studio 2005, add the following structure declaration:
    unsafe struct PRINTER_DEFAULTS
    { 
        public void * pDatatype;     // LPTSTR
        public void * pDevMode;      // LPDEVMODE
        public uint   DesiredAccess; // ACCESS_MASK
    };
    					
  4. After the structure declaration, add the following declarations for Windows API functions:
    [DllImport("kernel32", SetLastError=true)]
    static extern int GetLastError();
    
    [DllImport("WinSpool.drv", SetLastError=true)]
    static extern unsafe bool OpenPrinter
    (string pPrinterName, int * phPrinter, void * pDefault);
    
    [DllImport("WinSpool.drv", SetLastError=true)]
    static extern bool ClosePrinter(int hPrinter);
    
    [DllImport("WinSpool.drv",SetLastError=true)]
    static extern unsafe bool SetPrinter
    (int hPrinter, uint Level, void * pPrinter, uint Command);
    					
  5. After the function declaration, add the following constants for use in the Windows API functions:
    const uint PRINTER_ACCESS_ADMINISTER = 0x00000004;
    const uint PRINTER_STATUS_OFFLINE = 0x00000080;
    const uint PRINTER_CONTROL_PAUSE = 1;    
    const uint PRINTER_CONTROL_RESUME = 2;
    const uint PRINTER_CONTROL_PURGE = 3;
    const uint PRINTER_CONTROL_SET_STATUS = 4;
    					
  6. You can call the Windows API functions directly in your code. However, it is more convenient to place them in wrapper functions that handle the unsafe code and provide error handling through exceptions. Add the following wrapper functions in Class1:
    // Open a printer for administration operations.
    static unsafe int CSOpenPrinter(string printerName)
    {
        bool bResult;
        int hPrinter;
        PRINTER_DEFAULTS pd;
    
        pd.pDatatype     = null;
        pd.pDevMode      = null;
        pd.DesiredAccess = PRINTER_ACCESS_ADMINISTER;
        
        bResult = OpenPrinter(printerName, &hPrinter, &pd);
        if (!bResult)
        {
            throw new ApplicationException("Cannot open printer '" + 
                                            printerName + "' " + 
                                            Marshal.GetLastWin32Error());
        }
        return hPrinter;
    }
    
    // Close the printer.
    static void CSClosePrinter(int hPrinter)
    {
        if (!ClosePrinter(hPrinter))
        {
            throw new ApplicationException("Cannot close printer " +
                                            Marshal.GetLastWin32Error());
        }
    }
    
    // Pause printer.
    static unsafe void CSPausePrinter(int hPrinter)
    {
        if (!SetPrinter(hPrinter, 0, null, PRINTER_CONTROL_PAUSE))
        {
            throw new ApplicationException("Cannot pause printer " + 
                                            Marshal.GetLastWin32Error());
        }
    }
    
    // Resume printer.
    static unsafe void CSResumePrinter(int hPrinter)
    {
        if (!SetPrinter(hPrinter, 0, null, PRINTER_CONTROL_RESUME))
        {
            throw new ApplicationException("Cannot resume printer " + 
                                            Marshal.GetLastWin32Error());
        }
    }
    
    // Disable printer (offline).
    static unsafe void CSDisablePrinter(int hPrinter)
    {
        if (!SetPrinter(hPrinter, 0, 
                       (byte*)PRINTER_STATUS_OFFLINE, 
                        PRINTER_CONTROL_SET_STATUS))
        {
            throw new ApplicationException("Cannot disable printer " + 
                                            Marshal.GetLastWin32Error());
        }
    }
    
    // Enable printer.
    static unsafe void CSEnablePrinter(int hPrinter)
    {
        if (!SetPrinter(hPrinter, 0, (byte*)0, PRINTER_CONTROL_SET_STATUS))
        {
            throw new ApplicationException("Cannot enable printer " + 
                                            Marshal.GetLastWin32Error());
        }
    }
    					
  7. Add the following code in the Main function to call the wrapper functions to demonstrate the printer control operations (you will need to specify your printer name in the CSOpenPrinter function call):
    [STAThread]
    static void Main(string[] args)
    {
        int hPrinter;
        try
        {
      // Edit the following line to match your printer name.
            hPrinter = CSOpenPrinter("YourPrinterName");
    
            CSDisablePrinter(hPrinter);
            Console.WriteLine("The printer is disabled");
            Console.ReadLine();
    
            CSEnablePrinter(hPrinter);
            Console.WriteLine("The printer is enabled");
            Console.ReadLine();
    
            CSPausePrinter(hPrinter);
            Console.WriteLine("The printer is paused");
            
            Console.ReadLine();
            CSResumePrinter(hPrinter);
            
            Console.WriteLine("The printer is resumed");
            Console.ReadLine();
            
            CSClosePrinter(hPrinter);
        }
        catch (ApplicationException e)
        {
            Console.WriteLine("Exception: {0}", e.Message);
        }
    }
    					
back to the top

Build the Application

Before you build the application, you must enable unsafe code compilation for your project.

To do this, follow these steps:
  1. In Solution Explorer, right-click PrinterControl, and then click Properties on the shortcut menu.
  2. In the PrinterControl Property Pages dialog box, click Configuration Properties, and then set Allow unsafe code blocks to True.

    Note In Visual Studio 2005, click Build in the PrintControl Property Pages dialog box, and then click to select the Allow unsafe code check box.
  3. Click OK.
  4. Build the application.
back to the top

Verification

  1. Before you run the application, open the Printers window to display the name and status of each printer on your computer.

    To do this in Windows XP, click Start, and then click Printers and Faxes.

    In Windows Server 2003, Windows 2000, Windows NT, Microsoft Windows Millennium Edition, and Microsoft Windows 98, click Start, point to Settings, and then then click Printers.
  2. Run your application in Visual Studio .NET or in Visual Studio 2005.
  3. The application displays the following message:

    The printer is disabled
    Verify the printer is disabled by looking in the Printers folder. Press Enter in the application window, to continue the application.

    Press ENTER.
  4. The application displays the following message:

    The printer is enabled
    Verify that the printer is enabled by looking in the Printers folder. Press Enter in the application window, to continue the application.

    Press ENTER.
  5. The application displays the following message:

    The printer is paused
    Verify that the printer is paused by looking in the Printers folder. Press Enter in the application window, to continue the application.

    Press ENTER.
  6. The application displays the following message:

    The printer is resumed
    Verify that the printer is resumed by looking in the Printers folder. Press Enter in the application window, to continue the application.

    Press ENTER. The application terminates.
back to the top

Troubleshooting

The SetPrinter function requires appropriate permissions on Windows XP, Windows 2000, Windows Server 2003, and Windows NT-based systems. If you do not have administrative rights on the specified printer, the SetPrinter function call fails.

back to the top

REFERENCES

For additional information, click the article number below to view the article in the Microsoft Knowledge Base:

160129 HOWTO: Get the Status of a Printer and a Print Job

back to the top

Modification Type:MajorLast Reviewed:1/19/2006
Keywords:kbHOWTOmaster KB315720 kbAudDeveloper