C# 在Windows 7上构建的二进制文件在Windows Server 2012上失败

C# 在Windows 7上构建的二进制文件在Windows Server 2012上失败,c#,winapi,windows-7-x64,windows-server-2012,C#,Winapi,Windows 7 X64,Windows Server 2012,在夜间构建机器上构建的应用程序在Windows Server 2012上不起作用,但在其他桌面上可以正常工作 这种例外 “试图读取或写入受保护的内存。这通常表示其他内存已损坏。”被抛出 当我在WindowsServer2012机器和构建机器上使用远程调试进行调试时,我看到在代码中调用kernel32的地方引发了此异常。以下是如何导入和调用HeapSize: [DllImport("kernel32")] static extern int HeapSize(int hHeap, int fla

在夜间构建机器上构建的应用程序在Windows Server 2012上不起作用,但在其他桌面上可以正常工作

这种例外 “试图读取或写入受保护的内存。这通常表示其他内存已损坏。”被抛出

当我在WindowsServer2012机器和构建机器上使用远程调试进行调试时,我看到在代码中调用kernel32的地方引发了此异常。以下是如何导入和调用
HeapSize

[DllImport("kernel32")] 
static extern int HeapSize(int hHeap, int flags, void* block); 
// Returns the size of a memory block. 

public static int SizeOf(void* block) 
{ 
    int result = HeapSize(ph, 0, block); 
    if (result == -1) throw new InvalidOperationException(); 
    return result; 
}
这被称为不安全类构造函数的一部分:

    public UnManagedBuffer(StringBuilder sb)
    {
        PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString());
        Size = UnManagedMemory.SizeOf(PtrStart);
        PtrWriteNextValue = PtrStart + Size - 1;
        PtrReturnNextValue = PtrStart;
    }
关于可能丢失的内容以及如何修复的任何线索

这是我在Windbg中看到的:

事件日志显示:

    Log Name:      Application
    Source:        .NET Runtime
    Level:         Error
    Keywords:      Classic
    Description:
Application: TestEngine.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
   at Core.Utils.UnManagedMemory.HeapSize(Int32, Int32, Void*)
   at Core.Utils.UnManagedMemory.SizeOf(Void*)
   at Core.Utils.UnManagedBuffer..ctor</Event>

Faulting application name: TestEngine.exe, version: 1.0.0.0, time stamp: 0x56b532bb
Faulting module name: ntdll.dll, version: 6.3.9600.18185, time stamp: 0x5683f0c5
Exception code: 0xc0000005
Fault offset: 0x0000000000057306
Faulting process id: 0x2eb8
Faulting application start time: 0x01d164e45b12d7dd
Faulting application path: C:\NGDLM\Lib\TestEngine.exe
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll
Report Id: bea6eb89-d0d7-11e5-80eb-0050568cd888
Faulting package full name: 
Faulting package-relative application ID: 
日志名称:应用程序
源:.NET运行时
级别:错误
关键词:经典
说明:
应用程序:TestEngine.exe
框架版本:v4.0.30319
描述:由于未处理的异常,进程已终止。
异常信息:System.AccessViolationException
在Core.Utils.UnManagedMemory.HeapSize(Int32,Int32,Void*)
在Core.Utils.UnManagedMemory.SizeOf(Void*)处
在Core.Utils.UnManagedBuffer..ctor处
故障应用程序名称:TestEngine.exe,版本:1.0.0.0,时间戳:0x56b532bb
故障模块名称:ntdll.dll,版本:6.3.9600.18185,时间戳:0x5683f0c5
异常代码:0xc0000005
故障偏移量:0x0000000000057306
出错进程id:0x2eb8
故障应用程序启动时间:0x01d164e45b12d7dd
出现故障的应用程序路径:C:\NGDLM\Lib\TestEngine.exe
故障模块路径:C:\Windows\SYSTEM32\ntdll.dll
报告Id:bea6eb89-d0d7-11e5-80eb-0050568cd888
故障包全名:
错误包相对应用程序ID:

您编写的代码本不应该工作

HeapSize
返回堆的大小,例如,通过调用。提供给
HeapSize
的指针必须是通过调用
HeapAlloc
返回的指针:

lpMem[in]

指向函数将获得其大小的内存块的指针。这是HeapAlloc或heapreloc函数返回的指针

您正在调用
HeapSize
,但提供的指针可能位于该堆中的任何位置;或者根本不在那个堆里:

    PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString());
    Size = UnManagedMemory.SizeOf(PtrStart);
    PtrWriteNextValue = PtrStart + Size - 1;
    PtrReturnNextValue = PtrStart;
Marshal.StringToHGlobalAnsi()
不仅返回堆中某处的指针,而不是堆本身的指针,您甚至不知道指针是从哪个堆分配的,因为进程可能分配了多个堆

所有这些都无关紧要,因为您似乎对这个函数的用途有一个根本性的误解——您似乎在使用它来检索堆内分配的大小。
Marshal.StringToHGlobalAnsi()
返回的内存不是通过调用
HeapAlloc()
来分配的(因为它不是堆!),而是通过调用来分配的。必须通过调用
Marshal.FreeHGlobal()
来释放由其分配的内存:

从的文档:

由于此方法分配字符串所需的非托管内存,因此始终通过调用FreeHGlobal释放内存

Marshal
方法与
HeapAlloc
HeapSize
或相关函数无关

如果您确实想找出由
Marshal.StringToHGlobal()
返回的指针的内存分配大小,您可以深入研究并发现它使用了win32函数。碰巧,
LocalAlloc
有一个姊妹函数,它确实可以用来查找分配的大小

但是,不能保证这样做在将来会起作用,因为.Net framework不能保证它将继续使用
LocalAlloc
。如果他们更改了内部
LocalSize
可能会停止工作

所有这些都表明:

我认为这些都不是你一开始想做的 再次查看您的代码:

    PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString());
    Size = UnManagedMemory.SizeOf(PtrStart);
    PtrWriteNextValue = PtrStart + Size - 1;
    PtrReturnNextValue = PtrStart;
您正在尝试查找返回给您的ansi字符串的长度

HeapSize
LocalSize
的所有这些业务都是完全无关的

如果您只想找到一个“ansi”字符串的长度,您只需要实现一个愚蠢的简单字符串长度,或者使用已经存在的任何实现

以下程序使用
Marshal.StringToHGlobal()
,并打印:

字符串:“你好”;长度:5


你是用PInvoke打电话给HeapSize吗?你能展示一下方法声明吗?(还有,所有的机器都是相同的体系结构,比如x86和x64吗?)。代码是:[DllImport(“kernel32”)]静态外部int-HeapSize(int-hHeap,int-flags,void*block);//返回内存块的大小。public static int SizeOf(void*block){int result=HeapSize(ph,0,block);if(result=-1)抛出新的invalidoOperationException();返回结果;}您使用的是不安全的代码吗?@user5900294如果您可以在请求时将问题添加到代码中,这总是很好的-这样可以保持问题的连贯性,并且更易于阅读。这次我在这里为你做了编辑。
    public static void Main( string[] args )
    {
        IntPtr strPtr = IntPtr.Zero;
        string str = "Hello";
        try
        {
            strPtr = Marshal.StringToHGlobalAnsi( str );

            Console.Out.WriteLine( "String: '{0}'; Length: {1}", str, AnsiStrLen( strPtr ) );
        }
        finally
        {
            if( strPtr != IntPtr.Zero )
            {
                Marshal.FreeHGlobal( strPtr );
            }
        }
    }

    public static int AnsiStrLen( IntPtr strPtr )
    {
        int size = 0;

        while( Marshal.ReadByte( strPtr ) != 0 )
        {
            size++;
            strPtr = IntPtr.Add( strPtr, 1 );
        }

        return size;
    }