2585 lines
67 KiB
C++
2585 lines
67 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1995.
|
|
//
|
|
// File: shrpage.cxx
|
|
//
|
|
// Contents: "Sharing" shell property page extension
|
|
//
|
|
// History: 6-Apr-95 BruceFo Created
|
|
// 12-Jul-00 JonN fixed 140878, MSG_MULTIDEL debounce
|
|
// 06-Oct-00 jeffreys Split CShareBase out of CSharingPropertyPage
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "headers.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "resource.h"
|
|
#include "helpids.h"
|
|
#include "dlgnew.hxx"
|
|
#include "cache.hxx"
|
|
#include "share.hxx"
|
|
#include "acl.hxx"
|
|
#include "shrinfo.hxx"
|
|
#include "shrpage.hxx"
|
|
#include "util.hxx"
|
|
|
|
|
|
|
|
void _MyShow( HWND hwndParent, INT idControl, BOOL fShow )
|
|
{
|
|
HWND hwndChild = GetDlgItem( hwndParent, idControl );
|
|
appAssert( NULL != hwndChild );
|
|
ShowWindow( hwndChild, (fShow) ? SW_SHOW : SW_HIDE );
|
|
EnableWindow( hwndChild, fShow );
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CShareBase::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
static const QITAB qit[] = {
|
|
QITABENT(CShareBase, IOleWindow), // IID_IOleWindow
|
|
{ 0 }
|
|
};
|
|
return QISearch(this, qit, riid, ppvObj);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CShareBase::AddRef()
|
|
{
|
|
return InterlockedIncrement(&_cRef);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CShareBase::Release()
|
|
{
|
|
if (InterlockedDecrement(&_cRef))
|
|
return _cRef;
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
STDMETHODIMP CShareBase::GetWindow(HWND *phwnd)
|
|
{
|
|
*phwnd = _GetFrameWindow();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CShareBase::ContextSensitiveHelp(BOOL /*fEnterMode*/)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::PageCallback, static public
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
UINT CALLBACK
|
|
CShareBase::PageCallback(
|
|
IN HWND hwnd,
|
|
IN UINT uMsg,
|
|
IN LPPROPSHEETPAGE ppsp
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case PSPCB_CREATE:
|
|
return 1; // allow creation
|
|
|
|
case PSPCB_RELEASE:
|
|
{
|
|
CShareBase* pThis = (CShareBase*)ppsp->lParam;
|
|
pThis->Release(); // do this LAST!
|
|
return 0; // ignored
|
|
}
|
|
|
|
case PSPCB_ADDREF:
|
|
// Should probably implement some refcounting, but we only get
|
|
// addref'd once and released once.
|
|
return 0;
|
|
|
|
default:
|
|
appDebugOut((DEB_ERROR, "CShareBase::PageCallback, unknown page callback message %d\n", uMsg));
|
|
return 0;
|
|
|
|
} // end switch
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::DlgProcPage, static public
|
|
//
|
|
// Synopsis: Dialog Procedure for all sharing dialogs/pages
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
INT_PTR CALLBACK
|
|
CShareBase::DlgProcPage(
|
|
IN HWND hwnd,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
CShareBase* pThis = NULL;
|
|
|
|
if (msg==WM_INITDIALOG)
|
|
{
|
|
PROPSHEETPAGE* psp = (PROPSHEETPAGE*)lParam;
|
|
pThis = (CShareBase*)psp->lParam;
|
|
SetWindowLongPtr(hwnd,GWLP_USERDATA,(LPARAM)pThis);
|
|
}
|
|
else
|
|
{
|
|
pThis = (CShareBase*) GetWindowLongPtr(hwnd,GWLP_USERDATA);
|
|
}
|
|
|
|
if (pThis != NULL)
|
|
{
|
|
return pThis->_PageProc(hwnd,msg,wParam,lParam);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::CShareBase, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
CShareBase::CShareBase(
|
|
IN PWSTR pszPath,
|
|
IN BOOL bDialog // called as a dialog, not a property page?
|
|
)
|
|
:
|
|
_cRef(1),
|
|
_pszPath(pszPath), // take ownership!
|
|
_hwndPage(NULL),
|
|
_fInitializingPage(0), // JonN 7/11/00 140878
|
|
_bDirty(FALSE),
|
|
_pInfoList(NULL),
|
|
_pReplaceList(NULL),
|
|
_pCurInfo(NULL),
|
|
_cShares(0),
|
|
_bNewShare(TRUE),
|
|
_bDialog(bDialog)
|
|
{
|
|
INIT_SIG(CShareBase);
|
|
appAssert(NULL != _pszPath);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::~CShareBase, public
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
CShareBase::~CShareBase()
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
// delete the the list of shares
|
|
appAssert(NULL != _pInfoList);
|
|
DeleteShareInfoList(_pInfoList, TRUE);
|
|
_pInfoList = NULL;
|
|
_pCurInfo = NULL;
|
|
|
|
// delete the "replacement" list
|
|
appAssert(NULL != _pReplaceList);
|
|
DeleteShareInfoList(_pReplaceList, TRUE);
|
|
_pReplaceList = NULL;
|
|
|
|
delete[] _pszPath;
|
|
_pszPath = NULL;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::InitInstance, public
|
|
//
|
|
// Synopsis: Part II of the constuctor process
|
|
//
|
|
// Notes: We don't want to handle any errors in constuctor, so this
|
|
// method is necessary for the second phase error detection.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CShareBase::InitInstance(
|
|
VOID
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
appDebugOut((DEB_ITRACE, "CShareBase::InitInstance\n"));
|
|
|
|
_pInfoList = new CShareInfo(); // dummy head node
|
|
if (NULL == _pInfoList)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
_pReplaceList = new CShareInfo(); // dummy head node
|
|
if (NULL == _pReplaceList)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_PageProc, private
|
|
//
|
|
// Synopsis: Dialog Procedure for this object
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CShareBase::_PageProc(
|
|
IN HWND hwnd,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
_hwndPage = hwnd;
|
|
//
|
|
// We know this drive is allowed to be shared. However, someone may
|
|
// have changed the number or characteristics of the share using the
|
|
// command line or winfile or server manager or the new file server
|
|
// tool, and the cache may not have been refreshed. Force a refresh
|
|
// now, to pick up any new shares for this path.
|
|
//
|
|
// Note that for the SharingDialog() API, this is the first time the
|
|
// cache gets loaded. If the server is not running, we nuke the dialog
|
|
// and return an error code.
|
|
//
|
|
g_ShareCache.Refresh();
|
|
if (_bDialog && !g_fSharingEnabled)
|
|
{
|
|
EndDialog(hwnd, -1);
|
|
}
|
|
_ConstructShareList();
|
|
return _OnInitDialog(hwnd, (HWND)wParam, lParam);
|
|
|
|
case WM_COMMAND:
|
|
return _OnCommand(hwnd, HIWORD(wParam), LOWORD(wParam), (HWND)lParam);
|
|
|
|
case WM_NOTIFY:
|
|
return _OnNotify(hwnd, (int)wParam, (LPNMHDR)lParam);
|
|
|
|
case WM_HELP:
|
|
return _OnHelp(hwnd, (LPHELPINFO)lParam);
|
|
|
|
case WM_CONTEXTMENU:
|
|
return _OnContextMenu(hwnd, (HWND)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
|
|
} // end switch (msg)
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_OnCommand, private
|
|
//
|
|
// Synopsis: WM_COMMAND handler
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CShareBase::_OnCommand(
|
|
IN HWND hwnd,
|
|
IN WORD wNotifyCode,
|
|
IN WORD wID,
|
|
IN HWND hwndCtl
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
//
|
|
// Commands only used when this page is invoked as a dialog box, via the
|
|
// SharingDialog() API:
|
|
//
|
|
if (_bDialog)
|
|
{
|
|
switch (wID)
|
|
{
|
|
case IDCANCEL:
|
|
if (!_DoCancel(hwnd))
|
|
{
|
|
// We might consider not going away. But instead, go away anyway.
|
|
}
|
|
EndDialog(hwnd, FALSE);
|
|
return TRUE;
|
|
|
|
case IDOK:
|
|
if (!_ValidatePage(hwnd))
|
|
{
|
|
// don't go away
|
|
return TRUE;
|
|
}
|
|
if (!_DoApply(hwnd, TRUE))
|
|
{
|
|
// don't go away
|
|
return TRUE;
|
|
}
|
|
EndDialog(hwnd, TRUE);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_OnNotify, private
|
|
//
|
|
// Synopsis: WM_NOTIFY handler
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CShareBase::_OnNotify(
|
|
IN HWND hwnd,
|
|
IN int idCtrl,
|
|
IN LPNMHDR phdr
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
// assume a property sheet notification
|
|
return _OnPropertySheetNotify(hwnd, phdr);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_OnPropertySheetNotify, private
|
|
//
|
|
// Synopsis: WM_NOTIFY handler for the property sheet notification
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CShareBase::_OnPropertySheetNotify(
|
|
IN HWND hwnd,
|
|
IN LPNMHDR phdr
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
switch (phdr->code)
|
|
{
|
|
case PSN_RESET: // cancel
|
|
if (_DoCancel(hwnd))
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR); // go away
|
|
}
|
|
else
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_INVALID);
|
|
}
|
|
return TRUE;
|
|
|
|
case PSN_KILLACTIVE: // change to another page
|
|
if (_ValidatePage(hwnd))
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
|
|
return TRUE;
|
|
}
|
|
|
|
case PSN_APPLY:
|
|
if (_DoApply(hwnd, !!(((LPPSHNOTIFY)phdr)->lParam)))
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR); // go away
|
|
}
|
|
else
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_INVALID);
|
|
}
|
|
return TRUE;
|
|
|
|
} // end switch (phdr->code)
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_DoApply, public
|
|
//
|
|
// Synopsis: If anything has changed, apply the data
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CShareBase::_DoApply(
|
|
IN HWND hwnd,
|
|
IN BOOL /*bClose*/
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
if (_bDirty)
|
|
{
|
|
_bDirty = FALSE;
|
|
PropSheet_UnChanged(_GetFrameWindow(),_hwndPage);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_DoCancel, public
|
|
//
|
|
// Synopsis: Do whatever is necessary to cancel the changes
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CShareBase::_DoCancel(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
if (_bDirty)
|
|
{
|
|
_bDirty = FALSE;
|
|
PropSheet_UnChanged(_GetFrameWindow(),_hwndPage);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_MarkPageDirty, private
|
|
//
|
|
// Synopsis: A change has made such that the page is now dirty
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CShareBase::_MarkPageDirty(
|
|
VOID
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
if (!_fInitializingPage)
|
|
{
|
|
if (!_bDirty)
|
|
{
|
|
appDebugOut((DEB_ITRACE, "Marking Sharing page dirty\n"));
|
|
_bDirty = TRUE;
|
|
PropSheet_Changed(_GetFrameWindow(),_hwndPage);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_ConnstructShareList, private
|
|
//
|
|
// Synopsis: Construct the list of shares for the current path by
|
|
// iterating through the entire cache of shares and adding an
|
|
// element for every path that matches.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CShareBase::_ConstructShareList(
|
|
VOID
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
appDebugOut((DEB_ITRACE, "_ConstructShareList\n"));
|
|
|
|
// This routine sets _cShares, and _bNewShare, and adds to
|
|
// the _pInfoList list
|
|
|
|
HRESULT hr;
|
|
|
|
DeleteShareInfoList(_pInfoList);
|
|
_pCurInfo = NULL;
|
|
_bNewShare = FALSE;
|
|
|
|
appAssert(_pInfoList->IsSingle());
|
|
appAssert(_pCurInfo == NULL);
|
|
appAssert(_pszPath != NULL);
|
|
|
|
hr = g_ShareCache.ConstructList(_pszPath, _pInfoList, &_cShares);
|
|
|
|
if (SUCCEEDED(hr) && _cShares == 0)
|
|
{
|
|
// There are no existing shares. Construct an element to be used
|
|
// by the UI to stash the new share's data
|
|
|
|
hr = _ConstructNewShareInfo();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_ConstructNewShareInfo, private
|
|
//
|
|
// Synopsis: Construct an element to be used by the UI to stash the new
|
|
// share's data
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
CShareBase::_ConstructNewShareInfo(
|
|
VOID
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
HRESULT hr;
|
|
|
|
CShareInfo* pNewInfo = new CShareInfo();
|
|
if (NULL == pNewInfo)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
hr = pNewInfo->InitInstance();
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pNewInfo;
|
|
return hr;
|
|
}
|
|
|
|
hr = pNewInfo->SetPath(_pszPath);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pNewInfo;
|
|
return hr;
|
|
}
|
|
|
|
NET_API_STATUS ret = pNewInfo->ReadCacheFlags ();
|
|
if ( NERR_Success != ret )
|
|
{
|
|
delete pNewInfo;
|
|
return HRESULT_FROM_WIN32 (ret);
|
|
}
|
|
|
|
_bNewShare = TRUE;
|
|
|
|
pNewInfo->SetDirtyFlag(SHARE_FLAG_ADDED);
|
|
pNewInfo->InsertBefore(_pInfoList);
|
|
|
|
//NOTE: leave the count of shares to be zero. The count of shares only
|
|
// reflects the number of committed shares (?)
|
|
|
|
// Get the shell's name for the folder to use as the share name. This
|
|
// gives us localized names for things like "Shared Documents".
|
|
//
|
|
// Sometimes the shell's name contains invalid characters, such
|
|
// as when we're looking at the root of the drive. In that case
|
|
// SHGetFileInfo returns "label (X:)" and IsValidShareName fails
|
|
// on the colon. For those, try calling shell32's PathCleanupSpec
|
|
// to make the name valid.
|
|
//
|
|
// If SHGetFileInfo and PathCleanupSpec fail to give us a good name,
|
|
// fall back on the old method, which is...
|
|
//
|
|
// Give the share a default name. For paths like "X:\", use the default
|
|
// "X", for paths like "X:\foo\bar\baz", use the default "baz".
|
|
// For everything else, juse leave it blank. Also, check that the
|
|
// computed default is not already a share name. If it is, leave it
|
|
// blank.
|
|
|
|
appAssert(NULL != _pszPath);
|
|
|
|
WCHAR szDefault[2] = L"";
|
|
PWSTR pszDefault = NULL;
|
|
SHFILEINFOW sfi = {0};
|
|
|
|
if (SHGetFileInfoW(_pszPath, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME))
|
|
{
|
|
if (IsValidShareName(sfi.szDisplayName, &hr))
|
|
{
|
|
pszDefault = sfi.szDisplayName;
|
|
}
|
|
else
|
|
{
|
|
int iResult = PathCleanupSpec(NULL, sfi.szDisplayName);
|
|
if (0 == (iResult & (PCS_TRUNCATED|PCS_PATHTOOLONG|PCS_FATAL))
|
|
&& IsValidShareName(sfi.szDisplayName, &hr))
|
|
{
|
|
pszDefault = sfi.szDisplayName;
|
|
}
|
|
}
|
|
//
|
|
// NTRAID#NTBUG9-225755-2000/12/19-jeffreys
|
|
//
|
|
// Win9x boxes can't see the share if the name is long
|
|
//
|
|
if (NULL != pszDefault && wcslen(pszDefault) > LM20_NNLEN)
|
|
{
|
|
// Go back to the old way below
|
|
pszDefault = NULL;
|
|
}
|
|
}
|
|
if (NULL == pszDefault)
|
|
{
|
|
pszDefault = szDefault;
|
|
int len = wcslen(_pszPath);
|
|
if (len == 3 && _pszPath[1] == L':' && _pszPath[2] == L'\\')
|
|
{
|
|
szDefault[0] = _pszPath[0];
|
|
}
|
|
else
|
|
{
|
|
PWSTR pszTmp = wcsrchr(_pszPath, L'\\');
|
|
if (pszTmp != NULL)
|
|
{
|
|
pszDefault = pszTmp + 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (g_ShareCache.IsShareNameUsed(pszDefault))
|
|
{
|
|
pszDefault = szDefault;
|
|
szDefault[0] = L'\0';
|
|
}
|
|
|
|
hr = pNewInfo->SetNetname(pszDefault);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
// FEATURE: error handling?
|
|
_bNewShare = FALSE;
|
|
pNewInfo->Unlink();
|
|
delete pNewInfo;
|
|
return hr;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_ValidateNewShareName, protected
|
|
//
|
|
// Synopsis: Return TRUE if the sharename is valid, performing
|
|
// confirmations if necessary
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CShareBase::_ValidateNewShareName(
|
|
VOID
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
if (!_bNewShare)
|
|
{
|
|
// nothing to do
|
|
return TRUE;
|
|
}
|
|
|
|
appAssert(NULL != _pCurInfo);
|
|
if (NULL == _pCurInfo) // JonN 5/2/01 384155
|
|
return FALSE;
|
|
|
|
PWSTR pszShareName = _pCurInfo->GetNetname();
|
|
appAssert(NULL != pszShareName);
|
|
|
|
if ((NULL == pszShareName) || (0 == wcslen(pszShareName))) // PREFIX 240253
|
|
{
|
|
MyErrorDialog(_hwndPage, IERR_BlankShareName);
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT uTemp;
|
|
if (!IsValidShareName(pszShareName, &uTemp))
|
|
{
|
|
MyErrorDialog(_hwndPage, uTemp);
|
|
return FALSE;
|
|
}
|
|
|
|
// Trying to create a reserved share?
|
|
if (0 == _wcsicmp(g_szIpcShare, pszShareName))
|
|
{
|
|
MyErrorDialog(_hwndPage, IERR_SpecialShare);
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 == _wcsicmp(g_szAdminShare, pszShareName))
|
|
{
|
|
// We will let the admin create the admin$ share if they create
|
|
// it in the directory specified by GetWindowsDirectory().
|
|
WCHAR szWindowsDir[MAX_PATH];
|
|
UINT err = GetWindowsDirectory(szWindowsDir, ARRAYLEN(szWindowsDir));
|
|
if (err == 0)
|
|
{
|
|
// oh well, give them this error
|
|
MyErrorDialog(_hwndPage, IERR_SpecialShare);
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 != _wcsicmp(_pCurInfo->GetPath(), szWindowsDir))
|
|
{
|
|
MyErrorDialog(_hwndPage, IERR_SpecialShare);
|
|
return FALSE;
|
|
}
|
|
|
|
// otherwise, it is the right directory. Let them create it.
|
|
}
|
|
|
|
/* removed JonN 10/5/98
|
|
// Check for downlevel accessibility
|
|
// we should really get rid of this at some point -- JonN 7/18/97
|
|
ULONG nType;
|
|
if (NERR_Success != NetpPathType(NULL, pszShareName, &nType, INPT_FLAGS_OLDPATHS))
|
|
{
|
|
DWORD id = MyConfirmationDialog(
|
|
_hwndPage,
|
|
IERR_InaccessibleByDos,
|
|
MB_YESNO | MB_ICONEXCLAMATION,
|
|
pszShareName);
|
|
if (id == IDNO)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
*/
|
|
|
|
WCHAR szOldPath[PATHLEN+1];
|
|
|
|
if (g_ShareCache.IsExistingShare(pszShareName, _pCurInfo->GetPath(), szOldPath))
|
|
{
|
|
DWORD id = ConfirmReplaceShare(_hwndPage, pszShareName, szOldPath, _pCurInfo->GetPath());
|
|
if (id != IDYES)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// User said to replace the old share. We need to add
|
|
// a "delete" record for the old share.
|
|
|
|
HRESULT hr;
|
|
|
|
CShareInfo* pNewInfo = new CShareInfo();
|
|
if (NULL == pNewInfo)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hr = pNewInfo->InitInstance();
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pNewInfo;
|
|
return FALSE;
|
|
}
|
|
|
|
// only need net name for delete; ignore other fields
|
|
hr = pNewInfo->SetNetname(pszShareName);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pNewInfo;
|
|
return FALSE;
|
|
}
|
|
|
|
hr = pNewInfo->SetPath(szOldPath);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pNewInfo;
|
|
return FALSE;
|
|
}
|
|
|
|
NET_API_STATUS ret = pNewInfo->ReadCacheFlags ();
|
|
if ( NERR_Success != ret )
|
|
{
|
|
delete pNewInfo;
|
|
return HRESULT_FROM_WIN32 (ret);
|
|
}
|
|
|
|
pNewInfo->SetDirtyFlag(SHARE_FLAG_REMOVE);
|
|
pNewInfo->InsertBefore(_pReplaceList); // add to end of replace list
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CShareBase::_CommitShares, protected
|
|
//
|
|
// Synopsis: Commit outstanding share edits. Note that this method does
|
|
// not reset _bDirty.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CShareBase::_CommitShares(
|
|
IN BOOL bNotShared
|
|
)
|
|
{
|
|
CHECK_SIG(CShareBase);
|
|
|
|
if (!_bDirty)
|
|
{
|
|
// nothing to do
|
|
return;
|
|
}
|
|
|
|
if (bNotShared)
|
|
{
|
|
// When the user hits "Not Shared" after having had "Shared As"
|
|
// selected, we don't actually delete anything (or even mark it
|
|
// for deletion). This is so the user can hit "Shared As" again
|
|
// and they haven't lost anything. However, if they subsequently
|
|
// apply changes, we must go through and actually delete anything
|
|
// that they wanted to delete. So, fix up our list to do this.
|
|
// Delete SHARE_FLAG_ADDED nodes, and mark all others as
|
|
// SHARE_FLAG_REMOVE.
|
|
|
|
for (CShareInfo* p = (CShareInfo*) _pInfoList->Next();
|
|
p != _pInfoList;
|
|
)
|
|
{
|
|
CShareInfo* pNext = (CShareInfo*)p->Next();
|
|
|
|
if (p->GetFlag() == SHARE_FLAG_ADDED)
|
|
{
|
|
// get rid of p
|
|
p->Unlink();
|
|
delete p;
|
|
}
|
|
else
|
|
{
|
|
p->SetDirtyFlag(SHARE_FLAG_REMOVE);
|
|
}
|
|
|
|
p = pNext;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Commit the changes!
|
|
//
|
|
|
|
HRESULT hr;
|
|
CShareInfo* p;
|
|
|
|
// Delete all "replace" shares first. These are all the shares whos
|
|
// names are being reused to share a different directory.
|
|
// These replace deletes have already been confirmed.
|
|
|
|
for (p = (CShareInfo*) _pReplaceList->Next();
|
|
p != _pReplaceList;
|
|
p = (CShareInfo*) p->Next())
|
|
{
|
|
appAssert(p->GetFlag() == SHARE_FLAG_REMOVE);
|
|
NET_API_STATUS ret = p->Commit(NULL);
|
|
if (ret != NERR_Success)
|
|
{
|
|
DisplayError(_hwndPage, IERR_CANT_DEL_SHARE, ret, p->GetNetname());
|
|
// We've got a problem here because we couldn't delete a
|
|
// share that will be added subsequently. Oh well...
|
|
}
|
|
|
|
// Note that we don't delete this list because we need to notify
|
|
// the shell (*after* all changes) that all these guys have
|
|
// changed (and get rid of those little hands)...
|
|
}
|
|
|
|
// Now, do all add/delete/modify of the current
|
|
|
|
for (p = (CShareInfo*) _pInfoList->Next();
|
|
p != _pInfoList;
|
|
)
|
|
{
|
|
CShareInfo* pNext = (CShareInfo*)p->Next();
|
|
|
|
if (0 != p->GetFlag())
|
|
{
|
|
if (SHARE_FLAG_REMOVE == p->GetFlag())
|
|
{
|
|
// confirm the delete, if there are connections
|
|
DWORD id = ConfirmStopShare(_hwndPage, MB_YESNO, p->GetNetname());
|
|
if (id != IDYES)
|
|
{
|
|
p->SetDirtyFlag(0); // don't do anything to it
|
|
}
|
|
}
|
|
|
|
NET_API_STATUS ret = p->Commit(NULL);
|
|
if (ret != NERR_Success)
|
|
{
|
|
HRESULT hrMsg = 0;
|
|
switch (p->GetFlag())
|
|
{
|
|
case SHARE_FLAG_ADDED: hrMsg = IERR_CANT_ADD_SHARE; break;
|
|
case SHARE_FLAG_MODIFY: hrMsg = IERR_CANT_MODIFY_SHARE; break;
|
|
case SHARE_FLAG_REMOVE: hrMsg = IERR_CANT_DEL_SHARE; break;
|
|
default:
|
|
appAssert(!"Illegal flag for a failed commit!");
|
|
}
|
|
DisplayError(_hwndPage, hrMsg, ret, p->GetNetname());
|
|
}
|
|
else
|
|
{
|
|
if (p->GetFlag() == SHARE_FLAG_REMOVE)
|
|
{
|
|
// nuke it!
|
|
p->Unlink();
|
|
delete p;
|
|
}
|
|
else
|
|
{
|
|
p->SetDirtyFlag(0); // clear flag on success
|
|
}
|
|
}
|
|
}
|
|
|
|
p = pNext;
|
|
}
|
|
|
|
if (_bNewShare)
|
|
{
|
|
_bNewShare = FALSE;
|
|
_cShares = 1;
|
|
}
|
|
|
|
// I refresh the cache, even though the shell comes back and asks
|
|
// for a refresh after every SHChangeNotify. However, SHChangeNotify
|
|
// is asynchronous, and I need the cache refreshed immediately so I
|
|
// can display the new share information, if the "apply" button was
|
|
// hit and the page didn't go away.
|
|
|
|
g_ShareCache.Refresh();
|
|
|
|
appDebugOut((DEB_TRACE,
|
|
"Changed share for path %ws, notifying shell\n",
|
|
_pszPath));
|
|
|
|
SHChangeNotify(SHCNE_NETSHARE, SHCNF_PATH, _pszPath, NULL);
|
|
// FEATURE: might want to use SHCNE_NETUNSHARE, but the shell doesn't
|
|
// distinguish them
|
|
|
|
// Now, notify the shell about all the paths we got rid of to be able
|
|
// to use their share names ...
|
|
for (p = (CShareInfo*) _pReplaceList->Next();
|
|
p != _pReplaceList;
|
|
)
|
|
{
|
|
appAssert(p->GetFlag() == SHARE_FLAG_REMOVE);
|
|
|
|
appDebugOut((DEB_TRACE,
|
|
"Got rid of share on path %ws, notifying shell\n",
|
|
p->GetPath()));
|
|
|
|
// We're going to be asked by the shell to refresh the cache once
|
|
// for every notify. But, seeing as how the average case is zero
|
|
// of these notifies, don't worry about it.
|
|
SHChangeNotify(SHCNE_NETSHARE, SHCNF_PATH, p->GetPath(), NULL);
|
|
|
|
CShareInfo* pNext = (CShareInfo*) p->Next();
|
|
p->Unlink();
|
|
delete p;
|
|
p = pNext;
|
|
}
|
|
|
|
_ConstructShareList();
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CSharingPropertyPage::SizeWndProc, public
|
|
//
|
|
// Synopsis: "allow" edit window subclass proc to disallow non-numeric
|
|
// characters.
|
|
//
|
|
// History: 5-Apr-95 BruceFo Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK
|
|
CSharingPropertyPage::SizeWndProc(
|
|
IN HWND hwnd,
|
|
IN UINT wMsg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
switch (wMsg)
|
|
{
|
|
case WM_CHAR:
|
|
{
|
|
WCHAR chCharCode = (WCHAR)wParam;
|
|
if ( (chCharCode == TEXT('\t'))
|
|
|| (chCharCode == TEXT('\b'))
|
|
|| (chCharCode == TEXT('\n'))
|
|
// || (chCharCode == TEXT('\x1b')) // ESCAPE key
|
|
)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (chCharCode < TEXT('0') || chCharCode > TEXT('9'))
|
|
{
|
|
// bad key: ignore it
|
|
MessageBeep(0xffffffff); // let user know it's an illegal char
|
|
return FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
} // end of switch
|
|
|
|
CSharingPropertyPage* pThis = (CSharingPropertyPage*)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA);
|
|
appAssert(NULL != pThis);
|
|
appAssert(NULL != pThis->_pfnAllowProc);
|
|
return CallWindowProc(pThis->_pfnAllowProc, hwnd, wMsg, wParam, lParam);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::CSharingPropertyPage, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
CSharingPropertyPage::CSharingPropertyPage(
|
|
IN PWSTR pszPath,
|
|
IN BOOL bDialog // called as a dialog, not a property page?
|
|
)
|
|
:
|
|
CShareBase(pszPath, bDialog),
|
|
_wIDSelected(0), // JonN 7/12/00 140878
|
|
_bItemDirty(FALSE),
|
|
_bShareNameChanged(FALSE),
|
|
_bCommentChanged(FALSE),
|
|
_bUserLimitChanged(FALSE),
|
|
_wMaxUsers(DEFAULT_MAX_USERS),
|
|
_pfnAllowProc(NULL),
|
|
_bIsCachingSupported (false)
|
|
{
|
|
INIT_SIG(CSharingPropertyPage);
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::~CSharingPropertyPage, public
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
CSharingPropertyPage::~CSharingPropertyPage()
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_PageProc, private
|
|
//
|
|
// Synopsis: Dialog Procedure for this object
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_PageProc(
|
|
IN HWND hwnd,
|
|
IN UINT msg,
|
|
IN WPARAM wParam,
|
|
IN LPARAM lParam
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_VSCROLL:
|
|
// The up/down control changed the edit control: select it again
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
|
|
return TRUE;
|
|
|
|
case WM_CLOSE:
|
|
// NOTE: There is a bug where hitting "ESCAPE" with the focus on the
|
|
// MLE for the "allow" text doesn't kill the property sheet unless we
|
|
// forward the WM_CLOSE message on to the property sheet root dialog.
|
|
return (BOOL)SendMessage(_GetFrameWindow(), msg, wParam, lParam);
|
|
|
|
case WM_DESTROY:
|
|
// restore original subclass to window.
|
|
appAssert(NULL != GetDlgItem(hwnd,IDC_SHARE_ALLOW_VALUE));
|
|
SetWindowLongPtr(GetDlgItem(hwnd,IDC_SHARE_ALLOW_VALUE), GWLP_WNDPROC, (LONG_PTR)_pfnAllowProc);
|
|
break;
|
|
|
|
} // end switch (msg)
|
|
|
|
return CShareBase::_PageProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnInitDialog, private
|
|
//
|
|
// Synopsis: WM_INITDIALOG handler
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnInitDialog(
|
|
IN HWND hwnd,
|
|
IN HWND hwndFocus,
|
|
IN LPARAM lInitParam
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
appDebugOut((DEB_ITRACE, "_OnInitDialog\n"));
|
|
|
|
// Subclass allow edit control to disallow non-positive numbers
|
|
_pfnAllowProc = (WNDPROC)SetWindowLongPtr(
|
|
GetDlgItem(hwnd, IDC_SHARE_ALLOW_VALUE),
|
|
GWLP_WNDPROC,
|
|
(LONG_PTR)&SizeWndProc);
|
|
|
|
// use LanMan API constants to set maximum share name & comment lengths
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_SHARENAME, EM_LIMITTEXT, NNLEN, 0L);
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_COMMENT, EM_LIMITTEXT, MAXCOMMENTSZ, 0L);
|
|
|
|
if (_bDialog)
|
|
{
|
|
SetWindowText(hwnd, _pszPath);
|
|
}
|
|
else
|
|
{
|
|
_MyShow( hwnd, IDOK, FALSE );
|
|
_MyShow( hwnd, IDCANCEL, FALSE );
|
|
}
|
|
|
|
_InitializeControls(hwnd);
|
|
|
|
// #if DBG == 1
|
|
// Dump(L"_OnInitDialog finished");
|
|
// #endif // DBG == 1
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnCommand, private
|
|
//
|
|
// Synopsis: WM_COMMAND handler
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnCommand(
|
|
IN HWND hwnd,
|
|
IN WORD wNotifyCode,
|
|
IN WORD wID,
|
|
IN HWND hwndCtl
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
switch (wID)
|
|
{
|
|
|
|
//
|
|
// Notifications
|
|
//
|
|
|
|
case IDC_SHARE_NOTSHARED:
|
|
{
|
|
if (BN_CLICKED == wNotifyCode)
|
|
{
|
|
if ( (!_fInitializingPage)
|
|
&& (IDC_SHARE_NOTSHARED != _wIDSelected) // JonN 7/11/00 140878
|
|
// JonN 7/11/00 140878
|
|
// sometimes you get BN_CLICKED even before the
|
|
// button is selected according to IsDlgButtonChecked
|
|
&& (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_NOTSHARED))
|
|
)
|
|
{
|
|
_wIDSelected = IDC_SHARE_NOTSHARED;
|
|
|
|
_ReadControls(hwnd);
|
|
|
|
// Delete all shares from the combo box; convert the combo box
|
|
// to the edit control (default state), and then disable
|
|
// all the controls. Cache whatever shares we had, so if
|
|
// the user hits "Shared As", we can put them back.
|
|
|
|
if (_cShares > 1)
|
|
{
|
|
// JonN 7/11/00 140878
|
|
// Additional BN_CLICKED notifications are coming in while
|
|
// the MSG_MULTIDEL dialog is still onscreen, resulting
|
|
// in multiple copies of the dialog.
|
|
_fInitializingPage++; // JonN 7/11/00 140878
|
|
|
|
DWORD id = MyConfirmationDialog(
|
|
hwnd,
|
|
MSG_MULTIDEL,
|
|
MB_YESNO | MB_ICONQUESTION);
|
|
if (IDNO == id)
|
|
{
|
|
CheckRadioButton(
|
|
hwnd,
|
|
IDC_SHARE_NOTSHARED,
|
|
IDC_SHARE_SHAREDAS,
|
|
IDC_SHARE_SHAREDAS);
|
|
|
|
//
|
|
// JonN 3/8/01 140878 part 2 (unit-test 3/9/01)
|
|
// At this point, IDC_SHARE_SHAREDAS is selected,
|
|
// but focus is still on IDC_SHARE_NOTSHARED and
|
|
// _wIDSelected == IDC_SHARE_NOTSHARED.
|
|
// Correct this, but stay in the _fInitializingPage
|
|
// block so that the page will not be marked dirty.
|
|
//
|
|
SendMessage(hwnd, WM_NEXTDLGCTL,
|
|
(WPARAM)GetDlgItem(hwnd,IDC_SHARE_SHAREDAS),
|
|
(LPARAM)TRUE);
|
|
_wIDSelected = IDC_SHARE_SHAREDAS;
|
|
|
|
_fInitializingPage--; // JonN 7/11/00 140878
|
|
return TRUE;
|
|
}
|
|
_fInitializingPage--; // JonN 7/11/00 140878
|
|
}
|
|
|
|
//
|
|
// Next, regenerate the UI
|
|
//
|
|
|
|
_SetControlsFromData(hwnd, NULL);
|
|
|
|
_MarkPageDirty();
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case IDC_SHARE_SHAREDAS:
|
|
{
|
|
if (BN_CLICKED == wNotifyCode)
|
|
{
|
|
|
|
if ( (!_fInitializingPage)
|
|
&& (IDC_SHARE_SHAREDAS != _wIDSelected) // JonN 7/11/00 140878
|
|
// JonN 7/11/00 140878
|
|
// Sometimes you get BN_CLICKED even before the
|
|
// button is selected according to IsDlgButtonChecked
|
|
&& (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_SHAREDAS))
|
|
)
|
|
{
|
|
_wIDSelected = IDC_SHARE_SHAREDAS;
|
|
|
|
// if there were shares there that we just hid when the user
|
|
// pressed "Not Shared", then put them back.
|
|
|
|
//
|
|
// Regenerate the UI
|
|
//
|
|
|
|
_SetControlsFromData(hwnd, NULL);
|
|
|
|
_MarkPageDirty();
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case IDC_SHARE_SHARENAME:
|
|
{
|
|
if (EN_CHANGE == wNotifyCode)
|
|
{
|
|
if (!_fInitializingPage)
|
|
{
|
|
_bShareNameChanged = TRUE;
|
|
_MarkItemDirty();
|
|
}
|
|
EnableWindow (GetDlgItem(hwnd, IDC_SHARE_CACHING),
|
|
IsCachingSupported ());
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
case IDC_SHARE_COMMENT:
|
|
{
|
|
if (EN_CHANGE == wNotifyCode)
|
|
{
|
|
if (!_fInitializingPage)
|
|
{
|
|
_bCommentChanged = TRUE;
|
|
_MarkItemDirty();
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
case IDC_SHARE_SHARENAME_COMBO:
|
|
{
|
|
if (CBN_SELCHANGE == wNotifyCode)
|
|
{
|
|
_ReadControls(hwnd);
|
|
|
|
HWND hwndCombo = GetDlgItem(hwnd, IDC_SHARE_SHARENAME_COMBO);
|
|
int item = ComboBox_GetCurSel(hwndCombo);
|
|
LRESULT itemData = ComboBox_GetItemData(hwndCombo, item);
|
|
_pCurInfo = (CB_ERR == itemData) ? NULL : (CShareInfo *)itemData;
|
|
appAssert(NULL != _pCurInfo);
|
|
|
|
_SetFieldsFromCurrent(hwnd);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case IDC_SHARE_MAXIMUM:
|
|
if (BN_CLICKED == wNotifyCode)
|
|
{
|
|
// Take away WS_TABSTOP from the "allow users" edit control
|
|
HWND hwndEdit = GetDlgItem(hwnd, IDC_SHARE_ALLOW_VALUE);
|
|
SetWindowLong(hwndEdit, GWL_STYLE, GetWindowLong(hwndEdit, GWL_STYLE) & ~WS_TABSTOP);
|
|
|
|
_CacheMaxUses(hwnd);
|
|
SetDlgItemText(hwnd, IDC_SHARE_ALLOW_VALUE, L"");
|
|
|
|
_bUserLimitChanged = TRUE;
|
|
_MarkItemDirty();
|
|
}
|
|
return TRUE;
|
|
|
|
case IDC_SHARE_ALLOW:
|
|
if (BN_CLICKED == wNotifyCode)
|
|
{
|
|
// Give WS_TABSTOP to the "allow users" edit control
|
|
HWND hwndEdit = GetDlgItem(hwnd, IDC_SHARE_ALLOW_VALUE);
|
|
SetWindowLong(hwndEdit, GWL_STYLE, GetWindowLong(hwndEdit, GWL_STYLE) | WS_TABSTOP);
|
|
|
|
// let the spin control set the edit control
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_SETPOS, 0, MAKELONG(_wMaxUsers, 0));
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
|
|
|
|
_bUserLimitChanged = TRUE;
|
|
_MarkItemDirty();
|
|
}
|
|
return TRUE;
|
|
|
|
case IDC_SHARE_ALLOW_VALUE:
|
|
{
|
|
if (EN_CHANGE == wNotifyCode)
|
|
{
|
|
_bUserLimitChanged = TRUE;
|
|
_MarkItemDirty();
|
|
}
|
|
|
|
if (EN_SETFOCUS == wNotifyCode)
|
|
{
|
|
if (1 != IsDlgButtonChecked(hwnd, IDC_SHARE_ALLOW))
|
|
{
|
|
CheckRadioButton(
|
|
hwnd,
|
|
IDC_SHARE_MAXIMUM,
|
|
IDC_SHARE_ALLOW,
|
|
IDC_SHARE_ALLOW);
|
|
}
|
|
|
|
// let the spin control set the edit control
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_SETPOS, 0, MAKELONG(_wMaxUsers, 0));
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
|
|
|
|
_bUserLimitChanged = TRUE;
|
|
_MarkItemDirty();
|
|
}
|
|
|
|
if (EN_KILLFOCUS == wNotifyCode)
|
|
{
|
|
_CacheMaxUses(hwnd);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
case IDC_SHARE_ALLOW_SPIN:
|
|
if (UDN_DELTAPOS == wNotifyCode)
|
|
{
|
|
if (1 != IsDlgButtonChecked(hwnd, IDC_SHARE_ALLOW))
|
|
{
|
|
CheckRadioButton(
|
|
hwnd,
|
|
IDC_SHARE_MAXIMUM,
|
|
IDC_SHARE_ALLOW,
|
|
IDC_SHARE_ALLOW);
|
|
}
|
|
|
|
_bUserLimitChanged = TRUE;
|
|
_MarkItemDirty();
|
|
}
|
|
return TRUE;
|
|
|
|
//
|
|
// Commands
|
|
//
|
|
|
|
case IDC_SHARE_PERMISSIONS:
|
|
return _OnPermissions(hwnd);
|
|
|
|
case IDC_SHARE_REMOVE:
|
|
return _OnRemove(hwnd);
|
|
|
|
case IDC_SHARE_NEWSHARE:
|
|
return _OnNewShare(hwnd);
|
|
|
|
case IDC_SHARE_CACHING:
|
|
return _OnCaching(hwnd);
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return CShareBase::_OnCommand(hwnd, wNotifyCode, wID, hwndCtl);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnHelp, private
|
|
//
|
|
// Synopsis: WM_HELP handler
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
static const DWORD aHelpIds[] =
|
|
{
|
|
IDOK, HC_OK,
|
|
IDCANCEL, HC_CANCEL,
|
|
IDC_SHARE_SHARENAME, HC_SHARE_SHARENAME,
|
|
IDC_SHARE_SHARENAME_TEXT, HC_SHARE_SHARENAME,
|
|
IDC_SHARE_COMMENT, HC_SHARE_COMMENT,
|
|
IDC_SHARE_COMMENT_TEXT, HC_SHARE_COMMENT,
|
|
IDC_SHARE_MAXIMUM, HC_SHARE_MAXIMUM,
|
|
IDC_SHARE_ALLOW, HC_SHARE_ALLOW,
|
|
IDC_SHARE_ALLOW_VALUE, HC_SHARE_ALLOW_VALUE,
|
|
IDC_SHARE_ALLOW_SPIN, -1L, // 257807 by request of JillZ
|
|
IDC_SHARE_PERMISSIONS, HC_SHARE_PERMISSIONS,
|
|
IDC_SHARE_LIMIT, HC_SHARE_LIMIT,
|
|
|
|
IDC_SHARE_NOTSHARED, HC_SHARE_NOTSHARED,
|
|
IDC_SHARE_SHAREDAS, HC_SHARE_SHAREDAS,
|
|
IDC_SHARE_SHARENAME_COMBO, HC_SHARE_SHARENAME_COMBO,
|
|
IDC_SHARE_REMOVE, HC_SHARE_REMOVE,
|
|
IDC_SHARE_NEWSHARE, HC_SHARE_NEWSHARE,
|
|
IDC_SHARE_ICON, -1L, // 311328 JillZ
|
|
IDC_SHARE_TOPTEXT, -1L, // 311328 JillZ
|
|
0,0
|
|
};
|
|
static const DWORD aCSCUIHelpIds[] =
|
|
{
|
|
IDC_SHARE_CACHING, IDH_SHARE_CACHING_BTN,
|
|
IDC_SHARE_CACHING_TEXT, IDH_SHARE_CACHING_BTN,
|
|
0,0
|
|
};
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnHelp(
|
|
IN HWND hwnd,
|
|
IN LPHELPINFO lphi
|
|
)
|
|
{
|
|
if (lphi->iContextType == HELPINFO_WINDOW) // a control
|
|
{
|
|
WCHAR szHelp[50];
|
|
if ( IDC_SHARE_CACHING == lphi->iCtrlId || IDC_SHARE_CACHING_TEXT == lphi->iCtrlId )
|
|
{
|
|
LoadString(g_hInstance, IDS_CSCUI_HELPFILENAME, szHelp, ARRAYLEN(szHelp));
|
|
WinHelp(
|
|
(HWND)lphi->hItemHandle,
|
|
szHelp,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)aCSCUIHelpIds);
|
|
}
|
|
else
|
|
{
|
|
LoadString(g_hInstance, IDS_HELPFILENAME, szHelp, ARRAYLEN(szHelp));
|
|
WinHelp(
|
|
(HWND)lphi->hItemHandle,
|
|
szHelp,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)aHelpIds);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define _AfxGetDlgCtrlID(hWnd) ((UINT)(WORD)::GetDlgCtrlID(hWnd))
|
|
HWND MyChildWindowFromPoint(HWND hWnd, POINT pt)
|
|
{
|
|
appAssert(hWnd != NULL);
|
|
|
|
// check child windows
|
|
::ClientToScreen(hWnd, &pt);
|
|
HWND hWndChild = ::GetWindow(hWnd, GW_CHILD);
|
|
for (; hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))
|
|
{
|
|
if (_AfxGetDlgCtrlID(hWndChild) != (WORD)-1 &&
|
|
(::GetWindowLong(hWndChild, GWL_STYLE) & WS_VISIBLE))
|
|
{
|
|
// see if point hits the child window
|
|
RECT rect;
|
|
::GetWindowRect(hWndChild, &rect);
|
|
if (PtInRect(&rect, pt))
|
|
return hWndChild;
|
|
}
|
|
}
|
|
|
|
return NULL; // not found
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnContextMenu, private
|
|
//
|
|
// Synopsis: WM_CONTEXTMENU handler
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnContextMenu(
|
|
IN HWND hwnd,
|
|
IN HWND hCtrlWnd,
|
|
IN int xPos,
|
|
IN int yPos
|
|
)
|
|
{
|
|
WCHAR szHelp[50];
|
|
int ctrlID = 0;
|
|
|
|
if ( hwnd == hCtrlWnd )
|
|
{
|
|
POINT point;
|
|
|
|
point.x = xPos;
|
|
point.y = yPos;
|
|
if ( ScreenToClient (hwnd, &point) )
|
|
{
|
|
hCtrlWnd = MyChildWindowFromPoint (hwnd, point); // takes client coords
|
|
if ( !hCtrlWnd )
|
|
hCtrlWnd = hwnd;
|
|
}
|
|
}
|
|
|
|
ctrlID = GetDlgCtrlID (hCtrlWnd);
|
|
if ( IDC_SHARE_CACHING == ctrlID || IDC_SHARE_CACHING_TEXT == ctrlID )
|
|
{
|
|
LoadString(g_hInstance, IDS_CSCUI_HELPFILENAME, szHelp, ARRAYLEN(szHelp));
|
|
WinHelp(
|
|
hCtrlWnd,
|
|
szHelp,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)aCSCUIHelpIds);
|
|
}
|
|
else
|
|
{
|
|
LoadString(g_hInstance, IDS_HELPFILENAME, szHelp, ARRAYLEN(szHelp));
|
|
WinHelp(
|
|
hCtrlWnd,
|
|
szHelp,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)aHelpIds);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnPermissions, private
|
|
//
|
|
// Synopsis: WM_COMMAND handler: the permissions button
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnPermissions(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
appAssert(NULL != _pCurInfo);
|
|
if (NULL == _pCurInfo) // JonN 5/2/01 384155
|
|
return TRUE;
|
|
|
|
if (STYPE_SPECIAL & _pCurInfo->GetType())
|
|
{
|
|
MyErrorDialog(hwnd, IERR_AdminShare);
|
|
return TRUE;
|
|
}
|
|
|
|
WCHAR szShareName[NNLEN + 1];
|
|
if (_cShares > 0)
|
|
{
|
|
wcscpy(szShareName, _pCurInfo->GetNetname());
|
|
}
|
|
else
|
|
{
|
|
GetDlgItemText(hwnd, IDC_SHARE_SHARENAME, szShareName, ARRAYLEN(szShareName));
|
|
// don't trim spaces, this might be an existing share with spaces in its name
|
|
}
|
|
|
|
PSECURITY_DESCRIPTOR pNewSecDesc = NULL;
|
|
PSECURITY_DESCRIPTOR pSecDesc = _pCurInfo->GetSecurityDescriptor();
|
|
appAssert(NULL == pSecDesc || IsValidSecurityDescriptor(pSecDesc));
|
|
|
|
BOOL bSecDescChanged;
|
|
LONG err = EditShareAcl(
|
|
hwnd,
|
|
NULL,
|
|
szShareName,
|
|
pSecDesc,
|
|
&bSecDescChanged,
|
|
&pNewSecDesc);
|
|
|
|
if (bSecDescChanged)
|
|
{
|
|
appAssert(IsValidSecurityDescriptor(pNewSecDesc));
|
|
_pCurInfo->TransferSecurityDescriptor(pNewSecDesc);
|
|
_MarkPageDirty();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnRemove, private
|
|
//
|
|
// Synopsis: WM_COMMAND handler: the Remove button
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnRemove(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
appAssert(_cShares > 1);
|
|
appAssert(_pCurInfo != NULL);
|
|
if (NULL == _pCurInfo) // JonN 5/2/01 384155
|
|
return TRUE;
|
|
|
|
//
|
|
// Alter the data structures
|
|
//
|
|
|
|
if (_pCurInfo->GetFlag() == SHARE_FLAG_ADDED)
|
|
{
|
|
// Something that was added this session is being removed: get rid of
|
|
// it from our list.
|
|
|
|
_pCurInfo->Unlink();
|
|
delete _pCurInfo;
|
|
_pCurInfo = NULL;
|
|
// the _SetControlsFromData call resets the _pCurInfo pointer
|
|
}
|
|
else
|
|
{
|
|
// if the state was MODIFY or no state, then set it to REMOVE
|
|
_pCurInfo->SetDirtyFlag(SHARE_FLAG_REMOVE);
|
|
}
|
|
|
|
--_cShares;
|
|
|
|
//
|
|
// Next, regenerate the UI
|
|
//
|
|
|
|
_SetControlsFromData(hwnd, NULL);
|
|
|
|
_MarkPageDirty();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnNewShare, private
|
|
//
|
|
// Synopsis: WM_COMMAND handler: the New Share button
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnNewShare(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
//
|
|
// First, create an object to put the new share into.
|
|
// FEATURE: for out of memory errors, should we pop up an error box?
|
|
//
|
|
|
|
HRESULT hr;
|
|
|
|
CShareInfo* pNewInfo = new CShareInfo();
|
|
if (NULL == pNewInfo)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hr = pNewInfo->InitInstance();
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pNewInfo;
|
|
return FALSE;
|
|
}
|
|
|
|
hr = pNewInfo->SetPath(_pszPath);
|
|
CHECK_HRESULT(hr);
|
|
if (FAILED(hr))
|
|
{
|
|
delete pNewInfo;
|
|
return FALSE;
|
|
}
|
|
|
|
NET_API_STATUS ret = pNewInfo->ReadCacheFlags ();
|
|
if ( NERR_Success != ret )
|
|
{
|
|
delete pNewInfo;
|
|
return HRESULT_FROM_WIN32 (ret);
|
|
}
|
|
|
|
pNewInfo->SetDirtyFlag(SHARE_FLAG_ADDED);
|
|
|
|
CDlgNewShare dlg(hwnd);
|
|
dlg.m_pInfoList = _pInfoList;
|
|
dlg.m_pReplaceList = _pReplaceList;
|
|
dlg.m_pShareInfo = pNewInfo;
|
|
if (dlg.DoModal())
|
|
{
|
|
_ReadControls(hwnd); // read current stuff
|
|
|
|
//
|
|
// Add the new one to the list
|
|
//
|
|
|
|
pNewInfo->InsertBefore(_pInfoList); // add to end of list
|
|
|
|
++_cShares; // one more share in the list...
|
|
|
|
//
|
|
// Next, regenerate the UI
|
|
//
|
|
|
|
_SetControlsFromData(hwnd, pNewInfo->GetNetname());
|
|
|
|
_MarkPageDirty();
|
|
}
|
|
else
|
|
{
|
|
// user hit "cancel"
|
|
delete pNewInfo;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_OnCaching, private
|
|
//
|
|
// Synopsis: WM_COMMAND handler: the Caching button
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_OnCaching(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
// show wait cursor ??
|
|
HINSTANCE hInstance = ::LoadLibrary (L"FileMgmt.dll");
|
|
if ( hInstance )
|
|
{
|
|
typedef HRESULT (*PfnCacheSettingsDlg)(HWND hwndParent, DWORD & dwFlags);
|
|
PfnCacheSettingsDlg pfn = (PfnCacheSettingsDlg) ::GetProcAddress (
|
|
hInstance, "CacheSettingsDlg");
|
|
appAssert( NULL != _pCurInfo );
|
|
if ( pfn && NULL != _pCurInfo) // JonN 5/2/01 384155
|
|
{
|
|
DWORD dwFlags = _pCurInfo->GetCacheFlags ();
|
|
|
|
HRESULT hResult = pfn (hwnd, dwFlags);
|
|
if ( S_OK == hResult )
|
|
{
|
|
_pCurInfo->SetCacheFlags (dwFlags);
|
|
_MarkPageDirty();
|
|
}
|
|
}
|
|
::FreeLibrary (hInstance);
|
|
return FALSE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_InitializeControls, private
|
|
//
|
|
// Synopsis: Initialize the controls from scratch
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_InitializeControls(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
//
|
|
// Set defaults first
|
|
//
|
|
|
|
_SetControlsToDefaults(hwnd);
|
|
|
|
_fInitializingPage++; // JonN 7/11/00 140878
|
|
CheckRadioButton(
|
|
hwnd,
|
|
IDC_SHARE_NOTSHARED,
|
|
IDC_SHARE_SHAREDAS,
|
|
(_cShares > 0) ? IDC_SHARE_SHAREDAS : IDC_SHARE_NOTSHARED);
|
|
_fInitializingPage--; // JonN 7/11/00 140878
|
|
|
|
_SetControlsFromData(hwnd, NULL);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_SetControlsToDefaults, private
|
|
//
|
|
// Synopsis: Set all the controls on the page to their default values
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_SetControlsToDefaults(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
_fInitializingPage++; // JonN 7/11/00 140878
|
|
|
|
// Make "Maximum" the default number of users, and clear the value field
|
|
// (which the spin button set on creation?).
|
|
|
|
CheckRadioButton(
|
|
hwnd,
|
|
IDC_SHARE_MAXIMUM,
|
|
IDC_SHARE_ALLOW,
|
|
IDC_SHARE_MAXIMUM);
|
|
|
|
SetDlgItemText(hwnd, IDC_SHARE_ALLOW_VALUE, L"");
|
|
|
|
// set the spin control range: 1 <--> large number
|
|
SendDlgItemMessage(
|
|
hwnd,
|
|
IDC_SHARE_ALLOW_SPIN,
|
|
UDM_SETRANGE,
|
|
0,
|
|
MAKELONG(g_uiMaxUsers, 1));
|
|
|
|
_HideControls(hwnd, 0);
|
|
|
|
HWND hwndCombo = GetDlgItem(hwnd, IDC_SHARE_SHARENAME_COMBO);
|
|
ComboBox_ResetContent(hwndCombo);
|
|
|
|
SetDlgItemText(hwnd, IDC_SHARE_SHARENAME, L"");
|
|
SetDlgItemText(hwnd, IDC_SHARE_COMMENT, L"");
|
|
SetDlgItemText(hwnd, IDC_SHARE_ALLOW_VALUE, L"");
|
|
|
|
|
|
_fInitializingPage--; // JonN 7/11/00 140878
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::SetControlsFromData, private
|
|
//
|
|
// Synopsis: From the class variables and current state of the radio
|
|
// buttons, set the enabled/disabled state of the buttons, as
|
|
// well as filling the controls with the appropriate values.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_SetControlsFromData(
|
|
IN HWND hwnd,
|
|
IN PWSTR pszPreferredSelection
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
BOOL bIsShared = (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_SHAREDAS));
|
|
|
|
_EnableControls(hwnd, bIsShared);
|
|
|
|
if (bIsShared)
|
|
{
|
|
appDebugOut((DEB_ITRACE, "_SetControlsFromData: path is shared\n"));
|
|
|
|
_HideControls(hwnd, _cShares);
|
|
|
|
//
|
|
// Now, set controls based on actual data
|
|
//
|
|
|
|
_fInitializingPage++; // JonN 7/11/00 140878
|
|
|
|
// if there is a new share, we only show the edit control for the
|
|
// share name, not the combo box.
|
|
|
|
if (_cShares == 0)
|
|
{
|
|
_pCurInfo = (CShareInfo*)_pInfoList->Next();
|
|
appAssert(NULL != _pCurInfo);
|
|
|
|
if (NULL != _pCurInfo) // JonN 5/2/01 384155
|
|
SetDlgItemText(hwnd, IDC_SHARE_SHARENAME, _pCurInfo->GetNetname());
|
|
}
|
|
else // (_cShares > 0)
|
|
{
|
|
// in the combo box, the "item data" is the CShareInfo pointer of
|
|
// the item.
|
|
|
|
// fill the combo.
|
|
|
|
HWND hwndCombo = GetDlgItem(hwnd, IDC_SHARE_SHARENAME_COMBO);
|
|
ComboBox_ResetContent(hwndCombo);
|
|
|
|
for (CShareInfo* p = (CShareInfo*) _pInfoList->Next();
|
|
p != _pInfoList;
|
|
p = (CShareInfo*) p->Next())
|
|
{
|
|
if (p->GetFlag() != SHARE_FLAG_REMOVE)
|
|
{
|
|
int item = ComboBox_AddString(hwndCombo, p->GetNetname());
|
|
if (CB_ERR == item || CB_ERRSPACE == item)
|
|
{
|
|
// FEATURE: how to recover here?
|
|
break;
|
|
}
|
|
|
|
if (CB_ERR == ComboBox_SetItemData(hwndCombo, item, p))
|
|
{
|
|
// FEATURE: how to recover here?
|
|
}
|
|
}
|
|
}
|
|
|
|
int sel = 0;
|
|
if (NULL != pszPreferredSelection)
|
|
{
|
|
sel = ComboBox_FindStringExact(hwndCombo, -1, pszPreferredSelection);
|
|
if (CB_ERR == sel)
|
|
{
|
|
sel = 0;
|
|
}
|
|
}
|
|
ComboBox_SetCurSel(hwndCombo, sel);
|
|
|
|
_pCurInfo = (CShareInfo*)ComboBox_GetItemData(hwndCombo, sel);
|
|
appAssert(NULL != _pCurInfo);
|
|
}
|
|
|
|
_fInitializingPage--; // JonN 7/11/00 140878
|
|
|
|
// From the current item, set the rest of the fields
|
|
|
|
_SetFieldsFromCurrent(hwnd);
|
|
|
|
// This must be called after the share name field is initialized.
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SHARE_CACHING), IsCachingSupported ());
|
|
}
|
|
else
|
|
{
|
|
appDebugOut((DEB_ITRACE, "_SetControlsFromData: path is not shared\n"));
|
|
_pCurInfo = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_EnableControls, private
|
|
//
|
|
// Synopsis: Enable/disable controls
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_EnableControls(
|
|
IN HWND hwnd,
|
|
IN BOOL bEnable
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
int idControls[] =
|
|
{
|
|
IDC_SHARE_SHARENAME_TEXT,
|
|
IDC_SHARE_SHARENAME,
|
|
IDC_SHARE_SHARENAME_COMBO,
|
|
IDC_SHARE_COMMENT_TEXT,
|
|
IDC_SHARE_COMMENT,
|
|
IDC_SHARE_LIMIT,
|
|
IDC_SHARE_MAXIMUM,
|
|
IDC_SHARE_ALLOW,
|
|
IDC_SHARE_ALLOW_SPIN,
|
|
IDC_SHARE_ALLOW_VALUE,
|
|
IDC_SHARE_REMOVE,
|
|
IDC_SHARE_NEWSHARE,
|
|
IDC_SHARE_PERMISSIONS
|
|
};
|
|
|
|
for (int i = 0; i < ARRAYLEN(idControls); i++)
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, idControls[i]), bEnable);
|
|
}
|
|
|
|
EnableWindow(GetDlgItem(hwnd, IDC_SHARE_CACHING),
|
|
bEnable && IsCachingSupported ());
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_HideControls, private
|
|
//
|
|
// Synopsis: Hide or show the controls based on the current number
|
|
// of shares.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_HideControls(
|
|
IN HWND hwnd,
|
|
IN int cShares
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
_MyShow( hwnd, IDC_SHARE_REMOVE, !!(cShares > 1) );
|
|
_MyShow( hwnd, IDC_SHARE_NEWSHARE, !!(cShares >= 1) );
|
|
_MyShow( hwnd, IDC_SHARE_SHARENAME, !!(cShares < 1) );
|
|
_MyShow( hwnd, IDC_SHARE_SHARENAME_COMBO, !!(cShares >= 1) );
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_SetFieldsFromCurrent, private
|
|
//
|
|
// Synopsis: From the currently selected share, set the property page
|
|
// controls.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_SetFieldsFromCurrent(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
appAssert(NULL != _pCurInfo);
|
|
|
|
_fInitializingPage++; // JonN 7/11/00 140878
|
|
|
|
SetDlgItemText(hwnd, IDC_SHARE_COMMENT,
|
|
(NULL == _pCurInfo) ? L'\0' : _pCurInfo->GetRemark());
|
|
|
|
DWORD dwLimit = (NULL == _pCurInfo) // JonN 5/2/01 384155
|
|
? SHI_USES_UNLIMITED : _pCurInfo->GetMaxUses();
|
|
if (dwLimit == SHI_USES_UNLIMITED)
|
|
{
|
|
_wMaxUsers = DEFAULT_MAX_USERS;
|
|
|
|
appDebugOut((DEB_ITRACE, "_SetFieldsFromCurrent: unlimited users\n"));
|
|
|
|
CheckRadioButton(
|
|
hwnd,
|
|
IDC_SHARE_MAXIMUM,
|
|
IDC_SHARE_ALLOW,
|
|
IDC_SHARE_MAXIMUM);
|
|
|
|
SetDlgItemText(hwnd, IDC_SHARE_ALLOW_VALUE, L"");
|
|
}
|
|
else
|
|
{
|
|
_wMaxUsers = (WORD)dwLimit;
|
|
|
|
appDebugOut((DEB_ITRACE,
|
|
"_SetFieldsFromCurrent: max users = %d\n",
|
|
_wMaxUsers));
|
|
|
|
CheckRadioButton(
|
|
hwnd,
|
|
IDC_SHARE_MAXIMUM,
|
|
IDC_SHARE_ALLOW,
|
|
IDC_SHARE_ALLOW);
|
|
|
|
// let the spin control set the edit control
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_SETPOS, 0, MAKELONG(_wMaxUsers, 0));
|
|
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
|
|
}
|
|
|
|
_fInitializingPage--; // JonN 7/11/00 140878
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_ReadControls, private
|
|
//
|
|
// Synopsis: Load the data in the controls into internal data structures.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_ReadControls(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
if (!_bItemDirty)
|
|
{
|
|
// nothing to read
|
|
appDebugOut((DEB_ITRACE, "_ReadControls: item not dirty\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
appDebugOut((DEB_ITRACE, "_ReadControls: item dirty\n"));
|
|
appAssert(NULL != _pCurInfo);
|
|
if (NULL == _pCurInfo) // JonN 5/2/01 384155
|
|
return TRUE;
|
|
|
|
if (_bShareNameChanged)
|
|
{
|
|
appDebugOut((DEB_ITRACE, "_ReadControls: share name changed\n"));
|
|
|
|
WCHAR szShareName[NNLEN + 1];
|
|
GetDlgItemText(hwnd, IDC_SHARE_SHARENAME, szShareName, ARRAYLEN(szShareName));
|
|
TrimLeadingAndTrailingSpaces(szShareName);
|
|
_pCurInfo->SetNetname(szShareName);
|
|
_bShareNameChanged = FALSE;
|
|
}
|
|
|
|
if (_bCommentChanged)
|
|
{
|
|
appDebugOut((DEB_ITRACE, "_ReadControls: comment changed\n"));
|
|
|
|
WCHAR szComment[MAXCOMMENTSZ + 1];
|
|
GetDlgItemText(hwnd, IDC_SHARE_COMMENT, szComment, ARRAYLEN(szComment));
|
|
_pCurInfo->SetRemark(szComment);
|
|
_bCommentChanged = FALSE;
|
|
}
|
|
|
|
if (_bUserLimitChanged)
|
|
{
|
|
appDebugOut((DEB_ITRACE, "_ReadControls: user limit changed\n"));
|
|
|
|
if (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_MAXIMUM))
|
|
{
|
|
_pCurInfo->SetMaxUses(SHI_USES_UNLIMITED);
|
|
}
|
|
else if (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_ALLOW))
|
|
{
|
|
_CacheMaxUses(hwnd);
|
|
_pCurInfo->SetMaxUses(_wMaxUsers);
|
|
}
|
|
_bUserLimitChanged = FALSE;
|
|
}
|
|
|
|
_bItemDirty = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_MarkItemDirty, private
|
|
//
|
|
// Synopsis: A change has made such that the current item (and page)
|
|
// is now dirty
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_MarkItemDirty(
|
|
VOID
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
if (!_fInitializingPage)
|
|
{
|
|
if (!_bItemDirty)
|
|
{
|
|
appDebugOut((DEB_ITRACE, "Marking Sharing page---current item---dirty\n"));
|
|
_bItemDirty = TRUE;
|
|
}
|
|
|
|
_MarkPageDirty();
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_ValidatePage, private
|
|
//
|
|
// Synopsis: Return TRUE if the current page is valid
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_ValidatePage(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
_ReadControls(hwnd); // read current stuff
|
|
|
|
if (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_SHAREDAS))
|
|
{
|
|
// If the user is creating a share on the property sheet (as
|
|
// opposed to using the "new share" dialog), we must validate the
|
|
// share.... Note that _bNewShare is still TRUE if the the user has
|
|
// clicked on "Not Shared", so we must check that too.
|
|
|
|
// Validate the share
|
|
|
|
if (!_ValidateNewShareName())
|
|
{
|
|
SetErrorFocus(hwnd, IDC_SHARE_SHARENAME);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
#if DBG == 1
|
|
Dump(L"_ValidatePage finished");
|
|
#endif // DBG == 1
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_DoApply, public
|
|
//
|
|
// Synopsis: If anything has changed, apply the data
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_DoApply(
|
|
IN HWND hwnd,
|
|
IN BOOL bClose
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
if (_bDirty)
|
|
{
|
|
BOOL bNotShared = (1 == IsDlgButtonChecked(hwnd, IDC_SHARE_NOTSHARED));
|
|
|
|
if (!bNotShared)
|
|
{
|
|
_ReadControls(hwnd);
|
|
}
|
|
|
|
_CommitShares(bNotShared);
|
|
|
|
CShareBase::_DoApply(hwnd, bClose);
|
|
|
|
if (!bClose)
|
|
{
|
|
_InitializeControls(hwnd);
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_DoCancel, public
|
|
//
|
|
// Synopsis: Do whatever is necessary to cancel the changes
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
CSharingPropertyPage::_DoCancel(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
if (_bDirty)
|
|
{
|
|
_bItemDirty = FALSE;
|
|
_bShareNameChanged = FALSE;
|
|
_bCommentChanged = FALSE;
|
|
_bUserLimitChanged = FALSE;
|
|
}
|
|
|
|
return CShareBase::_DoCancel(hwnd);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::_CacheMaxUses, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
CSharingPropertyPage::_CacheMaxUses(
|
|
IN HWND hwnd
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
DWORD dwRet = (DWORD)SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_GETPOS, 0, 0);
|
|
if (HIWORD(dwRet) != 0)
|
|
{
|
|
_wMaxUsers = DEFAULT_MAX_USERS;
|
|
|
|
// Reset the edit control to the new value
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_SPIN, UDM_SETPOS, 0, MAKELONG(_wMaxUsers, 0));
|
|
SendDlgItemMessage(hwnd, IDC_SHARE_ALLOW_VALUE, EM_SETSEL, 0, (LPARAM)-1);
|
|
}
|
|
else
|
|
{
|
|
_wMaxUsers = LOWORD(dwRet);
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::IsCachingSupported
|
|
//
|
|
// Synopsis: Does the operating system support caching on this share?
|
|
// This method initializes _bIsCachingSupported, if it is not already true
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
bool CSharingPropertyPage::IsCachingSupported()
|
|
{
|
|
if (!_bIsCachingSupported)
|
|
{
|
|
LPWSTR pszShareName = 0;
|
|
WCHAR szShareName[NNLEN + 1];
|
|
UINT nRet = GetDlgItemText (_hwndPage, IDC_SHARE_SHARENAME, szShareName,
|
|
ARRAYLEN(szShareName));
|
|
if ( nRet > 0 )
|
|
pszShareName = szShareName;
|
|
else if ( _pCurInfo )
|
|
pszShareName = _pCurInfo->GetNetname ();
|
|
|
|
if ( pszShareName )
|
|
{
|
|
SHARE_INFO_501* pshi501 = NULL;
|
|
//
|
|
// On pre-NT5 systems (per IsaacHe), NetShareGetInfo will return
|
|
// ERROR_INVALID_LEVEL for info level 501 regardless of the share
|
|
// name provided. This is because the net code validates the
|
|
// requested level *before* validating the share name.
|
|
// Therefore, passing a blank share name works for our purposes
|
|
// here. If NetShareGetInfo returns ERROR_INVALID_LEVEL, this
|
|
// means level 501 is not supported which means the system
|
|
// isn't NT5 which means caching is not supported. No need to
|
|
// query the contents of *pshi501 because we're not interested in
|
|
// the level of caching at this point. [brianau - 8/11/98]
|
|
//
|
|
NET_API_STATUS retval = ::NetShareGetInfo(
|
|
L"", // machine name
|
|
L"", // share name
|
|
501,
|
|
(LPBYTE*)&pshi501);
|
|
|
|
if (ERROR_INVALID_LEVEL != retval)
|
|
{
|
|
_bIsCachingSupported = true;
|
|
}
|
|
if ( pshi501 )
|
|
{
|
|
::NetApiBufferFree (pshi501);
|
|
}
|
|
}
|
|
}
|
|
|
|
return _bIsCachingSupported;
|
|
}
|
|
|
|
|
|
#if DBG == 1
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Method: CSharingPropertyPage::Dump, private
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
CSharingPropertyPage::Dump(
|
|
IN PWSTR pszCaption
|
|
)
|
|
{
|
|
CHECK_SIG(CSharingPropertyPage);
|
|
|
|
appDebugOut((DEB_TRACE,
|
|
"CSharingPropertyPage::Dump, %ws\n",
|
|
pszCaption));
|
|
|
|
appDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
|
|
"\t This: 0x%08lx\n"
|
|
"\t Path: %ws\n"
|
|
"\t Page: 0x%08lx\n"
|
|
"\t Initializing?: %ws\n"
|
|
"\t Dirty?: %ws\n"
|
|
"\t Item dirty?: %ws\n"
|
|
"\t Share changed?: %ws\n"
|
|
"\tComment changed?: %ws\n"
|
|
"\tUsr Lim changed?: %ws\n"
|
|
"\t Max uses: %d\n"
|
|
"\t _pInfoList: 0x%08lx\n"
|
|
"\t _pCurInfo: 0x%08lx\n"
|
|
"\t Shares: %d\n"
|
|
,
|
|
this,
|
|
_pszPath,
|
|
_hwndPage,
|
|
_fInitializingPage ? L"yes" : L"no",
|
|
_bDirty ? L"yes" : L"no",
|
|
_bItemDirty ? L"yes" : L"no",
|
|
_bShareNameChanged ? L"yes" : L"no",
|
|
_bCommentChanged ? L"yes" : L"no",
|
|
_bUserLimitChanged ? L"yes" : L"no",
|
|
_wMaxUsers,
|
|
_pInfoList,
|
|
_pCurInfo,
|
|
_cShares
|
|
));
|
|
|
|
CShareInfo* p;
|
|
|
|
for (p = (CShareInfo*) _pInfoList->Next();
|
|
p != _pInfoList;
|
|
p = (CShareInfo*) p->Next())
|
|
{
|
|
p->Dump(L"Prop page list");
|
|
}
|
|
|
|
for (p = (CShareInfo*) _pReplaceList->Next();
|
|
p != _pReplaceList;
|
|
p = (CShareInfo*) p->Next())
|
|
{
|
|
p->Dump(L"Replace list");
|
|
}
|
|
}
|
|
|
|
#endif // DBG == 1
|
|
|