I've been for a long time trying to enumerate network shares on a workgroup (no domain) network with out success.
The last thing I did was to use some C++ and C# code as a guide and produce something that looks like a good start.
I knew there was no way to post a question that was meaningfull enough so I created a short demo completely self-contained.
It contains a couple of work arounds. They are marked with "For now".
I know it's a lot to ask but the code only needs to be pasted into a blank form and run.
I get a Null error when I run it.
The last thing I did was to use some C++ and C# code as a guide and produce something that looks like a good start.
I knew there was no way to post a question that was meaningfull enough so I created a short demo completely self-contained.
It contains a couple of work arounds. They are marked with "For now".
I know it's a lot to ask but the code only needs to be pasted into a blank form and run.
I get a Null error when I run it.
Ready To Run Code:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' NULL pointer, it retrieves a handle to the root of the network.
Dim lpnr As NETRESOURCE = Nothing
If EnumerateFunc(lpnr) = False Then
Debug.WriteLine("Call to EnumerateFunc failed" & vbLf)
Else
End If
End Sub
'From (C++ code) https://learn.microsoft.com/en-us/windows/win32/wnet/enumerating-network-resources
Public Shared Function EnumerateFunc(ByVal lpnr As NETRESOURCE) As Boolean
Dim errResult As Integer
Dim hEnum As IntPtr
Dim numbBytes As Integer = 16384 '16 kilobytes is typical
Dim pToGlobal As IntPtr 'Pointers to unmanaged memory
Dim numbResources As Integer = -1
Dim resources(1) As NETRESOURCE 'The "1" is only to suppress warning message
'Begin the enumeration.
errResult = WNetOpenEnum(ResourceScope.GLOBALNET, ResourceType.ANY, 0, lpnr, hEnum) ' Returns hEnum
If errResult <> ErrorCodes.NO_ERROR Then
Debug.WriteLine("WnetOpenEnum failed with error: " & errResult)
Return False
End If
Dim ByteArray(numbBytes - 1) As Byte 'Array of numbBytes bytes
pToGlobal = Marshal.AllocHGlobal(numbBytes) 'Get memory of numbBytes bytes
'Allocate memory
If pToGlobal = Nothing Then
Debug.WriteLine("WnetOpenEnum failed with error: " & errResult)
Return False
End If
Do
'Zero memory
Marshal.Copy(ByteArray, 0, pToGlobal, numbBytes)
' -1 = enumerate all, numbResource returns actual number, numbBytes = buffer size
errResult = WNetEnumResource(hEnum, numbResources, pToGlobal, numbBytes)
If errResult = ErrorCodes.NO_ERROR Then
MarshalUnmananagedArray2Struct(Of NETRESOURCE)(pToGlobal, numbResources, resources)
'Loop through the structures
For i As Integer = 0 To numbResources - 1
Debug.WriteLine("==========================")
'Display the contents of the NETRESOURCE structures.
DisplayStruct(resources(i))
Debug.WriteLine("Call the EnumerateFunc function recursively")
If ResourceUsage.CONTAINER = (resources(i).dwUsage And ResourceUsage.CONTAINER) Then
If Not EnumerateFunc(resources(i)) Then 'Call the EnumerateFunc function recursively
Debug.WriteLine("EnumerateFunc returned FALSE")
End If
End If
Next i
ElseIf errResult <> ErrorCodes.ERROR_NO_MORE_ITEMS Then
Debug.WriteLine("WNetEnumResource failed with error:" & errResult)
Exit Do
End If
Loop While errResult <> ErrorCodes.ERROR_NO_MORE_ITEMS
Marshal.FreeHGlobal(pToGlobal)
errResult = WNetCloseEnum(hEnum)
If errResult <> ErrorCodes.NO_ERROR Then
Debug.WriteLine("WNetCloseEnum failed with error: " & errResult)
Return False
End If
Return True
End Function
Public Shared Sub MarshalUnmananagedArray2Struct(Of T)(hEnum As IntPtr, numb As Integer, ByRef mangagedArray As T())
Dim size = Marshal.SizeOf(GetType(T))
mangagedArray = New T(numb - 1) {}
For I = 0 To numb - 1
Try
Dim ins As IntPtr = New IntPtr(hEnum.ToInt64() + I * size)
mangagedArray(I) = Marshal.PtrToStructure(Of T)(ins)
Catch
Exit Sub
End Try
Next
End Sub
Public Shared Sub DisplayStruct(resource As NETRESOURCE)
Debug.Write("NETRESOURCE Scope: ")
Select Case resource.dwScope
Case (ResourceScope.CONNECTED)
Debug.WriteLine("connected")
Case (ResourceScope.GLOBALNET)
Debug.WriteLine("all resources")
Case (ResourceScope.REMEMBERED)
Debug.WriteLine("remembered")
Case Else
Debug.WriteLine("unknown scope ", resource.dwScope)
End Select
Debug.Write("NETRESOURCE Type: ")
Select Case resource.dwType
Case (ResourceType.ANY)
Debug.WriteLine("any")
Case (ResourceType.DISK)
Debug.WriteLine("disk")
Case (ResourceType.PRINT)
Debug.WriteLine("print")
Case Else
Debug.WriteLine("unknown type ", resource.dwType)
End Select
Debug.Write("NETRESOURCE DisplayType: ")
Select Case resource.dwDisplayType
Case (ResourceDisplayType.GENERIC)
Debug.WriteLine("generic")
Case (ResourceDisplayType.DOMAIN)
Debug.WriteLine("domain")
Case (ResourceDisplayType.SERVER)
Debug.WriteLine("server")
Case (ResourceDisplayType.SHARE)
Debug.WriteLine("share")
Case (ResourceDisplayType.FILE)
Debug.WriteLine("file")
Case (ResourceDisplayType.GROUP)
Debug.WriteLine("group")
Case (ResourceDisplayType.NETWORK)
Debug.WriteLine("network")
Case Else
Debug.WriteLine("unknown display type: ", resource.dwDisplayType)
End Select
Debug.Write("NETRESOURCE Usage: ")
If (resource.dwUsage And ResourceUsage.CONNECTABLE) <> 0 Then
Debug.WriteLine("connectable ")
End If
If (resource.dwUsage And ResourceUsage.CONTAINER) <> 0 Then
Debug.WriteLine("container ")
End If
Debug.WriteLine("NETRESOURCE Localname: " & resource.lpLocalName)
Debug.WriteLine("NETRESOURCE Remotename: " & resource.lpRemoteName)
Debug.WriteLine("NETRESOURCE Comment: " & resource.lpComment)
Debug.WriteLine("NETRESOURCE Provider: " & resource.lpProvider)
End Sub
Public Enum ErrorCodes
NO_ERROR = 0
ERROR_NO_MORE_ITEMS = 259
End Enum
<StructLayout(LayoutKind.Sequential)>
Public Class NETRESOURCE
Public dwScope As ResourceScope
Public dwType As ResourceType
Public dwDisplayType As ResourceDisplayType
Public dwUsage As ResourceUsage
<MarshalAs(UnmanagedType.LPWStr, SizeConst:=64)>
Public lpLocalName As String
<MarshalAs(UnmanagedType.LPWStr, SizeConst:=64)>
Public lpRemoteName As String
<MarshalAs(UnmanagedType.LPWStr, SizeConst:=64)>
Public lpComment As String
<MarshalAs(UnmanagedType.LPWStr, SizeConst:=64)>
Public lpProvider As String
'This is defined as a class rather than a structure, so it's only appropriate for passing (by-value) when a pointer to a structure is needed.
'Class vs Structure is not a problem, if you changed it to Structure the WNetOpenEnum declaration would need a ByRef NETRESOURCE parameter.
End Class
Public Enum ResourceScope
CONNECTED = 1
GLOBALNET
REMEMBERED
RECENT
CONTEXT
End Enum
Public Enum ResourceType
ANY
DISK
PRINT
RESERVED
End Enum
Public Enum ResourceUsage
CONNECTABLE = &H1
CONTAINER = &H2
NOLOCALDEVICE = &H4
SIBLING = &H8
ATTACHED = &H10
ALL = CONNECTABLE Or CONTAINER Or ATTACHED
End Enum
Public Enum ResourceDisplayType
GENERIC
DOMAIN
SERVER
SHARE
FILE
GROUP
NETWORK
ROOT
SHAREADMIN
DIRECTORY
TREE
NDSCONTAINER
End Enum
Public Declare Auto Function WNetAddConnection2 Lib "Mpr.dll" (ByRef lpNetResource As NETRESOURCE, lpPassword As String, lpUserName As String, dwFlags As Integer) As Integer
Public Declare Auto Function WNetCancelConnection2 Lib "Mpr.dll" (lpName As String, dwFlags As Integer, fForce As Integer) As Integer
Public Declare Auto Function WNetOpenEnum Lib "Mpr.dll" (dwScope As ResourceScope, dwType As ResourceType, dwUsage As ResourceUsage, p As NETRESOURCE, <Out> ByRef lphEnum As IntPtr) As ErrorCodes
Public Declare Auto Function WNetCloseEnum Lib "Mpr.dll" (hEnum As IntPtr) As ErrorCodes
Public Declare Auto Function WNetEnumResource Lib "Mpr.dll" (hEnum As IntPtr, ByRef lpcCount As Integer, buffer As IntPtr, ByRef lpBufferSize As UInteger) As ErrorCodes
End Class
End Class
Last edited: