Что нового

[Файловая система] Получить путь к запускаемому файлу

joiner

Модератор
Локальный модератор
Сообщения
3,409
Репутация
597
нужно получить путь к файлу. я использовал
Код:
ControlGetText
для получения пути из адресной строки, но это не срабатывает, если файл находится в папке "мои документы". так как в адресной строке отображается не путь а название "мои документы" :smile:
на форуме нашел тему http://autoit-script.ru/index.php?topic=2381.0
но представленные скрипты имеют тот же недостаток.
плюс к этому скрипт от madmasles выдает ошибку если его применять к объектам в папке мои документы ( как я писал выше).
есть ли другой способ получения пути не используя адресную строку?
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
362
Если речь идет о получении пути до выделенного файла, то что покажет такой код?

Код:
HotKeySet("+{1}",'_Put') ;Shift+1

While 1
Sleep(20)
WEnd

Func _Put()
Send("{F2}")
$text = WinGetText("[ACTIVE]", "")
MsgBox(0, "", $text)
Endfunc
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,409
Репутация
597
WSWR
попробуй запустить этот скрипт в папке "мои документы". зайди в эту папку через значок на рабочем столе
вот что получается
"Мои документы
Мои документы
FolderView
AutoIt v3 Script"
а ведь настоящий путь в эту папку - C:\Documents and Settings\user\Мои документы\
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,665
Репутация
2,463
Код:
#include <Array.au3>

$aSelected_Info = _ExplorerGetSelectedItems("[CLASS:CabinetWClass]")
If @error Then Exit MsgBox(48, "Error", "There is no selected items." & @LF & @LF & "OK ==> EXIT")

_ArrayDisplay($aSelected_Info, "_ExplorerGetSelectedItems") 

;[0][0] = Total items count
;[N][0] = Selected element Index
;[N][1] = Selected element is Directory
;[N][2] = Selected element string (full path to the file/dir)
Func _ExplorerGetSelectedItems($sCabinetWClass="[CLASS:CabinetWClass]")
	Local $aRetInfo[1][1]
	Local $aIndexes, $iIndex, $iCount, $sSelected, $sSelected_Path
	Local $hSearch, $sCurrentFile
	
	$sSelected_Path = _GetWindowsExplorerPath(WinGetHandle($sCabinetWClass))
	$sSelected_Path = StringRegExpReplace($sSelected_Path, "\\+$", "")
	$aIndexes = StringSplit(ControlListView($sCabinetWClass, "", "SysListView321", "GetSelected", 1), "|")
	
	If $aIndexes[1] = "" Then
		Return SetError(1, 0, 0)
	EndIf
	
	Dim $aRetInfo[$aIndexes[0]+1][3]
	
	For $i = 1 To $aIndexes[0]
		$sSelected = ControlListView($sCabinetWClass, "", "SysListView321", "GetText", $aIndexes[$i])
		$sCurrentFile = $sSelected_Path & "\" & $sSelected
		
		If Not FileExists($sCurrentFile) Then ;Search the extension for file...
			$hSearch = FileFindFirstFile($sCurrentFile & ".*")
			
			If $hSearch <> -1 Then
				$sCurrentFile = $sSelected_Path & "\" & FileFindNextFile($hSearch)
				FileClose($hSearch)
			EndIf
		EndIf
		
		$aRetInfo[0][0] += 1
		$aRetInfo[$aRetInfo[0][0]][0] = $aIndexes[$i] ;Index
		$aRetInfo[$aRetInfo[0][0]][1] = Number(StringInStr(FileGetAttrib($sCurrentFile), "D") > 0) ;Is Directory
		$aRetInfo[$aRetInfo[0][0]][2] = $sCurrentFile ;Selected file / dir
	Next
	
	If $aRetInfo[0][0] = 0 Then
		Return SetError(2, 0, 0)
	EndIf
	
	ReDim $aRetInfo[$aRetInfo[0][0]+1][3]
	Return $aRetInfo
EndFunc

; ==================================================================================================
; Func _GetWindowsExplorerPath($hWnd)
;
; Function to get the path currently being explored by a Windows Explorer window
;
; $hWnd = Handle to the Windows Explorer window
;
; Returns:
;   Success: String - Path being explored by this window
;   Failure: "" empty string, with @error set:
;      @error = 1 = This is not a valid explorer window
;      @error = 2 = DLL call error, use _WinAPI_GetLastError()
;
; Author: WideBoyDixon
; ==================================================================================================
Func _GetWindowsExplorerPath($hWnd)
    Local $pv, $pidl, $return = "", $ret, $hMem, $pid, $folderPath = DllStructCreate("char[260]"), $className
    Local $bPIDL = False
    Local Const $CWM_GETPATH = 0x400 + 12;

    ; Check the classname of the window first
    $className = DllCall("user32.dll", "int", "GetClassName", "hwnd", $hWnd, "str", "", "int", 4096)
    If @error Then Return SetError(2, 0, "")
    If ($className[2] <> "ExploreWClass" And $className[2] <> "CabinetWClass") Then Return SetError(1, 0, "")
    
    ; Retrieve the process ID for our process
    $pid = DllCall("kernel32.dll", "int", "GetCurrentProcessId")
    If @error Then Return SetError(2, 0, "")

    ; Send the CWM_GETPATH message to the window
    $hMem = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $CWM_GETPATH, "wparam", $pid[0], "lparam", 0) 
    If @error Then Return SetError(2, 0, "")
    If $hMem[0] = 0 Then Return SetError(1, 0, "")
    
    ; Lock the shared memory
    $pv = DllCall("shell32.dll", "ptr", "SHLockShared", "uint", $hMem[0], "uint", $pid[0])
    If @error Then Return SetError(2, 0, "")
    If $pv[0] Then
        $pidl = DllCall("shell32.dll", "ptr", "ILClone", "uint", $pv[0]) ; Clone the PIDL
        If @error Then Return SetError(2, 0, "")
        $bPIDL = True
        DllCall("shell32.dll", "int", "SHUnlockShared", "uint", $pv) ; Unlock the shared memory
    EndIf
    DllCall("shell32.dll", "int", "SHFreeShared", "uint", $hMem, "uint", $pid) ; Free the shared memory
    
    If $bPIDL Then
        ; Retrieve the path from the PIDL
        $ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", "ptr", $pidl[0], "ptr", DllStructGetPtr($folderPath))
        If (@error = 0) And ($ret[0] <> 0) Then $return = DllStructGetData($folderPath, 1) ; Retrieve the value
        DllCall("shell32.dll", "none", "ILFree", "ptr", $pidl[0]) ; Free up the PIDL that we cloned
        Return SetError(0, 0, $return) ; Success
    EndIf
    
    Return SetError(2, 0, "") ; Failed a WinAPI call
EndFunc



Добавлено:
Сообщение автоматически объединено:

Ну или через буфер обмена:

Код:
#include <Array.au3>

$aSelected = _GetSelectedItems()
If @error Then Exit MsgBox(48, "Error", "There is no selected items." & @LF & @LF & "OK ==> EXIT")

_ArrayDisplay($aSelected, "_GetSelectedItems") 

Func _GetSelectedItems($sCabinetWClass = "[CLASS:CabinetWClass]")
	Local $sOrigin_ClipGet = ClipGet()
	ClipPut("")
	
	If ControlSend($sCabinetWClass, "", "SysListView321", "^{INSERT}") = 0 Then
		Return SetError(1, 0, ClipPut($sOrigin_ClipGet))
	EndIf
	
	Local $sClipGet = ClipGet(), $iTimer = TimerInit()
	
	While $sClipGet == "" And TimerDiff($iTimer) < 5000 ;wait 5 seconds and continue
		Sleep(10)
		$sClipGet = ClipGet()
	WEnd
	
	ClipPut($sOrigin_ClipGet)
	
	If $sClipGet == "" Then Return SetError(2, 0, 0)
	Return StringSplit($sClipGet, @LF)
EndFunc
 

WSWR

AutoIT Гуру
Сообщения
941
Репутация
362
Александр
Так в чем проблема-то? Я думал, нужно получить имя файла, и те старые скрипты, действительно, в папке "Мои документы" не работали. Имя файла знаем, знаем, что он в папке "Мои документы", а где находится сама эта папка, более чем вероятно, можно получить из реестра и т.д.
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,409
Репутация
597
второй пример от CreatoR изменил (смена класса)
Код:
[CLASS:CabinetWClass]

на
Код:
[CLASS:Progman]

и работает для рабочего стола

