Присвоение отображаемого имени сетевому диску
От: Sifury Россия  
Дата: 01.03.05 12:55
Оценка:
Здравствуйте.

У меня возникла проблема с присвоением отображаемого имени сетевому диску в службе.

Ситуация следующая:
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.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.