Page 1 of 1

SCI_REPLACESEL for Notepad++

Posted: 10 Mar 2019, 14:07
by toralf
I would like to replace the selction in notepad++ with a text.

Code: Select all

SCI_REPLACESEL(text){ ;2170
; SCI_REPLACESEL(<unused>, const char *text)
; The currently selected text between the anchor and the current position is replaced by the 0 terminated text string. If the anchor and current position are the same, the text is inserted at the caret position. The caret is positioned after the inserted text and the caret is scrolled into view.
  DllCall("SendMessage", "Ptr", SCI_HWND(), "UInt", 2170, "Int", 0, "Ptr", &text)
}
Nppm_HWND(Title := "Notepad++"){
	return DllCall("FindWindow", "Str", Title, "Int", 0, "Ptr") 
}
SCI_HWND(){
  ControlGet hSci, Hwnd,, Scintilla1, % "ahk_id" Nppm_HWND()
  Return hSci
}
unfortunately this doesn't work.
Any help or hint?

Re: SCI_REPLACESEL for Notepad++

Posted: 10 Mar 2019, 14:19
by toralf
It does work when i send numbers

Code: Select all

SCI_GotoLine(Line){
  DllCall("SendMessage", "Ptr", SCI_HWND(), "UInt", 2024 , "Int", Line - 1, "Int", 0)
}
SCI_GOTOPOS(Pos){
  DllCall("SendMessage", "Ptr", SCI_HWND(), "UInt", 2025 , "Int", Pos, "Int", 0)
}

Re: SCI_REPLACESEL for Notepad++

Posted: 10 Mar 2019, 14:33
by jeeswg
- I have some Scintilla control functions, here:
GUIs via DllCall: text functions (get/set internal/external control text) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=40514
- Sometimes, to put text into external processes, you have to use WriteProcessMemory etc.

Re: SCI_REPLACESEL for Notepad++

Posted: 11 Mar 2019, 01:39
by toralf
I tried to write to memory, but i didn't succeed. A selection gets replaced, but with nothing.

Code: Select all

SCI_REPLACESEL(text){ 
  
	hNpp := DllCall("FindWindow"
            , "Str", "Notepad++"
            , "Int", 0
            , "Ptr") 
  ControlGet hSci, Hwnd,, Scintilla1, % "ahk_id" hNpp
            
  NppPID := NPPM_PID()
  
  hProcess := DllCall("OpenProcess"
            , "UInt", ( PROCESS_VM_OPERATION := 0x8 | PROCESS_VM_READ := 0x10 | PROCESS_VM_WRITE := 0x20)
            , "Int" , false
            , "UInt", NppPID
            , "Ptr")
  
  BufferSize := StrLen(text) * (A_IsUnicode ? 2 : 1)

  nppBufAddress := DllCall("VirtualAllocEx"
              , "UInt", hProcess
              , "Int" , 0
              , "Int" , BufferSize
              , "Int" , MEM_COMMIT := 0x1000
              , "Int" , PAGE_READWRITE := 0x4
              , "Ptr" )

  DllCall("kernel32\WriteProcessMemory"
              , Ptr,hProcess
              , Ptr,nppBufAddress
              , Ptr, &text
              , UPtr,BufferSize
              , Ptr,0)

	DllCall("SendMessage", "Ptr", hSci, "UInt", 2170, "Int", 0, "Ptr", nppBufAddress)
		
	DllCall("VirtualFreeEx"
              , "Ptr", hProcess
              , "Ptr", nppBufAddress
              , "UInt", 0
              , "UInt", MEM_RELEASE := 0x8000)

	DllCall("CloseHandle"
              , "Ptr", hProcess)
}
Nppm_PID(TimeOutInSec := 1){
	Process, Wait, Notepad++.exe, %TimeOutInSec% 
	return ErrorLevel  ;PID or 0 when timed out
}

Re: SCI_REPLACESEL for Notepad++

Posted: 11 Mar 2019, 01:44
by jeeswg
Btw Scintilla controls generally use UTF-8. So, I convert strings to UTF-8 before using them with Scintilla controls.

Re: SCI_REPLACESEL for Notepad++

Posted: 11 Mar 2019, 01:46
by toralf
how could i do this?

Re: SCI_REPLACESEL for Notepad++

Posted: 11 Mar 2019, 01:55
by toralf
Thanks for the tip. It worked.

Code: Select all

BufferSize := StrPut(Text, "UTF-8")
	vOutput := ""
	VarSetCapacity(vOutput, BufferSize+1, 0)
	StrPut(Text, &vOutput, "UTF-8")

Re: SCI_REPLACESEL for Notepad++

Posted: 05 Jul 2022, 05:31
by vadus
Hi, @toralf,
When I run this code, only the first letter of the text 't' is inserted. What am I doing wrong?

Code: Select all

SCI_REPLACESEL("test")

Return

SCI_REPLACESEL(text){ 
  
	hNpp := DllCall("FindWindow"
            , "Str", "Notepad++"
            , "Int", 0
            , "Ptr") 
  ControlGet hSci, Hwnd,, Scintilla1, % "ahk_id" hNpp
            
  NppPID := NPPM_PID()
  
  hProcess := DllCall("OpenProcess"
            , "UInt", ( PROCESS_VM_OPERATION := 0x8 | PROCESS_VM_READ := 0x10 | PROCESS_VM_WRITE := 0x20)
            , "Int" , false
            , "UInt", NppPID
            , "Ptr")
  

  BufferSize := StrPut(Text, "UTF-8")
	vOutput := ""
	VarSetCapacity(vOutput, BufferSize+1, 0)
	StrPut(Text, &vOutput, "UTF-8")

  nppBufAddress := DllCall("VirtualAllocEx"
              , "UInt", hProcess
              , "Int" , 0
              , "Int" , BufferSize
              , "Int" , MEM_COMMIT := 0x1000
              , "Int" , PAGE_READWRITE := 0x4
              , "Ptr" )

  DllCall("kernel32\WriteProcessMemory"
              , Ptr,hProcess
              , Ptr,nppBufAddress
              , Ptr, &text
              , UPtr,BufferSize
              , Ptr,0)

	DllCall("SendMessage", "Ptr", hSci, "UInt", 2170, "Int", 0, "Ptr", nppBufAddress)
		
	DllCall("VirtualFreeEx"
              , "Ptr", hProcess
              , "Ptr", nppBufAddress
              , "UInt", 0
              , "UInt", MEM_RELEASE := 0x8000)

	DllCall("CloseHandle"
              , "Ptr", hProcess)
}

Nppm_PID(TimeOutInSec := 1){
	Process, Wait, Notepad++.exe, %TimeOutInSec% 
	return ErrorLevel  ;PID or 0 when timed out
}

Re: SCI_REPLACESEL for Notepad++

Posted: 05 Jul 2022, 11:33
by toralf
Hello vadus.
Welcome to the AHK Forum. I see this is your first post.

I’ll have to take a look at my current code and compare it. It will take a while, sorry

Re: SCI_REPLACESEL for Notepad++

Posted: 07 Jul 2022, 01:23
by vadus
Tnank you, toralf.
I'm waiting.
I just used your code with StrPut added. But unfortunately, as I mentioned, it doesn't work

Re: SCI_REPLACESEL for Notepad++

Posted: 21 Jul 2022, 07:17
by toralf
Sorry that it took so long.

This code works

Code: Select all

f5: SCI_REPLACESEL("toralf")

SCI_REPLACESEL(text){ ;2170
; SCI_REPLACESEL(<unused>, const char *text)
; The currently selected text between the anchor and the current position is replaced by the 0 terminated text string. If the anchor and current position are the same, the text is inserted at the caret position. The caret is positioned after the inserted text and the caret is scrolled into view.

  Output := NPPM_ConvertToUTF8(Text, BufferSize)
  
	hNpp := Nppm_Hwnd()

	openProcSuccess := NPPM_OpenBuffer(hProcess, nppBufAddress, BufferSize) 

	if (WinExist("ahk_id " . hNpp) == 0) OR (openProcSuccess == 0)
		return
    
  NPPM_WriteProcessMemory(hProcess, nppBufAddress, Output, BufferSize)
  
	DllCall("SendMessage", "Ptr", SCI_HWND(), "UInt", 2170, "Int", 0, "Ptr", nppBufAddress)
		
	NPPM_CloseBuffer(hProcess, nppBufAddress)

}

Re: SCI_REPLACESEL for Notepad++

Posted: 21 Jul 2022, 07:31
by vadus
Thanks, toralf, I'll try

Re: SCI_REPLACESEL for Notepad++

Posted: 21 Jul 2022, 08:16
by vadus
It's lib from here?
https://github.com/Ixiko/AHK-libs-and-classes-collection/blob/master/libs/g-n/NPPM.ahk

Unfortunately, it doesn't work for me.
Maybe this is a lib for AHK_V2? I have v 1.1.33

Re: SCI_REPLACESEL for Notepad++  Topic is solved

Posted: 21 Jul 2022, 12:14
by teadrinker
Try this:

Code: Select all

