Здравствуйте.
У меня возникла проблема с присвоением отображаемого имени сетевому диску в службе.
Ситуация следующая:
1. Служба работает под учетной записью LOCAL_SYSTEM;
2. В момент загрузки пользователя служба получает access token этого пользователя;
3. Служба для каждого пользователя подключает сетевой диск под произвольной буквой;
Задача: присвоить подключаемому диску заданное отображаемое имя.
Реализация:
bool spdr::CseDrivesMap::Mapping(const wchar_t* szUserName, const wchar_t* szPwd)
{
BYTE btBit = 0;
DWORD dwDrives;
wchar_t szLocalName[4];
HRESULT hr;
NETRESOURCE res;
ULONG uFlags;
wchar_t* szName;
STRRET strName;
IEnumIDList* pEnum = 0;
IShellFolder* pDesktop = 0;
IShellFolder* pFolder = 0;
LPITEMIDLIST pList = 0;
LPITEMIDLIST pNewList = 0;
dwDrives = ::GetLogicalDrives();
if (dwDrives == 0)
throw srspo::CseWin32Error(L"Ошибка определения наличия логических дисков.");
// Определяем свободную букву, если не задана
if (m_chDriveLetter != 0)
{
if ((dwDrives & ( 1 << (m_chDriveLetter - L'0'))) != 0)
btBit = 1;
}
if (!btBit)
{
for (btBit = 3; btBit < 32; btBit++)
{
if ((dwDrives & (1 << btBit)) == 0)
break;
}
if (btBit == 32)
throw srspo::CseWin32Error(ERROR_INVALID_DRIVE, L"Некорректное имя логического диска.");
}
::ZeroMemory(&res, sizeof(res));
szLocalName[0] = L'A' + btBit;
szLocalName[1] = L':';
szLocalName[2] = L'\0';
res.dwType = RESOURCETYPE_DISK;
res.lpLocalName = szLocalName;
res.lpRemoteName = (wchar_t*)m_sPath.c_str();
m_Token.ImpersonateLoggedOnUser();
if (!szPwd || !szUserName)
{
if (m_sPwd.length() && m_sUserName.length())
dwDrives = ::WNetAddConnection2(&res, m_sPwd.c_str(), m_sUserName.c_str(), 0);
else
dwDrives = ::WNetAddConnection2(&res, NULL, NULL, 0);
}
else
dwDrives = ::WNetAddConnection2(&res, szPwd, szUserName, 0);
szName = new wchar_t[1024];
try
{
if (FAILED(hr = ::SHGetDesktopFolder(&pDesktop)))
throw 1;
szLocalName[2] = L'\\';
szLocalName[3] = L'\0';
if (FAILED(hr = ::SHGetFolderLocation(NULL, CSIDL_DRIVES, m_Token.GetHandle(), 0, &pList)))
throw 2;
if (FAILED(hr = pDesktop->BindToObject(pList, 0, IID_IShellFolder, (void**)&pFolder)))
throw 3;
::CoTaskMemFree(pList);
pList = 0;
if (FAILED(hr = pFolder->EnumObjects(0, SHCONTF_STORAGE, &pEnum)))
throw 4;
while (pEnum->Next(1, &pList, 0) != S_FALSE)
{
if (FAILED(hr = pFolder->GetDisplayNameOf(pList, SHGDN_FORPARSING, &strName)))
throw 5;
if (FAILED(hr = ::StrRetToBuf(&strName, pList, szName, 2048)))
throw 6;
if (*szLocalName == *szName)
{
if (FAILED(hr = pFolder->SetNameOf(0, pList, L"TEST", SHGDN_INFOLDER | SHGDN_FOREDITING, 0)))
throw 7;
break;
}
::CoTaskMemFree(pList);
pList = 0;
}
}
catch (...)
{
}
if (pDesktop)
pDesktop->Release();
if (pList)
::CoTaskMemFree(pList);
delete szName;
if (pNewList)
::CoTaskMemFree(pNewList);
m_Token.Revert();
if (dwDrives != NO_ERROR)
{
::SetLastError(dwDrives);
m_chDriveLetter = 0;
return false;
//throw srspo::CseWin32Error(dwDrives, L"Ошибка подклюяения сетевого диска.");
}
m_chDriveLetter = szLocalName[0];
return true;
}
Приведенный код правильно работает только, если запущен в процессе, созданном под учетной записью загруженного пользователя. В службе этот код делает изменения для учетной записи LOCAL_SYSTEM, т.е. в вертки реестра HKEY_USERS\.DEFAULT.