1555 lines
38 KiB
C++
1555 lines
38 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1995.
|
|
//
|
|
// File: util.cxx
|
|
//
|
|
// Contents: Misc helper functions
|
|
//
|
|
// History: 5-Apr-95 BruceFo Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "headers.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include "resource.h"
|
|
#include "shares.h"
|
|
#include "util.hxx"
|
|
#include "shrpage.hxx"
|
|
#include "dlgnew.hxx"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DECLARE_INFOLEVEL(Sharing)
|
|
|
|
#define NETMSG_DLL TEXT("netmsg.dll")
|
|
|
|
#ifdef WIZARDS
|
|
TCHAR g_szShareWizardCmd[] = TEXT("ShrPubW.exe"); // The Share Publishing Wizard
|
|
TCHAR g_szShareWizardArg[] = TEXT("/folder "); // The Share Publishing Wizard
|
|
TCHAR g_szSfm[] = TEXT("/sfm "); // Services For Macintosh
|
|
TCHAR g_szFpnw[] = TEXT("/fpnw "); // File and Print Services for NetWare
|
|
TCHAR g_szAll[] = TEXT("/all "); // all services
|
|
#endif // WIZARDS
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Globals used elsewhere
|
|
|
|
UINT g_NonOLEDLLRefs = 0;
|
|
HINSTANCE g_hInstance = NULL;
|
|
UINT g_uiMaxUsers = 0; // max number of users based on product type
|
|
WCHAR g_szAdminShare[] = L"ADMIN$";
|
|
WCHAR g_szIpcShare[] = L"IPC$";
|
|
UINT g_cfHIDA = 0;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD
|
|
ConfirmStopShare(
|
|
IN HWND hwnd,
|
|
IN LPWSTR pszShare
|
|
);
|
|
|
|
NET_API_STATUS
|
|
ShareConnectionInfo(
|
|
IN LPWSTR pszShare,
|
|
OUT LPDWORD pcConns,
|
|
OUT LPDWORD pcOpens
|
|
);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: MyFormatMessageText
|
|
//
|
|
// Synopsis: Given a resource IDs, load strings from given instance
|
|
// and format the string into a buffer
|
|
//
|
|
// History: 11-Aug-93 WilliamW Created.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
MyFormatMessageText(
|
|
IN HRESULT dwMsgId,
|
|
IN PWSTR pszBuffer,
|
|
IN DWORD dwBufferSize,
|
|
IN va_list * parglist
|
|
)
|
|
{
|
|
//
|
|
// get message from system or app msg file.
|
|
//
|
|
|
|
DWORD dwReturn = FormatMessage(
|
|
FORMAT_MESSAGE_FROM_HMODULE,
|
|
g_hInstance,
|
|
dwMsgId,
|
|
LANG_USER_DEFAULT,
|
|
pszBuffer,
|
|
dwBufferSize,
|
|
parglist);
|
|
|
|
if (0 == dwReturn) // couldn't find message
|
|
{
|
|
appDebugOut((DEB_IERROR,
|
|
"FormatMessage failed, 0x%08lx\n",
|
|
GetLastError()));
|
|
|
|
WCHAR szText[200];
|
|
LoadString(g_hInstance, IDS_APP_MSG_NOT_FOUND, szText, ARRAYLEN(szText));
|
|
wsprintf(pszBuffer,szText,dwMsgId);
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: MyFormatMessage
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Note:
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
MyFormatMessage(
|
|
IN HRESULT dwMsgId,
|
|
IN PWSTR pszBuffer,
|
|
IN DWORD dwBufferSize,
|
|
...
|
|
)
|
|
{
|
|
va_list arglist;
|
|
va_start(arglist, dwBufferSize);
|
|
MyFormatMessageText(dwMsgId, pszBuffer, dwBufferSize, &arglist);
|
|
va_end(arglist);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: MyCommonDialog
|
|
//
|
|
// Synopsis: Common popup dialog routine - stole from diskadm directory
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
MyCommonDialog(
|
|
IN HWND hwnd,
|
|
IN HRESULT dwMsgCode,
|
|
IN PWSTR pszCaption,
|
|
IN DWORD dwFlags,
|
|
IN va_list arglist
|
|
)
|
|
{
|
|
WCHAR szMsgBuf[500];
|
|
|
|
MyFormatMessageText(dwMsgCode, szMsgBuf, ARRAYLEN(szMsgBuf), &arglist);
|
|
return MessageBox(hwnd, szMsgBuf, pszCaption, dwFlags);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: MyConfirmationDialog
|
|
//
|
|
// Synopsis: This routine retreives a message from the app or system
|
|
// message file and displays it in a message box.
|
|
//
|
|
// Note: Stole from diskadm directory
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
DWORD
|
|
MyConfirmationDialog(
|
|
IN HWND hwnd,
|
|
IN HRESULT dwMsgCode,
|
|
IN DWORD dwFlags,
|
|
...
|
|
)
|
|
{
|
|
WCHAR szCaption[100];
|
|
DWORD dwReturn;
|
|
va_list arglist;
|
|
|
|
va_start(arglist, dwFlags);
|
|
|
|
LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
|
|
dwReturn = MyCommonDialog(hwnd, dwMsgCode, szCaption, dwFlags, arglist);
|
|
va_end(arglist);
|
|
|
|
return dwReturn;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: MyErrorDialog
|
|
//
|
|
// Synopsis: This routine retreives a message from the app or system
|
|
// message file and displays it in a message box.
|
|
//
|
|
// Note: Stole from diskadm directory
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
VOID
|
|
MyErrorDialog(
|
|
IN HWND hwnd,
|
|
IN HRESULT dwErrorCode,
|
|
...
|
|
)
|
|
{
|
|
WCHAR szCaption[100];
|
|
va_list arglist;
|
|
|
|
va_start(arglist, dwErrorCode);
|
|
|
|
LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
|
|
MyCommonDialog(hwnd, dwErrorCode, szCaption, MB_ICONSTOP | MB_OK, arglist);
|
|
|
|
va_end(arglist);
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: NewDup
|
|
//
|
|
// Synopsis: Duplicate a string using '::new'
|
|
//
|
|
// History: 28-Dec-94 BruceFo Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
PWSTR
|
|
NewDup(
|
|
IN const WCHAR* psz
|
|
)
|
|
{
|
|
if (NULL == psz)
|
|
{
|
|
appDebugOut((DEB_IERROR,"Illegal string to duplicate: NULL\n"));
|
|
return NULL;
|
|
}
|
|
|
|
PWSTR pszRet = new WCHAR[wcslen(psz) + 1];
|
|
if (NULL == pszRet)
|
|
{
|
|
appDebugOut((DEB_ERROR,"OUT OF MEMORY\n"));
|
|
return NULL;
|
|
}
|
|
|
|
wcscpy(pszRet, psz);
|
|
return pszRet;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetResourceString
|
|
//
|
|
// Synopsis: Load a resource string, are return a "new"ed copy
|
|
//
|
|
// Arguments: [dwId] -- a resource string ID
|
|
//
|
|
// Returns: new memory copy of a string
|
|
//
|
|
// History: 5-Apr-95 BruceFo Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
PWSTR
|
|
GetResourceString(
|
|
IN DWORD dwId
|
|
)
|
|
{
|
|
WCHAR sz[50];
|
|
if (0 == LoadString(g_hInstance, dwId, sz, ARRAYLEN(sz)))
|
|
{
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
return NewDup(sz);
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: CopySecurityDescriptor, public
|
|
//
|
|
// Synopsis: Copy an NT security descriptor. The security descriptor must
|
|
// be in self-relative (not absolute) form. Delete the result
|
|
// using LocalFree().
|
|
//
|
|
// History: 19-Apr-95 BruceFo Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
PSECURITY_DESCRIPTOR
|
|
CopySecurityDescriptor(
|
|
IN PSECURITY_DESCRIPTOR pSecDesc
|
|
)
|
|
{
|
|
appDebugOut((DEB_ITRACE, "CopySecurityDescriptor, pSecDesc = 0x%08lx\n", pSecDesc));
|
|
|
|
if (NULL == pSecDesc)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
appAssert(IsValidSecurityDescriptor(pSecDesc));
|
|
|
|
LONG err;
|
|
|
|
DWORD dwLen = GetSecurityDescriptorLength(pSecDesc);
|
|
PSECURITY_DESCRIPTOR pSelfSecDesc = reinterpret_cast<PSECURITY_DESCRIPTOR>(
|
|
::LocalAlloc(LMEM_ZEROINIT, dwLen) );
|
|
if (NULL == pSelfSecDesc)
|
|
{
|
|
appDebugOut((DEB_ERROR, "new SECURITY_DESCRIPTOR (2) failed\n"));
|
|
return NULL; // actually, should probably return an error
|
|
}
|
|
|
|
DWORD cbSelfSecDesc = dwLen;
|
|
if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc))
|
|
{
|
|
appDebugOut((DEB_TRACE, "MakeSelfRelativeSD failed, 0x%08lx\n", GetLastError()));
|
|
|
|
// assume it failed because it was already self-relative
|
|
CopyMemory(pSelfSecDesc, pSecDesc, dwLen);
|
|
}
|
|
|
|
appAssert(IsValidSecurityDescriptor(pSelfSecDesc));
|
|
|
|
return pSelfSecDesc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DisplayError
|
|
//
|
|
// Synopsis: Display an error message
|
|
//
|
|
// History: 24-Apr-95 BruceFo Stolen
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DisplayError(
|
|
IN HWND hwnd,
|
|
IN HRESULT dwErrorCode, // message file number. not really an HRESULT
|
|
IN NET_API_STATUS err,
|
|
IN PWSTR pszShare
|
|
)
|
|
{
|
|
if ( err < MIN_LANMAN_MESSAGE_ID
|
|
|| err > MAX_LANMAN_MESSAGE_ID
|
|
)
|
|
{
|
|
// a Win32 error?
|
|
|
|
WCHAR szMsg[500];
|
|
DWORD dwReturn = FormatMessage(
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
err,
|
|
LANG_USER_DEFAULT,
|
|
szMsg,
|
|
ARRAYLEN(szMsg),
|
|
NULL);
|
|
if (0 == dwReturn) // couldn't find message
|
|
{
|
|
appDebugOut((DEB_IERROR,
|
|
"FormatMessage (from system) failed, 0x%08lx\n",
|
|
GetLastError()));
|
|
|
|
MyErrorDialog(hwnd, IERR_UNKNOWN, err);
|
|
}
|
|
else
|
|
{
|
|
MyErrorDialog(hwnd, dwErrorCode, pszShare, szMsg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DisplayLanmanError(hwnd, dwErrorCode, err, pszShare);
|
|
}
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DisplayLanmanError
|
|
//
|
|
// Synopsis: Display an error message from a LanMan error.
|
|
//
|
|
// History: 24-Apr-95 BruceFo Stolen
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DisplayLanmanError(
|
|
IN HWND hwnd,
|
|
IN HRESULT dwErrorCode, // message file number. not really an HRESULT
|
|
IN NET_API_STATUS err,
|
|
IN PWSTR pszShare
|
|
)
|
|
{
|
|
if ( err < MIN_LANMAN_MESSAGE_ID
|
|
|| err > MAX_LANMAN_MESSAGE_ID
|
|
)
|
|
{
|
|
MyErrorDialog(hwnd, IERR_UNKNOWN, err);
|
|
return;
|
|
}
|
|
|
|
WCHAR szCaption[100];
|
|
LoadString(g_hInstance, IDS_MSGTITLE, szCaption, ARRAYLEN(szCaption));
|
|
|
|
//
|
|
// get LanMan message from system message file.
|
|
//
|
|
|
|
WCHAR szNetMsg[500];
|
|
WCHAR szBuf[500];
|
|
|
|
HINSTANCE hInstanceNetMsg = LoadLibrary(NETMSG_DLL);
|
|
if (NULL == hInstanceNetMsg)
|
|
{
|
|
appDebugOut((DEB_IERROR,
|
|
"LoadLibrary(netmsg.dll) failed, 0x%08lx\n",
|
|
GetLastError()));
|
|
|
|
LoadString(g_hInstance, IDS_NO_NET_MSG, szBuf, ARRAYLEN(szBuf));
|
|
MessageBox(hwnd, szBuf, szCaption, MB_ICONSTOP | MB_OK);
|
|
return;
|
|
}
|
|
|
|
DWORD dwReturn = FormatMessage(
|
|
FORMAT_MESSAGE_FROM_HMODULE,
|
|
hInstanceNetMsg,
|
|
err,
|
|
LANG_USER_DEFAULT,
|
|
szNetMsg,
|
|
ARRAYLEN(szNetMsg),
|
|
NULL);
|
|
if (0 == dwReturn) // couldn't find message
|
|
{
|
|
appDebugOut((DEB_IERROR,
|
|
"FormatMessage failed, 0x%08lx\n",
|
|
GetLastError()));
|
|
|
|
LoadString(g_hInstance, IDS_NET_MSG_NOT_FOUND, szBuf, ARRAYLEN(szBuf));
|
|
wsprintf(szNetMsg, szBuf, GetLastError());
|
|
MessageBox(hwnd, szNetMsg, szCaption, MB_ICONSTOP | MB_OK);
|
|
}
|
|
else
|
|
{
|
|
MyErrorDialog(hwnd, dwErrorCode, pszShare, szNetMsg);
|
|
}
|
|
|
|
FreeLibrary(hInstanceNetMsg);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: IsValidShareName
|
|
//
|
|
// Synopsis: Checks if the proposed share name is valid or not. If not,
|
|
// it will return a message id for the reason why.
|
|
//
|
|
// Arguments: [pszShareName] - Proposed share name
|
|
// [puId] - If name is invalid, this will contain the reason why.
|
|
//
|
|
// Returns: TRUE if name is valid, else FALSE.
|
|
//
|
|
// History: 3-May-95 BruceFo Stolen
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
IsValidShareName(
|
|
IN PCWSTR pszShareName,
|
|
OUT HRESULT* uId
|
|
)
|
|
{
|
|
if (NetpNameValidate(NULL, (PWSTR)pszShareName, NAMETYPE_SHARE, 0L) != NERR_Success)
|
|
{
|
|
*uId = IERR_InvalidShareName;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SetErrorFocus
|
|
//
|
|
// Synopsis: Set focus to an edit control and select its text.
|
|
//
|
|
// Arguments: [hwnd] - dialog window
|
|
// [idCtrl] - edit control to set focus to (and select)
|
|
//
|
|
// Returns: nothing
|
|
//
|
|
// History: 3-May-95 BruceFo Stolen
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
SetErrorFocus(
|
|
IN HWND hwnd,
|
|
IN UINT idCtrl
|
|
)
|
|
{
|
|
HWND hCtrl = ::GetDlgItem(hwnd, idCtrl);
|
|
::SetFocus(hCtrl);
|
|
::SendMessage(hCtrl, EM_SETSEL, 0, -1);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ConfirmReplaceShare
|
|
//
|
|
// Synopsis: Display confirmations for replacing an existing share
|
|
//
|
|
// Arguments: [hwnd] - dialog window
|
|
// [pszShareName] - name of share being replaced
|
|
// [pszOldPath] - current path for the share
|
|
// [pszNewPath] - directory the user's trying to share
|
|
//
|
|
// Returns: Returns IDYES, IDNO, or IDCANCEL
|
|
//
|
|
// History: 4-May-95 BruceFo Stolen
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
ConfirmReplaceShare(
|
|
IN HWND hwnd,
|
|
IN PCWSTR pszShareName,
|
|
IN PCWSTR pszOldPath,
|
|
IN PCWSTR pszNewPath
|
|
)
|
|
{
|
|
DWORD id = MyConfirmationDialog(
|
|
hwnd,
|
|
MSG_RESHARENAMECONFIRM,
|
|
MB_YESNO | MB_ICONEXCLAMATION,
|
|
pszOldPath,
|
|
pszShareName,
|
|
pszNewPath);
|
|
if (id != IDYES)
|
|
{
|
|
return id;
|
|
}
|
|
|
|
return ConfirmStopShare(hwnd, (PWSTR)pszShareName);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: ConfirmStopShare, public
|
|
//
|
|
// Synopsis: Display the appropriate confirmations when stopping a share.
|
|
//
|
|
// Arguments: [hwnd] - parent window handle for messages
|
|
// [pszShare] - ptr to affected share name
|
|
//
|
|
// Returns: IDYES if share should be deleted, IDNO if we don't want to
|
|
// delete, but keep going, IDCANCEL to stop going.
|
|
//
|
|
// History: 19-Apr-95 BruceFo Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
DWORD
|
|
ConfirmStopShare(
|
|
IN HWND hwnd,
|
|
IN LPWSTR pszShare
|
|
)
|
|
{
|
|
DWORD cConns, cOpens;
|
|
NET_API_STATUS err = ShareConnectionInfo(pszShare, &cConns, &cOpens);
|
|
if (err != NERR_Success)
|
|
{
|
|
DisplayError(hwnd, IERR_CANT_DEL_SHARE, err, pszShare);
|
|
return IDYES; // allow the stop anyway
|
|
}
|
|
|
|
if (cConns != 0)
|
|
{
|
|
// If there are any open files, just give the more detailed
|
|
// message about there being open files. Otherwise, just say how
|
|
// many connections there are.
|
|
|
|
if (cOpens != 0)
|
|
{
|
|
return MyConfirmationDialog(
|
|
hwnd,
|
|
MSG_STOPSHAREOPENS,
|
|
MB_YESNOCANCEL | MB_ICONEXCLAMATION,
|
|
cOpens,
|
|
cConns,
|
|
pszShare);
|
|
}
|
|
else
|
|
{
|
|
return MyConfirmationDialog(
|
|
hwnd,
|
|
MSG_STOPSHARECONNS,
|
|
MB_YESNOCANCEL | MB_ICONEXCLAMATION,
|
|
cConns,
|
|
pszShare);
|
|
}
|
|
}
|
|
|
|
return IDYES; /* OK to delete */
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Member: ShareConnectionInfo, public
|
|
//
|
|
// Synopsis: Determine how many connections and file opens exist for a
|
|
// share, for use by confirmation dialogs.
|
|
//
|
|
// Arguments: [pszShare] - ptr to affected share name
|
|
// [pcConns] - *pcConns get the number of connections
|
|
// [pcOpens] - *pcOpens get the number of file opens
|
|
//
|
|
// Returns: standard net api code, NERR_Success if everything ok.
|
|
//
|
|
// History: 19-Apr-95 BruceFo Stolen
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
NET_API_STATUS
|
|
ShareConnectionInfo(
|
|
IN LPWSTR pszShare,
|
|
OUT LPDWORD pcConns,
|
|
OUT LPDWORD pcOpens
|
|
)
|
|
{
|
|
CONNECTION_INFO_1* pBuf;
|
|
|
|
DWORD iEntry, iTotal;
|
|
NET_API_STATUS err = NetConnectionEnum(
|
|
NULL,
|
|
pszShare,
|
|
1,
|
|
(LPBYTE*)&pBuf,
|
|
0xffffffff, // no buffer limit; get them all!
|
|
&iEntry,
|
|
&iTotal,
|
|
NULL);
|
|
|
|
if ((err == NERR_Success) || (err == ERROR_MORE_DATA))
|
|
{
|
|
int iConnections = 0;
|
|
for (DWORD i = 0; i < iEntry; i++)
|
|
{
|
|
iConnections += pBuf[i].coni1_num_opens;
|
|
}
|
|
|
|
*pcConns = iTotal;
|
|
*pcOpens = iConnections;
|
|
err = NERR_Success;
|
|
}
|
|
else
|
|
{
|
|
*pcConns = 0;
|
|
*pcOpens = 0;
|
|
}
|
|
NetApiBufferFree(pBuf);
|
|
|
|
appDebugOut((DEB_ITRACE,"Share '%ws' has %d connections and %d opens\n", pszShare, *pcConns, *pcOpens));
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: IsWorkstationProduct
|
|
//
|
|
// Synopsis: Determines the NT product type (server or workstation),
|
|
// and returns TRUE if it is workstation.
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns: TRUE if running on workstation products
|
|
//
|
|
// History: 11-Sep-95 BruceFo Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL
|
|
IsWorkstationProduct(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Determine whether this is the workstation or server product by looking
|
|
// at HKEY_LOCAL_MACHINE, System\CurrentControlSet\Control\ProductOptions.
|
|
// The ProductType value therein is interpreted as follows:
|
|
//
|
|
// LanmanNt -- server product, running as domain controller
|
|
// ServerNt -- server product, not a domain controller
|
|
// WinNT -- workstation product
|
|
//
|
|
|
|
LONG ec;
|
|
HKEY hkey;
|
|
DWORD type;
|
|
DWORD size;
|
|
UCHAR buf[100];
|
|
BOOL fIsWorkstation = TRUE;
|
|
|
|
ec = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hkey
|
|
);
|
|
|
|
if (ec == NO_ERROR)
|
|
{
|
|
size = sizeof(buf);
|
|
ec = RegQueryValueEx(hkey,
|
|
TEXT("ProductType"),
|
|
NULL,
|
|
&type,
|
|
buf,
|
|
&size);
|
|
|
|
if ((ec == NO_ERROR) && (type == REG_SZ))
|
|
{
|
|
if (0 == lstrcmpi((LPTSTR)buf, TEXT("lanmannt")))
|
|
{
|
|
fIsWorkstation = FALSE;
|
|
}
|
|
|
|
if (0 == lstrcmpi((LPTSTR)buf, TEXT("servernt")))
|
|
{
|
|
fIsWorkstation = FALSE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
return fIsWorkstation;
|
|
}
|
|
|
|
BOOL
|
|
DriveLetterShare(
|
|
PWSTR pszShareName
|
|
)
|
|
{
|
|
if (NULL == pszShareName || lstrlen(pszShareName) != 2)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// BUGBUG: what about non-English char sets?
|
|
return ( ((pszShareName[0] >= TEXT('a')) && pszShareName[0] <= TEXT('z'))
|
|
|| ((pszShareName[0] >= TEXT('A')) && pszShareName[0] <= TEXT('Z'))
|
|
)
|
|
&& (pszShareName[1] == TEXT('$'))
|
|
;
|
|
}
|
|
|
|
|
|
#if DBG == 1
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DumpNetEnum
|
|
//
|
|
// Synopsis: Dumps an array of SHARE_INFO_1 structures.
|
|
//
|
|
// History: 4-Apr-95 BruceFo Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID
|
|
DumpNetEnum(
|
|
IN LPVOID pBufShares,
|
|
IN ULONG entriesRead
|
|
)
|
|
{
|
|
SHARE_INFO_1* pBase = (SHARE_INFO_1*) pBufShares;
|
|
|
|
appDebugOut((DEB_TRACE,
|
|
"DumpNetEnum: %d entries\n",
|
|
entriesRead));
|
|
|
|
for (ULONG i = 0; i < entriesRead; i++)
|
|
{
|
|
SHARE_INFO_1* p = &(pBase[i]);
|
|
|
|
appDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
|
|
"\t Share name: %ws\n"
|
|
"\t Type: %d (0x%08lx)\n"
|
|
"\t Comment: %ws\n"
|
|
"\n"
|
|
,
|
|
p->shi1_netname,
|
|
p->shi1_type, p->shi1_type,
|
|
p->shi1_remark
|
|
));
|
|
|
|
}
|
|
}
|
|
|
|
#endif // DBG == 1
|
|
|
|
struct SHARE_PROPERTIES_DATA
|
|
{
|
|
IUnknown* punk;
|
|
LPTSTR pszMachine;
|
|
LPTSTR pszShareName;
|
|
};
|
|
|
|
DWORD CALLBACK
|
|
SharePropertiesThreadProc(
|
|
LPVOID lpThreadParameter
|
|
)
|
|
{
|
|
SHARE_PROPERTIES_DATA* pData = (SHARE_PROPERTIES_DATA*)lpThreadParameter;
|
|
if (NULL == pData)
|
|
{
|
|
appAssert(!"Unexpected properties thread data");
|
|
return 0;
|
|
}
|
|
|
|
WCHAR szCaption[MAX_PATH];
|
|
LoadString(g_hInstance, IDS_SHARE_PROPTITLE, szCaption, ARRAYLEN(szCaption));
|
|
|
|
SHARE_PROPSHEETPAGE sprop;
|
|
|
|
sprop.psp.dwSize = sizeof(sprop); // no extra data.
|
|
sprop.psp.dwFlags = PSP_USEREFPARENT;
|
|
sprop.psp.hInstance = g_hInstance;
|
|
sprop.psp.pszTemplate = MAKEINTRESOURCE(IDD_SHARE_PROPERTIES);
|
|
sprop.psp.hIcon = NULL;
|
|
sprop.psp.pszTitle = NULL;
|
|
sprop.psp.pfnDlgProc = CSharingPropertyPage::DlgProcPage;
|
|
sprop.psp.lParam = 0;
|
|
sprop.psp.pfnCallback = NULL;
|
|
sprop.psp.pcRefParent = &g_NonOLEDLLRefs;
|
|
sprop.pszMachine = pData->pszMachine;
|
|
sprop.pszShareName = pData->pszShareName;
|
|
|
|
PROPSHEETHEADER psh;
|
|
|
|
psh.dwSize = sizeof(PROPSHEETHEADER);
|
|
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_USEICONID;
|
|
psh.hwndParent = NULL;
|
|
psh.hInstance = g_hInstance;
|
|
psh.pszIcon = MAKEINTRESOURCE(IDI_SHARESFLD);
|
|
psh.pszCaption = szCaption;
|
|
psh.nPages = 1;
|
|
psh.nStartPage = 0;
|
|
psh.ppsp = (LPCPROPSHEETPAGE)&sprop;
|
|
psh.pfnCallback= NULL;
|
|
|
|
PropertySheet(&psh);
|
|
|
|
pData->punk->Release();
|
|
LocalFree(pData); // The strings are packed in the same allocation!
|
|
return 0;
|
|
}
|
|
|
|
HRESULT
|
|
ShareDoProperties(
|
|
IN IUnknown* punk,
|
|
IN LPTSTR pszMachine,
|
|
IN LPTSTR pszShareName
|
|
)
|
|
{
|
|
if (NULL == pszShareName)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
DWORD cbMachine = 0;
|
|
DWORD cbStrings = 0;
|
|
if (NULL != pszMachine)
|
|
{
|
|
cbMachine = (lstrlen(pszMachine) + 1) * sizeof(TCHAR);
|
|
cbStrings += cbMachine;
|
|
}
|
|
cbStrings += (lstrlen(pszShareName) + 1) * sizeof(TCHAR);
|
|
|
|
HRESULT hr = S_OK;
|
|
HANDLE hThread;
|
|
DWORD idThread;
|
|
SHARE_PROPERTIES_DATA* pData = (SHARE_PROPERTIES_DATA*)LocalAlloc(LPTR, sizeof(SHARE_PROPERTIES_DATA) + cbStrings);
|
|
if (pData)
|
|
{
|
|
if (NULL != pszMachine)
|
|
{
|
|
pData->pszMachine = (LPWSTR)(((LPBYTE)pData) + sizeof(SHARE_PROPERTIES_DATA));
|
|
lstrcpy(pData->pszMachine, pszMachine);
|
|
}
|
|
else
|
|
{
|
|
pData->pszMachine = NULL;
|
|
}
|
|
pData->pszShareName = (LPWSTR)(((LPBYTE)pData) + sizeof(SHARE_PROPERTIES_DATA) + cbMachine);
|
|
lstrcpy(pData->pszShareName, pszShareName);
|
|
|
|
pData->punk = punk;
|
|
pData->punk->AddRef();
|
|
|
|
hThread = CreateThread(NULL, 0, SharePropertiesThreadProc, pData, 0, &idThread);
|
|
|
|
if (hThread)
|
|
{
|
|
CloseHandle(hThread);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
pData->punk->Release();
|
|
LocalFree(pData);
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ShareDoDelete(
|
|
IN HWND hwndOwner,
|
|
IN PWSTR pszMachine,
|
|
IN PWSTR pszShareName
|
|
)
|
|
{
|
|
// Remove the share. We need to know the path that was
|
|
// shared to be able to update the explorer. So, get
|
|
// that.
|
|
SHARE_INFO_1* pInfo1 = NULL;
|
|
SHARE_INFO_2* pInfo2 = NULL;
|
|
DWORD ret;
|
|
HRESULT hr = S_OK;
|
|
|
|
ret = NetShareGetInfo(pszMachine, pszShareName, 2, (LPBYTE*)&pInfo2);
|
|
if (NERR_Success != ret)
|
|
{
|
|
// make sure it's null
|
|
pInfo2 = NULL;
|
|
}
|
|
|
|
// Warn and confirm if it's a special share, either ADMIN$, IPC$,
|
|
// or <drive>$
|
|
if (NULL == pInfo2)
|
|
{
|
|
// Permissions problem? Try getting SHARE_INFO_1.
|
|
|
|
ret = NetShareGetInfo(pszMachine, pszShareName, 1, (LPBYTE*)&pInfo1);
|
|
if (NERR_Success != ret)
|
|
{
|
|
// make sure it's null
|
|
pInfo1 = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pInfo1 = (SHARE_INFO_1*)pInfo2; // I just need the type
|
|
}
|
|
|
|
if (NULL != pInfo1)
|
|
{
|
|
DWORD id = IDYES;
|
|
if (pInfo1->shi1_type & STYPE_SPECIAL)
|
|
{
|
|
id = MyConfirmationDialog(
|
|
hwndOwner,
|
|
MSG_DELETESPECIAL,
|
|
MB_YESNO | MB_ICONEXCLAMATION,
|
|
pszShareName);
|
|
}
|
|
|
|
if (pInfo1 != (SHARE_INFO_1*)pInfo2)
|
|
{
|
|
NetApiBufferFree(pInfo1);
|
|
}
|
|
|
|
if (id != IDYES)
|
|
{
|
|
hr = S_OK;
|
|
goto nodelete;
|
|
}
|
|
}
|
|
|
|
// Actually delete the share
|
|
ret = NetShareDel(pszMachine, pszShareName, 0);
|
|
if (NERR_Success == ret)
|
|
{
|
|
if (NULL != pInfo2)
|
|
{
|
|
SHChangeNotify(SHCNE_NETUNSHARE, SHCNF_PATH, pInfo2->shi2_path, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// BUGBUG: error message to user
|
|
|
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
|
|
nodelete:
|
|
if (NULL != pInfo2)
|
|
{
|
|
NetApiBufferFree(pInfo2);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
struct SHARE_NEW_DATA
|
|
{
|
|
IUnknown* punk;
|
|
LPTSTR pszMachine;
|
|
};
|
|
|
|
DWORD CALLBACK
|
|
ShareNewThreadProc(
|
|
LPVOID lpThreadParameter
|
|
)
|
|
{
|
|
SHARE_NEW_DATA* pData = (SHARE_NEW_DATA*)lpThreadParameter;
|
|
if (NULL == pData)
|
|
{
|
|
appAssert(!"Unexpected properties thread data");
|
|
return 0;
|
|
}
|
|
|
|
CDlgNewShare dlg(NULL, pData->pszMachine);
|
|
if (dlg.DoModal())
|
|
{
|
|
}
|
|
|
|
pData->punk->Release();
|
|
LocalFree(pData); // The strings are packed in the same allocation!
|
|
return 0;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ShareDoNew(
|
|
IN IUnknown* punk,
|
|
IN PWSTR pszMachine
|
|
)
|
|
{
|
|
DWORD cbStrings = 0;
|
|
if (NULL != pszMachine)
|
|
{
|
|
cbStrings += (lstrlen(pszMachine) + 1) * sizeof(TCHAR);
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
HANDLE hThread;
|
|
DWORD idThread;
|
|
SHARE_NEW_DATA* pData = (SHARE_NEW_DATA*)LocalAlloc(LPTR, sizeof(SHARE_NEW_DATA) + cbStrings);
|
|
if (pData)
|
|
{
|
|
if (NULL != pszMachine)
|
|
{
|
|
pData->pszMachine = (LPWSTR)(((LPBYTE)pData) + sizeof(SHARE_NEW_DATA));
|
|
lstrcpy(pData->pszMachine, pszMachine);
|
|
}
|
|
else
|
|
{
|
|
pData->pszMachine = NULL;
|
|
}
|
|
|
|
pData->punk = punk;
|
|
pData->punk->AddRef();
|
|
|
|
hThread = CreateThread(NULL, 0, ShareNewThreadProc, pData, 0, &idThread);
|
|
|
|
if (hThread)
|
|
{
|
|
CloseHandle(hThread);
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
pData->punk->Release();
|
|
LocalFree(pData);
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
#ifdef WIZARDS
|
|
HRESULT
|
|
ShareDoSpecial(
|
|
IN HWND hwndOwner,
|
|
IN PWSTR pszMachine,
|
|
IN BYTE bType
|
|
)
|
|
{
|
|
// Construct the command line to pass to the Share Wizard
|
|
|
|
TCHAR szCommandLine[MAX_PATH];
|
|
lstrcpy(szCommandLine, g_szShareWizardArg);
|
|
|
|
switch (bType)
|
|
{
|
|
case SHID_SHARE_NW:
|
|
wcscat(szCommandLine, g_szFpnw);
|
|
break;
|
|
|
|
case SHID_SHARE_MAC:
|
|
wcscat(szCommandLine, g_szSfm);
|
|
break;
|
|
|
|
case SHID_SHARE_ALL:
|
|
wcscat(szCommandLine, g_szAll);
|
|
break;
|
|
|
|
case SHID_SHARE_NEW:
|
|
// nothing special
|
|
break;
|
|
|
|
default: appAssert(!"Unknown object type");
|
|
}
|
|
|
|
if (NULL != pszMachine)
|
|
{
|
|
wcscat(szCommandLine, pszMachine);
|
|
}
|
|
|
|
appDebugOut((DEB_TRACE, "Invoking wizard with this command line: %ws\n", szCommandLine));
|
|
|
|
// Looks like CreateProcess writes to this buffer!
|
|
STARTUPINFO si = { 0 };
|
|
si.cb = sizeof(si);
|
|
PROCESS_INFORMATION pi = { 0 };
|
|
BOOL b = CreateProcess(
|
|
g_szShareWizardCmd,
|
|
szCommandLine,
|
|
NULL, // pointer to process security attributes
|
|
NULL, // pointer to thread security attributes
|
|
FALSE, // handle inheritance flag
|
|
0, // creation flags
|
|
NULL, // pointer to new environment block
|
|
NULL, // pointer to current directory name
|
|
&si, // pointer to STARTUPINFO
|
|
&pi); // pointer to PROCESS_INFORMATION
|
|
if (b)
|
|
{
|
|
CloseHandle(pi.hProcess);
|
|
CloseHandle(pi.hThread);
|
|
}
|
|
else
|
|
{
|
|
appDebugOut((DEB_ERROR,
|
|
"CreateProcess failed, 0x%08lx\n",
|
|
GetLastError()));
|
|
|
|
MyErrorDialog(hwndOwner, MSG_NOWIZARD);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
#endif // WIZARDS
|
|
|
|
|
|
VOID FSSetStatusText(HWND hwndOwner, LPTSTR* ppszText, int iStart, int iEnd)
|
|
{
|
|
HWND hwndStatus = NULL;
|
|
IShellBrowser* psb = FileCabinet_GetIShellBrowser(hwndOwner);
|
|
|
|
if (psb)
|
|
{
|
|
psb->GetControlWindow(FCW_STATUS, &hwndStatus);
|
|
if (hwndStatus)
|
|
{
|
|
for (; iStart <= iEnd; iStart++)
|
|
{
|
|
LPTSTR lpsz;
|
|
|
|
if (ppszText)
|
|
{
|
|
lpsz = *ppszText;
|
|
ppszText++;
|
|
}
|
|
else
|
|
{
|
|
lpsz = (LPTSTR)TEXT("");
|
|
}
|
|
#ifdef WINDOWS_ME
|
|
SendMessage(hwndStatus, SB_SETTEXT, SB_RTLREADING | (WPARAM)iStart, (LPARAM)lpsz);
|
|
#else
|
|
SendMessage(hwndStatus, SB_SETTEXT, (WPARAM)iStart, (LPARAM)lpsz);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsLevelOk(
|
|
IN PWSTR pszMachine,
|
|
IN DWORD level
|
|
)
|
|
{
|
|
LPBYTE pBuf = NULL;
|
|
DWORD entriesread, totalentries;
|
|
NET_API_STATUS ret;
|
|
|
|
// we want to get the minimum amount of data, because all we care about
|
|
// is whether it succeeds the access check
|
|
DWORD prefmaxlen = 300;
|
|
for (;; prefmaxlen *= 2)
|
|
{
|
|
ret = NetShareEnum(
|
|
pszMachine,
|
|
level,
|
|
&pBuf,
|
|
prefmaxlen,
|
|
&entriesread,
|
|
&totalentries,
|
|
NULL);
|
|
if (NERR_BufTooSmall != ret)
|
|
{
|
|
NetApiBufferFree(pBuf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ERROR_ACCESS_DENIED == ret)
|
|
{
|
|
return FALSE;
|
|
}
|
|
else if (NERR_Success == ret || ERROR_MORE_DATA == ret)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// some other error
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SetDialogIconBig(
|
|
IN HWND hwnd,
|
|
WORD idIcon
|
|
)
|
|
{
|
|
HICON hiconLarge = (HICON)LoadImage(
|
|
g_hInstance,
|
|
MAKEINTRESOURCE(idIcon),
|
|
IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXICON),
|
|
GetSystemMetrics(SM_CYICON),
|
|
LR_DEFAULTCOLOR);
|
|
if (NULL == hiconLarge)
|
|
{
|
|
appDebugOut((DEB_ERROR,
|
|
"LoadImage for large image failed, 0x%08lx\n",
|
|
GetLastError()));
|
|
}
|
|
else
|
|
{
|
|
SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hiconLarge);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SetDialogIconSmall(
|
|
IN HWND hwnd,
|
|
WORD idIcon
|
|
)
|
|
{
|
|
HICON hiconSmall = (HICON)LoadImage(
|
|
g_hInstance,
|
|
MAKEINTRESOURCE(idIcon),
|
|
IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXSMICON),
|
|
GetSystemMetrics(SM_CYSMICON),
|
|
LR_DEFAULTCOLOR);
|
|
if (NULL == hiconSmall)
|
|
{
|
|
appDebugOut((DEB_ERROR,
|
|
"LoadImage for small image failed, 0x%08lx\n",
|
|
GetLastError()));
|
|
}
|
|
else
|
|
{
|
|
SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hiconSmall);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
STRRETLoadString(
|
|
UINT ids,
|
|
STRRET* pstr
|
|
)
|
|
{
|
|
#ifdef UNICODE
|
|
TCHAR szTemp[MAX_PATH];
|
|
szTemp[0] = TEXT('\0');
|
|
|
|
LoadString(g_hInstance, ids, szTemp, ARRAYLEN(szTemp));
|
|
pstr->pOleStr = (LPOLESTR)SHAlloc((lstrlen(szTemp)+1) * sizeof(TCHAR));
|
|
if (NULL != pstr->pOleStr)
|
|
{
|
|
pstr->uType = STRRET_OLESTR;
|
|
lstrcpy(pstr->pOleStr, szTemp);
|
|
}
|
|
else
|
|
{
|
|
pstr->uType = STRRET_CSTR;
|
|
pstr->cStr[0] = '\0';
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
#else
|
|
pstr->uType = STRRET_CSTR;
|
|
LoadString(g_hInstance, ids, pstr->cStr, ARRAYLEN(pstr->cStr));
|
|
#endif
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
STRRETCopy(
|
|
LPTSTR pszString,
|
|
STRRET* pstr
|
|
)
|
|
{
|
|
#ifdef UNICODE
|
|
pstr->pOleStr = (LPOLESTR)SHAlloc((lstrlen(pszString)+1) * sizeof(TCHAR));
|
|
if (NULL != pstr->pOleStr)
|
|
{
|
|
pstr->uType = STRRET_OLESTR;
|
|
lstrcpy(pstr->pOleStr, pszString);
|
|
}
|
|
else
|
|
{
|
|
pstr->uType = STRRET_CSTR;
|
|
pstr->cStr[0] = '\0';
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
#else
|
|
pstr->uType = STRRET_CSTR;
|
|
int cch = lstrlen(pszString);
|
|
cch = min(cch, ARRAYLEN(pstr->cStr) - 1);
|
|
strncpy(pstr->cStr, pszString, cch);
|
|
pszString[cch] = '\0';
|
|
#endif
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
VOID
|
|
FillSpecialID(
|
|
LPIDSHARE pids,
|
|
BYTE bFlags, // SHID_SHARE_*
|
|
UINT idsName
|
|
)
|
|
{
|
|
WCHAR szBuf[MAX_PATH];
|
|
szBuf[0] = L'\0';
|
|
LoadString(g_hInstance, idsName, szBuf, ARRAYLEN(szBuf));
|
|
LPWSTR pszName = szBuf;
|
|
USHORT nameLength = (USHORT)lstrlen(pszName);
|
|
USHORT nameOffset = 0;
|
|
|
|
pids->bFlags = bFlags;
|
|
pids->bReserved = 0;
|
|
pids->maxUses = 0xffffffff; // bogus
|
|
|
|
// we don't store nameOffset
|
|
pids->oComment = 0xffff; // bogus
|
|
pids->oPath = 0xffff; // bogus
|
|
|
|
lstrcpy(&pids->cBuf[nameOffset], pszName);
|
|
|
|
pids->cb = offsetof(IDSHARE, cBuf)
|
|
+ (nameLength + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// null terminate pidl
|
|
//
|
|
|
|
*(USHORT *)((LPBYTE)pids + pids->cb) = 0;
|
|
}
|
|
|
|
VOID
|
|
FillID1(
|
|
LPIDSHARE pids,
|
|
LPSHARE_INFO_1 pInfo
|
|
)
|
|
{
|
|
LPWSTR pszName = pInfo->shi1_netname;
|
|
LPWSTR pszComment = pInfo->shi1_remark;
|
|
|
|
USHORT nameLength, commentLength;
|
|
USHORT nameOffset, commentOffset;
|
|
|
|
nameLength = (USHORT)lstrlen(pszName);
|
|
commentLength = (USHORT)lstrlen(pszComment);
|
|
|
|
nameOffset = 0;
|
|
commentOffset = nameOffset + nameLength + 1;
|
|
|
|
pids->bFlags = SHID_SHARE_1;
|
|
pids->bReserved = 0;
|
|
pids->type = pInfo->shi1_type;
|
|
pids->maxUses = 0xffffffff; // bogus
|
|
|
|
// we don't store nameOffset
|
|
pids->oComment = commentOffset;
|
|
pids->oPath = 0xffff; // bogus
|
|
|
|
lstrcpy(&pids->cBuf[nameOffset], pszName);
|
|
lstrcpy(&pids->cBuf[commentOffset], pszComment);
|
|
|
|
pids->cb = offsetof(IDSHARE, cBuf)
|
|
+ (nameLength + 1 + commentLength + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// null terminate pidl
|
|
//
|
|
|
|
*(USHORT *)((LPBYTE)pids + pids->cb) = 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
FillID2(
|
|
LPIDSHARE pids,
|
|
LPSHARE_INFO_2 pInfo
|
|
)
|
|
{
|
|
LPWSTR pszName = pInfo->shi2_netname;
|
|
LPWSTR pszComment = pInfo->shi2_remark;
|
|
LPWSTR pszPath = pInfo->shi2_path;
|
|
|
|
USHORT nameLength, commentLength, pathLength;
|
|
USHORT nameOffset, commentOffset, pathOffset;
|
|
|
|
nameLength = (USHORT)lstrlen(pszName);
|
|
commentLength = (USHORT)lstrlen(pszComment);
|
|
pathLength = (USHORT)lstrlen(pszPath);
|
|
|
|
nameOffset = 0;
|
|
commentOffset = nameOffset + nameLength + 1;
|
|
pathOffset = commentOffset + commentLength + 1;
|
|
|
|
pids->bFlags = SHID_SHARE_2;
|
|
pids->bReserved = 0;
|
|
pids->type = pInfo->shi2_type;
|
|
pids->maxUses = pInfo->shi2_max_uses;
|
|
|
|
// we don't store nameOffset
|
|
pids->oComment = commentOffset;
|
|
pids->oPath = pathOffset;
|
|
|
|
lstrcpy(&pids->cBuf[nameOffset], pszName);
|
|
lstrcpy(&pids->cBuf[commentOffset], pszComment);
|
|
lstrcpy(&pids->cBuf[pathOffset], pszPath);
|
|
|
|
pids->cb = offsetof(IDSHARE, cBuf)
|
|
+ (nameLength + 1 + commentLength + 1 + pathLength + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// null terminate pidl
|
|
//
|
|
|
|
*(USHORT *)((LPBYTE)pids + pids->cb) = 0;
|
|
}
|
|
|
|
|
|
VOID
|
|
StrNCopy(
|
|
OUT LPWSTR pszTarget,
|
|
IN LPCWSTR pszSource,
|
|
IN DWORD cchTarget
|
|
)
|
|
{
|
|
DWORD cch = lstrlen(pszSource) + 1;
|
|
cch = min(cch, cchTarget);
|
|
wcsncpy(pszTarget, pszSource, cch - 1);
|
|
pszTarget[cch - 1] = TEXT('\0');
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: TrimLeadingAndTrailingSpaces
|
|
//
|
|
// Synopsis: Trims the leading and trailing spaces from a null-terminated string.
|
|
// Used primarily for share names.
|
|
//
|
|
// History: 18-Jul-97 JonN Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
TrimLeadingAndTrailingSpaces(
|
|
IN OUT PWSTR psz
|
|
)
|
|
{
|
|
int cchStrlen = ::wcslen(psz);
|
|
int cchLeadingSpaces = 0;
|
|
int cchTrailingSpaces = 0;
|
|
while (L' ' == psz[cchLeadingSpaces])
|
|
cchLeadingSpaces++;
|
|
if (cchLeadingSpaces < cchStrlen)
|
|
{
|
|
while (L' ' == psz[cchStrlen-(cchTrailingSpaces+1)])
|
|
cchTrailingSpaces++;
|
|
}
|
|
if ((cchLeadingSpaces+cchTrailingSpaces) > 0)
|
|
{
|
|
cchStrlen -= (cchLeadingSpaces+cchTrailingSpaces);
|
|
(void)memmove( psz,
|
|
psz+cchLeadingSpaces,
|
|
cchStrlen*sizeof(WCHAR) );
|
|
psz[cchStrlen] = L'\0';
|
|
}
|
|
}
|