NetFileEnum возвращает ERROR_MORE_DATA
Попытка получить большой список открытых файлов с файлового сервера возвращает значение ERROR_MORE_DATA (Ошибка № 234), но отлично работает, когда имеет дело только с небольшим списком файлов (кажется, возвращает около 84 записей). Этот код основан на примере по адресу: http://pinvoke.net/default.aspx/netapi32/NetFileEnum.html
Большинство примеров, которые я нашел, не касаются того, как обрабатывать большое количество файлов. Насколько я понимаю, это как-то связано с resume_handle, однако я не уверен, что нужно делать. Нужно ли как-то вызывать этот метод в цикле?
Код выглядит следующим образом:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace OpenFiles
{
class Program
{
public static string computername = "computername";
static void Main(string[] args)
{
List<string> theFileList = NativeMethods.GetFiles(computername);
foreach (string file in theFileList)
{
Console.WriteLine(file);
}
}
}
static class NativeMethods
{
[DllImport("netapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern int NetFileEnum(
string servername,
string basepath,
string username,
int level,
ref IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
IntPtr resume_handle
);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct FILE_INFO_3
{
public int fi3_id;
public int fi3_permission;
public int fi3_num_locks;
[MarshalAs(UnmanagedType.LPWStr)]
public string fi3_pathname;
[MarshalAs(UnmanagedType.LPWStr)]
public string fi3_username;
}
[DllImport("Netapi32.dll", SetLastError = true)]
static extern int NetApiBufferFree(IntPtr Buffer);
public static List<string> GetFiles(string Computername)
{
const int MAX_PREFERRED_LENGTH = -1;
int dwReadEntries;
int dwTotalEntries;
IntPtr pBuffer = IntPtr.Zero;
FILE_INFO_3 pCurrent = new FILE_INFO_3();
List<string> fileList = new List<string>();
int dwStatus = NetFileEnum(Computername, null, null, 3, ref pBuffer, MAX_PREFERRED_LENGTH, out dwReadEntries, out dwTotalEntries, IntPtr.Zero);
if (dwStatus == 0)
{
for (int dwIndex = 0; dwIndex < dwReadEntries; dwIndex++)
{
IntPtr iPtr = new IntPtr(pBuffer.ToInt32() + (dwIndex * Marshal.SizeOf(pCurrent)));
pCurrent = (FILE_INFO_3)Marshal.PtrToStructure(iPtr, typeof(FILE_INFO_3));
string fileInfo = pCurrent.fi3_id + "," +
pCurrent.fi3_num_locks + "," +
pCurrent.fi3_pathname + "," +
pCurrent.fi3_permission + "," +
pCurrent.fi3_username;
fileList.Add(fileInfo);
}
NetApiBufferFree(pBuffer);
}
else
{
Console.WriteLine("error: " + dwStatus);
}
return fileList;
}
}
}
1 ответ
В моем ограниченном опыте очень большое количество результатов может быть больше, чем максимальный буфер. В этом случае выдается более подробный ответ с данными, который дает нам указание перезвонить с указанным дескриптором возобновления. В вашем примере дескриптор возобновления не будет изменен, потому что подпись DllImport не определяет его как выходной параметр. Использование дескриптора возобновления результата первого вызова (переход в ноль означает первый вызов) позволяет получить следующий пакет. Повторяйте цикл, пока не получите ответ об успешном выполнении или другую ошибку.
Обязательно исправьте проблему, при которой определяется подпись NetFileEnum. Дескриптор возобновления не определен с выходом, поэтому не может быть изменен вызываемой функцией.
Вместо этого попробуйте следующую подпись импорта DLL:
[DllImport("netapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern int NetFileEnum(
string servername,
string basepath,
string username,
int level,
ref IntPtr bufptr,
int prefmaxlen,
out int entriesread,
out int totalentries,
out IntPtr resume_handle
);
Вы должны иметь возможность повторно вызывать NetFileEnum с обработкой результирующего резюме несколько раз, когда вы получаете больше данных ответа.