Что нового

[Процессы] Как отследить не занят ли файл другим процессом

Rjevsky

Новичок
Сообщения
102
Репутация
4
Для чего это мне нужно: Есть в сети расшаренная папка, в которую люди ложат файлы. Ftp клиент на autoit сканит эту папку каждые 10 секунд и при появлении новых файлов отправляет на сервер, при этом исходные файлы после успешной отправки удаляются.

Хочется научить клиента не обрабатывать следующие файлы:
-файл ещё копируется в папку
-если какойто нехороший человек решил файл(к примеру EXCEL или Word) открыть прямо в расшаренной папке.

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

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,320
Rjevsky,
Попробуйте так.
Код:
#include <WinAPI.au3>

; Временный, точно занятый файл из папки Temp
$sFile = @TempDir & '\~DF2C9D.tmp'
$hFile = _WinAPI_CreateFile($sFile, 2)
MsgBox(64, 'Info', _WinAPI_GetLastError() & @LF & _WinAPI_GetLastErrorMessage())
If $hFile Then _WinAPI_CloseHandle($hFile)


Или, как ниже предложил Yashied.
Код:
#Include <WinAPIEx.au3>

; Временный, точно занятый файл из папки Temp
$sFile = @TempDir & '\~DF2C9D.tmp'
;1 - занят, 0 - нет
MsgBox(64, 'Info', _WinAPI_FileInUse($sFile))
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
_WinAPI_FileInUse()
 

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
Yashied(Вопрос ко всем)
Как можно узнать PID процесса который использует файл?
 

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
VladUs
Я думаю Autoit способен узнать PID, без стороний программы... :smile:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Ganibal95 сказал(а):
Как можно узнать PID процесса который использует файл?

Код:
#Include <APIConstants.au3>
#Include <WinAPIEx.au3>

Global $aAdjust, $Result = False, $File = @DesktopDir & '\Test.txt'

FileOpen($File)

$Path = _WinAPI_PathSearchAndQualify($File, 1)
If @error Then
	MsgBox(16, '', $File & ' not found.')
	Exit
EndIf

If Not _WinAPI_FileInUse($Path) Then
	MsgBox(64, '', $Path & ' not used.')
	Exit
EndIf

$hToken = _WinAPI_OpenProcessToken(BitOR($TOKEN_ADJUST_PRIVILEGES, $TOKEN_QUERY))
If (@error) Or (Not _WinAPI_AdjustTokenPrivileges($hToken, $SE_DEBUG_NAME, $SE_PRIVILEGE_ENABLED, $aAdjust)) Then
	MsgBox(16, '', 'You do not have administrator rights.')
	Exit
EndIf

$tHandle = DllStructCreate('ushort;ushort;byte;byte;ushort;ptr;ulong')
$Size = DllStructGetSize($tHandle)
$tSHI = DllStructCreate('ulong;ptr[1048576]')
$pSHI = DllStructGetPtr($tSHI)
$Ret = DllCall('ntdll.dll', 'uint', 'ZwQuerySystemInformation', 'uint', 16, 'ptr', DllStructGetPtr($tSHI), 'ulong', DllStructGetSize($tSHI), 'ulong*', 0)
If (@error) Or ($Ret[0]) Then
	Exit
EndIf
$hAutoIt = _WinAPI_GetCurrentProcess()
For $i = DllStructGetData($tSHI, 1) To 1 Step -1
	$tHandle = DllStructCreate('ushort;ushort;byte;byte;ushort;ptr;ulong', $pSHI + 4 + ($i - 1) * $Size)
	Switch DllStructGetData($tHandle, 3)
		Case 28
			Switch DllStructGetData($tHandle, 7)
				Case 0x00100000, 0x00120189, 0x0012019F
					ContinueLoop
				Case Else

			EndSwitch
			$hProcess = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'dword', $PROCESS_DUP_HANDLE, 'int', 0, 'dword', DllStructGetData($tHandle, 1))
			If (Not @error) And ($hProcess[0]) Then
				$hObject = _WinAPI_DuplicateHandle($hProcess[0], DllStructGetData($tHandle, 5), $hAutoIt)
				If $hObject Then
					If StringInStr(_WinAPI_GetFinalPathNameByHandle($hObject), $Path) Then
						$Result = MsgBox(64, '', 'File: ' & $Path & @CR & 'Handle: ' & Ptr(DllStructGetData($tHandle, 5)) & @CR & 'PID: ' & DllStructGetData($tHandle, 1) & @CR & 'Path: ' & FileGetLongName(_WinAPI_GetProcessFileName(DllStructGetData($tHandle, 1))))
					EndIf
					_WinAPI_CloseHandle($hObject)
				EndIf
				_WinAPI_CloseHandle($hProcess[0])
			EndIf
		Case Else

	EndSwitch
Next

_WinAPI_AdjustTokenPrivileges($hToken, $aAdjust, 0, $aAdjust)
_WinAPI_CloseHandle($hToken)

If Not $Result Then
	MsgBox(16, '', 'Process not found.')
EndIf
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,320
Yashied,
Этот код только для Win 7? У меня в XP не работает.
 

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
Yashied и в правду не работает, ошибка:
Код:
E:\Documents and Settings\?????????????\??????? ????\AutoIt v3 Script (22).au3 (33) : ==> Incorrect number of parameters in function call.:
If (@error) Or (Not _WinAPI_AdjustTokenPrivileges($hToken, $SE_DEBUG_NAME, $SE_PRIVILEGE_ENABLED, $aAdjust)) Then
If (@error) Or (Not ^ ERROR

я это стер, потом еще ошибка:
Код:
E:\Documents and Settings\?????????????\??????? ????\AutoIt v3 Script (22).au3 (69) : ==> Incorrect number of parameters in function call.:
_WinAPI_AdjustTokenPrivileges($hToken, $aAdjust, 0, $aAdjust)
^ ERROR
 

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
madmasles
И в правду у меня старая версия...


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

Протестировал
Выдает: Process not found.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Ребята, вы, как кодеры, уже давно должны работать в Windows 7... Вот для XP:

Код:
#Include <APIConstants.au3>
#Include <WinAPIEx.au3>

Global $aAdjust, $Result = False, $File = @ScriptDir & '\Test.txt'

FileOpen($File)

$Path = _WinAPI_PathSearchAndQualify($File, 1)
If @error Then
	MsgBox(16, '', $File & ' not found.')
	Exit
EndIf

If Not _WinAPI_FileInUse($Path) Then
	MsgBox(64, '', $Path & ' not used.')
	Exit
EndIf

$hToken = _WinAPI_OpenProcessToken(BitOR($TOKEN_ADJUST_PRIVILEGES, $TOKEN_QUERY))
If (@error) Or (Not _WinAPI_AdjustTokenPrivileges($hToken, $SE_DEBUG_NAME, $SE_PRIVILEGE_ENABLED, $aAdjust)) Then
	MsgBox(16, '', 'You do not have administrator rights.')
	Exit
EndIf

$tHandle = DllStructCreate('ushort;ushort;byte;byte;ushort;ptr;ulong')
$Size = DllStructGetSize($tHandle)
$tSHI = DllStructCreate('ulong;ptr[1048576]')
$pSHI = DllStructGetPtr($tSHI)
$tFNI = DllStructCreate('ulong;wchar[4096]')
$tIOSB = DllStructCreate('ptr;ulong_ptr')
$Ret = DllCall('ntdll.dll', 'uint', 'ZwQuerySystemInformation', 'uint', 16, 'ptr', DllStructGetPtr($tSHI), 'ulong', DllStructGetSize($tSHI), 'ulong*', 0)
If (@error) Or ($Ret[0]) Then
	Exit
EndIf
$hAutoIt = _WinAPI_GetCurrentProcess()
For $i = DllStructGetData($tSHI, 1) To 1 Step -1
	$tHandle = DllStructCreate('ushort;ushort;byte;byte;ushort;ptr;ulong', $pSHI + 4 + ($i - 1) * $Size)
	Switch DllStructGetData($tHandle, 3)
		Case 28
			Switch DllStructGetData($tHandle, 7)
				Case 0x00100000, 0x00120189, 0x0012019F
					ContinueLoop
				Case Else

			EndSwitch
			$hProcess = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'dword', $PROCESS_DUP_HANDLE, 'int', 0, 'dword', DllStructGetData($tHandle, 1))
			If (Not @error) And ($hProcess[0]) Then
				$hObject = _WinAPI_DuplicateHandle($hProcess[0], DllStructGetData($tHandle, 5), $hAutoIt)
				If $hObject Then
					$Ret = DllCall('ntdll.dll', 'uint', 'ZwQueryInformationFile', 'ptr', $hObject, 'ptr', DllStructGetPtr($tIOSB), 'ptr', DllStructGetPtr($tFNI), 'ulong', DllStructGetSize($tFNI), 'uint', 9)
					If (Not @error) And (Not $Ret[0]) And (Not StringCompare(DllStructGetData(DllStructCreate('wchar[' & (DllStructGetData($tFNI, 1) / 2) & ']', DllStructGetPtr($tFNI, 2)), 1), StringTrimLeft($Path, 2))) Then
						$Result = MsgBox(64, '', 'File: ' & $Path & @CR & 'Handle: ' & Ptr(DllStructGetData($tHandle, 5)) & @CR & 'PID: ' & DllStructGetData($tHandle, 1) & @CR & 'Path: ' & FileGetLongName(_WinAPI_GetProcessFileName(DllStructGetData($tHandle, 1))))
					EndIf
;					If StringInStr(_WinAPI_GetFinalPathNameByHandle($hObject), $Path) Then
;						$Result = MsgBox(64, '', 'File: ' & $Path & @CR & 'Handle: ' & Ptr(DllStructGetData($tHandle, 5)) & @CR & 'PID: ' & DllStructGetData($tHandle, 1) & @CR & 'Path: ' & FileGetLongName(_WinAPI_GetProcessFileName(DllStructGetData($tHandle, 1))))
;					EndIf
					_WinAPI_CloseHandle($hObject)
				EndIf
				_WinAPI_CloseHandle($hProcess[0])
			EndIf
		Case Else

	EndSwitch
Next

_WinAPI_AdjustTokenPrivileges($hToken, $aAdjust, 0, $aAdjust)
_WinAPI_CloseHandle($hToken)

If Not $Result Then
	MsgBox(16, '', 'Process not found.')
EndIf
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
madmasles сказал(а):
Не дружу я пока с ней.

Давно уже пора подружиться, серьезно. Я тоже по началу не дружил с ней, но ситуация изменилась после того, как начал изучать ее API. Все намного грамотнее по сравнению с XP.

P.S

Так код работает?
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,320

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
madmasles [?]
У меня есть несколько программ для работы, которые работают только в XP, а подружить на одном компьютере обе системы мне пока не удалось.
а я подружил :smile:
 

Ganibal95

GreenBytes
Сообщения
877
Репутация
240
Эм... Мы узнали как можно получить PID процесса который использует файл. Теперь бы хотель узнать как освободить его от процесса не убивая его? Как функция в Unloker'е Разблокировать... :smile:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,716
Ganibal95 сказал(а):
Теперь бы хотель узнать как освободить его от процесса не убивая его?

Код:
Func _ProcessCloseHandle($PID, $hObject)

	Local $hModule, $hProcess, $hProc, $List, $Ret, $Index = 0

	$List = _WinAPI_EnumProcessModules($PID)
	If @error Then
		Return 0
	EndIf
	For $i = 1 To $List[0][0]
		If Not StringCompare(_WinAPI_PathStripPath($List[$i][1]), 'kernel32.dll') Then
			$Index = $i
			ExitLoop
		EndIf
	Next
	If Not $Index Then
		Return 0
	EndIf
	$hModule = _WinAPI_LoadLibrary($List[$Index][1])
	If Not $hModule Then
		Return 0
	EndIf
	$hProc = _WinAPI_GetProcAddress($hModule, 'CloseHandle')
	_WinAPI_FreeLibrary($hModule)
	If Not $hProc Then
		Return 0
	EndIf
	$hProcess = _WinAPI_OpenProcess(BitOR($PROCESS_CREATE_THREAD, $PROCESS_QUERY_INFORMATION, $PROCESS_VM_OPERATION, $PROCESS_VM_READ, $PROCESS_VM_WRITE), 0, $PID)
	If Not $hProcess Then
		Return 0
	EndIf
	$Ret = DllCall('kernel32.dll', 'ptr', 'CreateRemoteThread', 'ptr', $hProcess, 'ptr', 0, 'dword', 0, 'ptr', $List[$Index][0] + $hProc - $hModule, 'ptr', $hObject, 'dword', 0, 'ptr', 0)
	If (Not @error) And ($Ret[0]) Then
		_WinAPI_WaitForSingleObject($Ret[0])
		_WinAPI_CloseHandle($Ret[0])
	Else
		$Ret = 0
	EndIf
	_WinAPI_CloseHandle($hProcess)
	If Not IsArray($Ret) Then
		Return 0
	Else
		Return 1
	EndIf
EndFunc   ;==>_ProcessCloseHandle
 

---Zak---

Скриптер
Сообщения
443
Репутация
116
А возможно ли сделать так: файл занят другим процессом, если да, то узнать кто его юзает (имя пк, пользователь и т.п.) ?
т.е. допустим в сетке лежит файлик - на другом ПК его открыли. Существует ли что-нибудь для отслеживания кто его держит ?

ЗЫ: 7-zip не может заархивировать файл, который занят =(
 
Верх