Я много огляделся и не могу найти решение для чего-либо похожего на то, что я делаю. У меня есть два приложения: собственное приложение C++ и управляемое приложение C#. Приложение C++ выделяет пул байтов, которые используются в диспетчере памяти. Каждый объект, выделенный в этом диспетчере памяти, имеет заголовок, и каждый заголовок имеет char*, указывающий на имя, данное объекту. Приложение 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
к char*
, и все было бы хорошо, но в управляемом коде, который я читал, я должен использовать Marshaller для этого.
Этот код дает разные результаты. Иногда cptr
имеет значение null, иногда указывает на \0
, а иногда указывает на несколько азиатских символов (которые при выполнении метода PtrToStringAnsi
создают кажущиеся неуместными символы). Я думал, что это может быть fixed
, но ToPointer
создает фиксированный указатель. И иногда после приведения к char*
отладчик говорит Unable to evaluate the expression. The pointer is not valid
или что-то в этом роде (нелегко воспроизвести каждую переменную, которая возвращается). А в других случаях я получаю нарушение прав доступа при чтении памяти, что приводит меня к стороне C++.
Что касается C++, я подумал, что могут быть некоторые проблемы с фактическим чтением памяти, потому что, хотя память, в которой хранится указатель, является частью файла с отображением памяти, фактические байты, составляющие текст, не являются. Итак, я посмотрел, как изменить доступ для чтения/записи к памяти (заметьте, в Windows) и нашел метод VirtualProtect в библиотеках Windows, который я использую для изменения доступа к памяти на PAGE_EXECUTE_WRITECOPY, который, как я полагал, даст любому приложению, которое имеет указатель на этот адрес, сможет хотя бы прочитать, что там. Но и это не решило проблему.
Короче говоря:
У меня есть указатель (в C#) на первый символ в массиве символов (который был выделен в приложении C++), и я пытаюсь прочитать этот массив символов в строку в 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
— это то, что я пытаюсь разыменовать в С#.
РЕДАКТИРОВАТЬ:
На данный момент, даже используя приведенные ниже решения, я не могу разыменовать этот char* в управляемом коде. Таким образом, я просто сделал копию char* в пуле, на который ссылается файл с отображением памяти, и использовал указатель на него. Это работает, что заставляет меня поверить, что это проблема, связанная с защитой. Если я найду способ обойти это в какой-то момент, я отвечу на свой вопрос. До тех пор это будет моим обходным путем. Спасибо всем, кто помог!
GetBytes()
, вам придется использовать блокfixed
в массиве, чтобы превратить его в указатель. - person Richard J. Ross III   schedule 21.10.2013new string(addr, 0, len)
- person Marc Gravell   schedule 21.10.2013