Перейти к содержимому


Перед регистрацией ознакомьтесь с темой про сертификат безопасности:
Фотография
* * * * * 1 Голосов

Секреты Премьер Про


  • Please log in to reply
558 ответов в этой теме

#501 Muhin

Muhin

    не теряя ни секунды

  • Активные Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1789 Сообщений:

Отправлено 25 Oct 2017 - 15:41

Там пару вещей есть полезных.

https://blogs.adobe....remiere-pro-cc/



#502 Muhin

Muhin

    не теряя ни секунды

  • Активные Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1789 Сообщений:

Отправлено 26 Oct 2017 - 22:07

Видимо достали адобов с запросами, так они теперь письма шлют со ссылкой:

https://helpx.adobe....of-support.html



#503 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 02 Dec 2017 - 11:57

Объясните мне плз такую вот странность: были отрендерены превьюшки в MPEG I-Frame, ставлю галку использовать их в финальном рендере - фигушки, считает все по новой (судя по времени). До этого использовал QT DNxHR - все было нормально (последнее время стал вылетать посреди рендера, пришлось отказаться). Формат 1920х818. В чем может быть причина?



#504 corel

corel

    Есть камера, комп, а где поля ?

  • Участники
  • PipPipPipPip
  • 103 Сообщений:

Отправлено 03 Feb 2018 - 15:06

Вопрос включения QSV в премьере 11.1.2 решил, вручную прописав два пункта в файл консоли Debug Database.txt



#505 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 30 Mar 2018 - 12:06

Подскажите плз, для сборки видео в прокси до 1280х720, какой минимальной конфигурации ноута будет достаточно для комфортной работы "оффлайн" (только сборка и моушен, без эффектов). Но чтобы видео при перемотке не тормозило. И в каком кодеке это прокси лучше делать?



#506 PlayStation

PlayStation

    Сенсей для друзей по NLE

  • Писатели
  • PipPipPipPipPipPipPipPipPipPip
  • 1282 Сообщений:

Отправлено 30 Mar 2018 - 18:40

Я делаю прокси для в формате MPEG-2 720p. На монтаже просто летает, и создание прокси идёт быстро.



#507 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 31 Mar 2018 - 09:26

Я делаю прокси для в формате MPEG-2 720p. На монтаже просто летает, и создание прокси идёт быстро.

Для такого формата достаточно будет ноута c i3 - i5 с интегрированной графикой или GeForce 930 MX ?



#508 PlayStation

PlayStation

    Сенсей для друзей по NLE

  • Писатели
  • PipPipPipPipPipPipPipPipPipPip
  • 1282 Сообщений:

Отправлено 01 Apr 2018 - 08:41

Для такого формата достаточно будет ноута c i3 - i5 с интегрированной графикой или GeForce 930 MX ?

за глаза. Вопрос может возникнуть лишь при многослойном монтаже, когда монтажке понадобится одновременно подтягивать несколько слоёв. Но узким местом будет дисковая система, а не проц или видюха. На обычном компе с зеркала я монтировал 5 камер без затыков (больше камер просто не было)



#509 Muhin

Muhin

    не теряя ни секунды

  • Активные Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1789 Сообщений:

Отправлено 10 Apr 2018 - 19:35

Немножко обновились cc2018.

Premiere (12.1.0, 186)

https://helpx.adobe..../whats-new.html



#510 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 11 Apr 2018 - 00:29

Здорово, конечно... Но скриптов и "залипающих" хоткеев так и не предвидится (( Хотя в Афтере давно уже.



#511 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 11 Apr 2018 - 01:16

Но скриптов и "залипающих" хоткеев так и не предвидится

 

А это что?

https://premiereonscript.com/



#512 Kolobokk

Kolobokk

    Дали нажать на красную кнопку :)

  • Участники
  • PipPipPip
  • 91 Сообщений:

Отправлено 02 Jun 2018 - 08:46

Как в палитре Title Designer изменить масштаб изображения?

Спасибо!



#513 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 03 Jun 2018 - 02:37

Никак. Я при необходимости пользуюсь лупой.

Код на автохотки:

#NoEnv
SetBatchLines -1

CoordMode Mouse, Screen
OnExit GuiClose
zoom = 2 ; initial magnification, 1..32
antialize = 0
Rx = 128 ; half vertical/horizontal side of magnifier window
Ry = 128
Zx := Rx/zoom ; frame x/y size
Zy := Ry/zoom
; GUI to show the magnified image
Gui +AlwaysOnTop +Resize +ToolWindow
Gui Show, % "w" 2*Rx " h" 2*Ry " x0 y0", Magnifier
WinGet MagnifierID, id, Magnifier
WinSet Transparent, 255, Magnifier ; makes the window invisible to magnification
WinGet PrintSourceID, ID

hdd_frame := DllCall("GetDC", UInt, PrintSourceID)
hdc_frame := DllCall("GetDC", UInt, MagnifierID)

SetTimer Repaint, 50 ; flow through

Repaint:
MouseGetPos x, y
xz := In(x-Zx-6,0,A_ScreenWidth-2*Zx) ; keep the frame on screen
yz := In(y-Zy-6,0,A_ScreenHeight-2*Zy)
; WinMove Frame,,%xz%, %yz%, % 2*Zx, % 2*Zy
DllCall("gdi32.dll\StretchBlt", UInt,hdc_frame, Int,0, Int,0, Int,2*Rx, Int,2*Ry
, UInt,hdd_frame, UInt,xz, UInt,yz, Int,2*Zx, Int,2*Zy, UInt,0xCC0020) ; SRCCOPY
Return


GuiSize:
Rx := A_GuiWidth/2
Ry := A_GuiHeight/2
Zx := Rx/zoom
Zy := Ry/zoom
TrayTip,,% "Frame = " Round(2*Zx) " × " Round(2*Zy) "`nMagnified to = " A_GuiWidth "×" A_GuiHeight
Return

#a::
antialize := !antialize
DllCall( "gdi32.dll\SetStretchBltMode", "uint", hdc_frame, "int", 4*antialize ) ; Antializing ?
Return 

#x::
GuiClose:
DllCall("gdi32.dll\DeleteDC", UInt,hdc_frame )
DllCall("gdi32.dll\DeleteDC", UInt,hdd_frame )
ExitApp

#p::
MButton::
if paused = 
{
Gui, 2:Hide 
Gui, Hide 
SetTimer, Repaint, Off
paused = 1
}
else
{
Gui, 2:Show 
Gui, Show 
SetTimer, Repaint, 50
paused =
}
Return

^+Up::
^+Down::
^+WheelUp:: ; Ctrl+Shift+WheelUp to zoom in
^+WheelDown:: ; Ctrl+Shift+WheelUp to zoom out
If (zoom < 31 and ( A_ThisHotKey = "^+WheelUp" or A_ThisHotKey = "^+Up" ))
zoom *= 1.189207115 ; sqrt(sqrt(2))
If (zoom > 1 and ( A_ThisHotKey = "^+WheelDown" or A_ThisHotKey = "^+Down" ))
zoom /= 1.189207115
Zx := Rx/zoom
Zy := Ry/zoom
TrayTip,,% "Zoom = " Round(100*zoom) "%"
Return

In(x,a,b) { ; closest number to x in [a,b]
IfLess x,%a%, Return a
IfLess b,%x%, Return b
Return x
}


#514 Kolobokk

Kolobokk

    Дали нажать на красную кнопку :)

  • Участники
  • PipPipPip
  • 91 Сообщений:

Отправлено 03 Jun 2018 - 10:02

Malcev

Спасибо за ответ! Это ещё один повод чтобы отказаться от Title Designer, Я то в нём тайтлы и не делаю. Да тут использовал счётчик из Таймкода и подумал что проще будет прямо в Премьере к нему размерность добавить. И вдруг обнаружил, что не могу масштаб увеличить.

 

Подскажите, куда данный код нужно вставить, чтобы заработало. Боюсь, что здесь и кроме меня найдутся непрограммисты. :)



#515 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 03 Jun 2018 - 12:03

Скачиваете Download AutoHotkey Installer.

https://autohotkey.com/download/

Устанавливаете на компьютер, (лучше unicode 32 bit версию).

Создаете новый ahk файл, открываете его в  блокноте, вставляете в него этот код, сохраняете  и запускаете его, кликая по файлу 2 раза.

Шорткаты в нем:

ctrl+shift+вверх или ctrl+shift+колёсико мыши вверх - увеличение.

ctrl+shift+вниз или ctrl+shift+колёсико мыши вниз - уменьшение.

win+p или средня кнопка мыши - режим паузы.

win+a - включение/выключение сглаживания.

win+x - выход из программы.

При желании эти шорткаты можно изменить либо удалить.


Сообщение отредактировано Malcev: 03 Jun 2018 - 12:07


#516 Kolobokk

Kolobokk

    Дали нажать на красную кнопку :)

  • Участники
  • PipPipPip
  • 91 Сообщений:

Отправлено 03 Jun 2018 - 13:47

Malcev

Спасибо большое!

Я когда-то юзал этот Auto Hotkey для того чтобы цеплять целевой окно поверх других окон, так как привычный DeskPins на Win 8.1 не заработал. А на Win 10 он снова ожил. Так что я уже и забыл про эту программу. Но название знакомое, нашёл у себя среди портативных. Помню что там основная проблема была помнить все эти придуманные комбинации и обеспечить, чтобы они ни с чем не пересекались. Вот если бы в самом Premiere можно было подправить, чтобы стандартные хоткеи работали... Ещё Shift+3 раздражает, когда начинает перескакивать по секвенциям. Не всегда же следишь за фокусом.

 

Наверное всё же капшины лучше в Photoshop-е делать. Возможностей больше, да и корректнее PS работает. Одни из первых титров, которые я попытался сделать в Premiere, у меня не получились из-за того, что Premiere некорректно закругления делает. Меняешь форму бэкгрануда и радиусы перекашивает. Наверное там ещё много и других косяков. 

 

Ещё заметил, правда только в 2015.4, если надублировать много титров и потом тасовать их произвольно по проекту поверх секвенций-матрёшек, то Premiere может ответить чёрным экраном плеера (требуется перезагрузка Pr). С титрами, изготовленными в PS, такого пока не было ни разу. 



#517 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 03 Jun 2018 - 14:24

Вот этот код заблокирует shift+3 когда фокус будет на секвенции:

Setbatchlines -1
#If WinActive("ahk_class Premiere Pro") and !Timeline()
+3::return
#If

Timeline()
{
   Hwnd := WinExist("ahk_class Premiere Pro")
   MainMenu := DllCall("GetMenu", Ptr, Hwnd)
   SubMenu := DllCall("GetSubMenu", Ptr, MainMenu, Int, 3)   ;   Sequence
   SendMessage, 0x117, SubMenu, 12,, ahk_id %Hwnd% ; WM_INITMENUPOPUP to add edit
   return DllCall("GetMenuState", Ptr, SubMenu, UInt, 12, UInt, 0x400)
}


#518 Kolobokk

Kolobokk

    Дали нажать на красную кнопку :)

  • Участники
  • PipPipPip
  • 91 Сообщений:

Отправлено 03 Jun 2018 - 16:26

Malcev

Вот это супер! Это я попробую. Спасибо!



#519 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 18 Jun 2018 - 11:59

Подскажите, плз, где искать проблему, если 4 и 5 кнопка мыши не хотят работать правильно с автохотки: что бы ни назначил - включается скроллинг. Без автохотки они вообще ничего не делают.



#520 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 18 Jun 2018 - 13:46

Если при таком коде включается скроллинг, то надо

1) проверить не работают ли остальные автохоткискрипты в данный момент.

2) попробовать удалить драйвер мыши и поставить стандартный виндовский.

xbutton1::tooltip 1
xbutton2::tooltip 2

Сообщение отредактировано Malcev: 18 Jun 2018 - 13:47


#521 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 18 Jun 2018 - 14:32

1) Нет, только один скрипт (кнопки не прописаны)

2) Стандартный от Майкрософта. Раньше пробовал поставить драйвер 5-кнопочной А4 Х-7, но он почему-то мышку не увидел, и я его удалил (может, какие-то хвосты от него остались, но где?)

При запуске этого кода - горизонтальный скроллинг (в програмном окне - покадровое воспроизведение)



#522 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 18 Jun 2018 - 14:49

Сложно сказать.

tooltip при нажатии появляется?

Попробуйте подключить мышку к другому компьютеру и проверить как будет работать.



#523 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 22 Jun 2018 - 20:44

К сожалению, на другом компе эффект тот же. Но за совет спасибо



#524 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 23 Jun 2018 - 00:06

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



#525 nov

nov

    Есть камера, комп, а где поля ?

  • Писатели
  • PipPipPipPip
  • 190 Сообщений:

Отправлено 30 Jun 2018 - 22:52

Здравствуйте! Подскажите пожалуйста, как можно в папке проекта (FullHD) или при импорте в проект сделать так, чтобы все импортируемые DV файлы при попадании на сиквенцию были по размеру проекта. А то даже если делаю в настройках медиа scale to frame size. файлы становятся по размеру. но не 16\9, даже если изменить размер в настройках кадра на 16\9 (1,4587) все равно на сиквенции у него верх приходится делать 103%. Просто неудобно все старые транзишены и фоны по одному изменять размеры.



#526 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 02 Jul 2018 - 00:43

У меня такого не наблюдается.

Но если вы хотите автоматизировать процесс, чтобы при попадании дв клипа на таймлайн автоматически его размер увеличивался на 103%, то нужно отлавливать событие появления клипа на линейке.

Вроде в последнем апи есть что-то примерно такое, но я не тестировал:

    myOnProjectChanged : function(documentID){
        var msg = 'Project with ID ' + documentID + ' Changed.';
        // Commented out, as this happens a LOT.
        // $._PPP_.updateEventPanel(msg);
    },

    registerProjectChangedFxn : function() {
        app.bind('onProjectChanged', $._PPP_.myOnProjectChanged);
},

https://github.com/A...miere.jsx#L1668

Если же отловить событие не удастся, то можно отлавливать появления окошка экспорта видео и после этого уже пробегать по элементам секвенции.

https://premiere-scr...readthedocs.io/

Либо если со скриптингом возиться не хочется, то вы можете иметь проект заготовку со всеми своими футажами к которым применен мастер-эффект transform со 103%.


Сообщение отредактировано Malcev: 02 Jul 2018 - 00:46


#527 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 02 Jul 2018 - 10:29

Если речь о постоянно используемых клипах, то почему бы не создать из них отдельную секвенцию, выровнять размеры, а потом копипастить в рабочую. Или пересчитать в новые полноразмернык клипы.

 

И вопрос. Скажите, а автохотки может различать окна Премьера? Я бы хотел, чтобы скрипт работал только в таймлайне - постоянно забываю включать-выключать суспенд )


Сообщение отредактировано abg: 02 Jul 2018 - 10:30


#528 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 02 Jul 2018 - 14:02

Если речь о постоянно используемых клипах, то почему бы не создать из них отдельную секвенцию, выровнять размеры, а потом копипастить в рабочую.

Это неудобно. Обратите внимание на вариант с использованием master effect и transform.

 

Я бы хотел, чтобы скрипт работал только в таймлайне

Что вы имеете Вы имеете в виду? Срабатывание скрипта, когда мышка находится над окном таймлайна или когда таймлайн активирован?


Сообщение отредактировано Malcev: 02 Jul 2018 - 14:02


#529 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 02 Jul 2018 - 15:52

Когда активирован - чтобы шорткаты, которые запускают скрипты при работе в таймлайне, были обычными буквами, если мне нужно изменить название клипа в окне проекта. Фактически нужно вот это  #IfWinActive ahk_class Premiere Pro, но только для таймлайна



#530 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 02 Jul 2018 - 15:58

517 пост.



#531 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 02 Jul 2018 - 16:28

Спасибо, бум пробовать. Еще бы научиться все это понимать )



#532 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 02 Jul 2018 - 16:33

Определяем, что активирован таймлайн через получение состояния пункта меню add edit.

Так как этот пункт активен только при активном таймлайне.

Для этого обращаемся к следующим Виндовс АПИ функциям:

https://docs.microso...winuser-getmenu

https://docs.microso...user-getsubmenu

https://docs.microso...m-initmenupopup

https://docs.microso...er-getmenustate


Сообщение отредактировано Malcev: 02 Jul 2018 - 16:37


#533 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 03 Jul 2018 - 16:59

И еще раз спасибо ). А получить и записать в переменную количество выделенных клипов (отображается в панели Инфо) уже никак нельзя?



#534 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 04 Jul 2018 - 16:24

Можно. Я вижу 3 способа:

1) Запускать через ahk extendscript, который после выполнения создаст текстовый файл с результатом, а ahk-script прочитает его и удалит.

2) Через Clipboard (копировать выделенные клипы и парсить их).

3) Получать данные из памяти процесса (тут уже нужны хакерские навыки).

А зачем вам это надо?

У премьера есть такой баг - при выделении клипов, рисуя прямоугольник, результат отличается от выделения через ctrl+A, либо через track select tool, либо через shift+MouseClick.

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


Сообщение отредактировано Malcev: 04 Jul 2018 - 16:49


#535 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 04 Jul 2018 - 19:04

1) Что такое ahk extendscript пока еще не знаю )

2) А разве АНК видит скопированные клипы? ErrorLevel  при попытке такого копирования дает +.

Зачем надо? Корректировочный слой нарезать по склейкам в нижнем треке, пробелы между клипами удалять итп. Сейчас количество лупов задаю через инпутбокс, что вполне приемлемо, но ведь всегда хочется полной автоматизации )



#536 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 04 Jul 2018 - 19:53

Через клипбоард вроде так получается:
SetBatchLines -1
f12::
count := 0, Clipboard := ""
send ^{vk43} ; c
ClipWait, 1, 1
if ErrorLevel = 1
{
   MsgBox, Буфер обмена пуст!
   return
}
While !DllCall("OpenClipboard", "Ptr", 0)
   sleep 20
formatCount := DllCall("CountClipboardFormats"), format:=0
Loop % formatCount
{
   format := DllCall("EnumClipboardFormats", "UInt", format)
   VarSetCapacity(formatName, 512)
   DllCall("GetClipboardFormatName", "Uint", format, "str", formatName, "Uint", 256)
   if (formatName = "PProAE/Exchange/TrackItem")
      break
}
hText := DllCall("GetClipboardData", "UInt", format, "UInt")
pText := DllCall("GlobalLock", "UInt", hText, "UInt")
DataText := StrGet(pText, "UTF-8")
DllCall("GlobalUnlock", "UInt", hText)
DllCall("CloseClipboard")

; Sequence -> VideoTrackGroup / AudioTrackGroup -> VideoClipTrack / AudioClipTrack
Pos := 1, match := ""
While Pos := RegexMatch(DataText, "s)<Sequence ObjectUID=.+?</Sequence>", match, Pos+StrLen(match))
{
   If RegexMatch(match, "s)<Second ObjectRef=""(.+?)"".+?<Second ObjectRef=""(.+?)"".+?<Name>CopyPasteSequence</Name>", matchh)
   {
      ObjectID1 := matchh1, ObjectID2 := matchh2
      break
   }
}
loop 2
{
   If (A_Index = 1)
      AV := "Audio"
   else
      AV := "Video"
   RegexMatch(DataText, "s)<" AV "TrackGroup ObjectID=""" ObjectID%A_Index% """.+?</" AV "TrackGroup>", oTrackGroup)
   RegexMatch(oTrackGroup, "s)<Tracks Version="".+?</Tracks>", oTracks)
   Pos := 1, match := ""
   While Pos := RegexMatch(oTracks, "s)<Track Index=""\d+?"" ObjectURef=""(.+?)""", match, Pos+StrLen(match))
   {
      RegexMatch(DataText, "s)<" AV "ClipTrack ObjectUID=""" match1 """.+?</" AV "ClipTrack>", oClipTrack)
      RegexMatch(oClipTrack, "s)<ClipItems Version="".+?</ClipItems>", oClipItems)
      Poss := 1, matchh := ""
      While Poss := RegexMatch(oClipItems, "s)<TrackItem Index=""", matchh, Poss+StrLen(matchh))
         count++
   }
}
msgbox % count
Если делать через ExtendScript, то нужно установить Adobe ExtendScript Toolkit CC.
Поместить этот скрипт в C:\Users\username\Documents\Adobe Scripts\count.jsx
#target premierePro
var count = 0;
var videoTracks = app.project.activeSequence.videoTracks;
for (var a=0;a<videoTracks.numTracks;a++){
    var clips = videoTracks[a].clips;
    for (var b=0;b<clips.numItems;b++){
        if (clips[b].isSelected()==true){
            count++
        }
    }
}
var audioTracks = app.project.activeSequence.audioTracks;
for (var a=0;a<audioTracks.numTracks;a++){
    var clips = audioTracks[a].clips;
    for (var b=0;b<clips.numItems;b++){
        if (clips[b].isSelected()==true){
            count++
        }
    }
}

var myNewFile = new File("C:\\test\\info.txt");
myNewFile.open('w');
myNewFile.write(count);
myNewFile.close();
где var myNewFile = new File("C:\\test\\info.txt"); путь где лежит ahk файл и будет создаваться info.txt.
 
AHK файл такой:
script := A_MyDocuments "\Adobe Scripts\count.jsx"
info := "info.txt"
ExtendScriptToolkit := "C:\Program Files (x86)\Adobe\Adobe ExtendScript Toolkit CC\ExtendScript Toolkit.exe"

f11::
FileDelete, % info
Run, "%ExtendScriptToolkit%" -run "%script%"
loop
{
   FileRead, count, % info
   If (count != "")
   {
      FileDelete, % info
      break
   }
   sleep 50
}
msgbox % count
Кстати посмотрел ExtendScript в будущем весьма разовьётся - можно будет эффекты накладывать, резать, тримить...

Сообщение отредактировано Malcev: 06 Jul 2018 - 15:33


#537 Yuri_Teplo

Yuri_Teplo

    Сенсей для друзей по NLE

  • Писатели
  • PipPipPipPipPipPipPipPipPipPip
  • 1162 Сообщений:
  • место работы:

Отправлено 04 Jul 2018 - 21:53

вопрос.несколько несерьезный но всё-же.

как по вашему опыту по качеству кодирует последний MediaEncoder CC2018 в H264 mp4   

с профилем 4.2 High Quality 1080p25 CBR 23Mbps .Software only.

я просто перестал кодировать чем то еще из за скорости..

раньше Карбоном , но он теперь некоторые MXF Op1A_DNxHR не ест, а во вторых дююже медленно )

или не заморачиваться)) кто чем щас кодирует?


Сообщение отредактировано Yuri_Teplo: 04 Jul 2018 - 22:02


#538 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 08 Jul 2018 - 06:25

А вот так можно получать количество выделений напрямую из памяти процесса.
Адреса и оффсеты получил через Cheat Engine для Premiere CC 2017.1.2.
Autohotkey должен быть 64-бит.
Скрипт разбил в 3 поста - в один не вмещается.
setbatchlines -1
f11::
if !premiere.isHandleValid()
{
   premiere := new _ClassMemory("ahk_exe Adobe Premiere Pro.exe")
   pointerBase := premiere.getModuleBaseAddress("HandlerInfo.dll")
}
msgbox % premiere.readString(pointerBase+0x671F8, length := 0, encoding := "utf-16", 0x58, 0x50, 0x530, 0x0)
return






/*
    A basic memory class by RHCP:
    This is a wrapper for commonly used read and write memory functions.
    It also contains a variety of pattern scan functions.
    This class allows scripts to read/write integers and strings of various types. 
    Pointer addresses can easily be read/written by passing the base address and offsets to the various read/write functions.
    
    Process handles are kept open between reads. This increases speed.
    However, if a program closes/restarts then the process handle will become invalid
    and you will need to re-open another handle (blank/destroy the object and recreate it)
    isHandleValid() can be used to check if a handle is still active/valid.
    read(), readString(), write(), and writeString() can be used to read and write memory addresses respectively.
    readRaw() can be used to dump large chunks of memory, this is considerably faster when
    reading data from a large structure compared to repeated calls to read(). 
    For example, reading a single UInt takes approximately the same amount of time as reading 1000 bytes via readRaw().
    Although, most people wouldn't notice the performance difference. This does however require you 
    to retrieve the values using AHK's numget()/strGet() from the dumped memory.
    In a similar fashion writeRaw() allows a buffer to be be written in a single operation. 
    
    When the new operator is used this class returns an object which can be used to read that process's 
    memory space.To read another process simply create another object.
    Process handles are automatically closed when the script exits/restarts or when you free the object.
    **Notes:
        This was initially written for 32 bit target processes, however the various read/write functions
        should now completely support pointers in 64 bit target applications. The only caveat is that the AHK exe must also be 64 bit.  
        If AHK is 32 bit and the target application is 64 bit you can still read, write, and use pointers, so long as the addresses
        fit inside a 4 byte pointer, i.e. The maximum address is limited to the 32 bit range.
        The various pattern scan functions are intended to be used on 32 bit target applications, however: 
            - A 32 bit AHK script can perform pattern scans on a 32 bit target application.
            - A 32 bit AHK script may be able to perform pattern scans on a 64 bit process, providing the addresses fall within the 32 bit range.             
            - A 64 bit AHK script should be able to perform pattern scans on a 32 or 64 bit target application without issue. 
        If the target process has admin privileges, then the AHK script will also require admin privileges. 
        AHK doesn't support unsigned 64bit ints, you can however read them as Int64 and interpret negative values as large numbers.       
  
    Commonly used methods:
        read()
        readString()
        readRaw()
        write()
        writeString()
        writeRaw()
        isHandleValid() 
        getModuleBaseAddress()
    Less commonly used methods:
        getProcessBaseAddress()
        hexStringToPattern()
        stringToPattern()    
        modulePatternScan()
        processPatternScan()
        addressPatternScan()
        rawPatternScan()
        getModules()
        numberOfBytesRead()
        numberOfBytesWritten()
        suspend()
        resume()
    Internal methods: (some may be useful when directly called)
        getAddressFromOffsets() ; This will return the final memory address of a pointer. This is useful if the pointed address only changes on startup or map/level change and you want to eliminate the overhead associated with pointers.
        isTargetProcess64Bit()
        pointer() 
        GetModuleFileNameEx()
        EnumProcessModulesEx()
        GetModuleInformation()
        getNeedleFromAOBPattern()
        virtualQueryEx()
        patternScan()
        bufferScanForMaskedPattern()
        openProcess()
        closeHandle() 
    Useful properties:  (Do not modify the values of these properties - they are set automatically)
        baseAddress             ; The base address of the target process
        hProcess                ; The handle to the target process
        PID                     ; The PID of the target process
        currentProgram          ; The string the user used to identify the target process e.g. "ahk_exe calc.exe" 
        isTarget64bit           ; True if target process is 64 bit, otherwise false
        readStringLastError     ; Used to check for success/failure when reading a string
     Useful editable properties:
        insertNullTerminator    ; Determines if a null terminator is inserted when writing strings.
               
    Usage:
        ; **Note: If you wish to try this calc example, consider using the 32 bit version of calc.exe - 
        ;         which is in C:\Windows\SysWOW64\calc.exe on win7 64 bit systems.
        ; The contents of this file can be copied directly into your script. Alternately, you can copy the classMemory.ahk file into your library folder,
        ; in which case you will need to use the #include directive in your script i.e. 
            #Include <classMemory>
        
        ; You can use this code to check if you have installed the class correctly.
            if (_ClassMemory.__Class != "_ClassMemory")
            {
                msgbox class memory not correctly installed. Or the (global class) variable "_ClassMemory" has been overwritten
                ExitApp
            }
        ; Open a process with sufficient access to read and write memory addresses (this is required before you can use the other functions)
        ; You only need to do this once. But if the process closes/restarts, then you will need to perform this step again. Refer to the notes section below.
        ; Also, if the target process is running as admin, then the script will also require admin rights!
        ; Note: The program identifier can be any AHK windowTitle i.e.ahk_exe, ahk_class, ahk_pid, or simply the window title.
        ; hProcessCopy is an optional variable in which the opened handled is stored. 
          
            calc := new _ClassMemory("ahk_exe calc.exe", "", hProcessCopy) 
       
        ; Check if the above method was successful.
            if !isObject(calc) 
            {
                msgbox failed to open a handle
                if (hProcessCopy = 0)
                    msgbox The program isn't running (not found) or you passed an incorrect program identifier parameter. In some cases _ClassMemory.setSeDebugPrivilege() may be required. 
                else if (hProcessCopy = "")
                    msgbox OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. _ClassMemory.setSeDebugPrivilege() may also be required. Consult A_LastError for more information.
                ExitApp
            }
        ; Get the process's base address.
        ; When using the new operator this property is automatically set to the result of getModuleBaseAddress() or getProcessBaseAddress();
        ; the specific method used depends on the bitness of the target application and AHK.
        ; If the returned address is incorrect and the target application is 64 bit, but AHK is 32 bit, try using the 64 bit version of AHK.
            msgbox % calc.BaseAddress 
        
        ; Get the base address of a specific module.
            msgbox % calc.getModuleBaseAddress("GDI32.dll")
        ; The rest of these examples are just for illustration (the addresses specified are probably not valid).
        ; You can use cheat engine to find real addresses to read and write for testing purposes.
        
        ; Write 1234 as a UInt at address 0x0016CB60.
            calc.write(0x0016CB60, 1234, "UInt")
        ; Read a UInt.
            value := calc.read(0x0016CB60, "UInt")
        ; Read a pointer with offsets 0x20 and 0x15C which points to a UChar. 
            value := calc.read(pointerBase, "UChar", 0x20, 0x15C)
        ; Note: read(), readString(), readRaw(), write(), writeString(), and writeRaw() all support pointers/offsets.
        ; An array of pointers can be passed directly, i.e.
            arrayPointerOffsets := [0x20, 0x15C]
            value := calc.read(pointerBase, "UChar", arrayPointerOffsets*)
        ; Or they can be entered manually.
            value := calc.read(pointerBase, "UChar", 0x20, 0x15C)
        ; You can also pass all the parameters directly, i.e.
            aMyPointer := [pointerBase, "UChar", 0x20, 0x15C]
            value := calc.read(aMyPointer*)
        
        ; Read a utf-16 null terminated string of unknown size at address 0x1234556 - the function will read until the null terminator is found or something goes wrong.
            string := calc.readString(0x1234556, length := 0, encoding := "utf-16")
        
        ; Read a utf-8 encoded string which is 12 bytes long at address 0x1234556.
            string := calc.readString(0x1234556, 12)
        ; By default a null terminator is included at the end of written strings for writeString().
        ; The nullterminator property can be used to change this.
            _ClassMemory.insertNullTerminator := False ; This will change the property for all processes
            calc.insertNullTerminator := False ; Changes the property for just this process     
    Notes: 
        If the target process exits and then starts again (or restarts) you will need to free the derived object and then use the new operator to create a new object i.e. 
        calc := [] ; or calc := "" ; free the object. This is actually optional if using the line below, as the line below would free the previous derived object calc prior to initialising the new copy.
        calc := new _ClassMemory("ahk_exe calc.exe") ; Create a new derived object to read calc's memory.
        isHandleValid() can be used to check if a target process has closed or restarted.
*/


class _ClassMemory
{
    ; List of useful accessible values. Some of these inherited values (the non objects) are set when the new operator is used.
    static baseAddress, hProcess, PID, currentProgram
    , insertNullTerminator := True
    , readStringLastError := False
    , isTarget64bit := False
    , ptrType := "UInt"
    , aTypeSize := {    "UChar":    1,  "Char":     1
                    ,   "UShort":   2,  "Short":    2
                    ,   "UInt":     4,  "Int":      4
                    ,   "UFloat":   4,  "Float":    4
                    ,   "Int64":    8,  "Double":   8}  
    , aRights := {  "PROCESS_ALL_ACCESS": 0x001F0FFF
                ,   "PROCESS_CREATE_PROCESS": 0x0080
                ,   "PROCESS_CREATE_THREAD": 0x0002
                ,   "PROCESS_DUP_HANDLE": 0x0040
                ,   "PROCESS_QUERY_INFORMATION": 0x0400
                ,   "PROCESS_QUERY_LIMITED_INFORMATION": 0x1000
                ,   "PROCESS_SET_INFORMATION": 0x0200
                ,   "PROCESS_SET_QUOTA": 0x0100
                ,   "PROCESS_SUSPEND_RESUME": 0x0800
                ,   "PROCESS_TERMINATE": 0x0001
                ,   "PROCESS_VM_OPERATION": 0x0008
                ,   "PROCESS_VM_READ": 0x0010
                ,   "PROCESS_VM_WRITE": 0x0020
                ,   "SYNCHRONIZE": 0x00100000}




    ; Method:    __new(program, dwDesiredAccess := "", byRef handle := "", windowMatchMode := 3)
    ; Example:  derivedObject := new _ClassMemory("ahk_exe calc.exe")
    ;           This is the first method which should be called when trying to access a program's memory. 
    ;           If the process is successfully opened, an object is returned which can be used to read that processes memory space.
    ;           [derivedObject].hProcess stores the opened handle.
    ;           If the target process closes and re-opens, simply free the derived object and use the new operator again to open a new handle.
    ; Parameters:
    ;   program             The program to be opened. This can be any AHK windowTitle identifier, such as 
    ;                       ahk_exe, ahk_class, ahk_pid, or simply the window title. e.g. "ahk_exe calc.exe" or "Calculator".
    ;                       It's safer not to use the window title, as some things can have the same window title e.g. an open folder called "Starcraft II"
    ;                       would have the same window title as the game itself.
    ;                       *'DetectHiddenWindows, On' is required for hidden windows*
    ;   dwDesiredAccess     The access rights requested when opening the process.
    ;                       If this parameter is null the process will be opened with the following rights
    ;                       PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_READ, PROCESS_VM_WRITE, & SYNCHRONIZE
    ;                       This access level is sufficient to allow all of the methods in this class to work.
    ;                       Specific process access rights are listed here http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx                           
    ;   handle (Output)     Optional variable in which a copy of the opened processes handle will be stored.
    ;                       Values:
    ;                           Null    OpenProcess failed. The script may need to be run with admin rights admin, 
    ;                                   and/or with the use of _ClassMemory.setSeDebugPrivilege(). Consult A_LastError for more information.
    ;                           0       The program isn't running (not found) or you passed an incorrect program identifier parameter.
    ;                                   In some cases _ClassMemory.setSeDebugPrivilege() may be required.
    ;                           Positive Integer    A handle to the process. (Success)
    ;   windowMatchMode -   Determines the matching mode used when finding the program (windowTitle).
    ;                       The default value is 3 i.e. an exact match. Refer to AHK's setTitleMathMode for more information.
    ; Return Values: 
    ;   Object  On success an object is returned which can be used to read the processes memory.
    ;   Null    Failure. A_LastError and the optional handle parameter can be consulted for more information. 




    __new(program, dwDesiredAccess := "", byRef handle := "", windowMatchMode := 3)
    {         
        if this.PID := handle := this.findPID(program, windowMatchMode) ; set handle to 0 if program not found
        {
            ; This default access level is sufficient to read and write memory addresses, and to perform pattern scans.
            ; if the program is run using admin privileges, then this script will also need admin privileges
            if dwDesiredAccess is not integer       
                dwDesiredAccess := this.aRights.PROCESS_QUERY_INFORMATION | this.aRights.PROCESS_VM_OPERATION | this.aRights.PROCESS_VM_READ | this.aRights.PROCESS_VM_WRITE
            dwDesiredAccess |= this.aRights.SYNCHRONIZE ; add SYNCHRONIZE to all handles to allow isHandleValid() to work


            if this.hProcess := handle := this.OpenProcess(this.PID, dwDesiredAccess) ; NULL/Blank if failed to open process for some reason
            {
                this.pNumberOfBytesRead := DllCall("GlobalAlloc", "UInt", 0x0040, "Ptr", A_PtrSize, "Ptr") ; 0x0040 initialise to 0
                this.pNumberOfBytesWritten := DllCall("GlobalAlloc", "UInt", 0x0040, "Ptr", A_PtrSize, "Ptr") ; initialise to 0


                this.readStringLastError := False
                this.currentProgram := program
                if this.isTarget64bit := this.isTargetProcess64Bit(this.PID, this.hProcess, dwDesiredAccess)
                    this.ptrType := "Int64"
                else this.ptrType := "UInt" ; If false or Null (fails) assume 32bit
                
                ; if script is 64 bit, getModuleBaseAddress() should always work
                ; if target app is truly 32 bit, then getModuleBaseAddress()
                ; will work when script is 32 bit
                if (A_PtrSize != 4 || !this.isTarget64bit)
                    this.BaseAddress := this.getModuleBaseAddress()


                ; If the above failed or wasn't called, fall back to alternate method    
                if this.BaseAddress < 0 || !this.BaseAddress
                    this.BaseAddress := this.getProcessBaseAddress(program, windowMatchMode)            


                return this
            }
        }
        return
    }


    __delete()
    {
        this.closeHandle(this.hProcess)
        if this.pNumberOfBytesRead
            DllCall("GlobalFree", "Ptr", this.pNumberOfBytesRead)
        if this.pNumberOfBytesWritten
            DllCall("GlobalFree", "Ptr", this.pNumberOfBytesWritten)
        return
    }


    version()
    {
        return 2.91
    }   


    findPID(program, windowMatchMode := "3")
    {
        ; If user passes an AHK_PID, don't bother searching. There are cases where searching windows for PIDs 
        ; wont work - console apps
        if RegExMatch(program, "i)\s*AHK_PID\s+(0x[[:xdigit:]]+|\d+)", pid)
            return pid1
        if windowMatchMode
        {
            ; This is a string and will not contain the 0x prefix
            mode := A_TitleMatchMode
            ; remove hex prefix as SetTitleMatchMode will throw a run time error. This will occur if integer mode is set to hex and user passed an int (unquoted)
            StringReplace, windowMatchMode, windowMatchMode, 0x 
            SetTitleMatchMode, %windowMatchMode%
        }
        WinGet, pid, pid, %program%
        if windowMatchMode
            SetTitleMatchMode, %mode%    ; In case executed in autoexec


        ; If use 'ahk_exe test.exe' and winget fails (which can happen when setSeDebugPrivilege is required),
        ; try using the process command. When it fails due to setSeDebugPrivilege, setSeDebugPrivilege will still be required to openProcess
        ; This should also work for apps without windows.
        if (!pid && RegExMatch(program, "i)\bAHK_EXE\b\s*(.*)", fileName))
        {
            ; remove any trailing AHK_XXX arguments
            filename := RegExReplace(filename1, "i)\bahk_(class|id|pid|group)\b.*", "")
            filename := trim(filename)    ; extra spaces will make process command fail       
            ; AHK_EXE can be the full path, so just get filename
            SplitPath, fileName , fileName
            if (fileName) ; if filename blank, scripts own pid is returned
            {
                process, Exist, %fileName%
                pid := ErrorLevel
            }
        }


        return pid ? pid : 0 ; PID is null on fail, return 0
    }
    ; Method:   isHandleValid()
    ;           This method provides a means to check if the internal process handle is still valid
    ;           or in other words, the specific target application instance (which you have been reading from)
    ;           has closed or restarted.
    ;           For example, if the target application closes or restarts the handle will become invalid
    ;           and subsequent calls to this method will return false.
    ;
    ; Return Values: 
    ;   True    The handle is valid.
    ;   False   The handle is not valid. 
    ;
    ; Notes: 
    ;   This operation requires a handle with SYNCHRONIZE access rights.
    ;   All handles, even user specified ones are opened with the SYNCHRONIZE access right.


    isHandleValid()
    {
        return 0x102 = DllCall("WaitForSingleObject", "Ptr", this.hProcess, "UInt", 0)
        ; WaitForSingleObject return values
        ; -1 if called with null hProcess (sets lastError to 6 - invalid handle)
        ; 258 / 0x102 WAIT_TIMEOUT - if handle is valid (process still running)
        ; 0  WAIT_OBJECT_0 - if process has terminated        
    }


    ; Method:   openProcess(PID, dwDesiredAccess)
    ;           ***Note:    This is an internal method which shouldn't be called directly unless you absolutely know what you are doing.
    ;                       This is because the new operator, in addition to calling this method also sets other values
    ;                       which are required for the other methods to work correctly. 
    ; Parameters:
    ;   PID                 The Process ID of the target process.  
    ;   dwDesiredAccess     The access rights requested when opening the process.
    ;                       Specific process access rights are listed here http://msdn.microsoft.com/en-us/library/windows/desktop/ms684880(v=vs.85).aspx                           
    ; Return Values: 
    ;   Null/blank          OpenProcess failed. If the target process has admin rights, then the script also needs to be ran as admin. 
    ;                       _ClassMemory.setSeDebugPrivilege() may also be required.
    ;   Positive integer    A handle to the process.


    openProcess(PID, dwDesiredAccess)
    {
        r := DllCall("OpenProcess", "UInt", dwDesiredAccess, "Int", False, "UInt", PID, "Ptr")
        ; if it fails with 0x5 ERROR_ACCESS_DENIED, try enabling privilege ... lots of users never try this.
        ; there may be other errors which also require DebugPrivilege....
        if (!r && A_LastError = 5)
        {
            this.setSeDebugPrivilege(true) ; no harm in enabling it if it is already enabled by user
            if (r2 := DllCall("OpenProcess", "UInt", dwDesiredAccess, "Int", False, "UInt", PID, "Ptr"))
                return r2
            DllCall("SetLastError", "UInt", 5) ; restore original error if it doesnt work
        }
        ; If fails with 0x5 ERROR_ACCESS_DENIED (when setSeDebugPrivilege() is req.), the func. returns 0 rather than null!! Set it to null.
        ; If fails for another reason, then it is null.
        return r ? r : ""
    }   


    ; Method:   closeHandle(hProcess)
    ;           Note:   This is an internal method which is automatically called when the script exits or the derived object is freed/destroyed.
    ;                   There is no need to call this method directly. If you wish to close the handle simply free the derived object. 
    ;                   i.e. derivedObject := [] ; or derivedObject := ""
    ; Parameters:
    ;   hProcess        The handle to the process, as returned by openProcess().
    ; Return Values: 
    ;   Non-Zero        Success
    ;   0               Failure


    closeHandle(hProcess)
    {
        return DllCall("CloseHandle", "Ptr", hProcess)
    }


    ; Methods:      numberOfBytesRead() / numberOfBytesWritten()
    ;               Returns the number of bytes read or written by the last ReadProcessMemory or WriteProcessMemory operation. 
    ;             
    ; Return Values: 
    ;   zero or positive value      Number of bytes read/written
    ;   -1                          Failure. Shouldn't occur 


    numberOfBytesRead()
    {
        return !this.pNumberOfBytesRead ? -1 : NumGet(this.pNumberOfBytesRead+0, "Ptr")
    }
    numberOfBytesWritten()
    {
        return !this.pNumberOfBytesWritten ? -1 : NumGet(this.pNumberOfBytesWritten+0, "Ptr")
    }




    ; Method:   read(address, type := "UInt", aOffsets*)
    ;           Reads various integer type values
    ; Parameters:
    ;       address -   The memory address of the value or if using the offset parameter, 
    ;                   the base address of the pointer.
    ;       type    -   The integer type. 
    ;                   Valid types are UChar, Char, UShort, Short, UInt, Int, Float, Int64 and Double. 
    ;                   Note: Types must not contain spaces i.e. " UInt" or "UInt " will not work. 
    ;                   When an invalid type is passed the method returns NULL and sets ErrorLevel to -2
    ;       aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
    ;                   The address (base address) and offsets should point to the memory address which holds the integer.  
    ; Return Values:
    ;       integer -   Indicates success.
    ;       Null    -   Indicates failure. Check ErrorLevel and A_LastError for more information.
    ;       Note:       Since the returned integer value may be 0, to check for success/failure compare the result
    ;                   against null i.e. if (result = "") then an error has occurred.
    ;                   When reading doubles, adjusting "SetFormat, float, totalWidth.DecimalPlaces"
    ;                   may be required depending on your requirements.


