Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Доступ к директории исполняемого файла 
V
    Опции темы
xTr1m
Дата 18.1.2013, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 692
Регистрация: 9.2.2005
Где: Москва

Репутация: нет
Всего: 1



Доброго времени суток. В корпоративном коде (назовем это так) директория, в которой находится запущенная программа определяется так

Код

CString GetExePath()
{
        CString sExePath;
        HMODULE hModule;
        char szModuleName[2048];
        
        hModule = GetModuleHandle(NULL);
        if(hModule!=NULL)
        {
                if(GetModuleFileName(hModule, szModuleName, 2048)>0)
                {
                        CString buf;
                        buf= szModuleName;
                        sExePath = buf.Left(buf.ReverseFind('\\')+1);
                }
        }

        return sExePath;
}


но  разбираясь  с  Win32, прочитал, что путь также всегда передается в
командной  строке первым параметром,  также нашел, что в студии есть переменные, которые
позволяют получить путь вот так:

Код

CString filePath;
if(__argc > 0)
{
          filePath = __targv[0];
          filePath = filePath.Left(filePath.ReverseFind('\\')+1);
}


Выглядит   проще,  работает  быстрее.  Есть  только  вопрос,  а  можно
полагаться на переменные   __argc и   __targv и всегда ли путь будет находиться первым параметром в командной строке? 

А может есть другие варианты? Заранее спасибо.

PM MAIL WWW ICQ   Вверх
Albor
Дата 18.1.2013, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Можно так ещё
Код

CString target(GetCommandLine());
target=target.Mid(1,target.ReverseFind(_T('\\')));

PM MAIL ICQ   Вверх
volatile
Дата 18.1.2013, 18:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 4
Всего: 85



Цитата(xTr1m @  18.1.2013,  12:53 Найти цитируемый пост)
всегда ли путь будет находиться первым параметром в командной строке? 

Нет, не всегда.
Если программа запущена например, из другой програаммы с помощью CreateProcess(), то там может быть вообще нулевая строка.
Есть и еще случаи. 
Кроме того там может находицца относительный путь. 

Цитата(Albor @  18.1.2013,  15:22 Найти цитируемый пост)
Можно так ещё
CString target(GetCommandLine());
target=target.Mid(1,target.ReverseFind(_T('\\')));

а так вобще делать нельзя. Надеятесь, что в дополнительных параметров накогда не встретицца '\\' ?
Кроме того, все что выше, относицца и к этому варианту.

Цитата(xTr1m @  18.1.2013,  12:53 Найти цитируемый пост)
 студии есть переменные, которые 

В студии есть уже готовая переменная с путем программы _pgmptr, и функция _get_pgmptr();
Ими особо не пользовался, поэтому сказать за них ничо не могу.

Цитата(xTr1m @  18.1.2013,  12:53 Найти цитируемый пост)
В корпоративном коде (назовем это так) директория, в которой находится запущенная программа определяется так

Есть золотое правило - "если код работает, не трогай его".  smile 
Еще есть - "premature optimization.." и все такое 
Единственное, что мне здесь не очень нравицца это захардкоденное 2048


Это сообщение отредактировал(а) volatile - 19.1.2013, 01:21
PM MAIL   Вверх
Albor
Дата 19.1.2013, 22:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Цитата(volatile @  18.1.2013,  17:50 Найти цитируемый пост)
а так вобще делать нельзя. Надеятесь, что в дополнительных параметров накогда не встретицца '\\' ?
Кроме того, все что выше, относицца и к этому варианту.

Слэш должен быть обязательно - получим путь без имени файла. В чём может быть проблема (если не считать случай запуска, когда командной строки может не быть)? 
PM MAIL ICQ   Вверх
volatile
Дата 19.1.2013, 23:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 4
Всего: 85



Цитата(Albor @  19.1.2013,  22:07 Найти цитируемый пост)
 В чём может быть проблема 

Albor, GetCommandLine возвращает всю коммандную строку целиком.
например, при
Код

C:\path\mycopy.exe C:\tralala\file1.txt C:\blablabla\file2.txt

Ваш способ вернет:
Код

"C:\path\mycopy.exe C:\tralala\file1.txt C:\blablabla"

