DeviceIoControl GetLastError 87 (ERROR_INVALID_PARAMETER)

Этот код отлично работает при запуске в Windows 7:

HANDLE hVol = CreateFile(L"\\\\.\\c:", GENERIC_WRITE | GENERIC_READ, 
                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
// hVol is always successful (both of Win7 and 10), I double-checked
BYTE pData[sizeof(DWORDLONG) + 0x10000];
DWORD cb;
MFT_ENUM_DATA med;
med.StartFileReferenceNumber = 0;
med.LowUsn = 0;
med.HighUsn = MAXLONGLONG;
DeviceIoControl(hVol, FSCTL_ENUM_USN_DATA, &med, sizeof(med), pData, sizeof(pData), &cb, NULL);
err = GetLastError();

но я получаю сообщение об ошибке 87 (ERROR_INVALID_PARAMETER) при запуске в Windows 10. В чем может быть причина?


person Basj    schedule 31.07.2017    source источник
comment
Почему вы указываете GENERIC_WRITE? Вы, кажется, только читаете.   -  person IInspectable    schedule 01.08.2017


Ответы (1)


MFT_ENUM_DATA на самом деле это typedef, который расширяется до MFT_ENUM_DATA_V0 или MFT_ENUM_DATA_V1 в зависимости от NTDDI_VERSION:

#if (NTDDI_VERSION >= NTDDI_WIN8)
typedef MFT_ENUM_DATA_V1 MFT_ENUM_DATA, *PMFT_ENUM_DATA;
#else
typedef MFT_ENUM_DATA_V0 MFT_ENUM_DATA, *PMFT_ENUM_DATA;
#endif

очевидно, в вашем случае NTDDI_VERSION >= NTDDI_WIN8 и вы используете MFT_ENUM_DATA_V1.

и вы не инициализируете MaxMajorVersion, который должен быть установлен на 2 или 3.

поэтому вам нужно или добавить строку med.MaxMajorVersion = 2; (или 3). или используйте MFT_ENUM_DATA_V0 med={};

person RbMm    schedule 31.07.2017
comment
#if (NTDDI_VERSION >= NTDDI_WIN8) оценивается во время компиляции. OP запускает один и тот же двоичный файл в обеих системах, так что это не имеет отношения к проблеме. - person IInspectable; 01.08.2017
comment
@IInspectable - конечно, оценивается во время компиляции. и что ? - person RbMm; 01.08.2017
comment
Я скомпилировал на Win7 и протестировал один и тот же .exe на Win7 и Win10. Я согласен с вами @IInspectable: он оценивается во время компиляции. Но как ни странно, выполнение MFT_ENUM_DATA_V0 med; решило проблему :) (большое спасибо, RbMm!) - person Basj; 01.08.2017
comment
@Basj - где вы компилируете - абсолютно не важно. важно, какую версию SDK вы используете (я предполагаю, что вы не определяете NTDDI_VERSION самостоятельно) - person RbMm; 01.08.2017
comment
@RbMm это верно. Я проверил: во время компиляции (на Win7, но это не имеет значения) из-за того, что у меня есть SDK, я вижу, что NTDDI_VERSION >= NTDDI_WIN8 верно, поэтому применяется: typedef MFT_ENUM_DATA_V1 MFT_ENUM_DATA, *PMFT_ENUM_DATA; - person Basj; 01.08.2017
comment
И последнее, @RbMm, вы думаете, что использование _V0 или _V1 (или med.MaxMajorVersion = 2 или 3) немного изменит производительность перечисления? - person Basj; 01.08.2017
comment
@Basj - меньшая структура - больше структур в одном буфере. должен быть быстрее (но трудно сказать, как больше). с другой стороны версия с более высокой структурой имеет дополнительную информацию. но он может не поддерживаться ОС. действительно теперь MaxMajorVersion может быть 2 или 3 или 4 (на win 10) и выводить до USN_RECORD_V4. но win7 поддерживает только USN_RECORD_V2 - person RbMm; 01.08.2017
comment
Еще раз спасибо @RbMm. Хотел бы я +100 за этот ответ (я застрял на несколько часов...) - person Basj; 01.08.2017
comment
@Basj - если вы хотите повысить производительность - используйте большой буфер (скажем, 16 МБ) - с этим вы получите меньшее количество DeviceIoControl. - person RbMm; 01.08.2017