<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Серый форум &mdash; AHK: Аудит файловой системы и вызов wait-функции в отдельном потоке]]></title>
	<link rel="self" href="http://forum.script-coding.com/extern.php?action=feed&amp;tid=6273&amp;type=atom" />
	<updated>2020-05-24T10:22:07Z</updated>
	<generator>PunBB</generator>
	<id>http://forum.script-coding.com/viewtopic.php?id=6273</id>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Аудит файловой системы и вызов wait-функции в отдельном потоке]]></title>
			<link rel="alternate" href="http://forum.script-coding.com/viewtopic.php?pid=139685#p139685" />
			<content type="html"><![CDATA[<p><strong>Helgef</strong> пишет:<br /></p><div class="quotebox"><blockquote><p>The code by YMP is not safe, but can probably be made safe by calling CancelIoEx appropriately.<br />I think the simplest way to use ReadDirectoryChangeW is to specify a completion routine</p></blockquote></div><p><a href="https://www.autohotkey.com/boards/viewtopic.php?p=330939#p330939">https://www.autohotkey.com/boards/viewt … 39#p330939</a></p>]]></content>
			<author>
				<name><![CDATA[Malcev]]></name>
				<uri>http://forum.script-coding.com/profile.php?id=26930</uri>
			</author>
			<updated>2020-05-24T10:22:07Z</updated>
			<id>http://forum.script-coding.com/viewtopic.php?pid=139685#p139685</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Аудит файловой системы и вызов wait-функции в отдельном потоке]]></title>
			<link rel="alternate" href="http://forum.script-coding.com/viewtopic.php?pid=83866#p83866" />
			<content type="html"><![CDATA[<p>По мотивам второго скрипта Александра (см. пост выше) я написал версию, работающую для обеих битностей (32 и 64) и кодировок (но GUI нет). Алгоритм тот же: ReadDirectoryChangesW запускается через машинную функцию в отдельном потоке и посылает в скрытое окно скрипта сообщения о событиях в папке. Обработка сообщений идёт в функции WM_DIRECTORYCHANGE: она получает адрес выходного буфера с данными о событиях и количество записанных туда байт. Можно здесь прописать какие-то действия для нужных событий. В примере ниже просто формируется и выводится сообщение о типе действия и, если определена глобально переменная LogFile, в этот лог пишутся эти сообщения. Фильтр для событий можно задать в функции WatchDirectory в переменной NotifyFilter. Если повторно вызвать WatchDirectory с именем папки, предыдущее слежение будет остановлено автоматически и начато новое. Вызов с нулём — остановка.<br /></p><div class="codebox"><pre><code>
DirName := A_ScriptDir          ; Папка для слежения.
LogFile := A_Desktop . &quot;\DirLog.txt&quot;

F10:: WatchDirectory(DirName)   ; Начать слежение.
F11:: WatchDirectory(0)         ; Остановить.


; ================ Функции =====================================================

WM_DIRECTORYCHANGE(BytesReturned, pOutBuf)
{
    Global LogFile
    ;FILE_ACTION_ADDED := 1, FILE_ACTION_REMOVED := 2, FILE_ACTION_MODIFIED := 3
    ;FILE_ACTION_RENAMED_OLD_NAME := 4, FILE_ACTION_RENAMED_NEW_NAME := 5
    Static Actions := [&quot;Файл добавлен:  &quot;, &quot;Файл удалён:    &quot;, &quot;Файл изменён:   &quot;
                     , &quot;Файл переименован с имени: &quot;, &quot;Файл переименован на имя:  &quot;]
    If (pOutBuf = 0) {
        MsgBox, Ошибка в ReadDirectoryChangeW
        Return
    }
    DateTime := A_DD &quot;.&quot; A_MM &quot;.&quot; A_YYYY &quot; &quot; A_Hour &quot;:&quot; A_Min &quot;:&quot; A_Sec
    Addr := pOutBuf, Next := 0  ; Адрес текущей записи и смещение до следующей.
    Loop    ; Чтение из буфера записей о событиях и реакция на них.
    {
        Addr += Next, Next := NumGet(Addr+0, 0, &quot;uint&quot;) ; Смещение следующей записи.
        ActionCode := NumGet(Addr+0, 4, &quot;uint&quot;) ; Код события (см. в начале функции).
        If (Action := Actions[ActionCode]) {    ; Описание события из массива.
            cbFile := NumGet(Addr+0, 8, &quot;uint&quot;) ; Длина имени файла в байтах.
            FileName := StrGet(Addr+12, cbFile // 2, &quot;utf-16&quot;)
            Msg .= DateTime &quot; &quot; Action FileName &quot;`n&quot;
        }
        If (!Next)  ; Если смещение равно 0, больше записей в буфере нет.
            Break
    }
    If (Msg) {
        ToolTip, %Msg%
        If (LogFile)
            FileAppend, %Msg%, %LogFile%
        Sleep, 1000
        ToolTip
    }
    WatchDirectory(-1)  ; Продолжить слежение.
}

WatchDirectory(DirName)
{
    Static hDir, hThread, pData, pThreadStart, OutBuf, OutBufSize := 0x400  ; 1 KB
    Static BytesReturned, WM_DIRECTORYCHANGE := 0x401
    ;FILE_NOTIFY_CHANGE_FILE_NAME := 0x1, FILE_NOTIFY_CHANGE_DIR_NAME := 0x2
    ;FILE_NOTIFY_CHANGE_ATTRIBUTES := 0x4, FILE_NOTIFY_CHANGE_SIZE := 0x8
    ;FILE_NOTIFY_CHANGE_LAST_WRITE := 0x10, FILE_NOTIFY_CHANGE_LAST_ACCESS := 0x20
    ;FILE_NOTIFY_CHANGE_CREATION := 0x40, FILE_NOTIFY_CHANGE_SECURITY := 0x100
    Static NotifyFilter := 0x11     ; Комбинация из флагов выше (сумма).
    If (DirName = -1) {
        DllCall(&quot;CloseHandle&quot;, &quot;ptr&quot;, hThread)
        Goto NewThread
    }
    Else If (DirName = 0) {
        If (hThread) {
            DllCall(&quot;TerminateThread&quot;, &quot;ptr&quot;, hThread, &quot;int&quot;, 0)
            DllCall(&quot;CloseHandle&quot;, &quot;ptr&quot;, hThread), hThread := 0
        }
        If (hDir)
            DllCall(&quot;CloseHandle&quot;, &quot;ptr&quot;, hDir), hDir := 0
        Return
    }
    If (hDir)
        WatchDirectory(0) ; Остановить текущее слежение.
    If (!OutBuf) {
        VarSetCapacity(OutBuf, OutBufSize, 0), VarSetCapacity(BytesReturned, 4, 0)
        OnMessage(WM_DIRECTORYCHANGE, &quot;WM_DIRECTORYCHANGE&quot;)
        If !(pReadDirectoryChanges := GetProcAddress(&quot;kernel32.dll&quot;, &quot;ReadDirectoryChangesW&quot;))
            Return Error(&quot;GetProcAddress - ReadDirectoryChangesW&quot;)
        If !(pPostMessage := GetProcAddress(&quot;user32.dll&quot;, &quot;PostMessage&quot; . (A_IsUnicode? &quot;W&quot;:&quot;A&quot;)))
            Return Error(&quot;GetProcAddress - PostMessage&quot;)
        If !(pThreadStart := CreateMachineFunc())
            Return Error(&quot;CreateMachineFunc&quot;)
        pData := CreateStruct(pReadDirectoryChanges, hDir, &amp;OutBuf, OutBufSize, 0
                            , NotifyFilter, &amp;BytesReturned, 0, 0
                            , pPostMessage, A_ScriptHwnd, WM_DIRECTORYCHANGE)
    }
    If !(hDir := OpenDirectory(DirName))
        Return Error(&quot;OpenDirectory&quot;)
    NumPut(hDir, pData+0, A_PtrSize, &quot;ptr&quot;)
NewThread:
    If !(hThread := CreateThread(pThreadStart, pData))
        Return Error(&quot;CreateThread&quot;)
    Return True
}

OpenDirectory(Dir)
{
    Static FILE_LIST_DIRECTORY := 1, FILE_SHARE_READ := 1, FILE_SHARE_WRITE := 2
    Static OPEN_EXISTING := 3, FILE_FLAG_BACKUP_SEMANTICS := 0x02000000
    Static INVALID_HANDLE_VALUE := -1
    hDir := DllCall(&quot;CreateFile&quot;, &quot;str&quot;, Dir, &quot;uint&quot;, FILE_LIST_DIRECTORY
            , &quot;uint&quot;, FILE_SHARE_READ | FILE_SHARE_WRITE, &quot;ptr&quot;, 0, &quot;uint&quot;, OPEN_EXISTING
            , &quot;uint&quot;, FILE_FLAG_BACKUP_SEMANTICS, &quot;ptr&quot;, 0, &quot;ptr&quot;)
    Return hDir = INVALID_HANDLE_VALUE? 0:hDir      
}

CreateStruct(Members*)
{
    Static Struct
    cMembers := Members.MaxIndex()
    VarSetCapacity(Struct, cMembers * A_PtrSize, 0)
    addr := &amp;Struct
    Loop, %cMembers%
        addr := NumPut(Members[A_Index], addr+0, 0, &quot;ptr&quot;)
    Return &amp;Struct
}

GetProcAddress(Lib, Func)
{
    hLib := DllCall(&quot;LoadLibrary&quot;, &quot;str&quot;, Lib, &quot;ptr&quot;)
    If (hLib = 0)
        Return 0
    Return DllCall(&quot;GetProcAddress&quot;, &quot;ptr&quot;, hLib, &quot;astr&quot;, Func, &quot;ptr&quot;)
}

CreateMachineFunc()
{
    MEM_RESERVE := 0x2000, MEM_COMMIT := 0x1000, PAGE_EXECUTE_READWRITE := 0x40
    If (A_PtrSize = 8) {
        Hex = 
        ( Join LTrim
        488B0151FF7140FF7138FF7130FF71284883EC204C8B49204C8B4118488B5110488B4908FFD04
        C8B5424404D31C985C04D0F454A10498B4230448B00498B5258498B4A5041FF52484883C448C3
        )
    }
    Else {
        Hex =
        ( Join LTrim
        8B54240452FF7220FF721CFF7218FF7214FF7210FF720CFF7208FF7204FF125A85C00F4542088
        B4A1850FF31FF722CFF7228FF5224C20400
        )
    }
    Len := StrLen(Hex) // 2
    pFunc := DllCall(&quot;VirtualAlloc&quot;, &quot;ptr&quot;, 0, &quot;ptr&quot;, Len
                                   , &quot;uint&quot;, MEM_RESERVE | MEM_COMMIT
                                   , &quot;uint&quot;, PAGE_EXECUTE_READWRITE, &quot;ptr&quot;)
    If (pFunc = 0)
        Return 0
    Loop, % Len
        NumPut(&quot;0x&quot; . SubStr(Hex, A_Index * 2 - 1, 2), pFunc + 0
                                 , A_Index - 1, &quot;uchar&quot;)
    Return pFunc
}

CreateThread(StartAddr, Param)
{
    Return DllCall(&quot;CreateThread&quot;, &quot;ptr&quot;, 0, &quot;ptr&quot;, 0, &quot;ptr&quot;, StartAddr
                                 , &quot;ptr&quot;, Param, &quot;uint&quot;, 0, &quot;ptr&quot;, 0, &quot;ptr&quot;)
}

Error(Func)
{
    MsgBox, %Func% failed.
    Return False
}
</code></pre></div><p>Если кому интересно, вот исходный код машинных функций (на ассемблере GoAsm). Для работы скрипта, разумеется, он не нужен, т.к. он уже там в виде хекс-строк.<br /></p><div class="fancy_spoiler_switcher"><div class="fancy_spoiler_switcher_header" data-lang-open="открыть спойлер" data-lang-close="скрыть спойлер"><strong>+</strong>&nbsp;открыть спойлер</div><div class="fancy_spoiler"><div class="codebox"><pre><code>
#if x64

    mov rax,[rcx]
    push rcx,[rcx+40h],[rcx+38h],[rcx+30h],[rcx+28h]
    sub rsp,20h
    mov r9,[rcx+20h]
    mov r8,[rcx+18h]
    mov rdx,[rcx+10h]
    mov rcx,[rcx+8h]
    call rax            ; Вызов ReadDirectoryChangeW
    mov r10,[rsp+40h]
    xor r9,r9
    test eax,eax
    cmovnz r9,[r10+10h]
    mov rax,[r10+30h]
    mov r8d,[rax]
    mov rdx,[r10+58h]
    mov rcx,[r10+50h]
    call [r10+48h]      ; Вызов PostMessage
    add rsp,48h
    ret

#else

    mov edx,[esp+4]
    push edx
    push [edx+20h],[edx+1Ch],[edx+18h],[edx+14h],[edx+10h],[edx+0Ch],[edx+8h],[edx+4h]
    call [edx]
    pop edx
    test eax,eax
    cmovnz eax,[edx+8h]
    mov ecx,[edx+18h]
    push eax,[ecx],[edx+2Ch],[edx+28h]
    call [edx+24h]
    ret 4

#endif
</code></pre></div></div></div>]]></content>
			<author>
				<name><![CDATA[YMP]]></name>
				<uri>http://forum.script-coding.com/profile.php?id=81</uri>
			</author>
			<updated>2014-06-13T07:26:44Z</updated>
			<id>http://forum.script-coding.com/viewtopic.php?pid=83866#p83866</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[AHK: Аудит файловой системы и вызов wait-функции в отдельном потоке]]></title>
			<link rel="alternate" href="http://forum.script-coding.com/viewtopic.php?pid=52036#p52036" />
			<content type="html"><![CDATA[<p>Вариант 1, используем функции FindFirstChangeNotification/FindFirstChangeNotification.<br />Метод позволяет отлавливать изменения, но не предоставляет никакой информации о типах изменений и о конкретных файлах.<br /></p><div class="codebox"><pre><code>DetectHiddenWindows, on ; чтоб найти скрытое окно AHK
dir := &quot;C:\Users\Александр\Desktop\test\cur&quot; ; директория для мониторинга
FILE_NOTIFY_CHANGE_FILE_NAME :=  1  ; мониторинг изменений имён файлов(функция FindFirstChangeNotification)
INFINITE                     := -1  ; неограниченное время ожидания(функция WaitForSingleObject)
WM_USER                      := 0x400 ; начало диапазона пользовательских сообщений
Unicode                      := A_IsUnicode ? &quot;W&quot; : &quot;A&quot;
 
FindFirstChangeNotification(PathName, WatchSubtree, NotifyFilter)
; функция начинает отслеживать изменения в файловой системе
; PathName- имя директории
; WatchSubtree- мониторить ли поддиректории?(0- нет, любое другое значение- да)
; NotifyFilter- набор флагов, указывающих какие изменения нужно отслеживать
{
   global Unicode
   return DllCall(&quot;FindFirstChangeNotification&quot; . Unicode, &quot;str&quot;, PathName, &quot;int&quot;, WatchSubtree, &quot;int&quot;, NotifyFilter)
}
 
FindNextChangeNotification(hChangeHandle)
; функция продолжает мониторинг, начатый FindFirstChangeNotification
; hChangeHandle- хэндл, возвращённый функцией FindFirstChangeNotification
{
   return DllCall(&quot;FindNextChangeNotification&quot;, &quot;int&quot;, hChangeHandle)
}
 
FindCloseChangeNotification(hChangeHandle)
; функция заканчивает мониторинг, начатый FindFirstChangeNotification
; hChangeHandle- хэндл, возвращённый функцией FindFirstChangeNotification
{
   return DllCall(&quot;FindCloseChangeNotification&quot;, &quot;int&quot;, hChangeHandle)
}
 
CreateThread(ThreadAttributes, StackSize, StartAddress, Parameter, CreationFlags, ThreadId)
; функция создаёт поток
; ThreadAttributes- атрибуты безопасности, почти всегда 0
; StackSize- начальный размер стека, обычно тоже 0
; StartAddress- адрес функции, которую будет исполнять поток
; Parameter- параметр, который получит функция StartAddress
; CreationFlags- флаги создания, обычно 0, иногда 4(тогда поток создаётся, но не начинает выполняться)
; ThreadId- ссылка на переменную, в которую будет помещён идентификатор потока
{
   return DllCall(&quot;CreateThread&quot;,&quot;int&quot;,ThreadAttributes,&quot;int&quot;,StackSize,&quot;int&quot;,StartAddress,&quot;int&quot;,Parameter,&quot;int&quot;,CreationFlags,&quot;int&quot;,ThreadId)
}
 
CloseHandle(Handle)
; функция закрывает хэндл Handle
{
   return DllCall(&quot;CloseHandle&quot;,&quot;int&quot;,Handle)
}
 
TerminateThread(hThread, ExitCode)
; функция убивает поток по дескриптору hThread
; ЭТУ ФУНКЦИЮ НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ В ОБЫЧНЫХ ПРИЛОЖЕНИЯХ
{
   return DllCall(&quot;TerminateThread&quot;, &quot;int&quot;, hThread, &quot;int&quot;, ExitCode)
}
 
IfUnicodeThenUnicodeToAnsi(ByRef wStr, ByRef str)
; функция конвертирует Unicode-строку в Ascii в unicode-скриптах
; в ascii-скриптах ничего не делает
{
   if (!A_IsUnicode)
      return wStr
   Size := StrLen(wStr)*2
   VarSetCapacity(str, Size)
   DllCall(&quot;WideCharToMultiByte&quot;, &quot;Uint&quot;, 0, &quot;Uint&quot;, 0, &quot;Uint&quot;, &amp;wStr, &quot;int&quot;,  -1, &quot;str&quot;,  str, &quot;int&quot;,  Size, &quot;Uint&quot;, 0, &quot;Uint&quot;, 0)
   return str
}
 
VarSetCapacity(hThread, 4)
;дескриптор потока
 
VarSetCapacity(hChangeHandle, 4)
;хэндл из FindFirstChangeNotification
 
VarSetCapacity(hWnd, 4)
WinGet, hWnd, ID, ahk_class AutoHotkey
;хэндл окна
 
VarSetCapacity(PostMessageAddr, 4)
NumPut(DllCall(&quot;GetProcAddress&quot;,&quot;int&quot;,DllCall(&quot;GetModuleHandle&quot; . Unicode,&quot;str&quot;,&quot;user32.dll&quot;),&quot;str&quot;,IfUnicodeThenUnicodeToAnsi(&quot;PostMessage&quot; . Unicode, tempstr)),PostMessageAddr,0)
; адрес PostMessage
 
VarSetCapacity(WaitForSingleObjectAddr, 4)
NumPut(DllCall(&quot;GetProcAddress&quot;,&quot;int&quot;,DllCall(&quot;GetModuleHandle&quot; . Unicode,&quot;str&quot;,&quot;Kernel32.dll&quot;),&quot;str&quot;,IfUnicodeThenUnicodeToAnsi(&quot;WaitForSingleObject&quot;,tempstr)),WaitForSingleObjectAddr,0)
; адрес WaitForSingleObject
 
; Функция потока
; Ожидает возврата из WaitForSingleObject и отправляет сообщение окну
; lParam содержит возвращаемое WaitForSingleObject значение
VarSetCapacity(springboard, 38)
NumPut(0x68, springboard, 0, &quot;Char&quot;)
NumPut(INFINITE, springboard, 1)
;push -1
NumPut(0x68, springboard, 5, &quot;Char&quot;)
;NumPut(hChangeHandle, springboard, 6)
;push hChangeHandle
NumPut(0x15ff, springboard, 10, &quot;Short&quot;)
NumPut(&amp;WaitForSingleObjectAddr, springboard, 12)
;call WaitForsingleObject
NumPut(0x50, springboard, 16, &quot;Char&quot;)
;push EAX
NumPut(0x6A, springboard, 17, &quot;Char&quot;)
NumPut(0x00, springboard, 18, &quot;Char&quot;)
;push 0
NumPut(0x68, springboard, 19, &quot;Char&quot;)
NumPut(WM_USER, springboard, 20)
;push 0x400
NumPut(0x68, springboard, 24, &quot;Char&quot;)
NumPut(hWnd, springboard, 25)
;push hWnd
NumPut(0x15ff, springboard, 29, &quot;Short&quot;)
NumPut(&amp;PostMessageAddr, springboard, 31)
;Call PostMessage
NumPut(0xC2, springboard, 35,&quot;char&quot;)
NumPut(4, springboard, 36,&quot;short&quot;)
;ret 4
 
ThreadFunc(wParam, lParam)
{
   global hChangeHandle, springboard, hThread
   CloseHandle(hThread)
   if lParam
   {
      ;случился какой-то косяк
      return 0
   }
   MsgBox 4, , Был создан, удалён или переименован какой-то файл`r`nВы хотите продолжить мониторинг?
   IfMsgBox  No
      FindCloseChangeNotification(hChangeHandle)
   else
   {
      FindNextChangeNotification(hChangeHandle)
      hThread:=CreateThread(0, 64*1024, &amp;springboard, 0, 0, 0)
   }
   return 0
}
 
;будем обрабатывать сообщение WM_USER, функцией ThreadFunc
OnMessage(WM_USER,&quot;ThreadFunc&quot;)
 
hChangeHandle:=FindFirstChangeNotification( dir, 0, FILE_NOTIFY_CHANGE_FILE_NAME)
NumPut(hChangeHandle, springboard, 6)
hThread:=CreateThread(0, 64*1024, &amp;springboard, 0, 0, 0)
return
 
F12::
   ; Так делать не надо, этот код исключительно для удобства тестирования
   TerminateThread(hThread, -1)
   CloseHandle(hThread)
   FindCloseChangeNotification(hChangeHandle)
return</code></pre></div><p>Вариант 2, используем функцию ReadDirectoryChangesW.<br />Метод позволяет отлавливать изменения, а также сообщает имена файлов и различает пять видов действий.<br /></p><div class="codebox"><pre><code>#include %A_ScriptDir%\windows.ahk
 
DetectHiddenWindows, on ; чтоб найти скрытое окно AHK
WM_USER                      := 0x400 ; начало диапазона пользовательских сообщений
WM_DIRECTORYCHANGE           := WM_USER + 1
 
IfAnsiThenUnicodeToAnsi(ByRef wStr, ByRef str, len)
{
   if A_IsUnicode
      return wStr
   len := len/2+1
   VarSetCapacity(str, len)
   DllCall(&quot;WideCharToMultiByte&quot;, &quot;Uint&quot;, 0, &quot;Uint&quot;, 0, &quot;Uint&quot;, &amp;wStr, &quot;int&quot;,  -1, &quot;str&quot;,  str, &quot;int&quot;,  len, &quot;Uint&quot;, 0, &quot;Uint&quot;, 0)
   return str
}
 
VarSetCapacity(hThread, 4)
 
VarSetCapacity(hDirectory, 4)
 
VarSetCapacity(hWnd, 4)
PID := GetCurrentProcessId()
WinGet, hWnd, ID, ahk_pid %PID% ahk_class AutoHotkey
 
VarSetCapacity(PostMessageAddr, 4)
NumPut(GetProcAddress(GetModuleHandle(&quot;user32.dll&quot;), &quot;PostMessage&quot; . Unicode),PostMessageAddr,0)
 
VarSetCapacity(ReadDirectoryChangesWAddr, 4)
NumPut(GetProcAddress(GetModuleHandle(&quot;Kernel32.dll&quot;),&quot;ReadDirectoryChangesW&quot;),ReadDirectoryChangesWAddr,0)
 
VarSetCapacity(BytesReturned, 4)
VarSetCapacity(outBuffer, 0x400)
 
VarSetCapacity(springboard, 100)
NumPut(0x68, springboard, 0)
NumPut(0x00, springboard, 1)
NumPut(0x68, springboard, 5)
NumPut(0x00, springboard, 6)
NumPut(0x68, springboard, 10)
NumPut(&amp;BytesReturned, springboard, 11)
NumPut(0x68, springboard, 15)
;NumPut(FILE_NOTIFY_CHANGE_FILE_NAME, springboard, 16)
NumPut(0x68, springboard, 20)
;NumPut(0x00, springboard, 21)
NumPut(0x68, springboard, 25)
NumPut(0x400, springboard, 26)
NumPut(0x68, springboard, 30)
NumPut(&amp;outBuffer, springboard, 31)
NumPut(0x68, springboard, 35, &quot;Char&quot;)
;NumPut(hDirectory, springboard, 36)
NumPut(0x15ff, springboard, 40, &quot;Short&quot;)
NumPut(&amp;ReadDirectoryChangesWAddr, springboard, 42)
NumPut(0x50, springboard, 46, &quot;Char&quot;)
NumPut(0x6A, springboard, 47, &quot;Char&quot;)
NumPut(0x00, springboard, 48, &quot;Char&quot;)
NumPut(0x68, springboard, 49, &quot;Char&quot;)
NumPut(WM_DIRECTORYCHANGE, springboard, 50)
NumPut(0x68, springboard, 54, &quot;Char&quot;)
NumPut(hWnd, springboard, 55)
NumPut(0x15ff, springboard, 59, &quot;Short&quot;)
NumPut(&amp;PostMessageAddr, springboard, 61)
NumPut(0xC2, springboard, 65,&quot;char&quot;)
NumPut(4, springboard, 66,&quot;short&quot;)
 
ThreadFunc(wParam, lParam)
{
   global
   CloseHandle(hThread)
   if (!lParam)
   {
      msgbox &quot;exit&quot;, %lParam%, %A_lasterror%
      return 0
   }
   next := 0
   loop
   {
   type := NumGet(outBuffer,4+next)
   if (type == FILE_ACTION_ADDED)
      msg := &quot;Создан файл &quot;
   else if (type = FILE_ACTION_REMOVED)
      msg := &quot;Удалён файл &quot;
   else if (type = FILE_ACTION_MODIFIED)
      msg := &quot;Изменён файл &quot;
   else if (type = FILE_ACTION_RENAMED_OLD_NAME)
      msg := &quot;Файл переименован из &quot;
   else if (type = FILE_ACTION_RENAMED_NEW_NAME)
      msg := &quot;Файл переименован в &quot;
   else 
      msg := type
   NameLen := NumGet(outBuffer,8+next)
   VarSetCapacity(fn, NameLen+2)
   WriteProcessMemory(GetCurrentProcess(), &amp;fn, &amp;outBuffer+12+next, NameLen, &amp;BytesReturned)
   NumPut(0x0000, fn, NameLen ,&quot;short&quot;)
   next := NumGet(outBuffer, next)
   LV_Add(&quot;&quot;, msg, IfAnsiThenUnicodeToAnsi(fn, str, NameLen) )
   if (!next)
      break
   }
   hThread:=CreateThread(0, 64*1024, &amp;springboard, 0, 0, 0)
   return 0
}
 
OnMessage(WM_DIRECTORYCHANGE,&quot;ThreadFunc&quot;)
 
 
PathName := A_ScriptDir
Status := 0
Options := 0
Gui Add, Edit, w200 ReadOnly vE_PathName, %PathName%
Gui Add, Button, x210 y5 w50 vB_PathName gG_PathName, ...
Gui Add, Button, x300 y5 w150 vB_Start gG_Start, Начать слежение
Gui Add, Text, x10, Типы изменений:
Gui Add, Checkbox, x220 y35 vCh_SubDir gG_FILE_NOTIFY_CHANGE, Следить за поддиректориями
Gui Add, Checkbox, x10 y55 w110 vCh_FILE_NAME gG_FILE_NOTIFY_CHANGE, Имена файлов
Gui Add, Checkbox, x120 y55 w110 vCh_DIR_NAME gG_FILE_NOTIFY_CHANGE, Имена папок
Gui Add, Checkbox, x230 y55 w110 vCh_ATTRIBUTES gG_FILE_NOTIFY_CHANGE, Атрибуты
Gui Add, Checkbox, x340 y55 w110 vCh_SIZE gG_FILE_NOTIFY_CHANGE, Размер
Gui Add, Checkbox, x10 y75 w110 vCh_LAST_WRITE gG_FILE_NOTIFY_CHANGE, Запись
Gui Add, Checkbox, x120 y75 w110 vCh_LAST_ACCESS gG_FILE_NOTIFY_CHANGE, Доступ
Gui Add, Checkbox, x230 y75 w110 vCh_CHANGE_CREATION gG_FILE_NOTIFY_CHANGE, Время создания
Gui Add, Checkbox, x340 y75 w110 vCh_CHANGE_SECURITY gG_FILE_NOTIFY_CHANGE, Безопасность
Gui Add, ListView, x10 r20 w450 NoSort, Действие|Имя файла
LV_ModifyCol(1, 146)
LV_ModifyCol(2, 300)
Gui Show
return 
 
GuiClose:
   ExitApp
return
 
G_PathName:
   if (Status=1)
   {
      MsgBox Перед сменой директории остановите текущее слежение!
      return
   }
   Gui Submit, NoHide
   FileSelectFolder PathName , *%E_PathName%, 3, Выбирите папку для наблюдения
   if (PathName!=&quot;&quot;)
   {
      GuiControl ,, E_PathName, %PathName%
   }
return
 
G_Start:
   if (Status=1) ;остановка
   {
      Status := 0
      TerminateThread(hThread, -1)
      CloseHandle(hThread)
      CloseHandle(hDirectory)
      GuiControl ,, B_Start, Начать слежение
      LV_Add(&quot;&quot;, &quot;Слежение прервано&quot;, PathName)
   }
   else if (Status=0) ;начало
   {
      Gui Submit, NoHide
      Options := FILE_NOTIFY_CHANGE_FILE_NAME*Ch_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME*Ch_DIR_NAME|FILE_NOTIFY_CHANGE_ATTRIBUTES*Ch_ATTRIBUTES|FILE_NOTIFY_CHANGE_SIZE*Ch_SIZE|FILE_NOTIFY_CHANGE_LAST_WRITE*Ch_LAST_WRITE|FILE_NOTIFY_CHANGE_LAST_ACCESS*Ch_LAST_ACCESS|FILE_NOTIFY_CHANGE_CREATION*Ch_CHANGE_CREATION|FILE_NOTIFY_CHANGE_SECURITY*Ch_CHANGE_SECURITY
      if (Options=0)
      {
         MsgBox не выбран ни один тип слежения!
         return
      }
      Status := 1
      NumPut(Ch_SubDir, springboard, 21)
      NumPut(Options, springboard, 16)
      hDirectory := CreateFile(E_PathName, FILE_LIST_DIRECTORY, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
      if (hDirectory=-1)
      {
         msgbox CreateFile error, %a_lasterror%
         ExitApp
      }
      NumPut(hDirectory, springboard, 36)
      hThread:=CreateThread(0, 64*1024, &amp;springboard, 0, 0, 0)
      GuiControl ,, B_Start, Прервать слежение
      LV_Add(&quot;&quot;, &quot;Слежение начато&quot;, PathName)
   }
   else ;перезапуск
   {
      TerminateThread(hThread, -1)
      CloseHandle(hThread)
      CloseHandle(hDirectory)
      LV_Add(&quot;&quot;, &quot;Слежение прервано&quot;, PathName)
      Status := 0
      Goto G_Start
   }
return
 
G_FILE_NOTIFY_CHANGE:
   if (Status=1)
   {
      Status = -1
      GuiControl ,, B_Start, Применить изменения
   }
return</code></pre></div><p>вспомогательный файл &quot;windows.ahk&quot;, который должен лежать в папке с основным(в нём только константы и оболочки WinApi функций):<br /></p><div class="codebox"><pre><code>Unicode          := A_IsUnicode ? &quot;W&quot; : &quot;A&quot;
 
; CreateFile, ShareMode
FILE_SHARE_READ  := 1
FILE_SHARE_WRITE := 2
 
; CreateFile, DesiredAccess
GENERIC_READ     := 0x80000000
GENERIC_WRITE    := 0x40000000
; дополнительные атрибуты доступа
; тут необходимо указать FILE_LIST_DIRECTORY
FILE_ADD_FILE             := 0x0002
FILE_ADD_SUBDIRECTORY     := 0x0004
FILE_APPEND_DATA          := 0x0004
FILE_CREATE_PIPE_INSTANCE := 0x0004
FILE_DELETE_CHILD         := 0x0040
FILE_EXECUTE              := 0x0020
FILE_LIST_DIRECTORY       := 0x0001 ;право просматривать содержание директории
FILE_READ_ATTRIBUTES      := 0x0080
FILE_READ_DATA            := 0x0001
FILE_READ_EA              := 0x0008
FILE_TRAVERSE             := 0x0020
FILE_WRITE_ATTRIBUTES     := 0x0100
FILE_WRITE_DATA           := 0x0002
FILE_WRITE_EA             := 0x0010
 
; события получаемые в структуре FILE_NOTIFY_INFORMATION
FILE_ACTION_ADDED            := 0x00000001
FILE_ACTION_REMOVED          := 0x00000002
FILE_ACTION_MODIFIED         := 0x00000003 
FILE_ACTION_RENAMED_OLD_NAME := 0x00000004
FILE_ACTION_RENAMED_NEW_NAME := 0x00000005 
 
; CreateFile, CreationDisposition
CREATE_NEW        := 1
CREATE_ALWAYS     := 2
OPEN_EXISTING     := 3
OPEN_ALWAYS       := 4
TRUNCATE_EXISTING := 5
 
; CreateFile, FlagsAndAttributes
FILE_ATTRIBUTE_READONLY   := 0x00000001
FILE_ATTRIBUTE_HIDDEN     := 0x00000002
FILE_ATTRIBUTE_SYSTEM     := 0x00000004
FILE_ATTRIBUTE_DIRECTORY  := 0x00000010
FILE_ATTRIBUTE_ARCHIVE    := 0x00000020
FILE_ATTRIBUTE_NORMAL     := 0x00000080
FILE_ATTRIBUTE_TEMPORARY  := 0x00000100
FILE_ATTRIBUTE_COMPRESSED := 0x00000800
FILE_FLAG_POSIX_SEMANTICS  := 0x01000000
FILE_FLAG_BACKUP_SEMANTICS := 0x02000000
FILE_FLAG_DELETE_ON_CLOSE  := 0x04000000
FILE_FLAG_SEQUENTIAL_SCAN  := 0x08000000
FILE_FLAG_RANDOM_ACCESS    := 0x10000000
FILE_FLAG_NO_BUFFERING     := 0x20000000
FILE_FLAG_OVERLAPPED       := 0x40000000
FILE_FLAG_WRITE_THROUGH    := 0x80000000
 
FILE_NOTIFY_CHANGE_FILE_NAME   := 0x00000001
FILE_NOTIFY_CHANGE_DIR_NAME    := 0x00000002
FILE_NOTIFY_CHANGE_ATTRIBUTES  := 0x00000004
FILE_NOTIFY_CHANGE_SIZE        := 0x00000008
FILE_NOTIFY_CHANGE_LAST_WRITE  := 0x00000010
FILE_NOTIFY_CHANGE_LAST_ACCESS := 0x00000020
FILE_NOTIFY_CHANGE_CREATION    := 0x00000040
FILE_NOTIFY_CHANGE_SECURITY    := 0x00000100 
 
GetCurrentProcessId()
{
   return DllCall(&quot;GetCurrentProcessId&quot;)
}
 
GetCurrentProcess()
{
   return DllCall(&quot;GetCurrentProcess&quot;)
}
 
GetModuleHandle(Name)
{
   global Unicode
   return DllCall(&quot;GetModuleHandle&quot; . Unicode, &quot;str&quot;, Name)
}
 
GetProcAddress(hModule, FuncName)
{
   if (!A_IsUnicode)
      return DllCall(&quot;GetProcAddress&quot;, &quot;int&quot;, hModule, &quot;str&quot;, FuncName)
   len := StrLen(FuncName)+1
   VarSetCapacity(str, len)
   WideCharToMultiByte(0, 0, &amp;FuncName, -1, &amp;str, len, 0, 0)
   ret := DllCall(&quot;GetProcAddress&quot;, &quot;int&quot;, hModule, &quot;int&quot;, &amp;str)
   VarSetCapacity(str, 0)
   return ret
}
 
WideCharToMultiByte(CodePage, Flags, WideCharStr, WideChar, MultiByteStr, MultiByte, DefaultChar, UsedDefaultChar)
{
   return DllCall(&quot;WideCharToMultiByte&quot;, &quot;Uint&quot;, CodePage, &quot;Uint&quot;, Flags, &quot;int&quot;, WideCharStr, &quot;int&quot;,  WideChar, &quot;int&quot;, MultiByteStr, &quot;int&quot;, MultiByte, &quot;Uint&quot;, DefaultChar, &quot;Uint&quot;, UsedDefaultChar)
}
 
CreateFile(FileName, DesiredAccess, ShareMode, SecurityAttributes, CreationDisposition, FlagsAndAttributes, hTemplateFile)
; FileName- путь к файлу
; DesiredAccess- требуемый доступ(GENERIC_*)
; ShareMode- права на совместный доступ(FILE_SHARE_)
; SecurityAttributes- атрибуты защиты(обычно нуль)
; CreationDisposition- действия над файлом
; FlagsAndAttributes- атрибуты и флаги файла(FILE_ATTRIBUTE_* и FILE_FLAG_*, обычно FILE_ATTRIBUTE_NORMAL)
; hTemplateFile- файл, от которого наследуется FlagsAndAttributes(обычно 0)
{
   global Unicode
   return DllCall(&quot;CreateFile&quot; . Unicode, &quot;str&quot;, FileName, &quot;int&quot;, DesiredAccess, &quot;int&quot;, ShareMode, &quot;int&quot;, SecurityAttributes, &quot;int&quot;, CreationDisposition, &quot;int&quot;, FlagsAndAttributes, &quot;int&quot;, hTemplateFile)
}
 
CreateThread(ThreadAttributes, StackSize, StartAddress, Parameter, CreationFlags, ThreadId)
; функция создаёт поток
; ThreadAttributes- атрибуты безопасности, почти всегда 0
; StackSize- начальный размер стека, обычно тоже 0
; StartAddress- адрес функции, которую будет исполнять поток
; Parameter- параметр, который получит функция StartAddress
; CreationFlags- флаги создания, обычно 0, иногда 4(тогда поток создаётся, но не начинает выполняться)
; ThreadId- ссылка на переменную, в которую будет помещён идентификатор потока
{
   return DllCall(&quot;CreateThread&quot;,&quot;int&quot;,ThreadAttributes,&quot;int&quot;,StackSize,&quot;int&quot;,StartAddress,&quot;int&quot;,Parameter,&quot;int&quot;,CreationFlags,&quot;int&quot;,ThreadId)
}
 
CloseHandle(Handle)
; функция закрывает хэндл Handle
{
   return DllCall(&quot;CloseHandle&quot;,&quot;int&quot;,Handle)
}
 
TerminateThread(hThread, ExitCode)
; функция убивает поток по дескриптору hThread
; ЭТУ ФУНКЦИЮ НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ В ОБЫЧНЫХ ПРИЛОЖЕНИЯХ
{
   return DllCall(&quot;TerminateThread&quot;, &quot;int&quot;, hThread, &quot;int&quot;, ExitCode)
}
 
WriteProcessMemory(hProcess, BaseAddress, Buffer, Size, NumberOfBytesWritten)
; функция записывает Size байт с адреса Buffer в процесс hProcess по адресу BaseAddress
; в NumberOfBytesWritten помещает число записанный байтов
{
   return DllCall(&quot;WriteProcessMemory&quot;, &quot;int&quot;, hProcess, &quot;int&quot;, BaseAddress, &quot;int&quot;, Buffer, &quot;int&quot;, Size, &quot;int&quot;, NumberOfBytesWritten)
}</code></pre></div><p>см. также:<br /><a href="http://forum.script-coding.com/viewtopic.php?id=3465">Ускорение скриптов машинным кодом</a><br /><a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa365261%28v=VS.85%29.aspx">Obtaining Directory Change Notifications [ENG]</a></p>]]></content>
			<author>
				<name><![CDATA[Александр_]]></name>
				<uri>http://forum.script-coding.com/profile.php?id=24888</uri>
			</author>
			<updated>2011-09-30T22:03:01Z</updated>
			<id>http://forum.script-coding.com/viewtopic.php?pid=52036#p52036</id>
		</entry>
</feed>
