There is actually a (subtle) difference between the two. Imagine you have the following code in File1.cs:
// File1.cs
using System;
namespace Outer.Inner
{
class Foo
{
static void Bar()
{
double d = Math.PI;
}
}
}
Now imagine that someone adds another file (File2.cs) to the project that looks like this:
// File2.cs
namespace Outer
{
class Math
{
}
}
The compiler searches Outer
before looking at those using
directives outside the namespace, so it finds Outer.Math
instead of System.Math
. Unfortunately (or perhaps fortunately?), Outer.Math
has no PI
member, so File1 is now broken.
This changes if you put the using
inside your namespace declaration, as follows:
// File1b.cs
namespace Outer.Inner
{
using System;
class Foo
{
static void Bar()
{
double d = Math.PI;
}
}
}
Now the compiler searches System
before searching Outer
, finds System.Math
, and all is well.
Some would argue that Math
might be a bad name for a user-defined class, since there's already one in System
; the point here is just that there is a difference, and it affects the maintainability of your code.
It's also interesting to note what happens if Foo
is in namespace Outer
, rather than Outer.Inner
. In that case, adding Outer.Math
in File2 breaks File1 regardless of where the using
goes. This implies that the compiler searches the innermost enclosing namespace before it looks at any using
directive.
After some more investigation I eventually gave up with the registry settings. It seems that the key to a successful connection is the Password value in HKCU\Comm\EAP\Config[SSID]. But because CryptProtectData uses an undocumented entropy value (for obvious security reasons) to encrypt the password, it seems impossible to recreate a valid entry in the registry programmatically.
I then went with the second best solution, catching the User Logon dialog after calling WZCSetInterface
and enter the required fields in there:
bool enteredPeapCred = false;
DateTime timePeapCredStarted = DateTime.Now.AddSeconds(10);
// wait for PEAP credentials window to appear (max. wait for 10 seconds)
while (!enteredPeapCred && timePeapCredStarted >= DateTime.Now)
{
IntPtr hwndLogon = Win32.FindWindow(null, "User Logon");
if (hwndLogon != IntPtr.Zero)
{
// move User Logon window offscreen to prevent screen flicker in app
Win32.MoveWindow(hwndLogon, -600, 0, 320, 480, true);
// "Network Log On" label
IntPtr hwndCtrl1 = Win32.GetWindow(hwndLogon, Win32.GW_CHILD);
// "Enter network info..." label
IntPtr hwndCtrl2 = Win32.GetWindow(hwndCtrl1, Win32.GW_HWNDNEXT);
// "User name:" label
IntPtr hwndCtrl3 = Win32.GetWindow(hwndCtrl2, Win32.GW_HWNDNEXT);
// username textbox
IntPtr hwndCtrl4 = Win32.GetWindow(hwndCtrl3, Win32.GW_HWNDNEXT);
// "Password:" label
IntPtr hwndCtrl5 = Win32.GetWindow(hwndCtrl4, Win32.GW_HWNDNEXT);
// password textbox
IntPtr hwndCtrl6 = Win32.GetWindow(hwndCtrl5, Win32.GW_HWNDNEXT);
// enter password into textbox
StringBuilder sbPassword = new StringBuilder();
sbPassword.Append(eapPassword);
Win32.SetWindowText(hwndCtrl6, sbPassword);
// "Domain:" label
IntPtr hwndCtrl7 = Win32.GetWindow(hwndCtrl6, Win32.GW_HWNDNEXT);
// domain textbox
IntPtr hwndCtrl8 = Win32.GetWindow(hwndCtrl7, Win32.GW_HWNDNEXT);
// "Save password" checkbox
IntPtr hwndCtrl9 = Win32.GetWindow(hwndCtrl8, Win32.GW_HWNDNEXT);
// send BST_CHECKED message to set checkbox
Win32.SendMessage(hwndCtrl9, Win32.BM_SETCHECK, Win32.BST_CHECKED, 0);
// send WM_COMMAND with left softkey to submit user dialog
IntPtr hwndMenu = Win32.SHFindMenuBar(hwndLogon);
Win32.SendMessage(hwndLogon, Win32.WM_COMMAND, 0x2F87, hwndMenu.ToInt32());
enteredPeapCred = true;
}
}
Note that I'm only setting the password field, because the username and domain fields are pre-populated with the information already stored in the registry (the Identity value mentioned in my original question).
This works well enough, as it creates the WLAN connection using the PEAP credentials. And by moving User Logon dialog offscreen as soon as it's found, this all happens invisibly to our application's user (our app runs in kiosk mode).
Best Answer
Take a look at the Smart Device Framework. It has a NetworkInformation namespace that wrap a large amount of the WZC functionality. I know it will do WEP and WPA with TKIP (as well as open). It allows you to pass in the key material, set up most options, etc.
Look specifically at the WirelessZeroConfigNetworkInterface class and it's AddPreferredNetwork method.
Edit: If you're curious what APIs you'd use directly, you'd start here.