locked
OutOfMemory Exception on 64 bit machines (Interop Problem) RRS feed

  • Question

  • Hello

    Our application needs to display the printer settings dialog. This works fine in 32bit windows systems, but results in a System.OutOfMemoryException at System.Runtime.InteropServices.Marshal.AllocHGlobal(IntPtr cb) when it is running under 64bit (Windows 2008 Server).

    The problem can easily be reproduced in a winform app. You need to set the platform target to x86 to experience the problem.Unfortuantely, our application needs to be built fox x86 for other reasons.

    Any ideas why this happens?

    Kind Regards

    Mat

    Source Code:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Drawing.Printing;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Windows.Forms;

    namespace WindowsFormsApplication8
    {
        public partial class Form1 : Form
        {
            [DllImport("kernel32.dll")]
            static extern IntPtr GlobalLock(IntPtr hMem);

            [DllImport("kernel32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool GlobalUnlock(IntPtr hMem);

            [DllImport("kernel32.dll")]
            static extern IntPtr GlobalFree(IntPtr hMem);

            [DllImport("winspool.Drv", EntryPoint = "DocumentPropertiesW", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
            static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPWStr)] string pDeviceName, IntPtr pDevModeOutput, IntPtr pDevModeInput, int fMode);
           
            public Form1()
            {
                InitializeComponent();
            }

            private void button1_Click(object sender, EventArgs e)
            {
                PrinterSettings psSettings = new PrinterSettings();
                if (PrinterSettings.InstalledPrinters.Count == 0)
                {
                    MessageBox.Show("No Printer installed");
                    return;
                }
               
                psSettings.PrinterName = PrinterSettings.InstalledPrinters[0];
                IntPtr ipDevMode = psSettings.GetHdevmode(psSettings.DefaultPageSettings);
                IntPtr pDevMode = GlobalLock(ipDevMode);
                int nSize = DocumentProperties(this.Handle, IntPtr.Zero, psSettings.PrinterName, pDevMode, pDevMode, 0);
                IntPtr ipDevModeData = Marshal.AllocHGlobal(nSize);
                DocumentProperties(this.Handle, IntPtr.Zero, psSettings.PrinterName, ipDevModeData, pDevMode, 14);
                GlobalUnlock(ipDevMode);
                psSettings.SetHdevmode(ipDevModeData);
                psSettings.DefaultPageSettings.SetHdevmode(ipDevModeData);
                GlobalFree(ipDevMode);
                Marshal.FreeHGlobal(ipDevModeData);
            }
        }
    }

    Thursday, September 9, 2010 7:42 AM

Answers

  • To ensure that the code runs on x86 AND x64, I needed to change the call to DocumentProperties as follows

    int nSize = DocumentProperties(this.Handle, IntPtr.Zero, psSettings.PrinterName, IntPtr.Zero, pDevMode, 0);

     

    • Marked as answer by Mat Hes Thursday, September 9, 2010 5:35 PM
    Thursday, September 9, 2010 2:04 PM