Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Что такое текущая директория? (http://forum.oszone.net/showthread.php?t=29570)

Guest 27-01-2003 21:38 204622

Помогите, пожалуйста, начинающему программисту разобраться с понятием текущей директории процесса. Раньше думал, что это каталог, из которого запускается приложение. Однако, сомнение появилось после того, как API-функция GetCurrentDirectory() возвратила "C:\Documents and Settings\имя_учётной_записи" (в Windows XP; реально программа запускалась из другого каталога). Причём это имело место только в случае автозапуска программы из реестра (HKLM\...\Run), при обычном запуске, а также при автозапуске из папки "Автозагрузка" функция возвращала каталог, из которого запускалась программа. Вообще-то вопрос возник после того, как появилась необходимость в программе, стартующей вместе с системой, создать или открыть существующий файл в каталоге программы. Для этого использовалась функция CreateFile(), которой передавалось имя соответствующего файла без пути к нему. Согласно документации файл должен был быть создан в текущей директории - он создавался в "C:\Documents and Settings\имя_учётной_записи". В принципе это не является большой проблемой, т.к. можно, например,  запускать программу из папки "Автозагрузка" или использовать функцию GetModuleFileName() с последующим отбрасыванием имени исполняемого файла. Просто хочется узнать, почему так происходит?

shurikan 28-01-2003 02:21 204623

Понятие текущая директория - это наследство DOS. Там она отображалась в приглашении командной строки, после выбора диска и нескольких команд cd aaa\bbb, например. Т.е. это та директория на текущем диске, в которую ты вошёл. При наборе имени программы, которую ты хотел бы запустить, DOS сначала искала её в этом каталоге (текущем) или, если не находила, перебирала каталоги, указанные в переменной среды PATH. После того, как программа стартовала, текущий каталог оставался неизменным, а именно тем, в котором ты находиося, запуская программу. Хотя, если в программе были соответствующие вызовы, она могла сменить текущий каталог. Все файлы, открываемые на чтение или запись, брались/создавались в этом каталоге, если путь был указан как относительный, а не абсолютный.
В принципе Win XP тоже сохранила это понятие, хотя в ней трудно оставаться в одном и том же каталоге всё время. Как только ты открываешь (например в проводнике) ещё одну папку, сразу попадаешь в другой каталог, который и становится текущим. А при запуске программы надо рассматривать три вида каталогов - текущий, рабочий и каталог программы. В момент запуска текущим остаётся тот каталог, где ты находился. Но многие программы имеют еще т.н. рабочий каталог, они выдают запрос на смену текущего каталога и делают текущим рабочий. И ещё они точно знают тот каталог, где находится их бинарник.

Guest 29-01-2003 22:01 204624

Спасибо за ответ

vasketsov 30-01-2003 17:31 204625

Guest
Цитата:

Спасибо за ответ
Не за что. В смысле, ответ-то неправильный, причем совсем. Итак, по порядку.

Для каждого процесса есть установленный текущий каталог. Этот каталог, естественно, можно прочитать, сменить и так далее, но обычно сами процессы этим не балуются. Есть набольшие исключения, например, у процесса может не быть текущего каталога по умлочанию и хэндл на него может быть не открыт (см. ниже про PEB). Такие процессы существуют и нормально работают, по всей видимости, запрос текущего каталога для них лмбо обламывается, либо возвращает системый, большего придумать сложно. Но сталкиваться с такими процессами, уверяю, Вам придется ой как нечасто, если вообще придется (хотя, мой TaskEx, если ему указано запускаться под системной учетной записью, запускается с неоткрытым текущим каталогом, да и сам может показать, у кого какой текущий каталог, строка запуска и т.п.). А пока надо запомнить, что у каждого процесса есть свой каталог по умолчанию, абсолютно любой, лишь бы он существовал.

На NT-системах это подтверждается форматом PEB (Process Environment Block - блок окружения процесса). За этим отсылаю на свой сайт http://zw.nightmail.ru, где есть краткое описание, что такое TEB и PEB, а также их структура (в описании структур). Обратить внимание надо на PROCESS_PARAMETERS, ссылка на это есть в PEB, так вот, в параметрах процесса хранятся ОТДЕЛЬНЫЕ величины для
а) имени запускаемого образа,
б) текущего каталога,
в)командной строки (обращаю внимание, это полная командная строка, то есть, вообще говоря, в командной строке имя запускаемого файла иожет отсутствовать, она вообще может отсутствовать, как это ни странно)
г) пути поиска файлов (в этот путь в коде kernel32.dll насильно добавляется текущий каталог, но в общем случае его там тоже может не быть, как, например, в UNIX-системах из-за соображений безопасности)

