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