views:

252

answers:

2

Hi all,

I trying to create a pipe using C#. The code is quite simple but I get a error saying "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Here the COMPLETE code of my form :

public partial class Form1 : Form
{
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, SECURITY_ATTRIBUTES lpPipeAttributes, int nSize);

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public DWORD nLength;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void btCreate_Click(object sender, EventArgs e)
    {
        SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
        sa.nLength = (DWORD)System.Runtime.InteropServices.Marshal.SizeOf(sa);
        sa.lpSecurityDescriptor = IntPtr.Zero;
        sa.bInheritHandle = true;

        SafeFileHandle hWrite = null;
        SafeFileHandle hRead = null;

        if (CreatePipe(out hRead, out hWrite, sa, 4096))
        {
            MessageBox.Show("Pipe created !");
        }
        else
            MessageBox.Show("Error : Pipe not created !");
    }   
}

At the top I declare : using DWORD = System.UInt32;

Thank you very much if someone can help.

+2  A: 

The reason for the protected memory violation is because the Windows API for CreatePipe was expecting a pointer value to an area of memory which the function would use as a spring board to the security attributes structure. Simply passing in the SECURITY_ATTRIBUTES structure would then overwrite secure memory (pages not yet allocated to your application), and hence the protected memory error.

Passing in an IntPtr to represent this pointer, solves your problem.

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CreatePipe(ref IntPtr hReadPipe, ref IntPtr hWritePipe, IntPtr  lpPipeAttributes, int nSize);

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public DWORD nLength;
        public IntPtr lpSecurityDescriptor;
        [MarshalAs(UnmanagedType.Bool)]
        public bool bInheritHandle;
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void btnCreate_Click(object sender, EventArgs e)
    {

        SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
        sa.nLength = (DWORD)System.Runtime.InteropServices.Marshal.SizeOf(sa);
        sa.lpSecurityDescriptor = IntPtr.Zero;
        sa.bInheritHandle = true;

        IntPtr attr = Marshal.AllocHGlobal(Marshal.SizeOf(sa));
        Marshal.StructureToPtr(sa, attr, true);

        IntPtr hWrite = new IntPtr();
        IntPtr hRead = new IntPtr();

        if (CreatePipe(ref hRead, ref hWrite, attr, 4096))
        {
            MessageBox.Show("Pipe created !");
        }
        else
        {
            int error = Marshal.GetLastWin32Error();
            MessageBox.Show("Error : Pipe not created ! LastError= " + error);
        }
    }
Mike J
Thank you very much, work like a charm now.
M. Dimitri
Its my pleasure, I'm glad to help :-)
Mike J
+2  A: 

Just change the declaration, so that SECURITY_ATTRIBUTES is a pointer:

public static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, int nSize);
Lucero
Your solution is working fine too, thank you :p
M. Dimitri
I new to this board, seem like I can't tag both answers as solution ...
M. Dimitri
@Dimitri, that's the way it is, you can only accept one answer. However, when you get some more reputation, you'll be able to upvote multiple answers.
Lucero