Groups | Blog | Home
all groups > dotnet compact framework > november 2006 >

dotnet compact framework : DeviceIoControl failed with error 0x06/0x32


Mo
11/28/2006 10:03:39 PM
Hello all,
I am developing an application that will emulate the default Wi-Fi AP
menu, it will show the available
Access point list and allow the user to connect/renew IP/ view AP
properties, our client wants extended
AP properties (the default implementation is not enough for him)

so i am designing the application in .net CF 2.0 using C#, (i couldn't
use openCF implementation unfortunately), what i am trying to is
1)create a handle to the NDISUIO adapter
2)enumerate the NICs to find the WiFi one (get device name)
3)perform access point scan (then connect/view properties, etc)

i am able to create a handle to the NDISUIO driver, its a valid handle,
but then when i make DeviceIoControl using the handle from CreatFile,
and i pass the IOCTL "IOCTL_NDISUIO_QUERY_BINDING //Retrieves
adapter name and description."

the call fails, when i call GetLastError() it returns 0x06
"ERROR_INVALID_HANDLE " for the 1st iteration and then
0x32"ERROR_SHARING_VIOLATION " --does this mean the IOCTL is not
supported?

below is my code, i am new to C# and Interop, appreciate any help
Regards

<code>
// PInvoke definitions

[DllImport("coredll.dll", EntryPoint = "CreateFile")]
private static extern Handle CreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
int hTemplateFile);

[DllImport("coredll.dll", SetLastError = true)]
public static extern bool DeviceIoControl(
IntPtr hDevice, UInt32 dwIoControlCode,
IntPtr lpInBuffer, Int32 nInBufferSize,
IntPtr lpOutBuffer, Int32 nOutBufferSize,
ref UInt32 lpBytesReturned,
IntPtr lpOverlapped);

[DllImport("coredll.dll")]
public static extern uint GetLastError();

public const string NDIS_DEVICE_NAME = "NDS0:";
public const string NDISUIO_DEVICE_NAME = "UIO1:";

//define the IOCTL's
public const uint IOCTL_NDISUIO_QUERY_OID_VALUE = 0x120804;
public const uint IOCTL_NDISUIO_SET_OID_VALUE = 0x120814;
public const uint IOCTL_NDISUIO_REQUEST_NOTIFICATION =
0x12081c;
public const uint IOCTL_NDISUIO_CANCEL_NOTIFICATION = 0x120820;
public const uint IOCTL_NDISUIO_QUERY_BINDING = 0x12c80c;

[StructLayout(LayoutKind.Sequential)]
internal struct NDISUIO_QUERY_BINDING
{
internal uint BindingIndex; // 0-based binding number
internal uint DeviceNameOffset; // from start of this struct
internal uint DeviceNameLength; // in bytes
internal uint DeviceDescrOffset; // from start of this struct
internal uint DeviceDescrLength; // in bytes
}


