Using Network Resources

The preceding section explained how to connect and disconnect from a network resource. However, it can be somewhat difficult to establish a connection to a resource without explicit knowledge of its location, or what is currently available. Fortunately, the WNet APIs provide several functions that enable you to enumerate network resources, as well as to query them for additional information.

Enumerating Network Resources

Enumerating available network resources is similar to enumerating files or Internet cache entries you must first open the enumeration and get a handle, "walk" each item of the enumeration, and finish by closing the enumeration handle.

The first step in enumerating either available network resources or items that you have already mapped to your device is accomplished by calling the WNetOpenEnum() function:

 DWORD WNetOpenEnum(DWORD dwScope, DWORD dwType, DWORD   dwUsage, LPNETRESOURCEW lpNetResource, LPHANDLE lphEnum); 

The first parameter, dwScope, defines the scope of network-connected resources you want to enumerate, and can be one of the values in Table 4.6.

Table 4.6. Network Resource Scope Flags

Flag

Description

RESOURCE_CONNECTED

Return only the currently connected resources

RESOURCE_GLOBALNET

Return all resources on the network

RESOURCE_REMEMBERED

Return network connections that have been marked as persistent whether they are connected or not

The dwType parameter specifies what types of network resources you want to view in your enumeration (see Table 4.7).

Table 4.7. Network Resource Types

Flag

Description

RESOURCETYPE_ANY

Enumerate all network resources

RESOURCETYPE_DISK

Enumerate disk resources

RESOURCETYPE_PRINT

Enumerate print resources

The next parameter, dwUsage, further defines the enumeration scope by how it is being used. If the dwScope parameter is not set to RESOURCE_GLOBALNET, then this parameter must be set to 0; otherwise, it can be one of the flags listed in Table 4.8.

Table 4.8. Network Resource Usage Types

Flag

Description

0

All resources

RESOURCEUSAGE_CONNECTABLE

All connectable resources (such as shares)

RESOURCEUSAGE_CONTAINER

All server resources

The lpNetResource parameter is used to define the starting point for an enumeration. It should contain a pointer to a NETRESOURCE structure, as long as the dwScope parameter is set to RESOURCE_GLOBALNET; otherwise, it should be set to NULL. To correctly start an enumeration, you must also set the NETRESOURCE structure's lpRemoteName field to the root of the server you want to enumerate, and set its dwUsage member to RESOURCEUSAGE_CONTAINER:

 NETRESOURCE netResource; memset(&netResource, 0, sizeof(NETRESOURCE)); netResource.lpRemoteName = TEXT("\\\\LONDO"); netResource.dwUsage = RESOURCEUSAGE_CONTAINER; netResource.dwScope = RESOURCE_GLOBALNET; 

The last parameter, lphEnum, is a pointer to a handle for your enumeration. If your call to WNetOpenEnum() is successful, then the function will return an ERROR_SUCCESS return value.

Once you have successfully returned an enumeration handle, you can begin the actual enumeration of network resources by using the WNetEnumResource() function, which is defined as follows:

 DWORD WNetEnumResource(HANDLE hEnum, LPDWORD lpcCount,    LPVOID lpBuffer, LPDWORD lpBufferSize); 

The first parameter you use with WNetEnumResource() is the handle to the enumeration that you received from your previous call to WNetOpenEnum(). Next, lpcCount is a pointer to a DWORD value that specifies the number of items you are requesting. To get as many items as possible, you can set this to 0xFFFFFFFF. When the function returns, the variable to which lpcCount is pointing will contain the actual number of items that were returned. Next, the lpBuffer parameter should point to a buffer that contains the array of NETRESOURCE structures for each returned resource. The final parameter, lpBufferSize, should point to a DWORD value specifying the size, in bytes, of the buffer you pointed to with the lpBuffer parameter.

When the function returns, if you were able to successfully enumerate the network resources, you will receive an ERROR_SUCCESS return value. Your application should keep calling the WNetOpenEnum() function until you get ERROR_NO_MORE_ITEMS as a return value, which specifies that there are no more resources to enumerate. An error of ERROR_MORE_DATA indicates that there is still additional enumeration information.

You can use three different techniques to enumerate network resources:

  1. Specify a large buffer and attempt to get all the network enumerations in as a single call. You can allocate a large buffer (around 16KB), and pass 0xFFFFFFFF as the lpcCount value. Setting the lpcCount to this results in an attempt to get all of the network resources at once:

     DWORD dwReturn = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,    0, &netResource, &hNetEnum); // Allocate a large buffer, and get the resources in one shot DWORD dwNumEnum = 0xFFFFFFFF; NETRESOURCE netResources[15]; DWORD dwBufferSize = sizeof(NETRESOURCE)*15; // Make the enum call dwReturn = WNetEnumResource(hNetEnum, &dwNumEnum,    &netResources, &dwBufferSize); if(dwReturn == ERROR_SUCCESS) {    for(DWORD dwEnum = 0; dwEnum < dwNumEnum; dwEnum++) {       // Walk through the enumerated resources       MessageBox(NULL, netResources[dwEnum].lpRemoteName,          TEXT("Resource"), MB_OK);    } } WNetCloseEnum(hNetEnum); 
  2. Call WNetEnumResource() multiple times. The second option is to call WNetEnumResource() and pass in a relatively small buffer for the NETRESOURCE array. When the function returns, you need to create a loop until you receive a return code of ERROR_NO_MORE_ITEMS:

     DWORD dwNumEnum = 1; NETRESOURCE *pNetResource = NULL; // Allocate a small buffer pNetResource = (NETRESOURCE *)LocalAlloc(LPTR, sizeof(NETRESOURCE)); DWORD dwBufferSize = sizeof(NETRESOURCE); BOOL fContinue = TRUE; do {    // Make the enum call    DWORD dwReturn = WNetEnumResource(hNetEnum, &dwNumEnum,       pNetResource, &dwBufferSize);    // Was the buffer large enough?    if(dwReturn == ERROR_MORE_DATA) {       LocalFree(pNetResource);       pNetResource = (NETRESOURCE *)LocalAlloc(LPTR, dwBufferSize);       // Call again       dwReturn = WNetEnumResource(hNetEnum, &dwNumEnum,          pNetResource, &dwBufferSize);    }       if(dwReturn == ERROR_SUCCESS)          MessageBox(NULL, pNetResource->lpRemoteName,             TEXT("Resource"), MB_OK);       if(dwReturn == ERROR_NO_MORE_ITEMS)       fContinue = FALSE; } while(fContinue); LocalFree(pNetResource); WNetCloseEnum(hNetEnum); 
  3. Determine the size of the network resource buffer, and then call WNetEnumResource() again to get the actual data. Another option is to call the WNetEnumResource() function and pass a NULL value for the lpBuffer parameter. When the function returns, the size required for the resource array will be placed in the lpBufferSize parameter.

To end the resource enumeration, just call the WNetCloseEnum() function:

 DWORD WNetCloseEnum(HANDLE hEnum); 

WNetCloseEnum() takes a single parameter, which is the handle to the enumeration that you received in your initial call to WNetOpenEnum().

Getting Network Resource Information

In addition to the network enumeration functions, the WNet API also has some functions for obtaining information about network connections.

To find out the UNC path of a mapped drive that is currently connected, you can call the following function:

 DWORD WNetGetConnection(LPCWSTR lpLocalName, LPWSTR    lpRemoteName, LPDWORD lpnLength); 

The first parameter, lpLocalName, is a pointer to a null-terminated string that contains the local name of the mapped network resource. The next parameter, lpRemoteName, points to a buffer that will get the UNC network path for the locally mapped resource. Finally, lpnLength points to a DWORD value that specifies the size of the buffer pointed to with the lpRemoteName parameter. If the buffer is not large enough, the required size will be stored here, as shown in the following example:

 TCHAR tchRemoteName[1024] = TEXT("\0"); DWORD dwBufferSize = 1024; dwReturn = WNetGetConnection(TEXT("NetBackup"),   tchRemoteName, &dwBufferSize); 

