|
|
/*++
Module Name:
Utils.cpp
Abstract:
This module contains the declaration for CWaitCursor class. Contains utility methods which are used throughout the project.
--*/
#include "stdafx.h"
#include "resource.h"
#include "Utils.h"
#include "netutils.h"
#include <dns.h>
HRESULT CWaitCursor::SetStandardCursor( IN LPCTSTR i_lpCursorName ) /*++
Routine Description:
This method sets the cursor to the standard cursor specified. Usage: SetStandardCursor(IDC_WAIT)
Arguments:
i_lpCursorName - The name of a standard cursor, IDC_WAIT, IDC_ARROW.
--*/ { RETURN_INVALIDARG_IF_NULL(i_lpCursorName);
HCURSOR m_hcur = ::LoadCursor(NULL, i_lpCursorName); if (!m_hcur) return HRESULT_FROM_WIN32(GetLastError());
::ShowCursor(FALSE); SetCursor(m_hcur); ::ShowCursor(TRUE);
return S_OK; }
BOOL Is256ColorSupported( VOID ) { /*++
Routine Description:
Determines whether the display supports 256 colors.
Arguments:
None
Return value:
TRUE if display supports 256 colors FALSE if not.
--*/
BOOL bRetval = FALSE;
HDC hdc = ::GetDC(NULL);
if( hdc ) { if( ::GetDeviceCaps( hdc, BITSPIXEL ) >= 8 ) { bRetval = TRUE; } ::ReleaseDC(NULL, hdc); } return bRetval; }
VOID SetControlFont( IN HFONT hFont, IN HWND hwnd, IN INT nId ) { /*++
Routine Description:
Sets the text font of a dialog control to the input font.
Arguments:
hFont - The font to use.
hwnd - The parent dialog window.
nId - The control Id.
Return value:
None
--*/ if( hFont ) { HWND hwndControl = ::GetDlgItem(hwnd, nId);
if( hwndControl ) ::SendMessage(hwndControl, WM_SETFONT, (WPARAM) hFont, MAKELPARAM(TRUE, 0)); } }
VOID SetupFonts( IN HINSTANCE hInstance, IN HWND hwnd, IN HFONT *pBigBoldFont, IN HFONT *pBoldFont ) { /*++
Routine Description:
Creates fonts for Wizard Titles.
Arguments:
hInstance - The module instance.
hwnd - The dialog window.
pBigBoldFont- The font for large title.
pBoldFont - The font for small title.
Return value:
None
--*/ NONCLIENTMETRICS ncm = {0}; ncm.cbSize = sizeof(ncm); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
LOGFONT BigBoldLogFont = ncm.lfMessageFont; LOGFONT BoldLogFont = ncm.lfMessageFont;
// Create Big Bold Font and Bold Font
BigBoldLogFont.lfWeight = FW_BOLD; BoldLogFont.lfWeight = FW_BOLD;
TCHAR FontSizeString[24]; INT FontSize;
// Load size and name from resources, since these may change
// from locale to locale based on the size of the system font, etc.
if(!LoadString(hInstance,IDS_LARGEFONTNAME,BigBoldLogFont.lfFaceName,LF_FACESIZE)) { lstrcpy(BigBoldLogFont.lfFaceName,TEXT("MS Shell Dlg")); }
if(LoadString(hInstance,IDS_LARGEFONTSIZE,FontSizeString,sizeof(FontSizeString)/sizeof(TCHAR))) { FontSize = _tcstoul( FontSizeString, NULL, 10 ); } else { FontSize = 18; }
HDC hdc = ::GetDC( hwnd );
if( hdc ) { BigBoldLogFont.lfHeight = 0 - (GetDeviceCaps(hdc,LOGPIXELSY) * FontSize / 72);
if (pBigBoldFont) *pBigBoldFont = CreateFontIndirect(&BigBoldLogFont);
if (pBoldFont) *pBoldFont = CreateFontIndirect(&BoldLogFont);
::ReleaseDC(hwnd,hdc); } }
VOID DestroyFonts( IN HFONT hBigBoldFont, IN HFONT hBoldFont ) { /*++
Routine Description:
Creates fonts for Wizard Titles.
Arguments:
hBigBoldFont- The font for large title.
hBoldFont - The font for small title.
Return value:
None
--*/
if( hBigBoldFont ) { DeleteObject( hBigBoldFont ); }
if( hBoldFont ) { DeleteObject( hBoldFont ); } }
HRESULT LoadStringFromResource( IN const UINT i_uResourceID, OUT BSTR* o_pbstrReadValue ) /*++
Routine Description:
This method returns a resource string. The method no longer uses a fixed string to read the resource. Inspiration from MFC's CString::LoadString.
Arguments: i_uResourceID - The resource id o_pbstrReadValue - The BSTR* into which the value is copied
--*/ { RETURN_INVALIDARG_IF_NULL(o_pbstrReadValue);
TCHAR szResString[1024]; ULONG uCopiedLen = 0; szResString[0] = NULL; // Read the string from the resource
uCopiedLen = ::LoadString(_Module.GetModuleInstance(), i_uResourceID, szResString, 1024);
// If nothing was copied it is flagged as an error
if(uCopiedLen <= 0) { return HRESULT_FROM_WIN32(::GetLastError()); } else { *o_pbstrReadValue = ::SysAllocString(szResString); if (!*o_pbstrReadValue) return E_OUTOFMEMORY; }
return S_OK; }
HRESULT FormatResourceString( IN const UINT i_uResourceID, IN LPCTSTR i_szFirstArg, OUT BSTR* o_pbstrReadString ) /*++
Routine Description:
Reads a string from resource, puts the argument into this string and returns it. The returned string should be freed using SysFreeString.
Arguments:
i_uResourceID - The resource id of the string to be read. This string should contain a %1 to allow us to insert the argument
i_szFirstArg - The argument to be inserted
o_pbstrReadString - The string that is returned by the method after processing --*/ { RETURN_INVALIDARG_IF_NULL(i_szFirstArg); RETURN_INVALIDARG_IF_NULL(o_pbstrReadString);
CComBSTR bstrResString; LPTSTR lpszFormatedMessage = NULL;
HRESULT hr = LoadStringFromResource(i_uResourceID, &bstrResString); RETURN_IF_FAILED(hr); // Create a new string using the argument and the res string
int iBytes = ::FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER, // Format a string with %1, %2, etc
bstrResString, // Input buffer with a %1
0, // Message id. None
0, // Language id. Nothing particular
(LPTSTR)&lpszFormatedMessage, // Output buffer
0, (va_list*)&i_szFirstArg // List of arguments. Only 1 right now
);
if (0 == iBytes) { return HRESULT_FROM_WIN32(GetLastError()); } else { CComBSTR bstrRet(lpszFormatedMessage); *o_pbstrReadString = bstrRet.Copy(); LocalFree(lpszFormatedMessage); return S_OK; } }
HRESULT GetMessage( OUT BSTR* o_pbstrMsg, IN DWORD dwErr, IN UINT iStringId, // OPTIONAL: String resource Id
...) // Optional arguments
{ RETURN_INVALIDARG_IF_NULL(o_pbstrMsg);
_ASSERT(dwErr != 0 || iStringId != 0); // One of the parameter must be non-zero
HRESULT hr = S_OK;
TCHAR szString[1024]; CComBSTR bstrErrorMsg, bstrResourceString, bstrMsg;
if (dwErr) hr = GetErrorMessage(dwErr, &bstrErrorMsg);
if (SUCCEEDED(hr)) { if (iStringId == 0) { bstrMsg = bstrErrorMsg; } else { ::LoadString(_Module.GetModuleInstance(), iStringId, szString, sizeof(szString)/sizeof(TCHAR));
va_list arglist; va_start(arglist, iStringId); LPTSTR lpBuffer = NULL; DWORD dwRet = ::FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, szString, 0, // dwMessageId
0, // dwLanguageId, ignored
(LPTSTR)&lpBuffer, 0, // nSize
&arglist); va_end(arglist);
if (dwRet == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { bstrMsg = lpBuffer; if (dwErr) bstrMsg += bstrErrorMsg; LocalFree(lpBuffer); } } }
if (FAILED(hr)) { // Failed to retrieve the proper message, report the failure directly to user
_stprintf(szString, _T("0x%x"), hr); bstrMsg = szString; }
*o_pbstrMsg = bstrMsg.Copy(); if (!*o_pbstrMsg) return E_OUTOFMEMORY;
return S_OK; }
int DisplayMessageBox( IN HWND hwndParent, IN UINT uType, // style of message box
IN DWORD dwErr, IN UINT iStringId, // OPTIONAL: String resource Id
...) // Optional arguments
{ _ASSERT(dwErr != 0 || iStringId != 0); // One of the parameter must be non-zero
HRESULT hr = S_OK;
TCHAR szCaption[1024], szString[1024]; CComBSTR bstrErrorMsg, bstrResourceString, bstrMsg;
::LoadString(_Module.GetModuleInstance(), IDS_APPLICATION_NAME, szCaption, sizeof(szCaption)/sizeof(TCHAR));
if (dwErr) hr = GetErrorMessage(dwErr, &bstrErrorMsg);
if (SUCCEEDED(hr)) { if (iStringId == 0) { bstrMsg = bstrErrorMsg; } else { ::LoadString(_Module.GetModuleInstance(), iStringId, szString, sizeof(szString)/sizeof(TCHAR));
va_list arglist; va_start(arglist, iStringId); LPTSTR lpBuffer = NULL; DWORD dwRet = ::FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, szString, 0, // dwMessageId
0, // dwLanguageId, ignored
(LPTSTR)&lpBuffer, 0, // nSize
&arglist); va_end(arglist);
if (dwRet == 0) { hr = HRESULT_FROM_WIN32(GetLastError()); } else { bstrMsg = lpBuffer; if (dwErr) bstrMsg += bstrErrorMsg; LocalFree(lpBuffer); } } }
if (FAILED(hr)) { // Failed to retrieve the proper message, report the failure directly to user
_stprintf(szString, _T("0x%x"), hr); bstrMsg = szString; }
CThemeContextActivator activator; return ::MessageBox(hwndParent, bstrMsg, szCaption, uType); }
HRESULT DisplayMessageBoxWithOK( IN const int i_iMessageResID, IN const BSTR i_bstrArgument/* = NULL*/ ) { if (i_bstrArgument) DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, i_iMessageResID, i_bstrArgument); else DisplayMessageBox(::GetActiveWindow(), MB_OK, 0, i_iMessageResID);
return S_OK; }
HRESULT DisplayMessageBoxForHR( IN HRESULT i_hr ) { DisplayMessageBox(::GetActiveWindow(), MB_OK, i_hr, 0);
return S_OK; }
HRESULT CreateSmallImageList( IN HINSTANCE i_hInstance, IN int* i_pIconID, IN const int i_nNumOfIcons, OUT HIMAGELIST* o_phImageList ) { RETURN_INVALIDARG_IF_NULL(i_hInstance);
HRESULT hr = S_OK; HIMAGELIST hImageList = ImageList_Create( GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLORDDB | ILC_MASK, i_nNumOfIcons, 0); if (!hImageList) { hr = HRESULT_FROM_WIN32(GetLastError()); return hr; }
int i = 0; for (i = 0; i < i_nNumOfIcons; i++) { HICON hIcon = LoadIcon(i_hInstance, MAKEINTRESOURCE(i_pIconID[i])); if (!hIcon) { hr = HRESULT_FROM_WIN32(GetLastError()); break; }
if (-1 == ImageList_AddIcon(hImageList, hIcon)) { hr = HRESULT_FROM_WIN32(GetLastError()); break; } }
if (FAILED(hr)) { if (hImageList) ImageList_Destroy(hImageList); } else { if (o_phImageList) *o_phImageList = hImageList; }
return hr; }
HRESULT InsertIntoListView( IN HWND i_hwndList, IN LPCTSTR i_szItemText, IN int i_iImageIndex /*= 0*/ ) /*++
Routine Description:
Insert and item into the listview. The image index for the item is optional while the item text is necessary
Arguments:
i_hwndList - HWND of the list view i_szItemText - The text for the item i_iImageIndex - The image index for the item. Default is 0.
--*/ { RETURN_INVALIDARG_IF_NULL(i_hwndList); RETURN_INVALIDARG_IF_NULL(i_szItemText);
LVITEM lvi; ZeroMemory(&lvi, sizeof(lvi)); lvi.mask = LVIF_TEXT | LVIF_IMAGE; lvi.pszText = (LPTSTR)i_szItemText; lvi.iImage = i_iImageIndex;
int iItemIndex = ListView_InsertItem(i_hwndList, &lvi); // Insert the item into the list view
if ( -1 == iItemIndex) return E_FAIL;
return S_OK; }
HRESULT GetListViewItemText( IN HWND i_hwndListView, IN int i_iItemID, OUT BSTR* o_pbstrItemText ) /*++
Routine Description:
Needed to write a method as the standard one has a slight problem. Here, we make sure that string allocated is of proper length.
Arguments:
i_hwndList - HWND of the list view i_iItemID - The ID of the item to be read o_pbstrItemText - The item text returned by this method --*/ { RETURN_INVALIDARG_IF_NULL(i_hwndListView); RETURN_INVALIDARG_IF_NULL(o_pbstrItemText);
*o_pbstrItemText = NULL; if (-1 == i_iItemID) return S_FALSE; // not a valid item index
LRESULT iReadTextLen = 0; TCHAR szText[1024];
LVITEM lvItem; ZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_TEXT; // Initialize the LV item
lvItem.iItem = i_iItemID; lvItem.pszText = szText; lvItem.cchTextMax = 1024;
// Get the LV item text
iReadTextLen = SendMessage(i_hwndListView, LVM_GETITEMTEXT, lvItem.iItem, (LPARAM)&lvItem);
if(iReadTextLen <= 0) { return HRESULT_FROM_WIN32(::GetLastError()); } else { *o_pbstrItemText = SysAllocString(szText); if (!*o_pbstrItemText) return E_OUTOFMEMORY; }
return S_OK; }
HRESULT GetComboBoxText( IN HWND i_hwndCombo, OUT BSTR* o_pbstrText ) { RETURN_INVALIDARG_IF_NULL(o_pbstrText);
int index = ::SendMessage(i_hwndCombo, CB_GETCURSEL, 0, 0); int len = ::SendMessage(i_hwndCombo, CB_GETLBTEXTLEN, index, 0); if (!len) return S_FALSE; // no text
PTSTR pszText = (PTSTR)calloc(len + 1, sizeof(TCHAR)); RETURN_OUTOFMEMORY_IF_NULL(pszText);
::SendMessage(i_hwndCombo, CB_GETLBTEXT, index, (LPARAM)pszText);
*o_pbstrText = SysAllocString(pszText);
free(pszText);
RETURN_OUTOFMEMORY_IF_NULL(*o_pbstrText);
return S_OK; }
HRESULT EnableToolbarButtons( IN const LPTOOLBAR i_lpToolbar, IN const INT i_iFirstButtonID, IN const INT i_iLastButtonID, IN const BOOL i_bEnableState ) /*++
Routine Description:
Enable or disable the toolbar buttons
Arguments:
i_lpToolbar - Callback used to do toolbar related operations i_iFirstButtonID - The ID of the first button to be operated on. i_iLastButtonID - The ID of the last button to be operated on. i_bEnableState - The new state for enabled. Can be TRUE or FALSE
--*/ { RETURN_INVALIDARG_IF_NULL(i_lpToolbar); RETURN_INVALIDARG_IF_TRUE((i_iLastButtonID - i_iFirstButtonID) < 0);
for (int iCommandID = i_iFirstButtonID; iCommandID <= i_iLastButtonID; iCommandID++ ) { i_lpToolbar->SetButtonState(iCommandID, ENABLED, i_bEnableState); i_lpToolbar->SetButtonState(iCommandID, HIDDEN, !i_bEnableState); }
return S_OK; }
HRESULT AddBitmapToToolbar( IN const LPTOOLBAR i_lpToolbar, IN const INT i_iBitmapResource ) /*++
Routine Description:
Creates and adds the bitmap to the toolbar. This bitmap is used by the toolbar buttons. Arguments: i_lpToolbar - Callback used to do toolbar related operations i_iBitmapResource - The resource id of the bitmap.
--*/ { RETURN_INVALIDARG_IF_NULL(i_lpToolbar);
// Load the bitmap from resource
HBITMAP hBitmap = (HBITMAP)LoadImage(_Module.GetModuleInstance(), MAKEINTRESOURCE(i_iBitmapResource), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR); if(!hBitmap) return HRESULT_FROM_WIN32(GetLastError());
HRESULT hr = S_FALSE; BITMAP bmpRec; if (GetObject(hBitmap, sizeof(bmpRec), &bmpRec)) { if (bmpRec.bmHeight > 0) { int icyBitmap = bmpRec.bmHeight; int icxBitmap = icyBitmap; // Since the bitmaps are squares
int iNoOfBitmaps = bmpRec.bmWidth / bmpRec.bmHeight;
hr = i_lpToolbar->AddBitmap(iNoOfBitmaps, hBitmap, icxBitmap, icyBitmap, RGB(255, 0, 255) // Pink is the mask color
); } } else { hr = HRESULT_FROM_WIN32(GetLastError()); }
DeleteObject(hBitmap);
return hr; }
HRESULT GetInputText( IN HWND hwnd, OUT BSTR* o_pbstrText, OUT DWORD* o_pdwTextLength ) { _ASSERT(hwnd); _ASSERT(o_pbstrText); _ASSERT(o_pdwTextLength);
*o_pdwTextLength = 0; *o_pbstrText = NULL;
HRESULT hr = S_OK; int nLength = GetWindowTextLength(hwnd); if (nLength == 0) { *o_pbstrText = SysAllocString(_T("")); } else { PTSTR ptszText = (PTSTR)calloc(nLength+1, sizeof(TCHAR)); if (ptszText) { nLength = GetWindowText(hwnd, ptszText, nLength+1);
// trim right
PTSTR p = NULL; for (p = ptszText + nLength - 1; p >= ptszText && _istspace(*p); p--) { *p = _T('\0'); }
// trim left
for (p = ptszText; *p && _istspace(*p); p++) ;
*o_pdwTextLength = _tcslen(p); *o_pbstrText = SysAllocString(p);
free(ptszText); } }
if (!*o_pbstrText) hr = E_OUTOFMEMORY;
return hr; }
// return FALSE, if value is not present or 0
// return TRUE, if value is present and non-zero
BOOL CheckRegKey() { BOOL bReturn = FALSE; LONG lErr = ERROR_SUCCESS; HKEY hKey = 0;
lErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Services\\Dfs"), 0, KEY_QUERY_VALUE, &hKey); if (ERROR_SUCCESS == lErr) { DWORD dwType; DWORD dwData = 0; DWORD dwSize = sizeof(DWORD); lErr = RegQueryValueEx(hKey, _T("DfsDnsConfig"), 0, &dwType, (LPBYTE)&dwData, &dwSize);
if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 0 != (dwData & 0x1)) bReturn = TRUE;
RegCloseKey(hKey); }
return bReturn; }
// called when adding a new junction point or adding a new replica member
BOOL ValidateNetPath( IN BSTR i_bstrNetPath, OUT BSTR *o_pbstrServer, OUT BSTR *o_pbstrShare ) { HRESULT hr = S_OK; BOOL bReturn = FALSE; CComBSTR bstrServer; CComBSTR bstrShare; HWND hwnd = ::GetActiveWindow();
do { // Check UNC path
hr = CheckUNCPath(i_bstrNetPath); if (S_OK != hr) { DisplayMessageBox(hwnd, MB_OK, 0, IDS_NOT_UNC_PATH, i_bstrNetPath); break; }
CComBSTR bstrNetPath = i_bstrNetPath; // make a copy
// remove the ending backslash if any
TCHAR *p = bstrNetPath + lstrlen(bstrNetPath) - 1; if (*p == _T('\\')) *p = _T('\0'); /*
LinanT 6/2/2000: a) add "check if path is contactable", warn user */ DWORD dwRet = GetFileAttributes(bstrNetPath); if (-1 == dwRet) { if (IDYES != DisplayMessageBox(hwnd, MB_YESNO, GetLastError(), IDS_NETPATH_ADD_ANYWAY, i_bstrNetPath)) break; } else if (!(dwRet & FILE_ATTRIBUTE_DIRECTORY)) { DisplayMessageBox(hwnd, MB_OK, 0, IDS_PATH_NOT_FOLDER, i_bstrNetPath); break; }
PTSTR lpszServer = bstrNetPath + 2; // skip the first "\\"
PTSTR lpszShare = _tcschr(lpszServer, _T('\\')); if (!lpszShare) break; *lpszShare++ = _T('\0'); bstrShare = lpszShare;
/*
LinanT 3/19/99: a) remove "check if path is contactable", leave it to dfs API b) remove "get dns server name": c) add code to do simple check for dots, if non-dns-look, pop up dialog for confirmation */ bstrServer = lpszServer; if ( CheckRegKey() && NULL == _tcschr(bstrServer, _T('.')) && IDYES != DisplayMessageBox(hwnd, MB_YESNO, 0, IDS_NON_DNSNAME_ADD_ANYWAY, i_bstrNetPath) ) { break; }
bReturn = TRUE;
} while (0);
if (bReturn) { if ( !(*o_pbstrServer = bstrServer.Copy()) || !(*o_pbstrShare = bstrShare.Copy()) ) { bReturn = FALSE; DisplayMessageBox(hwnd, MB_OK | MB_ICONSTOP, (DWORD)E_OUTOFMEMORY, 0); } }
return bReturn; }
/////////////////////////////////////////////////////////////////////
// IsLocalComputername(): cut & pasted from ..\..\framewrk\islocal.cpp
//
TCHAR g_achComputerName[ MAX_COMPUTERNAME_LENGTH+1 ] = _T(""); TCHAR g_achDnsComputerName[DNS_MAX_NAME_BUFFER_LENGTH] = _T("");
BOOL IsLocalComputername( IN LPCTSTR pszMachineName ) { if ( NULL == pszMachineName || _T('\0') == pszMachineName[0] ) return TRUE;
if ( _T('\\') == pszMachineName[0] && _T('\\') == pszMachineName[1] ) pszMachineName += 2;
// compare with the local computer netbios name
if ( _T('\0') == g_achComputerName[0] ) { DWORD dwSize = sizeof(g_achComputerName)/sizeof(TCHAR); GetComputerName( g_achComputerName, &dwSize ); _ASSERT(_T('\0') != g_achComputerName[0]); } if ( 0 == lstrcmpi( pszMachineName, g_achComputerName ) ) { return TRUE; }
// compare with the local DNS name
// SKwan confirms that ComputerNameDnsFullyQualified is the right name to use
// when clustering is taken into account
if ( _T('\0') == g_achDnsComputerName[0] ) { DWORD dwSize = sizeof(g_achDnsComputerName)/sizeof(TCHAR); GetComputerNameEx( ComputerNameDnsFullyQualified, g_achDnsComputerName, &dwSize ); _ASSERT( _T('\0') != g_achDnsComputerName[0] ); } if ( 0 == lstrcmpi( pszMachineName, g_achDnsComputerName ) ) { return TRUE; }
return FALSE;
} // IsLocalComputername()
// S_OK: a local computer
// S_FALSE: not a local computer
HRESULT IsComputerLocal( IN LPCTSTR lpszServer ) { return (IsLocalComputername(lpszServer) ? S_OK : S_FALSE); }
BOOL IsValidLocalAbsolutePath( IN LPCTSTR lpszPath ) { DWORD dwPathType = 0; DWORD dwStatus = I_NetPathType( NULL, const_cast<LPTSTR>(lpszPath), &dwPathType, 0); if (dwStatus) return FALSE;
if (dwPathType ^ ITYPE_PATH_ABSD) return FALSE;
return TRUE; }
//
// This function will return the full path with the \\?\ prefix.
// That is, \\?\X:\a\b\c if local, or \\?\UNC\server\X$\a\b\c if remote.
//
HRESULT GetFullPath( IN LPCTSTR lpszServer, IN LPCTSTR lpszPath, OUT BSTR *o_pbstrFullPath ) { _ASSERT(IsValidLocalAbsolutePath(lpszPath));
CComBSTR bstrFullPath; if (S_OK == IsComputerLocal(lpszServer)) { bstrFullPath = _T("\\\\?\\"); bstrFullPath += lpszPath; } else { bstrFullPath = _T("\\\\?\\UNC\\"); if (mylstrncmpi(_T("\\\\"), lpszServer, 2)) { bstrFullPath += lpszServer; } else { bstrFullPath += lpszServer + 2; } bstrFullPath += _T("\\"); bstrFullPath += lpszPath;
TCHAR *p = _tcschr(bstrFullPath, _T(':')); if (p) { *p = _T('$'); } }
*o_pbstrFullPath = bstrFullPath.Detach();
return S_OK; }
// Purpose: verify if the specified drive belongs to a list of disk drives on the server
// Return:
// S_OK: yes
// S_FALSE: no
// hr: some error happened
HRESULT VerifyDriveLetter( IN LPCTSTR lpszServer, IN LPCTSTR lpszPath ) { _ASSERT(IsValidLocalAbsolutePath(lpszPath)); HRESULT hr = S_FALSE; LPBYTE pBuffer = NULL; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; DWORD dwRet = NetServerDiskEnum( const_cast<LPTSTR>(lpszServer), 0, &pBuffer, (DWORD)-1, &dwEntriesRead, &dwTotalEntries, NULL);
if (NERR_Success == dwRet) { LPTSTR pDrive = (LPTSTR)pBuffer; for (UINT i=0; i<dwEntriesRead; i++) { if (!mylstrncmpi(pDrive, lpszPath, 1)) { hr = S_OK; break; } pDrive += 3; }
NetApiBufferFree(pBuffer); } else { hr = HRESULT_FROM_WIN32(dwRet); }
return hr; }
// Purpose: is there a related admin $ share
// Return:
// S_OK: yes
// S_FALSE: no
// hr: some error happened
HRESULT IsAdminShare( IN LPCTSTR lpszServer, IN LPCTSTR lpszPath ) { _ASSERT(S_OK != IsComputerLocal(lpszServer)); _ASSERT(IsValidLocalAbsolutePath(lpszPath));
HRESULT hr = S_FALSE; LPBYTE pBuffer = NULL; DWORD dwEntriesRead = 0; DWORD dwTotalEntries = 0; DWORD dwRet = NetShareEnum( const_cast<LPTSTR>(lpszServer), 1, &pBuffer, (DWORD)-1, &dwEntriesRead, &dwTotalEntries, NULL);
if (NERR_Success == dwRet) { PSHARE_INFO_1 pShareInfo = (PSHARE_INFO_1)pBuffer; for (UINT i=0; i<dwEntriesRead; i++) { if ( (pShareInfo->shi1_type & STYPE_SPECIAL) && _tcslen(pShareInfo->shi1_netname) == 2 && *(pShareInfo->shi1_netname + 1) == _T('$') && !mylstrncmpi(pShareInfo->shi1_netname, lpszPath, 1) ) { hr = S_OK; break; } pShareInfo++; }
NetApiBufferFree(pBuffer); } else { hr = HRESULT_FROM_WIN32(dwRet); }
return hr; }
//+---------------------------------------------------------------------------
//
// Function: IsAnExistingFolder
//
// Synopsis: Check if pszPath is pointing at an existing folder.
//
// S_OK: The specified path points to an existing folder.
// S_FALSE: The specified path doesn't point to an existing folder.
// hr: Failed to get info on the specified path, or
// the path exists but doesn't point to a folder.
// The function reports error msg for both failures if desired.
//----------------------------------------------------------------------------
HRESULT IsAnExistingFolder( IN HWND hwnd, IN LPCTSTR pszPath // points to path with "\\?\" prefix
) { if (!hwnd) hwnd = GetActiveWindow();
HRESULT hr = S_OK;
WIN32_FILE_ATTRIBUTE_DATA fad = {0}; if (!GetFileAttributesEx(pszPath, GetFileExInfoStandard, &fad)) { DWORD dwErr = GetLastError(); if (ERROR_PATH_NOT_FOUND == dwErr || ERROR_FILE_NOT_FOUND == dwErr) { // the specified path doesn't exist
hr = S_FALSE; } else { DisplayMessageBox(hwnd, MB_OK, dwErr, IDS_FAILED_TO_GETINFO_FOLDER, pszPath); hr = HRESULT_FROM_WIN32(dwErr); } } else if ( 0 == (fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { // the specified path is not pointing to a folder
DisplayMessageBox(hwnd, MB_OK, 0, IDS_PATH_NOT_FOLDER, pszPath); hr = E_FAIL; }
return hr; }
// create the directories layer by layer
HRESULT CreateLayeredDirectory( IN LPCTSTR lpszServer, IN LPCTSTR lpszPath ) { _ASSERT(IsValidLocalAbsolutePath(lpszPath));
//
// get the full path with \\?\ prefix, such that CreateDirectory
// will turn off path parsing in case our path is longer than MAX_PATH
//
CComBSTR bstrFullPath; GetFullPath(lpszServer, lpszPath, &bstrFullPath);
LPTSTR p = _tcschr(bstrFullPath, (S_OK == IsComputerLocal(lpszServer)) ? _T(':') : _T('$'));
//
// bstrFullPath is either "\\?\C:\a\b\c\d" or "\\?\UNC\server\C$\a\b\c\d"
// move p to point at "a\b\c\d"
//
p += 2;
BOOL bRet = TRUE; while (p && *p) { p = _tcschr(p, _T('\\'));
if (p) *p = _T('\0');
bRet = CreateDirectory(bstrFullPath, NULL); if (!bRet) { DWORD dwErr = GetLastError(); if (dwErr != ERROR_ALREADY_EXISTS) return HRESULT_FROM_WIN32(dwErr); }
if (p) *p++ = _T('\\'); // restore the backslash, move p to point at the char after the backslash
}
return S_OK; }
HRESULT BrowseNetworkPath( IN HWND hwndParent, OUT BSTR *o_pbstrPath ) { _ASSERT(o_pbstrPath);
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { do { CComPtr<IMalloc> pMalloc; hr = SHGetMalloc(&pMalloc); if (FAILED(hr)) break;
CComBSTR bstrDlgLabel; hr = LoadStringFromResource(IDS_BROWSE_NET_DLG, &bstrDlgLabel); if (FAILED(hr)) break;
LPITEMIDLIST pItemIdList = NULL; hr = SHGetSpecialFolderLocation(NULL, CSIDL_NETWORK, &pItemIdList); if (FAILED(hr)) break;
BROWSEINFO bi = {hwndParent, pItemIdList, 0, bstrDlgLabel, BIF_RETURNONLYFSDIRS, NULL, NULL, 0};
LPITEMIDLIST pItemIdListBr = SHBrowseForFolder(&bi); if (!pItemIdListBr) { hr = S_FALSE; // user clicked Cancel
} else { CComBSTR bstrPath; TCHAR szPath[MAX_PATH] = _T("\0"); SHGetPathFromIDList(pItemIdListBr, szPath); //
// try to use Dns server name
//
if (CheckRegKey() && S_OK == CheckUNCPath(szPath)) { PTSTR lpszServer = szPath + 2; // skip the first "\\"
PTSTR lpszShare = _tcschr(lpszServer, _T('\\')); CComBSTR bstrServer = CComBSTR(lpszShare - lpszServer, lpszServer); CComBSTR bstrDnsServer; hr = GetServerInfo(bstrServer, NULL, // Domain
NULL, // NetbiosName
NULL, // bValidDSObject
&bstrDnsServer); if (S_OK == hr) { bstrPath = _T("\\\\"); bstrPath += bstrDnsServer; bstrPath += lpszShare; } else { hr = S_OK; // reset hr
bstrPath = szPath; } } else { bstrPath = szPath; }
*o_pbstrPath = bstrPath.Detach();
pMalloc->Free(pItemIdListBr); }
pMalloc->Free(pItemIdList);
} while (0);
CoUninitialize(); }
if (FAILED(hr)) DisplayMessageBox(hwndParent, MB_OK, hr, IDS_FAILED_TO_BROWSE_NETWORKPATH);
return hr; } #define MAX_DFS_REFERRAL_TIME 0xFFFFFFFF
BOOL ValidateTimeout( IN LPCTSTR lpszTimeout, OUT ULONG *pulTimeout ) { BOOL bReturn = FALSE;
if (pulTimeout) { *pulTimeout = 0;
__int64 i64Timeout = _wtoi64(lpszTimeout);
if (i64Timeout <= MAX_DFS_REFERRAL_TIME) { bReturn = TRUE; *pulTimeout = (ULONG)i64Timeout; } }
return bReturn; }
#include "winnetp.h"
// retrieve system drive letter on the specified machine
HRESULT GetSystemDrive(IN LPCTSTR lpszComputer, OUT TCHAR *ptch) { _ASSERT(ptch);
HRESULT hr = S_OK; SHARE_INFO_2* pShareInfo = NULL; NET_API_STATUS nstatRetVal = NetShareGetInfo( const_cast<LPTSTR>(lpszComputer), _T("Admin$"), 2, (LPBYTE *)&pShareInfo);
if (nstatRetVal == NERR_Success) { _ASSERT(_T(':') == *(pShareInfo->shi2_path + 1)); *ptch = *(pShareInfo->shi2_path); } else { hr = HRESULT_FROM_WIN32(nstatRetVal); }
return hr; }
//
// return a drive letter X, the staging path will be created at <X>:\FRS-Staging
// Try to exclude the following drives for performance consideration:
// 1. system drive: because the jet database ntfrs uses resides on system drive
// 2. the drive the replica folder sits on
// Will try to return a drive with the most free space
//
TCHAR GetDiskForStagingPath( IN LPCTSTR i_lpszServer, IN TCHAR i_tch ) { _ASSERT(i_lpszServer && *i_lpszServer); _ASSERT(_istalpha(i_tch));
TCHAR tchDrive = i_tch;
//
// retrieve the system drive letter on the specified machine
//
TCHAR tchSystemDrive; if (S_OK != GetSystemDrive(i_lpszServer, &tchSystemDrive)) return tchDrive;
//
// enumerate all shareable disks, e.g., \\server\C$, \\server\D$, etc.
//
CComBSTR bstrServer; if (mylstrncmpi(i_lpszServer, _T("\\\\"), 2)) { bstrServer = _T("\\\\"); bstrServer += i_lpszServer; } else bstrServer = i_lpszServer;
NETRESOURCE nr; nr.dwScope = RESOURCE_SHAREABLE; nr.dwType = RESOURCETYPE_ANY; nr.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC; nr.dwUsage = RESOURCEUSAGE_CONTAINER; nr.lpLocalName = _T(""); nr.lpRemoteName = bstrServer; nr.lpComment = _T(""); nr.lpProvider = _T("");
HANDLE hEnum = NULL; DWORD dwResult = WNetOpenEnum ( RESOURCE_SHAREABLE, RESOURCETYPE_ANY, RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER, &nr, &hEnum); if (dwResult == NO_ERROR) { NETRESOURCE nrBuffer[26]; DWORD dwBufferSize = 26 * sizeof(NETRESOURCE); DWORD dwNumEntries = 0xFFFFFFFF; // Enumerate all possible entries.
dwResult = WNetEnumResource ( hEnum, &dwNumEntries, nrBuffer, &dwBufferSize);
if (dwResult == NO_ERROR) { ULONGLONG ullFreeSpace = 0; for (DWORD dwIndex = 0; dwIndex < dwNumEntries; dwIndex++) { //
// lpRemoteName contains string in the form of \\server\C$
//
TCHAR *p = nrBuffer[dwIndex].lpRemoteName; TCHAR tchCurrent = *(p + _tcslen(p) - 2);
//
// exclude the current drive specified in i_tch
//
if ( _totupper(i_tch) == _totupper(tchCurrent) ) continue;
//
// skip if it's not a NTFS file system that supports object identifiers
//
TCHAR szFileSystemName[MAX_PATH + 1]; DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0; CComBSTR bstrRootPath = p; if (_T('\\') != *(p + _tcslen(p) - 1)) bstrRootPath += _T("\\"); if (FALSE == GetVolumeInformation(bstrRootPath, NULL, 0, NULL, &dwMaxCompLength, &dwFileSystemFlags, szFileSystemName, MAX_PATH)) continue;
if (CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, _T("NTFS"), -1, szFileSystemName, -1) || !(FILE_SUPPORTS_OBJECT_IDS & dwFileSystemFlags)) continue;
//
// 1. when i_tch is on a non-system drive and system drive is NTFS,
// change default to system drive
// 2. when other NTFS drives present, exclude system drive
//
if ( _totupper(tchSystemDrive) == _totupper(tchCurrent) ) { if ( 0 == ullFreeSpace ) tchDrive = tchSystemDrive;
continue; }
//
// find out the drive that has the most free space
//
ULARGE_INTEGER ulgiFreeBytesAvailableToCaller; ULARGE_INTEGER ulgiTotalNumberOfBytes;
if (GetDiskFreeSpaceEx(p, &ulgiFreeBytesAvailableToCaller, &ulgiTotalNumberOfBytes, NULL)) { if (ulgiFreeBytesAvailableToCaller.QuadPart > ullFreeSpace) { tchDrive = tchCurrent; ullFreeSpace = ulgiFreeBytesAvailableToCaller.QuadPart; } } } }
WNetCloseEnum (hEnum); }
return tchDrive; }
HRESULT GetUNCPath ( IN BSTR i_bstrServerName, IN BSTR i_bstrShareName, OUT BSTR* o_pbstrUNCPath ) { RETURN_INVALIDARG_IF_NULL(i_bstrServerName); RETURN_INVALIDARG_IF_NULL(i_bstrShareName); RETURN_INVALIDARG_IF_NULL(o_pbstrUNCPath);
CComBSTR bstrUNCPath;
bstrUNCPath = _T("\\\\"); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath); bstrUNCPath += i_bstrServerName; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath); bstrUNCPath += _T("\\"); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath); bstrUNCPath += i_bstrShareName; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrUNCPath);
*o_pbstrUNCPath = bstrUNCPath.Detach();
return S_OK; }
HRESULT GetDfsRootDisplayName ( IN BSTR i_bstrScopeName, IN BSTR i_bstrDfsName, OUT BSTR* o_pbstrDisplayName ) { return GetUNCPath(i_bstrScopeName, i_bstrDfsName, o_pbstrDisplayName); }
HRESULT GetDfsReplicaDisplayName ( IN BSTR i_bstrServerName, IN BSTR i_bstrShareName, OUT BSTR* o_pbstrDisplayName ) { return GetUNCPath(i_bstrServerName, i_bstrShareName, o_pbstrDisplayName); }
HRESULT AddLVColumns( IN const HWND hwndListBox, IN const INT iStartingResourceID, IN const UINT uiColumns ) { //
// calculate the listview column width
//
RECT rect; ZeroMemory(&rect, sizeof(rect)); ::GetWindowRect(hwndListBox, &rect); int nControlWidth = rect.right - rect.left; int nVScrollbarWidth = GetSystemMetrics(SM_CXVSCROLL); int nBorderWidth = GetSystemMetrics(SM_CXBORDER); int nControlNetWidth = nControlWidth - 4 * nBorderWidth; int nWidth = nControlNetWidth / uiColumns;
LVCOLUMN lvColumn; ZeroMemory(&lvColumn, sizeof(lvColumn)); lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_LEFT; lvColumn.cx = nWidth;
for (UINT i = 0; i < uiColumns; i++) { CComBSTR bstrColumnText;
LoadStringFromResource(iStartingResourceID + i, &bstrColumnText);
lvColumn.pszText = bstrColumnText; lvColumn.iSubItem = i;
ListView_InsertColumn(hwndListBox, i, &lvColumn); }
return S_OK; }
LPARAM GetListViewItemData( IN HWND hwndList, IN int index ) { if (-1 == index) return NULL;
LVITEM lvItem; ZeroMemory(&lvItem, sizeof(lvItem));
lvItem.mask = LVIF_PARAM; lvItem.iItem = index; if (ListView_GetItem(hwndList, &lvItem)) return lvItem.lParam;
return NULL; }
HRESULT CreateAndHideStagingPath( IN BSTR i_bstrServer, IN BSTR i_bstrStagingPath ) { RETURN_INVALIDARG_IF_NULL(i_bstrServer); RETURN_INVALIDARG_IF_NULL(i_bstrStagingPath);
//
// Create the directory
//
HRESULT hr = CreateLayeredDirectory(i_bstrServer, i_bstrStagingPath); if (FAILED(hr)) return hr;
//
// try to hide the staging directory, ignore errors
//
CComBSTR bstrFullPath; GetFullPath(i_bstrServer, i_bstrStagingPath, &bstrFullPath);
WIN32_FILE_ATTRIBUTE_DATA fad = {0}; if (GetFileAttributesEx(bstrFullPath, GetFileExInfoStandard, &fad)) { (void) SetFileAttributes(bstrFullPath, fad.dwFileAttributes | FILE_ATTRIBUTE_HIDDEN); }
return S_OK; }
//+-------------------------------------------------------------------------
//
// Function: ConfigAndStartNtfrs
//
// Synopsis: Config ntfrs to be AUTO_START, and start the service.
//
//--------------------------------------------------------------------------
HRESULT ConfigAndStartNtfrs ( BSTR i_bstrServer ) { HRESULT hr = S_OK; SC_HANDLE hScManager = NULL; SC_HANDLE hService = NULL; SERVICE_STATUS svcStatus; DWORD dwDesiredAccess = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_START;
do { if ((hScManager = ::OpenSCManager(i_bstrServer, NULL, SC_MANAGER_CONNECT )) == NULL || (hService = ::OpenService(hScManager, _T("ntfrs"), dwDesiredAccess)) == NULL || !ChangeServiceConfig(hService, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL) || !::QueryServiceStatus(hService, &svcStatus) ) { hr = HRESULT_FROM_WIN32(GetLastError()); break; } if (SERVICE_RUNNING != svcStatus.dwCurrentState) { if (!StartService(hService, 0, NULL)) { hr = HRESULT_FROM_WIN32(GetLastError()); break; } // The following is a cut&paste from MSDN article
// Check the status until the service is no longer start pending.
if (!QueryServiceStatus(hService,&svcStatus)) { hr = HRESULT_FROM_WIN32(GetLastError()); break; } // Get the tick count before entering the loop.
DWORD dwStartTickCount = GetTickCount(); DWORD dwOldCheckPoint = svcStatus.dwCheckPoint; DWORD dwWaitTime;
while (svcStatus.dwCurrentState == SERVICE_START_PENDING) { // Do not wait longer than the wait hint. A good interval is
// one tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
dwWaitTime = svcStatus.dwWaitHint / 10;
if ( dwWaitTime < 1000 ) dwWaitTime = 1000; else if ( dwWaitTime > 10000 ) dwWaitTime = 10000;
Sleep( dwWaitTime );
// Check the status again.
if (!QueryServiceStatus(hService, &svcStatus)) break; if (svcStatus.dwCheckPoint > dwOldCheckPoint) { // The service is making progress
dwStartTickCount = GetTickCount(); dwOldCheckPoint = svcStatus.dwCheckPoint; } else { if (GetTickCount() - dwStartTickCount > svcStatus.dwWaitHint) { // No progress made within the wait hint
break; } } } if (svcStatus.dwCurrentState == SERVICE_RUNNING) hr = S_OK; else hr = HRESULT_FROM_WIN32(GetLastError()); }
} while ( FALSE );
if (hService) CloseServiceHandle(hService); if (hScManager) CloseServiceHandle(hScManager);
return(hr); }
//+-------------------------------------------------------------------------
//
// Function: CheckResourceProvider
//
// Synopsis: see if pszResource is provided by "Microsoft Windows Network".
//
//--------------------------------------------------------------------------
HRESULT CheckResourceProvider(LPCTSTR pszResource) { DWORD dwError = 0; NETRESOURCE nr = {0}; NETRESOURCE nrOut = {0}; LPTSTR pszSystem = NULL; // pointer to variable-length strings
NETRESOURCE *pBuffer = &nrOut; // buffer
DWORD cbResult = sizeof(nrOut); // buffer size
nr.dwScope = RESOURCE_GLOBALNET; nr.dwType = RESOURCETYPE_DISK; nr.lpRemoteName = (LPTSTR)pszResource;
//
// Find the right provider string for "Microsoft Windows Network".
//
// Network provider string is localizable. In order to support localized
// system or MUI on ENG system, we need to retrieve the name from system
// instead of load the string from a resource file.
//
TCHAR szProviderName[MAX_PATH]; DWORD dwNumOfChars = MAX_PATH; PTSTR pszProviderName = szProviderName; dwError = WNetGetProviderName(WNNC_NET_LANMAN, pszProviderName, &dwNumOfChars); if (dwError == ERROR_MORE_DATA) { pszProviderName = (PTSTR)LocalAlloc(LMEM_FIXED, dwNumOfChars * sizeof(TCHAR)); if (!pszProviderName) { dwError = ERROR_NOT_ENOUGH_MEMORY; } else { dwError = WNetGetProviderName(WNNC_NET_LANMAN, pszProviderName, &dwNumOfChars); } }
if (dwError == NO_ERROR) { nr.lpProvider = pszProviderName;
//
// First call the WNetGetResourceInformation function with
// memory allocated to hold only a NETRESOURCE structure. This
// method can succeed if all the NETRESOURCE pointers are NULL.
//
dwError = WNetGetResourceInformation(&nr, (LPBYTE)pBuffer, &cbResult, &pszSystem);
//
// If the call fails because the buffer is too small,
// call the LocalAlloc function to allocate a larger buffer.
//
if (dwError == ERROR_MORE_DATA) { pBuffer = (NETRESOURCE *)LocalAlloc(LMEM_FIXED, cbResult);
if (!pBuffer) { dwError = ERROR_NOT_ENOUGH_MEMORY; } else { // Call WNetGetResourceInformation again with the larger buffer.
dwError = WNetGetResourceInformation(&nr, (LPBYTE)pBuffer, &cbResult, &pszSystem); } }
if (dwError == NO_ERROR) { // If the call succeeds, process the contents of the
// returned NETRESOURCE structure and the variable-length
// strings in lpBuffer. Then free the memory.
//
if (pBuffer != &nrOut) { LocalFree(pBuffer); } } }
if (pszProviderName && pszProviderName != szProviderName) { LocalFree(pszProviderName); }
return (dwError == NO_ERROR ? S_OK : HRESULT_FROM_WIN32(dwError)); }
HRESULT FRSShareCheck ( BSTR i_bstrServer, BSTR i_bstrFolder, OUT FRSSHARE_TYPE *pFRSShareType ) /*++
Routine Description: Performs FRS checks for the share to be able particiapte in a FRS set. Arguments: i_bstrServer - The server hosting the share i_bstrFolder - The share path. --*/ { _ASSERT(i_bstrServer && *i_bstrServer && i_bstrFolder && *i_bstrFolder && pFRSShareType);
// Is the server a NT 5.0 server with FRS?
HRESULT hr = S_FALSE; hr = FRSIsNTFRSInstalled(i_bstrServer); if (S_FALSE == hr) { *pFRSShareType = FRSSHARE_TYPE_NONTFRS; return hr; } else if (FAILED(hr)) { *pFRSShareType = FRSSHARE_TYPE_UNKNOWN; return hr; }
// Is the path on a valid disktree share?
hr = GetFolderInfo(i_bstrServer, i_bstrFolder); if (STG_E_NOTFILEBASEDSTORAGE == hr) { *pFRSShareType = FRSSHARE_TYPE_NOTDISKTREE; return S_FALSE; } else if (FAILED(hr)) { *pFRSShareType = FRSSHARE_TYPE_UNKNOWN; return hr; }
// Get root path as \\server\share
CComBSTR bstrRootPath = _T("\\\\"); bstrRootPath+= i_bstrServer; bstrRootPath+= _T("\\"); TCHAR *p = _tcschr(i_bstrFolder, _T('\\')); if (p) { bstrRootPath += CComBSTR(p - i_bstrFolder + 1, i_bstrFolder); } else { bstrRootPath += i_bstrFolder; bstrRootPath+= _T("\\"); }
TCHAR szFileSystemName[MAX_PATH]; DWORD dwMaxCompLength = 0, dwFileSystemFlags = 0;
_ASSERT(bstrRootPath);
// on NTFS file system that supports object identifiers?
if (0 == GetVolumeInformation( bstrRootPath, // Volume path
NULL, // Volume name not required
0, // Size of volume name buffer
NULL, // Serial number not required.
&dwMaxCompLength, &dwFileSystemFlags, szFileSystemName, MAX_PATH )) { *pFRSShareType = FRSSHARE_TYPE_UNKNOWN; return HRESULT_FROM_WIN32(GetLastError()); }
if (CSTR_EQUAL != CompareString(LOCALE_INVARIANT, NORM_IGNORECASE, _T("NTFS"), -1, szFileSystemName, -1) || !(FILE_SUPPORTS_OBJECT_IDS & dwFileSystemFlags)) { *pFRSShareType = FRSSHARE_TYPE_NOTNTFS; return S_FALSE; }
*pFRSShareType = FRSSHARE_TYPE_OK; return S_OK; }
HRESULT FRSIsNTFRSInstalled ( BSTR i_bstrServer ) /*++
Routine Description: Checks if the computer has ntfrs service. Arguments: i_bstrServer - The name of the server. Return value: S_OK, if server has ntfrs service. S_FALSE, if server does not have ntfrs service installed. --*/ { if (!i_bstrServer) return(E_INVALIDARG);
SC_HANDLE SCMHandle = NULL, NTFRSHandle = NULL; HRESULT hr = S_FALSE;
SCMHandle = OpenSCManager (i_bstrServer, NULL, SC_MANAGER_CONNECT); if (!SCMHandle) return(HRESULT_FROM_WIN32(GetLastError()));
NTFRSHandle = OpenService ( SCMHandle, _T("ntfrs"), SERVICE_QUERY_STATUS ); if (!NTFRSHandle) { DWORD dwError = GetLastError(); if (ERROR_SERVICE_DOES_NOT_EXIST == dwError) hr = S_FALSE; else hr = HRESULT_FROM_WIN32(dwError);
CloseServiceHandle(SCMHandle); return(hr); } else hr = S_OK;
CloseServiceHandle(NTFRSHandle); CloseServiceHandle(SCMHandle);
return(hr); }
typedef HRESULT (*pfnReplicationScheduleDialogEx) ( HWND hwndParent, // parent window
BYTE ** pprgbData, // pointer to pointer to array of 84 bytes
LPCTSTR pszTitle, // dialog title
DWORD dwFlags // option flags
);
static HINSTANCE g_hDllSchedule = NULL; static pfnReplicationScheduleDialogEx g_hProcSchedule = NULL;
//
// S_OK: button OK is clicked and the new schedule is returned in io_pSchedule
// S_FALSE: button Cancle is clicked, io_pSchedule is not touched
//
HRESULT InvokeScheduleDlg( IN HWND i_hwndParent, IN OUT SCHEDULE* io_pSchedule ) { CComBSTR bstrTitle; HRESULT hr = LoadStringFromResource(IDS_SCHEDULE, &bstrTitle); RETURN_IF_FAILED(hr);
//
// LoadLibrary
//
if (!g_hDllSchedule) { if (!(g_hDllSchedule = LoadLibrary(_T("loghours.dll"))) || !(g_hProcSchedule = (pfnReplicationScheduleDialogEx)GetProcAddress(g_hDllSchedule, "ReplicationScheduleDialogEx")) ) { hr = HRESULT_FROM_WIN32(GetLastError()); if (g_hDllSchedule) { FreeLibrary(g_hDllSchedule); g_hDllSchedule = NULL; } return hr; } }
//
// invoke the schedule dialog
//
BYTE* pbScheduleData = (BYTE *)io_pSchedule + io_pSchedule->Schedules->Offset; hr = (*g_hProcSchedule)(i_hwndParent, &pbScheduleData, bstrTitle, 0);
return hr; }
HRESULT TranslateManagedBy( IN PCTSTR i_pszDC, IN PCTSTR i_pszIn, OUT BSTR* o_pbstrOut, IN DS_NAME_FORMAT i_formatIn, IN DS_NAME_FORMAT i_formatOut ) { RETURN_INVALIDARG_IF_NULL(o_pbstrOut);
*o_pbstrOut = NULL;
HRESULT hr = S_OK; if (!i_pszIn || !*i_pszIn) return hr;
CComBSTR bstr; HANDLE hDS = NULL; DWORD dwErr = DsBind(i_pszDC, NULL, &hDS); if (ERROR_SUCCESS != dwErr) { hr = HRESULT_FROM_WIN32(dwErr); } else { hr = CrackName( hDS, (PTSTR)i_pszIn, i_formatIn, i_formatOut, &bstr ); DsUnBind(&hDS); }
if (SUCCEEDED(hr)) *o_pbstrOut = bstr.Detach();
return hr; }
HRESULT GetFTDfsObjectDN( IN PCTSTR i_pszDomainName, IN PCTSTR i_pszRootName, OUT BSTR* o_pbstrFTDfsObjectDN ) { CComBSTR bstrDomainDN; HRESULT hr = GetDomainInfo( i_pszDomainName, NULL, // return DC's Dns name
NULL, // return Domain's Dns name
&bstrDomainDN // return DC=nttest,DC=micr
); RETURN_IF_FAILED(hr);
CComBSTR bstrFTDfsObjectDN = _T("CN="); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN); bstrFTDfsObjectDN += i_pszRootName; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN); bstrFTDfsObjectDN += _T(","); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN); bstrFTDfsObjectDN += _T("CN=Dfs-Configuration,CN=System,"); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN); bstrFTDfsObjectDN += bstrDomainDN; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrFTDfsObjectDN);
*o_pbstrFTDfsObjectDN = bstrFTDfsObjectDN.Detach();
return hr; }
HRESULT ReadSharePublishInfoHelper( PLDAP i_pldap, LPCTSTR i_pszDN, LPCTSTR i_pszSearchFilter, OUT BOOL* o_pbPublish, OUT BSTR* o_pbstrUNCPath, OUT BSTR* o_pbstrDescription, OUT BSTR* o_pbstrKeywords, OUT BSTR* o_pbstrManagedBy) { dfsDebugOut((_T("ReadSharePublishInfoHelper %s %s\n"), i_pszDN, i_pszSearchFilter));
*o_pbPublish = FALSE;
HRESULT hr = S_OK; hr = IsValidObject(i_pldap, (PTSTR)i_pszDN); if (S_OK != hr) return hr;
LListElem* pElem = NULL;
do { PCTSTR ppszAttributes[] = { ATTR_SHRPUB_UNCNAME, ATTR_SHRPUB_DESCRIPTION, ATTR_SHRPUB_KEYWORDS, ATTR_SHRPUB_MANAGEDBY, 0 };
hr = GetValuesEx( i_pldap, i_pszDN, LDAP_SCOPE_BASE, i_pszSearchFilter, ppszAttributes, &pElem); RETURN_IF_FAILED(hr);
if (!pElem || !pElem->pppszAttrValues) return hr;
PTSTR** pppszValues = pElem->pppszAttrValues;
if (pppszValues[0] && *(pppszValues[0])) { *o_pbstrUNCPath = SysAllocString(*(pppszValues[0])); BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrUNCPath, &hr); *o_pbPublish = TRUE; }
if (pppszValues[1] && *(pppszValues[1])) { *o_pbstrDescription = SysAllocString(*(pppszValues[1])); BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrDescription, &hr); }
if (pppszValues[2] && *(pppszValues[2])) { CComBSTR bstrKeywords; PTSTR *ppszStrings = pppszValues[2]; while (*ppszStrings) { if (!bstrKeywords) { bstrKeywords = *ppszStrings; BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr); } else { bstrKeywords += _T(";"); BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr); bstrKeywords += *ppszStrings; BREAK_OUTOFMEMORY_IF_NULL((BSTR)bstrKeywords, &hr); } ppszStrings++; } *o_pbstrKeywords = bstrKeywords.Detach(); }
if (pppszValues[3] && *(pppszValues[3])) { *o_pbstrManagedBy = SysAllocString(*(pppszValues[3])); BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrManagedBy, &hr); }
} while (0);
if (pElem) FreeLListElem(pElem);
return hr; } HRESULT ReadSharePublishInfoOnFTRoot( LPCTSTR i_pszDomainName, LPCTSTR i_pszRootName, OUT BOOL* o_pbPublish, OUT BSTR* o_pbstrUNCPath, OUT BSTR* o_pbstrDescription, OUT BSTR* o_pbstrKeywords, OUT BSTR* o_pbstrManagedBy) { HRESULT hr = S_OK;
CComBSTR bstrFTDfsObjectDN; hr = GetFTDfsObjectDN(i_pszDomainName, i_pszRootName, &bstrFTDfsObjectDN); if (FAILED(hr)) return hr;
CComBSTR bstrDC; PLDAP pldap = NULL; hr = ConnectToDS(i_pszDomainName, &pldap, &bstrDC); // PDC is preferred
if (SUCCEEDED(hr)) { CComBSTR bstrManagedByFQDN; hr = ReadSharePublishInfoHelper( pldap, bstrFTDfsObjectDN, OBJCLASS_SF_FTDFS, o_pbPublish, o_pbstrUNCPath, o_pbstrDescription, o_pbstrKeywords, &bstrManagedByFQDN);
if (SUCCEEDED(hr)) { hr = TranslateManagedBy(bstrDC, bstrManagedByFQDN, o_pbstrManagedBy, DS_FQDN_1779_NAME, DS_USER_PRINCIPAL_NAME); if (FAILED(hr)) hr = TranslateManagedBy(bstrDC, bstrManagedByFQDN, o_pbstrManagedBy, DS_FQDN_1779_NAME, DS_NT4_ACCOUNT_NAME); }
CloseConnectionToDS(pldap); }
return hr; }
HRESULT ReadSharePublishInfoOnSARoot( LPCTSTR i_pszServerName, LPCTSTR i_pszShareName, OUT BOOL* o_pbPublish, OUT BSTR* o_pbstrUNCPath, OUT BSTR* o_pbstrDescription, OUT BSTR* o_pbstrKeywords, OUT BSTR* o_pbstrManagedBy) { RETURN_INVALIDARG_IF_NULL(i_pszServerName); RETURN_INVALIDARG_IF_NULL(i_pszShareName); RETURN_INVALIDARG_IF_NULL(o_pbPublish); RETURN_INVALIDARG_IF_NULL(o_pbstrUNCPath); RETURN_INVALIDARG_IF_NULL(o_pbstrDescription); RETURN_INVALIDARG_IF_NULL(o_pbstrKeywords); RETURN_INVALIDARG_IF_NULL(o_pbstrManagedBy);
*o_pbPublish = FALSE; *o_pbstrUNCPath = NULL; *o_pbstrDescription = NULL; *o_pbstrKeywords = NULL; *o_pbstrManagedBy = NULL;
CComBSTR bstrDomainName, bstrFQDN; HRESULT hr = GetServerInfo( (PTSTR)i_pszServerName, &bstrDomainName, NULL, //NetbiosName
NULL, //ValidDSObject
NULL, //DnsName,
NULL, //Guid,
&bstrFQDN); if (S_OK != hr) return hr;
CComBSTR bstrVolumeObjectDN = _T("CN="); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN); bstrVolumeObjectDN += i_pszShareName; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN); bstrVolumeObjectDN += _T(","); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN); bstrVolumeObjectDN += bstrFQDN; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN); CComBSTR bstrDC; PLDAP pldap = NULL; hr = ConnectToDS(bstrDomainName, &pldap, &bstrDC); if (SUCCEEDED(hr)) { CComBSTR bstrManagedByFQDN; hr = ReadSharePublishInfoHelper( pldap, bstrVolumeObjectDN, OBJCLASS_SF_VOLUME, o_pbPublish, o_pbstrUNCPath, o_pbstrDescription, o_pbstrKeywords, &bstrManagedByFQDN);
if (SUCCEEDED(hr)) { hr = TranslateManagedBy(bstrDC, bstrManagedByFQDN, o_pbstrManagedBy, DS_FQDN_1779_NAME, DS_USER_PRINCIPAL_NAME); if (FAILED(hr)) hr = TranslateManagedBy(bstrDC, bstrManagedByFQDN, o_pbstrManagedBy, DS_FQDN_1779_NAME, DS_NT4_ACCOUNT_NAME); }
CloseConnectionToDS(pldap); }
return hr; }
HRESULT CreateVolumeObject( PLDAP i_pldap, PCTSTR i_pszDN, PCTSTR i_pszUNCPath, PCTSTR i_pszDescription, PCTSTR i_pszKeywords, PCTSTR i_pszManagedBy) { HRESULT hr = S_OK;
LDAP_ATTR_VALUE pAttrVals[5];
int i =0; pAttrVals[i].bstrAttribute = OBJCLASS_ATTRIBUTENAME; pAttrVals[i].vpValue = (void *)OBJCLASS_VOLUME; pAttrVals[i].bBerValue = false; i++;
pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME; pAttrVals[i].vpValue = (void *)i_pszUNCPath; pAttrVals[i].bBerValue = false; i++;
if (i_pszDescription && *i_pszDescription) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION; pAttrVals[i].vpValue = (void *)i_pszDescription; pAttrVals[i].bBerValue = false; i++; }
LDAP_ATTR_VALUE *pHead = NULL; if (i_pszKeywords && *i_pszKeywords) { hr = PutMultiValuesIntoAttrValList(i_pszKeywords, &pHead); if (S_OK == hr) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS; pAttrVals[i].vpValue = (void *)pHead->vpValue; // multi-valued
pAttrVals[i].bBerValue = false; pAttrVals[i].Next = pHead->Next; i++; } }
if (i_pszManagedBy && *i_pszManagedBy) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY; pAttrVals[i].vpValue = (void *)i_pszManagedBy; pAttrVals[i].bBerValue = false; i++; } hr = AddValues(i_pldap, i_pszDN, i, pAttrVals);
if (pHead) FreeAttrValList(pHead);
return hr; }
HRESULT ModifyShareObject( PLDAP i_pldap, PCTSTR i_pszDN, PCTSTR i_pszUNCPath, PCTSTR i_pszDescription, PCTSTR i_pszKeywords, PCTSTR i_pszManagedBy) { HRESULT hr = S_OK;
hr = IsValidObject(i_pldap, (PTSTR)i_pszDN); if (S_OK != hr) return hr;
LDAP_ATTR_VALUE pAttrVals[4]; ZeroMemory(pAttrVals, sizeof(pAttrVals));
//
// modify values if any
//
int i =0; if (i_pszUNCPath && *i_pszUNCPath) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME; pAttrVals[i].vpValue = (void *)i_pszUNCPath; pAttrVals[i].bBerValue = false; i++; }
if (i_pszDescription && *i_pszDescription) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION; pAttrVals[i].vpValue = (void *)i_pszDescription; pAttrVals[i].bBerValue = false; i++; }
LDAP_ATTR_VALUE *pHead = NULL; if (i_pszKeywords && *i_pszKeywords) { hr = PutMultiValuesIntoAttrValList(i_pszKeywords, &pHead); if (S_OK == hr) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS; pAttrVals[i].vpValue = (void *)pHead->vpValue; // multi-valued
pAttrVals[i].bBerValue = false; pAttrVals[i].Next = pHead->Next; i++; } }
if (i_pszManagedBy && *i_pszManagedBy) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY; pAttrVals[i].vpValue = (void *)i_pszManagedBy; pAttrVals[i].bBerValue = false; i++; } if (i > 0) { hr = ModifyValues(i_pldap, i_pszDN, i, pAttrVals); dfsDebugOut((_T("ModifyValues i=%d, hr=%x\n"), i, hr)); }
if (pHead) FreeAttrValList(pHead);
RETURN_IF_FAILED(hr);
//
// delete values if any
//
i =0; ZeroMemory(pAttrVals, sizeof(pAttrVals)); if (!i_pszUNCPath || !*i_pszUNCPath) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_UNCNAME; pAttrVals[i].vpValue = NULL; pAttrVals[i].bBerValue = false; i++; }
if (!i_pszDescription || !*i_pszDescription) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_DESCRIPTION; pAttrVals[i].vpValue = NULL; pAttrVals[i].bBerValue = false; i++; }
if (!i_pszKeywords || !*i_pszKeywords) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_KEYWORDS; pAttrVals[i].vpValue = NULL; pAttrVals[i].bBerValue = false; i++; }
if (!i_pszManagedBy || !*i_pszManagedBy) { pAttrVals[i].bstrAttribute = ATTR_SHRPUB_MANAGEDBY; pAttrVals[i].vpValue = NULL; pAttrVals[i].bBerValue = false; i++; }
if (i > 0) { hr = DeleteValues(i_pldap, i_pszDN, i, pAttrVals); dfsDebugOut((_T("DeleteValues i=%d, hr=%x\n"), i, hr)); }
return hr; }
HRESULT ModifySharePublishInfoOnFTRoot( IN PCTSTR i_pszDomainName, IN PCTSTR i_pszRootName, IN BOOL i_bPublish, IN PCTSTR i_pszUNCPath, IN PCTSTR i_pszDescription, IN PCTSTR i_pszKeywords, IN PCTSTR i_pszManagedBy ) { dfsDebugOut((_T("ModifySharePublishInfoOnFTRoot %s, %s, %d, %s, %s, %s, %s\n"), i_pszDomainName, i_pszRootName, i_bPublish, i_pszUNCPath, i_pszDescription, i_pszKeywords, i_pszManagedBy ));
CComBSTR bstrFTDfsObjectDN; HRESULT hr = GetFTDfsObjectDN(i_pszDomainName, i_pszRootName, &bstrFTDfsObjectDN); if (FAILED(hr)) return hr;
CComBSTR bstrDC; PLDAP pldap = NULL; hr = ConnectToDS(i_pszDomainName, &pldap, &bstrDC); // PDC is preferred
if (SUCCEEDED(hr)) { if (i_bPublish) { CComBSTR bstrManagedByFQDN; if (i_pszManagedBy && *i_pszManagedBy) { hr = TranslateManagedBy(bstrDC, i_pszManagedBy, &bstrManagedByFQDN, (_tcschr(i_pszManagedBy, _T('@')) ? DS_USER_PRINCIPAL_NAME : DS_NT4_ACCOUNT_NAME), DS_FQDN_1779_NAME); }
if (SUCCEEDED(hr)) hr = ModifyShareObject( pldap, bstrFTDfsObjectDN, i_pszUNCPath, i_pszDescription, i_pszKeywords, bstrManagedByFQDN); } else { hr = ModifyShareObject( pldap, bstrFTDfsObjectDN, NULL, NULL, NULL, NULL); if (S_FALSE == hr) hr = S_OK; // ignore non-existing object
}
CloseConnectionToDS(pldap); }
dfsDebugOut((_T("ModifySharePublishInfoOnFTRoot hr=%x\n"), hr));
return hr; }
HRESULT ModifySharePublishInfoOnSARoot( IN PCTSTR i_pszServerName, IN PCTSTR i_pszShareName, IN BOOL i_bPublish, IN PCTSTR i_pszUNCPath, IN PCTSTR i_pszDescription, IN PCTSTR i_pszKeywords, IN PCTSTR i_pszManagedBy ) { dfsDebugOut((_T("ModifySharePublishInfoOnSARoot %s, %s, %d, %s, %s, %s, %s\n"), i_pszServerName, i_pszShareName, i_bPublish, i_pszUNCPath, i_pszDescription, i_pszKeywords, i_pszManagedBy ));
CComBSTR bstrDomainName, bstrFQDN; HRESULT hr = GetServerInfo( (PTSTR)i_pszServerName, &bstrDomainName, NULL, //NetbiosName
NULL, //ValidDSObject
NULL, //DnsName,
NULL, //Guid,
&bstrFQDN); if (S_OK != hr) return hr;
CComBSTR bstrVolumeObjectDN = _T("CN="); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN); bstrVolumeObjectDN += i_pszShareName; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN); bstrVolumeObjectDN += _T(","); RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN); bstrVolumeObjectDN += bstrFQDN; RETURN_OUTOFMEMORY_IF_NULL((BSTR)bstrVolumeObjectDN);
CComBSTR bstrDC; PLDAP pldap = NULL; hr = ConnectToDS(bstrDomainName, &pldap, &bstrDC); if (SUCCEEDED(hr)) { if (i_bPublish) { CComBSTR bstrManagedByFQDN; if (i_pszManagedBy && *i_pszManagedBy) { hr = TranslateManagedBy(bstrDC, i_pszManagedBy, &bstrManagedByFQDN, (_tcschr(i_pszManagedBy, _T('@')) ? DS_USER_PRINCIPAL_NAME : DS_NT4_ACCOUNT_NAME), DS_FQDN_1779_NAME); }
if (SUCCEEDED(hr)) { hr = IsValidObject(pldap, bstrVolumeObjectDN); if (S_OK == hr) { hr = ModifyShareObject( pldap, bstrVolumeObjectDN, i_pszUNCPath, i_pszDescription, i_pszKeywords, bstrManagedByFQDN); } else { hr = CreateVolumeObject( pldap, bstrVolumeObjectDN, i_pszUNCPath, i_pszDescription, i_pszKeywords, bstrManagedByFQDN); } } } else { hr = DeleteDSObject(pldap, bstrVolumeObjectDN, TRUE); if (S_FALSE == hr) hr = S_OK; // ignore non-existing object
}
CloseConnectionToDS(pldap); } dfsDebugOut((_T("ModifySharePublishInfoOnSARoot hr=%x\n"), hr));
return hr; }
HRESULT PutMultiValuesIntoAttrValList( IN PCTSTR i_pszValues, OUT LDAP_ATTR_VALUE** o_pVal ) { if (!i_pszValues || !o_pVal) return E_INVALIDARG;
LDAP_ATTR_VALUE* pHead = NULL; LDAP_ATTR_VALUE* pCurrent = NULL;
int index = 0; CComBSTR bstrToken; HRESULT hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken); while (SUCCEEDED(hr) && (BSTR)bstrToken) { TrimBSTR(bstrToken);
if (*bstrToken) { LDAP_ATTR_VALUE* pNew = new LDAP_ATTR_VALUE; RETURN_OUTOFMEMORY_IF_NULL(pNew); pNew->vpValue = _tcsdup(bstrToken); if (!(pNew->vpValue)) { delete pNew; hr = E_OUTOFMEMORY; break; }
if (!pHead) { pHead = pCurrent = pNew; } else { pCurrent->Next = pNew; pCurrent = pNew; } }
bstrToken.Empty(); hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken); }
if (FAILED(hr)) { FreeAttrValList(pHead); return hr; }
int nCount = 0; pCurrent = pHead; while (pCurrent) { nCount++; pCurrent = pCurrent->Next; } if (!nCount) return S_FALSE; // no token
*o_pVal = pHead;
return S_OK; }
HRESULT PutMultiValuesIntoStringArray( IN PCTSTR i_pszValues, OUT PTSTR** o_pVal ) { if (!i_pszValues || !o_pVal) return E_INVALIDARG;
int nCount = 0; CComBSTR bstrToken; int index = 0; HRESULT hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken); while (SUCCEEDED(hr) && (BSTR)bstrToken) { nCount++;
bstrToken.Empty(); hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);; }
if (!nCount) return E_INVALIDARG;
PTSTR* ppszStrings = (PTSTR *)calloc(nCount + 1, sizeof(PTSTR *)); RETURN_OUTOFMEMORY_IF_NULL(ppszStrings);
nCount = 0; index = 0; bstrToken.Empty(); hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken); while (SUCCEEDED(hr) && (BSTR)bstrToken) { TrimBSTR(bstrToken); if (*bstrToken) { ppszStrings[nCount] = _tcsdup(bstrToken); BREAK_OUTOFMEMORY_IF_NULL(ppszStrings[nCount], &hr);
nCount++; }
bstrToken.Empty(); hr = mystrtok(i_pszValues, &index, _T(";"), &bstrToken);; }
if (FAILED(hr)) FreeStringArray(ppszStrings); else *o_pVal = ppszStrings;
return hr; }
//
// free a null-terminated array of strings
//
void FreeStringArray(PTSTR* i_ppszStrings) { if (i_ppszStrings) { PTSTR* ppszString = i_ppszStrings; while (*ppszString) { free(*ppszString); ppszString++; }
free(i_ppszStrings); } }
HRESULT mystrtok( IN PCTSTR i_pszString, IN OUT int* io_pnIndex, // start from 0
IN PCTSTR i_pszCharSet, OUT BSTR* o_pbstrToken ) { if (!i_pszString || !*i_pszString || !i_pszCharSet || !io_pnIndex || !o_pbstrToken) return E_INVALIDARG;
*o_pbstrToken = NULL;
HRESULT hr = S_OK;
if (*io_pnIndex >= lstrlen(i_pszString)) { return hr; // no more tokens
}
TCHAR *ptchStart = (PTSTR)i_pszString + *io_pnIndex; if (!*i_pszCharSet) { *o_pbstrToken = SysAllocString(ptchStart); if (!*o_pbstrToken) hr = E_OUTOFMEMORY; return hr; }
//
// move p to the 1st char of the token
//
TCHAR *p = ptchStart; while (*p) { if (_tcschr(i_pszCharSet, *p)) p++; else break; }
ptchStart = p; // adjust ptchStart to point at the 1st char of the token
//
// move p to the char after the last char of the token
//
while (*p) { if (_tcschr(i_pszCharSet, *p)) break; else p++; }
//
// ptchStart: points at the 1st char of the token
// p: points at the char after the last char of the token
//
if (ptchStart != p) { *o_pbstrToken = SysAllocStringLen(ptchStart, (int)(p - ptchStart)); if (!*o_pbstrToken) hr = E_OUTOFMEMORY; *io_pnIndex = (int)(p - i_pszString); }
return hr; }
//
// trim off space chars at the beginning and at the end of the string
//
void TrimBSTR(BSTR bstr) { if (!bstr) return;
TCHAR* p = bstr;
//
// trim off space chars at the beginning
//
while (*p) { if (_istspace(*p)) p++; else break; }
if (p > bstr) _tcscpy(bstr, p);
int len = _tcslen(bstr); if (len > 0) { //
// trim off space chars at the end
//
p = bstr + len - 1; // the char before the ending '\0'
while (p > bstr) { if (_istspace(*p)) p--; else { *(p+1) = _T('\0'); break; } } }
}
BOOL CheckPolicyOnSharePublish() { //
// check group policy
//
BOOL bAddPublishPage = TRUE; // by default, we display the share publish page
HKEY hKey = NULL; DWORD dwType = 0; DWORD dwData = 0; DWORD cbData = sizeof(dwData); LONG lErr = RegOpenKeyEx( HKEY_CURRENT_USER, _T("Software\\Policies\\Microsoft\\Windows NT\\SharedFolders"), 0, KEY_QUERY_VALUE, &hKey); if (ERROR_SUCCESS == lErr) { lErr = RegQueryValueEx(hKey, _T("PublishDfsRoots"), 0, &dwType, (LPBYTE)&dwData, &cbData);
if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 0 == dwData) // policy is disabled
bAddPublishPage = FALSE;
RegCloseKey(hKey); }
return bAddPublishPage;
}
BOOL CheckPolicyOnDisplayingInitialMaster() { BOOL bShowInitialMaster = FALSE; // by default, we hide the initial master on property page
HKEY hKey = NULL; DWORD dwType = 0; DWORD dwData = 0; DWORD cbData = sizeof(dwData); LONG lErr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\DfsGui"), 0, KEY_QUERY_VALUE, &hKey); if (ERROR_SUCCESS == lErr) { lErr = RegQueryValueEx(hKey, _T("ShowInitialMaster"), 0, &dwType, (LPBYTE)&dwData, &cbData);
if (ERROR_SUCCESS == lErr && REG_DWORD == dwType && 1 == dwData) bShowInitialMaster = TRUE;
RegCloseKey(hKey); }
return bShowInitialMaster;
}
HRESULT GetMenuResourceStrings( IN int i_iStringID, OUT BSTR* o_pbstrMenuText, OUT BSTR* o_pbstrToolTipText, OUT BSTR* o_pbstrStatusBarText ) { if (!i_iStringID) return E_INVALIDARG;
if (o_pbstrMenuText) *o_pbstrMenuText = NULL; if (o_pbstrToolTipText) *o_pbstrToolTipText = NULL; if (o_pbstrStatusBarText) *o_pbstrStatusBarText = NULL;
TCHAR *pszMenuText = NULL; TCHAR *pszToolTipText = NULL; TCHAR *pszStatusBarText = NULL; TCHAR *p = NULL;
CComBSTR bstr; HRESULT hr = LoadStringFromResource(i_iStringID, &bstr); RETURN_IF_FAILED(hr);
pszMenuText = (BSTR)bstr; p = _tcschr(pszMenuText, _T('|')); RETURN_INVALIDARG_IF_NULL(p); *p++ = _T('\0');
pszToolTipText = p; p = _tcschr(pszToolTipText, _T('|')); RETURN_INVALIDARG_IF_NULL(p); *p++ = _T('\0');
pszStatusBarText = p;
do { if (o_pbstrMenuText) { *o_pbstrMenuText = SysAllocString(pszMenuText); BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrMenuText, &hr); }
if (o_pbstrToolTipText) { *o_pbstrToolTipText = SysAllocString(pszToolTipText); BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrToolTipText, &hr); }
if (o_pbstrStatusBarText) { *o_pbstrStatusBarText = SysAllocString(pszStatusBarText); BREAK_OUTOFMEMORY_IF_NULL(*o_pbstrStatusBarText, &hr); } } while (0);
if (FAILED(hr)) { if (o_pbstrMenuText && *o_pbstrMenuText) SysFreeString(*o_pbstrMenuText); if (o_pbstrToolTipText && *o_pbstrToolTipText) SysFreeString(*o_pbstrToolTipText); if (o_pbstrStatusBarText && *o_pbstrStatusBarText) SysFreeString(*o_pbstrStatusBarText); }
return hr; }
WNDPROC g_fnOldEditCtrlProc;
//+----------------------------------------------------------------------------
//
// Function: NoPasteEditCtrlProc
//
// Synopsis: The subclassed edit control callback procedure.
// The paste of this edit control is disabled.
//
//-----------------------------------------------------------------------------
LRESULT CALLBACK NoPasteEditCtrlProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (WM_PASTE == uMsg) { ::MessageBeep (0); return TRUE; }
return CallWindowProc(g_fnOldEditCtrlProc, hwnd, uMsg, wParam, lParam); }
void SetActivePropertyPage(IN HWND i_hwndParent, IN HWND i_hwndPage) { int index = ::SendMessage(i_hwndParent, PSM_HWNDTOINDEX, (WPARAM)i_hwndPage, 0); if (-1 != index) ::SendMessage(i_hwndParent, PSM_SETCURSEL, (WPARAM)index, 0); }
void MyShowWindow(HWND hwnd, BOOL bShow) { ::ShowWindow(hwnd, (bShow ? SW_NORMAL : SW_HIDE)); ::EnableWindow(hwnd, (bShow ? TRUE : FALSE)); }
//
// 7/11/2001 LinanT bug#426953
// Since connection made by Terminal Service may bring some client side resources
// (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
// the OK button when browsing to a non-local folder. We don't have this problem
// when browsing a remote machine.
//
typedef struct _LOCAL_DISKS { LPTSTR pszDisks; DWORD dwNumOfDisks; } LOCAL_DISKS;
#define DISK_ENTRY_LENGTH 3 // Drive letter, colon, NULL
#define DISK_NAME_LENGTH 2 // Drive letter, colon
BOOL InDiskList(IN LPCTSTR pszDir, IN LOCAL_DISKS *pDisks) { if (!pszDir || !pDisks) return FALSE;
DWORD i = 0; PTSTR pszDisk = pDisks->pszDisks; for (; pszDisk && i < pDisks->dwNumOfDisks; i++) { if (!_tcsnicmp(pszDisk, pszDir, DISK_NAME_LENGTH)) return TRUE;
pszDisk += DISK_ENTRY_LENGTH; }
return FALSE; }
int CALLBACK BrowseCallbackProc( IN HWND hwnd, IN UINT uMsg, IN LPARAM lp, IN LPARAM pData ) { switch(uMsg) { case BFFM_SELCHANGED: { // enable the OK button if the selected path is local to that computer.
BOOL bEnableOK = FALSE; TCHAR szDir[MAX_PATH]; if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir)) { if (pData) { // we're looking at a local computer, verify if szDir is on a local disk
bEnableOK = InDiskList(szDir, (LOCAL_DISKS *)pData); } else { // no such problem when browsing at a remote computer, always enable OK button.
bEnableOK = TRUE; } } SendMessage(hwnd, BFFM_ENABLEOK, 0, (LPARAM)bEnableOK); break; } case BFFM_VALIDATEFAILED: { DisplayMessageBox(hwnd, MB_OK, 0, IDS_BROWSE_FOLDER_INVALID); return 1; } default: break; }
return 0; }
void OpenBrowseDialog( IN HWND hwndParent, IN int idLabel, IN BOOL bLocalComputer, IN LPCTSTR lpszComputer, OUT LPTSTR lpszDir) { _ASSERT(lpszComputer && *lpszComputer);
LOCAL_DISKS localDisks = {0};
CComBSTR bstrComputer; if (*lpszComputer != _T('\\') || *(lpszComputer + 1) != _T('\\')) { bstrComputer = _T("\\\\"); bstrComputer += lpszComputer; } else { bstrComputer = lpszComputer; }
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { LPMALLOC pMalloc; hr = SHGetMalloc(&pMalloc); if (SUCCEEDED(hr)) { LPSHELLFOLDER pDesktopFolder; hr = SHGetDesktopFolder(&pDesktopFolder); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlRoot; if (bLocalComputer) { hr = SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &pidlRoot); if (SUCCEEDED(hr)) { //
// 7/11/2001 LinanT bug#426953
// Since connection made by Terminal Service may bring some client side resources
// (disks, serial ports, etc.) into "My Computer" namespace, we want to disable
// the OK button when browsing to a non-local folder. We don't have this problem
// when browsing a remote machine.
//
//
// Get an array of local disk names, this information is later used
// in the browse dialog to disable OK button if non-local path is selected.
//
DWORD dwTotalEntries = 0; DWORD nStatus = NetServerDiskEnum( NULL, // local computer
0, // level must be zero
(LPBYTE *)&(localDisks.pszDisks), -1, // dwPrefMaxLen,
&(localDisks.dwNumOfDisks), &dwTotalEntries, NULL); if (NERR_Success != nStatus) { hr = HRESULT_FROM_WIN32(nStatus); } } } else { hr = pDesktopFolder->ParseDisplayName(hwndParent, NULL, bstrComputer, NULL, &pidlRoot, NULL); }
if (SUCCEEDED(hr)) { CComBSTR bstrLabel; LoadStringFromResource(idLabel, &bstrLabel);
BROWSEINFO bi; ZeroMemory(&bi,sizeof(bi)); bi.hwndOwner = hwndParent; bi.pszDisplayName = 0; bi.lpszTitle = bstrLabel; bi.pidlRoot = pidlRoot; bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_SHAREABLE | BIF_USENEWUI | BIF_VALIDATE; bi.lpfn = BrowseCallbackProc; if (localDisks.pszDisks) bi.lParam = (LPARAM)&localDisks; // pass the structure to the browse dialog
LPITEMIDLIST pidl = SHBrowseForFolder(&bi); if (pidl) { SHGetPathFromIDList(pidl, lpszDir); pMalloc->Free(pidl); } pMalloc->Free(pidlRoot); } pDesktopFolder->Release(); } pMalloc->Release(); }
CoUninitialize(); }
if (localDisks.pszDisks) NetApiBufferFree(localDisks.pszDisks);
if (FAILED(hr)) DisplayMessageBox(::GetActiveWindow(), MB_OK, hr, IDS_CANNOT_BROWSE_FOLDER, lpszComputer); }
|