Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

WinAPI Работа с сетевым адаптером

69K
13 мая 2011 года
Denis_M
11 / / 13.05.2011
Всем привет!

У меня возник такой вопрос, может кто подскажет: в своем проекте в VS2008 я работаю с сетевой картой "напрямую", т.е. принимаю приходящие байты ("сырые" пакеты), записываю в буфер и дальше уже обрабатываю их. Описатель сетевого адаптера получаю через CreateFile:
m_hDevice = CreateFile(deviceName, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0), deviceName при этом равен "\\\\.\\ndisprot", драйвер протокола NDIS я установил. Принимаю пакеты с помощью ReadFile:
Код:
char[] buffer = new char[10240];
uint bytesSent;
uint bytesRead;
unsafe
{
     fixed (void* pvPacket = buffer)
     {
         ret = ReadFile(m_hDevice, pvPacket, (uint)buffer.Length, &bytesRead, 0);
         //ret = WriteFile(m_hDevice, pvPacket, bytesRead, &bytesSent, 0);//ret=false! Код ошибки 87, параметр задан неверно.
     }
}

ReadFile работает без ошибок, в buffer записываются данные, здесь вопросов нет. Но если мне раскомментить следующую строку, где я хочу отправить какие-то данные из того же buffer на тот же m_hDevice с помощью WriteFile, то появляется ошибка — Параметр задан неверно.
В чем здесь может быть дело? В каком случае я могу прочитать данные, но не могу их отправить, если в CreateFile параметр режим доступа — GENERIC_WRITE | GENERIC_READ...

API объявлены следующим образом:

Код:
[DllImport("kernel32", SetLastError=true)]
private static extern IntPtr CreateFile (
string _lpFileName,
uint _dwDesiredAccess,
uint _dwShareMode,
uint _lpSecurityAttributes,
uint _dwCreationDisposition,
uint _dwFlagsAndAttributes,
uint _hTemplateFile);

[DllImport("kernel32", SetLastError=true)]
private static extern unsafe bool WriteFile (
IntPtr _hFile,
void* _lpBuffer,
uint _nNumberOfBytesToWrite,
uint* _lpNumberOfBytesWritten,
uint _lpOverlapped);

[DllImport("kernel32", SetLastError=true)]
private static extern unsafe bool ReadFile (
IntPtr _hFile,
void* _lpBuffer,
uint _nNumberOfBytesToRead,
uint* _lpNumberOfBytesRead,
uint _lpOverlapped);


Спасибо.
297
13 мая 2011 года
koodeer
1.2K / / 02.05.2009
Не могу сказать ничего, как исправить ошибку, т. к. вроде всё правильно. Однако, зачем использовать unsafe код? Не лучше ли объявить функции в managed стиле:
CreateFile
ReadFile
WriteFile

pinvoke.net - полезный сайт.
14
15 мая 2011 года
Phodopus
3.3K / / 19.06.2008
Цитата: Denis_M
Описатель сетевого адаптера получаю через CreateFile:
m_hDevice = CreateFile(deviceName, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0), deviceName при этом равен "\\\\.\\ndisprot", драйвер протокола NDIS я установил.


Откуда взяли драйвер?

69K
16 мая 2011 года
Denis_M
11 / / 13.05.2011
Драйвер взял из WDK 7.0, он входит в комплект.
69K
16 мая 2011 года
Denis_M
11 / / 13.05.2011
kooder, спасибо за информацию, действительно полезный сайт, только я не понял, почему такая разница в объявлении функций между pinvoke.net и MSDN? Или же все таки это одно и тоже?
69K
16 мая 2011 года
Denis_M
11 / / 13.05.2011
Я использую unsafe код, т.к. в объявлении функций есть указатели...
297
16 мая 2011 года
koodeer
1.2K / / 02.05.2009
Denis_M, в том-то и дело, что можно обойтись без указателей и без unsafe.
В MSDN указано объявление API-функций для c/c++. А на pinvoke.net указано их объявление для .NET, без указателей и прочего.
14
17 мая 2011 года
Phodopus
3.3K / / 19.06.2008
Цитата: Denis_M
Драйвер взял из WDK 7.0, он входит в комплект.


К этому драйверу есть клиент, он работает корректно?

69K
17 мая 2011 года
Denis_M
11 / / 13.05.2011
Цитата: Phodopus
К этому драйверу есть клиент, он работает корректно?