В принципе, чтоб понять, что это все такое и как оно устроено, надо поглядеть структуру PEB и дочерних структур, и посмотреть TaskEx-ом эти параметры для запущенных в системе процессов и загруженные в них модули.

Для проводника переход в другой каталог НЕ приводит к изменению текущего каталога, он просто читает данные из другого каталога, и все. Так что заявления, что трудно оставаться в одном каталоге, мне напоминают заявления о шаловливых ручках, "куда б мне тыкнуться в проводнике"? Да и вообще, в одном процессе проводника может быть несколько окон, отображающих файлы и папки, тут уж явно никакой текущий каталог не поможет.

Никаких других каталогов, типа рабочих или программы, не существует. Все, чего нет в PEB - миф. Каталог программы получается из имени образа исполняемого файла, который сохраняется в структурах загрузчика. Откуда запустили - узнать невозможно, можно поглядеть текущий каталог для родительского процесса, но не более того. Вообще, программы запускаются не с диска, а из памяти, так что каталога такого принципиально быть не может.

Это все безусловно верно для всех NT-систем.
Для 9x - это немного не так, в плане структур и различных тонкостей в случае имени файла и командной строки, но все равно, текущий каталог устанавливается для процесса, а не для окна, он может быть сменен, но не меняется.

Guest 31-01-2003 00:45 204626

vasketsov
Теперь Вам спасибо за обстоятельный и, по всей видимости, правильный ответ. Однако,  кое-какие вопросы у меня ещё остались (наверное, я тупой :( ... или самокритичный :) ).

В связи с вышеобозначенным статусом начинающего программиста мне достаточно  сложно разобраться в данном вопросе на низком уровне (хотя абсолютно согласен с тем,  что истину можно найти именно там и не только по этому вопросу). Хочу подойти к  вопросу с немного другой стороны. В SDK нашёл определение текущего каталога как  каталога, из которого запущено приложение, кроме явно изменённого. В то же время  одним из параметров функции CreateProcess(), с помощью которой система создаёт  новый процесс, является указатель на строку, задающую текущий каталог для  создаваемого процесса. Если этот параметр равен NULL, в качестве текущего каталога  для нового процесса задаётся текущий каталог родительского процесса. Выходит, что,  как Вы и сказали, текущим каталогом для процесса может быть абсолютно любой каталог,  указанный родительским процессом. В моём случае функция GetCurrentDirectory()  возвратила "C:\Documents and Settings\имя_учётной_записи" при автозапуске программы  из реестра. Значит, либо этот каталог явно указан в функции CreateProcess(), либо это  текущий каталог родительского (системного) процесса, создающего мой процесс.  Возникает вопрос - а почему система не задаёт в качестве текущего каталог, в котором  расположен исполняемый файл? Ведь ей известен полный путь к нему, и именно так она  поступает в остальных случаях (при автозапуске через папку "Автозагрузка" и при  обычном запуске). Почему такое происходит только в случае автозапуска через реестр?

vasketsov 31-01-2003 13:31 204627

Цитата:

В SDK нашёл определение текущего каталога как  каталога, из которого запущено приложение, кроме явно изменённого
Это неверное определение, может SDK старый?

Цитата:

