2015-04-17 3 views
2

Я хотел бы получить некоторое просветление по поводу какой-либо проблемы с макетом памяти, которую я имею и пытаюсь понять. Это моя программа.C# Проблема с раскладкой памяти

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Management; 
using System.Diagnostics; 
using System.Threading; 
using System.Runtime.InteropServices; 
using System.ComponentModel; 

namespace ManagementSysInfo 
{ 
    class Program 
    { 
     public enum ACTION_TYPE :uint 
     { 
      NONE, // 0 
      RESTART, // 1. 
      ABORT, // 2. 
      WAIT //3 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct ACTIONS 
     { 
      public ACTION_TYPE type; 
      public int delay; 

     } 

     static void Main(string[] args) 
     { 
      int numAction = 3; 

      ACTIONS action1 = new ACTIONS() 
      { 
       type = ACTION_TYPE.RESTART, 
       delay = 10000 
      }; 

      ACTIONS action2, action3; 
      action2 = action3 = action1; 
      ACTIONS[] sc_act_array = new[] { action1, action2, action3 }; 

      int[] actionsArray = new int[numAction * 2]; 
      int index = -1; 
      foreach (ACTIONS act in sc_act_array) 
      { 
       actionsArray[++index] = (int)act.type; 
       actionsArray[++index] = (int)act.delay; 
      } 

      int buffsize = Marshal.SizeOf(actionsArray[0]) * actionsArray.Length ; 
      IntPtr actions_ptr = Marshal.AllocHGlobal(buffsize); 

      Marshal.Copy(actionsArray, 0, actions_ptr, sc_act_array.Length); 

      int i =Marshal.SizeOf(actions_ptr); 

      Marshal.FreeHGlobal(actions_ptr); 
     } 
    } 
} 

Хорошо, что я пытаюсь добиться здесь, это маршал массива структуры для неуправляемой памяти. Но после некоторого чтения здесь и там люди, кажется, говорят, что класс маршала в сервисе interop не обеспечивает чистый способ маршалирования массива структур. И лучше иногда, если выполнимо (я думаю, для не сложной структуры) выразить его как массив примитивов. Следовательно, my actionsArray переменная содержит упакованное содержимое структурного массива sc_act_array. И мой actions_ptr будет содержать ссылку на содержимое действийArray в неуправляемой памяти. Из моего понимания, если все пойдет правильно, я могу прочитать информацию, собранную с помощью указателя, и добавить к ней некоторое смещение. Поскольку каждый элемент массива occipies пространство 4 байта памяти (поправьте меня, если ошибаюсь) я имел это отображение в моей голове, думая, что это, как данные в неуправляемой памяти следует сопоставить один выстроил из управляемой памяти:

(actions_ptr, 0) = actionsArray [0] = 1

(actions_ptr, 4) = actionsArray [1] = 10000

(actions_ptr, 8) = actionsArray [2] = 1

(actions_ptr, 12) = actionsArray [3] = 10000

(actions_ptr, 16) = actionsArray [4] = 1

(actions_ptr, 20) = actionsArray [5] = 10000

При запуске программы все идет хорошо, не исключение. Но когда я debbug и проверять содержимое смещая указатель на значение 4 байта я получить что-то странно, следующий приходит из моего окна Immediate:

Marshal.ReadInt32 (actions_ptr, 0) Маршал. ReadInt32 (actions_ptr, 4) Marshal.ReadInt32 (actions_ptr, 8) Marshal.ReadInt32 (actions_ptr, 12) Marshal.ReadInt32 (actions_ptr, 16) Marshal.ReadInt32 (actions_ptr, 20)

Marshal.ReadInt32 (actions_ptr, 24) Marshal.ReadInt32 (actions_ptr, 28) -2147483640

Я изо всех сил, чтобы понять, почему память не заложили, как я ожидал. Я что-то пропустил? Я думал, что это может быть связано с тем, что ЦП любит обрабатывать данные в куске специфики (т. Е. 8 байтов), и каким-то образом он добавляет некоторые промежутки между ними. Или, может быть, это просто факт, что Marshal.copy копирует данные в неуправляемую память не последовательным образом.

Может кто-нибудь пролить свет, пожалуйста.

Благодаря

+0

* класс маршала в сервисе interop не обеспечивает чистый способ маршалирования массива структур * У вас есть ссылки на это? – xanatos

+0

Я видел это в нескольких блогах. Это последнее, что я помню: посмотрите на Issue1. http://www.codeproject.com/Articles/6164/A-ServiceInstaller-Extension-That-Enables-Recovery – user3485103

ответ

2

Маршалинг массивов простых структур из C# на C/C++ работает отлично. Проблема в обратном направлении: вы не можете создать массив C/C++ и маршалить его на C#, потому что CLR не может знать размер массива.

Код испытания:

C#

public enum ACTION_TYPE : uint 
{ 
    NONE, // 0 
    RESTART, // 1. 
    ABORT, // 2. 
    WAIT //3 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct ACTIONS 
{ 
    public ACTION_TYPE type; 
    public int delay; 

} 

[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.StdCall)] 
public static extern void testarray(ACTIONS[] actions, int len); 

var actions = new[] 
{ 
    new ACTIONS { type = ACTION_TYPE.RESTART, delay = 11 }, 
    new ACTIONS { type = ACTION_TYPE.ABORT, delay = 22 }, 
    new ACTIONS { type = ACTION_TYPE.WAIT, delay = 33 }, 
}; 

testarray(actions, actions.Length); 

C++

enum ACTION_TYPE : unsigned int 
{ 
    NONE, // 0 
    RESTART, // 1. 
    ABORT, // 2. 
    WAIT //3 
}; 

struct ACTIONS 
{ 
    ACTION_TYPE type; 
    int delay; 
}; 

__declspec(dllexport) void __stdcall testarray(ACTIONS* actions, int len) 
{ 
    for (int i = 0; i < len; i++) 
    { 
     printf("%u %d\n", actions[i].type, actions[i].delay); 
    } 
} 

и для вашей ошибки

Marshal.Copy(actionsArray, 0, actions_ptr, actionsArray.Length); 

Это с orrect Marshal.Copy. Вы копировали слишком мало байтов.

+0

Ха хорошо знать, что проблема с marshaling struct array применяется только при переходе с C# на c/C++. Спасибо за информацию. Но здесь больше интересует понимание того, как макет памяти разрабатывается средой выполнения, если вы видите, что я имею в виду. И почему мои данные не там, где они должны быть. – user3485103

+0

@ user3485103 См. Жирный раздел в конце. Вы копировали слишком мало байтов. – xanatos

+0

@ user3485103 * проблема с marshaling struct array применяется только при переходе с C# на c/C++. * Нет, это наоборот. Проблема возникает только в том случае, если вы хотите, чтобы C/C++ выделяла память и передавала ее на C#. Вы можете создать массив на C#, передать его на C++, изменить его значения (** не его размер, его значения **) в C/C++ и прочитать измененные значения на C# без каких-либо проблем. Единственная проблема заключается в том, что C/C++ должен создать массив и передать его на C#. – xanatos

Смежные вопросы