WinAPI Работа с сетевым адаптером
У меня возник такой вопрос, может кто подскажет: в своем проекте в VS2008 я работаю с сетевой картой "напрямую", т.е. принимаю приходящие байты ("сырые" пакеты), записываю в буфер и дальше уже обрабатываю их. Описатель сетевого адаптера получаю через CreateFile:
m_hDevice = CreateFile(deviceName, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0), deviceName при этом равен "\\\\.\\ndisprot", драйвер протокола NDIS я установил. Принимаю пакеты с помощью ReadFile:
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 объявлены следующим образом:
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);
Спасибо.
m_hDevice = CreateFile(deviceName, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0), deviceName при этом равен "\\\\.\\ndisprot", драйвер протокола NDIS я установил.
Откуда взяли драйвер?
В MSDN указано объявление API-функций для c/c++. А на pinvoke.net указано их объявление для .NET, без указателей и прочего.
К этому драйверу есть клиент, он работает корректно?
Если Вы имеете в виду, работает ли uiotest.exe из ndisprot\XX\test\, то да, работает.
Или можно поподробней, что имеется в виду под клиентом?
Хорошо, предположим я изменю объявление функции CreateFile. Если взять первый из предложенных вариантов в pinvoke.net, то функция будет возвращать объект SafeFileHandle, который потом я буду передавать функциям DeviceIoControl, ReadFile и WriteFile, но они работают только с объектами IntPtr. Как тогда можно конвертировать из SafeFileHandle в IntPtr?
Используя SafeHandle.DangerousGetHandle.
Или можно поподробней, что имеется в виду под клиентом?
Да, я имею в виду его. Ну так и пользуясь его исходником не удается определить ошибку??
1. А каким образом можно определить ошибку? Включить исходники в свой solution и поставить breakpoints?
2. И еще один вопрос по "конвертации": раньше я использовал msdn вариант DeviceIoControl:
private static extern unsafe bool DeviceIoControl (
IntPtr _hDevice,
uint _dwIoControlCode,
void* _lpInBuffer,
uint _nInBufferSize,
void* _lpOutBuffer,
uint _nOutBufferSize,
uint* _lpBytesReturned,
uint _lpOverlapped);
и кусок кода с использованием этой функции выглядит следующим образом:
// 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 решил взять следующее объявление:
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 не работает...
Либо во время сессии отладки указать расположение pdb файлов, открыть нужный исходник в студии, и в нем поставить бряку.
на pinvoke.net решил взять следующее объявление:
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.
"IntPtr lpInBuffer" заменить на "byte[] lpInBuffer". Аналогично с lpOutBuffer.
Заменил... правда в одном месте использовался массив char[] ndisAdapter = "\\DEVICE\\{4CF589F6-DD51-494A-A380-50595E708F49}", который я передавал раньше в качестве lpInBuffer, но раз сейчас этот параметр стал byte[], я перевел в этот тип ndisAdapter с помощью GetBytes(), надеюсь, что правильно использовал эту функцию, т.е. выбрал Unicode, а не другие варианты(UTF-8,...):
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, которое я нигде не могу найти... Каким образом можно узнать это значение?
Извини, но не совсем понял алгоритм действий, можно поподробней...
1. Где в VS можно указать расположение pdb файлов?
2. И добавить нужно исходники из ndisprot\XX\test\, поставить там бряки и запустить свой exe-шник?
hardcase, можно ли пояснить, как узнать ошибку с помощью pdb файлов?
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 (ну и другие полезные опции).
Project -> Properties -> Debug -> [X] Enable unmanaged code debugging.
Смотри, если у меня есть проект, в нем есть кусок кода, где функция WriteFile возвращает false, и я хочу узнать, что там за ошибка. Мне в этом же проекте включать отладку нативного кода или где?
После этого можно открыть в студии исходник неуправляемой DLL-ки и поставить точку останова в нужном месте.
И как узнать, исходники какой DDL-ки мне открывать?
Просто не понимаю алгоритм действий...
Спасибо.