ControlGet, hScintilla, hwnd,, Scintilla1, ahk_class Notepad++
if !hScintilla {
   MsgBox, Scintilla not found
   ExitApp
}

SCI_REPLACESEL(hScintilla, "AutoHotkey")

SCI_REPLACESEL(hScintilla, text) {
   WinGet, PID, PID, ahk_id %hScintilla%
   size := StrPut(text, "UTF-8")
   RB := new RemoteBuffer(PID, size)
   VarSetCapacity(buf, size, 0)
   StrPut(text, &buf, "UTF-8")
   RB.Write(&buf, size)
   SendMessage, SCI_REPLACESEL := 2170,, RB.ptr,, ahk_id %hScintilla%
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := ["UInt", MEM_COMMIT := 0x1000, "UInt", PAGE_READWRITE := 0x4, "Ptr"]
         
      if !this.hProc := DllCall("OpenProcess", "UInt", flags, "Int", 0, "UInt", PID, "Ptr")
         throw Exception("Can't open remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      
      if !this.ptr := DllCall("VirtualAllocEx", "Ptr", this.hProc, "Ptr", 0, "Ptr", size, Params*) {
         DllCall("CloseHandle", "Ptr", this.hProc)
         throw Exception("Can't allocate memory in remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      }
   }
   __Delete() {
      DllCall("VirtualFreeEx", "Ptr", this.hProc, "Ptr", this.ptr, "UInt", 0, "UInt", MEM_RELEASE := 0x8000)
      DllCall("CloseHandle", "Ptr", this.hProc)
   }  
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall("ReadProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", &localBuff, "Ptr", size, "PtrP", bytesRead)
         throw Exception("Can't read data from remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Read")
      Return bytesRead
   }
   Write(pData, size, offset = 0) {
      if !res := DllCall("WriteProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", pData, "Ptr", size, "PtrP", bytesWritten)
         throw Exception("Can't write data to remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Write")
      Return bytesWritten
   }
}

Re: SCI_REPLACESEL for Notepad++

Posted: 21 Jul 2022, 12:43
by vadus
Great, it works! Thank you, teadrinker.
Just how do I make it work with Cyrillic, ANSI encoding?
Now this code:

Code: Select all

SCI_REPLACESEL(hScintilla, "Борщ")

is inserted:

Code: Select all

Борщ

Re: SCI_REPLACESEL for Notepad++

Posted: 21 Jul 2022, 13:05
by teadrinker
vadus wrote:Just how do I make it work with Cyrillic, ANSI encoding?
Cyrillic is not an encoding, it's just a font group. For me this script works with any text. Ensure you save the script as UTF-8 with BOM. Scintilla in Notepad++ uses UTF-8 too.

Re: SCI_REPLACESEL for Notepad++

Posted: 21 Jul 2022, 14:46
by vadus
All right, it works, thank you

Re: SCI_REPLACESEL for Notepad++

Posted: 22 Jul 2022, 03:15
by lexikos
Scintilla also "supports" EM_REPLACESEL (although it's "deprecated and discouraged"), which means it "supports" Control EditPaste.

The trick is that unlike real Edit controls, Scintilla requires a UTF-8 string. So this works for me:

Code: Select all

str := "Text to insert"
VarSetCapacity(str8, StrPut(str8, "utf-8"), 1), StrPut(str, &str8, "utf-8")
SetTitleMatchMode 2
Control EditPaste, % str8, Scintilla1, ahk_class Notepad++
But SCI_REPLACESEL will be needed if the Edit control messages are ever actually removed (as the documentation warns).

EM_REPLACESEL is a system-defined message, so the system automatically copies the string between processes. This means it doesn't require RemoteBuffer or anything like it.

Re: SCI_REPLACESEL for Notepad++

Posted: 22 Jul 2022, 10:36
by vadus
Scintilla also "supports" EM_REPLACESEL
Yes, it works for me too

Re: SCI_REPLACESEL for Notepad++

Posted: 07 Sep 2022, 06:55
by vadus
Hi,
Maybe someone will be interested to know how to insert Cyrillic text in an ANSI encoded file using SCI_REPLACESEL
You just need to change UTF-8 to CP1251. The code will look like this:

Code: Select all

SCI_REPLACESEL(hScintilla, text) {
   WinGet, PID, PID, ahk_id %hScintilla%
   size := StrPut(text, "CP1251")
   RB := new RemoteBuffer(PID, size)
   VarSetCapacity(buf, size, 0)
   StrPut(text, &buf, "CP1251")
   RB.Write(&buf, size)
   SendMessage, SCI_REPLACESEL := 2170,, RB.ptr,, ahk_id %hScintilla%
}