Added AltSpider project to implement MySQL-based view enabled solution with different...
[LanSpider.git] / src / LanSpider / NetworkBrowser.cs
blob0112306dcb535747cb042dd45315ab2f9f8598cb
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Runtime.InteropServices;
5 using System.Security;
6 using System.Windows.Forms;
8 using Extensions;
10 namespace LanSpider
12 /// <summary>
13 /// Gets a list of machines and open shares on LAN. Uses DllImport of Netapi32.dll.
14 /// </summary>
15 public sealed class NetworkBrowser : INetworkBrowser
17 private static NetworkBrowser _instance;
19 private IEnumerable<string> _windowsNetworks;
21 private NetworkBrowser()
25 public static NetworkBrowser Instance
27 get
29 if ( _instance == null )
31 _instance = new NetworkBrowser();
33 return _instance;
37 #region Dll Imports
39 /// <summary>
40 /// Netapi32.dll : Get list of servers on the network.
41 /// </summary>
42 [DllImport( "Netapi32", CharSet = CharSet.Auto, SetLastError = true ), SuppressUnmanagedCodeSecurity]
43 private static extern int NetServerEnum(
44 string ServerNane, // must be null
45 int dwLevel,
46 ref IntPtr pBuf,
47 int dwPrefMaxLen,
48 out int dwEntriesRead,
49 out int dwTotalEntries,
50 int dwServerType,
51 string domain, // null for login domain
52 out int dwResumeHandle
55 /// <summary>
56 /// Netapi32.dll : Get list of shares on given machine.
57 /// </summary>
58 /// <returns></returns>
59 [DllImport( "Netapi32", CharSet = CharSet.Auto, SetLastError = true ), SuppressUnmanagedCodeSecurity]
60 private static extern int NetShareEnum(
61 string servername,
62 int level,
63 ref IntPtr bufptr,
64 int prefmaxlen,
65 out int entriesread,
66 out int totalentries,
67 out int resume_handle
71 /// <summary>
72 /// Netapi32.dll : The NetApiBufferFree function frees the memory
73 /// that the NetApiBufferAllocate function allocates.
74 /// Call NetApiBufferFree to free the memory that other network management functions return.
75 /// </summary>
76 [DllImport( "Netapi32", SetLastError = true ), SuppressUnmanagedCodeSecurity]
77 private static extern int NetApiBufferFree(
78 IntPtr pBuf );
80 /// <summary>
81 /// ServerInfo structure holds information on network servers returned by <see cref="NetServerEnum"/>.
82 /// </summary>
83 [StructLayout( LayoutKind.Sequential )]
84 private struct _SERVER_INFO_100
86 internal int sv100_platform_id;
87 [MarshalAs( UnmanagedType.LPWStr )] internal string sv100_name;
90 /// <summary>
91 /// ShareInfo1 structure hold share infomation as returned by <see cref="NetShareEnum"/> level 1.
92 /// </summary>
93 [StructLayout( LayoutKind.Sequential )]
94 private struct _SHARE_INFO_1
96 [MarshalAs( UnmanagedType.LPWStr )] internal string shi1_netname;
98 internal uint shi1_type;
99 [MarshalAs( UnmanagedType.LPWStr )] internal string shi1_remark;
102 [DllImport( "Mpr.dll", EntryPoint = "WNetOpenEnumA", CallingConvention = CallingConvention.Winapi )]
103 private static extern ErrorCodes WNetOpenEnum( ResourceScope dwScope, ResourceType dwType, ResourceUsage dwUsage,
104 NETRESOURCE p, out IntPtr lphEnum );
106 [DllImport( "Mpr.dll", EntryPoint = "WNetCloseEnum", CallingConvention = CallingConvention.Winapi )]
107 private static extern ErrorCodes WNetCloseEnum( IntPtr hEnum );
109 [DllImport( "Mpr.dll", EntryPoint = "WNetEnumResourceA", CallingConvention = CallingConvention.Winapi )]
110 private static extern ErrorCodes WNetEnumResource( IntPtr hEnum, ref uint lpcCount, IntPtr buffer,
111 ref uint lpBufferSize );
113 #endregion
115 #region Constants
117 private const int MAX_PREFERRED_LENGTH = -1;
119 private const int SV_TYPE_WORKSTATION = 1;
120 private const int SV_TYPE_SERVER = 2;
122 private const uint STYPE_PRINTQ = 1;
123 private const uint STYPE_DEVICE = 2;
124 private const uint STYPE_IPC = 3;
126 private const uint STYPE_SPECIAL = 0x80000000;
127 private const uint STYPE_TEMPORARY = 0x40000000;
129 #endregion
131 #region Public Methods
133 /// <summary>
134 /// Gets Microsoft Windows Networks.
135 /// </summary>
136 public IEnumerable<string> WindowsNetworks
140 if ( _windowsNetworks == null )
142 NETRESOURCE netRoot = new NETRESOURCE();
143 IEnumerable<string> networkObjects
144 = EnumerateServers( netRoot, ResourceScope.RESOURCE_GLOBALNET, ResourceType.RESOURCETYPE_DISK,
145 ResourceUsage.RESOURCEUSAGE_ALL,
146 ResourceDisplayType.RESOURCEDISPLAYTYPE_NETWORK, "" );
148 _windowsNetworks = from nwo in networkObjects
149 where nwo.EndsWith( "|RESOURCEDISPLAYTYPE_DOMAIN" )
150 select nwo.Remove( nwo.LastIndexOf( '|' ) );
153 return _windowsNetworks;
157 /// <summary>
158 /// Get public shares defined in network given.
159 /// </summary>
160 /// <param name="networkName"></param>
161 /// <returns></returns>
162 public IEnumerable<string> GetNetworkShares( string networkName )
164 IEnumerable<string> shares = null;
166 if ( WindowsNetworks.Contains( networkName ) )
168 NETRESOURCE netRoot = new NETRESOURCE();
169 IEnumerable<string> machines
170 = EnumerateServers( netRoot, ResourceScope.RESOURCE_GLOBALNET, ResourceType.RESOURCETYPE_DISK,
171 ResourceUsage.RESOURCEUSAGE_ALL, ResourceDisplayType.RESOURCEDISPLAYTYPE_SERVER,
172 networkName );
174 shares = from share in machines
175 where share.Count( '\\' ) >= 3
176 select share;
179 return shares;
183 /// <summary>
184 /// List network ResourceScope using Mpr.dll functions.
185 /// </summary>
186 /// <param name="pRsrc"></param>
187 /// <param name="scope"></param>
188 /// <param name="type"></param>
189 /// <param name="usage"></param>
190 /// <param name="displayType"></param>
191 /// <param name="kPath"></param>
192 /// <returns></returns>
193 private static IEnumerable<string> EnumerateServers( NETRESOURCE pRsrc, ResourceScope scope, ResourceType type,
194 ResourceUsage usage, ResourceDisplayType displayType,
195 string kPath )
197 List<string> aData = new List<string>();
199 uint bufferSize = 16384;
200 IntPtr buffer = Marshal.AllocHGlobal( (int) bufferSize );
201 IntPtr handle;
202 uint cEntries = 1;
203 bool serverenum = false;
205 ErrorCodes result = WNetOpenEnum( scope, type, usage, pRsrc, out handle );
207 if ( result == ErrorCodes.NO_ERROR )
211 result = WNetEnumResource( handle, ref cEntries, buffer, ref bufferSize );
213 if ( ( result == ErrorCodes.NO_ERROR ) )
215 Marshal.PtrToStructure( buffer, pRsrc );
217 if ( String.Compare( kPath, "" ) == 0 )
219 if ( ( pRsrc.dwDisplayType == displayType ) ||
220 ( pRsrc.dwDisplayType == ResourceDisplayType.RESOURCEDISPLAYTYPE_DOMAIN ) )
222 aData.Add( pRsrc.lpRemoteName + "|" + pRsrc.dwDisplayType );
225 if ( ( pRsrc.dwUsage & ResourceUsage.RESOURCEUSAGE_CONTAINER ) ==
226 ResourceUsage.RESOURCEUSAGE_CONTAINER )
228 if ( ( pRsrc.dwDisplayType == displayType ) )
230 aData.AddRange( EnumerateServers( pRsrc, scope, type, usage, displayType, kPath ) );
234 else
236 if ( pRsrc.dwDisplayType == displayType )
238 aData.Add( pRsrc.lpRemoteName );
239 aData.AddRange( EnumerateServers( pRsrc, scope, type, usage, displayType, kPath ) );
240 //return;
241 serverenum = true;
243 if ( !serverenum )
245 if ( pRsrc.dwDisplayType == ResourceDisplayType.RESOURCEDISPLAYTYPE_SHARE )
247 aData.Add( pRsrc.lpRemoteName + "-share" );
250 else
252 serverenum = false;
254 if ( ( kPath.IndexOf( pRsrc.lpRemoteName ) >= 0 ) ||
255 ( String.Compare( pRsrc.lpRemoteName, "Microsoft Windows Network" ) == 0 ) )
257 aData.AddRange( EnumerateServers( pRsrc, scope, type, usage, displayType, kPath ) );
261 else if ( result != ErrorCodes.ERROR_NO_MORE_ITEMS )
263 break;
266 while ( result != ErrorCodes.ERROR_NO_MORE_ITEMS );
268 WNetCloseEnum( handle );
271 Marshal.FreeHGlobal( buffer );
273 return aData;
277 public enum ResourceScope
279 RESOURCE_CONNECTED = 1,
280 RESOURCE_GLOBALNET,
281 RESOURCE_REMEMBERED,
282 RESOURCE_RECENT,
283 RESOURCE_CONTEXT
286 public enum ResourceType
288 RESOURCETYPE_ANY,
289 RESOURCETYPE_DISK,
290 RESOURCETYPE_PRINT,
291 RESOURCETYPE_RESERVED
294 [Flags]
295 public enum ResourceUsage
297 RESOURCEUSAGE_CONNECTABLE = 0x00000001,
298 RESOURCEUSAGE_CONTAINER = 0x00000002,
299 RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
300 RESOURCEUSAGE_SIBLING = 0x00000008,
301 RESOURCEUSAGE_ATTACHED = 0x00000010,
302 RESOURCEUSAGE_ALL = ( RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED ),
305 internal enum ErrorCodes
307 NO_ERROR = 0,
308 ERROR_NO_MORE_ITEMS = 259
311 public enum ResourceDisplayType
313 RESOURCEDISPLAYTYPE_GENERIC,
314 RESOURCEDISPLAYTYPE_DOMAIN,
315 RESOURCEDISPLAYTYPE_SERVER,
316 RESOURCEDISPLAYTYPE_SHARE,
317 RESOURCEDISPLAYTYPE_FILE,
318 RESOURCEDISPLAYTYPE_GROUP,
319 RESOURCEDISPLAYTYPE_NETWORK,
320 RESOURCEDISPLAYTYPE_ROOT,
321 RESOURCEDISPLAYTYPE_SHAREADMIN,
322 RESOURCEDISPLAYTYPE_DIRECTORY,
323 RESOURCEDISPLAYTYPE_TREE,
324 RESOURCEDISPLAYTYPE_NDSCONTAINER
327 [StructLayout( LayoutKind.Sequential )]
328 internal class NETRESOURCE
330 public ResourceScope dwScope = 0;
331 public ResourceType dwType = 0;
332 public ResourceDisplayType dwDisplayType = 0;
333 public ResourceUsage dwUsage = 0;
334 public string lpLocalName;
335 public string lpRemoteName;
336 public string lpComment;
337 public string lpProvider;
339 public NETRESOURCE()
341 lpProvider = null;
345 /// <summary>
346 /// Get list of share names available on given server.
347 /// </summary>
348 /// <param name="serverName">Network machine name.</param>
349 /// <returns>List of shares on server.</returns>
350 public IEnumerable<string> GetShares( string serverName )
352 IntPtr buffer = IntPtr.Zero;
354 List<string> shares = new List<string>();
355 int sizeofInfo = Marshal.SizeOf( typeof( _SHARE_INFO_1 ) );
359 int entriesRead;
360 int totalEntries;
361 int resHandle;
362 int ret = NetShareEnum( serverName, 1, ref buffer, MAX_PREFERRED_LENGTH, out entriesRead,
363 out totalEntries,
364 out resHandle );
366 if ( ret == 0 )
368 for ( int i = 0; i < totalEntries; i++ )
370 // Get next pointer to share info structure
371 IntPtr tmpBuffer = new IntPtr( (int) buffer + ( i * sizeofInfo ) );
373 // Get structure from pointer
374 _SHARE_INFO_1 shareInfo =
375 (_SHARE_INFO_1) Marshal.PtrToStructure( tmpBuffer, typeof( _SHARE_INFO_1 ) );
377 // Skipe special types of shares
378 if ( ( shareInfo.shi1_type & STYPE_TEMPORARY ) == STYPE_TEMPORARY
379 || ( shareInfo.shi1_type & STYPE_IPC ) == STYPE_IPC
380 || ( shareInfo.shi1_type & STYPE_DEVICE ) == STYPE_DEVICE
381 || ( shareInfo.shi1_type & STYPE_PRINTQ ) == STYPE_PRINTQ
382 || ( shareInfo.shi1_type & STYPE_SPECIAL ) == STYPE_SPECIAL
383 || shareInfo.shi1_remark == "Printer Drivers" )
385 continue;
388 shares.Add( @"\\" + serverName + @"\" + shareInfo.shi1_netname );
392 catch ( Exception ex )
394 MessageBox.Show( "Problem with acessing " +
395 "remote shares in NetworkBrowser " +
396 "\r\n\r\n\r\n" + ex.Message,
397 "Error", MessageBoxButtons.OK,
398 MessageBoxIcon.Error );
399 return null;
401 finally
403 // Free allocated memory
404 NetApiBufferFree( buffer );
407 return shares;
410 /// <summary>
411 /// Get the list of network machine of types serves and workstation.
412 /// </summary>
413 /// <returns>List of machines in network.</returns>
414 public IEnumerable<string> GetNetworkComputers()
416 IntPtr buffer = IntPtr.Zero;
417 int sizeofInfo = Marshal.SizeOf( typeof( _SERVER_INFO_100 ) );
418 string[] networkComputers = null;
421 // Get list of machines
422 int entriesRead;
423 int totalEntries;
424 int resHandle;
425 int ret = NetServerEnum( null, 100, ref buffer, MAX_PREFERRED_LENGTH, out entriesRead, out totalEntries,
426 SV_TYPE_WORKSTATION | SV_TYPE_SERVER, null, out resHandle );
428 if ( ret == 0 )
430 networkComputers = new string[totalEntries];
431 for ( int i = 0; i < totalEntries; i++ )
433 // Get next pointer to server info structure
434 IntPtr tmpBuffer = new IntPtr( (int) buffer + ( i * sizeofInfo ) );
436 // Get structure from pointer
437 _SERVER_INFO_100 svrInfo =
438 (_SERVER_INFO_100) Marshal.PtrToStructure( tmpBuffer, typeof( _SERVER_INFO_100 ) );
440 networkComputers[ i ] = svrInfo.sv100_name;
444 catch ( Exception ex )
446 MessageBox.Show( "Problem with acessing " +
447 "network computers in NetworkBrowser " +
448 "\r\n\r\n\r\n" + ex.Message,
449 "Error", MessageBoxButtons.OK,
450 MessageBoxIcon.Error );
451 return null;
453 finally
455 // Free allocated memory
456 NetApiBufferFree( buffer );
459 return networkComputers;
462 #endregion