c# - .NET Framework 4.5 或更高版本中的 AccessViolationException

标签 c# .net interop pinvoke access-violation

我正在尝试运行在互联网上找到的 .NET C# 控制台应用程序(articlecode)。

它使用一些 pInvoke 调用,并在某些时候触发 Marshal.PtrToStringUni(IntPtr ptr, int len)

非常奇怪,而且我无法修复的是:

  • 如果我将项目编译为 .NET Framework 4.0,它就可以工作。
  • 在 .NET Framework 4.5 或更高版本下,它会抛出 AccessViolationException(臭名昭著的“试图读取或写入 protected 内存。这通常表明其他内存已损坏。”)

堆栈跟踪告诉我:

at System.Buffer.Memmove(Byte* dest, Byte* src, UInt64 len) at System.String.CtorCharPtrStartLength(Char* ptr, Int32 startIndex, Int32 length) at System.Runtime.InteropServices.Marshal.PtrToStringUni(IntPtr ptr, Int32 len)

我在网上搜索了几个小时,看到了类似的问题,但没有任何帮助。我绝对需要在我的项目中实现这个功能,并且觉得在.Net Framework 4.0 中编译这部分而其余部分在更高版本中可能会在未来带来一些麻烦。无论如何,必须有一种方法让它发挥作用。

有没有办法让这段代码工作?

编辑:我刚刚更新了链接“代码”。作者刚刚提交了一个新版本。

编辑 2:我知道这里没有直接的代码不会让人想要提供帮助。我认为链接到列出重要部分的文章会更有效率。

所以这里有一些上下文和一些代码:

该代码旨在列出进程锁定的所有文件。它首先获取 SYSTEM_HANDLE_INFORMATION 列表。这是结构:

 [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct SYSTEM_HANDLE_INFORMATION
    { 
        public int ProcessID;
        public byte ObjectTypeNumber;
        public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
        public ushort Handle;
        public int Object_Pointer;
        public UInt32 GrantedAccess;
    }

它遍历集合,并在 GetFileDetails 方法中发送每个项目。

这里是方法,我只复制到.NET 4.5失败,.NET 4.0成功的try/catch语句:

private static FileDetails GetFileDetails(Win32API.SYSTEM_HANDLE_INFORMATION sYSTEM_HANDLE_INFORMATION)
    {
        FileDetails fd = new FileDetails();
        fd.Name = "";
        IntPtr ipHandle = IntPtr.Zero;
        Win32API.OBJECT_BASIC_INFORMATION objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
        IntPtr ipBasic = IntPtr.Zero;
        Win32API.OBJECT_TYPE_INFORMATION objObjectType = new Win32API.OBJECT_TYPE_INFORMATION();
        IntPtr ipObjectType = IntPtr.Zero;
        Win32API.OBJECT_NAME_INFORMATION objObjectName = new Win32API.OBJECT_NAME_INFORMATION();
        IntPtr ipObjectName = IntPtr.Zero;
        string strObjectTypeName = "";
        string strObjectName = "";
        int nLength = 0;
        int nReturn = 0;
        IntPtr ipTemp = IntPtr.Zero;


        if (!Win32API.DuplicateHandle(m_ipProcessHwnd, sYSTEM_HANDLE_INFORMATION.Handle,Win32API.GetCurrentProcess(), out ipHandle, 0, false, Win32API.DUPLICATE_SAME_ACCESS)) return fd;

        ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
        Win32API.NtQueryObject(ipHandle, (int) Win32API.ObjectInformationClass.ObjectBasicInformation, ipBasic, Marshal.SizeOf(objBasic), ref nLength);
        objBasic = (Win32API.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
        Marshal.FreeHGlobal(ipBasic);


        ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
        nLength = objBasic.TypeInformationLength;
        while ((uint)(nReturn = Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength)) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
        {
            Marshal.FreeHGlobal(ipObjectType);
            ipObjectType = Marshal.AllocHGlobal(nLength);
        }

        objObjectType = (Win32API.OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType());
        if (Is64Bits())
        {
            ipTemp = new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32);             
        }
        else
        {
            ipTemp = objObjectType.Name.Buffer;          
        }

        try
        {
            strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
        }
        catch (AccessViolationException)
        {
            return null;
        }

有兴趣的 friend 可以在上面的链接中找到完整的代码 谢谢你的帮助

最佳答案

由于一些错误的指针,访问冲突异常来自操作系统。由于 .NET 旨在避免裸指针,因此只有几个可能的来源:

  • 通过 P/Invoke 或 COM 互操作调用非托管代码。
  • 二进制错配。如果您调用的非托管代码是 x32 而您从 x64 调用它(反之亦然),它将不起作用。解决方法是对二进制进行硬编码或使用适当二进制的辅助进程。据说链接代码专为 x64 运行。如果您不定义二元性,框架可以选择今天感觉的“任何”二元性。您是否相应地选择了项目的目标?
  • 第三者干扰。那是几年前的事了,但我们曾遇到过某个病毒扫描程序会杀死所有其他 Windows 窗体应用程序的情况。尝试排除程序/关闭后台保护一段时间。

关于c# - .NET Framework 4.5 或更高版本中的 AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48733914/

相关文章:

c# - BITS 最好的免费 C# 包装器是什么?

javascript - 我通过端口从 Elm 应用程序传递一个元组。 JavaScript 将接收什么类型的对象?

c# - 如何使用 C# 选择带有 XML 命名空间的 XML 节点

c# - 排序后变量为空

.net - 使用 Npgsql 提供程序 (.NET) 执行 sql 文件

c# - 用户在我的程序上积极花费了多少时间?

c# - 向我的 Outlook 2010 插件添加功能区控件时遇到问题

c# - 如何在 Mongodb 的聚合框架中编写日期范围查询?

c# - 如何将列表绑定(bind)到 Data Grids 数据源的子类中的组合框?

C# 和 Excel 互操作