C# 安全属性什么时候改变的?为什么?

C# 安全属性什么时候改变的?为什么?,c#,.net,process,pinvoke,C#,.net,Process,Pinvoke,我有一些代码使用p/Invoke启动流程并捕获标准输出。(为什么我们使用P/Invoke而不是System.Diagnostics.Process来实现这一点的故事既长又复杂;可以说这是一项要求。)它在生产中已经在重载下工作了近一年,使用它的测试总是通过的 今天早上虽然我做了测试,但都失败了。我不能确定我上一次在今天早上(2014年5月15日)之前进行测试的时间,但我相信是2014年4月24日。测试当时通过了,但今天早上没有通过。我收到了“PinvokeStackDistancert”错误消息,

我有一些代码使用p/Invoke启动流程并捕获标准输出。(为什么我们使用P/Invoke而不是
System.Diagnostics.Process
来实现这一点的故事既长又复杂;可以说这是一项要求。)它在生产中已经在重载下工作了近一年,使用它的测试总是通过的

今天早上虽然我做了测试,但都失败了。我不能确定我上一次在今天早上(2014年5月15日)之前进行测试的时间,但我相信是2014年4月24日。测试当时通过了,但今天早上没有通过。我收到了“PinvokeStackDistancert”错误消息,因此我做了一些研究,最终发现
extern
方法(
CreatePipe
在本例中)使用的一个结构的签名不正确。我改了,考试又开始通过了

我很高兴找到了修复方案,但我担心部署问题为什么结构的签名会改变?我没有升级我的操作系统或任何东西-我在4/24上运行Windows 7 x64,现在仍在运行它。(部署环境是Windows Server 2012。)从那以后,我安装(并卸载)了一些应用程序,但它们是轻量级的第三方工具,而不是Microsoft或系统组件。我认为是Windows Update修补程序造成的,但我不知道是哪一个

要清楚,在我自己的代码中,我所做的更改是:

    [StructLayout(LayoutKind.Sequential)]
    public struct SECURITY_ATTRIBUTES
    {
        public UInt32 nLength;
        public IntPtr lpSecurityDescriptor;
        public bool bInheritHandle;
    }
为此:

    [StructLayout(LayoutKind.Sequential)]
    internal class SECURITY_ATTRIBUTES
    {
        public int nLength = 12;
        public IntPtr lpSecurityDescriptor = IntPtr.Zero;
        public bool bInheritHandle;
    }

我需要确保,当我部署到生产环境时,我为使代码在我的机器上运行所做的更改不会破坏应用程序。是否有人知道如何确定变更的必要性,以及如何确定生产环境是否需要变更

编辑:

以下是为标准输出打开管道的代码:

    private PipeInfo CreatePipe()
    {
        PipeInfo pipeInfo = new PipeInfo();

        SafeFileHandle safeFileHandle = null;
        try
        {
            Native.SECURITY_ATTRIBUTES pipeAttributes = new Native.SECURITY_ATTRIBUTES();
            pipeAttributes.bInheritHandle = true;
            if (!Native.CreatePipe(out safeFileHandle, out pipeInfo.ChildHandle, pipeAttributes, 0) || safeFileHandle.IsInvalid || pipeInfo.ChildHandle.IsInvalid)
            {
                throw new Win32Exception();
            }

            if (!Native.DuplicateHandle(new HandleRef(this, Native.GetCurrentProcess()), safeFileHandle, new HandleRef(this, Native.GetCurrentProcess()), out pipeInfo.ParentHandle, 0, false, 2))
            {
                throw new Win32Exception();
            }
        }
        finally
        {
            if (safeFileHandle != null && !safeFileHandle.IsInvalid)
            {
                safeFileHandle.Close();
            }
        }

        return pipeInfo;
    }
我不能完全相信这个代码,我基本上是从

只是为了明确时间线:

  • 2013年5月-使用第一个版本的
    SECURITY\u属性编写
    CreatePipe
    代码
  • 2013年6月-部署;此后,代码一直在成功运行
  • 2014年4月-在未进行任何更改的情况下,代码开始抛出堆栈不平衡错误
  • 2014年5月-我更改为第二版本的
    安全属性
    ,错误消失

我们在x64上遇到了这个问题,这篇文章是我们搜索的最热门结果。我们使用magic 12 for NLENGHT,就像我们从C#source for process获得的解决方案一样:

结果表明CreatePipe需要一个指针,来自:

lpPipeAttributes

指向安全属性结构的指针,该结构确定返回的句柄是否可由子进程继承。如果lpPipeAttributes为NULL,则无法继承句柄

本章详细介绍了解决方案。它适用于x86和x64。下面的代码基于堆栈溢出帖子和进程源代码(顶部使用DWORD=System.UInt32)


安全属性从未改变。你真的不应该使用魔法常数12。使用
Marshal.SizeOf
。我猜你在代码中更改了其他内容。查阅您的修订控制历史记录,找出x64的0.12是不正确的值。此外,您描述的更改不会改变您是否获得堆栈不平衡。所以你确实需要弄清楚事实。@DavidHeffernan,我知道解决方案本身的代码没有任何变化,这就是为什么我怀疑热修复程序改变了解决方案的底层依赖关系。此外,事实是,第一个代码块会产生堆栈不平衡,但在按照所述方式仅更改此结构/类之后,错误就会消失。所以事实是直截了当的,他们只是不加起来;这就是我的问题。(感谢您提醒我不要使用魔法常数;我将研究如何使用
SizeOf
)因此,我从未发现发生了什么。最后,我告诉我们的部署团队,我们需要在服务器上安装,然后我们成功地将其部署到QA和生产环境中。我的理论是,一些热修复程序使得
nLength
不再被设置为默认值,因此我必须在我的代码中执行,这可能会更好。
    [StructLayout(LayoutKind.Sequential)]
    internal class SECURITY_ATTRIBUTES {
    #if !SILVERLIGHT
        // We don't support ACL's on Silverlight nor on CoreSystem builds in our API's.  
        // But, we need P/Invokes to occasionally take these as parameters.  We can pass null.
        public int nLength = 12;
        public SafeLocalMemHandle lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, false);
        public bool bInheritHandle = false;
    #endif // !SILVERLIGHT
    }
internal static class NativeMethods
{

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe,
        IntPtr lpPipeAttributes, int nSize);
        
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, SafeHandle hSourceHandle,
        IntPtr hTargetProcess, out SafeFileHandle targetHandle, int dwDesiredAccess,
        bool bInheritHandle, int dwOptions);
        
    [StructLayout(LayoutKind.Sequential)]
    public struct PIPE_SECURITY_ATTRIBUTES
    {
        public DWORD nLength;
        public IntPtr lpSecurityDescriptor;
        [MarshalAs(UnmanagedType.Bool)]
        public bool bInheritHandle;
    }

    public static void CreatePipe(out SafeFileHandle parentHandle, out SafeFileHandle childHandle, bool parentInputs)
    {
        PIPE_SECURITY_ATTRIBUTES lpPipeAttributes = new PIPE_SECURITY_ATTRIBUTES();
        lpPipeAttributes.nLength = (DWORD)Marshal.SizeOf(lpPipeAttributes);
        lpPipeAttributes.bInheritHandle = true;
        lpPipeAttributes.lpSecurityDescriptor = IntPtr.Zero;
        IntPtr attr = Marshal.AllocHGlobal(Marshal.SizeOf(lpPipeAttributes));
        Marshal.StructureToPtr(lpPipeAttributes, attr, true);
        SafeFileHandle hWritePipe = null;
        try
        {
            if (parentInputs)
                CreatePipeWithSecurityAttributes(out childHandle, out hWritePipe, attr, 0);
            else
                CreatePipeWithSecurityAttributes(out hWritePipe, out childHandle, attr, 0);
            if (!DuplicateHandle(GetCurrentProcess(), hWritePipe, GetCurrentProcess(), out parentHandle, 0, false, 2))
                throw new Exception();
        }
        finally
        {
            if ((hWritePipe != null) && !hWritePipe.IsInvalid)
            {
                hWritePipe.Close();
            }
        }
    }
    
    public static void CreatePipeWithSecurityAttributes(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe,
        IntPtr lpPipeAttributes, int nSize)
    {
        hReadPipe = null;
        if ((!CreatePipe(out hReadPipe, out hWritePipe, lpPipeAttributes, nSize) || hReadPipe.IsInvalid) || hWritePipe.IsInvalid)
            throw new Exception();
    }
}