    read(address, type := "UInt", aOffsets*)
    {
        ; If invalid type RPM() returns success (as bytes to read resolves to null in dllCall())
        ; so set errorlevel to invalid parameter for DLLCall() i.e. -2
        if !this.aTypeSize.hasKey(type)
            return "", ErrorLevel := -2 
        if DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, type "*", result, "Ptr", this.aTypeSize[type], "Ptr", this.pNumberOfBytesRead)
            return result
        return        
    }


    ; Method:   readRaw(address, byRef buffer, bytes := 4, aOffsets*)
    ;           Reads an area of the processes memory and stores it in the buffer variable
    ; Parameters:
    ;       address  -  The memory address of the area to read or if using the offsets parameter
    ;                   the base address of the pointer which points to the memory region.
    ;       buffer   -  The unquoted variable name for the buffer. This variable will receive the contents from the address space.
    ;                   This method calls varsetCapcity() to ensure the variable has an adequate size to perform the operation. 
    ;                   If the variable already has a larger capacity (from a previous call to varsetcapcity()), then it will not be shrunk. 
    ;                   Therefore it is the callers responsibility to ensure that any subsequent actions performed on the buffer variable
    ;                   do not exceed the bytes which have been read - as these remaining bytes could contain anything.
    ;       bytes   -   The number of bytes to be read.          
    ;       aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
    ;                   The address (base address) and offsets should point to the memory address which is to be read
    ; Return Values:
    ;       Non Zero -   Indicates success.
    ;       Zero     -   Indicates failure. Check errorLevel and A_LastError for more information
    ; 
    ; Notes:            The contents of the buffer may then be retrieved using AHK's NumGet() and StrGet() functions.           
    ;                   This method offers significant (~30% and up) performance boost when reading large areas of memory. 
    ;                   As calling ReadProcessMemory for four bytes takes a similar amount of time as it does for 1,000 bytes.                


    readRaw(address, byRef buffer, bytes := 4, aOffsets*)
    {
        VarSetCapacity(buffer, bytes)
        return DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, "Ptr", &buffer, "Ptr", bytes, "Ptr", this.pNumberOfBytesRead)
    }


    ; Method:   readString(address, sizeBytes := 0, encoding := "utf-8", aOffsets*)
    ;           Reads string values of various encoding types
    ; Parameters:
    ;       address -   The memory address of the value or if using the offset parameter, 
    ;                   the base address of the pointer.
    ;       sizeBytes - The size (in bytes) of the string to be read.
    ;                   If zero is passed, then the function will read each character until a null terminator is found
    ;                   and then returns the entire string.
    ;       encoding -  This refers to how the string is stored in the program's memory.
    ;                   UTF-8 and UTF-16 are common. Refer to the AHK manual for other encoding types.
    ;       aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
    ;                   The address (base address) and offsets should point to the memory address which holds the string.                             
    ;                   
    ;  Return Values:
    ;       String -    On failure an empty (null) string is always returned. Since it's possible for the actual string 
    ;                   being read to be null (empty), then a null return value should not be used to determine failure of the method.
    ;                   Instead the property [derivedObject].ReadStringLastError can be used to check for success/failure.
    ;                   This property is set to 0 on success and 1 on failure. On failure ErrorLevel and A_LastError should be consulted
    ;                   for more information.
    ; Notes:
    ;       For best performance use the sizeBytes parameter to specify the exact size of the string. 
    ;       If the exact size is not known and the string is null terminated, then specifying the maximum
    ;       possible size of the string will yield the same performance.  
    ;       If neither the actual or maximum size is known and the string is null terminated, then specifying
    ;       zero for the sizeBytes parameter is fine. Generally speaking for all intents and purposes the performance difference is
    ;       inconsequential.  


    readString(address, sizeBytes := 0, encoding := "UTF-8", aOffsets*)
    {
        bufferSize := VarSetCapacity(buffer, sizeBytes ? sizeBytes : 100, 0)
        this.ReadStringLastError := False
        if aOffsets.maxIndex()
            address := this.getAddressFromOffsets(address, aOffsets*)
        if !sizeBytes  ; read until null terminator is found or something goes wrong
        {
            ; Even if there are multi-byte-characters (bigger than the encodingSize i.e. surrogates) in the string, when reading in encodingSize byte chunks they will never register as null (as they will have bits set on those bytes)
            if (encoding = "utf-16" || encoding = "cp1200")
                encodingSize := 2, charType := "UShort", loopCount := 2
            else encodingSize := 1, charType := "Char", loopCount := 4
            Loop
            {   ; Lets save a few reads by reading in 4 byte chunks
                if !DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", address + ((outterIndex := A_index) - 1) * 4, "Ptr", &buffer, "Ptr", 4, "Ptr", this.pNumberOfBytesRead) || ErrorLevel
                    return "", this.ReadStringLastError := True 
                else loop, %loopCount%
                {
                    if NumGet(buffer, (A_Index - 1) * encodingSize, charType) = 0 ; NULL terminator
                    {
                        if (bufferSize < sizeBytes := outterIndex * 4 - (4 - A_Index * encodingSize)) 
                            VarSetCapacity(buffer, sizeBytes)
                        break, 2
                    }  
                } 
            }
        }
        if DllCall("ReadProcessMemory", "Ptr", this.hProcess, "Ptr", address, "Ptr", &buffer, "Ptr", sizeBytes, "Ptr", this.pNumberOfBytesRead)   
            return StrGet(&buffer,, encoding)  
        return "", this.ReadStringLastError := True             
    }


    ; Method:  writeString(address, string, encoding := "utf-8", aOffsets*)
    ;          Encodes and then writes a string to the process.
    ; Parameters:
    ;       address -   The memory address to which data will be written or if using the offset parameter, 
    ;                   the base address of the pointer.
    ;       string -    The string to be written.
    ;       encoding -  This refers to how the string is to be stored in the program's memory.
    ;                   UTF-8 and UTF-16 are common. Refer to the AHK manual for other encoding types.
    ;       aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
    ;                   The address (base address) and offsets should point to the memory address which is to be written to.
    ; Return Values:
    ;       Non Zero -   Indicates success.
    ;       Zero     -   Indicates failure. Check errorLevel and A_LastError for more information
    ; Notes:
    ;       By default a null terminator is included at the end of written strings. 
    ;       This behaviour is determined by the property [derivedObject].insertNullTerminator
    ;       If this property is true, then a null terminator will be included.       


    writeString(address, string, encoding := "utf-8", aOffsets*)
    {
        encodingSize := (encoding = "utf-16" || encoding = "cp1200") ? 2 : 1
        requiredSize := StrPut(string, encoding) * encodingSize - (this.insertNullTerminator ? 0 : encodingSize)
        VarSetCapacity(buffer, requiredSize)
        StrPut(string, &buffer, StrLen(string) + (this.insertNullTerminator ?  1 : 0), encoding)
        return DllCall("WriteProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, "Ptr", &buffer, "Ptr", requiredSize, "Ptr", this.pNumberOfBytesWritten)
    }
    
    ; Method:   write(address, value, type := "Uint", aOffsets*)
    ;           Writes various integer type values to the process.
    ; Parameters:
    ;       address -   The memory address to which data will be written or if using the offset parameter, 
    ;                   the base address of the pointer.
    ;       type    -   The integer type. 
    ;                   Valid types are UChar, Char, UShort, Short, UInt, Int, Float, Int64 and Double. 
    ;                   Note: Types must not contain spaces i.e. " UInt" or "UInt " will not work. 
    ;                   When an invalid type is passed the method returns NULL and sets ErrorLevel to -2
    ;       aOffsets* - A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
    ;                   The address (base address) and offsets should point to the memory address which is to be written to.
    ; Return Values:
    ;       Non Zero -  Indicates success.
    ;       Zero     -  Indicates failure. Check errorLevel and A_LastError for more information
    ;       Null    -   An invalid type was passed. Errorlevel is set to -2


    write(address, value, type := "Uint", aOffsets*)
    {
        if !this.aTypeSize.hasKey(type)
            return "", ErrorLevel := -2 
        return DllCall("WriteProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, type "*", value, "Ptr", this.aTypeSize[type], "Ptr", this.pNumberOfBytesWritten) 
    }


    ; Method:   writeRaw(address, pBuffer, sizeBytes, aOffsets*)
    ;           Writes a buffer to the process.
    ; Parameters:
    ;   address -       The memory address to which the contents of the buffer will be written 
    ;                   or if using the offset parameter, the base address of the pointer.    
    ;   pBuffer -       A pointer to the buffer which is to be written.
    ;                   This does not necessarily have to be the beginning of the buffer itself e.g. pBuffer := &buffer + offset
    ;   sizeBytes -     The number of bytes which are to be written from the buffer.
    ;   aOffsets* -     A variadic list of offsets. When using offsets the address parameter should equal the base address of the pointer.
    ;                   The address (base address) and offsets should point to the memory address which is to be written to.
    ; Return Values:
    ;       Non Zero -  Indicates success.
    ;       Zero     -  Indicates failure. Check errorLevel and A_LastError for more information


    writeRaw(address, pBuffer, sizeBytes, aOffsets*)
    {
        return DllCall("WriteProcessMemory", "Ptr", this.hProcess, "Ptr", aOffsets.maxIndex() ? this.getAddressFromOffsets(address, aOffsets*) : address, "Ptr", pBuffer, "Ptr", sizeBytes, "Ptr", this.pNumberOfBytesWritten) 
    }


    ; Method:           pointer(address, finalType := "UInt", offsets*)
    ;                   This is an internal method. Since the other various methods all offer this functionality, they should be used instead.
    ;                   This will read integer values of both pointers and non-pointers (i.e. a single memory address)
    ; Parameters:
    ;   address -       The base address of the pointer or the memory address for a non-pointer.
    ;   finalType -     The type of integer stored at the final address.
    ;                   Valid types are UChar, Char, UShort, Short, UInt, Int, Float, Int64 and Double. 
    ;                   Note: Types must not contain spaces i.e. " UInt" or "UInt " will not work. 
    ;                   When an invalid type is passed the method returns NULL and sets ErrorLevel to -2
    ;   aOffsets* -     A variadic list of offsets used to calculate the pointers final address.
    ; Return Values: (The same as the read() method)
    ;       integer -   Indicates success.
    ;       Null    -   Indicates failure. Check ErrorLevel and A_LastError for more information.
    ;       Note:       Since the returned integer value may be 0, to check for success/failure compare the result
    ;                   against null i.e. if (result = "") then an error has occurred.
    ;                   If the target application is 64bit the pointers are read as an 8 byte Int64 (this.PtrType)
    
    pointer(address, finalType := "UInt", offsets*)
    { 
        For index, offset in offsets
            address := this.Read(address, this.ptrType) + offset 
        Return this.Read(address, finalType)
    }


    ; Method:               getAddressFromOffsets(address, aOffsets*)
    ;                       Returns the final address of a pointer.
    ;                       This is an internal method used by various methods however, this method may be useful if you are 
    ;                       looking to eliminate the overhead overhead associated with reading pointers which only change 
    ;                       on startup or map/level change. In other words you can cache the final address and
    ;                       read from this address directly.
    ; Parameters:
    ;   address             The base address of the pointer.
    ;   aOffsets*           A variadic list of offsets used to calculate the pointers final address.
    ;                       At least one offset must be present.
    ; Return Values:    
    ;   Positive integer    The final memory address pointed to by the pointer.
    ;   Negative integer    Failure
    ;   Null                Failure
    ; Note:                 If the target application is 64bit the pointers are read as an 8 byte Int64 (this.PtrType)


    getAddressFromOffsets(address, aOffsets*)
    {
        return  aOffsets.Remove() + this.pointer(address, this.ptrType, aOffsets*) ; remove the highest key so can use pointer() to find final memory address (minus the last offset)       
    }


    ; Interesting note:
    ; Although handles are 64-bit pointers, only the less significant 32 bits are employed in them for the purpose 
    ; of better compatibility (for example, to enable 32-bit and 64-bit processes interact with each other)
    ; Here are examples of such types: HANDLE, HWND, HMENU, HPALETTE, HBITMAP, etc. 
    ; http://www.viva64.com/en/k/0005/






    ; Method:   getProcessBaseAddress(WindowTitle, windowMatchMode := 3)
    ;           Returns the base address of a process. In most cases this will provide the same result as calling getModuleBaseAddress() (when passing 
    ;           a null value as the module parameter), however getProcessBaseAddress() will usually work regardless of the bitness
    ;           of both the AHK exe and the target process.
    ;           *This method relies on the target process having a window and will not work for console apps*
    ;           *'DetectHiddenWindows, On' is required for hidden windows*
    ;           ***If this returns an incorrect value, try using (the MORE RELIABLE) getModuleBaseAddress() instead.***
    ; Parameters:
    ;   windowTitle         This can be any AHK windowTitle identifier, such as 
    ;                       ahk_exe, ahk_class, ahk_pid, or simply the window title. e.g. "ahk_exe calc.exe" or "Calculator".
    ;                       It's safer not to use the window title, as some things can have the same window title e.g. an open folder called "Starcraft II"
    ;                       would have the same window title as the game itself.
    ;   windowMatchMode     Determines the matching mode used when finding the program's window (windowTitle).
    ;                       The default value is 3 i.e. an exact match. The current matchmode will be used if the parameter is null or 0.
    ;                       Refer to AHK's setTitleMathMode for more information.
    ; Return Values:
    ;   Positive integer    The base address of the process (success).
    ;   Null                The process's window couldn't be found.
    ;   0                   The GetWindowLong or GetWindowLongPtr call failed. Try getModuleBaseAddress() instead.
                           
  
    getProcessBaseAddress(windowTitle, windowMatchMode := "3")   
    {
        if (windowMatchMode && A_TitleMatchMode != windowMatchMode)
        {
            mode := A_TitleMatchMode ; This is a string and will not contain the 0x prefix
            StringReplace, windowMatchMode, windowMatchMode, 0x ; remove hex prefix as SetTitleMatchMode will throw a run time error. This will occur if integer mode is set to hex and matchmode param is passed as an number not a string.
            SetTitleMatchMode, %windowMatchMode%    ;mode 3 is an exact match
        }
        WinGet, hWnd, ID, %WindowTitle%
        if mode
            SetTitleMatchMode, %mode%    ; In case executed in autoexec
        if !hWnd
            return ; return blank failed to find window
       ; GetWindowLong returns a Long (Int) and GetWindowLongPtr return a Long_Ptr
        return DllCall(A_PtrSize = 4     ; If DLL call fails, returned value will = 0
            ? "GetWindowLong"
            : "GetWindowLongPtr"
            , "Ptr", hWnd, "Int", -6, A_Is64bitOS ? "Int64" : "UInt")  
            ; For the returned value when the OS is 64 bit use Int64 to prevent negative overflow when AHK is 32 bit and target process is 64bit 
            ; however if the OS is 32 bit, must use UInt, otherwise the number will be huge (however it will still work as the lower 4 bytes are correct)      
            ; Note - it's the OS bitness which matters here, not the scripts/AHKs
    }   


    ; http://winprogger.com/getmodulefilenameex-enumprocessmodulesex-failures-in-wow64/
    ; http://stackoverflow.com/questions/3801517/how-to-enum-modules-in-a-64bit-process-from-a-32bit-wow-process


    ; Method:            getModuleBaseAddress(module := "", byRef aModuleInfo := "")
    ; Parameters:
    ;   moduleName -    The file name of the module/dll to find e.g. "calc.exe", "GDI32.dll", "Bass.dll" etc
    ;                   If no module (null) is specified, the address of the base module - main()/process will be returned 
    ;                   e.g. for calc.exe the following two method calls are equivalent getModuleBaseAddress() and getModuleBaseAddress("calc.exe")
    ;   aModuleInfo -   (Optional) A module Info object is returned in this variable. If method fails this variable is made blank.
    ;                   This object contains the keys: name, fileName, lpBaseOfDll, SizeOfImage, and EntryPoint 
    ; Return Values: 
    ;   Positive integer - The module's base/load address (success).
    ;   -1 - Module not found
    ;   -3 - EnumProcessModulesEx failed
    ;   -4 - The AHK script is 32 bit and you are trying to access the modules of a 64 bit target process. Or the target process has been closed.
    ; Notes:    A 64 bit AHK can enumerate the modules of a target 64 or 32 bit process.
    ;           A 32 bit AHK can only enumerate the modules of a 32 bit process
    ;           This method requires PROCESS_QUERY_INFORMATION + PROCESS_VM_READ access rights. These are included by default with this class.


    getModuleBaseAddress(moduleName := "", byRef aModuleInfo := "")
    {
        aModuleInfo := ""
        if (moduleName = "")
            moduleName := this.GetModuleFileNameEx(0, True) ; main executable module of the process - get just fileName no path
        if r := this.getModules(aModules, True) < 0
            return r ; -4, -3
        return aModules.HasKey(moduleName) ? (aModules[moduleName].lpBaseOfDll, aModuleInfo := aModules[moduleName]) : -1
        ; no longer returns -5 for failed to get module info
    }  
     


    ; Method:                   getModuleFromAddress(address, byRef aModuleInfo) 
    ;                           Finds the module in which the address resides. 
    ; Parameters:
    ;   address                 The address of interest.
    ;                       
    ;   aModuleInfo             (Optional) An unquoted variable name. If the module associated with the address is found,
    ;                           a moduleInfo object will be stored in this variable. This object has the 
    ;                           following keys: name, fileName, lpBaseOfDll, SizeOfImage, and EntryPoint. 
    ;                           If the address is not found to reside inside a module, the passed variable is
    ;                           made blank/null.
    ;   offsetFromModuleBase    (Optional) Stores the relative offset from the module base address 
    ;                           to the specified address. If the method fails then the passed variable is set to blank/empty.
    ; Return Values:
    ;   1                       Success - The address is contained within a module.
    ;   -1                      The specified address does not reside within a loaded module.
    ;   -3                      EnumProcessModulesEx failed.
    ;   -4                      The AHK script is 32 bit and you are trying to access the modules of a 64 bit target process.      


    getModuleFromAddress(address, byRef aModuleInfo, byRef offsetFromModuleBase := "") 
    {
        aModuleInfo := offsetFromModule := ""
        if result := this.getmodules(aModules) < 0
            return result ; error -3, -4
        for k, module in aModules 
        {
            if (address >= module.lpBaseOfDll && address < module.lpBaseOfDll + module.SizeOfImage)
                return 1, aModuleInfo := module, offsetFromModuleBase := address - module.lpBaseOfDll
        }    
        return -1    
    }


    ; SeDebugPrivileges is required to read/write memory in some programs.
    ; This only needs to be called once when the script starts,
    ; regardless of the number of programs being read (or if the target programs restart)
    ; Call this before attempting to call any other methods in this class 
    ; i.e. call _ClassMemory.setSeDebugPrivilege() at the very start of the script.


    setSeDebugPrivilege(enable := True)
    {
        h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", DllCall("GetCurrentProcessId"), "Ptr")
        ; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
        DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
        VarSetCapacity(ti, 16, 0)  ; structure of privileges
        NumPut(1, ti, 0, "UInt")  ; one entry in the privileges array...
        ; Retrieves the locally unique identifier of the debug privilege:
        DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
        NumPut(luid, ti, 4, "Int64")
        if enable
            NumPut(2, ti, 12, "UInt")  ; enable this privilege: SE_PRIVILEGE_ENABLED = 2
        ; Update the privileges of this process with the new access token:
        r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
        DllCall("CloseHandle", "Ptr", t)  ; close this access token handle to save memory
        DllCall("CloseHandle", "Ptr", h)  ; close this process handle to save memory
        return r
    }




    ; Method:  isTargetProcess64Bit(PID, hProcess := "", currentHandleAccess := "")
    ;          Determines if a process is 64 bit.
    ; Parameters:
    ;   PID                     The Process ID of the target process. If required this is used to open a temporary process handle.  
    ;   hProcess                (Optional) A handle to the process, as returned by openProcess() i.e. [derivedObject].hProcess
    ;   currentHandleAccess     (Optional) The dwDesiredAccess value used when opening the process handle which has been 
    ;                           passed as the hProcess parameter. If specifying hProcess, you should also specify this value.                 
    ; Return Values:
    ;   True    The target application is 64 bit.
    ;   False   The target application is 32 bit.
    ;   Null    The method failed.
    ; Notes:
    ;   This is an internal method which is called when the new operator is used. It is used to set the pointer type for 32/64 bit applications so the pointer methods will work.
    ;   This operation requires a handle with PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access rights.
    ;   If the currentHandleAccess parameter does not contain these rights (or not passed) or if the hProcess (process handle) is invalid (or not passed)
    ;   a temporary handle is opened to perform this operation. Otherwise if hProcess and currentHandleAccess appear valid  
    ;   the passed hProcess is used to perform the operation.


    isTargetProcess64Bit(PID, hProcess := "", currentHandleAccess := "")
    {
        if !A_Is64bitOS
            return False 
        ; If insufficient rights, open a temporary handle
        else if !hProcess || !(currentHandleAccess & (this.aRights.PROCESS_QUERY_INFORMATION | this.aRights.PROCESS_QUERY_LIMITED_INFORMATION))
            closeHandle := hProcess := this.openProcess(PID, this.aRights.PROCESS_QUERY_INFORMATION)
        if (hProcess && DllCall("IsWow64Process", "Ptr", hProcess, "Int*", Wow64Process))
            result := !Wow64Process
        return result, closeHandle ? this.CloseHandle(hProcess) : ""
    }
    /*
        _Out_  PBOOL Wow64Proces value set to:
        True if the process is running under WOW64 - 32bit app on 64bit OS.
        False if the process is running under 32-bit Windows!
        False if the process is a 64-bit application running under 64-bit Windows.
    */  


    ; Method: suspend() / resume()
    ; Notes:
    ;   These are undocumented Windows functions which suspend and resume the process. Here be dragons.
    ;   The process handle must have PROCESS_SUSPEND_RESUME access rights. 
    ;   That is, you must specify this when using the new operator, as it is not included. 
    ;   Some people say it requires more rights and just use PROCESS_ALL_ACCESS, however PROCESS_SUSPEND_RESUME has worked for me.
    ;   Suspending a process manually can be quite helpful when reversing memory addresses and pointers, although it's not at all required. 
    ;   As an unorthodox example, memory addresses holding pointers are often stored in a slightly obfuscated manner i.e. they require bit operations to calculate their
    ;   true stored value (address). This obfuscation can prevent Cheat Engine from finding the true origin of a pointer or links to other memory regions. If there 
    ;   are no static addresses between the obfuscated address and the final destination address then CE wont find anything (there are ways around this in CE). One way around this is to
    ;   suspend the process, write the true/deobfuscated value to the address and then perform your scans. Afterwards write back the original values and resume the process.


    suspend()
    {
        return DllCall("ntdll\NtSuspendProcess", "Ptr", this.hProcess)
    }  


    resume()
    {
        return DllCall("ntdll\NtResumeProcess", "Ptr", this.hProcess)
    } 


    ; Method:               getModules(byRef aModules, useFileNameAsKey := False)
    ;                       Stores the process's loaded modules as an array of (object) modules in the aModules parameter.
    ; Parameters:
    ;   aModules            An unquoted variable name. The loaded modules of the process are stored in this variable as an array of objects.
    ;                       Each object in this array has the following keys: name, fileName, lpBaseOfDll, SizeOfImage, and EntryPoint. 
    ;   useFileNameAsKey    When true, the file name e.g. GDI32.dll is used as the lookup key for each module object.
    ; Return Values:
    ;   Positive integer    The size of the aModules array. (Success)
    ;   -3                  EnumProcessModulesEx failed.
    ;   -4                  The AHK script is 32 bit and you are trying to access the modules of a 64 bit target process.


    getModules(byRef aModules, useFileNameAsKey := False)
    {
        if (A_PtrSize = 4 && this.IsTarget64bit)
            return -4 ; AHK is 32bit and target process is 64 bit, this function wont work     
        aModules := []
        if !moduleCount := this.EnumProcessModulesEx(lphModule)
            return -3  
        loop % moduleCount
        {
            this.GetModuleInformation(hModule := numget(lphModule, (A_index - 1) * A_PtrSize), aModuleInfo)
            aModuleInfo.Name := this.GetModuleFileNameEx(hModule)
            filePath := aModuleInfo.name
            SplitPath, filePath, fileName
            aModuleInfo.fileName := fileName
            if useFileNameAsKey
                aModules[fileName] := aModuleInfo
            else aModules.insert(aModuleInfo)
        }
        return moduleCount        
    }






    getEndAddressOfLastModule(byRef aModuleInfo := "")
    {
        if !moduleCount := this.EnumProcessModulesEx(lphModule)
            return -3     
        hModule := numget(lphModule, (moduleCount - 1) * A_PtrSize)
        if this.GetModuleInformation(hModule, aModuleInfo)
            return aModuleInfo.lpBaseOfDll + aModuleInfo.SizeOfImage
        return -5
    }


    ; lpFilename [out]
    ; A pointer to a buffer that receives the fully qualified path to the module. 
    ; If the size of the file name is larger than the value of the nSize parameter, the function succeeds 
    ; but the file name is truncated and null-terminated.
    ; If the buffer is adequate the string is still null terminated. 


    GetModuleFileNameEx(hModule := 0, fileNameNoPath := False)
    {
        ; ANSI MAX_PATH = 260 (includes null) - unicode can be ~32K.... but no one would ever have one that size
        ; So just give it a massive size and don't bother checking. Most coders just give it MAX_PATH size anyway
        VarSetCapacity(lpFilename, 2048 * (A_IsUnicode ? 2 : 1)) 
        DllCall("psapi\GetModuleFileNameEx"
                    , "Ptr", this.hProcess
                    , "Ptr", hModule
                    , "Str", lpFilename
                    , "Uint", 2048 / (A_IsUnicode ? 2 : 1))
        if fileNameNoPath
            SplitPath, lpFilename, lpFilename ; strips the path so = GDI32.dll


        return lpFilename
    }


    ; dwFilterFlag
    ;   LIST_MODULES_DEFAULT    0x0  
    ;   LIST_MODULES_32BIT      0x01
    ;   LIST_MODULES_64BIT      0x02
    ;   LIST_MODULES_ALL        0x03
    ; If the function is called by a 32-bit application running under WOW64, the dwFilterFlag option 
    ; is ignored and the function provides the same results as the EnumProcessModules function.
    EnumProcessModulesEx(byRef lphModule, dwFilterFlag := 0x03)
    {
        lastError := A_LastError
        size := VarSetCapacity(lphModule, 4)
        loop 
        {
            DllCall("psapi\EnumProcessModulesEx"
                        , "Ptr", this.hProcess
                        , "Ptr", &lphModule
                        , "Uint", size
                        , "Uint*", reqSize
                        , "Uint", dwFilterFlag)
            if ErrorLevel
                return 0
            else if (size >= reqSize)
                break
            else size := VarSetCapacity(lphModule, reqSize)  
        }
        ; On first loop it fails with A_lastError = 0x299 as its meant to
        ; might as well reset it to its previous version
        DllCall("SetLastError", "UInt", lastError)
        return reqSize // A_PtrSize ; module count  ; sizeof(HMODULE) - enumerate the array of HMODULEs     
    }


    GetModuleInformation(hModule, byRef aModuleInfo)
    {
        VarSetCapacity(MODULEINFO, A_PtrSize * 3), aModuleInfo := []
        return DllCall("psapi\GetModuleInformation"
                    , "Ptr", this.hProcess
                    , "Ptr", hModule
                    , "Ptr", &MODULEINFO
                    , "UInt", A_PtrSize * 3)
                , aModuleInfo := {  lpBaseOfDll: numget(MODULEINFO, 0, "Ptr")
                                ,   SizeOfImage: numget(MODULEINFO, A_PtrSize, "UInt")
                                ,   EntryPoint: numget(MODULEINFO, A_PtrSize * 2, "Ptr") }
    }


    ; Method:           hexStringToPattern(hexString)
    ;                   Converts the hex string parameter into an array of bytes pattern (AOBPattern) that
    ;                   can be passed to the various pattern scan methods i.e.  modulePatternScan(), addressPatternScan(), rawPatternScan(), and processPatternScan()
    ;       
    ; Parameters:
    ;   hexString -     A string of hex bytes.  The '0x' hex prefix is optional.
    ;                   Bytes can optionally be separated using the space or tab characters.
    ;                   Each byte must be two characters in length i.e. '04' or '0x04' (not '4' or '0x4') 
    ;                   ** Unlike the other methods, wild card bytes MUST be denoted using '??' (two question marks)** 
    ;
    ; Return Values: 
    ;   Object          Success - The returned object contains the AOB pattern. 
    ;   -1              An empty string was passed.
    ;   -2              Non hex character present.  Acceptable characters are A-F, a-F, 0-9, ?, space, tab, and 0x (hex prefix).
    ;   -3              Non-even wild card character count. One of the wild card bytes is missing a '?' e.g. '?' instead of '??'.               
    ;   -4              Non-even character count. One of the hex bytes is probably missing a character e.g. '4' instead of '04'.
    ;
    ;   Examples:
    ;                   pattern := hexStringToPattern("DEADBEEF02")
    ;                   pattern := hexStringToPattern("0xDE0xAD0xBE0xEF0x02")
    ;                   pattern := hexStringToPattern("DE AD BE EF 02")
    ;                   pattern := hexStringToPattern("0xDE 0xAD 0xBE 0xEF 0x02")
    ;               
    ;                   This will mark the third byte as wild:
    ;                   pattern := hexStringToPattern("DE AD ?? EF 02")
    ;                   pattern := hexStringToPattern("0xDE 0xAD ?? 0xEF 0x02")
    ;               
    ;                   The returned pattern can then be passed to the various pattern scan methods, for example:
    ;                   pattern := hexStringToPattern("DE AD BE EF 02")
    ;                   memObject.processPatternScan(,, pattern*)   ; Note the '*'


    hexStringToPattern(hexString)
    {
        AOBPattern := []
        hexString := RegExReplace(hexString, "(\s|0x)")
        StringReplace, hexString, hexString, ?, ?, UseErrorLevel
        wildCardCount := ErrorLevel


        if !length := StrLen(hexString)
            return -1 ; no str
        else if RegExMatch(hexString, "[^0-9a-fA-F?]")
            return -2 ; non hex character and not a wild card
        else if Mod(wildCardCount, 2)
            return -3 ; non-even wild card character count
        else if Mod(length, 2)
            return -4 ; non-even character count
        loop, % length/2
        {
            value := "0x" SubStr(hexString, 1 + 2 * (A_index-1), 2)
            AOBPattern.Insert(value + 0 = "" ? "?" : value)
        }
        return AOBPattern
    }


    ; Method:           stringToPattern(string, encoding := "UTF-8", insertNullTerminator := False)
    ;                   Converts a text string parameter into an array of bytes pattern (AOBPattern) that
    ;                   can be passed to the various pattern scan methods i.e.  modulePatternScan(), addressPatternScan(), rawPatternScan(), and processPatternScan()
    ; 
    ; Parameters:
    ;   string                  The text string to convert.
    ;   encoding                This refers to how the string is stored in the program's memory.
    ;                           UTF-8 and UTF-16 are common. Refer to the AHK manual for other encoding types.  
    ;   insertNullTerminator    Includes the null terminating byte(s) (at the end of the string) in the AOB pattern.
    ;                           This should be set to 'false' unless you are certain that the target string is null terminated and you are searching for the entire string or the final part of the string.
    ;
    ; Return Values: 
    ;   Object          Success - The returned object contains the AOB pattern. 
    ;   -1              An empty string was passed.
    ;
    ;   Examples:
    ;                   pattern := stringToPattern("This text exists somewhere in the target program!")
    ;                   memObject.processPatternScan(,, pattern*)   ; Note the '*'


    stringToPattern(string, encoding := "UTF-8", insertNullTerminator := False)
    {   
        if !length := StrLen(string)
            return -1 ; no str  
        AOBPattern := []
        encodingSize := (encoding = "utf-16" || encoding = "cp1200") ? 2 : 1
        requiredSize := StrPut(string, encoding) * encodingSize - (insertNullTerminator ? 0 : encodingSize)
        VarSetCapacity(buffer, requiredSize)
        StrPut(string, &buffer, length + (insertNullTerminator ?  1 : 0), encoding) 
        loop, % requiredSize
            AOBPattern.Insert(NumGet(buffer, A_Index-1, "UChar"))
        return AOBPattern
    }    



    ; Method:           modulePatternScan(module := "", aAOBPattern*)
    ;                   Scans the specified module for the specified array of bytes    
    ; Parameters:
    ;   module -        The file name of the module/dll to search e.g. "calc.exe", "GDI32.dll", "Bass.dll" etc
    ;                   If no module (null) is specified, the executable file of the process will be used. 
    ;                   e.g. for calc.exe it would be the same as calling modulePatternScan(, aAOBPattern*) or modulePatternScan("calc.exe", aAOBPattern*)
    ;   aAOBPattern*    A variadic list of byte values i.e. the array of bytes to find.
    ;                   Wild card bytes should be indicated by passing a non-numeric value eg "?".
    ; Return Values:
    ;   Positive int    Success. The memory address of the found pattern.   
    ;   Null            Failed to find or retrieve the specified module. ErrorLevel is set to the returned error from getModuleBaseAddress()
    ;                   refer to that method for more information.
    ;   0               The pattern was not found inside the module
    ;   -9              VirtualQueryEx() failed
    ;   -10             The aAOBPattern* is invalid. No bytes were passed                   


    modulePatternScan(module := "", aAOBPattern*)
    {
        MEM_COMMIT := 0x1000, MEM_MAPPED := 0x40000, MEM_PRIVATE := 0x20000
        , PAGE_NOACCESS := 0x01, PAGE_GUARD := 0x100


        if (result := this.getModuleBaseAddress(module, aModuleInfo)) <= 0
             return "", ErrorLevel := result ; failed    
        if !patternSize := this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
            return -10 ; no pattern
        ; Try to read the entire module in one RPM()
        ; If fails with access (-1) iterate the modules memory pages and search the ones which are readable          
        if (result := this.PatternScan(aModuleInfo.lpBaseOfDll, aModuleInfo.SizeOfImage, patternMask, AOBBuffer)) >= 0
            return result  ; Found / not found
        ; else RPM() failed lets iterate the pages
        address := aModuleInfo.lpBaseOfDll
        endAddress := address + aModuleInfo.SizeOfImage
        loop 
        {
            if !this.VirtualQueryEx(address, aRegion)
                return -9
            if (aRegion.State = MEM_COMMIT 
            && !(aRegion.Protect & (PAGE_NOACCESS | PAGE_GUARD)) ; can't read these areas
            ;&& (aRegion.Type = MEM_MAPPED || aRegion.Type = MEM_PRIVATE) ;Might as well read Image sections as well
            && aRegion.RegionSize >= patternSize
            && (result := this.PatternScan(address, aRegion.RegionSize, patternMask, AOBBuffer)) > 0)
                return result
        } until (address += aRegion.RegionSize) >= endAddress
        return 0       
    }


    ; Method:               addressPatternScan(startAddress, sizeOfRegionBytes, aAOBPattern*)
    ;                       Scans a specified memory region for an array of bytes pattern.
    ;                       The entire memory area specified must be readable for this method to work,
    ;                       i.e. you must ensure the area is readable before calling this method.
    ; Parameters:
    ;   startAddress        The memory address from which to begin the search.
    ;   sizeOfRegionBytes   The numbers of bytes to scan in the memory region.
    ;   aAOBPattern*        A variadic list of byte values i.e. the array of bytes to find.
    ;                       Wild card bytes should be indicated by passing a non-numeric value eg "?".      
    ; Return Values:
    ;   Positive integer    Success. The memory address of the found pattern.
    ;   0                   Pattern not found
    ;   -1                  Failed to read the memory region.
    ;   -10                 An aAOBPattern pattern. No bytes were passed.


    addressPatternScan(startAddress, sizeOfRegionBytes, aAOBPattern*)
    {
        if !this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
            return -10
        return this.PatternScan(startAddress, sizeOfRegionBytes, patternMask, AOBBuffer)   
    }
   
    ; Method:       processPatternScan(startAddress := 0, endAddress := "", aAOBPattern*)
    ;               Scan the memory space of the current process for an array of bytes pattern. 
    ;               To use this in a loop (scanning for multiple occurrences of the same pattern),
    ;               simply call it again passing the last found address + 1 as the startAddress.
    ; Parameters:
    ;   startAddress -      The memory address from which to begin the search.
    ;   endAddress -        The memory address at which the search ends. 
    ;                       Defaults to 0x7FFFFFFF for 32 bit target processes.
    ;                       Defaults to 0xFFFFFFFF for 64 bit target processes when the AHK script is 32 bit.
    ;                       Defaults to 0x7FFFFFFFFFF for 64 bit target processes when the AHK script is 64 bit. 
    ;                       0x7FFFFFFF and 0x7FFFFFFFFFF are the maximum process usable virtual address spaces for 32 and 64 bit applications.
    ;                       Anything higher is used by the system (unless /LARGEADDRESSAWARE and 4GT have been modified).            
    ;                       Note: The entire pattern must be occur inside this range for a match to be found. The range is inclusive.
    ;   aAOBPattern* -      A variadic list of byte values i.e. the array of bytes to find.
    ;                       Wild card bytes should be indicated by passing a non-numeric value eg "?".
    ; Return Values:
    ;   Positive integer -  Success. The memory address of the found pattern.
    ;   0                   The pattern was not found.
    ;   -1                  VirtualQueryEx() failed.
    ;   -2                  Failed to read a memory region.
    ;   -10                 The aAOBPattern* is invalid. (No bytes were passed)


    processPatternScan(startAddress := 0, endAddress := "", aAOBPattern*)
    {
        address := startAddress
        if endAddress is not integer  
            endAddress := this.isTarget64bit ? (A_PtrSize = 8 ? 0x7FFFFFFFFFF : 0xFFFFFFFF) : 0x7FFFFFFF


        MEM_COMMIT := 0x1000, MEM_MAPPED := 0x40000, MEM_PRIVATE := 0x20000
        PAGE_NOACCESS := 0x01, PAGE_GUARD := 0x100
        if !patternSize := this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
            return -10  
        while address <= endAddress ; > 0x7FFFFFFF - definitely reached the end of the useful area (at least for a 32 target process)
        {
            if !this.VirtualQueryEx(address, aInfo)
                return -1
            if A_Index = 1
                aInfo.RegionSize -= address - aInfo.BaseAddress
            if (aInfo.State = MEM_COMMIT) 
            && !(aInfo.Protect & (PAGE_NOACCESS | PAGE_GUARD)) ; can't read these areas
            ;&& (aInfo.Type = MEM_MAPPED || aInfo.Type = MEM_PRIVATE) ;Might as well read Image sections as well
            && aInfo.RegionSize >= patternSize
            && (result := this.PatternScan(address, aInfo.RegionSize, patternMask, AOBBuffer))
            {
                if result < 0 
                    return -2
                else if (result + patternSize - 1 <= endAddress)
                    return result
                else return 0
            }
            address += aInfo.RegionSize
        }
        return 0
    }


    ; Method:           rawPatternScan(byRef buffer, sizeOfBufferBytes := "", aAOBPattern*)   
    ;                   Scans a binary buffer for an array of bytes pattern. 
    ;                   This is useful if you have already dumped a region of memory via readRaw()
    ; Parameters:
    ;   buffer              The binary buffer to be searched.
    ;   sizeOfBufferBytes   The size of the binary buffer. If null or 0 the size is automatically retrieved.
    ;   startOffset         The offset from the start of the buffer from which to begin the search. This must be >= 0.
    ;   aAOBPattern*        A variadic list of byte values i.e. the array of bytes to find.
    ;                       Wild card bytes should be indicated by passing a non-numeric value eg "?".
    ; Return Values:
    ;   >= 0                The offset of the pattern relative to the start of the haystack.
    ;   -1                  Not found.
    ;   -2                  Parameter incorrect.


    rawPatternScan(byRef buffer, sizeOfBufferBytes := "", startOffset := 0, aAOBPattern*)
    {
        if !this.getNeedleFromAOBPattern(patternMask, AOBBuffer, aAOBPattern*)
            return -10
        if (sizeOfBufferBytes + 0 = "" || sizeOfBufferBytes <= 0)
            sizeOfBufferBytes := VarSetCapacity(buffer)
        if (startOffset + 0 = "" || startOffset < 0)
            startOffset := 0
        return this.bufferScanForMaskedPattern(&buffer, sizeOfBufferBytes, patternMask, &AOBBuffer, startOffset)           
    }


    ; Method:           getNeedleFromAOBPattern(byRef patternMask, byRef needleBuffer, aAOBPattern*)
    ;                   Converts an array of bytes pattern (aAOBPattern*) into a binary needle and pattern mask string
    ;                   which are compatible with patternScan() and bufferScanForMaskedPattern().
    ;                   The modulePatternScan(), addressPatternScan(), rawPatternScan(), and processPatternScan() methods
    ;                   allow you to directly search for an array of bytes pattern in a single method call.
    ; Parameters:
    ;   patternMask -   (output) A string which indicates which bytes are wild/non-wild.
    ;   needleBuffer -  (output) The array of bytes passed via aAOBPattern* is converted to a binary needle and stored inside this variable.
    ;   aAOBPattern* -  (input) A variadic list of byte values i.e. the array of bytes from which to create the patternMask and needleBuffer.
    ;                   Wild card bytes should be indicated by passing a non-numeric value eg "?".
    ; Return Values:
    ;  The number of bytes in the binary needle and hence the number of characters in the patternMask string. 


    getNeedleFromAOBPattern(byRef patternMask, byRef needleBuffer, aAOBPattern*)
    {
        patternMask := "", VarSetCapacity(needleBuffer, aAOBPattern.MaxIndex())
        for i, v in aAOBPattern
            patternMask .= (v + 0 = "" ? "?" : "x"), NumPut(round(v), needleBuffer, A_Index - 1, "UChar")
        return round(aAOBPattern.MaxIndex())
    }


    ; The handle must have been opened with the PROCESS_QUERY_INFORMATION access right
    VirtualQueryEx(address, byRef aInfo)
    {


        if (aInfo.__Class != "_ClassMemory._MEMORY_BASIC_INFORMATION")
            aInfo := new this._MEMORY_BASIC_INFORMATION()
        return aInfo.SizeOfStructure = DLLCall("VirtualQueryEx" 
                                                , "Ptr", this.hProcess
                                                , "Ptr", address
                                                , "Ptr", aInfo.pStructure
                                                , "Ptr", aInfo.SizeOfStructure
                                                , "Ptr") 
    }


    /*
    // The c++ function used to generate the machine code
    int scan(unsigned char* haystack, unsigned int haystackSize, unsigned char* needle, unsigned int needleSize, char* patternMask, unsigned int startOffset)
    {
        for (unsigned int i = startOffset; i <= haystackSize - needleSize; i++)
        {
            for (unsigned int j = 0; needle[j] == haystack[i + j] || patternMask[j] == '?'; j++)
            {
                if (j + 1 == needleSize)
                    return i;
            }
        }
        return -1;
    }
    */


    ; Method:               PatternScan(startAddress, sizeOfRegionBytes, patternMask, byRef needleBuffer)
    ;                       Scans a specified memory region for a binary needle pattern using a machine code function
    ;                       If found it returns the memory address of the needle in the processes memory.
    ; Parameters:
    ;   startAddress -      The memory address from which to begin the search.
    ;   sizeOfRegionBytes - The numbers of bytes to scan in the memory region.
    ;   patternMask -       This string indicates which bytes must match and which bytes are wild. Each wildcard byte must be denoted by a single '?'. 
    ;                       Non wildcards can use any other single character e.g 'x'. There should be no spaces.
    ;                       With the patternMask 'xx??x', the first, second, and fifth bytes must match. The third and fourth bytes are wild.
    ;    needleBuffer -     The variable which contains the binary needle. This needle should consist of UChar bytes.
    ; Return Values:
    ;   Positive integer    The address of the pattern.
    ;   0                   Pattern not found.
    ;   -1                  Failed to read the region.


    patternScan(startAddress, sizeOfRegionBytes, byRef patternMask, byRef needleBuffer)
    {
        if !this.readRaw(startAddress, buffer, sizeOfRegionBytes)
            return -1      
        if (offset := this.bufferScanForMaskedPattern(&buffer, sizeOfRegionBytes, patternMask, &needleBuffer)) >= 0
            return startAddress + offset 
        else return 0
    }
    ; Method:               bufferScanForMaskedPattern(byRef hayStack, sizeOfHayStackBytes, byRef patternMask, byRef needle)
    ;                       Scans a binary haystack for binary needle against a pattern mask string using a machine code function.
    ; Parameters:
    ;   hayStackAddress -   The address of the binary haystack which is to be searched.
    ;   sizeOfHayStackBytes The total size of the haystack in bytes.
    ;   patternMask -       A string which indicates which bytes must match and which bytes are wild. Each wildcard byte must be denoted by a single '?'. 
    ;                       Non wildcards can use any other single character e.g 'x'. There should be no spaces.
    ;                       With the patternMask 'xx??x', the first, second, and fifth bytes must match. The third and fourth bytes are wild.
    ;   needleAddress -     The address of the binary needle to find. This needle should consist of UChar bytes.
    ;   startOffset -       The offset from the start of the haystack from which to begin the search. This must be >= 0.
    ; Return Values:    
    ;   >= 0                Found. The pattern begins at this offset - relative to the start of the haystack.
    ;   -1                  Not found.
    ;   -2                  Invalid sizeOfHayStackBytes parameter - Must be > 0.


    ; Notes:
    ;       This is a basic function with few safeguards. Incorrect parameters may crash the script.


    bufferScanForMaskedPattern(hayStackAddress, sizeOfHayStackBytes, byRef patternMask, needleAddress, startOffset := 0)
    {
        static p
        if !p
        {
            if A_PtrSize = 4    
                p := this.MCode("1,x86:8B44240853558B6C24182BC5568B74242489442414573BF0773E8B7C241CBB010000008B4424242BF82BD8EB038D49008B54241403D68A0C073A0A740580383F750B8D0C033BCD74174240EBE98B442424463B74241876D85F5E5D83C8FF5BC35F8BC65E5D5BC3")
            else 
                p := this.MCode("1,x64:48895C2408488974241048897C2418448B5424308BF2498BD8412BF1488BF9443BD6774A4C8B5C24280F1F800000000033C90F1F400066660F1F840000000000448BC18D4101418D4AFF03C80FB60C3941380C18740743803C183F7509413BC1741F8BC8EBDA41FFC2443BD676C283C8FF488B5C2408488B742410488B7C2418C3488B5C2408488B742410488B7C2418418BC2C3")
        }
        if (needleSize := StrLen(patternMask)) + startOffset > sizeOfHayStackBytes
            return -1 ; needle can't exist inside this region. And basic check to prevent wrap around error of the UInts in the machine function       
        if (sizeOfHayStackBytes > 0)
            return DllCall(p, "Ptr", hayStackAddress, "UInt", sizeOfHayStackBytes, "Ptr", needleAddress, "UInt", needleSize, "AStr", patternMask, "UInt", startOffset, "cdecl int")
        return -2
    }


    ; Notes: 
    ; Other alternatives for non-wildcard buffer comparison.
    ; Use memchr to find the first byte, then memcmp to compare the remainder of the buffer against the needle and loop if it doesn't match
    ; The function FindMagic() by Lexikos uses this method.
    ; Use scanInBuf() machine code function - but this only supports 32 bit ahk. I could check if needle contains wild card and AHK is 32bit,
    ; then call this function. But need to do a speed comparison to see the benefits, but this should be faster. Although the benefits for 
    ; the size of the memory regions be dumped would most likely be inconsequential as it's already extremely fast.


    MCode(mcode)
    {
        static e := {1:4, 2:1}, c := (A_PtrSize=8) ? "x64" : "x86"
        if !regexmatch(mcode, "^([0-9]+),(" c ":|.*?," c ":)([^,]+)", m)
            return
        if !DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", 0, "uint*", s, "ptr", 0, "ptr", 0)
            return
        p := DllCall("GlobalAlloc", "uint", 0, "ptr", s, "ptr")
        ; if (c="x64") ; Virtual protect must always be enabled for both 32 and 64 bit. If DEP is set to all applications (not just systems), then this is required
        DllCall("VirtualProtect", "ptr", p, "ptr", s, "uint", 0x40, "uint*", op)
        if DllCall("crypt32\CryptStringToBinary", "str", m3, "uint", 0, "uint", e[m1], "ptr", p, "uint*", s, "ptr", 0, "ptr", 0)
            return p
        DllCall("GlobalFree", "ptr", p)
        return
    }


    ; This link indicates that the _MEMORY_BASIC_INFORMATION32/64 should be based on the target process
    ; http://stackoverflow.com/questions/20068219/readprocessmemory-on-a-64-bit-proces-always-returns-error-299 
    ; The msdn documentation is unclear, and suggests that a debugger can pass either structure - perhaps there is some other step involved.
    ; My tests seem to indicate that you must pass _MEMORY_BASIC_INFORMATION i.e. structure is relative to the AHK script bitness.
    ; Another post on the net also agrees with my results. 


    ; Notes: 
    ; A 64 bit AHK script can call this on a target 64 bit process. Issues may arise at extremely high memory addresses as AHK does not support UInt64 (but these addresses should never be used anyway).
    ; A 64 bit AHK can call this on a 32 bit target and it should work. 
    ; A 32 bit AHk script can call this on a 64 bit target and it should work providing the addresses fall inside the 32 bit range.


    class _MEMORY_BASIC_INFORMATION
    {
        __new()
        {   
            if !this.pStructure := DllCall("GlobalAlloc", "UInt", 0, "Ptr", this.SizeOfStructure := A_PtrSize = 8 ? 48 : 28, "Ptr")
                return ""
            return this
        }
        __Delete()
        {
            DllCall("GlobalFree", "Ptr", this.pStructure)
        }
        ; For 64bit the int64 should really be unsigned. But AHK doesn't support these
        ; so this won't work correctly for higher memory address areas
        __get(key)
        {
            static aLookUp := A_PtrSize = 8 
                                ?   {   "BaseAddress": {"Offset": 0, "Type": "Int64"}
                                    ,    "AllocationBase": {"Offset": 8, "Type": "Int64"}
                                    ,    "AllocationProtect": {"Offset": 16, "Type": "UInt"}
                                    ,    "RegionSize": {"Offset": 24, "Type": "Int64"}
                                    ,    "State": {"Offset": 32, "Type": "UInt"}
                                    ,    "Protect": {"Offset": 36, "Type": "UInt"}
                                    ,    "Type": {"Offset": 40, "Type": "UInt"} }
                                :   {  "BaseAddress": {"Offset": 0, "Type": "UInt"}
                                    ,   "AllocationBase": {"Offset": 4, "Type": "UInt"}
                                    ,   "AllocationProtect": {"Offset": 8, "Type": "UInt"}
                                    ,   "RegionSize": {"Offset": 12, "Type": "UInt"}
                                    ,   "State": {"Offset": 16, "Type": "UInt"}
                                    ,   "Protect": {"Offset": 20, "Type": "UInt"}
                                    ,   "Type": {"Offset": 24, "Type": "UInt"} }


            if aLookUp.HasKey(key)
                return numget(this.pStructure+0, aLookUp[key].Offset, aLookUp[key].Type)        
        }
        __set(key, value)
        {
             static aLookUp := A_PtrSize = 8 
                                ?   {   "BaseAddress": {"Offset": 0, "Type": "Int64"}
                                    ,    "AllocationBase": {"Offset": 8, "Type": "Int64"}
                                    ,    "AllocationProtect": {"Offset": 16, "Type": "UInt"}
                                    ,    "RegionSize": {"Offset": 24, "Type": "Int64"}
                                    ,    "State": {"Offset": 32, "Type": "UInt"}
                                    ,    "Protect": {"Offset": 36, "Type": "UInt"}
                                    ,    "Type": {"Offset": 40, "Type": "UInt"} }
                                :   {  "BaseAddress": {"Offset": 0, "Type": "UInt"}
                                    ,   "AllocationBase": {"Offset": 4, "Type": "UInt"}
                                    ,   "AllocationProtect": {"Offset": 8, "Type": "UInt"}
                                    ,   "RegionSize": {"Offset": 12, "Type": "UInt"}
                                    ,   "State": {"Offset": 16, "Type": "UInt"}
                                    ,   "Protect": {"Offset": 20, "Type": "UInt"}
                                    ,   "Type": {"Offset": 24, "Type": "UInt"} }


            if aLookUp.HasKey(key)
            {
                NumPut(value, this.pStructure+0, aLookUp[key].Offset, aLookUp[key].Type)            
                return value
            }
        }
        Ptr()
        {
            return this.pStructure
        }
        sizeOf()
        {
            return this.SizeOfStructure
        }
    }


}


#539 abg

abg

    Научил друга включать камеру

  • Писатели
  • PipPipPipPipPipPip
  • 679 Сообщений:

Отправлено 11 Jul 2018 - 09:33

Интересно, в чем может быть причина долгого сохранения-загрузки проекта (2017.1)? Warp Stabilizers? После их использования (да, много) размер файла раздулся вдвое (со 100 до 200+МВ) и сейвы стали жутко тормозить. Это как-то лечится?



#540 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 06 Sep 2018 - 02:09

Обнаружил, что из Premiere CC2017 убрали экспорт legacy titles.
Скрипт на автохотки для экспорта титров (требуется offzip.exe для распаковки ZLib):
Offzip.exe нужно поместить в папку со скриптом.
http://aluigi.alterv...oolz/offzip.zip
Чтобы экспортировать нужно выделить титр (на линейке или в проекте) и нажать f11.
SetBatchLines -1
#If WinActive("ahk_class Premiere Pro")
f11::
if !FileExist("offzip.exe")
{
   MsgBox, 262144, Error!, Error! Place offzip.exe in the folder of script!
   return
}
FileName := SaveFile([WinExist("A"), "Save Title"], "title001", {"Premiere Title": "`r*.prtl"}, ,0x00000002 | 0x00000004 | 0x10000000 | 0x02000000)
If !FileName
  return
tmp := ClipboardAll
Clipboard := ""
send ^{vk43} ; c
ClipWait, 1, 1
if ErrorLevel = 1
{
   MsgBox, 262144, Error!, Error! ClipBoard is empty!
   Clipboard := tmp
   return
}
While !DllCall("OpenClipboard", "Ptr", 0)
   sleep 20
formatCount := DllCall("CountClipboardFormats"), format:=0
Loop % formatCount
{
   format := DllCall("EnumClipboardFormats", "UInt", format)
   VarSetCapacity(formatName, 512)
   DllCall("GetClipboardFormatName", "Uint", format, "str", formatName, "Uint", 256)
   if Instr(formatName, "PProAE/Exchange")
      break
}
if !Instr(formatName, "PProAE/Exchange")
{
   MsgBox, 262144, Error!, Error! ClipBoard does not have right format!
   DllCall("CloseClipboard")
   Clipboard := tmp
   return
}
hText := DllCall("GetClipboardData", "UInt", format, "UInt")
pText := DllCall("GlobalLock", "UInt", hText, "UInt")
DataText := StrGet(pText, "UTF-8")
DllCall("GlobalUnlock", "UInt", hText)
DllCall("CloseClipboard")
Clipboard := tmp
RegexMatch(DataText, "s)<ImporterPrefs Encoding=""base64"".+?>([^\s]+)\s*</ImporterPrefs>", match)
if !match1
{
   MsgBox, 262144, Error!, Error! ClipBoard does not have Premiere Title!
   return
}
n := tmpFile1 := tmpFile2 := ""
loop 2
{
   loop
   {
      n++
      if !FileExist("ahk" n ".tmp")
         break
      sleep 10
   }
   tmpFile%A_Index% := "AHK" n ".tmp"
}
Bytes := Base64Dec(BIN, match1)
oFile := FileOpen(tmpFile1, "rw")
oFile.RawWrite(BIN, Bytes)
oFile.Pos := 32
oFileContent := oFile.Read()
oFile.Pos := 0
oFile.Write(oFileContent)
oFile.Close()
RunWait, offzip.exe %tmpFile1% %tmpFile2%,,Hide
FileRead, data, %tmpFile2%
if !data
{
   MsgBox, 262144, Error!, Error! ClipBoard does not have Premiere Title!
   loop 2
      FileDelete, % tmpFile%A_Index%
   return
}
FileMove, %tmpFile2%, %FileName%, 1
if ErrorLevel
{
   MsgBox, 262144, Error!, Error! Cannot create file!
   loop 2
      FileDelete, % tmpFile%A_Index%
   return
}
FileDelete, % tmpFile1
MsgBox, 262144, Done, Done
return
#If


Base64dec(ByRef OutData, ByRef InData)
{
   DllCall("Crypt32.dll\CryptStringToBinary", Ptr, &InData, UInt, StrLen(InData), UInt,1, UInt,0, UIntP, Bytes, UIntP, 0, UIntP, 0)
   VarSetCapacity(OutData, Bytes)
   DllCall("Crypt32.dll\CryptStringToBinary",  Ptr, &InData, UInt, StrLen(InData), UInt,1, Str, OutData, UIntP, Bytes, UIntP, 0, UIntP, 0)
   Return Bytes
}

DirExist(DirName)
{
    loop Files, % DirName, D
        return A_LoopFileAttrib
}

/*
    Displays a standard dialog that allows the user to save a file.
    Parameters:
        Owner / Title:
            The identifier of the window that owns this dialog. This value can be zero.
            An Array with the identifier of the owner window and the title. If the title is an empty string, it is set to the default.
        FileName:
            The path to the file or directory selected by default. If you specify a directory, it must end with a backslash.
        Filter:
            Specify a file filter. You must specify an object, each key represents the description and the value the file types.
            To specify the filter selected by default, add the "`n" character to the value of the key. By default, the first filter is selected.
            To specify the default extension that will be added to the file names, specify the "`r" character next to the extension.
            The default character to separate the extensions is ";". The spaces are omitted from the value.
        CustomPlaces:
            Specify an Array with the custom directories that will be displayed in the left pane. Missing directories will be omitted.
            To specify the location in the list, specify an Array with the directory and its location (0 = Lower, 1 = Upper).
        Options:
            Determines the behavior of the dialog. This parameter must be one or more of the following values.
                0x00000002  (FOS_OVERWRITEPROMPT) = When saving a file, prompt before overwriting an existing file of the same name.
                0x00000004  (FOS_STRICTFILETYPES) = Only allow the user to choose a file that has one of the file name extensions specified through Filter.
                0x00040000 (FOS_HIDEPINNEDPLACES) = Hide items shown by default in the view's navigation pane.
                0x10000000  (FOS_FORCESHOWHIDDEN) = Include hidden and system items.
                0x02000000  (FOS_DONTADDTORECENT) = Do not add the item being opened or saved to the recent documents list (SHAddToRecentDocs).
            You can check all available values at https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx.
    Return:
        Returns 0 if the user canceled the dialog, otherwise returns the path of the selected file.
    Example:
        MsgBox % SaveFile( [0, "Dialog title - SaveFile.."]
                  , A_ComSpec
                  , {Music: "*.mp3", Images: "`n*.jpg;*.png", Videos: "*.avi;*.mp4;*.mkv;*.wmp", Documents: "*.txt"}
                  , [A_WinDir,A_Desktop,A_Temp,A_Startup,A_ProgramFiles]
                  , 0x00000002 | 0x00000004 | 0x10000000 | 0x02000000 )
*/

SaveFile(Owner, FileName := "", Filter := "", CustomPlaces := "", Options := 0x6)
{
    ; IFileSaveDialog interface
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775688(v=vs.85).aspx
    local IFileSaveDialog := ComObjCreate("{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}", "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}")
        ,           Title := IsObject(Owner) ? Owner[2] . "" : ""
        ,           Flags := Options     ; FILEOPENDIALOGOPTIONS enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/dn457282(v=vs.85).aspx)
        ,      IShellItem := PIDL := 0   ; PIDL recibe la dirección de memoria a la estructura ITEMIDLIST que debe ser liberada con la función CoTaskMemFree
        ,             Obj := {}, foo := bar := ""
        ,       Directory := FileName
    Owner := IsObject(Owner) ? Owner[1] : (WinExist("ahk_id" . Owner) ? Owner : 0)
    Filter := IsObject(Filter) ? Filter : {"All files": "*.*"}


    if ( FileName != "" )
    {
        if ( InStr(FileName, "\") )
        {
            if !( FileName ~= "\\$" )    ; si «FileName» termina con "\" se trata de una carpeta
            {
                local File := ""
                SplitPath FileName, File, Directory
                ; IFileDialog::SetFileName
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775974(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileSaveDialog+0)+15*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", &File)
            }
            
            while ( InStr(Directory,"\") && !DirExist(Directory) )                   ; si el directorio no existe buscamos directorios superiores
                Directory := SubStr(Directory, 1, InStr(Directory, "\",, -1) - 1)    ; recupera el directorio superior
            if ( DirExist(Directory) )
            {
                DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &Directory, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
                DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
                ObjRawSet(Obj, IShellItem, PIDL)
                ; IFileDialog::SetFolder method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761828(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileSaveDialog+0)+12*A_PtrSize), "Ptr", IFileSaveDialog, "UPtr", IShellItem)
            }
        }
        else    ; si «FileName» es únicamente el nombre de un archivo
            DllCall(NumGet(NumGet(IFileSaveDialog+0)+15*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", &FileName)
    }


    ; COMDLG_FILTERSPEC structure
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb773221(v=vs.85).aspx
    local Description := "", FileTypes := "", FileTypeIndex := 1
    ObjSetCapacity(Obj, "COMDLG_FILTERSPEC", 2*Filter.Count() * A_PtrSize)
    for Description, FileTypes in Filter
    {
        loop parse, FileTypes, ";"            ; itera por todas las extensiones separadas por ";"
            if ( InStr(A_LoopField, "`r") )   ; si se especificó el caracter "`r" en la extensión actual
                ; IFileDialog::SetDefaultExtension method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775970(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileSaveDialog+0)+22*A_PtrSize), "UPtr", IFileSaveDialog, "Str", RegExReplace(A_LoopField,"\s*`n*`r*\**\.*"))
        FileTypeIndex := InStr(FileTypes,"`n") ? A_Index : FileTypeIndex
        ObjRawSet(Obj, "#" . A_Index, Trim(Description)), ObjRawSet(Obj, "@" . A_Index, RegExReplace(FileTypes,"\s*`n*`r*"))
        NumPut(ObjGetAddress(Obj,"#" . A_Index), ObjGetAddress(Obj,"COMDLG_FILTERSPEC") + A_PtrSize * 2*(A_Index-1))        ; COMDLG_FILTERSPEC.pszName
        NumPut(ObjGetAddress(Obj,"@" . A_Index), ObjGetAddress(Obj,"COMDLG_FILTERSPEC") + A_PtrSize * (2*(A_Index-1)+1))    ; COMDLG_FILTERSPEC.pszSpec
    }

    ; IFileDialog::SetFileTypes method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775980(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog+0)+4*A_PtrSize), "UPtr", IFileSaveDialog, "UInt", Filter.Count(), "UPtr", ObjGetAddress(Obj,"COMDLG_FILTERSPEC"))

    ; IFileDialog::SetFileTypeIndex method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775978(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog+0)+5*A_PtrSize), "UPtr", IFileSaveDialog, "UInt", FileTypeIndex)


    if ( IsObject(CustomPlaces := IsObject(CustomPlaces) || CustomPlaces == "" ? CustomPlaces : [CustomPlaces]) )
    {
        local Directory := ""
        for foo, Directory in CustomPlaces    ; foo = index
        {
            foo := IsObject(Directory) ? Directory[2] : 0    ; FDAP enumeration (https://msdn.microsoft.com/en-us/library/windows/desktop/bb762502(v=vs.85).aspx)
            if ( DirExist(Directory := IsObject(Directory) ? Directory[1] : Directory) )
            {
                DllCall("Shell32.dll\SHParseDisplayName", "UPtr", &Directory, "Ptr", 0, "UPtrP", PIDL, "UInt", 0, "UInt", 0)
                DllCall("Shell32.dll\SHCreateShellItem", "Ptr", 0, "Ptr", 0, "UPtr", PIDL, "UPtrP", IShellItem)
                ObjRawSet(Obj, IShellItem, PIDL)
                ; IFileDialog::AddPlace method
                ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775946(v=vs.85).aspx
                DllCall(NumGet(NumGet(IFileSaveDialog+0)+21*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", IShellItem, "UInt", foo)
            }
        }
    }


    ; IFileDialog::SetTitle method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761834(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog+0)+17*A_PtrSize), "UPtr", IFileSaveDialog, "UPtr", Title == "" ? 0 : &Title)

    ; IFileDialog::SetOptions method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761832(v=vs.85).aspx
    DllCall(NumGet(NumGet(IFileSaveDialog+0)+9*A_PtrSize), "UPtr", IFileSaveDialog, "UInt", Flags)


    ; IModalWindow::Show method
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb761688(v=vs.85).aspx
    local Result := FALSE
    if ( !DllCall(NumGet(NumGet(IFileSaveDialog+0)+3*A_PtrSize), "UPtr", IFileSaveDialog, "Ptr", Owner, "UInt") )
    {
        ; IFileDialog::GetResult method
        ; https://msdn.microsoft.com/en-us/library/windows/desktop/bb775964(v=vs.85).aspx
        if ( !DllCall(NumGet(NumGet(IFileSaveDialog+0)+20*A_PtrSize), "UPtr", IFileSaveDialog, "UPtrP", IShellItem) )
        {
            VarSetCapacity(Result, 32767 * 2, 0)
            DllCall("Shell32.dll\SHGetIDListFromObject", "UPtr", IShellItem, "UPtrP", PIDL)
            DllCall("Shell32.dll\SHGetPathFromIDListEx", "UPtr", PIDL, "Str", Result, "UInt", 2000, "UInt", 0)
            ObjRawSet(Obj, IShellItem, PIDL)
        }
    }


    for foo, bar in Obj      ; foo = IShellItem interface (ptr)  |  bar = PIDL structure (ptr)
        if foo is integer    ; IShellItem?
            ObjRelease(foo), DllCall("Ole32.dll\CoTaskMemFree", "UPtr", bar)
    ObjRelease(IFileSaveDialog)

    return Result
} ; https://github.com/flipeador/Library-AutoHotkey/blob/master/dlg/SaveFile.ahk


#541 iliuxa

iliuxa

    я занят, позвоните попозже

  • Активные Участники
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 2623 Сообщений:
  • место работы:

Отправлено 07 Sep 2018 - 14:59

У меня тут одна мадам набила субтитры в премьере и ладно бы как субтитры, а то каждый титр это отдельный клип на таймлайне сделанный эффектом.

Можно ли из этого безобразия выдрать текст с таймингом?



#542 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 07 Sep 2018 - 17:21

Каким эффектом?

#543 Gradov_Georg

Gradov_Georg

    штатный злобный буратино форума

  • Модераторы
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 7796 Сообщений:

Отправлено 07 Sep 2018 - 19:53

Проект без видео - т.е. только титры на таймлане положи куда-нибудь



#544 iliuxa

iliuxa

    я занят, позвоните попозже

  • Активные Участники
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 2623 Сообщений:
  • место работы:

Отправлено 10 Sep 2018 - 00:18

попутал я , не эффектом, а title legasy вместо caption. В принципе эту мадам отправил самой текст дергать, только ради интереса хотел понять можно ли такое в текст конвертировать.

Проекта у меня сейчас нету, но там все просто File New Legacy Title и таких насоздавали на целый фильм



#545 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 12 Sep 2018 - 06:08

Можно.

В премьеровском проекте Legacy титры запакованы zlib, после чего закодированы в base64.
Как получить xml титра, я приводил пример выше.
Но кроме получения можно попробовать его изменить.

Требуется zlib1.dll и autohotkey 32 bit.

http://zlib.net/zlib128-dll.zip

В переменной var находится base64 строка скопированная из проекта c титром "Hello world!".

Скрипт раскодирует и распаковывает этот титр, измененяет на "Привет, мир!" и запаковывает и кодирует обратно.

Если полученную строку вставить в xml проекта вместо строки какого-либо титра и сохранить, то при открытии проекта титр заменится на "Привет, мир!".

var := "AQAAAAAAAACgYQAAAAAAAENvbXByZXNzZWRUaXRsZQB4nO1d63NTuxHXn+L2O/hBnMfMae6EkBSmgTBxLpBPjHGc4NbYru1Acv/4tru/lY7ex064YKd4MglH+9JK2l3tkY7Ef/9TqN/Urfqihqqmvqq+mqqZGqixGqm/qb+qpnqqGvRvjTAj1SP4JWFH6hrY39W5OlZPiGobNL+pfVWoA6IZq0/E8VGd0dNYzSP4OUmZU519YN559e6rFtXZULv0u0O/LaKoRzSFeg3JUv6oOoSfo8zazUDxlmroqjvCHhPVVH2j0pS02Ce6qbohDpacpypI6hylOWFNPT0q99Ef++qKsEOqTSQtomaNpmW/DOlnn9onOoTwQh2RrBmgr8AtlCGU6UakLdd4RT/VGlbTsn5jop0nNYwxro6n1J/zhJYGztDFI1avsBJu7wz6DoCfqhOM2xg1zMj+3mXtl/ld6rB8hP7ok/Q56rkieEpeS8ty6c9JygQ6mrancKI/e08vGhUXw3oNqD+6xH2DsZlF9CmKQr1ET7KcF8AP0Cshb45K5Fb3SNhrLOELbMf0UVWfTdQHsqJX9PeIpHQI1lR78HWuO8YyxwU9v1JvCCb0EhWE3scxdUcdknUe0c8bsqMzcAhtjCmo7VPS8Ru14zNaMtWtNRHG4M/QT5/RXi6PIHMRd9ifcV+FvXkAbxDr5rIZ1w7R8EhYbzhAbV1guXylPe+pbq+FFfR3TO13sQZSoC5pmeD3gHehBekyhl5j0t6l8uES/ar0NNgDp5fy7WiodmVLDL6qLe0lW9Ne0J6cxvWlRu850fTUv7S93MD3Ul6ypb2kQ7p2iYbxZ2h9H3Xy7MtxZIu03iMvEA2raQuKvvEccKptb0JQjgUmAp9Rmf9lzhFmwi/gc1sp3pTnY3yqxYx5AQ27BBkSL8+Vd2Vsz7d0BzLTratXyvRx51S6hR/2y1lk4vlrXofte+iwuJ6/E6xLsM+I+KdkL//UscOXJPbTR/8dgsPOJjP1b6LqQhfWIU1VkOQxRsnADknyGJbAY2LHh2VU08ayTvF3tFCOpWMvZ0xfvad/LxE790tPjzEFWeAAvjTFnCclw5HGFRSTZYZ7Trg/6Fk8LfSCHFXhtOYQXjAC7phohrAtGZlnZJlPSZPan/QksWqZmguylSGsaoKx+dlaLl87U9/P2o33HCKy8QilqNzoZOaObvlmYvKwECrR/xZeMoJePH+HdpGmYasa463gvW6P/w4RYwt4D8dB7qUTbd0zym/CGvN0ORkXS8q40O9dQ8yBI51/sJeYeVUy7hhf4E3mEzJ2nl/cyPpet1Xm3xxVAZ+cQHYPvnkO2g7mj145Kk2867Gs5ehzcm3Uc9u2iLbA29ow6k8DNf1grNkvhXYotvPmkVuny/kw21wsYWOZP9Yy05b4qRyN9bDRcEbeWOmvZqU5e5zpWke6lsdnn5s5/v/DRkNLrC+Zo1a/B6ZXK80aQDVvLfEmKtzyrmpkSPs7+NvTXjWgd50+3gu29YhYGPfDrXpJz3bFpEmZ/67ulRAn9P+AHnZ92oexR8pKsOnDDt4EzEqP+GOeYnnP53o7+g2YR2CnXCHy4SFlaoUkRWH4hogbc6+9LlTofsdbHPeCtZ24jhSV8Ltvwf4Y+O/HwicxIY4XLq4g7IDednnt/rLU3ocJzSt4gPiTS+fDhfYKNj+k+N1FZNnHCtkAdK/JBg1vTGf4x+i3Y8D57fEuKcvKqaL3ZbqRij3mGjrwmkkozY9pLsZGkXbE5UaYK/RKF+sR14idd+BhP9vFLtYejWOrlBHTSmSJfba+IBosQ2PWkU0rw3KNxvaFE0N2yrVIQ/Fc+2hV1Jo7fdXQP2K1tp8mWFEalJq9wHor22m3XFMz6/uLKe16kqwycDwws1vKF1J0BXa1pJUSV/2VxxhbQDZrwGv6jB9jLvngeEsOn+O9WMB7oTWV9V7OWD5SaYwoKXmArPaYmF5NV2A8psCMtE/PYYWm79PY+8WbIxqvT4jrQ7Tlc5l7dPSccwaPjGPjfTh5z9KsR8s6eBf5gPVOsV32OdnHrKY2+7i+3TP8GLZzXepyokco5RNt7RMhjz8LxzOw7MtyjXaG8WGFktX2oSPBhRSYn2WvNuxXF1NA+yNEjb6ehy7LHQW2nFh3X9r9+Xk1O4SGu6dVFOw9Pu4UfRNqlqMqkMuJf73Usx6PXMifo5K+H2GnqOtE4G0ab471u+VoxDS5ut09nFe6H28Rg1oUg7aQ0e3guV2hW06Ku8vDuNf0fIucgldzf9xff5/IrZkxKcv4Pk9pLuErT6g32z/VX9wVhnXyFlevVfnKzqPxlQbZ8/f83t8XYqiZayQrs/pXzUHN7I5yLZgF35A1fNHf1LhfbMwizv0gw3Ax6R3ph2nwbOUabK1cg/bKNdheuQY7K9dgd+Ua7K1cg2b5Dd0qdWiugQ6rj4zNNYiNzTWIjs3K+NjCuousQ+whN/gZOj2ptNFQp/ZP893GWvgva7EOPtzAN+Xrocc6+DLrsQ7+3MBXneuhx+ozH9Fj9flPU5/FWA891iMXWo98qLEmOVFjTfKixprkRo01yY8aC3Kkh+jhw91VCXfVPCzPojbEkKqdpZ7WgPHpL+HTFAX6htfc5JyM3/I0rsAptyH2XU69fbYtXVMa6/ex7Bm762wxtsAa5MDb17ArmSmcyyHrdP5OQQ7LX0DIPoec4jpXcmrC7JGnsSHXc+WekGgleX0aK+Eg2rNIYQrYL59CHGLnRXbV3V3BPN7WdUhW10vW5WLkK+oudsR4b8i13oYe6Rze1hWux8bwAl9Ii8WYfd2aGpTrjmznZjZhO7x0ZJmdtGs8yzf0ZqQtRL7ru/F6yZQLqoHXHqclzpa5FOu2nMbNR6dx69Fp/OzRabwVaNzC225ea4vPaW4pvld7GxvjWJTGudHIxuAwDrnR2UJTJwJDzvSpQYt/i2844t3xFIXLF7cvjfPbx7PTRM9AYQstLuThXvO/zMrjXV45wfo5seeWpnF5X2MOlfNm7gybppB5WWwr9a1XiA1znO/PU9JrUffLWNwvUjZ5yyZvWc+8pYW916p4b/D5eN8qzxdvcphNDrPJYTY5zCaHWb8cpv2AHOZhqy5mTvux2csmd/nVc5cfMzPxyvjOJmd5VBo//pxl1Rpv8pRNnvLQPMWH+Gcp3dvOfFgqozF75w9fUfHh5pyZwZsva2IJIaVkNzxHmTNN7gkWuz6ToygwrnI74xw+51PGJzOqqfnb7BtkDKLhUHtGKCdH5fKbb7dDC0lTsIX0UEdffXBa2NT2kcL5PClan+aiQu5FRu5FklZsYFDW4rbPhVuq8F4BF14oOUvFp7DjtqdxPk+H4J8cbCPiDClCG/6AE4JDjEg6I/cp3Prjfk3jfJ5FOscUoc4XC3W+CHT2sfbMS8xpv8RnjSaIPJ3SAtx2xriwnoOS6itZEZ+BvsvUmqZ0M/cUPszh0zL8DPpcz7WhZ+eowjalT0fHFHx2gntS5r2ZzgXmyt7AmMYyzo/kKZhE/BOKJNeIY0Ljl+WWOjtn2DKXXqDfvuGbCXtTXQpqak7B7Il/yctMiW9vHauJjrh3ydnIfLn0kFsm3pbR2+Yucu5lm36e4uTZts7OGHcHXFufNzani1NS3IyKefl7ij2SyOuwu4FEew7dSHS5lz2nvw43unzPLSG/yp0Z9Qr79q1feE1Wxs/+d0EpWI5b/MyMV+422ZriG4LNPXLm7HoTmEnJMVNy1s6n4HrMqV6/XQNYSNVpXr5/wZ4IbpOnyF2k5mS/jy9wo63Ep9hTLW7xid6vpYYy+5h+Cm02T1d4PXaS9NUqCsZX9RpTHGFdaKijDPO5t/1Z27K3/rDUZbkeesfNGck4iXrKQNnmzuCf07KtL5WcPOcboCUa88nBv2hbDqkLZC4j9BhD+GYOaZP4/qW29Sm8Vb7Vy90VuxxlTdfImf0N2mnPhdScWCNZu3+rQ620iRC7rbEfyttbpIVmrUxw5hbwHI2xkfgul5Cyrq3qz+u9OWZs9zaQkX62tcU09Sjq+FB/zq8n8wP7DiwzxY0yd83Yck1dl89hPJqgD3pU0zn98hwWn7KNKQp4YVdHcJtrhtDC8yium2/67+o1Hhs5TR9ZnaWcb109yLLqURb2rrzL+1i/CcU7BlVnV680V+hz9SyGe+ywzG73dWQOoYZOrMx/l/cxDMnrLnjbSv9OaIHwGeOqe+v3dfRK/a8J/wMFyDy9"

size := StringBase64ToData(var, outData)
offset := 32, OriginalSize := size*100
VarSetCapacity(var1, offset, 0)
DllCall("Ntdll\RtlMoveMemory", Ptr, &var1, Ptr, &outData, Ptr, offset)
VarSetCapacity(var2, size-offset, 0)
DllCall("Ntdll\RtlMoveMemory", Ptr, &var2, Ptr, &outData+offset, Ptr, size-offset)
zlib_Decompress(Decompressed, var2, size-offset, OriginalSize)
DecompressedData := StrGet(&Decompressed, "UTF-16")
DecompressedData := StrReplace(DecompressedData, "Hello world!", "Привет, мир!")
DecompressedSize := VarSetCapacity(DecompressedData, -1)
CompressedSize := zlib_Compress(Compressed, DecompressedData, DecompressedSize)
VarSetCapacity(var3, CompressedSize+offset, 0)
DllCall("Ntdll\RtlMoveMemory", Ptr, &var3, Ptr, &var1, Ptr, offset)
DllCall("Ntdll\RtlMoveMemory", Ptr, &var3+offset, Ptr, &Compressed, Ptr, CompressedSize)
msgbox % Base64Enc(var3, CompressedSize+offset)
return



Base64Enc(ByRef Bin, nBytes) { ; By SKAN / 18-Aug-2017
   Local Rqd := 0, B64 ; CRYPT_STRING_BASE64 := 0x1, CRYPT_STRING_NOCRLF := 0x40000000
   DllCall( "Crypt32.dll\CryptBinaryToString", "Ptr", &Bin ,"UInt", nBytes, "UInt",0x1|0x40000000, "Ptr",0,"UIntP",Rqd )
   VarSetCapacity( B64, Rqd * ( A_Isunicode ? 2 : 1 ), 0 )
   DllCall( "Crypt32.dll\CryptBinaryToString", "Ptr",&Bin, "UInt",nBytes, "UInt",0x1|0x40000000, "Str",B64, "UIntP",Rqd )
   Return B64
}


StringBase64ToData(stringBase64, ByRef outData)
{
   static CRYPT := CRYPT_STRING_BASE64 := 1
   DllCall("Crypt32\CryptStringToBinary", Ptr, &stringBase64, UInt, StrLen(stringBase64), UInt, CRYPT, UInt, 0, UIntP, bytes, UIntP, 0, UIntP, 0)
   VarSetCapacity(outData, bytes, 0)
   DllCall("Crypt32\CryptStringToBinary", Ptr, &stringBase64, UInt, StrLen(stringBase64), UInt, CRYPT, Str, outData, UIntP, bytes, UIntP, 0, UIntP, 0)
   Return bytes
}


; ===================================== zlib.ahk =====================================
; by shajul -- http://www.autohotkey.com/board/topic/63343-zlib/
; Download zlib1.dll -- http://zlib.net/zlib128-dll.zip
 
zlib_Compress(Byref Compressed, Byref Data, DataLen, level = -1) {
    nSize := DllCall("zlib1\compressBound", "UInt", DataLen, "Cdecl")
    VarSetCapacity(Compressed,nSize, 0)
    ErrorLevel := DllCall("zlib1\compress2", "ptr", &Compressed, "UIntP", nSize, "ptr", &Data, "UInt", DataLen, "Int"
                   , level    ;level 0 (no compression), 1 (best speed) - 9 (best compression)
                   , "Cdecl") ;0 means Z_OK
    return ErrorLevel ? 0 : nSize
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170
 
zlib_Decompress(Byref Decompressed, Byref CompressedData, DataLen, OriginalSize = -1) {
    OriginalSize := (OriginalSize > 0) ? OriginalSize : DataLen*10 ;should be large enough for most cases
    VarSetCapacity(Decompressed,OriginalSize, 0)
    ErrorLevel := DllCall("zlib1\uncompress", "Ptr", &Decompressed, "UIntP", OriginalSize, "Ptr", &CompressedData, "UInt", DataLen)
    return ErrorLevel ? 0 : OriginalSize
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170
 
 
/*
Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal events.
#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)
 
Compression levels.
#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
*/

Сообщение отредактировано Malcev: 12 Sep 2018 - 06:11


#546 Muhin

Muhin

    не теряя ни секунды

  • Активные Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1789 Сообщений:

Отправлено 05 Nov 2018 - 16:50

Жень, приветствую, не пробовал, что-нибудь на JS как здесь?

https://premiereonscript.com/



#547 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 05 Nov 2018 - 22:34

Привет.

Пробовал только подсчёт выделенных клипов - 2 вариант из 536 поста.



#548 Muhin

Muhin

    не теряя ни секунды

  • Активные Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1789 Сообщений:

Отправлено 06 Nov 2018 - 03:14

https://palettegear.com/premiere-pro

https://store.palettegear.com/

c 3min:

интересно, как внутри софта реализована(наверняка не так:): ), например, покрутив ручку менять масшаб, или внутри луметри сразу подкрутить экспозицию.

это все без тыканья в нужный слайдер в интерфейсе панелей премьера.

 

НЕ то что цена особо страшная, зудит захачить это при помощи autohotkey и подручных клавы и mouse wheel.

 

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


Сообщение отредактировано Muhin: 06 Nov 2018 - 03:41


#549 Gradov_Georg

Gradov_Georg

    штатный злобный буратино форума

  • Модераторы
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 7796 Сообщений:

Отправлено 06 Nov 2018 - 10:59

Давно и неправда... 

 

сидел без работы слепил такое в авфтер эффекте == тексты и фотки вставлялись из csv... за фефекты/артефакты ногами не бить , за это никто не платил  даже в теории, именно скриптование пинал :)

 

 

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

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

на третий раз потратил день на переговоры вместо просто  начитки прайса и пдф и начал получать винчестер == файлы картинок, акционный прайс, начитка

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

второй скрипт размечал для рендера на отдельные кусочки и давал названия удобные для плеера.

 

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

Время расчета вариантов увеличилось до неприличного на моей машине.

 

И тут я нашел постоянную работу абсолютно по другому профилю :) Увы исходниками не поделюсь -- умерло вместе с 8 летними терабайтниками. После середины декабря если буду в сознании можно будет еще один заход сделать если будет интересно -- нормальная задача, попытаюсь нормальное решение написать.

 

