I am attempting to use the GDI API to send data to a printer, with a
specific set of printer settings.  I am doing so using the openPrinter
API.  I have tried setting the DEVMODE within the PRINTER_DEFAULTS, as well
as setting it within the JOB_INFO_2 and doing a SetJob.  The data is
printed, but the printer settings (tray selection, orientation, etc.) are
being ignored.

Thanks for any help,
Eric

My Code (keep in mind this represents a lot of tweaking and messing around
trying to figure out what's wrong):

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing.Printing;
using System.IO;
using System.Runtime.InteropServices;

namespace FWITestApp
{
 /// <summary>
 /// Summary description for RAWTester.
 /// </summary>
 public class RAWTester
 {
  #region interop

  [StructLayout(LayoutKind.Sequential)]
  private struct SYSTEMTIME
  {
   public int wYear;
   public int wMonth;
   public int wDayOfWeek;
   public int wDay;
   public int wHour;
   public int wMinute;
   public int wSecond;
   public int wMilliseconds;
  }

  [StructLayout(LayoutKind.Sequential)]
  private struct JOB_INFO_1
  {
   public int JobId;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pPrinterName;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pMachineName;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pUserName;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pDocument;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pDatatype;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pStatus;
   public int Status;
   public int Priority;
   public int Position;
   public int TotalPages;
   public int PagesPrinted;
   public SYSTEMTIME Submitted;
  }

  [StructLayout(LayoutKind.Sequential)]
  private  struct JOB_INFO_2
  {
   public int  JobId;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pPrinterName;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pMachineName;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pUserName;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pDocument;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pNotifyName;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pDatatype;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pPrintProcessor;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pParameters;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pDriverName;
   public IntPtr pDevMode;
   [MarshalAs(UnmanagedType.LPWStr)]public string
pStatus;
   public IntPtr pSecurityDescriptor;
   public int  Status;
   public int  Priority;
   public int  Position;
   public int  StartTime;
   public int  UntilTime;
   public int  TotalPages;
   public int  Size;
   public SYSTEMTIME Submitted;
   public int  time;
   public int  PagesPrinted;
  }

  [StructLayout(LayoutKind.Sequential)]
  private class PRINTER_DEFAULTS
  {
   //[MarshalAs(UnmanagedType.LPStr)] public string
pDatatype;
   //[MarshalAs(UnmanagedType.LPStruct)] public
DEVMODE pDevMode;
   //public int  DesiredAccess;
   [MarshalAs(UnmanagedType.LPStr)] public String
pDatatype;
   public IntPtr pDevMode;
   public int DesiredAccess;
  }

  // Structure and API declarions:
  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
  private class DOCINFOA
  {
   [MarshalAs(UnmanagedType.LPStr)] public string
pDocName;
   [MarshalAs(UnmanagedType.LPStr)] public string
pOutputFile;
   [MarshalAs(UnmanagedType.LPStr)] public string
pDataType;
  }
  [DllImport("winspool.Drv", EntryPoint="OpenPrinterA",
SetLastError=true, CharSet=CharSet.Ansi, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern bool OpenPrinter([MarshalAs
(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, [In, MarshalAs
(UnmanagedType.LPStruct)] PRINTER_DEFAULTS pDefault);

  [DllImport("winspool.Drv", EntryPoint="ClosePrinter",
SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern bool ClosePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint="StartDocPrinterA",
SetLastError=true, CharSet=CharSet.Ansi, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern int StartDocPrinter( IntPtr hPrinter,
Int32 level,  [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

  [DllImport("winspool.Drv", EntryPoint="EndDocPrinter",
SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern bool EndDocPrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint="StartPagePrinter",
SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern bool StartPagePrinter(IntPtr
hPrinter);

  [DllImport("winspool.Drv", EntryPoint="EndPagePrinter",
SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern bool EndPagePrinter(IntPtr hPrinter);

  [DllImport("winspool.Drv", EntryPoint="WritePrinter",
SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern bool WritePrinter(IntPtr hPrinter,
IntPtr pBytes, Int32 dwCount, out Int32 dwWritten );

  [DllImport("winspool.drv",
EntryPoint="DeviceCapabilitiesA", SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern int DeviceCapabilities(string
lpDeviceName, string lpPort, int iIndex, IntPtr lpOutput, IntPtr lpDevMode);

  [DllImport("winspool.drv",
EntryPoint="DeviceCapabilitiesA", SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern int DeviceCapabilitiesIntArray(string
lpDeviceName, string lpPort, int iIndex, [MarshalAs(UnmanagedType.LPArray)]
short[] lpOutput, IntPtr lpDevMode);

  [DllImport("winspool.drv",
EntryPoint="DeviceCapabilitiesA", SetLastError=true, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
  private static extern int DeviceCapabilitiesStringArray
(string lpDeviceName, string lpPort, int iIndex, [In, Out, MarshalAs
(UnmanagedType.VBByRefStr)] ref string lpOutput, IntPtr lpDevMode);

  private const int DC_PERSONALITY = 25;
  private const int DC_BINS = 6;
  private const int DC_BINNAMES = 12;

  [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
  private struct DEVMODE
  {
   [MarshalAs(UnmanagedType.ByValArray,
SizeConst=CCHDEVICENAME)]
   public char [] dmDeviceName;
   public short dmSpecVersion;
   public short dmDriverVersion;
   public short dmSize;
   public short dmDriverExtra;
   public int dmFields;
   public DEVMODE_UNION u;
   public short dmColor;
   public short dmDuplex;
   public short dmYResolution;
   public short dmTTOption;
   public short dmCollate;
   [MarshalAs(UnmanagedType.ByValArray,
SizeConst=CCHFORMNAME)]
   public char [] dmFormName;
   public short dmLogPixels;
   public short dmBitsPerPel;
   public int dmPelsWidth;
   public int dmPelsHeight;
   public int dmDisplayFlagsOrdmNup;
   public int dmDisplayFrequency;
   //public int dmICMMethod;
   //public int dmICMIntent;
   //public int dmMediaType;
   //public int dmDitherType;
   //public int dmReserved1;
   //public int dmReserved2;
   //public int dmPanningWidth;
   //public int dmPanningHeight;
  }

  [StructLayout(LayoutKind.Explicit)]
  private struct DEVMODE_UNION
  {
   [FieldOffset(0)]
   public short dmOrientation;
   [FieldOffset(2)]
   public short dmPaperSize;
   [FieldOffset(4)]
   public short dmPaperLength;
   [FieldOffset(6)]
   public short dmPaperWidth;
   [FieldOffset(8)]
   public short dmScale;
   [FieldOffset(10)]
   public short dmCopies;
   [FieldOffset(12)]
   public short dmDefaultSource;
   [FieldOffset(14)]
   public short dmPrintQuality;
   //[FieldOffset(0)]
   //public int dmPosition_x;
   //[FieldOffset(4)]
   //public int dmPosition_y;
   //[FieldOffset(8)]
   //public int dmDisplayOrientation;
   //[FieldOffset(12)]
   //public int dmDisplayFixedOutput;
  }

  [DllImport("winspool.drv",CharSet=CharSet.Unicode,
    CallingConvention=CallingConvention.StdCall,
SetLastError=true )]
  private static extern int GetJob(IntPtr hPrinter, int
JobId, int Level, IntPtr pJob, int cbBuf, ref int pcbNeeded);

  [DllImport("winspool.drv",CharSet=CharSet.Unicode,
    CallingConvention=CallingConvention.StdCall,
SetLastError=true )]
  private static extern int SetJob(IntPtr hPrinter, int
JobId, int Level, IntPtr pJob, int Command);

  [DllImport("winspool.drv")]
  private static extern int DocumentProperties(int hwnd,
IntPtr hPrinter, string pDeviceName, IntPtr pDevModeOutput, [In, MarshalAs
(UnmanagedType.Struct)] ref DEVMODE pDevModeInput, int fMode);

  [DllImport("winspool.drv")]
  private static extern int EnumJobs(int hPrinter, int
FirstJob,
   int NoJobs, int Level, byte pJob, int cdBuf, int
pcbNeeded, int pcReturned);

  [DllImport("kernel32.dll")]
  private static extern int CloseHandle(int hObject);

  #endregion

  #region Member Fields

  // Constants Definition
  private const int CCHDEVICENAME = 32;
  private const int CCHFORMNAME = 32;
  private const int PRINTER_ACCESS_ADMINISTER = 0x00000004;
  private const int PRINTER_ACCESS_USE = 0x00000008;
  private const int DM_DEFAULTSOURCE = 0x0200;

  private const int STANDARD_RIGHTS_REQUIRED = 0x0F0000;
  private const int PRINTER_ALL_ACCESS =
(STANDARD_RIGHTS_REQUIRED
   | PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
  private const int DM_MODIFY = 8;
  private const int DM_PROMPT = 4;
  private const int DM_COPY = 2;
  private const int DM_IN_BUFFER = DM_MODIFY;
  private const int DM_IN_PROMPT = DM_PROMPT;
  private const int DM_OUT_BUFFER = DM_COPY;

  #endregion

  /// <summary>
  /// Defined private because all methods are static.
  /// </summary>
  private RAWTester()
  {
   //
   // TODO: Add constructor logic here
   //
  }

  /// <summary>
  /// Sends a hard coded string to the printer as raw data.
  /// </summary>
  /// <param name="printerName">Name of the printer queue to
look in.</param>
  /// <returns>whether or not print was successful</returns>
  public static bool SendStringToPrinter(string printerName)
  {
   string printText = "This is a really stupid test.";
   int textSize = printText.Length;

   IntPtr pUnmanagedBytes = new IntPtr(0);
   pUnmanagedBytes = Marshal.StringToCoTaskMemAnsi
(printText);

   bool bSuccess = SendBytesToPrinter(printerName,
pUnmanagedBytes, textSize, "My Stupid Test Job");
   // Free the unmanaged memory that you allocated
earlier.
   Marshal.FreeCoTaskMem(pUnmanagedBytes);
   return bSuccess;
  }

  /// <summary>
  /// When the function is given a printer name and an
unmanaged array
  /// of bytes, the function sends those bytes to the print
queue.
  /// </summary>
  /// <param name="printerName">Name of the printer queue to
look in.</param>
  /// <param name="pBytes">Data to send to the printer</param>
  /// <param name="dwCount">Number of bytes being
sent.</param>
  /// <param name="jobName">Name of the job in the print
queue.</param>
  /// <returns>true on success, false on failure.</returns>
  public static bool SendBytesToPrinter( string printerName,
IntPtr pBytes, Int32 dwCount, string jobName)
  {
   JOB_INFO_2 jobInfo;
   Int32    dwError = 0, dwWritten = 0;
   IntPtr    hPrinter = new IntPtr(0);
   DOCINFOA    di = new DOCINFOA();
   bool    bSuccess = false; // Assume failure unless
you specifically succeed.
   DEVMODE devMode;
   int lDoc = 0;

   di.pOutputFile = null;
   di.pDocName = jobName;
   di.pDataType = "RAW";

   devMode = new DEVMODE();
   devMode.u.dmDefaultSource = 1;
   devMode.u.dmOrientation = 2;
   devMode.dmFields = devMode.dmFields |
DM_DEFAULTSOURCE | 1;
   //devMode.dmDuplex = 1;

   //IntPtr devModePrinterSettings =
Marshal.AllocHGlobal(Marshal.SizeOf(devMode));
   //Marshal.StructureToPtr(devMode,
devModePrinterSettings, false);

   PRINTER_DEFAULTS defaults = new PRINTER_DEFAULTS();
   defaults.pDatatype = "RAW";
   defaults.pDevMode = Marshal.AllocHGlobal
(Marshal.SizeOf(devMode));
   Marshal.StructureToPtr(devMode, defaults.pDevMode,
false);
   //defaults.pDevMode = devModePrinterSettings;
   defaults.DesiredAccess =
PRINTER_ACCESS_USE; //PRINTER_ALL_ACCESS

   IntPtr defaultPtr = Marshal.AllocHGlobal
(Marshal.SizeOf(defaults));
   Marshal.StructureToPtr(defaults, defaultPtr, false);


   if( OpenPrinter( printerName, out hPrinter,
defaults ) )
   {
    lDoc = StartDocPrinter(hPrinter, 1, di);
    if( lDoc != 0 )
    {
     if( StartPagePrinter(hPrinter) )
     {
      jobInfo = GetJobInfo
(hPrinter, lDoc);
      devMode = (DEVMODE)
Marshal.PtrToStructure(jobInfo.pDevMode, typeof(DEVMODE));
      devMode.u.dmDefaultSource =
1;
      devMode.u.dmOrientation = 2;
      devMode.dmFields =
devMode.dmFields | DM_DEFAULTSOURCE | 1;
      Marshal.StructureToPtr
(devMode, jobInfo.pDevMode, false);
      //devMode = (DEVMODE)
Marshal.PtrToStructure(jobInfo.pDevMode, typeof(DEVMODE));

      //jobInfo.pDevMode =
devModePrinterSettings;
      IntPtr jobInfoPtr =
Marshal.AllocHGlobal(Marshal.SizeOf(jobInfo));
      Marshal.StructureToPtr
(jobInfo, jobInfoPtr, false);

      SetJob(hPrinter,
jobInfo.JobId, 2, jobInfoPtr, 0);

      // Write your bytes.
      bSuccess = WritePrinter
(hPrinter, pBytes, dwCount, out dwWritten);
      EndPagePrinter(hPrinter);

      //jobInfo = GetJobInfo
(hPrinter, lDoc);

      //devMode = (DEVMODE)
Marshal.PtrToStructure(jobInfo.pDevMode, typeof(DEVMODE));
     }
     EndDocPrinter(hPrinter);
    }

    //jobInfo = GetJobInfo(hPrinter, lDoc);

    //devMode = (DEVMODE)Marshal.PtrToStructure
(jobInfo.pDevMode, typeof(DEVMODE));

    ClosePrinter(hPrinter);
   }
   // If you did not succeed, GetLastError may give
more information
   // about why not.
   if( bSuccess == false )
   {
    dwError = Marshal.GetLastWin32Error();
   }

   return bSuccess;
  }

  /// <summary>
  /// Gets a managed Job Info.
  /// </summary>
  /// <param name="hPrinter">Handle to the printer</param>
  /// <param name="lDoc">Handle to the document being
printed.</param>
  /// <returns>Info about the print job.</returns>
  private static JOB_INFO_2 GetJobInfo(IntPtr hPrinter, int
lDoc)
  {
   int pcbNeeded = 0;
   int lReturn = 0;
   JOB_INFO_2 jobInfo = new JOB_INFO_2();
   IntPtr jobInfoPtr = new IntPtr();

   jobInfo.pPrinterName = "".PadLeft(100, ' ');
   jobInfo.pMachineName = "".PadLeft(100, ' ');
   jobInfo.pUserName = "".PadLeft(100, ' ');
   jobInfo.pDocument = "".PadLeft(100, ' ');
   jobInfo.pNotifyName = "".PadLeft(100, ' ');
   jobInfo.pDatatype = "".PadLeft(100, ' ');
   jobInfo.pPrintProcessor = "".PadLeft(100, ' ');
   jobInfo.pParameters = "".PadLeft(100, ' ');
   jobInfo.pDriverName = "".PadLeft(100, ' ');
   jobInfo.pSecurityDescriptor = new IntPtr(0);

   DEVMODE devDefaults = new DEVMODE();
   IntPtr hDevMode = Marshal.AllocHGlobal
(Marshal.SizeOf(devDefaults));
   Marshal.StructureToPtr(devDefaults, hDevMode,
false);
   jobInfo.pDevMode = hDevMode;

   jobInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf
(jobInfo));
   Marshal.StructureToPtr(jobInfo, jobInfoPtr, false);

   lReturn = GetJob(hPrinter, lDoc, 2, jobInfoPtr, 0,
ref pcbNeeded);
   if (pcbNeeded > 0)
   {
    Marshal.FreeHGlobal(jobInfoPtr);
    jobInfoPtr = Marshal.AllocHGlobal
(pcbNeeded);
    lReturn = GetJob(hPrinter, lDoc, 2,
jobInfoPtr, pcbNeeded, ref pcbNeeded);
    jobInfo = (JOB_INFO_2)Marshal.PtrToStructure
(jobInfoPtr, typeof(JOB_INFO_2));
   }

   return jobInfo;
  }
 }
}

===================================
This list is hosted by DevelopMentorŪ  http://www.develop.com
Some .NET courses you may be interested in:

NEW! Guerrilla ASP.NET, 26 Jan 2004, in Los Angeles
http://www.develop.com/courses/gaspdotnetls

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to