Что нового

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

joiner

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

WSWR

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

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

While 1
Sleep(20)
WEnd

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

joiner

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

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 473
Репутация
2 403
Код:
#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
Репутация
361
Александр
Так в чем проблема-то? Я думал, нужно получить имя файла, и те старые скрипты, действительно, в папке "Мои документы" не работали. Имя файла знаем, знаем, что он в папке "Мои документы", а где находится сама эта папка, более чем вероятно, можно получить из реестра и т.д.
 
Автор
joiner

joiner

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

на
Код:
[CLASS:Progman]

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

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

CreatoR

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

Код:
$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 319
AZJIO,
Второй вариант CreatoR`a (через буфер обмена) у меня работает на Win 7 как часы, если вместо "SysListView321" поставить пустое место ("").
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8 473
Репутация
2 403
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 752
Репутация
1 149
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 473
Репутация
2 403
AZJIO [?]
Поменял имя функции и вместо массива возвращает только путь...
А ссылку на оригинал можно? нашёл.
Мне просто интересно какие свойства нужно использовать чтобы получить имена выделнных файлов.
 
Автор
joiner

joiner

Модератор
Локальный модератор
Сообщения
3 353
Репутация
579
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 353
Репутация
579
madmasles [?]
если вместо "SysListView321" поставить пустое место ("").
у меня не сработало.
Код:
ClassnameNN:	DirectUIHWND3

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

joiner

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

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

AZJIO

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

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

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