Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> C / C++ -> Как получить список пользователей с сервера


Как получить список пользователей с сервера

Автор: Derek Lakin
Источник: www.sources.ru

Описание

Пример показывает, как пользоваться функцией NetQueryDisplayInformation, для получения специфической информации о пользователях, а так же представлен класс, который позволяет получить более общий доступ к данному сервису.

Детальное описание функции

Прототип функции выглядит так:

NET_API_STATUS NetQueryDisplayInformation(
  LPCWSTR ServerName,
  DWORD Level,
  DWORD Index,
  DWORD EntriesRequested,
  DWORD PreferredMaximumLength,
  LPDWORD ReturnedEntryCount,
  PVOID *SortedBuffer);

Возвращаемый тип NET_API_STATUS определён как DWORD. Если функция завершается успешно, то возвращаемое значение будет ERROR_SUCCESS (соответствует Win32 коду 0). Так же возможны следующие значения ошибки:

Значение Описание
ERROR_ACCESS_DENIED Пользователь не имеет доступа к запрашиваемой информации.
ERROR_INVALID_LEVEL Параметр Level имеет неправильное значение.
ERROR_MORE_DATA Данная ошибка сигнализирует о том, что на сервере доступно больше ячеек информации. Это говорит о том, что параметр SortedBuffer содержит не последнюю доступную ячейку информации. Для получения дополнительных данных, необходимо вызвать NetQueryDisplayInformation заново с параметром Index , содержащем значение, возвращённое в next_index члене последней ячейки в SortedBuffer.

Так же возможно возникновение ошибки со значением 1722, которая соответствует RPC_S_SERVER_UNAVAILABLE. Это говорит о том, что сервер в данный момент не доступен. Конечто не обязательно, но желательно включать в код программы проверку на возникновение данной ошибки.

Первый параметр ServerName - это строка Unicode wide-character, которая нам нужна, чтобы использовать MultiByteToWideChar для преобразования стандартных строк в необходимый формат. Он может быть NULL. При этом функция вернёт информацию о локальном компьютере. Если же не NULL, то строка должна начинаться с \\.

Особый интерес представляет параметр Level. Этот параметр указывает уровень получаемой информации, и может иметь одно из следующих значений.

Значение Описание
1 Получить информацию о пользователях. Параметр SortedBuffer указывает на массив структуры NET_DISPLAY_USER.
2 Получить информацию о компьютере. Параметр SortedBuffer указывает на массив структуры NET_DISPLAY_MACHINE.
3 Получить информацию о группе. Параметр SortedBuffer указывает на массив структуры NET_DISPLAY_GROUP.

Так как нас интересует информация о пользователях, то устанавливаем данный параметр в 1.

Теперь давайте посмотрим, как выглядит структура NET_DISPLAY_USER:

typedef struct _NET_DISPLAY_USER {
  LPWSTR   usri1_name;
  LPWSTR   usri1_comment;
  DWORD    usri1_flags;
  LPWSTR   usri1_full_name;
  DWORD    usri1_user_id;
  DWORD    usri1_next_index;
} NET_DISPLAY_USER, *PNET_DISPLAY_USER;

Не будем вдаваться в подробности описания каждого поля данной структуры. Так как нас интересует только список пользователей, то обратим внимание на два поля: usri1_name, в котором хранится логин пользователя и usri1_full_name, в котором содержится полное имя пользователя. Обе записи имеют формат Unicode wide-character строк.

 

Использование функции

Итак, при использовании данного сервиса рассмотрим три основных его составляющих:

  1. Установка параметров, для передачи в функцию.

  2. Вызов функции и получение результатов.

  3. Обработка возможных ошибок.

Параметры устанавливаются следующим образом:

// Во-первых, нам необходимо наши строки в Unicode wide-character формат
CString szServer = "\\\\MYSERVER";    // Сервер для запроса
LPWSTR pWideServer;
int nBytesSource = strlen(pString) * 2;
// Количество WChars необходимых для сохранения полученных данных
int nWCharNeeded = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
                                     pString, nBytesSource, NULL, 0);

// Распределяем необходимое пространство памяти плюс 2 байта для '\0'
pWideServer = (LPWSTR)GlobalAlloc (GPTR, (nWCharNeeded + 1) * 2);

// Делаем преобразование
nWCharNeeded = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pString,
    nBytesSource,(LPWSTR)pWideServer, nWCharNeeded);

if (0L == nWCharNeeded) {
    pWideServer = NULL;
}
else {
    *(LPWSTR)(pWideServer + nWCharNeeded) = L'\0';
}
nIndex = 0;        // Индекс внутри списка пользователей
DWORD dwCount;        // Возвращённое количество ячеек
void* pBuffer;        // Буфер для хранения результатов
NET_DISPLAY_USER* ndu;    // Информация о пользователе
DWORD dwResult,  i;    // Код завершения и индекс

Далее, для получения результатов используем следующий код:

