Тема: AHK: Создание нового файла с выделенным текстом
Здравствуйте. Я выделяю некий текст в Notepad++ и мне нужно, чтобы создался новый файл на рабочем столе, содержимое которого будет составлять выделенный мной текст. Можете мне помочь с этим?
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Здравствуйте. Я выделяю некий текст в Notepad++ и мне нужно, чтобы создался новый файл на рабочем столе, содержимое которого будет составлять выделенный мной текст. Можете мне помочь с этим?
Файлы создаются командой FileAppend. Как копировать выделенный текст, надеюсь, знаете?
ypppu, а нельзя что-нибудь попроще? Точнее посложнее, в обход буфера обмена.
Так, для обычного блокнота можно:
vk31:: ; 1
ControlGet, asd, Selected,, Edit1, ahk_class Notepad
FileAppend, %asd%, A_ScriptDir "\file.txt"
return
svoboden, ваш код полезен, возможно я буду вынужден использовать его, если не найдут решения с Notepad++, спасибо.
Хороший пример, только, по-моему, знака % не хватает.
ypppu, так не обязательно A_ScriptDir использовать, можно другой путь указать.
Вот для "Notepad++":
vk31:: ; 1
ControlGet, asd, Selected,, Scintilla1, ahk_class Notepad++
FileAppend, %asd%, A_ScriptDir "\file.txt"
return
svoboden, ваш последний код неверный.
Напишите что-нибудь на кириллице с кодировкой utf-8 и проверьте.
Да, у меня такой код то выдаёт правильный результат, то нет в одной и той же вкладке.
Но:
Просто я не использую то, чего не понимаю.
Я так понял, помогать не имеет смысла?
Malcev, у меня, и в Notepad и в Notepad++ в utf-8 работает.
1) В Notepad++ создайте документ с кодировкой utf8.
2) Напишите там слово - автохотки.
3) Выделите первые 2 буквы - ав.
4) Нажмите f1.
f1::
ControlGet, asd, Selected,, Scintilla1, ahk_class Notepad++
msgbox % asd
Я так понял, помогать не имеет смысла?
А ты можешь помочь человеку полностью понимающему windows и до кучи андроид или иос? Тут за советом надо, в очередь...
Код конечно есть, но замысловатый.
Со Scintilla1 подход неверный, если речь про "основное поле". После поиска по документам и.т.п. индекс меняется до следующей сессии.
А ты можешь помочь человеку полностью понимающему windows и до кучи андроид или иос?
Так вопрос не ко мне. Не я же «не использую, чего не понимаю». А тут, скорее всего, мало что понятно будет, поначалу во всяком случае.
Malcev, так Notepad++ всегда был ни очень надежным редактором.
Вы пришли к этому выводу из-за того, что ваш код с ним не работает?
f1::
ControlGetFocus, ControlFocused, ahk_class Notepad++
ControlGet, hSci, Hwnd,, %ControlFocused%, ahk_class Notepad++
msgbox % SciUtil_GetSelection(hSci)
return
SciUtil_GetCP(hSci)
{
; Retrieve active codepage. SCI_GETCODEPAGE
SendMessage, 2137, 0, 0,, ahk_id %hSci%
return ErrorLevel
}
SciUtil_GetSelection(hSci)
{
;Get length. SCI_GETSELTEXT
SendMessage, 2161, 0, 0,, ahk_id %hSci%
iLength := ErrorLevel
;Check if the line is empty
if iLength = 1
return
; Open remote buffer
RemoteBuf_Open(hBuf, hSci, iLength)
; Fill buffer. SCI_GETSELTEXT
SendMessage, 2161, 0, RemoteBuf_Get(hBuf),, ahk_id %hSci%
; Prep var
VarSetCapacity(sText, iLength)
RemoteBuf_Read(hBuf, sText, iLength)
; Done
RemoteBuf_Close(hBuf)
return StrGet(&sText, "CP" SciUtil_GetCP(hSci))
}
; Title: Remote Buffer
; *Read and write process memory*
;
/*-------------------------------------------------------------------------------
Function: Open
Open remote buffer
Parameters:
H - Reference to variable to receive remote buffer handle
hwnd - HWND of the window that belongs to the process
size - Size of the buffer
Returns:
Error message on failure
*/
RemoteBuf_Open(ByRef H, hwnd, size) {
static MEM_COMMIT=0x1000, PAGE_READWRITE=4
WinGet, pid, PID, ahk_id %hwnd%
hProc := DllCall( "OpenProcess", "uint", 0x38, "int", 0, "uint", pid) ;0x38 = PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE
IfEqual, hProc,0, return A_ThisFunc "> Unable to open process (" A_LastError ")"
bufAdr := DllCall( "VirtualAllocEx", "uint", hProc, "uint", 0, "uint", size, "uint", MEM_COMMIT, "uint", PAGE_READWRITE)
IfEqual, bufAdr,0, return A_ThisFunc "> Unable to allocate memory (" A_LastError ")"
; Buffer handle structure:
; @0: hProc
; @4: size
; @8: bufAdr
VarSetCapacity(H, 12, 0 )
NumPut( hProc, H, 0)
NumPut( size, H, 4)
NumPut( bufAdr, H, 8)
}
/*----------------------------------------------------
Function: Close
Close the remote buffer
Parameters:
H - Remote buffer handle
*/
RemoteBuf_Close(ByRef H) {
static MEM_RELEASE = 0x8000
handle := NumGet(H, 0)
IfEqual, handle, 0, return A_ThisFunc "> Invalid remote buffer handle"
adr := NumGet(H, 8)
r := DllCall( "VirtualFreeEx", "uint", handle, "uint", adr, "uint", 0, "uint", MEM_RELEASE)
ifEqual, r, 0, return A_ThisFunc "> Unable to free memory (" A_LastError ")"
DllCall( "CloseHandle", "uint", handle )
VarSetCapacity(H, 0 )
}
/*----------------------------------------------------
Function: Read
Read from the remote buffer into local buffer
Parameters:
H - Remote buffer handle
pLocal - Reference to the local buffer
pSize - Size of the local buffer
pOffset - Optional reading offset, by default 0
Returns:
TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
*/
RemoteBuf_Read(ByRef H, ByRef pLocal, pSize, pOffset = 0){
handle := NumGet( H, 0), size:= NumGet( H, 4), adr := NumGet( H, 8)
IfEqual, handle, 0, return A_ThisFunc "> Invalid remote buffer handle"
IfGreaterOrEqual, offset, %size%, return A_ThisFunc "> Offset is bigger then size"
VarSetCapacity( pLocal, pSize )
return DllCall( "ReadProcessMemory", "uint", handle, "uint", adr + pOffset, "uint", &pLocal, "uint", size, "uint", 0 ), VarSetCapacity(pLocal, -1)
}
/*----------------------------------------------------
Function: Write
Write local buffer into remote buffer
Parameters:
H - Remote buffer handle
pLocal - Reference to the local buffer
pSize - Size of the local buffer
pOffset - Optional writting offset, by default 0
Returns:
TRUE on success or FALSE on failure. ErrorMessage on bad remote buffer handle
*/
RemoteBuf_Write(Byref H, byref pLocal, pSize, pOffset=0) {
handle:= NumGet( H, 0), size := NumGet( H, 4), adr := NumGet( H, 8)
IfEqual, handle, 0, return A_ThisFunc "> Invalid remote buffer handle"
IfGreaterOrEqual, offset, %size%, return A_ThisFunc "> Offset is bigger then size"
return DllCall( "WriteProcessMemory", "uint", handle,"uint", adr + pOffset,"uint", &pLocal,"uint", pSize, "uint", 0 )
}
/*----------------------------------------------------
Function: Get
Get address or size of the remote buffer
Parameters:
H - Remote buffer handle
pQ - Query parameter: set to "adr" to get address (default), to "size" to get the size or to "handle" to get Windows API handle of the remote buffer.
Returns:
Address or size of the remote buffer
*/
RemoteBuf_Get(ByRef H, pQ="adr") {
return pQ = "adr" ? NumGet(H, 8) : pQ = "size" ? NumGet(H, 4) : NumGet(H)
}
/*---------------------------------------------------------------------------------------
Group: Example
(start code)
;get the handle of the Explorer window
WinGet, hw, ID, ahk_class ExploreWClass
;open two buffers
RemoteBuf_Open( hBuf1, hw, 128 )
RemoteBuf_Open( hBuf2, hw, 16 )
;write something
str := "1234"
RemoteBuf_Write( hBuf1, str, strlen(str) )
str := "_5678"
RemoteBuf_Write( hBuf1, str, strlen(str), 4)
str := "_testing"
RemoteBuf_Write( hBuf2, str, strlen(str))
;read
RemoteBuf_Read( hBuf1, str, 10 )
out = %str%
RemoteBuf_Read( hBuf2, str, 10 )
out = %out%%str%
MsgBox %out%
;close
RemoteBuf_Close( hBuf1 )
RemoteBuf_Close( hBuf2 )
(end code)
*/
/*-------------------------------------------------------------------------------------------------------------------
Group: About
o Ver 2.0 by majkinetor. See http://www.autohotkey.com/forum/topic12251.html
o Code updates by infogulch
o Licenced under Creative Commons Attribution-Noncommercial <http://creativecommons.org/licenses/by-nc/3.0/>.
*/
Malcev, у меня не работает. Да и опять AHK-basic детектед, из какого пыльного чулана ты всё это достаёшь? Я ж этот RemoteBuffer уже миллион раз выкладывал.
Ver 2.0 by majkinetor. See http://www.autohotkey.com/forum/topic12251.html
http://www.autohotkey.com/forum/topic12251.htm
Posted 01 September 2006 - 10:08 AM
Malcev, у меня не работает.
Поэтому я и пользуюсь 32-битной версией.
Есть ли смысл переделывать готовые скрипты, ради использования ahk 64 бит?
А достал всё отсюда:
https://github.com/fincs/SciTE4AutoHotk … ciUtil.ahk
Вот если б ты на свой класс RemoteBuffer дал комментарии, то было бы отлично.
Есть ли смысл переделывать готовые скрипты, ради использования ahk 64 бит?
Ради использования может и нет, ради понимания есть.
Вот если б ты на свой класс RemoteBuffer дал комментарии, то было бы отлично.
Так у меня то же самое, что и тут, просто размерность правильная. Я не знаю, какие именно комментарии нужны, если что-то неясно, лучше спрашивать, потому что у каждого ведь свой уровень понимания.
Так у меня получает выделенный текст даже из неактивного окна:
F11:: MsgBox, % GetSelTextFromNPP(WinExist("ahk_class Notepad++"))
GetSelTextFromNPP(hNPP) {
if !WinExist("ahk_id" hNPP) {
MsgBox, Окно Notepad++ не найдено
Return
}
WinGet, PID, PID
ControlGetFocus, focused
if InStr(focused, "Scintilla")
ControlGet, hScintilla, hwnd,, % focused
else
hScintilla := GetCurrentScintilla(PID)
if !hScintilla {
MsgBox, Не удалось определить текущее поле редактирования
Return
}
WinWait, ahk_id %hScintilla%
SendMessage, SCI_GETSELTEXT := 2161
charCount := ErrorLevel
if (charCount < 2)
Return
remoteBuff := new RemoteBuffer(PID, charCount)
SendMessage, SCI_GETSELTEXT,, remoteBuff.ptr
VarSetCapacity(localBuff, charCount, 0)
remoteBuff.Read(&localBuff, charCount)
SendMessage, SCI_GETCODEPAGE := 2137
Return StrGet(&localBuff, "CP" . ErrorLevel)
}
GetCurrentScintilla(PID) {
remoteBuff := new RemoteBuffer(PID, 4)
SendMessage, NPPM_GETCURRENTSCINTILLA := 2028,, remoteBuff.ptr
VarSetCapacity(localBuff, 4, 0)
remoteBuff.Read(&localBuff, 4)
if handles := GetScintillaHandles()
Return handles[ NumGet(localBuff, "Int") + 1 ]
}
GetScintillaHandles() {
WinGet, list, ControlList
WinGet, listHwnd, ControlListHwnd
arrClassNN := StrSplit(list, "`n")
arrHwnd := StrSplit(listHwnd, "`n")
for k, v in arrClassNN {
if InStr(prevClass, "Scintilla") && InStr(v, "Scintilla")
Return [ arrHwnd[k - 1], arrHwnd[k] ]
prevClass := v
}
}
class RemoteBuffer
{
__New(PID, size) {
static PROCESS_VM_OPERATION := 0x8, PROCESS_VM_WRITE := 0x20, PROCESS_VM_READ := 0x10
, MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x4
if !(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
Return
if !(this.ptr := DllCall("VirtualAllocEx", UInt, this.hProc, UInt, 0, UInt, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return, "", DllCall("CloseHandle", Ptr, this.hProc)
}
__Delete() {
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
}
Read(pLocalBuff, size, offset = 0) {
if !DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось прочитать данные`nОшибка """ A_LastError """", Str, "", UInt, 0)
}
}
Может стоит дополнить этот класс:
Class RemoteBuffer
{
__New(PID, size)
{
static PROCESS_VM_OPERATION := 0x8, PROCESS_VM_WRITE := 0x20, PROCESS_VM_READ := 0x10
, MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x4
if !(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
Return
if !(this.ptr := DllCall("VirtualAllocEx", UInt, this.hProc, UInt, 0, UInt, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return, "", DllCall("CloseHandle", Ptr, this.hProc)
}
__Delete()
{
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
}
Read(size, offset = 0)
{
static LocalBuff
VarSetCapacity(LocalBuff, size, 0)
if !DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, size, UInt, 0)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось прочитать данные`nОшибка " A_LastError, Str, "", UInt, 0)
VarSetCapacity(LocalBuff, -1)
Return &LocalBuff
}
Write(pLocalBuff, size, offset = 0)
{
res := DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
Return res ? res : 0, (!res) ? DllCall("MessageBox", Ptr, 0, Str, "Не удалось записать данные`nОшибка " A_LastError, Str, "", UInt, 0)
}
}
вот этим инджектом?
http://forum.script-coding.com/viewtopi … 42#p109142
Нет, чтение памяти чужого процесса и инжект dll в чужой процесс — разные вещи. Да там и не совсем корректный код, я с ним ещё не окончательно разобрался.
teadrinker, это же не значит, что я не стремлюсь обучаться, или вы обиделись на меня xD?
Malcev, ваш код работает на ура, спасибо. Проблема решена.
belyankin12, не обиделись. А мой код у вас не работает? Или опять не запускали?
teadrinker, проверил, работает, вам тоже спасибо!
Странно, а почему в "SciTE4AutoHotkey" в кодировки "code.page=65001" все работает, это же вроде и есть UTF-8? А что, начавшему тему пользователю обязательно нужны кириллические символы?
Вот если б ты на свой класс RemoteBuffer дал комментарии, то было бы отлично.
Вот подправленный RemoteBuffer с примером использования для Notepad++:
if hNPP := WinExist("ahk_class Notepad++")
WinGet, PID, PID
else {
try Run, notepad++,,, PID
catch e {
MsgBox, % e.Message "`n`n" e.Extra
ExitApp
}
WinWait, ahk_pid %PID%
}
WinActivate
; создаём удалённый буфер в адресном пространстве процесса Notepad++.exe
buff := new RemoteBuffer(PID, 512) ; размер 512 байт, с запасом
; созданный буфер находится теперь в адресном пространстве Notepad++.exe по адресу buff.ptr
; открываем наш скрипт в Notepad++
filePath := A_ScriptFullPath
; чтобы передать путь к файлу в сообщении, он должен находиться в АП Notepad++.exe
; Сначала запишем его в локальный буфер. Кодировка должна быть UTF-16.
VarSetCapacity(var, size := StrPut(filePath, "UTF-16")*2)
StrPut(filePath, &var, "UTF-16")
; теперь наш локальный буфер можно записать в удалённый через метод Write()
buff.Write(&var, size)
; сейчас путь к файлу находится в адресном пространстве Notepad++.exe по адресу buff.ptr
; передаём его окну сообщением:
SendMessage, NPPM_DOOPEN := 2101,, buff.ptr
if (ErrorLevel != 1) {
MsgBox, не удалось открыть файл
ExitApp
}
; получаем строку текста с номером LineNumber
LineNumber := 52
ControlGetFocus, focused
SendMessage, SCI_GETLINE := 2153, LineNumber - 1,, % focused
szBuff := ErrorLevel ; сколько места займёт строка
; подставляем buff.ptr в качестве буфера-получателя
SendMessage, SCI_GETLINE, LineNumber - 1, buff.ptr, % focused
; сейчас строка находится в адресном пространстве Notepad++.exe по адресу buff.ptr
; считываем её в локальный буфер, он будет создан автоматически
pStr := buff.Read(szBuff)
line := StrGet(pStr, szBuff, "UTF-8")
buff := "" ; уничтожаем удалённый буфер
MsgBox,, %LineNumber%-я строка:, % line
class RemoteBuffer
{
__New(PID, size) {
static PROCESS_VM_OPERATION := 0x8, PROCESS_VM_WRITE := 0x20
, PROCESS_VM_READ := 0x10, MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x4
if !(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
Return
if !(this.ptr := DllCall("VirtualAllocEx", Ptr, this.hProc, Ptr, 0, Ptr, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return, "", DllCall("CloseHandle", Ptr, this.hProc)
this.hHeap := DllCall("GetProcessHeap", Ptr)
}
__Delete() {
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
DllCall("HeapFree", Ptr, this.hHeap, UInt, 0, Ptr, this.pHeap)
}
Read(size, offset = 0) {
(this.pHeap && DllCall("HeapFree", Ptr, this.hHeap, UInt, 0, Ptr, this.pHeap))
this.pHeap := DllCall("HeapAlloc", Ptr, this.hHeap, UInt, HEAP_ZERO_MEMORY := 0x8, Ptr, size, Ptr)
if !DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, this.pHeap, Ptr, size, Int, 0)
Return, 0, DllCall("MessageBox", Ptr, 0, Str, "Не удалось прочитать данные`nОшибка " A_LastError, Str, "", UInt, 0)
Return this.pHeap
}
Write(pLocalBuff, size, offset = 0) {
if !res := DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, Ptr, size, PtrP, writtenBytes)
DllCall("MessageBox", Ptr, 0, Str, "Не удалось записать данные`nОшибка " A_LastError, Str, "", UInt, 0)
Return writtenBytes
}
}
Отлично. Спасибо!
Может в коллекцию?
Если бы ты потом, когда сам разберёшься, объяснил как инжектить dll на этом примере:
http://forum.script-coding.com/viewtopi … 42#p109142
И заодно, показал бы, что и как заинжектить тут:
http://forum.script-coding.com/viewtopi … 32#p111032
svoboden, мне не нужны. Мне нужна была вещь, что часть выделенного мной в notepad кода будет записывать в новый файл, чтобы я не создавал сто тысяч раз новый файл. А то мне вечно в скайпе пишут: "Белка, скинь это", "Скинь это" и т.д .
Malcev
По поводу последнего примера не в теме, по поводу первого — проблема инжекта dll в том, что внедряемой функции можно передать только один аргумент, и если нужно больше, то приведённым способом не получится. По идее нужно писать свою dll, которой будет передаваться указатель на структуру с аргументами для системных api-функций. Для AHK этот вариант не годится. Также можно вместо этого передать аргументы внедрённой функции, используя команды ассемблера. С этим и попытаюсь разобраться, как время будет.
Как перейти например на четвёртый символ в тексте если есть символы юникода?
Если в начале Scintilla прописать четыре русских буквы, то перейдёт на вторую.
1::
Pos := 4
SCI_SETSEL = 2160
ControlGetFocus, ControlNN, A
SendMessage, SCI_SETSEL, Pos, Pos, %ControlNN%, A
Return
Пока такой костыль вышел.
Но SubStr тут плохо смотрится.
SCI_GETCODEPAGE = 2137
SCI_SETSEL = 2160
Pos := 4
1::
ControlGetFocus, ControlNN, A
ControlGetText, Text, %ControlNN%, A
SendMessage, SCI_GETCODEPAGE, , , %ControlNN%, A
p := StrPut(SubStr(Text, 1, Pos - 1), "CP" Errorlevel)
SendMessage, SCI_SETSEL, p, p, %ControlNN%, A
Return
SCI_POSITIONRELATIVE := 2670
SCI_GETCODEPAGE := 2137
SCI_SETSEL := 2160
Pos := 4
1::
ControlGetFocus, ControlNN, A
SendMessage, SCI_POSITIONRELATIVE, 0, Pos, %ControlNN%, A
Pos := ErrorLevel
SendMessage, SCI_SETSEL, Pos, Pos, %ControlNN%, A
Return
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться