С# и передачу указателей структур в WinAPI
От: _f_b_i_  
Дата: 10.11.10 19:00
Оценка:
Доброе время суток форумчанам.

Клиент хочет рабочий пример на C#, а в виду того что програмированием на С# не занимался — возникли затруднения.

Есть экспортируемая из DLL функция int SomeFunct(struct SERVER_STRUCT *lpServers, unsigned int *lpInt);

В эквиваленте на С# получил следующее:

[DllImport("some.dll")]
public static extern Int32 SomeFunc(ref SERVER_STRUCT pServers, ref Int32 pulSize);

Возникло 2 вопроса:

1) Как в эту экспортируемую функцию в качестве первого параметра передать NULL ?
Чтобы было эквиваленто С++ вызову: SomeFunct(NULL, &ulSize);
Компилер хочет видеть именно указатель на структуру, а не NULL

2) Есди я правильно понял я могу выделить массив структур так:
SERVER_STRUCT[xxx] pServers = new SERVER_STRUCT[xxx];
Правильно ли организован вызов функции в этом случае?
Хочу передать начало этого массива в функцию чтобы она его заполнила.
SomeFunct(ref pServers[0], ref ulSize);
Компилер компилит, но логично ли это стилю C# ?

Прошу сильно не пинать. С# в глаза вижу первые 2 часа. Поиск пробовал, но конкрнетно на свои вопросы — ответов не нашел.

Спасибо.
Re: С# и передачу указателей структур в WinAPI
От: _FRED_ Черногория
Дата: 11.11.10 05:51
Оценка:
Здравствуйте, _f_b_i_, Вы писали:

___>>Клиент хочет рабочий пример на C#, а в виду того что програмированием на С# не занимался — возникли затруднения.

___>>Есть экспортируемая из DLL функция int SomeFunct(struct SERVER_STRUCT *lpServers, unsigned int *lpInt);
___>>В эквиваленте на С# получил следующее:
[c#]
___>>[DllImport("some.dll")]
___>>public static extern Int32 SomeFunc(ref SERVER_STRUCT pServers, ref Int32 pulSize);
[/c#]
___>>Возникло 2 вопроса:
___>>1) Как в эту экспортируемую функцию в качестве первого параметра передать NULL ?
___>> Чтобы было эквиваленто С++ вызову: SomeFunct(NULL, &ulSize);
___>> Компилер хочет видеть именно указатель на структуру, а не NULL

Объявить, вдобавок к основному определению, и так:
[DllImport("some.dll")]
public static extern Int32 SomeFunc(IntPtr pServers, IntPtr pulSize);

И вызывать с IntPtr.Zero.

___>>2) Есди я правильно понял я могу выделить массив структур так:

___>> SERVER_STRUCT[xxx] pServers = new SERVER_STRUCT[xxx];
___>> Правильно ли организован вызов функции в этом случае?
___>> Хочу передать начало этого массива в функцию чтобы она его заполнила.
___>> SomeFunct(ref pServers[0], ref ulSize);
___>> Компилер компилит, но логично ли это стилю C# ?
___>>Прошу сильно не пинать. С# в глаза вижу первые 2 часа. Поиск пробовал, но конкрнетно на свои вопросы — ответов не нашел.

В первом параметрe ожидается массив? Надо посмотреть описание структуры SERVER_STRUCT.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: С# и передачу указателей структур в WinAPI
От: _f_b_i_  
Дата: 11.11.10 08:38
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Объявить, вдобавок к основному определению, и так:

_FR>
_FR>[DllImport("some.dll")]
_FR>public static extern Int32 SomeFunc(IntPtr pServers, IntPtr pulSize);
_FR>

_FR>И вызывать с IntPtr.Zero.

Спасибо, не сообразил что может быть два определения к одному импорту.

_FR>В первом параметрe ожидается массив? Надо посмотреть описание структуры SERVER_STRUCT.


В первом параметре ожидается указатель на структуру. Обычный блок памяти который заполняется
структурными данными. Данных может быть много, поэтому выделяю блок памяти, столько — сколько
нужно и передаю указатель в фунцию. Собственно так делаю на С. Библиотечкая функция осталась,
а реализацию вызова нужно сделать на на C#.

Структура на С приблизительно такая:

typedef struct _SERVER_STRUCT
{
   unsigned int ...;
   unsigned int ...;
   ....
   char cName[256];
} SERVER_STRUCT;


Превратил в аналог:

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct SERVER_STRUCT
{
    public UInt32 ...;
    public UInt32 ...;
    ...
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public char[] cName;
}
Re[3]: С# и передачу указателей структур в WinAPI
От: _FRED_ Черногория
Дата: 11.11.10 09:01
Оценка:
Здравствуйте, _f_b_i_, Вы писали:

_FR>>В первом параметрe ожидается массив? Надо посмотреть описание структуры SERVER_STRUCT.

___>В первом параметре ожидается указатель на структуру.

Тогда всё нормально,
SomeFunct(ref pServers[0], ref ulSize);

вполне логично.

Единственно, если SomeFunct меняет что-то в переданной структуре более правильным будет указать [ Out ] перед параметром в объявлении:
[DllImport("some.dll")]
public static extern Int32 SomeFunc([In, Out] ref SERVER_STRUCT pServers, [In, Out] ref Int32 pulSize);
Help will always be given at Hogwarts to those who ask for it.
Re[4]: С# и передачу указателей структур в WinAPI
От: _f_b_i_  
Дата: 11.11.10 09:12
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, _f_b_i_, Вы писали:


_FR>Единственно, если SomeFunct меняет что-то в переданной структуре более правильным будет указать [ Out ] перед параметром в объявлении:

_FR>
_FR>[DllImport("some.dll")]
_FR>public static extern Int32 SomeFunc([In, Out] ref SERVER_STRUCT pServers, [In, Out] ref Int32 pulSize);
_FR>


Спасибо, уже понял что без [Out] никуда

Объявил еще вот так, корректно ли это? но тоже работае.

[DllImport("some.dll", EntryPoint = "SomeFunc", SetLastError = true)]
 public static extern Int32 SomeFunc([Out] SERVER_STRUCTb_[] pServer, ref Int32 pulSize);
Re[5]: С# и передачу указателей структур в WinAPI
От: _FRED_ Черногория
Дата: 11.11.10 09:21
Оценка:
Здравствуйте, _f_b_i_, Вы писали:

___>Спасибо, уже понял что без [Out] никуда

___>Объявил еще вот так, корректно ли это? но тоже работае.

"Работать" может многое — майкрософт некоторые вещи "делает за нас".

___>[DllImport("some.dll", EntryPoint = "SomeFunc", SetLastError = true)]
___> public static extern Int32 SomeFunc([Out] SERVER_STRUCTb_[] pServer, ref Int32 pulSize);


Если память под массив вы выделяете на дотнетной стороне и SomeFunc об этом знает и не меняет переданный ей указатель и не пишит по нему чего не попадя (структуры изменять — законно), то это корректно.
Help will always be given at Hogwarts to those who ask for it.
Re[6]: С# и передачу указателей структур в WinAPI
От: _f_b_i_  
Дата: 11.11.10 09:55
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>
___>>[DllImport("some.dll", EntryPoint = "SomeFunc", SetLastError = true)]
___>> public static extern Int32 SomeFunc([Out] SERVER_STRUCTb_[] pServer, ref Int32 pulSize);
_FR>


_FR>Если память под массив вы выделяете на дотнетной стороне и SomeFunc об этом знает и не меняет переданный ей указатель и не пишит по нему чего не попадя (структуры изменять — законно), то это корректно.


Да выделяю память вот так:
pServers = new SERVER_STRUCT[nServerCount];

Функция в DLL не знает кто и где выделил ей память (но полагаю что на C# выделяется из стандартной кучи процесса), все что она знает это указатель на начало памяти и ее размер.
Собствено функция в DLL только лишь заполняет структуры данных:

struct SERVER_STRUCT *pServer;
pServer->Port = ...;
pServer->Flags = ...;
...
Re[7]: С# и передачу указателей структур в WinAPI
От: _FRED_ Черногория
Дата: 11.11.10 10:35
Оценка:
Здравствуйте, _f_b_i_, Вы писали:

___>Да выделяю память вот так:

___>pServers = new SERVER_STRUCT[nServerCount];

___>Функция в DLL не знает кто и где выделил ей память (но полагаю что на C# выделяется из стандартной кучи процесса), все что она знает это указатель на начало памяти и ее размер.

___>Собствено функция в DLL только лишь заполняет структуры данных:

Тогда всё должно быть в порядке.
Help will always be given at Hogwarts to those who ask for it.
Re[8]: С# и передачу указателей структур в WinAPI
От: _f_b_i_  
Дата: 11.11.10 11:26
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Тогда всё должно быть в порядке.


А еще быстрый вопрос. у меня в структуре объявлен элемент:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
 public char[] cName;


Который правильно заполняется. Хочу преобразовать его в String (хотя меня как программера устроило бы и как есть, но
подозреваю что товаришь программист С# заказчика, будет доставать как конвертировать в его любимый String)

делаю приблизительно следующее:
string s = new string(pServers[i].cName);

Все хорошо, но раздражает куча нулей, которые остались от char[] cName.
Сразу возник вопрос — разве не должен был конструктор стринга отрезать стринг как только встретил первый /0 ?
Re[9]: С# и передачу указателей структур в WinAPI
От: _FRED_ Черногория
Дата: 11.11.10 11:38
Оценка:
Здравствуйте, _f_b_i_, Вы писали:

_FR>>Тогда всё должно быть в порядке.

___>А еще быстрый вопрос. у меня в структуре объявлен элемент:
___>[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
___> public char[] cName;

___>Который правильно заполняется. Хочу преобразовать его в String (хотя меня как программера устроило бы и как есть, но
___>подозреваю что товаришь программист С# заказчика, будет доставать как конвертировать в его любимый String)

___>делаю приблизительно следующее:

___>string s = new string(pServers[i].cName);
___>Все хорошо, но раздражает куча нулей, которые остались от char[] cName.
___>Сразу возник вопрос — разве не должен был конструктор стринга отрезать стринг как только встретил первый /0 ?

Вряд ли — а с какой стати? В спеке про это ни слова.
Можно так:
var s1 = new string(pServers[i].cName).TrimEnd('\0');
var s2 = new string(pServers[i].cName, 0, 1 + Array.FindLastIndex(pServers[i].cName, ch => ch != 0));


Я бы добавил в структуру метод:
public string Name() {
  if(cName == null) {
    return String.Empty;
  }//if

  return new string(cName, 0, 1 + Array.FindLastIndex(cName, ch => ch != 0));
}
Help will always be given at Hogwarts to those who ask for it.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.