Replace 1 + lines?

  • @guy038

    Guy, here the updated one.
    A “one-selection” action results in opening the standard replace dialog behavior.
    A “two-selections” action, even with an empty one, results in modifying the fields.
    I see it as a benefit that you are able to decide that only one of the fields should be filled
    and the other should be empty in any case.

    import ctypes
    from ctypes.wintypes import BOOL, HWND, LPARAM
    FindWindow = ctypes.windll.user32.FindWindowW
    FindWindowEx = ctypes.windll.user32.FindWindowExW
    SendMessage = ctypes.windll.user32.SendMessageW
    EnumChildWindows = ctypes.windll.user32.EnumChildWindows
    GetClassName = ctypes.windll.user32.GetClassNameW
    GetWindowText = ctypes.windll.user32.GetWindowTextW
    GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
    SetWindowText = ctypes.windll.user32.SetWindowTextW
    GetACP = ctypes.windll.kernel32.GetACP
    create_unicode_buffer = ctypes.create_unicode_buffer
    replace_tab_caption  = u'Replace'
    replacewith_caption = u'Rep&lace with :'
    replacewith_is_next_ctrl = False
    replacewith_handle = None
    replacewith_text = None
    findwhat_caption = u'&Find what :'
    findwhat_is_next_ctrl = False
    findwhat_handle = None
    findwhat_text = None
    def EnumCallback(hwnd, lparam):
        global replacewith_is_next_ctrl
        global findwhat_is_next_ctrl
        global replacewith_handle
        global findwhat_handle
        curr_class = create_unicode_buffer(256)
        GetClassName(hwnd, curr_class, 256)
        length = GetWindowTextLength(hwnd)
        buff = ctypes.create_unicode_buffer(length + 1)
        GetWindowText(hwnd, buff, length + 1)
        if curr_class.value.lower() == 'static':
            if buff.value == replacewith_caption:
                replacewith_is_next_ctrl = True
            elif buff.value == findwhat_caption:
                findwhat_is_next_ctrl = True
        elif curr_class.value.lower() == 'edit':
            if findwhat_is_next_ctrl:
                findwhat_handle = hwnd
                findwhat_is_next_ctrl = False
            elif replacewith_is_next_ctrl:
                replacewith_handle = hwnd
                replacewith_is_next_ctrl = False
                return False  # stop enumeration
        return True  # let enumeration continue
    def return_proper_string(selected_text):
        if notepad.getEncoding() == BUFFERENCODING.ENC8BIT:
            _selected_text = unicode(selected_text, '{}'.format(GetACP()))
            _selected_text = unicode(selected_text, 'utf-8')
        return _selected_text
    def main():
        msg = ''
        if editor.getSelections() == 1:
        elif editor.getSelections() == 2:
            if editor.getSelectionMode() == 0 and not editor.getSelectionEmpty():
                _find_what = editor.getTextRange(editor.getSelectionNStart(0), editor.getSelectionNEnd(0))
                _replace_with = editor.getTextRange(editor.getSelectionNStart(1), editor.getSelectionNEnd(1))
                if len(_find_what) > 2046:
                    _find_what = _find_what[:2046]
                    msg += 'Warning:  Selected text too long for find-what box; truncating to 2046 characters.  '
                if len(_replace_with) > 2046:
                    _replace_with = _replace_with[:2046]
                    msg += 'Warning:  Selected text too long for replace-with box; truncating to 2046 characters.  '
                find_dialog_hwnd = FindWindow(None, replace_tab_caption)
                if find_dialog_hwnd:
                    EnumChildWindows(find_dialog_hwnd, WNDENUMPROC(EnumCallback), 0)
                    if findwhat_handle and replacewith_handle:
                        if SetWindowText(findwhat_handle, return_proper_string(_find_what)) == 0:
                            msg += 'Error:  Problem setting find-what text'
                        if SetWindowText(replacewith_handle, return_proper_string(_replace_with)) == 0:
                            msg += 'Error:  Problem setting replace-with text'
                        msg += 'Error:  Bad value for replacewith_handle'
                    msg += 'Error:  Bad value for find_dialog_hwnd'
                msg += 'Error:  Either empty selection or unsupported selection mode detected'
            msg += 'Warning:  Only one or two selections are possible. Received:{}'.format(editor.getSelections())
        if len(msg) > 0: notepad.messageBox(msg)


  • Hello, @claudia-frank, @Scott-sumner, @pouemes44, @go2to, @jorge-campos, @herofiles, @azjio-azjio, @alan-kilborn and All

    Thanks to @claudia-frank, this present topic and the discussions, below, about multi-lines search AND multi-lines Replacement :

    have, now, an ELEGANT solution, with her Python’s script, just above !

    You just need to be able to do multiple selections ( Option Settings > Preferences… > Editing > Multi-Editing Settings > Enable CHECKED )

    BTW, the upper limit of 2046 characters, in the Find what: box of the Find/Replace dialog, only, could be by-passed, easily :-). Indeed, just use the Regular expression search mode and use the generic regex (?s)Left-boundary.+?Right-boundary !

    For instance, you can choose a particular character, which does not exist,yet, in your file(s) to be modified, and build the regex :


    This regex contains any non-null amount of characters between TWO same complete lines #####, with their line-breaks

    So :

    • Do a normal selection of this regex (?s)(#####\R).+?\1, using the mouse

    • Then, with a Ctrl + Left Click action, simply, select your Replace block, multi-lines or not

    • Run the Claudia’s script above

    => Immediately, the Find/Replace dialog pops-up and :

    • The Find what: box is filled with the regex (?s)(#####\R).+?\1

    • The Replace with: box is filled with the block of text, which must replace the searched text

    Best Regards,


    P.S. :

    @claudia-frank, I understand your point of view. Your script is quite flexible :-D. For instance, I was able to :

    • First, do a Ctrl + Clic selection of a multi-lines block of text

    • Run your script => Find what: box empty and Replace with: box filled with that multi-lines block

    • Select an second file, containing the text (?s)(#####\R).+?\1

    • Do a normal selection of that regex

    • Run again, your script => The find.Replace dialog, presently in the background, is, then, updated with this regex, filled in the Find what: box

    • Select a third file, containing the ##### boundaries lines

    • Perform the S/R on the contents of this third file

    Et voilà !!

    Many thanks, again, for this very, very, valuable script, indeed !!!

    Hum… Already 3 h 25 !! I’d better go to bed : working tomorrow !

  • It would be nice if the author would make an additional window when the button is clicked
    [](link url)

  • The external program is working. I make a plugin and no longer works (EnumChildWindows).

  • Sorry, but what are you try to tell us?
    Which external program and which meaning has EnumChildWindows API in this context?

  • I wrote a program for the test of regular expressions. It serves as a database. When you click a button, it fills in the search and replace fields.
    I decided to make a plugin that will do the same. But the same program (exe and dll) work differently. EXE fills the fields, but the DLL can not fill.
    I tried using EnumChildWindows to find the elements of the window, as is done in the examples above. But as a result, he found only 3 elements.
    0 hwnd = 725602 Class = Button Title = Caption
    1 hwnd = 2233572 Class = Static Title =
    2 hwnd = 1707882 Class = SysTabControl32 Title = Tab1


    without seeing/understanding the actual code it is hard to say what might be the issue
    but, personally, I would not recommend using EnumChildWindows when trying to find a
    dialog control window handle, instead use GetDlgItem.

  • ; PureBasic
    hwnd = FindWindowEx_(NppData_nppHandle, 0, “#32770”, 0) ; hwnd = yes
    If Not IsWindowVisible_(hwnd)
    SendMessage_(NppData_nppHandle, #NPPM_MENUCOMMAND, 0, #IDM_SEARCH_REPLACE) ; Показать диалог поиска используя команду меню
    hwndEdit_1 = GetDlgItem_(hwnd, 1601) ; hwndEdit_1 = 0
    hwndEdit_2 = GetDlgItem_(hwnd, 1602) ; hwndEdit_2 = 0
    SendMessage_(hwndEdit_1,#WM_SETTEXT,0,GetGadgetItemText(#Combo_2 , n-1, 0))
    SendMessage_(hwndEdit_2,#WM_SETTEXT,0,GetGadgetItemText(#Combo_2 , n-1, 1))

  • @AZJIO-AZJIO said:


    be careful about searching for the ordinal only, as every dialog uses it.
    Most plugins and internal npp windows are dialogs.

  • I know it. I do not set the window class. I have no way to change this. The external program, as I said, works.


    Sorry, didn’t recognize the update.
    Windows, sometimes, treats retrieving external and internal information differently.
    Means, something you retrieved from an exe might differ from something
    you want to retrieve within its own process.

    In python, I would it do like this

    import ctypes
    user32 = ctypes.WinDLL('user32')
    hwnd = user32.FindWindowExW(None, None, u'#32770', u'Replace')
    hwndEdit_1 = user32.GetDlgItem(hwnd, 1601)
    hwndEdit_2 = user32.GetDlgItem(hwnd, 1602)

    This takes care that only the dialog with name Replace is found.

  • I have done just that. Keyword only “Extended”. But using AutoIt3

    $hWnd = WinGetHandle("[CLASS:Notepad++]")
    If Not @error Then
    If BitAND(WinGetState($hWnd), 16) Then WinActivate($hWnd)
    $hWnd = WinWait("[CLASS:#32770]", “Extended”, 2)
    If $hWnd Then
    ControlSetText($hWnd, “Extended”, “Edit1”, _GUICtrlRichEdit_GetText($hRichEdit_SPE))
    ControlSetText($hWnd, “Extended”, “Edit2”, GUICtrlRead($PtnRep))
    ControlCommand($hWnd, “Extended”, “Button18”, ‘Check’) ; 18 - regular expression (16 - normal)

    on PureBasic code is the same for exe and dll. Search window “#32770” starts at the top, so it does not cause a problem. There are either no such windows or they are below.

  • Maybe I have a wrong assumption what you are actually doing.
    When you talk about an exe I assume that this is a different standalone program, correct?
    When you talked about dll I assumed that this might be a npp plugin.
    Now I get the feeling this is incorrect. Would you mind to explain what exactly is what
    and what your ultimate goal is?

  • Thank! The previous code helped. I saw in it the absence of a handle in FindWindowExW(None
    I am intensively writing 2 plugins

  • As a result, several plugins, but there is much to strive for.

Log in to reply