do {
    dwResult = NetQueryDisplayInformation ((LPCWSTR)pWideServer,
                              1, nIndex, 10, 24, &dwCount, &pBuffer);
    if ((dwResult == ERROR_SUCCESS) || (dwResult == ERROR_MORE_DATA)) { 
        for (i = 0, ndu = (NET_DISPLAY_USER*)pBuffer; i < dwCount; ++i, ++ndu) {
            CString szName, szFullName, szComment;
            szName.Format("%S", ndu->usri1_name);
            szFullName.Format("%S", ndu->usri1_full_name);
            szComment.Format ("%S", ndu->usri1_comment);
            TRACE ("Name:\t\t" + szName + "\n"); 
            TRACE ("Full Name:\t" + szFullName + "\n"); 
            TRACE ("Comment:\t" + szComment + "\n"); 
            TRACE ("--------------------------------\n");
            if (dwCount >  0){
                nIndex = ((NET_DISPLAY_USER *)pBuffer)[dwCount - 1].usri1_next_index;
            }
        }
    }
} while (dwResult == ERROR_MORE_DATA);

Первый раз функция NQDI делает запрос для индекса 0. Далее индекс увеличивается до тех пор, пока не будет получено очередных данных о пользователе, либо не возникнет ошибка. Индекс следующего пользователя содержится в поле usri1_next_index структуры NET_DISPLAY_USER.

      
switch (dwResult) { 
    case ERROR_ACCESS_DENIED: 
        TRACE ("%s(%i): The user does not have access
                 to the requested information.\n", __FILE__, __LINE__); 
        break; 
    case ERROR_INVALID_LEVEL:
        TRACE ("%s(%i): The Level parameter specifies
                             an invalid value.\n", __FILE__, __LINE__); 
        break;
    case ERROR_MORE_DATA: 
        TRACE ("%s(%i): More entries are available.\n", __FILE__, __LINE__); 
        break;
    case ERROR_SUCCESS: 
        //    ничиго не делаем 
        break; 
    default: {
        // Другие ошибки, возможно RPC related 
        LPVOID lpMsgBuf; // буфер для сообщения
        ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM,
            0,
            dwResult, 
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Язык по умолчанию
            (LPTSTR)&lpMsgBuf, 0, NULL ); 
        TRACE ("%s(%i): %s\n", __FILE__, __LINE__, lpMsgBuf); 
        // Освобождаем буфер, который был выделен при помощи LocalAlloc() 
        ::LocalFree (lpMsgBuf);
        }
        break;
}
GlobalFree (pWideServer);

 

 

Класс для использования данного сервиса

Как и все хорошие программисты, я не смог не создать для этой функции своего класса! Он имеет три основных статических функции и один дополнительный класс CNetInfo:

static DWORD GetUserInfo (USER_LIST* pUsers, LPCSTR pServer = NULL);
static DWORD GetMachineInfo (MACHINE_LIST* pMachines, LPCSTR pServer = NULL);
static DWORD GetGroupInfo (GROUP_LIST* pGroups, LPCSTR pServer = NULL); 
static CString FormatMessage (DWORD dwError);

Первые три функции вызывают всё тот же NQDI. Последняя используется для для приёма сообщений об ошибках и возвращает строку, содержащую описание произошедшей ошибки.

Типы USER_LIST, MACHINE_LIST и GROUP_LIST определены как:

#define USER_LIST    CList<NET_DISPLAY_USER, NET_DISPLAY_USER&>
#define MACHINE_LIST    CList<NET_DISPLAY_MACHINE, NET_DISPLAY_MACHINE&>
#define GROUP_LIST    CList<NET_DISPLAY_GROUP, NET_DISPLAY_GROUP>

Так же определены уровни получаемой информации:

#define LEVEL_USER    1
#define LEVEL_MACHINE    2
#define LEVEL_GROUP    3

Для использования данного класса, нам необходимо создать список необходимых типов, передать указатель на него и имя сервера в требуемую функцию (определённую параметром level), а затем, в зависимости от результата, либо обработать полученные результаты, либо обработать сообщение об ошибке. Класс определён в именном пространстве ssl_net, так что необходимо добавить строчку using namespace ssl_net;, либо вызывать функцию из класса, как это показано ниже:

USER_LIST pUsers = new USER_LIST;
CString szServer = "\\\\MYSERVER"
DWORD dwResult = ssl_net::CNetInfo::GetUserInfo (pUsers, szServer);
if (ERROR_SUCCESS == dwResult) {
    // Обрабатываем результаты
    POSITION pos = pUsers->GetHeadPosition ();
    while (NULL != pos) {
        NET_DISPLAY_USER ndu = pUsers->GetNext (pos); 
        CString szName, szComment, szFlags, szFullName, szUserID; 
        szName.Format ("%S", ndu.usri1_name);
        szComment.Format ("%S", ndu.usri1_comment); 
        szFlags.Format ("%d", ndu.usri1_flags); 
        szFullName.Format ("%S",n du.usri1_full_name); 
        szUserID.Format ("%d", ndu.usri1_user_id);
        TRACE ("%S\n%S\n%d\n%S\n%d\n", ndu.usri1_name,
            ndu.usri1_comment, ndu.usri1_flags,
            ndu.usri1_full_name, ndu.usri1_user_id);
    }
}
else {
    // Обрабатываем ошибки
    CString szErrMsg = ssl_net::CNetInfo::FormatMessage (dwResult);
    AfxMessageBox (szErrMsg);
}
delete pUsers;

Теперь для того, чтобы это всё заработало, достаточно включить в проект NetInfo.h и прилинковать NetApi32.lib.

Приведённый пример был написан на Visual C++ 6 SP4, но думаю, что код должен работать с различными модификациями VC6 или сервиспаков. Тестирование проводилось только на Windows NT 4 SP6a. В документации сказано, что функция NQDI поддерживается в Windows NT 3.1 или поздних версиях (включая Windows 2000), но не поддерживается в Windows 95 или 98.



 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100