Выделение родного.dll в C# с несколькими указателями

Имея следующий код в C++:

  • nConId - это идентификатор соединения
  • pParName имя параметра
  • pSubName Имя субпараметра (если есть)
  • pValue_out указатель на массив символов длины FCL_PAR_VALUE_LENGH
  • nValueSize реальный размер вектора pValue_out (не менее FCL_PAR_VALUE_LENGH)
extern "C" MY_API int ReadParameter(const ConnectionId_T nConId, const char* pParName,
    const char *pSubName, char *pValue_out, const int nValueSize );

Моя попытка:

[DllImport("mydll.dll", CharSet = CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
public static extern int ReadParameter(ConnectionId_T pConId, IntPtr pParName,
    ref IntPtr pSubName, ref IntPtr[] pValue_out, int nValueSize);

Я использую следующий код для вызова этой функции:

# nConId is returned from another function and the his value is 0

public const int FCL_PAR_VALUE_LENGH = 128; 

string param_string = "AUXF";
IntPtr pParName = (IntPtr)Marshal.StringToHGlobalAnsi(param_string);

string subparam_string = "T";
IntPtr pSubName = (IntPtr)Marshal.StringToHGlobalAnsi(subparam_string);

IntPtr[] aParValue = new IntPtr[FCL_PAR_VALUE_LENGH]; 

int returnedValue = ReadParameter(nConId, pParName, ref pSubName,
    ref aParValue, FCL_PAR_VALUE_LENGH);

Когда я запускаю код, я получаю AccessViolationException, поэтому я предполагаю, что в моем вызове что-то не так.

Неужели мой маршал не прав? Что я должен изменить в коде, чтобы получить хороший ответ?

PS: я тоже знаю, что звонок тоже что-то возвращает aParValue,

1 ответ

Решение

Ты слишком много работаешь с этими char*s. Совершенно законно (и поощряется) System.String для ввода и StringBuilder для вывода.

[DllImport("mydll.dll", CharSet = CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
public static extern int ReadParameter(
    ConnectionId_T pConId, 
    string pParName, 
    string pSubName,
    StringBuilder pValue_out,
    int nValueSize);

использование

const int sbLength = 256; //use a domain relevant value
StringBuilder sb = new StringBuilder(sbLength + 1); //for null character, hard to say if you need it without seeing the C++ code, but easier to just add it than find out.
int result = ReadParameter(conId, "paramname", "paramsubname", sb, sbLength);

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

Справочник по MSDN

Другие вопросы по тегам