CreatoR, как изменить первый пример, чтобы он работал для рабочего стола?
какой из двух твоих примеров надежнее?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,665
Репутация
2,463
Александр [?]
как изменить первый пример, чтобы он работал для рабочего стола?
У рабочего стола нет адресной строки, поэтому там всё проще. Можно сделать поддержку р.стола:

Код:
$aSelected_Info = _ExplorerGetSelectedItems("[CLASS:Progman]")

Func _ExplorerGetSelectedItems($sCabinetWClass="[CLASS:CabinetWClass]")
	...
    
	$sSelected_Path = _GetWindowsExplorerPath(WinGetHandle($sCabinetWClass))
	If StringInStr($sCabinetWClass, "Progman") Then $sSelected_Path = @DesktopDir
	
	...
EndFunc



какой из двух твоих примеров надежнее?
Мне кажется второй, т.к не используется адресная строка. Но минус в том, что используется буфер обмена :smile:
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,320
AZJIO,
Второй вариант CreatoR`a (через буфер обмена) у меня работает на Win 7 как часы, если вместо "SysListView321" поставить пустое место ("").
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,665
Репутация
2,463
AZJIO [?]
Мне нужно было получить только адреса открытых папок для SaveFolders, поэтому через буфер не подойдёт
Можно попробовать вот так если я правильно понял:

Код:
#include <Misc.au3>
#include <File.au3>

$sTmp_File = _TempFile()
$sTmp_FileName = StringRegExpReplace($sTmp_File, "^.*\\", "")
_FileCreate($sTmp_File)
_ClipPutFile($sTmp_File)
Sleep(500)
$sText = ControlGetText("[CLASS:#32770]", "FolderView", "Edit1")
ControlSetText("[CLASS:#32770]", "FolderView", "Edit1", "*")
ControlSend("[CLASS:#32770]", "FolderView", "Edit1", "{ENTER}")

WinActivate("[CLASS:#32770]", "FolderView")
WinActivate("[CLASS:#32770]", "FolderView")
WinWaitActive("[CLASS:#32770]", "FolderView")
ControlSend("[CLASS:#32770]", "FolderView", "SysListView321", "+{INS}")
Sleep(200)
ControlSend("[CLASS:#32770]", "FolderView", "SysListView321", "^{INS}")
Sleep(200)
$sPath = ClipGet()
$sPath_FileName = StringRegExpReplace($sPath, "^.*\\", "")
ControlSetText("[CLASS:#32770]", "FolderView", "Edit1", $sText)
If $sTmp_FileName = $sPath_FileName Then FileDelete($sPath)
$sPath = StringRegExpReplace($sPath, "\\[^\\]*$", "")
FileDelete($sTmp_File)

MsgBox(64, 'Title', $sPath)


Достаёт путь с диалога выбора файла.
 

AZJIO

Меценат
Меценат
Сообщения
2,757
Репутация
1,151
CreatoR
Я как раз только что разобрался в примерах на офсайте

Вот у меня работает на WinXP и Win7. Поменял имя функции и вместо массива возвращает только путь...
Код:
#include <Array.au3>

$aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
ReDim $aWinList[$aWinList[0][0]+1][3]

For $i = 1 To UBound($aWinList) - 1
	$aWinList[$i][2]=_GetWindowsExplorerPath($aWinList[$i][1])
Next
_ArrayDisplay($aWinList, "aWinList")

; ===================================================================================================================
; Name...........: _GetWindowsExplorerPath
; Description....: Функция для получения пути в Эксплорере
; Syntax.........: _GetWindowsExplorerPath($hWnd)
; Parameters.....: $hWnd - Дескриптор окна Эксплорера
; AutoIt Version.: 3.3.6.1
; Return values..: Успешно  -   Путь
;                               Путь, который выбран в дереве или адресной строке
;                  Неудачно  -  0
;                               Устанавливает @error не равным нулю.
;                               @error = 1 - $hwnd не является дескриптором окна
;                               @error = 2 - $hwnd не является дескриптором эксплорера
;                               @error = 3 - "Shell.Application" объект не может быть создан
;                               @error = 4 - "$oShellApp.Windows()" объект не может быть создан
; Author.........: Ascend4nt, KaFu, klaus.s
; (урезал функцию AZJIO, оригинал здесь http://www.autoitscript.com/forum/topic/89833-windows-explorer-current-folder/page__view__findpost__p__875837)
; ===================================================================================================================

Func _GetWindowsExplorerPath($hWnd)
    If Not IsHWnd($hWnd) Then Return SetError(1)
    Local $aWinList = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
    While 1
        For $i = 1 To UBound($aWinList) - 1
            If $hWnd = $aWinList[$i][1] Then ExitLoop 2
        Next
        Return SetError(2)
    WEnd
    Local $oShellApp = ObjCreate("Shell.Application")
    If Not IsObj($oShellApp) Then Return SetError(3)
    Local $oShellApp_Windows = $oShellApp.Windows()
    If Not IsObj($oShellApp_Windows) Then Return SetError(4)
    For $oShellApp_Inst In $oShellApp_Windows
        If $oShellApp_Inst.hwnd = $hWnd Then ExitLoop
    Next
    Local $iShellApp_Inst_SelectedItems_Count = $oShellApp_Inst.Document.SelectedItems.Count
    Local $sShellApp_Inst_LocationURL = $oShellApp_Inst.LocationURL
    Local $aRet = DllCall('shlwapi.dll', 'long', 'PathCreateFromUrlW', 'wstr', $sShellApp_Inst_LocationURL, 'wstr', '', 'dword*', 65534, 'dword', 0)
    If Not @error And $aRet[0] = 0 Then $sShellApp_Inst_LocationURL = $aRet[2]
    $oShellApp = 0
    $oShellApp_Windows = 0
    $oShellApp_Inst = 0
    Return $sShellApp_Inst_LocationURL
EndFunc   ;==>_GetWindowsExplorerPath
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,665
Репутация
2,463
AZJIO [?]
Поменял имя функции и вместо массива возвращает только путь...
А ссылку на оригинал можно? нашёл.
Мне просто интересно какие свойства нужно использовать чтобы получить имена выделнных файлов.
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,409
Репутация
597
AZJIO [?]
Мне нужно было получить только адреса открытых папок для SaveFolders
мне тоже нужны были адреса. имя файла . в принципе, мне не нужно было. в итоге у меня получилась такая функция
Код:
#include <WinAPI.au3>
_Path()

Func _Path($sCabinetWClass = "[CLASS:CabinetWClass]")
	Local $sOrigin_ClipGet = ClipGet()
	ClipPut("")
	If ControlSend($sCabinetWClass, "", "SysListView321", "^{INSERT}") = 0 Then
		Return SetError(1, 0, ClipPut($sOrigin_ClipGet))
	EndIf
	Local $sClipGet = ClipGet(), $iTimer = TimerInit(), $sRezult
	While $sClipGet == "" And TimerDiff($iTimer) < 5000
		Sleep(10)
		$sClipGet = ClipGet() ; полный путь к выделенному файлу
		MsgBox(0,"",$sClipGet)
	WEnd
	$sPath = StringLeft($sClipGet, StringInStr($sClipGet, "\", 2, -1)) ;получил путь в папку без названия файла

		MsgBox(0, "", $sPath)

EndFunc

сбоя не было. работает только на ХР. пробовал подогнать под вынь 7. не получилось. попробую сделать так
madmasles [?]
если вместо "SysListView321" поставить пустое место ("").
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,409
Репутация
597
madmasles [?]
если вместо "SysListView321" поставить пустое место ("").
у меня не сработало.
Код:
ClassnameNN:	DirectUIHWND3

это единственно чем отличается определение папки в семерке от ХР.
пустое место или подстановка значения DirectUIHWND3 не дает результата.
слегка сломал мозги. что нужно изменить?
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3,409
Репутация
597
AZJIO
просто хочется узнать реализацию в данном варианте решения.
да и честно говоря я пока не понял как получить результат твоей функции ( то есть путь в папку) для обработки дальше. мало знаний.
все, понял. просто видимо затуп случился :smile:
Код:
$var = WinList("[REGEXPCLASS:(Explore|Cabinet)WClass]")
$sPath =_GetWindowsExplorerPath($var[1][1]) & "\"

что еще хотел спросить у тебя. почему свел две функции из оригинала в одну?
 

AZJIO

Меценат
Меценат
Сообщения
2,757
Репутация
1,151
Александр
я пока не понял как получить результат
Там же ясно, что функция требует дескриптор окна (хэндл), который можно получить используя WinGetHandle. В параметрах WinGetHandle можно указать "[ACTIVE]" - для активного окна или имя.

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

Обновил функцию вставив русское описание
 
Верх