Если Вы имеете в виду, работает ли uiotest.exe из ndisprot\XX\test\, то да, работает.
Или можно поподробней, что имеется в виду под клиентом?

69K
17 мая 2011 года
Denis_M
11 / / 13.05.2011
Цитата: koodeer
Denis_M, в том-то и дело, что можно обойтись без указателей и без unsafe.


Хорошо, предположим я изменю объявление функции CreateFile. Если взять первый из предложенных вариантов в pinvoke.net, то функция будет возвращать объект SafeFileHandle, который потом я буду передавать функциям DeviceIoControl, ReadFile и WriteFile, но они работают только с объектами IntPtr. Как тогда можно конвертировать из SafeFileHandle в IntPtr?

5
17 мая 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Denis_M
Как тогда можно конвертировать из SafeFileHandle в IntPtr?


Используя SafeHandle.DangerousGetHandle.

14
18 мая 2011 года
Phodopus
3.3K / / 19.06.2008
Цитата: Denis_M
Если Вы имеете в виду, работает ли uiotest.exe из ndisprot\XX\test\, то да, работает.
Или можно поподробней, что имеется в виду под клиентом?


Да, я имею в виду его. Ну так и пользуясь его исходником не удается определить ошибку??

69K
18 мая 2011 года
Denis_M
11 / / 13.05.2011
Цитата: Phodopus
Да, я имею в виду его. Ну так и пользуясь его исходником не удается определить ошибку??



1. А каким образом можно определить ошибку? Включить исходники в свой solution и поставить breakpoints?

2. И еще один вопрос по "конвертации": раньше я использовал msdn вариант DeviceIoControl:

 
Код:
[DllImport("kernel32", SetLastError=true)]
        private static extern unsafe bool DeviceIoControl (
            IntPtr _hDevice,
            uint    _dwIoControlCode,
            void*   _lpInBuffer,
            uint    _nInBufferSize,
            void*   _lpOutBuffer,  
            uint    _nOutBufferSize,
            uint*   _lpBytesReturned,
            uint    _lpOverlapped);


и кусок кода с использованием этой функции выглядит следующим образом:
Код:
byte[] buf = new byte[1024];
               
                // number of bytes read into the buffer
                uint bytesRead = 0;
               
                // the query binding struct
                NDISPROT_QUERY_BINDING ndisprot = new NDISPROT_QUERY_BINDING();
               
                // size of the query binding struct
                uint bufsize = (uint)Marshal.SizeOf(ndisprot); 
               
                // set the current index to the next adapter
                ndisprot.BindingIndex = (ulong)adapterIndex;
               
                // read the adapter info
                unsafe
                {
                    fixed (void* vpBuf = buf)
                    {
                        validAdapter = DeviceIoControl (m_hDevice, IOCTL_NDISPROT_QUERY_BINDING, (void*)&ndisprot, bufsize, vpBuf, (uint)buf.Length, &bytesRead, 0);
                    }
                }


на pinvoke.net решил взять следующее объявление:

 
Код:
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
        static extern unsafe bool DeviceIoControl(
            IntPtr      hDevice,
            uint        dwIoControlCode,
            IntPtr       lpInBuffer,
            uint        nInBufferSize,
            IntPtr      lpOutBuffer,
            uint        nOutBufferSize,
            out uint    lpBytesReturned,
            IntPtr      lpOverlapped);


при этом возникает проблема - что передавать функции в качестве аргументов lpInBuffer и lpOutBuffer, которые раньше просто были указателями на void? Т.е. тот же buf, который я раньше передавал в качестве lpOutBuffer, для pinvoke.net варианта уже не подходит, а приведение типа (IntPtr)buf не работает...
5
18 мая 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Denis_M
1. А каким образом можно определить ошибку? Включить исходники в свой solution и поставить breakpoints?

Либо во время сессии отладки указать расположение pdb файлов, открыть нужный исходник в студии, и в нем поставить бряку.


Цитата: Denis_M
2. И еще один вопрос по "конвертации": раньше я использовал msdn вариант DeviceIoControl:

на pinvoke.net решил взять следующее объявление:

 
Код:
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
        static extern unsafe bool DeviceIoControl(
            IntPtr      hDevice,
            uint        dwIoControlCode,
            IntPtr       lpInBuffer,
            uint        nInBufferSize,
            IntPtr      lpOutBuffer,
            uint        nOutBufferSize,
            out uint    lpBytesReturned,
            IntPtr      lpOverlapped);