Это, не совсем 
Цитата(xTr1m @  18.1.2013,  12:53 Найти цитируемый пост)
директория, в которой находится запущенная программа 



Это сообщение отредактировал(а) volatile - 19.1.2013, 23:24
PM MAIL   Вверх
Albor
Дата 20.1.2013, 10:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Это понял, но программист наверняка знает как запускается его программа и может парсить строку как ему угодно. Кстати, озвученная вами  _pgmptr в MFC-проекте имеет значение NULL, соответственно вызов _get_pgmptr() заканчивается аварией. 


Это сообщение отредактировал(а) Albor - 20.1.2013, 11:48
PM MAIL ICQ   Вверх
Albor
Дата 20.1.2013, 11:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Цитата(volatile @  18.1.2013,  17:50 Найти цитируемый пост)
Единственное, что мне здесь не очень нравицца это захардкоденное 2048

MAX_PATH подошло бы больше, да и вызов GetModuleHandle(NULL) явно лишний, т.к. в GetModuleFileName() первым параметром можно передать NULL и получить тот же эффект.
PM MAIL ICQ   Вверх
volatile
Дата 20.1.2013, 19:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 4
Всего: 85



Цитата(Albor @  20.1.2013,  10:57 Найти цитируемый пост)
Кстати, озвученная вами  _pgmptr в MFC-проекте имеет значение NULL

Albor, в MFC все прекрасно работает.
Озвучил я для того чтобы обратились к мсдн. там и плюсы и минусы.
(поищите на форуме про юникодный/неюникодный проекты, это грабли для новичков обсуждались тыщу раз, надоело уже.)

PM MAIL   Вверх
Albor
Дата 20.1.2013, 20:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Цитата(volatile @  20.1.2013,  18:37 Найти цитируемый пост)
Albor, в MFC все прекрасно работает.
Озвучил я для того чтобы обратились к мсдн. там и плюсы и минусы.
(поищите на форуме про юникодный/неюникодный проекты, это грабли для новичков обсуждались тыщу раз, надоело уже.)

Да, работает, извиняюсь, мне нужно было обращаться к _wpgmptr.
PM MAIL ICQ   Вверх
xTr1m
Дата 21.1.2013, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 692
Регистрация: 9.2.2005
Где: Москва

Репутация: нет
Всего: 1



Спасибо большое. Получается, что буду писать так, как есть сейчас. Этот код не подходит, так как первым параметром не всегда идет
Код

CString filePath;
if(__argc > 0)
{
          filePath = __targv[0];
          filePath = filePath.Left(filePath.ReverseFind('\\')+1);
}


а этот, так как если будет два параметра, то нужен чуть более сложный разбор
Код

char *path = 0;
 _get_pgmptr(&path);

CString filePath(path);
filePath = filePath.Left(filePath.ReverseFind('\\')+1);

PM MAIL WWW ICQ   Вверх
volatile
Дата 21.1.2013, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 4
Всего: 85



Цитата(xTr1m @  21.1.2013,  14:18 Найти цитируемый пост)
нужен чуть более сложный разбор

xTr1m, да не нужен будет с _get_pgmptr()  разбор. (это я про совсем другое говорил.)
Просто у меня есть сильноее подозрение, что он работает точно также, извлекая из arg[0];
но вопрос сей подробно не изучал, так как
Цитата(volatile @  18.1.2013,  18:50 Найти цитируемый пост)
особо не пользовался, поэтому сказать за них ничо не могу.


Используйте ваш первый вариант. Имхо нормальный!
Единственно, теоретически, путь может быть длиной до 32К. 
И в этом случае и 2048 и тем более MAX_PATH обломаюцца.

Добавлено через 11 минут и 36 секунд
Кстати, на сверх длинных путях, обламываюцца многие программы, если вас это утешит.  smile 
ну или делайте с расчетом на 32К. 
PM MAIL   Вверх
Albor
Дата 22.1.2013, 08:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Можно (если очень осторожно) использовать GetCurrentDirectory() (внимательно читаем ремарку).
А это по максимальным путям, можно найти ещё кучу статей по решению проблем длинного пути. Но, надеюсь, что у xTr1m данной проблемы нет.
PM MAIL ICQ   Вверх
volatile
Дата 22.1.2013, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 4
Всего: 85



