-
Rouse_ © (11.04.08 17:04) [20]Ну не знаю... У меня этот код отрабатывает четко, ни одного срыва потока нет, хоть код и оставлен на всякий случай... Если без NtQueryInformationFile тогда виснет...
-
Rouse_ © (11.04.08 17:07) [21]А, ну понятно, там запрашивается FileModeInformation, а я прошу FileNameInformation :)
-
> [18] Rouse_ © (11.04.08 16:46)
> Т.к. нужно искать только файловые хэндлы, то перед вызовом NtQueryObject нужно сказать
> NtQueryInformationFile и проверить результат, если STATUS_SUCCESS, то повиснуть не должны ;)
Саш, насколько я помню, на самом запросе NtQueryInformationFile мы виснем с не меньшим успехом,
просто зависание не такое "глубокое" :)
Но нить терминировать все равно приходиться.
Могу еще раз проверить, если ошибаюсь.
P.S.
Кто-то говорил, что решил данную проблемму "путем анализа таблицы Handle`ов"
или что-то в этом духе. Не помню. Поиск по архивам старых веток ничего не дал. -
Rouse_ © (11.04.08 17:08) [23]Проверь...
-
> [21] Rouse_ © (11.04.08 17:07)
> А, ну понятно, там запрашивается FileModeInformation, а я прошу FileNameInformation :)
Так. Бросаю все дела и иду проверять :) -
> [24] Riply © (11.04.08 17:09)
P.S.
Надеюсь что много времени это не займет :) -
Rouse_ © (11.04.08 17:26) [26]Код у меня на сайте в разделе WinAPI возьми, чтоб самой не собирать...
-
Rouse_ © (11.04.08 17:40) [27]я сейчас изменил свой код на вот такой:WAIT_TIMEOUT:
begin
TerminateThread(hThread, 0);
Result := 'Thread terminated';
end;
сработок не было :) -
> [26] Rouse_ © (11.04.08 17:26)
> Код у меня на сайте в разделе WinAPI возьми, чтоб самой не собирать...
Хорошо.
Пока протестила у себя (на своем коде).
Добавила проверку NtQueryInformationFile(FileNameInformation).
Не помогло:
Если пробегаться по всем процессам системы, то терминировать нить приходится 25-26 раз.
Сейчас скачаю оригинальный код и попробую тоже самое с ним. -
Rouse_ © (11.04.08 17:48) [29]обманул я тебя :) действительно приходится срывать... оть-же... Не обращал на этот момент внимание... Там у меня логика работы, что ищется процесс и путь к файлу, если не находит - в лог ничего не выводиться... Блин... Лан будем думать...
-
> [29] Rouse_ © (11.04.08 17:48)
> обманул я тебя :)
А я уж было стала готовить отчет: чем твой пример компилировался, да на какой системе тестировался :)
> Лан будем думать...
Повторюсь: к сожалению, не помню кто с нашего форума (из мастеров)
говорил что решил проблемму "путем анализа таблицы Handle`ов". Или что-то в таком духе. -
Вот ведь надо же было напоминать об этой проблемме.
Вместо того чтобы делом заниматься, Handl`ы тут перечисляю :)
Если кому интересно вот некоторые результаты:
Как я уже говорила, давным-давно пыталась найти хоть какой-то запрос,
на котором не виснем, и по результату (или по возвращаемой ошибке) которого
можно было бы хотя бы разбить объекты типа файл на две группы:
"Опасную" и "Безопасную".
В этом случае, для "Опасной" группы, если уж так приспичило создаем нить,
а с другой работаем "напрямую".
Меня постигла неудача - самые невинные запросы приводили к зависанию.
Сейчас я подумала, а может попробовать в запросе не напрямую,
а как-то косвенно обратиться к Handl`у ?
И вот что у меня получилось:
По аналогии с методикой, используемой в ReopenFile (подсказанной guav - ом),
попробуем запросить атрибуты у файла с пустым именем,
указав в качестве его родителя наш "подопытный" Handle.
Т.е. делаем вид, что он нас вовсе не интересует, а интересует только ребенок :)var
EmptyName: UNICODE_STRING;
BaseInfo: FILE_BASIC_INFORMATION;
ObjectAttr: OBJECT_ATTRIBUTES;
begin
RtlInitUnicodeString(@EmptyName, nil);
InitializeObjectAttributes(@ObjectAttr, @EmptyName, OBJ_CASE_INSENSITIVE, pThreadParam.hFile, nil);
Result := NtQueryAttributesFile(@ObjectAttr, @BaseInfo);
Если Result = STATUS_SUCCESS, то (в зависимости от типа теста)
обходимся без нити, либо внутри нити не делаем запросы, ведущие к зависанию.
Результаты при пробежке по всем процессам системы:
RequestCount 1248 // Всего запросов для объектов типа FILE
SuccessRequestCount 801 // из них успешных
ErrorRequestCount 447 // и с ошибкой. Здесь, кроме файлов в стандартном понимании, еще куча всего :)
Итого в двух случаях из трех можно обойтись без нити.
И только треть остается под вопросом.
(Выигрыш по времени в разы :)
Тестирование на коде от Rouse дало более интересные результаты:
(У себя я шла по всем объектам без исключений и какой либо фильтрации )
Исходный код без изменений:
---------------------------
NameCount: 433
TickCount: 15015
TerminateCount: 25
Запрос нити для всех объектов, но внутри нити предварительная проверка на NtQueryAttributesFile
---------------------------
NameCount: 429
TickCount: 6000
TerminateCount: 0
Работаем вообще без нитей, основываясь на показаниях NtQueryAttributesFile :)
---------------------------
NameCount: 429
TickCount: 937
TerminateCount: 0
В последнем случае выигыш уже не в разы а на порядки, уж не говоря о "нерезаньи по-живому" :)
Есть маленькая неувязочка.
Мы потеряли четыре файла.
Кто они такие (может нормальные пайпы или еще кто) и почему потерялись,
оставляю изучение этого вопроса заинтересованным лицам. :)
Как подсказку к разбирательствам могу дать следующее:
я отбрасывала запрос на имя не анализируя результат.
Т.е если Result <> STATUS_SUCCESS, то бросала это дело.
На самом деле анализ может что-то подсказать.
Возвращаемые ошибки, которые удалось засечь:
STATUS_UNSUCCESSFUL, STATUS_INVALID_DEVICE_REQUEST, STATUS_INVALID_PARAMETER,
STATUS_OBJECT_NAME_INVALID, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_NOT_SUPPORTED
Ну и напоследок приведу основные изменения Сашином коде,
которые надо сделать для тестирования описанного выше безобразия:function GetFileNameDirect(hFile: THandle; var FileName: string): NTSTATUS; // - integer !!!
var
ObjectNameInfo: TOBJECT_NAME_INFORMATION;
dwReturn: DWORD;
// !!!! Это другое определение UNICODE_STRING, не как у Саши в данном примере
EmptyName: UNICODE_STRING;
BaseInfo: FILE_BASIC_INFORMATION;
ObjectAttr: OBJECT_ATTRIBUTES;
begin
FileName := '';
RtlInitUnicodeString(@EmptyName, nil);
InitializeObjectAttributes(@ObjectAttr, @EmptyName, OBJ_CASE_INSENSITIVE, hFile, nil);
Result := NtQueryAttributesFile(@ObjectAttr, @BaseInfo);
if Result = STATUS_SUCCESS then
begin
Result := NtQueryObject(hFile, ObjectNameInformation,
@ObjectNameInfo, MAX_PATH * 2, @dwReturn);
if Result = STATUS_SUCCESS then
begin
SetLength(FileName, MAX_PATH);
WideCharToMultiByte(CP_ACP, 0, @ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength -
ObjectNameInfo.Name.Length], ObjectNameInfo.Name.Length, PChar(FileName),
MAX_PATH, nil, nil);
end
end;
end;
Чуть измененная GetFileNameThread:function GetFileNameThread(lpParameters: Pointer): DWORD; stdcall;
var
FileNameInfo: FILE_NAME_INFORMATION;
ObjectNameInfo: TOBJECT_NAME_INFORMATION;
IoStatusBlock: IO_STATUS_BLOCK;
pThreadParam: TGetFileNameThreadParam;
dwReturn: DWORD;
// !!!! Это другое определение UNICODE_STRING, не как у Саши в данном примере
EmptyName: UNICODE_STRING;
BaseInfo: FILE_BASIC_INFORMATION;
ObjectAttr: OBJECT_ATTRIBUTES;
begin
ZeroMemory(@FileNameInfo, SizeOf(FILE_NAME_INFORMATION));
pThreadParam := PGetFileNameThreadParam(lpParameters)^;
// RtlInitUnicodeString(@EmptyName, nil);
// InitializeObjectAttributes(@ObjectAttr, @EmptyName, OBJ_CASE_INSENSITIVE, pThreadParam.hFile, nil);
// Result := NtQueryAttributesFile(@ObjectAttr, @BaseInfo);
Result := STATUS_SUCCESS;// Для теста внутри нити закоментировать эту строчку и открыть предыдущие
if Result = STATUS_SUCCESS then
begin
// Не убирайте эту строчку - на ней зависание не такое "глубокое" :)
if GetFileType(pThreadParam.hFile) <> FILE_TYPE_PIPE
then Result := NtQueryInformationFile(pThreadParam.hFile, @IoStatusBlock,
@FileNameInfo, MAX_PATH * 2, FileNameInformation);
if Result = STATUS_SUCCESS then
begin
Result := NtQueryObject(pThreadParam.hFile, ObjectNameInformation,
@ObjectNameInfo, MAX_PATH * 2, @dwReturn);
if Result = STATUS_SUCCESS then
begin
pThreadParam.Status := Result;
WideCharToMultiByte(CP_ACP, 0,
@ObjectNameInfo.Name.Buffer[ObjectNameInfo.Name.MaximumLength -
ObjectNameInfo.Name.Length],
ObjectNameInfo.Name.Length, @pThreadParam.Data[0],
MAX_PATH, nil, nil);
end
else
begin
pThreadParam.Status := STATUS_SUCCESS;
Result := STATUS_SUCCESS;
WideCharToMultiByte(CP_ACP, 0,
@FileNameInfo.FileName[0], IoStatusBlock.Information,
@pThreadParam.Data[0],
MAX_PATH, nil, nil);
end;
end;
end;
PGetFileNameThreadParam(lpParameters)^ := pThreadParam;
ExitThread(Result);
end;
Изменения в главной процедуре:if GetFileNameDirect(hFile, FilePath) <> STATUS_SUCCESS
then ;//FilePath := GetFileNameFromHandle(hFile);
Уфф... Вроде все.
В заключении хочу сказать, что то что у меня не нашлось объектов,
на которых NtQueryAttributesFile ведет к зависанию, вовсе не означает,
что их не существует :) -
Игорь Шевченко © (12.04.08 12:03) [32]Riply © (12.04.08 04:50) [31]
Можно нескромный вопрос - а нафига такие извращения ?
Все равно ты не получишь со 100% гарантией список открытых файлов (хендлов) чужого (да и своего тоже) процесса, к чему мучиться ?
Я просто к чему - сам страдал в свое время ерундой, потом сообразил, что лучше самодвижущееся пресс-папье изобрести.
Кому надо узнать список открытых хендлов, нехай запустит handles.exe или Process Explorer, авторы этих инструментов известны, а главное, применяют в корне другой подход.
И это правильно. -
> [32] Игорь Шевченко © (12.04.08 12:03)
> Все равно ты не получишь со 100% гарантией список открытых файлов (хендлов) чужого (да и своего тоже) процесса, к чему мучиться ?
Когда FileExists возвращает False это не означает что файл не существует, imho. Зачем она нужна ? :)
> Можно нескромный вопрос - а нафига такие извращения ?
Вопрос скромный :)
Начнем с того, что свой блок для работы с Handl`ми (не обязательно "файловыми") я написала только для
себя и не собираюсь его предлагать другим.
Не потому что жадная, а потому что нехай запустит "handles.exe или Process Explorer". :)
Мой блок работает так как надо мне и умеет то, что нужно мне.
А чтобы что-то работало так как надо ее величеству Riply, может написать только Riply :)
И он мне в работе неоднократно помогал в работе.
Это раз.
Второе:
мне очень не нравиться, когда у меня за спиной висят нерешенные задачи.
А я люблю себя чуствовать комфортно. :)
Третье:
этот вопрос интересует многих и мне будет приятно, если мое решение окажется правильным и принесет кому-то пользу :)
Четвертое:
Во время "страдания ерундой" я лучше начинаю понимать (чуствовать) как работает система
и получаю новые знания.
Есть еще пятое, шестое и т.д. Если будет интересно, продолжу перечисление :)
Вот так и получается, Игорь, что все это я делала для себя любимой :) -
> [33] Riply © (12.04.08 17:07)
Нулевой пункт забыла:
Мне интересно ! :) -
Игорь Шевченко © (12.04.08 23:52) [35]Riply © (12.04.08 17:07) [33]
Я к чему - и Process Explorer и handles.exe используют для получения информации ядерный драйвер.
Как ты понимаешь, и Руссиновичу и брату его во Христе Когсуэллу тоже интересно "как это там система работает", весьма вероятно, что было интересно даже больше, чем тебе. Следовательно, они пришли к выводу, что попытки получить такую информацию из пользовательского режима рано или поздно закончатся неудачей. Вот и Шрайбер тоже рекомендует для получения информации пользоваться драйвером - у него, у драйвера, возможностей больше - можно читать напрямую те же таблицы, из которых получается информация, возвращаемая NtQueryxxxxx, и главное, что в это время тебе никто не мешает. А от вызова NtQueryxxxx до вызова NtQueryzzzz в системе может произойти масса событий, в результате чего информация собранная обоими вызовами будет настолько не соответствовать действительности, что потеряет всякий смысл. -
> [35] Игорь Шевченко © (12.04.08 23:52)
Вынуждена полностью согласиться со всеми утверждениями.
К сожалению, до написания драйвера я еще не доросла. Уровень не тот :(
Правда, "еще не вечер" :)
А пока идет обучение, вынуждена довольствоваться тем,
что удается получить в пользовательском режиме :) -
Игорь Шевченко © (13.04.08 00:59) [37]
> К сожалению, до написания драйвера я еще не доросла. Уровень
> не тот :(
Да это несложно. Покупается/ищется книга Свена Шрайбера "Недокументированные возможности Windows 2000" - там как раз таких драйверов, которые читают ядерные таблицы, штук несколько, и по шагам расписано их написание. Я серьезно. -
> [37] Игорь Шевченко © (13.04.08 00:59)
> Да это несложно. Покупается/ищется книга Свена Шрайбера "Недокументированные возможности Windows 2000" -
> там как раз таких драйверов, которые читают ядерные таблицы, штук несколько, и по шагам расписано их написание.
> Я серьезно.
Ой, Игорь, я ведь могу последовать совету и сунуться в эту область :)
И дорги назад уже не будет. Уж я то себя знаю. Так и завязну там :)