"IntPtr lpInBuffer" заменить на "byte[] lpInBuffer". Аналогично с lpOutBuffer.

69K
19 мая 2011 года
Denis_M
11 / / 13.05.2011
Цитата: hardcase


"IntPtr lpInBuffer" заменить на "byte[] lpInBuffer". Аналогично с lpOutBuffer.



Заменил... правда в одном месте использовался массив char[] ndisAdapter = "\\DEVICE\\{4CF589F6-DD51-494A-A380-50595E708F49}", который я передавал раньше в качестве lpInBuffer, но раз сейчас этот параметр стал byte[], я перевел в этот тип ndisAdapter с помощью GetBytes(), надеюсь, что правильно использовал эту функцию, т.е. выбрал Unicode, а не другие варианты(UTF-8,...):

 
Код:
uint bytesReturned = 0;
bool ret = false;
byte[] buf = new byte[100];
byte[] Buff = new byte[256];
Encoding e = Encoding.Unicode;
Buff = e.GetBytes(ndisAdapter);
           
// attempt to bind to the adapter
ret = DeviceIoControl (m_hDevice, IOCTL_NDISPROT_OPEN_DEVICE, Buff, (uint)(nameLength*sizeof(char)), buf, 0, out bytesReturned, IntPtr.Zero);


Но тем не менее проблема осталась. Отправлять все равно не хочет, код ошибки 3. На одном зарубежном форуме я увидел похожую ситуацию, где была описана работа с сетевым адаптером, так там после открытия device с помощью CreateFile в самом начале работы сразу использовалась функция DeviceIoControl с параметром IOCTL_NDISPROT_BIND_WAIT: (handle, IOCTL_NDISPROT_BIND_WAIT,....). Но для ее использования необходимо знать значение control code IOCTL_NDISPROT_BIND_WAIT, которое я нигде не могу найти... Каким образом можно узнать это значение?
69K
19 мая 2011 года
Denis_M
11 / / 13.05.2011
Цитата: hardcase
Либо во время сессии отладки указать расположение pdb файлов, открыть нужный исходник в студии, и в нем поставить бряку.



Извини, но не совсем понял алгоритм действий, можно поподробней...
1. Где в VS можно указать расположение pdb файлов?
2. И добавить нужно исходники из ndisprot\XX\test\, поставить там бряки и запустить свой exe-шник?

69K
19 мая 2011 года
Denis_M
11 / / 13.05.2011
Вопрос с IOCTL_NDISPROT_BIND_WAIT решен, соответствующий DeviceIoControl добавлен, но проблема осталась...

hardcase, можно ли пояснить, как узнать ошибку с помощью pdb файлов?
5
20 мая 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Denis_M

1. Где в VS можно указать расположение pdb файлов?
2. И добавить нужно исходники из ndisprot\XX\test\, поставить там бряки и запустить свой exe-шник?



Нужно включить отладку нативного кода в VisualStudio для проекта:
Project -> Properties -> Debug -> [X] Enable unmanaged code debugging.
После этого можно открыть в студии исходник неуправляемой DLL-ки и поставить точку останова в нужном месте. Если студия показывает, что не нашла бд символов для DLL-ки и точка останова не работает, то можно указать ей путь до pdb файла указанного модуля. Во время отладки: Debug -> Windows -> Modules, откроется окно со списком загруженных модулей (DLL-ок). ПКМ на модуле -> Load Symbols From (ну и другие полезные опции).

69K
20 мая 2011 года
Denis_M
11 / / 13.05.2011
Цитата: hardcase
Нужно включить отладку нативного кода в VisualStudio для проекта:
Project -> Properties -> Debug -> [X] Enable unmanaged code debugging.



Смотри, если у меня есть проект, в нем есть кусок кода, где функция WriteFile возвращает false, и я хочу узнать, что там за ошибка. Мне в этом же проекте включать отладку нативного кода или где?

Цитата: hardcase

После этого можно открыть в студии исходник неуправляемой DLL-ки и поставить точку останова в нужном месте.



И как узнать, исходники какой DDL-ки мне открывать?

Просто не понимаю алгоритм действий...

Спасибо.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог