Wil*_*ode 5 c# c++ memory pointers unsafe
我经常环顾四周,似乎找不到与我正在做的事情相似的解决方案.我有两个应用程序,一个本机C++应用程序和一个托管C#应用程序.C++应用程序分配在内存管理器中使用的字节池.在此内存管理器中分配的每个对象都有一个标头,每个标头都有一个char*,指向给定对象的名称.C#app充当此内存的查看器.我使用内存映射文件允许C#app在C++应用程序运行时读取内存.我的问题是我试图从头结构中读取对象的名称并将其显示在C#中(或者只是将它存储在String中,无论如何).使用不安全的代码,我能够在四个字节组成转换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);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,bytes是从内存映射文件中读取的数组,它表示本机应用程序创建的所有字节池,并且index是名称指针的第一个字节的索引.
我已经验证,在托管方面,调用返回namePtr.ToPointer()的地址正是本机应用程序中名称指针的地址.如果这是本机代码,我会简单地转换ptr为a char*并且它会没问题,但在托管代码中,我已经阅读过,我必须使用Marshaller来执行此操作.
此代码会产生不同的结果.有时候cptr是null,有时它指向,有时它指向\0一些亚洲字符(当通过该PtrToStringAnsi方法运行时产生看似无关的字符).我认为这可能是一fixed件事,但ToPointer产生一个固定的指针.有时候,在char*调试者的演员表示Unable to evaluate the expression. The pointer is not valid或类似的东西之后(重新调整每一个变化的东西都不容易).有时我在读取内存时会遇到访问冲突,导致我进入C++方面.
在C++方面,我认为实际读取内存可能存在一些问题,因为虽然存储指针的内存是内存映射文件的一部分,但构成文本的实际字节却不是.所以我看看如何更改对内存的读/写访问权限(在Windows上,请注意)并在Windows库中找到VirtualProtect方法,我用它将内存访问权限更改为PAGE_EXECUTE_WRITECOPY,我认为这会给任何应用程序有一个指向该地址的指针将能够至少读取那里的内容.但这也没有解决问题.
简而言之:
我有一个指针(在C#中)到char数组中的第一个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;
};
Run Code Online (Sandbox Code Playgroud)
该_name字段是我试图在C#中取消引用的字段.
编辑:
截至目前,即使使用下面提供的解决方案,我也无法在托管代码中取消引用此char*.因此,我只是在内存映射文件引用的池中创建了char*的副本,并使用指向它的指针.这有效,这让我相信这是一个与保护相关的问题.如果我找到一种方法来规避这个问题,我会回答我自己的问题.在那之前,这将是我的解决方法.感谢所有帮助过的人!
在我的简单测试中,这似乎对我有用:
private static unsafe String MarshalUnsafeCStringToString(IntPtr ptr, Encoding encoding) {
void *rawPointer = ptr.ToPointer();
if (rawPointer == null) return "";
char* unsafeCString = (char*)rawPointer;
int lengthOfCString = 0;
while (unsafeCString[lengthOfCString] != '\0') {
lengthOfCString++;
}
// now that we have the length of the string, let's get its size in bytes
int lengthInBytes = encoding.GetByteCount (unsafeCString, lengthOfCString);
byte[] asByteArray = new byte[lengthInBytes];
fixed (byte *ptrByteArray = asByteArray) {
encoding.GetBytes(unsafeCString, lengthOfCString, ptrByteArray, lengthInBytes);
}
// now get the string
return encoding.GetString(asByteArray);
}
Run Code Online (Sandbox Code Playgroud)
也许有点复杂,但假设你的字符串是以 NUL 结尾的,它应该可以工作。