Encapsulating Standard Network API Functions

Environment: NT/W2K

Getting to grips with the standard 32-bit network API calls is a pain to begin with, which is why I wrote this small class to encapsulate two of the network functions I most use: NetSessionEnum() and NetUserGetInfo(). Anyone picking up this code can easily extend its functionality to take in other calls such as NetShareAdd() or NetUserAdd() etc. I will probably do the same when I have cause to use them.

In my development environment, the source files sit in a folder dedicated to various utility classes and are included in the Visual C++ workspace for each project for which I require them via Project->Add To Project->Files and then including the class header where necessary.

Source Code

The comments in the source code are (I hope) self-explanatory.

Header File


/*
NETUTIL.H
Net utilities class header

Michael Pritchard Mar 2001

*/


// 32-bit net API headers
// include them here so the whole application
// can see them
#include <lmcons.h>
#include <lmerr.h>
#include <lmapibuf.h>
#include <lmaccess.h> 
#include <lmshare.h>

// just a big number to allow a large enough
// buffer for the return from NetSessionEnum()
// because I'm too lazy to call the function twice
#define bigbuff 64000	

class CNetutil {

public:

	// prototypes of member functions
	BYTE* get_sessions(CString, DWORD&, DWORD&, DWORD&);
	PUSER_INFO_10 get_name(CString, CString, DWORD&);

protected:

private:


};

Implementation File


/*
NETUTIL.CPP
Net utilities class source file

Michael Pritchard Mar 2001

This class encapsulates 32-bit network API calls.

Windows NT/W2K only.

Project must be linked with NETAPI32.LIB.

Build with precompiled header use set to automatic.

This class requires the application to be built in unicode. If you
don't do it this way, you must covert strings to unicode before
applying them to the net API functions and convert the results
back. To build an MFC application in Unicode, you first need to 
make sure you have installed Visual Studio with the relevant
Unicode libraries. If you haven't, you'll need to re-install. Once
you have done this, create your project via the App Wizard as normal
and then change the project settings as follows:

Under Project/Settings/C++/General change the preprocessor directive from
(Debug)
WIN32,_DEBUG,_WINDOWS,_MBCS
to
WIN32,_DEBUG,_WINDOWS,_UNICODE
or (Release)
WIN32,NDEBUG,_WINDOWS,_MBCS
to
WIN32,NDEBUG,_WINDOWS,_UNICODE

If the strings don't look exactly like this, don't panic - all you
need to do is change _MBCS to _UNICODE

Under Project/Settings/Link/Output add
wWinMainCRTStartup
to the entry point symbol box

If you are converting an existing project to Unicode, you will
probably need to change some functions over to the Unicode
versions. This is straight forward and there is plenty of
information in MSDN.

All string literals need to be encapsulated in the _T() macro.
*/


#include "afx.h"
#include "NetUtil.h"     // don't forget this, either

/*
member function: get_sessions()

Uses API:    NetSessionEnum()

Arguments:   server -     name of server on which user database is held
                          (normally PDC), no preceeding backslashes required
             dwErrmsg   - reference to DWORD to contain return code from API call
             dwRecords  - reference to DWORD to contain no. records returned
                          by API call
             dwSessions - reference to DWORD to contain total sessions returned
                          by API call

Returns:     BYTE pointer to buffer returned by API call

Sample call to get_sessions():

void CMyClass::MyFunction()
{
     CNetutil net;
     CString sServer = _T("myPDC");

     DWORD dwError, dwRecords, dwSessions;
     BYTE* buffer;
     PSESSION_INFO_10 pSession;

     buffer = net.get_sessions(sServer, dwError, dwRecords, dwSessions);

     if( dwError != 0)
     {
          CString sError;
          sError.Format(_T("get_sessions() failed - error %ld"), dwError);
          AfxMessageBox(sError);
          return;
     }

     // cast returned buffer to structure
     pSession = (PSESSION_INFO_10 )buffer;

     // move through the BYTE buffer, advancing the pointer
     // by length PSESSION_INFO_10 each time
     for (DWORD dwCount = 0; dwCount++ < dwRecords; pSession++)
     {
          // do something with each instance of the PSESSION_INFO_10 structure
          // e.g. CString sUserid = pSession->sesi10_username;
     }

     NetApiBufferFree(buffer);
}

Notes:     Before processing returned BYTE pointer, value of dwErrmsg MUST be checked.
           A return of 0 indicates net API call successful, anything else must be
           noted and checked against the error code tables

*/

BYTE* CNetutil::get_sessions(CString server, 
                             DWORD& dwErrmsg, 
                             DWORD& dwRecords, 
                             DWORD& dwSessions)
{
     // buffer to take return from net API call
     BYTE *pBuf;          
     
     // Build full UNC name for PDC
     CString sSer;          
     sSer = _T("\\\\");
     sSer += server;
     
     // call net function level 10 (general access)
     dwErrmsg = NetSessionEnum (sSer.GetBuffer(0),
                                NULL,
                                NULL,
                                10,
                                &pBuf,
                                bigbuff,     // see header 
                                &dwRecords,
                                &dwSessions,
                                NULL);

     // if return sucessful, set dwErrmsg to zero
     // (confines net function error checking to this class)
     if (dwErrmsg == NERR_Success || dwErrmsg == ERROR_MORE_DATA)
          dwErrmsg = 0;

     return pBuf;


}


/*
member function: get_name()

Uses API:     NetUserGetInfo()

Arguments:    userid  -  individual user ID, or one of buffer returned 
                         by NetSessionEnum()
              server  -  name of server on which user database is held
                         (normally PDC) no preceeding backslashes required
              dwErrmsg - pointer to int to contain return code from API call

Returns:      pointer to PUSER_INFO_10 structure

Sample call to get_name():

void CMyClass::MyFunction()
{
     DWORD dwError;
     CNetutil net;
     CString sServer = _T("MyPDC");
     CString sUserid = _T("AnyValidUserid");

     PUSER_INFO_10 pUser;
     pUser = net.get_name(sUserid, sServer, dwError);

     if(dwError == 0)
     {
          // do something with the PUSER_INFO_10 structure
          // e.g. CString sName = pUser->usri10_full_name;
     }
     else
     {
          CString sError;
          sError.Format(_T("%ld"), dwError);
          AfxMessageBox(sError);
     }
}

Notes:      Before processing returned PUSER_INFO_10 pointer, value of dwErrmsg 
            MUST be checked. A return of 0 indicates net API call successful, 
            anything else must be noted and checked against the error code tables

*/

PUSER_INFO_10 CNetutil::get_name(CString sUserid, 
                                 CString server,
                                 DWORD& dwErrmsg) 
{

     // buffer to take return from net API call
     BYTE *pBuf;
     PUSER_INFO_10 pUser;

     // Build full UNC name for PDC
     CString sSer;
     sSer = _T("\\\\");
     sSer += server;
     
     // call net function level 10 (general access)
     dwErrmsg = NetUserGetInfo( sSer,
                                sUserid,
                                10,
                                &pBuf);

     // if return successful, set dwErrmsg to zero
     // (confines net function error checking to this class)
     if (dwErrmsg == NERR_Success || dwErrmsg == ERROR_MORE_DATA)
          dwErrmsg = 0;

     // cast returned BYTE buffer
     pUser = (PUSER_INFO_10 ) pBuf;

     // free the BYTE buffer
     NetApiBufferFree(pBuf);
     
     return pUser;

}


Downloads

Download source - 3 Kb