По поводу https://palettegear.com/premiere-pro -- это вариант клавиатуры-мышки ака HID устройство не очень, то удобное, аналог всяких шатлов. -- при движении слайдера генерит события клавиатуры почти как хоткейка.

Хотя идея кубиков прикольная -- на первый момент кажется лучше монолита... Честно признаюсь как они влезли в эту сумму за все не очень представляю... А так STM32 очень очень очень сделала это доступным и возможным...


PS == чето протупил по цене 29 за модуль более чем нормально, учитывая что на 99% это одна прошивка на все устройства. Основной модуль дает арбитраж и тут могут быть приколы вроде -- как разрешить если клиент одновременно двигает два-три движка/крутилки :) -- особенно если одна из них скроллинг по таймлайну -- на один ее тик давать каждому другому один тик или как?



#550 Malcev

Malcev

    Сенсей для друзей по NLE

  • Участники
  • PipPipPipPipPipPipPipPipPipPip
  • 1078 Сообщений:

Отправлено 06 Nov 2018 - 13:54

Я подобного не реализовывал, так как не было нужды.

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

Хотя наверняка можно реализовать такое, делая замены напрямую в памяти процесса (пример - пост 538), но при каждом апдейте адреса могут меняться.

У автора блога почти всё подробно расписано.

Я понимаю алгоритм такой: читаешь документацию по объектной модели премьера, пишешь скрипт, проверяешь его в ExtendScript Toolkit, создаёшь панель и в ней вписываешь обработчик горячих кнопок.






0 человек читают эту тему

0 пользователей, 0 гостей, 0 скрытых пользователей



Рейтинг@Mail.ru