|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
nwshui.cxx
Abstract:
This module implements the context menu actions of shell extension classes.
Author:
Yi-Hsin Sung (yihsins) 25-Oct-1995
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <commctrl.h>
#include <shellapi.h>
#include <shlobj.h>
#define DONT_WANT_SHELLDEBUG
#include <shlobjp.h>
#include <winnetwk.h>
#include <npapi.h>
#include <ntddnwfs.h>
#include <ndsapi32.h>
#include <nwapi.h>
#include <nwwks.h>
#include <nwmisc.h>
//extern "C"
//{
#include "nwutil.h"
//}
#include "nwshcmn.h"
#include "nwshrc.h"
extern "C" { NTSTATUS NwNdsOpenRdrHandle( OUT PHANDLE phandleRdr ); }
#define MAX_ONE_CONN_INFORMATION_SIZE 512
#define NW_ENUM_EXTRA_BYTES 256
#define GLOBAL_WHOAMI_REFRESH_INTERVAL 30000 // in milliseconds, Win95 uses 10000
DWORD LogoutFromServer( LPWSTR pszServer, PBOOL pfDisconnected );
INT_PTR CALLBACK GlobalWhoAmIDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
VOID GetConnectionStatusString( PCONN_STATUS pConnStatus, LPBYTE Buffer, DWORD nSize );
HRESULT NWUIWhoAmI( HWND hParent, LPNETRESOURCE pNetRes ) { DWORD err = NO_ERROR; DWORD_PTR ResumeKey = 0; LPBYTE pBuffer = NULL; DWORD EntriesRead = 0; DWORD dwMessageId; WCHAR szUserName[MAX_PATH+1] = L""; WCHAR szConnType[128]; WCHAR szRemoteName[MAX_PATH + 1];
szConnType[0] = 0;
if ( pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER ) { // Need to extract the server name from full UNC path
NwExtractServerName( pNetRes->lpRemoteName, szRemoteName ); dwMessageId = IDS_MESSAGE_NOT_ATTACHED; } else // NDS container name
{ // Need to extract the tree name from the full UNC path
szRemoteName[0] = TREECHAR; NwExtractTreeName( pNetRes->lpRemoteName, szRemoteName+1); dwMessageId = IDS_MESSAGE_NOT_ATTACHED_TO_TREE; }
err = NwGetConnectionStatus( szRemoteName, &ResumeKey, &pBuffer, &EntriesRead );
if ( err == NO_ERROR && EntriesRead > 0 ) // For trees, we'll get more than one entry
{ PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer; LPWSTR pszStart = szConnType; DWORD nSize = sizeof(szConnType)/sizeof(WCHAR);
if ( EntriesRead > 1 && szRemoteName[0] == TREECHAR ) { // If there is more than one entry for trees,
// then we need to find one entry where username is not null
// and the login type is NDS.
// If we cannot find one, then just use the first one.
DWORD i; PCONN_STATUS pConnStatusTmp = pConnStatus; PCONN_STATUS pConnStatusUser = NULL; PCONN_STATUS pConnStatusNoUser = NULL;
for ( i = 0; i < EntriesRead ; i++ ) { if ( pConnStatusTmp->fNds ) { pConnStatusNoUser = pConnStatusTmp;
if ( ( pConnStatusTmp->pszUserName != NULL ) && ( ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE ) || ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED ) ) ) { // Found it
pConnStatusUser = pConnStatusTmp; break; } }
// Continue with the next item
pConnStatusTmp = (PCONN_STATUS) ( (DWORD_PTR) pConnStatusTmp + pConnStatusTmp->dwTotalLength); }
if ( pConnStatusUser ) // found one nds entry with a user name
pConnStatus = pConnStatusUser; else if ( pConnStatusNoUser ) // use an nds entry with no user name
pConnStatus = pConnStatusNoUser; // else use the first entry
}
if ( szRemoteName[0] == TREECHAR // A tree
|| !pConnStatus->fPreferred // A server but not preferred
) { // Show this conneciton only if this is a tree or if this is
// not a implicit connection to the preferred server.
dwMessageId = pNetRes->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER ? IDS_MESSAGE_ATTACHED : IDS_MESSAGE_ATTACHED_TO_TREE;
if ( pConnStatus->pszUserName ) { wcscpy( szUserName, pConnStatus->pszUserName ); }
if ( pConnStatus->fNds ) // NDS
{ LoadString( ::hmodNW, IDS_LOGIN_TYPE_NDS, pszStart, nSize ); nSize -= wcslen( pszStart ); pszStart += wcslen( pszStart);
} else // Bindery
{ LoadString( ::hmodNW, IDS_LOGIN_TYPE_BINDERY, pszStart, nSize ); nSize -= wcslen( pszStart ); pszStart += wcslen( pszStart); }
LoadString( ::hmodNW, IDS_LOGIN_STATUS_SEPARATOR, pszStart, nSize ); nSize -= wcslen( pszStart ); pszStart += wcslen( pszStart);
GetConnectionStatusString( pConnStatus, (LPBYTE) pszStart, nSize ); } }
if ( err == NO_ERROR ) { // Popup the message now.
::MsgBoxPrintf( hParent, dwMessageId, IDS_TITLE_WHOAMI, MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION, szRemoteName[0] == TREECHAR? szRemoteName + 1 : szRemoteName, szUserName, szConnType ); } else // error occurred
{ ::MsgBoxErrorPrintf( hParent, IDS_MESSAGE_CONNINFO_ERROR, IDS_TITLE_WHOAMI, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, err, NULL ); }
if ( pBuffer != NULL ) { LocalFree( pBuffer ); pBuffer = NULL; }
return NOERROR; }
VOID GetConnectionStatusString( PCONN_STATUS pConnStatus, LPBYTE Buffer, DWORD nSize ) { LPWSTR pszStart = (LPWSTR) Buffer; DWORD dwMessageId = 0;
if ( pConnStatus->fNds ) // NDS
{ if ( pConnStatus->dwConnType == NW_CONN_NOT_AUTHENTICATED ) { dwMessageId = IDS_LOGIN_STATUS_NOT_AUTHENTICATED; } else if ( pConnStatus->dwConnType == NW_CONN_DISCONNECTED ) { dwMessageId = IDS_LOGIN_STATUS_NOT_ATTACHED; } else // authenticated, licensed or unlicensed
{ LoadString( ::hmodNW, IDS_LOGIN_STATUS_AUTHENTICATED, pszStart, nSize ); nSize -= wcslen( pszStart ); pszStart += wcslen( pszStart);
if ( pConnStatus->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED ) dwMessageId = IDS_LOGIN_STATUS_LICENSED; else // NW_CONN_NDS_AUTHENTICATED_NO_LICENSE
dwMessageId = IDS_LOGIN_STATUS_NOT_LICENSED; } } else // Bindery
{ if ( pConnStatus->dwConnType == NW_CONN_BINDERY_LOGIN ) dwMessageId = IDS_LOGIN_STATUS_LOGGED_IN; else if ( pConnStatus->dwConnType == NW_CONN_DISCONNECTED ) dwMessageId = IDS_LOGIN_STATUS_NOT_ATTACHED; else dwMessageId = IDS_LOGIN_STATUS_ATTACHED_ONLY; }
LoadString( ::hmodNW, dwMessageId, pszStart, nSize ); }
HRESULT NWUIGlobalWhoAmI( HWND hParent ) { ::DialogBoxParam( ::hmodNW, MAKEINTRESOURCE(DLG_GLOBAL_WHOAMI), hParent, ::GlobalWhoAmIDlgProc, NULL );
return NOERROR; }
HRESULT NWUILogOut( HWND hParent, LPNETRESOURCE pNetRes, PBOOL pfDisconnected ) { DWORD err = NO_ERROR; WCHAR szServer[MAX_PATH+1]; BOOL fAttached; BOOL fAuthenticated; DWORD dwMessageId;
*pfDisconnected = FALSE;
// Need to extract the server name from full UNC path
NwExtractServerName( pNetRes->lpRemoteName, szServer );
err = NwIsServerOrTreeAttached( szServer, &fAttached, &fAuthenticated );
if ( err == NO_ERROR && !fAttached ) { dwMessageId = IDS_MESSAGE_NOT_ATTACHED; } else if ( err == NO_ERROR ) // attached
{ int nRet = ::MsgBoxPrintf( hParent, IDS_MESSAGE_LOGOUT_CONFIRM, IDS_TITLE_LOGOUT, MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION);
if ( nRet != IDYES ) return NOERROR;
err = LogoutFromServer( szServer, pfDisconnected );
if ( err == NO_ERROR ) dwMessageId = IDS_MESSAGE_DETACHED; else dwMessageId = IDS_MESSAGE_LOGOUT_FAILED; } else // error occurred
{ ::MsgBoxErrorPrintf( hParent, IDS_MESSAGE_CONNINFO_ERROR, IDS_TITLE_LOGOUT, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, err, NULL );
return NOERROR; }
::MsgBoxPrintf( hParent, dwMessageId, IDS_TITLE_LOGOUT, MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION );
return NOERROR; }
DWORD LogoutFromServer( LPWSTR pszServer, PBOOL pfDisconnected ) { DWORD err = NO_ERROR; HANDLE EnumHandle = (HANDLE) NULL;
LPNETRESOURCE NetR = NULL; LPNETRESOURCEW SavePtr;
DWORD BytesNeeded = MAX_ONE_NETRES_SIZE; DWORD EntriesRead = 0; DWORD i;
*pfDisconnected = FALSE;
err = NPOpenEnum( RESOURCE_CONNECTED, 0, 0, NULL, &EnumHandle );
if ( err != NO_ERROR) { EnumHandle = (HANDLE) NULL; goto CleanExit; }
//
// Allocate buffer to get server list.
//
if ((NetR = (LPNETRESOURCE) LocalAlloc( 0, BytesNeeded )) == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; goto CleanExit; }
do {
EntriesRead = 0xFFFFFFFF; // Read as many as possible
err = NwEnumConnections( EnumHandle, &EntriesRead, (LPVOID) NetR, &BytesNeeded, TRUE );
if ( err == WN_SUCCESS) { SavePtr = NetR;
for (i = 0; i < EntriesRead; i++, NetR++) { BYTE Buffer[MAX_ONE_CONN_INFORMATION_SIZE]; BOOL fImplicit; LPWSTR pszCurrentServer;
fImplicit = FALSE;
if ( NwIsNdsSyntax( NetR->lpRemoteName)) { // For Nds name, the server name might not be in the full UNC name.
// Hence we need to get the server name from the Rdr.
DWORD err1 = NwGetConnectionInformation( NetR->lpLocalName? NetR->lpLocalName : NetR->lpRemoteName, Buffer, sizeof(Buffer));
if ( err1 != NO_ERROR ) continue; // continue with the next entry if error occurred
pszCurrentServer = ((PCONN_INFORMATION) Buffer)->HostServer;
// Need to NULL terminate the server name, this will probably used the space
// occupied by UserName but since we are not using it, it is probably ok.
LPWSTR pszTemp = (LPWSTR) ((DWORD_PTR) pszCurrentServer + ((PCONN_INFORMATION) Buffer)->HostServerLength ); *pszTemp = 0;
} else // in the form \\server\sys
{ LPWSTR pszTemp; wcscpy( (LPWSTR) Buffer, NetR->lpRemoteName + 2 ); // go past two backslashes
if ( pszTemp = wcschr( (LPWSTR) Buffer, L'\\' )) *pszTemp = 0; else { // The remote name contains only \\server, hence if the local name
// is null, this is a implicit connection
if ( NetR->lpLocalName == NULL ) fImplicit = TRUE; }
pszCurrentServer = (LPWSTR) Buffer; }
if ( _wcsicmp( pszCurrentServer, pszServer ) == 0 ) {
do {
// for implicit connections, we need to try and disconnect until
// we deleted all the implicit connections, i.e. until we
// get the invalid handle error
// NOTE: If we don't pass in CONNECT_UPDATE_PROFILE, shell won't update
// the windows that got disconnected. What do we want to do here?
err = WNetCancelConnection2( NetR->lpLocalName? NetR->lpLocalName : NetR->lpRemoteName, 0, // CONNECT_UPDATE_PROFILE,
TRUE );
if ( err == NO_ERROR ) *pfDisconnected = TRUE;
} while ( fImplicit && ( err == NO_ERROR));
if ( err == ERROR_INVALID_HANDLE ) { // implicit connection will sometimes return this if the explicit connection
// is already disconnected
err = NO_ERROR; }
if ( err != NO_ERROR ) { NetR = SavePtr; goto CleanExit; } } }
NetR = SavePtr; } else if ( err != WN_NO_MORE_ENTRIES) { if ( err == WN_MORE_DATA) {
//
// Original buffer was too small. Free it and allocate
// the recommended size and then some to get as many
// entries as possible.
//
(void) LocalFree((HLOCAL) NetR);
BytesNeeded += NW_ENUM_EXTRA_BYTES;
if ((NetR = (LPNETRESOURCE) LocalAlloc( 0, BytesNeeded )) == NULL) { err = ERROR_NOT_ENOUGH_MEMORY; goto CleanExit; } } else { goto CleanExit; } }
} while (err != WN_NO_MORE_ENTRIES);
if ( err == WN_NO_MORE_ENTRIES) err = NO_ERROR;
CleanExit:
if (EnumHandle != (HANDLE) NULL) (void) NPCloseEnum( EnumHandle);
if (NetR != NULL) { (void) LocalFree( (HLOCAL) NetR); NetR = NULL; }
return err; }
HRESULT NWUIAttachAs( HWND hParent, LPNETRESOURCE pNetRes ) { DWORD err = NO_ERROR; WCHAR szServerName[MAX_PATH+1]; BOOL fAttached; BOOL fAuthenticated;
// First, see if we are attached to the server.
// Note, Attach as menu will be disabled on the NDS servers that we are already logged into.
// Need to extract the server name from full UNC path
szServerName[0] = szServerName[1] = L'\\'; NwExtractServerName( pNetRes->lpRemoteName, szServerName + 2 );
err = NwIsServerOrTreeAttached( szServerName + 2, &fAttached, &fAuthenticated );
if ( err == NO_ERROR && fAttached && fAuthenticated ) { // Already attached and authenticated to the server.
// So, ask the user if he wants to log out first.
int nRet = ::MsgBoxPrintf( hParent, IDS_MESSAGE_LOGOUT_QUESTION, IDS_TITLE_LOGOUT, MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION );
if ( nRet != IDYES ) return NOERROR;
BOOL fDisconnected = FALSE; // can be used to refresh the shell if needed
err = LogoutFromServer( szServerName + 2, &fDisconnected );
if ( err != NO_ERROR ) { ::MsgBoxPrintf( hParent, IDS_MESSAGE_LOGOUT_FAILED, IDS_TITLE_LOGOUT, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP );
return NOERROR; } }
// If error occurred, just assume we are not attached to the server and continue on
// to login to the server.
DWORD dwConnFlags = CONNECT_INTERACTIVE | CONNECT_PROMPT;
// See if the server is in the default context tree.
// If yes, then we don't need to prompt the password first before connecting
// in WNetAddConnection3.
BOOL fInDefaultTree = FALSE; err = NwIsServerInDefaultTree( pNetRes->lpRemoteName, &fInDefaultTree );
if ( (err == NO_ERROR ) && fInDefaultTree ) dwConnFlags = CONNECT_INTERACTIVE;
//
// Now call WNetAddConnection3
//
// NOTE: net use \\mars_srv0 will succeed
// but net use \\marsdev\cn=mars_srv0... will failed
// Hence, just use the server name to connect.
LPWSTR pszSave = pNetRes->lpRemoteName; pNetRes->lpRemoteName = szServerName;
err = WNetAddConnection3( hParent, pNetRes, NULL, NULL, dwConnFlags );
if ( err != WN_SUCCESS && err != WN_CANCEL ) { ::MsgBoxErrorPrintf( hParent, IDS_MESSAGE_ADDCONN_ERROR, IDS_NETWARE_TITLE, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, err, pNetRes->lpRemoteName ); }
pNetRes->lpRemoteName = pszSave; // restore the original remote name just in case
return NOERROR; }
#if 0
HRESULT NWUISetDefaultContext( HWND hParent, LPNETRESOURCE pNetRes ) { DWORD dwPrintOptions; LPWSTR pszCurrentContext = NULL; WCHAR szNewContext[MAX_PATH+1];
DWORD err = NO_ERROR; HANDLE handleRdr = NULL;
UNICODE_STRING uTree; UNICODE_STRING uContext; LPWSTR pszContext = NULL;
// Open a handle to the redirector
err = RtlNtStatusToDosError( ::NwNdsOpenRdrHandle( &handleRdr ));
if ( err != NO_ERROR ) goto CleanExit;
// Get the print option so that we can use it later
err = ::NwQueryInfo( &dwPrintOptions, &pszCurrentContext );
if ( err != NO_ERROR ) goto CleanExit;
wcscpy( szNewContext, pNetRes->lpRemoteName + 1 ); // get past 1st '\\'
szNewContext[0] = TREECHAR; // in the format "*TREE\CONTEXT"
if ( (pszContext = wcschr( szNewContext, L'\\' )) != NULL ) { *pszContext = 0; RtlInitUnicodeString( &uContext, pszContext + 1 ); } else RtlInitUnicodeString( &uContext, L"");
RtlInitUnicodeString( &uTree, szNewContext+1 );
if ( (err = RtlNtStatusToDosError( ::NwNdsSetTreeContext( handleRdr, &uTree, &uContext))) == NO_ERROR ) { *pszContext = L'\\';
if ((err = ::NwSetInfoInRegistry( dwPrintOptions, szNewContext )) == NO_ERROR ) { ::MsgBoxPrintf( hParent, IDS_MESSAGE_CONTEXT_CHANGED, IDS_NETWARE_TITLE, MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION, pszCurrentContext ? ( *pszCurrentContext == TREECHAR ? pszCurrentContext + 1 : pszCurrentContext ) : L"", szNewContext+1 ); } }
CleanExit:
if ( err != NO_ERROR ) { ::MsgBoxErrorPrintf( hParent, IDS_MESSAGE_CONTEXT_ERROR, IDS_NETWARE_TITLE, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, err, szNewContext+1); }
if ( pszCurrentContext != NULL ) { LocalFree( pszCurrentContext ); pszCurrentContext = NULL; }
if ( handleRdr != NULL ) { ::NtClose( handleRdr ); handleRdr = NULL; }
return NOERROR; } #endif
HRESULT NWUIMapNetworkDrive( HWND hParent, LPNETRESOURCE pNetRes ) { HRESULT hres; CONNECTDLGSTRUCT cds;
cds.cbStructure = sizeof(cds); cds.hwndOwner = hParent; cds.lpConnRes = pNetRes; cds.dwFlags = CONNDLG_RO_PATH;
if ( (( hres = WNetConnectionDialog1( &cds )) == WN_SUCCESS ) && ( g_pFuncSHChangeNotify ) ) { WCHAR szPath[4];
szPath[0] = ((USHORT) cds.dwDevNum) - 1 + L'A'; szPath[1] = L':'; szPath[2] = L'\\'; szPath[3] = 0;
// Notify shell about added redirection
(*g_pFuncSHChangeNotify)( SHCNE_DRIVEADD, SHCNF_FLUSH | SHCNF_PATH | SHCNF_FLUSHNOWAIT, szPath, NULL );
Sleep(1000); // short delay to make sure Shell has updated drive table
// And we need to open shell window on this path
if (g_pFuncSHExecuteEx) { SHELLEXECUTEINFO ExecInfo;
::memset(&ExecInfo,0,sizeof(ExecInfo));
ExecInfo.hwnd = hParent; ExecInfo.lpVerb = 0; ExecInfo.lpFile = szPath; ExecInfo.lpParameters = NULL; ExecInfo.lpDirectory = NULL; ExecInfo.nShow = SW_NORMAL | SW_SHOW; ExecInfo.fMask = SEE_MASK_CLASSNAME; ExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ExecInfo.lpClass = (LPWSTR) L"Folder"; ExecInfo.hkeyClass = NULL;
(*g_pFuncSHExecuteEx)(&ExecInfo); } }
return hres; }
#define LB_PCT_NAME 25
#define LB_PCT_TYPE 11
#define LB_PCT_CONN 11
#define LB_PCT_USER 25
#define LB_PCT_STATUS 27
#define BITMAP_WIDTH 16
#define BITMAP_HEIGHT 16
#define MAPCOLOR RGB(0, 255, 0)
static UINT uiNDSIconIndex = 0; static UINT uiServerIconIndex = 0;
/*
* FillConnectionsListView * ----------------------- * * Fill list box with information on active connections */ VOID FillConnectionsListView( HWND hwndDlg ) { HWND hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST); LV_ITEM lvI; WCHAR szSubItemText[MAX_PATH+1]; UINT uiInsertedIndex;
DWORD_PTR ResumeKey = 0; LPBYTE pConnBuffer = NULL; DWORD EntriesRead = 0; DWORD err = NO_ERROR;
// Prepare ListView structure
lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE; lvI.state = 0; lvI.stateMask = 0;
do {
if ( pConnBuffer != NULL ) { LocalFree( pConnBuffer ); pConnBuffer = NULL; }
err = NwGetConnectionStatus( NULL, &ResumeKey, &pConnBuffer, &EntriesRead );
if ( ( err != NO_ERROR ) || ( EntriesRead == 0 ) ) { goto CleanExit; }
PCONN_STATUS pConnStatus = (PCONN_STATUS) pConnBuffer;
for ( DWORD i = 0; i < EntriesRead; i++) { // Allocate and initialize new item structure for use in the listbox
DWORD dwSize;
//
// Don't need to show preferred server with only implicit
// connections since we can't disconnect from it.
//
if ( pConnStatus->fPreferred ) { // Continue with the next item
pConnStatus = (PCONN_STATUS) ( (DWORD_PTR) pConnStatus + pConnStatus->dwTotalLength); continue; }
//
// Allocate and copy the connection information to be store with
// the listbox
//
PCONN_STATUS pConnStatusKeep = (PCONN_STATUS) LocalAlloc( LMEM_ZEROINIT, pConnStatus->dwTotalLength ); if ( pConnStatusKeep == NULL ) { err = ERROR_NOT_ENOUGH_MEMORY; goto CleanExit; }
memcpy( pConnStatusKeep, pConnStatus, pConnStatus->dwTotalLength );
dwSize = sizeof(CONN_STATUS);
if ( pConnStatus->pszServerName ) { pConnStatusKeep->pszServerName = (LPWSTR) ((DWORD_PTR)pConnStatusKeep + dwSize );
NwMakePrettyDisplayName( pConnStatusKeep->pszServerName );
dwSize += (wcslen(pConnStatus->pszServerName)+1)*sizeof(WCHAR); }
if ( pConnStatus->pszUserName ) { pConnStatusKeep->pszUserName = (LPWSTR) ((DWORD_PTR)pConnStatusKeep + dwSize );
dwSize += (wcslen(pConnStatus->pszUserName)+1) * sizeof(WCHAR);
NwAbbreviateUserName( pConnStatus->pszUserName, pConnStatusKeep->pszUserName );
NwMakePrettyDisplayName( pConnStatusKeep->pszUserName ); }
if ( pConnStatus->pszTreeName ) { pConnStatusKeep->pszTreeName = (LPWSTR) ((DWORD_PTR)pConnStatusKeep + dwSize ); }
//
// Construct the item to add to the listbox
//
lvI.iItem = i; lvI.iSubItem = 0; lvI.pszText = szSubItemText; lvI.cchTextMax = sizeof(szSubItemText);
// Select proper icon
lvI.iImage = pConnStatusKeep->fNds? uiNDSIconIndex : uiServerIconIndex;
lvI.lParam = (LPARAM) pConnStatusKeep;
wcscpy( szSubItemText, pConnStatusKeep->pszServerName );
// Insert the item
uiInsertedIndex = ListView_InsertItem( hwndLV, &lvI);
if ( uiInsertedIndex != -1 ) { // Added item itself - now for specific columns
// First, add the column indicating bindery or nds connection
if ( pConnStatusKeep->fNds ) { LoadString( ::hmodNW, IDS_LOGIN_TYPE_NDS, szSubItemText, sizeof(szSubItemText)/sizeof(szSubItemText[0])); } else { LoadString( ::hmodNW, IDS_LOGIN_TYPE_BINDERY, szSubItemText, sizeof(szSubItemText)/sizeof(szSubItemText[0])); }
ListView_SetItemText( hwndLV, uiInsertedIndex, 1, // SubItem id
szSubItemText );
// Next, Add the column indicating the connection number
if ( ( pConnStatusKeep->pszServerName[0] != TREECHAR ) && ( pConnStatusKeep->dwConnType != NW_CONN_DISCONNECTED ) ) { // Add connection number only if it is a connection
// to a server and not a tree.
// A connection number only makes sense when not disconnected
::wsprintf(szSubItemText,L"%4d",pConnStatusKeep->nConnNum ); ListView_SetItemText( hwndLV, uiInsertedIndex, 2, // SubItem id
szSubItemText ); }
// Then, add the column indicating the user name
*szSubItemText = L'\0'; if ( pConnStatusKeep->pszUserName ) { wcscpy( szSubItemText, pConnStatusKeep->pszUserName );
ListView_SetItemText( hwndLV, uiInsertedIndex, 3, // SubItem id
szSubItemText ); }
// Last of all, add the column indicating the connection status
*szSubItemText = L'\0'; GetConnectionStatusString( pConnStatusKeep, (LPBYTE) szSubItemText, sizeof(szSubItemText)/sizeof(szSubItemText[0]));
ListView_SetItemText( hwndLV, uiInsertedIndex, 4, // SubItem id
szSubItemText );
} else { // Failed inserting item in the list,
// need to delete the allocated CONN_STATUS
ASSERT( FALSE ); LocalFree( pConnStatusKeep ); pConnStatusKeep = NULL; }
// Continue with the next item
pConnStatus = (PCONN_STATUS) ( (DWORD_PTR) pConnStatus + pConnStatus->dwTotalLength); }
} while ( ResumeKey != 0 );
CleanExit:
if ( pConnBuffer != NULL ) { LocalFree( pConnBuffer ); pConnBuffer = NULL; }
if ( err != NO_ERROR ) { // If error occurred, we will end the dialog
::MsgBoxErrorPrintf( hwndDlg, IDS_MESSAGE_CONNINFO_ERROR, IDS_NETWARE_TITLE, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, err, NULL );
::EndDialog( hwndDlg, FALSE); } }
/*
* CreateConnectionsListView * ------------------------- * * Initialize the column headers of the list box */ VOID CreateConnectionsListView( HWND hwndDlg ) { HWND hwndLV; HIMAGELIST hSmall; UINT uiLBoxWidth;
InitCommonControls();
// Get the handle of the listbox
hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST);
RECT rc; ::GetWindowRect( ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST ), &rc ); uiLBoxWidth = rc.right - rc.left;
// Load image list
hSmall = ::ImageList_Create(BITMAP_WIDTH,BITMAP_HEIGHT,ILC_MASK,4,0);
// Load bitmap of the tree/server icon
HBITMAP hbm; hbm = ::LoadBitmap(::hmodNW,MAKEINTRESOURCE(IDB_TREE_ICON));
if ((uiNDSIconIndex = ImageList_AddMasked(hSmall,hbm,MAPCOLOR)) == -1) {
ASSERT(FALSE); }
hbm = ::LoadBitmap(::hmodNW,MAKEINTRESOURCE(IDB_SERVER_ICON));
if ((uiServerIconIndex = ImageList_AddMasked(hSmall,hbm,MAPCOLOR)) == -1) {
ASSERT(FALSE); }
ImageList_SetBkColor(hSmall, CLR_NONE);
// Associate image list with list view control
ListView_SetImageList(hwndLV,hSmall,LVSIL_SMALL);
// Initialize columns in header
LV_COLUMN lvC; UINT uiColumnIndex = 0; WCHAR szColumnName[128];
lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvC.fmt = LVCFMT_LEFT; lvC.cx = (uiLBoxWidth*LB_PCT_NAME)/100; lvC.pszText = szColumnName;
// Add the column header representing the server name
*szColumnName = L'\0'; ::LoadString( ::hmodNW, IDS_COLUMN_NAME, szColumnName, sizeof(szColumnName)/sizeof(szColumnName[0])); if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) { ASSERT(FALSE); }
// Add the column header representing the conneciton type
*szColumnName = L'\0'; lvC.cx = (uiLBoxWidth*LB_PCT_TYPE)/100; ::LoadString( ::hmodNW, IDS_COLUMN_CONN_TYPE, szColumnName, sizeof(szColumnName)/sizeof(szColumnName[0])); if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) { ASSERT(FALSE); }
// Add the column header representing the connection number
*szColumnName = L'\0'; lvC.cx = (uiLBoxWidth*LB_PCT_CONN)/100; lvC.fmt = LVCFMT_RIGHT;
::LoadString( ::hmodNW, IDS_COLUMN_CONN_NUMBER, szColumnName, sizeof(szColumnName)/sizeof(szColumnName[0])); if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) { ASSERT(FALSE); }
// Add the column header representing the name of the user
*szColumnName = L'\0'; lvC.cx = (uiLBoxWidth*LB_PCT_USER)/100; lvC.fmt = LVCFMT_LEFT;
::LoadString( ::hmodNW, IDS_COLUMN_USER, szColumnName, sizeof(szColumnName)/sizeof(szColumnName[0]));
if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) { ASSERT(FALSE); }
// Add the column header representing the status of the connection
*szColumnName = L'\0'; lvC.cx = (uiLBoxWidth*LB_PCT_STATUS)/100; lvC.fmt = LVCFMT_LEFT;
::LoadString( ::hmodNW, IDS_COLUMN_STATUS, szColumnName, sizeof(szColumnName)/sizeof(szColumnName[0]));
if ( ListView_InsertColumn(hwndLV,uiColumnIndex++,&lvC) == -1) { ASSERT(FALSE); }
// Now fill list view window with connection information
FillConnectionsListView( hwndDlg );
} /* endproc CreateConnectionsListView */
/*
* GlobalWhoAmI_ListViewCompareProc * -------------------------------- * */ LRESULT CALLBACK GlobalWhoAmI_ListViewCompareProc( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) { PCONN_STATUS pConnItem1 = (PCONN_STATUS)lParam1; PCONN_STATUS pConnItem2 = (PCONN_STATUS)lParam2;
int iResult = 0;
if ( pConnItem1 && pConnItem2 ) { switch(lParamSort) { case 0: iResult = ::_wcsicmp( pConnItem1->pszServerName, pConnItem2->pszServerName); break;
case 1: iResult = pConnItem1->fNds - pConnItem2->fNds; break;
case 2: iResult = pConnItem1->nConnNum - pConnItem2->nConnNum; break;
case 3: { // pszUserName might be NULL, so we need to be careful when
// comparing them.
if ( pConnItem1->pszUserName ) { if ( pConnItem2->pszUserName ) { iResult = ::_wcsicmp( pConnItem1->pszUserName, pConnItem2->pszUserName); } else { iResult = 1; } } else { iResult = -1; } break; }
case 4: iResult = pConnItem1->dwConnType - pConnItem2->dwConnType; break;
default: iResult = 0; break; } }
return (iResult);
}
LRESULT NotifyHandler( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam ) { NM_LISTVIEW *lpNm = (NM_LISTVIEW *)lParam; NMHDR *lphdr = &lpNm->hdr;
HWND hwndLV = ::GetDlgItem(hwndDlg,IDD_GLOBAL_SERVERLIST);
switch(lphdr->code) { case LVN_ITEMCHANGED: // Check for change in item state, make sure item has received focus
if (lpNm->uChanged & LVIF_STATE) { UINT uiSelectedItems = 0;
uiSelectedItems = ListView_GetSelectedCount(hwndLV);
EnableWindow( GetDlgItem(hwndDlg, IDD_DETACH), uiSelectedItems? TRUE : FALSE);
return TRUE; } break;
case LVN_COLUMNCLICK: ListView_SortItems( hwndLV, GlobalWhoAmI_ListViewCompareProc, (LPARAM)(lpNm->iSubItem)); return TRUE; /* we processed a message */
case LVN_DELETEITEM: // Free memory
LocalFree( (HLOCAL) lpNm->lParam ); lpNm->lParam = NULL; break;
default: break; }
return FALSE; }
BOOL DetachResourceProc( HWND hwndDlg ) { BOOL fDetached = FALSE; LV_ITEM lvitem; int index; DWORD err;
HWND hwndLV = ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST);
index = -1; // Start at beginning of item list.
while ((index = ListView_GetNextItem(hwndLV, index, LVNI_SELECTED)) != -1) { lvitem.iItem = index; lvitem.mask = LVIF_PARAM; lvitem.iSubItem = 0;
if ( ListView_GetItem( hwndLV, &lvitem )) { PCONN_STATUS pConnStatus = (PCONN_STATUS) lvitem.lParam; BOOL fDisconnected = FALSE; // Can be used to refresh
// the shell if needed
err = LogoutFromServer( pConnStatus->pszServerName, &fDisconnected );
if ( err == NO_ERROR ) { fDetached = TRUE; } else { NwMakePrettyDisplayName(pConnStatus->pszServerName); ::MsgBoxPrintf( hwndDlg, IDS_MESSAGE_LOGOUT_FROM_SERVER_FAILED, IDS_TITLE_LOGOUT, MB_OK | MB_SETFOREGROUND | MB_ICONINFORMATION, pConnStatus->pszServerName ); } } }
return fDetached; }
static DWORD aWhoAmIIds[] = { IDC_LOGOFRAME, NO_HELP, IDD_GLOBAL_SERVERLIST_T,IDH_GLOBAL_SERVERLIST, IDD_GLOBAL_SERVERLIST, IDH_GLOBAL_SERVERLIST, IDD_DETACH, IDH_GLOBAL_DETACH, IDD_GLOBAL_SVRLIST_DESC,IDH_GLOBAL_SERVERLIST, 0, 0 };
/*
* GlobalWhoAmIDlgProc * ------------------- * * WhoAmI information for list of attached servers */ INT_PTR CALLBACK GlobalWhoAmIDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam ) { switch (msg) { case WM_INITDIALOG: { LPWSTR pszCurrentContext = NULL; DWORD dwPrintOptions;
// Get the current default tree or server name
DWORD err = ::NwQueryInfo( &dwPrintOptions, &pszCurrentContext ); if ( err == NO_ERROR ) { LPWSTR pszName; WCHAR szUserName[MAX_PATH+1] = L""; WCHAR szNoName[2] = L""; DWORD_PTR ResumeKey = 0; LPBYTE pBuffer = NULL; DWORD EntriesRead = 0;
DWORD dwMessageId;
UNICODE_STRING uContext; WCHAR szContext[MAX_PATH+1];
szContext[0] = 0; uContext.Buffer = szContext; uContext.Length = uContext.MaximumLength = sizeof(szContext)/sizeof(szContext[0]);
if ( pszCurrentContext ) { pszName = pszCurrentContext; } else { pszName = szNoName; }
if ( pszName[0] == TREECHAR ) { // Get the tree name from the full name *TREE\CONTEXT
LPWSTR pszTemp; if ( pszTemp = wcschr( pszName, L'\\' )) *pszTemp = 0;
dwMessageId = IDS_MESSAGE_NOT_LOGGED_IN_TREE; } else { dwMessageId = IDS_MESSAGE_NOT_LOGGED_IN_SERVER; }
if ( pszName[0] != 0 ) // there is preferred server/tree
{ err = NwGetConnectionStatus( pszName, &ResumeKey, &pBuffer, &EntriesRead ); }
if ( err == NO_ERROR && EntriesRead > 0 ) // For trees, we'll get more than one entry
{ PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer;
if ( EntriesRead > 1 && pszName[0] == TREECHAR ) { // If there is more than one entry for trees,
// then we need to find one entry where username is not null.
// If we cannot find one, then just use the first one.
DWORD i; PCONN_STATUS pConnStatusTmp = pConnStatus; PCONN_STATUS pConnStatusUser = NULL; PCONN_STATUS pConnStatusNoUser = NULL;
for ( i = 0; i < EntriesRead ; i++ ) { if ( pConnStatusTmp->fNds ) { pConnStatusNoUser = pConnStatusTmp;
if ( ( pConnStatusTmp->pszUserName != NULL ) && ( ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE ) || ( pConnStatusTmp->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED ) ) ) { // Found it
pConnStatusUser = pConnStatusTmp; break; } }
// Continue with the next item
pConnStatusTmp = (PCONN_STATUS) ( (DWORD_PTR) pConnStatusTmp + pConnStatusTmp->dwTotalLength); }
if ( pConnStatusUser ) { // found one nds entry with a user name
pConnStatus = pConnStatusUser; } else if ( pConnStatusNoUser ) { // use an nds entry with no user name
pConnStatus = pConnStatusNoUser; } // else use the first entry
}
if ( ( pConnStatus->pszUserName ) && ( pConnStatus->pszUserName[0] != 0 ) ) { NwAbbreviateUserName( pConnStatus->pszUserName, szUserName);
NwMakePrettyDisplayName( szUserName );
if ( pszName[0] != TREECHAR ) { dwMessageId = IDS_MESSAGE_LOGGED_IN_SERVER; } else { dwMessageId = IDS_MESSAGE_LOGGED_IN_TREE; } }
if ( pszName[0] == TREECHAR ) { // For trees, we need to get the current context
// Open a handle to the redirector
HANDLE handleRdr = NULL; err = RtlNtStatusToDosError( ::NwNdsOpenRdrHandle( &handleRdr ));
if ( err == NO_ERROR ) { UNICODE_STRING uTree; RtlInitUnicodeString( &uTree, pszName+1 ); // get past '*'
// Get the current context in the default tree
err = RtlNtStatusToDosError( ::NwNdsGetTreeContext( handleRdr, &uTree, &uContext)); }
if ( handleRdr != NULL ) ::NtClose( handleRdr ); } }
if ( !err ) { LPWSTR pszText = NULL; err = ::LoadMsgPrintf( &pszText, dwMessageId, pszName[0] == TREECHAR? pszName + 1 : pszName, szUserName, szContext );
if ( err == NO_ERROR ) { ::SetDlgItemText( hwndDlg, IDD_GLOBAL_SERVERLIST_T, pszText); ::LocalFree( pszText ); } }
if ( pBuffer != NULL ) { LocalFree( pBuffer ); pBuffer = NULL; } }
if ( pszCurrentContext != NULL ) { LocalFree( pszCurrentContext ); pszCurrentContext = NULL; }
if ( err != NO_ERROR ) { ::MsgBoxErrorPrintf( hwndDlg, IDS_MESSAGE_CONNINFO_ERROR, IDS_NETWARE_TITLE, MB_OK | MB_SETFOREGROUND | MB_ICONSTOP, err, NULL ); ::EndDialog( hwndDlg, FALSE); return TRUE; }
// Fill listview control with connection parameters
CreateConnectionsListView(hwndDlg);
UnHideControl( hwndDlg, IDD_DETACH);
// List view fill defaults to no selected server, disable Detach.
EnableWindow( GetDlgItem( hwndDlg, IDD_DETACH), FALSE);
// Set up timer for automatic refresh interval
::SetTimer( hwndDlg, 1, GLOBAL_WHOAMI_REFRESH_INTERVAL, NULL);
// Set focus to list box
::SetFocus( ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST));
return FALSE; /* we set the focus */ }
case WM_DESTROY: ::KillTimer( hwndDlg, 1); break;
case WM_COMMAND:
switch (wParam) { case IDOK: case IDCANCEL: ::EndDialog( hwndDlg, FALSE); return TRUE; /* we processed a message */
case IDD_DETACH: // Attempt to detach server connection currently selected
if ( DetachResourceProc( hwndDlg )) { // If succeeded - refresh window
::SendMessage(hwndDlg,WM_COMMAND,IDD_REFRESH,0L); }
return TRUE; /* we processed a message */
case IDD_REFRESH: { // Refresh connection listbox
HWND hwndLV = ::GetDlgItem( hwndDlg, IDD_GLOBAL_SERVERLIST);
::SetFocus( hwndLV );
// Clear list
ListView_DeleteAllItems( hwndLV );
// Now refill list view window
FillConnectionsListView( hwndDlg );
// List view refill unsets selected server focus, disable Detach.
EnableWindow( GetDlgItem( hwndDlg, IDD_DETACH ), FALSE );
return TRUE; /* we processed a message */ }
default: break; } break;
case WM_NOTIFY: // Handle notifications
if ( NotifyHandler( hwndDlg, msg, wParam, lParam)) return TRUE; /* we processed a message */ break;
case WM_TIMER: ::SendMessage( hwndDlg, WM_COMMAND, IDD_REFRESH, 0L); break;
case WM_HELP: ::WinHelp( (HWND) ((LPHELPINFO)lParam)->hItemHandle, NW_HELP_FILE, HELP_WM_HELP, (DWORD_PTR) (LPVOID) aWhoAmIIds ); return TRUE;
case WM_CONTEXTMENU: ::WinHelp( (HWND) wParam, NW_HELP_FILE, HELP_CONTEXTMENU, (DWORD_PTR) (LPVOID) aWhoAmIIds ); return TRUE;
}
return FALSE; /* we didn't process the message */
}
|