PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » PureBasic для Windows » API, получить папку из которой стартовала программа


API, получить папку из которой стартовала программа

Сообщений 1 страница 21 из 21

1

ноги темы выросли тут
Ссылка

со встроенной функцией понятно, интересует апи

GetCurrentDirectory_() про неё в разных источниках, перевод разных авторов, написано что возвращает именно папку экзешника
но тут смущает наличие
SetCurrentDirectory_(), непонятно зачем это нужно

GetFullPathName_() эта формирует полный путь из текущего пути и заданного имени файла, интересная функция
функция идеально подходит для работы с папками, файлами программы
а что скажет товарищь Smitis

вот две версии кода, они всегда одно выдают
где правда? как правильно получить эту папку?

Код:
Procedure myGetCurrentDirectory()
Protected pPath.s, n1, n2, *m1, *m2, n3, s.s

n1 = GetCurrentDirectory_(0, 0); возвращает необходимую длину строки с учётом стоп байта
*m1=AllocateMemory(n1*2); удваиваем под юникод
n2 = GetCurrentDirectory_(n1, *m1); читаем путь
s = PeekS(*m1); получаем путь без последней косой

;Debug ""+n1+" "+n2+" "+pPath

; извращение, но эффект тот же
; имя обязательно, достаточно одного символа от тёти Фени
n1=GetFullPathName_("Nj", 0, 0, 0)
*m2=AllocateMemory(n1*2); удваиваем под юникод
n2=GetFullPathName_("N", n1, *m2, @n3)
;PokeU(n3, 0); необязательно забивать стоп байт, можно указать сколько символов читать
; -1 это длина имени файла
pPath = PeekS(*m2, n2-1); получаем путь откуда запущен экзешник
;Debug ""+n1+" "+n2+" "+Hex(n3)+" "+pPath
MessageRequester("",""+n1+" "+n2+" "+Hex(n3)+" "+pPath+#CRLF$+s)
;ShowMemoryViewer(*m2, 111)


EndProcedure

0

2

newJS написал(а):

...
GetCurrentDirectory_() про неё в разных источниках, перевод разных авторов, написано что возвращает именно папку экзешника
но тут смущает наличие
SetCurrentDirectory_(), непонятно зачем это нужно
...

Открой свойства любого ярлыка в windows. Поле рабочая папка: это папка где в первую очередь ищется всё на что не указан полный путь. И вот её(рабочую паку) можно как получить по запросу, так и поменять.

0

3

newJS написал(а):

написано что возвращает именно папку экзешника

Функция возвращает текущую папку. Она задается при запуске приложения.

В настойках компилятора на вкладке "Компиляция/Запуск" можно задать "Текущий каталог". Попробуйте и посмотрите что вернет GetCurrentDirectory_().

0

4

В предыдущей теме дали классический нативный кроссплатформеный рабочий 100 процентный вариант, зачем создавать себе трудности? Из winapi подойдет функция, которую давал Петр на кибер форуме для извлечения параметров ком. строки, где первым идёт путь к исполняемому файлу

Код:
; https://www.cyberforum.ru/pure-basic/thread3028721.html#post16492165
Debug PeekS(GetCommandLine_())

Функция "GetCurrentDirectory" может вернуть отличное от пути расположения исполняемого файла, надо просто про неё забыть, не надеяться, что повезёт. Запусти прогу из батника, чтобы батник располагался в другой папке и в MessageRequester() выведи путь и убедишься, что он будет путем где лежит батник, а не прога, и прога в этом случае потеряет доступ к своим внешним файлам. Я на этом уже собаку съел, как вариант при запуске проги сделать текущим путь принудительно, используя нативную функцию GetPathPart(ProgramFilename()), передав путь функции установки текущей - "SetCurrentDirectory", тогда батник или ярлык не переназначат её, так как она будет задана уже после запуска.

Отредактировано AZJIO (22.04.2023 07:09:11)

0

5

AZJIO написал(а):

Из winapi подойдет функция, которую давал Петр на кибер форуме для извлечения параметров ком. строки, где первым идёт путь к исполняемому файлу

Не, не подойдёт. Там лишь то, что было передано через CreateProcess. А там можно любое имя программы подставить.
Имхо, самый правильный метод это GetModuleFileName.

Отредактировано Smitis (22.04.2023 23:21:13)

0

6

Smitis написал(а):

Не, не подойдёт. Там лишь то, что было передано через CreateProcess. А там можно любое имя программы подставить.

Если имя другое, то наверно другая программа запустится? Не?
Я лишь предложил, так как автор темы указал API в заголовке, то есть другое неприемлемо и флуд. Я не любитель переубеждать, биться об стену, это контрпродуктивно, да ещё наказуемо. Поэтому не разделяю, но на работе делать нечего было, и не вытерпел чтобы написать ))). Я за нативный GetPathPart(ProgramFilename()) и SetCurrentDirectory(GetPathPart(ProgramFilename())) на старте проги, если хочется не указывать пути в функциях по работе с файлами, типа RunProgram("file.exe") или Load...(#ID, "file") без указания полного пути.
Да я видел примеры с GetModuleFileName, возможно оно и используется в виндовом компиляторе для ProgramFilename(), а если это так, то зачем извращения?

0

7

AZJIO написал(а):

Если имя другое, то наверно другая программа запустится? Не?

Не. Запустится то что надо. А командная строка будет передана запущенному процессу "как есть" (это другой параметр CreateProcess), первый параметр командной строки принято трактовать как имя запускаемой программы, но что туда на самом деле запишет запускающая программа на совести программистов этой программы.

AZJIO написал(а):

и SetCurrentDirectory(GetPathPart(ProgramFilename())) на старте проги, если хочется не указывать пути в функциях по работе с файлами

Я вот пытаюсь вспомнить, диалоги открытия папки/файла меняют текущую папку или нет?

Имхо, надеяться на текущую папку никогда нельзя. Если нет какой-то особой необходимости, я лично никогда не использую относительные пути. А практически единственная необходимость, с которой я сталкивался, это консольные утилиты, работа которых как раз и подразумевает работу из текущей папки. И то, лучше эту папку сразу определить и далее использовать полные пути.

Отредактировано Smitis (23.04.2023 21:40:44)

0

8

AZJIO написал(а):

а если это так, то зачем извращения?

Я вот тоже не понимаю.

0

9

newJS написал(а):

GetFullPathName_() эта формирует полный путь из текущего пути и заданного имени файла, интересная функция
функция идеально подходит для работы с папками, файлами программы
а что скажет товарищь Smitis

В другой теме ответил.

0

10

Пара ссылок
https://www.gunsmoker.ru/2015/01/never- … paths.html
https://www.transl-gunsmoker.ru/2015/01 … ctory.html

0

11

ну ещё одна попытка
со встроенной понятно

но я хочу знать какая айпишная функция возвращает то что возвращает встроенная
Smitis за ссылки спасибо, скопировал, потом почитаю, может там и есть ответ

AZJIO ну яё непонятно
хочу знать какая айпишная функция возвращает то что возвращает встроенная
почему нельзя?

0

12

В асм сохранить и все понятно будет. Я опять на работе

0

13

newJS написал(а):

хочу знать какая айпишная функция возвращает то что возвращает встроенная
почему нельзя?

GetModuleFileName

AZJIO написал(а):

В асм сохранить и все понятно будет. Я опять на работе

Функция библиотечная, в асме будет только её вызов.

0

14

До кучи вот ещё одна ссылка того же автора
https://www.transl-gunsmoker.ru/2011/07 … ogram.html

0

15

Smitis написал(а):

Не. Запустится то что надо. А командная строка будет передана запущенному процессу "как есть" (это другой параметр CreateProcess), первый параметр командной строки принято трактовать как имя запускаемой программы, но что туда на самом деле запишет запускающая программа на совести программистов этой программы.

Посмотрел ещё раз функцию, там есть указывается приложение (программа) и ком-строка, при этом ком-строка (параметр lpCommandLine) не содержит приложение (программу), а содержит только ключи передаваемые приложению в параметре lpApplicationName. Внимание вопрос, каким образом может быть запущено одно приложение, а ком-строка будет иметь другое приложение? Ком-строка получаемая WinAPI функцией является lpApplicationName + lpCommandLine. Как туда может затесаться третье и для чего разработчикам добавлять в структуру бесполезное поле для ложного имени, чтобы обмануть пользователя. Я посмотрел примеры на AutoIt3 и функцию, которая напрямую вызывает CreateProcess и передаваемые параметры, я не нашёл места, куда будет вставлено ложное имя, также как и в описании CreateProcess нет поля для ложного имени.
Если предположение что в lpCommandLine первым параметром будет вставлено ложное имя, тогда мы получим это как параметр, а не как программу, то есть:
"путь_к_проге" ложное_имя прочие_параметры
то есть путь к проге все равно будет настоящим, а ложное имя как параметр передаваемый настоящей программе.

newJS

Код:
; hModule - Дескриптор модуля, к которому требуется найти путь.
; Если этот параметр - 0, то функция GetModuleFileName извлекает путь к исполняемому файлу текущего процесса.

Global Path.s = Space(#MAX_PATH)
GetModuleFileName_(0, @Path, #MAX_PATH)
Debug Path
PathRemoveFileSpec_(@Path)
Debug Path
Smitis написал(а):

Я вот пытаюсь вспомнить, диалоги открытия папки/файла меняют текущую папку или нет?

Возможно меняют, но неизвестно, есть ли в программе диалоги, а если есть, то загрузка ресурсов может осуществлена на старте программы, а потом уже не важно что будет поменяно.

Тесты этого не подтверждают. В AutoIt3 это был макрос @WorkingDir и он меняется если в диалоге был произведён выбор, возможно это отличается от GetCurrentDirectory.

Код:
Debug GetCurrentDirectory()
Debug OpenFileRequester("Открыть файл", GetCurrentDirectory(), "Все (*.*)", 0)
Debug PathRequester("Открыть", GetCurrentDirectory())
Debug GetCurrentDirectory()

Отредактировано AZJIO (24.04.2023 19:45:49)

0

16

AZJIO
Всё-таки прочитайте по ссылке, что я дал выше. Там разжёвано.

AZJIO написал(а):

Возможно меняют, но неизвестно, есть ли в программе диалоги, а если есть, то загрузка ресурсов может осуществлена на старте программы, а потом уже не важно что будет поменяно.

Я так понимаю, Вы усиленно ищете оправдание "всё равно буду использовать относительные пути и текущую папку, чтобы там мне не говорили"? Да ради бога. :)
Лично для себя я эту проблему давно решил и закрыл.

0

17

Кстати, с текущей папкой есть ещё один прикол, когда путь превосходит MAX_PATH
Желающие могут поэкспериментировать.
Единственное, я не знаю, как это работает начиная с Windows 10, если включена поддержка очень длинных путей.  :question:

0

18

Smitis написал(а):

Вы усиленно ищете оправдание "всё равно буду использовать относительные пути и текущую папку

Нет, я категорически это не использую, но если автор просит и находит в этом смысл, то я выдаю расклад как я вижу без фетиша.

Smitis написал(а):

начиная с Windows 10, если включена поддержка очень длинных путей

тоже слышал, но пока не сталкивался чтобы функция с MAX_PATH столкнулась с проблемой.
Погуглил, там, по крайней мере предупредит о проблеме длинных путей.

Отредактировано AZJIO (24.04.2023 21:01:32)

0

19

Smitis написал(а):

Всё-таки прочитайте по ссылке, что я дал выше. Там разжёвано.

Хотелось бы верить, но ожидая от GetCommandLine_() только параметры я получаю первым исполняемый файл. Так что мне верить чужим словам и не доверять своим глазам?

Это означает, что если кто-то запустит вашу программу с такими параметрами к функции CreateProcess:

lpApplicationName  =  "C:\Path\To\Program.exe"
lpCommandLine  =  "slithy toves"

то когда ваша программа вызовет функцию GetCommandLine, она просто вернёт строку "slithy toves", которая не окажет вашей программе помощи по определению своего имени и местоположения.

не хотел конечно я 3 простыни читать, но попробовал искать в статьях "CreateProcess".

Нагуглил в MSDN, но указывается что система вернёт полный путь взамен только имени файла переданного пользователем. Так что, это не подмена а исправление "косяка" пользователя.

Примечание.   Имя исполняемого файла в командной строке, которую операционная система предоставляет процессу, не обязательно совпадает с именем в командной строке, которую вызывающий процесс дает функции CreateProcess . Операционная система может добавить полный путь к имени исполняемого файла, который указан без полного пути.

Это по сути отработает PathFindOnPath, чтобы дать путь на точную найденную запущенную копию, так как один и тот же файл может находится в разных системных папках, а какой из них будет запущен система подставляет более точно и конкретно.

Отредактировано AZJIO (24.04.2023 21:24:16)

0

20

AZJIO написал(а):

Так что мне верить чужим словам и не доверять своим глазам?

Это как с текущей папкой, может совпасть и даже скорее всего совпадёт, так как нормальные программисты скорее всего сделают правильно. Но может и не совпасть.

AZJIO написал(а):

Это по сути отработает PathFindOnPath, чтобы дать путь на точную найденную запущенную копию, так как один и тот же файл может находится в разных системных папках, а какой из них будет запущен система подставляет более точно и конкретно.

Вы не поняли. Там ДВА параметра. Первый, это путь к программе (lpApplicationName), он может быть и относительным, не содержать путь, так что в этом плане верно. И вот если этот параметр задан, во втором (lpCommandLine) может быть что угодно и на запуск это не повлияет, а вот в командную строку попадёт.

0

21

AZJIO написал(а):

но если автор просит и находит в этом смысл, то я выдаю расклад как я вижу без фетиша.

Попробую подвести итог этой продолжительной дискуссии, слава богу не перешедшей к переходу на личности и обмену любезностями, как это обычно случается в телеге:
Задача: использовать файлы в папке программы.
- Выяснили, что текущая папка программы предмет ненадёжный, может указывать куда угодно, кроме папки с программой. Хотя может и совпасть.
- Есть надёжные способы определить папку программы как встроенными средствами PB (ProgramName) так и средствами WinApi (GetModuleFileName).
- Относительные пути привязываются к текущей папке, что, как выяснили, ненадёжно. А использовать полные пути к файлам не сложно и даже не слишком накладно и при этом надёжно.
Вроде всё.
А дальше начинается какой-то экстремальный спорт по программированию (или специальная олимпиада, кому как нравится) - а давайте зафигачим по другому совершенно левым способом, а вдруг получится, а потом с замиранием сердца будем ждать, гикнется или нет, прибегут возмущённые пользователи или нет... Наверное, это в целом интересно, но в данном конкретном случае как-то бессмысленно.

0


Вы здесь » PureBasic - форум » PureBasic для Windows » API, получить папку из которой стартовала программа