Microsoft's wnet functions can search for and access Shared Resources on the local network, and map folders to local network drives.
The following is a summary of the usage and attention of the function. The first is to enumerate the entire network, and the local network is divided into Microsoft Terminal Service, microsfot Windows Network, and Web Client Network.
During enumeration, the sub-classes under these three types of networks will be searched separately. Microsfot windows network contains multiple workgroups and domains. Each Workgroup, region, and Shared Server are a node, but their types are different.
The msdn code shows the basic function of enumerating all nodes:
Bool winapi enumeratefunc (hwnd,
HDC,
Lpnetresource lpnr)
{
DWORD dwresult, dwresultenum;
Handle henum;
DWORD cbbuffer = 16384; // 16 K is a good size
DWORD centries =-1; // enumerate all possible entries
Lpnetresource lpnrlocal; // pointer to enumerated Structures
Dword I;
//
// Call the wnetopenenum function to begin the enumeration.
//
Dwresult = wnetopenenum (resource_globalnet, // All Network Resources
Resourcetype_any, // all resources
0, // enumerate all resources
Lpnr, // null first time the function is called
& Henum); // handle to the Resource
If (dwresult! = No_error)
{
//
// Process errors with an application-defined error handler.
//
Neterrorhandler (hwnd, dwresult, (lpstr) "wnetopenenum ");
Return false;
}
//
// Call the globalalloc function to allocate resources.
//
Lpnrlocal = (lpnetresource) globalalloc (gptr, cbbuffer );
If (lpnrlocal = NULL)
Return false;
Do
{
//
// Initialize the buffer.
//
Zeromemory (lpnrlocal, cbbuffer );
//
// Call the wnetenumresource function to continue
// The enumeration.
//
Dwresultenum = wnetenumresource (henum, // resource handle
& Centries, // defined locally as-1
Lpnrlocal, // lpnetresource
& Cbbuffer); // buffer size
//
// If the call succeeds, loop through the structures.
//
If (dwresultenum = no_error)
{
For (I = 0; I <centries; I ++)
{
// Call an application-defined function
// Display the contents of the netresource structures.
//
Displaystruct (HDC, & lpnrlocal [I]);
// If the netresource structure represents a container resource,
// Call the enumeratefunc function recursively.
If (resourceusage_container = (lpnrlocal [I]. dwusage
& Resourceusage_container ))
If (! Enumeratefunc (hwnd, HDC, & lpnrlocal [I])
Textout (HDC, 10, 10, "enumeratefunc returned false.", 29 );
}
}
// Process errors.
//
Else if (dwresultenum! = Error_no_more_items)
{
Neterrorhandler (hwnd, dwresultenum, (lpstr) "wnetenumresource ");
Break;
}
}
//
// End do.
//
While (dwresultenum! = Error_no_more_items );
//
// Call the globalfree function to free the memory.
//
Globalfree (hglobal) lpnrlocal );
//
// Call wnetcloseenum to end the enumeration.
//
Dwresult = wnetcloseenum (henum );
If (dwresult! = No_error)
{
//
// Process errors.
//
Neterrorhandler (hwnd, dwresult, (lpstr) "wnetcloseenum ");
Return false;
}
Return true;
}
The function recursively traverses the shared resources of all the shared servers under the workgroup and domain. However, this code needs to be improved in two ways. wnetopenenum is used to open a node. for Working Groups, authentication is not required, but for shared servers such as samba servers, if you open it directly, it will cause a failure. Samba must be authenticated. At this time, you can call another function connectwnetresource to pass the authentication. The Code is also from msdn:
DWORD connectwnetresource (lpnetresource lpnr, ptchar szusername, ptchar szpassword)
{
DWORD dwresult;
//
// Call the wnetaddconnection2 function to make the connection,
// Specifying a persistent connection.
//
Dwresult = wnetaddconnection2 (lpnr, // netresource from Enumeration
(Lpwstr) szpassword, // No Password
(Lpwstr) szusername, // logged-in user
Connect_update_profile); // Update Profile with connect information
// Process errors.
// The local device is already connected to a network resource.
//
If (dwresult = error_already_assigned)
{
Return false;
}
// An entry for the local device already exists in the user profile.
//
Else if (dwresult = error_device_already_remembered)
{
Return false;
}
Else if (dwresult! = No_error)
{
Return false;
}
//
// Otherwise, report a successful connection.
//
Return 0;
}
Wnetaddconnection2 is used to connect to a specified server or shared resource that requires authentication. The first parameter specifies the location and type of the shared resource, the specific content is not detailed, the focus is that the location of the Shared Server can be registered with its name, such as \ XX-PC to represent, you can also specify it with its \ + IP address. It is worth noting that the third parameter dwflag must be set to connect_update_profile so that the local system can cache this authentication information so that subsequent access operations do not repeat the authentication.
In this case, the above Code should be modified to the following:
Dwresult = wnetopenenum (resource_globalnet, // All Network Resources
Resourcetype_any, // all resources
Resourceusage_all, // enumerate all resources
Lpnr, // null first time the function is called
& Henum); // handle to the Resource
If (dwresult! = No_error)
{
//
// Process errors with an application-defined error handler.
//
// Neterrorhandler (hwnd, dwresult, (lpwstr) _ T ("wnetopenenum "));
If (dwresult = error_access_denied ){
If (connectwnetresource (lpnr, user, PWD) = false)
Return false;
Dwresult = wnetopenenum (resource_globalnet, // All Network Resources
Resourcetype_any, // all resources
Resourceusage_all, // enumerate all resources
Lpnr, // null first time the function is called
& Henum); // handle to the Resource
If (dwresult! = No_error ){
Return false;
}
} Else {
Return false;
}
}
After traversing a working group or domain, wnetenumresource is called to obtain all the shared servers under it. The first parameter is the handle obtained by wnetopenenum, the second parameter returns the total number of shared servers. The third parameter returns an array of the lpnetresource struct. Each element corresponds to a server. Now let's take a look at the specific content of this struct:
Typedef struct _ netresourcew {
DWORD dwscope;
DWORD dwtype;
DWORD dwdisplaytype;
DWORD dwusage;
Lpwstr lplocalname;
Lpwstr lpremotename;
Lpwstr lpcomment;
Lpwstr lpprovider;
} Netresourcew, * lpnetresourcew;
Dwdisplaytype indicates the type of the node, which can be a server or domain, a working group or a folder. Dwtype indicates the shared type, printer, or disk. Dwusage indicates whether the node can be mapped or a container. Folders can be mapped, while servers, domains, and working groups are both containers and cannot be mapped.
For a server-type node, lpremotename indicates the name of the server. Note that this name is a unique name that identifies the computer on the network. If needed, you can use getaddrinfo to resolve the network name to the IP address of the computer. For folder-type nodes, it indicates the specific path of the folder.
If you need to map a folder to a local network disk, you must set the lplocalname in the format of X:, indicating that you want to map the folder to a local Z disk. The implemented functions are roughly as follows:
DWORD winapi assigningdrivetoshare (lpnetresource lpnr, ptchar szusername, ptchar szpassword, ptchar szlocalname)
{
// Lpnr-> dwtype = resourcetype_any;
Lpnr-> lplocalname = szlocalname;
Lpnr-> lpprovider = NULL;
//
// Call the wnetaddconnection2 function to assign
// A drive letter to the share.
//
/// Tmp/Disk/app_path
DWORD res = wnetaddconnection2 (lpnr, szpassword, szusername, connect_update_profile );
//
// If the call succeeds, inform the user; otherwise,
// Print the error.
//
If (RES = no_error ){
// Tchar buffer [max_path];
//: Wsprintf (buffer, _ T ("connection added % s \ n"), lpnr-> lpremotename );
// MessageBox (null, buffer, 0, 0 );
}
Else {
If (RES = error_session_credential_conflict ){
Return-1;
}
Return 0;
}
In fact, wnetaddconnection2 is called. Note that if the returned error code is error_session_credential_conflict, you may have opened the mapped directory manually. In this case, the ing operation fails.
The final point is to find the resources you need through this enumeration method. The intermediate process is relatively slow. If you already know the IP address of a specific server, you can set lpremotename to an IP address in string format. The specific configuration is as follows:
Nrlocal. dwdisplaytype = resourcedisplaytype_server;
Nrlocal. dwscope = resource_globalnet;
Nrlocal. dwtype = resourcetype_any;
Nrlocal. dwusage = resourceusage_container;
Nrlocal. lpcomment = NULL;
Nrlocal. lplocalname = NULL;
Nrlocal. lpremotename = remotename;
Nrlocal. lpprovider = NULL;
You can call enumeratefunc to directly return all the shared folders under the server, and then map any or Multiple folders to the local disk.