Once you know how to determine the resources on a network, the next stage is to make a connection. Once a connection is made, the resource can be accessed through the entry in the \network directory in the Object Store. When making a connection you must specify the resource's UNC (such as "\\myserver\myresource") and a local name (such as "mylocal"). Once the connection is made, the local name can be used to access resources (such as "\network\mylocal\myfile.txt"). Unlike Windows 98/NT/2000, remembered connections are not reestablished automatically in Windows CE when the device is next powered-on. You can, however, find out about remembered connections by accessing the "\HKEY_Local_Machine\Comm\redir\connections" key in the registry (see Chapter 4 for information on accessing the registry). Listing 3.8 shows how to call WNetAddConnection3 to make a connection by specifying the UNC and local name. Listing 3.8 Adds a network connectionvoid Listing3_8() { TCHAR szUNCPath[MAX_PATH + 1]; TCHAR szLocalName[MAX_PATH + 1]; NETRESOURCE nr; if(!GetTextResponse(_T("Enter UNC to Connect to:"), szUNCPath, MAX_PATH)) return; if(!GetTextResponse(_T("Enter Local Name:"), szLocalName, MAX_PATH)) return; nr.dwType = RESOURCETYPE_DISK; nr.lpRemoteName = szUNCPath; nr.lpLocalName = szLocalName; // Microsoft Network is only provider nr.lpProvider = NULL; if(WNetAddConnection3(hWnd, &nr, NULL, NULL, CONNECT_UPDATE_PROFILE) != NO_ERROR) cout _T("Error adding connection: ") GetLastError() endl; } The WNetAddConnection3 function is passed a NETRESOURCE structure initialized with the type of resource to connect (RESOURCETYPE_DISK), and strings containing the UNC and the local name. The provider name must be set to NULL, since only Microsoft networks are supported. WNetAddConnection3 ignores the other NETRESOURCE members.
In Listing 3.8 the Password and Username parameters in WNetAddConnection3 are passed NULL values, indicating that the default user name and password will be used. The last parameter is passed CONNECT_UPDATE_PROFILE, which causes the registry to be updated to store the UNC and local name for the connection. Listing 3.9 shows how to disconnect from a network connection. The function prompts the user for the local or UNC name of the connection to be broken, and a call is made to WNetCancelConnection2. Listing 3.9 Disconnects a network connectionvoid Listing3_9() { TCHAR szPath[MAX_PATH + 1]; if(!GetTextResponse( _T("Enter UNC or Local Name to disconnect:"), szPath, MAX_PATH)) return; if(WNetCancelConnection2(szPath, CONNECT_UPDATE_PROFILE, TRUE) != ERROR_SUCCESS ) cout _T("Error disconnecting: ") GetLastError(); }
Adding and Canceling Connections With DialogsThe WNetConnectionDialog1 function can be used to prompt the user with a dialog for the UNC and local name, and then to make a connection using the supplied information. The dialog displayed by Windows CE is not particularly friendly, since it does not allow browsing. Listing 3.10 shows how the dialog can be displayed and a connection made. Listing 3.10 Adds a network connection using a dialog boxvoid Listing3_10() { CONNECTDLGSTRUCT cs; DWORD dwResult; NETRESOURCE nr; nr.dwType = RESOURCETYPE_DISK; nr.lpRemoteName = NULL; nr.lpLocalName = NULL; nr.lpProvider = NULL; cs.cbStructure = sizeof(cs); cs.hwndOwner = hWnd; cs.lpConnRes = &nr; cs.dwFlags = 0; dwResult = WNetConnectionDialog1(&cs); if(dwResult == 0xFFFFFFFF) cout _T("User cancelled") endl; else if(dwResult != WN_SUCCESS) cout _T("Error connecting: ") dwResult endl; } Two structures must be initialized. The NETRESOURCE structure specifies the type of connection to make. The CONNECTDLGSTRUCT structure points to the NETRESOURCE structure, and also specifies the handle of the window that will own the connection dialog.
The WNetDisconnectDialog function displays a list of all connections and allows the user to select one for disconnection. Listing 3.11 shows a call to this function. Listing 3.11 Disconnects a network connection using a dialog boxvoid Listing3_11() { DWORD dwResult; dwResult = WNetDisconnectDialog(hWnd, 0); if(dwResult == 0xFFFFFFFF) cout _T("User cancelled dialog") endl; else if(dwResult != NO_ERROR) cout _T("Error disconnecting: ") GetLastError(); }
The WNetDisconnectDialog1 function gives you more control over the disconnection, such as allowing the disconnection even if resources are being used. This function is passed a DISCDLGSTRUCT structure, and is described in the next section. Using Network PrintersWindows CE provides default support for PCL (Printer Control Language) printers. This support includes using printers located on a network. Connections can be made to network printers using the WNetAddConnection3 function. The local name results in an entry being made in the \network directory in the Object Store. Listing 3.12 shows how to map a printer to a local name. Listing 3.12 Maps a printer to a local namevoid Listing3_12() { TCHAR szUNCPath[MAX_PATH + 1], szLocal[MAX_PATH + 1]; NETRESOURCE nr; if(!GetTextResponse( _T("Enter Printer UNC to Connect to:"), szUNCPath, MAX_PATH)) return; if(!GetTextResponse( _T("Enter Local name for printer:"), szLocal, MAX_PATH)) return; nr.dwType = RESOURCETYPE_PRINT; nr.lpRemoteName = szUNCPath; nr.lpLocalName = szLocal; // Microsoft Network is only provider nr.lpProvider = NULL; if(WNetAddConnection3(hWnd, &nr, NULL, NULL, CONNECT_UPDATE_PROFILE) != NO_ERROR) cout _T("Error adding Printer connection: ") GetLastError() endl; } Once mapped, the local name can be used to specify a network printer. For example, if the shared printer "\\myserver\myprinter" is mapped tothe local name "PCLPrint", the printer can be referenced by the name "\network\PCLPrint". Listing 3.13 shows how to disconnect from a network printer resource using the function WNetDisconnectDialog1. Listing 3.13 Disconnects from network printervoid Listing3_13() { DWORD dwResult; DISCDLGSTRUCT ds; TCHAR szUNCPath[MAX_PATH + 1]; if(!GetTextResponse( _T("Enter Printer UNC to disconnect from:"), szUNCPath, MAX_PATH)) return; ds.cbStructure = sizeof(ds); ds.hwndOwner = hWnd; ds.lpLocalName = NULL; ds.lpRemoteName = szUNCPath; ds.dwFlags = DISC_NO_FORCE ; dwResult = WNetDisconnectDialog1(&ds); if(dwResult != NO_ERROR) cout _T("Error disconnecting: ") GetLastError(); } The DISCDLGSTRUCT is initialized to specify the UNC of the printer from which to disconnect. A dialog will only be displayed if an error occurs, and the owner window handle is provided. The connection will not be broken if the printer is currently in use since the DISC_NO_FORCE flag isused.
Getting User NamesYou can retrieve the current user's name or the name used to connect to any network resource using the WNetGetUser function as shown in Listing 3.14. Listing 3.14 Lists security details for network connectionvoid Listing3_14() { DWORD dwLen = 50; TCHAR szConnection[MAX_PATH + 1]; TCHAR szUser[51]; if(!GetTextResponse(_T("Enter connection to list:"), szConnection, MAX_PATH)) return; if(WNetGetUser(szConnection, szUser, &dwLen) != ERROR_SUCCESS) cout _T("Error getting user information: ") GetLastError() endl; else cout szConnection _T("connected as user ") szUser endl; }
If you pass zero or NULL in for the localName parameter, the function returns the name of the current user. If you pass in a device name, the function returns the name used to attach to the device when WNetAddConnection3 was called. The function returns an error code, or you can retrieve the error code with GetLastError. Listing Current ConnectionsListing 3.15 uses FindFirstFile and FindNextFile to iterate through the local connection names in the \network directory. These entries represent the active connections, and WNetGetConnection is used to determine the UNC to which the local name refers. This code will only show the active connections, since Windows CE will not automatically reestablish the remembered connections. You can write code to list the remembered connections by listing the registry entries under the key "\HKEY_Local_Machine\Comm\redir\connections" (see Chapter 4). Listing 3.15 Lists current connectionsvoid PrintConnectionData(WIN32_FIND_DATA* lpFD) { TCHAR szRemoteName[MAX_PATH + 1]; DWORD dwSize = MAX_PATH; cout _T("Connection: ") lpFD->cFileName; if(WNetGetConnection(lpFD->cFileName, szRemoteName, &dwSize) == NO_ERROR) cout _T(" to ") szRemoteName endl; else if(GetLastError() == ERROR_CONNECTION_UNAVAIL) cout _T(" not currently connected."); else cout _T(" Error calling WNetGetConnection ") GetLastError() endl; } void Listing3_15() { HANDLE hFindFile; WIN32_FIND_DATA fdData; // get first file hFindFile = FindFirstFile( _T("\\network\\*.*"), &fdData); if(hFindFile != INVALID_HANDLE_VALUE) { PrintConnectionData(&fdData); while(FindNextFile(hFindFile, &fdData)) { PrintFindData(&fdData); } FindClose(hFindFile); } else if(GetLastError() == ERROR_NO_MORE_FILES) cout _T("No shares"); else cout _T("Call to FindFirstFile failed: ") GetLastError(); } The function WNetGetConnection is passed the local file name (in lpFD->cFilename), and returns the UNC name in a character buffer.
|