//here is the bread and butter
public static NdisDevice[] EnumerateDevices()
{
bool bqueryBindingResult = false;
unsafe
{
fixed (byte* buf = Buffer)
{
UInt32 dwBytesWritten=0;
DriverHandle = CreateFile(NDISUIO_DEVICE_NAME,
0,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
INVALID_HANDLE_VALUE);

if ((int)DriverHandle == INVALID_HANDLE_VALUE)
{
uint uError = (uint)GetLastError();
}
NDISUIO_QUERY_BINDING* p = (NDISUIO_QUERY_BINDING*)buf;
for (uint i = 0; /* Nothing */; i++)
{
// The binding index is an *INPUT* to the operation.
// You have to set it to a valid value.
p->BindingIndex = i;
bqueryBindingResult=DeviceIoControl(DriverHandle,
IOCTL_NDISUIO_QUERY_BINDING,
new IntPtr(p),
sizeof(NDISUIO_QUERY_BINDING),
IntPtr.Zero,
Buffer.Length,
ref dwBytesWritten,
IntPtr.Zero);
if(bqueryBindingResult)
{
//get the adapter name
}
else if (GetLastError() != ERROR_NO_MORE_ITEMS)
{
uint uErrorCode = GetLastError();
}
else
break;
}
.....

</code>


--PS: sometimes with this version of CreateFile, DeviceIoControl fails
and i get errorcode 0x06 then 0x050 the next iterations 0x050
"ERROR_NOT_SUPPORTED"
DriverHandle = CreateFile(NDISUIO_DEVICE_NAME, GENERIC_READ |
GENERIC_WRITE,
FILE_SHARE_READ |
FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OVERLAPPED,INVALID_HANDLE_VALUE);
Paul G. Tobey [eMVP]
11/29/2006 9:12:56 AM
Well, you're an idiot for trying to redo everything that's in OpenNETCF,
especially when you're new to both the language and interop. I made tons of
mistakes during the development of the OpenNETCF code and I'm *not* new to
either one. Why wouldn't you use the source, at least, as a starting point?

Paul T.

[quoted text, click to view]

Mo
11/29/2006 10:31:04 AM
well i wish u granted me the benefit of a doubt, my client didnt
*agree* to use OpenNETCF code
(as far as i am concerned its a developer nightmare, so.....)
i am stuck with what i have


[quoted text, click to view]
Paul G. Tobey [eMVP]
11/29/2006 11:36:36 AM
So, you get the source code and start using that. He has something
specifically against any code that you didn't originally write yourself?
Will he allow you to use the new project wizard in Visual Studio? What
about sample code found on the Web? I transfer my comment to him...

Paul T.

[quoted text, click to view]

Mo
11/29/2006 12:36:13 PM
his company needs time to *study* the License of OpenCF before
approving it, and he needs this done next week :-(, i know i will be
done way after that
so i needed to get started

i found out why DeviceIOControl was failing, i defined
"IOCTL_NDISUIO_QUERY_BINDING = as 0x12c80c instead of 0x0012080c"
so now it works , i trying to extract the adapter name/description
using this call

<code>
p->BindingIndex = i;

bqueryBindingResult=DeviceIoControl(DriverHandle,
IOCTL_NDISUIO_QUERY_BINDING,
new IntPtr(p),
sizeof(NDISUIO_QUERY_BINDING),
IntPtr.Zero,
Buffer.Length,
ref dwBytesWritten,
IntPtr.Zero);
if(bqueryBindingResult)
{
string devName, devDesc;


devName = new string((char*)p,((int)(
p->DeviceNameOffset)),(int)(pDeviceNameLength));

devDesc = new string((char*)p, ((int)(p->DeviceDescrOffset)),
(int)(p->DeviceDescrLength));
</code>

what i get after 2 iterations is
1st iteration
==========
devName "1\0\0\0\0\0\0\0\0\0\0\0"
devDesc "\0\0\0\0\0\0\0\0\0\0\0\0"

2nd iteration
==========
devName "ndisFn1\0\0\0\0\0\0\0\0\0"
devDesc "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

shouldn't i be getting something like "WLAN" for the description? and
"Wireless" for the name?

am i parsing it wrong? the documentation of
"IOCTL_NDISUIO_QUERY_BINDING" and "NDISUIO_QUERY_BINDING" isnt clear
:-(
Regards
Mo


[quoted text, click to view]
Paul G. Tobey [eMVP]
11/29/2006 1:51:06 PM
I don't use DeviceIoControl to enumerate adapters. GetAdaptersInfo() works
a lot better.

Paul T.

[quoted text, click to view]
Mo
11/29/2006 7:26:01 PM
Hi Paul,
thanks for your help.
well i decided to use GetAdaptersInfo() as you advised, i found some
sample code
by Alex Feinman on how to use it via PInvloke
http://www.alexfeinman.com/download.asp?doc=AdapterInfo.zip

i added the code to my project, however i call GetAdaptersInfo() it
only finds
one adapter "RndisFn1" --which i believe is the Ethernet Pass thru
connection over AS,
it doesn't find the wi-fi adapter as the next ptr to an IP_ADAPTER_INFO
struct is null

i would like to add that i am using an sdio mini sd wifi card by
Spectec) and its not built in

below is my code, i would like to add that even the DeviceIOControl
call "IOCTL_NDISUIO_QUERY_BINDING" was finding 1 adapter as well (i was
parsing it wrong i guess, but i was getting "ndisFn1" for the adapter
name)

moreover i looked into my code, and it seems NDISUIO has the following
registry entries, do i need to add anything to it?

under HKLM\drivers\active\30
Name UIO1:
key Drivers\BuiltIn\NDISUIO

Regards
Mo

<code>
//enumerate the adapters
//this is the 1st thing i do in my code
int cb = 0;
int ret = GetAdaptersInfo(IntPtr.Zero, ref cb);
IntPtr pInfo = LocalAlloc(0x40, cb);
ret = GetAdaptersInfo(pInfo, ref cb);
if (ret == ERROR_BUFFER_OVERFLOW)
{
uint uErrorCode = GetLastError();
}
else if (ret == 0)
{
IP_ADAPTER_INFO info = new IP_ADAPTER_INFO(pInfo,
0);
while (info != null)
{
IP_ADDR_STRING st = info.IpAddressList;
string [] array1= new string[] {
info.AdapterName, info.CurrentIpAddress.IpAddress.String,
info.CurrentIpAddress.IpMask.String, info.GatewayList.IpAddress.String
};
info = info.Next;
}
}
LocalFree(pInfo);
//end



//below is the IP_ADAPTER_INFO class
/// <summary>
/// Class IP_ADAPTER_INFO
/// Description:
/// Implementation of custom marshaller for IPHLPAPI
IP_ADAPTER_INFO
/// </summary>
public class IP_ADAPTER_INFO : SelfMarshalledStruct
{
#region Constructors
public IP_ADAPTER_INFO()
: base(640)
{
}
public IP_ADAPTER_INFO(byte[] data, int offset)
: base(data, offset)
{
}


public IP_ADAPTER_INFO(IntPtr pData, int offset)
: base(640)
{
Marshal.Copy(new IntPtr(pData.ToInt32() + offset), data, 0,
640);
}
#endregion

#region Properties
public IP_ADAPTER_INFO Next
{
get
{
if (this.GetInt32(0) == 0)
return null;
return new IP_ADAPTER_INFO(new
IntPtr(this.GetInt32(0)), 0);
}
}
public uint ComboIndex
{
get { return GetUInt32(4); }
set { Set(typeof(uint), 4, value); }
}
public string AdapterName
{
get { return GetStringAscii(8, 268 - 8); }
set { Set(typeof(string), 8, value); }
}
public string Description
{
get { return GetStringAscii(268, 400 - 268); }
set { Set(typeof(string), 268, value); }
}
public uint AddressLength
{
get { return GetUInt32(400); }
set { Set(typeof(uint), 400, value); }
}
public byte[] Address
{
get { return GetSlice(404, (int)AddressLength); }
}
public uint Index
{
get { return GetUInt32(412); }
set { Set(typeof(uint), 412, value); }
}
public uint Type
{
get { return GetUInt32(416); }
set { Set(typeof(uint), 416, value); }
}
public uint DhcpEnabled
{
get { return GetUInt32(420); }
set { Set(typeof(uint), 420, value); }
}
public IP_ADDR_STRING CurrentIpAddress
{
get
{
IntPtr p = new IntPtr(GetInt32(424));
if (p == IntPtr.Zero)
return null;
return new IP_ADDR_STRING(p, 0);
}
}
public IP_ADDR_STRING IpAddressList
{
get
{
return new IP_ADDR_STRING(data, 428);
}
}
public IP_ADDR_STRING GatewayList
{
get
{
return new IP_ADDR_STRING(data, 468);
}
}
public IP_ADDR_STRING DhcpServer
{
get
{
return new IP_ADDR_STRING(data, 508);
}
}
public int HaveWins
{
get { return GetInt32(548); }
set { Set(typeof(int), 548, value); }
}
public IP_ADDR_STRING PrimaryWinsServer
{
get
{
return new IP_ADDR_STRING(data, 552);
}
}
public IP_ADDR_STRING SecondaryWinsServer
{
get
{
return new IP_ADDR_STRING(data, 592);
}
}
public uint LeaseObtained
{
get { return GetUInt32(632); }
set { Set(typeof(uint), 632, value); }
}
public uint LeaseExpires
{
get { return GetUInt32(636); }
set { Set(typeof(uint), 636, value); }
}
#endregion
}

/// <summary>
/// Class IP_ADDR_STRING
/// Description:
/// Implementation of custom marshaller for IPHLPAPI IP_ADDR_STRING
/// </summary>
public class IP_ADDR_STRING : SelfMarshalledStruct
{
#region Contructors
public IP_ADDR_STRING()
: base(40)
{
}
public IP_ADDR_STRING(byte[] data, int offset)
: base(data, offset)
{
}
public IP_ADDR_STRING(IntPtr pData, int offset)
: base(40)
{
Marshal.Copy(new IntPtr(pData.ToInt32() + offset), data, 0,
40);
}
#endregion

#region Properties
public IP_ADDR_STRING Next
{
get
{
if (this.GetInt32(0) == 0)
return null;
return new IP_ADDR_STRING(new IntPtr(GetInt32(0)), 0);
}
}
public IP_ADDRESS_STRING IpAddress
{
get { return new IP_ADDRESS_STRING(data, baseOffset + 4); }

}
public IP_ADDRESS_STRING IpMask
{
Paul G. Tobey [eMVP]
11/30/2006 9:06:45 AM
I'm sure you're doing something wrong. Punt managed code for now and do
this from C. That will remove wrappers, incorrect declarations of
structures, marshaling, etc. from the equation. How much space are you
passing to GetAdaptersInfo() for it to write the list of adapters into?

I'm not going to read your DeviceIoControl code. I'm not interested in
whether or how that method works...

Paul T.

[quoted text, click to view]
Mo
11/30/2006 1:52:52 PM
hey Paul,
thanks for taking the time to answer my questions,

well my device was acting weired so i did master reset on it,
re-installed the WLAN sdio driver
(its called IPN2128.cab for Wibotics SDIO WLAN adapter) --i didn't make
no code changes :-)

to my surprise both calls to GetAdaptersInfo() and
DeviceIOControl(..IOCTL_NDISUIO_QUERY_BINDING) now find 2/3 adapters
(i finally figured how to correctly parse
the name/description from "IOCTL_NDISUIO_QUERY_BINDING" call :-) )

the call to GetAdaptersInfo() finds 2 adapters,
1) RndisFn1(pass thru over AS)
2) IPN2128 (this is the wlan adapter)

both of these adapters are Ethernet type

however "IOCTL_NDISUIO_QUERY_BINDING" call find the 2 adapters above,
in addition to
a 3rd adapter called "WWAN1:" --which i think is the GPRS adapter"

now my question is, why the wlan sdio adapter has the same name
"IPN2128" as the description
shouldn't its description at least be something like "WLAN:"?

based on the info above, each WLAN sdio card will have different name,
i need to find the WLAN adapter from its description before i can bind
to it and proceed with the following IOCTLS/OID's to get all the info
that i need, my understanding that after i find the WLAN adapter i need
to get the AP list through "IOCTL_NDISUIO_QUERY_OID_VALUE"
OID_802_11_BSSID_LIST
and so on

but if each WLAN SDIO card has different name and its description
matches its name
then how can i distinguish the WLAN adapter from others? or should i
just say as long its not
"WWAN" or "RndisFn1" then go ahead and proceed with the IOCTL's?

i am missing something here?

Regards
Mo



[quoted text, click to view]
Paul G. Tobey [eMVP]
11/30/2006 3:08:29 PM
[quoted text, click to view]

The description, as far as I can recall, is set in the registry. If it's
not something that you like, change the registry for your adapter's NDIS
driver. It should *never* be something that looks like a driver name, as
it's not exposed as a named driver (in the sense of "COM1:"). You access it
through NDIS, always.

[quoted text, click to view]

Generally, the instance of the adapter will be named something more like
<drivername><indexnumber>. For example, our devices have a LAN9000 device
built onto the motherboard. The adapter name returned for that from
GetAdaptersInfo() is LAN90001 (index number is one for the first instance of
the adapter). This all gets set from the following registry entries:

[HKEY_LOCAL_MACHINE\Comm\LAN9000]
"DisplayName"="SMC LAN91C111 Ethernet"
"Group"="NDIS"
"ImagePath"="LAN91C111.DLL"

[HKEY_LOCAL_MACHINE\Comm\LAN9000\Linkage]
"Route"=multi_sz:"LAN90001"

[HKEY_LOCAL_MACHINE\Comm\LAN90001]
"DisplayName"="SMC LAN91C111 Ethernet"
"Group"="NDIS"
"ImagePath"="LAN91C111.DLL"

[HKEY_LOCAL_MACHINE\Comm\LAN90001\Parms]
"BusNumber"=dword:0
"BusType"=dword:1
"InterruptNumber"=dword:E ;<= interrupt number, in hex
"IoBaseAddress"=dword: ABA00300 ;<= IOBase address, in hex (SEE NOTE)
"Transceiver"=dword:1e ;<= Enter the correct sysintr value here.
"sysintr"=dword:1e

[HKEY_LOCAL_MACHINE\Comm\LAN90001\Parms\TcpIp]
"EnableDHCP"=dword:1 ;<== set to 1 if DHCP enabled.
"DefaultGateway"=""
"UseZeroBroadcast"=dword:0
"IpAddress"=""
"Subnetmask"=""

[HKEY_LOCAL_MACHINE\Comm\Tcpip\Linkage]
"Bind"=multi_sz:"LAN90001"

Paul T.

AddThis Social Bookmark Button