В то же время  одним из параметров функции CreateProcess(), с помощью которой система создаёт  новый процесс, является указатель на строку, задающую текущий каталог для  создаваемого процесса. Если этот параметр равен NULL, в качестве текущего каталога  для нового процесса задаётся текущий каталог родительского процесса
Да, это верно. Правда, это не система так делает, а реализуется в функции CreateProcess и тех функциях, что вызываются из нее. Если при непосредственном создании процесса указать, что у него текущий каталог NULL - так оно и будет.

Цитата:

функция GetCurrentDirectory()  возвратила "C:\Documents and Settings\имя_учётной_записи" при автозапуске программы  из реестра. Значит, либо этот каталог явно указан в функции CreateProcess(), либо это  текущий каталог родительского (системного) процесса, создающего мой процесс
1-е - вряд ли.
2-е - вероятнее всего, ибо запускает процессы оттуда сам Explorer, какой у него текущий каталог? У того Explorer-а им будет папка в профиле, именно та, что Вы указали, правда, я сейчас проверил для internat.exe - там еще добавлен подкаталог с рабочим столом.

Цитата:

Возникает вопрос - а почему система не задаёт в качестве текущего каталог, в котором  расположен исполняемый файл?
Еще раз, система сама это не делает, это устанавливаетс запускающая программа. Если из проводника даблкликом запускать процесс, то Explorer запускает его с тем текущим каталогом, что открыт (если только не нашелся ярлык, корректирующий запуск, например, pif).

Вобщем, различие связано с тем, как запускает процессы Explorer. Оно как раз показывает, что пока работает автозагрузка из реестра, текущим каталогом является текущий каталог самого Explorer-а, а при последующих запусках он текущий каталог устанавливает принудительно.

Автозагрузка из папки автозагрузки на самом деле реализуется через запуск ярлыка, так что это попадает под то, что выше написано.

Guest 01-02-2003 01:08 204628

vasketsov
А почему бы Explorer'у и в случае автозапуска программы из реестра не установить для  неё текущий каталог принудительно? Тот, в котором она находится. Мне кажется, что  такое поведение было бы более естественным. Я просто хочу понять, почему Explorer  по-разному устанавливает текущий каталог. Может быть из-за дополнительных затрат  времени на выделение каталога, в котором находится программа, из пути к исполняемому  файлу? Но ведь делает же он это при запуске программы через ярлык. И в каких целях  тогда может использовать свой текущий каталог приложение, если вызывающий процесс  (в частности Explorer) может установить его любым? Зачем он нужен?

А вообще посоветуйте, пожалуйста, хорошую литературу по программированию под  Windows (Visual C++, MFC, Win API). Что-нибудь классическое, вроде книги Страуструпа по  C++ (если есть такое, конечно :)).

vasketsov 01-02-2003 20:58 204629

Guest
1) вопрос не ко мне.

2) До известного уровня системных знаний в Windows - достаточно книг Рихтера. C++ и MFC никакого отношения к Windows не имеют.

Guest 02-02-2003 00:04 204630

vasketsov
Большое спасибо.

Serj Mig 14-06-2004 18:55 204631

При работе програмки  на Visual C++ функция GetCurrentDirectory возвращает путь расположения exe-шника. Но если после этого вызвать FileDialog и выбрать там файл, расположенный, например, в C:\Мои документы, то после этого GetCurrentDirectory будет возвращать C:\Мои документы.
Подскажите пожалуйста как с этим бороться. Заранее спасибо.

hasherfrog 15-06-2004 09:33 204632

Serj Mig
Скорее всего, FileDialog меняет текущую директорию. Ответ на Ваш вопрос, имхо, абсолютно очевиден. GetCurrentDirectory -> FileDialog -> SetCurrentDirectory(szOldCurrentPath)

RIKO 24-07-2004 00:19 204633

ExtractFilePath(Paramstr(0)) сегда возвращает диру откуда запущен exe. Принудительная установка GetDir


Время: 00:08.

Время: 00:08.
© OSzone.net 2001-