Цитата(Albor @  22.1.2013,  08:10 Найти цитируемый пост)
использовать GetCurrentDirectory() 

smile
вообще не из той оперы

Это сообщение отредактировал(а) volatile - 22.1.2013, 09:56
PM MAIL   Вверх
Albor
Дата 22.1.2013, 12:01 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



volatile, если, допустим, что моя программа не многопоточная и я ни где не устанавливаю текущую директорию,то почему 
Цитата(volatile @  22.1.2013,  08:47 Найти цитируемый пост)
вообще не из той оперы

user posted image

Это сообщение отредактировал(а) Albor - 23.1.2013, 08:01
PM MAIL ICQ   Вверх
Albor
Дата 3.2.2013, 09:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 589
Регистрация: 28.2.2009

Репутация: 7
Всего: 9



Решил всё же окончательно разобраться с данным вопросом. Итак, что мы имеем при запуске нашей программы? Я решил посмотреть в сторону  CreateProcess(): в неё передаётся (из того что нас интересует)
1. имя приложения и командная строка - данные параметры используются довольно хотрО, то есть мы можем и не передавать полный путь к исполняемому файлу - система сама будет искать файл по определённому алгоритму и, если найдёт, то запустит. Из этого следует то, что уже обсуждалось - через командную строку можно и не получить требуемое.
2. текущая директория - может передаваться, а может и нет,  смотря кто и как запускает процесс, то есть, вызовом GetCurrentDirectory() мы можем получить текущую директорию родительского процесса либо явно указываемую  при создании процесса, либо установленную вызовом SetCurrentDirectory() - опять-таки мы не получаем ни какой гарантии что текущая директория то что нам нужно.
Выходит, что входные параметры не дают 100 процентной информации для решения задачи, но... создатель процесса что-то ещё и делает - внутри функции путь к исполняемому файлу известен (если файл найден конечно), вот здесь, по моему предположению, и присваивается значение переменной _pgmptr, либо её UNICODE - версии _wpgmptr, которая позиционируется как полный путь и имя исполняемого файла
Теперь заглянем в русскую редакцию 2009г книги Рихтера "WINDIWS via c/c++", и посмотрим его мнение на счёт этой и некоторых других глобальных переменных
Цитата

...не рекомендуется использовать по соображениям безопасности, поскольку, использующий их код может быть запущен прежде, чем они будут инициализированы библиотекой С. В силу этих причин, лучше напрямую вызывать соответствующие функции Windows API.

Соответствующей функцией, по указанию этого же источника, является GetModuleFileName(). Выходит, что данная функция гарантированно даст нам правильный результат.
Остался вопрос с MAX_PATH. MSDN прямо указывает, что путь не должен превышать данного значения, но тут же делается оговорка для NTFS. Рихтер тоже однозначно не высказывается по этому вопросу - он говорит примерно то же самое и делает замечание, что размер, определённый в MAX_PATH можно обойти, вот только для чего и кому это нужно, для читателя остаётся загадкой. Для себя я сделал такой вывод, что если не хочешь проблем, то не нужно именовать файлы и каталоги своей программы так, чтобы они превышали MAX_PATH, а пользователю не следует пихать программу туда, от куда её будет тяжело достать (кстати, в некоторых статьях по решению проблемы длинных путей, Microsoft предлагает переименовать файлы и каталоги более короткими именами).

Это сообщение отредактировал(а) Albor - 3.2.2013, 09:31
PM MAIL ICQ   Вверх
HANDLE
Дата 9.4.2013, 14:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 25.6.2008

Репутация: нет
Всего: нет



Все можно сократить до безобразия, и сверхдлинные пути не помеха (32768 - предел), а MAX_PATH можно преодолеть путем перетаскивания файлов из папки в папку в пределах одного диска. 

Код

CString GetExePath()
{
        CString sExePath;
        GetModuleFileName(NULL, sExePath.GetBuffer(32768), 32768);
        sExePath.ReleaseBuffer(sExePath.ReverseFind('\\')+1);
        return sExePath;
}

PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.1204 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.