Преобразуйте массив структур к IntPtr

я нашел следующий отрывок при чтении источника для Tempfile#initialize в оперативной библиотеке Ruby:

begin
  tmpname = File.join(tmpdir, make_tmpname(basename, n))
  lock = tmpname + '.lock'
  n += 1
end while @@cleanlist.include?(tmpname) or
  File.exist?(lock) or File.exist?(tmpname)

На первый взгляд, я принял, в то время как модификатор будет оценен, прежде чем содержание начинает... конец, но дело не в этом. Наблюдайте:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil

, Как Вы ожидали бы, цикл продолжит выполняться, в то время как модификатор верен.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil

, В то время как я был бы рад никогда не видеть эту идиому снова, начните..., конец довольно мощен. Следующее является общей идиомой к memoize метод остроты без параметрических усилителей:

def expensive
  @expensive ||= 2 + 2
end

Вот является ужасный, но быстрый путь к memoize чем-то более сложным:

def expensive
  @expensive ||=
    begin
      n = 99
      buf = "" 
      begin
        buf << "#{n} bottles of beer on the wall\n" 
        # ...
        n -= 1
      end while n > 0
      buf << "no more bottles of beer" 
    end
end

Первоначально записанный Jeremy Voorhis . Содержание было скопировано здесь, потому что это, кажется, было удалено от инициирующего сайта. Копии могут также быть найдены в веб-Архив и в Форум Шума Ruby . - тарифицируют Ящерицу

11
задан Vegard Larsen 6 July 2009 в 11:33
поделиться

3 ответа

StructureToPtr expects struct object, and foo is not structure it is array, that is why exception occurs.

I can suggest you to write structures in cycle (sadly, StructureToPtr does not have overload with Index):

long LongPtr = ptr.ToInt64(); // Must work both on x86 and x64
for (int I = 0; I < foo.Length; I++)
{
    IntPtr RectPtr = new IntPtr(LongPtr);
    Marshal.StructureToPtr(foo[I], RectPtr, false); // You do not need to erase struct in this case
    LongPtr += Marshal.SizeOf(typeof(Rect));
}

Another option is to write structure as four integers, using Marshal.WriteInt32:

for (int I = 0; I < foo.Length; I++)
{
    int Base = I * sizeof(int) * 4;
    Marshal.WriteInt32(ptr, Base + 0, foo[I].Left);
    Marshal.WriteInt32(ptr, Base + sizeof(int), foo[I].Top);
    Marshal.WriteInt32(ptr, Base + sizeof(int) * 2, foo[I].Right);
    Marshal.WriteInt32(ptr, Base + sizeof(int) * 3, foo[I].Bottom);
}

And the last, you can use unsafe keyword, and work with pointers directly.

13
ответ дан 3 December 2019 в 08:31
поделиться

Вы можете попробовать следующее:

 RECT[] rects = new RECT[ 4 ];
 IntPtr[] pointers = new IntPtr[4];
 IntPtr result =  Marshal.AllocHGlobal(IntPtr.Size * rects.Length);
 for (int i = 0; i < rects.Length; i++)
 {
     pointers[i] = Marshal.AllocHGlobal (IntPtr.Size);
     Marshal.StructureToPtr(rects[i], pointers[i], true);
     Marshal.WriteIntPtr(result, i * IntPtr.Size, pointers[i]);
 }
 // the array that you need is stored in result

И не забудьте освободить все, когда закончите.

0
ответ дан 3 December 2019 в 08:31
поделиться

Arbiter дал вам один хороший ответ о том, как упорядочивать массивы структур. Для таких непреобразуемых структур, как эти, я лично использовал бы небезопасный код, а не вручную маршалинг каждого элемента в неуправляемую память. Примерно так:

RECT[] foo = new RECT[4];
unsafe
{
    fixed (RECT* pBuffer = foo)
    {
        //Do work with pointer
    }
}

или вы можете закрепить массив с помощью GCHandle.

К сожалению, вы говорите, что вам нужно отправить эту информацию другому процессу. Если сообщение, которое вы публикуете, не является одним из тех, для которых Windows обеспечивает автоматический маршалинг, у вас есть другая проблема. Поскольку указатель относится к локальному процессу, он ничего не значит в удаленном процессе, и отправка сообщения с этим указателем вызовет неожиданное поведение, включая вероятный сбой программы. Итак, что вам нужно сделать, это записать массив RECT в память другого процесса, а не в вашу. Для этого вам нужно использовать OpenProcess для получения дескриптора процесса, VitualAllocEx для выделения памяти в другом процессе, а затем WriteProcessMemory для записи массива в виртуальную память другого процесса.

Опять же, к сожалению, если вы переходите от 32-битного процесса к 32-битному процессу или с 64-битного процесса на 64-битный процесс, все довольно просто, но от 32-битного процесса к 64-битному процессу все может стать немного сложным. VirtualAllocEx и WriteProcessMemory на самом деле не поддерживаются от 32 до 64. Вы можете добиться успеха, если попытаетесь заставить VirtualAllocEx выделить свою память в нижних 4 ГБ 64-битного пространства памяти, чтобы полученный указатель был действителен для вызовов API 32-битного процесса, а затем записать с этим указателем. Кроме того, у вас могут быть различия в размере структуры и упаковке между двумя типами процессов.

1
ответ дан 3 December 2019 в 08:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: