miercuri, noiembrie 15, 2006

Screensaver

Un screensaver extrem de amuzant.

luni, noiembrie 13, 2006

Conexiune Wireless

Avand o conexiune wireless setata in mod peer-to-peer intre un desktop (pe post de router) si un laptop, am constatat in nenumarate randuri ca aceasta se deconecta fara un motiv evident dupa un interval de timp aparent aleator si, desi configurata sa se reconecteze automat, nu indeplinea aceasta sarcina. Procedeul de reconectare manuala consta in dezactivarea si apoi activarea conexiunii wireless pe desktop sau, mai comod, actionarea comenzii Repair pe acea conexiune - proces relativ incomod, mai ales in momentul in care laptopul se afla intr-o alta camera decat desktopul.

Cautand solutii atat pe Internet, cat si de la diversi specialisti in networking, modificand diverse setari ale placilor wireless (power saving mode, transmit power level etc), instaland drivere si diverse alte aplicatii, nu am putut gasi o rezolvare - mentionez faptul ca nu am vrut sa investesc intr-un Access Point din considerente legate atat de securitate, cat si de aspectul financiar.
Intr-un final, m-am decis sa automatizez procesul de reconectare cu ajutorul unui Windows Service in C# 2005. Planul era sa gasesc o modalitate de a afla starea conexiunii wireless (daca e activa sau nu si, in plus, daca e conectata sau nu), prin urmare, folosind o referinta la shell32.dll, am extras lista conexiunilor existente pe calculator si apoi, din aceasta lista, conexiunea in cauza. In felul acesta aveam atat o referinta catre conexiunea necesara, implicand verbele necesare activarii sau repararii ei, cat si informatia daca e activa sau nu. Ceea ce imi lipsea, era starea de conectare. Cautand un pic prin MSDN, am aflat ca printr-o interogare in WMI Win32_NetworkAdapter, pot afla cu exactitate si acest lucru. Prin urmare, avand la dispozitie toate ingredientele necesare, rezultatul era evident:

Codul sursa al serviciului (WirelessWatcher.cs) este urmatorul:

using System;
using System.ServiceProcess;
using System.Threading;
using System.Management;
using System.Diagnostics;
using System.Collections;
using Shell32;

namespace WirelessWatcher
{
public partial class WirelessWatcher : ServiceBase
{
private enum EventIDs
{
NetworkError = 60004,
WirelessNotAvailable = 60003,
EnableAction = 60002,
RepairAction = 60001,
UnknownError = 60000
}

private bool _IS_STOPPED = false;
private Thread _THREAD;
private string _NETWORK_NAME = Properties.Settings.Default.NetworkConnectionName;
private FolderItem2 _NETWORK_CONNECTION;
private FolderItemVerb _REPAIR_CONNECTION;

public WirelessWatcher()
{
InitializeComponent();
}

protected override void OnStart( string[] args )
{
//GET NETWORK CONNECTIONS LIST
Folder networkConnectionsFolder = GetNetworkConnectionsFolder();
if ( networkConnectionsFolder == null )
{
Log( "Network connections folder not found.", EventLogEntryType.Error, (int) EventIDs.NetworkError );
this.Stop();
}
else
{
this._NETWORK_CONNECTION = GetNetworkConnection( networkConnectionsFolder, this._NETWORK_NAME );
if ( this._NETWORK_CONNECTION == null )
{
Log( "Network connection not found.", EventLogEntryType.Error, (int) EventIDs.NetworkError );
this.Stop();
}
else
{
FolderItemVerb EnableVerb;
if ( !IsNetworkConnectionEnabled( this._NETWORK_CONNECTION, out EnableVerb ) )
{
Log( "Network: " + this._NETWORK_NAME + ". Enabling network.", EventLogEntryType.Warning, (int) EventIDs.EnableAction );
EnableVerb.DoIt();
System.Threading.Thread.Sleep( Properties.Settings.Default.TimeWaitAction * 1000 );
}

FolderItemVerbs verbs = this._NETWORK_CONNECTION.Verbs();
foreach ( FolderItemVerb verb in verbs )
{
if ( verb.Name == Properties.Settings.Default.RepairVerbName )
{
this._REPAIR_CONNECTION = verb;
break;
}
}
if ( this._REPAIR_CONNECTION == null )
{
Log( "Cannot find Repair verb.", EventLogEntryType.Error, (int) EventIDs.NetworkError );
this.Stop();
}
}
}

this._IS_STOPPED = false;
this._THREAD = new Thread( new ThreadStart( this.Start ) );
this._THREAD.Start();
}

protected override void OnStop()
{
this._IS_STOPPED = true;
if ( this._THREAD != null && ( this._THREAD.IsAlive || this._THREAD.ThreadState != System.Threading.ThreadState.Stopped ) )
this._THREAD.Abort();
}

private void Start()
{
int FailedActions = 0;
while ( !this._IS_STOPPED )
{
try
{
//FAILED TO CONNECT FOR MORE THAN MaxFailedActions TIMES
if ( FailedActions == Properties.Settings.Default.MaxFailedActions )
{
Log( "Failed to connect. Enabling sleep mode for " + Properties.Settings.Default.SleepTimeMinutes.ToString() + " minutes.", EventLogEntryType.Information, (int) EventIDs.WirelessNotAvailable );
FailedActions = 0;
//WAIT FOR SleepTimeMinutes
System.Threading.Thread.Sleep( Properties.Settings.Default.SleepTimeMinutes * 60000 );
}

using ( ManagementObjectSearcher mos = new ManagementObjectSearcher( "SELECT * FROM Win32_NetworkAdapter WHERE NetConnectionID = '" + this._NETWORK_NAME + "'" ) )
{
using ( ManagementObjectCollection moc = mos.Get() )
{
if ( moc.Count == 0 )
{
Log( "WMI Network connection not found.", EventLogEntryType.Error, (int) EventIDs.NetworkError );
this._IS_STOPPED = true;
}
else
{
IEnumerator e = moc.GetEnumerator();
e.MoveNext();
string ConnectionStatus = ( e.Current as ManagementObject ).Properties["NetConnectionStatus"].Value.ToString();
if ( ConnectionStatus == "7" ) //NOT CONNECTED
{
FailedActions++;
Log( "Network: " + this._NETWORK_NAME + ". Attempting repair #" + FailedActions + ".", EventLogEntryType.Warning, (int) EventIDs.RepairAction );
this._REPAIR_CONNECTION.DoIt();
System.Threading.Thread.Sleep( Properties.Settings.Default.TimeWaitAction * 1000 );
Log( "Network: " + this._NETWORK_NAME + ". Repair #" + FailedActions + " completed.", EventLogEntryType.Warning, (int) EventIDs.RepairAction );
}
else //CONNECTED OR UNAVAILABLE
{
FailedActions = 0;
System.Threading.Thread.Sleep( Properties.Settings.Default.TimeWaitAction * 1000 );
}
}
moc.Dispose();
}
mos.Dispose();
}
}
catch ( ThreadAbortException ) { }
catch ( Exception ex )
{
Log( "Thread exception: " + ex.Message, EventLogEntryType.Error, (int) EventIDs.UnknownError );
this._IS_STOPPED = true;
}
}
}

private static Folder GetNetworkConnectionsFolder()
{
Shell sh = new Shell();
Folder controlPanel = sh.NameSpace( 3 );
FolderItems items = controlPanel.Items();
foreach ( FolderItem item in items )
{
if ( item.Name == Properties.Settings.Default.NetworkConnectionsFolderName )
return (Folder) item.GetFolder;
}
return null;
}

private static FolderItem2 GetNetworkConnection( Folder networkConnectionsFolder, string networkName )
{
FolderItems items = networkConnectionsFolder.Items();
foreach ( FolderItem2 item in items )
{
if ( item.Name == networkName )
return item;
}
return null;
}

private static bool IsNetworkConnectionEnabled( FolderItem2 networkConnection, out FolderItemVerb outVerb )
{
FolderItemVerbs verbs = networkConnection.Verbs();
foreach ( FolderItemVerb verb in verbs )
{
if ( verb.Name == Properties.Settings.Default.EnableVerbName )
{
outVerb = verb;
return false;
}
else if ( verb.Name == Properties.Settings.Default.DisableVerbName )
{
outVerb = verb;
return true;
}
}
throw new Exception( "Cannot establish network status." );
}

private static void Log( string Message, EventLogEntryType type, int eventID )
{
if ( !EventLog.SourceExists( "Wireless Watcher" ) )
EventLog.CreateEventSource( "Wireless Watcher", "Application" );
EventLog.WriteEntry( "Wireless Watcher", Message, type, eventID );
}
}
}

iar cel al installer-ului (ProjectInstaller.cs):
using System;
using System.ComponentModel;
using System.Configuration.Install;
using System.Collections;

namespace WirelessWatcher
{
[RunInstaller( true )]
public partial class ProjectInstaller : Installer
{
public ProjectInstaller()
{
InitializeComponent();
}

public override void Install( IDictionary stateServer )
{
Microsoft.Win32.RegistryKey system, currentControlSet, services, service;

try
{
base.Install( stateServer );
system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "System" );
currentControlSet = system.OpenSubKey( "CurrentControlSet" );
services = currentControlSet.OpenSubKey( "Services" );
service = services.OpenSubKey( this.serviceInstaller1.ServiceName, true );
service.SetValue( "Description", "Wireless Watcher Service" );
}
catch ( Exception ex )
{
Console.WriteLine( "An exception was thrown during service installation:\n" + ex.ToString() );
}
}

public override void Uninstall( IDictionary stateServer )
{
Microsoft.Win32.RegistryKey system, currentControlSet, services, service;

try
{
system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( "System" );
currentControlSet = system.OpenSubKey( "CurrentControlSet" );
services = currentControlSet.OpenSubKey( "Services" );
service = services.OpenSubKey( this.serviceInstaller1.ServiceName, true );
}
catch ( Exception ex )
{
Console.WriteLine( "Exception encountered while uninstalling service:\n" + ex.ToString() );
}
finally
{
base.Uninstall( stateServer );
}
}
}
}

Si nu in ultimul rand, setarile serviciului (Settings.settings) fiind urmatoarele:

Dupa compilare, instalarea se realizeaza cu ajutorul utilitarului %SYSTEMROOT%\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe, din linie de comanda:
%SYSTEMROOT%\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe %APPLICATION_PATH%\bin\Release\WirelessWatcher.exe

unde %SYSTEMROOT% reprezinta calea catre directorul Windows, iar %APPLICATION_PATH% calea catre directorul unde se afla aplicatia. Dupa executarea comenzii, sistemul va cere credentialele user-ului sub care va rula serviciul. O recomandare ar fi crearea unui user cu drepturi minimale si folosirea lui pentru acest serviciu. Personal, am folosit credentialele contului Administrator, iar dupa instalare, am schimbat contul sub care ruleaza serviciul in Local System account.

De notat este faptul ca atunci cand se introduc credentialele, numele user-ului trebuie prefixat cu numele de domeniu sau numele masinii (ex: COMPUTER_NAME\UserName).
In final, ultimul pas este de a porni serviciul.

Intregul proiect este disponibil spre descarcare la adresa: http://www.ddainvest.ro/sharpidz/WirelessWatcher.zip