title: Windows Netapi32
body: <p>I am currently accessing the Windows <code>Netapi32</code> using <code>Netapi32.lib</code>, currently I am using <code>c++</code> to access the api. I am having trouble retrieving the computer name, currently one the <code>NetFileEnum</code> <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb525378%28v=vs.85%29.aspx" rel="nofollow">here</a> on <code>FILE_INFO_3</code> structure <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb525375%28v=vs.85%29.aspx" rel="nofollow">here</a>. In the documentation it says, </p>
  
  <blockquote>
    <p>fi3_username</p>
    
    <p>Pointer to a string that specifies which user (on servers that have user-level security) or which computer (on servers that have
    share-level security) opened the resource. Note that Windows does not
    support share-level security.This string is Unicode if _WIN32_WINNT or FORCE_UNICODE are defined.</p>
  </blockquote>
  
  <p>Now, the network that I am running this script in has indeed <b>Share-level security</b>, I am just not sure how to list the computer name. </p>
  
  <h2>Relevant code</h2>
  
  <p>Library includes:</p>
  
  <pre><code>#pragma comment(lib, "Netapi32.lib")
  #include &lt;stdio.h&gt;
  #include &lt;assert.h&gt;
  #include &lt;windows.h&gt; 
  #include &lt;lm.h&gt;
  </code></pre>
  
  <p>Initiate structure:</p>
  
  <p><code>fstatus</code> is defined in my code as, <code>NET_API_STATUS fStatus</code>, it is the I/O structure. Documentation <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb525378%28v=vs.85%29.aspx" rel="nofollow">here</a></p>
  
  <p>if <code>fstatus</code> is successful the Return value <code>NERR_Success</code>.</p>
  
  <p>If the function fails, the return value can be one of the following error codes.</p>
  
  <ul>
  <li><code>ERROR_ACCESS_DENIED</code> The user does not have access to the requested
  information.</li>
  <li><code>ERROR_INVALID_LEVEL</code> The value specified for the level parameter is
  not valid.</li>
  <li><code>ERROR_INVALID_PARAMETER</code> The specified parameter is not valid.</li>
  <li><code>ERROR_MORE_DATA More</code> entries are available. Specify a large enough buffer to receive all entries.</li>
  <li><strong>....</strong></li>
  </ul>
  
  <p>more <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb525382%28v=vs.85%29.aspx" rel="nofollow">here</a></p>
  
  <p>To handle that I use <code>if ((fStatus == NERR_Success) || (fStatus == ERROR_MORE_DATA))</code></p>
  
  <p>The user name could not be found.</p>
  
  <pre><code>fStatus = NetFileEnum(
                  flServerName, //Pointer to a string that specifies the DNS or NetBIOS name of the remote server on which the function is to execute. If this parameter is NULL, the local computer is used. 
                  flBasePath, //Pointer to a string that specifies a qualifier for the returned information. If this parameter is NULL, all open resources are enumerated.
                  flUserName, //Pointer to a string that specifies the name of the user or the name of the connection.
                  dfLevel, //Pointer to a string that specifies the name of the user or the name of the connection. Can be either 2 or 3, I am using 3
                  (LPBYTE*)&amp;pFile, //Pointer to the address of the buffer that receives the information. The format of this data depends on the value of the level parameter. 
                  fwPrefMaxLen, //pecifies the preferred maximum length of returned data, in bytes.
                  &amp;fwEntriesRead, //Pointer to a value that receives the count of elements actually enumerated.
                  &amp;fwTotalEntries, //Pointer to a value that receives the total number of entries that could have been enumerated from the current resume position.
                  &amp;fwResumeHandle); //Pointer to a value that contains a resume handle which is used to continue an existing file search.
  
  NET_API_STATUS NetFileEnum(
    _In_     LMSTR servername,
    _In_     LMSTR basepath,
    _In_     LMSTR username,
    _In_     DWORD level,
    _Out_    LPBYTE *bufptr,
    _In_     DWORD prefmaxlen,
    _Out_    LPDWORD entriesread,
    _Out_    LPDWORD totalentries,
    _Inout_  PDWORD_PTR resume_handle
  );
  </code></pre>
  
  <p>RAW Values for the above:</p>
  
  <pre><code>   NET_API_STATUS fStatus;
     LPFILE_INFO_3 pFile = NULL;
     LPFILE_INFO_3 pTmpFile;
     DWORD dfLevel = 3;
     LPTSTR flServerName = NULL;
     LPTSTR flUserName = NULL;
     LPTSTR flBasePath = NULL;
     DWORD fwPrefMaxLen = MAX_PREFERRED_LENGTH;
     DWORD fwEntriesRead = 0;
     DWORD fwTotalEntries = 0;
     DWORD fwResumeHandle = 0;
  </code></pre>
  
  <p><code>pTmpfile</code> is the level 3 (documentation <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb525375%28v=vs.85%29.aspx" rel="nofollow">here</a>) buffer object, </p>
  
  <blockquote>
    <p>bufptr [out]</p>
  
  <pre><code>Pointer to the address of the buffer that receives the information. The format of this data depends on the value of the levelparameter.
  </code></pre>
  </blockquote>
  
  <p>This buffer returns data in this format,</p>
  
  <pre><code>typedef struct _FILE_INFO_3 {
    DWORD fi3_id;
    DWORD fi3_permissions;
    DWORD fi3_num_locks;
    LMSTR fi3_pathname;
    LMSTR fi3_username;
  } FILE_INFO_3, *PFILE_INFO_3, *LPFILE_INFO_3;
  </code></pre>
  
  <p>Retrieve data:</p>
  
  <pre><code>printf("\n\tComputer: %S\n", pTmpFile-&gt;fi3_username); //how do I retrieve computer name???
  printf("\n\tid: %D\n", pTmpFile-&gt;fi3_id);
  printf("\n\tpath: %S\n", pTmpFile-&gt;fi3_pathname);
  </code></pre>
  
  <p>**It is important to note that I have tried this using vbnet and it works, but somehow cant figure it how to do it on c++. </p>
  
  <p>Complete Test Program:</p>
  
  <pre><code>#ifndef UNICODE
  #define UNICODE
  #endif
  //Initialize the NetAPI Library
  #pragma comment(lib, "Netapi32.lib")
  #include &lt;stdio.h&gt;
  #include &lt;assert.h&gt;
  #include &lt;windows.h&gt;
  #include &lt;lm.h&gt;
  int wmain(int argc, wchar_t *argv[])
  {
      //NetFile Enum, using 3 Level.
      NET_API_STATUS fStatus;
      LPFILE_INFO_3 pFile = NULL;
      LPFILE_INFO_3 pTmpFile;
      DWORD dfLevel = 3;
      LPTSTR flServerName = NULL;
      LPTSTR flUserName = NULL;
      LPTSTR flBasePath = NULL;
      DWORD fwPrefMaxLen = MAX_PREFERRED_LENGTH;
      DWORD fwEntriesRead = 0;
      DWORD fwTotalEntries = 0;
      DWORD fwResumeHandle = 0;
      DWORD fi;
      //
      // Check command line arguments.
      // Dont need this currently.
      //
      do
      {
          fStatus = NetFileEnum(flServerName,
          flBasePath,
          flUserName,
          dfLevel,
          (LPBYTE*)&amp;pFile,
          fwPrefMaxLen,
          &amp;fwEntriesRead,
          &amp;fwTotalEntries,
          &amp;fwResumeHandle);
          if ((fStatus == NERR_Success) || (fStatus == ERROR_MORE_DATA))
          {
              if ((pTmpFile = pFile) != NULL)
              {
                  for (fi=0; fi &lt; fwEntriesRead; fi++)
                  {
                      assert(pTmpFile != NULL);
                      if (pTmpFile == NULL)
                      {
                          fprintf(stderr, "An access violation has occurred\n");
                          break;
                      }
                      printf("\n\tComputer: %S", pTmpFile-&gt;fi3_username);
                      printf("\n\tid: %d", pTmpFile-&gt;fi3_id);
                      printf("\n\tpath: %s", pTmpFile-&gt;fi3_pathname);
                      printf("\n\tLocks: %d\n", pTmpFile-&gt;fi3_num_locks);
                      pTmpFile++;
                      fwTotalEntries++;
                  }
              }
          }
          else
          fprintf(stderr, "A system error has occurred: %d\n", fStatus);
          //
          // Free the allocated memory.
          //
          if (pFile != NULL)
          {
              NetApiBufferFree(pFile);
              pFile = NULL;
          }
      }
      //
      // Continue to call NetFilEnum while
      //  there are more entries.
      //
      while (fStatus == ERROR_MORE_DATA);
      if (pFile != NULL)
      NetApiBufferFree(pFile);
      return 0;
  }
  </code></pre>
  
  <p><strong>Output:</strong></p>
  
  <p>From Build:</p>
  
  <pre><code>1&gt;------ Build started: Project: Perfmon, Configuration: Release Win32 ------
  1&gt;Compiling...
  1&gt;file_enumerate.cpp
  1&gt;Linking...
  1&gt;Generating code
  1&gt;Finished generating code
  1&gt;Embedding manifest...
  1&gt;Build log was saved at "file://...."
  1&gt;Perfmon - 0 error(s), 0 warning(s)
  ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
  </code></pre>
  
  <p>Run:</p>
  
  <pre><code> Computer: User1 //prints only username, not computername (in our system, each user has the same username)
   id: 1005687
   path: c:\fips\library
  
   Computer: User2 //prints only username, not computername (in our system, each user has the same username)
   id: 1005689
   path: c:\fips\library\util
  </code></pre>