windows-nt/Source/XPSP1/NT/admin/snapin/filemgmt/sfmutil.cpp
2020-09-26 16:20:57 +08:00

517 lines
14 KiB
C++

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corp., 1997 **/
/**********************************************************************/
/*
sfmutil.cpp
Misc utility routines for SFM dialogs/property pages
FILE HISTORY:
8/20/97 ericdav Code moved into file managemnet snapin
*/
#include "stdafx.h"
#include "sfmutil.h"
#include "sfmcfg.h"
#include "sfmsess.h"
#include "sfmfasoc.h"
#include "macros.h" // MFC_TRY/MFC_CATCH
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
TCHAR c_szSoftware[] = _T("Software");
TCHAR c_szMicrosoft[] = _T("Microsoft");
TCHAR c_szWindowsNT[] = _T("Windows NT");
TCHAR c_szCurrentVersion[] = _T("CurrentVersion");
ULONG arrayHelpIDs_CONFIGURE_SFM[]=
{
IDC_BUTTON_ADD, HIDC_BUTTON_ADD, // File Association: "A&dd..." (Button)
IDC_BUTTON_EDIT, HIDC_BUTTON_EDIT, // File Association: "&Edit..." (Button)
IDC_COMBO_CREATOR, HIDC_COMBO_CREATOR, // Add Document Type: "" (ComboBox)
IDC_BUTTON_DELETE, HIDC_BUTTON_DELETE, // File Association: "De&lete" (Button)
IDC_BUTTON_ASSOCIATE, HIDC_BUTTON_ASSOCIATE, // File Association: "&Associate" (Button)
IDC_COMBO_FILE_TYPE, HIDC_COMBO_FILE_TYPE, // Add Document Type: "" (ComboBox)
IDC_LIST_TYPE_CREATORS, HIDC_LIST_TYPE_CREATORS, // File Association: "" (ListBox)
IDC_EDIT_LOGON_MESSAGE, HIDC_EDIT_LOGON_MESSAGE, // Configuration: "" (Edit)
IDC_COMBO_AUTHENTICATION, HIDC_COMBO_AUTHENTICATION, // Configuration: "Authentication type combo box"
IDC_CHECK_SAVE_PASSWORD, HIDC_CHECK_SAVE_PASSWORD, // Configuration: "Allow &Workstations to Save Password" (Button)
IDC_RADIO_SESSION_UNLIMITED,HIDC_RADIO_SESSION_UNLIMITED,// Configuration: "&Unlimited" (Button)
IDC_RADIO_SESSSION_LIMIT, HIDC_RADIO_SESSSION_LIMIT, // Configuration: "Li&mit to" (Button)
IDC_BUTTON_SEND, HIDC_BUTTON_SEND, // Sessions: "&Send" (Button)
IDC_EDIT_MESSAGE, HIDC_EDIT_MESSAGE, // Sessions: "" (Edit)
IDC_STATIC_SESSIONS, HIDC_STATIC_SESSIONS, // Sessions: "Static" (Static)
IDC_EDIT_DESCRIPTION, HIDC_EDIT_DESCRIPTION, // Add Document Type: "" (Edit)
IDC_STATIC_FORKS, HIDC_STATIC_FORKS, // Sessions: "Static" (Static)
IDC_STATIC_FILE_LOCKS, HIDC_STATIC_FILE_LOCKS, // Sessions: "Static" (Static)
IDC_STATIC_CREATOR, HIDC_STATIC_CREATOR, // Edit Document Type: "Static" (Static)
IDC_EDIT_SERVER_NAME, HIDC_EDIT_SERVER_NAME, // Configuration: "" (Edit)
IDC_COMBO_EXTENSION, HIDC_COMBO_EXTENSION, // File Association: "" (ComboBox)
IDC_EDIT_SESSION_LIMIT, HIDC_EDIT_SESSION_LIMIT, // Configuration: "0" (Edit)
IDC_SFM_EDIT_PASSWORD, HIDC_SFM_EDIT_PASSWORD,
IDC_SFM_CHECK_READONLY, HIDC_SFM_CHECK_READONLY,
IDC_SFM_CHECK_GUESTS, HIDC_SFM_CHECK_GUESTS,
(ULONG)IDC_STATIC, (ULONG)-1,
0, 0
};
// these are the only controls we care about....
const ULONG_PTR g_aHelpIDs_CONFIGURE_SFM = (ULONG_PTR)&arrayHelpIDs_CONFIGURE_SFM[0];
USE_HANDLE_MACROS("FILEMGMT(sfmutil.cpp)")
HRESULT
GetErrorMessageFromModule(
IN DWORD dwError,
IN LPCTSTR lpszDll,
OUT LPTSTR *ppBuffer
)
{
if (0 == dwError || !lpszDll || !*lpszDll || !ppBuffer)
return E_INVALIDARG;
HRESULT hr = S_OK;
HINSTANCE hMsgLib = LoadLibrary(lpszDll);
if (!hMsgLib)
hr = HRESULT_FROM_WIN32(GetLastError());
else
{
DWORD dwRet = ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
hMsgLib, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)ppBuffer, 0, NULL);
if (0 == dwRet)
hr = HRESULT_FROM_WIN32(GetLastError());
FreeLibrary(hMsgLib);
}
return hr;
}
HRESULT
GetErrorMessage(
IN DWORD i_dwError,
OUT CString& cstrErrorMsg
)
{
if (0 == i_dwError)
return E_INVALIDARG;
HRESULT hr = S_OK;
LPTSTR lpBuffer = NULL;
DWORD dwRet = ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, i_dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpBuffer, 0, NULL);
if (0 == dwRet)
{
// if no message is found, GetLastError will return ERROR_MR_MID_NOT_FOUND
hr = HRESULT_FROM_WIN32(GetLastError());
if (HRESULT_FROM_WIN32(ERROR_MR_MID_NOT_FOUND) == hr ||
0x80070000 == (i_dwError & 0xffff0000) ||
0 == (i_dwError & 0xffff0000) )
{
hr = GetErrorMessageFromModule((i_dwError & 0x0000ffff), _T("netmsg.dll"), &lpBuffer);
if (HRESULT_FROM_WIN32(ERROR_MR_MID_NOT_FOUND) == hr)
{
int iError = i_dwError; // convert to a signed integer
if (iError >= AFPERR_MIN && iError < AFPERR_BASE)
{
// use a positive number to search sfmmsg.dll
hr = GetErrorMessageFromModule(-iError, _T("sfmmsg.dll"), &lpBuffer);
}
}
}
}
if (SUCCEEDED(hr))
{
cstrErrorMsg = lpBuffer;
LocalFree(lpBuffer);
}
else
{
// we failed to retrieve the error message from system/netmsg.dll/sfmmsg.dll,
// report the error code directly to user
hr = S_OK;
cstrErrorMsg.Format(_T("0x%x"), i_dwError);
}
return S_OK;
}
void SFMMessageBox(DWORD dwErrCode)
{
HRESULT hr = S_OK;
CString strMessage;
if (!dwErrCode)
return; // not expected
hr = GetErrorMessage(dwErrCode, strMessage);
if (FAILED(hr))
{
// Failed to retrieve the proper message, report the failure directly to user
strMessage.Format(_T("0x%x"), hr);
}
AfxMessageBox(strMessage);
}
BOOL CALLBACK EnumThreadWndProc(HWND hwnd, /* enumerated HWND */
LPARAM lParam /* pass a HWND* for return value*/ )
{
_ASSERTE(hwnd);
HWND hParentWnd = GetParent(hwnd);
// the main window of the MMC console should staitsfy this condition
if ( ((hParentWnd == GetDesktopWindow()) || (hParentWnd == NULL)) && IsWindowVisible(hwnd) )
{
HWND* pH = (HWND*)lParam;
*pH = hwnd;
return FALSE; // stop enumerating
}
return TRUE;
}
HWND FindMMCMainWindow()
{
DWORD dwThreadID = ::GetCurrentThreadId();
_ASSERTE(dwThreadID != 0);
HWND hWnd = NULL;
BOOL bEnum = EnumThreadWindows(dwThreadID, EnumThreadWndProc,(LPARAM)&hWnd);
_ASSERTE(hWnd != NULL);
return hWnd;
}
/////////////////////////////////////////////////////////////////////
// Constructor for CSFMPropertySheet object
CSFMPropertySheet::CSFMPropertySheet()
{
m_pPageConfig = new CMacFilesConfiguration;
m_pPageConfig->m_pSheet = this;
m_pPageSessions = new CMacFilesSessions;
m_pPageSessions->m_pSheet = this;
m_pPageFileAssoc = new CMacFilesFileAssociation;
m_pPageFileAssoc->m_pSheet = this;
m_hSheetWindow = NULL;
m_hThread = NULL;
m_nRefCount =1;
} // CServicePropertyData::CServicePropertyData()
CSFMPropertySheet::~CSFMPropertySheet()
{
delete m_pPageConfig;
delete m_pPageSessions;
delete m_pPageFileAssoc;
if (m_hDestroySync)
{
CloseHandle(m_hDestroySync);
m_hDestroySync = NULL;
}
} // CServicePropertyData::~CServicePropertyData()
BOOL
CSFMPropertySheet::FInit
(
LPDATAOBJECT lpDataObject,
AFP_SERVER_HANDLE hAfpServer,
LPCTSTR pSheetTitle,
SfmFileServiceProvider * pSfmProvider,
LPCTSTR pMachine
)
{
m_spDataObject = lpDataObject;
m_strTitle = pSheetTitle;
m_hAfpServer = hAfpServer;
m_pSfmProvider = pSfmProvider;
m_strHelpFilePath = _T("sfmmgr.hlp"); // does not need to be localized
m_strMachine = pMachine;
m_hDestroySync = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (!m_hDestroySync)
return FALSE;
return TRUE;
}
BOOL
CSFMPropertySheet::DoModelessSheet(LPDATAOBJECT pDataObject)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
LPPROPERTYSHEETCALLBACK pCallback = NULL;
LPPROPERTYSHEETPROVIDER pProvider = NULL;
HPROPSHEETPAGE hPage;
HRESULT hr = S_OK;
HWND hWnd;
BOOL bReturn = TRUE;
// get the property sheet provider interface
hr = ::CoCreateInstance(CLSID_NodeManager, NULL, CLSCTX_INPROC,
IID_IPropertySheetProvider, reinterpret_cast<void **>(&pProvider));
if (FAILED(hr))
return FALSE;
_ASSERTE(pProvider != NULL);
// get an interface to a sheet callback
hr = pProvider->QueryInterface(IID_IPropertySheetCallback, (void**) &pCallback);
if (FAILED(hr))
{
bReturn = FALSE;
goto Error;
}
_ASSERTE(pCallback != NULL);
// create sheet
hr = pProvider->CreatePropertySheet(m_strTitle,
TRUE /* prop page */,
NULL,
//m_spDataObject,
pDataObject,
0);
// add pages to sheet - config
MMCPropPageCallback(INOUT &m_pPageConfig->m_psp);
hPage = MyCreatePropertySheetPage(IN &m_pPageConfig->m_psp);
Report(hPage != NULL);
if (hPage != NULL)
pCallback->AddPage(hPage);
// now the Sessions page
MMCPropPageCallback(INOUT &m_pPageFileAssoc->m_psp);
hPage = MyCreatePropertySheetPage(IN &m_pPageFileAssoc->m_psp);
Report(hPage != NULL);
if (hPage != NULL)
pCallback->AddPage(hPage);
// finally the File Association page
MMCPropPageCallback(INOUT &m_pPageSessions->m_psp);
hPage = MyCreatePropertySheetPage(IN &m_pPageSessions->m_psp);
Report(hPage != NULL);
if (hPage != NULL)
pCallback->AddPage(hPage);
// add pages
hr = pProvider->AddPrimaryPages(NULL, FALSE, NULL, FALSE);
if (FAILED(hr))
{
bReturn = FALSE;
goto Error;
}
hWnd = ::FindMMCMainWindow();
_ASSERTE(hWnd != NULL);
hr = pProvider->Show((LONG_PTR) hWnd, 0);
if (FAILED(hr))
{
bReturn = FALSE;
goto Error;
}
Error:
if (pCallback)
pCallback->Release();
if (pProvider)
pProvider->Release();
// release our data object... we don't need it anymore
m_spDataObject = NULL;
return bReturn;
}
int
CSFMPropertySheet::AddRef()
{
return ++m_nRefCount;
}
int
CSFMPropertySheet::Release()
{
int nRefCount = --m_nRefCount;
if (nRefCount == 0)
Destroy();
return nRefCount;
}
void
CSFMPropertySheet::SetSheetWindow
(
HWND hSheetWindow
)
{
if (m_hSheetWindow && !hSheetWindow)
{
// The Property Sheet is going away. Notify the provider so it can release
// any references to the object.
if (m_pSfmProvider)
m_pSfmProvider->SetSfmPropSheet(NULL);
}
m_hSheetWindow = hSheetWindow;
if (!m_hThread)
{
HANDLE hPseudohandle;
hPseudohandle = GetCurrentThread();
BOOL bRet = DuplicateHandle(GetCurrentProcess(),
hPseudohandle,
GetCurrentProcess(),
&m_hThread,
0,
FALSE,
DUPLICATE_SAME_ACCESS);
if (!bRet)
{
DWORD dwLastErr = GetLastError();
}
TRACE(_T("SfmProperty Sheet - Thread ID = %lx\n"), GetCurrentThreadId());
}
}
void
CSFMPropertySheet::Destroy()
{
m_hSheetWindow = NULL;
delete this;
}
void
CSFMPropertySheet::CancelSheet()
{
HWND hSheetWindow = m_hSheetWindow;
if (hSheetWindow != NULL)
{
// this message will cause the sheet to close all the pages,
// and eventually the destruction of "this"
VERIFY(::PostMessage(hSheetWindow, WM_COMMAND, IDCANCEL, 0L) != 0);
}
// now, if we've been initialized then wait for the property sheet thread
// to terminate. The property sheet provider is holding onto our dataobject
// that needs to be freed up before we can continue our cleanup.
if (m_hThread)
{
DWORD dwRet;
MSG msg;
while(1)
{
dwRet = MsgWaitForMultipleObjects(1, &m_hThread, FALSE, INFINITE, QS_ALLINPUT);
if (dwRet == WAIT_OBJECT_0)
return; // The event was signaled
if (dwRet != WAIT_OBJECT_0 + 1)
break; // Something else happened
// There is one or more window message available. Dispatch them
while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (WaitForSingleObject(m_hThread, 0) == WAIT_OBJECT_0)
return; // Event is now signaled.
}
}
}
}
/*!--------------------------------------------------------------------------
IsNT5Machine
-
Author: EricDav
---------------------------------------------------------------------------*/
DWORD
CSFMPropertySheet::IsNT5Machine(LPCTSTR pszMachine, BOOL *pfNt4)
{
// Look at the HKLM\Software\Microsoft\Windows NT\CurrentVersion
// CurrentVersion = REG_SZ "5.0"
CString skey;
DWORD dwErr = ERROR_SUCCESS;
TCHAR szVersion[64];
HKEY hkeyMachine, hKey;
DWORD dwType = REG_SZ;
DWORD dwSize = sizeof(szVersion);
if (!pszMachine || !lstrlen(pszMachine))
{
hkeyMachine = HKEY_LOCAL_MACHINE;
}
else
{
//
// Make the connection
//
dwErr = ::RegConnectRegistry(
(LPTSTR)pszMachine, HKEY_LOCAL_MACHINE, &hkeyMachine
);
}
if (dwErr != ERROR_SUCCESS)
return dwErr;
ASSERT(pfNt4);
skey = c_szSoftware;
skey += TEXT('\\');
skey += c_szMicrosoft;
skey += TEXT('\\');
skey += c_szWindowsNT;
skey += TEXT('\\');
skey += c_szCurrentVersion;
dwErr = ::RegOpenKeyEx( hkeyMachine, skey, 0, KEY_READ, & hKey ) ;
if (dwErr != ERROR_SUCCESS)
return dwErr;
// Ok, now try to get the current version value
dwErr = ::RegQueryValueEx( hKey,
c_szCurrentVersion,
0,
&dwType,
(LPBYTE) szVersion,
&dwSize ) ;
if (dwErr == ERROR_SUCCESS)
{
*pfNt4 = ((szVersion[0] == _T('5')) && (szVersion[1] == _T('.')));
}
::RegCloseKey( hKey );
if (hkeyMachine != HKEY_LOCAL_MACHINE)
::RegCloseKey( hkeyMachine );
return dwErr;
}