我环顾四周,似乎找不到与我正在做的事情类似的任何事情的解决方案。我有两个应用程序,一个本机 C++ 应用程序和一个托管 C# 应用程序。C++ 应用程序分配在内存管理器中使用的字节池。在此内存管理器中分配的每个对象都有一个标头,每个标头都有一个 char* 指向对象的名称。C# 应用程序充当此内存的查看器。我使用内存映射文件来允许 C# 应用程序在 C++ 应用程序运行时读取内存。我的问题是我试图从标题结构中读取对象的名称并将其显示在 C# 中(或者只是将其存储在字符串中,等等)。使用不安全的代码,我能够将组成的四个字节转换char*
为一个IntPtr
,将其转换为一个void*
,然后调用Marshal.PtrToStringAnsi
。这是代码:
IntPtr namePtr = new IntrPtr(BitConverter.ToInt32(bytes, index));
unsafe
{
void* ptr = namePtr.ToPointer();
char* cptr = (char*)ptr;
output = Marshal.PtrToStringAnsi((IntPtr)ptr);
}
在这种情况下,bytes
是从内存映射文件中读取的数组,表示本机应用程序创建的所有字节池,并且index
是名称指针的第一个字节的索引。
我已经验证,在托管方面,调用返回的namePtr.ToPointer()
地址正是本机应用程序中名称指针的地址。如果这是本机代码,我只需ptr
转换为 achar*
就可以了,但是在我读过的托管代码中,我必须使用 Marshaller 来执行此操作。
此代码产生不同的结果。有时cptr
为空,有时它指向 ,有时它指向\0
几个亚洲字符(通过该PtrToStringAnsi
方法运行时会产生看似不相关的字符)。我认为这可能是一fixed
件事,但ToPointer
会产生一个固定的指针。有时在char*
调试器说Unable to evaluate the expression. The pointer is not valid
或类似的转换之后(重现每个返回的不同事物并不容易)。有时我在读取内存时遇到访问冲突,这导致我进入 C++ 方面。
在 C++ 方面,我认为实际读取内存可能存在一些问题,因为虽然存储指针的内存是内存映射文件的一部分,但构成文本的实际字节却不是。因此,我查看了如何更改对内存的读/写访问(在 Windows 上,请注意),并在 Windows 库中找到了 VirtualProtect 方法,我用它来将内存访问更改为 PAGE_EXECUTE_WRITECOPY,我认为这会给任何应用程序有一个指向该地址的指针至少能够读取那里的内容。但这也没有解决问题。
简而言之:
我有一个指向 char 数组(在 C++ 应用程序中分配)中的第一个 char 的指针(在 C# 中),并且正在尝试将该 char 数组读入 C# 中的字符串。
编辑:
源标头如下所示:
struct AllocatorHeader
{
// These bytes are reserved, and their purposes may change.
char _reserved[4];
// A pointer to a destructor mapping that is associated with this object.
DestructorMappingBase* _destructor;
// The size of the object this header is for.
unsigned int _size;
char* _name;
};
该_name
字段是我试图在 C# 中取消引用的字段。
编辑:
截至目前,即使使用下面提供的解决方案,我也无法在托管代码中取消引用此 char*。因此,我只是在内存映射文件引用的池中复制了 char* 并使用指向它的指针。这很有效,这让我相信这是一个与保护相关的问题。如果我在某个时候找到一种方法来规避这个问题,我会回答我自己的问题。在那之前,这将是我的解决方法。感谢所有帮助过的人!