The WNetGetUniversalName() function gets the full UNC path (i.e., \\ServerName\Sharename) to any mapped resource, regardless of its current connection status. The parameters you pass in will determine the UNC format that is returned.

The WNetGetUniversalName() function is prototyped as follows:

 DWORD WNetGetUniversalName(LPCWSTR lpLocalPath, DWORD    dwInfoLevel, LPVOID lpBuffer, LPDWORD lpBufferSize); 

You first need to pass in the full path as a null-terminated string for a network resource that is mapped into the \Network folder. The next parameter, dwInfoLevel, determines the type of buffer returned from the function, and can be set to either UNIVERSAL_NAME_INFO_LEVEL or REMOTE_NAME_INFO_LEVEL.

Setting the dwInfoLevel flag to UNIVERSAL_NAME_INFO_LEVEL will return a UNIVERSAL_NAME_INFO structure, which looks like the following:

 typedef struct _UNIVERSAL_NAME_INFO {    LPWSTR lpUniversalName; }UNIVERSAL_NAME_INFO, *LPUNIVERSAL_NAME_INFO; 

The structure simply contains the UNC path to the file that you specified by lpLocalPath.

When calling WNetGetUniversalName(), if you set the dwInfoLevel flag to REMOTE_NAME_INFO_LEVEL (instead of UNIVERSAL_NAME_INFO_LEVEL), you will be returned a REMOTE_NAME_INFO structure. It is defined as follows:

 typedef struct _REMOTE_NAME_INFO {    LPWSTR lpUniversalName;    LPWSTR lpConnectionName;    LPWSTR lpRemainingPath; }REMOTE_NAME_INFO, *LPREMOTE_NAME_INFO; 

The first field, lpUniversalName, points to the full UNC path of the file that was specified in lpLocalPath (and is the same as the lpUniversalName member of the UNIVERSAL_NAME_INFO structure). The next two strings contain a parsed UNC path, which is already divided into the share name and the path of the file. The lpConnectionName member contains the share, and lpRemainingPath has the UNC name to the file.

The last parameter, lpBufferSize, should point to a DWORD value that specifies the size of the buffer passed in the lpBuffer parameter. If the buffer is too small, this value will contain the size that is needed when the function returns.

To get the username that was used to authenticate a remote network resource, WNet provides the WNetGetUser() function:

 DWORD WNetGetUser(LPCWSTR lpName, LPWSTR lpUserName, LPDWORD   lpnLength); 

The first parameter is a null-terminated string that contains the local name of the mapped network resource. This is followed by lpUserName, which is a buffer that receives the network resource logon name. Finally, lpnLength should point to a DWORD value that contains the size of the buffer used in the lpUserName parameter. If the buffer is too small, it will contain the size needed for the buffer when the function returns.

Working with Files

Working with files that are located on the network is essentially the same as if they were located inside the device's object store. For example, if you wanted to enumerate all of the files on a network-mapped share, you could just use the file system functions FindFirstFile() and FindNextFile():

 HANDLE hFileEnum = NULL; WIN32_FIND_DATA w32Find; BOOL fContinue = TRUE; memset(&w32Find, 0, sizeof(WIN32_FIND_DATA)); SetLastError(0); hFileEnum = FindFirstFile(TEXT("\\NETWORK\\NetBackup\\*.*"),    &w32Find); if(hFileEnum == INVALID_HANDLE_VALUE) {    DWORD dwError = GetLastError();    return FALSE; } do {    MessageBox(NULL, w32Find.cFileName, TEXT("File Enum"), MB_OK);    // Get the next item    if((FindNextFile(hFileEnum, &w32Find)) != 0) {       if(GetLastError() == ERROR_NO_MORE_FILES)          fContinue = FALSE;     } } while(fContinue); FindClose(hFileEnum); 

Copying a file to the network is just as easy using the CopyFile() function:

 TCHAR tchSource[MAX_PATH] = TEXT("\\TestFile.txt"); TCHAR tchDest[MAX_PATH] =    TEXT("\\NETWORK\\NetBackup\\TestFile.txt"); CopyFile(tchSource, tchDest, TRUE); 

Printing on the Network

Finding and using a printer on the network follows the same process as enumerating or connecting to a drive share. However, you must specify that you are looking for printers when calling the WNetOpenEnum() function by setting the dwType parameter to RESOURCETYPE_PRINT.

For example, if you wanted to enumerate all of the printer resources that were being made available by a particular server (in this case, "\\\\LONDO"), you could do the following:

 HANDLE hNetEnum = NULL; NETRESOURCE netResource; memset(&netResource, 0, sizeof(NETRESOURCE)); netResource.lpRemoteName = TEXT("\\\\LONDO"); netResource.dwUsage = RESOURCEUSAGE_CONTAINER; DWORD dwReturn = WNetOpenEnum(RESOURCE_GLOBALNET,    RESOURCETYPE_PRINT, 0, &netResource, &hNetEnum); // Allocate a large buffer, and get the printers in one shot DWORD dwNumEnum = 0xFFFFFFFF; NETRESOURCE netResources[3]; DWORD dwBufferSize = sizeof(NETRESOURCE)*3; // Make the enum call dwReturn = WNetEnumResource(hNetEnum, &dwNumEnum, &netResources,    &dwBufferSize); if(dwReturn == ERROR_SUCCESS) {    for(DWORD dwEnum = 0; dwEnum < dwNumEnum; dwEnum++) {        // Walk through the enumerated resources        MessageBox(NULL, netResources[dwEnum].lpRemoteName,    TEXT("Printers"), MB_OK);    } } WNetCloseEnum(hNetEnum); 

Once you have found a printer you want to use, you have two printing methods from which to choose. One, you can simply call the CopyFile() function, and pass in the UNC name for the printer as the destination for the file, as shown in the following example:

 TCHAR tchPrintFile[MAX_PATH] = TEXT("\\My   Documents\\Channels\\SamplePrint.txt"); TCHAR tchPrinter[MAX_PATH] = TEXT("\\\\LONDO\\Deskjet"); CopyFile(tchPrintFile, tchPrinter, FALSE); 

Alternately, you can use the CreateFile(), WriteFile(), and CloseHandle() functions. This method gives you more direct control over the buffers that are sent to the printer. Sending a file to the printer in this manner can be accomplished as follows:

 TCHAR tchPrintFile[MAX_PATH] = TEXT("\\My   Documents\\Channels\\SamplePrint.txt"); TCHAR tchPrinter[MAX_PATH] = TEXT("\\\\LONDO\\Deskjet"); // Create the print job HANDLE hPrintJob = NULL; hPrintJob = CreateFile(tchPrinter, GENERIC_WRITE, 0, NULL,   CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); // Open the file HANDLE hFile = NULL; LPVOID lpBuffer = NULL; DWORD dwRead = 0, dwWritten = 0; hFile = CreateFile(tchPrintFile, GENERIC_READ, 0, NULL,    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); lpBuffer = LocalAlloc(LPTR, 1024); do {    ReadFile(hFile, lpBuffer, 1024, &dwRead, NULL);    if(dwRead > 0) {       // Send the buffer to the printer       WriteFile(hPrintJob, lpBuffer, dwRead, &dwWritten, NULL);    } } while(dwRead > 0); CloseHandle(hFile); CloseHandle(hPrintJob); LocalFree(lpBuffer); 

Note that the Pocket PC has no real knowledge of the printer, printer resources, or the printer queue. It is basically sending a raw file dump of data to the network resource, so you are limited to printing only text files in this manner.



Pocket PC Network Programming
Pocket PC Network Programming
ISBN: 0321133528
EAN: 2147483647
Year: 2005
Pages: 90

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net